Lol @ Konngara decompilation being blocked by this giant card-flipping
function that took 2 pushes to understand, only for it to start with
if((stage % 5) == 4) {
return;
}
…
Completes P0129, funded by Yanga.
This is where the code generation actually confirms the SoA layout of
the global obstacle structure, rather than it being distinct pointers.
Part of P0129, funded by Yanga.
Continuing the good error handling from the .PTN functions they're
based on… if only its sole caller actually cared.
Also: A sort-of limit of 102 objects per stage, just because someone
didn't use huge pointers where they would have been necessary…
:tannedcirno:
Part of P0128, funded by Yanga.
Case in point: This structure member, which is located after all the
obstacle members. Sure, it'll look weird to see this one initialized by
a class method, but it'll be much weirder to somehow group both cards
and obstacles into one class.
Part of P0128, funded by Yanga.
And another one for all the obstacle types we saw earlier. The original
game probably combined all SoA pointers for both cards and obstacles
into a single "stage object". But that'll get way too unwieldy in the
functions later, given that those aren't even methods, and simply
reference one global variable. `stageobjs.obstacles.member`… yeah, no.
Part of P0128, funded by Yanga.
Sure, a SoA layout might actually be genius and what you should be
doing most of the time on modern systems, but you still wouldn't
allocate every member separately.
Part of P0128, funded by Yanga.
An enum to distinguish between bumpers, turrets, portals, bumper bars…
and cards that have to be flipped more than once?!
Part of P0128, funded by Yanga.
Finishing this push with another highly questionable one… Let's hope
that the port developers will certainly appreciate that they just have
to remove the weirdness here, and not mess with defining entirely new
functions in C land.
Completes P0127, funded by [Anonymous].
Undecompilable again. The loading functions have these *_noalpha()
variants that simply set a global variable and fall through to the
regular functions, while cdg_free() has its first `PUSH DI` instruction
after the first expression we'd be decompiling. cdg_free_all() *could*
be decompiled… but would also require _FLAGS trickery, and it's simply
not worth starting a translation unit for one such small function.
Part of P0127, funded by [Anonymous].
Nooooo, gotta throw away that decompilation for the stupidest of
reasons :( Turns out that a function may also be "undecompilable" if
the original code layout places it at a word-aligned address, but the
last byte of the previous function in just one of the original binaries
(TH03's MAIN.EXE, in this case) also lies at a word-aligned address.
There's simply no way to enforce per-function word alignment in Turbo
C++ alone. You *could* fake it with `#pragma codestring`, but of course
that won't work for functions that are part of the SHARED segment, and
where the alignment previously would have been correct. Conditionally
emitting that codestring would work, but then we'd also have to compile
that translation unit at least twice.
Now, I could have created a dummy .ASM file that just contains a single
zero-length but word-aligned SHARED segment, which could be placed
anywhere on the link command line where word alignment is needed… but
the decompilation of this function was a mess anyway, and probably
helped nobody.
Part of P0127, funded by [Anonymous].
And since inlining even removes longer if-else chains if they branch
depending on a literal constant, we can use a regular parameter to
select either MOV or OR in our _FS and _GS poke() template functions,
without needing to duplicate them!
Part of P0127, funded by [Anonymous].
Containing not one, but two decompilation innovations, one of which
works around a compiler bug using C++ template functions…
Completes P0126, funded by [Anonymous] and Blue Bolt.
Another function consisting almost entirely of inline ASM. Still worth
it though, if only to save us from duplicating any declarations in ASM
land.
Part of P0126, funded by [Anonymous] and Blue Bolt.
Actually fairly average, as far as unreasonable decompilations are
concerned. No `goto`, at least! Another place that would benefit from
EGC raster op documentation, though.
Also, got one more padding byte in TH05's MAINE.EXE correct. 🙂
Part of P0126, funded by [Anonymous] and Blue Bolt.
With a type-safe wrapper template that removes the need for ID length
and structure-size-in-paragraphs macros. *And* <dos.h>!
Part of P0126, funded by [Anonymous] and Blue Bolt.
Rather than preferring either the Microsoft/Watcom `(in|out)pw?` style,
or the Borland `(in|out)portb?` style, master.lib had to introduce its
own `(OUT|IN)P[BW]` naming scheme… Insert obligatory xkcd standards
comic.
Part of P0126, funded by [Anonymous] and Blue Bolt.
Which gets rid of 13 redundant translation units. Definitely a good
start, before I figure out how to best handle the more complicated
cases.
(Maintenance mode commit)
Not really surprising why this works, and probably was how the original
code looked all along: The function is never called from anywhere, and
as long as the next function still lies on the same 16-byte paragraph,
it makes no difference whether the unused one is placed at the end of
the previous segment, or the beginning of the next.
Which means we can choose whatever leads to fewer translation units 👍
(Maintenance mode commit)
There's the better name, in ALLCAPS for improved grepping. TH01 is also
going to need a pseudo-binary to bundle translation units that appear
in more than one .EXE, and since "segment 2" would be wrong for that
game, it makes more sense to have one consistent name for these
pseudo-binaries in all games.
(Maintenance mode commit)
Yup, no trick there. If the selection moves to the other character, the
original background behind the raised top and left edges has to be
blitted back to VRAM, which means that it also has to be stored
somewhere. TH04 backs up exactly the two 256×8 and 8×244 strips behind
Reimu and Marisa, requiring 2 KB of heap memory, whereas TH05 simply
gave up, and backs up the entire 640×400 screen, totalling 128 KB.
Part of P0125, funded by [Anonymous].
And get rid of the constraining FX() macro, with its spacing parameter
that we haven't even seen used so far.
Part of P0124, funded by [Anonymous] and Blue Bolt.
The change of pi_free() from a macro to a function in TH05 doesn't
require a complete redefinition.
Part of P0124, funded by [Anonymous] and Blue Bolt.
6149 LoC with the original master.h, vs. 2524 LoC *and* additional
semantic sugar with master.hpp. Nice!
(Yes, *semantic* sugar.)
Part of P0124, funded by [Anonymous] and Blue Bolt.