Jump to content

Useful Warps Hack


Jason777
 Share

Recommended Posts

I know of a lot of people who want to be able to use warps to travel from one area to another... and then they find out that exits and cutscenes are hardcoded and based on the scene you're currently in.

 

Well, this hack makes it so that you can specify which area and cutscene to warp to. All you simply have to do is...

  • Apply the patch
  • Place a warp actor (0x005D) on a map
  • Add the warp object (0x0048)
  • Modify the Y rotation to be the exit number you want
  • Modify the Z rotation to be the cutscene number you want (leave at 0x0000 if unsure)
For those of you who are asking "why couldn't you just make use of the variable instead?": there were issues with crashing. Besides that, there would be no reason to have to modify the Y or Z rotation value for the warp actor in a non-hacked ROM anyways. Also, even with the patch applied all original warps in-game should work just the same (not thoroughly tested).

 

 

The video above shows the result of...

  • Adding an actor and object to Hyrule Field via ZAO-ADD v1.3
  • Placing the warp actor and modifying the Y rotation via SceneNavi beta 8
(Old) V1: http://www.mediafire.com/download/58wnmjfm738obsy/warp_exit.ppf

(New) V2: http://www.cs.utexas.edu/~jason777/Modding/Zelda%2064/warp_exit/warp_exit_v2.ppf

 

Here's a little something extra that I thought would be neat to show: https://www.youtube.com/watch?v=9CKDmo2sJ6E#t=112

 

A note about cutscene values: values range from 0xFFF0 to 0xFFFA (I think), where 0xFFF0 is cutscene 0, 0xFFF1 is cutscene 1, 0xFFF2 is cutscene 2, and so on.

 

Notes and relevant data concerning hack: http://www.cs.utexas.edu/~jason777/Modding/Zelda%2064/warp_exit/

Exit list: http://wiki.cloudmodding.com/oot/Entrance_Table_(Data)

 

Partial credit goes to Airikita for pointing out some free space where I could extend the code to support cutscene values.

  • Like 2
Link to comment
Share on other sites

  • 2 months later...

I don't see why not; looking at the source reveals that cutscene values are stored as halfwords at 0x8015FA72 (0x80160000 + -1422). You can see instances of "sh t3,-1422($at)" and similar.

The only issue is making space for two more instructions to load the Z rotation and then store the cutscene value (I think).

Link to comment
Share on other sites

Or you can rewrite the code in the disassembled actor and re-assemble it after. That way you should have no trouble adding as much code as you need to.

What I suggested only needs a few lines, but okay, sure... if you think that's simpler? I don't think that's even a good idea, because disassembled and re-assembled actors will crash on console (likely) especially if it's spinout's tool.

Link to comment
Share on other sites

imo it's a whole lot simpler than having to manually update relocations data etc. but I didn't know about it crashing on a console, I never tried any actors out that I modified. I did hear that my boss rush hack mostly worked (most actors were modified this way) but I don't know.

Link to comment
Share on other sites

  • 1 month later...

Hey Jason777, I could work on the warp portal using z-rotation for storing a Cutscene value, unless you have this worked on?

 

I don't know what spare time I'll have, but I could tinker with it when I have more time. I'm sure I can find the right stuff if you could point me to where you modified the code to change the y rotation storage.

Link to comment
Share on other sites

I don't have much time to do it myself. In the mod source, there is a text document with notes that describe where I modified the actor to use Y rotation if it was not spawned by a boss. That area would be perfect to have the actor load Z rotation and establish cutscene values.

 

I would do it myself but the warp actor just so happens to be one of those few actors that have trouble recompiling -- they reference virtual addresses that are out of bounds or in the .bss section -- so inserting a couple more commands will be tedious without nOVL and zOVLDis. Besides that, it was already hard enough to make the hack without needing extra space.

Link to comment
Share on other sites

A thorough explanation of how the hack works...

 

If we look at the routine data_80999A68, specifically $L000046, we begin to see the logic that the warp applies when deciding the next exit.

It starts off by checking to see if the player is in Dodongo's Cavern Boss room. This, in way, is check to see if the player just faught King Dodongo. From here it decides to take exit 0x013D and cutscene 0x000F.

lh              v0,164(s0) // Load current scene number
li              $at,18
bnel            v0,$at,$L000049 // If current scene != Dodongo's Cavern Boss, goto $L000049
li              $at,17
jal             external_func_80035B4C // Seems to return something related to alternate headers or flags
li              a0,37
bne             v0,$zero,$L000050
li              t4,1146 // Exit 0x047A
jal             external_func_80035B74
li              a0,37
or              a0,s0,$zero
jal             external_func_80084D10
li              a1,109
lui             $at,0x1
addu            $at,$at,s0
li              t2,317 // Exit 0x013D
sh              t2,7706($at) // Set next exit
lui             $at,0x8016
li              t3,0xfff1 // Cutscene 0x000F (0xFFF1 = -0x000F)
b               $L000051 // Goto exit label
sh              t3,-1422($at) // Set next cutscene
We also see at $L000050 that exit 0x047A is taken. The conditional check in the above code snippet seems to have to do with event, scene, or map flags.

 

If the player wasn't in the Dodongo's Cavern Boss room, it checks to see if they were in the Deku Tree Boss room at $L000049. If so, it decides to take exit 0x00EE and cutscene 0x000F.

bnel            v0,$at,$L000052 // If current scene != Deku Tree Boss, goto $L000052
li              $at,19
jal             external_func_80035B4C // Seems to return something related to alternate headers or flags
li              a0,7
bne             v0,$zero,$L000053
li              t7,1111 // Exit 0x0457
jal             external_func_80035B74
li              a0,7
jal             external_func_80035B74
li              a0,9
or              a0,s0,$zero
jal             external_func_80084D10
li              a1,108
lui             $at,0x1
addu            $at,$at,s0
li              t5,238 // Exit 0x00EE
sh              t5,7706($at) // Set next exit
lui             $at,0x8016
li              t6,0xfff1 // Cutscene 0x000F (0xFFF1 = -0x000F)
b               $L000051 // Goto exit label
sh              t6,-1422($at) // Set next cutscene
We also see at $L000053 that exit 0x0457 is taken. The conditional check in the above code snippet seems to have to do with event, scene, or map flags.

 

If the player wasn't in the Deku Tree Boss room, it checks to see if they were in the Jabu Jabu's Belly Boss room at $L000052. If so, it decides to take exit 0x010E and cutscene 0x0000.

bne             v0,$at,$L000051 // If current scene != JabuJabu's Belly Boss, goto $L000051 (exit label)
li              t8,270 // Exit 0x010E
lui             $at,0x1
addu            $at,$at,s0
sh              t8,7706($at) // Set next exit
lui             $at,0x8016
sh              $zero,-1422($at) // Set next cutscene
There may be logic concerning using an alternate exit, check $L000060.

 

All other logic concerning exits in the elemental temples, can be seen in routine data_8099A5EC starting at $L000070. This routine is used before data_80999A68 and can be proven by tracing back function references.

By now we should have picked up where exits and cutscenes are stored:

  • Exit values can usually be found by looking for instances of ",7706(" and by looking at assembly beforehand, we can see that the exit number is stored at 0x80223E3A
  • Cutscene values can usually be found by looking for instances of ",-1422(" and by looking at assembly beforehand, we can see that the cutscene number is stored at 0x8015FA72
With this in mind, and the order of checks that warp makes when deciding the exit, we begin to devise our hack.
  • We don't want to interfere with any of the exits taken by boss warps so we should try to come up with an "else" statement where we apply our hack
  • Because I don't want to go through the headache of recompiling the warp actor and/or fixing reallocations through manual addition of code, we want to keep within the original size of the actor
Okay, so we see that $L000052 is the last check the actor makes before deciding the exit to take, this will be where we insert our "else" statement. Now we just need to find free space... well we're in luck because just above the start of $L000052 and in $L000053 we see this:
lui             $at,0x1
addu            $at,$at,s0
sh              t7,7706($at) // Set next exit
lui             $at,0x8016
b               $L000051 // Goto exit label
sh              $zero,-1422($at)
li              $at,19
It's a part of $L000053 where we are taken to exit 0x0457. It is branched to from $L000049 and most likely the result of alternate header or event flag checks.

 

What's so special about that code snippet? Well, with a little examination, we see that it makes an unconditional branch to $L000051 (which is a label where the warp is done deciding which exit to take), but that's besides that point. It's the code that follows immediately afterwards that's of interest:

b               $L000051 // Goto exit label
sh              $zero,-1422($at)
li              $at,19
We see in the delay slot (the instruction directly after the branch) that we set the cutscene number to 0x0000.

 

The delay slot may be in use, but the instruction directly after the delay slot is never executed at all. This gives us exactly 1 unused instruction. Now we change the original branch to $L000052 in $L000051 to this:

bnel            v0,$at,$L000052 - 1 // If current scene != Deku Tree Boss, goto one instruction before $L000052
This won't actually compile, it's just to help make things more easily readible.

 

So now we branch to the instruction located just before $L000052 which is:

li              $at,19
We're loading 19 into $at in order to make the scene number check at the start of $L000052.

 

Now we consider that the new start of $L000052. We replace the instruction there with a check to see if the player is in the Jabu Jabu's Belly Boss room:

bne             v0,$at,PC + 2 // If current scene != JabuJabu's Belly Boss, goto 2 opcodes ahead
This won't actually compile, it's just to help make things more easily readible. We jump two ahead because we still want to set an exit number.

 

Now we replace the instruction at the original start of $L000052 with an instruction that reads the actor's Y rotation into $t8:

bne             $t8,0x00B6(s1) // Load Y rotation of actor into $t8
From previous checks, it was concluded that at this point in the actor's code, register s1 contained the address of the actor panel.

 

Now the hack is complete. The way it works is that if the user is not in Jabu Jabu's Belly Boss room, it reads the Y rotation into $t8 and then merely skips the instruction that sets $t8 to exit 0x010E while continuing to execute the code in $L000052. If the user is in Jabu Jabu's Belly Boss room, then it still sets $t8 to the Y rotation of the actor but then $t8 is immediately overwritten with exit number 0x010E because the branch was not taken. Either way, the code for $L000052 is still executed. The logic can be written like so:

if (CURRENT_SCENE == JABU_JABU_BOSS)
{
  NEXT_EXIT = 0x010E;
}
else
{
  NEXT_EXIT = Y_ROTATION;
}
NEXT_CUTSCENE = 0x0000;
SetNextExit(NEXT_EXIT, NEXT_CUTSCENE);
Hopefully this pseudo-code clears things up for you.

 

In the end, here were the changes made to the actor file:

0x1438 : "54 41 00 1B" to "54 41 00 1A" <--- Changes a branch to $L000052 to branch to one opcode before $L000052
0x14A4 : "24 01 00 13" to "14 41 00 02" <--- Replaces an unused opcode located one opcode before $L000052 to a branch to 2 opcodes in front of it
0x14A8 : "14 41 00 06" to "86 38 00 B6" <--- Loads the Y rotation into t8
Now, I doubt you'll be able to optimize the code in the actor file to load the cutscene value from the Z rotation and still have the same file size, but this should have given you a good idea why $L000052 would be the best place to insert the hack. In the end, you should try to model the code to represent this:
if (CURRENT_SCENE == JABU_JABU_BOSS)
{
  NEXT_EXIT = 0x010E;
  NEXT_CUTSCENE = 0x0000;
}
else
{
  NEXT_EXIT = Y_ROTATION;
  NEXT_CUTSCENE = Z_ROTATION;
}
SetNextExit(NEXT_EXIT, NEXT_CUTSCENE);
Link to comment
Share on other sites

Oic, so it only works when not in a boss room. Well, that can make this easier for me then.

Yup, I wanted the warp hack to work with an original unmodified game without completely screwing over the boss warps. I haven't completely tested all the warps, but they should work (in theory).
  • Like 1
Link to comment
Share on other sites

I would totally understand it being that way. It really didn't make sense for the number to be 0xFFF1 and not be interpreted as a signed number so that's why I initially thought of it like that.

 

Also, in DeathBasket's Boss Rush hack, he would use a cutscene value of 0xFFEC to disable playing a cutscene.

Link to comment
Share on other sites

  • 10 months later...

EDIT:

New patch that allows cutscene values to specified in the Z-rotation: http://www.cs.utexas.edu/~jason777/Modding/Zelda%2064/warp_exit/warp_exit_v2.ppf

Notes and relevant data have been updated: http://www.cs.utexas.edu/~jason777/Modding/Zelda%2064/warp_exit/

 

I just exchanged some messages with Airikita briefly, and we extended the hack to where it reads cutscene values from the Z-rotation.

 

Apply the original patch and then write these next changes to the ROM:

 

@ 0x00D531D4 in ROM write...

10 00 00 2C
@ 0x00D531EC in ROM write...

10 00 00 26
@ 0x00D53244 in ROM write...

10 00 00 10
@ 0x00D5325C in ROM write...

10 00 00 0A
@ 0x00D53264 in ROM write...

86 2F 00 B8
14 22 00 03
86 38 00 B6
24 18 01 0E
24 0F 00 00
3C 01 80 22
A4 38 3E 3A
3C 01 80 16
A4 2F FA 72
3C 04 80 9A
A patch will be made if you all really need it.
Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.