Since I'd still prefer to not use include guards *and* to have that
standalone .GRZ viewer, these would have actually caused somewhat of
an issue with the upcoming final stretch of the master.hpp transition.
Part of P0133, funded by [Anonymous].
Might seem inconsistent, given that the function initializes pointers
that are declared in planar.h… but it's always called from other game
initialization functions that don't require pc98.h or planar.h.
Part of P0133, funded by [Anonymous].
Functions with 12 parameters are hard to describe, y'know. Looking
forward to decompiling these giant expressions for the actual
boss↔orb collision parameter passed to this function…
Oh well, at least we're now totally ready for some boss code next
year. 😌
Completes P0131, funded by Yanga.
Yes, no "generator", just a single number. Used to add some very
minimal randomness to certain things, by taking it modulo a small
number.
Part of P0131, funded by Yanga.
And once again, SinGyoku is the only boss to get its own variable.
Maybe this means that it was the first boss to be implemented after
all?
Part of P0131, funded by Yanga.
And we're right back to things not being nice. Because yeah, why
shouldn't these three distinct rendering functions be part of a single
function, selected by magic numbers?
Or why shouldn't the 16×16 wrapper around a 32×32 set of graphics
functions be used to handle backgrounds for 16×8 sprites, resulting in
needlessly complex parameter calculations that lead to sloppy code?
Part of P0131, funded by Yanga.
Nice GRCG use! The 8 dots of its tile register, which are commonly just
set to the same color value, can of course hold an arbitrary bit
pattern for every bitplane. This allows you to get different colors for
every pixel, with still just a single VRAM write of the alpha mask to
one bitplane.
And I thought TH01 only suffered the drawbacks of PC-98 hardware, and
made so little use of its actual features that it's perhaps not even
fair to call it "a PC-98 game"…
Completes P0130, funded by Yanga.
Made truly generic by its use in both the upcoming boss collision
handling, as well as some SinGyoku pellet spawning function.
Part of P0130, funded by Yanga.
And with that, TH01 is pushed over the 50% completion mark! 🎉
This time, it's only YuugenMagan who gets no own copy. Giant RE% gains
from all these calls, but let's hope I don't regret already decompiling
this one for all bosses. It's not quite at the beginning of SinGyoku's,
Mima's, and Elis' code segment, after all…
Part of P0130, funded by Yanga.
The placement at the beginning of Kikuri's code segment makes you think
this is only used for the barely noticeable white-in effect during
Kikuri's entrance animation. It's also used to periodically reset boss
sprite colors during the flashing effect after getting hit by the Orb,
though.
Part of P0130, funded by Yanga.
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.
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)
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.
And no longer force translation units that access the resident
structure into #including that mistake that was ReC98.h.
Part of P0124, funded by [Anonymous] and Blue Bolt.
*Still* no need for the classic `if(ptr) { delete[] ptr; ptr = NULL }`
macro, because who cares about dangling pointers anyway, right?
:zunpet:
Part of P0123, funded by Yanga.
All this CPU time spent optimizing the unblitting mask, yet the code
still ends up glitching if the two sprites are more than 2 horizontal
bytes away. So, Reimu's slide speed can only be as high as 8 pixels per
frame, before this function fails to unblit the previous sprite and
leaves little Reimu parts in VRAM.
Part of P0123, funded by Yanga.
"Let's add a row to the offset, and then subtract it again" :zunpet:
This could only *possibly* have been intended as a DoS attack against a
future manual decompilation, right?
Part of P0123, funded by Yanga.