Merge pull request #3756 from HarbourMasters/develop

develop -> develop-rando
This commit is contained in:
Garrett Cox 2023-12-28 20:12:39 +00:00 committed by GitHub
commit 6c88d33b19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1745 additions and 354 deletions

View File

@ -21,12 +21,17 @@ fi
while [[ (! -e "$SHIP_HOME"/oot.otr) || (! -e "$SHIP_HOME"/oot-mq.otr) ]]; do
for romfile in "$SHIP_HOME"/*.*64
do
if [[ -e $romfile ]]; then
if [[ -e "$romfile" ]] || [[ -L "$romfile" ]]; then
export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)"
ln -s "$HERE"/usr/bin/{assets,soh.elf,ZAPD} "$ASSETDIR"
ln -s "$SHIP_BIN_DIR"/{assets,soh.elf,ZAPD} "$ASSETDIR"
export OLDPWD="$PWD"
mkdir -p "$ASSETDIR"/tmp
if [[ -e "$romfile" ]]; then
ln -s "$romfile" "$ASSETDIR"/tmp/rom.z64
else
ORIG_ROM_PATH=$(readlink "$romfile")
ln -s "$ORIG_ROM_PATH" "$ASSETDIR"/tmp/rom.z64
fi
cd "$ASSETDIR"
ROMHASH=$(sha1sum -b "$ASSETDIR"/tmp/rom.z64 | awk '{ print $1 }')

View File

@ -2171,7 +2171,7 @@ void func_800FA18C(u8, u8);
void Audio_SetVolScale(u8 playerIdx, u8 scaleIdx, u8 targetVol, u8 volFadeTimer);
void func_800FA3DC(void);
u8 func_800FAD34(void);
void func_800FADF8(void);
void Audio_ResetActiveSequences(void);
void func_800FAEB4(void);
void GfxPrint_SetColor(GfxPrint* this, u32 r, u32 g, u32 b, u32 a);
void GfxPrint_SetPosPx(GfxPrint* this, s32 x, s32 y);

View File

@ -224,7 +224,7 @@ extern "C"
extern u16 gAudioSfxSwapSource[10];
extern u16 gAudioSfxSwapTarget[10];
extern u8 gAudioSfxSwapMode[10];
extern unk_D_8016E750 D_8016E750[4];
extern ActiveSequence gActiveSeqs[4];
extern AudioContext gAudioContext;
extern void(*D_801755D0)(void);

View File

@ -970,43 +970,43 @@ typedef struct {
} AudioContextInitSizes; // size = 0xC
typedef struct {
/* 0x00 */ f32 unk_00;
/* 0x04 */ f32 unk_04;
/* 0x08 */ f32 unk_08;
/* 0x0C */ u16 unk_0C;
/* 0x10 */ f32 unk_10;
/* 0x14 */ f32 unk_14;
/* 0x18 */ f32 unk_18;
/* 0x1C */ u16 unk_1C;
} unk_50_s; // size = 0x20
/* 0x00 */ f32 volCur;
/* 0x04 */ f32 volTarget;
/* 0x08 */ f32 volStep;
/* 0x0C */ u16 volTimer;
/* 0x10 */ f32 freqScaleCur;
/* 0x14 */ f32 freqScaleTarget;
/* 0x18 */ f32 freqScaleStep;
/* 0x1C */ u16 freqScaleTimer;
} ActiveSequenceChannelData; // size = 0x20
typedef struct {
/* 0x000 */ f32 volCur;
/* 0x004 */ f32 volTarget;
/* 0x008 */ f32 unk_08;
/* 0x00C */ u16 unk_0C;
/* 0x00E */ u8 volScales[0x4];
/* 0x008 */ f32 volStep;
/* 0x00C */ u16 volTimer;
/* 0x00E */ u8 volScales[4];
/* 0x012 */ u8 volFadeTimer;
/* 0x013 */ u8 fadeVolUpdate;
/* 0x014 */ u32 unk_14;
/* 0x018 */ u16 unk_18;
/* 0x01C */ f32 unk_1C;
/* 0x020 */ f32 unk_20;
/* 0x024 */ f32 unk_24;
/* 0x028 */ u16 unk_28;
/* 0x02C */ u32 unk_2C[8];
/* 0x04C */ u8 unk_4C;
/* 0x04D */ u8 unk_4D;
/* 0x04E */ u8 unk_4E;
/* 0x050 */ unk_50_s unk_50[0x10];
/* 0x250 */ u16 unk_250;
/* 0x252 */ u16 unk_252;
/* 0x254 */ u16 unk_254;
/* 0x256 */ u16 unk_256;
/* 0x258 */ u16 unk_258;
/* 0x25C */ u32 unk_25C;
/* 0x260 */ u8 unk_260;
} unk_D_8016E750; // size = 0x264
/* 0x014 */ u32 tempoCmd;
/* 0x018 */ u16 tempoOriginal; // stores the original tempo before modifying it (to reset back to)
/* 0x01C */ f32 tempoCur;
/* 0x020 */ f32 tempoTarget;
/* 0x024 */ f32 tempoStep;
/* 0x028 */ u16 tempoTimer;
/* 0x02C */ u32 setupCmd[8]; // a queue of cmds to execute once the player is disabled
/* 0x04C */ u8 setupCmdTimer; // only execute setup commands when the timer is at 0.
/* 0x04D */ u8 setupCmdNum; // number of setup commands requested once the player is disabled
/* 0x04E */ u8 setupFadeTimer;
/* 0x050 */ ActiveSequenceChannelData channelData[16];
/* 0x250 */ u16 freqScaleChannelFlags;
/* 0x252 */ u16 volChannelFlags;
/* 0x254 */ u16 seqId; // active seqId currently playing. Resets when sequence stops
/* 0x256 */ u16 prevSeqId; // last seqId played on a player. Does not reset when sequence stops
/* 0x258 */ u16 channelPortMask;
/* 0x25C */ u32 startSeqCmd; // This name comes from MM
/* 0x260 */ u8 isWaitingForFonts; // This name comes from MM
} ActiveSequence; // size = 0x264
typedef enum {
/* 0 */ BANK_PLAYER,

View File

@ -74,7 +74,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
{ ACTOR_EN_BUBBLE, "Shabom" },
{ ACTOR_DOOR_SHUTTER, "Shutter Door" },
{ ACTOR_EN_DODOJR, "Baby Dodongo" },
{ ACTOR_EN_BDFIRE, "Empty" },
{ ACTOR_EN_BDFIRE, "King Dodongo's Fire Breath" },
{ ACTOR_EN_BOOM, "Boomerang" },
{ ACTOR_EN_TORCH2, "Dark Link" },
{ ACTOR_EN_BILI, "Biri" },
@ -132,7 +132,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
{ ACTOR_BG_TOKI_HIKARI, "Windows (Temple of Time)" },
{ ACTOR_EN_YUKABYUN, "Flying Floor Tile" },
{ ACTOR_BG_TOKI_SWD, "Master Sword" },
{ ACTOR_EN_FHG_FIRE, "Empty" },
{ ACTOR_EN_FHG_FIRE, "Phantom Ganon's Lighting Attack" },
{ ACTOR_BG_MJIN, "Warp Song Pad" },
{ ACTOR_BG_HIDAN_KOUSI, "Sliding Metal Gate" },
{ ACTOR_DOOR_TOKI, "Door of Time Collision" },
@ -548,6 +548,10 @@ int ActorDB::RetrieveId(const std::string& name) {
return entry->second;
}
int ActorDB::GetEntryCount() {
return db.size();
}
ActorDB::Entry::Entry() {
entry.name = nullptr;
entry.desc = nullptr;

View File

@ -64,6 +64,7 @@ public:
static void AddBuiltInCustomActors();
int GetEntryCount();
private:
Entry& AddEntry(const std::string& name, const std::string& desc, size_t index);
Entry& AddEntry(const std::string& name, const std::string& desc, const ActorInit& init);

View File

@ -8,6 +8,7 @@
#include <array>
#include <bit>
#include <map>
#include <unordered_map>
#include <string>
#include <libultraship/bridge.h>
#include <libultraship/libultraship.h>
@ -24,6 +25,7 @@ extern PlayState* gPlayState;
#include "textures/icon_item_24_static/icon_item_24_static.h"
}
#define DEKUNUTS_FLOWER 10
#define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer"
typedef struct {
@ -107,6 +109,783 @@ void PopulateActorDropdown(int i, std::vector<Actor*>& data) {
}
}
//actors that don't use params at all
static std::vector<u16> noParamsActors = {
ACTOR_ARMS_HOOK,
ACTOR_ARROW_FIRE,
ACTOR_ARROW_ICE,
ACTOR_ARROW_LIGHT,
ACTOR_BG_BOM_GUARD,
ACTOR_BG_DY_YOSEIZO,
ACTOR_BG_GATE_SHUTTER,
ACTOR_BG_GJYO_BRIDGE,
ACTOR_BG_HIDAN_FSLIFT,
ACTOR_BG_HIDAN_RSEKIZOU,
ACTOR_BG_HIDAN_SYOKU,
ACTOR_BG_JYA_GOROIWA,
ACTOR_BG_MIZU_UZU,
ACTOR_BG_MORI_RAKKATENJO,
ACTOR_BG_PUSHBOX,
ACTOR_BG_SPOT01_FUSYA,
ACTOR_BG_SPOT01_IDOHASHIRA,
ACTOR_BG_SPOT01_IDOMIZU,
ACTOR_BG_SPOT01_IDOSOKO,
ACTOR_BG_SPOT11_OASIS,
ACTOR_BG_SPOT15_SAKU,
ACTOR_BG_SPOT18_FUTA,
ACTOR_BG_TOKI_SWD,
ACTOR_BG_TREEMOUTH,
ACTOR_BG_VB_SIMA,
ACTOR_BOSS_DODONGO,
ACTOR_BOSS_FD,
ACTOR_BOSS_GOMA,
ACTOR_DEMO_EXT,
ACTOR_DEMO_SHD,
ACTOR_DEMO_TRE_LGT,
ACTOR_DOOR_TOKI,
ACTOR_EFC_ERUPC,
ACTOR_EN_ANI,
ACTOR_EN_AROW_TRAP,
ACTOR_EN_BIRD,
ACTOR_EN_BLKOBJ,
ACTOR_EN_BOM_BOWL_MAN,
ACTOR_EN_BOM_BOWL_PIT,
ACTOR_EN_BOM_CHU,
ACTOR_EN_BUBBLE,
ACTOR_EN_DIVING_GAME,
ACTOR_EN_DNT_DEMO,
ACTOR_EN_DNT_JIJI,
ACTOR_EN_DS,
ACTOR_EN_DU,
ACTOR_EN_EG,
ACTOR_EN_FU,
ACTOR_EN_GB,
ACTOR_EN_GE3,
ACTOR_EN_GUEST,
ACTOR_EN_HATA,
ACTOR_EN_HORSE_GANON,
ACTOR_EN_HORSE_LINK_CHILD,
ACTOR_EN_HORSE_ZELDA,
ACTOR_EN_HS2,
ACTOR_EN_JS,
ACTOR_EN_KAKASI,
ACTOR_EN_KAKASI3,
ACTOR_EN_MA1,
ACTOR_EN_MA2,
ACTOR_EN_MA3,
ACTOR_EN_MAG,
ACTOR_EN_MK,
ACTOR_EN_MS,
ACTOR_EN_NIW_LADY,
ACTOR_EN_NWC,
ACTOR_EN_OE2,
ACTOR_EN_OKARINA_EFFECT,
ACTOR_EN_RR,
ACTOR_EN_SA,
ACTOR_EN_SCENE_CHANGE,
ACTOR_EN_SKJNEEDLE,
ACTOR_EN_SYATEKI_ITM,
ACTOR_EN_SYATEKI_MAN,
ACTOR_EN_TAKARA_MAN,
ACTOR_EN_TORYO,
ACTOR_EN_VASE,
ACTOR_EN_ZL1,
ACTOR_MAGIC_DARK,
ACTOR_MAGIC_FIRE,
ACTOR_OBJ_DEKUJR,
ACTOR_OCEFF_SPOT,
ACTOR_UNSET_1,
ACTOR_UNSET_3,
ACTOR_UNSET_5,
ACTOR_UNSET_6,
ACTOR_UNSET_17,
ACTOR_UNSET_1A,
ACTOR_UNSET_1F,
ACTOR_UNSET_22,
ACTOR_UNSET_31,
ACTOR_UNSET_36,
ACTOR_UNSET_53,
ACTOR_UNSET_73,
ACTOR_UNSET_74,
ACTOR_UNSET_75,
ACTOR_UNSET_76,
ACTOR_UNSET_78,
ACTOR_UNSET_79,
ACTOR_UNSET_7A,
ACTOR_UNSET_7B,
ACTOR_UNSET_7E,
ACTOR_UNSET_7F,
ACTOR_UNSET_83,
ACTOR_UNSET_A0,
ACTOR_UNSET_B2,
ACTOR_UNSET_CE,
ACTOR_UNSET_D8,
ACTOR_UNSET_EA,
ACTOR_UNSET_EB,
ACTOR_UNSET_F2,
ACTOR_UNSET_F3,
ACTOR_UNSET_FB,
ACTOR_UNSET_109,
ACTOR_UNSET_10D,
ACTOR_UNSET_10E,
ACTOR_UNSET_128,
ACTOR_UNSET_129,
ACTOR_UNSET_134,
ACTOR_UNSET_154,
ACTOR_UNSET_15D,
ACTOR_UNSET_161,
ACTOR_UNSET_180,
ACTOR_UNSET_1AA
};
static std::unordered_map<u16, std::function<s16(s16)>> actorSpecificData;
void CreateActorSpecificData() {
if (!actorSpecificData.empty()) {
return;
}
actorSpecificData[ACTOR_EN_DEKUNUTS] = [](s16 params) -> s16 {
bool isFlower = params == DEKUNUTS_FLOWER;
s16 shotsPerRound = (params >> 8) & 0xFF;
if (shotsPerRound == 0xFF || shotsPerRound == 0) {
shotsPerRound = 1;
}
ImGui::Checkbox("Flower", &isFlower);
if (!isFlower) {
ImGui::InputScalar("Shots Per Round", ImGuiDataType_S16, &shotsPerRound);
}
return isFlower ? DEKUNUTS_FLOWER : (shotsPerRound << 8);
};
actorSpecificData[ACTOR_EN_TITE] = [](s16 params) -> s16 {
static const char* items[] = { "Blue", "Red" };
if (params == 0) {
params = -2;
}
//the + 2 is because the params are -2 & -1 instead of 0 & 1
int selectedItem = params + 2;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 2;
}
return params;
};
actorSpecificData[ACTOR_EN_AM] = [](s16 params) -> s16 {
static const char* items[] = { "Statue", "Enemy" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_BG_ICE_TURARA] = [](s16 params) -> s16 {
static const char* items[] = { "Stalagmite", "Stalactite", "Stalactite (Regrow)" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_BG_BREAKWALL] = [](s16 params) -> s16 {
static const char* items[] = { "DC Entrance", "Wall", "KD Floor", "KD Lava Cover" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_TEST] = [](s16 params) -> s16 {
static const char* items[] = { "Invisible", "1", "2", "Ceiling", "4", "5" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_TANA] = [](s16 params) -> s16 {
static const char* items[] = { "Wooden", "Stone (1)", "Stone (2)" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_XC] = [](s16 params) -> s16 {
static const char* items[] = { "0", "1", "2", "3", "4", "5", "Minuet", "Bolero", "Serenade", "9" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_SHOT_SUN] = [](s16 params) -> s16 {
static const char* items[] = { "Sun's Song", "Song of Storms", "LH Sun" };
if (params == 0) {
params = 0x40;
}
//the - 0x40 is because the params are 0x40 & 0x41 instead of 0 & 1
int selectedItem = params - 0x40;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem + 0x40;
}
return params;
};
actorSpecificData[ACTOR_EN_HONOTRAP] = [](s16 params) -> s16 {
static const char* items[] = { "Eye", "Flame Move", "Flame Drop" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_REEBA] = [](s16 params) -> s16 {
bool isBig = params != 0;
ImGui::Checkbox("Big", &isBig);
return isBig;
};
actorSpecificData[ACTOR_EN_TK] = [](s16 params) -> s16 {
bool canTurn = params >= 0;
ImGui::Checkbox("Can Turn", &canTurn);
return canTurn ? 0 : -1;
};
actorSpecificData[ACTOR_EN_ITEM00] = [](s16 params) -> s16 {
bool autoCollect = params & 0x8000;
ImGui::Checkbox("Automatically Collect", &autoCollect);
u8 collectibleFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Collectible Flag", ImGuiDataType_U8, &collectibleFlag);
if (collectibleFlag > 0x3F) {
collectibleFlag = 0x3F;
}
static const char* items[] = {
"Green Rupee",
"Blue Rupee",
"Red Rupee",
"Recovery Heart",
"Bombs (A)",
"Arrow",
"Heart Piece",
"Heart Container",
"Arrows (5)",
"Arrows (10)",
"Arrows (30)",
"Bombs (B)",
"Deku Nuts (5)",
"Deku Stick",
"Magic (Large)",
"Magic (Small)",
"Deku Seeds (5)",
"Small Key",
"Flexible",
"Gold Rupee",
"Purple Rupee",
"Deku Shield",
"Hylian Shield",
"Zora Tunic",
"Goron Tunic",
"Bombs (Special)",
"Bombchus"
};
int selectedItem = params & 0xFF;
ImGui::Combo("Item", &selectedItem, items, IM_ARRAYSIZE(items));
return autoCollect * 0x8000 + (collectibleFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_OBJ_COMB] = [](s16 params) -> s16 {
static const char* items[] = {
"Green Rupee",
"Blue Rupee",
"Red Rupee",
"Recovery Heart",
"Bombs (A)",
"Arrow",
"Heart Piece",
"Heart Container",
"Arrows (5)",
"Arrows (10)",
"Arrows (30)",
"Bombs (B)",
"Deku Nuts (5)",
"Deku Stick",
"Magic (Large)",
"Magic (Small)",
"Deku Seeds (5)",
"Small Key",
"Flexible",
"Gold Rupee",
"Purple Rupee",
"Deku Shield",
"Hylian Shield",
"Zora Tunic",
"Goron Tunic",
"Bombs (Special)",
"Bombchus"
};
int selectedItem = params & 0xFF;
ImGui::Combo("Item Drop", &selectedItem, items, IM_ARRAYSIZE(items));
u8 collectibleFlag = (params & 0x3F00) >> 8;
if (selectedItem == 6) {
ImGui::InputScalar("PoH Collectible Flag", ImGuiDataType_U8, &collectibleFlag);
if (collectibleFlag > 0x3F) {
collectibleFlag = 0x3F;
}
}
return (collectibleFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_EN_GM] = [](s16 params) -> s16 {
u8 switchFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag);
if (switchFlag > 0x3F) {
switchFlag = 0x3F;
}
return switchFlag << 8;
};
actorSpecificData[ACTOR_EN_GIRLA] = [](s16 params) -> s16 {
static const char* items[] = {
"Deku Nuts (5)",
"Arrows (30)",
"Arrows (50)",
"Bombs (5) (25 Rupees)",
"Deku Nuts (10)",
"Deku Stick",
"Bombs (10)",
"Fish",
"Red Potion (30 Rupees)",
"Green Potion",
"Blue Potion",
"Longsword",
"Hylian Shield",
"Deku Shield",
"Goron Tunic",
"Zora Tunic",
"Heart",
"Milk Bottle",
"Weird Egg",
"19",
"20",
"Bomchu (10) [1]",
"Bomchu (20) [1]",
"Bomchu (20) [2]",
"Bomchu (10) [2]",
"Bomchu (10) [3]",
"Bomchu (20) [3]",
"Bomchu (20) [4]",
"Bomchu (10) [4]",
"Deku Seeds (30)",
"Keaton Mask",
"Spooky Mask",
"Skull Mask",
"Bunny Hood",
"Mask Of Truth",
"Zora Mask",
"Goron Mask",
"Gerudo Mask",
"Sold Out",
"Blue Fire",
"Bugs",
"Big Poe",
"Poe",
"Fairy",
"Arrows (10)",
"Bombs (20)",
"Bombs (30)",
"Bombs (5) (35 Rupees)",
"Red Potion (40 Rupees)",
"Red Potion (50 Rupees)",
"Randomizer Item"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_FIRE_ROCK] = [](s16 params) -> s16 {
static const char* items[] = {
"Spawned Falling (1)",
"Broken Piece (1)",
"Broken Piece (2)",
"Spawned Falling (2)",
//"INVALID",
"Ceiling Spot Spawner",
"On Floor"
};
int selectedItem = params > 3 ? params - 1 : params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem > 3 ? selectedItem + 1 : selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_EX_ITEM] = [](s16 params) -> s16 {
static const char* items[] = {
"Bomb Bag Bowling",
"Heart Piece Bowling",
"Bombchus Bowling",
"Bombs Bowling",
"Purple Rupee Bowling",
"Bomb Bag Counter",
"Heart Piece Counter",
"Bombchus Counter",
"Bombs Counter",
"Purple Rupee Counter",
"Green Rupee Chest",
"Blue Rupee Chest",
"Red Rupee Chest",
"13",
"14",
"Small Key Chest",
"Magic Fire",
"Magic Wind",
"Magic Dark",
"Bullet Bag"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_ELF] = [](s16 params) -> s16 {
static const char* items[] = {
"Navi",
"Revive Bottle",
"Heal Timed",
"Kokiri",
"Spawner",
"Revive Death",
"Heal",
"Heal Big"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_CLEAR_TAG] = [](s16 params) -> s16 {
static const char* items[] = {
"Cutscene", //0
"Normal", //1
"Laser" //100
};
int selectedItem = params == 100 ? 2 : params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem == 2 ? 100 : selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_BOMBF] = [](s16 params) -> s16 {
static const char* items[] = { "Flower", "Body", "Explosion" };
//the + 1 is because the params are -1, 0 & 1 instead of 0, 1 & 2
int selectedItem = params + 1;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 1;
}
return params;
};
actorSpecificData[ACTOR_EN_BOM] = [](s16 params) -> s16 {
static const char* items[] = { "Body", "Explosion" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_DOOR_WARP1] = [](s16 params) -> s16 {
static const char* items[] = {
"Blue Crystal", // -2
"Dungeon Adult",
"Dungeon Child",
"Clear Flag", // Activate on temp clear flag
"Sages", // Used by sages warping into chamber of sages during their cutscene
"Purple Crystal",
"Yellow", // The colored variants don't warp, they are cutscene setpieces
"Blue Ruto",
"Destination", // Spawning in after having taken a warp
"UNK 7",
"Orange",
"Green",
"Red"
};
int selectedItem = params + 2;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 2;
}
return params;
};
actorSpecificData[ACTOR_EN_DY_EXTRA] = [](s16 params) -> s16 {
static const char* items[] = { "Orange", "Green" };
int selectedItem = params;
if (ImGui::Combo("Color", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_SKB] = [](s16 params) -> s16 {
u8 size = params;
ImGui::InputScalar("Size", ImGuiDataType_U8, &size);
return size;
};
actorSpecificData[ACTOR_EN_WF] = [](s16 params) -> s16 {
static const char* items[] = { "Normal", "White" };
int selectedItem = params;
ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items));
u8 switchFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag);
return (switchFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_EN_BOX] = [](s16 params) -> s16 {
/*
trasureFlag = params & 0x1F; //0b0000 0000 0001 1111
itemId = (params >> 5) & 0x7F; //0b0000 1111 1110 0000
type = (params >> 12) & 0xF; //0b1111 0000 0000 0000
*/
u8 treasureFlag = params & 0x1F;
ImGui::InputScalar("Treasure Flag", ImGuiDataType_U8, &treasureFlag);
if (treasureFlag > 0x1F) {
treasureFlag = 0x1F;
}
u8 itemId = (params >> 5) & 0x7F;
ImGui::InputScalar("Item Id", ImGuiDataType_U8, &itemId);
if (itemId > 0x7F) {
itemId = 0x7F;
}
static const char* items[] = {
"Big (Default)",
"Room Clear Big",
"Decorated Big",
"Switch Flag Fall Big",
"4",
"Small",
"6",
"Room Clear Small",
"Switch Flag Fall Small",
"9",
"10",
"Switch Flag Big"
};
int type = (params >> 12) & 0xF;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
if (type > 0xF) {
type = 0xF;
}
return (type << 12) + (itemId << 5) + treasureFlag;
};
actorSpecificData[ACTOR_EN_DOOR] = [](s16 params) -> s16 {
/**
* Actor Parameters
*
* | | | |
* | Transition Index | Type | Double Door | Switch Flag OR Text Id - 0x0200
* |------------------|-------|-------------|---------------------------------
* | 0 0 0 0 0 0 | 0 0 0 | 0 | 0 0 0 0 0 0
* | 6 | 3 | 1 | 6
* |
*
* Transition Index 1111110000000000 Set by the actor engine when the door is spawned
* Type 0000001110000000
* Double Door 0000000001000000
* Switch Flag 0000000000111111 For use with the `DOOR_LOCKED` type
* Text id - 0x0200 0000000000111111 For use with the `DOOR_CHECKABLE` type
*
*/
u8 transitionIndex = params >> 10;
ImGui::InputScalar("Transition Index", ImGuiDataType_U8, &transitionIndex);
if (transitionIndex > 0x3F) {
transitionIndex = 0x3F;
}
static const char* items[] = {
"Room Load", // loads rooms
"Locked", // small key locked door
"Room Load (2)", // loads rooms
"Scene Exit", // doesn't load rooms, used for doors paired with scene transition polygons
"Ajar", // open slightly but slams shut if Link gets too close
"Checkable", // doors that display a textbox when interacting
"Evening", // unlocked between 18:00 and 21:00, Dampé's hut
"Room Load (7)" // loads rooms
};
int type = (params >> 7) & 7;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
if (type > 7) {
type = 7;
}
bool doubleDoor = ((params >> 6) & 1) != 0;
ImGui::Checkbox("Double Door", &doubleDoor);
u8 lowerBits = params & 0x3F;
if (type == 1) {
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &lowerBits);
if (lowerBits > 0x3F) {
lowerBits = 0x3F;
}
} else if (type == 5) {
ImGui::InputScalar("Text ID - 0x200", ImGuiDataType_U8, &lowerBits);
if (lowerBits > 0x3F) {
lowerBits = 0x3F;
}
} else {
lowerBits = 0;
}
return (transitionIndex << 10) + (type << 7) + (doubleDoor << 6) + lowerBits;
};
actorSpecificData[ACTOR_EN_PO_DESERT] = [](s16 params) -> s16 {
u8 switchFlag = params >> 8;
ImGui::InputScalar("Path", ImGuiDataType_U8, &switchFlag);
return switchFlag << 8;
};
actorSpecificData[ACTOR_EN_KANBAN] = [](s16 params) -> s16 {
bool piece = params == (s16)0xFFDD;
bool fishingSign = params == 0x300;
if (ImGui::Checkbox("Piece", &piece)) {
fishingSign = false;
}
if (ImGui::Checkbox("Fishing Sign", &fishingSign)) {
piece = false;
}
u8 textId = params;
if (!piece && !fishingSign) {
if (ImGui::InputScalar("Text ID", ImGuiDataType_U8, &textId)) {
textId |= 0x300;
}
}
return piece ? (s16)0xFFDD : (fishingSign ? 0x300 : textId);
};
actorSpecificData[ACTOR_EN_KUSA] = [](s16 params) -> s16 {
static const char* items[] = {
"0",
"1",
"2"
};
int type = params & 3;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
bool bugs = ((params >> 4) & 1) != 0;
ImGui::Checkbox("Bugs", &bugs);
u8 drop = (params >> 8) & 0xF;
if (type == 2) {
ImGui::InputScalar("Random Drop Params", ImGuiDataType_U8, &drop);
if (drop > 0xD) {
drop = 0xD;
}
} else {
drop = 0;
}
return (drop << 8) + (bugs << 4) + type;
};
actorSpecificData[ActorDB::Instance->RetrieveId("En_Partner")] = [](s16 params) -> s16 {
static const char* items[] = {
"Port 1",
"Port 2",
"Port 3",
"Port 4"
};
int selectedItem = params;
if (ImGui::Combo("Controller Port", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
}
std::vector<u16> GetActorsWithDescriptionContainingString(std::string s) {
std::locale loc;
for (size_t i = 0; i < s.length(); i += 1) {
s[i] = std::tolower(s[i], loc);
}
std::vector<u16> actors;
for (int i = 0; i < ActorDB::Instance->GetEntryCount(); i += 1) {
ActorDB::Entry actorEntry = ActorDB::Instance->RetrieveEntry(i);
std::string desc = actorEntry.desc;
for (size_t j = 0; j < desc.length(); j += 1) {
desc[j] = std::tolower(desc[j], loc);
}
if (desc.find(s) != std::string::npos) {
actors.push_back((u16)i);
}
}
return actors;
}
void ActorViewer_AddTagForActor(Actor* actor) {
int val = CVarGetInteger("gDebugActorViewerNameTags", ACTORVIEWER_NAMETAGS_NONE);
auto entry = ActorDB::Instance->RetrieveEntry(actor->id);
@ -163,6 +942,9 @@ void ActorViewerWindow::DrawElement() {
static std::string filler = "Please select";
static std::vector<Actor*> list;
static u16 lastSceneId = 0;
static char searchString[64] = "";
static s16 currentSelectedInDropdown;
static std::vector<u16> actors;
if (gPlayState != nullptr) {
needs_reset = lastSceneId != gPlayState->sceneNum;
@ -173,6 +955,11 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select";
list.clear();
needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
currentSelectedInDropdown = -1;
actors.clear();
}
lastSceneId = gPlayState->sceneNum;
if (ImGui::BeginCombo("Actor Type", acMapping[category])) {
@ -316,9 +1103,48 @@ void ActorViewerWindow::DrawElement() {
if (ImGui::TreeNode("New...")) {
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
if (ImGui::InputText("Search Actor", searchString, ARRAY_COUNT(searchString))) {
actors = GetActorsWithDescriptionContainingString(std::string(searchString));
currentSelectedInDropdown = -1;
}
if (searchString[0] != 0 && !actors.empty()) {
std::string preview = currentSelectedInDropdown == -1 ? "Please Select" : ActorDB::Instance->RetrieveEntry(actors[currentSelectedInDropdown]).desc;
if (ImGui::BeginCombo("Results", preview.c_str())) {
for (u8 i = 0; i < actors.size(); i++) {
if (ImGui::Selectable(
ActorDB::Instance->RetrieveEntry(actors[i]).desc.c_str(),
i == currentSelectedInDropdown
)) {
currentSelectedInDropdown = i;
newActor.id = actors[i];
}
}
ImGui::EndCombo();
}
}
ImGui::Text("%s", GetActorDescription(newActor.id).c_str());
ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one);
if (ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one)) {
newActor.params = 0;
}
UIWidgets::EnhancementCheckbox("Advanced mode", "gActorViewerAdvancedParams");
UIWidgets::InsertHelpHoverText("Changes the actor specific param menus with a direct input");
if (CVarGetInteger("gActorViewerAdvancedParams", 0)) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
} else if (std::find(noParamsActors.begin(), noParamsActors.end(), newActor.id) == noParamsActors.end()) {
CreateActorSpecificData();
if (actorSpecificData.find(newActor.id) == actorSpecificData.end()) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
} else {
DrawGroupWithBorder([&]() {
ImGui::Text("Actor Specific Data");
newActor.params = actorSpecificData[newActor.id](newActor.params);
});
}
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
@ -401,6 +1227,11 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select";
list.clear();
needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
currentSelectedInDropdown = -1;
actors.clear();
}
}

View File

@ -9,6 +9,7 @@
#include <bit>
#include <map>
#include <string>
#include <regex>
#include <libultraship/libultraship.h>
#include "dlViewer.h"
@ -18,15 +19,13 @@ extern "C" {
#include "variables.h"
#include "functions.h"
#include "macros.h"
extern PlayState* gPlayState;
char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize);
}
char searchString[64] = "";
int displayListsSearchResultsCount;
char** displayListsSearchResults;
char* activeDisplayList = nullptr;
std::string activeDisplayList = "";
std::vector<std::string> displayListSearchResults;
int16_t searchDebounceFrames = -1;
bool doSearch = false;
std::map<int, std::string> cmdMap = {
{ G_SETPRIMCOLOR, "gsDPSetPrimColor" },
@ -36,8 +35,63 @@ std::map<int, std::string> cmdMap = {
{ G_SETINTENSITY, "gsDPSetGrayscaleColor" },
{ G_LOADTLUT, "gsDPLoadTLUT" },
{ G_ENDDL, "gsSPEndDisplayList" },
{ G_TEXTURE, "gsSPTexture" },
{ G_SETTIMG, "gsDPSetTextureImage" },
{ G_SETTIMG_OTR_HASH, "gsDPSetTextureImage" },
{ G_SETTIMG_OTR_FILEPATH, "gsDPSetTextureImage" },
{ G_RDPTILESYNC, "gsDPTileSync" },
{ G_SETTILE, "gsDPSetTile" },
{ G_RDPLOADSYNC, "gsDPLoadSync" },
{ G_LOADBLOCK, "gsDPLoadBlock" },
{ G_SETTILESIZE, "gsDPSetTileSize" },
{ G_DL, "gsSPDisplayList" },
{ G_DL_OTR_FILEPATH, "gsSPDisplayList" },
{ G_DL_OTR_HASH, "gsSPDisplayList" },
{ G_MTX, "gsSPMatrix" },
{ G_MTX_OTR, "gsSPMatrix" },
{ G_VTX, "gsSPVertex" },
{ G_VTX_OTR_FILEPATH, "gsSPVertex" },
{ G_VTX_OTR_HASH, "gsSPVertex" },
{ G_GEOMETRYMODE, "gsSPSetGeometryMode" },
{ G_SETOTHERMODE_H, "gsSPSetOtherMode_H" },
{ G_SETOTHERMODE_L, "gsSPSetOtherMode_L" },
{ G_TRI1, "gsSP1Triangle" },
{ G_TRI1_OTR, "gsSP1Triangle" },
{ G_TRI2, "gsSP2Triangles" },
{ G_SETCOMBINE, "gsDPSetCombineLERP" },
{ G_CULLDL, "gsSPCullDisplayList" },
{ G_NOOP, "gsDPNoOp" },
{ G_SPNOOP, "gsSPNoOp" },
{ G_MARKER, "LUS Custom Marker" },
};
void PerformDisplayListSearch() {
auto result = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles("*" + std::string(searchString) + "*DL*");
std::regex dlSearch(".*((DL)|(DL_.*))$");
displayListSearchResults.clear();
// Filter the file results even further as StormLib can only use wildcard searching
for (size_t i = 0; i < result->size(); i++) {
std::string val = result->at(i);
if (std::regex_search(val.c_str(), dlSearch)) {
displayListSearchResults.push_back(val);
}
}
// Sort the final list
std::sort(displayListSearchResults.begin(), displayListSearchResults.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(
a.begin(), a.end(),
b.begin(), b.end(),
[](char c1, char c2) {
return std::tolower(c1) < std::tolower(c2);
}
);
});
}
void DLViewerWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Display List Viewer", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
@ -45,22 +99,50 @@ void DLViewerWindow::DrawElement() {
return;
}
ImGui::Text("%d", searchDebounceFrames);
// Debounce the search field as listing otr files is expensive
if (ImGui::InputText("Search Display Lists", searchString, ARRAY_COUNT(searchString))) {
displayListsSearchResults = ResourceMgr_ListFiles(("*" + std::string(searchString) + "*DL").c_str(), &displayListsSearchResultsCount);
doSearch = true;
searchDebounceFrames = 30;
}
if (ImGui::BeginCombo("Active Display List", activeDisplayList)) {
for (int i = 0; i < displayListsSearchResultsCount; i++) {
if (ImGui::Selectable(displayListsSearchResults[i])) {
activeDisplayList = displayListsSearchResults[i];
if (doSearch) {
if (searchDebounceFrames == 0) {
doSearch = false;
PerformDisplayListSearch();
}
searchDebounceFrames--;
}
if (ImGui::BeginCombo("Active Display List", activeDisplayList.c_str())) {
for (size_t i = 0; i < displayListSearchResults.size(); i++) {
if (ImGui::Selectable(displayListSearchResults[i].c_str())) {
activeDisplayList = displayListSearchResults[i];
break;
}
}
ImGui::EndCombo();
}
if (activeDisplayList != nullptr) {
if (activeDisplayList == "") {
ImGui::End();
return;
}
try {
auto res = std::static_pointer_cast<LUS::DisplayList>(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(activeDisplayList));
for (int i = 0; i < res->Instructions.size(); i++) {
if (res->GetInitData()->Type != LUS::ResourceType::DisplayList) {
ImGui::Text("Resource type is not a Display List. Please choose another.");
ImGui::End();
return;
}
ImGui::Text("Total Instruction Size: %lu", res->Instructions.size());
for (size_t i = 0; i < res->Instructions.size(); i++) {
std::string id = "##CMD" + std::to_string(i);
Gfx* gfx = (Gfx*)&res->Instructions[i];
int cmd = gfx->words.w0 >> 24;
@ -70,10 +152,11 @@ void DLViewerWindow::DrawElement() {
ImGui::BeginGroup();
ImGui::PushItemWidth(25.0f);
ImGui::Text("%d", i);
ImGui::Text("%lu", i);
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::PushItemWidth(150.0f);
ImGui::PushItemWidth(175.0f);
if (ImGui::BeginCombo(("CMD" + id).c_str(), cmdLabel.c_str())) {
if (ImGui::Selectable("gsDPSetPrimColor") && cmd != G_SETPRIMCOLOR) {
*gfx = gsDPSetPrimColor(0, 0, 0, 0, 0, 255);
@ -92,8 +175,10 @@ void DLViewerWindow::DrawElement() {
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
if (gfx->words.w0 >> 24 == G_SETPRIMCOLOR || gfx->words.w0 >> 24 == G_SETINTENSITY || gfx->words.w0 >> 24 == G_SETENVCOLOR) {
if (cmd == G_SETPRIMCOLOR || cmd == G_SETINTENSITY || cmd == G_SETENVCOLOR) {
uint8_t r = _SHIFTR(gfx->words.w1, 24, 8);
uint8_t g = _SHIFTR(gfx->words.w1, 16, 8);
uint8_t b = _SHIFTR(gfx->words.w1, 8, 8);
@ -117,21 +202,141 @@ void DLViewerWindow::DrawElement() {
}
ImGui::PopItemWidth();
}
if (gfx->words.w0 >> 24 == G_RDPPIPESYNC) {
if (cmd == G_RDPPIPESYNC) {
}
if (gfx->words.w0 >> 24 == G_SETGRAYSCALE) {
if (cmd == G_SETGRAYSCALE) {
bool* state = (bool*)&gfx->words.w1;
ImGui::SameLine();
if (ImGui::Checkbox(("state" + id).c_str(), state)) {
//
}
}
if (cmd == G_SETTILE) {
ImGui::SameLine();
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
ImGui::SameLine();
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
ImGui::SameLine();
ImGui::Text("LINE: %u", _SHIFTR(gfx->words.w0, 9, 9));
ImGui::SameLine();
ImGui::Text("TMEM: %u", _SHIFTR(gfx->words.w0, 0, 9));
ImGui::SameLine();
ImGui::Text("TILE: %u", _SHIFTR(gfx->words.w1, 24, 3));
ImGui::SameLine();
ImGui::Text("PAL: %u", _SHIFTR(gfx->words.w1, 20, 4));
ImGui::SameLine();
ImGui::Text("CMT: %u", _SHIFTR(gfx->words.w1, 18, 2));
ImGui::SameLine();
ImGui::Text("MASKT: %u", _SHIFTR(gfx->words.w1, 14, 4));
ImGui::SameLine();
ImGui::Text("SHIFT: %u", _SHIFTR(gfx->words.w1, 10, 4));
ImGui::SameLine();
ImGui::Text("CMS: %u", _SHIFTR(gfx->words.w1, 8, 2));
ImGui::SameLine();
ImGui::Text("MASKS: %u", _SHIFTR(gfx->words.w1, 4, 4));
ImGui::SameLine();
ImGui::Text("SHIFTS: %u", _SHIFTR(gfx->words.w1, 0, 4));
}
if (cmd == G_SETTIMG) {
ImGui::SameLine();
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
ImGui::SameLine();
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
ImGui::SameLine();
ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10));
ImGui::SameLine();
}
if (cmd == G_SETTIMG_OTR_HASH) {
gfx++;
uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1;
const char* fileName = ResourceGetNameByCrc(hash);
gfx--;
ImGui::SameLine();
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
ImGui::SameLine();
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
ImGui::SameLine();
ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10));
ImGui::SameLine();
ImGui::Text("Texture Name: %s", fileName);
}
if (cmd == G_SETTIMG_OTR_FILEPATH) {
char* fileName = (char*)gfx->words.w1;
gfx++;
ImGui::SameLine();
ImGui::Text("FMT: %u", _SHIFTR(gfx->words.w0, 21, 3));
ImGui::SameLine();
ImGui::Text("SIZ: %u", _SHIFTR(gfx->words.w0, 19, 2));
ImGui::SameLine();
ImGui::Text("WIDTH: %u", _SHIFTR(gfx->words.w0, 0, 10));
ImGui::SameLine();
ImGui::Text("Texture Name: %s", fileName);
}
if (cmd == G_VTX) {
ImGui::SameLine();
ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8));
ImGui::SameLine();
ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8));
}
if (cmd == G_VTX_OTR_HASH) {
gfx++;
uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1;
const char* fileName = ResourceGetNameByCrc(hash);
gfx--;
ImGui::SameLine();
ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8));
ImGui::SameLine();
ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8));
ImGui::SameLine();
ImGui::Text("Vertex Name: %s", fileName);
}
if (cmd == G_VTX_OTR_FILEPATH) {
char* fileName = (char*)gfx->words.w1;
gfx++;
ImGui::SameLine();
ImGui::Text("Num VTX: %u", _SHIFTR(gfx->words.w0, 12, 8));
ImGui::SameLine();
ImGui::Text("Offset: %u", _SHIFTR(gfx->words.w0, 1, 7) - _SHIFTR(gfx->words.w0, 12, 8));
ImGui::SameLine();
ImGui::Text("Vertex Name: %s", fileName);
}
if (cmd == G_DL) {
}
if (cmd == G_DL_OTR_HASH) {
gfx++;
uint64_t hash = ((uint64_t)gfx->words.w0 << 32) + (uint64_t)gfx->words.w1;
const char* fileName = ResourceGetNameByCrc(hash);
ImGui::SameLine();
ImGui::Text("DL Name: %s", fileName);
}
if (cmd == G_DL_OTR_FILEPATH) {
char* fileName = (char*)gfx->words.w1;
ImGui::SameLine();
ImGui::Text("DL Name: %s", fileName);
}
// Skip second half of instructions that are over 128-bit wide
if (cmd == G_SETTIMG_OTR_HASH || cmd == G_DL_OTR_HASH || cmd == G_VTX_OTR_HASH ||
cmd == G_BRANCH_Z_OTR || cmd == G_MARKER || cmd == G_MTX_OTR) {
i++;
ImGui::Text("%lu - Reserved - Second half of %s", i, cmdLabel.c_str());
}
ImGui::EndGroup();
}
} catch (const std::exception& e) {
ImGui::Text("Error displaying DL instructions.");
ImGui::End();
return;
}
ImGui::End();
}
void DLViewerWindow::InitElement() {
displayListsSearchResults = ResourceMgr_ListFiles("*DL", &displayListsSearchResultsCount);
PerformDisplayListSearch();
}

View File

@ -26,16 +26,30 @@
extern "C" {
#include <z64.h>
#include "align_asset_macro.h"
#include "macros.h"
#include "functions.h"
#include "variables.h"
#include "functions.h"
void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction);
void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
extern void Overlay_DisplayText(float duration, const char* text);
uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
}
// GreyScaleEndDlist
#define dgEndGrayscaleAndEndDlistDL "__OTR__helpers/cosmetics/gEndGrayscaleAndEndDlistDL"
static const ALIGN_ASSET(2) char gEndGrayscaleAndEndDlistDL[] = dgEndGrayscaleAndEndDlistDL;
// This is used for the Temple of Time Medalions' color
#define dtokinoma_room_0DL_007A70 "__OTR__scenes/shared/tokinoma_scene/tokinoma_room_0DL_007A70"
static const ALIGN_ASSET(2) char tokinoma_room_0DL_007A70[] = dtokinoma_room_0DL_007A70;
#define dtokinoma_room_0DL_007FD0 "__OTR__scenes/shared/tokinoma_scene/tokinoma_room_0DL_007FD0"
static const ALIGN_ASSET(2) char tokinoma_room_0DL_007FD0[] = dtokinoma_room_0DL_007FD0;
// TODO: When there's more uses of something like this, create a new GI::RawAction?
void ReloadSceneTogglingLinkAge() {
gPlayState->nextEntranceIndex = gSaveContext.entranceIndex;
@ -400,6 +414,52 @@ void RegisterShadowTag() {
});
}
static bool hasAffectedHealth = false;
void UpdatePermanentHeartLossState() {
if (!GameInteractor::IsSaveLoaded()) return;
if (!CVarGetInteger("gPermanentHeartLoss", 0) && hasAffectedHealth) {
uint8_t heartContainers = gSaveContext.sohStats.heartContainers; // each worth 16 health
uint8_t heartPieces = gSaveContext.sohStats.heartPieces; // each worth 4 health, but only in groups of 4
uint8_t startingHealth = 16 * 3;
uint8_t newCapacity = startingHealth + (heartContainers * 16) + ((heartPieces - (heartPieces % 4)) * 4);
gSaveContext.healthCapacity = MAX(newCapacity, gSaveContext.healthCapacity);
gSaveContext.health = MIN(gSaveContext.health, gSaveContext.healthCapacity);
hasAffectedHealth = false;
}
}
void RegisterPermanentHeartLoss() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>([](int16_t fileNum) {
hasAffectedHealth = false;
UpdatePermanentHeartLossState();
});
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayerUpdate>([]() {
if (!CVarGetInteger("gPermanentHeartLoss", 0) || !GameInteractor::IsSaveLoaded()) return;
if (gSaveContext.healthCapacity > 16 && gSaveContext.healthCapacity - gSaveContext.health >= 16) {
gSaveContext.healthCapacity -= 16;
gSaveContext.health = MIN(gSaveContext.health, gSaveContext.healthCapacity);
hasAffectedHealth = true;
}
});
};
void RegisterDeleteFileOnDeath() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
if (!CVarGetInteger("gDeleteFileOnDeath", 0) || !GameInteractor::IsSaveLoaded() || &gPlayState->gameOverCtx == NULL || &gPlayState->pauseCtx == NULL) return;
if (gPlayState->gameOverCtx.state == GAMEOVER_DEATH_MENU && gPlayState->pauseCtx.state == 9) {
SaveManager::Instance->DeleteZeldaFile(gSaveContext.fileNum);
hasAffectedHealth = false;
std::reinterpret_pointer_cast<LUS::ConsoleWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->Dispatch("reset");
}
});
}
struct DayTimeGoldSkulltulas {
uint16_t scene;
uint16_t room;
@ -1126,6 +1186,102 @@ void RegisterRandomizedEnemySizes() {
}
Actor_SetScale(actor, actor->scale.z * randomScale);
if (CVarGetInteger("gEnemySizeScalesHealth", 0) && (actor->category == ACTORCAT_ENEMY)) {
// Scale the health based on a smaller factor than randomScale
float healthScalingFactor = 0.8f; // Adjust this factor as needed
float scaledHealth = actor->colChkInfo.health * (randomScale * healthScalingFactor);
// Ensure the scaled health doesn't go below zero
actor->colChkInfo.health = fmax(scaledHealth, 1.0f);
} else {
return;
}
});
}
void PatchToTMedallions() {
// TODO: Refactor the DemoEffect_UpdateJewelAdult and DemoEffect_UpdateJewelChild from z_demo_effect
// effects to take effect in there
if (CVarGetInteger("gToTMedallionsColors", 0)) {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_StartGrayscale", 7, gsSPGrayscale(true));
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_StartGrayscale", 7, gsSPGrayscale(true));
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER)) {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeBlue", 16, gsDPSetGrayscaleColor(0, 161, 255, 255));
} else {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeBlue", 16, gsDPSetGrayscaleColor(255, 255, 255, 255));
}
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT)) {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeOrange", 45, gsDPSetGrayscaleColor(255, 135, 0, 255));
} else {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeOrange", 45, gsDPSetGrayscaleColor(255, 255, 255, 255));
}
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_LIGHT)) {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeYellow", 69, gsDPSetGrayscaleColor(255, 255, 0, 255));
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakeYellow", 16, gsDPSetGrayscaleColor(255, 255, 0, 255));
} else {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeYellow", 69, gsDPSetGrayscaleColor(255, 255, 255, 255));
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakeYellow", 16, gsDPSetGrayscaleColor(255, 255, 255, 255));
}
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST)) {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeGreen", 94, gsDPSetGrayscaleColor(0, 255, 0, 255));
} else {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeGreen", 94, gsDPSetGrayscaleColor(255, 255, 255, 255));
}
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE)) {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeRed", 118, gsDPSetGrayscaleColor(255, 0, 0, 255));
} else {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeRed", 118, gsDPSetGrayscaleColor(255, 255, 255, 255));
}
if (CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW)) {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakePurple", 142, gsDPSetGrayscaleColor(212, 0, 255, 255));
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakePurple", 27, gsDPSetGrayscaleColor(212, 0, 255, 255));
} else {
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakePurple", 142, gsDPSetGrayscaleColor(255, 255, 255, 255));
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakePurple", 27, gsDPSetGrayscaleColor(255, 255, 255, 255));
}
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_EndGrayscaleAndEndDlist", 160, gsSPBranchListOTRFilePath(gEndGrayscaleAndEndDlistDL));
ResourceMgr_PatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_EndGrayscaleAndEndDlist", 51, gsSPBranchListOTRFilePath(gEndGrayscaleAndEndDlistDL));
} else {
// Unpatch everything
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_StartGrayscale");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_StartGrayscale");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeBlue");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeOrange");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeYellow");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakeYellow");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakeRed");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_MakePurple");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_MakePurple");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007A70, "ToTMedallions_EndGrayscaleAndEndDlist");
ResourceMgr_UnpatchGfxByName(tokinoma_room_0DL_007FD0, "ToTMedallions_2_EndGrayscaleAndEndDlist");
}
}
void RegisterToTMedallionsFromItem() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>([](GetItemEntry _unused) {
if (!CVarGetInteger("gToTMedallionsColors", 0) && gPlayState->sceneNum != SCENE_TEMPLE_OF_TIME) {
return;
}
PatchToTMedallions();
});
}
void RegisterToTMedallionsFromScene() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
if (!CVarGetInteger("gToTMedallionsColors", 0) && gPlayState->sceneNum != SCENE_TEMPLE_OF_TIME) {
return;
}
PatchToTMedallions();
});
}
@ -1147,6 +1303,8 @@ void InitMods() {
RegisterDaytimeGoldSkultullas();
RegisterRupeeDash();
RegisterShadowTag();
RegisterPermanentHeartLoss();
RegisterDeleteFileOnDeath();
RegisterHyperBosses();
RegisterHyperEnemies();
RegisterBonkDamage();
@ -1159,5 +1317,7 @@ void InitMods() {
RegisterRandomizerSheikSpawn();
RegisterBossSouls();
RegisterRandomizedEnemySizes();
RegisterToTMedallionsFromItem();
RegisterToTMedallionsFromScene();
NameTag_RegisterHooks();
}

View File

@ -9,6 +9,8 @@ extern "C" {
void UpdateDirtPathFixState(int32_t sceneNum);
void UpdateMirrorModeState(int32_t sceneNum);
void PatchToTMedallions();
void UpdatePermanentHeartLossState();
void InitMods();
#ifdef __cplusplus

View File

@ -243,6 +243,7 @@ const std::vector<const char*> enhancementsCvars = {
"gAddTraps.Speed",
"gAddTraps.Tele",
"gAddTraps.Void",
"gToTMedallionsColors",
};
const std::vector<const char*> cheatCvars = {
@ -791,6 +792,9 @@ const std::vector<PresetEntry> randomizerPresetEntries = {
// Chest size & texture matches contents
PRESET_ENTRY_S32("gChestSizeAndTextureMatchesContents", CSMC_BOTH),
// Color Temple of Time's Medallions
PRESET_ENTRY_S32("gToTMedallionsColors", 1),
// Pause link animation (0 to 16)
PRESET_ENTRY_S32("gPauseLiveLink", 16),
// Frames to wait

View File

@ -64,7 +64,7 @@ typedef struct SaveStateInfo {
int16_t blueWarpTimerCopy; /* From door_warp_1 */
SeqScriptState seqScriptStateCopy[4];// Unrelocated
unk_D_8016E750 unk_D_8016E750Copy[4];
ActiveSequence gActiveSeqsCopy[4];
ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK];
uint8_t gSoundBankMutedCopy[7];
@ -905,7 +905,7 @@ void SaveState::Save(void) {
memcpy(&info->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */);
memcpy(&info->audioContextCopy, &gAudioContext, sizeof(AudioContext));
memcpy(&info->unk_D_8016E750Copy, D_8016E750, sizeof(info->unk_D_8016E750Copy));
memcpy(&info->gActiveSeqsCopy, gActiveSeqs, sizeof(info->gActiveSeqsCopy));
BackupSeqScriptState();
memcpy(info->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds));
@ -944,7 +944,7 @@ void SaveState::Load(void) {
memcpy(gAudioHeap, &info->audioHeapCopy, AUDIO_HEAP_SIZE);
memcpy(&gAudioContext, &info->audioContextCopy, sizeof(AudioContext));
memcpy(D_8016E750, &info->unk_D_8016E750Copy, sizeof(info->unk_D_8016E750Copy));
memcpy(gActiveSeqs, &info->gActiveSeqsCopy, sizeof(info->gActiveSeqsCopy));
LoadSeqScriptState();
memcpy(&gSaveContext, &info->saveContextCopy, sizeof(gSaveContext));

View File

@ -660,6 +660,14 @@ void DrawEnhancementsMenu() {
if (ImGui::BeginMenu("Difficulty Options"))
{
UIWidgets::PaddedEnhancementCheckbox("Delete File On Death", "gDeleteFileOnDeath", true, false);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
UIWidgets::Tooltip("Dying will delete your file\n\n " ICON_FA_EXCLAMATION_TRIANGLE " WARNING " ICON_FA_EXCLAMATION_TRIANGLE "\nTHIS IS NOT REVERSABLE\nUSE AT YOUR OWN RISK!");
ImGui::PopStyleColor();
if (UIWidgets::PaddedEnhancementCheckbox("Permanent heart loss", "gPermanentHeartLoss", true, false)) {
UpdatePermanentHeartLossState();
}
UIWidgets::Tooltip("When you lose 4 quarters of a heart you will permanently lose that heart container.\n\nDisabling this after the fact will restore your heart containers.");
ImGui::Text("Damage Multiplier");
UIWidgets::EnhancementCombobox("gDamageMul", allPowers, 0);
UIWidgets::Tooltip(
@ -725,6 +733,8 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("Always win the heart piece/purple rupee on the first dig in Dampe's grave digging game, just like in rando\nIn a rando file, this is unconditionally enabled");
UIWidgets::PaddedEnhancementCheckbox("All Dogs are Richard", "gAllDogsRichard", true, false);
UIWidgets::Tooltip("All dogs can be traded in and will count as Richard.");
UIWidgets::PaddedEnhancementSliderInt("Cuccos Stay Put Multiplier: %dx", "##CuccoStayDurationMultiplier", "gCuccoStayDurationMultiplier", 1, 5, "", 1, true, true, false);
UIWidgets::Tooltip("Cuccos will stay in place longer after putting them down, by a multiple of the value of the slider.");
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Potion Values"))
@ -986,6 +996,10 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("Always shows dungeon entrance icons on the minimap");
UIWidgets::PaddedEnhancementCheckbox("Show Gauntlets in First Person", "gFPSGauntlets", true, false);
UIWidgets::Tooltip("Renders Gauntlets when using the Bow and Hookshot like in OOT3D");
if (UIWidgets::PaddedEnhancementCheckbox("Color Temple of Time's Medallions", "gToTMedallionsColors", true, false)) {
PatchToTMedallions();
}
UIWidgets::Tooltip("When medallions are collected, the medallion imprints around the Master Sword pedestal in the Temple of Time will become colored");
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Animated Link in Pause Menu")) {
ImGui::Text("Rotation");
@ -1168,6 +1182,11 @@ void DrawEnhancementsMenu() {
UIWidgets::PaddedEnhancementCheckbox("Randomized Enemy Sizes", "gRandomizedEnemySizes", true, false);
UIWidgets::Tooltip("Enemies and Bosses spawn with random sizes.");
if (CVarGetInteger("gRandomizedEnemySizes", 0)) {
UIWidgets::EnhancementCheckbox("Scale Health with Size", "gEnemySizeScalesHealth");
UIWidgets::Tooltip("Scales normal enemies health with their randomized size. *This will NOT affect bosses*");
}
UIWidgets::PaddedEnhancementCheckbox("Ivan the Fairy (Coop Mode)", "gIvanCoopModeEnabled", true, false);
UIWidgets::Tooltip("Enables Ivan the Fairy upon the next map change. Player 2 can control Ivan and "
"press the C-Buttons to use items and mess with Player 1!");
@ -1475,6 +1494,26 @@ void DrawDeveloperToolsMenu() {
UIWidgets::Tooltip("Optimized debug warp screen, with the added ability to chose entrances and time of day");
UIWidgets::PaddedEnhancementCheckbox("Debug Warp Screen Translation", "gDebugWarpScreenTranslation", true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Translate the Debug Warp Screen based on the game language");
if (gPlayState != NULL) {
UIWidgets::PaddedSeparator();
ImGui::Checkbox("Frame Advance##frameAdvance", (bool*)&gPlayState->frameAdvCtx.enabled);
if (gPlayState->frameAdvCtx.enabled) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f));
if (ImGui::Button("Advance 1", ImVec2(ImGui::GetContentRegionAvail().x / 2.0f, 0.0f))) {
CVarSetInteger("gFrameAdvance", 1);
}
ImGui::SameLine();
ImGui::Button("Advance (Hold)");
if (ImGui::IsItemActive()) {
CVarSetInteger("gFrameAdvance", 1);
}
ImGui::PopStyleVar(3);
ImGui::PopStyleColor(1);
}
}
UIWidgets::PaddedSeparator();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0,0));

View File

@ -4735,7 +4735,7 @@ void Audio_SetSequenceMode(u8 seqMode) {
seqMode = SEQ_MODE_IGNORE;
}
seqId = D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254;
seqId = gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId;
if (seqId == NA_BGM_FIELD_LOGIC && func_800FA0B4(SEQ_PLAYER_BGM_SUB) == (NA_BGM_ENEMY | 0x800)) {
seqMode = SEQ_MODE_IGNORE;
@ -4746,10 +4746,10 @@ void Audio_SetSequenceMode(u8 seqMode) {
if (seqMode != (sPrevSeqMode & 0x7F)) {
if (seqMode == SEQ_MODE_ENEMY) {
// Start playing enemy bgm
if (D_8016E750[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol < 0) {
volumeFadeInTimer = -(D_8016E750[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol);
if (gActiveSeqs[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol < 0) {
volumeFadeInTimer = -(gActiveSeqs[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol);
} else {
volumeFadeInTimer = D_8016E750[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol;
volumeFadeInTimer = gActiveSeqs[SEQ_PLAYER_BGM_SUB].volScales[1] - sAudioEnemyVol;
}
Audio_SetVolScale(SEQ_PLAYER_BGM_SUB, 3, sAudioEnemyVol, volumeFadeInTimer);
@ -4812,11 +4812,11 @@ void Audio_SetBgmEnemyVolume(f32 dist) {
sAudioEnemyVol = ((350.0f - adjDist) * 127.0f) / 350.0f;
Audio_SetVolScale(SEQ_PLAYER_BGM_SUB, 3, sAudioEnemyVol, 10);
if (D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 != NA_BGM_NATURE_AMBIENCE) {
if (gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId != NA_BGM_NATURE_AMBIENCE) {
Audio_SetVolScale(SEQ_PLAYER_BGM_MAIN, 3, (0x7F - sAudioEnemyVol), 10);
}
}
if (D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 != NA_BGM_NATURE_AMBIENCE) {
if (gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId != NA_BGM_NATURE_AMBIENCE) {
Audio_SplitBgmChannels(sAudioEnemyVol);
}
}
@ -4973,7 +4973,7 @@ void Audio_SetExtraFilter(u8 filter) {
sAudioExtraFilter2 = filter;
sAudioExtraFilter = filter;
if (D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 == NA_BGM_NATURE_AMBIENCE) {
if (gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId == NA_BGM_NATURE_AMBIENCE) {
for (i = 0; i < 16; i++) {
t = i;
// CHAN_UPD_SCRIPT_IO (seq player 0, all channels, slot 6)
@ -5097,7 +5097,7 @@ void Audio_SetNatureAmbienceChannelIO(u8 channelIdxRange, u8 port, u8 val) {
u8 lastChannelIdx;
u8 channelIdx;
if ((D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 != NA_BGM_NATURE_AMBIENCE) && func_800FA11C(1, 0xF00000FF)) {
if ((gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId != NA_BGM_NATURE_AMBIENCE) && func_800FA11C(1, 0xF00000FF)) {
sAudioNatureFailed = true;
return;
}
@ -5159,8 +5159,8 @@ void Audio_PlayNatureAmbienceSequence(u8 natureAmbienceId) {
u8 port;
u8 val;
if ((D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254 == NA_BGM_DISABLED) ||
!(sSeqFlags[((u8)D_8016E750[SEQ_PLAYER_BGM_MAIN].unk_254) & 0xFF] & 0x80)) {
if ((gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId == NA_BGM_DISABLED) ||
!(sSeqFlags[((u8)gActiveSeqs[SEQ_PLAYER_BGM_MAIN].seqId) & 0xFF] & 0x80)) {
Audio_StartNatureAmbienceSequence(sNatureAmbienceDataIO[natureAmbienceId].playerIO,
sNatureAmbienceDataIO[natureAmbienceId].channelMask);
@ -5202,12 +5202,12 @@ void func_800F71BC(s32 arg0) {
func_800F6C34();
func_800EE930();
Audio_ResetSfxChannelState();
func_800FADF8();
Audio_ResetActiveSequences();
Audio_ResetSounds();
}
void func_800F7208(void) {
func_800FADF8();
Audio_ResetActiveSequences();
Audio_QueueCmdS32(0xF2000000, 1);
func_800F6C34();
Audio_ResetSfxChannelState();

View File

@ -12,9 +12,9 @@ typedef struct {
#define GET_PLAYER_IDX(cmd) (cmd & 0xF000000) >> 24
Struct_8016E320 D_8016E320[4][5];
u8 D_8016E348[4];
u8 sNumSeqRequests[4];
u32 sAudioSeqCmds[0x100];
unk_D_8016E750 D_8016E750[4];
ActiveSequence gActiveSeqs[4];
u8 sSeqCmdWrPos = 0;
u8 sSeqCmdRdPos = 0;
@ -51,33 +51,33 @@ void func_800F9280(u8 playerIdx, u8 seqId, u8 arg2, u16 fadeTimer) {
(fadeTimer * (u16)gAudioContext.audioBufferParameters.updatesPerFrame) / 4);
}
D_8016E750[playerIdx].unk_254 = seqId | (arg2 << 8);
D_8016E750[playerIdx].unk_256 = seqId | (arg2 << 8);
gActiveSeqs[playerIdx].seqId = seqId | (arg2 << 8);
gActiveSeqs[playerIdx].prevSeqId = seqId | (arg2 << 8);
if (D_8016E750[playerIdx].volCur != 1.0f) {
Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), D_8016E750[playerIdx].volCur);
if (gActiveSeqs[playerIdx].volCur != 1.0f) {
Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), gActiveSeqs[playerIdx].volCur);
}
D_8016E750[playerIdx].unk_28 = 0;
D_8016E750[playerIdx].unk_18 = 0;
D_8016E750[playerIdx].unk_14 = 0;
gActiveSeqs[playerIdx].tempoTimer = 0;
gActiveSeqs[playerIdx].tempoOriginal = 0;
gActiveSeqs[playerIdx].tempoCmd = 0;
for (i = 0; i < 0x10; i++) {
D_8016E750[playerIdx].unk_50[i].unk_00 = 1.0f;
D_8016E750[playerIdx].unk_50[i].unk_0C = 0;
D_8016E750[playerIdx].unk_50[i].unk_10 = 1.0f;
D_8016E750[playerIdx].unk_50[i].unk_1C = 0;
gActiveSeqs[playerIdx].channelData[i].volCur = 1.0f;
gActiveSeqs[playerIdx].channelData[i].volTimer = 0;
gActiveSeqs[playerIdx].channelData[i].freqScaleCur = 1.0f;
gActiveSeqs[playerIdx].channelData[i].freqScaleTimer = 0;
}
D_8016E750[playerIdx].unk_250 = 0;
D_8016E750[playerIdx].unk_252 = 0;
gActiveSeqs[playerIdx].freqScaleChannelFlags = 0;
gActiveSeqs[playerIdx].volChannelFlags = 0;
}
}
void func_800F9474(u8 playerIdx, u16 arg1) {
Audio_QueueCmdS32(0x83000000 | ((u8)playerIdx << 16),
(arg1 * (u16)gAudioContext.audioBufferParameters.updatesPerFrame) / 4);
D_8016E750[playerIdx].unk_254 = NA_BGM_DISABLED;
gActiveSeqs[playerIdx].seqId = NA_BGM_DISABLED;
}
typedef enum {
@ -133,7 +133,7 @@ void Audio_ProcessSeqCmd(u32 cmd) {
seqId = cmd & 0xFF;
seqArgs = (cmd & 0xFF00) >> 8;
fadeTimer = (cmd & 0xFF0000) >> 13;
if ((D_8016E750[playerIdx].unk_260 == 0) && (seqArgs < 0x80)) {
if ((gActiveSeqs[playerIdx].isWaitingForFonts == 0) && (seqArgs < 0x80)) {
func_800F9280(playerIdx, seqId, seqArgs, fadeTimer);
}
break;
@ -150,7 +150,7 @@ void Audio_ProcessSeqCmd(u32 cmd) {
seqArgs = (cmd & 0xFF00) >> 8;
fadeTimer = (cmd & 0xFF0000) >> 13;
new_var = seqArgs;
for (i = 0; i < D_8016E348[playerIdx]; i++) {
for (i = 0; i < sNumSeqRequests[playerIdx]; i++) {
if (D_8016E320[playerIdx][i].unk_0 == seqId) {
if (i == 0) {
func_800F9280(playerIdx, seqId, seqArgs, fadeTimer);
@ -159,18 +159,18 @@ void Audio_ProcessSeqCmd(u32 cmd) {
}
}
found = D_8016E348[playerIdx];
for (i = 0; i < D_8016E348[playerIdx]; i++) {
found = sNumSeqRequests[playerIdx];
for (i = 0; i < sNumSeqRequests[playerIdx]; i++) {
if (D_8016E320[playerIdx][i].unk_1 <= new_var) {
found = i;
i = D_8016E348[playerIdx]; // "break;"
i = sNumSeqRequests[playerIdx]; // "break;"
}
}
if (D_8016E348[playerIdx] < 5) {
D_8016E348[playerIdx]++;
if (sNumSeqRequests[playerIdx] < 5) {
sNumSeqRequests[playerIdx]++;
}
for (i = D_8016E348[playerIdx] - 1; i != found; i--) {
for (i = sNumSeqRequests[playerIdx] - 1; i != found; i--) {
D_8016E320[playerIdx][i].unk_1 = D_8016E320[playerIdx][i - 1].unk_1;
D_8016E320[playerIdx][i].unk_0 = D_8016E320[playerIdx][i - 1].unk_0;
}
@ -187,25 +187,25 @@ void Audio_ProcessSeqCmd(u32 cmd) {
seqId = cmd & 0xFF;
fadeTimer = (cmd & 0xFF0000) >> 13;
found = D_8016E348[playerIdx];
for (i = 0; i < D_8016E348[playerIdx]; i++) {
found = sNumSeqRequests[playerIdx];
for (i = 0; i < sNumSeqRequests[playerIdx]; i++) {
if (D_8016E320[playerIdx][i].unk_0 == seqId) {
found = i;
i = D_8016E348[playerIdx]; // "break;"
i = sNumSeqRequests[playerIdx]; // "break;"
}
}
if (found != D_8016E348[playerIdx]) {
for (i = found; i < D_8016E348[playerIdx] - 1; i++) {
if (found != sNumSeqRequests[playerIdx]) {
for (i = found; i < sNumSeqRequests[playerIdx] - 1; i++) {
D_8016E320[playerIdx][i].unk_1 = D_8016E320[playerIdx][i + 1].unk_1;
D_8016E320[playerIdx][i].unk_0 = D_8016E320[playerIdx][i + 1].unk_0;
}
D_8016E348[playerIdx]--;
sNumSeqRequests[playerIdx]--;
}
if (found == 0) {
func_800F9474(playerIdx, fadeTimer);
if (D_8016E348[playerIdx] != 0) {
if (sNumSeqRequests[playerIdx] != 0) {
func_800F9280(playerIdx, D_8016E320[playerIdx][0].unk_0, D_8016E320[playerIdx][0].unk_1, fadeTimer);
}
}
@ -218,11 +218,11 @@ void Audio_ProcessSeqCmd(u32 cmd) {
if (duration == 0) {
duration++;
}
D_8016E750[playerIdx].volTarget = (f32)val / 127.0f;
if (D_8016E750[playerIdx].volCur != D_8016E750[playerIdx].volTarget) {
D_8016E750[playerIdx].unk_08 =
(D_8016E750[playerIdx].volCur - D_8016E750[playerIdx].volTarget) / (f32)duration;
D_8016E750[playerIdx].unk_0C = duration;
gActiveSeqs[playerIdx].volTarget = (f32)val / 127.0f;
if (gActiveSeqs[playerIdx].volCur != gActiveSeqs[playerIdx].volTarget) {
gActiveSeqs[playerIdx].volStep =
(gActiveSeqs[playerIdx].volCur - gActiveSeqs[playerIdx].volTarget) / (f32)duration;
gActiveSeqs[playerIdx].volTimer = duration;
}
break;
@ -235,12 +235,12 @@ void Audio_ProcessSeqCmd(u32 cmd) {
}
freqScale = (f32)val / 1000.0f;
for (i = 0; i < 16; i++) {
D_8016E750[playerIdx].unk_50[i].unk_14 = freqScale;
D_8016E750[playerIdx].unk_50[i].unk_1C = duration;
D_8016E750[playerIdx].unk_50[i].unk_18 =
(D_8016E750[playerIdx].unk_50[i].unk_10 - freqScale) / (f32)duration;
gActiveSeqs[playerIdx].channelData[i].freqScaleTarget = freqScale;
gActiveSeqs[playerIdx].channelData[i].freqScaleTimer = duration;
gActiveSeqs[playerIdx].channelData[i].freqScaleStep =
(gActiveSeqs[playerIdx].channelData[i].freqScaleCur - freqScale) / (f32)duration;
}
D_8016E750[playerIdx].unk_250 = 0xFFFF;
gActiveSeqs[playerIdx].freqScaleChannelFlags = 0xFFFF;
break;
case 0xD:
@ -252,11 +252,11 @@ void Audio_ProcessSeqCmd(u32 cmd) {
duration++;
}
freqScale = (f32)val / 1000.0f;
D_8016E750[playerIdx].unk_50[chanIdx].unk_14 = freqScale;
D_8016E750[playerIdx].unk_50[chanIdx].unk_18 =
(D_8016E750[playerIdx].unk_50[chanIdx].unk_10 - freqScale) / (f32)duration;
D_8016E750[playerIdx].unk_50[chanIdx].unk_1C = duration;
D_8016E750[playerIdx].unk_250 |= 1 << chanIdx;
gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleTarget = freqScale;
gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleStep =
(gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleCur - freqScale) / (f32)duration;
gActiveSeqs[playerIdx].channelData[chanIdx].freqScaleTimer = duration;
gActiveSeqs[playerIdx].freqScaleChannelFlags |= 1 << chanIdx;
break;
case 0x6:
@ -267,13 +267,13 @@ void Audio_ProcessSeqCmd(u32 cmd) {
if (duration == 0) {
duration++;
}
D_8016E750[playerIdx].unk_50[chanIdx].unk_04 = (f32)val / 127.0f;
if (D_8016E750[playerIdx].unk_50[chanIdx].unk_00 != D_8016E750[playerIdx].unk_50[chanIdx].unk_04) {
D_8016E750[playerIdx].unk_50[chanIdx].unk_08 =
(D_8016E750[playerIdx].unk_50[chanIdx].unk_00 - D_8016E750[playerIdx].unk_50[chanIdx].unk_04) /
gActiveSeqs[playerIdx].channelData[chanIdx].volTarget = (f32)val / 127.0f;
if (gActiveSeqs[playerIdx].channelData[chanIdx].volCur != gActiveSeqs[playerIdx].channelData[chanIdx].volTarget) {
gActiveSeqs[playerIdx].channelData[chanIdx].volStep =
(gActiveSeqs[playerIdx].channelData[chanIdx].volCur - gActiveSeqs[playerIdx].channelData[chanIdx].volTarget) /
(f32)duration;
D_8016E750[playerIdx].unk_50[chanIdx].unk_0C = duration;
D_8016E750[playerIdx].unk_252 |= 1 << chanIdx;
gActiveSeqs[playerIdx].channelData[chanIdx].volTimer = duration;
gActiveSeqs[playerIdx].volChannelFlags |= 1 << chanIdx;
}
break;
@ -289,7 +289,7 @@ void Audio_ProcessSeqCmd(u32 cmd) {
chanIdx = (cmd & 0xF00) >> 8;
port = (cmd & 0xFF0000) >> 16;
val = cmd & 0xFF;
if ((D_8016E750[playerIdx].unk_258 & (1 << chanIdx)) == 0) {
if ((gActiveSeqs[playerIdx].channelPortMask & (1 << chanIdx)) == 0) {
Audio_QueueCmdS8(0x06000000 | _SHIFTL(playerIdx, 16, 8) | _SHIFTL(chanIdx, 8, 8) | _SHIFTL(port, 0, 8),
val);
}
@ -297,7 +297,7 @@ void Audio_ProcessSeqCmd(u32 cmd) {
case 0x9:
// set channel mask for command 0x8
D_8016E750[playerIdx].unk_258 = cmd & 0xFFFF;
gActiveSeqs[playerIdx].channelPortMask = cmd & 0xFFFF;
break;
case 0xA:
@ -319,22 +319,22 @@ void Audio_ProcessSeqCmd(u32 cmd) {
case 0xB:
// update tempo
D_8016E750[playerIdx].unk_14 = cmd;
gActiveSeqs[playerIdx].tempoCmd = cmd;
break;
case 0xC:
// start sequence with setup commands
subOp = (cmd & 0xF00000) >> 20;
if (subOp != 0xF) {
if (D_8016E750[playerIdx].unk_4D < 7) {
found = D_8016E750[playerIdx].unk_4D++;
if (gActiveSeqs[playerIdx].setupCmdNum < 7) {
found = gActiveSeqs[playerIdx].setupCmdNum++;
if (found < 8) {
D_8016E750[playerIdx].unk_2C[found] = cmd;
D_8016E750[playerIdx].unk_4C = 2;
gActiveSeqs[playerIdx].setupCmd[found] = cmd;
gActiveSeqs[playerIdx].setupCmdTimer = 2;
}
}
} else {
D_8016E750[playerIdx].unk_4D = 0;
gActiveSeqs[playerIdx].setupCmdNum = 0;
}
break;
@ -400,7 +400,7 @@ u16 func_800FA0B4(u8 playerIdx) {
if (!gAudioContext.seqPlayers[playerIdx].enabled) {
return NA_BGM_DISABLED;
}
return D_8016E750[playerIdx].unk_254;
return gActiveSeqs[playerIdx].seqId;
}
s32 func_800FA11C(u32 arg0, u32 arg1) {
@ -416,17 +416,17 @@ s32 func_800FA11C(u32 arg0, u32 arg1) {
}
void func_800FA174(u8 playerIdx) {
D_8016E348[playerIdx] = 0;
sNumSeqRequests[playerIdx] = 0;
}
void func_800FA18C(u8 playerIdx, u8 arg1) {
u8 i;
for (i = 0; i < D_8016E750[playerIdx].unk_4D; i++) {
u8 unkb = (D_8016E750[playerIdx].unk_2C[i] & 0xF00000) >> 20;
for (i = 0; i < gActiveSeqs[playerIdx].setupCmdNum; i++) {
u8 unkb = (gActiveSeqs[playerIdx].setupCmd[i] & 0xF00000) >> 20;
if (unkb == arg1) {
D_8016E750[playerIdx].unk_2C[i] = 0xFF000000;
gActiveSeqs[playerIdx].setupCmd[i] = 0xFF000000;
}
}
}
@ -435,14 +435,14 @@ void Audio_SetVolScale(u8 playerIdx, u8 scaleIdx, u8 targetVol, u8 volFadeTimer)
f32 volScale;
u8 i;
D_8016E750[playerIdx].volScales[scaleIdx] = targetVol & 0x7F;
gActiveSeqs[playerIdx].volScales[scaleIdx] = targetVol & 0x7F;
if (volFadeTimer != 0) {
D_8016E750[playerIdx].fadeVolUpdate = 1;
D_8016E750[playerIdx].volFadeTimer = volFadeTimer;
gActiveSeqs[playerIdx].fadeVolUpdate = 1;
gActiveSeqs[playerIdx].volFadeTimer = volFadeTimer;
} else {
for (i = 0, volScale = 1.0f; i < 4; i++) {
volScale *= D_8016E750[playerIdx].volScales[i] / 127.0f;
volScale *= gActiveSeqs[playerIdx].volScales[i] / 127.0f;
}
Audio_SetVolScaleNow(playerIdx, volFadeTimer, volScale);
@ -468,41 +468,41 @@ void func_800FA3DC(void) {
u8 k;
for (playerIdx = 0; playerIdx < 4; playerIdx++) {
if (D_8016E750[playerIdx].unk_260 != 0) {
if (gActiveSeqs[playerIdx].isWaitingForFonts != 0) {
switch (func_800E5E20(&dummy)) {
case 1:
case 2:
case 3:
case 4:
D_8016E750[playerIdx].unk_260 = 0;
Audio_ProcessSeqCmd(D_8016E750[playerIdx].unk_25C);
gActiveSeqs[playerIdx].isWaitingForFonts = 0;
Audio_ProcessSeqCmd(gActiveSeqs[playerIdx].startSeqCmd);
break;
}
}
if (D_8016E750[playerIdx].fadeVolUpdate) {
if (gActiveSeqs[playerIdx].fadeVolUpdate) {
phi_f0 = 1.0f;
for (j = 0; j < 4; j++) {
phi_f0 *= (D_8016E750[playerIdx].volScales[j] / 127.0f);
phi_f0 *= (gActiveSeqs[playerIdx].volScales[j] / 127.0f);
}
Audio_SeqCmd4(playerIdx, D_8016E750[playerIdx].volFadeTimer, (u8)(phi_f0 * 127.0f));
D_8016E750[playerIdx].fadeVolUpdate = 0;
Audio_SeqCmd4(playerIdx, gActiveSeqs[playerIdx].volFadeTimer, (u8)(phi_f0 * 127.0f));
gActiveSeqs[playerIdx].fadeVolUpdate = 0;
}
if (D_8016E750[playerIdx].unk_0C != 0) {
D_8016E750[playerIdx].unk_0C--;
if (gActiveSeqs[playerIdx].volTimer != 0) {
gActiveSeqs[playerIdx].volTimer--;
if (D_8016E750[playerIdx].unk_0C != 0) {
D_8016E750[playerIdx].volCur = D_8016E750[playerIdx].volCur - D_8016E750[playerIdx].unk_08;
if (gActiveSeqs[playerIdx].volTimer != 0) {
gActiveSeqs[playerIdx].volCur = gActiveSeqs[playerIdx].volCur - gActiveSeqs[playerIdx].volStep;
} else {
D_8016E750[playerIdx].volCur = D_8016E750[playerIdx].volTarget;
gActiveSeqs[playerIdx].volCur = gActiveSeqs[playerIdx].volTarget;
}
Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), D_8016E750[playerIdx].volCur);
Audio_QueueCmdF32(0x41000000 | _SHIFTL(playerIdx, 16, 8), gActiveSeqs[playerIdx].volCur);
}
if (D_8016E750[playerIdx].unk_14 != 0) {
temp_a1 = D_8016E750[playerIdx].unk_14;
if (gActiveSeqs[playerIdx].tempoCmd != 0) {
temp_a1 = gActiveSeqs[playerIdx].tempoCmd;
phi_t0 = (temp_a1 & 0xFF0000) >> 15;
phi_a2 = temp_a1 & 0xFFF;
if (phi_t0 == 0) {
@ -525,8 +525,8 @@ void func_800FA3DC(void) {
phi_a2 = temp_lo * (phi_a2 / 100.0f);
break;
case 4:
if (D_8016E750[playerIdx].unk_18) {
phi_a2 = D_8016E750[playerIdx].unk_18;
if (gActiveSeqs[playerIdx].tempoOriginal) {
phi_a2 = gActiveSeqs[playerIdx].tempoOriginal;
} else {
phi_a2 = temp_lo;
}
@ -537,71 +537,71 @@ void func_800FA3DC(void) {
phi_a2 = 300;
}
if (D_8016E750[playerIdx].unk_18 == 0) {
D_8016E750[playerIdx].unk_18 = temp_lo;
if (gActiveSeqs[playerIdx].tempoOriginal == 0) {
gActiveSeqs[playerIdx].tempoOriginal = temp_lo;
}
D_8016E750[playerIdx].unk_20 = phi_a2;
D_8016E750[playerIdx].unk_1C = gAudioContext.seqPlayers[playerIdx].tempo / 0x30;
D_8016E750[playerIdx].unk_24 = (D_8016E750[playerIdx].unk_1C - D_8016E750[playerIdx].unk_20) / phi_t0;
D_8016E750[playerIdx].unk_28 = phi_t0;
D_8016E750[playerIdx].unk_14 = 0;
gActiveSeqs[playerIdx].tempoTarget = phi_a2;
gActiveSeqs[playerIdx].tempoCur = gAudioContext.seqPlayers[playerIdx].tempo / 0x30;
gActiveSeqs[playerIdx].tempoStep = (gActiveSeqs[playerIdx].tempoCur - gActiveSeqs[playerIdx].tempoTarget) / phi_t0;
gActiveSeqs[playerIdx].tempoTimer = phi_t0;
gActiveSeqs[playerIdx].tempoCmd = 0;
}
}
if (D_8016E750[playerIdx].unk_28 != 0) {
D_8016E750[playerIdx].unk_28--;
if (D_8016E750[playerIdx].unk_28 != 0) {
D_8016E750[playerIdx].unk_1C = D_8016E750[playerIdx].unk_1C - D_8016E750[playerIdx].unk_24;
if (gActiveSeqs[playerIdx].tempoTimer != 0) {
gActiveSeqs[playerIdx].tempoTimer--;
if (gActiveSeqs[playerIdx].tempoTimer != 0) {
gActiveSeqs[playerIdx].tempoCur = gActiveSeqs[playerIdx].tempoCur - gActiveSeqs[playerIdx].tempoStep;
} else {
D_8016E750[playerIdx].unk_1C = D_8016E750[playerIdx].unk_20;
gActiveSeqs[playerIdx].tempoCur = gActiveSeqs[playerIdx].tempoTarget;
}
// set tempo
Audio_QueueCmdS32(0x47000000 | _SHIFTL(playerIdx, 16, 8), D_8016E750[playerIdx].unk_1C);
Audio_QueueCmdS32(0x47000000 | _SHIFTL(playerIdx, 16, 8), gActiveSeqs[playerIdx].tempoCur);
}
if (D_8016E750[playerIdx].unk_252 != 0) {
if (gActiveSeqs[playerIdx].volChannelFlags != 0) {
for (k = 0; k < 0x10; k++) {
if (D_8016E750[playerIdx].unk_50[k].unk_0C != 0) {
D_8016E750[playerIdx].unk_50[k].unk_0C--;
if (D_8016E750[playerIdx].unk_50[k].unk_0C != 0) {
D_8016E750[playerIdx].unk_50[k].unk_00 -= D_8016E750[playerIdx].unk_50[k].unk_08;
if (gActiveSeqs[playerIdx].channelData[k].volTimer != 0) {
gActiveSeqs[playerIdx].channelData[k].volTimer--;
if (gActiveSeqs[playerIdx].channelData[k].volTimer != 0) {
gActiveSeqs[playerIdx].channelData[k].volCur -= gActiveSeqs[playerIdx].channelData[k].volStep;
} else {
D_8016E750[playerIdx].unk_50[k].unk_00 = D_8016E750[playerIdx].unk_50[k].unk_04;
D_8016E750[playerIdx].unk_252 ^= (1 << k);
gActiveSeqs[playerIdx].channelData[k].volCur = gActiveSeqs[playerIdx].channelData[k].volTarget;
gActiveSeqs[playerIdx].volChannelFlags ^= (1 << k);
}
// CHAN_UPD_VOL_SCALE (playerIdx = seq, k = chan)
Audio_QueueCmdF32(0x01000000 | _SHIFTL(playerIdx, 16, 8) | _SHIFTL(k, 8, 8),
D_8016E750[playerIdx].unk_50[k].unk_00);
gActiveSeqs[playerIdx].channelData[k].volCur);
}
}
}
if (D_8016E750[playerIdx].unk_250 != 0) {
if (gActiveSeqs[playerIdx].freqScaleChannelFlags != 0) {
for (k = 0; k < 0x10; k++) {
if (D_8016E750[playerIdx].unk_50[k].unk_1C != 0) {
D_8016E750[playerIdx].unk_50[k].unk_1C--;
if (D_8016E750[playerIdx].unk_50[k].unk_1C != 0) {
D_8016E750[playerIdx].unk_50[k].unk_10 -= D_8016E750[playerIdx].unk_50[k].unk_18;
if (gActiveSeqs[playerIdx].channelData[k].freqScaleTimer != 0) {
gActiveSeqs[playerIdx].channelData[k].freqScaleTimer--;
if (gActiveSeqs[playerIdx].channelData[k].freqScaleTimer != 0) {
gActiveSeqs[playerIdx].channelData[k].freqScaleCur -= gActiveSeqs[playerIdx].channelData[k].freqScaleStep;
} else {
D_8016E750[playerIdx].unk_50[k].unk_10 = D_8016E750[playerIdx].unk_50[k].unk_14;
D_8016E750[playerIdx].unk_250 ^= (1 << k);
gActiveSeqs[playerIdx].channelData[k].freqScaleCur = gActiveSeqs[playerIdx].channelData[k].freqScaleTarget;
gActiveSeqs[playerIdx].freqScaleChannelFlags ^= (1 << k);
}
// CHAN_UPD_FREQ_SCALE
Audio_QueueCmdF32(0x04000000 | _SHIFTL(playerIdx, 16, 8) | _SHIFTL(k, 8, 8),
D_8016E750[playerIdx].unk_50[k].unk_10);
gActiveSeqs[playerIdx].channelData[k].freqScaleCur);
}
}
}
if (D_8016E750[playerIdx].unk_4D != 0) {
if (gActiveSeqs[playerIdx].setupCmdNum != 0) {
if (func_800FA11C(0xF0000000, 0xF0000000) == 0) {
D_8016E750[playerIdx].unk_4D = 0;
gActiveSeqs[playerIdx].setupCmdNum = 0;
return;
}
if (D_8016E750[playerIdx].unk_4C != 0) {
D_8016E750[playerIdx].unk_4C--;
if (gActiveSeqs[playerIdx].setupCmdTimer != 0) {
gActiveSeqs[playerIdx].setupCmdTimer--;
continue;
}
@ -609,28 +609,28 @@ void func_800FA3DC(void) {
continue;
}
for (j = 0; j < D_8016E750[playerIdx].unk_4D; j++) {
temp_a0 = (D_8016E750[playerIdx].unk_2C[j] & 0x00F00000) >> 20;
temp_s1 = (D_8016E750[playerIdx].unk_2C[j] & 0x000F0000) >> 16;
temp_s0_3 = (D_8016E750[playerIdx].unk_2C[j] & 0xFF00) >> 8;
temp_a3_3 = D_8016E750[playerIdx].unk_2C[j] & 0xFF;
for (j = 0; j < gActiveSeqs[playerIdx].setupCmdNum; j++) {
temp_a0 = (gActiveSeqs[playerIdx].setupCmd[j] & 0x00F00000) >> 20;
temp_s1 = (gActiveSeqs[playerIdx].setupCmd[j] & 0x000F0000) >> 16;
temp_s0_3 = (gActiveSeqs[playerIdx].setupCmd[j] & 0xFF00) >> 8;
temp_a3_3 = gActiveSeqs[playerIdx].setupCmd[j] & 0xFF;
switch (temp_a0) {
case 0:
Audio_SetVolScale(temp_s1, 1, 0x7F, temp_a3_3);
break;
case 7:
if (D_8016E348[playerIdx] == temp_a3_3) {
if (sNumSeqRequests[playerIdx] == temp_a3_3) {
Audio_SetVolScale(temp_s1, 1, 0x7F, temp_s0_3);
}
break;
case 1:
Audio_SeqCmd3(playerIdx, D_8016E750[playerIdx].unk_254);
Audio_SeqCmd3(playerIdx, gActiveSeqs[playerIdx].seqId);
break;
case 2:
Audio_StartSeq(temp_s1, 1, D_8016E750[temp_s1].unk_254);
D_8016E750[temp_s1].fadeVolUpdate = 1;
D_8016E750[temp_s1].volScales[1] = 0x7F;
Audio_StartSeq(temp_s1, 1, gActiveSeqs[temp_s1].seqId);
gActiveSeqs[temp_s1].fadeVolUpdate = 1;
gActiveSeqs[temp_s1].volScales[1] = 0x7F;
break;
case 3:
Audio_SeqCmdB30(temp_s1, temp_s0_3, temp_a3_3);
@ -639,13 +639,13 @@ void func_800FA3DC(void) {
Audio_SeqCmdB40(temp_s1, temp_a3_3, 0);
break;
case 5:
temp_v1 = D_8016E750[playerIdx].unk_2C[j] & 0xFFFF;
Audio_StartSeq(temp_s1, D_8016E750[temp_s1].unk_4E, temp_v1);
temp_v1 = gActiveSeqs[playerIdx].setupCmd[j] & 0xFFFF;
Audio_StartSeq(temp_s1, gActiveSeqs[temp_s1].setupFadeTimer, temp_v1);
Audio_SetVolScale(temp_s1, 1, 0x7F, 0);
D_8016E750[temp_s1].unk_4E = 0;
gActiveSeqs[temp_s1].setupFadeTimer = 0;
break;
case 6:
D_8016E750[playerIdx].unk_4E = temp_s0_3;
gActiveSeqs[playerIdx].setupFadeTimer = temp_s0_3;
break;
case 8:
Audio_SetVolScale(temp_s1, temp_s0_3, 0x7F, temp_a3_3);
@ -662,7 +662,7 @@ void func_800FA3DC(void) {
}
break;
case 9:
temp_v1 = D_8016E750[playerIdx].unk_2C[j] & 0xFFFF;
temp_v1 = gActiveSeqs[playerIdx].setupCmd[j] & 0xFFFF;
Audio_SeqCmdA(temp_s1, temp_v1);
break;
case 10:
@ -671,7 +671,7 @@ void func_800FA3DC(void) {
}
}
D_8016E750[playerIdx].unk_4D = 0;
gActiveSeqs[playerIdx].setupCmdNum = 0;
}
}
}
@ -695,26 +695,29 @@ u8 func_800FAD34(void) {
return D_80133418;
}
void func_800FADF8(void) {
u8 playerIdx, j;
void Audio_ResetActiveSequences(void) {
u8 seqPlayerIndex;
u8 scaleIndex;
for (playerIdx = 0; playerIdx < 4; playerIdx++) {
D_8016E348[playerIdx] = 0;
D_8016E750[playerIdx].unk_254 = NA_BGM_DISABLED;
D_8016E750[playerIdx].unk_256 = NA_BGM_DISABLED;
D_8016E750[playerIdx].unk_28 = 0;
D_8016E750[playerIdx].unk_18 = 0;
D_8016E750[playerIdx].unk_14 = 0;
D_8016E750[playerIdx].unk_258 = 0;
D_8016E750[playerIdx].unk_4D = 0;
D_8016E750[playerIdx].unk_4E = 0;
D_8016E750[playerIdx].unk_250 = 0;
D_8016E750[playerIdx].unk_252 = 0;
for (j = 0; j < 4; j++) {
D_8016E750[playerIdx].volScales[j] = 0x7F;
for (seqPlayerIndex = 0; seqPlayerIndex < 4; seqPlayerIndex++) {
sNumSeqRequests[seqPlayerIndex] = 0;
gActiveSeqs[seqPlayerIndex].seqId = NA_BGM_DISABLED;
gActiveSeqs[seqPlayerIndex].prevSeqId = NA_BGM_DISABLED;
gActiveSeqs[seqPlayerIndex].tempoTimer = 0;
gActiveSeqs[seqPlayerIndex].tempoOriginal = 0;
gActiveSeqs[seqPlayerIndex].tempoCmd = 0;
gActiveSeqs[seqPlayerIndex].channelPortMask = 0;
gActiveSeqs[seqPlayerIndex].setupCmdNum = 0;
gActiveSeqs[seqPlayerIndex].setupFadeTimer = 0;
gActiveSeqs[seqPlayerIndex].freqScaleChannelFlags = 0;
gActiveSeqs[seqPlayerIndex].volChannelFlags = 0;
for (scaleIndex = 0; scaleIndex < 4; scaleIndex++) {
gActiveSeqs[seqPlayerIndex].volScales[scaleIndex] = 0x7F;
}
D_8016E750[playerIdx].volFadeTimer = 1;
D_8016E750[playerIdx].fadeVolUpdate = 1;
gActiveSeqs[seqPlayerIndex].volFadeTimer = 1;
gActiveSeqs[seqPlayerIndex].fadeVolUpdate = true;
}
}
@ -722,12 +725,12 @@ void func_800FAEB4(void) {
u8 playerIdx, j;
for (playerIdx = 0; playerIdx < 4; playerIdx++) {
D_8016E750[playerIdx].volCur = 1.0f;
D_8016E750[playerIdx].unk_0C = 0;
D_8016E750[playerIdx].fadeVolUpdate = 0;
gActiveSeqs[playerIdx].volCur = 1.0f;
gActiveSeqs[playerIdx].volTimer = 0;
gActiveSeqs[playerIdx].fadeVolUpdate = 0;
for (j = 0; j < 4; j++) {
D_8016E750[playerIdx].volScales[j] = 0x7F;
gActiveSeqs[playerIdx].volScales[j] = 0x7F;
}
}
func_800FADF8();
Audio_ResetActiveSequences();
}

View File

@ -662,27 +662,33 @@ s32 Flags_GetSwitch(PlayState* play, s32 flag) {
* Sets current scene switch flag.
*/
void Flags_SetSwitch(PlayState* play, s32 flag) {
lusprintf(__FILE__, __LINE__, 2, "Switch Flag Set - %#x", flag);
u8 previouslyOff = !Flags_GetSwitch(play, flag);
if (flag < 0x20) {
play->actorCtx.flags.swch |= (1 << flag);
} else {
play->actorCtx.flags.tempSwch |= (1 << (flag - 0x20));
}
if (previouslyOff) {
LUSLOG_INFO("Switch Flag Set - %#x", flag);
GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_SWITCH, flag);
}
}
/**
* Unsets current scene switch flag.
*/
void Flags_UnsetSwitch(PlayState* play, s32 flag) {
lusprintf(__FILE__, __LINE__, 2, "Switch Flag Unset - %#x", flag);
u8 previouslyOn = Flags_GetSwitch(play, flag);
if (flag < 0x20) {
play->actorCtx.flags.swch &= ~(1 << flag);
} else {
play->actorCtx.flags.tempSwch &= ~(1 << (flag - 0x20));
}
if (previouslyOn) {
LUSLOG_INFO("Switch Flag Unset - %#x", flag);
GameInteractor_ExecuteOnSceneFlagUnset(play->sceneNum, FLAG_SCENE_SWITCH, flag);
}
}
/**
* Tests if unknown flag is set.
@ -728,10 +734,13 @@ s32 Flags_GetTreasure(PlayState* play, s32 flag) {
* Sets current scene chest flag.
*/
void Flags_SetTreasure(PlayState* play, s32 flag) {
lusprintf(__FILE__, __LINE__, 2, "Treasure Flag Set - %#x", flag);
u8 previouslyOff = !Flags_GetTreasure(play, flag);
play->actorCtx.flags.chest |= (1 << flag);
if (previouslyOff) {
LUSLOG_INFO("Treasure Flag Set - %#x", flag);
GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_TREASURE, flag);
}
}
/**
* Tests if current scene clear flag is set.
@ -744,17 +753,25 @@ s32 Flags_GetClear(PlayState* play, s32 flag) {
* Sets current scene clear flag.
*/
void Flags_SetClear(PlayState* play, s32 flag) {
u8 previouslyOff = !Flags_GetClear(play, flag);
play->actorCtx.flags.clear |= (1 << flag);
if (previouslyOff) {
LUSLOG_INFO("Clear Flag Set - %#x", flag);
GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_CLEAR, flag);
}
}
/**
* Unsets current scene clear flag.
*/
void Flags_UnsetClear(PlayState* play, s32 flag) {
u8 previouslyOn = Flags_GetClear(play, flag);
play->actorCtx.flags.clear &= ~(1 << flag);
if (previouslyOn) {
LUSLOG_INFO("Clear Flag Unset - %#x", flag);
GameInteractor_ExecuteOnSceneFlagUnset(play->sceneNum, FLAG_SCENE_CLEAR, flag);
}
}
/**
* Tests if current scene temp clear flag is set.
@ -792,7 +809,7 @@ s32 Flags_GetCollectible(PlayState* play, s32 flag) {
* Sets current scene collectible flag.
*/
void Flags_SetCollectible(PlayState* play, s32 flag) {
lusprintf(__FILE__, __LINE__, 2, "Collectible Flag Set - %#x", flag);
u8 previouslyOff = !Flags_GetCollectible(play, flag);
if (flag != 0) {
if (flag < 0x20) {
play->actorCtx.flags.collect |= (1 << flag);
@ -800,8 +817,11 @@ void Flags_SetCollectible(PlayState* play, s32 flag) {
play->actorCtx.flags.tempCollect |= (1 << (flag - 0x20));
}
}
if (previouslyOff) {
LUSLOG_INFO("Collectible Flag Set - %#x", flag);
GameInteractor_ExecuteOnSceneFlagSet(play->sceneNum, FLAG_SCENE_COLLECTIBLE, flag);
}
}
void func_8002CDE4(PlayState* play, TitleCardContext* titleCtx) {
titleCtx->durationTimer = titleCtx->delayTimer = titleCtx->intensityR = titleCtx->alpha = 0;
@ -4723,17 +4743,25 @@ s32 Flags_GetEventChkInf(s32 flag) {
* Sets "eventChkInf" flag.
*/
void Flags_SetEventChkInf(s32 flag) {
u8 previouslyOff = !Flags_GetEventChkInf(flag);
gSaveContext.eventChkInf[flag >> 4] |= (1 << (flag & 0xF));
if (previouslyOff) {
LUSLOG_INFO("EventChkInf Flag Set - %#x", flag);
GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, flag);
}
}
/**
* Unsets "eventChkInf" flag.
*/
void Flags_UnsetEventChkInf(s32 flag) {
u8 previouslyOn = Flags_GetEventChkInf(flag);
gSaveContext.eventChkInf[flag >> 4] &= ~(1 << (flag & 0xF));
if (previouslyOn) {
LUSLOG_INFO("EventChkInf Flag Unset - %#x", flag);
GameInteractor_ExecuteOnFlagUnset(FLAG_EVENT_CHECK_INF, flag);
}
}
/**
* Tests if "itemGetInf" flag is set.
@ -4746,17 +4774,25 @@ s32 Flags_GetItemGetInf(s32 flag) {
* Sets "itemGetInf" flag.
*/
void Flags_SetItemGetInf(s32 flag) {
u8 previouslyOff = !Flags_GetItemGetInf(flag);
gSaveContext.itemGetInf[flag >> 4] |= (1 << (flag & 0xF));
if (previouslyOff) {
LUSLOG_INFO("ItemGetInf Flag Set - %#x", flag);
GameInteractor_ExecuteOnFlagSet(FLAG_ITEM_GET_INF, flag);
}
}
/**
* Unsets "itemGetInf" flag.
*/
void Flags_UnsetItemGetInf(s32 flag) {
u8 previouslyOn = Flags_GetItemGetInf(flag);
gSaveContext.itemGetInf[flag >> 4] &= ~(1 << (flag & 0xF));
if (previouslyOn) {
LUSLOG_INFO("ItemGetInf Flag Unset - %#x", flag);
GameInteractor_ExecuteOnFlagUnset(FLAG_ITEM_GET_INF, flag);
}
}
/**
* Tests if "infTable" flag is set.
@ -4769,17 +4805,25 @@ s32 Flags_GetInfTable(s32 flag) {
* Sets "infTable" flag.
*/
void Flags_SetInfTable(s32 flag) {
u8 previouslyOff = !Flags_GetInfTable(flag);
gSaveContext.infTable[flag >> 4] |= (1 << (flag & 0xF));
if (previouslyOff) {
LUSLOG_INFO("InfTable Flag Set - %#x", flag);
GameInteractor_ExecuteOnFlagSet(FLAG_INF_TABLE, flag);
}
}
/**
* Unsets "infTable" flag.
*/
void Flags_UnsetInfTable(s32 flag) {
u8 previouslyOn = Flags_GetInfTable(flag);
gSaveContext.infTable[flag >> 4] &= ~(1 << (flag & 0xF));
if (previouslyOn) {
LUSLOG_INFO("InfTable Flag Unset - %#x", flag);
GameInteractor_ExecuteOnFlagUnset(FLAG_INF_TABLE, flag);
}
}
/**
* Tests if "eventInf" flag is set.
@ -4792,17 +4836,25 @@ s32 Flags_GetEventInf(s32 flag) {
* Sets "eventInf" flag.
*/
void Flags_SetEventInf(s32 flag) {
u8 previouslyOff = !Flags_GetEventInf(flag);
gSaveContext.eventInf[flag >> 4] |= (1 << (flag & 0xF));
if (previouslyOff) {
LUSLOG_INFO("EventInf Flag Set - %#x", flag);
GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_INF, flag);
}
}
/**
* Unsets "eventInf" flag.
*/
void Flags_UnsetEventInf(s32 flag) {
u8 previouslyOn = Flags_GetEventInf(flag);
gSaveContext.eventInf[flag >> 4] &= ~(1 << (flag & 0xF));
if (previouslyOn) {
LUSLOG_INFO("EventInf Flag Unset - %#x", flag);
GameInteractor_ExecuteOnFlagUnset(FLAG_EVENT_INF, flag);
}
}
/**
* Tests if "randomizerInf" flag is set.
@ -4815,17 +4867,25 @@ s32 Flags_GetRandomizerInf(RandomizerInf flag) {
* Sets "randomizerInf" flag.
*/
void Flags_SetRandomizerInf(RandomizerInf flag) {
u8 previouslyOff = !Flags_GetRandomizerInf(flag);
gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF));
if (previouslyOff) {
LUSLOG_INFO("RandomizerInf Flag Set - %#x", flag);
GameInteractor_ExecuteOnFlagSet(FLAG_RANDOMIZER_INF, flag);
}
}
/**
* Unsets "randomizerInf" flag.
*/
void Flags_UnsetRandomizerInf(RandomizerInf flag) {
u8 previouslyOn = Flags_GetRandomizerInf(flag);
gSaveContext.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF));
if (previouslyOn) {
LUSLOG_INFO("RandomizerInf Flag Unset - %#x", flag);
GameInteractor_ExecuteOnFlagUnset(FLAG_RANDOMIZER_INF, flag);
}
}
u32 func_80035BFC(PlayState* play, s16 arg1) {
u16 retTextId = 0;

View File

@ -18,9 +18,10 @@ s32 FrameAdvance_Update(FrameAdvanceContext* frameAdvCtx, Input* input) {
frameAdvCtx->enabled = !frameAdvCtx->enabled;
}
if (!frameAdvCtx->enabled || (CHECK_BTN_ALL(input->cur.button, BTN_Z) &&
if (!frameAdvCtx->enabled || CVarGetInteger("gFrameAdvance", 0) || (CHECK_BTN_ALL(input->cur.button, BTN_Z) &&
(CHECK_BTN_ALL(input->press.button, BTN_R) ||
(CHECK_BTN_ALL(input->cur.button, BTN_R) && (++frameAdvCtx->timer >= 9))))) {
CVarClear("gFrameAdvance");
frameAdvCtx->timer = 0;
return true;
}

View File

@ -666,7 +666,7 @@ void func_80AB6D08(EnNiw* this, PlayState* play) {
}
this->path = 1;
this->timer5 = 80;
this->timer5 = 80 * CVarGetInteger("gCuccoStayDurationMultiplier", 1);
this->actor.speedXZ = 0.0f;
this->actor.velocity.y = 4.0f;
} else {

View File

@ -14,8 +14,6 @@ u8 gAmmoItems[] = {
static s16 sEquipState = 0;
static s16 sEquipAnimTimer = 0;
static s16 sEquipMoveTimer = 10;
bool gSelectingMask;
bool gSelectingAdultTrade;
static s16 sAmmoVtxOffset[] = {
0, 2, 4, 6, 99, 99, 8, 99, 10, 99, 99, 99, 99, 99, 12,
@ -87,6 +85,10 @@ void KaleidoScope_SetItemCursorVtx(PauseContext* pauseCtx) {
KaleidoScope_SetCursorVtx(pauseCtx, pauseCtx->cursorSlot[PAUSE_ITEM] * 4, pauseCtx->itemVtx);
}
#pragma region Item Cycling
s8 gCurrentItemCyclingSlot;
// Vertices for the extra items
static Vtx sCycleExtraItemVtx[] = {
// Left Item
@ -127,9 +129,11 @@ static Vtx sCycleAButtonVtx[] = {
static sSlotCycleActiveAnimTimer[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// Renders a left and/or right item for any item slot that can support cycling
void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8 canCycle, u8 leftItem, u8 rightItem) {
void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 canCycle, u8 leftItem, u8 rightItem) {
PauseContext* pauseCtx = &play->pauseCtx;
u8 isCycling = gCurrentItemCyclingSlot == slot;
OPEN_DISPS(play->state.gfxCtx);
// Update active cycling animation timer
@ -208,10 +212,20 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8
gSPVertex(POLY_KAL_DISP++, sCycleExtraItemVtx, 8, 0);
if (showLeftItem) {
if (!CHECK_AGE_REQ_ITEM(leftItem)) {
gDPSetGrayscaleColor(POLY_KAL_DISP++, 109, 109, 109, 255);
gSPGrayscale(POLY_KAL_DISP++, true);
}
KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[leftItem], 32, 32, 0);
gSPGrayscale(POLY_KAL_DISP++, false);
}
if (showRightItem) {
if (!CHECK_AGE_REQ_ITEM(rightItem)) {
gDPSetGrayscaleColor(POLY_KAL_DISP++, 109, 109, 109, 255);
gSPGrayscale(POLY_KAL_DISP++, true);
}
KaleidoScope_DrawQuadTextureRGBA32(play->state.gfxCtx, gItemIcons[rightItem], 32, 32, 4);
gSPGrayscale(POLY_KAL_DISP++, false);
}
Matrix_Pop();
@ -220,6 +234,155 @@ void KaleidoScope_DrawItemCycleExtras(PlayState* play, u8 slot, u8 isCycling, u8
CLOSE_DISPS(play->state.gfxCtx);
}
void KaleidoScope_HandleItemCycleExtras(PlayState* play, u8 slot, bool canCycle, u8 leftItem, u8 rightItem, bool replaceCButtons) {
Input* input = &play->state.input[0];
PauseContext* pauseCtx = &play->pauseCtx;
bool dpad = (CVarGetInteger("gDpadPause", 0) && !CHECK_BTN_ALL(input->cur.button, BTN_CUP));
u8 slotItem = gSaveContext.inventory.items[slot];
u8 hasLeftItem = leftItem != ITEM_NONE && slotItem != leftItem;
u8 hasRightItem = rightItem != ITEM_NONE && slotItem != rightItem && leftItem != rightItem;
if (
canCycle &&
pauseCtx->cursorSlot[PAUSE_ITEM] == slot &&
CHECK_BTN_ALL(input->press.button, BTN_A) &&
(hasLeftItem || hasRightItem)
) {
Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
gCurrentItemCyclingSlot = gCurrentItemCyclingSlot == slot ? -1 : slot;
}
if (gCurrentItemCyclingSlot == slot) {
pauseCtx->cursorColorSet = 8;
if ((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP)) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
if (replaceCButtons) {
for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
if (gSaveContext.equips.buttonItems[i] == gSaveContext.inventory.items[slot]) {
if (CHECK_AGE_REQ_ITEM(rightItem)) {
gSaveContext.equips.buttonItems[i] = rightItem;
Interface_LoadItemIcon1(play, i);
} else {
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
}
break;
}
}
}
gSaveContext.inventory.items[slot] = rightItem;
} else if ((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN)) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
if (replaceCButtons) {
for (int i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) {
if (gSaveContext.equips.buttonItems[i] == gSaveContext.inventory.items[slot]) {
if (CHECK_AGE_REQ_ITEM(leftItem)) {
gSaveContext.equips.buttonItems[i] = leftItem;
Interface_LoadItemIcon1(play, i);
} else {
gSaveContext.equips.buttonItems[i] = ITEM_NONE;
}
break;
}
}
}
gSaveContext.inventory.items[slot] = leftItem;
}
gCurrentItemCyclingSlot = pauseCtx->cursorSlot[PAUSE_ITEM] == slot ? slot : -1;
}
}
bool CanMaskSelect() {
// only allow mask select when:
// the shop is open:
// * zelda's letter check: Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER)
// * kak gate check: Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD)
// and the mask quest is complete: Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE)
return CVarGetInteger("gMaskSelect", 0) &&
Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE) &&
Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) &&
Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD);
}
void KaleidoScope_HandleItemCycles(PlayState* play) {
//handle the mask select
KaleidoScope_HandleItemCycleExtras(
play,
SLOT_TRADE_CHILD,
CanMaskSelect(),
INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH ?
ITEM_MASK_TRUTH :
INV_CONTENT(ITEM_TRADE_CHILD) - 1,
INV_CONTENT(ITEM_TRADE_CHILD) >= ITEM_MASK_TRUTH || INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_KEATON ?
ITEM_MASK_KEATON :
INV_CONTENT(ITEM_TRADE_CHILD) + 1,
true
);
//the slot age requirement for the child trade slot has to be updated
//in case it currently holds the bunny hood
//to allow adult link to wear it if the setting is enabled
gSlotAgeReqs[SLOT_TRADE_CHILD] =
(
((CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger("gAdultBunnyHood", 0)) ||
CVarGetInteger("gTimelessEquipment", 0)
) &&
INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_MASK_BUNNY
? AGE_REQ_NONE
: AGE_REQ_CHILD;
//also update the age requirement for the bunny hood itself
gItemAgeReqs[ITEM_MASK_BUNNY] =
((CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger("gAdultBunnyHood", 0)) ||
CVarGetInteger("gTimelessEquipment", 0)
? AGE_REQ_NONE
: AGE_REQ_CHILD;
//handle the adult trade select
KaleidoScope_HandleItemCycleExtras(
play,
SLOT_TRADE_ADULT,
IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE),
Randomizer_GetPrevAdultTradeItem(),
Randomizer_GetNextAdultTradeItem(),
true
);
}
void KaleidoScope_DrawItemCycles(PlayState* play) {
//draw the mask select
KaleidoScope_DrawItemCycleExtras(
play,
SLOT_TRADE_CHILD,
CanMaskSelect(),
INV_CONTENT(ITEM_TRADE_CHILD) <= ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH ?
ITEM_MASK_TRUTH :
INV_CONTENT(ITEM_TRADE_CHILD) - 1,
INV_CONTENT(ITEM_TRADE_CHILD) >= ITEM_MASK_TRUTH || INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_KEATON ?
ITEM_MASK_KEATON :
INV_CONTENT(ITEM_TRADE_CHILD) + 1
);
//draw the adult trade select
KaleidoScope_DrawItemCycleExtras(
play,
SLOT_TRADE_ADULT,
IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE),
Randomizer_GetPrevAdultTradeItem(),
Randomizer_GetNextAdultTradeItem()
);
}
bool IsItemCycling() {
return gCurrentItemCyclingSlot != -1;
}
void KaleidoScope_ResetItemCycling() {
gCurrentItemCyclingSlot = -1;
}
#pragma endregion
void KaleidoScope_DrawItemSelect(PlayState* play) {
static s16 magicArrowEffectsR[] = { 255, 100, 255 };
static s16 magicArrowEffectsG[] = { 0, 100, 255 };
@ -240,16 +403,6 @@ void KaleidoScope_DrawItemSelect(PlayState* play) {
bool pauseAnyCursor = (CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_RANDO_ONLY && IS_RANDO) ||
(CVarGetInteger("gPauseAnyCursor", 0) == PAUSE_ANY_CURSOR_ALWAYS_ON);
// only allow mask select when:
// the shop is open:
// * zelda's letter check: Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER)
// * kak gate check: Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD)
// and the mask quest is complete: Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE)
bool canMaskSelect = CVarGetInteger("gMaskSelect", 0) &&
Flags_GetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE) &&
Flags_GetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER) &&
Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD);
OPEN_DISPS(play->state.gfxCtx);
Gfx_SetupDL_42Opa(play->state.gfxCtx);
@ -260,7 +413,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) {
pauseCtx->nameColorSet = 0;
if ((pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0) && (pauseCtx->pageIndex == PAUSE_ITEM)) {
moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade;
moveCursorResult = 0 || IsItemCycling();
oldCursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM];
cursorItem = pauseCtx->cursorItem[PAUSE_ITEM];
@ -434,7 +587,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) {
if (pauseCtx->cursorSpecialPos == 0) {
if (cursorItem != PAUSE_ITEM_NONE) {
if ((ABS(pauseCtx->stickRelY) > 30) || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DDOWN | BTN_DUP))) {
moveCursorResult = 0 || gSelectingMask || gSelectingAdultTrade;
moveCursorResult = 0 || IsItemCycling();
cursorPoint = pauseCtx->cursorPoint[PAUSE_ITEM];
cursorY = pauseCtx->cursorY[PAUSE_ITEM];
@ -499,68 +652,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) {
KaleidoScope_SetCursorVtx(pauseCtx, index, pauseCtx->itemVtx);
if ((pauseCtx->debugState == 0) && (pauseCtx->state == 6) && (pauseCtx->unk_1E4 == 0)) {
if (canMaskSelect && cursorSlot == SLOT_TRADE_CHILD && CHECK_BTN_ALL(input->press.button, BTN_A)) {
Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
gSelectingMask = !gSelectingMask;
}
if (gSelectingMask) {
pauseCtx->cursorColorSet = 8;
if (((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP)) &&
INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_TRUTH) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
++INV_CONTENT(ITEM_TRADE_CHILD);
} else if (((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN)) &&
INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_KEATON) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
--INV_CONTENT(ITEM_TRADE_CHILD);
} else if ((pauseCtx->stickRelX < -30 || pauseCtx->stickRelX > 30 || pauseCtx->stickRelY < -30 || pauseCtx->stickRelY > 30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT)) {
// Change to keaton mask if no mask is in child trade slot. Catches Zelda's letter and bottle duping over this slot.
if (INV_CONTENT(ITEM_TRADE_CHILD) < ITEM_MASK_KEATON || INV_CONTENT(ITEM_TRADE_CHILD) > ITEM_MASK_TRUTH) {
INV_CONTENT(ITEM_TRADE_CHILD) = ITEM_MASK_KEATON;
} else {
INV_CONTENT(ITEM_TRADE_CHILD) ^= ITEM_MASK_KEATON ^ ITEM_MASK_TRUTH;
}
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
}
for (uint16_t cSlotIndex = 0; cSlotIndex < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); cSlotIndex++) {
if (gSaveContext.equips.cButtonSlots[cSlotIndex] == SLOT_TRADE_CHILD) {
if (!LINK_IS_ADULT || CVarGetInteger("gTimelessEquipment", 0)) {
gSaveContext.equips.buttonItems[cSlotIndex+1] = INV_CONTENT(ITEM_TRADE_CHILD);
} else if (INV_CONTENT(ITEM_TRADE_CHILD) != gSaveContext.equips.buttonItems[cSlotIndex+1]) {
gSaveContext.equips.cButtonSlots[cSlotIndex] = SLOT_NONE;
gSaveContext.equips.buttonItems[cSlotIndex+1] = ITEM_NONE;
}
}
}
gSelectingMask = cursorSlot == SLOT_TRADE_CHILD;
gSlotAgeReqs[SLOT_TRADE_CHILD] = gItemAgeReqs[ITEM_MASK_BUNNY] =
((((CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && CVarGetInteger("gAdultBunnyHood", 0)) || CVarGetInteger("gTimelessEquipment", 0)) &&
INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_MASK_BUNNY)
? AGE_REQ_NONE
: AGE_REQ_CHILD;
}
if (IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE) &&
cursorSlot == SLOT_TRADE_ADULT && CHECK_BTN_ALL(input->press.button, BTN_A)) {
Audio_PlaySoundGeneral(NA_SE_SY_DECIDE, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
gSelectingAdultTrade = !gSelectingAdultTrade;
}
if (gSelectingAdultTrade) {
pauseCtx->cursorColorSet = 8;
if (((pauseCtx->stickRelX > 30 || pauseCtx->stickRelY > 30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT | BTN_DUP))) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
Inventory_ReplaceItem(play, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetNextAdultTradeItem());
} else if (((pauseCtx->stickRelX < -30 || pauseCtx->stickRelY < -30) ||
dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DDOWN))) {
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
Inventory_ReplaceItem(play, INV_CONTENT(ITEM_TRADE_ADULT), Randomizer_GetPrevAdultTradeItem());
}
gSelectingAdultTrade = cursorSlot == SLOT_TRADE_ADULT;
}
KaleidoScope_HandleItemCycles(play);
u16 buttonsToCheck = BTN_CLEFT | BTN_CDOWN | BTN_CRIGHT;
if (CVarGetInteger("gDpadEquips", 0) && (!CVarGetInteger("gDpadPause", 0) || CHECK_BTN_ALL(input->cur.button, BTN_CUP))) {
buttonsToCheck |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT;
@ -678,15 +770,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) {
}
}
// Adult trade item cycle
KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_ADULT, gSelectingAdultTrade,
IS_RANDO && Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE),
Randomizer_GetPrevAdultTradeItem(), Randomizer_GetNextAdultTradeItem());
// Child mask item cycle (mimics the left/right item behavior from the cycling logic above)
u8 childTradeItem = INV_CONTENT(ITEM_TRADE_CHILD);
KaleidoScope_DrawItemCycleExtras(play, SLOT_TRADE_CHILD, gSelectingMask, canMaskSelect,
childTradeItem <= ITEM_MASK_KEATON ? ITEM_MASK_TRUTH : childTradeItem - 1,
childTradeItem >= ITEM_MASK_TRUTH ? ITEM_MASK_KEATON : childTradeItem + 1);
KaleidoScope_DrawItemCycles(play);
CLOSE_DISPS(play->state.gfxCtx);
}
@ -694,8 +778,7 @@ void KaleidoScope_DrawItemSelect(PlayState* play) {
void KaleidoScope_SetupItemEquip(PlayState* play, u16 item, u16 slot, s16 animX, s16 animY) {
Input* input = &play->state.input[0];
PauseContext* pauseCtx = &play->pauseCtx;
gSelectingMask = false;
gSelectingAdultTrade = false;
KaleidoScope_ResetItemCycling();
if (CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) {
pauseCtx->equipTargetCBtn = 0;
@ -1080,8 +1163,3 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) {
}
}
}
void KaleidoScope_ResetTradeSelect() {
gSelectingMask = false;
gSelectingAdultTrade = false;
}

View File

@ -11,7 +11,6 @@ extern u8 gEquipAgeReqs[][4];
extern u8 gSlotAgeReqs[];
extern u8 gItemAgeReqs[];
extern u8 gAreaGsFlags[];
extern bool gSelectingMask;
#define MAP_48x85_TEX_WIDTH 48
#define MAP_48x85_TEX_HEIGHT 85
@ -50,6 +49,6 @@ void PauseMapMark_Draw(PlayState* play);
void KaleidoScope_UpdateCursorSize(PauseContext* pauseCtx);
void KaleidoScope_ResetTradeSelect();
void KaleidoScope_ResetItemCycling();
#endif

View File

@ -1008,7 +1008,7 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) {
PauseContext* pauseCtx = &play->pauseCtx;
s16 s;
s16 i;
gSelectingMask = false;
KaleidoScope_ResetItemCycling();
switch (pauseCtx->pageIndex) {
case PAUSE_ITEM:
@ -1042,7 +1042,6 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) {
void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) {
pauseCtx->unk_1E4 = 1;
pauseCtx->unk_1EA = 0;
gSelectingMask = false;
if (!pt) {
pauseCtx->mode = pauseCtx->pageIndex * 2 + 1;
@ -1074,7 +1073,7 @@ void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) {
gSaveContext.unk_13EA = 0;
Interface_ChangeAlpha(50);
KaleidoScope_ResetTradeSelect();
KaleidoScope_ResetItemCycling();
}
void KaleidoScope_HandlePageToggles(PauseContext* pauseCtx, Input* input) {
@ -3857,7 +3856,7 @@ void KaleidoScope_Update(PlayState* play)
}
}
KaleidoScope_ResetTradeSelect();
KaleidoScope_ResetItemCycling();
pauseCtx->state = 4;
break;