This is SBD Wolf. He’s held the speedrunning world record for Castlevania multiple times
over the years. We’re entering Stage 13 of Castlevania,
and he is going to move Simon to the right in a rather odd way.
However, there is a method to this madness…
A series of inputs to the controller has glitched the level in a very specific place – a place
where Simon normally steps off a stairwell and continues walking to the left.
But not this time…
The stairs didn’t “stop.” Simon continued upward and arrived in a later section – skipping
some gameplay and saving precious time.
It was accomplished thanks to glitching the scrolling of the game by moving Simon and
therefore the camera in such a way that this area of blocks of level data did not load
properly.
User controllable scroll manipulation for Castlevania was discovered in the summer of
2020, and the methods used and areas exploited have evolved ever since.
In this video, we’re going to examine how this is possible by peering into the inner-workings
of the game. This is going to get technical.
First of all, let’s talk about how scrolling works from the standpoint of building the
level that Simon traverses. There is more to scrolling than simply moving a camera.
We can’t load an entire level into Video RAM. It won’t fit. We only have room for
two screens-worth of background tiles. Logic has to examine where Simon is and in what
direction he is moving in order to load stage background make-up before it scrolls it onto
the screen.
When we reach a proverbial “edge” of VRAM - be it the start or the end, we wrap around
to the other side. If Simon is moving right, background data
is loaded into columns that are ½ a screen past the camera’s right.
Turn around and walk left, and the process reverses.
The graphics are loaded in blocks of 32 pixels by 32 pixels. The topmost block is loaded
first, and we see only a 16 pixel height for this one, and then 32 by 32 blocks are loaded
underneath from top to bottom – drawing down the screen inside a 32 pixel-wide column
as the camera continues to move. Top to bottom and column by column, the blocks
are replaced with newly loaded level data.
If we stop moving, the graphics stop loading. Our goal is to take this simple operation
– the loading of level data during scrolling - and break it.
Now how do we do that using an NES controller? Our dive begins.
The camera’s X Position is shown at the top of the screen. I can move right and the
value increases. When I walk left, the camera moves left, and
the number decreases. Pretty simple. We have two screens worth of information in
VRAM – 256 pixels across for a single screen times two. If you divide this into columns
that are 32 pixels across, you get 16 columns.
Castlevania maintains two numbers that represent the left side and right side “bookend offset
columns” we’ll call them. Our camera is between them. Naturally, they change as the
camera moves and the next column is targeted for loaded level data.
Currently, the left side bookend is column 0. Add 15 to this, and the right side bookend
is “Column 15.”
If I start walking to the right, we want to load the graphics for the last bookend – column
15 – so we do that. Once the camera has moved its first 32 pixels,
we’ve completed the first column. Our offsets increment. Our two screens-worth of information
now spans columns 1 through 16. Our figurative “seam” has moved… here.
Let’s return to the beginning.
Since we can’t walk to the left from the start of the game, the garbage tiles for columns
0 to 3 don’t matter. As for these garbage tiles - would you like
to see them in the game? Let’s change the right bookend offset in RAM from fifteen to
zero! That sets us up so that once I start moving the camera, the game will think it
needs to load column zero instead of column fifteen and proceed from there.
It draws these garbage columns in the same order we saw them in the PPU Viewer at the
start of the game.
Two gray columns, two garbage columns, and if I jump into the abyss and freeze it before
taking a death… you can see the very first column of the start of the game with the tree…
plus the second column with the statue. If I let the game roll so we lose a life…
The game respawns us at the start, resets the bookend offsets, and reloads the proper
background tiles into VRAM once again for current columns used, plus four columns to
camera left and three columns to camera right.
A single, untouched column retains those gray bricks. They are left over from our little
hack! But as you know, this will be the first column to receive background updates when
we walk to the right. The appropriate graphics overwrite the leftover data.
We now know about column layout, camera movement, and the bookends changing after every 32 pixels
of continuous camera movement in either direction.
If these numbers were too much to process, the fundamental questions they help answer
are: “Where are we?” and “Where are we going?”
As we move, the direction we are going is used to load level data for where we will
eventually be. If we can confuse the game logic that uses
camera direction to know where we are going and therefore which associated level data
and graphics to load, perhaps we can alter where the game lets us go.
The key lies within the logic that loads level data for a given 32 pixel-wide column.
While we could walk the code and level data involved, it is a lot easier to use graphics
to explain this one. Earlier, we observed column updates in the
PPU Viewer. If we show updates regardless of if data has changed or not, we can see
that each column is written to twice as the camera moves.
Let’s use scripting to draw boxes inside the game screen and represent the background
tiles being written to VRAM off screen that we can see in the PPU Viewer.
The game maintains a block counter in RAM to keep track of which block it should update.
I wrote the block counter’s value inside the boxes I am drawing.
As the camera moves across a lateral distance of 32 pixels, the block counter updates the
appropriate column twice. Graphics update on 1 through 6.
Once the camera has moved 32 pixels, the block counter is reset to zero, and the bookend
column offsets are incremented. We start the process of loading appropriate level data
and drawing the next column – 16 - to VRAM and. The process repeats.
First pass. Second pass. The block counter resets. Bookends increment. And so on.
Our Castlevania scroll analyzer is growing in complexity.
There is a value in RAM – we’ll call it “Tile Refresh” that alternates between
0 and 32 to represent when the camera crosses from one set of 32 pixels into the next set
of 32. Instead of using the values, let’s use the letters A and B. This helps the tile
refresh standout from the numbers on the screen. I’ll also match the color of the Tile Refresh
value to the boxes we are drawing.
Draw A column once, twice. Draw B column once, twice.
Tile refresh alternates every 32 pixels. Clockwork… so long as I keep walking to
the right.
For 32 pixels of horizontal travel starting from zero, the block counter rolls from 0
to 7 twice – or - 16 times total. The columns are drawn at half the rate of horizontal travel
so long as you keep moving. This is by design.
Now you may have noticed I’ve continued to repeat “as you keep moving” as a caveat.
Time for some finer points. Castlevania makes use of a frame counter in
RAM that does what it’s called and continues to count frames for the game. This can be
used for several things – including – knowing how to split-up logic so it doesn’t run
every single frame. Why would you do that? The answer is “performance.”
Let’s oversimplify and say you only have 7 values to analyze and/or operations to perform
for your logic in the game. You could just examine each value and perform the necessary
actions every frame. Unfortunately, this may result in performance problems – the game
may “slowdown” in some places as it has to churn through all of this logic every frame.
We certainly know what slowdown is on the NES.
Alternatively, you could run high priority items each frame and distribute other checks
so they run every other frame or even every several frames.
Speedrunners are aware of how often specific logic is executed, and they refer to this
frequency as a “frame rule.” Controller input? Pretty important! Best to
handle that every frame. Checking to see if we need to open a door,
move Simon forward, and then shut the door? Probably don’t need to check that every
single frame.
Scrolling is updated every other frame, and uses this frame counter to know if we should
update scrolling or not. As a matter of fact, I can freeze the frame
counter in RAM on an odd or even number to force columns to be updated every frame or
not at all. Freeze the frame counter on an odd value,
and the columns are updated on every frame – twice as fast as the default method.
Freeze the frame counter on an even value, and the columns never update. We are left
with whatever garbage was loaded at the start of the Stage.
Speaking of stage, our stage is set. All values we want to monitor are now in place.
Now for some important observations.
In normal gameplay, Simon can reverse direction when the player wants. When the reversal occurs,
the block counter just continues increasing as usual despite the fact blocks are now being
loaded off the opposite side of the screen. Second key point – the block counter resets
whenever we cross a tile refresh boundary. We illustrated this with a color change and
a swap between values A and B. Even if we are in the middle of updating a column, the
block counter resets at the tile refresh boundary. This helps us find a starting point for executing
a specific scrolling exploit.
Now… In order to manipulate level loading, we do
the following: 1: Use our knowledge of 32 pixel tile refresh
distances to know where on screen we need to stand to start the block counter at our
desired value. 2: Move in the direction we want to go and
load column blocks up until the block we want to skip loading.
3: Use a very short movement in the opposite direction to swap the side of the screen the
loading logic uses to load level data. 4: Repeat steps 2 and 3 until we cross a tile
refresh boundary, update the bookends, and therefore begin loading the next column.
That’s the magic formula.
Let’s use Stage 13 as our example. Under normal circumstances, we walk to the
right, make our way up two sets of stairs, and continue to the left. The second set of
stairs drops us off when we hit the next set of floor tiles here.
This is the block that we saw SBDWolf exploit earlier.
These tiles are not on the screen when the level first loads, and he kept this garbage
data in VRAM by performing a scrolling exploit technique.
If we use the PPU viewer, you can see the original garbage data here is still in place
after moving right.
Simon can now walk up those stairs, and… doesn’t have a way to get off of them on
this screen. The logic lets him keep going and climb to the next level up.
This bypasses having to walk all the way to the left, climb the stairs, deal with the
skeletons on the next screen, climb more stairs, walk right, and climb down.
Now – how do we do it?
There are multiple methods to choose from. I am going to use an early method the community
calls the “2-14 turnback method” – two pixel turnbacks with fourteen pixel walk forwards.
To execute a turnback, we will be making use of a “whip method.” By using the whip
a frame after pressing back, we can move Simon two pixels. The whip is used to stop him from
walking too far. We need to move at least two pixels for our
turnback because moving for two frames guarantees that we execute scrolling update logic as
it only executes every other frame. We could only move 1 pixel and still have
a 50% chance that we get that single block write in the opposite direction, but we are
guaranteed this update if we move two pixels because we know we executed logic on both
an even and odd frame counter.
Let’s examine SBDWolf’s method from his 11:05.717 former world record run in more
detail. A jump from this point is used to start the
move. 2 pixel turnaround – holy water was thrown
as the d-pad also received an up press on the maneuver. Walk forward 14 pixels. A whip
technique to slide Simon backward. He didn’t turn around, so this was likely a single pixel
movement with a 50% chance of executing scroll logic depending on if the frame counter was
on an odd or even number. In fact he later states… (“probably not
gonna work”) But fortunately, the slide happened on an
odd numbered frame counter and… (“it worked!”) As for the remainder of that sequence:
One last 14 pixel walk forward, a quick turnaround with no whip this time. Exploit complete.
Let’s perform an exploit in the emulator and see the step by step behind the scenes
values.
I’ll combine the column number with the block being updated in my narration like “16-2”
or “1-3” so you know which side of the screen I am talking about in addition to which
block. Here we go.
The initial scene looks like this. Our span is column 0 to 15. Column 15 hasn’t been
drawn yet. I’ve cleared all enemies and candles, disabled respawning and frozen the
game timer. I’m a programmer. Not a speedrunner.
We line Simon up with the rivet here and perform a backward jump by pressing A and immediately
holding right and down. Column 15 iterates through block updates 1 thru 6 twice, our
camera X Position rolls up past 32, the bookend offsets update to 1 and 16, and blocks 16-1
and 16-2 are drawn. We stop just short of drawing 16-3 as Simon lands facing right.
Next is a whip turnaround to move left 2 pixels. This updates 1-3 in the left direction and
prevents using new graphics for 16-3 to overwrite the garbage tile we want to keep.
We then walk forward and finish blocks 16-4 through 16-6, start our second pass for the
column, and update 16-1 and 16-2 once again. Whip turnaround to bypass the 16-3 write and
draw to 1-3 on the left once again. Walk forward to finish 16-4,5,6,1, and 2.
Whip turnaround once last time to write to 1-3 yet again.
And now we are done.
Once Simon starts walking right, the camera X Position reaches 64 pixels, the offsets
increment, and we are no longer in danger of drawing to column 16 as we move to the
right as we have crossed the tile refresh threshold.
Here is the “play by play” of the exploit. It should help illustrate the “journey”
across the screen. The fundamental goal is to NOT overwrite a
32x32 block or blocks that we wish to keep.
There are a few other methods that are perhaps worth mentioning – Instead of 14 forward
and 2 back, some runners like to use 12 forward and 4 back. This targets two blocks for the
glitch and provides some wiggle room – no pun intended – to allow for a mistake in
the input sequence.
Ideally, any mistake that occurs happens on the block you don’t care about.
Here, trisk uses a quick, rhythmic, left-right input on the d-pad to demonstrate a whipless
4-12 technique. No mistakes were made, and this results in
two 32x32 blocks of garbage instead of just one.
jay_cee uses whipless 4-12 and 2-14 techniques depending on the exploited area. A whipless
2-14 technique has less of a margin for error and is therefore risky, but the method selected
by the runner may simply depend on that runner’s muscle memory - use whatever works.
Although we have focused on a specific section of Stage 13, there are other areas where this
exploit is used.
Later in Stage 14 it lets Simon not only walk backward through an area where there used
to be a wall, but also “draw” a scroll stop with a door mechanic on the screen – letting
him quickly skip ahead to Stage 15. How did we manage that?
After arriving on Stage 14, the set of stairs that leave the first screen place us here.
There is no scrolling to the right from here. We go up and then left.
Adjacent level data in these columns when this screen is first drawn is not used. The
first screen of the game had garbage data that we investigated, but here we seem to
have legitimate level data. Does it look familiar?
It appears to be from the boss room. You fight Death in a room with this design and a door
on the left side. You never walk through that door as you have to defeat the boss and collect
the orb to complete the Stage, but it would appear that we can USE this scroll stop and
door thanks to our scrolling exploit in order to skip ahead to Stage 15.
I haven’t verified the level data, but it makes sense.
Turnbacks are also used in the crusher room in Stage 6 in order to create a tiny bit of
a staircase that lets Simon climb all the way up to the Medusa battle and skip the normal
corridors traversed.
Jay_cee’s World Record run of 10:45.283 showcases several scrolling exploits, and
I recommend you check that video out to see more of them in action.
Well! I hope you enjoyed this examination of the Scroll Glitch in Castlevania. Please
like and subscribe for more videos like this one. I have also have a Patreon available
for those of you interested, and thanks for watching.