Update to 12.0-beta1
This commit is contained in:
@@ -179,6 +179,7 @@ add_files(
|
||||
script_log.hpp
|
||||
script_map.hpp
|
||||
script_marine.hpp
|
||||
script_newgrf.hpp
|
||||
script_news.hpp
|
||||
script_object.hpp
|
||||
script_order.hpp
|
||||
@@ -246,6 +247,7 @@ add_files(
|
||||
script_log.cpp
|
||||
script_map.cpp
|
||||
script_marine.cpp
|
||||
script_newgrf.cpp
|
||||
script_news.cpp
|
||||
script_object.cpp
|
||||
script_order.cpp
|
||||
|
||||
@@ -13,6 +13,15 @@
|
||||
* functions may still be available if you return an older API version
|
||||
* in GetAPIVersion() in info.nut.
|
||||
*
|
||||
* \b 12.0
|
||||
*
|
||||
* This version is not yet released. The following changes are not set in stone yet.
|
||||
*
|
||||
* API additions:
|
||||
* \li AINewGRF
|
||||
* \li AINewGRFList
|
||||
* \li AIGroup::GetNumVehicles
|
||||
*
|
||||
* \b 1.11.0
|
||||
*
|
||||
* API additions:
|
||||
|
||||
@@ -13,6 +13,14 @@
|
||||
* functions may still be available if you return an older API version
|
||||
* in GetAPIVersion() in info.nut.
|
||||
*
|
||||
* \b 12.0
|
||||
*
|
||||
* This version is not yet released. The following changes are not set in stone yet.
|
||||
*
|
||||
* API additions:
|
||||
* \li GSNewGRF
|
||||
* \li GSNewGRFList
|
||||
*
|
||||
* \b 1.11.0
|
||||
*
|
||||
* API additions:
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
return 1;
|
||||
}
|
||||
|
||||
NetworkAdminGameScript(json.c_str());
|
||||
NetworkAdminGameScript(json);
|
||||
|
||||
sq_pushinteger(vm, 1);
|
||||
return 1;
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
|
||||
ScriptCargoList::ScriptCargoList()
|
||||
{
|
||||
const CargoSpec *cs;
|
||||
FOR_ALL_CARGOSPECS(cs) {
|
||||
for (const CargoSpec *cs : CargoSpec::Iterate()) {
|
||||
this->AddItem(cs->Index());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client)
|
||||
{
|
||||
NetworkClientInfo *ci = FindClientInfo(client);
|
||||
if (ci == nullptr) return nullptr;
|
||||
return stredup(ci->client_name);
|
||||
return stredup(ci->client_name.c_str());
|
||||
}
|
||||
|
||||
/* static */ ScriptCompany::CompanyID ScriptClient::GetCompany(ScriptClient::ClientID client)
|
||||
|
||||
@@ -140,9 +140,9 @@
|
||||
if (quarter > EARLIEST_QUARTER) return -1;
|
||||
|
||||
if (quarter == CURRENT_QUARTER) {
|
||||
return ::Company::Get(company)->cur_economy.delivered_cargo.GetSum<OverflowSafeInt<int32, INT32_MAX, INT32_MIN> >();
|
||||
return ::Company::Get(company)->cur_economy.delivered_cargo.GetSum<OverflowSafeInt32>();
|
||||
}
|
||||
return ::Company::Get(company)->old_economy[quarter - 1].delivered_cargo.GetSum<OverflowSafeInt<int32, INT32_MAX, INT32_MIN> >();
|
||||
return ::Company::Get(company)->old_economy[quarter - 1].delivered_cargo.GetSum<OverflowSafeInt32>();
|
||||
}
|
||||
|
||||
/* static */ int32 ScriptCompany::GetQuarterlyPerformanceRating(ScriptCompany::CompanyID company, uint32 quarter)
|
||||
@@ -260,7 +260,7 @@
|
||||
|
||||
/* static */ bool ScriptCompany::SetAutoRenewStatus(bool autorenew)
|
||||
{
|
||||
return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.engine_renew"), autorenew ? 1 : 0, CMD_CHANGE_COMPANY_SETTING);
|
||||
return ScriptObject::DoCommand(0, 0, autorenew ? 1 : 0, CMD_CHANGE_COMPANY_SETTING, "company.engine_renew");
|
||||
}
|
||||
|
||||
/* static */ bool ScriptCompany::GetAutoRenewStatus(CompanyID company)
|
||||
@@ -273,7 +273,7 @@
|
||||
|
||||
/* static */ bool ScriptCompany::SetAutoRenewMonths(int16 months)
|
||||
{
|
||||
return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.engine_renew_months"), months, CMD_CHANGE_COMPANY_SETTING);
|
||||
return ScriptObject::DoCommand(0, 0, months, CMD_CHANGE_COMPANY_SETTING, "company.engine_renew_months");
|
||||
}
|
||||
|
||||
/* static */ int16 ScriptCompany::GetAutoRenewMonths(CompanyID company)
|
||||
@@ -288,7 +288,7 @@
|
||||
{
|
||||
EnforcePrecondition(false, money >= 0);
|
||||
EnforcePrecondition(false, (int64)money <= UINT32_MAX);
|
||||
return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.engine_renew_money"), money, CMD_CHANGE_COMPANY_SETTING);
|
||||
return ScriptObject::DoCommand(0, 0, money, CMD_CHANGE_COMPANY_SETTING, "company.engine_renew_money");
|
||||
}
|
||||
|
||||
/* static */ Money ScriptCompany::GetAutoRenewMoney(CompanyID company)
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
* Creating instance of this class switches the company used for queries
|
||||
* and commands.
|
||||
* @param company The new company to switch to.
|
||||
* @note When the instance is destroyed, he restores the company that was
|
||||
* @note When the instance is destroyed, it restores the company that was
|
||||
* current when the instance was created!
|
||||
*/
|
||||
ScriptCompanyMode(int company);
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
seprintf(log_message, lastof(log_message), "Break: %s", message);
|
||||
ScriptLog::Log(ScriptLog::LOG_SQ_ERROR, log_message);
|
||||
|
||||
/* Inform script developer that his script has been paused and
|
||||
/* Inform script developer that their script has been paused and
|
||||
* needs manual action to continue. */
|
||||
ShowAIDebugWindow(ScriptObject::GetRootCompany());
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
* data from the loaded game.
|
||||
* - Finally, #Start is called to start execution of the script.
|
||||
*
|
||||
* See also http://wiki.openttd.org/AI:Save/Load for more details.
|
||||
* See also https://wiki.openttd.org/en/Development/Script/Save%20and%20Load for more details.
|
||||
*
|
||||
* @api ai game
|
||||
*/
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
* notified of the call. To avoid race-conditions between #Save and the
|
||||
* other script code, change variables directly after a #Sleep, it is
|
||||
* very unlikely, to get interrupted at that point in the execution.
|
||||
* See also http://wiki.openttd.org/AI:Save/Load for more details.
|
||||
* See also https://wiki.openttd.org/en/Development/Script/Save%20and%20Load for more details.
|
||||
*
|
||||
* @note No other information is saved than the table returned by #Save.
|
||||
* For example all pending events are lost as soon as the game is loaded.
|
||||
@@ -135,11 +135,20 @@ public:
|
||||
/**
|
||||
* Get the OpenTTD version of this executable. The version is formatted
|
||||
* with the bits having the following meaning:
|
||||
* 28-31 major version
|
||||
* 24-27 minor version
|
||||
* 20-23 build
|
||||
* 24-31 major version + 16.
|
||||
* 20-23 minor version.
|
||||
* 19 1 if it is a release, 0 if it is not.
|
||||
* 0-18 revision number; 0 when the revision is unknown.
|
||||
* You have to subtract 16 from the major version to get the correct
|
||||
* value.
|
||||
*
|
||||
* Prior to OpenTTD 12, the bits have the following meaning:
|
||||
* 28-31 major version.
|
||||
* 24-27 minor version.
|
||||
* 20-23 build.
|
||||
* 19 1 if it is a release, 0 if it is not.
|
||||
* 0-18 revision number; 0 when the revision is unknown.
|
||||
*
|
||||
* @return The version in newgrf format.
|
||||
*/
|
||||
static uint GetVersion();
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
|
||||
/** @file script_date.cpp Implementation of ScriptDate. */
|
||||
|
||||
#include <time.h>
|
||||
#include "../../stdafx.h"
|
||||
#include "script_date.hpp"
|
||||
#include "../../date_func.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/* static */ bool ScriptDate::IsValidDate(Date date)
|
||||
|
||||
@@ -118,23 +118,18 @@ bool ScriptEventCompanyAskMerger::AcceptMerger()
|
||||
return ScriptObject::DoCommand(0, this->owner, 0, CMD_BUY_COMPANY);
|
||||
}
|
||||
|
||||
ScriptEventAdminPort::ScriptEventAdminPort(const char *json) :
|
||||
ScriptEventAdminPort::ScriptEventAdminPort(const std::string &json) :
|
||||
ScriptEvent(ET_ADMIN_PORT),
|
||||
json(stredup(json))
|
||||
json(json)
|
||||
{
|
||||
}
|
||||
|
||||
ScriptEventAdminPort::~ScriptEventAdminPort()
|
||||
{
|
||||
free(this->json);
|
||||
}
|
||||
|
||||
#define SKIP_EMPTY(p) while (*(p) == ' ' || *(p) == '\n' || *(p) == '\r') (p)++;
|
||||
#define RETURN_ERROR(stack) { ScriptLog::Error("Received invalid JSON data from AdminPort."); if (stack != 0) sq_pop(vm, stack); return nullptr; }
|
||||
|
||||
SQInteger ScriptEventAdminPort::GetObject(HSQUIRRELVM vm)
|
||||
{
|
||||
char *p = this->json;
|
||||
const char *p = this->json.c_str();
|
||||
|
||||
if (this->ReadTable(vm, p) == nullptr) {
|
||||
sq_pushnull(vm);
|
||||
@@ -144,9 +139,9 @@ SQInteger ScriptEventAdminPort::GetObject(HSQUIRRELVM vm)
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *ScriptEventAdminPort::ReadString(HSQUIRRELVM vm, char *p)
|
||||
const char *ScriptEventAdminPort::ReadString(HSQUIRRELVM vm, const char *p)
|
||||
{
|
||||
char *value = p;
|
||||
const char *value = p;
|
||||
|
||||
bool escape = false;
|
||||
for (;;) {
|
||||
@@ -168,14 +163,14 @@ char *ScriptEventAdminPort::ReadString(HSQUIRRELVM vm, char *p)
|
||||
p++;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
sq_pushstring(vm, value, -1);
|
||||
*p++ = '"';
|
||||
size_t len = p - value;
|
||||
sq_pushstring(vm, value, len);
|
||||
p++; // Step past the end-of-string marker (")
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char *ScriptEventAdminPort::ReadTable(HSQUIRRELVM vm, char *p)
|
||||
const char *ScriptEventAdminPort::ReadTable(HSQUIRRELVM vm, const char *p)
|
||||
{
|
||||
sq_newtable(vm);
|
||||
|
||||
@@ -218,7 +213,7 @@ char *ScriptEventAdminPort::ReadTable(HSQUIRRELVM vm, char *p)
|
||||
return p;
|
||||
}
|
||||
|
||||
char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, char *p)
|
||||
const char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, const char *p)
|
||||
{
|
||||
SKIP_EMPTY(p);
|
||||
|
||||
@@ -257,7 +252,7 @@ char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, char *p)
|
||||
sq_newarray(vm, 0);
|
||||
|
||||
/* Empty array? */
|
||||
char *p2 = p + 1;
|
||||
const char *p2 = p + 1;
|
||||
SKIP_EMPTY(p2);
|
||||
if (*p2 == ']') {
|
||||
p = p2 + 1;
|
||||
|
||||
@@ -837,8 +837,7 @@ public:
|
||||
/**
|
||||
* @param json The JSON string which got sent.
|
||||
*/
|
||||
ScriptEventAdminPort(const char *json);
|
||||
~ScriptEventAdminPort();
|
||||
ScriptEventAdminPort(const std::string &json);
|
||||
|
||||
/**
|
||||
* Convert an ScriptEvent to the real instance.
|
||||
@@ -853,28 +852,28 @@ public:
|
||||
SQInteger GetObject(HSQUIRRELVM vm);
|
||||
|
||||
private:
|
||||
char *json; ///< The JSON string.
|
||||
std::string json; ///< The JSON string.
|
||||
|
||||
/**
|
||||
* Read a table from a JSON string.
|
||||
* @param vm The VM used.
|
||||
* @param p The (part of the) JSON string reading.
|
||||
*/
|
||||
char *ReadTable(HSQUIRRELVM vm, char *p);
|
||||
const char *ReadTable(HSQUIRRELVM vm, const char *p);
|
||||
|
||||
/**
|
||||
* Read a value from a JSON string.
|
||||
* @param vm The VM used.
|
||||
* @param p The (part of the) JSON string reading.
|
||||
*/
|
||||
char *ReadValue(HSQUIRRELVM vm, char *p);
|
||||
const char *ReadValue(HSQUIRRELVM vm, const char *p);
|
||||
|
||||
/**
|
||||
* Read a string from a JSON string.
|
||||
* @param vm The VM used.
|
||||
* @param p The (part of the) JSON string reading.
|
||||
*/
|
||||
char *ReadString(HSQUIRRELVM vm, char *p);
|
||||
const char *ReadString(HSQUIRRELVM vm, const char *p);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -968,7 +967,7 @@ public:
|
||||
private:
|
||||
uint16 uniqueid; ///< The uniqueid of the question.
|
||||
ScriptCompany::CompanyID company; ///< The company given the answer.
|
||||
ScriptGoal::QuestionButton button; ///< The button he pressed.
|
||||
ScriptGoal::QuestionButton button; ///< The button that was pressed.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ protected:
|
||||
public:
|
||||
/**
|
||||
* Creating instance of this class switches the build mode to Execute.
|
||||
* @note When the instance is destroyed, he restores the mode that was
|
||||
* @note When the instance is destroyed, it restores the mode that was
|
||||
* current when the instance was created!
|
||||
*/
|
||||
ScriptExecMode();
|
||||
|
||||
@@ -17,35 +17,27 @@
|
||||
|
||||
/* static */ bool ScriptGameSettings::IsValid(const char *setting)
|
||||
{
|
||||
uint i;
|
||||
const SettingDesc *sd = GetSettingFromName(setting, &i);
|
||||
return sd != nullptr && sd->desc.cmd != SDT_STRING;
|
||||
const SettingDesc *sd = GetSettingFromName(setting);
|
||||
return sd != nullptr && sd->IsIntSetting();
|
||||
}
|
||||
|
||||
/* static */ int32 ScriptGameSettings::GetValue(const char *setting)
|
||||
{
|
||||
if (!IsValid(setting)) return -1;
|
||||
|
||||
uint index;
|
||||
const SettingDesc *sd = GetSettingFromName(setting, &index);
|
||||
|
||||
void *ptr = GetVariableAddress(&_settings_game, &sd->save);
|
||||
if (sd->desc.cmd == SDT_BOOLX) return *(bool*)ptr;
|
||||
|
||||
return (int32)ReadValue(ptr, sd->save.conv);
|
||||
const SettingDesc *sd = GetSettingFromName(setting);
|
||||
return sd->AsIntSetting()->Read(&_settings_game);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGameSettings::SetValue(const char *setting, int value)
|
||||
{
|
||||
if (!IsValid(setting)) return false;
|
||||
|
||||
uint index;
|
||||
const SettingDesc *sd = GetSettingFromName(setting, &index);
|
||||
const SettingDesc *sd = GetSettingFromName(setting);
|
||||
|
||||
if ((sd->save.conv & SLF_NO_NETWORK_SYNC) != 0) return false;
|
||||
if (sd->desc.cmd != SDT_BOOLX && sd->desc.cmd != SDT_NUMX) return false;
|
||||
if ((sd->flags & SF_NO_NETWORK_SYNC) != 0) return false;
|
||||
|
||||
return ScriptObject::DoCommand(0, index, value, CMD_CHANGE_SETTING);
|
||||
return ScriptObject::DoCommand(0, 0, value, CMD_CHANGE_SETTING, sd->GetName().c_str());
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGameSettings::IsDisabledVehicleType(ScriptVehicle::VehicleType vehicle_type)
|
||||
|
||||
@@ -89,14 +89,14 @@
|
||||
{
|
||||
EnforcePrecondition(false, IsValidGroup(group_id));
|
||||
|
||||
return ScriptObject::DoCommand(0, group_id, enable ? 1 : 0, CMD_SET_GROUP_REPLACE_PROTECTION);
|
||||
return ScriptObject::DoCommand(0, group_id | GroupFlags::GF_REPLACE_PROTECTION, enable ? 1 : 0, CMD_SET_GROUP_FLAG);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGroup::GetAutoReplaceProtection(GroupID group_id)
|
||||
{
|
||||
if (!IsValidGroup(group_id)) return false;
|
||||
|
||||
return ::Group::Get(group_id)->replace_protection;
|
||||
return HasBit(::Group::Get(group_id)->flags, GroupFlags::GF_REPLACE_PROTECTION);
|
||||
}
|
||||
|
||||
/* static */ int32 ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id)
|
||||
@@ -106,6 +106,15 @@
|
||||
return GetGroupNumEngines(ScriptObject::GetCompany(), group_id, engine_id);
|
||||
}
|
||||
|
||||
/* static */ int32 ScriptGroup::GetNumVehicles(GroupID group_id, ScriptVehicle::VehicleType vehicle_type)
|
||||
{
|
||||
bool valid_group = IsValidGroup(group_id);
|
||||
if (!valid_group && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return -1;
|
||||
if (!valid_group && (vehicle_type < ScriptVehicle::VT_RAIL || vehicle_type > ScriptVehicle::VT_AIR)) return -1;
|
||||
|
||||
return GetGroupNumVehicle(ScriptObject::GetCompany(), group_id, valid_group ? ::Group::Get(group_id)->vehicle_type : (::VehicleType)vehicle_type);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGroup::MoveVehicle(GroupID group_id, VehicleID vehicle_id)
|
||||
{
|
||||
EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT);
|
||||
@@ -118,7 +127,7 @@
|
||||
{
|
||||
if (HasWagonRemoval() == enable_removal) return true;
|
||||
|
||||
return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.renew_keep_length"), enable_removal ? 1 : 0, CMD_CHANGE_COMPANY_SETTING);
|
||||
return ScriptObject::DoCommand(0, 0, enable_removal ? 1 : 0, CMD_CHANGE_COMPANY_SETTING, "company.renew_keep_length");
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGroup::HasWagonRemoval()
|
||||
|
||||
@@ -128,6 +128,20 @@ public:
|
||||
*/
|
||||
static int32 GetNumEngines(GroupID group_id, EngineID engine_id);
|
||||
|
||||
/**
|
||||
* Get the total number of vehicles in a given group and its sub-groups.
|
||||
* @param group_id The group to get the number of vehicles in.
|
||||
* @param vehicle_type The type of vehicle of the group.
|
||||
* @pre IsValidGroup(group_id) || group_id == GROUP_ALL || group_id == GROUP_DEFAULT.
|
||||
* @pre IsValidGroup(group_id) || vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL ||
|
||||
* vehicle_type == ScriptVehicle::VT_WATER || vehicle_type == ScriptVehicle::VT_AIR
|
||||
* @return The total number of vehicles in the group with id group_id and it's sub-groups.
|
||||
* @note If the group is valid (neither GROUP_ALL nor GROUP_DEFAULT), the value of
|
||||
* vehicle_type is retrieved from the group itself and not from the input value.
|
||||
* But if the group is GROUP_ALL or GROUP_DEFAULT, then vehicle_type must be valid.
|
||||
*/
|
||||
static int32 GetNumVehicles(GroupID group_id, ScriptVehicle::VehicleType vehicle_type);
|
||||
|
||||
/**
|
||||
* Move a vehicle to a group.
|
||||
* @param group_id The group to move the vehicle to.
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
if (!HasHeliport(industry_id)) return INVALID_TILE;
|
||||
|
||||
const Industry *ind = ::Industry::Get(industry_id);
|
||||
TILE_AREA_LOOP(tile_cur, ind->location) {
|
||||
for (TileIndex tile_cur : ind->location) {
|
||||
if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
|
||||
return tile_cur;
|
||||
}
|
||||
@@ -208,7 +208,7 @@
|
||||
if (!HasDock(industry_id)) return INVALID_TILE;
|
||||
|
||||
const Industry *ind = ::Industry::Get(industry_id);
|
||||
TILE_AREA_LOOP(tile_cur, ind->location) {
|
||||
for (TileIndex tile_cur : ind->location) {
|
||||
if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
|
||||
return tile_cur;
|
||||
}
|
||||
|
||||
@@ -468,8 +468,8 @@ int64 ScriptList::Begin()
|
||||
|
||||
int64 ScriptList::Next()
|
||||
{
|
||||
if (this->initialized == false) {
|
||||
DEBUG(script, 0, "Next() is invalid as Begin() is never called");
|
||||
if (!this->initialized) {
|
||||
Debug(script, 0, "Next() is invalid as Begin() is never called");
|
||||
return 0;
|
||||
}
|
||||
return this->sorter->Next();
|
||||
@@ -482,8 +482,8 @@ bool ScriptList::IsEmpty()
|
||||
|
||||
bool ScriptList::IsEnd()
|
||||
{
|
||||
if (this->initialized == false) {
|
||||
DEBUG(script, 0, "IsEnd() is invalid as Begin() is never called");
|
||||
if (!this->initialized) {
|
||||
Debug(script, 0, "IsEnd() is invalid as Begin() is never called");
|
||||
return true;
|
||||
}
|
||||
return this->sorter->IsEnd();
|
||||
@@ -832,7 +832,7 @@ SQInteger ScriptList::_nexti(HSQUIRRELVM vm)
|
||||
SQInteger idx;
|
||||
sq_getinteger(vm, 2, &idx);
|
||||
|
||||
int val = this->Next();
|
||||
SQInteger val = this->Next();
|
||||
if (this->IsEnd()) {
|
||||
sq_pushnull(vm);
|
||||
return 1;
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
}
|
||||
|
||||
/* Also still print to debug window */
|
||||
DEBUG(script, level, "[%d] [%c] %s", (uint)ScriptObject::GetRootCompany(), logc, log->lines[log->pos]);
|
||||
Debug(script, level, "[{}] [{}] {}", (uint)ScriptObject::GetRootCompany(), logc, log->lines[log->pos]);
|
||||
InvalidateWindowData(WC_AI_DEBUG, 0, ScriptObject::GetRootCompany());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class ScriptLog : public ScriptObject {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Log levels; The value is also feed to DEBUG() lvl.
|
||||
* Log levels; The value is also feed to Debug() lvl.
|
||||
* This has no use for you, as script writer.
|
||||
* @api -all
|
||||
*/
|
||||
|
||||
64
src/script/api/script_newgrf.cpp
Normal file
64
src/script/api/script_newgrf.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 script_newgrf.cpp Implementation of ScriptNewGRF and friends. */
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "script_newgrf.hpp"
|
||||
#include "../../core/bitmath_func.hpp"
|
||||
#include "../../newgrf_config.h"
|
||||
#include "../../string_func.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
ScriptNewGRFList::ScriptNewGRFList()
|
||||
{
|
||||
for (auto c = _grfconfig; c != nullptr; c = c->next) {
|
||||
if (!HasBit(c->flags, GCF_STATIC)) {
|
||||
this->AddItem(BSWAP32(c->ident.grfid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool ScriptNewGRF::IsLoaded(uint32 grfid)
|
||||
{
|
||||
grfid = BSWAP32(grfid); // Match people's expectations.
|
||||
|
||||
for (auto c = _grfconfig; c != nullptr; c = c->next) {
|
||||
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ uint32 ScriptNewGRF::GetVersion(uint32 grfid)
|
||||
{
|
||||
grfid = BSWAP32(grfid); // Match people's expectations.
|
||||
|
||||
for (auto c = _grfconfig; c != nullptr; c = c->next) {
|
||||
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
|
||||
return c->version;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* static */ char *ScriptNewGRF::GetName(uint32 grfid)
|
||||
{
|
||||
grfid = BSWAP32(grfid); // Match people's expectations.
|
||||
|
||||
for (auto c = _grfconfig; c != nullptr; c = c->next) {
|
||||
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
|
||||
return ::stredup(c->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
56
src/script/api/script_newgrf.hpp
Normal file
56
src/script/api/script_newgrf.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 script_newgrf.hpp NewGRF info for scripts. */
|
||||
|
||||
#ifndef SCRIPT_NEWGRF_HPP
|
||||
#define SCRIPT_NEWGRF_HPP
|
||||
|
||||
#include "script_list.hpp"
|
||||
|
||||
/**
|
||||
* Create a list of loaded NewGRFs.
|
||||
* @api ai game
|
||||
* @ingroup ScriptList
|
||||
*/
|
||||
class ScriptNewGRFList : public ScriptList {
|
||||
public:
|
||||
ScriptNewGRFList();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class that handles all NewGRF related functions.
|
||||
* @api ai game
|
||||
*/
|
||||
class ScriptNewGRF : public ScriptObject {
|
||||
public:
|
||||
/**
|
||||
* Check if a NewGRF with a given grfid is loaded.
|
||||
* @param grfid The grfid to check.
|
||||
* @return True if and only if a NewGRF with the given grfid is loaded in the game.
|
||||
*/
|
||||
static bool IsLoaded(uint32 grfid);
|
||||
|
||||
/**
|
||||
* Get the version of a loaded NewGRF.
|
||||
* @param grfid The NewGRF to query.
|
||||
* @pre ScriptNewGRF::IsLoaded(grfid).
|
||||
* @return Version of the NewGRF or 0 if the NewGRF specifies no version.
|
||||
*/
|
||||
static uint32 GetVersion(uint32 grfid);
|
||||
|
||||
/**
|
||||
* Get the name of a loaded NewGRF.
|
||||
* @param grfid The NewGRF to query.
|
||||
* @pre ScriptNewGRF::IsLoaded(grfid).
|
||||
* @return The name of the NewGRF or nullptr if no name is defined.
|
||||
*/
|
||||
static char *GetName(uint32 grfid);
|
||||
};
|
||||
|
||||
#endif /* SCRIPT_NEWGRF_HPP */
|
||||
@@ -85,7 +85,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
/* static */ void ScriptObject::SetLastCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
|
||||
{
|
||||
ScriptStorage *s = GetStorage();
|
||||
DEBUG(script, 6, "SetLastCommand company=%02d tile=%06x p1=%08x p2=%08x cmd=%d", s->root_company, tile, p1, p2, cmd);
|
||||
Debug(script, 6, "SetLastCommand company={:02d} tile={:06x} p1={:08x} p2={:08x} cmd={}", s->root_company, tile, p1, p2, cmd);
|
||||
s->last_tile = tile;
|
||||
s->last_p1 = p1;
|
||||
s->last_p2 = p2;
|
||||
@@ -95,7 +95,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
/* static */ bool ScriptObject::CheckLastCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
|
||||
{
|
||||
ScriptStorage *s = GetStorage();
|
||||
DEBUG(script, 6, "CheckLastCommand company=%02d tile=%06x p1=%08x p2=%08x cmd=%d", s->root_company, tile, p1, p2, cmd);
|
||||
Debug(script, 6, "CheckLastCommand company={:02d} tile={:06x} p1={:08x} p2={:08x} cmd={}", s->root_company, tile, p1, p2, cmd);
|
||||
if (s->last_tile != tile) return false;
|
||||
if (s->last_p1 != p1) return false;
|
||||
if (s->last_p2 != p2) return false;
|
||||
@@ -283,7 +283,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
{
|
||||
char buffer[64];
|
||||
::GetString(buffer, string, lastof(buffer));
|
||||
::str_validate(buffer, lastof(buffer), SVS_NONE);
|
||||
::StrMakeValidInPlace(buffer, lastof(buffer), SVS_NONE);
|
||||
return ::stredup(buffer);
|
||||
}
|
||||
|
||||
@@ -309,10 +309,11 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StrEmpty(text) && (GetCommandFlags(cmd) & CMD_STR_CTRL) == 0) {
|
||||
std::string command_text = text == nullptr ? std::string{} : text;
|
||||
if (!command_text.empty() && (GetCommandFlags(cmd) & CMD_STR_CTRL) == 0) {
|
||||
/* The string must be valid, i.e. not contain special codes. Since some
|
||||
* can be made with GSText, make sure the control codes are removed. */
|
||||
::str_validate(const_cast<char *>(text), text + strlen(text), SVS_NONE);
|
||||
command_text = ::StrMakeValid(command_text, SVS_NONE);
|
||||
}
|
||||
|
||||
/* Set the default callback to return a true/false result of the DoCommand */
|
||||
@@ -328,7 +329,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
if (!estimate_only && _networking && !_generating_world) SetLastCommand(tile, p1, p2, cmd);
|
||||
|
||||
/* Try to perform the command. */
|
||||
CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : nullptr, text, false, estimate_only);
|
||||
CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : nullptr, command_text, false, estimate_only);
|
||||
|
||||
/* We failed; set the error and bail out */
|
||||
if (res.Failed()) {
|
||||
@@ -365,7 +366,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
IncreaseDoCommandCosts(res.GetCost());
|
||||
|
||||
/* Suspend the script player for 1+ ticks, so it simulates multiplayer. This
|
||||
* both avoids confusion when a developer launched his script in a
|
||||
* both avoids confusion when a developer launched the script in a
|
||||
* multiplayer game, but also gives time for the GUI and human player
|
||||
* to interact with the game. */
|
||||
throw Script_Suspend(GetDoCommandDelay(), callback);
|
||||
|
||||
@@ -256,11 +256,11 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
||||
case OT_GOTO_STATION: {
|
||||
const Station *st = ::Station::Get(order->GetDestination());
|
||||
if (st->train_station.tile != INVALID_TILE) {
|
||||
TILE_AREA_LOOP(t, st->train_station) {
|
||||
for (TileIndex t : st->train_station) {
|
||||
if (st->TileBelongsToRailStation(t)) return t;
|
||||
}
|
||||
} else if (st->ship_station.tile != INVALID_TILE) {
|
||||
TILE_AREA_LOOP(t, st->ship_station) {
|
||||
for (TileIndex t : st->ship_station) {
|
||||
if (IsTileType(t, MP_STATION) && (IsDock(t) || IsOilRig(t)) && GetStationIndex(t) == st->index) return t;
|
||||
}
|
||||
} else if (st->bus_stops != nullptr) {
|
||||
@@ -268,7 +268,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
||||
} else if (st->truck_stops != nullptr) {
|
||||
return st->truck_stops->xy;
|
||||
} else if (st->airport.tile != INVALID_TILE) {
|
||||
TILE_AREA_LOOP(tile, st->airport) {
|
||||
for (TileIndex tile : st->airport) {
|
||||
if (st->TileBelongsToAirport(tile) && !::IsHangar(tile)) return tile;
|
||||
}
|
||||
}
|
||||
@@ -278,7 +278,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
||||
case OT_GOTO_WAYPOINT: {
|
||||
const Waypoint *wp = ::Waypoint::Get(order->GetDestination());
|
||||
if (wp->train_station.tile != INVALID_TILE) {
|
||||
TILE_AREA_LOOP(t, wp->train_station) {
|
||||
for (TileIndex t : wp->train_station) {
|
||||
if (wp->TileBelongsToRailStation(t)) return t;
|
||||
}
|
||||
}
|
||||
@@ -564,7 +564,7 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance)
|
||||
/* Make sure we don't go into an infinite loop */
|
||||
int retry = ScriptObject::GetCallbackVariable(3) - 1;
|
||||
if (retry < 0) {
|
||||
DEBUG(script, 0, "Possible infinite loop in SetOrderFlags() detected");
|
||||
Debug(script, 0, "Possible infinite loop in SetOrderFlags() detected");
|
||||
return false;
|
||||
}
|
||||
ScriptObject::SetCallbackVariable(3, retry);
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
SQInteger Peek(HSQUIRRELVM vm);
|
||||
SQInteger Exists(HSQUIRRELVM vm);
|
||||
SQInteger Clear(HSQUIRRELVM vm);
|
||||
#endif
|
||||
#endif /* DOXYGEN_API */
|
||||
|
||||
/**
|
||||
* Check if the queue is empty.
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
int index = 0;
|
||||
const StationSpec *spec = StationClass::GetByGrf(file->grfid, res, &index);
|
||||
if (spec == nullptr) {
|
||||
DEBUG(grf, 1, "%s returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename);
|
||||
Debug(grf, 1, "{} returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename);
|
||||
} else {
|
||||
/* We might have gotten an usable station spec. Try to build it, but if it fails we'll fall back to the original station. */
|
||||
if (ScriptObject::DoCommand(tile, p1, p2 | spec->cls_id | index << 8, CMD_BUILD_RAIL_STATION)) return true;
|
||||
|
||||
@@ -279,7 +279,7 @@ public:
|
||||
class ScriptStationList_Vehicle : public ScriptList {
|
||||
public:
|
||||
/**
|
||||
* @param vehicle_id The vehicle to get the list of stations he has in its orders from.
|
||||
* @param vehicle_id The vehicle to get the list of stations it has in its orders from.
|
||||
*/
|
||||
ScriptStationList_Vehicle(VehicleID vehicle_id);
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ protected:
|
||||
public:
|
||||
/**
|
||||
* Creating instance of this class switches the build mode to Testing.
|
||||
* @note When the instance is destroyed, he restores the mode that was
|
||||
* @note When the instance is destroyed, it restores the mode that was
|
||||
* current when the instance was created!
|
||||
*/
|
||||
ScriptTestMode();
|
||||
|
||||
@@ -82,7 +82,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
sq_getstring(vm, -1, &value);
|
||||
|
||||
this->params[parameter] = stredup(value);
|
||||
ValidateString(this->params[parameter]);
|
||||
StrMakeValidInPlace(this->params[parameter]);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
sq_pop(vm, 3);
|
||||
|
||||
/* Get the 'real' instance of this class */
|
||||
sq_getinstanceup(vm, -1, &real_instance, 0);
|
||||
sq_getinstanceup(vm, -1, &real_instance, nullptr);
|
||||
if (real_instance == nullptr) return SQ_ERROR;
|
||||
|
||||
ScriptText *value = static_cast<ScriptText *>(real_instance);
|
||||
@@ -157,7 +157,7 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
|
||||
if (sq_gettype(vm, 2) == OT_STRING) {
|
||||
const SQChar *key_string;
|
||||
sq_getstring(vm, 2, &key_string);
|
||||
ValidateString(key_string);
|
||||
StrMakeValidInPlace(const_cast<char *>(key_string));
|
||||
|
||||
if (strncmp(key_string, "param_", 6) != 0 || strlen(key_string) > 8) return SQ_ERROR;
|
||||
k = atoi(key_string + 6);
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
* @param ... Optional arguments for this string.
|
||||
*/
|
||||
ScriptText(StringID string, ...);
|
||||
#endif
|
||||
#endif /* DOXYGEN_API */
|
||||
~ScriptText();
|
||||
|
||||
#ifndef DOXYGEN_API
|
||||
|
||||
@@ -21,7 +21,7 @@ void ScriptTileList::AddRectangle(TileIndex t1, TileIndex t2)
|
||||
if (!::IsValidTile(t2)) return;
|
||||
|
||||
TileArea ta(t1, t2);
|
||||
TILE_AREA_LOOP(t, ta) this->AddItem(t);
|
||||
for (TileIndex t : ta) this->AddItem(t);
|
||||
}
|
||||
|
||||
void ScriptTileList::AddTile(TileIndex tile)
|
||||
@@ -37,7 +37,7 @@ void ScriptTileList::RemoveRectangle(TileIndex t1, TileIndex t2)
|
||||
if (!::IsValidTile(t2)) return;
|
||||
|
||||
TileArea ta(t1, t2);
|
||||
TILE_AREA_LOOP(t, ta) this->RemoveItem(t);
|
||||
for (TileIndex t : ta) this->RemoveItem(t);
|
||||
}
|
||||
|
||||
void ScriptTileList::RemoveTile(TileIndex tile)
|
||||
@@ -55,7 +55,7 @@ void ScriptTileList::RemoveTile(TileIndex tile)
|
||||
*/
|
||||
static void FillIndustryCatchment(const Industry *i, int radius, BitmapTileArea &bta)
|
||||
{
|
||||
TILE_AREA_LOOP(cur_tile, i->location) {
|
||||
for (TileIndex cur_tile : i->location) {
|
||||
if (!::IsTileType(cur_tile, MP_INDUSTRY) || ::GetIndustryIndex(cur_tile) != i->index) continue;
|
||||
|
||||
int tx = TileX(cur_tile);
|
||||
@@ -156,7 +156,7 @@ ScriptTileList_StationType::ScriptTileList_StationType(StationID station_id, Scr
|
||||
if ((station_type & ScriptStation::STATION_DOCK) != 0) station_type_value |= (1 << ::STATION_DOCK) | (1 << ::STATION_OILRIG);
|
||||
|
||||
TileArea ta(::TileXY(rect->left, rect->top), rect->right - rect->left + 1, rect->bottom - rect->top + 1);
|
||||
TILE_AREA_LOOP(cur_tile, ta) {
|
||||
for (TileIndex cur_tile : ta) {
|
||||
if (!::IsTileType(cur_tile, MP_STATION)) continue;
|
||||
if (::GetStationIndex(cur_tile) != station_id) continue;
|
||||
if (!HasBit(station_type_value, ::GetStationType(cur_tile))) continue;
|
||||
|
||||
@@ -34,7 +34,9 @@ public:
|
||||
class ScriptWaypointList_Vehicle : public ScriptList {
|
||||
public:
|
||||
/**
|
||||
* @param vehicle_id The vehicle to get the list of waypoints he has in its orders from.
|
||||
* Get the waypoints from the orders of the given vehicle. Duplicates are
|
||||
* not added. Waypoints are added in the order of the vehicle's orders.
|
||||
* @param vehicle_id The vehicle to get the list of waypoints for.
|
||||
*/
|
||||
ScriptWaypointList_Vehicle(VehicleID vehicle_id);
|
||||
};
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
if (ScriptGame::IsMultiplayer()) return;
|
||||
|
||||
if (number == NUMBER_ALL) {
|
||||
DeleteWindowByClass((::WindowClass)window);
|
||||
CloseWindowByClass((::WindowClass)window);
|
||||
return;
|
||||
}
|
||||
|
||||
DeleteWindowById((::WindowClass)window, number);
|
||||
CloseWindowById((::WindowClass)window, number);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptWindow::IsOpen(WindowClass window, uint32 number)
|
||||
|
||||
@@ -37,6 +37,7 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match,
|
||||
this->SetSetting(item.name, InteractiveRandomRange(item.max_value + 1 - item.min_value) + item.min_value);
|
||||
}
|
||||
}
|
||||
|
||||
this->AddRandomDeviation();
|
||||
}
|
||||
}
|
||||
@@ -52,7 +53,9 @@ ScriptConfig::ScriptConfig(const ScriptConfig *config)
|
||||
for (const auto &item : config->settings) {
|
||||
this->settings[stredup(item.first)] = item.second;
|
||||
}
|
||||
this->AddRandomDeviation();
|
||||
|
||||
/* Virtual functions get called statically in constructors, so make it explicit to remove any confusion. */
|
||||
this->ScriptConfig::AddRandomDeviation();
|
||||
}
|
||||
|
||||
ScriptConfig::~ScriptConfig()
|
||||
@@ -176,9 +179,9 @@ int ScriptConfig::GetVersion() const
|
||||
return this->version;
|
||||
}
|
||||
|
||||
void ScriptConfig::StringToSettings(const char *value)
|
||||
void ScriptConfig::StringToSettings(const std::string &value)
|
||||
{
|
||||
char *value_copy = stredup(value);
|
||||
char *value_copy = stredup(value.c_str());
|
||||
char *s = value_copy;
|
||||
|
||||
while (s != nullptr) {
|
||||
@@ -202,8 +205,10 @@ void ScriptConfig::StringToSettings(const char *value)
|
||||
free(value_copy);
|
||||
}
|
||||
|
||||
void ScriptConfig::SettingsToString(char *string, const char *last) const
|
||||
std::string ScriptConfig::SettingsToString() const
|
||||
{
|
||||
char string[1024];
|
||||
char *last = lastof(string);
|
||||
char *s = string;
|
||||
*s = '\0';
|
||||
for (const auto &item : this->settings) {
|
||||
@@ -213,7 +218,7 @@ void ScriptConfig::SettingsToString(char *string, const char *last) const
|
||||
/* Check if the string would fit in the destination */
|
||||
size_t needed_size = strlen(item.first) + 1 + strlen(no);
|
||||
/* If it doesn't fit, skip the next settings */
|
||||
if (string + needed_size > last) break;
|
||||
if (s + needed_size > last) break;
|
||||
|
||||
s = strecat(s, item.first, last);
|
||||
s = strecat(s, "=", last);
|
||||
@@ -223,6 +228,8 @@ void ScriptConfig::SettingsToString(char *string, const char *last) const
|
||||
|
||||
/* Remove the last ',', but only if at least one setting was saved. */
|
||||
if (s != string) s[-1] = '\0';
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
const char *ScriptConfig::GetTextfile(TextfileType type, CompanyID slot) const
|
||||
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
void AnchorUnchangeableSettings();
|
||||
|
||||
/**
|
||||
* Get the value of a setting for this config. It might fallback to his
|
||||
* Get the value of a setting for this config. It might fallback to its
|
||||
* 'info' to find the default value (if not set or if not-custom difficulty
|
||||
* level).
|
||||
* @return The (default) value of the setting, or -1 if the setting was not
|
||||
@@ -169,13 +169,13 @@ public:
|
||||
* Convert a string which is stored in the config file or savegames to
|
||||
* custom settings of this Script.
|
||||
*/
|
||||
void StringToSettings(const char *value);
|
||||
void StringToSettings(const std::string &value);
|
||||
|
||||
/**
|
||||
* Convert the custom settings to a string that can be stored in the config
|
||||
* file or savegames.
|
||||
*/
|
||||
void SettingsToString(char *string, const char *last) const;
|
||||
std::string SettingsToString() const;
|
||||
|
||||
/**
|
||||
* Search a textfile file next to this script.
|
||||
|
||||
@@ -122,14 +122,14 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
||||
while (SQ_SUCCEEDED(sq_next(vm, -2))) {
|
||||
const SQChar *key;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, &key))) return SQ_ERROR;
|
||||
ValidateString(key);
|
||||
StrMakeValidInPlace(const_cast<char *>(key));
|
||||
|
||||
if (strcmp(key, "name") == 0) {
|
||||
const SQChar *sqvalue;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, &sqvalue))) return SQ_ERROR;
|
||||
char *name = stredup(sqvalue);
|
||||
char *s;
|
||||
ValidateString(name);
|
||||
StrMakeValidInPlace(name);
|
||||
|
||||
/* Don't allow '=' and ',' in configure setting names, as we need those
|
||||
* 2 chars to nicely store the settings as a string. */
|
||||
@@ -141,7 +141,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
||||
const SQChar *sqdescription;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, &sqdescription))) return SQ_ERROR;
|
||||
config.description = stredup(sqdescription);
|
||||
ValidateString(config.description);
|
||||
StrMakeValidInPlace(const_cast<char *>(config.description));
|
||||
items |= 0x002;
|
||||
} else if (strcmp(key, "min_value") == 0) {
|
||||
SQInteger res;
|
||||
@@ -226,7 +226,7 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
|
||||
{
|
||||
const SQChar *setting_name;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, &setting_name))) return SQ_ERROR;
|
||||
ValidateString(setting_name);
|
||||
StrMakeValidInPlace(const_cast<char *>(setting_name));
|
||||
|
||||
ScriptConfigItem *config = nullptr;
|
||||
for (auto &item : this->config_list) {
|
||||
@@ -253,7 +253,7 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
|
||||
/* Because squirrel doesn't support identifiers starting with a digit,
|
||||
* we skip the first character. */
|
||||
int key = atoi(key_string + 1);
|
||||
ValidateString(label);
|
||||
StrMakeValidInPlace(const_cast<char *>(label));
|
||||
|
||||
/* !Contains() prevents stredup from leaking. */
|
||||
if (!config->labels->Contains(key)) config->labels->Insert(key, stredup(label));
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/* The reason this exists in C++, is that a user can trash his ai/ or game/ dir,
|
||||
/* The reason this exists in C++, is that a user can trash their ai/ or game/ dir,
|
||||
* leaving no Scripts available. The complexity to solve this is insane, and
|
||||
* therefore the alternative is used, and make sure there is always a Script
|
||||
* available, no matter what the situation is. By defining it in C++, there
|
||||
|
||||
@@ -116,8 +116,7 @@ bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirect
|
||||
{
|
||||
char script_name[32];
|
||||
seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
|
||||
Searchpath sp;
|
||||
FOR_ALL_SEARCHPATHS(sp) {
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
std::string buf = FioGetDirectory(sp, dir);
|
||||
buf += script_name;
|
||||
if (!FileExists(buf)) continue;
|
||||
@@ -125,7 +124,7 @@ bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirect
|
||||
if (this->engine->LoadScript(buf.c_str())) return true;
|
||||
|
||||
ScriptLog::Error("Failed to load API compatibility script");
|
||||
DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf.c_str());
|
||||
Debug(script, 0, "Error compiling / running API compatibility script: {}", buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -153,7 +152,7 @@ void ScriptInstance::Continue()
|
||||
|
||||
void ScriptInstance::Died()
|
||||
{
|
||||
DEBUG(script, 0, "The script died unexpectedly.");
|
||||
Debug(script, 0, "The script died unexpectedly.");
|
||||
this->is_dead = true;
|
||||
this->in_shutdown = true;
|
||||
|
||||
@@ -255,9 +254,12 @@ void ScriptInstance::GameLoop()
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptInstance::CollectGarbage() const
|
||||
void ScriptInstance::CollectGarbage()
|
||||
{
|
||||
if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
|
||||
if (this->is_started && !this->IsDead()) {
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
this->engine->CollectGarbage();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturn(ScriptInstance *instance)
|
||||
@@ -343,8 +345,7 @@ static byte _script_sl_byte; ///< Used as source/target by the script saveload c
|
||||
|
||||
/** SaveLoad array that saves/loads exactly one byte. */
|
||||
static const SaveLoad _script_byte[] = {
|
||||
SLEG_VAR(_script_sl_byte, SLE_UINT8),
|
||||
SLE_END()
|
||||
SLEG_VAR("type", _script_sl_byte, SLE_UINT8),
|
||||
};
|
||||
|
||||
/* static */ bool ScriptInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
|
||||
@@ -363,8 +364,8 @@ static const SaveLoad _script_byte[] = {
|
||||
SQInteger res;
|
||||
sq_getinteger(vm, index, &res);
|
||||
if (!test) {
|
||||
int value = (int)res;
|
||||
SlArray(&value, 1, SLE_INT32);
|
||||
int64 value = (int64)res;
|
||||
SlCopy(&value, 1, SLE_INT64);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -384,7 +385,7 @@ static const SaveLoad _script_byte[] = {
|
||||
if (!test) {
|
||||
_script_sl_byte = (byte)len;
|
||||
SlObject(nullptr, _script_byte);
|
||||
SlArray(const_cast<char *>(buf), len, SLE_CHAR);
|
||||
SlCopy(const_cast<char *>(buf), len, SLE_CHAR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -563,16 +564,17 @@ bool ScriptInstance::IsPaused()
|
||||
SlObject(nullptr, _script_byte);
|
||||
switch (_script_sl_byte) {
|
||||
case SQSL_INT: {
|
||||
int value;
|
||||
SlArray(&value, 1, SLE_INT32);
|
||||
int64 value;
|
||||
SlCopy(&value, 1, IsSavegameVersionBefore(SLV_SCRIPT_INT64) ? SLE_INT32 : SLE_INT64);
|
||||
if (vm != nullptr) sq_pushinteger(vm, (SQInteger)value);
|
||||
return true;
|
||||
}
|
||||
|
||||
case SQSL_STRING: {
|
||||
SlObject(nullptr, _script_byte);
|
||||
static char buf[256];
|
||||
SlArray(buf, _script_sl_byte, SLE_CHAR);
|
||||
static char buf[std::numeric_limits<decltype(_script_sl_byte)>::max()];
|
||||
SlCopy(buf, _script_sl_byte, SLE_CHAR);
|
||||
StrMakeValidInPlace(buf, buf + _script_sl_byte);
|
||||
if (vm != nullptr) sq_pushstring(vm, buf, -1);
|
||||
return true;
|
||||
}
|
||||
@@ -690,7 +692,7 @@ bool ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
|
||||
if (!ScriptObject::CheckLastCommand(tile, p1, p2, cmd)) {
|
||||
DEBUG(script, 1, "DoCommandCallback terminating a script, last command does not match expected command");
|
||||
Debug(script, 1, "DoCommandCallback terminating a script, last command does not match expected command");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
virtual class ScriptInfo *FindLibrary(const char *library, int version) = 0;
|
||||
|
||||
/**
|
||||
* A script in multiplayer waits for the server to handle his DoCommand.
|
||||
* A script in multiplayer waits for the server to handle its DoCommand.
|
||||
* It keeps waiting for this until this function is called.
|
||||
*/
|
||||
void Continue();
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
/**
|
||||
* Let the VM collect any garbage.
|
||||
*/
|
||||
void CollectGarbage() const;
|
||||
void CollectGarbage();
|
||||
|
||||
/**
|
||||
* Get the storage of this script.
|
||||
|
||||
@@ -38,7 +38,7 @@ bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length,
|
||||
try {
|
||||
this->engine->LoadScript(filename.c_str());
|
||||
} catch (Script_FatalError &e) {
|
||||
DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage().c_str(), filename.c_str());
|
||||
Debug(script, 0, "Fatal error '{}' when trying to load the script '{}'.", e.GetErrorMessage(), filename);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -106,7 +106,7 @@ void ScriptScanner::RegisterScript(ScriptInfo *info)
|
||||
|
||||
/* Check if GetShortName follows the rules */
|
||||
if (strlen(info->GetShortName()) != 4) {
|
||||
DEBUG(script, 0, "The script '%s' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName());
|
||||
Debug(script, 0, "The script '{}' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName());
|
||||
delete info;
|
||||
return;
|
||||
}
|
||||
@@ -123,10 +123,10 @@ void ScriptScanner::RegisterScript(ScriptInfo *info)
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(script, 1, "Registering two scripts with the same name and version");
|
||||
DEBUG(script, 1, " 1: %s", this->info_list[script_name]->GetMainScript());
|
||||
DEBUG(script, 1, " 2: %s", info->GetMainScript());
|
||||
DEBUG(script, 1, "The first is taking precedence.");
|
||||
Debug(script, 1, "Registering two scripts with the same name and version");
|
||||
Debug(script, 1, " 1: {}", this->info_list[script_name]->GetMainScript());
|
||||
Debug(script, 1, " 2: {}", info->GetMainScript());
|
||||
Debug(script, 1, "The first is taking precedence.");
|
||||
|
||||
delete info;
|
||||
return;
|
||||
@@ -182,7 +182,7 @@ struct ScriptFileChecksumCreator : FileScanner {
|
||||
byte tmp_md5sum[16];
|
||||
|
||||
/* Open the file ... */
|
||||
FILE *f = FioFOpenFile(filename.c_str(), "rb", this->dir, &size);
|
||||
FILE *f = FioFOpenFile(filename, "rb", this->dir, &size);
|
||||
if (f == nullptr) return false;
|
||||
|
||||
/* ... calculate md5sum... */
|
||||
@@ -224,16 +224,15 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S
|
||||
if (!tar_filename.empty() && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) {
|
||||
/* The main script is in a tar file, so find all files that
|
||||
* are in the same tar and add them to the MD5 checksumming. */
|
||||
TarFileList::iterator tar;
|
||||
FOR_ALL_TARS(tar, dir) {
|
||||
for (const auto &tar : _tar_filelist[dir]) {
|
||||
/* Not in the same tar. */
|
||||
if (tar->second.tar_filename != iter->first) continue;
|
||||
if (tar.second.tar_filename != iter->first) continue;
|
||||
|
||||
/* Check the extension. */
|
||||
const char *ext = strrchr(tar->first.c_str(), '.');
|
||||
const char *ext = strrchr(tar.first.c_str(), '.');
|
||||
if (ext == nullptr || strcasecmp(ext, ".nut") != 0) continue;
|
||||
|
||||
checksum.AddFile(tar->first, 0, tar_filename);
|
||||
checksum.AddFile(tar.first, 0, tar_filename);
|
||||
}
|
||||
} else {
|
||||
char path[MAX_PATH];
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
/** @file squirrel.cpp the implementation of the Squirrel class. It handles all Squirrel-stuff and gives a nice API back to work with. */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <map>
|
||||
#include "../stdafx.h"
|
||||
#include "../debug.h"
|
||||
#include "squirrel_std.hpp"
|
||||
@@ -21,6 +19,9 @@
|
||||
#include <../squirrel/sqvm.h>
|
||||
#include "../core/alloc_func.hpp"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <map>
|
||||
|
||||
/**
|
||||
* In the memory allocator for Squirrel we want to directly use malloc/realloc, so when the OS
|
||||
* does not have enough memory the game does not go into unrecoverable error mode and kill the
|
||||
@@ -206,7 +207,7 @@ void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *so
|
||||
engine->crashed = true;
|
||||
SQPrintFunc *func = engine->print_func;
|
||||
if (func == nullptr) {
|
||||
DEBUG(misc, 0, "[Squirrel] Compile error: %s", buf);
|
||||
Debug(misc, 0, "[Squirrel] Compile error: {}", buf);
|
||||
} else {
|
||||
(*func)(true, buf);
|
||||
}
|
||||
@@ -255,7 +256,7 @@ void Squirrel::RunError(HSQUIRRELVM vm, const SQChar *error)
|
||||
|
||||
SQInteger Squirrel::_RunError(HSQUIRRELVM vm)
|
||||
{
|
||||
const SQChar *sErr = 0;
|
||||
const SQChar *sErr = nullptr;
|
||||
|
||||
if (sq_gettop(vm) >= 1) {
|
||||
if (SQ_SUCCEEDED(sq_getstring(vm, -1, &sErr))) {
|
||||
@@ -339,8 +340,8 @@ void Squirrel::AddClassBegin(const char *class_name, const char *parent_class)
|
||||
sq_pushstring(this->vm, class_name, -1);
|
||||
sq_pushstring(this->vm, parent_class, -1);
|
||||
if (SQ_FAILED(sq_get(this->vm, -3))) {
|
||||
DEBUG(misc, 0, "[squirrel] Failed to initialize class '%s' based on parent class '%s'", class_name, parent_class);
|
||||
DEBUG(misc, 0, "[squirrel] Make sure that '%s' exists before trying to define '%s'", parent_class, class_name);
|
||||
Debug(misc, 0, "[squirrel] Failed to initialize class '{}' based on parent class '{}'", class_name, parent_class);
|
||||
Debug(misc, 0, "[squirrel] Make sure that '{}' exists before trying to define '{}'", parent_class, class_name);
|
||||
return;
|
||||
}
|
||||
sq_newclass(this->vm, SQTrue);
|
||||
@@ -424,7 +425,7 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT
|
||||
/* Find the function-name inside the script */
|
||||
sq_pushstring(this->vm, method_name, -1);
|
||||
if (SQ_FAILED(sq_get(this->vm, -2))) {
|
||||
DEBUG(misc, 0, "[squirrel] Could not find '%s' in the class", method_name);
|
||||
Debug(misc, 0, "[squirrel] Could not find '{}' in the class", method_name);
|
||||
sq_settop(this->vm, top);
|
||||
return false;
|
||||
}
|
||||
@@ -447,7 +448,7 @@ bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_nam
|
||||
if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
|
||||
if (ret._type != OT_STRING) return false;
|
||||
*res = stredup(ObjectToString(&ret));
|
||||
ValidateString(*res);
|
||||
StrMakeValidInPlace(const_cast<char *>(*res));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -489,14 +490,14 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool
|
||||
}
|
||||
|
||||
if (SQ_FAILED(sq_get(vm, -2))) {
|
||||
DEBUG(misc, 0, "[squirrel] Failed to find class by the name '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name);
|
||||
Debug(misc, 0, "[squirrel] Failed to find class by the name '{}{}'", prepend_API_name ? engine->GetAPIName() : "", class_name);
|
||||
sq_settop(vm, oldtop);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create the instance */
|
||||
if (SQ_FAILED(sq_createinstance(vm, -1))) {
|
||||
DEBUG(misc, 0, "[squirrel] Failed to create instance for class '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name);
|
||||
Debug(misc, 0, "[squirrel] Failed to create instance for class '{}{}'", prepend_API_name ? engine->GetAPIName() : "", class_name);
|
||||
sq_settop(vm, oldtop);
|
||||
return false;
|
||||
}
|
||||
@@ -650,8 +651,7 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer
|
||||
}
|
||||
unsigned short bom = 0;
|
||||
if (size >= 2) {
|
||||
size_t sr = fread(&bom, 1, sizeof(bom), file);
|
||||
(void)sr; // Inside tar, no point checking return value of fread
|
||||
[[maybe_unused]] size_t sr = fread(&bom, 1, sizeof(bom), file);
|
||||
}
|
||||
|
||||
SQLEXREADFUNC func;
|
||||
@@ -736,7 +736,7 @@ bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root)
|
||||
}
|
||||
|
||||
vm->_ops_till_suspend = ops_left;
|
||||
DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script);
|
||||
Debug(misc, 0, "[squirrel] Failed to compile '{}'", script);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ public:
|
||||
* @note This will only work just after a function-call from within Squirrel
|
||||
* to your C++ function.
|
||||
*/
|
||||
static bool GetRealInstance(HSQUIRRELVM vm, SQUserPointer *ptr) { return SQ_SUCCEEDED(sq_getinstanceup(vm, 1, ptr, 0)); }
|
||||
static bool GetRealInstance(HSQUIRRELVM vm, SQUserPointer *ptr) { return SQ_SUCCEEDED(sq_getinstanceup(vm, 1, ptr, nullptr)); }
|
||||
|
||||
/**
|
||||
* Get the Squirrel-instance pointer.
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
/**
|
||||
* This defines a method inside a class for Squirrel with defined params.
|
||||
* @note If you define nparam, make sure that he first param is always 'x',
|
||||
* @note If you define nparam, make sure that the first param is always 'x',
|
||||
* which is the 'this' inside the function. This is hidden from the rest
|
||||
* of the code, but without it calling your function will fail!
|
||||
*/
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
|
||||
/**
|
||||
* This defines a static method inside a class for Squirrel with defined params.
|
||||
* @note If you define nparam, make sure that he first param is always 'x',
|
||||
* @note If you define nparam, make sure that the first param is always 'x',
|
||||
* which is the 'this' inside the function. This is hidden from the rest
|
||||
* of the code, but without it calling your function will fail!
|
||||
*/
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace SQConvert {
|
||||
char *tmp_str = stredup(tmp);
|
||||
sq_poptop(vm);
|
||||
ptr->push_back((void *)tmp_str);
|
||||
str_validate(tmp_str, tmp_str + strlen(tmp_str));
|
||||
StrMakeValidInPlace(tmp_str);
|
||||
return tmp_str;
|
||||
}
|
||||
|
||||
@@ -754,9 +754,9 @@ namespace SQConvert {
|
||||
sq_pop(vm, 3);
|
||||
|
||||
/* Get the 'real' instance of this class */
|
||||
sq_getinstanceup(vm, 1, &real_instance, 0);
|
||||
sq_getinstanceup(vm, 1, &real_instance, nullptr);
|
||||
/* Get the real function pointer */
|
||||
sq_getuserdata(vm, nparam, &ptr, 0);
|
||||
sq_getuserdata(vm, nparam, &ptr, nullptr);
|
||||
if (real_instance == nullptr) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call");
|
||||
/* Remove the userdata from the stack */
|
||||
sq_pop(vm, 1);
|
||||
@@ -796,9 +796,9 @@ namespace SQConvert {
|
||||
sq_pop(vm, 3);
|
||||
|
||||
/* Get the 'real' instance of this class */
|
||||
sq_getinstanceup(vm, 1, &real_instance, 0);
|
||||
sq_getinstanceup(vm, 1, &real_instance, nullptr);
|
||||
/* Get the real function pointer */
|
||||
sq_getuserdata(vm, nparam, &ptr, 0);
|
||||
sq_getuserdata(vm, nparam, &ptr, nullptr);
|
||||
if (real_instance == nullptr) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call");
|
||||
/* Remove the userdata from the stack */
|
||||
sq_pop(vm, 1);
|
||||
@@ -820,7 +820,7 @@ namespace SQConvert {
|
||||
SQUserPointer ptr = nullptr;
|
||||
|
||||
/* Get the real function pointer */
|
||||
sq_getuserdata(vm, nparam, &ptr, 0);
|
||||
sq_getuserdata(vm, nparam, &ptr, nullptr);
|
||||
|
||||
try {
|
||||
/* Delegate it to a template that can handle this specific function */
|
||||
@@ -844,7 +844,7 @@ namespace SQConvert {
|
||||
SQUserPointer ptr = nullptr;
|
||||
|
||||
/* Get the real function pointer */
|
||||
sq_getuserdata(vm, nparam, &ptr, 0);
|
||||
sq_getuserdata(vm, nparam, &ptr, nullptr);
|
||||
/* Remove the userdata from the stack */
|
||||
sq_pop(vm, 1);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ SQInteger SquirrelStd::require(HSQUIRRELVM vm)
|
||||
SQStackInfos si;
|
||||
sq_stackinfos(vm, 1, &si);
|
||||
if (si.source == nullptr) {
|
||||
DEBUG(misc, 0, "[squirrel] Couldn't detect the script-name of the 'require'-caller; this should never happen!");
|
||||
Debug(misc, 0, "[squirrel] Couldn't detect the script-name of the 'require'-caller; this should never happen!");
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user