ai_scanner.cpp

Go to the documentation of this file.
00001 /* $Id: ai_scanner.cpp 23740 2012-01-03 21:32:51Z rubidium $ */
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 "../network/network.h"
00015 #include "../core/random_func.hpp"
00016 
00017 #include "../script/squirrel_class.hpp"
00018 #include "ai_info.hpp"
00019 #include "ai_scanner.hpp"
00020 
00021 
00022 AIScannerInfo::AIScannerInfo() :
00023   ScriptScanner(),
00024   info_dummy(NULL)
00025 {
00026 }
00027 
00028 void AIScannerInfo::Initialize()
00029 {
00030   ScriptScanner::Initialize("AIScanner");
00031 
00032   /* Create the dummy AI */
00033   free(this->main_script);
00034   this->main_script = strdup("%_dummy");
00035   extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir);
00036   Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
00037 }
00038 
00039 void AIScannerInfo::SetDummyAI(class AIInfo *info)
00040 {
00041   this->info_dummy = info;
00042 }
00043 
00044 AIScannerInfo::~AIScannerInfo()
00045 {
00046   delete this->info_dummy;
00047 }
00048 
00049 void AIScannerInfo::GetScriptName(ScriptInfo *info, char *name, int len)
00050 {
00051   snprintf(name, len, "%s", info->GetName());
00052 }
00053 
00054 void AIScannerInfo::RegisterAPI(class Squirrel *engine)
00055 {
00056   AIInfo::RegisterAPI(engine);
00057 }
00058 
00059 AIInfo *AIScannerInfo::SelectRandomAI() const
00060 {
00061   uint num_random_ais = 0;
00062   for (ScriptInfoList::const_iterator it = this->info_single_list.begin(); it != this->info_single_list.end(); it++) {
00063     AIInfo *i = static_cast<AIInfo *>((*it).second);
00064     if (i->UseAsRandomAI()) num_random_ais++;
00065   }
00066 
00067   if (num_random_ais == 0) {
00068     DEBUG(script, 0, "No suitable AI found, loading 'dummy' AI.");
00069     return this->info_dummy;
00070   }
00071 
00072   /* Find a random AI */
00073   uint pos;
00074   if (_networking) {
00075     pos = InteractiveRandomRange(num_random_ais);
00076   } else {
00077     pos = RandomRange(num_random_ais);
00078   }
00079 
00080   /* Find the Nth item from the array */
00081   ScriptInfoList::const_iterator it = this->info_single_list.begin();
00082 
00083 #define GetAIInfo(it) static_cast<AIInfo *>((*it).second)
00084   while (!GetAIInfo(it)->UseAsRandomAI()) it++;
00085   for (; pos > 0; pos--) {
00086     it++;
00087     while (!GetAIInfo(it)->UseAsRandomAI()) it++;
00088   }
00089   return GetAIInfo(it);
00090 #undef GetAIInfo
00091 }
00092 
00093 AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match)
00094 {
00095   if (this->info_list.size() == 0) return NULL;
00096   if (nameParam == NULL) return NULL;
00097 
00098   char ai_name[1024];
00099   ttd_strlcpy(ai_name, nameParam, sizeof(ai_name));
00100   strtolower(ai_name);
00101 
00102   AIInfo *info = NULL;
00103   int version = -1;
00104 
00105   if (versionParam == -1) {
00106     /* We want to load the latest version of this AI; so find it */
00107     if (this->info_single_list.find(ai_name) != this->info_single_list.end()) return static_cast<AIInfo *>(this->info_single_list[ai_name]);
00108 
00109     /* If we didn't find a match AI, maybe the user included a version */
00110     char *e = strrchr(ai_name, '.');
00111     if (e == NULL) return NULL;
00112     *e = '\0';
00113     e++;
00114     versionParam = atoi(e);
00115     /* FALL THROUGH, like we were calling this function with a version. */
00116   }
00117 
00118   if (force_exact_match) {
00119     /* Try to find a direct 'name.version' match */
00120     char ai_name_tmp[1024];
00121     snprintf(ai_name_tmp, sizeof(ai_name_tmp), "%s.%d", ai_name, versionParam);
00122     strtolower(ai_name_tmp);
00123     if (this->info_list.find(ai_name_tmp) != this->info_list.end()) return static_cast<AIInfo *>(this->info_list[ai_name_tmp]);
00124   }
00125 
00126   /* See if there is a compatible AI which goes by that name, with the highest
00127    *  version which allows loading the requested version */
00128   ScriptInfoList::iterator it = this->info_list.begin();
00129   for (; it != this->info_list.end(); it++) {
00130     AIInfo *i = static_cast<AIInfo *>((*it).second);
00131     if (strcasecmp(ai_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
00132       version = (*it).second->GetVersion();
00133       info = i;
00134     }
00135   }
00136 
00137   return info;
00138 }
00139 
00140 
00141 void AIScannerLibrary::Initialize()
00142 {
00143   ScriptScanner::Initialize("AIScanner");
00144 }
00145 
00146 void AIScannerLibrary::GetScriptName(ScriptInfo *info, char *name, int len)
00147 {
00148   AILibrary *library = static_cast<AILibrary *>(info);
00149   snprintf(name, len, "%s.%s", library->GetCategory(), library->GetInstanceName());
00150 }
00151 
00152 void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
00153 {
00154   AILibrary::RegisterAPI(engine);
00155 }
00156 
00157 AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version)
00158 {
00159   /* Internally we store libraries as 'library.version' */
00160   char library_name[1024];
00161   snprintf(library_name, sizeof(library_name), "%s.%d", library, version);
00162   strtolower(library_name);
00163 
00164   /* Check if the library + version exists */
00165   ScriptInfoList::iterator iter = this->info_list.find(library_name);
00166   if (iter == this->info_list.end()) return NULL;
00167 
00168   return static_cast<AILibrary *>((*iter).second);
00169 }