Jump to content

Jason777's Hack Ideas


Jason777
 Share

Recommended Posts

This is basically a place that I'll go to to post ideas and or little bits of information that I'll probably be interested in using or creating in the near future. Basically, I usually forget about a lot of mildly good ideas and this is to combat that problem :P

 

For the moment, I have one particular thing in which I'm interested and currently creating... a new item which will yet again be paired with a regular item and equipped to the D-Pad.

 

Basically what it does is it is paired with the Mirror Shield. While the shield is equipped, if you press D-pad up once, it'll freeze all enemies within a 20 unit radius, mirror shield is replaced with a new shield, redead scream sound is played, and your magic slowly decreases. You press D-pad up again to unfreeze all actors and to get the mirror shield back to normal.

 

Medusa's Glare Basic Routine Breakdown:

if shield equipped is Mirror Shield...    
    if there is Magic...        
        if Magic Decrease Flag is not set (0x00)            
              if D-Pad Up is Pressed...                
                   Swap mirror shield display list with Medusa's Glare display list                                       Play Redead Scream Sound                
                   Freeze or Stun all actors within a 20 unit radius                
                   Set Magic Decrease Flag (0x01)            
                   return

        else if Magic Decrease Flag is set (0x01)            
              if D-Pad Up is Pressed...                
                   Swap Medusa's Glare display list with mirror shield display list                                       Unfreeze or "unstun" all actors currently in a frozen/stunned state                                    Clear Magic Decrease Flag (0x00)                
                   return

              Decrease Magic Amount            
              return

        else return

    else if there is no Magic...        
        if Magic Decrease Flag is set (0x01)            
             Swap Medusa's Glare display list with mirror shield display list            
             Unfreeze or "unstun" all actors currently in a frozen/stunned state            
             Clear Magic Decrease Flag (0x00)            
             return

        else return
RAM Addresses to work with:

80211174 -- Make any Non-Zero value to "freeze" all actors

8015E693 -- Magic amount

8001CE60 - 80157D90 -- code.zdata (to fix some display list pointers)

80223E0B -- Number of map actors (nulled after actors are spawned iirc)

80223E18 -- Pointer to map actor list with position/rotation of stuff

 

RAM Addresses/Functions that may need to be found are...

PlaySound Function -- to play Redead Scream

Shield Equipped Address -- to find out which shield is equipped

Stun Flag in actor -- In case the freeze all actors address doesn't work out as planned

 

Variables:

Magic Decrease Flag

 

...And I'll have to import a custom display list into object_link_boy :) So what this means is that I'll have to distribute this via patch if ever completed.

  • Like 1
Link to comment
Share on other sites

0x80211174 - This address is for all actors - including link. You'll have to go about "freezing" other actors another way.0x8002F828 - this is the function that plays sounds. Breakpoint it to get the arguments.As for another way to freeze actors, I would suggest perhaps modifying the logic which executes actor code. Actors, when running, have two chunks of code which are executed: logic and visuals. Execute logic only, they will be invisible, and execute visuals only, and they will stay still. I'm not sure on the details, but whatever parses the array of double linked lists of actors (http://wiki.spinout182.com/w/Actors#Loaded_Actors see "At 0x80213C50 within RAM..." ).If needed, give me a RAM dump with a few different kinds of actors loaded and I will analyze it and provide you with an example of how it works if the article I provided isn't sufficient.

Link to comment
Share on other sites

Thanks for the info, spinout, I wasn't sure how I would begin to look for the sound function other than looking an unknown/specific function call within a disassembled ReDead actor... so you saved me quite a bit of trouble there, thanks again.I'll be reading up on the documentation on loaded actors in the RAM, too.I was planning to spawn a deku nut instead of messing with the freeze all actors address but realized that deku nuts don't have the same effect on every enemy :)

Link to comment
Share on other sites

  • 1 month later...

I realized that people who might find this topic interesting might find the below quote and download to be somewhat useful. Also, you'll find some documentation on how z64-tex-ext works... Admins, be warned, there may be a few OoT Debug ROMs in there:

 

You really are taking on quite a bit of work, soulofdeity :P But it will be greatly appreciated and not in vain!

 

Alright, I just decided to throw everything in together... so basically, the download contains alot of C hacks and a few little personal notes. Disclaimer: not everything in the download works; for example, ovl_en_PZGD_mask doesn't work properly and neither does Sword_of_Sages.

 

The folder that you are interested in is "ovl_en_example", I decided to just release it in the simplest form possible-- it only contains code that is REQUIRED to have a working custom actor (except for the two lines of code that represent the main function):

 

http://www.mediafire.com/?x6qpj8kqsy9vzv5

 

NOTE: Compressed with 7-ZIP

Link to comment
Share on other sites

  • 2 weeks later...

So I realized that I never tried to code the Medusa's Glare hack mentioned earlier in the thread... Well, I took the day off and gave it a shot. It's a bit different than I imagined it and not everything I planned is in it, but it's not too bad. Little video of me showing off the way it works and some of the bugs:

 

 

Changes...

  • There is no ReDead sound. I put a BPX on the PlaySound function spinout mentioned earlier... and a break was going off every single frame and the parameters varied greatly. Perhaps another time.
  • Instead of all type 5 actors within a certain radius freezing, I couldn't get that to work since for some reason I couldn't read the pointers to the "next" actor correctly.
  • No display list shield swap for the Mirror Shield, you just press D-Pad Up. Since I couldn't get the audio to play, I felt like the whole point of doing this was lost :P
Instead we have...
  • Z-Target a certain actor. Press D-Pad Up and it freezes. Press D-Pad Up again and it unfreezes.
  • You can only freeze one actor at a time. So don't try freezing another actor while one actor is already frozen. It'll just unfreeze.
Bugs...
  • The timer is kinda buggy/shitty so you'll find yourself pressing D-Pad Up and nothing happens every now and then. I shouldn lengthen the wait timer but I really don't care.
  • Every now and then after freezing and unfreezing an actor, they can't harm you and/or you can't harm them. There's probably some code within that certain actor which reads if the "Logic" routine pointer is NULL and causes this effect.
Download: http://www.mediafire.com/?fy63l94ld22dq

(The file is called "Medusas_Glare.7z")

Link to comment
Share on other sites

  • 2 months later...

Alright, I have something else now... I wrote this while bored on an airplane and I still don't have any emulator to test it out on (N64iPhone can't handle this stuff), but it should work in theory. If not, well I'll give you all the information one would need (someone like DeathBasket, spinout, or sakura) to fix it! My god, assembly is a bitch compared to hacking with C. It also doesn't help that I tried to use as little registers as possible.

 

I don't have too much experience with assembly (this hack was for practice), so I can't really spot any errors right now (damn delay slot -.-) but I'm sure someone who is more knowledgable can. Alright, I present to you a semi-complete fix for being able to use both the Bow (including the magical arrows) and the Slingshot as Young Link!:

 

 

.ORG 0x801064B0
J 0x80600000

.ORG 0x80600000
LUI AT, 0x8016        # AT = 0x80160000
LW K1, 0xE664(AT)        # Load word @ 0x8015E664 into K1
BNE K1, R0, CLeft        # If word @ 0x8015E664 = 0x0000001, Jump to "CLeft" routine
LUI A3, 0x8060        # Delay Slot; A3 will be used for Jump Returns
B Exit            # In case you are Adult Link, exit routine
NOP

CLeft:            # C-Left; 0x80600018
LUI GP, 0x0002        # GP = C-Left Value
LB K1, 0xE6C9(AT)        # K1 = Item equipped to C-Left
B Check            # Unconditional branch to "Check" routine
ADDIU A3, A3, 0x0025        # Delay Slot; A3 = 0x80600028

CBottom:            # C-Bottom; 0x80600028
LUI GP, 0x0004        # GP = C-Bottom Value
LUI AT, 0x8016
LB K1, 0xE6CA(AT)        # K1 = Item equipped to C-Bottom
B Check            # Unconditional Branch to Check Routine
ADDIU A3, A3, 0x0014        # Delay Slot; A3 = 0x8060003C

CRight:            # C-Right; 0x8060003C
LUI GP, 0x0001        # GP = C-Right Value
LUI AT, 0x8016
LB K1, 0xE6CB(AT)        # K1 = Item equipped to C-Right
B Check            # Unconditional branch to "Check" routine
ADDIU A3, A3, 0x0014        # Delay Slot; A3 = 0x80600050

Exit:                # Exit; 0x80600050
MOVE GP, R0            # Clear GP
MOVE AT, R0            # Clear AT
ADDIU K1, R0, 0x0AAA    # Restore K1 back to 0x00000AAA
ADDIU A3, R0, 0x0003    # Restore A3 back to 0x00000003
JR RA
ADDIU T2, R0, 0x2000    # Delay Slot; Restore T2 back to 0x00002000

Check:
MOVE T2, R0            # Clear T2 for future use
ADDIU AT, K1, 0xFFFD    # 0xFFFFFFFD = -0x03 (Bow)
BEQ AT, R0, Bow
NOP 
ADDIU AT, K1, 0xFFFC    # 0xFFFFFFFC = -0x04 (Fire Arrows)
BEQ AT, R0, Fire
NOP
ADDIU AT, K1, 0xFFFA    # 0xFFFFFFFA = -0x06 (Slingshot)
BEQ AT, R0, Sling
NOP
ADDIU AT, K1, 0xFFF4    # 0xFFFFFFF4 = -0x0C (Ice Arrows)
BEQ AT, R0, Ice
NOP
ADDIU AT, K1, 0xFFEE    # 0xFFFFFFEE = -0x12 (Light Arrows)
BEQ AT, R0, Light
NOP
JR A3                # Jump to next C-button check or Exit routine (address in A3)
MOVE AT, R0            # Delay Slot; Clear AT register of previous value

Bow:
LUI K1, 0x0603        # K1 = 0x06030003
ADDIU K1, K1, 0xFE7D    # 0x06030003 + 0xFFFFFE7D = 0x0602FE80 (Bow FPS)
LUI T2, T2, 0x0603    # T2 = 0x06030000
ORI T2, T2, 0x0490    # T2 = 0x06030490 (Bow String)
LUI AT, 0x8016
LW AT, 0x6AF0(AT)        # AT = Button currently pressed
AND AT, AT, GP
BNE AT, R0, FixDisplay    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0002    # Delay Slot; AT = Regular Arrow Spawn (0x0002)
B ClearData            # Else, branch to "ClearData" routine
NOP

Fire:
LUI K1, 0x0603        # K1 = 0x06030004
ADDIU K1, K1, 0xFE7C    # 0x06030004 + 0xFFFFFE7C = 0x0602FE80 (Bow FPS)
LUI T2, T2, 0x0603    # T2 = 0x06030000
ORI T2, T2, 0x0490    # T2 = 0x06030490 (Bow String)
LUI AT, 0x8016
LW AT, 0x6AF0(AT)        # AT = Buttons currently pressed
AND AT, AT, GP
BNE AT, R0, FixDisplay    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0003    # Delay Slot; AT = Fire Arrow Spawn (0x0003)
B ClearData            # Else, branch to "ClearData" routine
NOP

Ice:
LUI K1, 0x0603        # K1 = 0x0603000C
ADDIU K1, K1, 0xFE74    # 0x0603000C + 0xFFFFFE74 = 0x0602FE80 (Bow FPS)
LUI T2, T2, 0x0603    # T2 = 0x06030000
ORI T2, T2, 0x0490    # T2 = 0x06030490 (Bow String)
LUI AT, 0x8016
LW AT, 0x6AF0(AT)        # AT = Button currently pressed
AND AT, AT, GP
BNE AT, R0, FixDisplay    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0004    # Delay Slot; AT = Ice Arrow Spawn (0x0004)
B ClearData            # Else, branch to "ClearData" routine
NOP

Light:
LUI K1, 0x0603        # K1 = 0x06030012
ADDIU K1, K1, 0xFE6E    # 0x06030012 + 0xFFFFFE6E = 0x0602FE80 (Bow FPS)
LUI T2, T2, 0x0603    # T2 = 0x06030000
ORI T2, T2, 0x0490    # T2 = 0x06030490 (Bow String)
LUI AT, 0x8016
LW AT, 0x6AF0(AT)        # AT = Button currently pressed
AND AT, AT, GP
BNE AT, R0, FixDisplay    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0005    # Delay Slot; AT = Light Arrow Spawn (0x0005)
B ClearData            # Else, branch to "ClearData" routine
NOP

Sling:
LUI K1, 0x0602        # K1 = 0x06020006
ADDIU K1, K1, 0x8042    # 0x06020006 + 0xFFFF8042 = 0x06018048 (Slingshot FPS)
LUI T2, T2, 0x0602    # T2 = 0x06020000
ORI T2, T2, 0x21A8    # T2 = 0x060221A8 (Slingshot String)
LUI AT, 0x8016
LW AT, 0x6AF0(AT)        # AT = Button currently pressed
AND AT, AT, GP
BNE AT, R0, FixDisplay    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0009    # Delay Slot; AT = Deku Seed Spawn (0x0009)
B ClearData            # Else, branch to "ClearData" routine
NOP

FixDisplay:
MOVE GP, R0            # Clear GP for future use
LUI GP, 0x8012        # GP = 0x80120000
SW K1, 0x5F3C(GP)        # Store FPS display list pointer in K1 @ 0x80125F3C
SW T2, 0x6144(GP)        # Store String display list pointer in T2 @ 0x80126144
LUI GP, 0x8017        # GP = 0x80170000                
B ClearData            # Unconditional branch to "ClearData" routine
SH AT, 0x8232(GP)        # Delay Slot; Store Projectile Spawn Actor variable in AT @ 0x80168232 

ClearData:
MOVE AT, R0            # Clear AT for future use
MOVE K1, R0            # Clear K1 for future use
MOVE T2, R0            # Clear T2 for future use
JR A3                # Jump to next C-button check or Exit routine (address in A3)
MOVE GP, R0            # Delay Slot; Clear GP for future use

 

 

Notes:

 

 

# 0x0602FE80 = Bow Display List
# 0x06030490 = Bow String Display List
# 0x06018048 = Slingshot Display List
# 0x060221A8 = Slingshot String Display List

# 0x80125F3C = Bow/Slingshot FPS Mode Pointer (RAM)
# 0x80126144 = Bow/Slingshot String Pointer (RAM)
# 0x00B9D0DC = Bow/Slingshot FPS Mode Pointer (ROM)
# 0x00B9D2E4 = Bow/Slingshot String Pointer (ROM)

# 0x8015E664 (word) = Link Age?
# 0x8015E667 (byte or bit) = Young Link Flag (0x01 for Young; 0x00 for Adult)

# 0x8015E6C9 = Left C-Button Item
# 0x8015E6CA - Bottom C-Button Item
# 0x8015E6CB - Right C-Button Item
# 0x03 = Bow
# 0x04 = Fire Arrows
# 0x06 = Slingshot
# 0x0C = Ice Arrows
# 0x12 = Light Arrows

# 0x00C0323A = Projectile Spawn Actor (ROM)
# 0x80168232 = Projectile Spawn Actor (RAM)
# 0x0009 = Deku Seeds
# 0x0002 = Regular Arrows
# 0x0003 = Fire Arrows
# 0x0004 = Ice Arrows
# 0x0005 = Light Arrows

# 0x8015E6EF = Arrow Amount
# 0x8015E6F2 = Deku Seed Amount

# 0x80166AF0 = Player 1
# 0x0001 = C-Right
# 0x0002 = C- Left
# 0x0004 = C-Bottom

# Hook @ 0x801064B0 = JR RA
# Free Registers = AT, S4, S5, S6, S7, S8, GP
# Non-Changing Registers = A0, A3, T0, T1, T2, S1, S3, K0, K1, RA
# A0 = 0x80146020
# A3 = 0x00000003
# T0 = 0x80002000
# T1 = 0x80001FF0
# T2 = 0x00002000
# S1 = 0x801666A0
# S3 = 0x80166668
# K0 = 0xA430000C
# K1 = 0x00000AAA
# RA = 0x800C8D7C
# Registers in Use = AT, GP, K1, A3, T2

 

 

More notes concerning how to change the arrow spawn variable before the ActorSpawn function is called...:

Some stuff from DeathBasket:

--------------------------------------------------------------------------------------------------------------

I've been looking into this further and it turns out that there seems to be an additional actor spawning function, or at least that I didn't know about. I just realised from actually looking at the function that it actually appears to set up the data for the actor spawn function before jumping to it.

80032458 = address of function
a0 = 80213C44
a1 = RAM address of 'parent' actor
a2 = 80212020
a3 = actor number
0x2A(SP) = variable
x,y and z positions should also be stored at some offset close to the variable.

Spawning arrows with the 'beta' variables just makes them look like fire arrows, but I haven't tested their effects on enemies. At the moment I'm just setting an execute breakpoint at 80032458 and changing the variable's value in memory. The variable seems to be determined by:
func_80834380:
    lui             t0,0x8016
    addiu           t0,t0,-6560
    lw              t6,4(t0)
    li              t7,3
    li              t4,6
    bne             t6,$zero,$L000141
    li              t5,9
    ..
from: http://spinout182.com/mqd/ovl_player_actor.S

 

Which is a check to see if Link is an adult (uses variable 0009 if he isn't, if he is it presumably goes on to determine which type of arrows are equipped). The variable is in register t5.

 

Relevant to the topic: You can make the slingshot shoot arrows with this information but it won't look good unless you give Young Link a bow. To make the slingshot shoot arrows, go to 0xC0323A in ROM and change 0009 to 0002. Arrows won't work properly as an adult anymore though, so you'll need a bit of assembly hacking to get around that.

--------------------------------------------------------------------------------------------------------------

 

Some stuff from me (Jason777):

--------------------------------------------------------------------------------------------------------------

Looking at the routine at 0x80032458, we see how it sets up data to call the actor

spawn function for arrow spawning...

 

0x80032470 : LH T9, 0x005A (SP)
# And later we see...
# 0x80031F50 = ActorSpawn function
# SP + 0x0024 = Actor variable argument
0x800324A4 : JAL 0x80031F50
0x800324A8 : SW T9, 0x0024(SP)

# After putting a BPX on 0x80032470...
# SP = 801681D8
# T9 = halfword @ 0x80168232 (0x801681D8 + 0x005A)
# T9 = Arrow variable
0x80032470: LH T9, 0x005A (SP)

# So, I went to 0x80168232 and sure enough, the arrow variable was stored there...

The only problem is... 0x80168232 only contains the arrow's variable whenever

you're about to shoot it. I think I have to fix the hook...

--------------------------------------------------------------------------------------------------------------

 

I can see some problems arrising from my hook, seeing as how the arrow actor variable at 0x80168232 is only present as you're about to shoot the arrow and before the actor spawn function is called. However, the hook I have right now executes my hack every frame so it may not be a problem... I currently don't have an emulator to test this hack out on right now nor do I have a way to assemble this into a GS code.

 

Also, as you can see, in order to adapt this hack to work with your own display list ports, you would have to change a few LUI/ADDIU or LUI/ORI pairs in the hack since I use these offsets as my display lists:

# 0x0602FE80 = Bow Display List
# 0x06030490 = Bow String Display List
# 0x06018048 = Slingshot Display List
# 0x060221A8 = Slingshot String Display List
^^ Those instructions I am referring to, are in the last few labels: Bow, Fire, Ice, Light, Sling.

 

Things that I haven't put into the hack yet, that should be noted:

  • Firing an arrow decreases the deku seed amount.
  • Firing a magical arrow doesn't decrease the magic amount.
ENJOY :) Also, can anybody give me some pointers on writing cleaner assembly? I don't quite get how the delay slot is used (if the condition isn't met, doesn't skip the instructions in the delay slot?) and if I can use the JR opcode the way I am using it in the hack (I use "JR A3" instead of the usual "JR RA").
Link to comment
Share on other sites

I don't quite get how the delay slot is used (if the condition isn't met, doesn't skip the instructions in the delay slot?) and if I can use the JR opcode the way I am using it in the hack (I use "JR A3" instead of the usual "JR RA").

 

Whether or not the instruction in the delay slot executes depends on the branch instruction. Branch instructions ending in l (ex. beql) will only execute what is in the delay slot if the condition is met, branch instructions not ending in l will always execute what is in the delay slot.

You can use the jr instruction like that, yes.

 

Also, as you can see, in order to adapt this hack to work with your own display list ports, you would have to change a few LUI/ADDIU or LUI/ORI pairs in the hack since I use these offsets as my display lists:

# 0x0602FE80 = Bow Display List
# 0x06030490 = Bow String Display List
# 0x06018048 = Slingshot Display List
# 0x060221A8 = Slingshot String Display List
^^ Those instructions I am referring to, are in the last few labels: Bow, Fire, Ice, Light, Sling.

 

You could always do something like:

#define bow_dl 0x0602FE80

...

li t0, bow_dl
Then if somebody had the code, they'd only need to change that line to adapt it for their own purposes.

 

A few tips: Since you added your code at the end of a function that doesn't seem to be returning anything, you should be able to use all v, a, t and f registers without messing anything up. t registers can always be used freely if you are putting code at the start or end of a function. You also don't need to set registers to zero before using them unless they needed to be zero in the first place. ex.

MOVE GP, R0 # Clear GP for future use
LUI GP, 0x8012 # GP = 0x80120000
You only needed the second line since gp would be set to 0x80120000 regardless of what it already was.
Link to comment
Share on other sites

 

Whether or not the instruction in the delay slot executes depends on the branch instruction. Branch instructions ending in l (ex. beql) will only execute what is in the delay slot if the condition is met, branch instructions not ending in l will always execute what is in the delay slot.

You can use the jr instruction like that, yes.

 

Thanks for clearing that up, it was bothering me whenever I came to the situation where I could reduce the amount of code by putting an instruction in the delay slot and not knowing if that code would execute whether or not the condition was met.

 

You could always do something like:

#define bow_dl 0x0602FE80

...

li t0, bow_dl
Then if somebody had the code, they'd only need to change that line to adapt it for their own purposes.

 

I was thinking about that, and decided to try to not use any psuedo-opcodes like "la" and "li". However, I did use the "b" opcode because I was lazy :P They are psuedo-opcodes, yes?

 

A few tips: Since you added your code at the end of a function that doesn't seem to be returning anything, you should be able to use all v, a, t and f registers without messing anything up. t registers can always be used freely if you are putting code at the start or end of a function. You also don't need to set registers to zero before using them unless they needed to be zero in the first place. ex.

MOVE GP, R0 # Clear GP for future use
LUI GP, 0x8012 # GP = 0x80120000
You only needed the second line since gp would be set to 0x80120000 regardless of what it already was.

 

So you're saying that registers will clear their value when a branch occurs? The reason I thought I had to clear the GP value before moving on is because I assumed that it would preserve its previous value across a branch. This is what I mean:

 

# I am assuming that the button value GP has is C-left (0x0002)
Bow:
LUI K1, 0x0603          # K1 = 0x06030003 (Before we got to this area of code, K1 was equal to 0x03)
ADDIU K1, K1, 0xFE7D    # 0x06030003 + 0xFFFFFE7D = 0x0602FE80 (Bow FPS)
LUI T2, T2, 0x0603      # T2 = 0x06030000
ORI T2, T2, 0x0490      # T2 = 0x06030490 (Bow String)
LUI AT, 0x8016
LW AT, 0x6AF0(AT)               # AT = Button currently pressed
AND AT, AT, GP
BNE AT, R0, FixDisplay  # If button value stored in GP is pressed, branch to FixDisplay (now AT and GP equal 0x00020000)
ADDIU AT, R0, 0x0002    # Delay Slot; AT = Regular Arrow Spawn (0x0002)
B ClearData                     # Else, branch to "ClearData" routine (^^ AT = 0x0002 and GP = 0x00020000) 
NOP

...

# Assuming the button was pressed...
# GP = 0x00020000
# AT = 0x00000002
FixDisplay:
MOVE GP, R0                     # Clear GP for future use (or else the next line may change.... wait, shit -.-)
# ^^ I just realized that GP had an the 0x0002 in the upper immediate; this means the next line would overwrite that value
LUI GP, 0x8012          # GP = 0x80120000
SW K1, 0x5F3C(GP)               # Store FPS display list pointer in K1 @ 0x80125F3C
SW T2, 0x6144(GP)               # Store String display list pointer in T2 @ 0x80126144
LUI GP, 0x8017          # GP = 0x80170000                               
B ClearData                     # Unconditional branch to "ClearData" routine
SH AT, 0x8232(GP)               # Delay Slot; Store Projectile Spawn Actor variable in AT @ 0x80168232 (AT = 0x0002)

...

# Assuming the button wasn't pressed...
# GP = 0x00020000
# AT = 0x00000002
ClearData:
MOVE AT, R0                     # Clear AT for future use
MOVE K1, R0                     # Clear K1 for future use
MOVE T2, R0                     # Clear T2 for future use
JR A3                           # Jump to next C-button check or Exit routine (address in A3)
MOVE GP, R0                     # Delay Slot; Clear GP for future use
^^ If what all your saying is true (and I hope it is), I can cut the length of the code quite significantly o:

 

Thanks for the help and tips. Hmmm... I'll be studying over this.

Link to comment
Share on other sites

So you're saying that registers will clear their value when a branch occurs? The reason I thought I had to clear the GP value before moving on is because I assumed that it would preserve its previous value across a branch.

No. Registers never clear themselves. What I am saying is that you don't need to initialise a register before putting a number in it. A register can have any value in it but if you use an instruction like lui, li, la, etc. it's the same as saying register = constant, so there is no need to clear the register first.

 

ex.

lw	 a0, 0 ($sp) //a0 here could be anything (a0 = *sp)
li	 a0, 255 //now a0 = 255, since this is the same as addiu a0, $zero, 255 (a0 = 0 + 255)
lui     a0, 0x8016 //now a0 = 0x80160000

I guess what I'm trying to say is that these instructions will ignore what was already in the register and just set it equal to whatever value you gave them, which is what you seem to be confused about. There is never any need to set it to zero before putting another number in it.

 

LUI K1, 0x0603		 # K1 = 0x06030003 (Before we got to this area of code, K1 was equal to 0x03)
ADDIU K1, K1, 0xFE7D # 0x06030003 + 0xFFFFFE7D = 0x0602FE80 (Bow FPS)

Now you should see that this piece of code would give k1 = 0x0602FE7D, not k1 = 0x0602FE80, since the first line set k1 to be 0x06030000.

 

Also, pseudo-instructions are useful because they make writing the code easier and quicker so there's not really any point in avoiding them. move is a pseudo-instruction too, by the way (r1 = r2 | 0 / or r1,r2,$zero).

Link to comment
Share on other sites

 

 

No. Registers never clear themselves. What I am saying is that you don't need to initialise a register before putting a number in it. A register can have any value in it but if you use an instruction like lui, li, la, etc. it's the same as saying register = constant, so there is no need to clear the register first.

 

ex.

lw     a0, 0 ($sp) //a0 here could be anything (a0 = *sp)
li     a0, 255 //now a0 = 255, since this is the same as addiu a0, $zero, 255 (a0 = 0 + 255)
lui     a0, 0x8016 //now a0 = 0x80160000

I guess what I'm trying to say is that these instructions will ignore what was already in the register and just set it equal to whatever value you gave them, which is what you seem to be confused about. There is never any need to set it to zero before putting another number in it.

 

LUI K1, 0x0603         # K1 = 0x06030003 (Before we got to this area of code, K1 was equal to 0x03)
ADDIU K1, K1, 0xFE7D # 0x06030003 + 0xFFFFFE7D = 0x0602FE80 (Bow FPS)

Now you should see that this piece of code would give k1 = 0x0602FE7D, not k1 = 0x0602FE80, since the first line set k1 to be 0x06030000.

 

Also, pseudo-instructions are useful because they make writing the code easier and quicker so there's not really any point in avoiding them. move is a pseudo-instruction too, by the way (r1 = r2 | 0 / or r1,r2,$zero).

 

Awesome! I can reduce the number of lines of code by a shitload now :D Thanks again.

Link to comment
Share on other sites

UPDATE:

 

Alright, I've hopefully fixed the hack and will assemble it into a GS code later (did you know that the iPhone has GCC tools on it?). Of course, there's still a few areas where I could shorten the code, but I really don't feel like it now...:

.ORG 0x801064B0
J 0x80600000

.ORG 0x80600000
LUI AT, 0x8016        # AT = 0x80160000
LW K1, 0xE664(AT)    # Load word @ 0x8015E664 into K1
BNE K1, R0, CLeft    # If word @ 0x8015E664 = 0x0000001, Jump to "CLeft" routine
LUI A3, 0x8060        # Delay Slot; A3 will be used for Jump Returns
B Exit            # In case you are Adult Link, exit routine
NOP

CLeft:            # C-Left; 0x80600018
LUI GP, 0x0002        # GP = C-Left Value
LB K1, 0xE6C9(AT)    # K1 = Item equipped to C-Left
B Check            # Unconditional branch to "Check" routine
ADDIU A3, 0x0025    # Delay Slot; A3 = 0x80600028

CBottom:        # C-Bottom; 0x80600028
LUI GP, 0x0004        # GP = C-Bottom Value
LUI AT, 0x8016        # AT = 0x80160000
LB K1, 0xE6CA(AT)    # K1 = Item equipped to C-Bottom
B Check            # Unconditional Branch to Check Routine
ADDIU A3, 0x0014    # Delay Slot; A3 = 0x8060003C

CRight:            # C-Right; 0x8060003C
LUI GP, 0x0001        # GP = C-Right Value
LUI AT, 0x8016        # AT = 0x80160000
LB K1, 0xE6CB(AT)    # K1 = Item equipped to C-Right
B Check            # Unconditional branch to "Check" routine
ADDIU A3, 0x0014    # Delay Slot; A3 = 0x80600050

Exit:            # Exit; 0x80600050
MOVE GP, R0        # Clear GP
MOVE AT, R0        # Clear AT
ADDIU K1, R0, 0x0AAA    # Restore K1 back to 0x00000AAA
ADDIU A3, R0, 0x0003    # Restore A3 back to 0x00000003
JR RA
ADDIU T2, R0, 0x2000    # Delay Slot; Restore T2 back to 0x00002000

Check:
ADDIU AT, K1, 0xFFFD    # 0xFFFFFFFD = -0x03 ()
BEQ AT, R0, Arrow
NOP
ADDIU AT, K1, 0xFFFC    # 0xFFFFFFFC = -0x04 (Fire Arrows)
BEQ AT, R0, Fire
NOP
ADDIU AT, K1, 0xFFFA    # 0xFFFFFFFA = -0x06 (Slingshot)
BEQ AT, R0, Sling
NOP
ADDIU AT, K1, 0xFFF4    # 0xFFFFFFF4 = -0x0C (Ice Arrows)
BEQ AT, R0, Ice
NOP
ADDIU AT, K1, 0xFFEE    # 0xFFFFFFEE = -0x12 (Light Arrows)
BEQ AT, R0, Light
NOP
JR A3            # Jump to next C-button check or Exit routine (address in A3)
NOP

Arrow:
LUI AT, 0x8016        # AT = 0x80160000
LW AT, 0x6AF0(AT)    # AT = Buttons currently pressed
AND AT, AT, GP        # AT &= GP
BNE AT, R0, BowSetup    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0002    # Delay Slot; AT = Regular Arrow Spawn (0x0002)
JR A3            # Else, jump to next C-button check or Exit routine (address in A3)
NOP

Fire:
LUI AT, 0x8016        # AT = 0x80160000
LW AT, 0x6AF0(AT)    # AT = Buttons currently pressed
AND AT, AT, GP        # AT &= GP
BNE AT, R0, BowSetup    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0003    # Delay Slot; AT = Fire Arrow Spawn (0x0003)
JR A3            # Else, jump to next C-button check or Exit routine (address in A3)
NOP

Ice:
LUI AT, 0x8016        # AT = 0x80160000
LW AT, 0x6AF0(AT)    # AT = Buttons currently pressed
AND AT, AT, GP        # AT &= GP
BNE AT, R0, BowSetup    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0004    # Delay Slot; AT = Ice Arrow Spawn (0x0004)
JR A3            # Else, jump to next C-button check or Exit routine (address in A3)
NOP

Light:
LUI AT, 0x8016        # AT = 0x80160000
LW AT, 0x6AF0(AT)    # AT = Buttons currently pressed
AND AT, AT, GP        # AT &= GP
BNE AT, R0, BowSetup    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0005    # Delay Slot; AT = Light Arrow Spawn (0x0005)
JR A3            # Else, jump to next C-button check or Exit routine (address in A3)
NOP

Sling:
LUI K1, 0x0602        # K1 = 0x06020000
ADDIU K1, K1, 0x8048    # 0x06020000 + 0xFFFF8048 = 0x06018048 (Slingshot FPS)
LUI T2, T2, 0x0602    # T2 = 0x06020000
ORI T2, T2, 0x21A8    # T2 = 0x060221A8 (Slingshot String)
LUI AT, 0x8016        # AT = 0x80160000
LW AT, 0x6AF0(AT)    # AT = Buttons currently pressed
AND AT, AT, GP        # AT &= GP
BNE AT, R0, FixDisplay    # If button value stored in GP is pressed, branch to FixDisplay
ADDIU AT, R0, 0x0009    # Delay Slot; AT = Deku Seed Spawn (0x0009)
JR A3            # Else, jump to next C-button check or Exit routine (address in A3)
NOP

BowSetup:
LUI K1, 0x0603        # K1 = 0x06030000
ADDIU K1, K1, 0xFE80    # 0x06030000 + 0xFFFFFE80 = 0x0602FE80 (Bow FPS)
LUI T2, T2, 0x0603    # T2 = 0x06030000
B FixDisplay        # Unconditional branch to "FixDisplay" routine
ORI T2, T2, 0x0490    # Delay Slot; T2 = 0x06030490 (Bow String)

FixDisplay:
LUI GP, 0x8012        # GP = 0x80120000
SW K1, 0x5F3C(GP)    # Store FPS display list pointer in K1 @ 0x80125F3C
SW T2, 0x6144(GP)    # Store String display list pointer in T2 @ 0x80126144
LUI GP, 0x8017        # GP = 0x80170000                
JR A3            # Jump to next C-button check or Exit routine (address in A3)
SH AT, 0x8232(GP)    # Delay Slot; Store Projectile Spawn Actor variable in AT @ 0x80168232

EDIT:

Gah, with the syntax that mips-as uses, it'll take a while before I turn this into a GS code -.-

Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

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