Shipwright/soh/soh/Enhancements/randomizer/item.cpp
Philip Dubé 28944cc68f
fix some warnings (#5135)
* fix some warnings

* fix error caught by mac build, fix 3 more warnings

* merge fix

* feedback

* remove color refactor
2025-03-19 12:30:44 -04:00

449 lines
16 KiB
C++

#include "item.h"
#include "item_location.h"
#include "context.h"
#include "logic.h"
#include "3drando/item_pool.hpp"
#include "z64item.h"
#include "variables.h"
#include "macros.h"
#include "functions.h"
#include "../../OTRGlobals.h"
namespace Rando {
Item::Item() : randomizerGet(RG_NONE), type(ITEMTYPE_ITEM), getItemId(GI_NONE), advancement(false), hintKey(RHT_NONE),
progressive(false), price(0) {}
Item::Item(const RandomizerGet randomizerGet_, Text name_, const ItemType type_, const int16_t getItemId_,
const bool advancement_, LogicVal logicVal_, const RandomizerHintTextKey hintKey_, const uint16_t itemId_,
const uint16_t objectId_, const uint16_t gid_, const uint16_t textId_, const uint16_t field_,
const int16_t chestAnimation_, const GetItemCategory category_, const uint16_t modIndex_,
const bool progressive_, const uint16_t price_)
: randomizerGet(randomizerGet_), name(std::move(name_)), type(type_), getItemId(getItemId_),
advancement(advancement_), logicVal(logicVal_), hintKey(hintKey_), progressive(progressive_), price(price_) {
if (modIndex_ == MOD_RANDOMIZER || getItemId > 0x7D) {
giEntry = std::make_shared<GetItemEntry>(GetItemEntry{ itemId_, field_, static_cast<int16_t>((chestAnimation_ != CHEST_ANIM_SHORT ? 1 : -1) * (gid_ + 1)), textId_, objectId_, modIndex_, TABLE_RANDOMIZER, static_cast<int16_t>(randomizerGet_), gid_, true, ITEM_FROM_NPC, category_, static_cast<uint16_t>(randomizerGet_), MOD_RANDOMIZER, NULL });
}
else {
giEntry = std::make_shared<GetItemEntry>(GetItemEntry{ itemId_, field_, static_cast<int16_t>((chestAnimation_ != CHEST_ANIM_SHORT ? 1 : -1) * (gid_ + 1)), textId_, objectId_, modIndex_, TABLE_VANILLA, getItemId_, gid_, true, ITEM_FROM_NPC, category_, itemId_, modIndex_, NULL });
}
}
Item::Item(const RandomizerGet randomizerGet_, Text name_, const ItemType type_, const int16_t getItemId_,
const bool advancement_, LogicVal logicVal_, const RandomizerHintTextKey hintKey_, const bool progressive_,
const uint16_t price_)
: randomizerGet(randomizerGet_), name(std::move(name_)), type(type_), getItemId(getItemId_),
advancement(advancement_), logicVal(logicVal_), hintKey(hintKey_), progressive(progressive_), price(price_) {
}
Item::~Item() = default;
void Item::ApplyEffect() const {
auto ctx = Rando::Context::GetInstance();
ctx->GetLogic()->ApplyItemEffect(StaticData::RetrieveItem(randomizerGet), true);
ctx->GetLogic()->SetInLogic(logicVal, true);
}
void Item::UndoEffect() const {
auto ctx = Rando::Context::GetInstance();
ctx->GetLogic()->ApplyItemEffect(StaticData::RetrieveItem(randomizerGet), false);
ctx->GetLogic()->SetInLogic(logicVal, false);
}
const Text& Item::GetName() const {
return name;
}
bool Item::IsAdvancement() const {
return advancement;
}
int Item::GetItemID() const {
return getItemId;
}
ItemType Item::GetItemType() const {
return type;
}
LogicVal Item::GetLogicVal() const {
return logicVal;
}
RandomizerGet Item::GetRandomizerGet() const {
return randomizerGet;
}
uint16_t Item::GetPrice() const {
return price;
}
std::shared_ptr<GetItemEntry> Item::GetGIEntry() const { // NOLINT(*-no-recursion)
if (giEntry != nullptr) {
return giEntry;
}
std::shared_ptr<Rando::Context> ctx = Rando::Context::GetInstance();
auto logic = ctx->GetLogic();
RandomizerGet actual = RG_NONE;
const bool tycoonWallet = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INCLUDE_TYCOON_WALLET);
const u8 infiniteUpgrades = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_INFINITE_UPGRADES);
switch (randomizerGet) {
case RG_PROGRESSIVE_STICK_UPGRADE:
switch (logic->CurrentUpgrade(UPG_STICKS)) {
case 0:
if (ctx->GetOption(RSK_SHUFFLE_DEKU_STICK_BAG)) {
actual = RG_DEKU_STICK_BAG;
break;
}
[[fallthrough]];
case 1:
if (infiniteUpgrades == RO_INF_UPGRADES_CONDENSED_PROGRESSIVE) {
actual = RG_STICK_UPGRADE_INF;
} else {
actual = RG_DEKU_STICK_CAPACITY_20;
}
break;
case 2:
actual = RG_DEKU_STICK_CAPACITY_30;
break;
case 3:
case 4:
if (infiniteUpgrades == RO_INF_UPGRADES_PROGRESSIVE) {
actual = RG_STICK_UPGRADE_INF;
} else {
actual = RG_DEKU_STICK_CAPACITY_30;
}
break;
default:
break;
}
break;
case RG_PROGRESSIVE_NUT_UPGRADE:
switch (logic->CurrentUpgrade(UPG_NUTS)) {
case 0:
if (ctx->GetOption(RSK_SHUFFLE_DEKU_NUT_BAG)) {
actual = RG_DEKU_NUT_BAG;
break;
}
[[fallthrough]];
case 1:
if (infiniteUpgrades == RO_INF_UPGRADES_CONDENSED_PROGRESSIVE) {
actual = RG_NUT_UPGRADE_INF;
} else {
actual = RG_DEKU_NUT_CAPACITY_30;
}
break;
case 2:
actual = RG_DEKU_NUT_CAPACITY_40;
break;
case 3:
case 4:
if (infiniteUpgrades == RO_INF_UPGRADES_PROGRESSIVE) {
actual = RG_NUT_UPGRADE_INF;
} else {
actual = RG_DEKU_NUT_CAPACITY_40;
}
break;
default:
break;
}
break;
case RG_PROGRESSIVE_BOMB_BAG:
switch (logic->CurrentUpgrade(UPG_BOMB_BAG)) {
case 0:
actual = RG_BOMB_BAG;
break;
case 1:
if (infiniteUpgrades == RO_INF_UPGRADES_CONDENSED_PROGRESSIVE) {
actual = RG_BOMB_BAG_INF;
} else {
actual = RG_BIG_BOMB_BAG;
}
break;
case 2:
actual = RG_BIGGEST_BOMB_BAG;
break;
case 3:
case 4:
if (infiniteUpgrades == RO_INF_UPGRADES_PROGRESSIVE) {
actual = RG_BOMB_BAG_INF;
} else {
actual = RG_BIGGEST_BOMB_BAG;
}
break;
default:
break;
}
break;
case RG_PROGRESSIVE_BOW:
switch (logic->CurrentUpgrade(UPG_QUIVER)) {
case 0:
actual = RG_FAIRY_BOW;
break;
case 1:
if (infiniteUpgrades == RO_INF_UPGRADES_CONDENSED_PROGRESSIVE) {
actual = RG_QUIVER_INF;
} else {
actual = RG_BIG_QUIVER;
}
break;
case 2:
actual = RG_BIGGEST_QUIVER;
break;
case 3:
case 4:
if (infiniteUpgrades == RO_INF_UPGRADES_PROGRESSIVE) {
actual = RG_QUIVER_INF;
} else {
actual = RG_BIGGEST_QUIVER;
}
break;
default:
break;
}
break;
case RG_PROGRESSIVE_SLINGSHOT:
switch (logic->CurrentUpgrade(UPG_BULLET_BAG)) {
case 0:
actual = RG_FAIRY_SLINGSHOT;
break;
case 1:
if (infiniteUpgrades == RO_INF_UPGRADES_CONDENSED_PROGRESSIVE) {
actual = RG_BULLET_BAG_INF;
} else {
actual = RG_BIG_BULLET_BAG;
}
break;
case 2:
actual = RG_BIGGEST_BULLET_BAG;
break;
case 3:
case 4:
if (infiniteUpgrades == RO_INF_UPGRADES_PROGRESSIVE) {
actual = RG_BULLET_BAG_INF;
} else {
actual = RG_BIGGEST_BULLET_BAG;
}
break;
default:
break;
}
break;
case RG_PROGRESSIVE_OCARINA:
switch (logic->CurrentInventory(ITEM_OCARINA_FAIRY)) {
case ITEM_NONE:
actual = RG_FAIRY_OCARINA;
break;
case ITEM_OCARINA_FAIRY:
case ITEM_OCARINA_TIME:
actual = RG_OCARINA_OF_TIME;
break;
default:
break;
}
break;
case RG_PROGRESSIVE_HOOKSHOT:
switch (logic->CurrentInventory(ITEM_HOOKSHOT)) {
case ITEM_NONE:
actual = RG_HOOKSHOT;
break;
case ITEM_HOOKSHOT:
case ITEM_LONGSHOT:
actual = RG_LONGSHOT;
break;
default:
break;
}
break;
case RG_PROGRESSIVE_STRENGTH:
switch (logic->CurrentUpgrade(UPG_STRENGTH)) {
case 0:
actual = RG_GORONS_BRACELET;
break;
case 1:
actual = RG_SILVER_GAUNTLETS;
break;
case 2:
case 3:
actual = RG_GOLDEN_GAUNTLETS;
break;
default:
break;
}
break;
case RG_PROGRESSIVE_WALLET:
if (!logic->CheckRandoInf(RAND_INF_HAS_WALLET)) {
actual = RG_CHILD_WALLET;
break;
}
switch (logic->CurrentUpgrade(UPG_WALLET)) {
case 0:
actual = RG_ADULT_WALLET;
break;
case 1:
actual = RG_GIANT_WALLET;
break;
case 2:
if(tycoonWallet){
actual = RG_TYCOON_WALLET;
break;
}
//fallthrough
case 3:
case 4:
if (infiniteUpgrades != RO_INF_UPGRADES_OFF) {
actual = RG_WALLET_INF;
} else {
actual = tycoonWallet ? RG_TYCOON_WALLET : RG_GIANT_WALLET;
}
break;
default:
break;
}
break;
case RG_PROGRESSIVE_SCALE:
if (!logic->CheckRandoInf(RAND_INF_CAN_SWIM)) {
actual = RG_BRONZE_SCALE;
break;
}
switch (logic->CurrentUpgrade(UPG_SCALE)) {
case 0:
actual = RG_SILVER_SCALE;
break;
case 1:
case 2:
actual = RG_GOLDEN_SCALE;
break;
default:
break;
}
break;
case RG_PROGRESSIVE_MAGIC_METER:
switch (logic->GetSaveContext()->magicLevel) {
case 0:
actual = RG_MAGIC_SINGLE;
break;
case 1:
actual = RG_MAGIC_DOUBLE;
break;
case 2:
case 3:
if (infiniteUpgrades != RO_INF_UPGRADES_OFF) {
actual = RG_MAGIC_INF;
} else {
actual = RG_MAGIC_DOUBLE;
}
break;
default:
break;
}
break;
case RG_PROGRESSIVE_GORONSWORD: // todo progressive?
actual = RG_BIGGORON_SWORD;
break;
case RG_PROGRESSIVE_BOMBCHUS:
if (logic->CurrentInventory(ITEM_BOMBCHU) == ITEM_NONE) {
actual = RG_BOMBCHU_BAG;
} else if (infiniteUpgrades != RO_INF_UPGRADES_OFF) {
actual = RG_BOMBCHU_INF;
} else {
actual = RG_BOMBCHU_10;
}
break;
default:
actual = RG_NONE;
break;
}
return StaticData::RetrieveItem(actual).GetGIEntry();
}
GetItemEntry Item::GetGIEntry_Copy() const {
return *GetGIEntry();
}
void Item::SetPrice(const uint16_t price_) {
price = price_;
}
void Item::SetAsPlaythrough() {
playthrough = true;
}
void Item::SetCustomDrawFunc(const CustomDrawFunc drawFunc) const {
giEntry->drawFunc = drawFunc;
}
bool Item::IsPlaythrough() const {
return playthrough;
}
bool Item::IsBottleItem() const {
return getItemId == 0x0F || // Empty Bottle
getItemId == 0X14 || // Bottle with Milk
(getItemId >= 0x8C && getItemId <= 0x94); // Rest of bottled contents
}
bool Item::IsMajorItem() const {
const auto ctx = Context::GetInstance();
if (type == ITEMTYPE_TOKEN) {
return ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS) || ctx->LACSCondition() == RO_LACS_TOKENS;
}
if (type == ITEMTYPE_DROP || type == ITEMTYPE_EVENT || type == ITEMTYPE_SHOP || type == ITEMTYPE_MAP ||
type == ITEMTYPE_COMPASS) {
return false;
}
if (type == ITEMTYPE_DUNGEONREWARD && ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
return false;
}
if ((randomizerGet == RG_BOMBCHU_5 || randomizerGet == RG_BOMBCHU_10 || randomizerGet == RG_BOMBCHU_20) &&
!ctx->GetOption(RSK_BOMBCHU_BAG)) {
return false;
}
if (randomizerGet == RG_HEART_CONTAINER || randomizerGet == RG_PIECE_OF_HEART ||
randomizerGet == RG_TREASURE_GAME_HEART) {
return false;
}
if (type == ITEMTYPE_SMALLKEY && (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA) || ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON))) {
return false;
}
if (type == ITEMTYPE_FORTRESS_SMALLKEY && ctx->GetOption(RSK_GERUDO_KEYS).Is(RO_GERUDO_KEYS_VANILLA)) {
return false;
}
if (type == ITEMTYPE_BOSSKEY && getItemId != 0xAD &&
(ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA) || ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON))) {
return false;
}
// Ganons Castle Boss Key
if (getItemId == 0xAD && (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA) || ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON))) {
return false;
}
if (randomizerGet == RG_GREG_RUPEE) {
return ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG);
}
return IsAdvancement();
}
RandomizerHintTextKey Item::GetHintKey() const {
return hintKey;
}
const HintText& Item::GetHint() const {
return StaticData::hintTextTable[hintKey];
}
bool Item::operator==(const Item& right) const {
return type == right.GetItemType() && getItemId == right.GetItemID();
}
bool Item::operator!=(const Item& right) const {
return !operator==(right);
}
}