ASM land had a macro for this, which suggested a corresponding inlined
class method in C++ land. We couldn't use that macro for Konngara's
third boss entity though. So I probably wanted to wait with that inline
function until the decompilation of that Konngara load call, which
could verify the existence of said inline function. And it did!
Part of P0141, funded by [Anonymous] and rosenrose.
It's been like this since the beginning, I just hadn't written it down.
So yeah, sorry to everyone who likes to edit code in period correct
90's DOS terminal editors.
Part of P0141, funded by [Anonymous] and rosenrose.
Now you can grep for it¹!
¹ Editor that's actually smart enough to not only correctly detect
Shift-JIS during grepping, but also match the characters in a search
regardless of file encoding, sold separately
Part of P0141, funded by [Anonymous] and rosenrose.
The main point of the previous strings/ subdirectory was to bundle all
hardcoded strings for translators. And sure, *technically*, gaiji
strings are *both* strings *and* something you might want to translate.
But mainly, they're sprites with an attached enum, and their own
directory. Changes to the enum quickly tend to involve changes to the
strings that use these values, so it makes sense to keep both in the
same directory.
Especially since 82% of the previous strings/ directories consisted of
such gaiji strings.
That leaves the strings/ directory rather empty and nondescript though.
Recently though, I've been wanting to generally move all Shift-JIS text
to this directory. While that wouldn't *solve* the typical "text editor
accidentally a file upon save, due to wrongly detected encoding" issue,
it's at least a mitigation: If all Shift-JIS strings are in files that
contain nothing *but* Shift-JIS strings, a wrongly detected encoding
becomes immediately noticeable.
For that job, strings/ can have a more descriptive name though. Hence,
shiftjis/.
Part of P0141, funded by [Anonymous] and rosenrose.
We've got to move all of Konngara's escape sequences to C land right
now, to get them out of the way of the filenames, so we might as well
look at all of them, in the entire binary.
But, uh… "graph mode"? That one is severely underdocumented, seemingly
even in Japanese. Turns out that it's a way to disable Shift-JIS
decoding, which makes it possible to access the half-width glyphs in
the PC-98 font ROM at the 0x81-0x9F and 0xE0-0xFF codepoints.
(In regular "kanji mode", these are interpreted as Shift-JIS lead
bytes.)
So, I did a deep dive into NEC's IO.SYS to hunt down all places where
this distinction has an effect, and then implemented it into DOSBox-X,
which was still missing everything related to it:
https://github.com/joncampbell123/dosbox-x/pull/2547
If P0140 looks a bit empty as a result, that's why – most of the
feature work went into DOSBox-X, not ReC98. That's the beauty of
"anything" pushes. :tannedcirno:
So, after switching to graph mode, TH01 does… one of the slowest
possible memset()s over all of text RAM (one printf(" ") call for every
single one of its 80×25 half-width cells), before switching back to
kanji mode. What a waste of RE time…? Oh well, at least we've now got
plenty of documentation to prove to future port authors that these
weird escape sequences *actually* do nothing.
Completes P0140, funded by [Anonymous].
At least that's what we can infer from its position in the code.
Putting it into player shots for the sole reason that it's easier to
find it there.
Part of P0140, funded by [Anonymous].
Last one! Done with the SHARED segment for the forseeable future! 🎉
Sure, not the best C++ code either, but still by far the sanest
implementation of this function in any of the 4 games.
Completes P0139, funded by [Anonymous].
It's not a kaja_func_t if it's shifted left by 8 bits. Why is it
shifted left by 8 bits to begin with, though? Why not just pass a
kaja_func_t, and assign it to AH? Arrrrgh.
Part of P0139, funded by [Anonymous].
Hardcoding these *might* have been acceptable if the numbers actually
matched the sizes defined in GAME.BAT, but they don't. With PMD's
AH=22h function, there's really no excuse though.
About time I looked into this, and expressed that constant as an inline
function that can easily be replaced with a proper implementation.
Part of P0139, funded by [Anonymous].
Segment alignment issues once again… but that completes the SHARED
segments of all TH03 and TH05 binaries, for now!
Part of P0139, funded by [Anonymous].
I'll leave a comprehensive, fully documented enum to interested
contributors, since that would involve research into basically the
entire history of the PC-9800 series, and even the clearly out-of-scope
PC-88VA. After all, PC-98 Touhou only needs to distinguish "OPN- /
PC-9801-26K-compatible sound sources handled by PMD.COM" from
"everything else", since all other PMD varieties are OPNA- /
PC-9801-86-compatible.
Part of P0139, funded by [Anonymous].
4 games, 4 different versions of this function. Interestingly,
moving the game-specific differences to inline functions makes it
obvious that this function was only intended for BGM, not sound
effects.
Part of P0139, funded by [Anonymous].
TH04 is the only game that reserves memory for 8 .MPN slots, despite
only actually using just one of them, like all other games… And there
goes another 458 bytes of conventional RAM.
Part of P0138, funded by [Anonymous] and Blue Bolt.
We've been using the three-letter extension names for everything else
that isn't .DAT, so it's more consistent to do the same for .MPN,
however particularly nice and readable its FOURCC may be. 8.3 filenames
also really appreciate that they'll have to accommodate one fewer
letter.
Part of P0138, funded by [Anonymous] and Blue Bolt.
This gets rid of a couple of per-entity sprite bitplane types, makes
sprite declarations easier to read by putting width and height next to
each other… and points out a number of array dimension mistakes -.-
Even in places where we can't use it.
Part of P0138, funded by [Anonymous] and Blue Bolt.
Sure, we can't use them everywhere, but it's really nice to get rid of
that casting madness – and any explicit references to x86 memory
segmentation – wherever we can.
Part of P0138, funded by [Anonymous] and Blue Bolt.
Segment alignment forces us to do all of those at once… but now, we've
not only caught up with the segment split point in TH04's OP.EXE and
MAINE.EXE, but also decompiled all instances of DEFCONV functions!
Part of P0138, funded by [Anonymous] and Blue Bolt.
Boom! Clever segment renaming allows us to link the same .OBJ into 12
binaries.
(Well, 10 for now, due to alignment issues in TH04's OP.EXE and
MAINE.EXE.)
Part of P0138, funded by [Anonymous] and Blue Bolt.
So, we have a problem. The ridiculously optimized graph_putsa_fx() used
in TH04 and TH05 swaps out the target of two CALL instructions at
run-time… because there *really* wasn't any free register left for an
indirect CALL, eh? Therefore, the necessary relative addresses have to
be calculated at assembly time, by subtracting the target function
label from the call site label.
Unfortunately, the resulting values are stored in the .DATA segment,
which we can't move out right now. Declaring the labels as EXTERN
wouldn't work either, since the linker can't do fancy arithmetic and is
limited to simply replacing address placeholders with one single
address. This is explained pretty well at:
http://computer-programming-forum.com/46-asm/48f3d4a463bb38d1.htm
Which means we're stuck, and can't separate out this function for the
foreseeable future.
So, time to approach the SHARED segment from the top instead, to at
least get everything around graph_putsa_fx() done now. 🤷
vram_planes_set() is the first common function there. But since it was
introduced in TH01, we've got some maintenance to do for that game
first…
Part of P0138, funded by [Anonymous] and Blue Bolt.
Exhibit B for the theory that ZUN did *not* set the default calling
convention to `pascal` for TH03.
Part of P0138, funded by [Anonymous] and Blue Bolt.
Exhibit A for the theory that ZUN did *not* set the default calling
convention to `pascal` for TH03.
… Then again, at this point, it's way more likely that ZUN simply
didn't have a unified build setup for any of the games, and rather
pieced them together with manually compiled .OBJ files.
Part of P0137, funded by [Anonymous].
Second previously undecompilable translation unit, second creative
workaround for the workaround. We can't compile snd_se_play() with -WX,
as that function needs a stack frame, and it's also illegal to disable
-WX in the middle of a translation unit. But since we only need word
alignment in front of snd_se_reset() *and* that function is identical
in all 4 games, it makes sense to move it to its own translation unit.
And then you notice that the TH02/TH03 and TH04/TH05 versions of the
other two functions are basically identical. The small differences can
easily be moved out to inline functions, leaving us with a single
implementation file for all 4 games. Nice!
Part of P0137, funded by [Anonymous].
Now actually decompilable with the discovery of -WX… even though it
now requires additional workarounds for the drawbacks of the -WX
workaround.
Part of P0137, funded by [Anonymous].