OpenTTD
ai_info.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "../stdafx.h"
11 
12 #include "../script/squirrel_class.hpp"
13 #include "ai_info.hpp"
14 #include "ai_scanner.hpp"
15 #include "../debug.h"
16 #include "../string_func.h"
17 #include "../rev.h"
18 
19 #include "../safeguards.h"
20 
25 static bool CheckAPIVersion(const char *api_version)
26 {
27  return strcmp(api_version, "0.7") == 0 || strcmp(api_version, "1.0") == 0 || strcmp(api_version, "1.1") == 0 ||
28  strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 ||
29  strcmp(api_version, "1.5") == 0 || strcmp(api_version, "1.6") == 0 || strcmp(api_version, "1.7") == 0 ||
30  strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0;
31 }
32 
33 #if defined(_WIN32)
34 #undef GetClassName
35 #endif /* _WIN32 */
36 template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
37 
38 /* static */ void AIInfo::RegisterAPI(Squirrel *engine)
39 {
40  /* Create the AIInfo class, and add the RegisterAI function */
41  DefSQClass<AIInfo, ST_AI> SQAIInfo("AIInfo");
42  SQAIInfo.PreRegister(engine);
43  SQAIInfo.AddConstructor<void (AIInfo::*)(), 1>(engine, "x");
44  SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting");
45  SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels");
46  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE");
47  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM");
48  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN");
49  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME");
50  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER");
51 
52  /* Pre 1.2 had an AI prefix */
53  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "AICONFIG_NONE");
54  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "AICONFIG_RANDOM");
55  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "AICONFIG_BOOLEAN");
56  SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "AICONFIG_INGAME");
57 
58  SQAIInfo.PostRegister(engine);
59  engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx");
60  engine->AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, 2, "tx");
61 }
62 
63 /* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm)
64 {
65  /* Get the AIInfo */
66  SQUserPointer instance = nullptr;
67  if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, 0)) || instance == nullptr) return sq_throwerror(vm, "Pass an instance of a child class of AIInfo to RegisterAI");
68  AIInfo *info = (AIInfo *)instance;
69 
70  SQInteger res = ScriptInfo::Constructor(vm, info);
71  if (res != 0) return res;
72 
74  config.name = stredup(config.name);
75  config.description = stredup(config.description);
76  info->config_list.push_front(config);
77 
78  if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) {
79  if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
80  } else {
81  info->min_loadable_version = info->GetVersion();
82  }
83  /* When there is an UseAsRandomAI function, call it. */
84  if (info->engine->MethodExists(*info->SQ_instance, "UseAsRandomAI")) {
85  if (!info->engine->CallBoolMethod(*info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
86  } else {
87  info->use_as_random = true;
88  }
89  /* Try to get the API version the AI is written for. */
90  if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) {
91  if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
92  if (!CheckAPIVersion(info->api_version)) {
93  DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion());
94  return SQ_ERROR;
95  }
96  } else {
97  info->api_version = stredup("0.7");
98  }
99 
100  /* Remove the link to the real instance, else it might get deleted by RegisterAI() */
101  sq_setinstanceup(vm, 2, nullptr);
102  /* Register the AI to the base system */
103  info->GetScanner()->RegisterScript(info);
104  return 0;
105 }
106 
107 /* static */ SQInteger AIInfo::DummyConstructor(HSQUIRRELVM vm)
108 {
109  /* Get the AIInfo */
110  SQUserPointer instance;
111  sq_getinstanceup(vm, 2, &instance, 0);
112  AIInfo *info = (AIInfo *)instance;
113  info->api_version = nullptr;
114 
115  SQInteger res = ScriptInfo::Constructor(vm, info);
116  if (res != 0) return res;
117 
118  char buf[8];
119  seprintf(buf, lastof(buf), "%d.%d", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));
120  info->api_version = stredup(buf);
121 
122  /* Remove the link to the real instance, else it might get deleted by RegisterAI() */
123  sq_setinstanceup(vm, 2, nullptr);
124  /* Register the AI to the base system */
125  static_cast<AIScannerInfo *>(info->GetScanner())->SetDummyAI(info);
126  return 0;
127 }
128 
129 AIInfo::AIInfo() :
131  use_as_random(false),
132  api_version(nullptr)
133 {
134 }
135 
136 AIInfo::~AIInfo()
137 {
138  free(this->api_version);
139 }
140 
142 {
143  if (version == -1) return true;
144  return version >= this->min_loadable_version && version <= this->GetVersion();
145 }
146 
147 
148 AILibrary::~AILibrary()
149 {
150  free(this->category);
151 }
152 
154 {
155  /* Create the AILibrary class, and add the RegisterLibrary function */
156  engine->AddClassBegin("AILibrary");
157  engine->AddClassEnd();
158  engine->AddMethod("RegisterLibrary", &AILibrary::Constructor, 2, "tx");
159 }
160 
161 /* static */ SQInteger AILibrary::Constructor(HSQUIRRELVM vm)
162 {
163  /* Create a new library */
164  AILibrary *library = new AILibrary();
165 
166  SQInteger res = ScriptInfo::Constructor(vm, library);
167  if (res != 0) {
168  delete library;
169  return res;
170  }
171 
172  /* Cache the category */
173  if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
174  delete library;
175  return SQ_ERROR;
176  }
177 
178  /* Register the Library to the base system */
179  library->GetScanner()->RegisterScript(library);
180 
181  return 0;
182 }
int GetVersion() const
Get the version of the script.
Definition: script_info.hpp:72
This setting will only be visible when the Script development tools are active.
static SQInteger Constructor(HSQUIRRELVM vm)
Create an AI, using this AIInfo as start-template.
Definition: ai_info.cpp:161
int version
Version of the script.
HSQOBJECT * SQ_instance
The Squirrel instance created for this info.
bool CheckMethod(const char *name) const
Check if a given method exists.
Definition: script_info.cpp:47
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:407
const char * GetName() const
Get the Name of the script.
Definition: script_info.hpp:57
ScriptConfigItemList config_list
List of settings from this Script.
static bool CheckAPIVersion(const char *api_version)
Check if the API version provided by the AI is supported.
Definition: ai_info.cpp:25
bool use_as_random
Should this AI be used when the user wants a "random AI"?
Definition: ai_info.hpp:53
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:48
ScriptConfigItem _start_date_config
Configuration for AI start date, every AI has this setting.
Definition: ai_config.cpp:20
declarations of the class for AI scanner
No flags set.
The template to define classes in Squirrel.
static SQInteger Constructor(HSQUIRRELVM vm)
Create an AI, using this AIInfo as start-template.
Definition: ai_info.cpp:63
const char * api_version
API version used by this AI.
Definition: ai_info.hpp:54
void RegisterScript(class ScriptInfo *info)
Register a ScriptInfo to the scanner.
SQInteger AddLabels(HSQUIRRELVM vm)
Add labels for a setting.
static SQInteger DummyConstructor(HSQUIRRELVM vm)
Create a dummy-AI.
Definition: ai_info.cpp:107
All static information from an AI library like name, version, etc.
Definition: ai_info.hpp:58
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
Definition: string.cpp:136
static void RegisterAPI(Squirrel *engine)
Register the functions of this class.
Definition: ai_info.cpp:38
int min_loadable_version
The AI can load savegame data if the version is equal or greater than this.
Definition: ai_info.hpp:52
When randomizing the Script, pick any value between min_value and max_value when on custom difficulty...
void AddMethod(const char *method_name, SQFUNCTION proc, uint nparam=0, const char *params=nullptr, void *userdata=nullptr, int size=0)
Adds a function to the stack.
Definition: squirrel.cpp:225
This value is a boolean (either 0 (false) or 1 (true) ).
virtual class ScriptScanner * GetScanner()
Get the scanner which has found this ScriptInfo.
bool CanLoadFromVersion(int version) const
Check if we can start this AI.
Definition: ai_info.cpp:141
const char * description
The description of the configuration setting.
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
SQInteger AddSetting(HSQUIRRELVM vm)
Set a setting.
All static information from an AI like name, version, etc.
Definition: ai_info.hpp:16
Info about a single Script setting.
const char * category
The category this library is in.
Definition: ai_info.hpp:79
static const int MAX_GET_OPS
Number of operations to get the author and similar information.
Definition: script_info.hpp:25
bool MethodExists(HSQOBJECT instance, const char *method_name)
Check if a method exists in an instance.
Definition: squirrel.cpp:292
static void RegisterAPI(Squirrel *engine)
Register the functions of this class.
Definition: ai_info.cpp:153
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
void DefSQAdvancedMethod(Squirrel *engine, Func function_proc, const char *function_name)
This defines a method inside a class for Squirrel, which has access to the &#39;engine&#39; (experts only!)...
void AddClassBegin(const char *class_name)
Adds a class to the global scope.
Definition: squirrel.cpp:260
This setting can be changed while the Script is running.
class Squirrel * engine
Engine used to register for Squirrel.
static SQInteger Constructor(HSQUIRRELVM vm, ScriptInfo *info)
Process the creation of a FileInfo object.
Definition: script_info.cpp:58
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: depend.cpp:129
AIInfo keeps track of all information of an AI, like Author, Description, ...
void AddClassEnd()
Finishes adding a class to the global scope.
Definition: squirrel.cpp:284
const char * name
The name of the configuration setting.