• Welcome to Talking Time's third iteration! If you would like to register for an account, or have already registered but have not yet been confirmed, please read the following:

    1. The CAPTCHA key's answer is "Percy"
    2. Once you've completed the registration process please email us from the email you used for registration at percyreghelper@gmail.com and include the username you used for registration

    Once you have completed these steps, Moderation Staff will be able to get your account approved.

Talking about romhacks!

YangusKhan

does the Underpants Dance
(He/Him/His)
So, there's this guy, Praetarius, who likes making high-difficulty/big-changing romhacks of games. He has one for Seiken Densetsu 3 called Sin of Mana. For the longest time, he was really adamant about not releasing a patch that was just specifically the bugfixes he made as part of this hack. Turns out he finally "caved" on that and now you can find a bugfix patch on RHDN. This hack also makes some changes that are technically "balance changes", addressing things that are now unbalanced after fixing bugs (lol).
 

Yimothy

Red Plane
(he/him)
My hack is up on ROMHacking.net. Hopefully I haven’t messed it up. I’m surprised to see 31 downloads listed already. Didn’t think the public were crying out for this hack. Probably people who download everything that gets put up I guess.
 

Octopus Prime

Mysterious Contraption
(He/Him)
Any recommendations for an LttP romhack that changes up the game but doesn’t make it maliciously difficult?

Most of the ones I see brag about how much harder they’ve made the game and that’s not really what I’m there for
 

RT-55J

space hero for hire
(He/Him + RT/artee)
Zelda 3 was cursed, for the longest time, with an editor that could technically do everything you want it to, but had the inevitable and frequent risk of corrupting your entire rom for no reason whatsoever.
 

Yimothy

Red Plane
(he/him)
I recently offloaded a bunch of old games to a local game shop and used the proceeds to buy a smaller number of other games, because I am a moron. Among those, again because I am a moron, was a game I don't even like all that much: Golden Axe Warrior, Sega's SMS Zelda clone. I played it a few years ago in the PS3 Mega Drive collection, and I remember it as being pretty good but having a few major frustrations, particularly in that you always start with three hearts and three magic pots after dying, no matter what your current maximum is, plus you lose money. I think the three hearts thing is pretty Zelda, but I feel like usually you come back to life in a room full of pots to get hearts from so it's not such a big deal. In GAW, getting your hearts and magic back means killing a heap of enemies until you get the drops you need. Maybe I'm just bad at games, but I remember spending a lot of time on this and not liking it much. So I decided to dump my new cart and take a look at the code.

My assumption was that somewhere in the continue routine there would be code to this effect:

Set HP to 3
Set MP to 3
Reduce cash by 1/4

Calling on my vague memories of Z80 assembly from when I made a Wonder Boy in Monster Land ROMhack, I thought the third line might be accomplished by copying the current cash level into register A, shifting its bits right twice (each of which would divide its value by two, rounding down), then subtracting the result from the current cash level and setting that result as the new cash level. As it turned out, I had the general idea right, but the specifics a bit off. Let's take a quick look at the game:

MM976Um.png


Here's the opening gameplay screen, along with MEKA's Memory Editor (and some of its tile viewer, not relevant to what I'm doing here). I want to figure out which values in memory store the current and maximum HP and MP, and the current cash level. Right off the bat we can see where the game stores the name chosen by the player: C0B0 to at least C0B6. When I was hacking WBiML I tried to figure out where the values I wanted were stored for myself, but this time I took a lazier approach: I looked up cheat codes online. Action Replay and Game Genie devices work by sending particular values to particular memory addresses, so by looking up codes for infinite HP/MP/money, and codes to increase the HP/MP maximums, I was able to learn the relevant memory addresses without having to do any work myself. Four of them are visible on this screen:

C0DA - max HP, currently 18 (each hit costs two HP, and each heart takes four hits, so three full hearts equals 24 HP, which in hex is 18)
C0DB - current MP (also 18)
C0DC - max MP (again 18)
C0DD - current money (00 - I'm broke)

The other address I want is C318, where my current HP is stored. Why it's not with the rest, I dunno. Let's mess with these addresses:

6CF8euK.png


Here I've moved to the next screen and changed some memory values. My max HP is now 72, but I haven't changed the current HP, giving me three full hearts and a heap more empty ones. I've set max MP to 60, giving me a bunch of empty pots, and my money I've set to AB, hex for 171. I neglected to take screenshots, but changing the current HP/MP memory addresses also worked as expected, changing how many hearts/pots were filled (incidentally, they can be set higher than the maximum values - they'll count down from whatever you set them to as you take hits/use magic but the extra hearts will remain hidden from view).

OK, having established which memory addresses I'm interested in, let's find the relevant part of the game's code:

rIolChL.png


I've added MEKA's debugger interface to my screen, run my guy (now named "8" because I reset the game and couldn't be bothered on the name entry screen) into enemies until the continue screen appeared, set a breakpoint in the debugger to have it stop executing code the next time the current HP memory address gets written to, and then selected continue. The game immediately stopped. Let's take a look at the code and see how it compares to how I thought the game would manage this. The relevant part starts at line 2623 in the debugger window:

Code:
3E 18           ld a,18h        set reg A to value 18h (24 decimal)             7
32 18 C3        ld (C318h),a    set current HP to value of A (24)               13
32 DB C0        ld (C0DBh),a    set current MP to value of A (24)               13
3A DD C0        ld a,(C0DDh)    set reg A to current cash                       13
0F              rrca            rotate A's bits to the right                    4
0F              rrca            same again                                      4
E6 3F           and 3Fh         set first two bits of A to zero	                7
                                (these three actions divide A by four)
47              ld b,a          set reg B to value of A                         4
87              add a           add A to A (double it)                          4
80              add b           add B to A                                      4
                                these three actions multiply A by three,
                                resulting in 3/4 original figure
32 DD C0        ld (C0DDh),a    set current cash to value of A                  13

The first column here is the hex in the file - the instructions the ROM is giving to the CPU. The next column is MEKA's conversion of that into assembly code - almost readable by humans. The third is my description of what's happening. The fourth is how many CPU cycles each action takes, which is not super relevant to us but when I transcribed this I thought it might be. Basically:
  • Register A (aka the accumulator, basically 8 bits of memory used to store values temporarily so the CPU can do stuff with them) is set to hex value 18.
  • HP and MP are set to the value of register A (18h, or 24 decimal)
  • Register A is set to the value of my current cash level.
  • Register A is rotated right - this means the value of each bit is moved right, and the value of the last bit is copied over to the first one, so for example 00001111 would become 10000111. I thought the game would do this with a logical shift right, which is the same thing but doesn't copy the last bit over to the left side. I think the reason it doesn't do that is that rotation is cheaper: it requires a one byte opcode (0F) and uses 4 cycles of time. Logical shift uses a two byte opcode (CB 3F) and uses 8 cycles.
  • Register A is rotated right again.
  • Register A is ANDed with the value 3F - 0011 1111 in binary. This deletes the values of the first two bits. This is required because rotation was used instead of shifting, so there might be undesired 1s in those slots. The purpose of these three actions was to divide the value of A by four. If either of the original last two bits of A had been a 1, the result of the rotations would not have been a division without this AND.
  • The value of register A is copied to register B.
  • A is added to itself.
  • B is added to A - these two actions triple A, which was a quarter of my cash level.
  • The resultant value of A is written to the memory address where my money is stored. This should be approximately 3/4 of the original value, but because the 1/4 value is arrived at by dividing twice and rounding down each time it could be lower than the true 3/4 value.

So, if I want to start with full HP/MP and not lose any cash, all I need to do is get rid of the entire money subtraction sequence and change the HP/MP lines to read the maximum values of each into A instead of setting it to 18. Loading those values into A will require a few extra bytes of code, but because I'm getting rid of the money bit I have plenty of space. I'm going to replace the above code with:

Code:
set reg A to value of max HP:           ld a,(C0DA) = 3A DA C0          13
set current HP to value of reg A:       ld (C318),a = 32 18 C3          13
set reg A to value of max MP:           ld a,(C0DC) = 3A DC C0          13
set current MP to value of reg A:       ld (C0DB),a = 32 DB C0          13

I need the total length of code to remain the same, so I'm going to overwrite the remaining bytes of the original code sequence with 00s, the NOP (no operation) instruction. The total sequence winds up taking an extra two clock cycles, but I'm pretty sure it doesn't matter (there are roughly a million cycles per frame - a bit more in a PAL console, a bit less in NTSC). So my hack consists of going to address 2623 and overwriting from there with

3A DA C0 32 18 C3 3A DC C0 32 DB C0 00 00 00 00 00 00 00 00 00

HjXEGhI.png


So, here's the new ROM running. I've used the memory editor to set my HP/MP limits to the maximum (80 hex), and to reduce my MP to one pot. Then, rather than tediously running into enemies, I set my current HP to zero, a trick I wish I'd thought of much earlier in the piece (I was missing this screenshot so I've just started the game again and taken it - most of the rest of the shots in this post were taken before this one). I've used the same breakpoint to stop execution during the continue sequence as before, and you can see my changed code in the debug window on the right, most obviously in the long sequence of nops. Let's restart execution and see what happens:

v3TnfU0.png


Success! I've come back to life with full HP/MP. I was kind of stunned by how easy this was, to be honest. Writing the hack took less time than writing this post about it. Anyways, from here I just had to fix the checksum in the ROM header, easily done, and I was ready to publish. Though I should probably do more extensive playtesting than just continuing once. It's possible that other parts of the program use the routine I just modified and now won't perform as expected. But can I be bothered playing all through Golden Axe Warrior again? At this point, I turned off the computer and went to bed.

ZTAaN4S.png


Which, as it turns out, is highly relevant to the next stage of my hack's mission creep: when you stay at an inn, you don't get your MP back. This was questionable game design when the game was made, and doesn't make any sense now that I've put in full restore on death. It means getting yourself killed is a better move than resting (though I think when you die on the overworld you start at the last inn you stayed at, so it still makes sense to use them sometimes). OK, back to the debugger!

P8VhwgB.png


The in-game screen here is all black, so I'm just showing the debugger. The relevant two lines of code are immediately above the highlighted one, and as it happens they look familiar:

3A DA C0 loads maximum HP into A
32 18 C3 loads A into current HP

This is exactly the same code I used to give full HP on continuing. All I need to do to add a full MP restore is add the code I used for that earlier: 3A DC C0 32 DB C0. Problem is, there's nothing I want to delete here to make space for the extra code. If I just insert extra bytes here everything after it in the file will be moved from where it's supposed to be and anything that goes looking for the data will look in the wrong place. I could in theory go through and adjust every pointer, I guess, but that would be absurd. Instead, I'm going to use the work I've already done: I'll replace the HP refill code with a CALL instruction to the point in the continue code that restores HP/MP. Let's take another look at that:

401ZFbY.png


So here, starting from line 2623, we have the HP restore, the MP restore, a bunch of NOPs, then the value 06h is loaded to memory address C01D, then there's a RET instruction. If I use a CALL instruction in the inn code, execution will move to the HP/MP restore, then the NOPs, then modify memory address C01D, then return to the inn code. Sounds OK, but what does C01D do? Do I want to modify it?

qh6UjWO.png


The short answer is I don't know what it does and I don't want to modify it. In the above screenshots, C01D is the highlighted address in the memory editor. The first screen is a normal overworld shot. In the second, the screen is scrolling as I move between screens. C01D has gone from 0C to 0A, and as soon as the scrolling finished it changed back to 0C. It also changes on the continue screen, when I go indoors, and so on. I think it tells the game what sort of screen is currently on display, if that makes sense. Anyway, whatever it's for, it's not something I'm setting out to fiddle with, so let's not. I don't want my inn routine to change this memory address, but I do want to use my existing code for HP/MP restore and the RET instruction that follows. So, I'll just change the order of these instructions in the continue code - change C01D first, then do the HP/MP restore, then RET. I'll have the CALL instruction jump to the HP/MP restore, skipping the C01D bit. Simple!

3PdZs2e.png


Here's the new code in the inn routine. I've replaced loading the max HP into A with the CALL instruction, which moves execution to byte 2628 in the ROM, and I've replaced loading A into current HP with three NOPs.

9NzoRBi.png


And here's the continue routine. I've moved the modification of C01D to byte 2623, which used to be where the HP restore started. I also shifted the RET to be before the NOPs instead of after - gotta save those cycles. The continue routine does everything it did before, and the inn routine jumps in at the point where HP/MP restore starts (2628). This does mean that when the continue routine returns to wherever it was called from register A is carrying the value of maximum MP instead of 06h like it was before, but I had a look and it gets immediately changed to something else anyway so I don't think it matters. Now, the key question: does it work?

c5b95OL.png


It does! Continuing is still working, too. Hopefully I haven't broken anything else. I'll need to actually play the game to make sure. Also I can't rule out the game using different code when I rest in different towns or die in a dungeon or whatever, so there may be more changes to make. But for now, I've remodified the checksum in the header and it appears that I'm done.
 
Last edited:

RT-55J

space hero for hire
(He/Him + RT/artee)
Hot dang that's cool.

I remember trying to play through Golden Axe Warrior a while ago (after having finished Govellius), but giving up in frustration somewhere around the third dungeon. Maybe this will be what convinces me to finish the game.
 

Purple

(She/Her)
DMan's newest hack, Vitality, is by far his best and most approachable hack. The art and world design feel more confident and mature than his previous outings, and the environmental storytelling is more refined. Also, he had his girlfriend playtest the thing, which means the difficulty has been sanded down to "manageable by most people" and that wall-jumping is not required (the only advanced tech that is required is the rising mid-air morph, which is as easy as it gets imho). I highly recommend it myself, with only a couple caveats: (a) make sure you find at least one energy tank before heading to the second area, and (b) there's a reason the hack says it's "Rated R" (beyond the title screen and death animation) --- it's a tonal promise that the hack pays off by the end, and I know not everybody would like it.
So I just randomly stumbled across that one and... wow. Didn't actually play it first hand but from watching an LP, it seemed very "here is a decently designed largely original game in this engine," it does some REALLY creative stuff with the existing tileset (and showcases that Draygon's sprite really is a heck of a box of legos when broken up), does interesting things with the few bits of original art (modifying a couple bosses), and the way it handles plot progression flags for lack of a better term seems really technically neat. Not really sold on the plot of it, particularly the intro and the reference, but hey.
 

Becksworth

Aging Hipster Dragon Dad
On the subject of rom hacks from page one I got around to beating Peach's Adventure. Excellent game with a good difficulty up until the last level. Even it's not bad, it's just a LONG ass level by Mario standards and there is only one checkpoint, so don't be ashamed if you save scum between segments.

And to answer my question I found the dev's Deviant Art and BBW is definitely their fetish, but they're also surprisingly innocent/wholesome about it from the look of it. At the very least outside of some boob jiggle in Peach's running animation pervy-ness is kept to an absolute minimum in the rom hack.
 

RT-55J

space hero for hire
(He/Him + RT/artee)
So I just randomly stumbled across that one and... wow. Didn't actually play it first hand but from watching an LP, it seemed very "here is a decently designed largely original game in this engine," it does some REALLY creative stuff with the existing tileset (and showcases that Draygon's sprite really is a heck of a box of legos when broken up), does interesting things with the few bits of original art (modifying a couple bosses), and the way it handles plot progression flags for lack of a better term seems really technically neat. Not really sold on the plot of it, particularly the intro and the reference, but hey.
Always glad to see people experience Vitality. Still one of my favorites 2 years later. (Did I ever get around to providing more Metroid hack recommendations?)

With 2 years of hindsight, I still think that Vitality is a top-shelf narrative and aesthetic achievement (especially compared to Dread) with one caveat: you have to ignore every single bit of text the game provides. Everything else in the game ties together so cohesively and coherently, but as soon as the author commits more than a word to the screen the spell is broken. The Alien universe crossover is clumsy at best (though entirely expected if you're familiar with the author's prior work), but even worse the epilogue reads like a punchline.
 

Yimothy

Red Plane
(he/him)
I’ve been playing my Golden Axe Warrior hack and it seems to work perfectly - I thought dying in dungeons or using inns that charged might use different routines or something, but it’s all working. I think the hack has also improved the game a great deal - I’m finding it hard to believe I ever beat this game without it. Maybe I used save states? Was that an option on the PS3 Sega collection? I don’t remember.

Anyway, getting a full restore and not losing money on death makes the game pretty breezy. I no longer have to grind for HP/MP drops all the time. I suppose it ruins the balance a bit and makes things like the MP shops pointless but I don’t think those things matter. There are a couple of other annoying features that might be worth changing, like the cost of the earth magic - a full magic pot per cast. If it were purely offensive that’d be one thing, but you frequently have to use it on rocks and blocks to make progress which means I’m trying it out on all of them. Sometimes a single overworld screen might have enough rocks to use up all my MP, which is kind of annoying when I have the option to die or go to an inn to get it back but must be absolutely infuriating when running out meant grinding up some more drops. Maybe I should reduce the cost per cast. Another annoyance are enemies that weaken your armour. You can carry an item to fix it, but the last dungeon I was in had dozens of these enemies and a single touch is all it takes to inflict the effect permanently (until you heal it) so I just dealt with having weaker armour until the dungeon was done. Hopefully that’ll still be a viable approach in later dungeons.
 

RT-55J

space hero for hire
(He/Him + RT/artee)
(Did I ever get around to providing more Metroid hack recommendations?)
I swear I made a recommendation forSuper Metroid Y-Faster somewhere, but it's not in this thread. (whatever)

The main conceit of Y-Faster is that it has 4 areas branching off from a hub area, and can do them in any order (like a megaman). Thus, the appeal of the hack for me was replaying it over and over trying different routing options to see the various costs/benefits of different orders. It's not a long hack, but that does bring me to the hack's other conceit (and a major turnoff for many people): you have to complete the whole thing in under an hour of in-game time. Personally, I found that time limit to be perfectly tuned for a first playthrough (as long as you are aware of it), but I know many people who dropped the hack because of it.

The author ended up making two sequels to this hack a few years later, called Y-Faster 2 Fast and Y-Faster 2 Furious. The premise of both of these hacks is similar to the original Y-Faster, except each of the hack's 5 areas are based on other Super Metroid hacks. The result is very funny if you are familiar with the source material, but as a result both of these sequels are much harder than the original Y-Faster. Highly recommend if you want some distressingly accurate and loving homages to a bunch of terrible-to-mediocre SM hacks (I'm assuming that's none of you (I, for one, love it)).

(Metaquarius has not responded to my petitions for him to make a Y-Faster 3: Gensokyo Drift (he keeps saying "comment es-tu entré chez moi?" (whatever that means)))



Anyhow, my personal favorite Metroid series hack of the past two years is actually a Metroid 1 hack called Junkoid. Lemme just drop a ton a pictures to pique your interest:

ZU6U3ET.png
obYZCnA.png

Afflicted with perpetual nightmares, JUNKO is determined to defeat the manifestation of her dreams - the serpent trickster ASMODEUS.​

wTnFbWX.png
icXvb4g.png
KV1xuFy.png


QpTQei9.png
CCvr59D.png
BL4BuOp.png


ZRiQPY5.png
ZiLvg37.png
ZKpYIiA.png

It's got a fully custom soundtrack, tightly designed areas of entirely unique screens, a reasonably small scope (roughly 2-3 hours long) and excellent usage of background tile animations. Everybody I have recommended it to has loved it.
 

Beowulf

Son of The Answer Man
(He/Him)
I’ve been playing my Golden Axe Warrior hack and it seems to work perfectly - I thought dying in dungeons or using inns that charged might use different routines or something, but it’s all working. I think the hack has also improved the game a great deal - I’m finding it hard to believe I ever beat this game without it. Maybe I used save states? Was that an option on the PS3 Sega collection? I don’t remember.

Anyway, getting a full restore and not losing money on death makes the game pretty breezy. I no longer have to grind for HP/MP drops all the time. I suppose it ruins the balance a bit and makes things like the MP shops pointless but I don’t think those things matter. There are a couple of other annoying features that might be worth changing, like the cost of the earth magic - a full magic pot per cast. If it were purely offensive that’d be one thing, but you frequently have to use it on rocks and blocks to make progress which means I’m trying it out on all of them. Sometimes a single overworld screen might have enough rocks to use up all my MP, which is kind of annoying when I have the option to die or go to an inn to get it back but must be absolutely infuriating when running out meant grinding up some more drops. Maybe I should reduce the cost per cast. Another annoyance are enemies that weaken your armour. You can carry an item to fix it, but the last dungeon I was in had dozens of these enemies and a single touch is all it takes to inflict the effect permanently (until you heal it) so I just dealt with having weaker armour until the dungeon was done. Hopefully that’ll still be a viable approach in later dungeons.
I've never actually played Golden Axe Warrior, but when you've got your hack completed, I'm definitely going to try it.
 

Yimothy

Red Plane
(he/him)
I’m glad there’s some interest. At the moment I have moved the MP cost of the earth spell away from when you cast it and over to when it connects with an enemy, which allows it to be used infinitely for exploration but still limits using it for offence. The problem though is that now if you hit three enemies with one shot it triples the MP cost. I’ve written some code that will set a flag the first time it hits and not charge MP after that for the same shot, but to use it I need to store the flag in RAM somewhere, which means identifying some memory that is never used by the existing program. I think I’ve found some, but it’s hard to be certain without extensive play testing.

I also want to change the armour break status effect to go away when you die or rest in the inn, which should be straightforward once I find the location in memory where the status effect state is stored. I don’t think that’ll be too hard, but I haven’t started looking yet.
 

Yimothy

Red Plane
(he/him)
So I had what seemed like a pretty good Golden Axe Warrior hack: my key problem, needing to grind to get back HP and MP, solved. Losing money on death, gone. Rockin'. I started playing the game to make sure it would perform ok, and got about halfway through (5 of 9 crystals recovered). Doing so reminded me of the need to use the earth magic spell to investigate rocks to find hidden rooms and clear pathways, and the fact that if you run out of MP, which you quickly do when shooting magic at every rock, you have to get more before you can look again. Getting MP back on death or staying at an inn helped a great deal with that, but I thought I could do better. Also, the fifth dungeon introduces enemies who inflict the rusty status, which can only be healed with the magic oil, which you can only carry one of at a time, meaning taking a hit from one of them after you've healed once requires either leaving the dungeon and finding a shop with oil for sale or just dealing with lowered defence for the rest of the dungeon. I took on the earth magic's MP cost first, but the rust thing was simpler so let's go through that:

gHYvnpW.png


I took this screenshot after figuring things out, but I'll try to explain my process. In the lower part of the Memory Editor are a bunch of RAM addresses that control various aspects of the player character's status. 18 20 80 80 1C for example are respectively a mystery variable, my max HP, my current MP, my max MP, and how much cash I have. The random 01s in the bottom two rows are for the items I have - the 00s in the same place are mostly items I don't have yet. I started off by just randomly changing 00s to 01s in the hope that one of them stored the rust on/off status. This got me lots of items and occasionally crashed the game or messed up the graphics, but I didn't find what I was looking for.

So I got a little cleverer - I looked up the cheat code for having the magic oil item which cures rust. This let me know that that variable is stored at C0E2, so I set a breakpoint in the Meka Debugger for when that address gets written to, set it to 01 so that I had some oil, and then set off for the dungeon with the rust monsters (scorpions, I think - I wonder if it was supposed to be a poison status?). I got inflicted with rust, used the oil, and the debugger stopped execution after C0E2 was dropped from 01 (I have oil) to 00 (oil gone). You can see the code for this in the debugger on the right of the screenshot, just above the highlighted line:

Code:
AF          xor a
32 BF C0    ld (C0BFh),a
32 E2 C0    ld (C0E2h),a

What's happening here? Well, the first instruction, XOR A, takes the 8-bit value stored in register A and XORs it with itself bitwise. In other words, it compares each bit in A against the same bit in A. If the value of each is the same (which it always will be), the result of the eXclusive OR operation is zero, so it sets the bit in A to zero. To put it more simply, this instruction sets the value of A to 00. You could of course use a load instruction: LD A 00, but that would require two bytes and I think slightly more execution time (and, though this isn't immediately relevant, would have no effect on the Z80's flag register while XOR would). Anyways, A is set to zero. The next two lines then load that zero value into memory addresses C0BF and C0E2. We know that C0E2 is "do we have any oil?", but what does C0BF do? As it turns out, exactly what I want it to - I go into the memory editor and set C0BF to 01, and my guy is rusty again. I've found the value I want.

Now that I know the right memory address, I need to figure out what I want to do about it. One option would be to set a timer and have the rust go away after a certain time, but that would be more complicated than I want to be. Another would be to allow the player to accumulate more than one thing of oil, but again that would be complicated. I decided to keep it simple: I'll make the rust status revert to normal when you die or rest at an inn. And as it turns out, that's pretty easy for me to do, because I've already been fiddling with the code for death and resting.

If I look at my existing modification to the code:

3E 06 32 1D C0 3A DA C0 32 18 C3 3A DC C0 32 DB C0 C9 00 00 00 00 00 00 00 00 00

There's a whole bunch of zeroes at the end of the machine code. That's space where there used to be instructions but there aren't any more (because I removed the part that deducts your cash on death). So I can just stick a bit of code in there that'll fix the armour:

Code:
AF           XOR A, i.e., set A=00
32 BF C0     LD (C0BF), A - load the value of A (00) into memory address C0BF

So I just stick AF 32 BF C0 in before the C9 (return) in my previous code, delete the excess 00s at the end, and rust will be cured on death/rest. Easy!

jmwieSl.png


Now on to the tough stuff: making the earth spell free to use for breaking rocks and blocks. The simplest way to do this would be to make it always free, or to reduce the cost per cast as a middle ground move. To do that, I just need to find the place in the code that deducts the MP and change the value it deducts. In the above screenshot, I've started a new game, used the memory editor to give myself earth magic (set C0E5, the byte of RAM to the left of the selected byte, to 01), set a breakpoint for writes to the address where current MP is stored, and then cast the earth spell. As expected, the breakpoint has kicked in and stopped execution. Let's look at the code:

Code:
6E              ld l,(hl)       Load l with value stored at hex value of 
                                register hl in memory
3A DB C0        ld a,(C0DBh)    load a with current MP
95              sub l           subtract l from a
D8              ret c           if carry flag set (l bigger than a in previous), ret
32 DB C0        ld (C0DBh),a    set current MP to value of a
C9              ret

This appears to be a generic subtract routine rather than one specific to this spell - instead of loading a specific value and subtracting that from current MP, it gets a value from the memory address in the HL register and subtracts that value from current MP. If this subtraction takes current MP below zero, then the routine stops early (that's the ret c instruction - it means return from this routine if the carry flag is set). Otherwise, it puts the subtracted value into current MP and the routine ends. So I have two problems: one is that I don't know where HL was last set, and the other is that if this routine is shared by other parts of the game program then fiddling with it to modify the earth spell might break other stuff. The first problem should be easy to resolve: MEKA, the emulator I'm using, has a trace function in the debugger that can give me a list of recently executed instructions (I could just look at what comes earlier in the file than this code, but because execution can jump around in the file what's earlier in the file may not be what was recently executed). Unfortunately, for reasons I haven't been able to figure out, the tracer is not currently working for me. It worked fine when I was hacking Wonder Boy in Monster Land, but now when I try to use it it says there are zero logged instructions. I must have changed a setting somewhere or something, but I can't figure it out. Still, there are other options: the next instruction due to be executed is RET, which will move execution back to wherever this routine was called from.

iwWPvT5.png


Here I've stepped forward one instruction and jumped to where the subtract routine was called. The instruction above the highlighted one is call 30BBh, which is slightly earlier in the code than the subtract routine I spelled out above (I looked at the code at 30BB, but without access to the trace function to see what's going on before it's hard to make out exactly what it's doing - I think it's setting the MP cost but it seems needlessly complicated for that). I tried out the thunder and fire spells and they also made calls to 30BBh, but from slightly earlier and slightly later in the file respectively. So, although I don't fully understand this code, I'm pretty sure that the instruction at 307C is specific to the earth spell and starts a routine that checks whether you have enough MP and deducts the appropriate MP if so. The next instruction is ret c - the carry flag was set during the subtract routine if you didn't have enough MP, so I think that this ret is here to abandon the spell cast if you don't have enough MP. Time to experiment! I replaced CALL 30BBh with 00 00 00 - three no operation instructions. The intent was to remove the MP check and MP subtraction. Firing up the game, it worked! I had infinite use of the earth magic.

pd0i2CZ.png


Which is not bad for my purpose of stopping you running out of MP when you're testing rocks looking for hidden things, but the earth magic also has an effect on enemies - it freezes them in place temporarily. I still want that to cost MP, and my plan is to have MP deducted when the enemy gets hit rather than when the spell is cast. For that to happen, I need to identify the place in the code where the magic is striking the enemies. In the screenshot above, I've just frozen one of the enemies with the earth spell (the little cloud to the right of the enemy to the right of my character is the spell). The memory editor shows the data for the four enemies on screen, starting from C600, C630, C660, and C690. I found this data in memory by going to a screen with enemies on it, then scrolling through the memory editor looking for patterns of data that changed as the enemies moved around and did things, then confirmed that it was enemy data by killing them one at a time and watching sections of data disappear. Then I started firing off the earth spell and looking for the byte in memory that was changing when the spell hit. I've highlighted it in red in the memory editor - in the enemy I've just hit it's FC, in the others it's zero. It turns out that the spell sets that byte (C636 in this case) to FF, at which point the enemy freezes and the byte starts to count down to 00 and the enemy starts to move again. I assume it's going down one point per frame, giving about five seconds of freeze in my native PALonia or slightly over four seconds in NTSCerica. So it's back to the debugger. Let's set a breakpoint for writing the value FF to byte C636 and cast more earth magic:

znS1jox.png


OK, we don't have a lot of code to go on here - we know the last instruction executed was ld (ix+6=C636h),FFh, but not what came before that. I forget if I've mentioned this before, but the reason it's only showing one instruction is that we must have reached this point from either a call or a jump, where the program moves from one point in the file to another. This sort of thing is why the debugger's trace function, which is not currently working for me, is so useful. Anyway, the next instruction is a return, which will take me back to the place we called here from (technically, the last place anywhere was called from - it's possible there have been jumps since, which are one-way). Let's take a look:

0T5dxKj.png


I'll be honest: I don't know what's going on here. I could probably figure it out, but actually it's not relevant. I'm not looking to remove anything from what happens when the spell hits the enemy. What I want to do is add MP reduction to the existing behaviour. So let's go back to the code in the previous screenshot:

Code:
DD 36 06 FF     ld (ix+6=C636),FFh
C9              ret

The first line is the one we're interested in. It loads the value FF into the memory address at ix+6, which is currently C636, the one that stores the freeze counter. ix is one of the Z80's registers, and it appears it currently is storing the starting point of the relevant enemy's data (C630). The next line returns to whatever else the code was doing. My problem now is that there's no free space. I still want the freezing code to happen, but I need to add the MP reduction code. So there's really only one thing to do: put the code somewhere else and replace this load instruction with a call to my new code. Calling to a different address requires three bytes, so I can use the first three bytes of the four-byte load instruction and replace the last one with 00 - no operation. The program will jump to my new code, execute it, then return to the NOP, then hit the existing return and go back to what it was doing before. So let's take a look at the code I'm going to insert, as I wrote it in my notes file while making the hack:

Code:
new code:
LD a,C0DB    (set a to current MP)
SUB n        (subtract 08 from a)
RET C        (if current MP less than 08, do nothing)
LD C0DB,a    (set new MP)
LD (IX+6),FF (freeze enemy)
RET

Which is:
3A DB C0
D6 08
D8
32 DB C0
DD 36 06 FF
C9

But then I noticed that the earth cloud continues through enemies, hitting them repeatedly. With the code as above, you'd have all your MP chewed up by repeated strikes on the same enemy, so I added some more code at the start:

Code:
LD a,(IX+6)
SUB n (F0)
RET C

This loads the current value of the relevant byte into A, then subtracts F0 from it, and quits the routine early if the result is less than zero (which would indicate the enemy was already frozen). On reflection now I should probably have made that number lower in case the timer ticked lower than that before the cloud cleared the enemy, but (spoiler warning) I'll be removing this bit of code before we finish so it doesn't matter anyway.

EruGx2Z.png


The complete sequence is about twenty bytes. I needed to find somewhere to put it, so I just scrolled through the ROM in MEKA's Memory Editor until I reached the above - a big field of 00s. The last bit of code before all those zeroes is C3 44 74, which translates to JP 7444, an unconditional one-way jump to earlier in the code. So unless something in the program is jumping into this field of nothingness for some reason, it should be safe for me to modify this part of the ROM. There is one problem: the ROM is too big to fit entirely in the Z80's RAM, so it gets loaded in in chunks (I think the usual term is banks). This part of the ROM falls within the second chunk of the ROM, and the Z80 can fit three chunks at a time. Apparently most games always keep the first two chunks loaded and change the third RAM chunk to whichever ROM chunk is needed. Hopefully this is what GAW does and this section of ROM will always be in RAM. Anyways, hoping for the best I just copy/pasted my code in. And it didn't work - can you spot the error?

Code:
LD a,(IX+6)
SUB n (F0)
RET C

It's the last line - this code loads the value of the counter, subtracts F0, and drops out if the result is negative. Which is the opposite of what I want: if the counter is above F0, I want it to do nothing. If below, I want it to freeze. I need to change RET C (return if carry) to RET NC (return if no carry). So I do that, and it works. But! Now you get charged MP seperately for each enemy the spell hits, meaning a single cast against four enemies in a line might cost you four full MP pots. Not quite what I had in mind.

So I had a think, and landed on setting a variable in the RAM somewhere when the magic is activated, and then unsetting it when the first hit connects. Subsequent hits wouldn't need to check if the enemy was already frozen or if there was enough MP or to do an MP reduction, because the variable being unset while a spell was active would indicate it had already landed a hit and therefore was valid to land more. The only problem would be identifying some RAM that was never used by the existing program - I don't want to accidentally break something else, and I also don't want another part of the program randomly breaking what I'm trying to do. So I had a browse through the RAM in MEKA's memory viewer and found:

8PtqzPR.png


Another field of zeroes. Actually I found a couple of these, but this one stayed full of zeros as I played the game, whereas the one at C320, for example, looks good but fills with data when you cast a spell. There are probably better ways to find unused memory - I believe the emulator Emulicious has a function that specifically tracks which memory addresses have not been used while you play the game - but for now this seems to be suitable territory. My plan is to use byte CE01 in my code to see if it works, and then play the game through (probably just from where I'm up to, though) with a breakpoint for read/write actions on CE00 - if nothing accesses it in a playthrough then I'll move over to using CE00 (I don't want to set the breakpoint on the byte I'm using in my test code because it'll stop execution every time my code runs which would be annoying). Might also set a breakpoint on the RAM byte that controls which chunk of ROM data is loaded in the second slot to make sure it doesn't change and my extra code is always where it should be. Speaking of extra code, here's the routine I came up with:

Code:
3A 01 CE     load value of CE01 into A
A7           AND a - sets zero flag if a is zero (i.e., hit not yet landed)
C2 XX XX     if zero flag is not set, jump to XX XX (after MP deduction)
3A DB C0     load value of C0DB into A (current MP)
D6 08        subtract 08 from A
D8           return if carry (i.e., not enough MP)
32 DB C0     load A into C0DB (set current MP to new value)
3E 01        ld a,01
32 01 CE     load a (01) into CE01 (has it hit flag)
DD 36 06 FF  load (ix+6), FF - freeze enemy - make jump above to here
C9           return

XX XX in the above is where the second last line landed in the ROM once I'd put this sequence in, 7B 48 (actually written 48 7B because of endianness). It probably would have been better to use a relative jump rather than absolute, but that would have been an opportunity to miscalculate how far to jump so I did it this way. Anyways, I've skipped to the final version here, there were a couple of revisions. My new variable at CE01 is now set to zero when the spell is launched and changed to 01 when a hit lands, the reverse of how I first did it, which I changed to make the spell launching code more efficient. So basically,

  • I load my variable into register a and check if it's zero or not
  • If it is not zero, that means a hit has landed already and we can skip ahead to where the enemy gets frozen.
  • Otherwise, we load the current MP into register a, then subtract 8 from it.
  • If the result is less than zero, the routine quits and nothing happens - the enemy is not frozen, MP is not reduced, and the has-it-hit variable remains zero.
  • If the result is zero or higher, then that result is set as current MP, the has-it-hit variable is set to 01, and the enemy is frozen (this last is the point that gets jumped to if the has-it-hit variable is already 01).
  • The routine exits back to where it was called from.

Along with this I also needed to change the code for when the spell is cast. Previously, I just replaced the call to the MP subtraction routine with three NOPs. Originally, I wrote another routine to set the has-it-hit variable to 01, put it after the new code above, and replaced the three NOPs with a call to it. But then I realised that if I were to set to has-it-hit to 00 at this point instead of 01 I could do it in four bytes, and I also realised that the next instruction after the original MP subtraction call was a conditional return that I never wanted to execute, so I had an extra byte to work with, meaning I could fit in the new code without calling. This makes no difference whatsoever to the player experience, but it's a bit neater, so the new code there is:

Code:
AF          (XOR A)
32 01 CE    (set has it hit flag to A (00))

I put it all together, and it seems to work. Whew! Hopefully I won't have to find a different spot in RAM for the variable, or have issues with bank switching breaking my code. Otherwise, I'm done. I'm gonna finish my playthrough, and if nothing goes wrong I'll submit it to romhacking.net afterwards.
 

Kirin

Summon for hire
(he/him)
Very nice! At this rate you’ll be programming whole games directly in machine code before you know it. ;)
 

Yimothy

Red Plane
(he/him)
I won't say the thought hasn't crossed my mind, but I don't think that's going to happen.

Anyways, I've finished my playthrough of Golden Axe Warrior, and so far as I can tell my hack works just fine. Now I just need to come up with a readme and some screenshots and I can upload it to romhacking.net. I guess I need a title, too. I'm thinking "No Grind Hack" or something like that. Keep it simple.
 

Torzelbaum

????? LV 13 HP 292/ 292
(he, him, his)
There is one problem: the ROM is too big to fit entirely in the Z80's RAM, so it gets loaded in in chunks (I think the usual term is banks).
This sounds like memory paging but maybe it's different for single purpose systems like consoles.
 

Octopus Prime

Mysterious Contraption
(He/Him)

So this came out a few days ago and I’ve played it a little bit of it and, despite the pretty weird bitterness added into the introductory cutscene (it seems to imply that the Mario Brothers are the reasons there hasn’t been a Star Fox game in a while) it’s a really impressive hack.

It’s doubled the amount of levels in the game by adding a second star map, slightly remixed the audio so that it doesn’t go out of sync with the action despite moving a steady 60fps, and added the ability to toggle between first and third person cameras for all levels; in addition to an on-screen crosshair so you can aim in 3rd person mode (the Arwing is still large enough that it’s largely covering the reticle, but it’s a nice gesture).

My only real complaint is that while it gives each wing mate their own Arwing Color scheme so you can tell them apart more easily; Fox’s is a pretty unappealing pink/orange, and it’s the one I’m stuck looking at the most.
 

Becksworth

Aging Hipster Dragon Dad
I haven't played it yet but I saw there are alternative ship options. Maybe one is just a stock blue arwing?
 

Beowulf

Son of The Answer Man
(He/Him)
My hack is live on ROMhacking.net, so give it a shot if you’re interested.
I gave it a shot! Your hack makes the game significantly more playable, though I still don't think I'm going to get all the way through it. The fact that you need to navigate the crazy-powerful enemies in the mountains to get to the eighth heart and then still need to beat the 4th dungeon before you can get an armor upgrade is pretty much what wore me down. But I appreciated learning about this game (that I'd never heard of before this) and giving it a try.

(Random note you probably don't care about because I suspect the problem is the emulator and not your hack, but the OpenDingux port of PicoDrive on the RG350 displays graphical glitches when running it. It works perfectly on RetroArch and I suspect most other options.)
 

Yimothy

Red Plane
(he/him)
Yeah, I don’t think graphical glitches would come from my hack, though I guess I can’t rule it out. Do they happen on the unmodified ROM?
 

Beowulf

Son of The Answer Man
(He/Him)
Yeah, I don’t think graphical glitches would come from my hack, though I guess I can’t rule it out. Do they happen on the unmodified ROM?
...It hadn't occurred to me to check until now, but yes. The original rom has them too.
 
Top