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.
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.
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.
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!
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.
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.
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.
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.
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.
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>
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.
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.
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
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.
Allows to not hard code the location in-memory of decompiled functions
and imported data if not required. This allows to relocate the
referenced symbols when editing the original code or game data. If you
were getting the offset of those symbols from the symbol list in
`config/` I suggest to use the built `build/us/*.map` file instead.
As I finished importing the data in WRP, I came with a possible new
pattern when de-duplicating functions. I kept using a header file
(easily indexable from VS Code) in `src/st`. But this time it gets
included by `entity_relic_orb.c`. All the sections `.data`, `.rodata`
and `.text` are migrated into `entity_relic_orb.c` but the file itself
just includes `src/st/entity_relic_orb.h`. Thinking forward, once we
will be able to fix the problem present in #464 it will just be a matter
of renaming `entity_relic_orb.h` into `entity_relic_orb.c` and remove
each individual `entity_relic_orb.c` that currently acts as a proxy.
~~This PR is a draft. If you agree this is a good pattern I will proceed
to do the same with the remaining overlays after #528 is good to be
merged.~~
Took me a while. I had to move a good chunk of the data from 6FD0 due to
`const char* D_80180F84[] = {"Obtained "};` as it declares data in both
`.data` and `.rodata`. Due to its strategic location, I did not yet find
a clean way to have it matching in other overlays without starting to
import data.
The function is not very clean and there are loads of temp variables and
fake stuff. I ask to spend a bit of time to make improvements where
possible. I want to get it in a good shape before committing myself to
de-duplicating it for all the other overlays.
https://decomp.me/scratch/kyBr8
This is an unknown function. I don't know what it does. It is duplicated
across most overlays. It is called in CollectGold, EntityEquipItemDrop,
and TestCollisions.
It seems to take in a string, and then do a bunch of things with
primitives, but I don't know what. We don't directly reference that
array, we only read and write to it based on a pointer which moves
through the array. I tried to remove the pointer but didn't get
anywhere.
Fully-matching scratch is here: https://decomp.me/scratch/UV2K2
I am starting with only this one version of the function, so that if
changes need to be made (variable names, control flow, etc), I can
update them once here, and then copy them to the other places, instead
of making changes in every place. Once we are happy with the state of
this function, I will add the duplicates to this PR prior to merging.
---------
Co-authored-by: bismurphy <bismurphy@users.noreply.github.com>
These functions correspond to the two elevators in the Alchemy Lab, it's
been some time since i happen to get a match in this overlay so i think
this is good progress!
Despite the appearance, these functions were really hard to tackle,
there's some kind of variable reuse that i had to fake to get a match,
i'm leaving the scratches in case somebody wants to mess with them and
find a real match.
https://decomp.me/scratch/bnY5Nhttps://decomp.me/scratch/Hpxl5
After attempting this de-duplication process I see that it's pretty
slow, tedious and error-prone. I think it would make sense to have an
intermediate phase where we split stuff into #includes like this PR
does. Eventually this will be combined back into C files with proper
file splits. I think a process that is incremental and would get us
there eventually could be like this:
Split single function into a header, #include it.
Rename any D_XXXXXXX variables to UNK_Whatever#, add to symbols.*.txt
Once the above is done for all instances of the function, perform file
splits (if we know there's a sequential block of functions, wait to
split until the whole block is done)
Combine individual.h files into a c file, integrate building
st/shared_#.c into Makefile
I'm probably just going to do a little bit on this each day to try and
chip away at it, it's too tedious to do a big push.