Merge branch 'develop' of github.com:Malkierian/Shipwright into reindeer-games

This commit is contained in:
Malkierian
2025-12-03 09:14:56 -07:00
66 changed files with 977 additions and 473 deletions
+4
View File
@@ -9,6 +9,10 @@
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#include "soh/Enhancements/boss-rush/BossRush.h"
#define FULL_HEART_HEALTH 0x10
#define STARTING_HEALTH (3 * FULL_HEART_HEALTH)
#define MAX_HEALTH (20 * FULL_HEART_HEALTH)
typedef enum {
/* 0x0 */ MAGIC_STATE_IDLE, // Regular gameplay
/* 0x1 */ MAGIC_STATE_CONSUME_SETUP, // Sets the speed at which magic border flashes
@@ -0,0 +1,33 @@
#include <libultraship/bridge.h>
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
#include "functions.h"
#include "macros.h"
extern "C" PlayState* gPlayState;
static constexpr int32_t CVAR_HYPER_ENEMIES_DEFAULT = 0;
#define CVAR_HYPER_ENEMIES_NAME CVAR_ENHANCEMENT("HyperEnemies")
#define CVAR_HYPER_ENEMIES_VALUE CVarGetInteger(CVAR_HYPER_ENEMIES_NAME, CVAR_HYPER_ENEMIES_DEFAULT)
static void MakeHyperEnemies(void* refActor) {
// Run the update function a second time to make enemies and minibosses move and act twice as fast.
Player* player = GET_PLAYER(gPlayState);
Actor* actor = static_cast<Actor*>(refActor);
// Some enemies are not in the ACTORCAT_ENEMY category, and some are that aren't really enemies.
bool isEnemy = actor->category == ACTORCAT_ENEMY || actor->id == ACTOR_EN_TORCH2;
bool isExcludedEnemy = actor->id == ACTOR_EN_FIRE_ROCK || actor->id == ACTOR_EN_ENCOUNT2;
// Don't apply during cutscenes because it causes weird behaviour and/or crashes on some cutscenes.
if (isEnemy && !isExcludedEnemy && !Player_InBlockingCsMode(gPlayState, player)) {
GameInteractor::RawAction::UpdateActor(actor);
}
}
static void UpdateHyperEnemiesState() {
COND_HOOK(OnActorUpdate, CVAR_HYPER_ENEMIES_VALUE, MakeHyperEnemies);
}
static RegisterShipInitFunc initFunc(UpdateHyperEnemiesState, { CVAR_HYPER_ENEMIES_NAME });
@@ -1,5 +1,4 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/Enhancements/mods.h"
#include "soh/OTRGlobals.h"
#include "soh/SaveManager.h"
#include "soh/ShipInit.hpp"
@@ -23,9 +22,14 @@ static constexpr int32_t CVAR_DELETE_FILE_DEFAULT = 0;
static bool hasAffectedHealth = false;
void UpdatePermanentHeartLossState() {
if (!GameInteractor::IsSaveLoaded() || !hasAffectedHealth || CVAR_PERM_HEART_LOSS_VALUE)
static void UpdatePermanentHeartLossState() {
// Reset Link's hearts to the normal value without permanent losses. Only applies if all of the following are true:
// - A saved game is playing
// - The "Permanent Heart Loss" setting is turned off
// - The player has lost at least one Heart Container
if (!GameInteractor::IsSaveLoaded() || !hasAffectedHealth || CVAR_PERM_HEART_LOSS_VALUE) {
return;
}
uint8_t heartContainers = gSaveContext.ship.stats.heartContainers; // each worth 16 health
uint8_t heartPieces = gSaveContext.ship.stats.heartPieces; // each worth 4 health, but only in groups of 4
@@ -39,8 +43,10 @@ void UpdatePermanentHeartLossState() {
}
static void UpdateHealthCapacity() {
if (!GameInteractor::IsSaveLoaded())
// Applies permanent losses of Heart Containers to Link's health. Only applies when a saved game is playing.
if (!GameInteractor::IsSaveLoaded()) {
return;
}
if (gSaveContext.healthCapacity > 16 && gSaveContext.healthCapacity - gSaveContext.health >= 16) {
gSaveContext.healthCapacity -= 16;
@@ -50,8 +56,9 @@ static void UpdateHealthCapacity() {
}
static void DeleteFileOnDeath() {
if (!GameInteractor::IsSaveLoaded() || gPlayState == NULL)
if (!GameInteractor::IsSaveLoaded() || gPlayState == NULL) {
return;
}
if (gPlayState->gameOverCtx.state == GAMEOVER_DEATH_MENU && gPlayState->pauseCtx.state == 9) {
SaveManager::Instance->DeleteZeldaFile(gSaveContext.fileNum);
@@ -63,6 +70,7 @@ static void DeleteFileOnDeath() {
}
static void RegisterPermanentHeartLoss() {
UpdatePermanentHeartLossState();
COND_HOOK(OnPlayerUpdate, CVAR_PERM_HEART_LOSS_VALUE, UpdateHealthCapacity);
}
@@ -0,0 +1,42 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "variables.h"
extern SaveContext gSaveContext;
}
static constexpr int32_t CVAR_HURT_CONTAINER_DEFAULT = 0;
#define CVAR_HURT_CONTAINER_NAME CVAR_ENHANCEMENT("HurtContainer")
#define CVAR_HURT_CONTAINER_VALUE CVarGetInteger(CVAR_HURT_CONTAINER_NAME, CVAR_HURT_CONTAINER_DEFAULT)
static bool hurtEnabled = false;
static void UpdateHurtContainerModeState() {
hurtEnabled = CVAR_HURT_CONTAINER_VALUE;
uint16_t heartPieceContainers = gSaveContext.ship.stats.heartPieces / 4;
uint16_t heartContainers = gSaveContext.ship.stats.heartContainers;
uint16_t healthCapacityMod = (heartPieceContainers + heartContainers) * FULL_HEART_HEALTH;
if (hurtEnabled != CVAR_HURT_CONTAINER_DEFAULT) {
gSaveContext.healthCapacity = MAX_HEALTH - healthCapacityMod;
} else {
gSaveContext.healthCapacity = STARTING_HEALTH + healthCapacityMod;
}
}
static void RegisterHurtContainer() {
if (GameInteractor::IsSaveLoaded(false)) {
UpdateHurtContainerModeState();
}
COND_HOOK(OnLoadGame, hurtEnabled != CVAR_HURT_CONTAINER_VALUE, [](int32_t) { UpdateHurtContainerModeState(); });
COND_VB_SHOULD(VB_HEARTS_INCREASE_WITH_CONTAINERS, CVAR_HURT_CONTAINER_VALUE, {
*should = false;
gSaveContext.healthCapacity -= FULL_HEART_HEALTH;
gSaveContext.health -= FULL_HEART_HEALTH;
});
}
static RegisterShipInitFunc initFunc(RegisterHurtContainer, { CVAR_HURT_CONTAINER_NAME });
@@ -3,13 +3,12 @@
#include "soh/Enhancements/randomizer/3drando/random.hpp"
#include "soh/Enhancements/randomizer/context.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "soh/Enhancements/mods.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "variables.h"
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
}
static constexpr MirroredWorldMode CVAR_MIRRORED_WORLD_DEFAULT = MIRRORED_WORLD_OFF;
@@ -55,13 +54,7 @@ static bool MirroredWorld_ShouldApply(int32_t sceneNum) {
}
}
static void RegisterMirroredWorld() {
COND_HOOK(OnSceneInit, CVAR_MIRRORED_WORLD_MODE_VALUE, UpdateMirrorModeState);
}
static RegisterShipInitFunc initFunc(RegisterMirroredWorld, { CVAR_MIRRORED_WORLD_MODE_NAME });
void UpdateMirrorModeState(int32_t sceneNum) {
static void UpdateMirrorModeState(int32_t sceneNum) {
bool nextMirroredWorld = MirroredWorld_ShouldApply(sceneNum);
if (prevMirroredWorld == nextMirroredWorld) {
@@ -73,8 +66,17 @@ void UpdateMirrorModeState(int32_t sceneNum) {
CVarSetInteger(CVAR_MIRRORED_WORLD_NAME, 1);
} else {
CVarClear(CVAR_MIRRORED_WORLD_NAME);
RegisterMirroredWorld();
}
ApplyMirrorWorldGfxPatches();
}
static void RegisterMirroredWorld() {
if (gPlayState != NULL) {
UpdateMirrorModeState(gPlayState->sceneNum);
}
COND_HOOK(OnSceneInit, CVAR_MIRRORED_WORLD_MODE_VALUE, UpdateMirrorModeState);
}
static RegisterShipInitFunc initFunc(RegisterMirroredWorld, { CVAR_MIRRORED_WORLD_MODE_NAME });
@@ -17,7 +17,7 @@ static constexpr int32_t CVAR_RUPEE_DASH_INTERVAL_DEFAULT = 5;
#define CVAR_RUPEE_DASH_INTERVAL_TIME \
CVarGetInteger(CVAR_RUPEE_DASH_INTERVAL_NAME, CVAR_RUPEE_DASH_INTERVAL_DEFAULT) * 20
void UpdateRupeeDash() {
static void UpdateRupeeDash() {
// Initialize Timer
static uint16_t rupeeDashTimer = 0;
@@ -36,7 +36,7 @@ void UpdateRupeeDash() {
}
}
void RegisterRupeeDash() {
static void RegisterRupeeDash() {
COND_HOOK(OnPlayerUpdate, CVAR_RUPEE_DASH_VALUE, UpdateRupeeDash);
}
@@ -16,7 +16,7 @@ static constexpr s8 ROOM_GREEN_POE = 16;
static constexpr s8 ROOM_BLUE_POE = 13;
static constexpr s8 ROOM_RED_POE = 12;
void OnPlayerUpdateShadowTag() {
static void OnPlayerUpdateShadowTag() {
if (gPlayState->sceneNum == SCENE_FOREST_TEMPLE) {
switch (gPlayState->roomCtx.curRoom.num) {
case ROOM_GREEN_POE:
@@ -36,12 +36,12 @@ void OnPlayerUpdateShadowTag() {
}
}
void ResetShadowTagSpawnTimer() {
static void ResetShadowTagSpawnTimer() {
shouldSpawn = true;
delayTimer = 60;
}
void RegisterShadowTag() {
static void RegisterShadowTag() {
COND_HOOK(OnPlayerUpdate, CVAR_SHADOW_TAG_VALUE, OnPlayerUpdateShadowTag);
COND_HOOK(OnSceneSpawnActors, true, []() { ResetShadowTagSpawnTimer(); });
COND_HOOK(OnSceneInit, true, [](int16_t) { ResetShadowTagSpawnTimer(); });
@@ -13,7 +13,7 @@ static constexpr int32_t CVAR_BGS_FIX_DEFAULT = 0;
#define CVAR_BGS_FIX_NAME CVAR_ENHANCEMENT("FixBrokenGiantsKnife")
#define CVAR_BGS_FIX_VALUE CVarGetInteger(CVAR_BGS_FIX_NAME, CVAR_BGS_FIX_DEFAULT)
void OnReceiveBrokenGiantsKnife(GetItemEntry itemEntry) {
static void OnReceiveBrokenGiantsKnife(GetItemEntry itemEntry) {
if (itemEntry.itemId != ITEM_SWORD_BGS) {
return;
}
@@ -39,7 +39,7 @@ void OnReceiveBrokenGiantsKnife(GetItemEntry itemEntry) {
}
}
void RegisterBrokenGiantsKnifeFix() {
static void RegisterBrokenGiantsKnifeFix() {
// If enhancement is off, flag should be handled exclusively by vanilla behaviour
COND_HOOK(OnItemReceive, CVAR_BGS_FIX_VALUE || IS_RANDO, OnReceiveBrokenGiantsKnife);
}
@@ -13,7 +13,7 @@ static constexpr int32_t CVAR_NUT_UPGRADE_FIX_DEFAULT = 0;
#define CVAR_NUT_UPGRADE_FIX_NAME CVAR_ENHANCEMENT("DekuNutUpgradeFix")
#define CVAR_NUT_UPGRADE_FIX_VALUE CVarGetInteger(CVAR_NUT_UPGRADE_FIX_NAME, CVAR_NUT_UPGRADE_FIX_DEFAULT)
void DekuNutUpgradeFixAtForestStage(bool* should) {
static void DekuNutUpgradeFixAtForestStage(bool* should) {
// This check is needed because of an intentional fallthrough at the source
if (Player_GetMask(gPlayState) == PLAYER_MASK_SKULL) {
return;
@@ -30,11 +30,11 @@ void DekuNutUpgradeFixAtForestStage(bool* should) {
}
}
void DekuNutUpgradeSetByPoachersSaw(bool* should) {
static void DekuNutUpgradeSetByPoachersSaw(bool* should) {
*should = false;
}
void RegisterDekuNutUpgradeFix() {
static void RegisterDekuNutUpgradeFix() {
COND_VB_SHOULD(VB_POACHERS_SAW_SET_DEKU_NUT_UPGRADE_FLAG, CVAR_NUT_UPGRADE_FIX_VALUE || IS_RANDO,
{ DekuNutUpgradeSetByPoachersSaw(should); });
COND_VB_SHOULD(VB_DEKU_SCRUBS_REACT_TO_MASK_OF_TRUTH, CVAR_NUT_UPGRADE_FIX_VALUE && !IS_RANDO,
+7 -2
View File
@@ -1,13 +1,14 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "soh/Enhancements/mods.h"
#include "soh/ShipInit.hpp"
extern "C" PlayState* gPlayState;
static constexpr ZFightingFixType CVAR_DIRT_PATH_DEFAULT = ZFIGHT_FIX_DISABLED;
#define CVAR_DIRT_PATH_NAME CVAR_ENHANCEMENT("SceneSpecificDirtPathFix")
#define CVAR_DIRT_PATH_VALUE CVarGetInteger(CVAR_DIRT_PATH_NAME, CVAR_DIRT_PATH_DEFAULT)
void DirtPathFix_UpdateZFightingMode(int32_t sceneNum) {
static void DirtPathFix_UpdateZFightingMode(int32_t sceneNum) {
switch (sceneNum) {
case SCENE_HYRULE_FIELD:
case SCENE_KOKIRI_FOREST:
@@ -20,6 +21,10 @@ void DirtPathFix_UpdateZFightingMode(int32_t sceneNum) {
}
static void RegisterDirtPathFix() {
if (gPlayState != NULL) {
DirtPathFix_UpdateZFightingMode(gPlayState->sceneNum);
}
COND_HOOK(OnTransitionEnd, CVAR_DIRT_PATH_VALUE, DirtPathFix_UpdateZFightingMode);
}
@@ -0,0 +1,38 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "macros.h"
#include "soh/ResourceManagerHelpers.h"
#include "objects/object_link_boy/object_link_boy.h"
extern SaveContext gSaveContext;
}
static constexpr int32_t CVAR_HAMMER_HAND_DEFAULT = 0;
#define CVAR_HAMMER_HAND_NAME CVAR_ENHANCEMENT("FixHammerHand")
#define CVAR_HAMMER_HAND_VALUE CVarGetInteger(CVAR_HAMMER_HAND_NAME, CVAR_HAMMER_HAND_DEFAULT)
static void FixHammerHand() {
if (LINK_IS_ADULT) {
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1", 92,
gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2", 93, gsSPEndDisplayList());
}
}
static void ResetHammerHand() {
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2");
}
static void RegisterHammerHandFix() {
if (CVAR_HAMMER_HAND_VALUE) {
FixHammerHand();
} else {
ResetHammerHand();
}
COND_HOOK(OnSceneInit, CVAR_HAMMER_HAND_VALUE, [](int32_t) { FixHammerHand(); });
}
static RegisterShipInitFunc initFunc(RegisterHammerHandFix, { CVAR_HAMMER_HAND_NAME });
@@ -0,0 +1,86 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "macros.h"
#include "soh/ResourceManagerHelpers.h"
#include "objects/object_link_boy/object_link_boy.h"
#include "objects/object_link_child/object_link_child.h"
extern SaveContext gSaveContext;
}
static constexpr int32_t CVAR_AGE_EQUIPMENT_DEFAULT = 0;
#define CVAR_AGE_EQUIPMENT_NAME CVAR_ENHANCEMENT("EquipmentAlwaysVisible")
#define CVAR_AGE_EQUIPMENT_VALUE CVarGetInteger(CVAR_AGE_EQUIPMENT_NAME, CVAR_AGE_EQUIPMENT_DEFAULT)
static void ResetAdultHands() {
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2");
ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1");
ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2");
}
static void ResetChildHands() {
ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword");
ResourceMgr_UnpatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot");
ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang");
ResourceMgr_UnpatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield");
}
static void MakeEquipmentAlwaysVisible() {
if (LINK_IS_CHILD) {
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1", 92,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2", 93, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1", 84,
gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2", 85,
gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1", 51,
gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2", 52, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1", 104,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2", 105,
gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1", 79,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2", 80, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1", 76,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2", 77,
gsSPEndDisplayList());
ResetChildHands();
} else {
ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword", 13,
gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot", 13,
gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang", 50,
gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield", 49,
gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL));
ResetAdultHands();
}
}
static void RegisterAgeDependentEquipmentHook() {
if (CVAR_AGE_EQUIPMENT_VALUE) {
MakeEquipmentAlwaysVisible();
} else {
ResetAdultHands();
ResetChildHands();
}
COND_HOOK(OnSceneInit, CVAR_AGE_EQUIPMENT_VALUE, [](int32_t) { MakeEquipmentAlwaysVisible(); });
}
static RegisterShipInitFunc initFunc(RegisterAgeDependentEquipmentHook, { CVAR_AGE_EQUIPMENT_NAME });
@@ -1,5 +1,4 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/Enhancements/mods.h"
#include "soh/ShipInit.hpp"
extern "C" {
@@ -102,14 +101,6 @@ static void ResetToTMedallions() {
endGrayscale.RevertPatch();
}
void UpdateToTMedallions() {
if (CVAR_TOT_MEDALLION_COLORS_VALUE) {
PatchToTMedallions();
} else {
ResetToTMedallions();
}
}
static void CheckTempleOfTime(int16_t sceneNum) {
if (sceneNum != SCENE_TEMPLE_OF_TIME) {
return;
@@ -118,6 +109,12 @@ static void CheckTempleOfTime(int16_t sceneNum) {
}
static void RegisterToTMedallions() {
if (CVAR_TOT_MEDALLION_COLORS_VALUE) {
PatchToTMedallions();
} else {
ResetToTMedallions();
}
COND_HOOK(OnItemReceive, CVAR_TOT_MEDALLION_COLORS_VALUE, [](GetItemEntry) {
if (gPlayState) {
CheckTempleOfTime(gPlayState->sceneNum);
+1
View File
@@ -129,6 +129,7 @@ void applyPreset(std::string presetName, std::vector<PresetSection> includeSecti
}
}
ShipInit::InitAll();
OTRGlobals::Instance->ScaleImGui();
}
void DrawPresetSelector(std::vector<PresetSection> includeSections, std::string presetLoc, bool disabled) {
+2 -2
View File
@@ -21,7 +21,7 @@ struct DayTimeGoldSkulltulas {
using DayTimeGoldSkulltulasList = std::vector<DayTimeGoldSkulltulas>;
void OnSpawnNighttimeGoldSkulltula() {
static void OnSpawnNighttimeGoldSkulltula() {
// Gold Skulltulas that are not part of the scene actor list during the day
// Actor values copied from the night time scene actor list
static const DayTimeGoldSkulltulasList dayTimeGoldSkulltulas = {
@@ -62,7 +62,7 @@ void OnSpawnNighttimeGoldSkulltula() {
}
}
void RegisterDaytimeGoldSkultullas() {
static void RegisterDaytimeGoldSkultullas() {
COND_HOOK(OnSceneSpawnActors, CVAR_DAYTIME_GS_VALUE, OnSpawnNighttimeGoldSkulltula);
}
+5 -8
View File
@@ -24,12 +24,10 @@ static constexpr int32_t DOOR_NIGHT_KAK_POTION_SHOP = 7822;
static constexpr int32_t DOOR_NIGHT_KAK_POTION_SHOP_BACK = 8846;
static void OpenAllHours(void* refActor) {
Actor* actor = static_cast<Actor*>(refActor);
if (actor->id != ACTOR_EN_DOOR) {
return;
}
EnDoor* enDoor = static_cast<EnDoor*>(refActor);
s16* params = &enDoor->actor.params;
switch (actor->params) {
switch (*params) {
case DOOR_DAY_CHEST_GAME:
case DOOR_DAY_BOMBCHU_SHOP:
case DOOR_NIGHT_POTION_SHOP:
@@ -40,8 +38,7 @@ static void OpenAllHours(void* refActor) {
case DOOR_NIGHT_KAK_BAZAAR:
case DOOR_NIGHT_KAK_POTION_SHOP:
case DOOR_NIGHT_KAK_POTION_SHOP_BACK: {
actor->params = (actor->params & 0xFC00) | (DOOR_SCENEEXIT << 7) | 0x3F;
EnDoor* enDoor = static_cast<EnDoor*>(refActor);
*params = (*params & 0xFC00) | (DOOR_SCENEEXIT << 7) | 0x3F;
EnDoor_SetupType(enDoor, gPlayState);
break;
}
@@ -54,7 +51,7 @@ static void RegisterOpenAllHours() {
bool overworldDoorsOpen =
!IS_RANDO || !OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LOCK_OVERWORLD_DOORS);
COND_HOOK(OnActorInit, CVAR_OPEN_ALL_HOURS_VALUE && overworldDoorsOpen, OpenAllHours);
COND_ID_HOOK(OnActorInit, ACTOR_EN_DOOR, CVAR_OPEN_ALL_HOURS_VALUE && overworldDoorsOpen, OpenAllHours);
}
static RegisterShipInitFunc initFunc(RegisterOpenAllHours, { CVAR_OPEN_ALL_HOURS_NAME, "IS_RANDO" });
@@ -4,7 +4,6 @@
#include <map>
#include <set>
#include <string>
#include <sstream>
#include <libultraship/libultraship.h>
#include <functions.h>
#include "../randomizer/3drando/random.hpp"
@@ -5,12 +5,11 @@
#include <string>
#include <libultraship/bridge.h>
#include <random>
#include <math.h>
#include <algorithm>
#include <libultraship/libultraship.h>
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohMenu.h"
#include "soh/SohGui/SohGui.hpp"
#include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h"
@@ -22,7 +21,6 @@ extern "C" {
#include "objects/object_link_boy/object_link_boy.h"
#include "objects/object_link_child/object_link_child.h"
#include "objects/object_gi_shield_3/object_gi_shield_3.h"
#include "objects/object_gi_heart/object_gi_heart.h"
#include "objects/object_gi_bow/object_gi_bow.h"
#include "objects/object_gi_bracelet/object_gi_bracelet.h"
#include "objects/object_gi_rupy/object_gi_rupy.h"
@@ -64,6 +62,12 @@ void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
}
static WidgetInfo goronNeck;
namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
}
#define PATCH_GFX(path, name, cvar, index, instruction) \
if (CVarGetInteger(cvar, 0)) { \
ResourceMgr_PatchGfxByName(path, name, index, instruction); \
@@ -2026,15 +2030,7 @@ void DrawSillyTab() {
UIWidgets::Separator(true, true, 2.0f, 2.0f);
UIWidgets::CVarSliderFloat("Goron Neck Length", CVAR_COSMETIC("Goron.NeckLength"),
UIWidgets::FloatSliderOptions()
.Format("%.0f")
.Min(0.0f)
.Max(5000.0f)
.DefaultValue(0.0f)
.Step(10.0f)
.Size(ImVec2(300.0f, 0.0f))
.Color(THEME_COLOR));
SohGui::mSohMenu->MenuDrawItem(goronNeck, ImGui::GetContentRegionAvail().x, THEME_COLOR);
Reset_Option_Single("Reset##Goron_NeckLength", CVAR_COSMETIC("Goron.NeckLength"));
UIWidgets::Separator(true, true, 2.0f, 2.0f);
@@ -2648,22 +2644,6 @@ void RegisterOnGameFrameUpdateHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { CosmeticsUpdateTick(); });
}
void Cosmetics_RegisterOnSceneInitHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](int16_t sceneNum) {
if (CVarGetInteger(CVAR_COSMETIC("RandomizeAllOnNewScene"), 0)) {
CosmeticsEditor_RandomizeAll();
}
});
}
void CosmeticsEditorRegisterOnGenerationCompletionHook() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGenerationCompletion>([]() {
if (CVarGetInteger(CVAR_COSMETIC("RandomizeAllOnRandoGen"), 0)) {
CosmeticsEditor_RandomizeAll();
}
});
}
void CosmeticsEditorWindow::InitElement() {
// Convert the `current color` into the format that the ImGui color picker expects
for (auto& [id, cosmeticOption] : cosmeticOptions) {
@@ -2679,11 +2659,6 @@ void CosmeticsEditorWindow::InitElement() {
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
ApplyOrResetCustomGfxPatches();
ApplyAuthenticGfxPatches();
RegisterOnLoadGameHook();
RegisterOnGameFrameUpdateHook();
Cosmetics_RegisterOnSceneInitHook();
CosmeticsEditorRegisterOnGenerationCompletionHook();
}
void CosmeticsEditor_RandomizeAll() {
@@ -2732,3 +2707,33 @@ void CosmeticsEditor_ResetGroup(CosmeticGroup group) {
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
ApplyOrResetCustomGfxPatches();
}
void RegisterCosmeticHooks() {
COND_HOOK(OnSceneInit, CVarGetInteger(CVAR_COSMETIC("RandomizeAllOnNewScene"), 0),
[](s16 sceneNum) { CosmeticsEditor_RandomizeAll(); });
COND_HOOK(OnGenerationCompletion, CVarGetInteger(CVAR_COSMETIC("RandomizeAllOnRandoGen"), 0),
[]() { CosmeticsEditor_RandomizeAll(); });
COND_HOOK(OnGameFrameUpdate, true, CosmeticsUpdateTick);
}
void RegisterCosmeticWidgets() {
goronNeck = { .name = "Goron Neck Length", .type = WidgetType::WIDGET_CVAR_SLIDER_FLOAT };
goronNeck.CVar(CVAR_COSMETIC("Goron.NeckLength"))
.Options(UIWidgets::FloatSliderOptions()
.Format("%.0f")
.Min(0.0f)
.Max(5000.0f)
.DefaultValue(0.0f)
.Step(10.0f)
.Size(ImVec2(300.0f, 0.0f))
.Color(THEME_COLOR));
SohGui::mSohMenu->AddSearchWidget({ goronNeck, "Enhancements", "Cosmetics Editor", "Silly" });
}
static RegisterShipInitFunc initFunc(RegisterCosmeticHooks, {
CVAR_COSMETIC("RandomizeAllOnNewScene"),
CVAR_COSMETIC("RandomizeAllOnRandoGen"),
});
static RegisterMenuInitFunc menuInitFunc(RegisterCosmeticWidgets);
@@ -1,4 +1,5 @@
#include "hookDebugger.h"
#include "soh/SohGui/SohGui.hpp"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/OTRGlobals.h"
@@ -7,6 +8,9 @@
static std::map<const char*, std::map<HOOK_ID, HookInfo>*> hookData;
static bool hookOptCollapseAll; // A bool that will collapse all hook group once
static bool hookOptExpandAll; // A bool that will expand all hook group once
const ImVec4 grey = ImVec4(0.75, 0.75, 0.75, 1);
const ImVec4 yellow = ImVec4(1, 1, 0, 1);
const ImVec4 red = ImVec4(1, 0, 0, 1);
@@ -77,6 +81,9 @@ void DrawHookRegisteringInfos(const char* hookName) {
}
void HookDebuggerWindow::DrawElement() {
bool collapseLogic = false;
bool doingCollapseOrExpand = hookOptExpandAll || hookOptCollapseAll;
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
#ifndef __cpp_lib_source_location
ImGui::TextColored(yellow, "Some features of the Hook Debugger are unavailable because SoH was compiled "
@@ -84,9 +91,29 @@ void HookDebuggerWindow::DrawElement() {
"(\"__cpp_lib_source_location\" not defined in \"<version>\").");
#endif
if (UIWidgets::Button("Expand All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
hookOptCollapseAll = false;
hookOptExpandAll = true;
}
ImGui::SameLine();
if (UIWidgets::Button("Collapse All",
UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
hookOptExpandAll = false;
hookOptCollapseAll = true;
}
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
for (auto& [hookName, _] : hookData) {
if (doingCollapseOrExpand) {
if (hookOptExpandAll) {
collapseLogic = true;
} else if (hookOptCollapseAll) {
collapseLogic = false;
}
ImGui::SetNextItemOpen(collapseLogic, ImGuiCond_Always);
}
if (ImGui::TreeNode(hookName)) {
DrawHookRegisteringInfos(hookName);
ImGui::TreePop();
@@ -95,9 +122,17 @@ void HookDebuggerWindow::DrawElement() {
ImGui::PopFont();
ImGui::EndDisabled();
if (doingCollapseOrExpand) {
hookOptExpandAll = false;
hookOptCollapseAll = false;
}
}
void HookDebuggerWindow::InitElement() {
hookOptExpandAll = false;
hookOptCollapseAll = false;
#define DEFINE_HOOK(name, _) hookData.insert({ #name, GameInteractor::Instance->GetHookData<GameInteractor::name>() });
#include "../game-interactor/GameInteractor_HookTable.h"
@@ -1,3 +1,6 @@
#ifndef hookDebugger_h
#define hookDebugger_h
#include <libultraship/libultraship.h>
class HookDebuggerWindow final : public Ship::GuiWindow {
@@ -8,3 +11,5 @@ class HookDebuggerWindow final : public Ship::GuiWindow {
void DrawElement() override;
void UpdateElement() override{};
};
#endif // hookDebugger_h
@@ -101,8 +101,10 @@ void UnsetFlag::_Apply() {
GameInteractionEffectQueryResult ModifyHeartContainers::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded(true)) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else if ((parameters[0] > 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) > 0x140)) ||
(parameters[0] < 0 && (gSaveContext.healthCapacity + (parameters[0] * 0x10) < 0x10))) {
} else if ((parameters[0] > 0 &&
(gSaveContext.healthCapacity + (parameters[0] * FULL_HEART_HEALTH) > MAX_HEALTH)) ||
(parameters[0] < 0 &&
(gSaveContext.healthCapacity + (parameters[0] * FULL_HEART_HEALTH) < FULL_HEART_HEALTH))) {
return GameInteractionEffectQueryResult::NotPossible;
}
@@ -28,6 +28,7 @@ DEFINE_HOOK(OnPlayerDeath, ());
DEFINE_HOOK(OnSetDoAction, (uint16_t action));
DEFINE_HOOK(OnPlayerSfx, (u16 sfxId));
DEFINE_HOOK(OnOcarinaSongAction, ());
DEFINE_HOOK(OnOcarinaNote, (uint8_t note, float modulator, int8_t bend));
DEFINE_HOOK(OnCuccoOrChickenHatch, ());
DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
DEFINE_HOOK(OnDungeonKeyUsed, (uint16_t mapIndex));
@@ -110,6 +110,10 @@ void GameInteractor_ExecuteOnOcarinaSongAction() {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnOcarinaSongAction>();
}
void GameInteractor_ExecuteOnOcarinaNote(uint8_t note, float modulator, int8_t bend) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnOcarinaNote>(note, modulator, bend);
}
void GameInteractor_ExecuteOnCuccoOrChickenHatch() {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnCuccoOrChickenHatch>();
}
@@ -31,6 +31,7 @@ void GameInteractor_ExecuteOnPlayerDeath();
void GameInteractor_ExecuteOnSetDoAction(uint16_t action);
void GameInteractor_ExecuteOnPlayerSfx(u16 sfxId);
void GameInteractor_ExecuteOnOcarinaSongAction();
void GameInteractor_ExecuteOnOcarinaNote(uint8_t note, float modulator, int8_t bend);
void GameInteractor_ExecuteOnCuccoOrChickenHatch();
bool GameInteractor_ShouldActorInit(void* actor);
void GameInteractor_ExecuteOnActorInit(void* actor);
@@ -17,7 +17,7 @@ extern PlayState* gPlayState;
#include "overlays/actors/ovl_En_Bom/z_en_bom.h"
void GameInteractor::RawAction::AddOrRemoveHealthContainers(int16_t amount) {
gSaveContext.healthCapacity += amount * 0x10;
gSaveContext.healthCapacity += amount * FULL_HEART_HEALTH;
}
void GameInteractor::RawAction::AddOrRemoveMagic(int8_t amount) {
@@ -46,17 +46,17 @@ void GameInteractor::RawAction::AddOrRemoveMagic(int8_t amount) {
void GameInteractor::RawAction::HealOrDamagePlayer(int16_t hearts) {
if (hearts > 0) {
Health_ChangeBy(gPlayState, hearts * 0x10);
Health_ChangeBy(gPlayState, hearts * FULL_HEART_HEALTH);
} else if (hearts < 0) {
Player* player = GET_PLAYER(gPlayState);
Health_ChangeBy(gPlayState, hearts * 0x10);
Health_ChangeBy(gPlayState, hearts * FULL_HEART_HEALTH);
func_80837C0C(gPlayState, player, 0, 0, 0, 0, 0);
player->invincibilityTimer = 28;
}
}
void GameInteractor::RawAction::SetPlayerHealth(int16_t hearts) {
gSaveContext.health = hearts * 0x10;
gSaveContext.health = hearts * FULL_HEART_HEALTH;
}
void GameInteractor::RawAction::SetLinkInvisibility(bool active) {
@@ -1183,6 +1183,14 @@ typedef enum {
// - None
VB_HEALTH_METER_BE_CRITICAL,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_HEARTS_INCREASE_WITH_CONTAINERS,
// #### `result`
// ```c
// (respawnFlag == 1) || (respawnFlag == -1)
@@ -2343,6 +2351,15 @@ typedef enum {
// - `*BgHidanKowarerukabe`
VB_FIRE_TEMPLE_BOMBABLE_WALL_BREAK,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*Player`
// - `*Color_RGB8`
VB_APPLY_TUNIC_COLOR,
// #### `result`
// ```c
// true
+122 -47
View File
@@ -1,5 +1,7 @@
#include "kaleido.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/frame_interpolation.h"
#include "soh/ShipUtils.h"
@@ -45,7 +47,7 @@ void KaleidoEntryIcon::LoadIconTex(std::vector<Gfx>* mEntryDl) {
}
}
KaleidoEntry::KaleidoEntry(int16_t x, int16_t y, std::string text) : mX(x), mY(y), mText(std::move(text)) {
KaleidoEntry::KaleidoEntry(std::string text) : mText(std::move(text)) {
mHeight = 0;
mWidth = 0;
vtx = nullptr;
@@ -55,7 +57,12 @@ void KaleidoEntry::SetYOffset(int yOffset) {
mY = yOffset;
}
void KaleidoEntry::SetSelected(bool val) {
mSelected = val;
}
void KaleidoEntryIcon::Draw(PlayState* play, std::vector<Gfx>* mEntryDl) {
PauseContext* pauseCtx = &play->pauseCtx;
if (vtx == nullptr) {
return;
}
@@ -74,13 +81,24 @@ void KaleidoEntryIcon::Draw(PlayState* play, std::vector<Gfx>* mEntryDl) {
mEntryDl->push_back(gsSPMatrix(Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW));
// cursor (if selected)
if (mSelected) {
mEntryDl->push_back(gsDPSetPrimColor(0, 0, 255, 255, 255, 255));
mEntryDl->push_back(gsSPVertex(vtx, 4, 0));
Gfx cursorIconTex[] = { gsDPLoadTextureBlock(gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD) };
mEntryDl->insert(mEntryDl->end(), std::begin(cursorIconTex), std::end(cursorIconTex));
mEntryDl->push_back(gsSP1Quadrangle(0, 2, 3, 1, 0));
}
// icon
if (!mAchieved) {
mEntryDl->push_back(gsDPSetGrayscaleColor(109, 109, 109, 255));
mEntryDl->push_back(gsSPGrayscale(true));
}
mEntryDl->push_back(gsDPSetPrimColor(0, 0, mIconColor.r, mIconColor.g, mIconColor.b, mIconColor.a));
mEntryDl->push_back(gsSPVertex(vtx, 4, 0));
mEntryDl->push_back(gsSPVertex(&vtx[4], 4, 0));
LoadIconTex(mEntryDl);
mEntryDl->push_back(gsSP1Quadrangle(0, 2, 3, 1, 0));
mEntryDl->push_back(gsSPGrayscale(false));
@@ -90,10 +108,10 @@ void KaleidoEntryIcon::Draw(PlayState* play, std::vector<Gfx>* mEntryDl) {
for (size_t i = 0, vtxGroup = 0; i < numChar; i++) {
// A maximum of 64 Vtx can be loaded at once by gSPVertex, or basically 16 characters
// handle loading groups of 16 chars at a time until there are no more left to load.
// By this point 4 vertices have already been loaded for the preceding icon.
// By this point 8 vertices have already been loaded for the preceding icon and cursor.
if (i % 16 == 0) {
size_t numVtxToLoad = std::min<size_t>(numChar - i, 16) * 4;
mEntryDl->push_back(gsSPVertex(&vtx[4 + (vtxGroup * 16 * 4)], numVtxToLoad, 0));
mEntryDl->push_back(gsSPVertex(&vtx[8 + (vtxGroup * 16 * 4)], numVtxToLoad, 0));
vtxGroup++;
}
@@ -111,22 +129,29 @@ void KaleidoEntryIcon::Draw(PlayState* play, std::vector<Gfx>* mEntryDl) {
Kaleido::Kaleido() {
const auto ctx = Rando::Context::GetInstance();
int yOffset = 2;
int yOffset = 0;
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
gRupeeCounterIconTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, Color_RGBA8{ 0xC8, 0xFF, 0x64, 255 },
FlagType::FLAG_RANDOMIZER_INF, static_cast<int>(RAND_INF_GREG_FOUND), 0, yOffset, "Greg"));
yOffset += 18;
FlagType::FLAG_RANDOMIZER_INF, static_cast<int>(RAND_INF_GREG_FOUND), "Greg"));
if (ctx->GetOption(RSK_SHUFFLE_FISHING_POLE)) {
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
gItemIconFishingPoleTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 },
FlagType::FLAG_RANDOMIZER_INF, static_cast<int>(RAND_INF_FISHING_POLE_FOUND), "Fishing Pole"));
}
if (ctx->GetOption(RSK_TRIFORCE_HUNT)) {
mEntries.push_back(std::make_shared<KaleidoEntryIconCountRequired>(
gTriforcePieceTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 }, 0, yOffset,
gTriforcePieceTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 },
reinterpret_cast<int*>(&gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected),
ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).Get() + 1,
ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Get() + 1));
yOffset += 18;
}
if (ctx->GetOption(RSK_SKELETON_KEY)) {
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
gSmallKeyCounterIconTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, Color_RGBA8{ 255, 255, 255, 255 },
FlagType::FLAG_RANDOMIZER_INF, static_cast<int>(RAND_INF_HAS_SKELETON_KEY), "Skeleton Key"));
}
if (ctx->GetOption(RSK_SHUFFLE_OCARINA_BUTTONS)) {
mEntries.push_back(std::make_shared<KaleidoEntryOcarinaButtons>(0, yOffset));
yOffset += 18;
mEntries.push_back(std::make_shared<KaleidoEntryOcarinaButtons>());
}
if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).IsNot(RO_BOSS_SOULS_OFF)) {
static const char* bossSoulNames[] = {
@@ -136,15 +161,22 @@ Kaleido::Kaleido() {
for (int i = RAND_INF_GOHMA_SOUL; i < RAND_INF_GANON_SOUL; i++) {
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
gBossSoulTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 },
FlagType::FLAG_RANDOMIZER_INF, i, 0, yOffset, bossSoulNames[i - RAND_INF_GOHMA_SOUL]));
yOffset += 18;
FlagType::FLAG_RANDOMIZER_INF, i, bossSoulNames[i - RAND_INF_GOHMA_SOUL]));
}
}
if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).Is(RO_BOSS_SOULS_ON_PLUS_GANON)) {
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
gBossSoulTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255, 255, 255, 255 },
FlagType::FLAG_RANDOMIZER_INF, RAND_INF_GANON_SOUL, 0, yOffset, "Ganon's Soul"));
yOffset += 18;
FlagType::FLAG_RANDOMIZER_INF, RAND_INF_GANON_SOUL, "Ganon's Soul"));
}
if (ctx->GetOption(RSK_LOCK_OVERWORLD_DOORS)) {
int rg = RG_GUARD_HOUSE_KEY;
for (int i = RAND_INF_GUARD_HOUSE_KEY_OBTAINED; i <= RAND_INF_FISHING_HOLE_KEY_OBTAINED; i += 2, rg++) {
mEntries.push_back(std::make_shared<KaleidoEntryIconFlag>(
gSmallKeyCounterIconTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, Color_RGBA8{ 255, 255, 255, 255 },
FlagType::FLAG_RANDOMIZER_INF, i,
Rando::StaticData::RetrieveItem(static_cast<RandomizerGet>(rg)).GetName().english));
}
}
}
@@ -162,6 +194,7 @@ void Kaleido::Draw(PlayState* play) {
mEntryDl.clear();
OPEN_DISPS(play->state.gfxCtx);
mEntryDl.push_back(gsDPPipeSync());
Gfx_SetupDL_39Opa(play->state.gfxCtx);
Gfx_SetupDL_42Opa(play->state.gfxCtx);
mEntryDl.push_back(gsDPSetCombineMode(G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM));
@@ -179,13 +212,23 @@ void Kaleido::Draw(PlayState* play) {
if (!((pauseCtx->state != 6) || ((pauseCtx->stickRelX == 0) && (pauseCtx->stickRelY == 0)))) {
if (pauseCtx->cursorSpecialPos == 0) {
if ((pauseCtx->stickRelY > 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DUP))) {
if (mTopIndex > 0) {
mTopIndex--;
if (mCursorPos > 0) {
mCursorPos--;
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
if (mCursorPos < mTopIndex) {
mTopIndex = mCursorPos;
shouldScroll = true;
}
} else if ((pauseCtx->stickRelY < -30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DDOWN))) {
if (mTopIndex + mNumVisible < mEntries.size()) {
mTopIndex++;
if (mCursorPos < mEntries.size() - 1) {
mCursorPos++;
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
if (mCursorPos >= mTopIndex + mNumVisible && mTopIndex + mNumVisible < mEntries.size()) {
mTopIndex = mCursorPos - mNumVisible + 1;
shouldScroll = true;
}
}
@@ -213,16 +256,14 @@ void Kaleido::Draw(PlayState* play) {
pauseCtx->cursorSpecialPos = 0;
}
}
int yOffset = 2;
int yOffset = 1;
for (int i = mTopIndex; i < (mTopIndex + mNumVisible) && i < mEntries.size(); i++) {
auto& entry = mEntries[i];
if (shouldScroll) {
entry->SetYOffset(yOffset);
yOffset += 18;
Audio_PlaySoundGeneral(NA_SE_SY_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
entry->SetYOffset(yOffset);
yOffset += 9;
Matrix_Push();
entry->SetSelected((i == mCursorPos) && !(pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_RIGHT ||
pauseCtx->cursorSpecialPos == PAUSE_CURSOR_PAGE_LEFT));
entry->Draw(play, &mEntryDl);
Matrix_Pop();
}
@@ -252,9 +293,9 @@ extern "C" void RandoKaleido_UpdateMiscCollectibles(int16_t inDungeonScene) {
KaleidoEntryIconFlag::KaleidoEntryIconFlag(const char* iconResourceName, int iconFormat, int iconSize, int iconWidth,
int iconHeight, Color_RGBA8 iconColor, FlagType flagType, int flag,
int16_t x, int16_t y, std::string name)
: mFlagType(flagType), mFlag(flag), KaleidoEntryIcon(iconResourceName, iconFormat, iconSize, iconWidth, iconHeight,
iconColor, x, y, std::move(name)) {
std::string name)
: mFlagType(flagType), mFlag(flag),
KaleidoEntryIcon(iconResourceName, iconFormat, iconSize, iconWidth, iconHeight, iconColor, std::move(name)) {
BuildVertices();
}
@@ -264,9 +305,9 @@ void KaleidoEntryIconFlag::Update(PlayState* play) {
KaleidoEntryIconCountRequired::KaleidoEntryIconCountRequired(const char* iconResourceName, int iconFormat, int iconSize,
int iconWidth, int iconHeight, Color_RGBA8 iconColor,
int16_t x, int16_t y, int* watch, int required, int total)
int* watch, int required, int total)
: mWatch(watch), mRequired(required), mTotal(total),
KaleidoEntryIcon(iconResourceName, iconFormat, iconSize, iconWidth, iconHeight, iconColor, x, y) {
KaleidoEntryIcon(iconResourceName, iconFormat, iconSize, iconWidth, iconHeight, iconColor) {
mCount = *mWatch;
BuildText();
BuildVertices();
@@ -287,31 +328,54 @@ void KaleidoEntryIconCountRequired::BuildText() {
void KaleidoEntryIcon::BuildVertices() {
int offsetY = 0;
int offsetX = 0;
// 4 vertices per character, plus one for the preceding icon.
Vtx* vertices = (Vtx*)calloc(sizeof(Vtx[4]), mText.length() + 1);
// 4 vertices per character, plus one for the preceding icon, plus one for the cursor.
Vtx* vertices = (Vtx*)calloc(sizeof(Vtx[4]), mText.length() + 2);
// Vertex for the cursor.
Ship_CreateQuadVertexGroup(vertices, offsetX, offsetY, 16, 24, 0);
offsetX += 18;
// Vertex for the preceding icon.
Ship_CreateQuadVertexGroup(vertices, offsetX, offsetY, mIconWidth, mIconHeight, 0);
Ship_CreateQuadVertexGroup(&vertices[4], offsetX, offsetY, mIconWidth, mIconHeight, 0);
offsetX += 18;
for (size_t i = 0; i < mText.length(); i++) {
int charWidth = static_cast<int>(Ship_GetCharFontWidth(mText[i]));
Ship_CreateQuadVertexGroup(&(vertices)[(i + 1) * 4], offsetX, offsetY, charWidth, 16, 0);
Ship_CreateQuadVertexGroup(&(vertices)[((i + 1) * 4) + 4], offsetX, offsetY, charWidth, 16, 0);
offsetX += charWidth;
}
offsetY += FONT_CHAR_TEX_HEIGHT;
mWidth = static_cast<int16_t>(offsetX);
mHeight = static_cast<int16_t>(offsetY);
// mWidth = static_cast<int16_t>(offsetX);
// mHeight = static_cast<int16_t>(offsetY);
vertices[1].v.ob[0] = 15; // top-right x
vertices[2].v.ob[1] = 15; // bottom-left y
vertices[3].v.ob[0] = 15; // bottom-right x
vertices[3].v.ob[1] = 15; // bottom-right y
vertices[5].v.ob[0] = 32; // top-right x
vertices[6].v.ob[1] = 16; // bottom-left-y
vertices[7].v.ob[0] = 32; // bottom-right x
vertices[7].v.ob[1] = 16; // bottom-right y
for (size_t i = 0; i < mText.length() + 2; i++) {
size_t j = i * 4;
vertices[j].v.ob[0] = vertices[j].v.ob[0] / 2;
vertices[j].v.ob[1] = vertices[j].v.ob[1] / 2;
vertices[j + 1].v.ob[0] = vertices[j + 1].v.ob[0] / 2;
vertices[j + 1].v.ob[1] = vertices[j + 1].v.ob[1] / 2;
vertices[j + 2].v.ob[0] = vertices[j + 2].v.ob[0] / 2;
vertices[j + 2].v.ob[1] = vertices[j + 2].v.ob[1] / 2;
vertices[j + 3].v.ob[0] = vertices[j + 3].v.ob[0] / 2;
vertices[j + 3].v.ob[1] = vertices[j + 3].v.ob[1] / 2;
}
mWidth = static_cast<int16_t>(offsetX / 2);
mHeight = static_cast<int16_t>(8);
vertices[1].v.ob[0] = 16;
vertices[2].v.ob[1] = 16;
vertices[3].v.ob[0] = 16;
vertices[3].v.ob[1] = 16;
vtx = vertices;
}
KaleidoEntryIcon::KaleidoEntryIcon(const char* iconResourceName, int iconFormat, int iconSize, int iconWidth,
int iconHeight, Color_RGBA8 iconColor, int16_t x, int16_t y, std::string text)
int iconHeight, Color_RGBA8 iconColor, std::string text)
: mIconResourceName(iconResourceName), mIconFormat(iconFormat), mIconSize(iconSize), mIconWidth(iconWidth),
mIconHeight(iconHeight), mIconColor(iconColor), KaleidoEntry(x, y, std::move(text)) {
mIconHeight(iconHeight), mIconColor(iconColor), KaleidoEntry(std::move(text)) {
}
void KaleidoEntryIcon::RebuildVertices() {
@@ -329,9 +393,9 @@ void KaleidoEntryIconCountRequired::Update(PlayState* play) {
}
}
KaleidoEntryOcarinaButtons::KaleidoEntryOcarinaButtons(int16_t x, int16_t y)
KaleidoEntryOcarinaButtons::KaleidoEntryOcarinaButtons()
: KaleidoEntryIcon(gItemIconOcarinaOfTimeTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32,
Color_RGBA8{ 255, 255, 255, 255 }, x, y, "\x9F\xA5\xA6\xA7\xA8") {
Color_RGBA8{ 255, 255, 255, 255 }, "\x9F\xA5\xA6\xA7\xA8") {
CalculateColors();
BuildVertices();
}
@@ -405,13 +469,24 @@ void KaleidoEntryOcarinaButtons::Draw(PlayState* play, std::vector<Gfx>* mEntryD
mEntryDl->push_back(gsSPMatrix(Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW));
// cursor (if selected)
if (mSelected) {
mEntryDl->push_back(gsDPSetPrimColor(0, 0, 255, 255, 255, 255));
mEntryDl->push_back(gsSPVertex(vtx, 4, 0));
Gfx cursorIconTex[] = { gsDPLoadTextureBlock(gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK,
G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD) };
mEntryDl->insert(mEntryDl->end(), std::begin(cursorIconTex), std::end(cursorIconTex));
mEntryDl->push_back(gsSP1Quadrangle(0, 2, 3, 1, 0));
}
// icon
if (!mAchieved) {
mEntryDl->push_back(gsDPSetGrayscaleColor(109, 109, 109, 255));
mEntryDl->push_back(gsSPGrayscale(true));
}
mEntryDl->push_back(gsDPSetPrimColor(0, 0, mIconColor.r, mIconColor.g, mIconColor.b, mIconColor.a));
mEntryDl->push_back(gsSPVertex(vtx, 4, 0));
mEntryDl->push_back(gsSPVertex(&vtx[4], 4, 0));
LoadIconTex(mEntryDl);
mEntryDl->push_back(gsSP1Quadrangle(0, 2, 3, 1, 0));
mEntryDl->push_back(gsSPGrayscale(false));
@@ -426,7 +501,7 @@ void KaleidoEntryOcarinaButtons::Draw(PlayState* play, std::vector<Gfx>* mEntryD
// By this point 4 vertices have already been loaded for the preceding icon.
if (i % 16 == 0) {
size_t numVtxToLoad = std::min<size_t>(numChar - i, 16) * 4;
mEntryDl->push_back(gsSPVertex(&vtx[4 + (vtxGroup * 16 * 4)], numVtxToLoad, 0));
mEntryDl->push_back(gsSPVertex(&vtx[8 + (vtxGroup * 16 * 4)], numVtxToLoad, 0));
vtxGroup++;
}
+11 -10
View File
@@ -26,18 +26,20 @@ class KaleidoEntry {
* @param text the initial value of the line of text. Can be omitted for an
* empty string.
*/
KaleidoEntry(int16_t x, int16_t y, std::string text = "");
KaleidoEntry(std::string text = "");
virtual void Draw(PlayState* play, std::vector<Gfx>* mEntryDl) = 0;
virtual void Update(PlayState* play) = 0;
void SetYOffset(int yOffset);
void SetSelected(bool val);
protected:
int16_t mX;
int16_t mY;
int16_t mX = 0;
int16_t mY = 0;
int16_t mHeight;
int16_t mWidth;
Vtx* vtx;
std::string mText;
bool mSelected = false;
bool mAchieved = false;
};
@@ -59,7 +61,7 @@ class KaleidoEntryIcon : public KaleidoEntry {
* @param text text to draw to the right of the icon.
*/
KaleidoEntryIcon(const char* iconResourceName, int iconFormat, int iconSize, int iconWidth, int iconHeight,
Color_RGBA8 iconColor, int16_t x, int16_t y, std::string text = "");
Color_RGBA8 iconColor, std::string text = "");
void Draw(PlayState* play, std::vector<Gfx>* mEntryDl) override;
void RebuildVertices();
@@ -95,8 +97,7 @@ class KaleidoEntryIconFlag : public KaleidoEntryIcon {
* @param mName name to draw to the right of the icon. Leave blank to omit.
*/
KaleidoEntryIconFlag(const char* iconResourceName, int iconFormat, int iconSize, int iconWidth, int iconHeight,
Color_RGBA8 iconColor, FlagType flagType, int flag, int16_t x, int16_t y,
std::string name = "");
Color_RGBA8 iconColor, FlagType flagType, int flag, std::string name = "");
void Update(PlayState* play) override;
private:
@@ -128,8 +129,7 @@ class KaleidoEntryIconCountRequired : public KaleidoEntryIcon {
* @param total The amount of this collectible available in the seed. Set to 0 to not render.
*/
KaleidoEntryIconCountRequired(const char* iconResourceName, int iconFormat, int iconSize, int iconWidth,
int iconHeight, Color_RGBA8 iconColor, int16_t x, int16_t y, int* watch,
int required = 0, int total = 0);
int iconHeight, Color_RGBA8 iconColor, int* watch, int required = 0, int total = 0);
void Update(PlayState* play) override;
private:
@@ -143,7 +143,7 @@ class KaleidoEntryIconCountRequired : public KaleidoEntryIcon {
class KaleidoEntryOcarinaButtons : public KaleidoEntryIcon {
public:
KaleidoEntryOcarinaButtons(int16_t x, int16_t y);
KaleidoEntryOcarinaButtons();
void Update(PlayState* play) override;
void Draw(PlayState* play, std::vector<Gfx>* mEntryDl) override;
@@ -164,7 +164,8 @@ class Kaleido {
std::vector<std::shared_ptr<KaleidoEntry>> mEntries;
std::vector<Gfx> mEntryDl;
int mTopIndex = 0;
int mNumVisible = 7;
int mCursorPos = 0;
int mNumVisible = 14;
};
} // namespace Rando
-123
View File
@@ -27,8 +27,6 @@
#include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
#include "src/overlays/actors/ovl_Door_Gerudo/z_door_gerudo.h"
#include "src/overlays/actors/ovl_En_Elf/z_en_elf.h"
#include "objects/object_link_boy/object_link_boy.h"
#include "objects/object_link_child/object_link_child.h"
#include "soh_assets.h"
#include "kaleido.h"
@@ -203,102 +201,6 @@ void RegisterHyperBosses() {
[](int16_t fileNum) { UpdateHyperBossesState(); });
}
void UpdateHyperEnemiesState() {
static uint32_t actorUpdateHookId = 0;
if (actorUpdateHookId != 0) {
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorUpdate>(actorUpdateHookId);
actorUpdateHookId = 0;
}
if (CVarGetInteger(CVAR_ENHANCEMENT("HyperEnemies"), 0)) {
actorUpdateHookId =
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorUpdate>([](void* refActor) {
// Run the update function a second time to make enemies and minibosses move and act twice as fast.
Player* player = GET_PLAYER(gPlayState);
Actor* actor = static_cast<Actor*>(refActor);
// Some enemies are not in the ACTORCAT_ENEMY category, and some are that aren't really enemies.
bool isEnemy = actor->category == ACTORCAT_ENEMY || actor->id == ACTOR_EN_TORCH2;
bool isExcludedEnemy = actor->id == ACTOR_EN_FIRE_ROCK || actor->id == ACTOR_EN_ENCOUNT2;
// Don't apply during cutscenes because it causes weird behaviour and/or crashes on some cutscenes.
if (CVarGetInteger(CVAR_ENHANCEMENT("HyperEnemies"), 0) && isEnemy && !isExcludedEnemy &&
!Player_InBlockingCsMode(gPlayState, player)) {
GameInteractor::RawAction::UpdateActor(actor);
}
});
}
}
void UpdatePatchHand() {
if ((CVarGetInteger(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"), 0)) && LINK_IS_CHILD) {
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1", 92,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2", 93, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1", 84,
gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2", 85,
gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1", 51,
gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2", 52, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1", 104,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2", 105,
gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1", 79,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2", 80, gsSPEndDisplayList());
ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1", 76,
gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2", 77,
gsSPEndDisplayList());
} else {
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1");
ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2");
ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1");
ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2");
}
if ((CVarGetInteger(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"), 0)) && LINK_IS_ADULT) {
ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword", 13,
gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot", 13,
gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang", 50,
gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield", 49,
gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL));
} else {
ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword");
ResourceMgr_UnpatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot");
ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang");
ResourceMgr_UnpatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield");
}
if (CVarGetInteger("gEnhancements.FixHammerHand", 0) && LINK_IS_ADULT) {
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1", 92,
gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL));
ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2", 93, gsSPEndDisplayList());
} else {
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1");
ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2");
}
}
void RegisterPatchHandHandler() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>(
[](int32_t sceneNum) { UpdatePatchHand(); });
}
// this map is used for enemies that can be uniquely identified by their id
// and that are always counted
// enemies that can't be uniquely identified by their id
@@ -489,28 +391,6 @@ void RegisterEnemyDefeatCounts() {
});
}
void UpdateHurtContainerModeState(bool newState) {
static bool hurtEnabled = false;
if (hurtEnabled == newState) {
return;
}
hurtEnabled = newState;
uint16_t getHeartPieces = gSaveContext.ship.stats.heartPieces / 4;
uint16_t getHeartContainers = gSaveContext.ship.stats.heartContainers;
if (hurtEnabled) {
gSaveContext.healthCapacity = 320 - ((getHeartPieces + getHeartContainers) * 16);
} else {
gSaveContext.healthCapacity = 48 + ((getHeartPieces + getHeartContainers) * 16);
}
}
void RegisterHurtContainerModeHandler() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>(
[](int32_t fileNum) { UpdateHurtContainerModeState(CVarGetInteger(CVAR_ENHANCEMENT("HurtContainer"), 0)); });
}
void RegisterRandomizedEnemySizes() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](void* refActor) {
// Randomized Enemy Sizes
@@ -652,10 +532,7 @@ void InitMods() {
RegisterTTS();
RegisterOcarinaTimeTravel();
RegisterHyperBosses();
UpdateHyperEnemiesState();
RegisterEnemyDefeatCounts();
RegisterRandomizedEnemySizes();
RegisterPatchHandHandler();
RegisterHurtContainerModeHandler();
RandoKaleido_RegisterHooks();
}
-7
View File
@@ -7,15 +7,8 @@
extern "C" {
#endif
void DirtPathFix_UpdateZFightingMode(int32_t sceneNum);
void UpdateMirrorModeState(int32_t sceneNum);
void UpdateHurtContainerModeState(bool newState);
void UpdateToTMedallions();
void UpdatePermanentHeartLossState();
void UpdateHyperEnemiesState();
void UpdateHyperBossesState();
void InitMods();
void UpdatePatchHand();
void SwitchAge();
#ifdef __cplusplus
@@ -486,11 +486,11 @@ void RandomizerOnItemReceiveHandler(GetItemEntry receivedItemEntry) {
if (receivedItemEntry.modIndex == MOD_NONE &&
(receivedItemEntry.itemId == ITEM_HEART_PIECE || receivedItemEntry.itemId == ITEM_HEART_PIECE_2 ||
receivedItemEntry.itemId == ITEM_HEART_CONTAINER)) {
gSaveContext.healthAccumulator = 0x140; // Refill 20 hearts
gSaveContext.healthAccumulator = MAX_HEALTH; // Refill 20 hearts
if ((s32)(gSaveContext.inventory.questItems & 0xF0000000) == 0x40000000) {
gSaveContext.inventory.questItems ^= 0x40000000;
gSaveContext.healthCapacity += 0x10;
gSaveContext.health += 0x10;
gSaveContext.healthCapacity += FULL_HEART_HEALTH;
gSaveContext.health += FULL_HEART_HEALTH;
}
}
@@ -1723,12 +1723,6 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
}
break;
}
case VB_RENDER_KEY_COUNTER: {
if (Flags_GetRandomizerInf(RAND_INF_HAS_SKELETON_KEY)) {
*should = false;
}
break;
}
case VB_RENDER_RUPEE_COUNTER: {
if (!Flags_GetRandomizerInf(RAND_INF_HAS_WALLET) || Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY)) {
*should = false;
@@ -25,6 +25,7 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_LOBBY] = Region("Dodongos Cavern Lobby", SCENE_DODONGOS_CAVERN, {
//Events
EventAccess(LOGIC_GOSSIP_STONE_FAIRY, []{return (Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls();}) || logic->HasItem(RG_GORONS_BRACELET)) && logic->CallGossipFairy();}),
EventAccess(LOGIC_DC_EYES_LIT, []{return ctx->GetTrickOption(RT_DC_EYES_CHU) && logic->CanUse(RG_BOMBCHU_5);}),
}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MAP_CHEST, logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);),
@@ -282,7 +283,10 @@ void RegionTable_Init_DodongosCavern() {
Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return Here(RR_DODONGOS_CAVERN_MQ_BEGINNING, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);});}),
});
areaTable[RR_DODONGOS_CAVERN_MQ_LOBBY] = Region("Dodongos Cavern MQ Lobby", SCENE_DODONGOS_CAVERN, {}, {
areaTable[RR_DODONGOS_CAVERN_MQ_LOBBY] = Region("Dodongos Cavern MQ Lobby", SCENE_DODONGOS_CAVERN, {
//Events
EventAccess(LOGIC_DC_EYES_LIT, []{return ctx->GetTrickOption(RT_DC_EYES_CHU) && logic->CanUse(RG_BOMBCHU_5);}),
}, {
//Locations
LOCATION(RC_DODONGOS_CAVERN_MQ_MAP_CHEST, logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET)),
LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, logic->CanStunDeku()),
@@ -20,19 +20,29 @@ void RegionTable_Init_GerudoTrainingGround() {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, logic->CanHitEyeTargets()),
LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST, logic->CanHitEyeTargets()),
LOCATION(RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true)),
LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST, logic->CanKillEnemy(RE_BEAMOS) && logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true)),
LOCATION(RC_GERUDO_TRAINING_GROUND_ENTRANCE_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)),
LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_SOUTH_HEART, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_EAST_HEART, true),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true) && (logic->CanUse(RG_HOOKSHOT) || ctx->GetTrickOption(RT_GTG_WITHOUT_HOOKSHOT));}),
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return logic->CanKillEnemy(RE_BEAMOS) && logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true);});}),
Entrance(RR_GERUDO_TRAINING_GROUND_SAND_ROOM, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_DINALFOS, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_SAND_ROOM] = Region("Gerudo Training Ground Sand Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_BOULDER_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_SAND_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);});}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_BOULDER_ROOM] = Region("Gerudo Training Ground Boulder Room", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
Entrance(RR_GERUDO_TRAINING_GROUND_SAND_ROOM, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_BOULDER_ROOM, []{return logic->CanUse(logic->IsAdult ? RG_HOOKSHOT : RG_LONGSHOT) || ctx->GetTrickOption(RT_GTG_WITHOUT_HOOKSHOT);});}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE] = Region("Gerudo Training Ground Central Maze", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST, logic->SmallKeys(SCENE_GERUDO_TRAINING_GROUND, 3) && (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH))),
@@ -42,6 +52,7 @@ void RegionTable_Init_GerudoTrainingGround() {
LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST, logic->SmallKeys(SCENE_GERUDO_TRAINING_GROUND, 9)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT, []{return logic->SmallKeys(SCENE_GERUDO_TRAINING_GROUND, 9);}),
});
@@ -52,17 +63,74 @@ void RegionTable_Init_GerudoTrainingGround() {
LOCATION(RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY, true),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, []{return logic->CanUse(RG_HOOKSHOT);}),
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM_UPPER_LEDGE, []{return logic->CanUse(RG_HOOKSHOT);}),
Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE, []{return logic->SmallKeys(SCENE_GERUDO_TRAINING_GROUND, 9);}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_LAVA_ROOM] = Region("Gerudo Training Ground Lava Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
areaTable[RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM] = Region("Gerudo Training Ground Heavy Block Room", SCENE_GERUDO_TRAINING_GROUND, {
//Events
EventAccess(LOGIC_GTG_PUSHED_HEAVY_BLOCK, []{return logic->CanUse(RG_SILVER_GAUNTLETS);}),
}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24),
LOCATION(RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_WOLFOS, ED_CLOSE, true, 4, true)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT, []{return logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild;}),
Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, []{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_HOOKSHOT));}),
Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM_UPPER, []{return (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || (logic->IsAdult && logic->CanGroundJump()));}),
Entrance(RR_GERUDO_TRAINING_GROUND_BEHIND_HEAVY_BLOCK, []{return logic->Get(LOGIC_GTG_PUSHED_HEAVY_BLOCK);}),
Entrance(RR_GERUDO_TRAINING_GROUND_BOULDER_ROOM, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM_UPPER] = Region("Gerudo Training Ground Heavy Block Room Upper", SCENE_GERUDO_TRAINING_GROUND, {
//Events
EventAccess(LOGIC_GTG_UNLOCKED_DOOR_BEHIND_HEAVY_BLOCK, []{return true;}),
}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM, []{return ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH);}),
Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_BEHIND_HEAVY_BLOCK] = Region("Gerudo Training Ground Behind Heavy Block", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM, []{return logic->Get(LOGIC_GTG_PUSHED_HEAVY_BLOCK);}),
Entrance(RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM, []{return logic->Get(LOGIC_GTG_UNLOCKED_DOOR_BEHIND_HEAVY_BLOCK);}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM] = Region("Gerudo Training Ground Like Like Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST, logic->CanKillEnemy(RE_LIKE_LIKE)),
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST, logic->CanKillEnemy(RE_LIKE_LIKE)),
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST, (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanPassEnemy(RE_LIKE_LIKE)),
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST, true),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_BEHIND_HEAVY_BLOCK, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER] = Region("Gerudo Training Ground Eye Statue Upper", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM_UPPER, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_ABOVE_MAZE, []{return logic->Get(LOGIC_GTG_CLEARED_EYE_STATUE);}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_ABOVE_MAZE] = Region("Gerudo Training Ground Above Eye", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST, true),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER] = Region("Gerudo Training Ground Eye Statue Lower", SCENE_GERUDO_TRAINING_GROUND, {
//Events
EventAccess(LOGIC_GTG_CLEARED_EYE_STATUE, []{return logic->CanUse(RG_FAIRY_BOW);}),
}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST, logic->Get(LOGIC_GTG_CLEARED_EYE_STATUE)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM] = Region("Gerudo Training Ground Hammer Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
@@ -75,39 +143,43 @@ void RegionTable_Init_GerudoTrainingGround() {
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER] = Region("Gerudo Training Ground Eye Statue Lower", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)),
}, {
areaTable[RR_GERUDO_TRAINING_GROUND_LAVA_ROOM] = Region("Gerudo Training Ground Lava Room", SCENE_GERUDO_TRAINING_GROUND, {
EventAccess(LOGIC_GTG_PLATFORM_SILVER_RUPEES, []{return logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME));}),
}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_DINALFOS, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT, []{return logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild;}),
// possible to make across with adult's rolling jump, only requiring hookshot
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM_UPPER_LEDGE, []{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME)));}),
Entrance(RR_GERUDO_TRAINING_GROUND_UNDERWATER, []{return logic->Get(LOGIC_GTG_PLATFORM_SILVER_RUPEES);}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_LAVA_ROOM_UPPER_LEDGE] = Region("Gerudo Training Ground Lava Room", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
//Exits
// possible to make across with as adult's rolling jump, no hookshot necessary
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME);}),
Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER] = Region("Gerudo Training Ground Eye Statue Upper", SCENE_GERUDO_TRAINING_GROUND, {}, {
areaTable[RR_GERUDO_TRAINING_GROUND_UNDERWATER] = Region("Gerudo Training Ground Underwater", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST, logic->CanUse(RG_FAIRY_BOW)),
LOCATION(RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST, logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_BRONZE_SCALE) && logic->WaterTimer() >= 24),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM] = Region("Gerudo Training Ground Heavy Block Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
areaTable[RR_GERUDO_TRAINING_GROUND_DINALFOS] = Region("Gerudo Training Dinalfos", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_WOLFOS, ED_CLOSE, true, 4, true)),
LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST, logic->CanKillEnemy(RE_BEAMOS) && logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true)),
LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_SOUTH_HEART, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_EAST_HEART, true),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER, []{return (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanGroundJump()));}),
Entrance(RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM, []{return (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanGroundJump())) && logic->CanUse(RG_SILVER_GAUNTLETS);}),
Entrance(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_DINALFOS, []{return logic->CanKillEnemy(RE_BEAMOS) && logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true);});}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM] = Region("Gerudo Training Ground Like Like Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST, logic->CanJumpslashExceptHammer()),
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST, logic->CanJumpslashExceptHammer()),
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST, logic->CanJumpslashExceptHammer()),
LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST, logic->CanJumpslashExceptHammer()),
}, {});
#pragma endregion
#pragma region MQ
@@ -116,8 +188,6 @@ void RegionTable_Init_GerudoTrainingGround() {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_1, logic->CanBreakPots()),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_2, logic->CanBreakPots()),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_POT_1, logic->CanBreakPots()),
@@ -125,19 +195,21 @@ void RegionTable_Init_GerudoTrainingGround() {
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM, []{return ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK, []{return logic->SmallKeys(SCENE_GERUDO_TRAINING_GROUND, 1);}),
//It's possible to use the torch in RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM with flame storage to light these
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_BY_LOBBY, []{return true;}),
//It's possible to use the torch in hidden room of maze with flame storage to light these
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return logic->HasFireSource();});}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT));});}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return logic->CanHitEyeTargets();});}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM] = Region("Gerudo Training Ground MQ Maze Hidden Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_BY_LOBBY] = Region("Gerudo Training Ground MQ Maze By Lobby", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, true),
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK, []{return logic->SmallKeys(SCENE_GERUDO_TRAINING_GROUND, 1);}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK] = Region("Gerudo Training Ground MQ Maze First Lock", SCENE_GERUDO_TRAINING_GROUND, {}, {
@@ -166,34 +238,44 @@ void RegionTable_Init_GerudoTrainingGround() {
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, logic->CanKillEnemy(RE_IRON_KNUCKLE)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_BOULDER_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE] = Region("Gerudo Training Ground MQ Left Side", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_BOULDER_ROOM] = Region("Gerudo Training Ground MQ Left Side", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, []{return logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_GTG_MQ_WITHOUT_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanJumpslash() && logic->CanUse(RG_HOOKSHOT));});}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_BOULDER_ROOM, []{return logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_GTG_MQ_WITHOUT_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanJumpslash() && logic->CanUse(RG_HOOKSHOT));});}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM] = Region("Gerudo Training Ground MQ Stalfos Room", SCENE_GERUDO_TRAINING_GROUND, {
//Events
EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return true;}),
EventAccess(LOGIC_BLUE_FIRE_ACCESS, []{return true;}),
EventAccess(LOGIC_GTG_UNLOCKED_DOOR_BEHIND_HEAVY_BLOCK, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);});}),
EventAccess(LOGIC_GTG_PUSHED_HEAVY_BLOCK, []{return logic->CanUse(RG_SILVER_GAUNTLETS) && logic->CanAvoidEnemy(RE_STALFOS, true, 2);}),
}, {
//Locations
//implies logic->CanKillEnemy(RE_BIG_SKULLTULA)
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true)),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && logic->CanUse(RG_SILVER_GAUNTLETS);}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return logic->IsAdult && Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && (ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->BlueFire() && logic->IsAdult && (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanGroundJump());}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_BOULDER_ROOM, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK, []{return logic->Get(LOGIC_GTG_PUSHED_HEAVY_BLOCK);}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return logic->IsAdult && Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && (ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || (logic->IsAdult && logic->CanGroundJump()));}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK] = Region("Gerudo Training Ground MQ Behind Block", SCENE_GERUDO_TRAINING_GROUND, {}, {
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK] = Region("Gerudo Training Ground MQ Behind Block", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->Get(LOGIC_GTG_PUSHED_HEAVY_BLOCK);}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_ROOM_BEHIND_BLOCK, []{return logic->Get(LOGIC_GTG_UNLOCKED_DOOR_BEHIND_HEAVY_BLOCK);}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_ROOM_BEHIND_BLOCK] = Region("Gerudo Training Ground MQ Room Behind Block", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
//implies logic->CanKillEnemy(RE_SPIKE)
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_FREEZARD)),
}, {});
}, {
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_ROOM_BEHIND_BLOCK, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE] = Region("Gerudo Training Ground MQ Statue Room Ledge", SCENE_GERUDO_TRAINING_GROUND, {}, {}, {
//Exits
@@ -211,7 +293,7 @@ void RegionTable_Init_GerudoTrainingGround() {
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return true;}),
});
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM] = Region("Gerudo Training Ground MQ Statue ROom", SCENE_GERUDO_TRAINING_GROUND, {}, {
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM] = Region("Gerudo Training Ground MQ Statue Room", SCENE_GERUDO_TRAINING_GROUND, {}, {
//Locations
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)),
}, {
@@ -241,6 +323,7 @@ void RegionTable_Init_GerudoTrainingGround() {
//the fire bubble here is a jerk if you are aiming for the nearest hook platform, you have to aim to the right hand side with hook to dodge it
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, []{return logic->CanUse(RG_LONGSHOT) || (logic->Get(LOGIC_GTG_PLATFORM_SILVER_RUPEES) && logic->CanUse(RG_HOOKSHOT)) || ((logic->CanUse(RG_FIRE_ARROWS) && logic->Get(LOGIC_GTG_PLATFORM_SILVER_RUPEES)) && logic->CanUse(RG_HOVER_BOOTS));}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT, []{return logic->Get(LOGIC_GTG_MQ_RIGHT_SIDE_SWITCH) && logic->CanUse(RG_LONGSHOT);}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM, []{return true;}),
});
//this region exists to place silver rupee items on later, normally it's all on fire and cannot be stood on without access from another area
@@ -312,16 +395,17 @@ void RegionTable_Init_GerudoTrainingGround() {
areaTable[RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM] = Region("Gerudo Training Ground MQ Dinolfos Room", SCENE_GERUDO_TRAINING_GROUND, {
//Events
//EventAccess(&WallFairy, []{return WallFairy || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}),
//EventAccess(&WallFairy, []{return logic->IsAdult && logic->CanUse(RG_FAIRY_BOW);}),
}, {
//Locations
//implies logic->CanKillEnemy(RE_LIZALFOS and logic->CanKillEnemy(RE_DODONGO)
//is logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true) && logic->CanKillEnemy(RE_ARMOS, ED_CLOSE, true, 1, true) broken down to exclude sticks, as it take too many to clear the room
//is logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true) && logic->CanKillEnemy(RE_ARMOS, ED_CLOSE, true, 1, true) broken down to exclude sticks, as it takes too many to clear the room
//Proper enemy kill room ammo logic is needed to handle this room
//some combinations may be impossible without taking damage, keep an eye out for issues here
LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)))),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}),
Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SIDE_PLATFORMS, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, []{return logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)));});}),
});
@@ -13,7 +13,7 @@ void RegionTable_Init_GerudoFortress() {
}, {
//Locations
LOCATION(RC_GF_OUTSKIRTS_NE_CRATE, (logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD)) && logic->CanBreakCrates()),
LOCATION(RC_GF_OUTSKIRTS_NW_CRATE, logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD)),
LOCATION(RC_GF_OUTSKIRTS_NW_CRATE, (logic->IsChild || logic->CanPassEnemy(RE_GERUDO_GUARD)) && logic->CanBreakCrates()),
}, {
//Exits
Entrance(RR_GV_FORTRESS_SIDE, []{return true;}),
@@ -260,4 +260,4 @@ void RegionTable_Init_GerudoFortress() {
Entrance(RR_GF_NEAR_GROTTO, []{return true;}),
});
}
// clang-format on
// clang-format on
+16 -2
View File
@@ -6074,7 +6074,6 @@ std::map<RandomizerGet, RandomizerInf> randomizerGetToRandInf = {
{ RG_MAGIC_INF, RAND_INF_HAS_INFINITE_MAGIC_METER },
{ RG_BOMBCHU_INF, RAND_INF_HAS_INFINITE_BOMBCHUS },
{ RG_WALLET_INF, RAND_INF_HAS_INFINITE_MONEY },
{ RG_SKELETON_KEY, RAND_INF_HAS_SKELETON_KEY },
{ RG_OCARINA_A_BUTTON, RAND_INF_HAS_OCARINA_A },
{ RG_OCARINA_C_UP_BUTTON, RAND_INF_HAS_OCARINA_C_UP },
{ RG_OCARINA_C_DOWN_BUTTON, RAND_INF_HAS_OCARINA_C_DOWN },
@@ -6280,6 +6279,21 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
}
gSaveContext.inventory.dungeonItems[mapIndex] |= bitmask;
return Return_Item_Entry(giEntry, RG_NONE);
} else if (item == RG_SKELETON_KEY) {
Flags_SetRandomizerInf(RAND_INF_HAS_SKELETON_KEY);
// This isn't technically necessary, because keys will no longer be consumed,
// but for the player's sanity we display that they _have_ keys.
gSaveContext.inventory.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_THIEVES_HIDEOUT] = GERUDO_FORTRESS_SMALL_KEY_MAX;
gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX;
return Return_Item_Entry(giEntry, RG_NONE);
} else if (item >= RG_GUARD_HOUSE_KEY && item <= RG_FISHING_HOLE_KEY) {
Flags_SetRandomizerInf(
@@ -6311,7 +6325,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
case RG_DOUBLE_DEFENSE:
gSaveContext.isDoubleDefenseAcquired = true;
gSaveContext.inventory.defenseHearts = 20;
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
break;
case RG_TYCOON_WALLET:
Inventory_ChangeUpgrade(UPG_WALLET, 3);
@@ -331,6 +331,9 @@ typedef enum {
LOGIC_GTG_MQ_MAZE_SWITCH,
LOGIC_GTG_MQ_RIGHT_SIDE_SWITCH,
LOGIC_GTG_PLATFORM_SILVER_RUPEES,
LOGIC_GTG_UNLOCKED_DOOR_BEHIND_HEAVY_BLOCK,
LOGIC_GTG_PUSHED_HEAVY_BLOCK,
LOGIC_GTG_CLEARED_EYE_STATUE,
LOGIC_SHADOW_TRIAL_FIRST_CHEST,
LOGIC_MAX
} LogicVal;
@@ -1201,23 +1204,32 @@ typedef enum {
RR_ICE_CAVERN_MQ_ABOVE_BEGINNING,
RR_GERUDO_TRAINING_GROUND_LOBBY,
RR_GERUDO_TRAINING_GROUND_SAND_ROOM,
RR_GERUDO_TRAINING_GROUND_BOULDER_ROOM,
RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE,
RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT,
RR_GERUDO_TRAINING_GROUND_LAVA_ROOM,
RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM,
RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER,
RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER,
RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM,
RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM_UPPER,
RR_GERUDO_TRAINING_GROUND_BEHIND_HEAVY_BLOCK,
RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM,
RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER,
RR_GERUDO_TRAINING_GROUND_ABOVE_MAZE,
RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER,
RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM,
RR_GERUDO_TRAINING_GROUND_LAVA_ROOM,
RR_GERUDO_TRAINING_GROUND_LAVA_ROOM_UPPER_LEDGE,
RR_GERUDO_TRAINING_GROUND_UNDERWATER,
RR_GERUDO_TRAINING_GROUND_DINALFOS,
RR_GERUDO_TRAINING_GROUND_MQ_LOBBY,
RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM,
RR_GERUDO_TRAINING_GROUND_MQ_MAZE_BY_LOBBY,
RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK,
RR_GERUDO_TRAINING_GROUND_MQ_MAZE_CENTER,
RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM,
RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE,
RR_GERUDO_TRAINING_GROUND_MQ_BOULDER_ROOM,
RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM,
RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK,
RR_GERUDO_TRAINING_GROUND_MQ_ROOM_BEHIND_BLOCK,
RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE,
RR_GERUDO_TRAINING_GROUND_MQ_MAGENTA_FIRE_ROOM,
RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM,
@@ -3856,6 +3868,7 @@ typedef enum {
RT_DC_MQ_CHILD_EYES,
RT_DC_MQ_ADULT_EYES,
RT_DC_DODONGO_CHU,
RT_DC_EYES_CHU,
RT_JABU_ALCOVE_JUMP_DIVE,
RT_JABU_BOSS_HOVER,
RT_JABU_NEAR_BOSS_RANGED,
@@ -1042,16 +1042,17 @@ void CheckTrackerWindow::DrawElement() {
#else
float headerHeight = 20.0f;
#endif
ImVec2 size = ImGui::GetContentRegionMax();
size.y -= headerHeight;
if (!ImGui::BeginTable("Check Tracker", 1, 0, size)) {
if (!ImGui::BeginTable("Check Tracker", 1, 0)) {
EndFloatWindows();
return;
}
ImGui::TableNextRow(0, headerHeight);
ImGui::SetWindowFontScale(CVarGetFloat(CVAR_TRACKER_CHECK("FontSize"), 1.0f));
ImGui::TableNextRow(0, 0);
ImGui::TableNextColumn();
if (UIWidgets::CVarCheckbox(
if (CVarGetInteger(CVAR_TRACKER_CHECK("HiddenItemsToggleVisible"), 1) &&
UIWidgets::CVarCheckbox(
"Show Hidden Items", CVAR_TRACKER_CHECK("ShowHidden"),
UIWidgets::CheckboxOptions(
{ { .tooltip = "When active, items will show hidden checks by default when updated to this state." } })
@@ -1060,7 +1061,7 @@ void CheckTrackerWindow::DrawElement() {
showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0);
RecalculateAllAreaTotals();
}
if (enableAvailableChecks) {
if (enableAvailableChecks && CVarGetInteger(CVAR_TRACKER_CHECK("AvailableChecksToggleVisible"), 1)) {
if (UIWidgets::CVarCheckbox(
"Only Show Available Checks", CVAR_TRACKER_CHECK("OnlyShowAvailable"),
UIWidgets::CheckboxOptions({ { .tooltip = "When active, unavailable checks will be hidden." } })
@@ -1069,49 +1070,61 @@ void CheckTrackerWindow::DrawElement() {
RecalculateAllAreaTotals();
}
}
UIWidgets::PaddedSeparator();
if (UIWidgets::Button("Expand All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
optCollapseAll = false;
optExpandAll = true;
doAreaScroll = true;
}
ImGui::SameLine();
if (UIWidgets::Button("Collapse All",
UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
optExpandAll = false;
optCollapseAll = true;
}
ImGui::SameLine();
if (UIWidgets::Button("Clear", UIWidgets::ButtonOptions({ { .tooltip = "Clear the search field" } })
.Color(THEME_COLOR)
.Size(UIWidgets::Sizes::Inline))) {
checkSearch.Clear();
UpdateFilters();
doAreaScroll = true;
if (CVarGetInteger(CVAR_TRACKER_CHECK("ExpandCollapseButtonsVisible"), 0)) {
if (UIWidgets::Button(
"Expand All",
UIWidgets::ButtonOptions().Color(THEME_COLOR).Size({ ImGui::GetContentRegionAvail().x / 2 - 6, 0 }))) {
optCollapseAll = false;
optExpandAll = true;
doAreaScroll = true;
}
ImGui::SameLine();
if (UIWidgets::Button(
"Collapse All",
UIWidgets::ButtonOptions().Color(THEME_COLOR).Size({ ImGui::GetContentRegionAvail().x - 6, 0 }))) {
optExpandAll = false;
optCollapseAll = true;
}
}
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (checkSearch.Draw()) {
UpdateFilters();
if (CVarGetInteger(CVAR_TRACKER_CHECK("SearchInputVisible"), 1)) {
if (checkSearch.Draw("", ImGui::GetContentRegionAvail().x - 6)) {
UpdateFilters();
}
std::string checkSearchText = "";
checkSearchText = checkSearch.InputBuf;
checkSearchText.erase(std::remove(checkSearchText.begin(), checkSearchText.end(), ' '), checkSearchText.end());
if (checkSearchText.length() < 1) {
ImGui::SameLine(20.0f);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "Search...");
}
}
UIWidgets::PopStyleCombobox();
ImGui::Separator();
std::ostringstream totalChecksSS;
totalChecksSS << "Total Checks: ";
if (enableAvailableChecks) {
totalChecksSS << totalChecksAvailable << " Available / ";
if (CVarGetInteger(CVAR_TRACKER_CHECK("CheckTotalsVisible"), 1)) {
std::ostringstream totalChecksSS;
totalChecksSS << "";
if (enableAvailableChecks) {
totalChecksSS << totalChecksAvailable << " Available / ";
}
totalChecksSS << totalChecksGotten << " Checked / " << totalChecks << " Total";
ImGui::Text("%s", totalChecksSS.str().c_str());
}
totalChecksSS << totalChecksGotten << " Checked / " << totalChecks << " Total";
ImGui::Text("%s", totalChecksSS.str().c_str());
UIWidgets::PaddedSeparator();
bool headerPresent =
CVarGetInteger(CVAR_TRACKER_CHECK("HiddenItemsToggleVisible"), 1) ||
(enableAvailableChecks && CVarGetInteger(CVAR_TRACKER_CHECK("AvailableChecksToggleVisible"), 1)) ||
CVarGetInteger(CVAR_TRACKER_CHECK("ExpandCollapseButtonsVisible"), 0) ||
CVarGetInteger(CVAR_TRACKER_CHECK("SearchInputVisible"), 1) ||
CVarGetInteger(CVAR_TRACKER_CHECK("CheckTotalsVisible"), 1);
if (headerPresent) {
ImGui::Separator();
}
// Checks Section Lead-in
ImGui::TableNextRow();
ImGui::TableNextColumn();
size = ImGui::GetContentRegionAvail();
if (!ImGui::BeginTable("CheckTracker##Checks", 1, ImGuiTableFlags_ScrollY, size)) {
if (!ImGui::BeginTable("CheckTracker##Checks", 1, ImGuiTableFlags_ScrollY)) {
ImGui::EndTable();
EndFloatWindows();
return;
@@ -1181,7 +1194,7 @@ void CheckTrackerWindow::DrawElement() {
} else {
ImGui::SetNextItemOpen(!thisAreaFullyChecked, ImGuiCond_Once);
}
doDraw = ImGui::TreeNode(stemp.c_str());
doDraw = ImGui::TreeNodeEx(stemp.c_str(), ImGuiTreeNodeFlags_NoTreePushOnOpen);
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f,
@@ -1230,10 +1243,6 @@ void CheckTrackerWindow::DrawElement() {
DrawLocation(rc);
}
}
if (doDraw) {
ImGui::TreePop();
}
}
}
ImGui::PopStyleVar();
@@ -2130,6 +2139,16 @@ void CheckTrackerSettingsWindow::DrawElement() {
SohGui::mSohMenu->MenuDrawItem(windowTypeWidget, ImGui::GetContentRegionAvail().x, THEME_COLOR);
UIWidgets::CVarSliderFloat("Font Size", CVAR_TRACKER_CHECK("FontSize"),
UIWidgets::FloatSliderOptions()
.Tooltip("Sets the font size used in the check tracker.")
.Format("%.1f")
.Step(0.1f)
.Min(0.3f)
.Max(2.0f)
.Color(THEME_COLOR)
.DefaultValue(1.0f));
if (CVarGetInteger(CVAR_TRACKER_CHECK("WindowType"), TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) {
UIWidgets::CVarCheckbox("Enable Dragging", CVAR_TRACKER_CHECK("Draggable"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR));
@@ -2172,7 +2191,6 @@ void CheckTrackerSettingsWindow::DrawElement() {
ImGui::EndDisabled();
// Filtering settings
UIWidgets::PaddedSeparator();
UIWidgets::CVarCheckbox(
"Filter Empty Areas", CVAR_TRACKER_CHECK("HideFilteredAreas"),
UIWidgets::CheckboxOptions()
@@ -2180,6 +2198,18 @@ void CheckTrackerSettingsWindow::DrawElement() {
.Color(THEME_COLOR)
.DefaultValue(true));
ImGui::SeparatorText("Tracker Header Visibility");
UIWidgets::CVarCheckbox("Hidden Items Toggle", CVAR_TRACKER_CHECK("HiddenItemsToggleVisible"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
UIWidgets::CVarCheckbox("Available Checks Toggle", CVAR_TRACKER_CHECK("AvailableChecksToggleVisible"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
UIWidgets::CVarCheckbox("Expand/Collapse Buttons", CVAR_TRACKER_CHECK("ExpandCollapseButtonsVisible"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR).DefaultValue(false));
UIWidgets::CVarCheckbox("Search Input", CVAR_TRACKER_CHECK("SearchInputVisible"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
UIWidgets::CVarCheckbox("Check Totals", CVAR_TRACKER_CHECK("CheckTotalsVisible"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
ImGui::TableNextColumn();
CheckTracker::ImGuiDrawTwoColorPickerSection("Area Incomplete", CVAR_TRACKER_CHECK("AreaIncomplete.MainColor"),
@@ -706,6 +706,11 @@ void Settings::CreateOptions() {
RT_DC_MQ_ADULT_EYES, RCQUEST_MQ, RA_DODONGOS_CAVERN, { Tricks::Tag::ADVANCED },
"Dodongo\'s Cavern MQ Light the Eyes with Strength as Adult",
"If you move very quickly, it is possible to use the bomb flower at the top of the room to light the eyes.");
OPT_TRICK(
RT_DC_EYES_CHU, RCQUEST_BOTH, RA_DODONGOS_CAVERN, { Tricks::Tag::ADVANCED },
"Dodongo\'s Cavern Light the Eyes with Bombchus",
"You can light the dodongo head's eyes with bombchus from the main room, allowing instant access to the end "
"of the dungeon.");
OPT_TRICK(RT_JABU_ALCOVE_JUMP_DIVE, RCQUEST_BOTH, RA_JABU_JABUS_BELLY, { Tricks::Tag::NOVICE },
"Jabu Underwater Alcove as Adult with Jump Dive",
"Standing above the underwater tunnel leading to the scrub, jump down and swim through the tunnel. This "
@@ -773,7 +773,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li
(IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO))) {
if (IS_RANDO || *should) {
Flags_SetRandomizerInf(flag);
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
Magic_Fill(gPlayState);
}
*should = false;
+2
View File
@@ -110,6 +110,8 @@ void Anchor::ProcessIncomingPacketQueue() {
HandlePacket_GameComplete(payload);
else if (packetType == GIVE_ITEM)
HandlePacket_GiveItem(payload);
else if (packetType == OCARINA_SFX)
HandlePacket_OcarinaSfx(payload);
else if (packetType == PLAYER_SFX)
HandlePacket_PlayerSfx(payload);
else if (packetType == UPDATE_TEAM_STATE)
+9
View File
@@ -35,6 +35,8 @@ typedef struct {
s32 linkAge;
PosRot posRot;
Vec3s jointTable[24];
u8 movementFlags;
Vec3s prevTransl;
Vec3s upperLimbRot;
s8 currentBoots;
s8 currentShield;
@@ -46,8 +48,12 @@ typedef struct {
s8 heldItemAction;
u8 modelGroup;
s8 invincibilityTimer;
f32 unk_85C;
s16 unk_862;
s8 actionVar1;
u8 ocarinaNote;
f32 ocarinaModulator;
s8 ocarinaBend;
// Ptr to the dummy player
Player* player;
@@ -84,6 +90,7 @@ class Anchor : public Network {
void HandlePacket_EntranceDiscovered(nlohmann::json payload);
void HandlePacket_GameComplete(nlohmann::json payload);
void HandlePacket_GiveItem(nlohmann::json payload);
void HandlePacket_OcarinaSfx(nlohmann::json payload);
void HandlePacket_PlayerSfx(nlohmann::json payload);
void HandlePacket_PlayerUpdate(nlohmann::json payload);
void HandlePacket_RequestTeamState(nlohmann::json payload);
@@ -111,6 +118,7 @@ class Anchor : public Network {
inline static const std::string GAME_COMPLETE = "GAME_COMPLETE";
inline static const std::string GIVE_ITEM = "GIVE_ITEM";
inline static const std::string HANDSHAKE = "HANDSHAKE";
inline static const std::string OCARINA_SFX = "OCARINA_SFX";
inline static const std::string PLAYER_SFX = "PLAYER_SFX";
inline static const std::string PLAYER_UPDATE = "PLAYER_UPDATE";
inline static const std::string REQUEST_TEAM_STATE = "REQUEST_TEAM_STATE";
@@ -148,6 +156,7 @@ class Anchor : public Network {
void SendPacket_GameComplete();
void SendPacket_GiveItem(u16 modId, s16 getItemId);
void SendPacket_Handshake();
void SendPacket_OcarinaSfx(uint8_t note, float modulator, int8_t bend);
void SendPacket_PlayerSfx(u16 sfxId);
void SendPacket_PlayerUpdate();
void SendPacket_RequestTeamState();
+27 -2
View File
@@ -122,6 +122,8 @@ void DummyPlayer_Update(Actor* actor, PlayState* play) {
Math_Vec3s_Copy(&actor->shape.rot, &client.posRot.rot);
Math_Vec3f_Copy(&actor->world.pos, &client.posRot.pos);
player->skelAnime.jointTable = client.jointTable;
player->skelAnime.movementFlags = client.movementFlags;
Math_Vec3s_Copy(&player->skelAnime.prevTransl, &client.prevTransl);
player->currentBoots = client.currentBoots;
player->currentShield = client.currentShield;
player->currentTunic = client.currentTunic;
@@ -131,15 +133,38 @@ void DummyPlayer_Update(Actor* actor, PlayState* play) {
player->heldItemAction = client.heldItemAction;
player->invincibilityTimer = client.invincibilityTimer;
player->unk_862 = client.unk_862;
player->unk_85C = client.unk_85C;
player->av1.actionVar1 = client.actionVar1;
if (player->modelGroup != client.modelGroup) {
// Apply animation movement (Copied from Player_ApplyAnimMovementScaledByAge)
Vec3f diff;
SkelAnime_UpdateTranslation(&player->skelAnime, &diff, player->actor.shape.rot.y);
if (player->skelAnime.movementFlags & 1) {
if (!LINK_IS_ADULT) {
diff.x *= 0.64f;
diff.z *= 0.64f;
}
player->actor.world.pos.x += diff.x * player->actor.scale.x;
player->actor.world.pos.z += diff.z * player->actor.scale.z;
}
if (player->skelAnime.movementFlags & 2) {
if (!(player->skelAnime.movementFlags & 4)) {
diff.y *= player->ageProperties->unk_08;
}
player->actor.world.pos.y += diff.y * player->actor.scale.y;
}
if (player->modelGroup != Player_ActionToModelGroup(player, player->itemAction)) {
// Hack to account for usage of gSaveContext
s32 originalAge = gSaveContext.linkAge;
gSaveContext.linkAge = client.linkAge;
u8 originalButtonItem0 = gSaveContext.equips.buttonItems[0];
gSaveContext.equips.buttonItems[0] = client.buttonItem0;
Player_SetModelGroup(player, client.modelGroup);
Player_SetModelGroup(player, Player_ActionToModelGroup(player, player->itemAction));
gSaveContext.linkAge = originalAge;
gSaveContext.equips.buttonItems[0] = originalButtonItem0;
}
+27
View File
@@ -98,6 +98,8 @@ void Anchor::RegisterHooks() {
COND_HOOK(OnGameFrameUpdate, isConnected, [&]() { ProcessIncomingPacketQueue(); });
COND_HOOK(OnPlayerSfx, isConnected, [&](u16 sfxId) { SendPacket_PlayerSfx(sfxId); });
COND_HOOK(OnOcarinaNote, isConnected,
[&](uint8_t note, float modulator, int8_t bend) { SendPacket_OcarinaSfx(note, modulator, bend); });
COND_HOOK(OnLoadGame, isConnected, [&](s16 fileNum) { justLoadedSave = true; });
@@ -152,6 +154,31 @@ void Anchor::RegisterHooks() {
SendPacket_UpdateDungeonItems();
});
COND_VB_SHOULD(VB_APPLY_TUNIC_COLOR, isConnected, {
Actor* myPlayer = (Actor*)GET_PLAYER(gPlayState);
Actor* actor = va_arg(args, Actor*);
Color_RGB8* color = va_arg(args, Color_RGB8*);
if (actor == myPlayer) {
Color_RGBA8 ownColor = CVarGetColor(CVAR_REMOTE_ANCHOR("Color.Value"), { 100, 255, 100 });
color->r = ownColor.r;
color->g = ownColor.g;
color->b = ownColor.b;
return;
}
uint32_t clientId = Anchor::Instance->GetDummyPlayerClientId(actor);
if (!Anchor::Instance->clients.contains(clientId)) {
return;
}
AnchorClient& client = Anchor::Instance->clients[clientId];
color->r = client.color.r;
color->g = client.color.g;
color->b = client.color.b;
});
// #endregion
// #region Hooks that are purely to sync actor states across the clients, not super essential
+4 -1
View File
@@ -46,7 +46,10 @@ void AnchorMainMenu(WidgetInfo& info) {
}
UIWidgets::PopStyleInput();
ImGui::Text("Name");
ImGui::Text("Name & Color");
static Color_RGBA8 defaultColor = { 100, 255, 100, 255 };
UIWidgets::CVarColorPicker("##Color", CVAR_REMOTE_ANCHOR("Color"), defaultColor);
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (UIWidgets::InputString("##Name", &anchorName, UIWidgets::InputOptions().Color(THEME_COLOR))) {
CVarSetString(CVAR_REMOTE_ANCHOR("Name"), anchorName.c_str());
@@ -0,0 +1,65 @@
#include "soh/Network/Anchor/Anchor.h"
#include "soh/Network/Anchor/JsonConversions.hpp"
#include <nlohmann/json.hpp>
#include <libultraship/libultraship.h>
extern "C" {
#include "macros.h"
#include "functions.h"
#include "variables.h"
extern PlayState* gPlayState;
extern f32 D_80130F28;
}
/**
* OCARINA_SFX
*
* Ocarina effects, only sent to other clients in the same scene as the player
*/
void Anchor::SendPacket_OcarinaSfx(uint8_t note, float modulator, int8_t bend) {
if (!IsSaveLoaded()) {
return;
}
nlohmann::json payload;
payload["type"] = OCARINA_SFX;
payload["note"] = note;
payload["modulator"] = modulator;
payload["bend"] = bend;
payload["quiet"] = true;
for (auto& [clientId, client] : clients) {
if (client.sceneNum == gPlayState->sceneNum && client.online && client.isSaveLoaded && !client.self) {
payload["targetClientId"] = clientId;
SendJsonToRemote(payload);
}
}
}
void Anchor::HandlePacket_OcarinaSfx(nlohmann::json payload) {
uint32_t clientId = payload["clientId"].get<uint32_t>();
uint8_t note = payload["note"].get<uint8_t>();
float modulator = payload["modulator"].get<float>();
int8_t bend = payload["bend"].get<int8_t>();
if (!clients.contains(clientId) || !clients[clientId].player) {
return;
}
auto& client = clients[clientId];
client.ocarinaModulator = modulator;
client.ocarinaBend = bend;
if ((note != 0xFF) && (client.ocarinaNote != note)) {
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | 0xD07, client.ocarinaBend - 1);
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | 0xD05, note);
Audio_PlaySoundGeneral(NA_SE_OC_OCARINA, &client.player->actor.projectedPos, 4, &client.ocarinaModulator,
&D_80130F28, &gSfxDefaultReverb);
} else if ((client.ocarinaNote != 0xFF) && (note == 0xFF)) {
Audio_StopSfxById(NA_SE_OC_OCARINA);
}
client.ocarinaNote = note;
}
@@ -50,6 +50,8 @@ void Anchor::SendPacket_PlayerUpdate() {
jointArray.push_back(joint.y);
jointArray.push_back(joint.z);
}
payload["prevTransl"] = player->skelAnime.prevTransl;
payload["movementFlags"] = player->skelAnime.movementFlags;
payload["jointTable"] = jointArray;
payload["upperLimbRot"] = player->upperLimbRot;
payload["currentBoots"] = player->currentBoots;
@@ -63,6 +65,7 @@ void Anchor::SendPacket_PlayerUpdate() {
payload["modelGroup"] = player->modelGroup;
payload["invincibilityTimer"] = player->invincibilityTimer;
payload["unk_862"] = player->unk_862;
payload["unk_85C"] = player->unk_85C;
payload["actionVar1"] = player->av1.actionVar1;
payload["quiet"] = true;
@@ -94,6 +97,8 @@ void Anchor::HandlePacket_PlayerUpdate(nlohmann::json payload) {
client.jointTable[i].y = jointArray[i * 3 + 1];
client.jointTable[i].z = jointArray[i * 3 + 2];
}
client.movementFlags = payload["movementFlags"].get<u8>();
client.prevTransl = payload["prevTransl"].get<Vec3s>();
client.upperLimbRot = payload["upperLimbRot"].get<Vec3s>();
client.currentBoots = payload["currentBoots"].get<s8>();
client.currentShield = payload["currentShield"].get<s8>();
@@ -106,6 +111,7 @@ void Anchor::HandlePacket_PlayerUpdate(nlohmann::json payload) {
client.modelGroup = payload["modelGroup"].get<u8>();
client.invincibilityTimer = payload["invincibilityTimer"].get<s8>();
client.unk_862 = payload["unk_862"].get<s16>();
client.unk_85C = payload["unk_85C"].get<f32>();
client.actionVar1 = payload["actionVar1"].get<s8>();
}
}
@@ -23,7 +23,7 @@ extern PlayState* gPlayState;
nlohmann::json Anchor::PrepClientState() {
nlohmann::json payload;
payload["name"] = CVarGetString(CVAR_REMOTE_ANCHOR("Name"), "");
payload["color"] = CVarGetColor24(CVAR_REMOTE_ANCHOR("Color"), { 100, 255, 100 });
payload["color"] = CVarGetColor24(CVAR_REMOTE_ANCHOR("Color.Value"), { 100, 255, 100 });
payload["clientVersion"] = clientVersion;
payload["teamId"] = CVarGetString(CVAR_REMOTE_ANCHOR("TeamId"), "default");
payload["online"] = true;
+9 -1
View File
@@ -154,6 +154,7 @@ Color_RGB8 kokiriColor = { 0x1E, 0x69, 0x1B };
Color_RGB8 goronColor = { 0x64, 0x14, 0x00 };
Color_RGB8 zoraColor = { 0x00, 0xEC, 0x64 };
int32_t previousImGuiScaleIndex;
float previousImGuiScale;
bool prevAltAssets = false;
@@ -433,6 +434,7 @@ void OTRGlobals::Initialize() {
hasMasterQuest = hasOriginal = false;
previousImGuiScaleIndex = -1;
previousImGuiScale = defaultImGuiScale;
fontMonoSmall = CreateFontWithSize(14.0f, "fonts/Inconsolata-Regular.ttf");
@@ -501,11 +503,17 @@ OTRGlobals::~OTRGlobals() {
}
void OTRGlobals::ScaleImGui() {
float scale = imguiScaleOptionToValue[CVarGetInteger(CVAR_SETTING("ImGuiScale"), defaultImGuiScale)];
int32_t imGuiScaleIndex = CVarGetInteger(CVAR_SETTING("ImGuiScale"), defaultImGuiScale);
if (imGuiScaleIndex == previousImGuiScaleIndex) {
return;
}
float scale = imguiScaleOptionToValue[imGuiScaleIndex];
float newScale = scale / previousImGuiScale;
ImGui::GetStyle().ScaleAllSizes(newScale);
ImGui::GetIO().FontGlobalScale = scale;
previousImGuiScale = scale;
previousImGuiScaleIndex = imGuiScaleIndex;
}
ImFont* OTRGlobals::CreateDefaultFontWithSize(float size) {
+6 -6
View File
@@ -669,10 +669,10 @@ void SaveManager::InitFileNormal() {
gSaveContext.ship.filenameLanguage =
(gSaveContext.language == LANGUAGE_JPN) ? NAME_LANGUAGE_NTSC_JPN : NAME_LANGUAGE_NTSC_ENG;
}
gSaveContext.healthCapacity = 0x30;
gSaveContext.health = 0x30;
gSaveContext.healthCapacity = STARTING_HEALTH;
gSaveContext.health = STARTING_HEALTH;
gSaveContext.magicLevel = 0;
gSaveContext.magic = 0x30;
gSaveContext.magic = MAGIC_NORMAL_METER;
gSaveContext.rupees = 0;
gSaveContext.swordHealth = 0;
gSaveContext.naviTimer = 0;
@@ -964,10 +964,10 @@ void SaveManager::InitFileMaxed() {
gSaveContext.ship.filenameLanguage =
(gSaveContext.language == LANGUAGE_JPN) ? NAME_LANGUAGE_NTSC_JPN : NAME_LANGUAGE_NTSC_ENG;
}
gSaveContext.healthCapacity = 0x140;
gSaveContext.health = 0x140;
gSaveContext.healthCapacity = MAX_HEALTH;
gSaveContext.health = MAX_HEALTH;
gSaveContext.magicLevel = 2;
gSaveContext.magic = 0x60;
gSaveContext.magic = MAGIC_DOUBLE_METER;
gSaveContext.rupees = 500;
gSaveContext.swordHealth = 8;
gSaveContext.naviTimer = 0;
-18
View File
@@ -581,7 +581,6 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Show Age-Dependent Equipment", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"))
.RaceDisable(false)
.Callback([](WidgetInfo& info) { UpdatePatchHand(); })
.Options(CheckboxOptions().Tooltip("Makes all equipment visible, regardless of age."));
AddWidget(path, "Scale Adult Equipment as Child", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("ScaleAdultEquipmentAsChild"))
@@ -602,7 +601,6 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Color Temple of Time's Medallions", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("ToTMedallionsColors"))
.RaceDisable(false)
.Callback([](WidgetInfo& info) { UpdateToTMedallions(); })
.Options(CheckboxOptions().Tooltip(
"When Medallions are collected, the Medallion imprints around the Master Sword Pedestal in the Temple "
"of Time will become colored-in."));
@@ -1074,17 +1072,11 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Fix Hand Holding Hammer", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("FixHammerHand"))
.RaceDisable(false)
.Callback([](WidgetInfo& info) { UpdatePatchHand(); })
.Options(CheckboxOptions().Tooltip(
"Fixes Adult Link having a backwards Left hand when holding the Megaton Hammer."));
AddWidget(path, "Fix Vanishing Paths", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_ENHANCEMENT("SceneSpecificDirtPathFix"))
.RaceDisable(false)
.Callback([](WidgetInfo& info) {
if (gPlayState != NULL) {
DirtPathFix_UpdateZFightingMode(gPlayState->sceneNum);
}
})
.Options(
ComboboxOptions()
.ComboMap(zFightingOptions)
@@ -1181,7 +1173,6 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Health", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Permanent Heart Loss", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("PermanentHeartLoss"))
.Callback([](WidgetInfo& info) { UpdatePermanentHeartLossState(); })
.Options(CheckboxOptions().Tooltip(
"When you lose 4 quarters of a heart you will permanently lose that Heart Container.\n\n"
"Disabling this after the fact will restore your Heart Containers."));
@@ -1300,7 +1291,6 @@ void SohMenu::AddMenuEnhancements() {
.Options(CheckboxOptions().Tooltip("All Major Bosses move and act twice as fast."));
AddWidget(path, "Hyper Enemies", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("HyperEnemies"))
.Callback([](WidgetInfo& info) { UpdateHyperEnemiesState(); })
.Options(CheckboxOptions().Tooltip("All Regular Enemies and Mini-Bosses move and act twice as fast."));
AddWidget(path, "Enable Visual Guard Vision", WIDGET_CVAR_CHECKBOX).CVar(CVAR_ENHANCEMENT("GuardVision"));
AddWidget(path, "Leever Spawn Rate: %d seconds", WIDGET_CVAR_SLIDER_INT)
@@ -1524,11 +1514,6 @@ void SohMenu::AddMenuEnhancements() {
AddWidget(path, "Mirrored World", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_ENHANCEMENT("MirroredWorldMode"))
.Callback([](WidgetInfo& info) {
if (gPlayState != NULL) {
UpdateMirrorModeState(gPlayState->sceneNum);
}
})
.Options(
ComboboxOptions()
.DefaultIndex(MIRRORED_WORLD_OFF)
@@ -1568,9 +1553,6 @@ void SohMenu::AddMenuEnhancements() {
.Options(CheckboxOptions().Tooltip("A Wallmaster follows Link everywhere, don't get caught!"));
AddWidget(path, "Hurt Container Mode", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("HurtContainer"))
.Callback([](WidgetInfo& info) {
UpdateHurtContainerModeState(CVarGetInteger(CVAR_ENHANCEMENT("HurtContainer"), 0));
})
.Options(CheckboxOptions().Tooltip("Changes Heart Piece and Heart Container functionality.\n\n"
" - Each Heart Container or full Heart Piece reduces Link's Hearts by 1.\n"
" - Can be enabled retroactively after a File has already started."));
+1
View File
@@ -1677,6 +1677,7 @@ void func_800ED458(s32 arg0) {
} else if ((sPrevOcarinaNoteVal != 0xFF) && (sCurOcarinaBtnVal == 0xFF)) {
Audio_StopSfxById(NA_SE_OC_OCARINA);
}
GameInteractor_ExecuteOnOcarinaNote(sCurOcarinaBtnVal, D_80130F24, D_80130F10);
}
}
+1 -1
View File
@@ -1707,7 +1707,7 @@ void Item_DropCollectibleRandom(PlayState* play, Actor* fromActor, Vec3f* spawnP
}
if (dropId == ITEM00_FLEXIBLE) {
if (gSaveContext.health <= 0x10) { // 1 heart or less
if (gSaveContext.health <= FULL_HEART_HEALTH) { // 1 heart or less
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_ELF, spawnPos->x, spawnPos->y + 40.0f, spawnPos->z, 0, 0, 0,
FAIRY_HEAL_TIMED, true);
EffectSsDeadSound_SpawnStationary(play, spawnPos, NA_SE_EV_BUTTERFRY_TO_FAIRY, true,
+4 -4
View File
@@ -393,9 +393,9 @@ void HealthMeter_Draw(PlayState* play) {
InterfaceContext* interfaceCtx = &play->interfaceCtx;
GraphicsContext* gfxCtx = play->state.gfxCtx;
Vtx* sp154 = interfaceCtx->beatingHeartVtx;
s32 curHeartFraction = gSaveContext.health % 0x10;
s16 totalHeartCount = gSaveContext.healthCapacity / 0x10;
s16 fullHeartCount = gSaveContext.health / 0x10;
s32 curHeartFraction = gSaveContext.health % FULL_HEART_HEALTH;
s16 totalHeartCount = gSaveContext.healthCapacity / FULL_HEART_HEALTH;
s16 fullHeartCount = gSaveContext.health / FULL_HEART_HEALTH;
s32 pad2;
f32 sp144 = interfaceCtx->unk_22A * 0.1f;
s32 curCombineModeSet = 0;
@@ -410,7 +410,7 @@ void HealthMeter_Draw(PlayState* play) {
OPEN_DISPS(gfxCtx);
if (!(gSaveContext.health % 0x10)) {
if (!(gSaveContext.health % FULL_HEART_HEALTH)) {
fullHeartCount--;
}
+4 -7
View File
@@ -4656,7 +4656,7 @@ void Message_Update(PlayState* play) {
}
if ((msgCtx->textId >= 0xC2 && msgCtx->textId < 0xC7) ||
(msgCtx->textId >= 0xFA && msgCtx->textId < 0xFE)) {
gSaveContext.healthAccumulator = 0x140; // Refill 20 hearts
gSaveContext.healthAccumulator = MAX_HEALTH; // Refill 20 hearts
}
if (msgCtx->textId == 0x301F || msgCtx->textId == 0xA || msgCtx->textId == 0xC || msgCtx->textId == 0xCF ||
msgCtx->textId == 0x21C || msgCtx->textId == 9 || msgCtx->textId == 0x4078 ||
@@ -4694,12 +4694,9 @@ void Message_Update(PlayState* play) {
}
if ((s32)(gSaveContext.inventory.questItems & 0xF0000000) == 0x40000000) {
gSaveContext.inventory.questItems ^= 0x40000000;
if (!CVarGetInteger(CVAR_ENHANCEMENT("HurtContainer"), 0)) {
gSaveContext.healthCapacity += 0x10;
gSaveContext.health += 0x10;
} else {
gSaveContext.healthCapacity -= 0x10;
gSaveContext.health -= 0x10;
if (GameInteractor_Should(VB_HEARTS_INCREASE_WITH_CONTAINERS, true)) {
gSaveContext.healthCapacity += FULL_HEART_HEALTH;
gSaveContext.health += FULL_HEART_HEALTH;
}
}
if (msgCtx->ocarinaAction != OCARINA_ACTION_CHECK_NOWARP_DONE) {
+6 -9
View File
@@ -2325,19 +2325,16 @@ u8 Item_Give(PlayState* play, u8 item) {
gSaveContext.ship.stats.heartPieces++;
return Return_Item(item, MOD_NONE, ITEM_NONE);
} else if (item == ITEM_HEART_CONTAINER) {
if (!CVarGetInteger(CVAR_ENHANCEMENT("HurtContainer"), 0)) {
gSaveContext.healthCapacity += 0x10;
gSaveContext.health += 0x10;
} else {
gSaveContext.healthCapacity -= 0x10;
gSaveContext.health -= 0x10;
if (GameInteractor_Should(VB_HEARTS_INCREASE_WITH_CONTAINERS, true)) {
gSaveContext.healthCapacity += FULL_HEART_HEALTH;
gSaveContext.health += FULL_HEART_HEALTH;
}
gSaveContext.ship.stats.heartContainers++;
return Return_Item(item, MOD_NONE, ITEM_NONE);
} else if (item == ITEM_HEART) {
osSyncPrintf("回復ハート回復ハート回復ハート\n"); // "Recovery Heart"
if (play != NULL) {
Health_ChangeBy(play, 0x10);
Health_ChangeBy(play, FULL_HEART_HEALTH);
}
return Return_Item(item, MOD_NONE, item);
} else if (item == ITEM_MAGIC_SMALL) {
@@ -2917,7 +2914,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) {
gSaveContext.health = gSaveContext.healthCapacity;
}
heartCount = gSaveContext.health % 0x10;
heartCount = gSaveContext.health % FULL_HEART_HEALTH;
healthLevel = heartCount;
if (heartCount != 0) {
@@ -3574,7 +3571,7 @@ void Interface_DrawMagicBar(PlayState* play) {
R_MAGIC_FILL_X - 1;
}
} else {
if ((gSaveContext.healthCapacity - 1) / 0x10 >= lineLength && lineLength != 0) {
if ((gSaveContext.healthCapacity - 1) / FULL_HEART_HEALTH >= lineLength && lineLength != 0) {
magicBarY =
magicBarY_original_l +
magicDrop * (lineLength == 0 ? 0 : ((gSaveContext.healthCapacity - 1) / (0x10 * lineLength) - 1));
+4 -1
View File
@@ -7,6 +7,7 @@
#include "overlays/actors/ovl_Demo_Effect/z_demo_effect.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/Enhancements/randomizer/draw.h"
#include "soh/Enhancements/Holiday/Fredomato.h"
#include "soh/ResourceManagerHelpers.h"
@@ -1087,7 +1088,9 @@ void Player_DrawImpl(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dL
color = &sTemp;
}
gDPSetEnvColor(POLY_OPA_DISP++, color->r, color->g, color->b, 0);
if (GameInteractor_Should(VB_APPLY_TUNIC_COLOR, true, data, color)) {
gDPSetEnvColor(POLY_OPA_DISP++, color->r, color->g, color->b, 0);
}
// If we have a custom link model, always use the most detailed LOD
if (Player_IsCustomLinkModel()) {
+2 -2
View File
@@ -151,9 +151,9 @@ void Sram_OpenSave() {
osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex);
osSyncPrintf(VT_RST);
if (gSaveContext.health < 0x30) {
if (gSaveContext.health < STARTING_HEALTH) {
gSaveContext.health =
CVarGetInteger(CVAR_ENHANCEMENT("FullHealthSpawn"), 0) ? gSaveContext.healthCapacity : 0x30;
CVarGetInteger(CVAR_ENHANCEMENT("FullHealthSpawn"), 0) ? gSaveContext.healthCapacity : STARTING_HEALTH;
}
if (gSaveContext.scarecrowLongSongSet) {
@@ -475,7 +475,7 @@ void BgDyYoseizo_HealPlayer_NoReward(BgDyYoseizo* this, PlayState* play) {
}
if (this->healingTimer == 110) {
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
Magic_Fill(play);
this->refillTimer = 200;
}
@@ -743,7 +743,7 @@ void BgDyYoseizo_Give_Reward(BgDyYoseizo* this, PlayState* play) {
}
if (!this->healing) {
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
this->healing = true;
if (actionIndex == 2) {
Magic_Fill(play);
@@ -771,7 +771,7 @@ void BgDyYoseizo_Give_Reward(BgDyYoseizo* this, PlayState* play) {
}
this->itemSpawned = true;
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
Interface_ChangeAlpha(9);
gSaveContext.itemGetInf[1] |= sItemGetFlags[actionIndex];
Item_Give(play, sItemIds[actionIndex]);
@@ -586,7 +586,7 @@ void BossGanon_IntroCutscene(BossGanon* this, PlayState* play) {
this->unk_198 = 2;
this->timers[2] = 110;
if (GameInteractor_Should(VB_GANON_HEAL_BEFORE_FIGHT, true)) {
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
}
Audio_QueueSeqCmd(NA_BGM_STOP);
} else {
@@ -802,7 +802,7 @@ void BossGanon_IntroCutscene(BossGanon* this, PlayState* play) {
}
if (this->csTimer == 25) {
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
}
if (this->csTimer == 100) {
@@ -206,7 +206,7 @@ void EnBomBowlPit_Reset(EnBomBowlPit* this, PlayState* play) {
// "Normal termination"/"completion"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 正常終了 ☆☆☆☆☆ \n" VT_RST);
if (this->getItemId == GI_HEART_PIECE) {
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
// "Ah recovery!" (?)
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ あぁ回復! ☆☆☆☆☆ \n" VT_RST);
}
@@ -9517,7 +9517,7 @@ void func_80843AE8(PlayState* play, Player* this) {
LinkAnimation_Change(play, &this->skelAnime, &gPlayerAnim_link_derth_rebirth, 1.0f, 99.0f,
Animation_GetLastFrame(&gPlayerAnim_link_derth_rebirth), ANIMMODE_ONCE, 0.0f);
}
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
this->av2.actionVar2 = -1;
}
} else if (gSaveContext.healthAccumulator == 0) {
@@ -14599,20 +14599,20 @@ void Player_Action_8084EAC0(Player* this, PlayState* play) {
rand = 3;
}
if ((rand < 0) && (gSaveContext.health <= 0x10)) {
if ((rand < 0) && (gSaveContext.health <= FULL_HEART_HEALTH)) {
rand = 3;
}
if (rand < 0) {
Health_ChangeBy(play, -0x10);
Health_ChangeBy(play, -FULL_HEART_HEALTH);
} else {
gSaveContext.healthAccumulator = rand * 0x10;
gSaveContext.healthAccumulator = rand * FULL_HEART_HEALTH;
}
} else {
s32 sp28 = D_808549FC[this->itemAction - PLAYER_IA_BOTTLE_POTION_RED];
if (sp28 & 1) {
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
}
if (sp28 & 2) {
@@ -14756,7 +14756,7 @@ void Player_Action_8084EED8(Player* this, PlayState* play) {
Player_PlaySfx(this, NA_SE_EV_BOTTLE_CAP_OPEN);
Player_PlaySfx(this, NA_SE_EV_FIATY_HEAL - SFX_FLAG);
} else if (LinkAnimation_OnFrame(&this->skelAnime, 47.0f)) {
gSaveContext.healthAccumulator = 0x140;
gSaveContext.healthAccumulator = MAX_HEALTH;
}
}
@@ -2401,7 +2401,7 @@ void FileChoose_DrawFileInfo(GameState* thisx, s16 fileIndex, s16 isActive) {
gDPSetEnvColor(POLY_OPA_DISP++, heartBorder.r, heartBorder.g, heartBorder.b, 255);
}
i = Save_GetSaveMetaInfo(fileIndex)->healthCapacity / 0x10;
i = Save_GetSaveMetaInfo(fileIndex)->healthCapacity / FULL_HEART_HEALTH;
if (CVarGetInteger(CVAR_ENHANCEMENT("FileSelectMoreInfo"), 0) == 0 || this->menuMode != FS_MENU_MODE_SELECT ||
Save_GetSaveMetaInfo(this->selectedFileIndex)->archiSave) {
@@ -50,6 +50,8 @@ void Select_LoadGame(SelectContext* this, s32 entranceIndex) {
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenCurrentScene"), this->currentScene);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenTopDisplayedScene"), this->topDisplayedScene);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenPageDownIndex"), this->pageDownIndex);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenLinkAge"), gSaveContext.linkAge);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenNightFlag"), gSaveContext.nightFlag);
CVarSave();
if (ResourceMgr_GameHasMasterQuest() && ResourceMgr_GameHasOriginal()) {
@@ -118,6 +120,8 @@ void Select_Grotto_LoadGame(SelectContext* this, s32 grottoIndex) {
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenCurrentScene"), this->currentScene);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenTopDisplayedScene"), this->topDisplayedScene);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenPageDownIndex"), this->pageDownIndex);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenLinkAge"), gSaveContext.linkAge);
CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenNightFlag"), gSaveContext.nightFlag);
CVarSave();
}
@@ -1833,6 +1837,10 @@ void Select_SwitchBetterWarpMode(SelectContext* this, u8 isBetterWarpMode) {
this->opt = 1;
}
}
gSaveContext.linkAge = CVarGetInteger(CVAR_GENERAL("BetterDebugWarpScreenLinkAge"), 1);
gSaveContext.nightFlag = CVarGetInteger(CVAR_GENERAL("BetterDebugWarpScreenNightFlag"), 0);
gSaveContext.dayTime = gSaveContext.nightFlag ? 0x0000 : 0x8000;
} else {
this->count = ARRAY_COUNT(sScenes);
@@ -140,7 +140,7 @@ void KaleidoScope_DrawDebugEditor(PlayState* play) {
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0);
// Current Health Quarter (X / 4)
KaleidoScope_DrawDigit(play, (gSaveContext.health % 0x10) / 4, 194, 15);
KaleidoScope_DrawDigit(play, (gSaveContext.health % FULL_HEART_HEALTH) / 4, 194, 15);
gDPPipeSync(POLY_OPA_DISP++);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
@@ -169,7 +169,7 @@ void KaleidoScope_DrawDebugEditor(PlayState* play) {
// Health capacity
spD8[2] = 0;
spD8[3] = gSaveContext.healthCapacity / 0x10;
spD8[3] = gSaveContext.healthCapacity / FULL_HEART_HEALTH;
while (spD8[3] >= 10) {
spD8[2]++;
spD8[3] -= 10;
@@ -180,7 +180,7 @@ void KaleidoScope_DrawDebugEditor(PlayState* play) {
// Health
spD8[2] = 0;
spD8[3] = gSaveContext.health / 0x10;
spD8[3] = gSaveContext.health / FULL_HEART_HEALTH;
while (spD8[3] >= 10) {
spD8[2]++;
spD8[3] -= 10;
@@ -368,15 +368,15 @@ void KaleidoScope_DrawDebugEditor(PlayState* play) {
case 1:
if (CHECK_BTN_ALL(input->press.button, BTN_CUP) || CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) {
gSaveContext.healthCapacity -= 0x10;
if (gSaveContext.healthCapacity < 0x30) {
gSaveContext.healthCapacity = 0x30;
gSaveContext.healthCapacity -= FULL_HEART_HEALTH;
if (gSaveContext.healthCapacity < STARTING_HEALTH) {
gSaveContext.healthCapacity = STARTING_HEALTH;
}
} else if (CHECK_BTN_ALL(input->press.button, BTN_CDOWN) ||
CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) {
gSaveContext.healthCapacity += 0x10;
if (gSaveContext.healthCapacity >= 0x140) {
gSaveContext.healthCapacity = 0x140;
gSaveContext.healthCapacity += FULL_HEART_HEALTH;
if (gSaveContext.healthCapacity >= MAX_HEALTH) {
gSaveContext.healthCapacity = MAX_HEALTH;
}
}
break;
@@ -387,9 +387,9 @@ void KaleidoScope_DrawDebugEditor(PlayState* play) {
} else if (CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) {
Health_ChangeBy(play, 4);
} else if (CHECK_BTN_ALL(input->press.button, BTN_CUP)) {
Health_ChangeBy(play, -0x10);
Health_ChangeBy(play, -FULL_HEART_HEALTH);
} else if (CHECK_BTN_ALL(input->press.button, BTN_CDOWN)) {
Health_ChangeBy(play, 0x10);
Health_ChangeBy(play, FULL_HEART_HEALTH);
}
break;
@@ -1633,8 +1633,7 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (pauseCtx->randoQuestMode) {
POLY_OPA_DISP =
KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->saveVtx, sSaveTexs[gSaveContext.language]);
POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->saveVtx, sGameOverTexs);
RandoKaleido_DrawMiscCollectibles(play);
} else {
POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->questPageVtx,
@@ -1729,8 +1728,7 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
if (pauseCtx->randoQuestMode) {
POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->saveVtx,
sSaveTexs[gSaveContext.language]);
POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->saveVtx, sGameOverTexs);
RandoKaleido_DrawMiscCollectibles(play);
} else {
POLY_OPA_DISP = KaleidoScope_DrawPageSections(POLY_OPA_DISP, pauseCtx->questPageVtx,
@@ -4773,8 +4771,9 @@ void KaleidoScope_Update(PlayState* play) {
// Reset frame counter to prevent autosave on respawn
play->gameplayFrames = 0;
gSaveContext.nextTransitionType = TRANS_TYPE_FADE_BLACK;
gSaveContext.health =
CVarGetInteger(CVAR_ENHANCEMENT("FullHealthSpawn"), 0) ? gSaveContext.healthCapacity : 0x30;
gSaveContext.health = CVarGetInteger(CVAR_ENHANCEMENT("FullHealthSpawn"), 0)
? gSaveContext.healthCapacity
: STARTING_HEALTH;
Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA);
gSaveContext.healthAccumulator = 0;
gSaveContext.magicState = MAGIC_STATE_IDLE;