Merge pull request #1449 from HarbourMasters/develop-zhora

zhora -> rando-next
This commit is contained in:
briaguya 2022-09-09 00:16:36 -04:00 committed by GitHub
commit 19b8e12933
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 256 additions and 34 deletions

View File

@ -186,9 +186,9 @@ cmake --build build-cmake --target ExtractAssets
# Setup cmake project for building for Wii U
cmake -H. -Bbuild-wiiu -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/WiiU.cmake # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging)
# Build project and generate rpx
cmake --build build-wiiu --target soh
cmake --build build-wiiu --target soh # --target soh_wuhb (for building .wuhb)
# Now you can run the executable in ./build-wiiu/soh/soh.rpx
# Now you can run the executable in ./build-wiiu/soh/soh.rpx or the Wii U Homebrew Bundle in ./build-wiiu/soh/soh.wuhb
# To develop the project open the repository in VSCode (or your preferred editor)
```

3
Jenkinsfile vendored
View File

@ -206,9 +206,10 @@ pipeline {
docker exec sohwiiucont scripts/wiiu/build.sh
mv build-wiiu/soh/*.rpx soh.rpx
mv build-wiiu/soh/*.wuhb soh.wuhb
mv README.md readme.txt
7z a soh-wiiu.7z soh.rpx readme.txt
7z a soh-wiiu.7z soh.rpx soh.wuhb readme.txt
'''
}

View File

@ -12,6 +12,7 @@ extern "C" void DeinitOTR(void);
#include <dlfcn.h> // for dladdr
#include <execinfo.h>
#include <unistd.h>
#include <SDL.h>
@ -135,9 +136,11 @@ static void ErrorHandler(int sig, siginfo_t* sigInfo, void* data) {
SPDLOG_CRITICAL("{} {}", i, functionName.c_str());
}
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "SoH has crashed", "SoH Has crashed. Please upload the logs to the support channel in discord.", nullptr);
free(symbols);
DeinitOTR();
Ship::Window::GetInstance()->GetLogger()->flush();
spdlog::shutdown();
exit(1);
}

View File

@ -139,7 +139,7 @@ namespace Ship {
ToLoad->resource = Res;
ResourceCache[Res->file->path] = Res;
SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path);
SPDLOG_TRACE("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path);
Res->file = nullptr;
} else {

View File

@ -540,13 +540,12 @@ namespace Ship {
if (!ResMan->DidLoadSuccessfully())
{
#ifdef _WIN32
MessageBox(nullptr, L"Main OTR file not found!", L"Uh oh", MB_OK);
#elif defined(__SWITCH__)
#if defined(__SWITCH__)
printf("Main OTR file not found!\n");
#elif defined(__WIIU__)
Ship::WiiU::ThrowMissingOTR(MainPath.c_str());
#else
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OTR file not found", "Main OTR file not found. Please generate one", nullptr);
SPDLOG_ERROR("Main OTR file not found!");
#endif
exit(1);

View File

@ -1,4 +1,4 @@
#!/bin/bash
cmake -H. -Bbuild-wiiu -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/WiiU.cmake -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build-wiiu --target soh --config Release
cmake --build build-wiiu --target soh_wuhb --config Release

View File

@ -2040,6 +2040,13 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "CafeOS")
wut_create_rpx(${PROJECT_NAME})
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/soh.rpx DESTINATION . COMPONENT ship)
wut_create_wuhb(${PROJECT_NAME}
NAME "Ship of Harkinian"
SHORTNAME "SoH"
AUTHOR "Harbour Masters"
ICON ${CMAKE_CURRENT_SOURCE_DIR}/icon.jpg
)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/soh.rpx ${CMAKE_CURRENT_BINARY_DIR}/soh.wuhb DESTINATION . COMPONENT ship)
endif()

View File

@ -238,6 +238,10 @@ namespace GameMenuBar {
CVar_SetS32("gInjectSkulltulaCount", 0);
// Pull grave during the day
CVar_SetS32("gDayGravePull", 0);
// Blue Fire Arrows
CVar_SetS32("gBlueFireArrows", 0);
// Sunlight Arrows
CVar_SetS32("gSunlightArrows", 0);
// Rotate link (0 to 2)
CVar_SetS32("gPauseLiveLinkRotation", 0);
@ -655,8 +659,6 @@ namespace GameMenuBar {
UIWidgets::Tooltip("Allows the D-pad to be used as extra C buttons");
UIWidgets::PaddedEnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor", true, false);
UIWidgets::Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97");
UIWidgets::PaddedEnhancementCheckbox("Prevent Dropped Ocarina Inputs", "gDpadNoDropOcarinaInput", true, false);
UIWidgets::Tooltip("Prevent dropping inputs when playing the ocarina quickly");
UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL", true, false);
UIWidgets::Tooltip("Speak to Navi with L but enter first-person camera with C-Up");
ImGui::EndMenu();
@ -680,8 +682,6 @@ namespace GameMenuBar {
UIWidgets::Tooltip("Prevent forced Navi conversations");
UIWidgets::PaddedEnhancementCheckbox("No Skulltula Freeze", "gSkulltulaFreeze", true, false);
UIWidgets::Tooltip("Stops the game from freezing the player when picking up Gold Skulltulas");
UIWidgets::PaddedEnhancementCheckbox("MM Bunny Hood", "gMMBunnyHood", true, false);
UIWidgets::Tooltip("Wearing the Bunny Hood grants a speed increase like in Majora's Mask");
UIWidgets::PaddedEnhancementCheckbox("Fast Chests", "gFastChests", true, false);
UIWidgets::Tooltip("Kick open every chest");
UIWidgets::PaddedEnhancementCheckbox("Skip Pickup Messages", "gFastDrops", true, false);
@ -697,15 +697,26 @@ namespace GameMenuBar {
UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", "gSkipScarecrow", true, false,
forceSkipScarecrow, forceSkipScarecrowText, UIWidgets::CheckboxGraphics::Checkmark);
UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song.");
UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false);
UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n"
"This doesn't work if the save was made in a grotto.");
ImGui::EndMenu();
}
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Items"))
{
UIWidgets::PaddedEnhancementCheckbox("Instant Putaway", "gInstantPutaway", true, false);
UIWidgets::Tooltip("Allow Link to put items away without having to wait around");
UIWidgets::PaddedEnhancementCheckbox("Instant Boomerang Recall", "gFastBoomerang", true, false);
UIWidgets::Tooltip("Instantly return the boomerang to Link by pressing its item button while it's in the air");
UIWidgets::PaddedEnhancementCheckbox("Prevent Dropped Ocarina Inputs", "gDpadNoDropOcarinaInput", true, false);
UIWidgets::Tooltip("Prevent dropping inputs when playing the ocarina quickly");
UIWidgets::PaddedEnhancementCheckbox("MM Bunny Hood", "gMMBunnyHood", true, false);
UIWidgets::Tooltip("Wearing the Bunny Hood grants a speed increase like in Majora's Mask");
UIWidgets::PaddedEnhancementCheckbox("Mask Select in Inventory", "gMaskSelect", true, false);
UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks");
UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false);
UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n"
"This doesn't work if the save was made in a grotto.");
ImGui::EndMenu();
}
@ -884,6 +895,10 @@ namespace GameMenuBar {
UIWidgets::Tooltip("Injects Golden Skulltula total count in pickup messages");
UIWidgets::PaddedEnhancementCheckbox("Pull grave during the day", "gDayGravePull", true, false);
UIWidgets::Tooltip("Allows graves to be pulled when child during the day");
UIWidgets::PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false);
UIWidgets::Tooltip("Allows Ice Arrows to melt red ice.\nMay require a room reload if toggled during gameplay.");
UIWidgets::PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false);
UIWidgets::Tooltip("Allows Light Arrows to activate sun switches.\nMay require a room reload if toggled during gameplay.");
ImGui::EndMenu();
}

View File

@ -1,4 +1,4 @@
const char gBuildVersion[] = "ZHORA ALFA (3.1.0)";
const char gBuildVersion[] = "ZHORA ALFA (4.0.0)";
const char gBuildTeam[] = "github.com/harbourmasters";
const char gBuildDate[] = __DATE__ " " __TIME__;
const char gBuildMakeOption[] = "";

View File

@ -218,7 +218,8 @@ void GivePlayerRandoRewardNocturne(GlobalContext* globalCtx, RandomizerCheck che
!Player_InBlockingCsMode(globalCtx, player) && !Flags_GetEventChkInf(0xAA)) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(check, RG_NOCTURNE_OF_SHADOW);
GiveItemEntryWithoutActor(globalCtx, getItemEntry);
Flags_SetEventChkInf(0xAA);
player->pendingFlag.flagID = 0xAA;
player->pendingFlag.flagType = FLAG_EVENT_CHECK_INF;
}
}
@ -230,7 +231,8 @@ void GivePlayerRandoRewardRequiem(GlobalContext* globalCtx, RandomizerCheck chec
!Player_InBlockingCsMode(globalCtx, player)) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(check, RG_SONG_OF_TIME);
GiveItemEntryWithoutActor(globalCtx, getItemEntry);
Flags_SetEventChkInf(0xAC);
player->pendingFlag.flagID = 0xAC;
player->pendingFlag.flagType = FLAG_EVENT_CHECK_INF;
}
}
}

View File

@ -59,6 +59,27 @@ static ColliderQuadInit sQuadInit = {
{ { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } },
};
// Replacement quad used for "Blue Fire Arrows" enhancement
static ColliderQuadInit sIceArrowQuadInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER | AC_TYPE_OTHER,
OC1_NONE,
OC2_TYPE_2,
COLSHAPE_QUAD,
},
{
ELEMTYPE_UNK0,
{ 0x00000048, 0x00, 0x00 },
{ 0x00001048, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_NONE,
},
{ { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } },
};
static BombableWallInfo sBombableWallInfo[] = {
{ &object_bwall_Col_000118, object_bwall_DL_000040, 0 },
{ &object_bwall_Col_000118, object_bwall_DL_000040, 0 },
@ -73,6 +94,8 @@ static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneDownward, 400, ICHAIN_STOP),
};
bool blueFireArrowsEnabledOnMudwallLoad = false;
void BgBreakwall_SetupAction(BgBreakwall* this, BgBreakwallActionFunc actionFunc) {
this->actionFunc = actionFunc;
}
@ -82,6 +105,9 @@ void BgBreakwall_Init(Actor* thisx, GlobalContext* globalCtx) {
s32 pad;
s32 wallType = ((this->dyna.actor.params >> 13) & 3) & 0xFF;
// Initialize this with the mud wall, so it can't be affected by toggling while the actor is loaded
blueFireArrowsEnabledOnMudwallLoad = (CVar_GetS32("gBlueFireArrows", 0));
Actor_ProcessInitChain(&this->dyna.actor, sInitChain);
DynaPolyActor_Init(&this->dyna, DPM_UNK);
this->bombableWallDList = sBombableWallInfo[wallType].dList;
@ -98,8 +124,15 @@ void BgBreakwall_Init(Actor* thisx, GlobalContext* globalCtx) {
}
ActorShape_Init(&this->dyna.actor.shape, 0.0f, NULL, 0.0f);
Collider_InitQuad(globalCtx, &this->collider);
Collider_SetQuad(globalCtx, &this->collider, &this->dyna.actor, &sQuadInit);
// If "Blue Fire Arrows" are enabled, set up this collider for them
if (blueFireArrowsEnabledOnMudwallLoad) {
Collider_InitQuad(globalCtx, &this->collider);
Collider_SetQuad(globalCtx, &this->collider, &this->dyna.actor, &sIceArrowQuadInit);
} else {
Collider_InitQuad(globalCtx, &this->collider);
Collider_SetQuad(globalCtx, &this->collider, &this->dyna.actor, &sQuadInit);
}
} else {
this->dyna.actor.world.pos.y -= 40.0f;
}
@ -227,7 +260,21 @@ void BgBreakwall_WaitForObject(BgBreakwall* this, GlobalContext* globalCtx) {
* despawn itself.
*/
void BgBreakwall_Wait(BgBreakwall* this, GlobalContext* globalCtx) {
if (this->collider.base.acFlags & 2) {
bool blueFireArrowHit = false;
// If "Blue Fire Arrows" enabled, check this collider for a hit
if (blueFireArrowsEnabledOnMudwallLoad) {
if (this->collider.base.acFlags & AC_HIT) {
if ((this->collider.base.ac != NULL) && (this->collider.base.ac->id == ACTOR_EN_ARROW)) {
if (this->collider.base.ac->child != NULL &&
this->collider.base.ac->child->id == ACTOR_ARROW_ICE) {
blueFireArrowHit = true;
}
}
}
}
if (this->collider.base.acFlags & 2 || blueFireArrowHit) {
Vec3f effectPos;
s32 wallType = ((this->dyna.actor.params >> 13) & 3) & 0xFF;

View File

@ -14,6 +14,9 @@ void func_808911BC(BgIceShelter* this);
void func_8089107C(BgIceShelter* this, GlobalContext* globalCtx);
void func_808911D4(BgIceShelter* this, GlobalContext* globalCtx);
// For "Blue Fire Arrows" enhancement
void MeltOnIceArrowHit(BgIceShelter* this, ColliderCylinder cylinder, s16 type, GlobalContext* globalCtx);
const ActorInit Bg_Ice_Shelter_InitVars = {
ACTOR_BG_ICE_SHELTER,
ACTORCAT_BG,
@ -32,7 +35,7 @@ static f32 sScales[] = { 0.1f, 0.06f, 0.1f, 0.1f, 0.25f };
static Color_RGBA8 sDustPrimColor = { 250, 250, 250, 255 };
static Color_RGBA8 sDustEnvColor = { 180, 180, 180, 255 };
static ColliderCylinderInit D_8089170C = {
static ColliderCylinderInit sCylinder1Init = {
{
COLTYPE_NONE,
AT_NONE,
@ -52,7 +55,7 @@ static ColliderCylinderInit D_8089170C = {
{ 0, 0, 0, { 0, 0, 0 } },
};
static ColliderCylinderInit D_80891738 = {
static ColliderCylinderInit sCylinder2Init = {
{
COLTYPE_HARD,
AT_NONE,
@ -72,14 +75,45 @@ static ColliderCylinderInit D_80891738 = {
{ 0, 0, 0, { 0, 0, 0 } },
};
// This cylinder only used for "Blue Fire Arrows" enhancement
static ColliderCylinderInit sIceArrowCylinderInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_OTHER | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_2,
COLSHAPE_CYLINDER,
},
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0xFFCFFFFF, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_ON,
},
{ 0, 0, 0, { 0, 0, 0 } },
};
bool blueFireArrowsEnabledOnRedIceLoad = false;
void func_80890740(BgIceShelter* this, GlobalContext* globalCtx) {
static s16 cylinderRadii[] = { 47, 33, 44, 41, 100 };
static s16 cylinderHeights[] = { 80, 54, 90, 60, 200 };
s32 pad;
s32 type = (this->dyna.actor.params >> 8) & 7;
// Initialize this with the red ice, so it can't be affected by toggling while the actor is loaded
blueFireArrowsEnabledOnRedIceLoad = (CVar_GetS32("gBlueFireArrows", 0));
Collider_InitCylinder(globalCtx, &this->cylinder1);
Collider_SetCylinder(globalCtx, &this->cylinder1, &this->dyna.actor, &D_8089170C);
// If "Blue Fire Arrows" is enabled, set up a collider on the red ice that responds to them
if (blueFireArrowsEnabledOnRedIceLoad) {
Collider_SetCylinder(globalCtx, &this->cylinder1, &this->dyna.actor, &sIceArrowCylinderInit);
} else {
Collider_SetCylinder(globalCtx, &this->cylinder1, &this->dyna.actor, &sCylinder1Init);
}
Collider_UpdateCylinder(&this->dyna.actor, &this->cylinder1);
this->cylinder1.dim.radius = cylinderRadii[type];
@ -87,7 +121,7 @@ void func_80890740(BgIceShelter* this, GlobalContext* globalCtx) {
if (type == 0 || type == 1 || type == 4) {
Collider_InitCylinder(globalCtx, &this->cylinder2);
Collider_SetCylinder(globalCtx, &this->cylinder2, &this->dyna.actor, &D_80891738);
Collider_SetCylinder(globalCtx, &this->cylinder2, &this->dyna.actor, &sCylinder2Init);
Collider_UpdateCylinder(&this->dyna.actor, &this->cylinder2);
this->cylinder2.dim.radius = cylinderRadii[type];
this->cylinder2.dim.height = cylinderHeights[type];
@ -292,7 +326,12 @@ void func_8089107C(BgIceShelter* this, GlobalContext* globalCtx) {
this->dyna.actor.parent->freezeTimer = 10000;
}
}
// If we have "Blue Fire Arrows" enabled, check both cylinders for a hit
if (blueFireArrowsEnabledOnRedIceLoad) {
MeltOnIceArrowHit(this, this->cylinder1, type, globalCtx);
MeltOnIceArrowHit(this, this->cylinder2, type, globalCtx);
}
// Default blue fire check
if (this->cylinder1.base.acFlags & AC_HIT) {
this->cylinder1.base.acFlags &= ~AC_HIT;
@ -320,6 +359,24 @@ void func_8089107C(BgIceShelter* this, GlobalContext* globalCtx) {
CollisionCheck_SetAC(globalCtx, &globalCtx->colChkCtx, &this->cylinder1.base);
}
// For "Blue Fire Arrows" enhancement: If hit by an Ice Arrow, melt the red ice (copied from the default blue fire function above).
void MeltOnIceArrowHit(BgIceShelter* this, ColliderCylinder cylinder, s16 type, GlobalContext* globalCtx) {
if (cylinder.base.acFlags & AC_HIT) {
cylinder.base.acFlags &= ~AC_HIT;
if ((cylinder.base.ac != NULL) && (cylinder.base.ac->id == ACTOR_EN_ARROW)) {
if (cylinder.base.ac->child != NULL && cylinder.base.ac->child->id == ACTOR_ARROW_ICE) {
if (type == 4) {
if (this->dyna.actor.parent != NULL) {
this->dyna.actor.parent->freezeTimer = 50;
}
}
func_808911BC(this);
Audio_PlayActorSound2(&this->dyna.actor, NA_SE_EV_ICE_MELT);
}
}
}
}
void func_808911BC(BgIceShelter* this) {
this->actionFunc = func_808911D4;
this->alpha = 255;

View File

@ -96,7 +96,15 @@ void BgJyaLift_DelayMove(BgJyaLift* this, GlobalContext* globalCtx) {
if (Flags_GetSwitch(globalCtx, this->dyna.actor.params & 0x3F) || (this->moveDelay > 0)) {
this->moveDelay++;
if (this->moveDelay >= 20) {
OnePointCutscene_Init(globalCtx, 3430, -99, &this->dyna.actor, MAIN_CAM);
// The cutscene of the platform lowering will show the central room in an unloaded state if
// Link is not standing on the platform as it lowers. Therefore check for the Sunlight arrows
// enhancement and if it's enabled, check that Link is on the platform. Otherwise skip it.
if (!CVar_GetS32("gSunlightArrows", 0) || (GET_PLAYER(globalCtx)->actor.world.pos.x > -19.0f &&
GET_PLAYER(globalCtx)->actor.world.pos.x < 139.0f &&
GET_PLAYER(globalCtx)->actor.world.pos.z > -1172.0f &&
GET_PLAYER(globalCtx)->actor.world.pos.z < -1009.0f)) {
OnePointCutscene_Init(globalCtx, 3430, -99, &this->dyna.actor, MAIN_CAM);
}
BgJyaLift_SetupMove(this);
}
}

View File

@ -73,6 +73,36 @@ static ColliderJntSphInit sColliderJntSphInit = {
1,
sColliderJntSphElementInit,
};
// Collider info used for "Sunlight Arrows"
static ColliderJntSphElementInit sColliderLightArrowElementInit[] = {
{
{
ELEMTYPE_UNK0,
{ 0x00000000, 0x00, 0x00 },
{ 0x00202000, 0x00, 0x00 },
TOUCH_NONE,
BUMP_ON,
OCELEM_ON,
},
{ 0, { { 0, 0, 0 }, 19 }, 100 },
},
};
// Sphere collider used for "Sunlight Arrows"
static ColliderJntSphInit sColliderLightArrowInit = {
{
COLTYPE_NONE,
AT_NONE,
AC_ON | AC_TYPE_PLAYER,
OC1_ON | OC1_TYPE_ALL,
OC2_TYPE_2,
COLSHAPE_JNTSPH,
},
1,
sColliderLightArrowElementInit,
};
bool sunSwitchActivatedByLightArrow = false;
bool sunLightArrowsEnabledOnSunSwitchLoad = false;
static CollisionCheckInfoInit sColChkInfoInit = { 0, 12, 60, MASS_IMMOVABLE };
@ -92,8 +122,16 @@ static InitChainEntry sInitChain[] = {
void ObjLightswitch_InitCollider(ObjLightswitch* this, GlobalContext* globalCtx) {
s32 pad;
// Initialize this with the sun switch, so it can't be affected by toggling while the actor is loaded
sunLightArrowsEnabledOnSunSwitchLoad = (CVar_GetS32("gSunlightArrows", 0));
Collider_InitJntSph(globalCtx, &this->collider);
Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sColliderJntSphInit, this->colliderItems);
// If "Sunlight Arrows" is enabled, set up the collider to allow Light Arrow hits
if (sunLightArrowsEnabledOnSunSwitchLoad) {
Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sColliderLightArrowInit, this->colliderItems);
} else {
Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sColliderJntSphInit, this->colliderItems);
}
Matrix_SetTranslateRotateYXZ(this->actor.world.pos.x,
this->actor.world.pos.y + (this->actor.shape.yOffset * this->actor.scale.y),
this->actor.world.pos.z, &this->actor.shape.rot);
@ -211,6 +249,26 @@ void ObjLightswitch_Destroy(Actor* thisx, GlobalContext* globalCtx2) {
GlobalContext* globalCtx = globalCtx2;
ObjLightswitch* this = (ObjLightswitch*)thisx;
// Unset the switch flag on room exit to prevent the rock in the wall from
// vanishing on its own after activating the sun switch by Light Arrow
// Also prevents the cobra mirror from rotating to face the sun on its own
// Makes sun switches temporary when activated by Light Arrows (will turn off on room exit)
if (sunSwitchActivatedByLightArrow) {
switch (this->actor.params >> 4 & 3) {
case OBJLIGHTSWITCH_TYPE_STAY_ON:
case OBJLIGHTSWITCH_TYPE_2:
case OBJLIGHTSWITCH_TYPE_1:
// Except for this one, because we want the chain platform to stay down for good
if (this->actor.room != 25) {
Flags_UnsetSwitch(globalCtx, this->actor.params >> 8 & 0x3F);
}
sunSwitchActivatedByLightArrow = false;
break;
case OBJLIGHTSWITCH_TYPE_BURN:
break;
}
}
Collider_DestroyJntSph(globalCtx, &this->collider);
}
@ -221,8 +279,11 @@ void ObjLightswitch_SetupOff(ObjLightswitch* this) {
this->color[1] = 125 << 6;
this->color[2] = 255 << 6;
this->alpha = 255 << 6;
if (sunLightArrowsEnabledOnSunSwitchLoad) {
sunSwitchActivatedByLightArrow = false;
}
}
// A Sun Switch that is currently turned off
void ObjLightswitch_Off(ObjLightswitch* this, GlobalContext* globalCtx) {
switch (this->actor.params >> 4 & 3) {
case OBJLIGHTSWITCH_TYPE_STAY_ON:
@ -230,6 +291,13 @@ void ObjLightswitch_Off(ObjLightswitch* this, GlobalContext* globalCtx) {
if (this->collider.base.acFlags & AC_HIT) {
ObjLightswitch_SetupTurnOn(this);
ObjLightswitch_SetSwitchFlag(this, globalCtx);
// Remember if we've been activated by a Light Arrow, so we can
// prevent the switch from immediately turning back off
if (sunLightArrowsEnabledOnSunSwitchLoad) {
if (this->collider.base.ac != NULL && this->collider.base.ac->id == ACTOR_EN_ARROW) {
sunSwitchActivatedByLightArrow = true;
}
}
}
break;
case OBJLIGHTSWITCH_TYPE_1:
@ -289,13 +357,19 @@ void ObjLightswitch_SetupOn(ObjLightswitch* this) {
this->flameRingRotSpeed = -0xAA;
this->timer = 0;
}
// A Sun Switch that is currently turned on
void ObjLightswitch_On(ObjLightswitch* this, GlobalContext* globalCtx) {
switch (this->actor.params >> 4 & 3) {
case OBJLIGHTSWITCH_TYPE_STAY_ON:
if (!Flags_GetSwitch(globalCtx, this->actor.params >> 8 & 0x3F)) {
ObjLightswitch_SetupTurnOff(this);
}
// If hit by sunlight after already being turned on, then behave as if originally activated by sunlight
if (sunLightArrowsEnabledOnSunSwitchLoad && (this->collider.base.acFlags & AC_HIT)) {
if (this->collider.base.ac != NULL && this->collider.base.ac->id != ACTOR_EN_ARROW) {
sunSwitchActivatedByLightArrow = false;
}
}
break;
case OBJLIGHTSWITCH_TYPE_1:
if (this->collider.base.acFlags & AC_HIT && !(this->prevFrameACflags & AC_HIT)) {
@ -304,10 +378,19 @@ void ObjLightswitch_On(ObjLightswitch* this, GlobalContext* globalCtx) {
}
break;
case OBJLIGHTSWITCH_TYPE_2:
// If hit by sunlight after already being turned on, then behave as if originally activated by sunlight
if (sunLightArrowsEnabledOnSunSwitchLoad && (this->collider.base.acFlags & AC_HIT)) {
if (this->collider.base.ac != NULL && this->collider.base.ac->id != ACTOR_EN_ARROW) {
sunSwitchActivatedByLightArrow = false;
}
}
if (!(this->collider.base.acFlags & AC_HIT)) {
if (this->timer >= 7) {
ObjLightswitch_SetupTurnOff(this);
ObjLightswitch_ClearSwitchFlag(this, globalCtx);
// If we aren't using Enhanced Light Arrows, let the switch turn off normally
if (!sunSwitchActivatedByLightArrow) {
ObjLightswitch_SetupTurnOff(this);
ObjLightswitch_ClearSwitchFlag(this, globalCtx);
}
} else {
this->timer++;
}