This change moves BSS variables into their most appropriate compile
unit, "decompiles" several data files, and splits out some existing data
into its logical unit.
BSS data has all been removed from `bss.c` and moved to a file where the
data is either first used or where it can be made static.
Several data files have been converted to appropriate types and added
to the most appropriate file. This converts the header related
references and some of the other early data.
Finally, some data like has been rearranged and moved into logical
compile units like data from `entity.c` into `holyglassescutscene.c`.
Logical boundaries were chosen based on where data could be made static.
Allow to compile weapon overlays as a single C files. The benefit is to
disallow symbols to be exported by statically compile them all but the
header. We would no longer need to use `OVL_EXPORT` as long as the
symbols are marked as `static`. The frames data is also generated as an
array of data that can be just included into their respective C files,
generated by JSON files on the fly.
I changed `animset` to `frameset` as the data does not represent a set
of animations but rather a set of frames, where every frame has multiple
sprites. The information on how the frames are played (e.g. animation)
is found elsewhere.
Following the full list of changes to achieve this project:
* The `animset` from splat is now dummied out
* The `frameset` JSON is now generated by the asset manager
* The `frameset` JSON is now compiled into `src/weapon/w_0xx_y.h`
* The `header.c` has been moved into `shared.h`
* For simplicity I added a `#define g_Animset w_000_1`. I did not want
to hack the asset manager too much to force the name to be `g_Animset`
and I did not want to change all the symbols yet.
* Simplified `weapon_pc.c` as we now only need the exported header
* Always try to build the most up-to-date asset manager: this should
avoid weird errors whenever people pull new changes
As the asset manager now can accept those `config` files, now the CLI
supports the following commands:
* `stage extract`
* `stage build`
* `config extract` (NEW)
* `config build` (NEW)
The config structure is heavily inspired to Splat to maintain
consistency and continuity.
I did not do it for `weapon`. This is the script I used:
`python3 a.py asm/us/st/dre/data/23264.sbss.s > src/st/dre/bss.c`
```python
import sys
with open(sys.argv[1], "r") as f:
lines = f.readlines()
print('#include "common.h"')
print("")
for line in lines:
if line == "\n":
continue
elif line.startswith(".include"):
continue
elif line.startswith(".section"):
continue
elif line.startswith("glabel"):
label = line[7:].replace("\n", "")
len = 0
elif ".word" in line:
if len > 0 and n != 4:
print(f"WARN: {label}", file=sys.stderr)
n = 4
len += 1
elif ".short" in line:
if len > 0 and n != 2:
print(f"WARN: {label}", file=sys.stderr)
n = 2
len += 1
elif ".byte" in line:
if len > 0 and n != 1:
print(f"WARN: {label}", file=sys.stderr)
n = 1
len += 1
elif line.startswith(".size"):
if len == 1:
if n == 1:
print(f"u8 {label};")
elif n == 2:
print(f"u16 {label};")
elif n == 4:
print(f"u32 {label};")
else:
if n == 1:
print(f"u8 {label}[{len}];")
elif n == 2:
print(f"u16 {label}[{len}];")
elif n == 4:
print(f"u32 {label}[{len}];")
```
the script is a bit dumb. It does not account of the header. Some types
are wrong compared to their prototype. The memory layout matches though,
so we can keep iterating on top of this.
Adds an a PSX implementation of `EntityRWarpRoom`. This is similar to
`EntityWarpRoom`, but needs to raise and lower the player stands on, and
obviously has to warp to other inverted rooms.
This also pulls in the remaining data and static storage, completing the
`rwrp` mapping.
---------
Co-authored-by: Jonathan Hohle <jon@ttkb.co>
The most important thing here is that D_170000_8017CBD0 is an array of
f32 values. But since entry 0 is only accessed with `.i.hi`, the
auto-detected symbol was `CBD2`, offset by 2, so I had to manually make
the symbol for this one variable. I studied the symbols file to figure
out how to declare it, and this ended up working. Now that I know how to
make weapon symbols, I can start making useful names for these in the
future. Not for this one though, this doesn't make any sense.
Brings DRA up to one function remaining.
I think everything is in order, but looking forward to any suggestions.
The last missing function is a pretty irrelevant Kanji function, so it
will be nice to have all the material to really start understanding DRA
now.
Start to perform a series of code refactoring to align the various
overlays on how NZ0, WRP and RWRP are currently organised, aiming to
share as much code as possible. This is a good stop gap that does not
change too much. There are virtually no major changes other than the
removal of the fake symbol `D_8003BEEC`.
I found it is very hard to share every single line of code due to some
minor differences in the castle flags. I couldn't yet spot a reliable
pattern on how castle flags are manager across stages.
My vision is to share as much code as possible, possibly not as header
files but as C files in a similar fashion of #1425 . I am aiming to
model NP3 so we can merge it with NO3 given the fact they share a good
chunk of the code base.
I am waiting to split the rest of the entities into their own individual
files. My idea is to have a file per entity or per entity group with
their own set of data and helper functions, possibly all marked as
`static`. We agreed it is probably a good idea to wait exploring the PSP
build of NZ0, NO3 or NP3 before performing this step.
This will decompile all the functions but the new `EntityRWarpRoom` from
the RWRP overlay.
Note that as `e_misc.c` has a function with a different castle flag, I
had to use a shared header. Everything else was identical.
---------
Co-authored-by: bismurphy <tjmurphy@mit.edu>
Mostly identical to MAD and PSP. There are four very different functions
from US that needs to be decompiled to be 100% complete:
* [x] `e_misc.c` `EntityMessageBox`
* [x] `e_misc.c` `EntityRelicOrb`
* [x] ~`e_stage_name.c` `StageNamePopupHelper`~ it does not exist
* [x] `e_stage_name.c` `EntityStageNamePopup`
These four very different functions are the only ones that use the JP
text instead of the US one. This overlay also lacks of `BlitChar`.
`EntityStageNamePopup` is very similar to the PSP counterpart. I used
@joshlory scratch to match the HD part.
`EntityRelicOrb` had some #ifdef between US and BETA (aka the MAD
overlay). I found some code that crossed between BETA and HD, so I just
put an `#else` after `VERSION_US`. We are starting to reconstruct how
the source code originally evolved across different game builds.
The vast majority of this comes from a 6-month-old scratch by
@ser-pounce , here: https://decomp.me/scratch/7Ram0
I finished it up, and made some changes to make it fit into the current
state of the repo.
That scratch puts the isrgb24 value into a StreamCtl struct. I'm
inclined to agree with that, but want to minimize the impact of this PR
on the larger repo for the moment. I expect StreamCtl to be used more
heavily in the final function for SEL, but we'll see how that goes.
The StreamEnv struct is in exactly the same location as
Unkstruct_801B9B7C (which was actually unused), so I eliminated that
one.
That's just about all I have to say for now.
The next function of SEL, func_801B99E4, makes it clear that D_8003C908
is not a struct member. I do not know why it was placed in this struct.
I have that function now matching, but since we're changing around
variables that are used elsewhere, I decided to split the PR so that we
can handle one type of change at a time.
The D_8003C908 variable has not yet been used in any C code, so this
change does not affect anything.
Further, since both struct members were s32, I decided to make it a
2-member array for the sake of conciseness in the code.
Changelog:
* Import all the PSP WRP data that belong to `e_collect.c`
* Remove the `ext.generic` use in favour of `ET_EquipItemDrop`
* Document some fields from `ET_EquipItemDrop`
* Discover the extra field `mariaSubWeapon` on PSP
* `g_api.AddToInventory` signature changed to allow a better match on
[EntityEquipItemDrop](https://decomp.me/scratch/PULKm)
* Remove the fake array `D_8003BF9C` in favour of `g_CastleFlags`
* The `O_TAG` struct is also valid on PSP
* Decompile `EntityPrizeDrop` on PSP
* Align `func_8018CAB0` to PSP
* Align `EntityPrizeDrop` to PSP with a bunch of `#ifdef`
* Align `EntityEquipItemDrop` to PSP using the WIP scratch
[EntityEquipItemDrop](https://decomp.me/scratch/PULKm)
* `DestroyCurrentEntity` is just an dummy item collector from
`EntityPrizeDrop`
* Duplicate functions in other overlays are not yet aligned as I am
waiting to migrate them to use `e_collect`
I noticed splat is not able to successfully recognise pointers if the
data is too scattered. I had to merge the `data` in the YAML and allow
it to be exported into a single file before starting to import it.
The only missing function from `e_collect.c` is
[EntityEquipItemDrop](https://decomp.me/scratch/PULKm).
Data on PSX are slightly shuffled within the same C file. I believe the
PSP build retains the original data order.
Thanks to @sozud for the majority of the work on `EntityPrizeDrop` and
`EntityEquipItemDrop` on PSP. And thanks to @bismurphy for solving the
last piece of the puzzle to match `EntityPrizeDrop`.
Wow! With this one, Richter is now down to a single non-matching
function (it's a duplicate of a DRA function which is missing - the one
with the funny pointer math which is connected with
EntityPlayerDissolves).
Anyway, we're matching. This is different from DRA's
EntityPlayerBlinkWhite, but in weird ways that made it a huge pain to
get matching. Definitely was not a matter of replacing a few lines like
some duplicated functions are.
Anyway, looking forward to see if there's anything to fix!
This was decompiled by @joshlory , but due to some annoying rodata, I
ended up taking over the PR on their behalf and submitting. The file
split here was a bit tricky to get right, but now we're matching.
I did not do any reviewing of this code, it is presented here as it was
made by josh's scratch.
RIC had 3 functions remaining, one of which was this one. Given its
similarity to the one in DRA, I decided to revisit it, and thankfully it
now matches.
I also did some cleanup on the DRA one, including renaming variables,
using macros, etc.
We now have two functions remaining in RIC. They are both duplicates of
remaining DRA functions, which have the same issues as the DRA ones do.
This means that once DRA is solved, RIC will be too, which is amazing!
This function was previously the last function in its file.
Upon decompiling, the rodata (specifically the `00 00 00 00` pattern)
indicated that the file does not end here, and that in fact the entire
following file should be part of this file, so I had to change the
splits to accomplish this.
It's an ugly function, and was hard to get a match, but here it is. Did
what I could to document variables but it doesn't seem to make much
sense, if you ask me.
This was EntityMPReplenished, but then I looked into how it is used and
found that it is used for many other things besides replenishing MP, so
I named it more generically.
I think I hunted down every situation where it is used and documented
them fairly well. In general, I think this is a relatively good-looking
function and is easy to read.
Looking forward to seeing any feedback!
Now with the maspsx changes, this can also match by using
SPRITESHEET_PTR.
Tried to document all the variables, use flags when possible, etc, so
hopefully this is mostly complete. Should be exciting to have
RenderEntities and RenderPrimitives both working now!
Open to suggestions for how to break this change up to make it easier to
review. The data extraction necessary for naming values in `D_800ACF60`
and `D_800ACF84` could be a separate commit... but I'm not sure it's
worth it.
This links w_000 and allows the texture to be loaded to vram, as well as
the functions executed.
g_Cluts was renamed since the stages also have g_Cluts. A macro and
preprocessor defines are used to allow unique weapon function names.
This doesn't load the animsets since it seems like that stuff is getting
redone with the asset manager.
This is the largest function remaining in the decomp, and now it's dealt
with.
It's a giant beast and I can't claim to be anywhere near understanding a
single thing that it does. Researching this and documenting it will be a
second giant PR. Maybe I'll do that someday, but for now I'll leave it
to anyone else who wants to give it a try. None of the variables have
useful names. We could have "give the variables in this function useful
names relating to how they are used" be a "good first PR" issue, since
we set up several of those a while ago.
Data types on some of the externs it uses have been changed to match how
the function uses them.
This also uses g_PlOvlSpritesheet, which we have found seems to need to
be accessed as a numerical pointer, so I added a #define for that. It
seems to be working, so big thank you to everyone who was involved in
the process of setting that up. I believe this is the first function to
actually make use of that.
Besides that, I'll leave it to others to make their comments. There is
really too much in this function for me to talk about it, but hopefully
this is a reasonable start and we can make whatever tweaks are needed to
get this merged.
This is a big messy function, but it's decompiled!
Did what I could to rename variables in a useful way, but I could only
get so far. Hopefully one day we can work out exactly what all the
different angles, XY variables, etc are. But this is one of the biggest
remaining functions and it's great to have matching.
There was a question in the decomp discord about the bounce when Alucard
dive-kicks and hits an enemy. I tracked this down, and in the process,
found some moderately old functions that could use some improvements to
their code style. I also cross-referenced these with PSP to make the
code make a bit more sense.
The PSP version makes it clear that D_800ACF7C is not a struct and is
just an array of s16, so I made that change. The struct version matched
on PS1, but now that PSP reveals that it was fake, we turn it back to
just an array.
Let me know if I missed anything! Nice to have real names for some of
these functions.
This aims to deprecate all the Splat tools in `tools/splat_ext` in
favour of a more centralised asset manager. This brings the following
advantages:
* Much faster extraction
* Faster build
* Automatically define `static` symbols or unique names whenever
`static` is not possible
* Allow to embed assets into the output binary
* Drastically simplify `Makefile` by removing all the asset build rules
* Avoid situations where it is not possible to extract and build assets
that is not 4-byte aligned
This is achieved by having the splat YAML targeting a normal C file as
data and have an external tool to take care of the following:
1. Extract asset files straight from the overlay binary file into human
readable file in `assets/st/STAGE_NAME`
2. Build assets as header files that go into `src/st/STAGE_NAME` to just
include them from any C file
This requires each stage header to have the following new format: please
see `src/st/nz0/header.c`
Built assets in `src/st` are ignored by Git.
As for now, for simplicity sake, the steps `make extract_assets` and
`make build_assets` are just executed within `make extract` exclusively
for the US version.
I plan to auto-generate files such as `src/st/nz0/tile_data.c`.
For a first iteration I am aiming to handle the following:
* [X] Extract rooms: `assets/st/*/rooms.json`
* [X] Extract room layers: `assets/st/*/entity_layouts.json`
* [X] Extract tilemap data: `assets/st/*/tilemap_*.bin`
* [X] Extract tilemap definitions: `assets/st/*/tiledef_*.json`
* [X] Extract sprites: `assets/st/*/sprites.json`
* [x] Extract entity layouts
* [X] Build rooms: `src/st/*/rooms.h`
* [X] Build room layers: `src/st/*/layers.h`
* [X] Build tilemap data: `src/st/*/tilemap_*.h`
* [X] Build tilemap definitions: `src/st/*/tiledef_*.h`
* [x] Build sprites (aka `g_SpriteBanks`)
* [x] Build entity layouts
* [x] Allow the tool to suggest how to adjust the Splat config for each
overlay
I want the tool to cover the following stages:
* [x] CEN
* [x] DRE
* ~MAD~ I do not think this can be done, it is way too different from
the other overlays
* [x] NO3
* [x] NP3
* [X] NZ0
* [x] ST0
* [X] WRP
* [x] RWRP
* ~WRP (PSP)~ Maybe in a follow-up PR
For a later iteration I plan on extracting and build:
* Entity GFX thingie
* The CLUT thingie in the header
* Uncompressed GFX data
* Cutscene data
* Blueprints
* The `src/config_us.h` thingie
---------
Co-authored-by: Josh Lory <josh.lory@outlook.com>
The Karma Coin, surprisingly, has the largest EntityWeaponAttack of all
the weapons. For that reason, I'm targeting it next.
It has one small other entity function, so this PR decompiles that
first, prior to going ahead and decompiling the EntityWeaponAttack
itself.
Otherwise, nothing too crazy special here. I imagine decompiling the
Karma Coin will make it clear what this helper entity is.
This PR is trying to get SsVabOpenHeadWithMode running, but I'm getting
the wrong result vs. my test app. I'm putting this up to see if others
have ideas.
c7484b6800/test.c (L154)
I check a bunch of preconditions on the test app and the implementation
so I think they are starting from the same state. The test app is able
to play the library song so I think it's OK.
The problem is that SpuMalloc returns the wrong value. See
```
_svm_vab_start[vabId] = spuAllocMem;
```
_svm_vab_start[0] is supposed to be 0x00001010 but instead we get
0x11010.
c7484b6800/test.c (L201)
```
69648 != 4112 in check_ss_vab_open_head_with_mode /home/d/sotn-decomp-2/src/pc/psxsdk/emu.cpp:306
```
The scratch for SpuMalloc is https://decomp.me/scratch/UjIPd
The version here is based off this one since I think that scratch isn't
usable yet.
4ff48d4660/psx_seq_player/lib_spu.cpp (L2462)
The scratch for func_800286E0 is https://decomp.me/scratch/msP8t
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.