By looking at how the gold pickup sfx are handled using `#ifdef`, I
chose to do the same thing here with swapping the sfx references in
`e_red_door.h`.
`SFX_METAL_CLANG_E` is the only sound effect that seems to be the same
between MAD and the final collision handler.
We've hit the first beta sound ID `0x640`, which is the old door open
sound effect (final is `0x642`). How do we want to implement the beta
sfx IDs in the enum?
Most important note on this one is that it uses the 0xA0 entity offset.
We already had `shield.unkA0` being used in a different shield. However,
on this shield it's accessed as a half-word, while the other one
accesses as a word.
I looked into it a bit, and realized that the other shield uses it as a
change in Y velocity, and ET_Weapon already uses 0xA0 as an
accelerationY. Therefore, I changed that shield to use ext.weapon for
that entry, and this allows us to change Shields to use 0xA0 as a
halfword.
In general, it looks like shields use a mix of the normal ET_Weapon and
the specific ET_Shield. Maybe we can work out what's what at some point
in the future, especially once all the weapons are done and we can start
truly digging into the purpose of every unkXX value in there.
Stopping at 0x633 (`SFX_UI_SELECT`) for now, but will continue to add
and update more sfx references soon.
So far we have 51 out of a potential 736 sfx IDs (`0x8E0` - `0x600`).
For what it's worth, the last valid sound ID I have listed in my
spreadsheet is `0x8D2` found in `DRA`, `RIC`, `BO4`, `BO6`, and `RBO5`
so the actual number might be 722 enum IDs, but we'll see what happens
since the last sfx group in the list belongs to vabid 3.
I decided to rename `SFX_SKULL_HIT` to `SFX_METAL_CLANG`, as well as
`SFX_SWORD_SWISH` to `SFX_WEAPON_SWISH`.
These are more generic names that better match up with the actual sound.
While `SFX_SWORD` is mainly used for sword weapon cues, it is used for
other weapon entities so I renamed it.
Same idea also applied to `METAL_CLANG`; it's mainly used for the CGI
spinning Stone Skull enemies but it also shows up in CEN as an elevator
sound cue.
I also used `SFX_RIC_RSTONE_TINK` as an abbreviation for the Rebound
Stone "tink" sfx, to help keep these names short.
Starting off with something simple. Per
[sozud](https://github.com/sozud)'s suggestion in #1441 , I put in a new
enum for sounds. There's only one reference to Richter's whip sound in
the codebase so far. According to my research, BO6 and RBO1 reference
this ID as well.
There's several other whip rattle sounds (0x603-0x606) immediately
following the commonly heard 0x602 cue. Unless BO6 or RBO1 uses random
sound calls (like Alucard's randomized grunts), I don't believe these
are referenced in the game and are unused.
This modifies a variable at 0x80097420, I noticed that was in the
g_UnkGraphicsStruct, so I went through all the uses of that variable and
made them all use the struct.
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.
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
:)
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.
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.
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.
Decompiles HandleMenu. The HD version is not yet in and I will submit it
with another commit in this same PR. I wanted to collect some feedback
before decompiling the HD counterpart.
This is a pretty cool function. It seems to handle most of the logic for
the bat transformation, including the wing smash spell, fireballs,
echos, and normal movement.
I am not sure what to call it - maybe ControlBatForm? Very open to
suggestions.
This is a large one, so please do double check what I have here to make
sure I'm not introducing code that will need to be fixed later. I
suspect this function might be helpful for understanding some behavioral
details.
There are a few really weird version differences between US and HD here.
It makes parts of the code come out really ugly, but I guess that's the
price we have to pay for representing two codebases in one.
Looking forward to any and all feedback for this one!
Very happy of this one. I tried decompiling it two months ago without
success but I decided to give it another try less than 24 hours ago. It
is the function called on every frame while the normal gameplay is
running. This also manages how to transition from a stage to another,
which files to load, set specific random seeds when playing a Tactics
recording.
Note that I refactored `func_800EAF28` as it is used by `HandlePlay`. I
also moved `GameSteps` out of `gameover.c` as it is started to be used
in another handler too. I do not know what `SET_UNK_0B` or `SET_UNK_12`
do, but I added in case at some point we want to explore their meaning.
`func_800F298C` is the function that handles the whole gameplay. That is
the biggest DRA function and the second biggest function of the game. I
hope one day we will manage to decompile that too.
In `case Play_LoadStageChr` there seems to be a hidden loading screen
populated by that `for` loop right after `D_8013640C =
AllocPrimitives(PRIM_GT4, 16);`. It is hidden because `blendMode` is set
to `0`. Setting it to either `8` or `0x88` shows a black screen rather
than showing Alucard frozen in the CD room for those two seconds. I do
not believe it was supposed to be black as X2, Y2, X3 and Y3 have some
kind of rotation and the U/V coords hints the fact some textures were
supposed to be loaded.
It's been a wild ride with this one, but i'm proud to present the first
Boss decompilation of the project.
![image](https://github.com/Xeeynamo/sotn-decomp/assets/96613413/d0ed35a9-7032-42b8-b237-3cdc2a4d5db6)
However, this contribution doesn't come without problems. I managed to
match EntitySlogra 100% but the local assembler is skipping a NOP, so
this makes it a NON_MATCHING until the compiler combo is fixed.
As for EntityGaibon, i couldn't get a perfect match, some regalloc and
instruction reordering persist in the assembler output, nevertheless the
behaviour has been extensively tested in-game for days using two
emulators simultaneously side by side to ensure it's equivalent.
If you want to try the functions, you'd have to change
splat.us.stnz0.yaml to exclude rodata extraction like this:
- [0x305FC, .rodata, 33FCC] # EntitySlogra
- [0x30618, .rodata, 33FCC] # EntityGaibon
and remember to change the #ifndef to #ifdef to be able to compile them.
Scratches:
NZ0_EntitySlogra: https://decomp.me/scratch/vaRJR
NZ0_EntityGaibon: https://decomp.me/scratch/QGtpG
NP3_EntitySlogra: https://decomp.me/scratch/DGetH
NP3_EntityGaibon: https://decomp.me/scratch/wUo18
Co-authored by the great @MottZilla, who actively provided his
dynamic-analysis and code interpretation skills to achieve the perfect
behaviour and documentation of the code.
I was curious about the SFX used in the game over screen, but it turns
out that they have mostly been moved around/replaced in the US version.
I documented these for the US version and put them in an ifdef.
NZ0:
EntityAxeKnight (I'm proud to present the first enemy decompiled in the
project perhaps?)
Here is the scratch in case somebody wants to tune it and provide
changes:
https://decomp.me/scratch/LKkYQ
EntitySubWeaponContainer
EntityBloodSplatter
func_801B69E8
func_801C0D08
func_801C9E98
NP3:
EntityBloodSplatter
EntityZombie
func_801B8CC0
This function is weird in various ways, for starters, i needed to remove
the void type from the prototype argument of MoveEntity(), because the
function needed 'self' to be passed to it for matching, that could have
been a mistake from the dev, since DestroyEntity() takes an Entity* for
example, so it's very likely someone made that mistake, and like we have
been encountering a lot of times, it seems like the devs weren't care
about doing prototypes for functions so the compiler would assume
MoveEntity(s32), making it possible to receive an argument without
erroring out. There's no other way that i or @nim-ka found to match the
function. The other possibility is that the function actually takes an
Entity* but it's unused, but i think this is unlikely.
The other thing is that the function needs to use 'x2' for the last
member used below to match, but in decomp.me compiler it needs to be
'y2' for the offset to be correct in the asm, i couldn't figure out why.
I'm leaving the already cleaned up scratch in case someone wants to mess
with it and try to figure out a solution for the MoveEntity() argument
needed, and once we're all sure this is what we want, i'll make the
other duplicates in another PR.
https://decomp.me/scratch/sPUOP