Rework Get Item Table to be more flexible for adding custom items (#1050)

* Adds ItemTableManager class.

* Implements new getItem table in game.

* Adds rando item table and way to differentiate tables in GetItemEntry.

* Adds rough ability to differentiate between rando and vanilla items.merge stashed changes from before develop-zhora merge

* Change ItemTableID to be uint16_t so we can use ModIndex for it.

* Should fix switch build

* Should fix switch build pt 2

* Adds new files to CMakeLists.

* Implements fixes for competing getItem calls.

* Correctly renders freestanding items

Particle effects are probably broken, need to fix them still, I pretty
much know how I would do that.

* Fixed Particle effects in the new getItem system.

* Fixes item fanfares

* Partially fixes Ice Traps

Obtaining a freestanding Ice Trap causes link to slide forward
and receiving one from an NPC plays the sound effect and damage
animation but doesn't freeze link.

* Some more partial ice trap fixing that wasn't pushed earlier

* Removes unused function override

* Replaces ::find with ::at and adds exception handling

* Removes some commented out code.

* Refactors rando's GetItemEntry array into two arrays.

One array is for the vanilla items that don't have GetItemEntries in
vanilla, the other is for rando exclusive items. They are stored in
separate arrays before getting added to the table so that we can apply
different modIndexes. The items in the first table have are handled
by the vanilla Item_Give, and the second table needed a custom
`Randomizer_Item_Give` function.

* Renames, relocates, and implements ModIndex enum.

* Removes now unused ItemIDs and GetItemIDs

Also makes all the necessary changes to other code that was still
using them indirectly through the GI to GID map that was removed.
There's quite a lot of changes here and I haven't had time to test them
yet.

* Re-implements GIMESSAGE_UNTRANSLATED as macro

* Removes commented out function.

* Throws exception if an invalid itemID is used

Addresses https://github.com/HarbourMasters/Shipwright/pull/1050#discussion_r943694857

* Removes ARRAY_SIZE in favor of ARRAY_COUNT

ARRAY_COUNT already exists in `macros.h`, I just didn't find it before.

Addresses https://github.com/HarbourMasters/Shipwright/pull/1050#discussion_r943153833

* Inverts CheckContainsRandoItem to CheckContainsVanillaItem.

Addresses https://github.com/HarbourMasters/Shipwright/pull/1050#discussion_r940895135

* Cleanup, bugfixes, removing the `- 1`s from `z_player.c`

* Fixes some funky formatting that got committed earlier.

* Adds else if to added fanfare sound cases.

Addresses https://github.com/HarbourMasters/Shipwright/pull/1050#discussion_r940112924 and https://github.com/HarbourMasters/Shipwright/pull/1050#discussion_r940113492

* Extends GetItemEntry to include getItemId

Also adapts some existing calls for both the entry and the id to only
get the entry.

* Extends GetItemEntry to include GID.

This allows for using it later when drawing freestanding items.

Addresses https://github.com/HarbourMasters/Shipwright/pull/1050#discussion_r943168136

* Rando-specific items use new textId again.

This got lost when merging develop-zhora in because I didn't have custom
messages merged when I started this.

* Sets global modIndex to MOD_NONE on scene load

Fixes a crash when buying items in shops due to them
not triggering the rando code that normally sets these items.
May have also been crashing vanilla playthroughs.

* Realized I had the bgm conditions wrong.

* Fixes "static drops" (i.e. sticks from withered babas)

* Fixes LACS/Prelude situation... again.

* Fixes too many arguments error.

Not sure why this didn't fail to build on Windows before.

* Fixes Link's Pocket items.

* Simplifies sram init for rando-specific items

* Fixes issues with approaching bottleable items.

* Fixes Ruto's Letter.

It was accidentally getting classified as a rando item.

* Should re-fix freestanding ice traps

* Makes freestanding items set player->getItemEntry.

This prevents freestanding items from setting the global modIndex.
This is part of a larger transition that needs to happen to switch
to setting getItemEntries for all of the rando items. This prevents
some things that set getItemId of GI_MAX from granting a Fire Medallion
when the global modIndex is MOD_RANDOMIZER.

* Makes sure we aren't using getItemEntry when not randoed.

* Replace Randomizer_GetRandomizedItemId with Randomizer_GetRandomizedItem and Randomizer_GetItemIdFromKnownCheck with Randomizer_GetItemFromKnownCheck

* Introduce some new methods and migrate most actors to them

* Fixes ocarina game skull kids to set player->getItemEntry

* Sets `z_en_box.c` to set `player->getItemEntry`

* Fix logical errors and migrate most of the rest of the rando checks to GiveItemEntryFromActor

* Use GiveItemEntryFromActorWithFixedRange in item00

* Fixes Anju to set player->getItemEntry.

* Add a few missing cases

* Additional fix for Skull Kid

* Fixes vanilla ice traps and randomized ice smoke

* Fixes rendering of treasure chest game items.

* Removes unused `Randomizer_GetItemIdFromGetItemId`.

* Cleans up an if statement for item00.

* Cleans up another if statement in item00

* This should fix a bug with the Gerudo Archery minigame.

I wasn't able to get the bug to happen after making this change.

* Documents our new GiveItemEntry fuctions.

* Uses more descriptive type name for ItemIDs for creating custom messages.

* Fixes potential issue with if statement.

* Fixes missed type change.

Co-authored-by: Garrett Cox <garrettjcox@gmail.com>
This commit is contained in:
Christopher Leggett 2022-08-23 20:11:38 -04:00 committed by GitHub
parent ed1708508a
commit 168e84498f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 1439 additions and 1087 deletions

View File

@ -218,6 +218,7 @@ set(Header_Files__soh__Enhancements__randomizer__3drando
"soh/Enhancements/randomizer/3drando/trial.hpp"
"soh/Enhancements/randomizer/3drando/utils.hpp"
)
source_group("Header Files\\soh\\Enhancements\\randomizer\\3drando" FILES ${Header_Files__soh__Enhancements__randomizer__3drando})
set(Header_Files__soh__Enhancements__custom_message
@ -227,6 +228,13 @@ set(Header_Files__soh__Enhancements__custom_message
source_group("Header Files\\soh\\Enhancements\\custom-message" FILES ${Header_Files__soh__Enhancements__custom_message})
set(Header_Files__soh__Enhancements__item_tables
"soh/Enhancements/item-tables/ItemTableManager.h"
"soh/Enhancements/item-tables/ItemTableTypes.h"
)
source_group("Header Files\\soh\\Enhancements\\item-tables" FILES ${Header_Files__soh__Enhancements__item_tables})
set(Source_Files__soh
"soh/GbiWrap.cpp"
"soh/OTRAudio.h"
@ -349,6 +357,12 @@ set(Source_Files__soh__Enhancements__custom_message
source_group("Source Files\\soh\\Enhancements\\custom-message" FILES ${Source_Files__soh__Enhancements__custom_message})
set(Source_Files__soh__Enhancements__item_tables
"soh/Enhancements/item-tables/ItemTableManager.cpp"
)
source_group("Source Files\\soh\\Enhancements\\item-tables" FILES ${Source_Files__soh__Enhancements__item_tables})
set(Source_Files__src__boot
"src/boot/assert.c"
"src/boot/boot_main.c"
@ -1558,6 +1572,7 @@ set(ALL_FILES
${Header_Files__soh__Enhancements__debugger}
${Header_Files__soh__Enhancements__randomizer}
${Header_Files__soh__Enhancements__randomizer__3drando}
${Header_Files__soh__Enhancements__item_tables}
${Header_Files__soh__Enhancements__custom_message}
${Source_Files__soh}
${Source_Files__soh__Enhancements}
@ -1568,6 +1583,7 @@ set(ALL_FILES
${Source_Files__soh__Enhancements__randomizer__3drando}
${Source_Files__soh__Enhancements__randomizer__3drando__hint_list}
${Source_Files__soh__Enhancements__randomizer__3drando__location_access}
${Source_Files__soh__Enhancements__item_tables}
${Source_Files__soh__Enhancements__custom_message}
${Source_Files__src__boot}
${Source_Files__src__buffers}

View File

@ -10,6 +10,7 @@ extern "C"
#endif
#include "../../libultraship/libultraship/luslog.h"
#include <soh/Enhancements/item-tables/ItemTableTypes.h>
#if defined(INCLUDE_GAME_PRINTF) && !defined(NDEBUG)
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, __VA_ARGS__)
@ -453,7 +454,10 @@ u32 Actor_TextboxIsClosing(Actor* actor, GlobalContext* globalCtx);
s8 func_8002F368(GlobalContext* globalCtx);
void Actor_GetScreenPos(GlobalContext* globalCtx, Actor* actor, s16* x, s16* y);
u32 Actor_HasParent(Actor* actor, GlobalContext* globalCtx);
s32 GiveItemWithoutActor(GlobalContext* globalCtx, s32 getItemId);
// TODO: Rename the follwing 3 functions using whatever scheme we use when we rename func_8002F434 and func_8002F554.
s32 GiveItemEntryWithoutActor(GlobalContext* globalCtx, GetItemEntry getItemEntry);
s32 GiveItemEntryFromActor(Actor* actor, GlobalContext* globalCtx, GetItemEntry getItemEntry, f32 xzRange, f32 yRange);
void GiveItemEntryFromActorWithFixedRange(Actor* actor, GlobalContext* globalCtx, GetItemEntry getItemEntry);
s32 func_8002F434(Actor* actor, GlobalContext* globalCtx, s32 getItemId, f32 xzRange, f32 yRange);
void func_8002F554(Actor* actor, GlobalContext* globalCtx, s32 getItemId);
void func_8002F580(Actor* actor, GlobalContext* globalCtx);
@ -1050,6 +1054,7 @@ void Interface_LoadItemIcon1(GlobalContext* globalCtx, u16 button);
void Interface_LoadItemIcon2(GlobalContext* globalCtx, u16 button);
void func_80084BF4(GlobalContext* globalCtx, u16 flag);
u8 Item_Give(GlobalContext* globalCtx, u8 item);
u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry);
u8 Item_CheckObtainability(u8 item);
void Inventory_DeleteItem(u16 item, u16 invSlot);
s32 Inventory_ReplaceItem(GlobalContext* globalCtx, u16 oldItem, u16 newItem);

View File

@ -244,15 +244,6 @@ typedef enum {
/* 0x99 */ ITEM_STICK_UPGRADE_30,
/* 0x9A */ ITEM_NUT_UPGRADE_30,
/* 0x9B */ ITEM_NUT_UPGRADE_40,
/* 0x9C */ ITEM_BOTTLE_WITH_RED_POTION,
/* 0x9D */ ITEM_BOTTLE_WITH_GREEN_POTION,
/* 0x9E */ ITEM_BOTTLE_WITH_BLUE_POTION,
/* 0x9F */ ITEM_BOTTLE_WITH_FAIRY,
/* 0xA0 */ ITEM_BOTTLE_WITH_FISH,
/* 0xA1 */ ITEM_BOTTLE_WITH_BLUE_FIRE,
/* 0xA2 */ ITEM_BOTTLE_WITH_BUGS,
/* 0xA3 */ ITEM_BOTTLE_WITH_POE,
/* 0xA4 */ ITEM_BOTTLE_WITH_BIG_POE,
/* 0xFC */ ITEM_LAST_USED = 0xFC,
/* 0xFE */ ITEM_NONE_FE = 0xFE,
/* 0xFF */ ITEM_NONE = 0xFF
@ -388,47 +379,7 @@ typedef enum {
/* 0x7A */ GI_NUT_UPGRADE_40,
/* 0x7B */ GI_BULLET_BAG_50,
/* 0x7C */ GI_ICE_TRAP, // freezes link when opened from a chest
/* 0x7D */ GI_TEXT_0, // no model appears over Link, shows text id 0 (pocket egg)
/* 0x7E */ GI_MEDALLION_LIGHT,
/* 0x7F */ GI_MEDALLION_FOREST,
/* 0x80 */ GI_MEDALLION_FIRE,
/* 0x81 */ GI_MEDALLION_WATER,
/* 0x82 */ GI_MEDALLION_SHADOW,
/* 0x83 */ GI_MEDALLION_SPIRIT,
/* 0x81 */ GI_STONE_KOKIRI,
/* 0x82 */ GI_STONE_GORON,
/* 0x83 */ GI_STONE_ZORA,
/* 0x81 */ GI_ZELDAS_LULLABY,
/* 0x82 */ GI_SUNS_SONG,
/* 0x83 */ GI_EPONAS_SONG,
/* 0x81 */ GI_SONG_OF_STORMS,
/* 0x82 */ GI_SONG_OF_TIME,
/* 0x83 */ GI_SARIAS_SONG,
/* 0x81 */ GI_MINUET_OF_FOREST,
/* 0x82 */ GI_BOLERO_OF_FIRE,
/* 0x83 */ GI_SERENADE_OF_WATER,
/* 0x81 */ GI_NOCTURNE_OF_SHADOW,
/* 0x82 */ GI_REQUIEM_OF_SPIRIT,
/* 0x83 */ GI_PRELUDE_OF_LIGHT,
GI_SINGLE_MAGIC,
GI_DOUBLE_MAGIC,
GI_DOUBLE_DEFENSE,
GI_BOTTLE_WITH_RED_POTION,
GI_BOTTLE_WITH_GREEN_POTION,
GI_BOTTLE_WITH_BLUE_POTION,
GI_BOTTLE_WITH_FAIRY,
GI_BOTTLE_WITH_FISH,
GI_BOTTLE_WITH_BLUE_FIRE,
GI_BOTTLE_WITH_BUGS,
GI_BOTTLE_WITH_POE,
GI_BOTTLE_WITH_BIG_POE,
/* 0x7D */ GI_TEXT_0, // no model appears over Link, shows text id 0 (pocket egg)
/* 0x84 */ GI_MAX
} GetItemID;

View File

@ -2,6 +2,7 @@
#define Z64PLAYER_H
#include "z64actor.h"
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
struct Player;
@ -364,6 +365,7 @@ typedef enum {
FLAG_SCENE_TREASURE,
FLAG_SCENE_CLEAR,
FLAG_SCENE_COLLECTIBLE,
FLAG_EVENT_CHECK_INF,
} FlagType;
typedef struct {
@ -627,6 +629,7 @@ typedef struct Player {
/* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position
/* 0x0A94 */ PendingFlag pendingFlag;
/* 0x0AA0 */ u8 boomerangQuickRecall; // Has the player pressed the boomerang button while it's in the air still?
} Player; // size = 0xAA1
/* 0x0AA1 */ GetItemEntry getItemEntry;
} Player; // size = 0xAA9
#endif

View File

@ -1,5 +1,6 @@
#include "CustomMessageManager.h"
#include <algorithm>
#include <stdint.h>
using namespace std::literals::string_literals;
@ -80,9 +81,8 @@ bool CustomMessageManager::InsertCustomMessage(std::string tableID, uint16_t tex
return messageInsertResult.second;
}
bool CustomMessageManager::CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messageEntry) {
bool CustomMessageManager::CreateGetItemMessage(std::string tableID, uint16_t giid, ItemID iid,
CustomMessageEntry messageEntry) {
FormatCustomMessage(messageEntry.english, iid);
FormatCustomMessage(messageEntry.german, iid);
FormatCustomMessage(messageEntry.french, iid);

View File

@ -89,7 +89,7 @@ class CustomMessageManager {
with the provided giid (getItemID) as its key. This function also inserts the icon corresponding to
the provided iid (itemID) at the beginning of each page of the textbox.
*/
bool CreateGetItemMessage(std::string tableID, GetItemID giid, ItemID iid, CustomMessageEntry messages);
bool CreateGetItemMessage(std::string tableID, uint16_t giid, ItemID iid, CustomMessageEntry messages);
/*
Formats the provided Custom Message Entry and inserts it into the table with the provided tableID,

View File

@ -17,7 +17,7 @@ typedef enum {
#ifdef __cplusplus
typedef struct {
GetItemID giid;
u16 giid;
ItemID iid;
std::string english;
std::string german;

View File

@ -0,0 +1,42 @@
#include "ItemTableManager.h"
#include <stdexcept>
ItemTableManager::ItemTableManager() {
}
ItemTableManager::~ItemTableManager() {
this->itemTables.clear();
}
bool ItemTableManager::AddItemTable(uint16_t tableID) {
ItemTable newItemTable;
return itemTables.emplace(tableID, newItemTable).second;
}
bool ItemTableManager::AddItemEntry(uint16_t tableID, uint16_t getItemID, GetItemEntry getItemEntry) {
try {
ItemTable* itemTable = RetrieveItemTable(tableID);
return itemTable->emplace(getItemID, getItemEntry).second;
} catch (const std::out_of_range& oor) { return false; }
}
GetItemEntry ItemTableManager::RetrieveItemEntry(uint16_t tableID, uint16_t itemID) {
try {
ItemTable* itemTable = RetrieveItemTable(tableID);
return itemTable->at(itemID);
} catch (std::out_of_range& oor) { return GET_ITEM_NONE; }
}
bool ItemTableManager::ClearItemTable(uint16_t tableID) {
try {
ItemTable* itemTable = RetrieveItemTable(tableID);
itemTable->clear();
return true;
} catch (const std::out_of_range& oor) { return false; }
}
ItemTable* ItemTableManager::RetrieveItemTable(uint16_t tableID) {
try {
return &itemTables.at(tableID);
} catch (const std::out_of_range& oor) { throw(oor); }
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "ItemTableTypes.h"
#include "z64item.h"
#include <unordered_map>
typedef std::unordered_map<uint16_t, GetItemEntry> ItemTable;
class ItemTableManager {
public:
static ItemTableManager* Instance;
ItemTableManager();
~ItemTableManager();
bool AddItemTable(uint16_t tableID);
bool AddItemEntry(uint16_t tableID, uint16_t getItemID, GetItemEntry getItemEntry);
GetItemEntry RetrieveItemEntry(uint16_t tableID, uint16_t itemID);
bool ClearItemTable(uint16_t tableID);
private:
std::unordered_map<uint16_t, ItemTable> itemTables;
ItemTable* RetrieveItemTable(uint16_t tableID);
};

View File

@ -0,0 +1,25 @@
#pragma once
#ifdef __cplusplus
#include <stdint.h>
#endif
#define CHEST_ANIM_SHORT 0
#define CHEST_ANIM_LONG 1
#define GET_ITEM(itemId, objectId, drawId, textId, field, chestAnim, modIndex, getItemId) \
{ itemId, field, (chestAnim != CHEST_ANIM_SHORT ? 1 : -1) * (drawId + 1), textId, objectId, modIndex, getItemId, drawId, true }
#define GET_ITEM_NONE \
{ ITEM_NONE, 0, 0, 0, 0, 0, 0, 0, false }
typedef struct {
/* 0x00 */ uint16_t itemId;
/* 0x01 */ uint16_t field; // various bit-packed data
/* 0x02 */ int16_t gi; // defines the draw id and chest opening animation
/* 0x03 */ uint16_t textId;
/* 0x04 */ uint16_t objectId;
/* 0x06 */ uint16_t modIndex; // 0 = Vanilla, 1 = Randomizer, future mods will increment up?
/* 0x08 */ int16_t getItemId;
/* 0x0A */ uint16_t gid; // Stores the GID value unmodified for future reference.
/* 0x0C */ uint16_t collectable; // determines whether the item can be collected on the overworld. Will be true in most cases.
} GetItemEntry; // size = 0x0F

View File

@ -15,6 +15,8 @@
#include "Lib/ImGui/imgui_internal.h"
#include <soh/Enhancements/custom-message/CustomMessageManager.h>
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
#include <soh/Enhancements/item-tables/ItemTableManager.h>
#include <stdexcept>
using json = nlohmann::json;
using namespace std::literals::string_literals;
@ -806,202 +808,6 @@ std::unordered_map<std::string, RandomizerCheck> SpoilerfileCheckNameToEnum = {
{ "ZR Open Grotto Gossip Stone", RC_ZR_OPEN_GROTTO_GOSSIP_STONE }
};
std::unordered_map<s16, s16> getItemIdToItemId = {
{ GI_BOW, ITEM_BOW },
{ GI_ARROW_FIRE, ITEM_ARROW_FIRE },
{ GI_DINS_FIRE, ITEM_DINS_FIRE },
{ GI_SLINGSHOT, ITEM_SLINGSHOT },
{ GI_OCARINA_FAIRY, ITEM_OCARINA_FAIRY },
{ GI_OCARINA_OOT, ITEM_OCARINA_TIME },
{ GI_HOOKSHOT, ITEM_HOOKSHOT },
{ GI_LONGSHOT, ITEM_LONGSHOT },
{ GI_ARROW_ICE, ITEM_ARROW_ICE },
{ GI_FARORES_WIND, ITEM_FARORES_WIND },
{ GI_BOOMERANG, ITEM_BOOMERANG },
{ GI_LENS, ITEM_LENS },
{ GI_HAMMER, ITEM_HAMMER },
{ GI_ARROW_LIGHT, ITEM_ARROW_LIGHT },
{ GI_NAYRUS_LOVE, ITEM_NAYRUS_LOVE },
{ GI_BOTTLE, ITEM_BOTTLE },
{ GI_POTION_RED, ITEM_POTION_RED },
{ GI_POTION_GREEN, ITEM_POTION_GREEN },
{ GI_POTION_BLUE, ITEM_POTION_BLUE },
{ GI_FAIRY, ITEM_FAIRY },
{ GI_FISH, ITEM_FISH },
{ GI_MILK_BOTTLE, ITEM_MILK_BOTTLE },
{ GI_LETTER_RUTO, ITEM_LETTER_RUTO },
{ GI_BLUE_FIRE, ITEM_BLUE_FIRE },
{ GI_BUGS, ITEM_BUG },
{ GI_BIG_POE, ITEM_BIG_POE },
{ GI_POE, ITEM_POE },
{ GI_WEIRD_EGG, ITEM_WEIRD_EGG },
{ GI_LETTER_ZELDA, ITEM_LETTER_ZELDA },
{ GI_POCKET_EGG, ITEM_POCKET_EGG },
{ GI_COJIRO, ITEM_COJIRO },
{ GI_ODD_MUSHROOM, ITEM_ODD_MUSHROOM },
{ GI_ODD_POTION, ITEM_ODD_POTION },
{ GI_SAW, ITEM_SAW },
{ GI_SWORD_BROKEN, ITEM_SWORD_BROKEN },
{ GI_PRESCRIPTION, ITEM_PRESCRIPTION },
{ GI_FROG, ITEM_FROG },
{ GI_EYEDROPS, ITEM_EYEDROPS },
{ GI_CLAIM_CHECK, ITEM_CLAIM_CHECK }
};
std::unordered_map<s16, s16> itemIdToModel = { { GI_NONE, GID_MAXIMUM },
{ GI_BOMBS_5, GID_BOMB },
{ GI_NUTS_5, GID_NUTS },
{ GI_BOMBCHUS_10, GID_BOMBCHU },
{ GI_BOW, GID_BOW },
{ GI_SLINGSHOT, GID_SLINGSHOT },
{ GI_BOOMERANG, GID_BOOMERANG },
{ GI_STICKS_1, GID_STICK },
{ GI_HOOKSHOT, GID_HOOKSHOT },
{ GI_LONGSHOT, GID_LONGSHOT },
{ GI_LENS, GID_LENS },
{ GI_LETTER_ZELDA, GID_LETTER_ZELDA },
{ GI_OCARINA_OOT, GID_OCARINA_TIME },
{ GI_HAMMER, GID_HAMMER },
{ GI_COJIRO, GID_COJIRO },
{ GI_LETTER_RUTO, GID_LETTER_RUTO },
{ GI_LETTER_RUTO, GID_LETTER_RUTO },
{ GI_BOTTLE, GID_BOTTLE },
{ GI_POTION_RED, GID_POTION_RED },
{ GI_POTION_GREEN, GID_POTION_GREEN },
{ GI_POTION_BLUE, GID_POTION_BLUE },
{ GI_FAIRY, GID_FAIRY },
{ GI_MILK_BOTTLE, GID_MILK },
{ GI_LETTER_RUTO, GID_LETTER_RUTO },
{ GI_BEAN, GID_BEAN },
{ GI_MASK_SKULL, GID_MASK_SKULL },
{ GI_MASK_SPOOKY, GID_MASK_SPOOKY },
{ GI_CHICKEN, GID_CHICKEN },
{ GI_MASK_KEATON, GID_MASK_KEATON },
{ GI_MASK_BUNNY, GID_MASK_BUNNY },
{ GI_MASK_TRUTH, GID_MASK_TRUTH },
{ GI_POCKET_EGG, GID_EGG },
{ GI_POCKET_CUCCO, GID_CHICKEN },
{ GI_ODD_MUSHROOM, GID_ODD_MUSHROOM },
{ GI_ODD_POTION, GID_ODD_POTION },
{ GI_SAW, GID_SAW },
{ GI_SWORD_BROKEN, GID_SWORD_BROKEN },
{ GI_PRESCRIPTION, GID_PRESCRIPTION },
{ GI_FROG, GID_FROG },
{ GI_EYEDROPS, GID_EYEDROPS },
{ GI_CLAIM_CHECK, GID_CLAIM_CHECK },
{ GI_SWORD_KOKIRI, GID_SWORD_KOKIRI },
{ GI_SWORD_KNIFE, GID_SWORD_BGS },
{ GI_SHIELD_DEKU, GID_SHIELD_DEKU },
{ GI_SHIELD_HYLIAN, GID_SHIELD_HYLIAN },
{ GI_SHIELD_MIRROR, GID_SHIELD_MIRROR },
{ GI_TUNIC_GORON, GID_TUNIC_GORON },
{ GI_TUNIC_ZORA, GID_TUNIC_ZORA },
{ GI_BOOTS_IRON, GID_BOOTS_IRON },
{ GI_BOOTS_HOVER, GID_BOOTS_HOVER },
{ GI_QUIVER_40, GID_QUIVER_40 },
{ GI_QUIVER_50, GID_QUIVER_50 },
{ GI_BOMB_BAG_20, GID_BOMB_BAG_20 },
{ GI_BOMB_BAG_30, GID_BOMB_BAG_30 },
{ GI_BOMB_BAG_40, GID_BOMB_BAG_40 },
{ GI_GAUNTLETS_SILVER, GID_GAUNTLETS_SILVER },
{ GI_GAUNTLETS_GOLD, GID_GAUNTLETS_GOLD },
{ GI_SCALE_SILVER, GID_SCALE_SILVER },
{ GI_SCALE_GOLD, GID_SCALE_GOLDEN },
{ GI_STONE_OF_AGONY, GID_STONE_OF_AGONY },
{ GI_GERUDO_CARD, GID_GERUDO_CARD },
{ GI_OCARINA_FAIRY, GID_OCARINA_FAIRY },
{ GI_SEEDS_5, GID_SEEDS },
{ GI_HEART_CONTAINER, GID_HEART_CONTAINER },
{ GI_HEART_PIECE, GID_HEART_PIECE },
{ GI_KEY_BOSS, GID_KEY_BOSS },
{ GI_COMPASS, GID_COMPASS },
{ GI_MAP, GID_DUNGEON_MAP },
{ GI_KEY_SMALL, GID_KEY_SMALL },
{ GI_MAGIC_SMALL, GID_MAGIC_SMALL },
{ GI_MAGIC_LARGE, GID_MAGIC_LARGE },
{ GI_WALLET_ADULT, GID_WALLET_ADULT },
{ GI_WALLET_GIANT, GID_WALLET_GIANT },
{ GI_WEIRD_EGG, GID_EGG },
{ GI_HEART, GID_HEART },
{ GI_ARROWS_SMALL, GID_ARROWS_SMALL },
{ GI_ARROWS_MEDIUM, GID_ARROWS_MEDIUM },
{ GI_ARROWS_LARGE, GID_ARROWS_LARGE },
{ GI_RUPEE_GREEN, GID_RUPEE_GREEN },
{ GI_RUPEE_BLUE, GID_RUPEE_BLUE },
{ GI_RUPEE_RED, GID_RUPEE_RED },
{ GI_HEART_CONTAINER_2, GI_HEART_CONTAINER_2 },
{ GI_MILK, GID_MILK },
{ GI_MASK_GORON, GID_MASK_GORON },
{ GI_MASK_ZORA, GID_MASK_ZORA },
{ GI_MASK_GERUDO, GID_MASK_GERUDO },
{ GI_BRACELET, GID_BRACELET },
{ GI_RUPEE_PURPLE, GID_RUPEE_PURPLE },
{ GI_RUPEE_GOLD, GID_RUPEE_GOLD },
{ GI_SWORD_BGS, GID_SWORD_BGS },
{ GI_ARROW_FIRE, GID_ARROW_FIRE },
{ GI_ARROW_ICE, GID_ARROW_ICE },
{ GI_ARROW_LIGHT, GID_ARROW_LIGHT },
{ GI_SKULL_TOKEN, GID_SKULL_TOKEN },
{ GI_DINS_FIRE, GID_DINS_FIRE },
{ GI_FARORES_WIND, GID_FARORES_WIND },
{ GI_NAYRUS_LOVE, GID_NAYRUS_LOVE },
{ GI_BULLET_BAG_30, GID_BULLET_BAG },
{ GI_BULLET_BAG_40, GID_BULLET_BAG },
{ GI_STICKS_5, GID_STICK },
{ GI_STICKS_10, GID_STICK },
{ GI_NUTS_5_2, GID_NUTS },
{ GI_NUTS_10, GID_NUTS },
{ GI_BOMBS_1, GID_BOMB },
{ GI_BOMBS_10, GID_BOMB },
{ GI_BOMBS_20, GID_BOMB },
{ GI_BOMBS_30, GID_BOMB },
{ GI_SEEDS_30, GID_SEEDS },
{ GI_BOMBCHUS_5, GID_BOMBCHU },
{ GI_BOMBCHUS_20, GID_BOMBCHU },
{ GI_FISH, GID_FISH },
{ GI_BUGS, GID_BUG },
{ GI_BLUE_FIRE, GID_BLUE_FIRE },
{ GI_POE, GID_POE },
{ GI_BIG_POE, GID_BIG_POE },
{ GI_DOOR_KEY, GID_KEY_SMALL },
{ GI_RUPEE_GREEN_LOSE, GID_RUPEE_GREEN },
{ GI_RUPEE_BLUE_LOSE, GID_RUPEE_BLUE },
{ GI_RUPEE_RED_LOSE, GID_RUPEE_RED },
{ GI_RUPEE_PURPLE_LOSE, GID_RUPEE_PURPLE },
{ GI_HEART_PIECE_WIN, GID_HEART_PIECE },
{ GI_STICK_UPGRADE_20, GID_STICK },
{ GI_STICK_UPGRADE_30, GID_STICK },
{ GI_NUT_UPGRADE_30, GID_NUTS },
{ GI_NUT_UPGRADE_40, GID_NUTS },
{ GI_BULLET_BAG_50, GID_BULLET_BAG_50 },
{ GI_ZELDAS_LULLABY, GID_SONG_ZELDA },
{ GI_EPONAS_SONG, GID_SONG_EPONA },
{ GI_SARIAS_SONG, GID_SONG_SARIA },
{ GI_SUNS_SONG, GID_SONG_SUN },
{ GI_SONG_OF_TIME, GID_SONG_TIME },
{ GI_SONG_OF_STORMS, GID_SONG_STORM },
{ GI_MINUET_OF_FOREST, GID_SONG_MINUET },
{ GI_BOLERO_OF_FIRE, GID_SONG_BOLERO },
{ GI_SERENADE_OF_WATER, GID_SONG_SERENADE },
{ GI_REQUIEM_OF_SPIRIT, GID_SONG_REQUIEM },
{ GI_NOCTURNE_OF_SHADOW, GID_SONG_NOCTURNE },
{ GI_PRELUDE_OF_LIGHT, GID_SONG_PRELUDE },
{ GI_DOUBLE_DEFENSE, GID_HEART_CONTAINER },
{ GI_STONE_KOKIRI, GID_KOKIRI_EMERALD },
{ GI_STONE_GORON, GID_GORON_RUBY },
{ GI_STONE_ZORA, GID_ZORA_SAPPHIRE },
{ GI_MEDALLION_FOREST, GID_MEDALLION_FOREST },
{ GI_MEDALLION_FIRE, GID_MEDALLION_FIRE },
{ GI_MEDALLION_WATER, GID_MEDALLION_WATER },
{ GI_MEDALLION_SPIRIT, GID_MEDALLION_SPIRIT },
{ GI_MEDALLION_SHADOW, GID_MEDALLION_SHADOW },
{ GI_MEDALLION_LIGHT, GID_MEDALLION_LIGHT },
{ GI_SINGLE_MAGIC, GID_MAGIC_SMALL },
{ GI_DOUBLE_MAGIC, GID_MAGIC_LARGE },
{ GI_ICE_TRAP, GID_RUPEE_GOLD },
{ GI_ICE_TRAP, GID_MAXIMUM },
{ GI_TEXT_0, GID_MAXIMUM } };
std::unordered_map<std::string, RandomizerGet> SpoilerfileGetNameToEnum = {
{ "No Item", RG_NONE },
{ "Rien", RG_NONE },
@ -1418,18 +1224,6 @@ std::unordered_map<std::string, RandomizerSettingKey> SpoilerfileSettingNameToEn
{ "Timesaver Settings:Skip Tower Escape", RSK_SKIP_TOWER_ESCAPE }
};
s32 Randomizer::GetItemIDFromGetItemID(s32 getItemId) {
if (getItemIdToItemId.count(getItemId) == 0) {
return -1;
}
return getItemIdToItemId[getItemId];
}
s16 Randomizer::GetItemModelFromId(s16 itemId) {
return itemIdToModel[itemId];
}
std::string sanitize(std::string stringValue) {
// Add backslashes.
for (auto i = stringValue.begin();;) {
@ -2008,14 +1802,13 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId)
case RG_MAGIC_BEAN_PACK:
return GI_BEAN; //todo make it 10 of them
case RG_DOUBLE_DEFENSE:
return GI_DOUBLE_DEFENSE;
case RG_WEIRD_EGG:
return GI_WEIRD_EGG;
case RG_ZELDAS_LETTER:
return GI_LETTER_ZELDA;
case RG_RUTOS_LETTER:
return GI_LETTER_RUTO;
case RG_POCKET_EGG:
return GI_POCKET_EGG;
@ -2138,9 +1931,9 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId)
case RG_PROGRESSIVE_MAGIC_METER:
switch (gSaveContext.magicLevel) {
case 0:
return GI_SINGLE_MAGIC;
return (GetItemID)RG_MAGIC_SINGLE;
case 1:
return GI_DOUBLE_MAGIC;
return (GetItemID)RG_MAGIC_DOUBLE;
}
return GI_RUPEE_BLUE;
@ -2160,52 +1953,6 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId)
return GI_BOTTLE;
case RG_BOTTLE_WITH_MILK:
return GI_MILK_BOTTLE;
case RG_BOTTLE_WITH_RED_POTION:
return GI_BOTTLE_WITH_RED_POTION;
case RG_BOTTLE_WITH_GREEN_POTION:
return GI_BOTTLE_WITH_GREEN_POTION;
case RG_BOTTLE_WITH_BLUE_POTION:
return GI_BOTTLE_WITH_BLUE_POTION;
case RG_BOTTLE_WITH_FAIRY:
return GI_BOTTLE_WITH_FAIRY;
case RG_BOTTLE_WITH_FISH:
return GI_BOTTLE_WITH_FISH;
case RG_BOTTLE_WITH_BLUE_FIRE:
return GI_BOTTLE_WITH_BLUE_FIRE;
case RG_BOTTLE_WITH_BUGS:
return GI_BOTTLE_WITH_BUGS;
case RG_BOTTLE_WITH_POE:
return GI_BOTTLE_WITH_POE;
case RG_RUTOS_LETTER:
return GI_LETTER_RUTO;
case RG_BOTTLE_WITH_BIG_POE:
return GI_BOTTLE_WITH_BIG_POE;
case RG_ZELDAS_LULLABY:
return GI_ZELDAS_LULLABY;
case RG_EPONAS_SONG:
return GI_EPONAS_SONG;
case RG_SARIAS_SONG:
return GI_SARIAS_SONG;
case RG_SUNS_SONG:
return GI_SUNS_SONG;
case RG_SONG_OF_TIME:
return GI_SONG_OF_TIME;
case RG_SONG_OF_STORMS:
return GI_SONG_OF_STORMS;
case RG_MINUET_OF_FOREST:
return GI_MINUET_OF_FOREST;
case RG_BOLERO_OF_FIRE:
return GI_BOLERO_OF_FIRE;
case RG_SERENADE_OF_WATER:
return GI_SERENADE_OF_WATER;
case RG_REQUIEM_OF_SPIRIT:
return GI_REQUIEM_OF_SPIRIT;
case RG_NOCTURNE_OF_SHADOW:
return GI_NOCTURNE_OF_SHADOW;
case RG_PRELUDE_OF_LIGHT:
return GI_PRELUDE_OF_LIGHT;
// todo implement dungeon-specific maps/compasses
case RG_DEKU_TREE_MAP:
@ -2268,26 +2015,6 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId)
case RG_GANONS_CASTLE_KEY_RING:
return GI_RUPEE_BLUE;
case RG_KOKIRI_EMERALD:
return GI_STONE_KOKIRI;
case RG_GORON_RUBY:
return GI_STONE_GORON;
case RG_ZORA_SAPPHIRE:
return GI_STONE_ZORA;
case RG_FOREST_MEDALLION:
return GI_MEDALLION_FOREST;
case RG_FIRE_MEDALLION:
return GI_MEDALLION_FIRE;
case RG_WATER_MEDALLION:
return GI_MEDALLION_WATER;
case RG_SPIRIT_MEDALLION:
return GI_MEDALLION_SPIRIT;
case RG_SHADOW_MEDALLION:
return GI_MEDALLION_SHADOW;
case RG_LIGHT_MEDALLION:
return GI_MEDALLION_LIGHT;
case RG_RECOVERY_HEART:
return GI_HEART;
@ -2307,10 +2034,6 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId)
case RG_HEART_CONTAINER:
// todo figure out what GI_HEART_CONTAINER_2 is
return GI_HEART_CONTAINER;
case RG_ICE_TRAP:
return GI_ICE_TRAP;
case RG_MILK:
return GI_MILK; //todo logic around needing a bottle?
@ -2365,11 +2088,138 @@ GetItemID Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId)
case RG_HINT:
return GI_RUPEE_BLUE; //todo
default:
default: {
if (!IsItemVanilla(randoGet)) {
return (GetItemID)randoGet;
}
return ogItemId;
}
}
}
bool Randomizer::IsItemVanilla(RandomizerGet randoGet) {
switch (randoGet) {
case RG_NONE:
case RG_KOKIRI_SWORD:
case RG_GIANTS_KNIFE:
case RG_BIGGORON_SWORD:
case RG_DEKU_SHIELD:
case RG_HYLIAN_SHIELD:
case RG_MIRROR_SHIELD:
case RG_GORON_TUNIC:
case RG_ZORA_TUNIC:
case RG_IRON_BOOTS:
case RG_HOVER_BOOTS:
case RG_BOOMERANG:
case RG_LENS_OF_TRUTH:
case RG_MEGATON_HAMMER:
case RG_STONE_OF_AGONY:
case RG_DINS_FIRE:
case RG_FARORES_WIND:
case RG_NAYRUS_LOVE:
case RG_FIRE_ARROWS:
case RG_ICE_ARROWS:
case RG_LIGHT_ARROWS:
case RG_GERUDO_MEMBERSHIP_CARD:
case RG_MAGIC_BEAN:
case RG_WEIRD_EGG:
case RG_ZELDAS_LETTER:
case RG_RUTOS_LETTER:
case RG_POCKET_EGG:
case RG_COJIRO:
case RG_ODD_MUSHROOM:
case RG_ODD_POTION:
case RG_POACHERS_SAW:
case RG_BROKEN_SWORD:
case RG_PRESCRIPTION:
case RG_EYEBALL_FROG:
case RG_EYEDROPS:
case RG_CLAIM_CHECK:
case RG_GOLD_SKULLTULA_TOKEN:
case RG_PROGRESSIVE_HOOKSHOT:
case RG_PROGRESSIVE_STRENGTH:
case RG_PROGRESSIVE_BOMB_BAG:
case RG_PROGRESSIVE_BOW:
case RG_PROGRESSIVE_SLINGSHOT:
case RG_PROGRESSIVE_WALLET:
case RG_PROGRESSIVE_SCALE:
case RG_PROGRESSIVE_NUT_UPGRADE:
case RG_PROGRESSIVE_STICK_UPGRADE:
case RG_PROGRESSIVE_BOMBCHUS:
case RG_PROGRESSIVE_OCARINA:
case RG_PROGRESSIVE_GORONSWORD:
case RG_EMPTY_BOTTLE:
case RG_BOTTLE_WITH_MILK:
case RG_RECOVERY_HEART:
case RG_GREEN_RUPEE:
case RG_BLUE_RUPEE:
case RG_RED_RUPEE:
case RG_PURPLE_RUPEE:
case RG_HUGE_RUPEE:
case RG_PIECE_OF_HEART:
case RG_HEART_CONTAINER:
case RG_MILK:
case RG_BOMBS_5:
case RG_BOMBS_10:
case RG_BOMBS_20:
case RG_BOMBCHU_5:
case RG_BOMBCHU_10:
case RG_BOMBCHU_20:
case RG_BOMBCHU_DROP:
case RG_ARROWS_5:
case RG_ARROWS_10:
case RG_ARROWS_30:
case RG_DEKU_NUTS_5:
case RG_DEKU_NUTS_10:
case RG_DEKU_SEEDS_30:
case RG_DEKU_STICK_1:
case RG_RED_POTION_REFILL:
case RG_GREEN_POTION_REFILL:
case RG_BLUE_POTION_REFILL:
case RG_TREASURE_GAME_HEART:
case RG_TREASURE_GAME_GREEN_RUPEE:
case RG_BUY_DEKU_NUT_5:
case RG_BUY_ARROWS_30:
case RG_BUY_ARROWS_50:
case RG_BUY_BOMBS_525:
case RG_BUY_DEKU_NUT_10:
case RG_BUY_DEKU_STICK_1:
case RG_BUY_BOMBS_10:
case RG_BUY_FISH:
case RG_BUY_RED_POTION_30:
case RG_BUY_GREEN_POTION:
case RG_BUY_BLUE_POTION:
case RG_BUY_HYLIAN_SHIELD:
case RG_BUY_DEKU_SHIELD:
case RG_BUY_GORON_TUNIC:
case RG_BUY_ZORA_TUNIC:
case RG_BUY_HEART:
case RG_BUY_BOMBCHU_10:
case RG_BUY_BOMBCHU_20:
case RG_BUY_BOMBCHU_5:
case RG_BUY_DEKU_SEEDS_30:
case RG_SOLD_OUT:
case RG_BUY_BLUE_FIRE:
case RG_BUY_BOTTLE_BUG:
case RG_BUY_POE:
case RG_BUY_FAIRYS_SPIRIT:
case RG_BUY_ARROWS_10:
case RG_BUY_BOMBS_20:
case RG_BUY_BOMBS_30:
case RG_BUY_BOMBS_535:
case RG_BUY_RED_POTION_40:
case RG_BUY_RED_POTION_50:
return true;
default:
return false;
}
}
bool Randomizer::CheckContainsVanillaItem(RandomizerCheck randoCheck) {
RandomizerGet randoGet = this->itemLocations[randoCheck];
return IsItemVanilla(randoGet);
}
std::string Randomizer::GetAdultAltarText() const {
return this->adultAltarText;
}
@ -4738,31 +4588,116 @@ void Randomizer::CreateCustomMessages() {
// RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED
// with GIMESSAGE(getItemID, itemID, english, german, french).
const std::vector<GetItemMessage> getItemMessages = {
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE,
"You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE,
"You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE,
"You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_FISH, ITEM_FISH,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_FISH, ITEM_FISH,
"You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_BUGS, ITEM_BUG,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_BUGS, ITEM_BUG,
"You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!"),
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED,
"You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN,
"You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!"),
GIMESSAGE_UNTRANSLATED(GI_BOTTLE_WITH_POE, ITEM_POE,
GIMESSAGE_UNTRANSLATED(RG_BOTTLE_WITH_POE, ITEM_POE,
"You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this..."),
};
CreateGetItemMessages(getItemMessages);
CreateScrubMessages();
}
class ExtendedVanillaTableInvalidItemIdException: public std::exception {
private:
s16 itemID;
public:
ExtendedVanillaTableInvalidItemIdException(s16 itemID): itemID(itemID) {}
std::string what() {
return itemID + " is not a valid ItemID for the extendedVanillaGetItemTable. If you are adding a new"
"item, try adding it to randoGetItemTable instead.";
}
};
void InitRandoItemTable() {
// These entries have ItemIDs from vanilla, but not GetItemIDs or entries in the old sGetItemTable
GetItemEntry extendedVanillaGetItemTable[] = {
GET_ITEM(ITEM_MEDALLION_LIGHT, OBJECT_GI_MEDAL, GID_MEDALLION_LIGHT, 0x40, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_LIGHT_MEDALLION),
GET_ITEM(ITEM_MEDALLION_FOREST, OBJECT_GI_MEDAL, GID_MEDALLION_FOREST, 0x3E, 0x80, CHEST_ANIM_LONG,
MOD_NONE, RG_FOREST_MEDALLION),
GET_ITEM(ITEM_MEDALLION_FIRE, OBJECT_GI_MEDAL, GID_MEDALLION_FIRE, 0x3C, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_FIRE_MEDALLION),
GET_ITEM(ITEM_MEDALLION_WATER, OBJECT_GI_MEDAL, GID_MEDALLION_WATER, 0x3D, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_WATER_MEDALLION),
GET_ITEM(ITEM_MEDALLION_SHADOW, OBJECT_GI_MEDAL, GID_MEDALLION_SHADOW, 0x41, 0x80, CHEST_ANIM_LONG,
MOD_NONE, RG_SHADOW_MEDALLION),
GET_ITEM(ITEM_MEDALLION_SPIRIT, OBJECT_GI_MEDAL, GID_MEDALLION_SPIRIT, 0x3F, 0x80, CHEST_ANIM_LONG,
MOD_NONE, RG_SPIRIT_MEDALLION),
GET_ITEM(ITEM_KOKIRI_EMERALD, OBJECT_GI_JEWEL, GID_KOKIRI_EMERALD, 0x80, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_KOKIRI_EMERALD),
GET_ITEM(ITEM_GORON_RUBY, OBJECT_GI_JEWEL, GID_GORON_RUBY, 0x81, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_GORON_RUBY),
GET_ITEM(ITEM_ZORA_SAPPHIRE, OBJECT_GI_JEWEL, GID_ZORA_SAPPHIRE, 0x82, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_ZORA_SAPPHIRE),
GET_ITEM(ITEM_SONG_LULLABY, OBJECT_GI_MELODY, GID_SONG_ZELDA, 0xD4, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_ZELDAS_LULLABY),
GET_ITEM(ITEM_SONG_SUN, OBJECT_GI_MELODY, GID_SONG_SUN, 0xD3, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_SUNS_SONG),
GET_ITEM(ITEM_SONG_EPONA, OBJECT_GI_MELODY, GID_SONG_EPONA, 0xD2, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_EPONAS_SONG),
GET_ITEM(ITEM_SONG_STORMS, OBJECT_GI_MELODY, GID_SONG_STORM, 0xD6, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_SONG_OF_STORMS),
GET_ITEM(ITEM_SONG_TIME, OBJECT_GI_MELODY, GID_SONG_TIME, 0xD5, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_SONG_OF_TIME),
GET_ITEM(ITEM_SONG_SARIA, OBJECT_GI_MELODY, GID_SONG_SARIA, 0xD1, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_SARIAS_SONG),
GET_ITEM(ITEM_SONG_MINUET, OBJECT_GI_MELODY, GID_SONG_MINUET, 0x73, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_MINUET_OF_FOREST),
GET_ITEM(ITEM_SONG_BOLERO, OBJECT_GI_MELODY, GID_SONG_BOLERO, 0x74, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_BOLERO_OF_FIRE),
GET_ITEM(ITEM_SONG_SERENADE, OBJECT_GI_MELODY, GID_SONG_SERENADE, 0x75, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_SERENADE_OF_WATER),
GET_ITEM(ITEM_SONG_NOCTURNE, OBJECT_GI_MELODY, GID_SONG_NOCTURNE, 0x77, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_NOCTURNE_OF_SHADOW),
GET_ITEM(ITEM_SONG_REQUIEM, OBJECT_GI_MELODY, GID_SONG_REQUIEM, 0x76, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_REQUIEM_OF_SPIRIT),
GET_ITEM(ITEM_SONG_PRELUDE, OBJECT_GI_MELODY, GID_SONG_PRELUDE, 0x78, 0x80, CHEST_ANIM_LONG, MOD_NONE, RG_PRELUDE_OF_LIGHT),
};
// These do not have ItemIDs or GetItemIDs from vanilla, so I'm using their
// RandomizerGet enum values for both.
GetItemEntry randoGetItemTable[] = {
GET_ITEM(RG_ICE_TRAP, OBJECT_GI_RUPY, GID_RUPEE_GOLD, 0, 0x80, CHEST_ANIM_SHORT, MOD_RANDOMIZER, RG_ICE_TRAP),
GET_ITEM(RG_MAGIC_SINGLE, OBJECT_GI_MAGICPOT, GID_MAGIC_SMALL, 0xE4, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER,
RG_MAGIC_SINGLE),
GET_ITEM(RG_MAGIC_DOUBLE, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER,
RG_MAGIC_DOUBLE),
GET_ITEM(RG_DOUBLE_DEFENSE, OBJECT_GI_HEARTS, GID_HEART_CONTAINER, 0xE9, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER,
RG_DOUBLE_DEFENSE),
GET_ITEM(RG_BOTTLE_WITH_RED_POTION, OBJECT_GI_LIQUID, GID_POTION_RED, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80,
CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTLE_WITH_RED_POTION),
GET_ITEM(RG_BOTTLE_WITH_GREEN_POTION, OBJECT_GI_LIQUID, GID_POTION_GREEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80,
CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTLE_WITH_GREEN_POTION),
GET_ITEM(RG_BOTTLE_WITH_BLUE_POTION, OBJECT_GI_LIQUID, GID_POTION_BLUE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80,
CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTLE_WITH_BLUE_POTION),
GET_ITEM(RG_BOTTLE_WITH_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG,
MOD_RANDOMIZER, RG_BOTTLE_WITH_FAIRY),
GET_ITEM(RG_BOTTLE_WITH_FISH, OBJECT_GI_FISH, GID_FISH, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG,
MOD_RANDOMIZER, RG_BOTTLE_WITH_FISH),
GET_ITEM(RG_BOTTLE_WITH_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80,
CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTLE_WITH_BLUE_FIRE),
GET_ITEM(RG_BOTTLE_WITH_BUGS, OBJECT_GI_INSECT, GID_BUG, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG,
MOD_RANDOMIZER, RG_BOTTLE_WITH_BUGS),
GET_ITEM(RG_BOTTLE_WITH_POE, OBJECT_GI_GHOST, GID_POE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG,
MOD_RANDOMIZER, RG_BOTTLE_WITH_POE),
GET_ITEM(RG_BOTTLE_WITH_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80,
CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTLE_WITH_BIG_POE),
};
ItemTableManager::Instance->AddItemTable(MOD_RANDOMIZER);
for (int i = 0; i < ARRAY_COUNT(extendedVanillaGetItemTable); i++) {
ItemTableManager::Instance->AddItemEntry(MOD_RANDOMIZER, extendedVanillaGetItemTable[i].getItemId, extendedVanillaGetItemTable[i]);
}
for (int i = 0; i < ARRAY_COUNT(randoGetItemTable); i++) {
ItemTableManager::Instance->AddItemEntry(MOD_RANDOMIZER, randoGetItemTable[i].itemId, randoGetItemTable[i]);
}
}
void InitRando() {
SohImGui::AddWindow("Randomizer", "Randomizer Settings", DrawRandoEditor);
Randomizer::CreateCustomMessages();
InitRandoItemTable();
}
extern "C" {

View File

@ -21,6 +21,8 @@ class Randomizer {
void ParseRandomizerSettingsFile(const char* spoilerFileName);
void ParseHintLocationsFile(const char* spoilerFileName);
void ParseItemLocationsFile(const char* spoilerFileName, bool silent);
bool IsItemVanilla(RandomizerGet randoGet);
public:
Randomizer();
@ -38,7 +40,7 @@ class Randomizer {
void LoadHintLocations(const char* spoilerFileName);
void LoadItemLocations(const char* spoilerFileName, bool silent);
u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum);
RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams);
std::string GetChildAltarText() const;
std::string GetAdultAltarText() const;
std::string GetGanonText() const;
@ -46,6 +48,7 @@ class Randomizer {
GetItemID GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
GetItemID GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum);
static void CreateCustomMessages();
bool CheckContainsVanillaItem(RandomizerCheck randoCheck);
};
#ifdef __cplusplus

View File

@ -1,5 +1,10 @@
#pragma once
// This should probably go in a less rando-specific location
// but the best location will probably be in the modding engine
// which doesn't exist yet.
typedef enum { MOD_NONE, MOD_RANDOMIZER } ModIndex;
typedef struct {
char tex[512];
uint16_t width;
@ -806,6 +811,8 @@ typedef enum {
RG_PROGRESSIVE_STICK_UPGRADE,
RG_PROGRESSIVE_BOMBCHUS,
RG_PROGRESSIVE_MAGIC_METER,
RG_MAGIC_SINGLE, // Added for refactor of GetItemEntries
RG_MAGIC_DOUBLE, // Added for refactor of GetItemEntries
RG_PROGRESSIVE_OCARINA,
RG_PROGRESSIVE_GORONSWORD,
RG_EMPTY_BOTTLE,
@ -947,7 +954,8 @@ typedef enum {
RG_BUY_RED_POTION_40,
RG_BUY_RED_POTION_50,
RG_TRIFORCE,
RG_HINT
RG_HINT,
RG_MAX
} RandomizerGet;
typedef enum {

View File

@ -60,10 +60,12 @@
#include <Audio.h>
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
#include <functions.h>
#include <soh/Enhancements/item-tables/ItemTableManager.h>
OTRGlobals* OTRGlobals::Instance;
SaveManager* SaveManager::Instance;
CustomMessageManager* CustomMessageManager::Instance;
ItemTableManager* ItemTableManager::Instance;
OTRGlobals::OTRGlobals() {
context = Ship::Window::CreateInstance("Ship of Harkinian");
@ -160,6 +162,145 @@ extern "C" void OTRAudio_Exit() {
audio.thread.join();
}
extern "C" void VanillaItemTable_Init() {
GetItemEntry getItemTable[] = {
GET_ITEM(ITEM_BOMBS_5, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBS_5),
GET_ITEM(ITEM_NUTS_5, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, MOD_NONE, GI_NUTS_5),
GET_ITEM(ITEM_BOMBCHU, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBCHUS_10),
GET_ITEM(ITEM_BOW, OBJECT_GI_BOW, GID_BOW, 0x31, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOW),
GET_ITEM(ITEM_SLINGSHOT, OBJECT_GI_PACHINKO, GID_SLINGSHOT, 0x30, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SLINGSHOT),
GET_ITEM(ITEM_BOOMERANG, OBJECT_GI_BOOMERANG, GID_BOOMERANG, 0x35, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOOMERANG),
GET_ITEM(ITEM_STICK, OBJECT_GI_STICK, GID_STICK, 0x37, 0x0D, CHEST_ANIM_SHORT, MOD_NONE, GI_STICKS_1),
GET_ITEM(ITEM_HOOKSHOT, OBJECT_GI_HOOKSHOT, GID_HOOKSHOT, 0x36, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_HOOKSHOT),
GET_ITEM(ITEM_LONGSHOT, OBJECT_GI_HOOKSHOT, GID_LONGSHOT, 0x4F, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_LONGSHOT),
GET_ITEM(ITEM_LENS, OBJECT_GI_GLASSES, GID_LENS, 0x39, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_LENS),
GET_ITEM(ITEM_LETTER_ZELDA, OBJECT_GI_LETTER, GID_LETTER_ZELDA, 0x69, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_LETTER_ZELDA),
GET_ITEM(ITEM_OCARINA_TIME, OBJECT_GI_OCARINA, GID_OCARINA_TIME, 0x3A, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_OCARINA_OOT),
GET_ITEM(ITEM_HAMMER, OBJECT_GI_HAMMER, GID_HAMMER, 0x38, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_HAMMER),
GET_ITEM(ITEM_COJIRO, OBJECT_GI_NIWATORI, GID_COJIRO, 0x02, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_COJIRO),
GET_ITEM(ITEM_BOTTLE, OBJECT_GI_BOTTLE, GID_BOTTLE, 0x42, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOTTLE),
GET_ITEM(ITEM_POTION_RED, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_POTION_RED),
GET_ITEM(ITEM_POTION_GREEN, OBJECT_GI_LIQUID, GID_POTION_GREEN, 0x44, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_POTION_GREEN),
GET_ITEM(ITEM_POTION_BLUE, OBJECT_GI_LIQUID, GID_POTION_BLUE, 0x45, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_POTION_BLUE),
GET_ITEM(ITEM_FAIRY, OBJECT_GI_BOTTLE, GID_BOTTLE, 0x46, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_FAIRY),
GET_ITEM(ITEM_MILK_BOTTLE, OBJECT_GI_MILK, GID_MILK, 0x98, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MILK_BOTTLE),
GET_ITEM(ITEM_LETTER_RUTO, OBJECT_GI_BOTTLE_LETTER, GID_LETTER_RUTO, 0x99, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_LETTER_RUTO),
GET_ITEM(ITEM_BEAN, OBJECT_GI_BEAN, GID_BEAN, 0x48, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_BEAN),
GET_ITEM(ITEM_MASK_SKULL, OBJECT_GI_SKJ_MASK, GID_MASK_SKULL, 0x10, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_SKULL),
GET_ITEM(ITEM_MASK_SPOOKY, OBJECT_GI_REDEAD_MASK, GID_MASK_SPOOKY, 0x11, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_SPOOKY),
GET_ITEM(ITEM_CHICKEN, OBJECT_GI_NIWATORI, GID_CHICKEN, 0x48, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_CHICKEN),
GET_ITEM(ITEM_MASK_KEATON, OBJECT_GI_KI_TAN_MASK, GID_MASK_KEATON, 0x12, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_KEATON),
GET_ITEM(ITEM_MASK_BUNNY, OBJECT_GI_RABIT_MASK, GID_MASK_BUNNY, 0x13, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_BUNNY),
GET_ITEM(ITEM_MASK_TRUTH, OBJECT_GI_TRUTH_MASK, GID_MASK_TRUTH, 0x17, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_TRUTH),
GET_ITEM(ITEM_POCKET_EGG, OBJECT_GI_EGG, GID_EGG, 0x01, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_POCKET_EGG),
GET_ITEM(ITEM_POCKET_CUCCO, OBJECT_GI_NIWATORI, GID_CHICKEN, 0x48, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_POCKET_CUCCO),
GET_ITEM(ITEM_ODD_MUSHROOM, OBJECT_GI_MUSHROOM, GID_ODD_MUSHROOM, 0x03, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_ODD_MUSHROOM),
GET_ITEM(ITEM_ODD_POTION, OBJECT_GI_POWDER, GID_ODD_POTION, 0x04, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_ODD_POTION),
GET_ITEM(ITEM_SAW, OBJECT_GI_SAW, GID_SAW, 0x05, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SAW),
GET_ITEM(ITEM_SWORD_BROKEN, OBJECT_GI_BROKENSWORD, GID_SWORD_BROKEN, 0x08, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SWORD_BROKEN),
GET_ITEM(ITEM_PRESCRIPTION, OBJECT_GI_PRESCRIPTION, GID_PRESCRIPTION, 0x09, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_PRESCRIPTION),
GET_ITEM(ITEM_FROG, OBJECT_GI_FROG, GID_FROG, 0x0D, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_FROG),
GET_ITEM(ITEM_EYEDROPS, OBJECT_GI_EYE_LOTION, GID_EYEDROPS, 0x0E, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_EYEDROPS),
GET_ITEM(ITEM_CLAIM_CHECK, OBJECT_GI_TICKETSTONE, GID_CLAIM_CHECK, 0x0A, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_CLAIM_CHECK),
GET_ITEM(ITEM_SWORD_KOKIRI, OBJECT_GI_SWORD_1, GID_SWORD_KOKIRI, 0xA4, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SWORD_KOKIRI),
GET_ITEM(ITEM_SWORD_BGS, OBJECT_GI_LONGSWORD, GID_SWORD_BGS, 0x4B, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SWORD_KNIFE),
GET_ITEM(ITEM_SHIELD_DEKU, OBJECT_GI_SHIELD_1, GID_SHIELD_DEKU, 0x4C, 0xA0, CHEST_ANIM_SHORT, MOD_NONE, GI_SHIELD_DEKU),
GET_ITEM(ITEM_SHIELD_HYLIAN, OBJECT_GI_SHIELD_2, GID_SHIELD_HYLIAN, 0x4D, 0xA0, CHEST_ANIM_SHORT, MOD_NONE, GI_SHIELD_HYLIAN),
GET_ITEM(ITEM_SHIELD_MIRROR, OBJECT_GI_SHIELD_3, GID_SHIELD_MIRROR, 0x4E, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SHIELD_MIRROR),
GET_ITEM(ITEM_TUNIC_GORON, OBJECT_GI_CLOTHES, GID_TUNIC_GORON, 0x50, 0xA0, CHEST_ANIM_LONG, MOD_NONE, GI_TUNIC_GORON),
GET_ITEM(ITEM_TUNIC_ZORA, OBJECT_GI_CLOTHES, GID_TUNIC_ZORA, 0x51, 0xA0, CHEST_ANIM_LONG, MOD_NONE, GI_TUNIC_ZORA),
GET_ITEM(ITEM_BOOTS_IRON, OBJECT_GI_BOOTS_2, GID_BOOTS_IRON, 0x53, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOOTS_IRON),
GET_ITEM(ITEM_BOOTS_HOVER, OBJECT_GI_HOVERBOOTS, GID_BOOTS_HOVER, 0x54, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOOTS_HOVER),
GET_ITEM(ITEM_QUIVER_40, OBJECT_GI_ARROWCASE, GID_QUIVER_40, 0x56, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_QUIVER_40),
GET_ITEM(ITEM_QUIVER_50, OBJECT_GI_ARROWCASE, GID_QUIVER_50, 0x57, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_QUIVER_50),
GET_ITEM(ITEM_BOMB_BAG_20, OBJECT_GI_BOMBPOUCH, GID_BOMB_BAG_20, 0x58, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOMB_BAG_20),
GET_ITEM(ITEM_BOMB_BAG_30, OBJECT_GI_BOMBPOUCH, GID_BOMB_BAG_30, 0x59, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOMB_BAG_30),
GET_ITEM(ITEM_BOMB_BAG_40, OBJECT_GI_BOMBPOUCH, GID_BOMB_BAG_40, 0x5A, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BOMB_BAG_40),
GET_ITEM(ITEM_GAUNTLETS_SILVER, OBJECT_GI_GLOVES, GID_GAUNTLETS_SILVER, 0x5B, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_GAUNTLETS_SILVER),
GET_ITEM(ITEM_GAUNTLETS_GOLD, OBJECT_GI_GLOVES, GID_GAUNTLETS_GOLD, 0x5C, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_GAUNTLETS_GOLD),
GET_ITEM(ITEM_SCALE_SILVER, OBJECT_GI_SCALE, GID_SCALE_SILVER, 0xCD, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SCALE_SILVER),
GET_ITEM(ITEM_SCALE_GOLDEN, OBJECT_GI_SCALE, GID_SCALE_GOLDEN, 0xCE, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SCALE_GOLD),
GET_ITEM(ITEM_STONE_OF_AGONY, OBJECT_GI_MAP, GID_STONE_OF_AGONY, 0x68, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_STONE_OF_AGONY),
GET_ITEM(ITEM_GERUDO_CARD, OBJECT_GI_GERUDO, GID_GERUDO_CARD, 0x7B, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_GERUDO_CARD),
GET_ITEM(ITEM_OCARINA_FAIRY, OBJECT_GI_OCARINA_0, GID_OCARINA_FAIRY, 0x4A, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_OCARINA_FAIRY),
GET_ITEM(ITEM_SEEDS, OBJECT_GI_SEED, GID_SEEDS, 0xDC, 0x50, CHEST_ANIM_SHORT, MOD_NONE, GI_SEEDS_5),
GET_ITEM(ITEM_HEART_CONTAINER, OBJECT_GI_HEARTS, GID_HEART_CONTAINER, 0xC6, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_HEART_CONTAINER),
GET_ITEM(ITEM_HEART_PIECE_2, OBJECT_GI_HEARTS, GID_HEART_PIECE, 0xC2, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_HEART_PIECE),
GET_ITEM(ITEM_KEY_BOSS, OBJECT_GI_BOSSKEY, GID_KEY_BOSS, 0xC7, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_KEY_BOSS),
GET_ITEM(ITEM_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, 0x67, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_COMPASS),
GET_ITEM(ITEM_DUNGEON_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, 0x66, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MAP),
GET_ITEM(ITEM_KEY_SMALL, OBJECT_GI_KEY, GID_KEY_SMALL, 0x60, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_KEY_SMALL),
GET_ITEM(ITEM_MAGIC_SMALL, OBJECT_GI_MAGICPOT, GID_MAGIC_SMALL, 0x52, 0x6F, CHEST_ANIM_SHORT, MOD_NONE, GI_MAGIC_SMALL),
GET_ITEM(ITEM_MAGIC_LARGE, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0x52, 0x6E, CHEST_ANIM_SHORT, MOD_NONE, GI_MAGIC_LARGE),
GET_ITEM(ITEM_WALLET_ADULT, OBJECT_GI_PURSE, GID_WALLET_ADULT, 0x5E, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_WALLET_ADULT),
GET_ITEM(ITEM_WALLET_GIANT, OBJECT_GI_PURSE, GID_WALLET_GIANT, 0x5F, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_WALLET_GIANT),
GET_ITEM(ITEM_WEIRD_EGG, OBJECT_GI_EGG, GID_EGG, 0x9A, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_WEIRD_EGG),
GET_ITEM(ITEM_HEART, OBJECT_GI_HEART, GID_HEART, 0x55, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_HEART),
GET_ITEM(ITEM_ARROWS_SMALL, OBJECT_GI_ARROW, GID_ARROWS_SMALL, 0xE6, 0x48, CHEST_ANIM_SHORT, MOD_NONE, GI_ARROWS_SMALL),
GET_ITEM(ITEM_ARROWS_MEDIUM, OBJECT_GI_ARROW, GID_ARROWS_MEDIUM, 0xE6, 0x49, CHEST_ANIM_SHORT, MOD_NONE, GI_ARROWS_MEDIUM),
GET_ITEM(ITEM_ARROWS_LARGE, OBJECT_GI_ARROW, GID_ARROWS_LARGE, 0xE6, 0x4A, CHEST_ANIM_SHORT, MOD_NONE, GI_ARROWS_LARGE),
GET_ITEM(ITEM_RUPEE_GREEN, OBJECT_GI_RUPY, GID_RUPEE_GREEN, 0x6F, 0x00, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_GREEN),
GET_ITEM(ITEM_RUPEE_BLUE, OBJECT_GI_RUPY, GID_RUPEE_BLUE, 0xCC, 0x01, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_BLUE),
GET_ITEM(ITEM_RUPEE_RED, OBJECT_GI_RUPY, GID_RUPEE_RED, 0xF0, 0x02, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_RED),
GET_ITEM(ITEM_HEART_CONTAINER, OBJECT_GI_HEARTS, GID_HEART_CONTAINER, 0xC6, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_HEART_CONTAINER_2),
GET_ITEM(ITEM_MILK, OBJECT_GI_MILK, GID_MILK, 0x98, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MILK),
GET_ITEM(ITEM_MASK_GORON, OBJECT_GI_GOLONMASK, GID_MASK_GORON, 0x14, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_GORON),
GET_ITEM(ITEM_MASK_ZORA, OBJECT_GI_ZORAMASK, GID_MASK_ZORA, 0x15, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_ZORA),
GET_ITEM(ITEM_MASK_GERUDO, OBJECT_GI_GERUDOMASK, GID_MASK_GERUDO, 0x16, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_MASK_GERUDO),
GET_ITEM(ITEM_BRACELET, OBJECT_GI_BRACELET, GID_BRACELET, 0x79, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BRACELET),
GET_ITEM(ITEM_RUPEE_PURPLE, OBJECT_GI_RUPY, GID_RUPEE_PURPLE, 0xF1, 0x14, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_PURPLE),
GET_ITEM(ITEM_RUPEE_GOLD, OBJECT_GI_RUPY, GID_RUPEE_GOLD, 0xF2, 0x13, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_GOLD),
GET_ITEM(ITEM_SWORD_BGS, OBJECT_GI_LONGSWORD, GID_SWORD_BGS, 0x0C, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_SWORD_BGS),
GET_ITEM(ITEM_ARROW_FIRE, OBJECT_GI_M_ARROW, GID_ARROW_FIRE, 0x70, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_ARROW_FIRE),
GET_ITEM(ITEM_ARROW_ICE, OBJECT_GI_M_ARROW, GID_ARROW_ICE, 0x71, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_ARROW_ICE),
GET_ITEM(ITEM_ARROW_LIGHT, OBJECT_GI_M_ARROW, GID_ARROW_LIGHT, 0x72, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_ARROW_LIGHT),
GET_ITEM(ITEM_SKULL_TOKEN, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, 0xB4, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_SKULL_TOKEN),
GET_ITEM(ITEM_DINS_FIRE, OBJECT_GI_GODDESS, GID_DINS_FIRE, 0xAD, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_DINS_FIRE),
GET_ITEM(ITEM_FARORES_WIND, OBJECT_GI_GODDESS, GID_FARORES_WIND, 0xAE, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_FARORES_WIND),
GET_ITEM(ITEM_NAYRUS_LOVE, OBJECT_GI_GODDESS, GID_NAYRUS_LOVE, 0xAF, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_NAYRUS_LOVE),
GET_ITEM(ITEM_BULLET_BAG_30, OBJECT_GI_DEKUPOUCH, GID_BULLET_BAG, 0x07, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BULLET_BAG_30),
GET_ITEM(ITEM_BULLET_BAG_40, OBJECT_GI_DEKUPOUCH, GID_BULLET_BAG, 0x07, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BULLET_BAG_40),
GET_ITEM(ITEM_STICKS_5, OBJECT_GI_STICK, GID_STICK, 0x37, 0x0D, CHEST_ANIM_SHORT, MOD_NONE, GI_STICKS_5),
GET_ITEM(ITEM_STICKS_10, OBJECT_GI_STICK, GID_STICK, 0x37, 0x0D, CHEST_ANIM_SHORT, MOD_NONE, GI_STICKS_10),
GET_ITEM(ITEM_NUTS_5, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, MOD_NONE, GI_NUTS_5_2),
GET_ITEM(ITEM_NUTS_10, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, MOD_NONE, GI_NUTS_10),
GET_ITEM(ITEM_BOMB, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBS_1),
GET_ITEM(ITEM_BOMBS_10, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBS_10),
GET_ITEM(ITEM_BOMBS_20, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBS_20),
GET_ITEM(ITEM_BOMBS_30, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBS_30),
GET_ITEM(ITEM_SEEDS_30, OBJECT_GI_SEED, GID_SEEDS, 0xDC, 0x50, CHEST_ANIM_SHORT, MOD_NONE, GI_SEEDS_30),
GET_ITEM(ITEM_BOMBCHUS_5, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBCHUS_5),
GET_ITEM(ITEM_BOMBCHUS_20, OBJECT_GI_BOMB_2, GID_BOMBCHU, 0x33, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_BOMBCHUS_20),
GET_ITEM(ITEM_FISH, OBJECT_GI_FISH, GID_FISH, 0x47, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_FISH),
GET_ITEM(ITEM_BUG, OBJECT_GI_INSECT, GID_BUG, 0x7A, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BUGS),
GET_ITEM(ITEM_BLUE_FIRE, OBJECT_GI_FIRE, GID_BLUE_FIRE, 0x5D, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BLUE_FIRE),
GET_ITEM(ITEM_POE, OBJECT_GI_GHOST, GID_POE, 0x97, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_POE),
GET_ITEM(ITEM_BIG_POE, OBJECT_GI_GHOST, GID_BIG_POE, 0xF9, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BIG_POE),
GET_ITEM(ITEM_KEY_SMALL, OBJECT_GI_KEY, GID_KEY_SMALL, 0xF3, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_DOOR_KEY),
GET_ITEM(ITEM_RUPEE_GREEN, OBJECT_GI_RUPY, GID_RUPEE_GREEN, 0xF4, 0x00, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_GREEN_LOSE),
GET_ITEM(ITEM_RUPEE_BLUE, OBJECT_GI_RUPY, GID_RUPEE_BLUE, 0xF5, 0x01, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_BLUE_LOSE),
GET_ITEM(ITEM_RUPEE_RED, OBJECT_GI_RUPY, GID_RUPEE_RED, 0xF6, 0x02, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_RED_LOSE),
GET_ITEM(ITEM_RUPEE_PURPLE, OBJECT_GI_RUPY, GID_RUPEE_PURPLE, 0xF7, 0x14, CHEST_ANIM_SHORT, MOD_NONE, GI_RUPEE_PURPLE_LOSE),
GET_ITEM(ITEM_HEART_PIECE_2, OBJECT_GI_HEARTS, GID_HEART_PIECE, 0xFA, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_HEART_PIECE_WIN),
GET_ITEM(ITEM_STICK_UPGRADE_20, OBJECT_GI_STICK, GID_STICK, 0x90, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_STICK_UPGRADE_20),
GET_ITEM(ITEM_STICK_UPGRADE_30, OBJECT_GI_STICK, GID_STICK, 0x91, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_STICK_UPGRADE_30),
GET_ITEM(ITEM_NUT_UPGRADE_30, OBJECT_GI_NUTS, GID_NUTS, 0xA7, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_NUT_UPGRADE_30),
GET_ITEM(ITEM_NUT_UPGRADE_40, OBJECT_GI_NUTS, GID_NUTS, 0xA8, 0x80, CHEST_ANIM_SHORT, MOD_NONE, GI_NUT_UPGRADE_40),
GET_ITEM(ITEM_BULLET_BAG_50, OBJECT_GI_DEKUPOUCH, GID_BULLET_BAG_50, 0x6C, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BULLET_BAG_50),
GET_ITEM_NONE,
GET_ITEM_NONE,
};
ItemTableManager::Instance->AddItemTable(MOD_NONE);
for (uint8_t i = 0; i < ARRAY_COUNT(getItemTable); i++) {
// The vanilla item table array started with ITEM_BOMBS_5,
// but the GetItemID enum started with GI_NONE. Then everywhere
// that table was accessed used `GetItemID - 1`. This allows the
// "first" item of the new map to start at 1, syncing it up with
// the GetItemID values and removing the need for the `- 1`
ItemTableManager::Instance->AddItemEntry(MOD_NONE, i+1, getItemTable[i]);
}
}
extern "C" void OTRExtScanner() {
auto lst = *OTRGlobals::Instance->context->GetResourceManager()->ListFiles("*.*").get();
@ -182,6 +323,7 @@ extern "C" void InitOTR() {
OTRGlobals::Instance = new OTRGlobals();
SaveManager::Instance = new SaveManager();
CustomMessageManager::Instance = new CustomMessageManager();
ItemTableManager::Instance = new ItemTableManager();
auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version");
if (!t->bHasLoadError)
@ -200,6 +342,7 @@ extern "C" void InitOTR() {
Rando_Init();
InitItemTracker();
OTRExtScanner();
VanillaItemTable_Init();
}
extern "C" void DeinitOTR() {
@ -1410,14 +1553,6 @@ extern "C" void* getN64WeirdFrame(s32 i) {
return &weirdFrameBytes[i + sizeof(n64WeirdFrames)];
}
extern "C" s16 Randomizer_GetItemModelFromId(s16 itemId) {
return OTRGlobals::Instance->gRandomizer->GetItemModelFromId(itemId);
}
extern "C" s32 Randomizer_GetItemIDFromGetItemID(s32 getItemId) {
return OTRGlobals::Instance->gRandomizer->GetItemIDFromGetItemID(getItemId);
}
extern "C" void Randomizer_LoadSettings(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadRandomizerSettings(spoilerFileName);
}
@ -1477,21 +1612,45 @@ extern "C" CustomMessageEntry Randomizer_GetHintFromCheck(RandomizerCheck check)
return hintText;
}
extern "C" s32 Randomizer_GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) {
return OTRGlobals::Instance->gRandomizer->GetRandomizedItemId(ogId, actorId, actorParams, sceneNum);
extern "C" GetItemEntry ItemTable_Retrieve(int16_t getItemID) {
GetItemEntry giEntry = ItemTableManager::Instance->RetrieveItemEntry(OTRGlobals::Instance->getItemModIndex, getItemID);
return giEntry;
}
extern "C" s32 Randomizer_GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) {
return OTRGlobals::Instance->gRandomizer->GetRandomizedItemIdFromKnownCheck(randomizerCheck, ogId);
extern "C" GetItemEntry ItemTable_RetrieveEntry(s16 tableID, s16 getItemID) {
return ItemTableManager::Instance->RetrieveItemEntry(tableID, getItemID);
}
extern "C" GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) {
s16 getItemModIndex;
if (OTRGlobals::Instance->gRandomizer->CheckContainsVanillaItem(
OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams))) {
getItemModIndex = MOD_NONE;
} else {
getItemModIndex = MOD_RANDOMIZER;
}
s16 itemID = OTRGlobals::Instance->gRandomizer->GetRandomizedItemId(ogId, actorId, actorParams, sceneNum);
return ItemTable_RetrieveEntry(getItemModIndex, itemID);
}
extern "C" GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) {
s16 getItemModIndex;
if (OTRGlobals::Instance->gRandomizer->CheckContainsVanillaItem(randomizerCheck)) {
getItemModIndex = MOD_NONE;
} else {
getItemModIndex = MOD_RANDOMIZER;
}
s16 itemID = OTRGlobals::Instance->gRandomizer->GetRandomizedItemIdFromKnownCheck(randomizerCheck, ogId);
return ItemTable_RetrieveEntry(getItemModIndex, itemID);
}
extern "C" bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor) {
return gSaveContext.n64ddFlag && (actor->parent != NULL) &&