If anyone is interested in making a warpless Grant improvement (on J or U), please contact me so I can share what improvements I know.
Myself, I'm not gonna have much time to get into this, sadly.
Alright, here is a trick that I feel should be documented for posterity. However, it unfortunately turned out incompatible with any fast approach for doing this section.
The Fast Grant Orb drop
Rarely, the boss orb on defeating Grant will fall one pixel further to the left, causing it to land on the raised ledge. This allows Trevor to pick it up earlier, saving a few frames.
The reason it works is because some properties from the enemy that previously occupied the orb's object slot were not properly cleared. Specifically, the orb shares some properties with this Medusa Head in the previous room:
More generally, every second medusa head that spawns will always occupy the same slot as the orb.
The way it works is that, on the first frame spawning, the game sets the orb's X speed to 128 subpx/frame. The orb inherits the X subpixel position (0x50B) from the Medsua head, so if it above 128, it will roll over a full pixel. However, if bit 3 (0x8) of the orb's status byte (0x560) is set, the game considers it facing left, and will move it left. Now, with a sufficiently small subpixel position, it will roll over one pixel to the left, which is how it lands on the upper ledge.
Before the orb, the status byte is used by the Medusa head as a hitstun timer: On taking a nonlethal hit, it will be set to 16 and count down to 0.
The status byte is also used by Grant himself, who will set it to a specific value when performing certain projectile attacks. In particular, throwing an axe or a dagger to the left will set bit 3, and him throwing one to the right will clear it.
So, the steps to reproduce it are as follows:
1.Injure the Medusa Head with a nonlethal hit and kill it within 8 frames to prevent its hitstun timer from dropping below 8. This sets 0x560 to the right value.
2.Prevent further Medusa Heads from spawning and overriding 0x560
3.Make sure to leave the vertical room with $50B set to 127 or less
4.Prevent Grant from launching any projectile attacks to the right (to the left is OK)
5.Presto, fast orb drop.
So, why is it not helpful?
In the clip you see, Trevor can collect the orb earlier, and also much further to the left than before. This finishes the stage faster, however, the subsequent cutscene will take longer, because Trevor will start further to the left and take more frames to walk to his destination in the cutscene. This more than cancels out the frame savings from the orb drop. It might potentially be ameliorated by Trevor being as far right as possible while collecting the orb. However, I've not been able to find a strat that kills Grant fast enough and still gets Trevor in the right position to collect the orb in time. Because of this, I decided to share the explanation here, in case it might be made useful in the future.
So yeah.
This changes everything. Works on J as well.
Link to videoUserfile
Like Castlevania 1, it involves only scrolling the camera on specific frames to prevent new tiles from loading. In this case, because you keep moving for one frame after you let go of a direction, it is much less obvious how to scroll the camera. The game also seems to have a failsafe that will load tiles for a frame even after the camera stopped scrolling, which further complicates things.
The general method I found is as follows:
1.Find out whether the game loads tiles on odd or even frames. The necessary value to look for is the framecounter (0x1A on U, 0x1B on J)
2.Walk in the direction you need to go and pause the game
3.If the game loads tiles on even frames, unpause on an odd frame, otherwise unpause on an even frame, holding in the direction you need to go
4.On the next frame, turn around
5.On the frame after that, turn back in the original direction
6.Finally, pause again, waiting until the next good frame to unpause
The general input rhythm going right is therefore this:
1 - Start + R (unpause)
2 - L
3 - R
4 - Start (pause)
5 -
6 -
7 - Start + R (unpause) (repeat)
For Grant, walking the inputs are the same. When climbing ceilings, you can also corrupt the map, but the inputs are slightly different.
Also important to note: In this game, visual tiles and collision tiles are not actually tied together. You can manipulate them the same way though, only you can't actually see what you're doing. This is gonna make a map viewer basically essential. Collision data lives at around 0x6E0 in RAM.
I've also started a map viewer script for BizHawk, which should hopefully help with figuring out some usable glitches.
Edit:
Link to video
Made a video showing some possible applications of the glitch I've found. Due to how long it takes to perform, a lot of potentially viable skips are not worth it. Some tricks also only are viable for Trevor only, because the other characters have shortcuts that let them bypass the section anyway.
I got a small improvement to the scroll glitch. By pausing at certain times as you walk into a column, you can delay the scrolling engine from trying to load new tiles for a little bit, minimizing the number of turnarounds you need to do.
Input File
If the tile you want to despawn is placed at the lowest row of the screen, this can save up to ten frames.
Unfortunately, with my current knowledge of the scroll glitch, this is as good as it's gonna get, and it's still way too slow for more useful applications.
I've been busy trying to write a number of Lua scripts for this game with the aim of helping to explore memory corruption. The ultimate aim of both scripts is to help with exploration in the glitched worlds, and for possibly finding new effects or a faster wrong warp. I'm not sure how useful they'll end up being, but oh well. They certainly turned out way more complex than I anticipated:
LinkCorruption Visualizer
This script informs you when whenever memory gets corrupted when being out-of-bounds. It shows which values get corrupted in the form of a RAM heatmap. It also shows some of the game's internal state that is relevant for determining which values actually get loaded.
It also includes a map viewer to help with navigating the glitched worlds.
Video DemonstrationMap Viewer
This is a stand-alone version of the map viewer. It's supposed to help with navigating the glitched worlds, as it turns out that even if you get stranded somewhere, there's often stairs that take you further. It also shows the raw contents of the tile buffer at $6E0, which is important for scroll glitching.
Video DemonstrationEdit:
While I'm at it, I've also started writing a Stair Dismount Guide.
Been meaning to do that for a while now.
Edit 2:
I also turned the Fast Charswitch mod from last page into a Lua script that pokes the necessary values in game, which allows me to distribute it to others, which I couldn't do with the modified ROM. You can find it here.
Video Demonstration
I've got something that may be interesting. By triggering memory corruption from going out of bounds, it is possible corrupt some of the memory values which the game uses to index into various jump tables. This normally causes the game to freeze, but it may be possible to redirect the game to jump into RAM, where it might be used to read code from the controller input variables located from $26 to $29.
Link to videoInput File
In this case, I use it to write the following code into memory:
ASL $18
DEC $18
This sets the gamestate variable from 4 to 7, which triggers a debug stage select menu, which allows me to warp straight to Dracula, completing the game in 01:12.83.
There is one major caveat though:
The way this works is that the player state variable at $0565 is corrupted to 1, when it should normally be a multiple of two, which causes the game to swap the low and high byte of two adjacent pointers. This causes it to jump to $388A, which then causes the game to execute code from open bus. It is only by luck that it eventually somehow ends up at $0020 in RAM, which is close enough to where I can manipulate it. This means that the method shown here does not work on console. I have already had Alyosha gracefully test the warp for me on console, which wasn't successful This means another way needs to be found that avoids going through open bus.
How to go from here
To find another ACE exploit that doesn't go through open bus, one would need to check what other parts of the code use these two jump handlers: CV3 Disassembly. They are located at $E86D and $E886 in ROM respectively. It would then be necessary to check if any address used as an index here can be corrupted through memory corruption, and to see if it could be corrupted to a value that jumps to a useful location in memory. However, because it is so hard to find specific, targeted memory corruptions, I am leaving it at this and posting it here for posterity. Maybe in the future, a real ACE run can come from this that can be synced on console.
As for triggering a complete credits warp, this may also be possible, but here there is also a caveat. The memory layout of the affected variables is as follows:
$26: P1 Buttons Pressed
$27: P2 Buttons Pressed
$28: P1 Buttons Held
$29: P2 Buttons Held
This means that any bits that are set in $26 and $28 must also be set in $27 and $29 respectively. This severely limits what code I can write. In particular, there is no simple "LDA / STA"-type combo that would work here, as the opcode matrix of the 6502 is simply not laid out right. This means that any way to set the gamestate variable directly to $0C (game ending) would depend on the contents of the registers at the moment this code is executed, which didn't work out when I tried. Another option might be jumping to some location in the ROM that sets the gamestate variable, but there was again no apparent option when I tried.