Commit Graph

289 Commits

Author SHA1 Message Date
nmlgc d9bc75d28e [Decompilation] [th01] Boss entities: Position and movement clamp area setter
Yay, 7 parameters.

Part of P0108, funded by Yanga.
2020-08-12 18:02:18 +02:00
nmlgc 9ce0034934 [Decompilation] [th01] Boss entities: 16×8 section unblitting + blitting
Yet another unused function. No idea what it could have been intended
for – no boss sprite has animated sections that small.

But come on, out of all places that could have required the macro form
of a VRAM offset function, it had to be a unused one…

Anyway, that completes the low-level blitting functions for boss
entities!

Part of P0108, funded by Yanga.
2020-08-12 18:02:17 +02:00
nmlgc a2c4aadda9 [Decompilation] [th01] Boss entities: Broken wavy unblitting of two sprites
Another unused function! This might indicate that Elis could originally
split herself into two sprites, similar to TH04 Stage 6 Yuuka?
Or it might just have been some other kind of animation effect, who
knows.

Part of P0108, funded by Yanga.
2020-08-12 18:02:16 +02:00
nmlgc bc9b7cdfcd [Decompilation] [th01] Boss entities: Wavy blitting
Used for Elis' entrance animation. Including an unused unblitting +
blitting function – apparently, ZUN wrote that one before the sloppy
EGC-accelerated wavy unblitting function that I decompiled way back in
6d2fa9f.
Oh well, the latter one is fine in context, since there are no other
sprites on screen during the animation.

Part of P0108, funded by Yanga.
2020-08-12 18:01:33 +02:00
nmlgc 1650241f07 [Decompilation] [th01] Boss entities: Byte-aligned unblitting
A precise unblitting function, actually using the alpha plane of the
sprite… and it's unused.

Completes P0107, funded by Yanga.
2020-08-12 17:51:44 +02:00
nmlgc de688ddc20 [Decompilation] [th01] Boss entities: Byte-aligned unblitting + blitting
And we're back to not using functions, and needing our own VRAM access
macros…

Part of P0107, funded by Yanga.
2020-08-12 17:51:43 +02:00
nmlgc 96f3b1057c [Decompilation] [th01] Boss entities: Unaligned 1-line unblitting + blitting
… except that those single-plane functions provide basically no
useful abstraction in the context of a 4-plane image format. Should
have just gone all the way and directly take something like our
Planar<dots16_t> type to operate on all 4 planes, so that I wouldn't
have had to add that layer of abstraction myself.

Apparently, early ZUN was allergic to passing structures by reference?

Part of P0107, funded by Yanga.
2020-08-12 17:51:43 +02:00
nmlgc 816ba8342c [Decompilation] [th01] Background + foreground VRAM blit functions
Yes, functions! Those would have been nice earlier!
Also documented another overly specific Borland C++ code generation
quirk with regard to assigning expression results to elements of 16-bit
arrays…

Part of P0107, funded by Yanga.
2020-08-12 17:51:42 +02:00
nmlgc 34a5f4d183 [Decompilation] [th01] Boss entities: Unaligned 1-line blitting
"Oh wait, actually, I *do* want to blit 8 pixels at a time in some
cases" :zunpet:

First time in a long while that the VRAM access macros couldn't do the
job, because code generation wants *both* pointer arithmetic *and*
subscripts within the same expression.

But *come on*, just blit the 16 pixels for the byte-aligned case!

Part of P0107, funded by Yanga.
2020-08-12 17:51:42 +02:00
nmlgc 32c57c32e7 [Decompilation] [th01] Boss entities: Regular, byte-aligned blitting
That attempt at clipping the sprite at the left and right edges of
VRAM… is serviceable, I guess?

Part of P0107, funded by Yanga.
2020-08-12 17:51:42 +02:00
nmlgc 1f1829d2d8 [Decompilation] [th01] Boss entities: Copying .BOS metadata
So if the boss entity class stores all non-pixel metadata for its
associated .BOS file, how can YuugenMagan have 5 independent eye
sprites, or Kikuri have more than one soul and tear sprite?
By duplicating that data, of course!

Those structure copies to local variables seen in the load functions
of these bosses still remain pointless, though.

Completes P0106, funded by Yanga.
2020-08-12 17:51:40 +02:00
nmlgc 342e6450bc [Decompilation] [th01] Boss entities: .BOS load function
"Hm, I have this format that specifies sprite width in multiples of 8,
but *actually*, I'd like to blit 16 pixels at a time… well, time to
pepper the code with divisions and casts, I guess :zunpet:"

Which becomes even more hilarious once you realize that the `operator
new` function does require bytes after all. Which leads

	new dots16_t[image_size / 2];

to compile to

	operator new((image_size / 2) * 2);

:tannedcirno:

Part of P0106, funded by Yanga.
2020-08-12 17:49:35 +02:00
nmlgc 5f5eb8aa4e [Decompilation] [th01] .BOS: Unused and broken plane pointer reset function
Because that's not how you free dynamically allocated memory?

Part of P0106, funded by Yanga.
2020-08-12 17:49:34 +02:00
nmlgc 1a595cf60c [Reverse-engineering] [th01] Boss entity classes
What else to call something a boss can have multiple of, that may or
may not be part of a larger boss sprite, may or may not be animated,
and that may or may not have a orb hitbox?

Needed to be RE'd before the .BOS loading functions, because those are
actually methods of this class. And because renaming all these
variables in ASM land is tedious anyway, we might as well name each
individual entity of every boss.

Still, what's with the pointless local variable copies in the
YuugenMagan and Kikuri functions?

Part of P0106, funded by Yanga.
2020-08-12 17:49:34 +02:00
nmlgc 11b776b32e [Decompilation] [th01] 8×8 diamond, star, and snowflake sprite blitting
More hardcoded sprites! These are prominently seen in the Konngara,
Elis, and Sariel battles, respectively.

Completes P0105, funded by Yanga.
2020-08-12 16:24:04 +02:00
nmlgc 757f00e063 [Decompilation] [th01] Unaligned monochrome 8×8 sprite blitting
This is a perfectly fine generic sprite blitting function. Why doesn't
this game have more of these?

Part of P0105, funded by Yanga.
2020-08-12 16:21:28 +02:00
nmlgc 96e06fc746 [Decompilation] [th01] .GRC: Freeing images in a single slot
Part of P0105, funded by Yanga.
2020-08-12 16:20:54 +02:00
nmlgc 7ca525ba5c [Decompilation] [th01] .GRC: Byte-aligned blitting
And that's all? No unblitting or non-aligned functions? Oh well, at
least this one correctly clips the sprite at all 4 edges of VRAM, for
once.

Part of P0105, funded by Yanga.
2020-08-12 16:20:18 +02:00
nmlgc 72538610ba [Decompilation] [th01] .GRC: Load function
Still no idea what those 7 unknown bytes in the .GRC and .BOS headers
could be.

Part of P0105, funded by Yanga.
2020-08-12 16:19:39 +02:00
nmlgc b22bc80e98 [Reverse-engineering] [th01] .GRC: Slot structure
Part of P0105, funded by Yanga.
2020-08-12 16:17:58 +02:00
nmlgc bd1c2ee7de [Maintenance] #define the number of dots in a byte
One fewer magic number. And one more deliberate dependency on a
PC-98-specific hardware constant, to further drive home just how
unportable these games are, even once decompilation will be complete.

Part of P0105, funded by Yanga.
2020-08-12 16:16:58 +02:00
nmlgc 67d35115e6 [Maintenance] Use inline functions for all VRAM offset calculations
At least those can all be moved to a single place.

Part of P0105, funded by Yanga.
2020-08-12 16:16:18 +02:00
nmlgc a75e0f8f53 [Maintenance] Compile all VRAM-accessing translation units as C++
Leading to slight complications in TH02's Music Room and shot type
selection menus. Thought about leaving those in C for a while, but I
still think it's worth it for the consistency we get with the VRAM
offset functions. Also, we'll have similar code for the main menus of
later games, and I'll surely won't be using C++ when starting out with
these.

Part of P0105, funded by Yanga.
2020-08-12 16:16:09 +02:00
nmlgc 74b834fd7f [Maintenance] Use a distinct name for arc_file_get()'s sizeof() macro
We not only actually still need the (pointer, size) function to fill
heap-allocated memory, but we also need to differentiate between near
and far pointers, to move those pesky `PUSH DS` instructions to their
original places?!

Part of P0105, funded by Yanga.
2020-08-12 16:12:02 +02:00
nmlgc 3622eb6298 [Decompilation] [th01] HUD: Stage number rendering
Completes P0104, funded by Ember2528.
2020-07-27 17:23:06 +02:00
nmlgc 8367a41d46 [Maintenance] Decide on *_id for 0-based, and *_num for 1-based IDs
Which we've been already subconciously doing with the resident
`demo_num` variable.

Part of P0104, funded by Ember2528.
2020-07-27 17:22:28 +02:00
nmlgc afd74fb8aa [Decompilation] [th01] 16-bit integer to string conversion
"Hey, let's have separate functions for uint16_t and int16_t… and then
just *not* support negative numbers in the latter" :zunpet:

Part of P0104, funded by Ember2528.
2020-07-27 17:22:16 +02:00
nmlgc a0215ea85c [Decompilation] [th01] HUD: Life and bomb count rendering
If you've ever cheated more than 6 lives in TH01, you might have
noticed that those additional lives appear in additional rows in the
HUD. And well, that had to be coded somewhere…

Part of P0104, funded by Ember2528.
2020-07-27 17:20:29 +02:00
nmlgc e0bcdafb00 [Maintenance] [th01] Declare proper IDs for all .PTN sprites seen so far
Part of P0104, funded by Ember2528.
2020-07-27 17:19:48 +02:00
nmlgc f3093a802c [Decompilation] [th01] HUD: Inter-page row-sized rectangle blitting
Both inlined and non-inlined page switching within the same function,
together with an approach that doesn't correspond to our other planar
access macros? That code must have been written during a very
experimental phase very early in the development of this game.

Part of P0104, funded by Ember2528.
2020-07-27 17:19:12 +02:00
nmlgc edd9a14273 [Decompilation] [th01] HUD: Background (MASK.GRF) loading and rendering
Look, it's a memory leak!

Part of P0104, funded by Ember2528.
2020-07-27 17:17:59 +02:00
nmlgc 05c00287e9 [Decompilation] [th01] HUD: Initial score and card combo rendering
Hey look, this one *does* only render to a single page, and then blits
the area to the other one! Using an unnecessary new function that isn't
even EGC-accelerated…

Completes P0103, funded by Ember2528.
2020-07-27 17:17:22 +02:00
nmlgc b9038be04d [Decompilation] [th01] HUD: Current score and card combo rendering
Part of P0103, funded by Ember2528.
2020-07-27 17:13:35 +02:00
nmlgc b73762ba12 [Decompilation] [th01] HUD: Maximum card combo rendering
Nice and consistent…

Part of P0103, funded by Ember2528.
2020-07-27 17:12:21 +02:00
nmlgc f92c2a637c [Decompilation] [th01] HUD: High score update/render function
The scores are rendered to *both* VRAM pages…? Which means that we
need a separate set of sprites to store the background behind the
numbers. This does not bode well for animated backgrounds…

Part of P0103, funded by Ember2528.
2020-07-27 17:11:43 +02:00
nmlgc 57a2294f7a [Maintenance] Add a Planar<> template for any type of 4-plane value
Part of P0103, funded by Ember2528.
2020-07-27 17:10:00 +02:00
nmlgc 91ff008140 [Maintenance] Define the number of score digits in a consistent place
Even if that place is a one-line header file…?

Part of P0103, funded by Ember2528.
2020-07-27 17:09:07 +02:00
nmlgc b60f38d42d [Decompilation] [th01] Pellets: Delay cloud unblit/update/render function
And with that, we're actually *done* with TH01 pellets, and never have
to look at them again! 🎉

Completes P0102, funded by Yanga.
2020-07-12 16:45:53 +02:00
nmlgc dbc8da99d5 [Decompilation] [th01] Pellets: Player collision
How optimized is TH01? Well, since the player Y is constant, checking
for Y ≥ 368 first would rule out a collision for the majority of
entities during gameplay after just 1 check.

TH01 still checks X first.

Part of P0102, funded by Yanga.
2020-07-12 16:35:31 +02:00
nmlgc 5735c1622e [Decompilation] [th01] Pellets: Reset and decay functions
Or, in more relevant news: That's the function that forced TH01's
pellet sprites to be defined in C land. First sprite to make that jump.

Part of P0102, funded by Yanga.
2020-07-12 16:34:16 +02:00
nmlgc 63dafdb9c7 [Decompilation] [th01] Pellets: Unblit/update/render function
… pellet unblitting uses a *doubly* sloppy 16×8 rectangle. 🤦
The resulting terrible flickering is probably why the Stage 15 and 20
battles enable this weird "interlace" mode that only renders and
hit-tests half of the pellets each frame… except that player shots
are still hit-tested every frame?
So yeah, your eyes aren't deceiving you, the game does effectively drop
its perceived frame rate in the Elis, Kikuri, Sariel, and Konngara
fights, and it does so deliberately.

And *then* you realize that those weird hit tests are actually a
futile attempt to mitigate the disastrous effects of a way too large
unblitting rectangle. Congratulations, you've found the most stupid
piece of code in this game.

Part of P0102, funded by Yanga.
2020-07-12 16:29:51 +02:00
nmlgc d840841a2b [Naming] Rename egc_copy_rect_1_to_0() to emphasize its 16-dot alignment
ZUN might have gotten the impression that the EGC can *only* work with
multiples of 16 pixels per load or store? Which might explain why…

Part of P0102, funded by Yanga.
2020-07-12 16:27:56 +02:00
nmlgc edb70162e0 [Decompilation] [th01] Pellets: Manager class constructor
Note how Turbo C++ auto-generates that call to `operator new`, which
you don't see in the decompilation anymore. So yeah, as soon as you add
a constructor, Turbo C++ enforces heap allocation for any instance of
that class, even function-local ones that would otherwise be
stack-allocated.

That's where the bad reputation of C++ comes from, I guess?

Part of P0102, funded by Yanga.
2020-07-12 16:23:12 +02:00
nmlgc c11a95666b [Decompilation] [th01] Pellets: Shot/Orb/deflecting player collision
First off: 👏 Just 👏 pass 👏 a 👏 reference 👏 to 👏 the 👏
currently 👏 iterated 👏 pellet 👏 if 👏 you 👏 need 👏 to 👏
modify 👏 it 👏
Second: Don't we hit-test pellets vs. shots already, in the CShots
class? So what is this garbage…?!

Completes P0101, funded by Yanga and Ember2528.
2020-07-12 16:21:17 +02:00
nmlgc 8328905f46 [Decompilation] [th01] Pellets: Multi-pellet patterns
Actually quite cute with their hardcoded limitations, since the created
patterns do follow a clear logic.
But yeah, no 6-way spreads for you, we only support 2-, 3-, 4-, and
5-way ones here :zunpet:

Part of P0101, funded by Yanga and Ember2528.
2020-07-12 16:15:24 +02:00
nmlgc ceb81db49c [Decompilation] [th01] Pellets: Spawn functions
Completes P0100, funded by Yanga.
2020-07-12 16:14:01 +02:00
nmlgc 8f33b9717c [Decompilation] [th01] Pellets: Motion types
Look, an unused pellet motion type! Which doesn't work as intended
thanks to no fewer than 3 ZUN bugs in one single if() expression.

Part of P0100, funded by Yanga.
2020-07-12 16:13:33 +02:00
nmlgc 2fdaa35535 [Reverse-engineering] [th01] Pellets: Manager class
A 4227-byte structure, with 100 pellet_t instances followed by a few
other data members. A textbook example of why you can't just quickly
get full position independence by parsing individual lines of ASM.

Part of P0100, funded by Yanga.
2020-07-12 16:06:36 +02:00
nmlgc 1b25830786 [Reverse-engineering] [th01] Pellets: Single pellet structure
Completes P0099, funded by Ember2528.
2020-07-12 16:03:19 +02:00
nmlgc 2d0b4a5b06 [Maintenance] Add generic overlap test macros for collision detection
Part of P0099, funded by Ember2528.
2020-07-12 16:02:04 +02:00
nmlgc a207d6a494 [Decompilation] Add screen-space assignment overloads for Subpixels
Also great news for those people who want to remove any and all C++ in
their mods, because this forces us to spell out subpixel literals as
actual floats, every time. And with that, you're back to being able to
simply search-replace for all the instances you'll have to change.

Part of P0099, funded by Ember2528.
2020-07-12 16:00:59 +02:00
nmlgc f0baf27c04 [Reverse-engineering] [th01] REIIDEN.CFG variables in REIIDEN.EXE
Part of P0099, funded by Ember2528.
2020-07-12 16:00:09 +02:00
nmlgc e3a78bd19b [Maintenance] Fix vector creation function declarations and calls
Part of P0099, funded by Ember2528.
2020-07-12 15:22:50 +02:00
nmlgc 8f8940801d [Maintenance] Move the Subpixel class to TH01
At least pellets are moved at a decent precision in this game.

Part of P0099, funded by Ember2528.
2020-07-12 15:16:03 +02:00
nmlgc 3e3129567c [Decompilation] [th01] Pellet delay cloud blitting and unblitting
And immediately, we discover another two hardcoded sprites, with, of
course, another set of functions for blitting and unblitting them…

Part of P0099, funded by Ember2528.
2020-07-12 15:15:05 +02:00
nmlgc f612c40dce [Maintenance] Move generic VRAM macros from REIIDEN.EXE's PTN code to planar.h
C++ templates would be *so nice* here, but code generation… 😢

Part of P0099, funded by Ember2528.
2020-07-12 15:08:38 +02:00
nmlgc 1799d67782 [Build] Convert all known hardcoded sprites during the 32-bit build part
You can now mod them by simply editing .BMP files!
2020-07-09 22:28:15 +02:00
nmlgc f03f43db3a [Regression] Fix conditional branches in CShots::hittest_pellet()
1 wrong byte of ASM that slipped through due to a off-by-one error in
an experimental mzdiff branch. Having MOV rather than LES here was
ultimately a harmless mistake though. In context, it's even covered by
the "identical instruction encoding" exception 🙂
2020-06-25 17:37:39 +02:00
nmlgc ed4d7282a0 [Pipeline] Add .BMP versions of all hardcoded 1bpp sprites found so far
A future sprite converter (documented in #8) could then convert these
to C or ASM arrays.

(Except for the piano sprites for TH05's Music Room, which are stored
and used in such a compressed way that it defeats the purpose of
storing them as bitmaps.
2020-06-21 23:03:45 +02:00
nmlgc 43c97ccaa1 [Maintenance] Decide on __asm as the keyword for inline assembly
Which works in both Borland C++, Open Watcom, and Visual C++.

Not that we're about to port any of the games to these compilers, just
something I noticed while evaluating 32-bit compilers for ReC98's own
32-bit pipeline tools. Modders might want to look into that though,
since 100% position independence also makes it easier to change
compilers.
2020-06-21 22:18:00 +02:00
nmlgc 97dce75446 [Maintenance] Proofread all comments in C land 2020-06-21 22:14:08 +02:00
nmlgc f54e05492e [Maintenance] [th01] Rename z_col_at() to z_graph_readdot()
There actually is a master.lib function doing the same!
2020-06-21 22:13:47 +02:00
nmlgc ad067486ca [Decompilation] [th01] Player shots: Pellet and boss collision
*Still* sloppily unblitting. And that's why you end up shooting 1-frame
holes into bosses!

Completes P0098, funded by Yanga.
2020-06-13 21:15:32 +02:00
nmlgc 60805cea7c [Decompilation] [th01] Player shots: Unblit/update/render function
And that's exactly where TH01's sprite flickering comes from. You
aren't supposed to unblit all entities of one type immediately before
rendering them, since sprites of different entity types are free to
overlap each other. And you might have already blitted one of those
before!

Not to mention that ZUN *still* uses the sloppy unblitting method here.
🙄

Part of P0098, funded by Yanga.
2020-06-13 21:15:31 +02:00
nmlgc d158d186e2 [Decompilation] [th01] Player shots: Reset function
Why the sloppyness of unblitting a whole 16×16 rectangle *if you have
a dedicated function to precisely unblit a .PTN sprite using its alpha
mask*???
Oh well, it's not the regular function called in the main loop, so who
cares…?

Part of P0098, funded by Yanga.
2020-06-13 21:15:31 +02:00
nmlgc 442a92d32b [Decompilation] [th01] Player shots: Spawn function
Continuing to learn new things about Turbo C++'s code generation!

Part of P0098, funded by Yanga.
2020-06-13 21:15:31 +02:00
nmlgc 40b8325cc3 [Maintenance] [th01] Move MDRV2 files to a separate `snd/` directory
Consistency… even though we won't have more of those in this game.

Part of P0098, funded by Yanga.
2020-06-13 21:15:30 +02:00
nmlgc 9ef56ad5ca [Reverse-engineering] [th01] Player shot class
Part of P0098, funded by Yanga.
2020-06-13 21:15:29 +02:00
nmlgc 600f036c04 [Reverse-engineering] [th01] Portal-related orb flags and variables
Completes P0097, funded by Ember2528.
2020-06-13 21:15:29 +02:00
nmlgc 51de73bcc9 [Decompilation] [th01] Orb physics
"Physics". Not only did ZUN restrict the X velocity to the 5 discrete
states of -8, -4, 0, 4, and 8 (because hey, unaligned blitting is slow
anyway?), but gravity is also only applied every 5 frames.

We're still missing quite a bit of usage code, but these are the core
functions. One of which turned out to be undecompilable, due to… a
rigorously defined instruction order when performing arithmetic between
`double`s and `float`s?! Still, spelling out all this stuff in ASM
seems much better than somehow splitting the data segment, just so that
we can immediately use literals there.

Part of P0097, funded by Ember2528.
2020-06-13 21:15:27 +02:00
nmlgc f364dc0182 [Reverse-engineering] [th01] Orb position
… Wow, the orb is *actually* only ever displayed at byte-aligned X
coordinates, divisible by 8. It's only thanks to the constant spinning
that its movement appears at least *somewhat* smooth.

(And yeah, this is purely a rendering issue; internally, its position
*is* tracked at pixel precision.)

Part of P0097, funded by Ember2528.
2020-06-13 21:13:51 +02:00
nmlgc 8283c5eec8 [Decompilation] [th01] .PTN: Unaligned 16×16 blitting
But no corresponding unblitting function…?

Completes P0096, funded by Ember2528.
2020-06-13 21:13:50 +02:00
nmlgc 979f401515 [Maintenance] [th01] .PTN: Define the transparent color in a single place
Inlined template functions! \o/

Part of P0096, funded by Ember2528.
2020-06-13 21:13:50 +02:00
nmlgc 9cd54f1b13 [Decompilation] [th01] .PTN: Byte-aligned 16×16 blitting
Part of P0096, funded by Ember2528.
2020-06-13 21:13:49 +02:00
nmlgc f6c668dafc [Decompilation] [th01] .PTN: Byte-aligned 16×16 unblitting
Part of P0096, funded by Ember2528.
2020-06-13 21:13:49 +02:00
nmlgc 71970f57c6 [Decompilation] [th01] .PTN: Byte-aligned 32×32 blitting
Part of P0096, funded by Ember2528.
2020-06-13 21:13:49 +02:00
nmlgc a55c5ced81 [Decompilation] [th01] .PTN: Byte-aligned 32×32 unblitting
Part of P0096, funded by Ember2528.
2020-06-13 21:13:48 +02:00
nmlgc 6a5fa3aee9 [Maintenance] [th01] Decide on `unput` for VRAM page 1 pixel restoration
"Unblitting" reads better in commit descriptions, though 🤔

Part of P0096, funded by Ember2528.
2020-06-13 21:13:48 +02:00
nmlgc 52b8414993 [Reverse-engineering] [th01] Reimu's X position
13 copies of the clamping branches… Quality.

Part of P0096, funded by Ember2528.
2020-06-13 21:13:47 +02:00
nmlgc dd89843fae [Decompilation] [th01] Pellet rendering
So even TH01 wasn't 100% C++ after all. Turns out that this function
was the only instance in all of REIIDEN.EXE where ReC98 previously had
different encodings for identical x86 instructions.

Part of P0096, funded by Ember2528.
2020-06-13 21:11:53 +02:00
nmlgc 94dc9ef251 [Maintenance] Move the pellet sprite to TH01
That's where it actually originated.

Part of P0096, funded by Ember2528.
2020-06-12 21:49:16 +02:00
nmlgc 8ddb77801d [Decompilation] [th01] GDC-powered graphics layer scrolling
Surprise, it's the (terribly suboptimal) setgsta() example function
from the PC-9801 Programmers' Bible! 100% identical, so ZUN must have
read that book as well.
Used for screen shaking effects, as well as the scrolling backgrounds
at the start of the Final Boss stages.

Completes P0095, funded by Yanga.
2020-05-31 17:46:46 +02:00
nmlgc 416aa4ccef [Reverse-engineering] [th01] .BOS bitplane pointers
No idea why ZUN split the 6 slots into 4 with a regular alpha plane,
and 2 with a negated alpha plane. The latter are only used for Sariel's
animations.

Part of P0095, funded by Yanga.
2020-05-31 17:31:07 +02:00
nmlgc 55b3cb0330 [Decompilation] [th01] Main menu: White line animation
> "Sure, this is a PI push, but this second-to-last set of PI false
  positives so small, let's immediately decompile it ^.^"
> Time taken: 22 minutes
Nice when this works out!

Part of P0095, funded by Yanga.
2020-05-31 17:27:37 +02:00
nmlgc 57a8487084 [Decompilation] [th01] FUUIN.EXE resident structure data retrieval
Completes P0094, funded by Yanga.
2020-05-25 15:22:53 +02:00
nmlgc 026fff63a5 [Decompilation] [th01] Ending picture loading and display
Aww, how far we've come with inlining and helpful macros.

Part of P0094, funded by Yanga.
2020-05-25 15:18:44 +02:00
nmlgc a7230ba26a [Maintenance] Move the EGC copy setup function to a separate file
Too bad we still have to bother with renaming the function via #define
in the few cases where an executable contains two or more copies of
this function. We can't just make it `static`, since TH02 MAINE.EXE
actually does far-call it from a different segment (and thus,
translation unit).

Part of P0094, funded by Yanga.
2020-05-25 15:17:41 +02:00
nmlgc 5c77db08ca [Decompilation] [th01] High score registration
Completing the high score menu with a final stupid set of
inconsistencies between REIIDEN.EXE and FUUIN.EXE. Oh well.

Part of P0094, funded by Yanga.
2020-05-25 15:16:40 +02:00
nmlgc 753e1b670a [Decompilation] Change graph_move_byterect_interpage() page parameters to int
Turbo C++ doesn't do the 32-bit PUSH LARGE optimization for 8-bit
parameters?

Part of P0094, funded by Yanga.
2020-05-25 15:15:41 +02:00
nmlgc 3bd824b5be [Maintenance] [th01] Add a header for the slow 2× rectangle scale function
Part of P0094, funded by Yanga.
2020-05-25 15:14:19 +02:00
nmlgc 0e73029276 [Decompilation] [th01] High score menu: Name entering loop
The REIIDEN.EXE version (which is only shown when game-overing) has a
completely invisible timeout that force-enters a high score name after
1000... *keyboard inputs*? Not frames? Why. Like, how do even you
realistically to such a number.
(Best guess: It's a hidden easter egg to amuse players who place
drinking glasses on cursor keys. Or beer bottles.)

And hey, that initialization of the name variable with ASCII spaces.
The only actually meaningful byte-wise access… except that it's not,
because ZUN could have just used the Shift-JIS ideographic space for
the exact same effect.

Completes P0093, funded by Ember2528.
2020-05-25 15:11:12 +02:00
nmlgc bbef9b0bdb [Decompilation] [th01] REYHI*.DAT saving
Now with POSIX file I/O in both executables. And the confirmation that
the name array is indeed exclusively accessed per-byte.

Part of P0093, funded by Ember2528.
2020-05-25 15:10:07 +02:00
nmlgc 6e0c33a8bf [Decompilation] [th01] High score menu: Input handling
It's exactly as terrible as you would have expected after hearing
"alphabet cursor actually stored as on-screen position". Nothing gained
in reducing redundancy any further here, any meaningful change would
pretty much have to rewrite the entire thing.

Part of P0093, funded by Ember2528.
2020-05-25 15:07:59 +02:00
nmlgc 440330857a [Decompilation] [th01] High score menu: Shot key handling
In which inline functions are apparently the only way to trick Turbo
C++ into not actually optimizing away the useless `AND AL, 0FFh`.

But come on. Just accessing the high score name characters in chunks of
16-bit Shift-JIS codepoints (which is what they are!) instead of
breaking them down to bytes *everywhere* would have been both more
readable (no swapping of Shift-JIS literals, no bitshifts), more
efficient (this isn't running on an 8-bit CPU after all), and less of a
waste of my time…

Completes P0092, funded by Yanga.
2020-05-25 15:06:48 +02:00
nmlgc 7a1332e1f5 [Decompilation] [th01] High score menu: Re-rendering individual characters
Lol, the internal alphabet cursor position is actually stored as the
on-screen top-left position of the selected character, which this
function then maps back to a character index. At least that gets rid of
quite a bunch of PI false positives now.

Part of P0092, funded by Yanga.
2020-05-25 15:05:43 +02:00
nmlgc 57be510056 [Decompilation] [th01] High score menu: Initial table rendering
With ternary operator expressions straight out of Jigoku.
(TL note: Jigoku means hell.)
Nice to see that Turbo C++ apparently has no nesting limit on function
call inlining in general, though!

Part of P0092, funded by Yanga.
2020-05-25 15:03:55 +02:00
nmlgc 8473dc2048 [Maintenance] [th01] Rethink high score menu constants
The one thing where I didn't think ahead…

Part of P0092, funded by Yanga.
2020-05-25 14:59:23 +02:00
nmlgc 16ac6b4206 [Decompilation] [th01] High score menu: Initial alphabet rendering
Completes P0091, funded by Ember2528.
2020-05-12 15:06:12 +02:00
nmlgc 4f87ec8152 [Decompilation] [th01] Blitting full-width numbers onto VRAM
Part of P0091, funded by Ember2528.
2020-05-12 15:06:12 +02:00
nmlgc 651d09f5bd [Decompilation] [th01] Keyboard input in FUUIN.EXE
The only TH01 executable not supporting the numpad?

And that's the point where you just rewrite the distinct input_prev_*
values as a single array, because they're local to input_sense()
anyway.

Part of P0091, funded by Ember2528.
2020-05-12 15:06:11 +02:00
nmlgc f2543c8336 [Decompilation] [th01] Keyboard input in REIIDEN.EXE
Yes, TH01's memory info screen will recurse into itself for every 3
frames the PgUp key is held, requiring one additional PgDown press per
recursion to actually get out of it.
You can, of course, also crash the system via a stack overflow this
way, if that's your thing.

Part of P0091, funded by Ember2528.
2020-05-12 15:06:11 +02:00
nmlgc 07dab293ad [Decompilation] [th01] Input declarations shared between REIIDEN and FUUIN
Of which we can express precisely *nothing* as an inline function,
because Turbo C++ always emits a useless `JMP SHORT $+2` at the end of
such an inlined function if it contains nested `if` statements. This is
also what forced some of the functions in 90252cc to be expressed as
macros. By now, this is clear enough to be documented separately.

And to warrant this separate commit.

Completes P0090, funded by Yanga.
2020-05-12 15:05:49 +02:00
nmlgc 389b9a1056 [Decompilation] [th01] Keyboard input in OP.EXE
Starting with the odd one out, the one that doesn't use master.lib and
has two input sense functions: one for the main menu, and one for the
option window.

Both of which also immediately perform the ring arithmetic on the menu
cursor variable… because there's nothing else to be done with these
inputs in OP.EXE? Separating input sensing from processing apparently
wasn't all too obvious of a thought, and it's only truly done in TH02
and later.

Part of P0090, funded by Yanga.
2020-05-12 14:55:09 +02:00
nmlgc 7ad14db394 [Decompilation] [th01] REIIDEN.CFG loading and saving
That's where the backwards `goto` for .CFG file error handling
originated!

Part of P0090, funded by Yanga.
2020-05-12 14:36:43 +02:00
nmlgc 05a0e9b1c8 [Decompilation] [th01] Unused function to snap all dots with hardware color #4
That's… pretty specific. The only thing on the main menu with this
color is the "1996 ZUN" text at the bottom… probably part of an
effect that we never got to see. Every other idea would be baseless
speculation, given that the snapped buffer isn't used anywhere else.

Part of P0090, funded by Yanga.
2020-05-11 22:12:51 +02:00
nmlgc 97ce7b78cd [Maintenance] Consistently use forward slashes in #include paths
Completes P0087, funded by -Tom-.
2020-04-15 21:34:32 +02:00
nmlgc d1f3dcd620 [Maintenance] Move all features exclusive to MAIN.EXE to a main/ subdirectory
Adding op/, main/, and end/ directories does nicely cover a great
majority of the "not really further classifiable slices" implied in
d56bd45.

Part of P0086, funded by [Anonymous] and Blue Bolt.
2020-04-15 20:58:01 +02:00
nmlgc 02f0a0afcc [Build] Don't word-align everything by default
Again, 11 necessary workarounds, vs. forcing byte aligment in at least
18 places, and that number would have significantly grown in the
future.

Part of P0085, funded by -Tom-.
2020-04-03 17:35:57 +02:00
nmlgc ffad8cc897 [Build] Use the minimum possible size for enums by default
5 enums where code generation wants an `int`, vs. 11 cases where using
the minimum size is exactly the right default. So it's way more
idiomatic to force those 5 to 16 bits via a dummy element… except that
we can't give it a single, consistent name, because you can't redeclare
the same element in a different enum later.

Oh well, let's have this ugly naming convention instead, which makes it
totally clear that the force element not, in fact, a valid value of
that enum.

Part of P0085, funded by -Tom-.
2020-04-03 17:33:58 +02:00
nmlgc c338305a61 [Decompilation] REYHI*.DAT loading and recreation
With master.lib file I/O in REIIDEN.EXE, and POSIX file I/O in
FUUIN.EXE… yup.

Part of P0084, funded by Yanga.
2020-03-22 10:16:08 +01:00
nmlgc ee9168b7eb [Reverse-engineering] [th01] REYHI*.DAT structure
Part of P0084, funded by Yanga.
2020-03-22 10:01:16 +01:00
nmlgc 1cc9cefa26 [Decompilation] [th01] PTN-sized page 0→1 copies
Final shared function in TH01's OP.EXE.

Part of P0084, funded by Yanga.
2020-03-22 09:59:24 +01:00
nmlgc dfac2f2fd4 [Position independence] [th01] EGC-powered page 1→0 region copy calls
12.4 fixed-point subpixels, in TH01?

Completes P0083, funded by Yanga.
2020-03-18 20:33:59 +01:00
nmlgc 9e676ce3ef [Decompilation] [th01] .PTN snap functions
Which repurpose the .PTN image slots to store the background of
frequently updated VRAM sections, like all the numbers in the HUD.
Future games would simply use the text RAM and gaiji for numbers. Which
would have worked just fine for TH01 as well (especially since all the
functions we've seen so far are aligned to the 8-pixel byte grid), but
it looks as if ZUN simply wasn't aware of gaiji during the development
of TH01.

Part of P0083, funded by Yanga.
2020-03-18 20:33:58 +01:00
nmlgc a184413f27 [Decompilation] [th01] .PTN file loading and non-transparent display
What is this, error checking in a ZUN game?! And surprisingly good code
for deriving the alpha plane?!

Part of P0083, funded by Yanga.
2020-03-18 20:33:58 +01:00
nmlgc d79f4c1171 [Maintenance] [th01] Correctly declare the packfile functions in C land
Mangled C++ function names would *not* have been a mistake if I hadn't
made the other mistake of restricting parts of the code to C…

Part of P0083, funded by Yanga.
2020-03-18 20:33:53 +01:00
nmlgc df6b636053 [Decompilation] Add an inline function for VRAM offset calculation
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.
2020-03-18 20:11:18 +01:00
nmlgc 2546c5dfcb [Reverse-engineering] [th01] .PTN slot structure
Part of P0083, funded by Yanga.
2020-03-18 20:09:57 +01:00
nmlgc f6cbff0bf9 [Decompilation] [th01] .GRP file loading and display
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.
2020-03-13 19:48:38 +01:00
nmlgc 70176537e6 [Maintenance] Add include guards to ReC98.h
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.
2020-03-13 19:16:02 +01:00
nmlgc 76634342f1 [Reverse-engineering] [th01] Global .GRP and .PTN variables
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.
2020-03-13 19:14:45 +01:00
nmlgc 8adbeb76b6 [Decompilation] [th01] .GRP palette fades
It's optimization barrier time again \o/

Part of P0082, funded by Ember2528.
2020-03-13 19:14:32 +01:00
nmlgc 63ed22ba67 [Reverse-engineering] [th01] .GRP palette
Part of P0082, funded by Ember2528.
2020-03-13 19:09:24 +01:00
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 74269c3834 [Reverse-engineering] [th01] FUUIN.EXE frame delay
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.
2020-03-13 19:06:21 +01:00
nmlgc ac0cbb6dc9 [Reverse-engineering] [th01] Identify the end of grx_header_t as a palette
Unfortunately, none of the images in BOSS8.GRZ actually set it to their
intended palette, which means we…

Part of P0081, funded by Ember2528.
2020-03-07 21:43:07 +01:00
nmlgc fd6a8bae81 [Decompilation] [th01] .GRZ file loading and display
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.
2020-03-07 21:43:00 +01:00
nmlgc 54e5bf39fc [Maintenance] Use `dots` for 1bpp lines, and `planar` for B/R/G/E dot structs
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.
2020-03-07 21:19:25 +01:00
nmlgc 0252da2a71 [Decompilation] [th01] Game init and exit functions
Yes, that's the code that forgot reactivating the text cursor before
returning to the DOS prompt!

Completes P0080, funded by Ember2528 and Splashman.
2020-03-03 13:12:00 +01:00
nmlgc f56725f3d0 [Maintenance] [th01] Move ztext.c to the hardware/ directory
And fix a typo from 2015 that hasn't actually mattered yet.

Part of P0080, funded by Ember2528 and Splashman.
2020-03-03 13:08:33 +01:00
nmlgc de3f9ec31b [Decompilation] [th01] Graphics BIOS initialization and activation functions
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.
2020-03-03 13:07:55 +01:00
nmlgc ee682ce2e1 [Decompilation] [th01] Page flipping
No macros here either.

Part of P0080, funded by Ember2528 and Splashman.
2020-03-03 13:07:29 +01:00
nmlgc 14f9bc3bbe [Decompilation] [th01] Basic hardware palette and GRCG functions
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.
2020-03-03 13:06:34 +01:00
nmlgc 0e852feee8 [Decompilation] [th01] Whole-page color fills and copies
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.
2020-03-03 13:05:49 +01:00
nmlgc 7d77338e29 [Decompilation] [th01] Palette fades from and to white and black
Nice lambda functions.

Part of P0080, funded by Ember2528 and Splashman.
2020-03-03 13:04:49 +01:00
nmlgc 3229b2285d [Decompilation] Encode the per-component range in the RGB color template
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.
2020-03-03 13:02:30 +01:00
nmlgc f2b454dfc6 [Decompilation] Overload operator[] for palettes
Which has no run-time cost in almost all cases.

Part of P0080, funded by Ember2528 and Splashman.
2020-03-03 13:01:27 +01:00
nmlgc f99d7a571c [Maintenance] Remove all dependencies on Borland C++ run-time source headers
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-.
2020-02-23 17:53:18 +01:00
nmlgc 0f18dbc4bd [Decompilation] [th01] Single-point drawing and retrieval
In which our typedefs mercilessly reveal ZUN's original sloppiness, and
the unncessary sign extension taking place here. Also,  unused…

Completes P0069, funded by [Anonymous] and Yanga.
2020-01-14 22:12:18 +01:00
nmlgc b0c832bdee [Decompilation] [th01] Restorable line drawing
Yes, when clipping the start and end points to the screen area, ZUN
uses an integer division to calculate the line slopes, rather than a
floating-point one. Doesn't seem like it actually causes any incorrect
lines to be drawn, though; that case is only hit in the Mima boss
fight, which draws a few lines with a bottom coordinate of 400 rather
than 399. It *might* also restore the wrong pixels at parts of the
YuugenMagan fight, causing weird flickering, but seriously, that's an
issue everywhere you look in this game.

Part of P0069, funded by [Anonymous] and Yanga.
2020-01-14 22:12:08 +01:00
nmlgc b5cef6eb69 [Maintenance] Define VRAM access macros for arbitrary bit counts
Templates would have been nicer, but as soon as you add just one
non-immediate parameter, Turbo C++ generates a useless store to a new
local variable, ruining the generated code.

Part of P0069, funded by [Anonymous] and Yanga.
2020-01-14 22:09:51 +01:00
wintiger0222 4d13d7f7e9 [Decompilation] [th01] graph_printf_fx 2020-01-14 22:08:44 +01:00
nmlgc 2ac00d47bf [Decompilation] [th01] Box and rectangle drawing
Completes P0068, funded by Yanga.
2020-01-14 22:06:58 +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 4340b5d6ae [Maintenance] [th01/th02] Split graph_putsa_fx() into its shared parts
I did consider not doing this, because "well, can't anyone who's
*actually* interested just diff the TH01 and TH02 implementations to
figure out the differences themselves", but that duplication ended up
feeling too filthy after all.

And hey, it's a nice excuse to update TH02's version to current naming
standards! 😛

Part of P0068, funded by Yanga.
2020-01-14 22:03:00 +01:00
nmlgc ebb30ce170 [Reverse-engineering] [th01] Restorable line and box drawing
Including the longest function present in more than one game among all
of PC-98 Touhou, and #23 on the list of longest functions overall,
which draws a 1-pixel line between two arbitrary pixels.

Completes P0067, funded by Splashman.
2020-01-14 21:53:00 +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 f87b0d4f9e [Maintenance] [th01] Don't #define away master.lib's graph_accesspage() macro
We will in fact have to use both the function call and the macro
version, even within the same translation unit.

Part of P0067, funded by Splashman.
2020-01-14 21:49:38 +01:00
nmlgc 6222b78514 [Reverse-engineering] [th01] Current back page
Previously sloppily mis-RE'd as "some page variable, idk", back in
2015…
Now also with a page number typedef. And yeah, restricting bool to C++
has now proven to be stupid after all.

Part of P0067, funded by Splashman.
2020-01-14 21:48:40 +01:00
nmlgc 22ebc48eea [Decompilation] [th01] Blocking palette fade-ins from a custom start color
 Unused…

Part of P0067, funded by Splashman.
2020-01-14 21:47:17 +01:00