mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-26 08:05:21 -07:00
Merge branch 'develop-macready' into christmas-tree
This commit is contained in:
commit
48643c6aea
16 changed files with 288 additions and 46 deletions
|
@ -5,8 +5,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
|
||||||
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
||||||
|
|
||||||
project(Ship VERSION 8.0.1 LANGUAGES C CXX)
|
project(Ship VERSION 8.0.2 LANGUAGES C CXX)
|
||||||
set(PROJECT_BUILD_NAME "MacReady Bravo" CACHE STRING "")
|
set(PROJECT_BUILD_NAME "MacReady Charlie" CACHE STRING "")
|
||||||
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
|
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
|
||||||
|
|
||||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9509806ae3ca6e35882fb976de70c5bde471b8f5
|
Subproject commit f717dd265aff2eff359de26915d8ad4e498ffdaf
|
|
@ -380,13 +380,13 @@ CrowdControl::Effect* CrowdControl::ParseMessage(char payload[512]) {
|
||||||
effect->category = kEffectCatBoots;
|
effect->category = kEffectCatBoots;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
||||||
effect->giEffect->parameters[0] = PLAYER_BOOTS_IRON;
|
effect->giEffect->parameters[0] = EQUIP_VALUE_BOOTS_IRON;
|
||||||
break;
|
break;
|
||||||
case kEffectForceHoverBoots:
|
case kEffectForceHoverBoots:
|
||||||
effect->category = kEffectCatBoots;
|
effect->category = kEffectCatBoots;
|
||||||
effect->timeRemaining = 30000;
|
effect->timeRemaining = 30000;
|
||||||
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
effect->giEffect = new GameInteractionEffect::ForceEquipBoots();
|
||||||
effect->giEffect->parameters[0] = PLAYER_BOOTS_HOVER;
|
effect->giEffect->parameters[0] = EQUIP_VALUE_BOOTS_HOVER;
|
||||||
break;
|
break;
|
||||||
case kEffectSlipperyFloor:
|
case kEffectSlipperyFloor:
|
||||||
effect->category = kEffectCatSlipperyFloor;
|
effect->category = kEffectCatSlipperyFloor;
|
||||||
|
|
|
@ -194,6 +194,8 @@ public:
|
||||||
|
|
||||||
DEFINE_HOOK(OnSetGameLanguage, void());
|
DEFINE_HOOK(OnSetGameLanguage, void());
|
||||||
|
|
||||||
|
DEFINE_HOOK(OnAssetAltChange, void());
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
static bool IsSaveLoaded();
|
static bool IsSaveLoaded();
|
||||||
static bool IsGameplayPaused();
|
static bool IsGameplayPaused();
|
||||||
|
|
|
@ -181,3 +181,9 @@ void GameInteractor_ExecuteOnUpdateFileNameSelection(int16_t charCode) {
|
||||||
void GameInteractor_ExecuteOnSetGameLanguage() {
|
void GameInteractor_ExecuteOnSetGameLanguage() {
|
||||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetGameLanguage>();
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetGameLanguage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - System
|
||||||
|
|
||||||
|
void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)) {
|
||||||
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnAssetAltChange>(fn);
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,10 @@ void GameInteractor_ExecuteOnUpdateFileNameSelection(int16_t charCode);
|
||||||
|
|
||||||
// MARK: - Game
|
// MARK: - Game
|
||||||
void GameInteractor_ExecuteOnSetGameLanguage();
|
void GameInteractor_ExecuteOnSetGameLanguage();
|
||||||
|
|
||||||
|
// MARK: - System
|
||||||
|
void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void));
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -255,7 +255,7 @@ OTRGlobals::OTRGlobals() {
|
||||||
std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName);
|
std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName);
|
||||||
if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) {
|
if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) {
|
||||||
if (std::filesystem::is_directory(patchesPath)) {
|
if (std::filesystem::is_directory(patchesPath)) {
|
||||||
for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath)) {
|
for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath, std::filesystem::directory_options::follow_directory_symlink)) {
|
||||||
if (StringHelper::IEquals(p.path().extension().string(), ".otr")) {
|
if (StringHelper::IEquals(p.path().extension().string(), ".otr")) {
|
||||||
OTRFiles.push_back(p.path().generic_string());
|
OTRFiles.push_back(p.path().generic_string());
|
||||||
}
|
}
|
||||||
|
@ -1217,6 +1217,7 @@ extern "C" void Graph_StartFrame() {
|
||||||
case KbScancode::LUS_KB_TAB: {
|
case KbScancode::LUS_KB_TAB: {
|
||||||
// Toggle HD Assets
|
// Toggle HD Assets
|
||||||
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
|
CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
|
||||||
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
|
||||||
ShouldClearTextureCacheAtEndOfFrame = true;
|
ShouldClearTextureCacheAtEndOfFrame = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1416,6 +1417,14 @@ extern "C" void ResourceMgr_DirtyDirectory(const char* resName) {
|
||||||
LUS::Context::GetInstance()->GetResourceManager()->DirtyDirectory(resName);
|
LUS::Context::GetInstance()->GetResourceManager()->DirtyDirectory(resName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void ResourceMgr_UnloadResource(const char* resName) {
|
||||||
|
std::string path = resName;
|
||||||
|
if (path.substr(0, 7) == "__OTR__") {
|
||||||
|
path = path.substr(7);
|
||||||
|
}
|
||||||
|
auto res = LUS::Context::GetInstance()->GetResourceManager()->UnloadResource(path);
|
||||||
|
}
|
||||||
|
|
||||||
// OTRTODO: There is probably a more elegant way to go about this...
|
// OTRTODO: There is probably a more elegant way to go about this...
|
||||||
// Kenix: This is definitely leaking memory when it's called.
|
// Kenix: This is definitely leaking memory when it's called.
|
||||||
extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) {
|
extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) {
|
||||||
|
@ -1442,6 +1451,27 @@ extern "C" uint8_t ResourceMgr_FileExists(const char* filePath) {
|
||||||
return ExtensionCache.contains(path);
|
return ExtensionCache.contains(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" uint8_t ResourceMgr_FileAltExists(const char* filePath) {
|
||||||
|
std::string path = filePath;
|
||||||
|
if (path.substr(0, 7) == "__OTR__") {
|
||||||
|
path = path.substr(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.substr(0, 4) != "alt/") {
|
||||||
|
path = "alt/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExtensionCache.contains(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unloads a resource if an alternate version exists when alt assets are enabled
|
||||||
|
// The resource is only removed from the internal cache to prevent it from used in the next resource lookup
|
||||||
|
extern "C" void ResourceMgr_UnloadOriginalWhenAltExists(const char* resName) {
|
||||||
|
if (CVarGetInteger("gAltAssets", 0) && ResourceMgr_FileAltExists((char*) resName)) {
|
||||||
|
ResourceMgr_UnloadResource((char*) resName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void ResourceMgr_LoadFile(const char* resName) {
|
extern "C" void ResourceMgr_LoadFile(const char* resName) {
|
||||||
LUS::Context::GetInstance()->GetResourceManager()->LoadResource(resName);
|
LUS::Context::GetInstance()->GetResourceManager()->LoadResource(resName);
|
||||||
}
|
}
|
||||||
|
@ -1481,6 +1511,11 @@ extern "C" char* ResourceMgr_LoadFileFromDisk(const char* filePath) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" uint8_t ResourceMgr_TexIsRaw(const char* texPath) {
|
||||||
|
auto res = std::static_pointer_cast<LUS::Texture>(GetResourceByNameHandlingMQ(texPath));
|
||||||
|
return res->Flags & TEX_FLAG_LOAD_AS_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) {
|
extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) {
|
||||||
auto res = GetResourceByNameHandlingMQ(texPath);
|
auto res = GetResourceByNameHandlingMQ(texPath);
|
||||||
return res->GetInitData()->Type == LUS::ResourceType::SOH_Background;
|
return res->GetInitData()->Type == LUS::ResourceType::SOH_Background;
|
||||||
|
@ -1566,6 +1601,11 @@ extern "C" void ResourceMgr_PushCurrentDirectory(char* path)
|
||||||
|
|
||||||
extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path)
|
extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path)
|
||||||
{
|
{
|
||||||
|
// When an alt resource exists for the DL, 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(path);
|
||||||
|
|
||||||
auto res = std::static_pointer_cast<LUS::DisplayList>(GetResourceByNameHandlingMQ(path));
|
auto res = std::static_pointer_cast<LUS::DisplayList>(GetResourceByNameHandlingMQ(path));
|
||||||
return (Gfx*)&res->Instructions[0];
|
return (Gfx*)&res->Instructions[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,11 +86,15 @@ uint32_t ResourceMgr_GetGameVersion(int index);
|
||||||
uint32_t ResourceMgr_GetGamePlatform(int index);
|
uint32_t ResourceMgr_GetGamePlatform(int index);
|
||||||
uint32_t ResourceMgr_GetGameRegion(int index);
|
uint32_t ResourceMgr_GetGameRegion(int index);
|
||||||
void ResourceMgr_LoadDirectory(const char* resName);
|
void ResourceMgr_LoadDirectory(const char* resName);
|
||||||
|
void ResourceMgr_UnloadResource(const char* resName);
|
||||||
char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize);
|
char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize);
|
||||||
uint8_t ResourceMgr_FileExists(const char* resName);
|
uint8_t ResourceMgr_FileExists(const char* resName);
|
||||||
|
uint8_t ResourceMgr_FileAltExists(const char* resName);
|
||||||
|
void ResourceMgr_UnloadOriginalWhenAltExists(const char* resName);
|
||||||
char* GetResourceDataByNameHandlingMQ(const char* path);
|
char* GetResourceDataByNameHandlingMQ(const char* path);
|
||||||
void ResourceMgr_LoadFile(const char* resName);
|
void ResourceMgr_LoadFile(const char* resName);
|
||||||
char* ResourceMgr_LoadFileFromDisk(const char* filePath);
|
char* ResourceMgr_LoadFileFromDisk(const char* filePath);
|
||||||
|
uint8_t ResourceMgr_TexIsRaw(const char* texPath);
|
||||||
uint8_t ResourceMgr_ResourceIsBackground(char* texPath);
|
uint8_t ResourceMgr_ResourceIsBackground(char* texPath);
|
||||||
char* ResourceMgr_LoadJPEG(char* data, size_t dataSize);
|
char* ResourceMgr_LoadJPEG(char* data, size_t dataSize);
|
||||||
uint16_t ResourceMgr_LoadTexWidthByName(char* texPath);
|
uint16_t ResourceMgr_LoadTexWidthByName(char* texPath);
|
||||||
|
|
|
@ -907,6 +907,7 @@ void DrawEnhancementsMenu() {
|
||||||
if (ImGui::BeginMenu("Mods")) {
|
if (ImGui::BeginMenu("Mods")) {
|
||||||
if (UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false)) {
|
if (UIWidgets::PaddedEnhancementCheckbox("Use Alternate Assets", "gAltAssets", false, false)) {
|
||||||
ShouldClearTextureCacheAtEndOfFrame = true;
|
ShouldClearTextureCacheAtEndOfFrame = true;
|
||||||
|
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnAssetAltChange>();
|
||||||
}
|
}
|
||||||
UIWidgets::Tooltip("Toggle between standard assets and alternate assets. Usually mods will indicate if this setting has to be used or not.");
|
UIWidgets::Tooltip("Toggle between standard assets and alternate assets. Usually mods will indicate if this setting has to be used or not.");
|
||||||
UIWidgets::PaddedEnhancementCheckbox("Disable Bomb Billboarding", "gDisableBombBillboarding", true, false);
|
UIWidgets::PaddedEnhancementCheckbox("Disable Bomb Billboarding", "gDisableBombBillboarding", true, false);
|
||||||
|
@ -1628,4 +1629,4 @@ void SohMenuBar::DrawElement() {
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace SohGui
|
} // namespace SohGui
|
||||||
|
|
|
@ -260,7 +260,7 @@ void Audio_osWritebackDCache(void* mem, s32 size)
|
||||||
|
|
||||||
s32 osAiSetFrequency(u32 freq)
|
s32 osAiSetFrequency(u32 freq)
|
||||||
{
|
{
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 osEPiStartDma(OSPiHandle* handle, OSIoMesg* mb, s32 direction)
|
s32 osEPiStartDma(OSPiHandle* handle, OSIoMesg* mb, s32 direction)
|
||||||
|
|
|
@ -1526,13 +1526,13 @@ void Inventory_SwapAgeEquipment(void) {
|
||||||
} else {
|
} else {
|
||||||
// When becoming child, set swordless flag if player doesn't have kokiri sword
|
// When becoming child, set swordless flag if player doesn't have kokiri sword
|
||||||
// Only in rando to keep swordless link bugs in vanilla
|
// 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);
|
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When using enhancements, set swordless flag if player doesn't have kokiri sword or hasn't equipped a sword yet.
|
// 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
|
// 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);
|
Flags_SetInfTable(INFTABLE_SWORDLESS);
|
||||||
gSaveContext.childEquips.buttonItems[0] = ITEM_NONE;
|
gSaveContext.childEquips.buttonItems[0] = ITEM_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1568,7 +1568,7 @@ void Inventory_SwapAgeEquipment(void) {
|
||||||
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
|
gSaveContext.equips.equipment = gSaveContext.childEquips.equipment;
|
||||||
gSaveContext.equips.equipment &= (u16) ~(0xF << (EQUIP_TYPE_SWORD * 4));
|
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
|
// 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);
|
gSaveContext.equips.equipment |= EQUIP_VALUE_SWORD_KOKIRI << (EQUIP_TYPE_SWORD * 4);
|
||||||
}
|
}
|
||||||
} else if (gSaveContext.childEquips.buttonItems[0] != ITEM_NONE) {
|
} 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).
|
(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
|
When becoming child, set swordless flag if player doesn't have kokiri sword
|
||||||
Only in rando to keep swordless link bugs in vanilla*/
|
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);
|
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.imagePal = 0;
|
||||||
bg->b.imageFlip = CVarGetInteger("gMirroredWorld", 0) ? G_BG_FLAG_FLIPS : 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)) {
|
if (ResourceMgr_ResourceIsBackground((char*) source)) {
|
||||||
char* blob = (char*) ResourceGetDataByName((char *) source);
|
char* blob = (char*) ResourceGetDataByName((char *) source);
|
||||||
swapAndConvertJPEG(blob);
|
swapAndConvertJPEG(blob);
|
||||||
|
|
|
@ -417,7 +417,12 @@ void func_800AEFC8(SkyboxContext* skyboxCtx, s16 skyboxId) {
|
||||||
s32 j;
|
s32 j;
|
||||||
s32 phi_s3 = 0;
|
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) {
|
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,
|
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);
|
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[2]);
|
||||||
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[3]);
|
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[3]);
|
||||||
|
|
||||||
if (skyboxId != SKYBOX_BAZAAR) {
|
//! @bug All shops only provide 2 faces for their sky box. Mask shop is missing from the condition
|
||||||
if (skyboxId <= SKYBOX_HOUSE_KAKARIKO || skyboxId > SKYBOX_BOMBCHU_SHOP) {
|
// 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++);
|
gDPPipeSync(POLY_OPA_DISP++);
|
||||||
gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[2]);
|
gDPLoadTLUT_pal256(POLY_OPA_DISP++, skyboxCtx->palettes[2]);
|
||||||
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]);
|
gSPDisplayList(POLY_OPA_DISP++, skyboxCtx->dListBuf[4]);
|
||||||
|
|
|
@ -6,6 +6,14 @@
|
||||||
#include "soh/frame_interpolation.h"
|
#include "soh/frame_interpolation.h"
|
||||||
#include "soh/Enhancements/boss-rush/BossRush.h"
|
#include "soh/Enhancements/boss-rush/BossRush.h"
|
||||||
#include "soh_assets.h"
|
#include "soh_assets.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 FLAGS (ACTOR_FLAG_TARGETABLE | ACTOR_FLAG_HOSTILE | ACTOR_FLAG_UPDATE_WHILE_CULLED | ACTOR_FLAG_DRAW_WHILE_CULLED)
|
||||||
|
|
||||||
|
@ -60,6 +68,13 @@ static u8 sMaskTex8x8[8 * 8] = { { 0 } };
|
||||||
static u8 sMaskTex8x32[8 * 32] = { { 0 } };
|
static u8 sMaskTex8x32[8 * 32] = { { 0 } };
|
||||||
static u8 sMaskTexLava[32 * 64] = { { 0 } };
|
static u8 sMaskTexLava[32 * 64] = { { 0 } };
|
||||||
|
|
||||||
|
static u32* sLavaFloorModifiedTexRaw = NULL;
|
||||||
|
static u32* sLavaWavyTexRaw = NULL;
|
||||||
|
static u16 sLavaFloorModifiedTex[4096];
|
||||||
|
static u16 sLavaWavyTex[2048];
|
||||||
|
|
||||||
|
static u8 hasRegisteredBlendedHook = 0;
|
||||||
|
|
||||||
static InitChainEntry sInitChain[] = {
|
static InitChainEntry sInitChain[] = {
|
||||||
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
|
ICHAIN_U8(targetMode, 5, ICHAIN_CONTINUE),
|
||||||
ICHAIN_S8(naviEnemyId, 0x0C, ICHAIN_CONTINUE),
|
ICHAIN_S8(naviEnemyId, 0x0C, ICHAIN_CONTINUE),
|
||||||
|
@ -67,6 +82,70 @@ static InitChainEntry sInitChain[] = {
|
||||||
ICHAIN_F32(targetArrowOffset, 8200.0f, ICHAIN_STOP),
|
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(sLavaFloorLavaTex)) {
|
||||||
|
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 {
|
||||||
|
u16* lavaTex = ResourceGetDataByName(sLavaFloorLavaTex);
|
||||||
|
memcpy(sLavaFloorModifiedTex, lavaTex, sizeof(sLavaFloorModifiedTex));
|
||||||
|
|
||||||
|
// When KD is dead, just immediately copy the rock texture
|
||||||
|
if (Flags_GetClear(gPlayState, gPlayState->roomCtx.curRoom.num)) {
|
||||||
|
u16* rockTex = ResourceGetDataByName(sLavaFloorRockTex);
|
||||||
|
size_t rockSize = ResourceGetSizeByName(sLavaFloorRockTex);
|
||||||
|
memcpy(sLavaFloorModifiedTex, rockTex, rockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
void func_808C12C4(u8* arg1, s16 arg2) {
|
||||||
if (arg2[arg1] != 0) {
|
if (arg2[arg1] != 0) {
|
||||||
sMaskTex8x16[arg2 / 2] = 1;
|
sMaskTex8x16[arg2 / 2] = 1;
|
||||||
|
@ -87,12 +166,51 @@ void func_808C12C4(u8* arg1, s16 arg2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
// Same as func_808C1554 but works with u32 values for RGBA32 raw textures
|
||||||
arg0 = GetResourceDataByNameHandlingMQ(arg0);
|
void func_808C1554_Raw(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
||||||
floorTex = ResourceGetDataByName(floorTex);
|
u16 width = ResourceGetTexWidthByName(arg0);
|
||||||
|
s32 size = ResourceGetTexHeightByName(arg0) * width;
|
||||||
|
|
||||||
u16* temp_s3 = SEGMENTED_TO_VIRTUAL(arg0);
|
u32* temp_s3 = sLavaWavyTexRaw;
|
||||||
u16* temp_s1 = SEGMENTED_TO_VIRTUAL(floorTex);
|
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 / 32;
|
||||||
|
|
||||||
|
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 i;
|
||||||
s16 i2;
|
s16 i2;
|
||||||
u16 sp54[2048];
|
u16 sp54[2048];
|
||||||
|
@ -113,6 +231,9 @@ void func_808C1554(void* arg0, void* floorTex, s32 arg2, f32 arg3) {
|
||||||
temp_s3[i + temp2] = sp54[i + i2];
|
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) {
|
void func_808C17C8(PlayState* play, Vec3f* arg1, Vec3f* arg2, Vec3f* arg3, f32 arg4, s16 arg5) {
|
||||||
|
@ -188,27 +309,21 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
||||||
Collider_SetJntSph(play, &this->collider, &this->actor, &sJntSphInit, this->items);
|
Collider_SetJntSph(play, &this->collider, &this->actor, &sJntSphInit, this->items);
|
||||||
|
|
||||||
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) { // KD is dead
|
if (Flags_GetClear(play, play->roomCtx.curRoom.num)) { // KD is dead
|
||||||
u16* LavaFloorTex = ResourceGetDataByName(gDodongosCavernBossLavaFloorTex);
|
// SOH [General]
|
||||||
u16* LavaFloorRockTex = ResourceGetDataByName(sLavaFloorRockTex);
|
// Applying the "cooled off" lava rock CPU modified texture for re-visiting the scene
|
||||||
temp_s1_3 = SEGMENTED_TO_VIRTUAL(LavaFloorTex);
|
// is now handled by BossDodongo_RegisterBlendedLavaTextureUpdate below
|
||||||
temp_s2 = SEGMENTED_TO_VIRTUAL(LavaFloorRockTex);
|
|
||||||
Actor_Kill(&this->actor);
|
Actor_Kill(&this->actor);
|
||||||
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f,
|
Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_DOOR_WARP1, -890.0f, -1523.76f,
|
||||||
-3304.0f, 0, 0, 0, WARP_DUNGEON_CHILD);
|
-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_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);
|
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;
|
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++) {
|
for (int i = 0; i < ARRAY_COUNT(sMaskTex8x16); i++) {
|
||||||
sMaskTex8x16[i] = 0;
|
sMaskTex8x16[i] = 0;
|
||||||
}
|
}
|
||||||
|
@ -224,6 +339,12 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
||||||
for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) {
|
for (int i = 0; i < ARRAY_COUNT(sMaskTex32x16); i++) {
|
||||||
sMaskTex32x16[i] = 0;
|
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_015890, sMaskTex8x16, NULL);
|
||||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_017210, sMaskTex8x32, NULL);
|
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_017210, sMaskTex8x32, NULL);
|
||||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015D90, sMaskTex16x16, NULL);
|
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_015D90, sMaskTex16x16, NULL);
|
||||||
|
@ -235,10 +356,14 @@ void BossDodongo_Init(Actor* thisx, PlayState* play) {
|
||||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL);
|
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016990, sMaskTex32x16, NULL);
|
||||||
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL);
|
Gfx_RegisterBlendedTexture(object_kingdodongo_Tex_016E10, sMaskTex32x16, NULL);
|
||||||
|
|
||||||
// OTRTODO: This is causing OOB memory reads with HD assets
|
BossDodongo_RegisterBlendedLavaTextureUpdate();
|
||||||
// commenting this out means the lava will stay lava even after beating king d
|
|
||||||
//
|
// Register alt listener to update the blended lava for the replacement texture based on alt path
|
||||||
// Gfx_RegisterBlendedTexture(gDodongosCavernBossLavaFloorTex, sMaskTexLava, sLavaFloorRockTex);
|
if (!hasRegisteredBlendedHook) {
|
||||||
|
GameInteractor_RegisterOnAssetAltChange(BossDodongo_RegisterBlendedLavaTextureUpdate);
|
||||||
|
hasRegisteredBlendedHook = 1;
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
void BossDodongo_Destroy(Actor* thisx, PlayState* play) {
|
void BossDodongo_Destroy(Actor* thisx, PlayState* play) {
|
||||||
|
@ -1015,21 +1140,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.
|
// The lava bubbles with a wavy effect as a CPU modified texture
|
||||||
//func_808C1554(gDodongosCavernBossLavaFloorTex, sLavaFloorLavaTex, this->unk_19E, this->unk_224);
|
// 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) {
|
if (this->unk_1C6 != 0) {
|
||||||
u16* ptr1 = ResourceGetDataByName(sLavaFloorLavaTex);
|
// Similar to above, the cooling off effect is a CPU modified texture effect
|
||||||
u16* ptr2 = ResourceGetDataByName(sLavaFloorRockTex);
|
// Apply corresponding to the texture being raw or not
|
||||||
s16 i2;
|
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++) {
|
// Get the scale based on the original texture size
|
||||||
s16 new_var = this->unk_1C2 & 0x7FF;
|
u16 widthScale = width / 32;
|
||||||
|
u16 heightScale = height / 64;
|
||||||
|
u32 size = width * height;
|
||||||
|
|
||||||
sMaskTexLava[new_var] = 1;
|
for (i2 = 0; i2 < 20; i2++) {
|
||||||
this->unk_1C2 += 37;
|
s16 new_var = this->unk_1C2 & 0x7FF;
|
||||||
|
// Compute the index to a scaled position (scaling pseudo x,y as a 1D value)
|
||||||
|
s32 indexStart = ((new_var % 32) * widthScale) + ((new_var / 32) * 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);
|
Math_SmoothStepToF(&this->unk_224, 0.0f, 1.0f, 0.01f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10101,7 +10101,8 @@ void func_80847BA0(PlayState* play, Player* this) {
|
||||||
|
|
||||||
D_808535F0 = func_80041DB8(&play->colCtx, this->actor.wallPoly, this->actor.wallBgId);
|
D_808535F0 = 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.
|
/* 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
|
* 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
|
* still be valid once climbing begins by doing a second raycast with a small
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue