Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -43,23 +43,23 @@ foreach(API "ai;AI" "game;GS" "template;Template")
|
||||
if("${SCRIPT_API_FILE}" MATCHES ".*script_controller.*")
|
||||
continue()
|
||||
endif()
|
||||
get_filename_component(SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE}" NAME)
|
||||
get_filename_component(SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE}" NAME_WE)
|
||||
string(REPLACE "script_" "${APILC}_" SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE_NAME}")
|
||||
set(SCRIPT_API_BINARY_FILE "${CMAKE_BINARY_DIR}/generated/script/api/${APILC}/${SCRIPT_API_FILE_NAME}.sq")
|
||||
set(SCRIPT_API_BINARY_FILE "${CMAKE_BINARY_DIR}/generated/script/api/${APILC}/${SCRIPT_API_FILE_NAME}.sq.hpp")
|
||||
|
||||
add_custom_command_timestamp(OUTPUT ${SCRIPT_API_BINARY_FILE}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DSCRIPT_API_SOURCE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/squirrel_export.hpp.sq.in
|
||||
-DSCRIPT_API_SOURCE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/squirrel_export.sq.hpp.in
|
||||
-DSCRIPT_API_BINARY_FILE=${SCRIPT_API_BINARY_FILE}
|
||||
-DSCRIPT_API_FILE=${SCRIPT_API_FILE}
|
||||
-DAPIUC=${APIUC}
|
||||
-DAPILC=${APILC}
|
||||
-P ${CMAKE_SOURCE_DIR}/cmake/scripts/SquirrelExport.cmake
|
||||
MAIN_DEPENDENCY ${SCRIPT_API_FILE}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/squirrel_export.hpp.sq.in
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/squirrel_export.sq.hpp.in
|
||||
${CMAKE_SOURCE_DIR}/cmake/scripts/SquirrelExport.cmake
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating ${APILC}/${SCRIPT_API_FILE_NAME}.sq"
|
||||
COMMENT "Generating ${APILC}/${SCRIPT_API_FILE_NAME}.sq.hpp"
|
||||
)
|
||||
list(APPEND SCRIPT_${APIUC}_BINARY_FILES ${SCRIPT_API_BINARY_FILE})
|
||||
endforeach()
|
||||
@@ -73,7 +73,7 @@ foreach(API "ai;AI" "game;GS" "template;Template")
|
||||
)
|
||||
|
||||
if(NOT "${APILC}" STREQUAL "template")
|
||||
list(APPEND SCRIPT_${APIUC}_BINARY_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${APILC}/${APILC}_controller.hpp.sq")
|
||||
list(APPEND SCRIPT_${APIUC}_BINARY_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${APILC}/${APILC}_controller.sq.hpp")
|
||||
set(INCLUDES_BINARY_FILE "${CMAKE_BINARY_DIR}/generated/script/api/${APILC}/${APILC}_includes.hpp")
|
||||
set(API_FILES "${CMAKE_CURRENT_BINARY_DIR}/${APILC}.files")
|
||||
file(GENERATE OUTPUT ${API_FILES} CONTENT "${SCRIPT_${APIUC}_BINARY_FILES}")
|
||||
|
||||
@@ -7,24 +7,24 @@
|
||||
|
||||
#include "../script_controller.hpp"
|
||||
|
||||
template <> SQInteger PushClassName<ScriptController, ScriptType::AI>(HSQUIRRELVM vm) { sq_pushstring(vm, "AIController", -1); return 1; }
|
||||
template <> SQInteger PushClassName<ScriptController, ScriptType::AI>(HSQUIRRELVM vm) { sq_pushstring(vm, "AIController"); return 1; }
|
||||
|
||||
void SQAIController_Register(Squirrel *engine)
|
||||
void SQAIController_Register(Squirrel &engine)
|
||||
{
|
||||
DefSQClass<ScriptController, ScriptType::AI> SQAIController("AIController");
|
||||
SQAIController.PreRegister(engine);
|
||||
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", 1, ".");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetOpsTillSuspend, "GetOpsTillSuspend", 1, ".");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::SetCommandDelay, "SetCommandDelay", 2, ".i");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Sleep, "Sleep", 2, ".i");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Break, "Break", 2, ".s");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetSetting, "GetSetting", 2, ".s");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetVersion, "GetVersion", 1, ".");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Print, "Print", 3, ".bs");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", ".");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetOpsTillSuspend, "GetOpsTillSuspend", ".");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::SetCommandDelay, "SetCommandDelay", ".i");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Sleep, "Sleep", ".i");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Break, "Break", ".s");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetSetting, "GetSetting", ".s");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetVersion, "GetVersion", ".");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Print, "Print", ".bs");
|
||||
|
||||
SQAIController.PostRegister(engine);
|
||||
|
||||
/* Register the import statement to the global scope */
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Import, "import", 4, ".ssi");
|
||||
SQAIController.DefSQStaticMethod(engine, &ScriptController::Import, "import", ".ssi");
|
||||
}
|
||||
@@ -27,11 +27,15 @@
|
||||
* \li AICargo::CC_NON_POURABLE
|
||||
* \li AICargo::CC_POTABLE
|
||||
* \li AICargo::CC_NON_POTABLE
|
||||
* \li AIVehicleList_Waypoint
|
||||
* \li AIError::ERR_BRIDGE_TOO_LOW
|
||||
*
|
||||
* Other changes:
|
||||
* \li AIBridge::GetBridgeID renamed to AIBridge::GetBridgeType
|
||||
* \li AIWaypoint::GetWaypointID now returns the StationID of any type of waypoint
|
||||
* \li AIList instances can now be saved
|
||||
* \li AIVehicleList_Station accepts an optional AIVehicle::VehicleType parameter
|
||||
* \li AIList instances can now be cloned
|
||||
*
|
||||
* \b 14.0
|
||||
*
|
||||
|
||||
@@ -80,7 +80,7 @@ BEGIN {
|
||||
/^( *)class/ {
|
||||
if (cls_level == 0) {
|
||||
if (api_selected == "") {
|
||||
print "Class '"$2"' has no @api. It won't be published to any API." > "/dev/stderr"
|
||||
printf "%s:%d: %s\n", FILENAME, NR, "Class '"$2"' has no @api. It won't be published to any API." > "/dev/stderr"
|
||||
api_selected = "false"
|
||||
}
|
||||
public = "false"
|
||||
@@ -105,7 +105,7 @@ BEGIN {
|
||||
}
|
||||
api_selected = ""
|
||||
} else {
|
||||
print "Classes nested too deep" > "/dev/stderr"
|
||||
printf "%s:%d: %s\n", FILENAME, NR, "Classes nested too deep" > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
cls_level++
|
||||
@@ -279,7 +279,7 @@ BEGIN {
|
||||
}
|
||||
if (match($0, "~")) {
|
||||
if (api_selected != "") {
|
||||
print "Destructor for '"cls"' has @api. Tag ignored." > "/dev/stderr"
|
||||
printf "%s:%d: %s\n", FILENAME, NR, "Destructor for '"cls"' has @api. Tag ignored." > "/dev/stderr"
|
||||
api_selected = ""
|
||||
}
|
||||
next
|
||||
|
||||
+11
-11
@@ -7,24 +7,24 @@
|
||||
|
||||
#include "../script_controller.hpp"
|
||||
|
||||
template <> SQInteger PushClassName<ScriptController, ScriptType::GS>(HSQUIRRELVM vm) { sq_pushstring(vm, "GSController", -1); return 1; }
|
||||
template <> SQInteger PushClassName<ScriptController, ScriptType::GS>(HSQUIRRELVM vm) { sq_pushstring(vm, "GSController"); return 1; }
|
||||
|
||||
void SQGSController_Register(Squirrel *engine)
|
||||
void SQGSController_Register(Squirrel &engine)
|
||||
{
|
||||
DefSQClass<ScriptController, ScriptType::GS> SQGSController("GSController");
|
||||
SQGSController.PreRegister(engine);
|
||||
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", 1, ".");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetOpsTillSuspend, "GetOpsTillSuspend", 1, ".");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::SetCommandDelay, "SetCommandDelay", 2, ".i");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Sleep, "Sleep", 2, ".i");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Break, "Break", 2, ".s");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetSetting, "GetSetting", 2, ".s");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetVersion, "GetVersion", 1, ".");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Print, "Print", 3, ".bs");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", ".");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetOpsTillSuspend, "GetOpsTillSuspend", ".");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::SetCommandDelay, "SetCommandDelay", ".i");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Sleep, "Sleep", ".i");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Break, "Break", ".s");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetSetting, "GetSetting", ".s");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetVersion, "GetVersion", ".");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Print, "Print", ".bs");
|
||||
|
||||
SQGSController.PostRegister(engine);
|
||||
|
||||
/* Register the import statement to the global scope */
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Import, "import", 4, ".ssi");
|
||||
SQGSController.DefSQStaticMethod(engine, &ScriptController::Import, "import", ".ssi");
|
||||
}
|
||||
@@ -27,11 +27,16 @@
|
||||
* \li GSCargo::CC_NON_POURABLE
|
||||
* \li GSCargo::CC_POTABLE
|
||||
* \li GSCargo::CC_NON_POTABLE
|
||||
* \li GSVehicleList_Waypoint
|
||||
* \li GSBaseStation::GetOwner
|
||||
* \li GSError:ERR_BRIDGE_TOO_LOW
|
||||
*
|
||||
* Other changes:
|
||||
* \li GSBridge::GetBridgeID renamed to GSBridge::GetBridgeType
|
||||
* \li GSWaypoint::GetWaypointID now returns the StationID of any type of waypoint
|
||||
* \li GSList instances can now be saved
|
||||
* \li GSVehicleList_Station accepts an optional GSVehicle::VehicleType parameter
|
||||
* \li GSList instances can now be cloned
|
||||
*
|
||||
* \b 14.0
|
||||
*
|
||||
|
||||
@@ -45,10 +45,10 @@ bool ScriptAdminMakeJSON(nlohmann::json &json, HSQUIRRELVM vm, SQInteger index,
|
||||
}
|
||||
|
||||
case OT_STRING: {
|
||||
const SQChar *buf;
|
||||
sq_getstring(vm, index, &buf);
|
||||
std::string_view view;
|
||||
sq_getstring(vm, index, view);
|
||||
|
||||
json = std::string(buf);
|
||||
json = view;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -78,9 +78,9 @@ bool ScriptAdminMakeJSON(nlohmann::json &json, HSQUIRRELVM vm, SQInteger index,
|
||||
sq_pushnull(vm);
|
||||
while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
|
||||
sq_tostring(vm, -2);
|
||||
const SQChar *buf;
|
||||
sq_getstring(vm, -1, &buf);
|
||||
std::string key = std::string(buf);
|
||||
std::string_view view;
|
||||
sq_getstring(vm, -1, view);
|
||||
std::string key{view};
|
||||
sq_pop(vm, 1);
|
||||
|
||||
nlohmann::json value;
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
if (_settings_game.economy.station_noise_level) {
|
||||
uint dist;
|
||||
const auto &layout = as->layouts[0];
|
||||
AirportGetNearestTown(as, layout.rotation, tile, AirportTileTableIterator(layout.tiles.data(), tile), dist);
|
||||
AirportGetNearestTown(as, layout.rotation, tile, AirportTileTableIterator(layout.tiles, tile), dist);
|
||||
return GetAirportNoiseLevelForDistance(as, dist);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
|
||||
uint dist;
|
||||
const auto &layout = as->layouts[0];
|
||||
return AirportGetNearestTown(as, layout.rotation, tile, AirportTileTableIterator(layout.tiles.data(), tile), dist)->index;
|
||||
return AirportGetNearestTown(as, layout.rotation, tile, AirportTileTableIterator(layout.tiles, tile), dist)->index;
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptAirport::GetMaintenanceCostFactor(AirportType type)
|
||||
|
||||
@@ -147,7 +147,7 @@ public:
|
||||
* @exception ScriptError::ERR_AREA_NOT_CLEAR
|
||||
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
|
||||
* @exception ScriptError::ERR_LOCAL_AUTHORITY_REFUSES
|
||||
* @exception ScriptStation::ERR_STATION_TOO_LARGE
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
|
||||
* @return Whether the airport has been/can be build or not.
|
||||
*/
|
||||
|
||||
@@ -49,7 +49,7 @@ void ScriptAsyncMode::FinalRelease()
|
||||
{
|
||||
if (this->GetDoCommandAsyncModeInstance() != this) {
|
||||
/* Ignore this error if the script is not alive. */
|
||||
if (ScriptObject::GetActiveInstance()->IsAlive()) {
|
||||
if (ScriptObject::GetActiveInstance().IsAlive()) {
|
||||
throw Script_FatalError("Asyncmode object was removed while it was not the latest *Mode object created.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,17 @@
|
||||
return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity() || st->owner == OWNER_NONE);
|
||||
}
|
||||
|
||||
/* static */ ScriptCompany::CompanyID ScriptBaseStation::GetOwner(StationID station_id)
|
||||
{
|
||||
if (!IsValidBaseStation(station_id)) return ScriptCompany::COMPANY_INVALID;
|
||||
return ScriptCompany::ToScriptCompanyID(::BaseStation::Get(station_id)->owner);
|
||||
}
|
||||
|
||||
/* static */ std::optional<std::string> ScriptBaseStation::GetName(StationID station_id)
|
||||
{
|
||||
if (!IsValidBaseStation(station_id)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(::Station::IsValidID(station_id) ? STR_STATION_NAME : STR_WAYPOINT_NAME, station_id));
|
||||
return ::StrMakeValid(::GetString(::Station::IsValidID(station_id) ? STR_STATION_NAME : STR_WAYPOINT_NAME, station_id), {});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptBaseStation::SetName(StationID station_id, Text *name)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define SCRIPT_BASESTATION_HPP
|
||||
|
||||
#include "script_text.hpp"
|
||||
#include "script_company.hpp"
|
||||
#include "script_date.hpp"
|
||||
#include "../../station_type.h"
|
||||
|
||||
@@ -32,6 +33,15 @@ public:
|
||||
*/
|
||||
static bool IsValidBaseStation(StationID station_id);
|
||||
|
||||
/**
|
||||
* Get the owner of a basestation.
|
||||
* @param station_id The basestation to get the owner of.
|
||||
* @pre IsValidBaseStation(station_id).
|
||||
* @return The owner the basestation has.
|
||||
* @api -ai
|
||||
*/
|
||||
static ScriptCompany::CompanyID GetOwner(StationID station_id);
|
||||
|
||||
/**
|
||||
* Get the name of a basestation.
|
||||
* @param station_id The basestation to get the name of.
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
* Helper function to connect a just built bridge to nearby roads.
|
||||
* @param instance The script instance we have to built the road for.
|
||||
*/
|
||||
static void _DoCommandReturnBuildBridge2(class ScriptInstance *instance)
|
||||
static void _DoCommandReturnBuildBridge2(class ScriptInstance &instance)
|
||||
{
|
||||
if (!ScriptBridge::_BuildBridgeRoad2()) {
|
||||
ScriptInstance::DoCommandReturn(instance);
|
||||
@@ -59,7 +59,7 @@ static void _DoCommandReturnBuildBridge2(class ScriptInstance *instance)
|
||||
* Helper function to connect a just built bridge to nearby roads.
|
||||
* @param instance The script instance we have to built the road for.
|
||||
*/
|
||||
static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance)
|
||||
static void _DoCommandReturnBuildBridge1(class ScriptInstance &instance)
|
||||
{
|
||||
if (!ScriptBridge::_BuildBridgeRoad1()) {
|
||||
ScriptInstance::DoCommandReturn(instance);
|
||||
@@ -135,7 +135,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance)
|
||||
EnforcePrecondition(std::nullopt, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER);
|
||||
if (!IsValidBridge(bridge_type)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(vehicle_type == ScriptVehicle::VT_WATER ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : ::GetBridgeSpec(bridge_type)->transport_name[vehicle_type]));
|
||||
return ::StrMakeValid(::GetString(vehicle_type == ScriptVehicle::VT_WATER ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : ::GetBridgeSpec(bridge_type)->transport_name[vehicle_type]), {});
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptBridge::GetMaxSpeed(BridgeType bridge_type)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
{
|
||||
if (!IsValidCargo(cargo_type)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_JUST_CARGO_LIST, 1ULL << cargo_type));
|
||||
return ::StrMakeValid(::GetString(STR_JUST_CARGO_LIST, 1ULL << cargo_type), {});
|
||||
}
|
||||
|
||||
/* static */ std::optional<std::string> ScriptCargo::GetCargoLabel(CargoType cargo_type)
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
company = ResolveCompanyID(company);
|
||||
if (company == ScriptCompany::COMPANY_INVALID) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_COMPANY_NAME, ScriptCompany::FromScriptCompanyID(company)));
|
||||
return ::StrMakeValid(::GetString(STR_COMPANY_NAME, ScriptCompany::FromScriptCompanyID(company)), {});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptCompany::SetPresidentName(Text *name)
|
||||
@@ -99,7 +99,7 @@
|
||||
company = ResolveCompanyID(company);
|
||||
if (company == ScriptCompany::COMPANY_INVALID) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_PRESIDENT_NAME, ScriptCompany::FromScriptCompanyID(company)));
|
||||
return ::StrMakeValid(::GetString(STR_PRESIDENT_NAME, ScriptCompany::FromScriptCompanyID(company)), {});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptCompany::SetPresidentGender(Gender gender)
|
||||
@@ -108,12 +108,18 @@
|
||||
EnforcePrecondition(false, gender == GENDER_MALE || gender == GENDER_FEMALE);
|
||||
EnforcePrecondition(false, GetPresidentGender(ScriptCompany::COMPANY_SELF) != gender);
|
||||
|
||||
Randomizer &randomizer = ScriptObject::GetRandomizer();
|
||||
CompanyManagerFace cmf;
|
||||
GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (randomizer.Next() & (1 << ETHNICITY_BLACK)));
|
||||
RandomCompanyManagerFaceBits(cmf, ge, false, randomizer);
|
||||
assert(GetNumCompanyManagerFaceStyles() >= 2); /* At least two styles are needed to fake a gender. */
|
||||
|
||||
return ScriptObject::Command<CMD_SET_COMPANY_MANAGER_FACE>::Do(cmf);
|
||||
/* Company faces no longer have a defined gender, so pick a random face style instead. */
|
||||
Randomizer &randomizer = ScriptObject::GetRandomizer();
|
||||
CompanyManagerFace cmf{};
|
||||
do {
|
||||
cmf.style = randomizer.Next(GetNumCompanyManagerFaceStyles());
|
||||
} while ((HasBit(cmf.style, 0) ? GENDER_FEMALE : GENDER_MALE) != gender);
|
||||
|
||||
RandomiseCompanyManagerFaceBits(cmf, GetCompanyManagerFaceVars(cmf.style), randomizer);
|
||||
|
||||
return ScriptObject::Command<CMD_SET_COMPANY_MANAGER_FACE>::Do(cmf.style, cmf.bits);
|
||||
}
|
||||
|
||||
/* static */ ScriptCompany::Gender ScriptCompany::GetPresidentGender(ScriptCompany::CompanyID company)
|
||||
@@ -121,8 +127,10 @@
|
||||
company = ResolveCompanyID(company);
|
||||
if (company == ScriptCompany::COMPANY_INVALID) return GENDER_INVALID;
|
||||
|
||||
GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(Company::Get(ScriptCompany::FromScriptCompanyID(company))->face, CMFV_GEN_ETHN, GE_WM);
|
||||
return HasBit(ge, ::GENDER_FEMALE) ? GENDER_FEMALE : GENDER_MALE;
|
||||
/* Company faces no longer have a defined gender, so fake one based on the style index. This might not match
|
||||
* the face appearance. */
|
||||
const auto &cmf = ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->face;
|
||||
return HasBit(cmf.style, 0) ? GENDER_FEMALE : GENDER_MALE;
|
||||
}
|
||||
|
||||
/* static */ Money ScriptCompany::GetQuarterlyIncome(ScriptCompany::CompanyID company, SQInteger quarter)
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
{
|
||||
if (_network_dedicated || !_settings_client.gui.ai_developer_tools) return;
|
||||
|
||||
ScriptObject::GetActiveInstance()->Pause();
|
||||
ScriptObject::GetActiveInstance().Pause();
|
||||
|
||||
ScriptLog::Log(ScriptLogTypes::LOG_SQ_ERROR, fmt::format("Break: {}", message));
|
||||
|
||||
@@ -76,17 +76,17 @@ ScriptController::ScriptController(::CompanyID company) :
|
||||
|
||||
/* static */ uint ScriptController::GetTick()
|
||||
{
|
||||
return ScriptObject::GetActiveInstance()->GetController()->ticks;
|
||||
return ScriptObject::GetActiveInstance().GetController().ticks;
|
||||
}
|
||||
|
||||
/* static */ int ScriptController::GetOpsTillSuspend()
|
||||
{
|
||||
return ScriptObject::GetActiveInstance()->GetOpsTillSuspend();
|
||||
return ScriptObject::GetActiveInstance().GetOpsTillSuspend();
|
||||
}
|
||||
|
||||
/* static */ int ScriptController::GetSetting(const std::string &name)
|
||||
{
|
||||
return ScriptObject::GetActiveInstance()->GetSetting(name);
|
||||
return ScriptObject::GetActiveInstance().GetSetting(name);
|
||||
}
|
||||
|
||||
/* static */ uint ScriptController::GetVersion()
|
||||
@@ -96,11 +96,11 @@ ScriptController::ScriptController(::CompanyID company) :
|
||||
|
||||
/* static */ HSQOBJECT ScriptController::Import(const std::string &library, const std::string &class_name, int version)
|
||||
{
|
||||
ScriptController *controller = ScriptObject::GetActiveInstance()->GetController();
|
||||
Squirrel *engine = ScriptObject::GetActiveInstance()->engine;
|
||||
HSQUIRRELVM vm = engine->GetVM();
|
||||
ScriptController &controller = ScriptObject::GetActiveInstance().GetController();
|
||||
Squirrel &engine = *ScriptObject::GetActiveInstance().engine;
|
||||
HSQUIRRELVM vm = engine.GetVM();
|
||||
|
||||
ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version);
|
||||
ScriptInfo *lib = ScriptObject::GetActiveInstance().FindLibrary(library, version);
|
||||
if (lib == nullptr) {
|
||||
throw sq_throwerror(vm, fmt::format("couldn't find library '{}' with version {}", library, version));
|
||||
}
|
||||
@@ -114,37 +114,37 @@ ScriptController::ScriptController(::CompanyID company) :
|
||||
|
||||
std::string fake_class;
|
||||
|
||||
LoadedLibraryList::iterator it = controller->loaded_library.find(library_name);
|
||||
if (it != controller->loaded_library.end()) {
|
||||
LoadedLibraryList::iterator it = controller.loaded_library.find(library_name);
|
||||
if (it != controller.loaded_library.end()) {
|
||||
fake_class = (*it).second;
|
||||
} else {
|
||||
int next_number = ++controller->loaded_library_count;
|
||||
int next_number = ++controller.loaded_library_count;
|
||||
|
||||
/* Create a new fake internal name */
|
||||
fake_class = fmt::format("_internalNA{}", next_number);
|
||||
|
||||
/* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, fake_class, -1);
|
||||
sq_pushstring(vm, fake_class);
|
||||
sq_newclass(vm, SQFalse);
|
||||
/* Load the library */
|
||||
if (!engine->LoadScript(vm, lib->GetMainScript(), false)) {
|
||||
if (!engine.LoadScript(vm, lib->GetMainScript(), false)) {
|
||||
throw sq_throwerror(vm, fmt::format("there was a compile error when importing '{}' version {}", library, version));
|
||||
}
|
||||
/* Create the fake class */
|
||||
sq_newslot(vm, -3, SQFalse);
|
||||
sq_pop(vm, 1);
|
||||
|
||||
controller->loaded_library[library_name] = fake_class;
|
||||
controller.loaded_library[library_name] = fake_class;
|
||||
}
|
||||
|
||||
/* Find the real class inside the fake class (like 'sets.Vector') */
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, fake_class, -1);
|
||||
sq_pushstring(vm, fake_class);
|
||||
if (SQ_FAILED(sq_get(vm, -2))) {
|
||||
throw sq_throwerror(vm, "internal error assigning library class");
|
||||
}
|
||||
sq_pushstring(vm, lib->GetInstanceName(), -1);
|
||||
sq_pushstring(vm, lib->GetInstanceName());
|
||||
if (SQ_FAILED(sq_get(vm, -2))) {
|
||||
throw sq_throwerror(vm, fmt::format("unable to find class '{}' in the library '{}' version {}", lib->GetInstanceName(), library, version));
|
||||
}
|
||||
@@ -156,7 +156,7 @@ ScriptController::ScriptController(::CompanyID company) :
|
||||
|
||||
/* Now link the name the user wanted to our 'fake' class */
|
||||
sq_pushobject(vm, parent);
|
||||
sq_pushstring(vm, class_name, -1);
|
||||
sq_pushstring(vm, class_name);
|
||||
sq_pushobject(vm, obj);
|
||||
sq_newclass(vm, SQTrue);
|
||||
sq_newslot(vm, -3, SQFalse);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define SCRIPT_CONTROLLER_HPP
|
||||
|
||||
#include "script_types.hpp"
|
||||
#include "../../string_func.h"
|
||||
#include "../../company_type.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
{
|
||||
if (!IsValidEngine(engine_id)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_ENGINE_NAME, engine_id));
|
||||
return ::StrMakeValid(::GetString(STR_ENGINE_NAME, engine_id), {});
|
||||
}
|
||||
|
||||
/* static */ CargoType ScriptEngine::GetCargoType(EngineID engine_id)
|
||||
|
||||
@@ -27,7 +27,7 @@ ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::S
|
||||
{
|
||||
auto it = ScriptError::error_map_string.find(ScriptError::GetLastError());
|
||||
assert(it != ScriptError::error_map_string.end());
|
||||
return it->second;
|
||||
return std::string{it->second};
|
||||
}
|
||||
|
||||
/* static */ ScriptErrorType ScriptError::StringToError(StringID internal_string_id)
|
||||
@@ -62,7 +62,7 @@ ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::S
|
||||
error_map[internal_string_id] = ai_error_msg;
|
||||
}
|
||||
|
||||
/* static */ void ScriptError::RegisterErrorMapString(ScriptErrorType ai_error_msg, const char *message)
|
||||
/* static */ void ScriptError::RegisterErrorMapString(ScriptErrorType ai_error_msg, std::string_view message)
|
||||
{
|
||||
error_map_string[ai_error_msg] = message;
|
||||
}
|
||||
|
||||
@@ -175,6 +175,9 @@ public:
|
||||
|
||||
/** Station is too spread out */
|
||||
ERR_STATION_TOO_SPREAD_OUT, // [STR_ERROR_STATION_TOO_SPREAD_OUT]
|
||||
|
||||
/** Bridge is too low */
|
||||
ERR_BRIDGE_TOO_LOW, // [STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION, STR_ERROR_BRIDGE_TOO_LOW_FOR_ROADSTOP, STR_ERROR_BRIDGE_TOO_LOW_FOR_BUOY, STR_ERROR_BRIDGE_TOO_LOW_FOR_RAIL_WAYPOINT, STR_ERROR_BRIDGE_TOO_LOW_FOR_ROAD_WAYPOINT]
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -218,11 +221,11 @@ public:
|
||||
* @param ai_error_msg The script error message representation.
|
||||
* @param message The string representation of this error message, used for debug purposes.
|
||||
*/
|
||||
static void RegisterErrorMapString(ScriptErrorType ai_error_msg, const char *message);
|
||||
static void RegisterErrorMapString(ScriptErrorType ai_error_msg, std::string_view message);
|
||||
|
||||
private:
|
||||
typedef std::map<StringID, ScriptErrorType> ScriptErrorMap; ///< The type for mapping between error (internal OpenTTD) StringID to the script error type.
|
||||
typedef std::map<ScriptErrorType, const char *> ScriptErrorMapString; ///< The type for mapping between error type and textual representation.
|
||||
using ScriptErrorMap = std::map<StringID, ScriptErrorType>; ///< The type for mapping between error (internal OpenTTD) StringID to the script error type.
|
||||
using ScriptErrorMapString = std::map<ScriptErrorType, std::string_view>; ///< The type for mapping between error type and textual representation.
|
||||
|
||||
static ScriptErrorMap error_map; ///< The mapping between error (internal OpenTTD) StringID to the script error type.
|
||||
static ScriptErrorMapString error_map_string; ///< The mapping between error type and textual representation.
|
||||
|
||||
@@ -9,64 +9,27 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "script_event_types.hpp"
|
||||
|
||||
#include <queue>
|
||||
#include "../script_storage.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/** The queue of events for a script. */
|
||||
struct ScriptEventData {
|
||||
std::queue<ScriptEvent *> stack; ///< The actual queue.
|
||||
};
|
||||
|
||||
/* static */ void ScriptEventController::CreateEventPointer()
|
||||
{
|
||||
assert(ScriptObject::GetEventPointer() == nullptr);
|
||||
|
||||
ScriptObject::GetEventPointer() = new ScriptEventData();
|
||||
}
|
||||
|
||||
/* static */ void ScriptEventController::FreeEventPointer()
|
||||
{
|
||||
ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer();
|
||||
|
||||
/* Free all waiting events (if any) */
|
||||
while (!data->stack.empty()) {
|
||||
ScriptEvent *e = data->stack.front();
|
||||
data->stack.pop();
|
||||
e->Release();
|
||||
}
|
||||
|
||||
/* Now kill our data pointer */
|
||||
delete data;
|
||||
}
|
||||
|
||||
/* static */ bool ScriptEventController::IsEventWaiting()
|
||||
{
|
||||
if (ScriptObject::GetEventPointer() == nullptr) ScriptEventController::CreateEventPointer();
|
||||
ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer();
|
||||
|
||||
return !data->stack.empty();
|
||||
return !ScriptObject::GetEventQueue().empty();
|
||||
}
|
||||
|
||||
/* static */ ScriptEvent *ScriptEventController::GetNextEvent()
|
||||
{
|
||||
if (ScriptObject::GetEventPointer() == nullptr) ScriptEventController::CreateEventPointer();
|
||||
ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer();
|
||||
auto &queue = ScriptObject::GetEventQueue();
|
||||
if (queue.empty()) return nullptr;
|
||||
|
||||
if (data->stack.empty()) return nullptr;
|
||||
|
||||
ScriptEvent *e = data->stack.front();
|
||||
data->stack.pop();
|
||||
return e;
|
||||
auto *result = queue.front().release();
|
||||
queue.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ void ScriptEventController::InsertEvent(ScriptEvent *event)
|
||||
{
|
||||
if (ScriptObject::GetEventPointer() == nullptr) ScriptEventController::CreateEventPointer();
|
||||
ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer();
|
||||
|
||||
event->AddRef();
|
||||
data->stack.push(event);
|
||||
ScriptObject::GetEventQueue().push(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
ET_PRESIDENT_RENAMED,
|
||||
};
|
||||
|
||||
#ifndef DOXYGEN_API
|
||||
/**
|
||||
* Constructor of ScriptEvent, to get the type of event.
|
||||
* @param type The type of event to construct.
|
||||
@@ -68,6 +69,7 @@ public:
|
||||
ScriptEvent(ScriptEvent::ScriptEventType type) :
|
||||
type(type)
|
||||
{}
|
||||
#endif /* DOXYGEN_API */
|
||||
|
||||
/**
|
||||
* Get the event-type.
|
||||
|
||||
@@ -34,7 +34,7 @@ std::optional<std::string> ScriptEventEnginePreview::GetName()
|
||||
{
|
||||
if (!this->IsEngineValid()) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_ENGINE_NAME, this->engine));
|
||||
return ::StrMakeValid(::GetString(STR_ENGINE_NAME, this->engine), {});
|
||||
}
|
||||
|
||||
CargoType ScriptEventEnginePreview::GetCargoType()
|
||||
@@ -139,7 +139,7 @@ static bool ScriptEventAdminPortReadValue(HSQUIRRELVM vm, nlohmann::json &json)
|
||||
|
||||
case nlohmann::json::value_t::string: {
|
||||
auto value = json.get<std::string>();
|
||||
sq_pushstring(vm, value.data(), value.size());
|
||||
sq_pushstring(vm, value);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ static bool ScriptEventAdminPortReadValue(HSQUIRRELVM vm, nlohmann::json &json)
|
||||
sq_newtable(vm);
|
||||
|
||||
for (auto &[key, value] : json.items()) {
|
||||
sq_pushstring(vm, key.data(), key.size());
|
||||
sq_pushstring(vm, key);
|
||||
|
||||
if (!ScriptEventAdminPortReadValue(vm, value)) {
|
||||
return false;
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventVehicleCrashed *Convert(ScriptEvent *instance) { return (ScriptEventVehicleCrashed *)instance; }
|
||||
static ScriptEventVehicleCrashed *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventVehicleCrashed *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the VehicleID of the crashed vehicle.
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventSubsidyOffer *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyOffer *)instance; }
|
||||
static ScriptEventSubsidyOffer *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventSubsidyOffer *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the SubsidyID of the subsidy.
|
||||
@@ -156,7 +156,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventSubsidyOfferExpired *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyOfferExpired *)instance; }
|
||||
static ScriptEventSubsidyOfferExpired *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventSubsidyOfferExpired *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the SubsidyID of the subsidy.
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventSubsidyAwarded *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyAwarded *)instance; }
|
||||
static ScriptEventSubsidyAwarded *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventSubsidyAwarded *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the SubsidyID of the subsidy.
|
||||
@@ -222,7 +222,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventSubsidyExpired *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyExpired *)instance; }
|
||||
static ScriptEventSubsidyExpired *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventSubsidyExpired *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the SubsidyID of the subsidy.
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventEnginePreview *Convert(ScriptEvent *instance) { return (ScriptEventEnginePreview *)instance; }
|
||||
static ScriptEventEnginePreview *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventEnginePreview *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the name of the offered engine.
|
||||
@@ -349,7 +349,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventCompanyNew *Convert(ScriptEvent *instance) { return (ScriptEventCompanyNew *)instance; }
|
||||
static ScriptEventCompanyNew *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventCompanyNew *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company that has been created.
|
||||
@@ -383,7 +383,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventCompanyRenamed *Convert(ScriptEvent *instance) { return static_cast<ScriptEventCompanyRenamed *>(instance); }
|
||||
static ScriptEventCompanyRenamed *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventCompanyRenamed *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company that has been renamed.
|
||||
@@ -425,7 +425,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventCompanyInTrouble *Convert(ScriptEvent *instance) { return (ScriptEventCompanyInTrouble *)instance; }
|
||||
static ScriptEventCompanyInTrouble *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventCompanyInTrouble *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company that is in trouble.
|
||||
@@ -460,7 +460,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventCompanyAskMerger *Convert(ScriptEvent *instance) { return (ScriptEventCompanyAskMerger *)instance; }
|
||||
static ScriptEventCompanyAskMerger *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventCompanyAskMerger *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company that can be bought.
|
||||
@@ -511,7 +511,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventCompanyMerger *Convert(ScriptEvent *instance) { return (ScriptEventCompanyMerger *)instance; }
|
||||
static ScriptEventCompanyMerger *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventCompanyMerger *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company that has been bought.
|
||||
@@ -554,7 +554,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventCompanyBankrupt *Convert(ScriptEvent *instance) { return (ScriptEventCompanyBankrupt *)instance; }
|
||||
static ScriptEventCompanyBankrupt *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventCompanyBankrupt *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company that has gone bankrupt.
|
||||
@@ -587,7 +587,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventVehicleLost *Convert(ScriptEvent *instance) { return (ScriptEventVehicleLost *)instance; }
|
||||
static ScriptEventVehicleLost *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventVehicleLost *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the VehicleID of the vehicle that is lost.
|
||||
@@ -620,7 +620,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventVehicleWaitingInDepot *Convert(ScriptEvent *instance) { return (ScriptEventVehicleWaitingInDepot *)instance; }
|
||||
static ScriptEventVehicleWaitingInDepot *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventVehicleWaitingInDepot *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the VehicleID of the vehicle that is waiting in a depot.
|
||||
@@ -653,7 +653,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventVehicleUnprofitable *Convert(ScriptEvent *instance) { return (ScriptEventVehicleUnprofitable *)instance; }
|
||||
static ScriptEventVehicleUnprofitable *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventVehicleUnprofitable *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the VehicleID of the vehicle that lost money.
|
||||
@@ -686,7 +686,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventIndustryOpen *Convert(ScriptEvent *instance) { return (ScriptEventIndustryOpen *)instance; }
|
||||
static ScriptEventIndustryOpen *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventIndustryOpen *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the IndustryID of the new industry.
|
||||
@@ -719,7 +719,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventIndustryClose *Convert(ScriptEvent *instance) { return (ScriptEventIndustryClose *)instance; }
|
||||
static ScriptEventIndustryClose *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventIndustryClose *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the IndustryID of the closing industry.
|
||||
@@ -752,7 +752,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventEngineAvailable *Convert(ScriptEvent *instance) { return (ScriptEventEngineAvailable *)instance; }
|
||||
static ScriptEventEngineAvailable *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventEngineAvailable *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the EngineID of the new engine.
|
||||
@@ -787,7 +787,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventStationFirstVehicle *Convert(ScriptEvent *instance) { return (ScriptEventStationFirstVehicle *)instance; }
|
||||
static ScriptEventStationFirstVehicle *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventStationFirstVehicle *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the StationID of the visited station.
|
||||
@@ -827,7 +827,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventDisasterZeppelinerCrashed *Convert(ScriptEvent *instance) { return (ScriptEventDisasterZeppelinerCrashed *)instance; }
|
||||
static ScriptEventDisasterZeppelinerCrashed *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventDisasterZeppelinerCrashed *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the StationID of the station containing the affected airport.
|
||||
@@ -860,7 +860,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventDisasterZeppelinerCleared *Convert(ScriptEvent *instance) { return (ScriptEventDisasterZeppelinerCleared *)instance; }
|
||||
static ScriptEventDisasterZeppelinerCleared *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventDisasterZeppelinerCleared *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the StationID of the station containing the affected airport.
|
||||
@@ -893,7 +893,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventTownFounded *Convert(ScriptEvent *instance) { return (ScriptEventTownFounded *)instance; }
|
||||
static ScriptEventTownFounded *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventTownFounded *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the TownID of the town.
|
||||
@@ -928,7 +928,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventAircraftDestTooFar *Convert(ScriptEvent *instance) { return (ScriptEventAircraftDestTooFar *)instance; }
|
||||
static ScriptEventAircraftDestTooFar *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventAircraftDestTooFar *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the VehicleID of the aircraft whose destination is too far away.
|
||||
@@ -958,7 +958,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventAdminPort *Convert(ScriptEvent *instance) { return (ScriptEventAdminPort *)instance; }
|
||||
static ScriptEventAdminPort *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventAdminPort *>(instance); }
|
||||
|
||||
#ifndef DOXYGEN_API
|
||||
/**
|
||||
@@ -1003,7 +1003,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventWindowWidgetClick *Convert(ScriptEvent *instance) { return (ScriptEventWindowWidgetClick *)instance; }
|
||||
static ScriptEventWindowWidgetClick *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventWindowWidgetClick *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the class of the window that was clicked.
|
||||
@@ -1056,7 +1056,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventGoalQuestionAnswer *Convert(ScriptEvent *instance) { return (ScriptEventGoalQuestionAnswer *)instance; }
|
||||
static ScriptEventGoalQuestionAnswer *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventGoalQuestionAnswer *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the unique id of the question.
|
||||
@@ -1106,7 +1106,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventCompanyTown *Convert(ScriptEvent *instance) { return (ScriptEventCompanyTown *)instance; }
|
||||
static ScriptEventCompanyTown *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventCompanyTown *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company.
|
||||
@@ -1147,7 +1147,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventExclusiveTransportRights *Convert(ScriptEventCompanyTown *instance) { return (ScriptEventExclusiveTransportRights *)instance; }
|
||||
static ScriptEventExclusiveTransportRights *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventExclusiveTransportRights *>(instance); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1172,7 +1172,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventRoadReconstruction *Convert(ScriptEventCompanyTown *instance) { return (ScriptEventRoadReconstruction *)instance; }
|
||||
static ScriptEventRoadReconstruction *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventRoadReconstruction *>(instance); }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1198,7 +1198,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventVehicleAutoReplaced *Convert(ScriptEvent *instance) { return (ScriptEventVehicleAutoReplaced *)instance; }
|
||||
static ScriptEventVehicleAutoReplaced *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventVehicleAutoReplaced *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the VehicleID of the vehicle that has been replaced.
|
||||
@@ -1242,7 +1242,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventStoryPageButtonClick *Convert(ScriptEvent *instance) { return (ScriptEventStoryPageButtonClick *)instance; }
|
||||
static ScriptEventStoryPageButtonClick *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventStoryPageButtonClick *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the player that selected a tile.
|
||||
@@ -1295,7 +1295,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventStoryPageTileSelect *Convert(ScriptEvent *instance) { return (ScriptEventStoryPageTileSelect *)instance; }
|
||||
static ScriptEventStoryPageTileSelect *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventStoryPageTileSelect *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the player that selected a tile.
|
||||
@@ -1355,7 +1355,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventStoryPageVehicleSelect *Convert(ScriptEvent *instance) { return (ScriptEventStoryPageVehicleSelect *)instance; }
|
||||
static ScriptEventStoryPageVehicleSelect *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventStoryPageVehicleSelect *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the player that selected a tile.
|
||||
@@ -1413,7 +1413,7 @@ public:
|
||||
* @param instance The instance to convert.
|
||||
* @return The converted instance.
|
||||
*/
|
||||
static ScriptEventPresidentRenamed *Convert(ScriptEvent *instance) { return static_cast<ScriptEventPresidentRenamed *>(instance); }
|
||||
static ScriptEventPresidentRenamed *Convert(ScriptEvent *instance) { return dynamic_cast<ScriptEventPresidentRenamed *>(instance); }
|
||||
|
||||
/**
|
||||
* Get the CompanyID of the company that got its president renamed.
|
||||
|
||||
@@ -32,7 +32,7 @@ void ScriptExecMode::FinalRelease()
|
||||
{
|
||||
if (this->GetDoCommandModeInstance() != this) {
|
||||
/* Ignore this error if the script is not alive. */
|
||||
if (ScriptObject::GetActiveInstance()->IsAlive()) {
|
||||
if (ScriptObject::GetActiveInstance().IsAlive()) {
|
||||
throw Script_FatalError("ScriptExecMode object was removed while it was not the latest *Mode object created.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
{
|
||||
if (!IsValidGroup(group_id)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_GROUP_NAME, group_id));
|
||||
return ::StrMakeValid(::GetString(STR_GROUP_NAME, group_id), {});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptGroup::SetParent(GroupID group_id, GroupID parent_group_id)
|
||||
|
||||
@@ -11,22 +11,12 @@
|
||||
|
||||
${SQUIRREL_INCLUDES}
|
||||
|
||||
static SQInteger ${APIUC}ObjectConstructor(HSQUIRRELVM vm)
|
||||
{
|
||||
return sq_throwerror(vm, "${APIUC}Object is not instantiable");
|
||||
}
|
||||
|
||||
static SQInteger ${APIUC}ObjectCloned(HSQUIRRELVM)
|
||||
{
|
||||
throw Script_FatalError("This instance is not cloneable");
|
||||
}
|
||||
|
||||
void SQ${APIUC}_RegisterAll(Squirrel *engine)
|
||||
void SQ${APIUC}_RegisterAll(Squirrel &engine)
|
||||
{
|
||||
DefSQClass<ScriptObject, ScriptType::${APIUC}> SQ${APIUC}Object("${APIUC}Object");
|
||||
SQ${APIUC}Object.PreRegister(engine);
|
||||
SQ${APIUC}Object.DefSQAdvancedStaticMethod(engine, &${APIUC}ObjectConstructor, "constructor");
|
||||
SQ${APIUC}Object.DefSQAdvancedStaticMethod(engine, &${APIUC}ObjectCloned, "_cloned");
|
||||
SQ${APIUC}Object.DefSQAdvancedStaticMethod(engine, &ScriptObject::Constructor, "constructor");
|
||||
SQ${APIUC}Object.DefSQAdvancedStaticMethod(engine, &ScriptObject::_cloned, "_cloned");
|
||||
SQ${APIUC}Object.PostRegister(engine);
|
||||
|
||||
${SQUIRREL_REGISTER}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
{
|
||||
if (!IsValidIndustry(industry_id)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_INDUSTRY_NAME, industry_id));
|
||||
return ::StrMakeValid(::GetString(STR_INDUSTRY_NAME, industry_id), {});
|
||||
}
|
||||
|
||||
/* static */ ScriptDate::Date ScriptIndustry::GetConstructionDate(IndustryID industry_id)
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
{
|
||||
if (!IsValidIndustryType(industry_type)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(::GetIndustrySpec(industry_type)->name));
|
||||
return ::StrMakeValid(::GetString(::GetIndustrySpec(industry_type)->name), {});
|
||||
}
|
||||
|
||||
/* static */ ScriptList *ScriptIndustryType::GetProducedCargo(IndustryType industry_type)
|
||||
|
||||
@@ -453,6 +453,20 @@ bool ScriptList::LoadObject(HSQUIRRELVM vm)
|
||||
return true;
|
||||
}
|
||||
|
||||
ScriptObject *ScriptList::CloneObject()
|
||||
{
|
||||
ScriptList *clone = new ScriptList();
|
||||
clone->CopyList(this);
|
||||
return clone;
|
||||
}
|
||||
|
||||
void ScriptList::CopyList(const ScriptList *list)
|
||||
{
|
||||
this->Sort(list->sorter_type, list->sort_ascending);
|
||||
this->items = list->items;
|
||||
this->buckets = list->buckets;
|
||||
}
|
||||
|
||||
ScriptList::ScriptList()
|
||||
{
|
||||
/* Default sorter */
|
||||
@@ -910,8 +924,7 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||
|
||||
/* Don't allow docommand from a Valuator, as we can't resume in
|
||||
* mid C++-code. */
|
||||
bool backup_allow = ScriptObject::GetAllowDoCommand();
|
||||
ScriptObject::SetAllowDoCommand(false);
|
||||
ScriptObject::DisableDoCommandScope disabler{};
|
||||
|
||||
/* Limit the total number of ops that can be consumed by a valuate operation */
|
||||
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "valuator function");
|
||||
@@ -932,8 +945,7 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||
}
|
||||
|
||||
/* Call the function. Squirrel pops all parameters and pushes the return value. */
|
||||
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQFalse))) {
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
@@ -956,7 +968,6 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||
/* See below for explanation. The extra pop is the return value. */
|
||||
sq_pop(vm, nparam + 4);
|
||||
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
return sq_throwerror(vm, "return value of valuator is not valid (not integer/bool)");
|
||||
}
|
||||
}
|
||||
@@ -966,7 +977,6 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||
/* See below for explanation. The extra pop is the return value. */
|
||||
sq_pop(vm, nparam + 4);
|
||||
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
return sq_throwerror(vm, "modifying valuated list outside of valuator function");
|
||||
}
|
||||
|
||||
@@ -984,6 +994,5 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
||||
* 4. The ScriptList instance object. */
|
||||
sq_pop(vm, nparam + 3);
|
||||
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -88,11 +88,9 @@ protected:
|
||||
sq_push(vm, 2);
|
||||
}
|
||||
|
||||
/* Don't allow docommand from a Valuator, as we can't resume in
|
||||
/* Don't allow docommand from a filter, as we can't resume in
|
||||
* mid C++-code. */
|
||||
bool backup_allow = ScriptObject::GetAllowDoCommand();
|
||||
ScriptObject::SetAllowDoCommand(false);
|
||||
|
||||
ScriptObject::DisableDoCommandScope disabler{};
|
||||
|
||||
if (nparam < 1) {
|
||||
ScriptList::FillList<T>(list, item_valid);
|
||||
@@ -101,7 +99,7 @@ protected:
|
||||
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "list filter function");
|
||||
|
||||
ScriptList::FillList<T>(list, item_valid,
|
||||
[vm, nparam, backup_allow](const T *item) {
|
||||
[vm, nparam](const T *item) {
|
||||
/* Push the root table as instance object, this is what squirrel does for meta-functions. */
|
||||
sq_pushroottable(vm);
|
||||
/* Push all arguments for the valuator function. */
|
||||
@@ -111,9 +109,8 @@ protected:
|
||||
}
|
||||
|
||||
/* Call the function. Squirrel pops all parameters and pushes the return value. */
|
||||
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
throw sq_throwerror(vm, "failed to run filter");
|
||||
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQFalse))) {
|
||||
throw static_cast<SQInteger>(SQ_ERROR);
|
||||
}
|
||||
|
||||
SQBool add = SQFalse;
|
||||
@@ -125,7 +122,6 @@ protected:
|
||||
break;
|
||||
|
||||
default:
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
|
||||
}
|
||||
|
||||
@@ -139,8 +135,6 @@ protected:
|
||||
/* Pop the filter function */
|
||||
sq_poptop(vm);
|
||||
}
|
||||
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -151,6 +145,13 @@ protected:
|
||||
|
||||
virtual bool SaveObject(HSQUIRRELVM vm) override;
|
||||
virtual bool LoadObject(HSQUIRRELVM vm) override;
|
||||
virtual ScriptObject *CloneObject() override;
|
||||
|
||||
/**
|
||||
* Copy the content of a list.
|
||||
* @param list The list that will be copied.
|
||||
*/
|
||||
void CopyList(const ScriptList *list);
|
||||
|
||||
public:
|
||||
typedef std::set<SQInteger> ScriptItemList; ///< The list of items inside the bucket
|
||||
|
||||
@@ -123,6 +123,7 @@ public:
|
||||
* @exception ScriptError::ERR_SITE_UNSUITABLE
|
||||
* @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @return Whether the dock has been/can be build or not.
|
||||
*/
|
||||
static bool BuildDock(TileIndex tile, StationID station_id);
|
||||
@@ -135,6 +136,8 @@ public:
|
||||
* @exception ScriptError::ERR_AREA_NOT_CLEAR
|
||||
* @exception ScriptError::ERR_SITE_UNSUITABLE
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS
|
||||
* @exception ScriptError::ERR_BRIDGE_TOO_LOW
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @return Whether the buoy has been/can be build or not.
|
||||
*/
|
||||
static bool BuildBuoy(TileIndex tile);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "../script_fatalerror.hpp"
|
||||
#include "script_error.hpp"
|
||||
#include "../../debug.h"
|
||||
#include "../squirrel_helper.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
@@ -44,18 +45,18 @@ void SimpleCountedObject::Release()
|
||||
* Get the storage associated with the current ScriptInstance.
|
||||
* @return The storage.
|
||||
*/
|
||||
static ScriptStorage *GetStorage()
|
||||
static ScriptStorage &GetStorage()
|
||||
{
|
||||
return ScriptObject::GetActiveInstance()->GetStorage();
|
||||
return ScriptObject::GetActiveInstance().GetStorage();
|
||||
}
|
||||
|
||||
|
||||
/* static */ ScriptInstance *ScriptObject::ActiveInstance::active = nullptr;
|
||||
|
||||
ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance *instance) : alc_scope(instance->engine)
|
||||
ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance &instance) : alc_scope(instance.engine.get())
|
||||
{
|
||||
this->last_active = ScriptObject::ActiveInstance::active;
|
||||
ScriptObject::ActiveInstance::active = instance;
|
||||
ScriptObject::ActiveInstance::active = &instance;
|
||||
}
|
||||
|
||||
ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
@@ -63,209 +64,203 @@ ScriptObject::ActiveInstance::~ActiveInstance()
|
||||
ScriptObject::ActiveInstance::active = this->last_active;
|
||||
}
|
||||
|
||||
/* static */ ScriptInstance *ScriptObject::GetActiveInstance()
|
||||
ScriptObject::DisableDoCommandScope::DisableDoCommandScope()
|
||||
: AutoRestoreBackup(GetStorage().allow_do_command, false)
|
||||
{}
|
||||
|
||||
/* static */ ScriptInstance &ScriptObject::GetActiveInstance()
|
||||
{
|
||||
assert(ScriptObject::ActiveInstance::active != nullptr);
|
||||
return ScriptObject::ActiveInstance::active;
|
||||
return *ScriptObject::ActiveInstance::active;
|
||||
}
|
||||
|
||||
|
||||
/* static */ void ScriptObject::SetDoCommandDelay(uint ticks)
|
||||
{
|
||||
assert(ticks > 0);
|
||||
GetStorage()->delay = ticks;
|
||||
GetStorage().delay = ticks;
|
||||
}
|
||||
|
||||
/* static */ uint ScriptObject::GetDoCommandDelay()
|
||||
{
|
||||
return GetStorage()->delay;
|
||||
return GetStorage().delay;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetDoCommandMode(ScriptModeProc *proc, ScriptObject *instance)
|
||||
{
|
||||
GetStorage()->mode = proc;
|
||||
GetStorage()->mode_instance = instance;
|
||||
GetStorage().mode = proc;
|
||||
GetStorage().mode_instance = instance;
|
||||
}
|
||||
|
||||
/* static */ ScriptModeProc *ScriptObject::GetDoCommandMode()
|
||||
{
|
||||
return GetStorage()->mode;
|
||||
return GetStorage().mode;
|
||||
}
|
||||
|
||||
/* static */ ScriptObject *ScriptObject::GetDoCommandModeInstance()
|
||||
{
|
||||
return GetStorage()->mode_instance;
|
||||
return GetStorage().mode_instance;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetDoCommandAsyncMode(ScriptAsyncModeProc *proc, ScriptObject *instance)
|
||||
{
|
||||
GetStorage()->async_mode = proc;
|
||||
GetStorage()->async_mode_instance = instance;
|
||||
GetStorage().async_mode = proc;
|
||||
GetStorage().async_mode_instance = instance;
|
||||
}
|
||||
|
||||
/* static */ ScriptAsyncModeProc *ScriptObject::GetDoCommandAsyncMode()
|
||||
{
|
||||
return GetStorage()->async_mode;
|
||||
return GetStorage().async_mode;
|
||||
}
|
||||
|
||||
/* static */ ScriptObject *ScriptObject::GetDoCommandAsyncModeInstance()
|
||||
{
|
||||
return GetStorage()->async_mode_instance;
|
||||
return GetStorage().async_mode_instance;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetLastCommand(const CommandDataBuffer &data, Commands cmd)
|
||||
{
|
||||
ScriptStorage *s = GetStorage();
|
||||
Debug(script, 6, "SetLastCommand company={:02d} cmd={} data={}", s->root_company, cmd, FormatArrayAsHex(data));
|
||||
s->last_data = data;
|
||||
s->last_cmd = cmd;
|
||||
ScriptStorage &s = GetStorage();
|
||||
Debug(script, 6, "SetLastCommand company={:02d} cmd={} data={}", s.root_company, cmd, FormatArrayAsHex(data));
|
||||
s.last_data = data;
|
||||
s.last_cmd = cmd;
|
||||
}
|
||||
|
||||
/* static */ bool ScriptObject::CheckLastCommand(const CommandDataBuffer &data, Commands cmd)
|
||||
{
|
||||
ScriptStorage *s = GetStorage();
|
||||
Debug(script, 6, "CheckLastCommand company={:02d} cmd={} data={}", s->root_company, cmd, FormatArrayAsHex(data));
|
||||
if (s->last_cmd != cmd) return false;
|
||||
if (s->last_data != data) return false;
|
||||
ScriptStorage &s = GetStorage();
|
||||
Debug(script, 6, "CheckLastCommand company={:02d} cmd={} data={}", s.root_company, cmd, FormatArrayAsHex(data));
|
||||
if (s.last_cmd != cmd) return false;
|
||||
if (s.last_data != data) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetDoCommandCosts(Money value)
|
||||
{
|
||||
GetStorage()->costs = CommandCost(INVALID_EXPENSES, value); // Expense type is never read.
|
||||
GetStorage().costs = CommandCost(INVALID_EXPENSES, value); // Expense type is never read.
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::IncreaseDoCommandCosts(Money value)
|
||||
{
|
||||
GetStorage()->costs.AddCost(value);
|
||||
GetStorage().costs.AddCost(value);
|
||||
}
|
||||
|
||||
/* static */ Money ScriptObject::GetDoCommandCosts()
|
||||
{
|
||||
return GetStorage()->costs.GetCost();
|
||||
return GetStorage().costs.GetCost();
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetLastError(ScriptErrorType last_error)
|
||||
{
|
||||
GetStorage()->last_error = last_error;
|
||||
GetStorage().last_error = last_error;
|
||||
}
|
||||
|
||||
/* static */ ScriptErrorType ScriptObject::GetLastError()
|
||||
{
|
||||
return GetStorage()->last_error;
|
||||
return GetStorage().last_error;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetLastCost(Money last_cost)
|
||||
{
|
||||
GetStorage()->last_cost = last_cost;
|
||||
GetStorage().last_cost = last_cost;
|
||||
}
|
||||
|
||||
/* static */ Money ScriptObject::GetLastCost()
|
||||
{
|
||||
return GetStorage()->last_cost;
|
||||
return GetStorage().last_cost;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetRoadType(RoadType road_type)
|
||||
{
|
||||
GetStorage()->road_type = road_type;
|
||||
GetStorage().road_type = road_type;
|
||||
}
|
||||
|
||||
/* static */ RoadType ScriptObject::GetRoadType()
|
||||
{
|
||||
return GetStorage()->road_type;
|
||||
return GetStorage().road_type;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetRailType(RailType rail_type)
|
||||
{
|
||||
GetStorage()->rail_type = rail_type;
|
||||
GetStorage().rail_type = rail_type;
|
||||
}
|
||||
|
||||
/* static */ RailType ScriptObject::GetRailType()
|
||||
{
|
||||
return GetStorage()->rail_type;
|
||||
return GetStorage().rail_type;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetLastCommandRes(bool res)
|
||||
{
|
||||
GetStorage()->last_command_res = res;
|
||||
GetStorage().last_command_res = res;
|
||||
}
|
||||
|
||||
/* static */ bool ScriptObject::GetLastCommandRes()
|
||||
{
|
||||
return GetStorage()->last_command_res;
|
||||
return GetStorage().last_command_res;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetLastCommandResData(CommandDataBuffer data)
|
||||
{
|
||||
GetStorage()->last_cmd_ret = std::move(data);
|
||||
GetStorage().last_cmd_ret = std::move(data);
|
||||
}
|
||||
|
||||
/* static */ const CommandDataBuffer &ScriptObject::GetLastCommandResData()
|
||||
{
|
||||
return GetStorage()->last_cmd_ret;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetAllowDoCommand(bool allow)
|
||||
{
|
||||
GetStorage()->allow_do_command = allow;
|
||||
}
|
||||
|
||||
/* static */ bool ScriptObject::GetAllowDoCommand()
|
||||
{
|
||||
return GetStorage()->allow_do_command;
|
||||
return GetStorage().last_cmd_ret;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetCompany(::CompanyID company)
|
||||
{
|
||||
if (GetStorage()->root_company == INVALID_OWNER) GetStorage()->root_company = company;
|
||||
GetStorage()->company = company;
|
||||
if (GetStorage().root_company == INVALID_OWNER) GetStorage().root_company = company;
|
||||
GetStorage().company = company;
|
||||
|
||||
_current_company = company;
|
||||
}
|
||||
|
||||
/* static */ ::CompanyID ScriptObject::GetCompany()
|
||||
{
|
||||
return GetStorage()->company;
|
||||
return GetStorage().company;
|
||||
}
|
||||
|
||||
/* static */ ::CompanyID ScriptObject::GetRootCompany()
|
||||
{
|
||||
return GetStorage()->root_company;
|
||||
return GetStorage().root_company;
|
||||
}
|
||||
|
||||
/* static */ bool ScriptObject::CanSuspend()
|
||||
{
|
||||
Squirrel *squirrel = ScriptObject::GetActiveInstance()->engine;
|
||||
return GetStorage()->allow_do_command && squirrel->CanSuspend();
|
||||
Squirrel &squirrel = *ScriptObject::GetActiveInstance().engine;
|
||||
return GetStorage().allow_do_command && squirrel.CanSuspend();
|
||||
}
|
||||
|
||||
/* static */ void *&ScriptObject::GetEventPointer()
|
||||
/* static */ ScriptEventQueue &ScriptObject::GetEventQueue()
|
||||
{
|
||||
return GetStorage()->event_data;
|
||||
return GetStorage().event_queue;
|
||||
}
|
||||
|
||||
/* static */ ScriptLogTypes::LogData &ScriptObject::GetLogData()
|
||||
{
|
||||
return GetStorage()->log_data;
|
||||
return GetStorage().log_data;
|
||||
}
|
||||
|
||||
/* static */ void ScriptObject::SetCallbackVariable(int index, int value)
|
||||
{
|
||||
if (static_cast<size_t>(index) >= GetStorage()->callback_value.size()) GetStorage()->callback_value.resize(index + 1);
|
||||
GetStorage()->callback_value[index] = value;
|
||||
if (static_cast<size_t>(index) >= GetStorage().callback_value.size()) GetStorage().callback_value.resize(index + 1);
|
||||
GetStorage().callback_value[index] = value;
|
||||
}
|
||||
|
||||
/* static */ int ScriptObject::GetCallbackVariable(int index)
|
||||
{
|
||||
return GetStorage()->callback_value[index];
|
||||
return GetStorage().callback_value[index];
|
||||
}
|
||||
|
||||
/* static */ CommandCallbackData *ScriptObject::GetDoCommandCallback()
|
||||
{
|
||||
return ScriptObject::GetActiveInstance()->GetDoCommandCallback();
|
||||
return ScriptObject::GetActiveInstance().GetDoCommandCallback();
|
||||
}
|
||||
|
||||
std::tuple<bool, bool, bool, bool> ScriptObject::DoCommandPrep()
|
||||
/* static */ std::tuple<bool, bool, bool, bool> ScriptObject::DoCommandPrep()
|
||||
{
|
||||
if (!ScriptObject::CanSuspend()) {
|
||||
throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
|
||||
@@ -287,7 +282,7 @@ std::tuple<bool, bool, bool, bool> ScriptObject::DoCommandPrep()
|
||||
return { false, estimate_only, asynchronous, networking };
|
||||
}
|
||||
|
||||
bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only, bool asynchronous)
|
||||
/* static */ bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only, bool asynchronous)
|
||||
{
|
||||
/* Set the default callback to return a true/false result of the DoCommand */
|
||||
if (callback == nullptr) callback = &ScriptInstance::DoCommandReturn;
|
||||
@@ -315,8 +310,8 @@ bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_Suspend
|
||||
IncreaseDoCommandCosts(res.GetCost());
|
||||
if (!_generating_world) {
|
||||
/* Charge a nominal fee for asynchronously executed commands */
|
||||
Squirrel *engine = ScriptObject::GetActiveInstance()->engine;
|
||||
Squirrel::DecreaseOps(engine->GetVM(), 100);
|
||||
Squirrel &engine = *ScriptObject::GetActiveInstance().engine;
|
||||
Squirrel::DecreaseOps(engine.GetVM(), 100);
|
||||
}
|
||||
if (callback != nullptr) {
|
||||
/* Insert return value into to stack and throw a control code that
|
||||
@@ -344,15 +339,33 @@ bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_Suspend
|
||||
|
||||
/* static */ ScriptObject::RandomizerArray ScriptObject::random_states;
|
||||
|
||||
Randomizer &ScriptObject::GetRandomizer(Owner owner)
|
||||
/* static */ Randomizer &ScriptObject::GetRandomizer(Owner owner)
|
||||
{
|
||||
return ScriptObject::random_states[owner];
|
||||
}
|
||||
|
||||
void ScriptObject::InitializeRandomizers()
|
||||
/* static */ void ScriptObject::InitializeRandomizers()
|
||||
{
|
||||
Randomizer random = _random;
|
||||
for (Owner owner = OWNER_BEGIN; owner < OWNER_END; ++owner) {
|
||||
ScriptObject::GetRandomizer(owner).SetSeed(random.Next());
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptObject::Constructor(HSQUIRRELVM)
|
||||
{
|
||||
throw Script_FatalError("This class is not instantiatable");
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptObject::_cloned(HSQUIRRELVM vm)
|
||||
{
|
||||
ScriptObject *original = static_cast<ScriptObject *>(Squirrel::GetRealInstance(vm, 2, "Object"));
|
||||
if (ScriptObject *clone = original->CloneObject(); clone != nullptr) {
|
||||
clone->AddRef();
|
||||
sq_setinstanceup(vm, 1, clone);
|
||||
sq_setreleasehook(vm, 1, SQConvert::DefSQDestructorCallback<ScriptObject>);
|
||||
return 0;
|
||||
}
|
||||
|
||||
throw Script_FatalError("This instance is not cloneable");
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* Uper-parent object of all API classes. You should never use this class in
|
||||
* Upper-parent object of all API classes. You should never use this class in
|
||||
* your script, as it doesn't publish any public functions. It is used
|
||||
* internally to have a common place to handle general things, like internal
|
||||
* command processing, and command-validation checks.
|
||||
@@ -75,7 +75,7 @@ protected:
|
||||
class ActiveInstance {
|
||||
friend class ScriptObject;
|
||||
public:
|
||||
ActiveInstance(ScriptInstance *instance);
|
||||
ActiveInstance(ScriptInstance &instance);
|
||||
~ActiveInstance();
|
||||
private:
|
||||
ScriptInstance *last_active; ///< The active instance before we go instantiated.
|
||||
@@ -84,6 +84,11 @@ protected:
|
||||
static ScriptInstance *active; ///< The global current active instance.
|
||||
};
|
||||
|
||||
class DisableDoCommandScope : private AutoRestoreBackup<bool> {
|
||||
public:
|
||||
DisableDoCommandScope();
|
||||
};
|
||||
|
||||
/**
|
||||
* Save this object.
|
||||
* Must push 2 elements on the stack:
|
||||
@@ -100,6 +105,12 @@ protected:
|
||||
*/
|
||||
virtual bool LoadObject(HSQUIRRELVM) { return false; }
|
||||
|
||||
/**
|
||||
* Clone an object.
|
||||
* @return The clone if cloning this type is supported, nullptr otherwise.
|
||||
*/
|
||||
virtual ScriptObject *CloneObject() { return nullptr; }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Store the latest result of a DoCommand per company.
|
||||
@@ -117,7 +128,7 @@ public:
|
||||
* Get the currently active instance.
|
||||
* @return The instance.
|
||||
*/
|
||||
static class ScriptInstance *GetActiveInstance();
|
||||
static class ScriptInstance &GetActiveInstance();
|
||||
|
||||
/**
|
||||
* Get a reference of the randomizer that brings this script random values.
|
||||
@@ -131,6 +142,16 @@ public:
|
||||
*/
|
||||
static void InitializeRandomizers();
|
||||
|
||||
/**
|
||||
* Used when trying to instantiate ScriptObject from squirrel.
|
||||
*/
|
||||
static SQInteger Constructor(HSQUIRRELVM);
|
||||
|
||||
/**
|
||||
* Used for 'clone' from squirrel.
|
||||
*/
|
||||
static SQInteger _cloned(HSQUIRRELVM);
|
||||
|
||||
protected:
|
||||
template <Commands TCmd, typename T> struct ScriptDoCommandHelper;
|
||||
|
||||
@@ -265,21 +286,6 @@ protected:
|
||||
*/
|
||||
static const CommandDataBuffer &GetLastCommandResData();
|
||||
|
||||
/**
|
||||
* Store a allow_do_command per company.
|
||||
* @param allow The new allow.
|
||||
*/
|
||||
static void SetAllowDoCommand(bool allow);
|
||||
|
||||
/**
|
||||
* Get the internal value of allow_do_command. This can differ
|
||||
* from CanSuspend() if the reason we are not allowed
|
||||
* to execute a DoCommand is in squirrel and not the API.
|
||||
* In that case use this function to restore the previous value.
|
||||
* @return True iff DoCommands are allowed in the current scope.
|
||||
*/
|
||||
static bool GetAllowDoCommand();
|
||||
|
||||
/**
|
||||
* Set the current company to execute commands for or request
|
||||
* information about.
|
||||
@@ -327,12 +333,12 @@ protected:
|
||||
static bool CanSuspend();
|
||||
|
||||
/**
|
||||
* Get the pointer to store event data in.
|
||||
* Get the reference to the event queue.
|
||||
*/
|
||||
static void *&GetEventPointer();
|
||||
static struct ScriptEventQueue &GetEventQueue();
|
||||
|
||||
/**
|
||||
* Get the pointer to store log message in.
|
||||
* Get the reference to the log message storage.
|
||||
*/
|
||||
static ScriptLogTypes::LogData &GetLogData();
|
||||
|
||||
@@ -341,7 +347,7 @@ private:
|
||||
static std::tuple<bool, bool, bool, bool> DoCommandPrep();
|
||||
static bool DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only, bool asynchronous);
|
||||
static CommandCallbackData *GetDoCommandCallback();
|
||||
using RandomizerArray = ReferenceThroughBaseContainer<std::array<Randomizer, OWNER_END.base()>>;
|
||||
using RandomizerArray = TypedIndexContainer<std::array<Randomizer, OWNER_END.base()>, Owner>;
|
||||
static RandomizerArray random_states; ///< Random states for each of the scripts (game script uses OWNER_DEITY)
|
||||
};
|
||||
|
||||
@@ -467,6 +473,14 @@ public:
|
||||
if (this->data != nullptr) this->data->Release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer ownership to the caller.
|
||||
*/
|
||||
[[nodiscard]] T *release()
|
||||
{
|
||||
return std::exchange(this->data, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dereferencing this reference returns a reference to the reference
|
||||
* counted object
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
{
|
||||
EnforcePrecondition(std::nullopt, IsValidObjectType(object_type));
|
||||
|
||||
return ::StrMakeValid(::GetString(ObjectSpec::Get(object_type)->name));
|
||||
return ::StrMakeValid(::GetString(ObjectSpec::Get(object_type)->name), {});
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptObjectType::GetViews(ObjectType object_type)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
/** @file script_order.cpp Implementation of ScriptOrder. */
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include <ranges>
|
||||
#include "script_order.hpp"
|
||||
#include "script_cargo.hpp"
|
||||
#include "script_map.hpp"
|
||||
@@ -34,7 +35,7 @@ static OrderType GetOrderTypeByTile(TileIndex t)
|
||||
switch (::GetTileType(t)) {
|
||||
default: break;
|
||||
case MP_STATION:
|
||||
if (IsBuoy(t) || IsRailWaypoint(t)) return OT_GOTO_WAYPOINT;
|
||||
if (IsBuoy(t) || IsRailWaypoint(t) || IsRoadWaypoint(t)) return OT_GOTO_WAYPOINT;
|
||||
if (IsHangar(t)) return OT_GOTO_DEPOT;
|
||||
return OT_GOTO_STATION;
|
||||
|
||||
@@ -67,15 +68,12 @@ static const Order *ResolveOrder(VehicleID vehicle_id, ScriptOrder::OrderPositio
|
||||
order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position);
|
||||
if (order_position == ScriptOrder::ORDER_INVALID) return nullptr;
|
||||
}
|
||||
const Order *order = v->GetFirstOrder();
|
||||
assert(order != nullptr);
|
||||
while (order->GetType() == OT_IMPLICIT) order = order->next;
|
||||
while (order_position > 0) {
|
||||
order_position = (ScriptOrder::OrderPosition)(order_position - 1);
|
||||
order = order->next;
|
||||
while (order->GetType() == OT_IMPLICIT) order = order->next;
|
||||
}
|
||||
return order;
|
||||
|
||||
auto real_orders = v->Orders() | std::views::filter([](const Order &order) { return !order.IsType(OT_IMPLICIT); });
|
||||
auto it = std::ranges::next(std::begin(real_orders), order_position, std::end(real_orders));
|
||||
if (it != std::end(real_orders)) return &*it;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,17 +89,10 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
||||
|
||||
assert(ScriptOrder::IsValidVehicleOrder(vehicle_id, order_position));
|
||||
|
||||
int res = (int)order_position;
|
||||
const Order *order = v->orders->GetFirstOrder();
|
||||
assert(order != nullptr);
|
||||
for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
|
||||
while (order_position > 0) {
|
||||
order_position = (ScriptOrder::OrderPosition)(order_position - 1);
|
||||
order = order->next;
|
||||
for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
|
||||
}
|
||||
|
||||
return res;
|
||||
auto orders = v->Orders();
|
||||
auto real_orders = orders | std::views::filter([](const Order &order) { return !order.IsType(OT_IMPLICIT); });
|
||||
auto it = std::ranges::next(std::begin(real_orders), order_position, std::end(real_orders));
|
||||
return static_cast<int>(std::distance(std::begin(orders), it.base()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,14 +102,13 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
|
||||
*/
|
||||
static ScriptOrder::OrderPosition RealOrderPositionToScriptOrderPosition(VehicleID vehicle_id, int order_position)
|
||||
{
|
||||
const Order *order = ::Vehicle::Get(vehicle_id)->GetFirstOrder();
|
||||
assert(order != nullptr);
|
||||
int num_implicit_orders = 0;
|
||||
for (int i = 0; i < order_position; i++) {
|
||||
if (order->GetType() == OT_IMPLICIT) num_implicit_orders++;
|
||||
order = order->next;
|
||||
}
|
||||
return static_cast<ScriptOrder::OrderPosition>(order_position - num_implicit_orders);
|
||||
const Vehicle *v = ::Vehicle::Get(vehicle_id);
|
||||
|
||||
auto orders = v->Orders();
|
||||
auto first = std::begin(orders);
|
||||
auto last = std::ranges::next(first, order_position, std::end(orders));
|
||||
int num_implicit = static_cast<int>(std::count_if(first, last, [](const Order &order) { return order.IsType(OT_IMPLICIT); }));
|
||||
return static_cast<ScriptOrder::OrderPosition>(order_position - num_implicit);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptOrder::IsGotoStationOrder(VehicleID vehicle_id, OrderPosition order_position)
|
||||
@@ -296,8 +286,12 @@ static ScriptOrder::OrderPosition RealOrderPositionToScriptOrderPosition(Vehicle
|
||||
for (TileIndex t : wp->train_station) {
|
||||
if (wp->TileBelongsToRailStation(t)) return t;
|
||||
}
|
||||
} else if (wp->road_waypoint_area.tile != INVALID_TILE) {
|
||||
for (TileIndex t : wp->road_waypoint_area) {
|
||||
if (::IsRoadWaypointTile(t) && ::GetStationIndex(t) == wp->index) return t;
|
||||
}
|
||||
}
|
||||
/* If the waypoint has no rail waypoint tiles, it must have a buoy */
|
||||
/* If the waypoint has no rail or road waypoint tiles, it must have a buoy */
|
||||
return wp->xy;
|
||||
}
|
||||
default: return INVALID_TILE;
|
||||
@@ -579,7 +573,7 @@ static ScriptOrder::OrderPosition RealOrderPositionToScriptOrderPosition(Vehicle
|
||||
* between the wanted and the current order.
|
||||
* @param instance The script instance we are doing the callback for.
|
||||
*/
|
||||
static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance)
|
||||
static void _DoCommandReturnSetOrderFlags(class ScriptInstance &instance)
|
||||
{
|
||||
ScriptObject::SetLastCommandRes(ScriptOrder::_SetOrderFlags());
|
||||
ScriptInstance::DoCommandReturn(instance);
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
OC_RELIABILITY = ::OCV_RELIABILITY, ///< Skip based on the reliability, value is percent (0..100).
|
||||
OC_MAX_RELIABILITY = ::OCV_MAX_RELIABILITY, ///< Skip based on the maximum reliability. Value in percent
|
||||
OC_MAX_SPEED = ::OCV_MAX_SPEED, ///< Skip based on the maximum speed, value is in OpenTTD's internal speed unit, see ScriptEngine::GetMaxSpeed.
|
||||
OC_AGE = ::OCV_AGE, ///< Skip based on the age, value is in calender-years. @see \ref ScriptCalendarTime
|
||||
OC_AGE = ::OCV_AGE, ///< Skip based on the age, value is in calendar-years. @see \ref ScriptCalendarTime
|
||||
OC_REQUIRES_SERVICE = ::OCV_REQUIRES_SERVICE, ///< Skip when the vehicle requires service, no value.
|
||||
OC_UNCONDITIONALLY = ::OCV_UNCONDITIONALLY, ///< Always skip, no compare function, no value.
|
||||
OC_REMAINING_LIFETIME = ::OCV_REMAINING_LIFETIME, ///< Skip based on the remaining lifetime in calendar-years. @see \ref ScriptCalendarTime
|
||||
|
||||
@@ -26,9 +26,9 @@ static bool operator==(const ScriptPriorityQueue::PriorityItem &lhs, const HSQOB
|
||||
ScriptPriorityQueue::~ScriptPriorityQueue()
|
||||
{
|
||||
/* Release reference to stored objects. */
|
||||
auto inst = ScriptObject::GetActiveInstance();
|
||||
if (!inst->InShutdown()) {
|
||||
for (auto &i : this->queue) inst->ReleaseSQObject(const_cast<HSQOBJECT *>(&i.second));
|
||||
auto &inst = ScriptObject::GetActiveInstance();
|
||||
if (!inst.InShutdown()) {
|
||||
for (auto &i : this->queue) inst.ReleaseSQObject(const_cast<HSQOBJECT *>(&i.second));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
{
|
||||
if (!IsRailTypeAvailable(rail_type)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text));
|
||||
return ::StrMakeValid(::GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text), {});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptRail::IsRailTile(TileIndex tile)
|
||||
@@ -175,8 +175,7 @@
|
||||
EnforcePrecondition(false, source_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(source_industry));
|
||||
EnforcePrecondition(false, goal_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(goal_industry));
|
||||
|
||||
const GRFFile *file;
|
||||
uint16_t res = GetAiPurchaseCallbackResult(
|
||||
auto res = GetAiPurchaseCallbackResult(
|
||||
GSF_STATIONS,
|
||||
cargo_type,
|
||||
0,
|
||||
@@ -185,17 +184,16 @@
|
||||
ClampTo<uint8_t>(distance / 2),
|
||||
AICE_STATION_GET_STATION_ID,
|
||||
source_station ? 0 : 1,
|
||||
std::min<SQInteger>(15u, num_platforms) << 4 | std::min<SQInteger>(15u, platform_length),
|
||||
&file
|
||||
std::min<SQInteger>(15u, num_platforms) << 4 | std::min<SQInteger>(15u, platform_length)
|
||||
);
|
||||
|
||||
Axis axis = direction == RAILTRACK_NW_SE ? AXIS_Y : AXIS_X;
|
||||
bool adjacent = station_id != ScriptStation::STATION_JOIN_ADJACENT;
|
||||
StationID to_join = ScriptStation::IsValidStation(station_id) ? station_id : StationID::Invalid();
|
||||
if (res != CALLBACK_FAILED) {
|
||||
const StationSpec *spec = StationClass::GetByGrf(file->grfid, res);
|
||||
if (res.second != CALLBACK_FAILED) {
|
||||
const StationSpec *spec = StationClass::GetByGrf(res.first->grfid, res.second);
|
||||
if (spec == nullptr) {
|
||||
Debug(grf, 1, "{} 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", res.first->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::Command<CMD_BUILD_RAIL_STATION>::Do(tile, (::RailType)GetCurrentRailType(), axis, num_platforms, platform_length, spec->class_index, spec->index, to_join, adjacent)) return true;
|
||||
|
||||
@@ -262,6 +262,8 @@ public:
|
||||
* @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
|
||||
* @exception ScriptError::ERR_BRIDGE_TOO_LOW
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @return Whether the station has been/can be build or not.
|
||||
*/
|
||||
static bool BuildRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id);
|
||||
@@ -299,6 +301,8 @@ public:
|
||||
* @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
|
||||
* @exception ScriptError::ERR_BRIDGE_TOO_LOW
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @return Whether the station has been/can be build or not.
|
||||
*/
|
||||
static bool BuildNewGRFRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id, CargoType cargo_type, IndustryType source_industry, IndustryType goal_industry, SQInteger distance, bool source_station);
|
||||
@@ -312,6 +316,8 @@ public:
|
||||
* @pre IsRailTypeAvailable(GetCurrentRailType()).
|
||||
* @game @pre ScriptCompanyMode::IsValid().
|
||||
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
|
||||
* @exception ScriptError::ERR_BRIDGE_TOO_LOW
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @return Whether the rail waypoint has been/can be build or not.
|
||||
*/
|
||||
static bool BuildRailWaypoint(TileIndex tile);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
{
|
||||
if (!IsRoadTypeAvailable(road_type)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(GetRoadTypeInfo((::RoadType)road_type)->strings.name));
|
||||
return ::StrMakeValid(::GetString(GetRoadTypeInfo((::RoadType)road_type)->strings.name), {});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptRoad::IsRoadTile(TileIndex tile)
|
||||
|
||||
@@ -446,6 +446,8 @@ public:
|
||||
* @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
|
||||
* @exception ScriptError::ERR_BRIDGE_TOO_LOW
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @return Whether the station has been/can be build or not.
|
||||
*/
|
||||
static bool BuildRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id);
|
||||
@@ -471,6 +473,8 @@ public:
|
||||
* @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS
|
||||
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
|
||||
* @exception ScriptError::ERR_BRIDGE_TOO_LOW
|
||||
* @exception ScriptError::ERR_STATION_TOO_SPREAD_OUT
|
||||
* @return Whether the station has been/can be build or not.
|
||||
*/
|
||||
static bool BuildDriveThroughRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id);
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
{
|
||||
if (!IsValidSign(sign_id)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_SIGN_NAME, sign_id));
|
||||
return ::StrMakeValid(::GetString(STR_SIGN_NAME, sign_id), {});
|
||||
}
|
||||
|
||||
/* static */ TileIndex ScriptSign::GetLocation(SignID sign_id)
|
||||
|
||||
@@ -26,13 +26,6 @@
|
||||
return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity() || st->owner == OWNER_NONE);
|
||||
}
|
||||
|
||||
/* static */ ScriptCompany::CompanyID ScriptStation::GetOwner(StationID station_id)
|
||||
{
|
||||
if (!IsValidStation(station_id)) return ScriptCompany::COMPANY_INVALID;
|
||||
|
||||
return ScriptCompany::ToScriptCompanyID(::Station::Get(station_id)->owner);
|
||||
}
|
||||
|
||||
/* static */ StationID ScriptStation::GetStationID(TileIndex tile)
|
||||
{
|
||||
if (!::IsValidTile(tile) || !::IsTileType(tile, MP_STATION)) return StationID::Invalid();
|
||||
|
||||
@@ -59,15 +59,6 @@ public:
|
||||
*/
|
||||
static bool IsValidStation(StationID station_id);
|
||||
|
||||
/**
|
||||
* Get the owner of a station.
|
||||
* @param station_id The station to get the owner of.
|
||||
* @pre IsValidStation(station_id).
|
||||
* @return The owner the station has.
|
||||
* @api -ai
|
||||
*/
|
||||
static ScriptCompany::CompanyID GetOwner(StationID station_id);
|
||||
|
||||
/**
|
||||
* Get the StationID of a tile, if there is a station.
|
||||
* @param tile The tile to find the stationID of
|
||||
|
||||
@@ -34,8 +34,8 @@ ScriptStationList_Vehicle::ScriptStationList_Vehicle(VehicleID vehicle_id)
|
||||
|
||||
const Vehicle *v = ::Vehicle::Get(vehicle_id);
|
||||
|
||||
for (Order *o = v->GetFirstOrder(); o != nullptr; o = o->next) {
|
||||
if (o->IsType(OT_GOTO_STATION)) this->AddItem(o->GetDestination().ToStationID().base());
|
||||
for (const Order &o : v->Orders()) {
|
||||
if (o.IsType(OT_GOTO_STATION)) this->AddItem(o.GetDestination().ToStationID().base());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ public:
|
||||
/**
|
||||
* Opens the Story Book if not yet open and selects the given page.
|
||||
* @param story_page_id The story page to update. If it is a global page, clients of all
|
||||
* companies are affecetd. Otherwise only the clients of the company which the page belongs
|
||||
* companies are affected. Otherwise only the clients of the company which the page belongs
|
||||
* to are affected.
|
||||
* @return True if the action succeeded.
|
||||
* @pre ScriptCompanyMode::IsDeity().
|
||||
@@ -317,10 +317,10 @@ public:
|
||||
static bool IsValidStoryPageButtonColour(StoryPageButtonColour colour);
|
||||
|
||||
/**
|
||||
* Check whether this is a valid story page button flag.
|
||||
* @param flags The StoryPageButtonFlags to check.
|
||||
* @return True if and only if this story page button flag is valid.
|
||||
*/
|
||||
* Check whether this is a valid story page button flag.
|
||||
* @param flags The StoryPageButtonFlags to check.
|
||||
* @return True if and only if this story page button flag is valid.
|
||||
*/
|
||||
static bool IsValidStoryPageButtonFlags(StoryPageButtonFlags flags);
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
|
||||
/**
|
||||
* Create a new subsidy.
|
||||
* @param cargo_type The type of cargo to cary for the subsidy.
|
||||
* @param cargo_type The type of cargo to carry for the subsidy.
|
||||
* @param from_type The type of the subsidy on the 'from' side.
|
||||
* @param from_id The ID of the 'from' side.
|
||||
* @param to_type The type of the subsidy on the 'to' side.
|
||||
|
||||
@@ -32,7 +32,7 @@ void ScriptTestMode::FinalRelease()
|
||||
{
|
||||
if (this->GetDoCommandModeInstance() != this) {
|
||||
/* Ignore this error if the script is not alive. */
|
||||
if (ScriptObject::GetActiveInstance()->IsAlive()) {
|
||||
if (ScriptObject::GetActiveInstance().IsAlive()) {
|
||||
throw Script_FatalError("Testmode object was removed while it was not the latest *Mode object created.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "script_text.hpp"
|
||||
#include "script_log.hpp"
|
||||
#include "../script_fatalerror.hpp"
|
||||
#include "../../core/string_consumer.hpp"
|
||||
#include "../../table/control_codes.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
@@ -56,14 +57,14 @@ ScriptText::ScriptText(HSQUIRRELVM vm)
|
||||
|
||||
SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
{
|
||||
if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
|
||||
if (static_cast<size_t>(parameter) >= std::size(this->param)) this->param.resize(parameter + 1);
|
||||
|
||||
switch (sq_gettype(vm, -1)) {
|
||||
case OT_STRING: {
|
||||
const SQChar *value;
|
||||
sq_getstring(vm, -1, &value);
|
||||
std::string_view view;
|
||||
sq_getstring(vm, -1, view);
|
||||
|
||||
this->param[parameter] = StrMakeValid(value);
|
||||
this->param[parameter] = StrMakeValid(view);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
|
||||
/* Validate if it is a GSText instance */
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, "GSText", -1);
|
||||
sq_pushstring(vm, "GSText");
|
||||
sq_get(vm, -2);
|
||||
sq_pushobject(vm, instance);
|
||||
if (sq_instanceof(vm) != SQTrue) return SQ_ERROR;
|
||||
@@ -98,10 +99,13 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
break;
|
||||
}
|
||||
|
||||
case OT_NULL:
|
||||
this->param[parameter] = {};
|
||||
break;
|
||||
|
||||
default: return SQ_ERROR;
|
||||
}
|
||||
|
||||
if (this->paramc <= parameter) this->paramc = parameter + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -112,7 +116,6 @@ SQInteger ScriptText::SetParam(HSQUIRRELVM vm)
|
||||
SQInteger k;
|
||||
sq_getinteger(vm, 2, &k);
|
||||
|
||||
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
|
||||
if (k < 1) return SQ_ERROR;
|
||||
k--;
|
||||
|
||||
@@ -122,7 +125,7 @@ SQInteger ScriptText::SetParam(HSQUIRRELVM vm)
|
||||
SQInteger ScriptText::AddParam(HSQUIRRELVM vm)
|
||||
{
|
||||
SQInteger res;
|
||||
res = this->_SetParam(this->paramc, vm);
|
||||
res = this->_SetParam(static_cast<int>(std::size(this->param)), vm);
|
||||
if (res != 0) return res;
|
||||
|
||||
/* Push our own instance back on top of the stack */
|
||||
@@ -135,13 +138,15 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
|
||||
int32_t k;
|
||||
|
||||
if (sq_gettype(vm, 2) == OT_STRING) {
|
||||
const SQChar *key_string;
|
||||
sq_getstring(vm, 2, &key_string);
|
||||
std::string_view view;
|
||||
sq_getstring(vm, 2, view);
|
||||
|
||||
std::string str = StrMakeValid(key_string);
|
||||
if (!str.starts_with("param_") || str.size() > 8) return SQ_ERROR;
|
||||
std::string str = StrMakeValid(view);
|
||||
if (!str.starts_with("param_")) return SQ_ERROR;
|
||||
|
||||
k = stoi(str.substr(6));
|
||||
auto key = ParseInteger<int32_t>(str.substr(6));
|
||||
if (!key.has_value()) return SQ_ERROR;
|
||||
k = *key;
|
||||
} else if (sq_gettype(vm, 2) == OT_INTEGER) {
|
||||
SQInteger key;
|
||||
sq_getinteger(vm, 2, &key);
|
||||
@@ -150,13 +155,35 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm)
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
|
||||
if (k < 1) return SQ_ERROR;
|
||||
k--;
|
||||
|
||||
return this->_SetParam(k, vm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of padding parameters to use, for compatibility with old scripts.
|
||||
* This is called during RegisterGameTranslation.
|
||||
*/
|
||||
void ScriptText::SetPadParameterCount(HSQUIRRELVM vm)
|
||||
{
|
||||
ScriptText::pad_parameter_count = 0;
|
||||
|
||||
SQInteger top = sq_gettop(vm);
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, "GSText");
|
||||
if (!SQ_FAILED(sq_get(vm, -2))) {
|
||||
sq_pushstring(vm, "SCRIPT_TEXT_MAX_PARAMETERS");
|
||||
if (!SQ_FAILED(sq_get(vm, -2))) {
|
||||
SQInteger value;
|
||||
if (!SQ_FAILED(sq_getinteger(vm, -1, &value))) {
|
||||
ScriptText::pad_parameter_count = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
sq_settop(vm, top);
|
||||
}
|
||||
|
||||
EncodedString ScriptText::GetEncodedText()
|
||||
{
|
||||
ScriptTextList seen_texts;
|
||||
@@ -166,7 +193,6 @@ EncodedString ScriptText::GetEncodedText()
|
||||
StringBuilder builder(result);
|
||||
this->_FillParamList(params, seen_texts);
|
||||
this->_GetEncodedText(builder, param_count, params, true);
|
||||
if (param_count > SCRIPT_TEXT_MAX_PARAMETERS) throw Script_FatalError(fmt::format("{}: Too many parameters", GetGameStringName(this->string)));
|
||||
return ::EncodedString{std::move(result)};
|
||||
}
|
||||
|
||||
@@ -175,21 +201,21 @@ void ScriptText::_FillParamList(ParamList ¶ms, ScriptTextList &seen_texts)
|
||||
if (std::ranges::find(seen_texts, this) != seen_texts.end()) throw Script_FatalError(fmt::format("{}: Circular reference detected", GetGameStringName(this->string)));
|
||||
seen_texts.push_back(this);
|
||||
|
||||
for (int i = 0; i < this->paramc; i++) {
|
||||
Param *p = &this->param[i];
|
||||
params.emplace_back(this->string, i, p);
|
||||
if (!std::holds_alternative<ScriptTextRef>(*p)) continue;
|
||||
std::get<ScriptTextRef>(*p)->_FillParamList(params, seen_texts);
|
||||
for (int idx = 0; Param &p : this->param) {
|
||||
params.emplace_back(this->string, idx, &p);
|
||||
++idx;
|
||||
if (!std::holds_alternative<ScriptTextRef>(p)) continue;
|
||||
std::get<ScriptTextRef>(p)->_FillParamList(params, seen_texts);
|
||||
}
|
||||
|
||||
seen_texts.pop_back();
|
||||
|
||||
/* Fill with dummy parameters to match FormatString() behaviour. */
|
||||
if (seen_texts.empty()) {
|
||||
static Param dummy = 0;
|
||||
int nb_extra = SCRIPT_TEXT_MAX_PARAMETERS - (int)params.size();
|
||||
for (int i = 0; i < nb_extra; i++)
|
||||
params.emplace_back(StringIndexInTab(-1), i, &dummy);
|
||||
/* Fill with dummy parameters to match old FormatString() compatibility behaviour. */
|
||||
if (seen_texts.empty() && ScriptText::pad_parameter_count > 0) {
|
||||
static Param dummy = {};
|
||||
for (int idx = static_cast<int>(std::size(this->param)); idx < ScriptText::pad_parameter_count; ++idx) {
|
||||
params.emplace_back(StringIndexInTab(-1), idx, &dummy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +227,8 @@ void ScriptText::ParamCheck::Encode(StringBuilder &builder, std::string_view cmd
|
||||
struct visitor {
|
||||
StringBuilder &builder;
|
||||
|
||||
void operator()(const std::monostate &) { }
|
||||
|
||||
void operator()(std::string value)
|
||||
{
|
||||
this->builder.PutUtf8(SCC_ENCODED_STRING);
|
||||
@@ -211,7 +239,8 @@ void ScriptText::ParamCheck::Encode(StringBuilder &builder, std::string_view cmd
|
||||
void operator()(const SQInteger &value)
|
||||
{
|
||||
this->builder.PutUtf8(SCC_ENCODED_NUMERIC);
|
||||
this->builder.PutIntegerBase(value, 16);
|
||||
/* Sign-extend the value, then store as unsigned */
|
||||
this->builder.PutIntegerBase<uint64_t>(static_cast<uint64_t>(static_cast<int64_t>(value)), 16);
|
||||
}
|
||||
|
||||
void operator()(const ScriptTextRef &value)
|
||||
|
||||
@@ -75,8 +75,6 @@ private:
|
||||
*/
|
||||
class ScriptText : public Text {
|
||||
public:
|
||||
static const int SCRIPT_TEXT_MAX_PARAMETERS = 20; ///< The maximum amount of parameters you can give to one object.
|
||||
|
||||
#ifndef DOXYGEN_API
|
||||
/**
|
||||
* The constructor wrapper from Squirrel.
|
||||
@@ -128,10 +126,15 @@ public:
|
||||
*/
|
||||
EncodedString GetEncodedText() override;
|
||||
|
||||
/**
|
||||
* @api -all
|
||||
*/
|
||||
static void SetPadParameterCount(HSQUIRRELVM vm);
|
||||
|
||||
private:
|
||||
using ScriptTextRef = ScriptObjectRef<ScriptText>;
|
||||
using ScriptTextList = std::vector<ScriptText *>;
|
||||
using Param = std::variant<SQInteger, std::string, ScriptTextRef>;
|
||||
using Param = std::variant<std::monostate, SQInteger, std::string, ScriptTextRef>;
|
||||
|
||||
struct ParamCheck {
|
||||
StringIndexInTab owner;
|
||||
@@ -149,8 +152,9 @@ private:
|
||||
using ParamSpan = std::span<ParamCheck>;
|
||||
|
||||
StringIndexInTab string;
|
||||
std::array<Param, SCRIPT_TEXT_MAX_PARAMETERS> param = {};
|
||||
int paramc = 0;
|
||||
std::vector<Param> param{};
|
||||
|
||||
static inline int pad_parameter_count = 0; ///< Pad parameters for relaxed string validation.
|
||||
|
||||
/**
|
||||
* Internal function to recursively fill a list of parameters.
|
||||
|
||||
@@ -415,7 +415,7 @@ public:
|
||||
* Raise the given corners of the tile. The corners can be combined,
|
||||
* for example: SLOPE_N | SLOPE_W (= SLOPE_NW) will raise the west and the north corner.
|
||||
* @note The corners will be modified in the order west (first), south, east, north (last).
|
||||
* Changing one corner might cause another corner to be changed too. So modifiing
|
||||
* Changing one corner might cause another corner to be changed too. So modifying
|
||||
* multiple corners may result in changing some corners by multiple steps.
|
||||
* @param tile The tile to raise.
|
||||
* @param slope Corners to raise (SLOPE_xxx).
|
||||
@@ -432,7 +432,7 @@ public:
|
||||
* Lower the given corners of the tile. The corners can be combined,
|
||||
* for example: SLOPE_N | SLOPE_W (= SLOPE_NW) will lower the west and the north corner.
|
||||
* @note The corners will be modified in the order west (first), south, east, north (last).
|
||||
* Changing one corner might cause another corner to be changed too. So modifiing
|
||||
* Changing one corner might cause another corner to be changed too. So modifying
|
||||
* multiple corners may result in changing some corners by multiple steps.
|
||||
* @param tile The tile to lower.
|
||||
* @param slope Corners to lower (SLOPE_xxx).
|
||||
|
||||
@@ -23,6 +23,13 @@ bool ScriptTileList::SaveObject(HSQUIRRELVM vm)
|
||||
return true;
|
||||
}
|
||||
|
||||
ScriptObject *ScriptTileList::CloneObject()
|
||||
{
|
||||
ScriptTileList *clone = new ScriptTileList();
|
||||
clone->CopyList(this);
|
||||
return clone;
|
||||
}
|
||||
|
||||
void ScriptTileList::AddRectangle(TileIndex t1, TileIndex t2)
|
||||
{
|
||||
if (!::IsValidTile(t1)) return;
|
||||
@@ -144,8 +151,8 @@ ScriptTileList_StationType::ScriptTileList_StationType(StationID station_id, Scr
|
||||
if ((station_type & ScriptStation::STATION_TRAIN) != 0) station_types.Set(::StationType::Rail);
|
||||
if ((station_type & ScriptStation::STATION_TRUCK_STOP) != 0) station_types.Set(::StationType::Truck);
|
||||
if ((station_type & ScriptStation::STATION_BUS_STOP) != 0) station_types.Set(::StationType::Bus);
|
||||
if ((station_type & ScriptStation::STATION_AIRPORT) != 0) station_types.Set(::StationType::Airport).Set(::StationType::Oilrig);
|
||||
if ((station_type & ScriptStation::STATION_DOCK) != 0) station_types.Set(::StationType::Dock).Set(::StationType::Oilrig);
|
||||
if ((station_type & ScriptStation::STATION_AIRPORT) != 0) station_types.Set({::StationType::Airport, ::StationType::Oilrig});
|
||||
if ((station_type & ScriptStation::STATION_DOCK) != 0) station_types.Set({::StationType::Dock, ::StationType::Oilrig});
|
||||
|
||||
TileArea ta(::TileXY(rect->left, rect->top), rect->Width(), rect->Height());
|
||||
for (TileIndex cur_tile : ta) {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
class ScriptTileList : public ScriptList {
|
||||
protected:
|
||||
virtual bool SaveObject(HSQUIRRELVM) override;
|
||||
virtual ScriptObject *CloneObject() override;
|
||||
public:
|
||||
/**
|
||||
* Adds the rectangle between tile_from and tile_to to the to-be-evaluated tiles.
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
{
|
||||
if (!IsValidTown(town_id)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_TOWN_NAME, town_id));
|
||||
return ::StrMakeValid(::GetString(STR_TOWN_NAME, town_id), {});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptTown::SetName(TownID town_id, Text *name)
|
||||
@@ -93,7 +93,10 @@
|
||||
|
||||
const Town *t = ::Town::Get(town_id);
|
||||
|
||||
return t->supplied[cargo_type].old_max;
|
||||
auto it = t->GetCargoSupplied(cargo_type);
|
||||
if (it == std::end(t->supplied)) return 0;
|
||||
|
||||
return it->history[LAST_MONTH].production;
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptTown::GetLastMonthSupplied(TownID town_id, CargoType cargo_type)
|
||||
@@ -103,7 +106,10 @@
|
||||
|
||||
const Town *t = ::Town::Get(town_id);
|
||||
|
||||
return t->supplied[cargo_type].old_act;
|
||||
auto it = t->GetCargoSupplied(cargo_type);
|
||||
if (it == std::end(t->supplied)) return 0;
|
||||
|
||||
return it->history[LAST_MONTH].transported;
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptTown::GetLastMonthTransportedPercentage(TownID town_id, CargoType cargo_type)
|
||||
@@ -206,7 +212,7 @@
|
||||
if (!IsValidTown(town_id)) return false;
|
||||
|
||||
const Town *t = ::Town::Get(town_id);
|
||||
return ((uint32_t)GetDistanceSquareToTile(town_id, tile) <= t->cache.squared_town_zone_radius[HZB_TOWN_EDGE]);
|
||||
return ((uint32_t)GetDistanceSquareToTile(town_id, tile) <= t->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptTown::HasStatue(TownID town_id)
|
||||
@@ -278,7 +284,7 @@
|
||||
|
||||
houses = std::min<SQInteger>(houses, UINT32_MAX);
|
||||
|
||||
return ScriptObject::Command<CMD_EXPAND_TOWN>::Do(town_id, houses);
|
||||
return ScriptObject::Command<CMD_EXPAND_TOWN>::Do(town_id, houses, {TownExpandMode::Buildings, TownExpandMode::Roads});
|
||||
}
|
||||
|
||||
/* static */ bool ScriptTown::FoundTown(TileIndex tile, TownSize size, bool city, RoadLayout layout, Text *name)
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
* Helper function to connect a just built tunnel to nearby roads.
|
||||
* @param instance The script instance we have to built the road for.
|
||||
*/
|
||||
static void _DoCommandReturnBuildTunnel2(class ScriptInstance *instance)
|
||||
static void _DoCommandReturnBuildTunnel2(class ScriptInstance &instance)
|
||||
{
|
||||
if (!ScriptTunnel::_BuildTunnelRoad2()) {
|
||||
ScriptInstance::DoCommandReturn(instance);
|
||||
@@ -67,7 +67,7 @@ static void _DoCommandReturnBuildTunnel2(class ScriptInstance *instance)
|
||||
* Helper function to connect a just built tunnel to nearby roads.
|
||||
* @param instance The script instance we have to built the road for.
|
||||
*/
|
||||
static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance)
|
||||
static void _DoCommandReturnBuildTunnel1(class ScriptInstance &instance)
|
||||
{
|
||||
if (!ScriptTunnel::_BuildTunnelRoad1()) {
|
||||
ScriptInstance::DoCommandReturn(instance);
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
{
|
||||
if (!IsPrimaryVehicle(vehicle_id)) return std::nullopt;
|
||||
|
||||
return ::StrMakeValid(::GetString(STR_VEHICLE_NAME, vehicle_id));
|
||||
return ::StrMakeValid(::GetString(STR_VEHICLE_NAME, vehicle_id), {});
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptVehicle::GetAge(VehicleID vehicle_id)
|
||||
|
||||
@@ -370,7 +370,7 @@ public:
|
||||
* is owned by you.
|
||||
* @pre ScriptEngine::IsBuildable(engine_id).
|
||||
* @pre ScriptCargo::IsValidCargo(cargo).
|
||||
* @return The capacity the vehicle will have when refited.
|
||||
* @return The capacity the vehicle will have when refitted.
|
||||
*/
|
||||
static SQInteger GetBuildWithRefitCapacity(TileIndex depot, EngineID engine_id, CargoType cargo);
|
||||
|
||||
@@ -431,7 +431,7 @@ public:
|
||||
* @pre ScriptCargo::IsValidCargo(cargo).
|
||||
* @pre You must own the vehicle.
|
||||
* @pre The vehicle must be stopped in the depot.
|
||||
* @return The capacity the vehicle will have when refited.
|
||||
* @return The capacity the vehicle will have when refitted.
|
||||
*/
|
||||
static SQInteger GetRefitCapacity(VehicleID vehicle_id, CargoType cargo);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "script_group.hpp"
|
||||
#include "script_map.hpp"
|
||||
#include "script_station.hpp"
|
||||
#include "script_waypoint.hpp"
|
||||
#include "../../depot_map.h"
|
||||
#include "../../vehicle_base.h"
|
||||
#include "../../vehiclelist_func.h"
|
||||
@@ -33,17 +34,52 @@ ScriptVehicleList::ScriptVehicleList(HSQUIRRELVM vm)
|
||||
);
|
||||
}
|
||||
|
||||
ScriptVehicleList_Station::ScriptVehicleList_Station(StationID station_id)
|
||||
ScriptVehicleList_Station::ScriptVehicleList_Station(HSQUIRRELVM vm)
|
||||
{
|
||||
EnforceDeityOrCompanyModeValid_Void();
|
||||
|
||||
int nparam = sq_gettop(vm) - 1;
|
||||
|
||||
if (nparam < 1 || nparam > 2) throw sq_throwerror(vm, "wrong number of parameters");
|
||||
|
||||
SQInteger sqstationid;
|
||||
if (SQ_FAILED(sq_getinteger(vm, 2, &sqstationid))) {
|
||||
throw sq_throwerror(vm, "parameter 1 must be an integer");
|
||||
}
|
||||
StationID station_id = static_cast<StationID>(sqstationid);
|
||||
if (!ScriptBaseStation::IsValidBaseStation(station_id)) return;
|
||||
|
||||
bool is_deity = ScriptCompanyMode::IsDeity();
|
||||
::CompanyID owner = ScriptObject::GetCompany();
|
||||
::VehicleType type = VEH_INVALID;
|
||||
|
||||
if (nparam == 2) {
|
||||
SQInteger sqtype;
|
||||
if (SQ_FAILED(sq_getinteger(vm, 3, &sqtype))) {
|
||||
throw sq_throwerror(vm, "parameter 2 must be an integer");
|
||||
}
|
||||
if (sqtype < ScriptVehicle::VT_RAIL || sqtype > ScriptVehicle::VT_AIR) return;
|
||||
type = static_cast<::VehicleType>(sqtype);
|
||||
}
|
||||
|
||||
FindVehiclesWithOrder(
|
||||
[is_deity, owner, type](const Vehicle *v) { return (is_deity || v->owner == owner) && (type == VEH_INVALID || v->type == type); },
|
||||
[station_id](const Order *order) { return (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id; },
|
||||
[this](const Vehicle *v) { this->AddItem(v->index.base()); }
|
||||
);
|
||||
}
|
||||
|
||||
ScriptVehicleList_Waypoint::ScriptVehicleList_Waypoint(StationID waypoint_id)
|
||||
{
|
||||
EnforceDeityOrCompanyModeValid_Void();
|
||||
if (!ScriptWaypoint::IsValidWaypoint(waypoint_id)) return;
|
||||
|
||||
bool is_deity = ScriptCompanyMode::IsDeity();
|
||||
::CompanyID owner = ScriptObject::GetCompany();
|
||||
|
||||
FindVehiclesWithOrder(
|
||||
[is_deity, owner](const Vehicle *v) { return is_deity || v->owner == owner; },
|
||||
[station_id](const Order *order) { return (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id; },
|
||||
[waypoint_id](const Order *order) { return order->IsType(OT_GOTO_WAYPOINT) && order->GetDestination() == waypoint_id; },
|
||||
[this](const Vehicle *v) { this->AddItem(v->index.base()); }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,11 +58,39 @@ public:
|
||||
*/
|
||||
class ScriptVehicleList_Station : public ScriptList {
|
||||
public:
|
||||
#ifdef DOXYGEN_API
|
||||
/**
|
||||
* @param station_id The station to get the list of vehicles from, which have orders to it.
|
||||
* @pre ScriptBaseStation::IsValidBaseStation(station_id)
|
||||
*/
|
||||
ScriptVehicleList_Station(StationID station_id);
|
||||
|
||||
/**
|
||||
* @param station_id The station to get the list of vehicles from, which have orders to it.
|
||||
* @param vehicle_type The VehicleType to get the list of vehicles for.
|
||||
* @pre ScriptBaseStation::IsValidBaseStation(station_id)
|
||||
*/
|
||||
ScriptVehicleList_Station(StationID station_id, ScriptVehicle::VehicleType vehicle_type);
|
||||
#else
|
||||
/**
|
||||
* The constructor wrapper from Squirrel.
|
||||
*/
|
||||
ScriptVehicleList_Station(HSQUIRRELVM vm);
|
||||
#endif /* DOXYGEN_API */
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a list of vehicles that have orders to a given waypoint.
|
||||
* @api ai game
|
||||
* @ingroup ScriptList
|
||||
*/
|
||||
class ScriptVehicleList_Waypoint : public ScriptList {
|
||||
public:
|
||||
/**
|
||||
* @param waypoint_id The waypoint to get the list of vehicles from, which have orders to it.
|
||||
* @pre ScriptWaypoint::IsValidWaypoint(waypoint_id)
|
||||
*/
|
||||
ScriptVehicleList_Waypoint(StationID waypoint_id);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,7 +34,7 @@ ScriptWaypointList_Vehicle::ScriptWaypointList_Vehicle(VehicleID vehicle_id)
|
||||
|
||||
const Vehicle *v = ::Vehicle::Get(vehicle_id);
|
||||
|
||||
for (const Order *o = v->GetFirstOrder(); o != nullptr; o = o->next) {
|
||||
if (o->IsType(OT_GOTO_WAYPOINT)) this->AddItem(o->GetDestination().ToStationID().base());
|
||||
for (const Order &o : v->Orders()) {
|
||||
if (o.IsType(OT_GOTO_WAYPOINT)) this->AddItem(o.GetDestination().ToStationID().base());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
void ScriptConfig::Change(std::optional<std::string> name, int version, bool force_exact_match)
|
||||
void ScriptConfig::Change(std::optional<std::string_view> name, int version, bool force_exact_match)
|
||||
{
|
||||
if (name.has_value()) {
|
||||
this->name = std::move(name.value());
|
||||
this->name = name.value();
|
||||
this->info = this->FindInfo(this->name, version, force_exact_match);
|
||||
} else {
|
||||
this->info = nullptr;
|
||||
@@ -88,7 +88,7 @@ int ScriptConfig::GetSetting(const std::string &name) const
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
void ScriptConfig::SetSetting(const std::string_view name, int value)
|
||||
void ScriptConfig::SetSetting(std::string_view name, int value)
|
||||
{
|
||||
/* You can only set Script specific settings if an Script is selected. */
|
||||
if (this->info == nullptr) return;
|
||||
@@ -140,7 +140,7 @@ int ScriptConfig::GetVersion() const
|
||||
return this->version;
|
||||
}
|
||||
|
||||
void ScriptConfig::StringToSettings(const std::string &value)
|
||||
void ScriptConfig::StringToSettings(std::string_view value)
|
||||
{
|
||||
std::string_view to_process = value;
|
||||
for (;;) {
|
||||
@@ -168,7 +168,7 @@ std::string ScriptConfig::SettingsToString() const
|
||||
|
||||
std::string result;
|
||||
for (const auto &item : this->settings) {
|
||||
fmt::format_to(std::back_inserter(result), "{}={},", item.first, item.second);
|
||||
format_append(result, "{}={},", item.first, item.second);
|
||||
}
|
||||
|
||||
/* Remove the last ','. */
|
||||
|
||||
@@ -19,7 +19,7 @@ static const int INT32_DIGITS_WITH_SIGN_AND_TERMINATION = 10 + 1 + 1;
|
||||
|
||||
/** Flags for Script settings. */
|
||||
enum class ScriptConfigFlag : uint8_t {
|
||||
// Unused flag 0x1.
|
||||
/* Unused flag 0x1. */
|
||||
Boolean = 1, ///< This value is a boolean (either 0 (false) or 1 (true) ).
|
||||
InGame = 2, ///< This setting can be changed while the Script is running.
|
||||
Developer = 3, ///< This setting will only be visible when the Script development tools are active.
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
* @param force_exact_match If true try to find the exact same version
|
||||
* as specified. If false any compatible version is ok.
|
||||
*/
|
||||
void Change(std::optional<std::string> name, int version = -1, bool force_exact_match = false);
|
||||
void Change(std::optional<std::string_view> name, int version = -1, bool force_exact_match = false);
|
||||
|
||||
/**
|
||||
* Get the ScriptInfo linked to this ScriptConfig.
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
/**
|
||||
* Set the value of a setting for this config.
|
||||
*/
|
||||
void SetSetting(const std::string_view name, int value);
|
||||
void SetSetting(std::string_view name, int value);
|
||||
|
||||
/**
|
||||
* Reset all settings to their default value.
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
* Convert a string which is stored in the config file or savegames to
|
||||
* custom settings of this Script.
|
||||
*/
|
||||
void StringToSettings(const std::string &value);
|
||||
void StringToSettings(std::string_view value);
|
||||
|
||||
/**
|
||||
* Convert the custom settings to a string that can be stored in the config
|
||||
|
||||
+48
-59
@@ -25,6 +25,7 @@
|
||||
#include "../strings_func.h"
|
||||
#include "../timer/timer.h"
|
||||
#include "../timer/timer_window.h"
|
||||
#include "../core/string_consumer.hpp"
|
||||
|
||||
#include "script_gui.h"
|
||||
#include "script_log.hpp"
|
||||
@@ -72,7 +73,7 @@ struct ScriptListWindow : public Window {
|
||||
ScriptListWindow(WindowDesc &desc, CompanyID slot, bool show_all) : Window(desc),
|
||||
slot(slot), show_all(show_all)
|
||||
{
|
||||
if (slot == OWNER_DEITY) {
|
||||
if (this->slot == OWNER_DEITY) {
|
||||
this->info_list = this->show_all ? Game::GetInfoList() : Game::GetUniqueInfoList();
|
||||
} else {
|
||||
this->info_list = this->show_all ? AI::GetInfoList() : AI::GetUniqueInfoList();
|
||||
@@ -85,8 +86,8 @@ struct ScriptListWindow : public Window {
|
||||
this->vscroll->SetCount(this->info_list->size() + 1);
|
||||
|
||||
/* Try if we can find the currently selected AI */
|
||||
if (GetConfig(slot)->HasScript()) {
|
||||
ScriptInfo *info = GetConfig(slot)->GetInfo();
|
||||
if (GetConfig(this->slot)->HasScript()) {
|
||||
ScriptInfo *info = GetConfig(this->slot)->GetInfo();
|
||||
int i = 0;
|
||||
for (const auto &item : *this->info_list) {
|
||||
if (item.second == info) {
|
||||
@@ -113,7 +114,7 @@ struct ScriptListWindow : public Window {
|
||||
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
|
||||
|
||||
resize.width = 1;
|
||||
resize.height = this->line_height;
|
||||
fill.height = resize.height = this->line_height;
|
||||
size.height = 5 * this->line_height;
|
||||
}
|
||||
|
||||
@@ -169,25 +170,25 @@ struct ScriptListWindow : public Window {
|
||||
void ChangeScript()
|
||||
{
|
||||
if (this->selected == -1) {
|
||||
GetConfig(slot)->Change(std::nullopt);
|
||||
GetConfig(this->slot)->Change(std::nullopt);
|
||||
} else {
|
||||
ScriptInfoList::const_iterator it = this->info_list->cbegin();
|
||||
std::advance(it, this->selected);
|
||||
GetConfig(slot)->Change(it->second->GetName(), it->second->GetVersion());
|
||||
GetConfig(this->slot)->Change(it->second->GetName(), it->second->GetVersion());
|
||||
}
|
||||
if (_game_mode == GM_EDITOR) {
|
||||
if (slot == OWNER_DEITY) {
|
||||
if (this->slot == OWNER_DEITY) {
|
||||
if (Game::GetInstance() != nullptr) Game::ResetInstance();
|
||||
Game::StartNew();
|
||||
} else {
|
||||
Company *c = Company::GetIfValid(slot);
|
||||
Company *c = Company::GetIfValid(this->slot);
|
||||
if (c != nullptr && c->ai_instance != nullptr) {
|
||||
c->ai_instance.reset();
|
||||
AI::StartNew(slot);
|
||||
AI::StartNew(this->slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
InvalidateWindowData(WC_GAME_OPTIONS, slot == OWNER_DEITY ? WN_GAME_OPTIONS_GS : WN_GAME_OPTIONS_AI);
|
||||
InvalidateWindowData(WC_GAME_OPTIONS, this->slot == OWNER_DEITY ? WN_GAME_OPTIONS_GS : WN_GAME_OPTIONS_AI);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_SETTINGS);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, -1);
|
||||
CloseWindowByClass(WC_QUERY_STRING);
|
||||
@@ -199,7 +200,7 @@ struct ScriptListWindow : public Window {
|
||||
switch (widget) {
|
||||
case WID_SCRL_LIST: { // Select one of the Scripts
|
||||
int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SCRL_LIST) - 1;
|
||||
if (sel < (int)this->info_list->size()) {
|
||||
if (sel < static_cast<int>(this->info_list->size())) {
|
||||
this->selected = sel;
|
||||
this->SetDirty();
|
||||
if (click_count > 1) {
|
||||
@@ -215,10 +216,6 @@ struct ScriptListWindow : public Window {
|
||||
this->Close();
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_SCRL_CANCEL:
|
||||
this->Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,10 +259,7 @@ static constexpr NWidgetPart _nested_script_list_widgets[] = {
|
||||
NWidget(WWT_PANEL, COLOUR_MAUVE, WID_SCRL_INFO_BG), SetMinimalTextLines(8, WidgetDimensions::unscaled.framerect.Vertical() + WidgetDimensions::unscaled.vsep_normal * 3), SetResize(1, 0),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCRL_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_LIST_ACCEPT, STR_AI_LIST_ACCEPT_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCRL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_LIST_CANCEL, STR_AI_LIST_CANCEL_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCRL_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_LIST_ACCEPT, STR_AI_LIST_ACCEPT_TOOLTIP),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
|
||||
EndContainer(),
|
||||
};
|
||||
@@ -315,7 +309,7 @@ struct ScriptSettingsWindow : public Window {
|
||||
{
|
||||
this->CreateNestedTree();
|
||||
this->vscroll = this->GetScrollbar(WID_SCRS_SCROLLBAR);
|
||||
this->FinishInitNested(slot); // Initializes 'this->line_height' as side effect.
|
||||
this->FinishInitNested(this->slot); // Initializes 'this->line_height' as side effect.
|
||||
|
||||
this->OnInvalidateData();
|
||||
}
|
||||
@@ -327,12 +321,12 @@ struct ScriptSettingsWindow : public Window {
|
||||
*/
|
||||
void RebuildVisibleSettings()
|
||||
{
|
||||
visible_settings.clear();
|
||||
this->visible_settings.clear();
|
||||
|
||||
for (const auto &item : *this->script_config->GetConfigList()) {
|
||||
bool no_hide = !item.flags.Test(ScriptConfigFlag::Developer);
|
||||
if (no_hide || _settings_client.gui.ai_developer_tools) {
|
||||
visible_settings.push_back(&item);
|
||||
this->visible_settings.push_back(&item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +347,7 @@ struct ScriptSettingsWindow : public Window {
|
||||
this->line_height = std::max(SETTING_BUTTON_HEIGHT, GetCharacterHeight(FS_NORMAL)) + padding.height;
|
||||
|
||||
resize.width = 1;
|
||||
resize.height = this->line_height;
|
||||
fill.height = resize.height = this->line_height;
|
||||
size.height = 5 * this->line_height;
|
||||
}
|
||||
|
||||
@@ -361,7 +355,7 @@ struct ScriptSettingsWindow : public Window {
|
||||
{
|
||||
if (widget != WID_SCRS_BACKGROUND) return;
|
||||
|
||||
Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
|
||||
Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
Rect br = ir.WithWidth(SETTING_BUTTON_WIDTH, rtl);
|
||||
Rect tr = ir.Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
|
||||
@@ -377,11 +371,11 @@ struct ScriptSettingsWindow : public Window {
|
||||
bool editable = this->IsEditableItem(config_item);
|
||||
|
||||
if (config_item.flags.Test(ScriptConfigFlag::Boolean)) {
|
||||
DrawBoolButton(br.left, y + button_y_offset, current_value != 0, editable);
|
||||
DrawBoolButton(br.left, y + button_y_offset, COLOUR_YELLOW, COLOUR_MAUVE, current_value != 0, editable);
|
||||
} else {
|
||||
int i = static_cast<int>(std::distance(std::begin(this->visible_settings), it));
|
||||
if (config_item.complete_labels) {
|
||||
DrawDropDownButton(br.left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && clicked_dropdown, editable);
|
||||
DrawDropDownButton(br.left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && this->clicked_dropdown, editable);
|
||||
} else {
|
||||
DrawArrowButtons(br.left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, editable && current_value > config_item.min_value, editable && current_value < config_item.max_value);
|
||||
}
|
||||
@@ -421,7 +415,7 @@ struct ScriptSettingsWindow : public Window {
|
||||
|
||||
bool bool_item = config_item.flags.Test(ScriptConfigFlag::Boolean);
|
||||
|
||||
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
|
||||
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
|
||||
int x = pt.x - r.left;
|
||||
if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x;
|
||||
|
||||
@@ -484,10 +478,6 @@ struct ScriptSettingsWindow : public Window {
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_SCRS_ACCEPT:
|
||||
this->Close();
|
||||
break;
|
||||
|
||||
case WID_SCRS_RESET:
|
||||
this->script_config->ResetEditableSettings(_game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot)));
|
||||
this->SetDirty();
|
||||
@@ -497,20 +487,20 @@ struct ScriptSettingsWindow : public Window {
|
||||
|
||||
void OnQueryTextFinished(std::optional<std::string> str) override
|
||||
{
|
||||
if (!str.has_value() || str->empty()) return;
|
||||
int32_t value = atoi(str->c_str());
|
||||
|
||||
SetValue(value);
|
||||
if (!str.has_value()) return;
|
||||
auto value = ParseInteger<int32_t>(*str, 10, true);
|
||||
if (!value.has_value()) return;
|
||||
this->SetValue(*value);
|
||||
}
|
||||
|
||||
void OnDropdownSelect(WidgetID widget, int index) override
|
||||
void OnDropdownSelect(WidgetID widget, int index, int) override
|
||||
{
|
||||
if (widget != WID_SCRS_SETTING_DROPDOWN) return;
|
||||
assert(this->clicked_dropdown);
|
||||
SetValue(index);
|
||||
this->SetValue(index);
|
||||
}
|
||||
|
||||
void OnDropdownClose(Point, WidgetID widget, int, bool) override
|
||||
void OnDropdownClose(Point, WidgetID widget, int, int, bool) override
|
||||
{
|
||||
if (widget != WID_SCRS_SETTING_DROPDOWN) return;
|
||||
/* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
|
||||
@@ -578,9 +568,8 @@ static constexpr NWidgetPart _nested_script_settings_widgets[] = {
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_SCRS_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCRS_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_SETTINGS_CLOSE),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCRS_RESET), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_SETTINGS_RESET),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCRS_RESET), SetStringTip(STR_AI_SETTINGS_RESET),
|
||||
NWidget(WWT_PANEL, COLOUR_MAUVE), SetResize(1, 0), SetFill(1, 0),
|
||||
EndContainer(),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
|
||||
EndContainer(),
|
||||
@@ -610,7 +599,7 @@ void ShowScriptSettingsWindow(CompanyID slot)
|
||||
struct ScriptTextfileWindow : public TextfileWindow {
|
||||
CompanyID slot{}; ///< View the textfile of this CompanyID slot.
|
||||
|
||||
ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot)
|
||||
ScriptTextfileWindow(Window *parent, TextfileType file_type, CompanyID slot) : TextfileWindow(parent, file_type), slot(slot)
|
||||
{
|
||||
this->ConstructWindow();
|
||||
this->OnInvalidateData();
|
||||
@@ -619,7 +608,7 @@ struct ScriptTextfileWindow : public TextfileWindow {
|
||||
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
|
||||
{
|
||||
if (widget == WID_TF_CAPTION) {
|
||||
return GetString(stringid, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI, GetConfig(slot)->GetInfo()->GetName());
|
||||
return GetString(stringid, (this->slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI, GetConfig(this->slot)->GetInfo()->GetName());
|
||||
}
|
||||
|
||||
return this->Window::GetWidgetString(widget, stringid);
|
||||
@@ -627,11 +616,11 @@ struct ScriptTextfileWindow : public TextfileWindow {
|
||||
|
||||
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
|
||||
{
|
||||
auto textfile = GetConfig(slot)->GetTextfile(file_type, slot);
|
||||
auto textfile = GetConfig(this->slot)->GetTextfile(file_type, this->slot);
|
||||
if (!textfile.has_value()) {
|
||||
this->Close();
|
||||
} else {
|
||||
this->LoadTextfile(textfile.value(), (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR);
|
||||
this->LoadTextfile(textfile.value(), (this->slot == OWNER_DEITY) ? GAME_DIR : AI_DIR);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -641,10 +630,10 @@ struct ScriptTextfileWindow : public TextfileWindow {
|
||||
* @param file_type The type of textfile to display.
|
||||
* @param slot The slot the Script is using.
|
||||
*/
|
||||
void ShowScriptTextfileWindow(TextfileType file_type, CompanyID slot)
|
||||
void ShowScriptTextfileWindow(Window *parent, TextfileType file_type, CompanyID slot)
|
||||
{
|
||||
CloseWindowById(WC_TEXTFILE, file_type);
|
||||
new ScriptTextfileWindow(file_type, slot);
|
||||
parent->CloseChildWindowById(WC_TEXTFILE, file_type);
|
||||
new ScriptTextfileWindow(parent, file_type, slot);
|
||||
}
|
||||
|
||||
|
||||
@@ -745,13 +734,13 @@ struct ScriptDebugWindow : public Window {
|
||||
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->is_ai) {
|
||||
ChangeToScript(c->index);
|
||||
this->ChangeToScript(c->index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no AI is available, see if there is a game script. */
|
||||
if (Game::GetInstance() != nullptr) ChangeToScript(OWNER_DEITY);
|
||||
if (Game::GetInstance() != nullptr) this->ChangeToScript(OWNER_DEITY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -802,7 +791,7 @@ struct ScriptDebugWindow : public Window {
|
||||
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
|
||||
{
|
||||
if (widget == WID_SCRD_LOG_PANEL) {
|
||||
resize.height = GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
fill.height = resize.height = GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
size.height = 14 * resize.height + WidgetDimensions::scaled.framerect.Vertical();
|
||||
}
|
||||
}
|
||||
@@ -857,9 +846,9 @@ struct ScriptDebugWindow : public Window {
|
||||
void DrawWidgetCompanyButton(const Rect &r, WidgetID widget, int start) const
|
||||
{
|
||||
if (this->IsWidgetDisabled(widget)) return;
|
||||
CompanyID cid = (CompanyID)(widget - start);
|
||||
CompanyID cid = static_cast<CompanyID>(widget - start);
|
||||
Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON);
|
||||
DrawCompanyIcon(cid, CenterBounds(r.left, r.right, sprite_size.width), CenterBounds(r.top, r.bottom, sprite_size.height));
|
||||
DrawCompanyIcon(cid, CentreBounds(r.left, r.right, sprite_size.width), CentreBounds(r.top, r.bottom, sprite_size.height));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -922,7 +911,7 @@ struct ScriptDebugWindow : public Window {
|
||||
|
||||
ScriptLogTypes::LogData &log = this->GetLogData();
|
||||
|
||||
int scroll_count = (int)log.size();
|
||||
int scroll_count = static_cast<int>(log.size());
|
||||
if (this->vscroll->GetCount() != scroll_count) {
|
||||
this->vscroll->SetCount(scroll_count);
|
||||
|
||||
@@ -934,10 +923,10 @@ struct ScriptDebugWindow : public Window {
|
||||
|
||||
/* Detect when the user scrolls the window. Enable autoscroll when the bottom-most line becomes visible. */
|
||||
if (this->last_vscroll_pos != this->vscroll->GetPosition()) {
|
||||
this->autoscroll = this->vscroll->GetPosition() + this->vscroll->GetCapacity() >= (int)log.size();
|
||||
this->autoscroll = this->vscroll->GetPosition() + this->vscroll->GetCapacity() >= static_cast<int>(log.size());
|
||||
}
|
||||
|
||||
if (this->autoscroll && this->vscroll->SetPosition((int)log.size())) {
|
||||
if (this->autoscroll && this->vscroll->SetPosition(static_cast<int>(log.size()))) {
|
||||
/* We need a repaint */
|
||||
this->SetWidgetDirty(WID_SCRD_VSCROLLBAR);
|
||||
this->SetWidgetDirty(WID_SCRD_LOG_PANEL);
|
||||
@@ -1016,12 +1005,12 @@ struct ScriptDebugWindow : public Window {
|
||||
|
||||
/* Check which button is clicked */
|
||||
if (IsInsideMM(widget, WID_SCRD_COMPANY_BUTTON_START, WID_SCRD_COMPANY_BUTTON_END + 1)) {
|
||||
ChangeToScript((CompanyID)(widget - WID_SCRD_COMPANY_BUTTON_START), citymania::_fn_mod);
|
||||
this->ChangeToScript(static_cast<CompanyID>(widget - WID_SCRD_COMPANY_BUTTON_START), citymania::_fn_mod);
|
||||
}
|
||||
|
||||
switch (widget) {
|
||||
case WID_SCRD_SCRIPT_GAME:
|
||||
ChangeToScript(OWNER_DEITY, citymania::_fn_mod);
|
||||
this->ChangeToScript(OWNER_DEITY, citymania::_fn_mod);
|
||||
break;
|
||||
|
||||
case WID_SCRD_RELOAD_TOGGLE:
|
||||
@@ -1124,7 +1113,7 @@ struct ScriptDebugWindow : public Window {
|
||||
}
|
||||
|
||||
/* Highlight row that matched */
|
||||
this->highlight_row = (int)(log.size() - 1);
|
||||
this->highlight_row = static_cast<int>(log.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
#include "../company_type.h"
|
||||
#include "../textfile_type.h"
|
||||
|
||||
struct Window;
|
||||
|
||||
void ShowScriptListWindow(CompanyID slot, bool show_all);
|
||||
Window *ShowScriptDebugWindow(CompanyID show_company = CompanyID::Invalid(), bool new_window = false);
|
||||
void ShowScriptSettingsWindow(CompanyID slot);
|
||||
void ShowScriptTextfileWindow(TextfileType file_type, CompanyID slot);
|
||||
void ShowScriptTextfileWindow(Window *parent, TextfileType file_type, CompanyID slot);
|
||||
void ShowScriptDebugWindowIfScriptError();
|
||||
void InitializeScriptGui();
|
||||
|
||||
|
||||
+75
-64
@@ -14,11 +14,12 @@
|
||||
|
||||
#include "script_info.hpp"
|
||||
#include "script_scanner.hpp"
|
||||
#include "../core/string_consumer.hpp"
|
||||
#include "../3rdparty/fmt/format.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
bool ScriptInfo::CheckMethod(const char *name) const
|
||||
bool ScriptInfo::CheckMethod(std::string_view name) const
|
||||
{
|
||||
if (!this->engine->MethodExists(this->SQ_instance, name)) {
|
||||
this->engine->ThrowError(fmt::format("your info.nut/library.nut doesn't have the method '{}'", name));
|
||||
@@ -27,18 +28,18 @@ bool ScriptInfo::CheckMethod(const char *name) const
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ SQInteger ScriptInfo::Constructor(HSQUIRRELVM vm, ScriptInfo *info)
|
||||
/* static */ SQInteger ScriptInfo::Constructor(HSQUIRRELVM vm, ScriptInfo &info)
|
||||
{
|
||||
/* Set some basic info from the parent */
|
||||
Squirrel::GetInstance(vm, &info->SQ_instance, 2);
|
||||
Squirrel::GetInstance(vm, &info.SQ_instance, 2);
|
||||
/* Make sure the instance stays alive over time */
|
||||
sq_addref(vm, &info->SQ_instance);
|
||||
sq_addref(vm, &info.SQ_instance);
|
||||
|
||||
info->scanner = (ScriptScanner *)Squirrel::GetGlobalPointer(vm);
|
||||
info->engine = info->scanner->GetEngine();
|
||||
info.scanner = (ScriptScanner *)Squirrel::GetGlobalPointer(vm);
|
||||
info.engine = info.scanner->GetEngine();
|
||||
|
||||
/* Ensure the mandatory functions exist */
|
||||
static const char * const required_functions[] = {
|
||||
static const std::string_view required_functions[] = {
|
||||
"GetAuthor",
|
||||
"GetName",
|
||||
"GetShortName",
|
||||
@@ -48,30 +49,31 @@ bool ScriptInfo::CheckMethod(const char *name) const
|
||||
"CreateInstance",
|
||||
};
|
||||
for (const auto &required_function : required_functions) {
|
||||
if (!info->CheckMethod(required_function)) return SQ_ERROR;
|
||||
if (!info.CheckMethod(required_function)) return SQ_ERROR;
|
||||
}
|
||||
|
||||
/* Get location information of the scanner */
|
||||
info->main_script = info->scanner->GetMainScript();
|
||||
info->tar_file = info->scanner->GetTarFile();
|
||||
info.main_script = info.scanner->GetMainScript();
|
||||
info.tar_file = info.scanner->GetTarFile();
|
||||
|
||||
/* Cache the data the info file gives us. */
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info->engine->CallIntegerMethod(info->SQ_instance, "GetVersion", &info->version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR;
|
||||
if (!info.engine->CallStringMethod(info.SQ_instance, "GetAuthor", &info.author, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info.engine->CallStringMethod(info.SQ_instance, "GetName", &info.name, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info.engine->CallStringMethod(info.SQ_instance, "GetShortName", &info.short_name, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info.engine->CallStringMethod(info.SQ_instance, "GetDescription", &info.description, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info.engine->CallStringMethod(info.SQ_instance, "GetDate", &info.date, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!info.engine->CallIntegerMethod(info.SQ_instance, "GetVersion", &info.version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info.version < 0) return SQ_ERROR;
|
||||
if (!info.engine->CallStringMethod(info.SQ_instance, "CreateInstance", &info.instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR;
|
||||
|
||||
/* The GetURL function is optional. */
|
||||
if (info->engine->MethodExists(info->SQ_instance, "GetURL")) {
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetURL", &info->url, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (info.engine->MethodExists(info.SQ_instance, "GetURL")) {
|
||||
if (!info.engine->CallStringMethod(info.SQ_instance, "GetURL", &info.url, MAX_GET_OPS)) return SQ_ERROR;
|
||||
}
|
||||
|
||||
/* Check if we have settings */
|
||||
if (info->engine->MethodExists(info->SQ_instance, "GetSettings")) {
|
||||
if (!info->GetSettings()) return SQ_ERROR;
|
||||
if (info.engine->MethodExists(info.SQ_instance, "GetSettings")) {
|
||||
if (!info.GetSettings()) return SQ_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -82,65 +84,74 @@ bool ScriptInfo::GetSettings()
|
||||
return this->engine->CallMethod(this->SQ_instance, "GetSettings", nullptr, MAX_GET_SETTING_OPS);
|
||||
}
|
||||
|
||||
enum class ScriptConfigItemKey : uint8_t {
|
||||
Name,
|
||||
Description,
|
||||
MinValue,
|
||||
MaxValue,
|
||||
MediumValue,
|
||||
DefaultValue,
|
||||
Flags,
|
||||
};
|
||||
using ScriptConfigItemKeys = EnumBitSet<ScriptConfigItemKey, uint8_t>;
|
||||
|
||||
SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
||||
{
|
||||
ScriptConfigItem config;
|
||||
uint items = 0;
|
||||
ScriptConfigItemKeys present{};
|
||||
|
||||
int medium_value = INT32_MIN;
|
||||
|
||||
/* Read the table, and find all properties we care about */
|
||||
sq_pushnull(vm);
|
||||
while (SQ_SUCCEEDED(sq_next(vm, -2))) {
|
||||
const SQChar *key_string;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, &key_string))) return SQ_ERROR;
|
||||
std::string_view key_string;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, key_string))) return SQ_ERROR;
|
||||
std::string key = StrMakeValid(key_string);
|
||||
|
||||
if (key == "name") {
|
||||
const SQChar *sqvalue;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, &sqvalue))) return SQ_ERROR;
|
||||
std::string_view sqvalue;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, sqvalue))) return SQ_ERROR;
|
||||
|
||||
/* Don't allow '=' and ',' in configure setting names, as we need those
|
||||
* 2 chars to nicely store the settings as a string. */
|
||||
auto replace_with_underscore = [](auto c) { return c == '=' || c == ','; };
|
||||
config.name = StrMakeValid(sqvalue);
|
||||
std::replace_if(config.name.begin(), config.name.end(), replace_with_underscore, '_');
|
||||
items |= 0x001;
|
||||
present.Set(ScriptConfigItemKey::Name);
|
||||
} else if (key == "description") {
|
||||
const SQChar *sqdescription;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, &sqdescription))) return SQ_ERROR;
|
||||
std::string_view sqdescription;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, sqdescription))) return SQ_ERROR;
|
||||
config.description = StrMakeValid(sqdescription);
|
||||
items |= 0x002;
|
||||
present.Set(ScriptConfigItemKey::Description);
|
||||
} else if (key == "min_value") {
|
||||
SQInteger res;
|
||||
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
|
||||
config.min_value = ClampTo<int32_t>(res);
|
||||
items |= 0x004;
|
||||
present.Set(ScriptConfigItemKey::MinValue);
|
||||
} else if (key == "max_value") {
|
||||
SQInteger res;
|
||||
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
|
||||
config.max_value = ClampTo<int32_t>(res);
|
||||
items |= 0x008;
|
||||
present.Set(ScriptConfigItemKey::MaxValue);
|
||||
} else if (key == "easy_value") {
|
||||
// No longer parsed.
|
||||
items |= 0x010;
|
||||
/* No longer parsed. */
|
||||
} else if (key == "medium_value") {
|
||||
SQInteger res;
|
||||
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
|
||||
medium_value = ClampTo<int32_t>(res);
|
||||
items |= 0x020;
|
||||
present.Set(ScriptConfigItemKey::MediumValue);
|
||||
} else if (key == "hard_value") {
|
||||
// No longer parsed.
|
||||
items |= 0x040;
|
||||
/* No longer parsed. */
|
||||
} else if (key == "custom_value") {
|
||||
// No longer parsed.
|
||||
/* No longer parsed. */
|
||||
} else if (key == "default_value") {
|
||||
SQInteger res;
|
||||
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
|
||||
config.default_value = ClampTo<int32_t>(res);
|
||||
items |= 0x080;
|
||||
present.Set(ScriptConfigItemKey::DefaultValue);
|
||||
} else if (key == "random_deviation") {
|
||||
// No longer parsed.
|
||||
/* No longer parsed. */
|
||||
} else if (key == "step_size") {
|
||||
SQInteger res;
|
||||
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
|
||||
@@ -148,8 +159,8 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
||||
} else if (key == "flags") {
|
||||
SQInteger res;
|
||||
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
|
||||
config.flags = (ScriptConfigFlags)res;
|
||||
items |= 0x100;
|
||||
config.flags = static_cast<ScriptConfigFlags>(res);
|
||||
present.Set(ScriptConfigItemKey::Flags);
|
||||
} else {
|
||||
this->engine->ThrowError(fmt::format("unknown setting property '{}'", key));
|
||||
return SQ_ERROR;
|
||||
@@ -162,23 +173,22 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
||||
/* Check if default_value is set. Although required, this was changed with
|
||||
* 14.0, and as such, older AIs don't use it yet. So we convert the older
|
||||
* values into a default_value. */
|
||||
if ((items & 0x080) == 0) {
|
||||
if (!present.Test(ScriptConfigItemKey::DefaultValue)) {
|
||||
/* Easy/medium/hard should all three be defined. */
|
||||
if ((items & 0x010) == 0 || (items & 0x020) == 0 || (items & 0x040) == 0) {
|
||||
if (!present.Test(ScriptConfigItemKey::MediumValue)) {
|
||||
this->engine->ThrowError("please define all properties of a setting (min/max not allowed for booleans)");
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
config.default_value = medium_value;
|
||||
items |= 0x080;
|
||||
} else {
|
||||
/* For compatibility, also act like the default sets the easy/medium/hard. */
|
||||
items |= 0x010 | 0x020 | 0x040;
|
||||
present.Set(ScriptConfigItemKey::DefaultValue);
|
||||
}
|
||||
|
||||
/* Make sure all properties are defined */
|
||||
uint mask = config.flags.Test(ScriptConfigFlag::Boolean) ? 0x1F3 : 0x1FF;
|
||||
if (items != mask) {
|
||||
/* Make sure all required properties are defined */
|
||||
ScriptConfigItemKeys required = {ScriptConfigItemKey::Name, ScriptConfigItemKey::Description, ScriptConfigItemKey::DefaultValue, ScriptConfigItemKey::Flags};
|
||||
if (!config.flags.Test(ScriptConfigFlag::Boolean)) required.Set({ScriptConfigItemKey::MinValue, ScriptConfigItemKey::MaxValue});
|
||||
|
||||
if (!present.All(required)) {
|
||||
this->engine->ThrowError("please define all properties of a setting (min/max not allowed for booleans)");
|
||||
return SQ_ERROR;
|
||||
}
|
||||
@@ -189,9 +199,9 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
|
||||
|
||||
SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
|
||||
{
|
||||
const SQChar *setting_name_str;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, &setting_name_str))) return SQ_ERROR;
|
||||
std::string setting_name = StrMakeValid(setting_name_str);
|
||||
std::string_view setting_name_view;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, setting_name_view))) return SQ_ERROR;
|
||||
std::string setting_name = StrMakeValid(setting_name_view);
|
||||
|
||||
ScriptConfigItem *config = nullptr;
|
||||
for (auto &item : this->config_list) {
|
||||
@@ -207,21 +217,22 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
|
||||
/* Read the table and find all labels */
|
||||
sq_pushnull(vm);
|
||||
while (SQ_SUCCEEDED(sq_next(vm, -2))) {
|
||||
const SQChar *key_string;
|
||||
const SQChar *label;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, &key_string))) return SQ_ERROR;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, &label))) return SQ_ERROR;
|
||||
std::string_view key_string;
|
||||
std::string_view label;
|
||||
if (SQ_FAILED(sq_getstring(vm, -2, key_string))) return SQ_ERROR;
|
||||
if (SQ_FAILED(sq_getstring(vm, -1, label))) return SQ_ERROR;
|
||||
/* Because squirrel doesn't support identifiers starting with a digit,
|
||||
* we skip the first character. */
|
||||
key_string++;
|
||||
key_string.remove_prefix(1);
|
||||
int sign = 1;
|
||||
if (*key_string == '_') {
|
||||
if (key_string.starts_with('_')) {
|
||||
/* When the second character is '_', it indicates the value is negative. */
|
||||
sign = -1;
|
||||
key_string++;
|
||||
key_string.remove_prefix(1);
|
||||
}
|
||||
int key = atoi(key_string) * sign;
|
||||
config->labels[key] = StrMakeValid(label);
|
||||
auto key = ParseInteger<int>(key_string);
|
||||
if (!key.has_value()) return SQ_ERROR;
|
||||
config->labels[*key * sign] = StrMakeValid(label);
|
||||
|
||||
sq_pop(vm, 2);
|
||||
}
|
||||
@@ -244,7 +255,7 @@ const ScriptConfigItemList *ScriptInfo::GetConfigList() const
|
||||
return &this->config_list;
|
||||
}
|
||||
|
||||
const ScriptConfigItem *ScriptInfo::GetConfigItem(const std::string_view name) const
|
||||
const ScriptConfigItem *ScriptInfo::GetConfigItem(std::string_view name) const
|
||||
{
|
||||
for (const auto &item : this->config_list) {
|
||||
if (item.name == name) return &item;
|
||||
|
||||
@@ -82,12 +82,12 @@ public:
|
||||
/**
|
||||
* Check if a given method exists.
|
||||
*/
|
||||
bool CheckMethod(const char *name) const;
|
||||
bool CheckMethod(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* Process the creation of a FileInfo object.
|
||||
*/
|
||||
static SQInteger Constructor(HSQUIRRELVM vm, ScriptInfo *info);
|
||||
static SQInteger Constructor(HSQUIRRELVM vm, ScriptInfo &info);
|
||||
|
||||
/**
|
||||
* Get the scanner which has found this ScriptInfo.
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
/**
|
||||
* Get the description of a certain Script config option.
|
||||
*/
|
||||
const ScriptConfigItem *GetConfigItem(const std::string_view name) const;
|
||||
const ScriptConfigItem *GetConfigItem(std::string_view name) const;
|
||||
|
||||
/**
|
||||
* Set a setting.
|
||||
@@ -149,7 +149,7 @@ private:
|
||||
class ScriptScanner *scanner = nullptr; ///< ScriptScanner object that was used to scan this script info.
|
||||
};
|
||||
|
||||
void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir);
|
||||
void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type);
|
||||
void Script_CreateDummyInfo(HSQUIRRELVM vm, std::string_view type, std::string_view dir);
|
||||
void Script_CreateDummy(HSQUIRRELVM vm, StringID string, std::string_view type);
|
||||
|
||||
#endif /* SCRIPT_INFO_HPP */
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "../string_func.h"
|
||||
#include "../strings_func.h"
|
||||
#include "../3rdparty/fmt/format.h"
|
||||
#include "../core/format.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
*/
|
||||
|
||||
/** Run the dummy info.nut. */
|
||||
void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir)
|
||||
void Script_CreateDummyInfo(HSQUIRRELVM vm, std::string_view type, std::string_view dir)
|
||||
{
|
||||
std::string dummy_script = fmt::format(
|
||||
"class Dummy{0} extends {0}Info {{\n"
|
||||
@@ -42,7 +42,7 @@ void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir)
|
||||
sq_pushroottable(vm);
|
||||
|
||||
/* Load and run the script */
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script.c_str(), dummy_script.size(), "dummy", SQTrue))) {
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script, "dummy", SQTrue))) {
|
||||
sq_push(vm, -2);
|
||||
if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) {
|
||||
sq_pop(vm, 1);
|
||||
@@ -78,7 +78,7 @@ static std::vector<std::string> EscapeQuotesAndSlashesAndSplitOnNewLines(const s
|
||||
}
|
||||
|
||||
/** Run the dummy AI and let it generate an error message. */
|
||||
void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type)
|
||||
void Script_CreateDummy(HSQUIRRELVM vm, StringID string, std::string_view type)
|
||||
{
|
||||
/* We want to translate the error message.
|
||||
* We do this in three steps:
|
||||
@@ -90,19 +90,18 @@ void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type)
|
||||
|
||||
/* 2) We construct the AI's code. This is done by merging a header, body and footer */
|
||||
std::string dummy_script;
|
||||
auto back_inserter = std::back_inserter(dummy_script);
|
||||
/* Just a rough ballpark estimate. */
|
||||
dummy_script.reserve(error_message.size() + 128 + 64 * messages.size());
|
||||
|
||||
fmt::format_to(back_inserter, "class Dummy{0} extends {0}Controller {{\n function Start()\n {{\n", type);
|
||||
format_append(dummy_script, "class Dummy{0} extends {0}Controller {{\n function Start()\n {{\n", type);
|
||||
for (std::string &message : messages) {
|
||||
fmt::format_to(back_inserter, " {}Log.Error(\"{}\");\n", type, message);
|
||||
format_append(dummy_script, " {}Log.Error(\"{}\");\n", type, message);
|
||||
}
|
||||
dummy_script += " }\n}\n";
|
||||
|
||||
/* 3) Finally we load and run the script */
|
||||
sq_pushroottable(vm);
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script.c_str(), dummy_script.size(), "dummy", SQTrue))) {
|
||||
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script, "dummy", SQTrue))) {
|
||||
sq_push(vm, -2);
|
||||
if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) {
|
||||
sq_pop(vm, 1);
|
||||
|
||||
@@ -24,46 +24,45 @@
|
||||
#include "api/script_event.hpp"
|
||||
#include "api/script_log.hpp"
|
||||
|
||||
#include "../company_base.h"
|
||||
#include "../company_func.h"
|
||||
#include "../company_type.h"
|
||||
#include "../fileio_func.h"
|
||||
#include "../goal_type.h"
|
||||
#include "../league_type.h"
|
||||
#include "../signs_type.h"
|
||||
#include "../story_type.h"
|
||||
#include "../misc/endian_buffer.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
ScriptStorage::~ScriptStorage()
|
||||
{
|
||||
/* Free our pointers */
|
||||
if (event_data != nullptr) ScriptEventController::FreeEventPointer();
|
||||
}
|
||||
ScriptStorage::ScriptStorage() = default;
|
||||
ScriptStorage::~ScriptStorage() = default;
|
||||
|
||||
/**
|
||||
* Callback called by squirrel when a script uses "print" and for error messages.
|
||||
* @param error_msg Is this an error message?
|
||||
* @param message The actual message text.
|
||||
*/
|
||||
static void PrintFunc(bool error_msg, const std::string &message)
|
||||
static void PrintFunc(bool error_msg, std::string_view message)
|
||||
{
|
||||
/* Convert to OpenTTD internal capable string */
|
||||
ScriptController::Print(error_msg, message);
|
||||
ScriptController::Print(error_msg, std::string{message});
|
||||
}
|
||||
|
||||
ScriptInstance::ScriptInstance(const char *APIName)
|
||||
ScriptInstance::ScriptInstance(std::string_view api_name)
|
||||
{
|
||||
this->storage = new ScriptStorage();
|
||||
this->engine = new Squirrel(APIName);
|
||||
this->storage = std::make_unique<ScriptStorage>();
|
||||
this->engine = std::make_unique<Squirrel>(api_name);
|
||||
this->engine->SetPrintFunction(&PrintFunc);
|
||||
}
|
||||
|
||||
void ScriptInstance::Initialize(const std::string &main_script, const std::string &instance_name, CompanyID company)
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
this->controller = new ScriptController(company);
|
||||
this->controller = std::make_unique<ScriptController>(company);
|
||||
|
||||
/* Register the API functions and classes */
|
||||
this->engine->SetGlobalPointer(this->engine);
|
||||
this->engine->SetGlobalPointer(this->engine.get());
|
||||
this->RegisterAPI();
|
||||
if (this->IsDead()) {
|
||||
/* Failed to register API; a message has already been logged. */
|
||||
@@ -71,7 +70,7 @@ void ScriptInstance::Initialize(const std::string &main_script, const std::strin
|
||||
}
|
||||
|
||||
try {
|
||||
ScriptObject::SetAllowDoCommand(false);
|
||||
ScriptObject::DisableDoCommandScope disabler{};
|
||||
/* Load and execute the script for this script */
|
||||
if (main_script == "%_dummy") {
|
||||
this->LoadDummyScript();
|
||||
@@ -82,16 +81,14 @@ void ScriptInstance::Initialize(const std::string &main_script, const std::strin
|
||||
}
|
||||
|
||||
/* Create the main-class */
|
||||
this->instance = new SQObject();
|
||||
if (!this->engine->CreateClassInstance(instance_name, this->controller, this->instance)) {
|
||||
this->instance = std::make_unique<SQObject>();
|
||||
if (!this->engine->CreateClassInstance(instance_name, this->controller.get(), this->instance.get())) {
|
||||
/* If CreateClassInstance has returned false instance has not been
|
||||
* registered with squirrel, so avoid trying to Release it by clearing it now */
|
||||
delete this->instance;
|
||||
this->instance = nullptr;
|
||||
this->instance.reset();
|
||||
this->Died();
|
||||
return;
|
||||
}
|
||||
ScriptObject::SetAllowDoCommand(true);
|
||||
} catch (Script_FatalError &e) {
|
||||
this->is_dead = true;
|
||||
this->engine->ThrowError(e.GetErrorMessage());
|
||||
@@ -102,7 +99,7 @@ void ScriptInstance::Initialize(const std::string &main_script, const std::strin
|
||||
|
||||
void ScriptInstance::RegisterAPI()
|
||||
{
|
||||
squirrel_register_std(this->engine);
|
||||
squirrel_register_std(*this->engine);
|
||||
}
|
||||
|
||||
bool ScriptInstance::LoadCompatibilityScript(std::string_view api_version, Subdirectory dir)
|
||||
@@ -132,6 +129,13 @@ bool ScriptInstance::LoadCompatibilityScripts(Subdirectory dir, std::span<const
|
||||
|
||||
ScriptLog::Info(fmt::format("Downgrading API to be compatible with version {}", this->api_version));
|
||||
|
||||
HSQUIRRELVM vm = this->engine->GetVM();
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, "CompatScriptRootTable");
|
||||
sq_pushroottable(vm);
|
||||
sq_newslot(vm, -3, SQFalse);
|
||||
sq_pop(vm, 1);
|
||||
|
||||
/* Downgrade the API till we are the same version as the script. The last
|
||||
* entry in the list is always the current version, so skip that one. */
|
||||
for (auto it = std::rbegin(api_versions) + 1; it != std::rend(api_versions); ++it) {
|
||||
@@ -140,19 +144,23 @@ bool ScriptInstance::LoadCompatibilityScripts(Subdirectory dir, std::span<const
|
||||
if (*it == this->api_version) break;
|
||||
}
|
||||
|
||||
sq_pushroottable(vm);
|
||||
sq_pushstring(vm, "CompatScriptRootTable");
|
||||
sq_deleteslot(vm, -2, SQFalse);
|
||||
sq_pop(vm, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ScriptInstance::~ScriptInstance()
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
this->in_shutdown = true;
|
||||
|
||||
if (instance != nullptr) this->engine->ReleaseObject(this->instance);
|
||||
if (engine != nullptr) delete this->engine;
|
||||
delete this->storage;
|
||||
delete this->controller;
|
||||
delete this->instance;
|
||||
if (instance != nullptr) this->engine->ReleaseObject(this->instance.get());
|
||||
|
||||
/* Engine must be reset explicitly in scope of the active instance. */
|
||||
this->engine.reset();
|
||||
}
|
||||
|
||||
void ScriptInstance::Continue()
|
||||
@@ -169,16 +177,14 @@ void ScriptInstance::Died()
|
||||
|
||||
this->last_allocated_memory = this->GetAllocatedMemory(); // Update cache
|
||||
|
||||
if (this->instance != nullptr) this->engine->ReleaseObject(this->instance);
|
||||
delete this->instance;
|
||||
delete this->engine;
|
||||
this->instance = nullptr;
|
||||
this->engine = nullptr;
|
||||
if (this->instance != nullptr) this->engine->ReleaseObject(this->instance.get());
|
||||
this->engine.reset();
|
||||
this->instance.reset();
|
||||
}
|
||||
|
||||
void ScriptInstance::GameLoop()
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
if (this->IsDead()) return;
|
||||
if (this->engine->HasScriptCrashed()) {
|
||||
@@ -202,7 +208,7 @@ void ScriptInstance::GameLoop()
|
||||
this->is_save_data_on_stack = false;
|
||||
}
|
||||
try {
|
||||
this->callback(this);
|
||||
this->callback(*this);
|
||||
} catch (Script_Suspend &e) {
|
||||
this->suspend = e.GetSuspendTime();
|
||||
this->callback = e.GetSuspendCallback();
|
||||
@@ -216,21 +222,22 @@ void ScriptInstance::GameLoop()
|
||||
|
||||
if (!this->is_started) {
|
||||
try {
|
||||
ScriptObject::SetAllowDoCommand(false);
|
||||
/* Run the constructor if it exists. Don't allow any DoCommands in it. */
|
||||
if (this->engine->MethodExists(*this->instance, "constructor")) {
|
||||
if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
|
||||
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started.");
|
||||
{
|
||||
ScriptObject::DisableDoCommandScope disabler{};
|
||||
/* Run the constructor if it exists. Don't allow any DoCommands in it. */
|
||||
if (this->engine->MethodExists(*this->instance, "constructor")) {
|
||||
if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
|
||||
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started.");
|
||||
this->Died();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!this->CallLoad() || this->engine->IsSuspended()) {
|
||||
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started.");
|
||||
this->Died();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!this->CallLoad() || this->engine->IsSuspended()) {
|
||||
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started.");
|
||||
this->Died();
|
||||
return;
|
||||
}
|
||||
ScriptObject::SetAllowDoCommand(true);
|
||||
/* Start the script by calling Start() */
|
||||
if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
|
||||
} catch (Script_Suspend &e) {
|
||||
@@ -268,65 +275,66 @@ void ScriptInstance::GameLoop()
|
||||
void ScriptInstance::CollectGarbage()
|
||||
{
|
||||
if (this->is_started && !this->IsDead()) {
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
this->engine->CollectGarbage();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturn(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturn(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(ScriptObject::GetLastCommandRes());
|
||||
instance.engine->InsertResult(ScriptObject::GetLastCommandRes());
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnVehicleID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnVehicleID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<VehicleID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<VehicleID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnSignID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnSignID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<SignID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<SignID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnGroupID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnGroupID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<GroupID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<GroupID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnGoalID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnGoalID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<GoalID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<GoalID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnStoryPageID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnStoryPageID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<StoryPageID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<StoryPageID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnStoryPageElementID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnStoryPageElementID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<StoryPageElementID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<StoryPageElementID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnLeagueTableElementID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnLeagueTableElementID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<LeagueTableElementID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<LeagueTableElementID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
/* static */ void ScriptInstance::DoCommandReturnLeagueTableID(ScriptInstance *instance)
|
||||
/* static */ void ScriptInstance::DoCommandReturnLeagueTableID(ScriptInstance &instance)
|
||||
{
|
||||
instance->engine->InsertResult(EndianBufferReader::ToValue<LeagueTableID>(ScriptObject::GetLastCommandResData()));
|
||||
instance.engine->InsertResult(EndianBufferReader::ToValue<LeagueTableID>(ScriptObject::GetLastCommandResData()));
|
||||
}
|
||||
|
||||
|
||||
ScriptStorage *ScriptInstance::GetStorage()
|
||||
ScriptStorage &ScriptInstance::GetStorage()
|
||||
{
|
||||
return this->storage;
|
||||
assert(this->storage != nullptr);
|
||||
return *this->storage;
|
||||
}
|
||||
|
||||
ScriptLogTypes::LogData &ScriptInstance::GetLogData()
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
return ScriptObject::GetLogData();
|
||||
}
|
||||
@@ -386,9 +394,9 @@ static const SaveLoad _script_byte[] = {
|
||||
_script_sl_byte = SQSL_STRING;
|
||||
SlObject(nullptr, _script_byte);
|
||||
}
|
||||
const SQChar *buf;
|
||||
sq_getstring(vm, index, &buf);
|
||||
size_t len = strlen(buf) + 1;
|
||||
std::string_view view;
|
||||
sq_getstring(vm, index, view);
|
||||
size_t len = view.size() + 1;
|
||||
if (len >= 255) {
|
||||
ScriptLog::Error("Maximum string length is 254 chars. No data saved.");
|
||||
return false;
|
||||
@@ -396,7 +404,7 @@ static const SaveLoad _script_byte[] = {
|
||||
if (!test) {
|
||||
_script_sl_byte = (uint8_t)len;
|
||||
SlObject(nullptr, _script_byte);
|
||||
SlCopy(const_cast<char *>(buf), len, SLE_CHAR);
|
||||
SlCopy(const_cast<char *>(view.data()), len, SLE_CHAR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -504,7 +512,7 @@ static const SaveLoad _script_byte[] = {
|
||||
|
||||
void ScriptInstance::Save()
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
/* Don't save data if the script didn't start yet or if it crashed. */
|
||||
if (this->engine == nullptr || this->engine->HasScriptCrashed()) {
|
||||
@@ -523,10 +531,9 @@ void ScriptInstance::Save()
|
||||
return;
|
||||
} else if (this->engine->MethodExists(*this->instance, "Save")) {
|
||||
HSQOBJECT savedata;
|
||||
/* We don't want to be interrupted during the save function. */
|
||||
bool backup_allow = ScriptObject::GetAllowDoCommand();
|
||||
ScriptObject::SetAllowDoCommand(false);
|
||||
try {
|
||||
/* We don't want to be interrupted during the save function. */
|
||||
ScriptObject::DisableDoCommandScope disabler{};
|
||||
if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) {
|
||||
/* The script crashed in the Save function. We can't kill
|
||||
* it here, but do so in the next script tick. */
|
||||
@@ -547,10 +554,9 @@ void ScriptInstance::Save()
|
||||
this->engine->CrashOccurred();
|
||||
return;
|
||||
}
|
||||
ScriptObject::SetAllowDoCommand(backup_allow);
|
||||
|
||||
if (!sq_istable(savedata)) {
|
||||
ScriptLog::Error(this->engine->IsSuspended() ? "This script took too long to Save." : "Save function should return a table.");
|
||||
ScriptLog::Error(this->GetOpsTillSuspend() <= 0 ? "This script took too long to Save." : "Save function should return a table.");
|
||||
SaveEmpty();
|
||||
this->engine->CrashOccurred();
|
||||
return;
|
||||
@@ -652,7 +658,7 @@ bool ScriptInstance::IsPaused()
|
||||
ScriptData *data;
|
||||
|
||||
bool operator()(const SQInteger &value) { sq_pushinteger(this->vm, value); return true; }
|
||||
bool operator()(const std::string &value) { sq_pushstring(this->vm, value, -1); return true; }
|
||||
bool operator()(const std::string &value) { sq_pushstring(this->vm, value); return true; }
|
||||
bool operator()(const SQBool &value) { sq_pushbool(this->vm, value); return true; }
|
||||
bool operator()(const SQSaveLoadType &type)
|
||||
{
|
||||
@@ -681,10 +687,10 @@ bool ScriptInstance::IsPaused()
|
||||
case SQSL_INSTANCE: {
|
||||
SQInteger top = sq_gettop(this->vm);
|
||||
LoadObjects(this->vm, this->data);
|
||||
const SQChar *buf;
|
||||
sq_getstring(this->vm, -1, &buf);
|
||||
std::string_view view;
|
||||
sq_getstring(this->vm, -1, view);
|
||||
Squirrel *engine = static_cast<Squirrel *>(sq_getforeignptr(this->vm));
|
||||
std::string class_name = fmt::format("{}{}", engine->GetAPIName(), buf);
|
||||
std::string class_name = fmt::format("{}{}", engine->GetAPIName(), view);
|
||||
sq_pushroottable(this->vm);
|
||||
sq_pushstring(this->vm, class_name);
|
||||
if (SQ_FAILED(sq_get(this->vm, -2))) throw Script_FatalError(fmt::format("'{}' doesn't exist", class_name));
|
||||
@@ -742,7 +748,7 @@ bool ScriptInstance::IsPaused()
|
||||
|
||||
void ScriptInstance::LoadOnStack(ScriptData *data)
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
if (this->IsDead() || data == nullptr) return;
|
||||
|
||||
@@ -781,7 +787,7 @@ bool ScriptInstance::CallLoad()
|
||||
/* Go to the instance-root */
|
||||
sq_pushobject(vm, *this->instance);
|
||||
/* Find the function-name inside the script */
|
||||
sq_pushstring(vm, "Load", -1);
|
||||
sq_pushstring(vm, "Load");
|
||||
/* Change the "Load" string in a function pointer */
|
||||
sq_get(vm, -2);
|
||||
/* Push the main instance as "this" object */
|
||||
@@ -806,7 +812,7 @@ SQInteger ScriptInstance::GetOpsTillSuspend()
|
||||
|
||||
bool ScriptInstance::DoCommandCallback(const CommandCost &result, const CommandDataBuffer &data, CommandDataBuffer result_data, Commands cmd)
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
if (!ScriptObject::CheckLastCommand(data, cmd)) {
|
||||
Debug(script, 1, "DoCommandCallback terminating a script, last command does not match expected command");
|
||||
@@ -830,7 +836,7 @@ bool ScriptInstance::DoCommandCallback(const CommandCost &result, const CommandD
|
||||
|
||||
void ScriptInstance::InsertEvent(class ScriptEvent *event)
|
||||
{
|
||||
ScriptObject::ActiveInstance active(this);
|
||||
ScriptObject::ActiveInstance active(*this);
|
||||
|
||||
ScriptEventController::InsertEvent(event);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
/**
|
||||
* Create a new script.
|
||||
*/
|
||||
ScriptInstance(const char *APIName);
|
||||
ScriptInstance(std::string_view api_name);
|
||||
virtual ~ScriptInstance();
|
||||
|
||||
/**
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
/**
|
||||
* Get the storage of this script.
|
||||
*/
|
||||
class ScriptStorage *GetStorage();
|
||||
class ScriptStorage &GetStorage();
|
||||
|
||||
/**
|
||||
* Get the log pointer of this script.
|
||||
@@ -101,52 +101,56 @@ public:
|
||||
/**
|
||||
* Return a true/false reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturn(ScriptInstance *instance);
|
||||
static void DoCommandReturn(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a VehicleID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnVehicleID(ScriptInstance *instance);
|
||||
static void DoCommandReturnVehicleID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a SignID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnSignID(ScriptInstance *instance);
|
||||
static void DoCommandReturnSignID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a GroupID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnGroupID(ScriptInstance *instance);
|
||||
static void DoCommandReturnGroupID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a GoalID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnGoalID(ScriptInstance *instance);
|
||||
static void DoCommandReturnGoalID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a StoryPageID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnStoryPageID(ScriptInstance *instance);
|
||||
static void DoCommandReturnStoryPageID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a StoryPageElementID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnStoryPageElementID(ScriptInstance *instance);
|
||||
static void DoCommandReturnStoryPageElementID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a LeagueTableID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnLeagueTableID(ScriptInstance *instance);
|
||||
static void DoCommandReturnLeagueTableID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Return a LeagueTableElementID reply for a DoCommand.
|
||||
*/
|
||||
static void DoCommandReturnLeagueTableElementID(ScriptInstance *instance);
|
||||
static void DoCommandReturnLeagueTableElementID(ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* Get the controller attached to the instance.
|
||||
*/
|
||||
class ScriptController *GetController() { return controller; }
|
||||
class ScriptController &GetController()
|
||||
{
|
||||
assert(this->controller != nullptr);
|
||||
return *this->controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "this script died" value
|
||||
@@ -252,7 +256,7 @@ public:
|
||||
void ReleaseSQObject(HSQOBJECT *obj);
|
||||
|
||||
protected:
|
||||
class Squirrel *engine = nullptr; ///< A wrapper around the squirrel vm.
|
||||
std::unique_ptr<class Squirrel> engine; ///< A wrapper around the squirrel vm.
|
||||
std::string api_version{}; ///< Current API used by this script.
|
||||
|
||||
/**
|
||||
@@ -284,9 +288,9 @@ protected:
|
||||
virtual void LoadDummyScript() = 0;
|
||||
|
||||
private:
|
||||
class ScriptController *controller = nullptr; ///< The script main class.
|
||||
class ScriptStorage *storage = nullptr; ///< Some global information for each running script.
|
||||
SQObject *instance = nullptr; ///< Squirrel-pointer to the script main class.
|
||||
std::unique_ptr<class ScriptStorage> storage; ///< Some global information for each running script.
|
||||
std::unique_ptr<class ScriptController> controller; ///< The script main class.
|
||||
std::unique_ptr<SQObject> instance; ///< Squirrel-pointer to the script main class.
|
||||
|
||||
bool is_started = false; ///< Is the scripts constructor executed?
|
||||
bool is_dead = false; ///< True if the script has been stopped.
|
||||
|
||||
@@ -44,21 +44,18 @@ bool ScriptScanner::AddFile(const std::string &filename, size_t, const std::stri
|
||||
return true;
|
||||
}
|
||||
|
||||
ScriptScanner::ScriptScanner() :
|
||||
engine(nullptr)
|
||||
{
|
||||
}
|
||||
ScriptScanner::ScriptScanner() = default;
|
||||
|
||||
void ScriptScanner::ResetEngine()
|
||||
{
|
||||
this->engine->Reset();
|
||||
this->engine->SetGlobalPointer(this);
|
||||
this->RegisterAPI(this->engine);
|
||||
this->RegisterAPI(*this->engine);
|
||||
}
|
||||
|
||||
void ScriptScanner::Initialize(const char *name)
|
||||
void ScriptScanner::Initialize(std::string_view name)
|
||||
{
|
||||
this->engine = new Squirrel(name);
|
||||
this->engine = std::make_unique<Squirrel>(name);
|
||||
|
||||
this->RescanDir();
|
||||
|
||||
@@ -68,8 +65,6 @@ void ScriptScanner::Initialize(const char *name)
|
||||
ScriptScanner::~ScriptScanner()
|
||||
{
|
||||
this->Reset();
|
||||
|
||||
delete this->engine;
|
||||
}
|
||||
|
||||
void ScriptScanner::RescanDir()
|
||||
@@ -83,57 +78,52 @@ void ScriptScanner::RescanDir()
|
||||
|
||||
void ScriptScanner::Reset()
|
||||
{
|
||||
for (const auto &item : this->info_list) {
|
||||
delete item.second;
|
||||
}
|
||||
|
||||
this->info_list.clear();
|
||||
this->info_single_list.clear();
|
||||
this->info_vector.clear();
|
||||
}
|
||||
|
||||
void ScriptScanner::RegisterScript(ScriptInfo *info)
|
||||
void ScriptScanner::RegisterScript(std::unique_ptr<ScriptInfo> &&info)
|
||||
{
|
||||
std::string script_original_name = this->GetScriptName(info);
|
||||
std::string script_original_name = this->GetScriptName(*info);
|
||||
std::string script_name = fmt::format("{}.{}", script_original_name, info->GetVersion());
|
||||
|
||||
/* Check if GetShortName follows the rules */
|
||||
if (info->GetShortName().size() != 4) {
|
||||
Debug(script, 0, "The script '{}' returned a string from GetShortName() which is not four characters. Unable to load the script.", info->GetName());
|
||||
delete info;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->info_list.find(script_name) != this->info_list.end()) {
|
||||
if (auto it = this->info_list.find(script_name); it != this->info_list.end()) {
|
||||
/* This script was already registered */
|
||||
#ifdef _WIN32
|
||||
/* Windows doesn't care about the case */
|
||||
if (StrEqualsIgnoreCase(this->info_list[script_name]->GetMainScript(), info->GetMainScript())) {
|
||||
if (StrEqualsIgnoreCase(it->second->GetMainScript(), info->GetMainScript())) {
|
||||
#else
|
||||
if (this->info_list[script_name]->GetMainScript() == info->GetMainScript()) {
|
||||
if (it->second->GetMainScript() == info->GetMainScript()) {
|
||||
#endif
|
||||
delete info;
|
||||
return;
|
||||
}
|
||||
|
||||
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, " 1: {}", it->second->GetMainScript());
|
||||
Debug(script, 1, " 2: {}", info->GetMainScript());
|
||||
Debug(script, 1, "The first is taking precedence.");
|
||||
|
||||
delete info;
|
||||
return;
|
||||
}
|
||||
|
||||
this->info_list[script_name] = info;
|
||||
ScriptInfo *script_info = this->info_vector.emplace_back(std::move(info)).get();
|
||||
this->info_list[script_name] = script_info;
|
||||
|
||||
if (!info->IsDeveloperOnly() || _settings_client.gui.ai_developer_tools) {
|
||||
if (!script_info->IsDeveloperOnly() || _settings_client.gui.ai_developer_tools) {
|
||||
/* Add the script to the 'unique' script list, where only the highest version
|
||||
* of the script is registered. */
|
||||
auto it = this->info_single_list.find(script_original_name);
|
||||
if (it == this->info_single_list.end()) {
|
||||
this->info_single_list[script_original_name] = info;
|
||||
} else if (it->second->GetVersion() < info->GetVersion()) {
|
||||
it->second = info;
|
||||
this->info_single_list[script_original_name] = script_info;
|
||||
} else if (it->second->GetVersion() < script_info->GetVersion()) {
|
||||
it->second = script_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,17 +185,17 @@ struct ScriptFileChecksumCreator : FileScanner {
|
||||
* @param info The script to get the shortname and md5 sum from.
|
||||
* @return True iff they're the same.
|
||||
*/
|
||||
static bool IsSameScript(const ContentInfo &ci, bool md5sum, ScriptInfo *info, Subdirectory dir)
|
||||
static bool IsSameScript(const ContentInfo &ci, bool md5sum, const ScriptInfo &info, Subdirectory dir)
|
||||
{
|
||||
uint32_t id = 0;
|
||||
const char *str = info->GetShortName().c_str();
|
||||
for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j);
|
||||
auto str = std::string_view{info.GetShortName()}.substr(0, 4);
|
||||
for (size_t j = 0; j < str.size(); j++) id |= static_cast<uint8_t>(str[j]) << (8 * j);
|
||||
|
||||
if (id != ci.unique_id) return false;
|
||||
if (!md5sum) return true;
|
||||
|
||||
ScriptFileChecksumCreator checksum(dir);
|
||||
const auto &tar_filename = info->GetTarFile();
|
||||
const auto &tar_filename = info.GetTarFile();
|
||||
TarList::iterator iter;
|
||||
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
|
||||
@@ -215,8 +205,8 @@ static bool IsSameScript(const ContentInfo &ci, bool md5sum, ScriptInfo *info, S
|
||||
if (tar.second.tar_filename != iter->first) continue;
|
||||
|
||||
/* Check the extension. */
|
||||
const char *ext = strrchr(tar.first.c_str(), '.');
|
||||
if (ext == nullptr || !StrEqualsIgnoreCase(ext, ".nut")) continue;
|
||||
auto ext = tar.first.rfind('.');
|
||||
if (ext == std::string_view::npos || !StrEqualsIgnoreCase(tar.first.substr(ext), ".nut")) continue;
|
||||
|
||||
checksum.AddFile(tar.first, 0, tar_filename);
|
||||
}
|
||||
@@ -224,7 +214,7 @@ static bool IsSameScript(const ContentInfo &ci, bool md5sum, ScriptInfo *info, S
|
||||
/* There'll always be at least 1 path separator character in a script
|
||||
* main script name as the search algorithm requires the main script to
|
||||
* be in a subdirectory of the script directory; so <dir>/<path>/main.nut. */
|
||||
const std::string &main_script = info->GetMainScript();
|
||||
const std::string &main_script = info.GetMainScript();
|
||||
std::string path = main_script.substr(0, main_script.find_last_of(PATHSEPCHAR));
|
||||
checksum.Scan(".nut", path);
|
||||
}
|
||||
@@ -235,15 +225,15 @@ static bool IsSameScript(const ContentInfo &ci, bool md5sum, ScriptInfo *info, S
|
||||
bool ScriptScanner::HasScript(const ContentInfo &ci, bool md5sum)
|
||||
{
|
||||
for (const auto &item : this->info_list) {
|
||||
if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return true;
|
||||
if (IsSameScript(ci, md5sum, *item.second, this->GetDirectory())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *ScriptScanner::FindMainScript(const ContentInfo &ci, bool md5sum)
|
||||
std::optional<std::string_view> ScriptScanner::FindMainScript(const ContentInfo &ci, bool md5sum)
|
||||
{
|
||||
for (const auto &item : this->info_list) {
|
||||
if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return item.second->GetMainScript().c_str();
|
||||
if (IsSameScript(ci, md5sum, *item.second, this->GetDirectory())) return item.second->GetMainScript();
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "../fileio_func.h"
|
||||
#include "../string_func.h"
|
||||
|
||||
typedef std::map<std::string, class ScriptInfo *, CaseInsensitiveComparator> ScriptInfoList; ///< Type for the list of scripts.
|
||||
using ScriptInfoList = std::map<std::string, class ScriptInfo *, CaseInsensitiveComparator>; ///< Type for the list of scripts.
|
||||
|
||||
/** Scanner to help finding scripts. */
|
||||
class ScriptScanner : public FileScanner {
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
/**
|
||||
* Get the engine of the main squirrel handler (it indexes all available scripts).
|
||||
*/
|
||||
class Squirrel *GetEngine() { return this->engine; }
|
||||
class Squirrel *GetEngine() { return this->engine.get(); }
|
||||
|
||||
/**
|
||||
* Get the current main script the ScanDir is currently tracking.
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
/**
|
||||
* Register a ScriptInfo to the scanner.
|
||||
*/
|
||||
void RegisterScript(class ScriptInfo *info);
|
||||
void RegisterScript(std::unique_ptr<class ScriptInfo> &&info);
|
||||
|
||||
/**
|
||||
* Get the list of registered scripts to print on the console.
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
* @param md5sum Whether to check the MD5 checksum.
|
||||
* @return A filename of a file of the content, else \c nullptr.
|
||||
*/
|
||||
const char *FindMainScript(const ContentInfo &ci, bool md5sum);
|
||||
std::optional<std::string_view> FindMainScript(const ContentInfo &ci, bool md5sum);
|
||||
|
||||
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override;
|
||||
|
||||
@@ -84,28 +84,30 @@ public:
|
||||
void RescanDir();
|
||||
|
||||
protected:
|
||||
class Squirrel *engine; ///< The engine we're scanning with.
|
||||
std::unique_ptr<class Squirrel> engine; ///< The engine we're scanning with.
|
||||
std::string main_script; ///< The full path of the script.
|
||||
std::string tar_file; ///< If, which tar file the script was in.
|
||||
|
||||
ScriptInfoList info_list; ///< The list of all script.
|
||||
std::vector<std::unique_ptr<ScriptInfo>> info_vector;
|
||||
|
||||
ScriptInfoList info_list; ///< The list of all script.
|
||||
ScriptInfoList info_single_list; ///< The list of all unique script. The best script (highest version) is shown.
|
||||
|
||||
/**
|
||||
* Initialize the scanner.
|
||||
* @param name The name of the scanner ("AIScanner", "GSScanner", ..).
|
||||
*/
|
||||
void Initialize(const char *name);
|
||||
void Initialize(std::string_view name);
|
||||
|
||||
/**
|
||||
* Get the script name how to store the script in memory.
|
||||
*/
|
||||
virtual std::string GetScriptName(ScriptInfo *info) = 0;
|
||||
virtual std::string GetScriptName(ScriptInfo &info) = 0;
|
||||
|
||||
/**
|
||||
* Get the filename to scan for this type of script.
|
||||
*/
|
||||
virtual const char *GetFileName() const = 0;
|
||||
virtual std::string_view GetFileName() const = 0;
|
||||
|
||||
/**
|
||||
* Get the directory to scan in.
|
||||
@@ -115,12 +117,12 @@ protected:
|
||||
/**
|
||||
* Register the API for this ScriptInfo.
|
||||
*/
|
||||
virtual void RegisterAPI(class Squirrel *engine) = 0;
|
||||
virtual void RegisterAPI(class Squirrel &engine) = 0;
|
||||
|
||||
/**
|
||||
* Get the type of the script, in plural.
|
||||
*/
|
||||
virtual const char *GetScannerName() const = 0;
|
||||
virtual std::string_view GetScannerName() const = 0;
|
||||
|
||||
/**
|
||||
* Reset all allocated lists.
|
||||
|
||||
@@ -10,15 +10,22 @@
|
||||
#ifndef SCRIPT_STORAGE_HPP
|
||||
#define SCRIPT_STORAGE_HPP
|
||||
|
||||
#include "../signs_func.h"
|
||||
#include "../vehicle_func.h"
|
||||
#include <queue>
|
||||
|
||||
#include "../command_type.h"
|
||||
#include "../company_type.h"
|
||||
#include "../rail_type.h"
|
||||
#include "../road_type.h"
|
||||
#include "../group.h"
|
||||
#include "../goal_type.h"
|
||||
#include "../story_type.h"
|
||||
|
||||
#include "script_types.hpp"
|
||||
#include "script_log_types.hpp"
|
||||
#include "script_object.hpp"
|
||||
|
||||
class ScriptEvent;
|
||||
|
||||
/* This is a "struct", so we can forward declare it, and use as incomplete type. */
|
||||
struct ScriptEventQueue : std::queue<ScriptObjectRef<ScriptEvent>> {
|
||||
};
|
||||
|
||||
/**
|
||||
* The callback function for Mode-classes.
|
||||
@@ -36,53 +43,35 @@ typedef bool (ScriptAsyncModeProc)();
|
||||
class ScriptStorage {
|
||||
friend class ScriptObject;
|
||||
private:
|
||||
ScriptModeProc *mode; ///< The current build mode we are int.
|
||||
class ScriptObject *mode_instance; ///< The instance belonging to the current build mode.
|
||||
ScriptAsyncModeProc *async_mode; ///< The current command async mode we are in.
|
||||
class ScriptObject *async_mode_instance; ///< The instance belonging to the current command async mode.
|
||||
CompanyID root_company; ///< The root company, the company that the script really belongs to.
|
||||
CompanyID company; ///< The current company.
|
||||
ScriptModeProc *mode = nullptr; ///< The current build mode we are int.
|
||||
class ScriptObject *mode_instance = nullptr; ///< The instance belonging to the current build mode.
|
||||
ScriptAsyncModeProc *async_mode = nullptr; ///< The current command async mode we are in.
|
||||
class ScriptObject *async_mode_instance = nullptr; ///< The instance belonging to the current command async mode.
|
||||
CompanyID root_company = INVALID_OWNER; ///< The root company, the company that the script really belongs to.
|
||||
CompanyID company = INVALID_OWNER; ///< The current company.
|
||||
|
||||
uint delay; ///< The ticks of delay each DoCommand has.
|
||||
bool allow_do_command; ///< Is the usage of DoCommands restricted?
|
||||
uint delay = 1; ///< The ticks of delay each DoCommand has.
|
||||
bool allow_do_command = true; ///< Is the usage of DoCommands restricted?
|
||||
|
||||
CommandCost costs; ///< The costs the script is tracking.
|
||||
Money last_cost; ///< The last cost of the command.
|
||||
CommandCost costs; ///< The costs the script is tracking.
|
||||
Money last_cost = 0; ///< The last cost of the command.
|
||||
ScriptErrorType last_error{}; ///< The last error of the command.
|
||||
bool last_command_res; ///< The last result of the command.
|
||||
bool last_command_res = true; ///< The last result of the command.
|
||||
|
||||
CommandDataBuffer last_data; ///< The last data passed to a command.
|
||||
Commands last_cmd; ///< The last cmd passed to a command.
|
||||
CommandDataBuffer last_cmd_ret; ///< The extra data returned by the last command.
|
||||
CommandDataBuffer last_data; ///< The last data passed to a command.
|
||||
Commands last_cmd = CMD_END; ///< The last cmd passed to a command.
|
||||
CommandDataBuffer last_cmd_ret; ///< The extra data returned by the last command.
|
||||
|
||||
std::vector<int> callback_value; ///< The values which need to survive a callback.
|
||||
|
||||
RoadType road_type; ///< The current roadtype we build.
|
||||
RailType rail_type; ///< The current railtype we build.
|
||||
RoadType road_type = INVALID_ROADTYPE; ///< The current roadtype we build.
|
||||
RailType rail_type = INVALID_RAILTYPE; ///< The current railtype we build.
|
||||
|
||||
void *event_data; ///< Pointer to the event data storage.
|
||||
ScriptLogTypes::LogData log_data;///< Log data storage.
|
||||
ScriptEventQueue event_queue; ///< Event queue for this script.
|
||||
ScriptLogTypes::LogData log_data; ///< Log data storage.
|
||||
|
||||
public:
|
||||
ScriptStorage() :
|
||||
mode (nullptr),
|
||||
mode_instance (nullptr),
|
||||
async_mode (nullptr),
|
||||
async_mode_instance (nullptr),
|
||||
root_company (INVALID_OWNER),
|
||||
company (INVALID_OWNER),
|
||||
delay (1),
|
||||
allow_do_command (true),
|
||||
/* costs (can't be set) */
|
||||
last_cost (0),
|
||||
last_command_res (true),
|
||||
last_cmd (CMD_END),
|
||||
/* calback_value (can't be set) */
|
||||
road_type (INVALID_ROADTYPE),
|
||||
rail_type (INVALID_RAILTYPE),
|
||||
event_data (nullptr)
|
||||
{ }
|
||||
|
||||
ScriptStorage();
|
||||
~ScriptStorage();
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
/**
|
||||
* The callback function when a script suspends.
|
||||
*/
|
||||
typedef void (Script_SuspendCallbackProc)(class ScriptInstance *instance);
|
||||
typedef void (Script_SuspendCallbackProc)(class ScriptInstance &instance);
|
||||
|
||||
/**
|
||||
* A throw-class that is given when the script wants to suspend.
|
||||
|
||||
+93
-68
@@ -18,6 +18,8 @@
|
||||
#include <sqstdaux.h>
|
||||
#include <../squirrel/sqpcheader.h>
|
||||
#include <../squirrel/sqvm.h>
|
||||
#include "../core/math_func.hpp"
|
||||
#include "../core/string_consumer.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -132,7 +134,7 @@ public:
|
||||
this->CheckAllocationAllowed(size - oldsize);
|
||||
|
||||
void *new_p = this->DoAlloc(size);
|
||||
memcpy(new_p, p, std::min(oldsize, size));
|
||||
std::copy_n(static_cast<std::byte *>(p), std::min(oldsize, size), static_cast<std::byte *>(new_p));
|
||||
this->Free(p, oldsize);
|
||||
|
||||
return new_p;
|
||||
@@ -177,7 +179,7 @@ size_t Squirrel::GetAllocatedMemory() const noexcept
|
||||
}
|
||||
|
||||
|
||||
void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column)
|
||||
void Squirrel::CompileError(HSQUIRRELVM vm, std::string_view desc, std::string_view source, SQInteger line, SQInteger column)
|
||||
{
|
||||
std::string msg = fmt::format("Error {}:{}/{}: {}", source, line, column, desc);
|
||||
|
||||
@@ -192,7 +194,7 @@ void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *so
|
||||
}
|
||||
}
|
||||
|
||||
void Squirrel::ErrorPrintFunc(HSQUIRRELVM vm, const std::string &s)
|
||||
void Squirrel::ErrorPrintFunc(HSQUIRRELVM vm, std::string_view s)
|
||||
{
|
||||
/* Check if we have a custom print function */
|
||||
SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func;
|
||||
@@ -203,7 +205,7 @@ void Squirrel::ErrorPrintFunc(HSQUIRRELVM vm, const std::string &s)
|
||||
}
|
||||
}
|
||||
|
||||
void Squirrel::RunError(HSQUIRRELVM vm, const SQChar *error)
|
||||
void Squirrel::RunError(HSQUIRRELVM vm, std::string_view error)
|
||||
{
|
||||
/* Set the print function to something that prints to stderr */
|
||||
SQPRINTFUNCTION pf = sq_getprintfunc(vm);
|
||||
@@ -227,11 +229,11 @@ void Squirrel::RunError(HSQUIRRELVM vm, const SQChar *error)
|
||||
|
||||
SQInteger Squirrel::_RunError(HSQUIRRELVM vm)
|
||||
{
|
||||
const SQChar *sErr = nullptr;
|
||||
std::string_view view;
|
||||
|
||||
if (sq_gettop(vm) >= 1) {
|
||||
if (SQ_SUCCEEDED(sq_getstring(vm, -1, &sErr))) {
|
||||
Squirrel::RunError(vm, sErr);
|
||||
if (SQ_SUCCEEDED(sq_getstring(vm, -1, view))) {
|
||||
Squirrel::RunError(vm, view);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -240,7 +242,7 @@ SQInteger Squirrel::_RunError(HSQUIRRELVM vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Squirrel::PrintFunc(HSQUIRRELVM vm, const std::string &s)
|
||||
void Squirrel::PrintFunc(HSQUIRRELVM vm, std::string_view s)
|
||||
{
|
||||
/* Check if we have a custom print function */
|
||||
SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func;
|
||||
@@ -251,57 +253,57 @@ void Squirrel::PrintFunc(HSQUIRRELVM vm, const std::string &s)
|
||||
}
|
||||
}
|
||||
|
||||
void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, const char *params, void *userdata, int size)
|
||||
void Squirrel::AddMethod(std::string_view method_name, SQFUNCTION proc, std::string_view params, void *userdata, int size)
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
|
||||
sq_pushstring(this->vm, method_name, -1);
|
||||
sq_pushstring(this->vm, method_name);
|
||||
|
||||
if (size != 0) {
|
||||
void *ptr = sq_newuserdata(vm, size);
|
||||
memcpy(ptr, userdata, size);
|
||||
std::copy_n(static_cast<std::byte *>(userdata), size, static_cast<std::byte *>(ptr));
|
||||
}
|
||||
|
||||
sq_newclosure(this->vm, proc, size != 0 ? 1 : 0);
|
||||
if (nparam != 0) sq_setparamscheck(this->vm, nparam, params);
|
||||
if (!params.empty()) sq_setparamscheck(this->vm, params.size(), params);
|
||||
sq_setnativeclosurename(this->vm, -1, method_name);
|
||||
sq_newslot(this->vm, -3, SQFalse);
|
||||
}
|
||||
|
||||
void Squirrel::AddConst(const char *var_name, int value)
|
||||
void Squirrel::AddConst(std::string_view var_name, int value)
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
|
||||
sq_pushstring(this->vm, var_name, -1);
|
||||
sq_pushstring(this->vm, var_name);
|
||||
sq_pushinteger(this->vm, value);
|
||||
sq_newslot(this->vm, -3, SQTrue);
|
||||
}
|
||||
|
||||
void Squirrel::AddConst(const char *var_name, bool value)
|
||||
void Squirrel::AddConst(std::string_view var_name, bool value)
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
|
||||
sq_pushstring(this->vm, var_name, -1);
|
||||
sq_pushstring(this->vm, var_name);
|
||||
sq_pushbool(this->vm, value);
|
||||
sq_newslot(this->vm, -3, SQTrue);
|
||||
}
|
||||
|
||||
void Squirrel::AddClassBegin(const char *class_name)
|
||||
void Squirrel::AddClassBegin(std::string_view class_name)
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
|
||||
sq_pushroottable(this->vm);
|
||||
sq_pushstring(this->vm, class_name, -1);
|
||||
sq_pushstring(this->vm, class_name);
|
||||
sq_newclass(this->vm, SQFalse);
|
||||
}
|
||||
|
||||
void Squirrel::AddClassBegin(const char *class_name, const char *parent_class)
|
||||
void Squirrel::AddClassBegin(std::string_view class_name, std::string_view parent_class)
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
|
||||
sq_pushroottable(this->vm);
|
||||
sq_pushstring(this->vm, class_name, -1);
|
||||
sq_pushstring(this->vm, parent_class, -1);
|
||||
sq_pushstring(this->vm, class_name);
|
||||
sq_pushstring(this->vm, parent_class);
|
||||
if (SQ_FAILED(sq_get(this->vm, -3))) {
|
||||
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);
|
||||
@@ -318,7 +320,7 @@ void Squirrel::AddClassEnd()
|
||||
sq_pop(vm, 1);
|
||||
}
|
||||
|
||||
bool Squirrel::MethodExists(HSQOBJECT instance, const char *method_name)
|
||||
bool Squirrel::MethodExists(HSQOBJECT instance, std::string_view method_name)
|
||||
{
|
||||
assert(!this->crashed);
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
@@ -327,7 +329,7 @@ bool Squirrel::MethodExists(HSQOBJECT instance, const char *method_name)
|
||||
/* Go to the instance-root */
|
||||
sq_pushobject(this->vm, instance);
|
||||
/* Find the function-name inside the script */
|
||||
sq_pushstring(this->vm, method_name, -1);
|
||||
sq_pushstring(this->vm, method_name);
|
||||
if (SQ_FAILED(sq_get(this->vm, -2))) {
|
||||
sq_settop(this->vm, top);
|
||||
return false;
|
||||
@@ -371,7 +373,7 @@ void Squirrel::CollectGarbage()
|
||||
sq_collectgarbage(this->vm);
|
||||
}
|
||||
|
||||
bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend)
|
||||
bool Squirrel::CallMethod(HSQOBJECT instance, std::string_view method_name, HSQOBJECT *ret, int suspend)
|
||||
{
|
||||
assert(!this->crashed);
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
@@ -386,7 +388,7 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT
|
||||
/* Go to the instance-root */
|
||||
sq_pushobject(this->vm, instance);
|
||||
/* Find the function-name inside the script */
|
||||
sq_pushstring(this->vm, method_name, -1);
|
||||
sq_pushstring(this->vm, method_name);
|
||||
if (SQ_FAILED(sq_get(this->vm, -2))) {
|
||||
Debug(misc, 0, "[squirrel] Could not find '{}' in the class", method_name);
|
||||
sq_settop(this->vm, top);
|
||||
@@ -405,16 +407,19 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Squirrel::CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend)
|
||||
bool Squirrel::CallStringMethod(HSQOBJECT instance, std::string_view method_name, std::string *res, int suspend)
|
||||
{
|
||||
HSQOBJECT ret;
|
||||
if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
|
||||
if (ret._type != OT_STRING) return false;
|
||||
*res = StrMakeValid(ObjectToString(&ret));
|
||||
|
||||
auto str = ObjectToString(&ret);
|
||||
if (!str.has_value()) return false;
|
||||
|
||||
*res = StrMakeValid(*str);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Squirrel::CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend)
|
||||
bool Squirrel::CallIntegerMethod(HSQOBJECT instance, std::string_view method_name, int *res, int suspend)
|
||||
{
|
||||
HSQOBJECT ret;
|
||||
if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
|
||||
@@ -423,7 +428,7 @@ bool Squirrel::CallIntegerMethod(HSQOBJECT instance, const char *method_name, in
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend)
|
||||
bool Squirrel::CallBoolMethod(HSQOBJECT instance, std::string_view method_name, bool *res, int suspend)
|
||||
{
|
||||
HSQOBJECT ret;
|
||||
if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
|
||||
@@ -442,11 +447,10 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool
|
||||
sq_pushroottable(vm);
|
||||
|
||||
if (prepend_API_name) {
|
||||
std::string prepended_class_name = engine->GetAPIName();
|
||||
prepended_class_name += class_name;
|
||||
sq_pushstring(vm, prepended_class_name, -1);
|
||||
std::string prepended_class_name = fmt::format("{}{}", engine->GetAPIName(), class_name);
|
||||
sq_pushstring(vm, prepended_class_name);
|
||||
} else {
|
||||
sq_pushstring(vm, class_name, -1);
|
||||
sq_pushstring(vm, class_name);
|
||||
}
|
||||
|
||||
if (SQ_FAILED(sq_get(vm, -2))) {
|
||||
@@ -486,7 +490,7 @@ bool Squirrel::CreateClassInstance(const std::string &class_name, void *real_ins
|
||||
return Squirrel::CreateClassInstanceVM(this->vm, class_name, real_instance, instance, nullptr);
|
||||
}
|
||||
|
||||
/* static */ SQUserPointer Squirrel::GetRealInstance(HSQUIRRELVM vm, int index, const char *tag)
|
||||
/* static */ SQUserPointer Squirrel::GetRealInstance(HSQUIRRELVM vm, int index, std::string_view tag)
|
||||
{
|
||||
if (index < 0) index += sq_gettop(vm) + 1;
|
||||
Squirrel *engine = static_cast<Squirrel *>(sq_getforeignptr(vm));
|
||||
@@ -503,8 +507,8 @@ bool Squirrel::CreateClassInstance(const std::string &class_name, void *real_ins
|
||||
throw sq_throwerror(vm, fmt::format("parameter {} has an invalid type ; expected: '{}'", index - 1, class_name));
|
||||
}
|
||||
|
||||
Squirrel::Squirrel(const char *APIName) :
|
||||
APIName(APIName), allocator(new ScriptAllocator())
|
||||
Squirrel::Squirrel(std::string_view api_name) :
|
||||
api_name(api_name), allocator(std::make_unique<ScriptAllocator>())
|
||||
{
|
||||
this->Initialize();
|
||||
}
|
||||
@@ -532,7 +536,7 @@ void Squirrel::Initialize()
|
||||
sq_setforeignptr(this->vm, this);
|
||||
|
||||
sq_pushroottable(this->vm);
|
||||
squirrel_register_global_std(this);
|
||||
squirrel_register_global_std(*this);
|
||||
|
||||
/* Set consts table as delegate of root table, so consts/enums defined via require() are accessible */
|
||||
sq_pushconsttable(this->vm);
|
||||
@@ -544,52 +548,73 @@ private:
|
||||
FileHandle file;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
std::string buffer;
|
||||
StringConsumer consumer;
|
||||
|
||||
size_t ReadInternal(std::span<char> buf)
|
||||
{
|
||||
size_t count = buf.size();
|
||||
if (this->pos + count > this->size) {
|
||||
count = this->size - this->pos;
|
||||
}
|
||||
if (count > 0) count = fread(buf.data(), 1, count, this->file);
|
||||
this->pos += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public:
|
||||
SQFile(FileHandle file, size_t size) : file(std::move(file)), size(size), pos(0) {}
|
||||
SQFile(FileHandle file, size_t size) : file(std::move(file)), size(size), pos(0), consumer(buffer) {}
|
||||
|
||||
size_t Read(void *buf, size_t elemsize, size_t count)
|
||||
StringConsumer &GetConsumer(size_t min_size = 64)
|
||||
{
|
||||
assert(elemsize != 0);
|
||||
if (this->pos + (elemsize * count) > this->size) {
|
||||
count = (this->size - this->pos) / elemsize;
|
||||
if (this->consumer.GetBytesLeft() < min_size && this->pos < this->size) {
|
||||
this->buffer.erase(0, this->consumer.GetBytesRead());
|
||||
|
||||
size_t buffer_size = this->buffer.size();
|
||||
size_t read_size = Align(min_size - buffer_size, 4096); // read pages of 4096 bytes
|
||||
/* TODO C++23: use std::string::resize_and_overwrite() */
|
||||
this->buffer.resize(buffer_size + read_size);
|
||||
auto dest = std::span(this->buffer.data(), this->buffer.size()).subspan(buffer_size);
|
||||
buffer_size += this->ReadInternal(dest);
|
||||
this->buffer.resize(buffer_size);
|
||||
|
||||
this->consumer = StringConsumer(this->buffer);
|
||||
}
|
||||
if (count == 0) return 0;
|
||||
size_t ret = fread(buf, elemsize, count, this->file);
|
||||
this->pos += ret * elemsize;
|
||||
return ret;
|
||||
return this->consumer;
|
||||
}
|
||||
|
||||
size_t Read(void *buf, size_t max_size)
|
||||
{
|
||||
std::span<char> dest(reinterpret_cast<char *>(buf), max_size);
|
||||
|
||||
auto view = this->consumer.Read(max_size);
|
||||
std::copy(view.data(), view.data() + view.size(), dest.data());
|
||||
size_t result_size = view.size();
|
||||
|
||||
if (result_size < max_size) {
|
||||
assert(!this->consumer.AnyBytesLeft());
|
||||
result_size += this->ReadInternal(dest.subspan(result_size));
|
||||
}
|
||||
|
||||
return result_size;
|
||||
}
|
||||
};
|
||||
|
||||
static char32_t _io_file_lexfeed_ASCII(SQUserPointer file)
|
||||
{
|
||||
unsigned char c;
|
||||
if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) return c;
|
||||
return 0;
|
||||
StringConsumer &consumer = reinterpret_cast<SQFile *>(file)->GetConsumer();
|
||||
return consumer.TryReadUint8().value_or(0); // read as unsigned, otherwise integer promotion breaks it
|
||||
}
|
||||
|
||||
static char32_t _io_file_lexfeed_UTF8(SQUserPointer file)
|
||||
{
|
||||
char buffer[5];
|
||||
|
||||
/* Read the first character, and get the length based on UTF-8 specs. If invalid, bail out. */
|
||||
if (((SQFile *)file)->Read(buffer, sizeof(buffer[0]), 1) != 1) return 0;
|
||||
uint len = Utf8EncodedCharLen(buffer[0]);
|
||||
if (len == 0) return -1;
|
||||
|
||||
/* Read the remaining bits. */
|
||||
if (len > 1 && ((SQFile *)file)->Read(buffer + 1, sizeof(buffer[0]), len - 1) != len - 1) return 0;
|
||||
|
||||
/* Convert the character, and when definitely invalid, bail out as well. */
|
||||
char32_t c;
|
||||
if (Utf8Decode(&c, buffer) != len) return -1;
|
||||
|
||||
return c;
|
||||
StringConsumer &consumer = reinterpret_cast<SQFile *>(file)->GetConsumer();
|
||||
return consumer.AnyBytesLeft() ? consumer.ReadUtf8(-1) : 0;
|
||||
}
|
||||
|
||||
static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger size)
|
||||
{
|
||||
SQInteger ret = ((SQFile *)file)->Read(buf, 1, size);
|
||||
SQInteger ret = reinterpret_cast<SQFile *>(file)->Read(buf, size);
|
||||
if (ret == 0) return -1;
|
||||
return ret;
|
||||
}
|
||||
@@ -600,10 +625,10 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool
|
||||
|
||||
std::optional<FileHandle> file = std::nullopt;
|
||||
size_t size;
|
||||
if (strncmp(this->GetAPIName(), "AI", 2) == 0) {
|
||||
if (this->GetAPIName().starts_with("AI")) {
|
||||
file = FioFOpenFile(filename, "rb", AI_DIR, &size);
|
||||
if (!file.has_value()) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size);
|
||||
} else if (strncmp(this->GetAPIName(), "GS", 2) == 0) {
|
||||
} else if (this->GetAPIName().starts_with("GS")) {
|
||||
file = FioFOpenFile(filename, "rb", GAME_DIR, &size);
|
||||
if (!file.has_value()) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size);
|
||||
} else {
|
||||
|
||||
+24
-24
@@ -26,14 +26,14 @@ class Squirrel {
|
||||
friend class ScriptInstance;
|
||||
|
||||
private:
|
||||
typedef void (SQPrintFunc)(bool error_msg, const std::string &message);
|
||||
using SQPrintFunc = void (bool error_msg, std::string_view message);
|
||||
|
||||
HSQUIRRELVM vm; ///< The VirtualMachine instance for squirrel
|
||||
void *global_pointer; ///< Can be set by who ever initializes Squirrel
|
||||
SQPrintFunc *print_func; ///< Points to either nullptr, or a custom print handler
|
||||
bool crashed; ///< True if the squirrel script made an error.
|
||||
int overdrawn_ops; ///< The amount of operations we have overdrawn.
|
||||
const char *APIName; ///< Name of the API used for this squirrel.
|
||||
std::string_view api_name; ///< Name of the API used for this squirrel.
|
||||
std::unique_ptr<ScriptAllocator> allocator; ///< Allocator object used by this script.
|
||||
|
||||
/**
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
/**
|
||||
* Get the API name.
|
||||
*/
|
||||
const char *GetAPIName() { return this->APIName; }
|
||||
std::string_view GetAPIName() { return this->api_name; }
|
||||
|
||||
/** Perform all initialization steps to create the engine. */
|
||||
void Initialize();
|
||||
@@ -55,25 +55,25 @@ protected:
|
||||
/**
|
||||
* The CompileError handler.
|
||||
*/
|
||||
static void CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column);
|
||||
static void CompileError(HSQUIRRELVM vm, std::string_view desc, std::string_view source, SQInteger line, SQInteger column);
|
||||
|
||||
/**
|
||||
* The RunError handler.
|
||||
*/
|
||||
static void RunError(HSQUIRRELVM vm, const SQChar *error);
|
||||
static void RunError(HSQUIRRELVM vm, std::string_view error);
|
||||
|
||||
/**
|
||||
* If a user runs 'print' inside a script, this function gets the params.
|
||||
*/
|
||||
static void PrintFunc(HSQUIRRELVM vm, const std::string &s);
|
||||
static void PrintFunc(HSQUIRRELVM vm, std::string_view s);
|
||||
|
||||
/**
|
||||
* If an error has to be print, this function is called.
|
||||
*/
|
||||
static void ErrorPrintFunc(HSQUIRRELVM vm, const std::string &s);
|
||||
static void ErrorPrintFunc(HSQUIRRELVM vm, std::string_view s);
|
||||
|
||||
public:
|
||||
Squirrel(const char *APIName);
|
||||
Squirrel(std::string_view api_name);
|
||||
~Squirrel();
|
||||
|
||||
/**
|
||||
@@ -98,39 +98,39 @@ public:
|
||||
* Adds a function to the stack. Depending on the current state this means
|
||||
* either a method or a global function.
|
||||
*/
|
||||
void AddMethod(const char *method_name, SQFUNCTION proc, uint nparam = 0, const char *params = nullptr, void *userdata = nullptr, int size = 0);
|
||||
void AddMethod(std::string_view method_name, SQFUNCTION proc, std::string_view params = {}, void *userdata = nullptr, int size = 0);
|
||||
|
||||
/**
|
||||
* Adds a const to the stack. Depending on the current state this means
|
||||
* either a const to a class or to the global space.
|
||||
*/
|
||||
void AddConst(const char *var_name, int value);
|
||||
void AddConst(std::string_view var_name, int value);
|
||||
|
||||
/**
|
||||
* Adds a const to the stack. Depending on the current state this means
|
||||
* either a const to a class or to the global space.
|
||||
*/
|
||||
void AddConst(const char *var_name, uint value) { this->AddConst(var_name, (int)value); }
|
||||
void AddConst(std::string_view var_name, uint value) { this->AddConst(var_name, (int)value); }
|
||||
|
||||
void AddConst(const char *var_name, const ConvertibleThroughBase auto &value) { this->AddConst(var_name, static_cast<int>(value.base())); }
|
||||
void AddConst(std::string_view var_name, const ConvertibleThroughBase auto &value) { this->AddConst(var_name, static_cast<int>(value.base())); }
|
||||
|
||||
/**
|
||||
* Adds a const to the stack. Depending on the current state this means
|
||||
* either a const to a class or to the global space.
|
||||
*/
|
||||
void AddConst(const char *var_name, bool value);
|
||||
void AddConst(std::string_view var_name, bool value);
|
||||
|
||||
/**
|
||||
* Adds a class to the global scope. Make sure to call AddClassEnd when you
|
||||
* are done adding methods.
|
||||
*/
|
||||
void AddClassBegin(const char *class_name);
|
||||
void AddClassBegin(std::string_view class_name);
|
||||
|
||||
/**
|
||||
* Adds a class to the global scope, extending 'parent_class'.
|
||||
* Make sure to call AddClassEnd when you are done adding methods.
|
||||
*/
|
||||
void AddClassBegin(const char *class_name, const char *parent_class);
|
||||
void AddClassBegin(std::string_view class_name, std::string_view parent_class);
|
||||
|
||||
/**
|
||||
* Finishes adding a class to the global scope. If this isn't called, no
|
||||
@@ -162,16 +162,16 @@ public:
|
||||
* Call a method of an instance, in various flavors.
|
||||
* @return False if the script crashed or returned a wrong type.
|
||||
*/
|
||||
bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend);
|
||||
bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, nullptr, suspend); }
|
||||
bool CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend);
|
||||
bool CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend);
|
||||
bool CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend);
|
||||
bool CallMethod(HSQOBJECT instance, std::string_view method_name, HSQOBJECT *ret, int suspend);
|
||||
bool CallMethod(HSQOBJECT instance, std::string_view method_name, int suspend) { return this->CallMethod(instance, method_name, nullptr, suspend); }
|
||||
bool CallStringMethod(HSQOBJECT instance, std::string_view method_name, std::string *res, int suspend);
|
||||
bool CallIntegerMethod(HSQOBJECT instance, std::string_view method_name, int *res, int suspend);
|
||||
bool CallBoolMethod(HSQOBJECT instance, std::string_view method_name, bool *res, int suspend);
|
||||
|
||||
/**
|
||||
* Check if a method exists in an instance.
|
||||
*/
|
||||
bool MethodExists(HSQOBJECT instance, const char *method_name);
|
||||
bool MethodExists(HSQOBJECT instance, std::string_view method_name);
|
||||
|
||||
/**
|
||||
* Creates a class instance.
|
||||
@@ -195,7 +195,7 @@ public:
|
||||
* @note This will only work just after a function-call from within Squirrel
|
||||
* to your C++ function.
|
||||
*/
|
||||
static SQUserPointer GetRealInstance(HSQUIRRELVM vm, int index, const char *tag);
|
||||
static SQUserPointer GetRealInstance(HSQUIRRELVM vm, int index, std::string_view tag);
|
||||
|
||||
/**
|
||||
* Get the Squirrel-instance pointer.
|
||||
@@ -207,7 +207,7 @@ public:
|
||||
/**
|
||||
* Convert a Squirrel-object to a string.
|
||||
*/
|
||||
static const char *ObjectToString(HSQOBJECT *ptr) { return sq_objtostring(ptr); }
|
||||
static std::optional<std::string_view> ObjectToString(HSQOBJECT *ptr) { return sq_objtostring(ptr); }
|
||||
|
||||
/**
|
||||
* Convert a Squirrel-object to an integer.
|
||||
@@ -238,7 +238,7 @@ public:
|
||||
/**
|
||||
* Throw a Squirrel error that will be nicely displayed to the user.
|
||||
*/
|
||||
void ThrowError(const std::string_view error) { sq_throwerror(this->vm, error); }
|
||||
void ThrowError(std::string_view error) { sq_throwerror(this->vm, error); }
|
||||
|
||||
/**
|
||||
* Release a SQ object.
|
||||
|
||||
@@ -19,111 +19,91 @@
|
||||
template <class CL, ScriptType ST>
|
||||
class DefSQClass {
|
||||
private:
|
||||
const char *classname;
|
||||
std::string_view classname;
|
||||
|
||||
public:
|
||||
DefSQClass(const char *_classname) :
|
||||
DefSQClass(std::string_view _classname) :
|
||||
classname(_classname)
|
||||
{}
|
||||
|
||||
/**
|
||||
* This defines a method inside a class for Squirrel.
|
||||
* This defines a method inside a class for Squirrel with defined params.
|
||||
* @note If you define params, 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!
|
||||
*/
|
||||
template <typename Func>
|
||||
void DefSQMethod(Squirrel *engine, Func function_proc, const char *function_name)
|
||||
void DefSQMethod(Squirrel &engine, Func function_proc, std::string_view function_name, std::string_view params = {})
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod(function_name, DefSQNonStaticCallback<CL, Func, ST>, 0, nullptr, &function_proc, sizeof(function_proc));
|
||||
engine.AddMethod(function_name, DefSQNonStaticCallback<CL, Func, ST>, params, &function_proc, sizeof(function_proc));
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines a method inside a class for Squirrel, which has access to the 'engine' (experts only!).
|
||||
*/
|
||||
template <typename Func>
|
||||
void DefSQAdvancedMethod(Squirrel *engine, Func function_proc, const char *function_name)
|
||||
void DefSQAdvancedMethod(Squirrel &engine, Func function_proc, std::string_view function_name)
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod(function_name, DefSQAdvancedNonStaticCallback<CL, Func, ST>, 0, nullptr, &function_proc, sizeof(function_proc));
|
||||
engine.AddMethod(function_name, DefSQAdvancedNonStaticCallback<CL, Func, ST>, {}, &function_proc, sizeof(function_proc));
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines a method inside a class for Squirrel with defined params.
|
||||
* @note If you define nparam, make sure that the first param is always 'x',
|
||||
* This defines a static method inside a class for Squirrel with defined params.
|
||||
* @note If you define params, 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!
|
||||
*/
|
||||
template <typename Func>
|
||||
void DefSQMethod(Squirrel *engine, Func function_proc, const char *function_name, int nparam, const char *params)
|
||||
void DefSQStaticMethod(Squirrel &engine, Func function_proc, std::string_view function_name, std::string_view params = {})
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod(function_name, DefSQNonStaticCallback<CL, Func, ST>, nparam, params, &function_proc, sizeof(function_proc));
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines a static method inside a class for Squirrel.
|
||||
*/
|
||||
template <typename Func>
|
||||
void DefSQStaticMethod(Squirrel *engine, Func function_proc, const char *function_name)
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod(function_name, DefSQStaticCallback<CL, Func>, 0, nullptr, &function_proc, sizeof(function_proc));
|
||||
engine.AddMethod(function_name, DefSQStaticCallback<CL, Func>, params, &function_proc, sizeof(function_proc));
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines a static method inside a class for Squirrel, which has access to the 'engine' (experts only!).
|
||||
*/
|
||||
template <typename Func>
|
||||
void DefSQAdvancedStaticMethod(Squirrel *engine, Func function_proc, const char *function_name)
|
||||
void DefSQAdvancedStaticMethod(Squirrel &engine, Func function_proc, std::string_view function_name)
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod(function_name, DefSQAdvancedStaticCallback<CL, Func>, 0, nullptr, &function_proc, sizeof(function_proc));
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines a static method inside a class for Squirrel with defined params.
|
||||
* @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!
|
||||
*/
|
||||
template <typename Func>
|
||||
void DefSQStaticMethod(Squirrel *engine, Func function_proc, const char *function_name, int nparam, const char *params)
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod(function_name, DefSQStaticCallback<CL, Func>, nparam, params, &function_proc, sizeof(function_proc));
|
||||
engine.AddMethod(function_name, DefSQAdvancedStaticCallback<CL, Func>, {}, &function_proc, sizeof(function_proc));
|
||||
}
|
||||
|
||||
template <typename Var>
|
||||
void DefSQConst(Squirrel *engine, Var value, const char *var_name)
|
||||
void DefSQConst(Squirrel &engine, Var value, std::string_view var_name)
|
||||
{
|
||||
engine->AddConst(var_name, value);
|
||||
engine.AddConst(var_name, value);
|
||||
}
|
||||
|
||||
void PreRegister(Squirrel *engine)
|
||||
void PreRegister(Squirrel &engine)
|
||||
{
|
||||
engine->AddClassBegin(this->classname);
|
||||
engine.AddClassBegin(this->classname);
|
||||
}
|
||||
|
||||
void PreRegister(Squirrel *engine, const char *parent_class)
|
||||
void PreRegister(Squirrel &engine, std::string_view parent_class)
|
||||
{
|
||||
engine->AddClassBegin(this->classname, parent_class);
|
||||
engine.AddClassBegin(this->classname, parent_class);
|
||||
}
|
||||
|
||||
template <typename Func, int Tnparam>
|
||||
void AddConstructor(Squirrel *engine, const char *params)
|
||||
template <typename Func>
|
||||
void AddConstructor(Squirrel &engine, std::string_view params)
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod("constructor", DefSQConstructorCallback<CL, Func, Tnparam>, Tnparam, params);
|
||||
engine.AddMethod("constructor", DefSQConstructorCallback<CL, Func>, params);
|
||||
}
|
||||
|
||||
void AddSQAdvancedConstructor(Squirrel *engine)
|
||||
void AddSQAdvancedConstructor(Squirrel &engine)
|
||||
{
|
||||
using namespace SQConvert;
|
||||
engine->AddMethod("constructor", DefSQAdvancedConstructorCallback<CL>, 0, nullptr);
|
||||
engine.AddMethod("constructor", DefSQAdvancedConstructorCallback<CL>);
|
||||
}
|
||||
|
||||
void PostRegister(Squirrel *engine)
|
||||
void PostRegister(Squirrel &engine)
|
||||
{
|
||||
engine->AddClassEnd();
|
||||
engine.AddClassEnd();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace SQConvert {
|
||||
static inline int Set(HSQUIRRELVM vm, std::optional<std::string> res)
|
||||
{
|
||||
if (res.has_value()) {
|
||||
sq_pushstring(vm, res.value(), -1);
|
||||
sq_pushstring(vm, res.value());
|
||||
} else {
|
||||
sq_pushnull(vm);
|
||||
}
|
||||
@@ -110,9 +110,9 @@ namespace SQConvert {
|
||||
/* Convert what-ever there is as parameter to a string */
|
||||
sq_tostring(vm, index);
|
||||
|
||||
const SQChar *tmp;
|
||||
sq_getstring(vm, -1, &tmp);
|
||||
std::string result = StrMakeValid(tmp);
|
||||
std::string_view view;
|
||||
sq_getstring(vm, -1, view);
|
||||
std::string result = StrMakeValid(view);
|
||||
sq_poptop(vm);
|
||||
return result;
|
||||
}
|
||||
@@ -187,9 +187,9 @@ namespace SQConvert {
|
||||
return SQCall(instance, func, vm, std::index_sequence_for<Targs...>{});
|
||||
}
|
||||
|
||||
static Tcls *SQConstruct(Tcls *instance, Tretval(Tcls:: *func)(Targs...), HSQUIRRELVM vm)
|
||||
static Tcls *SQConstruct(HSQUIRRELVM vm)
|
||||
{
|
||||
return SQConstruct(instance, func, vm, std::index_sequence_for<Targs...>{});
|
||||
return SQConstruct(vm, std::index_sequence_for<Targs...>{});
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -210,7 +210,7 @@ namespace SQConvert {
|
||||
}
|
||||
|
||||
template <size_t... i>
|
||||
static Tcls *SQConstruct(Tcls *, Tretval(Tcls:: *)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
|
||||
static Tcls *SQConstruct([[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
|
||||
{
|
||||
Tcls *inst = new Tcls(
|
||||
Param<Targs>::Get(vm, 2 + i)...
|
||||
@@ -376,14 +376,17 @@ namespace SQConvert {
|
||||
* params. It creates the instance in C++, and it sets all the needed
|
||||
* settings in SQ to register the instance.
|
||||
*/
|
||||
template <typename Tcls, typename Tmethod, int Tnparam>
|
||||
template <typename Tcls, typename Tmethod>
|
||||
inline SQInteger DefSQConstructorCallback(HSQUIRRELVM vm)
|
||||
{
|
||||
try {
|
||||
/* Find the amount of params we got */
|
||||
int nparam = sq_gettop(vm);
|
||||
|
||||
/* Create the real instance */
|
||||
Tcls *instance = HelperT<Tmethod>::SQConstruct((Tcls *)nullptr, (Tmethod)nullptr, vm);
|
||||
sq_setinstanceup(vm, -Tnparam, instance);
|
||||
sq_setreleasehook(vm, -Tnparam, DefSQDestructorCallback<Tcls>);
|
||||
Tcls *instance = HelperT<Tmethod>::SQConstruct(vm);
|
||||
sq_setinstanceup(vm, -nparam, instance);
|
||||
sq_setreleasehook(vm, -nparam, DefSQDestructorCallback<Tcls>);
|
||||
instance->AddRef();
|
||||
return 0;
|
||||
} catch (SQInteger &e) {
|
||||
|
||||
+10
-14
@@ -41,20 +41,16 @@ SQInteger SquirrelStd::max(HSQUIRRELVM vm)
|
||||
SQInteger SquirrelStd::require(HSQUIRRELVM vm)
|
||||
{
|
||||
SQInteger top = sq_gettop(vm);
|
||||
const SQChar *filename;
|
||||
std::string_view filename;
|
||||
|
||||
sq_getstring(vm, 2, &filename);
|
||||
sq_getstring(vm, 2, filename);
|
||||
|
||||
/* Get the script-name of the current file, so we can work relative from it */
|
||||
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!");
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
/* Keep the dir, remove the rest */
|
||||
std::string path = si.source;
|
||||
std::string path{si.source};
|
||||
auto p = path.find_last_of(PATHSEPCHAR);
|
||||
/* Keep the PATHSEPCHAR there, remove the rest */
|
||||
if (p != std::string::npos) path.erase(p + 1);
|
||||
@@ -86,20 +82,20 @@ SQInteger SquirrelStd::notifyallexceptions(HSQUIRRELVM vm)
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
void squirrel_register_global_std(Squirrel *engine)
|
||||
void squirrel_register_global_std(Squirrel &engine)
|
||||
{
|
||||
/* We don't use squirrel_helper here, as we want to register to the global
|
||||
* scope and not to a class. */
|
||||
engine->AddMethod("require", &SquirrelStd::require, 2, ".s");
|
||||
engine->AddMethod("notifyallexceptions", &SquirrelStd::notifyallexceptions, 2, ".b");
|
||||
engine.AddMethod("require", &SquirrelStd::require, ".s");
|
||||
engine.AddMethod("notifyallexceptions", &SquirrelStd::notifyallexceptions, ".b");
|
||||
}
|
||||
|
||||
void squirrel_register_std(Squirrel *engine)
|
||||
void squirrel_register_std(Squirrel &engine)
|
||||
{
|
||||
/* We don't use squirrel_helper here, as we want to register to the global
|
||||
* scope and not to a class. */
|
||||
engine->AddMethod("min", &SquirrelStd::min, 3, ".ii");
|
||||
engine->AddMethod("max", &SquirrelStd::max, 3, ".ii");
|
||||
engine.AddMethod("min", &SquirrelStd::min, ".ii");
|
||||
engine.AddMethod("max", &SquirrelStd::max, ".ii");
|
||||
|
||||
sqstd_register_mathlib(engine->GetVM());
|
||||
sqstd_register_mathlib(engine.GetVM());
|
||||
}
|
||||
|
||||
@@ -52,12 +52,12 @@ public:
|
||||
/**
|
||||
* Register all standard functions we want to give to a script.
|
||||
*/
|
||||
void squirrel_register_std(Squirrel *engine);
|
||||
void squirrel_register_std(Squirrel &engine);
|
||||
|
||||
/**
|
||||
* Register all standard functions that are available on first startup.
|
||||
* @note this set is very limited, and is only meant to load other scripts and things like that.
|
||||
*/
|
||||
void squirrel_register_global_std(Squirrel *engine);
|
||||
void squirrel_register_global_std(Squirrel &engine);
|
||||
|
||||
#endif /* SQUIRREL_STD_HPP */
|
||||
|
||||
Reference in New Issue
Block a user