New Inventory Editor (#107)

* inventory editor

* fixed a bug where the menu was usable in special pause screens

* fixed most equipment screen issues

* draw page number on upgrade screen and minor improvements

* format

* fix build issues

* format

* fix build issues

* format

* various improvements

* fix build issues with non-debug

* small cleanup

* last improvements and bugfixes + cleanup and format
This commit is contained in:
Yanis
2025-11-04 17:23:27 +01:00
committed by GitHub
parent 90ca9c6ff9
commit af3dc71a5c
28 changed files with 1825 additions and 176 deletions

View File

@@ -72,7 +72,7 @@
/**** [INVENTORY EDITOR] ****/
// ``IS_INV_EDITOR_ENABLED``
#define ENABLE_INV_EDITOR false
#define ENABLE_INV_EDITOR true
/**** [EVENT EDITOR] ****/
// ``IS_EVENT_EDITOR_ENABLED``

View File

@@ -6,6 +6,7 @@
#include "padmgr.h"
#include "debug/print.h"
#include "debug/collision_view.h"
#include "debug/inventory_editor.h"
#include "debug/menu.h"
#include "debug/profiler.h"
#include "z_math.h"
@@ -19,11 +20,14 @@
#define COLOR_BLUE2 (0x0080FF)
#define COLOR_BLUE3 (0x00BFFF)
#define IS_INV_EDITOR_ACTIVE (IS_INV_EDITOR_ENABLED && gDebug.invDebug.state != INVEDITOR_STATE_OFF)
typedef struct Debug {
struct PlayState* play;
Input* input;
PrintUtils printer;
Menu menu;
InventoryEditor invDebug;
} Debug;
void Debug_DrawColorRectangle(Vec2s rectLeft, Vec2s rectRight, Color_RGBA8 rgba);

View File

@@ -0,0 +1,207 @@
#ifndef INVENTORY_EDITOR_H
#define INVENTORY_EDITOR_H
#include "config.h"
#include "pause.h"
typedef enum InvEditorMagicState {
INVEDITOR_MAGIC_STATE_NONE,
INVEDITOR_MAGIC_STATE_NORMAL,
INVEDITOR_MAGIC_STATE_DOUBLE,
} InvEditorMagicState;
typedef enum InvEditorInfosMiscTransState {
INVEDITOR_TRANS_STATE_DONE,
INVEDITOR_TRANS_STATE_INFO_REQUESTED,
INVEDITOR_TRANS_STATE_INFO_SWITCHING,
INVEDITOR_TRANS_STATE_MISC_REQUESTED,
INVEDITOR_TRANS_STATE_MISC_SWITCHING,
} InvEditorInfosMiscTransState;
typedef enum InvEditorCursorPos {
INVEDITOR_CURSOR_POS_MIN = -1,
INVEDITOR_CURSOR_POS_HEARTS,
INVEDITOR_CURSOR_POS_MAGIC,
INVEDITOR_CURSOR_POS_RUPEES,
INVEDITOR_CURSOR_POS_SMALL_KEYS,
INVEDITOR_CURSOR_POS_BOSS_KEY,
INVEDITOR_CURSOR_POS_COMPASS,
INVEDITOR_CURSOR_POS_MAP,
INVEDITOR_CURSOR_POS_MAX
} InvEditorCursorPos;
typedef enum InvEditorTitleState {
INVEDITOR_TITLE_STATE_MIN = -1,
INVEDITOR_TITLE_STATE_NAME,
INVEDITOR_TITLE_STATE_COMMANDS,
INVEDITOR_TITLE_STATE_MISCDBG
} InvEditorTitleState;
typedef enum InvEditorCommonState {
INVEDITOR_COMMON_STATE_MIN = -1,
INVEDITOR_COMMON_STATE_UNREADY,
INVEDITOR_COMMON_STATE_READY
} InvEditorCommonState;
typedef enum InvEditorState {
INVEDITOR_STATE_MIN = -1,
INVEDITOR_STATE_OFF,
INVEDITOR_STATE_INIT,
INVEDITOR_STATE_UPDATE,
INVEDITOR_STATE_DESTROY
} InvEditorState;
typedef struct InventoryEditorCommon {
InvEditorCommonState state;
u8 selectedItem;
u8 selectedSlot;
s8 changeBy;
} InvEditorCommon;
typedef struct InvEditorItems {
u8 childTradeItem;
u8 adultTradeItem;
u8 hookshotType;
u8 ocarinaType;
u8 bottleItems[4];
} InvEditorItems;
typedef struct InvEditorEquipment {
u8 showMiscUpgrades;
u8 upgradeSlots[8];
u8 upgradeValues[8];
u8 bgsFlag;
u16 swordHealth;
} InvEditorEquipment;
typedef struct InvEditorMisc {
u8 showMiscScreen;
u8 stickMoved;
u8 updateDefenseHearts;
InvEditorCursorPos hudCursorPos;
s8 hudDungeonIconIndex;
s16 hudTopPosY;
s16 hudBottomPosY;
s16 invertVal;
s16 mapIndex;
} InvEditorMisc;
struct GraphicsContext;
typedef struct InventoryEditor {
InvEditorState state;
GraphicsContext* gfxCtx;
PauseContext* pauseCtx;
InvEditorCommon common;
InvEditorItems itemDebug;
InvEditorEquipment equipDebug;
InvEditorMisc miscDebug;
u8 titleTimer;
InvEditorTitleState titleState;
s16 titlePosY;
s16 backgroundPosY;
u8 showInfoScreen;
s16 elementsAlpha;
s16 miscElementsAlpha;
} InventoryEditor;
Gfx* Gfx_TextureIA8(Gfx* displayListHead, void* texture, s16 textureWidth, s16 textureHeight, s16 rectLeft, s16 rectTop,
s16 rectWidth, s16 rectHeight, u16 dsdx, u16 dtdy);
u8 InventoryEditor_GetUpgradeType(u16 slotIndex);
void InventoryEditor_SetItemFromSlot(InventoryEditor* this);
void InventoryEditor_SetHUDAlpha(InventoryEditor* this);
void InventoryEditor_UpdateMiscScreen(InventoryEditor* this);
void InventoryEditor_UpdateQuestScreen(InventoryEditor* this);
void InventoryEditor_UpdateEquipmentScreen(InventoryEditor* this);
void InventoryEditor_UpdateItemScreen(InventoryEditor* this);
void InventoryEditor_UpdateInformationScreen(InventoryEditor* this);
void InventoryEditor_DrawRectangle(InventoryEditor* this, s32 leftX, s32 leftY, s32 rightX, s32 rightY,
Color_RGBA8 rgba);
void InventoryEditor_DrawMiscScreen(InventoryEditor* this);
void InventoryEditor_DrawEquipmentUpgrades(InventoryEditor* this, u16 i, s16 alpha);
void InventoryEditor_DrawInformationScreen(InventoryEditor* this);
void InventoryEditor_Init(InventoryEditor* this);
void InventoryEditor_Update(InventoryEditor* this);
void InventoryEditor_Draw(InventoryEditor* this);
bool InventoryEditor_Destroy(InventoryEditor* this);
void InventoryEditor_Main(InventoryEditor* this);
#define IS_IN_RANGE(val, min, max) ((val >= min) && (val <= max))
#define TIMER_DECR(val, target, changeBy) \
(((val - changeBy) < target) ? target : (val > target) ? (val - changeBy) : val)
#define TIMER_INCR(val, target, changeBy) \
(((val + changeBy) > target) ? target : (val < target) ? (val + changeBy) : val)
// General
#define INVEDITOR_PRINT_NEWLINE "\n "
#define INVEDITOR_ANIM_BASE_SPEED 16
#define INVEDITOR_BG_ANIM_SPEED INVEDITOR_ANIM_BASE_SPEED
#define INVEDITOR_BG_YPOS_TARGET 0
#define INVEDITOR_BG_YPOS 220
#define INVEDITOR_TITLE_TIMER 70 // frames
#define INVEDITOR_TITLE_ANIM_SPEED (INVEDITOR_ANIM_BASE_SPEED / 8)
#define INVEDITOR_TITLE_YPOS_TARGET 2
#define INVEDITOR_TITLE_YPOS 28
#define INVEDITOR_ALPHA_TRANS_SPEED (INVEDITOR_ANIM_BASE_SPEED * 2)
// Items
#define INVEDITOR_GET_BOTTLE_ITEM(invDebug) \
(IS_IN_RANGE((invDebug)->common.selectedSlot, SLOT_BOTTLE_1, SLOT_BOTTLE_4) \
? (invDebug)->itemDebug.bottleItems[(invDebug)->common.selectedSlot - SLOT_BOTTLE_1] \
: ITEM_NONE)
#define INVEDITOR_GET_CHILD_TRADE_ITEM(invDebug) \
(((invDebug)->common.selectedSlot == SLOT_TRADE_CHILD) ? (invDebug)->itemDebug.childTradeItem : ITEM_NONE)
#define INVEDITOR_GET_ADULT_TRADE_ITEM(invDebug) \
(((invDebug)->common.selectedSlot == SLOT_TRADE_ADULT) ? (invDebug)->itemDebug.adultTradeItem : ITEM_NONE)
#define INVEDITOR_GET_HOOKSHOT(invDebug) \
(((invDebug)->common.selectedSlot == SLOT_HOOKSHOT) ? (invDebug)->itemDebug.hookshotType : ITEM_NONE)
#define INVEDITOR_GET_OCARINA(invDebug) \
(((invDebug)->common.selectedSlot == SLOT_OCARINA) ? (invDebug)->itemDebug.ocarinaType : ITEM_NONE)
#define INVEDITOR_GET_VARIABLE_ITEM(invDebug) \
((INVEDITOR_GET_BOTTLE_ITEM(invDebug) != ITEM_NONE) ? INVEDITOR_GET_BOTTLE_ITEM(invDebug) \
: (INVEDITOR_GET_CHILD_TRADE_ITEM(invDebug) != ITEM_NONE) ? INVEDITOR_GET_CHILD_TRADE_ITEM(invDebug) \
: (INVEDITOR_GET_ADULT_TRADE_ITEM(invDebug) != ITEM_NONE) ? INVEDITOR_GET_ADULT_TRADE_ITEM(invDebug) \
: (INVEDITOR_GET_HOOKSHOT(invDebug) != ITEM_NONE) ? INVEDITOR_GET_HOOKSHOT(invDebug) \
: (INVEDITOR_GET_OCARINA(invDebug) != ITEM_NONE) ? INVEDITOR_GET_OCARINA(invDebug) \
: ITEM_NONE)
#define INVEDITOR_UPDATE_ITEM(invDbgCommon, min, max) \
{ \
if (IS_IN_RANGE(invDbgCommon.selectedItem, min, max)) { \
gSaveContext.save.info.inventory.items[invDbgCommon.selectedSlot] += invDbgCommon.changeBy; \
if (gSaveContext.save.info.inventory.items[invDbgCommon.selectedSlot] > max) { \
gSaveContext.save.info.inventory.items[invDbgCommon.selectedSlot] = min; \
} \
\
if (gSaveContext.save.info.inventory.items[invDbgCommon.selectedSlot] < min) { \
gSaveContext.save.info.inventory.items[invDbgCommon.selectedSlot] = max; \
} \
} \
}
// Equipment
#define INVEDITOR_IS_UPGRADE(invDbgCommon) \
(((invDbgCommon).selectedSlot == SLOT_UPG_QUIVER) || ((invDbgCommon).selectedSlot == SLOT_UPG_BOMB_BAG) || \
((invDbgCommon).selectedSlot == SLOT_UPG_STRENGTH) || ((invDbgCommon).selectedSlot == SLOT_UPG_SCALE))
// Misc
#define INVEDITOR_HUD_TOP_ANIM_SPEED INVEDITOR_ANIM_BASE_SPEED / 5
#define INVEDITOR_HUD_TOP_YPOS_TARGET 35
#define INVEDITOR_HUD_TOP_YPOS 0
#define INVEDITOR_HUD_BOTTOM_ANIM_SPEED INVEDITOR_ANIM_BASE_SPEED / 2
#define INVEDITOR_HUD_BOTTOM_YPOS_TARGET 100
#define INVEDITOR_HUD_BOTTOM_YPOS 0
#define INVEDITOR_HUD_BOTTOM_INVERT_SPEED INVEDITOR_ANIM_BASE_SPEED / 16
#define INVEDITOR_HUD_BOTTOM_INVERT_TARGET 16
#endif

View File

@@ -105,6 +105,11 @@ Gfx* Gfx_SetupDL_39(Gfx* gfx);
void Gfx_SetupDL_39Opa(struct GraphicsContext* gfxCtx);
void Gfx_SetupDL_39Overlay(struct GraphicsContext* gfxCtx);
void Gfx_SetupDL_39Ptr(Gfx** gfxP);
#if DEBUG_FEATURES
void Gfx_SetupDL_39Debug(struct GraphicsContext* gfxCtx);
#endif
void Gfx_SetupDL_40Opa(struct GraphicsContext* gfxCtx);
void Gfx_SetupDL_41Opa(struct GraphicsContext* gfxCtx);
void Gfx_SetupDL_47Xlu(struct GraphicsContext* gfxCtx);

View File

@@ -151,6 +151,25 @@ typedef enum InventorySlot {
/* 0xFF */ SLOT_NONE = 0xFF
} InventorySlot;
typedef enum EquipmentSlot {
/* 0x00 */ SLOT_UPG_QUIVER, // also bullet bag slot
/* 0x01 */ SLOT_SWORD_KOKIRI,
/* 0x02 */ SLOT_SWORD_MASTER,
/* 0x03 */ SLOT_SWORD_BIGGORON,
/* 0x04 */ SLOT_UPG_BOMB_BAG, // also deku stick capacity slot (inventory editor only)
/* 0x05 */ SLOT_SHIELD_DEKU,
/* 0x06 */ SLOT_SHIELD_HYLIAN,
/* 0x07 */ SLOT_SHIELD_MIRROR,
/* 0x08 */ SLOT_UPG_STRENGTH, // also deku nut capacity slot (inventory editor only)
/* 0x09 */ SLOT_TUNIC_KOKIRI,
/* 0x0A */ SLOT_TUNIC_GORON,
/* 0x0B */ SLOT_TUNIC_ZORA,
/* 0x0C */ SLOT_UPG_SCALE, // also wallet capacity slot (inventory editor only)
/* 0x0D */ SLOT_BOOTS_KOKIRI,
/* 0x0E */ SLOT_BOOTS_IRON,
/* 0x0F */ SLOT_BOOTS_HOVER
} EquipmentSlot;
typedef enum ItemID {
/* 0x00 */ ITEM_DEKU_STICK,
/* 0x01 */ ITEM_DEKU_NUT,

View File

@@ -93,7 +93,7 @@ typedef enum PauseDebugState {
#if IS_INV_EDITOR_ENABLED || IS_EVENT_EDITOR_ENABLED
#define IS_PAUSED(pauseCtx) \
(((pauseCtx)->state != PAUSE_STATE_OFF) || ((pauseCtx)->debugState != PAUSE_DEBUG_STATE_CLOSED))
(((pauseCtx)->state != PAUSE_STATE_OFF) || (IS_INV_EDITOR_ACTIVE && (pauseCtx)->debugState != PAUSE_DEBUG_STATE_CLOSED))
#else
#define IS_PAUSED(pauseCtx) \
((pauseCtx)->state != PAUSE_STATE_OFF)