Which actually does inline… in C++, because Turbo C++ doesn't support
the `inline` keyword in C mode. So much for the superiority of that
language, even in 1994…
Part of P0083, funded by Yanga.
All the weird double returns in FUUIN.EXE just magically appear with
-O-! 😮
And yeah, it's a bowl of global state spaghetti once again. 🍝 Named
the functions in a way that would make sense to a user of the API, who
should be aware of typical side effects, like, y'know, a changed
hardware palette… That's how you end up with the supposed "main"
function getting a "_palette_show" suffix.
Completes P0082, funded by Ember2528.
They do make everything so much simpler, after all. Especially now that
th01/formats/grz.cpp should compile as a freestanding translation unit,
as part of the .GRZ viewer.
Part of P0082, funded by Ember2528.
Since we not only have the .PTN sub-image count array in the middle of
all those .GRP flags, but the .PTN loading code also reusing the
palette set flag…
Part of P0082, funded by Ember2528.
Turns out that the .GRP file functions are, of course, also present in
FUUIN.EXE… but use different palette fade functions there? This is the
first function in the way.
Part of P0082, funded by Ember2528.
Yet another run-length encoded graphics format, this one being
exclusively used to wastefully store Konngara's sword slash and kuji-in
kill "animation".
But for once, the terrible code generated by inline functions with
non-literal parameters perfectly matches what ZUN wrote here.
Part of P0081, funded by Ember2528.
I tried `brge` for the latter, but that had *the* most horrible
ergonomics, and I misspelled it as `bgre` 100% of the times I typed it
manually. Turns out that `dots` is also consistent with master.lib's
naming scheme, leaving `planar` to *actually* refer to types storing
multiple planes worth of pixels. These types are showing up more and
more, and deserve something better than their previous long-winded and
misleading name.
Part of P0081, funded by Ember2528.
Just like with the z_text_*() functions, master.lib doesn't already
have graph_init() and graph_exit() either, and once again, ZUN's code
here doesn't fully correspond to any master.lib function. Unlike the
z_text_*() functions though, those names aren't really the best
descriptions for these rather random combinations of BIOS calls and I/O
port writes…
Anyway, that's the entire segment!
Part of P0080, funded by Ember2528 and Splashman.
No macros for the port numbers here! Anyone who will try to read and
understand this code will probably want to look those up in PC-98
hardware documentation, and macros would just be an annoying layer of
indirection then.
Part of P0080, funded by Ember2528 and Splashman.
Page… 2? On a system with only page 0 and 1? Had to get out my real
PC-98 to double-check that I wasn't missing anything here, since
every emulator only looks at the bottom bit of the page number. But
real hardware seems to do the same, and there really is nothing special
to it semantically, being equivalent to page 0. 🤷
Part of P0080, funded by Ember2528 and Splashman.
Allowing us to then retrieve it using a function call with no run-time
cost, although we do have to be careful with the types here.
Also, is that another solution to decompilation puzzles that involve
types of number literals?
Part of P0080, funded by Ember2528 and Splashman.
Which need to be separate from Mai's and Yuki's 32×32 balls because…
they have a delay cloud, whose radius absolutely has to be stored
redundantly, rather then deriving it from the [age]? Same for the decay
frame count. And the _update() function was copy-pasted from the knife
one…
Part of P0079, funded by -Tom-.
Heavily hardcoded for only two of them, even though there'd be space
for 65, even without position independence. Puppet army mod when?
Part of P0078, funded by iruleatgames and -Tom-.
On the surface, TH05 uses one single 26-byte structure for
• the Stage 2 starfield,
• Alice's puppets,
• curve bullet heads,
• Mai's snowballs and Yuki's fireballs,
• Yumeko's knives,
• and Shinki's 32×32 bullets.
But looking closer, it turns out that the fields of all these have very
different semantics, and in some cases, even different types. uth05win
treated all of those as distinct structures, and we're going to do the
same, merely overlaying the pointers onto the same generic array.
Part of P0078, funded by iruleatgames and -Tom-.
7 individually moving curve bullets × (16 trail points + 1 head point)
= 117 effective hitboxes. And yes, the game only renders half of them.
Part of P0078, funded by iruleatgames and -Tom-.
This cautionary tale of wasted time will now be told at
https://github.com/nmlgc/Slices
with additional context for anyone else thinking about starting their
own ReC project.
Completes P0077, funded by Splashman and -Tom-.
And with all possible .COM executables decompiled, this set of changes
reaches an acceptable scope, allowing us to *finally*…
Part of P0077, funded by Splashman and -Tom-.
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-.
Huh, C++ wants its `char`s to be unsigned in order to *not* sign-extend
them to 16 bits for comparison against ASCII literals?!
Anyway, that completes TH03's ZUN.COM, with bascially no new C code.
Part of P0077, funded by Splashman and -Tom-.
The supposedly low-hanging fruit that almost every outside contributor
wanted to grab a lot earlier, but (of course) always just for a single
game… Comprehensively covering all of them has only started to make
sense recently 😛
Also, yes, the variable with the uppercase .CFG filename has itself a
lowercase name and vice versa…
Part of P0077, funded by Splashman and -Tom-.
Oh wow, caff4fe introduced wrong bytes into RES_KSO.COM by confusing
[cfg_bombs] with [credit_lives] -.- Which I didn't find out back then
because all the RES_*.COM binaries still had some different instruction
encodings anyway and I just didn't care enough to base my diff of those
files on the wrong encoding versions to notice the bug…
Whoops.
Part of P0077, funded by Splashman and -Tom-.
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-.
Necessary to make string literals from the first one end up at their
correct positions in the data segment even after the upcoming
deduplication…
Part of P0076, funded by [Anonymous] and -Tom-.
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-.
Now with the correct types, more consistency with the other games with
some field names (rank, is_cpu, rand, bgm_mode, demo_num), and some
more research to improve some of the TH03-specific fields.
Part of P0076, funded by [Anonymous] and -Tom-.