Chest size and texture matches contents (#1778)

* Implement most of chest size and texture matches contents, just need an item table

* Add GetItemCategory to getItem tables

* Revert changes that tie chest size and texture to randomizer

* Support chest size & texture as an enhancement that works on outside of rando

* Add gChestSizeAndTextureMatchesContents to rando preset

* Prevent gChestSizeAndTextureMatchesContents in chest minigame

* Fix for forest temple boss key chest

* Add options for texture or size only
This commit is contained in:
Garrett Cox 2022-10-20 21:33:04 -05:00 committed by GitHub
commit e5cc09a96f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 412 additions and 249 deletions

View file

@ -140,7 +140,9 @@ void func_808A39FC(BgMoriHineri* this, GlobalContext* globalCtx) {
colHeader = NULL;
this->dyna.actor.draw = BgMoriHineri_DrawHallAndRoom;
if (this->dyna.actor.params == 0) {
this->actionFunc = func_808A3C8C;
// In vanilla this actionFunc is set to func_808A3C8C, and the boss key chest is rendered from scratch in BgMoriHineri_DrawHallAndRoom
// In SOH we instead spawn the en_box actor, which allows the rendering to be handled consistently with the rest of the chests in the game
this->actionFunc = BgMoriHineri_SpawnBossKeyChest;
CollisionHeader_GetVirtual(&object_mori_hineri1_Col_0054B8, &colHeader);
} else if (this->dyna.actor.params == 1) {
this->actionFunc = BgMoriHineri_SpawnBossKeyChest;
@ -161,9 +163,15 @@ void BgMoriHineri_DoNothing(BgMoriHineri* this, GlobalContext* globalCtx) {
}
void BgMoriHineri_SpawnBossKeyChest(BgMoriHineri* this, GlobalContext* globalCtx) {
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_BOX, this->dyna.actor.world.pos.x + 147.0f,
this->dyna.actor.world.pos.y + -245.0f, this->dyna.actor.world.pos.z + -453.0f, 0, 0x4000, 0, 0x27EE);
this->actionFunc = BgMoriHineri_DoNothing;
if (this->dyna.actor.params == 0) {
Object_Spawn(&globalCtx->objectCtx, OBJECT_BOX);
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_BOX, -1515.0f, 1440.0f, -3475.0f, -0x4000, 0x4000, 0, 0x27EE);
this->actionFunc = func_808A3C8C;
} else {
Actor_Spawn(&globalCtx->actorCtx, globalCtx, ACTOR_EN_BOX, this->dyna.actor.world.pos.x + 147.0f,
this->dyna.actor.world.pos.y + -245.0f, this->dyna.actor.world.pos.z + -453.0f, 0, 0x4000, 0, 0x27EE);
this->actionFunc = BgMoriHineri_DoNothing;
}
}
void func_808A3C8C(BgMoriHineri* this, GlobalContext* globalCtx) {
@ -255,29 +263,6 @@ void BgMoriHineri_DrawHallAndRoom(Actor* thisx, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gDungeonDoorDL);
}
if ((this->boxObjIdx > 0) && ((this->boxObjIdx = Object_GetIndex(&globalCtx->objectCtx, OBJECT_BOX)) > 0) &&
Object_IsLoaded(&globalCtx->objectCtx, this->boxObjIdx)) {
gSPSegment(POLY_OPA_DISP++, 0x06, globalCtx->objectCtx.status[this->boxObjIdx].segment);
gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]);
Matrix_Put(&mtx);
Matrix_Translate(147.0f, -245.0f, -453.0f, MTXMODE_APPLY);
Matrix_RotateY(M_PI / 2, MTXMODE_APPLY);
Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gTreasureChestBossKeyChestFrontDL);
Matrix_Put(&mtx);
Matrix_Translate(167.0f, -218.0f, -453.0f, MTXMODE_APPLY);
if (Flags_GetTreasure(globalCtx, 0xE)) {
Matrix_RotateZ(0x3500 * (M_PI / 0x8000), MTXMODE_APPLY);
} else {
Matrix_RotateZ(M_PI, MTXMODE_APPLY);
}
Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gTreasureChestBossKeyChestSideAndTopDL);
}
CLOSE_DISPS(globalCtx->state.gfxCtx);
}

View file

@ -48,6 +48,8 @@ void EnBox_AppearInit(EnBox*, GlobalContext*);
void EnBox_AppearAnimation(EnBox*, GlobalContext*);
void EnBox_WaitOpen(EnBox*, GlobalContext*);
void EnBox_Open(EnBox*, GlobalContext*);
void EnBox_CreateExtraChestTextures();
void EnBox_UpdateSizeAndTexture(EnBox*, GlobalContext*);
const ActorInit En_Box_InitVars = {
ACTOR_EN_BOX,
@ -72,6 +74,14 @@ static InitChainEntry sInitChain[] = {
static UNK_TYPE sUnused;
GetItemEntry sItem;
Gfx gSkullTreasureChestChestSideAndLidDL[116] = {0};
Gfx gGoldTreasureChestChestSideAndLidDL[116] = {0};
Gfx gKeyTreasureChestChestSideAndLidDL[116] = {0};
Gfx gSkullTreasureChestChestFrontDL[128] = {0};
Gfx gGoldTreasureChestChestFrontDL[128] = {0};
Gfx gKeyTreasureChestChestFrontDL[128] = {0};
u8 hasCreatedRandoChestTextures = 0;
void EnBox_SetupAction(EnBox* this, EnBoxActionFunc actionFunc) {
this->actionFunc = actionFunc;
}
@ -174,17 +184,11 @@ void EnBox_Init(Actor* thisx, GlobalContext* globalCtx2) {
SkelAnime_Init(globalCtx, &this->skelanime, &gTreasureChestSkel, anim, this->jointTable, this->morphTable, 5);
Animation_Change(&this->skelanime, anim, 1.5f, animFrameStart, endFrame, ANIMMODE_ONCE, 0.0f);
switch (this->type) {
case ENBOX_TYPE_SMALL:
case ENBOX_TYPE_6:
case ENBOX_TYPE_ROOM_CLEAR_SMALL:
case ENBOX_TYPE_SWITCH_FLAG_FALL_SMALL:
Actor_SetScale(&this->dyna.actor, 0.005f);
Actor_SetFocus(&this->dyna.actor, 20.0f);
break;
default:
Actor_SetScale(&this->dyna.actor, 0.01f);
Actor_SetFocus(&this->dyna.actor, 40.0f);
EnBox_UpdateSizeAndTexture(this, globalCtx);
// For SOH we spawn a chest actor instead of rendering the object from scratch for forest boss
// key chest, and it's up on the wall so disable gravity for it.
if (globalCtx->sceneNum == SCENE_BMORI1 && this->dyna.actor.params == 10222) {
this->movementFlags = ENBOX_MOVE_IMMOBILE;
}
}
@ -575,6 +579,8 @@ void EnBox_SpawnIceSmoke(EnBox* this, GlobalContext* globalCtx) {
void EnBox_Update(Actor* thisx, GlobalContext* globalCtx) {
EnBox* this = (EnBox*)thisx;
EnBox_UpdateSizeAndTexture(this, globalCtx);
if (this->movementFlags & ENBOX_MOVE_STICK_TO_GROUND) {
this->movementFlags &= ~ENBOX_MOVE_STICK_TO_GROUND;
EnBox_ClipToGround(this, globalCtx);
@ -604,6 +610,154 @@ void EnBox_Update(Actor* thisx, GlobalContext* globalCtx) {
this->iceSmokeTimer < 100) EnBox_SpawnIceSmoke(this, globalCtx);
}
void EnBox_UpdateSizeAndTexture(EnBox* this, GlobalContext* globalCtx) {
EnBox_CreateExtraChestTextures();
int cvar = CVar_GetS32("gChestSizeAndTextureMatchesContents", 0);
GetItemCategory getItemCategory;
if (globalCtx->sceneNum != SCENE_TAKARAYA && cvar > 0) {
GetItemEntry getItemEntry = GET_ITEM_NONE;
if (gSaveContext.n64ddFlag) {
getItemEntry = Randomizer_GetItemFromActorWithoutObtainabilityCheck(this->dyna.actor.id, globalCtx->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F);
} else {
getItemEntry = ItemTable_RetrieveEntry(MOD_NONE, this->dyna.actor.params >> 5 & 0x7F);
}
getItemCategory = getItemEntry.getItemCategory;
// If they don't have bombchu's yet consider the bombchu item major
if (getItemEntry.gid == GID_BOMBCHU && INV_CONTENT(ITEM_BOMBCHU) != ITEM_BOMBCHU) {
getItemCategory = ITEM_CATEGORY_MAJOR;
}
}
if (globalCtx->sceneNum != SCENE_TAKARAYA && (cvar == 1 || cvar == 3)) {
switch (getItemCategory) {
case ITEM_CATEGORY_JUNK:
case ITEM_CATEGORY_SMALL_KEY:
case ITEM_CATEGORY_SKULLTULA_TOKEN:
Actor_SetScale(&this->dyna.actor, 0.005f);
Actor_SetFocus(&this->dyna.actor, 20.0f);
break;
default:
Actor_SetScale(&this->dyna.actor, 0.01f);
Actor_SetFocus(&this->dyna.actor, 40.0f);
break;
}
} else {
switch (this->type) {
case ENBOX_TYPE_SMALL:
case ENBOX_TYPE_6:
case ENBOX_TYPE_ROOM_CLEAR_SMALL:
case ENBOX_TYPE_SWITCH_FLAG_FALL_SMALL:
Actor_SetScale(&this->dyna.actor, 0.005f);
Actor_SetFocus(&this->dyna.actor, 20.0f);
break;
default:
Actor_SetScale(&this->dyna.actor, 0.01f);
Actor_SetFocus(&this->dyna.actor, 40.0f);
}
}
if (globalCtx->sceneNum != SCENE_TAKARAYA && (cvar == 1 || cvar == 2)) {
switch (getItemCategory) {
case ITEM_CATEGORY_MAJOR:
this->boxBodyDL = gGoldTreasureChestChestFrontDL;
this->boxLidDL = gGoldTreasureChestChestSideAndLidDL;
break;
case ITEM_CATEGORY_SKULLTULA_TOKEN:
this->boxBodyDL = gSkullTreasureChestChestFrontDL;
this->boxLidDL = gSkullTreasureChestChestSideAndLidDL;
break;
case ITEM_CATEGORY_SMALL_KEY:
this->boxBodyDL = gKeyTreasureChestChestFrontDL;
this->boxLidDL = gKeyTreasureChestChestSideAndLidDL;
break;
case ITEM_CATEGORY_BOSS_KEY:
this->boxBodyDL = gTreasureChestBossKeyChestFrontDL;
this->boxLidDL = gTreasureChestBossKeyChestSideAndTopDL;
break;
case ITEM_CATEGORY_LESSER:
case ITEM_CATEGORY_JUNK:
default:
this->boxBodyDL = gTreasureChestChestFrontDL;
this->boxLidDL = gTreasureChestChestSideAndLidDL;
break;
}
} else {
if (this->type != ENBOX_TYPE_DECORATED_BIG) {
this->boxBodyDL = gTreasureChestChestFrontDL;
this->boxLidDL = gTreasureChestChestSideAndLidDL;
} else {
this->boxBodyDL = gTreasureChestBossKeyChestFrontDL;
this->boxLidDL = gTreasureChestBossKeyChestSideAndTopDL;
}
}
}
void EnBox_CreateExtraChestTextures() {
if (hasCreatedRandoChestTextures) return;
Gfx gTreasureChestChestTextures[] = {
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, ResourceMgr_LoadFileRaw("assets/objects/object_box/gSkullTreasureChestFrontTex")),
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, ResourceMgr_LoadFileRaw("assets/objects/object_box/gSkullTreasureChestSideAndTopTex")),
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, ResourceMgr_LoadFileRaw("assets/objects/object_box/gGoldTreasureChestFrontTex")),
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, ResourceMgr_LoadFileRaw("assets/objects/object_box/gGoldTreasureChestSideAndTopTex")),
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, ResourceMgr_LoadFileRaw("assets/objects/object_box/gKeyTreasureChestFrontTex")),
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, ResourceMgr_LoadFileRaw("assets/objects/object_box/gKeyTreasureChestSideAndTopTex")),
};
Gfx* frontCmd = ResourceMgr_LoadGfxByName(gTreasureChestChestFrontDL);
int frontIndex = 0;
while (frontCmd->words.w0 >> 24 != G_ENDDL) {
gSkullTreasureChestChestFrontDL[frontIndex] = *frontCmd;
gGoldTreasureChestChestFrontDL[frontIndex] = *frontCmd;
gKeyTreasureChestChestFrontDL[frontIndex] = *frontCmd;
frontIndex++;
++frontCmd;
}
gSkullTreasureChestChestFrontDL[frontIndex] = *frontCmd;
gGoldTreasureChestChestFrontDL[frontIndex] = *frontCmd;
gKeyTreasureChestChestFrontDL[frontIndex] = *frontCmd;
gSkullTreasureChestChestFrontDL[5] = gTreasureChestChestTextures[0];
gSkullTreasureChestChestFrontDL[23] = gTreasureChestChestTextures[1];
gSkullTreasureChestChestFrontDL[37] = gTreasureChestChestTextures[0];
gSkullTreasureChestChestFrontDL[50] = gTreasureChestChestTextures[1];
gGoldTreasureChestChestFrontDL[5] = gTreasureChestChestTextures[2];
gGoldTreasureChestChestFrontDL[23] = gTreasureChestChestTextures[3];
gGoldTreasureChestChestFrontDL[37] = gTreasureChestChestTextures[2];
gGoldTreasureChestChestFrontDL[50] = gTreasureChestChestTextures[3];
gKeyTreasureChestChestFrontDL[5] = gTreasureChestChestTextures[4];
gKeyTreasureChestChestFrontDL[23] = gTreasureChestChestTextures[5];
gKeyTreasureChestChestFrontDL[37] = gTreasureChestChestTextures[4];
gKeyTreasureChestChestFrontDL[50] = gTreasureChestChestTextures[5];
Gfx* sideCmd = ResourceMgr_LoadGfxByName(gTreasureChestChestSideAndLidDL);
int sideIndex = 0;
while (sideCmd->words.w0 >> 24 != G_ENDDL) {
gSkullTreasureChestChestSideAndLidDL[sideIndex] = *sideCmd;
gGoldTreasureChestChestSideAndLidDL[sideIndex] = *sideCmd;
gKeyTreasureChestChestSideAndLidDL[sideIndex] = *sideCmd;
sideIndex++;
++sideCmd;
}
gSkullTreasureChestChestSideAndLidDL[sideIndex] = *sideCmd;
gGoldTreasureChestChestSideAndLidDL[sideIndex] = *sideCmd;
gKeyTreasureChestChestSideAndLidDL[sideIndex] = *sideCmd;
gSkullTreasureChestChestSideAndLidDL[5] = gTreasureChestChestTextures[0];
gSkullTreasureChestChestSideAndLidDL[29] = gTreasureChestChestTextures[1];
gSkullTreasureChestChestSideAndLidDL[45] = gTreasureChestChestTextures[0];
gGoldTreasureChestChestSideAndLidDL[5] = gTreasureChestChestTextures[2];
gGoldTreasureChestChestSideAndLidDL[29] = gTreasureChestChestTextures[3];
gGoldTreasureChestChestSideAndLidDL[45] = gTreasureChestChestTextures[2];
gKeyTreasureChestChestSideAndLidDL[5] = gTreasureChestChestTextures[4];
gKeyTreasureChestChestSideAndLidDL[29] = gTreasureChestChestTextures[5];
gKeyTreasureChestChestSideAndLidDL[45] = gTreasureChestChestTextures[4];
hasCreatedRandoChestTextures = 1;
}
void EnBox_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx, Gfx** gfx) {
EnBox* this = (EnBox*)thisx;
s32 pad;
@ -611,19 +765,11 @@ void EnBox_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Ve
if (limbIndex == 1) {
gSPMatrix((*gfx)++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (this->type != ENBOX_TYPE_DECORATED_BIG) {
gSPDisplayList((*gfx)++, gTreasureChestChestFrontDL);
} else {
gSPDisplayList((*gfx)++, gTreasureChestBossKeyChestFrontDL);
}
gSPDisplayList((*gfx)++, this->boxBodyDL);
} else if (limbIndex == 3) {
gSPMatrix((*gfx)++, MATRIX_NEWMTX(globalCtx->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (this->type != ENBOX_TYPE_DECORATED_BIG) {
gSPDisplayList((*gfx)++, gTreasureChestChestSideAndLidDL);
} else {
gSPDisplayList((*gfx)++, gTreasureChestBossKeyChestSideAndTopDL);
}
gSPDisplayList((*gfx)++, this->boxLidDL);
}
}

View file

@ -45,6 +45,8 @@ typedef struct EnBox {
/* 0x01F9 */ u8 type;
/* 0x01FA */ u8 iceSmokeTimer;
/* 0x01FB */ u8 unk_1FB;
/* */ Gfx* boxLidDL;
/* */ Gfx* boxBodyDL;
} EnBox; // size = 0x01FC
#endif