mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-05-23 06:54:39 -04:00
Merge branch 'develop' of github.com:Malkierian/Shipwright into reindeer-games
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,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()),
|
||||
|
||||
+136
-52
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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."));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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--;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user