ReC98
@rec98project.bsky.social
110 followers 7 following 160 posts
https://rec98.nmlgc.net The Touhou PC-98 Restoration Project. Decompiled 100% of TH01 to provably legit C++ code, remaining games in progress. Which mods or ports do *you* want to see?
Posts Media Videos Starter Packs
rec98project.bsky.social
Summary blog post: rec98.nmlgc.net/blog/2025-09-29

Ending this overly indulgent subproject with, among other things:
• Heap fragmentation everywhere
• An asynchronous fade effect
• Silly binary size micro-optimizations

Funded by [Anonymous] and Ember2528.
Table inspecting the different states of the master.lib heap when entering and leaving TH05's Music Room in an early version of the debloated P0323 build, showcasing how heap fragmentation prevents the main menu's background image from being loaded a second time, which caused the game to crash prior to finding a workaround. Taken from the ReC98 2025-09-29 blog post. Not-quite-pseudocode snippet showcasing an easy solution for a screen tearing landmine using the new `vblank_run()` mechanism that will deterministically run its task either now (if currently in VBLANK) or after the next VSync interrupt. Taken from the ReC98 2025-09-29 blog post. Visualization of the DOS heap when trying to launch TH02-TH05's INTvector set program using the spawn-at-top technique I developed in 2023 for the TH01 Anniversary Edition. Thanks to ZUN's fantastic idea of bundling these small utility tools and TSRs into a single binary that's larger than each individual TSR, DOS fails to load ZUN.COM, as the total binary is much larger than the resident size of the interrupt vectors. Taken from the ReC98 2025-09-29 blog post. Table of the various PMD versions bundled with TH02-TH05, listing their release date and resident sizes in conventional DOS RAM. The caption reads: "The PMD versions that ZUN shipped with each game. The byte size refers to the in-memory TSR size without any music, voice, or effect data added on top." Taken from the ReC98 2025-09-29 blog post.
rec98project.bsky.social
Many thanks to this month's subscribers!

The current plan for the rest of the year:
1) Shuusou Gyoku maintenance (will quickly free up some budget)
2) TH03 RE
3) Better replays for Shuusou Gyoku
4) TH03 netplay (would be nice to get it done by the end of the year)
Active ReC98 subscriptions for September 2025:

• €300 from Ember2528 towards better replays for Shuusou Gyoku, followed by a long-term plan to first decompile TH03, adding replays, porting it to modern systems, and then implementing netplay (although we're also going for a more short-term option of having netplay on PC-98)
• €125 from [Anonymous] towards anything (including tooling)
• €35 from [Anonymous] towards TH03 RE
• €10 from Root towards porting SDL2 to Windows 98 to get Shuusou Gyoku running there again
rec98project.bsky.social
🚚 Released the first version of the TH03 Anniversary Edition together with the first debloated builds of all five games! Primarily reduces lag in menus and cutscenes as a first step towards portability, but also comes with a single new feature.

Download: github.com/nmlgc/ReC98/...
Screenshot of the VS Start menu in the P0323 build of TH03's Anniversary Edition, showing off the new Quit option and the version text. The caption reads: "Matching the style of the version text to the style of 「☪ The Phantasmagoria of Dim. Dream」 on the other side seemed like the least bad option here. That outline is indeed created by rendering every line 9 times…" Taken from the ReC98 2025-09-29 blog post. Screenshot of a video of the flashing 東方封魔録 animation before TH02's title screen, as rendered by the original game on Neko Project 21/W with a clock speed of 2.4576 × 27 = 66.3552 MHz. Showcases screen tearing and slow .PI blitting. Taken from the ReC98 2025-09-29 blog post. Screenshot of a video of TH03's character selection screen in 1P vs. CPU mode, showcasing the screen tearing landmine upon entering the screen in the original game. The caption reads: "Recorded on DOSBox-X with 375,000 cycles, since exact machine specifications are not important to demonstrate these landmines." Taken from the ReC98 2025-09-29 blog post. Screenshot of a video of leaving TH02's HiScore menu, as rendered by the original game on Neko Project 21/W with a clock speed of 1.9968 × 17 = 33.9456 MHz. Showcasing both a landmine (ZUN copying the invisible VRAM page onto the visible one without any palette trick to hide the copy, resulting in mixed pixels) and a bug (the scoreboard should have been removed from the PC-98's text layer by that point). The caption reads: "Recorded at 1.9968 × 17 = 33.9456 MHz for a change to magnify the jank that you perhaps wouldn't see at higher clock speeds." Taken from the ReC98 2025-09-29 blog post.
rec98project.bsky.social
The end is near! >9,800 words, and probably the last big blog post for this year. I wanna code again!

Out within the next few hours…
The table of contents of the upcoming 2025-09-29 post on the ReC98 blog. It reads:

1. The scope
2. Retaining menu backgrounds in conventional RAM
   • Fighting heap fragmentation
3. Resolving screen tearing landmines
   • Deterministically running tasks in VBLANK
   • An easy example (TH04/TH05 main menu reinitialization)
   • A hard example (TH03 character selection)
   • A lunatic example (TH02 High Score screen)
4. Intermission: Handling unused code on fork branches
5. Merging TH02-TH05's OP.EXE and MAINE.EXE/MAINL.EXE
   • Scorefile inconsistencies
   • Keeping TH05's binary size low
6. Replicating TH02-TH05's GAME.BAT in C++
   • Calculating correct resident sizes
   • Additional features and obstacles
7. Topping it off with an actual feature
rec98project.bsky.social
$ git diff --stat debloated~193 debloated
[…]
259 files changed, 4145 insertions(+), 8099 deletions(-)

~4,000 lines of ad-hoc PC-98-native graphics code, bloat, landmines, bloat- and landmine-documenting comments, and binary-specific inconsistencies removed from game code 🎉
rec98project.bsky.social
Summary blog post: rec98.nmlgc.net/blog/2025-09...

This time with:
• More research into earlier Bluesky posts
• Special content for Peaceful Romancer enjoyers
• The 4th bug caused by C's integer promotion rules within 11 months

Funded by [Anonymous], Ember2528, Yanga, and Blue Bolt.
Screenshot of a video of the first 8 beats of TH05's All Cast sequence as shown in the original game, showcasing how the first picture crossfades onto the screen way behind the second beat of Peaceful Romancer indicated in the code. Taken from the ReC98 2025-09-16 blog post. Screenshot of a video of the transition from the second to the third screen of Yuuka's TH05 All Cast sequence, demonstrating how the picture and text cues have to catch up with the BGM beat targets during such a transition. The caption reads: "As pointed out by the uneven placement of the Reimu and Rika cues. These are Yuuka's second and third screens; the fact that each character gets its own sequence of pictures is common knowledge by now, right?" Taken from the ReC98 2025-09-16 blog post. The scorefile deobfuscation algorithm used in TH03, TH04, and TH05, compressed to a single line of C++20:

// [key1] and [key2] are `uint8_t` as well.
decoded_byte[i] = (key1 + (std::rotr<uint8_t>(encoded_byte[i + 1], 3) ^ key2) + encoded_byte[i]);

Look at that nice `std::rotr()`! Have fun expressing the same in C while remaining as succinct.
Taken from the ReC98 2025-09-16 blog post. Screenshot of TH03's High Score viewer, rendering a `YUME.NEM` file that consists entirely of 00 bytes. The caption reads: "Since `YUME.NEM` stores names, scores, and stage numbers as raw sprite IDs, we get sprite #0 from `REGI2.BFT` for all of them. AAAAAAAA AAAAAAAAAA A". Taken from the ReC98 2025-09-16 blog post.
rec98project.bsky.social
🚚 Part 3 is out, bringing five disconnected and small decompilations and actually shifting the percentages on the front page for a change!

🐞 5 bugs
💣 3 landmines
🎺 2 quirks
🪨 24 pieces of bloat
The table of contents of the 2025-09-16 post on the ReC98 blog. It reads:

1. Revising TH02's main menu
2. Finishing TH03's High Score menu
3. TH04's title screen animation
4. TH05's All Cast sequence
5. Finishing TH03/TH04/TH05 scorefiles
6. A typo in TH04 Reimu A's Good Ending Mockup of the TH01's "HIT KEY" string in TH02, using the unused gaiji string that's still present in ZUN's original code. The caption reads: "This string is so unused that we don't even know its intended position, though." Taken from the ReC98 2025-09-16 blog post. Screenshot of a video showcasing the default name replacement in TH03's High Score menu, triggered by entering `BBBBBBBB`. The video later showcases how name replacement happens for any character, not just `A` or an empty name. Taken from the ReC98 2025-09-16 blog post. Screenshot of a video of TH04's title animation, on the last frame of the separately faded-in black outlines of the title screen's background image. The caption reads: "Also note that single black pixel in Reimu's gohei. 🎺" Taken from the ReC98 2025-09-16 blog post.
rec98project.bsky.social
> Next post is about five small and disconnected RE tasks
> Try to write five short paragraphs with bullet points in the style of touhou-memories
> Still end up with over 2,000 words

Coming to you within the next few hours…
The table of contents of the upcoming 2025-09-16 post on the ReC98 blog. It reads:

1. Revising TH02's main menu
2. Finishing TH03's High Score menu
3. TH04's title screen animation
4. TH05's All Cast sequence
5. Finishing TH03/TH04/TH05 scorefiles
6. A typo in TH04 Reimu A's Good Ending
rec98project.bsky.social
Link: rec98.nmlgc.net/blog/2025-09...

… OK, it does have two bits of very silly Touhou content in the end. That'll have to do until the next one.

Funded by [Anonymous], Ember2528, and Congrio.
TH03's `ENEMY01.PI`, showing off the unnecessary line doubling of TH03's in-game sprites loaded from .PI files. The caption reads: "Since PI's location codes are designed around vertical repetition, line doubling has a negligible impact on compressed file sizes. Such an image still decodes into twice as many bytes as needed, though…" Taken from the ReC98 2025-09-10 blog post. Screenshot of TH05's title screen crossfading effect, as rendered by the original game on Neko Project 21/W with a clock speed of 2.4576 × 27 = 66.3552 MHz. Showcases an unusual landmine where an incomplete VRAM-page-to-VRAM-page copy results in partially masked and partially unmasked colors, in addition to a screen tearing line. Taken from the ReC98 2025-09-10 blog post.
rec98project.bsky.social
Part 2 of my 4-part 2025 PC-98 Touhou portability series is out!
This one is also our second deep dive into PC-98 blitting performance with two new benchmarks, and also looks at the two libraries that ZUN used to load PI images.

Not a lot of Touhou-specific content in this one.
Screenshot of the new wide-sprite blitting benchmark for PC-98, running on Neko Project 21/W with a clock speed of 2.4576 × 27 = 66.3552 MHz. The caption reads: "This recording in Neko Project 21/W at 2.4576 × 27 = 66.3552 MHz might even be representative?" Taken from the ReC98 2025-09-10 blog post. Graphed results for the wide-sprite blitting benchmark, highlighting the Neko Project 21/W test at 66 MHz and showing `MOVS` winning at every width except 640 pixels, where `REP MOVS` takes the crown. The caption reads: "Number of frames required to blit [Width]×5120 pixels of a 1bpp bitmap to a byte-aligned position in VRAM, using the GRCG. The plots are relative to the respective `REP MOVS` result. Thanks to 1️⃣ オップナー2608 for the real-hardware test." Taken from the ReC98 2025-09-10 blog post. Screenshot of the new masked crossfading benchmark for PC-98, running on Neko Project 21/W with a clock speed of 2.4576 × 27 = 66.3552 MHz. Taken from the ReC98 2025-09-10 blog post. Graphed results for the wide-sprite blitting benchmark, highlighting Neko Project 21/W and showing how the optimized EGC implementation vastly outperforms not only the CPU and GRCG + CPU methods, but especially ZUN's original unoptimized code. The caption reads: "Number of frames required to crossfade [Width]×400 pixels onto all four planes of VRAM. Thanks to 1️⃣ オップナー2608, 2️⃣ Furball, 4️⃣ Will.Broke.It, and 5️⃣ spaztron64 for the real-hardware tests. Taken from the ReC98 2025-09-10 blog post.
rec98project.bsky.social
Second part is in proofreading. Over 9,300 words about PC-98 blitting and the .PI format, coming to you within the next few hours…
The table of contents of the upcoming 2025-09-10 post on the ReC98 blog. It reads:

1. Benchmarking wide sprites
   • Algorithms
   • Results
2. Reworking the blitter
3. Benchmarking masked crossfading
   • Algorithms
   • Results
   • Future work
4. Optimizing .PI image handling
   • Initial attempts
   • Extending PiLoad
   • TH03's silly line-doubled sprite sheets
5. Meeting our performance target (and uncovering ZUN bugs along with it)
rec98project.bsky.social
📝 Wrote a post about the various strategies of porting PC-98 Touhou to modern platforms! Also clears up common misconceptions about the performance of the PC-98 originals.
This one is required reading for anyone who wants to see these games ported.

Link: rec98.nmlgc.net/blog/2025-09...
The table of contents of the 2025-09-06 post on the ReC98 blog. It reads:

1. Deciding on a porting strategy
2. "Accurate slowdown"
3. Picking a CPU clock speed for emulators
   • Can 66 MHz be enough for anybody?
4. "Frame-perfect"
   • Resolving screen tearing
5. Port implementation thoughts
   • Non-issues
   • Palettized and planar graphics
   • Page flipping The list of PC-98 hardware models that Amusement Makers tested PC-98 Touhou on and confirmed working (taken from http://www.kt.rim.or.jp/~aotaka/am/get.htm), followed by a remark about "accurate slowdown" (taken from the ReC98 2025-09-06 blog post.) The whole text reads:

なお当サークルでは
    ・ NEC PC-9821Xs        i486DX2 66MHz
    ・ NEC PC-9821La13      Pentium Processor (P54C) 133MHz
    ・ EPSON PC-486MS       AMD 5x86-P133 換装
などで正常に動くことを確認しています
These models are one whole CPU generation apart and their clock speed differs by 100%. Which one of these is supposed to have the accurate slowdown?" Screenshot of TH04's Music Room, demonstrating the screen tearing landmine that the original game exhibits on every frame, with an overlaid colored visualization of which lines correspond to which frame. The caption reads: "Which frame are we even on? 😵 This landmine is the reason why the first rule explicitly restricts rendering to a single VRAM page. Check the Music Room blog post (https://rec98.nmlgc.net/blog/2024-02-03#mess-2024-02-03) for an explanation of what went wrong here. Taken from the ReC98 2025-09-06 blog post. Screenshot of a frame within the shake animation at the beginning of TH02's Stage 3, demonstrating how shaking VRAM by 16 pixels temporarily reveals parts of the tile area below the HUD. The caption reads: "This definitely counts as a bug to be fixed in this game's Anniversary Edition, but how would we fix this one on PC-98 where we do need the tile area in VRAM? Moving the tiles to another place and patching the .MAP (https://rec98.nmlgc.net/blog/2023-03-30#diffs-2023-03-30) at runtime?" Taken from the ReC98 2025-09-06 blog post.
rec98project.bsky.social
Trying something new this time! The next release touches on so many topics that one blog post would have been way too intense for everyone.

So I'm splitting it up into 4 posts, with each focusing on a different topic.

First part (~8,000 words) coming within the next few hours…
The table of contents of the upcoming 2025-09-06 post on the ReC98 blog. It reads:

1. Deciding on a porting strategy
2. "Accurate slowdown"
3. Picking a CPU clock speed for emulators
   • Can 66 MHz be enough for anybody?
4. "Frame-perfect"
   • Resolving screen tearing
5. Port implementation thoughts
   • Non-issues
   • Palettized and planar graphics
   • Page flipping
rec98project.bsky.social
Many thanks to this month's subscribers!

Code is done escalating, and now it's the blog post's turn. Got >13,000 words now and it's still missing lots of content… I'll be so relieved once I get to spend the rest of the year on TH03 and Shuusou Gyoku with no more distractions.
Active ReC98 subscriptions for August 2025:

• €300 from Ember2528 towards better replays for Shuusou Gyoku, followed by a long-term plan to first decompile TH03, giving it a single Anniversary Edition release on PC-98, adding replays, porting it to modern systems, and then implementing netplay (although we're also going for a more short-term option of having netplay on PC-98)
• €125 from [Anonymous] towards anything (including tooling)
• €35 from [Anonymous] towards TH03 RE
• €10 from Root towards porting SDL2 to Windows 98 to get Shuusou Gyoku running there again
rec98project.bsky.social
Here's all the ZUN quirks, bugs, landmines, and bloat from previously RE'd code that I missed or got wrong in previous pushes and fixed for the upcoming ones.

Reverse-engineering is hard.

Commit subject lines:
• [Research] [th01] Packfiles: Document landmine when loading nonexistent files
• [Research] [th01] Document palette oddities in boss setup code
• [Research] [th01] Resident structure: Document the allocation failure landmine
• [Research] [th01/th02/th03] graph_putsa_fx(): Note illegal Shift-JIS landmine
• [Research] [th02] Staff Roll: Suggest the EGC for the version string animation
• [Research] [th02] Staff Roll: Fix wrongly interpreted bottom shift coordinate
• [Research] [th02] Verdict: Remove bloat label from skill capping
• [Research] [th03/th04/th05] Cutscenes: Document screen tearing landmines Commit subject lines:
• [Research] [th02/th03/th04/th05] Document remaining tearing landmines in menus
• [Research] [th02] High Score viewer: Document the 50% page landmine on exit Commit subject lines:
• [Research] [th03] High Score menu: Note excessive unblitting for rows
• [Research] [th04/th05] High Score menu: Clarify GENSOU.SCR load TOCTOU issue
• [Research] [th04] GENSOU.SCR: Document the recreation landmine in `OP.EXE`
• [Research] [th05] Title screen animation: Upgrade fade cel landmine to a bug
• [Research] [th03] YUME.NEM: Remove incorrect comment about file recreation
• [Research] [th03] YUME.NEM: Document the `MAINL.EXE` clear flag landmine Commit subject lines:
• [Research] [th03] Main menu: Document the initial held key quirk
• [Research] [th03] Main menu: Remove bloat label from difficulty strings
• [Research] [th03] Main menu: Remove bloat label from seen opponent array
• [Research] [th03] Main menu: Document the box unblitting region bloat
• [Research] [th03] VS menu: Document the initial held key quirk
• [Research] [th03] Main menu: Document gaiji restoration landmines
• [Research] [th03] Character selection: Document the 1P vs. CPU delay quirk
• [Research] [th03] Character selection: Note integer division in curve plotting
• [Research] [th03] High Score menu: Document how sorting ignores the last digit
rec98project.bsky.social
By the way, your TH06 review contains what's still the best piece of journalism I've read about ReC98 so far. Thank you so much for that.
rec98project.bsky.social
Testing completed.
rec98project.bsky.social
This one was fixed in the 2014 English patch.
rec98project.bsky.social
The same screen appears correctly in Reimu B's Good Ending, which reveals this as a typo in a picture crossfading command.

The ",4" is supposed to be the second parameter, specifying how many frames to wait between each crossfading step.
rec98project.bsky.social
Here's a funny script bug in TH04's Good Ending for Reimu A that I just stumbled over.

",4魔理沙"?! 🎺

(Third-party clip from 2013 for proof: www.youtube.com/clip/UgkxUo6...)
Screenshot of the ",4魔理沙" script bug in TH04's Good Ending for Reimu A.
rec98project.bsky.social
Summary blog post (1,031 words) and downloads:
rec98.nmlgc.net/blog/2025-08...

Found no actual case of such a desync in the wild so far, but the possibility is there.

Many, many thanks to Ripper Roo for reporting this one.
Screenshot of the very embarrassing refactoring mistake that led to the gameplay-forking bug in Marisa's bit calculations. Taken from the ReC98 2025-08-12 blog post.
rec98project.bsky.social
⚠️ Another Shuusou Gyoku Extra Stage replay desync bug?
This time though, it's the actual catastrophic kind: An accidental fork of Marisa's gameplay that might invalidate replays recorded on any ReC98 build from the last 10 months, now that I've restored the original behavior.
Screenshot of a video showcasing the gameplay-forking bug that the ReC98 P0925 build introduced into Shuusou Gyoku's Extra Stage, resulting in a pattern that differs from what this previously recorded replay expects. Taken from the ReC98 2025-08-12 blog post. Screenshot of a video showcasing the expected gameplay behavior that the bug-triggering Shuusou Gyoku Extra Stage replay was recorded with. Taken from the ReC98 2025-08-12 blog post.
rec98project.bsky.social
Many thanks to this month's subscribers!

384 commits across 10 pushes coming your way soon… (Hopefully)
Active ReC98 subscriptions for July 2025:

• €300 from Ember2528 towards better replays for Shuusou Gyoku, followed by a long-term plan to first decompile TH03, giving it a single Anniversary Edition release on PC-98, adding replays, porting it to modern systems, and then implementing netplay (although we're also going for a more short-term option of having netplay on PC-98)
• €125 from [Anonymous] towards anything (including tooling)
• €35 from [Anonymous] towards TH03 RE
• €35 from Yanga towards TH02 RE
• €10 from LeyDud towards TH03 AI/Enemy/Pattern RE > Gameplay RE > MAIN.EXE > anything
• €10 from Root towards porting SDL2 to Windows 98 to get Shuusou Gyoku running there again
rec98project.bsky.social
But for the most part, this went hand in hand with making the games more portable by throwing out redundant PC-98-specific code, sorting out inconsistencies between OP and MAINE/MAINL, and general code cleanup.

That finally concludes this dev cycle! Onto testing and blogging…
rec98project.bsky.social
And TH05. This game has by far the most data unique to its OP.EXE and MAINE.EXE; even just *matching* the memory consumption of the original OP.EXE required every trick in the book and then some.

(Storing all those hardcoded strings in files would have still been better.)
DOS memory layout when launching the merged TH05 OP/MAINE executable of the upcoming debloated ReC98 build, as reported by DOSBox-X's `DOS MCBS` debug command. The main program allocation of DEBLOAT.EXE takes up 88,064 bytes of RAM. DOS memory layout when launching ZUN's original version of TH05's OP.EXE, as reported by DOSBox-X's `DOS MCBS` debug command. The main program allocation of OP.EXE takes up 88,064 bytes of RAM. DOS memory layout when launching ZUN's original version of TH05's MAINE.EXE, as reported by DOSBox-X's `DOS MCBS` debug command. The main program allocation of MAINE.EXE takes up 121,856 bytes of RAM.