diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 527a6ca0fb..4b3f544237 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.4.25 (in development) ------------------------------------------------------------------------ +- Feature: [#24468] [Plugin] Add awards to plugin API. - Feature: [#24702] [Plugin] Add bindings for missing cheats (forcedParkRating, ignoreRidePrice, makeAllDestructible). - Fix: [#24598] Cannot load .park files that use official legacy footpaths by accident. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 9c828690ac..892b4cce63 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -4179,6 +4179,53 @@ declare global { "scenarioCompleteNameInput" | "unlockAllPrices"; + type AwardType = + "mostUntidy" | + "mostTidy" | + "bestRollerCoasters" | + "bestValue" | + "mostBeautiful" | + "worstValue" | + "safest" | + "bestStaff" | + "bestFood" | + "worstFood" | + "bestToilets" | + "mostDisappointing" | + "bestWaterRides" | + "bestCustomDesignedRides" | + "mostDazzlingRideColours" | + "mostConfusingLayout" | + "bestGentleRides"; + + interface Award { + /** + * The type of the award. + */ + readonly type: AwardType; + + /** + * The award description. + */ + readonly text: string; + + /** + * Number of months this award will remain active. + * Starts at 5, expires at 0. + */ + readonly monthsRemaining: number; + + /** + * The sprite of the award. + */ + readonly imageId: number; + + /** + * Whether this is a positive or negative award. + */ + readonly positive: boolean; + } + interface Park { cash: number; rating: number; @@ -4326,6 +4373,25 @@ declare global { * @param type The type of expenditure to get. */ getMonthlyExpenditure(type: ExpenditureType): number[] + + /** + * The current awards of the park. + */ + readonly awards: Award[] + + /** + * Clear all awards. + */ + clearAwards(): void + + /** + * Grant the given award type to the park. + * Does not check eligibility. + * If the park already has an active award of the given type, the old award will be removed. + * If the park already has 4 active awards, the oldest award will be removed. + * @param type the award type to grant + */ + grantAward(type: AwardType): void } interface Research { diff --git a/src/openrct2-ui/UiStringIds.h b/src/openrct2-ui/UiStringIds.h index b890df371f..290734a5ae 100644 --- a/src/openrct2-ui/UiStringIds.h +++ b/src/openrct2-ui/UiStringIds.h @@ -1290,23 +1290,6 @@ namespace OpenRCT2 // Window: Park STR_ADMISSION_PRICE = 1756, STR_ADMISSION_PRICE_PAY_PER_RIDE_TIP = 6014, - STR_AWARD_MOST_UNTIDY = 2814, - STR_AWARD_BEST_CUSTOM_DESIGNED_RIDES = STR_AWARD_MOST_UNTIDY + 13, - STR_AWARD_BEST_FOOD = STR_AWARD_MOST_UNTIDY + 8, - STR_AWARD_BEST_GENTLE_RIDES = STR_AWARD_MOST_UNTIDY + 16, - STR_AWARD_BEST_ROLLERCOASTERS = STR_AWARD_MOST_UNTIDY + 2, - STR_AWARD_BEST_STAFF = STR_AWARD_MOST_UNTIDY + 7, - STR_AWARD_BEST_TOILETS = STR_AWARD_MOST_UNTIDY + 10, - STR_AWARD_BEST_VALUE = STR_AWARD_MOST_UNTIDY + 3, - STR_AWARD_BEST_WATER_RIDES = STR_AWARD_MOST_UNTIDY + 12, - STR_AWARD_MOST_BEAUTIFUL = STR_AWARD_MOST_UNTIDY + 4, - STR_AWARD_MOST_CONFUSING_LAYOUT = STR_AWARD_MOST_UNTIDY + 15, - STR_AWARD_MOST_DAZZLING_RIDE_COLOURS = STR_AWARD_MOST_UNTIDY + 14, - STR_AWARD_MOST_DISAPPOINTING = STR_AWARD_MOST_UNTIDY + 11, - STR_AWARD_MOST_TIDY = STR_AWARD_MOST_UNTIDY + 1, - STR_AWARD_SAFEST = STR_AWARD_MOST_UNTIDY + 6, - STR_AWARD_WORST_FOOD = STR_AWARD_MOST_UNTIDY + 9, - STR_AWARD_WORST_VALUE = STR_AWARD_MOST_UNTIDY + 5, STR_BUY_LAND_AND_CONSTRUCTION_RIGHTS_TIP = 5135, STR_CLOSE_PARK = 1013, STR_CLOSE_PARK_TIP = 5296, diff --git a/src/openrct2-ui/windows/Park.cpp b/src/openrct2-ui/windows/Park.cpp index 9b8e81d7ec..233d86cbdf 100644 --- a/src/openrct2-ui/windows/Park.cpp +++ b/src/openrct2-ui/windows/Park.cpp @@ -164,31 +164,6 @@ namespace OpenRCT2::Ui::Windows 0, 0, }; - - struct WindowParkAward { - StringId text; - uint32_t sprite; - }; - - static constexpr WindowParkAward _parkAwards[] = { - { STR_AWARD_MOST_UNTIDY, SPR_AWARD_MOST_UNTIDY }, - { STR_AWARD_MOST_TIDY, SPR_AWARD_MOST_TIDY }, - { STR_AWARD_BEST_ROLLERCOASTERS, SPR_AWARD_BEST_ROLLERCOASTERS }, - { STR_AWARD_BEST_VALUE, SPR_AWARD_BEST_VALUE }, - { STR_AWARD_MOST_BEAUTIFUL, SPR_AWARD_MOST_BEAUTIFUL }, - { STR_AWARD_WORST_VALUE, SPR_AWARD_WORST_VALUE }, - { STR_AWARD_SAFEST, SPR_AWARD_SAFEST }, - { STR_AWARD_BEST_STAFF, SPR_AWARD_BEST_STAFF }, - { STR_AWARD_BEST_FOOD, SPR_AWARD_BEST_FOOD }, - { STR_AWARD_WORST_FOOD, SPR_AWARD_WORST_FOOD }, - { STR_AWARD_BEST_TOILETS, SPR_AWARD_BEST_TOILETS }, - { STR_AWARD_MOST_DISAPPOINTING, SPR_AWARD_MOST_DISAPPOINTING }, - { STR_AWARD_BEST_WATER_RIDES, SPR_AWARD_BEST_WATER_RIDES }, - { STR_AWARD_BEST_CUSTOM_DESIGNED_RIDES, SPR_AWARD_BEST_CUSTOM_DESIGNED_RIDES }, - { STR_AWARD_MOST_DAZZLING_RIDE_COLOURS, SPR_AWARD_MOST_DAZZLING_RIDE_COLOURS }, - { STR_AWARD_MOST_CONFUSING_LAYOUT, SPR_AWARD_MOST_CONFUSING_LAYOUT }, - { STR_AWARD_BEST_GENTLE_RIDES, SPR_AWARD_BEST_GENTLE_RIDES }, - }; // clang-format on class ParkWindow final : public Window @@ -1164,8 +1139,8 @@ namespace OpenRCT2::Ui::Windows for (const auto& award : currentAwards) { - GfxDrawSprite(rt, ImageId(_parkAwards[EnumValue(award.Type)].sprite), screenCoords); - DrawTextWrapped(rt, screenCoords + ScreenCoordsXY{ 34, 6 }, 180, _parkAwards[EnumValue(award.Type)].text); + GfxDrawSprite(rt, ImageId(AwardGetSprite(award.Type)), screenCoords); + DrawTextWrapped(rt, screenCoords + ScreenCoordsXY{ 34, 6 }, 180, AwardGetText(award.Type)); screenCoords.y += 32; } diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 51117b3e26..5467efa682 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -595,6 +595,7 @@ + @@ -1117,6 +1118,7 @@ + diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index ae9a3dd9d2..f8868b66ee 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -1096,6 +1096,23 @@ enum : StringId STR_PEEPS_CANT_FIND_TOILET = 2811, STR_PEEPS_GETTING_LOST_OR_STUCK = 2812, STR_ENTRANCE_FEE_TOO_HI = 2813, + STR_AWARD_MOST_UNTIDY = 2814, + STR_AWARD_BEST_CUSTOM_DESIGNED_RIDES = STR_AWARD_MOST_UNTIDY + 13, + STR_AWARD_BEST_FOOD = STR_AWARD_MOST_UNTIDY + 8, + STR_AWARD_BEST_GENTLE_RIDES = STR_AWARD_MOST_UNTIDY + 16, + STR_AWARD_BEST_ROLLERCOASTERS = STR_AWARD_MOST_UNTIDY + 2, + STR_AWARD_BEST_STAFF = STR_AWARD_MOST_UNTIDY + 7, + STR_AWARD_BEST_TOILETS = STR_AWARD_MOST_UNTIDY + 10, + STR_AWARD_BEST_VALUE = STR_AWARD_MOST_UNTIDY + 3, + STR_AWARD_BEST_WATER_RIDES = STR_AWARD_MOST_UNTIDY + 12, + STR_AWARD_MOST_BEAUTIFUL = STR_AWARD_MOST_UNTIDY + 4, + STR_AWARD_MOST_CONFUSING_LAYOUT = STR_AWARD_MOST_UNTIDY + 15, + STR_AWARD_MOST_DAZZLING_RIDE_COLOURS = STR_AWARD_MOST_UNTIDY + 14, + STR_AWARD_MOST_DISAPPOINTING = STR_AWARD_MOST_UNTIDY + 11, + STR_AWARD_MOST_TIDY = STR_AWARD_MOST_UNTIDY + 1, + STR_AWARD_SAFEST = STR_AWARD_MOST_UNTIDY + 6, + STR_AWARD_WORST_FOOD = STR_AWARD_MOST_UNTIDY + 9, + STR_AWARD_WORST_VALUE = STR_AWARD_MOST_UNTIDY + 5, STR_NEWS_ITEM_AWARD_MOST_UNTIDY = 2831, STR_NEWS_ITEM_MOST_TIDY = STR_NEWS_ITEM_AWARD_MOST_UNTIDY + 1, STR_NEWS_ITEM_BEST_ROLLERCOASTERS = STR_NEWS_ITEM_AWARD_MOST_UNTIDY + 2, diff --git a/src/openrct2/management/Award.cpp b/src/openrct2/management/Award.cpp index 8fcc967abd..f08ada6a8d 100644 --- a/src/openrct2/management/Award.cpp +++ b/src/openrct2/management/Award.cpp @@ -13,7 +13,6 @@ #include "../config/Config.h" #include "../entity/EntityList.h" #include "../entity/Guest.h" -#include "../localisation/StringIds.h" #include "../profiling/Profiling.h" #include "../ride/Ride.h" #include "../ride/RideData.h" @@ -29,49 +28,55 @@ enum class AwardEffect : uint8_t negative, positive }; -static constexpr AwardEffect kAwardPositiveMap[] = { - AwardEffect::negative, // AwardType::MostUntidy - AwardEffect::positive, // AwardType::MostTidy - AwardEffect::positive, // AwardType::BestRollerCoasters - AwardEffect::positive, // AwardType::BestValue - AwardEffect::positive, // AwardType::MostBeautiful - AwardEffect::negative, // AwardType::WorstValue - AwardEffect::positive, // AwardType::Safest - AwardEffect::positive, // AwardType::BestStaff - AwardEffect::positive, // AwardType::BestFood - AwardEffect::negative, // AwardType::WorstFood - AwardEffect::positive, // AwardType::BestToilets - AwardEffect::negative, // AwardType::MostDisappointing - AwardEffect::positive, // AwardType::BestWaterRides - AwardEffect::positive, // AwardType::BestCustomDesignedRides - AwardEffect::positive, // AwardType::MostDazzlingRideColours - AwardEffect::negative, // AwardType::MostConfusingLayout - AwardEffect::positive, // AwardType::BestGentleRides + +struct AwardData_t +{ + StringId text; + StringId news; + ImageIndex sprite; + AwardEffect effect; }; -static constexpr StringId AwardNewsStrings[] = { - STR_NEWS_ITEM_AWARD_MOST_UNTIDY, - STR_NEWS_ITEM_MOST_TIDY, - STR_NEWS_ITEM_BEST_ROLLERCOASTERS, - STR_NEWS_ITEM_BEST_VALUE, - STR_NEWS_ITEM_MOST_BEAUTIFUL, - STR_NEWS_ITEM_WORST_VALUE, - STR_NEWS_ITEM_SAFEST, - STR_NEWS_ITEM_BEST_STAFF, - STR_NEWS_ITEM_BEST_FOOD, - STR_NEWS_ITEM_WORST_FOOD, - STR_NEWS_ITEM_BEST_TOILETS, - STR_NEWS_ITEM_MOST_DISAPPOINTING, - STR_NEWS_ITEM_BEST_WATER_RIDES, - STR_NEWS_ITEM_BEST_CUSTOM_DESIGNED_RIDES, - STR_NEWS_ITEM_MOST_DAZZLING_RIDE_COLOURS, - STR_NEWS_ITEM_MOST_CONFUSING_LAYOUT, - STR_NEWS_ITEM_BEST_GENTLE_RIDES, +// clang-format off +static constexpr AwardData_t AwardData[] = { + { STR_AWARD_MOST_UNTIDY, STR_NEWS_ITEM_AWARD_MOST_UNTIDY, SPR_AWARD_MOST_UNTIDY, AwardEffect::negative }, + { STR_AWARD_MOST_TIDY, STR_NEWS_ITEM_MOST_TIDY, SPR_AWARD_MOST_TIDY, AwardEffect::positive }, + { STR_AWARD_BEST_ROLLERCOASTERS, STR_NEWS_ITEM_BEST_ROLLERCOASTERS, SPR_AWARD_BEST_ROLLERCOASTERS, AwardEffect::positive }, + { STR_AWARD_BEST_VALUE, STR_NEWS_ITEM_BEST_VALUE, SPR_AWARD_BEST_VALUE, AwardEffect::positive }, + { STR_AWARD_MOST_BEAUTIFUL, STR_NEWS_ITEM_MOST_BEAUTIFUL, SPR_AWARD_MOST_BEAUTIFUL, AwardEffect::positive }, + { STR_AWARD_WORST_VALUE, STR_NEWS_ITEM_WORST_VALUE, SPR_AWARD_WORST_VALUE, AwardEffect::negative }, + { STR_AWARD_SAFEST, STR_NEWS_ITEM_SAFEST, SPR_AWARD_SAFEST, AwardEffect::positive }, + { STR_AWARD_BEST_STAFF, STR_NEWS_ITEM_BEST_STAFF, SPR_AWARD_BEST_STAFF, AwardEffect::positive }, + { STR_AWARD_BEST_FOOD, STR_NEWS_ITEM_BEST_FOOD, SPR_AWARD_BEST_FOOD, AwardEffect::positive }, + { STR_AWARD_WORST_FOOD, STR_NEWS_ITEM_WORST_FOOD, SPR_AWARD_WORST_FOOD, AwardEffect::negative }, + { STR_AWARD_BEST_TOILETS, STR_NEWS_ITEM_BEST_TOILETS, SPR_AWARD_BEST_TOILETS, AwardEffect::positive }, + { STR_AWARD_MOST_DISAPPOINTING, STR_NEWS_ITEM_MOST_DISAPPOINTING, SPR_AWARD_MOST_DISAPPOINTING, AwardEffect::negative }, + { STR_AWARD_BEST_WATER_RIDES, STR_NEWS_ITEM_BEST_WATER_RIDES, SPR_AWARD_BEST_WATER_RIDES, AwardEffect::positive }, + { STR_AWARD_BEST_CUSTOM_DESIGNED_RIDES, STR_NEWS_ITEM_BEST_CUSTOM_DESIGNED_RIDES, SPR_AWARD_BEST_CUSTOM_DESIGNED_RIDES, AwardEffect::positive }, + { STR_AWARD_MOST_DAZZLING_RIDE_COLOURS, STR_NEWS_ITEM_MOST_DAZZLING_RIDE_COLOURS, SPR_AWARD_MOST_DAZZLING_RIDE_COLOURS, AwardEffect::positive }, + { STR_AWARD_MOST_CONFUSING_LAYOUT, STR_NEWS_ITEM_MOST_CONFUSING_LAYOUT, SPR_AWARD_MOST_CONFUSING_LAYOUT, AwardEffect::negative }, + { STR_AWARD_BEST_GENTLE_RIDES, STR_NEWS_ITEM_BEST_GENTLE_RIDES, SPR_AWARD_BEST_GENTLE_RIDES, AwardEffect::positive }, }; +// clang-format on bool AwardIsPositive(AwardType type) { - return kAwardPositiveMap[EnumValue(type)] == AwardEffect::positive; + return AwardData[EnumValue(type)].effect == AwardEffect::positive; +} + +ImageIndex AwardGetSprite(AwardType type) +{ + return AwardData[EnumValue(type)].sprite; +} + +StringId AwardGetText(AwardType type) +{ + return AwardData[EnumValue(type)].text; +} + +StringId AwardGetNews(AwardType type) +{ + return AwardData[EnumValue(type)].news; } #pragma region Award checks @@ -598,6 +603,16 @@ void AwardReset() getGameState().currentAwards.clear(); } +static void AwardAdd(AwardType type) +{ + getGameState().currentAwards.push_back(Award{ 5u, type }); + if (Config::Get().notifications.ParkAward) + { + News::AddItemToQueue(News::ItemType::award, AwardGetNews(type), 0, {}); + } + Ui::GetWindowManager()->InvalidateByClass(WindowClass::ParkInformation); +} + /** * * rct2: 0x0066A86C @@ -648,14 +663,24 @@ void AwardUpdateAll() // Check if award is deserved if (AwardIsDeserved(awardType, activeAwardTypes)) { - // Add award - currentAwards.push_back(Award{ 5u, awardType }); - if (Config::Get().notifications.ParkAward) - { - News::AddItemToQueue(News::ItemType::award, AwardNewsStrings[EnumValue(awardType)], 0, {}); - } - windowMgr->InvalidateByClass(WindowClass::ParkInformation); + AwardAdd(awardType); } } } } + +void AwardGrant(AwardType type) +{ + auto& currentAwards = getGameState().currentAwards; + + // Remove award type if already granted + std::erase_if(currentAwards, [type](const Award& award) { return award.Type == type; }); + + // Ensure there is space for the award + if (currentAwards.size() >= OpenRCT2::Limits::kMaxAwards) + { + currentAwards.erase(currentAwards.begin()); + } + + AwardAdd(type); +} diff --git a/src/openrct2/management/Award.h b/src/openrct2/management/Award.h index 24467da0e3..60790f0954 100644 --- a/src/openrct2/management/Award.h +++ b/src/openrct2/management/Award.h @@ -9,6 +9,9 @@ #pragma once +#include "../SpriteIds.h" +#include "../localisation/StringIds.h" + #include #include @@ -42,5 +45,9 @@ struct Award }; bool AwardIsPositive(AwardType type); +ImageIndex AwardGetSprite(AwardType type); +StringId AwardGetText(AwardType type); +StringId AwardGetNews(AwardType type); +void AwardGrant(AwardType type); void AwardReset(); void AwardUpdateAll(); diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index 8ddfd71c80..537842edf3 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -51,6 +51,7 @@ #include "bindings/object/ScObjectManager.h" #include "bindings/ride/ScRide.hpp" #include "bindings/ride/ScRideStation.hpp" + #include "bindings/world/ScAward.hpp" #include "bindings/world/ScClimate.hpp" #include "bindings/world/ScDate.hpp" #include "bindings/world/ScMap.hpp" @@ -403,6 +404,7 @@ void ScriptEngine::Initialise() throw std::runtime_error("Script engine already initialised."); auto ctx = static_cast(_context); + ScAward::Register(ctx); ScCheats::Register(ctx); ScClimate::Register(ctx); ScWeatherState::Register(ctx); diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index e54898add0..38919c5cbf 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -46,7 +46,7 @@ namespace OpenRCT2 namespace OpenRCT2::Scripting { - static constexpr int32_t kPluginApiVersion = 109; + static constexpr int32_t kPluginApiVersion = 110; // Versions marking breaking changes. static constexpr int32_t kApiVersionPeepDeprecation = 33; diff --git a/src/openrct2/scripting/bindings/world/ScAward.cpp b/src/openrct2/scripting/bindings/world/ScAward.cpp new file mode 100644 index 0000000000..f1f29d7d40 --- /dev/null +++ b/src/openrct2/scripting/bindings/world/ScAward.cpp @@ -0,0 +1,90 @@ +/***************************************************************************** + * Copyright (c) 2014-2025 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. + *****************************************************************************/ + +#ifdef ENABLE_SCRIPTING + + #include "ScAward.hpp" + + #include "../../../GameState.h" + #include "../../../localisation/Formatting.h" + #include "../../../management/Award.h" + #include "../../../windows/Intent.h" + #include "../../Duktape.hpp" + +namespace OpenRCT2::Scripting +{ + ScAward::ScAward(size_t index) + : _index(index) + { + } + + void ScAward::Register(duk_context* ctx) + { + dukglue_register_property(ctx, &ScAward::type_get, nullptr, "type"); + dukglue_register_property(ctx, &ScAward::text_get, nullptr, "text"); + dukglue_register_property(ctx, &ScAward::positive_get, nullptr, "positive"); + dukglue_register_property(ctx, &ScAward::imageId_get, nullptr, "imageId"); + dukglue_register_property(ctx, &ScAward::monthsRemaining_get, nullptr, "monthsRemaining"); + } + + Award* ScAward::GetAward() const + { + return &getGameState().currentAwards[_index]; + } + + std::string ScAward::type_get() const + { + auto award = GetAward(); + if (award == nullptr) + return {}; + + return AwardTypeToString(award->Type).value_or(std::string()); + } + + std::string ScAward::text_get() const + { + auto award = GetAward(); + if (award == nullptr) + return {}; + + Formatter ft{}; + ft.Add(AwardGetText(award->Type)); + return FormatStringIDLegacy(STR_STRINGID, ft.Data()); + } + + uint16_t ScAward::monthsRemaining_get() const + { + auto award = GetAward(); + if (award == nullptr) + return {}; + + return award->Time; + } + + bool ScAward::positive_get() const + { + auto award = GetAward(); + if (award == nullptr) + return {}; + + return AwardIsPositive(award->Type); + } + + uint32_t ScAward::imageId_get() const + { + auto award = GetAward(); + if (award == nullptr) + return {}; + + return AwardGetSprite(award->Type); + } + +} // namespace OpenRCT2::Scripting + +#endif diff --git a/src/openrct2/scripting/bindings/world/ScAward.hpp b/src/openrct2/scripting/bindings/world/ScAward.hpp new file mode 100644 index 0000000000..f38b1a556f --- /dev/null +++ b/src/openrct2/scripting/bindings/world/ScAward.hpp @@ -0,0 +1,85 @@ +/***************************************************************************** + * Copyright (c) 2014-2025 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 "../../../management/Award.h" + #include "../../Duktape.hpp" + #include "../../ScriptEngine.h" + + #include + +namespace OpenRCT2::Scripting +{ + static constexpr const char* AwardTypes[] = { + "mostUntidy", + "mostTidy", + "bestRollerCoasters", + "bestValue", + "mostBeautiful", + "worstValue", + "safest", + "bestStaff", + "bestFood", + "worstFood", + "bestToilets", + "mostDisappointing", + "bestWaterRides", + "bestCustomDesignedRides", + "mostDazzlingRideColours", + "mostConfusingLayout", + "bestGentleRides", + }; + + inline std::optional AwardTypeToString(AwardType awardType) + { + auto index = static_cast(awardType); + if (index < std::size(AwardTypes)) + { + return AwardTypes[index]; + } + return std::nullopt; + } + + inline std::optional StringToAwardType(std::string_view awardType) + { + auto it = std::find(std::begin(AwardTypes), std::end(AwardTypes), awardType); + if (it != std::end(AwardTypes)) + { + return std::optional(static_cast(std::distance(std::begin(AwardTypes), it))); + } + return std::nullopt; + } + + class ScAward + { + private: + size_t _index{}; + + public: + ScAward(size_t index); + + static void Register(duk_context* ctx); + + private: + Award* GetAward() const; + + std::string type_get() const; + std::string text_get() const; + uint16_t monthsRemaining_get() const; + bool positive_get() const; + uint32_t imageId_get() const; + }; + +} // namespace OpenRCT2::Scripting + +#endif diff --git a/src/openrct2/scripting/bindings/world/ScPark.cpp b/src/openrct2/scripting/bindings/world/ScPark.cpp index 555bcff057..5dabf66f1c 100644 --- a/src/openrct2/scripting/bindings/world/ScPark.cpp +++ b/src/openrct2/scripting/bindings/world/ScPark.cpp @@ -430,6 +430,35 @@ namespace OpenRCT2::Scripting return result; } + std::vector> ScPark::awards_get() const + { + std::vector> result; + + auto& gameState = getGameState(); + for (size_t i = 0; i < gameState.currentAwards.size(); i++) + { + result.push_back(std::make_shared(i)); + } + + return result; + } + + void ScPark::clearAwards() const + { + ThrowIfGameStateNotMutable(); + AwardReset(); + } + + void ScPark::grantAward(const std::string& awardType) const + { + ThrowIfGameStateNotMutable(); + auto optType = StringToAwardType(awardType); + if (optType.has_value()) + { + AwardGrant(optType.value()); + } + } + void ScPark::Register(duk_context* ctx) { dukglue_register_property(ctx, &ScPark::cash_get, &ScPark::cash_set, "cash"); @@ -463,6 +492,9 @@ namespace OpenRCT2::Scripting dukglue_register_method(ctx, &ScPark::setFlag, "setFlag"); dukglue_register_method(ctx, &ScPark::postMessage, "postMessage"); dukglue_register_method(ctx, &ScPark::getMonthlyExpenditure, "getMonthlyExpenditure"); + dukglue_register_property(ctx, &ScPark::awards_get, nullptr, "awards"); + dukglue_register_method(ctx, &ScPark::clearAwards, "clearAwards"); + dukglue_register_method(ctx, &ScPark::grantAward, "grantAward"); } } // namespace OpenRCT2::Scripting diff --git a/src/openrct2/scripting/bindings/world/ScPark.hpp b/src/openrct2/scripting/bindings/world/ScPark.hpp index 42668dbe9c..dcef4d4377 100644 --- a/src/openrct2/scripting/bindings/world/ScPark.hpp +++ b/src/openrct2/scripting/bindings/world/ScPark.hpp @@ -13,6 +13,7 @@ #include "../../../Context.h" #include "../../Duktape.hpp" + #include "ScAward.hpp" #include "ScParkMessage.hpp" #include "ScResearch.hpp" @@ -101,6 +102,12 @@ namespace OpenRCT2::Scripting std::vector getMonthlyExpenditure(const std::string& expenditureType) const; + std::vector> awards_get() const; + + void clearAwards() const; + + void grantAward(const std::string& awardType) const; + static void Register(duk_context* ctx); }; } // namespace OpenRCT2::Scripting