Faxanadu - Unused items and saving unlocked doors

Started by njosro, August 28, 2021, 01:17:42 PM

Previous topic - Next topic

njosro

I decided to have fun and work on a little hack to make the unused items Brown Potion (BLACK POTION) and Fire Crystal (CRYSTAL) have functionality!

The hack is based on UnsavoryMaggot's Faxanadu Restoration hack v1.04. (Thanks for all your hard work!!)

It's a work in progress and currently none of the items have their own text. They just say the Red Potion text.

Video:
https://youtu.be/g6q201wMLRE

- The brown potion refills magic, and the refill animation is faster and smoother than the red potion in the original game.
- The hourglass doesn't halve your remaining health, and it lasts twice as long (just because!)
- The fire crystal deals massive damage to the enemies on screen. It will usually kill them all but some enemies like the cobra and the bosses have enough HP that they won't get killed.
- bread restores magic by half as much as it restores health.

Here's what I was thinking for the message that appears when you use the fire crystal:
I struck the fire crystal.

Next, I want to make the Holy Bible (BOOK) teleport you to the priest (guru) you would appear at if you died. But using the Bible you won't lose any EXP or gold. So it's like an emergency exit from the battle field.

As for the lamp, I think it should just be changed into another item. I was thinking of using the graphics for the FIRE CRYSTAL (not the one featured here, but the one in the original that has a diamond graphic) and then go from there.
What functionality would you give to an extra item?

Here's some code snippets.

Brown Potion:

C48B    LDA EquippedItem         
C48E    JSR $FE60               

@FE60:
FE60    ASL A                   
FE61    TAY                     
FE62    CPY #$22    ;check if item used * 2 is 22 (brown potion)
FE64    BNE $FE69   ;exit if not
FE66    LDY #$20    ;set Y to 20 otherwise (will point to red potion code)
FE68    CLC                     
FE69    RTS

@C491:
C491    NOP                     
C492    BCS $C49C   ;if the item index used is too high then exit
C494    LDA $C49E,Y ;get low byte of location to jump to based on item used (red potion in this case)
C497    PHA         ;push onto the stack
C498    LDA $C49D,Y ;get high byte of location to jump to based on item used (red potion in this case)
C49B    PHA         ;push             
C49C    RTS         ;pull the two bytes from the stack and jump there.

@C533:
C533    LDA #$80           ;index of red potion message     
C535    JSR ShowMessage
C538    .db 0c 41 82       ;idk what this is but it's required for the ShowMessage function to work
C53B    LDA EquippedItem         
C53E    STA $A0                 
C540    JSR RemoveSelectedItem   
C543    LDX #$50           ;max health is 50 so this is the max countdown for refill
C545    TXA                     
C546    PHA                ;save onto stack
C547    AND #$01           ;check if the countdown is at an even number
C549    BEQ $C550          ;if so, allow the refill sound to play
C54B    LDA #$13           ;(I did this ^ to prevent the refill sound from sounding weird)
C54D    JSR PlaySound           
C550    LDA #$02                 
C552    LDX $A0            ;retrieve the item that was actually used (brown potion or red potion)
C554    NOP                     
C555    JSR $FE06               

@FE06:
FE06    CPX #$11             ;if brown potion, skip to the mana part.   
FE08    BEQ $FE10               
FE0A    JSR AddHealthPoints     
FE0D    JMP $FE13               
FE10    JSR AddMana             
FE13    JSR $DC46              ;do something?
FE16    JSR $CA25              ;do a frame of refill 
FE19    JSR $CBA8               
FE1C    JSR $CA25              ;do another frame of refill 
FE1F    JSR $CBA8               
        RTS

C558    LDA $A0               ;again check which item was used   
C55A    CMP #$11              ;check if brown potion   
C55C    BNE $C563             ;skip to health part if not
C55E    LDA ManaPoints       
C561    BCS $C566               
C563    LDA HealthPoints         
C566    STA $B0               ;store current mana/health (whichever one is refilling) into B0   
C568    NOP                     
C569    NOP                     
C56A    NOP                     
C56B    NOP                     
C56C    PLA                     
C56D    TAX                     
C56E    LDA $B0                 
C570    NOP                     
C571    CMP #$50           ;if the amount of mana/health reached max then exit, else loop.     
C573    BCS $C578               
C575    DEX                     
C576    BNE $C545               
C578    RTS                     


Fire Crystal:

C48B    LDA EquippedItem         
C48E    JSR $FE60               

@FE60:
FE60    ASL A                   
FE61    TAY                     
FE62    CPY #$22    ;check if item used * 2 is 22 (brown potion)
FE64    BNE $FE69   ;exit if not (will exit because fire crystal is not)
FE66    LDY #$20
FE68    CLC                     
FE69    RTS

@C491:
C491    NOP                     
C492    BCS $C49C   ;if the item index used is too high then exit
C494    LDA $C49E,Y ;get low byte of location to jump to based on item used (fire crystal in this case)
C497    PHA         ;push onto the stack
C498    LDA $C49D,Y ;get high byte of location to jump to based on item used (fire crystal in this case)
C49B    PHA         ;push             
C49C    RTS         ;pull the two bytes from the stack and jump there.

@FE23:

FE23    LDA #$80     ;index of message to show (red potion because I dont know how to make a new text)           
FE25    JSR ShowMessage           
--------data block--------
FE28  .db $0C $41 $82         
----------------         
FE2B    LDX #$07     ;loop through the 8 enemies that could possibly be on the screen
FE2D    LDA $02CC,X  ;Check if the current enemy's ID is FF           
FE30    CMP #$FF                 
FE32    BEQ $FE44    ;skip to the next loop if it is.
FE34    STX $A0      ;store the current loop index.
FE36    TXA                     
FE37    STA $0378    ;set CurrentEnemyToHandle to the current loop index.           
FE3A    LDA #$27     ;amount of damage to deal
FE3C    STA $00      ;used by subroutine below.
FE3E    JSR $8891    ;This subroutine handles damage dealing. I jump into the middle of it.
FE41    LDA $A0      ;retrieve current loop index.
FE43    TAX                     
FE44    DEX                     
FE45    BPL $FE2D               
FE47    JSR $C4BF    ;Remove fire crystal from inventory
FE4A    RTS                     



You can play around with my progress so far by downloading the patch here:
https://drive.google.com/uc?export=download&id=1UNejlrLYrWfi-QpIg2E3JdXDJQoPXpHW
I think this one is just for the fire crystal but it might also have all the other changes... I haven't been good at keeping track.
You have to first apply umaggot's faxanadu restoration v1.04 on a japanese faxanadu rom and then apply this patch.

ifightdragons

These are all very welcome additions. Hopefully you will add the patch to the site when it's done!

the_E_y_Es

Faxanadu! It's great to see this getting some attention.  :)

I like the changes so far. The fire crystal text is more than appropriate, too.

I've been thinking of hacking this game to change the doors -- once you use a key, the door should stay open permanently. And I'd like to make the jump smoother and less restricted, if possible. After doing a little bit of SNES asm, I feel more confident in attempting these two things.

Thanks for this :beer:

njosro

#3
Quote from: ifightdragons on August 28, 2021, 06:01:25 PM
These are all very welcome additions. Hopefully you will add the patch to the site when it's done!
For sure!

Quote from: the_E_y_Es on August 29, 2021, 06:16:50 AM
Faxanadu! It's great to see this getting some attention.  :)

I like the changes so far. The fire crystal text is more than appropriate, too.

I've been thinking of hacking this game to change the doors -- once you use a key, the door should stay open permanently. And I'd like to make the jump smoother and less restricted, if possible. After doing a little bit of SNES asm, I feel more confident in attempting these two things.

Thanks for this :beer:

I'm happy you're interested! The keys definitely need that change, and so does the physics engine. The only thing with the keys is that the mantra system wasn't designed to remember which doors were unlocked. But, since this is based on umaggot's restoration hack with saving, we could manually read/write the appropriate bytes to SRAM during the same routine that auto reads/writes the mantra to SRAM. So it shouldn't be a problem!

September 03, 2021, 09:16:22 AM - (Auto Merged - Double Posts are not allowed before 7 days.)

patch on google drive has been updated and the OP has the link.

the_E_y_Es

Hello again. I've found the relevant code for the doors' requirements and key usage. I'm using FCEUX. I also found a good spot to place my jump (after the door check is successful). Let me ask, where is some free space I can use in the patched retranslation ROM? Looking at your snippets, seems you managed to write your stuff in place/without jumping.

njosro

Good find.
My code actually does do a bit of jumping. Some of it changes the existing code but a lot of it is in a new spot.
You'll have to check the bank that the door code is in. You can't jump to the spot I used unless the place you're jumping from is in the same bank.

For the bank with the item usage code, the free space was at the end of the bank.

Since you're using FCEUX, you can set a breakpoint for when the door requirement code executes, then use the debugger to look through the bank that it stopped at for free space. It'll probably be at the end of the bank as well.

the_E_y_Es

Ah, I understand now. I applied your patch and it seems the $FE60 segment is now free. I'll use that spot, then.

Key requirements start at $E5DB in RAM, offset 0x03E5EB in ROM. So we have:

$E5B9: LDA $E5DB,Y ;loads key requirement for current door
$E5BC: STA $042B ;stores it


Then later:

$EB2F: LDA $042B ;loads key requirement for current door
$EB32: BEQ $EB3E ;is it open?


After that, it checks your selected item. The relevant byte is $03C1.

$EB81: LDA $03C1 ;loads selected item ID
$EB84: CMP #$07 ;is it key of Jack?
$EB86: BEQ $EBD1 ;if yes, go to $EBD1


^There are other snippets like this one, with similar checks for different keys. If the check is successful, they lead to $EBD1:

$EBD1: LDA #$84
$EBD3: JSR $F921


I assume JSR $F921 is the "door unlocked" routine.

My idea is to overwrite the key requirements at $E5DB with "00" everytime a door is unlocked. Then save that whole segment to SRAM. It looks like this:

00 04 00 03 00 01 00 07 00 08 00 00 00 01 00 02 01 03 02 04 03 05 04 05 00 00 08

In this string, the values represent the keys, as in:

00 = (none)
01 = Ace
02 = King
03 = Queen
04 = Jack
05 = Joker
06/07/08 = Rings

When I've made some progress, I'll post it here (if you don't mind me highjacking your thread).

njosro

This is great stuff!

Your idea makes sense to me. Feel free to use this thread for your updates :)
I updated the thread title to accommodate it.

StarWyvern

 This looks like a definitely needed improvement. I hated having to rebuy keys for the same door. I hope the finished patch will be compatible with the Facelift patch.  :thumbsup:
Insert "Witty Text" here.

Ok Impala!

This is an extremely cool hack! Maybe it's also possible to make the towers in Mist land more useful? The extra item could be some kind of ultimate key to continue forward with your quest. Would also love the last boss to be more of a fight. You can now blast it with your strongest Magic and be done with in seconds. Even though the game states that shouldn't be possible. And while we're at it, could you give the fighting master in the first town some more meaning? Now he just heals your, which is pretty redundant. I always thought they had some other use for him, but ultimately never found the time to implement it.  :huh:

njosro

QuoteMaybe it's also possible to make the towers in Mist land more useful?
Yes! I want to make all the towers have cool stuff in them. That useless tower is so stupid!

QuoteWould also love the last boss to be more of a fight. You can now blast it with your strongest Magic and be done with in seconds. Even though the game states that shouldn't be possible.
I completely agree. I don't think it'll be too hard to implement. It's near the same code that I had to get into for the fire crystal to work.

QuoteAnd while we're at it, could you give the fighting master in the first town some more meaning? Now he just heals your, which is pretty redundant. I always thought they had some other use for him, but ultimately never found the time to implement it.
I've thought the exact same thing. Thanks for reminding me about that! He needs to do something useful. Any ideas?

lexluthermiester

Have to agree with all the encouragement here! This looks like a great project!

Ok Impala!

Quote from: njosro on September 22, 2021, 01:27:00 PM
I've thought the exact same thing. Thanks for reminding me about that! He needs to do something useful. Any ideas?

Since the game already has code to increase your strength through the pendant, I thought it might be fun if the fighting master gives you a temporary attack or defense boost. Or even better, he sells you an item which can be used for that.

phosphorescent

This sounds like an awesome project!  I realize this thread is a couple of months old.  Any updates?  :)