diff --git a/.github/workflows/build-test-release.yml b/.github/workflows/build-test-release.yml index eb3f1f07..4a8f326f 100644 --- a/.github/workflows/build-test-release.yml +++ b/.github/workflows/build-test-release.yml @@ -289,6 +289,8 @@ jobs: google_drive_url_secret: PH_US_DPAD_GOOGLE_DRIVE_ID steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Set up Python uses: actions/setup-python@v5 @@ -404,6 +406,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + submodules: recursive # Also retrieve previous commit so we can check if there are relevant changes fetch-depth: 2 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..dc068475 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "base/code/external/ph-decomp"] + path = base/code/external/ph-decomp + url = https://github.com/zeldaret/ph diff --git a/base/Dockerfile b/base/Dockerfile index b3d197af..1d887dac 100644 --- a/base/Dockerfile +++ b/base/Dockerfile @@ -29,6 +29,7 @@ RUN pip install -r requirements.txt # Add needed source files to the docker build ADD data/* /app/ ADD code/* /app/code/ +ADD code/external/ /app/code/external/ ADD extract_rom.py /app ADD rebuild_rom.py /app ADD Makefile /app diff --git a/base/Makefile b/base/Makefile index f679c60d..bbd30d99 100644 --- a/base/Makefile +++ b/base/Makefile @@ -1,16 +1,21 @@ .PHONY: all debug -# Set ARM compiler +# Set ARM compiler (using g++ for C++ support) +CXX=arm-none-eabi-g++ CC=arm-none-eabi-gcc -# Set up compilation flags -CFLAGS := -marm -mno-thumb-interwork -march=armv5te -mtune=arm946e-s -fno-inline -Wall -Os - -# C source file directory +# C++ source file directory SRC_DIR=code -SRC=$(wildcard $(SRC_DIR)/*.c) -OBJ=$(SRC:.c=.o) -ASM=$(SRC:.c=.asm) +SRC_CPP=$(wildcard $(SRC_DIR)/*.cpp) +SRC_C=$(wildcard $(SRC_DIR)/*.c) +OBJ_CPP=$(SRC_CPP:.cpp=.o) +OBJ_C=$(SRC_C:.c=.o) +OBJ=$(OBJ_CPP) $(OBJ_C) +ASM=$(SRC_CPP:.cpp=.asm) $(SRC_C:.c=.asm) + +# Set up compilation flags +CXXFLAGS := -marm -mno-thumb-interwork -march=armv5te -mtune=arm946e-s -fno-inline -Os -nostdlib -fno-exceptions -fno-rtti -Wno-multichar -fpermissive -I$(SRC_DIR)/external/ph-decomp/include -I$(SRC_DIR)/external/ph-decomp/libs/nds/include -I$(SRC_DIR)/external/ph-decomp/libs/c/include +CFLAGS := -marm -mno-thumb-interwork -march=armv5te -mtune=arm946e-s -fno-inline -Wall -Os -nostdlib INPUT_NDS_FILE=$(PH_ROM_PATH) PREPATCHED_NDS_FILE=prepatched.nds @@ -35,10 +40,18 @@ $(PREPATCHED_NDS_FILE): $(INPUT_NDS_FILE) # Same as `all`, but also includes readable .asm file debug: $(OBJ) $(ASM) +# Compile C++ source file to assembly code +%.asm: %.cpp + $(CXX) $(CXXFLAGS) -S "$<" -o "$@" -fverbose-asm + # Compile C source file to assembly code %.asm: %.c $(CC) $(CFLAGS) -S "$<" -o "$@" -fverbose-asm +# Compile C++ source file to object file +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c "$<" -o "$@" + # Compile C source file to object file %.o: %.c $(CC) $(CFLAGS) -c "$<" -o "$@" diff --git a/base/code/custom_salvage_item.c b/base/code/custom_salvage_item.c deleted file mode 100644 index f667734b..00000000 --- a/base/code/custom_salvage_item.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "ph.h" -#include - -#define MAX_HEALTH_ADDR 0x021BA348 -#define CURRENT_HEALTH_ADDR 0x021BA34A -#define PLAYER_HEALTH_PTR_ADDR 0x2146470 - -void custom_salvage_item(uint32_t item_id_with_flag) { - uint16_t item_id = item_id_with_flag & 0x7FFF; // Unset the most significant bit - - // The salvage arm "get item" code doesn't properly set memory values for items - // that it was never intended to give, so we need to manually set them here. - switch (item_id) { - case 0xA: // heart container - gHealthManager->mMaxHealth += 4; // Increment max health by 4 (one heart container) - gHealthManager->mHealth = - gHealthManager->mMaxHealth; // Restore the player's health to the new maximum - break; - case 0x45: // phantom sword - gItemManager->mItemFlags[1] = gItemManager->mItemFlags[1] | 0x20; - break; - } - - uint32_t *player_health_ptr = (uint32_t *)PLAYER_HEALTH_PTR_ADDR; - uint32_t player_data = *player_health_ptr; - *((uint16_t *)(player_data + 0xEC)) = item_id; // Store the item ID in the specified offset -} diff --git a/base/code/custom_salvage_item.cpp b/base/code/custom_salvage_item.cpp new file mode 100644 index 00000000..d354a1fa --- /dev/null +++ b/base/code/custom_salvage_item.cpp @@ -0,0 +1,30 @@ +#include "ph.hpp" + +#define MAX_HEALTH_ADDR 0x021BA348 +#define CURRENT_HEALTH_ADDR 0x021BA34A +#define PLAYER_HEALTH_PTR_ADDR 0x2146470 + +extern "C" { + +void custom_salvage_item(u32 item_id_with_flag) { + u16 item_id = item_id_with_flag & 0x7FFF; // Unset the most significant bit + + // The salvage arm "get item" code doesn't properly set memory values for items + // that it was never intended to give, so we need to manually set them here. + switch (item_id) { + case 0xA: // heart container + gPlayerManager->mMaxHealth += 4; // Increment max health by 4 (one heart container) + gPlayerManager->mHealth = + gPlayerManager->mMaxHealth; // Restore the player's health to the new maximum + break; + case 0x45: // phantom sword + gItemManager->mItemFlags.flags[1] = gItemManager->mItemFlags.flags[1] | 0x20; + break; + } + + u32 *player_health_ptr = (u32 *)PLAYER_HEALTH_PTR_ADDR; + u32 player_data = *player_health_ptr; + *((u16 *)(player_data + 0xEC)) = item_id; // Store the item ID in the specified offset +} + +} // extern "C" diff --git a/base/code/extend_RUPY_npc.c b/base/code/extend_RUPY_npc.cpp similarity index 82% rename from base/code/extend_RUPY_npc.c rename to base/code/extend_RUPY_npc.cpp index 5655c469..0ac38cc4 100644 --- a/base/code/extend_RUPY_npc.c +++ b/base/code/extend_RUPY_npc.cpp @@ -1,7 +1,9 @@ -#include +#include "ph.hpp" -uint32_t extend_RUPY_npc(uint32_t *addr) { - uint32_t rupy_type = addr[0x56]; +extern "C" { + +u32 extend_RUPY_npc(u32 *addr) { + u32 rupy_type = addr[0x56]; switch (rupy_type) { case 3: return 9; @@ -24,3 +26,5 @@ uint32_t extend_RUPY_npc(uint32_t *addr) { return 0xffffffff; } } + +} // extern "C" diff --git a/base/code/extend_give_item_function.c b/base/code/extend_give_item_function.c deleted file mode 100644 index fea31b72..00000000 --- a/base/code/extend_give_item_function.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "ph.h" -#include - -void extend_give_item_function(ItemManager *inventory, int32_t item_id) { - switch (item_id) { - case 0x45: // phantom sword - inventory->mItemFlags[1] = inventory->mItemFlags[1] | 0x20; - break; - } -} diff --git a/base/code/extend_give_item_function.cpp b/base/code/extend_give_item_function.cpp new file mode 100644 index 00000000..149eae2a --- /dev/null +++ b/base/code/extend_give_item_function.cpp @@ -0,0 +1,13 @@ +#include "ph.hpp" + +extern "C" { + +void extend_give_item_function(ItemManager *inventory, s32 item_id) { + switch (item_id) { + case 0x45: // phantom sword + inventory->mItemFlags.flags[1] = inventory->mItemFlags.flags[1] | 0x20; + break; + } +} + +} // extern "C" diff --git a/base/code/external/ph-decomp b/base/code/external/ph-decomp new file mode 160000 index 00000000..5b15874c --- /dev/null +++ b/base/code/external/ph-decomp @@ -0,0 +1 @@ +Subproject commit 5b15874c4d2d7c185c98f2791cf8fa6a9d86a440 diff --git a/base/code/faster_boat.c b/base/code/faster_boat.cpp similarity index 52% rename from base/code/faster_boat.c rename to base/code/faster_boat.cpp index 06cd8272..9d21e9cf 100644 --- a/base/code/faster_boat.c +++ b/base/code/faster_boat.cpp @@ -1,19 +1,21 @@ -#include +#include "ph.hpp" + +extern "C" { void faster_boat() { - uint32_t boat_speed_offset = (*(uint32_t *)(0x20EE4B4) + 0xF7FFF5B4); + u32 boat_speed_offset = (*(u32 *)(0x20EE4B4) + 0xF7FFF5B4); - int16_t *boat_speed = (int16_t *)(0x8000000 + boat_speed_offset); + s16 *boat_speed = (s16 *)(0x8000000 + boat_speed_offset); // Increase boat speed if R button is pressed and the current speed is less // than max speed - if (((*((uint16_t *)0x4000130) >> 8) & 1) == 0 && *boat_speed < 0x540) { + if (((*((u16 *)0x4000130) >> 8) & 1) == 0 && *boat_speed < 0x540) { *boat_speed += 0x20; } // Decrease boat speed if L button is pressed and the current speed is greater // than zero - if (((*((uint16_t *)0x4000130) >> 9) & 1) == 0 && *boat_speed > 0) { + if (((*((u16 *)0x4000130) >> 9) & 1) == 0 && *boat_speed > 0) { *boat_speed -= 0x20; } @@ -22,3 +24,5 @@ void faster_boat() { } return; } + +} // extern "C" diff --git a/base/code/fixed_random_treasure_in_shop.c b/base/code/fixed_random_treasure_in_shop.cpp similarity index 83% rename from base/code/fixed_random_treasure_in_shop.c rename to base/code/fixed_random_treasure_in_shop.cpp index 1ed28df3..c78368b2 100644 --- a/base/code/fixed_random_treasure_in_shop.c +++ b/base/code/fixed_random_treasure_in_shop.cpp @@ -1,4 +1,6 @@ -#include +#include "ph.hpp" + +extern "C" { __attribute__((target("thumb"))) void fixed_random_treasure_in_shop(char *stack_ptr, char *nsbmd_file, char *nsbtx_file) { @@ -7,3 +9,5 @@ fixed_random_treasure_in_shop(char *stack_ptr, char *nsbmd_file, char *nsbtx_fil stack_ptr[i + 0x44] = nsbmd_file[i]; } } + +} // extern "C" diff --git a/base/code/get_item_model.c b/base/code/get_item_model.cpp similarity index 86% rename from base/code/get_item_model.c rename to base/code/get_item_model.cpp index 7a3d0164..3d2b8abb 100644 --- a/base/code/get_item_model.c +++ b/base/code/get_item_model.cpp @@ -1,9 +1,10 @@ -#include "ph.h" -#include +#include "ph.hpp" #define NEW_DATA_FILE_PATH_PREFIX "r/" -void get_item_model(uint32_t item_id, char *nsbmd_dest, char *nsbtx_dest) { +extern "C" { + +void get_item_model(u32 item_id, char *nsbmd_dest, char *nsbtx_dest) { char *model_name; char *model_file_path_prefix = NEW_DATA_FILE_PATH_PREFIX; @@ -29,3 +30,5 @@ void get_item_model(uint32_t item_id, char *nsbmd_dest, char *nsbtx_dest) { strcat(nsbtx_dest, model_name); strcat(nsbtx_dest, ".nsbtx"); } + +} // extern "C" diff --git a/base/code/ph.asm b/base/code/ph.asm index b18ddfbd..a0db3bcb 100644 --- a/base/code/ph.asm +++ b/base/code/ph.asm @@ -15,5 +15,4 @@ .definelabel got_new_item_model_path_prefix, 0x20e5da8 .definelabel item_id_to_string, 0x20e5c3c .definelabel gItemManager, 0x27e0fb4 -.definelabel GiveItem, 0x20adc7c -.definelabel gHealthManager, 0x27e0fbc +.definelabel gPlayerManager, 0x27e0fbc diff --git a/base/code/ph.h b/base/code/ph.h deleted file mode 100644 index 354c5469..00000000 --- a/base/code/ph.h +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include - -// This header file contains definitions for functions, variables, struct -// definitions, etc that are present in the base game. - -extern void strcat(char *dest, char *src); -extern int strcmp(char *s1, char *s2); -extern int strncmp(char *s1, char *s2, int n); -extern void strcpy(char *dest, char *src); -extern void strncpy(char *dest, char *src, int n); -extern int32_t strlen(char *s); -extern char *strrchr(char *s, int c); -extern char *strstr(char *haystack, char needle); - -// TODO: verify this is correct. I'm not sure if this -// function is really an implementation of sprintf. -extern void sprintf(char *string, char *format); - -typedef struct { - uint32_t id; - void *baseAddr; - int32_t textSize; - int32_t bssSize; - int32_t sinitStart; - int32_t sinitEnd; - int32_t fileId; - int32_t fileSize; -} Overlay; - -extern bool LoadOverlay(Overlay *overlay); - -typedef struct { - uint32_t npc_id; - uint32_t (*spawn_function)(void); - uint32_t unknown1; - uint32_t unknown2; - struct NPC *next; -} NPC; - -// searches the list of NPC structs in memory for the given NPC and returns its -// address. -extern NPC *get_npc_address(uint32_t npc_id); // 203e824 - -extern char *got_new_item_model_path_prefix; -extern char *item_id_to_string[]; - -typedef struct { - int32_t mEquippedItem; - int32_t mPrevEquippedItem; - int32_t mForcedItem; // game crashes when any item besides this one is equipped - uint32_t mHourglassSandFrames; - int32_t mEquippedFairy; - void *mFairies[3]; - uint16_t mEquipLoadTimer; - uint16_t mNumRupees; - uint8_t mNumGems[3]; - uint8_t mUnk_027; // padding? - uint32_t mEquippedShipParts[8]; - int8_t mShipParts[8][9]; - int8_t mTreasure[8]; - uint8_t mUnk_098[6]; // max 99 - uint16_t mUnk_09e[6]; // max 9999, corresponds with mUnk_098 - uint16_t mUnk_0aa; // padding? - void *(*mEquipItems)[11]; - uint16_t (*mAmmo)[11]; - uint16_t mQuiverSize; - uint16_t mBombBagSize; - uint16_t mBombchuBagSize; - uint16_t mUnk_0ba; // only between 0 and 9 - uint8_t mPotions[2]; - uint8_t mUnk_0be[2]; // padding? - void *mItemModels[16]; - void *mDungeonItemModels[5]; // non-null in dungeons/caves - void *mModelRender; - int32_t mFanfareItemId; - uint32_t mFanfareSfx; - void *mFanfareItemModel; - void *mUnk_124; - uint32_t mItemFlags[4]; - uint32_t mSalvagedTreasureFlags; - uint32_t mShipPartPricesShown[3]; - uint32_t mTreasurePriceShownFlag; - bool mMuteNextFanfare; - uint8_t mUnk_14d; - uint8_t mUnk_14e[0x2]; // padding? -} ItemManager; - -extern ItemManager *gItemManager; -extern void GiveItem(ItemManager *inventory, int32_t itemId); - -typedef struct { - uint16_t mMaxHealth; - uint16_t mHealth; - int16_t mMaxShipHealth; - int16_t mShipHealth; - uint16_t mSalvageArmHealth; - int16_t mFlags; - uint16_t mUnk_0c; - uint8_t mUnk_0e; - uint8_t mUnk_0f; -} HealthManager; - -extern HealthManager *gHealthManager; diff --git a/base/code/ph.hpp b/base/code/ph.hpp new file mode 100644 index 00000000..68949daf --- /dev/null +++ b/base/code/ph.hpp @@ -0,0 +1,44 @@ +#ifndef PH_RANDOMIZER_H +#define PH_RANDOMIZER_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "string.h" +#include "types.h" +#ifdef __cplusplus +} +#endif + +#include "Actor/ActorType.hpp" +#include "Item/ItemManager.hpp" +#include "Player/PlayerManager.hpp" + +// This header file contains definitions for functions, variables, struct +// definitions, etc that are present in the base game. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + u32 id; + void *baseAddr; + s32 textSize; + s32 bssSize; + s32 sinitStart; + s32 sinitEnd; + s32 fileId; + s32 fileSize; +} Overlay; + +extern bool LoadOverlay(Overlay *overlay); + +extern char *got_new_item_model_path_prefix; +extern char *item_id_to_string[]; + +#ifdef __cplusplus +} +#endif + +#endif // PH_RANDOMIZER_H diff --git a/base/code/progressive_sword_check.c b/base/code/progressive_sword_check.cpp similarity index 74% rename from base/code/progressive_sword_check.c rename to base/code/progressive_sword_check.cpp index 153e35db..b5eb03e5 100644 --- a/base/code/progressive_sword_check.c +++ b/base/code/progressive_sword_check.cpp @@ -1,17 +1,18 @@ -#include -#include +#include "ph.hpp" #define OSHUS_SWORD_FLAG_OFFSET (0x128) #define OSHUS_SWORD_FLAG_BIT (0x1) #define PHANTOM_SWORD_FLAG_OFFSET (0x12C) #define PHANTOM_SWORD_FLAG_BIT (0x20) -__attribute__((target("thumb"))) void progressive_sword_check(const uint32_t base_address) { +extern "C" { + +__attribute__((target("thumb"))) void progressive_sword_check(const u32 base_address) { // Address of oshus sword flag - uint8_t *oshus_sword = (uint8_t *)(base_address + OSHUS_SWORD_FLAG_OFFSET); + u8 *oshus_sword = (u8 *)(base_address + OSHUS_SWORD_FLAG_OFFSET); // Address of phantom sword flag - uint8_t *phantom_sword = (uint8_t *)(base_address + PHANTOM_SWORD_FLAG_OFFSET); + u8 *phantom_sword = (u8 *)(base_address + PHANTOM_SWORD_FLAG_OFFSET); // Check if player has the oshus sword bool has_oshus_sword = (*oshus_sword & OSHUS_SWORD_FLAG_BIT) == OSHUS_SWORD_FLAG_BIT; @@ -24,3 +25,5 @@ __attribute__((target("thumb"))) void progressive_sword_check(const uint32_t bas *oshus_sword |= OSHUS_SWORD_FLAG_BIT; } } + +} // extern "C" diff --git a/base/code/rando_settings.c b/base/code/rando_settings.c deleted file mode 100644 index e9955187..00000000 --- a/base/code/rando_settings.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "rando_settings.h" - -bool setting_is_enabled(uint8_t offset, uint8_t bit) { - uint8_t *base_addr = (uint8_t *)RANDO_SETTINGS_BITMAP_ADDR; - return (base_addr[offset] & bit) == bit; -} diff --git a/base/code/rando_settings.cpp b/base/code/rando_settings.cpp new file mode 100644 index 00000000..069b8624 --- /dev/null +++ b/base/code/rando_settings.cpp @@ -0,0 +1,10 @@ +#include "rando_settings.h" + +extern "C" { + +bool setting_is_enabled(u8 offset, u8 bit) { + u8 *base_addr = (u8 *)RANDO_SETTINGS_BITMAP_ADDR; + return (base_addr[offset] & bit) == bit; +} + +} // extern "C" diff --git a/base/code/rando_settings.h b/base/code/rando_settings.h index 0163b3e5..3168b288 100644 --- a/base/code/rando_settings.h +++ b/base/code/rando_settings.h @@ -1,5 +1,11 @@ -#include -#include +#ifndef RANDO_SETTINGS_H +#define RANDO_SETTINGS_H + +#include "ph.hpp" + +#ifdef __cplusplus +extern "C" { +#endif // RAM address of bitmap encoding randomizer settings #define RANDO_SETTINGS_BITMAP_ADDR 0x2058180 @@ -17,4 +23,10 @@ * `RANDO_SETTINGS_BITMAP_ADDR[offset]` byte * @return true if setting is enabled, false if it is disabled */ -bool setting_is_enabled(uint8_t offset, uint8_t bit); +bool setting_is_enabled(u8 offset, u8 bit); + +#ifdef __cplusplus +} +#endif + +#endif // RANDO_SETTINGS_H diff --git a/base/code/set_initial_flags.c b/base/code/set_initial_flags.cpp similarity index 76% rename from base/code/set_initial_flags.c rename to base/code/set_initial_flags.cpp index 3fe44fd6..d4496373 100644 --- a/base/code/set_initial_flags.c +++ b/base/code/set_initial_flags.cpp @@ -1,20 +1,21 @@ -#include "ph.h" +#include "ph.hpp" #include "rando_settings.h" -#include + +extern "C" { #define NO_SETTING -1, 0 typedef struct { - uint16_t flag_offset; // offset of the flag from the "base address" (see first - // arg of set_initial_flags() ) - uint8_t flag_bit; // the bit within the value @ flag_offset that represents - // this flag - int32_t setting_offset; // offset of the randomizer setting that this flag is - // gated behind, or -1 if it's not gated behind any - // settings. Make this a 32 bit uint to pad struct to - // 16 bytes - uint8_t setting_bit; // the bit within the value @ setting_offset that this - // represents this setting + u16 flag_offset; // offset of the flag from the "base address" (see first + // arg of set_initial_flags() ) + u8 flag_bit; // the bit within the value @ flag_offset that represents + // this flag + s32 setting_offset; // offset of the randomizer setting that this flag is + // gated behind, or -1 if it's not gated behind any + // settings. Make this a 32 bit uint to pad struct to + // 16 bytes + u8 setting_bit; // the bit within the value @ setting_offset that this + // represents this setting } Flag; /** @@ -72,15 +73,17 @@ Flag flags[] = { {0x24, 0x20, NO_SETTING}, // blew dust off of NW sea chart }; -static void set_flag(uint32_t addr, uint8_t bit) { - *((uint8_t *)addr) |= bit; +static void set_flag(u32 addr, u8 bit) { + *((u8 *)addr) |= bit; } -void set_initial_flags(uint32_t base_flag_address) { +void set_initial_flags(u32 base_flag_address) { for (int i = 0; i < sizeof(flags) / sizeof(Flag); i++) { Flag f = flags[i]; - if (f.setting_offset == -1 || setting_is_enabled((uint8_t)f.setting_offset, f.setting_bit)) { + if (f.setting_offset == -1 || setting_is_enabled((u8)f.setting_offset, f.setting_bit)) { set_flag(base_flag_address + f.flag_offset, f.flag_bit); } } } + +} // extern "C" diff --git a/base/code/spawn_custom_freestanding_item.c b/base/code/spawn_custom_freestanding_item.cpp similarity index 71% rename from base/code/spawn_custom_freestanding_item.c rename to base/code/spawn_custom_freestanding_item.cpp index 9533ec10..4153a0ca 100644 --- a/base/code/spawn_custom_freestanding_item.c +++ b/base/code/spawn_custom_freestanding_item.cpp @@ -1,24 +1,26 @@ -#include +#include "ph.hpp" #define RUPY 0x52555059 +extern "C" { + /** * @param param_1 - original function arg, don't modify * @param npc_type - 4 character string representing NPC type. * @param param_3 - original function arg, don't modify * @param param_4 - original function arg, don't modify */ -uint16_t spawn_custom_freestanding_item(void *param_1, uint32_t npc_type, void *param_3, - uint16_t *param_4) { +u16 spawn_custom_freestanding_item(void *param_1, u32 npc_type, void *param_3, u16 *param_4) { // declare pointer to the game's `spawn_npc` function - uint16_t (*spawn_npc)(void *, uint32_t, void *, uint16_t *) = (void *)0x20C3FE8; + u16 (*spawn_npc)(void *, u32, void *, u16 *) = + reinterpret_cast(0x20C3FE8); - uint16_t *item_id_address; + u16 *item_id_address; // pull the base address of the NPCA entry's item_id off of the stack asm volatile("ldr %0, [sp, #0x4]" : "=r"(item_id_address) :); // get the item id - uint16_t item_id = item_id_address[0x10]; + u16 item_id = item_id_address[0x10]; // if item_id is 0x1, continue as the vanilla game does. if (item_id == 0x1) { @@ -29,3 +31,5 @@ uint16_t spawn_custom_freestanding_item(void *param_1, uint32_t npc_type, void * *param_4 = item_id; return (*spawn_npc)(param_1, RUPY, param_3, param_4); } + +} // extern "C"