mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-23 15:52:55 +01:00
Add research plugin API
This commit is contained in:
99
distribution/openrct2.d.ts
vendored
99
distribution/openrct2.d.ts
vendored
@@ -2123,7 +2123,7 @@ declare global {
|
||||
* The track segment adds to inversion counter. Usually applied to the first half of inversions.
|
||||
*/
|
||||
readonly countsAsInversion: boolean;
|
||||
|
||||
|
||||
/**
|
||||
* Gets a length of the subpositions list for this track segment.
|
||||
*/
|
||||
@@ -3150,6 +3150,103 @@ declare global {
|
||||
postMessage(message: ParkMessageDesc): void;
|
||||
}
|
||||
|
||||
interface Research {
|
||||
/**
|
||||
* The list of rides and scenery sets that have already been researched.
|
||||
*/
|
||||
inventedItems: ResearchItemType[];
|
||||
|
||||
/**
|
||||
* The order of rides and scenery sets to be researched.
|
||||
*/
|
||||
uninventedItems: ResearchItemType[];
|
||||
|
||||
/**
|
||||
* The amount of funding currently spent on research.
|
||||
*/
|
||||
funding: ResearchFundingLevel;
|
||||
|
||||
/**
|
||||
* Flags representing which research categories are enabled.
|
||||
*/
|
||||
priorities: number;
|
||||
|
||||
/**
|
||||
* The current stage for the ride or scenery set being researched.
|
||||
*/
|
||||
stage: ResearchFundingStage;
|
||||
|
||||
/**
|
||||
* The progress for the current stage between 0 and 65535.
|
||||
* This will increment more quickly the higher the research funding.
|
||||
*/
|
||||
progress: number;
|
||||
|
||||
/**
|
||||
* The expected month the current item being researched will complete.
|
||||
* Value is between 0 and 7, 0 being March and 7 being October.
|
||||
* Value is null if there is not yet an expected month.
|
||||
*/
|
||||
readonly expectedMonth: number | null;
|
||||
|
||||
/**
|
||||
* The expected day of the month the current item being researched will complete.
|
||||
* Value is between 0 and 30, add 1 to it for the human readable date.
|
||||
* Value is null if there is not yet an expected month.
|
||||
*/
|
||||
readonly expectedDay: number | null;
|
||||
|
||||
/**
|
||||
* Gets whether a particular object has been researched and is available to construct.
|
||||
* @param type The type of object, e.g. ride, scenery group, or small scenery.
|
||||
* @param index The object index.
|
||||
*/
|
||||
isObjectResearched(type: ObjectType, index: number): boolean;
|
||||
}
|
||||
|
||||
interface ResearchItem {
|
||||
/**
|
||||
* The research category this item belongs in.
|
||||
* E.g. gentle rides, thrill rides, shops etc.
|
||||
*/
|
||||
category: ResearchCategory;
|
||||
|
||||
/**
|
||||
* Weather the research item is a ride or scenery set.
|
||||
*/
|
||||
type: ResearchItemType;
|
||||
|
||||
/**
|
||||
* The ride or scenery set object index.
|
||||
*/
|
||||
object: number;
|
||||
}
|
||||
|
||||
type ResearchItemType = "scenery" | "ride";
|
||||
|
||||
enum ResearchCategory {
|
||||
Transport,
|
||||
Gentle,
|
||||
Rollercoaster,
|
||||
Thrill,
|
||||
Water,
|
||||
Shop
|
||||
}
|
||||
|
||||
enum ResearchFundingLevel {
|
||||
None,
|
||||
Minimum,
|
||||
Normal,
|
||||
Maximum
|
||||
}
|
||||
|
||||
type ResearchFundingStage =
|
||||
"initial_research" |
|
||||
"designing" |
|
||||
"completing_design" |
|
||||
"unknown" |
|
||||
"finished_all";
|
||||
|
||||
type ScenarioObjectiveType =
|
||||
"none" |
|
||||
"guestsBy" |
|
||||
|
||||
@@ -519,6 +519,25 @@ bool ResearchInsertSceneryGroupEntry(ObjectEntryIndex entryIndex, bool researche
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResearchIsInvented(ObjectType objectType, ObjectEntryIndex index)
|
||||
{
|
||||
switch (objectType)
|
||||
{
|
||||
case ObjectType::Ride:
|
||||
return RideEntryIsInvented(index);
|
||||
case ObjectType::SceneryGroup:
|
||||
return SceneryGroupIsInvented(index);
|
||||
case ObjectType::SmallScenery:
|
||||
case ObjectType::LargeScenery:
|
||||
case ObjectType::Walls:
|
||||
case ObjectType::Banners:
|
||||
case ObjectType::PathBits:
|
||||
return SceneryIsInvented({ static_cast<uint8_t>(objectType), index });
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool RideTypeIsInvented(uint32_t rideType)
|
||||
{
|
||||
return RideTypeIsValid(rideType) ? _researchedRideTypes[rideType] : false;
|
||||
|
||||
@@ -138,6 +138,8 @@ bool ResearchInsertRideEntry(ride_type_t rideType, ObjectEntryIndex entryIndex,
|
||||
void ResearchInsertRideEntry(ObjectEntryIndex entryIndex, bool researched);
|
||||
bool ResearchInsertSceneryGroupEntry(ObjectEntryIndex entryIndex, bool researched);
|
||||
|
||||
bool ResearchIsInvented(ObjectType objectType, ObjectEntryIndex index);
|
||||
bool ResearchSetInvented(ObjectType objectType, ObjectEntryIndex index, bool value);
|
||||
void RideTypeSetInvented(uint32_t rideType);
|
||||
void RideEntrySetInvented(ObjectEntryIndex rideEntryIndex);
|
||||
void ScenerySetInvented(const ScenerySelection& sceneryItem);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
# include "bindings/world/ScMap.hpp"
|
||||
# include "bindings/world/ScPark.hpp"
|
||||
# include "bindings/world/ScParkMessage.hpp"
|
||||
# include "bindings/world/ScResearch.hpp"
|
||||
# include "bindings/world/ScScenario.hpp"
|
||||
# include "bindings/world/ScTile.hpp"
|
||||
# include "bindings/world/ScTileElement.hpp"
|
||||
@@ -409,6 +410,7 @@ void ScriptEngine::Initialise()
|
||||
ScPlayer::Register(ctx);
|
||||
ScPlayerGroup::Register(ctx);
|
||||
ScProfiler::Register(ctx);
|
||||
ScResearch::Register(ctx);
|
||||
ScRide::Register(ctx);
|
||||
ScRideStation::Register(ctx);
|
||||
ScRideObject::Register(ctx);
|
||||
@@ -439,7 +441,7 @@ void ScriptEngine::Initialise()
|
||||
dukglue_register_global(ctx, std::make_shared<ScDate>(), "date");
|
||||
dukglue_register_global(ctx, std::make_shared<ScMap>(ctx), "map");
|
||||
dukglue_register_global(ctx, std::make_shared<ScNetwork>(ctx), "network");
|
||||
dukglue_register_global(ctx, std::make_shared<ScPark>(), "park");
|
||||
dukglue_register_global(ctx, std::make_shared<ScPark>(ctx), "park");
|
||||
dukglue_register_global(ctx, std::make_shared<ScProfiler>(ctx), "profiler");
|
||||
dukglue_register_global(ctx, std::make_shared<ScScenario>(), "scenario");
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@ namespace OpenRCT2::Scripting
|
||||
{ "unlockAllPrices", PARK_FLAGS_UNLOCK_ALL_PRICES },
|
||||
});
|
||||
|
||||
ScPark::ScPark(duk_context* ctx)
|
||||
: _context(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
money64 ScPark::cash_get() const
|
||||
{
|
||||
return gCash;
|
||||
@@ -294,6 +299,11 @@ namespace OpenRCT2::Scripting
|
||||
GfxInvalidateScreen();
|
||||
}
|
||||
|
||||
std::shared_ptr<ScResearch> ScPark::research_get() const
|
||||
{
|
||||
return std::make_shared<ScResearch>(_context);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ScParkMessage>> ScPark::messages_get() const
|
||||
{
|
||||
std::vector<std::shared_ptr<ScParkMessage>> result;
|
||||
@@ -405,6 +415,7 @@ namespace OpenRCT2::Scripting
|
||||
ctx, &ScPark::constructionRightsPrice_get, &ScPark::constructionRightsPrice_set, "constructionRightsPrice");
|
||||
dukglue_register_property(ctx, &ScPark::parkSize_get, nullptr, "parkSize");
|
||||
dukglue_register_property(ctx, &ScPark::name_get, &ScPark::name_set, "name");
|
||||
dukglue_register_property(ctx, &ScPark::research_get, nullptr, "research");
|
||||
dukglue_register_property(ctx, &ScPark::messages_get, &ScPark::messages_set, "messages");
|
||||
dukglue_register_property(ctx, &ScPark::casualtyPenalty_get, &ScPark::casualtyPenalty_set, "casualtyPenalty");
|
||||
dukglue_register_method(ctx, &ScPark::getFlag, "getFlag");
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
# include "../../../common.h"
|
||||
# include "../../Duktape.hpp"
|
||||
# include "ScParkMessage.hpp"
|
||||
# include "ScResearch.hpp"
|
||||
|
||||
# include <algorithm>
|
||||
# include <vector>
|
||||
@@ -23,7 +24,12 @@ namespace OpenRCT2::Scripting
|
||||
{
|
||||
class ScPark
|
||||
{
|
||||
private:
|
||||
duk_context* _context;
|
||||
|
||||
public:
|
||||
ScPark(duk_context* ctx);
|
||||
|
||||
money64 cash_get() const;
|
||||
void cash_set(money64 value);
|
||||
|
||||
@@ -85,6 +91,8 @@ namespace OpenRCT2::Scripting
|
||||
|
||||
void setFlag(const std::string& key, bool value);
|
||||
|
||||
std::shared_ptr<ScResearch> research_get() const;
|
||||
|
||||
std::vector<std::shared_ptr<ScParkMessage>> messages_get() const;
|
||||
|
||||
void messages_set(const std::vector<DukValue>& value);
|
||||
|
||||
274
src/openrct2/scripting/bindings/world/ScResearch.hpp
Normal file
274
src/openrct2/scripting/bindings/world/ScResearch.hpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2023 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
|
||||
# include "../../../Context.h"
|
||||
# include "../../../common.h"
|
||||
# include "../../../core/String.hpp"
|
||||
# include "../../../management/Research.h"
|
||||
# include "../../../ride/RideData.h"
|
||||
# include "../../Duktape.hpp"
|
||||
# include "../../ScriptEngine.h"
|
||||
# include "../object/ScObject.hpp"
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
static const DukEnumMap<uint8_t> ResearchStageMap({
|
||||
{ "initial_research", RESEARCH_STAGE_INITIAL_RESEARCH },
|
||||
{ "designing", RESEARCH_STAGE_DESIGNING },
|
||||
{ "completing_design", RESEARCH_STAGE_COMPLETING_DESIGN },
|
||||
{ "unknown", RESEARCH_STAGE_UNKNOWN },
|
||||
{ "finished_all", RESEARCH_STAGE_FINISHED_ALL },
|
||||
});
|
||||
|
||||
static const DukEnumMap<ResearchCategory> ResearchCategoryMap({
|
||||
{ "transport", ResearchCategory::Transport },
|
||||
{ "gentle", ResearchCategory::Gentle },
|
||||
{ "rollercoaster", ResearchCategory::Rollercoaster },
|
||||
{ "thrill", ResearchCategory::Thrill },
|
||||
{ "water", ResearchCategory::Water },
|
||||
{ "shop", ResearchCategory::Shop },
|
||||
{ "scenery_group", ResearchCategory::SceneryGroup },
|
||||
});
|
||||
|
||||
static const DukEnumMap<Research::EntryType> ResearchEntryTypeMap({
|
||||
{ "ride", Research::EntryType::Ride },
|
||||
{ "scenery", Research::EntryType::Scenery },
|
||||
});
|
||||
|
||||
template<> inline DukValue ToDuk(duk_context* ctx, const ResearchItem& value)
|
||||
{
|
||||
DukObject obj(ctx);
|
||||
obj.Set("category", ResearchCategoryMap[value.category]);
|
||||
obj.Set("type", ResearchEntryTypeMap[value.type]);
|
||||
if (value.type == Research::EntryType::Ride)
|
||||
{
|
||||
obj.Set("rideType", value.baseRideType);
|
||||
}
|
||||
obj.Set("object", value.entryIndex);
|
||||
return obj.Take();
|
||||
}
|
||||
|
||||
template<> Research::EntryType inline FromDuk(const DukValue& d)
|
||||
{
|
||||
if (d.type() == DukValue::STRING)
|
||||
{
|
||||
auto it = ResearchEntryTypeMap.find(d.as_string());
|
||||
if (it != ResearchEntryTypeMap.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
return Research::EntryType::Scenery;
|
||||
}
|
||||
|
||||
template<> ResearchItem inline FromDuk(const DukValue& d)
|
||||
{
|
||||
ResearchItem result;
|
||||
result.baseRideType = 0;
|
||||
result.category = ResearchCategory::Transport;
|
||||
result.flags = 0;
|
||||
result.type = FromDuk<Research::EntryType>(d["type"]);
|
||||
auto baseRideType = d["rideType"];
|
||||
if (baseRideType.type() == DukValue::NUMBER)
|
||||
result.baseRideType = baseRideType.as_int();
|
||||
result.entryIndex = d["object"].as_int();
|
||||
return result;
|
||||
}
|
||||
|
||||
class ScResearch
|
||||
{
|
||||
private:
|
||||
duk_context* _context;
|
||||
|
||||
public:
|
||||
ScResearch(duk_context* ctx)
|
||||
: _context(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t funding_get() const
|
||||
{
|
||||
return gResearchFundingLevel;
|
||||
}
|
||||
|
||||
void funding_set(uint8_t value)
|
||||
{
|
||||
ThrowIfGameStateNotMutable();
|
||||
gResearchFundingLevel = value;
|
||||
}
|
||||
|
||||
uint8_t priorities_get() const
|
||||
{
|
||||
return gResearchPriorities;
|
||||
}
|
||||
|
||||
void priorities_set(uint8_t value)
|
||||
{
|
||||
ThrowIfGameStateNotMutable();
|
||||
gResearchPriorities = value;
|
||||
}
|
||||
|
||||
std::string stage_get() const
|
||||
{
|
||||
return std::string(ResearchStageMap[gResearchProgressStage]);
|
||||
}
|
||||
|
||||
void stage_set(const std::string& value)
|
||||
{
|
||||
ThrowIfGameStateNotMutable();
|
||||
auto it = ResearchStageMap.find(value);
|
||||
if (it != ResearchStageMap.end())
|
||||
{
|
||||
gResearchProgressStage = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t progress_get() const
|
||||
{
|
||||
return gResearchProgress;
|
||||
}
|
||||
|
||||
void progress_set(uint16_t value)
|
||||
{
|
||||
ThrowIfGameStateNotMutable();
|
||||
gResearchProgress = value;
|
||||
}
|
||||
|
||||
DukValue expectedMonth_get() const
|
||||
{
|
||||
if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || gResearchExpectedDay == 255)
|
||||
return ToDuk(_context, nullptr);
|
||||
return ToDuk(_context, gResearchExpectedMonth);
|
||||
}
|
||||
|
||||
DukValue expectedDay_get() const
|
||||
{
|
||||
if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || gResearchExpectedDay == 255)
|
||||
return ToDuk(_context, nullptr);
|
||||
return ToDuk(_context, gResearchExpectedDay);
|
||||
}
|
||||
|
||||
DukValue lastResearchedItem_get() const
|
||||
{
|
||||
if (!gResearchLastItem)
|
||||
return ToDuk(_context, nullptr);
|
||||
return ToDuk(_context, *gResearchLastItem);
|
||||
}
|
||||
|
||||
DukValue expectedItem_get() const
|
||||
{
|
||||
if (gResearchProgressStage == RESEARCH_STAGE_INITIAL_RESEARCH || !gResearchNextItem)
|
||||
return ToDuk(_context, nullptr);
|
||||
return ToDuk(_context, *gResearchNextItem);
|
||||
}
|
||||
|
||||
std::vector<DukValue> inventedItems_get() const
|
||||
{
|
||||
std::vector<DukValue> result;
|
||||
for (auto& item : gResearchItemsInvented)
|
||||
{
|
||||
result.push_back(ToDuk(_context, item));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void inventedItems_set(const std::vector<DukValue>& value)
|
||||
{
|
||||
auto list = ConvertResearchList(value);
|
||||
gResearchItemsInvented = std::move(list);
|
||||
ResearchFix();
|
||||
}
|
||||
|
||||
std::vector<DukValue> uninventedItems_get() const
|
||||
{
|
||||
std::vector<DukValue> result;
|
||||
for (auto& item : gResearchItemsUninvented)
|
||||
{
|
||||
result.push_back(ToDuk(_context, item));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void uninventedItems_set(const std::vector<DukValue>& value)
|
||||
{
|
||||
auto list = ConvertResearchList(value);
|
||||
gResearchItemsUninvented = std::move(list);
|
||||
ResearchFix();
|
||||
}
|
||||
|
||||
bool isObjectResearched(const std::string& typez, ObjectEntryIndex index)
|
||||
{
|
||||
auto result = false;
|
||||
auto type = ScObject::StringToObjectType(typez);
|
||||
if (type)
|
||||
{
|
||||
result = ResearchIsInvented(*type, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
duk_error(_context, DUK_ERR_ERROR, "Invalid object type.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Register(duk_context* ctx)
|
||||
{
|
||||
dukglue_register_property(ctx, &ScResearch::funding_get, &ScResearch::funding_set, "funding");
|
||||
dukglue_register_property(ctx, &ScResearch::priorities_get, &ScResearch::priorities_set, "priorities");
|
||||
dukglue_register_property(ctx, &ScResearch::stage_get, &ScResearch::stage_set, "stage");
|
||||
dukglue_register_property(ctx, &ScResearch::progress_get, &ScResearch::progress_set, "progress");
|
||||
dukglue_register_property(ctx, &ScResearch::expectedMonth_get, nullptr, "expectedMonth");
|
||||
dukglue_register_property(ctx, &ScResearch::expectedDay_get, nullptr, "expectedDay");
|
||||
dukglue_register_property(ctx, &ScResearch::lastResearchedItem_get, nullptr, "lastResearchedItem");
|
||||
dukglue_register_property(ctx, &ScResearch::expectedItem_get, nullptr, "expectedItem");
|
||||
dukglue_register_property(ctx, &ScResearch::inventedItems_get, &ScResearch::inventedItems_set, "inventedItems");
|
||||
dukglue_register_property(
|
||||
ctx, &ScResearch::uninventedItems_get, &ScResearch::uninventedItems_set, "uninventedItems");
|
||||
dukglue_register_method(ctx, &ScResearch::isObjectResearched, "isObjectResearched");
|
||||
}
|
||||
|
||||
static std::vector<ResearchItem> ConvertResearchList(const std::vector<DukValue>& value)
|
||||
{
|
||||
auto& objManager = GetContext()->GetObjectManager();
|
||||
std::vector<ResearchItem> result;
|
||||
for (auto& item : value)
|
||||
{
|
||||
auto researchItem = FromDuk<ResearchItem>(item);
|
||||
researchItem.flags = 0;
|
||||
if (researchItem.type == Research::EntryType::Ride)
|
||||
{
|
||||
auto rideEntry = GetRideEntryByIndex(researchItem.entryIndex);
|
||||
if (rideEntry != nullptr)
|
||||
{
|
||||
researchItem.category = GetRideTypeDescriptor(researchItem.baseRideType).GetResearchCategory();
|
||||
result.push_back(researchItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto sceneryGroup = objManager.GetLoadedObject(ObjectType::SceneryGroup, researchItem.entryIndex);
|
||||
if (sceneryGroup != nullptr)
|
||||
{
|
||||
researchItem.baseRideType = 0;
|
||||
researchItem.category = ResearchCategory::SceneryGroup;
|
||||
result.push_back(researchItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user