Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Another softlock possibility while cursed. #90

Open
CaitSith2 opened this issue Jun 24, 2019 · 3 comments
Open

Another softlock possibility while cursed. #90

CaitSith2 opened this issue Jun 24, 2019 · 3 comments

Comments

@CaitSith2
Copy link
Contributor

You can be softlocked in the following situation.

  1. You are cursed.
  2. The castle is surrounded by Swamp.
  3. You don't have Erdrick's Armour.
  4. You don't have the spells Heal or Healmore, or you don't have sufficient MP to cast the spell.
  5. You don't have any herbs on hand.
  6. You die either in battle, or on damage tiles.
  7. There isn't a town horizontally/vertically adjacent to the castle that is not haukness, or you have insufficient gold to stay at the inn of said town. (If there is a town, the other criteria is not having Magic armour, and likely insufficient gold to buy magic armour, assuming the town sells it.)

What happens, is the game gives you exactly one HP, and kicks you out of the castle right then and there, with no way to get to a town to recover HP/MP.

@CaitSith2
Copy link
Contributor Author

CaitSith2 commented Jun 24, 2019

As a note, I have located the section of code that handles the giving of 1HP.

03:CB6B A5 CF    LDA $00CF
03:CB6D 29 C0    AND #$C0  ;Check to see if cursed item is equipped
03:CB6F F0 07    BEQ $CB78 ;if so, give exactly 1 HP.
03:CB71 A9 01    LDA #$01
03:CB73 85 C5    STA $00C5
03:CB75 4C 96 CB JMP $CB96
;code after this point handles full HP/MP recovery.

@CaitSith2
Copy link
Contributor Author

CaitSith2 commented Jun 25, 2019

Wrote a vpatch block, that changes the code a tiny bit. It gives the lesser of max HP or 75, and exactly 8MP on revive, if cursed, otherwise, it gives full HP/MP as normal.

vpatch(rom, 0x0cb6b, 85,
    0xA9, 0x30,             /* LDA #$30    ; Move always initalized stuff up here.          */
    0x85, 0x90,             /* STA $0090   ;                                                */
    0xA9, 0x40,             /* LDA #$40    ;                                                */
    0x85, 0x92,             /* STA $0092   ;                                                */
    0xA9, 0x00,             /* LDA #$00    ;                                                */
    0x85, 0xD6,             /* STA $00D6   ;                                                */
    0x85, 0xDB,             /* STA $00DB   ;                                                */
    0x85, 0x91,             /* STA $0091   ;                                                */
    0x85, 0x93,             /* STA $0093   ;                                                */
    0xA2, 0x03,             /* LDX #$03    ;                                                */
    0x86, 0x3A,             /* STX $003A   ;                                                */
    0x86, 0x8E,             /* STX $008E   ;                                                */
    0xE8,                   /* INX         ;                                                */
    0x86, 0x3B,             /* STX $003B   ;                                                */
    0x86, 0x8F,             /* STX $008F   ;                                                */
    0xE8,                   /* INX         ;                                                */
    0x86, 0x45,             /* STX $0045   ;                                                */
    0xE8,                   /* INX         ;                                                */
    0xE8,                   /* INX         ;                                                */
    0x86, 0x4B,             /* STX $004B   ;                                                */
    0xE8,                   /* INX         ;                                                */
    0x86, 0x4A,             /* STX $004A   ; End of always initialized variables.	        */

    0xAD, 0x3A, 0x60,       /* LDA $603A   ; Check to see if game was just loaded.	        */
    0xC9, 0x78,             /* CMP #$78    ;                                                */
    0xD0, 0x25,             /* BNE $CBBE   ; If yes, skip restoring record.	                */

    /* Preload Cursed HP/MP */
    0x86, 0xC6,             /* STX $00C6   ; MP = 8 - Enough to cast Healmore exactly once. */
    0xA9, 0x4B,             /* LDA $#4B    ; HP = 75                                        */ /* If desired, compute how much HP is actually needed to make it to a town, and set that value instead. */
    0xC5, 0xCA,             /* CMP $00CA   ; Or current maximum                             */
    0x90, 0x02,             /* BCC $CBA3   ; Whichever is less                              */
    0xA5, 0xCA,             /* LDA $00CA   ;                                                */
    / * cba3: */
    0x85, 0xC5,             /* STA $00C5   ; Store Max HP                                   */

    0xA5, 0xCF,             /* LDA $00CF   ; Is cursed belt/death necklace equipped?        */
    0x29, 0xC0,             /* AND #$C0    ;                                                */
    0xD0, 0x13,             /* BNE $CBBE   ; If yes, skip full HP/MP restore                */
    0xA5, 0xCA,             /* LDA $00CA   ; Load Max HP                                    */
    0x85, 0xC5,             /* STA $00C5   ;                                                */
    0xA5, 0xCB,             /* LDA $00CB   ; Load Max MP                                    */
    0x85, 0xC6,             /* STA $00C6   ;                                                */
    0xAE, 0x39, 0x60,       /* LDX $6039   ;                                                */
    0xA9, 0xAB,             /* LDA #$AB    ;                                                */
    0x9D, 0x45, 0x60,       /* STA $6045,X ;                                                */
    0x8D, 0x3A, 0x60,       /* STA $603A   ;                                                */
    /* cbbe: */
    0xEA,                   /* NOP	       ;                                                */
    0xEA                    /* NOP         ;                                                */
);

I confirmed that the code that preserves register X was not required, as the calls that follow clobbers register X without using whatever value it had.

@CaitSith2
Copy link
Contributor Author

CaitSith2 commented Jun 27, 2019

Had another idea, which took me a while to write a vpatch for. The idea is if cursed, the HP/MP only restores fully up to a certain level, Code wise, that level is being defined as Level 7 plus/minus 2, randomly selected per seed.

dw_stats *stats;
stats = &rom->stats[mt_rand(5, 9)];    //Base Cursed HP off of stats randomly chosen from Level 5 to Level 9.  (7 +/- 2)

vpatch(rom, 0xcb6b, 85, 
    0x84, 0xd6,       /* STY $00D6   ; Register Y is definitely 0 by the time this code is reached.                           */
    0x84, 0xdb,       /* STY $00DB   ; Moved the always initialized values on load/death to the top.                          */
    0x84, 0x91,       /* STY $0091   ;                                                                                        */
    0x84, 0x93,       /* STY $0093   ;                                                                                        */
    0xa9, 0x30,       /* LDA #$30    ;                                                                                        */
    0x85, 0x90,       /* STA $0090   ;                                                                                        */
    0xa9, 0x40,       /* LDA #$40    ;                                                                                        */
    0x85, 0x92,       /* STA $0092   ;                                                                                        */
    0xa2, 0x08,       /* LDX #$08    ;                                                                                        */
    0x86, 0x4a,       /* STX $004A   ;                                                                                        */
    0xca,             /* DEX         ;                                                                                        */
    0x86, 0x4b,       /* STX $004B   ;                                                                                        */
    0xa2, 0x05,       /* LDX #$05    ;                                                                                        */
    0x86, 0x45,       /* STX $0045   ;                                                                                        */
    0xca,             /* DEX         ;                                                                                        */
    0x86, 0x8f,       /* STX $008F   ;                                                                                        */
    0x86, 0x3b,       /* STX $003B   ;                                                                                        */
    0xca,             /* DEX         ;                                                                                        */
    0x86, 0x8e,       /* STX $008E   ;                                                                                        */
    0x86, 0x3a,       /* STX $003A   ; End of Always Initialized Values.                                                      */
    
    0xa2, 0x01,       /* LDX #$01    ; HP/MP restore code completes two loops, MP is restored first.                          */
    0xad, 0x3a, 0x60, /* LDA $603A   ; Check to see if the save was just loaded.                                              */
    0xc9, 0x78,       /* CMP #$78    ; If so, skip the rest of this code.                                                     */
    0xd0, 0x27,       /* BNE $CBC0   ;                                                                                        */
    0xa0, stats->mp,  /* LDY #$24    ; Store Max Cursed MP.  (Based off of random selection of level 7 plus/minus 2 base MP)  */
    
    /* CB9B: */
    0xa5, 0xcf,       /* LDA $00CF   ; Load Equiped items                                                                     */
    0x29, 0xc0,       /* AND #$C0    ; Check against Death Necklace / Cursed Belt.                                            */
    0xf0, 0x05,       /* BEQ $CBA6   ; If not cursed, directly load Max HP/MP.                                                */
    0x98,             /* TYA         ; Otherwise, move Cursed HP/MP into memory.                                              */
    0xd5, 0xca,       /* CMP $CA,X   ; Check to see if Cursed HP/MP is greater than Max HP/MP.                                */
    0x90, 0x02,       /* BCC $CBA8   ; If so, directly load Max HP/MP.                                                        */
    
    /* CBA6: */
    0xb5, 0xca,       /* LDA $CA,X   ;                                                                                        */
        
    /* CBA8: */
    0x95, 0xc5,       /* STA $C5,X   ; Store Loaded HP/MP value.                                                              */
    0xa0, stats->hp,  /* LDY #$32    ; Set Max Cursed HP.  (Again, Level 7 plus/minus 2 base HP)                              */
    0xca,             /* DEX         ;                                                                                        */
    0xf0, 0xec,       /* BEQ $CB9B   ; Loop again if MP was set, otherwise continue on.                                       */
    0xa5, 0xcf,       /* LDA $00CF   ; Check to see if cursed.                                                                */
    0x29, 0xc0,       /* AND #$C0    ;                                                                                        */
    0xd0, 0x0b,       /* BNE $CBC0   ;                                                                                        */
    0xae, 0x39, 0x60, /* LDX $6039   ; If not, mark save as already loaded.                                                   */
    0xa9, 0xab,       /* LDA #$AB    ;                                                                                        */
    0x9d, 0x45, 0x60, /* STA $6045,X ;                                                                                        */
    0x8d, 0x3a, 0x60  /* STA $603A   ;                                                                                        */
    /* CBC0: */
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant