Decompiles stage header data for all in progress stages.
Of note is that NO3 and NP3 (and likely other future stages) use an
`AbbreviatedHeader` because their `SpriteBanks` start immediately after
`UpdateStageEntities`. There are several areas which use
`sizeof(Overlay)` to copy this data over, in those cases sprite bank
data is copied into the tail fields of the overlay but are never used.
I'm not sure if I did the data extraction correctly. There is more to
pull out of the remaining `0x106C8` section but the sizes aren't quite
lining up.
This finishes NP3.
Gaibon's logic is extremely similar here as it is in NZ0. There are a
few differences, especially in the initialization code (which runs
before the primary switch), but as a whole, it's a copy-paste.
Slogra and Gaibon are in separate files. The only way we know this is
because they both have debugging `charal` strings which exist separately
in rodata (if they were the same file, it would reuse the same rodata
location for both strings).
This function is kind of crazy and huge.
I also made its helper static.
The name for the function comes from the fact that the duplicate finder
matched this up with a function in NO3, which had been given that name,
so I named this one to make them match up.
This is a helper function for the entity that comes right after it.
It's relatively simple in terms of functionality, but I have no idea
what it's actually doing, so unfortunately everything is completely
unnamed. At least it matches.
This is a huge one! Lots of file shuffling needed to happen, but now
that things are in place I feel relatively confident that we have our
file splits in the right places, which is great. It's really cool when
we can make file splits that are motivated by game structure, and not by
rodata limitations.
Anyway, here it is, let me know which flags and stuff I forgot about :)
Another big one! This required mangling the files a little bit; once the
other functions are decompiled the files should come back together
nicely. The function itself is in 4B018.c, and the function is currently
alone in that file.
Kind of a complicated process to get this one working, beyond the normal
function decompilation.
Files are split for now, because there are weird things with rodata. I
have already done the two remaining Gurkha functions, so my next PRs
will pull those in and will end up bringing the files back together.
Messy things here, tried to make it looks nice but as always, feedback
is appreciated.
What is a SOTN? A nasty, miserable little pile of pointer manipulations!
Well here we are, the last one! Solving the previous function helped me
figure out the patterns here, but wow, this is really a miracle.
Let me know how you want to handle the de-duplication. We can either do
that here, or merge this and do all the others in a second PR.
Fairly straightforward de-duplication. If anyone has better names for
either the function or the array it uses, feel free to suggest them, but
with this thing being so weird and its purpose being unknown, I had to
keep the names pretty generic.
3 NZ0 functions remaining? I think you mean 2 NZ0 functions remaining :)
I don't really understand this one, it's a bit of a mess. Lots of
tilemap stuff, so maybe this does something with the weird shifting
backgrounds in the Alchemy lab? Who knows.
I was able to start with the red door code and rely on that a fair bit.
I modified the code to recreate the parts that are needed for the blue
door.
Their entity extensions matched up (with the blue door needing a couple
extra members) so I changed ET_RedDoor to just be ET_Door, and both
doors use it. I'll be curious to see if the weird golden door to the
Olrox fight is similar to these ones.
NZ0 is really getting empty now!
This is a weird function, we don't really know what it does. But
matching is always the first step. Just glad it works.
The behavior on the `dataPtr` makes me sad. Pointers are treated in such
evil ways in this game.
This took me a lot of manual work. But I think I confirmed a pattern
that will help me to automate all of this for all the next stage
overlays that will be imported in the repo.
I noticed some stages with only one room having more than two layers or
more than two tile definitions, it might be either debugging or unused
content? I did not have time to explore any of that.
I modified the `tiledef` splat extension to greatly minimise the set-up
and noise.
Relatively simple function.
I'm trying to get better at things like using good variable names,
organizing files, etc, and I think it pays off. This function is more
readable than it would have been in the initial scratch. Excited to
really get the game into a state where all the code is directly
readable.
PSX: https://decomp.me/scratch/74j2Y
PSP: https://decomp.me/scratch/ons5L
Let me know if you'd like to inline `CLAMP_MIN` and `CLAMP_MAX`, or move
them to `macros.h` or `common.h`. I see a reference to `CLAMP` in
STYLE.md but couldn't find it in the repo.
The duplicate finder missed this one, but I found it indirectly by
looking for the preceding functions, which are all duplicates. This
should actually be the last of the cutscenes (at least, until we get new
overlays).
All these cutscenes have little tweaks to their logic, but nothing very
interesting, so not much more to share here. But cool to have them all
done!
I think this is pretty much ready to be merged it. I do not see much of
a point of having the branch floating around.
I am using a `#ifndef HARD_LINK` to avoid compiling duplicate functions
with the same symbol name.
For data with the same symbol name but different content I am doing a
`#define OVL_EXPORT(x) WRP_##x`. So for example
`OVL_EXPORT(g_EntityGfx)` will be expanded as `WRP_g_EntityGfx`. It is
an unfortunate hack. On the other hand all the data migration allowed me
to mark most of the data and functions as `static`. If we use the same
approach on other overlays we could easily statically link them as well.
SEL is enabled by default. It will take you straight to the real WRP,
not the dummy one.
Most of the changes are loading assets from their respective JSON files.
Linking the stage was pretty straight forward.
Still work in progress. I removed splat as a submodule and started using
it as a pip package instead. Everything is matching but the memory card
icons part in both DRA and SEL. I still have no idea what the issue is.
Once this PR is good to be merged, we can get rid of the splat fork too.
As far as the duplicate-finder can tell, this is the last of the
cutscenes, but who knows - we may find more. Luckily, the pattern is
pretty recognizable.
Named it due to what we see at the very end in `case 7`, with the
TimeAttackController getting triggered.
I was asked to help with #556 , but that is an old PR and I'm not sure I
want to be doing a PR into a PR, so here's this one.
I did not touch the code at all, just shifted around the files and such
in order to get rodata to match.
Merging `wrp_psp/warp.c` into `wrp/warp.c`.
I imported all the BSS data into `wrp_psp/bss.c`. I do not feel it is
yet the right time to split the bss section into the individual files as
I feel it might have a ripple effect to every other overlay.
I confirm empty arrays on PSX are in data, but on PSP they are in bss.
This is currently forcing me to do some `#ifdef` here and there. It
should get solved once the bss is split into their respective original
files.
I feel very positive about the file split in WRP. So far it seems to be
accurate. I really hope to spread this new pattern to other overlays
too. It should make importing new stage overlays in the future much
easier.
Continuing to run the cycle on all these cutscenes.
This one is interesting because it switches on self->params to do
different things - this might signify when the Succubus shows up as
"Lisa", versus after the reveal when it shows up as Succubus. Unsure,
that can be a project for the future.
This adds some additional context for func_801B9744 and renames globals
to fit their assumed purpose.
Migrated various stream metadata to C definitions.
The makefile changes add a dependency on `sel.h` to all the objects that
get built from the `st/sel` directory.
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
Wow. This is perhaps one of the hardest functions I've ever done. It
does disgusting things with pointers that I've never seen anything like
before - some of them are the fault of the programmers, some are the
compiler.
Once I was like 98% done, I found func_801B69F8 which is very similar
(and decompiled), but wasn't picked up by the duplicate finder, so that
was a little sad. Once I found that though, the last of my mysteries
were quickly solved.
This is a huge function and it's nice to get it cracked.
More data imported into the C files. I reached this stopgap due to
`st_debug.c`, where I am failing to import the data from PSP. Strangely
enough, PSP suggests `st_debug`, `e_breakable` and even `warp` being in
the same file?!
The INIT section seems to follow the `PfnEntityUpdates` on both PSP and
PSX. But on PSX this is very close to the top while on PSP is right in
the middle.
Overall the PSX C and DATA order seem to align perfectly. PSP is far
more unpredictable, but the DATA order seem to also follow the C files.
The advantage of PSP is that almost everything is out of order compared
to PSX, which easily suggests file splits.
Another key difference between PSP and PSX is that arrays filled with
`0x00` are found in DATA on PSX and in BSS on PSP.
These are the common implementation. They needed to be split for the
jump tables to be positioned correctly.
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
Boy, this one was a beast!
It created yet another evil awful horrible variant of Primitive, where
it's referencing several s32 values in the struct, so we had to add
another to Primitive.h.
The splat was slightly off, it was missing the nop at the end of this
function.
It appears that this function manages 385 primitives to make the life
max up spawning animation, and puts them all through a bunch of GTE
functions, so I'm wondering if that's why the animation is so laggy.
I'm confused on why this function doesn't show up in duplicates.txt,
since I would have thought it would be universal across all overlays
which contain a boss (which is most of them). Although... now that I
think of it, Slogra and Gaibon are the only bosses in the overlays that
are currently in the decomp, so that's probably why. CEN, DRE, ST0, NP3,
etc don't have bosses so they don't need to have this entity. Hopefully
this ends up duplicating in the other overlays once those get pulled in.
An awful function, but at least it matches!
Given the fact that sharing compiled C objects is not exactly possible
(code heavily copy&pasted maybe? this initiative is now abandoned 👉53a566f075)
I decided to keep pressing forward with shared headers. Thanks a lot to
@hohle for making our life much easier by cross-referencing symbols.
The file split on WRP seems to be the closest file split we might have
compared to the original source code (still speculating here). I think
it would be a good idea to start splitting other overlays too with the
same approach.
My idea is to have a file split like the following:
```
st/
cen/
e_particles.c
e_misc.c
st_common.c
nz0/
e_particles.c
e_misc.c
st_common.c
wrp/
e_particles.c
e_misc.c
st_common.c
e_particles.h
e_misc.h
st_common.h
```
each of those C files will just be a one-line `#include
"../the_shared_code.h"` as usual. Right now we create individual headers
for single functions, sometimes for more than one function when we think
grouping makes sense. But I think we can start merging some of those
headers and consolidate the code. This can be done gradually. For
example `src/st/e_particles.h` is still importing function headers under
the hood. That is okay for now, but later on I wish to import those
headers functions into their respective parent headers.
Another important aspect to consider that will validate a correct file
split is to start importing the data inside these new C files. Right now
we have floating data such as `src/st/wrp_psp/wrp_data_EA00.c` or
monstrosities such as `src/st/wrp/6FD0.c`. An example of a (possibly)
correct migrated data is what this PR does with WRP PSP and NZ0 PSX,
with data pointing in `src/st/*/e_particles.c`.
A few changes here.
First, Slogra needs to be split out to his own file, as mentioned in my
previous PR.
I decompiled EntityCloseBossRoom, but I decided it needed a better name,
since, while it does close the door to the boss room, it actually does a
lot more and in general manages the fight (most importantly, it starts
the fight, spawns Slogra and Gaibon, and when they die, spawns the life
max up). Therefore I named it BossFightManager. Since this function, and
the door blocks it spawns, are the only ones in this file, I decided to
call it bossfight. I think we should try to be liberal with naming
files, once we know all the functions contained in them.
Otherwise I think that should do it! Very cool to have the first boss
fight in the game all figured out.
This was great to get working!
There was a Decompme WIP, but I decided to ignore that and do it from
the beginning, and I think that worked out well. PSP was of course very
helpful.
This ended up being pretty readable with all the steps that were already
documented (I think that was Sonic's doing, so thanks!). Pretty happy to
have this working!
Slogra and Gaibon each have a separate `FntPrint("charal %x\n",
self->animCurFrame);` call in their debug step. Importantly, this string
is in rodata in two places. If Slogra and Gaibon are in the same file,
they share the same string address, and the rodata only gets the string
in one place. Splitting the files restores the duplicated string in
rodata, meaning that these files need to be split.
I have already decompiled EntityCloseBossRoom and found the same issue
there, so my next PR will end up pulling out Slogra into his own file as
well.
Lots of code here, review carefully!
This one was fun! Lots of use of the coordinate transformation
functions, and lots of weirdly packed data.
Had to shift the splat a little bit. This is the last function in the
file (location-wise, not the last to be decompiled) and the end of the C
segment was slightly off.
Pulls out `EntityExplosion` into a common file.
`cen` and `rwrp` appear to have not imported a declaration for
`AnimateEntity` and call it as an undeclared function with a int-sized
return value. Since `AnimateEntity` is declared in the same compilation
unit a workaround is done to fix how the return value is interpreted.
In the interest of reducing uses of `generic`, and especially the
`entityPtr` member of it, I found this function which had several
duplicates already, all of which used `generic`. Rather than cleaning it
up in every instance, I decided instead to de-duplicate it, and then
clean it up in the .h file.
I needed to make a new entity extension for this, and noticed that we
had `ET_Entity16`, but then I realized that this was being used for
`g_Entities[16]`, so I renamed that to be `ET_EntitySlot16`, leaving
`ET_EntityXX` available, for XX being the ID of an unknown entity.
This took a few hours of research spread across a few days. A few
take-aways:
`.ext.weapon.anim` and `.ext.player.anim` are both on `0xAC` and they
NEED to stay aligned since they both call `PlayAnimation`, which
operates on `.anim`. I double-checked `EntityWeaponAttack` and the param
entity is definitively not `PLAYER`, despite `.anim` being in the same
offset. I did not encounter a single `.ext.generic.unkAC` that is not
related to animations, so this can be a pretty strong clue of a pattern.
I have this theory where not all the area of an entity from `0x7C` to
`0xBC` is reserved, but just from `0x7C` to _at least_ `0xAC`, with _at
least_ the last `0x10` bytes are part of a shared struct among all
entities.
```c
/* 0x7C */ Ext ext;
/* 0xAC*/ u8 anim;
[...]
};
```
I want to collect more proof before proceeding to mass-rename
everything.
I learnt what `g_Player.pl_vram_flag` is actually doing. It holds some
kind of state of the player towards the map collision. It holds a bunch
of flags that helps setting the animation. I still feel not confident
enough to create `#define`'s for it until we know more.
All the `condition = ((g_Player.pl_vram_flag & 0x20) != condition)` got
rewritten with the following:
```c
atLedge = 0;
if (g_Player.pl_vram_flag & 0x20) {
atLedge = 1;
}
```
the `atLedge` adds up to the `anim` function. The animation table
essentially have one ID after the other where the first holds the Anim
ID when the player is not at the ledge and the next one where it is. For
example: `[ANIM_STAND, ANIM_STAND_ATLEDGE, ANIM_ATTACK,
ANIM_ATTACK_ATLEDGE]`.
`D_800ACF4C` and `D_800ACF54` are some kind-of animation helpers when
Alucard either stands still, jumps or falls. I burnt the values in
`stubs.c` while we wait for importing the remaining DRA data.
This was an old one with a decompme comment in the code that I decided
to tackle. Turned out to be able to make it relatively straightforward!
I think the naming is reasonable and is motivated by the behavior in the
code, but happy to adjust if needed.
Strangely, decompme informed me that the function was matched here:
https://decomp.me/scratch/aEXJO by "NicoVazCan", 3 months ago. Not sure
who that is, but they never submitted it, so I guess it's abandoned.
Either way, I think the code in this PR is more readable.
The yaml changes were generated with a script.
https://gist.github.com/sozud/ae6837a24bc8bb4e8bcc89d3e14d83f4
The alignment of the yaml seems to be wrong so I had to check if the
address % 16 == 0 and only split at those spots. I put the data in
create_entity since it's the first file in the psp yaml.
I think those are a bunch of animation indices? I am not yet sure how to
represent them as structured data, so there you go having them imported
as C files.
Importing some data from `DBD4` with the goal of making the _Sound_ app
more accurate.
I do not know in which file to put this data into, so I created a file
ad-hoc.
EDIT: I kept importing more
Quite a big one. I merged `EntitySoulStealOrb` across all overlays by
normalising the symbol names. The symbol types was all over the place,
so I had to fix that as well.
I solved the s16/u16 ifdef between PSX and PSP. The only part I couldn't
match without a ifdef was `angle = (angle - 1) * 8;` and `angle = (angle
* 8) - 8;`.
I also decompiled the exclusive PSP functions `func_psp_0923AD68` and
`func_psp_0923B2F0` and merged the PSX and PSP `e_particles.c` code. The
exclusive functions required a file split.
Straightforward PR. Interestingly importing the data doesn't seem to
result to a match ad there's some `0x10` aligned padding added. Either
we know too little about importing data with MWCC or the file split was
wrong and the data belonged together with other functions in another C
file.
For now I had to use a `#ifdef`. It will probably get forgotten until we
decide to import the data from WRP PSP.
I found the variable `distance` in `func_80132A04` can be negative. The
array index will underflow unless the two global variables
`g_CdVolumeTable` and `g_VolumeTable` gets merged
As discovered in [one of the recent PSP
functions](https://decomp.me/scratch/thtl9), the types for
`g_LayoutObjHorizontal` and `g_LayoutObjVertical` are not of
`LayoutObject*` but `u16*`. This saves some awkward casts that caused
Clang and modern GCC to fail to compile some recent code (specifically
`((u16*)g_LayoutObjVertical) = ` being not valid C).
This is a bit sad as it reverts part of the changes from #1166 that
aimed to improve code clarity.
This one had some small differences in MAD and ST0, so I worked them in
as ifdef.
Also, I cleaned up the function a bit, by removing the unneeded
pointers.
The GoldSizeIndex local variable is unneeded. It is possible to just use
the goldSize argument, and do `-=2`, but I think using the local
variable makes it more readable, so I left it in place.
Made a small tweak to mwccgap so that we don't compile a .c file twice
if we don't need to... compiling psp used to take 2.7s and now takes
2.0s on my laptop - so not super noticeable at this point, but makes
sense not to compile things twice!
Also added sha1sum for the wrp.bin to avoid people copying in the wrong
file and having a bad time (dont know why I didnt catch that pspeu means
psp eu.. not psp us!)
This is an entity that is in every overlay, but appears to be unused, at
least so far.
It looks just like Gaibon's big fireball (in his second form), but that
is handled by a different entity. Presumably we will find its use in a
future overlay.
I also made some general improvements to the function, such as turning
the weird bit shifting into a simple division by 4, thus eliminating the
variables. I also created an entity extension for this entity.
Another victory for my automated deduplicator.
Another nice de-duplication. Cool to dig into these functions and see
what they do.
Continuing working on my automated de-duplication script. This one was
definitely much easier because of it. I didn't have to track down a
single symbol. In fact, most of my time putting this together was just
commenting in the .h file.
This spawns several copies of EntityUnkId14, very similarly to the
existing EntityUnkId15Spawner.
Most of the work for this PR (renaming all the functions,
cross-referencing symbols across overlays) was done by an automated
script I made. I am still testing this script, but it is nice to see
that it appears to be starting to work. I will test it on a few more
de-duplication PRs, and then consider adding it to the `tools`
directory.
Fairly standard function de-duplication PR. Starting to get kind of good
at these! I might look into automating parts of this process to make it
go faster...
Next I'll be doing the unkId14 spawner, which is just like the existing
unkid15 spawner.
Found this function which is in every overlay, and is a dependency of
another function I'd like to de-duplicate.
See the comment on the .h file for a description of what this function
appears to do. I think the fact that it's taking the entity's position,
offsetting it based on the provided array, and running CheckCollision
makes CheckColliderOffsets a reasonable name without being too verbose.
Happy to use a different name if anyone has opinions.
This function had been decompiled in a few overlays, but was still
INCLUDE_ASM in others, so this will also unify them to all be
decompiled.
Noticed these in the duplicates list. These are different from the
existing EntityEquipItemDrop, but they match each other.
I took the function from `wrp/e_collect.c` and pasted it in, and then
made adjustments until it matched.
Probably not worth de-duplicating. I left comments at the top of these
functions though, as future reminders.
When decompiling MAD TestCollisions in my last PR, I noticed that the
call to BottomCornerText was going to func_80198BC8 in MAD, which was
not yet decompiled.
The duplicates report indicated that func_80198BC8 was a duplicate of
func_97000_8017AB54, a weapon function that I decompiled a few weeks
ago.
I copied the code for that function into here, and renamed it to
BottomCornerText to match the other overlays, even though it's not the
exact same code as is used in other overlays.
This should finish out the set :)
Can't say I understand the differences here (it's modifying
g_CastleFlags during the item drop randomization routine for crying out
loud) but hey, a match is a match.
Got this one done too! ST0 is slightly simpler than the others.
I tried to adapt the existing matching TestCollisions directly, but I
found that it was easier to work on PSP to get the logic right and then
move to PSX instead.
I think I did this right, but this is my first time de-duplicating a
function, so please point out any mistakes :)
ST0 not included because it has different logic internally - will work
on decompiling that one next.
Well here we are, TestCollisions matching!
I'm going to start with this one, and once it's in, I will follow up by
de-duplicating it.
Please review this closely, especially the changes that are happening in
other files than the main C file.
I suspect we will learn a lot from studying this function; I've already
made some changes (including to the Entity struct) but there will surely
be more.
Nice that this was possible with only two `goto` statements.
I expect a fair bit of revision here, especially related to any
enums/defines I might not be aware of. Please be liberal with comments
:)
Same as #1181 but on PSX. The imported data falls right at the top of
each new file based on some old assumptions of mine, suggesting we're
probably on the right track.
A massive PR, I know. It's the smallest change I could do to make this
happen.
After comparing the function order from both ST/WRP PSX and ST/WRP PSP,
I was able to come up with a file split much different from the one
suggested from Splat. It still returns an 🆗 and it follows the same
group functions order from the two game builds.
As soon as we are on board with the C names, next PR will be to do the
same with the PSX overlay. Then in another PR we will be able to start
merging the C files between the two builds. Ideally the same approach
can be used for sharing C files across the different overlays instead of
relying to floating header files in `src/st`
Thanks to @sozud for the hint and @bismurphy for the refactoring idea.
The function `PreventEntityFromRespawning` on PSP hints that the struct
starts 8 bytes earlier. Also there's a missing `nop` at
`PreventEntityFromRespawning`, suggesting the function had to be moved
to the previous function.
I noticed that this struct had some overlap with other values in memory,
so I have pulled all those values into this struct.
The boundaries of this struct are uncertain and are a matter of ongoing
research.
I get
```
mipsel-linux-gnu-ld: build/pspeu/src/st/wrp_psp/BF50.c.o: in function `FallEntity':
(.text+0x0): undefined reference to `g_CurrentEntity'
mipsel-linux-gnu-ld: (.text+0x4): undefined reference to `g_CurrentEntity'
mipsel-linux-gnu-ld: (.text+0x1c): undefined reference to `g_CurrentEntity'
mipsel-linux-gnu-ld: (.text+0x20): undefined reference to `g_CurrentEntity'
```
Not sure what the issue is
Extract ST/WRP out of #1119 . All the function symbols should have been
cross-referenced. There as some PSX functions missing from PSP and some
new functions from PSP that are not present on PSX (e.g.
`st_init_wrp.c`).
The files `st_debug.c` and `e_breakable.c` are shared between WRP PSX
and WRP PSP. Everything else from PSP is isolated into its own folder. I
had to do some tricks on the YAML config to allow shared code.
`ST_WRP_MERGE = st_debug e_breakable` in the `Makefile` is a bit
annoying as MWCC complains about every single minute detail from the C
source that has been already decompiled for the PSX US build.
`EntityWarpSmallRocks` is matching on PSP but I couldn't extract the
rodata without having a bunch of linker errors. This might be a Splat
issue. I need to investigate further.
`func_psp_09244760` is soooo interesting. The values from `0x11` to
`0x17` matches the Entity IDs that are unique to the WRP overlay. This
aligns to what we have in `typedef enum EntityIDs`.
Overall I am very excited to the recent discoveries from the PSP build!
This organizes funcitons believed to be originally found in `entity.c`
into an equivalent `entity.h` based on the research of @Xeeynamo:
* `DestroyEntity`
* `DestroyEntitiesFromIndex`
* `AnimateEntity`
* `PreventEntityFromRespawning`
Includes `entity.h` in place of stage implementations or ASM.
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
Discovered in #1167, where when the player approaches the red door it
forces the input. The line `g_Player.padPressed = g_Player.padSim;`
makes it even more obvious.
This needs to be rebased upon the other PR, otherwise it will break the
build if merged.
Pulls out `CreateEntityFromLayout`, `CreateEntityWhenInVerticalRange`,
`CreateEntityWhenInHorizontalRange`, `FindFirstEntityToTheRight`,
`FindFirstEntityToTheLeft`, `CreateEntitiesToTheRight`,
`CreateEntitiesToTheLeft`, `FindFirstEntityAbove`,
`FindFirstEntityBelow`, `CreateEntitiesAbove`, `CreateEntitiesBelow`,
`InitRoomEntities`, `UpdateRoomPosition`,
`CreateEntityFromCurrentEntity`, `CreateEntityFromEntity`,
`EntityIsNearPlayer`, and `InitializeEntity` into headers to share the
implementation between stages.
`libstage.h` is a new header intended to bring in a sequential block of
functions shared by all stages.
`st_private.h` is a new header intended for declaring symbols used by
all stages that aren't otherwise accessible to code outside of a stage.
The only discrepency is `MAD` which has a unique implementation of
`CreateEntitiesToTheLeft`. Instead of being able to blanket include
`libstage.h` it needs to bring in individual headers before and after
its implementation.
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
This change renames functions and global stage variables uniformly
across the stages so that these functions can be pulled out and shared
across all of the stages. Based on some other tests there are 12 or so
functions that this will allow to be pulled out of each stage. Since
these implementations are shared, an additional 12 asm functions can be
eliminated in a subsequent pass.
**Vars**
* `g_pStObjLayoutHorizontal` - a horizontally sorted array of stage
entities
* `g_pStObjLayoutVertical` - a vertically sorted array of stage entities
* `g_LayoutObjHorizontal` - a pointer to a `LayoutEntity` in
`g_pStObjLayoutHorizontal`
* `g_LayoutObjVertical` - a pointer to a `LayoutEntity` in
`g_pStObjLayoutVertical`
* `g_LayoutObjPosHorizontal` - the direction last traversed in
`g_LayoutObjHorizontal`
* `g_LayoutObjPosVertical` - the direction last traversed in
`g_pStObjLayoutVertical `
**Functions**
* `FindFirstEntityToTheRight` - given an `x` position, update
`g_LayoutObjHorizontal` with the first entity to the right of `x`
* `FindFirstEntityToTheLeft` - given a `x` position, update
`g_LayoutObjHorizontal` with the first entity to the left of `x`
(backwards)
* `CreateEntitiesToTheRight` - given an `x` position, create all
entities to the right (mutates `g_LayoutObjHorizontal`)
* `CreateEntitiesToTheLeft` - given an `x` position, create all entities
to the left (mutates `g_LayoutObjHorizontal`)
* `FindFirstEntityAbove` - given an `y` position, update
`g_LayoutObjVertical ` with the first entity to the above of `y`
* `FindFirstEntityBelow` - given an `y` position, update
`g_LayoutObjVertical ` with the first entity to the below of `y`
* `CreateEntitiesAbove` - given an `y` position, create all entities
above (mutates `g_LayoutObjVertical`)
* `CreateEntitiesBelow` - given an `y` position, create all entities
beneath (mutates `g_LayoutObjVertical`)
* `UpdateRoomPosition` - look at the current game loop scroll delta and
create any entities given the room layout
I believe all of these implementations are shared across all stages
(including `InitRoomEntities`, and two more `CreateEntity` functions)
(in my initial tests I had a small difference in `DER`, but I believe
that had to do with an incorrect symbol table change).
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
Based on their use in the game loop and during stage updates, it appears
the renamed variables store the scroll position delta for the current
loop and store off the current position for future delta calculation.
These vars are then used by stage code to determine if any entities need
to be created or destroyed based on the new position.
Thanks a lot to @SestrenExsis for doing the majority of the function
matching! I only take the credit for cross-referencing it with the PSP
counterpart and massaging the code until I got a match on PSX.
Based on Sozud's scratch (https://decomp.me/scratch/zVBXP), I got the
function to match, and then confirmed that it also matches on PSX.
I also discovered a few improvements, especially in changing
`D_8016FCC0[entityId];` to instead be
`((PfnEntityUpdate*)FAMILIAR_PTR)[entity->entityId - 0xD0];`
While I was at it, I also updated the D_80170000 variable from a void*
to be g_ServantDesc, just like we have in the servant overlay. The
ServantDesc struct only exists in servant.h, so we update that as well.
Finally, we move g_Weapon to not be at 80170000, since it doesn't belong
there.
Highlights:
* `abs` is a real function the compiler can optimise and inline (thanks
@Mc-muffin for the discovery)
* `-Op` is required to avoid using `div` when dividing integer numbers
* A file split in TT_000 is required to match on PSP
* `UpdateAnim` had the wrong signature
* Splatting the PSP build has been an excellent idea
More PSP matches and a lot of fixes on types and symbols from the PSX
counterpart. I am very happy with the results so far.
`func_80173F74` has some weird `#ifdef VERSION_PSP` I cannot remove. Any
help will be very welcomed.
OK. Here goes. Version 0.0.1 alpha of the MWCC Global Assembly Processor
(mwccgap). It's currently very simple/limited, but it appears to work
for `src/servant/tt_000/10E8.c`.
There is lot more that can be done to improve mwccgap - i.e. supporting
.rodata migration would be a good addition, but let's see how far we can
get with it in it's current state.
Note that the Makefile could do with some improvements - we don't nede
to use mwccgap for any C file that *dont* have INCLUDE_ASM macros (it's
a waste of time) so these could be ignored, i.e. for SSSV I do something
like this to find the files that need fixing up:
```
GLOBAL_ASM_C_FILES := $(shell $(GREP) GLOBAL_ASM $(SRC_DIR) </dev/null 2>/dev/null)
```
.. although this is perhaps too simple given that SOTN has a mix of PSP
and PSX functions (and therefore there may be INCLUDE_ASM for a PSX
function but none for PSP functions...
This follows the model of
#[`collect_hearts.h`](../blob/master/src/st/collect_heart.h) to reuse
the `CollectHeartVessel` implementation across stages that use the same
implementation.
This adds implementations for CEN and WRP as well.
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
This replaces several dozen BIOS trampolines from the extracted ASM to
"decompiled" source. These are modeled on the `INCLUDE_ASM` macro, but
generate the instructions necessary for each trampoline directly instead
of importing an extracted source file.
Because these trampolines never return, and GCC 2.6 doesnt appear to
have builtins for leaving off the return jump postamble, these will
likely need to remain assembly.
This also changes the `main.elf` target to depend on `main.ld`, and
undefined symbols files, allowing `make build` to regenerate those files
if necessary.
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
As noted in the comment, this is closely related to BottomCornerText,
which exists in the overlays. It shows the text boxes in the lower left
and lower right corners of the screen (an item you picked up, an enemy
you encountered, etc).
I'm not sure how this is triggered in relation to food (I'll see when I
decompile the caller), but there it is. The logic is weird since it
parses characters two at a time.
I tried to make a symbol definition for this function, but it didn't
work. Leaving my attempt in place to show what I did; I can remove it if
desired, or do whatever is needed to rename functions in the weapon
overlays. Anything works.
Having `platform: psx` will not correctly disassemble PSP functions with
opcodes that are not part of the R3000 (the PSX CPU) architecture. These
functions would be disassembled by Splat as a bunch of `.word
0xBLAHBLAH`.
Changing the platform to `psp` introduces all sort of new challenges.
Function prototypes needs to be declared earlier. But also the MWCC
compiler will not accept the `%lo` and `%hi` dialect from GNU AS. There
were some patches on `mwcpp.py` to use `la SYMBOL_NAME` that would
expand into a `lui / addiu` combo. But even though symbols needs to be
declared like function prototypes at the top of the file. This is simply
not feasible on bigger overlays.
As a solution to the problem above, I replaced the existing patches by
converting instructions into `.word`. The overlay cannot longer be
relocated with this approach, but it is not an issue as the final goal
is to decompile these functions any way.
The labels in the jump table has the same problem, which forced me to
change the segment type from `rodata` to `data.
This is just another single step to create the conditions to start
including bigger re-compilable PSP overlays. I am sure the `mwcpp.py`
solution will be thrown into the bin at some point, but this PR improves
our current situation.
This improves the function readability from the already decompiled PSX
functions. Since the PSP build is compiled with `-O0`, the statement
order is much clearer. Even `if (entity->facingLeft != 0)` and `if
(!entity->facingLeft)` produces different output on the PSP build. I was
able to remove a couple of temp variables too.
---
There are a few functions I cannot match due to a trailing `nop` at the
end of the function. It looks like the overlay have functions aligned by
`8`. I do not know how to trigger that using MWCC or if it is a linker
thing. Two functions that have this problem are `DestroyEntity` and
`func_801746A0`.
![image](https://github.com/Xeeynamo/sotn-decomp/assets/6128729/754fe1ef-5d2d-4b86-a3fb-736a8058347d)
TT_000 is the first overlay from PlayStation 1 that we are now able to
compile from the source and produce a 1:1 binary. This lead me to start
exploring the same overlay from the game Castlevania: Dracula X
Chronicles, which contains a PSP re-build of Symphony of the Night.
This PR adds all the infrastructure to add the same flow for a PSP
matching decomp. Use `export VERSION=pspeu` and then the usual `sotn`
command to splat the overlay, build it and check if it matches. Running
`make extract_disk` should not be necessary as the same ISO used from
`VERSION=hd` is also used for `pspeu`, so you will probably have it
extracted already.
Some important notes about the PSP build:
* The whole PSP build seems to be compiled with `-O0`, which makes it
much easier to decompile
* Having ŧhe PSX, PSP and Saturn builds will allow to easily
cross-reference the code and reduce fake matches
* `disks/pspeu/PSP_GAME/USRDIR/res/ps/hdbin/tt_000.bin` is the HD PSX
build
* `disks/pspeu/PSP_GAME/USRDIR/res/ps/PSPBIN/tt_000.bin` has the same
code from the HD build, but for PSP
* `disks/pspeu/PSP_GAME/USRDIR/res/ps/PACK_E/TP00.BIN` is the same as
above, but it packs both overlay and graphics. This is the file the PSP
game seems to actually use
* The PSP build uses the Metrowerk CodeWarrior's C compiler, which is
very different from the GCC one used on PSX.
* Thanks to @mkst lead, we found a way to still use the GNU assembler
and linker
* MWCC uses [wibo](https://github.com/decompals/WiBo/), a think
compatibility layer to run Windows CLI tools on Linux. It is much more
lightweight than Wine.
* MWCC does not support the `INCLUDE_ASM` dialect, so the custom
pre-processor `tools/mwcpp` had to be created
* The exact MWCC compiler version is unknown, but I suspect it is `build
147`
* I am not yet sure of any implications for using GNU AS and GNU LD
instead of the MW correspondent tools
* Not all the functions can be correctly disassembled, spimdisasm will
just produce a bunch of `.word 0x________` due to the in-progress effort
of adding the Allegrex-specific opcodes support
---
TO-DO list before marking the PR as ready:
- [X] Add PSP build to the CI
- [x] Add progress reporting to the PSP build
- [x] Integrate source file from `src/servant/tt_000_psp` to
`src/servant/tt_000` to promote the psp build as first-citizen
---
TO-DO in a follow-up PR:
* Figure out what `header` is: can we extract it as assembly code? or
maybe as custom re-compilable asset via splat? Is it a MW stuff or a
Castlevania-specific file?
* Get rid of the last line in `Makefile.psp.mk`
100% decompiled.
`US` adds some padding to have the file exactly 40KB long. The HD
version does not add any padding, hence why I ended up producing
`tt_000_raw.bin`. I would have used just `tt_000.bin` as a name as found
in `disks/pspeu/PSP_GAME/USRDIR/res/ps/hdbin/tt_000.bin`, but on
Windows-based file system it would collide with `TT_000.BIN` due to the
OS having case insensitive names.
I modified `make clean` as I found annoying that `VERSION=hd make clean`
would wipe out `us` build stuff.
The only different function in HD is `ProcessEvent`, which has a weaker
check. Another hint suggesting HD being older than US.
`s32 _unused[26];` added enough padding in the bss section to get an
🆗 . I am pretty sure it is unused data because the final binary is
not aligned by any power of 2.
Big thanks to @mkst and @Xeeynamo for looking into my rodata issue on
this one! Still not sure why it worked the way it did but glad we got it
working and we can now get this function in.
Solves an annoying fake match that made the US version to match but not
in the HD version. Special thanks to @Gillou68310 for figuring out the
right switch/case pattern!
Don't get fooled by the size of this function. I struggled more than I
thought I would. I think it generates the map bitmap but I am not yet
sure. There is a lot that I still do not understand of how the map gets
filled while walking through the castle. I do not even know how
partially explored maps work (e.g. when you get the Castle Map 1 or 2
from the Librarian but you do not actually pass by those unexplored
areas). I would like to wait to know more of the logic here before
documenting.
![image](https://github.com/Xeeynamo/sotn-decomp/assets/6128729/e3b9b89c-6a6b-49a9-8804-b0f49da6dc79)
This thing here. Special thanks to @sonicdcer who helped me on the final
reg swaps!
I renamed `D_8003C104` as `g_ClutIds`. I am not a fan of the name, but
it gets used by `poly->clut = g_ClutIds[xyz]`, the function that
populates the table is called `GetClut` and the [official
docs](file:///run/media/xeeynamo/wd_black/SDK/sony_ps1/psyq_sdk/DOCS/LIBREF46.PDF)
mentions _Calculates and returns the texture CLUT ID_ . So that seems to
be the most appropriate name.
A relatively small but complicated function. I matched it by decompiling
from scratch while taking some inspiration from an old scratch made by
@sonicdcer
Some data belong to `7A4D0.c` but I had to import to `7E4BC.c` instead
due to the `factory_blueprint` getting extracted in the between. I think
in the future those JSON assets need to generate C files.
Completes `90264.c` with the exception of the BSS section.
After this PR I am thinking to either decompile and move
`func_8012F178`, `func_8012F83C` and `func_8012F894` into `90264.c` as
they all follow the same pattern, or move back `90264.c` before the
split back into `8D3E8.c` as all the code seem to be related to the wolf
form.
As per title.
`#if !defined(VERSION_PC) && !defined(M2CTX)` allows
`tools/decompile.py` to work on files where the GTE instructions are
used. Otherwise it wouldn't normally work.
Big function, does a bunch of stuff with DRAWENV which is neat.
Had to create an inline for addition, otherwise all my `lh` instructions
were becoming `lhu`. Maybe there's a better solution, I'm not sure.
This is going out to a new file due to weird rodata stuff, I'm hoping
decompiling EntityDraculaFinalForm (which I have a working scratch of)
will allow everything to settle into place, but we'll see.
First function of my new effort to make progress in ST0.
There's a fun bug in case 5 where they forgot to increment their prim.
This required the creation of a new variety of Primitive, since there's
strong evidence of an `f32` at offset 0x20. For now it's
draculaPrimitive, but maybe we'll find more uses of it in the future.
I think those are the main highlights. No pressure to merge this one
quickly, I'm expecting progress on ST0 to be slow.
Another disappointing non-match, even closer than #1008 . There is only
one registry swap in one single line. I've been permuting for a day
without success. Putting this here if anyone wants to give it a try:
https://decomp.me/scratch/AuSvv
There were some symbols overlapping with the `g_Entities` array. By
fixing them I also de-faked `func_801B519C`. I included the removal of
`g_api_AllocPrimitives` too as I did not see much point of doing it in a
separate PR.
I am still unsure of the size of `g_CastleFlags` and unfortunately I
doubt it will be clearer before start decompiling new stage overlays.
A side-project I've been working on that helped me understanding some
structures that are now a bit better documented in #1034 . Richter
sprites are extracted as usual. Doing `python3
tools/splat_ext/spritesheet.py decode disks/us/BIN/ARC_F.BIN assets/arc
alucard disks/us/BIN/F_GAME.BIN 1` can extract Alucard sprites too.
There is no repacking yet as I want to avoid using splat for this one.
Big file shuffle to get this one working, but it works!
I have now made some degree of attempt at every function in RIC. Now we
circle back to finish the hard ones!
Required splitting to a new file.
Yet another instance of PRIM_LINE_G2 using its own type of Primitive,
which is neat.
Also resolved another member of that primitive. This is getting wild!
RIC is so close!
This one was pretty complicated but I'm glad I got it working. Not
completely certain what this does but good enough for now. The two
functions are even more similar than DRA and RIC functions usually are.
For any comments to be made, feel free to only comment on one of the two
instances and I will make the change on both.
Did the DRA version of this a while ago, now here is RIC. Very little
overlap, generally speaking, which kind of surprises me. Anyway, more
progress on RIC!
This monster is finally done thanks to the assistance of @ser-pounce .
Really not sure what any of this logic is for, but there you go. Great
to have more collaboration happening!
------------------
Co-authored-by: ser-pounce <ser-pounce@users.noreply.github.com>
Tried to comment this one pretty heavily since it's a relatively more
comprehensible function than usual.
Otherwise nothing too special or surprising here. I'm surprised at how
case 1 works though, I wonder what condition it's actually testing for.
Oh, and there was one pesky fake variable in there, but it's not too
egregious. It's in case 5.
This is the entity that runs when Richter dies in the prologue, gets
revived, and makes a glowing white pillar effect out from his body. You
can see it at 1:33 here: https://www.youtube.com/watch?v=7_RhQR3aQ_0
It is extremely similar to the column that appears when the cross
subweapon crash is used (visible at 1:15 in the same video), but lacks
the screen-filling giant white flash that comes after. A huge amount of
the code is copy-pasted between these two entities, even the `one` and
`three` variables from the cross entity that was just merged.
It's hard to come up with a good descriptive name for this, but I think
this one is at least good enough.
Similar thing to what I've had a lot of lately - I decompiled the RIC
version, then went through the process of cross-referencing RIC and DRA
to identify the duplicate function. There are a fair number of
differences between these, so it wasn't super straightforward to go from
the RIC match to the DRA match.
There's a lot of weird stuff in these, especially the "one" and "three"
variables. Probably some weirdness that I didn't quite write the same as
the original, but a match is a match.
Scratches here if you'd like to take a crack at any of the weird junk.
RIC: https://decomp.me/scratch/rRANW
DRA: https://decomp.me/scratch/jWF5h
There is already EntityHolyWater in DRA, but this one is quite different
(which makes sense, because Richter's is very different in behavior from
Alucard's). Still, there are some small overlaps here and there.
Due to the ongoing failure to match `func_80166784` (the previous
rodata-using function), this is being split out to a new file, even
though I'm pretty sure they're supposed to be in the same file. We will
reunify the files once `func_80166784` can be solved.
There is a function which is identical in the overlays, and is only used
by this function. I have gone ahead and named it identically in both
overlays.
This one was tricky and required some restructuring of an area of
memory, but it matches now, so that's cool!
No big comments from me but this one has a lot of random stuff so let me
know if I missed some enum or something!
Several things with this one.
1) In order to determine what this actually was, I needed to extract
Richter's subweapon definitions. I decided, at least for now, to add
that extraction for RIC, using the `assets.py` script.
2) In order to match this function, we need a new Primitive, which is
similar to the existing one (and FakePrim) but has a few totally
incompatible fields. Most importantly, we have s16's at offsets 0x0C and
0x0E, which don't match either of those. Therefore, I introduce a new
primitive that I am, at least for now, calling PrimLineG2, since this is
the first time we're using LineG2, and is also the first use of this
struct, so those may be connected. If a different primitive is found
using these fields, we can rename this.
3) Recognizing that we now have 3 different varieties of Primitive, I
have taken the definitions for all of them and moved them to a dedicated
`primitive.h`, which I think is a good home for them. We should rename
the variations eventually, but having them in one place makes sense, I
think.
Otherwise, this one is fairly straightforward. It's interesting that we
have the hardcoded values for the color of the hydro storm rain in there
- using this knowledge I have made a fun PR for the randomizer which
randomizes the colors of the rain. That PR is here:
https://github.com/3snowp7im/SotN-Randomizer/pull/121
I think that's about it!
Again, huge thanks to @ser-pounce for figuring out the final puzzle on
this function!
Getting this in and parsing all the rodata before and after meant I
discovered some different file splits, but now it's all set, with no
`const s32 rodata_padding` type of stuff, which is great.
I imagine having this working will be a great resource for learning more
about how Richter works.
I've been wanting to match this for a long time. I matched it by pure
coincidence by moving things around. This is one of the few functions
were the permuter was completely useless.
The function renders a room tilemap, with its background and foreground
layers. This is also the first function that uses the PlayStation 1
scratchpad. It took me a few trials to understand how to use it. This
match gives me the confidence to match the much bigger functions
`RenderPrimitives` and `RenderEntities`. They will be my next targets.
I noticed there were a few wrongs in the rendering system. I used one of
the PSY-Q SDK samples to help me understanding how to implement
`PutDrawEnv` and how to render a `SPRT`. The stealth changes in this PR
aims to easily have the tilemap rendering working. The map currently
appears black. This is not a regression, but the lack of logic of
loading a room.
[EquipKind](https://discord.com/channels/1079389589950705684/1087866009983139870/1196073673392652388)
group decision
[drawMode](https://discord.com/channels/1079389589950705684/1087866009983139870/1197935480428302476)
group decision
I was thinking a more soft PR, but in the light of `BLEND_VISIBLE` to
`DRAW_HIDE`, a mass rename would have happened anyway. So I decided to
rename everything since the majority of the code stands on the same line
of `BLEND_VISIBLE`.
The only changes other than the mass rename are:
```c
#define blendMode drawMode // maintained to easily migrate existing scratches
```
this might or not be useful
.
```c
#define DRAW_DEFAULT 0x00
#define DRAW_TRANSP 0x01 // make it semi transparent
#define DRAW_COLORS 0x04 // use color blending
#define DRAW_HIDE 0x08 // do not render the primitive
#define DRAW_TPAGE 0x10 // use custom tpage
#define DRAW_NOMENU 0x80 // do not render if D_800973EC is set
#define DRAW_ABSPOS 0x2000 // use absolute coordinates with DRAW_NOMENU
```
This is based on the research from the
[RenderPrimitives](https://decomp.me/scratch/geI8L) function.
This was a community effort relying on the work of myself, @ser-pounce ,
@Xeeynamo , and others. Thanks all for helping to put this together and
it will be very exciting to have such a large and important function in
the repo!
Lots of room for improving this one in terms of code style, but having a
baseline functional version in is huge.
These functions both have very difficult functions before them in their
files, so need to split to new files to make the rodata work.
Originally decompiled RIC func_80166060, then once that was done I dug
through the blueprints and realized it matches EntityTeleport, which
made decompiling EntityTeleport an easy task, at which point I renamed
the RIC function to match.
I've also gone through a lot of the functions they call and labeled the
ones that match between overlays; I expect this to be helpful in the
task of identifying names for a bunch more functions.
Decompile and de-duplicate EntityStageNamePopup for all the overlays the
function is in.
I also detected a helper function I renamed as `PrimDecreaseBrightness`
that was originally accepting a completely wrong parameter type. This
helped me to get rid of `Unkstruct_80128BBC` too.
Progress on RIC has been hugely beneficial for solving some old DRA
functions. I'm going to start going through all the entities and try to
identify all of the ones that are in common between the two. I tried
this one in DRA a long time ago, but once I identified the
correspondence between these two functions, having the RIC version
available made things a HUGE amount easier.
One very important thing in the analysis of these functions: Take a look
at the RIC version, func_80160FC4:
https://github.com/Xeeynamo/sotn-decomp/blob/master/src/ric/24788.c#L260
The first thing the function does is it loads paramsLo and paramsHi.
Then there is an if-statement which takes paramsHi into account.
But in this new function, those variables aren't given values until the
switch statement. This means that in the if-statement, paramsHi is not
initialized and will be undefined. I believe this is a bug, but would
like to hear someone else's thoughts before giving it an official bug
label.
Working in parallel on these two overlays has been hugely beneficial, I
think I will continue to try to do things this way.
I don't think I have any major comments besides that. This code required
more fake stuff than usual in order to make registers agree.
Originally decompiled this for RIC, then in the process of figuring out
what this entity was, I realized it was a duplicate of one in DRA which
was already named EntityHitByIce. Therefore, I have gone ahead and
decompiled it for DRA as well.
I think there are a whole lot more functions that are duplicated between
RIC and DRA, but there are enough subtle differences that the
duplicate-finder script misses them.
Because of the close relation between this and AlucardHandleDamage and a
previously-unnamed RIC function, I have named that function
RichterHandleDamage to match.
This is a pretty big one!
There are a lot of unknown SFX entries, I'll leave that as a future
thing to work out what all the hex codes for the sounds are.
Pulling in the rodata gave the usual mismatch with 00 bytes, so I moved
the following C file into this one.
Several other changes here and there, this is a fairly large commit so
please be sure to examine it carefully.
I need help on this pull request. While it matches as it is, I cannot
decode the Japanese strings from bytes to UTF-8 convertible into
Shift-JIS into a C file that is able to give me an `OK`. I think the
problem lies on how Python decodes Shift-JIS byte arrays.
I [wrote a
tool](https://gist.github.com/Xeeynamo/d75c73431eaf54b42f955ca8740bb754)
to automate the process:
```bash
python3 sotn_config.py > src/dra/config_jp.c && make
```
To extract some of the strings as Shift-JIS, uncomment the first line at
the function `get_sjis_str`. I am tempted to make a custom decoder. But
first I want to gather your insight in case I am missing something
obvious.
Imports the `D_800C1ECC` table straight into `953A0.c`, so
`ApplyQuadChannelSetting` can populate the fields correctly.
Also removes a fake symbol from `menu.c`, which allows to access the new
merged `g_ChButton` array correctly. This fixes the _"Button Settings"_
sub-menu in _"System"_
The function is not referenced anywhere other than by being exported in
`GameAPI`. I suspect only the LIB overlay uses it. I added a comment
speculating what the function might be about.
Came across this function today and found several improvements for it.
- Unkstruct_800FD5BC is a duplicate of DamageParam. Therefore, I have
changed all instances of Unkstruct_800FD5BC to DamageParam. The fields
make sense in context and everything.
- Because func_800FD5BC is in GameApi, which is defined in `game.h`, its
argument (now a DamageParam) needs to be accessible in `game.h`.
Therefore, DamageParam moves from dra.h to game.h.
- We had a fake division being done with using a `temp` and checking a
comparison to zero; this has been changed to be a normal division. This
is a common pattern I see in initial m2c output and I'm sure it exists
in other places in the repo, would be nice if we could find an automated
way to search for this type of structure to simplify the code.
- Changed a 0x14 to 20 since it makes way more sense that way
- Changed an `if(){dostuff; return} else{morestuff}` to just
`if(){dostuff; return} morestuff`, eliminating the `else`
I think this function should not be in `menu.c` since it has no close
connection to any kind of menu. It would also be nice if we could figure
out what damageKind actually is, and maybe make an enum for it.
Overall, no new decompiling here, but lots of improvement to the
readability of the code. This might actually be a good PR to keep in
mind as an example for people who are interested in the project but
aren't comfortable with assembly, since this is a lot of improvement and
change, without touching assembly at all.
Some deduping and renaming that might help later
- Dedupe DestroyEntity
- Dedupe ST EntityIsNearPlayer
- Dedupe DestroyEntitiesFromIndex
- Dedupe ST CollectHeart
- Dedupe ST UnkEntityFunc0
- Decompile + rename rwrp EntityExplosionSpawn
Comment describes what this function is for. I identified it by setting
a breakpoint in an emulator and waiting for it to trigger, then verified
by NOP-ing it out.
Here is a screenshot of the sparkle appearing:
![image](https://github.com/Xeeynamo/sotn-decomp/assets/15314202/d071e946-b012-4878-a050-41ada78fe2bc)
This is the last function using rodata in 32324.c. However, once I
decompiled it and did the normal rodata steps, I had a mismatch of `00
00 00 00` bytes, which signalled that this should not be the end of the
file. Therefore, I pulled 345EC.c into this file, which now matches.
Function scratch is here: https://decomp.me/scratch/PSKCu
My main goal was to extract the .data for the table in RIC, but while I
was doing that, I also decided to clean things up a bit, so now:
- Both tables have proper names
- Both tables have all the entities forward-declared in the proper .h
file
- Attempted to remove all repeated forward-declarations in the .h file,
not sure if I got them all
Overall this should improve readability and should be pretty close to
how I would expect the original game to have done it.
I noticed that there was a mismatch in the rodata where a set of 4 `00`
bytes was being skipped, and those indicate that these should be the
same file.
This is one of the few remaining sound functions.
It calls `ApplyQuadChannelSetting` and `func_80135624` in extremely
similar ways, so I've adjusted the arguments to those functions so they
match. `func_80135624` should probably get its own name which is similar
to `ApplyQuadChannelSetting`, but I don't know enough about these
functions to actually tell what it's doing.
One of the few remaining DRA functions.
Some of the code here seems fake, but it matches so I'm going with it. I
tried to change all the pointers to use the loop indexing but it didn't
work. Might have been written by a coder who was more comfortable
working with pointers than with loops.
Simple PR that aims to re-use the same `config_us` file from #948 but
for SEL. The file is de-duplicated since it is identical.
The file `lba_stage` has to be split again since in DRA it comes before
`config_us` but in SEL it comes after. That indicates it could have been
a stand-alone file.
I also imported the exp table responsible for levelling up.
Creates the file `config_us.c` with all the configuration needed for the
game to know where to locate files in the disc (previously
`lba_stage.c`), equipments, accessories, menu strings (previously
`lang_us.c`, , spells, relics and enemy structures. There is also an exp
table for levelling up but I did not import it yet.
This is a major change in the codebase on how we handle assets.
Previously they were exported as JSON in `assets/dra`. The main problem
is that strings were not properly compiled, still relying on hardcoded
offsets expected to be found in the `.rodata` section.
I deducted all those information belong to a single C file because the
same strings in rodata were referenced from equipment to enemies. If
those strings are found in the same C file, the compiler will optimise
duplicated strings by de-duplicating them. This is how I reached the
conclusion of having all those definitions in a single file.
Obviously the major pain point of this is that a JSON was much more
declarative and easy to be consumed. Especially if tools were going to
use those files. Counting the commas with the struct definition on the
side is not the best thing for modding.
I had to comment out the HD `lba_stage` as it would require a major work
to support the Japanese text.
I had to merge `2C048.c`, `2D260.c` and `2EED8.c`. The hint was in a
string that had to be in `2C048.c` but it was also used in the other two
files. I couldn't still merge this with `33164.c` due to the same
problem I described in #946 .
EDIT: I kept importing more data. SEL also contains its own `lba_stage`,
but some offsets and OVL size are out of sync compared to DRA. I have
the suspect the table was manually maintained, unlike our _"top class
engineering"_
I spent some time trying to merge `2EED8` and `33164` as the rodata
seems to suggest it. But there is a weird 4-bytes padding that is added
when the file split does NOT happen. If you want to have a look before
merging this, please do.
This is a historical W.I.P. that held me back due to some dirty bytes in
the US version. It is now done.
I renamed the file to `lba_stage.c` as I plan to add another file called
`lba_bin.c` right after this PR.
To quickly build the HD LBA, which is very different, I wrote a quick
script to duplicate and patch the US one:
```python
def s16(f):
return int.from_bytes(f.read(2), byteorder='little', signed=False)
def s32(f):
return int.from_bytes(f.read(4), byteorder='little', signed=False)
with open("disks/pspeu/PSP_GAME/USRDIR/res/ps/hdbin/dra.bin", "rb") as f:
f.seek(0x3C50)
for i in range(0, 0x50):
print(f"0x{s32(f):04X}, 0x{s32(f):04X}, 0x{s32(f):05X}, 0x{s32(f):04X}, 0x{s32(f):04X}, 0x{s32(f):05X}, 0x{s32(f):04X},")
s32(f)
s32(f)
s32(f)
s32(f)
```
---------
Co-authored-by: sozud <122322823+sozud@users.noreply.github.com>
Found this function in RIC, it's very similar to the one in DRA, which
is nice.
Patterns of zeros in the rodata indicated that this should be the start
of a new file, which also makes sense since CreateEntFactoryFromEntity
comes with it.
RIC has its own array of blueprints, I'll probably add that to the splat
later on but that seems like material for a separate PR. For now we
focus on the entity function.
This appears to control Richter using an item crash.
We add an enum for the subweapon IDs. This should be useful in other
places but for now makes the switch much more readable.
Loops in EntityAlucard and UpdateEntityRichter indicate that these 16
elements of g_Player are an array of 16 values. The known ones appear to
be player status effect timers.
While those functions have a long-standing issue preventing them from
matching, they provide enough evidence to suggest that we should make
this change. I have changed all existing uses, and changed the symbols
so that any remaining non-decompiled functions will use the proper form.
It would probably be beneficial to make an enum for the 16 elements of
this new array, but I'll hold off on that for now until we can identify
the purpose of more of them.
---------
Co-authored-by: Luciano Ciccariello <Xeeynamo@users.noreply.github.com>
This one has a corresponding DRA function. I believe these relate to the
fading shadows that appear behind the player, but I'm not confident
enough about that to go ahead and rename things. For now, it's
decompiled at least.
I had the suspect menu strings were part of a string of arrays since a
while. So I come up with a `g_MenuStr[]`, which removed the need of many
fake symbols. I did not yet come with a bunch of `#define`s to resolve
some magic numbers. Luckily you can guess which string is which from the
context of the function. Resolving the HD strings might give me more
clues on how to come up with good defines.
I decided to go for the route of having a `lang_us.c` and a `lang_jp.c`
for the sake of maintaining things simpler. This is also due to the fact
the HD build orders the japanese strings in a different way, making
things a bit harder. Any modder can just come up with their own
`lang_XX.c`, translate the menu in the language they want and just link
it, without touching the original files.
For the test app things were tricky. I've been debating how to implement
it as SOTN-encoded strings are not pre-encoded on compilation time like
the PSX toolchain does. Instead they are burnt into the executable as
UTF-8 characters. Instead of encoding them on-the-fly in `MenuDrawChar`,
I decided to re-use `AnsiToSotnMenuString` to pre-encode all the strings
and re-route each `g_MenuStr` pointer to the converted strings. This is
both efficient at runtime and prevents to modify the existing matching
code. Now the menu looks amazing.
I thought this was going to be much harder to do. I ended up doing
incremental steps in each commit to ensure having healthy checkpoints in
case things were going south. The tool ` ./tools/sotn-str.py parse
disks/us/DRA.BIN 0xOFFSET` saved me sooo much time. But we need to tweak
it to deal with Japanese characters.
This one was very complicated. It has 4 different switches in it, all
with their own rodata!
It also interacts with a lot of different parts of the game, including
various unknown members of structs like g_Player, so it might be a
useful resource for starting to understand what some of that stuff is.
One goto left in it that I couldn't get rid of, the jump is between two
unexpected locations that seem very different from each other.
Scratch here if anyone would like to attempt improvements:
https://decomp.me/scratch/0k84D
Not totally sure what this one is for, but it's connected to saving the
game.
D_801379C8.vy is very heavily used, I'm not sure what the purpose of
that SVECTOR is. But anyway, it matches.
Mostly a proof of concept to extract resources from `BIN/F_GAME.BIN`.
There are tons of hacks to make this work:
* Tweaked png2s to decode binaries into PNGs
* Add a `config/gfx.game.json` that describes how to extract different
sprites out of a binary file
* Coded the palette location by reading the `clut` parameter in the
source code. A clut value of `0x196` corresponds to `"palette": "0x96"`
or `"palette": 150`.
* Coded the bits per pixel for a couple of 8-bit images
* Coded the palette location of those graphics that expects the palette
from DRA.BIN instead of F_GAME.BIN
* For all the undiscovered palette, I called the files `unk` and
defaulted their palette to grey
The expectation is that sprites will slowly be documented and added into
`config/gfx.game.json` by modders and enthusiasts. This does not yet
pack back these PNGs into the binary file. The way these assets are
extracted is probably not final or perfect, but we have to start from
somewhere.
![image](https://github.com/Xeeynamo/sotn-decomp/assets/6128729/ce12ad2d-d95d-41e8-ac31-186cd36ac965)
The next subweapon entity. This is for the lightning subweapon. Happy to
take name suggestions but for now we have a comment on the function so
doesn't really matter if we name it immediately.
Remove a bunch of fake symbols that were overlapping with `D_80097488`.
I created a new struct called `Pos`. Since it is very similar to
`Camera` I placed them close-by as in future we might want to merge
them.
I created some symbol hints like `D_8009748A_x_i_hi` as there are a few
functions that still use them.
Nothing super special here, just another RIC function. I believe this is
a helper function for Richter's state machine, since it switches on
PLAYER.step_s.
This was done by comparing the src/servant/tt_000/spriteparts.c file to
the data I found in RIC 170AC.data.s. I then wrote a Python script to
take the data in the data file and output a C file which has all the
same formatting as that existing spriteparts.c file. This is a big chunk
of the .data section for RIC, so it's nice to have it pulled out to a C
file now.
The `const int PRIM = -5;` is very weird, I am not sure what's going on
there. The struct makes sense on the surrounding functions. I am not
even sure if the function is ever called as it involves the use of a
cutscene dialogue, never seen in the SEL overlay.
Mostly a duplicate of a DRA function but enough different logic to be
fairly different.
Interesting that this uses the "dead player" string which matches HD but
is different from in US DRA.
There are 3 strings in DRA that were being left in rodata and printed
with `FntPrint(&whatever)`, this fixes two of them (the third will first
require other stuff in rodata before it to be extracted).
I also discovered that HD uses a different string in one of those spots
which was a big surprise! Weirdly, US has a string written in Japanese
(though using Latin characters) and HD has a string written in English.
The function that keeps track of if Richter has pressed down-up-cross to
do a High Jump move.
This is the first time we have a button combo being tracked outside of
DRA, so I moved the ButtonComboState struct from dra.h to game.h.
When the input succeeds, a function is called, so I've named that
function DoHighJump and also made general changes to that function to
bring it up to date with our current code standards (like FIX()).
I think those are the main highlights!
More data importing and more documentation as data is providing more
context.
I also found a good amount of "fake" symbols, like in `DrawHud` and
`DrawHudSubweapon`.
Quite big PR that aims to document most of `menu.c` and make the code
more portable.
I had to declare `u16* func_80106A28(u32 arg0, u16 kind);` on the top of
`main.c`. Without it the compiler assumes it returns an `int`, which is
not big enough for 64-bit pointers. It took me a while to realise that
was the cause of the crash. We will have more of them in the future.
EDIT: Ignore the commit `******* FIX`. It was meant to be squashed for a
clearer commit history but I forgot to do it.
Highlights:
* Move `MenuContextInit` into `main.c`
* Document `Unkstruct_800A2D98` as `EquipMenuHelper`
* Use shorter global variable names
* Change `D_801375CC` type on Saturn
* `g_MenuInit` is different between JP and US due to different window
arrangement and text width differences
As per title. I also added a new tool called `dirt_patch`. As I
mentioned in our Discord server there is some left-over data from
previous dev builds in DRA.BIN and potentially elsewhere too. The tool
uses the new file `config/dirt.us.json` which stores a list of patches
to avoid crazy hacks and `#ifdef` for the sake of getting a match. I
hope this tool will not be abused.
Extract the memory card icons out of DRA.BIN and SEL.BIN.
![image](https://user-images.githubusercontent.com/6128729/227794798-4dd071f9-512b-4c72-8f5d-fcbf7a615519.png)
I also took the opportunity to extract `g_MemcardPortMask` into its own
source file `save_mgr_pre.c`. Unfortunately this is required to keep the
original data order. This suggests that most likely the icon palette and
bitmap were baked into the original `save_mgr.c` as byte arrays. I
decided to take a different approach and extracted them as PNGs for
better moddability.
I had to spin-off Splat into a new fork due to some breaking changes on
0.18.0.
This is actually the last function in RIC (by which I mean "There are no
functions in RIC which are located later in the ROM than this one"), so
that's neat. There was a mistake with the splat, where the nop in the
delay slot for the return instruction of this function was being treated
as the first 4 bytes of SBSS, rather than as the final instruction of
this function, but luckily I worked that out and fixed it in the splat.
This is extremely similar to the one in DRA. However, it stores to 0xB0
in the entity. This is interesting, I've seen that being a significant
address in other RIC functions too. I added it to the extension that was
used for this entity in DRA.
Next entity function in the same file I've been chewing through. Only
one left in here!
There's a really weird block with a bunch of trig functions that I can't
make sense of. Might be doing some kind of weird 3D transformation? Not
sure, but it matches. Would have never gotten it without the permuter.
Scratch here if you want to play with anything, especially if you can
remove the temp_a1 being used in the block of trig.
https://decomp.me/scratch/xdNx7
temp_v0 is also a bit funny, not sure why it would use lhu to load a
variable which is explicitly an s16 and we're negating, but whatever.
Everything matches so submitting now.
Refactoring with no functional changes. `5087C.c` is currently a bloated
file that contains both a game state machine to handle the gameplay and
the menu handler.
This PR splits the menu handler into its own new file `menu.c`.
The way I detected the file split is the amount of `.rodata` strings
defined between the new last function of `5087C.c` and everything else
related to the menu.
This is a pretty big function, and I'll admit that my code for it is
pretty low quality. But it matches. Scratch is here if you'd like to
make improvements:
https://decomp.me/scratch/xok2Z
A lot of the things that I tried to remove the gotos and temp variables
didn't work.
The entity extension for this uses f32 variables. Those are defined in
`game.h`, but `game.h` is not accessible to `entity.h`, so I moved the
definition of f32 to `types.h` which is accessible in all places and
overall seems like a better place for it anyway.
After finding a copy of GetFreeDraEntity in RIC, I decided to rename the
function (in both DRA and RIC) to GetFreeEntity. Similarly, the function
right after it is GetFreeEntityReverse (since its logic runs in
reverse).
I also found CreateEntFactoryFromEntity in RIC, so I renamed that to
match the version in DRA. We will need to go through and use the FACTORY
macro for its uses, but I'm not going to tackle that quite yet.
Seems there is a lot of work to be done making RIC catch up to DRA,
we'll see if I keep working on that moving forward, it's neat to find
the ways the two match.
Another entity function in RIC, continuing to work through these to
remove the rodata padding.
Still no knowledge of what this function is for but once I get these
done I'll focus on getting the entity factory system working in RIC like
we have it in DRA, I've found a lot of the important functions already.
This appears to be an entity updating function unique to RIC. I do not
know what it is for yet.
Main reason for doing it is that it has rodata and the file it is in
currently requires a rodata padding to be present. Having this one
working and parsing the rodata into it means we can move the padding,
and once we finish everything in this file, we will be able to remove
the padding entirely.
As mentioned in the previous PR, this removes a few rodata_padding
variables by simply un-splitting the files involved here.
There are two more paddings I found in other places; I will look into
those next but don't want to do too much file reshuffling in one PR.
This PR takes 3 files and merges them into one, removing the padding in
the process.
Another function, not sure what it really does besides messing with a
bunch of primitives.
Some clues in the rodata (particularly 00 00 00 00 bytes) indicated that
we should merge these C files, so I did.
An issue with maspsx was discovered in the process of decompiling this
one. I submitted a PR to maspsx which was accepted, and therefore I also
updated maspsx in this PR in order to capture the fix.
For some reason this was included as:
```
#if defined(VERSION_US)
INCLUDE_ASM("asm/us/dra/nonmatchings/627C4", func_801028AC);
#elif defined(VERSION_HD)
INCLUDE_ASM("asm/hd/dra/nonmatchings/627C4", func_801028AC);
#endif
```
But that wasn't actually needed, the functions are identical. Not sure
why it was that way but it's fixed now.
- Main focus is an update of func_8015D020. That had a TODO to remove a
variable, which I have now removed. I also used enums for player steps,
and changed the speeds to use FIX(). I also cleaned up the control flow
to remove the goto.
- While working on that function, I noticed that it calls an unnamed
function. The duplicates list at
https://raw.githubusercontent.com/Xeeynamo/sotn-decomp/gh-duplicates/duplicates.txt
indicates that SetSpeedX was missing from RIC. I added that in now and
adjusted all uses in RIC, including the ones in func_8015D020.
That's about it; these are two different changes but given that we're
just changing the format of them, I'm assuming this will not be an issue
to have them in one PR.
Had to add PlayerSteps into RIC since we're using enums for Player.step
and SetPlayerStep. I think maybe these should be moved out of dra.h and
into somewhere more generic, but for now copying it over works well
enough. If there are steps that are reused between Alucard and Richter
for mutually exclusive moves (ie, step N is an Alucard-specific move for
Alucard and a Richter-specific move for Richter) then we will need to
maintain separate lists. This works for now.
Handles a bunch of the internal logic of saving the game. There is a
small group of functions that deal with the process of saving; once we
get them all decompiled it makes sense to rename them once we understand
the individual steps involved.
This appears to generate the menu that appears when you use a save room.
This is obvious by the strings present in the many calls to
`func_800F9D88`.
Appears to be closely related to some other functions which may make the
logic a bit more obvious. Cool to have this working though, might be
useful for some types of research into how saving works. I wonder if all
these messages have actually showed up before for real players.
Many of the strings feature Shift-JIS characters (specifically, the
periods, question marks, and the 0, 1, and 2 numerals). Big thank you to
Sozud for helping me understand those weird bytes in the strings!
Parsing rodata for strings is pretty fun!
Happy to change the name of this function, but wanted to at least
replace the numerical placeholder.
Follow-up to #797 by decompiling the MAD counterpart and share all the
functions within the same file. I renamed the function as
`UnkPrimHelper` as I do not know what it does.
This is an old one that I had almost-matching, I set the permuter
running for a few hours while I was doing something else and came back
to a match!
It appears to be responsible for managing some type of alternate player
status. This is evidenced by the
```
if (!(g_Player.unk0C & 0x10000)) {
DestroyEntity(entity);
return;
}
```
That variable holds statuses like PLAYER_STATUS_STONE,
PLAYER_STATUS_POISON, PLAYER_STATUS_CURSE. We do not have 0x10000
identified yet. The entity is made by an entity factory which currently
does not have any decompiled calls, so hopefully when that happens, we
will know exactly what this entity is responsible for.
Not sure what this one does, but it's in all the overlays.
I couldn't get `mad` to work, since it gives errors when I reference
functions like `RotMatrixZ` (which isn't even one of the new `gte_`
defines). I figured we can leave that for later since `mad` is its own
weird thing.
I also found an issue with the splat for `no3` where some boundaries
were being drawn in the wrong places; this is now corrected which allows
the function to work in that location.
The function takes a primitive as its argument and does some stuff with
it. I don't know what it actually does. It appears that the different
overlays use it in different places (and some overlays don't call it at
all). The function loads an external SVECTOR from a variable, which I
added to the `.h` file for each overlay. The vector is in a weird
location in some overlays, especially in no3 where it appears to be the
last few bytes of the rodata.
Anyway, happy to take naming ideas for either the function or the
SVECTOR that it loads. And I imagine we'll end up renaming those sp
variables.
We have a lot of casts and especially LOH calls in this one. Maybe we're
interpreting the primitive wrong. It doesn't match up with the FakePrim
we've been using lately, so I don't know what to make of this.
I think those are the main highlights! There aren't many functions that
use the GTE and it's nice that there is so much duplication so we can
deal with a lot of them all at once. I expect a lot of changes on this
one so please don't hold back :)
Here's the scratch for one instance of the function, in case you'd like
to play around with anything: https://decomp.me/scratch/N5RR5
This was a weird one. This uses the Geometry Transformation Engine,
which I don't think any previous function has done. It was confusing to
get it working but it seems to work.
I think I put the macros in the right place, but let me know if not.
Overall this is the first PR of this type, so please do make sure
everything looks good so we don't pollute the repo. If this goes in, I
might try to find more of the gte functions so we can crack those all
away. Making this work was difficult and required a lot of SDK research,
so I'm hoping I can do more functions before the knowledge disappears
from my brain :)
---------
Co-authored-by: sozud <122322823+sozud@users.noreply.github.com>
This is a cool one to have working.
It uses the FakePrim struct which we discovered a little while ago. It
is only the second one we've found to use it, and happily, the fields in
it match.
I'm wondering if FakePrim might represent a single pixel. The Vibhuti is
a set of white pixels that get thrown out, and therefore they don't need
a full set of multiple r,g,b values. Once we find a couple more users
for FakePrim, we might be able to give it a proper name. We may need to
consider making Primitive a union. But that's a decision for the future.
Very interestingly, this function and `func_8011E4BC` (the previous
function which used FakePrim) both call func_800EDB58 in the manner that
other functions call AllocPrimitives. This function seems to allocate
FakePrims.
Second last function of TT_000 decompiled.
* Add `printf '\x00' | dd of=$@ bs=1 seek=40959 count=1 conv=notrunc` to
ensure the output binary is 40960 bytes long (useful once BSS is
migrated)
* Add `$(BUILD_DIR)/tt_%.ld` so every time the splat YAML changes, doing
`make tt_000` triggers the extract again
* All the variables from BSS are now in `10E8` and in order. Removing
`extern` from will properly create the BSS section
* Fix 7A4D0.c to not use the familiar entity extension
* Delete the fake symbols `D_80170660` and `D_8017065C`
* Replace all the instances of `ext.generic` as `ext.bat` when possible
NOTES:
* For `SquareRoot12((...) << 0xC) >> 0xC;` I was not able to use the
macro `FLT`
*
Occasional maintenance:
* asm-differ: latest commit
* m2c: latest commit
* maspsx: latest commit
* spimdisasm: 0.18.0 latest
* splat: 0.17.3
The latest version of splat is 0.19.1 but a breaking change in
[0.18.0](https://github.com/ethteck/splat/pull/294) is preventing me to
upgrade further ([discussion
here](https://discord.com/channels/710646040331681844/813939516385525790/1172978921000669274))
Some YAML were malformed and since splat 0.17.0 there are additional
checks to ensure they are compliant. There are also new checks that
prevents a malformed symbol list including duplicates, which I fixed
too.
This has been one of the most weird functions I ever decompiled. I will
share a few tricks I learnt. In short, I tried inlining as much as
possible by removing all the temps.
---
```c
switch (self->step) {
...
case 2:
isEntityAlive = 0;
if (self->step != 2) {
return;
}
```
This was the output from M2C. As there is no way that `self->step` is
different than `2`, deleting had no effect on the matching.
---
```c
var_v0 = self->step;
switch (var_v0) {
case 1:
...
if (statement) {
self->step++;
}
...
D_SOME_VARIABLE = var_v0;
}
```
This was another very weird one. I couldn't understand why
`D_SOME_VARIABLE` was assigned that way much further down the `case 1`.
The way I fixed it is that `var_v0` was always `1` due to `case 1:`. By
doing `D_SOME_VARIABLE = 1` I got a match.
---
```c
temp_a0_2 = D_80174C2C + 1;
...
D_80174C2C = temp_a0_2 & -(temp_a0_2 < 0x10);
```
To understand this madness I used a random C compiler I found online and
tested in a `for` loop what's the output for all the given `temp_a0_2`.
It seemed the value never changed but over `16` the value was always 0.
I logically re-written that statement into something that made logically
more sense for me and it matched, even if it looks very different from
the original:
```c
D_80174C2C++;
D_80174C2C = D_80174C2C >= 16 ? 0 : D_80174C2C;
```
Fairly straightforward one here I think.
Unfortunately the subweapon name does not appear in the definition
(actually... are subweapon names in the game at all? I don't recall them
being in there, I think it's all just in the manual?) so it's hard to
map these definitions to the subweapons. Might be good to think about
whether we could insert comments somehow. Anyway, this works for now and
might help with collecting the subweapons in one place to understand the
remaining members of the definition.
Primarily decompiling the entity function for the rebound stone, but
also some slight cleanups here and there for things that relate to it.
Very nice to be able to understand things better! Seems that subweapon
entities aren't very well decompiled so that might be nice to dig into.
After decompiling the bat fireball, I wanted to decompile all the places
where it can be created, so I did this one, which contains the entity
factory creation function call for the bat familiar to shoot its own
fireball.
Kind of neat to learn that the player's own fireballs and the familiar's
fireballs appear to be identical since they use the same function and
everything.
This required a bit of shuffling of other code in other places; happy to
elaborate on any of those changes but they seem fairly benign.
This is the entity produced when you use Fire of Bat.
Function is decompiled, and I also added some slight improvements to
ControlBatForm. I also tried to make a descriptive comment about this
function and how it is created - I'm hoping that, moving forward, we can
increase the amount of descriptive, guiding comments exist on things, to
help improve our ability to identify various values in things.
Take a look at the weird if-statement in `case 0`, no idea why it
exists. Seems like old code that someone adjusted and left stuff behind.