Last one of the shared entity types! The TH05 version of the .STD enemy
VM would now be ready for decompilation in one single future push.
Completes P0088, funded by -Tom-.
Copying out the shot position might have actually been a decent
optimization for hit detection, to avoid the indirection if the shot
is not colliding with anything.
Part of P0088, funded by -Tom-.
TH04's z_super_roll_put_tiny_32x32(), which this is based on, had
checks for not writing empty rows to VRAM. Why would ZUN remove them
here?
Completes P0086, funded by [Anonymous] and Blue Bolt.
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.
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-.
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-.
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.
Which need to be separate from Mai's and Yuki's 32×32 balls because…
they have a delay cloud, whose radius absolutely has to be stored
redundantly, rather then deriving it from the [age]? Same for the decay
frame count. And the _update() function was copy-pasted from the knife
one…
Part of P0079, funded by -Tom-.
Heavily hardcoded for only two of them, even though there'd be space
for 65, even without position independence. Puppet army mod when?
Part of P0078, funded by iruleatgames and -Tom-.
On the surface, TH05 uses one single 26-byte structure for
• the Stage 2 starfield,
• Alice's puppets,
• curve bullet heads,
• Mai's snowballs and Yuki's fireballs,
• Yumeko's knives,
• and Shinki's 32×32 bullets.
But looking closer, it turns out that the fields of all these have very
different semantics, and in some cases, even different types. uth05win
treated all of those as distinct structures, and we're going to do the
same, merely overlaying the pointers onto the same generic array.
Part of P0078, funded by iruleatgames and -Tom-.
7 individually moving curve bullets × (16 trail points + 1 head point)
= 117 effective hitboxes. And yes, the game only renders half of them.
Part of P0078, funded by iruleatgames and -Tom-.
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-.
And of course, TH05 ruins the consistency once again. Sure, the added
file error handling is nice, but we also have changes in the playful
messages (lol), and now need a third distinct optimization barrier
(🤦)… But as it turns out, inlined calls to empty functions work as
well. They also seem closer to what ZUN might have actually written
there, given that their function body could have been removed by the
preprocessor, similar to the logging functions in the Windows Touhou
games. (With the difference that the latter infamously *aren't*
inlined…)
Part of P0077, funded by Splashman and -Tom-.
The supposedly low-hanging fruit that almost every outside contributor
wanted to grab a lot earlier, but (of course) always just for a single
game… Comprehensively covering all of them has only started to make
sense recently 😛
Also, yes, the variable with the uppercase .CFG filename has itself a
lowercase name and vice versa…
Part of P0077, funded by Splashman and -Tom-.
Oh hey, guarding declarations with complicated types via #ifdef limits
the header files we additionally have to #include!
Part of P0076, funded by [Anonymous] and -Tom-.
Well… how else to call a variable that handles
• pellet vs. 16×16 sprite (TH04),
• the delay cloud flags from bullet_spawn_state_t, but with different
values (which is restricted to 16×16 sprites in TH04),
• optionally showing the gather animation before spawning the bullet
… whether the bullet uses the basic slowdown motion (TH05),
(which is restricted to pellets in TH04),
• and defining what happens *after* the gather animation – not actually
spawning any bullets (TH04), or using the special motion type from
the bullet template (TH05)
🤯
Completes P0075, funded by Myles and -Tom-.
uth05win TL note: "n-way all-around" means "ring"… yep, let's better
improve on the naming here, once again using established terminology
from Sparen's Danmaku Design Guide at
https://sparen.github.io/ph3tutorials/ddsga3.html
Since TH04 only supports rings *or* spreads *or* stacks, overloading
[delta] to store both spread angle and stack speed, that enum does
serve kind of a purpose in TH04. Unlike TH05, where it could be vastly
simplified to a bitfield with 4 flags: aim to player, randomize angle,
randomize speed, force single. Which could then actually create *more*
types of patterns than these uselessly defined 14 distinct types, all
of which can already be derived from the other values of the upcoming
template structure:
• Set [stack] to 1 if you don't want a stack
• Set [spread] to 1 if you don't want a spread
• Set [spread_delta_angle] to 0 to turn a N-way spread into a ring
Easy.
Part of P0075, funded by Myles and -Tom-.
Since they're determined by the order of sprites in a .BFT file,
they're best auto-generated by an enum as much as possible.
Part of P0074, funded by Myles.
Might as well cover this one while I've got this type of function in my
head. This one is used for the animated star backgrounds during Stage 2
and the Shinki battle.
Completes P0073, funded by [Anonymous] and -Tom-.
Which finally allows us to use the PLANE_SIZE macro in ASM land. Yeah,
(ROW_SIZE * RES_Y) has finally got old.
Part of P0073, funded by [Anonymous] and -Tom-.
WTF. Fine, let's have separate, micro-optimized ASM implementations for
decoding and encoding inr MAIN.EXE, but still, all those minute
difference between OP.EXE and MAINE.EXE…
This is as far as anyone should reasonably go before decompilation;
things will get really ugly with the loading functions once the file
name is involved as well…
Completes P0063, funded by -Tom-.
Funny how the actual scores are stored as little-endian gaiji strings
in the bold font, yet never actually used as such.
Part of P0063, funded by -Tom-.
Since a few annoying alignment bytes suggested more translation units
than previously expected, using many small headers has proved to be
better than one big shared TH04/TH05 header file. Or should we *really*
pepper the code with lots of `#pragma codestring`? 😛
And in case we have multiple translation units which all #include the
same set of headers, we'll just go with situational shared headers,
using a common prefix.
Part of P0062, funded by Touhou Patch Center.
As used for the title screen fade-in effect. Another function that
apparently was deliberately written to run not that fast, by blitting
each row individually to the 400th VRAM row just so that it can then
turn on the EGC, perform the *actual* masked blit to the VRAM
destination, and then turn the EGC off before moving to the next now.
The same effect could have entirely been accomplished by copying
graph_pack_put_8() and applying the mask there; it's not like ZUN
didn't know how to modify master.lib…
(See also 44ad3eb4) --Nmlgc