Commit Graph

840 Commits

Author SHA1 Message Date
nmlgc 550bba9b3c [Position independence] False positives in master.lib EGC function calls
Mostly used for screen shaking.

Part of P0059, funded by [Anonymous] and -Tom-.
2019-11-18 22:21:34 +01:00
nmlgc 3d7211b128 [Position independence] Remaining motion structures and comparisons
Part of P0059, funded by [Anonymous] and -Tom-.
2019-11-18 22:21:29 +01:00
nmlgc ad22ce26c2 [Reverse-engineering] [th04/th05] Player position clamping
Part of P0059, funded by [Anonymous] and -Tom-.
2019-11-18 22:21:23 +01:00
nmlgc b37611b1be [Maintenance] Add an underscore to the player_pos variable
No need to declare them as `pascal` on the C side only because I messed
up when naming them first.

Part of P0059, funded by [Anonymous] and -Tom-.
2019-11-18 22:21:15 +01:00
wintiger0222 01de2900dd [Decompilation] [th01] frame_delay
Closes #7.
2019-11-18 21:29:43 +01:00
nmlgc fef0299fbc [Reverse-engineering] [th04/th05] Midboss / boss explosion phase constants
In the end, the explosions remain the only constant in these phases,
everything else ("defeat"? "last phase"?) could have been
misunderstood. And yes, the algorithm really treated these 111
constants as potential memory references…

Completes P0058, funded by -Tom-.
2019-11-14 00:57:38 +01:00
nmlgc 6c4852f789 [Position independence] False positives in master.lib GRCG function calls
Yup, function parameters that can clearly be identified as coordinates
are by far the fastest way to raise the calculated position
independence percentage. Kinda makes it sound like useless work, which
I'm only doing because it's dictated by some counting algorithm on a
website, but decompilation will want to un-hex all of these values
anyway. We're merely doing that right now, across all games.

Part of P0058, funded by -Tom-.
2019-11-14 00:51:48 +01:00
nmlgc 8a250701bd [Reverse-engineering] [th04/th05] Items dropped when losing a life
> not using the Point structure, which is not only perfectly suitable
here, but would have also generated much better code

Part of P0058, funded by -Tom-.
2019-11-14 00:50:56 +01:00
nmlgc ac7540dada [Reverse-engineering] [th04/th05] Item types and sprite IDs
Completes P0057, funded by [Anonymous] and -Tom-.
2019-11-14 00:49:22 +01:00
nmlgc 2f0ca1ccf1 [Position independence] False positives in item functions
Welcome to this new [brand] of reverse-engineering, where we only fix
things that might be mistaken for addresses, without looking deeper
into what the actual functions do… unless that directly leaps into
the eye.

Part of P0057, funded by [Anonymous] and -Tom-.
2019-11-14 00:48:24 +01:00
nmlgc 34089cbe3f [Reverse-engineering] [th04/th05] Item structure
Part of P0057, funded by [Anonymous] and -Tom-.
2019-11-14 00:47:20 +01:00
nmlgc 2918e6dbd0 [Reverse-engineering] [th04/th05] Item spawn "splash" circles
"Splashes"? That's what uth05win calls them. Oh well, "circle" is
already taken, and merely keeping the slices in the item/ directory
won't avoid the name collision when looking at game code.

These are hardly visible on top of regular enemy explosion animations;
you can most clearly see them at the end of the TH04 Extra Stage
midboss. Easy enough to *almost* completely cover right now, even
during a position independence push. Struct strITEM_SPLASH in uth05win.

Part of P0057, funded by [Anonymous] and -Tom-.
2019-11-14 00:45:32 +01:00
nmlgc d1acb70cdc [Maintenance] Move the enemy item drop table to an item/ subdirectory
Part of P0057, funded by [Anonymous] and -Tom-.
2019-11-14 00:44:10 +01:00
nmlgc 1cb97310c7 [Readme] Remove the porting plans
Well, that might have been my entire sales pitch for the decompilation,
and now I've ruined everything… Still, I've been getting way too many
confused questions about this by now. Let's focus on reconstructing,
and once that's done, ReC98 is done, and another project can take over.
Maybe done by me and mostly following the original plans, but probably
not.

Thanks to -Tom- for finally pushing me to do this 😛
2019-11-12 20:42:21 +01:00
nmlgc a2e8866c28 [Readme] Clarify that the library % numbers only apply to the two main ones
Apparently, people might have misunderstood this to mean "we've found
SPRITE16, so TH03 is now 74% (OP) / 54% (MAIN) done"? Thanks to
Splashman for the tip.
2019-11-12 19:50:41 +01:00
nmlgc c09446a1f4 [Reverse-engineering] [th03] SPRITE16 calls
Aha! TH03's in-game graphics run in line-doubled 640×200 simply because
that's what this SPRITE16.COM version was written for, making use of
the PC-98 EGC for optimized blitting.

Doesn't seem all *too* optimized though, given that it chooses to
effectively draw every sprite twice, just in case it might overlap with
something that's already in VRAM. It first clears the previous VRAM
content at the drawing position according to the sprite's alpha mask,
then ORs in the actual sprite data. The EGC can do monochrome alpha-
tested blitting just as well as the GRCG, but once the sprite data
covers all bitplanes, ORing is apparently the best it can do by itself?
More technical details on the raster operations in the next push!

Completes P0056, funded by rosenrose and [Anonymous].
2019-11-06 23:36:47 +01:00
nmlgc 772897c8f5 [th03] Identify ZUNSP.COM as a rebrand of Promisence Soft's SPRITE16.COM driver
Which was actually found out by @m1yur1 last year, who thankfully
tweeted this in reference to ReC98:

	https://twitter.com/m1yur1/status/1018855232371998720

Thanks a lot! But what makes this more than a piece of trivia is the
fact that the StormySpace release actually *was* bundled with
documentation. Shoutout to the Neo Kobe PC-98 collection for preserving
the original release! This should now greatly simplify any RE efforts
related to TH03's INT 42h calls. (Not *trivialize*, because there's
still all this EGC hardware to be understood…)

And sure, you *were* allowed to use this driver in your own game, but
replacing the copyright with your own isn't exactly the nicest thing to
do… That now makes three library programmers that ZUN didn't credit.
Makes me wonder what makes M. Kajihara so special. Probably the fact
that Touhou has always been about the music for ZUN, first and
foremost.

Part of P0056, funded by rosenrose and [Anonymous].
2019-11-06 23:30:43 +01:00
nmlgc b28cefc1c1 [Readme] Start a separate contribution guideline file 2019-11-04 22:33:53 +01:00
Egor 0460072f25 [Decompilation] [th01] mdrv2_resident
I thought this would be a good target for my first attempt at
decompilation. Should have known something was up, because it's the only
undecompiled proc in the translation unit.

Oh well, SCOPY stands for "structure copy" anyway. /s
2019-11-04 22:14:10 +01:00
Egor 61252e83f5 [Maintenance] gitignore everything in bin 2019-11-02 19:22:05 +02:00
nmlgc 34e3c7e530 [Readme] Add crowdfunding / progress badges and a GitHub funding button
Are we cool now?
2019-10-17 20:58:50 +02:00
nmlgc e7e1cbcaaf [Decompilation] [th05] Marisa's shot control functions
Yeah… such fun pretending that the original code wasn't copy-pasted.
And yes, Reimu will have to wait until the next one.

Completes P0037, funded by zorg.
2019-10-14 23:54:37 +02:00
nmlgc 1276a0c94a [Decompilation] [th05] Mima's shot control functions
And if I don't manage to cover Reimu in this push, it's because ZUN
switched around the cases in half of the functions here… 😵  Here's
some macros instead, to make the code at least *look* as table-driven
and readable as it should have been in the first place.

Part of P0037, funded by zorg.
2019-10-14 23:54:37 +02:00
nmlgc da27eb4c31 [Decompilation] [th05] Yuuka's shot control functions
Ooh, shot position being determined by RNG at lower shot levels? That's
some RNG manipulation TAS potential right there! Maybe.

Part of P0037, funded by zorg.
2019-10-14 23:54:29 +02:00
nmlgc db4de240e9 [Decompilation] Prepare the C side for the shot type control functions
That should make this convoluted copypasta a bit easier to read. And
sure, I could have done something about the loop as well, but
SHOT_FUNC_INIT already hides enough control flow behind a macro…

Part of P0037, funded by zorg.
2019-10-14 23:42:20 +02:00
nmlgc 82b0e1db24 [Reverse-engineering] [th05] Player shot cycle bitflags
A TH05 innovation that actually makes the game code easier to read?!
Although it was quite hard to actually reverse-engineer it, with the
confusing flag ordering pointing to some deeper meaning behind the
flags, which really doesn't exist.

Completes P0036, funded by zorg.
2019-10-14 23:42:09 +02:00
nmlgc a84fa33beb [Reverse-engineering] [th04/th05] Player shot cycle counter
Part of P0036, funded by zorg.
2019-10-14 23:42:02 +02:00
nmlgc f33a3ef220 [Maintenance] [th04/th05] Separate constant for the player↔option distance
Used in pretty much all shot type control functions.

Part of P0036, funded by zorg.
2019-10-14 23:41:57 +02:00
nmlgc b801d24a34 [Reverse-engineering] [th04/th05] Setting the player shot velocity
The TH05 difference: A ridiculous out-of-bounds structure field access.
Could have done safely by just passing a shot_t*, but ZUN's too cool
for that?

Also, about time we started putting the function prototypes directly
into the C headers, and the C headers *only*, upon reverse-engineering…

Part of P0036, funded by zorg.
2019-10-14 23:41:52 +02:00
nmlgc 5ebbe7bda9 [Maintenance] Move all shot-related slices to the player/ subdirectory
It seems that the main th0?/ directories should only contain actual
translation units (of which there are more than previously assumed)
as well as other not really further classifiable slices?

Part of P0036, funded by zorg.
2019-10-14 23:41:46 +02:00
nmlgc a533b5d3ea [Reverse-engineering] [th04/th05] Player sprite area invalidation
And once again, the TH05 version is un-decompilable. :/ It was pretty
close this time, though, as the entire block between PUSH DI and POP DI
kind of resembles a separate inlined function, in accordance with Turbo
C++'s  automatic backup of the DI register, as researched in 7f971a0.

Except that it contains a loop, and Turbo C++ refuses to inline any
function with `do`, `while`, `for`, or `goto`. If it didn't, it would
have totally worked.

Also, yes, C++ class methods are treated identically in this regard.

Oh well. Shot type control functions next, finally!

Completes P0035, funded by zorg.
2019-09-24 22:04:26 +02:00
nmlgc 7887f53ea8 [Maintenance] Move the playfield constants to a separate .inc file
With both 16- and 32-bit build parts soon having full dependency
tracking, having more small includes wins out over having fewer, larger
ones – and also, over having to fix tons of macro conflicts that stem
from most .inc files assuming the context of the big .asm files.

Case in point, including ReC98.inc doesn't work right now without
defining a .MODEL, which is counter-productive for ASM compilation
units.

Part of P0035, funded by zorg.
2019-09-24 22:00:48 +02:00
nmlgc e65cf0d05d [Maintenance] Change a few ASM .inc files to use 8.3 names
Part of P0035, funded by zorg.
2019-09-24 21:58:18 +02:00
nmlgc 290935fe3e [Reverse-engineering] [th04/th05] Player character display
Including options and the death explosions.

Part of P0035, funded by zorg.
2019-09-24 21:58:09 +02:00
nmlgc 68c9a3c79c [Reverse-engineering] [th02/th04/th05] Single-plane sprite display calls
Require understanding a hardware detail, so let's do them all at once.

Part of P0035, funded by zorg.
2019-09-24 21:58:03 +02:00
nmlgc 6f1f36722f [Reverse-engineering] [th01/th02/th04/th05] Player invincibility frames
Completes P0034, funded by zorg.
2019-09-24 21:57:53 +02:00
nmlgc c77a9276d3 [Reverse-engineering] [th04/th05] Death-related variables
Including the confirmation that both games have an 8-frame deathbomb
window.
The placement of the variables is all over the place though, what the
hell?

Part of P0034, funded by zorg.
2019-09-24 21:57:46 +02:00
nmlgc 5a6567e173 [Reverse-engineering] [th04/th05] Number of point items collected
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.
2019-09-24 21:57:41 +02:00
nmlgc 881f2c671e [Reverse-engineering] [th04/th05] Player option position
They are supposed to lag behind the player's movement by one frame, and
therefore have to be tracked separately.

I would have also included TH02, if it weren't for the weird sprite
indirection system (not storing X and Y positions directly in the
structure, but taking them from a buffer, with their addresses
always changing, WTF?!) that absolutely needs separate attention.

Part of P0034, funded by zorg.
2019-09-24 21:57:35 +02:00
nmlgc b7d204aeec [Reverse-engineering] [th02/th04/th05] Player option sprite number
Part of P0034, funded by zorg.
2019-09-24 21:57:29 +02:00
nmlgc 0b542125a5 [Decompilation] [th04/th05] Remove the Subpixel constructors
They just create unnecessary code when passing Subpixels by value to
functions.

Part of P0034, funded by zorg.
2019-09-24 21:57:23 +02:00
nmlgc 6cdd2296bb [Reverse-engineering] [th04/th05] Input → player movement
Completes P0033, funded by zorg.
2019-09-21 14:01:51 +02:00
nmlgc 7f971a0d1c [Research] Find out why we can't decompile TH05's hud_bar_put()
Part of P0033, funded by zorg.
2019-09-21 14:01:51 +02:00
nmlgc f8213c5a32 [Reverse-engineering] [th04/th05] HUD bar display
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.
2019-09-21 14:01:50 +02:00
nmlgc e6294c2c1a [Reverse-engineering] [th02/th04/th05] Score update and display
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.
2019-09-21 14:01:47 +02:00
nmlgc 88c05e48e5 [Maintenance] Move a few more ASM definitions to their own .inc files
Part of P0032, funded by zorg.
2019-09-21 13:05:54 +02:00
nmlgc d19f91914e [Maintenance] Mirror the TH04/TH05 C header sharing on the ASM side
Part of P0032, funded by zorg.
2019-09-21 13:04:28 +02:00
nmlgc f07089017f [Maintenance] Rename the extension of game-specific ASM includes to .inc
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.
2019-09-21 13:03:56 +02:00
nmlgc b2184e99fd [Maintenance] Remove merge=union from .gitattributes
What the…? *That's* what's been messing up merge conflicts all the
time?

Part of P0032, funded by zorg.
2019-09-21 13:03:17 +02:00
nmlgc 9f764fa6fb [Maintenance] [th04] Split code segment #1 into two
So yes, we *can* technically decompile from anywhere, by splitting the
segment after the function we want, then .SEQuentially GROUPing the two
segments back together into one virtual segment matching the original
one. This gives us one more point where we can slot in new compilation
units that emit their code into the same segment, in the order given on
the link command line.

*But* since all ASM in ReC98 heavily relies on being assembled in MASM
mode, we then start to suffer from MASM's group addressing quirk,
described in the "Accessing data in a segment belonging to a group"
section in the Turbo Assembler Version 5 User's Guide.
Which then forces us to manually prefix every single function call

• from inside the group
• to anywhere else within the newly created segment

with the group name. It's stupidly boring busywork, because of all the
function calls you *mustn't* prefix. Special tooling might make this
easier, but I don't have it, and I'm not getting crowdfunded for it.

And while this is faster than porting the entire codebase to Ideal
mode, I'll only do this on rare occasions.
Like the upcoming, particularly awful piece of reverse-engineering.

Completes P0031, funded by zorg.
2019-09-21 13:02:09 +02:00