Merge pull request #3468 from briaguya-ai/delta-to-dev
MacReady Delta -> develop
This commit is contained in:
@@ -3384,7 +3384,7 @@ void Message_Update(PlayState* play) {
|
||||
}
|
||||
sLastPlayedSong = 0xFF;
|
||||
osSyncPrintf("OCARINA_MODE=%d chk_ocarina_no=%d\n", play->msgCtx.ocarinaMode, msgCtx->unk_E3F2);
|
||||
CheckTracker_OnMessageClose();
|
||||
// TODO: OnMessageClose hook
|
||||
break;
|
||||
case MSGMODE_PAUSED:
|
||||
break;
|
||||
|
||||
@@ -1526,13 +1526,13 @@ void Inventory_SwapAgeEquipment(void) {
|
||||
} else {
|
||||
// When becoming child, set swordless flag if player doesn't have kokiri sword
|
||||
// Only in rando to keep swordless link bugs in vanilla
|
||||
if (IS_RANDO && (EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment) == 0) {
|
||||
if (IS_RANDO && CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) {
|
||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||
}
|
||||
|
||||
// When using enhancements, set swordless flag if player doesn't have kokiri sword or hasn't equipped a sword yet.
|
||||
// Then set the child equips button items to item none to ensure kokiri sword is not equipped
|
||||
if ((CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) && ((EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment) == 0 || Flags_GetInfTable(INFTABLE_SWORDLESS))) {
|
||||
if ((CVarGetInteger("gSwitchAge", 0) || CVarGetInteger("gSwitchTimeline", 0)) && (CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0 || Flags_GetInfTable(INFTABLE_SWORDLESS))) {
|
||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||
gSaveContext.childEquips.buttonItems[0] = ITEM_NONE;
|
||||
}
|
||||
@@ -1568,7 +1568,7 @@ void Inventory_SwapAgeEquipment(void) {
|
||||
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
|
||||
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
||||
// Equips kokiri sword in the inventory screen only if kokiri sword exists in inventory and a sword has been equipped already
|
||||
if (!((EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment) == 0) && !Flags_GetInfTable(INFTABLE_SWORDLESS)) {
|
||||
if (!(CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) && !Flags_GetInfTable(INFTABLE_SWORDLESS)) {
|
||||
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
|
||||
}
|
||||
} else if (gSaveContext.childEquips.buttonItems[0] != ITEM_NONE) {
|
||||
@@ -1598,7 +1598,7 @@ void Inventory_SwapAgeEquipment(void) {
|
||||
(only kokiri tunic/boots equipped, no sword, no C-button items, no D-Pad items).
|
||||
When becoming child, set swordless flag if player doesn't have kokiri sword
|
||||
Only in rando to keep swordless link bugs in vanilla*/
|
||||
if (EQUIP_INV_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4) & gSaveContext.inventory.equipment == 0) {
|
||||
if (CHECK_OWNED_EQUIP(EQUIP_TYPE_SWORD, EQUIP_INV_SWORD_KOKIRI) == 0) {
|
||||
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -277,6 +277,11 @@ void func_8009638C(Gfx** displayList, void* source, void* tlut, u16 width, u16 h
|
||||
bg->b.imagePal = 0;
|
||||
bg->b.imageFlip = CVarGetInteger("gMirroredWorld", 0) ? G_BG_FLAG_FLIPS : 0;
|
||||
|
||||
// When an alt resource exists for the background, we need to unload the original asset
|
||||
// to clear the cache so the alt asset will be loaded instead
|
||||
// OTRTODO: If Alt loading over original cache is fixed, this line can most likely be removed
|
||||
ResourceMgr_UnloadOriginalWhenAltExists((char*) source);
|
||||
|
||||
if (ResourceMgr_ResourceIsBackground((char*) source)) {
|
||||
char* blob = (char*) ResourceGetDataByName((char *) source);
|
||||
swapAndConvertJPEG(blob);
|
||||
|
||||
@@ -417,7 +417,12 @@ void func_800AEFC8(SkyboxContext* skyboxCtx, s16 skyboxId) {
|
||||
s32 j;
|
||||
s32 phi_s3 = 0;
|
||||
|
||||
if (skyboxId == SKYBOX_BAZAAR || (skyboxId > SKYBOX_HOUSE_KAKARIKO && skyboxId <= SKYBOX_BOMBCHU_SHOP)) {
|
||||
//! @bug All shops only provide 2 faces for their sky box. Mask shop is missing from the condition
|
||||
// meaning that the Mask shop will calculate 4 faces
|
||||
// This effect is not noticed as the faces are behind the camera, but will cause a crash in SoH.
|
||||
// SOH General: We have added the Mask shop to this check so only the 2 expected faces are calculated.
|
||||
if (skyboxId == SKYBOX_BAZAAR || skyboxId == SKYBOX_HAPPY_MASK_SHOP ||
|
||||
(skyboxId >= SKYBOX_KOKIRI_SHOP && skyboxId <= SKYBOX_BOMBCHU_SHOP)) {
|
||||
for (j = 0, i = 0; i < 2; i++, j += 2) {
|
||||
phi_s3 = func_800ADBB0(skyboxCtx, skyboxCtx->roomVtx, phi_s3, D_8012AEBC[i].unk_0, D_8012AEBC[i].unk_4,
|
||||
D_8012AEBC[i].unk_8, D_8012AEBC[i].unk_C, D_8012AEBC[i].unk_10, i, j);
|
||||
|
||||
@@ -59,8 +59,14 @@ void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyb
|
||||
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[2]);
|
||||
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[3]);
|
||||
|
||||
if (skyboxId != SKYBOX_BAZAAR) {
|
||||
if (skyboxId <= SKYBOX_HOUSE_KAKARIKO || skyboxId > SKYBOX_BOMBCHU_SHOP) {
|
||||
//! @bug All shops only provide 2 faces for their sky box. Mask shop is missing from the condition
|
||||
// meaning that the Mask shop will render the previously loaded sky box values, or uninitialized data.
|
||||
// This effect is not noticed as the faces are behind the camera, but will cause a crash in SoH.
|
||||
// SOH General: We have added the Mask shop to this check so only the 2 expected faces are rendered.
|
||||
if (skyboxId != SKYBOX_BAZAAR && skyboxId != SKYBOX_HAPPY_MASK_SHOP) {
|
||||
if (skyboxId < SKYBOX_KOKIRI_SHOP || skyboxId > SKYBOX_BOMBCHU_SHOP) {
|
||||
// Skip remaining faces for most shop skyboxes
|
||||
|
||||
gDPPipeSync(POLY_OPA_DISP++);
|
||||
gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[2]);
|
||||
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]);
|
||||
|
||||
@@ -5,9 +5,21 @@
|
||||
#include "scenes/dungeons/ddan_boss/ddan_boss_room_1.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
|
||||
|
||||
#include <stdlib.h> // malloc
|
||||
#include <string.h> // memcpy
|
||||
|
||||
// OTRTODO: Replace usage of this method when we can clear the cache
|
||||
// for a single texture without the need of a DL opcode in the render code
|
||||
void gfx_texture_cache_clear();
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||
|
||||
#define LAVA_TEX_WIDTH 32
|
||||
#define LAVA_TEX_HEIGHT 64
|
||||
#define LAVA_TEX_SIZE 2048
|
||||
|
||||
void BossDodongo_Init(Actor* thisx, PlayState* play);
|
||||
void BossDodongo_Destroy(Actor* thisx, PlayState* play);
|
||||
void BossDodongo_Update(Actor* thisx, PlayState* play);
|
||||
@@ -59,6 +71,13 @@ static u8 sMaskTex8x8[8 * 8] = { { 0 } };
|
||||
static u8 sMaskTex8x32[8 * 32] = { { 0 } };
|
||||
static u8 sMaskTexLava[32 * 64] = { { 0 } };
|
||||
|
||||
static u32* sLavaFloorModifiedTexRaw = NULL;
|
||||
static u32* sLavaWavyTexRaw = NULL;
|
||||
static u16 sLavaFloorModifiedTex[LAVA_TEX_SIZE];
|
||||
static u16 sLavaWavyTex[LAVA_TEX_SIZE];
|
||||
|
||||
static u8 hasRegisteredBlendedHook = 0;
|
||||
|
||||
static InitChainEntry sInitChain[] = {
|
||||
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
|
||||
ICHAIN_S8(naviEnemyId, 0x0C, ICHAIN_CONTINUE),
|
||||
@@ -66,6 +85,69 @@ static InitChainEntry sInitChain[] = {
|
||||
ICHAIN_F32(targetArrowOffset, 8200.0f, ICHAIN_STOP),
|
||||
};
|
||||
|
||||
void BossDodongo_RegisterBlendedLavaTextureUpdate() {
|
||||
// Not in scene so there is nothing to do
|
||||
if (gPlayState == NULL || gPlayState->sceneNum != SCENE_DODONGOS_CAVERN_BOSS) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Free old textures
|
||||
if (sLavaFloorModifiedTexRaw != NULL) {
|
||||
free(sLavaFloorModifiedTexRaw);
|
||||
sLavaFloorModifiedTexRaw = NULL;
|
||||
}
|
||||
if (sLavaWavyTexRaw != NULL) {
|
||||
free(sLavaWavyTexRaw);
|
||||
sLavaWavyTexRaw = NULL;
|
||||
}
|
||||
|
||||
// Unload original textures to bypass cache result for lookups
|
||||
ResourceMgr_UnloadOriginalWhenAltExists(sLavaFloorLavaTex);
|
||||
ResourceMgr_UnloadOriginalWhenAltExists(sLavaFloorRockTex);
|
||||
ResourceMgr_UnloadOriginalWhenAltExists(gDodongosCavernBossLavaFloorTex);
|
||||
|
||||
// When the texture is HD (raw) we need to work with u32 values for RGBA32
|
||||
// Otherwise the original asset is u16 for RGBA16
|
||||
if (ResourceMgr_TexIsRaw(gDodongosCavernBossLavaFloorTex)) {
|
||||
u32* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex);
|
||||
size_t lavaSize = ResourceGetSizeByName(sLavaFloorLavaTex);
|
||||
size_t floorSize = ResourceGetSizeByName(gDodongosCavernBossLavaFloorTex);
|
||||
|
||||
sLavaFloorModifiedTexRaw = malloc(lavaSize);
|
||||
sLavaWavyTexRaw = malloc(floorSize);
|
||||
|
||||
memcpy(sLavaFloorModifiedTexRaw, lavaTex, lavaSize);
|
||||
|
||||
// When KD is dead, just immediately copy the rock texture
|
||||
if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) {
|
||||
u32* rockTex = ResourceGetDataByName(sLavaFloorRockTex);
|
||||
size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex);
|
||||
memcpy(sLavaFloorModifiedTexRaw, rockTex, rockSize);
|
||||
}
|
||||
|
||||
memcpy(sLavaWavyTexRaw, sLavaFloorModifiedTexRaw, floorSize);
|
||||
|
||||
// Register the blended effect for the raw texture
|
||||
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTexRaw);
|
||||
} else {
|
||||
// When KD is dead, just immediately copy the rock texture
|
||||
if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) {
|
||||
u16* rockTex = ResourceGetDataByName(sLavaFloorRockTex);
|
||||
memcpy(sLavaFloorModifiedTex, rockTex, sizeof(sLavaFloorModifiedTex));
|
||||
} else {
|
||||
u16* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex);
|
||||
memcpy(sLavaFloorModifiedTex, lavaTex, sizeof(sLavaFloorModifiedTex));
|
||||
}
|
||||
|
||||
// Register the blended effect for the non-raw texture
|
||||
memcpy(sLavaWavyTex, sLavaFloorModifiedTex, sizeof(sLavaWavyTex));
|
||||
|
||||
Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaWavyTex);
|
||||
}
|
||||
|
||||
gfx_texture_cache_clear();
|
||||
}
|
||||
|
||||
void func_808C12C4(u8* arg1, s16 arg2) {
|
||||
if (arg2[arg1] != 0) {
|
||||
sMaskTex8x16[arg2 / 2] = 1;
|
||||
@@ -86,12 +168,51 @@ void func_808C12C4(u8* arg1, s16 arg2) {
|
||||
}
|
||||
}
|
||||
|
||||
void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
||||
arg0 = GetResourceDataByNameHandlingMQ(arg0);
|
||||
floorTex = ResourceGetDataByName(floorTex);
|
||||
// Same as func_808C1554 but works with u32 values for RGBA32 raw textures
|
||||
void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
||||
u16 width = ResourceGetTexWidthByName(arg0);
|
||||
s32 size = ResourceGetTexHeightByName(arg0) * width;
|
||||
|
||||
u16* temp_s3 = SEGMENTED_TO_VIRTUAL(arg0);
|
||||
u16* temp_s1 = SEGMENTED_TO_VIRTUAL(floorTex);
|
||||
u32* temp_s3 = sLavaWavyTexRaw;
|
||||
u32* temp_s1 = sLavaFloorModifiedTexRaw;
|
||||
s32 i;
|
||||
s32 i2;
|
||||
u32* sp54 = malloc(size * sizeof(u32)); // Match the size for lava floor tex
|
||||
s32 temp;
|
||||
s32 temp2;
|
||||
|
||||
// Multiplier is used to try to scale the wavy effect to match the scale of the HD texture
|
||||
// Applying sqrt(multiplier) to arg3 is to control how many pixels move left/right for the selected row
|
||||
// Applying to arg2 and M_PI help to space out the wave effect
|
||||
// It's not perfect but close enough
|
||||
u16 multiplier = width / LAVA_TEX_WIDTH;
|
||||
|
||||
for (i = 0; i < size; i += width) {
|
||||
temp = sinf((((i / width) + (s32)(((arg2 * multiplier) * 50.0f) / 100.0f)) & (width - 1)) * (M_PI / (16 * multiplier))) * (arg3 * sqrt(multiplier));
|
||||
for (i2 = 0; i2 < width; i2++) {
|
||||
sp54[i + ((temp + i2) & (width - 1))] = temp_s1[i + i2];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < width; i++) {
|
||||
temp = sinf(((i + (s32)(((arg2 * multiplier) * 80.0f) / 100.0f)) & (width - 1)) * (M_PI / (16 * multiplier))) * (arg3 * sqrt(multiplier));
|
||||
temp *= width;
|
||||
for (i2 = 0; i2 < size; i2 += width) {
|
||||
temp2 = (temp + i2) & (size - 1);
|
||||
temp_s3[i + temp2] = sp54[i + i2];
|
||||
}
|
||||
}
|
||||
|
||||
free(sp54);
|
||||
|
||||
// Need to clear the cache after updating sLavaWavyTexRaw
|
||||
gfx_texture_cache_clear();
|
||||
}
|
||||
|
||||
// Modified to support CPU modified texture with the resource system
|
||||
// Used for the original non-raw asset working with u16 values
|
||||
void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
||||
u16* temp_s3 = sLavaWavyTex;
|
||||
u16* temp_s1 = sLavaFloorModifiedTex;
|
||||
s16 i;
|
||||
s16 i2;
|
||||
u16 sp54[2048];
|
||||
@@ -112,6 +233,9 @@ void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
||||
temp_s3[i + temp2] = sp54[i + i2];
|
||||
}
|
||||
}
|
||||
|
||||
// Need to clear the cache after updating sLavaWavyTex
|
||||
gfx_texture_cache_clear();
|
||||
}
|
||||
|
||||
void func_808C17C8(PlayState* play, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3, f32 arg4, s16 arg5) {
|
||||
@@ -187,27 +311,21 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
||||
Collider_SetJntSph(play, &this->collider, &this->actor, &sJntSphInit, this->items);
|
||||
|
||||
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) { // KD is dead
|
||||
u16* LavaFloorTex = ResourceGetDataByName(gDodongosCavernBossLavaFloorTex);
|
||||
u16* LavaFloorRockTex = ResourceGetDataByName(sLavaFloorRockTex);
|
||||
temp_s1_3 = SEGMENTED_TO_VIRTUAL(LavaFloorTex);
|
||||
temp_s2 = SEGMENTED_TO_VIRTUAL(LavaFloorRockTex);
|
||||
// SOH [General]
|
||||
// Applying the "cooled off" lava rock CPU modified texture for re-visiting the scene
|
||||
// is now handled by BossDodongo_RegisterBlendedLavaTextureUpdate below
|
||||
|
||||
Actor_Kill(&this->actor);
|
||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f,
|
||||
-3304.0f, 0, 0, 0, WARP_DUNGEON_CHILD);
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_BG_BREAKWALL, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, 0x6000, true);
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_ITEM_B_HEART, -690.0f, -1523.76f, -3304.0f, 0, 0, 0, 0, true);
|
||||
|
||||
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
|
||||
sMaskTexLava[i] = 1;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
|
||||
sMaskTexLava[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this->actor.flags &= ~ACTOR_FLAG_TARGETABLE;
|
||||
|
||||
// #region SOH [General]
|
||||
// Init mask values for all blended textures
|
||||
for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) {
|
||||
sMaskTex8x16[i] = 0;
|
||||
}
|
||||
@@ -223,6 +341,12 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
||||
for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) {
|
||||
sMaskTex32x16[i] = 0;
|
||||
}
|
||||
// Set all true for the lava as it will always replace the scene texture
|
||||
for (int i = 0; i < ARRAY_COUNT(sMaskTexLava); i++) {
|
||||
sMaskTexLava[i] = 1;
|
||||
}
|
||||
|
||||
// Register all blended textures
|
||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015890, sMaskTex8x16, NULL);
|
||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_017210, sMaskTex8x32, NULL);
|
||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015D90, sMaskTex16x16, NULL);
|
||||
@@ -234,10 +358,14 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL);
|
||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL);
|
||||
|
||||
// OTRTODO: This is causing OOB memory reads with HD assets
|
||||
// commenting this out means the lava will stay lava even after beating king d
|
||||
//
|
||||
// Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaFloorRockTex);
|
||||
BossDodongo_RegisterBlendedLavaTextureUpdate();
|
||||
|
||||
// Register alt listener to update the blended lava for the replacement texture based on alt path
|
||||
if (!hasRegisteredBlendedHook) {
|
||||
GameInteractor_RegisterOnAssetAltChange(BossDodongo_RegisterBlendedLavaTextureUpdate);
|
||||
hasRegisteredBlendedHook = 1;
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
|
||||
void BossDodongo_Destroy(Actor* thisx, PlayState* play) {
|
||||
@@ -1014,21 +1142,64 @@ void BossDodongo_Update(Actor* thisx, PlayState* play2) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO The lave floor bubbles with an effect that modifies the texture. This needs to be recreated shader-side.
|
||||
//func_808C1554(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224);
|
||||
// The lava bubbles with a wavy effect as a CPU modified texture
|
||||
// This has been done by maintaining copied/modified texture values in the actor code
|
||||
// The "cooling off" effect for the lava is pre-applied to the lava texture before applying
|
||||
// the wavy effect. Since this is two effects and closely related to the actor, I've opted
|
||||
// to handle them here rather than as a shader effect.
|
||||
//
|
||||
// Apply the corresponding wavy effect based on the texture being raw or not
|
||||
if (ResourceMgr_TexIsRaw(gDodongosCavernBossLavaFloorTex)) {
|
||||
func_808C1554_Raw(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224);
|
||||
} else {
|
||||
func_808C1554(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the "cooling off" effect for the lava
|
||||
if (this->unk_1C6 != 0) {
|
||||
u16* ptr1 = ResourceGetDataByName(sLavaFloorLavaTex);
|
||||
u16* ptr2 = ResourceGetDataByName(sLavaFloorRockTex);
|
||||
s16 i2;
|
||||
// Similar to above, the cooling off effect is a CPU modified texture effect
|
||||
// Apply corresponding to the texture being raw or not
|
||||
if (ResourceMgr_TexIsRaw(sLavaFloorRockTex)) {
|
||||
u32* ptr1 = sLavaFloorModifiedTexRaw;
|
||||
u32* ptr2 = ResourceGetDataByName(sLavaFloorRockTex);
|
||||
u16 width = ResourceGetTexWidthByName(sLavaFloorRockTex);
|
||||
u16 height = ResourceGetTexHeightByName(sLavaFloorRockTex);
|
||||
s16 i2;
|
||||
|
||||
for (i2 = 0; i2 < 20; i2++) {
|
||||
s16 new_var = this->unk_1C2 & 0x7FF;
|
||||
// Get the scale based on the original texture size
|
||||
u16 widthScale = width / LAVA_TEX_WIDTH;
|
||||
u16 heightScale = height / LAVA_TEX_HEIGHT;
|
||||
u32 size = width * height;
|
||||
|
||||
sMaskTexLava[new_var] = 1;
|
||||
this->unk_1C2 += 37;
|
||||
for (i2 = 0; i2 < 20; i2++) {
|
||||
s16 new_var = this->unk_1C2 & (LAVA_TEX_SIZE - 1);
|
||||
// Compute the index to a scaled position (scaling pseudo x,y as a 1D value)
|
||||
s32 indexStart = ((new_var % LAVA_TEX_WIDTH) * widthScale) + ((new_var / LAVA_TEX_WIDTH) * width * heightScale);
|
||||
|
||||
// From the starting index, apply extra pixels right/down based on the scale
|
||||
for (size_t j = 0; j < heightScale; j++) {
|
||||
for (size_t i3 = 0; i3 < widthScale; i3++) {
|
||||
s32 scaledIndex = (indexStart + i3 + (j * width)) & (size - 1);
|
||||
ptr1[scaledIndex] = ptr2[scaledIndex];
|
||||
}
|
||||
}
|
||||
|
||||
this->unk_1C2 += 37;
|
||||
}
|
||||
} else {
|
||||
u16* ptr1 = sLavaFloorModifiedTex;
|
||||
u16* ptr2 = ResourceGetDataByName(sLavaFloorRockTex);
|
||||
s16 i2;
|
||||
|
||||
for (i2 = 0; i2 < 20; i2++) {
|
||||
s16 new_var = this->unk_1C2 & 0x7FF;
|
||||
|
||||
ptr1[new_var] = ptr2[new_var];
|
||||
this->unk_1C2 += 37;
|
||||
}
|
||||
}
|
||||
|
||||
Math_SmoothStepToF(&this->unk_224, 0.0f, 1.0f, 0.01f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,26 @@ static AnimationInfo sAnimationInfo[] = {
|
||||
{ &gDaruniaDancingEndAnim, 1.0f, 0.0f, -1.0f, ANIMMODE_ONCE, -6.0f },
|
||||
};
|
||||
|
||||
// #region SOH [Enhancement] Only animations too fast need to be slowed down, otherwise not touched
|
||||
static AnimationInfo sAnimationInfoFix[] = {
|
||||
{ NULL },
|
||||
{ NULL },
|
||||
{ NULL },
|
||||
{ NULL },
|
||||
{ NULL },
|
||||
{ NULL },
|
||||
{ NULL },
|
||||
{ &gDaruniaDancingLoop1Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, -10.0f }, //
|
||||
{ &gDaruniaDancingLoop1Anim, 0.77f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // hop
|
||||
{ &gDaruniaDancingLoop2Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // from hop to spin
|
||||
{ &gDaruniaDancingLoop3Anim, 0.77f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // spin
|
||||
{ NULL },
|
||||
{ NULL },
|
||||
{ &gDaruniaDancingLoop4Anim, 0.78f, 0.0f, -1.0f, ANIMMODE_ONCE, 0.0f }, // from spin to hop
|
||||
{ NULL },
|
||||
};
|
||||
// #endregion
|
||||
|
||||
void EnDu_SetupAction(EnDu* this, EnDuActionFunc actionFunc) {
|
||||
this->actionFunc = actionFunc;
|
||||
}
|
||||
@@ -255,7 +275,13 @@ void func_809FE040(EnDu* this) {
|
||||
if (this->unk_1E6 >= 8) {
|
||||
this->unk_1E6 = 0;
|
||||
}
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]);
|
||||
// #region SOH[Enhancement]
|
||||
if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1)) {
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, animationIndices[this->unk_1E6]);
|
||||
// #endregion
|
||||
} else {
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +297,13 @@ void func_809FE104(EnDu* this) {
|
||||
if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) {
|
||||
this->unk_1E6++;
|
||||
if (this->unk_1E6 < 4) {
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]);
|
||||
// #region SOH[Enhancement]
|
||||
if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1) && this->unk_1E6 <= 1) {
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, animationIndices[this->unk_1E6]);
|
||||
// #endregion
|
||||
} else {
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, animationIndices[this->unk_1E6]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,7 +497,13 @@ void func_809FE890(EnDu* this, PlayState* play) {
|
||||
}
|
||||
if (csAction->action == 7 || csAction->action == 8) {
|
||||
this->unk_1E6 = 0;
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENDU_ANIM_7);
|
||||
// #region SOH[Enhancement]
|
||||
if (CVarGetInteger("gEnhancements.FixDaruniaDanceSpeed", 1)) {
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfoFix, ENDU_ANIM_7);
|
||||
// #endregion
|
||||
} else {
|
||||
Animation_ChangeByInfo(&this->skelAnime, sAnimationInfo, ENDU_ANIM_7);
|
||||
}
|
||||
}
|
||||
this->unk_1EA = csAction->action;
|
||||
if (this->unk_1EA == 7) {
|
||||
|
||||
@@ -211,6 +211,13 @@ void EnInsect_Init(Actor* thisx, PlayState* play2) {
|
||||
|
||||
func_80A7D39C(this);
|
||||
|
||||
// For bugs that aren't linked to a soil patch, we remove the "short lived" flag to prevent them from despawning
|
||||
// And exit early to not increment the "bugs dropped count"
|
||||
if (CVarGetInteger("gNoBugsDespawn", 0) && this->soilActor == NULL) {
|
||||
this->unk_314 &= ~4;
|
||||
return;
|
||||
}
|
||||
|
||||
D_80A7DEB8++;
|
||||
} else {
|
||||
rand = Rand_ZeroOne();
|
||||
@@ -394,9 +401,6 @@ void func_80A7CAD0(EnInsect* this, PlayState* play) {
|
||||
}
|
||||
|
||||
void func_80A7CBC8(EnInsect* this) {
|
||||
if (CVarGetInteger("gNoBugsDespawn", 0) != 0) {
|
||||
return;
|
||||
}
|
||||
this->unk_31A = 60;
|
||||
func_80A7BF58(this);
|
||||
this->skelAnime.playSpeed = 1.9f;
|
||||
|
||||
@@ -313,7 +313,9 @@ void EnSth_GiveReward(EnSth* this, PlayState* play) {
|
||||
this->actor.parent = NULL;
|
||||
EnSth_SetupAction(this, EnSth_RewardObtainedTalk);
|
||||
gSaveContext.eventChkInf[EVENTCHKINF_SKULLTULA_REWARD_INDEX] |= this->eventFlag;
|
||||
GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, (EVENTCHKINF_SKULLTULA_REWARD_INDEX << 4) + sEventFlagsShift[this->actor.params]);
|
||||
if (this->eventFlag != 0) {
|
||||
GameInteractor_ExecuteOnFlagSet(FLAG_EVENT_CHECK_INF, (EVENTCHKINF_SKULLTULA_REWARD_INDEX << 4) + sEventFlagsShift[this->actor.params]);
|
||||
}
|
||||
} else {
|
||||
EnSth_GivePlayerItem(this, play);
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ s32 EnTk_ChooseReward(EnTk* this) {
|
||||
f32 luck;
|
||||
s32 reward;
|
||||
|
||||
if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, 0x1F) && this->heartPieceSpawned == 0) {
|
||||
if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE) && this->heartPieceSpawned == 0) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@@ -624,10 +624,8 @@ void EnTk_Dig(EnTk* this, PlayState* play) {
|
||||
|
||||
this->currentReward = EnTk_ChooseReward(this);
|
||||
|
||||
// merging in dampe tour fix seems messy, so i'm just wrapping this whole thing
|
||||
// in an n64dd check for now
|
||||
if (IS_RANDO || CVarGetInteger("gDampeWin", 0)) {
|
||||
if (this->currentReward == 3) {
|
||||
if (this->currentReward == 3) {
|
||||
if (IS_RANDO || CVarGetInteger("gDampeWin", 0)) {
|
||||
/*
|
||||
* Upgrade the purple rupee reward to the heart piece if this
|
||||
* is the first grand prize dig.
|
||||
@@ -635,37 +633,31 @@ void EnTk_Dig(EnTk* this, PlayState* play) {
|
||||
if (!Flags_GetItemGetInf(ITEMGETINF_1C) && !(IS_RANDO || CVarGetInteger("gDampeWin", 0))) {
|
||||
Flags_SetItemGetInf(ITEMGETINF_1C);
|
||||
this->currentReward = 4;
|
||||
} else if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, 0x1F) && this->heartPieceSpawned == 0) {
|
||||
} else if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && !Flags_GetCollectible(gPlayState, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE) && this->heartPieceSpawned == 0) {
|
||||
this->currentReward = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ((IS_RANDO || CVarGetInteger("gDampeWin", 0)) && this->currentReward == 4) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, rewardPos.x, rewardPos.y, rewardPos.z, 0,
|
||||
0, 0, 0x1F06, true);
|
||||
this->heartPieceSpawned = 1;
|
||||
} else {
|
||||
Item_DropCollectible(play, &rewardPos, rewardParams[this->currentReward]);
|
||||
/*
|
||||
* Upgrade the purple rupee reward to the heart piece if this
|
||||
* is the first grand prize dig.
|
||||
*/
|
||||
// If vanilla itemGetInf flag is not set, it's impossible for the new flag to be set, so return true.
|
||||
// Otherwise if the gGravediggingTourFix is enabled and the new flag hasn't been set, return true.
|
||||
// If true, spawn the heart piece and set the vanilla itemGetInf flag and new temp clear flag.
|
||||
if (!heartPieceSpawned &&
|
||||
(!(gSaveContext.itemGetInf[1] & ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE) ||
|
||||
CVarGetInteger("gGravediggingTourFix", 0) &&
|
||||
!Flags_GetCollectible(play, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE))) {
|
||||
this->currentReward = 4;
|
||||
gSaveContext.itemGetInf[1] |= ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE;
|
||||
heartPieceSpawned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_RANDO && this->currentReward == 4) {
|
||||
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ITEM00, rewardPos.x, rewardPos.y, rewardPos.z, 0, 0, 0, 0x1906, true);
|
||||
this->heartPieceSpawned = 1;
|
||||
} else {
|
||||
if (this->currentReward == 3) {
|
||||
/*
|
||||
* Upgrade the purple rupee reward to the heart piece if this
|
||||
* is the first grand prize dig.
|
||||
*/
|
||||
// If vanilla itemGetInf flag is not set, it's impossible for the new flag to be set, so return true.
|
||||
// Otherwise if the gGravediggingTourFix is enabled and the new flag hasn't been set, return true.
|
||||
// If true, spawn the heart piece and set the vanilla itemGetInf flag and new temp clear flag.
|
||||
if (!heartPieceSpawned &&
|
||||
(!(gSaveContext.itemGetInf[1] & ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE) ||
|
||||
CVarGetInteger("gGravediggingTourFix", 0) &&
|
||||
!Flags_GetCollectible(play, COLLECTFLAG_GRAVEDIGGING_HEART_PIECE))) {
|
||||
this->currentReward = 4;
|
||||
gSaveContext.itemGetInf[1] |= ITEMGETINFFLAG_GRAVEDIGGING_HEART_PIECE;
|
||||
heartPieceSpawned = true;
|
||||
}
|
||||
}
|
||||
|
||||
EnItem00* reward = Item_DropCollectible(play, &rewardPos, rewardParams[this->currentReward]);
|
||||
if (this->currentReward == 4) {
|
||||
reward->collectibleFlag = COLLECTFLAG_GRAVEDIGGING_HEART_PIECE;
|
||||
|
||||
@@ -10474,7 +10474,8 @@ void Player_ProcessSceneCollision(PlayState* play, Player* this) {
|
||||
|
||||
sTouchedWallFlags = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId);
|
||||
|
||||
if (CVarGetInteger("gFixVineFall", 0)) {
|
||||
// conflicts arise from these two being enabled at once, and with ClimbEverything on, FixVineFall is redundant anyway
|
||||
if (CVarGetInteger("gFixVineFall", 0) && !CVarGetInteger("gClimbEverything", 0)) {
|
||||
/* This fixes the "started climbing a wall and then immediately fell off" bug.
|
||||
* The main idea is if a climbing wall is detected, double-check that it will
|
||||
* still be valid once climbing begins by doing a second raycast with a small
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "file_choose.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "textures/title_static/title_static.h"
|
||||
#include "textures/parameter_static/parameter_static.h"
|
||||
@@ -1024,7 +1025,7 @@ void FileChoose_UpdateRandomizer() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SpoilerFileExists(CVarGetString("gSpoilerLog", ""))) {
|
||||
if (!SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && !CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) {
|
||||
CVarSetString("gSpoilerLog", "");
|
||||
fileSelectSpoilerFileLoaded = false;
|
||||
}
|
||||
@@ -1051,6 +1052,10 @@ void FileChoose_UpdateRandomizer() {
|
||||
Randomizer_LoadMasterQuestDungeons(fileLoc);
|
||||
Randomizer_LoadEntranceOverrides(fileLoc, silent);
|
||||
fileSelectSpoilerFileLoaded = true;
|
||||
|
||||
if (SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) {
|
||||
remove(fileLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1071,6 +1076,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) {
|
||||
Input* input = &this->state.input[0];
|
||||
bool dpad = CVarGetInteger("gDpadText", 0);
|
||||
|
||||
SoH_ProcessDroppedFiles();
|
||||
FileChoose_UpdateRandomizer();
|
||||
|
||||
if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) {
|
||||
@@ -1261,6 +1267,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
|
||||
s8 i = 0;
|
||||
bool dpad = CVarGetInteger("gDpadText", 0);
|
||||
|
||||
SoH_ProcessDroppedFiles();
|
||||
FileChoose_UpdateRandomizer();
|
||||
|
||||
if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) {
|
||||
@@ -3686,4 +3693,7 @@ void FileChoose_Init(GameState* thisx) {
|
||||
Font_LoadOrderedFont(&this->font);
|
||||
Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA);
|
||||
func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_FILE_SELECT, 0, 7, 1);
|
||||
|
||||
// Originally this was only set when transitioning from the title screen, but gSkipLogoTitle skips that process so we're ensuring it's set here
|
||||
gSaveContext.gameMode = GAMEMODE_FILE_SELECT;
|
||||
}
|
||||
|
||||
@@ -1054,8 +1054,9 @@ void KaleidoScope_UpdateItemEquip(PlayState* play) {
|
||||
|
||||
//Fix for Equip Dupe
|
||||
if (pauseCtx->equipTargetItem == ITEM_BOW) {
|
||||
if ((gSaveContext.equips.buttonItems[otherButtonIndex] >= ITEM_BOW_ARROW_FIRE) &&
|
||||
(gSaveContext.equips.buttonItems[otherButtonIndex] <= ITEM_BOW_ARROW_LIGHT)) {
|
||||
if (gSaveContext.equips.buttonItems[otherButtonIndex] >= ITEM_BOW_ARROW_FIRE &&
|
||||
gSaveContext.equips.buttonItems[otherButtonIndex] <= ITEM_BOW_ARROW_LIGHT &&
|
||||
!CVarGetInteger("gSeparateArrows", 0)) {
|
||||
gSaveContext.equips.buttonItems[otherButtonIndex] = gSaveContext.equips.buttonItems[targetButtonIndex];
|
||||
gSaveContext.equips.cButtonSlots[otherSlotIndex] = gSaveContext.equips.cButtonSlots[pauseCtx->equipTargetCBtn];
|
||||
Interface_LoadItemIcon2(play, otherButtonIndex);
|
||||
|
||||
Reference in New Issue
Block a user