Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,312 changes: 662 additions & 650 deletions ASM/build/asm_symbols.txt

Large diffs are not rendered by default.

Binary file modified ASM/build/bundle.o
Binary file not shown.
1,263 changes: 637 additions & 626 deletions ASM/build/c_symbols.txt

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions ASM/c/bg_treemouth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef BGTREEMOUTH_H
#define BGTREEMOUTH_H

#include "z64.h"

struct BgTreemouth;

typedef void (*BgTreemouthActionFunc)(struct BgTreemouth*, z64_game_t*);

typedef struct BgTreemouth {
/* 0x0000 */ DynaPolyActor dyna;
/* 0x0154 */ char unk_164[0x4];
/* 0x0158 */ float unk_168;
/* 0x015C */ BgTreemouthActionFunc actionFunc;
} BgTreemouth; // size = 0x0160

#endif
30 changes: 30 additions & 0 deletions ASM/c/en_md.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef ENMD_H
#define ENMD_H

#include "z64.h"

struct EnMd;

typedef void (*EnMdActionFunc)(struct EnMd*, z64_game_t*);

typedef struct EnMd {
/* 0x0000 */ z64_actor_t actor;
/* 0x013C */ SkelAnime skelanime;
/* 0x0180 */ EnMdActionFunc actionFunc;
/* 0x0184 */ ColliderCylinder collider;
/* 0x01D0 */ NpcInteractInfo interactInfo;
/* 0x01F8 */ uint8_t messageEntry; // tracks message state changes, like with `BOX_BREAK` or `TEXTID`
/* 0x01F9 */ uint8_t messageState; // last known result of `Message_GetState`
/* 0x01FA */ uint8_t animSequenceEntry; // each one changes animation info and waits
/* 0x01FB */ uint8_t animSequence;
/* 0x01FC */ int16_t blinkTimer;
/* 0x01FE */ int16_t eyeTexIndex;
/* 0x0200 */ int16_t alpha;
/* 0x0202 */ int16_t waypoint;
/* 0x0204 */ int16_t fidgetTableY[12];
/* 0x0226 */ int16_t fidgetTableZ[12];
/* 0x0248 */ z64_xyz_t jointTable[12];
/* 0x02AE */ z64_xyz_t morphTable[12];
} EnMd; // size = 0x0314

#endif
6 changes: 6 additions & 0 deletions ASM/c/get_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "actor.h"
#include "save.h"
#include "models.h"
#include "item_effects.h"

extern uint8_t SHUFFLE_CHEST_GAME;
extern uint8_t FAST_CHESTS;
Expand Down Expand Up @@ -475,6 +476,11 @@ void get_item(z64_actor_t* from_actor, z64_link_t* link, int8_t incoming_item_id
override = lookup_override(from_actor, z64_game.scene_index, item_id);
}

// Notify deku shield buy in shops.
if (from_actor->actor_id == 0x3D && incoming_item_id == GI_SHIELD_DEKU) {
handle_deku_shield(&z64_file, 0, 0);
}

if (override.key.all == 0) {
// No override, use base game's item code
clear_override();
Expand Down
81 changes: 81 additions & 0 deletions ASM/c/item_effects.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "trade_quests.h"
#include "bg_gate_shutter.h"
#include "save.h"
#include "en_md.h"
#include "bg_treemouth.h"

#define rupee_cap ((uint16_t*)0x800F8CEC)
volatile uint8_t MAX_RUPEES = 0;
Expand Down Expand Up @@ -264,6 +266,85 @@ void trade_quest_upgrade(z64_file_t* save, int16_t item_id, int16_t arg2) {
SaveFile_SetTradeItemAsOwned(item_id);
}


extern uint8_t FAST_FOREST;
extern uint8_t DUNGEONS_SHUFFLED;
extern BgTreemouthActionFunc OVL_BgTreemouth_func_808BC6F8;
extern EnMdActionFunc OVL_EnMd_Idle;
extern EnMdActionFunc OVL_EnMd_SetMovedPos;
// If we're in Kokiri Forest, either move Mido or open Deku Tree mouth according to age.
void move_mido_or_open_mouth() {
if (z64_game.scene_index == 0x55) {
if (LINK_IS_ADULT && DUNGEONS_SHUFFLED) {
// Loop through the actors looking for Deku tree mouth.
z64_actor_t* curr = z64_game.actorLists[ACTORCAT_BG].head;
while (curr != NULL) {
if (curr->actor_id == 0x003E) { // Check for Bg_Treemouth
BgTreemouth* DekuTreeMouth = (BgTreemouth*)curr;
// Not named yet in decomp but this is the function that opens the mouth in the early game cutscene.
BgTreemouthActionFunc func_808BC6F8 = resolve_overlay_addr(&OVL_BgTreemouth_func_808BC6F8, 0x003E);
func_808BC6F8(DekuTreeMouth, &z64_game);
break;
}
curr = curr->next;
}
}
else {
// Loop through the actors looking for Mido.
z64_actor_t* curr = z64_game.actorLists[ACTORCAT_NPC].head;
while (curr != NULL) {
if (curr->actor_id == 0x016D) { // Check for EN_Md
EnMd* Mido = (EnMd*)curr;
// First put his current action to Idle, else his Block action will still take effect.
Mido->actionFunc = resolve_overlay_addr(&OVL_EnMd_Idle, 0x016D);
// Then move him out.
EnMdActionFunc EnMd_SetMovedPos = resolve_overlay_addr(&OVL_EnMd_SetMovedPos, 0x016D);
EnMd_SetMovedPos(Mido, &z64_game);
break;
}
curr = curr->next;
}
}
}
}

void handle_kokiri_sword(z64_file_t* save, int16_t item_id, int16_t arg2) {

if (!FAST_FOREST) {
return;
}
bool mido_already_moved = save->event_chk_inf[0] & 0x10;
if (mido_already_moved) {
return;
}
// If no deku shield in inventory.
if (!CHECK_OWNED_EQUIP_ALT(1, 0)) {
return;
}

save->event_chk_inf[0] |= 0x10; // "Showed Mido Sword & Shield"

move_mido_or_open_mouth();
}

void handle_deku_shield(z64_file_t* save, int16_t item_id, int16_t arg2) {

if (!FAST_FOREST) {
return;
}
bool mido_already_moved = save->event_chk_inf[0] & 0x10;
if (mido_already_moved) {
return;
}
// If no kokiri sword in inventory.
if (!CHECK_OWNED_EQUIP_ALT(0, 0)) {
return;
}

save->event_chk_inf[0] |= 0x10; // "Showed Mido Sword & Shield"

move_mido_or_open_mouth();
}
void unlock_ocarina_note(z64_file_t* save, int16_t arg1, int16_t arg2) {
switch(arg1) {
case 0:
Expand Down
2 changes: 2 additions & 0 deletions ASM/c/item_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ void clear_excess_hearts(z64_file_t* save, int16_t arg1, int16_t arg2);
void open_gate_and_mask_shop(z64_file_t* save, int16_t arg1, int16_t arg2);
void give_bombchus(z64_file_t* save, int16_t arg1, int16_t arg2);
void trade_quest_upgrade(z64_file_t* save, int16_t item_id, int16_t arg2);
void handle_kokiri_sword(z64_file_t* save, int16_t arg1, int16_t arg2);
void handle_deku_shield(z64_file_t* save, int16_t arg1, int16_t arg2);
extern uint8_t KEYRING_BOSSKEY_CONDITION;
void unlock_ocarina_note(z64_file_t* save, int16_t arg1, int16_t arg2);

Expand Down
35 changes: 33 additions & 2 deletions ASM/c/item_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ item_row_t item_table[GI_RANDO_MAX] = {
[GI_EYE_DROPS] = ITEM_ROW(0x53, GILDED_CHEST, 0x36, -1, 0x000E, 0x013F, 0x52, no_upgrade, trade_quest_upgrade, 0x36, -1, NULL), // Eye Drops
[GI_CLAIM_CHECK] = ITEM_ROW(0x53, GILDED_CHEST, 0x37, -1, 0x000A, 0x0142, 0x55, no_upgrade, trade_quest_upgrade, 0x37, -1, NULL), // Claim Check

[GI_SWORD_KOKIRI] = ITEM_ROW(0x53, GILDED_CHEST, 0x3B, -1, 0x00A4, 0x018D, 0x74, no_upgrade, no_effect, -1, -1, NULL), // Kokiri Sword
[GI_SWORD_KOKIRI] = ITEM_ROW(0x53, GILDED_CHEST, 0x3B, -1, 0x00A4, 0x018D, 0x74, no_upgrade, handle_kokiri_sword, -1, -1, resolve_text_kokiri_sword), // Kokiri Sword
[GI_SWORD_KNIFE] = ITEM_ROW(0x53, GILDED_CHEST, 0x3D, -1, 0x004B, 0x00F8, 0x43, no_upgrade, no_effect, -1, -1, NULL), // Giant's Knife
[GI_SHIELD_DEKU] = ITEM_ROW(0x53, BROWN_CHEST, 0x3E, -1, 0x90AD, 0x00CB, 0x1D, no_upgrade, no_effect, -1, -1, NULL), // Deku Shield
[GI_SHIELD_DEKU] = ITEM_ROW(0x53, BROWN_CHEST, 0x3E, -1, 0x90AD, 0x00CB, 0x1D, no_upgrade, handle_deku_shield, -1, -1, resolve_text_deku_shield), // Deku Shield
[GI_SHIELD_HYLIAN] = ITEM_ROW(0x53, BROWN_CHEST, 0x3F, -1, 0x90AE, 0x00DC, 0x2C, no_upgrade, no_effect, -1, -1, NULL), // Hylian Shield
[GI_SHIELD_MIRROR] = ITEM_ROW(0x53, GILDED_CHEST, 0x40, -1, 0x004E, 0x00EE, 0x3A, no_upgrade, no_effect, -1, -1, NULL), // Mirror Shield
[GI_TUNIC_GORON] = ITEM_ROW(0x53, GILDED_CHEST, 0x42, -1, 0x90AF, 0x00F2, 0x3C, no_upgrade, no_effect, -1, -1, NULL), // Goron Tunic
Expand Down Expand Up @@ -469,3 +469,34 @@ uint16_t resolve_upgrades(override_t override) {
void call_effect_function(item_row_t* item_row) {
item_row->effect(&z64_file, item_row->effect_arg1, item_row->effect_arg2);
}

extern uint8_t FAST_FOREST;
uint16_t resolve_text_kokiri_sword(item_row_t* item_row, bool is_outgoing) {
if (!FAST_FOREST) {
return item_row->text_id;
}
bool mido_already_moved = z64_file.event_chk_inf[0] & 0x10;
if (mido_already_moved) {
return item_row->text_id;
}
// If Deku shield is in inventory, return alternate textbox to inform player that deku tree was opened automatically.
if (CHECK_OWNED_EQUIP_ALT(1, 0)) {
return 0x045E;
}
return item_row->text_id;
}

uint16_t resolve_text_deku_shield(item_row_t* item_row, bool is_outgoing) {
if (!FAST_FOREST) {
return item_row->text_id;
}
bool mido_already_moved = z64_file.event_chk_inf[0] & 0x10;
if (mido_already_moved) {
return item_row->text_id;
}
// If Kokiri sword is in inventory, return alternate textbox to inform player that deku tree was opened automatically.
if (CHECK_OWNED_EQUIP_ALT(0, 0)) {
return 0x045F;
}
return item_row->text_id;
}
2 changes: 2 additions & 0 deletions ASM/c/item_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,5 +397,7 @@ uint16_t resolve_text_silver_rupee_pouches(item_row_t* item_row, bool is_outgoin
uint16_t resolve_text_small_keys(item_row_t* item_row, bool is_outgoing);
uint16_t resolve_text_small_keys_cmg(item_row_t* item_row, bool is_outgoing);
uint16_t resolve_text_keyrings(item_row_t* item_row, bool is_outgoing);
uint16_t resolve_text_kokiri_sword(item_row_t* item_row, bool is_outgoing);
uint16_t resolve_text_deku_shield(item_row_t* item_row, bool is_outgoing);

#endif
8 changes: 8 additions & 0 deletions ASM/c/save.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@
#define DEFENSE_OFFSET OFFSETOF(z64_file_t, defense_hearts)
#define HEALTH_OFFSET OFFSETOF(z64_file_t, energy )

// Bit Flag array in which gBitFlags[n] is literally (1 << n)
uint32_t gBitFlags[] = {
(1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7),
(1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15),
(1 << 16), (1 << 17), (1 << 18), (1 << 19), (1 << 20), (1 << 21), (1 << 22), (1 << 23),
(1 << 24), (1 << 25), (1 << 26), (1 << 27), (1 << 28), (1 << 29), (1 << 30), (1 << 31),
};


extern uint8_t* collectible_override_flags;
extern uint16_t num_override_flags;
Expand Down
16 changes: 16 additions & 0 deletions ASM/c/z64.h
Original file line number Diff line number Diff line change
Expand Up @@ -1935,11 +1935,27 @@ typedef struct SkelAnime {
/* 0x1C */ char known_2_[0x28];
} SkelAnime; // size = 0x44

typedef struct NpcInteractInfo {
/* 0x00 */ int16_t talkState;
/* 0x02 */ int16_t trackingMode;
/* 0x04 */ int16_t autoTurnTimer;
/* 0x06 */ int16_t autoTurnState;
/* 0x08 */ z64_xyz_t headRot;
/* 0x0E */ z64_xyz_t torsoRot;
/* 0x14 */ float yOffset; // Y position offset to add to actor position when calculating angle to target
/* 0x18 */ z64_xyzf_t trackPos;
/* 0x24 */ char unk_24[0x4];
} NpcInteractInfo; // size = 0x28

// Bit Flag array in which gBitFlags[n] is literally (1 << n)
extern uint32_t gBitFlags[32];

/* helper macros */
#define LINK_IS_ADULT (z64_file.link_age == 0)
#define SLOT(item) gItemSlots[item]
#define INV_CONTENT(item) z64_file.items[SLOT(item)]
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define CHECK_OWNED_EQUIP_ALT(equip, value) (z64_file.equipment & gBitFlags[(value) + (equip) * 4])

/* dram addresses */
#define z64_EnItem00Action_addr 0x800127E0
Expand Down
3 changes: 3 additions & 0 deletions ASM/ootSymbols.ld
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,8 @@ gActorOverlayTable = 0x800E8530;
Message_CloseTextbox = 0x800d6218;
sSetupDL = 0x800f7d50;
Player_UseItem = 0x8038c9a0; /* 0x80834000 */
OVL_BgTreemouth_func_808BC6F8 = 0x808D5564;
OVL_EnOkarinaTag_Action2 = 0x80a872d0;
OVL_EnOkarinaTag_Action1 = 0x80a87088;
OVL_EnMd_SetMovedPos = 0x80AE3B0C;
OVL_EnMd_Idle = 0x80AE3EA8;
2 changes: 2 additions & 0 deletions ASM/src/config.asm
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ CFG_DUNGEON_PRECOMPLETED:
.endarea
DOT_CONDITION:
.byte 0x01
FAST_FOREST:
.byte 0x00
.align 4

; These configuration values are given fixed addresses to aid auto-trackers.
Expand Down
12 changes: 12 additions & 0 deletions Patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,18 @@ def calculate_traded_flags(world):
elif world.settings.zora_fountain == 'adult':
rom.write_byte(rom.sym('MOVED_ADULT_KING_ZORA'), 1)

if world.settings.open_forest == 'fast':
# If shield and sword already in inventory, just open Deku.
if 'Deku Shield' in world.settings.starting_items and 'Kokiri Sword' in world.settings.starting_items:
count_shield = world.settings.starting_items['Deku Shield']
count_sword = world.settings.starting_items['Kokiri Sword']
if count_shield.count > 0 and count_sword.count > 0:
save_context.write_bits(0xED5, 0x10) # "Showed Mido Sword & Shield"
else:
rom.write_byte(rom.sym('FAST_FOREST'), 1)
else:
rom.write_byte(rom.sym('FAST_FOREST'), 1)

# Make all chest opening animations fast
rom.write_byte(rom.sym('FAST_CHESTS'), int(world.settings.fast_chests))

Expand Down
5 changes: 5 additions & 0 deletions SettingsList.py
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,7 @@ class SettingInfos:
default = 'closed',
choices = {
'open': 'Open Forest',
'fast': 'Deku opens automatically',
'closed_deku': 'Closed Deku',
'closed': 'Closed Forest',
},
Expand All @@ -1238,6 +1239,10 @@ class SettingInfos:
Deku Tree, and the Kokiri boy no longer blocks the path
out of the forest.

'Deku opens automatically': Same as Closed Deku, but when
both Kokiri Sword and Deku Shield are found, Mido moves automatically,
and Deku Tree opens his mouth for adult in Dungeon Entrance rando.

'Closed Deku': The Kokiri boy no longer blocks the path
out of the forest, but Mido still blocks the path to the
Deku Tree, requiring Kokiri Sword and Deku Shield to access
Expand Down
3 changes: 2 additions & 1 deletion data/Glitched World/Overworld.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"region_name": "Root",
"hint": "ROOT",
"events": {
"Kakariko Village Gate Open": "open_kakariko == 'open' or (open_kakariko == 'zelda' and Zeldas_Letter)"
"Kakariko Village Gate Open": "open_kakariko == 'open' or (open_kakariko == 'zelda' and Zeldas_Letter)",
"Showed Mido Sword & Shield": "open_forest == 'fast' and Kokiri_Sword and Deku_Shield"
},
"locations": {
"Gift from Sages": "can_receive_ganon_bosskey"
Expand Down
3 changes: 2 additions & 1 deletion data/World/Overworld.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"region_name": "Root",
"hint": "ROOT",
"events": {
"Kakariko Village Gate Open": "open_kakariko == 'open' or (open_kakariko == 'zelda' and Zeldas_Letter)"
"Kakariko Village Gate Open": "open_kakariko == 'open' or (open_kakariko == 'zelda' and Zeldas_Letter)",
"Showed Mido Sword & Shield": "open_forest == 'fast' and Kokiri_Sword and Deku_Shield"
},
"locations": {
"Gift from Sages": "can_receive_ganon_bosskey"
Expand Down
2 changes: 1 addition & 1 deletion data/generated/patch_symbols.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading