Yes, if you collect more than 255 point items in one TH04 stage, the
counter will overflow to 0.
It's a 16-bit word in both TH02 and TH05.
Part of P0034, funded by zorg.
So it's *_put(), inherited from master.lib, for everything just writing
to text RAM, and *_render() for everything more involved? But what
about master.lib's own graphics RAM functions like super_put()? Need to
fix that inconsistency some day.
Once again no decompilation, because…
Part of P0033, funded by zorg.
The TH02 version is a piece of cake…
… but TH04 starts turning it into this un-decompilable piece of
unnecessarily micro-optimized ZUN code. Couldn't have chosen anything
better for the first separate ASM translation unit.
Aside from now having to convert names of exported *variables* to
uppercase for visibility in ASM translation units, the most notable
lesson in this was the one about avoiding fixup overflows. From the
Borland C++ Version 4.0 User's Guide:
"In an assembly language program, a fixup overflow frequently
occurs if you have declared an external variable within a
segment definition, but this variable actually exists in a
different segment."
Can't be restated often enough.
Completes P0032, funded by zorg.
Rule of thumb going forward: Everything that emits data is .asm,
everything that doesn't is .inc.
(Let's hope that th01_reiiden_2.inc won't exist for that much longer!)
Part of P0032, funded by zorg.
"Yeah, let's do this real quick, how can this possibly be hard, it's
just MOVs and a few function calls"…
…except that these MOVs access quite a lot of data, which we now all
have to declare in the C world, hooray.
Once it came to midbosses and bosses, I just turned them into C structs
after all. Despite what I said in 260edd8… after all, the ASM world
doesn't care about the representation in the C world, so they don't
necessarily have to be the same.
Since these structs can't contain everything related to midbosses and
bosses (really, why did all those variables have to be spread out like
this, ZUN?), it also made for a nice occasion to continue the "stuff"
naming scheme, describing "an obviously incomplete collection of
variables related to a thing", first seen in 160d4eb.
Also, PROCDESC apparently is the only syntactically correct option to
declare an extern near proc?
Also, that `boss_phase_timed_out` variable only needs to be here
already because TCC enforces word alignment for the .data segment…
yeah, it's technically not related to this commit, but why waste time
working around it if we can just include that one variable.
Completes P0030, funded by zorg.
I've had the idea to hide this implementation detail and improve code
readability for some time now, but it obviously must still all inline,
to be indistinguishable from a direct assignment of the correct value…
… which, amazingly, it does! Even the static_cast from float to int.
The latter allows us to exclusively implement this for float, since we
do have to express the occasional value smaller than 16.
Who needs macros anyway. Yay, C++ in TH04 and TH05 after all!
Part of P0030, funded by zorg.
… yeah, I don't really like these ambiguous "mode" and "mode change"
variable names either, but what's the alternative? Something something
"sub-phase", to distinguish them from regular phases? Feels way too
early to decide on something more specific. And pretty much nothing I
could come up with right now would have made their inconsistent use any
clearer.
But I need to decide on *something* before moving on, so… eh, let's
just go with what uth05win chose.
Also, yeah, dealing with those 0xFE and 0xFD boss_phase constants some
other time 😛
Also, today in "Weird TASM crashes": Trailing commas at the end of
`public` lines…
Completes P0028, funded by zorg.
Many thanks to http://bytepointer.com/tasm/index.htm for providing a
better searchable resource for TASM's default `LEA imm16` → `MOV imm16`
optimization, which we initially had to hack around here.
Funded by -Tom-.
So apparently, this way of distorting a circle into an ellipse (?) by
adding a value to the angle for one of the two coordinates isn't
actually widely known in math and doesn't have a name. Fair enough.
Funded by -Tom-.
Sure, I like me some global variables too. If you have to temporarily
replace them for a single function call though, it's pretty much the
textbook example of where *not* to use them.
Funded by -Tom-.
Yup, nothing interesting in here.
Except for maybe the confirmation that LS00.BB is used for the curved
bullets used by Shinki and EX-Alice?
Funded by -Tom-.
… because TH04's version of this takes the ASCII stage ID directly from
the resident structure.
So boss battles are simply triggered by setting the background tile
scroll speed to 0? That means…
Funded by zorg.
Again, one of these functions that ZUN *probably* wrote in ASM for shits
and giggles, which you *again could* "decompile" using in-line assembly,
but that kind of defeats the point.
Oh well, at least the fact that the parameter is passed in AL means that
the calling convention must have been __fastcall, and *that* part *does*
cleanly map to C. Unlike some of the functions in d08a7f4.
Funded by zorg.
Struct strLASER in uth05win… except that the member names in that one
were not only a bit too unclear, but `ageThres` and `shootAgeThres`
should have also been the other way round.
Also, yes, TH04's laser structure seems completely different.
Funded by -Tom-.
With TH05 definitely being the Galaxy Brain version of this function.
You'll see once I get to push the C decompilation for that one…
Anyway, that covers all shared input functions of TH02-TH05!
Funded by zorg.
Seemingly included in every other larger structure describing anything
remotely sprite-like. Couldn't find this in the earlier games,
unfortunately…
Funded by zorg.
TH02 just seems to use a sequence of branches in sub_D6CA.
I thought about keeping variable and function names consistent with
uth05win (on which most upcoming reverse-engineering commits will be
based). But as it will turn out, it ignored a certain very important
substructure, so I don't think it's worth introducing this naming style
clash.
Funded by zorg.
Yes, you're reading that correctly. If the cursor is at 255, reading a
16-bit value will fill the upper 8 bits with the neighboring cursor
value, which always is 0xFF.
Funded by -Tom-.
Oh, right, these functions can have parameters. So, let's turn snd_kaja_func()
into a macro that combines the function number and the parameter into the AX
value for the driver.
And renaming them all to the short filenames they will be decompiled to for
consistency. These functions aren't really immediately hardware-related, as
we've established earlier in the decompilation.
Yes, all of it. Including the bouncing polygons, of course. And since it's
placed at the end of ZUN's code inside the executable, the code's already
position-independent and fully hackable.