mirror of
https://github.com/zeldaret/oot.git
synced 2025-07-04 15:04:31 +00:00
PlayState Rename (#1231)
* global context -> play * fix PlayState* PlayState
This commit is contained in:
parent
154f44b6da
commit
2e6279bc8e
912 changed files with 40489 additions and 41078 deletions
|
@ -43,7 +43,7 @@ The general rule for order of decompilation is
|
|||
- Next, decompile any other functions from the actor you have found in `Init`. You generally start with the action functions, because they return nothing and all take the same arguments,
|
||||
|
||||
```C
|
||||
void func_80whatever(EnJj* this, GlobalContext* globalCtx);
|
||||
void func_80whatever(EnJj* this, PlayState* play);
|
||||
```
|
||||
|
||||
- Decompile each action function in turn until you run out. Along the way, do any other functions in the actor for which you have discovered the argument types. (You are probably better doing depth-first on action functions than breadth-first: it's normally easier to follow along one branch of the actions than )
|
||||
|
@ -103,7 +103,7 @@ Copy the entire contents of this file into the upper box, labelled "MIPS assembl
|
|||
|
||||
Now press "Decompile". This should produce C code:
|
||||
```C
|
||||
void EnJj_Init(EnJj *this, GlobalContext *globalCtx) {
|
||||
void EnJj_Init(EnJj *this, PlayState *play) {
|
||||
CollisionHeader *sp4C;
|
||||
DynaCollisionContext *sp44;
|
||||
DynaCollisionContext *temp_a1;
|
||||
|
@ -146,7 +146,7 @@ While we are carrying out initial changes, you can also find-and-replace any ins
|
|||
</summary>
|
||||
|
||||
```C
|
||||
void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void EnJj_Init(Actor *thisx, PlayState *play) {
|
||||
EnJj* this = THIS;
|
||||
|
||||
CollisionHeader *sp4C;
|
||||
|
@ -164,7 +164,7 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
temp_a1 = this + 0x164;
|
||||
if (temp_v0 == -1) {
|
||||
sp44 = temp_a1;
|
||||
SkelAnime_InitFlex(globalCtx, (SkelAnime *) temp_a1, (FlexSkeletonHeader *) &D_0600B9A8, (AnimationHeader *) &D_06001F4C, this + 0x1A8, this + 0x22C, 0x16);
|
||||
SkelAnime_InitFlex(play, (SkelAnime *) temp_a1, (FlexSkeletonHeader *) &D_0600B9A8, (AnimationHeader *) &D_06001F4C, this + 0x1A8, this + 0x22C, 0x16);
|
||||
Animation_PlayLoop((SkelAnime *) sp44, (AnimationHeader *) &D_06001F4C);
|
||||
this->unk30A = (u16)0;
|
||||
this->unk30E = (u8)0;
|
||||
|
@ -176,25 +176,25 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
} else {
|
||||
func_80A87800(this, &func_80A87C30);
|
||||
}
|
||||
this->unk300 = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, (u16)0x5A, this->actor.world.pos.x - 10.0f, this->actor.world.pos.y, this->actor.world.pos.z, 0, (?32) this->actor.world.rot.y, 0, 0);
|
||||
this->unk300 = Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, (u16)0x5A, this->actor.world.pos.x - 10.0f, this->actor.world.pos.y, this->actor.world.pos.z, 0, (?32) this->actor.world.rot.y, 0, 0);
|
||||
DynaPolyActor_Init((DynaPolyActor *) this, 0);
|
||||
CollisionHeader_GetVirtual((void *) &D_06000A1C, &sp4C);
|
||||
this->unk_14C = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->actor, sp4C);
|
||||
this->unk_14C = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->actor, sp4C);
|
||||
temp_a1_3 = this + 0x2B0;
|
||||
sp44 = temp_a1_3;
|
||||
Collider_InitCylinder(globalCtx, (ColliderCylinder *) temp_a1_3);
|
||||
Collider_SetCylinder(globalCtx, (ColliderCylinder *) temp_a1_3, &this->actor, &D_80A88CB4);
|
||||
Collider_InitCylinder(play, (ColliderCylinder *) temp_a1_3);
|
||||
Collider_SetCylinder(play, (ColliderCylinder *) temp_a1_3, &this->actor, &D_80A88CB4);
|
||||
this->actor.colChkInfo.mass = 0xFF;
|
||||
return;
|
||||
}
|
||||
if (temp_v0 == 0) {
|
||||
DynaPolyActor_Init((DynaPolyActor *) this, 0);
|
||||
CollisionHeader_GetVirtual((void *) &D_06001830, &sp4C);
|
||||
temp_a1_2 = &globalCtx->colCtx.dyna;
|
||||
temp_a1_2 = &play->colCtx.dyna;
|
||||
sp44 = temp_a1_2;
|
||||
temp_v0_2 = DynaPoly_SetBgActor(globalCtx, temp_a1_2, &this->actor, sp4C);
|
||||
temp_v0_2 = DynaPoly_SetBgActor(play, temp_a1_2, &this->actor, sp4C);
|
||||
this->unk_14C = temp_v0_2;
|
||||
func_8003ECA8(globalCtx, temp_a1_2, (s32) temp_v0_2);
|
||||
func_8003ECA8(play, temp_a1_2, (s32) temp_v0_2);
|
||||
this->actor.update = &func_80A87F44;
|
||||
this->actor.draw = NULL;
|
||||
Actor_SetScale(&this->actor, 0.087f);
|
||||
|
@ -205,7 +205,7 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
}
|
||||
DynaPolyActor_Init((DynaPolyActor *) this, 0);
|
||||
CollisionHeader_GetVirtual((void *) &D_0600BA8C, &sp4C);
|
||||
this->unk_14C = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->actor, sp4C);
|
||||
this->unk_14C = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->actor, sp4C);
|
||||
this->actor.update = &func_80A87F44;
|
||||
this->actor.draw = NULL;
|
||||
Actor_SetScale(&this->actor, 0.087f);
|
||||
|
@ -281,7 +281,7 @@ Glancing through the rest of `EnJj_Init`, we notice some references to DynaPoly,
|
|||
```C
|
||||
DynaPolyActor_Init((DynaPolyActor *) this, 0);
|
||||
CollisionHeader_GetVirtual((void *) &D_06000A1C, &sp4C);
|
||||
this->unk_14C = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->actor, sp4C);
|
||||
this->unk_14C = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->actor, sp4C);
|
||||
```
|
||||
|
||||
This means that EnJj is not an ordinary actor: it is instead a DynaPoly actor. In-game this is to do with how the actor interacts with Link and the environment (a good rule of thumb is that Link can often stand on DynaPoly actors as if they were ground). For decompilation purposes, it means that the actor struct is wrong: the first element of a DynaPoly actor's struct is not an `Actor` struct, but a `DynaPolyActor`, usually called `dyna`. We should fix this immediately to avoid confusion later. (Some actors have this correctly identified already; we were unlucky with this one.)
|
||||
|
@ -318,7 +318,7 @@ Now that we know this, it is worth remaking the context file and running mips2c
|
|||
```C
|
||||
DynaPolyActor_Init((DynaPolyActor *) this, 0);
|
||||
CollisionHeader_GetVirtual((void *) &D_06000A1C, &sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
```
|
||||
|
||||
Next, replace `(DynaPolyActor *) this` by `&this->dyna`. There's not a lot more we can do to the DynaPoly stuff right now, so just remove the casts to void and move on.
|
||||
|
@ -331,8 +331,8 @@ The relevant functions in this actor are
|
|||
```C
|
||||
temp_a1_3 = this + 0x2B0;
|
||||
sp44 = temp_a1_3;
|
||||
Collider_InitCylinder(globalCtx, (ColliderCylinder *) temp_a1_3);
|
||||
Collider_SetCylinder(globalCtx, (ColliderCylinder *) temp_a1_3, &this->dyna.actor, &D_80A88CB4);
|
||||
Collider_InitCylinder(play, (ColliderCylinder *) temp_a1_3);
|
||||
Collider_SetCylinder(play, (ColliderCylinder *) temp_a1_3, &this->dyna.actor, &D_80A88CB4);
|
||||
```
|
||||
|
||||
Notice that `sp44` is set, but actually not used anywhere in the actor. This is a good indication that it is fake. We'll get back to that. Similarly, `temp_a1_3` is only used in these functions, so is likely to be fake as well: it's simply trying to get the pointer into the `a1` register.
|
||||
|
@ -349,8 +349,8 @@ typedef struct EnJj {
|
|||
|
||||
Now replace the temps, so we have
|
||||
```C
|
||||
Collider_InitCylinder(globalCtx, &this->collider);
|
||||
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
Collider_InitCylinder(play, &this->collider);
|
||||
Collider_SetCylinder(play, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
```
|
||||
|
||||
(You may prefer to just comment out temps initially, to keep track of where they were.)
|
||||
|
@ -398,7 +398,7 @@ This is the combined system that handles actors' skeletons and their animations.
|
|||
temp_a1 = this->unk_164;
|
||||
...
|
||||
sp44 = (DynaCollisionContext *) temp_a1;
|
||||
SkelAnime_InitFlex(globalCtx, (SkelAnime *) temp_a1, (FlexSkeletonHeader *) &D_0600B9A8, (AnimationHeader *) &D_06001F4C, this + 0x1A8, this + 0x22C, 0x16);
|
||||
SkelAnime_InitFlex(play, (SkelAnime *) temp_a1, (FlexSkeletonHeader *) &D_0600B9A8, (AnimationHeader *) &D_06001F4C, this + 0x1A8, this + 0x22C, 0x16);
|
||||
Animation_PlayLoop((SkelAnime *) sp44, (AnimationHeader *) &D_06001F4C);
|
||||
```
|
||||
|
||||
|
@ -438,7 +438,7 @@ extern UNK_TYPE D_0600BA8C;
|
|||
|
||||
and removing the temps,
|
||||
```C
|
||||
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
|
||||
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
|
||||
```
|
||||
|
||||
|
@ -446,13 +446,13 @@ Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
|
|||
|
||||
This function also gives us information about other things in the struct. One obvious thing that sticks out is
|
||||
```C
|
||||
this->unk300 = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, (u16)0x5A, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, (?32) this->dyna.actor.world.rot.y, 0, 0);
|
||||
this->unk300 = Actor_SpawnAsChild(&play->actorCtx, &this->dyna.actor, play, (u16)0x5A, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, (?32) this->dyna.actor.world.rot.y, 0, 0);
|
||||
```
|
||||
Hovering over this function tells us it outputs a pointer to the spawned actor, so `this->unk_300` is an `Actor*`. We may or may not care what this actor actually is, depending on how it is used later on, so let's just add `/* 0x0300 */ Actor* childActor` to the struct for now.
|
||||
|
||||
We can look up what the actor with ID 0x5A is in `z64actor.h`: we find it is `ACTOR_EN_JJ`. So some Jabus spawn another Jabu. Filling this in and removing the spurious cast, we have
|
||||
```C
|
||||
this->childActor = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
|
||||
this->childActor = Actor_SpawnAsChild(&play->actorCtx, &this->dyna.actor, play, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
|
||||
```
|
||||
|
||||
Finally, we have this block:
|
||||
|
@ -491,7 +491,7 @@ typedef struct EnJj {
|
|||
|
||||
We can remove a few more temps that don't look real, and end up with
|
||||
```C
|
||||
void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void EnJj_Init(Actor *thisx, PlayState *play) {
|
||||
EnJj* this = THIS;
|
||||
|
||||
CollisionHeader *sp4C;
|
||||
|
@ -509,7 +509,7 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
// temp_a1 = this->unk_164;
|
||||
if (temp_v0 == -1) {
|
||||
// sp44 = (DynaCollisionContext *) temp_a1;
|
||||
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
|
||||
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
|
||||
this->unk_30A = 0;
|
||||
this->unk_30E = 0;
|
||||
|
@ -521,24 +521,24 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
} else {
|
||||
func_80A87800(this, &func_80A87C30);
|
||||
}
|
||||
this->childActor = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
|
||||
this->childActor = Actor_SpawnAsChild(&play->actorCtx, &this->dyna.actor, play, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_06000A1C, &sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
// temp_a1_3 = this + 0x2B0;
|
||||
// sp44 = temp_a1_3;
|
||||
Collider_InitCylinder(globalCtx, &this->collider);
|
||||
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
Collider_InitCylinder(play, &this->collider);
|
||||
Collider_SetCylinder(play, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
this->dyna.actor.colChkInfo.mass = 0xFF;
|
||||
return;
|
||||
}
|
||||
if (temp_v0 == 0) {
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_06001830, &sp4C);
|
||||
// temp_a1_2 = &globalCtx->colCtx.dyna;
|
||||
// temp_a1_2 = &play->colCtx.dyna;
|
||||
// sp44 = temp_a1_2;
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
func_8003ECA8(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
func_8003ECA8(play, &play->colCtx.dyna, this->dyna.bgId);
|
||||
this->dyna.actor.update = &func_80A87F44;
|
||||
this->dyna.actor.draw = NULL;
|
||||
Actor_SetScale(&this->dyna.actor, 0.087f);
|
||||
|
@ -549,7 +549,7 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
}
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_0600BA8C, &sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.actor.update = &func_80A87F44;
|
||||
this->dyna.actor.draw = NULL;
|
||||
Actor_SetScale(&this->dyna.actor, 0.087f);
|
||||
|
@ -563,12 +563,12 @@ This will still not compile without errors: we need to know what the functions i
|
|||
|
||||
Function pointers do not need `&`, so remove all those. There are three functions that are called in this actor. Firstly, `this->dyna.actor.update = func_80A87F44;` tells us that `func_80A87F44` is an alternative update function for this actor. We therefore give it a prototype similar to the original Update:
|
||||
```C
|
||||
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Update(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Init(Actor* thisx, PlayState* play);
|
||||
void EnJj_Destroy(Actor* thisx, PlayState* play);
|
||||
void EnJj_Update(Actor* thisx, PlayState* play);
|
||||
void EnJj_Draw(Actor* thisx, PlayState* play);
|
||||
|
||||
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx);
|
||||
void func_80A87F44(Actor* thisx, PlayState* play);
|
||||
```
|
||||
|
||||
Unfortunately the others are not so easy to deal with. In order to find out what type the functions called by `func_80A87800`, we have to look at `func_80A87800` itself. But fortunately, this is the entire MIPS for `func_80A87800`:
|
||||
|
@ -583,7 +583,7 @@ This is simple enough to read that we don't even need to appeal to mips2c: it sa
|
|||
|
||||
*Action functions* are the main other kind of function in most actors: they are usually run by Update every frame, and carry out the main actions that the actor does (hence the name). They all have the same arguments, and so we have a typedef for such things: it is
|
||||
```C
|
||||
typedef void (*EnJjActionFunc)(struct EnJj*, GlobalContext*);
|
||||
typedef void (*EnJjActionFunc)(struct EnJj*, PlayState*);
|
||||
```
|
||||
Put this between `struct EnJj;` and the actor struct in the header file. This also gives us another bit of the struct, conveniently plugging the gap at `0x2FC`:
|
||||
```C
|
||||
|
@ -599,14 +599,14 @@ void func_80A87800(EnJj* this, EnJjActionFunc actionFunc) {
|
|||
|
||||
and that `func_80A87BEC` and `func_80A87C30`, passed to it in `EnJj_Init`, are action functions. Since they are first used above where they are defined, we prototype them at the top as well,
|
||||
```C
|
||||
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Update(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Init(Actor* thisx, PlayState* play);
|
||||
void EnJj_Destroy(Actor* thisx, PlayState* play);
|
||||
void EnJj_Update(Actor* thisx, PlayState* play);
|
||||
void EnJj_Draw(Actor* thisx, PlayState* play);
|
||||
|
||||
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx);
|
||||
void func_80A87BEC(EnJj* this, GlobalContext* globalCtx);
|
||||
void func_80A87C30(EnJj* this, GlobalContext* globalCtx);
|
||||
void func_80A87F44(Actor* thisx, PlayState* play);
|
||||
void func_80A87BEC(EnJj* this, PlayState* play);
|
||||
void func_80A87C30(EnJj* this, PlayState* play);
|
||||
```
|
||||
|
||||
|
||||
|
@ -629,14 +629,14 @@ With all of this implemented, the function should now compile without errors. Th
|
|||
</summary>
|
||||
|
||||
```C
|
||||
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Update(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnJj_Init(Actor* thisx, PlayState* play);
|
||||
void EnJj_Destroy(Actor* thisx, PlayState* play);
|
||||
void EnJj_Update(Actor* thisx, PlayState* play);
|
||||
void EnJj_Draw(Actor* thisx, PlayState* play);
|
||||
|
||||
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx);
|
||||
void func_80A87BEC(EnJj* this, GlobalContext* globalCtx);
|
||||
void func_80A87C30(EnJj* this, GlobalContext* globalCtx);
|
||||
void func_80A87F44(Actor* thisx, PlayState* play);
|
||||
void func_80A87BEC(EnJj* this, PlayState* play);
|
||||
void func_80A87C30(EnJj* this, PlayState* play);
|
||||
|
||||
/*
|
||||
const ActorInit En_Jj_InitVars = {
|
||||
|
@ -699,7 +699,7 @@ void func_80A87800(EnJj* this, EnJjActionFunc actionFunc) {
|
|||
}
|
||||
|
||||
// #pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Jj/EnJj_Init.s")
|
||||
void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void EnJj_Init(Actor *thisx, PlayState *play) {
|
||||
EnJj* this = THIS;
|
||||
|
||||
CollisionHeader *sp4C;
|
||||
|
@ -717,7 +717,7 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
// temp_a1 = this->unk_164;
|
||||
if (temp_v0 == -1) {
|
||||
// sp44 = (DynaCollisionContext *) temp_a1;
|
||||
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable, this->morphTable, 22);
|
||||
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
|
||||
this->unk_30A = 0;
|
||||
this->unk_30E = 0;
|
||||
|
@ -729,24 +729,24 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
} else {
|
||||
func_80A87800(this, func_80A87C30);
|
||||
}
|
||||
this->childActor = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
|
||||
this->childActor = Actor_SpawnAsChild(&play->actorCtx, &this->dyna.actor, play, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f, this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_06000A1C, &sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
// temp_a1_3 = this + 0x2B0;
|
||||
// sp44 = temp_a1_3;
|
||||
Collider_InitCylinder(globalCtx, &this->collider);
|
||||
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
Collider_InitCylinder(play, &this->collider);
|
||||
Collider_SetCylinder(play, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
this->dyna.actor.colChkInfo.mass = 0xFF;
|
||||
return;
|
||||
}
|
||||
if (temp_v0 == 0) {
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_06001830, &sp4C);
|
||||
// temp_a1_2 = &globalCtx->colCtx.dyna;
|
||||
// temp_a1_2 = &play->colCtx.dyna;
|
||||
// sp44 = temp_a1_2;
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
func_8003ECA8(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
func_8003ECA8(play, &play->colCtx.dyna, this->dyna.bgId);
|
||||
this->dyna.actor.update = func_80A87F44;
|
||||
this->dyna.actor.draw = NULL;
|
||||
Actor_SetScale(&this->dyna.actor, 0.087f);
|
||||
|
@ -757,7 +757,7 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) {
|
|||
}
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_0600BA8C, &sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.actor.update = func_80A87F44;
|
||||
this->dyna.actor.draw = NULL;
|
||||
Actor_SetScale(&this->dyna.actor, 0.087f);
|
||||
|
@ -827,7 +827,7 @@ You can keep the diff open in the terminal, and it will refresh when the C file
|
|||
In this case, we see that various branches are happening in the wrong place. Here I fear experience is necessary: notice that the function has three blocks that look quite similar, and three separate conditionals that depend on the same variable. This is a good indicator of a switch. Changing the function to use a switch,
|
||||
|
||||
```C
|
||||
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
void EnJj_Init(Actor* thisx, PlayState* play) {
|
||||
EnJj* this = THIS;
|
||||
|
||||
s32 sp4C;
|
||||
|
@ -840,7 +840,7 @@ void EnJj_Init(Actor* thisx, GlobalContext* globalCtx) {
|
|||
|
||||
switch (temp_v0) {
|
||||
case -1:
|
||||
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable,
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &D_0600B9A8, &D_06001F4C, this->jointTable,
|
||||
this->morphTable, 22);
|
||||
Animation_PlayLoop(&this->skelAnime, &D_06001F4C);
|
||||
this->unk_30A = 0;
|
||||
|
@ -854,24 +854,24 @@ void EnJj_Init(Actor* thisx, GlobalContext* globalCtx) {
|
|||
func_80A87800(this, func_80A87C30);
|
||||
}
|
||||
this->childActor = Actor_SpawnAsChild(
|
||||
&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f,
|
||||
&play->actorCtx, &this->dyna.actor, play, ACTOR_EN_JJ, this->dyna.actor.world.pos.x - 10.0f,
|
||||
this->dyna.actor.world.pos.y, this->dyna.actor.world.pos.z, 0, this->dyna.actor.world.rot.y, 0, 0);
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_06000A1C, &sp4C);
|
||||
this->dyna.bgId =
|
||||
DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
Collider_InitCylinder(globalCtx, &this->collider);
|
||||
Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
Collider_InitCylinder(play, &this->collider);
|
||||
Collider_SetCylinder(play, &this->collider, &this->dyna.actor, &D_80A88CB4);
|
||||
this->dyna.actor.colChkInfo.mass = 0xFF;
|
||||
break;
|
||||
case 0:
|
||||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_06001830, &sp4C);
|
||||
// temp_a1_2 = &globalCtx->colCtx.dyna;
|
||||
// temp_a1_2 = &play->colCtx.dyna;
|
||||
// sp44 = temp_a1_2;
|
||||
this->dyna.bgId =
|
||||
DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
func_8003ECA8(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
|
||||
DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
func_8003ECA8(play, &play->colCtx.dyna, this->dyna.bgId);
|
||||
this->dyna.actor.update = func_80A87F44;
|
||||
this->dyna.actor.draw = NULL;
|
||||
Actor_SetScale(&this->dyna.actor, 0.087f);
|
||||
|
@ -880,7 +880,7 @@ void EnJj_Init(Actor* thisx, GlobalContext* globalCtx) {
|
|||
DynaPolyActor_Init(&this->dyna, 0);
|
||||
CollisionHeader_GetVirtual(&D_0600BA8C, &sp4C);
|
||||
this->dyna.bgId =
|
||||
DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, sp4C);
|
||||
this->dyna.actor.update = func_80A87F44;
|
||||
this->dyna.actor.draw = NULL;
|
||||
Actor_SetScale(&this->dyna.actor, 0.087f);
|
||||
|
@ -899,10 +899,10 @@ we see that the diff is nearly correct (note that `-3` lets you compare current
|
|||

|
||||
</details>
|
||||
|
||||
except we still have some stack issues. Now that `temp_v0` is only used once, it looks fake. Eliminating it actually seems to make the stack worse. To fix this, we employ something that we have evidence that the developers did: namely, we make a copy of `globalCtx` (the theory is that they actually used `gameState` as an argument of the main 4 functions, just like we used `Actor* thisx` as the first argument.) The quick way to do this is to change the top of the function to
|
||||
except we still have some stack issues. Now that `temp_v0` is only used once, it looks fake. Eliminating it actually seems to make the stack worse. To fix this, we employ something that we have evidence that the developers did: namely, we make a copy of `play` (the theory is that they actually used `gameState` as an argument of the main 4 functions, just like we used `Actor* thisx` as the first argument.) The quick way to do this is to change the top of the function to
|
||||
```C
|
||||
void EnJj_Init(Actor* thisx, GlobalContext* globalCtx2) {
|
||||
GlobalContext* globalCtx = globalCtx2;
|
||||
void EnJj_Init(Actor* thisx, PlayState* play2) {
|
||||
PlayState* play = play2;
|
||||
EnJj* this = THIS;
|
||||
...
|
||||
```
|
||||
|
|
|
@ -84,10 +84,10 @@ Large code block, click to show
|
|||
|
||||
#define THIS ((EnTg*)thisx)
|
||||
|
||||
void EnTg_Init(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnTg_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnTg_Update(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnTg_Draw(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnTg_Init(Actor* thisx, PlayState* play);
|
||||
void EnTg_Destroy(Actor* thisx, PlayState* play);
|
||||
void EnTg_Update(Actor* thisx, PlayState* play);
|
||||
void EnTg_Draw(Actor* thisx, PlayState* play);
|
||||
|
||||
s32 D_80B18910[] = { 0x0A000039, 0x20010000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000100, 0x00140040, 0x00000000, 0x00000000 };
|
||||
|
||||
|
@ -136,18 +136,18 @@ to tell the compiler not to look for the data in that file any more. Now run `ma
|
|||
|
||||
Now carry out the usual steps to decompile `Init`. The usual cleanup and struct population gets us to
|
||||
```C
|
||||
void EnTg_Init(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void EnTg_Init(Actor *thisx, PlayState *play) {
|
||||
EnTg *this = THIS;
|
||||
|
||||
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawFunc_Circle, 28.0f);
|
||||
SkelAnime_InitFlex(globalCtx, &this->skelAnime, &D_0600AE40, &D_06005040, 0, 0, 0);
|
||||
Collider_InitCylinder(globalCtx, &this->collider);
|
||||
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, (ColliderCylinderInit *) D_80B18910);
|
||||
SkelAnime_InitFlex(play, &this->skelAnime, &D_0600AE40, &D_06005040, 0, 0, 0);
|
||||
Collider_InitCylinder(play, &this->collider);
|
||||
Collider_SetCylinder(play, &this->collider, &this->actor, (ColliderCylinderInit *) D_80B18910);
|
||||
func_80061EFC(&this->actor.colChkInfo, NULL, (CollisionCheckInfoInit2 *) D_80B1893C);
|
||||
this->actor.unk_1F = 6;
|
||||
Actor_SetScale(&this->actor, 0.01f);
|
||||
this->actionFunc = func_80B185C0;
|
||||
this->unk_208 = globalCtx->state.frames & 1;
|
||||
this->unk_208 = play->state.frames & 1;
|
||||
}
|
||||
```
|
||||
and it remains to deal with the data. mips2c has told us what the types should be. We run `colliderinit` on `D_80B18910` as usual, which gives
|
||||
|
@ -182,7 +182,7 @@ CollisionCheckInfoInit2 D_80B1893C = { 0, 0, 0, 0, 0xFF };
|
|||
|
||||
One more thing needs to change: since both are no longer arrays, we need to make the uses in the functions pointers:
|
||||
```C
|
||||
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &D_80B18910);
|
||||
Collider_SetCylinder(play, &this->collider, &this->actor, &D_80B18910);
|
||||
func_80061EFC(&this->actor.colChkInfo, NULL, &D_80B1893C);
|
||||
```
|
||||
|
||||
|
@ -190,7 +190,7 @@ A quick check of the diff shows that we just need to put the action function set
|
|||
|
||||
Following the function tree as usual, we find the only other place any data is used is in `func_80B1871C`. From its use in `EnTg_Draw`, we realise that this is a `PostLimbDraw` function. Giving mips2c the correct prototype, it comes out as
|
||||
```C
|
||||
void func_80B1871C(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
||||
void func_80B1871C(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
||||
? sp18;
|
||||
|
||||
sp18.unk0 = (s32) D_80B18968->unk0;
|
||||
|
@ -207,7 +207,7 @@ Vec3f D_80B18968 = { 0.0f, 800.0f, 0.0f };
|
|||
```
|
||||
and the function matches as
|
||||
```C
|
||||
void func_80B1871C(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
||||
void func_80B1871C(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) {
|
||||
EnTg* this = THIS;
|
||||
|
||||
Vec3f sp18 = D_80B18968;
|
||||
|
|
|
@ -12,13 +12,13 @@ For this tutorial we will first look at the `EnJj` draw function, `EnJj_Draw`, t
|
|||
Unless it is completely invisible, an actor usually has a draw function as one of the main four actor functions. Hence its prototype looks like
|
||||
|
||||
```C
|
||||
EnJj_Draw(Actor* thisx, GlobalContext* globalCtx);
|
||||
EnJj_Draw(Actor* thisx, PlayState* play);
|
||||
```
|
||||
|
||||
As in Init, Destroy and Update, it is much more convenient to feed mips2c the fake prototype
|
||||
|
||||
```C
|
||||
EnJj_Draw(EnJj* this, GlobalContext* globalCtx);
|
||||
EnJj_Draw(EnJj* this, PlayState* play);
|
||||
```
|
||||
|
||||
so that it fills out the struct fields from the actuar actor; we then put a
|
||||
|
@ -29,7 +29,7 @@ EnJj* this = THIS;
|
|||
|
||||
in the declarations as before. From now on, the process is rather different from the decompilation process used for the other functions. Here is the output of mips2c after sorting out the actor struct from Init, and with the arguments set back to `Actor* thisx`:
|
||||
```C
|
||||
void EnJj_Draw(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void EnJj_Draw(Actor *thisx, PlayState *play) {
|
||||
EnJj* this = THIS;
|
||||
|
||||
GraphicsContext *sp4C;
|
||||
|
@ -39,10 +39,10 @@ void EnJj_Draw(Actor *thisx, GlobalContext *globalCtx) {
|
|||
GraphicsContext *temp_a1;
|
||||
s32 temp_a0;
|
||||
|
||||
temp_a1 = globalCtx->state.gfxCtx;
|
||||
temp_a1 = play->state.gfxCtx;
|
||||
sp4C = temp_a1;
|
||||
Graph_OpenDisps(&sp3C, temp_a1, (const char *) "../z_en_jj.c", 0x36F);
|
||||
func_800943C8(globalCtx->state.gfxCtx);
|
||||
func_800943C8(play->state.gfxCtx);
|
||||
Matrix_Translate(0.0f, (cosf(this->skelAnime.curFrame * 0.076624215f) * 10.0f) - 10.0f, 0.0f, (u8)1U);
|
||||
Matrix_Scale(10.0f, 10.0f, 10.0f, (u8)1U);
|
||||
temp_v1 = temp_a1->polyOpa.p;
|
||||
|
@ -51,8 +51,8 @@ void EnJj_Draw(Actor *thisx, GlobalContext *globalCtx) {
|
|||
temp_a0 = *(&D_80A88CFC + (this->unk_30E * 4));
|
||||
temp_v1->words.w1 = (temp_a0 & 0xFFFFFF) + gSegments[(u32) (temp_a0 * 0x10) >> 0x1C] + 0x80000000;
|
||||
sp18 = this;
|
||||
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable, (s32) this->skelAnime.dListCount, 0, 0);
|
||||
Graph_CloseDisps(&sp3C, globalCtx->state.gfxCtx, (const char *) "../z_en_jj.c", 0x382);
|
||||
SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, (s32) this->skelAnime.dListCount, 0, 0);
|
||||
Graph_CloseDisps(&sp3C, play->state.gfxCtx, (const char *) "../z_en_jj.c", 0x382);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -131,7 +131,7 @@ OPEN_DISPS(temp_a1, "../z_en_jj.c", 879);
|
|||
```
|
||||
(the last argument is a line number, so should be in decimal).
|
||||
|
||||
The function may or may not use a temp for `globalCtx->state.gfxCtx`: you have to work it out using the diff.
|
||||
The function may or may not use a temp for `play->state.gfxCtx`: you have to work it out using the diff.
|
||||
|
||||
Once you've replaced all the blocks and the open and close with macros, you proceed with the function as usual.
|
||||
|
||||
|
@ -141,21 +141,21 @@ Two last things: the last argument of the matrix functions tells the compiler wh
|
|||
|
||||
After all that, it turns out that
|
||||
```C
|
||||
void EnJj_Draw(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void EnJj_Draw(Actor *thisx, PlayState *play) {
|
||||
EnJj *this = THIS;
|
||||
|
||||
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_jj.c", 879);
|
||||
func_800943C8(globalCtx->state.gfxCtx);
|
||||
OPEN_DISPS(play->state.gfxCtx, "../z_en_jj.c", 879);
|
||||
func_800943C8(play->state.gfxCtx);
|
||||
Matrix_Translate(0.0f, (cosf(this->skelAnime.curFrame * (M_PI/41.0f)) * 10.0f) - 10.0f, 0.0f, 1);
|
||||
Matrix_Scale(10.0f, 10.0f, 10.0f, 1);
|
||||
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(D_80A88CFC[this->unk_30E]));
|
||||
SkelAnime_DrawFlexOpa(globalCtx, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
||||
SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable,
|
||||
this->skelAnime.dListCount, 0, 0, this);
|
||||
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_jj.c", 898);
|
||||
CLOSE_DISPS(play->state.gfxCtx, "../z_en_jj.c", 898);
|
||||
}
|
||||
```
|
||||
|
||||
matches apart from a couple of stack differences. This can be resolved by giving it `GlobalContext* globalCtx = globalCtx2;` at the top of the function and changing the second argument to `globalCtx2` as usual.
|
||||
matches apart from a couple of stack differences. This can be resolved by giving it `PlayState* play = play2;` at the top of the function and changing the second argument to `play2` as usual.
|
||||
|
||||
We have enums for the last argument of the matrix functions: `0` is `MTXMODE_NEW`, `1` is `MTXMODE_APPLY`.
|
||||
|
||||
|
@ -169,7 +169,7 @@ For more examples of graphics macros and the structure of Draw functions, we loo
|
|||
The mips2c output for
|
||||
|
||||
```C
|
||||
void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void func_809F5A6C(Actor *thisx, PlayState *play) {
|
||||
? sp60;
|
||||
Gfx *sp48;
|
||||
Gfx *sp38;
|
||||
|
@ -187,17 +187,17 @@ void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
|
|||
sp60.unk0 = (s32) D_809F5E94.unk0;
|
||||
sp60.unk4 = (s32) D_809F5E94.unk4;
|
||||
sp60.unk8 = (s32) D_809F5E94.unk8;
|
||||
temp_a1 = globalCtx->state.gfxCtx;
|
||||
temp_a1 = play->state.gfxCtx;
|
||||
temp_s0 = temp_a1;
|
||||
Graph_OpenDisps(&sp48, temp_a1, (const char *) "../z_en_dnt_nomal.c", 0x6FE);
|
||||
func_80093D18(globalCtx->state.gfxCtx);
|
||||
func_80093D18(play->state.gfxCtx);
|
||||
temp_v0 = temp_s0->polyOpa.p;
|
||||
temp_s0->polyOpa.p = temp_v0 + 8;
|
||||
temp_v0->words.w0 = 0xDB060020;
|
||||
temp_a0 = *(&D_809F5EA0 + (thisx->unk268 * 4));
|
||||
temp_v0->words.w1 = (temp_a0 & 0xFFFFFF) + gSegments[(u32) (temp_a0 * 0x10) >> 0x1C] + 0x80000000;
|
||||
sp14 = thisx;
|
||||
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, &func_809F58E4, &func_809F59E4);
|
||||
SkelAnime_DrawOpa(play, thisx->unk150, thisx->unk16C, &func_809F58E4, &func_809F59E4);
|
||||
Matrix_Translate(thisx->unk21C, thisx->unk220, (bitwise f32) thisx->unk224, (u8)0U);
|
||||
Matrix_Scale(0.01f, 0.01f, 0.01f, (u8)1U);
|
||||
temp_v0_2 = temp_s0->polyOpa.p;
|
||||
|
@ -213,14 +213,14 @@ void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
|
|||
temp_s0->polyOpa.p = temp_v0_4 + 8;
|
||||
temp_v0_4->words.w0 = 0xDA380003;
|
||||
sp38 = temp_v0_4;
|
||||
sp38->words.w1 = Matrix_NewMtx(globalCtx->state.gfxCtx, (char *) "../z_en_dnt_nomal.c", 0x716);
|
||||
sp38->words.w1 = Matrix_NewMtx(play->state.gfxCtx, (char *) "../z_en_dnt_nomal.c", 0x716);
|
||||
temp_v0_5 = temp_s0->polyOpa.p;
|
||||
temp_s0->polyOpa.p = temp_v0_5 + 8;
|
||||
temp_v0_5->words.w1 = (u32) &D_06001B00;
|
||||
temp_v0_5->words.w0 = 0xDE000000;
|
||||
Graph_CloseDisps(&sp48, globalCtx->state.gfxCtx, (const char *) "../z_en_dnt_nomal.c", 0x719);
|
||||
Graph_CloseDisps(&sp48, play->state.gfxCtx, (const char *) "../z_en_dnt_nomal.c", 0x719);
|
||||
if (&func_809F49A4 == thisx->unk214) {
|
||||
func_80033C30((Vec3f *) &thisx->world, (Vec3f *) &sp60, (u8)0xFFU, globalCtx);
|
||||
func_80033C30((Vec3f *) &thisx->world, (Vec3f *) &sp60, (u8)0xFFU, play);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -328,7 +328,7 @@ temp_v0_4 = temp_s0->polyOpa.p;
|
|||
temp_s0->polyOpa.p = temp_v0_4 + 8;
|
||||
temp_v0_4->words.w0 = 0xDA380003;
|
||||
sp38 = temp_v0_4;
|
||||
sp38->words.w1 = Matrix_NewMtx(globalCtx->state.gfxCtx, (char *) "../z_en_dnt_nomal.c", 0x716);
|
||||
sp38->words.w1 = Matrix_NewMtx(play->state.gfxCtx, (char *) "../z_en_dnt_nomal.c", 0x716);
|
||||
```
|
||||
The macro is
|
||||
```
|
||||
|
@ -337,7 +337,7 @@ gSPMatrix(POLY_OPA_DISP++, 0x12345678, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVI
|
|||
```
|
||||
and the second argument is filled by the `Matrix_NewMtx` function:
|
||||
```C
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1814), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, "../z_en_dnt_nomal.c", 1814), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
```
|
||||
|
||||
Lastly,
|
||||
|
@ -359,7 +359,7 @@ gSPDisplayList(POLY_OPA_DISP++, D_06001B00);
|
|||
|
||||
Putting this all together
|
||||
```C
|
||||
void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void func_809F5A6C(Actor *thisx, PlayState *play) {
|
||||
EnDntNormal *this = THIS;
|
||||
? sp60;
|
||||
Actor *sp14;
|
||||
|
@ -369,26 +369,26 @@ void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
|
|||
sp60.unk4 = (s32) D_809F5E94.unk4;
|
||||
sp60.unk8 = (s32) D_809F5E94.unk8;
|
||||
|
||||
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1790);
|
||||
func_80093D18(globalCtx->state.gfxCtx);
|
||||
OPEN_DISPS(play->state.gfxCtx, "../z_en_dnt_nomal.c", 1790);
|
||||
func_80093D18(play->state.gfxCtx);
|
||||
|
||||
gSPSegment(POLY_OPA_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(D_809F5EA0[this->unk_268]));
|
||||
|
||||
sp14 = this;
|
||||
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, &func_809F58E4, &func_809F59E4);
|
||||
SkelAnime_DrawOpa(play, thisx->unk150, thisx->unk16C, &func_809F58E4, &func_809F59E4);
|
||||
Matrix_Translate(thisx->unk21C, thisx->unk220, (bitwise f32) thisx->unk224, (u8)0U);
|
||||
Matrix_Scale(0.01f, 0.01f, 0.01f, (u8)1U);
|
||||
|
||||
gDPPipeSync(POLY_OPA_DISP++);
|
||||
temp_v1 = D_809F5E4C[this->unk_26A - 1];
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, temp_v1.r, temp_v1.g, temp_v1.r, 0xFF);
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1814), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, "../z_en_dnt_nomal.c", 1814), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gSPDisplayList(POLY_OPA_DISP++, D_06001B00);
|
||||
|
||||
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1817);
|
||||
CLOSE_DISPS(play->state.gfxCtx, "../z_en_dnt_nomal.c", 1817);
|
||||
|
||||
if (&func_809F49A4 == this->unk214) {
|
||||
func_80033C30((Vec3f *) &this.actor->world, (Vec3f *) &sp60, (u8)0xFFU, globalCtx);
|
||||
func_80033C30((Vec3f *) &this.actor->world, (Vec3f *) &sp60, (u8)0xFFU, play);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -398,23 +398,23 @@ void func_809F5A6C(Actor *thisx, GlobalContext *globalCtx) {
|
|||
Some more general tidying up can be done here (`sp60` and so `D_809F5E94` are `Vec3f`, for example, and under normal circumstances we'd know that ), but the big remaining issue is
|
||||
```C
|
||||
sp14 = this;
|
||||
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, func_809F58E4, func_809F59E4);
|
||||
SkelAnime_DrawOpa(play, thisx->unk150, thisx->unk16C, func_809F58E4, func_809F59E4);
|
||||
```
|
||||
If we look at the definition of `SkelAnime_DrawOpa`, we find that it's missing the last argument. This is mips2c not noticing why `this` has been put on the stack: this code should actually be
|
||||
```C
|
||||
SkelAnime_DrawOpa(globalCtx, thisx->unk150, thisx->unk16C, func_809F58E4, func_809F59E4, this);
|
||||
SkelAnime_DrawOpa(play, thisx->unk150, thisx->unk16C, func_809F58E4, func_809F59E4, this);
|
||||
```
|
||||
mips2c doing this is not especially unusual, so bear it in mind.
|
||||
|
||||
The other thing this tells us is that `func_809F58E4` is of type `OverrideLimbDraw`, and `func_809F59E4` of type `PostLimbDraw`. Their names are fairly self-explanatory. Filling in the prototypes as
|
||||
```C
|
||||
s32 func_809F58E4(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx);
|
||||
void func_809F59E4(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx);
|
||||
s32 func_809F58E4(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f* pos, Vec3s* rot, void* thisx);
|
||||
void func_809F59E4(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx);
|
||||
```
|
||||
and running mips2c gives
|
||||
|
||||
```C
|
||||
s32 func_809F58E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3f *pos, Vec3s *rot, void *thisx) {
|
||||
s32 func_809F58E4(PlayState *play, s32 limbIndex, Gfx **dList, Vec3f *pos, Vec3s *rot, void *thisx) {
|
||||
GraphicsContext *sp38;
|
||||
Gfx *sp28;
|
||||
Gfx *temp_v1;
|
||||
|
@ -423,7 +423,7 @@ s32 func_809F58E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3f *p
|
|||
void *temp_v0;
|
||||
|
||||
if ((limbIndex == 1) || (limbIndex == 3) || (limbIndex == 4) || (limbIndex == 5) || (limbIndex == 6)) {
|
||||
temp_a1 = globalCtx->state.gfxCtx;
|
||||
temp_a1 = play->state.gfxCtx;
|
||||
sp38 = temp_a1;
|
||||
Graph_OpenDisps(&sp28, temp_a1, (const char *) "../z_en_dnt_nomal.c", 0x6C5);
|
||||
temp_v1 = sp38->polyOpa.p;
|
||||
|
@ -435,12 +435,12 @@ s32 func_809F58E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3f *p
|
|||
temp_v1_2->words.w0 = 0xFB000000;
|
||||
temp_v0 = (thisx->unk26A * 4) + &D_809F5E4C;
|
||||
temp_v1_2->words.w1 = (temp_v0->unk-2 << 8) | (temp_v0->unk-4 << 0x18) | (temp_v0->unk-3 << 0x10) | 0xFF;
|
||||
Graph_CloseDisps(&sp28, globalCtx->state.gfxCtx, (const char *) "../z_en_dnt_nomal.c", 0x6CF);
|
||||
Graph_CloseDisps(&sp28, play->state.gfxCtx, (const char *) "../z_en_dnt_nomal.c", 0x6CF);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void func_809F59E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3s *rot, void *thisx) {
|
||||
void func_809F59E4(PlayState *play, s32 limbIndex, Gfx **dList, Vec3s *rot, void *thisx) {
|
||||
? sp18;
|
||||
|
||||
sp18.unk0 = (s32) D_809F5E88.unk0;
|
||||
|
@ -459,14 +459,14 @@ void func_809F59E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3s *
|
|||
|
||||
This structure is pretty typical: both edit what certain limbs do. Both also usually need a `ActorName *this = THIS;` at the top. We have seen both of the macros in the former before: applying the usual procedure, we find that it becomes
|
||||
```C
|
||||
s32 func_809F58E4(GlobalContext *globalCtx, s32 limbIndex, Gfx **dList, Vec3f *pos, Vec3s *rot, void *thisx) {
|
||||
s32 func_809F58E4(PlayState *play, s32 limbIndex, Gfx **dList, Vec3f *pos, Vec3s *rot, void *thisx) {
|
||||
EnDntNormal *this = THIS;
|
||||
|
||||
if ((limbIndex == 1) || (limbIndex == 3) || (limbIndex == 4) || (limbIndex == 5) || (limbIndex == 6)) {
|
||||
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1733);
|
||||
OPEN_DISPS(play->state.gfxCtx, "../z_en_dnt_nomal.c", 1733);
|
||||
gDPPipeSync(POLY_OPA_DISP++);
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, D_809F5E4C[this->type - 1].r, D_809F5E4C[this->type - 1].g, D_809F5E4C[this->type - 1].b, 255);
|
||||
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_en_dnt_nomal.c", 1743);
|
||||
CLOSE_DISPS(play->state.gfxCtx, "../z_en_dnt_nomal.c", 1743);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ glabel func_80A87F44
|
|||
```
|
||||
This is a classic "function with two arguments that does nothing". So we can simply comment out the appropriate pragma and put
|
||||
```C
|
||||
void func_80A87F44(Actor* thisx, GlobalContext* globalCtx) {
|
||||
void func_80A87F44(Actor* thisx, PlayState* play) {
|
||||
|
||||
}
|
||||
```
|
||||
|
@ -30,16 +30,16 @@ in the C file.
|
|||
|
||||
Destroy will be a dead end, but we might as well do it now. Remaking the context and using mips2c on it (main 4 function, so change the prototype to use `EnJj* this`!) gives
|
||||
```C
|
||||
void EnJj_Destroy(EnJj *this, GlobalContext *globalCtx) {
|
||||
GlobalContext *temp_a3;
|
||||
void EnJj_Destroy(EnJj *this, PlayState *play) {
|
||||
PlayState *temp_a3;
|
||||
s16 temp_v0;
|
||||
|
||||
temp_v0 = this->dyna.actor.params;
|
||||
temp_a3 = globalCtx;
|
||||
temp_a3 = play;
|
||||
if (temp_v0 == -1) {
|
||||
globalCtx = temp_a3;
|
||||
play = temp_a3;
|
||||
DynaPoly_DeleteBgActor(temp_a3, &temp_a3->colCtx.dyna, (s32) this->dyna.bgId);
|
||||
Collider_DestroyCylinder(globalCtx, &this->collider);
|
||||
Collider_DestroyCylinder(play, &this->collider);
|
||||
return;
|
||||
}
|
||||
if ((temp_v0 != 0) && (temp_v0 != 1)) {
|
||||
|
@ -51,15 +51,15 @@ void EnJj_Destroy(EnJj *this, GlobalContext *globalCtx) {
|
|||
|
||||
Again remember to return the first argument to `Actor* this` and put `EnJj* this = THIS;` in the function body. Based on what we know about this actor already, we expect this to be another switch. Rearranging it as such, and removing the likely fake `temp_v0` gives
|
||||
```C
|
||||
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
||||
void EnJj_Destroy(Actor* thisx, PlayState* play) {
|
||||
EnJj* this = THIS;
|
||||
GlobalContext* temp_a3;
|
||||
temp_a3 = globalCtx;
|
||||
PlayState* temp_a3;
|
||||
temp_a3 = play;
|
||||
|
||||
switch (this->dyna.actor.params) {
|
||||
case -1:
|
||||
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
|
||||
Collider_DestroyCylinder(globalCtx, &this->collider);
|
||||
DynaPoly_DeleteBgActor(play, &play->colCtx.dyna, this->dyna.bgId);
|
||||
Collider_DestroyCylinder(play, &this->collider);
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
|
@ -70,23 +70,23 @@ void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
|||
```
|
||||
Using `./diff.py -mwo3 EnJj_Destroy` shows that this matches already, but it seems like the temp usage should be more consistent. A little experimentation shows that
|
||||
```C
|
||||
void EnJj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
||||
void EnJj_Destroy(Actor* thisx, PlayState* play) {
|
||||
EnJj* this = THIS;
|
||||
|
||||
switch (this->dyna.actor.params) {
|
||||
case -1:
|
||||
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
|
||||
Collider_DestroyCylinder(globalCtx, &this->collider);
|
||||
DynaPoly_DeleteBgActor(play, &play->colCtx.dyna, this->dyna.bgId);
|
||||
Collider_DestroyCylinder(play, &this->collider);
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
|
||||
DynaPoly_DeleteBgActor(play, &play->colCtx.dyna, this->dyna.bgId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
also matches, with no need for the `GlobalContext*` temp.
|
||||
also matches, with no need for the `PlayState*` temp.
|
||||
|
||||
## Action Functions
|
||||
|
||||
|
@ -94,7 +94,7 @@ also matches, with no need for the `GlobalContext*` temp.
|
|||
|
||||
Of the two functions we have available, `func_80A87BEC` is shorter, so we do that next. Since we haven't changed any types or header file information, there is no need to remake the context. mips2c gives
|
||||
```C
|
||||
void func_80A87BEC(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87BEC(EnJj *this, PlayState *play) {
|
||||
if (this->dyna.actor.xzDistToPlayer < 300.0f) {
|
||||
func_80A87800(this, &func_80A87B9C);
|
||||
}
|
||||
|
@ -104,10 +104,10 @@ void func_80A87BEC(EnJj *this, GlobalContext *globalCtx) {
|
|||
We see that this function just sets another action function when Link is close enough to the actor. All we have to do to this is remove the `&`, and prototype `func_80A87B9C` to be an action function. Notably, this time it is not used before it is defined, so we don't need a prototype at the top: putting a placeholder one in at the function position will do, i.e. our total edits this time are
|
||||
```C
|
||||
#pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Jj/func_80A87B9C.s")
|
||||
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx);
|
||||
void func_80A87B9C(EnJj *this, PlayState *play);
|
||||
|
||||
// #pragma GLOBAL_ASM("asm/non_matchings/overlays/actors/ovl_En_Jj/func_80A87BEC.s")
|
||||
void func_80A87BEC(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87BEC(EnJj *this, PlayState *play) {
|
||||
if (this->dyna.actor.xzDistToPlayer < 300.0f) {
|
||||
func_80A87800(this, func_80A87B9C);
|
||||
}
|
||||
|
@ -120,14 +120,14 @@ We can now either follow this chain of action functions down, or start with the
|
|||
|
||||
We can remake the context, but it's simpler to just stick the function prototype we made at the bottom of the context. Either way, mips2c gives us
|
||||
```C
|
||||
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87B9C(EnJj *this, PlayState *play) {
|
||||
s16 temp_v0;
|
||||
|
||||
temp_v0 = this->unk308;
|
||||
if ((s32) temp_v0 >= -0x1450) {
|
||||
this->unk308 = (s16) (temp_v0 - 0x66);
|
||||
if ((s32) this->unk308 < -0xA28) {
|
||||
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, this->childActor->unk14C);
|
||||
func_8003EBF8(play, &play->colCtx.dyna, this->childActor->unk14C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,11 +163,11 @@ this->childActor = (DynaPolyActor*)Actor_SpawnAsChild(...)
|
|||
|
||||
Doing so, we are left with
|
||||
```C
|
||||
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87B9C(EnJj *this, PlayState *play) {
|
||||
if (this->unk_308 >= -0x1450) {
|
||||
this->unk_308 -= 0x66;
|
||||
if (this->unk_308 < -0xA28) {
|
||||
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, this->childActor->bgId);
|
||||
func_8003EBF8(play, &play->colCtx.dyna, this->childActor->bgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ The first suggestion looks plausible:
|
|||
+++ after
|
||||
@@ -1390,12 +1390,14 @@
|
||||
} EnJj;
|
||||
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx)
|
||||
void func_80A87B9C(EnJj *this, PlayState *play)
|
||||
{
|
||||
- if (this->unk_308 >= (-0x1450))
|
||||
+ DynaPolyActor *new_var;
|
||||
|
@ -214,8 +214,8 @@ The first suggestion looks plausible:
|
|||
this->unk_308 -= 0x66;
|
||||
if (this->unk_308 < (-0xA28))
|
||||
{
|
||||
- func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, this->childActor->bgId);
|
||||
+ func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, new_var->bgId);
|
||||
- func_8003EBF8(play, &play->colCtx.dyna, this->childActor->bgId);
|
||||
+ func_8003EBF8(play, &play->colCtx.dyna, new_var->bgId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -223,13 +223,13 @@ The first suggestion looks plausible:
|
|||
|
||||
In particular, adding a temp for the actor. Some of the rest is rather puzzling, but let's just try the actor temp,
|
||||
```C
|
||||
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87B9C(EnJj *this, PlayState *play) {
|
||||
DynaPolyActor* child = this->childActor;
|
||||
|
||||
if (this->unk_308 >= -0x1450) {
|
||||
this->unk_308 -= 0x66;
|
||||
if (this->unk_308 < -0xA28) {
|
||||
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
|
||||
func_8003EBF8(play, &play->colCtx.dyna, child->bgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,13 +241,13 @@ Hooray, that worked. The function now matches (as you can check by running `make
|
|||
|
||||
However, the hex values look a bit strange, and it turns out the decimal equivalents look less strange, so it's a good idea to translate them:
|
||||
```C
|
||||
void func_80A87B9C(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87B9C(EnJj *this, PlayState *play) {
|
||||
DynaPolyActor* child = this->childActor;
|
||||
|
||||
if (this->unk_308 >= -5200) {
|
||||
this->unk_308 -= 102;
|
||||
if (this->unk_308 < -2600) {
|
||||
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
|
||||
func_8003EBF8(play, &play->colCtx.dyna, child->bgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,29 +259,29 @@ With that, we have reached the end of this action function chain, and now have t
|
|||
|
||||
Remaking the context and running mips2c on the assembly gives
|
||||
```C
|
||||
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, globalCtx->unk1C44 + 0x24) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
|
||||
void func_80A87C30(EnJj *this, PlayState *play) {
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, play->unk1C44 + 0x24) < 300.0f) && (play->isPlayerDroppingFish(play) != 0)) {
|
||||
this->unk_30C = 0x64;
|
||||
func_80A87800(this, &func_80A87CEC);
|
||||
}
|
||||
this->collider.dim.pos.x = -0x4DD;
|
||||
this->collider.dim.pos.y = 0x14;
|
||||
this->collider.dim.pos.z = -0x30;
|
||||
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, (Collider *) &this->collider);
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, (Collider *) &this->collider);
|
||||
}
|
||||
```
|
||||
|
||||
If you know anything about this game, this is obviously the function that begins the process of the swallowing Link cutscene. Performing minor cleanups reduces us to
|
||||
```C
|
||||
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, globalCtx->unk1C44 + 0x24) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
|
||||
void func_80A87C30(EnJj *this, PlayState *play) {
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, play->unk1C44 + 0x24) < 300.0f) && (play->isPlayerDroppingFish(play) != 0)) {
|
||||
this->unk_30C = 100;
|
||||
func_80A87800(this, func_80A87CEC);
|
||||
}
|
||||
this->collider.dim.pos.x = -1245;
|
||||
this->collider.dim.pos.y = 20;
|
||||
this->collider.dim.pos.z = -48;
|
||||
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider);
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -294,23 +294,23 @@ extern Vec3f D_80A88CF0;
|
|||
```
|
||||
(you must include the `.0f` parts even for integer floats: it can affect codegen, and as such it is part of our style).
|
||||
|
||||
- replace the mysterious `globalCtx->unk1C44 + 0x24`. The first part is so common that most people on decomp know it by heart: it is the location of the Player actor. `+ 0x24` is obviously an offset that leats to a `Vec3f`, and if you look in the actor struct, you find that this is the location of `world.pos`. To use `Player`, we put `Player* player = GET_PLAYER(globalCtx)` at the top of the function.
|
||||
- replace the mysterious `play->unk1C44 + 0x24`. The first part is so common that most people on decomp know it by heart: it is the location of the Player actor. `+ 0x24` is obviously an offset that leats to a `Vec3f`, and if you look in the actor struct, you find that this is the location of `world.pos`. To use `Player`, we put `Player* player = GET_PLAYER(play)` at the top of the function.
|
||||
|
||||
**NOTE:** mips_to_c will now output something like `&globalCtx->actorCtx.actorLists[2].head` for the Player pointer instead: this makes a lot more sense, but is not so easy to spot in the ASM without the characteristic `1C44`.
|
||||
**NOTE:** mips_to_c will now output something like `&play->actorCtx.actorLists[2].head` for the Player pointer instead: this makes a lot more sense, but is not so easy to spot in the ASM without the characteristic `1C44`.
|
||||
|
||||
After all this, the function becomes
|
||||
```C
|
||||
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
|
||||
Player* player = GET_PLAYER(globalCtx);
|
||||
void func_80A87C30(EnJj *this, PlayState *play) {
|
||||
Player* player = GET_PLAYER(play);
|
||||
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, &player->actor.world.pos) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, &player->actor.world.pos) < 300.0f) && (play->isPlayerDroppingFish(play) != 0)) {
|
||||
this->unk_30C = 100;
|
||||
func_80A87800(this, func_80A87CEC);
|
||||
}
|
||||
this->collider.dim.pos.x = -1245;
|
||||
this->collider.dim.pos.y = 20;
|
||||
this->collider.dim.pos.z = -48;
|
||||
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider);
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -341,19 +341,19 @@ typedef struct EnJj {
|
|||
} EnJj; // size = 0x0314
|
||||
```
|
||||
|
||||
The diff now looks fine for this function, but it gives compiler warnings about `CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider);`: the last argument is the wrong type: we need to give it `&this->collider.base` instead, which points to the same address, but is the right type. So the matching function is
|
||||
The diff now looks fine for this function, but it gives compiler warnings about `CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider);`: the last argument is the wrong type: we need to give it `&this->collider.base` instead, which points to the same address, but is the right type. So the matching function is
|
||||
```C
|
||||
void func_80A87C30(EnJj *this, GlobalContext *globalCtx) {
|
||||
Player* player = GET_PLAYER(globalCtx);
|
||||
void func_80A87C30(EnJj *this, PlayState *play) {
|
||||
Player* player = GET_PLAYER(play);
|
||||
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, &player->actor.world.pos) < 300.0f) && (globalCtx->isPlayerDroppingFish(globalCtx) != 0)) {
|
||||
if ((Math_Vec3f_DistXZ(&D_80A88CF0, &player->actor.world.pos) < 300.0f) && (play->isPlayerDroppingFish(play) != 0)) {
|
||||
this->unk_30C = 100;
|
||||
func_80A87800(this, func_80A87CEC);
|
||||
}
|
||||
this->collider.dim.pos.x = -1245;
|
||||
this->collider.dim.pos.y = 20;
|
||||
this->collider.dim.pos.z = -48;
|
||||
CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collider.base);
|
||||
CollisionCheck_SetOC(play, &play->colChkCtx, &this->collider.base);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -363,7 +363,7 @@ Again we have only one choice for our next function, namely `func_80A87CEC`.
|
|||
|
||||
Remaking the context and running mips2c on the assembly gives
|
||||
```C
|
||||
void func_80A87CEC(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87CEC(EnJj *this, PlayState *play) {
|
||||
DynaPolyActor *sp1C;
|
||||
DynaPolyActor *temp_v1;
|
||||
s16 temp_v0;
|
||||
|
@ -375,12 +375,12 @@ void func_80A87CEC(EnJj *this, GlobalContext *globalCtx) {
|
|||
return;
|
||||
}
|
||||
sp1C = temp_v1;
|
||||
globalCtx = globalCtx;
|
||||
play = play;
|
||||
func_80A87800(this, &func_80A87EF0);
|
||||
globalCtx->csCtx.segment = &D_80A88164;
|
||||
play->csCtx.segment = &D_80A88164;
|
||||
gSaveContext.cutsceneTrigger = (u8)1U;
|
||||
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, (s32) temp_v1->bgId);
|
||||
func_8005B1A4(globalCtx->cameraPtrs[globalCtx->activeCamId]);
|
||||
func_8003EBF8(play, &play->colCtx.dyna, (s32) temp_v1->bgId);
|
||||
func_8005B1A4(play->cameraPtrs[play->activeCamId]);
|
||||
gSaveContext.unkEDA = (u16) (gSaveContext.unkEDA | 0x400);
|
||||
func_80078884((u16)0x4802U);
|
||||
}
|
||||
|
@ -394,9 +394,9 @@ Easy things to sort out:
|
|||
|
||||
- We can remove the casts from `(u8)1U` and just leave `1`.
|
||||
|
||||
- `globalCtx->cameraPtrs[globalCtx->activeCamId]` has a macro: it is `GET_ACTIVE_CAM(globalCtx)`, so this line can be written as
|
||||
- `play->cameraPtrs[play->activeCamId]` has a macro: it is `GET_ACTIVE_CAM(play)`, so this line can be written as
|
||||
```C
|
||||
func_8005B1A4(GET_ACTIVE_CAM(globalCtx));
|
||||
func_8005B1A4(GET_ACTIVE_CAM(play));
|
||||
```
|
||||
|
||||
- `gSaveContext.unkEDA` we have dealt with before: it is `gSaveContext.eventChkInf[3]`. This is a flag-setting function; it can be written more compactly as
|
||||
|
@ -408,17 +408,17 @@ gSaveContext.unkEDA |= 0x400
|
|||
|
||||
It remains to work out which, if any, of the temps are real. Based on our previous experience, we expect `temp_v1` to be real. `sp1C` is unused and hence unlikely to be real. `temp_v0` is only used in the short if and so probably not real. Checking the diff shows that our suspicions were correct:
|
||||
```C
|
||||
void func_80A87CEC(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87CEC(EnJj *this, PlayState *play) {
|
||||
DynaPolyActor *child = this->childActor;
|
||||
if (this->unk_30C > 0) {
|
||||
this->unk_30C--;
|
||||
return;
|
||||
}
|
||||
func_80A87800(this, func_80A87EF0);
|
||||
globalCtx->csCtx.segment = &D_80A88164;
|
||||
play->csCtx.segment = &D_80A88164;
|
||||
gSaveContext.cutsceneTrigger = 1;
|
||||
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
|
||||
func_8005B1A4(GET_ACTIVE_CAM(globalCtx));
|
||||
func_8003EBF8(play, &play->colCtx.dyna, child->bgId);
|
||||
func_8005B1A4(GET_ACTIVE_CAM(play));
|
||||
gSaveContext.eventChkInf[3] |= 0x400;
|
||||
func_80078884(NA_SE_SY_CORRECT_CHIME);
|
||||
}
|
||||
|
@ -428,16 +428,16 @@ matches, but generates a complier warning for `func_8005B1A4`, which it can't fi
|
|||
|
||||
Lastly, we prefer to limit use of early `return`s, and use `else`s instead if possible. That applies here: the function can be rewritten as
|
||||
```C
|
||||
void func_80A87CEC(EnJj* this, GlobalContext* globalCtx) {
|
||||
void func_80A87CEC(EnJj* this, PlayState* play) {
|
||||
DynaPolyActor* child = this->childActor;
|
||||
if (this->unk_30C > 0) {
|
||||
this->unk_30C--;
|
||||
} else {
|
||||
func_80A87800(this, func_80A87EF0);
|
||||
globalCtx->csCtx.segment = &D_80A88164;
|
||||
play->csCtx.segment = &D_80A88164;
|
||||
gSaveContext.cutsceneTrigger = 1;
|
||||
func_8003EBF8(globalCtx, &globalCtx->colCtx.dyna, child->bgId);
|
||||
func_8005B1A4(GET_ACTIVE_CAM(globalCtx));
|
||||
func_8003EBF8(play, &play->colCtx.dyna, child->bgId);
|
||||
func_8005B1A4(GET_ACTIVE_CAM(play));
|
||||
gSaveContext.eventChkInf[3] |= 0x400;
|
||||
func_80078884(NA_SE_SY_CORRECT_CHIME);
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ and still match. (Early `return`s are used after an `Actor_Kill` and in a few ot
|
|||
|
||||
mips2c with updated context gives
|
||||
```C
|
||||
void func_80A87EF0(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87EF0(EnJj *this, PlayState *play) {
|
||||
char *temp_a0;
|
||||
u16 temp_v0;
|
||||
|
||||
|
@ -475,7 +475,7 @@ lhu $v0, 0x030A($a0)
|
|||
```
|
||||
which at last tells us that `unk_30A` is actually a `u16`. We can now eliminate `temp_v0`, and replace the ` == 0` by a `!(...)`, which leaves
|
||||
```C
|
||||
void func_80A87EF0(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87EF0(EnJj *this, PlayState *play) {
|
||||
Actor *temp_a0;
|
||||
|
||||
if (!(this->unk_30A & 4)) {
|
||||
|
@ -496,8 +496,8 @@ Again we have run out of action functions. The rules suggest that we now look at
|
|||
|
||||
Update runs every frame and updates the properties of the actor, and usually runs the action functions once per frame. As before we change the first argument to `EnJj* this` to get it to use our actor's struct. mips2c gives
|
||||
```C
|
||||
void EnJj_Update(EnJj *this, GlobalContext *globalCtx) {
|
||||
if ((globalCtx->csCtx.state != CS_STATE_IDLE) && (globalCtx->unk1D94 != 0)) {
|
||||
void EnJj_Update(EnJj *this, PlayState *play) {
|
||||
if ((play->csCtx.state != CS_STATE_IDLE) && (play->unk1D94 != 0)) {
|
||||
func_80A87D94();
|
||||
} else {
|
||||
this->actionFunc(this);
|
||||
|
@ -512,19 +512,19 @@ void EnJj_Update(EnJj *this, GlobalContext *globalCtx) {
|
|||
}
|
||||
```
|
||||
|
||||
This has several problems: firstly, the action function is called with the wrong argument. We should thus be suspicious of previous functions this actor calls, and decompile them mith mips2c without context if necessary, if only to find out how many arguments they have. We find that `func_80A87D94` definitely takes `EnJj* this, GlobalContext* globalCtx` as arguments. Again, put this prototype at the function location above to avoid compiler warnings.
|
||||
This has several problems: firstly, the action function is called with the wrong argument. We should thus be suspicious of previous functions this actor calls, and decompile them mith mips2c without context if necessary, if only to find out how many arguments they have. We find that `func_80A87D94` definitely takes `EnJj* this, PlayState* play` as arguments. Again, put this prototype at the function location above to avoid compiler warnings.
|
||||
|
||||
`unk40` of an array of `Vec3s`s is `0x40 = 0x6 * 0xA + 0x4`, so is actually `this->skelAnime.jointTable[10].z`
|
||||
|
||||
Lastly, what is `globalCtx->unk1D94`? It is at `globalCtx->csCtx + 0x30`, or `globalCtx->csCtx.npcActions + 0x8`, which is `globalCtx->csCtx.npcActions[2]` since this is an array of pointers. Hence it is a pointer, and so should be compared to `NULL`. Looking up the sfx Id again, we end up with
|
||||
Lastly, what is `play->unk1D94`? It is at `play->csCtx + 0x30`, or `play->csCtx.npcActions + 0x8`, which is `play->csCtx.npcActions[2]` since this is an array of pointers. Hence it is a pointer, and so should be compared to `NULL`. Looking up the sfx Id again, we end up with
|
||||
```C
|
||||
void EnJj_Update(Actor *thisx, GlobalContext *globalCtx) {
|
||||
void EnJj_Update(Actor *thisx, PlayState *play) {
|
||||
EnJj* this = THIS;
|
||||
|
||||
if ((globalCtx->csCtx.state != CS_STATE_IDLE) && (globalCtx->csCtx.npcActions[2] != NULL)) {
|
||||
func_80A87D94(this, globalCtx);
|
||||
if ((play->csCtx.state != CS_STATE_IDLE) && (play->csCtx.npcActions[2] != NULL)) {
|
||||
func_80A87D94(this, play);
|
||||
} else {
|
||||
this->actionFunc(this, globalCtx);
|
||||
this->actionFunc(this, play);
|
||||
if (this->skelAnime.curFrame == 41.0f) {
|
||||
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_JABJAB_GROAN);
|
||||
}
|
||||
|
@ -631,7 +631,7 @@ You will also find that the permuter is essentially useless here: most solutions
|
|||
|
||||
This is our last ordinary function. Unfortunately, even with new context, mips2c gives us a bit of a mess:
|
||||
```C
|
||||
void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87D94(EnJj *this, PlayState *play) {
|
||||
s16 temp_v0_2;
|
||||
u16 temp_t1;
|
||||
u16 temp_t4;
|
||||
|
@ -643,7 +643,7 @@ void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
|
|||
u16 temp_v1_3;
|
||||
u16 phi_v1;
|
||||
|
||||
temp_v0 = *globalCtx->unk1D94;
|
||||
temp_v0 = *play->unk1D94;
|
||||
if (temp_v0 != 1) {
|
||||
if (temp_v0 != 2) {
|
||||
if (temp_v0 != 3) {
|
||||
|
@ -667,7 +667,7 @@ void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
|
|||
this->unk_30A = temp_t1;
|
||||
phi_v1 = temp_v1_2;
|
||||
if ((temp_v1_2 & 8) == 0) {
|
||||
this->unk_304 = Actor_SpawnAsChild(&globalCtx->actorCtx, (Actor *) this, globalCtx, (u16)0x101, -1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
|
||||
this->unk_304 = Actor_SpawnAsChild(&play->actorCtx, (Actor *) this, play, (u16)0x101, -1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
|
||||
temp_t4 = this->unk_30A | 8;
|
||||
this->unk_30A = temp_t4;
|
||||
phi_v1 = temp_t4 & 0xFFFF;
|
||||
|
@ -698,16 +698,16 @@ void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
|
|||
|
||||
At the top we have
|
||||
```C
|
||||
temp_v0 = *globalCtx->unk1D94;
|
||||
temp_v0 = *play->unk1D94;
|
||||
if (temp_v0 != 1) {
|
||||
if (temp_v0 != 2) {
|
||||
if (temp_v0 != 3) {
|
||||
```
|
||||
Firstly, we are now comparing with the value of `globalCtx->unk1D94`, not just using a pointer, so we need the first thing in `globalCtx->csCtx.npcActions[2]`. This turns out to be `globalCtx->csCtx.npcActions[2]->action`.
|
||||
Firstly, we are now comparing with the value of `play->unk1D94`, not just using a pointer, so we need the first thing in `play->csCtx.npcActions[2]`. This turns out to be `play->csCtx.npcActions[2]->action`.
|
||||
|
||||
The if structure here is another classic indicator of a switch: nested, with the same variable compared multiple times. If you were to diff this as-is, you would find that the code is in completely the wrong order. Reading how the ifs work, we see that if `temp_v0` is `1`, it executes the outermost else block, if it is `2`, the middle, if `3`, the innermost, and if it is anything else, the contents of the innermost if. Hence this becomes
|
||||
```C
|
||||
void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
|
||||
void func_80A87D94(EnJj *this, PlayState *play) {
|
||||
s16 temp_v0_2;
|
||||
u16 temp_t1;
|
||||
u16 temp_t4;
|
||||
|
@ -719,7 +719,7 @@ void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
|
|||
u16 temp_v1_3;
|
||||
u16 phi_v1;
|
||||
|
||||
switch (globalCtx->csCtx.npcActions[2]->action) {
|
||||
switch (play->csCtx.npcActions[2]->action) {
|
||||
case 1:
|
||||
temp_v1_3 = this->unk_30A;
|
||||
phi_v1 = temp_v1_3;
|
||||
|
@ -739,7 +739,7 @@ void func_80A87D94(EnJj *this, GlobalContext *globalCtx) {
|
|||
this->unk_30A = temp_t1;
|
||||
phi_v1 = temp_v1_2;
|
||||
if ((temp_v1_2 & 8) == 0) {
|
||||
this->unk_304 = Actor_SpawnAsChild(&globalCtx->actorCtx, (Actor *) this, globalCtx, (u16)0x101, -1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
|
||||
this->unk_304 = Actor_SpawnAsChild(&play->actorCtx, (Actor *) this, play, (u16)0x101, -1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
|
||||
temp_t4 = this->unk_30A | 8;
|
||||
this->unk_30A = temp_t4;
|
||||
phi_v1 = temp_t4 & 0xFFFF;
|
||||
|
@ -784,8 +784,8 @@ As usual, most of the remaining temps look fake. The only one that does not is p
|
|||
</summary>
|
||||
|
||||
```C
|
||||
void func_80A87D94(EnJj* this, GlobalContext* globalCtx) {
|
||||
switch (globalCtx->csCtx.npcActions[2]->action) {
|
||||
void func_80A87D94(EnJj* this, PlayState* play) {
|
||||
switch (play->csCtx.npcActions[2]->action) {
|
||||
case 1:
|
||||
if ((this->unk_30A & 2) != 0) {
|
||||
this->unk_30E = 0;
|
||||
|
@ -798,7 +798,7 @@ void func_80A87D94(EnJj* this, GlobalContext* globalCtx) {
|
|||
case 2:
|
||||
this->unk_30A |= 1;
|
||||
if ((this->unk_30A & 8) == 0) {
|
||||
this->unk_304 = Actor_SpawnAsChild(&globalCtx->actorCtx, &this->dyna.actor, globalCtx, ACTOR_EFF_DUST,
|
||||
this->unk_304 = Actor_SpawnAsChild(&play->actorCtx, &this->dyna.actor, play, ACTOR_EFF_DUST,
|
||||
-1100.0f, 105.0f, -27.0f, 0, 0, 0, 0);
|
||||
this->unk_30A |= 8;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ Useful data for guessing types:
|
|||
|
||||
Another useful thing to put here: the prototype for an action function is
|
||||
```C
|
||||
typedef void (*ActorNameActionFunc)(struct ActorName*, GlobalContext*);
|
||||
typedef void (*ActorNameActionFunc)(struct ActorName*, PlayState*);
|
||||
```
|
||||
where you replace `ActorName` by the actual actor name as used elsewhere in the actor, e.g. `EnJj`.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue