Merge branch 'develop' of github.com:Malkierian/Shipwright into preset-manager

This commit is contained in:
Malkierian 2025-05-19 09:29:43 -07:00
commit 35a91d3ec5
187 changed files with 1396 additions and 726 deletions

View file

@ -1,7 +1,5 @@
set(CVAR_VSYNC_ENABLED "${CVAR_PREFIX_SETTING}.VsyncEnabled" CACHE STRING "")
set(CVAR_Z_FIGHTING_MODE "${CVAR_PREFIX_SETTING}.ZFightingMode" CACHE STRING "")
set(CVAR_NEW_FILE_DROPPED "${CVAR_PREFIX_GENERAL}.NewFileDropped" CACHE STRING "")
set(CVAR_DROPPED_FILE "${CVAR_PREFIX_GENERAL}.DroppedFile" CACHE STRING "")
set(CVAR_INTERNAL_RESOLUTION "${CVAR_PREFIX_SETTING}.InternalResolution" CACHE STRING "")
set(CVAR_MSAA_VALUE "${CVAR_PREFIX_SETTING}.MSAAValue" CACHE STRING "")
set(CVAR_SDL_WINDOWED_FULLSCREEN "${CVAR_PREFIX_SETTING}.SdlWindowedFullscreen" CACHE STRING "")

View file

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.26.0 FATAL_ERROR)
set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "" FORCE)
set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_C_STANDARD 23 CACHE STRING "The C standard to use")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")

@ -1 +1 @@
Subproject commit 35c3a7e80721e5f5a5260753c14499dc943dd3d8
Subproject commit 6a3f6cd327b99f617b623e5b9a3afeae460aac2b

View file

@ -4,6 +4,7 @@ set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "" FORCE)
project(soh LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_C_STANDARD 23 CACHE STRING "The C standard to use")
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
enable_language(OBJCXX)
@ -511,10 +512,10 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
-Wno-parentheses
-Wno-narrowing
-Wno-missing-braces
-Wno-int-conversion
$<$<COMPILE_LANGUAGE:C>:
-Werror-implicit-function-declaration
-Wno-incompatible-pointer-types
-Wno-int-conversion
>
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
$<$<COMPILE_LANGUAGE:CXX>:
@ -587,11 +588,11 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
-Wno-parentheses
-Wno-narrowing
-Wno-missing-braces
-Wno-int-conversion
-Wno-implicit-int
$<$<COMPILE_LANGUAGE:C>:
-Werror-implicit-function-declaration
-Wno-implicit-int
-Wno-incompatible-pointer-types
-Wno-int-conversion
>
$<$<COMPILE_LANGUAGE:CXX>:-fpermissive>
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion>

View file

@ -15,7 +15,7 @@ extern "C"
#include <soh/Enhancements/randomizer/randomizer_inf.h>
#if defined(INCLUDE_GAME_PRINTF) && defined(_DEBUG)
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, __VA_ARGS__)
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, ##__VA_ARGS__)
#else
#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, ##__VA_ARGS__)
#endif
@ -1044,6 +1044,7 @@ VecSph* OLib_Vec3fToVecSph(VecSph* dest, Vec3f* vec);
VecSph* OLib_Vec3fToVecSphGeo(VecSph* arg0, Vec3f* arg1);
VecSph* OLib_Vec3fDiffToVecSphGeo(VecSph* arg0, Vec3f* a, Vec3f* b);
Vec3f* OLib_Vec3fDiffRad(Vec3f* dest, Vec3f* a, Vec3f* b);
void OnePointCutscene_SetCsCamPoints(Camera* camera, s16 actionParameters, s16 initTimer, CutsceneCameraPoint* atPoints, CutsceneCameraPoint* eyePoints);
s16 OnePointCutscene_Init(PlayState* play, s16 csId, s16 timer, Actor* actor, s16 camIdx);
s16 OnePointCutscene_EndCutscene(PlayState* play, s16 camIdx);
s32 OnePointCutscene_Attention(PlayState* play, Actor* actor);
@ -1102,6 +1103,7 @@ void FrameAdvance_Init(FrameAdvanceContext* frameAdvCtx);
s32 FrameAdvance_Update(FrameAdvanceContext* frameAdvCtx, Input* input);
u8 PlayerGrounded(Player* player);
void Player_SetBootData(PlayState* play, Player* player);
void Player_StartAnimMovement(PlayState* play, Player* player, s32 flags);
s32 Player_InBlockingCsMode(PlayState* play, Player* player);
s32 Player_TryCsAction(PlayState* play, Actor* actor, s32 csAction);
s32 Player_InCsMode(PlayState* play);
@ -1376,7 +1378,7 @@ void func_800AA0B4();
void func_800AA0F0(void);
u32 func_800AA148();
void func_800AA15C();
void func_800AA16C();
void Rumble_ClearRequests();
void func_800AA178(u32);
View* View_New(GraphicsContext* gfxCtx);
void View_Free(View* view);

View file

@ -544,7 +544,7 @@ typedef enum {
LANGUAGE_MAX
} Language;
#define TODO_TRANSLATE "__Translate_This__"
#define TODO_TRANSLATE "TranslateThis"
// TODO get these properties from the textures themselves
#define FONT_CHAR_TEX_WIDTH 16

View file

@ -245,27 +245,30 @@ typedef void (*PostCurveLimbDraw)(struct PlayState* play, SkelAnimeCurve* skelCu
typedef s32 (*AnimUpdateFunc)();
typedef struct SkelAnime {
/* 0x00 */ u8 limbCount; // Number of limbs in the skeleton
/* 0x01 */ u8 mode; // See `AnimationMode`
/* 0x02 */ u8 dListCount; // Number of display lists in a flexible skeleton
/* 0x03 */ s8 taper; // Tapering to use when morphing between animations. Only used by Door_Warp1.
/* 0x04 */ void** skeleton; // An array of pointers to limbs. Can be StandardLimb, LodLimb, or SkinLimb.
/* 0x08 */ void* animation; // Can be an AnimationHeader or LinkAnimationHeader.
/* 0x0C */ f32 startFrame; // In mode ANIMMODE_LOOP_PARTIAL*, start of partial loop.
/* 0x10 */ f32 endFrame; // In mode ANIMMODE_ONCE*, Update returns true when curFrame is equal to this. In mode ANIMMODE_LOOP_PARTIAL*, end of partial loop.
/* 0x14 */ f32 animLength; // Total number of frames in the current animation.
/* 0x18 */ f32 curFrame; // Current frame in the animation
/* 0x1C */ f32 playSpeed; // Multiplied by R_UPDATE_RATE / 3 to get the animation's frame rate.
/* 0x00 */ u8 limbCount; // Number of limbs in the skeleton
/* 0x01 */ u8 mode; // See `AnimationMode`
/* 0x02 */ u8 dListCount; // Number of display lists in a flexible skeleton
/* 0x03 */ s8 taper; // Tapering to use when morphing between animations. Only used by Door_Warp1.
/* 0x04 */ void** skeleton; // An array of pointers to limbs. Can be StandardLimb, LodLimb, or SkinLimb.
/* 0x08 */ void* animation; // Can be an AnimationHeader or LinkAnimationHeader.
/* 0x0C */ f32 startFrame; // In mode ANIMMODE_LOOP_PARTIAL*, start of partial loop.
/* 0x10 */ f32 endFrame; // In mode ANIMMODE_ONCE*, Update returns true when curFrame is equal to this. In mode ANIMMODE_LOOP_PARTIAL*, end of partial loop.
/* 0x14 */ f32 animLength; // Total number of frames in the current animation.
/* 0x18 */ f32 curFrame; // Current frame in the animation
/* 0x1C */ f32 playSpeed; // Multiplied by R_UPDATE_RATE / 3 to get the animation's frame rate.
/* 0x20 */ Vec3s* jointTable; // Current translation of model and rotations of all limbs
/* 0x24 */ Vec3s* morphTable; // Table of values used to morph between animations
/* 0x28 */ f32 morphWeight; // Weight of the current animation morph as a fraction in [0,1]
/* 0x2C */ f32 morphRate; // Reciprocal of the number of frames in the morph
/* 0x30 */ s32 (*update)(); // Can be Loop, Partial loop, Play once, Morph, or Tapered morph. Link only has Loop, Play once, and Morph.
/* 0x34 */ s8 initFlags; // Flags used when initializing Link's skeleton
/* 0x35 */ u8 moveFlags; // Flags used for animations that move the actor in worldspace.
/* 0x36 */ s16 prevRot; // Previous rotation in worldspace.
/* 0x38 */ Vec3s prevTransl; // Previous modelspace translation.
/* 0x3E */ Vec3s baseTransl; // Base modelspace translation.
/* 0x28 */ f32 morphWeight; // Weight of the current animation morph as a fraction in [0,1]
/* 0x2C */ f32 morphRate; // Reciprocal of the number of frames in the morph
/* 0x30 */ union {
s32 (*normal)(struct SkelAnime*); // Can be Loop, Partial loop, Play once, Morph, or Tapered morph
s32 (*link)(struct PlayState*, struct SkelAnime*); // Can be Loop, Play once, or Morph
} update;
/* 0x34 */ s8 initFlags; // Flags used when initializing Link's skeleton
/* 0x35 */ u8 movementFlags; // Flags used for animations that move the actor in worldspace.
/* 0x36 */ s16 prevRot; // Previous rotation in worldspace.
/* 0x38 */ Vec3s prevTransl; // Previous modelspace translation.
/* 0x3E */ Vec3s baseTransl; // Base modelspace translation.
SkeletonHeader* skeletonHeader;
} SkelAnime; // size = 0x44

View file

@ -61,8 +61,8 @@ std::vector<AltTrapType> getEnabledAddTraps() {
};
static void RollRandomTrap(uint32_t seed) {
uint32_t finalSeed =
seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt);
uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed()
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));
Random_Init(finalSeed);
roll = RandomElement(getEnabledAddTraps());
@ -126,12 +126,12 @@ static void OnPlayerUpdate() {
Play_TriggerRespawn(gPlayState);
break;
case ADD_AMMO_TRAP:
AMMO(ITEM_STICK) = AMMO(ITEM_STICK) * 0.5;
AMMO(ITEM_NUT) = AMMO(ITEM_NUT) * 0.5;
AMMO(ITEM_SLINGSHOT) = AMMO(ITEM_SLINGSHOT) * 0.5;
AMMO(ITEM_BOW) = AMMO(ITEM_BOW) * 0.5;
AMMO(ITEM_BOMB) = AMMO(ITEM_BOMB) * 0.5;
AMMO(ITEM_BOMBCHU) = AMMO(ITEM_BOMBCHU) * 0.5;
AMMO(ITEM_STICK) = static_cast<int8_t>(floor(AMMO(ITEM_STICK) * 0.5f));
AMMO(ITEM_NUT) = static_cast<int8_t>(floor(AMMO(ITEM_NUT) * 0.5f));
AMMO(ITEM_SLINGSHOT) = static_cast<int8_t>(floor(AMMO(ITEM_SLINGSHOT) * 0.5f));
AMMO(ITEM_BOW) = static_cast<int8_t>(floor(AMMO(ITEM_BOW) * 0.5f));
AMMO(ITEM_BOMB) = static_cast<int8_t>(floor(AMMO(ITEM_BOMB) * 0.5f));
AMMO(ITEM_BOMBCHU) = static_cast<int8_t>(floor(AMMO(ITEM_BOMBCHU) * 0.5f));
Audio_PlaySoundGeneral(NA_SE_VO_FR_SMILE_0, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
break;

View file

@ -1,6 +1,6 @@
#include <libultraship/libultraship.h>
class TimeDisplayWindow : public Ship::GuiWindow {
class TimeDisplayWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -0,0 +1,110 @@
#include <libultraship/bridge.h>
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
#include "global.h"
extern "C" {
#include "functions.h"
#include "objects/gameplay_keep/gameplay_keep.h"
extern PlayState* gPlayState;
}
#define CVAR_CRAWL_SPEED_NAME CVAR_ENHANCEMENT("CrawlSpeed")
#define CVAR_CRAWL_SPEED_DEFAULT 1
#define CVAR_CRAWL_SPEED_VALUE CVarGetInteger(CVAR_CRAWL_SPEED_NAME, CVAR_CRAWL_SPEED_DEFAULT)
#define CVAR_GLITCH_AIDING_NAME CVAR_ENHANCEMENT("GlitchAidingCrawlspaces")
#define CVAR_GLITCH_AIDING_DEFAULT 0
#define CVAR_GLITCH_AIDING_VALUE CVarGetInteger(CVAR_GLITCH_AIDING_NAME, CVAR_GLITCH_AIDING_DEFAULT)
extern "C" void ExitCrawlspace(Player* player, PlayState* play) {
LinkAnimationHeader* animExit = (LinkAnimationHeader*)gPlayerAnim_link_child_tunnel_end;
LinkAnimationHeader* animEnter = (LinkAnimationHeader*)gPlayerAnim_link_child_tunnel_start;
if (player->linearVelocity > 0.0f) {
// Leaving a crawlspace forwards
player->actor.shape.rot.y = player->actor.wallYaw + 0x8000;
LinkAnimation_Change(play, &player->skelAnime, animExit, ((CVAR_CRAWL_SPEED_VALUE + 1.0f) / 2.0f), 0.0f,
Animation_GetLastFrame(animExit), ANIMMODE_ONCE, 0.0f);
Player_StartAnimMovement(play, player, 0x9D);
OnePointCutscene_Init(play, 9601, 999, NULL, MAIN_CAM);
} else {
// Leaving a crawlspace backwards
player->actor.shape.rot.y = player->actor.wallYaw;
LinkAnimation_Change(play, &player->skelAnime, animEnter, -1.0f * ((CVAR_CRAWL_SPEED_VALUE + 1.0f) / 2.0f),
Animation_GetLastFrame(animEnter), 0.0f, ANIMMODE_ONCE, 0.0f);
Player_StartAnimMovement(play, player, 0x9D);
OnePointCutscene_Init(play, 9602, 999, NULL, MAIN_CAM);
}
}
extern "C" void ExitCrawlspaceCS(PlayState* play, Camera* csCam, int16_t actionParameters, int16_t initTimer,
CutsceneCameraPoint* atPoints, CutsceneCameraPoint* eyePoints) {
s16 camCrawlTemp = CVAR_CRAWL_SPEED_VALUE;
s16 camCrawlTimer = initTimer / camCrawlTemp;
OnePointCutscene_SetCsCamPoints(csCam, actionParameters | 0x1000, camCrawlTimer, atPoints, eyePoints);
}
extern "C" void EnterCrawlspace(Player* player, PlayState* play) {
LinkAnimationHeader* anim = (LinkAnimationHeader*)gPlayerAnim_link_child_tunnel_start;
LinkAnimation_Change(play, &player->skelAnime, anim, ((CVAR_CRAWL_SPEED_VALUE + 1.0f) / 2.0f), 0.0f,
Animation_GetLastFrame(anim), ANIMMODE_ONCE, 0.0f);
}
extern "C" void IncreaseCrawlSpeed(Player* player, PlayState* play) {
Input* sControlInput = &play->state.input[0];
player->linearVelocity = sControlInput->rel.stick_y * 0.03f * CVAR_CRAWL_SPEED_VALUE;
}
void CrawlSpeed_Register() {
bool shouldRegister = CVAR_CRAWL_SPEED_VALUE > 1;
COND_VB_SHOULD(VB_CRAWL_SPEED_EXIT, shouldRegister, {
Player* player = GET_PLAYER(gPlayState);
bool excludeWellBackroom = (player->actor.world.pos.x > 950.0f) && (player->actor.world.pos.x < 1025.0f) &&
(player->actor.world.pos.z > -1510.0f) && (player->actor.world.pos.z < -1490.0f) &&
gPlayState->sceneNum == SCENE_BOTTOM_OF_THE_WELL;
bool excludeGlitchAiding = CVAR_GLITCH_AIDING_VALUE;
if (excludeGlitchAiding && excludeWellBackroom) {
*should = true;
} else {
ExitCrawlspace(player, gPlayState);
*should = false;
}
});
COND_VB_SHOULD(VB_CRAWL_SPEED_EXIT_CS, shouldRegister, {
Player* player = GET_PLAYER(gPlayState);
Camera* csCam = va_arg(args, Camera*);
s16 csId = va_arg(args, s16);
s16 actionParameters = va_arg(args, s16);
s16 initTimer = va_arg(args, s16);
CutsceneCameraPoint* atPoints = va_arg(args, CutsceneCameraPoint*);
CutsceneCameraPoint* eyePoints = va_arg(args, CutsceneCameraPoint*);
bool excludeWellBackroom = (player->actor.world.pos.x > 950.0f) && (player->actor.world.pos.x < 1025.0f) &&
(player->actor.world.pos.z > -1510.0f) && (player->actor.world.pos.z < -1490.0f) &&
gPlayState->sceneNum == SCENE_BOTTOM_OF_THE_WELL;
bool excludeGlitchAiding = CVAR_GLITCH_AIDING_VALUE;
if (excludeGlitchAiding && excludeWellBackroom) {
*should = true;
} else {
ExitCrawlspaceCS(gPlayState, csCam, actionParameters, initTimer, atPoints, eyePoints);
*should = false;
}
});
COND_VB_SHOULD(VB_CRAWL_SPEED_ENTER, shouldRegister, {
Player* player = GET_PLAYER(gPlayState);
EnterCrawlspace(player, gPlayState);
*should = false;
});
COND_VB_SHOULD(VB_CRAWL_SPEED_INCREASE, shouldRegister, {
Player* player = GET_PLAYER(gPlayState);
IncreaseCrawlSpeed(player, gPlayState);
*should = false;
});
}
static RegisterShipInitFunc initSpeed(CrawlSpeed_Register, { CVAR_CRAWL_SPEED_NAME });

View file

@ -0,0 +1,13 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "z64save.h"
}
void RegisterFasterBeanSkulltula() {
COND_VB_SHOULD(VB_SPAWN_BEAN_SKULLTULA, CVarGetInteger(CVAR_ENHANCEMENT("FasterBeanSkull"), 0),
{ *should = true; });
}
static RegisterShipInitFunc initFunc(RegisterFasterBeanSkulltula, { CVAR_ENHANCEMENT("FasterBeanSkull") });

View file

@ -0,0 +1,19 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/ShipInit.hpp"
extern "C" {
#include "z64save.h"
}
void RegisterFasterEmptyBottle() {
COND_VB_SHOULD(VB_EMPTYING_BOTTLE, CVarGetInteger(CVAR_ENHANCEMENT("FasterBottleEmpty"), 0), {
Player* player = va_arg(args, Player*);
if (player->skelAnime.curFrame <= 60.0f) {
player->skelAnime.playSpeed = 3.0f;
} else {
player->skelAnime.playSpeed = 1.0f;
}
});
}
static RegisterShipInitFunc initFunc(RegisterFasterEmptyBottle, { CVAR_ENHANCEMENT("FasterBottleEmpty") });

View file

@ -41,7 +41,7 @@ void FasterHeavyBlockLift_Register() {
LinkAnimationHeader* anim = va_arg(args, LinkAnimationHeader*);
// Same actor is used for small and large silver rocks, use actor params to identify large ones
bool isLargeSilverRock = interactActorId == ACTOR_EN_ISHI && interactRangeActor->params & 1 == 1;
bool isLargeSilverRock = (interactActorId == ACTOR_EN_ISHI) && ((interactRangeActor->params & 1) == 1);
if (CVarGetInteger(CVAR_ENHANCEMENT("FasterHeavyBlockLift"), 0) &&
(isLargeSilverRock || interactActorId == ACTOR_BG_HEAVY_BLOCK)) {
*should = false;

View file

@ -265,6 +265,9 @@ void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabN
}
}
auto playingFromMenu = CVarGetInteger(CVAR_AUDIO("Playing"), 0);
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
// Longest text in Audio Editor
ImVec2 columnSize = ImGui::CalcTextSize("Navi - Look/Hey/Watchout (Target Enemy)");
ImGui::BeginTable(tabId.c_str(), 3, ImGuiTableFlags_SizingFixedFit);
@ -291,10 +294,13 @@ void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabN
const std::string lockedButton = ICON_FA_LOCK + hiddenKey;
const std::string unlockedButton = ICON_FA_UNLOCK + hiddenKey;
const int currentValue = CVarGetInteger(cvarKey.c_str(), defaultValue);
const bool isCurrentlyPlaying = currentValue == playingFromMenu || seqData.sequenceId == currentBGM;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", seqData.label.c_str());
ImGui::TextColored(
UIWidgets::ColorValues.at(isCurrentlyPlaying ? UIWidgets::Colors::Yellow : UIWidgets::Colors::White), "%s",
seqData.label.c_str());
ImGui::TableNextColumn();
ImGui::PushItemWidth(-FLT_MIN);
const int initialValue = map.contains(currentValue) ? currentValue : defaultValue;

View file

@ -7,7 +7,7 @@
#include <imgui.h>
#include "AudioCollection.h"
class AudioEditor : public Ship::GuiWindow {
class AudioEditor final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -111,7 +111,7 @@ const char* BossRush_GetSettingChoiceName(u8 optionIndex, u8 choiceIndex, u8 lan
}
u8 BossRush_GetSettingOptionsAmount(u8 optionIndex) {
return BossRushOptions[optionIndex].choices.size();
return static_cast<u8>(BossRushOptions[optionIndex].choices.size());
}
void BossRush_SpawnBlueWarps(PlayState* play) {
@ -311,7 +311,8 @@ void BossRush_HandleCompleteBoss(PlayState* play) {
play->sceneNum == SCENE_GANON_BOSS) {
gSaveContext.ship.stats.playTimer += 2;
gSaveContext.ship.stats.gameComplete = 1;
gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_BOSSRUSH_FINISH] = GAMEPLAYSTAT_TOTAL_TIME;
gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_BOSSRUSH_FINISH] =
static_cast<uint32_t>(GAMEPLAYSTAT_TOTAL_TIME);
}
}

View file

@ -49,14 +49,14 @@ void InputViewer::RenderButton(std::string btnTexture, std::string btnOutlineTex
if (outlineMode == BUTTON_OUTLINE_ALWAYS_SHOWN || (outlineMode == BUTTON_OUTLINE_NOT_PRESSED && !state) ||
(outlineMode == BUTTON_OUTLINE_PRESSED && state)) {
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(btnOutlineTexture), size,
ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
ImVec2(0, 0), ImVec2(1.0f, 1.0f));
}
// Render button if pressed
if (state) {
ImGui::SetCursorPos(pos);
ImGui::SetNextItemAllowOverlap();
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(btnTexture), size,
ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
ImVec2(0, 0), ImVec2(1.0f, 1.0f));
}
}
@ -201,7 +201,7 @@ void InputViewer::DrawElement() {
// Background
ImGui::Image(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Input-Viewer-Background"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f));
}
// A/B
@ -345,14 +345,14 @@ void InputViewer::DrawElement() {
// Analog Stick
const int analogOutlineMode =
CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.OutlineMode"), STICK_MODE_ALWAYS_SHOWN);
const float maxStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.Movement"), 12);
const int32_t maxStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.Movement"), 12);
if (analogOutlineMode == STICK_MODE_ALWAYS_SHOWN ||
(analogOutlineMode == STICK_MODE_HIDDEN_IN_DEADZONE && !analogStickIsInDeadzone)) {
ImGui::SetNextItemAllowOverlap();
ImGui::SetCursorPos(aPos);
ImGui::Image(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Analog-Stick Outline"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f));
}
const int analogStickMode =
CVarGetInteger(CVAR_INPUT_VIEWER("AnalogStick.VisibilityMode"), STICK_MODE_ALWAYS_SHOWN);
@ -363,11 +363,11 @@ void InputViewer::DrawElement() {
ImVec2(aPos.x + maxStickDistance * ((float)(pads[0].stick_x) / MAX_AXIS_RANGE) * scale,
aPos.y - maxStickDistance * ((float)(pads[0].stick_y) / MAX_AXIS_RANGE) * scale));
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Analog-Stick"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f));
}
// Right Stick
const float maxRightStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.Movement"), 7);
const int32_t maxRightStickDistance = CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.Movement"), 7);
const int rightOutlineMode =
CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.OutlineMode"), STICK_MODE_ALWAYS_HIDDEN);
if (rightOutlineMode == STICK_MODE_ALWAYS_SHOWN ||
@ -376,7 +376,7 @@ void InputViewer::DrawElement() {
ImGui::SetCursorPos(aPos);
ImGui::Image(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Right-Stick Outline"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f));
}
const int rightStickMode =
CVarGetInteger(CVAR_INPUT_VIEWER("RightStick.VisibilityMode"), STICK_MODE_ALWAYS_HIDDEN);
@ -387,7 +387,7 @@ void InputViewer::DrawElement() {
ImVec2(aPos.x + maxRightStickDistance * ((float)(pads[0].right_stick_x) / MAX_AXIS_RANGE) * scale,
aPos.y - maxRightStickDistance * ((float)(pads[0].right_stick_y) / MAX_AXIS_RANGE) * scale));
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Right-Stick"),
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, 255));
scaledBGSize, ImVec2(0, 0), ImVec2(1.0f, 1.0f));
}
// Analog stick angle text
@ -401,7 +401,7 @@ void InputViewer::DrawElement() {
ImGui::PushFont(ImGui::GetFont());
// Calculate polar R coordinate from X and Y angles, squared to avoid sqrt
const float rSquared = pads[0].stick_x * pads[0].stick_x + pads[0].stick_y * pads[0].stick_y;
const int32_t rSquared = pads[0].stick_x * pads[0].stick_x + pads[0].stick_y * pads[0].stick_y;
// ESS range
const int range1Min = CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Min"), 8);

View file

@ -17,7 +17,7 @@ typedef enum {
STICK_MODE_ALWAYS_HIDDEN,
} StickMode;
class InputViewer : public Ship::GuiWindow {
class InputViewer final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
@ -33,7 +33,7 @@ class InputViewer : public Ship::GuiWindow {
void RenderButton(std::string btn, std::string btnOutline, int state, ImVec2 size, int outlineMode);
};
class InputViewerSettingsWindow : public Ship::GuiWindow {
class InputViewerSettingsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -50,8 +50,8 @@ void Mouse_HandleFirstPerson(Player* player) {
: 1;
s8 invertYAxisMulti = CVarGetInteger(CVAR_SETTING("Controls.InvertAimingYAxis"), 1) ? 1 : -1;
if (MOUSE_ENABLED) {
player->actor.focus.rot.y -= mouseCoordRel.x * 6.0f * xAxisMulti * invertXAxisMulti;
player->actor.focus.rot.x += mouseCoordRel.y * 6.0f * yAxisMulti * invertYAxisMulti;
player->actor.focus.rot.y -= static_cast<int16_t>(mouseCoordRel.x * 6.0f * xAxisMulti * invertXAxisMulti);
player->actor.focus.rot.x += static_cast<int16_t>(mouseCoordRel.y * 6.0f * yAxisMulti * invertYAxisMulti);
}
}
@ -59,7 +59,7 @@ void Mouse_RecenterCursor() {
u32 width = GetWindow()->GetWidth();
u32 height = GetWindow()->GetHeight();
if (MOUSE_ENABLED) {
GetWindow()->SetMousePos({ (s32)(width / 2), (s32)(height / 2) });
GetWindow()->SetMousePos({ static_cast<s32>(width / 2), static_cast<s32>(height / 2) });
}
}
@ -67,8 +67,8 @@ void Mouse_HandleShield(f32* sp50, f32* sp54) {
if (MOUSE_ENABLED) {
s32 width = GetWindow()->GetWidth();
s32 height = GetWindow()->GetHeight();
f32 xBound = 7200 / ((f32)width / 2);
f32 yBound = 6000 / ((f32)height / 2);
f32 xBound = 7200 / (width / 2.0f);
f32 yBound = 6000 / (height / 2.0f);
*sp50 +=
(mouseCoord.x - (width / 2)) * xBound * (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? 1 : -1);
*sp54 += (mouseCoord.y - (height / 2)) * yBound;
@ -78,8 +78,8 @@ void Mouse_HandleShield(f32* sp50, f32* sp54) {
}
static s8 iterMouse = 0;
static f32 mouseQuickspinX[5] = {};
static f32 mouseQuickspinY[5] = {};
static s32 mouseQuickspinX[5] = {};
static s32 mouseQuickspinY[5] = {};
static u8 quickspinCount = 0;
void Mouse_UpdateQuickspinCount() {
@ -102,9 +102,9 @@ bool Mouse_HandleQuickspin(bool* should, s8* iter2, s8* sp3C) {
for (i = 0; i < 4; i++, iter2++) {
// Calculating angles as per z_lib.c:func_80077D10()
f32 relY = mouseQuickspinY[i + 1] - mouseQuickspinY[i];
f32 relX = mouseQuickspinX[i + 1] - mouseQuickspinX[i];
s16 aTan = Math_Atan2S(relY, -relX);
s32 relY = mouseQuickspinY[i + 1] - mouseQuickspinY[i];
s32 relX = mouseQuickspinX[i + 1] - mouseQuickspinX[i];
s16 aTan = Math_Atan2S((f32)relY, (f32)-relX);
iterMouse = (u16)(aTan + 0x2000) >> 9; // See z_player.c:Player_ProcessControlStick()
if ((*iter2 = iterMouse) < 0) {
return *should = false;

View file

@ -642,10 +642,14 @@ void SohInputEditorWindow::DrawStickSection(uint8_t port, uint8_t stick, int32_t
ImGui::SameLine();
ImGui::BeginGroup();
DrawStickDirectionLine(ICON_FA_ARROW_UP, port, stick, Ship::UP, color);
DrawStickDirectionLine(ICON_FA_ARROW_DOWN, port, stick, Ship::DOWN, color);
DrawStickDirectionLine(ICON_FA_ARROW_LEFT, port, stick, Ship::LEFT, color);
DrawStickDirectionLine(ICON_FA_ARROW_RIGHT, port, stick, Ship::RIGHT, color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_UP, stick).c_str(), port, stick, Ship::UP,
color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_DOWN, stick).c_str(), port, stick, Ship::DOWN,
color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_LEFT, stick).c_str(), port, stick, Ship::LEFT,
color);
DrawStickDirectionLine(StringHelper::Sprintf("%s##%d", ICON_FA_ARROW_RIGHT, stick).c_str(), port, stick,
Ship::RIGHT, color);
ImGui::EndGroup();
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode(StringHelper::Sprintf("Analog Stick Options##%d", id).c_str())) {
@ -1335,12 +1339,12 @@ void SohInputEditorWindow::DrawOcarinaControlPanel() {
ImGui::AlignTextToFramePadding();
ImGui::BulletText("Disable song detection");
DrawButtonLine(ICON_FA_BAN, 0, BTN_CUSTOM_OCARINA_DISABLE_SONGS);
DrawButtonLine(ICON_FA_BAN "##DisableSongDetection", 0, BTN_CUSTOM_OCARINA_DISABLE_SONGS);
ImGui::AlignTextToFramePadding();
ImGui::BulletText("Pitch");
DrawButtonLine(ICON_FA_ARROW_UP, 0, BTN_CUSTOM_OCARINA_PITCH_UP);
DrawButtonLine(ICON_FA_ARROW_DOWN, 0, BTN_CUSTOM_OCARINA_PITCH_DOWN);
DrawButtonLine(ICON_FA_ARROW_UP "##Pitch", 0, BTN_CUSTOM_OCARINA_PITCH_UP);
DrawButtonLine(ICON_FA_ARROW_DOWN "##Pitch", 0, BTN_CUSTOM_OCARINA_PITCH_DOWN);
if (!CVarGetInteger(CVAR_SETTING("CustomOcarina.Enabled"), 0)) {
ImGui::EndDisabled();

View file

@ -17,7 +17,7 @@ typedef struct {
N64ButtonMask defaultBtn;
} CustomButtonMap;
class SohInputEditorWindow : public Ship::GuiWindow {
class SohInputEditorWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
~SohInputEditorWindow();

View file

@ -60,7 +60,7 @@ void CosmeticsEditor_ResetAll();
void CosmeticsEditor_ResetGroup(CosmeticGroup group);
void ApplyOrResetCustomGfxPatches(bool manualChange = true);
class CosmeticsEditorWindow : public Ship::GuiWindow {
class CosmeticsEditorWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -155,12 +155,12 @@ const std::string CustomMessage::GetFrench(MessageFormat format) const {
}
const std::string CustomMessage::GetForCurrentLanguage(MessageFormat format) const {
return GetForLanguage(((Language)gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : gSaveContext.language,
format);
return GetForLanguage(
((Language)gSaveContext.language == LANGUAGE_JPN) ? LANGUAGE_ENG : (Language)gSaveContext.language, format);
}
const std::string CustomMessage::GetForLanguage(uint8_t language, MessageFormat format) const {
std::string output = messages[language] != TODO_TRANSLATE ? messages[language] : messages[LANGUAGE_ENG];
std::string output = !messages[language].starts_with(TODO_TRANSLATE) ? messages[language] : messages[LANGUAGE_ENG];
ProcessMessageFormat(output, format);
return output;
}

View file

@ -25,7 +25,7 @@ void MessageDebug_DisplayCustomMessage(const char* customMessage);
#ifdef __cplusplus
}
class MessageViewer : public Ship::GuiWindow {
class MessageViewer final : public Ship::GuiWindow {
public:
static inline const char* TABLE_ID = "MessageViewer";
using GuiWindow::GuiWindow;

View file

@ -3,7 +3,7 @@
#include <libultraship/libultraship.h>
class SohStatsWindow : public Ship::GuiWindow {
class SohStatsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
~SohStatsWindow(){};

View file

@ -5,6 +5,7 @@
#include "soh/ActorDB.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/nametag.h"
#include "soh/ShipInit.hpp"
#include <array>
#include <bit>
@ -13,6 +14,7 @@
#include <string>
#include <libultraship/bridge.h>
#include <libultraship/libultraship.h>
#include <spdlog/fmt/fmt.h>
#include "soh/OTRGlobals.h"
#include "soh/cvar_prefixes.h"
@ -31,6 +33,10 @@ extern PlayState* gPlayState;
#define DEKUNUTS_FLOWER 10
#define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer"
#define CVAR_ACTOR_NAME_TAGS(val) CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags." val)
#define CVAR_ACTOR_NAME_TAGS_ENABLED_NAME CVAR_ACTOR_NAME_TAGS("Enabled")
#define CVAR_ACTOR_NAME_TAGS_ENABLED CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0)
typedef struct {
u16 id;
u16 params;
@ -67,6 +73,10 @@ const std::string GetActorDescription(u16 id) {
return ActorDB::Instance->RetrieveEntry(id).entry.valid ? ActorDB::Instance->RetrieveEntry(id).entry.desc : "???";
}
const std::string GetActorDebugName(u16 id) {
return ActorDB::Instance->RetrieveEntry(id).entry.valid ? ActorDB::Instance->RetrieveEntry(id).entry.name : "???";
}
template <typename T> void DrawGroupWithBorder(T&& drawFunc, std::string section) {
// First group encapsulates the inner portion and border
ImGui::BeginChild(std::string("##" + section).c_str(), ImVec2(0, 0),
@ -812,25 +822,37 @@ std::vector<u16> GetActorsWithDescriptionContainingString(std::string s) {
}
void ActorViewer_AddTagForActor(Actor* actor) {
int val = CVarGetInteger(CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), ACTORVIEWER_NAMETAGS_NONE);
auto entry = ActorDB::Instance->RetrieveEntry(actor->id);
std::string tag;
if (val > 0 && entry.entry.valid) {
switch (val) {
case ACTORVIEWER_NAMETAGS_DESC:
tag = entry.desc;
break;
case ACTORVIEWER_NAMETAGS_NAME:
tag = entry.name;
break;
case ACTORVIEWER_NAMETAGS_BOTH:
tag = entry.name + '\n' + entry.desc;
break;
}
NameTag_RegisterForActorWithOptions(actor, tag.c_str(), { .tag = DEBUG_ACTOR_NAMETAG_TAG });
if (!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0)) {
return;
}
std::vector<std::string> parts;
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 0)) {
parts.push_back(GetActorDebugName(actor->id));
}
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayDescription"), 0)) {
parts.push_back(GetActorDescription(actor->id));
}
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayCategory"), 0)) {
parts.push_back(acMapping[actor->category]);
}
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayParams"), 0)) {
parts.push_back(fmt::format("0x{:04X} ({})", (u16)actor->params, actor->params));
}
std::string tag = "";
for (size_t i = 0; i < parts.size(); i++) {
if (i != 0) {
tag += "\n";
}
tag += parts.at(i);
}
bool withZBuffer = CVarGetInteger(CVAR_ACTOR_NAME_TAGS("WithZBuffer"), 0);
NameTag_RegisterForActorWithOptions(actor, tag.c_str(),
{ .tag = DEBUG_ACTOR_NAMETAG_TAG, .noZBuffer = !withZBuffer });
}
void ActorViewer_AddTagForAllActors() {
@ -881,6 +903,57 @@ void ActorViewerWindow::DrawElement() {
}
lastSceneId = gPlayState->sceneNum;
if (ImGui::BeginChild("options", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
bool toggled = false;
bool optionChange = false;
ImGui::SeparatorText("Options");
toggled = UIWidgets::CVarCheckbox("Actor Name Tags", CVAR_ACTOR_NAME_TAGS("Enabled"),
{ { .tooltip = "Adds \"name tags\" above actors for identification" } });
ImGui::SameLine();
UIWidgets::Button("Display Items", { { .tooltip = "Click to add display items on the name tags" } });
if (ImGui::BeginPopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonLeft | ImGuiPopupFlags_NoReopen)) {
optionChange |= UIWidgets::CVarCheckbox("ID", CVAR_ACTOR_NAME_TAGS("DisplayID"));
optionChange |= UIWidgets::CVarCheckbox("Description", CVAR_ACTOR_NAME_TAGS("DisplayDescription"));
optionChange |= UIWidgets::CVarCheckbox("Category", CVAR_ACTOR_NAME_TAGS("DisplayCategory"));
optionChange |= UIWidgets::CVarCheckbox("Params", CVAR_ACTOR_NAME_TAGS("DisplayParams"));
ImGui::EndPopup();
}
optionChange |= UIWidgets::CVarCheckbox(
"Name tags with Z-Buffer", CVAR_ACTOR_NAME_TAGS("WithZBuffer"),
{ { .tooltip = "Allow name tags to be obstructed when behind geometry and actors" } });
if (toggled || optionChange) {
bool tagsEnabled = CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0);
bool noOptionsEnabled = !CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 0) &&
!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayDescription"), 0) &&
!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayCategory"), 0) &&
!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayParams"), 0);
// Save the user an extra click and prevent adding "empty" tags by enabling,
// disabling, or setting an option based on what changed
if (tagsEnabled && noOptionsEnabled) {
if (toggled) {
CVarSetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 1);
} else {
CVarSetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0);
}
} else if (optionChange && !tagsEnabled && !noOptionsEnabled) {
CVarSetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 1);
}
NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG);
ActorViewer_AddTagForAllActors();
}
}
ImGui::EndChild();
PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo("Actor Type", acMapping[category])) {
for (int i = 0; i < acMapping.size(); i++) {
@ -1160,20 +1233,6 @@ void ActorViewerWindow::DrawElement() {
ImGui::TreePop();
}
PopStyleHeader();
static std::unordered_map<int32_t, const char*> nameTagOptions = {
{ 0, "None" },
{ 1, "Short Description" },
{ 2, "Actor ID" },
{ 3, "Both" },
};
if (CVarCombobox(
"Actor Name Tags", CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), nameTagOptions,
ComboboxOptions().Color(THEME_COLOR).Tooltip("Adds \"name tags\" above actors for identification"))) {
NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG);
ActorViewer_AddTagForAllActors();
}
} else {
ImGui::Text("Global Context needed for actor info!");
if (needs_reset) {
@ -1190,9 +1249,9 @@ void ActorViewerWindow::DrawElement() {
ImGui::EndDisabled();
}
void ActorViewerWindow::InitElement() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](void* refActor) {
Actor* actor = static_cast<Actor*>(refActor);
ActorViewer_AddTagForActor(actor);
});
void ActorViewer_RegisterNameTagHooks() {
COND_HOOK(OnActorInit, CVAR_ACTOR_NAME_TAGS_ENABLED,
[](void* actor) { ActorViewer_AddTagForActor(static_cast<Actor*>(actor)); });
}
RegisterShipInitFunc nametagInit(ActorViewer_RegisterNameTagHooks, { CVAR_ACTOR_NAME_TAGS_ENABLED_NAME });

View file

@ -2,11 +2,11 @@
#include <libultraship/libultraship.h>
class ActorViewerWindow : public Ship::GuiWindow {
class ActorViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void DrawElement() override;
void InitElement() override;
void InitElement() override{};
void UpdateElement() override{};
};

View file

@ -20,7 +20,7 @@ extern "C" {
extern PlayState* gPlayState;
}
typedef enum ColRenderSetting { ColRenderDisabled, ColRenderSolid, ColRenderTransparent } ColRenderSetting;
enum ColRenderSetting { ColRenderDisabled, ColRenderSolid, ColRenderTransparent };
static std::unordered_map<int32_t, const char*> ColRenderSettingNames = {
{ ColRenderDisabled, "Disabled" },

View file

@ -5,7 +5,7 @@
typedef enum { COLVIEW_DISABLED, COLVIEW_SOLID, COLVIEW_TRANSPARENT } ColViewerRenderSetting;
#ifdef __cplusplus
class ColViewerWindow : public Ship::GuiWindow {
class ColViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -106,7 +106,7 @@ char z2ASCII(int code) {
return char(ret);
}
typedef enum MagicLevel { MAGIC_LEVEL_NONE, MAGIC_LEVEL_SINGLE, MAGIC_LEVEL_DOUBLE };
enum MagicLevel { MAGIC_LEVEL_NONE, MAGIC_LEVEL_SINGLE, MAGIC_LEVEL_DOUBLE };
std::unordered_map<int8_t, const char*> magicLevelMap = {
{ MAGIC_LEVEL_NONE, "None" },
@ -114,7 +114,7 @@ std::unordered_map<int8_t, const char*> magicLevelMap = {
{ MAGIC_LEVEL_DOUBLE, "Double" },
};
typedef enum AudioOutput {
enum AudioOutput {
AUDIO_STEREO,
AUDIO_MONO,
AUDIO_HEADSET,
@ -128,7 +128,7 @@ std::unordered_map<uint8_t, const char*> audioMap = {
{ AUDIO_SURROUND, "Surround" },
};
typedef enum ZTarget {
enum ZTarget {
Z_TARGET_SWITCH,
Z_TARGET_HOLD,
};

View file

@ -1770,7 +1770,7 @@ const std::vector<std::string> state3 = {
"Travelling to Hook Target",
};
class SaveEditorWindow : public Ship::GuiWindow {
class SaveEditorWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -2,7 +2,7 @@
#include <libultraship/libultraship.h>
class DLViewerWindow : public Ship::GuiWindow {
class DLViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -1,6 +1,6 @@
#include <libultraship/libultraship.h>
class HookDebuggerWindow : public Ship::GuiWindow {
class HookDebuggerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -33,7 +33,7 @@ typedef struct {
uint32_t y;
} ValueTableElement;
class ValueViewerWindow : public Ship::GuiWindow {
class ValueViewerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -22,12 +22,14 @@ DEFINE_HOOK(OnFlagSet, (int16_t flagType, int16_t flag));
DEFINE_HOOK(OnFlagUnset, (int16_t flagType, int16_t flag));
DEFINE_HOOK(OnSceneSpawnActors, ());
DEFINE_HOOK(OnPlayerUpdate, ());
DEFINE_HOOK(OnSetDoAction, (uint16_t action));
DEFINE_HOOK(OnOcarinaSongAction, ());
DEFINE_HOOK(OnCuccoOrChickenHatch, ());
DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
DEFINE_HOOK(OnActorInit, (void* actor));
DEFINE_HOOK(OnActorUpdate, (void* actor));
DEFINE_HOOK(OnActorKill, (void* actor));
DEFINE_HOOK(OnActorDestroy, (void* actor));
DEFINE_HOOK(OnEnemyDefeat, (void* actor));
DEFINE_HOOK(OnBossDefeat, (void* actor));
DEFINE_HOOK(OnTimestamp, (u8 item));

View file

@ -85,6 +85,10 @@ void GameInteractor_ExecuteOnPlayerUpdate() {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerUpdate>();
}
void GameInteractor_ExecuteOnSetDoAction(uint16_t action) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetDoAction>(action);
}
void GameInteractor_ExecuteOnOcarinaSongAction() {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnOcarinaSongAction>();
}
@ -118,6 +122,13 @@ void GameInteractor_ExecuteOnActorKill(void* actor) {
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorKill>(actor);
}
void GameInteractor_ExecuteOnActorDestroy(void* actor) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnActorDestroy>(actor);
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnActorDestroy>(((Actor*)actor)->id, actor);
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::OnActorDestroy>((uintptr_t)actor, actor);
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorDestroy>(actor);
}
void GameInteractor_ExecuteOnEnemyDefeat(void* actor) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnEnemyDefeat>(actor);
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnEnemyDefeat>(((Actor*)actor)->id, actor);

View file

@ -25,11 +25,13 @@ void GameInteractor_ExecuteOnFlagSet(int16_t flagType, int16_t flag);
void GameInteractor_ExecuteOnFlagUnset(int16_t flagType, int16_t flag);
void GameInteractor_ExecuteOnSceneSpawnActors();
void GameInteractor_ExecuteOnPlayerUpdate();
void GameInteractor_ExecuteOnSetDoAction(uint16_t action);
void GameInteractor_ExecuteOnOcarinaSongAction();
void GameInteractor_ExecuteOnCuccoOrChickenHatch();
void GameInteractor_ExecuteOnActorInit(void* actor);
void GameInteractor_ExecuteOnActorUpdate(void* actor);
void GameInteractor_ExecuteOnActorKill(void* actor);
void GameInteractor_ExecuteOnActorDestroy(void* actor);
void GameInteractor_ExecuteOnEnemyDefeat(void* actor);
void GameInteractor_ExecuteOnBossDefeat(void* actor);
void GameInteractor_ExecuteOnTimestamp(u8 item);

View file

@ -112,7 +112,7 @@ void GameInteractor::RawAction::FreezePlayer() {
void GameInteractor::RawAction::BurnPlayer() {
Player* player = GET_PLAYER(gPlayState);
for (int i = 0; i < 18; i++) {
player->bodyFlameTimers[i] = Rand_S16Offset(0, 200);
player->bodyFlameTimers[i] = static_cast<uint8_t>(Rand_S16Offset(0, 200));
}
player->bodyIsBurning = true;
func_80837C0C(gPlayState, player, 0, 0, 0, 0, 0);
@ -559,7 +559,7 @@ void GameInteractor::RawAction::SetRandomWind(bool active) {
GameInteractor::State::RandomWindActive = 0;
GameInteractor::State::RandomWindSecondsSinceLastDirectionChange = 0;
player->pushedSpeed = 0.0f;
player->pushedYaw = 0.0f;
player->pushedYaw = 0;
}
}
@ -617,7 +617,7 @@ GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset
}
// Generate point in random angle with a radius.
float angle = Random(0, 2 * M_PI);
float angle = static_cast<float>(RandomDouble() * 2 * M_PI);
float radius = 150;
float posXOffset = radius * cos(angle);
float posZOffset = radius * sin(angle);

View file

@ -294,6 +294,43 @@ typedef enum {
// - `*ObjKibako2`
VB_CRATE_SETUP_DRAW,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_CRAWL_SPEED_ENTER,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_CRAWL_SPEED_EXIT,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*Camera`
// - 'int16_t' (csId)
// - 'int16_t' (actionParameters)
// - 'int16_t' (initTimer)
// - 'CutsceneCameraPoint*' (atPoints)
// - 'CutsceneCameraPoint*' (eyePoints)
VB_CRAWL_SPEED_EXIT_CS,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_CRAWL_SPEED_INCREASE,
// #### `result`
// ```c
// !Flags_GetItemGetInf(ITEMGETINF_1C)
@ -425,6 +462,14 @@ typedef enum {
// - `*int16_t` (item id)
VB_DRAW_AMMO_COUNT,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - Player*
VB_EMPTYING_BOTTLE,
// #### `result`
// ```c
// (Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(play)
@ -474,6 +519,14 @@ typedef enum {
// - `*BgHeavyBlock`
VB_FREEZE_LINK_FOR_BLOCK_THROW,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - None
VB_FREEZE_LINK_FOR_FOREST_PILLARS,
// #### `result`
// ```c
// true
@ -1358,6 +1411,14 @@ typedef enum {
// - `*BgTreemouth`
VB_PLAY_DEKU_TREE_INTRO_CS,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*DemoKekkai`
VB_PLAY_DISPEL_BARRIER_CS,
// #### `result`
// ```c
// true
@ -1422,6 +1483,15 @@ typedef enum {
// - None
VB_PLAY_FIRE_ARROW_CS,
// #### `result`
// ```c
// true
// ```
// #### `args`
// - `*EnHeishi2`
// - `bool` (clearCamera - true if the code clears a sub-camera, false otherwise)
VB_PLAY_GATE_OPENING_OR_CLOSING_CS,
// #### `result`
// ```c
// true
@ -1790,6 +1860,14 @@ typedef enum {
// - `*ObjBean`
VB_SPAWN_BEAN_STALK_FAIRIES,
// #### `result`
// ```c
// this->timer >= 60
// ```
// #### `args`
// - `None`
VB_SPAWN_BEAN_SKULLTULA,
// #### `result`
// ```c
// true

View file

@ -1,6 +1,6 @@
#include <libultraship/libultraship.h>
class GameplayStatsWindow : public Ship::GuiWindow {
class GameplayStatsWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -12,7 +12,6 @@
#include "soh/Enhancements/randomizer/3drando/random.hpp"
#include "soh/Enhancements/cosmetics/authenticGfxPatches.h"
#include <soh/Enhancements/item-tables/ItemTableManager.h>
#include "soh/Enhancements/nametag.h"
#include "soh/Enhancements/timesaver_hook_handlers.h"
#include "soh/Enhancements/TimeSavers/TimeSavers.h"
#include "soh/Enhancements/randomizer/hook_handlers.h"
@ -1090,7 +1089,6 @@ void InitMods() {
RegisterRandomizedEnemySizes();
RegisterOpenAllHours();
RegisterToTMedallions();
NameTag_RegisterHooks();
RegisterFloorSwitchesHook();
RegisterPatchHandHandler();
RegisterHurtContainerModeHandler();

View file

@ -5,7 +5,7 @@
#include "soh/frame_interpolation.h"
#include "soh/Enhancements/custom-message/CustomMessageInterfaceAddon.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/OTRGlobals.h"
#include "soh/ShipUtils.h"
extern "C" {
#include "z64.h"
@ -26,12 +26,16 @@ typedef struct {
int16_t height; // Textbox height
int16_t width; // Textbox width
int16_t yOffset; // Addition Y offset
uint8_t noZBuffer; // Allow rendering over geometry
Mtx* mtx; // Allocated Mtx for rendering
Vtx* vtx; // Allocated Vtx for rendering
} NameTag;
static std::vector<NameTag> nameTags;
static std::vector<Gfx> nameTagDl;
static bool sMirrorWorldActive = false;
void NameTag_RegisterHooks();
void FreeNameTag(NameTag* nameTag) {
if (nameTag->vtx != nullptr) {
@ -51,14 +55,14 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) {
}
// Name tag is too far away to meaningfully read, don't bother rendering it
if (nameTag->actor->xyzDistToPlayerSq > 200000.0f) {
if (nameTag->actor->xyzDistToPlayerSq > 440000.0f) {
return;
}
// Fade out name tags that are far away
float alpha = 1.0f;
if (nameTag->actor->xyzDistToPlayerSq > 160000.0f) {
alpha = (200000.0f - nameTag->actor->xyzDistToPlayerSq) / 40000.0f;
if (nameTag->actor->xyzDistToPlayerSq > 360000.0f) {
alpha = (440000.0f - nameTag->actor->xyzDistToPlayerSq) / 80000.0f;
}
float scale = 75.0f / 100.f;
@ -79,7 +83,7 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) {
textColor = CVarGetColor(CVAR_COSMETIC("HUD.NameTagActorText.Value"), textColor);
}
FrameInterpolation_RecordOpenChild(nameTag->actor, 10);
FrameInterpolation_RecordOpenChild(nameTag->actor, 0);
// Prefer the highest between world position and focus position if targetable
float posY = nameTag->actor->world.pos.y;
@ -92,7 +96,7 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) {
// Set position, billboard effect, scale (with mirror mode), then center nametag
Matrix_Translate(nameTag->actor->world.pos.x, posY, nameTag->actor->world.pos.z, MTXMODE_NEW);
Matrix_ReplaceRotation(&play->billboardMtxF);
Matrix_Scale(scale * (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? -1 : 1), -scale, 1.0f, MTXMODE_APPLY);
Matrix_Scale(scale * (sMirrorWorldActive ? -1.0f : 1.0f), -scale, 1.0f, MTXMODE_APPLY);
Matrix_Translate(-(float)nameTag->width / 2, -nameTag->height, 0, MTXMODE_APPLY);
Matrix_ToMtx(nameTag->mtx, (char*)__FILE__, __LINE__);
@ -154,15 +158,27 @@ void DrawNameTags() {
OPEN_DISPS(gPlayState->state.gfxCtx);
// Setup before rendering name tags
Gfx_SetupDL_38Xlu(gPlayState->state.gfxCtx);
nameTagDl.push_back(gsDPSetAlphaDither(G_AD_DISABLE));
nameTagDl.push_back(gsSPClearGeometryMode(G_SHADE));
POLY_XLU_DISP = Gfx_SetupDL_39(POLY_XLU_DISP);
nameTagDl.push_back(gsDPSetAlphaCompare(G_AC_NONE));
nameTagDl.push_back(
gsDPSetCombineLERP(0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0));
bool zbufferEnabled = false;
// Add all the name tags
for (const auto& nameTag : nameTags) {
// Toggle ZBuffer mode based on last state and next tag
if (zbufferEnabled == nameTag.noZBuffer) {
if (nameTag.noZBuffer) {
nameTagDl.push_back(gsSPClearGeometryMode(G_ZBUFFER));
zbufferEnabled = false;
} else {
nameTagDl.push_back(gsSPSetGeometryMode(G_ZBUFFER));
zbufferEnabled = true;
}
}
DrawNameTag(gPlayState, &nameTag);
}
@ -189,22 +205,22 @@ void UpdateNameTags() {
return aDistToCamera > bDistToCamera;
});
sMirrorWorldActive = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0);
}
extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* text, NameTagOptions options) {
std::string processedText = std::string(Interface_ReplaceSpecialCharacters((char*)text));
// Strip out unsupported characters
processedText.erase(std::remove_if(processedText.begin(), processedText.end(),
[](const char& c) {
// 172 is max supported texture for the in-game font system,
// and filter anything less than a space but not the newline or nul
// characters
return (unsigned char)c > 172 || (c < ' ' && c != '\n' && c != '\0');
}),
processedText.end());
// 172 is max supported texture for the in-game font system,
// and filter anything less than a space but not the newline or nul characters
processedText.erase(
std::remove_if(processedText.begin(), processedText.end(),
[](const char& c) { return (uint8_t)c > 172 || (c < ' ' && c != '\n' && c != '\0'); }),
processedText.end());
int16_t numChar = processedText.length();
size_t numChar = processedText.length();
int16_t numLines = 1;
int16_t offsetX = 0;
int16_t maxOffsetX = 0;
@ -213,7 +229,7 @@ extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* te
Vtx* vertices = (Vtx*)calloc(sizeof(Vtx[4]), numChar + 1);
// Set all the char vtx first to get the total size for the textbox
for (int16_t i = 0; i < numChar; i++) {
for (size_t i = 0; i < numChar; i++) {
if (processedText[i] == '\n') {
offsetX = 0;
numLines++;
@ -249,10 +265,13 @@ extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* te
nameTag.height = height;
nameTag.width = width;
nameTag.yOffset = options.yOffset;
nameTag.noZBuffer = options.noZBuffer;
nameTag.mtx = new Mtx();
nameTag.vtx = vertices;
nameTags.push_back(nameTag);
NameTag_RegisterHooks();
}
extern "C" void NameTag_RegisterForActor(Actor* actor, const char* text) {
@ -268,6 +287,8 @@ extern "C" void NameTag_RemoveAllForActor(Actor* actor) {
it++;
}
}
NameTag_RegisterHooks();
}
extern "C" void NameTag_RemoveAllByTag(const char* tag) {
@ -279,6 +300,8 @@ extern "C" void NameTag_RemoveAllByTag(const char* tag) {
it++;
}
}
NameTag_RegisterHooks();
}
void RemoveAllNameTags() {
@ -287,23 +310,49 @@ void RemoveAllNameTags() {
}
nameTags.clear();
NameTag_RegisterHooks();
}
static bool sRegisteredHooks = false;
void NameTag_RegisterHooks() {
if (sRegisteredHooks) {
static HOOK_ID gameStatUpdateHookID = 0;
static HOOK_ID drawHookID = 0;
static HOOK_ID playDestroyHookID = 0;
static HOOK_ID actorDestroyHookID = 0;
static bool sRegisteredHooks = false;
// Hooks already (un)registered based on nametags
if ((nameTags.size() > 0) == sRegisteredHooks) {
return;
}
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnGameFrameUpdate>(gameStatUpdateHookID);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnPlayDrawEnd>(drawHookID);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnPlayDestroy>(playDestroyHookID);
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorDestroy>(actorDestroyHookID);
gameStatUpdateHookID = 0;
drawHookID = 0;
playDestroyHookID = 0;
actorDestroyHookID = 0;
sRegisteredHooks = false;
if (nameTags.size() == 0) {
return;
}
sRegisteredHooks = true;
// Reorder tags every frame to mimic depth rendering
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { UpdateNameTags(); });
gameStatUpdateHookID =
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(UpdateNameTags);
// Render name tags at the end of player draw to avoid overflowing the display buffers
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDrawEnd>([]() { DrawNameTags(); });
// Render name tags at the end of the Play World drawing
drawHookID = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDrawEnd>(DrawNameTags);
// Remove all name tags on play state destroy as all actors are removed anyways
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDestroy>([]() { RemoveAllNameTags(); });
playDestroyHookID = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDestroy>(RemoveAllNameTags);
// Remove all name tags for actor on destroy
actorDestroyHookID = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorDestroy>(
[](void* actor) { NameTag_RemoveAllForActor((Actor*)actor); });
}

View file

@ -1,11 +1,16 @@
#ifndef _NAMETAG_H_
#define _NAMETAG_H_
#include <z64.h>
#ifndef NAMETAG_H
#define NAMETAG_H
#include <libultraship/color.h>
#include <libultraship/libultra.h>
struct Actor;
typedef struct {
const char* tag; // Tag identifier to filter/remove multiple tags
int16_t yOffset; // Additional Y offset to apply for the name tag
Color_RGBA8 textColor; // Text color override. Global color is used if alpha is 0
uint8_t noZBuffer; // Allow rendering over geometry
} NameTagOptions;
// Register required hooks for nametags on startup
@ -28,4 +33,4 @@ void NameTag_RemoveAllByTag(const char* tag);
}
#endif
#endif // _NAMETAG_H_
#endif // NAMETAG_H

View file

@ -219,18 +219,18 @@ void ProcessExits(Region* region, GetAccessibleLocationsStruct& gals, Randomizer
}
ValidateSphereZero(gals);
}
// If the exit is accessible and hasn't been added yet, add it to the pool
// RANDOTODO do we want to add the region after the loop now, considering we
// are processing the new region immediately. Maybe a reverse for loop in ProcessRegion?
if (!exitRegion->addedToPool) {
exitRegion->addedToPool = true;
gals.regionPool.push_back(exit.GetConnectedRegionKey());
}
// process the region we just expanded to, to reduce looping
ProcessRegion(exitRegion, gals, ignore, stopOnBeatable, addToPlaythrough);
}
// If the exit is accessible and hasn't been added yet, add it to the pool
// RANDOTODO do we want to add the region after the loop now, considering we
// are processing the new region immediately. Maybe a reverse for loop in ProcessRegion?
if (!exitRegion->addedToPool && exit.ConditionsMet()) {
exitRegion->addedToPool = true;
gals.regionPool.push_back(exit.GetConnectedRegionKey());
}
if (addToPlaythrough) {
// RANDOTODO Should this match the regular spheres?
// Add shuffled entrances to the entrance playthrough
@ -327,13 +327,12 @@ bool IsBeatableWithout(RandomizerCheck excludedCheck, bool replaceItem,
auto ctx = Rando::Context::GetInstance();
RandomizerGet copy = ctx->GetItemLocation(excludedCheck)->GetPlacedRandomizerGet(); // Copy out item
ctx->GetItemLocation(excludedCheck)->SetPlacedItem(RG_NONE); // Write in empty item
ctx->playthroughBeatable = false;
logic->Reset();
CheckBeatable(ignore);
bool result = CheckBeatable(ignore);
if (replaceItem) {
ctx->GetItemLocation(excludedCheck)->SetPlacedItem(copy); // Immediately put item back
}
return ctx->playthroughBeatable;
return result;
}
// Reset non-Logic-class logic, and optionally apply the initial inventory
@ -581,6 +580,7 @@ void GeneratePlaythrough() {
// return if the seed is currently beatable or not
bool CheckBeatable(RandomizerGet ignore /* = RG_NONE*/) {
auto ctx = Rando::Context::GetInstance();
ctx->playthroughBeatable = false;
GetAccessibleLocationsStruct gals(0);
ResetLogic(ctx, gals, true);
do {
@ -625,6 +625,8 @@ void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAcce
if (ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES).Is(RO_INTERIOR_ENTRANCE_SHUFFLE_OFF)) {
Rando::StaticData::RetrieveItem(RG_GUARD_HOUSE_KEY).ApplyEffect();
}
RegionTable(RR_ROOT)->adultNight = true;
RegionTable(RR_ROOT)->adultDay = true;
} else {
ApplyAllAdvancmentItems();
}
@ -710,11 +712,11 @@ static void PareDownPlaythrough() {
auto ctx = Rando::Context::GetInstance();
std::vector<RandomizerCheck> toAddBackItem;
// Start at sphere before Ganon's and count down
for (int i = ctx->playthroughLocations.size() - 2; i >= 0; i--) {
for (int32_t i = static_cast<int32_t>(ctx->playthroughLocations.size()) - 2; i >= 0; i--) {
// Check each item location in sphere
std::vector<int> erasableIndices;
std::vector<RandomizerCheck> sphere = ctx->playthroughLocations.at(i);
for (int j = sphere.size() - 1; j >= 0; j--) {
for (int32_t j = static_cast<int32_t>(sphere.size()) - 1; j >= 0; j--) {
RandomizerCheck loc = sphere.at(j);
RandomizerGet locGet = ctx->GetItemLocation(loc)->GetPlacedRandomizerGet(); // Copy out item
@ -929,10 +931,8 @@ static void AssumedFill(const std::vector<RandomizerGet>& items, const std::vect
// If ALR is off, then we check beatability after placing the item.
// If the game is beatable, then we can stop placing items with logic.
if (!ctx->GetOption(RSK_ALL_LOCATIONS_REACHABLE)) {
ctx->playthroughBeatable = false;
logic->Reset();
CheckBeatable();
if (ctx->playthroughBeatable) {
if (CheckBeatable()) {
SPDLOG_DEBUG("Game beatable, now placing items randomly. " + std::to_string(itemsToPlace.size()) +
" major items remaining.\n\n");
FastFill(itemsToPlace, GetEmptyLocations(allowedLocations), true);

View file

@ -72,4 +72,4 @@ void GeneratePlaythrough();
bool CheckBeatable(RandomizerGet ignore = RG_NONE);
void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAccess);
void ValidateEntrances(bool checkPoeCollectorAccess, bool checkOtherEntranceAccess);

View file

@ -2467,13 +2467,13 @@ void StaticData::HintTable_Init() {
/*german*/ "ein abgelegener Ort",
/*french*/ "un lieu isolé"));
hintTextTable[RHT_DUNGEON_ORDINARY] = HintText(CustomMessage(" It's ordinary.",
/*german*/ "&Sieht aus wie immer.",
/*french*/ "&Elle vous semble %rordinaire%w."));
hintTextTable[RHT_DUNGEON_ORDINARY] = HintText(CustomMessage("&It's %gordinary%w.",
/*german*/ "&Sieht aus %gwie immer%w.",
/*french*/ "&Elle vous semble %gordinaire%w."));
hintTextTable[RHT_DUNGEON_MASTERFUL] = HintText(CustomMessage(" It's masterful!",
/*german*/ "&Man kann darauf die Worte&%r\"Master Quest\"%w entziffern...",
/*french*/ "&Étrange... les mots %r\"Master&Quest\"%w sont gravés dessus."));
hintTextTable[RHT_DUNGEON_MASTERFUL] = HintText(CustomMessage("&It's %rmasterful%w!",
/*german*/ "&Man kann darauf die Worte %r\"Master_Quest\"%w entziffern...",
/*french*/ "&Étrange... les mots %r\"Master_Quest\"%w sont gravés dessus."));
// clang-format on
}

View file

@ -63,11 +63,11 @@ const CustomMessage& HintText::GetAmbiguous(uint8_t selection) const {
}
uint8_t HintText::GetAmbiguousSize() const {
return ambiguousText.size();
return static_cast<uint8_t>(ambiguousText.size());
}
uint8_t HintText::GetObscureSize() const {
return obscureText.size();
return static_cast<uint8_t>(obscureText.size());
}
const CustomMessage& HintText::GetHintMessage(uint8_t selection) const {
@ -598,7 +598,7 @@ static void DistributeHints(std::vector<uint8_t>& selected, size_t stoneCount,
}
// if stones are left, assign junk to every remaining stone as a fallback.
if (stoneCount > 0) {
selected[selected.size() - 1] += stoneCount;
selected[static_cast<uint8_t>(selected.size()) - 1] += static_cast<uint8_t>(stoneCount);
}
}

View file

@ -325,7 +325,7 @@ RandomizerGet GetJunkItem() {
return RandomElement(JunkPoolItems);
}
// Ice Trap is the last item in JunkPoolItems, so subtract 1 to never hit that index
uint8_t idx = Random(0, JunkPoolItems.size() - 1);
uint8_t idx = Random(0, static_cast<uint32_t>(JunkPoolItems.size()) - 1);
return JunkPoolItems[idx];
}

View file

@ -27,7 +27,7 @@ bool GenerateRandomizer(std::set<RandomizerCheck> excludedLocations, std::set<Ra
ResetPerformanceTimers();
StartPerformanceTimer(PT_WHOLE_SEED);
srand(time(NULL));
srand(static_cast<uint32_t>(time(NULL)));
// if a blank seed was entered, make a random one
if (seedInput.empty()) {
seedInput = std::to_string(rand() % 0xFFFFFFFF);
@ -35,7 +35,7 @@ bool GenerateRandomizer(std::set<RandomizerCheck> excludedLocations, std::set<Ra
int count;
try {
count = std::stoi(seedInput.substr(18), nullptr);
} catch (std::invalid_argument& e) { count = 1; } catch (std::out_of_range& e) {
} catch (std::invalid_argument&) { count = 1; } catch (std::out_of_range&) {
count = 1;
}
Playthrough::Playthrough_Repeat(excludedLocations, enabledTricks, count);

View file

@ -14,8 +14,7 @@ void Random_Init(uint32_t seed) {
generator = boost::random::mt19937{ seed };
}
// Returns a random integer in range [min, max-1]
uint32_t Random(int min, int max) {
void Random_InitSeed() {
if (!init) {
// No seed given, get a random number from device to seed
#if !defined(__SWITCH__) && !defined(__WIIU__)
@ -25,11 +24,16 @@ uint32_t Random(int min, int max) {
#endif
Random_Init(seed);
}
}
// Returns a random unsigned integer in range [min, max-1]
uint32_t Random(uint32_t min, uint32_t max) {
Random_InitSeed();
boost::random::uniform_int_distribution<uint32_t> distribution(min, max - 1);
return distribution(generator);
}
// Returns a random floating point number in [0.0, 1.0]
// Returns a random floating point number in [0.0, 1.0)
double RandomDouble() {
boost::random::uniform_real_distribution<double> distribution(0.0, 1.0);
return distribution(generator);

View file

@ -8,12 +8,12 @@
#include <set>
void Random_Init(uint32_t seed);
uint32_t Random(int min, int max);
uint32_t Random(uint32_t min, uint32_t max);
double RandomDouble();
// Get a random element from a vector or array
template <typename T> T RandomElement(std::vector<T>& vector, bool erase) {
const auto idx = Random(0, vector.size());
const auto idx = Random(0, static_cast<uint32_t>(vector.size()));
const T selected = vector[idx];
if (erase) {
vector.erase(vector.begin() + idx);
@ -21,17 +21,17 @@ template <typename T> T RandomElement(std::vector<T>& vector, bool erase) {
return selected;
}
template <typename Container> auto& RandomElement(Container& container) {
return container[Random(0, std::size(container))];
return container[Random(0, static_cast<uint32_t>(std::size(container)))];
}
template <typename Container> const auto& RandomElement(const Container& container) {
return container[Random(0, std::size(container))];
return container[Random(0, static_cast<uint32_t>(std::size(container)))];
}
template <typename T> const T RandomElementFromSet(const std::set<T>& set) {
if (set.size() == 1) {
return *set.begin();
}
uint32_t rand = Random(0, set.size());
uint32_t rand = Random(0, static_cast<uint32_t>(set.size()));
auto it = set.begin();
for (uint32_t i = 0; i < rand; i++) {
it++;
@ -43,12 +43,12 @@ template <typename T> const T RandomElementFromSet(const std::set<T>& set) {
// Shuffle items within a vector or array
// RANDOTODO There's probably a more efficient way to do what this does.
template <typename T> void Shuffle(std::vector<T>& vector) {
for (std::size_t i = 0; i + 1 < vector.size(); i++) {
std::swap(vector[i], vector[Random(i, vector.size())]);
for (size_t i = 0; i + 1 < vector.size(); i++) {
std::swap(vector[i], vector[Random(static_cast<uint32_t>(i), static_cast<uint32_t>(vector.size()))]);
}
}
template <typename T, std::size_t size> void Shuffle(std::array<T, size>& arr) {
for (std::size_t i = 0; i + 1 < arr.size(); i++) {
std::swap(arr[i], arr[Random(i, arr.size())]);
template <typename T, size_t size> void Shuffle(std::array<T, size>& arr) {
for (size_t i = 0; i + 1 < arr.size(); i++) {
std::swap(arr[i], arr[Random(static_cast<uint32_t>(i), static_cast<uint32_t>(arr.size()))]);
}
}

View file

@ -115,7 +115,7 @@ uint16_t GetPriceFromSettings(Rando::Location* loc, PriceSettingsStruct priceSet
if (random < ShopPriceProbability[i]) {
// The randomly generated value has surpassed the total probability up to this point, so this is the
// generated price i in range [0, 59], output in range [0, 295] in increments of 5
return i * 5;
return static_cast<uint16_t>(i) * 5;
}
}
return 150;
@ -196,7 +196,8 @@ uint16_t GetCheapBalancedPrice() {
double random = RandomDouble();
for (size_t i = 0; i < CheapPriceProbability.size(); i++) {
if (random < CheapPriceProbability[i]) {
return i * 5; // i in range [0, 19], output in range [0, 95] in increments of 5
// i in range [0, 19], output in range [0, 95] in increments of 5
return static_cast<uint16_t>(i) * 5;
}
}
return -1;

View file

@ -632,7 +632,7 @@ void PlandomizerLoadSpoilerLog(std::string logFile) {
PlandomizerAddToItemList(plandomizerRandoRetrieveItem(RG_SOLD_OUT));
}
}
} catch (nlohmann::json::parse_error& e) {
} catch (nlohmann::json::parse_error&) {
Notification::Emit({ .message = "Invalid Spoiler Log Format", .remainingTime = 10.0f });
}
}
@ -967,7 +967,7 @@ void PlandomizerDrawOptions() {
}
ImGui::TableNextColumn();
size_t index = 0;
int32_t index = 0;
PlandoPushImageButtonStyle();
for (auto& hash : plandoHash) {
ImGui::PushID(index);
@ -995,7 +995,7 @@ void PlandomizerDrawOptions() {
ImGui::PopStyleVar();
if (downRet) {
if (hash == 0) {
hash = gSeedTextures.size() - 1;
hash = static_cast<int32_t>(gSeedTextures.size()) - 1;
} else {
hash--;
}

View file

@ -16,7 +16,7 @@ extern "C" {
#include "soh/Enhancements/randomizer/item.h"
#ifdef __cplusplus
class PlandomizerWindow : public Ship::GuiWindow {
class PlandomizerWindow final : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;

View file

@ -19,7 +19,7 @@ void EnCow_MoveForRandomizer(EnCow* enCow, PlayState* play) {
// Move left cow in lon lon tower
enCow->actor.world.pos.x = -229.0f;
enCow->actor.world.pos.z = 157.0f;
enCow->actor.shape.rot.y = 15783.0f;
enCow->actor.shape.rot.y = 15783;
moved = true;
} else if (play->sceneNum == SCENE_STABLE && enCow->actor.world.pos.x == -3 && enCow->actor.world.pos.z == -254) {
// Move right cow in lon lon stable
@ -39,7 +39,8 @@ void RegisterShuffleCows() {
COND_VB_SHOULD(VB_GIVE_ITEM_FROM_COW, shouldRegister, {
EnCow* enCow = va_arg(args, EnCow*);
CowIdentity cowIdentity = OTRGlobals::Instance->gRandomizer->IdentifyCow(
gPlayState->sceneNum, enCow->actor.world.pos.x, enCow->actor.world.pos.z);
gPlayState->sceneNum, static_cast<int32_t>(enCow->actor.world.pos.x),
static_cast<int32_t>(enCow->actor.world.pos.z));
// Has this cow already rewarded an item?
if (!Flags_GetRandomizerInf(cowIdentity.randomizerInf)) {
Flags_SetRandomizerInf(cowIdentity.randomizerInf);

View file

@ -3,6 +3,7 @@
#include "static_data.h"
#include <libultraship/libultra.h>
#include "global.h"
#include "soh/ResourceManagerHelpers.h"
extern "C" {
#include "variables.h"
@ -11,7 +12,6 @@ extern "C" {
#include "overlays/actors/ovl_Obj_Kibako/z_obj_kibako.h"
#include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "soh/ResourceManagerHelpers.h"
extern PlayState* gPlayState;
}
@ -195,7 +195,7 @@ void ObjKibako2_RandomizerSpawnCollectible(ObjKibako2* crateActor, PlayState* pl
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
item00->actor.velocity.y = 8.0f;
item00->actor.speedXZ = 2.0f;
item00->actor.world.rot.y = Rand_CenteredFloat(65536.0f);
item00->actor.world.rot.y = static_cast<int16_t>(Rand_CenteredFloat(65536.0f));
}
void ObjKibako_RandomizerSpawnCollectible(ObjKibako* smallCrateActor, PlayState* play) {
@ -206,7 +206,7 @@ void ObjKibako_RandomizerSpawnCollectible(ObjKibako* smallCrateActor, PlayState*
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
item00->actor.velocity.y = 8.0f;
item00->actor.speedXZ = 2.0f;
item00->actor.world.rot.y = Rand_CenteredFloat(65536.0f);
item00->actor.world.rot.y = static_cast<int16_t>(Rand_CenteredFloat(65536.0f));
}
void ObjKibako2_RandomizerInit(void* actorRef) {
@ -535,6 +535,8 @@ void Rando::StaticData::RegisterCrateLocations() {
locationTable[RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2] = Location::SmallCrate(RC_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2, RCQUEST_VANILLA, RCAREA_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE, TWO_ACTOR_PARAMS(-1151, -939), "Before Child Climb Small Crate 2", RHT_CRATE_SPIRIT_TEMPLE, RG_DEKU_NUTS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_SPIRIT_TEMPLE_BEFORE_CHILD_CLIMB_SMALL_CRATE_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-512, -4592), "MQ Triple Hallway Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-666, -4671), "MQ Triple Hallway Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1381, -2115), "MQ Jigglies Small Crate 1", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2] = Location::SmallCrate(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1341, -2116), "MQ Jigglies Small Crate 2", RHT_CRATE_JABU_JABU, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(1599, -1322), "MQ Frozen Eye Switch Small Crate 1", RHT_CRATE_FOREST_TEMPLE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2364, -873), "MQ Frozen Eye Switch Small Crate 2", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2));
locationTable[RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3] = Location::SmallCrate(RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3, RCQUEST_MQ, RCAREA_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, TWO_ACTOR_PARAMS(2312, -874), "MQ Frozen Eye Switch Small Crate 3", RHT_CRATE_FOREST_TEMPLE, RG_ARROWS_5, SpoilerCollectionCheck::RandomizerInf(RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3));

View file

@ -117,7 +117,7 @@ void EnKusa_RandomizerSpawnCollectible(EnKusa* grassActor, PlayState* play) {
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
item00->actor.velocity.y = 8.0f;
item00->actor.speedXZ = 2.0f;
item00->actor.world.rot.y = Rand_CenteredFloat(65536.0f);
item00->actor.world.rot.y = static_cast<int16_t>(Rand_CenteredFloat(65536.0f));
}
void EnKusa_RandomizerInit(void* actorRef) {
@ -497,7 +497,7 @@ void Rando::StaticData::RegisterGrassLocations() {
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-91, -2815), "MQ Basement Grass 1", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1));
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(231, -3575), "MQ Basement Grass 2", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2));
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(305, -3481), "MQ Basement Grass 3", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3));
locationTable[RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1089, -1489), "MQ Wigglers Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS));
locationTable[RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1089, -1489), "MQ Jigglies Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS));
locationTable[RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(652, -5687), "MQ Like Like Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS));
locationTable[RC_JABU_JABUS_BELLY_MQ_BASEMENT_BOOMERANG_GRASS] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_BASEMENT_BOOMERANG_GRASS, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(1228, -2647), "MQ Basement Boomerang Grass", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_BOOMERANG_GRASS));
locationTable[RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1] = Location::Grass(RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1, RCQUEST_MQ, RCAREA_JABU_JABUS_BELLY, SCENE_JABU_JABU, TWO_ACTOR_PARAMS(-1360, -3606), "MQ After Big Octo Grass 1", RHT_JABU_JABUS_BELLY_GRASS, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1));

View file

@ -48,7 +48,7 @@ void ObjTsubo_RandomizerSpawnCollectible(ObjTsubo* potActor, PlayState* play) {
item00->actor.draw = (ActorFunc)EnItem00_DrawRandomizedItem;
item00->actor.velocity.y = 8.0f;
item00->actor.speedXZ = 2.0f;
item00->actor.world.rot.y = Rand_CenteredFloat(65536.0f);
item00->actor.world.rot.y = static_cast<int16_t>(Rand_CenteredFloat(65536.0f));
}
void ObjTsubo_RandomizerInit(void* actorRef) {

View file

@ -597,7 +597,7 @@ extern "C" s32 OverrideLimbDrawBarinade(PlayState* play, s32 limbIndex, Gfx** dL
(uintptr_t)Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 8, 16, 1, 0,
(play->gameplayFrames * -2) % 64, 16, 16));
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 200);
Matrix_RotateX(-M_PI / 2, MTXMODE_APPLY);
Matrix_RotateX(-M_PIf / 2.0f, MTXMODE_APPLY);
} else if ((limbIndex >= 10) && (limbIndex < 20)) {
rot->x -= 0x4000;
*dList = NULL;
@ -1097,7 +1097,7 @@ extern "C" void Randomizer_DrawBronzeScale(PlayState* play, GetItemEntry* getIte
gSPSegment(POLY_XLU_DISP++, 0x08,
(uintptr_t)Gfx_TwoTexScroll(play->state.gfxCtx, 0, 1 * (play->state.frames * 2),
-1 * (play->state.frames * 2), 64, 64, 1, 1 * (play->state.frames * 4),
1 * -(play->state.frames * 4), 32, 32));
-1 * (play->state.frames * 4), 32, 32));
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_MODELVIEW | G_MTX_LOAD);
@ -1116,7 +1116,7 @@ extern "C" void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getI
// Draw rod
Gfx_SetupDL_25Opa(play->state.gfxCtx);
Matrix_Scale(0.2, 0.2, 0.2, MTXMODE_APPLY);
Matrix_Scale(0.2f, 0.2f, 0.2f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gFishingPoleGiDL);
@ -1126,8 +1126,8 @@ extern "C" void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getI
Matrix_Scale(5.0f, 5.0f, 5.0f, MTXMODE_APPLY);
pos = { 0.0f, -25.5f, -4.0f };
Matrix_Translate(pos.x, pos.y, pos.z, MTXMODE_APPLY);
Matrix_RotateZ(-M_PI_2, MTXMODE_APPLY);
Matrix_RotateY(-M_PI_2 - 0.2f, MTXMODE_APPLY);
Matrix_RotateZ(-M_PI_2f, MTXMODE_APPLY);
Matrix_RotateY(-M_PI_2f - 0.2f, MTXMODE_APPLY);
Matrix_Scale(0.006f, 0.006f, 0.006f, MTXMODE_APPLY);
Gfx_SetupDL_25Opa(play->state.gfxCtx);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
@ -1140,7 +1140,7 @@ extern "C" void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getI
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gFishingLureHookDL);
Matrix_RotateZ(M_PI_2, MTXMODE_APPLY);
Matrix_RotateZ(M_PI_2f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gFishingLureHookDL);
@ -1149,7 +1149,7 @@ extern "C" void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getI
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gFishingLureHookDL);
Matrix_RotateZ(M_PI / 2, MTXMODE_APPLY);
Matrix_RotateZ(M_PIf / 2.0f, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gFishingLureHookDL);

View file

@ -1489,62 +1489,62 @@ int EntranceShuffler::ShuffleAllEntrances() {
// If a boss room is inside a boss door, make the blue warp go outside the dungeon's entrance
std::map<std::string, Entrance*> bossExits = {
{ EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_DEKU_TREE_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_ENTRYWAY, RR_KF_OUTSIDE_DEKU_TREE)) },
GetEntrance(RR_DEKU_TREE_ENTRYWAY, RR_KF_OUTSIDE_DEKU_TREE) },
{ EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DODONGOS_CAVERN_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_ENTRYWAY, RR_DEATH_MOUNTAIN_TRAIL)) },
GetEntrance(RR_DODONGOS_CAVERN_ENTRYWAY, RR_DEATH_MOUNTAIN_TRAIL) },
{ EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_ENTRYWAY, RR_ZORAS_FOUNTAIN)) },
GetEntrance(RR_JABU_JABUS_BELLY_ENTRYWAY, RR_ZORAS_FOUNTAIN) },
{ EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_FOREST_TEMPLE_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_ENTRYWAY, RR_SACRED_FOREST_MEADOW)) },
GetEntrance(RR_FOREST_TEMPLE_ENTRYWAY, RR_SACRED_FOREST_MEADOW) },
{ EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_FIRE_TEMPLE_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_ENTRYWAY, RR_DMC_CENTRAL_LOCAL)) },
GetEntrance(RR_FIRE_TEMPLE_ENTRYWAY, RR_DMC_CENTRAL_LOCAL) },
{ EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_WATER_TEMPLE_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_ENTRYWAY, RR_LAKE_HYLIA)) },
GetEntrance(RR_WATER_TEMPLE_ENTRYWAY, RR_LAKE_HYLIA) },
{ EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE)) },
GetEntrance(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE) },
{ EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY),
GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION)) },
GetEntrance(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION) },
};
// If a boss room is inside a dungeon entrance (or inside a dungeon which is inside a dungeon entrance), make
// the blue warp go to that dungeon's blue warp target
std::map<std::string, Entrance*> dungeonExits = {
{ EntranceNameByRegions(RR_DEKU_TREE_ENTRYWAY, RR_KF_OUTSIDE_DEKU_TREE),
GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE)) },
GetEntrance(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE) },
{ EntranceNameByRegions(RR_DODONGOS_CAVERN_ENTRYWAY, RR_DEATH_MOUNTAIN_TRAIL),
GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL)) },
GetEntrance(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL) },
{ EntranceNameByRegions(RR_JABU_JABUS_BELLY_ENTRYWAY, RR_ZORAS_FOUNTAIN),
GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN)) },
GetEntrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN) },
{ EntranceNameByRegions(RR_FOREST_TEMPLE_ENTRYWAY, RR_SACRED_FOREST_MEADOW),
GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW)) },
GetEntrance(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW) },
{ EntranceNameByRegions(RR_FIRE_TEMPLE_ENTRYWAY, RR_DMC_CENTRAL_LOCAL),
GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL)) },
GetEntrance(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL) },
{ EntranceNameByRegions(RR_WATER_TEMPLE_ENTRYWAY, RR_LAKE_HYLIA),
GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA)) },
GetEntrance(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA) },
{ EntranceNameByRegions(RR_SPIRIT_TEMPLE_ENTRYWAY, RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE),
GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS)) },
GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS) },
{ EntranceNameByRegions(RR_SHADOW_TEMPLE_ENTRYWAY, RR_GRAVEYARD_WARP_PAD_REGION),
GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION)) },
GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION) },
};
// Pair <BlueWarp exit, BossRoom reverse exit>
std::vector<EntrancePair> bossRoomExitPairs = {
{ GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE)),
GetEntrance(EntranceNameByRegions(RR_DEKU_TREE_BOSS_ROOM, RR_DEKU_TREE_BOSS_ENTRYWAY)) },
{ GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL)),
GetEntrance(EntranceNameByRegions(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DODONGOS_CAVERN_BOSS_ENTRYWAY)) },
{ GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN)),
GetEntrance(EntranceNameByRegions(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY)) },
{ GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW)),
GetEntrance(EntranceNameByRegions(RR_FOREST_TEMPLE_BOSS_ROOM, RR_FOREST_TEMPLE_BOSS_ENTRYWAY)) },
{ GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL)),
GetEntrance(EntranceNameByRegions(RR_FIRE_TEMPLE_BOSS_ROOM, RR_FIRE_TEMPLE_BOSS_ENTRYWAY)) },
{ GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA)),
GetEntrance(EntranceNameByRegions(RR_WATER_TEMPLE_BOSS_ROOM, RR_WATER_TEMPLE_BOSS_ENTRYWAY)) },
{ GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS)),
GetEntrance(EntranceNameByRegions(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY)) },
{ GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION)),
GetEntrance(EntranceNameByRegions(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY)) },
{ GetEntrance(RR_DEKU_TREE_BOSS_ROOM, RR_KF_OUTSIDE_DEKU_TREE),
GetEntrance(RR_DEKU_TREE_BOSS_ROOM, RR_DEKU_TREE_BOSS_ENTRYWAY) },
{ GetEntrance(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DEATH_MOUNTAIN_TRAIL),
GetEntrance(RR_DODONGOS_CAVERN_BOSS_ROOM, RR_DODONGOS_CAVERN_BOSS_ENTRYWAY) },
{ GetEntrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_ZORAS_FOUNTAIN),
GetEntrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY) },
{ GetEntrance(RR_FOREST_TEMPLE_BOSS_ROOM, RR_SACRED_FOREST_MEADOW),
GetEntrance(RR_FOREST_TEMPLE_BOSS_ROOM, RR_FOREST_TEMPLE_BOSS_ENTRYWAY) },
{ GetEntrance(RR_FIRE_TEMPLE_BOSS_ROOM, RR_DMC_CENTRAL_LOCAL),
GetEntrance(RR_FIRE_TEMPLE_BOSS_ROOM, RR_FIRE_TEMPLE_BOSS_ENTRYWAY) },
{ GetEntrance(RR_WATER_TEMPLE_BOSS_ROOM, RR_LAKE_HYLIA),
GetEntrance(RR_WATER_TEMPLE_BOSS_ROOM, RR_WATER_TEMPLE_BOSS_ENTRYWAY) },
{ GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_DESERT_COLOSSUS),
GetEntrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY) },
{ GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_GRAVEYARD_WARP_PAD_REGION),
GetEntrance(RR_SHADOW_TEMPLE_BOSS_ROOM, RR_SHADOW_TEMPLE_BOSS_ENTRYWAY) },
};
for (EntrancePair pair : bossRoomExitPairs) {
@ -1645,7 +1645,7 @@ void EntranceShuffler::ParseJson(nlohmann::json spoilerFileJson) {
try {
nlohmann::json entrancesJson = spoilerFileJson["entrances"];
size_t i = 0;
for (auto it = entrancesJson.begin(); it != entrancesJson.end(); ++it, i++) {
for (auto it = entrancesJson.begin(); it != entrancesJson.end() && i < entranceOverrides.size(); ++it, i++) {
nlohmann::json entranceJson = *it;
for (auto entranceIt = entranceJson.begin(); entranceIt != entranceJson.end(); ++entranceIt) {
if (entranceIt.key() == "type") {

View file

@ -90,7 +90,7 @@ class Entrance {
Entrance* reverse = nullptr;
Entrance* assumed = nullptr;
Entrance* replacement = nullptr;
int16_t index = 0xFFFF;
int16_t index = -1;
bool shuffled = false;
bool primary = false;
bool addedToPool = false;

View file

@ -136,8 +136,9 @@ Fishsanity::GetFishingPondLocations(FishsanityOptionsSource optionsSource) {
}
// NOTE: This only works because we can assume activeFish is already sorted; changes that break this assumption will
// also break this
FilterAndEraseFromPool(remainingFish,
[&](uint32_t loc) { return std::binary_search(activeFish.begin(), activeFish.end(), loc); });
FilterAndEraseFromPool(remainingFish, [&](RandomizerCheck loc) {
return std::binary_search(activeFish.begin(), activeFish.end(), loc);
});
return std::make_pair(activeFish, remainingFish);
}

View file

@ -226,7 +226,8 @@ uint8_t Hint::GetNumberOfMessages() const {
if (numMessages == 0) {
numMessages = 1; // RANDOTODO make std::max actually fucking work for 3 arguments
}
return numMessages;
// RANDOTODO will number of messages always be u8?
return static_cast<uint8_t>(numMessages);
}
const std::vector<std::string> Hint::GetAllMessageStrings(MessageFormat format) const {

View file

@ -328,7 +328,7 @@ void RandomizerOnPlayerUpdateForRCQueueHandler() {
(getItemEntry.getItemCategory == ITEM_CATEGORY_JUNK ||
getItemEntry.getItemCategory == ITEM_CATEGORY_SKULLTULA_TOKEN ||
getItemEntry.getItemCategory == ITEM_CATEGORY_LESSER))))) {
Item_DropCollectible(gPlayState, &spawnPos, ITEM00_SOH_GIVE_ITEM_ENTRY | 0x8000);
Item_DropCollectible(gPlayState, &spawnPos, static_cast<int16_t>(ITEM00_SOH_GIVE_ITEM_ENTRY | 0x8000));
}
}
@ -1013,7 +1013,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
if (item00->itemEntry.getItemId == GI_SWORD_BGS) {
gSaveContext.bgsFlag = true;
}
Item_Give(gPlayState, item00->itemEntry.itemId);
Item_Give(gPlayState, static_cast<uint8_t>(item00->itemEntry.itemId));
} else if (item00->itemEntry.modIndex == MOD_RANDOMIZER) {
if (item00->itemEntry.getItemId == RG_ICE_TRAP) {
gSaveContext.ship.pendingIceTrapCount++;
@ -2137,27 +2137,27 @@ void RandomizerOnActorInitHandler(void* actorRef) {
void RandomizerOnGameFrameUpdateHandler() {
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_QUIVER)) {
AMMO(ITEM_BOW) = CUR_CAPACITY(UPG_QUIVER);
AMMO(ITEM_BOW) = static_cast<int8_t>(CUR_CAPACITY(UPG_QUIVER));
}
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BOMB_BAG)) {
AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG);
AMMO(ITEM_BOMB) = static_cast<int8_t>(CUR_CAPACITY(UPG_BOMB_BAG));
}
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BULLET_BAG)) {
AMMO(ITEM_SLINGSHOT) = CUR_CAPACITY(UPG_BULLET_BAG);
AMMO(ITEM_SLINGSHOT) = static_cast<int8_t>(CUR_CAPACITY(UPG_BULLET_BAG));
}
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_STICK_UPGRADE)) {
AMMO(ITEM_STICK) = CUR_CAPACITY(UPG_STICKS);
AMMO(ITEM_STICK) = static_cast<int8_t>(CUR_CAPACITY(UPG_STICKS));
}
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_NUT_UPGRADE)) {
AMMO(ITEM_NUT) = CUR_CAPACITY(UPG_NUTS);
AMMO(ITEM_NUT) = static_cast<int8_t>(CUR_CAPACITY(UPG_NUTS));
}
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MAGIC_METER)) {
gSaveContext.magic = gSaveContext.magicCapacity;
gSaveContext.magic = static_cast<int8_t>(gSaveContext.magicCapacity);
}
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_BOMBCHUS)) {
@ -2165,7 +2165,7 @@ void RandomizerOnGameFrameUpdateHandler() {
}
if (Flags_GetRandomizerInf(RAND_INF_HAS_INFINITE_MONEY)) {
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
gSaveContext.rupees = static_cast<int8_t>(CUR_CAPACITY(UPG_WALLET));
}
if (!Flags_GetRandomizerInf(RAND_INF_HAS_WALLET)) {
@ -2203,7 +2203,8 @@ void RandomizerOnActorUpdateHandler(void* refActor) {
if (actor->id == ACTOR_OBJ_COMB) {
ObjComb* combActor = reinterpret_cast<ObjComb*>(actor);
combActor->actor.shape.rot.x =
Math_SinS(combActor->unk_1B2) * CLAMP_MIN(combActor->unk_1B0, 0) + combActor->actor.home.rot.x;
static_cast<int16_t>(Math_SinS(combActor->unk_1B2)) * CLAMP_MIN(combActor->unk_1B0, 0) +
combActor->actor.home.rot.x;
}
}
@ -2216,29 +2217,29 @@ typedef struct {
// special respawns used when voided out without swim to prevent infinite loops
std::map<s32, SpecialRespawnInfo> swimSpecialRespawnInfo = {
{ ENTR_ZORAS_RIVER_3, // hf to zr in water
{ { -1455.443, -20, 1384.826 }, 28761 } },
{ { -1455.443f, -20.0f, 1384.826f }, 28761 } },
{ ENTR_HYRULE_FIELD_14, // zr to hf in water
{ { 5730.209, -20, 3725.911 }, -20025 } },
{ { 5730.209f, -20.0f, 3725.911f }, -20025 } },
{ ENTR_LOST_WOODS_UNDERWATER_SHORTCUT, // zr to lw
{ { 1978.718, -36.908, -855 }, -16384 } },
{ { 1978.718f, -36.908f, -855.0f }, -16384 } },
{ ENTR_ZORAS_RIVER_UNDERWATER_SHORTCUT, // lw to zr
{ { 4082.366, 860.442, -1018.949 }, -32768 } },
{ { 4082.366f, 860.442f, -1018.949f }, -32768 } },
{ ENTR_LAKE_HYLIA_RIVER_EXIT, // gv to lh
{ { -3276.416, -1033, 2908.421 }, 11228 } },
{ { -3276.416f, -1033.0f, 2908.421f }, 11228 } },
{ ENTR_WATER_TEMPLE_ENTRANCE, // lh to water temple
{ { -182, 780, 759.5 }, -32768 } },
{ { -182.0f, 780.0f, 759.5f }, -32768 } },
{ ENTR_LAKE_HYLIA_OUTSIDE_TEMPLE, // water temple to lh
{ { -955.028, -1306.9, 6768.954 }, -32768 } },
{ { -955.028f, -1306.9f, 6768.954f }, -32768 } },
{ ENTR_ZORAS_DOMAIN_UNDERWATER_SHORTCUT, // lh to zd
{ { -109.86, 11.396, -9.933 }, -29131 } },
{ { -109.86f, 11.396f, -9.933f }, -29131 } },
{ ENTR_LAKE_HYLIA_UNDERWATER_SHORTCUT, // zd to lh
{ { -912, -1326.967, 3391 }, 0 } },
{ { -912.0f, -1326.967f, 3391.0f }, 0 } },
{ ENTR_GERUDO_VALLEY_1, // caught by gerudos as child
{ { -424, -2051, -74 }, 16384 } },
{ { -424.0f, -2051.0f, -74.0f }, 16384 } },
{ ENTR_HYRULE_FIELD_ON_BRIDGE_SPAWN, // mk to hf (can be a problem when it then turns night)
{ { 0, 0, 1100 }, 0 } },
{ { 0.0f, 0.0f, 1100.0f }, 0 } },
{ ENTR_ZORAS_FOUNTAIN_JABU_JABU_BLUE_WARP, // jabu blue warp to zf
{ { -1580, 150, 1670 }, 8000 } },
{ { -1580.0f, 150.0f, 1670.0f }, 8000 } },
};
f32 triforcePieceScale;
@ -2298,8 +2299,8 @@ void RandomizerOnSceneSpawnActorsHandler() {
switch (gPlayState->sceneNum) {
case SCENE_TEMPLE_OF_TIME:
if (gPlayState->roomCtx.curRoom.num == 1) {
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_XC, -104, -40, 2382, 0, 0x8000, 0,
SHEIK_TYPE_RANDO, false);
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_XC, -104, -40, 2382, 0,
static_cast<int16_t>(0x8000), 0, SHEIK_TYPE_RANDO, false);
}
break;
case SCENE_INSIDE_GANONS_CASTLE:

View file

@ -286,12 +286,12 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_TREASURE_GAME_HEART] = Item(RG_TREASURE_GAME_HEART, Text{ "Piece of Heart (WINNER)", "Quart de Coeur (Chasse-aux-Trésors)", "Herzstück (Schatztruhenminispiel)" }, ITEMTYPE_ITEM, GI_HEART_PIECE_WIN, true, LOGIC_PIECE_OF_HEART, RHT_TREASURE_GAME_HEART, ITEM_HEART_PIECE_2, OBJECT_GI_HEARTS, GID_HEART_PIECE, 0xFA, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_NONE);
itemTable[RG_TREASURE_GAME_GREEN_RUPEE] = Item(RG_TREASURE_GAME_GREEN_RUPEE, Text{ "Green Rupee (LOSER)", "Rubis Vert (Chasse-aux-Trésors)", "Grüner Rubin (Schatztruhenminispiel)" }, ITEMTYPE_ITEM, GI_RUPEE_GREEN_LOSE, false, LOGIC_NONE, RHT_TREASURE_GAME_GREEN_RUPEE, ITEM_RUPEE_GREEN, OBJECT_GI_RUPY, GID_RUPEE_GREEN, 0xF4, 0x00, CHEST_ANIM_SHORT, ITEM_CATEGORY_MAJOR, MOD_NONE);
// Shop
itemTable[RG_BUY_DEKU_NUTS_5] = Item(RG_BUY_DEKU_NUTS_5, Text{ "Buy Deku Nut (5)", "Acheter: Noix Mojo (5)", "Deku-Nuß kaufen (5)" }, ITEMTYPE_SHOP, GI_NUTS_5_2, true, LOGIC_NUTS, RHT_DEKU_NUTS_5, ITEM_NUTS_5, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 15);
itemTable[RG_BUY_DEKU_NUTS_5] = Item(RG_BUY_DEKU_NUTS_5, Text{ "Buy Deku Nut (5)", "Acheter: Noix Mojo (5)", "Deku-Nuß kaufen (5)" }, ITEMTYPE_SHOP, GI_NUTS_5_2, true, LOGIC_BUY_NUTS, RHT_DEKU_NUTS_5, ITEM_NUTS_5, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 15);
itemTable[RG_BUY_ARROWS_30] = Item(RG_BUY_ARROWS_30, Text{ "Buy Arrows (30)", "Acheter: Flèches (30)", "Pfeile kaufen (30)" }, ITEMTYPE_SHOP, GI_ARROWS_MEDIUM, true, LOGIC_BUY_ARROW, RHT_ARROWS_30, ITEM_ARROWS_MEDIUM, OBJECT_GI_ARROW, GID_ARROWS_MEDIUM, 0xE6, 0x49, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 60);
itemTable[RG_BUY_ARROWS_50] = Item(RG_BUY_ARROWS_50, Text{ "Buy Arrows (50)", "Acheter: Flèches (50)", "Pfeile kaufen (50)" }, ITEMTYPE_SHOP, GI_ARROWS_LARGE, true, LOGIC_BUY_ARROW, RHT_ARROWS_30, ITEM_ARROWS_LARGE, OBJECT_GI_ARROW, GID_ARROWS_LARGE, 0xE6, 0x4A, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 90);
itemTable[RG_BUY_BOMBS_525] = Item(RG_BUY_BOMBS_525, Text{ "Buy Bombs (5) [25]", "Acheter: Bombes (5) [25]", "Bomben kaufen (5) [25]" }, ITEMTYPE_SHOP, GI_BOMBS_5, true, LOGIC_BUY_BOMB, RHT_BOMBS_5, ITEM_BOMBS_5, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 25);
itemTable[RG_BUY_DEKU_NUTS_10] = Item(RG_BUY_DEKU_NUTS_10, Text{ "Buy Deku Nut (10)", "Acheter: Noix Mojo (10)", "Deku-Nuß kaufen (10)" }, ITEMTYPE_SHOP, GI_NUTS_10, true, LOGIC_NUTS, RHT_DEKU_NUTS_10, ITEM_NUTS_10, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 30);
itemTable[RG_BUY_DEKU_STICK_1] = Item(RG_BUY_DEKU_STICK_1, Text{ "Buy Deku Stick (1)", "Acheter: Bâton Mojo (1)", "Deku-Stab kaufen (1)" }, ITEMTYPE_SHOP, GI_STICKS_1, true, LOGIC_STICKS, RHT_DEKU_STICK_1, ITEM_STICK, OBJECT_GI_STICK, GID_STICK, 0x37, 0x0D, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 10);
itemTable[RG_BUY_DEKU_NUTS_10] = Item(RG_BUY_DEKU_NUTS_10, Text{ "Buy Deku Nut (10)", "Acheter: Noix Mojo (10)", "Deku-Nuß kaufen (10)" }, ITEMTYPE_SHOP, GI_NUTS_10, true, LOGIC_BUY_NUTS, RHT_DEKU_NUTS_10, ITEM_NUTS_10, OBJECT_GI_NUTS, GID_NUTS, 0x34, 0x0C, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 30);
itemTable[RG_BUY_DEKU_STICK_1] = Item(RG_BUY_DEKU_STICK_1, Text{ "Buy Deku Stick (1)", "Acheter: Bâton Mojo (1)", "Deku-Stab kaufen (1)" }, ITEMTYPE_SHOP, GI_STICKS_1, true, LOGIC_BUY_STICKS, RHT_DEKU_STICK_1, ITEM_STICK, OBJECT_GI_STICK, GID_STICK, 0x37, 0x0D, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 10);
itemTable[RG_BUY_BOMBS_10] = Item(RG_BUY_BOMBS_10, Text{ "Buy Bombs (10)", "Acheter: Bombes (10)", "Bomben kaufen (10)" }, ITEMTYPE_SHOP, GI_BOMBS_10, true, LOGIC_BUY_BOMB, RHT_BOMBS_10, ITEM_BOMBS_10, OBJECT_GI_BOMB_1, GID_BOMB, 0x32, 0x59, CHEST_ANIM_SHORT, ITEM_CATEGORY_JUNK, MOD_NONE, false, 50);
itemTable[RG_BUY_FISH] = Item(RG_BUY_FISH, Text{ "Buy Fish", "Acheter: Poisson", "Fisch kaufen" }, ITEMTYPE_SHOP, GI_FISH, true, LOGIC_FISH_ACCESS, RHT_BOTTLE_WITH_FISH, ITEM_FISH, OBJECT_GI_FISH, GID_FISH, 0x47, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 200);
itemTable[RG_BUY_RED_POTION_30] = Item(RG_BUY_RED_POTION_30, Text{ "Buy Red Potion [30]", "Acheter: Potion Rouge [30]", "Rotes Elixier kaufen [30]" }, ITEMTYPE_SHOP, GI_POTION_RED, false, LOGIC_NONE, RHT_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 30);

View file

@ -10,9 +10,10 @@
#include "soh/Enhancements/debugger/performanceTimer.h"
#include <fstream>
#include <soh/OTRGlobals.h>
#include "3drando/shops.hpp"
extern "C" {
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
}
@ -45,17 +46,71 @@ bool LocationAccess::ConditionsMet(Region* parentRegion, bool calculatingAvailab
conditionsMet = true;
}
return conditionsMet &&
(calculatingAvailableChecks || CanBuy()); // TODO: run CanBuy when price is known due to settings
return conditionsMet && CanBuy(calculatingAvailableChecks);
}
bool LocationAccess::CanBuy() const {
return CanBuyAnother(location);
static uint16_t GetMinimumPrice(const Rando::Location* loc) {
extern PriceSettingsStruct shopsanityPrices;
extern PriceSettingsStruct scrubPrices;
extern PriceSettingsStruct merchantPrices;
PriceSettingsStruct priceSettings = loc->GetRCType() == RCTYPE_SHOP ? shopsanityPrices
: loc->GetRCType() == RCTYPE_SCRUB ? scrubPrices
: merchantPrices;
auto ctx = Rando::Context::GetInstance();
switch (ctx->GetOption(priceSettings.main).Get()) {
case RO_PRICE_VANILLA:
return loc->GetVanillaPrice();
case RO_PRICE_CHEAP_BALANCED:
return 0;
case RO_PRICE_BALANCED:
return 0;
case RO_PRICE_FIXED:
return ctx->GetOption(priceSettings.fixedPrice).Get() * 5;
case RO_PRICE_RANGE: {
uint16_t range1 = ctx->GetOption(priceSettings.range1).Get() * 5;
uint16_t range2 = ctx->GetOption(priceSettings.range1).Get() * 5;
return range1 < range2 ? range1 : range2;
}
case RO_PRICE_SET_BY_WALLET: {
if (ctx->GetOption(priceSettings.noWallet).Get()) {
return 0;
} else if (ctx->GetOption(priceSettings.childWallet).Get()) {
return 1;
} else if (ctx->GetOption(priceSettings.adultWallet).Get()) {
return 100;
} else if (ctx->GetOption(priceSettings.giantWallet).Get()) {
return 201;
} else {
return 501;
}
}
default:
return 0;
}
}
bool LocationAccess::CanBuy(bool calculatingAvailableChecks) const {
const auto& loc = Rando::StaticData::GetLocation(location);
const auto& itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(location);
if (loc->GetRCType() == RCTYPE_SHOP || loc->GetRCType() == RCTYPE_SCRUB || loc->GetRCType() == RCTYPE_MERCHANT) {
// Checks should only be identified while playing
if (calculatingAvailableChecks && itemLoc->GetCheckStatus() != RCSHOW_IDENTIFIED) {
return CanBuyAnother(GetMinimumPrice(loc));
} else {
return CanBuyAnother(itemLoc->GetPrice());
}
}
return true;
}
bool CanBuyAnother(RandomizerCheck rc) {
uint16_t price = ctx->GetItemLocation(rc)->GetPrice();
return CanBuyAnother(ctx->GetItemLocation(rc)->GetPrice());
}
bool CanBuyAnother(uint16_t price) {
if (price > 500) {
return logic->HasItem(RG_TYCOON_WALLET);
} else if (price > 200) {
@ -275,7 +330,7 @@ bool BeanPlanted(const RandomizerRegion region) {
if (gPlayState != nullptr && gPlayState->sceneNum == sceneID) {
swch = gPlayState->actorCtx.flags.swch;
} else if (sceneID != SCENE_ID_MAX) {
swch = gSaveContext.sceneFlags[sceneID].swch;
swch = Rando::Context::GetInstance()->GetLogic()->GetSaveContext()->sceneFlags[sceneID].swch;
} else {
swch = 0;
}
@ -312,7 +367,7 @@ void RegionTable_Init() {
logic = ctx->GetLogic(); // RANDOTODO do not hardcode, instead allow accepting a Logic class somehow
grottoEvents = {
EventAccess(&logic->GossipStoneFairy, [] { return logic->CallGossipFairy(); }),
EventAccess(&logic->ButterflyFairy, [] { return logic->ButterflyFairy || (logic->CanUse(RG_STICKS)); }),
EventAccess(&logic->ButterflyFairy, [] { return logic->CanUse(RG_STICKS); }),
EventAccess(&logic->BugShrub, [] { return logic->CanCutShrubs(); }),
EventAccess(&logic->LoneFish, [] { return true; }),
};
@ -627,13 +682,10 @@ std::vector<Rando::Entrance*> GetShuffleableEntrances(Rando::EntranceType type,
return entrancesToShuffle;
}
// Get the specific entrance by name
Rando::Entrance* GetEntrance(const std::string name) {
for (RandomizerRegion region : Regions::GetAllRegions()) {
for (auto& exit : RegionTable(region)->exits) {
if (exit.GetName() == name) {
return &exit;
}
Rando::Entrance* GetEntrance(RandomizerRegion source, RandomizerRegion destination) {
for (auto& exit : RegionTable(source)->exits) {
if (exit.GetConnectedRegionKey() == destination) {
return &exit;
}
}

View file

@ -100,9 +100,10 @@ class LocationAccess {
std::string condition_str;
// Makes sure shop locations are buyable
bool CanBuy() const;
bool CanBuy(bool calculatingAvailableChecks) const;
};
bool CanBuyAnother(uint16_t price);
bool CanBuyAnother(RandomizerCheck rc);
namespace Rando {
@ -350,7 +351,7 @@ extern void DumpWorldGraph(std::string str);
void RegionTable_Init();
Region* RegionTable(const RandomizerRegion regionKey);
std::vector<Rando::Entrance*> GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary = true);
Rando::Entrance* GetEntrance(const std::string name);
Rando::Entrance* GetEntrance(RandomizerRegion source, RandomizerRegion destination);
// Overworld
void RegionTable_Init_KokiriForest();

View file

@ -25,7 +25,6 @@ void RegionTable_Init_BottomOfTheWell() {
}, {
//Locations
LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, logic->HasExplosives()),
LOCATION(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, (logic->HasItem(RG_BRONZE_SCALE) || logic->LoweredWaterInsideBotw) && logic->CanUse(RG_STICKS) || logic->CanUse(RG_DINS_FIRE)),
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, logic->LoweredWaterInsideBotw),
LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, logic->LoweredWaterInsideBotw),
LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1, logic->CanBreakPots()),

View file

@ -445,7 +445,7 @@ void RegionTable_Init_DekuTree() {
areaTable[RR_DEKU_TREE_BOSS_ROOM] = Region("Deku Tree Boss Room", "Deku Tree", {}, NO_DAY_NIGHT_CYCLE, {
// Events
EventAccess(&logic->DekuTreeClear, []{return logic->DekuTreeClear || logic->CanKillEnemy(RE_GOHMA);}),
EventAccess(&logic->DekuTreeClear, []{return logic->CanKillEnemy(RE_GOHMA);}),
}, {
// Locations
LOCATION(RC_QUEEN_GOHMA, logic->DekuTreeClear),

View file

@ -567,7 +567,7 @@ void RegionTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_BOSS_ROOM] = Region("Dodongos Cavern Boss Room", "Dodongos Cavern", {}, NO_DAY_NIGHT_CYCLE, {
// Events
EventAccess(&logic->DodongosCavernClear, []{return logic->DodongosCavernClear || (Here(RR_DODONGOS_CAVERN_BOSS_ROOM, []{return logic->HasExplosives() || (logic->CanUse(RG_MEGATON_HAMMER) && ctx->GetTrickOption(RT_DC_HAMMER_FLOOR));}) && logic->CanKillEnemy(RE_KING_DODONGO)); /*todo add chu kill to tricks*/}),
EventAccess(&logic->DodongosCavernClear, []{return Here(RR_DODONGOS_CAVERN_BOSS_ROOM, []{return logic->HasExplosives() || (logic->CanUse(RG_MEGATON_HAMMER) && ctx->GetTrickOption(RT_DC_HAMMER_FLOOR));}) && logic->CanKillEnemy(RE_KING_DODONGO); /*todo add chu kill to tricks*/}),
}, {
// Locations
LOCATION(RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST, true),

View file

@ -20,14 +20,14 @@ void RegionTable_Init_FireTemple() {
//Exits
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return true;}),
Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return logic->FireTimer() >= 24;}),
Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return Here(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && (logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity);}),
Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return Here(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && (logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsFireLoopLocked);}),
Entrance(RR_FIRE_TEMPLE_LOOP_EXIT, []{return true;}),
Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 2) && logic->FireTimer() >= 24;}),
});
areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM] = Region("Fire Temple Near Boss Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->FairyPot, []{return logic->FairyPot || (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}),
EventAccess(&logic->FairyPot, []{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}),
}, {
//Locations
LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_CHEST, true),
@ -43,7 +43,7 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_LOOP_ENEMIES] = Region("Fire Temple Loop Enemies", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity;}),
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsFireLoopLocked;}),
Entrance(RR_FIRE_TEMPLE_LOOP_TILES, []{return Here(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return logic->CanKillEnemy(RE_TORCH_SLUG) && logic->CanKillEnemy(RE_FIRE_KEESE);});}),
});
@ -67,7 +67,7 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_LOOP_HAMMER_SWITCH] = Region("Fire Temple Loop Hammer Switch", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->FireLoopSwitch, []{return logic->FireLoopSwitch || logic->CanUse(RG_MEGATON_HAMMER);}),
EventAccess(&logic->FireLoopSwitch, []{return logic->CanUse(RG_MEGATON_HAMMER);}),
}, {}, {
//Exits
Entrance(RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, []{return true;}),
@ -745,7 +745,7 @@ void RegionTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_BOSS_ROOM] = Region("Fire Temple Boss Room", "Fire Temple", {}, NO_DAY_NIGHT_CYCLE, {
// Events
EventAccess(&logic->FireTempleClear, []{return logic->FireTempleClear || (logic->FireTimer() >= 64 && logic->CanKillEnemy(RE_VOLVAGIA));}),
EventAccess(&logic->FireTempleClear, []{return logic->FireTimer() >= 64 && logic->CanKillEnemy(RE_VOLVAGIA);}),
}, {
// Locations
LOCATION(RC_FIRE_TEMPLE_VOLVAGIA_HEART, logic->FireTempleClear),

View file

@ -34,7 +34,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_LOBBY] = Region("Forest Temple Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->ForestTempleMeg, []{return logic->ForestTempleMeg || (logic->ForestTempleJoelle && logic->ForestTempleBeth && logic->ForestTempleAmy && logic->CanUse(RG_FAIRY_BOW));}),
EventAccess(&logic->ForestTempleMeg, []{return logic->ForestTempleJoelle && logic->ForestTempleBeth && logic->ForestTempleAmy && logic->CanUse(RG_FAIRY_BOW);}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_GS_LOBBY, logic->HookshotOrBoomerang()),
@ -203,7 +203,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_RED_POE_ROOM] = Region("Forest Temple Red Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->ForestTempleJoelle, []{return logic->ForestTempleJoelle || logic->CanUse(RG_FAIRY_BOW);}),
EventAccess(&logic->ForestTempleJoelle, []{return logic->CanUse(RG_FAIRY_BOW);}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_RED_POE_CHEST, logic->ForestTempleJoelle),
@ -228,7 +228,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_BLUE_POE_ROOM] = Region("Forest Temple Blue Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->ForestTempleBeth, []{return logic->ForestTempleBeth || logic->CanUse(RG_FAIRY_BOW);}),
EventAccess(&logic->ForestTempleBeth, []{return logic->CanUse(RG_FAIRY_BOW);}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_BLUE_POE_CHEST, logic->ForestTempleBeth),
@ -274,7 +274,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_GREEN_POE_ROOM] = Region("Forest Temple Green Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->ForestTempleAmy, []{return logic->ForestTempleAmy || logic->CanUse(RG_FAIRY_BOW);}),
EventAccess(&logic->ForestTempleAmy, []{return logic->CanUse(RG_FAIRY_BOW);}),
}, {
//Locations
LOCATION(RC_FOREST_TEMPLE_GREEN_POE_POT_1, logic->CanBreakPots()),
@ -608,7 +608,7 @@ void RegionTable_Init_ForestTemple() {
areaTable[RR_FOREST_TEMPLE_BOSS_ROOM] = Region("Forest Temple Boss Room", "Forest Temple", {}, NO_DAY_NIGHT_CYCLE, {
// Events
EventAccess(&logic->ForestTempleClear, []{return logic->ForestTempleClear || logic->CanKillEnemy(RE_PHANTOM_GANON);}),
EventAccess(&logic->ForestTempleClear, []{return logic->CanKillEnemy(RE_PHANTOM_GANON);}),
}, {
// Locations
LOCATION(RC_FOREST_TEMPLE_PHANTOM_GANON_HEART, logic->ForestTempleClear),

View file

@ -80,7 +80,7 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_WATER_TRIAL] = Region("Ganon's Castle Water Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->BlueFireAccess, []{return true;}),
EventAccess(&logic->FairyPot, []{return logic->FairyPot || (logic->BlueFire() && logic->CanKillEnemy(RE_FREEZARD));}),
EventAccess(&logic->FairyPot, []{return logic->BlueFire() && logic->CanKillEnemy(RE_FREEZARD);}),
EventAccess(&logic->WaterTrialClear, []{return logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_LIGHT_ARROWS);}),
}, {
//Locations
@ -109,7 +109,7 @@ void RegionTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_SPIRIT_TRIAL] = Region("Ganon's Castle Spirit Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->NutPot, []{return logic->NutPot || (((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))));}),
EventAccess(&logic->NutPot, []{return ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)));}),
EventAccess(&logic->SpiritTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS) && (logic->CanUse(RG_MIRROR_SHIELD) || ctx->GetOption(RSK_SUNLIGHT_ARROWS)) && logic->CanUse(RG_BOMBCHU_5) && ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT));}),
}, {
//Locations

View file

@ -312,9 +312,11 @@ void RegionTable_Init_JabuJabusBelly() {
}, {
//Locations
LOCATION(RC_JABU_JABUS_BELLY_MQ_COW, logic->CanUse(RG_EPONAS_SONG) && logic->CanUse(RG_FAIRY_SLINGSHOT)),
LOCATION(RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS, logic->CanCutShrubs()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS, logic->CanCutShrubs()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1, logic->CanCutShrubs()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2, logic->CanCutShrubs()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1, logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->CanBreakSmallCrates()),
LOCATION(RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2, logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->CanBreakSmallCrates()),
}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, []{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT);}),
@ -359,7 +361,7 @@ void RegionTable_Init_JabuJabusBelly() {
areaTable[RR_JABU_JABUS_BELLY_BOSS_ROOM] = Region("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", {}, NO_DAY_NIGHT_CYCLE, {
// Events //todo: add pot kill trick
EventAccess(&logic->JabuJabusBellyClear, []{return logic->JabuJabusBellyClear || logic->CanKillEnemy(RE_BARINADE);}),
EventAccess(&logic->JabuJabusBellyClear, []{return logic->CanKillEnemy(RE_BARINADE);}),
}, {
// Locations
LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_1, logic->CanBreakPots()),

View file

@ -408,7 +408,7 @@ void RegionTable_Init_ShadowTemple() {
areaTable[RR_SHADOW_TEMPLE_BOSS_ROOM] = Region("Shadow Temple Boss Room", "Shadow Temple", {}, NO_DAY_NIGHT_CYCLE, {
// Events
EventAccess(&logic->ShadowTempleClear, []{return logic->ShadowTempleClear || logic->CanKillEnemy(RE_BONGO_BONGO);}),
EventAccess(&logic->ShadowTempleClear, []{return logic->CanKillEnemy(RE_BONGO_BONGO);}),
}, {
// Locations
LOCATION(RC_SHADOW_TEMPLE_BONGO_BONGO_HEART, logic->ShadowTempleClear),

View file

@ -556,7 +556,7 @@ void RegionTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_BOSS_ROOM] = Region("Spirit Temple Boss Room", "Spirit Temple", {}, NO_DAY_NIGHT_CYCLE, {
// Events
EventAccess(&logic->SpiritTempleClear, []{return logic->SpiritTempleClear || logic->CanKillEnemy(RE_TWINROVA);}),
EventAccess(&logic->SpiritTempleClear, []{return logic->CanKillEnemy(RE_TWINROVA);}),
}, {
// Locations
LOCATION(RC_SPIRIT_TEMPLE_TWINROVA_HEART, logic->SpiritTempleClear),

View file

@ -40,7 +40,7 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_EAST_LOWER] = Region("Water Temple East Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->CanWaterTempleLowFromHigh, []{return logic->CanWaterTempleLowFromHigh || logic->CanUse(RG_ZELDAS_LULLABY);}),
EventAccess(&logic->CanWaterTempleLowFromHigh, []{return logic->CanUse(RG_ZELDAS_LULLABY);}),
}, {
//Locations
LOCATION(RC_WATER_TEMPLE_TORCH_POT_1, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)))),
@ -165,7 +165,7 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER] = Region("Water Temple Central Pillar Upper", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->CanWaterTempleMiddle, []{return logic->CanWaterTempleMiddle || logic->CanUse(RG_ZELDAS_LULLABY);}),
EventAccess(&logic->CanWaterTempleMiddle, []{return logic->CanUse(RG_ZELDAS_LULLABY);}),
}, {
//Locations
LOCATION(RC_WATER_TEMPLE_GS_CENTRAL_PILLAR, logic->CanUse(RG_LONGSHOT) || (((ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE) || logic->SmallKeys(RR_WATER_TEMPLE, 5))) || (ctx->GetTrickOption(RT_WATER_IRONS_CENTRAL_GS) && logic->CanUse(RG_IRON_BOOTS) && ((logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_FAIRY_BOW)) || (logic->CanUse(RG_DINS_FIRE))))) && logic->CanWaterTempleHigh && logic->HookshotOrBoomerang())),
@ -202,7 +202,7 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_HIGH_WATER] = Region("Water Temple High Water", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->CanWaterTempleHigh, []{return logic->CanWaterTempleHigh || logic->CanUse(RG_ZELDAS_LULLABY);}),
EventAccess(&logic->CanWaterTempleHigh, []{return logic->CanUse(RG_ZELDAS_LULLABY);}),
}, {}, {
//Exits
Entrance(RR_WATER_TEMPLE_LOBBY, []{return true;}),
@ -658,7 +658,7 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE] = Region("Water Temple MQ Dragon Room Alcove", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->MQWaterDragonTorches, []{return true;}),
EventAccess(&logic->MQWaterDragonTorches, []{return logic->HasFireSource();}),
},
{
//Locations
@ -848,7 +848,7 @@ void RegionTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_BOSS_ROOM] = Region("Water Temple Boss Room", "Water Temple", {}, NO_DAY_NIGHT_CYCLE, {
// Events
EventAccess(&logic->WaterTempleClear, []{return logic->WaterTempleClear || logic->CanKillEnemy(RE_MORPHA);}),
EventAccess(&logic->WaterTempleClear, []{return logic->CanKillEnemy(RE_MORPHA);}),
}, {
// Locations
LOCATION(RC_WATER_TEMPLE_MORPHA_HEART, logic->WaterTempleClear),

View file

@ -14,7 +14,7 @@ void RegionTable_Init_GerudoFortress() {
//Events
EventAccess(&logic->CarpenterRescue, []{return logic->CanFinishGerudoFortress();}),
EventAccess(&logic->GF_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}),
EventAccess(&logic->GtG_GateOpen, []{return logic->GtG_GateOpen || (logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->HasItem(RG_CHILD_WALLET));}),
EventAccess(&logic->GtG_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->HasItem(RG_CHILD_WALLET);}),
}, {
//Locations
LOCATION(RC_GF_CHEST, logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || logic->CanUse(RG_LONGSHOT)),

View file

@ -17,7 +17,7 @@ void RegionTable_Init_CastleGrounds() {
areaTable[RR_HYRULE_CASTLE_GROUNDS] = Region("Hyrule Castle Grounds", "Castle Grounds", {RA_HYRULE_CASTLE}, DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}),
EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}),
EventAccess(&logic->ButterflyFairy, []{return logic->CanUse(RG_STICKS);}),
EventAccess(&logic->BugRock, []{return true;}),
}, {
//Locations

View file

@ -14,7 +14,7 @@ void RegionTable_Init_DeathMountainCrater() {
areaTable[RR_DMC_UPPER_LOCAL] = Region("DMC Upper Local", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->GossipStoneFairy || (logic->HasExplosives() && logic->CallGossipFairyExceptSuns() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3));}),
EventAccess(&logic->GossipStoneFairy, []{return logic->HasExplosives() && logic->CallGossipFairyExceptSuns() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3);}),
}, {
//Locations
LOCATION(RC_DMC_WALL_FREESTANDING_POH, logic->FireTimer() >= 16 || logic->Hearts() >= 3),

View file

@ -33,7 +33,7 @@ void RegionTable_Init_DeathMountainTrail() {
areaTable[RR_DEATH_MOUNTAIN_SUMMIT] = Region("Death Mountain Summit", "Death Mountain", {RA_DEATH_MOUNTAIN_TRAIL}, DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}),
EventAccess(&logic->BugRock, []{return logic->BugRock || logic->IsChild;}),
EventAccess(&logic->BugRock, []{return logic->IsChild;}),
}, {
//Locations
LOCATION(RC_DMT_TRADE_BROKEN_SWORD, logic->IsAdult && logic->CanUse(RG_BROKEN_SWORD)),

View file

@ -7,7 +7,7 @@ void RegionTable_Init_DesertColossus() {
// clang-format off
areaTable[RR_DESERT_COLOSSUS] = Region("Desert Colossus", "Desert Colossus", {RA_DESERT_COLOSSUS}, DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->FairyPond, []{return logic->FairyPond || logic->CanUse(RG_SONG_OF_STORMS);}),
EventAccess(&logic->FairyPond, []{return logic->CanUse(RG_SONG_OF_STORMS);}),
EventAccess(&logic->BugRock, []{return true;}),
}, {
//Locations

View file

@ -7,7 +7,7 @@ void RegionTable_Init_GerudoValley() {
// clang-format off
areaTable[RR_GERUDO_VALLEY] = Region("Gerudo Valley", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->BugRock, []{return logic->BugRock || logic->IsChild;}),
EventAccess(&logic->BugRock, []{return logic->IsChild;}),
}, {
//Locations
LOCATION(RC_GV_GS_SMALL_BRIDGE, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()),

View file

@ -8,12 +8,12 @@ void RegionTable_Init_GoronCity() {
areaTable[RR_GORON_CITY] = Region("Goron City", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}),
EventAccess(&logic->StickPot, []{return logic->StickPot || logic->IsChild;}),
EventAccess(&logic->BugRock, []{return logic->BugRock || (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS));}),
EventAccess(&logic->GoronCityChildFire, []{return logic->GoronCityChildFire || (logic->IsChild && logic->CanUse(RG_DINS_FIRE));}),
EventAccess(&logic->GCWoodsWarpOpen, []{return logic->GCWoodsWarpOpen || (logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_FAIRY_BOW) || logic->HasItem(RG_GORONS_BRACELET) || logic->GoronCityChildFire);}),
EventAccess(&logic->GCDaruniasDoorOpenChild, []{return logic->GCDaruniasDoorOpenChild || (logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY));}),
EventAccess(&logic->StopGCRollingGoronAsAdult, []{return logic->StopGCRollingGoronAsAdult || (logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || (ctx->GetTrickOption(RT_GC_LINK_GORON_DINS) && logic->CanUse(RG_DINS_FIRE))));}),
EventAccess(&logic->StickPot, []{return logic->IsChild;}),
EventAccess(&logic->BugRock, []{return logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS);}),
EventAccess(&logic->GoronCityChildFire, []{return logic->IsChild && logic->CanUse(RG_DINS_FIRE);}),
EventAccess(&logic->GCWoodsWarpOpen, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_FAIRY_BOW) || logic->HasItem(RG_GORONS_BRACELET) || logic->GoronCityChildFire;}),
EventAccess(&logic->GCDaruniasDoorOpenChild, []{return logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY);}),
EventAccess(&logic->StopGCRollingGoronAsAdult, []{return logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || (ctx->GetTrickOption(RT_GC_LINK_GORON_DINS) && logic->CanUse(RG_DINS_FIRE)));}),
}, {
//Locations
LOCATION(RC_GC_MAZE_LEFT_CHEST, logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_SILVER_GAUNTLETS) || (ctx->GetTrickOption(RT_GC_LEFTMOST) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS))),
@ -58,7 +58,7 @@ void RegionTable_Init_GoronCity() {
areaTable[RR_GC_WOODS_WARP] = Region("GC Woods Warp", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GCWoodsWarpOpen, []{return logic->GCWoodsWarpOpen || (logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE));}),
EventAccess(&logic->GCWoodsWarpOpen, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE);}),
}, {}, {
//Exits
Entrance(RR_GORON_CITY, []{return logic->CanLeaveForest() && logic->GCWoodsWarpOpen;}),
@ -67,7 +67,7 @@ void RegionTable_Init_GoronCity() {
areaTable[RR_GC_DARUNIAS_CHAMBER] = Region("GC Darunias Chamber", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GoronCityChildFire, []{return logic->GoronCityChildFire || (logic->IsChild && logic->CanUse(RG_STICKS));}),
EventAccess(&logic->GoronCityChildFire, []{return logic->IsChild && logic->CanUse(RG_STICKS);}),
}, {
//Locations
LOCATION(RC_GC_DARUNIAS_JOY, logic->IsChild && logic->CanUse(RG_SARIAS_SONG)),

View file

@ -7,7 +7,7 @@ void RegionTable_Init_Graveyard() {
// clang-format off
areaTable[RR_THE_GRAVEYARD] = Region("The Graveyard", "The Graveyard", {RA_THE_GRAVEYARD}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || (logic->CanUse(RG_STICKS) && logic->AtDay);}),
EventAccess(&logic->ButterflyFairy, []{return logic->CanUse(RG_STICKS) && logic->AtDay;}),
EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}),
EventAccess(&logic->BugRock, []{return true;}),
}, {
@ -88,7 +88,7 @@ void RegionTable_Init_Graveyard() {
areaTable[RR_GRAVEYARD_DAMPES_GRAVE] = Region("Graveyard Dampes Grave", "Windmill and Dampes Grave", {}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->NutPot, []{return true;}),
EventAccess(&logic->DampesWindmillAccess, []{return logic->DampesWindmillAccess || (logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME));}),
EventAccess(&logic->DampesWindmillAccess, []{return logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME);}),
}, {
//Locations
LOCATION(RC_GRAVEYARD_HOOKSHOT_CHEST, true),

View file

@ -166,7 +166,7 @@ void RegionTable_Init_Kakariko() {
areaTable[RR_KAK_WINDMILL] = Region("Kak Windmill", "Windmill and Dampes Grave", {}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->DrainWell, []{return logic->DrainWell || (logic->IsChild && logic->CanUse(RG_SONG_OF_STORMS));}),
EventAccess(&logic->DrainWell, []{return logic->IsChild && logic->CanUse(RG_SONG_OF_STORMS);}),
}, {
//Locations
LOCATION(RC_KAK_WINDMILL_FREESTANDING_POH, logic->CanUse(RG_BOOMERANG) || logic->DampesWindmillAccess || (logic->IsAdult && ctx->GetTrickOption(RT_KAK_ADULT_WINDMILL_POH)) || (logic->IsChild && logic->CanJumpslashExceptHammer() && ctx->GetTrickOption(RT_KAK_CHILD_WINDMILL_POH))),

View file

@ -9,7 +9,7 @@ void RegionTable_Init_KokiriForest() {
//Events
EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}),
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}),
EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}),
EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD);}),
}, {
//Locations
LOCATION(RC_KF_KOKIRI_SWORD_CHEST, logic->IsChild),
@ -93,7 +93,7 @@ void RegionTable_Init_KokiriForest() {
//Events
EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}),
EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}),
EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}),
EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD);}),
}, {
//Locations
LOCATION(RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()),

View file

@ -9,10 +9,10 @@ void RegionTable_Init_LakeHylia() {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}),
EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}),
EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}),
EventAccess(&logic->BugShrub, []{return logic->BugShrub || (logic->IsChild && logic->CanCutShrubs());}),
EventAccess(&logic->ChildScarecrow, []{return logic->ChildScarecrow || (logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2);}),
EventAccess(&logic->AdultScarecrow, []{return logic->AdultScarecrow || (logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2);}),
EventAccess(&logic->ButterflyFairy, []{return logic->CanUse(RG_STICKS);}),
EventAccess(&logic->BugShrub, []{return logic->IsChild && logic->CanCutShrubs();}),
EventAccess(&logic->ChildScarecrow, []{return logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2;}),
EventAccess(&logic->AdultScarecrow, []{return logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2;}),
}, {
//Locations
LOCATION(RC_LH_UNDERWATER_ITEM, logic->IsChild && logic->HasItem(RG_SILVER_SCALE)),

View file

@ -7,8 +7,8 @@ void RegionTable_Init_LonLonRanch() {
// clang-format off
areaTable[RR_LON_LON_RANCH] = Region("Lon Lon Ranch", "Lon Lon Ranch", {RA_LON_LON_RANCH}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->FreedEpona, []{return logic->FreedEpona || ((logic->HasItem(RG_CHILD_WALLET) || ctx->GetOption(RSK_SKIP_EPONA_RACE)) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay);}),
EventAccess(&logic->LinksCow, []{return logic->LinksCow || (logic->HasItem(RG_CHILD_WALLET) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay);}),
EventAccess(&logic->FreedEpona, []{return (logic->HasItem(RG_CHILD_WALLET) || ctx->GetOption(RSK_SKIP_EPONA_RACE)) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay;}),
EventAccess(&logic->LinksCow, []{return logic->HasItem(RG_CHILD_WALLET) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay;}),
}, {
//Locations
LOCATION(RC_SONG_FROM_MALON, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_FAIRY_OCARINA) && logic->AtDay),

View file

@ -64,7 +64,7 @@ void RegionTable_Init_LostWoods() {
areaTable[RR_LW_BEYOND_MIDO] = Region("LW Beyond Mido", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}),
EventAccess(&logic->ButterflyFairy, []{return logic->CanUse(RG_STICKS);}),
}, {
//Locations
LOCATION(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, logic->IsChild && logic->CanStunDeku()),

View file

@ -138,8 +138,8 @@ void RegionTable_Init_Market() {
areaTable[RR_MARKET_MASK_SHOP] = Region("Market Mask Shop", "Market Mask Shop", {}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->SkullMask, []{return logic->SkullMask || (logic->HasItem(RG_ZELDAS_LETTER) && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || ChildCanAccess(RR_KAKARIKO_VILLAGE)));}), //RANDOTODO Complete mask quest does not need this location, so should be tied to link's pocket
EventAccess(&logic->MaskOfTruth, []{return logic->MaskOfTruth || (logic->SkullMask && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || (ChildCanAccess(RR_THE_LOST_WOODS) && logic->CanUse(RG_SARIAS_SONG) && RegionTable(RR_THE_GRAVEYARD)->childDay && ChildCanAccess(RR_HYRULE_FIELD) && logic->StoneCount() == 3)));}),
EventAccess(&logic->SkullMask, []{return logic->HasItem(RG_ZELDAS_LETTER) && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || ChildCanAccess(RR_KAKARIKO_VILLAGE));}), //RANDOTODO Complete mask quest does not need this location, so should be tied to link's pocket
EventAccess(&logic->MaskOfTruth, []{return logic->SkullMask && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || (ChildCanAccess(RR_THE_LOST_WOODS) && logic->CanUse(RG_SARIAS_SONG) && RegionTable(RR_THE_GRAVEYARD)->childDay && ChildCanAccess(RR_HYRULE_FIELD) && logic->StoneCount() == 3));}),
}, {
//Locations
LOCATION(RC_MASK_SHOP_HINT, true),

View file

@ -9,10 +9,10 @@ void RegionTable_Init_ZorasDomain() {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}),
EventAccess(&logic->NutPot, []{return true;}),
EventAccess(&logic->StickPot, []{return logic->StickPot || logic->IsChild;}),
EventAccess(&logic->FishGroup, []{return logic->FishGroup || logic->IsChild;}),
EventAccess(&logic->KingZoraThawed, []{return logic->KingZoraThawed || (logic->IsAdult && logic->BlueFire());}),
EventAccess(&logic->DeliverLetter, []{return logic->DeliverLetter || (logic->CanUse(RG_RUTOS_LETTER) && logic->IsChild && ctx->GetOption(RSK_ZORAS_FOUNTAIN).IsNot(RO_ZF_OPEN));}),
EventAccess(&logic->StickPot, []{return logic->IsChild;}),
EventAccess(&logic->FishGroup, []{return logic->IsChild;}),
EventAccess(&logic->KingZoraThawed, []{return logic->IsAdult && logic->BlueFire();}),
EventAccess(&logic->DeliverLetter, []{return logic->CanUse(RG_RUTOS_LETTER) && logic->IsChild && ctx->GetOption(RSK_ZORAS_FOUNTAIN).IsNot(RO_ZF_OPEN);}),
}, {
//Locations
LOCATION(RC_ZD_DIVING_MINIGAME, logic->HasItem(RG_BRONZE_SCALE) && logic->HasItem(RG_CHILD_WALLET) && logic->IsChild),

View file

@ -8,7 +8,7 @@ void RegionTable_Init_ZorasFountain() {
areaTable[RR_ZORAS_FOUNTAIN] = Region("Zoras Fountain", "Zoras Fountain", {RA_ZORAS_FOUNTAIN}, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}),
EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || (logic->CanUse(RG_STICKS) && logic->AtDay);}),
EventAccess(&logic->ButterflyFairy, []{return logic->CanUse(RG_STICKS) && logic->AtDay;}),
}, {
//Locations
LOCATION(RC_ZF_GS_TREE, logic->IsChild),

View file

@ -30,8 +30,8 @@ void RegionTable_Init_ZoraRiver() {
//Events
EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}),
EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}),
EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}),
EventAccess(&logic->BugShrub, []{return logic->BugShrub || logic->CanCutShrubs();}),
EventAccess(&logic->ButterflyFairy, []{return logic->CanUse(RG_STICKS);}),
EventAccess(&logic->BugShrub, []{return logic->CanCutShrubs();}),
}, {
//Locations
LOCATION(RC_ZR_MAGIC_BEAN_SALESMAN, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild),

View file

@ -322,11 +322,9 @@ bool Logic::CanUse(RandomizerGet itemName) {
case RG_KOKIRI_SWORD:
return IsChild; // || KokiriSwordAsAdult;
case RG_NUTS:
return (NutPot || NutCrate || DekuBabaNuts) &&
AmmoCanDrop; // RANDOTODO BuyNuts currently mixed in with Nuts, should be seperate as BuyNuts are
// also a Nuts source
return ((NutPot || NutCrate || DekuBabaNuts) && AmmoCanDrop) || GetInLogic(LOGIC_BUY_NUTS);
case RG_STICKS:
return IsChild /* || StickAsAdult;*/ && (StickPot || DekuBabaSticks);
return IsChild /* || StickAsAdult;*/ && (StickPot || DekuBabaSticks || GetInLogic(LOGIC_BUY_STICKS));
case RG_DEKU_SHIELD:
return IsChild; // || DekuShieldAsAdult;
case RG_PROGRESSIVE_BOMB_BAG:
@ -1389,6 +1387,7 @@ bool Logic::SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless
static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >=
static_cast<uint8_t>(GlitchDifficulty::INTERMEDIATE))) { return FireTempleKeys >= requiredAmountGlitched;
}*/
// If the Fire Temple loop lock is removed, Small key Count is set to 1 before starting
return GetSmallKeyCount(SCENE_FIRE_TEMPLE) >= requiredAmountGlitchless;
case RR_WATER_TEMPLE:
@ -1816,7 +1815,7 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
if (randoGet == RG_BOTTLE_WITH_BIG_POE) {
BigPoes++;
}
mSaveContext->inventory.items[slot] = itemId;
mSaveContext->inventory.items[slot] = static_cast<uint8_t>(itemId);
} break;
case RG_RUTOS_LETTER:
SetRandoInf(RAND_INF_OBTAINED_RUTOS_LETTER, state);
@ -2308,7 +2307,7 @@ void Logic::SetEventChkInf(int32_t flag, bool state) {
}
uint8_t Logic::GetGSCount() {
return mSaveContext->inventory.gsTokens;
return static_cast<uint8_t>(mSaveContext->inventory.gsTokens);
}
uint8_t Logic::GetAmmo(uint32_t item) {
@ -2336,9 +2335,9 @@ void Logic::Reset() {
StartPerformanceTimer(PT_LOGIC_RESET);
memset(inLogic, false, sizeof(inLogic));
// Settings-dependent variables
IsKeysanity = ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE);
IsFireLoopLocked = ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD) ||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON);
// AmmoCanDrop = /*AmmoDrops.IsNot(AMMODROPS_NONE)*/ false; TODO: AmmoDrop setting
@ -2400,7 +2399,7 @@ void Logic::Reset() {
// If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in vanilla
// FiT
if (!IsKeysanity && ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
if (!IsFireLoopLocked && ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
SetSmallKeyCount(SCENE_FIRE_TEMPLE, 1);
}
@ -2498,6 +2497,7 @@ void Logic::Reset() {
ForestOpenBossCorridor = false;
ShadowTrialFirstChest = false;
MQGTGMazeSwitch = false;
MQGTGRightSideSwitch = false;
GTGPlatformSilverRupees = false;
MQJabuHolesRoomDoor = false;
JabuWestTentacle = false;

View file

@ -59,7 +59,7 @@ class Logic {
bool LightTrialClear = false;
// Logical keysanity
bool IsKeysanity = false;
bool IsFireLoopLocked = false;
// Bottle Count
uint8_t Bottles = 0;

View file

@ -83,11 +83,11 @@ void Option::RestoreDelayedOption() {
contextSelection = delayedSelection;
}
void Option::SetContextIndex(size_t idx) {
void Option::SetContextIndex(uint8_t idx) {
// TODO: Set to Context's OptionValue array.
contextSelection = idx;
if (contextSelection > options.size() - 1) {
contextSelection = options.size() - 1;
if (contextSelection > static_cast<uint8_t>(options.size() - 1)) {
contextSelection = static_cast<uint8_t>(options.size() - 1);
}
}
@ -105,7 +105,7 @@ bool Option::IsHidden() const {
void Option::ChangeOptions(std::vector<std::string> opts) {
if (GetOptionIndex() >= opts.size()) {
CVarSetInteger(cvarName.c_str(), opts.size() - 1);
CVarSetInteger(cvarName.c_str(), static_cast<uint8_t>(opts.size() - 1));
}
options = std::move(opts);
}
@ -206,8 +206,8 @@ bool Option::RenderCheckbox() {
bool Option::RenderCombobox() {
bool changed = false;
uint8_t selected = CVarGetInteger(cvarName.c_str(), defaultOption);
if (selected >= options.size()) {
selected = options.size();
if (selected >= static_cast<uint8_t>(options.size())) {
selected = static_cast<uint8_t>(options.size());
CVarSetInteger(cvarName.c_str(), selected);
changed = true;
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
@ -231,13 +231,13 @@ bool Option::RenderSlider() {
bool changed = false;
int val = CVarGetInteger(cvarName.c_str(), defaultOption);
if (val > options.size() - 1) {
val = options.size() - 1;
val = static_cast<int>(options.size()) - 1;
changed = true;
}
UIWidgets::IntSliderOptions widgetOptions = UIWidgets::IntSliderOptions()
.Color(THEME_COLOR)
.Min(0)
.Max(options.size() - 1)
.Max(static_cast<uint8_t>(options.size() - 1))
.Tooltip(description.c_str())
.Format(options[val].c_str())
.DefaultValue(defaultOption);

View file

@ -241,11 +241,11 @@ class Option {
void RestoreDelayedOption();
/**
* @brief Set the rando context index for this Option. Also calls `SetVariable()`.
* @brief Set the rando context index for this Option.
*
* @param idx the index to set as the selected index.
*/
void SetContextIndex(size_t idx);
void SetContextIndex(uint8_t idx);
/**
* @brief Hides this Option in the menu. (Not currently being used afaik, we prefer to

View file

@ -65,7 +65,7 @@ const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi";
const std::string Randomizer::IceTrapRandoMessageTableID = "RandomizerIceTrap";
const std::string Randomizer::randoMiscHintsTableID = "RandomizerMiscHints";
static const char* englishRupeeNames[190] = {
static const char* englishRupeeNames[188] = {
"[P]",
"Bad RNG Rolls",
"Baht",
@ -111,8 +111,6 @@ static const char* englishRupeeNames[190] = {
"Dimes",
"Dinars",
"DNA",
"Doge",
"Dogecoin",
"Doll Hairs",
"Dollars",
"Dollarydoos",
@ -258,25 +256,25 @@ static const char* englishRupeeNames[190] = {
"Zorkmids",
};
static const char* germanRupeeNames[80] = {
"Baht", "Bananen", "Bitcoin", "Bonbons", "Bratwürste", "Brause UFOs", "Brötchen", "Cent",
"Diamanten", "Dinar", "Diridari", "Dogecoin", "Dollar", "Draken", "ECU", "Elexit",
"Erz", "Erzbrocken", "Euro", "EXP", "Forint", "Franken", "Freunde", "Gil",
"Gold", "Groschen", "Gulden", "Gummibären", "Heller", "Juwelen", "Karolin", "Kartoffeln",
"Kies", "Knete", "Knochen", "Kohle", "Kraniche", "Kreuzer", "Kronen", "Kronkorken",
"Kröten", "Lira", "Mark", "Mäuse", "Monde", "Moorhühner", "Moos", "Münzen",
"Naira", "Penunze", "Pesa", "Pfandflaschen", "Pfennig", "Pfund", "Pilze", "Plastiks",
"Pokédollar", "Radieschen", "Rand", "Rappen", "Real", "Rial", "Riyal", "Rubine",
"Rupien", "Saphire", "Schilling", "Seelen", "Septime", "Smaragde", "Steine", "Sterne",
"Sternis", "Tael", "Taler", "Wagenchips", "Won", "Yen", "Yuan", "Zenny",
static const char* germanRupeeNames[79] = {
"Baht", "Bananen", "Bitcoin", "Bonbons", "Bratwürste", "Brause UFOs", "Brötchen", "Cent",
"Diamanten", "Dinar", "Diridari", "Dollar", "Draken", "ECU", "Elexit", "Erz",
"Erzbrocken", "Euro", "EXP", "Forint", "Franken", "Freunde", "Gil", "Gold",
"Groschen", "Gulden", "Gummibären", "Heller", "Juwelen", "Karolin", "Kartoffeln", "Kies",
"Knete", "Knochen", "Kohle", "Kraniche", "Kreuzer", "Kronen", "Kronkorken", "Kröten",
"Lira", "Mark", "Mäuse", "Monde", "Moorhühner", "Moos", "Münzen", "Naira",
"Penunze", "Pesa", "Pfandflaschen", "Pfennig", "Pfund", "Pilze", "Plastiks", "Pokédollar",
"Radieschen", "Rand", "Rappen", "Real", "Rial", "Riyal", "Rubine", "Rupien",
"Saphire", "Schilling", "Seelen", "Septime", "Smaragde", "Steine", "Sterne", "Sternis",
"Tael", "Taler", "Wagenchips", "Won", "Yen", "Yuan", "Zenny",
};
static const char* frenchRupeeNames[40] = {
"Anneaux", "Baguettes", "Balles", "Bananes", "Bitcoin", "Blés", "Bling", "Capsules",
"Centimes", "Champignons", "Clochettes", "Crédits", "Croissants", "Diamants", "Dogecoin", "Dollars",
"Émeraudes", "Éthers", "Étoiles", "Euros", "Florens", "Francs", "Galds", "Gils",
"Grouses", "Halos", "Joyaux", "Lunes", "Mailles", "Munnies", "Orbes", "Orens",
"Pépètes", "Pièces", "Plastyks", "Pokédollars", "Pokémon", "Radis", "Rubis", "Zennies",
static const char* frenchRupeeNames[39] = {
"Anneaux", "Baguettes", "Balles", "Bananes", "Bitcoin", "Blés", "Bling", "Capsules",
"Centimes", "Champignons", "Clochettes", "Crédits", "Croissants", "Diamants", "Dollars", "Émeraudes",
"Éthers", "Étoiles", "Euros", "Florens", "Francs", "Galds", "Gils", "Grouses",
"Halos", "Joyaux", "Lunes", "Mailles", "Munnies", "Orbes", "Orens", "Pépètes",
"Pièces", "Plastyks", "Pokédollars", "Pokémon", "Radis", "Rubis", "Zennies",
};
Randomizer::Randomizer() {
@ -357,9 +355,12 @@ std::unordered_map<s16, s16> getItemIdToItemId = {
{ GI_CLAIM_CHECK, ITEM_CLAIM_CHECK },
};
#ifdef _MSC_VER
#pragma optimize("", off)
#else
#pragma GCC push_options
#pragma GCC optimize("O0")
#endif
bool Randomizer::SpoilerFileExists(const char* spoilerFileName) {
if (strcmp(spoilerFileName, "") != 0) {
std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName));
@ -372,8 +373,11 @@ bool Randomizer::SpoilerFileExists(const char* spoilerFileName) {
return false;
}
#pragma GCC pop_options
#ifdef _MSC_VER
#pragma optimize("", on)
#else
#pragma GCC pop_options
#endif
void Randomizer::LoadHintMessages() {
auto ctx = Rando::Context::GetInstance();
@ -1552,7 +1556,7 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
{ RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1, RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1 },
{ RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2, RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2 },
{ RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3, RAND_INF_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3 },
{ RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS, RAND_INF_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS },
{ RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS, RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS },
{ RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1, RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1 },
{ RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2, RAND_INF_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2 },
{ RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS, RAND_INF_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS },
@ -3023,6 +3027,14 @@ std::map<RandomizerCheck, RandomizerInf> rcToRandomizerInf = {
RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2,
RAND_INF_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2,
},
{
RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1,
RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1,
},
{
RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2,
RAND_INF_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2,
},
{
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1,
RAND_INF_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1,
@ -3498,9 +3510,9 @@ CrateIdentity Randomizer::IdentifyCrate(s32 sceneNum, s32 posX, s32 posZ) {
crateSceneNum = SCENE_MARKET_DAY;
} else if (sceneNum == SCENE_GERUDOS_FORTRESS && gPlayState->linkAgeOnLoad == 1 && posX == 310) {
if (posZ == -1830) {
posZ = -1842.0f;
posZ = -1842;
} else if (posZ == -1770) {
posZ = -1782.0f;
posZ = -1782;
}
}
@ -3726,13 +3738,15 @@ void RandomizerSettingsWindow::DrawElement() {
}
UIWidgets::Spacer(0);
ImGui::BeginDisabled((gSaveContext.gameMode != GAMEMODE_FILE_SELECT) || GameInteractor::IsSaveLoaded());
if (UIWidgets::Button("Generate Randomizer",
UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR))) {
UIWidgets::ButtonOptions options = UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR);
options.Disabled((gSaveContext.gameMode != GAMEMODE_FILE_SELECT) || GameInteractor::IsSaveLoaded());
if (options.disabled) {
options.DisabledTooltip("Must be on File Select to generate a randomizer seed.");
}
if (UIWidgets::Button("Generate Randomizer", options)) {
ctx->SetSpoilerLoaded(false);
GenerateRandomizer(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0) ? seedString : "");
}
ImGui::EndDisabled();
ImGui::SameLine();
if (!CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0)) {
@ -4088,7 +4102,7 @@ void RandomizerSettingsWindow::DrawElement() {
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
if (ImGui::BeginTable("trickTags", showTag.size(),
if (ImGui::BeginTable("trickTags", static_cast<int>(showTag.size()),
ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings |
ImGuiTableFlags_Borders)) {
for (auto [rtTag, isShown] : showTag) {
@ -4511,6 +4525,9 @@ CustomMessage Randomizer::GetMapGetItemMessageWithHint(GetItemEntry itemEntry) {
messageEntry.Replace("[[typeHint]]", Rando::StaticData::hintTextTable[RHT_DUNGEON_ORDINARY].GetHintMessage());
}
// BUG: the icon is not in the message yet so are not accounted for, so overflows are possible
messageEntry.AutoFormat();
return messageEntry;
}
@ -5560,7 +5577,7 @@ void RandomizerSettingsWindow::InitElement() {
// (special cases for rando items)
void Randomizer_GameplayStats_SetTimestamp(uint16_t item) {
u32 time = GAMEPLAYSTAT_TOTAL_TIME;
u32 time = static_cast<u32>(GAMEPLAYSTAT_TOTAL_TIME);
// Have items in Link's pocket shown as being obtained at 0.1 seconds
if (time == 0) {
@ -5856,7 +5873,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
case RG_GREG_RUPEE:
Rupees_ChangeBy(1);
Flags_SetRandomizerInf(RAND_INF_GREG_FOUND);
gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_FOUND_GREG] = GAMEPLAYSTAT_TOTAL_TIME;
gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_FOUND_GREG] = static_cast<u32>(GAMEPLAYSTAT_TOTAL_TIME);
break;
case RG_TRIFORCE_PIECE:
gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected++;
@ -5865,7 +5882,8 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
// Teleport to credits when goal is reached.
if (gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected ==
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1)) {
gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME;
gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] =
static_cast<u32>(GAMEPLAYSTAT_TOTAL_TIME);
gSaveContext.ship.stats.gameComplete = 1;
Flags_SetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY);
Play_PerformSave(play);
@ -5898,12 +5916,12 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
case RG_DEKU_STICK_BAG:
Inventory_ChangeUpgrade(UPG_STICKS, 1);
INV_CONTENT(ITEM_STICK) = ITEM_STICK;
AMMO(ITEM_STICK) = CUR_CAPACITY(UPG_STICKS);
AMMO(ITEM_STICK) = static_cast<int8_t>(CUR_CAPACITY(UPG_STICKS));
break;
case RG_DEKU_NUT_BAG:
Inventory_ChangeUpgrade(UPG_NUTS, 1);
INV_CONTENT(ITEM_NUT) = ITEM_NUT;
AMMO(ITEM_NUT) = CUR_CAPACITY(UPG_NUTS);
AMMO(ITEM_NUT) = static_cast<int8_t>(CUR_CAPACITY(UPG_NUTS));
break;
default:
LUSLOG_WARN("Randomizer_Item_Give didn't have behaviour specified for getItemId=%d", item);

View file

@ -184,10 +184,10 @@ typedef enum {
LOGIC_GREG,
LOGIC_PIECE_OF_HEART,
LOGIC_HEART_CONTAINER,
LOGIC_NUTS,
LOGIC_BUY_NUTS,
LOGIC_BUY_ARROW,
LOGIC_BUY_BOMB,
LOGIC_STICKS,
LOGIC_BUY_STICKS,
LOGIC_FISH_ACCESS,
LOGIC_BUY_MAGIC_POTION,
LOGIC_BUY_BOMBCHUS,
@ -2576,6 +2576,8 @@ typedef enum {
// MQ Dungeon Small Crates
RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_1,
RC_JABU_JABUS_BELLY_MQ_TRIPLE_HALLWAY_SMALL_CRATE_2,
RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_1,
RC_JABU_JABUS_BELLY_MQ_JIGGLIES_SMALL_CRATE_2,
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_1,
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_2,
RC_FOREST_TEMPLE_MQ_FROZEN_EYE_SWITCH_SMALL_CRATE_3,
@ -3448,7 +3450,7 @@ typedef enum {
RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_1,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_2,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_GRASS_3,
RC_JABU_JABUS_BELLY_MQ_WIGGLERS_GRASS,
RC_JABU_JABUS_BELLY_MQ_JIGGLIES_GRASS,
RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_1,
RC_JABU_JABUS_BELLY_MQ_AFTER_BIG_OCTO_GRASS_2,
RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_GRASS,

Some files were not shown because too many files have changed in this diff Show more