Points of Required Attention™
Please chime in on a proposed restructuring of the ROM hacking sections.
Views: 88,434,105
Main | FAQ | Uploader | IRC chat | Radio | Memberlist | Active users | Latest posts | Calendar | Stats | Online users | Search 04-19-24 03:16 AM
Guest: Register | Login

0 users currently in ROM Hacking | 1 guest

Main - ROM Hacking - Zelda 2 restart from current palace after game over New thread | New reply


njosro
Posted on 05-15-14 06:16 PM (rev. 8 of 05-20-14 01:39 AM) Link | Quote | ID: 156541


Goomba
Level: 13

Posts: 1/27
EXP: 8448
Next: 1819

Since: 05-15-14

Last post: 2532 days
Last view: 2270 days
This is my first post(!), my first time doing real ASM hacking, and the first time I really come to appreciate the tools FCEUX provides.

I heard about someone making it so that you start where you died if you were in a palace in zelda 2, instead of being sent allll the way back to zelda's castle. I never saw anything come of it though, so I decided to try for myself. I figured I could exploit the fact that the game has a real continue option for the great palace.

This is when I discovered how magical fceux is.

I used the code/data logger in conjunction with the trace logger to narrow my search for the relevant code. It took a few tries, but eventually I found it! The debugger was incredibly helpful in making the code understandable with the symbolic names and all that. ...sorry if I'm rambling about stuff you already know about!

So this is what I found:

Let's start with relevant RAM addresses. Naming these and finding their functions were the preliminary steps.
$0700 - lives left
$0701 - how Link enters the screen
$0706 - overworld index (0=west hyrule, 1=death mtn/maze island, 2=east hyrule)
$0707 - "world" (0=caves, enemy encounters...; 1=west hyrule towns; 2=east hyrule towns; 3=palace 1,2,5 ; 4=palace 3,4,6 ; 5=great palace)
$0736 - screen intro type
$0748 - area location index (the index of the spot on the overworld that pulled you into the sideview)
$075C - start this many 'pages' into the scene
$075F - something to do with music
$0760 - I don't know... freezing it doesn't affect anything anywhere but it's in the code so... yeah
$0561 - scene layout index (doesn't affect location)
$076C - begin a special routine. Changing this value has the most 'automation' (00=restart from zelda's castle with 3 lives, 01=no routine, 02=die, 03=wake up zelda, 04=roll credits, 06=show the lives then restart the scene)

Okay now for the the ASM code. It starts at CF30, but of course in the file it's really at 1CF40.

LDA $0706
ASL
ASL
ADC $0706
ADC $0707
RTS

;returns to CAD3:

CMP #$0F
BEQ $CADE
LDA #$00
LDY #$01
JMP $CAF0
JSR $C358 -------------> LDA #$03
LDA #$00 STA $0700
STA $0561 INC $0760
STA $0701 INC $076C
STA $075C RTS
LDA #$01
LDY #$02
STA $076C
STY $075F
RTS

So it calculates with a formula whether to send you back to the beginning or keep you in the same "world". Here's my little pseudocode describing the situation.
if (overworld_index*4+overworld_index+world = $F)
{
lives=3
???++
special_routine++
scene_index=0 //return to the palace entrance
Link_entrance_type=0 //walk in from the left
pages_into_scene=0
special_routine=1 //don't do any special routine
change_music=2
}
else
{
special_routine=0 //go back to zelda's castle. This sets a bunch of ram addresses automatically.
change_music=1
}

My first step was to make it so that you stay in the current world no matter which palace you're in. So I changed the condition for branching.

LDA $0706
RTS

;returns to CAD3

CMP #$03
BCS $CADE

(if you're in any world >= 3, you're in a palace so don't start over)
And it worked!! ... except it always sets scene_index (ram $561) to 0, so if you're in the ocean palace, for example, you'll be sent to scene 0 of that world which is the entrance to parapa palace! But the palette stays green, and your location on the overworld is fine.

At this point I thought I was in over my head, beyond my capabilities. I was really nervous about injecting my own routine instead of just manipulating what's already there!
First I had to figure out how to get a unique number identifier for each palace, since I couldn't find one already in the game. I took the area location index ($748), world ($707), and overworld index ($706) of each palace and tried to see what I could do with that. After playing around a bit, I got a unique number for each one. It could probably be better, but this one works:

overworld_index*4 + world + area_location_index = the palace id (sure why not)

4 is the smallest multiplier that prevents non-unique numbers for each palace.

Now I needed a place to store the corresponding scene indices in RAM. I found a spot with a bunch of zeros and I'm hoping that it isn't used for anything important It's around $6500. I think that's near the SRAM?
I also needed a place in ROM to put my code that would load the scene index from the correct RAM address. I found a bunch of FF's (undefined opcodes) in the debugger and stupid me thought it would be plenty of room for everything! (thinking 1 byte = room for a whole opcode and operand(s)) The FF's start at $D39A in rom. I just barely made it, in terms of available bytes. (2 bytes to spare!)

At $CADE in rom I changed the JSR location from $C358 (the subroutine in bold from above) to $D39A (the FF's). At $D39A:

JSR $C358 ;We still need to execute the subroutine that was there before
;now storing each scene_index value in appropriate RAM as (I the human) computed by the math formula using $64D0 as base address.
LDA #$00
STA $6507 ;lookup location for parapa palace
STA $650A ;lookup location for 'red' palace
LDA #$0E
STA $6508 ;lookup location for swamp palace
LDA #$0F
STA $650C ;lookup location for 'purple' palace
LDA #$23
STA $650F ;lookup location for ocean palace
LDA #$24
STA $6511 ;lookup location for hidden palace
;retrieving the correct scene_index value from RAM. The game computes the lookup address using the math formula this time.
LDA $0706
ASL
ASL
ADC $0707
ADC $0748
TAY
LDA $4060, Y
RTS

(the code then returns to that LDA #$00 statement, but I don't want A to be overwritten so I just changed it to LDY)

I don't have an assembler and I don't know how to access fceux's inline assembler if it has one, so doing this by hand in the hex editor took a little while. (Good old pen and paper planning!)
I gulped, started the game, went into the 'purple' palace and continued from a gameover. Annnnd.... (play 'item found' sound) it works!!!! For every single palace without a glitch!

And then I realized I didn't code any scene_index lookup location for the great palace
But lucky me, the spot in RAM that gets looked up for the great palace is unused (I hope) and always = 00 which is correct!

So... wow, I actually did it. Hopefully without inadvertently causing problems somewhere else. I don't really know how to make an ips patch, but if anyone's interested I could try making one I posted it below.

video!
https://www.youtube.com/watch?v=4PWFpUTDwK4

patch!
http://acmlm.kafuka.org/uploader/get.php?id=4629

EDIT: a glitch was fixed. The link now takes you to the new patch.
EDIT2: the glitch was fixed properly this time and works without causing problems elsewhere in the game (finally!)

Chaobomr
Posted on 05-15-14 09:43 PM Link | Quote | ID: 156543


Buster Beetle
Banned: Spammer takeover?
Level: 45

Posts: 319/467
EXP: 638211
Next: 21953

Since: 05-07-13
From: The dirty south

Last post: 3473 days
Last view: 3471 days
That's easy! You take an IPS Patcher (I'm gonna say Lunar IPS), and click on the option that essentially says "Create Patch." Then you go through the steps that the patcher tells you and voila! You have created an IPS! You can then upload that sucker here using that "Uploader" up there or right here, and post it using the <a href=""></a> or [url] tags.

____________________
Sorry for the stupidity. That jerk will be dealt with in the most insane way possible.

njosro
Posted on 05-16-14 12:29 AM Link | Quote | ID: 156544


Goomba
Level: 13

Posts: 2/27
EXP: 8448
Next: 1819

Since: 05-15-14

Last post: 2532 days
Last view: 2270 days
Oh cool I didn't think it would be that simple.
Ok, I'll edit my post above to include the patch.

If anyone can think of a way to improve my code or to expand on it, let me know!

Vanya
Posted on 05-16-14 03:27 AM Link | Quote | ID: 156545


Red Koopa
Level: 27

Posts: 51/139
EXP: 104994
Next: 11165

Since: 01-22-13

Last post: 3286 days
Last view: 3285 days
Sweet! This is a great patch for people like me that have always been turned off by this one incredibly annoying 'feature' of Zelda II.

____________________
Krakenskin Leather Works, my Etsy store.
LordVanya, my art page.
FundamentalEssence, my game development page.

njosro
Posted on 05-17-14 07:19 AM Link | Quote | ID: 156554


Goomba
Level: 13

Posts: 3/27
EXP: 8448
Next: 1819

Since: 05-15-14

Last post: 2532 days
Last view: 2270 days
Ok so I did a whole playthrough of the game with my patch applied and everything worked completely fine until the very end... the game froze just as Thunderbird was about to die! > Also the continue feature might mess up in the great palace. Luckily I was able to find the opcodes causing the problems. I messed around with a few values because I was getting desperate and luckily got it to work. Thunderbird dies and if you die in the great palace you can continue glitch-free. That is, unless this new patch causes something else to go wrong. If anyone finds a new glitch, let me know.

Updated my first post with the new patch.

njosro
Posted on 05-20-14 01:45 AM Link | Quote | ID: 156570


Goomba
Level: 13

Posts: 4/27
EXP: 8448
Next: 1819

Since: 05-15-14

Last post: 2532 days
Last view: 2270 days
New update. version 3 patch caused glitches with some other bosses in the game. I got the will power to look through why this was happening and it turns out that the code at $CF30 is shared! If you're in the great palace then I guess it does a different defeat explosion? But that's how it is. It was checking for the great palace with CMP #$0F but with my modified code it should actually be #$05. This seems to work properly for everything, and I'm fairly confident that it won't cause any unwanted effects elsewhere (nothing noticeable anyway)

If you downloaded one of the older patches, just repatch the rom with this new one and it should work.

Moo
Posted on 05-20-14 05:41 PM Link | Quote | ID: 156572


Micro-Goomba
Level: 8

Posts: 10/10
EXP: 2015
Next: 172

Since: 03-05-13

Last post: 3621 days
Last view: 3615 days
When you get to a final version, you should submit this hack to romhacking.net. I'm sure a hack like this would be definately useful.

Trax
Posted on 05-21-14 06:16 AM Link | Quote | ID: 156574


Yellow Stalfos
Level: 71

Posts: 1143/1145
EXP: 3033986
Next: 133128

Since: 07-06-07
From: Québec

Last post: 3619 days
Last view: 2871 days
The Palaces in the game have several codes that define them, but most of the time, it's not straightforward, like 00 for Palace 1 and 06 for Palace 7. There are two major RAM addresses that are used to refer to Side-Scrolling Areas. One is $607, which I call Region Code, and $707, which I call World Code...

Region (0706) World (0707) R * 5 + W

West Hyrule 00 00 00
Death Mountain 01 00 05
Maze Island 01 00 05
East Hyrule 02 00 0A

Towns in West Hyrule 00 01 01
Towns in East Hyrule 02 02 0C

Palace 1 00 03 03
Palace 2 00 03 03
Palace 3 00 04 04
Palace 4 01 04 09
Palace 5 02 03 0D
Palace 6 02 04 0E
Palace 7 02 05 0F


Another very important RAM address is $748 : Overworld Area out of Side View. This address contains the Area Index that tells where Link will re-emerge when getting out of a Side-Scrolling Area. This value is used at $1CB82 to determine where Link will be located when he exits the Palace. With this information, you can find out the last Palace visited (where Link died last) and set the $706 and $707 variables accordingly...

But maybe I'm overcomplicating things here. A long time ago, I tried to do the same as Njosro here is trying to accomplish. I almost succeeded, except that you would restart in any Area, including the non-Palace ones. So maybe by doing this, and adding a simple condition (one that is true only if you're in a Palace), we could have what we want...

infidelity
Posted on 05-21-14 05:18 PM Link | Quote | ID: 156576


Fuzz Ball
Level: 66

Posts: 523/968
EXP: 2366651
Next: 95200

Since: 05-24-07

Last post: 951 days
Last view: 807 days
Wow, great info/insight Trax!

njosro
Posted on 05-21-14 08:35 PM (rev. 2 of 05-21-14 10:24 PM) Link | Quote | ID: 156578


Goomba
Level: 13

Posts: 5/27
EXP: 8448
Next: 1819

Since: 05-15-14

Last post: 2532 days
Last view: 2270 days
Hey Trax thanks a lot for getting back to me!

If you download the patch you'll see it already does work as I want it to! At this point I just need to make sure I'm not interfering with something else by accident.

In case you didn't see in my first post (which I wouldnt blame you because it's a mess of paragraphs ), I do use $706 and $707 to compute where the game should make you restart.

The trick is that there is no single variable that can be used to identify which palace your're at, so I use a combination of the two. Just like in your chart, except I do *4 instead of *5. (two ASL instructions) The code is in my first post.

Since we only want the game to care about where you are if you're in a palace, I took advantage of the fact that whenever $707 ('world') >= 3, you're in a palace. The original code does region*4 + region + world. If it equals $F, (which it only does if you're in the great palace), then it hard codes in the proper values of where to begin. I modified it so that if world >= 3, JSR to my own subroutine, which computes where to start off based on lookup values I manually store in RAM.


The problem was that when the bosses die, they share the code that tests if region*4+region+world=$F so that Thunderbird can have a distinguished explosion from the other bosses. I don't remember the specifics but in my newest patch I fixed where the branching and jumping goes so it goes to the correct routines.

Download the patch! Try it out

Trax
Posted on 05-22-14 12:06 AM Link | Quote | ID: 156579


Yellow Stalfos
Level: 71

Posts: 1144/1145
EXP: 3033986
Next: 133128

Since: 07-06-07
From: Québec

Last post: 3619 days
Last view: 2871 days
Njosro, I've read your first post more attentively, and it covers most of the issue. About your hack, if it works without glitch, that's a good thing. While I give you brownie points for ASM, I've seen worrisome things about your code...

First, I would not temper with the R*5+W routine, because it's used in many places and it's not worth having glitches somewhere else in the game (like with the Thunderbird). Free space is not that limited, and this calculation can be used to find out about the Palaces Starting Screens...

Your new routine stores arbitrary values one after the other in Cartridge RAM, but you could simply store a table somewhere in ROM, since this data is not meant to change...

Also, there could be additional problems if you decide to move the Palaces around in the Overworld. The game engine presumes that all Palaces in a given region start at index 34 (1CB87) in the Overworld. Maximum 4 Palaces per region. There are at least two data tables that rely on this to confer the right values for Graphics Banks (1CD2A) and Palace Palettes (1CD35)...

So, what do we want exactly? The right map number to start from. This value can be found in the Overworld Area Data Table, stored between 6A00 and 6AFB in Cartridge RAM (VRAM):

6A00-6A3E Area Byte 0 (Y Position)
6A3F-6A7D Area Byte 1 (X Position)
6A7E-6ABC Area Byte 2 (Map Number)
6ABD-6AFB Area Byte 3 (Region/World Code)

Take byte 2, keep bits 0-5, and you've got your Map Number. That's where $748 comes handy. It's the index to use in these tables...

njosro
Posted on 05-22-14 02:46 AM (rev. 4 of 05-22-14 04:28 AM) Link | Quote | ID: 156580


Goomba
Level: 13

Posts: 6/27
EXP: 8448
Next: 1819

Since: 05-15-14

Last post: 2532 days
Last view: 2270 days
Yes this is exactly the kind of feedback I was looking for. I knew the way I did it is not a very good way.

For the R*5+W routine, I thought about the problems it might cause if changed, but I did three play throughs of the entire game and noticed no change, except for the original Thunderbird glitch. But the latest patch fixes that. The problem was that for Thunderbird's explosion, it would use my new thing of just taking 'world', then exit that subroutine and compare it to $F. I changed it to compare it to $5, which is of course the great palace. So now every boss works. Even Dark Link (because he doesn't explode of course). Nothing else has been affected by this change as far as I could tell when I played through it again.

For me writing to RAM, I really didn't want to do that. It was just my on-the-spot thinking to get the job done. I was thinking about what you mentioned: moving the Palaces in the overworld, and how flexible my modification would be. Because what if, for example, ice penguin got a soft spot in his heart and decided to use the patch to make one of his future hacks easier ? There's no guarantee that the palace entrances would be the same.

I actually do know about the area data table thanks to people like you and dwedit updating data crystal, although I thought it was only in ROM. I used that data to make an overworld editor that can modify areas (because hex editing for that is soooo archaic! And I don't have a mac to use yours). I haven't released it. Anyway, I'm no expert, but are you saying that I should use $748 to lookup the correct index, then extract the corresponding map number from byte 2, and use THAT as the scene to return the player to after a gameover?

Something like this maybe:

LDY $0748
LDA $6A7E , Y
AND #%00111111
RTS
...
STA $0561

is that kind of what you're saying? I'll try it out. Thanks

EDIT: Ok maybe that's not what you meant... I tested it out. The problem is that the area tables completely change as soon as you enter a palace (or change to any other world I'm guessing), so the lookup index doesn't work for me inside a palace which is when I need it. Aw man

EDIT 2: It doesn't fix anything, but I thought you were going from left to right talking about bits 0-5. Now I know you meant to go right-to-left. Fixed the code anyway.

Trax
Posted on 05-22-14 08:15 AM Link | Quote | ID: 156581


Yellow Stalfos
Level: 71

Posts: 1145/1145
EXP: 3033986
Next: 133128

Since: 07-06-07
From: Québec

Last post: 3619 days
Last view: 2871 days
Yeah, I realized my mistake after posting. The code you wrote in your last message is exactly what I used myself, verbatim. But yes, the Area Data Bytes change when the world change, and the VRAM is updated, so it's a no-go that way...

To correct this, we would have to determine the correct bank to load, switch to it, load $561 accordingly, and switch back. It looks complicated when said like that, but games do that kind of manipulation all the time, and Zelda II is no exception...

Your code could be simplified by taking the result of R*5+W, transfer it to Y, and use that index in your own custom table. If someone wants to change Palaces around, they could simply change these values by hand to match the starting areas of the palaces. Seems like a reasonable tradeoff...

I just realized that the R*5+W routine is also used to determine the RAM range used for Item Presence. This is vital because this is what makes an item taken and doesn't reappear when you go back to the area. This data is saved to VRAM...

njosro
Posted on 05-22-14 10:41 PM Link | Quote | ID: 156583


Goomba
Level: 13

Posts: 7/27
EXP: 8448
Next: 1819

Since: 05-15-14

Last post: 2532 days
Last view: 2270 days
The R*5+W routine seems like it is very important in theory, but honestly I've played the patched rom, going back to areas after saving and restarting, and it remembers correctly that, for example, the candle was taken or a P-bag was taken. But if you're telling me I should change it back, I'll change it back.

Using Y as an index for my own custom table is what I had in the first place, except I make the game write it to RAM, which I know is not good. I don't know how to load data from a table of values in ROM. But like you said, doing it this way makes palace entrance manipulation an extra chore. I guess it isn't too much work for the user, but ideally I think we'd like this patch to work automatically even if the palace entrances get moved.

If switching banks is what it takes to accomplish this, I'm willing to try. But I don't know how to switch banks...

Main - ROM Hacking - Zelda 2 restart from current palace after game over New thread | New reply

Acmlmboard 2.1+4δ (2023-01-15)
© 2005-2023 Acmlm, blackhole89, Xkeeper et al.

Page rendered in 0.026 seconds. (349KB of memory used)
MySQL - queries: 102, rows: 135/136, time: 0.017 seconds.