1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00
Files
OpenRCT2/src/openrct2/scripting/bindings/entity/ScGuest.cpp
Aaron van Geffen c034d2c921 Introduce PeepAnimation compilation unit (#23383)
* Move StaffType enum into Staff.h

* Introduce PeepAnimation compilation unit
2024-12-12 00:23:42 +01:00

1019 lines
35 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2024 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 "ScGuest.hpp"
#include "../../../GameState.h"
#include "../../../entity/Guest.h"
#include "../../../localisation/Formatting.h"
#include "../../../peep/PeepAnimationData.h"
#include "../../../peep/PeepAnimations.h"
#include "../../../ride/RideEntry.h"
namespace OpenRCT2::Scripting
{
static const DukEnumMap<PeepThoughtType> ThoughtTypeMap({
{ "cant_afford_ride", PeepThoughtType::CantAffordRide },
{ "spent_money", PeepThoughtType::SpentMoney },
{ "sick", PeepThoughtType::Sick },
{ "very_sick", PeepThoughtType::VerySick },
{ "more_thrilling", PeepThoughtType::MoreThrilling },
{ "intense", PeepThoughtType::Intense },
{ "havent_finished", PeepThoughtType::HaventFinished },
{ "sickening", PeepThoughtType::Sickening },
{ "bad_value", PeepThoughtType::BadValue },
{ "go_home", PeepThoughtType::GoHome },
{ "good_value", PeepThoughtType::GoodValue },
{ "already_got", PeepThoughtType::AlreadyGot },
{ "cant_afford_item", PeepThoughtType::CantAffordItem },
{ "not_hungry", PeepThoughtType::NotHungry },
{ "not_thirsty", PeepThoughtType::NotThirsty },
{ "drowning", PeepThoughtType::Drowning },
{ "lost", PeepThoughtType::Lost },
{ "was_great", PeepThoughtType::WasGreat },
{ "queuing_ages", PeepThoughtType::QueuingAges },
{ "tired", PeepThoughtType::Tired },
{ "hungry", PeepThoughtType::Hungry },
{ "thirsty", PeepThoughtType::Thirsty },
{ "toilet", PeepThoughtType::Toilet },
{ "cant_find", PeepThoughtType::CantFind },
{ "not_paying", PeepThoughtType::NotPaying },
{ "not_while_raining", PeepThoughtType::NotWhileRaining },
{ "bad_litter", PeepThoughtType::BadLitter },
{ "cant_find_exit", PeepThoughtType::CantFindExit },
{ "get_off", PeepThoughtType::GetOff },
{ "get_out", PeepThoughtType::GetOut },
{ "not_safe", PeepThoughtType::NotSafe },
{ "path_disgusting", PeepThoughtType::PathDisgusting },
{ "crowded", PeepThoughtType::Crowded },
{ "vandalism", PeepThoughtType::Vandalism },
{ "scenery", PeepThoughtType::Scenery },
{ "very_clean", PeepThoughtType::VeryClean },
{ "fountains", PeepThoughtType::Fountains },
{ "music", PeepThoughtType::Music },
{ "balloon", PeepThoughtType::Balloon },
{ "toy", PeepThoughtType::Toy },
{ "map", PeepThoughtType::Map },
{ "photo", PeepThoughtType::Photo },
{ "umbrella", PeepThoughtType::Umbrella },
{ "drink", PeepThoughtType::Drink },
{ "burger", PeepThoughtType::Burger },
{ "chips", PeepThoughtType::Chips },
{ "ice_cream", PeepThoughtType::IceCream },
{ "candyfloss", PeepThoughtType::Candyfloss },
{ "pizza", PeepThoughtType::Pizza },
{ "popcorn", PeepThoughtType::Popcorn },
{ "hot_dog", PeepThoughtType::HotDog },
{ "tentacle", PeepThoughtType::Tentacle },
{ "hat", PeepThoughtType::Hat },
{ "toffee_apple", PeepThoughtType::ToffeeApple },
{ "tshirt", PeepThoughtType::Tshirt },
{ "doughnut", PeepThoughtType::Doughnut },
{ "coffee", PeepThoughtType::Coffee },
{ "chicken", PeepThoughtType::Chicken },
{ "lemonade", PeepThoughtType::Lemonade },
{ "wow", PeepThoughtType::Wow },
{ "wow2", PeepThoughtType::Wow2 },
{ "watched", PeepThoughtType::Watched },
{ "balloon_much", PeepThoughtType::BalloonMuch },
{ "toy_much", PeepThoughtType::ToyMuch },
{ "map_much", PeepThoughtType::MapMuch },
{ "photo_much", PeepThoughtType::PhotoMuch },
{ "umbrella_much", PeepThoughtType::UmbrellaMuch },
{ "drink_much", PeepThoughtType::DrinkMuch },
{ "burger_much", PeepThoughtType::BurgerMuch },
{ "chips_much", PeepThoughtType::ChipsMuch },
{ "ice_cream_much", PeepThoughtType::IceCreamMuch },
{ "candyfloss_much", PeepThoughtType::CandyflossMuch },
{ "pizza_much", PeepThoughtType::PizzaMuch },
{ "popcorn_much", PeepThoughtType::PopcornMuch },
{ "hot_dog_much", PeepThoughtType::HotDogMuch },
{ "tentacle_much", PeepThoughtType::TentacleMuch },
{ "hat_much", PeepThoughtType::HatMuch },
{ "toffee_apple_much", PeepThoughtType::ToffeeAppleMuch },
{ "tshirt_much", PeepThoughtType::TshirtMuch },
{ "doughnut_much", PeepThoughtType::DoughnutMuch },
{ "coffee_much", PeepThoughtType::CoffeeMuch },
{ "chicken_much", PeepThoughtType::ChickenMuch },
{ "lemonade_much", PeepThoughtType::LemonadeMuch },
{ "photo2", PeepThoughtType::Photo2 },
{ "photo3", PeepThoughtType::Photo3 },
{ "photo4", PeepThoughtType::Photo4 },
{ "pretzel", PeepThoughtType::Pretzel },
{ "hot_chocolate", PeepThoughtType::HotChocolate },
{ "iced_tea", PeepThoughtType::IcedTea },
{ "funnel_cake", PeepThoughtType::FunnelCake },
{ "sunglasses", PeepThoughtType::Sunglasses },
{ "beef_noodles", PeepThoughtType::BeefNoodles },
{ "fried_rice_noodles", PeepThoughtType::FriedRiceNoodles },
{ "wonton_soup", PeepThoughtType::WontonSoup },
{ "meatball_soup", PeepThoughtType::MeatballSoup },
{ "fruit_juice", PeepThoughtType::FruitJuice },
{ "soybean_milk", PeepThoughtType::SoybeanMilk },
{ "sujongkwa", PeepThoughtType::Sujongkwa },
{ "sub_sandwich", PeepThoughtType::SubSandwich },
{ "cookie", PeepThoughtType::Cookie },
{ "roast_sausage", PeepThoughtType::RoastSausage },
{ "photo2_much", PeepThoughtType::Photo2Much },
{ "photo3_much", PeepThoughtType::Photo3Much },
{ "photo4_much", PeepThoughtType::Photo4Much },
{ "pretzel_much", PeepThoughtType::PretzelMuch },
{ "hot_chocolate_much", PeepThoughtType::HotChocolateMuch },
{ "iced_tea_much", PeepThoughtType::IcedTeaMuch },
{ "funnel_cake_much", PeepThoughtType::FunnelCakeMuch },
{ "sunglasses_much", PeepThoughtType::SunglassesMuch },
{ "beef_noodles_much", PeepThoughtType::BeefNoodlesMuch },
{ "fried_rice_noodles_much", PeepThoughtType::FriedRiceNoodlesMuch },
{ "wonton_soup_much", PeepThoughtType::WontonSoupMuch },
{ "meatball_soup_much", PeepThoughtType::MeatballSoupMuch },
{ "fruit_juice_much", PeepThoughtType::FruitJuiceMuch },
{ "soybean_milk_much", PeepThoughtType::SoybeanMilkMuch },
{ "sujongkwa_much", PeepThoughtType::SujongkwaMuch },
{ "sub_sandwich_much", PeepThoughtType::SubSandwichMuch },
{ "cookie_much", PeepThoughtType::CookieMuch },
{ "roast_sausage_much", PeepThoughtType::RoastSausageMuch },
{ "help", PeepThoughtType::Help },
{ "running_out", PeepThoughtType::RunningOut },
{ "new_ride", PeepThoughtType::NewRide },
{ "nice_ride_deprecated", PeepThoughtType::NiceRideDeprecated },
{ "excited_deprecated", PeepThoughtType::ExcitedDeprecated },
{ "here_we_are", PeepThoughtType::HereWeAre },
});
ScGuest::ScGuest(EntityId id)
: ScPeep(id)
{
}
void ScGuest::Register(duk_context* ctx)
{
dukglue_set_base_class<ScPeep, ScGuest>(ctx);
dukglue_register_property(ctx, &ScGuest::tshirtColour_get, &ScGuest::tshirtColour_set, "tshirtColour");
dukglue_register_property(ctx, &ScGuest::trousersColour_get, &ScGuest::trousersColour_set, "trousersColour");
dukglue_register_property(ctx, &ScGuest::balloonColour_get, &ScGuest::balloonColour_set, "balloonColour");
dukglue_register_property(ctx, &ScGuest::hatColour_get, &ScGuest::hatColour_set, "hatColour");
dukglue_register_property(ctx, &ScGuest::umbrellaColour_get, &ScGuest::umbrellaColour_set, "umbrellaColour");
dukglue_register_property(ctx, &ScGuest::happiness_get, &ScGuest::happiness_set, "happiness");
dukglue_register_property(ctx, &ScGuest::happinessTarget_get, &ScGuest::happinessTarget_set, "happinessTarget");
dukglue_register_property(ctx, &ScGuest::nausea_get, &ScGuest::nausea_set, "nausea");
dukglue_register_property(ctx, &ScGuest::nauseaTarget_get, &ScGuest::nauseaTarget_set, "nauseaTarget");
dukglue_register_property(ctx, &ScGuest::hunger_get, &ScGuest::hunger_set, "hunger");
dukglue_register_property(ctx, &ScGuest::thirst_get, &ScGuest::thirst_set, "thirst");
dukglue_register_property(ctx, &ScGuest::toilet_get, &ScGuest::toilet_set, "toilet");
dukglue_register_property(ctx, &ScGuest::mass_get, &ScGuest::mass_set, "mass");
dukglue_register_property(ctx, &ScGuest::minIntensity_get, &ScGuest::minIntensity_set, "minIntensity");
dukglue_register_property(ctx, &ScGuest::maxIntensity_get, &ScGuest::maxIntensity_set, "maxIntensity");
dukglue_register_property(ctx, &ScGuest::nauseaTolerance_get, &ScGuest::nauseaTolerance_set, "nauseaTolerance");
dukglue_register_property(ctx, &ScGuest::cash_get, &ScGuest::cash_set, "cash");
dukglue_register_property(ctx, &ScGuest::isInPark_get, nullptr, "isInPark");
dukglue_register_property(ctx, &ScGuest::isLost_get, nullptr, "isLost");
dukglue_register_property(ctx, &ScGuest::lostCountdown_get, &ScGuest::lostCountdown_set, "lostCountdown");
dukglue_register_property(ctx, &ScGuest::favouriteRide_get, &ScGuest::favouriteRide_set, "favouriteRide");
dukglue_register_property(ctx, &ScGuest::thoughts_get, nullptr, "thoughts");
dukglue_register_property(ctx, &ScGuest::items_get, nullptr, "items");
dukglue_register_property(ctx, &ScGuest::availableAnimations_get, nullptr, "availableAnimations");
dukglue_register_property(ctx, &ScGuest::animation_get, &ScGuest::animation_set, "animation");
dukglue_register_property(ctx, &ScGuest::animationOffset_get, &ScGuest::animationOffset_set, "animationOffset");
dukglue_register_property(ctx, &ScGuest::animationLength_get, nullptr, "animationLength");
dukglue_register_method(ctx, &ScGuest::getAnimationSpriteIds, "getAnimationSpriteIds");
dukglue_register_method(ctx, &ScGuest::has_item, "hasItem");
dukglue_register_method(ctx, &ScGuest::give_item, "giveItem");
dukglue_register_method(ctx, &ScGuest::remove_item, "removeItem");
dukglue_register_method(ctx, &ScGuest::remove_all_items, "removeAllItems");
}
Guest* ScGuest::GetGuest() const
{
return ::GetEntity<Guest>(_id);
}
uint8_t ScGuest::tshirtColour_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->TshirtColour : 0;
}
void ScGuest::tshirtColour_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->TshirtColour = value;
peep->Invalidate();
}
}
uint8_t ScGuest::trousersColour_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->TrousersColour : 0;
}
void ScGuest::trousersColour_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->TrousersColour = value;
peep->Invalidate();
}
}
uint8_t ScGuest::balloonColour_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->BalloonColour : 0;
}
void ScGuest::balloonColour_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->BalloonColour = value;
peep->Invalidate();
}
}
uint8_t ScGuest::hatColour_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->HatColour : 0;
}
void ScGuest::hatColour_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->HatColour = value;
peep->Invalidate();
}
}
uint8_t ScGuest::umbrellaColour_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->UmbrellaColour : 0;
}
void ScGuest::umbrellaColour_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->UmbrellaColour = value;
peep->Invalidate();
}
}
uint8_t ScGuest::happiness_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Happiness : 0;
}
void ScGuest::happiness_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Happiness = value;
}
}
uint8_t ScGuest::happinessTarget_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->HappinessTarget : 0;
}
void ScGuest::happinessTarget_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->HappinessTarget = value;
}
}
uint8_t ScGuest::nausea_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Nausea : 0;
}
void ScGuest::nausea_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Nausea = value;
}
}
uint8_t ScGuest::nauseaTarget_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->NauseaTarget : 0;
}
void ScGuest::nauseaTarget_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->NauseaTarget = value;
}
}
uint8_t ScGuest::hunger_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Hunger : 0;
}
void ScGuest::hunger_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Hunger = value;
}
}
uint8_t ScGuest::thirst_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Thirst : 0;
}
void ScGuest::thirst_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Thirst = value;
}
}
uint8_t ScGuest::toilet_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Toilet : 0;
}
void ScGuest::toilet_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Toilet = value;
}
}
uint8_t ScGuest::mass_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Mass : 0;
}
void ScGuest::mass_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Mass = value;
}
}
uint8_t ScGuest::minIntensity_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Intensity.GetMinimum() : 0;
}
void ScGuest::minIntensity_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Intensity = peep->Intensity.WithMinimum(value);
}
}
uint8_t ScGuest::maxIntensity_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->Intensity.GetMaximum() : 0;
}
void ScGuest::maxIntensity_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->Intensity = peep->Intensity.WithMaximum(value);
}
}
uint8_t ScGuest::nauseaTolerance_get() const
{
auto peep = GetGuest();
return peep != nullptr ? EnumValue(peep->NauseaTolerance) : 0;
}
void ScGuest::nauseaTolerance_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->NauseaTolerance = static_cast<PeepNauseaTolerance>(std::min<uint8_t>(value, 3));
}
}
int32_t ScGuest::cash_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->CashInPocket : 0;
}
void ScGuest::cash_set(int32_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->CashInPocket = std::max(0, value);
}
}
bool ScGuest::isInPark_get() const
{
auto peep = GetGuest();
return (peep != nullptr && !peep->OutsideOfPark);
}
bool ScGuest::isLost_get() const
{
auto peep = GetGuest();
return (peep != nullptr && peep->GuestIsLostCountdown < 90);
}
uint8_t ScGuest::lostCountdown_get() const
{
auto peep = GetGuest();
return peep != nullptr ? peep->GuestIsLostCountdown : 0;
}
void ScGuest::lostCountdown_set(uint8_t value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->GuestIsLostCountdown = value;
}
}
DukValue ScGuest::favouriteRide_get() const
{
auto& scriptEngine = GetContext()->GetScriptEngine();
auto* ctx = scriptEngine.GetContext();
auto peep = GetGuest();
if (peep != nullptr)
{
if (peep->FavouriteRide != RideId::GetNull())
{
duk_push_int(ctx, peep->FavouriteRide.ToUnderlying());
}
else
{
duk_push_null(ctx);
}
}
else
{
duk_push_null(ctx);
}
return DukValue::take_from_stack(ctx);
}
void ScGuest::favouriteRide_set(const DukValue& value)
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
auto& gameState = GetGameState();
if (value.type() == DukValue::Type::NUMBER && value.as_uint() < gameState.Rides.size()
&& gameState.Rides[value.as_uint()].type != RIDE_TYPE_NULL)
{
peep->FavouriteRide = RideId::FromUnderlying(value.as_uint());
}
else
{
peep->FavouriteRide = RideId::GetNull();
}
}
}
DukValue ScGuest::thoughts_get() const
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_push_array(ctx);
auto peep = GetGuest();
if (peep != nullptr)
{
duk_uarridx_t index = 0;
for (const auto& thought : peep->Thoughts)
{
if (thought.type == PeepThoughtType::None)
break;
if (thought.freshness == 0)
continue;
auto scThoughtPtr = std::make_shared<ScThought>(thought);
auto dukThought = GetObjectAsDukValue(ctx, scThoughtPtr);
dukThought.push();
duk_put_prop_index(ctx, -2, index);
index++;
}
}
return DukValue::take_from_stack(ctx, -1);
}
DukValue ScGuest::items_get() const
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_push_array(ctx);
auto peep = GetGuest();
if (peep != nullptr)
{
duk_uarridx_t index = 0;
for (const auto& itemEnumPair : ShopItemMap)
{
auto shopItem = itemEnumPair.second;
if (!peep->HasItem(shopItem))
{
continue;
}
// GuestItem
auto obj = OpenRCT2::Scripting::DukObject(ctx);
obj.Set("type", itemEnumPair.first);
if (shopItem == ShopItem::Voucher)
{
// Voucher
obj.Set("voucherType", VoucherTypeMap[peep->VoucherType]);
if (peep->VoucherType == VOUCHER_TYPE_RIDE_FREE)
{
// RideVoucher
obj.Set("rideId", peep->VoucherRideId.ToUnderlying());
}
else if (peep->VoucherType == VOUCHER_TYPE_FOOD_OR_DRINK_FREE)
{
// FoodDrinkVoucher
obj.Set("item", ShopItemMap[peep->VoucherShopItem]);
}
}
else if (GetShopItemDescriptor(shopItem).IsPhoto())
{
// GuestPhoto
switch (shopItem)
{
case ShopItem::Photo:
obj.Set("rideId", peep->Photo1RideRef.ToUnderlying());
break;
case ShopItem::Photo2:
obj.Set("rideId", peep->Photo2RideRef.ToUnderlying());
break;
case ShopItem::Photo3:
obj.Set("rideId", peep->Photo3RideRef.ToUnderlying());
break;
case ShopItem::Photo4:
obj.Set("rideId", peep->Photo4RideRef.ToUnderlying());
break;
default:
// This should not be possible
duk_error(ctx, DUK_ERR_TYPE_ERROR, "Item is photo without a ride ref.");
}
}
auto dukItem = obj.Take();
dukItem.push();
duk_put_prop_index(ctx, -2, index);
index++;
}
}
return DukValue::take_from_stack(ctx, -1);
}
bool ScGuest::has_item(const DukValue& item) const
{
auto peep = GetGuest();
if (peep == nullptr)
{
return false;
}
if (item["type"].type() != DukValue::Type::STRING)
{
return false;
}
// GuestItem
auto shopItem = ShopItemMap.TryGet(item["type"].as_string());
if (!shopItem || !peep->HasItem(*shopItem))
{
return false;
}
if (*shopItem == ShopItem::Voucher)
{
if (item["voucherType"].type() == DukValue::Type::STRING)
{
// Voucher
auto voucher = VoucherTypeMap.TryGet(item["voucherType"].as_string());
if (!voucher || *voucher != peep->VoucherType)
{
return false;
}
if (*voucher == VOUCHER_TYPE_RIDE_FREE)
{
if (item["rideId"].type() == DukValue::Type::NUMBER)
{
// RideVoucher
if (item["rideId"].as_uint() != peep->VoucherRideId.ToUnderlying())
{
return false;
}
}
}
else if (*voucher == VOUCHER_TYPE_FOOD_OR_DRINK_FREE)
{
if (item["item"].type() == DukValue::Type::STRING)
{
// FoodDrinkVoucher
auto voucherItem = ShopItemMap.TryGet(item["item"].as_string());
if (!voucherItem || *voucherItem != peep->VoucherShopItem)
{
return false;
}
}
}
}
}
else if (GetShopItemDescriptor(*shopItem).IsPhoto())
{
// GuestPhoto
if (item["rideId"].type() == DukValue::Type::NUMBER)
{
switch (*shopItem)
{
case ShopItem::Photo:
if (item["rideId"].as_uint() != peep->Photo1RideRef.ToUnderlying())
{
return false;
}
break;
case ShopItem::Photo2:
if (item["rideId"].as_uint() != peep->Photo2RideRef.ToUnderlying())
{
return false;
}
break;
case ShopItem::Photo3:
if (item["rideId"].as_uint() != peep->Photo3RideRef.ToUnderlying())
{
return false;
}
break;
case ShopItem::Photo4:
if (item["rideId"].as_uint() != peep->Photo4RideRef.ToUnderlying())
{
return false;
}
break;
default:
return false;
}
}
}
return true;
}
void ScGuest::give_item(const DukValue& item) const
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
// GuestItem
if (item["type"].type() != DukValue::Type::STRING)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'type'.");
}
auto shopItem = ShopItemMap.TryGet(item["type"].as_string());
if (!shopItem)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'type'.");
}
if (*shopItem == ShopItem::Voucher)
{
// Voucher
if (item["voucherType"].type() != DukValue::Type::STRING)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'voucherType'.");
}
auto voucherType = VoucherTypeMap.TryGet(item["voucherType"].as_string());
if (!voucherType)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'voucherType'.");
}
if (*voucherType == VOUCHER_TYPE_RIDE_FREE)
{
// RideVoucher
if (item["rideId"].type() != DukValue::Type::NUMBER)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'rideId'.");
}
peep->VoucherRideId = RideId::FromUnderlying(item["rideId"].as_uint());
}
else if (*voucherType == VOUCHER_TYPE_FOOD_OR_DRINK_FREE)
{
// FoodDrinkVoucher
if (item["item"].type() != DukValue::Type::STRING)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'item' (for food/drink voucher).");
}
auto voucherItem = ShopItemMap.TryGet(item["item"].as_string());
if (!voucherItem)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'item' (for food/drink voucher).");
}
peep->VoucherShopItem = *voucherItem;
}
peep->VoucherType = *voucherType;
}
else if (GetShopItemDescriptor(*shopItem).IsPhoto())
{
// GuestPhoto
if (item["rideId"].type() != DukValue::Type::NUMBER)
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
duk_error(ctx, DUK_ERR_ERROR, "Invalid 'rideId'.");
}
switch (*shopItem)
{
case ShopItem::Photo:
peep->Photo1RideRef = RideId::FromUnderlying(item["rideId"].as_uint());
break;
case ShopItem::Photo2:
peep->Photo2RideRef = RideId::FromUnderlying(item["rideId"].as_uint());
break;
case ShopItem::Photo3:
peep->Photo3RideRef = RideId::FromUnderlying(item["rideId"].as_uint());
break;
case ShopItem::Photo4:
peep->Photo4RideRef = RideId::FromUnderlying(item["rideId"].as_uint());
break;
default:
return;
}
}
peep->GiveItem(*shopItem);
peep->UpdateAnimationGroup();
}
void ScGuest::remove_item(const DukValue& item) const
{
ThrowIfGameStateNotMutable();
if (has_item(item))
{
// Since guests can only have one item of a type and this item matches, remove it.
auto peep = GetGuest();
peep->RemoveItem(ShopItemMap[item["type"].as_string()]);
peep->UpdateAnimationGroup();
}
}
void ScGuest::remove_all_items() const
{
ThrowIfGameStateNotMutable();
auto peep = GetGuest();
if (peep != nullptr)
{
peep->RemoveAllItems();
peep->UpdateAnimationGroup();
}
}
std::vector<std::string> ScGuest::availableAnimations_get() const
{
std::vector<std::string> availableAnimations{};
for (auto& animation : getAnimationsByPeepType(AnimationPeepType::Guest))
{
availableAnimations.push_back(std::string(animation.first));
}
return availableAnimations;
}
std::vector<uint32_t> ScGuest::getAnimationSpriteIds(std::string groupKey, uint8_t rotation) const
{
std::vector<uint32_t> spriteIds{};
auto& availableGuestAnimations = getAnimationsByPeepType(AnimationPeepType::Guest);
auto animationType = availableGuestAnimations.TryGet(groupKey);
if (animationType == std::nullopt)
{
return spriteIds;
}
auto peep = GetPeep();
if (peep != nullptr)
{
const auto& animationGroup = GetPeepAnimation(peep->AnimationGroup, *animationType);
for (auto frameOffset : animationGroup.frame_offsets)
{
auto imageId = animationGroup.base_image;
if (animationType != PeepAnimationType::Hanging)
imageId += rotation + frameOffset * 4;
else
imageId += frameOffset;
spriteIds.push_back(imageId);
}
}
return spriteIds;
}
std::string ScGuest::animation_get() const
{
auto* peep = GetGuest();
if (peep == nullptr)
{
return nullptr;
}
auto& availableGuestAnimations = getAnimationsByPeepType(AnimationPeepType::Guest);
std::string_view action = availableGuestAnimations[peep->AnimationType];
// Special consideration for sitting peeps
// TODO: something funky going on in the state machine
if (peep->AnimationType == PeepAnimationType::Walking && peep->State == PeepState::Sitting)
action = availableGuestAnimations[PeepAnimationType::SittingIdle];
return std::string(action);
}
void ScGuest::animation_set(std::string groupKey)
{
ThrowIfGameStateNotMutable();
auto& availableGuestAnimations = getAnimationsByPeepType(AnimationPeepType::Guest);
auto newType = availableGuestAnimations.TryGet(groupKey);
if (newType == std::nullopt)
{
throw DukException() << "Invalid animation for this guest (" << groupKey << ")";
}
auto* peep = GetGuest();
peep->AnimationType = peep->NextAnimationType = *newType;
auto offset = 0;
if (peep->IsActionWalking())
peep->WalkingAnimationFrameNum = offset;
else
peep->AnimationFrameNum = offset;
const auto& animationGroup = GetPeepAnimation(peep->AnimationGroup, peep->AnimationType);
peep->AnimationImageIdOffset = animationGroup.frame_offsets[offset];
peep->UpdateSpriteBoundingBox();
}
uint8_t ScGuest::animationOffset_get() const
{
auto* peep = GetGuest();
if (peep == nullptr)
{
return 0;
}
if (peep->IsActionWalking())
return peep->WalkingAnimationFrameNum;
else
return peep->AnimationFrameNum;
}
void ScGuest::animationOffset_set(uint8_t offset)
{
ThrowIfGameStateNotMutable();
auto* peep = GetGuest();
const auto& animationGroup = GetPeepAnimation(peep->AnimationGroup, peep->AnimationType);
auto length = animationGroup.frame_offsets.size();
offset %= length;
if (peep->IsActionWalking())
peep->WalkingAnimationFrameNum = offset;
else
peep->AnimationFrameNum = offset;
peep->AnimationImageIdOffset = animationGroup.frame_offsets[offset];
peep->UpdateSpriteBoundingBox();
}
uint8_t ScGuest::animationLength_get() const
{
auto* peep = GetGuest();
if (peep == nullptr)
{
return 0;
}
const auto& animationGroup = GetPeepAnimation(peep->AnimationGroup, peep->AnimationType);
return static_cast<uint8_t>(animationGroup.frame_offsets.size());
}
ScThought::ScThought(PeepThought backing)
: _backing(backing)
{
}
void ScThought::Register(duk_context* ctx)
{
dukglue_register_property(ctx, &ScThought::type_get, nullptr, "type");
dukglue_register_property(ctx, &ScThought::item_get, nullptr, "item");
dukglue_register_property(ctx, &ScThought::freshness_get, nullptr, "freshness");
dukglue_register_property(ctx, &ScThought::freshTimeout_get, nullptr, "freshTimeout");
dukglue_register_method(ctx, &ScThought::toString, "toString");
}
std::string ScThought::type_get() const
{
return std::string(ThoughtTypeMap[_backing.type]);
}
uint16_t ScThought::item_get() const
{
return _backing.item;
}
uint8_t ScThought::freshness_get() const
{
return _backing.freshness;
}
uint8_t ScThought::freshTimeout_get() const
{
return _backing.fresh_timeout;
}
std::string ScThought::toString() const
{
// format string with arguments
auto ft = Formatter();
PeepThoughtSetFormatArgs(&_backing, ft);
return FormatStringIDLegacy(STR_STRINGID, ft.Data());
}
} // namespace OpenRCT2::Scripting
#endif