Files @ r27888:73e8956ac824
Branch filter:

Location: cpp/openttd-patchpack/source/src/ai/ai_info.cpp - annotation

Michael Lutz
Feature: [NewGRF] Related Act2 objects for airports and airport tiles.

Airports are similar two stations and industries, both of which have the town as related object.
Airport tiles are similar to industry tiles, which have the industry as related object.
This seems a sensible structure, so let's make it Airport Tile -> Airport -> Town.
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r12738:a48207b124c5
r21410:ae5961f02724
r13098:e677182a57ae
r10696:8dfe83e30d01
r21383:942c32fb8b0e
r21383:942c32fb8b0e
r15598:7c4c457ebe78
r15598:7c4c457ebe78
r15598:7c4c457ebe78
r15598:7c4c457ebe78
r27352:2279f2687a7b
r12738:a48207b124c5
r26708:fcfe8e5e499a
r24108:7efb3e692372
r12738:a48207b124c5
r12738:a48207b124c5
r23088:6710c4c79ac6
r18508:f893337ab5c7
r23088:6710c4c79ac6
r27106:2d95beb51290
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r27106:2d95beb51290
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18510:9d33e9643f80
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r23607:36c15679007d
r25705:db1afb7a7392
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r27369:d93808e810cd
r27369:d93808e810cd
r11118:0461c8a427c2
r11118:0461c8a427c2
r11118:0461c8a427c2
r11720:a2a7bf20700e
r27369:d93808e810cd
r27369:d93808e810cd
r11720:a2a7bf20700e
r11720:a2a7bf20700e
r11720:a2a7bf20700e
r12738:a48207b124c5
r27369:d93808e810cd
r27369:d93808e810cd
r12738:a48207b124c5
r25655:1030dcb7eb52
r12738:a48207b124c5
r12738:a48207b124c5
r12738:a48207b124c5
r27352:2279f2687a7b
r12738:a48207b124c5
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r23607:36c15679007d
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r25705:db1afb7a7392
r10696:8dfe83e30d01
r27352:2279f2687a7b
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r23607:36c15679007d
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r13879:b9c13f7998cb
r13879:b9c13f7998cb
r27352:2279f2687a7b
r13879:b9c13f7998cb
r13879:b9c13f7998cb
r13879:b9c13f7998cb
r11119:63ffa1a1ddd6
r11118:0461c8a427c2
r11118:0461c8a427c2
r11118:0461c8a427c2
r11118:0461c8a427c2
r11118:0461c8a427c2
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10787:bea3f79225f8
r10787:bea3f79225f8
r10787:bea3f79225f8
r10787:bea3f79225f8
r10696:8dfe83e30d01
r11118:0461c8a427c2
r27369:d93808e810cd
r11121:b7c57fb5f2a7
r11121:b7c57fb5f2a7
r11121:b7c57fb5f2a7
r11118:0461c8a427c2
r10696:8dfe83e30d01
r18508:f893337ab5c7
r10696:8dfe83e30d01
r10696:8dfe83e30d01
r10696:8dfe83e30d01
/*
 * This file is part of OpenTTD.
 * 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.
 * 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.
 * 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/>.
 */

/** @file ai_info.cpp Implementation of AIInfo and AILibrary */

#include "../stdafx.h"

#include "../script/squirrel_class.hpp"
#include "ai_info.hpp"
#include "ai_scanner.hpp"
#include "../debug.h"
#include "../string_func.h"
#include "../rev.h"

#include "../safeguards.h"

/**
 * Check if the API version provided by the AI is supported.
 * @param api_version The API version as provided by the AI.
 */
static bool CheckAPIVersion(const std::string &api_version)
{
	static const std::set<std::string> versions = { "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" };
	return versions.find(api_version) != versions.end();
}

#if defined(_WIN32)
#undef GetClassName
#endif /* _WIN32 */
template <> const char *GetClassName<AIInfo, ScriptType::AI>() { return "AIInfo"; }

/* static */ void AIInfo::RegisterAPI(Squirrel *engine)
{
	/* Create the AIInfo class, and add the RegisterAI function */
	DefSQClass<AIInfo, ScriptType::AI> SQAIInfo("AIInfo");
	SQAIInfo.PreRegister(engine);
	SQAIInfo.AddConstructor<void (AIInfo::*)(), 1>(engine, "x");
	SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting");
	SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER");

	/* Pre 1.2 had an AI prefix */
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "AICONFIG_NONE");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "AICONFIG_RANDOM");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "AICONFIG_BOOLEAN");
	SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "AICONFIG_INGAME");

	SQAIInfo.PostRegister(engine);
	engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx");
	engine->AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, 2, "tx");
}

/* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm)
{
	/* Get the AIInfo */
	SQUserPointer instance = nullptr;
	if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, nullptr)) || instance == nullptr) return sq_throwerror(vm, "Pass an instance of a child class of AIInfo to RegisterAI");
	AIInfo *info = (AIInfo *)instance;

	SQInteger res = ScriptInfo::Constructor(vm, info);
	if (res != 0) return res;

	if (info->engine->MethodExists(info->SQ_instance, "MinVersionToLoad")) {
		if (!info->engine->CallIntegerMethod(info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
	} else {
		info->min_loadable_version = info->GetVersion();
	}
	/* When there is an UseAsRandomAI function, call it. */
	if (info->engine->MethodExists(info->SQ_instance, "UseAsRandomAI")) {
		if (!info->engine->CallBoolMethod(info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR;
	} else {
		info->use_as_random = true;
	}
	/* Try to get the API version the AI is written for. */
	if (info->engine->MethodExists(info->SQ_instance, "GetAPIVersion")) {
		if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
		if (!CheckAPIVersion(info->api_version)) {
			Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion());
			return SQ_ERROR;
		}
	} else {
		info->api_version = "0.7";
	}

	/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
	sq_setinstanceup(vm, 2, nullptr);
	/* Register the AI to the base system */
	info->GetScanner()->RegisterScript(info);
	return 0;
}

/* static */ SQInteger AIInfo::DummyConstructor(HSQUIRRELVM vm)
{
	/* Get the AIInfo */
	SQUserPointer instance;
	sq_getinstanceup(vm, 2, &instance, nullptr);
	AIInfo *info = (AIInfo *)instance;
	info->api_version = fmt::format("{}.{}", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4));

	SQInteger res = ScriptInfo::Constructor(vm, info);
	if (res != 0) return res;

	/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
	sq_setinstanceup(vm, 2, nullptr);
	/* Register the AI to the base system */
	static_cast<AIScannerInfo *>(info->GetScanner())->SetDummyAI(info);
	return 0;
}

AIInfo::AIInfo() :
	min_loadable_version(0),
	use_as_random(false)
{
}

bool AIInfo::CanLoadFromVersion(int version) const
{
	if (version == -1) return true;
	return version >= this->min_loadable_version && version <= this->GetVersion();
}


/* static */ void AILibrary::RegisterAPI(Squirrel *engine)
{
	/* Create the AILibrary class, and add the RegisterLibrary function */
	engine->AddClassBegin("AILibrary");
	engine->AddClassEnd();
	engine->AddMethod("RegisterLibrary", &AILibrary::Constructor, 2, "tx");
}

/* static */ SQInteger AILibrary::Constructor(HSQUIRRELVM vm)
{
	/* Create a new library */
	AILibrary *library = new AILibrary();

	SQInteger res = ScriptInfo::Constructor(vm, library);
	if (res != 0) {
		delete library;
		return res;
	}

	/* Cache the category */
	if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
		delete library;
		return SQ_ERROR;
	}

	/* Register the Library to the base system */
	library->GetScanner()->RegisterScript(library);

	return 0;
}