Update to 14.0-beta1

This commit is contained in:
dP
2024-02-04 02:18:17 +05:30
parent 79037e2c65
commit 33ef333b57
1325 changed files with 138465 additions and 70987 deletions

View File

@@ -9,6 +9,8 @@ add_files(
script_config.cpp
script_config.hpp
script_fatalerror.hpp
script_gui.h
script_gui.cpp
script_info.cpp
script_info.hpp
script_info_dummy.cpp

View File

@@ -146,10 +146,12 @@ add_files(
script_accounting.hpp
script_admin.hpp
script_airport.hpp
script_asyncmode.hpp
script_base.hpp
script_basestation.hpp
script_bridge.hpp
script_bridgelist.hpp
script_timemode.hpp
script_cargo.hpp
script_cargolist.hpp
script_cargomonitor.hpp
@@ -180,6 +182,7 @@ add_files(
script_league.hpp
script_list.hpp
script_log.hpp
script_log_types.hpp
script_map.hpp
script_marine.hpp
script_newgrf.hpp
@@ -218,10 +221,12 @@ add_files(
script_accounting.cpp
script_admin.cpp
script_airport.cpp
script_asyncmode.cpp
script_base.cpp
script_basestation.cpp
script_bridge.cpp
script_bridgelist.cpp
script_timemode.cpp
script_cargo.cpp
script_cargolist.cpp
script_cargomonitor.cpp

View File

@@ -7,11 +7,11 @@
#include "../script_controller.hpp"
template <> const char *GetClassName<ScriptController, ST_AI>() { return "AIController"; }
template <> const char *GetClassName<ScriptController, ScriptType::AI>() { return "AIController"; }
void SQAIController_Register(Squirrel *engine)
{
DefSQClass<ScriptController, ST_AI> SQAIController("AIController");
DefSQClass<ScriptController, ScriptType::AI> SQAIController("AIController");
SQAIController.PreRegister(engine);
SQAIController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", 1, ".");

View File

@@ -13,6 +13,28 @@
* functions may still be available if you return an older API version
* in GetAPIVersion() in info.nut.
*
* \b 14.0
*
* This version is not yet released. The following changes are not set in stone yet.
*
* API additions:
* \li AITimeMode
* \li AITown::ROAD_LAYOUT_RANDOM
* \li AIVehicle::IsPrimaryVehicle
*
* API removals:
* \li AIError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
* \li AIInfo::CONFIG_RANDOM, no longer used.
*
* Other changes:
* \li AIGroupList accepts an optional filter function
* \li AIIndustryList accepts an optional filter function
* \li AISignList accepts an optional filter function
* \li AISubsidyList accepts an optional filter function
* \li AITownList accepts an optional filter function
* \li AIVehicleList accepts an optional filter function
* \li AIInfo::AddSettings easy_value / medium_value / hard_value are replaced with default_value
*
* \b 13.0
*
* API additions:

View File

@@ -7,11 +7,11 @@
#include "../script_controller.hpp"
template <> const char *GetClassName<ScriptController, ST_GS>() { return "GSController"; }
template <> const char *GetClassName<ScriptController, ScriptType::GS>() { return "GSController"; }
void SQGSController_Register(Squirrel *engine)
{
DefSQClass<ScriptController, ST_GS> SQGSController("GSController");
DefSQClass<ScriptController, ScriptType::GS> SQGSController("GSController");
SQGSController.PreRegister(engine);
SQGSController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", 1, ".");

View File

@@ -13,6 +13,94 @@
* functions may still be available if you return an older API version
* in GetAPIVersion() in info.nut.
*
* \b 14.0
*
* This version is not yet released. The following changes are not set in stone yet.
*
* API additions:
* \li GSIndustry::GetConstructionDate
* \li GSAsyncMode
* \li GSCompanyMode::IsValid
* \li GSCompanyMode::IsDeity
* \li GSTimeMode
* \li GSTown::ROAD_LAYOUT_RANDOM
* \li GSVehicle::IsPrimaryVehicle
* \li GSOrder::SetOrderJumpTo
* \li GSOrder::SetOrderCondition
* \li GSOrder::SetOrderCompareFunction
* \li GSOrder::SetOrderCompareValue
* \li GSOrder::SetStopLocation
* \li GSOrder::SetOrderRefit
* \li GSOrder::AppendOrder
* \li GSOrder::AppendConditionalOrder
* \li GSOrder::InsertOrder
* \li GSOrder::InsertConditionalOrder
* \li GSOrder::RemoveOrder
* \li GSOrder::SetOrderFlags
* \li GSOrder::MoveOrder
* \li GSOrder::SkipToOrder
* \li GSOrder::CopyOrders
* \li GSOrder::ShareOrders
* \li GSOrder::UnshareOrders
* \li GSCompany::IsMine
* \li GSCompany::SetPresidentGender
* \li GSCompany::SetAutoRenewStatus
* \li GSCompany::SetAutoRenewMonths
* \li GSCompany::SetAutoRenewMoney
* \li GSCompany::SetMaxLoanAmountForCompany
* \li GSCompany::ResetMaxLoanAmountForCompany
* \li GSGameSettings::IsDisabledVehicleType
* \li GSGroup::GroupID
* \li GSGroup::IsValidGroup
* \li GSGroup::CreateGroup
* \li GSGroup::DeleteGroup
* \li GSGroup::GetVehicleType
* \li GSGroup::SetName
* \li GSGroup::GetName
* \li GSGroup::SetParent
* \li GSGroup::GetParent
* \li GSGroup::EnableAutoReplaceProtection
* \li GSGroup::GetAutoReplaceProtection
* \li GSGroup::GetNumEngines
* \li GSGroup::GetNumVehicles
* \li GSGroup::MoveVehicle
* \li GSGroup::EnableWagonRemoval
* \li GSGroup::HasWagonRemoval
* \li GSGroup::SetAutoReplace
* \li GSGroup::GetEngineReplacement
* \li GSGroup::StopAutoReplace
* \li GSGroup::GetProfitThisYear
* \li GSGroup::GetProfitLastYear
* \li GSGroup::GetCurrentUsage
* \li GSGroup::SetPrimaryColour
* \li GSGroup::SetSecondaryColour
* \li GSGroup::GetPrimaryColour
* \li GSGroup::GetSecondaryColour
* \li GSGroupList
* \li GSVehicleList_Group
* \li GSVehicleList_DefaultGroup
* \li GSGoal::IsValidGoalDestination
* \li GSGoal::SetDestination
* \li GSIndustry::GetProductionLevel
* \li GSIndustry::SetProductionLevel
* \li GSStoryPage::IsValidStoryPageElementType
* \li GSStoryPage::IsValidStoryPageButtonColour
* \li GSStoryPage::IsValidStoryPageButtonFlags
* \li GSStoryPage::IsValidStoryPageButtonCursor
*
* API removals:
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
* \li AIInfo::CONFIG_RANDOM, no longer used.
*
* Other changes:
* \li GSGroupList accepts an optional filter function
* \li GSIndustryList accepts an optional filter function
* \li GSSignList accepts an optional filter function
* \li GSSubsidyList accepts an optional filter function
* \li GSTownList accepts an optional filter function
* \li GSVehicleList accepts an optional filter function
* \li GSInfo::AddSettings easy_value / medium_value / hard_value are replaced with default_value
*
* \b 13.0
*
* API additions:

View File

@@ -13,12 +13,24 @@
#include "../../network/network_admin.h"
#include "../script_instance.hpp"
#include "../../string_func.h"
#include "../../3rdparty/nlohmann/json.hpp"
#include "../../safeguards.h"
/* static */ bool ScriptAdmin::MakeJSON(HSQUIRRELVM vm, SQInteger index, int max_depth, std::string &data)
/**
* Convert a Squirrel structure into a JSON object.
*
* This function is not "static", so it can be tested in unittests.
*
* @param json The resulting JSON object.
* @param vm The VM to operate on.
* @param index The index we are currently working for.
* @param depth The current depth in the squirrel struct.
* @return True iff the conversion was successful.
*/
bool ScriptAdminMakeJSON(nlohmann::json &json, HSQUIRRELVM vm, SQInteger index, int depth = 0)
{
if (max_depth == 0) {
if (depth == SQUIRREL_MAX_DEPTH) {
ScriptLog::Error("Send parameters can only be nested to 25 deep. No data sent."); // SQUIRREL_MAX_DEPTH = 25
return false;
}
@@ -28,9 +40,7 @@
SQInteger res;
sq_getinteger(vm, index, &res);
char buf[10];
seprintf(buf, lastof(buf), "%d", (int32)res);
data = buf;
json = res;
return true;
}
@@ -38,63 +48,52 @@
const SQChar *buf;
sq_getstring(vm, index, &buf);
size_t len = strlen(buf) + 1;
if (len >= 255) {
ScriptLog::Error("Maximum string length is 254 chars. No data sent.");
return false;
}
data = std::string("\"") + buf + "\"";
json = std::string(buf);
return true;
}
case OT_ARRAY: {
data = "[ ";
json = nlohmann::json::array();
bool first = true;
sq_pushnull(vm);
while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
if (!first) data += ", ";
if (first) first = false;
nlohmann::json tmp;
std::string tmp;
bool res = MakeJSON(vm, -1, max_depth - 1, tmp);
bool res = ScriptAdminMakeJSON(tmp, vm, -1, depth + 1);
sq_pop(vm, 2);
if (!res) {
sq_pop(vm, 1);
return false;
}
data += tmp;
json.push_back(tmp);
}
sq_pop(vm, 1);
data += " ]";
return true;
}
case OT_TABLE: {
data = "{ ";
json = nlohmann::json::object();
bool first = true;
sq_pushnull(vm);
while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
if (!first) data += ", ";
if (first) first = false;
/* Squirrel ensure the key is a string. */
assert(sq_gettype(vm, -2) == OT_STRING);
const SQChar *buf;
sq_getstring(vm, -2, &buf);
std::string key = std::string(buf);
std::string key;
std::string value;
/* Store the key + value */
bool res = MakeJSON(vm, -2, max_depth - 1, key) && MakeJSON(vm, -1, max_depth - 1, value);
nlohmann::json value;
bool res = ScriptAdminMakeJSON(value, vm, -1, depth + 1);
sq_pop(vm, 2);
if (!res) {
sq_pop(vm, 1);
return false;
}
data += key + ": " + value;
json[key] = value;
}
sq_pop(vm, 1);
data += " }";
return true;
}
@@ -102,17 +101,12 @@
SQBool res;
sq_getbool(vm, index, &res);
if (res) {
data = "true";
return true;
}
data = "false";
json = res ? true : false;
return true;
}
case OT_NULL: {
data = "null";
json = nullptr;
return true;
}
@@ -130,16 +124,13 @@
return sq_throwerror(vm, "ScriptAdmin::Send requires a table as first parameter. No data sent.");
}
std::string json;
ScriptAdmin::MakeJSON(vm, -1, SQUIRREL_MAX_DEPTH, json);
if (json.length() > NETWORK_GAMESCRIPT_JSON_LENGTH) {
ScriptLog::Error("You are trying to send a table that is too large to the AdminPort. No data sent.");
nlohmann::json json;
if (!ScriptAdminMakeJSON(json, vm, -1)) {
sq_pushinteger(vm, 0);
return 1;
}
NetworkAdminGameScript(json);
NetworkAdminGameScript(json.dump());
sq_pushinteger(vm, 1);
return 1;

View File

@@ -10,7 +10,6 @@
#ifndef SCRIPT_ADMIN_HPP
#define SCRIPT_ADMIN_HPP
#include <string>
#include "script_object.hpp"
/**
@@ -36,16 +35,6 @@ public:
*/
static bool Send(void *table);
#endif /* DOXYGEN_API */
private:
/**
* Convert a Squirrel structure into a JSON string.
* @param vm The VM to operate on.
* @param index The index we are currently working for.
* @param max_depth The maximal depth to follow the squirrel struct.
* @param data The resulting json string.
*/
static bool MakeJSON(HSQUIRRELVM vm, SQInteger index, int max_depth, std::string &data);
};
#endif /* SCRIPT_ADMIN_HPP */

View File

@@ -49,21 +49,21 @@
return ::IsTileType(tile, MP_STATION) && ::IsAirport(tile);
}
/* static */ int32 ScriptAirport::GetAirportWidth(AirportType type)
/* static */ SQInteger ScriptAirport::GetAirportWidth(AirportType type)
{
if (!IsAirportInformationAvailable(type)) return -1;
return ::AirportSpec::Get(type)->size_x;
}
/* static */ int32 ScriptAirport::GetAirportHeight(AirportType type)
/* static */ SQInteger ScriptAirport::GetAirportHeight(AirportType type)
{
if (!IsAirportInformationAvailable(type)) return -1;
return ::AirportSpec::Get(type)->size_y;
}
/* static */ int32 ScriptAirport::GetAirportCoverageRadius(AirportType type)
/* static */ SQInteger ScriptAirport::GetAirportCoverageRadius(AirportType type)
{
if (!IsAirportInformationAvailable(type)) return -1;
@@ -72,7 +72,7 @@
/* static */ bool ScriptAirport::BuildAirport(TileIndex tile, AirportType type, StationID station_id)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsValidAirportType(type));
EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
@@ -82,20 +82,21 @@
/* static */ bool ScriptAirport::RemoveAirport(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile))
EnforcePrecondition(false, IsAirportTile(tile) || IsHangarTile(tile));
return ScriptObject::Command<CMD_LANDSCAPE_CLEAR>::Do(tile);
}
/* static */ int32 ScriptAirport::GetNumHangars(TileIndex tile)
/* static */ SQInteger ScriptAirport::GetNumHangars(TileIndex tile)
{
EnforceDeityOrCompanyModeValid(-1);
if (!::IsValidTile(tile)) return -1;
if (!::IsTileType(tile, MP_STATION)) return -1;
const Station *st = ::Station::GetByTile(tile);
if (st->owner != ScriptObject::GetCompany() && ScriptObject::GetCompany() != OWNER_DEITY) return -1;
if (st->owner != ScriptObject::GetCompany() && ScriptCompanyMode::IsValid()) return -1;
if ((st->facilities & FACIL_AIRPORT) == 0) return -1;
return st->airport.GetNumHangars();
@@ -103,12 +104,13 @@
/* static */ TileIndex ScriptAirport::GetHangarOfAirport(TileIndex tile)
{
EnforceDeityOrCompanyModeValid(INVALID_TILE);
if (!::IsValidTile(tile)) return INVALID_TILE;
if (!::IsTileType(tile, MP_STATION)) return INVALID_TILE;
if (GetNumHangars(tile) < 1) return INVALID_TILE;
const Station *st = ::Station::GetByTile(tile);
if (st->owner != ScriptObject::GetCompany() && ScriptObject::GetCompany() != OWNER_DEITY) return INVALID_TILE;
if (st->owner != ScriptObject::GetCompany() && ScriptCompanyMode::IsValid()) return INVALID_TILE;
if ((st->facilities & FACIL_AIRPORT) == 0) return INVALID_TILE;
return st->airport.GetHangarTile(0);
@@ -126,11 +128,8 @@
}
/* static */ int ScriptAirport::GetNoiseLevelIncrease(TileIndex tile, AirportType type)
/* static */ SQInteger ScriptAirport::GetNoiseLevelIncrease(TileIndex tile, AirportType type)
{
extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist);
extern uint8 GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance);
if (!::IsValidTile(tile)) return -1;
if (!IsAirportInformationAvailable(type)) return -1;
@@ -138,9 +137,8 @@
if (!as->IsWithinMapBounds(0, tile)) return -1;
if (_settings_game.economy.station_noise_level) {
AirportTileTableIterator it(as->table[0], tile);
uint dist;
AirportGetNearestTown(as, it, dist);
AirportGetNearestTown(as, as->rotation[0], tile, AirportTileTableIterator(as->table[0], tile), dist);
return GetAirportNoiseLevelForDistance(as, dist);
}
@@ -149,8 +147,6 @@
/* static */ TownID ScriptAirport::GetNearestTown(TileIndex tile, AirportType type)
{
extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist);
if (!::IsValidTile(tile)) return INVALID_TOWN;
if (!IsAirportInformationAvailable(type)) return INVALID_TOWN;
@@ -158,12 +154,12 @@
if (!as->IsWithinMapBounds(0, tile)) return INVALID_TOWN;
uint dist;
return AirportGetNearestTown(as, AirportTileTableIterator(as->table[0], tile), dist)->index;
return AirportGetNearestTown(as, as->rotation[0], tile, AirportTileTableIterator(as->table[0], tile), dist)->index;
}
/* static */ uint16 ScriptAirport::GetMaintenanceCostFactor(AirportType type)
/* static */ SQInteger ScriptAirport::GetMaintenanceCostFactor(AirportType type)
{
if (!IsAirportInformationAvailable(type)) return INVALID_TOWN;
if (!IsAirportInformationAvailable(type)) return 0;
return AirportSpec::Get(type)->maintenance_cost;
}
@@ -172,5 +168,5 @@
{
if (!IsAirportInformationAvailable(type)) return -1;
return (int64)GetMaintenanceCostFactor(type) * _price[PR_INFRASTRUCTURE_AIRPORT] >> 3;
return (int64_t)GetMaintenanceCostFactor(type) * _price[PR_INFRASTRUCTURE_AIRPORT] >> 3;
}

View File

@@ -96,7 +96,7 @@ public:
* @pre IsAirportInformationAvailable(type).
* @return The width in tiles.
*/
static int32 GetAirportWidth(AirportType type);
static SQInteger GetAirportWidth(AirportType type);
/**
* Get the height of this type of airport.
@@ -104,7 +104,7 @@ public:
* @pre IsAirportInformationAvailable(type).
* @return The height in tiles.
*/
static int32 GetAirportHeight(AirportType type);
static SQInteger GetAirportHeight(AirportType type);
/**
* Get the coverage radius of this type of airport.
@@ -112,7 +112,7 @@ public:
* @pre IsAirportInformationAvailable(type).
* @return The radius in tiles.
*/
static int32 GetAirportCoverageRadius(AirportType type);
static SQInteger GetAirportCoverageRadius(AirportType type);
/**
* Get the number of hangars of the airport.
@@ -120,7 +120,7 @@ public:
* @pre ScriptMap::IsValidTile(tile).
* @return The number of hangars of the airport.
*/
static int32 GetNumHangars(TileIndex tile);
static SQInteger GetNumHangars(TileIndex tile);
/**
* Get the first hangar tile of the airport.
@@ -142,7 +142,7 @@ public:
* @pre ScriptMap::IsValidTile(tile).
* @pre AirportAvailable(type).
* @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
* @exception ScriptError::ERR_LOCAL_AUTHORITY_REFUSES
@@ -156,7 +156,7 @@ public:
* Removes an airport.
* @param tile Any tile of the airport.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the airport has been/can be removed or not.
*/
@@ -180,7 +180,7 @@ public:
* @return The amount of noise added to the nearest town.
* @note The noise will be added to the town with TownID GetNearestTown(tile, type).
*/
static int GetNoiseLevelIncrease(TileIndex tile, AirportType type);
static SQInteger GetNoiseLevelIncrease(TileIndex tile, AirportType type);
/**
* Get the TownID of the town whose local authority will influence
@@ -198,7 +198,7 @@ public:
* @pre IsAirportInformationAvailable(type)
* @return Maintenance cost factor of the airport type.
*/
static uint16 GetMaintenanceCostFactor(AirportType type);
static SQInteger GetMaintenanceCostFactor(AirportType type);
/**
* Get the monthly maintenance cost of an airport type.

View File

@@ -0,0 +1,61 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file script_asyncmode.cpp Implementation of ScriptAsyncMode. */
#include "../../stdafx.h"
#include "script_asyncmode.hpp"
#include "../script_instance.hpp"
#include "../script_fatalerror.hpp"
#include "../../safeguards.h"
bool ScriptAsyncMode::AsyncModeProc()
{
/* In async mode we only return 'true', telling the DoCommand it
* should stop run the command in asynchronous/fire-and-forget mode. */
return true;
}
bool ScriptAsyncMode::NonAsyncModeProc()
{
/* In non-async mode we only return 'false', normal operation. */
return false;
}
ScriptAsyncMode::ScriptAsyncMode(HSQUIRRELVM vm)
{
int nparam = sq_gettop(vm) - 1;
if (nparam < 1) {
throw sq_throwerror(vm, "You need to pass a boolean to the constructor");
}
SQBool sqasync;
if (SQ_FAILED(sq_getbool(vm, 2, &sqasync))) {
throw sq_throwerror(vm, "Argument must be a boolean");
}
this->last_mode = this->GetDoCommandAsyncMode();
this->last_instance = this->GetDoCommandAsyncModeInstance();
this->SetDoCommandAsyncMode(sqasync ? &ScriptAsyncMode::AsyncModeProc : &ScriptAsyncMode::NonAsyncModeProc, this);
}
void ScriptAsyncMode::FinalRelease()
{
if (this->GetDoCommandAsyncModeInstance() != this) {
/* Ignore this error if the script is not alive. */
if (ScriptObject::GetActiveInstance()->IsAlive()) {
throw Script_FatalError("Asyncmode object was removed while it was not the latest *Mode object created.");
}
}
}
ScriptAsyncMode::~ScriptAsyncMode()
{
this->SetDoCommandAsyncMode(this->last_mode, this->last_instance);
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file script_asyncmode.hpp Switch the script instance to Async Mode. */
#ifndef SCRIPT_ASYNCMODE_HPP
#define SCRIPT_ASYNCMODE_HPP
#include "script_object.hpp"
/**
* Class to switch current mode to Async Mode.
* If you create an instance of this class, the mode will be switched to
* either Asynchronous or Non-Asynchronous mode.
* The original mode is stored and recovered from when ever the instance is destroyed.
* In Asynchronous mode all the commands you execute are queued for later execution. The
* system checks if it would be able to execute your requests, and returns what
* the cost would be. The actual cost and whether the command succeeded when the command
* is eventually executed may differ from what was reported to the script.
* @api game
*/
class ScriptAsyncMode : public ScriptObject {
private:
ScriptAsyncModeProc *last_mode; ///< The previous mode we were in.
ScriptObject *last_instance; ///< The previous instance of the mode.
protected:
static bool AsyncModeProc();
static bool NonAsyncModeProc();
public:
#ifndef DOXYGEN_API
/**
* The constructor wrapper from Squirrel.
*/
ScriptAsyncMode(HSQUIRRELVM vm);
#else
/**
* Creating instance of this class switches the build mode to Asynchronous or Non-Asynchronous (normal).
* @note When the instance is destroyed, it restores the mode that was
* current when the instance was created!
* @param asynchronous Whether the new mode should be Asynchronous, if true, or Non-Asynchronous, if false.
*/
ScriptAsyncMode(bool asynchronous);
#endif /* DOXYGEN_API */
/**
* Destroying this instance resets the asynchronous mode to the mode it was
* in when the instance was created.
*/
~ScriptAsyncMode();
/**
* @api -all
*/
void FinalRelease() override;
};
#endif /* SCRIPT_ASYNCMODE_HPP */

View File

@@ -10,44 +10,39 @@
#include "../../stdafx.h"
#include "script_base.hpp"
#include "script_error.hpp"
#include "../../network/network.h"
#include "../../core/random_func.hpp"
#include "../../safeguards.h"
/* static */ uint32 ScriptBase::Rand()
/* static */ SQInteger ScriptBase::Rand()
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandom();
return ::Random();
return ScriptObject::GetRandomizer().Next();
}
/* static */ uint32 ScriptBase::RandItem(int unused_param)
/* static */ SQInteger ScriptBase::RandItem(SQInteger)
{
return ScriptBase::Rand();
}
/* static */ uint ScriptBase::RandRange(uint max)
/* static */ SQInteger ScriptBase::RandRange(SQInteger max)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandomRange(max);
return ::RandomRange(max);
max = Clamp<SQInteger>(max, 0, UINT32_MAX);
return ScriptObject::GetRandomizer().Next(max);
}
/* static */ uint32 ScriptBase::RandRangeItem(int unused_param, uint max)
/* static */ SQInteger ScriptBase::RandRangeItem(SQInteger, SQInteger max)
{
return ScriptBase::RandRange(max);
}
/* static */ bool ScriptBase::Chance(uint out, uint max)
/* static */ bool ScriptBase::Chance(SQInteger out, SQInteger max)
{
out = Clamp<SQInteger>(out, 0, UINT32_MAX);
max = Clamp<SQInteger>(max, 0, UINT32_MAX);
EnforcePrecondition(false, out <= max);
return ScriptBase::RandRange(max) < out;
}
/* static */ bool ScriptBase::ChanceItem(int unused_param, uint out, uint max)
/* static */ bool ScriptBase::ChanceItem(SQInteger, SQInteger out, SQInteger max)
{
return ScriptBase::Chance(out, max);
}

View File

@@ -18,60 +18,63 @@
*
* @note The random functions are not called Random and RandomRange, because
* RANDOM_DEBUG does some tricky stuff, which messes with those names.
* @note In MP we cannot use Random because that will cause desyncs (scripts are
* ran on the server only, not on all clients). This means that
* we use InteractiveRandom in MP. Rand() takes care of this for you.
*/
class ScriptBase : public ScriptObject {
public:
/**
* Get a random value.
* @return A random value between 0 and MAX(uint32).
* @return A random value between 0 and MAX(uint32_t).
*/
static uint32 Rand();
static SQInteger Rand();
/**
* Get a random value.
* @param unused_param This parameter is not used, but is needed to work with lists.
* @return A random value between 0 and MAX(uint32).
* @return A random value between 0 and MAX(uint32_t).
*/
static uint32 RandItem(int unused_param);
static SQInteger RandItem(SQInteger unused_param);
/**
* Get a random value in a range.
* @param max The first number this function will never return (the maximum it returns is max - 1).
* The value will be clamped to 0 .. MAX(uint32_t).
* @return A random value between 0 .. max - 1.
*/
static uint RandRange(uint max);
static SQInteger RandRange(SQInteger max);
/**
* Get a random value in a range.
* @param unused_param This parameter is not used, but is needed to work with lists.
* @param max The first number this function will never return (the maximum it returns is max - 1).
* The value will be clamped to 0 .. MAX(uint32_t).
* @return A random value between 0 .. max - 1.
*/
static uint RandRangeItem(int unused_param, uint max);
static SQInteger RandRangeItem(SQInteger unused_param, SQInteger max);
/**
* Returns approximately 'out' times true when called 'max' times.
* After all, it is a random function.
* @param out How many times it should return true.
* The value will be clamped to 0 .. MAX(uint32_t).
* @param max Out of this many times.
* The value will be clamped to 0 .. MAX(uint32_t).
* @pre \a out is at most equal to \a max.
* @return True if the chance worked out.
*/
static bool Chance(uint out, uint max);
static bool Chance(SQInteger out, SQInteger max);
/**
* Returns approximately 'out' times true when called 'max' times.
* After all, it is a random function.
* @param unused_param This parameter is not used, but is needed to work with lists.
* @param out How many times it should return true.
* The value will be clamped to 0 .. MAX(uint32_t).
* @param max Out of this many times.
* The value will be clamped to 0 .. MAX(uint32_t).
* @pre \a out is at most equal to \a max.
* @return True if the chance worked out.
*/
static bool ChanceItem(int unused_param, uint out, uint max);
static bool ChanceItem(SQInteger unused_param, SQInteger out, SQInteger max);
};
#endif /* SCRIPT_BASE_HPP */

View File

@@ -15,19 +15,21 @@
#include "../../strings_func.h"
#include "../../station_cmd.h"
#include "../../waypoint_cmd.h"
#include "../../timer/timer_game_calendar.h"
#include "table/strings.h"
#include "../../safeguards.h"
/* static */ bool ScriptBaseStation::IsValidBaseStation(StationID station_id)
{
EnforceDeityOrCompanyModeValid(false);
const BaseStation *st = ::BaseStation::GetIfValid(station_id);
return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE);
return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity() || st->owner == OWNER_NONE);
}
/* static */ char *ScriptBaseStation::GetName(StationID station_id)
/* static */ std::optional<std::string> ScriptBaseStation::GetName(StationID station_id)
{
if (!IsValidBaseStation(station_id)) return nullptr;
if (!IsValidBaseStation(station_id)) return std::nullopt;
::SetDParam(0, station_id);
return GetString(::Station::IsValidID(station_id) ? STR_STATION_NAME : STR_WAYPOINT_NAME);
@@ -37,10 +39,10 @@
{
CCountedPtr<Text> counter(name);
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidBaseStation(station_id));
EnforcePrecondition(false, name != nullptr);
const char *text = name->GetDecodedText();
const std::string &text = name->GetDecodedText();
EnforcePreconditionEncodedText(false, text);
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_STATION_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
@@ -62,5 +64,5 @@
{
if (!IsValidBaseStation(station_id)) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)::BaseStation::Get(station_id)->build_date;
return (ScriptDate::Date)::BaseStation::Get(station_id)->build_date.base();
}

View File

@@ -43,7 +43,7 @@ public:
* @pre IsValidBaseStation(station_id).
* @return The name of the station.
*/
static char *GetName(StationID station_id);
static std::optional<std::string> GetName(StationID station_id);
/**
* Set the name this basestation.
@@ -51,7 +51,7 @@ public:
* @param name The new name of the station (can be either a raw string, or a ScriptText object).
* @pre IsValidBaseStation(station_id).
* @pre name != null && len(name) != 0.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE
* @return True if the name was changed.
*/

View File

@@ -13,17 +13,17 @@
#include "../script_instance.hpp"
#include "../../bridge_map.h"
#include "../../strings_func.h"
#include "../../date_func.h"
#include "../../landscape_cmd.h"
#include "../../road_cmd.h"
#include "../../tunnelbridge_cmd.h"
#include "../../timer/timer_game_calendar.h"
#include "table/strings.h"
#include "../../safeguards.h"
/* static */ bool ScriptBridge::IsValidBridge(BridgeID bridge_id)
{
return bridge_id < MAX_BRIDGES && ::GetBridgeSpec(bridge_id)->avail_year <= _cur_year;
return bridge_id < MAX_BRIDGES && ::GetBridgeSpec(bridge_id)->avail_year <= TimerGameCalendar::year;
}
/* static */ bool ScriptBridge::IsBridgeTile(TileIndex tile)
@@ -72,18 +72,19 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance)
/* static */ bool ScriptBridge::BuildBridge(ScriptVehicle::VehicleType vehicle_type, BridgeID bridge_id, TileIndex start, TileIndex end)
{
EnforceDeityOrCompanyModeValid(false);
EnforcePrecondition(false, start != end);
EnforcePrecondition(false, ::IsValidTile(start) && ::IsValidTile(end));
EnforcePrecondition(false, TileX(start) == TileX(end) || TileY(start) == TileY(end));
EnforcePrecondition(false, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER);
EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_RAIL || ScriptRail::IsRailTypeAvailable(ScriptRail::GetCurrentRailType()));
EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_ROAD || ScriptRoad::IsRoadTypeAvailable(ScriptRoad::GetCurrentRoadType()));
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY || vehicle_type == ScriptVehicle::VT_ROAD);
EnforcePrecondition(false, ScriptCompanyMode::IsValid() || vehicle_type == ScriptVehicle::VT_ROAD);
switch (vehicle_type) {
case ScriptVehicle::VT_ROAD:
ScriptObject::SetCallbackVariable(0, start);
ScriptObject::SetCallbackVariable(1, end);
ScriptObject::SetCallbackVariable(0, start.base());
ScriptObject::SetCallbackVariable(1, end.base());
return ScriptObject::Command<CMD_BUILD_BRIDGE>::Do(&::_DoCommandReturnBuildBridge1, end, start, TRANSPORT_ROAD, bridge_id, ScriptRoad::GetCurrentRoadType());
case ScriptVehicle::VT_RAIL:
return ScriptObject::Command<CMD_BUILD_BRIDGE>::Do(end, start, TRANSPORT_RAIL, bridge_id, ScriptRail::GetCurrentRailType());
@@ -95,6 +96,8 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance)
/* static */ bool ScriptBridge::_BuildBridgeRoad1()
{
EnforceDeityOrCompanyModeValid(false);
/* Build the piece of road on the 'start' side of the bridge */
TileIndex end = ScriptObject::GetCallbackVariable(0);
TileIndex start = ScriptObject::GetCallbackVariable(1);
@@ -107,6 +110,8 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance)
/* static */ bool ScriptBridge::_BuildBridgeRoad2()
{
EnforceDeityOrCompanyModeValid(false);
/* Build the piece of road on the 'end' side of the bridge */
TileIndex end = ScriptObject::GetCallbackVariable(0);
TileIndex start = ScriptObject::GetCallbackVariable(1);
@@ -119,45 +124,47 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance)
/* static */ bool ScriptBridge::RemoveBridge(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsBridgeTile(tile));
return ScriptObject::Command<CMD_LANDSCAPE_CLEAR>::Do(tile);
}
/* static */ char *ScriptBridge::GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type)
/* static */ std::optional<std::string> ScriptBridge::GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type)
{
EnforcePrecondition(nullptr, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER);
if (!IsValidBridge(bridge_id)) return nullptr;
EnforcePrecondition(std::nullopt, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER);
if (!IsValidBridge(bridge_id)) return std::nullopt;
return GetString(vehicle_type == ScriptVehicle::VT_WATER ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : ::GetBridgeSpec(bridge_id)->transport_name[vehicle_type]);
}
/* static */ int32 ScriptBridge::GetMaxSpeed(BridgeID bridge_id)
/* static */ SQInteger ScriptBridge::GetMaxSpeed(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return -1;
return ::GetBridgeSpec(bridge_id)->speed; // km-ish/h
}
/* static */ Money ScriptBridge::GetPrice(BridgeID bridge_id, uint length)
/* static */ Money ScriptBridge::GetPrice(BridgeID bridge_id, SQInteger length)
{
if (!IsValidBridge(bridge_id)) return -1;
length = Clamp<SQInteger>(length, 0, INT32_MAX);
return ::CalcBridgeLenCostFactor(length) * _price[PR_BUILD_BRIDGE] * ::GetBridgeSpec(bridge_id)->price >> 8;
}
/* static */ int32 ScriptBridge::GetMaxLength(BridgeID bridge_id)
/* static */ SQInteger ScriptBridge::GetMaxLength(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return -1;
return std::min(::GetBridgeSpec(bridge_id)->max_length, _settings_game.construction.max_bridge_length) + 2;
return std::min<SQInteger>(::GetBridgeSpec(bridge_id)->max_length, _settings_game.construction.max_bridge_length) + 2;
}
/* static */ int32 ScriptBridge::GetMinLength(BridgeID bridge_id)
/* static */ SQInteger ScriptBridge::GetMinLength(BridgeID bridge_id)
{
if (!IsValidBridge(bridge_id)) return -1;
return ::GetBridgeSpec(bridge_id)->min_length + 2;
return static_cast<SQInteger>(::GetBridgeSpec(bridge_id)->min_length) + 2;
}
/* static */ TileIndex ScriptBridge::GetOtherBridgeEnd(TileIndex tile)

View File

@@ -69,7 +69,7 @@ public:
* @pre vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER
* @return The name the bridge has.
*/
static char *GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type);
static std::optional<std::string> GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type);
/**
* Get the maximum speed of a bridge.
@@ -80,16 +80,17 @@ public:
* This is mph / 1.6, which is roughly km/h.
* To get km/h multiply this number by 1.00584.
*/
static int32 GetMaxSpeed(BridgeID bridge_id);
static SQInteger GetMaxSpeed(BridgeID bridge_id);
/**
* Get the new cost of a bridge, excluding the road and/or rail.
* @param bridge_id The bridge to get the new cost of.
* @param length The length of the bridge.
* The value will be clamped to 0 .. MAX(int32_t).
* @pre IsValidBridge(bridge_id).
* @return The new cost the bridge has.
*/
static Money GetPrice(BridgeID bridge_id, uint length);
static Money GetPrice(BridgeID bridge_id, SQInteger length);
/**
* Get the maximum length of a bridge.
@@ -97,7 +98,7 @@ public:
* @pre IsValidBridge(bridge_id).
* @returns The maximum length the bridge has.
*/
static int32 GetMaxLength(BridgeID bridge_id);
static SQInteger GetMaxLength(BridgeID bridge_id);
/**
* Get the minimum length of a bridge.
@@ -105,7 +106,7 @@ public:
* @pre IsValidBridge(bridge_id).
* @returns The minimum length the bridge has.
*/
static int32 GetMinLength(BridgeID bridge_id);
static SQInteger GetMinLength(BridgeID bridge_id);
/**
* Internal function to help BuildBridge in case of road.
@@ -136,7 +137,7 @@ public:
* @pre vehicle_type == ScriptVehicle::VT_WATER ||
* (vehicle_type == ScriptVehicle::VT_ROAD && ScriptRoad::IsRoadTypeAvailable(ScriptRoad::GetCurrentRoadType())) ||
* (vehicle_type == ScriptVehicle::VT_RAIL && ScriptRail::IsRailTypeAvailable(ScriptRail::GetCurrentRailType())).
* @game @pre Outside CompanyMode: vehicle_type == ScriptVehicle::VT_ROAD.
* @game @pre ScriptCompanyMode::IsValid() || vehicle_type == ScriptVehicle::VT_ROAD.
* @exception ScriptError::ERR_ALREADY_BUILT
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_LAND_SLOPED_WRONG
@@ -145,7 +146,7 @@ public:
* @exception ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER
* @exception ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT
* @return Whether the bridge has been/can be build or not.
* @game @note Building a bridge (without CompanyMode) results in a bridge owned by towns.
* @game @note Building a bridge as deity (ScriptCompanyMode::IsDeity()) results in a bridge owned by towns.
* @note No matter if the road pieces were build or not, if building the
* bridge succeeded, this function returns true.
*/
@@ -155,7 +156,7 @@ public:
* Removes a bridge, by executing it on either the start or end tile.
* @param tile An end or start tile of the bridge.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the bridge has been/can be removed or not.
*/

View File

@@ -21,11 +21,11 @@ ScriptBridgeList::ScriptBridgeList()
}
}
ScriptBridgeList_Length::ScriptBridgeList_Length(uint length)
ScriptBridgeList_Length::ScriptBridgeList_Length(SQInteger length)
{
for (byte j = 0; j < MAX_BRIDGES; j++) {
if (ScriptBridge::IsValidBridge(j)) {
if (length >= (uint)ScriptBridge::GetMinLength(j) && length <= (uint)ScriptBridge::GetMaxLength(j)) this->AddItem(j);
if (length >= ScriptBridge::GetMinLength(j) && length <= ScriptBridge::GetMaxLength(j)) this->AddItem(j);
}
}
}

View File

@@ -32,7 +32,7 @@ public:
/**
* @param length The length of the bridge you want to build.
*/
ScriptBridgeList_Length(uint length);
ScriptBridgeList_Length(SQInteger length);
};
#endif /* SCRIPT_BRIDGELIST_HPP */

View File

@@ -10,6 +10,7 @@
#include "../../stdafx.h"
#include "script_cargo.hpp"
#include "../../economy_func.h"
#include "../../core/alloc_func.hpp"
#include "../../core/bitmath_func.hpp"
#include "../../strings_func.h"
#include "../../settings_type.h"
@@ -24,29 +25,28 @@
/* static */ bool ScriptCargo::IsValidTownEffect(TownEffect towneffect_type)
{
return (towneffect_type >= (TownEffect)TE_BEGIN && towneffect_type < (TownEffect)TE_END);
return (towneffect_type >= (TownEffect)TAE_BEGIN && towneffect_type < (TownEffect)TAE_END);
}
/* static */ char *ScriptCargo::GetName(CargoID cargo_type)
/* static */ std::optional<std::string> ScriptCargo::GetName(CargoID cargo_type)
{
if (!IsValidCargo(cargo_type)) return nullptr;
if (!IsValidCargo(cargo_type)) return std::nullopt;
::SetDParam(0, 1ULL << cargo_type);
return GetString(STR_JUST_CARGO_LIST);
}
/* static */ char *ScriptCargo::GetCargoLabel(CargoID cargo_type)
/* static */ std::optional<std::string> ScriptCargo::GetCargoLabel(CargoID cargo_type)
{
if (!IsValidCargo(cargo_type)) return nullptr;
if (!IsValidCargo(cargo_type)) return std::nullopt;
const CargoSpec *cargo = ::CargoSpec::Get(cargo_type);
/* cargo->label is a uint32 packing a 4 character non-terminated string,
/* cargo->label is a uint32_t packing a 4 character non-terminated string,
* like "PASS", "COAL", "OIL_". New ones can be defined by NewGRFs */
char *cargo_label = MallocT<char>(sizeof(cargo->label) + 1);
std::string cargo_label;
for (uint i = 0; i < sizeof(cargo->label); i++) {
cargo_label[i] = GB(cargo->label, (uint8)(sizeof(cargo->label) - i - 1) * 8, 8);
cargo_label.push_back(GB(cargo->label, (uint8_t)(sizeof(cargo->label) - i - 1) * 8, 8));
}
cargo_label[sizeof(cargo->label)] = '\0';
return cargo_label;
}
@@ -67,13 +67,16 @@
{
if (!IsValidCargo(cargo_type)) return TE_NONE;
return (ScriptCargo::TownEffect)::CargoSpec::Get(cargo_type)->town_effect;
return (ScriptCargo::TownEffect)::CargoSpec::Get(cargo_type)->town_acceptance_effect;
}
/* static */ Money ScriptCargo::GetCargoIncome(CargoID cargo_type, uint32 distance, uint32 days_in_transit)
/* static */ Money ScriptCargo::GetCargoIncome(CargoID cargo_type, SQInteger distance, SQInteger days_in_transit)
{
if (!IsValidCargo(cargo_type)) return -1;
return ::GetTransportedGoodsIncome(1, distance, Clamp(days_in_transit * 2 / 5, 0, 255), cargo_type);
distance = Clamp<SQInteger>(distance, 0, UINT32_MAX);
return ::GetTransportedGoodsIncome(1, distance, Clamp(days_in_transit * 2 / 5, 0, UINT16_MAX), cargo_type);
}
/* static */ ScriptCargo::DistributionType ScriptCargo::GetDistributionType(CargoID cargo_type)
@@ -82,8 +85,11 @@
return (ScriptCargo::DistributionType)_settings_game.linkgraph.GetDistributionType(cargo_type);
}
/* static */ int64 ScriptCargo::GetWeight(CargoID cargo_type, uint32 amount)
/* static */ SQInteger ScriptCargo::GetWeight(CargoID cargo_type, SQInteger amount)
{
if (!IsValidCargo(cargo_type)) return -1;
amount = Clamp<SQInteger>(amount, 0, UINT32_MAX);
return ::CargoSpec::Get(cargo_type)->WeightOfNUnits(amount);
}

View File

@@ -42,12 +42,12 @@ public:
*/
enum TownEffect {
/* Note: these values represent part of the in-game TownEffect enum */
TE_NONE = ::TE_NONE, ///< This cargo has no effect on a town
TE_PASSENGERS = ::TE_PASSENGERS, ///< This cargo supplies passengers to a town
TE_MAIL = ::TE_MAIL, ///< This cargo supplies mail to a town
TE_GOODS = ::TE_GOODS, ///< This cargo supplies goods to a town
TE_WATER = ::TE_WATER, ///< This cargo supplies water to a town
TE_FOOD = ::TE_FOOD, ///< This cargo supplies food to a town
TE_NONE = ::TAE_NONE, ///< This cargo has no effect on a town
TE_PASSENGERS = ::TAE_PASSENGERS, ///< This cargo supplies passengers to a town
TE_MAIL = ::TAE_MAIL, ///< This cargo supplies mail to a town
TE_GOODS = ::TAE_GOODS, ///< This cargo supplies goods to a town
TE_WATER = ::TAE_WATER, ///< This cargo supplies water to a town
TE_FOOD = ::TAE_FOOD, ///< This cargo supplies food to a town
};
/**
@@ -55,9 +55,9 @@ public:
*/
enum SpecialCargoID {
/* Note: these values represent part of the in-game CargoTypes enum */
CT_AUTO_REFIT = ::CT_AUTO_REFIT, ///< Automatically choose cargo type when doing auto-refitting.
CT_NO_REFIT = ::CT_NO_REFIT, ///< Do not refit cargo of a vehicle.
CT_INVALID = ::CT_INVALID, ///< An invalid cargo type.
CT_AUTO_REFIT = ::CARGO_AUTO_REFIT, ///< Automatically choose cargo type when doing auto-refitting.
CT_NO_REFIT = ::CARGO_NO_REFIT, ///< Do not refit cargo of a vehicle.
CT_INVALID = ::INVALID_CARGO, ///< An invalid cargo type.
};
/**
@@ -90,7 +90,7 @@ public:
* @pre IsValidCargo(cargo_type).
* @return The name of the cargo type.
*/
static char *GetName(CargoID cargo_type);
static std::optional<std::string> GetName(CargoID cargo_type);
/**
* Gets the string representation of the cargo label.
@@ -107,7 +107,7 @@ public:
* - In other words: Only use the cargo label, if you know more about the behaviour
* of a specific cargo from a specific industry set, than the API methods can tell you.
*/
static char *GetCargoLabel(CargoID cargo_type);
static std::optional<std::string> GetCargoLabel(CargoID cargo_type);
/**
* Checks whether the give cargo is a freight or not.
@@ -142,10 +142,12 @@ public:
* @param cargo_type The cargo to transport.
* @pre ScriptCargo::IsValidCargo(cargo_type).
* @param distance The distance the cargo travels from begin to end.
* @param days_in_transit Amount of (game) days the cargo is in transit. The max value of this variable is 637. Any value higher returns the same as 637 would.
* The value will be clamped to 0 .. MAX(uint32_t).
* @param days_in_transit Amount of (game) days the cargo is in transit.
* The max value of this variable is 637. Any value higher returns the same as 637 would.
* @return The amount of money that would be earned by this trip.
*/
static Money GetCargoIncome(CargoID cargo_type, uint32 distance, uint32 days_in_transit);
static Money GetCargoIncome(CargoID cargo_type, SQInteger distance, SQInteger days_in_transit);
/**
* Get the cargo distribution type for a cargo.
@@ -159,10 +161,11 @@ public:
* cargo for the specified type.
* @param cargo_type The cargo to check on.
* @param amount The quantity of cargo.
* The value will be clamped to 0 .. MAX(uint32_t).
* @pre ScriptCargo::IsValidCargo(cargo_type).
* @return The weight in tonnes for that quantity of cargo.
*/
static int64 GetWeight(CargoID cargo_type, uint32 amount);
static SQInteger GetWeight(CargoID cargo_type, SQInteger amount);
};
#endif /* SCRIPT_CARGO_HPP */

View File

@@ -29,10 +29,9 @@ ScriptCargoList_IndustryAccepting::ScriptCargoList_IndustryAccepting(IndustryID
if (!ScriptIndustry::IsValidIndustry(industry_id)) return;
Industry *ind = ::Industry::Get(industry_id);
for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
CargoID cargo_id = ind->accepts_cargo[i];
if (cargo_id != CT_INVALID) {
this->AddItem(cargo_id);
for (const auto &a : ind->accepted) {
if (::IsValidCargoID(a.cargo)) {
this->AddItem(a.cargo);
}
}
}
@@ -42,10 +41,9 @@ ScriptCargoList_IndustryProducing::ScriptCargoList_IndustryProducing(IndustryID
if (!ScriptIndustry::IsValidIndustry(industry_id)) return;
Industry *ind = ::Industry::Get(industry_id);
for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
CargoID cargo_id = ind->produced_cargo[i];
if (cargo_id != CT_INVALID) {
this->AddItem(cargo_id);
for (const auto &p : ind->produced) {
if (::IsValidCargoID(p.cargo)) {
this->AddItem(p.cargo);
}
}
}

View File

@@ -15,7 +15,7 @@
#include "../../safeguards.h"
/* static */ int32 ScriptCargoMonitor::GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
/* static */ SQInteger ScriptCargoMonitor::GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
{
CompanyID cid = static_cast<CompanyID>(company);
if (cid >= MAX_COMPANIES) return -1;
@@ -26,7 +26,7 @@
return GetDeliveryAmount(monitor, keep_monitoring);
}
/* static */ int32 ScriptCargoMonitor::GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
/* static */ SQInteger ScriptCargoMonitor::GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
{
CompanyID cid = static_cast<CompanyID>(company);
if (cid >= MAX_COMPANIES) return -1;
@@ -37,7 +37,7 @@
return GetDeliveryAmount(monitor, keep_monitoring);
}
/* static */ int32 ScriptCargoMonitor::GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
/* static */ SQInteger ScriptCargoMonitor::GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
{
CompanyID cid = static_cast<CompanyID>(company);
if (cid >= MAX_COMPANIES) return -1;
@@ -48,7 +48,7 @@
return GetPickupAmount(monitor, keep_monitoring);
}
/* static */ int32 ScriptCargoMonitor::GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
/* static */ SQInteger ScriptCargoMonitor::GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
{
CompanyID cid = static_cast<CompanyID>(company);
if (cid >= MAX_COMPANIES) return -1;

View File

@@ -51,7 +51,7 @@ public:
* @return Amount of delivered cargo of the given cargo type to the given town by the given company since the last call, or
* \c -1 if a parameter is out-of-bound.
*/
static int32 GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
static SQInteger GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
/**
* Get the amount of cargo delivered to an industry by a company since the last query, and update the monitoring state.
@@ -62,7 +62,7 @@ public:
* @return Amount of delivered cargo of the given cargo type to the given industry by the given company since the last call, or
* \c -1 if a parameter is out-of-bound.
*/
static int32 GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
static SQInteger GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
/**
* Get the amount of cargo picked up (and delivered) from a town by a company since the last query, and update the monitoring state.
@@ -74,7 +74,7 @@ public:
* \c -1 if a parameter is out-of-bound.
* @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it.
*/
static int32 GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
static SQInteger GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
/**
* Get the amount of cargo picked up (and delivered) from an industry by a company since the last query, and update the monitoring state.
@@ -86,7 +86,7 @@ public:
* \c -1 if a parameter is out-of-bound.
* @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it.
*/
static int32 GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
static SQInteger GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
/** Stop monitoring everything. */
static void StopAllMonitoring();

View File

@@ -32,11 +32,11 @@ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client)
return (FindClientInfo(client) == nullptr ? ScriptClient::CLIENT_INVALID : client);
}
/* static */ char *ScriptClient::GetName(ScriptClient::ClientID client)
/* static */ std::optional<std::string> ScriptClient::GetName(ScriptClient::ClientID client)
{
NetworkClientInfo *ci = FindClientInfo(client);
if (ci == nullptr) return nullptr;
return stredup(ci->client_name.c_str());
if (ci == nullptr) return std::nullopt;
return ci->client_name;
}
/* static */ ScriptCompany::CompanyID ScriptClient::GetCompany(ScriptClient::ClientID client)
@@ -50,5 +50,5 @@ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client)
{
NetworkClientInfo *ci = FindClientInfo(client);
if (ci == nullptr) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)ci->join_date;
return (ScriptDate::Date)ci->join_date.base();
}

View File

@@ -24,7 +24,7 @@ class ScriptClient : public ScriptObject {
public:
/** Different constants related to ClientID. */
enum ClientID : uint32 {
enum ClientID : uint32_t {
CLIENT_INVALID = 0, ///< Client is not part of anything
CLIENT_SERVER = 1, ///< Servers always have this ID
CLIENT_FIRST = 2, ///< The first client ID
@@ -45,7 +45,7 @@ public:
* @pre ResolveClientID(client) != CLIENT_INVALID.
* @return The name of the given client.
*/
static char *GetName(ClientID client);
static std::optional<std::string> GetName(ClientID client);
/**
* Get the company in which the given client is playing.

View File

@@ -40,6 +40,7 @@
/* static */ bool ScriptCompany::IsMine(ScriptCompany::CompanyID company)
{
EnforceCompanyModeValid(false);
return ResolveCompanyID(company) == ResolveCompanyID(COMPANY_SELF);
}
@@ -47,18 +48,19 @@
{
CCountedPtr<Text> counter(name);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, name != nullptr);
const char *text = name->GetDecodedText();
const std::string &text = name->GetDecodedText();
EnforcePreconditionEncodedText(false, text);
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_COMPANY_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
return ScriptObject::Command<CMD_RENAME_COMPANY>::Do(text);
}
/* static */ char *ScriptCompany::GetName(ScriptCompany::CompanyID company)
/* static */ std::optional<std::string> ScriptCompany::GetName(ScriptCompany::CompanyID company)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return nullptr;
if (company == COMPANY_INVALID) return std::nullopt;
::SetDParam(0, company);
return GetString(STR_COMPANY_NAME);
@@ -68,38 +70,34 @@
{
CCountedPtr<Text> counter(name);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, name != nullptr);
const char *text = name->GetDecodedText();
const std::string &text = name->GetDecodedText();
EnforcePreconditionEncodedText(false, text);
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_PRESIDENT_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
return ScriptObject::Command<CMD_RENAME_PRESIDENT>::Do(text);
}
/* static */ char *ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company)
/* static */ std::optional<std::string> ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return std::nullopt;
static const int len = 64;
char *president_name = MallocT<char>(len);
if (company != COMPANY_INVALID) {
::SetDParam(0, company);
::GetString(president_name, STR_PRESIDENT_NAME, &president_name[len - 1]);
} else {
*president_name = '\0';
}
return president_name;
::SetDParam(0, company);
return GetString(STR_PRESIDENT_NAME);
}
/* static */ bool ScriptCompany::SetPresidentGender(Gender gender)
{
EnforceCompanyModeValid(false);
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) | (::InteractiveRandom() & (1 << ETHNICITY_BLACK)));
RandomCompanyManagerFaceBits(cmf, ge, false);
GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (randomizer.Next() & (1 << ETHNICITY_BLACK)));
RandomCompanyManagerFaceBits(cmf, ge, false, randomizer);
return ScriptObject::Command<CMD_SET_COMPANY_MANAGER_FACE>::Do(cmf);
}
@@ -113,11 +111,12 @@
return HasBit(ge, ::GENDER_FEMALE) ? GENDER_FEMALE : GENDER_MALE;
}
/* static */ Money ScriptCompany::GetQuarterlyIncome(ScriptCompany::CompanyID company, uint32 quarter)
/* static */ Money ScriptCompany::GetQuarterlyIncome(ScriptCompany::CompanyID company, SQInteger quarter)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return -1;
if (quarter > EARLIEST_QUARTER) return -1;
if (quarter < CURRENT_QUARTER) return -1;
if (quarter == CURRENT_QUARTER) {
return ::Company::Get(company)->cur_economy.income;
@@ -125,11 +124,12 @@
return ::Company::Get(company)->old_economy[quarter - 1].income;
}
/* static */ Money ScriptCompany::GetQuarterlyExpenses(ScriptCompany::CompanyID company, uint32 quarter)
/* static */ Money ScriptCompany::GetQuarterlyExpenses(ScriptCompany::CompanyID company, SQInteger quarter)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return -1;
if (quarter > EARLIEST_QUARTER) return -1;
if (quarter < CURRENT_QUARTER) return -1;
if (quarter == CURRENT_QUARTER) {
return ::Company::Get(company)->cur_economy.expenses;
@@ -137,11 +137,12 @@
return ::Company::Get(company)->old_economy[quarter - 1].expenses;
}
/* static */ int32 ScriptCompany::GetQuarterlyCargoDelivered(ScriptCompany::CompanyID company, uint32 quarter)
/* static */ SQInteger ScriptCompany::GetQuarterlyCargoDelivered(ScriptCompany::CompanyID company, SQInteger quarter)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return -1;
if (quarter > EARLIEST_QUARTER) return -1;
if (quarter < CURRENT_QUARTER) return -1;
if (quarter == CURRENT_QUARTER) {
return ::Company::Get(company)->cur_economy.delivered_cargo.GetSum<OverflowSafeInt32>();
@@ -149,21 +150,22 @@
return ::Company::Get(company)->old_economy[quarter - 1].delivered_cargo.GetSum<OverflowSafeInt32>();
}
/* static */ int32 ScriptCompany::GetQuarterlyPerformanceRating(ScriptCompany::CompanyID company, uint32 quarter)
/* static */ SQInteger ScriptCompany::GetQuarterlyPerformanceRating(ScriptCompany::CompanyID company, SQInteger quarter)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return -1;
if (quarter > EARLIEST_QUARTER) return -1;
if (quarter == CURRENT_QUARTER) return -1;
if (quarter <= CURRENT_QUARTER) return -1;
return ::Company::Get(company)->old_economy[quarter - 1].performance_history;
}
/* static */ Money ScriptCompany::GetQuarterlyCompanyValue(ScriptCompany::CompanyID company, uint32 quarter)
/* static */ Money ScriptCompany::GetQuarterlyCompanyValue(ScriptCompany::CompanyID company, SQInteger quarter)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return -1;
if (quarter > EARLIEST_QUARTER) return -1;
if (quarter < CURRENT_QUARTER) return -1;
if (quarter == CURRENT_QUARTER) {
return ::CalculateCompanyValue(::Company::Get(company));
@@ -177,7 +179,7 @@
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return -1;
return ::Company::Get(company)->money;
return GetAvailableMoney((::CompanyID)company);
}
/* static */ Money ScriptCompany::GetLoanAmount()
@@ -190,7 +192,32 @@
/* static */ Money ScriptCompany::GetMaxLoanAmount()
{
return _economy.max_loan;
if (ScriptCompanyMode::IsDeity()) return _economy.max_loan;
ScriptCompany::CompanyID company = ResolveCompanyID(COMPANY_SELF);
if (company == COMPANY_INVALID) return -1;
return ::Company::Get(company)->GetMaxLoan();
}
/* static */ bool ScriptCompany::SetMaxLoanAmountForCompany(CompanyID company, Money amount)
{
EnforceDeityMode(false);
EnforcePrecondition(false, amount >= 0 && amount <= (Money)MAX_LOAN_LIMIT);
company = ResolveCompanyID(company);
EnforcePrecondition(false, company != COMPANY_INVALID);
return ScriptObject::Command<CMD_SET_COMPANY_MAX_LOAN>::Do((::CompanyID)company, amount);
}
/* static */ bool ScriptCompany::ResetMaxLoanAmountForCompany(CompanyID company)
{
EnforceDeityMode(false);
company = ResolveCompanyID(company);
EnforcePrecondition(false, company != COMPANY_INVALID);
return ScriptObject::Command<CMD_SET_COMPANY_MAX_LOAN>::Do((::CompanyID)company, COMPANY_MAX_LOAN_DEFAULT);
}
/* static */ Money ScriptCompany::GetLoanInterval()
@@ -200,9 +227,9 @@
/* static */ bool ScriptCompany::SetLoanAmount(Money loan)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, loan >= 0);
EnforcePrecondition(false, ((int64)loan % GetLoanInterval()) == 0);
EnforcePrecondition(false, ((int64_t)loan % GetLoanInterval()) == 0);
EnforcePrecondition(false, loan <= GetMaxLoanAmount());
EnforcePrecondition(false, (loan - GetLoanAmount() + GetBankBalance(COMPANY_SELF)) >= 0);
@@ -219,10 +246,10 @@
/* static */ bool ScriptCompany::SetMinimumLoanAmount(Money loan)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, loan >= 0);
Money over_interval = (int64)loan % GetLoanInterval();
Money over_interval = (int64_t)loan % GetLoanInterval();
if (over_interval != 0) loan += GetLoanInterval() - over_interval;
EnforcePrecondition(false, loan <= GetMaxLoanAmount());
@@ -234,10 +261,8 @@
/* static */ bool ScriptCompany::ChangeBankBalance(CompanyID company, Money delta, ExpensesType expenses_type, TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, expenses_type < (ExpensesType)::EXPENSES_END);
EnforcePrecondition(false, (int64)delta >= INT32_MIN);
EnforcePrecondition(false, (int64)delta <= INT32_MAX);
EnforcePrecondition(false, tile == INVALID_TILE || ::IsValidTile(tile));
company = ResolveCompanyID(company);
@@ -249,7 +274,7 @@
/* static */ bool ScriptCompany::BuildCompanyHQ(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
return ScriptObject::Command<CMD_BUILD_OBJECT>::Do(tile, OBJECT_HQ, 0);
@@ -266,6 +291,7 @@
/* static */ bool ScriptCompany::SetAutoRenewStatus(bool autorenew)
{
EnforceCompanyModeValid(false);
return ScriptObject::Command<CMD_CHANGE_COMPANY_SETTING>::Do("company.engine_renew", autorenew ? 1 : 0);
}
@@ -277,12 +303,15 @@
return ::Company::Get(company)->settings.engine_renew;
}
/* static */ bool ScriptCompany::SetAutoRenewMonths(int16 months)
/* static */ bool ScriptCompany::SetAutoRenewMonths(SQInteger months)
{
EnforceCompanyModeValid(false);
months = Clamp<SQInteger>(months, INT16_MIN, INT16_MAX);
return ScriptObject::Command<CMD_CHANGE_COMPANY_SETTING>::Do("company.engine_renew_months", months);
}
/* static */ int16 ScriptCompany::GetAutoRenewMonths(CompanyID company)
/* static */ SQInteger ScriptCompany::GetAutoRenewMonths(CompanyID company)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return 0;
@@ -292,8 +321,9 @@
/* static */ bool ScriptCompany::SetAutoRenewMoney(Money money)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, money >= 0);
EnforcePrecondition(false, (int64)money <= UINT32_MAX);
EnforcePrecondition(false, (int64_t)money <= UINT32_MAX);
return ScriptObject::Command<CMD_CHANGE_COMPANY_SETTING>::Do("company.engine_renew_money", money);
}
@@ -307,11 +337,13 @@
/* static */ bool ScriptCompany::SetPrimaryLiveryColour(LiveryScheme scheme, Colours colour)
{
EnforceCompanyModeValid(false);
return ScriptObject::Command<CMD_SET_COMPANY_COLOUR>::Do((::LiveryScheme)scheme, true, (::Colours)colour);
}
/* static */ bool ScriptCompany::SetSecondaryLiveryColour(LiveryScheme scheme, Colours colour)
{
EnforceCompanyModeValid(false);
return ScriptObject::Command<CMD_SET_COMPANY_COLOUR>::Do((::LiveryScheme)scheme, false, (::Colours)colour);
}

View File

@@ -129,8 +129,8 @@ public:
/**
* Check if a CompanyID is your CompanyID, to ease up checks.
* @param company The company index to check.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and only if this company is your CompanyID.
* @api -game
*/
static bool IsMine(CompanyID company);
@@ -138,6 +138,7 @@ public:
* Set the name of your company.
* @param name The new name of the company (can be either a raw string, or a ScriptText object).
* @pre name != null && len(name) != 0.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE
* @return True if the name was changed.
*/
@@ -149,12 +150,13 @@ public:
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @return The name of the given company.
*/
static char *GetName(CompanyID company);
static std::optional<std::string> GetName(CompanyID company);
/**
* Set the name of your president.
* @param name The new name of the president (can be either a raw string, or a ScriptText object).
* @pre name != null && len(name) != 0.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE
* @return True if the name was changed.
*/
@@ -166,15 +168,15 @@ public:
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @return The name of the president of the given company.
*/
static char *GetPresidentName(CompanyID company);
static std::optional<std::string> GetPresidentName(CompanyID company);
/**
* Set the gender of the president of your company.
* @param gender The new gender for your president.
* @pre GetPresidentGender(ScriptCompany.COMPANY_SELF) != gender.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if the gender was changed.
* @note When successful a random face will be created.
* @api -game
*/
static bool SetPresidentGender(Gender gender);
@@ -192,7 +194,7 @@ public:
* @pre GetLoanInterval() must be a multiplier of 'loan'.
* @pre 'loan' must be below GetMaxLoanAmount().
* @pre 'loan' - GetLoanAmount() + GetBankBalance() must be non-negative.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if the loan could be set to your requested amount.
*/
static bool SetLoanAmount(Money loan);
@@ -202,7 +204,7 @@ public:
* @param loan The amount to loan (any positive number).
* @pre 'loan' must be non-negative.
* @pre 'loan' must be below GetMaxLoanAmount().
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if we could allocate a minimum of 'loan' loan.
*/
static bool SetMinimumLoanAmount(Money loan);
@@ -215,12 +217,38 @@ public:
static Money GetLoanAmount();
/**
* Gets the maximum amount your company can loan.
* Gets the maximum amount your company can loan. In deity mode returns the global max loan.
* @return The maximum amount your company can loan.
* @post GetLoanInterval() is always a multiplier of the return value.
*/
static Money GetMaxLoanAmount();
/**
* Sets the max amount of money company can loan.
* @param company The company ID.
* @param amount Max loan amount. Will be rounded down to a multiple of GetLoanInterval().
* @return True, if the max loan was changed.
* @pre ScriptCompanyMode::IsDeity().
* @pre amount >= 0.
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @note You need to create your own news message to inform about max loan change.
* @note Max loan value set with this method is not affected by inflation.
* @api -ai
*/
static bool SetMaxLoanAmountForCompany(CompanyID company, Money amount);
/**
* Makes the max amount of money company can loan follow the global max loan setting.
* @param company The company ID.
* @return True, if the max loan was reset.
* @pre ScriptCompanyMode::IsDeity().
* @pre amount >= 0 && amount <= MAX_LOAN_LIMIT.
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @note You need to create your own news message to inform about max loan change.
* @api -ai
*/
static bool ResetMaxLoanAmountForCompany(CompanyID company);
/**
* Gets the interval/loan step.
* @return The loan step.
@@ -244,10 +272,8 @@ public:
* @param expenses_type The account in the finances window that will register the cost.
* @param tile The tile to show text effect on or ScriptMap::TILE_INVALID
* @return True, if the bank balance was changed.
* @game @pre No ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsDeity().
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @pre delta >= -2**31
* @pre delta < 2**31
* @note You need to create your own news message to inform about costs/gifts that you create using this command.
* @api -ai
*/
@@ -263,7 +289,7 @@ public:
* @pre quarter <= EARLIEST_QUARTER.
* @return The gross income of the company in the given quarter.
*/
static Money GetQuarterlyIncome(CompanyID company, uint32 quarter);
static Money GetQuarterlyIncome(CompanyID company, SQInteger quarter);
/**
* Get the expenses of the company in the given quarter.
@@ -276,7 +302,7 @@ public:
* @pre quarter <= EARLIEST_QUARTER.
* @return The expenses of the company in the given quarter.
*/
static Money GetQuarterlyExpenses(CompanyID company, uint32 quarter);
static Money GetQuarterlyExpenses(CompanyID company, SQInteger quarter);
/**
* Get the amount of cargo delivered by the given company in the given quarter.
@@ -286,7 +312,7 @@ public:
* @pre quarter <= EARLIEST_QUARTER.
* @return The amount of cargo delivered by the given company in the given quarter.
*/
static int32 GetQuarterlyCargoDelivered(CompanyID company, uint32 quarter);
static SQInteger GetQuarterlyCargoDelivered(CompanyID company, SQInteger quarter);
/**
* Get the performance rating of the given company in the given quarter.
@@ -298,7 +324,7 @@ public:
* @note The performance rating is calculated after every quarter, so the value for CURRENT_QUARTER is undefined.
* @return The performance rating of the given company in the given quarter.
*/
static int32 GetQuarterlyPerformanceRating(CompanyID company, uint32 quarter);
static SQInteger GetQuarterlyPerformanceRating(CompanyID company, SQInteger quarter);
/**
* Get the value of the company in the given quarter.
@@ -308,13 +334,13 @@ public:
* @pre quarter <= EARLIEST_QUARTER.
* @return The value of the company in the given quarter.
*/
static Money GetQuarterlyCompanyValue(CompanyID company, uint32 quarter);
static Money GetQuarterlyCompanyValue(CompanyID company, SQInteger quarter);
/**
* Build your company's HQ on the given tile.
* @param tile The tile to build your HQ on, this tile is the most northern tile of your HQ.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
* @return True if the HQ could be build.
@@ -335,8 +361,8 @@ public:
/**
* Set whether autorenew is enabled for your company.
* @param autorenew The new autorenew status.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if autorenew status has been modified.
* @api -game
*/
static bool SetAutoRenewStatus(bool autorenew);
@@ -351,10 +377,11 @@ public:
/**
* Set the number of months before/after max age to autorenew an engine for your company.
* @param months The new months between autorenew.
* The value will be clamped to MIN(int16_t) .. MAX(int16_t).
* @game @pre ScriptCompanyMode::IsValid().
* @return True if autorenew months has been modified.
* @api -game
*/
static bool SetAutoRenewMonths(int16 months);
static bool SetAutoRenewMonths(SQInteger months);
/**
* Return the number of months before/after max age to autorenew an engine for a company.
@@ -362,15 +389,15 @@ public:
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @return The months before/after max age of engine.
*/
static int16 GetAutoRenewMonths(CompanyID company);
static SQInteger GetAutoRenewMonths(CompanyID company);
/**
* Set the minimum money needed to autorenew an engine for your company.
* @param money The new minimum required money for autorenew to work.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if autorenew money has been modified.
* @pre money >= 0
* @pre money < 2**32
* @api -game
*/
static bool SetAutoRenewMoney(Money money);
@@ -386,6 +413,7 @@ public:
* Set primary colour for your company.
* @param scheme Livery scheme to set.
* @param colour Colour to set.
* @game @pre ScriptCompanyMode::IsValid().
* @return False if unable to set primary colour of the livery scheme (e.g. colour in use).
*/
static bool SetPrimaryLiveryColour(LiveryScheme scheme, Colours colour);
@@ -394,6 +422,7 @@ public:
* Set secondary colour for your company.
* @param scheme Livery scheme to set.
* @param colour Colour to set.
* @game @pre ScriptCompanyMode::IsValid().
* @return False if unable to set secondary colour of the livery scheme.
*/
static bool SetSecondaryLiveryColour(LiveryScheme scheme, Colours colour);

View File

@@ -13,16 +13,26 @@
#include "../../safeguards.h"
ScriptCompanyMode::ScriptCompanyMode(int company)
ScriptCompanyMode::ScriptCompanyMode(SQInteger company)
{
if (company < OWNER_BEGIN || company >= MAX_COMPANIES) company = INVALID_COMPANY;
if (!::Company::IsValidID(company)) company = INVALID_COMPANY;
this->last_company = ScriptObject::GetCompany();
ScriptObject::SetCompany((CompanyID)company);
ScriptObject::SetCompany((::CompanyID)company);
}
ScriptCompanyMode::~ScriptCompanyMode()
{
ScriptObject::SetCompany(this->last_company);
}
/* static */ bool ScriptCompanyMode::IsValid()
{
return ::Company::IsValidID(ScriptObject::GetCompany());
}
/* static */ bool ScriptCompanyMode::IsDeity()
{
return ScriptObject::GetCompany() == OWNER_DEITY;
}

View File

@@ -40,13 +40,29 @@ public:
* @note When the instance is destroyed, it restores the company that was
* current when the instance was created!
*/
ScriptCompanyMode(int company);
ScriptCompanyMode(SQInteger company);
/**
* Destroying this instance reset the company to that what it was
* in when the instance was created.
*/
~ScriptCompanyMode();
/**
* Check whether a company mode is valid. In other words, are commands
* being executed under some company and does the company still exist?
* @return true When a company mode is valid.
* @post !ScriptCompanyMode::IsDeity().
*/
static bool IsValid();
/**
* Check whether the company mode is not active, i.e. whether we are a deity.
* In other words, are commands are not being executed under some company.
* @return true When we are a deity, i.e. company mode is not active.
* @post !ScriptCompanyMode::IsValid().
*/
static bool IsDeity();
};
#endif /* SCRIPT_COMPANYMODE_HPP */

View File

@@ -18,7 +18,7 @@
#include "../script_info.hpp"
#include "../script_instance.hpp"
#include "script_log.hpp"
#include "../../ai/ai_gui.hpp"
#include "../script_gui.h"
#include "../../settings_type.h"
#include "../../network/network.h"
#include "../../misc_cmd.h"
@@ -45,28 +45,26 @@
throw Script_Suspend(ticks, nullptr);
}
/* static */ void ScriptController::Break(const char* message)
/* static */ void ScriptController::Break(const std::string &message)
{
if (_network_dedicated || !_settings_client.gui.ai_developer_tools) return;
ScriptObject::GetActiveInstance()->Pause();
char log_message[1024];
seprintf(log_message, lastof(log_message), "Break: %s", message);
ScriptLog::Log(ScriptLog::LOG_SQ_ERROR, log_message);
ScriptLog::Log(ScriptLogTypes::LOG_SQ_ERROR, fmt::format("Break: {}", message));
/* Inform script developer that their script has been paused and
* needs manual action to continue. */
ShowAIDebugWindow(ScriptObject::GetRootCompany());
ShowScriptDebugWindow(ScriptObject::GetRootCompany());
if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) {
ScriptObject::Command<CMD_PAUSE>::Do(PM_PAUSED_NORMAL, true);
}
}
/* static */ void ScriptController::Print(bool error_msg, const char *message)
/* static */ void ScriptController::Print(bool error_msg, const std::string &message)
{
ScriptLog::Log(error_msg ? ScriptLog::LOG_SQ_ERROR : ScriptLog::LOG_SQ_INFO, message);
ScriptLog::Log(error_msg ? ScriptLogTypes::LOG_SQ_ERROR : ScriptLogTypes::LOG_SQ_INFO, message);
}
ScriptController::ScriptController(CompanyID company) :
@@ -76,16 +74,6 @@ ScriptController::ScriptController(CompanyID company) :
ScriptObject::SetCompany(company);
}
ScriptController::~ScriptController()
{
for (const auto &item : this->loaded_library) {
free(item.second);
free(item.first);
}
this->loaded_library.clear();
}
/* static */ uint ScriptController::GetTick()
{
return ScriptObject::GetActiveInstance()->GetController()->ticks;
@@ -96,7 +84,7 @@ ScriptController::~ScriptController()
return ScriptObject::GetActiveInstance()->GetOpsTillSuspend();
}
/* static */ int ScriptController::GetSetting(const char *name)
/* static */ int ScriptController::GetSetting(const std::string &name)
{
return ScriptObject::GetActiveInstance()->GetSetting(name);
}
@@ -106,7 +94,7 @@ ScriptController::~ScriptController()
return _openttd_newgrf_version;
}
/* static */ HSQOBJECT ScriptController::Import(const char *library, const char *class_name, int version)
/* 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;
@@ -114,30 +102,26 @@ ScriptController::~ScriptController()
ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version);
if (lib == nullptr) {
char error[1024];
seprintf(error, lastof(error), "couldn't find library '%s' with version %d", library, version);
throw sq_throwerror(vm, error);
throw sq_throwerror(vm, fmt::format("couldn't find library '{}' with version {}", library, version));
}
/* Internally we store libraries as 'library.version' */
char library_name[1024];
seprintf(library_name, lastof(library_name), "%s.%d", library, version);
strtolower(library_name);
std::string library_name = fmt::format("{}.{}", library, version);
/* Get the current table/class we belong to */
HSQOBJECT parent;
sq_getstackobj(vm, 1, &parent);
char fake_class[1024];
std::string fake_class;
LoadedLibraryList::iterator it = controller->loaded_library.find(library_name);
if (it != controller->loaded_library.end()) {
strecpy(fake_class, (*it).second, lastof(fake_class));
fake_class = (*it).second;
} else {
int next_number = ++controller->loaded_library_count;
/* Create a new fake internal name */
seprintf(fake_class, lastof(fake_class), "_internalNA%d", next_number);
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);
@@ -145,15 +129,13 @@ ScriptController::~ScriptController()
sq_newclass(vm, SQFalse);
/* Load the library */
if (!engine->LoadScript(vm, lib->GetMainScript(), false)) {
char error[1024];
seprintf(error, lastof(error), "there was a compile error when importing '%s' version %d", library, version);
throw sq_throwerror(vm, error);
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[stredup(library_name)] = stredup(fake_class);
controller->loaded_library[library_name] = fake_class;
}
/* Find the real class inside the fake class (like 'sets.Vector') */
@@ -164,15 +146,13 @@ ScriptController::~ScriptController()
}
sq_pushstring(vm, lib->GetInstanceName(), -1);
if (SQ_FAILED(sq_get(vm, -2))) {
char error[1024];
seprintf(error, lastof(error), "unable to find class '%s' in the library '%s' version %d", lib->GetInstanceName(), library, version);
throw sq_throwerror(vm, error);
throw sq_throwerror(vm, fmt::format("unable to find class '{}' in the library '{}' version {}", lib->GetInstanceName(), library, version));
}
HSQOBJECT obj;
sq_getstackobj(vm, -1, &obj);
sq_pop(vm, 3);
if (StrEmpty(class_name)) return obj;
if (class_name.empty()) return obj;
/* Now link the name the user wanted to our 'fake' class */
sq_pushobject(vm, parent);

View File

@@ -11,8 +11,6 @@
#define SCRIPT_CONTROLLER_HPP
#include "script_types.hpp"
#include "../../core/string_compare_type.hpp"
#include <map>
/**
* The Controller, the class each Script should extend. It creates the Script,
@@ -48,17 +46,14 @@ class ScriptController {
friend class ScriptInstance;
public:
#ifndef DOXYGEN_API
/**
* Initializer of the ScriptController.
* @param company The company this Script is normally serving.
*/
ScriptController(CompanyID company);
/**
* Destructor of the ScriptController.
*/
~ScriptController();
#else
/**
* This function is called to start your script. Your script starts here. If you
* return from this function, your script dies, so make sure that doesn't
@@ -67,7 +62,6 @@ public:
*/
void Start();
#ifdef DOXYGEN_API
/**
* Save the state of the script.
*
@@ -130,7 +124,7 @@ public:
* @param name The name of the setting.
* @return the value for the setting, or -1 if the setting is not known.
*/
static int GetSetting(const char *name);
static int GetSetting(const std::string &name);
/**
* Get the OpenTTD version of this executable. The version is formatted
@@ -186,7 +180,7 @@ public:
* @note gui.ai_developer_tools setting must be enabled or the break is
* ignored.
*/
static void Break(const char* message);
static void Break(const std::string &message);
/**
* When Squirrel triggers a print, this function is called.
@@ -195,7 +189,7 @@ public:
* @param message The message Squirrel logged.
* @note Use ScriptLog.Info/Warning/Error instead of 'print'.
*/
static void Print(bool error_msg, const char *message);
static void Print(bool error_msg, const std::string &message);
/**
* Import a library.
@@ -206,10 +200,10 @@ public:
* @return The loaded library object. If class_name is set, it is also available (under the scope of the import) under that name.
* @note This command can be called from the global space, and does not need an instance.
*/
static HSQOBJECT Import(const char *library, const char *class_name, int version);
static HSQOBJECT Import(const std::string &library, const std::string &class_name, int version);
private:
typedef std::map<const char *, const char *, StringCompare> LoadedLibraryList; ///< The type for loaded libraries.
typedef std::map<std::string, std::string, CaseInsensitiveComparator> LoadedLibraryList; ///< The type for loaded libraries.
uint ticks; ///< The amount of ticks we're sleeping.
LoadedLibraryList loaded_library; ///< The libraries we loaded.

View File

@@ -9,7 +9,9 @@
#include "../../stdafx.h"
#include "script_date.hpp"
#include "../../date_func.h"
#include "script_timemode.hpp"
#include "../../timer/timer_game_calendar.h"
#include "../../timer/timer_game_economy.h"
#include <time.h>
@@ -22,46 +24,62 @@
/* static */ ScriptDate::Date ScriptDate::GetCurrentDate()
{
return (ScriptDate::Date)_date;
if (ScriptTimeMode::IsCalendarMode()) return (ScriptDate::Date)TimerGameCalendar::date.base();
return (ScriptDate::Date)TimerGameEconomy::date.base();
}
/* static */ int32 ScriptDate::GetYear(ScriptDate::Date date)
/* static */ SQInteger ScriptDate::GetYear(ScriptDate::Date date)
{
if (date < 0) return DATE_INVALID;
::YearMonthDay ymd;
::ConvertDateToYMD(date, &ymd);
return ymd.year;
if (ScriptTimeMode::IsCalendarMode()) {
::TimerGameCalendar::YearMonthDay ymd = ::TimerGameCalendar::ConvertDateToYMD(date);
return ymd.year.base();
}
::TimerGameEconomy::YearMonthDay ymd = ::TimerGameEconomy::ConvertDateToYMD(date);
return ymd.year.base();
}
/* static */ int32 ScriptDate::GetMonth(ScriptDate::Date date)
/* static */ SQInteger ScriptDate::GetMonth(ScriptDate::Date date)
{
if (date < 0) return DATE_INVALID;
::YearMonthDay ymd;
::ConvertDateToYMD(date, &ymd);
if (ScriptTimeMode::IsCalendarMode()) {
::TimerGameCalendar::YearMonthDay ymd = ::TimerGameCalendar::ConvertDateToYMD(date);
return ymd.month + 1;
}
::TimerGameEconomy::YearMonthDay ymd = ::TimerGameEconomy::ConvertDateToYMD(date);
return ymd.month + 1;
}
/* static */ int32 ScriptDate::GetDayOfMonth(ScriptDate::Date date)
/* static */ SQInteger ScriptDate::GetDayOfMonth(ScriptDate::Date date)
{
if (date < 0) return DATE_INVALID;
::YearMonthDay ymd;
::ConvertDateToYMD(date, &ymd);
if (ScriptTimeMode::IsCalendarMode()) {
::TimerGameCalendar::YearMonthDay ymd = ::TimerGameCalendar::ConvertDateToYMD(date);
return ymd.day;
}
::TimerGameEconomy::YearMonthDay ymd = ::TimerGameEconomy::ConvertDateToYMD(date);
return ymd.day;
}
/* static */ ScriptDate::Date ScriptDate::GetDate(int32 year, int32 month, int32 day_of_month)
/* static */ ScriptDate::Date ScriptDate::GetDate(SQInteger year, SQInteger month, SQInteger day_of_month)
{
if (month < 1 || month > 12) return DATE_INVALID;
if (day_of_month < 1 || day_of_month > 31) return DATE_INVALID;
if (year < 0 || year > MAX_YEAR) return DATE_INVALID;
if (year < 0 || year > CalendarTime::MAX_YEAR) return DATE_INVALID;
return (ScriptDate::Date)::ConvertYMDToDate(year, month - 1, day_of_month);
if (ScriptTimeMode::IsCalendarMode()) return (ScriptDate::Date)::TimerGameCalendar::ConvertYMDToDate(year, month - 1, day_of_month).base();
return (ScriptDate::Date)::TimerGameEconomy::ConvertYMDToDate(year, month - 1, day_of_month).base();
}
/* static */ int32 ScriptDate::GetSystemTime()
/* static */ SQInteger ScriptDate::GetSystemTime()
{
time_t t;
time(&t);

View File

@@ -11,7 +11,7 @@
#define SCRIPT_DATE_HPP
#include "script_object.hpp"
#include "../../date_type.h"
#include "../../timer/timer_game_calendar.h"
/**
* Class that handles all date related (calculation) functions.
@@ -31,7 +31,7 @@ public:
* compose valid date values for a known year, month and day.
*/
enum Date {
DATE_INVALID = ::INVALID_DATE, ///< A value representing an invalid date.
DATE_INVALID = ::CalendarTime::INVALID_DATE.base(), ///< A value representing an invalid date.
};
/**
@@ -55,21 +55,21 @@ public:
* @param date The date to get the year of.
* @return The year.
*/
static int32 GetYear(Date date);
static SQInteger GetYear(Date date);
/**
* Get the month of the given date.
* @param date The date to get the month of.
* @return The month.
*/
static int32 GetMonth(Date date);
static SQInteger GetMonth(Date date);
/**
* Get the day (of the month) of the given date.
* @param date The date to get the day of.
* @return The day.
*/
static int32 GetDayOfMonth(Date date);
static SQInteger GetDayOfMonth(Date date);
/**
* Get the date given a year, month and day of month.
@@ -78,7 +78,7 @@ public:
* @param day_of_month The day of month of the to-be determined date.
* @return The date.
*/
static Date GetDate(int32 year, int32 month, int32 day_of_month);
static Date GetDate(SQInteger year, SQInteger month, SQInteger day_of_month);
/**
* Get the time of the host system.
@@ -86,7 +86,7 @@ public:
* @api -ai
* @note This uses the clock of the host system, which can skew or be set back. Use with caution.
*/
static int32 GetSystemTime();
static SQInteger GetSystemTime();
};
#endif /* SCRIPT_DATE_HPP */

View File

@@ -16,6 +16,7 @@
ScriptDepotList::ScriptDepotList(ScriptTile::TransportType transport_type)
{
EnforceDeityOrCompanyModeValid_Void();
::TileType tile_type;
switch (transport_type) {
default: return;
@@ -26,10 +27,12 @@ ScriptDepotList::ScriptDepotList(ScriptTile::TransportType transport_type)
case ScriptTile::TRANSPORT_AIR: {
/* Hangars are not seen as real depots by the depot code. */
bool is_deity = ScriptCompanyMode::IsDeity();
CompanyID owner = ScriptObject::GetCompany();
for (const Station *st : Station::Iterate()) {
if (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) {
if (is_deity || st->owner == owner) {
for (uint i = 0; i < st->airport.GetNumHangars(); i++) {
this->AddItem(st->airport.GetHangarTile(i));
this->AddItem(st->airport.GetHangarTile(i).base());
}
}
}
@@ -38,7 +41,9 @@ ScriptDepotList::ScriptDepotList(ScriptTile::TransportType transport_type)
}
/* Handle 'standard' depots. */
bool is_deity = ScriptCompanyMode::IsDeity();
CompanyID owner = ScriptObject::GetCompany();
for (const Depot *depot : Depot::Iterate()) {
if ((::GetTileOwner(depot->xy) == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && ::IsTileType(depot->xy, tile_type)) this->AddItem(depot->xy);
if ((is_deity || ::GetTileOwner(depot->xy) == owner) && ::IsTileType(depot->xy, tile_type)) this->AddItem(depot->xy.base());
}
}

View File

@@ -18,30 +18,33 @@
#include "../../engine_func.h"
#include "../../articulated_vehicles.h"
#include "../../engine_cmd.h"
#include "../../timer/timer_game_calendar.h"
#include "table/strings.h"
#include "../../safeguards.h"
/* static */ bool ScriptEngine::IsValidEngine(EngineID engine_id)
{
EnforceDeityOrCompanyModeValid(false);
const Engine *e = ::Engine::GetIfValid(engine_id);
if (e == nullptr || !e->IsEnabled()) return false;
/* AIs have only access to engines they can purchase or still have in use.
* Deity has access to all engined that will be or were available ever. */
CompanyID company = ScriptObject::GetCompany();
return company == OWNER_DEITY || ::IsEngineBuildable(engine_id, e->type, company) || ::Company::Get(company)->group_all[e->type].num_engines[engine_id] > 0;
return ScriptCompanyMode::IsDeity() || ::IsEngineBuildable(engine_id, e->type, company) || ::Company::Get(company)->group_all[e->type].GetNumEngines(engine_id) > 0;
}
/* static */ bool ScriptEngine::IsBuildable(EngineID engine_id)
{
EnforceDeityOrCompanyModeValid(false);
const Engine *e = ::Engine::GetIfValid(engine_id);
return e != nullptr && ::IsEngineBuildable(engine_id, e->type, ScriptObject::GetCompany());
}
/* static */ char *ScriptEngine::GetName(EngineID engine_id)
/* static */ std::optional<std::string> ScriptEngine::GetName(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return nullptr;
if (!IsValidEngine(engine_id)) return std::nullopt;
::SetDParam(0, engine_id);
return GetString(STR_ENGINE_NAME);
@@ -49,20 +52,14 @@
/* static */ CargoID ScriptEngine::GetCargoType(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return CT_INVALID;
if (!IsValidEngine(engine_id)) return INVALID_CARGO;
CargoArray cap = ::GetCapacityOfArticulatedParts(engine_id);
CargoID most_cargo = CT_INVALID;
uint amount = 0;
for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
if (cap[cid] > amount) {
amount = cap[cid];
most_cargo = cid;
}
}
auto it = std::max_element(std::cbegin(cap), std::cend(cap));
if (*it == 0) return INVALID_CARGO;
return most_cargo;
return CargoID(std::distance(std::cbegin(cap), it));
}
/* static */ bool ScriptEngine::CanRefitCargo(EngineID engine_id, CargoID cargo_id)
@@ -83,7 +80,7 @@
}
/* static */ int32 ScriptEngine::GetCapacity(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetCapacity(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
@@ -92,9 +89,8 @@
case VEH_ROAD:
case VEH_TRAIN: {
CargoArray capacities = GetCapacityOfArticulatedParts(engine_id);
for (CargoID c = 0; c < NUM_CARGO; c++) {
if (capacities[c] == 0) continue;
return capacities[c];
for (uint &cap : capacities) {
if (cap != 0) return cap;
}
return -1;
}
@@ -107,7 +103,7 @@
}
}
/* static */ int32 ScriptEngine::GetReliability(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetReliability(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1;
@@ -115,12 +111,12 @@
return ::ToPercent16(::Engine::Get(engine_id)->reliability);
}
/* static */ int32 ScriptEngine::GetMaxSpeed(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetMaxSpeed(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
const Engine *e = ::Engine::Get(engine_id);
int32 max_speed = e->GetDisplayMaxSpeed(); // km-ish/h
uint max_speed = e->GetDisplayMaxSpeed(); // km-ish/h
if (e->type == VEH_AIRCRAFT) max_speed /= _settings_game.vehicle.plane_speed;
return max_speed;
}
@@ -132,12 +128,12 @@
return ::Engine::Get(engine_id)->GetCost();
}
/* static */ int32 ScriptEngine::GetMaxAge(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetMaxAge(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1;
return ::Engine::Get(engine_id)->GetLifeLengthInDays();
return ::Engine::Get(engine_id)->GetLifeLengthInDays().base();
}
/* static */ Money ScriptEngine::GetRunningCost(EngineID engine_id)
@@ -147,7 +143,7 @@
return ::Engine::Get(engine_id)->GetRunningCost();
}
/* static */ int32 ScriptEngine::GetPower(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetPower(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1;
@@ -156,7 +152,7 @@
return ::Engine::Get(engine_id)->GetPower();
}
/* static */ int32 ScriptEngine::GetWeight(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetWeight(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1;
@@ -164,20 +160,20 @@
return ::Engine::Get(engine_id)->GetDisplayWeight();
}
/* static */ int32 ScriptEngine::GetMaxTractiveEffort(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetMaxTractiveEffort(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return -1;
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1;
if (IsWagon(engine_id)) return -1;
return ::Engine::Get(engine_id)->GetDisplayMaxTractiveEffort();
return ::Engine::Get(engine_id)->GetDisplayMaxTractiveEffort() / 1000;
}
/* static */ ScriptDate::Date ScriptEngine::GetDesignDate(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)::Engine::Get(engine_id)->intro_date;
return (ScriptDate::Date)::Engine::Get(engine_id)->intro_date.base();
}
/* static */ ScriptVehicle::VehicleType ScriptEngine::GetVehicleType(EngineID engine_id)
@@ -265,24 +261,19 @@
return (ScriptAirport::PlaneType)::AircraftVehInfo(engine_id)->subtype;
}
/* static */ uint ScriptEngine::GetMaximumOrderDistance(EngineID engine_id)
/* static */ SQInteger ScriptEngine::GetMaximumOrderDistance(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return 0;
if (GetVehicleType(engine_id) != ScriptVehicle::VT_AIR) return 0;
switch (GetVehicleType(engine_id)) {
case ScriptVehicle::VT_AIR:
return ::Engine::Get(engine_id)->GetRange() * ::Engine::Get(engine_id)->GetRange();
default:
return 0;
}
return (SQInteger)::Engine::Get(engine_id)->GetRange() * ::Engine::Get(engine_id)->GetRange();
}
/* static */ bool ScriptEngine::EnableForCompany(EngineID engine_id, ScriptCompany::CompanyID company)
{
company = ScriptCompany::ResolveCompanyID(company);
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidEngine(engine_id));
EnforcePrecondition(false, company != ScriptCompany::COMPANY_INVALID);
@@ -293,7 +284,7 @@
{
company = ScriptCompany::ResolveCompanyID(company);
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidEngine(engine_id));
EnforcePrecondition(false, company != ScriptCompany::COMPANY_INVALID);

View File

@@ -24,7 +24,7 @@ public:
/**
* Checks whether the given engine type is valid.
* An engine is valid for a company if it has at least one vehicle of this engine or it's currently buildable.
* @game Outside ScriptCompanyMode scope the function reports all engines valid, which were or will be available at some point.
* @game Outside ScriptCompanyMode scope (ScriptCompanyMode::IsDeity) the function reports all engines valid, which were or will be available at some point.
* @param engine_id The engine to check.
* @return True if and only if the engine type is valid.
*/
@@ -32,7 +32,7 @@ public:
/**
* Checks whether the given engine type is buildable for a company.
* @game Outside ScriptCompanyMode scope the function checks whether the engine is currently buildable by all companies (no exclusive preview).
* @game Outside ScriptCompanyMode scope (ScriptCompanyMode::IsDeity) the function checks whether the engine is currently buildable by all companies (no exclusive preview).
* @param engine_id The engine to check.
* @return True if and only if the engine type is buildable.
*/
@@ -44,7 +44,7 @@ public:
* @pre IsValidEngine(engine_id).
* @return The name the engine has.
*/
static char *GetName(EngineID engine_id);
static std::optional<std::string> GetName(EngineID engine_id);
/**
* Get the cargo-type of an engine. In case it can transport multiple cargoes, it
@@ -89,7 +89,7 @@ public:
* @pre IsValidEngine(engine_id).
* @return The capacity of the engine.
*/
static int32 GetCapacity(EngineID engine_id);
static SQInteger GetCapacity(EngineID engine_id);
/**
* Get the reliability of an engine. The value is between 0 and 100, where
@@ -100,7 +100,7 @@ public:
* @pre GetVehicleType(engine_id) != ScriptVehicle::VT_TRAIN || !IsWagon(engine_id).
* @return The reliability the engine has.
*/
static int32 GetReliability(EngineID engine_id);
static SQInteger GetReliability(EngineID engine_id);
/**
* Get the maximum speed of an engine.
@@ -111,7 +111,7 @@ public:
* This is mph / 1.6, which is roughly km/h.
* To get km/h multiply this number by 1.00584.
*/
static int32 GetMaxSpeed(EngineID engine_id);
static SQInteger GetMaxSpeed(EngineID engine_id);
/**
* Get the new cost of an engine.
@@ -128,7 +128,7 @@ public:
* @returns The maximum age of a new engine in days.
* @note Age is in days; divide by 366 to get per year.
*/
static int32 GetMaxAge(EngineID engine_id);
static SQInteger GetMaxAge(EngineID engine_id);
/**
* Get the running cost of an engine.
@@ -146,7 +146,7 @@ public:
* @pre (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL || GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD) && !IsWagon(engine_id).
* @return The power of the engine in hp.
*/
static int32 GetPower(EngineID engine_id);
static SQInteger GetPower(EngineID engine_id);
/**
* Get the weight of an engine.
@@ -155,7 +155,7 @@ public:
* @pre (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL || GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD).
* @return The weight of the engine in metric tons.
*/
static int32 GetWeight(EngineID engine_id);
static SQInteger GetWeight(EngineID engine_id);
/**
* Get the maximum tractive effort of an engine.
@@ -164,7 +164,7 @@ public:
* @pre (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL || GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD) && !IsWagon(engine_id).
* @return The maximum tractive effort of the engine in kN.
*/
static int32 GetMaxTractiveEffort(EngineID engine_id);
static SQInteger GetMaxTractiveEffort(EngineID engine_id);
/**
* Get the date this engine was designed.
@@ -286,7 +286,7 @@ public:
* not be compared with map distances
* @see ScriptOrder::GetOrderDistance
*/
static uint GetMaximumOrderDistance(EngineID engine_id);
static SQInteger GetMaximumOrderDistance(EngineID engine_id);
/**
* Allows a company to use an engine before its intro date or after retirement.

View File

@@ -15,7 +15,10 @@
ScriptEngineList::ScriptEngineList(ScriptVehicle::VehicleType vehicle_type)
{
EnforceDeityOrCompanyModeValid_Void();
bool is_deity = ScriptCompanyMode::IsDeity();
CompanyID owner = ScriptObject::GetCompany();
for (const Engine *e : Engine::IterateType((::VehicleType)vehicle_type)) {
if (ScriptObject::GetCompany() == OWNER_DEITY || HasBit(e->company_avail, ScriptObject::GetCompany())) this->AddItem(e->index);
if (is_deity || HasBit(e->company_avail, owner)) this->AddItem(e->index);
}
}

View File

@@ -23,9 +23,9 @@ ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::S
return ScriptObject::GetLastError();
}
/* static */ char *ScriptError::GetLastErrorString()
/* static */ std::optional<std::string> ScriptError::GetLastErrorString()
{
return stredup((*error_map_string.find(ScriptError::GetLastError())).second);
return (*error_map_string.find(ScriptError::GetLastError())).second;
}
/* static */ ScriptErrorType ScriptError::StringToError(StringID internal_string_id)
@@ -38,7 +38,7 @@ ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::S
case TEXT_TAB_SPECIAL:
if (index < 0xE4) break; // Player name
FALLTHROUGH;
[[fallthrough]];
case TEXT_TAB_TOWN:
if (index < 0xC0) break; // Town name

View File

@@ -11,7 +11,7 @@
#define SCRIPT_ERROR_HPP
#include "script_object.hpp"
#include <map>
#include "script_companymode.hpp"
/**
* Helper to write precondition enforcers for the script API in an abbreviated manner.
@@ -42,15 +42,51 @@
* @param string The string that is checked.
*/
#define EnforcePreconditionEncodedText(returnval, string) \
if ((string) == nullptr) { \
ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS); \
return returnval; \
} \
if (StrEmpty(string)) { \
if (string.empty()) { \
ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED); \
return returnval; \
}
/**
* Helper to enforce the precondition that the company mode is valid.
* @param returnval The value to return on failure.
*/
#define EnforceCompanyModeValid(returnval) \
EnforcePreconditionCustomError(returnval, ScriptCompanyMode::IsValid(), ScriptError::ERR_PRECONDITION_INVALID_COMPANY)
/**
* Helper to enforce the precondition that the company mode is valid.
*/
#define EnforceCompanyModeValid_Void() \
if (!ScriptCompanyMode::IsValid()) { \
ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY); \
return; \
}
/**
* Helper to enforce the precondition that we are in a deity mode.
* @param returnval The value to return on failure.
*/
#define EnforceDeityMode(returnval) \
EnforcePreconditionCustomError(returnval, ScriptCompanyMode::IsDeity(), ScriptError::ERR_PRECONDITION_INVALID_COMPANY)
/**
* Helper to enforce the precondition that the company mode is valid or that we are a deity.
* @param returnval The value to return on failure.
*/
#define EnforceDeityOrCompanyModeValid(returnval) \
EnforcePreconditionCustomError(returnval, ScriptCompanyMode::IsDeity() || ScriptCompanyMode::IsValid(), ScriptError::ERR_PRECONDITION_INVALID_COMPANY)
/**
* Helper to enforce the precondition that the company mode is valid or that we are a deity.
*/
#define EnforceDeityOrCompanyModeValid_Void() \
if (!(ScriptCompanyMode::IsDeity() || ScriptCompanyMode::IsValid())) { \
ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY); \
return; \
}
/**
* Class that handles all error related functions.
* @api ai game
@@ -94,8 +130,6 @@ public:
ERR_PRECONDITION_FAILED, // []
/** A string supplied was too long */
ERR_PRECONDITION_STRING_TOO_LONG, // []
/** A string had too many parameters */
ERR_PRECONDITION_TOO_MANY_PARAMETERS, // []
/** The company you use is invalid */
ERR_PRECONDITION_INVALID_COMPANY, // []
/** An error returned by a NewGRF. No possibility to get the exact error in an script readable format */
@@ -158,7 +192,7 @@ public:
* Get the last error in string format (for human readability).
* @return An ErrorMessage enum item, as string.
*/
static char *GetLastErrorString();
static std::optional<std::string> GetLastErrorString();
/**
* Get the error based on the OpenTTD StringID.

View File

@@ -18,6 +18,7 @@
#include "../../string_func.h"
#include "../../economy_cmd.h"
#include "../../engine_cmd.h"
#include "../../3rdparty/nlohmann/json.hpp"
#include "table/strings.h"
#include "../../safeguards.h"
@@ -28,9 +29,9 @@ bool ScriptEventEnginePreview::IsEngineValid() const
return e != nullptr && e->IsEnabled();
}
char *ScriptEventEnginePreview::GetName()
std::optional<std::string> ScriptEventEnginePreview::GetName()
{
if (!this->IsEngineValid()) return nullptr;
if (!this->IsEngineValid()) return std::nullopt;
::SetDParam(0, this->engine);
return GetString(STR_ENGINE_NAME);
@@ -38,22 +39,16 @@ char *ScriptEventEnginePreview::GetName()
CargoID ScriptEventEnginePreview::GetCargoType()
{
if (!this->IsEngineValid()) return CT_INVALID;
if (!this->IsEngineValid()) return INVALID_CARGO;
CargoArray cap = ::GetCapacityOfArticulatedParts(this->engine);
CargoID most_cargo = CT_INVALID;
uint amount = 0;
for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
if (cap[cid] > amount) {
amount = cap[cid];
most_cargo = cid;
}
}
auto it = std::max_element(std::cbegin(cap), std::cend(cap));
if (*it == 0) return INVALID_CARGO;
return most_cargo;
return CargoID(std::distance(std::cbegin(cap), it));
}
int32 ScriptEventEnginePreview::GetCapacity()
int32_t ScriptEventEnginePreview::GetCapacity()
{
if (!this->IsEngineValid()) return -1;
const Engine *e = ::Engine::Get(this->engine);
@@ -61,9 +56,8 @@ int32 ScriptEventEnginePreview::GetCapacity()
case VEH_ROAD:
case VEH_TRAIN: {
CargoArray capacities = GetCapacityOfArticulatedParts(this->engine);
for (CargoID c = 0; c < NUM_CARGO; c++) {
if (capacities[c] == 0) continue;
return capacities[c];
for (uint &cap : capacities) {
if (cap != 0) return cap;
}
return -1;
}
@@ -76,11 +70,11 @@ int32 ScriptEventEnginePreview::GetCapacity()
}
}
int32 ScriptEventEnginePreview::GetMaxSpeed()
int32_t ScriptEventEnginePreview::GetMaxSpeed()
{
if (!this->IsEngineValid()) return -1;
const Engine *e = ::Engine::Get(this->engine);
int32 max_speed = e->GetDisplayMaxSpeed(); // km-ish/h
int32_t max_speed = e->GetDisplayMaxSpeed(); // km-ish/h
if (e->type == VEH_AIRCRAFT) max_speed /= _settings_game.vehicle.plane_speed;
return max_speed;
}
@@ -97,7 +91,7 @@ Money ScriptEventEnginePreview::GetRunningCost()
return ::Engine::Get(this->engine)->GetRunningCost();
}
int32 ScriptEventEnginePreview::GetVehicleType()
int32_t ScriptEventEnginePreview::GetVehicleType()
{
if (!this->IsEngineValid()) return ScriptVehicle::VT_INVALID;
switch (::Engine::Get(this->engine)->type) {
@@ -111,13 +105,15 @@ int32 ScriptEventEnginePreview::GetVehicleType()
bool ScriptEventEnginePreview::AcceptPreview()
{
EnforceCompanyModeValid(false);
if (!this->IsEngineValid()) return false;
return ScriptObject::Command<CMD_WANT_ENGINE_PREVIEW>::Do(this->engine);
}
bool ScriptEventCompanyAskMerger::AcceptMerger()
{
return ScriptObject::Command<CMD_BUY_COMPANY>::Do((::CompanyID)this->owner);
EnforceCompanyModeValid(false);
return ScriptObject::Command<CMD_BUY_COMPANY>::Do((::CompanyID)this->owner, false);
}
ScriptEventAdminPort::ScriptEventAdminPort(const std::string &json) :
@@ -125,193 +121,89 @@ ScriptEventAdminPort::ScriptEventAdminPort(const std::string &json) :
json(json)
{
}
/**
* Convert a JSON part fo Squirrel.
* @param vm The VM used.
* @param json The JSON part to convert to Squirrel.
*/
static bool ScriptEventAdminPortReadValue(HSQUIRRELVM vm, nlohmann::json &json)
{
switch (json.type()) {
case nlohmann::json::value_t::null:
sq_pushnull(vm);
break;
#define SKIP_EMPTY(p) while (*(p) == ' ' || *(p) == '\n' || *(p) == '\r') (p)++;
#define RETURN_ERROR(stack) { ScriptLog::Error("Received invalid JSON data from AdminPort."); if (stack != 0) sq_pop(vm, stack); return nullptr; }
case nlohmann::json::value_t::boolean:
sq_pushbool(vm, json.get<bool>() ? 1 : 0);
break;
case nlohmann::json::value_t::string: {
auto value = json.get<std::string>();
sq_pushstring(vm, value.data(), value.size());
break;
}
case nlohmann::json::value_t::number_integer:
case nlohmann::json::value_t::number_unsigned:
sq_pushinteger(vm, json.get<int64_t>());
break;
case nlohmann::json::value_t::object:
sq_newtable(vm);
for (auto &[key, value] : json.items()) {
sq_pushstring(vm, key.data(), key.size());
if (!ScriptEventAdminPortReadValue(vm, value)) {
return false;
}
sq_rawset(vm, -3);
}
break;
case nlohmann::json::value_t::array:
sq_newarray(vm, 0);
for (auto &value : json) {
if (!ScriptEventAdminPortReadValue(vm, value)) {
return false;
}
sq_arrayappend(vm, -2);
}
break;
/* These types are not supported by Squirrel. */
case nlohmann::json::value_t::number_float:
default:
return false;
}
return true;
}
SQInteger ScriptEventAdminPort::GetObject(HSQUIRRELVM vm)
{
const char *p = this->json.c_str();
auto json = nlohmann::json::parse(this->json, nullptr, false);
if (!json.is_object()) {
ScriptLog::Error("The root element in the JSON data from AdminPort has to be an object.");
sq_pushnull(vm);
return 1;
}
auto top = sq_gettop(vm);
if (!ScriptEventAdminPortReadValue(vm, json)) {
/* Rewind the stack, removing anything that might be left on top. */
sq_settop(vm, top);
ScriptLog::Error("Received invalid JSON data from AdminPort.");
if (this->ReadTable(vm, p) == nullptr) {
sq_pushnull(vm);
return 1;
}
return 1;
}
const char *ScriptEventAdminPort::ReadString(HSQUIRRELVM vm, const char *p)
{
const char *value = p;
bool escape = false;
for (;;) {
if (*p == '\\') {
escape = true;
p++;
continue;
}
if (*p == '"' && escape) {
escape = false;
p++;
continue;
}
escape = false;
if (*p == '"') break;
if (*p == '\0') RETURN_ERROR(0);
p++;
}
size_t len = p - value;
sq_pushstring(vm, value, len);
p++; // Step past the end-of-string marker (")
return p;
}
const char *ScriptEventAdminPort::ReadTable(HSQUIRRELVM vm, const char *p)
{
sq_newtable(vm);
SKIP_EMPTY(p);
if (*p++ != '{') RETURN_ERROR(1);
for (;;) {
SKIP_EMPTY(p);
if (*p++ != '"') RETURN_ERROR(1);
p = ReadString(vm, p);
if (p == nullptr) {
sq_pop(vm, 1);
return nullptr;
}
SKIP_EMPTY(p);
if (*p++ != ':') RETURN_ERROR(2);
p = this->ReadValue(vm, p);
if (p == nullptr) {
sq_pop(vm, 2);
return nullptr;
}
sq_rawset(vm, -3);
/* The key (-2) and value (-1) are popped from the stack by squirrel. */
SKIP_EMPTY(p);
if (*p == ',') {
p++;
continue;
}
break;
}
SKIP_EMPTY(p);
if (*p++ != '}') RETURN_ERROR(1);
return p;
}
const char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, const char *p)
{
SKIP_EMPTY(p);
if (strncmp(p, "false", 5) == 0) {
sq_pushinteger(vm, 0);
return p + 5;
}
if (strncmp(p, "true", 4) == 0) {
sq_pushinteger(vm, 1);
return p + 4;
}
if (strncmp(p, "null", 4) == 0) {
sq_pushnull(vm);
return p + 4;
}
switch (*p) {
case '"': {
/* String */
p = ReadString(vm, ++p);
if (p == nullptr) return nullptr;
break;
}
case '{': {
/* Table */
p = this->ReadTable(vm, p);
if (p == nullptr) return nullptr;
break;
}
case '[': {
/* Array */
sq_newarray(vm, 0);
/* Empty array? */
const char *p2 = p + 1;
SKIP_EMPTY(p2);
if (*p2 == ']') {
p = p2 + 1;
break;
}
while (*p++ != ']') {
p = this->ReadValue(vm, p);
if (p == nullptr) {
sq_pop(vm, 1);
return nullptr;
}
sq_arrayappend(vm, -2);
SKIP_EMPTY(p);
if (*p == ',') continue;
if (*p == ']') break;
RETURN_ERROR(1);
}
p++;
break;
}
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
case '-': {
/* Integer */
const char *value = p++;
for (;;) {
switch (*p++) {
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9': case '0':
continue;
default:
break;
}
p--;
break;
}
int res = atoi(value);
sq_pushinteger(vm, (SQInteger)res);
break;
}
default:
RETURN_ERROR(0);
}
return p;
}
#undef SKIP_EMPTY
#undef RETURN_ERROR

View File

@@ -239,7 +239,7 @@ public:
* Get the name of the offered engine.
* @return The name the engine has.
*/
char *GetName();
std::optional<std::string> GetName();
/**
* Get the cargo-type of the offered engine. In case it can transport multiple cargoes, it
@@ -253,7 +253,7 @@ public:
* returns the first/main.
* @return The capacity of the engine.
*/
int32 GetCapacity();
int32_t GetCapacity();
/**
* Get the maximum speed of the offered engine.
@@ -262,7 +262,7 @@ public:
* This is mph / 1.6, which is roughly km/h.
* To get km/h multiply this number by 1.00584.
*/
int32 GetMaxSpeed();
int32_t GetMaxSpeed();
/**
* Get the new cost of the offered engine.
@@ -284,11 +284,12 @@ public:
#ifdef DOXYGEN_API
ScriptVehicle::VehicleType GetVehicleType();
#else
int32 GetVehicleType();
int32_t GetVehicleType();
#endif /* DOXYGEN_API */
/**
* Accept the engine preview.
* @game @pre ScriptCompanyMode::IsValid().
* @return True when the accepting succeeded.
*/
bool AcceptPreview();
@@ -381,7 +382,7 @@ public:
* @param owner The company that can be bought.
* @param value The value/costs of buying the company.
*/
ScriptEventCompanyAskMerger(Owner owner, int32 value) :
ScriptEventCompanyAskMerger(Owner owner, Money value) :
ScriptEvent(ET_COMPANY_ASK_MERGER),
owner((ScriptCompany::CompanyID)owner),
value(value)
@@ -406,17 +407,18 @@ public:
* Get the value of the new company.
* @return The value of the new company.
*/
int32 GetValue() { return this->value; }
Money GetValue() { return this->value; }
/**
* Take over the company for this merger.
* @game @pre ScriptCompanyMode::IsValid().
* @return true if the merger was a success.
*/
bool AcceptMerger();
private:
ScriptCompany::CompanyID owner; ///< The company that is in trouble.
int32 value; ///< The value of the company, i.e. the amount you would pay.
Money value; ///< The value of the company, i.e. the amount you would pay.
};
/**
@@ -908,27 +910,6 @@ public:
private:
std::string json; ///< The JSON string.
/**
* Read a table from a JSON string.
* @param vm The VM used.
* @param p The (part of the) JSON string reading.
*/
const char *ReadTable(HSQUIRRELVM vm, const char *p);
/**
* Read a value from a JSON string.
* @param vm The VM used.
* @param p The (part of the) JSON string reading.
*/
const char *ReadValue(HSQUIRRELVM vm, const char *p);
/**
* Read a string from a JSON string.
* @param vm The VM used.
* @param p The (part of the) JSON string reading.
*/
const char *ReadString(HSQUIRRELVM vm, const char *p);
};
/**
@@ -943,7 +924,7 @@ public:
* @param number The windownumber that was clicked.
* @param widget The widget in the window that was clicked.
*/
ScriptEventWindowWidgetClick(ScriptWindow::WindowClass window, uint32 number, uint8 widget) :
ScriptEventWindowWidgetClick(ScriptWindow::WindowClass window, uint32_t number, WidgetID widget) :
ScriptEvent(ET_WINDOW_WIDGET_CLICK),
window(window),
number(number),
@@ -968,18 +949,18 @@ public:
* Get the number of the window that was clicked.
* @return The clicked identifying number of the widget within the class.
*/
uint32 GetWindowNumber() { return this->number; }
uint32_t GetWindowNumber() { return this->number; }
/**
* Get the number of the widget that was clicked.
* @return The number of the clicked widget.
*/
uint8 GetWidgetNumber() { return this->widget; }
int GetWidgetNumber() { return this->widget; }
private:
ScriptWindow::WindowClass window; ///< Window of the click.
uint32 number; ///< Number of the click.
uint8 widget; ///< Widget of the click.
uint32_t number; ///< Number of the click.
WidgetID widget; ///< Widget of the click.
};
/**
@@ -996,7 +977,7 @@ public:
* @param company The company that is replying.
* @param button The button the company pressed.
*/
ScriptEventGoalQuestionAnswer(uint16 uniqueid, ScriptCompany::CompanyID company, ScriptGoal::QuestionButton button) :
ScriptEventGoalQuestionAnswer(uint16_t uniqueid, ScriptCompany::CompanyID company, ScriptGoal::QuestionButton button) :
ScriptEvent(ET_GOAL_QUESTION_ANSWER),
uniqueid(uniqueid),
company(company),
@@ -1015,7 +996,7 @@ public:
* Get the unique id of the question.
* @return The unique id.
*/
uint16 GetUniqueID() { return this->uniqueid; }
uint16_t GetUniqueID() { return this->uniqueid; }
/**
* Get the company that pressed a button.
@@ -1030,7 +1011,7 @@ public:
ScriptGoal::QuestionButton GetButton() { return this->button; }
private:
uint16 uniqueid; ///< The uniqueid of the question.
uint16_t uniqueid; ///< The uniqueid of the question.
ScriptCompany::CompanyID company; ///< The company given the answer.
ScriptGoal::QuestionButton button; ///< The button that was pressed.
};

View File

@@ -31,8 +31,8 @@ ScriptExecMode::ScriptExecMode()
void ScriptExecMode::FinalRelease()
{
if (this->GetDoCommandModeInstance() != this) {
/* Ignore this error if the script already died. */
if (!ScriptObject::GetActiveInstance()->IsDead()) {
/* Ignore this error if the script is not alive. */
if (ScriptObject::GetActiveInstance()->IsAlive()) {
throw Script_FatalError("ScriptExecMode object was removed while it was not the latest *Mode object created.");
}
}

View File

@@ -48,7 +48,7 @@ public:
/**
* @api -all
*/
virtual void FinalRelease();
void FinalRelease() override;
};
#endif /* SCRIPT_EXECMODE_HPP */

View File

@@ -9,6 +9,7 @@
#include "../../stdafx.h"
#include "script_game.hpp"
#include "script_error.hpp"
#include "../../command_type.h"
#include "../../settings_type.h"
#include "../../network/network.h"

View File

@@ -16,28 +16,33 @@
#include "../../safeguards.h"
/* static */ bool ScriptGameSettings::IsValid(const char *setting)
/* static */ bool ScriptGameSettings::IsValid(const std::string &setting)
{
const SettingDesc *sd = GetSettingFromName(setting);
return sd != nullptr && sd->IsIntSetting();
}
/* static */ int32 ScriptGameSettings::GetValue(const char *setting)
/* static */ SQInteger ScriptGameSettings::GetValue(const std::string &setting)
{
if (!IsValid(setting)) return -1;
const SettingDesc *sd = GetSettingFromName(setting);
assert(sd != nullptr);
return sd->AsIntSetting()->Read(&_settings_game);
}
/* static */ bool ScriptGameSettings::SetValue(const char *setting, int value)
/* static */ bool ScriptGameSettings::SetValue(const std::string &setting, SQInteger value)
{
EnforceDeityOrCompanyModeValid(false);
if (!IsValid(setting)) return false;
const SettingDesc *sd = GetSettingFromName(setting);
assert(sd != nullptr);
if ((sd->flags & SF_NO_NETWORK_SYNC) != 0) return false;
value = Clamp<SQInteger>(value, INT32_MIN, INT32_MAX);
return ScriptObject::Command<CMD_CHANGE_SETTING>::Do(sd->GetName(), value);
}

View File

@@ -44,7 +44,7 @@ public:
* @note Results achieved in the past offer no guarantee for the future.
* @return True if and only if the setting is valid.
*/
static bool IsValid(const char *setting);
static bool IsValid(const std::string &setting);
/**
* Gets the value of the game setting.
@@ -57,24 +57,24 @@ public:
* @note Results achieved in the past offer no guarantee for the future.
* @return The value for the setting.
*/
static int32 GetValue(const char *setting);
static SQInteger GetValue(const std::string &setting);
/**
* Sets the value of the game setting.
* @param setting The setting to set the value of.
* @param value The value to set the setting to.
* The value will be clamped to MIN(int32_t) .. MAX(int32_t).
* @pre IsValid(setting).
* @return True if the action succeeded.
* @note Results achieved in the past offer no guarantee for the future.
* @api -ai
*/
static bool SetValue(const char *setting, int value);
static bool SetValue(const std::string &setting, SQInteger value);
/**
* Checks whether the given vehicle-type is disabled for companies.
* @param vehicle_type The vehicle-type to check.
* @return True if the vehicle-type is disabled.
* @api -game
*/
static bool IsDisabledVehicleType(ScriptVehicle::VehicleType vehicle_type);
};

View File

@@ -28,29 +28,32 @@
return ::Goal::IsValidID(goal_id);
}
/* static */ ScriptGoal::GoalID ScriptGoal::New(ScriptCompany::CompanyID company, Text *goal, GoalType type, uint32 destination)
/* static */ bool ScriptGoal::IsValidGoalDestination(ScriptCompany::CompanyID company, GoalType type, SQInteger destination)
{
CCountedPtr<Text> counter(goal);
EnforcePrecondition(GOAL_INVALID, ScriptObject::GetCompany() == OWNER_DEITY);
EnforcePrecondition(GOAL_INVALID, goal != nullptr);
const char *text = goal->GetEncodedText();
EnforcePreconditionEncodedText(GOAL_INVALID, text);
EnforcePrecondition(GOAL_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID);
CompanyID c = (::CompanyID)company;
if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
StoryPage *story_page = nullptr;
if (type == GT_STORY_PAGE && ScriptStoryPage::IsValidStoryPage((ScriptStoryPage::StoryPageID)destination)) story_page = ::StoryPage::Get((ScriptStoryPage::StoryPageID)destination);
EnforcePrecondition(GOAL_INVALID, (type == GT_NONE && destination == 0) ||
return (type == GT_NONE && destination == 0) ||
(type == GT_TILE && ScriptMap::IsValidTile(destination)) ||
(type == GT_INDUSTRY && ScriptIndustry::IsValidIndustry(destination)) ||
(type == GT_TOWN && ScriptTown::IsValidTown(destination)) ||
(type == GT_COMPANY && ScriptCompany::ResolveCompanyID((ScriptCompany::CompanyID)destination) != ScriptCompany::COMPANY_INVALID) ||
(type == GT_STORY_PAGE && story_page != nullptr && (c == INVALID_COMPANY ? story_page->company == INVALID_COMPANY : story_page->company == INVALID_COMPANY || story_page->company == c)));
(type == GT_STORY_PAGE && story_page != nullptr && (c == INVALID_COMPANY ? story_page->company == INVALID_COMPANY : story_page->company == INVALID_COMPANY || story_page->company == c));
}
if (!ScriptObject::Command<CMD_CREATE_GOAL>::Do(&ScriptInstance::DoCommandReturnGoalID, c, (::GoalType)type, destination, text)) return GOAL_INVALID;
/* static */ ScriptGoal::GoalID ScriptGoal::New(ScriptCompany::CompanyID company, Text *goal, GoalType type, SQInteger destination)
{
CCountedPtr<Text> counter(goal);
EnforceDeityMode(GOAL_INVALID);
EnforcePrecondition(GOAL_INVALID, goal != nullptr);
std::string text = goal->GetEncodedText();
EnforcePreconditionEncodedText(GOAL_INVALID, text);
EnforcePrecondition(GOAL_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID);
EnforcePrecondition(GOAL_INVALID, IsValidGoalDestination(company, type, destination));
if (!ScriptObject::Command<CMD_CREATE_GOAL>::Do(&ScriptInstance::DoCommandReturnGoalID, (::CompanyID)company, (::GoalType)type, destination, text)) return GOAL_INVALID;
/* In case of test-mode, we return GoalID 0 */
return (ScriptGoal::GoalID)0;
@@ -58,22 +61,33 @@
/* static */ bool ScriptGoal::Remove(GoalID goal_id)
{
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidGoal(goal_id));
return ScriptObject::Command<CMD_REMOVE_GOAL>::Do(goal_id);
}
/* static */ bool ScriptGoal::SetDestination(GoalID goal_id, GoalType type, SQInteger destination)
{
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidGoal(goal_id));
Goal *g = Goal::Get(goal_id);
EnforcePrecondition(false, IsValidGoalDestination((ScriptCompany::CompanyID)g->company, type, destination));
return ScriptObject::Command<CMD_SET_GOAL_DESTINATION>::Do(goal_id, (::GoalType)type, destination);
}
/* static */ bool ScriptGoal::SetText(GoalID goal_id, Text *goal)
{
CCountedPtr<Text> counter(goal);
EnforcePrecondition(false, IsValidGoal(goal_id));
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, goal != nullptr);
EnforcePrecondition(false, !StrEmpty(goal->GetEncodedText()));
std::string text = goal->GetEncodedText();
EnforcePreconditionEncodedText(false, text);
return ScriptObject::Command<CMD_SET_GOAL_TEXT>::Do(goal_id, goal->GetEncodedText());
return ScriptObject::Command<CMD_SET_GOAL_TEXT>::Do(goal_id, text);
}
/* static */ bool ScriptGoal::SetProgress(GoalID goal_id, Text *progress)
@@ -81,20 +95,15 @@
CCountedPtr<Text> counter(progress);
EnforcePrecondition(false, IsValidGoal(goal_id));
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
/* Ensure null as used for empty string. */
if (progress != nullptr && StrEmpty(progress->GetEncodedText())) {
progress = nullptr;
}
return ScriptObject::Command<CMD_SET_GOAL_PROGRESS>::Do(goal_id, progress != nullptr ? std::string{ progress->GetEncodedText() } : std::string{});
return ScriptObject::Command<CMD_SET_GOAL_PROGRESS>::Do(goal_id, progress != nullptr ? progress->GetEncodedText() : std::string{});
}
/* static */ bool ScriptGoal::SetCompleted(GoalID goal_id, bool completed)
{
EnforcePrecondition(false, IsValidGoal(goal_id));
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
return ScriptObject::Command<CMD_SET_GOAL_COMPLETED>::Do(goal_id, completed);
}
@@ -102,49 +111,49 @@
/* static */ bool ScriptGoal::IsCompleted(GoalID goal_id)
{
EnforcePrecondition(false, IsValidGoal(goal_id));
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
Goal *g = Goal::Get(goal_id);
return g != nullptr && g->completed;
}
/* static */ bool ScriptGoal::DoQuestion(uint16 uniqueid, uint32 target, bool is_client, Text *question, QuestionType type, uint32 buttons)
/* static */ bool ScriptGoal::DoQuestion(SQInteger uniqueid, uint32_t target, bool is_client, Text *question, QuestionType type, SQInteger buttons)
{
CCountedPtr<Text> counter(question);
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, question != nullptr);
const char *text = question->GetEncodedText();
std::string text = question->GetEncodedText();
EnforcePreconditionEncodedText(false, text);
uint min_buttons = (type == QT_QUESTION ? 1 : 0);
EnforcePrecondition(false, CountBits(buttons) >= min_buttons && CountBits(buttons) <= 3);
EnforcePrecondition(false, buttons < (1 << ::GOAL_QUESTION_BUTTON_COUNT));
EnforcePrecondition(false, CountBits<uint64_t>(buttons) >= min_buttons && CountBits<uint64_t>(buttons) <= 3);
EnforcePrecondition(false, buttons >= 0 && buttons < (1 << ::GOAL_QUESTION_BUTTON_COUNT));
EnforcePrecondition(false, (int)type < ::GQT_END);
EnforcePrecondition(false, uniqueid >= 0 && uniqueid <= UINT16_MAX);
return ScriptObject::Command<CMD_GOAL_QUESTION>::Do(uniqueid, target, is_client, buttons, (::GoalQuestionType)type, text);
}
/* static */ bool ScriptGoal::Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons)
/* static */ bool ScriptGoal::Question(SQInteger uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, SQInteger buttons)
{
EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID);
uint8 c = company;
uint8_t c = company;
if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
return DoQuestion(uniqueid, c, false, question, type, buttons);
}
/* static */ bool ScriptGoal::QuestionClient(uint16 uniqueid, ScriptClient::ClientID client, Text *question, QuestionType type, int buttons)
/* static */ bool ScriptGoal::QuestionClient(SQInteger uniqueid, ScriptClient::ClientID client, Text *question, QuestionType type, SQInteger buttons)
{
EnforcePrecondition(false, ScriptGame::IsMultiplayer());
EnforcePrecondition(false, ScriptClient::ResolveClientID(client) != ScriptClient::CLIENT_INVALID);
/* Can only send 16 bits of client_id before proper fix is implemented */
EnforcePrecondition(false, client < (1 << 16));
return DoQuestion(uniqueid, client, true, question, type, buttons);
}
/* static */ bool ScriptGoal::CloseQuestion(uint16 uniqueid)
/* static */ bool ScriptGoal::CloseQuestion(SQInteger uniqueid)
{
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, uniqueid >= 0 && uniqueid <= UINT16_MAX);
return ScriptObject::Command<CMD_GOAL_QUESTION_ANSWER>::Do(uniqueid, 0);
}

View File

@@ -28,9 +28,9 @@ public:
/**
* The goal IDs.
*/
enum GoalID {
enum GoalID : uint16_t {
/* Note: these values represent part of the in-game GoalID enum */
GOAL_INVALID = ::INVALID_GOALTYPE, ///< An invalid goal id.
GOAL_INVALID = ::INVALID_GOAL, ///< An invalid goal id.
};
/**
@@ -89,6 +89,15 @@ public:
*/
static bool IsValidGoal(GoalID goal_id);
/**
* Check whether this is a valid goal destination.
* @param company The relevant company if a story page is the destination.
* @param type The type of the goal.
* @param destination The destination of the \a type type.
* @return True if and only if this goal destination is valid.
*/
static bool IsValidGoalDestination(ScriptCompany::CompanyID company, GoalType type, SQInteger destination);
/**
* Create a new goal.
* @param company The company to create the goal for, or ScriptCompany::COMPANY_INVALID for all.
@@ -96,30 +105,42 @@ public:
* @param type The type of the goal.
* @param destination The destination of the \a type type.
* @return The new GoalID, or GOAL_INVALID if it failed.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre goal != null && len(goal) != 0.
* @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID.
* @pre if type is GT_STORY_PAGE, the company of the goal and the company of the story page need to match:
* \li Global goals can only reference global story pages.
* \li Company specific goals can reference global story pages and story pages of the same company.
*/
static GoalID New(ScriptCompany::CompanyID company, Text *goal, GoalType type, uint32 destination);
static GoalID New(ScriptCompany::CompanyID company, Text *goal, GoalType type, SQInteger destination);
/**
* Remove a goal from the list.
* @param goal_id The goal to remove.
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre IsValidGoal(goal_id).
*/
static bool Remove(GoalID goal_id);
/**
* Update goal destination of a goal.
* @param goal_id The goal to update.
* @param type The type of the goal.
* @param destination The destination of the \a type type.
* @return True if the action succeeded.
* @pre ScriptCompanyMode::IsDeity().
* @pre IsValidGoal(goal_id).
* @pre IsValidGoalDestination(g->company, type, destination).
*/
static bool SetDestination(GoalID goal_id, GoalType type, SQInteger destination);
/**
* Update goal text of a goal.
* @param goal_id The goal to update.
* @param goal The new goal text (can be either a raw string, or a ScriptText object).
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre goal != null && len(goal) != 0.
* @pre IsValidGoal(goal_id).
*/
@@ -134,7 +155,7 @@ public:
* or a ScriptText object). To clear the progress string you can pass null or an
* empty string.
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre IsValidGoal(goal_id).
*/
static bool SetProgress(GoalID goal_id, Text *progress);
@@ -144,7 +165,7 @@ public:
* @param goal_id The goal to update.
* @param complete The new goal completed status.
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre IsValidGoal(goal_id).
*/
static bool SetCompleted(GoalID goal_id, bool complete);
@@ -153,7 +174,7 @@ public:
* Checks if a given goal have been marked as completed.
* @param goal_id The goal to check complete status.
* @return True if the goal is completed, otherwise false.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre IsValidGoal(goal_id).
*/
static bool IsCompleted(GoalID goal_id);
@@ -166,14 +187,15 @@ public:
* @param type The type of question that is being asked.
* @param buttons Any combinations (at least 1, up to 3) of buttons defined in QuestionButton. Like BUTTON_YES + BUTTON_NO.
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre question != null && len(question) != 0.
* @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID.
* @pre CountBits(buttons) >= 1 && CountBits(buttons) <= 3.
* @note Replies to the question are given by you via the event ScriptEvent_GoalQuestionAnswer.
* @pre uniqueid >= 0 && uniqueid <= MAX(uint16_t)
* @note Replies to the question are given by you via the event ScriptEventGoalQuestionAnswer.
* @note There is no guarantee you ever get a reply on your question.
*/
static bool Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons);
static bool Question(SQInteger uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, SQInteger buttons);
/**
* Ask client a question.
@@ -183,33 +205,35 @@ public:
* @param type The type of question that is being asked.
* @param buttons Any combinations (at least 1, up to 3) of buttons defined in QuestionButton. Like BUTTON_YES + BUTTON_NO.
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre ScriptGame::IsMultiplayer()
* @pre question != null && len(question) != 0.
* @pre ResolveClientID(client) != CLIENT_INVALID.
* @pre CountBits(buttons) >= 1 && CountBits(buttons) <= 3.
* @note Replies to the question are given by you via the event ScriptEvent_GoalQuestionAnswer.
* @pre uniqueid >= 0 && uniqueid <= MAX(uint16_t)
* @note Replies to the question are given by you via the event ScriptEventGoalQuestionAnswer.
* @note There is no guarantee you ever get a reply on your question.
*/
static bool QuestionClient(uint16 uniqueid, ScriptClient::ClientID client, Text *question, QuestionType type, int buttons);
static bool QuestionClient(SQInteger uniqueid, ScriptClient::ClientID client, Text *question, QuestionType type, SQInteger buttons);
/**
* Close the question on all clients.
* @param uniqueid The uniqueid of the question you want to close.
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @pre uniqueid >= 0 && uniqueid <= MAX(uint16_t)
* @note If you send a question to a single company, and get a reply for them,
* the question is already closed on all clients. Only use this function if
* you want to timeout a question, or if you send the question to all
* companies, but you are only interested in the reply of the first.
*/
static bool CloseQuestion(uint16 uniqueid);
static bool CloseQuestion(SQInteger uniqueid);
protected:
/**
* Does common checks and asks the question.
*/
static bool DoQuestion(uint16 uniqueid, uint32 target, bool is_client, Text *question, QuestionType type, uint32 buttons);
static bool DoQuestion(SQInteger uniqueid, uint32_t target, bool is_client, Text *question, QuestionType type, SQInteger buttons);
};
#endif /* SCRIPT_GOAL_HPP */

View File

@@ -25,12 +25,14 @@
/* static */ bool ScriptGroup::IsValidGroup(GroupID group_id)
{
EnforceDeityOrCompanyModeValid(false);
const Group *g = ::Group::GetIfValid(group_id);
return g != nullptr && g->owner == ScriptObject::GetCompany();
}
/* static */ ScriptGroup::GroupID ScriptGroup::CreateGroup(ScriptVehicle::VehicleType vehicle_type, GroupID parent_group_id)
{
EnforceCompanyModeValid(GROUP_INVALID);
if (!ScriptObject::Command<CMD_CREATE_GROUP>::Do(&ScriptInstance::DoCommandReturnGroupID, (::VehicleType)vehicle_type, parent_group_id)) return GROUP_INVALID;
/* In case of test-mode, we return GroupID 0 */
@@ -39,6 +41,7 @@
/* static */ bool ScriptGroup::DeleteGroup(GroupID group_id)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id));
return ScriptObject::Command<CMD_DELETE_GROUP>::Do(group_id);
@@ -55,18 +58,19 @@
{
CCountedPtr<Text> counter(name);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id));
EnforcePrecondition(false, name != nullptr);
const char *text = name->GetDecodedText();
const std::string &text = name->GetDecodedText();
EnforcePreconditionEncodedText(false, text);
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_GROUP_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
return ScriptObject::Command<CMD_ALTER_GROUP>::Do(AlterGroupMode::Rename, group_id, 0, text);
}
/* static */ char *ScriptGroup::GetName(GroupID group_id)
/* static */ std::optional<std::string> ScriptGroup::GetName(GroupID group_id)
{
if (!IsValidGroup(group_id)) return nullptr;
if (!IsValidGroup(group_id)) return std::nullopt;
::SetDParam(0, group_id);
return GetString(STR_GROUP_NAME);
@@ -74,6 +78,7 @@
/* static */ bool ScriptGroup::SetParent(GroupID group_id, GroupID parent_group_id)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id));
EnforcePrecondition(false, IsValidGroup(parent_group_id));
@@ -90,6 +95,7 @@
/* static */ bool ScriptGroup::EnableAutoReplaceProtection(GroupID group_id, bool enable)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id));
return ScriptObject::Command<CMD_SET_GROUP_FLAG>::Do(group_id, GroupFlags::GF_REPLACE_PROTECTION, enable, false);
@@ -102,15 +108,17 @@
return HasBit(::Group::Get(group_id)->flags, GroupFlags::GF_REPLACE_PROTECTION);
}
/* static */ int32 ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id)
/* static */ SQInteger ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id)
{
EnforceCompanyModeValid(-1);
if (!IsValidGroup(group_id) && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return -1;
return GetGroupNumEngines(ScriptObject::GetCompany(), group_id, engine_id);
}
/* static */ int32 ScriptGroup::GetNumVehicles(GroupID group_id, ScriptVehicle::VehicleType vehicle_type)
/* static */ SQInteger ScriptGroup::GetNumVehicles(GroupID group_id, ScriptVehicle::VehicleType vehicle_type)
{
EnforceCompanyModeValid(-1);
bool valid_group = IsValidGroup(group_id);
if (!valid_group && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return -1;
if (!valid_group && (vehicle_type < ScriptVehicle::VT_RAIL || vehicle_type > ScriptVehicle::VT_AIR)) return -1;
@@ -120,14 +128,16 @@
/* static */ bool ScriptGroup::MoveVehicle(GroupID group_id, VehicleID vehicle_id)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT);
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
return ScriptObject::Command<CMD_ADD_VEHICLE_GROUP>::Do(group_id, vehicle_id, false);
return ScriptObject::Command<CMD_ADD_VEHICLE_GROUP>::Do(group_id, vehicle_id, false, VehicleListIdentifier{});
}
/* static */ bool ScriptGroup::EnableWagonRemoval(bool enable_removal)
{
EnforceCompanyModeValid(false);
if (HasWagonRemoval() == enable_removal) return true;
return ScriptObject::Command<CMD_CHANGE_COMPANY_SETTING>::Do("company.renew_keep_length", enable_removal ? 1 : 0);
@@ -135,11 +145,13 @@
/* static */ bool ScriptGroup::HasWagonRemoval()
{
EnforceCompanyModeValid(false);
return ::Company::Get(ScriptObject::GetCompany())->settings.renew_keep_length;
}
/* static */ bool ScriptGroup::SetAutoReplace(GroupID group_id, EngineID engine_id_old, EngineID engine_id_new)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL);
EnforcePrecondition(false, ScriptEngine::IsBuildable(engine_id_new));
@@ -148,6 +160,7 @@
/* static */ EngineID ScriptGroup::GetEngineReplacement(GroupID group_id, EngineID engine_id)
{
EnforceCompanyModeValid(::INVALID_ENGINE);
if (!IsValidGroup(group_id) && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return ::INVALID_ENGINE;
return ::EngineReplacementForCompany(Company::Get(ScriptObject::GetCompany()), engine_id, group_id);
@@ -155,6 +168,7 @@
/* static */ bool ScriptGroup::StopAutoReplace(GroupID group_id, EngineID engine_id)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL);
return ScriptObject::Command<CMD_SET_AUTOREPLACE>::Do(group_id, engine_id, ::INVALID_ENGINE, false);
@@ -183,12 +197,12 @@
return ::Group::Get(group_id)->statistics.profit_last_year;
}
/* static */ uint32 ScriptGroup::GetCurrentUsage(GroupID group_id)
/* static */ SQInteger ScriptGroup::GetCurrentUsage(GroupID group_id)
{
if (!IsValidGroup(group_id)) return -1;
uint32 occupancy = 0;
uint32 vehicle_count = 0;
uint32_t occupancy = 0;
uint32_t vehicle_count = 0;
for (const Vehicle *v : Vehicle::Iterate()) {
if (v->group_id != group_id) continue;
@@ -205,6 +219,7 @@
/* static */ bool ScriptGroup::SetPrimaryColour(GroupID group_id, ScriptCompany::Colours colour)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id));
return ScriptObject::Command<CMD_SET_GROUP_LIVERY>::Do(group_id, true, (::Colours)colour);
@@ -212,6 +227,7 @@
/* static */ bool ScriptGroup::SetSecondaryColour(GroupID group_id, ScriptCompany::Colours colour)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidGroup(group_id));
return ScriptObject::Command<CMD_SET_GROUP_LIVERY>::Do(group_id, false, (::Colours)colour);

View File

@@ -15,7 +15,7 @@
/**
* Class that handles all group related functions.
* @api ai
* @api ai game
*/
class ScriptGroup : public ScriptObject {
public:
@@ -41,6 +41,7 @@ public:
* Create a new group.
* @param vehicle_type The type of vehicle to create a group for.
* @param parent_group_id The parent group id to create this group under, INVALID_GROUP for top-level.
* @game @pre ScriptCompanyMode::IsValid().
* @return The GroupID of the new group, or an invalid GroupID when
* it failed. Check the return value using IsValidGroup(). In test-mode
* 0 is returned if it was successful; any other value indicates failure.
@@ -52,6 +53,7 @@ public:
* given group will move to the GROUP_DEFAULT.
* @param group_id The group to delete.
* @pre IsValidGroup(group_id).
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and only if the group was successfully deleted.
*/
static bool DeleteGroup(GroupID group_id);
@@ -70,6 +72,7 @@ public:
* @param name The name for the group (can be either a raw string, or a ScriptText object).
* @pre IsValidGroup(group_id).
* @pre name != null && len(name) != 0
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE
* @return True if and only if the name was changed.
*/
@@ -81,7 +84,7 @@ public:
* @pre IsValidGroup(group_id).
* @return The name the group has.
*/
static char *GetName(GroupID group_id);
static std::optional<std::string> GetName(GroupID group_id);
/**
* Set parent group of a group.
@@ -89,6 +92,7 @@ public:
* @param parent_group_id The parent group to set.
* @pre IsValidGroup(group_id).
* @pre IsValidGroup(parent_group_id).
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and only if the parent group was changed.
*/
static bool SetParent(GroupID group_id, GroupID parent_group_id);
@@ -107,6 +111,7 @@ public:
* @param group_id The group to change the protection for.
* @param enable True if protection should be enabled.
* @pre IsValidGroup(group_id).
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and only if the protection was successfully changed.
*/
static bool EnableAutoReplaceProtection(GroupID group_id, bool enable);
@@ -124,9 +129,10 @@ public:
* @param group_id The group to get the number of engines in.
* @param engine_id The engine id to count.
* @pre IsValidGroup(group_id) || group_id == GROUP_ALL || group_id == GROUP_DEFAULT.
* @game @pre ScriptCompanyMode::IsValid().
* @return The number of engines with id engine_id in the group with id group_id.
*/
static int32 GetNumEngines(GroupID group_id, EngineID engine_id);
static SQInteger GetNumEngines(GroupID group_id, EngineID engine_id);
/**
* Get the total number of vehicles in a given group and its sub-groups.
@@ -135,19 +141,21 @@ public:
* @pre IsValidGroup(group_id) || group_id == GROUP_ALL || group_id == GROUP_DEFAULT.
* @pre IsValidGroup(group_id) || vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL ||
* vehicle_type == ScriptVehicle::VT_WATER || vehicle_type == ScriptVehicle::VT_AIR
* @game @pre ScriptCompanyMode::IsValid().
* @return The total number of vehicles in the group with id group_id and it's sub-groups.
* @note If the group is valid (neither GROUP_ALL nor GROUP_DEFAULT), the value of
* vehicle_type is retrieved from the group itself and not from the input value.
* But if the group is GROUP_ALL or GROUP_DEFAULT, then vehicle_type must be valid.
*/
static int32 GetNumVehicles(GroupID group_id, ScriptVehicle::VehicleType vehicle_type);
static SQInteger GetNumVehicles(GroupID group_id, ScriptVehicle::VehicleType vehicle_type);
/**
* Move a vehicle to a group.
* @param group_id The group to move the vehicle to.
* @param vehicle_id The vehicle to move to the group.
* @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and only if the vehicle was successfully moved to the group.
* @note A vehicle can be in only one group at the same time. To remove it from
* a group, move it to another or to GROUP_DEFAULT. Moving the vehicle to the
@@ -161,12 +169,14 @@ public:
* If enabled, wagons are removed from the end of the vehicle until it
* fits in the same number of tiles as it did before.
* @param keep_length If true, wagons will be removed if the new engine is longer.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and only if the value was successfully changed.
*/
static bool EnableWagonRemoval(bool keep_length);
/**
* Get the current status of wagon removal.
* @game @pre ScriptCompanyMode::IsValid().
* @return Whether or not wagon removal is enabled.
*/
static bool HasWagonRemoval();
@@ -179,6 +189,7 @@ public:
* @param engine_id_new The engine id to replace with.
* @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL.
* @pre ScriptEngine.IsBuildable(engine_id_new).
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and if the replacing was successfully started.
* @note To stop autoreplacing engine_id_old, call StopAutoReplace(group_id, engine_id_old).
*/
@@ -189,6 +200,7 @@ public:
* @param group_id The group to get the replacement from.
* @param engine_id The engine that is being replaced.
* @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL.
* @game @pre ScriptCompanyMode::IsValid().
* @return The EngineID that is replacing engine_id or an invalid EngineID
* in case engine_id is not begin replaced.
*/
@@ -199,6 +211,7 @@ public:
* @param group_id The group to stop replacing the engine in.
* @param engine_id The engine id to stop replacing with another engine.
* @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and if the replacing was successfully stopped.
*/
static bool StopAutoReplace(GroupID group_id, EngineID engine_id);
@@ -225,13 +238,14 @@ public:
* @pre IsValidGroup(group_id).
* @return The current usage of the group.
*/
static uint32 GetCurrentUsage(GroupID group_id);
static SQInteger GetCurrentUsage(GroupID group_id);
/**
* Set primary colour for a group.
* @param group_id The group id to set the colour of.
* @param colour Colour to set.
* @pre IsValidGroup(group_id).
* @game @pre ScriptCompanyMode::IsValid().
* @return True iff the colour was set successfully.
*/
static bool SetPrimaryColour(GroupID group_id, ScriptCompany::Colours colour);
@@ -241,6 +255,7 @@ public:
* @param group_id The group id to set the colour of.
* @param colour Colour to set.
* @pre IsValidGroup(group_id).
* @game @pre ScriptCompanyMode::IsValid().
* @return True iff the colour was set successfully.
*/
static bool SetSecondaryColour(GroupID group_id, ScriptCompany::Colours colour);

View File

@@ -9,13 +9,16 @@
#include "../../stdafx.h"
#include "script_grouplist.hpp"
#include "script_error.hpp"
#include "../../group.h"
#include "../../safeguards.h"
ScriptGroupList::ScriptGroupList()
ScriptGroupList::ScriptGroupList(HSQUIRRELVM vm)
{
for (const Group *g : Group::Iterate()) {
if (g->owner == ScriptObject::GetCompany()) this->AddItem(g->index);
}
EnforceCompanyModeValid_Void();
CompanyID owner = ScriptObject::GetCompany();
ScriptList::FillList<Group>(vm, this,
[owner](const Group *g) { return g->owner == owner; }
);
}

View File

@@ -15,12 +15,40 @@
/**
* Creates a list of groups of which you are the owner.
* @note Neither ScriptGroup::GROUP_ALL nor ScriptGroup::GROUP_DEFAULT is in this list.
* @api ai
* @api ai game
* @ingroup ScriptList
*/
class ScriptGroupList : public ScriptList {
public:
#ifdef DOXYGEN_API
/**
* @game @pre ScriptCompanyMode::IsValid().
*/
ScriptGroupList();
/**
* Apply a filter when building the list.
* @param filter_function The function which will be doing the filtering.
* @param params The params to give to the filters (minus the first param,
* which is always the index-value).
* @game @pre ScriptCompanyMode::IsValid().
* @note You can write your own filters and use them. Just remember that
* the first parameter should be the index-value, and it should return
* a bool.
* @note Example:
* function IsType(group_id, type)
* {
* return ScriptGroup.GetVehicleType(group_id) == type;
* }
* ScriptGroupList(IsType, ScriptVehicle.VT_ROAD);
*/
ScriptGroupList(void *filter_function, int params, ...);
#else
/**
* The constructor wrapper from Squirrel.
*/
ScriptGroupList(HSQUIRRELVM vm);
#endif /* DOXYGEN_API */
};
#endif /* SCRIPT_GROUPLIST_HPP */

View File

@@ -20,14 +20,14 @@
#include "../../station_base.h"
#include "../../newgrf_industries.h"
#include "../../industry_cmd.h"
#include "../../timer/timer_game_calendar.h"
#include "table/strings.h"
#include <numeric>
#include "../../safeguards.h"
/* static */ int32 ScriptIndustry::GetIndustryCount()
/* static */ SQInteger ScriptIndustry::GetIndustryCount()
{
return (int32)::Industry::GetNumItems();
return ::Industry::GetNumItems();
}
/* static */ bool ScriptIndustry::IsValidIndustry(IndustryID industry_id)
@@ -41,26 +41,29 @@
return ::GetIndustryIndex(tile);
}
/* static */ char *ScriptIndustry::GetName(IndustryID industry_id)
/* static */ std::optional<std::string> ScriptIndustry::GetName(IndustryID industry_id)
{
if (!IsValidIndustry(industry_id)) return nullptr;
if (!IsValidIndustry(industry_id)) return std::nullopt;
::SetDParam(0, industry_id);
return GetString(STR_INDUSTRY_NAME);
}
/* static */ ScriptDate::Date ScriptIndustry::GetConstructionDate(IndustryID industry_id)
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)i->construction_date.base();
}
/* static */ bool ScriptIndustry::SetText(IndustryID industry_id, Text *text)
{
CCountedPtr<Text> counter(text);
const char *encoded_text = nullptr;
if (text != nullptr) {
encoded_text = text->GetEncodedText();
EnforcePreconditionEncodedText(false, encoded_text);
}
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidIndustry(industry_id));
return ScriptObject::Command<CMD_INDUSTRY_CTRL>::Do(industry_id, IndustryAction::SetText, INDCTL_NONE, INVALID_OWNER, std::string{ encoded_text ? encoded_text : "" });
return ScriptObject::Command<CMD_INDUSTRY_SET_TEXT>::Do(industry_id, text != nullptr ? text->GetEncodedText() : std::string{});
}
/* static */ ScriptIndustry::CargoAcceptState ScriptIndustry::IsCargoAccepted(IndustryID industry_id, CargoID cargo_id)
@@ -70,72 +73,62 @@
Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
if (i->accepts_cargo[j] == cargo_id) {
if (IndustryTemporarilyRefusesCargo(i, cargo_id)) return CAS_TEMP_REFUSED;
return CAS_ACCEPTED;
}
}
if (!i->IsCargoAccepted(cargo_id)) return CAS_NOT_ACCEPTED;
if (IndustryTemporarilyRefusesCargo(i, cargo_id)) return CAS_TEMP_REFUSED;
return CAS_NOT_ACCEPTED;
return CAS_ACCEPTED;
}
/* static */ int32 ScriptIndustry::GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id)
/* static */ SQInteger ScriptIndustry::GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id)
{
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
Industry *ind = ::Industry::Get(industry_id);
for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
CargoID cid = ind->accepts_cargo[i];
if (cid == cargo_id) {
return ind->incoming_cargo_waiting[i];
}
}
Industry *i = ::Industry::Get(industry_id);
return -1;
auto it = i->GetCargoAccepted(cargo_id);
if (it == std::end(i->accepted)) return -1;
return it->waiting;
}
/* static */ int32 ScriptIndustry::GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id)
/* static */ SQInteger ScriptIndustry::GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id)
{
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
const Industry *i = ::Industry::Get(industry_id);
Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) return i->last_month_production[j];
}
auto it = i->GetCargoProduced(cargo_id);
if (it == std::end(i->produced)) return -1;
return -1;
return it->history[LAST_MONTH].production;
}
/* static */ int32 ScriptIndustry::GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id)
/* static */ SQInteger ScriptIndustry::GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id)
{
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
const Industry *i = ::Industry::Get(industry_id);
Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) return i->last_month_transported[j];
}
auto it = i->GetCargoProduced(cargo_id);
if (it == std::end(i->produced)) return -1;
return -1;
return it->history[LAST_MONTH].transported;
}
/* static */ int32 ScriptIndustry::GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id)
/* static */ SQInteger ScriptIndustry::GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id)
{
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
const Industry *i = ::Industry::Get(industry_id);
Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) return ::ToPercent8(i->last_month_pct_transported[j]);
}
auto it = i->GetCargoProduced(cargo_id);
if (it == std::end(i->produced)) return -1;
return -1;
return ::ToPercent8(it->history[LAST_MONTH].PctTransported());
}
/* static */ TileIndex ScriptIndustry::GetLocation(IndustryID industry_id)
@@ -145,22 +138,22 @@
return ::Industry::Get(industry_id)->location.tile;
}
/* static */ int32 ScriptIndustry::GetAmountOfStationsAround(IndustryID industry_id)
/* static */ SQInteger ScriptIndustry::GetAmountOfStationsAround(IndustryID industry_id)
{
if (!IsValidIndustry(industry_id)) return -1;
Industry *ind = ::Industry::Get(industry_id);
return (int32)ind->stations_near.size();
return ind->stations_near.size();
}
/* static */ int32 ScriptIndustry::GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile)
/* static */ SQInteger ScriptIndustry::GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile)
{
if (!IsValidIndustry(industry_id)) return -1;
return ScriptMap::DistanceManhattan(tile, GetLocation(industry_id));
}
/* static */ int32 ScriptIndustry::GetDistanceSquareToTile(IndustryID industry_id, TileIndex tile)
/* static */ SQInteger ScriptIndustry::GetDistanceSquareToTile(IndustryID industry_id, TileIndex tile)
{
if (!IsValidIndustry(industry_id)) return -1;
@@ -225,40 +218,41 @@
return ::Industry::Get(industry_id)->type;
}
int32 ScriptIndustry::GetLastProductionYear(IndustryID industry_id)
/* static */ SQInteger ScriptIndustry::GetLastProductionYear(IndustryID industry_id)
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return 0;
return i->last_prod_year;
return i->last_prod_year.base();
}
ScriptDate::Date ScriptIndustry::GetCargoLastAcceptedDate(IndustryID industry_id, CargoID cargo_type)
/* static */ ScriptDate::Date ScriptIndustry::GetCargoLastAcceptedDate(IndustryID industry_id, CargoID cargo_type)
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return ScriptDate::DATE_INVALID;
if (cargo_type == CT_INVALID) {
return (ScriptDate::Date)std::accumulate(std::begin(i->last_cargo_accepted_at), std::end(i->last_cargo_accepted_at), 0, [](Date a, Date b) { return std::max(a, b); });
if (!::IsValidCargoID(cargo_type)) {
auto it = std::max_element(std::begin(i->accepted), std::end(i->accepted), [](const auto &a, const auto &b) { return a.last_accepted < b.last_accepted; });
return (ScriptDate::Date)it->last_accepted.base();
} else {
int index = i->GetCargoAcceptedIndex(cargo_type);
if (index < 0) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)i->last_cargo_accepted_at[index];
auto it = i->GetCargoAccepted(cargo_type);
if (it == std::end(i->accepted)) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)it->last_accepted.base();
}
}
uint32 ScriptIndustry::GetControlFlags(IndustryID industry_id)
/* static */ SQInteger ScriptIndustry::GetControlFlags(IndustryID industry_id)
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return 0;
return i->ctlflags;
}
bool ScriptIndustry::SetControlFlags(IndustryID industry_id, uint32 control_flags)
/* static */ bool ScriptIndustry::SetControlFlags(IndustryID industry_id, SQInteger control_flags)
{
if (ScriptObject::GetCompany() != OWNER_DEITY) return false;
EnforceDeityMode(false);
if (!IsValidIndustry(industry_id)) return false;
return ScriptObject::Command<CMD_INDUSTRY_CTRL>::Do(industry_id, IndustryAction::SetControlFlags, (::IndustryControlFlags)control_flags & ::INDCTL_MASK, INVALID_OWNER, {});
return ScriptObject::Command<CMD_INDUSTRY_SET_FLAGS>::Do(industry_id, (::IndustryControlFlags)control_flags & ::INDCTL_MASK);
}
/* static */ ScriptCompany::CompanyID ScriptIndustry::GetExclusiveSupplier(IndustryID industry_id)
@@ -273,11 +267,12 @@ bool ScriptIndustry::SetControlFlags(IndustryID industry_id, uint32 control_flag
/* static */ bool ScriptIndustry::SetExclusiveSupplier(IndustryID industry_id, ScriptCompany::CompanyID company_id)
{
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidIndustry(industry_id));
auto company = ScriptCompany::ResolveCompanyID(company_id);
::Owner owner = (company == ScriptCompany::COMPANY_INVALID ? ::INVALID_OWNER : (::Owner)company);
return ScriptObject::Command<CMD_INDUSTRY_CTRL>::Do(industry_id, IndustryAction::SetExclusiveSupplier, INDCTL_NONE, owner, {});
return ScriptObject::Command<CMD_INDUSTRY_SET_EXCLUSIVITY>::Do(industry_id, owner, false);
}
/* static */ ScriptCompany::CompanyID ScriptIndustry::GetExclusiveConsumer(IndustryID industry_id)
@@ -292,9 +287,28 @@ bool ScriptIndustry::SetControlFlags(IndustryID industry_id, uint32 control_flag
/* static */ bool ScriptIndustry::SetExclusiveConsumer(IndustryID industry_id, ScriptCompany::CompanyID company_id)
{
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidIndustry(industry_id));
auto company = ScriptCompany::ResolveCompanyID(company_id);
::Owner owner = (company == ScriptCompany::COMPANY_INVALID ? ::INVALID_OWNER : (::Owner)company);
return ScriptObject::Command<CMD_INDUSTRY_CTRL>::Do(industry_id, IndustryAction::SetExclusiveConsumer, INDCTL_NONE, owner, {});
return ScriptObject::Command<CMD_INDUSTRY_SET_EXCLUSIVITY>::Do(industry_id, owner, true);
}
/* static */ SQInteger ScriptIndustry::GetProductionLevel(IndustryID industry_id)
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return 0;
return i->prod_level;
}
/* static */ bool ScriptIndustry::SetProductionLevel(IndustryID industry_id, SQInteger prod_level, bool show_news, Text *custom_news)
{
CCountedPtr<Text> counter(custom_news);
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidIndustry(industry_id));
EnforcePrecondition(false, prod_level >= PRODLEVEL_MINIMUM && prod_level <= PRODLEVEL_MAXIMUM);
return ScriptObject::Command<CMD_INDUSTRY_SET_PRODUCTION>::Do(industry_id, prod_level, show_news, custom_news != nullptr ? custom_news->GetEncodedText() : std::string{});
}

View File

@@ -47,6 +47,10 @@ public:
* This does not prevent a closure already announced.
*/
INDCTL_NO_CLOSURE = ::INDCTL_NO_CLOSURE,
/**
* Indicates that the production level of the industry is controlled by a game script.
*/
INDCTL_EXTERNAL_PROD_LEVEL = ::INDCTL_EXTERNAL_PROD_LEVEL,
};
/**
@@ -54,7 +58,7 @@ public:
* @return The number of industries.
* @note The maximum valid IndustryID can be higher than the value returned.
*/
static int32 GetIndustryCount();
static SQInteger GetIndustryCount();
/**
* Checks whether the given industry index is valid.
@@ -79,12 +83,22 @@ public:
* @pre IsValidIndustry(industry_id).
* @return The name of the industry.
*/
static char *GetName(IndustryID industry_id);
static std::optional<std::string> GetName(IndustryID industry_id);
/**
* Get the construction date of an industry.
* @param industry_id The index of the industry.
* @pre IsValidIndustry(industry_id).
* @return Date the industry was constructed.
* @api -ai
*/
static ScriptDate::Date GetConstructionDate(IndustryID industry_id);
/**
* Set the custom text of an industry, shown in the GUI.
* @param industry_id The industry to set the custom text of.
* @param text The text to set it to (can be either a raw string, or a ScriptText object). If null is passed, the text will be removed.
* @param text The text to set it to (can be either a raw string, or a ScriptText object). If null, or an empty string, is passed, the text will be removed.
* @pre ScriptCompanyMode::IsDeity().
* @pre IsValidIndustry(industry_id).
* @return True if the action succeeded.
* @api -ai
@@ -109,7 +123,7 @@ public:
* @pre ScriptCargo::IsValidCargo(cargo_id).
* @return The amount of cargo that is waiting for processing.
*/
static int32 GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id);
static SQInteger GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id);
/**
* Get the total last month's production of the given cargo at an industry.
@@ -119,7 +133,7 @@ public:
* @pre ScriptCargo::IsValidCargo(cargo_id).
* @return The last month's production of the given cargo for this industry.
*/
static int32 GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id);
static SQInteger GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id);
/**
* Get the total amount of cargo transported from an industry last month.
@@ -129,7 +143,7 @@ public:
* @pre ScriptCargo::IsValidCargo(cargo_id).
* @return The amount of given cargo transported from this industry last month.
*/
static int32 GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id);
static SQInteger GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id);
/**
* Get the percentage of cargo transported from an industry last month.
@@ -139,7 +153,7 @@ public:
* @pre ScriptCargo::IsValidCargo(cargo_id).
* @return The percentage of given cargo transported from this industry last month.
*/
static int32 GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id);
static SQInteger GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id);
/**
* Gets the location of the industry.
@@ -157,7 +171,7 @@ public:
* @pre IsValidIndustry(industry_id).
* @return The number of stations around an industry.
*/
static int32 GetAmountOfStationsAround(IndustryID industry_id);
static SQInteger GetAmountOfStationsAround(IndustryID industry_id);
/**
* Get the manhattan distance from the tile to the ScriptIndustry::GetLocation()
@@ -168,7 +182,7 @@ public:
* @pre ScriptMap::IsValidTile(tile).
* @return The distance between industry and tile.
*/
static int32 GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile);
static SQInteger GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile);
/**
* Get the square distance from the tile to the ScriptIndustry::GetLocation()
@@ -179,7 +193,7 @@ public:
* @pre ScriptMap::IsValidTile(tile).
* @return The distance between industry and tile.
*/
static int32 GetDistanceSquareToTile(IndustryID industry_id, TileIndex tile);
static SQInteger GetDistanceSquareToTile(IndustryID industry_id, TileIndex tile);
/**
* Is this industry built on water.
@@ -238,14 +252,14 @@ public:
* @return Year the industry last had production, 0 if error.
* @api -ai
*/
static int32 GetLastProductionYear(IndustryID industry_id);
static SQInteger GetLastProductionYear(IndustryID industry_id);
/**
* Get the last date this industry accepted any cargo delivery.
* @param industry_id The index of the industry.
* @param cargo_type The cargo to query, or CT_INVALID to query latest of all accepted cargoes.
* @param cargo_type The cargo to query, or INVALID_CARGO to query latest of all accepted cargoes.
* @pre IsValidIndustry(industry_id).
* @pre IsValidCargo(cargo_type) || cargo_type == CT_INVALID.
* @pre IsValidCargo(cargo_type) || cargo_type == INVALID_CARGO.
* @return Date the industry last received cargo from a delivery, or ScriptDate::DATE_INVALID on error.
* @api -ai
*/
@@ -258,18 +272,18 @@ public:
* @return Bit flags of the IndustryControlFlags enumeration.
* @api -ai
*/
static uint32 GetControlFlags(IndustryID industry_id);
static SQInteger GetControlFlags(IndustryID industry_id);
/**
* Change the control flags for an industry.
* @param industry_id The index of the industry.
* @param control_flags New flags as a combination of IndustryControlFlags values.
* @pre IsValidIndustry(industry_id).
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity().
* @return True if the action succeeded.
* @api -ai
*/
static bool SetControlFlags(IndustryID industry_id, uint32 control_flags);
static bool SetControlFlags(IndustryID industry_id, SQInteger control_flags);
/**
* Find out which company currently has the exclusive rights to deliver cargo to the industry.
@@ -286,6 +300,7 @@ public:
* @param industry_id The index of the industry.
* @param company_id The company to set (ScriptCompany::COMPANY_INVALID to reset).
* @pre IsValidIndustry(industry_id).
* @pre ScriptCompanyMode::IsDeity().
* @return True if the action succeeded.
* @api -ai
*/
@@ -306,11 +321,35 @@ public:
* @param industry_id The index of the industry.
* @param company_id The company to set (ScriptCompany::COMPANY_INVALID to reset).
* @pre IsValidIndustry(industry_id).
* @pre ScriptCompanyMode::IsDeity().
* @return True if the action succeeded.
* @api -ai
*/
static bool SetExclusiveConsumer(IndustryID industry_id, ScriptCompany::CompanyID company_id);
/**
* Gets the current production level of an industry.
* @param industry_id The index of the industry.
* @return The current production level of the industry.
* @api -ai
*/
static SQInteger GetProductionLevel(IndustryID industry_id);
/**
* Sets the current production level of an industry.
* @note Setting the production level automatically sets the control flag INDCTL_EXTERNAL_PROD_LEVEL if it wasn't already set.
* Normal production behaviour can be restored by clearing the control flag.
* @param industry_id The index of the industry.
* @param prod_level The production level to set.
* @param show_news If set to true and the production changed, generate a production change news message. If set to false, no news message is shown.
* @param custom_news Custom news message text to override the default news text with. Pass null to use the default text. Only used if \c show_news is set to true.
* @pre IsValidIndustry(industry_id).
* @pre ScriptCompanyMode::IsDeity().
* @pre prod_level >= 4 && prod_level <= 128.
* @return True if the action succeeded.
* @api -ai
*/
static bool SetProductionLevel(IndustryID industry_id, SQInteger prod_level, bool show_news, Text *custom_news);
};
#endif /* SCRIPT_INDUSTRY_HPP */

View File

@@ -13,27 +13,21 @@
#include "../../safeguards.h"
ScriptIndustryList::ScriptIndustryList()
ScriptIndustryList::ScriptIndustryList(HSQUIRRELVM vm)
{
for (const Industry *i : Industry::Iterate()) {
this->AddItem(i->index);
}
ScriptList::FillList<Industry>(vm, this);
}
ScriptIndustryList_CargoAccepting::ScriptIndustryList_CargoAccepting(CargoID cargo_id)
{
for (const Industry *i : Industry::Iterate()) {
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
if (i->accepts_cargo[j] == cargo_id) this->AddItem(i->index);
}
}
ScriptList::FillList<Industry>(this,
[cargo_id](const Industry *i) { return i->IsCargoAccepted(cargo_id); }
);
}
ScriptIndustryList_CargoProducing::ScriptIndustryList_CargoProducing(CargoID cargo_id)
{
for (const Industry *i : Industry::Iterate()) {
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) this->AddItem(i->index);
}
}
ScriptList::FillList<Industry>(this,
[cargo_id](const Industry *i) { return i->IsCargoProduced(cargo_id); }
);
}

View File

@@ -19,7 +19,32 @@
*/
class ScriptIndustryList : public ScriptList {
public:
#ifdef DOXYGEN_API
ScriptIndustryList();
/**
* Apply a filter when building the list.
* @param filter_function The function which will be doing the filtering.
* @param params The params to give to the filters (minus the first param,
* which is always the index-value).
* @note You can write your own filters and use them. Just remember that
* the first parameter should be the index-value, and it should return
* a bool.
* @note Example:
* ScriptIndustryList(ScriptIndustry.HasDock);
* function IsType(industry_id, type)
* {
* return ScriptIndustry.GetIndustryType(industry_id) == type;
* }
* ScriptIndustryList(IsType, 0);
*/
ScriptIndustryList(void *filter_function, int params, ...);
#else
/**
* The constructor wrapper from Squirrel.
*/
ScriptIndustryList(HSQUIRRELVM vm);
#endif /* DOXYGEN_API */
};
/**

View File

@@ -9,6 +9,7 @@
#include "../../stdafx.h"
#include "script_industrytype.hpp"
#include "script_base.hpp"
#include "script_map.hpp"
#include "script_error.hpp"
#include "../../strings_func.h"
@@ -56,9 +57,9 @@
return ::GetIndustrySpec(industry_type)->GetConstructionCost();
}
/* static */ char *ScriptIndustryType::GetName(IndustryType industry_type)
/* static */ std::optional<std::string> ScriptIndustryType::GetName(IndustryType industry_type)
{
if (!IsValidIndustryType(industry_type)) return nullptr;
if (!IsValidIndustryType(industry_type)) return std::nullopt;
return GetString(::GetIndustrySpec(industry_type)->name);
}
@@ -70,8 +71,8 @@
const IndustrySpec *ins = ::GetIndustrySpec(industry_type);
ScriptList *list = new ScriptList();
for (size_t i = 0; i < lengthof(ins->produced_cargo); i++) {
if (ins->produced_cargo[i] != CT_INVALID) list->AddItem(ins->produced_cargo[i]);
for (const CargoID &c : ins->produced_cargo) {
if (::IsValidCargoID(c)) list->AddItem(c);
}
return list;
@@ -84,8 +85,8 @@
const IndustrySpec *ins = ::GetIndustrySpec(industry_type);
ScriptList *list = new ScriptList();
for (size_t i = 0; i < lengthof(ins->accepts_cargo); i++) {
if (ins->accepts_cargo[i] != CT_INVALID) list->AddItem(ins->accepts_cargo[i]);
for (const CargoID &c : ins->accepts_cargo) {
if (::IsValidCargoID(c)) list->AddItem(c);
}
return list;
@@ -95,7 +96,7 @@
{
if (!IsValidIndustryType(industry_type)) return false;
const bool deity = ScriptObject::GetCompany() == OWNER_DEITY;
const bool deity = ScriptCompanyMode::IsDeity();
if (::GetIndustryProbabilityCallback(industry_type, deity ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) return false;
if (deity) return true;
if (!::GetIndustrySpec(industry_type)->IsRawIndustry()) return true;
@@ -108,7 +109,7 @@
{
if (!IsValidIndustryType(industry_type)) return false;
const bool deity = ScriptObject::GetCompany() == OWNER_DEITY;
const bool deity = ScriptCompanyMode::IsDeity();
if (!deity && !::GetIndustrySpec(industry_type)->IsRawIndustry()) return false;
if (::GetIndustryProbabilityCallback(industry_type, deity ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) return false;
@@ -118,19 +119,21 @@
/* static */ bool ScriptIndustryType::BuildIndustry(IndustryType industry_type, TileIndex tile)
{
EnforceDeityOrCompanyModeValid(false);
EnforcePrecondition(false, CanBuildIndustry(industry_type));
EnforcePrecondition(false, ScriptMap::IsValidTile(tile));
uint32 seed = ::InteractiveRandom();
uint32 layout_index = ::InteractiveRandomRange((uint32)::GetIndustrySpec(industry_type)->layouts.size());
uint32_t seed = ScriptBase::Rand();
uint32_t layout_index = ScriptBase::RandRange((uint32_t)::GetIndustrySpec(industry_type)->layouts.size());
return ScriptObject::Command<CMD_BUILD_INDUSTRY>::Do(tile, industry_type, layout_index, true, seed);
}
/* static */ bool ScriptIndustryType::ProspectIndustry(IndustryType industry_type)
{
EnforceDeityOrCompanyModeValid(false);
EnforcePrecondition(false, CanProspectIndustry(industry_type));
uint32 seed = ::InteractiveRandom();
uint32_t seed = ScriptBase::Rand();
return ScriptObject::Command<CMD_BUILD_INDUSTRY>::Do(0, industry_type, 0, false, seed);
}
@@ -155,10 +158,10 @@
return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0;
}
/* static */ IndustryType ScriptIndustryType::ResolveNewGRFID(uint32 grfid, uint16 grf_local_id)
/* static */ IndustryType ScriptIndustryType::ResolveNewGRFID(SQInteger grfid, SQInteger grf_local_id)
{
EnforcePrecondition(INVALID_INDUSTRYTYPE, IsInsideBS(grf_local_id, 0x00, NUM_INDUSTRYTYPES_PER_GRF));
grfid = BSWAP32(grfid); // Match people's expectations.
grfid = BSWAP32(GB(grfid, 0, 32)); // Match people's expectations.
return _industry_mngr.GetID(grf_local_id, grfid);
}

View File

@@ -39,7 +39,7 @@ public:
* @pre IsValidIndustryType(industry_type).
* @return The name of an industry.
*/
static char *GetName(IndustryType industry_type);
static std::optional<std::string> GetName(IndustryType industry_type);
/**
* Get a list of CargoID possible produced by this industry-type.
@@ -111,9 +111,9 @@ public:
* @pre IsValidIndustryType(industry_type).
* @return True if you can build this type of industry at locations of your choice.
* @ai @note Returns false if you can only prospect this type of industry, or not build it at all.
* @game @note If no valid ScriptCompanyMode active in scope, this method returns false if you can
* @game @note When ScriptCompanyMode::IsDeity, this method returns false if you can
* @game only prospect this type of industry, or not build it at all.
* @game @note If no valid ScriptCompanyMode active in scope, the script can
* @game @note When ScriptCompanyMode::IsDeity, the script can
* @game build as long as the industry type can be built. (a NewGRF can for example
* @game reject construction based on current year)
*/
@@ -126,10 +126,10 @@ public:
* @return True if you can prospect this type of industry.
* @ai @note If the setting "Manual primary industry construction method" is set
* @ai to either "None" or "as other industries" this function always returns false.
* @game @note If no valid ScriptCompanyMode is active in scope, and if the setting
* @game @note When ScriptCompanyMode::IsDeity, and if the setting
* @game "Manual primary industry construction method" is set to either "None" or
* @game "as other industries" this function always returns false.
* @game @note If no valid ScriptCompanyMode active in scope, the script can
* @game @note When ScriptCompanyMode::IsDeity, the script can
* @game prospect as long as the industry type can be built. (a NewGRF can for
* @game example reject construction based on current year)
*/
@@ -152,7 +152,7 @@ public:
* @return True if no error occurred while trying to prospect.
* @note Even if true is returned there is no guarantee a new industry is build.
* @note If true is returned the money is paid, whether a new industry was build or not.
* @game @note if no valid ScriptCompanyMode exist in scope, prospection will not fail
* @game @note When ScriptCompanyMode::IsDeity, prospection will not fail
* @game due to the general chance that prospection may fail. However prospection can still
* @game fail if OpenTTD is unable to find a suitable location to place the industry.
*/
@@ -189,7 +189,7 @@ public:
* @pre 0x00 <= grf_local_id < NUM_INDUSTRYTYPES_PER_GRF.
* @return the industry-type ID, local to the current game (this diverges from the grf_local_id).
*/
static IndustryType ResolveNewGRFID(uint32 grfid, uint16 grf_local_id);
static IndustryType ResolveNewGRFID(SQInteger grfid, SQInteger grf_local_id);
};
#endif /* SCRIPT_INDUSTRYTYPE_HPP */

View File

@@ -203,7 +203,6 @@ public:
/** Miscellaneous flags for Script settings. */
enum ScriptConfigFlags {
CONFIG_NONE, ///< Normal setting.
CONFIG_RANDOM, ///< When randomizing the Script, pick any value between min_value and max_value (inclusive).
CONFIG_BOOLEAN, ///< This value is a boolean (either 0 (false) or 1 (true) ).
CONFIG_INGAME, ///< This setting can be changed while the Script is running.
CONFIG_DEVELOPER, ///< This setting will only be visible when the Script development tools are active.
@@ -219,27 +218,18 @@ public:
* - description A single line describing the setting. Required.
* - min_value The minimum value of this setting. Required for integer
* settings and not allowed for boolean settings. The value will be
* clamped in the range [MIN(int32), MAX(int32)] (inclusive).
* clamped in the range [MIN(int32_t), MAX(int32_t)] (inclusive).
* - max_value The maximum value of this setting. Required for integer
* settings and not allowed for boolean settings. The value will be
* clamped in the range [MIN(int32), MAX(int32)] (inclusive).
* - easy_value The default value if the easy difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32), MAX(int32)] (inclusive).
* - medium_value The default value if the medium difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32), MAX(int32)] (inclusive).
* - hard_value The default value if the hard difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32), MAX(int32)] (inclusive).
* - custom_value The default value if the custom difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32), MAX(int32)] (inclusive).
* clamped in the range [MIN(int32_t), MAX(int32_t)] (inclusive).
* - default_value The default value. Required. The value will be
* clamped in the range [MIN(int32_t), MAX(int32_t)] (inclusive).
* - random_deviation If this property has a nonzero value, then the
* actual value of the setting in game will be randomized in the range
* actual value of the setting in game will be randomised in the range
* [user_configured_value - random_deviation, user_configured_value + random_deviation] (inclusive).
* random_deviation sign is ignored and the value is clamped in the range [0, MAX(int32)] (inclusive).
* Not allowed if the CONFIG_RANDOM flag is set, otherwise optional.
* random_deviation sign is ignored and the value is clamped in the range [0, MAX(int32_t)] (inclusive).
* The randomisation will happen just before the Script start.
* Not allowed if the CONFIG_BOOLEAN flag is set, otherwise optional.
* - step_size The increase/decrease of the value every time the user
* clicks one of the up/down arrow buttons. Optional, default is 1.
* - flags Bitmask of some flags, see ScriptConfigFlags. Required.

View File

@@ -18,7 +18,7 @@
#include "../../safeguards.h"
/* static */ uint32 ScriptInfrastructure::GetRailPieceCount(ScriptCompany::CompanyID company, ScriptRail::RailType railtype)
/* static */ SQInteger ScriptInfrastructure::GetRailPieceCount(ScriptCompany::CompanyID company, ScriptRail::RailType railtype)
{
company = ScriptCompany::ResolveCompanyID(company);
if (company == ScriptCompany::COMPANY_INVALID || (::RailType)railtype >= RAILTYPE_END) return 0;
@@ -26,7 +26,7 @@
return ::Company::Get((::CompanyID)company)->infrastructure.rail[railtype];
}
/* static */ uint32 ScriptInfrastructure::GetRoadPieceCount(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype)
/* static */ SQInteger ScriptInfrastructure::GetRoadPieceCount(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype)
{
company = ScriptCompany::ResolveCompanyID(company);
if (company == ScriptCompany::COMPANY_INVALID || (::RoadType)roadtype >= ROADTYPE_END) return 0;
@@ -34,31 +34,21 @@
return ::Company::Get((::CompanyID)company)->infrastructure.road[roadtype];
}
/* static */ uint32 ScriptInfrastructure::GetInfrastructurePieceCount(ScriptCompany::CompanyID company, Infrastructure infra_type)
/* static */ SQInteger ScriptInfrastructure::GetInfrastructurePieceCount(ScriptCompany::CompanyID company, Infrastructure infra_type)
{
company = ScriptCompany::ResolveCompanyID(company);
if (company == ScriptCompany::COMPANY_INVALID) return 0;
::Company *c = ::Company::Get((::CompanyID)company);
switch (infra_type) {
case INFRASTRUCTURE_RAIL: {
uint32 count = 0;
for (::RailType rt = ::RAILTYPE_BEGIN; rt != ::RAILTYPE_END; rt++) {
count += c->infrastructure.rail[rt];
}
return count;
}
case INFRASTRUCTURE_RAIL:
return c->infrastructure.GetRailTotal();
case INFRASTRUCTURE_SIGNALS:
return c->infrastructure.signal;
case INFRASTRUCTURE_ROAD: {
uint32 count = 0;
for (::RoadType rt = ::ROADTYPE_BEGIN; rt != ::ROADTYPE_END; rt++) {
count += c->infrastructure.road[rt];
}
return count;
}
case INFRASTRUCTURE_ROAD:
return c->infrastructure.GetRoadTotal() + c->infrastructure.GetTramTotal();
case INFRASTRUCTURE_CANAL:
return c->infrastructure.water;
@@ -101,7 +91,7 @@
switch (infra_type) {
case INFRASTRUCTURE_RAIL: {
Money cost;
uint32 rail_total = c->infrastructure.GetRailTotal();
uint32_t rail_total = c->infrastructure.GetRailTotal();
for (::RailType rt = ::RAILTYPE_BEGIN; rt != ::RAILTYPE_END; rt++) {
cost += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
}
@@ -113,7 +103,7 @@
case INFRASTRUCTURE_ROAD: {
Money cost;
uint32 road_total = c->infrastructure.GetRoadTotal();
uint32_t road_total = c->infrastructure.GetRoadTotal();
for (::RoadType rt = ::ROADTYPE_BEGIN; rt != ::ROADTYPE_END; rt++) {
cost += RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total);
}

View File

@@ -35,7 +35,7 @@ public:
* @param railtype Rail type to get the count of.
* @return Count for the rail type.
*/
static uint32 GetRailPieceCount(ScriptCompany::CompanyID company, ScriptRail::RailType railtype);
static SQInteger GetRailPieceCount(ScriptCompany::CompanyID company, ScriptRail::RailType railtype);
/**
* Return the number of road pieces of a specific road type for a company.
@@ -43,7 +43,7 @@ public:
* @param roadtype Road type to get the count of.
* @return Count for the road type.
*/
static uint32 GetRoadPieceCount(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype);
static SQInteger GetRoadPieceCount(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype);
/**
* Return the number of pieces of an infrastructure category for a company.
@@ -52,7 +52,7 @@ public:
* @return Count for the wanted category.
* @note #INFRASTRUCTURE_RAIL and #INFRASTRUCTURE_ROAD return the total count for all rail/road types.
*/
static uint32 GetInfrastructurePieceCount(ScriptCompany::CompanyID company, Infrastructure infra_type);
static SQInteger GetInfrastructurePieceCount(ScriptCompany::CompanyID company, Infrastructure infra_type);
/**
* Return the monthly maintenance costs of a specific rail type for a company.

View File

@@ -30,13 +30,13 @@
CCountedPtr<Text> header_counter(header);
CCountedPtr<Text> footer_counter(footer);
EnforcePrecondition(LEAGUE_TABLE_INVALID, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(LEAGUE_TABLE_INVALID);
EnforcePrecondition(LEAGUE_TABLE_INVALID, title != nullptr);
const char *encoded_title = title->GetEncodedText();
std::string encoded_title = title->GetEncodedText();
EnforcePreconditionEncodedText(LEAGUE_TABLE_INVALID, encoded_title);
auto encoded_header = (header != nullptr ? std::string{ header->GetEncodedText() } : std::string{});
auto encoded_footer = (footer != nullptr ? std::string{ footer->GetEncodedText() } : std::string{});
std::string encoded_header = (header != nullptr ? header->GetEncodedText() : std::string{});
std::string encoded_footer = (footer != nullptr ? footer->GetEncodedText() : std::string{});
if (!ScriptObject::Command<CMD_CREATE_LEAGUE_TABLE>::Do(&ScriptInstance::DoCommandReturnLeagueTableID, encoded_title, encoded_header, encoded_footer)) return LEAGUE_TABLE_INVALID;
@@ -49,12 +49,12 @@
return ::LeagueTableElement::IsValidID(element_id);
}
/* static */ ScriptLeagueTable::LeagueTableElementID ScriptLeagueTable::NewElement(ScriptLeagueTable::LeagueTableID table, int64 rating, ScriptCompany::CompanyID company, Text *text, Text *score, LinkType link_type, uint32 link_target)
/* static */ ScriptLeagueTable::LeagueTableElementID ScriptLeagueTable::NewElement(ScriptLeagueTable::LeagueTableID table, SQInteger rating, ScriptCompany::CompanyID company, Text *text, Text *score, LinkType link_type, LinkTargetID link_target)
{
CCountedPtr<Text> text_counter(text);
CCountedPtr<Text> score_counter(score);
EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(LEAGUE_TABLE_ELEMENT_INVALID);
EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, IsValidLeagueTable(table));
@@ -63,12 +63,11 @@
if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, text != nullptr);
const char *encoded_text_ptr = text->GetEncodedText();
EnforcePreconditionEncodedText(LEAGUE_TABLE_ELEMENT_INVALID, encoded_text_ptr);
std::string encoded_text = encoded_text_ptr; // save into string so GetEncodedText can reuse the internal buffer
std::string encoded_text = text->GetEncodedText();
EnforcePreconditionEncodedText(LEAGUE_TABLE_ELEMENT_INVALID, encoded_text);
EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, score != nullptr);
const char *encoded_score = score->GetEncodedText();
std::string encoded_score = score->GetEncodedText();
EnforcePreconditionEncodedText(LEAGUE_TABLE_ELEMENT_INVALID, encoded_score);
EnforcePrecondition(LEAGUE_TABLE_ELEMENT_INVALID, IsValidLink(Link((::LinkType)link_type, link_target)));
@@ -83,7 +82,7 @@
{
CCountedPtr<Text> text_counter(text);
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidLeagueTableElement(element));
EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID);
@@ -91,7 +90,7 @@
if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
EnforcePrecondition(false, text != nullptr);
const char *encoded_text = text->GetEncodedText();
std::string encoded_text = text->GetEncodedText();
EnforcePreconditionEncodedText(false, encoded_text);
EnforcePrecondition(false, IsValidLink(Link((::LinkType)link_type, link_target)));
@@ -99,15 +98,15 @@
return ScriptObject::Command<CMD_UPDATE_LEAGUE_TABLE_ELEMENT_DATA>::Do(element, c, encoded_text, (::LinkType)link_type, (::LinkTargetID)link_target);
}
/* static */ bool ScriptLeagueTable::UpdateElementScore(LeagueTableElementID element, int64 rating, Text *score)
/* static */ bool ScriptLeagueTable::UpdateElementScore(LeagueTableElementID element, SQInteger rating, Text *score)
{
CCountedPtr<Text> score_counter(score);
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidLeagueTableElement(element));
EnforcePrecondition(false, score != nullptr);
const char *encoded_score = score->GetEncodedText();
std::string encoded_score = score->GetEncodedText();
EnforcePreconditionEncodedText(false, encoded_score);
return ScriptObject::Command<CMD_UPDATE_LEAGUE_TABLE_ELEMENT_SCORE>::Do(element, rating, encoded_score);
@@ -115,7 +114,7 @@
/* static */ bool ScriptLeagueTable::RemoveElement(LeagueTableElementID element)
{
EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidLeagueTableElement(element));
return ScriptObject::Command<CMD_REMOVE_LEAGUE_TABLE_ELEMENT>::Do(element);

View File

@@ -71,7 +71,7 @@ public:
* @param header The optional header text for the table (null is allowed).
* @param footer The optional footer text for the table (null is allowed).
* @return The new LeagueTableID, or LEAGUE_TABLE_INVALID if it failed.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity.
* @pre title != null && len(title) != 0.
*/
static LeagueTableID New(Text *title, Text *header, Text *footer);
@@ -86,13 +86,13 @@ public:
* @param link_type Type of the referenced object.
* @param link_target Id of the referenced object.
* @return The new LeagueTableElementID, or LEAGUE_TABLE_ELEMENT_INVALID if it failed.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity.
* @pre IsValidLeagueTable(table).
* @pre text != null && len(text) != 0.
* @pre score != null && len(score) != 0.
* @pre IsValidLink(Link(link_type, link_target)).
*/
static LeagueTableElementID NewElement(LeagueTableID table, int64 rating, ScriptCompany::CompanyID company, Text *text, Text *score, LinkType link_type, LinkTargetID link_target);
static LeagueTableElementID NewElement(LeagueTableID table, SQInteger rating, ScriptCompany::CompanyID company, Text *text, Text *score, LinkType link_type, LinkTargetID link_target);
/**
* Update the attributes of a league table element.
@@ -102,7 +102,7 @@ public:
* @param link_type Type of the referenced object.
* @param link_target Id of the referenced object.
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity.
* @pre IsValidLeagueTableElement(element).
* @pre text != null && len(text) != 0.
* @pre IsValidLink(Link(link_type, link_target)).
@@ -115,18 +115,18 @@ public:
* @param rating Value that elements are ordered by.
* @param score String representation of the score associated with the element (can be either a raw string, or ScriptText object).
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity.
* @pre IsValidLeagueTableElement(element).
* @pre score != null && len(score) != 0.
*/
static bool UpdateElementScore(LeagueTableElementID element, int64 rating, Text *score);
static bool UpdateElementScore(LeagueTableElementID element, SQInteger rating, Text *score);
/**
* Remove a league table element.
* @param element Id of the element to update
* @return True if the action succeeded.
* @pre No ScriptCompanyMode may be in scope.
* @pre ScriptCompanyMode::IsDeity.
* @pre IsValidLeagueTableElement(element).
*/
static bool RemoveElement(LeagueTableElementID element);

View File

@@ -9,7 +9,6 @@
#include "../../stdafx.h"
#include "script_list.hpp"
#include "script_controller.hpp"
#include "../../debug.h"
#include "../../script/squirrel.hpp"
@@ -22,18 +21,18 @@ class ScriptListSorter {
protected:
ScriptList *list; ///< The list that's being sorted.
bool has_no_more_items; ///< Whether we have more items to iterate over.
int64 item_next; ///< The next item we will show.
SQInteger item_next; ///< The next item we will show.
public:
/**
* Virtual dtor, needed to mute warnings.
*/
virtual ~ScriptListSorter() { }
virtual ~ScriptListSorter() = default;
/**
* Get the first item of the sorter.
*/
virtual int64 Begin() = 0;
virtual SQInteger Begin() = 0;
/**
* Stop iterating a sorter.
@@ -43,7 +42,7 @@ public:
/**
* Get the next item of the sorter.
*/
virtual int64 Next() = 0;
virtual SQInteger Next() = 0;
/**
* See if the sorter has reached the end.
@@ -56,7 +55,7 @@ public:
/**
* Callback from the list if an item gets removed.
*/
virtual void Remove(int item) = 0;
virtual void Remove(SQInteger item) = 0;
/**
* Attach the sorter to a new list. This assumes the content of the old list has been moved to
@@ -90,7 +89,7 @@ public:
this->End();
}
int64 Begin()
SQInteger Begin() override
{
if (this->list->buckets.empty()) return 0;
this->has_no_more_items = false;
@@ -100,12 +99,12 @@ public:
this->bucket_list_iter = this->bucket_list->begin();
this->item_next = *this->bucket_list_iter;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void End()
void End() override
{
this->bucket_list = nullptr;
this->has_no_more_items = true;
@@ -135,16 +134,16 @@ public:
this->item_next = *this->bucket_list_iter;
}
int64 Next()
SQInteger Next() override
{
if (this->IsEnd()) return 0;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item)
void Remove(SQInteger item) override
{
if (this->IsEnd()) return;
@@ -179,7 +178,7 @@ public:
this->End();
}
int64 Begin()
SQInteger Begin() override
{
if (this->list->buckets.empty()) return 0;
this->has_no_more_items = false;
@@ -194,12 +193,12 @@ public:
--this->bucket_list_iter;
this->item_next = *this->bucket_list_iter;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void End()
void End() override
{
this->bucket_list = nullptr;
this->has_no_more_items = true;
@@ -232,16 +231,16 @@ public:
this->item_next = *this->bucket_list_iter;
}
int64 Next()
SQInteger Next() override
{
if (this->IsEnd()) return 0;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item)
void Remove(SQInteger item) override
{
if (this->IsEnd()) return;
@@ -271,7 +270,7 @@ public:
this->End();
}
int64 Begin()
SQInteger Begin() override
{
if (this->list->items.empty()) return 0;
this->has_no_more_items = false;
@@ -279,12 +278,12 @@ public:
this->item_iter = this->list->items.begin();
this->item_next = (*this->item_iter).first;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void End()
void End() override
{
this->has_no_more_items = true;
}
@@ -302,16 +301,16 @@ public:
if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
}
int64 Next()
SQInteger Next() override
{
if (this->IsEnd()) return 0;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item)
void Remove(SQInteger item) override
{
if (this->IsEnd()) return;
@@ -344,7 +343,7 @@ public:
this->End();
}
int64 Begin()
SQInteger Begin() override
{
if (this->list->items.empty()) return 0;
this->has_no_more_items = false;
@@ -353,12 +352,12 @@ public:
--this->item_iter;
this->item_next = (*this->item_iter).first;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void End()
void End() override
{
this->has_no_more_items = true;
}
@@ -381,16 +380,16 @@ public:
if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
}
int64 Next()
SQInteger Next() override
{
if (this->IsEnd()) return 0;
int64 item_current = this->item_next;
SQInteger item_current = this->item_next;
FindNext();
return item_current;
}
void Remove(int item)
void Remove(SQInteger item) override
{
if (this->IsEnd()) return;
@@ -419,7 +418,7 @@ ScriptList::~ScriptList()
delete this->sorter;
}
bool ScriptList::HasItem(int64 item)
bool ScriptList::HasItem(SQInteger item)
{
return this->items.count(item) == 1;
}
@@ -433,7 +432,7 @@ void ScriptList::Clear()
this->sorter->End();
}
void ScriptList::AddItem(int64 item, int64 value)
void ScriptList::AddItem(SQInteger item, SQInteger value)
{
this->modifications++;
@@ -443,14 +442,14 @@ void ScriptList::AddItem(int64 item, int64 value)
this->buckets[value].insert(item);
}
void ScriptList::RemoveItem(int64 item)
void ScriptList::RemoveItem(SQInteger item)
{
this->modifications++;
ScriptListMap::iterator item_iter = this->items.find(item);
if (item_iter == this->items.end()) return;
int64 value = item_iter->second;
SQInteger value = item_iter->second;
this->sorter->Remove(item);
ScriptListBucket::iterator bucket_iter = this->buckets.find(value);
@@ -460,13 +459,13 @@ void ScriptList::RemoveItem(int64 item)
this->items.erase(item_iter);
}
int64 ScriptList::Begin()
SQInteger ScriptList::Begin()
{
this->initialized = true;
return this->sorter->Begin();
}
int64 ScriptList::Next()
SQInteger ScriptList::Next()
{
if (!this->initialized) {
Debug(script, 0, "Next() is invalid as Begin() is never called");
@@ -489,25 +488,25 @@ bool ScriptList::IsEnd()
return this->sorter->IsEnd();
}
int32 ScriptList::Count()
SQInteger ScriptList::Count()
{
return (int32)this->items.size();
return this->items.size();
}
int64 ScriptList::GetValue(int64 item)
SQInteger ScriptList::GetValue(SQInteger item)
{
ScriptListMap::const_iterator item_iter = this->items.find(item);
return item_iter == this->items.end() ? 0 : item_iter->second;
}
bool ScriptList::SetValue(int64 item, int64 value)
bool ScriptList::SetValue(SQInteger item, SQInteger value)
{
this->modifications++;
ScriptListMap::iterator item_iter = this->items.find(item);
if (item_iter == this->items.end()) return false;
int64 value_old = item_iter->second;
SQInteger value_old = item_iter->second;
if (value_old == value) return true;
this->sorter->Remove(item);
@@ -564,9 +563,9 @@ void ScriptList::AddList(ScriptList *list)
this->modifications++;
} else {
ScriptListMap *list_items = &list->items;
for (ScriptListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
this->AddItem((*iter).first);
this->SetValue((*iter).first, (*iter).second);
for (auto &it : *list_items) {
this->AddItem(it.first);
this->SetValue(it.first, it.second);
}
}
}
@@ -586,7 +585,7 @@ void ScriptList::SwapList(ScriptList *list)
list->sorter->Retarget(list);
}
void ScriptList::RemoveAboveValue(int64 value)
void ScriptList::RemoveAboveValue(SQInteger value)
{
this->modifications++;
@@ -596,7 +595,7 @@ void ScriptList::RemoveAboveValue(int64 value)
}
}
void ScriptList::RemoveBelowValue(int64 value)
void ScriptList::RemoveBelowValue(SQInteger value)
{
this->modifications++;
@@ -606,7 +605,7 @@ void ScriptList::RemoveBelowValue(int64 value)
}
}
void ScriptList::RemoveBetweenValue(int64 start, int64 end)
void ScriptList::RemoveBetweenValue(SQInteger start, SQInteger end)
{
this->modifications++;
@@ -616,7 +615,7 @@ void ScriptList::RemoveBetweenValue(int64 start, int64 end)
}
}
void ScriptList::RemoveValue(int64 value)
void ScriptList::RemoveValue(SQInteger value)
{
this->modifications++;
@@ -626,7 +625,7 @@ void ScriptList::RemoveValue(int64 value)
}
}
void ScriptList::RemoveTop(int32 count)
void ScriptList::RemoveTop(SQInteger count)
{
this->modifications++;
@@ -663,7 +662,7 @@ void ScriptList::RemoveTop(int32 count)
}
}
void ScriptList::RemoveBottom(int32 count)
void ScriptList::RemoveBottom(SQInteger count)
{
this->modifications++;
@@ -714,7 +713,7 @@ void ScriptList::RemoveList(ScriptList *list)
}
}
void ScriptList::KeepAboveValue(int64 value)
void ScriptList::KeepAboveValue(SQInteger value)
{
this->modifications++;
@@ -724,7 +723,7 @@ void ScriptList::KeepAboveValue(int64 value)
}
}
void ScriptList::KeepBelowValue(int64 value)
void ScriptList::KeepBelowValue(SQInteger value)
{
this->modifications++;
@@ -734,7 +733,7 @@ void ScriptList::KeepBelowValue(int64 value)
}
}
void ScriptList::KeepBetweenValue(int64 start, int64 end)
void ScriptList::KeepBetweenValue(SQInteger start, SQInteger end)
{
this->modifications++;
@@ -744,7 +743,7 @@ void ScriptList::KeepBetweenValue(int64 start, int64 end)
}
}
void ScriptList::KeepValue(int64 value)
void ScriptList::KeepValue(SQInteger value)
{
this->modifications++;
@@ -754,14 +753,14 @@ void ScriptList::KeepValue(int64 value)
}
}
void ScriptList::KeepTop(int32 count)
void ScriptList::KeepTop(SQInteger count)
{
this->modifications++;
this->RemoveBottom(this->Count() - count);
}
void ScriptList::KeepBottom(int32 count)
void ScriptList::KeepBottom(SQInteger count)
{
this->modifications++;
@@ -866,6 +865,9 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
bool backup_allow = ScriptObject::GetAllowDoCommand();
ScriptObject::SetAllowDoCommand(false);
/* Limit the total number of ops that can be consumed by a valuate operation */
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "valuator function");
/* Push the function to call */
sq_push(vm, 2);
@@ -911,16 +913,6 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
}
}
/* Kill the script when the valuator call takes way too long.
* Triggered by nesting valuators, which then take billions of iterations. */
if (ScriptController::GetOpsTillSuspend() < -1000000) {
/* See below for explanation. The extra pop is the return value. */
sq_pop(vm, nparam + 4);
ScriptObject::SetAllowDoCommand(backup_allow);
return sq_throwerror(vm, "excessive CPU usage in valuator function");
}
/* Was something changed? */
if (previous_modification_count != this->modifications) {
/* See below for explanation. The extra pop is the return value. */

View File

@@ -12,8 +12,9 @@
#define SCRIPT_LIST_HPP
#include "script_object.hpp"
#include <map>
#include <set>
/** Maximum number of operations allowed for valuating a list. */
static const int MAX_VALUATE_OPS = 1000000;
class ScriptListSorter;
@@ -41,10 +42,111 @@ private:
bool initialized; ///< Whether an iteration has been started
int modifications; ///< Number of modification that has been done. To prevent changing data while valuating.
protected:
template<typename T, class ItemValid, class ItemFilter>
static void FillList(ScriptList *list, ItemValid item_valid, ItemFilter item_filter)
{
for (const T *item : T::Iterate()) {
if (!item_valid(item)) continue;
if (!item_filter(item)) continue;
list->AddItem(item->index);
}
}
template<typename T, class ItemValid>
static void FillList(ScriptList *list, ItemValid item_valid)
{
ScriptList::FillList<T>(list, item_valid, [](const T *) { return true; });
}
template<typename T>
static void FillList(ScriptList *list)
{
ScriptList::FillList<T>(list, [](const T *) { return true; });
}
template<typename T, class ItemValid>
static void FillList(HSQUIRRELVM vm, ScriptList *list, ItemValid item_valid)
{
int nparam = sq_gettop(vm) - 1;
if (nparam >= 1) {
/* Make sure the filter function is really a function, and not any
* other type. It's parameter 2 for us, but for the user it's the
* first parameter they give. */
SQObjectType valuator_type = sq_gettype(vm, 2);
if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
throw sq_throwerror(vm, "parameter 1 has an invalid type (expected function)");
}
/* Push the function to call */
sq_push(vm, 2);
}
/* Don't allow docommand from a Valuator, as we can't resume in
* mid C++-code. */
bool backup_allow = ScriptObject::GetAllowDoCommand();
ScriptObject::SetAllowDoCommand(false);
if (nparam < 1) {
ScriptList::FillList<T>(list, item_valid);
} else {
/* Limit the total number of ops that can be consumed by a filter operation, if a filter function is present */
SQOpsLimiter limiter(vm, MAX_VALUATE_OPS, "list filter function");
ScriptList::FillList<T>(list, item_valid,
[vm, nparam, backup_allow](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. */
sq_pushinteger(vm, item->index);
for (int i = 0; i < nparam - 1; i++) {
sq_push(vm, i + 3);
}
/* 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");
}
SQBool add = SQFalse;
/* Retrieve the return value */
switch (sq_gettype(vm, -1)) {
case OT_BOOL:
sq_getbool(vm, -1, &add);
break;
default:
ScriptObject::SetAllowDoCommand(backup_allow);
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
}
/* Pop the return value. */
sq_poptop(vm);
return add;
}
);
/* Pop the filter function */
sq_poptop(vm);
}
ScriptObject::SetAllowDoCommand(backup_allow);
}
template<typename T>
static void FillList(HSQUIRRELVM vm, ScriptList *list)
{
ScriptList::FillList<T>(vm, list, [](const T *) { return true; });
}
public:
typedef std::set<int64> ScriptItemList; ///< The list of items inside the bucket
typedef std::map<int64, ScriptItemList> ScriptListBucket; ///< The bucket list per value
typedef std::map<int64, int64> ScriptListMap; ///< List per item
typedef std::set<SQInteger> ScriptItemList; ///< The list of items inside the bucket
typedef std::map<SQInteger, ScriptItemList> ScriptListBucket; ///< The bucket list per value
typedef std::map<SQInteger, SQInteger> ScriptListMap; ///< List per item
ScriptListMap items; ///< The items in the list
ScriptListBucket buckets; ///< The items in the list, sorted by value
@@ -58,16 +160,16 @@ public:
* @param item the item to add. Should be unique, otherwise it is ignored.
* @param value the value to assign.
*/
void AddItem(int64 item, int64 value);
void AddItem(SQInteger item, SQInteger value);
#else
void AddItem(int64 item, int64 value = 0);
void AddItem(SQInteger item, SQInteger value = 0);
#endif /* DOXYGEN_API */
/**
* Remove a single item from the list.
* @param item the item to remove. If not existing, it is ignored.
*/
void RemoveItem(int64 item);
void RemoveItem(SQInteger item);
/**
* Clear the list, making Count() returning 0 and IsEmpty() returning true.
@@ -79,21 +181,21 @@ public:
* @param item the item to check for.
* @return true if the item is in the list.
*/
bool HasItem(int64 item);
bool HasItem(SQInteger item);
/**
* Go to the beginning of the list and return the item. To get the value use list.GetValue(list.Begin()).
* @return the first item.
* @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
*/
int64 Begin();
SQInteger Begin();
/**
* Go to the next item in the list and return the item. To get the value use list.GetValue(list.Next()).
* @return the next item.
* @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list.
*/
int64 Next();
SQInteger Next();
/**
* Check if a list is empty.
@@ -112,14 +214,14 @@ public:
* Returns the amount of items in the list.
* @return amount of items in the list.
*/
int32 Count();
SQInteger Count();
/**
* Get the value that belongs to this item.
* @param item the item to get the value from
* @return the value that belongs to this item.
*/
int64 GetValue(int64 item);
SQInteger GetValue(SQInteger item);
/**
* Set a value of an item directly.
@@ -129,7 +231,7 @@ public:
* @note Changing values of items while looping through a list might cause
* entries to be skipped. Be very careful with such operations.
*/
bool SetValue(int64 item, int64 value);
bool SetValue(SQInteger item, SQInteger value);
/**
* Sort this list by the given sorter and direction.
@@ -160,38 +262,38 @@ public:
* Removes all items with a higher value than 'value'.
* @param value the value above which all items are removed.
*/
void RemoveAboveValue(int64 value);
void RemoveAboveValue(SQInteger value);
/**
* Removes all items with a lower value than 'value'.
* @param value the value below which all items are removed.
*/
void RemoveBelowValue(int64 value);
void RemoveBelowValue(SQInteger value);
/**
* Removes all items with a value above start and below end.
* @param start the lower bound of the to be removed values (exclusive).
* @param end the upper bound of the to be removed values (exclusive).
*/
void RemoveBetweenValue(int64 start, int64 end);
void RemoveBetweenValue(SQInteger start, SQInteger end);
/**
* Remove all items with this value.
* @param value the value to remove.
*/
void RemoveValue(int64 value);
void RemoveValue(SQInteger value);
/**
* Remove the first count items.
* @param count the amount of items to remove.
*/
void RemoveTop(int32 count);
void RemoveTop(SQInteger count);
/**
* Remove the last count items.
* @param count the amount of items to remove.
*/
void RemoveBottom(int32 count);
void RemoveBottom(SQInteger count);
/**
* Remove everything that is in the given list from this list (same item index that is).
@@ -204,38 +306,38 @@ public:
* Keep all items with a higher value than 'value'.
* @param value the value above which all items are kept.
*/
void KeepAboveValue(int64 value);
void KeepAboveValue(SQInteger value);
/**
* Keep all items with a lower value than 'value'.
* @param value the value below which all items are kept.
*/
void KeepBelowValue(int64 value);
void KeepBelowValue(SQInteger value);
/**
* Keep all items with a value above start and below end.
* @param start the lower bound of the to be kept values (exclusive).
* @param end the upper bound of the to be kept values (exclusive).
*/
void KeepBetweenValue(int64 start, int64 end);
void KeepBetweenValue(SQInteger start, SQInteger end);
/**
* Keep all items with this value.
* @param value the value to keep.
*/
void KeepValue(int64 value);
void KeepValue(SQInteger value);
/**
* Keep the first count items, i.e. remove everything except the first count items.
* @param count the amount of items to keep.
*/
void KeepTop(int32 count);
void KeepTop(SQInteger count);
/**
* Keep the last count items, i.e. remove everything except the last count items.
* @param count the amount of items to keep.
*/
void KeepBottom(int32 count);
void KeepBottom(SQInteger count);
/**
* Keeps everything that is in the given list from this list (same item index that is).

View File

@@ -8,6 +8,7 @@
/** @file script_log.cpp Implementation of ScriptLog. */
#include "../../stdafx.h"
#include "script_log_types.hpp"
#include "script_log.hpp"
#include "../../core/alloc_func.hpp"
#include "../../debug.h"
@@ -16,77 +17,46 @@
#include "../../safeguards.h"
/* static */ void ScriptLog::Info(const char *message)
/* static */ void ScriptLog::Info(const std::string &message)
{
ScriptLog::Log(LOG_INFO, message);
ScriptLog::Log(ScriptLogTypes::LOG_INFO, message);
}
/* static */ void ScriptLog::Warning(const char *message)
/* static */ void ScriptLog::Warning(const std::string &message)
{
ScriptLog::Log(LOG_WARNING, message);
ScriptLog::Log(ScriptLogTypes::LOG_WARNING, message);
}
/* static */ void ScriptLog::Error(const char *message)
/* static */ void ScriptLog::Error(const std::string &message)
{
ScriptLog::Log(LOG_ERROR, message);
ScriptLog::Log(ScriptLogTypes::LOG_ERROR, message);
}
/* static */ void ScriptLog::Log(ScriptLog::ScriptLogType level, const char *message)
/* static */ void ScriptLog::Log(ScriptLogTypes::ScriptLogType level, const std::string &message)
{
if (ScriptObject::GetLogPointer() == nullptr) {
ScriptObject::GetLogPointer() = new LogData();
LogData *log = (LogData *)ScriptObject::GetLogPointer();
ScriptLogTypes::LogData &logdata = ScriptObject::GetLogData();
log->lines = CallocT<char *>(400);
log->type = CallocT<ScriptLog::ScriptLogType>(400);
log->count = 400;
log->pos = log->count - 1;
log->used = 0;
}
LogData *log = (LogData *)ScriptObject::GetLogPointer();
/* Limit the log to 400 lines. */
if (logdata.size() >= 400U) logdata.pop_front();
/* Go to the next log-line */
log->pos = (log->pos + 1) % log->count;
if (log->used != log->count) log->used++;
/* Free last message, and write new message */
free(log->lines[log->pos]);
log->lines[log->pos] = stredup(message);
log->type[log->pos] = level;
auto &line = logdata.emplace_back();
line.type = level;
/* Cut string after first \n */
char *p;
while ((p = strchr(log->lines[log->pos], '\n')) != nullptr) {
*p = '\0';
break;
}
line.text = message.substr(0, message.find_first_of('\n'));
char logc;
switch (level) {
case LOG_SQ_ERROR: logc = 'S'; break;
case LOG_ERROR: logc = 'E'; break;
case LOG_SQ_INFO: logc = 'P'; break;
case LOG_WARNING: logc = 'W'; break;
case LOG_INFO: logc = 'I'; break;
default: logc = '?'; break;
case ScriptLogTypes::LOG_SQ_ERROR: logc = 'S'; break;
case ScriptLogTypes::LOG_ERROR: logc = 'E'; break;
case ScriptLogTypes::LOG_SQ_INFO: logc = 'P'; break;
case ScriptLogTypes::LOG_WARNING: logc = 'W'; break;
case ScriptLogTypes::LOG_INFO: logc = 'I'; break;
default: logc = '?'; break;
}
/* Also still print to debug window */
Debug(script, level, "[{}] [{}] {}", (uint)ScriptObject::GetRootCompany(), logc, log->lines[log->pos]);
InvalidateWindowData(WC_AI_DEBUG, 0, ScriptObject::GetRootCompany());
}
/* static */ void ScriptLog::FreeLogPointer()
{
LogData *log = (LogData *)ScriptObject::GetLogPointer();
for (int i = 0; i < log->count; i++) {
free(log->lines[i]);
}
free(log->lines);
free(log->type);
delete log;
Debug(script, level, "[{}] [{}] {}", (uint)ScriptObject::GetRootCompany(), logc, line.text);
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, ScriptObject::GetRootCompany());
}

View File

@@ -22,64 +22,32 @@ class ScriptLog : public ScriptObject {
friend class ScriptController;
public:
/**
* Log levels; The value is also feed to Debug() lvl.
* This has no use for you, as script writer.
* @api -all
*/
enum ScriptLogType {
LOG_SQ_ERROR = 0, ///< Squirrel printed an error.
LOG_ERROR = 1, ///< User printed an error.
LOG_SQ_INFO = 2, ///< Squirrel printed some info.
LOG_WARNING = 3, ///< User printed some warning.
LOG_INFO = 4, ///< User printed some info.
};
/**
* Internal representation of the log-data inside the script.
* This has no use for you, as script writer.
* @api -all
*/
struct LogData {
char **lines; ///< The log-lines.
ScriptLog::ScriptLogType *type; ///< Per line, which type of log it was.
int count; ///< Total amount of log-lines possible.
int pos; ///< Current position in lines.
int used; ///< Total amount of used log-lines.
};
/**
* Print an Info message to the logs.
* @param message The message to log.
* @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs.
*/
static void Info(const char *message);
static void Info(const std::string &message);
/**
* Print a Warning message to the logs.
* @param message The message to log.
* @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs.
*/
static void Warning(const char *message);
static void Warning(const std::string &message);
/**
* Print an Error message to the logs.
* @param message The message to log.
* @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs.
*/
static void Error(const char *message);
/**
* Free the log pointer.
* @api -all
*/
static void FreeLogPointer();
static void Error(const std::string &message);
private:
/**
* Internal command to log the message in a common way.
*/
static void Log(ScriptLog::ScriptLogType level, const char *message);
static void Log(ScriptLogTypes::ScriptLogType level, const std::string &message);
};
#endif /* SCRIPT_LOG_HPP */

View File

@@ -0,0 +1,46 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file script_log_types.hpp Data types for script log messages. */
#ifndef SCRIPT_LOG_TYPES_HPP
#define SCRIPT_LOG_TYPES_HPP
namespace ScriptLogTypes {
/**
* Log levels; The value is also feed to Debug() lvl.
* This has no use for you, as script writer.
* @api -all
*/
enum ScriptLogType {
LOG_SQ_ERROR = 0, ///< Squirrel printed an error.
LOG_ERROR = 1, ///< User printed an error.
LOG_SQ_INFO = 2, ///< Squirrel printed some info.
LOG_WARNING = 3, ///< User printed some warning.
LOG_INFO = 4, ///< User printed some info.
};
/**
* Internal representation of the log-data inside the script.
* This has no use for you, as script writer.
* @api -all
*/
struct LogLine {
std::string text; ///< The text
ScriptLogType type; ///< Text type
uint width; ///< The text width
};
/**
* Internal representation of the log-data inside the script.
* This has no use for you, as script writer.
* @api -all
*/
using LogData = std::deque<LogLine>; ///< The log type
};
#endif /* SCRIPT_LOG_TYPES_HPP */

View File

@@ -18,57 +18,57 @@
return ::IsValidTile(t);
}
/* static */ TileIndex ScriptMap::GetMapSize()
/* static */ SQInteger ScriptMap::GetMapSize()
{
return ::MapSize();
return ::Map::Size();
}
/* static */ uint32 ScriptMap::GetMapSizeX()
/* static */ SQInteger ScriptMap::GetMapSizeX()
{
return ::MapSizeX();
return ::Map::SizeX();
}
/* static */ uint32 ScriptMap::GetMapSizeY()
/* static */ SQInteger ScriptMap::GetMapSizeY()
{
return ::MapSizeY();
return ::Map::SizeY();
}
/* static */ int32 ScriptMap::GetTileX(TileIndex t)
/* static */ SQInteger ScriptMap::GetTileX(TileIndex t)
{
if (!::IsValidTile(t)) return -1;
return ::TileX(t);
}
/* static */ int32 ScriptMap::GetTileY(TileIndex t)
/* static */ SQInteger ScriptMap::GetTileY(TileIndex t)
{
if (!::IsValidTile(t)) return -1;
return ::TileY(t);
}
/* static */ TileIndex ScriptMap::GetTileIndex(uint32 x, uint32 y)
/* static */ TileIndex ScriptMap::GetTileIndex(SQInteger x, SQInteger y)
{
return ::TileXY(x, y);
}
/* static */ int32 ScriptMap::DistanceManhattan(TileIndex t1, TileIndex t2)
/* static */ SQInteger ScriptMap::DistanceManhattan(TileIndex t1, TileIndex t2)
{
if (!::IsValidTile(t1) || !::IsValidTile(t2)) return -1;
return ::DistanceManhattan(t1, t2);
}
/* static */ int32 ScriptMap::DistanceMax(TileIndex t1, TileIndex t2)
/* static */ SQInteger ScriptMap::DistanceMax(TileIndex t1, TileIndex t2)
{
if (!::IsValidTile(t1) || !::IsValidTile(t2)) return -1;
return ::DistanceMax(t1, t2);
}
/* static */ int32 ScriptMap::DistanceSquare(TileIndex t1, TileIndex t2)
/* static */ SQInteger ScriptMap::DistanceSquare(TileIndex t1, TileIndex t2)
{
if (!::IsValidTile(t1) || !::IsValidTile(t2)) return -1;
return ::DistanceSquare(t1, t2);
}
/* static */ int32 ScriptMap::DistanceFromEdge(TileIndex t)
/* static */ SQInteger ScriptMap::DistanceFromEdge(TileIndex t)
{
if (!::IsValidTile(t)) return -1;
return ::DistanceFromEdge(t);

View File

@@ -19,7 +19,7 @@
*/
class ScriptMap : public ScriptObject {
public:
static const int TILE_INVALID = (int)INVALID_TILE; ///< Invalid TileIndex.
static const int TILE_INVALID = INVALID_TILE.base(); ///< Invalid TileIndex.
/**
* Checks whether the given tile is valid.
@@ -33,21 +33,21 @@ public:
* @return The size of the map in tiles.
* @post Return value is always positive.
*/
static TileIndex GetMapSize();
static SQInteger GetMapSize();
/**
* Gets the amount of tiles along the SW and NE border.
* @return The length along the SW and NE borders.
* @post Return value is always positive.
*/
static uint32 GetMapSizeX();
static SQInteger GetMapSizeX();
/**
* Gets the amount of tiles along the SE and NW border.
* @return The length along the SE and NW borders.
* @post Return value is always positive.
*/
static uint32 GetMapSizeY();
static SQInteger GetMapSizeY();
/**
* Gets the place along the SW/NE border (X-value).
@@ -56,7 +56,7 @@ public:
* @return The X-value.
* @post Return value is always lower than GetMapSizeX().
*/
static int32 GetTileX(TileIndex tile);
static SQInteger GetTileX(TileIndex tile);
/**
* Gets the place along the SE/NW border (Y-value).
@@ -65,17 +65,18 @@ public:
* @return The Y-value.
* @post Return value is always lower than GetMapSizeY().
*/
static int32 GetTileY(TileIndex tile);
static SQInteger GetTileY(TileIndex tile);
/**
* Gets the TileIndex given a x,y-coordinate.
* @param x The X coordinate.
* @param y The Y coordinate.
* @pre x < GetMapSizeX().
* @pre y < GetMapSizeY().
* @return The TileIndex for the given (x,y) coordinate.
* @post When 0 <= x && x < GetMapSizeX() && 0 <= y && y < GetMapSizeY(), then a valid tile index is returned.
* Otherwise it may be invalid, but could be used to calculated neighbouring tiles, e.g. tile + AIMap.GetTileIndex(-1, -1) gets
* the tile index of the tile to the north. But be aware that even when tile is a valid tile, the result might not be a valid tile.
*/
static TileIndex GetTileIndex(uint32 x, uint32 y);
static TileIndex GetTileIndex(SQInteger x, SQInteger y);
/**
* Calculates the Manhattan distance; the difference of
@@ -86,7 +87,7 @@ public:
* @pre IsValidTile(tile_to).
* @return The Manhattan distance between the tiles.
*/
static int32 DistanceManhattan(TileIndex tile_from, TileIndex tile_to);
static SQInteger DistanceManhattan(TileIndex tile_from, TileIndex tile_to);
/**
* Calculates the distance between two tiles via 1D calculation.
@@ -98,7 +99,7 @@ public:
* @pre IsValidTile(tile_to).
* @return The maximum distance between the tiles.
*/
static int32 DistanceMax(TileIndex tile_from, TileIndex tile_to);
static SQInteger DistanceMax(TileIndex tile_from, TileIndex tile_to);
/**
* The squared distance between the two tiles.
@@ -110,7 +111,7 @@ public:
* @pre IsValidTile(tile_to).
* @return The squared distance between the tiles.
*/
static int32 DistanceSquare(TileIndex tile_from, TileIndex tile_to);
static SQInteger DistanceSquare(TileIndex tile_from, TileIndex tile_to);
/**
* Calculates the shortest distance to the edge.
@@ -118,7 +119,7 @@ public:
* @pre IsValidTile(tile).
* @return The distances to the closest edge.
*/
static int32 DistanceFromEdge(TileIndex tile);
static SQInteger DistanceFromEdge(TileIndex tile);
};
#endif /* SCRIPT_MAP_HPP */

View File

@@ -78,7 +78,7 @@
/* static */ bool ScriptMarine::BuildWaterDepot(TileIndex tile, TileIndex front)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(front));
EnforcePrecondition(false, (::TileX(front) == ::TileX(tile)) != (::TileY(front) == ::TileY(tile)));
@@ -88,7 +88,7 @@
/* static */ bool ScriptMarine::BuildDock(TileIndex tile, StationID station_id)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id));
@@ -97,7 +97,7 @@
/* static */ bool ScriptMarine::BuildBuoy(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
return ScriptObject::Command<CMD_BUILD_BUOY>::Do(tile);
@@ -105,7 +105,7 @@
/* static */ bool ScriptMarine::BuildLock(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
return ScriptObject::Command<CMD_BUILD_LOCK>::Do(tile);
@@ -113,7 +113,7 @@
/* static */ bool ScriptMarine::BuildCanal(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
return ScriptObject::Command<CMD_BUILD_CANAL>::Do(tile, tile, WATER_CLASS_CANAL, false);
@@ -121,7 +121,7 @@
/* static */ bool ScriptMarine::RemoveWaterDepot(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsWaterDepotTile(tile));
@@ -130,7 +130,7 @@
/* static */ bool ScriptMarine::RemoveDock(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsDockTile(tile));
@@ -139,7 +139,7 @@
/* static */ bool ScriptMarine::RemoveBuoy(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsBuoyTile(tile));
@@ -148,7 +148,7 @@
/* static */ bool ScriptMarine::RemoveLock(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsLockTile(tile));
@@ -157,7 +157,7 @@
/* static */ bool ScriptMarine::RemoveCanal(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsCanalTile(tile));

View File

@@ -99,7 +99,7 @@ public:
* @param front A tile on the same axis with 'tile' as the depot shall be oriented.
* @pre ScriptMap::IsValidTile(tile).
* @pre ScriptMap::IsValidTile(front).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_SITE_UNSUITABLE
* @exception ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER
@@ -115,7 +115,7 @@ public:
* @param station_id The station to join, ScriptStation::STATION_NEW or ScriptStation::STATION_JOIN_ADJACENT.
* @pre ScriptMap::IsValidTile(tile).
* @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_SITE_UNSUITABLE
* @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION
@@ -128,7 +128,7 @@ public:
* Builds a buoy on tile.
* @param tile The tile where the buoy will be build.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_SITE_UNSUITABLE
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS
@@ -140,7 +140,7 @@ public:
* Builds a lock on tile.
* @param tile The tile where the lock will be build.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_LAND_SLOPED_WRONG
* @exception ScriptError::ERR_SITE_UNSUITABLE
* @return Whether the lock has been/can be build or not.
@@ -151,7 +151,7 @@ public:
* Builds a canal on tile.
* @param tile The tile where the canal will be build.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_LAND_SLOPED_WRONG
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
@@ -164,7 +164,7 @@ public:
* Removes a water depot.
* @param tile Any tile of the water depot.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the water depot has been/can be removed or not.
*/
@@ -174,7 +174,7 @@ public:
* Removes a dock.
* @param tile Any tile of the dock.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the dock has been/can be removed or not.
*/
@@ -184,7 +184,7 @@ public:
* Removes a buoy.
* @param tile Any tile of the buoy.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the buoy has been/can be removed or not.
*/
@@ -194,7 +194,7 @@ public:
* Removes a lock.
* @param tile Any tile of the lock.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the lock has been/can be removed or not.
*/
@@ -204,7 +204,7 @@ public:
* Removes a canal.
* @param tile Any tile of the canal.
* @pre ScriptMap::IsValidTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return Whether the canal has been/can be removed or not.
*/

View File

@@ -24,9 +24,9 @@ ScriptNewGRFList::ScriptNewGRFList()
}
}
/* static */ bool ScriptNewGRF::IsLoaded(uint32 grfid)
/* static */ bool ScriptNewGRF::IsLoaded(SQInteger grfid)
{
grfid = BSWAP32(grfid); // Match people's expectations.
grfid = BSWAP32(GB(grfid, 0, 32)); // Match people's expectations.
for (auto c = _grfconfig; c != nullptr; c = c->next) {
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
@@ -37,9 +37,9 @@ ScriptNewGRFList::ScriptNewGRFList()
return false;
}
/* static */ uint32 ScriptNewGRF::GetVersion(uint32 grfid)
/* static */ SQInteger ScriptNewGRF::GetVersion(SQInteger grfid)
{
grfid = BSWAP32(grfid); // Match people's expectations.
grfid = BSWAP32(GB(grfid, 0, 32)); // Match people's expectations.
for (auto c = _grfconfig; c != nullptr; c = c->next) {
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
@@ -50,15 +50,15 @@ ScriptNewGRFList::ScriptNewGRFList()
return 0;
}
/* static */ char *ScriptNewGRF::GetName(uint32 grfid)
/* static */ std::optional<std::string> ScriptNewGRF::GetName(SQInteger grfid)
{
grfid = BSWAP32(grfid); // Match people's expectations.
grfid = BSWAP32(GB(grfid, 0, 32)); // Match people's expectations.
for (auto c = _grfconfig; c != nullptr; c = c->next) {
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
return ::stredup(c->GetName());
return c->GetName();
}
}
return nullptr;
return std::nullopt;
}

View File

@@ -34,7 +34,7 @@ public:
* @param grfid The grfid to check.
* @return True if and only if a NewGRF with the given grfid is loaded in the game.
*/
static bool IsLoaded(uint32 grfid);
static bool IsLoaded(SQInteger grfid);
/**
* Get the version of a loaded NewGRF.
@@ -42,7 +42,7 @@ public:
* @pre ScriptNewGRF::IsLoaded(grfid).
* @return Version of the NewGRF or 0 if the NewGRF specifies no version.
*/
static uint32 GetVersion(uint32 grfid);
static SQInteger GetVersion(SQInteger grfid);
/**
* Get the name of a loaded NewGRF.
@@ -50,7 +50,7 @@ public:
* @pre ScriptNewGRF::IsLoaded(grfid).
* @return The name of the NewGRF or null if no name is defined.
*/
static char *GetName(uint32 grfid);
static std::optional<std::string> GetName(SQInteger grfid);
};
#endif /* SCRIPT_NEWGRF_HPP */

View File

@@ -20,12 +20,13 @@
#include "../../safeguards.h"
/* static */ bool ScriptNews::Create(NewsType type, Text *text, ScriptCompany::CompanyID company, NewsReferenceType ref_type, uint32 reference)
/* static */ bool ScriptNews::Create(NewsType type, Text *text, ScriptCompany::CompanyID company, NewsReferenceType ref_type, SQInteger reference)
{
CCountedPtr<Text> counter(text);
EnforceDeityMode(false);
EnforcePrecondition(false, text != nullptr);
const char *encoded = text->GetEncodedText();
std::string encoded = text->GetEncodedText();
EnforcePreconditionEncodedText(false, encoded);
EnforcePrecondition(false, type == NT_ECONOMY || type == NT_SUBSIDIES || type == NT_GENERAL);
EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID);
@@ -35,7 +36,7 @@
(ref_type == NR_INDUSTRY && ScriptIndustry::IsValidIndustry(reference)) ||
(ref_type == NR_TOWN && ScriptTown::IsValidTown(reference)));
uint8 c = company;
uint8_t c = company;
if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
if (ref_type == NR_NONE) reference = 0;

View File

@@ -62,8 +62,9 @@ public:
* @pre text != null.
* @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID.
* @pre The \a reference condition must be fulfilled.
* @pre ScriptCompanyMode::IsDeity().
*/
static bool Create(NewsType type, Text *text, ScriptCompany::CompanyID company, NewsReferenceType ref_type, uint32 reference);
static bool Create(NewsType type, Text *text, ScriptCompany::CompanyID company, NewsReferenceType ref_type, SQInteger reference);
};
#endif /* SCRIPT_NEWS_HPP */

View File

@@ -82,6 +82,22 @@ ScriptObject::ActiveInstance::~ActiveInstance()
return GetStorage()->mode_instance;
}
/* static */ void ScriptObject::SetDoCommandAsyncMode(ScriptAsyncModeProc *proc, ScriptObject *instance)
{
GetStorage()->async_mode = proc;
GetStorage()->async_mode_instance = instance;
}
/* static */ ScriptAsyncModeProc *ScriptObject::GetDoCommandAsyncMode()
{
return GetStorage()->async_mode;
}
/* static */ ScriptObject *ScriptObject::GetDoCommandAsyncModeInstance()
{
return GetStorage()->async_mode_instance;
}
/* static */ void ScriptObject::SetLastCommand(const CommandDataBuffer &data, Commands cmd)
{
ScriptStorage *s = GetStorage();
@@ -184,6 +200,16 @@ ScriptObject::ActiveInstance::~ActiveInstance()
return GetStorage()->allow_do_command;
}
/* static */ void ScriptObject::SetTimeMode(bool calendar)
{
GetStorage()->time_mode = calendar;
}
/* static */ bool ScriptObject::IsCalendarTimeMode()
{
return GetStorage()->time_mode;
}
/* static */ void ScriptObject::SetCompany(CompanyID company)
{
if (GetStorage()->root_company == INVALID_OWNER) GetStorage()->root_company = company;
@@ -213,17 +239,14 @@ ScriptObject::ActiveInstance::~ActiveInstance()
return GetStorage()->event_data;
}
/* static */ void *&ScriptObject::GetLogPointer()
/* static */ ScriptLogTypes::LogData &ScriptObject::GetLogData()
{
return GetStorage()->log_data;
}
/* static */ char *ScriptObject::GetString(StringID string)
/* static */ std::string ScriptObject::GetString(StringID string)
{
char buffer[64];
::GetString(buffer, string, lastof(buffer));
::StrMakeValidInPlace(buffer, lastof(buffer), SVS_NONE);
return ::stredup(buffer);
return ::StrMakeValid(::GetString(string));
}
/* static */ void ScriptObject::SetCallbackVariable(int index, int value)
@@ -242,7 +265,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
return ScriptObject::GetActiveInstance()->GetDoCommandCallback();
}
std::tuple<bool, bool, bool> ScriptObject::DoCommandPrep()
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.");
@@ -251,17 +274,20 @@ std::tuple<bool, bool, bool> ScriptObject::DoCommandPrep()
/* Are we only interested in the estimate costs? */
bool estimate_only = GetDoCommandMode() != nullptr && !GetDoCommandMode()();
/* Should the command be executed asynchronously? */
bool asynchronous = GetDoCommandAsyncMode() != nullptr && GetDoCommandAsyncMode()();
bool networking = _networking && !_generating_world;
if (ScriptObject::GetCompany() != OWNER_DEITY && !::Company::IsValidID(ScriptObject::GetCompany())) {
if (!ScriptCompanyMode::IsDeity() && !ScriptCompanyMode::IsValid()) {
ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY);
return { true, estimate_only, networking };
return { true, estimate_only, asynchronous, networking };
}
return { false, estimate_only, networking };
return { false, estimate_only, asynchronous, networking };
}
bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only)
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;
@@ -285,8 +311,13 @@ bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_Suspend
SetLastCost(res.GetCost());
SetLastCommandRes(true);
if (_generating_world) {
if (_generating_world || asynchronous) {
IncreaseDoCommandCosts(res.GetCost());
if (!_generating_world) {
/* Charge a nominal fee for asynchronously executed commands */
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
* the return value in the stack should be used. */
@@ -309,3 +340,19 @@ bool ScriptObject::DoCommandProcessResult(const CommandCost &res, Script_Suspend
NOT_REACHED();
}
/* static */ Randomizer ScriptObject::random_states[OWNER_END];
Randomizer &ScriptObject::GetRandomizer(Owner owner)
{
return ScriptObject::random_states[owner];
}
void ScriptObject::InitializeRandomizers()
{
Randomizer random = _random;
for (Owner owner = OWNER_BEGIN; owner < OWNER_END; owner++) {
ScriptObject::GetRandomizer(owner).SetSeed(random.Next());
}
}

View File

@@ -15,16 +15,25 @@
#include "../../rail_type.h"
#include "../../string_func.h"
#include "../../command_func.h"
#include "../../core/random_func.hpp"
#include "script_types.hpp"
#include "script_log_types.hpp"
#include "../script_suspend.hpp"
#include "../squirrel.hpp"
#include <utility>
/**
* The callback function for Mode-classes.
*/
typedef bool (ScriptModeProc)();
/**
* The callback function for Async Mode-classes.
*/
typedef bool (ScriptAsyncModeProc)();
/**
* Uper-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
@@ -35,6 +44,7 @@ typedef bool (ScriptModeProc)();
class ScriptObject : public SimpleCountedObject {
friend class ScriptInstance;
friend class ScriptController;
friend class TestScriptController;
protected:
/**
* A class that handles the current active instance. By instantiating it at
@@ -73,6 +83,18 @@ public:
*/
static class ScriptInstance *GetActiveInstance();
/**
* Get a reference of the randomizer that brings this script random values.
* @param owner The owner/script to get the randomizer for. This defaults to ScriptObject::GetRootCompany()
*/
static Randomizer &GetRandomizer(Owner owner = ScriptObject::GetRootCompany());
/**
* Initialize/reset the script random states. The state of the scripts are
* based on the current _random seed, but _random does not get changed.
*/
static void InitializeRandomizers();
protected:
template<Commands TCmd, typename T> struct ScriptDoCommandHelper;
@@ -172,6 +194,21 @@ protected:
*/
static ScriptObject *GetDoCommandModeInstance();
/**
* Set the current async mode of your script to this proc.
*/
static void SetDoCommandAsyncMode(ScriptAsyncModeProc *proc, ScriptObject *instance);
/**
* Get the current async mode your script is currently under.
*/
static ScriptModeProc *GetDoCommandAsyncMode();
/**
* Get the instance of the current async mode your script is currently under.
*/
static ScriptObject *GetDoCommandAsyncModeInstance();
/**
* Set the delay of the DoCommand.
*/
@@ -207,6 +244,20 @@ protected:
*/
static bool GetAllowDoCommand();
/**
* Set if the script is running in calendar time or economy time mode.
* Calendar time is used by OpenTTD for technology like vehicle introductions and expiration, and variable snowline. It can be sped up or slowed down by the player.
* Economy time always runs at the same pace and handles things like cargo production, everything related to money, etc.
* @param Calendar Should we use calendar time mode? (Set to false for economy time mode.)
*/
static void SetTimeMode(bool calendar);
/**
* Check if the script is operating in calendar time mode, or in economy time mode. See SetTimeMode() for more information.
* @return True if we are in calendar time mode, false if we are in economy time mode.
*/
static bool IsCalendarTimeMode();
/**
* Set the current company to execute commands for or request
* information about.
@@ -261,18 +312,19 @@ protected:
/**
* Get the pointer to store log message in.
*/
static void *&GetLogPointer();
static ScriptLogTypes::LogData &GetLogData();
/**
* Get an allocated string with all control codes stripped off.
*/
static char *GetString(StringID string);
static std::string GetString(StringID string);
private:
/* Helper functions for DoCommand. */
static std::tuple<bool, bool, bool> DoCommandPrep();
static bool DoCommandProcessResult(const CommandCost &res, Script_SuspendCallbackProc *callback, bool estimate_only);
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();
static Randomizer random_states[OWNER_END]; ///< Random states for each of the scripts (game script uses OWNER_DEITY)
};
namespace ScriptObjectInternal {
@@ -321,7 +373,7 @@ namespace ScriptObjectInternal {
template <Commands Tcmd, typename Tret, typename... Targs>
bool ScriptObject::ScriptDoCommandHelper<Tcmd, Tret(*)(DoCommandFlag, Targs...)>::Execute(Script_SuspendCallbackProc *callback, std::tuple<Targs...> args)
{
auto [err, estimate_only, networking] = ScriptObject::DoCommandPrep();
auto [err, estimate_only, asynchronous, networking] = ScriptObject::DoCommandPrep();
if (err) return false;
if ((::GetCommandFlags<Tcmd>() & CMD_STR_CTRL) == 0) {
@@ -334,7 +386,7 @@ bool ScriptObject::ScriptDoCommandHelper<Tcmd, Tret(*)(DoCommandFlag, Targs...)>
}
/* Do not even think about executing out-of-bounds tile-commands. */
if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (GetCommandFlags<Tcmd>() & CMD_ALL_TILES) == 0))) return false;
if (tile != 0 && (tile >= Map::Size() || (!IsValidTile(tile) && (GetCommandFlags<Tcmd>() & CMD_ALL_TILES) == 0))) return false;
/* Only set ClientID parameters when the command does not come from the network. */
if constexpr ((::GetCommandFlags<Tcmd>() & CMD_CLIENT_ID) != 0) ScriptObjectInternal::SetClientIds(args, std::index_sequence_for<Targs...>{});
@@ -346,11 +398,75 @@ bool ScriptObject::ScriptDoCommandHelper<Tcmd, Tret(*)(DoCommandFlag, Targs...)>
Tret res = ::Command<Tcmd>::Unsafe((StringID)0, networking ? ScriptObject::GetDoCommandCallback() : nullptr, false, estimate_only, tile, args);
if constexpr (std::is_same_v<Tret, CommandCost>) {
return ScriptObject::DoCommandProcessResult(res, callback, estimate_only);
return ScriptObject::DoCommandProcessResult(res, callback, estimate_only, asynchronous);
} else {
ScriptObject::SetLastCommandResData(EndianBufferWriter<CommandDataBuffer>::FromValue(ScriptObjectInternal::RemoveFirstTupleElement(res)));
return ScriptObject::DoCommandProcessResult(std::get<0>(res), callback, estimate_only);
return ScriptObject::DoCommandProcessResult(std::get<0>(res), callback, estimate_only, asynchronous);
}
}
/**
* Internally used class to automate the ScriptObject reference counting.
* @api -all
*/
template <typename T>
class ScriptObjectRef {
private:
T *data; ///< The reference counted object.
public:
/**
* Create the reference counter for the given ScriptObject instance.
* @param data The underlying object.
*/
ScriptObjectRef(T *data) : data(data)
{
this->data->AddRef();
}
/* No copy constructor. */
ScriptObjectRef(const ScriptObjectRef<T> &ref) = delete;
/* Move constructor. */
ScriptObjectRef(ScriptObjectRef<T> &&ref) noexcept : data(std::exchange(ref.data, nullptr))
{
}
/* No copy assignment. */
ScriptObjectRef& operator=(const ScriptObjectRef<T> &other) = delete;
/* Move assignment. */
ScriptObjectRef& operator=(ScriptObjectRef<T> &&other) noexcept
{
std::swap(this->data, other.data);
return *this;
}
/**
* Release the reference counted object.
*/
~ScriptObjectRef()
{
if (this->data != nullptr) this->data->Release();
}
/**
* Dereferencing this reference returns a reference to the reference
* counted object
* @return Reference to the underlying object.
*/
T &operator*()
{
return *this->data;
}
/**
* The arrow operator on this reference returns the reference counted object.
* @return Pointer to the underlying object.
*/
T *operator->()
{
return this->data;
}
};
#endif /* SCRIPT_OBJECT_HPP */

View File

@@ -19,36 +19,38 @@
/* static */ bool ScriptObjectType::IsValidObjectType(ObjectType object_type)
{
if (object_type >= NUM_OBJECTS) return false;
if (object_type >= ObjectSpec::Count()) return false;
return ObjectSpec::Get(object_type)->IsEverAvailable();
}
/* static */ char *ScriptObjectType::GetName(ObjectType object_type)
/* static */ std::optional<std::string> ScriptObjectType::GetName(ObjectType object_type)
{
EnforcePrecondition(nullptr, IsValidObjectType(object_type));
EnforcePrecondition(std::nullopt, IsValidObjectType(object_type));
return GetString(ObjectSpec::Get(object_type)->name);
}
/* static */ uint8 ScriptObjectType::GetViews(ObjectType object_type)
/* static */ SQInteger ScriptObjectType::GetViews(ObjectType object_type)
{
EnforcePrecondition(0, IsValidObjectType(object_type));
return ObjectSpec::Get(object_type)->views;
}
/* static */ bool ScriptObjectType::BuildObject(ObjectType object_type, uint8 view, TileIndex tile)
/* static */ bool ScriptObjectType::BuildObject(ObjectType object_type, SQInteger view, TileIndex tile)
{
EnforceDeityOrCompanyModeValid(false);
EnforcePrecondition(false, IsValidObjectType(object_type));
EnforcePrecondition(false, view >= 0 && view < GetViews(object_type));
EnforcePrecondition(false, ScriptMap::IsValidTile(tile));
return ScriptObject::Command<CMD_BUILD_OBJECT>::Do(tile, object_type, view);
}
/* static */ ObjectType ScriptObjectType::ResolveNewGRFID(uint32 grfid, uint16 grf_local_id)
/* static */ ObjectType ScriptObjectType::ResolveNewGRFID(SQInteger grfid, SQInteger grf_local_id)
{
EnforcePrecondition(INVALID_OBJECT_TYPE, IsInsideBS(grf_local_id, 0x00, NUM_OBJECTS_PER_GRF));
grfid = BSWAP32(grfid); // Match people's expectations.
grfid = BSWAP32(GB(grfid, 0, 32)); // Match people's expectations.
return _object_mngr.GetID(grf_local_id, grfid);
}

View File

@@ -33,7 +33,7 @@ public:
* @pre IsValidObjectType(object_type).
* @return The name of an object.
*/
static char *GetName(ObjectType object_type);
static std::optional<std::string> GetName(ObjectType object_type);
/**
* Get the number of views for an object-type.
@@ -41,7 +41,7 @@ public:
* @pre IsValidObjectType(object_type).
* @return The number of views for an object.
*/
static uint8 GetViews(ObjectType object_type);
static SQInteger GetViews(ObjectType object_type);
/**
* Build an object of the specified type.
@@ -51,7 +51,7 @@ public:
* @pre IsValidObjectType(object_type).
* @return True if the object was successfully build.
*/
static bool BuildObject(ObjectType object_type, uint8 view, TileIndex tile);
static bool BuildObject(ObjectType object_type, SQInteger view, TileIndex tile);
/**
* Get a specific object-type from a grf.
@@ -60,7 +60,7 @@ public:
* @pre 0x00 <= grf_local_id < NUM_OBJECTS_PER_GRF.
* @return the object-type ID, local to the current game (this diverges from the grf_local_id).
*/
static ObjectType ResolveNewGRFID(uint32 grfid, uint16 grf_local_id);
static ObjectType ResolveNewGRFID(SQInteger grfid, SQInteger grf_local_id);
};
#endif /* SCRIPT_OBJECTTYPE_HPP */

View File

@@ -15,9 +15,8 @@
ScriptObjectTypeList::ScriptObjectTypeList()
{
for (int i = 0; i < NUM_OBJECTS; i++) {
const ObjectSpec *spec = ObjectSpec::Get(i);
if (!spec->IsEverAvailable()) continue;
this->AddItem(i);
for (const auto &spec : ObjectSpec::Specs()) {
if (!spec.IsEverAvailable()) continue;
this->AddItem(spec.Index());
}
}

View File

@@ -50,7 +50,7 @@ static OrderType GetOrderTypeByTile(TileIndex t)
/* static */ bool ScriptOrder::IsValidVehicleOrder(VehicleID vehicle_id, OrderPosition order_position)
{
return ScriptVehicle::IsValidVehicle(vehicle_id) && order_position >= 0 && (order_position < ::Vehicle::Get(vehicle_id)->GetNumManualOrders() || order_position == ORDER_CURRENT);
return ScriptVehicle::IsPrimaryVehicle(vehicle_id) && order_position >= 0 && (order_position < ::Vehicle::Get(vehicle_id)->GetNumManualOrders() || order_position == ORDER_CURRENT);
}
/**
@@ -68,6 +68,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, ScriptOrder::OrderPositio
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);
@@ -92,6 +93,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
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);
@@ -132,6 +134,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position));
assert(order != nullptr);
return order->GetType() == OT_CONDITIONAL;
}
@@ -141,6 +144,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
const Order *order = ::ResolveOrder(vehicle_id, order_position);
assert(order != nullptr);
return order->GetType() == OT_DUMMY;
}
@@ -154,7 +158,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ bool ScriptOrder::IsCurrentOrderPartOfOrderList(VehicleID vehicle_id)
{
if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return false;
if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return false;
if (GetOrderCount(vehicle_id) == 0) return false;
const Order *order = &::Vehicle::Get(vehicle_id)->current_order;
@@ -164,7 +168,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ ScriptOrder::OrderPosition ScriptOrder::ResolveOrderPosition(VehicleID vehicle_id, OrderPosition order_position)
{
if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return ORDER_INVALID;
if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return ORDER_INVALID;
int num_manual_orders = ::Vehicle::Get(vehicle_id)->GetNumManualOrders();
if (num_manual_orders == 0) return ORDER_INVALID;
@@ -172,6 +176,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (order_position == ORDER_CURRENT) {
int cur_order_pos = ::Vehicle::Get(vehicle_id)->cur_real_order_index;
const Order *order = ::Vehicle::Get(vehicle_id)->GetFirstOrder();
assert(order != nullptr);
int num_implicit_orders = 0;
for (int i = 0; i < cur_order_pos; i++) {
if (order->GetType() == OT_IMPLICIT) num_implicit_orders++;
@@ -229,9 +234,9 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
}
}
/* static */ int32 ScriptOrder::GetOrderCount(VehicleID vehicle_id)
/* static */ SQInteger ScriptOrder::GetOrderCount(VehicleID vehicle_id)
{
return ScriptVehicle::IsValidVehicle(vehicle_id) ? ::Vehicle::Get(vehicle_id)->GetNumManualOrders() : -1;
return ScriptVehicle::IsPrimaryVehicle(vehicle_id) ? ::Vehicle::Get(vehicle_id)->GetNumManualOrders() : -1;
}
/* static */ TileIndex ScriptOrder::GetOrderDestination(VehicleID vehicle_id, OrderPosition order_position)
@@ -344,13 +349,13 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
return (CompareFunction)order->GetConditionComparator();
}
/* static */ int32 ScriptOrder::GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position)
/* static */ SQInteger ScriptOrder::GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position)
{
if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1;
if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return -1;
const Order *order = ::ResolveOrder(vehicle_id, order_position);
int32 value = order->GetConditionValue();
SQInteger value = order->GetConditionValue();
if (order->GetConditionVariable() == OCV_MAX_SPEED) value = value * 16 / 10;
return value;
}
@@ -367,15 +372,16 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ CargoID ScriptOrder::GetOrderRefit(VehicleID vehicle_id, OrderPosition order_position)
{
if (!IsValidVehicleOrder(vehicle_id, order_position)) return CT_NO_REFIT;
if (order_position != ORDER_CURRENT && !IsGotoStationOrder(vehicle_id, order_position) && !IsGotoDepotOrder(vehicle_id, order_position)) return CT_NO_REFIT;
if (!IsValidVehicleOrder(vehicle_id, order_position)) return CARGO_NO_REFIT;
if (order_position != ORDER_CURRENT && !IsGotoStationOrder(vehicle_id, order_position) && !IsGotoDepotOrder(vehicle_id, order_position)) return CARGO_NO_REFIT;
const Order *order = ::ResolveOrder(vehicle_id, order_position);
return order->IsRefit() ? order->GetRefitCargo() : (CargoID)CT_NO_REFIT;
return order->IsRefit() ? order->GetRefitCargo() : CARGO_NO_REFIT;
}
/* static */ bool ScriptOrder::SetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT);
@@ -385,6 +391,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ bool ScriptOrder::SetOrderCondition(VehicleID vehicle_id, OrderPosition order_position, OrderCondition condition)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
EnforcePrecondition(false, condition >= OC_LOAD_PERCENTAGE && condition <= OC_REMAINING_LIFETIME);
@@ -395,6 +402,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ bool ScriptOrder::SetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position, CompareFunction compare)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
EnforcePrecondition(false, compare >= CF_EQUALS && compare <= CF_IS_FALSE);
@@ -403,8 +411,9 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
return ScriptObject::Command<CMD_MODIFY_ORDER>::Do(0, vehicle_id, order_pos, MOF_COND_COMPARATOR, compare);
}
/* static */ bool ScriptOrder::SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, int32 value)
/* static */ bool ScriptOrder::SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, SQInteger value)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position));
EnforcePrecondition(false, value >= 0 && value < 2048);
@@ -416,6 +425,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ bool ScriptOrder::SetStopLocation(VehicleID vehicle_id, OrderPosition order_position, StopLocation stop_location)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
EnforcePrecondition(false, ScriptVehicle::GetVehicleType(vehicle_id) == ScriptVehicle::VT_RAIL);
EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position));
@@ -429,16 +439,18 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ bool ScriptOrder::SetOrderRefit(VehicleID vehicle_id, OrderPosition order_position, CargoID refit_cargo)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position) || (IsGotoDepotOrder(vehicle_id, order_position) && refit_cargo != CT_AUTO_REFIT));
EnforcePrecondition(false, ScriptCargo::IsValidCargo(refit_cargo) || refit_cargo == CT_AUTO_REFIT || refit_cargo == CT_NO_REFIT);
EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position) || (IsGotoDepotOrder(vehicle_id, order_position) && refit_cargo != CARGO_AUTO_REFIT));
EnforcePrecondition(false, ScriptCargo::IsValidCargo(refit_cargo) || refit_cargo == CARGO_AUTO_REFIT || refit_cargo == CARGO_NO_REFIT);
return ScriptObject::Command<CMD_ORDER_REFIT>::Do(0, vehicle_id, ScriptOrderPositionToRealOrderPosition(vehicle_id, ScriptOrder::ResolveOrderPosition(vehicle_id, order_position)), refit_cargo);
}
/* static */ bool ScriptOrder::AppendOrder(VehicleID vehicle_id, TileIndex destination, ScriptOrderFlags order_flags)
{
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
return InsertOrder(vehicle_id, (ScriptOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), destination, order_flags);
@@ -446,7 +458,8 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* static */ bool ScriptOrder::AppendConditionalOrder(VehicleID vehicle_id, OrderPosition jump_to)
{
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to));
return InsertConditionalOrder(vehicle_id, (ScriptOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), jump_to);
@@ -457,7 +470,8 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* IsValidVehicleOrder is not good enough because it does not allow appending. */
if (order_position == ORDER_CURRENT) order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position);
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders());
EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags));
@@ -511,7 +525,8 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
/* IsValidVehicleOrder is not good enough because it does not allow appending. */
if (order_position == ORDER_CURRENT) order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position);
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders());
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT);
@@ -526,6 +541,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
{
order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position);
@@ -536,6 +552,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
{
next_order = ScriptOrder::ResolveOrderPosition(vehicle_id, next_order);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, next_order));
int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, next_order);
@@ -572,6 +589,7 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance)
order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position));
EnforcePrecondition(false, AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags));
@@ -629,6 +647,7 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance)
order_position_move = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position_move);
order_position_target = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position_target);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_move));
EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_target));
EnforcePrecondition(false, order_position_move != order_position_target);
@@ -640,28 +659,31 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance)
/* static */ bool ScriptOrder::CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
{
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(main_vehicle_id));
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(main_vehicle_id));
return ScriptObject::Command<CMD_CLONE_ORDER>::Do(0, CO_COPY, vehicle_id, main_vehicle_id);
}
/* static */ bool ScriptOrder::ShareOrders(VehicleID vehicle_id, VehicleID main_vehicle_id)
{
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(main_vehicle_id));
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(main_vehicle_id));
return ScriptObject::Command<CMD_CLONE_ORDER>::Do(0, CO_SHARE, vehicle_id, main_vehicle_id);
}
/* static */ bool ScriptOrder::UnshareOrders(VehicleID vehicle_id)
{
EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptVehicle::IsPrimaryVehicle(vehicle_id));
return ScriptObject::Command<CMD_CLONE_ORDER>::Do(0, CO_UNSHARE, vehicle_id, 0);
}
/* static */ uint ScriptOrder::GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile)
/* static */ SQInteger ScriptOrder::GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile)
{
if (vehicle_type == ScriptVehicle::VT_AIR) {
if (ScriptTile::IsStationTile(origin_tile)) {

View File

@@ -142,7 +142,7 @@ public:
* Checks whether the given order id is valid for the given vehicle.
* @param vehicle_id The vehicle to check the order index for.
* @param order_position The order index to check.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @return True if and only if the order_position is valid for the given vehicle.
*/
static bool IsValidVehicleOrder(VehicleID vehicle_id, OrderPosition order_position);
@@ -207,7 +207,7 @@ public:
/**
* Checks whether the current order is part of the orderlist.
* @param vehicle_id The vehicle to check.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @return True if and only if the current order is part of the order list.
* @note If the order is a non-'non-stop' order, and the vehicle is currently
* (un)loading at a station that is not the final destination, this function
@@ -222,7 +222,7 @@ public:
* given index does not exist it will return ORDER_INVALID.
* @param vehicle_id The vehicle to check the order index for.
* @param order_position The order index to resolve.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @return The resolved order index.
*/
static OrderPosition ResolveOrderPosition(VehicleID vehicle_id, OrderPosition order_position);
@@ -246,11 +246,11 @@ public:
/**
* Returns the number of orders for the given vehicle.
* @param vehicle_id The vehicle to get the order count of.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @return The number of orders for the given vehicle or a negative
* value when the vehicle does not exist.
*/
static int32 GetOrderCount(VehicleID vehicle_id);
static SQInteger GetOrderCount(VehicleID vehicle_id);
/**
* Gets the destination of the given order for the given vehicle.
@@ -320,7 +320,7 @@ public:
* @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position).
* @return The value to compare against of the order.
*/
static int32 GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position);
static SQInteger GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position);
/**
* Gets the stoplocation of the given order for the given train.
@@ -356,8 +356,8 @@ public:
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre IsValidVehicleOrder(vehicle_id, jump_to).
* @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position).
* @game @pre ScriptCompanyMode::IsValid().
* @return Whether the order has been/can be changed.
* @api -game
*/
static bool SetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to);
@@ -369,8 +369,8 @@ public:
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position).
* @pre condition >= OC_LOAD_PERCENTAGE && condition <= OC_UNCONDITIONALLY.
* @game @pre ScriptCompanyMode::IsValid().
* @return Whether the order has been/can be changed.
* @api -game
*/
static bool SetOrderCondition(VehicleID vehicle_id, OrderPosition order_position, OrderCondition condition);
@@ -382,8 +382,8 @@ public:
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position).
* @pre compare >= CF_EQUALS && compare <= CF_IS_FALSE.
* @game @pre ScriptCompanyMode::IsValid().
* @return Whether the order has been/can be changed.
* @api -game
*/
static bool SetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position, CompareFunction compare);
@@ -395,10 +395,10 @@ public:
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position).
* @pre value >= 0 && value < 2048.
* @game @pre ScriptCompanyMode::IsValid().
* @return Whether the order has been/can be changed.
* @api -game
*/
static bool SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, int32 value);
static bool SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, SQInteger value);
/**
* Sets the stoplocation of the given order for the given train.
@@ -409,8 +409,8 @@ public:
* @pre ScriptVehicle::GetVehicleType(vehicle_id) == ScriptVehicle::VT_RAIL.
* @pre IsGotoStationOrder(vehicle_id, order_position).
* @pre stop_location >= STOPLOCATION_NEAR && stop_location <= STOPLOCATION_FAR
* @game @pre ScriptCompanyMode::IsValid().
* @return Whether the order has been/can be changed.
* @api -game
*/
static bool SetStopLocation(VehicleID vehicle_id, OrderPosition order_position, StopLocation stop_location);
@@ -422,8 +422,8 @@ public:
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre IsGotoStationOrder(vehicle_id, order_position) || (IsGotoDepotOrder(vehicle_id, order_position) && refit_cargo != CT_AUTO_REFIT).
* @pre ScriptCargo::IsValidCargo(refit_cargo) || refit_cargo == CT_AUTO_REFIT || refit_cargo == CT_NO_REFIT
* @game @pre ScriptCompanyMode::IsValid().
* @return Whether the order has been/can be changed.
* @api -game
*/
static bool SetOrderRefit(VehicleID vehicle_id, OrderPosition order_position, CargoID refit_cargo);
@@ -432,13 +432,13 @@ public:
* @param vehicle_id The vehicle to append the order to.
* @param destination The destination of the order.
* @param order_flags The flags given to the order.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @pre AreOrderFlagsValid(destination, order_flags).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptOrder::ERR_ORDER_TOO_MANY
* @exception ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION
* @return True if and only if the order was appended.
* @api -game
*/
static bool AppendOrder(VehicleID vehicle_id, TileIndex destination, ScriptOrderFlags order_flags);
@@ -446,12 +446,12 @@ public:
* Appends a conditional order to the end of the vehicle's order list.
* @param vehicle_id The vehicle to append the order to.
* @param jump_to The OrderPosition to jump to if the condition is true.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @pre IsValidVehicleOrder(vehicle_id, jump_to).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptOrder::ERR_ORDER_TOO_MANY
* @return True if and only if the order was appended.
* @api -game
*/
static bool AppendConditionalOrder(VehicleID vehicle_id, OrderPosition jump_to);
@@ -461,13 +461,14 @@ public:
* @param order_position The order to place the new order before.
* @param destination The destination of the order.
* @param order_flags The flags given to the order.
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id)
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre AreOrderFlagsValid(destination, order_flags).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptOrder::ERR_ORDER_TOO_MANY
* @exception ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION
* @return True if and only if the order was inserted.
* @api -game
*/
static bool InsertOrder(VehicleID vehicle_id, OrderPosition order_position, TileIndex destination, ScriptOrderFlags order_flags);
@@ -476,12 +477,13 @@ public:
* @param vehicle_id The vehicle to add the order to.
* @param order_position The order to place the new order before.
* @param jump_to The OrderPosition to jump to if the condition is true.
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre IsValidVehicleOrder(vehicle_id, jump_to).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptOrder::ERR_ORDER_TOO_MANY
* @return True if and only if the order was inserted.
* @api -game
*/
static bool InsertConditionalOrder(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to);
@@ -490,9 +492,9 @@ public:
* @param vehicle_id The vehicle to remove the order from.
* @param order_position The order to remove from the order list.
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return True if and only if the order was removed.
* @api -game
*/
static bool RemoveOrder(VehicleID vehicle_id, OrderPosition order_position);
@@ -510,9 +512,9 @@ public:
* @pre IsValidVehicleOrder(vehicle_id, order_position).
* @pre AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags).
* @pre (order_flags & OF_GOTO_NEAREST_DEPOT) == (GetOrderFlags(vehicle_id, order_position) & OF_GOTO_NEAREST_DEPOT).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return True if and only if the order was changed.
* @api -game
*/
static bool SetOrderFlags(VehicleID vehicle_id, OrderPosition order_position, ScriptOrderFlags order_flags);
@@ -524,13 +526,13 @@ public:
* @pre IsValidVehicleOrder(vehicle_id, order_position_move).
* @pre IsValidVehicleOrder(vehicle_id, order_position_target).
* @pre order_position_move != order_position_target.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return True if and only if the order was moved.
* @note If the order is moved to a lower place (e.g. from 7 to 2)
* the target order is moved upwards (e.g. 3). If the order is moved
* to a higher place (e.g. from 7 to 9) the target will be moved
* downwards (e.g. 8).
* @api -game
*/
static bool MoveOrder(VehicleID vehicle_id, OrderPosition order_position_move, OrderPosition order_position_target);
@@ -539,9 +541,9 @@ public:
* @param vehicle_id The vehicle that should skip some orders.
* @param next_order The order the vehicle should skip to.
* @pre IsValidVehicleOrder(vehicle_id, next_order).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @return True if and only the current order was changed.
* @api -game
*/
static bool SkipToOrder(VehicleID vehicle_id, OrderPosition next_order);
@@ -550,13 +552,13 @@ public:
* are going to be the orders of the changed vehicle.
* @param vehicle_id The vehicle to copy the orders to.
* @param main_vehicle_id The vehicle to copy the orders from.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsValidVehicle(main_vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(main_vehicle_id).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptOrder::ERR_ORDER_TOO_MANY
* @exception ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE
* @return True if and only if the copying succeeded.
* @api -game
*/
static bool CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id);
@@ -565,12 +567,12 @@ public:
* vehicle are going to be the orders of the changed vehicle.
* @param vehicle_id The vehicle to add to the shared order list.
* @param main_vehicle_id The vehicle to share the orders with.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsValidVehicle(main_vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(main_vehicle_id).
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE
* @return True if and only if the sharing succeeded.
* @api -game
*/
static bool ShareOrders(VehicleID vehicle_id, VehicleID main_vehicle_id);
@@ -578,9 +580,9 @@ public:
* Removes the given vehicle from a shared orders list.
* After unsharing orders, the orders list of the vehicle is empty.
* @param vehicle_id The vehicle to remove from the shared order list.
* @pre ScriptVehicle::IsValidVehicle(vehicle_id).
* @pre ScriptVehicle::IsPrimaryVehicle(vehicle_id).
* @game @pre ScriptCompanyMode::IsValid().
* @return True if and only if the unsharing succeeded.
* @api -game
*/
static bool UnshareOrders(VehicleID vehicle_id);
@@ -599,7 +601,7 @@ public:
* not be compared with map distances
* @see ScriptEngine::GetMaximumOrderDistance and ScriptVehicle::GetMaximumOrderDistance
*/
static uint GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile);
static SQInteger GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile);
};
DECLARE_ENUM_AS_BIT_SET(ScriptOrder::ScriptOrderFlags)

View File

@@ -35,7 +35,7 @@ ScriptPriorityQueue::~ScriptPriorityQueue()
SQInteger ScriptPriorityQueue::Insert(HSQUIRRELVM vm)
{
HSQOBJECT item;
int64 priority;
SQInteger priority;
sq_resetobject(&item);
sq_getstackobj(vm, 2, &item);
sq_getinteger(vm, 3, &priority);
@@ -45,7 +45,7 @@ SQInteger ScriptPriorityQueue::Insert(HSQUIRRELVM vm)
this->queue.emplace_back(priority, item);
std::push_heap(this->queue.begin(), this->queue.end(), this->comp);
return SQConvert::Return(vm, true);
return SQConvert::Return<bool>::Set(vm, true);
}
SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm)
@@ -61,7 +61,7 @@ SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm)
this->queue.pop_back();
/* Store the object on the Squirrel stack before releasing it to make sure the ref count can't drop to zero. */
auto ret = SQConvert::Return(vm, item);
auto ret = SQConvert::Return<HSQOBJECT>::Set(vm, item);
sq_release(vm, &item);
return ret;
}
@@ -74,7 +74,7 @@ SQInteger ScriptPriorityQueue::Peek(HSQUIRRELVM vm)
return 1;
}
return SQConvert::Return(vm, this->queue.front().second);
return SQConvert::Return<HSQOBJECT>::Set(vm, this->queue.front().second);
}
SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm)
@@ -83,7 +83,7 @@ SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm)
sq_resetobject(&item);
sq_getstackobj(vm, 2, &item);
return SQConvert::Return(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend());
return SQConvert::Return<bool>::Set(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend());
}
SQInteger ScriptPriorityQueue::Clear(HSQUIRRELVM vm)

View File

@@ -13,7 +13,6 @@
#include "script_object.hpp"
#include <utility>
#include <vector>
/**
* Class that creates a queue which keeps its items ordered by an item priority.
@@ -21,7 +20,7 @@
*/
class ScriptPriorityQueue : public ScriptObject {
public:
typedef std::pair<int64, HSQOBJECT> PriorityItem;
typedef std::pair<SQInteger, HSQOBJECT> PriorityItem;
private:
struct PriorityComparator {
bool operator()(const PriorityItem &lhs, const PriorityItem &rhs) const noexcept
@@ -43,7 +42,7 @@ public:
* @param priority The priority to assign the item.
* @return True if the item was inserted, false if it was already in the queue.
*/
bool Insert(void *item, int64 priority);
bool Insert(void *item, SQInteger priority);
/**
* Remove and return the item with the lowest priority.

View File

@@ -24,9 +24,9 @@
#include "../../safeguards.h"
/* static */ char *ScriptRail::GetName(RailType rail_type)
/* static */ std::optional<std::string> ScriptRail::GetName(RailType rail_type)
{
if (!IsRailTypeAvailable(rail_type)) return nullptr;
if (!IsRailTypeAvailable(rail_type)) return std::nullopt;
return GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text);
}
@@ -69,9 +69,10 @@
/* static */ bool ScriptRail::IsRailTypeAvailable(RailType rail_type)
{
EnforceDeityOrCompanyModeValid(false);
if ((::RailType)rail_type >= RAILTYPE_END) return false;
return ScriptObject::GetCompany() == OWNER_DEITY || ::HasRailtypeAvail(ScriptObject::GetCompany(), (::RailType)rail_type);
return ScriptCompanyMode::IsDeity() || ::HasRailTypeAvail(ScriptObject::GetCompany(), (::RailType)rail_type);
}
/* static */ ScriptRail::RailType ScriptRail::GetCurrentRailType()
@@ -111,7 +112,7 @@
/* static */ bool ScriptRail::ConvertRailType(TileIndex start_tile, TileIndex end_tile, ScriptRail::RailType convert_to)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(start_tile));
EnforcePrecondition(false, ::IsValidTile(end_tile));
EnforcePrecondition(false, IsRailTypeAvailable(convert_to));
@@ -135,7 +136,7 @@
/* static */ bool ScriptRail::BuildRailDepot(TileIndex tile, TileIndex front)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, tile != front);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(front));
@@ -147,9 +148,9 @@
return ScriptObject::Command<CMD_BUILD_TRAIN_DEPOT>::Do(tile, (::RailType)ScriptObject::GetRailType(), entrance_dir);
}
/* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id)
/* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
@@ -161,9 +162,9 @@
return ScriptObject::Command<CMD_BUILD_RAIL_STATION>::Do(tile, (::RailType)GetCurrentRailType(), direction == RAILTRACK_NW_SE ? AXIS_Y : AXIS_X, num_platforms, platform_length, STAT_CLASS_DFLT, 0, ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION, adjacent);
}
/* static */ bool ScriptRail::BuildNewGRFRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, int distance, bool source_station)
/* static */ bool ScriptRail::BuildNewGRFRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, SQInteger distance, bool source_station)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW);
EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF);
@@ -175,16 +176,16 @@
EnforcePrecondition(false, goal_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(goal_industry));
const GRFFile *file;
uint16 res = GetAiPurchaseCallbackResult(
uint16_t res = GetAiPurchaseCallbackResult(
GSF_STATIONS,
cargo_id,
0,
source_industry,
goal_industry,
std::min(255, distance / 2),
ClampTo<uint8_t>(distance / 2),
AICE_STATION_GET_STATION_ID,
source_station ? 0 : 1,
std::min(15u, num_platforms) << 4 | std::min(15u, platform_length),
std::min<SQInteger>(15u, num_platforms) << 4 | std::min<SQInteger>(15u, platform_length),
&file
);
@@ -207,7 +208,7 @@
/* static */ bool ScriptRail::BuildRailWaypoint(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsRailTile(tile));
EnforcePrecondition(false, GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE);
@@ -218,7 +219,7 @@
/* static */ bool ScriptRail::RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(tile2));
@@ -227,7 +228,7 @@
/* static */ bool ScriptRail::RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(tile2));
@@ -246,10 +247,10 @@
/* static */ bool ScriptRail::BuildRailTrack(TileIndex tile, RailTrack rail_track)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, rail_track != 0);
EnforcePrecondition(false, (rail_track & ~::TRACK_BIT_ALL) == 0);
EnforcePrecondition(false, (static_cast<uint>(rail_track) & ~static_cast<uint>(::TRACK_BIT_ALL)) == 0);
EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0);
EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType()));
@@ -258,7 +259,7 @@
/* static */ bool ScriptRail::RemoveRailTrack(TileIndex tile, RailTrack rail_track)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsPlainRailTile(tile) || ::IsLevelCrossingTile(tile));
EnforcePrecondition(false, GetRailTracks(tile) & rail_track);
@@ -276,11 +277,11 @@
if (tile - from == 1) {
if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NE_SW) != 0;
if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NE_SE) != 0;
} else if (tile - from == ::MapSizeX()) {
if (to - tile == (int)ScriptMap::GetMapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NE_SE) != 0;
} else if (tile - from == (int)ScriptMap::GetMapSizeX()) {
if (tile - to == 1) return (GetRailTracks(tile) & RAILTRACK_NW_NE) != 0;
if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NW_SW) != 0;
if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NW_SE) != 0;
if (to - tile == (int)ScriptMap::GetMapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NW_SE) != 0;
} else {
return (GetRailTracks(tile) & RAILTRACK_SW_SE) != 0;
}
@@ -301,7 +302,7 @@ static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
} else if (::TileX(from) == ::TileX(*to)) {
track = TRACK_Y;
*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
*to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
} else if (::TileY(from) < ::TileY(tile)) {
if (::TileX(*to) < ::TileX(tile)) {
track = TRACK_UPPER;
@@ -311,7 +312,7 @@ static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
if (diag_offset != 0) {
*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
} else {
*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
*to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
}
} else if (::TileY(from) > ::TileY(tile)) {
if (::TileX(*to) < ::TileX(tile)) {
@@ -322,7 +323,7 @@ static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
if (diag_offset != 0) {
*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
} else {
*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
*to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
}
} else if (::TileX(from) < ::TileX(tile)) {
if (::TileY(*to) < ::TileY(tile)) {
@@ -333,7 +334,7 @@ static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
if (diag_offset == 0) {
*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
} else {
*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
*to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
}
} else if (::TileX(from) > ::TileX(tile)) {
if (::TileY(*to) < ::TileY(tile)) {
@@ -344,7 +345,7 @@ static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
if (diag_offset == 0) {
*to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1);
} else {
*to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
*to -= ScriptMap::GetMapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1);
}
}
return track;
@@ -352,7 +353,7 @@ static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
/* static */ bool ScriptRail::BuildRail(TileIndex from, TileIndex tile, TileIndex to)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(from));
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(to));
@@ -370,7 +371,7 @@ static Track SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to)
/* static */ bool ScriptRail::RemoveRail(TileIndex from, TileIndex tile, TileIndex to)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(from));
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(to));
@@ -443,13 +444,13 @@ static bool IsValidSignalType(int signal_type)
/* static */ bool ScriptRail::BuildSignal(TileIndex tile, TileIndex front, SignalType signal)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
EnforcePrecondition(false, ::IsPlainRailTile(tile));
EnforcePrecondition(false, ::IsValidSignalType(signal));
Track track = INVALID_TRACK;
uint signal_cycles;
uint signal_cycles = 0;
int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile));
for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) {
@@ -468,12 +469,12 @@ static bool IsValidSignalType(int signal_type)
}
::SignalType sig_type = (::SignalType)(signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal);
return ScriptObject::Command<CMD_BUILD_SIGNALS>::Do(tile, track, sig_type, ::SIG_ELECTRIC, false, false, false, ::SIGTYPE_NORMAL, ::SIGTYPE_NORMAL, signal_cycles, 0);
return ScriptObject::Command<CMD_BUILD_SINGLE_SIGNAL>::Do(tile, track, sig_type, ::SIG_ELECTRIC, false, false, false, ::SIGTYPE_BLOCK, ::SIGTYPE_BLOCK, signal_cycles, 0);
}
/* static */ bool ScriptRail::RemoveSignal(TileIndex tile, TileIndex front)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1)
EnforcePrecondition(false, GetSignalType(tile, front) != SIGNALTYPE_NONE);
@@ -487,7 +488,7 @@ static bool IsValidSignalType(int signal_type)
}
EnforcePrecondition(false, track != INVALID_TRACK);
return ScriptObject::Command<CMD_REMOVE_SIGNALS>::Do(tile, track);
return ScriptObject::Command<CMD_REMOVE_SINGLE_SIGNAL>::Do(tile, track);
}
/* static */ Money ScriptRail::GetBuildCost(RailType railtype, BuildType build_type)
@@ -504,14 +505,14 @@ static bool IsValidSignalType(int signal_type)
}
}
/* static */ int32 ScriptRail::GetMaxSpeed(RailType railtype)
/* static */ SQInteger ScriptRail::GetMaxSpeed(RailType railtype)
{
if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1;
return ::GetRailTypeInfo((::RailType)railtype)->max_speed;
}
/* static */ uint16 ScriptRail::GetMaintenanceCostFactor(RailType railtype)
/* static */ SQInteger ScriptRail::GetMaintenanceCostFactor(RailType railtype)
{
if (!ScriptRail::IsRailTypeAvailable(railtype)) return 0;

View File

@@ -64,7 +64,7 @@ public:
*/
enum SignalType {
/* Note: these values represent part of the in-game SignalType enum */
SIGNALTYPE_NORMAL = ::SIGTYPE_NORMAL, ///< Normal signal.
SIGNALTYPE_NORMAL = ::SIGTYPE_BLOCK, ///< Block signal.
SIGNALTYPE_ENTRY = ::SIGTYPE_ENTRY, ///< Entry presignal.
SIGNALTYPE_EXIT = ::SIGTYPE_EXIT, ///< Exit signal.
SIGNALTYPE_COMBO = ::SIGTYPE_COMBO, ///< Combo signal.
@@ -101,7 +101,7 @@ public:
* means that the name could be something like "Maglev construction" instead
* of just "Maglev".
*/
static char *GetName(RailType rail_type);
static std::optional<std::string> GetName(RailType rail_type);
/**
* Checks whether the given tile is actually a tile with rail that can be
@@ -201,7 +201,7 @@ public:
* @pre ScriptMap::IsValidTile(start_tile).
* @pre ScriptMap::IsValidTile(end_tile).
* @pre IsRailTypeAvailable(convert_to).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRail::ERR_UNSUITABLE_TRACK
* @return Whether at least some rail has been converted successfully.
*/
@@ -231,7 +231,7 @@ public:
* @pre ScriptMap::IsValidTile(front).
* @pre 'tile' is not equal to 'front', but in a straight line of it.
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @return Whether the rail depot has been/can be build or not.
@@ -251,7 +251,7 @@ public:
* @pre num_platforms > 0 && num_platforms <= 255.
* @pre platform_length > 0 && platform_length <= 255.
* @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
@@ -260,7 +260,7 @@ public:
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
* @return Whether the station has been/can be build or not.
*/
static bool BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id);
static bool BuildRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id);
/**
* Build a NewGRF rail station. This calls callback 18 to let a NewGRF
@@ -288,7 +288,7 @@ public:
* @pre ScriptCargo::IsValidCargo(cargo_type)
* @pre source_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(source_industry).
* @pre goal_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(goal_industry).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
@@ -297,7 +297,7 @@ public:
* @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN
* @return Whether the station has been/can be build or not.
*/
static bool BuildNewGRFRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, int distance, bool source_station);
static bool BuildNewGRFRailStation(TileIndex tile, RailTrack direction, SQInteger num_platforms, SQInteger platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, SQInteger distance, bool source_station);
/**
* Build a rail waypoint.
@@ -306,7 +306,7 @@ public:
* @pre IsRailTile(tile).
* @pre GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE.
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
* @return Whether the rail waypoint has been/can be build or not.
*/
@@ -319,7 +319,7 @@ public:
* @param keep_rail Whether to keep the rail after removal.
* @pre IsValidTile(tile).
* @pre IsValidTile(tile2).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRail::ERR_UNSUITABLE_TRACK
* @return Whether at least one tile has been/can be cleared or not.
*/
@@ -332,7 +332,7 @@ public:
* @param keep_rail Whether to keep the rail after removal.
* @pre IsValidTile(tile).
* @pre IsValidTile(tile2).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRail::ERR_UNSUITABLE_TRACK
* @return Whether at least one tile has been/can be cleared or not.
*/
@@ -353,7 +353,7 @@ public:
* @param rail_track The RailTrack to build.
* @pre ScriptMap::IsValidTile(tile).
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_LAND_SLOPED_WRONG
* @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS
@@ -371,7 +371,7 @@ public:
* @param rail_track The RailTrack to remove.
* @pre ScriptMap::IsValidTile(tile).
* @pre (GetRailTracks(tile) & rail_track) != 0.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRail::ERR_UNSUITABLE_TRACK
* @return Whether the rail has been/can be removed or not.
* @note You can only remove a single track with this function so do not
@@ -404,7 +404,7 @@ public:
* (ScriptMap::GetTileX(from) == ScriptMap::GetTileX(tile) && ScriptMap::GetTileX(tile) == ScriptMap::GetTileX(to)) ||
* (ScriptMap::GetTileY(from) == ScriptMap::GetTileY(tile) && ScriptMap::GetTileY(tile) == ScriptMap::GetTileY(to)).
* @pre IsRailTypeAvailable(GetCurrentRailType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_LAND_SLOPED_WRONG
* @exception ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD
@@ -427,7 +427,7 @@ public:
* abs(ScriptMap::GetTileY(to) - ScriptMap::GetTileY(tile))) <= 1) ||
* (ScriptMap::GetTileX(from) == ScriptMap::GetTileX(tile) && ScriptMap::GetTileX(tile) == ScriptMap::GetTileX(to)) ||
* (ScriptMap::GetTileY(from) == ScriptMap::GetTileY(tile) && ScriptMap::GetTileY(tile) == ScriptMap::GetTileY(to)).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRail::ERR_UNSUITABLE_TRACK
* @return Whether the rail has been/can be removed or not.
*/
@@ -449,7 +449,7 @@ public:
* @param signal The SignalType to build.
* @pre ScriptMap::DistanceManhattan(tile, front) == 1.
* @pre IsRailTile(tile) && !IsRailStationTile(tile) && !IsRailWaypointTile(tile).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRail::ERR_UNSUITABLE_TRACK
* @return Whether the signal has been/can be build or not.
*/
@@ -461,7 +461,7 @@ public:
* @param front The tile in front of the signal.
* @pre ScriptMap::DistanceManhattan(tile, front) == 1.
* @pre GetSignalType(tile, front) != SIGNALTYPE_NONE.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRail::ERR_UNSUITABLE_TRACK
* @return Whether the signal has been/can be removed or not.
*/
@@ -486,7 +486,7 @@ public:
* This is mph / 1.6, which is roughly km/h.
* To get km/h multiply this number by 1.00584.
*/
static int32 GetMaxSpeed(RailType railtype);
static SQInteger GetMaxSpeed(RailType railtype);
/**
* Get the maintenance cost factor of a railtype.
@@ -494,7 +494,7 @@ public:
* @pre IsRailTypeAvailable(railtype)
* @return Maintenance cost factor of the railtype.
*/
static uint16 GetMaintenanceCostFactor(RailType railtype);
static SQInteger GetMaintenanceCostFactor(RailType railtype);
};
#endif /* SCRIPT_RAIL_HPP */

View File

@@ -9,13 +9,17 @@
#include "../../stdafx.h"
#include "script_railtypelist.hpp"
#include "script_error.hpp"
#include "../../rail.h"
#include "../../safeguards.h"
ScriptRailTypeList::ScriptRailTypeList()
{
EnforceDeityOrCompanyModeValid_Void();
bool is_deity = ScriptCompanyMode::IsDeity();
CompanyID owner = ScriptObject::GetCompany();
for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
if (ScriptObject::GetCompany() == OWNER_DEITY || ::HasRailtypeAvail(ScriptObject::GetCompany(), rt)) this->AddItem(rt);
if (is_deity || ::HasRailTypeAvail(owner, rt)) this->AddItem(rt);
}
}

View File

@@ -15,6 +15,7 @@
#include "../../landscape_cmd.h"
#include "../../road_cmd.h"
#include "../../station_cmd.h"
#include "../../newgrf_roadstop.h"
#include "../../script/squirrel_helper_type.hpp"
#include "../../safeguards.h"
@@ -24,9 +25,9 @@
return ScriptCargo::HasCargoClass(cargo_type, ScriptCargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK;
}
/* static */ char *ScriptRoad::GetName(RoadType road_type)
/* static */ std::optional<std::string> ScriptRoad::GetName(RoadType road_type)
{
if (!IsRoadTypeAvailable(road_type)) return nullptr;
if (!IsRoadTypeAvailable(road_type)) return std::nullopt;
return GetString(GetRoadTypeInfo((::RoadType)road_type)->strings.name);
}
@@ -66,6 +67,7 @@
/* static */ bool ScriptRoad::IsRoadTypeAvailable(RoadType road_type)
{
EnforceDeityOrCompanyModeValid(false);
return (::RoadType)road_type < ROADTYPE_END && ::HasRoadTypeAvail(ScriptObject::GetCompany(), (::RoadType)road_type);
}
@@ -124,7 +126,7 @@
/* static */ bool ScriptRoad::ConvertRoadType(TileIndex start_tile, TileIndex end_tile, RoadType road_type)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(start_tile));
EnforcePrecondition(false, ::IsValidTile(end_tile));
EnforcePrecondition(false, IsRoadTypeAvailable(road_type));
@@ -148,9 +150,9 @@
* @param end The part that will be build second.
* @return True if and only if the road bits can be build.
*/
static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 end)
static bool CheckAutoExpandedRoadBits(const Array<> &existing, int32_t start, int32_t end)
{
return (start + end == 0) && (existing->size == 0 || existing->array[0] == start || existing->array[0] == end);
return (start + end == 0) && (existing.empty() || existing[0] == start || existing[0] == end);
}
/**
@@ -163,7 +165,7 @@ static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32
* they are build or 2 when building the first part automatically
* builds the second part.
*/
static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end)
static int32_t LookupWithoutBuildOnSlopes(::Slope slope, const Array<> &existing, int32_t start, int32_t end)
{
switch (slope) {
/* Flat slopes can always be build. */
@@ -175,9 +177,9 @@ static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, in
* in the game have been changed.
*/
case SLOPE_NE: case SLOPE_SW:
return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0;
return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing.empty() ? 2 : 1) : 0;
case SLOPE_SE: case SLOPE_NW:
return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0;
return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing.empty() ? 2 : 1) : 0;
/* Any other tile cannot be built on. */
default:
@@ -190,7 +192,7 @@ static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, in
* @param neighbour The neighbour.
* @return The rotate neighbour data.
*/
static int32 RotateNeighbour(int32 neighbour)
static int32_t RotateNeighbour(int32_t neighbour)
{
switch (neighbour) {
case -2: return -1;
@@ -206,7 +208,7 @@ static int32 RotateNeighbour(int32 neighbour)
* @param neighbour The neighbour.
* @return The bits representing the direction.
*/
static RoadBits NeighbourToRoadBits(int32 neighbour)
static RoadBits NeighbourToRoadBits(int32_t neighbour)
{
switch (neighbour) {
case -2: return ROAD_NW;
@@ -227,7 +229,7 @@ static RoadBits NeighbourToRoadBits(int32 neighbour)
* they are build or 2 when building the first part automatically
* builds the second part.
*/
static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end)
static int32_t LookupWithBuildOnSlopes(::Slope slope, const Array<> &existing, int32_t start, int32_t end)
{
/* Steep slopes behave the same as slopes with one corner raised. */
if (IsSteepSlope(slope)) {
@@ -277,9 +279,6 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start
/* Now perform the actual rotation. */
for (int j = 0; j < base_rotate; j++) {
for (size_t i = 0; i < existing->size; i++) {
existing->array[i] = RotateNeighbour(existing->array[i]);
}
start = RotateNeighbour(start);
end = RotateNeighbour(end);
}
@@ -288,8 +287,11 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start
RoadBits start_roadbits = NeighbourToRoadBits(start);
RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end);
RoadBits existing_roadbits = ROAD_NONE;
for (size_t i = 0; i < existing->size; i++) {
existing_roadbits |= NeighbourToRoadBits(existing->array[i]);
for (int32_t neighbour : existing) {
for (int j = 0; j < base_rotate; j++) {
neighbour = RotateNeighbour(neighbour);
}
existing_roadbits |= NeighbourToRoadBits(neighbour);
}
switch (slope) {
@@ -363,7 +365,7 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start
* @param tile The tile to normalise.
* @return True if and only if the tile offset is valid.
*/
static bool NormaliseTileOffset(int32 *tile)
static bool NormaliseTileOffset(int32_t *tile)
{
if (*tile == 1 || *tile == -1) return true;
if (*tile == ::TileDiffXY(0, -1)) {
@@ -377,17 +379,17 @@ static bool NormaliseTileOffset(int32 *tile)
return false;
}
/* static */ int32 ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array *existing, TileIndex start_, TileIndex end_)
/* static */ SQInteger ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> &&existing, TileIndex start_, TileIndex end_)
{
::Slope slope = (::Slope)slope_;
int32 start = start_;
int32 end = end_;
int32_t start = start_.base();
int32_t end = end_.base();
/* The start tile and end tile cannot be the same tile either. */
if (start == end) return -1;
for (size_t i = 0; i < existing->size; i++) {
if (!NormaliseTileOffset(&existing->array[i])) return -1;
for (size_t i = 0; i < existing.size(); i++) {
if (!NormaliseTileOffset(&existing[i])) return -1;
}
if (!NormaliseTileOffset(&start)) return -1;
@@ -398,15 +400,13 @@ static bool NormaliseTileOffset(int32 *tile)
return _settings_game.construction.build_on_slopes ? LookupWithBuildOnSlopes(slope, existing, start, end) : LookupWithoutBuildOnSlopes(slope, existing, start, end);
}
/* static */ int32 ScriptRoad::CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end)
/* static */ SQInteger ScriptRoad::CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end)
{
if (!::IsValidTile(tile) || !::IsValidTile(start) || !::IsValidTile(end)) return -1;
if (::DistanceManhattan(tile, start) != 1 || ::DistanceManhattan(tile, end) != 1) return -1;
/* ROAD_NW ROAD_SW ROAD_SE ROAD_NE */
const TileIndexDiff neighbours[] = {::TileDiffXY(0, -1), ::TileDiffXY(1, 0), ::TileDiffXY(0, 1), ::TileDiffXY(-1, 0)};
Array *existing = (Array*)alloca(sizeof(Array) + lengthof(neighbours) * sizeof(int32));
existing->size = 0;
::RoadBits rb = ::ROAD_NONE;
if (::IsNormalRoadTile(tile)) {
@@ -414,11 +414,13 @@ static bool NormaliseTileOffset(int32 *tile)
} else {
rb = ::GetAnyRoadBits(tile, RTT_ROAD) | ::GetAnyRoadBits(tile, RTT_TRAM);
}
Array<> existing;
for (uint i = 0; i < lengthof(neighbours); i++) {
if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i];
if (HasBit(rb, i)) existing.emplace_back(neighbours[i]);
}
return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), existing, start - tile, end - tile);
return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), std::move(existing), start - tile, end - tile);
}
/**
@@ -449,13 +451,13 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
}
}
/* static */ int32 ScriptRoad::GetNeighbourRoadCount(TileIndex tile)
/* static */ SQInteger ScriptRoad::GetNeighbourRoadCount(TileIndex tile)
{
if (!::IsValidTile(tile)) return false;
if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
if (!::IsValidTile(tile)) return -1;
if (!IsRoadTypeAvailable(GetCurrentRoadType())) return -1;
::RoadType rt = (::RoadType)GetCurrentRoadType();
int32 neighbour = 0;
int32_t neighbour = 0;
if (TileX(tile) > 0 && NeighbourHasReachableRoad(rt, tile, DIAGDIR_NE)) neighbour++;
if (NeighbourHasReachableRoad(rt, tile, DIAGDIR_SE)) neighbour++;
@@ -488,6 +490,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::_BuildRoadInternal(TileIndex start, TileIndex end, bool one_way, bool full)
{
EnforceDeityOrCompanyModeValid(false);
EnforcePrecondition(false, start != end);
EnforcePrecondition(false, ::IsValidTile(start));
EnforcePrecondition(false, ::IsValidTile(end));
@@ -506,7 +509,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::BuildOneWayRoad(TileIndex start, TileIndex end)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
return _BuildRoadInternal(start, end, true, false);
}
@@ -517,13 +520,13 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::BuildOneWayRoadFull(TileIndex start, TileIndex end)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
return _BuildRoadInternal(start, end, true, true);
}
/* static */ bool ScriptRoad::BuildRoadDepot(TileIndex tile, TileIndex front)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, tile != front);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(front));
@@ -537,7 +540,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, tile != front);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, ::IsValidTile(front));
@@ -549,7 +552,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
DiagDirection entrance_dir = DiagdirBetweenTiles(tile, front);
RoadStopType stop_type = road_veh_type == ROADVEHTYPE_TRUCK ? ROADSTOP_TRUCK : ROADSTOP_BUS;
StationID to_join = ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION;
return ScriptObject::Command<CMD_BUILD_ROAD_STOP>::Do(tile, 1, 1, stop_type, drive_through, entrance_dir, ScriptObject::GetRoadType(), to_join, station_id != ScriptStation::STATION_JOIN_ADJACENT);
return ScriptObject::Command<CMD_BUILD_ROAD_STOP>::Do(tile, 1, 1, stop_type, drive_through, entrance_dir, ScriptObject::GetRoadType(), ROADSTOP_CLASS_DFLT, 0, to_join, station_id != ScriptStation::STATION_JOIN_ADJACENT);
}
/* static */ bool ScriptRoad::BuildRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id)
@@ -564,7 +567,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::RemoveRoad(TileIndex start, TileIndex end)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, start != end);
EnforcePrecondition(false, ::IsValidTile(start));
EnforcePrecondition(false, ::IsValidTile(end));
@@ -576,7 +579,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::RemoveRoadFull(TileIndex start, TileIndex end)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, start != end);
EnforcePrecondition(false, ::IsValidTile(start));
EnforcePrecondition(false, ::IsValidTile(end));
@@ -588,7 +591,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::RemoveRoadDepot(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsTileType(tile, MP_ROAD))
EnforcePrecondition(false, GetRoadTileType(tile) == ROAD_TILE_DEPOT);
@@ -598,7 +601,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
/* static */ bool ScriptRoad::RemoveRoadStation(TileIndex tile)
{
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforceCompanyModeValid(false);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsTileType(tile, MP_STATION));
EnforcePrecondition(false, IsRoadStop(tile));
@@ -624,14 +627,14 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
return (RoadTramTypes)(1 << ::GetRoadTramType((::RoadType)roadtype));
}
/* static */ int32 ScriptRoad::GetMaxSpeed(RoadType road_type)
/* static */ SQInteger ScriptRoad::GetMaxSpeed(RoadType road_type)
{
if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return 0;
if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return -1;
return GetRoadTypeInfo((::RoadType)road_type)->max_speed;
}
/* static */ uint16 ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype)
/* static */ SQInteger ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype)
{
if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return 0;

View File

@@ -11,6 +11,7 @@
#define SCRIPT_ROAD_HPP
#include "script_tile.hpp"
#include "../squirrel_helper_type.hpp"
#include "../../../road.h"
/**
@@ -60,7 +61,7 @@ public:
/**
* Road/tram types
*/
enum RoadTramTypes : uint8 {
enum RoadTramTypes : uint8_t {
ROADTRAMTYPES_ROAD = ::RTTB_ROAD, ///< Road road types.
ROADTRAMTYPES_TRAM = ::RTTB_TRAM, ///< Tram road types.
};
@@ -89,7 +90,7 @@ public:
* @pre IsRoadTypeAvailable(road_type).
* @return The name the road type has.
*/
static char *GetName(RoadType road_type);
static std::optional<std::string> GetName(RoadType road_type);
/**
* Determines whether a busstop or a truckstop is needed to transport a certain cargo.
@@ -140,7 +141,7 @@ public:
/**
* Check if a given RoadType is available.
* @param road_type The RoadType to check for.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @return True if this RoadType can be used.
*/
static bool IsRoadTypeAvailable(RoadType road_type);
@@ -186,7 +187,7 @@ public:
* @pre ScriptMap::IsValidTile(start_tile).
* @pre ScriptMap::IsValidTile(end_tile).
* @pre IsRoadTypeAvailable(road_type).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptRoad::ERR_UNSUITABLE_ROAD
* @return Whether at least some road has been converted successfully.
*/
@@ -245,7 +246,7 @@ public:
* they are build or 2 when building the first part automatically
* builds the second part. -1 means the preconditions are not met.
*/
static int32 CanBuildConnectedRoadParts(ScriptTile::Slope slope, struct Array *existing, TileIndex start, TileIndex end);
static SQInteger CanBuildConnectedRoadParts(ScriptTile::Slope slope, Array<> &&existing, TileIndex start, TileIndex end);
/**
* Lookup function for building road parts independent of whether the
@@ -266,7 +267,7 @@ public:
* they are build or 2 when building the first part automatically
* builds the second part. -1 means the preconditions are not met.
*/
static int32 CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end);
static SQInteger CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end);
/**
* Count how many neighbours are road.
@@ -275,7 +276,7 @@ public:
* @pre IsRoadTypeAvailable(GetCurrentRoadType()).
* @return 0 means no neighbour road; max value is 4.
*/
static int32 GetNeighbourRoadCount(TileIndex tile);
static SQInteger GetNeighbourRoadCount(TileIndex tile);
/**
* Gets the tile in front of a road depot.
@@ -321,7 +322,7 @@ public:
* @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS
* @exception ScriptError::ERR_VEHICLE_IN_THE_WAY
* @note Construction will fail if an obstacle is found between the start and end tiles.
* @game @note Building a piece of road (without CompanyMode) results in a piece of road owned by towns.
* @game @note Building a piece of road as deity (ScriptCompanyMode::IsDeity()) results in a piece of road owned by towns.
* @return Whether the road has been/can be build or not.
*/
static bool BuildRoad(TileIndex start, TileIndex end);
@@ -342,7 +343,7 @@ public:
* ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or
* ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end).
* @pre GetCurrentRoadType() == ROADTYPE_ROAD.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_ALREADY_BUILT
* @exception ScriptError::ERR_LAND_SLOPED_WRONG
* @exception ScriptError::ERR_AREA_NOT_CLEAR
@@ -373,7 +374,7 @@ public:
* @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS
* @exception ScriptError::ERR_VEHICLE_IN_THE_WAY
* @note Construction will fail if an obstacle is found between the start and end tiles.
* @game @note Building a piece of road (without CompanyMode) results in a piece of road owned by towns.
* @game @note Building a piece of road as deity (ScriptCompanyMode::IsDeity()) results in a piece of road owned by towns.
* @return Whether the road has been/can be build or not.
*/
static bool BuildRoadFull(TileIndex start, TileIndex end);
@@ -394,7 +395,7 @@ public:
* ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or
* ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end).
* @pre GetCurrentRoadType() == ROADTYPE_ROAD.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_ALREADY_BUILT
* @exception ScriptError::ERR_LAND_SLOPED_WRONG
* @exception ScriptError::ERR_AREA_NOT_CLEAR
@@ -414,7 +415,7 @@ public:
* @pre ScriptMap::IsValidTile(front).
* @pre 'tile' is not equal to 'front', but in a straight line of it.
* @pre IsRoadTypeAvailable(GetCurrentRoadType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @return Whether the road depot has been/can be build or not.
@@ -432,7 +433,7 @@ public:
* @pre 'tile' is not equal to 'front', but in a straight line of it.
* @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id).
* @pre GetCurrentRoadType() == ROADTYPE_ROAD.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
@@ -457,7 +458,7 @@ public:
* @pre 'tile' is not equal to 'front', but in a straight line of it.
* @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id).
* @pre IsRoadTypeAvailable(GetCurrentRoadType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_AREA_NOT_CLEAR
* @exception ScriptError::ERR_FLAT_LAND_REQUIRED
@@ -482,7 +483,7 @@ public:
* ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or
* ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end).
* @pre IsRoadTypeAvailable(GetCurrentRoadType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_VEHICLE_IN_THE_WAY
* @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS
@@ -502,7 +503,7 @@ public:
* ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or
* ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end).
* @pre IsRoadTypeAvailable(GetCurrentRoadType()).
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_VEHICLE_IN_THE_WAY
* @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS
@@ -515,7 +516,7 @@ public:
* @param tile Place to remove the depot from.
* @pre ScriptMap::IsValidTile(tile).
* @pre Tile is a road depot.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_VEHICLE_IN_THE_WAY
* @return Whether the road depot has been/can be removed or not.
@@ -527,7 +528,7 @@ public:
* @param tile Place to remove the station from.
* @pre ScriptMap::IsValidTile(tile).
* @pre Tile is a road station.
* @game @pre Valid ScriptCompanyMode active in scope.
* @game @pre ScriptCompanyMode::IsValid().
* @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY
* @exception ScriptError::ERR_VEHICLE_IN_THE_WAY
* @return Whether the station has been/can be removed or not.
@@ -560,7 +561,7 @@ public:
* This is mph / 0.8, which is roughly 0.5 km/h.
* To get km/h multiply this number by 2.01168.
*/
static int32 GetMaxSpeed(RoadType road_type);
static SQInteger GetMaxSpeed(RoadType road_type);
/**
* Get the maintenance cost factor of a road type.
@@ -568,7 +569,7 @@ public:
* @pre IsRoadTypeAvailable(roadtype)
* @return Maintenance cost factor of the roadtype.
*/
static uint16 GetMaintenanceCostFactor(RoadType roadtype);
static SQInteger GetMaintenanceCostFactor(RoadType roadtype);
private:

View File

@@ -15,8 +15,10 @@
ScriptRoadTypeList::ScriptRoadTypeList(ScriptRoad::RoadTramTypes rtts)
{
EnforceDeityOrCompanyModeValid_Void();
CompanyID owner = ScriptObject::GetCompany();
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
if (!HasBit(rtts, GetRoadTramType(rt))) continue;
if (ScriptObject::GetCompany() == OWNER_DEITY || ::HasRoadTypeAvail(ScriptObject::GetCompany(), rt)) this->AddItem(rt);
if (::HasRoadTypeAvail(owner, rt)) this->AddItem(rt);
}
}

View File

@@ -21,6 +21,7 @@
/* static */ bool ScriptSign::IsValidSign(SignID sign_id)
{
EnforceDeityOrCompanyModeValid(false);
const Sign *si = ::Sign::GetIfValid(sign_id);
return si != nullptr && (si->owner == ScriptObject::GetCompany() || si->owner == OWNER_DEITY);
}
@@ -36,18 +37,19 @@
{
CCountedPtr<Text> counter(name);
EnforceDeityOrCompanyModeValid(false);
EnforcePrecondition(false, IsValidSign(sign_id));
EnforcePrecondition(false, name != nullptr);
const char *text = name->GetDecodedText();
const std::string &text = name->GetDecodedText();
EnforcePreconditionEncodedText(false, text);
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_SIGN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
return ScriptObject::Command<CMD_RENAME_SIGN>::Do(sign_id, text);
}
/* static */ char *ScriptSign::GetName(SignID sign_id)
/* static */ std::optional<std::string> ScriptSign::GetName(SignID sign_id)
{
if (!IsValidSign(sign_id)) return nullptr;
if (!IsValidSign(sign_id)) return std::nullopt;
::SetDParam(0, sign_id);
return GetString(STR_SIGN_NAME);
@@ -63,6 +65,7 @@
/* static */ bool ScriptSign::RemoveSign(SignID sign_id)
{
EnforceDeityOrCompanyModeValid(false);
EnforcePrecondition(false, IsValidSign(sign_id));
return ScriptObject::Command<CMD_RENAME_SIGN>::Do(sign_id, "");
}
@@ -71,9 +74,10 @@
{
CCountedPtr<Text> counter(name);
EnforceDeityOrCompanyModeValid(INVALID_SIGN);
EnforcePrecondition(INVALID_SIGN, ::IsValidTile(location));
EnforcePrecondition(INVALID_SIGN, name != nullptr);
const char *text = name->GetDecodedText();
const std::string &text = name->GetDecodedText();
EnforcePreconditionEncodedText(INVALID_SIGN, text);
EnforcePreconditionCustomError(INVALID_SIGN, ::Utf8StringLength(text) < MAX_LENGTH_SIGN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);

View File

@@ -55,7 +55,7 @@ public:
* @pre IsValidSign(sign_id).
* @return The name of the sign.
*/
static char *GetName(SignID sign_id);
static std::optional<std::string> GetName(SignID sign_id);
/**
* Get the owner of a sign.

View File

@@ -14,9 +14,9 @@
#include "../../safeguards.h"
ScriptSignList::ScriptSignList()
ScriptSignList::ScriptSignList(HSQUIRRELVM vm)
{
for (const Sign *s : Sign::Iterate()) {
if (ScriptSign::IsValidSign(s->index)) this->AddItem(s->index);
}
ScriptList::FillList<Sign>(vm, this,
[](const Sign *s) { return ScriptSign::IsValidSign(s->index); }
);
}

View File

@@ -19,7 +19,29 @@
*/
class ScriptSignList : public ScriptList {
public:
#ifdef DOXYGEN_API
ScriptSignList();
/**
* Apply a filter when building the list.
* @param filter_function The function which will be doing the filtering.
* @param params The params to give to the filters (minus the first param,
* which is always the index-value).
* @note You can write your own filters and use them. Just remember that
* the first parameter should be the index-value, and it should return
* a bool.
* @note Example:
* function Contains(sign_id, str)
* {
* local name = ScriptSign.GetName(sign_id);
* return name != null && name.find(str) != null;
* }
* ScriptSignList(Contains, "something");
*/
ScriptSignList(void *filter_function, int params, ...);
#else
ScriptSignList(HSQUIRRELVM);
#endif /* DOXYGEN_API */
};
#endif /* SCRIPT_SIGNLIST_HPP */

View File

@@ -21,8 +21,9 @@
/* static */ bool ScriptStation::IsValidStation(StationID station_id)
{
EnforceDeityOrCompanyModeValid(false);
const Station *st = ::Station::GetIfValid(station_id);
return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE);
return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity() || st->owner == OWNER_NONE);
}
/* static */ ScriptCompany::CompanyID ScriptStation::GetOwner(StationID station_id)
@@ -50,7 +51,7 @@ template<bool Tfrom, bool Tvia>
}
template<bool Tfrom, bool Tvia>
/* static */ int32 ScriptStation::CountCargoWaiting(StationID station_id,
/* static */ SQInteger ScriptStation::CountCargoWaiting(StationID station_id,
StationID from_station_id, StationID via_station_id, CargoID cargo_id)
{
if (!ScriptStation::IsCargoRequestValid<Tfrom, Tvia>(station_id, from_station_id,
@@ -61,44 +62,44 @@ template<bool Tfrom, bool Tvia>
const StationCargoList &cargo_list = ::Station::Get(station_id)->goods[cargo_id].cargo;
if (!Tfrom && !Tvia) return cargo_list.TotalCount();
uint16 cargo_count = 0;
uint16_t cargo_count = 0;
std::pair<StationCargoList::ConstIterator, StationCargoList::ConstIterator> range = Tvia ?
cargo_list.Packets()->equal_range(via_station_id) :
std::make_pair(StationCargoList::ConstIterator(cargo_list.Packets()->begin()),
StationCargoList::ConstIterator(cargo_list.Packets()->end()));
for (StationCargoList::ConstIterator it = range.first; it != range.second; it++) {
const CargoPacket *cp = *it;
if (!Tfrom || cp->SourceStation() == from_station_id) cargo_count += cp->Count();
if (!Tfrom || cp->GetFirstStation() == from_station_id) cargo_count += cp->Count();
}
return cargo_count;
}
/* static */ int32 ScriptStation::GetCargoWaiting(StationID station_id, CargoID cargo_id)
/* static */ SQInteger ScriptStation::GetCargoWaiting(StationID station_id, CargoID cargo_id)
{
return CountCargoWaiting<false, false>(station_id, STATION_INVALID, STATION_INVALID, cargo_id);
}
/* static */ int32 ScriptStation::GetCargoWaitingFrom(StationID station_id,
/* static */ SQInteger ScriptStation::GetCargoWaitingFrom(StationID station_id,
StationID from_station_id, CargoID cargo_id)
{
return CountCargoWaiting<true, false>(station_id, from_station_id, STATION_INVALID, cargo_id);
}
/* static */ int32 ScriptStation::GetCargoWaitingVia(StationID station_id,
/* static */ SQInteger ScriptStation::GetCargoWaitingVia(StationID station_id,
StationID via_station_id, CargoID cargo_id)
{
return CountCargoWaiting<false, true>(station_id, STATION_INVALID, via_station_id, cargo_id);
}
/* static */ int32 ScriptStation::GetCargoWaitingFromVia(StationID station_id,
/* static */ SQInteger ScriptStation::GetCargoWaitingFromVia(StationID station_id,
StationID from_station_id, StationID via_station_id, CargoID cargo_id)
{
return CountCargoWaiting<true, true>(station_id, from_station_id, via_station_id, cargo_id);
}
template<bool Tfrom, bool Tvia>
/* static */ int32 ScriptStation::CountCargoPlanned(StationID station_id,
/* static */ SQInteger ScriptStation::CountCargoPlanned(StationID station_id,
StationID from_station_id, StationID via_station_id, CargoID cargo_id)
{
if (!ScriptStation::IsCargoRequestValid<Tfrom, Tvia>(station_id, from_station_id,
@@ -115,24 +116,24 @@ template<bool Tfrom, bool Tvia>
}
}
/* static */ int32 ScriptStation::GetCargoPlanned(StationID station_id, CargoID cargo_id)
/* static */ SQInteger ScriptStation::GetCargoPlanned(StationID station_id, CargoID cargo_id)
{
return CountCargoPlanned<false, false>(station_id, STATION_INVALID, STATION_INVALID, cargo_id);
}
/* static */ int32 ScriptStation::GetCargoPlannedFrom(StationID station_id,
/* static */ SQInteger ScriptStation::GetCargoPlannedFrom(StationID station_id,
StationID from_station_id, CargoID cargo_id)
{
return CountCargoPlanned<true, false>(station_id, from_station_id, STATION_INVALID, cargo_id);
}
/* static */ int32 ScriptStation::GetCargoPlannedVia(StationID station_id,
/* static */ SQInteger ScriptStation::GetCargoPlannedVia(StationID station_id,
StationID via_station_id, CargoID cargo_id)
{
return CountCargoPlanned<false, true>(station_id, STATION_INVALID, via_station_id, cargo_id);
}
/* static */ int32 ScriptStation::GetCargoPlannedFromVia(StationID station_id,
/* static */ SQInteger ScriptStation::GetCargoPlannedFromVia(StationID station_id,
StationID from_station_id, StationID via_station_id, CargoID cargo_id)
{
return CountCargoPlanned<true, true>(station_id, from_station_id, via_station_id, cargo_id);
@@ -146,14 +147,14 @@ template<bool Tfrom, bool Tvia>
return ::Station::Get(station_id)->goods[cargo_id].HasRating();
}
/* static */ int32 ScriptStation::GetCargoRating(StationID station_id, CargoID cargo_id)
/* static */ SQInteger ScriptStation::GetCargoRating(StationID station_id, CargoID cargo_id)
{
if (!ScriptStation::HasCargoRating(station_id, cargo_id)) return -1;
return ::ToPercent8(::Station::Get(station_id)->goods[cargo_id].rating);
}
/* static */ int32 ScriptStation::GetCoverageRadius(ScriptStation::StationType station_type)
/* static */ SQInteger ScriptStation::GetCoverageRadius(ScriptStation::StationType station_type)
{
if (station_type == STATION_AIRPORT) return -1;
if (!HasExactlyOneBit(station_type)) return -1;
@@ -169,21 +170,21 @@ template<bool Tfrom, bool Tvia>
}
}
/* static */ int32 ScriptStation::GetStationCoverageRadius(StationID station_id)
/* static */ SQInteger ScriptStation::GetStationCoverageRadius(StationID station_id)
{
if (!IsValidStation(station_id)) return -1;
return Station::Get(station_id)->GetCatchmentRadius();
}
/* static */ int32 ScriptStation::GetDistanceManhattanToTile(StationID station_id, TileIndex tile)
/* static */ SQInteger ScriptStation::GetDistanceManhattanToTile(StationID station_id, TileIndex tile)
{
if (!IsValidStation(station_id)) return -1;
return ScriptMap::DistanceManhattan(tile, GetLocation(station_id));
}
/* static */ int32 ScriptStation::GetDistanceSquareToTile(StationID station_id, TileIndex tile)
/* static */ SQInteger ScriptStation::GetDistanceSquareToTile(StationID station_id, TileIndex tile)
{
if (!IsValidStation(station_id)) return -1;
@@ -202,7 +203,7 @@ template<bool Tfrom, bool Tvia>
if (!IsValidStation(station_id)) return false;
if (!HasExactlyOneBit(station_type)) return false;
return (::Station::Get(station_id)->facilities & station_type) != 0;
return (::Station::Get(station_id)->facilities & static_cast<StationFacility>(station_type)) != 0;
}
/* static */ bool ScriptStation::HasRoadType(StationID station_id, ScriptRoad::RoadType road_type)
@@ -237,6 +238,7 @@ template<bool Tfrom, bool Tvia>
/* static */ bool ScriptStation::OpenCloseAirport(StationID station_id)
{
EnforceCompanyModeValid(false);
EnforcePrecondition(false, IsValidStation(station_id));
EnforcePrecondition(false, HasStationType(station_id, STATION_AIRPORT));

View File

@@ -82,7 +82,7 @@ public:
* @pre IsValidCargo(cargo_id).
* @return The amount of units waiting at the station.
*/
static int32 GetCargoWaiting(StationID station_id, CargoID cargo_id);
static SQInteger GetCargoWaiting(StationID station_id, CargoID cargo_id);
/**
* See how much cargo with a specific source station there is waiting on a station.
@@ -95,7 +95,7 @@ public:
* @return The amount of units waiting at the station originating from from_station_id.
* @note source station means, the station where cargo was first loaded.
*/
static int32 GetCargoWaitingFrom(StationID station_id, StationID from_station_id, CargoID cargo_id);
static SQInteger GetCargoWaitingFrom(StationID station_id, StationID from_station_id, CargoID cargo_id);
/**
* See how much cargo with a specific via-station there is waiting on a station.
@@ -108,7 +108,7 @@ public:
* @return The amount of units waiting at the station with via_station_id as next hop.
* @note if ScriptCargo.GetCargoDistributionType(cargo_id) == ScriptCargo.DT_MANUAL, then all waiting cargo will have STATION_INVALID as next hop.
*/
static int32 GetCargoWaitingVia(StationID station_id, StationID via_station_id, CargoID cargo_id);
static SQInteger GetCargoWaitingVia(StationID station_id, StationID via_station_id, CargoID cargo_id);
/**
* See how much cargo with a specific via-station and source station there is waiting on a station.
@@ -123,7 +123,7 @@ public:
* @return The amount of units waiting at the station with from_station_id as source and via_station_id as next hop.
* @note if ScriptCargo.GetCargoDistributionType(cargo_id) == ScriptCargo.DT_MANUAL, then all waiting cargo will have STATION_INVALID as next hop.
*/
static int32 GetCargoWaitingFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id);
static SQInteger GetCargoWaitingFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id);
/**
* See how much cargo was planned to pass (including production and consumption) this station per month.
@@ -133,7 +133,7 @@ public:
* @pre IsValidCargo(cargo_id).
* @return The amount of cargo units planned to pass the station per month.
*/
static int32 GetCargoPlanned(StationID station_id, CargoID cargo_id);
static SQInteger GetCargoPlanned(StationID station_id, CargoID cargo_id);
/**
* See how much cargo from the specified origin was planned to pass (including production and consumption) this station per month.
@@ -145,7 +145,7 @@ public:
* @pre IsValidCargo(cargo_id).
* @return The amount of cargo units from the specified origin planned to pass the station per month.
*/
static int32 GetCargoPlannedFrom(StationID station_id, StationID from_station_id, CargoID cargo_id);
static SQInteger GetCargoPlannedFrom(StationID station_id, StationID from_station_id, CargoID cargo_id);
/**
* See how much cargo was planned to pass (including production and consumption) this station per month, heading for the specified next hop.
@@ -158,7 +158,7 @@ public:
* @return The amount of cargo units planned to pass the station per month, going via the specified next hop.
* @note Cargo planned to go "via" the same station that's being queried is actually planned to be consumed there.
*/
static int32 GetCargoPlannedVia(StationID station_id, StationID via_station_id, CargoID cargo_id);
static SQInteger GetCargoPlannedVia(StationID station_id, StationID via_station_id, CargoID cargo_id);
/**
* See how much cargo from the specified origin was planned to pass this station per month,
@@ -175,7 +175,7 @@ public:
* @note Cargo planned to go "via" the same station that's being queried is actually planned to be consumed there.
* @note Cargo planned to pass "from" the same station that's being queried is actually produced there.
*/
static int32 GetCargoPlannedFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id);
static SQInteger GetCargoPlannedFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id);
/**
* Check whether the given cargo at the given station a rating.
@@ -196,7 +196,7 @@ public:
* @pre HasCargoRating(station_id, cargo_id).
* @return The rating in percent of the cargo on the station.
*/
static int32 GetCargoRating(StationID station_id, CargoID cargo_id);
static SQInteger GetCargoRating(StationID station_id, CargoID cargo_id);
/**
* Get the coverage radius of this type of station.
@@ -205,7 +205,7 @@ public:
* @return The radius in tiles.
* @note Coverage radius of airports needs to be requested via ScriptAirport::GetAirportCoverageRadius(), as it requires AirportType.
*/
static int32 GetCoverageRadius(ScriptStation::StationType station_type);
static SQInteger GetCoverageRadius(ScriptStation::StationType station_type);
/**
* Get the coverage radius of this station.
@@ -213,7 +213,7 @@ public:
* @pre IsValidStation(station_id).
* @return The radius in tiles.
*/
static int32 GetStationCoverageRadius(StationID station_id);
static SQInteger GetStationCoverageRadius(StationID station_id);
/**
* Get the manhattan distance from the tile to the ScriptStation::GetLocation()
@@ -223,7 +223,7 @@ public:
* @pre IsValidStation(station_id).
* @return The distance between station and tile.
*/
static int32 GetDistanceManhattanToTile(StationID station_id, TileIndex tile);
static SQInteger GetDistanceManhattanToTile(StationID station_id, TileIndex tile);
/**
* Get the square distance from the tile to the ScriptStation::GetLocation()
@@ -233,7 +233,7 @@ public:
* @pre IsValidStation(station_id).
* @return The distance between station and tile.
*/
static int32 GetDistanceSquareToTile(StationID station_id, TileIndex tile);
static SQInteger GetDistanceSquareToTile(StationID station_id, TileIndex tile);
/**
* Find out if this station is within the rating influence of a town.
@@ -287,6 +287,7 @@ public:
/**
* Toggle the open/closed state of an airport.
* @param station_id The airport to modify.
* @game @pre ScriptCompanyMode::IsValid().
* @pre IsValidStation(station_id).
* @pre HasStationType(station_id, STATION_AIRPORT).
* @return True if the state was toggled successfully.
@@ -299,11 +300,11 @@ private:
StationID via_station_id, CargoID cargo_id);
template<bool Tfrom, bool Tvia>
static int32 CountCargoWaiting(StationID station_id, StationID from_station_id,
static SQInteger CountCargoWaiting(StationID station_id, StationID from_station_id,
StationID via_station_id, CargoID cargo_id);
template<bool Tfrom, bool Tvia>
static int32 CountCargoPlanned(StationID station_id, StationID from_station_id,
static SQInteger CountCargoPlanned(StationID station_id, StationID from_station_id,
StationID via_station_id, CargoID cargo_id);
};

View File

@@ -18,14 +18,19 @@
ScriptStationList::ScriptStationList(ScriptStation::StationType station_type)
{
for (Station *st : Station::Iterate()) {
if ((st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && (st->facilities & station_type) != 0) this->AddItem(st->index);
}
EnforceDeityOrCompanyModeValid_Void();
bool is_deity = ScriptCompanyMode::IsDeity();
CompanyID owner = ScriptObject::GetCompany();
ScriptList::FillList<Station>(this,
[is_deity, owner, station_type](const Station *st) {
return (is_deity || st->owner == owner) && (st->facilities & static_cast<StationFacility>(station_type)) != 0;
}
);
}
ScriptStationList_Vehicle::ScriptStationList_Vehicle(VehicleID vehicle_id)
{
if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return;
if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id)) return;
Vehicle *v = ::Vehicle::Get(vehicle_id);
@@ -148,13 +153,13 @@ void CargoCollector::Update(StationID from, StationID via, uint amount)
switch (Tselector) {
case ScriptStationList_Cargo::CS_VIA_BY_FROM:
if (via != this->other_station) return;
FALLTHROUGH;
[[fallthrough]];
case ScriptStationList_Cargo::CS_BY_FROM:
key = from;
break;
case ScriptStationList_Cargo::CS_FROM_BY_VIA:
if (from != this->other_station) return;
FALLTHROUGH;
[[fallthrough]];
case ScriptStationList_Cargo::CS_BY_VIA:
key = via;
break;
@@ -178,7 +183,7 @@ void ScriptStationList_CargoWaiting::Add(StationID station_id, CargoID cargo, St
StationCargoList::ConstIterator iter = collector.GE()->cargo.Packets()->begin();
StationCargoList::ConstIterator end = collector.GE()->cargo.Packets()->end();
for (; iter != end; ++iter) {
collector.Update<Tselector>((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count());
collector.Update<Tselector>((*iter)->GetFirstStation(), iter.GetKey(), (*iter)->Count());
}
}
@@ -217,7 +222,7 @@ ScriptStationList_CargoWaitingViaByFrom::ScriptStationList_CargoWaitingViaByFrom
std::pair<StationCargoList::ConstIterator, StationCargoList::ConstIterator> range =
collector.GE()->cargo.Packets()->equal_range(via);
for (StationCargoList::ConstIterator iter = range.first; iter != range.second; ++iter) {
collector.Update<CS_VIA_BY_FROM>((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count());
collector.Update<CS_VIA_BY_FROM>((*iter)->GetFirstStation(), iter.GetKey(), (*iter)->Count());
}
}

Some files were not shown because too many files have changed in this diff Show More