Hacking the SNES ROM

Discuss PoP1 for SNES here.
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 13th, 2020, 3:14 am - Multiple special exits per level in all four directions.
- Multiple checkpoint and restart points per level. (Maybe passwords can use the unused checkpoint feature that would restore you at the checkpoint, or the code isn't complete?)
I chose to do these two together, because both hacks need to pay attention to the prince leaving rooms.

First part: Watch for the prince exiting rooms.
WRONG: At 0x8139 write: 20 60 FA
WRONG: At 0xFA60 write: 8D 8B 05 A2 0F BD 90 FA CD 79 05 D0 1F BD A0 FA CD 62 04 D0 17 BD B0 FA CD 8B 05 D0 0F BD C0 FA F0 08 C9 FF D0 03 4C FA 9E 4C BF 83 CA 10 D8 60
FIX: At 0x82CF write: 20 60 FA
FIX: At 0xFA60 write: 8D 8B 05 A2 0F BD A0 FA CD 79 05 D0 21 BD B0 FA CD 62 04 D0 19 BD C0 FA CD 8B 05 D0 11 BD D0 FA F0 0C C9 FF D0 03 4C FA 9E 20 BF 83 80 03 CA 10 D4 AD 8B 05 4C 72 84

Second part: Handle checkpoints when restarting the level.
At 0xDF18 write: 4C 10 FB
At 0xFB10 write: AD 27 06 D0 03 4C 1B E0 A2 0F BD A0 FA CD 79 05 D0 20 BD D0 FA CD 27 06 D0 18 BD E0 FA 8F 10 F1 7F BD F0 FA 8F 11 F1 7F BD 00 FB 8F 12 F1 7F 4C 1B E0 CA 10 D5 4C 1B E0

Third part: Configuring the special exits and checkpoints.
16 events are supported by default, so the index X can go from 0x0 to 0xF.

At 0xFAA0 + X write the level number. 00=level 1, 01=level 2, etc. as usual.
At 0xFAB0 + X write the room which the prince needs to leave to trigger the event.
At 0xFAC0 + X write the direction in which the prince needs to leave the room. 00=left, 01=right, 02=up, 03=down.
At 0xFAD0 + X write what should happen: 00=nothing, FF=level complete, 01,02,03,etc.=set checkpoint. (Different checkpoints on the same level must have different numbers.)
For checkpoints only:
At 0xFAE0 + X write the room where the prince should restart.
At 0xFAF0 + X write the tile position where the prince should restart.
At 0xFB00 + X write the direction to turn: 00=right, FF=left.

If you need more than 16 events (in the whole game) then change the following:
* The bytes after A2 bytes (LDX #$..) to the number of events minus 1.
* The 2-byte offsets after BD bytes (LDA $....,X), to the new location of each table.


Details:

Code: Select all

First part:

At 0x82CF write:
20 60 FA  JSR $FA60

At 0xFA60 write:
8D 8B 05  STA $058B ; ]cutdir
A2 0F     LDX #$0F ; number of room events-1
          :loop
BD A0 FA  LDA $FAA0,X ; level[X]
CD 79 05  CMP $0579 ; current level
D0 21     BNE :no
BD B0 FA  LDA $FAB0,X ; leave_room[X]
CD 62 04  CMP $0462 ; Char.room ; CharScrn
D0 19     BNE :no
BD C0 FA  LDA $FAC0,X ; leave_direction[X]
CD 8B 05  CMP $058B ; ]cutdir
D0 11     BNE :no
          ; found a room event
BD D0 FA  LDA $FAD0,X ; action[X]
F0 0C     BEQ :no ; zero means no action
C9 FF     CMP #$FF
D0 03     BNE :chkp ; FF means next level
4C FA 9E  JMP $9EFA ; seq level ended ; GoneUpstairs
          :chkp ; 01..FE means checkpoint
20 BF 83  JSR $83BF ; set checkpoint
80 03     BRA :end
          :no
CA        DEX
10 D4     BPL :loop
          :end
AD 8B 05  LDA $058B ; ]cutdir
4C 72 84  JMP $8472 ; do warp? ; CUT


Second part:

At 0xDF18 write:
4C 10 FB  JMP $FB10

At 0xFB10 write:
AD 27 06     LDA $0627 ; checkpoint on/off
D0 03        BNE :1
4C 1B E0     JMP $E01B ; default startpos
             :1
A2 0F        LDX #$0F ; number of room events-1
             :loop
BD A0 FA     LDA $FAA0,X ; level[X]
CD 79 05     CMP $0579 ; current level
D0 20        BNE :no
BD D0 FA     LDA $FAD0,X ; action[X]
CD 27 06     CMP $0627 ; checkpoint on/off
D0 18        BNE :no ; zero means no action
BD E0 FA     LDA $FAE0,X ; restart_room[X]
8F 10 F1 7F  STA $7F:F110 ; start room
BD F0 FA     LDA $FAF0,X ; restart_tile[X]
8F 11 F1 7F  STA $7F:F111 ; start tile
BD 00 FB     LDA $FB00,X ; restart_direction[X]
8F 12 F1 7F  STA $7F:F112 ; start direction
4C 1B E0     JMP $E01B ; default startpos
             :no
CA           DEX
10 D5        BPL :loop
4C 1B E0     JMP $E01B ; default startpos
Last edited by David on July 11th, 2020, 9:39 am, edited 1 time in total.
Reason: Fixed one of the hacks.
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 28th, 2020, 5:31 pm Ah, so doing it via hex-editing isn't possible? I recall one door sprite on The Quiet Levels being swapped with another door sprite from a different level.
Ah, yes, I explained that here: viewtopic.php?p=21860#p21860

However, swapping level door sprites is different from swapping wall graphics.

Each level door sprite is in a separate sprite resource, and they are loaded only when needed.
So it's possible to change which one is loaded per level or even per room.

In contrast, wall graphics are part of the environment graphics, which are loaded when the level starts.
It's not straightforward to load different tiles from different environments.
Maybe the three layers could be loaded from different environments, but anything finer than that is too hard.

Shauing wrote: June 28th, 2020, 5:31 pm In any case, we might now focus on the hack of multiple special exits in all four directions
I've done that in my previous post. (I posted it before I saw your post.)
Shauing wrote: June 28th, 2020, 5:31 pm and see if levels can have different start points depending of the exit path that is taken, perhaps similar to the checkpoint system that restores you to some part of the level after crossing a specific room, in this case it could be a specific room and/or exit from a different level,
Yes, checkpoints seem to be the way to go. Except these checkpoints must not be zeroed when leaving the level.

Part 1: Don't clear the checkpoint flag when the prince enters a different level.
WRONG: At 0xF786 write: EA EA EA EA EA
FIX: At 0xF786 write: A9 00 EA EA EA

Part 2 is a variant of this hack: viewtopic.php?p=28586#p28586
At 0x9F01 write: 20 00 FD EA
At 0xFD00 write: 9C 27 06 AD 79 05 AE 06 05 [ C9 LL D0 0C E0 RR D0 08 A9 CH 8D 27 06 A9 NN 60 ] 1A 60

Where:
* LL is the level where the exit door is. (As usual, 00=level 1, 01=level 2, etc.)
* RR is the room of the exit door. (I'm assuming you would put the two exits into different rooms.)
(This works with special exits as well, in that case RR is the room which the prince leaves.)
* CH is the checkpoint on level NN where the prince should start. (Use 00 for the regular starting position set in the level editor.)
* NN is the level where this exit door should lead.
* [ ] means you can repeat the enclosed part as many times as needed, with different values of LL,RR,CH,NN.

You only need to include the cases where either:
a) the exit door doesn't lead to the next level (NN is not LL+1), or
b) the prince doesn't start the next level from the regular starting position (CH is not 00).


Details:

Code: Select all

We overwrite this with NOPs:
01:F786: a9 00       LDA #$00
01:F788: 8d 27 06    STA $0627 ; checkpoint on/off

At 0x9F01 write:
20 00 FD  JSR 0xFD00
EA        NOP

At 0xFD00 write:
9C 27 06  STZ $0627 ; checkpoint on/off
AD 79 05  LDA $0579 ; current level
AE 06 05  LDX $0506 ; shown room ; VisScrn
          [[[ repeat as needed
C9 LL     CMP #$LL ; current level
D0 0C     BNE :1
E0 RR     CPX #$RR ; room
D0 08     BNE :1
A9 CH     LDA #$CH ; checkpoint index
8D 27 06  STA $0627 ; checkpoint on/off
A9 NN     LDA #$NN ; next level
60        RTS
          :1
          ]]]
1A        INC
60        RTS
This is my last post for today, I will see your replies next weekend.
User avatar
Shauing
Calif
Calif
Posts: 432
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Hacking the SNES ROM

Post by Shauing »

Spoiler: show
David wrote: June 28th, 2020, 8:46 pm
Shauing wrote: June 13th, 2020, 3:14 am - Multiple special exits per level in all four directions.
- Multiple checkpoint and restart points per level. (Maybe passwords can use the unused checkpoint feature that would restore you at the checkpoint, or the code isn't complete?)
I chose to do these two together, because both hacks need to pay attention to the prince leaving rooms.

First part: Watch for the prince exiting rooms.
At 0x8139 write: 20 60 FA
At 0xFA60 write: 8D 8B 05 A2 0F BD 90 FA CD 79 05 D0 1F BD A0 FA CD 62 04 D0 17 BD B0 FA CD 8B 05 D0 0F BD C0 FA F0 08 C9 FF D0 03 4C FA 9E 4C BF 83 CA 10 D8 60

Second part: Handle checkpoints when restarting the level.
At 0xDF18 write: 4C 10 FB
At 0xFB10 write: AD 27 06 D0 03 4C 1B E0 A2 0F BD A0 FA CD 79 05 D0 20 BD D0 FA CD 27 06 D0 18 BD E0 FA 8F 10 F1 7F BD F0 FA 8F 11 F1 7F BD 00 FB 8F 12 F1 7F 4C 1B E0 CA 10 D5 4C 1B E0

Third part: Configuring the special exits and checkpoints.
16 events are supported by default, so the index X can go from 0x0 to 0xF.

At 0xFAA0 + X write the level number. 00=level 1, 01=level 2, etc. as usual.
At 0xFAB0 + X write the room which the prince needs to leave to trigger the event.
At 0xFAC0 + X write the direction in which the prince needs to leave the room. 00=left, 01=right, 02=up, 03=down.
At 0xFAD0 + X write what should happen: 00=nothing, FF=level complete, 01,02,03,etc.=set checkpoint. (Different checkpoints on the same level must have different numbers.)
For checkpoints only:
At 0xFAE0 + X write the room where the prince should restart.
At 0xFAF0 + X write the tile position where the prince should restart.
At 0xFB00 + X write the direction to turn: 00=right, FF=left.

If you need more than 16 events (in the whole game) then change the following:
* The bytes after A2 bytes (LDX #$..) to the number of events minus 1.
* The 2-byte offsets after BD bytes (LDA $....,X), to the new location of each table.


Details:

Code: Select all

First part:

At 0x82CF write:
20 60 FA  JSR $FA60

At 0xFA60 write:
8D 8B 05  STA $058B ; ]cutdir
A2 0F     LDX #$0F ; number of room events-1
          :loop
BD A0 FA  LDA $FAA0,X ; level[X]
CD 79 05  CMP $0579 ; current level
D0 21     BNE :no
BD B0 FA  LDA $FAB0,X ; leave_room[X]
CD 62 04  CMP $0462 ; Char.room ; CharScrn
D0 19     BNE :no
BD C0 FA  LDA $FAC0,X ; leave_direction[X]
CD 8B 05  CMP $058B ; ]cutdir
D0 11     BNE :no
          ; found a room event
BD D0 FA  LDA $FAD0,X ; action[X]
F0 0C     BEQ :no ; zero means no action
C9 FF     CMP #$FF
D0 03     BNE :chkp ; FF means next level
4C FA 9E  JMP $9EFA ; seq level ended ; GoneUpstairs
          :chkp ; 01..FE means checkpoint
20 BF 83  JSR $83BF ; set checkpoint
80 03     BRA :end
          :no
CA        DEX
10 D4     BPL :loop
          :end
AD 8B 05  LDA $058B ; ]cutdir
4C 72 84  JMP $8472 ; do warp? ; CUT


Second part:

At 0xDF18 write:
4C 10 FB  JMP $FB10

At 0xFB10 write:
AD 27 06     LDA $0627 ; checkpoint on/off
D0 03        BNE :1
4C 1B E0     JMP $E01B ; default startpos
             :1
A2 0F        LDX #$0F ; number of room events-1
             :loop
BD A0 FA     LDA $FAA0,X ; level[X]
CD 79 05     CMP $0579 ; current level
D0 20        BNE :no
BD D0 FA     LDA $FAD0,X ; action[X]
CD 27 06     CMP $0627 ; checkpoint on/off
D0 18        BNE :no ; zero means no action
BD E0 FA     LDA $FAE0,X ; restart_room[X]
8F 10 F1 7F  STA $7F:F110 ; start room
BD F0 FA     LDA $FAF0,X ; restart_tile[X]
8F 11 F1 7F  STA $7F:F111 ; start tile
BD 00 FB     LDA $FB00,X ; restart_direction[X]
8F 12 F1 7F  STA $7F:F112 ; start direction
4C 1B E0     JMP $E01B ; default startpos
             :no
CA           DEX
10 D5        BPL :loop
4C 1B E0     JMP $E01B ; default startpos
Uh, I think on this one something is wrong. I'm writing at FAA0 the value 00 for Level 1, at FAB0 value 05 for room 5, at FAC0 value 00 to leave to the left, and at FAD0 value FF to finish level, but as soon as the Prince goes down the first room, the camera doesn't follow him.
EDIT: The first part of the hack that you described first is wrong (where you say write at 8139 and at FA60). The hack on the code details for the first part is the one that works (it says write at 82CF and at FA60 you give a slightly different code to write).
Overall, it works as I intend to, though there's a few times (not always) where checkpoints and special exits might be shared, in order for the Prince to travel between these levels. For example, lets say exiting to the left of Room 8 of Level 1 leads you to Room 13 of Level 3. From there, you can return to Room 8 of Level 1 by just exiting to the right of this Room 13. But it seems that if I write both, the checkpoint has priority and overrides the special exit.
Also, it seems that choosing to ''Game End'' and then choosing continue restarts you to the level door start room, rather than on the checkpoint, that's why I was asking if passwords could have that unused checkpoint flag activated (if the code's complete/still there).
Spoiler: show
David wrote: June 28th, 2020, 9:44 pm Ah, yes, I explained that here: viewtopic.php?p=21860#p21860

However, swapping level door sprites is different from swapping wall graphics.

Each level door sprite is in a separate sprite resource, and they are loaded only when needed.
So it's possible to change which one is loaded per level or even per room.

In contrast, wall graphics are part of the environment graphics, which are loaded when the level starts.
It's not straightforward to load different tiles from different environments.
Maybe the three layers could be loaded from different environments, but anything finer than that is too hard.
Ah, that explains it. Perhaps we can experiment with that. How can it be done?

What is left for now besides all of the above is to remove the ''Lv XX'' on the pause screen, best time only display the final total time, and at least one guard (besides the skeleton) to not display his HP bar.

On the 30th Anniversary Port side, what is left is to see if level can be restarted as soon as the Prince is killed like on DOS 'cause on SNES you have to wait for the music to play in its entirety, as well as see if the star-hitpoint-sprite can reflect the guard/prince HP palette whenever they get hit by a sword, plus see if the Level 13 loose tiles can be activated without the skeleton pressing a switch, because he makes noise when doing so.
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 29th, 2020, 9:44 pm EDIT: The first part of the hack that you described first is wrong (where you say write at 8139 and at FA60). The hack on the code details for the first part is the one that works (it says write at 82CF and at FA60 you give a slightly different code to write).
Whoops, my mistake!
I made multiple iterations of the hack and apparently I copied the hex codes from the first one (which had bugs), but the details from the last one.

Shauing wrote: June 29th, 2020, 9:44 pm Overall, it works as I intend to, though there's a few times (not always) where checkpoints and special exits might be shared, in order for the Prince to travel between these levels. For example, lets say exiting to the left of Room 8 of Level 1 leads you to Room 13 of Level 3. From there, you can return to Room 8 of Level 1 by just exiting to the right of this Room 13. But it seems that if I write both, the checkpoint has priority and overrides the special exit.
I'm not sure exactly what values did you enter, but below is something that works for me.

The special exits in this example lead between level 1 room 0 (exit right) and level 2 room 9 (exit left).
(I was using the original levels for this test.)

The explanation of the CC bytes:
The prince should only ever start at those checkpoints through the code at 0xFD00, so I've set the exit room and direction of those checkpoints to invalid values.
This simply means that these checkpoints cannot be triggered by exiting a room on the same level.
But they still can be triggered by exiting a room (or entering an exit door) on a different level, if the code at 0xFD00 is set to trigger that checkpoint on that level.

I hope this explanation was clear. If it wasn't just tell me what part is unclear.

Code: Select all

At 0xFAA0: 00 01 00 01 (level)
At 0xFAB0: 00 09 CC CC (exit room)
At 0xFAC0: 01 00 CC CC (exit direction)
At 0xFAD0: FF FF 01 01 (action)
At 0xFAE0: 00 00 00 09 (restart room)
At 0xFAF0: 00 00 13 0A (restart tilepos)
At 0xFB00: 00 00 FF 00 (restart direction)

At 0xFD00:
9C 27 06 AD 79 05 AE 06 05
C9 00 D0 0C E0 00 D0 08 A9 01 8D 27 06 A9 01 60
C9 01 D0 0C E0 09 D0 08 A9 01 8D 27 06 A9 00 60
1A 60
Shauing wrote: June 29th, 2020, 9:44 pm What is left for now besides all of the above is to remove the ''Lv XX'' on the pause screen,
I've already posted that one here: viewtopic.php?p=29633#p29633


I will see what I can do about the other remaining things.
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 3rd, 2020, 5:25 am 1. When the Prince dies, you have to wait for the music to end to restart the level, but on DOS you can restart the level immediately. Though I find this a bit disrespectful to the music, you still lose time while waiting for the music to end.
At 0xF39A write: D0 1D
At 0xEFA6 write: B0 08

Optional:
At 0xEF48 write: 22 D6 F8 00
This immediately stops the death music instead of fading it out.

Details:

Code: Select all

The first part allows button presses to request level restart (set current level to #$FF), even while the death music is still playing.
01:F397: ad 41 05    LDA $0541 ; SongCue ; nonzero if music is playing
01:F39A: d0 d8       BNE $f374 ; <-- changed to BNE $F3B9
[...]
01:F3B9: ad 80 02    LDA $0280 ; joypad data 2 copy
01:F3BC: 0d 81 02    ORA $0281 ; pressed buttons (for pause)
01:F3BF: f0 10       BEQ $f3d1
[...]
01:F3CC: a9 ff       LDA #$ff
01:F3CE: 8d 79 05    STA $0579 ; current level
01:F3D1: 60          RTS

The second part allows the level restart request to take effect, even while the death music is still playing.
This part decides if we can go to next level (or restart the current one).
01:EF9D: ad 79 05    LDA $0579 ; current level
[...]
01:EFA4: c9 fe       CMP #$fe
01:EFA6: f0 08       BEQ $efb0 ; <-- changed to BCS $EFB0, that one jumps when current level is #$FE (return to menu) or #$FF (restart level)
01:EFA8: ad 41 05    LDA $0541 ; SongCue ; nonzero if music is playing
01:EFAB: 10 03       BPL $efb0
01:EFAD: a9 00       LDA #$00 ; no
01:EFAF: 60          RTS
01:EFB0: a9 01       LDA #$01 ; yes
01:EFB2: 60          RTS

The third part changes this:
01:EF48: 22 df f8 00 JSR $00:f8df ; fade music out ; <-- changed to JSR $00:F8D6 (stop music)
01:EF4C: ad 79 05    LDA $0579 ; current level
01:EF4F: c9 ff       CMP #$ff
01:EF51: f0 41       BEQ $ef94 ; go to next level
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 3rd, 2020, 5:25 am 2. When the guard or Prince gets hit, the small orange-yellow pointy star-ish hit shape that appears also reflects their HP palette.
Kid:
At 0xF5A1 write: 20 F0 FC
At 0xFCF0 write: 20 F8 C3 A9 75 8D 21 21 AE 3B 21 AC 3B 21 AD 69 02 0A 0A 0A 0A 48 18 69 88 8D 21 21 A9 04 8E 22 21 8C 22 21 3A D0 F7 A9 74 8D 21 21 AE 3B 21 AC 3B 21 68 18 69 8C 8D 21 21 A9 03 8E 22 21 8C 22 21 3A D0 F7 60

Guard:
At 0xF5E2 write: 20 A0 FC
At 0xFCA0 write: AD 64 04 C9 01 D0 03 4C F0 FC 20 F8 C3 A9 77 8D 21 21 AE 3B 21 AC 3B 21 AD 69 02 0A 0A 0A 0A 48 18 69 88 8D 21 21 A9 04 8E 22 21 8C 22 21 3A D0 F7 A9 76 8D 21 21 AE 3B 21 AC 3B 21 68 18 69 8C 8D 21 21 A9 03 8E 22 21 8C 22 21 3A D0 F7 60

(Maybe I should reduce some of the repetitions...)

Details:

Code: Select all

The SNES splash sprite uses palette indices $08..$0E (7 colors).
The DOS splash sprite uses only two colors.
I've decided to assign the two colors to $08..$0B (outer part) and $0C..$0E (inner part).

Kid:
We overwrite this part:
01:F59C: ad 09 05    LDA $0509 ; kid delta HP ; ChgKidStr
01:F59F: 10 03       BPL $f5a4
01:F5A1: 20 f8 c3    JSR $c3f8 ; draw hurt splash
01:F5A4: 60          RTS

At 0xF5A1 write:
20 F0 FC  JSR $FCF0

At 0xFCF0 write:
20 F8 C3  JSR $C3F8 ; draw hurt splash
          ;
A9 75     LDA #$75 ; bright red in kid's HP
8D 21 21  STA $2121 ; CGADD
AE 3B 21  LDX $213B ; RDCGRAM
AC 3B 21  LDY $213B ; RDCGRAM
AD 69 02  LDA $0269 ; hurt splash/torch flame palette
0A        ASL
0A        ASL
0A        ASL
0A        ASL
48        PHA ; save A
18        CLC
69 88     ADC #$88 ; $80 for sprite palettes + splash outer part
8D 21 21  STA $2121 ; CGADD
A9 04     LDA #$04 ; overwrite the first 4 colors
          :1
8E 22 21  STX $2122 ; CGDATA
8C 22 21  STY $2122 ; CGDATA
3A        DEC
D0 F7     BNE :1
          ;
A9 74     LDA #$74 ; dark red in kid's HP
8D 21 21  STA $2121 ; CGADD
AE 3B 21  LDX $213B ; RDCGRAM
AC 3B 21  LDY $213B ; RDCGRAM
68        PLA ; restore A
18        CLC
69 8C     ADC #$8C ; $80 for sprite palettes + splash inner part
8D 21 21  STA $2121 ; CGADD
A9 03     LDA #$03 ; overwrite the next 3 colors
          :2
8E 22 21  STX $2122 ; CGDATA
8C 22 21  STY $2122 ; CGDATA
3A        DEC
D0 F7     BNE :2
60        RTS

Guard:
We overwrite this part:
01:F5DD: ad 0c 05    LDA $050c ; guard delta HP ; ChgOppStr
01:F5E0: 10 03       BPL $f5e5
01:F5E2: 20 f8 c3    JSR $c3f8 ; draw hurt splash
01:F5E5: 60          RTS

At 0xF5E2 write:
20 A0 FC  JSR $FCA0

At 0xFCA0 write:
AD 64 04  LDA $0464 ; Char.chtype
C9 01     CMP #$01 ; shadow
D0 03     BNE :no
4C F0 FC  JMP $FCF0 ; use kid's HP colors for shadow
          :no
This is followed by the same code as for 0xFCF0 but with the two source palette indices changed from #$75 and #$74 to #$77 and #$76 to use the colors of the guard's HP.
User avatar
Shauing
Calif
Calif
Posts: 432
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Hacking the SNES ROM

Post by Shauing »

Spoiler: show
David wrote: July 4th, 2020, 5:38 pm
Shauing wrote: June 29th, 2020, 9:44 pm Overall, it works as I intend to, though there's a few times (not always) where checkpoints and special exits might be shared, in order for the Prince to travel between these levels. For example, lets say exiting to the left of Room 8 of Level 1 leads you to Room 13 of Level 3. From there, you can return to Room 8 of Level 1 by just exiting to the right of this Room 13. But it seems that if I write both, the checkpoint has priority and overrides the special exit.
I'm not sure exactly what values did you enter, but below is something that works for me.

The special exits in this example lead between level 1 room 0 (exit right) and level 2 room 9 (exit left).
(I was using the original levels for this test.)

The explanation of the CC bytes:
The prince should only ever start at those checkpoints through the code at 0xFD00, so I've set the exit room and direction of those checkpoints to invalid values.
This simply means that these checkpoints cannot be triggered by exiting a room on the same level.
But they still can be triggered by exiting a room (or entering an exit door) on a different level, if the code at 0xFD00 is set to trigger that checkpoint on that level.

I hope this explanation was clear. If it wasn't just tell me what part is unclear.

Code: Select all

At 0xFAA0: 00 01 00 01 (level)
At 0xFAB0: 00 09 CC CC (exit room)
At 0xFAC0: 01 00 CC CC (exit direction)
At 0xFAD0: FF FF 01 01 (action)
At 0xFAE0: 00 00 00 09 (restart room)
At 0xFAF0: 00 00 13 0A (restart tilepos)
At 0xFB00: 00 00 FF 00 (restart direction)

At 0xFD00:
9C 27 06 AD 79 05 AE 06 05
C9 00 D0 0C E0 00 D0 08 A9 01 8D 27 06 A9 01 60
C9 01 D0 0C E0 09 D0 08 A9 01 8D 27 06 A9 00 60
1A 60
These were mine (It goes to Level 3's checkpoint):
Spoiler: show
At 0xFAA0: 00 02 00 02 (level)
At 0xFAB0: 03 0A 03 0A (exit room)
At 0xFAC0: 00 01 01 00 (exit direction)
At 0xFAD0: FF FF 01 01 (action)
At 0xFAE0: 00 00 03 0A (restart room)
At 0xFAF0: 00 00 00 09 (restart tilepos)
At 0xFB00: 00 00 00 00 (restart direction)
(If were to put the first value at FAC0 as 01, the checkpoint overrides the exit one).

At 0xFD00:
9C 27 06 AD 79 05 AE 06 05
C9 00 D0 0C E0 03 D0 08 A9 01 8D 27 06 A9 02 60
C9 02 D0 0C E0 0A D0 08 A9 01 8D 27 06 A9 00 60
1A 60
Spoiler: show
David wrote: July 4th, 2020, 5:38 pm
Shauing wrote: June 29th, 2020, 9:44 pm What is left for now besides all of the above is to remove the ''Lv XX'' on the pause screen,
I've already posted that one here: viewtopic.php?p=29633#p29633
Somehow I missed it. I'll check it out.
The box has a bit of empty space to the right, can it be trimmed down?
Spoiler: show
David wrote: July 4th, 2020, 8:43 pm
Shauing wrote: June 3rd, 2020, 5:25 am 1. When the Prince dies, you have to wait for the music to end to restart the level, but on DOS you can restart the level immediately. Though I find this a bit disrespectful to the music, you still lose time while waiting for the music to end.
At 0xF39A write: D0 1D
At 0xEFA6 write: B0 08

Optional:
At 0xEF48 write: 22 D6 F8 00
This immediately stops the death music instead of fading it out.

Details:

Code: Select all

The first part allows button presses to request level restart (set current level to #$FF), even while the death music is still playing.
01:F397: ad 41 05    LDA $0541 ; SongCue ; nonzero if music is playing
01:F39A: d0 d8       BNE $f374 ; <-- changed to BNE $F3B9
[...]
01:F3B9: ad 80 02    LDA $0280 ; joypad data 2 copy
01:F3BC: 0d 81 02    ORA $0281 ; pressed buttons (for pause)
01:F3BF: f0 10       BEQ $f3d1
[...]
01:F3CC: a9 ff       LDA #$ff
01:F3CE: 8d 79 05    STA $0579 ; current level
01:F3D1: 60          RTS

The second part allows the level restart request to take effect, even while the death music is still playing.
This part decides if we can go to next level (or restart the current one).
01:EF9D: ad 79 05    LDA $0579 ; current level
[...]
01:EFA4: c9 fe       CMP #$fe
01:EFA6: f0 08       BEQ $efb0 ; <-- changed to BCS $EFB0, that one jumps when current level is #$FE (return to menu) or #$FF (restart level)
01:EFA8: ad 41 05    LDA $0541 ; SongCue ; nonzero if music is playing
01:EFAB: 10 03       BPL $efb0
01:EFAD: a9 00       LDA #$00 ; no
01:EFAF: 60          RTS
01:EFB0: a9 01       LDA #$01 ; yes
01:EFB2: 60          RTS

The third part changes this:
01:EF48: 22 df f8 00 JSR $00:f8df ; fade music out ; <-- changed to JSR $00:F8D6 (stop music)
01:EF4C: ad 79 05    LDA $0579 ; current level
01:EF4F: c9 ff       CMP #$ff
01:EF51: f0 41       BEQ $ef94 ; go to next level
Nice, very nice! Seeing the last optional hack, this makes me wonder: as I'm planning to remove the graphical effects and password/time texts, can the level ending jingle be removed from all levels and the level music fade-out when the Prince reaches an exit rather than abruptly cut off?
EDIT: Did an attempt of this by writing at 0x9EFA: A9 FF 22 DF F8 00, taking cues from previous hacks we did, and it mostly works, except if a jingle is playing (such as the victory ones or Shadow's theme) where the Prince keeps falling from bottom to top of the same room until it ends. We did fix this but this fix abruptly cuts the jingle instead of fading it out. Also, if the next level triggers a Princess cutscene, the fade-out is cut-off by said cutscene.
Spoiler: show
David wrote: July 4th, 2020, 10:30 pm
Shauing wrote: June 3rd, 2020, 5:25 am 2. When the guard or Prince gets hit, the small orange-yellow pointy star-ish hit shape that appears also reflects their HP palette.
Kid:
At 0xF5A1 write: 20 F0 FC
At 0xFCF0 write: 20 F8 C3 A9 75 8D 21 21 AE 3B 21 AC 3B 21 AD 69 02 0A 0A 0A 0A 48 18 69 88 8D 21 21 A9 04 8E 22 21 8C 22 21 3A D0 F7 A9 74 8D 21 21 AE 3B 21 AC 3B 21 68 18 69 8C 8D 21 21 A9 03 8E 22 21 8C 22 21 3A D0 F7 60

Guard:
At 0xF5E2 write: 20 A0 FC
At 0xFCA0 write: AD 64 04 C9 01 D0 03 4C F0 FC 20 F8 C3 A9 77 8D 21 21 AE 3B 21 AC 3B 21 AD 69 02 0A 0A 0A 0A 48 18 69 88 8D 21 21 A9 04 8E 22 21 8C 22 21 3A D0 F7 A9 76 8D 21 21 AE 3B 21 AC 3B 21 68 18 69 8C 8D 21 21 A9 03 8E 22 21 8C 22 21 3A D0 F7 60

(Maybe I should reduce some of the repetitions...)

Details:

Code: Select all

The SNES splash sprite uses palette indices $08..$0E (7 colors).
The DOS splash sprite uses only two colors.
I've decided to assign the two colors to $08..$0B (outer part) and $0C..$0E (inner part).

Kid:
We overwrite this part:
01:F59C: ad 09 05    LDA $0509 ; kid delta HP ; ChgKidStr
01:F59F: 10 03       BPL $f5a4
01:F5A1: 20 f8 c3    JSR $c3f8 ; draw hurt splash
01:F5A4: 60          RTS

At 0xF5A1 write:
20 F0 FC  JSR $FCF0

At 0xFCF0 write:
20 F8 C3  JSR $C3F8 ; draw hurt splash
          ;
A9 75     LDA #$75 ; bright red in kid's HP
8D 21 21  STA $2121 ; CGADD
AE 3B 21  LDX $213B ; RDCGRAM
AC 3B 21  LDY $213B ; RDCGRAM
AD 69 02  LDA $0269 ; hurt splash/torch flame palette
0A        ASL
0A        ASL
0A        ASL
0A        ASL
48        PHA ; save A
18        CLC
69 88     ADC #$88 ; $80 for sprite palettes + splash outer part
8D 21 21  STA $2121 ; CGADD
A9 04     LDA #$04 ; overwrite the first 4 colors
          :1
8E 22 21  STX $2122 ; CGDATA
8C 22 21  STY $2122 ; CGDATA
3A        DEC
D0 F7     BNE :1
          ;
A9 74     LDA #$74 ; dark red in kid's HP
8D 21 21  STA $2121 ; CGADD
AE 3B 21  LDX $213B ; RDCGRAM
AC 3B 21  LDY $213B ; RDCGRAM
68        PLA ; restore A
18        CLC
69 8C     ADC #$8C ; $80 for sprite palettes + splash inner part
8D 21 21  STA $2121 ; CGADD
A9 03     LDA #$03 ; overwrite the next 3 colors
          :2
8E 22 21  STX $2122 ; CGDATA
8C 22 21  STY $2122 ; CGDATA
3A        DEC
D0 F7     BNE :2
60        RTS

Guard:
We overwrite this part:
01:F5DD: ad 0c 05    LDA $050c ; guard delta HP ; ChgOppStr
01:F5E0: 10 03       BPL $f5e5
01:F5E2: 20 f8 c3    JSR $c3f8 ; draw hurt splash
01:F5E5: 60          RTS

At 0xF5E2 write:
20 A0 FC  JSR $FCA0

At 0xFCA0 write:
AD 64 04  LDA $0464 ; Char.chtype
C9 01     CMP #$01 ; shadow
D0 03     BNE :no
4C F0 FC  JMP $FCF0 ; use kid's HP colors for shadow
          :no
This is followed by the same code as for 0xFCF0 but with the two source palette indices changed from #$75 and #$74 to #$77 and #$76 to use the colors of the guard's HP.
Cool, only moved the Prince palette code to FAF0 as FCF0 has already some coding there. Oddly, the Shadow does not display a splash at all even though it previously did, and on DOS he does display a similar splash to the Prince (though with the center filled grey).
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: July 5th, 2020, 1:12 am These were mine (It goes to Level 3's checkpoint):
Spoiler: show
At 0xFAA0: 00 02 00 02 (level)
At 0xFAB0: 03 0A 03 0A (exit room)
At 0xFAC0: 00 01 01 00 (exit direction)
At 0xFAD0: FF FF 01 01 (action)
At 0xFAE0: 00 00 03 0A (restart room)
At 0xFAF0: 00 00 00 09 (restart tilepos)
At 0xFB00: 00 00 00 00 (restart direction)
(If were to put the first value at FAC0 as 01, the checkpoint overrides the exit one).

At 0xFD00:
9C 27 06 AD 79 05 AE 06 05
C9 00 D0 0C E0 03 D0 08 A9 01 8D 27 06 A9 02 60
C9 02 D0 0C E0 0A D0 08 A9 01 8D 27 06 A9 00 60
1A 60
I have tried these now, and it works for me in both directions.
Are you using the correct code at 0x82CF and 0xFA60 (from the details)?
(And did you undo the incorrect edit at 0x8139?)
If you're sure you have the correct hacks at those offsets, then you could send me your ROM so I can see what are we doing differently.


Shauing wrote: July 5th, 2020, 1:12 am Cool, only moved the Prince palette code to FAF0 as FCF0 has already some coding there. Oddly, the Shadow does not display a splash at all even though it previously did, and on DOS he does display a similar splash to the Prince (though with the center filled grey).
If you moved the code from 0xFCF0 (to 0xFAF0 in this case) then in the code starting at 0xFCA0 you need do change 4C F0 FC accordingly (to 4C F0 FA in this case).

Shauing wrote: July 5th, 2020, 1:12 am The box has a bit of empty space to the right, can it be trimmed down?
The width of the box is stored at 0xF26.
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 3rd, 2020, 5:25 am 4. You can hear the sound of the skull pressing a switch to make fall the loose tiles on Level 13.
Perhaps a hack for making the loose tiles fall without needing a skull and a switch?
Shake the ceiling in those two rooms when the prince enters them.
At 0xF68A write: 20 60 FC
At 0xFC60 write: 20 BD C4 AD 79 05 C9 0C D0 26 AD 06 05 C9 01 F0 04 C9 03 D0 1B AD 68 05 8D CF 04 A9 02 8D CE 04 A2 07 8E CD 04 20 D1 E3 AE CD 04 CA E0 02 B0 F2 60

Loose floors on level 13 should not stop.
At 0xD75E write: E0 0C
At 0xD767 write: 80 EF

Loose floors on level 13 should not shake when you land on their row.
At 0xDBAF write: 4C 50 FC
WRONG: At 0xFC50 write: AD 79 05 C9 0D F0 03 4C FA DB 60
FIX: At 0xFC50 write: AD 79 05 C9 0C F0 03 4C FA DC 60


I found out there is a reason why loose floors don't shake on level 13 in the DOS (and Apple II) version:
Because that would interfere with the trick Mechner used to make the loose floors on the ceiling fall at random times.

Namely, the ceiling loose floors are given a random modifier between 0xF0 and 0xFF when the prince enters the room below them.
The modifier of every animating loose floor (not just the special ones) is increased in every frame until it reaches 0x0A, then the floor falls.
(In case of these special loose floors, the modifier wraps around from 0xFF to 0x00.)

But there is another piece of code which stops the animation every loose floor whose modifier is above 0x84.
That's needed because normally, modifiers 0x80..0x84 are used for loose floors which are merely shaking, while modifiers 0x00..0x0A are used for loose floors which are going to fall.
But the 0xF0..0xFF values are also above 0x84, which means the auto-triggered loose floors on level 13 would stop animating right after they started.
That's why the 0x84 check has to be disabled on level 13.
But then, the merely shaking loose floors would not stop either, so Mechner's solution was to not shake regular loose floors if they are not going to fall.

Another solution would be to use random modifiers from the range 0x00..0x0A for the special floors, but that would make the floors fall sooner.


Details of the hack:

Code: Select all

At 0xF68A write:
20 60 FC  JSR $FC60

At 0xFC60 write:
20 BD C4  JSR $C4BD ; (the instruction which was originally at 0xF68A)
AD 79 05  LDA $0579 ; current level
C9 0C     CMP #$0C ; level 13
D0 26     BNE :no
AD 06 05  LDA $0506 ; shown room ; VisScrn
C9 01     CMP #$01 ; room 1
F0 04     BEQ :yes
C9 03     CMP #$03 ; room 3
D0 1B     BNE :no
          :yes
AD 68 05  LDA $0568 ; above room ; scrnAbove
8D CF 04  STA $04CF ; tempscrn
A9 02     LDA #$02 ; bottom row
8D CE 04  STA $04CE ; tempblocky
A2 07     LDX #$07 ; rightmost column
          :loop
8E CD 04  STX $04CD ; tempblockx
20 D1 E3  JSR $E3D1 ; :trigloose
AE CD 04  LDX $04CD ; tempblockx
CA        DEX
E0 02     CPX #$02 ; leftmost column
B0 F2     BCS :loop
          :no
60        RTS


level 15 room 18 (Jaffar) loose floors don't stop shaking: :wiggle:
01:D75B: ae 79 05    LDX $0579 ; current level
01:D75E: e0 0e       CPX #$0e ; <-- changed to #$0C (level 13)
01:D760: d0 07       BNE $d769
01:D762: ae b7 06    LDX $06b7 ; trob.room ; trscrn
01:D765: e0 12       CPX #$12
01:D767: f0 ef       BEQ $d758 ; :red ; <-- changed to BRA (jump always, ignoring room number)
01:D769: c9 84       CMP #$84 ; stop if modifier is above 0x84
01:D76B: 90 06       BCC $d773


At 0xDBAF write:
4C 50 FC  JMP $FC50

At 0xFC50 write:
AD 79 05  LDA $0579 ; current level
C9 0D     CMP #$0D ; level 13
F0 03     BEQ :1
4C FA DB  JMP $DCFA ; add trob (which was originally at 0xDBAF)
          :1
60        RTS
Last edited by David on July 11th, 2020, 9:34 am, edited 1 time in total.
Reason: Fixed one of the hacks.
User avatar
Shauing
Calif
Calif
Posts: 432
Joined: April 5th, 2018, 10:38 pm
Contact:

Re: Hacking the SNES ROM

Post by Shauing »

Spoiler: show
David wrote: July 5th, 2020, 10:47 am
Shauing wrote: July 5th, 2020, 1:12 am These were mine (It goes to Level 3's checkpoint):
Spoiler: show
At 0xFAA0: 00 02 00 02 (level)
At 0xFAB0: 03 0A 03 0A (exit room)
At 0xFAC0: 00 01 01 00 (exit direction)
At 0xFAD0: FF FF 01 01 (action)
At 0xFAE0: 00 00 03 0A (restart room)
At 0xFAF0: 00 00 00 09 (restart tilepos)
At 0xFB00: 00 00 00 00 (restart direction)
(If were to put the first value at FAC0 as 01, the checkpoint overrides the exit one).
EDIT: FAC2 as 00.

At 0xFD00:
9C 27 06 AD 79 05 AE 06 05
C9 00 D0 0C E0 03 D0 08 A9 01 8D 27 06 A9 02 60
C9 02 D0 0C E0 0A D0 08 A9 01 8D 27 06 A9 00 60
1A 60
I have tried these now, and it works for me in both directions.
Are you using the correct code at 0x82CF and 0xFA60 (from the details)?
(And did you undo the incorrect edit at 0x8139?)
If you're sure you have the correct hacks at those offsets, then you could send me your ROM so I can see what are we doing differently.
Yes, they were done on an otherwise new PoP ROM. The value that overrides the checkpoint is at FAC2, changing it to 00, not FAC0, that was a mistake on my part. Change that value and you'll see that the exit no longer works, but the checkpoint does.
Spoiler: show
David wrote: July 5th, 2020, 10:47 am
Shauing wrote: July 5th, 2020, 1:12 am Cool, only moved the Prince palette code to FAF0 as FCF0 has already some coding there. Oddly, the Shadow does not display a splash at all even though it previously did, and on DOS he does display a similar splash to the Prince (though with the center filled grey).
If you moved the code from 0xFCF0 (to 0xFAF0 in this case) then in the code starting at 0xFCA0 you need do change 4C F0 FC accordingly (to 4C F0 FA in this case).
Yes, I did.
Spoiler: show
David wrote: July 5th, 2020, 10:47 am
Shauing wrote: July 5th, 2020, 1:12 am The box has a bit of empty space to the right, can it be trimmed down?
The width of the box is stored at 0xF26.
Excellent.
Spoiler: show
David wrote: July 5th, 2020, 10:52 am
Shauing wrote: June 3rd, 2020, 5:25 am 4. You can hear the sound of the skull pressing a switch to make fall the loose tiles on Level 13.
Perhaps a hack for making the loose tiles fall without needing a skull and a switch?
Shake the ceiling in those two rooms when the prince enters them.
At 0xF68A write: 20 60 FC
At 0xFC60 write: 20 BD C4 AD 79 05 C9 0C D0 26 AD 06 05 C9 01 F0 04 C9 03 D0 1B AD 68 05 8D CF 04 A9 02 8D CE 04 A2 07 8E CD 04 20 D1 E3 AE CD 04 CA E0 02 B0 F2 60

Loose floors on level 13 should not stop.
At 0xD75E write: E0 0C
At 0xD767 write: 80 EF

Loose floors on level 13 should not shake when you land on their row.
At 0xDBAF write: 4C 50 FC
At 0xFC50 write: AD 79 05 C9 0D F0 03 4C FA DB 60


I found out there is a reason why loose floors don't shake on level 13 in the DOS (and Apple II) version:
Because that would interfere with the trick Mechner used to make the loose floors on the ceiling fall at random times.

Namely, the ceiling loose floors are given a random modifier between 0xF0 and 0xFF when the prince enters the room below them.
The modifier of every animating loose floor (not just the special ones) is increased in every frame until it reaches 0x0A, then the floor falls.
(In case of these special loose floors, the modifier wraps around from 0xFF to 0x00.)

But there is another piece of code which stops the animation every loose floor whose modifier is above 0x84.
That's needed because normally, modifiers 0x80..0x84 are used for loose floors which are merely shaking, while modifiers 0x00..0x0A are used for loose floors which are going to fall.
But the 0xF0..0xFF values are also above 0x84, which means the auto-triggered loose floors on level 13 would stop animating right after they started.
That's why the 0x84 check has to be disabled on level 13.
But then, the merely shaking loose floors would not stop either, so Mechner's solution was to not shake regular loose floors if they are not going to fall.

Another solution would be to use random modifiers from the range 0x00..0x0A for the special floors, but that would make the floors fall sooner.


Details of the hack:

Code: Select all

At 0xF68A write:
20 60 FC  JSR $FC60

At 0xFC60 write:
20 BD C4  JSR $C4BD ; (the instruction which was originally at 0xF68A)
AD 79 05  LDA $0579 ; current level
C9 0C     CMP #$0C ; level 13
D0 26     BNE :no
AD 06 05  LDA $0506 ; shown room ; VisScrn
C9 01     CMP #$01 ; room 1
F0 04     BEQ :yes
C9 03     CMP #$03 ; room 3
D0 1B     BNE :no
          :yes
AD 68 05  LDA $0568 ; above room ; scrnAbove
8D CF 04  STA $04CF ; tempscrn
A9 02     LDA #$02 ; bottom row
8D CE 04  STA $04CE ; tempblocky
A2 07     LDX #$07 ; rightmost column
          :loop
8E CD 04  STX $04CD ; tempblockx
20 D1 E3  JSR $E3D1 ; :trigloose
AE CD 04  LDX $04CD ; tempblockx
CA        DEX
E0 02     CPX #$02 ; leftmost column
B0 F2     BCS :loop
          :no
60        RTS


level 15 room 18 (Jaffar) loose floors don't stop shaking: :wiggle:
01:D75B: ae 79 05    LDX $0579 ; current level
01:D75E: e0 0e       CPX #$0e ; <-- changed to #$0C (level 13)
01:D760: d0 07       BNE $d769
01:D762: ae b7 06    LDX $06b7 ; trob.room ; trscrn
01:D765: e0 12       CPX #$12
01:D767: f0 ef       BEQ $d758 ; :red ; <-- changed to BRA (jump always, ignoring room number)
01:D769: c9 84       CMP #$84 ; stop if modifier is above 0x84
01:D76B: 90 06       BCC $d773


At 0xDBAF write:
4C 50 FC  JMP $FC50

At 0xFC50 write:
AD 79 05  LDA $0579 ; current level
C9 0D     CMP #$0D ; level 13
F0 03     BEQ :1
4C FA DB  JMP $DCFA ; add trob (which was originally at 0xDBAF)
          :1
60        RTS
Ok, it works beautifully. I've not altered any of the loose floor modifiers yet, and I like how it looks as of now.
Unrelated to this hack but something I noticed while testing this and it's related to the hack of the level end music starting when Prince starts going upstairs: On Level 13 he starts going upstairs but the level ends abruptly due to this hack we did as the cue is muted for this level. Can this be fixed?
NEW UPDATE! Prince Of Persia: 30th Anniversary Port v1.1.5. Download it today!: viewtopic.php?p=29053#p29053
NEW UPDATE! Prince Of Persia: The Queen Of Light v2.6. Download it today! viewtopic.php?p=33174#p33174
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: July 5th, 2020, 11:31 am Yes, they were done on an otherwise new PoP ROM. The value that overrides the checkpoint is at FAC2, changing it to 00, not FAC0, that was a mistake on my part. Change that value and you'll see that the exit no longer works, but the checkpoint does.
Sorry, I somehow ignored your remark in parentheses when I was testing it!
Indeed, if I change FAC2 to 00 then the checkpoint and the special exit will have the same triggering level, room, and direction; and the checkpoint will override the special exit.

The question is, what are you trying to achieve?
If exiting room 3 to the left should take the prince to level 3, then why do you want to set a checkpoint at the same place?
If your goal is to start level 3 from a checkpoint then it's enough to configure that in the code starting at 0xFD00.
That's what I tried to say here, but maybe I wasn't clear enough?
Shauing wrote: July 5th, 2020, 11:31 am Ok, it works beautifully. I've not altered any of the loose floor modifiers yet, and I like how it looks as of now.
You don't need to alter their modifiers, that's done by the hack.
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: July 5th, 2020, 11:31 am Unrelated to this hack but something I noticed while testing this and it's related to the hack of the level end music starting when Prince starts going upstairs: On Level 13 he starts going upstairs but the level ends abruptly due to this hack we did as the cue is muted for this level. Can this be fixed?
Luckily I had an alternate version of the hack which starts the level end music earlier.
Back then I decided to publish a different version which requires fewer edits.
But it seems we need this alternate version after all.

First undo the old version of the hack:
At 0x174CB write: F1
You don't need to undo the edits at 0x1749B and 0xFF96 because the new hack changes them as well.

Now, the new hack:

Detach going to the next level from the level ending music.
At 0x9EFE write: 4C

When it's time to enter the next level, trigger specifically going to the next level, not the music before it.
At 0x8313 write: 20 01 9F
At 0x8367 write: 20 01 9F
At 0x964A write: 20 01 9F

Change the unused sequence table sound 7 into the level ending music.
At 0x96BF write: 4C FA 9E

Use sound 7 in the sequence table instead of one of the footsteps.
At 0x1749B write: F2 07
(If this is too early, you can use one of these later offsets instead: 0x174A1, 0x174A8, 0x174B0.)

Don't stop the prince while the music is playing.
At 0xFF96 write: A2 00
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 13th, 2020, 3:14 am (Maybe passwords can use the unused checkpoint feature that would restore you at the checkpoint, or the code isn't complete?)
Shauing wrote: June 29th, 2020, 9:44 pm Also, it seems that choosing to ''Game End'' and then choosing continue restarts you to the level door start room, rather than on the checkpoint, that's why I was asking if passwords could have that unused checkpoint flag activated (if the code's complete/still there).
I made two variants.
The first variant was easier to make, but I wasn't sure if its limitations are acceptable to you, so I made a more complicated but less limited second variant.


First variant: Use only one bit for the checkpoint, namely bit 2 of character 5, marked as "x" in the documentation.
This means the passwords can only bring the prince to the default starting place of the level ("checkpoint #0") or checkpoint #1 of the level.
If you want more checkpoints then use the second variant.

At 0x15B7C write: 2A EA
At 0x1591C write: 20 F0 FF
At 0x17FF0 write: A5 56 4A 90 04 EB 04 5F EB A9 02 EB 60

Code: Select all

When the the game decodes a password:

The existing code:
read checkpoint from password:
02:DB77: a9 00       LDA #$00
02:DB79: 4e 5f 00    LSR $005f ; read next bit from character 5
02:DB7C: 85 56       STA $56 ; password checkpoint
02:DB7E: 8d 5f 0e    STA $0e5f ; decoded checkpoint
02:DB81: 60          RTS

At 02:DB7C = 0x15B7C write:
2A        ROL ; add bit to A
EA        NOP


When the game makes a password:

At 02:D91C = 0x1591C write:
20 F0 FF  JSR $FFF0

At 02:FFF0 = 0x17FF0 write:
A5 56     LDA $56 ; password checkpoint
4A        LSR ; check lowest bit
90 04     BCC :1 ; if not zero:
EB        XBA
04 5F     TSB $5F ; set bit 2 of character 5
EB        XBA
          :1
          ; the code which we overwrote at 02:D91C
A9 02     LDA #$02
EB        XBA
          ;
60        RTS

Second variant: Use two bits for the checkpoint.
The first bit is the same as in the first variant.
The second bit is bit 4 of character 1, marked as "0" in the documentation.
This means the passwords can bring the prince to the default starting place of the level ("checkpoint #0") or checkpoint #1, #2, or #3 of the level.

At 0x15B79 write: 20 A0 FF 85 56
At 0x17FA0 write: AD 5B 00 29 02 1C 5B 00 4A 4E 5F 00 2A 60
At 0x158AD write: EA EA EA EA
At 0x1591C write: 20 B0 FF
At 0x17FB0 write: A5 56 4A 90 04 EB 04 5F EB EB A9 10 EB 4A 90 04 EB 04 5B EB A9 02 EB 60
At 0x15BB5 write: EA EA EA
At 0x15ACD write: 29 1F

Code: Select all

When the the game decodes a password:

At 02:DB79 = 0x15B79 write:
20 A0 FF  JSR $FFA0
85 56     STA $56 ; password checkpoint

At 02:FFA0 = 0x17FA0 write:
AD 5B 00  LDA $005B ; char 1
29 02     AND #$02 ; we need only bit 1 (shifted from bit 4 by the previous reads)
1C 5B 00  TRB $005B ; clear this bit from char 1 (because it's originally an always-zero bit of the CRC)
4A        LSR ; shift bit 1 to bit 0
4E 5F 00  LSR $005F ; char 5
2A        ROL ; add bit to A
60        RTS


When the game makes a password:

We want to use the actual value of the checkpoint number, not 0xFF.
The existing code:
02:D8AA: ad 27 06    LDA $0627 ; checkpoint on/off
02:D8AD: f0 02       BEQ $d8b1 ; <-- remove
02:D8AF: a9 ff       LDA #$ff ; <-- remove
02:D8B1: 85 56       STA $56 ; password checkpoint

At 02:D8AD = 0x158AD write: EA EA EA EA


At 02:D91C = 0x1591C write:
20 B0 FF  JSR $FFB0

At 02:FFB0 = 0x17FB0 write:
A5 56     LDA $56 ; password checkpoint
4A        LSR ; check lowest bit
90 04     BCC :1 ; if not zero:
EB        XBA
04 5F     TSB $5F ; set bit 2 of character 5
EB        XBA
          :1
EB        XBA
A9 10     LDA #$10 ; bit 4
EB        XBA
4A        LSR ; check next bit
90 04     BCC :1 ; if not zero:
EB        XBA
04 5B     TSB $5B ; set bit 4 of character 1
EB        XBA
          ; the code which we overwrote at 02:D91C
A9 02     LDA #$02
EB        XBA
          ;
60        RTS


existing code:
read CRC from password:
02:DBA7: a9 00       LDA #$00
02:DBA9: 4e 5e 00    LSR $005e ; char 4
02:DBAC: 2a          ROL
02:DBAD: 4e 5d 00    LSR $005d ; char 3
02:DBB0: 2a          ROL
02:DBB1: 4e 5c 00    LSR $005c ; char 2
02:DBB4: 2a          ROL
02:DBB5: 4e 5b 00    LSR $005b ; char 1 ; <-- Remove, so that bit 4 of character 1 will not be read as part of the CRC.
02:DBB8: 2a          ROL
02:DBB9: 60          RTS

At 02:DBB5 = 0x15BB5 write: EA EA EA


existing code:
copy password X->Y, set checksum/CRC to zero:
02:DACA: bd 00 00    LDA $0000,X
02:DACD: 29 0f       AND #$0f ; <-- change to 0x1F, to keep bit 4 of character 1
02:DACF: 99 00 00    STA $0000,Y

At 02:DACD = 0x15ACD write: 29 1F

David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

David wrote: June 28th, 2020, 9:44 pm Part 1: Don't clear the checkpoint flag when the prince enters a different level.
At 0xF786 write: EA EA EA EA EA
Sorry, I made a mistake here.
You need to keep the first two bytes as A9 00.
Only the next 3 bytes (8D 27 06, at 0xF788) should be overwritten with EA EA EA.
David
The Prince of Persia
The Prince of Persia
Posts: 2848
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: Hacking the SNES ROM

Post by David »

Shauing wrote: June 13th, 2020, 3:14 am - Best time menu should only display the total final time.
At 0x1583B write: AD 44 05 C9 LL D0 4C C2 30 AD 2D 05 8D 4B 05 A9 00 00 4C 5D D8
Where LL is a level number.
When the player gets to this level, the total elapsed time is written to the best time slot of level 1 (if it's better than what was there previously).
It should generally be the level which triggers the good ending when you enter it.

I don't know if you changed (or will change) the starting time in this mod.
If you did (or will) then this hack needs to be adjusted for that.

At 0x156E0 you can edit the texts of the BEST TIME window.

Placement and size of the BEST TIME window:
At 0x1560C: left
At 0x1560D: top
At 0x1560E: width
At 0x1560F: height

Placement of the now single best time within the BEST TIME window:
At 0x1564F: row
At 0x15659: column

Code: Select all

At 02:D83B = 0x1583B write:
AD 44 05  LDA $0544 ; next level
C9 LL     CMP #$LL ; ending level
D0 4C     BNE $D88E ; don't store
C2 30     REP #$30 ; 16-bit A
AD 2D 05  LDA $052D ; elapsed time 1 L ; FrameCount
8D 4B 05  STA $054B ; elapsed time on this level L
A9 00 00  LDA #$0000 ; store into level 1 slot
4C 5D D8  JMP $D85D
Post Reply