If we double down on this concept by defining all needed prefix and R/M
opcodes, the code turns out much simpler if we __emit__() even the
basic, non-broken case. And if the inlined functions directly take
the opcode bytes as parameters, we don't even need templates.
Completes P0227, funded by nrook.
9th PC-98 Touhou boss almost completely decompiled, 22 to go!
I definitely did not miss the convoluted control flow of the TH05 ones.
Part of P0227, funded by nrook.
The one where Sara spawns a symmetric laser pair to wall the player
into a 0x14° corridor while firing dense spread pellets and random blue
balls every 16 seconds.
Part of P0227, funded by nrook.
Easier to get the bit shifts right if you focus on them in a separate
helper function that is decoupled from any semantics – and Sara is
about to add two more variants of these setters. By interleaving the
per-difficulty count/delta values instead of listing them separately,
it also turns out that I originally mixed them up in Shinki's 4th
pattern. Reads much better now.
Part of P0227, funded by nrook.
Biggest decompilation breakthrough of the year already? Completely
removes the need for the "set near pointer to far function" hack, and
solves quite a few upcoming issues.
The TASM manuals did have a few pages on the topic of segments and
groups, but there's absolutely nothing about it in the TCC ones beyond
the three-sentence description of `#pragma codeseg` and that completely
unhelpful "🤷" of an explanation for the `Fixup overflow` error…
Part of P0227, funded by nrook.
As implied in adffa1c, a single segment-switching translation unit for
both rendering functions and game logic is the most straightforward
solution for those two games. Especially once you look at TH04, and
realize that the wildly chaotic order of the *_fg_render() functions in
the first code segment exactly matches the order of the *_update()
functions in the third.
Part of P0225, funded by Enderwolf, Blue Bolt, 32th System, and Yanga.
It's easy to blame ASM micro-optimizations for bugs like these, but the
original C++ version from TH01 was equally bugged for FX_WEIGHT_BLACK.
Part of P0225, funded by Enderwolf, Blue Bolt, 32th System, and Yanga.
Even that part's the same in these three games… except for the 27 small
places where it isn't, 7 of which are purely coding style cosmetics.
Completes P0224, funded by Splashman and -Tom-.
With the script parsing and picture/box rendering functions being as
interleaved as they are, it makes little sense to keep the cutscene
code in more than one translation unit. How would those translation
units even be called? This time, having everything in one file should
beat the few hundred preprocessor-removed lines of code that we end up
adding to each one of the three affected games – and ultimately, you'd
want to merge those systems into one translation unit anyway.
Part of P0224, funded by Splashman and -Tom-.
That only leaves the TH02 versions of this function that really should
have been defined at one central location.
Part of P0223, funded by Blue Bolt and rosenrose.
Here's an entire commit to point out why the difference between these
function names matters and shouldn't be #define'd away in some central
input header file.
Part of P0223, funded by Blue Bolt and rosenrose.
You can fast-forward through cutscenes by holding Escape in these
games?! And the script interpreter adds automatic line breaks?!
Part of P0223, funded by Blue Bolt and rosenrose.
Thanks to TH03 having text-below-picture cutscenes before stages 8 and
9, the `/end/` directory is the wrong place to keep this code. And as
we're soon going to see, this feature did evolve during these three
games.
Part of P0223, funded by Blue Bolt and rosenrose.
The later games need this constant for their buffers as well, and it's
not just needed for loading sound files. Might be overkill to force all
of `master.hpp` to be #included in some additional places, but the
alternative would have been to move it to a `fn_len.hpp` file.
Ultimately, this constant *is* related to master.lib.
Part of P0223, funded by Blue Bolt and rosenrose.
These are more generally useful for general text width calculations
that don't necessarily involve TRAM.
Part of P0223, funded by Blue Bolt and rosenrose.
• Comments that describe all lines of code until a blank one are placed
into the lines immediately above
• Comments that describe an entire demarcated block are placed
immediately below the dash row at the top
• In any case, there should be a blank line after the top comment of
a demarcated block, to keep IntelliSense-style systems from applying
the block comment to the first actual line of code…
• …but there shouldn't be one before the dash row at the bottom, where
it'd be redundant.
Part of P0207, funded by GhostPhanom.
Let's see if anyone ever tries to compile this codebase with a pre-C89
compiler that enforces the # at the beginning of the line.
Part of P0203, funded by [Anonymous] and GhostRiderCog.
The .PTN functions, vector functions, and egc_copy_rect_1_to_0_1()
(finally!) from TH01, as well as playfld.hpp from all games(finally!),
together with a bunch of other functions in their vicinity.
Part of P0201, funded by Ember2528 and Yanga.
Reason: Too much micro-optimization using 32-bit registers, which
aren't supported by Turbo C++'s inline assembler. It's also just
another variation on a common function we've decompiled time and time
again.
Part of P0192, funded by [Anonymous], nrook, and -Tom-.
Reason: Saving SI and DI on the stack way too late. Just because ZUN
absolutely *had* to move the clipping condition before these two PUSH
instructions… Was it really necessary to save a total of 4 instructions
for an unlikely worst case in a function that's maybe called like 10-20
times per frame *at worst*?
Part of P0192, funded by [Anonymous], nrook, and -Tom-.