diff --git a/libultraship/libultraship/CMakeLists.txt b/libultraship/libultraship/CMakeLists.txt index aec229bfb..d2b35a1f8 100644 --- a/libultraship/libultraship/CMakeLists.txt +++ b/libultraship/libultraship/CMakeLists.txt @@ -121,6 +121,7 @@ set(Source_Files__CustomImpl source_group("Source Files\\CustomImpl" FILES ${Source_Files__CustomImpl}) set(Source_Files__CustomImpl__Hooks + "Hooks.cpp" "Hooks.h" ) source_group("Source Files\\CustomImpl\\Hooks" FILES ${Source_Files__CustomImpl__Hooks}) diff --git a/libultraship/libultraship/CrashHandler.cpp b/libultraship/libultraship/CrashHandler.cpp index f8d66beab..f454ddfdc 100644 --- a/libultraship/libultraship/CrashHandler.cpp +++ b/libultraship/libultraship/CrashHandler.cpp @@ -1,6 +1,9 @@ #include "spdlog/spdlog.h" #include "Utils/StringHelper.h" #include "CrashHandler.h" +#include "Window.h" + +extern "C" void DeinitOTR(void); #if defined(__linux__) #include @@ -10,163 +13,343 @@ #include #include -extern "C" void DeinitOTR(void); static void PrintRegisters(ucontext_t* ctx) { - char regbuffer[1024]; - SPDLOG_CRITICAL("Registers:"); + char regbuffer[1024]; + SPDLOG_CRITICAL("Registers:"); #if defined(__x86_64__) - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RAX]); - SPDLOG_CRITICAL("RAX: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDI]); - SPDLOG_CRITICAL("RDI: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSI]); - SPDLOG_CRITICAL("RSI: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDX]); - SPDLOG_CRITICAL("RDX: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RCX]); - SPDLOG_CRITICAL("RCX: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R8]); - SPDLOG_CRITICAL("R8 : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R9]); - SPDLOG_CRITICAL("R9 : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R10]); - SPDLOG_CRITICAL("R10: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R11]); - SPDLOG_CRITICAL("R11: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSP]); - SPDLOG_CRITICAL("RSP: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBX]); - SPDLOG_CRITICAL("RBX: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBP]); - SPDLOG_CRITICAL("RBP: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R12]); - SPDLOG_CRITICAL("R12: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R13]); - SPDLOG_CRITICAL("R13: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R14]); - SPDLOG_CRITICAL("R14: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R15]); - SPDLOG_CRITICAL("R15: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RIP]); - SPDLOG_CRITICAL("RIP: {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_EFL]); - SPDLOG_CRITICAL("EFLAGS: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RAX]); + SPDLOG_CRITICAL("RAX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDI]); + SPDLOG_CRITICAL("RDI: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSI]); + SPDLOG_CRITICAL("RSI: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDX]); + SPDLOG_CRITICAL("RDX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RCX]); + SPDLOG_CRITICAL("RCX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R8]); + SPDLOG_CRITICAL("R8 : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R9]); + SPDLOG_CRITICAL("R9 : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R10]); + SPDLOG_CRITICAL("R10: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R11]); + SPDLOG_CRITICAL("R11: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSP]); + SPDLOG_CRITICAL("RSP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBX]); + SPDLOG_CRITICAL("RBX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBP]); + SPDLOG_CRITICAL("RBP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R12]); + SPDLOG_CRITICAL("R12: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R13]); + SPDLOG_CRITICAL("R13: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R14]); + SPDLOG_CRITICAL("R14: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R15]); + SPDLOG_CRITICAL("R15: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RIP]); + SPDLOG_CRITICAL("RIP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_EFL]); + SPDLOG_CRITICAL("EFLAGS: {} ", regbuffer); #else - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDI]); - SPDLOG_CRITICAL("EDI : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESI]); - SPDLOG_CRITICAL("ESI : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBP]); - SPDLOG_CRITICAL("EBP : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESP]); - SPDLOG_CRITICAL("ESP : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBX]); - SPDLOG_CRITICAL("EBX : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDX]); - SPDLOG_CRITICAL("EDX : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ECX]); - SPDLOG_CRITICAL("ECX : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EAX]); - SPDLOG_CRITICAL("EAX : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EIP]); - SPDLOG_CRITICAL("EIP : {} ", regbuffer); - snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EFL]); - SPDLOG_CRITICAL("EFL : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDI]); + SPDLOG_CRITICAL("EDI : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESI]); + SPDLOG_CRITICAL("ESI : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBP]); + SPDLOG_CRITICAL("EBP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESP]); + SPDLOG_CRITICAL("ESP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBX]); + SPDLOG_CRITICAL("EBX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDX]); + SPDLOG_CRITICAL("EDX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ECX]); + SPDLOG_CRITICAL("ECX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EAX]); + SPDLOG_CRITICAL("EAX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EIP]); + SPDLOG_CRITICAL("EIP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EFL]); + SPDLOG_CRITICAL("EFL : {} ", regbuffer); #endif } -static void ErrorHandler(int sig, siginfo_t* sigInfo, void* data) -{ - std::array arr; - ucontext_t* ctx = static_cast(data); - constexpr size_t nMaxFrames = arr.size(); - size_t size = backtrace(arr.data(), nMaxFrames); - char** symbols = backtrace_symbols(arr.data(), nMaxFrames); +static void ErrorHandler(int sig, siginfo_t* sigInfo, void* data) { + std::array arr; + ucontext_t* ctx = static_cast(data); + constexpr size_t nMaxFrames = arr.size(); + size_t size = backtrace(arr.data(), nMaxFrames); + char** symbols = backtrace_symbols(arr.data(), nMaxFrames); - SPDLOG_CRITICAL("(Signal: {})\n", sig); + SPDLOG_CRITICAL("(Signal: {})", sig); - switch (sig) { - case SIGILL: - SPDLOG_CRITICAL("ILLEGAL INSTRUCTION"); - break; - case SIGABRT: - SPDLOG_CRITICAL("ABORT"); - break; - case SIGFPE: - SPDLOG_CRITICAL("ERRONEUS ARITHEMETIC OPERATION"); - break; - case SIGSEGV: - SPDLOG_CRITICAL("INVALID ACCESS TO STORAGE"); - break; - } + switch (sig) { + case SIGILL: + SPDLOG_CRITICAL("ILLEGAL INSTRUCTION"); + break; + case SIGABRT: + SPDLOG_CRITICAL("ABORT"); + break; + case SIGFPE: + SPDLOG_CRITICAL("ERRONEUS ARITHEMETIC OPERATION"); + break; + case SIGSEGV: + SPDLOG_CRITICAL("INVALID ACCESS TO STORAGE"); + break; + } - PrintRegisters(ctx); + PrintRegisters(ctx); - SPDLOG_CRITICAL("Traceback:\n"); - for (size_t i = 1; i < size; i++) - { - Dl_info info; - int gotAddress = dladdr(arr[i], &info); - std::string functionName(symbols[i]); + SPDLOG_CRITICAL("Traceback:"); + for (size_t i = 1; i < size; i++) { + Dl_info info; + int gotAddress = dladdr(arr[i], &info); + std::string functionName(symbols[i]); - if (gotAddress != 0 && info.dli_sname != nullptr) - { + if (gotAddress != 0 && info.dli_sname != nullptr) { FILE* pipe; - int32_t status; - char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); - const char* nameFound = info.dli_sname; + int32_t status; + char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); + const char* nameFound = info.dli_sname; - if (status == 0) - { - nameFound = demangled; - } + if (status == 0) { + nameFound = demangled; + } #if 0 - char command[256]; + char command[256]; char addrLine[128]; snprintf(command, sizeof(command), "addr2line -e soh.elf %s + 0x%lX", nameFound, (uintptr_t)arr[i] - (uintptr_t)info.dli_saddr); - pipe = popen(command, "r"); + pipe = popen(command, "r"); fgets(addrLine, 128, pipe); - #endif - + #endif + functionName = StringHelper::Sprintf("%s (+0x%X)", nameFound, - (char*)arr[i] - (char*)info.dli_saddr); - free(demangled); - } + (char*)arr[i] - (char*)info.dli_saddr); + free(demangled); + } - SPDLOG_CRITICAL("{} {}", i, functionName.c_str()); - } + SPDLOG_CRITICAL("{} {}", i, functionName.c_str()); + } - free(symbols); - DeinitOTR(); - exit(1); + free(symbols); + DeinitOTR(); + exit(1); } static void ShutdownHandler(int sig, siginfo_t* sigInfo, void* data) { - DeinitOTR(); - exit(1); + DeinitOTR(); + exit(1); } extern "C" void SetupHandlerLinux() { - struct sigaction action; - struct sigaction shutdownAction; + struct sigaction action; + struct sigaction shutdownAction; - action.sa_flags = SA_SIGINFO; - action.sa_sigaction = ErrorHandler; - - sigaction(SIGILL, &action, nullptr); - sigaction(SIGABRT, &action, nullptr); - sigaction(SIGFPE, &action, nullptr); - sigaction(SIGSEGV, &action, nullptr); - - shutdownAction.sa_flags = SA_SIGINFO; - shutdownAction.sa_sigaction = ShutdownHandler; - sigaction(SIGINT, &shutdownAction, nullptr); - sigaction(SIGTERM, &shutdownAction, nullptr); - sigaction(SIGQUIT, &shutdownAction, nullptr); - sigaction(SIGKILL, &shutdownAction, nullptr); + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = ErrorHandler; + sigaction(SIGILL, &action, nullptr); + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); + shutdownAction.sa_flags = SA_SIGINFO; + shutdownAction.sa_sigaction = ShutdownHandler; + sigaction(SIGINT, &shutdownAction, nullptr); + sigaction(SIGTERM, &shutdownAction, nullptr); + sigaction(SIGQUIT, &shutdownAction, nullptr); + sigaction(SIGKILL, &shutdownAction, nullptr); } +#elif _WIN32 + +#if defined(_WIN32) && !defined(_WIN64) +#define WINDOWS_32_BIT +#endif + +static void PrintRegisters(CONTEXT* ctx) { + SPDLOG_CRITICAL("Register dump"); + char regBuff[50]; +#if defined(_M_AMD64) + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rax); + SPDLOG_CRITICAL("RAX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rcx); + SPDLOG_CRITICAL("RCX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rdx); + SPDLOG_CRITICAL("RDX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rbx); + SPDLOG_CRITICAL("RBX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rsp); + SPDLOG_CRITICAL("RSP: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rbp); + SPDLOG_CRITICAL("RBP: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rsi); + SPDLOG_CRITICAL("RSI: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rdi); + SPDLOG_CRITICAL("RDI: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R9); + SPDLOG_CRITICAL("R9: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R10); + SPDLOG_CRITICAL("R10: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R11); + SPDLOG_CRITICAL("R11: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R12); + SPDLOG_CRITICAL("R12: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R13); + SPDLOG_CRITICAL("R13: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R14); + SPDLOG_CRITICAL("R14: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R15); + SPDLOG_CRITICAL("R15: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rip); + SPDLOG_CRITICAL("RIP: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->EFlags); + SPDLOG_CRITICAL("EFLAGS: {}", regBuff); +#elif WINDOWS_32_BIT + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Edi); + SPDLOG_CRITICAL("EDI: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Esi); + SPDLOG_CRITICAL("ESI: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Ebx); + SPDLOG_CRITICAL("EBX: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Ecx); + SPDLOG_CRITICAL("ECX: 0x{}", ctx->Ecx); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Eax); + SPDLOG_CRITICAL("EAX: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Ebp); + SPDLOG_CRITICAL("EBP: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Esp); + SPDLOG_CRITICAL("ESP: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->EFlags); + SPDLOG_CRITICAL("EFLAGS: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Eip); + SPDLOG_CRITICAL("EIP: 0x{}", regBuff); +#endif +} + +static void printStack(CONTEXT* ctx) { + BOOL result; + HANDLE process; + HANDLE thread; + HMODULE hModule; + ULONG frame; + DWORD64 displacement; + DWORD disp; + +#if defined(_M_AMD64) + STACKFRAME64 stack; + memset(&stack, 0, sizeof(STACKFRAME64)); +#elif WINDOWS_32_BIT + STACKFRAME stack; + memset(&stack, 0, sizeof(STACKFRAME)); + stack.AddrPC.Offset = (*ctx).Eip; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrStack.Offset = (*ctx).Esp; + stack.AddrStack.Mode = AddrModeFlat; + stack.AddrFrame.Offset = (*ctx).Ebp; + stack.AddrFrame.Mode = AddrModeFlat; +#endif + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME + sizeof(TCHAR)]; + char module[512]; + + PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; + + CONTEXT ctx2; + memcpy(&ctx2, ctx, sizeof(CONTEXT)); + + PrintRegisters(&ctx2); + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + SymInitialize(process, nullptr, true); + + + constexpr DWORD machineType = +#if defined(_M_AMD64) + IMAGE_FILE_MACHINE_AMD64; +#elif WINDOWS_32_BIT + IMAGE_FILE_MACHINE_I386; +#endif + + displacement = 0; + for (frame = 0;; frame++) { + result = StackWalk(machineType, process, thread, &stack, &ctx2, nullptr, SymFunctionTableAccess, + SymGetModuleBase, nullptr); + if (!result) { + break; + } + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + SymFromAddr(process, (ULONG64)stack.AddrPC.Offset, &displacement, symbol); +#if defined(_M_AMD64) + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); +#elif WINDOWS_32_BIT + IMAGEHLP_LINE line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE); +#endif + if (SymGetLineFromAddr(process, stack.AddrPC.Offset, &disp, &line)) { + SPDLOG_CRITICAL("{} in {}: line: {}: ", symbol->Name, line.FileName, line.LineNumber); + } + else { + char addrString[25]; + snprintf(addrString, std::size(addrString), "0x%016llX", symbol->Address); + SPDLOG_CRITICAL("at {}, addr 0x{}", symbol->Name, addrString); + hModule = nullptr; + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCTSTR)(stack.AddrPC.Offset), &hModule); + + if (hModule != nullptr) { + GetModuleFileNameA(hModule, module, sizeof(module)); + } + SPDLOG_CRITICAL("In {}", module); + } + } + Ship::Window::GetInstance()->GetLogger()->flush(); + spdlog::shutdown(); + DeinitOTR(); +} + +extern "C" LONG seh_filter(struct _EXCEPTION_POINTERS* ex) { + char exceptionString[20]; + + snprintf(exceptionString, std::size(exceptionString), "0x%x", ex->ExceptionRecord->ExceptionCode); + + SPDLOG_CRITICAL("EXCEPTION {} occurred", exceptionString); + printStack(ex->ContextRecord); + MessageBox(nullptr, L"SoH Has crashed. Please upload the logs to the support channel in discord.", L"Crash", MB_OK | MB_ICONERROR); + + return EXCEPTION_EXECUTE_HANDLER; +} + + #endif diff --git a/libultraship/libultraship/CrashHandler.h b/libultraship/libultraship/CrashHandler.h index e068a4e38..103034ea4 100644 --- a/libultraship/libultraship/CrashHandler.h +++ b/libultraship/libultraship/CrashHandler.h @@ -13,6 +13,25 @@ void SetupHandlerLinux(void); } #endif -#endif // __linux__ +#elif _WIN32 // __linux__ ^^^^ _WIN32 vvvvv +#include +#include -#endif // CRASH_HANDLER_H \ No newline at end of file +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +LONG seh_filter(struct _EXCEPTION_POINTERS* ex); + +#ifdef __cplusplus +} +#endif + +#pragma comment(lib, "Dbghelp.lib") +#endif + +#endif // CRASH_HANDLER_H diff --git a/libultraship/libultraship/GameOverlay.cpp b/libultraship/libultraship/GameOverlay.cpp index b5225e22e..a331c5cf6 100644 --- a/libultraship/libultraship/GameOverlay.cpp +++ b/libultraship/libultraship/GameOverlay.cpp @@ -16,28 +16,28 @@ namespace Ship { if (CVar_Get(args[2].c_str()) != nullptr) { const char* key = args[2].c_str(); - GameOverlay* overlay = SohImGui::overlay; + GameOverlay* overlay = SohImGui::GetGameOverlay(); if (args[1] == "add") { if (!overlay->RegisteredOverlays.contains(key)) { overlay->RegisteredOverlays[key] = new Overlay({ OverlayType::TEXT, ImStrdup(key), -1.0f }); - SohImGui::console->SendInfoMessage("Added overlay: %s", key); + SohImGui::GetConsole()->SendInfoMessage("Added overlay: %s", key); } else { - SohImGui::console->SendErrorMessage("Overlay already exists: %s", key); + SohImGui::GetConsole()->SendErrorMessage("Overlay already exists: %s", key); } } else if (args[1] == "remove") { if (overlay->RegisteredOverlays.contains(key)) { overlay->RegisteredOverlays.erase(key); - SohImGui::console->SendInfoMessage("Removed overlay: %s", key); + SohImGui::GetConsole()->SendInfoMessage("Removed overlay: %s", key); } else { - SohImGui::console->SendErrorMessage("Overlay not found: %s", key); + SohImGui::GetConsole()->SendErrorMessage("Overlay not found: %s", key); } } } else { - SohImGui::console->SendErrorMessage("CVar {} does not exist", args[2].c_str()); + SohImGui::GetConsole()->SendErrorMessage("CVar {} does not exist", args[2].c_str()); } return CMD_SUCCESS; @@ -124,7 +124,7 @@ namespace Ship { else text_display_end = text_end; - GameOverlay* overlay = SohImGui::overlay; + GameOverlay* overlay = SohImGui::GetGameOverlay(); ImFont* font = overlay->CurrentFont == "Default" ? g.Font : overlay->Fonts[overlay->CurrentFont]; const float font_size = font->FontSize; @@ -157,7 +157,7 @@ namespace Ship { } } - SohImGui::console->AddCommand("overlay", { OverlayCommand, "Draw an overlay using a cvar value" }); + SohImGui::GetConsole()->AddCommand("overlay", { OverlayCommand, "Draw an overlay using a cvar value" }); } void GameOverlay::DrawSettings() { @@ -167,7 +167,7 @@ namespace Ship { if (ImGui::Selectable(name.c_str(), name == this->CurrentFont)) { this->CurrentFont = name; CVar_SetString("gOverlayFont", ImStrdup(name.c_str())); - SohImGui::needs_save = true; + SohImGui::RequestCvarSaveOnNextTick(); } } diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index aa0aca9ad..13e8ac078 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -7,13 +7,6 @@ #include #include -#include -#include -#include -#include -#include -#include "../../soh/include/z64audio.h" -#include "Archive.h" #include "Console.h" #include "Hooks.h" #define IMGUI_DEFINE_MATH_OPERATORS @@ -27,7 +20,6 @@ #include "Lib/stb/stb_image.h" #include "Lib/Fast3D/gfx_rendering_api.h" #include "Lib/spdlog/include/spdlog/common.h" -#include "UltraController.h" #ifdef __WIIU__ #include // GX2SetViewport / GX2SetScissor @@ -69,12 +61,8 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPAR using namespace Ship; bool oldCursorState = true; -#define EXPERIMENTAL() \ - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 50, 50, 255)); \ - InsertPadding(3.0f); \ - ImGui::Text("Experimental"); \ - ImGui::PopStyleColor(); \ - PaddedSeparator(false, true); +#define BindButton(btn, status) ImGui::Image(GetTextureByID(DefaultAssets[btn]->textureId), ImVec2(16.0f * scale, 16.0f * scale), ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, (status) ? 255 : 0)); + #define TOGGLE_BTN ImGuiKey_F1 #define TOGGLE_PAD_BTN ImGuiKey_GamepadBack #define HOOK(b) if(b) needs_save = true; @@ -83,21 +71,6 @@ OSContPad* pads; std::map DefaultAssets; std::vector emptyArgs; -bool isBetaQuestEnabled = false; - -enum SeqPlayers { - /* 0 */ SEQ_BGM_MAIN, - /* 1 */ SEQ_FANFARE, - /* 2 */ SEQ_SFX, - /* 3 */ SEQ_BGM_SUB, - /* 4 */ SEQ_MAX -}; - -extern "C" { - void enableBetaQuest() { isBetaQuestEnabled = true; } - void disableBetaQuest() { isBetaQuestEnabled = false; } -} - namespace SohImGui { WindowImpl impl; @@ -106,7 +79,10 @@ namespace SohImGui { GameOverlay* overlay = new GameOverlay; InputEditor* controller = new InputEditor; static ImVector s_GroupPanelLabelStack; - bool p_open = false; + + std::function clientDrawMenu; + std::function clientSetupHooks; + bool needs_save = false; int lastBackendID = 0; bool statsWindowOpen; @@ -132,32 +108,12 @@ namespace SohImGui { #endif }; - - const char* powers[9] = { - "Vanilla (1x)", - "Double (2x)", - "Quadruple (4x)", - "Octuple (8x)", - "Hexadecuple (16x)", - "Duotrigintuple (32x)", - "Quattuorsexagintuple (64x)", - "Octoviginticentuple (128x)", - "Hexaquinquagintiducentuple (256x)" - }; - std::map> hiddenwindowCategories; std::map> windowCategories; std::map customWindows; - void UpdateAudio() { - Audio_SetGameVolume(SEQ_BGM_MAIN, CVar_GetFloat("gMainMusicVolume", 1)); - Audio_SetGameVolume(SEQ_BGM_SUB, CVar_GetFloat("gSubMusicVolume", 1)); - Audio_SetGameVolume(SEQ_FANFARE, CVar_GetFloat("gSFXMusicVolume", 1)); - Audio_SetGameVolume(SEQ_SFX, CVar_GetFloat("gFanfareVolume", 1)); - } - void InitSettings() { - Ship::RegisterHook(UpdateAudio); + clientSetupHooks(); Ship::RegisterHook([] { gfx_get_current_rendering_api()->set_texture_filter((FilteringMode)CVar_GetS32("gTextureFilter", FILTER_THREE_POINT)); if (CVar_GetS32("gConsoleEnabled", 0)) { @@ -171,8 +127,6 @@ namespace SohImGui { } else { controller->Close(); } - - UpdateAudio(); }); } @@ -191,16 +145,6 @@ namespace SohImGui { return 0; } - int ClampFloatToInt(float value, int min, int max) { - return fmin(fmax(value, min), max); - } - - void Tooltip(const char* text) { - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s", BreakTooltip(text, 60).c_str()); - } - } - void ImGuiWMInit() { switch (impl.backend) { #ifdef __WIIU__ @@ -352,26 +296,6 @@ namespace SohImGui { } } - void ShowCursor(bool hide, Dialogues d) { - if (d == Dialogues::dLoadSettings) { - Window::GetInstance()->ShowCursor(hide); - return; - } - - if (d == Dialogues::dConsole && CVar_GetS32("gOpenMenuBar", 0)) { - return; - } - if (!Window::GetInstance()->IsFullscreen()) { - oldCursorState = false; - return; - } - - if (oldCursorState != hide) { - oldCursorState = hide; - Window::GetInstance()->ShowCursor(hide); - } - } - void LoadTexture(const std::string& name, const std::string& path) { GfxRenderingAPI* api = gfx_get_current_rendering_api(); const auto res = Window::GetInstance()->GetResourceManager()->LoadFile(path); @@ -392,65 +316,7 @@ namespace SohImGui { stbi_image_free(img_data); } - void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha) - { - Color_RGBA8 defaultColors; - defaultColors.r = default_colors.x; - defaultColors.g = default_colors.y; - defaultColors.b = default_colors.z; - defaultColors.a = default_colors.w; - - Color_RGBA8 cvarColor = CVar_GetRGBA(cvarname, defaultColors); - - ColorArray.x = cvarColor.r / 255.0; - ColorArray.y = cvarColor.g / 255.0; - ColorArray.z = cvarColor.b / 255.0; - ColorArray.w = cvarColor.a / 255.0; - } - - void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint) { - GfxRenderingAPI* api = gfx_get_current_rendering_api(); - const auto res = static_cast(Window::GetInstance()->GetResourceManager()->LoadResource(path).get()); - - std::vector texBuffer; - texBuffer.reserve(res->width * res->height * 4); - - switch (res->texType) { - case Ship::TextureType::RGBA32bpp: - texBuffer.assign(res->imageData, res->imageData + (res->width * res->height * 4)); - break; - case Ship::TextureType::GrayscaleAlpha8bpp: - for (int32_t i = 0; i < res->width * res->height; i++) { - uint8_t ia = res->imageData[i]; - uint8_t color = ((ia >> 4) & 0xF) * 255 / 15; - uint8_t alpha = (ia & 0xF) * 255 / 15; - texBuffer.push_back(color); - texBuffer.push_back(color); - texBuffer.push_back(color); - texBuffer.push_back(alpha); - } - break; - default: - // TODO convert other image types - SPDLOG_WARN("SohImGui::LoadResource: Attempting to load unsupporting image type %s", path.c_str()); - return; - } - - for (size_t pixel = 0; pixel < texBuffer.size() / 4; pixel++) { - texBuffer[pixel * 4 + 0] *= tint.x; - texBuffer[pixel * 4 + 1] *= tint.y; - texBuffer[pixel * 4 + 2] *= tint.z; - texBuffer[pixel * 4 + 3] *= tint.w; - } - - const auto asset = new GameAsset{ api->new_texture() }; - - api->select_texture(0, asset->textureId); - api->set_sampler_parameters(0, false, 0, 0); - api->upload_texture(texBuffer.data(), res->width, res->height); - - DefaultAssets[name] = asset; - } + // MARK: - Public API void Init(WindowImpl window_impl) { CVar_Load(); @@ -551,427 +417,6 @@ namespace SohImGui { ImGuiProcessEvent(event); } -#define BindButton(btn, status) ImGui::Image(GetTextureByID(DefaultAssets[btn]->textureId), ImVec2(16.0f * scale, 16.0f * scale), ImVec2(0, 0), ImVec2(1.0f, 1.0f), ImVec4(255, 255, 255, (status) ? 255 : 0)); - - void BindAudioSlider(const char* name, const char* key, float defaultValue, SeqPlayers playerId) - { - float value = CVar_GetFloat(key, defaultValue); - - ImGui::Text(name, static_cast(100 * value)); - if (ImGui::SliderFloat((std::string("##") + key).c_str(), &value, 0.0f, 1.0f, "")) { - const float volume = floorf(value * 100) / 100; - CVar_SetFloat(key, volume); - needs_save = true; - Audio_SetGameVolume(playerId, volume); - } - } - - void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue = 0) { - if (FirstTimeValue <= 0) { - FirstTimeValue = 0; - } - uint8_t selected = CVar_GetS32(name, FirstTimeValue); - uint8_t DefaultValue = selected; - std::string comboName = std::string("##") + std::string(name); - if (ImGui::BeginCombo(comboName.c_str(), ComboArray[DefaultValue])) { - for (uint8_t i = 0; i < arraySize; i++) { - if (strlen(ComboArray[i]) > 1) { - if (ImGui::Selectable(ComboArray[i], i == selected)) { - CVar_SetS32(name, i); - selected = i; - needs_save = true; - } - } - } - ImGui::EndCombo(); - } - } - - void EnhancementRadioButton(const char* text, const char* cvarName, int id) { - /*Usage : - EnhancementRadioButton("My Visible Name","gMyCVarName", MyID); - First arg is the visible name of the Radio button - Second is the cvar name where MyID will be saved. - Note: the CVar name should be the same to each Buddies. - Example : - EnhancementRadioButton("English", "gLanguages", 0); - EnhancementRadioButton("German", "gLanguages", 1); - EnhancementRadioButton("French", "gLanguages", 2); - */ - std::string make_invisible = "##"; - make_invisible += text; - make_invisible += cvarName; - - int val = CVar_GetS32(cvarName, 0); - if (ImGui::RadioButton(make_invisible.c_str(), id == val)) { - CVar_SetS32(cvarName, id); - needs_save = true; - } - ImGui::SameLine(); - ImGui::Text("%s", text); - } - - void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) - { - float thickness = ImMax(sz / 5.0f, 1.0f); - sz -= thickness * 0.5f; - pos += ImVec2(thickness * 0.25f, thickness * 0.25f); - - draw_list->PathLineTo(ImVec2(pos.x, pos.y)); - draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y + sz)); - draw_list->PathStroke(col, 0, thickness); - - draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y)); - draw_list->PathLineTo(ImVec2(pos.x, pos.y + sz)); - draw_list->PathStroke(col, 0, thickness); - } - - bool CustomCheckbox(const char* label, bool* v, bool disabled, ImGuiCheckboxGraphics disabledGraphic) { - ImGuiWindow* window = ImGui::GetCurrentWindow(); - if (window->SkipItems) - return false; - - ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); - const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); - - const float square_sz = ImGui::GetFrameHeight(); - const ImVec2 pos = window->DC.CursorPos; - const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); - ImGui::ItemSize(total_bb, style.FramePadding.y); - if (!ImGui::ItemAdd(total_bb, id)) - { - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); - return false; - } - - bool hovered, held; - bool pressed = ImGui::ButtonBehavior(total_bb, id, &hovered, &held); - if (pressed) - { - *v = !(*v); - ImGui::MarkItemEdited(id); - } - - const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); - ImGui::RenderNavHighlight(total_bb, id); - ImGui::RenderFrame(check_bb.Min, check_bb.Max, ImGui::GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); - ImU32 check_col = ImGui::GetColorU32(ImGuiCol_CheckMark); - ImU32 cross_col = ImGui::GetColorU32(ImVec4(0.50f, 0.50f, 0.50f, 1.00f)); - bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; - if (mixed_value) - { - // Undocumented tristate/mixed/indeterminate checkbox (#2644) - // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) - ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); - window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); - } - else if ((!disabled && *v) || (disabled && disabledGraphic == ImGuiCheckboxGraphics::Checkmark)) - { - const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); - ImGui::RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); - } - else if (disabled && disabledGraphic == ImGuiCheckboxGraphics::Cross) { - const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); - RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), cross_col, square_sz - pad * 2.0f); - } - - ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); - if (g.LogEnabled) - ImGui::LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); - if (label_size.x > 0.0f) - ImGui::RenderText(label_pos, label); - - IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); - return pressed; - } - - void EnhancementCheckbox(const char* text, const char* cvarName, bool disabled, const char* disabledTooltipText, ImGuiCheckboxGraphics disabledGraphic) - { - if (disabled) { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); - } - bool val = (bool)CVar_GetS32(cvarName, 0); - if (CustomCheckbox(text, &val, disabled, disabledGraphic)) { - CVar_SetS32(cvarName, val); - needs_save = true; - } - - if (disabled) { - ImGui::PopStyleVar(1); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && disabledTooltipText != "") { - ImGui::SetTooltip("%s", disabledTooltipText); - } - ImGui::PopItemFlag(); - } - } - - void EnhancementButton(const char* text, const char* cvarName) - { - bool val = (bool)CVar_GetS32(cvarName, 0); - if (ImGui::Button(text)) { - CVar_SetS32(cvarName, !val); - CVar_SetS32(cvarName, !val); - needs_save = true; - } - } - - void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton) - { - int val = CVar_GetS32(cvarName, defaultValue); - ImGui::Text(text, val); - if(PlusMinusButton) { - std::string MinusBTNName = " - ##"; - MinusBTNName += cvarName; - if (ImGui::Button(MinusBTNName.c_str())) { - val--; - CVar_SetS32(cvarName, val); - needs_save = true; - } - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - } - - if (ImGui::SliderInt(id, &val, min, max, format)) - { - CVar_SetS32(cvarName, val); - needs_save = true; - } - - if(PlusMinusButton) { - std::string PlusBTNName = " + ##"; - PlusBTNName += cvarName; - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - if (ImGui::Button(PlusBTNName.c_str())) { - val++; - CVar_SetS32(cvarName, val); - needs_save = true; - } - } - - if (val < min) - { - val = min; - CVar_SetS32(cvarName, val); - needs_save = true; - } - - if (val > max) - { - val = max; - CVar_SetS32(cvarName, val); - needs_save = true; - } - } - - void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton) - { - float val = CVar_GetFloat(cvarName, defaultValue); - - if (!isPercentage) - ImGui::Text(text, val); - else - ImGui::Text(text, static_cast(100 * val)); - - InsertPadding(); - - if(PlusMinusButton) { - std::string MinusBTNName = " - ##"; - MinusBTNName += cvarName; - if (ImGui::Button(MinusBTNName.c_str())) { - if (!isPercentage) - val -= 0.1f; - else - val -= 0.01f; - CVar_SetFloat(cvarName, val); - needs_save = true; - } - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - } - if (PlusMinusButton) { - #ifdef __WIIU__ - ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f * 2); - #else - ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f); - #endif - } - if (ImGui::SliderFloat(id, &val, min, max, format)) - { - CVar_SetFloat(cvarName, val); - needs_save = true; - } - if (PlusMinusButton) { - ImGui::PopItemWidth(); - } - if(PlusMinusButton) { - std::string PlusBTNName = " + ##"; - PlusBTNName += cvarName; - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - if (ImGui::Button(PlusBTNName.c_str())) { - if (!isPercentage) - val += 0.1f; - else - val += 0.01f; - CVar_SetFloat(cvarName, val); - needs_save = true; - } - } - - if (val < min) - { - val = min; - CVar_SetFloat(cvarName, val); - needs_save = true; - } - - if (val > max) - { - val = max; - CVar_SetFloat(cvarName, val); - needs_save = true; - } - } - - void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector& items, int defaultValue) { - - if (ImGui::BeginCombo(name.c_str(), items[static_cast(CVar_GetS32(cvarName, defaultValue))].c_str())) { - for (int settingIndex = 0; settingIndex < (int) items.size(); settingIndex++) { - if (ImGui::Selectable(items[settingIndex].c_str())) { - CVar_SetS32(cvarName, settingIndex); - needs_save = true; - - } - } - ImGui::EndCombo(); - } - } - - void RandomizeColor(const char* cvarName, ImVec4* colors) { - Color_RGBA8 NewColors = {0,0,0,255}; - std::string Cvar_RBM = cvarName; - Cvar_RBM += "RBM"; - std::string MakeInvisible = "##"; - MakeInvisible += cvarName; - MakeInvisible += "Random"; - std::string FullName = "Random"; - FullName += MakeInvisible; - if (ImGui::Button(FullName.c_str())) { - s16 RND_R = rand() % (255 - 0); - s16 RND_G = rand() % (255 - 0); - s16 RND_B = rand() % (255 - 0); - colors->x = (float)RND_R / 255; - colors->y = (float)RND_G / 255; - colors->z = (float)RND_B / 255; - NewColors.r = ClampFloatToInt(colors->x * 255, 0, 255); - NewColors.g = ClampFloatToInt(colors->y * 255, 0, 255); - NewColors.b = ClampFloatToInt(colors->z * 255, 0, 255); - CVar_SetRGBA(cvarName, NewColors); - CVar_SetS32(Cvar_RBM.c_str(), 0); //On click disable rainbow mode. - needs_save = true; - } - Tooltip("Chooses a random color\nOverwrites previously chosen color"); - } - - void RainbowColor(const char* cvarName, ImVec4* colors) { - std::string Cvar_RBM = cvarName; - Cvar_RBM += "RBM"; - std::string MakeInvisible = "Rainbow"; - MakeInvisible += "##"; - MakeInvisible += cvarName; - MakeInvisible += "Rainbow"; - - EnhancementCheckbox(MakeInvisible.c_str(), Cvar_RBM.c_str()); - Tooltip("Cycles through colors on a timer\nOverwrites previously chosen color"); - } - - void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha) { - std::string Cvar_RBM = cvarName; - Cvar_RBM += "RBM"; - std::string MakeInvisible = "Reset"; - MakeInvisible += "##"; - MakeInvisible += cvarName; - MakeInvisible += "Reset"; - if (ImGui::Button(MakeInvisible.c_str())) { - colors->x = defaultcolors.x; - colors->y = defaultcolors.y; - colors->z = defaultcolors.z; - if (has_alpha) { colors->w = defaultcolors.w; }; - - Color_RGBA8 colorsRGBA; - colorsRGBA.r = defaultcolors.x; - colorsRGBA.g = defaultcolors.y; - colorsRGBA.b = defaultcolors.z; - if (has_alpha) { colorsRGBA.a = defaultcolors.w; }; - - CVar_SetRGBA(cvarName, colorsRGBA); - CVar_SetS32(Cvar_RBM.c_str(), 0); //On click disable rainbow mode. - needs_save = true; - } - Tooltip("Revert colors to the game's original colors (GameCube version)\nOverwrites previously chosen color"); - } - - void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow, bool has_alpha, bool TitleSameLine) { - LoadPickersColors(ColorRGBA, cvarName, default_colors, has_alpha); - - ImGuiColorEditFlags flags = ImGuiColorEditFlags_None; - - if (!TitleSameLine) { - ImGui::Text("%s", text); - flags = ImGuiColorEditFlags_NoLabel; - } - - ImGui::PushID(cvarName); - - if (!has_alpha) { - if (ImGui::ColorEdit3(text, (float*)&ColorRGBA, flags)) - { - Color_RGBA8 colors; - colors.r = ColorRGBA.x * 255.0; - colors.g = ColorRGBA.y * 255.0; - colors.b = ColorRGBA.z * 255.0; - colors.a = ColorRGBA.w * 255.0; - - CVar_SetRGBA(cvarName, colors); - needs_save = true; - } - } - else - { - if (ImGui::ColorEdit4(text, (float*)&ColorRGBA, flags)) - { - Color_RGBA8 colors; - colors.r = ColorRGBA.x / 255; - colors.g = ColorRGBA.y / 255; - colors.b = ColorRGBA.z / 255; - colors.a = ColorRGBA.w / 255; - - CVar_SetRGBA(cvarName, colors); - needs_save = true; - } - } - - ImGui::PopID(); - - //ImGui::SameLine(); // Removing that one to gain some width spacing on the HUD editor - ImGui::PushItemWidth(-FLT_MIN); - ResetColor(cvarName, &ColorRGBA, default_colors, has_alpha); - ImGui::SameLine(); - RandomizeColor(cvarName, &ColorRGBA); - if (allow_rainbow) { - if (ImGui::GetContentRegionAvail().x > 185) { - ImGui::SameLine(); - } - RainbowColor(cvarName, &ColorRGBA); - } - ImGui::NewLine(); - ImGui::PopItemWidth(); - } - void DrawMainMenuAndCalculateGameSize(void) { console->Update(); ImGuiBackendNewFrame(); @@ -1030,13 +475,13 @@ namespace SohImGui { if ((ImGui::IsKeyDown(ImGuiKey_LeftSuper) || ImGui::IsKeyDown(ImGuiKey_RightSuper)) && ImGui::IsKeyPressed(ImGuiKey_R, false)) { - console->Dispatch("reset"); + DispatchConsoleCommand("reset"); } #else if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R, false)) { - console->Dispatch("reset"); + DispatchConsoleCommand("reset"); } #endif @@ -1076,958 +521,7 @@ namespace SohImGui { ImGui::SetCursorPosY(0.0f); - if (ImGui::BeginMenu("Settings")) - { - if (ImGui::BeginMenu("Audio")) { - EnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true); - InsertPadding(); - BindAudioSlider("Main Music Volume: %d %%", "gMainMusicVolume", 1.0f, SEQ_BGM_MAIN); - InsertPadding(); - BindAudioSlider("Sub Music Volume: %d %%", "gSubMusicVolume", 1.0f, SEQ_BGM_SUB); - InsertPadding(); - BindAudioSlider("Sound Effects Volume: %d %%", "gSFXMusicVolume", 1.0f, SEQ_SFX); - InsertPadding(); - BindAudioSlider("Fanfare Volume: %d %%", "gFanfareVolume", 1.0f, SEQ_FANFARE); - - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Controller")) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2 (12.0f, 6.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); - if (ImGui::Button(GetWindowButtonText("Controller Configuration", CVar_GetS32("gControllerConfigurationEnabled", 0)).c_str())) - { - bool currentValue = CVar_GetS32("gControllerConfigurationEnabled", 0); - CVar_SetS32("gControllerConfigurationEnabled", !currentValue); - needs_save = true; - if (CVar_GetS32("gControllerConfigurationEnabled", 0)) { - controller->Open(); - } else { - controller->Close(); - } - } - ImGui::PopStyleColor(1); - ImGui::PopStyleVar(3); - #ifndef __SWITCH__ - PaddedEnhancementCheckbox("Use Controller Navigation", "gControlNav", true, false); - Tooltip("Allows controller navigation of the menu bar\nD-pad to move between items, A to select, and X to grab focus on the menu bar"); - #endif - PaddedEnhancementCheckbox("Show Inputs", "gInputEnabled", true, false); - Tooltip("Shows currently pressed inputs on the bottom right of the screen"); - InsertPadding(); - ImGui::PushItemWidth(ImGui::GetWindowSize().x - 20.0f); - EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false); - Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting"); - ImGui::PopItemWidth(); - - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Graphics")) { - #ifndef __APPLE__ - EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, "", 1.0f, true, true); - Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective form of anti-aliasing"); - gfx_current_dimensions.internal_mul = CVar_GetFloat("gInternalResolution", 1); - #endif - #ifndef __WIIU__ - PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "", 1, false, true, false); - Tooltip("Activates multi-sample anti-aliasing when above 1x up to 8x for 8 samples for every pixel"); - gfx_msaa_level = CVar_GetS32("gMSAAValue", 1); - #endif - - if (impl.backend == Backend::DX11) - { - const char* cvar = "gExtraLatencyThreshold"; - int val = CVar_GetS32(cvar, 80); - val = MAX(MIN(val, 360), 0); - int fps = val; - - InsertPadding(); - - if (fps == 0) - { - ImGui::Text("Jitter fix: Off"); - } - else - { - ImGui::Text("Jitter fix: >= %d FPS", fps); - } - - std::string MinusBTNELT = " - ##ExtraLatencyThreshold"; - std::string PlusBTNELT = " + ##ExtraLatencyThreshold"; - if (ImGui::Button(MinusBTNELT.c_str())) { - val--; - CVar_SetS32(cvar, val); - needs_save = true; - } - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f); - if (ImGui::SliderInt("##ExtraLatencyThreshold", &val, 0, 360, "", ImGuiSliderFlags_AlwaysClamp)) - { - CVar_SetS32(cvar, val); - needs_save = true; - } - ImGui::PopItemWidth(); - Tooltip("When Interpolation FPS setting is at least this threshold, add one frame of input lag (e.g. 16.6 ms for 60 FPS) in order to avoid jitter. This setting allows the CPU to work on one frame while GPU works on the previous frame.\nThis setting should be used when your computer is too slow to do CPU + GPU work in time."); - - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - if (ImGui::Button(PlusBTNELT.c_str())) { - val++; - CVar_SetS32(cvar, val); - needs_save = true; - } - - InsertPadding(); - } - - ImGui::Text("Renderer API (Needs reload)"); - if (ImGui::BeginCombo("##RApi", backends[lastBackendID].second)) { - for (uint8_t i = 0; i < sizeof(backends) / sizeof(backends[0]); i++) { - if (ImGui::Selectable(backends[i].second, i == lastBackendID)) { - pConf->setString("Window.GfxBackend", backends[i].first); - lastBackendID = i; - } - } - ImGui::EndCombo(); - } - - EXPERIMENTAL(); - - ImGui::Text("Texture Filter (Needs reload)"); - EnhancementCombobox("gTextureFilter", filters, 3, 0); - - InsertPadding(); - - overlay->DrawSettings(); - - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Languages")) { - EnhancementRadioButton("English", "gLanguages", 0); - EnhancementRadioButton("German", "gLanguages", 1); - EnhancementRadioButton("French", "gLanguages", 2); - ImGui::EndMenu(); - } - ImGui::EndMenu(); - } - - ImGui::SetCursorPosY(0.0f); - - if (ImGui::BeginMenu("Enhancements")) - { - - const char* enhancementPresets[4] = { "Default", "Vanilla Plus", "Enhanced", "Randomizer"}; - PaddedText("Enhancement Presets", false, true); - SohImGui::EnhancementCombobox("gSelectEnhancementPresets", enhancementPresets, 4, 0); - Tooltip( - "Default - Set all enhancements to their default values. The true vanilla SoH experience.\n" - "\n" - "Vanilla Plus - Adds Quality of Life features that enhance your experience, but don't alter gameplay. Recommended for a first playthrough of OoT.\n" - "\n" - "Enhanced - The \"Vanilla Plus\" preset, but with more quality of life enhancements that might alter gameplay slightly. Recommended for returning players.\n" - "\n" - "Randomizer - The \"Enhanced\" preset, plus any other enhancements that are recommended for playing Randomizer." - ); - - InsertPadding(); - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f)); - if (ImGui::Button("Apply Preset")) { - applyEnhancementPresets(); - needs_save = true; - } - ImGui::PopStyleVar(1); - - PaddedSeparator(); - - if (ImGui::BeginMenu("Controls")) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); - float availableWidth = ImGui::GetContentRegionAvail().x; - if (ImGui::Button( - GetWindowButtonText("Customize Game Controls", CVar_GetS32("gGameControlEditorEnabled", 0)).c_str(), - ImVec2(availableWidth, 0) - )) { - bool currentValue = CVar_GetS32("gGameControlEditorEnabled", 0); - CVar_SetS32("gGameControlEditorEnabled", !currentValue); - needs_save = true; - customWindows["Game Control Editor"].enabled = CVar_GetS32("gGameControlEditorEnabled", 0); - } - ImGui::PopStyleVar(3); - ImGui::PopStyleColor(1); - - // TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected - PaddedEnhancementCheckbox("D-pad Support on Pause and File Select", "gDpadPauseName"); - Tooltip("Enables Pause and File Select screen navigation with the D-pad\nIf used with D-pad as Equip Items, you must hold C-Up to equip instead of navigate"); - PaddedEnhancementCheckbox("D-pad Support in Text Choice", "gDpadText", true, false); - PaddedEnhancementCheckbox("D-pad Support for Browsing Shop Items", "gDpadShop", true, false); - PaddedEnhancementCheckbox("D-pad as Equip Items", "gDpadEquips", true, false); - Tooltip("Allows the D-pad to be used as extra C buttons"); - PaddedEnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor", true, false); - Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97"); - PaddedEnhancementCheckbox("Prevent Dropped Ocarina Inputs", "gDpadNoDropOcarinaInput", true, false); - Tooltip("Prevent dropping inputs when playing the ocarina quickly"); - PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL", true, false); - Tooltip("Speak to Navi with L but enter first-person camera with C-Up"); - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Gameplay")) - { - if (ImGui::BeginMenu("Time Savers")) - { - PaddedEnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, "", 1, false, false, true); - PaddedEnhancementSliderInt("King Zora Speed: %dx", "##MWEEPSPEED", "gMweepSpeed", 1, 5, "", 1, false, false, true); - EnhancementSliderInt("Biggoron Forge Time: %d days", "##FORGETIME", "gForgeTime", 0, 3, "", 3); - Tooltip("Allows you to change the number of days it takes for Biggoron to forge the Biggoron Sword"); - PaddedEnhancementSliderInt("Vine/Ladder Climb speed +%d", "##CLIMBSPEED", "gClimbSpeed", 0, 12, "", 0, false, false, true); - PaddedEnhancementSliderInt("Block pushing speed +%d", "##BLOCKSPEED", "gFasterBlockPush", 0, 5, "", 0, false, false, true); - PaddedEnhancementCheckbox("Faster Heavy Block Lift", "gFasterHeavyBlockLift", true, false); - Tooltip("Speeds up lifting silver rocks and obelisks"); - PaddedEnhancementCheckbox("No Forced Navi", "gNoForcedNavi", true, false); - Tooltip("Prevent forced Navi conversations"); - PaddedEnhancementCheckbox("No Skulltula Freeze", "gSkulltulaFreeze", true, false); - Tooltip("Stops the game from freezing the player when picking up Gold Skulltulas"); - PaddedEnhancementCheckbox("MM Bunny Hood", "gMMBunnyHood", true, false); - Tooltip("Wearing the Bunny Hood grants a speed increase like in Majora's Mask"); - PaddedEnhancementCheckbox("Fast Chests", "gFastChests", true, false); - Tooltip("Kick open every chest"); - PaddedEnhancementCheckbox("Skip Pickup Messages", "gFastDrops", true, false); - Tooltip("Skip pickup messages for new consumable items and bottle swipes"); - PaddedEnhancementCheckbox("Better Owl", "gBetterOwl", true, false); - Tooltip("The default response to Kaepora Gaebora is always that you understood what he said"); - PaddedEnhancementCheckbox("Fast Ocarina Playback", "gFastOcarinaPlayback", true, false); - Tooltip("Skip the part where the Ocarina playback is called when you play a song"); - PaddedEnhancementCheckbox("Skip Scarecrow Song", "gSkipScarecrow", true, false); - Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song."); - PaddedEnhancementCheckbox("Instant Putaway", "gInstantPutaway", true, false); - Tooltip("Allow Link to put items away without having to wait around"); - PaddedEnhancementCheckbox("Instant Boomerang Recall", "gFastBoomerang", true, false); - Tooltip("Instantly return the boomerang to Link by pressing its item button while it's in the air"); - PaddedEnhancementCheckbox("Mask Select in Inventory", "gMaskSelect", true, false); - Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); - PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false); - Tooltip("When loading a save, places Link at the last entrance he went through.\n" - "This doesn't work if the save was made in a grotto."); - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Difficulty Options")) - { - ImGui::Text("Damage Multiplier"); - EnhancementCombobox("gDamageMul", powers, 9, 0); - Tooltip( - "Modifies all sources of damage not affected by other sliders\n\ - 2x: Can survive all common attacks from the start of the game\n\ - 4x: Dies in 1 hit to any substantial attack from the start of the game\n\ - 8x: Can only survive trivial damage from the start of the game\n\ - 16x: Can survive all common attacks with max health without double defense\n\ - 32x: Can survive all common attacks with max health and double defense\n\ - 64x: Can survive trivial damage with max health without double defense\n\ - 128x: Can survive trivial damage with max health and double defense\n\ - 256x: Cannot survive damage" - ); - PaddedText("Fall Damage Multiplier", true, false); - EnhancementCombobox("gFallDamageMul", powers, 8, 0); - Tooltip( - "Modifies all fall damage\n\ - 2x: Can survive all fall damage from the start of the game\n\ - 4x: Can only survive short fall damage from the start of the game\n\ - 8x: Cannot survive any fall damage from the start of the game\n\ - 16x: Can survive all fall damage with max health without double defense\n\ - 32x: Can survive all fall damage with max health and double defense\n\ - 64x: Can survive short fall damage with double defense\n\ - 128x: Cannot survive fall damage" - ); - PaddedText("Void Damage Multiplier", true, false); - EnhancementCombobox("gVoidDamageMul", powers, 7, 0); - Tooltip( - "Modifies damage taken after falling into a void\n\ - 2x: Can survive void damage from the start of the game\n\ - 4x: Cannot survive void damage from the start of the game\n\ - 8x: Can survive void damage twice with max health without double defense\n\ - 16x: Can survive void damage with max health without double defense\n\ - 32x: Can survive void damage with max health and double defense\n\ - 64x: Cannot survive void damage" - ); - PaddedEnhancementCheckbox("No Random Drops", "gNoRandomDrops", true, false); - Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses"); - PaddedEnhancementCheckbox("Enable Bombchu Drops", "gBombchuDrops", true, false); - Tooltip("Bombchus will sometimes drop in place of bombs"); - PaddedEnhancementCheckbox("No Heart Drops", "gNoHeartDrops", true, false); - Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series"); - PaddedEnhancementCheckbox("Always Win Goron Pot", "gGoronPot", true, false); - Tooltip("Always get the heart piece/purple rupee from the spinning Goron pot"); - InsertPadding(); - - if (ImGui::BeginMenu("Potion Values")) - { - EnhancementCheckbox("Change Red Potion Effect", "gRedPotionEffect"); - Tooltip("Enable the following changes to the amount of health restored by Red Potions"); - EnhancementSliderInt("Red Potion Health: %d", "##REDPOTIONHEALTH", "gRedPotionHealth", 1, 100, "", 0, true); - Tooltip("Changes the amount of health restored by Red Potions"); - EnhancementCheckbox("Red Potion Percent Restore", "gRedPercentRestore"); - Tooltip("Toggles from Red Potions restoring a fixed amount of health to a percent of the player's current max health"); - - ImGui::Separator(); - - EnhancementCheckbox("Change Green Potion Effect", "gGreenPotionEffect"); - Tooltip("Enable the following changes to the amount of mana restored by Green Potions"); - EnhancementSliderInt("Green Potion Mana: %d", "##GREENPOTIONMANA", "gGreenPotionMana", 1, 100, "", 0, true); - Tooltip("Changes the amount of mana restored by Green Potions, base max mana is 48, max upgraded mana is 96"); - EnhancementCheckbox("Green Potion Percent Restore", "gGreenPercentRestore"); - Tooltip("Toggles from Green Potions restoring a fixed amount of mana to a percent of the player's current max mana"); - - ImGui::Separator(); - - EnhancementCheckbox("Change Blue Potion Effects", "gBluePotionEffects"); - Tooltip("Enable the following changes to the amount of health and mana restored by Blue Potions"); - EnhancementSliderInt("Blue Potion Health: %d", "##BLUEPOTIONHEALTH", "gBluePotionHealth", 1, 100, "", 0, true); - Tooltip("Changes the amount of health restored by Blue Potions"); - EnhancementCheckbox("Blue Potion Health Percent Restore", "gBlueHealthPercentRestore"); - Tooltip("Toggles from Blue Potions restoring a fixed amount of health to a percent of the player's current max health"); - - ImGui::Separator(); - - EnhancementSliderInt("Blue Potion Mana: %d", "##BLUEPOTIONMANA", "gBluePotionMana", 1, 100, "", 0, true); - Tooltip("Changes the amount of mana restored by Blue Potions, base max mana is 48, max upgraded mana is 96"); - EnhancementCheckbox("Blue Potion Mana Percent Restore", "gBlueManaPercentRestore"); - Tooltip("Toggles from Blue Potions restoring a fixed amount of mana to a percent of the player's current max mana"); - - ImGui::Separator(); - - EnhancementCheckbox("Change Milk Effect", "gMilkEffect"); - Tooltip("Enable the following changes to the amount of health restored by Milk"); - EnhancementSliderInt("Milk Health: %d", "##MILKHEALTH", "gMilkHealth", 1, 100, "", 0, true); - Tooltip("Changes the amount of health restored by Milk"); - EnhancementCheckbox("Milk Percent Restore", "gMilkPercentRestore"); - Tooltip("Toggles from Milk restoring a fixed amount of health to a percent of the player's current max health"); - - ImGui::Separator(); - - EnhancementCheckbox("Separate Half Milk Effect", "gSeparateHalfMilkEffect"); - Tooltip("Enable the following changes to the amount of health restored by Half Milk\nIf this is disabled, Half Milk will behave the same as Full Milk."); - EnhancementSliderInt("Half Milk Health: %d", "##HALFMILKHEALTH", "gHalfMilkHealth", 1, 100, "", 0, true); - Tooltip("Changes the amount of health restored by Half Milk"); - EnhancementCheckbox("Half Milk Percent Restore", "gHalfMilkPercentRestore"); - Tooltip("Toggles from Half Milk restoring a fixed amount of health to a percent of the player's current max health"); - - ImGui::Separator(); - - EnhancementCheckbox("Change Fairy Effect", "gFairyEffect"); - Tooltip("Enable the following changes to the amount of health restored by Fairies"); - EnhancementSliderInt("Fairy: %d", "##FAIRYHEALTH", "gFairyHealth", 1, 100, "", 0, true); - Tooltip("Changes the amount of health restored by Fairies"); - EnhancementCheckbox("Fairy Percent Restore", "gFairyPercentRestore"); - Tooltip("Toggles from Fairies restoring a fixed amount of health to a percent of the player's current max health"); - - ImGui::Separator(); - - EnhancementCheckbox("Change Fairy Revive Effect", "gFairyReviveEffect"); - Tooltip("Enable the following changes to the amount of health restored by Fairy Revivals"); - EnhancementSliderInt("Fairy Revival: %d", "##FAIRYREVIVEHEALTH", "gFairyReviveHealth", 1, 100, "", 0, true); - Tooltip("Changes the amount of health restored by Fairy Revivals"); - EnhancementCheckbox("Fairy Revive Percent Restore", "gFairyRevivePercentRestore"); - Tooltip("Toggles from Fairy Revivals restoring a fixed amount of health to a percent of the player's current max health"); - - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Fishing")) { - EnhancementCheckbox("Instant Fishing", "gInstantFishing"); - Tooltip("All fish will be caught instantly"); - PaddedEnhancementCheckbox("Guarantee Bite", "gGuaranteeFishingBite", true, false); - Tooltip("When a line is stable, guarantee bite. Otherwise use default logic"); - PaddedEnhancementSliderInt("Child Minimum Weight: %d", "##cMinimumWeight", "gChildMinimumWeightFish", 6, 10, "", 10, false, true, false); - Tooltip("The minimum weight for the unique fishing reward as a child"); - PaddedEnhancementSliderInt("Adult Minimum Weight: %d", "##aMinimumWeight", "gAdultMinimumWeightFish", 8, 13, "", 13, false, true, false); - Tooltip("The minimum weight for the unique fishing reward as an adult"); - ImGui::EndMenu(); - } - - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Reduced Clutter")) - { - EnhancementCheckbox("Mute Low HP Alarm", "gLowHpAlarm"); - Tooltip("Disable the low HP beeping sound"); - PaddedEnhancementCheckbox("Minimal UI", "gMinimalUI", true, false); - Tooltip("Hides most of the UI when not needed\nNote: Doesn't activate until after loading a new scene"); - PaddedEnhancementCheckbox("Disable Navi Call Audio", "gDisableNaviCallAudio", true, false); - Tooltip("Disables the voice audio when Navi calls you"); - - ImGui::EndMenu(); - } - - InsertPadding(); - - EnhancementCheckbox("Visual Stone of Agony", "gVisualAgony"); - Tooltip("Displays an icon and plays a sound when Stone of Agony should be activated, for those without rumble"); - PaddedEnhancementCheckbox("Assignable Tunics and Boots", "gAssignableTunicsAndBoots", true, false); - Tooltip("Allows equipping the tunic and boots to c-buttons"); - PaddedEnhancementCheckbox("Equipment Toggle", "gEquipmentCanBeRemoved", true, false); - Tooltip("Allows equipment to be removed by toggling it off on\nthe equipment subscreen."); - PaddedEnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime", true, false); - Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods"); - PaddedEnhancementCheckbox("Enable visible guard vision", "gGuardVision", true, false); - PaddedEnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect", true, false); - PaddedEnhancementCheckbox("Count Golden Skulltulas", "gInjectSkulltulaCount", true, false); - Tooltip("Injects Golden Skulltula total count in pickup messages"); - PaddedEnhancementCheckbox("Pull grave during the day", "gDayGravePull", true, false); - Tooltip("Allows graves to be pulled when child during the day"); - PaddedEnhancementCheckbox("Blue Fire Arrows", "gBlueFireArrows", true, false); - Tooltip("Allows Ice Arrows to melt red ice (may need to reload the room when first enabled)"); - PaddedEnhancementCheckbox("Sunlight Arrows", "gSunlightArrows", true, false); - Tooltip("Allows Light Arrows to activate sun switches (may need to reload the room when first enabled)"); - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Graphics")) - { - if (ImGui::BeginMenu("Animated Link in Pause Menu")) { - ImGui::Text("Rotation"); - EnhancementRadioButton("Disabled", "gPauseLiveLinkRotation", 0); - EnhancementRadioButton("Rotate Link with D-pad", "gPauseLiveLinkRotation", 1); - Tooltip("Allow you to rotate Link on the Equipment menu with the D-pad\nUse D-pad Up or D-pad Down to reset Link's rotation"); - EnhancementRadioButton("Rotate Link with C-buttons", "gPauseLiveLinkRotation", 2); - Tooltip("Allow you to rotate Link on the Equipment menu with the C-buttons\nUse C-Up or C-Down to reset Link's rotation"); - EnhancementRadioButton("Rotate Link with Right Stick", "gPauseLiveLinkRotation", 3); - Tooltip("Allow you to rotate Link on the Equipment menu with the Right Stick\nYou can zoom in by pointing up and reset Link's rotation by pointing down"); - if (CVar_GetS32("gPauseLiveLinkRotation", 0) != 0) { - EnhancementSliderInt("Rotation Speed: %d", "##MinRotationSpeed", "gPauseLiveLinkRotationSpeed", 1, 20, ""); - } - PaddedSeparator(); - ImGui::Text("Static loop"); - EnhancementRadioButton("Disabled", "gPauseLiveLink", 0); - EnhancementRadioButton("Idle (standing)", "gPauseLiveLink", 1); - EnhancementRadioButton("Idle (look around)", "gPauseLiveLink", 2); - EnhancementRadioButton("Idle (belt)", "gPauseLiveLink", 3); - EnhancementRadioButton("Idle (shield)", "gPauseLiveLink", 4); - EnhancementRadioButton("Idle (test sword)", "gPauseLiveLink", 5); - EnhancementRadioButton("Idle (yawn)", "gPauseLiveLink", 6); - EnhancementRadioButton("Battle Stance", "gPauseLiveLink", 7); - EnhancementRadioButton("Walking (no shield)", "gPauseLiveLink", 8); - EnhancementRadioButton("Walking (holding shield)", "gPauseLiveLink", 9); - EnhancementRadioButton("Running (no shield)", "gPauseLiveLink", 10); - EnhancementRadioButton("Running (holding shield)", "gPauseLiveLink", 11); - EnhancementRadioButton("Hand on hip", "gPauseLiveLink", 12); - EnhancementRadioButton("Spin attack charge", "gPauseLiveLink", 13); - EnhancementRadioButton("Look at hand", "gPauseLiveLink", 14); - PaddedSeparator(); - ImGui::Text("Randomize"); - EnhancementRadioButton("Random", "gPauseLiveLink", 15); - Tooltip("Randomize the animation played each time you open the menu"); - EnhancementRadioButton("Random cycle", "gPauseLiveLink", 16); - Tooltip("Randomize the animation played on the menu after a certain time"); - EnhancementRadioButton("Random cycle (Idle)", "gPauseLiveLink", 17); - Tooltip("Randomize the animation played on the menu after a certain time (Idle animations only)"); - if (CVar_GetS32("gPauseLiveLink", 0) >= 16) { - EnhancementSliderInt("Frame to wait: %d", "##MinFrameCount", "gMinFrameCount", 1, 1000, "", 0, true); - } - - ImGui::EndMenu(); - } - PaddedEnhancementCheckbox("N64 Mode", "gN64Mode", true, false); - Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution"); - PaddedEnhancementCheckbox("Enable 3D Dropped items/projectiles", "gNewDrops", true, false); - Tooltip("Change most 2D items and projectiles on the overworld to their 3D versions"); - PaddedEnhancementCheckbox("Disable Black Bar Letterboxes", "gDisableBlackBars", true, false); - Tooltip("Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be minor visual glitches that were covered up by the black bars\nPlease disable this setting before reporting a bug"); - PaddedEnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon", true, false); - Tooltip("Changes the rupee in the wallet icon to match the wallet size you currently have"); - PaddedEnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon", true, false); - Tooltip("Always shows dungeon entrance icons on the minimap"); - - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Fixes")) - { - EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR"); - Tooltip("Makes the L and R buttons in the pause menu the same color"); - PaddedEnhancementCheckbox("Fix L&Z Page switch in Pause menu", "gNGCKaleidoSwitcher", true, false); - Tooltip("Makes L and R switch pages like on the GameCube\nZ opens the Debug Menu instead"); - PaddedEnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon", true, false); - Tooltip("Removes the dungeon entrance icon on the top-left corner of the screen when no dungeon is present on the current map"); - PaddedEnhancementCheckbox("Fix Two Handed idle animations", "gTwoHandedIdle", true, false); - Tooltip("Re-enables the two-handed idle animation, a seemingly finished animation that was disabled on accident in the original game"); - PaddedEnhancementCheckbox("Fix the Gravedigging Tour Glitch", "gGravediggingTourFix", true, false); - Tooltip("Fixes a bug where the Gravedigging Tour Heart Piece disappears if the area reloads"); - PaddedEnhancementCheckbox("Fix Deku Nut upgrade", "gDekuNutUpgradeFix", true, false); - Tooltip("Prevents the Forest Stage Deku Nut upgrade from becoming unobtainable after receiving the Poacher's Saw"); - PaddedEnhancementCheckbox("Fix Navi text HUD position", "gNaviTextFix", true, false); - Tooltip("Correctly centers the Navi text prompt on the HUD's C-Up button"); - PaddedEnhancementCheckbox("Fix Anubis fireballs", "gAnubisFix", true, false); - Tooltip("Make Anubis fireballs do fire damage when reflected back at them with the Mirror Shield"); - PaddedEnhancementCheckbox("Fix Megaton Hammer crouch stab", "gCrouchStabHammerFix", true, false); - Tooltip("Make the Megaton Hammer's crouch stab able to destroy rocks without first swinging it normally"); - if (CVar_GetS32("gCrouchStabHammerFix", 0) == 0) { - CVar_SetS32("gCrouchStabFix", 0); - } else { - PaddedEnhancementCheckbox("Remove power crouch stab", "gCrouchStabFix", true, false); - Tooltip("Make crouch stabbing always do the same damage as a regular slash"); - } - - ImGui::EndMenu(); - } - - InsertPadding(); - - if (ImGui::BeginMenu("Restoration")) - { - EnhancementCheckbox("Red Ganon blood", "gRedGanonBlood"); - Tooltip("Restore the original red blood from NTSC 1.0/1.1. Disable for green blood"); - PaddedEnhancementCheckbox("Fish while hovering", "gHoverFishing", true, false); - Tooltip("Restore a bug from NTSC 1.0 that allows casting the Fishing Rod while using the Hover Boots"); - PaddedEnhancementCheckbox("N64 Weird Frames", "gN64WeirdFrames", true, false); - Tooltip("Restores N64 Weird Frames allowing weirdshots to behave the same as N64"); - PaddedEnhancementCheckbox("Bombchus out of bounds", "gBombchusOOB", true, false); - Tooltip("Allows bombchus to explode out of bounds\nSimilar to GameCube and Wii VC"); - PaddedEnhancementCheckbox("Restore old Gold Skulltula cutscene", "gGsCutscene", true, false); - - ImGui::EndMenu(); - } - - PaddedEnhancementCheckbox("Autosave", "gAutosave", true, false); - Tooltip("Automatically save the game every time a new area is entered or item is obtained\n" - "To disable saving when obtaining an item, manually set gAutosaveAllItems and gAutosaveMajorItems to 0\n" - "gAutosaveAllItems takes priority over gAutosaveMajorItems if both are set to 1\n" - "gAutosaveMajorItems excludes rupees and health/magic/ammo refills (but includes bombchus)"); - - InsertPadding(); - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); - static ImVec2 buttonSize(200.0f, 0.0f); - if (ImGui::Button(GetWindowButtonText("Cosmetics Editor", CVar_GetS32("gCosmeticsEditorEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gCosmeticsEditorEnabled", 0); - CVar_SetS32("gCosmeticsEditorEnabled", !currentValue); - needs_save = true; - customWindows["Cosmetics Editor"].enabled = CVar_GetS32("gCosmeticsEditorEnabled", 0); - } - ImGui::PopStyleVar(3); - ImGui::PopStyleColor(1); - - EXPERIMENTAL(); - - const char* fps_cvar = "gInterpolationFPS"; - { - #if defined(__SWITCH__) || defined(__WIIU__) - int minFps = 20; - int maxFps = 60; - #else - int minFps = 20; - int maxFps = 360; - #endif - - int val = CVar_GetS32(fps_cvar, minFps); - val = MAX(MIN(val, maxFps), 20); - - #ifdef __WIIU__ - // only support divisors of 60 on the Wii U - val = 60 / (60 / val); - #endif - - int fps = val; - - if (fps == 20) - { - ImGui::Text("Frame interpolation: Off"); - } - else - { - ImGui::Text("Frame interpolation: %d FPS", fps); - } - - std::string MinusBTNFPSI = " - ##FPSInterpolation"; - std::string PlusBTNFPSI = " + ##FPSInterpolation"; - if (ImGui::Button(MinusBTNFPSI.c_str())) { - #ifdef __WIIU__ - if (val >= 60) val = 30; - else val = 20; - #else - val--; - #endif - CVar_SetS32(fps_cvar, val); - needs_save = true; - } - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - #ifdef __WIIU__ - ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f * 2); - #else - ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f); - #endif - if (ImGui::SliderInt("##FPSInterpolation", &val, minFps, maxFps, "", ImGuiSliderFlags_AlwaysClamp)) - { - #ifdef __WIIU__ - // only support divisors of 60 on the Wii U - val = 60 / (60 / val); - #endif - if (val > 360) - { - val = 360; - } - else if (val < 20) - { - val = 20; - } - - CVar_SetS32(fps_cvar, val); - needs_save = true; - } - ImGui::PopItemWidth(); - Tooltip("Interpolate extra frames to get smoother graphics\n" - "Set to match your monitor's refresh rate, or a divisor of it\n" - "A higher target FPS than your monitor's refresh rate will just waste resources, " - "and might give a worse result.\n" - "For consistent input lag, set this value and your monitor's refresh rate to a multiple of 20\n" - "Ctrl+Click for keyboard input"); - - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - if (ImGui::Button(PlusBTNFPSI.c_str())) { - #ifdef __WIIU__ - if (val <= 20) val = 30; - else val = 60; - #else - val++; - #endif - CVar_SetS32(fps_cvar, val); - needs_save = true; - } - } - - if (impl.backend == Backend::DX11) - { - InsertPadding(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f)); - if (ImGui::Button("Match Refresh Rate")) - { - int hz = roundf(gfx_get_detected_hz()); - if (hz >= 20 && hz <= 360) - { - CVar_SetS32(fps_cvar, hz); - needs_save = true; - } - } - ImGui::PopStyleVar(1); - InsertPadding(); - } - EnhancementCheckbox("Disable LOD", "gDisableLOD"); - Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance"); - PaddedEnhancementCheckbox("Disable Draw Distance", "gDisableDrawDistance", true, false); - Tooltip("Turns off the objects draw distance, making objects being visible from a longer range"); - if (CVar_GetS32("gDisableDrawDistance", 0) == 0) { - CVar_SetS32("gDisableKokiriDrawDistance", 0); - } else if (CVar_GetS32("gDisableDrawDistance", 0) == 1) { - PaddedEnhancementCheckbox("Kokiri Draw Distance", "gDisableKokiriDrawDistance", true, false); - Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this will remove their draw distance"); - } - PaddedEnhancementCheckbox("Skip Text", "gSkipText", true, false); - Tooltip("Holding down B skips text\nKnown to cause a cutscene softlock in Water Temple\nSoftlock can be fixed by pressing D-Right in Debug mode"); - PaddedEnhancementCheckbox("Free Camera", "gFreeCamera", true, false); - Tooltip("Enables camera control\nNote: You must remap C buttons off of the right stick in the controller config menu, and map the camera stick to the right stick."); - - #ifdef __SWITCH__ - InsertPadding(); - int slot = CVar_GetS32("gSwitchPerfMode", (int)SwitchProfiles::STOCK); - ImGui::Text("Switch performance mode"); - if (ImGui::BeginCombo("##perf", SWITCH_CPU_PROFILES[slot])) { - for (int sId = 0; sId <= SwitchProfiles::POWERSAVINGM3; sId++) { - if (ImGui::Selectable(SWITCH_CPU_PROFILES[sId], sId == slot)) { - SPDLOG_INFO("Profile:: %s", SWITCH_CPU_PROFILES[sId]); - CVar_SetS32("gSwitchPerfMode", sId); - Switch::ApplyOverclock(); - needs_save = true; - } - - } - ImGui::EndCombo(); - } - #endif - - ImGui::EndMenu(); - } - - ImGui::SetCursorPosY(0.0f); - - if (ImGui::BeginMenu("Cheats")) - { - if (ImGui::BeginMenu("Infinite...")) { - EnhancementCheckbox("Money", "gInfiniteMoney"); - PaddedEnhancementCheckbox("Health", "gInfiniteHealth", true, false); - PaddedEnhancementCheckbox("Ammo", "gInfiniteAmmo", true, false); - PaddedEnhancementCheckbox("Magic", "gInfiniteMagic", true, false); - PaddedEnhancementCheckbox("Nayru's Love", "gInfiniteNayru", true, false); - PaddedEnhancementCheckbox("Epona Boost", "gInfiniteEpona", true, false); - - ImGui::EndMenu(); - } - - PaddedEnhancementCheckbox("No Clip", "gNoClip", true, false); - Tooltip("Allows you to walk through walls"); - PaddedEnhancementCheckbox("Climb Everything", "gClimbEverything", true, false); - Tooltip("Makes every surface in the game climbable"); - PaddedEnhancementCheckbox("Moon Jump on L", "gMoonJumpOnL", true, false); - Tooltip("Holding L makes you float into the air"); - PaddedEnhancementCheckbox("Super Tunic", "gSuperTunic", true, false); - Tooltip("Makes every tunic have the effects of every other tunic"); - PaddedEnhancementCheckbox("Easy ISG", "gEzISG", true, false); - Tooltip("Passive Infinite Sword Glitch\nIt makes your sword's swing effect and hitbox stay active indefinitely"); - PaddedEnhancementCheckbox("Unrestricted Items", "gNoRestrictItems", true, false); - Tooltip("Allows you to use any item at any location"); - PaddedEnhancementCheckbox("Freeze Time", "gFreezeTime", true, false); - Tooltip("Freezes the time of day"); - PaddedEnhancementCheckbox("Drops Don't Despawn", "gDropsDontDie", true, false); - Tooltip("Drops from enemies, grass, etc. don't disappear after a set amount of time"); - PaddedEnhancementCheckbox("Fireproof Deku Shield", "gFireproofDekuShield", true, false); - Tooltip("Prevents the Deku Shield from burning on contact with fire"); - PaddedEnhancementCheckbox("Shield with Two-Handed Weapons", "gShieldTwoHanded", true, false); - Tooltip("This allows you to put up your shield with any two-handed weapon in hand except for Deku Sticks"); - PaddedEnhancementCheckbox("Time Sync", "gTimeSync", true, false); - Tooltip("This syncs the ingame time with the real world time"); - - { - static int32_t betaQuestEnabled = CVar_GetS32("gEnableBetaQuest", 0); - static int32_t lastBetaQuestEnabled = betaQuestEnabled; - static int32_t betaQuestWorld = CVar_GetS32("gBetaQuestWorld", 0xFFEF); - static int32_t lastBetaQuestWorld = betaQuestWorld; - - if (!isBetaQuestEnabled) { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); - } - - PaddedEnhancementCheckbox("Enable Beta Quest", "gEnableBetaQuest", true, false); - Tooltip("Turns on OoT Beta Quest. *WARNING* This will reset your game."); - betaQuestEnabled = CVar_GetS32("gEnableBetaQuest", 0); - if (betaQuestEnabled) { - if (betaQuestEnabled != lastBetaQuestEnabled) { - betaQuestWorld = 0; - } - - ImGui::Text("Beta Quest World: %d", betaQuestWorld); - - if (ImGui::Button(" - ##BetaQuest")) { - betaQuestWorld--; - } - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - - ImGui::SliderInt("##BetaQuest", &betaQuestWorld, 0, 8, "", ImGuiSliderFlags_AlwaysClamp); - Tooltip("Set the Beta Quest world to explore. *WARNING* Changing this will reset your game.\nCtrl+Click to type in a value."); - - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - if (ImGui::Button(" + ##BetaQuest")) { - betaQuestWorld++; - } - - if (betaQuestWorld > 8) { - betaQuestWorld = 8; - } - else if (betaQuestWorld < 0) { - betaQuestWorld = 0; - } - } - else { - lastBetaQuestWorld = betaQuestWorld = 0xFFEF; - CVar_SetS32("gBetaQuestWorld", betaQuestWorld); - } - if (betaQuestEnabled != lastBetaQuestEnabled || betaQuestWorld != lastBetaQuestWorld) - { - // Reset the game if the beta quest state or world changed because beta quest happens on redirecting the title screen cutscene. - lastBetaQuestEnabled = betaQuestEnabled; - lastBetaQuestWorld = betaQuestWorld; - CVar_SetS32("gEnableBetaQuest", betaQuestEnabled); - CVar_SetS32("gBetaQuestWorld", betaQuestWorld); - - console->Dispatch("reset"); - - needs_save = true; - } - - if (!isBetaQuestEnabled) { - ImGui::PopItemFlag(); - ImGui::PopStyleVar(1); - } - } - - ImGui::EndMenu(); - } - - ImGui::SetCursorPosY(0.0f); - - if (ImGui::BeginMenu("Developer Tools")) - { - EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); - Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right, and open the debug menu with L on the pause screen"); - PaddedEnhancementCheckbox("OoT Skulltula Debug", "gSkulltulaDebugEnabled", true, false); - Tooltip("Enables Skulltula Debug, when moving the cursor in the menu above various map icons (boss key, compass, map screen locations, etc) will set the GS bits in that area.\nUSE WITH CAUTION AS IT DOES NOT UPDATE THE GS COUNT."); - PaddedEnhancementCheckbox("Fast File Select", "gSkipLogoTitle", true, false); - Tooltip("Load the game to the selected menu or file\n\"Zelda Map Select\" require debug mode else you will fallback to File choose menu\nUsing a file number that don't have save will create a save file only if you toggle on \"Create a new save if none ?\" else it will bring you to the File choose menu"); - if (CVar_GetS32("gSkipLogoTitle", 0)) { - const char* FastFileSelect[5] = { - "File N.1", - "File N.2", - "File N.3", - "File select", - "Zelda Map Select (require OoT Debug Mode)" - }; - ImGui::Text("Loading :"); - EnhancementCombobox("gSaveFileID", FastFileSelect, 5, 0); - PaddedEnhancementCheckbox("Create a new save if none", "gCreateNewSave", true, false); - Tooltip("Enable the creation of a new save file if none exist in the File number selected\nNo file name will be assigned please do in Save editor once you see the first text else your save file name will be named \"00000000\"\nIf disabled you will fall back in File select menu"); - }; - PaddedSeparator(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); - static ImVec2 buttonSize(160.0f, 0.0f); - if (ImGui::Button(GetWindowButtonText("Stats", CVar_GetS32("gStatsEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gStatsEnabled", 0); - CVar_SetS32("gStatsEnabled", !currentValue); - statsWindowOpen = true; - needs_save = true; - } - Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on"); - InsertPadding(); - if (ImGui::Button(GetWindowButtonText("Console", CVar_GetS32("gConsoleEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gConsoleEnabled", 0); - CVar_SetS32("gConsoleEnabled", !currentValue); - needs_save = true; - if(CVar_GetS32("gConsoleEnabled", 0)){ - console->Open(); - } else { - console->Close(); - } - } - Tooltip("Enables the console window, allowing you to input commands, type help for some examples"); - InsertPadding(); - if (ImGui::Button(GetWindowButtonText("Save Editor", CVar_GetS32("gSaveEditorEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gSaveEditorEnabled", 0); - CVar_SetS32("gSaveEditorEnabled", !currentValue); - needs_save = true; - customWindows["Save Editor"].enabled = CVar_GetS32("gSaveEditorEnabled", 0); - } - InsertPadding(); - if (ImGui::Button(GetWindowButtonText("Collision Viewer", CVar_GetS32("gCollisionViewerEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gCollisionViewerEnabled", 0); - CVar_SetS32("gCollisionViewerEnabled", !currentValue); - needs_save = true; - customWindows["Collision Viewer"].enabled = CVar_GetS32("gCollisionViewerEnabled", 0); - } - InsertPadding(); - if (ImGui::Button(GetWindowButtonText("Actor Viewer", CVar_GetS32("gActorViewerEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gActorViewerEnabled", 0); - CVar_SetS32("gActorViewerEnabled", !currentValue); - needs_save = true; - customWindows["Actor Viewer"].enabled = CVar_GetS32("gActorViewerEnabled", 0); - } - ImGui::PopStyleVar(3); - ImGui::PopStyleColor(1); - - ImGui::EndMenu(); - } - - ImGui::SetCursorPosY(0.0f); - - if (ImGui::BeginMenu("Randomizer")) - { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); - static ImVec2 buttonSize(200.0f, 0.0f); - if (ImGui::Button(GetWindowButtonText("Randomizer Settings", CVar_GetS32("gRandomizerSettingsEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gRandomizerSettingsEnabled", 0); - CVar_SetS32("gRandomizerSettingsEnabled", !currentValue); - needs_save = true; - customWindows["Randomizer Settings"].enabled = CVar_GetS32("gRandomizerSettingsEnabled", 0); - } - InsertPadding(); - if (ImGui::Button(GetWindowButtonText("Item Tracker", CVar_GetS32("gItemTrackerEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gItemTrackerEnabled", 0); - CVar_SetS32("gItemTrackerEnabled", !currentValue); - needs_save = true; - customWindows["Item Tracker"].enabled = CVar_GetS32("gItemTrackerEnabled", 0); - } - InsertPadding(); - if (ImGui::Button(GetWindowButtonText("Item Tracker Settings", CVar_GetS32("gItemTrackerSettingsEnabled", 0)).c_str(), buttonSize)) - { - bool currentValue = CVar_GetS32("gItemTrackerSettingsEnabled", 0); - CVar_SetS32("gItemTrackerSettingsEnabled", !currentValue); - needs_save = true; - customWindows["Item Tracker Settings"].enabled = CVar_GetS32("gItemTrackerSettingsEnabled", 0); - } - ImGui::PopStyleVar(3); - ImGui::PopStyleColor(1); - - PaddedSeparator(); - - if (ImGui::BeginMenu("Rando Enhancements")) - { - EnhancementCheckbox("Rando-Relevant Navi Hints", "gRandoRelevantNavi"); - Tooltip( - "Replace Navi's overworld quest hints with rando-related gameplay hints." - ); - PaddedEnhancementCheckbox("Random Rupee Names", "gRandomizeRupeeNames", true, false); - Tooltip( - "When obtaining rupees, randomize what the rupee is called in the textbox." - ); - PaddedEnhancementCheckbox("Key Colors Match Dungeon", "gRandoMatchKeyColors", true, false); - Tooltip( - "Matches the color of small keys and boss keys to the dungeon they belong to. " - "This helps identify keys from afar and adds a little bit of flair.\n\nThis only " - "applies to seeds with keys and boss keys shuffled to Any Dungeon, Overworld, or Anywhere."); - PaddedEnhancementCheckbox("Quest Item Fanfares", "gRandoQuestItemFanfares", true, false); - Tooltip( - "Play unique fanfares when obtaining quest items " - "(medallions/stones/songs). Note that these fanfares are longer than usual." - ); - ImGui::EndMenu(); - } - - ImGui::EndMenu(); - } + clientDrawMenu(); ImGui::PopStyleVar(1); ImGui::EndMenuBar(); @@ -2054,19 +548,19 @@ namespace SohImGui { ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::Begin("Debug Stats", &statsWindowOpen, ImGuiWindowFlags_NoFocusOnAppearing); -#if defined(_WIN32) + #if defined(_WIN32) ImGui::Text("Platform: Windows"); -#elif defined(__APPLE__) + #elif defined(__APPLE__) ImGui::Text("Platform: macOS"); -#elif defined(__SWITCH__) + #elif defined(__SWITCH__) ImGui::Text("Platform: Nintendo Switch"); -#elif defined(__WIIU__) + #elif defined(__WIIU__) ImGui::Text("Platform: Nintendo Wii U"); -#elif defined(__linux__) + #elif defined(__linux__) ImGui::Text("Platform: Linux"); -#else + #else ImGui::Text("Platform: Unknown"); -#endif + #endif ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / framerate, framerate); ImGui::End(); ImGui::PopStyleColor(); @@ -2117,6 +611,14 @@ namespace SohImGui { overlay->Draw(); } + void RegisterMenuDrawMethod(std::function drawMethod) { + clientDrawMenu = drawMethod; + } + + void AddSetupHooksDelegate(std::function setupHooksMethod) { + clientSetupHooks = setupHooksMethod; + } + void DrawFramebufferAndGameInput(void) { const ImVec2 main_pos = ImGui::GetWindowPos(); ImVec2 size = ImGui::GetContentRegionAvail(); @@ -2185,364 +687,6 @@ namespace SohImGui { } } - void applyEnhancementPresets(void) { - - switch (CVar_GetS32("gSelectEnhancementPresets", 0)) { - // Default - case 0: - applyEnhancementPresetDefault(); - break; - - // Vanilla Plus - case 1: - applyEnhancementPresetDefault(); - applyEnhancementPresetVanillaPlus(); - break; - - // Enhanced - case 2: - applyEnhancementPresetDefault(); - applyEnhancementPresetVanillaPlus(); - applyEnhancementPresetEnhanced(); - break; - - // Randomizer - case 3: - applyEnhancementPresetDefault(); - applyEnhancementPresetVanillaPlus(); - applyEnhancementPresetEnhanced(); - applyEnhancementPresetRandomizer(); - break; - } - } - - void applyEnhancementPresetDefault(void) { - // D-pad Support on Pause and File Select - CVar_SetS32("gDpadPauseName", 0); - // D-pad Support in Ocarina and Text Choice - CVar_SetS32("gDpadOcarinaText", 0); - // D-pad Support for Browsing Shop Items - CVar_SetS32("gDpadShop", 0); - // D-pad as Equip Items - CVar_SetS32("gDpadEquips", 0); - // Allow the cursor to be on any slot - CVar_SetS32("gPauseAnyCursor", 0); - // Prevent Dropped Ocarina Inputs - CVar_SetS32("gDpadNoDropOcarinaInput", 0); - // Answer Navi Prompt with L Button - CVar_SetS32("gNaviOnL", 0); - - // Text Speed (1 to 5) - CVar_SetS32("gTextSpeed", 1); - // King Zora Speed (1 to 5) - CVar_SetS32("gMweepSpeed", 1); - // Biggoron Forge Time (0 to 3) - CVar_SetS32("gForgeTime", 3); - // Vine/Ladder Climb speed (+0 to +12) - CVar_SetS32("gClimbSpeed", 0); - // Faster Block Push (+0 to +5) - CVar_SetS32("gFasterBlockPush", 0); - // Faster Heavy Block Lift - CVar_SetS32("gFasterHeavyBlockLift", 0); - // No Forced Navi - CVar_SetS32("gNoForcedNavi", 0); - // No Skulltula Freeze - CVar_SetS32("gSkulltulaFreeze", 0); - // MM Bunny Hood - CVar_SetS32("gMMBunnyHood", 0); - // Fast Chests - CVar_SetS32("gFastChests", 0); - // Fast Drops - CVar_SetS32("gFastDrops", 0); - // Better Owl - CVar_SetS32("gBetterOwl", 0); - // Fast Ocarina Playback - CVar_SetS32("gFastOcarinaPlayback", 0); - // Instant Putaway - CVar_SetS32("gInstantPutaway", 0); - // Instant Boomerang Recall - CVar_SetS32("gFastBoomerang", 0); - // Mask Select in Inventory - CVar_SetS32("gMaskSelect", 0); - // Remember Save Location - CVar_SetS32("gRememberSaveLocation", 0); - - // Damage Multiplier (0 to 8) - CVar_SetS32("gDamageMul", 0); - // Fall Damage Multiplier (0 to 7) - CVar_SetS32("gFallDamageMul", 0); - // Void Damage Multiplier (0 to 6) - CVar_SetS32("gVoidDamageMul", 0); - // No Random Drops - CVar_SetS32("gNoRandomDrops", 0); - // No Heart Drops - CVar_SetS32("gNoHeartDrops", 0); - // Enable Bombchu Drops - CVar_SetS32("gBombchuDrops", 0); - // Always Win Goron Pot - CVar_SetS32("gGoronPot", 0); - - // Change Red Potion Effect - CVar_SetS32("gRedPotionEffect", 0); - // Red Potion Health (1 to 100) - CVar_SetS32("gRedPotionHealth", 1); - // Red Potion Percent Restore - CVar_SetS32("gRedPercentRestore", 0); - // Change Green Potion Effect - CVar_SetS32("gGreenPotionEffect", 0); - // Green Potion Mana (1 to 100) - CVar_SetS32("gGreenPotionMana", 1); - // Green Potion Percent Restore - CVar_SetS32("gGreenPercentRestore", 0); - // Change Blue Potion Effects - CVar_SetS32("gBluePotionEffects", 0); - // Blue Potion Health (1 to 100) - CVar_SetS32("gBluePotionHealth", 1); - // Blue Potion Health Percent Restore - CVar_SetS32("gBlueHealthPercentRestore", 0); - // Blue Potion Mana (1 to 100) - CVar_SetS32("gBluePotionMana", 1); - // Blue Potion Mana Percent Restore - CVar_SetS32("gBlueManaPercentRestore", 0); - // Change Milk Effect - CVar_SetS32("gMilkEffect", 0); - // Milk Health (1 to 100) - CVar_SetS32("gMilkHealth", 1); - // Milk Percent Restore - CVar_SetS32("gMilkPercentRestore", 0); - // Separate Half Milk Effect - CVar_SetS32("gSeparateHalfMilkEffect", 0); - // Half Milk Health (1 to 100) - CVar_SetS32("gHalfMilkHealth", 0); - // Half Milk Percent Restore - CVar_SetS32("gHalfMilkPercentRestore", 0); - // Change Fairy Effect - CVar_SetS32("gFairyEffect", 0); - // Fairy (1 to 100) - CVar_SetS32("gFairyHealth", 1); - // Fairy Percent Restore - CVar_SetS32("gFairyPercentRestore", 0); - // Change Fairy Revive Effect - CVar_SetS32("gFairyReviveEffect", 0); - // Fairy Revival (1 to 100) - CVar_SetS32("gFairyReviveHealth", 1); - // Fairy Revive Percent Restore - CVar_SetS32("gFairyRevivePercentRestore", 0); - - // Instant Fishing - CVar_SetS32("gInstantFishing", 0); - // Guarantee Bite - CVar_SetS32("gGuaranteeFishingBite", 0); - // Child Minimum Weight (6 to 10) - CVar_SetS32("gChildMinimumWeightFish", 10); - // Adult Minimum Weight (8 to 13) - CVar_SetS32("gAdultMinimumWeightFish", 13); - - // Mute Low HP Alarm - CVar_SetS32("gLowHpAlarm", 0); - // Minimal UI - CVar_SetS32("gMinimalUI", 0); - // Disable Navi Call Audio - CVar_SetS32("gDisableNaviCallAudio", 0); - - // Visual Stone of Agony - CVar_SetS32("gVisualAgony", 0); - // Assignable Tunics and Boots - CVar_SetS32("gAssignableTunicsAndBoots", 0); - // Equipment Toggle - CVar_SetS32("gEquipmentCanBeRemoved", 0); - // Link's Cow in Both Time Periods - CVar_SetS32("gCowOfTime", 0); - // Enable visible guard vision - CVar_SetS32("gGuardVision", 0); - // Enable passage of time on file select - CVar_SetS32("gTimeFlowFileSelect", 0); - // Count Golden Skulltulas - CVar_SetS32("gInjectSkulltulaCount", 0); - // Pull grave during the day - CVar_SetS32("gDayGravePull", 0); - // Blue Fire Arrows - CVar_SetS32("gBlueFireArrows", 0); - // Sunlight Arrows - CVar_SetS32("gSunlightArrows", 0); - - // Rotate link (0 to 2) - CVar_SetS32("gPauseLiveLinkRotation", 0); - // Pause link animation (0 to 16) - CVar_SetS32("gPauseLiveLink", 0); - // Frames to wait - CVar_SetS32("gMinFrameCount", 1); - - // N64 Mode - CVar_SetS32("gN64Mode", 0); - // Enable 3D Dropped items/projectiles - CVar_SetS32("gNewDrops", 0); - // Disable Black Bar Letterboxes - CVar_SetS32("gDisableBlackBars", 0); - // Dynamic Wallet Icon - CVar_SetS32("gDynamicWalletIcon", 0); - // Always show dungeon entrances - CVar_SetS32("gAlwaysShowDungeonMinimapIcon", 0); - - // Fix L&R Pause menu - CVar_SetS32("gUniformLR", 0); - // Fix L&Z Page switch in Pause menu - CVar_SetS32("gNGCKaleidoSwitcher", 0); - // Fix Dungeon entrances - CVar_SetS32("gFixDungeonMinimapIcon", 0); - // Fix Two Handed idle animations - CVar_SetS32("gTwoHandedIdle", 0); - // Fix the Gravedigging Tour Glitch - CVar_SetS32("gGravediggingTourFix", 0); - // Fix Deku Nut upgrade - CVar_SetS32("gDekuNutUpgradeFix", 0); - // Fix Navi text HUD position - CVar_SetS32("gNaviTextFix", 0); - // Fix Anubis fireballs - CVar_SetS32("gAnubisFix", 0); - // Fix Megaton Hammer crouch stab - CVar_SetS32("gCrouchStabHammerFix", 0); - // Fix all crouch stab - CVar_SetS32("gCrouchStabFix", 0); - - // Red Ganon blood - CVar_SetS32("gRedGanonBlood", 0); - // Fish while hovering - CVar_SetS32("gHoverFishing", 0); - // N64 Weird Frames - CVar_SetS32("gN64WeirdFrames", 0); - // Bombchus out of bounds - CVar_SetS32("gBombchusOOB", 0); - - CVar_SetS32("gGsCutscene", 0); - // Autosave - CVar_SetS32("gAutosave", 0); - } - - void applyEnhancementPresetVanillaPlus(void) { - // D-pad Support in Ocarina and Text Choice - CVar_SetS32("gDpadOcarinaText", 1); - // D-pad Support for Browsing Shop Items - CVar_SetS32("gDpadShop", 1); - // D-pad as Equip Items - CVar_SetS32("gDpadEquips", 1); - // Prevent Dropped Ocarina Inputs - CVar_SetS32("gDpadNoDropOcarinaInput", 1); - - // Text Speed (1 to 5) - CVar_SetS32("gTextSpeed", 5); - // King Zora Speed (1 to 5) - CVar_SetS32("gMweepSpeed", 2); - // Faster Block Push (+0 to +5) - CVar_SetS32("gFasterBlockPush", 5); - // Better Owl - CVar_SetS32("gBetterOwl", 1); - - // Assignable Tunics and Boots - CVar_SetS32("gAssignableTunicsAndBoots", 1); - // Enable passage of time on file select - CVar_SetS32("gTimeFlowFileSelect", 1); - // Count Golden Skulltulas - CVar_SetS32("gInjectSkulltulaCount", 1); - - // Pause link animation (0 to 16) - CVar_SetS32("gPauseLiveLink", 1); - - // Dynamic Wallet Icon - CVar_SetS32("gDynamicWalletIcon", 1); - // Always show dungeon entrances - CVar_SetS32("gAlwaysShowDungeonMinimapIcon", 1); - - // Fix L&R Pause menu - CVar_SetS32("gUniformLR", 1); - // Fix Dungeon entrances - CVar_SetS32("gFixDungeonMinimapIcon", 1); - // Fix Two Handed idle animations - CVar_SetS32("gTwoHandedIdle", 1); - // Fix the Gravedigging Tour Glitch - CVar_SetS32("gGravediggingTourFix", 1); - // Fix Deku Nut upgrade - CVar_SetS32("gDekuNutUpgradeFix", 1); - - // Red Ganon blood - CVar_SetS32("gRedGanonBlood", 1); - // Fish while hovering - CVar_SetS32("gHoverFishing", 1); - // N64 Weird Frames - CVar_SetS32("gN64WeirdFrames", 1); - // Bombchus out of bounds - CVar_SetS32("gBombchusOOB", 1); - } - - void applyEnhancementPresetEnhanced(void) { - // King Zora Speed (1 to 5) - CVar_SetS32("gMweepSpeed", 5); - // Biggoron Forge Time (0 to 3) - CVar_SetS32("gForgeTime", 0); - // Vine/Ladder Climb speed (+0 to +12) - CVar_SetS32("gClimbSpeed", 1); - // Faster Heavy Block Lift - CVar_SetS32("gFasterHeavyBlockLift", 1); - // No Forced Navi - CVar_SetS32("gNoForcedNavi", 1); - // No Skulltula Freeze - CVar_SetS32("gSkulltulaFreeze", 1); - // MM Bunny Hood - CVar_SetS32("gMMBunnyHood", 1); - // Fast Chests - CVar_SetS32("gFastChests", 1); - // Fast Drops - CVar_SetS32("gFastDrops", 1); - // Fast Ocarina Playback - CVar_SetS32("gFastOcarinaPlayback", 1); - // Instant Putaway - CVar_SetS32("gInstantPutaway", 1); - // Instant Boomerang Recall - CVar_SetS32("gFastBoomerang", 1); - // Mask Select in Inventory - CVar_SetS32("gMaskSelect", 1); - - // Disable Navi Call Audio - CVar_SetS32("gDisableNaviCallAudio", 1); - - // Equipment Toggle - CVar_SetS32("gEquipmentCanBeRemoved", 1); - // Count Golden Skulltulas - CVar_SetS32("gInjectSkulltulaCount", 1); - - // Enable 3D Dropped items/projectiles - CVar_SetS32("gNewDrops", 1); - - // Fix Anubis fireballs - CVar_SetS32("gAnubisFix", 1); - } - - void applyEnhancementPresetRandomizer(void) { - // Allow the cursor to be on any slot - CVar_SetS32("gPauseAnyCursor", 1); - - // Instant Fishing - CVar_SetS32("gInstantFishing", 1); - // Guarantee Bite - CVar_SetS32("gGuaranteeFishingBite", 1); - // Child Minimum Weight (6 to 10) - CVar_SetS32("gChildMinimumWeightFish", 6); - // Adult Minimum Weight (8 to 13) - CVar_SetS32("gAdultMinimumWeightFish", 8); - - // Visual Stone of Agony - CVar_SetS32("gVisualAgony", 1); - // Pull grave during the day - CVar_SetS32("gDayGravePull", 1); - // Pull out Ocarina to Summon Scarecrow - CVar_SetS32("gSkipScarecrow", 0); - - // Pause link animation (0 to 16) - CVar_SetS32("gPauseLiveLink", 16); - // Frames to wait - CVar_SetS32("gMinFrameCount", 200); - } - void Render() { ImGui::Render(); ImGuiRenderDrawData(ImGui::GetDrawData()); @@ -2569,8 +713,41 @@ namespace SohImGui { } } - void BindCmd(const std::string& cmd, CommandEntry entry) { - console->AddCommand(cmd, entry); + void DrawSettings() { + overlay->DrawSettings(); + } + + Backend WindowBackend() { + return impl.backend; + } + + float WindowRefreshRate() { + return gfx_get_detected_hz(); + } + + std::pair* GetAvailableRenderingBackends() { + return backends; + } + + std::pair GetCurrentRenderingBackend() { + return backends[lastBackendID]; + } + + void SetCurrentRenderingBackend(uint8_t index, std::pair backend) { + Window::GetInstance()->GetConfig()->setString("Window.GfxBackend", backend.first); + lastBackendID = index; + } + + const char** GetSupportedTextureFilters() { + return filters; + } + + void SetResolutionMultiplier(float multiplier) { + gfx_current_dimensions.internal_mul = multiplier; + } + + void SetMSAALevel(uint32_t value) { + gfx_msaa_level = value; } void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc, bool isEnabled, bool isHidden) { @@ -2591,30 +768,135 @@ namespace SohImGui { } } + void EnableWindow(const std::string& name, bool isEnabled) { + customWindows[name].enabled = isEnabled; + } + + Ship::GameOverlay* GetGameOverlay() { + return overlay; + } + + Ship::InputEditor* GetInputEditor() { + return controller; + } + + void ToggleInputEditorWindow(bool isOpen) { + if (isOpen) + controller->Open(); + else + controller->Close(); + } + + void ToggleStatisticsWindow(bool isOpen) { + statsWindowOpen = isOpen; + } + + std::shared_ptr GetConsole() { + return console; + } + + void ToggleConsoleWindow(bool isOpen) { + if (isOpen) + console->Open(); + else + console->Close(); + } + + void DispatchConsoleCommand(const std::string& line) { + console->Dispatch(line); + } + + void RequestCvarSaveOnNextTick() { + needs_save = true; + } + ImTextureID GetTextureByName(const std::string& name) { return GetTextureByID(DefaultAssets[name]->textureId); } ImTextureID GetTextureByID(int id) { -#ifdef ENABLE_DX11 + #ifdef ENABLE_DX11 if (impl.backend == Backend::DX11) { ImTextureID gfx_d3d11_get_texture_by_id(int id); return gfx_d3d11_get_texture_by_id(id); } -#endif -#ifdef __WIIU__ + #endif + #ifdef __WIIU__ if (impl.backend == Backend::GX2) { return gfx_gx2_texture_for_imgui(id); } -#endif + #endif return reinterpret_cast(id); } - void BeginGroupPanel(const char* name, const ImVec2& size) - { + void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint) { + GfxRenderingAPI* api = gfx_get_current_rendering_api(); + const auto res = static_cast(Window::GetInstance()->GetResourceManager()->LoadResource(path).get()); + + std::vector texBuffer; + texBuffer.reserve(res->width * res->height * 4); + + switch (res->texType) { + case Ship::TextureType::RGBA32bpp: + texBuffer.assign(res->imageData, res->imageData + (res->width * res->height * 4)); + break; + case Ship::TextureType::GrayscaleAlpha8bpp: + for (int32_t i = 0; i < res->width * res->height; i++) { + uint8_t ia = res->imageData[i]; + uint8_t color = ((ia >> 4) & 0xF) * 255 / 15; + uint8_t alpha = (ia & 0xF) * 255 / 15; + texBuffer.push_back(color); + texBuffer.push_back(color); + texBuffer.push_back(color); + texBuffer.push_back(alpha); + } + break; + default: + // TODO convert other image types + SPDLOG_WARN("SohImGui::LoadResource: Attempting to load unsupporting image type %s", path.c_str()); + return; + } + + for (size_t pixel = 0; pixel < texBuffer.size() / 4; pixel++) { + texBuffer[pixel * 4 + 0] *= tint.x; + texBuffer[pixel * 4 + 1] *= tint.y; + texBuffer[pixel * 4 + 2] *= tint.z; + texBuffer[pixel * 4 + 3] *= tint.w; + } + + const auto asset = new GameAsset{ api->new_texture() }; + + api->select_texture(0, asset->textureId); + api->set_sampler_parameters(0, false, 0, 0); + api->upload_texture(texBuffer.data(), res->width, res->height); + + DefaultAssets[name] = asset; + } + + void ShowCursor(bool hide, Dialogues d) { + if (d == Dialogues::dLoadSettings) { + Window::GetInstance()->ShowCursor(hide); + return; + } + + if (d == Dialogues::dConsole && CVar_GetS32("gOpenMenuBar", 0)) { + return; + } + if (!Window::GetInstance()->IsFullscreen()) { + oldCursorState = false; + return; + } + + if (oldCursorState != hide) { + oldCursorState = hide; + Window::GetInstance()->ShowCursor(hide); + } + } + + void BeginGroupPanel(const char* name, const ImVec2& size) { ImGui::BeginGroup(); // auto cursorPos = ImGui::GetCursorScreenPos(); @@ -2648,13 +930,13 @@ namespace SohImGui { ImGui::PopStyleVar(2); -#if IMGUI_VERSION_NUM >= 17301 + #if IMGUI_VERSION_NUM >= 17301 ImGui::GetCurrentWindow()->ContentRegionRect.Max.x -= frameHeight * 0.5f; ImGui::GetCurrentWindow()->WorkRect.Max.x -= frameHeight * 0.5f; ImGui::GetCurrentWindow()->InnerRect.Max.x -= frameHeight * 0.5f; -#else + #else ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x -= frameHeight * 0.5f; -#endif + #endif ImGui::GetCurrentWindow()->Size.x -= frameHeight; auto itemWidth = ImGui::CalcItemWidth(); @@ -2719,101 +1001,17 @@ namespace SohImGui { ImGui::PopStyleVar(2); -#if IMGUI_VERSION_NUM >= 17301 + #if IMGUI_VERSION_NUM >= 17301 ImGui::GetCurrentWindow()->ContentRegionRect.Max.x += frameHeight * 0.5f; ImGui::GetCurrentWindow()->WorkRect.Max.x += frameHeight * 0.5f; ImGui::GetCurrentWindow()->InnerRect.Max.x += frameHeight * 0.5f; -#else + #else ImGui::GetCurrentWindow()->ContentsRegionRect.Max.x += frameHeight * 0.5f; -#endif + #endif ImGui::GetCurrentWindow()->Size.x += frameHeight; - InsertPadding(); + ImGui::Dummy(ImVec2(0.0f, 0.0f)); ImGui::EndGroup(); } - - // Automatically add newlines to break up tooltips longer than a specified number of characters - // Manually included newlines will still be respected and reset the line length - // Default line length is 60 characters - std::string BreakTooltip(const char* text, int lineLength) { - std::string newText(text); - const int tipLength = newText.length(); - int lastSpace = -1; - int currentLineLength = 0; - for (int currentCharacter = 0; currentCharacter < tipLength; currentCharacter++) { - if (newText[currentCharacter] == '\n') { - currentLineLength = 0; - lastSpace = -1; - continue; - } - else if (newText[currentCharacter] == ' ') { - lastSpace = currentCharacter; - } - - if ((currentLineLength >= lineLength) && (lastSpace >= 0)) { - newText[lastSpace] = '\n'; - currentLineLength = currentCharacter - lastSpace - 1; - lastSpace = -1; - } - currentLineLength++; - } - return newText; - } - - std::string BreakTooltip(const std::string& text, int lineLength) { - return BreakTooltip(text.c_str(), lineLength); - } - - void InsertPadding(float extraVerticalPadding) { - ImGui::Dummy(ImVec2(0.0f, extraVerticalPadding)); - } - - void PaddedSeparator(bool padTop, bool padBottom, float extraVerticalTopPadding, float extraVerticalBottomPadding) { - if (padTop) { - ImGui::Dummy(ImVec2(0.0f, extraVerticalTopPadding)); - } - ImGui::Separator(); - if (padBottom) { - ImGui::Dummy(ImVec2(0.0f, extraVerticalBottomPadding)); - } - } - - void PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton, bool padTop, bool padBottom) { - if (padTop) { - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - } - EnhancementSliderInt(text, id, cvarName, min, max, format, defaultValue, PlusMinusButton); - if (padBottom) { - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - } - } - - void PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText, ImGuiCheckboxGraphics disabledGraphic) { - if (padTop) { - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - } - EnhancementCheckbox(text, cvarName, disabled, disabledTooltipText, disabledGraphic); - if (padBottom) { - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - } - } - - void PaddedText(const char* text, bool padTop, bool padBottom) { - if (padTop) { - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - } - ImGui::Text("%s", text); - if (padBottom) { - ImGui::Dummy(ImVec2(0.0f, 0.0f)); - } - } - - std::string GetWindowButtonText(const char* text, bool menuOpen) { - char buttonText[100] = ""; - if(menuOpen) { strcat(buttonText,"> "); } - strcat(buttonText, text); - if (!menuOpen) { strcat(buttonText, " "); } - return buttonText; - } } diff --git a/libultraship/libultraship/ImGuiImpl.h b/libultraship/libultraship/ImGuiImpl.h index 733e9d1cf..cd035ae8a 100644 --- a/libultraship/libultraship/ImGuiImpl.h +++ b/libultraship/libultraship/ImGuiImpl.h @@ -1,14 +1,5 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - void enableBetaQuest(); - void disableBetaQuest(); -#ifdef __cplusplus -} -#endif - #ifdef __cplusplus #include "GameOverlay.h" #include "Lib/ImGui/imgui.h" @@ -34,14 +25,6 @@ namespace SohImGui { dLoadSettings, }; - // Enumeration for disabled checkbox graphics - enum class ImGuiCheckboxGraphics - { - Cross, - Checkmark, - None - }; - typedef struct { Backend backend; union { @@ -76,8 +59,6 @@ namespace SohImGui { } gx2; } EventImpl; - extern WindowImpl impl; - using WindowDrawFunc = void(*)(bool& enabled); typedef struct { @@ -85,55 +66,49 @@ namespace SohImGui { WindowDrawFunc drawFunc; } CustomWindow; - extern std::shared_ptr console; - extern Ship::InputEditor* controller; - extern Ship::GameOverlay* overlay; - extern bool needs_save; void Init(WindowImpl window_impl); void Update(EventImpl event); - void Tooltip(const char* text); - - void EnhancementRadioButton(const char* text, const char* cvarName, int id); - void EnhancementCheckbox(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", ImGuiCheckboxGraphics disabledGraphic = ImGuiCheckboxGraphics::Cross); - void EnhancementButton(const char* text, const char* cvarName); - void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = false); - void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton = false); - void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue); - void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false); - void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector& items, int defaultValue = 0); - - void applyEnhancementPresets(void); - void applyEnhancementPresetDefault(void); - void applyEnhancementPresetVanillaPlus(void); - void applyEnhancementPresetEnhanced(void); - void applyEnhancementPresetRandomizer(void); void DrawMainMenuAndCalculateGameSize(void); + void RegisterMenuDrawMethod(std::function drawMethod); + void AddSetupHooksDelegate(std::function setupHooksMethod); void DrawFramebufferAndGameInput(void); void Render(void); void CancelFrame(void); - void ShowCursor(bool hide, Dialogues w); - void BindCmd(const std::string& cmd, Ship::CommandEntry entry); - void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc, bool isEnabled=false, bool isHidden=false); - void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint = ImVec4(1, 1, 1, 1)); - void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha=false); - int ClampFloatToInt(float value, int min, int max); - void RandomizeColor(const char* cvarName, ImVec4* colors); - void RainbowColor(const char* cvarName, ImVec4* colors); - void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha); + void DrawSettings(); + + Backend WindowBackend(); + float WindowRefreshRate(); + std::pair* GetAvailableRenderingBackends(); + std::pair GetCurrentRenderingBackend(); + void SetCurrentRenderingBackend(uint8_t index, std::pair); + const char** GetSupportedTextureFilters(); + void SetResolutionMultiplier(float multiplier); + void SetMSAALevel(uint32_t value); + + void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc, bool isEnabled = false, bool isHidden = false); + void EnableWindow(const std::string& name, bool isEnabled = true); + + Ship::GameOverlay* GetGameOverlay(); + + Ship::InputEditor* GetInputEditor(); + void ToggleInputEditorWindow(bool isOpen = true); + void ToggleStatisticsWindow(bool isOpen = true); + + std::shared_ptr GetConsole(); + void ToggleConsoleWindow(bool isOpen = true); + void DispatchConsoleCommand(const std::string& line); + + void RequestCvarSaveOnNextTick(); + ImTextureID GetTextureByID(int id); ImTextureID GetTextureByName(const std::string& name); + void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint = ImVec4(1, 1, 1, 1)); + + void ShowCursor(bool hide, Dialogues w); void BeginGroupPanel(const char* name, const ImVec2 & size = ImVec2(0.0f, 0.0f)); void EndGroupPanel(float minHeight = 0.0f); - std::string BreakTooltip(const char* text, int lineLength = 60); - std::string BreakTooltip(const std::string& text, int lineLength = 60); - void InsertPadding(float extraVerticalPadding = 0.0f); - void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f); - void PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = false, bool padTop = true, bool padBottom = true); - void PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "", ImGuiCheckboxGraphics disabledGraphic = ImGuiCheckboxGraphics::Cross); - void PaddedText(const char* text, bool padTop = true, bool padBottom = true); - std::string GetWindowButtonText(const char* text, bool menuOpen); } #endif diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp index cca872f99..9fde7e276 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp @@ -2134,6 +2134,10 @@ static void gfx_run_dl(Gfx* cmd) { switch (opcode) { // RSP commands: + case G_LOAD_UCODE: + rsp.fog_mul = 0; + rsp.fog_offset = 0; + break; case G_MARKER: { cmd++; diff --git a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h index 8a629aa1a..4bb8cf2c6 100644 --- a/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h +++ b/libultraship/libultraship/Lib/spdlog/include/spdlog/sinks/sohconsole_sink.h @@ -41,8 +41,8 @@ protected: } formatted.push_back('\0'); const char* msg_output = formatted.data(); - if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->IsOpened()) { - SohImGui::console->Append("Logs", msg.level, "%s", msg_output); + if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::GetConsole()->IsOpened()) { + SohImGui::GetConsole()->Append("Logs", msg.level, "%s", msg_output); } } @@ -57,4 +57,4 @@ private: using soh_sink_mt = sohconsole_sink; using soh_sink_st = sohconsole_sink; } // namespace sinks -} // namespace spdlog \ No newline at end of file +} // namespace spdlog diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index b9e84fd60..36a10b505 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -86,7 +86,7 @@ extern "C" { pad->gyro_x = 0; pad->gyro_y = 0; - if (SohImGui::controller->IsOpened()) return; + if (SohImGui::GetInputEditor()->IsOpened()) return; Ship::Window::GetInstance()->GetControlDeck()->WriteToPad(pad); Ship::ExecuteHooks(pad); diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 96aef33df..fcd66c93f 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -165,6 +165,7 @@ set(Header_Files__soh__Enhancements__controls ) source_group("Header Files\\soh\\Enhancements\\controls" FILES ${Header_Files__soh__Enhancements__controls}) + set(Header_Files__soh__Enhancements__cosmetics "soh/Enhancements/cosmetics/CosmeticsEditor.h" ) @@ -175,7 +176,6 @@ set(Header_Files__soh__Enhancements__debugger "soh/Enhancements/debugger/colViewer.h" "soh/Enhancements/debugger/debugger.h" "soh/Enhancements/debugger/debugSaveEditor.h" - "soh/Enhancements/debugger/ImGuiHelpers.h" ) source_group("Header Files\\soh\\Enhancements\\debugger" FILES ${Header_Files__soh__Enhancements__debugger}) @@ -258,6 +258,10 @@ set(Source_Files__soh "soh/z_message_OTR.cpp" "soh/z_play_otr.cpp" "soh/z_scene_otr.cpp" + "soh/GameMenuBar.hpp" + "soh/GameMenuBar.cpp" + "soh/UIWidgets.hpp" + "soh/UIWidgets.cpp" ) source_group("Source Files\\soh" FILES ${Source_Files__soh}) @@ -284,7 +288,6 @@ set(Source_Files__soh__Enhancements__debugger "soh/Enhancements/debugger/colViewer.cpp" "soh/Enhancements/debugger/debugger.cpp" "soh/Enhancements/debugger/debugSaveEditor.cpp" - "soh/Enhancements/debugger/ImGuiHelpers.cpp" ) source_group("Source Files\\soh\\Enhancements\\debugger" FILES ${Source_Files__soh__Enhancements__debugger}) @@ -1679,14 +1682,13 @@ set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS}) target_include_directories(${PROJECT_NAME} PRIVATE assets ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${CMAKE_CURRENT_SOURCE_DIR}/src/ + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/ ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/libjpeg/include/ - ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/ ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/spdlog/include/ + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/Fast3D/U64/PR ${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils - ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/Fast3D/U64 - ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/Fast3D/U64/PR ${SDL2-INCLUDE} - ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/ ${CMAKE_CURRENT_SOURCE_DIR}/assets/ . ) diff --git a/soh/include/functions.h b/soh/include/functions.h index 203d4eea7..99681eb10 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1063,6 +1063,7 @@ u8 Item_CheckObtainability(u8 item); void Inventory_DeleteItem(u16 item, u16 invSlot); s32 Inventory_ReplaceItem(GlobalContext* globalCtx, u16 oldItem, u16 newItem); s32 Inventory_HasEmptyBottle(void); +bool Inventory_HasEmptyBottleSlot(void); s32 Inventory_HasSpecificBottle(u8 bottleItem); void Inventory_UpdateBottleItem(GlobalContext* globalCtx, u8 item, u8 cButton); s32 Inventory_ConsumeFairy(GlobalContext* globalCtx); diff --git a/soh/include/global.h b/soh/include/global.h index 65203c1aa..aa904984f 100644 --- a/soh/include/global.h +++ b/soh/include/global.h @@ -6,7 +6,7 @@ #include "macros.h" #include "soh/OTRGlobals.h" #include "soh/Enhancements/gameconsole.h" -#include "Cvar.h" +#include diff --git a/soh/include/macros.h b/soh/include/macros.h index bcfb3fce5..5c441dad9 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -1,7 +1,7 @@ #ifndef MACROS_H #define MACROS_H -#include "endianness.h" +#include #define ARRAY_COUNT(arr) (s32)(sizeof(arr) / sizeof(arr[0])) #define ARRAY_COUNTU(arr) (u32)(sizeof(arr) / sizeof(arr[0])) diff --git a/soh/include/z64.h b/soh/include/z64.h index 1f0bbc25c..7264b663b 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -26,7 +26,7 @@ #include "z64interface.h" #include "sequence.h" #include "sfx.h" -#include "color.h" +#include #include "ichain.h" #include "regs.h" diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index e821d7f17..8f7b8f2b4 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -1,7 +1,7 @@ #ifndef Z64_AUDIO_H #define Z64_AUDIO_H -#include "endianness.h" +#include #define MK_CMD(b0,b1,b2,b3) ((((b0) & 0xFF) << 0x18) | (((b1) & 0xFF) << 0x10) | (((b2) & 0xFF) << 0x8) | (((b3) & 0xFF) << 0)) @@ -815,7 +815,7 @@ typedef struct { /* 0x0E */ u8 ttl; // duration after which the DMA can be discarded } SampleDma; // size = 0x10 -#include +#include typedef struct { /* 0x0000 */ char unk_0000; @@ -1122,4 +1122,4 @@ float Audio_GetGameVolume(int player_id); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/soh/include/z64effect.h b/soh/include/z64effect.h index 861eb9070..7b364f0ea 100644 --- a/soh/include/z64effect.h +++ b/soh/include/z64effect.h @@ -1,7 +1,7 @@ #ifndef Z64EFFECT_H #define Z64EFFECT_H -#include "color.h" +#include struct GraphicsContext; struct GlobalContext; diff --git a/soh/include/z64light.h b/soh/include/z64light.h index 639490022..d642a7364 100644 --- a/soh/include/z64light.h +++ b/soh/include/z64light.h @@ -4,7 +4,7 @@ #include "ultra64.h" #include "ultra64/gbi.h" #include "z64math.h" -#include "color.h" +#include typedef struct { /* 0x0 */ s16 x; diff --git a/soh/include/z64transition.h b/soh/include/z64transition.h index 2adb6f604..9c93e44b7 100644 --- a/soh/include/z64transition.h +++ b/soh/include/z64transition.h @@ -2,7 +2,7 @@ #define Z64TRANSITION_H #include "ultra64.h" -#include "color.h" +#include typedef struct { f32 unk_0; diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index ee8e33dea..f494711e6 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -6,12 +6,14 @@ #include #include -#include "Lib/ImGui/imgui.h" -#include "Lib/ImGui/imgui_internal.h" -#include "Cvar.h" -#include "UltraController.h" -#include "Utils/StringHelper.h" -#include "../libultraship/ImGuiImpl.h" +#include +#include +#include +#include +#include +#include + +#include "../../UIWidgets.hpp" namespace GameControlEditor { const ImGuiTableFlags PANEL_TABLE_FLAGS = @@ -50,7 +52,11 @@ namespace GameControlEditor { // place the ? button to the most of the right side of the cell it is using. ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 15); ImGui::SmallButton("?"); - SohImGui::Tooltip(helptext.c_str()); + + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", helptext.c_str()); + } + if (sameline) { //I do not use ImGui::SameLine(); because it make some element vanish. ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 22); @@ -119,7 +125,7 @@ namespace GameControlEditor { preview = "Unknown"; } - SohImGui::InsertPadding(); + UIWidgets::Spacer(0); ImVec2 cursorPos = ImGui::GetCursorPos(); ImVec2 textSize = ImGui::CalcTextSize(mapping.label); ImGui::SetCursorPosY(cursorPos.y + textSize.y / 4); @@ -140,7 +146,7 @@ namespace GameControlEditor { } ImGui::EndCombo(); } - SohImGui::InsertPadding(); + UIWidgets::Spacer(0); } void DrawOcarinaControlPanel() { @@ -157,7 +163,7 @@ namespace GameControlEditor { ImVec2 cursor = ImGui::GetCursorPos(); ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5)); - SohImGui::EnhancementCheckbox("Customize Ocarina Controls", "gCustomOcarinaControls"); + UIWidgets::EnhancementCheckbox("Customize Ocarina Controls", "gCustomOcarinaControls"); if (CVar_GetS32("gCustomOcarinaControls", 0) == 1) { if (ImGui::BeginTable("tableCustomMainOcarinaControls", 2, ImGuiTableFlags_SizingStretchProp)) { @@ -194,10 +200,10 @@ namespace GameControlEditor { ImGui::EndTable(); } } else { - SohImGui::InsertPadding(); + UIWidgets::Spacer(0); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); ImGui::TextWrapped("To modify the main ocarina controls, select the \"Customize Ocarina Controls\" checkbox."); - SohImGui::InsertPadding(); + UIWidgets::Spacer(0); } SohImGui::BeginGroupPanel("Alternate controls", ImGui::GetContentRegionAvail()); @@ -206,9 +212,9 @@ namespace GameControlEditor { ImGui::TableSetupColumn("Right stick", PANEL_TABLE_COLUMN_FLAGS); TableHelper::InitHeader(false); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - SohImGui::EnhancementCheckbox("Play with D-pad", "gDpadOcarina"); + UIWidgets::EnhancementCheckbox("Play with D-pad", "gDpadOcarina"); TableHelper::NextCol(); - SohImGui::EnhancementCheckbox("Play with camera stick", "gRStickOcarina"); + UIWidgets::EnhancementCheckbox("Play with camera stick", "gRStickOcarina"); ImGui::EndTable(); } SohImGui::EndGroupPanel(); @@ -223,17 +229,17 @@ namespace GameControlEditor { ImVec2 cursor = ImGui::GetCursorPos(); ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5)); - SohImGui::PaddedEnhancementCheckbox("Invert Camera X Axis", "gInvertXAxis"); - SohImGui::Tooltip("Inverts the Camera X Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); + UIWidgets::PaddedEnhancementCheckbox("Invert Camera X Axis", "gInvertXAxis"); + UIWidgets::Tooltip("Inverts the Camera X Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - SohImGui::PaddedEnhancementCheckbox("Invert Camera Y Axis", "gInvertYAxis"); - SohImGui::Tooltip("Inverts the Camera Y Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); + UIWidgets::PaddedEnhancementCheckbox("Invert Camera Y Axis", "gInvertYAxis"); + UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-Free camera\n-C-Up view\n-Weapon Aiming"); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - SohImGui::PaddedEnhancementCheckbox("Right Stick Aiming", "gRightStickAiming"); - SohImGui::Tooltip("Allows for aiming with the rights stick when:\n-Aiming in the C-Up view\n-Aiming with weapons"); + UIWidgets::PaddedEnhancementCheckbox("Right Stick Aiming", "gRightStickAiming"); + UIWidgets::Tooltip("Allows for aiming with the rights stick when:\n-Aiming in the C-Up view\n-Aiming with weapons"); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - SohImGui::PaddedEnhancementCheckbox("Auto-Center First Person View", "gAutoCenterView"); - SohImGui::Tooltip("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming"); + UIWidgets::PaddedEnhancementCheckbox("Auto-Center First Person View", "gAutoCenterView"); + UIWidgets::Tooltip("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming"); } void DrawUI(bool& open) { diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index b04f30e35..5782119f1 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -1,11 +1,13 @@ #include "CosmeticsEditor.h" -#include "../libultraship/ImGuiImpl.h" +#include #include -#include +#include #include #include -#include +#include + +#include "../../UIWidgets.hpp" const char* RainbowColorCvarList[] = { //This is the list of possible CVars that has rainbow effect. @@ -51,9 +53,9 @@ void GetRandomColorRGB(CosmeticsColorSection* ColorSection, int SectionSize){ std::string cvarName = Element->CvarName; std::string Cvar_RBM = cvarName + "RBM"; colors = RANDOMIZE_32(255); - NewColors.r = SohImGui::ClampFloatToInt(colors.x * 255, 0, 255); - NewColors.g = SohImGui::ClampFloatToInt(colors.y * 255, 0, 255); - NewColors.b = SohImGui::ClampFloatToInt(colors.z * 255, 0, 255); + NewColors.r = fmin(fmax(colors.x * 255, 0), 255); + NewColors.g = fmin(fmax(colors.y * 255, 0), 255); + NewColors.b = fmin(fmax(colors.z * 255, 0), 255); Element->ModifiedColor = colors; CVar_SetRGBA(cvarName.c_str(), NewColors); CVar_SetS32(Cvar_RBM.c_str(), 0); @@ -149,9 +151,9 @@ void LoadRainbowColor(bool& open) { case 6: NewColor.x = 255; NewColor.y = 0; NewColor.z = a; break; } Color_RGBA8 NewColorRGB = { - SohImGui::ClampFloatToInt(NewColor.x, 0, 255), - SohImGui::ClampFloatToInt(NewColor.y, 0, 255), - SohImGui::ClampFloatToInt(NewColor.z, 0, 255), + fmin(fmax(NewColor.x, 0), 255), + fmin(fmax(NewColor.y, 0), 255), + fmin(fmax(NewColor.z, 0), 255), 255 }; if (CVar_GetS32(Cvar_RBM.c_str(), 0) != 0) { @@ -187,7 +189,7 @@ void Draw_HelpIcon(const std::string& helptext, bool sameline = true, int Pos = ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x-60); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 15); ImGui::SmallButton("?"); - SohImGui::Tooltip(helptext.c_str()); + UIWidgets::Tooltip(helptext.c_str()); if (sameline) { //I do not use ImGui::SameLine(); because it make some element vanish. ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 22); @@ -197,96 +199,96 @@ void Draw_HelpIcon(const std::string& helptext, bool sameline = true, int Pos = void DrawUseMarginsSlider(const std::string ElementName, const std::string CvarName){ std::string CvarLabel = CvarName + "UseMargins"; std::string Label = ElementName + " use margins"; - SohImGui::EnhancementCheckbox(Label.c_str(), CvarLabel.c_str()); - SohImGui::Tooltip("Using this allow you move the element with General margins sliders"); + UIWidgets::EnhancementCheckbox(Label.c_str(), CvarLabel.c_str()); + UIWidgets::Tooltip("Using this allow you move the element with General margins sliders"); } void DrawPositionsRadioBoxes(const std::string CvarName, bool NoAnchorEnabled = true){ std::string CvarLabel = CvarName + "PosType"; - SohImGui::EnhancementRadioButton("Original position", CvarLabel.c_str(), 0); - SohImGui::Tooltip("This will use original intended elements position"); - SohImGui::EnhancementRadioButton("Anchor to the left", CvarLabel.c_str(), 1); - SohImGui::Tooltip("This will make your elements follow the left side of your game window"); - SohImGui::EnhancementRadioButton("Anchor to the right", CvarLabel.c_str(), 2); - SohImGui::Tooltip("This will make your elements follow the right side of your game window"); + UIWidgets::EnhancementRadioButton("Original position", CvarLabel.c_str(), 0); + UIWidgets::Tooltip("This will use original intended elements position"); + UIWidgets::EnhancementRadioButton("Anchor to the left", CvarLabel.c_str(), 1); + UIWidgets::Tooltip("This will make your elements follow the left side of your game window"); + UIWidgets::EnhancementRadioButton("Anchor to the right", CvarLabel.c_str(), 2); + UIWidgets::Tooltip("This will make your elements follow the right side of your game window"); if (NoAnchorEnabled) { - SohImGui::EnhancementRadioButton("No anchors", CvarLabel.c_str(), 3); - SohImGui::Tooltip("This will make your elements to not follow any side\nBetter used for center elements"); + UIWidgets::EnhancementRadioButton("No anchors", CvarLabel.c_str(), 3); + UIWidgets::Tooltip("This will make your elements to not follow any side\nBetter used for center elements"); } - SohImGui::EnhancementRadioButton("Hidden", CvarLabel.c_str(), 4); - SohImGui::Tooltip("This will make your elements hidden"); + UIWidgets::EnhancementRadioButton("Hidden", CvarLabel.c_str(), 4); + UIWidgets::Tooltip("This will make your elements hidden"); } void DrawTransitions(const std::string CvarName){ - SohImGui::EnhancementRadioButton("Really slow fade (white)", CvarName.c_str(), 8); + UIWidgets::EnhancementRadioButton("Really slow fade (white)", CvarName.c_str(), 8); Table_NextCol(); - SohImGui::EnhancementRadioButton("Really slow fade (black)", CvarName.c_str(), 7); + UIWidgets::EnhancementRadioButton("Really slow fade (black)", CvarName.c_str(), 7); Table_NextLine(); - SohImGui::EnhancementRadioButton("Slow fade (white)", CvarName.c_str(), 10); + UIWidgets::EnhancementRadioButton("Slow fade (white)", CvarName.c_str(), 10); Table_NextCol(); - SohImGui::EnhancementRadioButton("Slow fade (black)", CvarName.c_str(), 9); + UIWidgets::EnhancementRadioButton("Slow fade (black)", CvarName.c_str(), 9); Table_NextLine(); - SohImGui::EnhancementRadioButton("Normal fade (white)", CvarName.c_str(), 3); + UIWidgets::EnhancementRadioButton("Normal fade (white)", CvarName.c_str(), 3); Table_NextCol(); - SohImGui::EnhancementRadioButton("Normal fade (black)", CvarName.c_str(), 2); + UIWidgets::EnhancementRadioButton("Normal fade (black)", CvarName.c_str(), 2); Table_NextLine(); - SohImGui::EnhancementRadioButton("Fast fade (white)", CvarName.c_str(), 5); + UIWidgets::EnhancementRadioButton("Fast fade (white)", CvarName.c_str(), 5); Table_NextCol(); - SohImGui::EnhancementRadioButton("Fast fade (black)", CvarName.c_str(), 4); + UIWidgets::EnhancementRadioButton("Fast fade (black)", CvarName.c_str(), 4); Table_NextLine(); - SohImGui::EnhancementRadioButton("Fast circle (white)", CvarName.c_str(), 40); + UIWidgets::EnhancementRadioButton("Fast circle (white)", CvarName.c_str(), 40); Table_NextCol(); - SohImGui::EnhancementRadioButton("Normal circle (black)", CvarName.c_str(), 32); + UIWidgets::EnhancementRadioButton("Normal circle (black)", CvarName.c_str(), 32); Table_NextLine(); - SohImGui::EnhancementRadioButton("Slow circle (white)", CvarName.c_str(), 41); + UIWidgets::EnhancementRadioButton("Slow circle (white)", CvarName.c_str(), 41); Table_NextCol(); - SohImGui::EnhancementRadioButton("Slow circle (black)", CvarName.c_str(), 33); + UIWidgets::EnhancementRadioButton("Slow circle (black)", CvarName.c_str(), 33); Table_NextLine(); - SohImGui::EnhancementRadioButton("Fast noise circle (white)", CvarName.c_str(), 42); + UIWidgets::EnhancementRadioButton("Fast noise circle (white)", CvarName.c_str(), 42); Table_NextCol(); - SohImGui::EnhancementRadioButton("Fast noise circle (black)", CvarName.c_str(), 34); + UIWidgets::EnhancementRadioButton("Fast noise circle (black)", CvarName.c_str(), 34); Table_NextLine(); - SohImGui::EnhancementRadioButton("Slow noise circle (white)", CvarName.c_str(), 43); + UIWidgets::EnhancementRadioButton("Slow noise circle (white)", CvarName.c_str(), 43); Table_NextCol(); - SohImGui::EnhancementRadioButton("Slow noise circle (black)", CvarName.c_str(), 35); + UIWidgets::EnhancementRadioButton("Slow noise circle (black)", CvarName.c_str(), 35); Table_NextLine(); - SohImGui::EnhancementRadioButton("Normal waves circle (white)", CvarName.c_str(), 44); + UIWidgets::EnhancementRadioButton("Normal waves circle (white)", CvarName.c_str(), 44); Table_NextCol(); - SohImGui::EnhancementRadioButton("Normal waves circle (black)", CvarName.c_str(), 36); + UIWidgets::EnhancementRadioButton("Normal waves circle (black)", CvarName.c_str(), 36); Table_NextLine(); - SohImGui::EnhancementRadioButton("Slow waves circle (white)", CvarName.c_str(), 45); + UIWidgets::EnhancementRadioButton("Slow waves circle (white)", CvarName.c_str(), 45); Table_NextCol(); - SohImGui::EnhancementRadioButton("Slow waves circle (black)", CvarName.c_str(), 37); + UIWidgets::EnhancementRadioButton("Slow waves circle (black)", CvarName.c_str(), 37); Table_NextLine(); - SohImGui::EnhancementRadioButton("Normal close circle (white)", CvarName.c_str(), 46); + UIWidgets::EnhancementRadioButton("Normal close circle (white)", CvarName.c_str(), 46); Table_NextCol(); - SohImGui::EnhancementRadioButton("Normal close circle (black)", CvarName.c_str(), 38); + UIWidgets::EnhancementRadioButton("Normal close circle (black)", CvarName.c_str(), 38); Table_NextLine(); - SohImGui::EnhancementRadioButton("Slow close circle (white)", CvarName.c_str(), 47); + UIWidgets::EnhancementRadioButton("Slow close circle (white)", CvarName.c_str(), 47); Table_NextCol(); - SohImGui::EnhancementRadioButton("Slow close circle (black)", CvarName.c_str(), 39); + UIWidgets::EnhancementRadioButton("Slow close circle (black)", CvarName.c_str(), 39); Table_NextLine(); - SohImGui::EnhancementRadioButton("Super fast circle (white)", CvarName.c_str(), 56); + UIWidgets::EnhancementRadioButton("Super fast circle (white)", CvarName.c_str(), 56); Table_NextCol(); - SohImGui::EnhancementRadioButton("Super fast circle (black)", CvarName.c_str(), 58); + UIWidgets::EnhancementRadioButton("Super fast circle (black)", CvarName.c_str(), 58); Table_NextLine(); - SohImGui::EnhancementRadioButton("Super fast noise circle (white)", CvarName.c_str(), 57); + UIWidgets::EnhancementRadioButton("Super fast noise circle (white)", CvarName.c_str(), 57); Table_NextCol(); - SohImGui::EnhancementRadioButton("Super fast noise circle (black)", CvarName.c_str(), 59); + UIWidgets::EnhancementRadioButton("Super fast noise circle (black)", CvarName.c_str(), 59); } void DrawPositionSlider(const std::string CvarName, int MinY, int MaxY, int MinX, int MaxX){ std::string PosXCvar = CvarName+"PosX"; std::string PosYCvar = CvarName+"PosY"; std::string InvisibleLabelX = "##"+PosXCvar; std::string InvisibleLabelY = "##"+PosYCvar; - SohImGui::EnhancementSliderInt("Up <-> Down : %d", InvisibleLabelY.c_str(), PosYCvar.c_str(), MinY, MaxY, "", 0, true); - SohImGui::Tooltip("This slider is used to move Up and Down your elements."); - SohImGui::EnhancementSliderInt("Left <-> Right : %d", InvisibleLabelX.c_str(), PosXCvar.c_str(), MinX, MaxX, "", 0, true); - SohImGui::Tooltip("This slider is used to move Left and Right your elements."); + UIWidgets::EnhancementSliderInt("Up <-> Down : %d", InvisibleLabelY.c_str(), PosYCvar.c_str(), MinY, MaxY, "", 0, true); + UIWidgets::Tooltip("This slider is used to move Up and Down your elements."); + UIWidgets::EnhancementSliderInt("Left <-> Right : %d", InvisibleLabelX.c_str(), PosXCvar.c_str(), MinX, MaxX, "", 0, true); + UIWidgets::Tooltip("This slider is used to move Left and Right your elements."); } void DrawScaleSlider(const std::string CvarName,float DefaultValue){ std::string InvisibleLabel = "##"+CvarName; std::string CvarLabel = CvarName+"Scale"; //Disabled for now. feature not done and several fixes needed to be merged. - //SohImGui::EnhancementSliderFloat("Scale : %dx", InvisibleLabel.c_str(), CvarLabel.c_str(), 0.1f, 3.0f,"",DefaultValue,true,true); + //UIWidgets::EnhancementSliderFloat("Scale : %dx", InvisibleLabel.c_str(), CvarLabel.c_str(), 0.1f, 3.0f,"",DefaultValue,true,true); } void DrawColorSection(CosmeticsColorSection* ColorSection, int SectionSize) { for (s16 i = 0; i < SectionSize; i++) { @@ -308,7 +310,7 @@ void DrawColorSection(CosmeticsColorSection* ColorSection, int SectionSize) { Table_NextLine(); } Draw_HelpIcon(Tooltip.c_str()); - SohImGui::EnhancementColor(Name.c_str(), Cvar.c_str(), ModifiedColor, DefaultColor, canRainbow, hasAlpha, sameLine); + UIWidgets::EnhancementColor(Name.c_str(), Cvar.c_str(), ModifiedColor, DefaultColor, canRainbow, hasAlpha, sameLine); } } void DrawRandomizeResetButton(const std::string Identifier, CosmeticsColorSection* ColorSection, int SectionSize, bool isAllCosmetics = false){ @@ -335,21 +337,21 @@ void DrawRandomizeResetButton(const std::string Identifier, CosmeticsColorSectio CVar_SetS32("gCCparated", 1); GetRandomColorRGB(ColorSection, SectionSize); } - SohImGui::Tooltip(Tooltip_RNG.c_str()); + UIWidgets::Tooltip(Tooltip_RNG.c_str()); Table_NextCol(); if(ImGui::Button(Reset_BtnText.c_str(), ImVec2( ImGui::GetContentRegionAvail().x, 20.0f))){ GetDefaultColorRGB(ColorSection, SectionSize); } - SohImGui::Tooltip("Enable/Disable custom Link's tunics colors\nIf disabled you will have original colors for Link's tunics."); - SohImGui::Tooltip(Tooltip_RNG.c_str()); + UIWidgets::Tooltip("Enable/Disable custom Link's tunics colors\nIf disabled you will have original colors for Link's tunics."); + UIWidgets::Tooltip(Tooltip_RNG.c_str()); ImGui::EndTable(); } } void Draw_Npcs(){ DrawRandomizeResetButton("all NPCs", NPCs_section, SECTION_SIZE(NPCs_section)); - SohImGui::EnhancementCheckbox("Custom colors for Navi", "gUseNaviCol"); - SohImGui::Tooltip("Enable/Disable custom Navi colors\nIf disabled, default colors will be used\nColors go into effect when Navi goes back into your pockets"); + UIWidgets::EnhancementCheckbox("Custom colors for Navi", "gUseNaviCol"); + UIWidgets::Tooltip("Enable/Disable custom Navi colors\nIf disabled, default colors will be used\nColors go into effect when Navi goes back into your pockets"); if (CVar_GetS32("gUseNaviCol",0)) { DrawRandomizeResetButton("Navi's", Navi_Section, SECTION_SIZE(Navi_Section)); }; @@ -360,8 +362,8 @@ void Draw_Npcs(){ DrawColorSection(Navi_Section, SECTION_SIZE(Navi_Section)); ImGui::EndTable(); } - SohImGui::EnhancementCheckbox("Custom colors for Keese", "gUseKeeseCol"); - SohImGui::Tooltip("Enable/Disable custom Keese element colors\nIf disabled, default element colors will be used\nColors go into effect when Keese respawn (or when the room is reloaded)"); + UIWidgets::EnhancementCheckbox("Custom colors for Keese", "gUseKeeseCol"); + UIWidgets::Tooltip("Enable/Disable custom Keese element colors\nIf disabled, default element colors will be used\nColors go into effect when Keese respawn (or when the room is reloaded)"); if (CVar_GetS32("gUseKeeseCol",0) && ImGui::BeginTable("tableKeese", 2, FlagsTable)) { ImGui::TableSetupColumn("Fire colors##Keese", FlagsCell, TablesCellsWidth/2); ImGui::TableSetupColumn("Ice colors##Keese", FlagsCell, TablesCellsWidth/2); @@ -369,8 +371,8 @@ void Draw_Npcs(){ DrawColorSection(Keese_Section, SECTION_SIZE(Keese_Section)); ImGui::EndTable(); } - SohImGui::EnhancementCheckbox("Custom colors for Dogs", "gUseDogsCol"); - SohImGui::Tooltip("Enable/Disable custom colors for the two Dog variants\nIf disabled, default colors will be used"); + UIWidgets::EnhancementCheckbox("Custom colors for Dogs", "gUseDogsCol"); + UIWidgets::Tooltip("Enable/Disable custom colors for the two Dog variants\nIf disabled, default colors will be used"); if (CVar_GetS32("gUseDogsCol",0) && ImGui::BeginTable("tableDogs", 2, FlagsTable)) { ImGui::TableSetupColumn("White Dog color", FlagsCell, TablesCellsWidth/2); ImGui::TableSetupColumn("Brown Dog color", FlagsCell, TablesCellsWidth/2); @@ -381,8 +383,8 @@ void Draw_Npcs(){ } void Draw_ItemsSkills(){ DrawRandomizeResetButton("all skills and items", AllItemsSkills_section, SECTION_SIZE(AllItemsSkills_section)); - SohImGui::EnhancementCheckbox("Custom tunics color", "gUseTunicsCol"); - SohImGui::Tooltip("Enable/Disable custom Link's tunics colors\nIf disabled you will have original colors for Link's tunics."); + UIWidgets::EnhancementCheckbox("Custom tunics color", "gUseTunicsCol"); + UIWidgets::Tooltip("Enable/Disable custom Link's tunics colors\nIf disabled you will have original colors for Link's tunics."); if (CVar_GetS32("gUseTunicsCol",0)) { DrawRandomizeResetButton("Link's tunics", Tunics_Section, SECTION_SIZE(Tunics_Section)); }; @@ -394,7 +396,7 @@ void Draw_ItemsSkills(){ DrawColorSection(Tunics_Section, SECTION_SIZE(Tunics_Section)); ImGui::EndTable(); } - SohImGui::EnhancementCheckbox("Custom arrows colors", "gUseArrowsCol"); + UIWidgets::EnhancementCheckbox("Custom arrows colors", "gUseArrowsCol"); if (CVar_GetS32("gUseArrowsCol",0)) { DrawRandomizeResetButton("elemental arrows", Arrows_section, SECTION_SIZE(Arrows_section)); } @@ -405,7 +407,7 @@ void Draw_ItemsSkills(){ DrawColorSection(Arrows_section, SECTION_SIZE(Arrows_section)); ImGui::EndTable(); } - SohImGui::EnhancementCheckbox("Custom spells colors", "gUseSpellsCol"); + UIWidgets::EnhancementCheckbox("Custom spells colors", "gUseSpellsCol"); if (CVar_GetS32("gUseSpellsCol",0)) { DrawRandomizeResetButton("spells", Spells_section, SECTION_SIZE(Spells_section)); } @@ -416,7 +418,7 @@ void Draw_ItemsSkills(){ DrawColorSection(Spells_section, SECTION_SIZE(Spells_section)); ImGui::EndTable(); } - SohImGui::EnhancementCheckbox("Custom spin attack colors", "gUseChargedCol"); + UIWidgets::EnhancementCheckbox("Custom spin attack colors", "gUseChargedCol"); if (CVar_GetS32("gUseChargedCol",0)) { DrawRandomizeResetButton("spins attack", SpinAtk_section, SECTION_SIZE(SpinAtk_section)); } @@ -427,13 +429,13 @@ void Draw_ItemsSkills(){ DrawColorSection(SpinAtk_section, SECTION_SIZE(SpinAtk_section)); ImGui::EndTable(); } - SohImGui::EnhancementCheckbox("Custom trails color", "gUseTrailsCol"); + UIWidgets::EnhancementCheckbox("Custom trails color", "gUseTrailsCol"); if (CVar_GetS32("gUseTrailsCol",0) && ImGui::BeginTable("tabletrails", 1, FlagsTable)) { ImGui::TableSetupColumn("Custom Trails", FlagsCell, TablesCellsWidth); Table_InitHeader(); DrawColorSection(Trails_section, SECTION_SIZE(Trails_section)); - SohImGui::EnhancementSliderInt("Trails duration: %dx", "##TrailsMul", "gTrailDurantion", 1, 5, ""); - SohImGui::Tooltip("The longer the trails the weirder it become"); + UIWidgets::EnhancementSliderInt("Trails duration: %dx", "##TrailsMul", "gTrailDurantion", 1, 5, ""); + UIWidgets::Tooltip("The longer the trails the weirder it become"); ImGui::NewLine(); ImGui::EndTable(); } @@ -455,18 +457,18 @@ void Draw_Placements(){ if (ImGui::BeginTable("tableMargins", 1, FlagsTable)) { ImGui::TableSetupColumn("General margins settings", FlagsCell, TablesCellsWidth); Table_InitHeader(); - SohImGui::EnhancementSliderInt("Top : %dx", "##UIMARGINT", "gHUDMargin_T", (ImGui::GetWindowViewport()->Size.y/2)*-1, 25, "", 0, true); - SohImGui::EnhancementSliderInt("Left: %dx", "##UIMARGINL", "gHUDMargin_L", -25, ImGui::GetWindowViewport()->Size.x, "", 0, true); - SohImGui::EnhancementSliderInt("Right: %dx", "##UIMARGINR", "gHUDMargin_R", (ImGui::GetWindowViewport()->Size.x)*-1, 25, "", 0, true); - SohImGui::EnhancementSliderInt("Bottom: %dx", "##UIMARGINB", "gHUDMargin_B", (ImGui::GetWindowViewport()->Size.y/2)*-1, 25, "", 0, true); + UIWidgets::EnhancementSliderInt("Top : %dx", "##UIMARGINT", "gHUDMargin_T", (ImGui::GetWindowViewport()->Size.y/2)*-1, 25, "", 0, true); + UIWidgets::EnhancementSliderInt("Left: %dx", "##UIMARGINL", "gHUDMargin_L", -25, ImGui::GetWindowViewport()->Size.x, "", 0, true); + UIWidgets::EnhancementSliderInt("Right: %dx", "##UIMARGINR", "gHUDMargin_R", (ImGui::GetWindowViewport()->Size.x)*-1, 25, "", 0, true); + UIWidgets::EnhancementSliderInt("Bottom: %dx", "##UIMARGINB", "gHUDMargin_B", (ImGui::GetWindowViewport()->Size.y/2)*-1, 25, "", 0, true); SetMarginAll("All margins on",true); - SohImGui::Tooltip("Set most of the element to use margin\nSome elements with default position will not be affected\nElements without Archor or Hidden will not be turned on"); + UIWidgets::Tooltip("Set most of the element to use margin\nSome elements with default position will not be affected\nElements without Archor or Hidden will not be turned on"); ImGui::SameLine(); SetMarginAll("All margins off",false); - SohImGui::Tooltip("Set all of the element to not use margin"); + UIWidgets::Tooltip("Set all of the element to not use margin"); ImGui::SameLine(); ResetPositionAll(); - SohImGui::Tooltip("Revert every element to use their original position and no margins"); + UIWidgets::Tooltip("Revert every element to use their original position and no margins"); ImGui::NewLine(); ImGui::EndTable(); } @@ -775,7 +777,7 @@ void Draw_HUDButtons(){ DrawColorSection(C_Btn_Unified_section, SECTION_SIZE(C_Btn_Unified_section)); ImGui::EndTable(); } - SohImGui::EnhancementCheckbox("C-Buttons use separate colors", "gCCparated"); + UIWidgets::EnhancementCheckbox("C-Buttons use separate colors", "gCCparated"); if (CVar_GetS32("gCCparated",0) && ImGui::CollapsingHeader("C Button individual colors")) { if (ImGui::BeginTable("tableBTN_CSep", 1, FlagsTable)) { ImGui::TableSetupColumn("C-Buttons individual colors", FlagsCell, TablesCellsWidth); @@ -813,19 +815,19 @@ void Draw_General(){ ImGui::TableSetupColumn("Custom Schemes", FlagsCell, TablesCellsWidth); Table_InitHeader(); Draw_HelpIcon("Change interface color to N64 style"); - SohImGui::EnhancementRadioButton("N64 Colors", "gHudColors", 0); + UIWidgets::EnhancementRadioButton("N64 Colors", "gHudColors", 0); Table_NextCol(); Draw_HelpIcon("Change interface color to GameCube style"); - SohImGui::EnhancementRadioButton("GCN Colors", "gHudColors", 1); + UIWidgets::EnhancementRadioButton("GCN Colors", "gHudColors", 1); Table_NextCol(); Draw_HelpIcon("Lets you change every interface color to your liking"); - SohImGui::EnhancementRadioButton("Custom Colors", "gHudColors", 2); + UIWidgets::EnhancementRadioButton("Custom Colors", "gHudColors", 2); ImGui::EndTable(); } if (CVar_GetS32("gHudColors",0) ==2 ){ DrawRandomizeResetButton("interface (excluding buttons)", Misc_Interface_section, SECTION_SIZE(Misc_Interface_section)); if (ImGui::CollapsingHeader("Hearts colors")) { - SohImGui::Tooltip("Hearts colors in general\nDD stand for Double Defense"); + UIWidgets::Tooltip("Hearts colors in general\nDD stand for Double Defense"); if (ImGui::BeginTable("tableHearts", 3, FlagsTable | ImGuiTableFlags_Hideable)) { ImGui::TableSetupColumn("Hearts (normal)", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_IndentEnable, TablesCellsWidth/3); ImGui::TableSetupColumn("Hearts (DD)", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_IndentEnable, TablesCellsWidth/3); @@ -874,25 +876,25 @@ void Draw_General(){ ImGui::TableSetupColumn("transitionother1", FlagsCell, TablesCellsWidth/2); ImGui::TableSetupColumn("transitionother2", FlagsCell, TablesCellsWidth/2); Table_InitHeader(false); - SohImGui::EnhancementRadioButton("Originals", "gSceneTransitions", 255); - SohImGui::Tooltip("This will make the game use original scenes transitions"); + UIWidgets::EnhancementRadioButton("Originals", "gSceneTransitions", 255); + UIWidgets::Tooltip("This will make the game use original scenes transitions"); Table_NextCol(); - SohImGui::EnhancementRadioButton("None", "gSceneTransitions", 11); - SohImGui::Tooltip("This will make the game use no any scenes transitions"); + UIWidgets::EnhancementRadioButton("None", "gSceneTransitions", 11); + UIWidgets::Tooltip("This will make the game use no any scenes transitions"); Table_NextLine(); - SohImGui::EnhancementRadioButton("Desert mode (persistant)", "gSceneTransitions", 14); - SohImGui::Tooltip("This will make the game use the sand storm scenes transitions that will persist in map"); + UIWidgets::EnhancementRadioButton("Desert mode (persistant)", "gSceneTransitions", 14); + UIWidgets::Tooltip("This will make the game use the sand storm scenes transitions that will persist in map"); Table_NextCol(); - SohImGui::EnhancementRadioButton("Desert mode (non persistant)", "gSceneTransitions", 15); - SohImGui::Tooltip("This will make the game use the sand storm scenes transitions"); + UIWidgets::EnhancementRadioButton("Desert mode (non persistant)", "gSceneTransitions", 15); + UIWidgets::Tooltip("This will make the game use the sand storm scenes transitions"); Table_NextLine(); - SohImGui::EnhancementRadioButton("Normal fade (green)", "gSceneTransitions", 18); - SohImGui::Tooltip("This will make the game use a greenish fade in/out scenes transitions"); + UIWidgets::EnhancementRadioButton("Normal fade (green)", "gSceneTransitions", 18); + UIWidgets::Tooltip("This will make the game use a greenish fade in/out scenes transitions"); Table_NextCol(); - SohImGui::EnhancementRadioButton("Normal fade (blue)", "gSceneTransitions", 19); - SohImGui::Tooltip("This will make the game use a blue fade in/out scenes transitions"); + UIWidgets::EnhancementRadioButton("Normal fade (blue)", "gSceneTransitions", 19); + UIWidgets::Tooltip("This will make the game use a blue fade in/out scenes transitions"); Table_NextLine(); - SohImGui::EnhancementRadioButton("Triforce", "gSceneTransitions", 1); + UIWidgets::EnhancementRadioButton("Triforce", "gSceneTransitions", 1); ImGui::EndTable(); } if (ImGui::BeginTable("tabletransitionCol", 2, FlagsTable | ImGuiTableFlags_Hideable)) { @@ -948,6 +950,7 @@ void DrawCosmeticsEditor(bool& open) { } ImGui::End(); } + void InitCosmeticsEditor() { //This allow to hide a window without disturbing the player nor adding things in menu //LoadRainbowColor() will this way run in background once it's window is activated @@ -955,4 +958,4 @@ void InitCosmeticsEditor() { SohImGui::AddWindow("Enhancements", "Rainbowfunction", LoadRainbowColor, true, true); //Draw the bar in the menu. SohImGui::AddWindow("Enhancements", "Cosmetics Editor", DrawCosmeticsEditor); -} \ No newline at end of file +} diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h index 4b6ea249b..cd104633d 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.h @@ -1,5 +1,5 @@ #pragma once -#include "../libultraship/ImGuiImpl.h" +#include #define SECTION_SIZE(arr) (s32)(sizeof(arr) / sizeof(arr[0])) #define RANDOMIZE_32(Max) GetRandomValue(Max); #define CATEGORY_NPC 0 @@ -405,4 +405,4 @@ static CosmeticsColorSection AllItemsSkills_section[]{ void InitCosmeticsEditor();//Init the menu itself void LoadRainbowColor(); -void NewSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0); \ No newline at end of file +void NewSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0); diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 409f2e4b5..36c9f9ea0 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -1,7 +1,7 @@ #include "debugconsole.h" -#include "../libultraship/ImGuiImpl.h" +#include #include "savestates.h" -#include "Console.h" +#include #include #include @@ -12,8 +12,8 @@ #define PATH_HACK #include -#include "Window.h" -#include "Lib/ImGui/imgui_internal.h" +#include +#include #undef PATH_HACK #undef Path @@ -25,18 +25,18 @@ extern "C" { extern GlobalContext* gGlobalCtx; } -#include "Cvar.h" +#include -#define CMD_REGISTER SohImGui::BindCmd +#define CMD_REGISTER SohImGui::GetConsole()->AddCommand static bool ActorSpawnHandler(std::shared_ptr Console, const std::vector& args) { if ((args.size() != 9) && (args.size() != 3) && (args.size() != 6)) { - SohImGui::console->SendErrorMessage("Not enough arguments passed to actorspawn"); + SohImGui::GetConsole()->SendErrorMessage("Not enough arguments passed to actorspawn"); return CMD_FAILED; } if (gGlobalCtx == nullptr) { - SohImGui::console->SendErrorMessage("GlobalCtx == nullptr"); + SohImGui::GetConsole()->SendErrorMessage("GlobalCtx == nullptr"); return CMD_FAILED; } @@ -72,7 +72,7 @@ static bool ActorSpawnHandler(std::shared_ptr Console, const std: if (Actor_Spawn(&gGlobalCtx->actorCtx, gGlobalCtx, actorId, spawnPoint.pos.x, spawnPoint.pos.y, spawnPoint.pos.z, spawnPoint.rot.x, spawnPoint.rot.y, spawnPoint.rot.z, params) == NULL) { - SohImGui::console->SendErrorMessage("Failed to spawn actor. Actor_Spawn returned NULL"); + SohImGui::GetConsole()->SendErrorMessage("Failed to spawn actor. Actor_Spawn returned NULL"); return CMD_FAILED; } return CMD_SUCCESS; @@ -81,13 +81,13 @@ static bool ActorSpawnHandler(std::shared_ptr Console, const std: static bool KillPlayerHandler(std::shared_ptr Console, const std::vector&) { gSaveContext.health = 0; - SohImGui::console->SendInfoMessage("[SOH] You've met with a terrible fate, haven't you?"); + SohImGui::GetConsole()->SendInfoMessage("[SOH] You've met with a terrible fate, haven't you?"); return CMD_SUCCESS; } static bool SetPlayerHealthHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { - SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } @@ -96,18 +96,18 @@ static bool SetPlayerHealthHandler(std::shared_ptr Console, const try { health = std::stoi(args[1]); } catch (std::invalid_argument const& ex) { - SohImGui::console->SendErrorMessage("[SOH] Health value must be an integer."); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Health value must be an integer."); return CMD_FAILED; } if (health < 0) { - SohImGui::console->SendErrorMessage("[SOH] Health value must be a positive integer"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Health value must be a positive integer"); return CMD_SUCCESS; } gSaveContext.health = health * 0x10; - SohImGui::console->SendInfoMessage("[SOH] Player health updated to %d", health); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Player health updated to %d", health); return CMD_SUCCESS; } @@ -129,31 +129,31 @@ static bool RuppeHandler(std::shared_ptr Console, const std::vect rupeeAmount = std::stoi(args[1]); } catch (std::invalid_argument const& ex) { - SohImGui::console->SendErrorMessage("[SOH] Rupee count must be an integer."); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Rupee count must be an integer."); return CMD_FAILED; } if (rupeeAmount < 0) { - SohImGui::console->SendErrorMessage("[SOH] Rupee count must be positive"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Rupee count must be positive"); return CMD_FAILED; } gSaveContext.rupees = rupeeAmount; - SohImGui::console->SendInfoMessage("Set rupee count to %u", rupeeAmount); + SohImGui::GetConsole()->SendInfoMessage("Set rupee count to %u", rupeeAmount); return CMD_SUCCESS; } static bool SetPosHandler(std::shared_ptr Console, const std::vector args) { if (gGlobalCtx == nullptr) { - SohImGui::console->SendErrorMessage("GlobalCtx == nullptr"); + SohImGui::GetConsole()->SendErrorMessage("GlobalCtx == nullptr"); return CMD_FAILED; } Player* player = GET_PLAYER(gGlobalCtx); if (args.size() == 1) { - SohImGui::console->SendInfoMessage("Player position is [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x, + SohImGui::GetConsole()->SendInfoMessage("Player position is [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x, player->actor.world.pos.y, player->actor.world.pos.z); return CMD_SUCCESS; @@ -165,7 +165,7 @@ static bool SetPosHandler(std::shared_ptr Console, const std::vec player->actor.world.pos.y = std::stof(args[2]); player->actor.world.pos.z = std::stof(args[3]); - SohImGui::console->SendInfoMessage("Set player position to [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x, + SohImGui::GetConsole()->SendInfoMessage("Set player position to [ %.2f, %.2f, %.2f ]", player->actor.world.pos.x, player->actor.world.pos.y, player->actor.world.pos.z); return CMD_SUCCESS; @@ -173,7 +173,7 @@ static bool SetPosHandler(std::shared_ptr Console, const std::vec static bool ResetHandler(std::shared_ptr Console, std::vector args) { if (gGlobalCtx == nullptr) { - SohImGui::console->SendErrorMessage("GlobalCtx == nullptr"); + SohImGui::GetConsole()->SendErrorMessage("GlobalCtx == nullptr"); return CMD_FAILED; } @@ -194,7 +194,7 @@ const static std::map ammoItems{ static bool AmmoHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 3) { - SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } @@ -203,19 +203,19 @@ static bool AmmoHandler(std::shared_ptr Console, const std::vecto try { count = std::stoi(args[2]); } catch (std::invalid_argument const& ex) { - SohImGui::console->SendErrorMessage("Ammo count must be an integer"); + SohImGui::GetConsole()->SendErrorMessage("Ammo count must be an integer"); return CMD_FAILED; } if (count < 0) { - SohImGui::console->SendErrorMessage("Ammo count must be positive"); + SohImGui::GetConsole()->SendErrorMessage("Ammo count must be positive"); return CMD_FAILED; } const auto& it = ammoItems.find(args[1]); if (it == ammoItems.end()) { - SohImGui::console->SendErrorMessage("Invalid item passed"); + SohImGui::GetConsole()->SendErrorMessage("Invalid item passed"); return CMD_FAILED; } @@ -237,7 +237,7 @@ const static std::map bottleItems{ static bool BottleHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 3) { - SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } @@ -245,19 +245,19 @@ static bool BottleHandler(std::shared_ptr Console, const std::vec try { slot = std::stoi(args[2]); } catch (std::invalid_argument const& ex) { - SohImGui::console->SendErrorMessage("[SOH] Bottle slot must be an integer."); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Bottle slot must be an integer."); return CMD_FAILED; } if ((slot < 1) || (slot > 4)) { - SohImGui::console->SendErrorMessage("Invalid slot passed"); + SohImGui::GetConsole()->SendErrorMessage("Invalid slot passed"); return CMD_FAILED; } const auto& it = bottleItems.find(args[1]); if (it == bottleItems.end()) { - SohImGui::console->SendErrorMessage("Invalid item passed"); + SohImGui::GetConsole()->SendErrorMessage("Invalid item passed"); return CMD_FAILED; } @@ -269,7 +269,7 @@ static bool BottleHandler(std::shared_ptr Console, const std::vec static bool BHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { - SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } @@ -279,7 +279,7 @@ static bool BHandler(std::shared_ptr Console, const std::vector Console, const std::vector& args) { if (args.size() != 3) { - SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } @@ -290,7 +290,7 @@ static bool ItemHandler(std::shared_ptr Console, const std::vecto static bool EntranceHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { - SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } @@ -299,7 +299,7 @@ static bool EntranceHandler(std::shared_ptr Console, const std::v try { entrance = std::stoi(args[1], nullptr, 16); } catch (std::invalid_argument const& ex) { - SohImGui::console->SendErrorMessage("[SOH] Entrance value must be a Hex number."); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Entrance value must be a Hex number."); return CMD_FAILED; } @@ -319,7 +319,7 @@ static bool VoidHandler(std::shared_ptr Console, const std::vecto gGlobalCtx->fadeTransition = 2; gSaveContext.nextTransition = 2; } else { - SohImGui::console->SendErrorMessage("gGlobalCtx == nullptr"); + SohImGui::GetConsole()->SendErrorMessage("gGlobalCtx == nullptr"); return CMD_FAILED; } return CMD_SUCCESS; @@ -332,7 +332,7 @@ static bool ReloadHandler(std::shared_ptr Console, const std::vec gGlobalCtx->fadeTransition = 11; gSaveContext.nextTransition = 11; } else { - SohImGui::console->SendErrorMessage("gGlobalCtx == nullptr"); + SohImGui::GetConsole()->SendErrorMessage("gGlobalCtx == nullptr"); return CMD_FAILED; } return CMD_SUCCESS; @@ -345,11 +345,11 @@ static bool FWHandler(std::shared_ptr Console, const std::vector< gGlobalCtx->nextEntranceIndex = gSaveContext.respawn[RESPAWN_MODE_TOP].entranceIndex; gGlobalCtx->fadeTransition = 5; } else { - SohImGui::console->SendErrorMessage("Farore's wind not set!"); + SohImGui::GetConsole()->SendErrorMessage("Farore's wind not set!"); } } else { - SohImGui::console->SendErrorMessage("gGlobalCtx == nullptr"); + SohImGui::GetConsole()->SendErrorMessage("gGlobalCtx == nullptr"); return CMD_FAILED; } @@ -361,7 +361,7 @@ static bool FileSelectHandler(std::shared_ptr Console, const std: SET_NEXT_GAMESTATE(&gGlobalCtx->state, FileChoose_Init, FileChooseContext); gGlobalCtx->state.running = 0; } else { - SohImGui::console->SendErrorMessage("gGlobalCtx == nullptr"); + SohImGui::GetConsole()->SendErrorMessage("gGlobalCtx == nullptr"); return CMD_FAILED; } return CMD_SUCCESS; @@ -378,10 +378,10 @@ static bool SaveStateHandler(std::shared_ptr Console, const std:: switch (rtn) { case SaveStateReturn::SUCCESS: - SohImGui::console->SendInfoMessage("[SOH] Saved state to slot %u", slot); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Saved state to slot %u", slot); return CMD_SUCCESS; case SaveStateReturn::FAIL_WRONG_GAMESTATE: - SohImGui::console->SendErrorMessage("[SOH] Can not save a state outside of \"GamePlay\""); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Can not save a state outside of \"GamePlay\""); return CMD_FAILED; } } @@ -392,16 +392,16 @@ static bool LoadStateHandler(std::shared_ptr Console, const std:: switch (rtn) { case SaveStateReturn::SUCCESS: - SohImGui::console->SendInfoMessage("[SOH] Loaded state from slot (%u)", slot); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Loaded state from slot (%u)", slot); return CMD_SUCCESS; case SaveStateReturn::FAIL_INVALID_SLOT: - SohImGui::console->SendErrorMessage("[SOH] Invalid State Slot Number (%u)", slot); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Invalid State Slot Number (%u)", slot); return CMD_FAILED; case SaveStateReturn::FAIL_STATE_EMPTY: - SohImGui::console->SendErrorMessage("[SOH] State Slot (%u) is empty", slot); + SohImGui::GetConsole()->SendErrorMessage("[SOH] State Slot (%u) is empty", slot); return CMD_FAILED; case SaveStateReturn::FAIL_WRONG_GAMESTATE: - SohImGui::console->SendErrorMessage("[SOH] Can not load a state outside of \"GamePlay\""); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Can not load a state outside of \"GamePlay\""); return CMD_FAILED; } @@ -409,7 +409,7 @@ static bool LoadStateHandler(std::shared_ptr Console, const std:: static bool StateSlotSelectHandler(std::shared_ptr Console, const std::vector& args) { if (args.size() != 2) { - SohImGui::console->SendErrorMessage("[SOH] Unexpected arguments passed"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Unexpected arguments passed"); return CMD_FAILED; } int slot; @@ -417,17 +417,17 @@ static bool StateSlotSelectHandler(std::shared_ptr Console, const try { slot = std::stoi(args[1], nullptr, 10); } catch (std::invalid_argument const& ex) { - SohImGui::console->SendErrorMessage("[SOH] SaveState slot value must be a number."); + SohImGui::GetConsole()->SendErrorMessage("[SOH] SaveState slot value must be a number."); return CMD_FAILED; } if (slot < 0) { - SohImGui::console->SendErrorMessage("[SOH] Invalid slot passed. Slot must be between 0 and 2"); + SohImGui::GetConsole()->SendErrorMessage("[SOH] Invalid slot passed. Slot must be between 0 and 2"); return CMD_FAILED; } OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot); - SohImGui::console->SendInfoMessage("[SOH] Slot %u selected", + SohImGui::GetConsole()->SendInfoMessage("[SOH] Slot %u selected", OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot()); return CMD_SUCCESS; } @@ -488,7 +488,7 @@ static bool SetCVarHandler(std::shared_ptr Console, const std::ve CVar_Save(); - //SohImGui::console->SendInfoMessage("[SOH] Updated player position to [ %.2f, %.2f, %.2f ]", pos.x, pos.y, pos.z); + //SohImGui::GetConsole()->SendInfoMessage("[SOH] Updated player position to [ %.2f, %.2f, %.2f ]", pos.x, pos.y, pos.z); return CMD_SUCCESS; } @@ -502,17 +502,17 @@ static bool GetCVarHandler(std::shared_ptr Console, const std::ve if (cvar != nullptr) { if (cvar->type == CVarType::S32) - SohImGui::console->SendInfoMessage("[SOH] Variable %s is %i", args[1].c_str(), cvar->value.valueS32); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Variable %s is %i", args[1].c_str(), cvar->value.valueS32); else if (cvar->type == CVarType::Float) - SohImGui::console->SendInfoMessage("[SOH] Variable %s is %f", args[1].c_str(), cvar->value.valueFloat); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Variable %s is %f", args[1].c_str(), cvar->value.valueFloat); else if (cvar->type == CVarType::String) - SohImGui::console->SendInfoMessage("[SOH] Variable %s is %s", args[1].c_str(), cvar->value.valueStr); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Variable %s is %s", args[1].c_str(), cvar->value.valueStr); else if (cvar->type == CVarType::RGBA) - SohImGui::console->SendInfoMessage("[SOH] Variable %s is %08X", args[1].c_str(), cvar->value.valueRGBA); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Variable %s is %08X", args[1].c_str(), cvar->value.valueRGBA); } else { - SohImGui::console->SendInfoMessage("[SOH] Could not find variable %s", args[1].c_str()); + SohImGui::GetConsole()->SendInfoMessage("[SOH] Could not find variable %s", args[1].c_str()); } diff --git a/soh/soh/Enhancements/debugger/ImGuiHelpers.cpp b/soh/soh/Enhancements/debugger/ImGuiHelpers.cpp deleted file mode 100644 index d0ccab0eb..000000000 --- a/soh/soh/Enhancements/debugger/ImGuiHelpers.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "ImGuiHelpers.h" -#include "../../../../libultraship/libultraship/ImGuiImpl.h" - -// Adds a text tooltip for the previous ImGui item -void SetLastItemHoverText(const std::string& text) { - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text(SohImGui::BreakTooltip(text, 60).c_str()); - ImGui::EndTooltip(); - } -} - -// Adds a "?" next to the previous ImGui item with a custom tooltip -void InsertHelpHoverText(const std::string& text) { - ImGui::SameLine(); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?"); - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text(SohImGui::BreakTooltip(text, 60).c_str()); - ImGui::EndTooltip(); - } -} - -void PaddedSeparator(bool padTop, bool padBottom, float extraVerticalPadding) { - if (padTop) { - ImGui::Dummy(ImVec2(0.0f, extraVerticalPadding)); - } - ImGui::Separator(); - if (padBottom) { - ImGui::Dummy(ImVec2(0.0f, extraVerticalPadding)); - } -} diff --git a/soh/soh/Enhancements/debugger/ImGuiHelpers.h b/soh/soh/Enhancements/debugger/ImGuiHelpers.h deleted file mode 100644 index 91df059aa..000000000 --- a/soh/soh/Enhancements/debugger/ImGuiHelpers.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "../libultraship/Lib/ImGui/imgui.h" - -#include - -void SetLastItemHoverText(const std::string& text); - -void InsertHelpHoverText(const std::string& text); - -void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalPadding = 0); diff --git a/soh/soh/Enhancements/debugger/actorViewer.cpp b/soh/soh/Enhancements/debugger/actorViewer.cpp index 33bc532a0..8c6a4d543 100644 --- a/soh/soh/Enhancements/debugger/actorViewer.cpp +++ b/soh/soh/Enhancements/debugger/actorViewer.cpp @@ -1,13 +1,13 @@ #include "actorViewer.h" #include "../../util.h" -#include "../libultraship/ImGuiImpl.h" -#include "ImGuiHelpers.h" +#include "../../UIWidgets.hpp" +#include #include #include #include #include -#include +#include extern "C" { #include @@ -632,7 +632,7 @@ void DrawActorViewer(bool& open) { if (display.category == ACTORCAT_BOSS || display.category == ACTORCAT_ENEMY) { ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display.colChkInfo.health); - InsertHelpHoverText("Some actors might not use this!"); + UIWidgets::InsertHelpHoverText("Some actors might not use this!"); } if (ImGui::Button("Refresh")) { @@ -667,7 +667,7 @@ void DrawActorViewer(bool& open) { rm = TARGET; } } - InsertHelpHoverText("Grabs actor with target arrow above it. You might need C-Up for enemies"); + UIWidgets::InsertHelpHoverText("Grabs actor with target arrow above it. You might need C-Up for enemies"); if (ImGui::Button("Fetch from Held")) { Player* player = GET_PLAYER(gGlobalCtx); fetch = player->heldActor; @@ -678,7 +678,7 @@ void DrawActorViewer(bool& open) { rm = HELD; } } - InsertHelpHoverText("Grabs actor that Link is holding"); + UIWidgets::InsertHelpHoverText("Grabs actor that Link is holding"); if (ImGui::Button("Fetch from Interaction")) { Player* player = GET_PLAYER(gGlobalCtx); fetch = player->interactRangeActor; @@ -689,7 +689,7 @@ void DrawActorViewer(bool& open) { rm = INTERACT; } } - InsertHelpHoverText("Grabs actor from \"interaction range\""); + UIWidgets::InsertHelpHoverText("Grabs actor from \"interaction range\""); ImGui::TreePop(); } @@ -776,4 +776,4 @@ void DrawActorViewer(bool& open) { void InitActorViewer() { SohImGui::AddWindow("Developer Tools", "Actor Viewer", DrawActorViewer); -} \ No newline at end of file +} diff --git a/soh/soh/Enhancements/debugger/colViewer.cpp b/soh/soh/Enhancements/debugger/colViewer.cpp index e98ff0399..0146e626f 100644 --- a/soh/soh/Enhancements/debugger/colViewer.cpp +++ b/soh/soh/Enhancements/debugger/colViewer.cpp @@ -1,12 +1,12 @@ #include "colViewer.h" -#include "../libultraship/ImGuiImpl.h" -#include "ImGuiHelpers.h" +#include #include "../../frame_interpolation.h" +#include "../../UIWidgets.hpp" #include #include #include -#include +#include extern "C" { #include @@ -62,42 +62,42 @@ void DrawColViewerWindow(bool& open) { ImGui::End(); return; } - SohImGui::EnhancementCheckbox("Enabled", "gColViewerEnabled"); + UIWidgets::EnhancementCheckbox("Enabled", "gColViewerEnabled"); - SohImGui::EnhancementCombo("Scene", "gColViewerScene", ColRenderSettingNames); - SohImGui::EnhancementCombo("Bg Actors", "gColViewerBgActors", ColRenderSettingNames); - SohImGui::EnhancementCombo("Col Check", "gColViewerColCheck", ColRenderSettingNames); - SohImGui::EnhancementCombo("Waterbox", "gColViewerWaterbox", ColRenderSettingNames); + UIWidgets::EnhancementCombo("Scene", "gColViewerScene", ColRenderSettingNames); + UIWidgets::EnhancementCombo("Bg Actors", "gColViewerBgActors", ColRenderSettingNames); + UIWidgets::EnhancementCombo("Col Check", "gColViewerColCheck", ColRenderSettingNames); + UIWidgets::EnhancementCombo("Waterbox", "gColViewerWaterbox", ColRenderSettingNames); - SohImGui::EnhancementCheckbox("Apply as decal", "gColViewerDecal"); - InsertHelpHoverText("Applies the collision as a decal display. This can be useful if there is z-fighting occuring " + UIWidgets::EnhancementCheckbox("Apply as decal", "gColViewerDecal"); + UIWidgets::InsertHelpHoverText("Applies the collision as a decal display. This can be useful if there is z-fighting occuring " "with the scene geometry, but can cause other artifacts."); - SohImGui::EnhancementCheckbox("Shaded", "gColViewerShaded"); - InsertHelpHoverText("Applies the scene's shading to the collision display."); + UIWidgets::EnhancementCheckbox("Shaded", "gColViewerShaded"); + UIWidgets::InsertHelpHoverText("Applies the scene's shading to the collision display."); // This has to be duplicated in both code paths due to the nature of ImGui::IsItemHovered() const std::string colorHelpText = "View and change the colors used for collision display."; if (ImGui::TreeNode("Colors")) { - InsertHelpHoverText(colorHelpText); + UIWidgets::InsertHelpHoverText(colorHelpText); - SohImGui::EnhancementColor("Normal", "gColViewerColorNormal", scene_col, ImVec4(255, 255, 255, 255), false); - SohImGui::EnhancementColor("Hookshot", "gColViewerColorHookshot", hookshot_col, ImVec4(128, 128, 255, 255), + UIWidgets::EnhancementColor("Normal", "gColViewerColorNormal", scene_col, ImVec4(255, 255, 255, 255), false); + UIWidgets::EnhancementColor("Hookshot", "gColViewerColorHookshot", hookshot_col, ImVec4(128, 128, 255, 255), false); - SohImGui::EnhancementColor("Entrance", "gColViewerColorEntrance", entrance_col, ImVec4(0, 255, 0, 255), false); - SohImGui::EnhancementColor("Special Surface (Grass/Sand/Etc)", "gColViewerColorSpecialSurface", + UIWidgets::EnhancementColor("Entrance", "gColViewerColorEntrance", entrance_col, ImVec4(0, 255, 0, 255), false); + UIWidgets::EnhancementColor("Special Surface (Grass/Sand/Etc)", "gColViewerColorSpecialSurface", specialSurface_col, ImVec4(192, 255, 192, 255), false); - SohImGui::EnhancementColor("Interactable (Vines/Crawlspace/Etc)", "gColViewerColorInteractable", + UIWidgets::EnhancementColor("Interactable (Vines/Crawlspace/Etc)", "gColViewerColorInteractable", interactable_col, ImVec4(192, 0, 192, 255), false); - SohImGui::EnhancementColor("Slope", "gColViewerColorSlope", slope_col, ImVec4(255, 255, 128, 255), false); - SohImGui::EnhancementColor("Void", "gColViewerColorVoid", void_col, ImVec4(255, 0, 0, 255), false); - SohImGui::EnhancementColor("OC", "gColViewerColorOC", oc_col, ImVec4(255, 255, 255, 255), false); - SohImGui::EnhancementColor("AC", "gColViewerColorAC", ac_col, ImVec4(0, 0, 255, 255), false); - SohImGui::EnhancementColor("AT", "gColViewerColorAT", at_col, ImVec4(255, 0, 0, 255), false); - SohImGui::EnhancementColor("Waterbox", "gColViewerColorWaterbox", waterbox_col, ImVec4(0, 0, 255, 255), false); + UIWidgets::EnhancementColor("Slope", "gColViewerColorSlope", slope_col, ImVec4(255, 255, 128, 255), false); + UIWidgets::EnhancementColor("Void", "gColViewerColorVoid", void_col, ImVec4(255, 0, 0, 255), false); + UIWidgets::EnhancementColor("OC", "gColViewerColorOC", oc_col, ImVec4(255, 255, 255, 255), false); + UIWidgets::EnhancementColor("AC", "gColViewerColorAC", ac_col, ImVec4(0, 0, 255, 255), false); + UIWidgets::EnhancementColor("AT", "gColViewerColorAT", at_col, ImVec4(255, 0, 0, 255), false); + UIWidgets::EnhancementColor("Waterbox", "gColViewerColorWaterbox", waterbox_col, ImVec4(0, 0, 255, 255), false); ImGui::TreePop(); } else { - InsertHelpHoverText(colorHelpText); + UIWidgets::InsertHelpHoverText(colorHelpText); } ImGui::End(); diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 174aa63d0..3765f5d6b 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -1,14 +1,14 @@ #include "debugSaveEditor.h" #include "../../util.h" #include "../../OTRGlobals.h" -#include "../libultraship/ImGuiImpl.h" -#include "ImGuiHelpers.h" +#include +#include "../../UIWidgets.hpp" #include #include #include #include -#include +#include extern "C" { #include @@ -311,7 +311,7 @@ void DrawInfoTab() { ImGui::PushItemWidth(ImGui::GetFontSize() * 6); ImGui::Text("Name: %s", name.c_str()); - InsertHelpHoverText("Player Name"); + UIWidgets::InsertHelpHoverText("Player Name"); std::string nameID; for (int i = 0; i < 8; i++) { nameID = z2ASCII(i); @@ -328,7 +328,7 @@ void DrawInfoTab() { if (ImGui::IsItemDeactivated()) { gSaveContext.healthCapacity = healthIntermediary; } - InsertHelpHoverText("Maximum health. 16 units per full heart"); + UIWidgets::InsertHelpHoverText("Maximum health. 16 units per full heart"); if (gSaveContext.health > gSaveContext.healthCapacity) { gSaveContext.health = gSaveContext.healthCapacity; // Clamp health to new max } @@ -337,7 +337,7 @@ void DrawInfoTab() { const uint16_t healthMax = gSaveContext.healthCapacity; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); ImGui::SliderScalar("Health", ImGuiDataType_S16, &gSaveContext.health, &healthMin, &healthMax); - InsertHelpHoverText("Current health. 16 units per full heart"); + UIWidgets::InsertHelpHoverText("Current health. 16 units per full heart"); bool doubleDefense = gSaveContext.doubleDefense != 0; if (ImGui::Checkbox("Double Defense", &doubleDefense)) { @@ -345,7 +345,7 @@ void DrawInfoTab() { gSaveContext.inventory.defenseHearts = gSaveContext.doubleDefense ? 20 : 0; // Set to get the border drawn in the UI } - InsertHelpHoverText("Is double defense unlocked?"); + UIWidgets::InsertHelpHoverText("Is double defense unlocked?"); std::string magicName; if (gSaveContext.magicLevel == 2) { @@ -375,7 +375,7 @@ void DrawInfoTab() { ImGui::EndCombo(); } - InsertHelpHoverText("Current magic level"); + UIWidgets::InsertHelpHoverText("Current magic level"); gSaveContext.unk_13F4 = gSaveContext.magicLevel * 0x30; // Set to get the bar drawn in the UI if (gSaveContext.magic > gSaveContext.unk_13F4) { gSaveContext.magic = gSaveContext.unk_13F4; // Clamp magic to new max @@ -385,16 +385,16 @@ void DrawInfoTab() { const uint8_t magicMax = gSaveContext.unk_13F4; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); ImGui::SliderScalar("Magic", ImGuiDataType_S8, &gSaveContext.magic, &magicMin, &magicMax); - InsertHelpHoverText("Current magic. 48 units per magic level"); + UIWidgets::InsertHelpHoverText("Current magic. 48 units per magic level"); ImGui::InputScalar("Rupees", ImGuiDataType_S16, &gSaveContext.rupees); - InsertHelpHoverText("Current rupees"); + UIWidgets::InsertHelpHoverText("Current rupees"); const uint16_t dayTimeMin = 0; const uint16_t dayTimeMax = 0xFFFF; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); ImGui::SliderScalar("Time", ImGuiDataType_U16, &gSaveContext.dayTime, &dayTimeMin, &dayTimeMax); - InsertHelpHoverText("Time of day"); + UIWidgets::InsertHelpHoverText("Time of day"); if (ImGui::Button("Dawn")) { gSaveContext.dayTime = 0x4000; } @@ -412,43 +412,43 @@ void DrawInfoTab() { } ImGui::InputScalar("Total Days", ImGuiDataType_S32, &gSaveContext.totalDays); - InsertHelpHoverText("Total number of days elapsed since the start of the game"); + UIWidgets::InsertHelpHoverText("Total number of days elapsed since the start of the game"); ImGui::InputScalar("Deaths", ImGuiDataType_U16, &gSaveContext.deaths); - InsertHelpHoverText("Total number of deaths"); + UIWidgets::InsertHelpHoverText("Total number of deaths"); bool bgsFlag = gSaveContext.bgsFlag != 0; if (ImGui::Checkbox("Has BGS", &bgsFlag)) { gSaveContext.bgsFlag = bgsFlag; } - InsertHelpHoverText("Is Biggoron sword unlocked? Replaces Giant's knife"); + UIWidgets::InsertHelpHoverText("Is Biggoron sword unlocked? Replaces Giant's knife"); ImGui::InputScalar("Sword Health", ImGuiDataType_U16, &gSaveContext.swordHealth); - InsertHelpHoverText("Giant's knife health. Default is 8. Must be >0 for Biggoron sword to work"); + UIWidgets::InsertHelpHoverText("Giant's knife health. Default is 8. Must be >0 for Biggoron sword to work"); ImGui::InputScalar("Bgs Day Count", ImGuiDataType_S32, &gSaveContext.bgsDayCount); - InsertHelpHoverText("Total number of days elapsed since giving Biggoron the claim check"); + UIWidgets::InsertHelpHoverText("Total number of days elapsed since giving Biggoron the claim check"); ImGui::InputScalar("Entrance Index", ImGuiDataType_S32, &gSaveContext.entranceIndex); - InsertHelpHoverText("From which entrance did Link arrive?"); + UIWidgets::InsertHelpHoverText("From which entrance did Link arrive?"); ImGui::InputScalar("Cutscene Index", ImGuiDataType_S32, &gSaveContext.cutsceneIndex); - InsertHelpHoverText("Which cutscene is this?"); + UIWidgets::InsertHelpHoverText("Which cutscene is this?"); ImGui::InputScalar("Navi Timer", ImGuiDataType_U16, &gSaveContext.naviTimer); - InsertHelpHoverText("Navi wants to talk at 600 units, decides not to at 3000."); + UIWidgets::InsertHelpHoverText("Navi wants to talk at 600 units, decides not to at 3000."); ImGui::InputScalar("Timer 1 State", ImGuiDataType_S16, &gSaveContext.timer1State); - InsertHelpHoverText("Heat timer, race timer, etc. Has white font"); + UIWidgets::InsertHelpHoverText("Heat timer, race timer, etc. Has white font"); ImGui::InputScalar("Timer 1 Value", ImGuiDataType_S16, &gSaveContext.timer1Value, &one, NULL); - InsertHelpHoverText("Time, in seconds"); + UIWidgets::InsertHelpHoverText("Time, in seconds"); ImGui::InputScalar("Timer 2 State", ImGuiDataType_S16, &gSaveContext.timer2State); - InsertHelpHoverText("Trade timer, Ganon collapse timer, etc. Has yellow font"); + UIWidgets::InsertHelpHoverText("Trade timer, Ganon collapse timer, etc. Has yellow font"); ImGui::InputScalar("Timer 2 Value", ImGuiDataType_S16, &gSaveContext.timer2Value, &one, NULL); - InsertHelpHoverText("Time, in seconds"); + UIWidgets::InsertHelpHoverText("Time, in seconds"); const char* audioName; switch (gSaveContext.audioSetting) { @@ -483,13 +483,13 @@ void DrawInfoTab() { ImGui::EndCombo(); } - InsertHelpHoverText("Sound setting"); + UIWidgets::InsertHelpHoverText("Sound setting"); bool n64DDFlag = gSaveContext.n64ddFlag != 0; if (ImGui::Checkbox("64 DD file?", &n64DDFlag)) { gSaveContext.n64ddFlag = n64DDFlag; } - InsertHelpHoverText("WARNING! If you save, your file may be locked! Use caution!"); + UIWidgets::InsertHelpHoverText("WARNING! If you save, your file may be locked! Use caution!"); if (ImGui::BeginCombo("Z Target Mode", gSaveContext.zTargetSetting ? "Hold" : "Switch")) { if (ImGui::Selectable("Switch")) { @@ -500,7 +500,7 @@ void DrawInfoTab() { } ImGui::EndCombo(); } - InsertHelpHoverText("Z-Targeting behavior"); + UIWidgets::InsertHelpHoverText("Z-Targeting behavior"); ImGui::PushItemWidth(ImGui::GetFontSize() * 10); @@ -552,7 +552,7 @@ void DrawInventoryTab() { static bool restrictToValid = true; ImGui::Checkbox("Restrict to valid items", &restrictToValid); - InsertHelpHoverText("Restricts items and ammo to only what is possible to legally acquire in-game"); + UIWidgets::InsertHelpHoverText("Restricts items and ammo to only what is possible to legally acquire in-game"); for (int32_t y = 0; y < 4; y++) { for (int32_t x = 0; x < 6; x++) { @@ -594,7 +594,7 @@ void DrawInventoryTab() { } ImGui::CloseCurrentPopup(); } - SetLastItemHoverText("None"); + UIWidgets::SetLastItemHoverText("None"); std::vector possibleItems; if (restrictToValid) { @@ -624,14 +624,14 @@ void DrawInventoryTab() { gSaveContext.inventory.items[selectedIndex] = slotEntry.id; // Set adult trade item flag if you're playing adult trade shuffle in rando if (gSaveContext.n64ddFlag && - OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE); + OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) && selectedIndex == SLOT_TRADE_ADULT && slotEntry.id >= ITEM_POCKET_EGG && slotEntry.id <= ITEM_CLAIM_CHECK) { gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id); } ImGui::CloseCurrentPopup(); } - SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id)); } ImGui::EndPopup(); @@ -725,7 +725,7 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Switch"); - InsertHelpHoverText("Permanently-saved switch flags"); + UIWidgets::InsertHelpHoverText("Permanently-saved switch flags"); DrawFlagArray32("Switch", act->flags.swch); }); @@ -733,13 +733,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Temp Switch"); - InsertHelpHoverText("Temporary switch flags. Unset on scene transitions"); + UIWidgets::InsertHelpHoverText("Temporary switch flags. Unset on scene transitions"); DrawFlagArray32("Temp Switch", act->flags.tempSwch); }); DrawGroupWithBorder([&]() { ImGui::Text("Clear"); - InsertHelpHoverText("Permanently-saved room-clear flags"); + UIWidgets::InsertHelpHoverText("Permanently-saved room-clear flags"); DrawFlagArray32("Clear", act->flags.clear); }); @@ -747,13 +747,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Temp Clear"); - InsertHelpHoverText("Temporary room-clear flags. Unset on scene transitions"); + UIWidgets::InsertHelpHoverText("Temporary room-clear flags. Unset on scene transitions"); DrawFlagArray32("Temp Clear", act->flags.tempClear); }); DrawGroupWithBorder([&]() { ImGui::Text("Collect"); - InsertHelpHoverText("Permanently-saved collect flags"); + UIWidgets::InsertHelpHoverText("Permanently-saved collect flags"); DrawFlagArray32("Collect", act->flags.collect); }); @@ -761,13 +761,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Temp Collect"); - InsertHelpHoverText("Temporary collect flags. Unset on scene transitions"); + UIWidgets::InsertHelpHoverText("Temporary collect flags. Unset on scene transitions"); DrawFlagArray32("Temp Collect", act->flags.tempCollect); }); DrawGroupWithBorder([&]() { ImGui::Text("Chest"); - InsertHelpHoverText("Permanently-saved chest flags"); + UIWidgets::InsertHelpHoverText("Permanently-saved chest flags"); DrawFlagArray32("Chest", act->flags.chest); }); @@ -781,7 +781,7 @@ void DrawFlagsTab() { act->flags.collect = gSaveContext.sceneFlags[gGlobalCtx->sceneNum].collect; act->flags.chest = gSaveContext.sceneFlags[gGlobalCtx->sceneNum].chest; } - SetLastItemHoverText("Load flags from saved scene flags. Normally happens on scene load"); + UIWidgets::SetLastItemHoverText("Load flags from saved scene flags. Normally happens on scene load"); if (ImGui::Button("Save Flags")) { gSaveContext.sceneFlags[gGlobalCtx->sceneNum].swch = act->flags.swch; @@ -789,7 +789,7 @@ void DrawFlagsTab() { gSaveContext.sceneFlags[gGlobalCtx->sceneNum].collect = act->flags.collect; gSaveContext.sceneFlags[gGlobalCtx->sceneNum].chest = act->flags.chest; } - SetLastItemHoverText("Save current scene flags. Normally happens on scene exit"); + UIWidgets::SetLastItemHoverText("Save current scene flags. Normally happens on scene exit"); ImGui::EndGroup(); } else { @@ -819,12 +819,12 @@ void DrawFlagsTab() { if (ImGui::Button("Current")) { selectedSceneFlagMap = gGlobalCtx->sceneNum; } - SetLastItemHoverText("Open flags for current scene"); + UIWidgets::SetLastItemHoverText("Open flags for current scene"); } DrawGroupWithBorder([&]() { ImGui::Text("Switch"); - InsertHelpHoverText("Switch flags"); + UIWidgets::InsertHelpHoverText("Switch flags"); DrawFlagArray32("Switch", gSaveContext.sceneFlags[selectedSceneFlagMap].swch); }); @@ -832,13 +832,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Clear"); - InsertHelpHoverText("Room-clear flags"); + UIWidgets::InsertHelpHoverText("Room-clear flags"); DrawFlagArray32("Clear", gSaveContext.sceneFlags[selectedSceneFlagMap].clear); }); DrawGroupWithBorder([&]() { ImGui::Text("Collect"); - InsertHelpHoverText("Collect flags"); + UIWidgets::InsertHelpHoverText("Collect flags"); DrawFlagArray32("Collect", gSaveContext.sceneFlags[selectedSceneFlagMap].collect); }); @@ -846,13 +846,13 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Chest"); - InsertHelpHoverText("Chest flags"); + UIWidgets::InsertHelpHoverText("Chest flags"); DrawFlagArray32("Chest", gSaveContext.sceneFlags[selectedSceneFlagMap].chest); }); DrawGroupWithBorder([&]() { ImGui::Text("Rooms"); - InsertHelpHoverText("Flags for visted rooms"); + UIWidgets::InsertHelpHoverText("Flags for visted rooms"); DrawFlagArray32("Rooms", gSaveContext.sceneFlags[selectedSceneFlagMap].rooms); }); @@ -860,7 +860,7 @@ void DrawFlagsTab() { DrawGroupWithBorder([&]() { ImGui::Text("Floors"); - InsertHelpHoverText("Flags for visted floors"); + UIWidgets::InsertHelpHoverText("Flags for visted floors"); DrawFlagArray32("Floors", gSaveContext.sceneFlags[selectedSceneFlagMap].floors); }); @@ -916,7 +916,7 @@ void DrawFlagsTab() { if (!(gSaveContext.n64ddFlag && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_TOKENS))) { static bool keepGsCountUpdated = true; ImGui::Checkbox("Keep GS Count Updated", &keepGsCountUpdated); - InsertHelpHoverText("Automatically adjust the number of gold skulltula tokens acquired based on set flags."); + UIWidgets::InsertHelpHoverText("Automatically adjust the number of gold skulltula tokens acquired based on set flags."); int32_t gsCount = 0; if (keepGsCountUpdated) { for (int32_t gsFlagIndex = 0; gsFlagIndex < 6; gsFlagIndex++) { @@ -930,85 +930,85 @@ void DrawFlagsTab() { if (ImGui::TreeNode("Event Check Inf Flags")) { DrawGroupWithBorder([&]() { ImGui::Text("0"); - InsertHelpHoverText("Mostly Kokiri Forest related"); + UIWidgets::InsertHelpHoverText("Mostly Kokiri Forest related"); DrawFlagArray16("eci0", gSaveContext.eventChkInf[0]); }); DrawGroupWithBorder([&]() { ImGui::Text("1"); - InsertHelpHoverText("Mostly Lon Lon Ranch related"); + UIWidgets::InsertHelpHoverText("Mostly Lon Lon Ranch related"); DrawFlagArray16("eci1", gSaveContext.eventChkInf[1]); }); DrawGroupWithBorder([&]() { ImGui::Text("2"); - InsertHelpHoverText("Dodongo Related?"); + UIWidgets::InsertHelpHoverText("Dodongo Related?"); DrawFlagArray16("eci2", gSaveContext.eventChkInf[2]); }); DrawGroupWithBorder([&]() { ImGui::Text("3"); - InsertHelpHoverText("Mostly Zora related"); + UIWidgets::InsertHelpHoverText("Mostly Zora related"); DrawFlagArray16("eci3", gSaveContext.eventChkInf[3]); }); DrawGroupWithBorder([&]() { ImGui::Text("4"); - InsertHelpHoverText("Random"); + UIWidgets::InsertHelpHoverText("Random"); DrawFlagArray16("eci4", gSaveContext.eventChkInf[4]); }); DrawGroupWithBorder([&]() { ImGui::Text("5"); - InsertHelpHoverText("Mostly song learning related"); + UIWidgets::InsertHelpHoverText("Mostly song learning related"); DrawFlagArray16("eci5", gSaveContext.eventChkInf[5]); }); DrawGroupWithBorder([&]() { ImGui::Text("6"); - InsertHelpHoverText("Random"); + UIWidgets::InsertHelpHoverText("Random"); DrawFlagArray16("eci6", gSaveContext.eventChkInf[6]); }); DrawGroupWithBorder([&]() { ImGui::Text("7"); - InsertHelpHoverText("Boss Battle related"); + UIWidgets::InsertHelpHoverText("Boss Battle related"); DrawFlagArray16("eci7", gSaveContext.eventChkInf[7]); }); DrawGroupWithBorder([&]() { ImGui::Text("8"); - InsertHelpHoverText("Mask related?"); + UIWidgets::InsertHelpHoverText("Mask related?"); DrawFlagArray16("eci8", gSaveContext.eventChkInf[8]); }); DrawGroupWithBorder([&]() { ImGui::Text("9"); - InsertHelpHoverText("Mostly carpenter related"); + UIWidgets::InsertHelpHoverText("Mostly carpenter related"); DrawFlagArray16("eci9", gSaveContext.eventChkInf[9]); }); DrawGroupWithBorder([&]() { ImGui::Text("A"); - InsertHelpHoverText("First-time overworld entrance cs related"); + UIWidgets::InsertHelpHoverText("First-time overworld entrance cs related"); DrawFlagArray16("eci10", gSaveContext.eventChkInf[10]); }); DrawGroupWithBorder([&]() { ImGui::Text("B"); - InsertHelpHoverText("First-time dungeon entrance cs/trial cs related"); + UIWidgets::InsertHelpHoverText("First-time dungeon entrance cs/trial cs related"); DrawFlagArray16("eci11", gSaveContext.eventChkInf[11]); }); DrawGroupWithBorder([&]() { ImGui::Text("C"); - InsertHelpHoverText("Random"); + UIWidgets::InsertHelpHoverText("Random"); DrawFlagArray16("eci12", gSaveContext.eventChkInf[12]); }); DrawGroupWithBorder([&]() { ImGui::Text("D"); - InsertHelpHoverText("Frog songs/GS rewards"); + UIWidgets::InsertHelpHoverText("Frog songs/GS rewards"); DrawFlagArray16("eci13", gSaveContext.eventChkInf[13]); }); @@ -1061,7 +1061,7 @@ void DrawUpgrade(const std::string& categoryName, int32_t categoryId, const std: ImGui::EndCombo(); } ImGui::PopID(); - SetLastItemHoverText(categoryName.c_str()); + UIWidgets::SetLastItemHoverText(categoryName.c_str()); } // Draws a combo that lets you choose and upgrade value from a popup grid of icons @@ -1086,7 +1086,7 @@ void DrawUpgradeIcon(const std::string& categoryName, int32_t categoryId, const } ImGui::PopStyleVar(); ImGui::PopStyleColor(); - SetLastItemHoverText(categoryName.c_str()); + UIWidgets::SetLastItemHoverText(categoryName.c_str()); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); if (ImGui::BeginPopup(upgradePopupPicker)) { @@ -1100,7 +1100,7 @@ void DrawUpgradeIcon(const std::string& categoryName, int32_t categoryId, const Inventory_ChangeUpgrade(categoryId, pickerIndex); ImGui::CloseCurrentPopup(); } - SetLastItemHoverText("None"); + UIWidgets::SetLastItemHoverText("None"); } else { const ItemMapEntry& slotEntry = itemMapping[items[pickerIndex]]; if (ImGui::ImageButton(SohImGui::GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), @@ -1108,7 +1108,7 @@ void DrawUpgradeIcon(const std::string& categoryName, int32_t categoryId, const Inventory_ChangeUpgrade(categoryId, pickerIndex); ImGui::CloseCurrentPopup(); } - SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(slotEntry.id)); } } @@ -1150,7 +1150,7 @@ void DrawEquipmentTab() { } ImGui::PopStyleColor(); ImGui::PopID(); - SetLastItemHoverText(SohUtils::GetItemName(entry.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(entry.id)); } const std::vector bulletBagValues = { @@ -1240,7 +1240,7 @@ void DrawQuestItemButton(uint32_t item) { } } ImGui::PopStyleColor(); - SetLastItemHoverText(SohUtils::GetQuestItemName(entry.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(entry.id)); } // Draws a toggleable icon for a dungeon item that is faded when disabled @@ -1258,7 +1258,7 @@ void DrawDungeonItemButton(uint32_t item, uint32_t scene) { } } ImGui::PopStyleColor(); - SetLastItemHoverText(SohUtils::GetItemName(entry.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(entry.id)); } void DrawQuestStatusTab() { @@ -1305,11 +1305,11 @@ void DrawQuestStatusTab() { } } ImGui::PopStyleColor(); - SetLastItemHoverText(SohUtils::GetQuestItemName(entry.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(entry.id)); } ImGui::InputScalar("GS Count", ImGuiDataType_S16, &gSaveContext.inventory.gsTokens); - InsertHelpHoverText("Number of gold skulltula tokens aquired"); + UIWidgets::InsertHelpHoverText("Number of gold skulltula tokens aquired"); uint32_t bitMask = 1 << QUEST_SKULL_TOKEN; bool gsUnlocked = (bitMask & gSaveContext.inventory.questItems) != 0; @@ -1320,7 +1320,7 @@ void DrawQuestStatusTab() { gSaveContext.inventory.questItems &= ~bitMask; } } - InsertHelpHoverText("If unlocked, enables showing the gold skulltula count in the quest status menu"); + UIWidgets::InsertHelpHoverText("If unlocked, enables showing the gold skulltula count in the quest status menu"); int32_t pohCount = (gSaveContext.inventory.questItems & 0xF0000000) >> 28; if (ImGui::BeginCombo("PoH count", std::to_string(pohCount).c_str())) { @@ -1332,7 +1332,7 @@ void DrawQuestStatusTab() { } ImGui::EndCombo(); } - InsertHelpHoverText("The number of pieces of heart acquired towards the next heart container"); + UIWidgets::InsertHelpHoverText("The number of pieces of heart acquired towards the next heart container"); DrawGroupWithBorder([&]() { ImGui::Text("Dungeon Items"); @@ -1457,7 +1457,7 @@ void DrawPlayerTab() { DrawGroupWithBorder([&]() { ImGui::Text("Link's Rotation"); - InsertHelpHoverText("For Link's rotation in relation to the world"); + UIWidgets::InsertHelpHoverText("For Link's rotation in relation to the world"); ImGui::InputScalar("X Rot", ImGuiDataType_S16, &player->actor.world.rot.x); ImGui::SameLine(); ImGui::InputScalar("Y Rot", ImGuiDataType_S16, &player->actor.world.rot.y); @@ -1467,7 +1467,7 @@ void DrawPlayerTab() { DrawGroupWithBorder([&]() { ImGui::Text("Link's Model Rotation"); - InsertHelpHoverText("For Link's actual model"); + UIWidgets::InsertHelpHoverText("For Link's actual model"); ImGui::InputScalar("X ModRot", ImGuiDataType_S16, &player->actor.shape.rot.x); ImGui::SameLine(); ImGui::InputScalar("Y ModRot", ImGuiDataType_S16, &player->actor.shape.rot.y); @@ -1476,19 +1476,19 @@ void DrawPlayerTab() { }); ImGui::InputScalar("Linear Velocity", ImGuiDataType_Float, &player->linearVelocity); - InsertHelpHoverText("Link's speed along the XZ plane"); + UIWidgets::InsertHelpHoverText("Link's speed along the XZ plane"); ImGui::InputScalar("Y Velocity", ImGuiDataType_Float, &player->actor.velocity.y); - InsertHelpHoverText("Link's speed along the Y plane. Caps at -20"); + UIWidgets::InsertHelpHoverText("Link's speed along the Y plane. Caps at -20"); ImGui::InputScalar("Wall Height", ImGuiDataType_Float, &player->wallHeight); - InsertHelpHoverText("Height used to determine whether Link can climb or grab a ledge at the top"); + UIWidgets::InsertHelpHoverText("Height used to determine whether Link can climb or grab a ledge at the top"); ImGui::InputScalar("Invincibility Timer", ImGuiDataType_S8, &player->invincibilityTimer); - InsertHelpHoverText("Can't take damage while this is nonzero"); + UIWidgets::InsertHelpHoverText("Can't take damage while this is nonzero"); ImGui::InputScalar("Gravity", ImGuiDataType_Float, &player->actor.gravity); - InsertHelpHoverText("Rate at which Link falls. Default -4.0f"); + UIWidgets::InsertHelpHoverText("Rate at which Link falls. Default -4.0f"); if (ImGui::BeginCombo("Link Age on Load", gGlobalCtx->linkAgeOnLoad == 0 ? "Adult" : "Child")) { if (ImGui::Selectable("Adult")) { @@ -1500,7 +1500,7 @@ void DrawPlayerTab() { ImGui::EndCombo(); } - InsertHelpHoverText("This will change Link's age when you load a map"); + UIWidgets::InsertHelpHoverText("This will change Link's age when you load a map"); ImGui::Separator(); diff --git a/soh/soh/Enhancements/gameconsole.h b/soh/soh/Enhancements/gameconsole.h index 33301afe6..27838ff63 100644 --- a/soh/soh/Enhancements/gameconsole.h +++ b/soh/soh/Enhancements/gameconsole.h @@ -3,7 +3,7 @@ #include #include -#include "Cvar.h" +#include #define MAX_CVARS 2048 @@ -39,4 +39,4 @@ s32 GameConsole_Split(char* str, char** argv); } #endif -#endif \ No newline at end of file +#endif diff --git a/soh/soh/Enhancements/randomizer/3drando/entrance.cpp b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp index 144759e29..549624760 100644 --- a/soh/soh/Enhancements/randomizer/3drando/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include std::list entranceOverrides = {}; bool noRandomEntrances = false; diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index e23f9633d..cbd636022 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -17,7 +17,7 @@ #include #include -#include +#include using namespace CustomMessages; using namespace Logic; diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp index 4c18524fc..b5f0743fb 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hints.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -12,7 +12,7 @@ #include "trial.hpp" #include "entrance.hpp" #include "z64item.h" -#include +#include using namespace CustomMessages; using namespace Logic; diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp index 0a4405c78..bfe04eb82 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -6,7 +6,7 @@ #include "shops.hpp" #include "debug.hpp" #include "keys.hpp" -#include +#include #include "../randomizerTypes.h" //Location definitions @@ -1638,4 +1638,4 @@ void CreateItemOverrides() { } SPDLOG_DEBUG("Overrides Created: "); SPDLOG_DEBUG(std::to_string(overrides.size())); -} \ No newline at end of file +} diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index ec03a0ebd..d6676fa6c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -9,7 +9,7 @@ #include "settings.hpp" #include "spoiler_log.hpp" #include "z64item.h" -#include +#include using namespace Settings; diff --git a/soh/soh/Enhancements/randomizer/3drando/menu.cpp b/soh/soh/Enhancements/randomizer/3drando/menu.cpp index 4f0d7b7d5..781dbead7 100644 --- a/soh/soh/Enhancements/randomizer/3drando/menu.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/menu.cpp @@ -13,8 +13,8 @@ #include "spoiler_log.hpp" #include "location_access.hpp" #include "debug.hpp" -#include -#include "soh/Enhancements/randomizer/randomizerTypes.h" +#include +#include "../../randomizer/randomizerTypes.h" namespace { bool seedChanged; @@ -547,4 +547,4 @@ std::string GenerateRandomizer(std::unordered_map std::string GetInput(const char* hintText) { return std::string(); -} \ No newline at end of file +} diff --git a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp index da91fcd9b..7495adf66 100644 --- a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp @@ -5,9 +5,9 @@ #include "location_access.hpp" #include "rando_main.hpp" // #include -#include -#include -#include +#include +#include +#include #define TICKS_PER_SEC 268123480.0 diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 487902acb..1fabb8b4f 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2600,6 +2600,8 @@ namespace Settings { NightGSExpectSuns.SetSelectedIndex(cvarSettings[RSK_SKULLS_SUNS_SONG]); + LinksPocketItem.SetSelectedIndex(cvarSettings[RSK_LINKS_POCKET]); + // RANDOTODO implement chest shuffle with keysanity // ShuffleChestMinigame.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 63230c2d1..09f98f6ce 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -11,7 +11,7 @@ #include "utils.hpp" #include "shops.hpp" #include "hints.hpp" -#include "Lib/nlohmann/json.hpp" +#include #include #include @@ -26,7 +26,7 @@ #include #include -#include "Window.h" +#include using json = nlohmann::json; @@ -780,4 +780,4 @@ bool PlacementLog_Write() { contentNode->SetCData(true); return true; -} \ No newline at end of file +} diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index f859634a9..760d0e2f8 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1,21 +1,21 @@ #include "randomizer.h" -#include "Lib/nlohmann/json.hpp" +#include #include "3drando/settings.hpp" #include #include #include #include #include -#include +#include #include #include -#include "../libultraship/ImGuiImpl.h" +#include #include #include "3drando/rando_main.hpp" -#include -#include "Lib/ImGui/imgui_internal.h" -#include -#include +#include "../../UIWidgets.hpp" +#include +#include "../custom-message/CustomMessageTypes.h" +#include "../item-tables/ItemTableManager.h" #include #include "randomizer_check_objects.h" #include @@ -567,12 +567,13 @@ std::unordered_map SpoilerfileSettingNameToEn { "Open Settings:Token Count", RSK_RAINBOW_BRIDGE_TOKEN_COUNT }, { "Open Settings:Random Ganon's Trials", RSK_RANDOM_TRIALS }, { "Open Settings:Trial Count", RSK_TRIAL_COUNT }, + { "Shuffle Settings:Link's Pocket", RSK_LINKS_POCKET}, { "Shuffle Settings:Shuffle Gerudo Card", RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD }, { "Shuffle Settings:Scrub Shuffle", RSK_SHUFFLE_SCRUBS }, { "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS }, { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, - { "Shuffle Settings:Shuffle Magic Beans", RSK_SHUFFLE_MAGIC_BEANS}, + { "Shuffle Settings:Shuffle Magic Beans", RSK_SHUFFLE_MAGIC_BEANS }, { "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD }, { "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD }, { "Start with Fairy Ocarina", RSK_STARTING_OCARINA }, @@ -973,6 +974,17 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { gSaveContext.randoSettings[index].value = 3; } break; + case RSK_LINKS_POCKET: + if (it.value() == "Dungeon Reward") { + gSaveContext.randoSettings[index].value = 0; + } else if (it.value() == "Advancement") { + gSaveContext.randoSettings[index].value = 1; + } else if (it.value() == "Anything") { + gSaveContext.randoSettings[index].value = 2; + } else if (it.value() == "Nothing") { + gSaveContext.randoSettings[index].value = 3; + } + break; } index++; } @@ -1140,6 +1152,8 @@ void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { return; } + this->trialsRequired.clear(); + try { json spoilerFileJson; spoilerFileStream >> spoilerFileJson; @@ -1207,87 +1221,556 @@ bool Randomizer::IsTrialRequired(RandomizerInf trial) { return this->trialsRequired.contains(trial); } -s16 Randomizer::GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { - s16 itemId = GetItemFromActor(actorId, actorParams, sceneNum, ogId); - return itemId; +RandomizerGet Randomizer::GetRandomizerGetFromActor(s16 actorId, s16 sceneNum, s16 actorParams) { + return this->itemLocations[GetCheckFromActor(actorId, sceneNum, actorParams)]; } -s16 Randomizer::GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId) { - return GetItemFromGet(this->itemLocations[GetCheckFromActor(sceneNum, actorId, actorParams)], ogItemId); +RandomizerGet Randomizer::GetRandomizerGetFromKnownCheck(RandomizerCheck randomizerCheck) { + return this->itemLocations[randomizerCheck]; } -s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { +GetItemID Randomizer::GetItemIdFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogItemId) { + return GetItemIdFromRandomizerGet(GetRandomizerGetFromActor(actorId, sceneNum, actorParams), ogItemId); +} + +ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerCheck(RandomizerCheck randomizerCheck) { + return GetItemObtainabilityFromRandomizerGet(GetRandomizerGetFromKnownCheck(randomizerCheck)); +} + +ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGet randoGet) { + switch (randoGet) { + case RG_NONE: + case RG_TRIFORCE: + case RG_HINT: + case RG_MAX: + case RG_SOLD_OUT: + // TODO: Implement key rings + case RG_FOREST_TEMPLE_KEY_RING: + case RG_FIRE_TEMPLE_KEY_RING: + case RG_WATER_TEMPLE_KEY_RING: + case RG_SPIRIT_TEMPLE_KEY_RING: + case RG_SHADOW_TEMPLE_KEY_RING: + case RG_BOTTOM_OF_THE_WELL_KEY_RING: + case RG_GERUDO_TRAINING_GROUNDS_KEY_RING: + case RG_GERUDO_FORTRESS_KEY_RING: + case RG_GANONS_CASTLE_KEY_RING: + return CANT_OBTAIN_MISC; + + // Equipment + case RG_KOKIRI_SWORD: + return !CHECK_OWNED_EQUIP(EQUIP_SWORD, 0) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BIGGORON_SWORD: + return !gSaveContext.bgsFlag ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DEKU_SHIELD: + case RG_BUY_DEKU_SHIELD: + return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 0) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_HYLIAN_SHIELD: + case RG_BUY_HYLIAN_SHIELD: + return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MIRROR_SHIELD: + return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 2) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GORON_TUNIC: + case RG_BUY_GORON_TUNIC: + return !CHECK_OWNED_EQUIP(EQUIP_TUNIC, 1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ZORA_TUNIC: + case RG_BUY_ZORA_TUNIC: + return !CHECK_OWNED_EQUIP(EQUIP_TUNIC, 2) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_IRON_BOOTS: + return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_HOVER_BOOTS: + return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 2) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Inventory Items + case RG_PROGRESSIVE_STICK_UPGRADE: + return CUR_UPG_VALUE(UPG_STICKS) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_NUT_UPGRADE: + return CUR_UPG_VALUE(UPG_NUTS) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_BOMB_BAG: + return CUR_UPG_VALUE(UPG_BOMB_BAG) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOMBS_5: + case RG_BOMBS_10: + case RG_BOMBS_20: + case RG_BUY_BOMBS_525: + case RG_BUY_BOMBS_535: + case RG_BUY_BOMBS_10: + case RG_BUY_BOMBS_20: + case RG_BUY_BOMBS_30: + return CUR_UPG_VALUE(UPG_BOMB_BAG) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_BOW: + return CUR_UPG_VALUE(UPG_QUIVER) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ARROWS_5: + case RG_ARROWS_10: + case RG_ARROWS_30: + case RG_BUY_ARROWS_10: + case RG_BUY_ARROWS_30: + case RG_BUY_ARROWS_50: + return CUR_UPG_VALUE(UPG_QUIVER) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_SLINGSHOT: + return CUR_UPG_VALUE(UPG_BULLET_BAG) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DEKU_SEEDS_30: + case RG_BUY_DEKU_SEEDS_30: + return CUR_UPG_VALUE(UPG_BULLET_BAG) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_OCARINA: + switch (INV_CONTENT(ITEM_OCARINA_FAIRY)) { + case ITEM_NONE: + case ITEM_OCARINA_FAIRY: + return CAN_OBTAIN; + case ITEM_OCARINA_TIME: + default: + return CANT_OBTAIN_ALREADY_HAVE; + } + case RG_BOMBCHU_5: + case RG_BOMBCHU_10: + case RG_BOMBCHU_20: + case RG_PROGRESSIVE_BOMBCHUS: + return CAN_OBTAIN; + case RG_BUY_BOMBCHU_10: + case RG_BUY_BOMBCHU_20: + case RG_BUY_BOMBCHU_5: + // If Bombchus aren't in logic, you need a bomb bag to purchase them + // If they are in logic, you need to have already obtained them somewhere else + if (GetRandoSettingValue(RSK_BOMBCHUS_IN_LOGIC)) { + return INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + } else { + return CUR_UPG_VALUE(UPG_BOMB_BAG) ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + } + case RG_BOMBCHU_DROP: + return INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU ? CAN_OBTAIN : CANT_OBTAIN_NEED_UPGRADE; + case RG_PROGRESSIVE_HOOKSHOT: + switch (INV_CONTENT(ITEM_HOOKSHOT)) { + case ITEM_NONE: + case ITEM_HOOKSHOT: + return CAN_OBTAIN; + case ITEM_LONGSHOT: + default: + return CANT_OBTAIN_ALREADY_HAVE; + } + case RG_BOOMERANG: + return INV_CONTENT(ITEM_BOOMERANG) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_LENS_OF_TRUTH: + return INV_CONTENT(ITEM_LENS) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MAGIC_BEAN: + case RG_MAGIC_BEAN_PACK: + return BEANS_BOUGHT < 10 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MEGATON_HAMMER: + return INV_CONTENT(ITEM_HAMMER) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_ARROWS: + return INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ICE_ARROWS: + return INV_CONTENT(ITEM_ARROW_ICE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_LIGHT_ARROWS: + return INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DINS_FIRE: + return INV_CONTENT(ITEM_DINS_FIRE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FARORES_WIND: + return INV_CONTENT(ITEM_FARORES_WIND) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_NAYRUS_LOVE: + return INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Bottles + case RG_EMPTY_BOTTLE: + case RG_BOTTLE_WITH_MILK: + case RG_BOTTLE_WITH_RED_POTION: + case RG_BOTTLE_WITH_GREEN_POTION: + case RG_BOTTLE_WITH_BLUE_POTION: + case RG_BOTTLE_WITH_FAIRY: + case RG_BOTTLE_WITH_FISH: + case RG_BOTTLE_WITH_BLUE_FIRE: + case RG_BOTTLE_WITH_BUGS: + case RG_BOTTLE_WITH_POE: + case RG_RUTOS_LETTER: + case RG_BOTTLE_WITH_BIG_POE: + return Inventory_HasEmptyBottleSlot() ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Bottle Refills + case RG_MILK: + case RG_RED_POTION_REFILL: + case RG_GREEN_POTION_REFILL: + case RG_BLUE_POTION_REFILL: + case RG_BUY_FISH: + case RG_BUY_RED_POTION_30: + case RG_BUY_GREEN_POTION: + case RG_BUY_BLUE_POTION: + case RG_BUY_BLUE_FIRE: + case RG_BUY_BOTTLE_BUG: + case RG_BUY_POE: + case RG_BUY_FAIRYS_SPIRIT: + case RG_BUY_RED_POTION_40: + case RG_BUY_RED_POTION_50: + return Inventory_HasEmptyBottle() ? CAN_OBTAIN : CANT_OBTAIN_NEED_EMPTY_BOTTLE; + + // Trade Items + // TODO: Do we want to be strict about any of this? + // case RG_WEIRD_EGG: + // case RG_ZELDAS_LETTER: + // case RG_POCKET_EGG: + // case RG_COJIRO: + // case RG_ODD_MUSHROOM: + // case RG_ODD_POTION: + // case RG_POACHERS_SAW: + // case RG_BROKEN_SWORD: + // case RG_PRESCRIPTION: + // case RG_EYEBALL_FROG: + // case RG_EYEDROPS: + // case RG_CLAIM_CHECK: + // case RG_PROGRESSIVE_GORONSWORD: + // case RG_GIANTS_KNIFE: + + // Misc Items + case RG_STONE_OF_AGONY: + return !CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GERUDO_MEMBERSHIP_CARD: + return !CHECK_QUEST_ITEM(QUEST_GERUDO_CARD) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DOUBLE_DEFENSE: + return !gSaveContext.doubleDefense ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GOLD_SKULLTULA_TOKEN: + return gSaveContext.inventory.gsTokens < 100 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_STRENGTH: + return CUR_UPG_VALUE(UPG_STRENGTH) < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_WALLET: + return CUR_UPG_VALUE(UPG_WALLET) < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_SCALE: + return CUR_UPG_VALUE(UPG_SCALE) < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_MAGIC_METER: + case RG_MAGIC_SINGLE: + case RG_MAGIC_DOUBLE: + return gSaveContext.magicLevel < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Songs + case RG_ZELDAS_LULLABY: + return !CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_EPONAS_SONG: + return !CHECK_QUEST_ITEM(QUEST_SONG_EPONA) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SARIAS_SONG: + return !CHECK_QUEST_ITEM(QUEST_SONG_SARIA) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SUNS_SONG: + return !CHECK_QUEST_ITEM(QUEST_SONG_SUN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SONG_OF_TIME: + return !CHECK_QUEST_ITEM(QUEST_SONG_TIME) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SONG_OF_STORMS: + return !CHECK_QUEST_ITEM(QUEST_SONG_STORMS) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_MINUET_OF_FOREST: + return !CHECK_QUEST_ITEM(QUEST_SONG_MINUET) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOLERO_OF_FIRE: + return !CHECK_QUEST_ITEM(QUEST_SONG_BOLERO) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SERENADE_OF_WATER: + return !CHECK_QUEST_ITEM(QUEST_SONG_SERENADE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_REQUIEM_OF_SPIRIT: + return !CHECK_QUEST_ITEM(QUEST_SONG_REQUIEM) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_NOCTURNE_OF_SHADOW: + return !CHECK_QUEST_ITEM(QUEST_SONG_NOCTURNE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PRELUDE_OF_LIGHT: + return !CHECK_QUEST_ITEM(QUEST_SONG_PRELUDE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Dungeon Items + case RG_DEKU_TREE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_YDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DODONGOS_CAVERN_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_DDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_JABU_JABUS_BELLY_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_BDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_BMORI1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_HIDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_MIZUSIN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_JYASINZOU) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_HAKADAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOTTOM_OF_THE_WELL_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_HAKADANCH) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ICE_CAVERN_MAP: + return !CHECK_DUNGEON_ITEM(DUNGEON_MAP, SCENE_ICE_DOUKUTO) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DEKU_TREE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_YDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_DODONGOS_CAVERN_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_DDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_JABU_JABUS_BELLY_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_BDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_BMORI1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_HIDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_MIZUSIN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_JYASINZOU) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_HAKADAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOTTOM_OF_THE_WELL_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_HAKADANCH) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ICE_CAVERN_COMPASS: + return !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, SCENE_ICE_DOUKUTO) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_BMORI1) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_HIDAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_MIZUSIN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_JYASINZOU) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_HAKADAN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GANONS_CASTLE_BOSS_KEY: + return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_GANON) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + // TODO: Handle MQ key counts + case RG_FOREST_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_BMORI1] < 5 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_HIDAN] < 8 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_MIZUSIN] < 6 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_JYASINZOU] < 5 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_TEMPLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_HAKADAN] < 5 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_HAKADANCH] < 3 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_MEN] < 9 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GERUDO_FORTRESS_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_GERUDOWAY] < 4 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GANONS_CASTLE_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_GANONTIKA] < 2 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_TREASURE_GAME_SMALL_KEY: + return gSaveContext.inventory.dungeonKeys[SCENE_TAKARAYA] < 6 ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + // Dungeon Rewards + case RG_KOKIRI_EMERALD: + return !CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_GORON_RUBY: + return !CHECK_QUEST_ITEM(QUEST_GORON_RUBY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_ZORA_SAPPHIRE: + return !CHECK_QUEST_ITEM(QUEST_ZORA_SAPPHIRE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FOREST_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_FIRE_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_WATER_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SPIRIT_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_SHADOW_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_LIGHT_MEDALLION: + return !CHECK_QUEST_ITEM(QUEST_MEDALLION_LIGHT) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + + case RG_RECOVERY_HEART: + case RG_GREEN_RUPEE: + case RG_BLUE_RUPEE: + case RG_RED_RUPEE: + case RG_PURPLE_RUPEE: + case RG_HUGE_RUPEE: + case RG_PIECE_OF_HEART: + case RG_HEART_CONTAINER: + case RG_ICE_TRAP: + case RG_DEKU_NUTS_5: + case RG_DEKU_NUTS_10: + case RG_DEKU_STICK_1: + case RG_TREASURE_GAME_HEART: + case RG_TREASURE_GAME_GREEN_RUPEE: + case RG_BUY_DEKU_NUT_5: + case RG_BUY_DEKU_NUT_10: + case RG_BUY_DEKU_STICK_1: + case RG_BUY_HEART: + default: + return CAN_OBTAIN; + } +} + +GetItemID Randomizer::GetItemIdFromRandomizerGet(RandomizerGet randoGet, GetItemID ogItemId) { switch (randoGet) { case RG_NONE: return ogItemId; + case RG_TRIFORCE: + case RG_HINT: + case RG_MAX: + case RG_SOLD_OUT: + return GI_NONE; + // Equipment case RG_KOKIRI_SWORD: - return !CHECK_OWNED_EQUIP(EQUIP_SWORD, 0) ? GI_SWORD_KOKIRI : GI_RUPEE_BLUE; + return GI_SWORD_KOKIRI; + case RG_PROGRESSIVE_GORONSWORD: //todo progressive? + return GI_SWORD_BGS; case RG_GIANTS_KNIFE: return GI_SWORD_KNIFE; case RG_BIGGORON_SWORD: - return !gSaveContext.bgsFlag ? GI_SWORD_BGS : GI_RUPEE_BLUE; - + return GI_SWORD_BGS; case RG_DEKU_SHIELD: + case RG_BUY_DEKU_SHIELD: return GI_SHIELD_DEKU; case RG_HYLIAN_SHIELD: + case RG_BUY_HYLIAN_SHIELD: return GI_SHIELD_HYLIAN; case RG_MIRROR_SHIELD: - return !CHECK_OWNED_EQUIP(EQUIP_SHIELD, 2) ? GI_SHIELD_MIRROR : GI_RUPEE_BLUE; - + return GI_SHIELD_MIRROR; case RG_GORON_TUNIC: + case RG_BUY_GORON_TUNIC: return GI_TUNIC_GORON; case RG_ZORA_TUNIC: + case RG_BUY_ZORA_TUNIC: return GI_TUNIC_ZORA; - case RG_IRON_BOOTS: - return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 1) ? GI_BOOTS_IRON : GI_RUPEE_BLUE; + return GI_BOOTS_IRON; case RG_HOVER_BOOTS: - return !CHECK_OWNED_EQUIP(EQUIP_BOOTS, 2) ? GI_BOOTS_HOVER : GI_RUPEE_BLUE; + return GI_BOOTS_HOVER; + // Inventory Items + case RG_PROGRESSIVE_STICK_UPGRADE: + switch (CUR_UPG_VALUE(UPG_STICKS)) { + case 0: + case 1: + return GI_STICK_UPGRADE_20; + case 2: + return GI_STICK_UPGRADE_30; + } + case RG_PROGRESSIVE_NUT_UPGRADE: + switch (CUR_UPG_VALUE(UPG_NUTS)) { + case 0: + case 1: + return GI_NUT_UPGRADE_30; + case 2: + return GI_NUT_UPGRADE_40; + } + case RG_PROGRESSIVE_BOMB_BAG: + switch (CUR_UPG_VALUE(UPG_BOMB_BAG)) { + case 0: + return GI_BOMB_BAG_20; + case 1: + return GI_BOMB_BAG_30; + case 2: + return GI_BOMB_BAG_40; + } + case RG_BOMBS_5: + case RG_BUY_BOMBS_525: + case RG_BUY_BOMBS_535: + return GI_BOMBS_5; + case RG_BOMBS_10: + case RG_BUY_BOMBS_10: + return GI_BOMBS_10; + case RG_BOMBS_20: + case RG_BUY_BOMBS_20: + return GI_BOMBS_20; + case RG_BUY_BOMBS_30: + return GI_BOMBS_30; + case RG_PROGRESSIVE_BOW: + switch (CUR_UPG_VALUE(UPG_QUIVER)) { + case 0: + return GI_BOW; + case 1: + return GI_QUIVER_40; + case 2: + return GI_QUIVER_50; + } + case RG_ARROWS_5: + case RG_BUY_ARROWS_10: + return GI_ARROWS_SMALL; + case RG_ARROWS_10: + case RG_BUY_ARROWS_30: + return GI_ARROWS_MEDIUM; + case RG_ARROWS_30: + case RG_BUY_ARROWS_50: + return GI_ARROWS_LARGE; + case RG_PROGRESSIVE_SLINGSHOT: + switch (CUR_UPG_VALUE(UPG_BULLET_BAG)) { + case 0: + return GI_SLINGSHOT; + case 1: + return GI_BULLET_BAG_40; + case 2: + return GI_BULLET_BAG_50; + } + case RG_DEKU_SEEDS_30: + case RG_BUY_DEKU_SEEDS_30: + return GI_SEEDS_30; + case RG_PROGRESSIVE_OCARINA: + switch (INV_CONTENT(ITEM_OCARINA_FAIRY)) { + case ITEM_NONE: + return GI_OCARINA_FAIRY; + case ITEM_OCARINA_FAIRY: + return GI_OCARINA_OOT; + } + case RG_PROGRESSIVE_BOMBCHUS: + return GI_BOMBCHUS_20; + case RG_BOMBCHU_5: + case RG_BUY_BOMBCHU_5: + case RG_BOMBCHU_DROP: + return GI_BOMBCHUS_5; + case RG_BOMBCHU_10: + case RG_BUY_BOMBCHU_10: + return GI_BOMBCHUS_10; + case RG_BOMBCHU_20: + case RG_BUY_BOMBCHU_20: + return GI_BOMBCHUS_20; + case RG_PROGRESSIVE_HOOKSHOT: + switch (INV_CONTENT(ITEM_HOOKSHOT)) { + case ITEM_NONE: + return GI_HOOKSHOT; + case ITEM_HOOKSHOT: + return GI_LONGSHOT; + } case RG_BOOMERANG: - return INV_CONTENT(ITEM_BOOMERANG) == ITEM_NONE ? GI_BOOMERANG : GI_RUPEE_BLUE; - + return GI_BOOMERANG; case RG_LENS_OF_TRUTH: - return INV_CONTENT(ITEM_LENS) == ITEM_NONE ? GI_LENS : GI_RUPEE_BLUE; - - case RG_MEGATON_HAMMER: - return INV_CONTENT(ITEM_HAMMER) == ITEM_NONE ? GI_HAMMER : GI_RUPEE_BLUE; - - case RG_STONE_OF_AGONY: - return GI_STONE_OF_AGONY; - - case RG_DINS_FIRE: - return INV_CONTENT(ITEM_DINS_FIRE) == ITEM_NONE ? GI_DINS_FIRE : GI_RUPEE_BLUE; - case RG_FARORES_WIND: - return INV_CONTENT(ITEM_FARORES_WIND) == ITEM_NONE ? GI_FARORES_WIND : GI_RUPEE_BLUE; - case RG_NAYRUS_LOVE: - return INV_CONTENT(ITEM_NAYRUS_LOVE) == ITEM_NONE ? GI_NAYRUS_LOVE : GI_RUPEE_BLUE; - - case RG_FIRE_ARROWS: - return INV_CONTENT(ITEM_ARROW_FIRE) == ITEM_NONE ? GI_ARROW_FIRE : GI_RUPEE_BLUE; - case RG_ICE_ARROWS: - return INV_CONTENT(ITEM_ARROW_ICE) == ITEM_NONE ? GI_ARROW_ICE : GI_RUPEE_BLUE; - case RG_LIGHT_ARROWS: - return INV_CONTENT(ITEM_ARROW_LIGHT) == ITEM_NONE ? GI_ARROW_LIGHT : GI_RUPEE_BLUE; - - case RG_DOUBLE_DEFENSE: - return !gSaveContext.doubleDefense ? (GetItemID)RG_DOUBLE_DEFENSE : GI_RUPEE_BLUE; - - case RG_GERUDO_MEMBERSHIP_CARD: - return GI_GERUDO_CARD; - + return GI_LENS; case RG_MAGIC_BEAN: return GI_BEAN; + case RG_MEGATON_HAMMER: + return GI_HAMMER; + case RG_FIRE_ARROWS: + return GI_ARROW_FIRE; + case RG_ICE_ARROWS: + return GI_ARROW_ICE; + case RG_LIGHT_ARROWS: + return GI_ARROW_LIGHT; + case RG_DINS_FIRE: + return GI_DINS_FIRE; + case RG_FARORES_WIND: + return GI_FARORES_WIND; + case RG_NAYRUS_LOVE: + return GI_NAYRUS_LOVE; - case RG_WEIRD_EGG: - return GI_WEIRD_EGG; - - case RG_ZELDAS_LETTER: - return GI_LETTER_ZELDA; + // Bottles + case RG_EMPTY_BOTTLE: + return GI_BOTTLE; + case RG_BOTTLE_WITH_MILK: + return GI_MILK_BOTTLE; case RG_RUTOS_LETTER: return GI_LETTER_RUTO; + // Bottle Refills + case RG_MILK: + return GI_MILK; + case RG_RED_POTION_REFILL: + case RG_BUY_RED_POTION_30: + case RG_BUY_RED_POTION_40: + case RG_BUY_RED_POTION_50: + return GI_POTION_RED; + case RG_GREEN_POTION_REFILL: + case RG_BUY_GREEN_POTION: + return GI_POTION_GREEN; + case RG_BLUE_POTION_REFILL: + case RG_BUY_BLUE_POTION: + return GI_POTION_BLUE; + case RG_BUY_FISH: + return GI_FISH; + case RG_BUY_BLUE_FIRE: + return GI_BLUE_FIRE; + case RG_BUY_BOTTLE_BUG: + return GI_BUGS; + case RG_BUY_POE: + return GI_POE; + case RG_BUY_FAIRYS_SPIRIT: + return GI_FAIRY; + + // Trade Items + case RG_WEIRD_EGG: + return GI_WEIRD_EGG; + case RG_ZELDAS_LETTER: + return GI_LETTER_ZELDA; case RG_POCKET_EGG: return GI_POCKET_EGG; case RG_COJIRO: @@ -1308,19 +1791,14 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { return GI_EYEDROPS; case RG_CLAIM_CHECK: return GI_CLAIM_CHECK; - + + // Misc Items + case RG_STONE_OF_AGONY: + return GI_STONE_OF_AGONY; + case RG_GERUDO_MEMBERSHIP_CARD: + return GI_GERUDO_CARD; case RG_GOLD_SKULLTULA_TOKEN: return GI_SKULL_TOKEN; - - case RG_PROGRESSIVE_HOOKSHOT: - switch (gSaveContext.inventory.items[SLOT_HOOKSHOT]) { - case ITEM_NONE: - return GI_HOOKSHOT; - case ITEM_HOOKSHOT: - return GI_LONGSHOT; - } - return GI_RUPEE_BLUE; - case RG_PROGRESSIVE_STRENGTH: switch (CUR_UPG_VALUE(UPG_STRENGTH)) { case 0: @@ -1330,41 +1808,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 2: return GI_GAUNTLETS_GOLD; } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_BOMB_BAG: - switch (CUR_UPG_VALUE(UPG_BOMB_BAG)) { - case 0: - return GI_BOMB_BAG_20; - case 1: - return GI_BOMB_BAG_30; - case 2: - return GI_BOMB_BAG_40; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_BOW: - switch (CUR_UPG_VALUE(UPG_QUIVER)) { - case 0: - return GI_BOW; - case 1: - return GI_QUIVER_40; - case 2: - return GI_QUIVER_50; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_SLINGSHOT: - switch (CUR_UPG_VALUE(UPG_BULLET_BAG)) { - case 0: - return GI_SLINGSHOT; - case 1: - return GI_BULLET_BAG_40; - case 2: - return GI_BULLET_BAG_50; - } - return GI_RUPEE_BLUE; - case RG_PROGRESSIVE_WALLET: switch (CUR_UPG_VALUE(UPG_WALLET)) { case 0: @@ -1372,8 +1815,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 1: return GI_WALLET_GIANT; } - return GI_RUPEE_BLUE; - case RG_PROGRESSIVE_SCALE: switch (CUR_UPG_VALUE(UPG_SCALE)) { case 0: @@ -1381,37 +1822,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 1: return GI_SCALE_GOLD; } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_NUT_UPGRADE: - switch (CUR_UPG_VALUE(UPG_NUTS)) { - case 0: - case 1: - return GI_NUT_UPGRADE_30; - case 2: - return GI_NUT_UPGRADE_40; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_STICK_UPGRADE: - switch (CUR_UPG_VALUE(UPG_STICKS)) { - case 0: - case 1: - return GI_STICK_UPGRADE_20; - case 2: - return GI_STICK_UPGRADE_30; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_BOMBCHUS: - if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE) { - return GI_BOMBCHUS_20; - } - if (AMMO(ITEM_BOMBCHU) < 5) { - return GI_BOMBCHUS_10; - } - return GI_BOMBCHUS_5; - case RG_PROGRESSIVE_MAGIC_METER: switch (gSaveContext.magicLevel) { case 0: @@ -1419,24 +1829,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case 1: return (GetItemID)RG_MAGIC_DOUBLE; } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_OCARINA: - switch (INV_CONTENT(ITEM_OCARINA_FAIRY) == ITEM_NONE) { - case 1: - return GI_OCARINA_FAIRY; - case 0: - return GI_OCARINA_OOT; - } - return GI_RUPEE_BLUE; - - case RG_PROGRESSIVE_GORONSWORD: - return GI_SWORD_BGS; //todo progressive? - - case RG_EMPTY_BOTTLE: - return GI_BOTTLE; - case RG_BOTTLE_WITH_MILK: - return GI_MILK_BOTTLE; case RG_DEKU_TREE_MAP: case RG_DODONGOS_CAVERN_MAP: @@ -1451,7 +1843,7 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { return GI_MAP; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_DEKU_TREE_COMPASS: @@ -1467,7 +1859,7 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) < 3) { return GI_COMPASS; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_FOREST_TEMPLE_BOSS_KEY: @@ -1478,13 +1870,13 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_BOSS_KEYSANITY) < 3) { return GI_KEY_BOSS; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_GANONS_CASTLE_BOSS_KEY: if (GetRandoSettingValue(RSK_GANONS_BOSS_KEY) < 3) { return GI_KEY_BOSS; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_FOREST_TEMPLE_SMALL_KEY: @@ -1498,34 +1890,18 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { if (GetRandoSettingValue(RSK_KEYSANITY) < 3) { return GI_KEY_SMALL; } else { - return randoGet; + return (GetItemID)randoGet; } case RG_GERUDO_FORTRESS_SMALL_KEY: if (GetRandoSettingValue(RSK_GERUDO_KEYS) == 0) { return GI_KEY_SMALL; } else { - return randoGet; + return (GetItemID)randoGet; } - // todo test this with keys in own dungeon - case RG_TREASURE_GAME_SMALL_KEY: - return GI_DOOR_KEY; - - // todo keyrings - case RG_FOREST_TEMPLE_KEY_RING: - case RG_FIRE_TEMPLE_KEY_RING: - case RG_WATER_TEMPLE_KEY_RING: - case RG_SPIRIT_TEMPLE_KEY_RING: - case RG_SHADOW_TEMPLE_KEY_RING: - case RG_BOTTOM_OF_THE_WELL_KEY_RING: - case RG_GERUDO_TRAINING_GROUNDS_KEY_RING: - case RG_GERUDO_FORTRESS_KEY_RING: - case RG_GANONS_CASTLE_KEY_RING: - return GI_RUPEE_BLUE; - case RG_RECOVERY_HEART: + case RG_BUY_HEART: return GI_HEART; - case RG_GREEN_RUPEE: return GI_RUPEE_GREEN; case RG_BLUE_RUPEE: @@ -1536,73 +1912,33 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { return GI_RUPEE_PURPLE; case RG_HUGE_RUPEE: return GI_RUPEE_GOLD; - case RG_PIECE_OF_HEART: return GI_HEART_PIECE; case RG_HEART_CONTAINER: - // todo figure out what GI_HEART_CONTAINER_2 is return GI_HEART_CONTAINER; - case RG_MILK: - return GI_MILK; //todo logic around needing a bottle? - - case RG_BOMBS_5: - return CUR_UPG_VALUE(UPG_BOMB_BAG) ? GI_BOMBS_5 : GI_RUPEE_BLUE; - case RG_BOMBS_10: - return CUR_UPG_VALUE(UPG_BOMB_BAG) ? GI_BOMBS_10 : GI_RUPEE_BLUE; - case RG_BOMBS_20: - return CUR_UPG_VALUE(UPG_BOMB_BAG) ? GI_BOMBS_20 : GI_RUPEE_BLUE; - - case RG_BOMBCHU_5: - return GI_BOMBCHUS_5; - case RG_BOMBCHU_10: - return GI_BOMBCHUS_10; - case RG_BOMBCHU_20: - return GI_BOMBCHUS_20; - case RG_BOMBCHU_DROP: - return GI_BOMBCHUS_5; //todo figure out what we want to do for chu drops - - case RG_ARROWS_5: - return CUR_UPG_VALUE(UPG_QUIVER) ? GI_ARROWS_SMALL : GI_RUPEE_BLUE; - case RG_ARROWS_10: - return CUR_UPG_VALUE(UPG_QUIVER) ? GI_ARROWS_MEDIUM : GI_RUPEE_BLUE; - case RG_ARROWS_30: - return CUR_UPG_VALUE(UPG_QUIVER) ? GI_ARROWS_LARGE : GI_RUPEE_BLUE; - + case RG_DEKU_NUTS_5: + case RG_BUY_DEKU_NUT_5: return GI_NUTS_5; case RG_DEKU_NUTS_10: + case RG_BUY_DEKU_NUT_10: return GI_NUTS_10; - - case RG_DEKU_SEEDS_30: - return CUR_UPG_VALUE(UPG_BULLET_BAG) ? GI_SEEDS_30 : GI_RUPEE_BLUE; - case RG_DEKU_STICK_1: + case RG_BUY_DEKU_STICK_1: return GI_STICKS_1; - - // RANDOTODO these won't be used until we implement shopsanity/scrub shuffle - case RG_RED_POTION_REFILL: - case RG_GREEN_POTION_REFILL: - case RG_BLUE_POTION_REFILL: - return GI_NONE; - + case RG_TREASURE_GAME_SMALL_KEY: + return GI_DOOR_KEY; case RG_TREASURE_GAME_HEART: return GI_HEART_PIECE_WIN; case RG_TREASURE_GAME_GREEN_RUPEE: - return GI_RUPEE_GREEN_LOSE; //todo figure out how this works outside of the game - - case RG_TRIFORCE: - return GI_RUPEE_BLUE; //todo figure out what this is/does - - case RG_HINT: - return GI_RUPEE_BLUE; //todo - + return GI_RUPEE_GREEN_LOSE; default: if (!IsItemVanilla(randoGet)) { - return randoGet; + return (GetItemID)randoGet; } return ogItemId; - } } +} bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { switch (randoGet) { @@ -2076,11 +2412,11 @@ u8 Randomizer::GetRandoSettingValue(RandomizerSettingKey randoSettingKey) { return this->randoSettings[randoSettingKey]; } -s16 Randomizer::GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId) { - return GetItemFromGet(this->itemLocations[randomizerCheck], ogId); +GetItemID Randomizer::GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogItemId) { + return GetItemIdFromRandomizerGet(this->itemLocations[randomizerCheck], ogItemId); } -RandomizerCheck Randomizer::GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams) { +RandomizerCheck Randomizer::GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams) { if (!gSaveContext.n64ddFlag) { return RC_UNKNOWN_CHECK; } @@ -3139,6 +3475,9 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_ENABLE_GLITCH_CUTSCENES] = CVar_GetS32("gRandomizeEnableGlitchCutscenes", 0); cvarSettings[RSK_SKULLS_SUNS_SONG] = CVar_GetS32("gRandomizeGsExpectSunsSong", 0); + // Link's Pocket has to have a dungeon reward if the other rewards are shuffled to end of dungeon. + cvarSettings[RSK_LINKS_POCKET] = CVar_GetS32("gRandomizeShuffleDungeonReward", 0) != 0 ? + CVar_GetS32("gRandomizeLinksPocket", 0) : 0; // todo: this efficently when we build out cvar array support std::set excludedLocations; @@ -3234,7 +3573,7 @@ void DrawRandoEditor(bool& open) { bool disableEditingRandoSettings = CVar_GetS32("gRandoGenerating", 0) || CVar_GetS32("gOnFileSelectNameEntry", 0); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, disableEditingRandoSettings); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * (disableEditingRandoSettings ? 0.5f : 1.0f)); - SohImGui::EnhancementCheckbox("Enable Randomizer", "gRandomizer"); + UIWidgets::EnhancementCheckbox("Enable Randomizer", "gRandomizer"); if (CVar_GetS32("gRandomizer", 0)) { ImGui::Dummy(ImVec2(0.0f, 0.0f)); @@ -3252,7 +3591,7 @@ void DrawRandoEditor(bool& open) { // ImGui::Text("Settings File: %s", presetfilepath.c_str()); } - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGuiWindow* window = ImGui::GetCurrentWindow(); static ImVec2 cellPadding(8.0f, 8.0f); @@ -3278,7 +3617,7 @@ void DrawRandoEditor(bool& open) { // Forest ImGui::Text(Settings::OpenForest.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Closed - Kokiri sword & shield are required to access " "the Deku Tree, and completing the Deku Tree is required to " "access the Hyrule Field exit.\n" @@ -3290,26 +3629,26 @@ void DrawRandoEditor(bool& open) { "Open - Mido no longer blocks the path to the Deku Tree. Kokiri " "boy no longer blocks the path out of the forest." ); - SohImGui::EnhancementCombobox("gRandomizeForest", randoForest, 3, 0); + UIWidgets::EnhancementCombobox("gRandomizeForest", randoForest, 3, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Kakariko Gate ImGui::Text(Settings::OpenKakariko.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Closed - The gate will remain closed until Zelda's letter " "is shown to the guard.\n" "\n" "Open - The gate is always open. The happy mask shop " "will open immediately after obtaining Zelda's letter." ); - SohImGui::EnhancementCombobox("gRandomizeKakarikoGate", randoKakarikoGate, 2, 0); + UIWidgets::EnhancementCombobox("gRandomizeKakarikoGate", randoKakarikoGate, 2, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Door of Time ImGui::Text(Settings::OpenDoorOfTime.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Closed - The Ocarina of Time, the Song of Time and all " "three spiritual stones are required to open the Door of Time.\n" "\n" @@ -3318,13 +3657,13 @@ void DrawRandoEditor(bool& open) { "\n" "Open - The Door of Time is permanently open with no requirements." ); - SohImGui::EnhancementCombobox("gRandomizeDoorOfTime", randoDoorOfTime, 3, 0); + UIWidgets::EnhancementCombobox("gRandomizeDoorOfTime", randoDoorOfTime, 3, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Zora's Fountain ImGui::Text(Settings::ZorasFountain.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Closed - King Zora obstructs the way to Zora's Fountain. " "Ruto's letter must be shown as child Link in order to move " "him in both time periods.\n" @@ -3335,9 +3674,9 @@ void DrawRandoEditor(bool& open) { "Open - King Zora has already mweeped out of the way in both " "time periods. Ruto's Letter is removed from the item pool." ); - SohImGui::EnhancementCombobox("gRandomizeZorasFountain", randoZorasFountain, 3, 0); + UIWidgets::EnhancementCombobox("gRandomizeZorasFountain", randoZorasFountain, 3, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::EndChild(); @@ -3349,7 +3688,7 @@ void DrawRandoEditor(bool& open) { // Gerudo Fortress ImGui::Text("Gerudo Fortress Carpenters"); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Sets the amount of carpenters required to repair the bridge " "in Gerudo Valley.\n" "\n" @@ -3359,13 +3698,13 @@ void DrawRandoEditor(bool& open) { "\n" "Open - The bridge is repaired from the start." ); - SohImGui::EnhancementCombobox("gRandomizeGerudoFortress", randoGerudoFortress, 3, 0); + UIWidgets::EnhancementCombobox("gRandomizeGerudoFortress", randoGerudoFortress, 3, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Rainbow Bridge ImGui::Text("Rainbow Bridge Requirements"); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Alters the requirements to open the bridge to Ganon's Castle.\n" "\n" "Vanilla - Obtain the Shadow Medallion, Spirit Medallion and Light Arrows.\n" @@ -3386,7 +3725,7 @@ void DrawRandoEditor(bool& open) { "Tokens - Obtain the specified amount of Skulltula tokens." ); - SohImGui::EnhancementCombobox("gRandomizeRainbowBridge", randoRainbowBridge, 7, 0); + UIWidgets::EnhancementCombobox("gRandomizeRainbowBridge", randoRainbowBridge, 7, 0); ImGui::PopItemWidth(); switch (CVar_GetS32("gRandomizeRainbowBridge", 0)) { case 0: @@ -3395,37 +3734,37 @@ void DrawRandoEditor(bool& open) { break; case 2: ImGui::Dummy(ImVec2(0.0f, 0.0f)); - SohImGui::EnhancementSliderInt("Stone Count: %d", "##RandoStoneCount", + UIWidgets::EnhancementSliderInt("Stone Count: %d", "##RandoStoneCount", "gRandomizeStoneCount", 1, 3, "", 3, true); break; case 3: ImGui::Dummy(ImVec2(0.0f, 0.0f)); - SohImGui::EnhancementSliderInt("Medallion Count: %d", "##RandoMedallionCount", + UIWidgets::EnhancementSliderInt("Medallion Count: %d", "##RandoMedallionCount", "gRandomizeMedallionCount", 1, 6, "", 6, true); break; case 4: ImGui::Dummy(ImVec2(0.0f, 0.0f)); - SohImGui::EnhancementSliderInt("Reward Count: %d", "##RandoRewardCount", + UIWidgets::EnhancementSliderInt("Reward Count: %d", "##RandoRewardCount", "gRandomizeRewardCount", 1, 9, "", 9, true); break; case 5: ImGui::Dummy(ImVec2(0.0f, 0.0f)); - SohImGui::EnhancementSliderInt("Dungeon Count: %d", "##RandoDungeonCount", + UIWidgets::EnhancementSliderInt("Dungeon Count: %d", "##RandoDungeonCount", "gRandomizeDungeonCount", 1, 8, "", 8, true); break; case 6: ImGui::Dummy(ImVec2(0.0f, 0.0f)); - SohImGui::EnhancementSliderInt("Token Count: %d", "##RandoTokenCount", + UIWidgets::EnhancementSliderInt("Token Count: %d", "##RandoTokenCount", "gRandomizeTokenCount", 1, 100, "", 100, true); break; } - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Ganon's Trials ImGui::PushItemWidth(-FLT_MIN); ImGui::Text("Ganon's Trials"); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Sets the number of Ganon's Trials required to dispel the barrier.\n" "\n" "Skip - No Trials are required and the barrier is already dispelled.\n" @@ -3435,16 +3774,16 @@ void DrawRandoEditor(bool& open) { "\n" "Random Number - A Random number and set of trials will be required." ); - SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); + UIWidgets::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); ImGui::PopItemWidth(); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { ImGui::Dummy(ImVec2(0.0f, 0.0f)); - SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", + UIWidgets::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 1, 6, "", 6, true); - InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); + UIWidgets::InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); } - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::EndChild(); @@ -3456,7 +3795,7 @@ void DrawRandoEditor(bool& open) { ImGui::Text("Coming soon"); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::PopItemWidth(); ImGui::EndChild(); @@ -3486,7 +3825,7 @@ void DrawRandoEditor(bool& open) { // Shuffle Songs ImGui::Text(Settings::ShuffleSongs.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Song locations - Songs will only appear at locations that normally teach songs.\n" "\n" "Dungeon rewards - Songs appear after beating a major dungeon boss.\n" @@ -3498,13 +3837,13 @@ void DrawRandoEditor(bool& open) { "\n" "Anywhere - Songs can appear at any location." ); - SohImGui::EnhancementCombobox("gRandomizeShuffleSongs", randoShuffleSongs, 3, 0); + UIWidgets::EnhancementCombobox("gRandomizeShuffleSongs", randoShuffleSongs, 3, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Tokens ImGui::Text(Settings::Tokensanity.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Shuffles Golden Skulltula Tokens into the item pool. This means " "Golden Skulltulas can contain other items as well.\n" "\n" @@ -3516,53 +3855,53 @@ void DrawRandoEditor(bool& open) { "\n" "All Tokens - Shuffle all 100 GS tokens." ); - SohImGui::EnhancementCombobox("gRandomizeShuffleTokens", randoTokensanity, 4, 0); + UIWidgets::EnhancementCombobox("gRandomizeShuffleTokens", randoTokensanity, 4, 0); ImGui::Dummy(ImVec2(0,0)); - SohImGui::EnhancementCheckbox("Nighttime GS expect Sun's Song", "gRandomizeGsExpectSunsSong"); - InsertHelpHoverText( + UIWidgets::EnhancementCheckbox("Nighttime GS expect Sun's Song", "gRandomizeGsExpectSunsSong"); + UIWidgets::InsertHelpHoverText( "All Golden Skulltulas that require nighttime to appear will only be " "expected to be collected after getting Sun's Song." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Kokiri Sword // Disabled when Start with Kokiri Sword is active bool disableShuffleKokiriSword = CVar_GetS32("gRandomizeStartingKokiriSword", 0); const char* disableShuffleKokiriSwordText = "This option is disabled because \"Start with Kokiri Sword\" is enabled."; - SohImGui::EnhancementCheckbox(Settings::ShuffleKokiriSword.GetName().c_str(), "gRandomizeShuffleKokiriSword", + UIWidgets::EnhancementCheckbox(Settings::ShuffleKokiriSword.GetName().c_str(), "gRandomizeShuffleKokiriSword", disableShuffleKokiriSword, disableShuffleKokiriSwordText); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Shuffles the Kokiri Sword into the item pool.\n" "\n" "This will require the use of sticks until the Kokiri Sword is found." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Ocarinas // Disabled when Start with Ocarina is active bool disableShuffleOcarinas = CVar_GetS32("gRandomizeStartingOcarina", 0); const char* disableShuffleOcarinasText = "This option is disabled because \"Start with Fairy Ocarina\" is enabled."; - SohImGui::EnhancementCheckbox(Settings::ShuffleOcarinas.GetName().c_str(), "gRandomizeShuffleOcarinas", + UIWidgets::EnhancementCheckbox(Settings::ShuffleOcarinas.GetName().c_str(), "gRandomizeShuffleOcarinas", disableShuffleOcarinas, disableShuffleOcarinasText); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Enabling this shuffles the Fairy Ocarina and the Ocarina of Time into the item pool.\n" "\n" "This will require finding an Ocarina before being able to play songs." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Weird Egg // Disabled when Skip Child Zelda is active bool disableShuffleWeirdEgg = CVar_GetS32("gRandomizeSkipChildZelda", 0); const char* disableShuffleWeirdEggText = "This option is disabled because \"Skip Child Zelda\" is enabled."; - SohImGui::EnhancementCheckbox(Settings::ShuffleWeirdEgg.GetName().c_str(), "gRandomizeShuffleWeirdEgg", + UIWidgets::EnhancementCheckbox(Settings::ShuffleWeirdEgg.GetName().c_str(), "gRandomizeShuffleWeirdEgg", disableShuffleWeirdEgg, disableShuffleWeirdEggText); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Shuffles the Weird Egg from Malon in to the item pool. Enabling " "\"Skip Child Zelda\" disables this feature.\n" "\n" @@ -3574,19 +3913,19 @@ void DrawRandoEditor(bool& open) { " - Happy Mask Shop sidequest\n" ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Gerudo Membership Card - SohImGui::EnhancementCheckbox(Settings::ShuffleGerudoToken.GetName().c_str(), + UIWidgets::EnhancementCheckbox(Settings::ShuffleGerudoToken.GetName().c_str(), "gRandomizeShuffleGerudoToken"); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Shuffles the Gerudo Membership Card into the item pool.\n" "\n" "The Gerudo Card is required to enter the Gerudo Training Grounds, opening " "the gate to Haunted Wasteland and the Horseback Archery minigame." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::PopItemWidth(); ImGui::EndChild(); @@ -3599,7 +3938,7 @@ void DrawRandoEditor(bool& open) { // Shuffle Scrubs ImGui::Text(Settings::Scrubsanity.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Off - Scrubs will not be shuffled. The 3 Scrubs that give one-time items in the vanilla game " "(PoH, Deku Nut capacity, and Deku Stick capacity) will have random items.\n" "\n" @@ -3608,27 +3947,27 @@ void DrawRandoEditor(bool& open) { "Expensive - Scrubs will be shuffled and their item will cost the vanilla price.\n" "\n" "Random - Scrubs will be shuffled and their item will cost will be between 0-95 rupees.\n"); - SohImGui::EnhancementCombobox("gRandomizeShuffleScrubs", randoShuffleScrubs, 4, 0); + UIWidgets::EnhancementCombobox("gRandomizeShuffleScrubs", randoShuffleScrubs, 4, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Cows - SohImGui::EnhancementCheckbox(Settings::ShuffleCows.GetName().c_str(), "gRandomizeShuffleCows"); - InsertHelpHoverText("Cows give a randomized item from the pool upon performing Epona's Song in front of them."); + UIWidgets::EnhancementCheckbox(Settings::ShuffleCows.GetName().c_str(), "gRandomizeShuffleCows"); + UIWidgets::InsertHelpHoverText("Cows give a randomized item from the pool upon performing Epona's Song in front of them."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); - SohImGui::EnhancementCheckbox(Settings::ShuffleMagicBeans.GetName().c_str(), "gRandomizeShuffleBeans"); - InsertHelpHoverText( + UIWidgets::EnhancementCheckbox(Settings::ShuffleMagicBeans.GetName().c_str(), "gRandomizeShuffleBeans"); + UIWidgets::InsertHelpHoverText( "Enabling this adds a pack of 10 beans to the item pool and changes the Magic Bean " "Salesman to sell a random item at a price of 60 rupees." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Frog Song Rupees - SohImGui::EnhancementCheckbox(Settings::ShuffleFrogSongRupees.GetName().c_str(), "gRandomizeShuffleFrogSongRupees"); - InsertHelpHoverText( + UIWidgets::EnhancementCheckbox(Settings::ShuffleFrogSongRupees.GetName().c_str(), "gRandomizeShuffleFrogSongRupees"); + UIWidgets::InsertHelpHoverText( "Shuffles 5 Purple Rupees into to the item pool, and allows\n" "you to earn items by playing songs at the Frog Choir.\n" "\n" @@ -3636,12 +3975,12 @@ void DrawRandoEditor(bool& open) { "the Song of Storms and the frog song minigame." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Shuffle Adult Trade Quest - SohImGui::EnhancementCheckbox(Settings::ShuffleAdultTradeQuest.GetName().c_str(), + UIWidgets::EnhancementCheckbox(Settings::ShuffleAdultTradeQuest.GetName().c_str(), "gRandomizeShuffleAdultTrade"); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Adds all of the adult trade quest items into the pool, each of which " "can be traded for a unique reward.\n" "\n" @@ -3652,7 +3991,7 @@ void DrawRandoEditor(bool& open) { "If disabled, only the Claim Check will be found in the pool." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::PopItemWidth(); ImGui::EndChild(); @@ -3665,7 +4004,7 @@ void DrawRandoEditor(bool& open) { // Shuffle Dungeon Rewards ImGui::Text(Settings::ShuffleRewards.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Shuffles the location of spiritual stones and medallions.\n" "\n" "End of dungeons - Spiritual stones and medallions will be given as rewards " @@ -3677,13 +4016,13 @@ void DrawRandoEditor(bool& open) { "\n" "Anywhere - Spiritual stones and medallions can appear anywhere." ); - SohImGui::EnhancementCombobox("gRandomizeShuffleDungeonReward", randoShuffleDungeonRewards, 4, 0); + UIWidgets::EnhancementCombobox("gRandomizeShuffleDungeonReward", randoShuffleDungeonRewards, 4, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Maps & Compasses ImGui::Text(Settings::MapsAndCompasses.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Start with - You will start with Maps & Compasses from all dungeons.\n" "\n" "Vanilla - Maps & Compasses will appear in their vanilla locations.\n" @@ -3696,13 +4035,13 @@ void DrawRandoEditor(bool& open) { "\n" "Anywhere - Maps & Compasses can appear anywhere in the world." ); - SohImGui::EnhancementCombobox("gRandomizeStartingMapsCompasses", randoShuffleMapsAndCompasses, 6, 2); + UIWidgets::EnhancementCombobox("gRandomizeStartingMapsCompasses", randoShuffleMapsAndCompasses, 6, 2); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Keysanity ImGui::Text(Settings::Keysanity.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Start with - You will start with all Small Keys from all dungeons.\n" "\n" "Vanilla - Small Keys will appear in their vanilla locations.\n" @@ -3715,13 +4054,13 @@ void DrawRandoEditor(bool& open) { "\n" "Anywhere - Small Keys can appear anywhere in the world." ); - SohImGui::EnhancementCombobox("gRandomizeKeysanity", randoShuffleSmallKeys, 6, 2); + UIWidgets::EnhancementCombobox("gRandomizeKeysanity", randoShuffleSmallKeys, 6, 2); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Gerudo Keys ImGui::Text(Settings::GerudoKeys.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Vanilla - Thieve's Hideout Keys will appear in their vanilla locations.\n" "\n" "Any dungeon - Thieve's Hideout Keys can only appear inside of any dungon.\n" @@ -3730,13 +4069,13 @@ void DrawRandoEditor(bool& open) { "\n" "Anywhere - Thieve's Hideout Keys can appear anywhere in the world." ); - SohImGui::EnhancementCombobox("gRandomizeGerudoKeys", randoShuffleGerudoFortressKeys, 4, 0); + UIWidgets::EnhancementCombobox("gRandomizeGerudoKeys", randoShuffleGerudoFortressKeys, 4, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Boss Keysanity ImGui::Text(Settings::BossKeysanity.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Start with - You will start with Boss keys from all dungeons.\n" "\n" "Vanilla - Boss Keys will appear in their vanilla locations.\n" @@ -3749,13 +4088,13 @@ void DrawRandoEditor(bool& open) { "\n" "Anywhere - Boss Keys can appear anywhere in the world." ); - SohImGui::EnhancementCombobox("gRandomizeBossKeysanity", randoShuffleBossKeys, 6, 2); + UIWidgets::EnhancementCombobox("gRandomizeBossKeysanity", randoShuffleBossKeys, 6, 2); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Ganon's Boss Key ImGui::Text(Settings::GanonsBossKey.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Vanilla - Ganon's Boss Key will appear in the vanilla location.\n" "\n" "Own dungeon - Ganon's Boss Key can appear anywhere inside Ganon's Castle.\n" @@ -3768,9 +4107,9 @@ void DrawRandoEditor(bool& open) { "\n" "Anywhere - Ganon's Boss Key Key can appear anywhere in the world." ); - SohImGui::EnhancementCombobox("gRandomizeShuffleGanonBossKey", randoShuffleGanonsBossKey, 6, 1); + UIWidgets::EnhancementCombobox("gRandomizeShuffleGanonBossKey", randoShuffleGanonsBossKey, 6, 1); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::PopItemWidth(); ImGui::EndChild(); @@ -3797,53 +4136,53 @@ void DrawRandoEditor(bool& open) { ImGui::BeginChild("ChildTimeSavers", ImVec2(0, -8)); // Cuccos to return - SohImGui::EnhancementSliderInt("Cuccos to return: %d", "##RandoCuccosToReturn", + UIWidgets::EnhancementSliderInt("Cuccos to return: %d", "##RandoCuccosToReturn", "gRandomizeCuccosToReturn", 0, 7, "", 7, true); - InsertHelpHoverText("The amount of cuccos needed to claim the reward from Anju the cucco lady"); + UIWidgets::InsertHelpHoverText("The amount of cuccos needed to claim the reward from Anju the cucco lady"); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Big Poe Target Count - SohImGui::EnhancementSliderInt("Big Poe Target Count: %d", "##RandoBigPoeTargetCount", + UIWidgets::EnhancementSliderInt("Big Poe Target Count: %d", "##RandoBigPoeTargetCount", "gRandomizeBigPoeTargetCount", 1, 10, "", 10, true); - InsertHelpHoverText("The Poe collector will give a reward for turning in this many Big Poes."); + UIWidgets::InsertHelpHoverText("The Poe collector will give a reward for turning in this many Big Poes."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Skip child stealth // Disabled when Skip Child Zelda is active bool disableChildStealth = CVar_GetS32("gRandomizeSkipChildZelda", 0); const char* disableChildStealthText = "This option is disabled because \"Skip Child Zelda\" is enabled"; - SohImGui::EnhancementCheckbox(Settings::SkipChildStealth.GetName().c_str(), "gRandomizeSkipChildStealth", disableChildStealth, disableChildStealthText); - InsertHelpHoverText("The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards."); + UIWidgets::EnhancementCheckbox(Settings::SkipChildStealth.GetName().c_str(), "gRandomizeSkipChildStealth", disableChildStealth, disableChildStealthText); + UIWidgets::InsertHelpHoverText("The crawlspace into Hyrule Castle goes straight to Zelda, skipping the guards."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Skip child zelda - SohImGui::EnhancementCheckbox("Skip Child Zelda", "gRandomizeSkipChildZelda"); - InsertHelpHoverText("Start with Zelda's Letter and the item Impa would normally give you and skip the sequence up " + UIWidgets::EnhancementCheckbox("Skip Child Zelda", "gRandomizeSkipChildZelda"); + UIWidgets::InsertHelpHoverText("Start with Zelda's Letter and the item Impa would normally give you and skip the sequence up " "until after meeting Zelda. Disables the ability to shuffle Weird Egg."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Skip Epona race - SohImGui::EnhancementCheckbox(Settings::SkipEponaRace.GetName().c_str(), "gRandomizeSkipEponaRace"); - InsertHelpHoverText("Epona can be summoned with Epona's Song without needing to race Ingo."); + UIWidgets::EnhancementCheckbox(Settings::SkipEponaRace.GetName().c_str(), "gRandomizeSkipEponaRace"); + UIWidgets::InsertHelpHoverText("Epona can be summoned with Epona's Song without needing to race Ingo."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Skip tower escape - SohImGui::EnhancementCheckbox(Settings::SkipTowerEscape.GetName().c_str(), "gRandomizeSkipTowerEscape"); - InsertHelpHoverText("The tower escape sequence between Ganondorf and Ganon will be skipped."); + UIWidgets::EnhancementCheckbox(Settings::SkipTowerEscape.GetName().c_str(), "gRandomizeSkipTowerEscape"); + UIWidgets::InsertHelpHoverText("The tower escape sequence between Ganondorf and Ganon will be skipped."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Complete mask quest - SohImGui::EnhancementCheckbox(Settings::CompleteMaskQuest.GetName().c_str(), + UIWidgets::EnhancementCheckbox(Settings::CompleteMaskQuest.GetName().c_str(), "gRandomizeCompleteMaskQuest"); - InsertHelpHoverText("Once the happy mask shop is opened, all masks will be available to be borrowed."); + UIWidgets::InsertHelpHoverText("Once the happy mask shop is opened, all masks will be available to be borrowed."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::EndChild(); @@ -3855,7 +4194,7 @@ void DrawRandoEditor(bool& open) { // Item Pool Settings ImGui::Text(Settings::ItemPoolValue.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Sets how many major items appear in the item pool.\n" "\n" "Plentiful - Extra major items are added to the pool.\n" @@ -3866,12 +4205,12 @@ void DrawRandoEditor(bool& open) { "\n" "Minimal - Most excess items are removed." ); - SohImGui::EnhancementCombobox("gRandomizeItemPool", randoItemPool, 4, 1); - PaddedSeparator(); + UIWidgets::EnhancementCombobox("gRandomizeItemPool", randoItemPool, 4, 1); + UIWidgets::PaddedSeparator(); // Ice Traps ImGui::Text(Settings::IceTrapValue.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Sets how many items are replaced by ice traps.\n" "\n" "Off - No ice traps.\n" @@ -3885,13 +4224,13 @@ void DrawRandoEditor(bool& open) { "Onslaught - All junk items will be replaced by Ice Traps, even those " "in the base pool." ); - SohImGui::EnhancementCombobox("gRandomizeIceTraps", randoIceTraps, 5, 1); + UIWidgets::EnhancementCombobox("gRandomizeIceTraps", randoIceTraps, 5, 1); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Gossip Stone Hints ImGui::Text(Settings::GossipStoneHints.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Allows Gossip Stones to provide hints on item locations. Hints mentioning " "\"Way of the Hero\" indicate a location that holds an item required to beat " "the seed.\n" @@ -3903,13 +4242,13 @@ void DrawRandoEditor(bool& open) { "Need Stone of Agony - Hints are only available after obtaining the Stone of Agony.\n" "\n" "Need Mask of Truth - Hints are only available whilst wearing the Mask of Truth.\n"); - SohImGui::EnhancementCombobox("gRandomizeGossipStoneHints", randoGossipStoneHints, 4, 1); + UIWidgets::EnhancementCombobox("gRandomizeGossipStoneHints", randoGossipStoneHints, 4, 1); if (CVar_GetS32("gRandomizeGossipStoneHints", 1) != 0) { // Hint Clarity ImGui::Dummy(ImVec2(0.0f, 0.0f)); ImGui::Indent(); ImGui::Text(Settings::ClearerHints.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Sets the difficulty of hints.\n" "\n" "Obscure - Hints are unique for each item, but the writing may be cryptic.\n" @@ -3921,12 +4260,12 @@ void DrawRandoEditor(bool& open) { "Clear - Hints are clearly written and are unique for each item.\n" "Ex: Kokiri Sword > the Kokiri Sword" ); - SohImGui::EnhancementCombobox("gRandomizeHintClarity", randoHintClarity, 3, 2); + UIWidgets::EnhancementCombobox("gRandomizeHintClarity", randoHintClarity, 3, 2); // Hint Distribution ImGui::Dummy(ImVec2(0.0f, 0.0f)); ImGui::Text(Settings::HintDistribution.GetName().c_str()); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Sets how many hints will be useful.\n" "\n" "Useless - Only junk hints.\n" @@ -3937,11 +4276,11 @@ void DrawRandoEditor(bool& open) { "\n" "Very Strong - Many powerful hints." ); - SohImGui::EnhancementCombobox("gRandomizeHintDistribution", randoHintDistribution, 4, 1); + UIWidgets::EnhancementCombobox("gRandomizeHintDistribution", randoHintDistribution, 4, 1); ImGui::Unindent(); } - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::PopItemWidth(); ImGui::EndChild(); @@ -3952,14 +4291,14 @@ void DrawRandoEditor(bool& open) { ImGui::BeginChild("ChildAdditionalFeatures", ImVec2(0, -8)); ImGui::PushItemWidth(-FLT_MIN); - SohImGui::EnhancementCheckbox("Full Wallets", "gRandomizeFullWallets"); - InsertHelpHoverText("Start with a full wallet. All wallet upgrades come filled with rupees."); + UIWidgets::EnhancementCheckbox("Full Wallets", "gRandomizeFullWallets"); + UIWidgets::InsertHelpHoverText("Start with a full wallet. All wallet upgrades come filled with rupees."); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Bombchus in Logic - SohImGui::EnhancementCheckbox(Settings::BombchusInLogic.GetName().c_str(), "gRandomizeBombchusInLogic"); - InsertHelpHoverText( + UIWidgets::EnhancementCheckbox(Settings::BombchusInLogic.GetName().c_str(), "gRandomizeBombchusInLogic"); + UIWidgets::InsertHelpHoverText( "Bombchus are properly considered in logic.\n" "\n" "The first Bombchu pack will always be 20, and subsequent packs will be " @@ -3969,23 +4308,23 @@ void DrawRandoEditor(bool& open) { "Bombchu Bowling is opened by obtaining Bombchus." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); - SohImGui::EnhancementCheckbox("WIP - Blue Fire Arrows", "gRandomizeBlueFireArrows", true, "In development"); - InsertHelpHoverText( + UIWidgets::EnhancementCheckbox("WIP - Blue Fire Arrows", "gRandomizeBlueIceArrows", true, "In development"); + UIWidgets::InsertHelpHoverText( "Ice Arrows act like Blue Fire, making them able to melt red ice. " "Item placement logic will respect this option, so it might be required to use this to progress." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); - SohImGui::EnhancementCheckbox("WIP - Sunlight Arrows", "gRandomizeSunlightArrows", true, "In development"); - InsertHelpHoverText( + UIWidgets::EnhancementCheckbox("WIP - Sunlight Arrows", "gRandomizeSunlightArrows", true, "In development"); + UIWidgets::InsertHelpHoverText( "Light Arrows can be used to light up the sun switches instead of using the Mirror Shield. " "Item placement logic will respect this option, so it might be required to use this to progress." ); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::PopItemWidth(); ImGui::EndChild(); @@ -4053,7 +4392,7 @@ void DrawRandoEditor(bool& open) { excludedLocationString += ","; } CVar_SetString("gRandomizeExcludedLocations", excludedLocationString.c_str()); - SohImGui::needs_save = true; + SohImGui::RequestCvarSaveOnNextTick(); } ImGui::SameLine(); ImGui::Text(locationIt.rcShortName.c_str()); @@ -4094,7 +4433,7 @@ void DrawRandoEditor(bool& open) { excludedLocationString += ","; } CVar_SetString("gRandomizeExcludedLocations", excludedLocationString.c_str()); - SohImGui::needs_save = true; + SohImGui::RequestCvarSaveOnNextTick(); } ImGui::SameLine(); ImGui::Text(locationIt.rcShortName.c_str()); @@ -4122,19 +4461,19 @@ void DrawRandoEditor(bool& open) { ImGui::TableNextColumn(); ImGui::PushItemWidth(170.0); ImGui::Text("Logic Rules"); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "Glitchless - No glitches are required, but may require some minor tricks.\n" "\n" "No logic - Item placement is completely random. MAY BE IMPOSSIBLE TO BEAT." ); - SohImGui::EnhancementCombobox("gRandomizeLogicRules", randoLogicRules, 2, 0); + UIWidgets::EnhancementCombobox("gRandomizeLogicRules", randoLogicRules, 2, 0); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); // Enable Glitch-Useful Cutscenes - SohImGui::EnhancementCheckbox(Settings::EnableGlitchCutscenes.GetName().c_str(), + UIWidgets::EnhancementCheckbox(Settings::EnableGlitchCutscenes.GetName().c_str(), "gRandomizeEnableGlitchCutscenes"); - InsertHelpHoverText( + UIWidgets::InsertHelpHoverText( "The cutscenes of the Poes in Forest Temple and Darunia in Fire Temple will not be skipped. " "These cutscenes are only useful for glitched gameplay and can be safely skipped otherwise."); @@ -4188,14 +4527,21 @@ void DrawRandoEditor(bool& open) { ImGui::TableNextColumn(); window->DC.CurrLineTextBaseOffset = 0.0f; ImGui::BeginChild("ChildStartingEquipment", ImVec2(0, -8)); + // Don't display this option if Dungeon Rewards are Shuffled to End of Dungeon. + // TODO: Show this but disabled when we have options for disabled Comboboxes. + if (CVar_GetS32("gRandomizeShuffleDungeonReward", 0) != 0) { + ImGui::Text(Settings::LinksPocketItem.GetName().c_str()); + UIWidgets::EnhancementCombobox("gRandomizeLinksPocket", randoLinksPocket, 4, 0); + UIWidgets::PaddedSeparator(); + } - SohImGui::EnhancementCheckbox(Settings::StartingKokiriSword.GetName().c_str(), + UIWidgets::EnhancementCheckbox(Settings::StartingKokiriSword.GetName().c_str(), "gRandomizeStartingKokiriSword"); - PaddedSeparator(); - SohImGui::EnhancementCheckbox(Settings::StartingDekuShield.GetName().c_str(), + UIWidgets::PaddedSeparator(); + UIWidgets::EnhancementCheckbox(Settings::StartingDekuShield.GetName().c_str(), "gRandomizeStartingDekuShield"); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::EndChild(); @@ -4204,11 +4550,11 @@ void DrawRandoEditor(bool& open) { window->DC.CurrLineTextBaseOffset = 0.0f; ImGui::BeginChild("ChildStartingItems", ImVec2(0, -8)); - SohImGui::EnhancementCheckbox(Settings::StartingOcarina.GetName().c_str(), "gRandomizeStartingOcarina"); - PaddedSeparator(); - SohImGui::EnhancementCheckbox(Settings::StartingConsumables.GetName().c_str(), + UIWidgets::EnhancementCheckbox(Settings::StartingOcarina.GetName().c_str(), "gRandomizeStartingOcarina"); + UIWidgets::PaddedSeparator(); + UIWidgets::EnhancementCheckbox(Settings::StartingConsumables.GetName().c_str(), "gRandomizeStartingConsumables"); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::EndChild(); @@ -4219,7 +4565,7 @@ void DrawRandoEditor(bool& open) { ImGui::Text("Coming soon"); - PaddedSeparator(); + UIWidgets::PaddedSeparator(); ImGui::EndChild(); ImGui::EndTable(); @@ -4372,7 +4718,7 @@ CustomMessageMinimal NaviMessages[NUM_NAVI_MESSAGES] = { "%cSi tu es coincé sur cette seed,&tu peux toujours jeter l'éponge&et regader le %wSpoiler log%c..." }, { "%cDid you know that the %yHover&Boots %ccan be used to cross&%wquicksand%c?", - "%cWusstest du, dass du mit den&%yGleitstiefeln %cTreibsand %wüberqueren&kannst%c?", + "%cWußtest du, daß du mit den&%yGleitstiefeln %cTreibsand %wüberqueren&kannst%c?", "%cEst-ce que tu savais que les %rBottes&des airs %cpouvaient être utilisées&pour traverser les %wsables mouvants%c?" }, { "%cYou can reach the back of %wImpa's&House %cby jumping from the&unfinished house with a %rcucco%c!", @@ -4380,15 +4726,15 @@ CustomMessageMinimal NaviMessages[NUM_NAVI_MESSAGES] = { "%cTu peux atteindre l'arrière de la&%wMaison d'Impa %cen sautant depuis la&maison en construction avec une&%rcocotte%c!" }, { "%cThe %ySpirit Trial %cin %pGanon's Castle&%chas a %whidden chest %csomewhere.&Did you already know that?", - "%cDie %yGeister-Prüfung %cin %pGanons&Schloss %chat irgendwo eine&%wversteckte Kiste%c. Weißt du schon&wo?", + "%cDie %yGeister-Prüfung %cin %pGanons&Schloß %chat irgendwo eine&%wversteckte Kiste%c. Weißt du schon&wo?", "%cL'%yÉpreuve de l'Esprit%c dans le %pChâteau&de Ganon %ca un coffre caché quelque&part. Je suppose que tu le savais&déjà?" }, { "%cYou know the %wBombchu Bowling&Alley%c? I heard %wonly two of the &prizes %care worthwhile. The rest &is junk!", - "%cKennst du die %wMinenbowlingbahn%c?&Ich habe gehört dass sich nur &%wzwei der Preise%c lohnen. Der Rest&ist Krimskrams!", + "%cKennst du die %wMinenbowlingbahn%c?&Ich habe gehört daß sich nur &%wzwei der Preise%c lohnen. Der Rest&ist Krimskrams!", "%cEst-ce que tu savais qu'au %wBowling&Teigneux%c, il n'y a que les %wdeux&premiers prix %cqui sont intéréssant?" }, { "%cHave you been using %wDeku Nuts&%cenough? I've seen them blow up&a %rBombchu%c!", - "%cBenutzt du auch genügend %wDeku&Nüsse%c? Ich habe mal gesehen dass&man damit %rKrabbelminen %cdetonieren&kann!", + "%cBenutzt du auch genügend %wDeku&Nüsse%c? Ich habe mal gesehen daß&man damit %rKrabbelminen %cdetonieren&kann!", "%cTu es sûr d'utiliser tes %wNoix Mojo &%ccorrectement? J'en ai déjà vu&exploser des %rChoux-Péteurs%c!" }, { "%cYou might end up with an %wextra&key %cfor the %bWater Temple %cor the&%rFire Temple%c. It's for your safety!", @@ -4404,7 +4750,7 @@ CustomMessageMinimal NaviMessages[NUM_NAVI_MESSAGES] = { "%cMême un adulte ne peut pas pousser&de grands blocs sans un petit %wgain&de force%c!" }, { "%cI've heard that %rFlare Dancer&%cis weak to the %wMaster Sword%c!&Have you tried it?", - "%cIch habe gehört dass der&%rFlammenderwisch %ceine Schwäche für&das %wMasterschwert %caufweist. Hast du&es schonmal versucht einzusetzen?", + "%cIch habe gehört daß der&%rFlammenderwisch %ceine Schwäche für&das %wMasterschwert %caufweist. Hast du&es schonmal versucht einzusetzen?", "%cJ'ai entendu dire que les %rDanse-&Flammes %csont faîbles face à l'%wÉpée de&Légende%c! Est-ce que tu as essayé?" }, { "%cDon't have a weapon to kill a&%rspider%c? Try throwing a %wpot&%cat it!", @@ -4412,8 +4758,24 @@ CustomMessageMinimal NaviMessages[NUM_NAVI_MESSAGES] = { "%cSi tu n'as pas d'arme pour tuer&une %raraignée%c, pourquoi n'essayerais&-tu pas de lui jetter une %wjarre&%cà la figure?" }, { "%cI hear the patch of %wsoft soil&%cin %bZora's River %cis the only one&that isn't home to a %rspider%c!", - "%cIch habe gehört dass die Stelle&%wfeuchten Bodens %cim %bZora-Fluss %cals&einzige keine %rSkulltula %cbeherbergt.", + "%cIch habe gehört daß die Stelle&%wfeuchten Bodens %cim %bZora-Fluß %cals&einzige keine %rSkulltula %cbeherbergt.", "%cJ'ai entendu dire que la %wterre meuble&%cqui se trouve à la %bRivière Zora %cest&la seule qui ne contienne pas&d'%raraignée%c." }, + + { "%cThe people of Hyrule sometimes&have %witems %cfor you, but they won't&like it if you're %wwearing a mask%c!", + "%cDie Bewohner Hyrules haben manchmal&%wGegenstände %cfür dich, aber Sie mögen&es nicht wenn du %wMasken trägst%c!", + "%cIl se peut que les habitants d'Hyrule&aient des %wobjets %cpour toi. Par contre,&ils risquent de ne pas trop apprécier&le fait que tu %wportes un masque%c!" }, + + { "%cIf you get trapped somewhere, you&might have to %wsave your game %cand&%wreset%c!", + "%cSolltest du irgendwo eingeschloßen&sein, mußt du vielleicht dein %wSpiel&speichern %cund %wneustarten%c!", + "%cSi tu es coincé quelque part, tu&devrais %wsauvegarder ta partie %cet&faire un %wreset%c!" }, + + { "%cSheik will meet you in a %rburning&village %conce you have %gForest%c,&%rFire%c, and %bWater %cMedallions!", + "%cSheik wird dich in einem %rbrennenden&Dorf %ctreffen sobald du das Amulett&des %gWaldes%c, %rFeuers %cund %bWassers&%cbesitzt.", + "%cSheik t'attendra dans un %rvillage&en feu %clorsque tu auras récupéré&les médaillons de la %gForêt%c, du %rFeu&%cet de l'%bEau%c!" }, + + { "%cIf you don't have a %wsword %cas a&child, try buying %wDeku Sticks%c!&They're effective against your foes!", + "%cSolltest du als Kind kein %wSchwert&%cbesitzen, empfehle ich %wDeku Stäbe&%czu kaufen! Diese sind effektiv gegen&Widersacher!", + "%cSi tu n'as pas d'%wépée %cen tant&qu'enfant, pourquoi n'irais-tu pas&acheter quelques %wBâtons Mojo%c? Ils&sont efficaces contre tes ennemis!" } }; void CreateNaviRandoMessages() { diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 2c87a5b03..0ebb8d694 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -8,7 +8,7 @@ #include #include -#define NUM_NAVI_MESSAGES 15 +#define NUM_NAVI_MESSAGES 19 class Randomizer { private: @@ -21,8 +21,6 @@ class Randomizer { std::string ganonText; std::unordered_map randoSettings; std::unordered_map randomizerMerchantPrices; - s16 GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId); - s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId); void ParseRandomizerSettingsFile(const char* spoilerFileName); void ParseHintLocationsFile(const char* spoilerFileName); void ParseRequiredTrialsFile(const char* spoilerFileName); @@ -50,14 +48,19 @@ class Randomizer { void LoadItemLocations(const char* spoilerFileName,bool silent); bool IsTrialRequired(RandomizerInf trial); u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey); - RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams); + RandomizerCheck GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams); + RandomizerGet GetRandomizerGetFromActor(s16 actorId, s16 sceneNum, s16 actorParams); + RandomizerGet GetRandomizerGetFromKnownCheck(RandomizerCheck randomizerCheck); std::string GetChildAltarText() const; std::string GetAdultAltarText() const; std::string GetGanonText() const; std::string GetGanonHintText() const; ScrubIdentity IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); - s16 GetRandomizedItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); - s16 GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); + GetItemID GetItemIdFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogItemId); + GetItemID GetItemIdFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogItemId); + GetItemID GetItemIdFromRandomizerGet(RandomizerGet randoGet, GetItemID ogItemId); + ItemObtainability GetItemObtainabilityFromRandomizerCheck(RandomizerCheck randomizerCheck); + ItemObtainability GetItemObtainabilityFromRandomizerGet(RandomizerGet randomizerCheck); static void CreateCustomMessages(); static std::string RandomizeRupeeName(std::string message, int language); static CustomMessageEntry GetRupeeMessage(u16 rupeeTextId); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index a7eb97aa8..cc9d7930e 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1021,8 +1021,18 @@ typedef enum { RSK_BLUE_FIRE_ARROWS, RSK_SUNLIGHT_ARROWS, RSK_BOMBCHUS_IN_LOGIC + RSK_BOMBCHUS_IN_LOGIC, + RSK_LINKS_POCKET } RandomizerSettingKey; +typedef enum { + CAN_OBTAIN, + CANT_OBTAIN_MISC, + CANT_OBTAIN_ALREADY_HAVE, + CANT_OBTAIN_NEED_UPGRADE, + CANT_OBTAIN_NEED_EMPTY_BOTTLE, +} ItemObtainability; + typedef struct ScrubIdentity { RandomizerInf randomizerInf; RandomizerCheck randomizerCheck; diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp index 67327985b..0f3031887 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_objects.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include /* typedef struct { diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 8cede9a66..3696fa67f 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -1,14 +1,13 @@ #include "randomizer_item_tracker.h" #include "../../util.h" -#include "../libultraship/ImGuiImpl.h" -#include "../libultraship/Hooks.h" -#include "../libultraship/UltraController.h" -#include "../debugger/ImGuiHelpers.h" +#include +#include "../../UIWidgets.hpp" #include #include #include -#include +#include +#include extern "C" { #include @@ -351,7 +350,7 @@ void DrawEquip(ItemTrackerItem item) { ImGui::Image(SohImGui::GetTextureByName(hasEquip && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); - SetLastItemHoverText(SohUtils::GetItemName(item.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id)); } void DrawQuest(ItemTrackerItem item) { @@ -367,7 +366,7 @@ void DrawQuest(ItemTrackerItem item) { ImGui::EndGroup(); - SetLastItemHoverText(SohUtils::GetQuestItemName(item.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(item.id)); }; void DrawItem(ItemTrackerItem item) { @@ -418,7 +417,7 @@ void DrawItem(ItemTrackerItem item) { DrawItemCount(item); ImGui::EndGroup(); - SetLastItemHoverText(SohUtils::GetItemName(item.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id)); } void DrawBottle(ItemTrackerItem item) { @@ -433,7 +432,7 @@ void DrawBottle(ItemTrackerItem item) { ImGui::Image(SohImGui::GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1)); - SetLastItemHoverText(SohUtils::GetItemName(item.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id)); }; void DrawDungeonItem(ItemTrackerItem item) { @@ -471,7 +470,7 @@ void DrawDungeonItem(ItemTrackerItem item) { } ImGui::EndGroup(); - SetLastItemHoverText(SohUtils::GetItemName(item.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id)); } void DrawSong(ItemTrackerItem item) { @@ -482,7 +481,7 @@ void DrawSong(ItemTrackerItem item) { ImGui::SetCursorScreenPos(ImVec2(p.x + 6, p.y)); ImGui::Image(SohImGui::GetTextureByName(hasSong && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize / 1.5, iconSize), ImVec2(0, 0), ImVec2(1, 1)); - SetLastItemHoverText(SohUtils::GetQuestItemName(item.id)); + UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(item.id)); } void DrawNotes(bool resizeable = false) { @@ -647,7 +646,7 @@ void LabeledComboBoxRightAligned(const char* label, const char* cvar, std::vecto for (int i = 0; i < options.size(); i++) { if (ImGui::Selectable(options[i].c_str())) { CVar_SetS32(cvar, i); - SohImGui::needs_save = true; + SohImGui::RequestCvarSaveOnNextTick(); shouldUpdateVectors = true; } } @@ -664,7 +663,7 @@ void PaddedEnhancementCheckbox(const char* text, const char* cvarName, s32 defau bool val = (bool)CVar_GetS32(cvarName, defaultValue); if (ImGui::Checkbox(text, &val)) { CVar_SetS32(cvarName, val); - SohImGui::needs_save = true; + SohImGui::RequestCvarSaveOnNextTick(); shouldUpdateVectors = true; } if (padBottom) { @@ -858,7 +857,7 @@ void DrawItemTrackerOptions(bool& open) { CVar_SetFloat("gItemTrackerBgColorG", ChromaKeyBackground.y); CVar_SetFloat("gItemTrackerBgColorB", ChromaKeyBackground.z); CVar_SetFloat("gItemTrackerBgColorA", ChromaKeyBackground.w); - SohImGui::needs_save = true; + SohImGui::RequestCvarSaveOnNextTick(); } ImGui::PopItemWidth(); @@ -873,9 +872,9 @@ void DrawItemTrackerOptions(bool& open) { LabeledComboBoxRightAligned("Combo Button 2", "gItemTrackerComboButton2", { "A", "B", "C-Up", "C-Down", "C-Left", "C-Right", "L", "Z", "R", "Start", "D-Up", "D-Down", "D-Left", "D-Right" }, 8); } } - PaddedSeparator(); - SohImGui::EnhancementSliderInt("Icon size : %dpx", "##ITEMTRACKERICONSIZE", "gItemTrackerIconSize", 25, 128, "", 36, true); - SohImGui::EnhancementSliderInt("Icon margins : %dpx", "##ITEMTRACKERSPACING", "gItemTrackerIconSpacing", -5, 50, "", 12, true); + UIWidgets::PaddedSeparator(); + UIWidgets::EnhancementSliderInt("Icon size : %dpx", "##ITEMTRACKERICONSIZE", "gItemTrackerIconSize", 25, 128, "", 36, true); + UIWidgets::EnhancementSliderInt("Icon margins : %dpx", "##ITEMTRACKERSPACING", "gItemTrackerIconSpacing", -5, 50, "", 12, true); PaddedEnhancementCheckbox("Display \"Current/Max\" values", "gItemTrackerDisplayCurrentMax", 0); if (CVar_GetS32("gItemTrackerDisplayCurrentMax", 0) == 0) { PaddedEnhancementCheckbox("Align count to left side", "gItemTrackerCurrentOnLeft", 0); diff --git a/soh/soh/Enhancements/savestates.cpp b/soh/soh/Enhancements/savestates.cpp index 37856aa81..4296ce869 100644 --- a/soh/soh/Enhancements/savestates.cpp +++ b/soh/soh/Enhancements/savestates.cpp @@ -1,6 +1,6 @@ #include "savestates.h" -#include "GameVersions.h" +#include #include // std::sprintf @@ -9,7 +9,7 @@ #include #include -#include +#include #include "z64.h" #include "z64save.h" @@ -823,7 +823,7 @@ extern "C" void ProcessSaveStateRequests(void) { } void SaveStateMgr::SetCurrentSlot(unsigned int slot) { - SohImGui::overlay->TextDrawNotification(1.0f, true, "slot %u set", slot); + SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "slot %u set", slot); this->currentSlot = slot; } @@ -841,12 +841,12 @@ void SaveStateMgr::ProcessSaveStateRequests(void) { this->states[request.slot] = std::make_shared(OTRGlobals::Instance->gSaveStateMgr, request.slot); } this->states[request.slot]->Save(); - SohImGui::overlay->TextDrawNotification(1.0f, true, "saved state %u", request.slot); + SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "saved state %u", request.slot); break; case RequestType::LOAD: if (this->states.contains(request.slot)) { this->states[request.slot]->Load(); - SohImGui::overlay->TextDrawNotification(1.0f, true, "loaded state %u", request.slot); + SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "loaded state %u", request.slot); } else { SPDLOG_ERROR("Invalid SaveState slot: {}", request.type); } @@ -862,7 +862,7 @@ void SaveStateMgr::ProcessSaveStateRequests(void) { SaveStateReturn SaveStateMgr::AddRequest(const SaveStateRequest request) { if (gGlobalCtx == nullptr) { SPDLOG_ERROR("[SOH] Can not save or load a state outside of \"GamePlay\""); - SohImGui::overlay->TextDrawNotification(1.0f, true, "states not available here", request.slot); + SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "states not available here", request.slot); return SaveStateReturn::FAIL_WRONG_GAMESTATE; } @@ -876,7 +876,7 @@ SaveStateReturn SaveStateMgr::AddRequest(const SaveStateRequest request) { return SaveStateReturn::SUCCESS; } else { SPDLOG_ERROR("Invalid SaveState slot: {}", request.type); - SohImGui::overlay->TextDrawNotification(1.0f, true, "state slot %u empty", request.slot); + SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "state slot %u empty", request.slot); return SaveStateReturn::FAIL_INVALID_SLOT; } [[unlikely]] default: diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp new file mode 100644 index 000000000..26b4b1ffb --- /dev/null +++ b/soh/soh/GameMenuBar.cpp @@ -0,0 +1,1400 @@ +// +// GameMenuBar.cpp +// soh +// +// Created by David Chavez on 24.08.22. +// + +#include "GameMenuBar.hpp" + +#include +#include +#define IMGUI_DEFINE_MATH_OPERATORS +#include +#include +#include +#include +#include +#include +#include + +#ifdef __SWITCH__ +#include +#endif + +#include "UIWidgets.hpp" +#include "include/z64audio.h" + +#define EXPERIMENTAL() \ + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 50, 50, 255)); \ + UIWidgets::Spacer(3.0f); \ + ImGui::Text("Experimental"); \ + ImGui::PopStyleColor(); \ + UIWidgets::PaddedSeparator(false, true); + +bool isBetaQuestEnabled = false; + +extern "C" { + void enableBetaQuest() { isBetaQuestEnabled = true; } + void disableBetaQuest() { isBetaQuestEnabled = false; } +} + +enum SeqPlayers { + /* 0 */ SEQ_BGM_MAIN, + /* 1 */ SEQ_FANFARE, + /* 2 */ SEQ_SFX, + /* 3 */ SEQ_BGM_SUB, + /* 4 */ SEQ_MAX +}; + +namespace GameMenuBar { + + // MARK: - Properties + + const char* powers[9] = { + "Vanilla (1x)", + "Double (2x)", + "Quadruple (4x)", + "Octuple (8x)", + "Hexadecuple (16x)", + "Duotrigintuple (32x)", + "Quattuorsexagintuple (64x)", + "Octoviginticentuple (128x)", + "Hexaquinquagintiducentuple (256x)" + }; + + // MARK: - Helpers + + std::string GetWindowButtonText(const char* text, bool menuOpen) { + char buttonText[100] = ""; + if(menuOpen) { strcat(buttonText,"> "); } + strcat(buttonText, text); + if (!menuOpen) { strcat(buttonText, " "); } + return buttonText; + } + + void BindAudioSlider(const char* name, const char* key, float defaultValue, SeqPlayers playerId) { + float value = CVar_GetFloat(key, defaultValue); + + ImGui::Text(name, static_cast(100 * value)); + if (ImGui::SliderFloat((std::string("##") + key).c_str(), &value, 0.0f, 1.0f, "")) { + const float volume = floorf(value * 100) / 100; + CVar_SetFloat(key, volume); + SohImGui::RequestCvarSaveOnNextTick(); + Audio_SetGameVolume(playerId, volume); + } + } + + void UpdateAudio() { + Audio_SetGameVolume(SEQ_BGM_MAIN, CVar_GetFloat("gMainMusicVolume", 1)); + Audio_SetGameVolume(SEQ_BGM_SUB, CVar_GetFloat("gSubMusicVolume", 1)); + Audio_SetGameVolume(SEQ_FANFARE, CVar_GetFloat("gSFXMusicVolume", 1)); + Audio_SetGameVolume(SEQ_SFX, CVar_GetFloat("gFanfareVolume", 1)); + } + + void applyEnhancementPresetDefault(void) { + // D-pad Support on Pause and File Select + CVar_SetS32("gDpadPauseName", 0); + // D-pad Support in Ocarina and Text Choice + CVar_SetS32("gDpadOcarinaText", 0); + // D-pad Support for Browsing Shop Items + CVar_SetS32("gDpadShop", 0); + // D-pad as Equip Items + CVar_SetS32("gDpadEquips", 0); + // Allow the cursor to be on any slot + CVar_SetS32("gPauseAnyCursor", 0); + // Prevent Dropped Ocarina Inputs + CVar_SetS32("gDpadNoDropOcarinaInput", 0); + // Answer Navi Prompt with L Button + CVar_SetS32("gNaviOnL", 0); + + // Text Speed (1 to 5) + CVar_SetS32("gTextSpeed", 1); + // King Zora Speed (1 to 5) + CVar_SetS32("gMweepSpeed", 1); + // Biggoron Forge Time (0 to 3) + CVar_SetS32("gForgeTime", 3); + // Vine/Ladder Climb speed (+0 to +12) + CVar_SetS32("gClimbSpeed", 0); + // Faster Block Push (+0 to +5) + CVar_SetS32("gFasterBlockPush", 0); + // Faster Heavy Block Lift + CVar_SetS32("gFasterHeavyBlockLift", 0); + // No Forced Navi + CVar_SetS32("gNoForcedNavi", 0); + // No Skulltula Freeze + CVar_SetS32("gSkulltulaFreeze", 0); + // MM Bunny Hood + CVar_SetS32("gMMBunnyHood", 0); + // Fast Chests + CVar_SetS32("gFastChests", 0); + // Fast Drops + CVar_SetS32("gFastDrops", 0); + // Better Owl + CVar_SetS32("gBetterOwl", 0); + // Fast Ocarina Playback + CVar_SetS32("gFastOcarinaPlayback", 0); + // Instant Putaway + CVar_SetS32("gInstantPutaway", 0); + // Instant Boomerang Recall + CVar_SetS32("gFastBoomerang", 0); + // Mask Select in Inventory + CVar_SetS32("gMaskSelect", 0); + // Remember Save Location + CVar_SetS32("gRememberSaveLocation", 0); + + // Damage Multiplier (0 to 8) + CVar_SetS32("gDamageMul", 0); + // Fall Damage Multiplier (0 to 7) + CVar_SetS32("gFallDamageMul", 0); + // Void Damage Multiplier (0 to 6) + CVar_SetS32("gVoidDamageMul", 0); + // No Random Drops + CVar_SetS32("gNoRandomDrops", 0); + // No Heart Drops + CVar_SetS32("gNoHeartDrops", 0); + // Enable Bombchu Drops + CVar_SetS32("gBombchuDrops", 0); + // Always Win Goron Pot + CVar_SetS32("gGoronPot", 0); + + // Change Red Potion Effect + CVar_SetS32("gRedPotionEffect", 0); + // Red Potion Health (1 to 100) + CVar_SetS32("gRedPotionHealth", 1); + // Red Potion Percent Restore + CVar_SetS32("gRedPercentRestore", 0); + // Change Green Potion Effect + CVar_SetS32("gGreenPotionEffect", 0); + // Green Potion Mana (1 to 100) + CVar_SetS32("gGreenPotionMana", 1); + // Green Potion Percent Restore + CVar_SetS32("gGreenPercentRestore", 0); + // Change Blue Potion Effects + CVar_SetS32("gBluePotionEffects", 0); + // Blue Potion Health (1 to 100) + CVar_SetS32("gBluePotionHealth", 1); + // Blue Potion Health Percent Restore + CVar_SetS32("gBlueHealthPercentRestore", 0); + // Blue Potion Mana (1 to 100) + CVar_SetS32("gBluePotionMana", 1); + // Blue Potion Mana Percent Restore + CVar_SetS32("gBlueManaPercentRestore", 0); + // Change Milk Effect + CVar_SetS32("gMilkEffect", 0); + // Milk Health (1 to 100) + CVar_SetS32("gMilkHealth", 1); + // Milk Percent Restore + CVar_SetS32("gMilkPercentRestore", 0); + // Separate Half Milk Effect + CVar_SetS32("gSeparateHalfMilkEffect", 0); + // Half Milk Health (1 to 100) + CVar_SetS32("gHalfMilkHealth", 0); + // Half Milk Percent Restore + CVar_SetS32("gHalfMilkPercentRestore", 0); + // Change Fairy Effect + CVar_SetS32("gFairyEffect", 0); + // Fairy (1 to 100) + CVar_SetS32("gFairyHealth", 1); + // Fairy Percent Restore + CVar_SetS32("gFairyPercentRestore", 0); + // Change Fairy Revive Effect + CVar_SetS32("gFairyReviveEffect", 0); + // Fairy Revival (1 to 100) + CVar_SetS32("gFairyReviveHealth", 1); + // Fairy Revive Percent Restore + CVar_SetS32("gFairyRevivePercentRestore", 0); + + // Instant Fishing + CVar_SetS32("gInstantFishing", 0); + // Guarantee Bite + CVar_SetS32("gGuaranteeFishingBite", 0); + // Child Minimum Weight (6 to 10) + CVar_SetS32("gChildMinimumWeightFish", 10); + // Adult Minimum Weight (8 to 13) + CVar_SetS32("gAdultMinimumWeightFish", 13); + + // Mute Low HP Alarm + CVar_SetS32("gLowHpAlarm", 0); + // Minimal UI + CVar_SetS32("gMinimalUI", 0); + // Disable Navi Call Audio + CVar_SetS32("gDisableNaviCallAudio", 0); + + // Visual Stone of Agony + CVar_SetS32("gVisualAgony", 0); + // Assignable Tunics and Boots + CVar_SetS32("gAssignableTunicsAndBoots", 0); + // Equipment Toggle + CVar_SetS32("gEquipmentCanBeRemoved", 0); + // Link's Cow in Both Time Periods + CVar_SetS32("gCowOfTime", 0); + // Enable visible guard vision + CVar_SetS32("gGuardVision", 0); + // Enable passage of time on file select + CVar_SetS32("gTimeFlowFileSelect", 0); + // Count Golden Skulltulas + CVar_SetS32("gInjectSkulltulaCount", 0); + // Pull grave during the day + CVar_SetS32("gDayGravePull", 0); + + // Rotate link (0 to 2) + CVar_SetS32("gPauseLiveLinkRotation", 0); + // Pause link animation (0 to 16) + CVar_SetS32("gPauseLiveLink", 0); + // Frames to wait + CVar_SetS32("gMinFrameCount", 1); + + // N64 Mode + CVar_SetS32("gN64Mode", 0); + // Enable 3D Dropped items/projectiles + CVar_SetS32("gNewDrops", 0); + // Disable Black Bar Letterboxes + CVar_SetS32("gDisableBlackBars", 0); + // Dynamic Wallet Icon + CVar_SetS32("gDynamicWalletIcon", 0); + // Always show dungeon entrances + CVar_SetS32("gAlwaysShowDungeonMinimapIcon", 0); + + // Fix L&R Pause menu + CVar_SetS32("gUniformLR", 0); + // Fix L&Z Page switch in Pause menu + CVar_SetS32("gNGCKaleidoSwitcher", 0); + // Fix Dungeon entrances + CVar_SetS32("gFixDungeonMinimapIcon", 0); + // Fix Two Handed idle animations + CVar_SetS32("gTwoHandedIdle", 0); + // Fix the Gravedigging Tour Glitch + CVar_SetS32("gGravediggingTourFix", 0); + // Fix Deku Nut upgrade + CVar_SetS32("gDekuNutUpgradeFix", 0); + // Fix Navi text HUD position + CVar_SetS32("gNaviTextFix", 0); + // Fix Anubis fireballs + CVar_SetS32("gAnubisFix", 0); + // Fix Megaton Hammer crouch stab + CVar_SetS32("gCrouchStabHammerFix", 0); + // Fix all crouch stab + CVar_SetS32("gCrouchStabFix", 0); + + // Red Ganon blood + CVar_SetS32("gRedGanonBlood", 0); + // Fish while hovering + CVar_SetS32("gHoverFishing", 0); + // N64 Weird Frames + CVar_SetS32("gN64WeirdFrames", 0); + // Bombchus out of bounds + CVar_SetS32("gBombchusOOB", 0); + + CVar_SetS32("gGsCutscene", 0); + // Autosave + CVar_SetS32("gAutosave", 0); + } + + void applyEnhancementPresetVanillaPlus(void) { + // D-pad Support in Ocarina and Text Choice + CVar_SetS32("gDpadOcarinaText", 1); + // D-pad Support for Browsing Shop Items + CVar_SetS32("gDpadShop", 1); + // D-pad as Equip Items + CVar_SetS32("gDpadEquips", 1); + // Prevent Dropped Ocarina Inputs + CVar_SetS32("gDpadNoDropOcarinaInput", 1); + + // Text Speed (1 to 5) + CVar_SetS32("gTextSpeed", 5); + // King Zora Speed (1 to 5) + CVar_SetS32("gMweepSpeed", 2); + // Faster Block Push (+0 to +5) + CVar_SetS32("gFasterBlockPush", 5); + // Better Owl + CVar_SetS32("gBetterOwl", 1); + + // Assignable Tunics and Boots + CVar_SetS32("gAssignableTunicsAndBoots", 1); + // Enable passage of time on file select + CVar_SetS32("gTimeFlowFileSelect", 1); + // Count Golden Skulltulas + CVar_SetS32("gInjectSkulltulaCount", 1); + + // Pause link animation (0 to 16) + CVar_SetS32("gPauseLiveLink", 1); + + // Dynamic Wallet Icon + CVar_SetS32("gDynamicWalletIcon", 1); + // Always show dungeon entrances + CVar_SetS32("gAlwaysShowDungeonMinimapIcon", 1); + + // Fix L&R Pause menu + CVar_SetS32("gUniformLR", 1); + // Fix Dungeon entrances + CVar_SetS32("gFixDungeonMinimapIcon", 1); + // Fix Two Handed idle animations + CVar_SetS32("gTwoHandedIdle", 1); + // Fix the Gravedigging Tour Glitch + CVar_SetS32("gGravediggingTourFix", 1); + // Fix Deku Nut upgrade + CVar_SetS32("gDekuNutUpgradeFix", 1); + + // Red Ganon blood + CVar_SetS32("gRedGanonBlood", 1); + // Fish while hovering + CVar_SetS32("gHoverFishing", 1); + // N64 Weird Frames + CVar_SetS32("gN64WeirdFrames", 1); + // Bombchus out of bounds + CVar_SetS32("gBombchusOOB", 1); + } + + void applyEnhancementPresetEnhanced(void) { + // King Zora Speed (1 to 5) + CVar_SetS32("gMweepSpeed", 5); + // Biggoron Forge Time (0 to 3) + CVar_SetS32("gForgeTime", 0); + // Vine/Ladder Climb speed (+0 to +12) + CVar_SetS32("gClimbSpeed", 1); + // Faster Heavy Block Lift + CVar_SetS32("gFasterHeavyBlockLift", 1); + // No Forced Navi + CVar_SetS32("gNoForcedNavi", 1); + // No Skulltula Freeze + CVar_SetS32("gSkulltulaFreeze", 1); + // MM Bunny Hood + CVar_SetS32("gMMBunnyHood", 1); + // Fast Chests + CVar_SetS32("gFastChests", 1); + // Fast Drops + CVar_SetS32("gFastDrops", 1); + // Fast Ocarina Playback + CVar_SetS32("gFastOcarinaPlayback", 1); + // Instant Putaway + CVar_SetS32("gInstantPutaway", 1); + // Instant Boomerang Recall + CVar_SetS32("gFastBoomerang", 1); + // Mask Select in Inventory + CVar_SetS32("gMaskSelect", 1); + + // Disable Navi Call Audio + CVar_SetS32("gDisableNaviCallAudio", 1); + + // Equipment Toggle + CVar_SetS32("gEquipmentCanBeRemoved", 1); + // Count Golden Skulltulas + CVar_SetS32("gInjectSkulltulaCount", 1); + + // Enable 3D Dropped items/projectiles + CVar_SetS32("gNewDrops", 1); + + // Fix Anubis fireballs + CVar_SetS32("gAnubisFix", 1); + } + + void applyEnhancementPresetRandomizer(void) { + // Allow the cursor to be on any slot + CVar_SetS32("gPauseAnyCursor", 1); + + // Instant Fishing + CVar_SetS32("gInstantFishing", 1); + // Guarantee Bite + CVar_SetS32("gGuaranteeFishingBite", 1); + // Child Minimum Weight (6 to 10) + CVar_SetS32("gChildMinimumWeightFish", 6); + // Adult Minimum Weight (8 to 13) + CVar_SetS32("gAdultMinimumWeightFish", 8); + + // Visual Stone of Agony + CVar_SetS32("gVisualAgony", 1); + // Pull grave during the day + CVar_SetS32("gDayGravePull", 1); + // Pull out Ocarina to Summon Scarecrow + CVar_SetS32("gSkipScarecrow", 0); + + // Pause link animation (0 to 16) + CVar_SetS32("gPauseLiveLink", 16); + // Frames to wait + CVar_SetS32("gMinFrameCount", 200); + } + + void applyEnhancementPresets(void) { + switch (CVar_GetS32("gSelectEnhancementPresets", 0)) { + // Default + case 0: + applyEnhancementPresetDefault(); + break; + + // Vanilla Plus + case 1: + applyEnhancementPresetDefault(); + applyEnhancementPresetVanillaPlus(); + break; + + // Enhanced + case 2: + applyEnhancementPresetDefault(); + applyEnhancementPresetVanillaPlus(); + applyEnhancementPresetEnhanced(); + break; + + // Randomizer + case 3: + applyEnhancementPresetDefault(); + applyEnhancementPresetVanillaPlus(); + applyEnhancementPresetEnhanced(); + applyEnhancementPresetRandomizer(); + break; + } + } + + // MARK: - Delegates + + void SetupHooks() { + Ship::RegisterHook(UpdateAudio); + Ship::RegisterHook(UpdateAudio); + } + + void Draw() { + if (ImGui::BeginMenu("Settings")) + { + if (ImGui::BeginMenu("Audio")) { + UIWidgets::EnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, 1.0f, "", 1.0f, true); + UIWidgets::Spacer(0); + BindAudioSlider("Main Music Volume: %d %%", "gMainMusicVolume", 1.0f, SEQ_BGM_MAIN); + UIWidgets::Spacer(0); + BindAudioSlider("Sub Music Volume: %d %%", "gSubMusicVolume", 1.0f, SEQ_BGM_SUB); + UIWidgets::Spacer(0); + BindAudioSlider("Sound Effects Volume: %d %%", "gSFXMusicVolume", 1.0f, SEQ_SFX); + UIWidgets::Spacer(0); + BindAudioSlider("Fanfare Volume: %d %%", "gFanfareVolume", 1.0f, SEQ_FANFARE); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Controller")) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2 (12.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + if (ImGui::Button(GetWindowButtonText("Controller Configuration", CVar_GetS32("gControllerConfigurationEnabled", 0)).c_str())) + { + bool currentValue = CVar_GetS32("gControllerConfigurationEnabled", 0); + CVar_SetS32("gControllerConfigurationEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::ToggleInputEditorWindow(CVar_GetS32("gControllerConfigurationEnabled", 0)); + } + ImGui::PopStyleColor(1); + ImGui::PopStyleVar(3); + #ifndef __SWITCH__ + UIWidgets::PaddedEnhancementCheckbox("Use Controller Navigation", "gControlNav", true, false); + UIWidgets::Tooltip("Allows controller navigation of the menu bar\nD-pad to move between items, A to select, and X to grab focus on the menu bar"); + #endif + UIWidgets::PaddedEnhancementCheckbox("Show Inputs", "gInputEnabled", true, false); + UIWidgets::Tooltip("Shows currently pressed inputs on the bottom right of the screen"); + UIWidgets::Spacer(0); + ImGui::PushItemWidth(ImGui::GetWindowSize().x - 20.0f); + UIWidgets::EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false); + UIWidgets::Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting"); + ImGui::PopItemWidth(); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Graphics")) { + #ifndef __APPLE__ + UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, "", 1.0f, true, true); + UIWidgets::Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective form of anti-aliasing"); + SohImGui::SetResolutionMultiplier(CVar_GetFloat("gInternalResolution", 1)); + #endif + #ifndef __WIIU__ + UIWidgets::PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "", 1, false, true, false); + UIWidgets::Tooltip("Activates multi-sample anti-aliasing when above 1x up to 8x for 8 samples for every pixel"); + SohImGui::SetMSAALevel(CVar_GetS32("gMSAAValue", 1)); + #endif + + if (SohImGui::WindowBackend() == SohImGui::Backend::DX11) + { + const char* cvar = "gExtraLatencyThreshold"; + int val = CVar_GetS32(cvar, 80); + val = fmax(fmin(val, 360), 0); + int fps = val; + + UIWidgets::Spacer(0); + + if (fps == 0) + { + ImGui::Text("Jitter fix: Off"); + } + else + { + ImGui::Text("Jitter fix: >= %d FPS", fps); + } + + std::string MinusBTNELT = " - ##ExtraLatencyThreshold"; + std::string PlusBTNELT = " + ##ExtraLatencyThreshold"; + if (ImGui::Button(MinusBTNELT.c_str())) { + val--; + CVar_SetS32(cvar, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f); + if (ImGui::SliderInt("##ExtraLatencyThreshold", &val, 0, 360, "", ImGuiSliderFlags_AlwaysClamp)) + { + CVar_SetS32(cvar, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::PopItemWidth(); + UIWidgets::Tooltip("When Interpolation FPS setting is at least this threshold, add one frame of input lag (e.g. 16.6 ms for 60 FPS) in order to avoid jitter. This setting allows the CPU to work on one frame while GPU works on the previous frame.\nThis setting should be used when your computer is too slow to do CPU + GPU work in time."); + + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + if (ImGui::Button(PlusBTNELT.c_str())) { + val++; + CVar_SetS32(cvar, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + + UIWidgets::Spacer(0); + } + + ImGui::Text("Renderer API (Needs reload)"); + auto backends = SohImGui::GetAvailableRenderingBackends(); + auto currentBackend = SohImGui::GetCurrentRenderingBackend(); + + if (ImGui::BeginCombo("##RApi", currentBackend.second)) { + for (uint8_t i = 0; i < sizeof(backends) / sizeof(backends[0]); i++) { + if (ImGui::Selectable(backends[i].second, backends[i] == currentBackend)) { + SohImGui::SetCurrentRenderingBackend(i, backends[i]); + } + } + + ImGui::EndCombo(); + } + + EXPERIMENTAL(); + + ImGui::Text("Texture Filter (Needs reload)"); + UIWidgets::EnhancementCombobox("gTextureFilter", SohImGui::GetSupportedTextureFilters(), 3, 0); + + UIWidgets::Spacer(0); + + SohImGui::DrawSettings(); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Languages")) { + UIWidgets::EnhancementRadioButton("English", "gLanguages", 0); + UIWidgets::EnhancementRadioButton("German", "gLanguages", 1); + UIWidgets::EnhancementRadioButton("French", "gLanguages", 2); + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + + ImGui::SetCursorPosY(0.0f); + + if (ImGui::BeginMenu("Enhancements")) + { + + const char* enhancementPresets[4] = { "Default", "Vanilla Plus", "Enhanced", "Randomizer"}; + UIWidgets::PaddedText("Enhancement Presets", false, true); + UIWidgets::EnhancementCombobox("gSelectEnhancementPresets", enhancementPresets, 4, 0); + UIWidgets::Tooltip( + "Default - Set all enhancements to their default values. The true vanilla SoH experience.\n" + "\n" + "Vanilla Plus - Adds Quality of Life features that enhance your experience, but don't alter gameplay. Recommended for a first playthrough of OoT.\n" + "\n" + "Enhanced - The \"Vanilla Plus\" preset, but with more quality of life enhancements that might alter gameplay slightly. Recommended for returning players.\n" + "\n" + "Randomizer - The \"Enhanced\" preset, plus any other enhancements that are recommended for playing Randomizer." + ); + + UIWidgets::Spacer(0); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f)); + if (ImGui::Button("Apply Preset")) { + applyEnhancementPresets(); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::PopStyleVar(1); + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Controls")) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + float availableWidth = ImGui::GetContentRegionAvail().x; + if (ImGui::Button( + GetWindowButtonText("Customize Game Controls", CVar_GetS32("gGameControlEditorEnabled", 0)).c_str(), + ImVec2(availableWidth, 0) + )) { + bool currentValue = CVar_GetS32("gGameControlEditorEnabled", 0); + CVar_SetS32("gGameControlEditorEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Game Control Editor", CVar_GetS32("gGameControlEditorEnabled", 0)); + } + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(1); + + // TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected + UIWidgets::PaddedEnhancementCheckbox("D-pad Support on Pause and File Select", "gDpadPauseName"); + UIWidgets::Tooltip("Enables Pause and File Select screen navigation with the D-pad\nIf used with D-pad as Equip Items, you must hold C-Up to equip instead of navigate"); + UIWidgets::PaddedEnhancementCheckbox("D-pad Support in Text Choice", "gDpadText", true, false); + UIWidgets::PaddedEnhancementCheckbox("D-pad Support for Browsing Shop Items", "gDpadShop", true, false); + UIWidgets::PaddedEnhancementCheckbox("D-pad as Equip Items", "gDpadEquips", true, false); + UIWidgets::Tooltip("Allows the D-pad to be used as extra C buttons"); + UIWidgets::PaddedEnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor", true, false); + UIWidgets::Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97"); + UIWidgets::PaddedEnhancementCheckbox("Prevent Dropped Ocarina Inputs", "gDpadNoDropOcarinaInput", true, false); + UIWidgets::Tooltip("Prevent dropping inputs when playing the ocarina quickly"); + UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL", true, false); + UIWidgets::Tooltip("Speak to Navi with L but enter first-person camera with C-Up"); + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Gameplay")) + { + if (ImGui::BeginMenu("Time Savers")) + { + UIWidgets::PaddedEnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, "", 1, false, false, true); + UIWidgets::PaddedEnhancementSliderInt("King Zora Speed: %dx", "##MWEEPSPEED", "gMweepSpeed", 1, 5, "", 1, false, false, true); + UIWidgets::EnhancementSliderInt("Biggoron Forge Time: %d days", "##FORGETIME", "gForgeTime", 0, 3, "", 3); + UIWidgets::Tooltip("Allows you to change the number of days it takes for Biggoron to forge the Biggoron Sword"); + UIWidgets::PaddedEnhancementSliderInt("Vine/Ladder Climb speed +%d", "##CLIMBSPEED", "gClimbSpeed", 0, 12, "", 0, false, false, true); + UIWidgets::PaddedEnhancementSliderInt("Block pushing speed +%d", "##BLOCKSPEED", "gFasterBlockPush", 0, 5, "", 0, false, false, true); + UIWidgets::PaddedEnhancementCheckbox("Faster Heavy Block Lift", "gFasterHeavyBlockLift", true, false); + UIWidgets::Tooltip("Speeds up lifting silver rocks and obelisks"); + UIWidgets::PaddedEnhancementCheckbox("No Forced Navi", "gNoForcedNavi", true, false); + UIWidgets::Tooltip("Prevent forced Navi conversations"); + UIWidgets::PaddedEnhancementCheckbox("No Skulltula Freeze", "gSkulltulaFreeze", true, false); + UIWidgets::Tooltip("Stops the game from freezing the player when picking up Gold Skulltulas"); + UIWidgets::PaddedEnhancementCheckbox("MM Bunny Hood", "gMMBunnyHood", true, false); + UIWidgets::Tooltip("Wearing the Bunny Hood grants a speed increase like in Majora's Mask"); + UIWidgets::PaddedEnhancementCheckbox("Fast Chests", "gFastChests", true, false); + UIWidgets::Tooltip("Kick open every chest"); + UIWidgets::PaddedEnhancementCheckbox("Skip Pickup Messages", "gFastDrops", true, false); + UIWidgets::Tooltip("Skip pickup messages for new consumable items and bottle swipes"); + UIWidgets::PaddedEnhancementCheckbox("Better Owl", "gBetterOwl", true, false); + UIWidgets::Tooltip("The default response to Kaepora Gaebora is always that you understood what he said"); + UIWidgets::PaddedEnhancementCheckbox("Fast Ocarina Playback", "gFastOcarinaPlayback", true, false); + UIWidgets::Tooltip("Skip the part where the Ocarina playback is called when you play a song"); + UIWidgets::PaddedEnhancementCheckbox("Skip Scarecrow Song", "gSkipScarecrow", true, false); + UIWidgets::Tooltip("Pierre appears when Ocarina is pulled out. Requires learning scarecrow song."); + UIWidgets::PaddedEnhancementCheckbox("Instant Putaway", "gInstantPutaway", true, false); + UIWidgets::Tooltip("Allow Link to put items away without having to wait around"); + UIWidgets::PaddedEnhancementCheckbox("Instant Boomerang Recall", "gFastBoomerang", true, false); + UIWidgets::Tooltip("Instantly return the boomerang to Link by pressing its item button while it's in the air"); + UIWidgets::PaddedEnhancementCheckbox("Mask Select in Inventory", "gMaskSelect", true, false); + UIWidgets::Tooltip("After completing the mask trading sub-quest, press A and any direction on the mask slot to change masks"); + UIWidgets::PaddedEnhancementCheckbox("Remember Save Location", "gRememberSaveLocation", true, false); + UIWidgets::Tooltip("When loading a save, places Link at the last entrance he went through.\n" + "This doesn't work if the save was made in a grotto."); + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Difficulty Options")) + { + ImGui::Text("Damage Multiplier"); + UIWidgets::EnhancementCombobox("gDamageMul", powers, 9, 0); + UIWidgets::Tooltip( + "Modifies all sources of damage not affected by other sliders\n\ + 2x: Can survive all common attacks from the start of the game\n\ + 4x: Dies in 1 hit to any substantial attack from the start of the game\n\ + 8x: Can only survive trivial damage from the start of the game\n\ + 16x: Can survive all common attacks with max health without double defense\n\ + 32x: Can survive all common attacks with max health and double defense\n\ + 64x: Can survive trivial damage with max health without double defense\n\ + 128x: Can survive trivial damage with max health and double defense\n\ + 256x: Cannot survive damage" + ); + UIWidgets::PaddedText("Fall Damage Multiplier", true, false); + UIWidgets::EnhancementCombobox("gFallDamageMul", powers, 8, 0); + UIWidgets::Tooltip( + "Modifies all fall damage\n\ + 2x: Can survive all fall damage from the start of the game\n\ + 4x: Can only survive short fall damage from the start of the game\n\ + 8x: Cannot survive any fall damage from the start of the game\n\ + 16x: Can survive all fall damage with max health without double defense\n\ + 32x: Can survive all fall damage with max health and double defense\n\ + 64x: Can survive short fall damage with double defense\n\ + 128x: Cannot survive fall damage" + ); + UIWidgets::PaddedText("Void Damage Multiplier", true, false); + UIWidgets::EnhancementCombobox("gVoidDamageMul", powers, 7, 0); + UIWidgets::Tooltip( + "Modifies damage taken after falling into a void\n\ + 2x: Can survive void damage from the start of the game\n\ + 4x: Cannot survive void damage from the start of the game\n\ + 8x: Can survive void damage twice with max health without double defense\n\ + 16x: Can survive void damage with max health without double defense\n\ + 32x: Can survive void damage with max health and double defense\n\ + 64x: Cannot survive void damage" + ); + UIWidgets::PaddedEnhancementCheckbox("No Random Drops", "gNoRandomDrops", true, false); + UIWidgets::Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses"); + UIWidgets::PaddedEnhancementCheckbox("Enable Bombchu Drops", "gBombchuDrops", true, false); + UIWidgets::Tooltip("Bombchus will sometimes drop in place of bombs"); + UIWidgets::PaddedEnhancementCheckbox("No Heart Drops", "gNoHeartDrops", true, false); + UIWidgets::Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series"); + UIWidgets::PaddedEnhancementCheckbox("Always Win Goron Pot", "gGoronPot", true, false); + UIWidgets::Tooltip("Always get the heart piece/purple rupee from the spinning Goron pot"); + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Potion Values")) + { + UIWidgets::EnhancementCheckbox("Change Red Potion Effect", "gRedPotionEffect"); + UIWidgets::Tooltip("Enable the following changes to the amount of health restored by Red Potions"); + UIWidgets::EnhancementSliderInt("Red Potion Health: %d", "##REDPOTIONHEALTH", "gRedPotionHealth", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of health restored by Red Potions"); + UIWidgets::EnhancementCheckbox("Red Potion Percent Restore", "gRedPercentRestore"); + UIWidgets::Tooltip("Toggles from Red Potions restoring a fixed amount of health to a percent of the player's current max health"); + + ImGui::Separator(); + + UIWidgets::EnhancementCheckbox("Change Green Potion Effect", "gGreenPotionEffect"); + UIWidgets::Tooltip("Enable the following changes to the amount of mana restored by Green Potions"); + UIWidgets::EnhancementSliderInt("Green Potion Mana: %d", "##GREENPOTIONMANA", "gGreenPotionMana", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of mana restored by Green Potions, base max mana is 48, max upgraded mana is 96"); + UIWidgets::EnhancementCheckbox("Green Potion Percent Restore", "gGreenPercentRestore"); + UIWidgets::Tooltip("Toggles from Green Potions restoring a fixed amount of mana to a percent of the player's current max mana"); + + ImGui::Separator(); + + UIWidgets::EnhancementCheckbox("Change Blue Potion Effects", "gBluePotionEffects"); + UIWidgets::Tooltip("Enable the following changes to the amount of health and mana restored by Blue Potions"); + UIWidgets::EnhancementSliderInt("Blue Potion Health: %d", "##BLUEPOTIONHEALTH", "gBluePotionHealth", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of health restored by Blue Potions"); + UIWidgets::EnhancementCheckbox("Blue Potion Health Percent Restore", "gBlueHealthPercentRestore"); + UIWidgets::Tooltip("Toggles from Blue Potions restoring a fixed amount of health to a percent of the player's current max health"); + + ImGui::Separator(); + + UIWidgets::EnhancementSliderInt("Blue Potion Mana: %d", "##BLUEPOTIONMANA", "gBluePotionMana", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of mana restored by Blue Potions, base max mana is 48, max upgraded mana is 96"); + UIWidgets::EnhancementCheckbox("Blue Potion Mana Percent Restore", "gBlueManaPercentRestore"); + UIWidgets::Tooltip("Toggles from Blue Potions restoring a fixed amount of mana to a percent of the player's current max mana"); + + ImGui::Separator(); + + UIWidgets::EnhancementCheckbox("Change Milk Effect", "gMilkEffect"); + UIWidgets::Tooltip("Enable the following changes to the amount of health restored by Milk"); + UIWidgets::EnhancementSliderInt("Milk Health: %d", "##MILKHEALTH", "gMilkHealth", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of health restored by Milk"); + UIWidgets::EnhancementCheckbox("Milk Percent Restore", "gMilkPercentRestore"); + UIWidgets::Tooltip("Toggles from Milk restoring a fixed amount of health to a percent of the player's current max health"); + + ImGui::Separator(); + + UIWidgets::EnhancementCheckbox("Separate Half Milk Effect", "gSeparateHalfMilkEffect"); + UIWidgets::Tooltip("Enable the following changes to the amount of health restored by Half Milk\nIf this is disabled, Half Milk will behave the same as Full Milk."); + UIWidgets::EnhancementSliderInt("Half Milk Health: %d", "##HALFMILKHEALTH", "gHalfMilkHealth", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of health restored by Half Milk"); + UIWidgets::EnhancementCheckbox("Half Milk Percent Restore", "gHalfMilkPercentRestore"); + UIWidgets::Tooltip("Toggles from Half Milk restoring a fixed amount of health to a percent of the player's current max health"); + + ImGui::Separator(); + + UIWidgets::EnhancementCheckbox("Change Fairy Effect", "gFairyEffect"); + UIWidgets::Tooltip("Enable the following changes to the amount of health restored by Fairies"); + UIWidgets::EnhancementSliderInt("Fairy: %d", "##FAIRYHEALTH", "gFairyHealth", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of health restored by Fairies"); + UIWidgets::EnhancementCheckbox("Fairy Percent Restore", "gFairyPercentRestore"); + UIWidgets::Tooltip("Toggles from Fairies restoring a fixed amount of health to a percent of the player's current max health"); + + ImGui::Separator(); + + UIWidgets::EnhancementCheckbox("Change Fairy Revive Effect", "gFairyReviveEffect"); + UIWidgets::Tooltip("Enable the following changes to the amount of health restored by Fairy Revivals"); + UIWidgets::EnhancementSliderInt("Fairy Revival: %d", "##FAIRYREVIVEHEALTH", "gFairyReviveHealth", 1, 100, "", 0, true); + UIWidgets::Tooltip("Changes the amount of health restored by Fairy Revivals"); + UIWidgets::EnhancementCheckbox("Fairy Revive Percent Restore", "gFairyRevivePercentRestore"); + UIWidgets::Tooltip("Toggles from Fairy Revivals restoring a fixed amount of health to a percent of the player's current max health"); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Fishing")) { + UIWidgets::EnhancementCheckbox("Instant Fishing", "gInstantFishing"); + UIWidgets::Tooltip("All fish will be caught instantly"); + UIWidgets::PaddedEnhancementCheckbox("Guarantee Bite", "gGuaranteeFishingBite", true, false); + UIWidgets::Tooltip("When a line is stable, guarantee bite. Otherwise use default logic"); + UIWidgets::PaddedEnhancementSliderInt("Child Minimum Weight: %d", "##cMinimumWeight", "gChildMinimumWeightFish", 6, 10, "", 10, false, true, false); + UIWidgets::Tooltip("The minimum weight for the unique fishing reward as a child"); + UIWidgets::PaddedEnhancementSliderInt("Adult Minimum Weight: %d", "##aMinimumWeight", "gAdultMinimumWeightFish", 8, 13, "", 13, false, true, false); + UIWidgets::Tooltip("The minimum weight for the unique fishing reward as an adult"); + ImGui::EndMenu(); + } + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Reduced Clutter")) + { + UIWidgets::EnhancementCheckbox("Mute Low HP Alarm", "gLowHpAlarm"); + UIWidgets::Tooltip("Disable the low HP beeping sound"); + UIWidgets::PaddedEnhancementCheckbox("Minimal UI", "gMinimalUI", true, false); + UIWidgets::Tooltip("Hides most of the UI when not needed\nNote: Doesn't activate until after loading a new scene"); + UIWidgets::PaddedEnhancementCheckbox("Disable Navi Call Audio", "gDisableNaviCallAudio", true, false); + UIWidgets::Tooltip("Disables the voice audio when Navi calls you"); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + UIWidgets::EnhancementCheckbox("Visual Stone of Agony", "gVisualAgony"); + UIWidgets::Tooltip("Displays an icon and plays a sound when Stone of Agony should be activated, for those without rumble"); + UIWidgets::PaddedEnhancementCheckbox("Assignable Tunics and Boots", "gAssignableTunicsAndBoots", true, false); + UIWidgets::Tooltip("Allows equipping the tunic and boots to c-buttons"); + UIWidgets::PaddedEnhancementCheckbox("Equipment Toggle", "gEquipmentCanBeRemoved", true, false); + UIWidgets::Tooltip("Allows equipment to be removed by toggling it off on\nthe equipment subscreen."); + UIWidgets::PaddedEnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime", true, false); + UIWidgets::Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods"); + UIWidgets::PaddedEnhancementCheckbox("Enable visible guard vision", "gGuardVision", true, false); + UIWidgets::PaddedEnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect", true, false); + UIWidgets::PaddedEnhancementCheckbox("Count Golden Skulltulas", "gInjectSkulltulaCount", true, false); + UIWidgets::Tooltip("Injects Golden Skulltula total count in pickup messages"); + UIWidgets::PaddedEnhancementCheckbox("Pull grave during the day", "gDayGravePull", true, false); + UIWidgets::Tooltip("Allows graves to be pulled when child during the day"); + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Graphics")) + { + if (ImGui::BeginMenu("Animated Link in Pause Menu")) { + ImGui::Text("Rotation"); + UIWidgets::EnhancementRadioButton("Disabled", "gPauseLiveLinkRotation", 0); + UIWidgets::EnhancementRadioButton("Rotate Link with D-pad", "gPauseLiveLinkRotation", 1); + UIWidgets::Tooltip("Allow you to rotate Link on the Equipment menu with the D-pad\nUse D-pad Up or D-pad Down to reset Link's rotation"); + UIWidgets::EnhancementRadioButton("Rotate Link with C-buttons", "gPauseLiveLinkRotation", 2); + UIWidgets::Tooltip("Allow you to rotate Link on the Equipment menu with the C-buttons\nUse C-Up or C-Down to reset Link's rotation"); + UIWidgets::EnhancementRadioButton("Rotate Link with Right Stick", "gPauseLiveLinkRotation", 3); + UIWidgets::Tooltip("Allow you to rotate Link on the Equipment menu with the Right Stick\nYou can zoom in by pointing up and reset Link's rotation by pointing down"); + if (CVar_GetS32("gPauseLiveLinkRotation", 0) != 0) { + UIWidgets::EnhancementSliderInt("Rotation Speed: %d", "##MinRotationSpeed", "gPauseLiveLinkRotationSpeed", 1, 20, ""); + } + UIWidgets::PaddedSeparator(); + ImGui::Text("Static loop"); + UIWidgets::EnhancementRadioButton("Disabled", "gPauseLiveLink", 0); + UIWidgets::EnhancementRadioButton("Idle (standing)", "gPauseLiveLink", 1); + UIWidgets::EnhancementRadioButton("Idle (look around)", "gPauseLiveLink", 2); + UIWidgets::EnhancementRadioButton("Idle (belt)", "gPauseLiveLink", 3); + UIWidgets::EnhancementRadioButton("Idle (shield)", "gPauseLiveLink", 4); + UIWidgets::EnhancementRadioButton("Idle (test sword)", "gPauseLiveLink", 5); + UIWidgets::EnhancementRadioButton("Idle (yawn)", "gPauseLiveLink", 6); + UIWidgets::EnhancementRadioButton("Battle Stance", "gPauseLiveLink", 7); + UIWidgets::EnhancementRadioButton("Walking (no shield)", "gPauseLiveLink", 8); + UIWidgets::EnhancementRadioButton("Walking (holding shield)", "gPauseLiveLink", 9); + UIWidgets::EnhancementRadioButton("Running (no shield)", "gPauseLiveLink", 10); + UIWidgets::EnhancementRadioButton("Running (holding shield)", "gPauseLiveLink", 11); + UIWidgets::EnhancementRadioButton("Hand on hip", "gPauseLiveLink", 12); + UIWidgets::EnhancementRadioButton("Spin attack charge", "gPauseLiveLink", 13); + UIWidgets::EnhancementRadioButton("Look at hand", "gPauseLiveLink", 14); + UIWidgets::PaddedSeparator(); + ImGui::Text("Randomize"); + UIWidgets::EnhancementRadioButton("Random", "gPauseLiveLink", 15); + UIWidgets::Tooltip("Randomize the animation played each time you open the menu"); + UIWidgets::EnhancementRadioButton("Random cycle", "gPauseLiveLink", 16); + UIWidgets::Tooltip("Randomize the animation played on the menu after a certain time"); + UIWidgets::EnhancementRadioButton("Random cycle (Idle)", "gPauseLiveLink", 17); + UIWidgets::Tooltip("Randomize the animation played on the menu after a certain time (Idle animations only)"); + if (CVar_GetS32("gPauseLiveLink", 0) >= 16) { + UIWidgets::EnhancementSliderInt("Frame to wait: %d", "##MinFrameCount", "gMinFrameCount", 1, 1000, "", 0, true); + } + + ImGui::EndMenu(); + } + UIWidgets::PaddedEnhancementCheckbox("N64 Mode", "gN64Mode", true, false); + UIWidgets::Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution"); + UIWidgets::PaddedEnhancementCheckbox("Enable 3D Dropped items/projectiles", "gNewDrops", true, false); + UIWidgets::Tooltip("Change most 2D items and projectiles on the overworld to their 3D versions"); + UIWidgets::PaddedEnhancementCheckbox("Disable Black Bar Letterboxes", "gDisableBlackBars", true, false); + UIWidgets::Tooltip("Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be minor visual glitches that were covered up by the black bars\nPlease disable this setting before reporting a bug"); + UIWidgets::PaddedEnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon", true, false); + UIWidgets::Tooltip("Changes the rupee in the wallet icon to match the wallet size you currently have"); + UIWidgets::PaddedEnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon", true, false); + UIWidgets::Tooltip("Always shows dungeon entrance icons on the minimap"); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Fixes")) + { + UIWidgets::EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR"); + UIWidgets::Tooltip("Makes the L and R buttons in the pause menu the same color"); + UIWidgets::PaddedEnhancementCheckbox("Fix L&Z Page switch in Pause menu", "gNGCKaleidoSwitcher", true, false); + UIWidgets::Tooltip("Makes L and R switch pages like on the GameCube\nZ opens the Debug Menu instead"); + UIWidgets::PaddedEnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon", true, false); + UIWidgets::Tooltip("Removes the dungeon entrance icon on the top-left corner of the screen when no dungeon is present on the current map"); + UIWidgets::PaddedEnhancementCheckbox("Fix Two Handed idle animations", "gTwoHandedIdle", true, false); + UIWidgets::Tooltip("Re-enables the two-handed idle animation, a seemingly finished animation that was disabled on accident in the original game"); + UIWidgets::PaddedEnhancementCheckbox("Fix the Gravedigging Tour Glitch", "gGravediggingTourFix", true, false); + UIWidgets::Tooltip("Fixes a bug where the Gravedigging Tour Heart Piece disappears if the area reloads"); + UIWidgets::PaddedEnhancementCheckbox("Fix Deku Nut upgrade", "gDekuNutUpgradeFix", true, false); + UIWidgets::Tooltip("Prevents the Forest Stage Deku Nut upgrade from becoming unobtainable after receiving the Poacher's Saw"); + UIWidgets::PaddedEnhancementCheckbox("Fix Navi text HUD position", "gNaviTextFix", true, false); + UIWidgets::Tooltip("Correctly centers the Navi text prompt on the HUD's C-Up button"); + UIWidgets::PaddedEnhancementCheckbox("Fix Anubis fireballs", "gAnubisFix", true, false); + UIWidgets::Tooltip("Make Anubis fireballs do fire damage when reflected back at them with the Mirror Shield"); + UIWidgets::PaddedEnhancementCheckbox("Fix Megaton Hammer crouch stab", "gCrouchStabHammerFix", true, false); + UIWidgets::Tooltip("Make the Megaton Hammer's crouch stab able to destroy rocks without first swinging it normally"); + if (CVar_GetS32("gCrouchStabHammerFix", 0) == 0) { + CVar_SetS32("gCrouchStabFix", 0); + } else { + UIWidgets::PaddedEnhancementCheckbox("Remove power crouch stab", "gCrouchStabFix", true, false); + UIWidgets::Tooltip("Make crouch stabbing always do the same damage as a regular slash"); + } + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Restoration")) + { + UIWidgets::EnhancementCheckbox("Red Ganon blood", "gRedGanonBlood"); + UIWidgets::Tooltip("Restore the original red blood from NTSC 1.0/1.1. Disable for green blood"); + UIWidgets::PaddedEnhancementCheckbox("Fish while hovering", "gHoverFishing", true, false); + UIWidgets::Tooltip("Restore a bug from NTSC 1.0 that allows casting the Fishing Rod while using the Hover Boots"); + UIWidgets::PaddedEnhancementCheckbox("N64 Weird Frames", "gN64WeirdFrames", true, false); + UIWidgets::Tooltip("Restores N64 Weird Frames allowing weirdshots to behave the same as N64"); + UIWidgets::PaddedEnhancementCheckbox("Bombchus out of bounds", "gBombchusOOB", true, false); + UIWidgets::Tooltip("Allows bombchus to explode out of bounds\nSimilar to GameCube and Wii VC"); + UIWidgets::PaddedEnhancementCheckbox("Restore old Gold Skulltula cutscene", "gGsCutscene", true, false); + + ImGui::EndMenu(); + } + + UIWidgets::PaddedEnhancementCheckbox("Autosave", "gAutosave", true, false); + UIWidgets::Tooltip("Automatically save the game every time a new area is entered or item is obtained\n" + "To disable saving when obtaining an item, manually set gAutosaveAllItems and gAutosaveMajorItems to 0\n" + "gAutosaveAllItems takes priority over gAutosaveMajorItems if both are set to 1\n" + "gAutosaveMajorItems excludes rupees and health/magic/ammo refills (but includes bombchus)"); + + UIWidgets::Spacer(0); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + static ImVec2 buttonSize(200.0f, 0.0f); + if (ImGui::Button(GetWindowButtonText("Cosmetics Editor", CVar_GetS32("gCosmeticsEditorEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gCosmeticsEditorEnabled", 0); + CVar_SetS32("gCosmeticsEditorEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Cosmetics Editor", CVar_GetS32("gCosmeticsEditorEnabled", 0)); + } + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(1); + + EXPERIMENTAL(); + + const char* fps_cvar = "gInterpolationFPS"; + { + #if defined(__SWITCH__) || defined(__WIIU__) + int minFps = 20; + int maxFps = 60; + #else + int minFps = 20; + int maxFps = 360; + #endif + + int val = CVar_GetS32(fps_cvar, minFps); + val = fmax(fmin(val, maxFps), 20); + + #ifdef __WIIU__ + // only support divisors of 60 on the Wii U + val = 60 / (60 / val); + #endif + + int fps = val; + + if (fps == 20) + { + ImGui::Text("Frame interpolation: Off"); + } + else + { + ImGui::Text("Frame interpolation: %d FPS", fps); + } + + std::string MinusBTNFPSI = " - ##FPSInterpolation"; + std::string PlusBTNFPSI = " + ##FPSInterpolation"; + if (ImGui::Button(MinusBTNFPSI.c_str())) { + #ifdef __WIIU__ + if (val >= 60) val = 30; + else val = 20; + #else + val--; + #endif + CVar_SetS32(fps_cvar, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + #ifdef __WIIU__ + ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f * 2); + #else + ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f); + #endif + if (ImGui::SliderInt("##FPSInterpolation", &val, minFps, maxFps, "", ImGuiSliderFlags_AlwaysClamp)) + { + #ifdef __WIIU__ + // only support divisors of 60 on the Wii U + val = 60 / (60 / val); + #endif + if (val > 360) + { + val = 360; + } + else if (val < 20) + { + val = 20; + } + + CVar_SetS32(fps_cvar, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::PopItemWidth(); + UIWidgets::Tooltip("Interpolate extra frames to get smoother graphics\n" + "Set to match your monitor's refresh rate, or a divisor of it\n" + "A higher target FPS than your monitor's refresh rate will just waste resources, " + "and might give a worse result.\n" + "For consistent input lag, set this value and your monitor's refresh rate to a multiple of 20\n" + "Ctrl+Click for keyboard input"); + + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + if (ImGui::Button(PlusBTNFPSI.c_str())) { + #ifdef __WIIU__ + if (val <= 20) val = 30; + else val = 60; + #else + val++; + #endif + CVar_SetS32(fps_cvar, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + + if (SohImGui::WindowBackend() == SohImGui::Backend::DX11) + { + UIWidgets::Spacer(0); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f)); + if (ImGui::Button("Match Refresh Rate")) + { + int hz = roundf(SohImGui::WindowRefreshRate()); + if (hz >= 20 && hz <= 360) + { + CVar_SetS32(fps_cvar, hz); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + ImGui::PopStyleVar(1); + UIWidgets::Spacer(0); + } + UIWidgets::EnhancementCheckbox("Disable LOD", "gDisableLOD"); + UIWidgets::Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance"); + UIWidgets::PaddedEnhancementCheckbox("Disable Draw Distance", "gDisableDrawDistance", true, false); + UIWidgets::Tooltip("Turns off the objects draw distance, making objects being visible from a longer range"); + if (CVar_GetS32("gDisableDrawDistance", 0) == 0) { + CVar_SetS32("gDisableKokiriDrawDistance", 0); + } else if (CVar_GetS32("gDisableDrawDistance", 0) == 1) { + UIWidgets::PaddedEnhancementCheckbox("Kokiri Draw Distance", "gDisableKokiriDrawDistance", true, false); + UIWidgets::Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this will remove their draw distance"); + } + UIWidgets::PaddedEnhancementCheckbox("Skip Text", "gSkipText", true, false); + UIWidgets::Tooltip("Holding down B skips text\nKnown to cause a cutscene softlock in Water Temple\nSoftlock can be fixed by pressing D-Right in Debug mode"); + UIWidgets::PaddedEnhancementCheckbox("Free Camera", "gFreeCamera", true, false); + UIWidgets::Tooltip("Enables camera control\nNote: You must remap C buttons off of the right stick in the controller config menu, and map the camera stick to the right stick."); + + #ifdef __SWITCH__ + UIWidgets::Spacer(0); + int slot = CVar_GetS32("gSwitchPerfMode", (int)Ship::SwitchProfiles::STOCK); + ImGui::Text("Switch performance mode"); + if (ImGui::BeginCombo("##perf", SWITCH_CPU_PROFILES[slot])) { + for (int sId = 0; sId <= Ship::SwitchProfiles::POWERSAVINGM3; sId++) { + if (ImGui::Selectable(SWITCH_CPU_PROFILES[sId], sId == slot)) { + SPDLOG_INFO("Profile:: %s", SWITCH_CPU_PROFILES[sId]); + CVar_SetS32("gSwitchPerfMode", sId); + Ship::Switch::ApplyOverclock(); + SohImGui::RequestCvarSaveOnNextTick(); + } + + } + ImGui::EndCombo(); + } + #endif + + ImGui::EndMenu(); + } + + ImGui::SetCursorPosY(0.0f); + + if (ImGui::BeginMenu("Cheats")) + { + if (ImGui::BeginMenu("Infinite...")) { + UIWidgets::EnhancementCheckbox("Money", "gInfiniteMoney"); + UIWidgets::PaddedEnhancementCheckbox("Health", "gInfiniteHealth", true, false); + UIWidgets::PaddedEnhancementCheckbox("Ammo", "gInfiniteAmmo", true, false); + UIWidgets::PaddedEnhancementCheckbox("Magic", "gInfiniteMagic", true, false); + UIWidgets::PaddedEnhancementCheckbox("Nayru's Love", "gInfiniteNayru", true, false); + UIWidgets::PaddedEnhancementCheckbox("Epona Boost", "gInfiniteEpona", true, false); + + ImGui::EndMenu(); + } + + UIWidgets::PaddedEnhancementCheckbox("No Clip", "gNoClip", true, false); + UIWidgets::Tooltip("Allows you to walk through walls"); + UIWidgets::PaddedEnhancementCheckbox("Climb Everything", "gClimbEverything", true, false); + UIWidgets::Tooltip("Makes every surface in the game climbable"); + UIWidgets::PaddedEnhancementCheckbox("Moon Jump on L", "gMoonJumpOnL", true, false); + UIWidgets::Tooltip("Holding L makes you float into the air"); + UIWidgets::PaddedEnhancementCheckbox("Super Tunic", "gSuperTunic", true, false); + UIWidgets::Tooltip("Makes every tunic have the effects of every other tunic"); + UIWidgets::PaddedEnhancementCheckbox("Easy ISG", "gEzISG", true, false); + UIWidgets::Tooltip("Passive Infinite Sword Glitch\nIt makes your sword's swing effect and hitbox stay active indefinitely"); + UIWidgets::PaddedEnhancementCheckbox("Unrestricted Items", "gNoRestrictItems", true, false); + UIWidgets::Tooltip("Allows you to use any item at any location"); + UIWidgets::PaddedEnhancementCheckbox("Freeze Time", "gFreezeTime", true, false); + UIWidgets::Tooltip("Freezes the time of day"); + UIWidgets::PaddedEnhancementCheckbox("Drops Don't Despawn", "gDropsDontDie", true, false); + UIWidgets::Tooltip("Drops from enemies, grass, etc. don't disappear after a set amount of time"); + UIWidgets::PaddedEnhancementCheckbox("Fireproof Deku Shield", "gFireproofDekuShield", true, false); + UIWidgets::Tooltip("Prevents the Deku Shield from burning on contact with fire"); + UIWidgets::PaddedEnhancementCheckbox("Shield with Two-Handed Weapons", "gShieldTwoHanded", true, false); + UIWidgets::Tooltip("This allows you to put up your shield with any two-handed weapon in hand except for Deku Sticks"); + UIWidgets::PaddedEnhancementCheckbox("Time Sync", "gTimeSync", true, false); + UIWidgets::Tooltip("This syncs the ingame time with the real world time"); + + { + static int32_t betaQuestEnabled = CVar_GetS32("gEnableBetaQuest", 0); + static int32_t lastBetaQuestEnabled = betaQuestEnabled; + static int32_t betaQuestWorld = CVar_GetS32("gBetaQuestWorld", 0xFFEF); + static int32_t lastBetaQuestWorld = betaQuestWorld; + + if (!isBetaQuestEnabled) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + + UIWidgets::PaddedEnhancementCheckbox("Enable Beta Quest", "gEnableBetaQuest", true, false); + UIWidgets::Tooltip("Turns on OoT Beta Quest. *WARNING* This will reset your game."); + betaQuestEnabled = CVar_GetS32("gEnableBetaQuest", 0); + if (betaQuestEnabled) { + if (betaQuestEnabled != lastBetaQuestEnabled) { + betaQuestWorld = 0; + } + + ImGui::Text("Beta Quest World: %d", betaQuestWorld); + + if (ImGui::Button(" - ##BetaQuest")) { + betaQuestWorld--; + } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + + ImGui::SliderInt("##BetaQuest", &betaQuestWorld, 0, 8, "", ImGuiSliderFlags_AlwaysClamp); + UIWidgets::Tooltip("Set the Beta Quest world to explore. *WARNING* Changing this will reset your game.\nCtrl+Click to type in a value."); + + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + if (ImGui::Button(" + ##BetaQuest")) { + betaQuestWorld++; + } + + if (betaQuestWorld > 8) { + betaQuestWorld = 8; + } + else if (betaQuestWorld < 0) { + betaQuestWorld = 0; + } + } + else { + lastBetaQuestWorld = betaQuestWorld = 0xFFEF; + CVar_SetS32("gBetaQuestWorld", betaQuestWorld); + } + if (betaQuestEnabled != lastBetaQuestEnabled || betaQuestWorld != lastBetaQuestWorld) + { + // Reset the game if the beta quest state or world changed because beta quest happens on redirecting the title screen cutscene. + lastBetaQuestEnabled = betaQuestEnabled; + lastBetaQuestWorld = betaQuestWorld; + CVar_SetS32("gEnableBetaQuest", betaQuestEnabled); + CVar_SetS32("gBetaQuestWorld", betaQuestWorld); + + SohImGui::DispatchConsoleCommand("reset"); + + SohImGui::RequestCvarSaveOnNextTick(); + } + + if (!isBetaQuestEnabled) { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(1); + } + } + + ImGui::EndMenu(); + } + + ImGui::SetCursorPosY(0.0f); + + if (ImGui::BeginMenu("Developer Tools")) + { + UIWidgets::EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); + UIWidgets::Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right, and open the debug menu with L on the pause screen"); + UIWidgets::PaddedEnhancementCheckbox("OoT Skulltula Debug", "gSkulltulaDebugEnabled", true, false); + UIWidgets::Tooltip("Enables Skulltula Debug, when moving the cursor in the menu above various map icons (boss key, compass, map screen locations, etc) will set the GS bits in that area.\nUSE WITH CAUTION AS IT DOES NOT UPDATE THE GS COUNT."); + UIWidgets::PaddedEnhancementCheckbox("Fast File Select", "gSkipLogoTitle", true, false); + UIWidgets::Tooltip("Load the game to the selected menu or file\n\"Zelda Map Select\" require debug mode else you will fallback to File choose menu\nUsing a file number that don't have save will create a save file only if you toggle on \"Create a new save if none ?\" else it will bring you to the File choose menu"); + if (CVar_GetS32("gSkipLogoTitle", 0)) { + const char* FastFileSelect[5] = { + "File N.1", + "File N.2", + "File N.3", + "File select", + "Zelda Map Select (require OoT Debug Mode)" + }; + ImGui::Text("Loading :"); + UIWidgets::EnhancementCombobox("gSaveFileID", FastFileSelect, 5, 0); + UIWidgets::PaddedEnhancementCheckbox("Create a new save if none", "gCreateNewSave", true, false); + UIWidgets::Tooltip("Enable the creation of a new save file if none exist in the File number selected\nNo file name will be assigned please do in Save editor once you see the first text else your save file name will be named \"00000000\"\nIf disabled you will fall back in File select menu"); + }; + UIWidgets::PaddedSeparator(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + static ImVec2 buttonSize(160.0f, 0.0f); + if (ImGui::Button(GetWindowButtonText("Stats", CVar_GetS32("gStatsEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gStatsEnabled", 0); + CVar_SetS32("gStatsEnabled", !currentValue); + SohImGui::ToggleStatisticsWindow(true); + SohImGui::RequestCvarSaveOnNextTick(); + } + UIWidgets::Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on"); + UIWidgets::Spacer(0); + if (ImGui::Button(GetWindowButtonText("Console", CVar_GetS32("gConsoleEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gConsoleEnabled", 0); + CVar_SetS32("gConsoleEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::ToggleConsoleWindow(!currentValue); + } + UIWidgets::Tooltip("Enables the console window, allowing you to input commands, type help for some examples"); + UIWidgets::Spacer(0); + if (ImGui::Button(GetWindowButtonText("Save Editor", CVar_GetS32("gSaveEditorEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gSaveEditorEnabled", 0); + CVar_SetS32("gSaveEditorEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Save Editor", CVar_GetS32("gSaveEditorEnabled", 0)); + } + UIWidgets::Spacer(0); + if (ImGui::Button(GetWindowButtonText("Collision Viewer", CVar_GetS32("gCollisionViewerEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gCollisionViewerEnabled", 0); + CVar_SetS32("gCollisionViewerEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Collision Viewer", CVar_GetS32("gCollisionViewerEnabled", 0)); + } + UIWidgets::Spacer(0); + if (ImGui::Button(GetWindowButtonText("Actor Viewer", CVar_GetS32("gActorViewerEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gActorViewerEnabled", 0); + CVar_SetS32("gActorViewerEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Actor Viewer", CVar_GetS32("gActorViewerEnabled", 0)); + } + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(1); + + ImGui::EndMenu(); + } + + ImGui::SetCursorPosY(0.0f); + + if (ImGui::BeginMenu("Randomizer")) + { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + static ImVec2 buttonSize(200.0f, 0.0f); + if (ImGui::Button(GetWindowButtonText("Randomizer Settings", CVar_GetS32("gRandomizerSettingsEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gRandomizerSettingsEnabled", 0); + CVar_SetS32("gRandomizerSettingsEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Randomizer Settings", CVar_GetS32("gRandomizerSettingsEnabled", 0)); + } + ImGui::Dummy(ImVec2(0.0f, 0.0f)); + if (ImGui::Button(GetWindowButtonText("Item Tracker", CVar_GetS32("gItemTrackerEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gItemTrackerEnabled", 0); + CVar_SetS32("gItemTrackerEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Item Tracker", CVar_GetS32("gItemTrackerEnabled", 0)); + } + ImGui::Dummy(ImVec2(0.0f, 0.0f)); + if (ImGui::Button(GetWindowButtonText("Item Tracker Settings", CVar_GetS32("gItemTrackerSettingsEnabled", 0)).c_str(), buttonSize)) + { + bool currentValue = CVar_GetS32("gItemTrackerSettingsEnabled", 0); + CVar_SetS32("gItemTrackerSettingsEnabled", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("Item Tracker Settings", CVar_GetS32("gItemTrackerSettingsEnabled", 0)); + } + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(1); + + UIWidgets::PaddedSeparator(); + + if (ImGui::BeginMenu("Rando Enhancements")) + { + UIWidgets::EnhancementCheckbox("Rando-Relevant Navi Hints", "gRandoRelevantNavi"); + UIWidgets::Tooltip( + "Replace Navi's overworld quest hints with rando-related gameplay hints." + ); + UIWidgets::PaddedEnhancementCheckbox("Random Rupee Names", "gRandomizeRupeeNames", true, false); + UIWidgets::Tooltip( + "When obtaining rupees, randomize what the rupee is called in the textbox." + ); + UIWidgets::PaddedEnhancementCheckbox("Key Colors Match Dungeon", "gRandoMatchKeyColors", true, false); + UIWidgets::Tooltip( + "Matches the color of small keys and boss keys to the dungeon they belong to. " + "This helps identify keys from afar and adds a little bit of flair.\n\nThis only " + "applies to seeds with keys and boss keys shuffled to Any Dungeon, Overworld, or Anywhere."); + UIWidgets::PaddedEnhancementCheckbox("Quest Item Fanfares", "gRandoQuestItemFanfares", true, false); + UIWidgets::Tooltip( + "Play unique fanfares when obtaining quest items " + "(medallions/stones/songs). Note that these fanfares are longer than usual." + ); + ImGui::EndMenu(); + } + + ImGui::EndMenu(); + } + } +} diff --git a/soh/soh/GameMenuBar.hpp b/soh/soh/GameMenuBar.hpp new file mode 100644 index 000000000..07280707b --- /dev/null +++ b/soh/soh/GameMenuBar.hpp @@ -0,0 +1,27 @@ +// +// GameMenuBar.hpp +// soh +// +// Created by David Chavez on 24.08.22. +// + +#ifndef GameMenuBar_hpp +#define GameMenuBar_hpp + +#include + +#ifdef __cplusplus +extern "C" { +#endif + void enableBetaQuest(); + void disableBetaQuest(); +#ifdef __cplusplus +} +#endif + +namespace GameMenuBar { + void SetupHooks(); + void Draw(); +} + +#endif /* GameMenuBar_hpp */ diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index efb0e4464..2781d6a6e 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -5,46 +5,46 @@ #include #include -#include "ResourceMgr.h" -#include "DisplayList.h" -#include "PlayerAnimation.h" -#include "Skeleton.h" -#include "Window.h" +#include +#include +#include +#include +#include #include "z64animation.h" #include "z64bgcheck.h" #include "Enhancements/gameconsole.h" #include -#include +#include #ifdef _WIN32 #include #else #include #endif -#include -#include -#include -#include "Lib/stb/stb_image.h" +#include +#include +#include +#include #define DRMP3_IMPLEMENTATION -#include "Lib/dr_libs/mp3.h" +#include #define DRWAV_IMPLEMENTATION -#include "Lib/dr_libs/wav.h" -#include "AudioPlayer.h" +#include +#include #include "Enhancements/controls/GameControlEditor.h" #include "Enhancements/cosmetics/CosmeticsEditor.h" #include "Enhancements/debugconsole.h" #include "Enhancements/debugger/debugger.h" -#include -#include +#include "Enhancements/randomizer/randomizer.h" +#include "Enhancements/randomizer/randomizer_item_tracker.h" #include "Enhancements/n64_weird_frame_data.inc" -#include "soh/frame_interpolation.h" +#include "frame_interpolation.h" #include "variables.h" #include "macros.h" #include -#include "Hooks.h" -#include +#include +#include "Enhancements/custom-message/CustomMessageManager.h" -#include "Lib/Fast3D/gfx_pc.h" -#include "Lib/Fast3D/gfx_rendering_api.h" +#include +#include #ifdef __APPLE__ #include @@ -53,15 +53,16 @@ #endif #ifdef __SWITCH__ -#include "SwitchImpl.h" +#include #elif defined(__WIIU__) -#include "WiiUImpl.h" +#include #endif -#include -#include +#include +#include "Enhancements/custom-message/CustomMessageTypes.h" #include -#include +#include "Enhancements/item-tables/ItemTableManager.h" +#include "GameMenuBar.hpp" OTRGlobals* OTRGlobals::Instance; SaveManager* SaveManager::Instance; @@ -290,6 +291,7 @@ extern "C" void VanillaItemTable_Init() { GET_ITEM(ITEM_BULLET_BAG_50, OBJECT_GI_DEKUPOUCH, GID_BULLET_BAG_50, 0x6C, 0x80, CHEST_ANIM_LONG, MOD_NONE, GI_BULLET_BAG_50), GET_ITEM_NONE, GET_ITEM_NONE, + GET_ITEM_NONE // GI_MAX - if you need to add to this table insert it before this entry. }; ItemTableManager::Instance->AddItemTable(MOD_NONE); for (uint8_t i = 0; i < ARRAY_COUNT(getItemTable); i++) { @@ -321,6 +323,9 @@ extern "C" void InitOTR() { #elif defined(__WIIU__) Ship::WiiU::Init(); #endif + SohImGui::AddSetupHooksDelegate(GameMenuBar::SetupHooks); + SohImGui::RegisterMenuDrawMethod(GameMenuBar::Draw); + OTRGlobals::Instance = new OTRGlobals(); SaveManager::Instance = new SaveManager(); CustomMessageManager::Instance = new CustomMessageManager(); @@ -1582,8 +1587,8 @@ extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey) { return OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(randoSettingKey); } -extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams) { - return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams); +extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams) { + return OTRGlobals::Instance->gRandomizer->GetCheckFromActor(actorId, sceneNum, actorParams); } extern "C" ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData) { @@ -1621,7 +1626,7 @@ extern "C" CustomMessageEntry Randomizer_GetHintFromCheck(RandomizerCheck check) } extern "C" GetItemEntry ItemTable_Retrieve(int16_t getItemID) { - GetItemEntry giEntry = ItemTableManager::Instance->RetrieveItemEntry(OTRGlobals::Instance->getItemModIndex, getItemID); + GetItemEntry giEntry = ItemTableManager::Instance->RetrieveItemEntry(MOD_NONE, getItemID); return giEntry; } @@ -1629,15 +1634,20 @@ extern "C" GetItemEntry ItemTable_RetrieveEntry(s16 tableID, s16 getItemID) { return ItemTableManager::Instance->RetrieveItemEntry(tableID, getItemID); } -extern "C" GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { +extern "C" GetItemEntry Randomizer_GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogId) { s16 getItemModIndex; - if (OTRGlobals::Instance->gRandomizer->CheckContainsVanillaItem( - OTRGlobals::Instance->gRandomizer->GetCheckFromActor(sceneNum, actorId, actorParams))) { + RandomizerCheck randomizerCheck = OTRGlobals::Instance->gRandomizer->GetCheckFromActor(actorId, sceneNum, actorParams); + if (OTRGlobals::Instance->gRandomizer->CheckContainsVanillaItem(randomizerCheck)) { getItemModIndex = MOD_NONE; } else { getItemModIndex = MOD_RANDOMIZER; } - s16 itemID = OTRGlobals::Instance->gRandomizer->GetRandomizedItemId(ogId, actorId, actorParams, sceneNum); + s16 itemID = OTRGlobals::Instance->gRandomizer->GetItemIdFromActor(actorId, sceneNum, actorParams, ogId); + + if (OTRGlobals::Instance->gRandomizer->GetItemObtainabilityFromRandomizerCheck(randomizerCheck) != CAN_OBTAIN) { + return ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); + } + return ItemTable_RetrieveEntry(getItemModIndex, itemID); } @@ -1648,7 +1658,12 @@ extern "C" GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomi } else { getItemModIndex = MOD_RANDOMIZER; } - s16 itemID = OTRGlobals::Instance->gRandomizer->GetRandomizedItemIdFromKnownCheck(randomizerCheck, ogId); + s16 itemID = OTRGlobals::Instance->gRandomizer->GetItemIdFromKnownCheck(randomizerCheck, ogId); + + if (OTRGlobals::Instance->gRandomizer->GetItemObtainabilityFromRandomizerCheck(randomizerCheck) != CAN_OBTAIN) { + return ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); + } + return ItemTable_RetrieveEntry(getItemModIndex, itemID); } @@ -1707,7 +1722,7 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { } RandomizerCheck hintCheck = - Randomizer_GetCheckFromActor(globalCtx->sceneNum, msgCtx->talkActor->id, actorParams); + Randomizer_GetCheckFromActor(msgCtx->talkActor->id, globalCtx->sceneNum, actorParams); messageEntry = Randomizer_GetHintFromCheck(hintCheck); } else if (textId == TEXT_ALTAR_CHILD || textId == TEXT_ALTAR_ADULT) { diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index e1541f0a8..2e20e8752 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -7,7 +7,7 @@ #include #ifdef __cplusplus -#include "Window.h" +#include #include "Enhancements/savestates.h" #include "Enhancements/randomizer/randomizer.h" @@ -21,7 +21,6 @@ public: std::shared_ptr context; std::shared_ptr gSaveStateMgr; std::shared_ptr gRandomizer; - uint16_t getItemModIndex; OTRGlobals(); ~OTRGlobals(); @@ -97,13 +96,13 @@ void* getN64WeirdFrame(s32 i); Sprite* GetSeedTexture(uint8_t index); void Randomizer_LoadSettings(const char* spoilerFileName); u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); -RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); +RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams); ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); void Randomizer_LoadHintLocations(const char* spoilerFileName); void Randomizer_LoadRequiredTrials(const char* spoilerFileName); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); bool Randomizer_IsTrialRequired(RandomizerInf trial); -GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); +GetItemEntry Randomizer_GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogId); GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor); bool Randomizer_ItemIsIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 8d8e7cd77..c048d1056 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -4,7 +4,7 @@ #include "z64.h" #include "functions.h" #include "macros.h" -#include "Cvar.h" +#include #define NOGDI // avoid various windows defines that conflict with things in z64.h #include "spdlog/spdlog.h" @@ -1594,4 +1594,4 @@ extern "C" void Save_DeleteFile(int fileNum) { extern "C" bool Save_Exist(int fileNum) { return SaveManager::Instance->SaveFile_Exist(fileNum); -} \ No newline at end of file +} diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 06a382baa..1acbcbfc9 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -23,7 +23,7 @@ typedef struct { #include #include -#include "Lib/nlohmann/json.hpp" +#include class SaveManager { public: diff --git a/soh/soh/UIWidgets.cpp b/soh/soh/UIWidgets.cpp new file mode 100644 index 000000000..148a820c2 --- /dev/null +++ b/soh/soh/UIWidgets.cpp @@ -0,0 +1,523 @@ +// +// UIWidgets.cpp +// soh +// +// Created by David Chavez on 25.08.22. +// + +#include "UIWidgets.hpp" + +#define IMGUI_DEFINE_MATH_OPERATORS +#include +#include +#include + +#include + +namespace UIWidgets { + + // MARK: - Layout Helper + + // Automatically adds newlines to break up text longer than a specified number of characters + // Manually included newlines will still be respected and reset the line length + // If line is midword when it hits the limit, text should break at the last encountered space + char* WrappedText(const char* text, unsigned int charactersPerLine) { + std::string newText(text); + const size_t tipLength = newText.length(); + int lastSpace = -1; + int currentLineLength = 0; + for (unsigned int currentCharacter = 0; currentCharacter < tipLength; currentCharacter++) { + if (newText[currentCharacter] == '\n') { + currentLineLength = 0; + lastSpace = -1; + continue; + } else if (newText[currentCharacter] == ' ') { + lastSpace = currentCharacter; + } + + if ((currentLineLength >= charactersPerLine) && (lastSpace >= 0)) { + newText[lastSpace] = '\n'; + currentLineLength = currentCharacter - lastSpace - 1; + lastSpace = -1; + } + currentLineLength++; + } + + return strdup(newText.c_str()); + } + + char* WrappedText(const std::string& text, unsigned int charactersPerLine) { + return WrappedText(text.c_str(), charactersPerLine); + } + + void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha) + { + Color_RGBA8 defaultColors; + defaultColors.r = default_colors.x; + defaultColors.g = default_colors.y; + defaultColors.b = default_colors.z; + defaultColors.a = default_colors.w; + + Color_RGBA8 cvarColor = CVar_GetRGBA(cvarname, defaultColors); + + ColorArray.x = cvarColor.r / 255.0; + ColorArray.y = cvarColor.g / 255.0; + ColorArray.z = cvarColor.b / 255.0; + ColorArray.w = cvarColor.a / 255.0; + } + + void SetLastItemHoverText(const std::string& text) { + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("%s", WrappedText(text, 60)); + ImGui::EndTooltip(); + } + } + + // Adds a "?" next to the previous ImGui item with a custom tooltip + void InsertHelpHoverText(const std::string& text) { + ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?"); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("%s", WrappedText(text, 60)); + ImGui::EndTooltip(); + } + } + + + // MARK: - UI Elements + + void Tooltip(const char* text) { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", WrappedText(text)); + } + } + + void Spacer(float height) { + ImGui::Dummy(ImVec2(0.0f, height)); + } + + void PaddedSeparator(bool padTop, bool padBottom, float extraVerticalTopPadding, float extraVerticalBottomPadding) { + if (padTop) + Spacer(0); + + ImGui::Separator(); + + if (padBottom) + Spacer(0); + } + + void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) { + float thickness = ImMax(sz / 5.0f, 1.0f); + sz -= thickness * 0.5f; + pos += ImVec2(thickness * 0.25f, thickness * 0.25f); + + draw_list->PathLineTo(ImVec2(pos.x, pos.y)); + draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y + sz)); + draw_list->PathStroke(col, 0, thickness); + + draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y)); + draw_list->PathLineTo(ImVec2(pos.x, pos.y + sz)); + draw_list->PathStroke(col, 0, thickness); + } + + bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic) { + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); + + const float square_sz = ImGui::GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ImGui::ItemSize(total_bb, style.FramePadding.y); + if (!ImGui::ItemAdd(total_bb, id)) { + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return false; + } + + bool hovered, held; + bool pressed = ImGui::ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) { + *v = !(*v); + ImGui::MarkItemEdited(id); + } + + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + ImGui::RenderNavHighlight(total_bb, id); + ImGui::RenderFrame(check_bb.Min, check_bb.Max, ImGui::GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + ImU32 check_col = ImGui::GetColorU32(ImGuiCol_CheckMark); + ImU32 cross_col = ImGui::GetColorU32(ImVec4(0.50f, 0.50f, 0.50f, 1.00f)); + bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; + if (mixed_value) { + // Undocumented tristate/mixed/indeterminate checkbox (#2644) + // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) + ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); + window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); + } else if ((!disabled && *v) || (disabled && disabledGraphic == CheckboxGraphics::Checkmark)) { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + ImGui::RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); + } else if (disabled && disabledGraphic == CheckboxGraphics::Cross) { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), cross_col, square_sz - pad * 2.0f); + } + + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + if (g.LogEnabled) + ImGui::LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + if (label_size.x > 0.0f) + ImGui::RenderText(label_pos, label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; + } + + void EnhancementCheckbox(const char* text, const char* cvarName, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic) { + if (disabled) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + bool val = (bool)CVar_GetS32(cvarName, 0); + if (CustomCheckbox(text, &val, disabled, disabledGraphic)) { + CVar_SetS32(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + + if (disabled) { + ImGui::PopStyleVar(1); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(disabledTooltipText, "") != 0) { + ImGui::SetTooltip("%s", disabledTooltipText); + } + ImGui::PopItemFlag(); + } + } + + void PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic) { + if (padTop) Spacer(0); + + EnhancementCheckbox(text, cvarName, disabled, disabledTooltipText, disabledGraphic); + + if (padBottom) Spacer(0); + } + + void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector& items, int defaultValue) { + if (ImGui::BeginCombo(name.c_str(), items[static_cast(CVar_GetS32(cvarName, defaultValue))].c_str())) { + for (int settingIndex = 0; settingIndex < (int) items.size(); settingIndex++) { + if (ImGui::Selectable(items[settingIndex].c_str())) { + CVar_SetS32(cvarName, settingIndex); + SohImGui::RequestCvarSaveOnNextTick(); + + } + } + ImGui::EndCombo(); + } + } + + void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue) { + if (FirstTimeValue <= 0) { + FirstTimeValue = 0; + } + uint8_t selected = CVar_GetS32(name, FirstTimeValue); + uint8_t DefaultValue = selected; + std::string comboName = std::string("##") + std::string(name); + if (ImGui::BeginCombo(comboName.c_str(), ComboArray[DefaultValue])) { + for (uint8_t i = 0; i < arraySize; i++) { + if (strlen(ComboArray[i]) > 1) { + if (ImGui::Selectable(ComboArray[i], i == selected)) { + CVar_SetS32(name, i); + selected = i; + SohImGui::RequestCvarSaveOnNextTick(); + } + } + } + ImGui::EndCombo(); + } + } + + void PaddedText(const char* text, bool padTop, bool padBottom) { + if (padTop) + Spacer(0); + + ImGui::Text("%s", text); + + if (padBottom) + Spacer(0); + } + + void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton) { + int val = CVar_GetS32(cvarName, defaultValue); + ImGui::Text(text, val); + if(PlusMinusButton) { + std::string MinusBTNName = " - ##"; + MinusBTNName += cvarName; + if (ImGui::Button(MinusBTNName.c_str())) { + val--; + CVar_SetS32(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + } + + if (ImGui::SliderInt(id, &val, min, max, format)) + { + CVar_SetS32(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + + if(PlusMinusButton) { + std::string PlusBTNName = " + ##"; + PlusBTNName += cvarName; + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + if (ImGui::Button(PlusBTNName.c_str())) { + val++; + CVar_SetS32(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + + if (val < min) + { + val = min; + CVar_SetS32(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + + if (val > max) + { + val = max; + CVar_SetS32(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + + void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton) { + float val = CVar_GetFloat(cvarName, defaultValue); + + if (!isPercentage) + ImGui::Text(text, val); + else + ImGui::Text(text, static_cast(100 * val)); + + Spacer(0); + + if(PlusMinusButton) { + std::string MinusBTNName = " - ##"; + MinusBTNName += cvarName; + if (ImGui::Button(MinusBTNName.c_str())) { + if (!isPercentage) + val -= 0.1f; + else + val -= 0.01f; + CVar_SetFloat(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + } + if (PlusMinusButton) { + #ifdef __WIIU__ + ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f * 2); + #else + ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f); + #endif + } + if (ImGui::SliderFloat(id, &val, min, max, format)) + { + CVar_SetFloat(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + if (PlusMinusButton) { + ImGui::PopItemWidth(); + } + if(PlusMinusButton) { + std::string PlusBTNName = " + ##"; + PlusBTNName += cvarName; + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + if (ImGui::Button(PlusBTNName.c_str())) { + if (!isPercentage) + val += 0.1f; + else + val += 0.01f; + CVar_SetFloat(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + + if (val < min) + { + val = min; + CVar_SetFloat(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + + if (val > max) + { + val = max; + CVar_SetFloat(cvarName, val); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + + void PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton, bool padTop, bool padBottom) { + if (padTop) + Spacer(0); + + EnhancementSliderInt(text, id, cvarName, min, max, format, defaultValue, PlusMinusButton); + + if (padBottom) + Spacer(0); + } + + void EnhancementRadioButton(const char* text, const char* cvarName, int id) { + /*Usage : + EnhancementRadioButton("My Visible Name","gMyCVarName", MyID); + First arg is the visible name of the Radio button + Second is the cvar name where MyID will be saved. + Note: the CVar name should be the same to each Buddies. + Example : + EnhancementRadioButton("English", "gLanguages", 0); + EnhancementRadioButton("German", "gLanguages", 1); + EnhancementRadioButton("French", "gLanguages", 2); + */ + std::string make_invisible = "##"; + make_invisible += text; + make_invisible += cvarName; + + int val = CVar_GetS32(cvarName, 0); + if (ImGui::RadioButton(make_invisible.c_str(), id == val)) { + CVar_SetS32(cvarName, id); + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::SameLine(); + ImGui::Text("%s", text); + } + + void ResetColor(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha) { + std::string Cvar_RBM = cvarName; + Cvar_RBM += "RBM"; + std::string MakeInvisible = "Reset"; + MakeInvisible += "##"; + MakeInvisible += cvarName; + MakeInvisible += "Reset"; + if (ImGui::Button(MakeInvisible.c_str())) { + colors->x = defaultcolors.x; + colors->y = defaultcolors.y; + colors->z = defaultcolors.z; + if (has_alpha) { colors->w = defaultcolors.w; }; + + Color_RGBA8 colorsRGBA; + colorsRGBA.r = defaultcolors.x; + colorsRGBA.g = defaultcolors.y; + colorsRGBA.b = defaultcolors.z; + if (has_alpha) { colorsRGBA.a = defaultcolors.w; }; + + CVar_SetRGBA(cvarName, colorsRGBA); + CVar_SetS32(Cvar_RBM.c_str(), 0); //On click disable rainbow mode. + SohImGui::RequestCvarSaveOnNextTick(); + } + Tooltip("Revert colors to the game's original colors (GameCube version)\nOverwrites previously chosen color"); + } + + void RandomizeColor(const char* cvarName, ImVec4* colors) { + Color_RGBA8 NewColors = {0,0,0,255}; + std::string Cvar_RBM = cvarName; + Cvar_RBM += "RBM"; + std::string MakeInvisible = "##"; + MakeInvisible += cvarName; + MakeInvisible += "Random"; + std::string FullName = "Random"; + FullName += MakeInvisible; + if (ImGui::Button(FullName.c_str())) { + s16 RND_R = rand() % (255 - 0); + s16 RND_G = rand() % (255 - 0); + s16 RND_B = rand() % (255 - 0); + colors->x = (float)RND_R / 255; + colors->y = (float)RND_G / 255; + colors->z = (float)RND_B / 255; + NewColors.r = fmin(fmax(colors->x, 0), 255); + NewColors.g = fmin(fmax(colors->y, 0), 255); + NewColors.b = fmin(fmax(colors->z, 0), 255); + CVar_SetRGBA(cvarName, NewColors); + CVar_SetS32(Cvar_RBM.c_str(), 0); // On click disable rainbow mode. + SohImGui::RequestCvarSaveOnNextTick(); + } + Tooltip("Chooses a random color\nOverwrites previously chosen color"); + } + + void RainbowColor(const char* cvarName, ImVec4* colors) { + std::string Cvar_RBM = cvarName; + Cvar_RBM += "RBM"; + std::string MakeInvisible = "Rainbow"; + MakeInvisible += "##"; + MakeInvisible += cvarName; + MakeInvisible += "Rainbow"; + + EnhancementCheckbox(MakeInvisible.c_str(), Cvar_RBM.c_str()); + Tooltip("Cycles through colors on a timer\nOverwrites previously chosen color"); + } + + void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow, bool has_alpha, bool TitleSameLine) { + LoadPickersColors(ColorRGBA, cvarName, default_colors, has_alpha); + + ImGuiColorEditFlags flags = ImGuiColorEditFlags_None; + + if (!TitleSameLine) { + ImGui::Text("%s", text); + flags = ImGuiColorEditFlags_NoLabel; + } + + ImGui::PushID(cvarName); + + if (!has_alpha) { + if (ImGui::ColorEdit3(text, (float*)&ColorRGBA, flags)) + { + Color_RGBA8 colors; + colors.r = ColorRGBA.x * 255.0; + colors.g = ColorRGBA.y * 255.0; + colors.b = ColorRGBA.z * 255.0; + colors.a = ColorRGBA.w * 255.0; + + CVar_SetRGBA(cvarName, colors); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + else + { + if (ImGui::ColorEdit4(text, (float*)&ColorRGBA, flags)) + { + Color_RGBA8 colors; + colors.r = ColorRGBA.x / 255; + colors.g = ColorRGBA.y / 255; + colors.b = ColorRGBA.z / 255; + colors.a = ColorRGBA.w / 255; + + CVar_SetRGBA(cvarName, colors); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + + ImGui::PopID(); + + //ImGui::SameLine(); // Removing that one to gain some width spacing on the HUD editor + ImGui::PushItemWidth(-FLT_MIN); + ResetColor(cvarName, &ColorRGBA, default_colors, has_alpha); + ImGui::SameLine(); + RandomizeColor(cvarName, &ColorRGBA); + if (allow_rainbow) { + if (ImGui::GetContentRegionAvail().x > 185) { + ImGui::SameLine(); + } + RainbowColor(cvarName, &ColorRGBA); + } + ImGui::NewLine(); + ImGui::PopItemWidth(); + } +} diff --git a/soh/soh/UIWidgets.hpp b/soh/soh/UIWidgets.hpp new file mode 100644 index 000000000..6ea62a9fa --- /dev/null +++ b/soh/soh/UIWidgets.hpp @@ -0,0 +1,49 @@ +// +// UIWidgets.hpp +// soh +// +// Created by David Chavez on 25.08.22. +// + +#ifndef UIWidgets_hpp +#define UIWidgets_hpp + +#include +#include +#include +#include + +namespace UIWidgets { + + // MARK: - Enums + + enum class CheckboxGraphics { + Cross, + Checkmark, + None + }; + + char* WrappedText(const char* text, unsigned int charactersPerLine = 60); + char* WrappedText(const std::string& text, unsigned int charactersPerLine); + + void SetLastItemHoverText(const std::string& text); + void InsertHelpHoverText(const std::string& text); + + void Tooltip(const char* text); + void Spacer(float height); + + void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f); + void EnhancementCheckbox(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross); + void PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross); + void EnhancementCombo(const std::string& name, const char* cvarName, const std::vector& items, int defaultValue = 0); + void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue); + void PaddedText(const char* text, bool padTop = true, bool padBottom = true); + void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = false); + void PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = false, bool padTop = true, bool padBottom = true); + void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton = false); + void EnhancementRadioButton(const char* text, const char* cvarName, int id); + + void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false); +} + +#endif /* UIWidgets_hpp */ diff --git a/soh/soh/frame_interpolation.cpp b/soh/soh/frame_interpolation.cpp index 44c255db1..79ac23d43 100644 --- a/soh/soh/frame_interpolation.cpp +++ b/soh/soh/frame_interpolation.cpp @@ -1,4 +1,4 @@ -#include "Cvar.h" +#include #include #include diff --git a/soh/soh/z_message_OTR.cpp b/soh/soh/z_message_OTR.cpp index 5cfc99395..96cb0f016 100644 --- a/soh/soh/z_message_OTR.cpp +++ b/soh/soh/z_message_OTR.cpp @@ -1,13 +1,13 @@ #include "OTRGlobals.h" -#include "ResourceMgr.h" -#include "Scene.h" -#include "Utils/StringHelper.h" +#include +#include +#include #include "global.h" #include "vt.h" -#include +#include #include -#include -#include +#include "Enhancements/custom-message/CustomMessageManager.h" +#include "Enhancements/custom-message/CustomMessageTypes.h" extern "C" MessageTableEntry* sNesMessageEntryTablePtr; extern "C" MessageTableEntry* sGerMessageEntryTablePtr; diff --git a/soh/soh/z_play_otr.cpp b/soh/soh/z_play_otr.cpp index d0137644c..52b71c905 100644 --- a/soh/soh/z_play_otr.cpp +++ b/soh/soh/z_play_otr.cpp @@ -1,10 +1,10 @@ -#include "OTRGlobals.h" -#include "ResourceMgr.h" -#include "Scene.h" -#include "Utils/StringHelper.h" +#include "OTRGlobals.h" +#include +#include +#include #include "global.h" #include "vt.h" -#include "Vertex.h" +#include extern "C" void Gameplay_InitScene(GlobalContext * globalCtx, s32 spawn); extern "C" void Gameplay_InitEnvironment(GlobalContext * globalCtx, s16 skyboxId); @@ -60,7 +60,6 @@ void OTRGameplay_InitScene(GlobalContext* globalCtx, s32 spawn) { globalCtx->cUpElfMsgs = nullptr; globalCtx->setupPathList = nullptr; globalCtx->numSetupActors = 0; - OTRGlobals::Instance->getItemModIndex = MOD_NONE; Object_InitBank(globalCtx, &globalCtx->objectCtx); LightContext_Init(globalCtx, &globalCtx->lightCtx); TransitionActor_InitContext(&globalCtx->state, &globalCtx->transiActorCtx); @@ -77,4 +76,4 @@ void OTRGameplay_InitScene(GlobalContext* globalCtx, s32 spawn) { auto data2 = ResourceMgr_LoadVtxByCRC(0x68d4ea06044e228f);*/ volatile int a = 0; -} \ No newline at end of file +} diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index 73953c681..97c0b8040 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -1,15 +1,15 @@ -#include "OTRGlobals.h" -#include "ResourceMgr.h" -#include "Scene.h" -#include "Utils/StringHelper.h" +#include "OTRGlobals.h" +#include +#include +#include #include "global.h" #include "vt.h" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include extern Ship::Resource* OTRGameplay_LoadFile(GlobalContext* globalCtx, const char* fileName); extern "C" s32 Object_Spawn(ObjectContext* objectCtx, s16 objectId); diff --git a/soh/src/code/audio_playback.c b/soh/src/code/audio_playback.c index b2017b514..2c7ff425d 100644 --- a/soh/src/code/audio_playback.c +++ b/soh/src/code/audio_playback.c @@ -1,5 +1,5 @@ #include "global.h" -#include "Cvar.h" +#include extern bool gUseLegacySD; diff --git a/soh/src/code/audio_synthesis.c b/soh/src/code/audio_synthesis.c index 67f7033ea..72dbb25ec 100644 --- a/soh/src/code/audio_synthesis.c +++ b/soh/src/code/audio_synthesis.c @@ -1,6 +1,6 @@ #include "ultra64.h" #include "global.h" -#include "mixer.h" +#include #define DEFAULT_LEN_1CH 0x1A0 #define DEFAULT_LEN_2CH 0x340 diff --git a/soh/src/code/code_800F9280.c b/soh/src/code/code_800F9280.c index 6ca2ad75d..5fa3d50fa 100644 --- a/soh/src/code/code_800F9280.c +++ b/soh/src/code/code_800F9280.c @@ -1,7 +1,7 @@ #include "ultra64.h" #include "global.h" -#include "ultra64/abi.h" -#include "mixer.h" +#include +#include typedef struct { u8 unk_0; diff --git a/soh/src/code/main.c b/soh/src/code/main.c index 8e9fe1776..7a6d6c6d9 100644 --- a/soh/src/code/main.c +++ b/soh/src/code/main.c @@ -3,7 +3,7 @@ #include #include "soh/OTRGlobals.h" -#include "../libultraship/CrashHandler.h" +#include s32 gScreenWidth = SCREEN_WIDTH; @@ -42,6 +42,8 @@ int main(int argc, char** argv) { #ifdef __linux__ SetupHandlerLinux(); +#elif _WIN32 + SetUnhandledExceptionFilter(seh_filter); #endif GameConsole_Init(); diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 95375ea48..986d5a135 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -515,13 +515,13 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) { } if (!Actor_HasParent(&this->actor, globalCtx)) { - if (!gSaveContext.n64ddFlag) { - if (getItemId != GI_NONE) { + if (getItemId != GI_NONE) { + if (!gSaveContext.n64ddFlag) { func_8002F554(&this->actor, globalCtx, getItemId); + } else { + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, getItemId); + GiveItemEntryFromActorWithFixedRange(&this->actor, globalCtx, getItem); } - } else { - getItem = Randomizer_GetRandomizedItem(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); - GiveItemEntryFromActorWithFixedRange(&this->actor, globalCtx, getItem); } } @@ -686,7 +686,7 @@ void func_8001E5C8(EnItem00* this, GlobalContext* globalCtx) { func_8002F434(&this->actor, globalCtx, this->getItemId, 50.0f, 80.0f); } else { GetItemEntry getItemEntry = - Randomizer_GetRandomizedItem(this->getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); + Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, this->getItemId); GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 50.0f, 80.0f); } this->unk_15A++; @@ -911,7 +911,7 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) { if (!gSaveContext.n64ddFlag) { func_8002F554(&this->actor, globalCtx, getItemId); } else { - getItem = Randomizer_GetRandomizedItem(getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, getItemId); getItemId = getItem.getItemId; GiveItemEntryFromActorWithFixedRange(&this->actor, globalCtx, getItem); } @@ -1380,7 +1380,7 @@ void EnItem00_DrawCollectible(EnItem00* this, GlobalContext* globalCtx) { f32 mtxScale = 16.0f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); GetItemEntry randoGetItemEntry = - Randomizer_GetRandomizedItem(this->getItemId, this->actor.id, this->ogParams, globalCtx->sceneNum); + Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, this->getItemId); EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemEntry); GetItemEntry_Draw(globalCtx, randoGetItemEntry); } else { @@ -1442,7 +1442,7 @@ void EnItem00_DrawHeartPiece(EnItem00* this, GlobalContext* globalCtx) { f32 mtxScale = 16.0f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); GetItemEntry randoGetItemEntry = - Randomizer_GetRandomizedItem(GI_HEART_PIECE, this->actor.id, this->ogParams, globalCtx->sceneNum); + Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->ogParams, GI_HEART_PIECE); EnItem00_CustomItemsParticles(&this->actor, globalCtx, randoGetItemEntry); GetItemEntry_Draw(globalCtx, randoGetItemEntry); } else { diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 8d26f3658..4d4807442 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1575,6 +1575,17 @@ void func_80084BF4(GlobalContext* globalCtx, u16 flag) { } } +/** + * @brief Adds the given item to Link's inventory. + * + * NOTE: This function has been edited to be safe to use with a NULL globalCtx. + * If you need to add to this function, be sure you check if the globalCtx is not + * NULL before doing any operations requiring it. + * + * @param globalCtx + * @param item + * @return u8 + */ u8 Item_Give(GlobalContext* globalCtx, u8 item) { static s16 sAmmoRefillCounts[] = { 5, 10, 20, 30, 5, 10, 30, 0, 5, 20, 1, 5, 20, 50, 200, 10 }; s16 i; @@ -1654,7 +1665,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { if (gSaveContext.equips.buttonItems[0] == ITEM_SWORD_KNIFE) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_BGS; - Interface_LoadItemIcon1(globalCtx, 0); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, 0); + } } } @@ -1662,7 +1675,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { gSaveContext.equips.buttonItems[0] = ITEM_SWORD_MASTER; gSaveContext.equips.equipment &= 0xFFF0; gSaveContext.equips.equipment |= 0x0002; - Interface_LoadItemIcon1(globalCtx, 0); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, 0); + } } return ITEM_NONE; @@ -1677,7 +1692,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return ITEM_NONE; } else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) { // Boss Key, Compass, and Dungeon Map exceptions for rando. - if (gSaveContext.n64ddFlag) { + // Rando should never be able to get here for Link's Pocket unless something goes wrong, + // but we check for a globalCtx here so the game won't crash if we do somehow get here. + if (gSaveContext.n64ddFlag && globalCtx != NULL) { if (globalCtx->sceneNum == 13) { // ganon's castle -> ganon's tower gSaveContext.inventory.dungeonItems[10] |= 1; } else if (globalCtx->sceneNum == 92) { // Desert Colossus -> Spirit Temple. @@ -1691,7 +1708,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return ITEM_NONE; } else if (item == ITEM_KEY_SMALL) { // Small key exceptions for rando with keysanity off. - if (gSaveContext.n64ddFlag) { + // Rando should never be able to get here for Link's Pocket unless something goes wrong, + // but we check for a globalCtx here so the game won't crash if we do somehow get here. + if (gSaveContext.n64ddFlag && globalCtx != NULL) { if (globalCtx->sceneNum == 10) { // ganon's tower -> ganon's castle if (gSaveContext.inventory.dungeonKeys[13] < 0) { gSaveContext.inventory.dungeonKeys[13] = 1; @@ -1828,7 +1847,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (gSaveContext.equips.buttonItems[i] == ITEM_HOOKSHOT) { gSaveContext.equips.buttonItems[i] = ITEM_LONGSHOT; - Interface_LoadItemIcon1(globalCtx, i); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, i); + } } } // update the adult/child equips when rando'd (accounting for equp swapped hookshot as child) @@ -1836,7 +1857,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { for (i = 1; i < ARRAY_COUNT(gSaveContext.adultEquips.buttonItems); i++) { if (gSaveContext.adultEquips.buttonItems[i] == ITEM_HOOKSHOT) { gSaveContext.adultEquips.buttonItems[i] = ITEM_LONGSHOT; - Interface_LoadItemIcon1(globalCtx, i); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, i); + } } } } @@ -1844,7 +1867,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { for (i = 1; i < ARRAY_COUNT(gSaveContext.childEquips.buttonItems); i++) { if (gSaveContext.childEquips.buttonItems[i] == ITEM_HOOKSHOT) { gSaveContext.childEquips.buttonItems[i] = ITEM_LONGSHOT; - Interface_LoadItemIcon1(globalCtx, i); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, i); + } } } } @@ -1989,7 +2014,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { for (i = 1; i < ARRAY_COUNT(gSaveContext.adultEquips.buttonItems); i++) { if (gSaveContext.adultEquips.buttonItems[i] == ITEM_OCARINA_FAIRY) { gSaveContext.adultEquips.buttonItems[i] = ITEM_OCARINA_TIME; - Interface_LoadItemIcon1(globalCtx, i); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, i); + } } } } @@ -1997,7 +2024,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { for (i = 1; i < ARRAY_COUNT(gSaveContext.childEquips.buttonItems); i++) { if (gSaveContext.childEquips.buttonItems[i] == ITEM_OCARINA_FAIRY) { gSaveContext.childEquips.buttonItems[i] = ITEM_OCARINA_TIME; - Interface_LoadItemIcon1(globalCtx, i); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, i); + } } } } @@ -2021,14 +2050,20 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return ITEM_NONE; } else if (item == ITEM_HEART) { osSyncPrintf("回復ハート回復ハート回復ハート\n"); // "Recovery Heart" - Health_ChangeBy(globalCtx, 0x10); + if (globalCtx != NULL) { + Health_ChangeBy(globalCtx, 0x10); + } return item; } else if (item == ITEM_MAGIC_SMALL) { if (gSaveContext.unk_13F0 != 10) { - Magic_Fill(globalCtx); + if (globalCtx != NULL) { + Magic_Fill(globalCtx); + } } - func_80087708(globalCtx, 12, 5); + if (globalCtx != NULL) { + func_80087708(globalCtx, 12, 5); + } if (!(gSaveContext.infTable[25] & 0x100)) { gSaveContext.infTable[25] |= 0x100; @@ -2038,10 +2073,13 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { return item; } else if (item == ITEM_MAGIC_LARGE) { if (gSaveContext.unk_13F0 != 10) { - Magic_Fill(globalCtx); + if (globalCtx != NULL) { + Magic_Fill(globalCtx); + } + } + if (globalCtx != NULL) { + func_80087708(globalCtx, 24, 5); } - - func_80087708(globalCtx, 24, 5); if (!(gSaveContext.infTable[25] & 0x100)) { gSaveContext.infTable[25] |= 0x100; @@ -2080,7 +2118,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { for (int buttonIndex = 1; buttonIndex < ARRAY_COUNT(gSaveContext.equips.buttonItems); buttonIndex++) { if ((temp + i) == gSaveContext.equips.cButtonSlots[buttonIndex - 1]) { gSaveContext.equips.buttonItems[buttonIndex] = item; - Interface_LoadItemIcon2(globalCtx, buttonIndex); + if (globalCtx != NULL) { + Interface_LoadItemIcon2(globalCtx, buttonIndex); + } gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(buttonIndex)] = BTN_ENABLED; break; } @@ -2115,7 +2155,9 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { if (temp == gSaveContext.equips.buttonItems[i]) { if (item != ITEM_SOLD_OUT) { gSaveContext.equips.buttonItems[i] = item; - Interface_LoadItemIcon1(globalCtx, i); + if (globalCtx != NULL) { + Interface_LoadItemIcon1(globalCtx, i); + } } else { gSaveContext.equips.buttonItems[i] = ITEM_NONE; } @@ -2132,7 +2174,7 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) { INV_CONTENT(item) = item; // Autosave after getting items by default (cvars are not shown in the UI) - if (CVar_GetS32("gAutosave", 0)) { + if (CVar_GetS32("gAutosave", 0) && globalCtx != NULL) { if (CVar_GetS32("gAutosaveAllItems", 1)) { Gameplay_PerformSave(globalCtx); } @@ -2556,6 +2598,17 @@ s32 Inventory_HasEmptyBottle(void) { } } +bool Inventory_HasEmptyBottleSlot(void) { + u8* items = gSaveContext.inventory.items; + + return ( + items[SLOT_BOTTLE_1] == ITEM_NONE || + items[SLOT_BOTTLE_2] == ITEM_NONE || + items[SLOT_BOTTLE_3] == ITEM_NONE || + items[SLOT_BOTTLE_4] == ITEM_NONE + ); +} + s32 Inventory_HasSpecificBottle(u8 bottleItem) { u8* items = gSaveContext.inventory.items; diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index b1dd2bc7c..d40a0de7a 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -4,7 +4,7 @@ #include #include "soh/Enhancements/gameconsole.h" -#include "../libultraship/ImGuiImpl.h" +#include #include "soh/frame_interpolation.h" #include diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index c131f172f..20d255bca 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -54,31 +54,6 @@ void GiveLinkRupees(int numOfRupees) { } } -void GiveLinkRupeesByGetItemId(GetItemID giid) { - if (giid == GI_RUPEE_GREEN) { - GiveLinkRupees(1); - } else if (giid == GI_RUPEE_BLUE) { - GiveLinkRupees(5); - } else if (giid == GI_RUPEE_RED) { - GiveLinkRupees(20); - } else if (giid == GI_RUPEE_PURPLE) { - GiveLinkRupees(50); - } else if (giid == GI_RUPEE_GOLD) { - GiveLinkRupees(100); - } -} - -void GiveLinkBombchus(GetItemID giid) { - INV_CONTENT(ITEM_BOMBCHU) = ITEM_BOMBCHU; - if (giid == GI_BOMBCHUS_5) { - AMMO(ITEM_BOMBCHU) += 5; - } else if (giid == GI_BOMBCHUS_10) { - AMMO(ITEM_BOMBCHU) += 10; - } else if (giid == GI_BOMBCHUS_20) { - AMMO(ITEM_BOMBCHU) += 20; - } -} - void GiveLinkDekuSticks(int howManySticks) { int maxStickCount; if (CUR_UPG_VALUE(UPG_STICKS) == 0) { @@ -100,16 +75,6 @@ void GiveLinkDekuSticks(int howManySticks) { } } -void GiveLinkDekuSticksByGetItemId(GetItemID giid) { - if (giid == GI_STICKS_1) { - GiveLinkDekuSticks(1); - } else if (giid == GI_STICKS_5) { - GiveLinkDekuSticks(5); - } else if (giid == GI_STICKS_10) { - GiveLinkDekuSticks(10); - } -} - void GiveLinkDekuNuts(int howManyNuts) { int maxNutCount; if (CUR_UPG_VALUE(UPG_NUTS) == 0) { @@ -131,441 +96,18 @@ void GiveLinkDekuNuts(int howManyNuts) { } } -void GiveLinkDekuNutsByGetItemId(GetItemID giid) { - if (giid == GI_NUTS_5) { - GiveLinkDekuNuts(5); - } else if (giid == GI_NUTS_10) { - GiveLinkDekuNuts(10); - } -} +void GiveLinksPocketItem() { + if (Randomizer_GetSettingValue(RSK_LINKS_POCKET) < 3) { + GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, RG_NONE); -void GiveLinkBeans() { - INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; - AMMO(ITEM_BEAN)++; -} - -void GiveLinkKokiriSword() { - uint32_t bitMask = 1 << 0; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkGiantsKnife() { - gSaveContext.bgsFlag = 0; - gSaveContext.swordHealth = 8; - uint32_t bitMask = 1 << 2; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkBiggoronSword() { - gSaveContext.bgsFlag = 1; - gSaveContext.swordHealth = 8; - uint32_t bitMask = 1 << 2; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkDekuShield() { - uint32_t bitMask = 1 << 4; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkHylianShield() { - uint32_t bitMask = 1 << 5; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkMirrorShield() { - uint32_t bitMask = 1 << 6; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkGoronTunic() { - uint32_t bitMask = 1 << 9; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkZoraTunic() { - uint32_t bitMask = 1 << 10; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkIronBoots() { - uint32_t bitMask = 1 << 13; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkHoverBoots() { - uint32_t bitMask = 1 << 14; - gSaveContext.inventory.equipment |= bitMask; -} - -void GiveLinkStoneOfAgony() { - uint32_t bitMask = 1 << QUEST_STONE_OF_AGONY; - gSaveContext.inventory.questItems |= bitMask; -} - -void GiveLinkGerudoCard() { - uint32_t bitMask = 1 << QUEST_GERUDO_CARD; - gSaveContext.inventory.questItems |= bitMask; -} - -void GiveLinkPieceOfHeart() { - int32_t pohCount = (gSaveContext.inventory.questItems & 0xF0000000) >> 28; - pohCount++; - gSaveContext.inventory.questItems |= (pohCount << 28); -} - -void GiveLinkHeartContainer() { - gSaveContext.healthCapacity += 16; - gSaveContext.health += 16; -} - -void GiveLinkBulletBagUpgrade(GetItemID giid) { - if (giid == GI_SLINGSHOT) { - INV_CONTENT(ITEM_SLINGSHOT) = ITEM_SLINGSHOT; - AMMO(ITEM_SLINGSHOT) = 30; - Inventory_ChangeUpgrade(UPG_BULLET_BAG, 1); - } else if (giid == GI_BULLET_BAG_40) { - Inventory_ChangeUpgrade(UPG_BULLET_BAG, 2); - AMMO(ITEM_SLINGSHOT) = 40; - } else if (giid == GI_BULLET_BAG_50) { - Inventory_ChangeUpgrade(UPG_BULLET_BAG, 3); - AMMO(ITEM_SLINGSHOT) = 50; - } -} - -void GiveLinkQuiverUpgrade(GetItemID giid) { - if (giid == GI_BOW) { - INV_CONTENT(ITEM_BOW) = ITEM_BOW; - Inventory_ChangeUpgrade(UPG_QUIVER, 1); - AMMO(ITEM_BOW) = 30; - } else if (giid == GI_QUIVER_40) { - Inventory_ChangeUpgrade(UPG_QUIVER, 2); - AMMO(ITEM_BOW) = 40; - } else if (giid == GI_QUIVER_50) { - Inventory_ChangeUpgrade(UPG_QUIVER, 3); - AMMO(ITEM_BOW) = 50; - } -} - -void GiveLinkBombBagUpgrade(GetItemID giid) { - if (giid == GI_BOMB_BAG_20) { - INV_CONTENT(ITEM_BOMB) = ITEM_BOMB; - Inventory_ChangeUpgrade(UPG_BOMB_BAG, 1); - AMMO(ITEM_BOMB) = 20; - } else if (giid == GI_BOMB_BAG_30) { - Inventory_ChangeUpgrade(UPG_BOMB_BAG, 2); - AMMO(ITEM_BOMB) = 30; - } else if (giid == GI_BOMB_BAG_40) { - Inventory_ChangeUpgrade(UPG_BOMB_BAG, 3); - AMMO(ITEM_BOMB) = 40; - } -} - -void GiveLinkStrengthUpgrade(GetItemID giid) { - if (giid == GI_BRACELET) { - Inventory_ChangeUpgrade(UPG_STRENGTH, 1); - } else if (giid == GI_GAUNTLETS_SILVER) { - Inventory_ChangeUpgrade(UPG_STRENGTH, 2); - } else if (giid == GI_GAUNTLETS_GOLD) { - Inventory_ChangeUpgrade(UPG_STRENGTH, 3); - } -} - -void GiveLinkScaleUpgrade(GetItemID giid) { - if (giid == GI_SCALE_SILVER) { - Inventory_ChangeUpgrade(UPG_SCALE, 1); - } else if (giid == GI_SCALE_GOLD) { - Inventory_ChangeUpgrade(UPG_SCALE, 2); - } -} - -void GiveLinkWalletUpgrade(GetItemID giid) { - if (giid == GI_WALLET_ADULT) { - Inventory_ChangeUpgrade(UPG_WALLET, 1); - } else if (giid == GI_WALLET_GIANT) { - Inventory_ChangeUpgrade(UPG_WALLET, 2); - } -} - -void GiveLinkDekuStickUpgrade(GetItemID giid) { - if (giid == GI_STICK_UPGRADE_20) { - INV_CONTENT(ITEM_STICK) = ITEM_STICK; - Inventory_ChangeUpgrade(UPG_STICKS, 2); - AMMO(ITEM_STICK) = 20; - } else if (giid == GI_STICK_UPGRADE_30) { - Inventory_ChangeUpgrade(UPG_STICKS, 3); - AMMO(ITEM_STICK) = 30; - } -} - -void GiveLinkDekuNutUpgrade(GetItemID giid) { - if (giid == GI_NUT_UPGRADE_30) { - INV_CONTENT(ITEM_NUT) = ITEM_NUT; - Inventory_ChangeUpgrade(UPG_NUTS, 2); - AMMO(ITEM_NUT) = 30; - } else if (giid == GI_NUT_UPGRADE_40) { - Inventory_ChangeUpgrade(UPG_NUTS, 3); - AMMO(ITEM_NUT) = 40; - } -} - -void GiveLinkSkullToken() { - gSaveContext.inventory.questItems |= gBitFlags[QUEST_SKULL_TOKEN]; - gSaveContext.inventory.gsTokens++; -} - -void GiveLinkMagic(GetItemID giid) { - if (giid == RG_MAGIC_SINGLE) { - gSaveContext.magicLevel = 1; - gSaveContext.magicAcquired = true; - gSaveContext.doubleMagic = false; - } else if (giid == RG_MAGIC_DOUBLE) { - gSaveContext.magicLevel = 2; - gSaveContext.magicAcquired = true; - gSaveContext.doubleMagic = true; - } -} - -void GiveLinkDoubleDefense() { - gSaveContext.doubleDefense = 1; - gSaveContext.inventory.defenseHearts = 20; -} - -void GiveLinkSong(GetItemID getItemId) { - uint32_t bitMask; - - switch (getItemId) { - case RG_ZELDAS_LULLABY: - bitMask = 1 << QUEST_SONG_LULLABY; - break; - case RG_SUNS_SONG: - bitMask = 1 << QUEST_SONG_SUN; - break; - case RG_EPONAS_SONG: - bitMask = 1 << QUEST_SONG_EPONA; - break; - case RG_SONG_OF_STORMS: - bitMask = 1 << QUEST_SONG_STORMS; - break; - case RG_SONG_OF_TIME: - bitMask = 1 << QUEST_SONG_TIME; - break; - case RG_SARIAS_SONG: - bitMask = 1 << QUEST_SONG_SARIA; - break; - case RG_MINUET_OF_FOREST: - bitMask = 1 << QUEST_SONG_MINUET; - break; - case RG_BOLERO_OF_FIRE: - bitMask = 1 << QUEST_SONG_BOLERO; - break; - case RG_SERENADE_OF_WATER: - bitMask = 1 << QUEST_SONG_SERENADE; - break; - case RG_NOCTURNE_OF_SHADOW: - bitMask = 1 << QUEST_SONG_NOCTURNE; - break; - case RG_REQUIEM_OF_SPIRIT: - bitMask = 1 << QUEST_SONG_REQUIEM; - break; - case RG_PRELUDE_OF_LIGHT: - bitMask = 1 << QUEST_SONG_PRELUDE; - break; - } - - gSaveContext.inventory.questItems |= bitMask; -} - -void GiveLinkDungeonReward(uint16_t getItemId) { - s16 item; - - u8 medallion = 0; - - switch (getItemId) { - case RG_FOREST_MEDALLION: - item = ITEM_MEDALLION_FOREST; - medallion = 1; - break; - case RG_FIRE_MEDALLION: - item = ITEM_MEDALLION_FIRE; - medallion = 1; - break; - case RG_WATER_MEDALLION: - item = ITEM_MEDALLION_WATER; - medallion = 1; - break; - case RG_SHADOW_MEDALLION: - item = ITEM_MEDALLION_SHADOW; - medallion = 1; - break; - case RG_SPIRIT_MEDALLION: - item = ITEM_MEDALLION_SPIRIT; - medallion = 1; - break; - case RG_LIGHT_MEDALLION: - item = ITEM_MEDALLION_LIGHT; - medallion = 1; - break; - case RG_KOKIRI_EMERALD: - item = ITEM_KOKIRI_EMERALD; - break; - case RG_GORON_RUBY: - item = ITEM_GORON_RUBY; - break; - case RG_ZORA_SAPPHIRE: - item = ITEM_ZORA_SAPPHIRE; - break; - } - - if (medallion == 1) { - gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_MEDALLION_FOREST + QUEST_MEDALLION_FOREST]; - } else { - gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_KOKIRI_EMERALD + QUEST_KOKIRI_EMERALD]; - } -} - -void GiveLinkDungeonItem(GetItemID getItemId) { - int mapIndex; - - switch (getItemId) { - case RG_DEKU_TREE_MAP: - case RG_DEKU_TREE_COMPASS: - mapIndex = SCENE_YDAN; - break; - case RG_DODONGOS_CAVERN_MAP: - case RG_DODONGOS_CAVERN_COMPASS: - mapIndex = SCENE_DDAN; - break; - case RG_JABU_JABUS_BELLY_MAP: - case RG_JABU_JABUS_BELLY_COMPASS: - mapIndex = SCENE_BDAN; - break; - case RG_FOREST_TEMPLE_MAP: - case RG_FOREST_TEMPLE_COMPASS: - case RG_FOREST_TEMPLE_SMALL_KEY: - case RG_FOREST_TEMPLE_BOSS_KEY: - mapIndex = SCENE_BMORI1; - break; - case RG_FIRE_TEMPLE_MAP: - case RG_FIRE_TEMPLE_COMPASS: - case RG_FIRE_TEMPLE_SMALL_KEY: - case RG_FIRE_TEMPLE_BOSS_KEY: - mapIndex = SCENE_HIDAN; - break; - case RG_WATER_TEMPLE_MAP: - case RG_WATER_TEMPLE_COMPASS: - case RG_WATER_TEMPLE_SMALL_KEY: - case RG_WATER_TEMPLE_BOSS_KEY: - mapIndex = SCENE_MIZUSIN; - break; - case RG_SPIRIT_TEMPLE_MAP: - case RG_SPIRIT_TEMPLE_COMPASS: - case RG_SPIRIT_TEMPLE_SMALL_KEY: - case RG_SPIRIT_TEMPLE_BOSS_KEY: - mapIndex = SCENE_JYASINZOU; - break; - case RG_SHADOW_TEMPLE_MAP: - case RG_SHADOW_TEMPLE_COMPASS: - case RG_SHADOW_TEMPLE_SMALL_KEY: - case RG_SHADOW_TEMPLE_BOSS_KEY: - mapIndex = SCENE_HAKADAN; - break; - case RG_BOTTOM_OF_THE_WELL_MAP: - case RG_BOTTOM_OF_THE_WELL_COMPASS: - case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: - mapIndex = SCENE_HAKADANCH; - break; - case RG_ICE_CAVERN_MAP: - case RG_ICE_CAVERN_COMPASS: - mapIndex = SCENE_ICE_DOUKUTO; - break; - case RG_GANONS_CASTLE_BOSS_KEY: - mapIndex = SCENE_GANON; - break; - case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: - mapIndex = SCENE_MEN; - break; - case RG_GERUDO_FORTRESS_SMALL_KEY: - mapIndex = SCENE_GERUDOWAY; - break; - case RG_GANONS_CASTLE_SMALL_KEY: - mapIndex = SCENE_GANONTIKA; - break; - } - - if ((getItemId >= RG_GERUDO_FORTRESS_SMALL_KEY) && (getItemId <= RG_GANONS_CASTLE_SMALL_KEY)) { - if (gSaveContext.inventory.dungeonKeys[mapIndex] < 0) { - gSaveContext.inventory.dungeonKeys[mapIndex] = 1; - } else { - gSaveContext.inventory.dungeonKeys[mapIndex]++; + if (getItemEntry.modIndex == MOD_NONE) { + Item_Give(NULL, getItemEntry.itemId); + } else if (getItemEntry.modIndex == MOD_RANDOMIZER) { + Randomizer_Item_Give(NULL, getItemEntry); } - } else { - int bitmask; - if ((getItemId >= RG_DEKU_TREE_MAP) && (getItemId <= RG_ICE_CAVERN_MAP)) { - bitmask = gBitFlags[2]; - } else if ((getItemId >= RG_DEKU_TREE_COMPASS) && (getItemId <= RG_ICE_CAVERN_COMPASS)) { - bitmask = gBitFlags[1]; - } else { - bitmask = gBitFlags[0]; - } - - gSaveContext.inventory.dungeonItems[mapIndex] |= bitmask; } } -void GiveLinkAdultTradeItem(GetItemID giid) { - ItemID item; - switch (giid) { - case GI_POCKET_EGG: - item = ITEM_POCKET_EGG; - break; - case GI_POCKET_CUCCO: - item = ITEM_POCKET_CUCCO; - break; - case GI_COJIRO: - item = ITEM_COJIRO; - break; - case GI_ODD_MUSHROOM: - item = ITEM_ODD_MUSHROOM; - break; - case GI_ODD_POTION: - item = ITEM_ODD_POTION; - break; - case GI_SAW: - item = ITEM_SAW; - break; - case GI_SWORD_BROKEN: - item = ITEM_SWORD_BROKEN; - break; - case GI_PRESCRIPTION: - item = ITEM_PRESCRIPTION; - break; - case GI_FROG: - item = ITEM_FROG; - break; - case GI_EYEDROPS: - item = ITEM_EYEDROPS; - break; - case GI_CLAIM_CHECK: - item = ITEM_CLAIM_CHECK; - break; - } - if ((item == ITEM_SAW) && CVar_GetS32("gDekuNutUpgradeFix", 0) == 0) { - gSaveContext.itemGetInf[1] |= 0x8000; - } - - if (item >= ITEM_POCKET_EGG) { - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); - } - INV_CONTENT(ITEM_TRADE_ADULT) = item; -} - -void GiveLinksPocketMedallion() { - GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, RG_NONE); - - GiveLinkDungeonReward(getItemEntry.getItemId); -} - /** * Copy save currently on the buffer to Save Context and complete various tasks to open the save. * This includes: @@ -802,7 +344,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { } // Give Link's pocket item - GiveLinksPocketMedallion(); + GiveLinksPocketItem(); int openForest = Randomizer_GetSettingValue(RSK_FOREST); switch (openForest) { @@ -831,8 +373,8 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { break; } - if(Randomizer_GetSettingValue(RSK_STARTING_KOKIRI_SWORD)) GiveLinkKokiriSword(); - if(Randomizer_GetSettingValue(RSK_STARTING_DEKU_SHIELD)) GiveLinkDekuShield(); + if(Randomizer_GetSettingValue(RSK_STARTING_KOKIRI_SWORD)) Item_Give(NULL, ITEM_SWORD_KOKIRI); + if(Randomizer_GetSettingValue(RSK_STARTING_DEKU_SHIELD)) Item_Give(NULL, ITEM_SHIELD_DEKU); if(Randomizer_GetSettingValue(RSK_STARTING_OCARINA)) { INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY; @@ -858,73 +400,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { s32 giid = getItem.getItemId; if (getItem.modIndex == MOD_NONE) { - if (getItem.itemId >= ITEM_MEDALLION_FOREST && getItem.itemId <= ITEM_ZORA_SAPPHIRE) { - GiveLinkDungeonReward(getItem.getItemId); - } else if (getItem.itemId >= ITEM_SONG_MINUET && getItem.itemId <= ITEM_SONG_STORMS) { - GiveLinkSong(getItem.getItemId); - } else if (giid == GI_RUPEE_GREEN || giid == GI_RUPEE_BLUE || giid == GI_RUPEE_RED || - giid == GI_RUPEE_PURPLE || giid == GI_RUPEE_GOLD) { - GiveLinkRupeesByGetItemId(giid); - } else if (giid == GI_BOMBCHUS_10 || giid == GI_BOMBCHUS_5 || giid == GI_BOMBCHUS_20) { - GiveLinkBombchus(giid); - } else if (giid == GI_STICKS_1 || giid == GI_STICKS_5 || giid == GI_STICKS_10) { - GiveLinkDekuSticksByGetItemId(giid); - } else if (giid == GI_NUTS_5 || giid == GI_NUTS_10) { - GiveLinkDekuNutsByGetItemId(giid); - } else if (giid == GI_BEAN) { - GiveLinkBeans(); - } else if (giid == GI_SWORD_KOKIRI) { - GiveLinkKokiriSword(); - } else if (giid == GI_SWORD_BGS) { - GiveLinkBiggoronSword(); - } else if (giid == GI_SWORD_KNIFE) { - GiveLinkGiantsKnife(); - } else if (giid == GI_SHIELD_DEKU) { - GiveLinkDekuShield(); - } else if (giid == GI_SHIELD_HYLIAN) { - GiveLinkHylianShield(); - } else if (giid == GI_SHIELD_MIRROR) { - GiveLinkMirrorShield(); - } else if (giid == GI_TUNIC_GORON) { - GiveLinkGoronTunic(); - } else if (giid == GI_TUNIC_ZORA) { - GiveLinkZoraTunic(); - } else if (giid == GI_BOOTS_IRON) { - GiveLinkIronBoots(); - } else if (giid == GI_BOOTS_HOVER) { - GiveLinkHoverBoots(); - } else if (giid == GI_SLINGSHOT || giid == GI_BULLET_BAG_40 || giid == GI_BULLET_BAG_50) { - GiveLinkBulletBagUpgrade(giid); - } else if (giid == GI_BOW || giid == GI_QUIVER_40 || giid == GI_QUIVER_50) { - GiveLinkQuiverUpgrade(giid); - } else if (giid == GI_BOMB_BAG_20 || giid == GI_BOMB_BAG_30 || giid == GI_BOMB_BAG_40) { - GiveLinkBombBagUpgrade(giid); - } else if (giid == GI_BRACELET || giid == GI_GAUNTLETS_SILVER || giid == GI_GAUNTLETS_GOLD) { - GiveLinkStrengthUpgrade(giid); - } else if (giid == GI_SCALE_SILVER || giid == GI_SCALE_GOLD) { - GiveLinkScaleUpgrade(giid); - } else if (giid == GI_WALLET_ADULT || giid == GI_WALLET_GIANT) { - GiveLinkWalletUpgrade(giid); - } else if (giid == GI_STONE_OF_AGONY) { - GiveLinkStoneOfAgony(); - } else if (giid == GI_GERUDO_CARD) { - GiveLinkGerudoCard(); - } else if (giid == GI_HEART_PIECE) { - GiveLinkPieceOfHeart(); - } else if (giid == GI_HEART_CONTAINER) { - GiveLinkHeartContainer(); - } else if (giid == GI_STICK_UPGRADE_20 || giid == GI_STICK_UPGRADE_30) { - GiveLinkDekuStickUpgrade(giid); - } else if (giid == GI_NUT_UPGRADE_30 || giid == GI_NUT_UPGRADE_40) { - GiveLinkDekuNutUpgrade(giid); - } else if (giid == GI_SKULL_TOKEN) { - GiveLinkSkullToken(); - } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK || giid == GI_COJIRO) { - GiveLinkAdultTradeItem(giid); - } else { - s32 iid = getItem.itemId; - if (iid != -1) INV_CONTENT(iid) = iid; - } + Item_Give(NULL, getItem.itemId); } else if (getItem.modIndex == MOD_RANDOMIZER) { Randomizer_Item_Give(NULL, getItem); } @@ -1033,7 +509,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.sceneFlags[12].collect |= (1 << 0x0C); if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) { - GiveLinkGerudoCard(); + Item_Give(NULL, ITEM_GERUDO_CARD); } } diff --git a/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c b/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c index e04755a34..33adac2cf 100644 --- a/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c +++ b/soh/src/overlays/actors/ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c @@ -70,7 +70,7 @@ const ActorInit Bg_Dy_Yoseizo_InitVars = { void GivePlayerRandoRewardGreatFairy(BgDyYoseizo* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_NONE, this->actor.id, this->fountainType + 1, globalCtx->sceneNum); + GetItemEntry getItemEntry = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->fountainType + 1, GI_NONE); if (this->actor.parent == GET_PLAYER(globalCtx) && !Flags_GetTreasure(globalCtx, this->fountainType + 1) && !Player_InBlockingCsMode(globalCtx, GET_PLAYER(globalCtx))) { diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index 6d0b51db2..b2dc185d7 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -88,7 +88,7 @@ s32 DemoKekkai_CheckEventFlag(s32 params) { if ((params < KEKKAI_TOWER) || (params > KEKKAI_FOREST)) { return true; } - if (gSaveContext.n64ddFlag) { + if (gSaveContext.n64ddFlag && params > KEKKAI_TOWER) { return Flags_GetRandomizerInf(trialParamToRandInf(params)); } return Flags_GetEventChkInf(eventFlags[params]); diff --git a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c index e372d3291..39b754fb8 100644 --- a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c +++ b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c @@ -462,7 +462,7 @@ s32 DoorWarp1_PlayerInRange(DoorWarp1* this, GlobalContext* globalCtx) { } void GivePlayerRandoReward(DoorWarp1* this, Player* player, GlobalContext* globalCtx, u8 ruto, u8 adult) { - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_NONE, this->actor.id, this->actor.params, globalCtx->sceneNum); + GetItemEntry getItemEntry = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_NONE); if (this->actor.parent != NULL && this->actor.parent->id == GET_PLAYER(globalCtx)->actor.id && !Flags_GetTreasure(globalCtx, 0x1F)) { diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index 3e78982a3..26d29b6d4 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -446,7 +446,7 @@ void EnBox_WaitOpen(EnBox* this, GlobalContext* globalCtx) { func_8002DBD0(&this->dyna.actor, &sp4C, &player->actor.world.pos); if (sp4C.z > -50.0f && sp4C.z < 0.0f && fabsf(sp4C.y) < 10.0f && fabsf(sp4C.x) < 20.0f && Player_IsFacingActor(&this->dyna.actor, 0x3000, globalCtx)) { - sItem = Randomizer_GetRandomizedItem(this->dyna.actor.params >> 5 & 0x7F, this->dyna.actor.id, this->dyna.actor.params, globalCtx->sceneNum); + sItem = Randomizer_GetItemFromActor(this->dyna.actor.id, globalCtx->sceneNum, this->dyna.actor.params, this->dyna.actor.params >> 5 & 0x7F); GetItemEntry blueRupee = ItemTable_RetrieveEntry(MOD_NONE, GI_RUPEE_BLUE); // RANDOTODO treasure chest game rando diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c index 39e1195f5..b955eda0e 100644 --- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c +++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c @@ -187,7 +187,7 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) { if (!gSaveContext.n64ddFlag) { GetItem_Draw(globalCtx, GID_SKULL_TOKEN_2); } else { - getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_SKULL_TOKEN); EnItem00_CustomItemsParticles(&this->actor, globalCtx, getItem); if (getItem.itemId != ITEM_SKULL_TOKEN) { f32 mtxScale = 1.5f; @@ -202,7 +202,7 @@ void EnSi_Draw(Actor* thisx, GlobalContext* globalCtx) { void Randomizer_UpdateSkullReward(EnSi* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); - getItem = Randomizer_GetRandomizedItem(GI_SKULL_TOKEN, this->actor.id, this->actor.params, globalCtx->sceneNum); + getItem = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_SKULL_TOKEN); getItemId = getItem.getItemId; if (getItemId == RG_ICE_TRAP) { player->pendingIceTrap = true; diff --git a/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c b/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c index f4181146a..b785d35fa 100644 --- a/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c +++ b/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c @@ -62,7 +62,7 @@ void ItemBHeart_Update(Actor* thisx, GlobalContext* globalCtx) { if (!gSaveContext.n64ddFlag) { func_8002F434(&this->actor, globalCtx, GI_HEART_CONTAINER_2, 30.0f, 40.0f); } else { - GetItemEntry getItemEntry = Randomizer_GetRandomizedItem(GI_HEART_CONTAINER_2, this->actor.id, this->actor.params, globalCtx->sceneNum); + GetItemEntry getItemEntry = Randomizer_GetItemFromActor(this->actor.id, globalCtx->sceneNum, this->actor.params, GI_HEART_CONTAINER_2); GiveItemEntryFromActor(&this->actor, globalCtx, getItemEntry, 30.0f, 40.0f); } } @@ -99,8 +99,8 @@ void ItemBHeart_Draw(Actor* thisx, GlobalContext* globalCtx) { } if (gSaveContext.n64ddFlag) { - GetItemEntry_Draw(globalCtx, Randomizer_GetRandomizedItem(GI_HEART_CONTAINER_2, - this->actor.id,this->actor.params, globalCtx->sceneNum)); + GetItemEntry_Draw(globalCtx, Randomizer_GetItemFromActor(this->actor.id, + globalCtx->sceneNum,this->actor.params, GI_HEART_CONTAINER_2)); } else { if (flag) { func_80093D84(globalCtx->state.gfxCtx); diff --git a/soh/src/overlays/gamestates/ovl_title/z_title.c b/soh/src/overlays/gamestates/ovl_title/z_title.c index 73da17185..7c63ef35c 100644 --- a/soh/src/overlays/gamestates/ovl_title/z_title.c +++ b/soh/src/overlays/gamestates/ovl_title/z_title.c @@ -10,7 +10,7 @@ #include "alloca.h" #include "textures/nintendo_rogo_static/nintendo_rogo_static.h" #include -#include "GameVersions.h" +#include #include const char* GetGameVersionString(); @@ -301,6 +301,9 @@ void Title_Init(GameState* thisx) { saveloading = true; gSaveContext.fileNum = selectedfile; Sram_OpenSave(); + Randomizer_LoadSettings(""); + Randomizer_LoadHintLocations(""); + Randomizer_LoadItemLocations("", true); gSaveContext.gameMode = 0; gSaveContext.magic = gSaveContext.magic; SET_NEXT_GAMESTATE(&this->state, Gameplay_Init, GlobalContext);