Changing heart container properties on ZELDA 1 (Possibly ASM) ?

Started by The3Dude, March 23, 2020, 03:46:49 PM

Previous topic - Next topic

The3Dude

I know this might be too much to ask, but I have no ASM knowledge whatsoever, and who knows maybe you don't need ASM for this idea to be realized.

I was wondering if it's possible to change the value, if there is one, of the Heart Container item to just give you 1/4 of a heart expansion, maybe even just half a full heart.

If anyone knows how to find or figure out/go about doing this help would be greatly appreciated.
~The3Dude~

bogaabogaa

If you look at the RAM value $66f and $670 you will find the values for heart container and health. First 4 bit are for container the second 4 bit health. For example the value $52 will leave you with 6 hearts and half health.

In Ram at $670 you actually have "half" container and health what is used to show half hearts. When you pick up a big heart container it will do a ADC #$11 to the $66f Ram value. You can not go smaller then $1 so you would need to write costume routines for it to work. It would be easy to double it if you change the value $11 to $22 at $6c7c in the PRG ROM. Also keep in mind that this routines are copied to SRAM when you start up the game. It might not work if you use old saves-states to test it.

If you try to balance the game it might be easier and more interesting for you to look for enemy health tables. They are much easier to change. Also I did never hack Legend of Zelda. There might be good resources for the game so you don't need to find things yourself. What is your plan when I may ask. Would you like to do a balance hack?
CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 23, 2020, 05:30:38 PM
If you look at the RAM value $66f and $670 you will find the values for heart container and health. First 4 bit are for container the second 4 bit health. For example the value $52 will leave you with 6 hearts and half health.

In Ram at $670 you actually have "half" container and health what is used to show half hearts. When you pick up a big heart container it will do a ADC #$11 to the $66f Ram value. You can not go smaller then $1 so you would need to write costume routines for it to work. It would be easy to double it if you change the value $11 to $22 at $6c7c in the PRG ROM. Also keep in mind that this routines are copied to SRAM when you start up the game. It might not work if you use old saves-states to test it.

If you try to balance the game it might be easier and more interesting for you to look for enemy health tables. They are much easier to change. Also I did never hack Legend of Zelda. There might be good resources for the game so you don't need to find things yourself. What is your plan when I may ask. Would you like to do a balance hack?



Thank you very much for your detailed help! I actually I am trying to make this hack balanced, challenging, and fun for everyone here's what I've done so far https://www.romhacking.net/forum/index.php?topic=29937.0
~The3Dude~

bogaabogaa

This looks like a ambition project. I like your work. I don't know how much the info really helps you so far.

You don't require ASM knowledge to change how much damage a enemy does. Here a example.

I suggest that you use Mesen since this editor does a very good job explaining the NES in the debugger and is a excellent emulator overall. It has info you can learn all over it.
In this picture I like to find out how much damage this red enemy does. I make a save state on that screen. I open the debugger/memory editor and move to tab SRAM and the offset you see on the picture. When I load the save state previews color highlights go away. Then I run into the enemy and a number will get blue. Green colored things are op codes this are instruction processed by the CPU. Blue color shows data. In this case probably all enemy damage is stored in that table.


As you noticed we use SRAM to find out how much damage a enemy does. This table is located on the PRG ROM. So you start to do a document about that table that might look like this.

************************
PRG ROM

$72bb Enemy Damage Table
..
..
$72c2 Red Enemy
..

Format: First half byte is sub damage point second half byte full damage point
*************************

If you wonder what PRG ROM is. The NES file will contain a header, PRG ROM and CHR ROM. In a nes file this is combined. The nes header (ines header) is $10 byte length and will tell a emulator where everything goes. So when you open the Nes file in a hex editor you will need to subtract the header from the offset to get the correct PRG ROM offset. But you have also the option to save the ROM within the memory tool or generate a IPS of the change.
CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 24, 2020, 06:17:43 AM
This looks like a ambition project. I like your work. I don't know how much the info really helps you so far.

You don't require ASM knowledge to change how much damage a enemy does. Here a example.

I suggest that you use Mesen since this editor does a very good job explaining the NES in the debugger and is a excellent emulator overall. It has info you can learn all over it.
In this picture I like to find out how much damage this red enemy does. I make a save state on that screen. I open the debugger/memory editor and move to tab SRAM and the offset you see on the picture. When I load the save state previews color highlights go away. Then I run into the enemy and a number will get blue. Green colored things are op codes this are instruction processed by the CPU. Blue color shows data. In this case probably all enemy damage is stored in that table.


As you noticed we use SRAM to find out how much damage a enemy does. This table is located on the PRG ROM. So you start to do a document about that table that might look like this.

************************
PRG ROM

$72bb Enemy Damage Table
..
..
$72c2 Red Enemy
..

Format: First half byte is sub damage point second half byte full damage point
*************************

If you wonder what PRG ROM is. The NES file will contain a header, PRG ROM and CHR ROM. In a nes file this is combined. The nes header (ines header) is $10 byte length and will tell a emulator where everything goes. So when you open the Nes file in a hex editor you will need to subtract the header from the offset to get the correct PRG ROM offset. But you have also the option to save the ROM within the memory tool or generate a IPS of the change.



Thank you so much! I've actually decided not to change the heart containers, but I have been changing the damage the enemies give, thanks to your help!

I do have one more question though.

How would I find the health of enemies? Like say for instance if I wanted to make a boss take more hits to defeat?
~The3Dude~

bogaabogaa

I started to find some enemies you can go about as I described before. It is a bit easier since this table is not located in SRAM. Not sure if all enemies are located on the same spot but they might. Finding things like this requires a bit of ASM knowledge or a lot of patience when you try and error your way through. It might be a bit overwhelming when looking at a debugger the first time. But in the end a CPU does follow instructions like jumping, copy or do some logic. In the end it is a simple machine and with the debugger you can make a point where it triggers a pause (break point) Then you can step slowly to see what happen.


Enemy Health Table PRG ROM

$1fb52 RedRockThrower/Blue?
$1fb56 ZoraShooter

$1fb51 BumerangDude   Level-1
$1fb5b Bat       Level-1
$1fb60 Skellet       Level-1
$1fb6c DragonBoss   Level-1


Format: First half byte ?? second half byte full damage point
CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 25, 2020, 12:30:12 AM
I started to find some enemies you can go about as I described before. It is a bit easier since this table is not located in SRAM. Not sure if all enemies are located on the same spot but they might. Finding things like this requires a bit of ASM knowledge or a lot of patience when you try and error your way through. It might be a bit overwhelming when looking at a debugger the first time. But in the end a CPU does follow instructions like jumping, copy or do some logic. In the end it is a simple machine and with the debugger you can make a point where it triggers a pause (break point) Then you can step slowly to see what happen.


Enemy Health Table PRG ROM

$1fb52 RedRockThrower/Blue?
$1fb56 ZoraShooter

$1fb51 BumerangDude   Level-1
$1fb5b Bat       Level-1
$1fb60 Skellet       Level-1
$1fb6c DragonBoss   Level-1


Format: First half byte ?? second half byte full damage point


Thank you! I've changed most of the bosses health, about heart containers though. I figured out how to make you need 4 heart containers to get a full new container. But the game doesn't remember me getting those containers when I save and reset the game. Does this have to do with SRAM? If so do you know how I could solve this?
~The3Dude~

Vanya

That is definitely an SRAM issue.
You need to make sure you have space to record the extra containers themselves and at least 3 bits to use as flags for the heart container pieces.
And as far as code is concerned you have to make it so that when you pick up a piece it writes that to SRAM at the appropriate time.

The3Dude

Quote from: Vanya on March 26, 2020, 05:58:47 PM
That is definitely an SRAM issue.
You need to make sure you have space to record the extra containers themselves and at least 3 bits to use as flags for the heart container pieces.
And as far as code is concerned you have to make it so that when you pick up a piece it writes that to SRAM at the appropriate time.

Thank you Vanya! :D I honestly don't know how I would go about doing this though, I know where some free space of FF bytes are. But how would I write my own code? Is there a document I could find about it? :-\

(P.S Also I posted another post on the Looming Darkness thread but it auto merged, you should check it out. 8) )
~The3Dude~

bogaabogaa

If I would know what you did to collect 4 containers to get one container I might know a better way to hijack the code. The problem is probably that one value is saved to RAM but should go to SRAM to keep the value between save sessions.

Here a example how I would hijack the code with my current knowledge.



On the bottom right you see that SRAM is mapped to CPU bus $6000-$8000. This is impotent since the CPU can only access the CPU bus. It talks to PPU over registers that are mapped to the CPU bus.. just to get a idea how this works.

I made a breakpoint and you see how I stepped code where you heart-container will add one up and health will get refilled. On the left bottom you see a assembler with some code I documented. There I made a jump to a location where I can put code. I could INC (increase) a value in SRAM and then compare that number to #$04. Then when it is equal I would reset that counter and add the heart-container. Else skip that part.

Learning to code will not happen over night. You will find the best documentation for the NES on wiki.nesdev.com.
You will study opcodes and how to use them. Probably follow tutorials on different pages and experimenting a lot.

Here a good list of opcodes and the hex equivalent.


If you really feel lost and you liked to learn to code for a 6502 you can also join my discord. There are channels for questions about it.

**NEW**

I probably did not explain it properly and did think I could write you a ASM file that would explain it better.. but..

I did try to create a ASM file with ASM6. I could not get it to include the code to a existing Zelda.bin. It will overwrite it or put it on the end of the file. I tryed for a view hours to get this to work but failed with any attempt. I find it very easy to do this sort of thing on the SNES and tools like asar or xkas. I think it would be the best way to learn to code and write small patches with it. It is easy to apply and change after. I could not find any ASM6 patches and I am glad if anyone could show me one. I found only large scale projects so if anyone knows where to find a example patch I would like to learn how to use it properly on the NES too!

I did not explain that you need to allocate the code at PRG $6c7d (pointer) PRG $7751 (new code) You can write out the code as hex in the memory editor or use the build in assembler in a debugger.
CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 27, 2020, 01:00:31 AM
If I would know what you did to collect 4 containers to get one container I might know a better way to hijack the code. The problem is probably that one value is saved to RAM but should go to SRAM to keep the value between save sessions.

Here a example how I would hijack the code with my current knowledge.



On the bottom right you see that SRAM is mapped to CPU bus $6000-$8000. This is impotent since the CPU can only access the CPU bus. It talks to PPU over registers that are mapped to the CPU bus.. just to get a idea how this works.

I made a breakpoint and you see how I stepped code where you heart-container will add one up and health will get refilled. On the left bottom you see a assembler with some code I documented. There I made a jump to a location where I can put code. I could INC (increase) a value in SRAM and then compare that number to #$04. Then when it is equal I would reset that counter and add the heart-container. Else skip that part.

Learning to code will not happen over night. You will find the best documentation for the NES on wiki.nesdev.com.
You will study opcodes and how to use them. Probably follow tutorials on different pages and experimenting a lot.

Here a good list of opcodes and the hex equivalent.


If you really feel lost and you liked to learn to code for a 6502 you can also join my discord. There are channels for questions about it.

**NEW**

I probably did not explain it properly and did think I could write you a ASM file that would explain it better.. but..

I did try to create a ASM file with ASM6. I could not get it to include the code to a existing Zelda.bin. It will overwrite it or put it on the end of the file. I tryed for a view hours to get this to work but failed with any attempt. I find it very easy to do this sort of thing on the SNES and tools like asar or xkas. I think it would be the best way to learn to code and write small patches with it. It is easy to apply and change after. I could not find any ASM6 patches and I am glad if anyone could show me one. I found only large scale projects so if anyone knows where to find a example patch I would like to learn how to use it properly on the NES too! Here my failed project: https://www.dropbox.com/s/psflejhiyrbstf3/asm6%20and%20Zelda%20ASM.zip?dl=0

I did not explain that you need to allocate the code at PRG $6c7d (pointer) PRG $7751 (new code) You can write out the code as hex in the memory editor or use the build in assembler in a debugger.



First off I just want to say , wow. I left for a day and came back to this very detailed explanation. I appreciate you going out of your way for this. Thank you!

I do think xkas works on NES though maybe. I remember hearing people mention it in the Zelda 1 redux thread (correct me if I'm wrong) I will figure this out with the info you gave me and the patch as much as I can. Really thank you man.

I'll let you know how it goes.
~The3Dude~

bogaabogaa

It is a learning experience for me too. I did read about the xkas version that can do 6502 assembly but I think ASM6 would be the better choice overall. I think it comes down that I don't understand how to allocate banks. It seems you use ORG to set where the banks is mapped in the cpu bus. Like org $8000 or org $c000. Not sure how to add the different banks at all yet..

All this is simpler on the SNES since the CPU bus has a large range to include everything. You use ORG to set the location where you like to put your code. You need to know that the RAM is mirrored to each bank and you are ready to go to do some damage. The assembler makes coding easy and might help beginners to get into.

On the Nes it seems you need to have a way better understanding of things before you get rolling with ASM6. I think you should not care yet. I started out finding some pointer tables and changing them in a hex editor. I did find data for the enemy assembly and learned how sprites are put together. Tasks like this seem to be easier and  might be the thing that will add to a hack quiet a lot. Use Mesen to write code since that one has a assembler. Or write it by hand and translate it to hex as a exercise.. Mesen will help you to find the proper bank in the ROM as you can just right click and go to the location. This is how I did most changes so far. In the process you will gain more knowledge how it works.

Tell me how you did change the heart-container to give a heart after 4 times. I will make you a example.
CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 27, 2020, 09:40:44 PM
It is a learning experience for me too. I did read about the xkas version that can do 6502 assembly but I think ASM6 would be the better choice overall. I think it comes down that I don't understand how to allocate banks. It seems you use ORG to set where the banks is mapped in the cpu bus. Like org $8000 or org $c000. Not sure how to add the different banks at all yet..

All this is simpler on the SNES since the CPU bus has a large range to include everything. You use ORG to set the location where you like to put your code. You need to know that the RAM is mirrored to each bank and you are ready to go to do some damage. The assembler makes coding easy and might help beginners to get into.

On the Nes it seems you need to have a way better understanding of things before you get rolling with ASM6. I think you should not care yet. I started out finding some pointer tables and changing them in a hex editor. I did find data for the enemy assembly and learned how sprites are put together. Tasks like this seem to be easier and  might be the thing that will add to a hack quiet a lot. Use Mesen to write code since that one has a assembler. Or write it by hand and translate it to hex as a exercise.. Mesen will help you to find the proper bank in the ROM as you can just right click and go to the location. This is how I did most changes so far. In the process you will gain more knowledge how it works.

Tell me how you did change the heart-container to give a heart after 4 times. I will make you a example.


I went to 6c7c in PRG rom and changed 11 to 04. I made an example hack, just go in the first cave you see and reenter until you get 4 heart containers and it will add. I sent you a message check inbox.
~The3Dude~

bogaabogaa

Ok this is the value I showed you. I did describe that the first four bit are for container and the second 4 is health. You added more health. After 4 times the value did overflow and added a container. This is a bug and the game code will usually prevent that form happening. (4 bit can make characters from 0-f) 0000 - 1111)

So I make a example how to add code with what I know. In this picture you see that I used mesen to write some horrible long code to get something working very quick. First I like to find out if it works. You see some old notes below so you know where I pasted the code into the PRG ROM after. This code does not work over save sessions since most of the SRAM will be overwritten when reseting the game. I would need to find free space in the save format at the beginning of SRAM. I will also need to find out how this is handled for different save files. So $7eff would need to go to the correct save file to be carried and this is a lot of research again for something I don't see much gained. May be it will make the experience worse since it feels like you never get stronger.
I rater research some interesting tables so you can make enemies shoot or what not.


I post a ips anyway if you like to work with the new code..

* I updated the patch. According to this RAM MAP (http://datacrystal.romhacking.net/wiki/The_Legend_of_Zelda:RAM_map) $677 seems not used. But sure it needs testing.
https://www.dropbox.com/s/9tr504v9w84b70x/QuaterHeartZelda.ips?dl=0

** I did bug fixing and added overflow protection so you can have to many hearts without problem. Should work if the SRAM address is really not used for anything..
https://www.dropbox.com/s/zkhy5fqud8irhnx/QuaterHeartZelda2.ips?dl=0
CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 28, 2020, 05:41:13 AM
Ok this is the value I showed you. I did describe that the first four bit are for container and the second 4 is health. You added more health. After 4 times the value did overflow and added a container. This is a bug and the game code will usually prevent that form happening. (4 bit can make characters from 0-f) 0000 - 1111)

So I make a example how to add code with what I know. In this picture you see that I used mesen to write some horrible long code to get something working very quick. First I like to find out if it works. You see some old notes below so you know where I pasted the code into the PRG ROM after. This code does not work over save sessions since most of the SRAM will be overwritten when reseting the game. I would need to find free space in the save format at the beginning of SRAM. I will also need to find out how this is handled for different save files. So $7eff would need to go to the correct save file to be carried and this is a lot of research again for something I don't see much gained. May be it will make the experience worse since it feels like you never get stronger.
I rater research some interesting tables so you can make enemies shoot or what not.


I post a ips anyway if you like to work with the new code..

* I updated the patch. According to this RAM MAP (http://datacrystal.romhacking.net/wiki/The_Legend_of_Zelda:RAM_map) $677 seems not used. But sure it needs testing.
https://www.dropbox.com/s/9tr504v9w84b70x/QuaterHeartZelda.ips?dl=0

** I did bug fixing and added overflow protection so you can have to many hearts without problem. Should work if the SRAM address is really not used for anything..
https://www.dropbox.com/s/zkhy5fqud8irhnx/QuaterHeartZelda2.ips?dl=0


I tested it and tried resetting in multiple situations to see if the SRAM remembered. It works Great! Thank you! You will be credited!

EDIT: If I could add anything else to this ASM would be to add a counter for how many pieces you have that would reset to 0 after getting 4. I used PPU viewer to make an example image. Something that looks like this. Counter is under rupee counter.



Thank you very much for all your work thus far and going out of your way to make this. Highly appreciated. :thumbsup: :D
~The3Dude~

bogaabogaa

With testing I do mean looking at it in a playthrough. Could be that this memory is used in lvl 9 to keep track of something special may be it is ok how it is. The RAM map did clear a lot up but there is still a lot to be discovered.

About Hud changes. It is kinda easy to do changes to it that are stationary.
PRG $1a2d3 Hud Tilemap Starts out with attributes. Tile mapping start at $1a2e4 

Format:
$20=offset from top
$FF=end of table
..there are more special Values. Tiles have nametable values as you find them in the PPU.

to put the heart down you write Heart=$65 to $1a312

After we need to find out how we could do a counter. So far I did look into how to game handles Hud updates. Turns out that at CPU $300 is a table that will be loaded into the PPU via registers $2006-2007. The format of this tables and how to use them is puzzling. I did see that there is space to expand the table. I was hopping I could look at the ruby routines and more or less copy them.. well there goes more research how things are handled. You know the table at CPU $6c97 will get drawn and places with special values will get updated (I guess). This routine will store impotent values to $00-0f.. before updating. It is hard to make out what all it has to do and why. But you need to know that if you like to extend on existing routines. I feel like it would be easier to write my own routine to update that value. Probably try this next.

It is interesting to look at a game how it does the things. I did see that SRAM is used as a other bank to save routines and at the end there is almost no space to add your own things.
If you like to expand it you can write overwrite $7f with $80 at PRG $4d31. This will load a extra 256 byte. There seems to be a impotent value on the bottom of the bank so put $a5 at PRG $786f too.

There goes a lot of text to explain little things. I know of a tool called DavePatcher. Probably will do some little things and add it to that format. Really easy to understand format and a great way to apply changes to a ROM. I had in mind to do that with some games I did look into. It is great to put a value and explain with a view words what it does. Might take me a while but I plan to post a other patch here and explain the patcher a bit. 

CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 30, 2020, 03:22:08 AM
With testing I do mean looking at it in a playthrough. Could be that this memory is used in lvl 9 to keep track of something special may be it is ok how it is. The RAM map did clear a lot up but there is still a lot to be discovered.


I'll play through the game with your patch and see if anything crashes, I'll even look at little things like if items are working correctly such as map and compass. I'll tell you what I find in a few hours.

Thanks again for your help/info I will be looking forward to seeing what you find. :thumbsup:


(EDIT) I played through and nothing went wrong. I beat the game normally. looks fine. :D
~The3Dude~

bogaabogaa

If you do testing it is good if you can do multiple things in a play-through to save time overall. I guess making list of the enemy health and damage tables is one of them. When you look for not used values use breakpoints. In the picture you see some of free values in SRAM. There will be writes when saving and loading but only $00 values. 



I am interested to see when you can finish describing a table. I don't know how to beat the game and it is always a big time factor to properly test things.


*NEW

Here is a patch with quarter heart and HUD indicator.
https://www.dropbox.com/s/lt2fwksggbfr82o/QuaterHeartContainers.ips?dl=0

As promised I will share a SpiderPatch here too!
https://www.dropbox.com/s/xi97vva2zst4b3t/patch.txt?dl=0

The benefits of the Spider Patch are that you can edit things. I can add a bunch of things you can enable or disable.

Get the patcher here: http://spiderdave.com/programs.php
There is a link to the git. Then download the folder from there.
It looks like this:


You will need to look at the config file and tell it where to find the ROM to patch and where to put and how to name it after.
Then open and run a patch file to mod your ROM.

The patch file has a simple format. First you might add "offset 10" this will skip the header and I can write PRG addresses now.
Here how to put values after a new offset: put "offset" "values" "more values till end of line"
If you like to describe something use a / "everything after a slash will be ignored by the patcher. Comment here till end of line!

If you like to disable something just comment it out with slashes.

My example might be confusing since I explained my research. This might be useful to understand it when doing further changes.
Look at the examples of SpiderDave they explain a lot more.

When I make further changes I can just update this link with the Spider Patch.
CV ROM DiscordServer
https://discord.gg/PvFgxRg

The3Dude

Quote from: bogaabogaa on March 31, 2020, 04:17:46 AM
If you do testing it is good if you can do multiple things in a play-through to save time overall. I guess making list of the enemy health and damage tables is one of them. When you look for not used values use breakpoints. In the picture you see some of free values in SRAM. There will be writes when saving and loading but only $00 values. 



I am interested to see when you can finish describing a table. I don't know how to beat the game and it is always a big time factor to properly test things.


*NEW

Here is a patch with quarter heart and HUD indicator.
https://www.dropbox.com/s/lt2fwksggbfr82o/QuaterHeartContainers.ips?dl=0

As promised I will share a SpiderPatch here too!
https://www.dropbox.com/s/xi97vva2zst4b3t/patch.txt?dl=0

The benefits of the Spider Patch are that you can edit things. I can add a bunch of things you can enable or disable.

Get the patcher here: http://spiderdave.com/programs.php
There is a link to the git. Then download the folder from there.
It looks like this:


You will need to look at the config file and tell it where to find the ROM to patch and where to put and how to name it after.
Then open and run a patch file to mod your ROM.

The patch file has a simple format. First you might add "offset 10" this will skip the header and I can write PRG addresses now.
Here how to put values after a new offset: put "offset" "values" "more values till end of line"
If you like to describe something use a / "everything after a slash will be ignored by the patcher. Comment here till end of line!

If you like to disable something just comment it out with slashes.

My example might be confusing since I explained my research. This might be useful to understand it when doing further changes.
Look at the examples of SpiderDave they explain a lot more.

When I make further changes I can just update this link with the Spider Patch.




Thank you for all your help bogaabogaa, wow. You just earned yourself a spot on my hacks credits. You've been a HUGE help with this, and your info was very detailed and informative. I've added the sprite for the heart on my own. Thank you so much! :D
~The3Dude~

bogaabogaa

I noticed something that could complicate things with my patch. The ROM you send me did had different offsets for some stuff my patch depends on it. I did try to save the original ROM with the snarfblam tools (ZeldaTech and DungeonMaster) I saved rigth away but the offsets did remain. What tools did you use? Do you have a idea how that happen? Might be that the tool changes offsets after some changes though..
CV ROM DiscordServer
https://discord.gg/PvFgxRg