Commit Graph

15 Commits

Author SHA1 Message Date
nmlgc 00050d0e5e [Decompilation] [th01] VRAM text typing
Yeah, that 8×16 text RAM grid is so restricting.

Part of P0082, funded by Ember2528.
2020-03-13 19:09:12 +01:00
nmlgc ebd214bbb2 [Decompilation] [th05] RES_KSO.COM
And of course, TH05 ruins the consistency once again. Sure, the added
file error handling is nice, but we also have changes in the playful
messages (lol), and now need a third distinct optimization barrier
(🤦)… But as it turns out, inlined calls to empty functions work as
well. They also seem closer to what ZUN might have actually written
there, given that their function body could have been removed by the
preprocessor, similar to the logging functions in the Windows Touhou
games. (With the difference that the latter infamously *aren't*
inlined…)

Part of P0077, funded by Splashman and -Tom-.
2020-02-23 17:53:17 +01:00
nmlgc b8ca607c38 [Decompilation] [th02] Get zun_res1.c right
4½ years after aa56a7c, it turns out that the correct decompilation
involves… no-ops generated by assigning variables that just happen to
be in registers to themselves?! Which does get optimized out, but only
after TCC folded identical tail code in all branches of a function,
thus effectively functioning as an optimization barrier.

The initial attempt used register pseudovariables, but this definitely
is the best possible way this could work – portable, and doesn't
unnecessarily shred the code into tiny inlined functions pieces. The
mindblowing thing here is that ZUN could have actually written this to
have additional, albeit unnecessary, lines to place breakpoints on. But
that means he must have chosen those two local variables in SI and DI
completely by chance… 🤯

The best thing though? ~#pragma inline is gone~

Part of P0076, funded by [Anonymous] and -Tom-.
2020-02-23 17:12:35 +01:00
nmlgc a1f36ffa04 [Reverse-engineering] [th03] Demo initialization
Something small that came out of the resident structure review.
Including more research to suggest that we probably can't ever use C++
constructors for anything in ReC98.

Part of P0076, funded by [Anonymous] and -Tom-.
2020-02-23 16:58:30 +01:00
nmlgc ff777a099e [Decompilation] [th03] Add a type for the paletted playchar IDs
Much better than the previous incorrect comment, since the char_id()
method now easily generates the correct sequence of conversion
instructions, seen all throughout the ASM. Even within array
subscripts!

Part of P0076, funded by [Anonymous] and -Tom-.
2020-02-23 16:56:14 +01:00
nmlgc a6d292a62c [Decompilation] [th01] graph_putsa_fx
TH01's (original) version also replicates the PC-98 text RAM's reverse
and underline attributes. Which was removed in later games,
interestingly and inconsistently enough.

Part of P0068, funded by Yanga.
2020-01-14 22:04:12 +01:00
nmlgc 9f7dde8953 [Decompilation] [th01] Inter-page rectangle moves
Semi-unused, that is, the one use of this function doesn't actually
move the rectangle to a different position. Ironically, the non-moving
back-to-front function immediately above *is* unused…

Also, too bad that stack order is the only reason we can't use structs
to combine all plane variables into a single object.

Part of P0067, funded by Splashman.
2020-01-14 21:50:23 +01:00
nmlgc e55a48b700 [Decompilation] [th01] master.lib resident palette function reimplementations
Which store colors as GRB, as suggested by the structure's ID string.
Even master.lib's own functions add an additional XCHG AH, AL
instruction to get colors into and out of this format. MASTER.MAN
suggests that it's some sort of standard on PC-98. It does match the
order of ths hardware's palette register ports, after all.
(0AAh = green, 0ACh = red, 0AEh = blue)

Now we also know why __seg* wasn't used more commonly, as lamented in
c8e8e98. Turbo C++ simply doesn't support a lot of arithmetic on
segment pointers.

And then that undecompilable far call to a function within the same
segment, but inside a different translation unit…
Also, thanks again to Egor for the SCOPY@ hack that debuted in 0460072.
Would have probably struggled with this a lot more without that.

And *then* you realize that TH01 effectively doesn't even use the
resident palette. 😐

And yes, we're procrastinating the whole issue of potentially using
a single translation unit for all three binaries by using a common
segment name, because it *really* isn't that easy.

Completes P0066, funded by Keyblade Wiedling Neko and Splashman.
2020-01-05 20:23:27 +01:00
nmlgc 5f4f5d87dc [Decompilation] [th03] Shot update and render functions
Meh, can't overload arithmetic operators that take a Subpixel without
generating a needless load and store, even with -Z. But heck, slightly
uglifying subpixel/subpixel arithmetic is exactly the right trade-off.

Completes P0061, funded by Touhou Patch Center.
2019-12-05 21:41:31 +01:00
nmlgc da27eb4c31 [Decompilation] [th05] Yuuka's shot control functions
Ooh, shot position being determined by RNG at lower shot levels? That's
some RNG manipulation TAS potential right there! Maybe.

Part of P0037, funded by zorg.
2019-10-14 23:54:29 +02:00
nmlgc db4de240e9 [Decompilation] Prepare the C side for the shot type control functions
That should make this convoluted copypasta a bit easier to read. And
sure, I could have done something about the loop as well, but
SHOT_FUNC_INIT already hides enough control flow behind a macro…

Part of P0037, funded by zorg.
2019-10-14 23:42:20 +02:00
nmlgc 82b0e1db24 [Reverse-engineering] [th05] Player shot cycle bitflags
A TH05 innovation that actually makes the game code easier to read?!
Although it was quite hard to actually reverse-engineer it, with the
confusing flag ordering pointing to some deeper meaning behind the
flags, which really doesn't exist.

Completes P0036, funded by zorg.
2019-10-14 23:42:09 +02:00
nmlgc a533b5d3ea [Reverse-engineering] [th04/th05] Player sprite area invalidation
And once again, the TH05 version is un-decompilable. :/ It was pretty
close this time, though, as the entire block between PUSH DI and POP DI
kind of resembles a separate inlined function, in accordance with Turbo
C++'s  automatic backup of the DI register, as researched in 7f971a0.

Except that it contains a loop, and Turbo C++ refuses to inline any
function with `do`, `while`, `for`, or `goto`. If it didn't, it would
have totally worked.

Also, yes, C++ class methods are treated identically in this regard.

Oh well. Shot type control functions next, finally!

Completes P0035, funded by zorg.
2019-09-24 22:04:26 +02:00
nmlgc 7f971a0d1c [Research] Find out why we can't decompile TH05's hud_bar_put()
Part of P0033, funded by zorg.
2019-09-21 14:01:51 +02:00
nmlgc 8dfc2cd535 [Research] Find out why ≥TH03 checks input twice per frame, with a 0.6ms delay
Thanks to @joncampbell123 for the tip!

Funded by zorg.
2018-09-13 18:32:24 +02:00