You can definitely make an argument that these if/else if branches are
easier to read than their implied formula, especially with all
variables being signed here.
Completes P0197, funded by Yanga and Ember2528.
AKA a reaction commit to the unfounded theory from Asprey's "Unused
Content in Touhou Project" video. (Seriously though, it does help with
the code for these games.)
Part of P0197, funded by Yanga and Ember2528.
Turns out that the "new idea" for handling these data slices won't work
out in reality. At least the amount of necessary manual `extern`
declarations isn't soul-crushingly large, so this way isn't bad either,
after all!
Part of P0197, funded by Yanga and Ember2528.
Brought to you by diagonal movement and the combined effect of 4 ZUN
bugs. Most commonly reported for Elis and Mima.
Part of P0197, funded by Yanga and Ember2528.
These could have been nicely separated into per-device translations
(one for GDC, one for EGC, one for regular VRAM accesses)… if their
original order followed that classification.
OK, so let's make it one full `graph_ex.cpp` translation unit… nope,
FUUIN.EXE needs graph_2xscale_byterect_1_to_0_slow() with different
compilation flags. 🤦
Whatever, fuck it, let's go for individual translation units, with
individual headers, so that we at least get predictably organized
source code out of this.
Part of P0196, funded by Yanga.
The phase 3 selection logic was fine! No need to reinvent it with even
more convoluted logic, in a function that should not exist to begin
with. (Phase 4 is another one that only consists of a teleport and a
bat transformation.)
Part of P0195, funded by Yanga.
The one where Elis fires aimed 5-spreads from her left and right wings,
togther with an aimed laser every second time, and finishes with a
32-ring of static bullets along, yet again, not quite the center
position of the big circle around her.
Part of P0195, funded by Yanga.
The one where Elis creates a safety zone of 256 pixels around the
initial position of the player, indicated by a circle, and then fires
pellets from random positions at the top edge of the playfield for a
while.
Followed by 5 aimed pellets from her center position.
Followed by… 7 aimed pellets from the bat entity's center position?!
Except that those aren't even correctly centered relative to the bat,
and still use the center offset of the girl sprite.
Part of P0195, funded by Yanga.
The one where Elis' bat form fires a slow spread group every 16 frames.
Interestingly, it's easiest on Lunatic, where the pellets are always
fired downwards and you just have to not stand below Elis. On every
other difficulty, the pellets are aimed to the player.
And what's this, an appropriately used local variable?!
Part of P0195, funded by Yanga.
The one where Elis fires pellets from 5 random blue rifts around her
sprite, first with random angles firing downwards, then with random
angles in all directions.
A~nd we've reached Konngara levels of copy-pasta again. 🍝
Part of P0194, funded by Ember2528.
Nice that this is a dedicated function. ZUN could have easily
copy-pasted it into every pattern, just as we've seen with Konngara… 🎺
Part of P0194, funded by Ember2528.
Oh hey, ZUN wrote a function to help with the very meaningful task of
expressing the Star of David's point coordinates in polar form!
Part of P0194, funded by Ember2528.
The one where Elis, on Lunatic, runs past the pellet cap of 100 by
spawning 160 slow aimed pellets along a circle in a single frame, and
that's not the only janky quirk in there.
Completes P0193, funded by Ember2528.
The one where Elis fires missiles from random locations around her
sprite, aimed at random angles towards the bottom of the playfield.
Part of P0193, funded by Ember2528.
The one where Elis fires 11 (yes, 11) evenly spaced lasers from her
left eye (?) across the whole playfield, from either the left or right
edge to the other one. First pattern you see in the fight.
Part of P0193, funded by Ember2528.
Yup, assigning this one to Elis, even though its proximity to the rest
of the generic boss variables might suggest that it was intended as a
generic boss state variable. Nope, that idea has already demonstrated
its uglyness in the previous TH04 and TH05 pushes…
Part of P0193, funded by Ember2528.
Even ZUN once preferred nice floating-point syntax for subpixel values,
apparently. Still, `double` is massive overkill here.
Part of P0193, funded by Ember2528.
It's slowly starting to make sense, as it eliminates the need for both
separate `*_COUNT` macros in places where the count isn't used for
anything else, as well as custom class declarations.
Part of P0193, funded by Ember2528.
Looking back at the MAG.Net footage, that out-of-focus block of pixels
is clearly separated from the opening parenthesis with an `l`, with the
second word alone making up four monospaced ASCII characters. `Execl`
is also a much more descriptive name, given what the function does.
Part of P0192, funded by [Anonymous], nrook, and -Tom-.
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-.