mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-04 03:12:48 -04:00
Compare commits
228 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93e9767c9f | |||
| c774f53dad | |||
| 7fbfe5ad88 | |||
| ef02037990 | |||
| 23cc18ba0e | |||
| 924dbc7715 | |||
| 742f4938f2 | |||
| 02e0f586d3 | |||
| 5717aeef85 | |||
| da9b99f650 | |||
| dd2b993cd5 | |||
| 83577d3b82 | |||
| 1cb8b19520 | |||
| d109cd891e | |||
| 63c4002ca6 | |||
| 6954efcd15 | |||
| 78c2147771 | |||
| c938d5468e | |||
| 35590c5312 | |||
| e976b10e2a | |||
| 3949706b28 | |||
| ce55916845 | |||
| 9b252cbdd2 | |||
| 97fa09f6ee | |||
| 0e7a7cccb9 | |||
| 1c0cdcc176 | |||
| 280305c2ba | |||
| d1f1d579bc | |||
| eeeb3ffe25 | |||
| 1ee0f862e1 | |||
| 6b327c9f61 | |||
| f148e0ebc1 | |||
| 6f20f4d629 | |||
| 94670270d6 | |||
| 8e21247a97 | |||
| aa84004cb4 | |||
| e1c201f4bd | |||
| 425a1d15a0 | |||
| e3ad41792a | |||
| c1ba10fc8b | |||
| 1c5686f71b | |||
| b9e0f2b9ca | |||
| ede175f141 | |||
| a301874e30 | |||
| 9b4a9a6bd9 | |||
| 04274b1884 | |||
| ca783b8424 | |||
| 2e4c2b5b46 | |||
| 4c09d8b910 | |||
| fb1b260d09 | |||
| 98eb8f718e | |||
| 68b2e0ee2d | |||
| 81771a0522 | |||
| 93c8bcc210 | |||
| 176bf5f0c4 | |||
| 65a5945778 | |||
| 8f7b9cdfdd | |||
| acecba7ff7 | |||
| 507e0aadbc | |||
| 8406d9b192 | |||
| 6f3170cb56 | |||
| 835582224e | |||
| 52879f50f0 | |||
| 2b505f1be4 | |||
| f089f9024d | |||
| 43fb421a93 | |||
| f06d6b50a9 | |||
| 2c987b0211 | |||
| 3d860ad454 | |||
| b5bf19569b | |||
| 5a7f5cb4a7 | |||
| 1affefbbfc | |||
| e4ff38a712 | |||
| f2ac4d6f44 | |||
| 48b98a5432 | |||
| a4752154f7 | |||
| 0d973a497b | |||
| ab4eccf1df | |||
| e0c449f28e | |||
| ce9a5c06d5 | |||
| 2bbba1e4e8 | |||
| 39298f8d8f | |||
| 32b4c0567a | |||
| 7ff1b5332e | |||
| 5e77a60bd6 | |||
| 9629c000bd | |||
| 9dc5fed686 | |||
| 2cc9db77dd | |||
| 8aa08c9443 | |||
| dca3e2eba6 | |||
| 57061fba38 | |||
| cee6a24309 | |||
| 62edb3abc6 | |||
| 1c9e1c0a66 | |||
| a06aeb10c1 | |||
| b84b309e00 | |||
| 62eecb3ccd | |||
| ec07572ced | |||
| b45e2fa34d | |||
| 289a718446 | |||
| 292a2a6c34 | |||
| 2e8415b950 | |||
| dbf1f6e354 | |||
| 9a2fe9745d | |||
| b5ca343fac | |||
| 88c7ff63ff | |||
| 7a438ad30f | |||
| 89649de7c3 | |||
| a1960eaa33 | |||
| d6820c9233 | |||
| 5c4bb8d33d | |||
| e3ce1f01c9 | |||
| 9b6b344ecf | |||
| 3db85d5b44 | |||
| b5871d72d9 | |||
| b70a714f88 | |||
| cad5a8d1bc | |||
| 93f8a5fa8f | |||
| b0809ea78c | |||
| b0e9033736 | |||
| 1ac6df8de7 | |||
| 5899b2157a | |||
| 3185f578fb | |||
| 4fc09799b6 | |||
| fe0e3cad72 | |||
| 37d1aa7f40 | |||
| 4a12554bf4 | |||
| fecd1d5683 | |||
| bce9bf6fd9 | |||
| fbf63b075a | |||
| b86d6e90e2 | |||
| 6425b452e7 | |||
| 1657fe8083 | |||
| ecd74a4cbd | |||
| 36dc43c602 | |||
| d92515f0d4 | |||
| f147dcac0c | |||
| ee4c84f39b | |||
| b8a83c6f59 | |||
| 4462c0ef69 | |||
| c803bfb545 | |||
| 2623c44cab | |||
| 24dd02fc81 | |||
| a97602b6dc | |||
| e2943e90dc | |||
| 3cb7fbd030 | |||
| afe54f22ab | |||
| e15f5bcee9 | |||
| 1e372a856d | |||
| b26896cad5 | |||
| f75faf6b06 | |||
| b48d9aa052 | |||
| d899706208 | |||
| 3e05789b58 | |||
| 9a7b62cbc6 | |||
| 8e0f0e878e | |||
| 79344edf0d | |||
| e59bfd1a9c | |||
| 4d12cc8ea2 | |||
| 2ed2268579 | |||
| 94a99e8da0 | |||
| ddaf50c01d | |||
| 7566949b42 | |||
| bb6db3caea | |||
| 2dc494dc1c | |||
| 3c25633ee9 | |||
| d99ed2729b | |||
| 782455d48b | |||
| 47863b34c2 | |||
| 92391d5eb8 | |||
| 0d37cb4e54 | |||
| ea528ed9d9 | |||
| f7b880c5ea | |||
| ff78bc8d6c | |||
| 6503b4e7eb | |||
| 30b7087f30 | |||
| 0c1372f986 | |||
| 8fb4ba8924 | |||
| 5f675c6f2b | |||
| b3333241c5 | |||
| e39079c0f8 | |||
| c3317d9232 | |||
| a4777045fe | |||
| bbe8ea6aa6 | |||
| d662db69f0 | |||
| 9b259143be | |||
| 025cb58493 | |||
| b3dee825e8 | |||
| f6c5aac3c8 | |||
| 25e9064d09 | |||
| 5f33489465 | |||
| 3e1e8f1244 | |||
| 23a91a37be | |||
| a886f8a2df | |||
| 6df7b1e9cd | |||
| 206c02b527 | |||
| a05d1a9ee6 | |||
| ed0df01b8d | |||
| 0f9d563a3e | |||
| f3fb65495e | |||
| 196f33005e | |||
| 90c0bdded0 | |||
| f856f871bb | |||
| e75ea18ef0 | |||
| 50e2d9d1a7 | |||
| 5c84978c3c | |||
| 3859f39729 | |||
| 3498ded9d9 | |||
| 8784958c40 | |||
| c1231885fe | |||
| 6cf94b4491 | |||
| 30aa2dd527 | |||
| 8e121a7e51 | |||
| 0bf663141a | |||
| 17949e526b | |||
| d7dced7ddf | |||
| 78b0563c0e | |||
| 871d18e294 | |||
| c157564da6 | |||
| ecc3b00c51 | |||
| 8afb1141ab | |||
| 8c5673d9b8 | |||
| 916dfcd9da | |||
| 842210e539 | |||
| 39d951d0cb | |||
| a4be0841e5 | |||
| 0d76b90144 | |||
| a6690c2052 |
+1
-1
@@ -2,7 +2,7 @@
|
||||
Language: Cpp
|
||||
Standard: C++03
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignOperands: true
|
||||
|
||||
@@ -100,6 +100,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
endif ()
|
||||
set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
|
||||
set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE)
|
||||
set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE)
|
||||
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
||||
|
||||
add_subdirectory(libs/freeverb)
|
||||
@@ -306,6 +307,10 @@ if (DUSK_ENABLE_SENTRY_NATIVE)
|
||||
list(APPEND GAME_COMPILE_DEFS DUSK_ENABLE_SENTRY_NATIVE=1 SENTRY_BUILD_STATIC=1)
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND GAME_LIBS Ws2_32)
|
||||
endif ()
|
||||
|
||||
if (DUSK_MOVIE_SUPPORT)
|
||||
if (TARGET libjpeg-turbo::turbojpeg-static)
|
||||
list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||

|
||||

|
||||
|
||||
- ### **[Official Website](https://twilitrealm.dev)**
|
||||
- ### **[Discord](https://discord.gg/QACynxeyna)**
|
||||
|
||||
# Overview
|
||||
Dusk is a reverse-engineered reimplementation of Twilight Princess.
|
||||
It aims to be as accurate as possible to the original while also providing new options, enhancements, and tools to customize your experience.
|
||||
|
||||
# Setup
|
||||
**⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.**
|
||||
|
||||
@@ -27,5 +31,7 @@ First make sure your dump of the game is clean and supported by Dusk. You can do
|
||||
# Building
|
||||
If you'd like to build Dusk from source, please read the [build instructions](docs/building.md).
|
||||
|
||||
Pull Requests are welcomed! Note that we do not accept contributions that are primarily AI generated and will close your PR if we suspect as much.
|
||||
|
||||
# Credits
|
||||
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors).
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 135e976867...77ad549530
+45
-1
@@ -1,7 +1,7 @@
|
||||
|
||||
set(DOLZEL_FILES
|
||||
src/m_Do/m_Do_main.cpp
|
||||
src/m_Do/m_Do_printf.cpp
|
||||
#src/m_Do/m_Do_printf.cpp
|
||||
src/m_Do/m_Do_audio.cpp
|
||||
src/m_Do/m_Do_controller_pad.cpp
|
||||
#src/m_Do/m_Re_controller_pad.cpp
|
||||
@@ -1429,6 +1429,7 @@ set(DUSK_FILES
|
||||
src/dusk/globals.cpp
|
||||
src/dusk/gyro.cpp
|
||||
src/dusk/gamepad_color.cpp
|
||||
src/dusk/autosave.cpp
|
||||
src/dusk/io.cpp
|
||||
src/dusk/layout.cpp
|
||||
src/dusk/logging.cpp
|
||||
@@ -1462,10 +1463,53 @@ set(DUSK_FILES
|
||||
src/dusk/imgui/ImGuiStateShare.cpp
|
||||
src/dusk/imgui/ImGuiAchievements.hpp
|
||||
src/dusk/imgui/ImGuiAchievements.cpp
|
||||
src/dusk/ui/bool_button.cpp
|
||||
src/dusk/ui/bool_button.hpp
|
||||
src/dusk/ui/button.cpp
|
||||
src/dusk/ui/button.hpp
|
||||
src/dusk/ui/component.cpp
|
||||
src/dusk/ui/component.hpp
|
||||
src/dusk/ui/controller_config.cpp
|
||||
src/dusk/ui/controller_config.hpp
|
||||
src/dusk/ui/document.cpp
|
||||
src/dusk/ui/document.hpp
|
||||
src/dusk/ui/editor.cpp
|
||||
src/dusk/ui/editor.hpp
|
||||
src/dusk/ui/event.cpp
|
||||
src/dusk/ui/event.hpp
|
||||
src/dusk/ui/input.cpp
|
||||
src/dusk/ui/input.hpp
|
||||
src/dusk/ui/nav_types.hpp
|
||||
src/dusk/ui/number_button.cpp
|
||||
src/dusk/ui/number_button.hpp
|
||||
src/dusk/ui/overlay.cpp
|
||||
src/dusk/ui/overlay.hpp
|
||||
src/dusk/ui/pane.cpp
|
||||
src/dusk/ui/pane.hpp
|
||||
src/dusk/ui/popup.cpp
|
||||
src/dusk/ui/popup.hpp
|
||||
src/dusk/ui/prelaunch.cpp
|
||||
src/dusk/ui/prelaunch.hpp
|
||||
src/dusk/ui/prelaunch_options.cpp
|
||||
src/dusk/ui/prelaunch_options.hpp
|
||||
src/dusk/ui/select_button.cpp
|
||||
src/dusk/ui/select_button.hpp
|
||||
src/dusk/ui/settings.cpp
|
||||
src/dusk/ui/settings.hpp
|
||||
src/dusk/ui/string_button.cpp
|
||||
src/dusk/ui/string_button.hpp
|
||||
src/dusk/ui/tab_bar.cpp
|
||||
src/dusk/ui/tab_bar.hpp
|
||||
src/dusk/ui/ui.cpp
|
||||
src/dusk/ui/ui.hpp
|
||||
src/dusk/ui/window.cpp
|
||||
src/dusk/ui/window.hpp
|
||||
src/dusk/achievements.cpp
|
||||
src/dusk/iso_validate.cpp
|
||||
src/dusk/livesplit.cpp
|
||||
src/dusk/offset_ptr.cpp
|
||||
src/dusk/OSContext.cpp
|
||||
src/dusk/OSReport.cpp
|
||||
src/dusk/OSThread.cpp
|
||||
src/dusk/OSMutex.cpp
|
||||
src/dusk/discord_presence.cpp
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
/* 0x17C */ cXyz mViewScale;
|
||||
#if TARGET_PC
|
||||
bool mbReset = false;
|
||||
bool mbHadEntry = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@ public:
|
||||
int Draw();
|
||||
int Delete();
|
||||
|
||||
#if TARGET_PC
|
||||
void onInterpCallback();
|
||||
#endif
|
||||
|
||||
enum Param_e {
|
||||
LOCK_e = (1 << 6), NO_BASE_DISP = (1 << 7)
|
||||
};
|
||||
@@ -50,6 +54,13 @@ private:
|
||||
/* 0x1020 */ dCcD_Cyl mCylinderCollider;
|
||||
/* 0x115C */ s32 mStopSwingingFrames;
|
||||
|
||||
#if TARGET_PC
|
||||
cXyz mChainInterpPrev[64];
|
||||
cXyz mChainInterpCurr[64];
|
||||
bool mChainInterpPrevValid;
|
||||
bool mChainInterpCurrValid;
|
||||
#endif
|
||||
|
||||
// Number of chain models
|
||||
u32 getArg0() {
|
||||
return fopAcM_GetParamBit(this, 0, 6);
|
||||
|
||||
@@ -58,6 +58,9 @@ public:
|
||||
void setNextPoint();
|
||||
int Draw();
|
||||
int Delete();
|
||||
#if TARGET_PC
|
||||
friend void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork);
|
||||
#endif
|
||||
|
||||
u8 getPthID() { return fopAcM_GetParamBit(this, 0, 8); }
|
||||
u8 getMoveSpeed() { return fopAcM_GetParamBit(this, 8, 4); }
|
||||
|
||||
@@ -91,6 +91,10 @@ public:
|
||||
void calcCursor();
|
||||
void drawCursor();
|
||||
|
||||
#if TARGET_PC
|
||||
void dMapBgWide();
|
||||
#endif
|
||||
|
||||
void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; }
|
||||
|
||||
f32 getMapWidth() { return mMapWidth; }
|
||||
|
||||
@@ -81,6 +81,10 @@ public:
|
||||
void calcDrawPriority();
|
||||
void setArrowPosAxis(f32, f32);
|
||||
|
||||
#if TARGET_PC
|
||||
void fMapBackWide();
|
||||
#endif
|
||||
|
||||
virtual void draw();
|
||||
virtual ~dMenu_Fmap2DBack_c();
|
||||
|
||||
@@ -330,6 +334,10 @@ public:
|
||||
void setHIO(bool);
|
||||
bool isWarpAccept();
|
||||
|
||||
#if TARGET_PC
|
||||
void fMapTopWide();
|
||||
#endif
|
||||
|
||||
virtual void draw();
|
||||
virtual ~dMenu_Fmap2DTop_c();
|
||||
|
||||
|
||||
@@ -67,6 +67,9 @@ public:
|
||||
bool isStaffMessage();
|
||||
bool isSaveMessage();
|
||||
bool isTalkMessage();
|
||||
#if TARGET_PC
|
||||
bool isShopItemMessage();
|
||||
#endif
|
||||
const char* getSmellName();
|
||||
const char* getPortalName();
|
||||
const char* getBombName();
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
@@ -14,6 +16,7 @@ enum class AchievementCategory : uint8_t {
|
||||
Collection,
|
||||
Challenge,
|
||||
Minigame,
|
||||
Misc,
|
||||
Glitched
|
||||
};
|
||||
|
||||
@@ -40,6 +43,11 @@ public:
|
||||
void save();
|
||||
void tick();
|
||||
void clearAll();
|
||||
void clearOne(const char* key);
|
||||
|
||||
// Signals are visible to all achievement checks within the same tick, then cleared.
|
||||
void signal(const char* key);
|
||||
bool hasSignal(const char* key) const;
|
||||
|
||||
std::vector<Achievement> getAchievements() const;
|
||||
bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); }
|
||||
@@ -57,6 +65,7 @@ private:
|
||||
void processEntry(Entry& e);
|
||||
|
||||
std::vector<Entry> m_entries;
|
||||
std::unordered_set<std::string_view> m_signals;
|
||||
bool m_loaded = false;
|
||||
bool m_dirty = false;
|
||||
std::queue<std::string> m_pendingUnlocks;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef AUTOSAVE_H
|
||||
#define AUTOSAVE_H
|
||||
|
||||
#include <m_Do/m_Do_MemCardRWmng.h>
|
||||
#include <m_Do/m_Do_MemCard.h>
|
||||
|
||||
void noAutoSave();
|
||||
void triggerAutoSave();
|
||||
void updateAutoSave();
|
||||
void enterAutoSave();
|
||||
void autoSaving();
|
||||
void waitingForWrite();
|
||||
void endAutoSave();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dusk::speedrun {
|
||||
void onGameFrame();
|
||||
uint64_t getFrameCount();
|
||||
void start();
|
||||
void reset();
|
||||
void connectLiveSplit(const char* host = "127.0.0.1", int port = 16834);
|
||||
void disconnectLiveSplit();
|
||||
bool consumeConnectedEvent();
|
||||
bool consumeDisconnectedEvent();
|
||||
void updateLiveSplit();
|
||||
void shutdown();
|
||||
}
|
||||
@@ -55,6 +55,7 @@ struct UserSettings {
|
||||
ConfigVar<int> soundEffectsVolume;
|
||||
ConfigVar<int> fanfareVolume;
|
||||
ConfigVar<bool> enableReverb;
|
||||
ConfigVar<bool> enableHrtf;
|
||||
} audio;
|
||||
|
||||
// Game settings
|
||||
@@ -76,9 +77,11 @@ struct UserSettings {
|
||||
ConfigVar<bool> fastClimbing;
|
||||
ConfigVar<bool> noMissClimbing;
|
||||
ConfigVar<bool> fastTears;
|
||||
ConfigVar<bool> no2ndFishForCat;
|
||||
ConfigVar<bool> instantSaves;
|
||||
ConfigVar<bool> instantText;
|
||||
ConfigVar<bool> sunsSong;
|
||||
ConfigVar<bool> autoSave;
|
||||
|
||||
// Preferences
|
||||
ConfigVar<bool> enableMirrorMode;
|
||||
@@ -96,6 +99,7 @@ struct UserSettings {
|
||||
ConfigVar<int> internalResolutionScale;
|
||||
ConfigVar<int> shadowResolutionMultiplier;
|
||||
ConfigVar<bool> enableDepthOfField;
|
||||
ConfigVar<bool> enableMapBackground;
|
||||
|
||||
// Audio
|
||||
ConfigVar<bool> noLowHpSound;
|
||||
@@ -137,6 +141,10 @@ struct UserSettings {
|
||||
|
||||
// Controls
|
||||
ConfigVar<bool> enableTurboKeybind;
|
||||
|
||||
// Tools
|
||||
ConfigVar<bool> speedrunMode;
|
||||
ConfigVar<bool> liveSplitEnabled;
|
||||
} game;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -59,6 +59,9 @@ public:
|
||||
bool isActive() const { return mSeqList.getNumLinks() != 0; }
|
||||
int getNumActiveSeqs() const { return mSeqList.getNumLinks(); }
|
||||
void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; }
|
||||
#if TARGET_PC
|
||||
JSUList<JAISeq>* getSeqList() { return &mSeqList; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* 0x08 */ JAIAudience* mAudience;
|
||||
|
||||
@@ -207,4 +207,11 @@ void JPARegistAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
void JPARegistPrmAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
|
||||
#if TARGET_PC
|
||||
void JPAInterpBillboard(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
void JPAInterpRotBillboard(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
void JPAInterpDirection(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
void JPAInterpRotDirection(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
#endif
|
||||
|
||||
#endif /* JPABASESHAPE_H */
|
||||
|
||||
@@ -24,6 +24,9 @@ public:
|
||||
void init_c(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
bool calc_p(JPAEmitterWorkData*);
|
||||
bool calc_c(JPAEmitterWorkData*);
|
||||
#if TARGET_PC
|
||||
void interp(JPAEmitterWorkData*, void const* drawFunc);
|
||||
#endif
|
||||
bool canCreateChild(JPAEmitterWorkData*);
|
||||
f32 getWidth(JPABaseEmitter const*) const;
|
||||
f32 getHeight(JPABaseEmitter const*) const;
|
||||
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); }
|
||||
u16 getNumColors() const { return mNumColors; }
|
||||
ResTLUT* getColorTable() const { return mColorTable; }
|
||||
#if TARGET_PC
|
||||
void dataUploaded();
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* 0x00 */ GXTlutObj mTlutObj;
|
||||
|
||||
@@ -75,6 +75,7 @@ public:
|
||||
s32 getTransparency() const { return mTexInfo->alphaEnabled; }
|
||||
s32 getWidth() const { return mTexInfo->width; }
|
||||
s32 getHeight() const { return mTexInfo->height; }
|
||||
JUTPalette* getPalette() const { return mPalette; }
|
||||
void setCaptureFlag(bool flag) { mFlags &= 2 | flag; }
|
||||
bool getCaptureFlag() const { return mFlags & 1; }
|
||||
bool getEmbPaletteDelFlag() const { return mFlags & 2; }
|
||||
@@ -82,7 +83,7 @@ public:
|
||||
int getTlutName() const { return mTlutName; }
|
||||
bool operator==(const JUTTexture& other) {
|
||||
return mTexInfo == other.mTexInfo
|
||||
&& field_0x2c == other.field_0x2c
|
||||
&& mPalette == other.mPalette
|
||||
&& mWrapS == other.mWrapS
|
||||
&& mWrapT == other.mWrapT
|
||||
&& mMinFilter == other.mMinFilter
|
||||
@@ -100,7 +101,7 @@ private:
|
||||
/* 0x20 */ const ResTIMG* mTexInfo;
|
||||
/* 0x24 */ void* mTexData;
|
||||
/* 0x28 */ JUTPalette* mEmbPalette;
|
||||
/* 0x2C */ JUTPalette* field_0x2c;
|
||||
/* 0x2C */ JUTPalette* mPalette;
|
||||
/* 0x30 */ u8 mWrapS;
|
||||
/* 0x31 */ u8 mWrapT;
|
||||
/* 0x32 */ u8 mMinFilter;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
||||
|
||||
#include "JSystem/JAudio2/JASChannel.h"
|
||||
#if TARGET_PC
|
||||
#include "dusk/audio/DuskDsp.hpp"
|
||||
#endif
|
||||
#include "JSystem/JAudio2/JASAiCtrl.h"
|
||||
#include "JSystem/JAudio2/JASCalc.h"
|
||||
#include "JSystem/JAudio2/JASDriverIF.h"
|
||||
@@ -170,7 +173,12 @@ void JASChannel::updateEffectorParam(JASDsp::TChannel* i_channel, u16* i_mixerVo
|
||||
|
||||
f32 pan = 0.5f;
|
||||
f32 dolby = 0.0f;
|
||||
switch (JASDriver::getOutputMode()) {
|
||||
#if TARGET_PC
|
||||
u32 effectiveOutputMode = dusk::audio::EnableHrtf ? JAS_OUTPUT_SURROUND : JASDriver::getOutputMode();
|
||||
#else
|
||||
u32 effectiveOutputMode = JASDriver::getOutputMode();
|
||||
#endif
|
||||
switch (effectiveOutputMode) {
|
||||
case JAS_OUTPUT_MONO:
|
||||
break;
|
||||
case JAS_OUTPUT_STEREO:
|
||||
|
||||
@@ -302,7 +302,6 @@ void JASKernel::setupRootHeap(JKRSolidHeap* heap, u32 size) {
|
||||
JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap");
|
||||
JUT_ASSERT(787, sSystemHeap);
|
||||
sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>;
|
||||
JKRHEAP_NAME(sSystemHeap, "JASKernel::sCommandHeap");
|
||||
JUT_ASSERT(790, sCommandHeap);
|
||||
JASDram = heap;
|
||||
}
|
||||
|
||||
@@ -442,6 +442,7 @@ static JAUSectionHeap* JAUNewSectionHeap(JKRSolidHeap* heap, bool param_1) {
|
||||
JAUSectionHeap* JAUNewSectionHeap(bool param_0) {
|
||||
s32 freeSize = JASDram->getFreeSize();
|
||||
JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true);
|
||||
JKRHEAP_NAME(sectionHeap, "sectionHeap");
|
||||
JUT_ASSERT(821, sectionHeap);
|
||||
return JAUNewSectionHeap(sectionHeap, param_0);
|
||||
}
|
||||
|
||||
@@ -222,16 +222,11 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
||||
OSReport_Error("Free block list as follows:\n");
|
||||
OSReport_Error("Start | End | Size \n");
|
||||
|
||||
int i = 0;
|
||||
for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) {
|
||||
if (block->mMagic) {
|
||||
// Allocated, ignore.
|
||||
continue;
|
||||
}
|
||||
if (i++ > 10) {
|
||||
OSReport_Error("<more>\n");
|
||||
break;
|
||||
}
|
||||
|
||||
auto blockStart = (uintptr_t)block - (uintptr_t)mStart;
|
||||
auto blockEnd = (uintptr_t)block + block->size - (uintptr_t)mStart;
|
||||
@@ -239,6 +234,14 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
||||
OSReport_Error("%08X | %08X | %08X\n", (u32) blockStart, (u32) blockEnd, (u32) blockSize);
|
||||
}
|
||||
|
||||
OSReport_Error("Child heaps as follows:\n");
|
||||
OSReport_Error("Start | End | Name \n");
|
||||
|
||||
const JSUTree<JKRHeap>& tree = getHeapTree();
|
||||
for (JSUTreeIterator iter(tree.getFirstChild()); iter != tree.getEndChild(); ++iter) {
|
||||
OSReport_Error("%08X | %08X | %s\n", iter->getStartAddr(), iter->getEndAddr(), iter->getName());
|
||||
}
|
||||
|
||||
CRASH("Aborting due to allocation failure!");
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include <mtx.h>
|
||||
#include <gx.h>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#endif
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
void JPASetPointSize(JPAEmitterWorkData* work) {
|
||||
@@ -418,50 +421,95 @@ static projectionFunc p_prj[3] = {
|
||||
loadPrjAnm,
|
||||
};
|
||||
|
||||
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
#if TARGET_PC
|
||||
void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
Mtx ptclPosMtx;
|
||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
||||
dusk::frame_interp::record_final_mtx(ptclPosMtx, ptcl);
|
||||
}
|
||||
|
||||
void JPAInterpRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
Mtx ptclPosMtx;
|
||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
||||
ptclPosMtx[0][0] = cosRot;
|
||||
ptclPosMtx[0][1] = -sinRot;
|
||||
ptclPosMtx[1][0] = sinRot;
|
||||
ptclPosMtx[1][1] = cosRot;
|
||||
dusk::frame_interp::record_final_mtx(ptclPosMtx, ptcl);
|
||||
}
|
||||
#endif
|
||||
|
||||
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JGeometry::TVec3<f32> local_48;
|
||||
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
|
||||
Mtx local_38;
|
||||
local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||
local_38[0][3] = local_48.x;
|
||||
local_38[1][1] = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||
local_38[1][3] = local_48.y;
|
||||
local_38[2][2] = 1.0f;
|
||||
local_38[2][3] = local_48.z;
|
||||
local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
|
||||
GXLoadPosMtxImm(local_38, 0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
JGeometry::TVec3<f32> pos;
|
||||
#if TARGET_PC
|
||||
Mtx ptclPosMtx;
|
||||
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
||||
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
||||
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
|
||||
}
|
||||
Mtx posMtx;
|
||||
posMtx[0][0] = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
posMtx[0][3] = pos.x;
|
||||
posMtx[1][1] = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
posMtx[1][3] = pos.y;
|
||||
posMtx[2][2] = 1.0f;
|
||||
posMtx[2][3] = pos.z;
|
||||
posMtx[0][1] = posMtx[0][2] = posMtx[1][0] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
}
|
||||
|
||||
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JGeometry::TVec3<f32> local_48;
|
||||
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
|
||||
f32 sinRot = JMASSin(param_1->mRotateAngle);
|
||||
f32 cosRot = JMASCos(param_1->mRotateAngle);
|
||||
f32 particleX = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||
f32 particleY = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||
if (work->mpRes->getUsrIdx() == 0x89d7) {
|
||||
int a = 0;
|
||||
}
|
||||
|
||||
Mtx local_38;
|
||||
local_38[0][0] = cosRot * particleX;
|
||||
local_38[0][1] = -sinRot * particleY;
|
||||
local_38[0][3] = local_48.x;
|
||||
local_38[1][0] = sinRot * particleX;
|
||||
local_38[1][1] = cosRot * particleY;
|
||||
local_38[1][3] = local_48.y;
|
||||
local_38[2][2] = 1.0f;
|
||||
local_38[2][3] = local_48.z;
|
||||
local_38[0][2] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
|
||||
GXLoadPosMtxImm(local_38, 0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
JGeometry::TVec3<f32> pos;
|
||||
f32 sinRot, cosRot;
|
||||
#if TARGET_PC
|
||||
Mtx ptclPosMtx;
|
||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
||||
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
||||
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
||||
sinRot = ptclPosMtx[1][0];
|
||||
cosRot = ptclPosMtx[0][0];
|
||||
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
|
||||
sinRot = JMASSin(ptcl->mRotateAngle);
|
||||
cosRot = JMASCos(ptcl->mRotateAngle);
|
||||
}
|
||||
f32 particleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
f32 particleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
Mtx posMtx;
|
||||
posMtx[0][0] = cosRot * particleX;
|
||||
posMtx[0][1] = -sinRot * particleY;
|
||||
posMtx[0][3] = pos.x;
|
||||
posMtx[1][0] = sinRot * particleX;
|
||||
posMtx[1][1] = cosRot * particleY;
|
||||
posMtx[1][3] = pos.y;
|
||||
posMtx[2][2] = 1.0f;
|
||||
posMtx[2][3] = pos.z;
|
||||
posMtx[0][2] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
}
|
||||
|
||||
@@ -484,7 +532,7 @@ void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
local_38[2][2] = work->mYBBCamMtx[2][2];
|
||||
local_38[2][3] = local_48.z;
|
||||
local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[2][0] = 0.0f;
|
||||
GXLoadPosMtxImm(local_38, 0);
|
||||
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
}
|
||||
@@ -517,7 +565,7 @@ void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
local_38[2][1] = local_94 * fVar1;
|
||||
local_38[2][2] = local_90;
|
||||
local_38[2][3] = local_48.z;
|
||||
GXLoadPosMtxImm(local_38, 0);
|
||||
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
}
|
||||
@@ -681,103 +729,197 @@ static u8* p_dl[2] = {
|
||||
jpa_dl_x,
|
||||
};
|
||||
|
||||
void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
#if TARGET_PC
|
||||
void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||
|
||||
if (axisY.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZoneScoped;
|
||||
axisY.normalize();
|
||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
||||
|
||||
JGeometry::TVec3<f32> local_6c;
|
||||
JGeometry::TVec3<f32> local_78;
|
||||
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
||||
|
||||
if (local_6c.isZero()) {
|
||||
if (axisZ.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
local_6c.normalize();
|
||||
local_78.cross(param_1->mBaseAxis, local_6c);
|
||||
|
||||
if (local_78.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
local_78.normalize();
|
||||
param_1->mBaseAxis.cross(local_6c, local_78);
|
||||
param_1->mBaseAxis.normalize();
|
||||
Mtx local_60;
|
||||
f32 fVar1 = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||
f32 fVar2 = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||
local_60[0][0] = param_1->mBaseAxis.x;
|
||||
local_60[0][1] = local_6c.x;
|
||||
local_60[0][2] = local_78.x;
|
||||
local_60[0][3] = param_1->mPosition.x;
|
||||
local_60[1][0] = param_1->mBaseAxis.y;
|
||||
local_60[1][1] = local_6c.y;
|
||||
local_60[1][2] = local_78.y;
|
||||
local_60[1][3] = param_1->mPosition.y;
|
||||
local_60[2][0] = param_1->mBaseAxis.z;
|
||||
local_60[2][1] = local_6c.z;
|
||||
local_60[2][2] = local_78.z;
|
||||
local_60[2][3] = param_1->mPosition.z;
|
||||
p_plane[param_0->mPlaneType](local_60, fVar1, fVar2);
|
||||
MTXConcat(param_0->mPosCamMtx, local_60, local_60);
|
||||
GXLoadPosMtxImm(local_60, 0);
|
||||
p_prj[param_0->mPrjType](param_0, local_60);
|
||||
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
|
||||
axisZ.normalize();
|
||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
||||
ptcl->mBaseAxis.normalize();
|
||||
Mtx posMtx;
|
||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
posMtx[0][0] = ptcl->mBaseAxis.x;
|
||||
posMtx[0][1] = axisY.x;
|
||||
posMtx[0][2] = axisZ.x;
|
||||
posMtx[0][3] = ptcl->mPosition.x;
|
||||
posMtx[1][0] = ptcl->mBaseAxis.y;
|
||||
posMtx[1][1] = axisY.y;
|
||||
posMtx[1][2] = axisZ.y;
|
||||
posMtx[1][3] = ptcl->mPosition.y;
|
||||
posMtx[2][0] = ptcl->mBaseAxis.z;
|
||||
posMtx[2][1] = axisY.z;
|
||||
posMtx[2][2] = axisZ.z;
|
||||
posMtx[2][3] = ptcl->mPosition.z;
|
||||
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
|
||||
dusk::frame_interp::record_final_mtx(posMtx, ptcl);
|
||||
}
|
||||
|
||||
void JPADrawRotDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||
|
||||
if (axisY.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
axisY.normalize();
|
||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
||||
|
||||
if (axisZ.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
axisZ.normalize();
|
||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
||||
ptcl->mBaseAxis.normalize();
|
||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
Mtx mtx1;
|
||||
Mtx mtx2;
|
||||
p_rot[work->mRotType](sinRot, cosRot, mtx1);
|
||||
p_plane[work->mPlaneType](mtx1, scaleX, scaleY);
|
||||
mtx2[0][0] = ptcl->mBaseAxis.x;
|
||||
mtx2[0][1] = axisY.x;
|
||||
mtx2[0][2] = axisZ.x;
|
||||
mtx2[0][3] = ptcl->mPosition.x;
|
||||
mtx2[1][0] = ptcl->mBaseAxis.y;
|
||||
mtx2[1][1] = axisY.y;
|
||||
mtx2[1][2] = axisZ.y;
|
||||
mtx2[1][3] = ptcl->mPosition.y;
|
||||
mtx2[2][0] = ptcl->mBaseAxis.z;
|
||||
mtx2[2][1] = axisY.z;
|
||||
mtx2[2][2] = axisZ.z;
|
||||
mtx2[2][3] = ptcl->mPosition.z;
|
||||
MTXConcat(mtx2, mtx1, mtx1);
|
||||
dusk::frame_interp::record_final_mtx(mtx1, ptcl);
|
||||
}
|
||||
#endif
|
||||
|
||||
void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZoneScoped;
|
||||
|
||||
f32 sinRot = JMASSin(param_1->mRotateAngle);
|
||||
f32 cosRot = JMASCos(param_1->mRotateAngle);
|
||||
JGeometry::TVec3<f32> local_6c;
|
||||
JGeometry::TVec3<f32> local_78;
|
||||
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
||||
Mtx posMtx;
|
||||
#if TARGET_PC
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx))
|
||||
#endif
|
||||
{
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||
|
||||
if (local_6c.isZero()) {
|
||||
if (axisY.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
axisY.normalize();
|
||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
||||
|
||||
if (axisZ.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
axisZ.normalize();
|
||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
||||
ptcl->mBaseAxis.normalize();
|
||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
posMtx[0][0] = ptcl->mBaseAxis.x;
|
||||
posMtx[0][1] = axisY.x;
|
||||
posMtx[0][2] = axisZ.x;
|
||||
posMtx[0][3] = ptcl->mPosition.x;
|
||||
posMtx[1][0] = ptcl->mBaseAxis.y;
|
||||
posMtx[1][1] = axisY.y;
|
||||
posMtx[1][2] = axisZ.y;
|
||||
posMtx[1][3] = ptcl->mPosition.y;
|
||||
posMtx[2][0] = ptcl->mBaseAxis.z;
|
||||
posMtx[2][1] = axisY.z;
|
||||
posMtx[2][2] = axisZ.z;
|
||||
posMtx[2][3] = ptcl->mPosition.z;
|
||||
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
|
||||
}
|
||||
|
||||
MTXConcat(work->mPosCamMtx, posMtx, posMtx);
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
}
|
||||
|
||||
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
local_6c.normalize();
|
||||
local_78.cross(param_1->mBaseAxis, local_6c);
|
||||
ZoneScoped;
|
||||
|
||||
if (local_78.isZero()) {
|
||||
return;
|
||||
Mtx mtx1;
|
||||
Mtx mtx2;
|
||||
#if TARGET_PC
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1))
|
||||
#endif
|
||||
{
|
||||
f32 sinRot = JMASSin(ptcl->mRotateAngle);
|
||||
f32 cosRot = JMASCos(ptcl->mRotateAngle);
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||
|
||||
if (axisY.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
axisY.normalize();
|
||||
axisZ.cross(ptcl->mBaseAxis, axisY);
|
||||
|
||||
if (axisZ.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
axisZ.normalize();
|
||||
ptcl->mBaseAxis.cross(axisY, axisZ);
|
||||
ptcl->mBaseAxis.normalize();
|
||||
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
|
||||
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
|
||||
p_rot[work->mRotType](sinRot, cosRot, mtx1);
|
||||
p_plane[work->mPlaneType](mtx1, scaleX, scaleY);
|
||||
mtx2[0][0] = ptcl->mBaseAxis.x;
|
||||
mtx2[0][1] = axisY.x;
|
||||
mtx2[0][2] = axisZ.x;
|
||||
mtx2[0][3] = ptcl->mPosition.x;
|
||||
mtx2[1][0] = ptcl->mBaseAxis.y;
|
||||
mtx2[1][1] = axisY.y;
|
||||
mtx2[1][2] = axisZ.y;
|
||||
mtx2[1][3] = ptcl->mPosition.y;
|
||||
mtx2[2][0] = ptcl->mBaseAxis.z;
|
||||
mtx2[2][1] = axisY.z;
|
||||
mtx2[2][2] = axisZ.z;
|
||||
mtx2[2][3] = ptcl->mPosition.z;
|
||||
MTXConcat(mtx2, mtx1, mtx1);
|
||||
}
|
||||
|
||||
local_78.normalize();
|
||||
param_1->mBaseAxis.cross(local_6c, local_78);
|
||||
param_1->mBaseAxis.normalize();
|
||||
f32 particleX = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||
f32 particleY = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||
Mtx auStack_80;
|
||||
Mtx local_60;
|
||||
p_rot[param_0->mRotType](sinRot, cosRot, auStack_80);
|
||||
p_plane[param_0->mPlaneType](auStack_80, particleX, particleY);
|
||||
local_60[0][0] = param_1->mBaseAxis.x;
|
||||
local_60[0][1] = local_6c.x;
|
||||
local_60[0][2] = local_78.x;
|
||||
local_60[0][3] = param_1->mPosition.x;
|
||||
local_60[1][0] = param_1->mBaseAxis.y;
|
||||
local_60[1][1] = local_6c.y;
|
||||
local_60[1][2] = local_78.y;
|
||||
local_60[1][3] = param_1->mPosition.y;
|
||||
local_60[2][0] = param_1->mBaseAxis.z;
|
||||
local_60[2][1] = local_6c.z;
|
||||
local_60[2][2] = local_78.z;
|
||||
local_60[2][3] = param_1->mPosition.z;
|
||||
MTXConcat(local_60, auStack_80, auStack_80);
|
||||
MTXConcat(param_0->mPosCamMtx, auStack_80, local_60);
|
||||
GXLoadPosMtxImm(local_60, 0);
|
||||
p_prj[param_0->mPrjType](param_0, local_60);
|
||||
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
|
||||
MTXConcat(work->mPosCamMtx, mtx1, mtx2);
|
||||
GXLoadPosMtxImm(mtx2, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, mtx2);
|
||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
}
|
||||
|
||||
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
|
||||
@@ -204,6 +204,28 @@ void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent)
|
||||
mTexAnmIdx = 0;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
void JPABaseParticle::interp(JPAEmitterWorkData* work, void const* drawFunc) {
|
||||
static bool enable = false;
|
||||
if (!enable)
|
||||
return;
|
||||
|
||||
// don't interpolate the first frame
|
||||
if (mAge == 0)
|
||||
return;
|
||||
|
||||
if (drawFunc == JPADrawBillboard) {
|
||||
JPAInterpBillboard(work, this);
|
||||
} else if (drawFunc == JPADrawRotBillboard) {
|
||||
JPAInterpRotBillboard(work, this);
|
||||
} else if (drawFunc == JPADrawDirection) {
|
||||
JPAInterpDirection(work, this);
|
||||
} else if (drawFunc == JPADrawRotDirection) {
|
||||
JPAInterpRotDirection(work, this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
|
||||
if (++mAge >= mLifeTime) {
|
||||
return true;
|
||||
@@ -247,6 +269,17 @@ bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
|
||||
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
||||
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
|
||||
|
||||
#if TARGET_PC
|
||||
JPABaseShape* pBsp = work->mpRes->getBsp();
|
||||
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pBsp->getBaseSizeX();
|
||||
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pBsp->getBaseSizeY();
|
||||
work->mDirType = pBsp->getDirType();
|
||||
work->mRotType = pBsp->getRotType();
|
||||
work->mDLType = pBsp->getType() == 4 || pBsp->getType() == 8;
|
||||
work->mPlaneType = work->mDLType ? 2 : pBsp->getBasePlaneType();
|
||||
interp(work, (void const*)work->mpRes->mpDrawParticleFuncList[0]);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -289,6 +322,23 @@ bool JPABaseParticle::calc_c(JPAEmitterWorkData* work) {
|
||||
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
||||
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
|
||||
|
||||
#if TARGET_PC
|
||||
JPABaseShape* pBsp = work->mpRes->getBsp();
|
||||
JPAChildShape* pCsp = work->mpRes->getCsp();
|
||||
if (pCsp->isScaleInherited()) {
|
||||
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pBsp->getBaseSizeX();
|
||||
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pBsp->getBaseSizeY();
|
||||
} else {
|
||||
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pCsp->getScaleX();
|
||||
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pCsp->getScaleY();
|
||||
}
|
||||
work->mDirType = pCsp->getDirType();
|
||||
work->mRotType = pCsp->getRotType();
|
||||
work->mDLType = pCsp->getType() == 4 || pCsp->getType() == 8;
|
||||
work->mPlaneType = work->mDLType ? 2 : pCsp->getBasePlaneType();
|
||||
interp(work, (void const*)work->mpRes->mpDrawParticleChildFuncList[0]);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,3 +38,9 @@ bool JUTPalette::load() {
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
void JUTPalette::dataUploaded() {
|
||||
GXInitTlutObjData(&mTlutObj, (void*)mColorTable);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -27,7 +27,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, u8 param_1) {
|
||||
mTexData = (void*)((intptr_t)mTexInfo + 0x20);
|
||||
}
|
||||
|
||||
field_0x2c = NULL;
|
||||
mPalette = NULL;
|
||||
mTlutName = 0;
|
||||
mWrapS = mTexInfo->wrapS;
|
||||
mWrapT = mTexInfo->wrapT;
|
||||
@@ -95,7 +95,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
|
||||
}
|
||||
mEmbPalette = param_1;
|
||||
setEmbPaletteDelFlag(false);
|
||||
field_0x2c = NULL;
|
||||
mPalette = NULL;
|
||||
if (param_1 != NULL) {
|
||||
mTlutName = param_2;
|
||||
if (param_2 != param_1->getTlutName()) {
|
||||
@@ -120,11 +120,11 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
|
||||
void JUTTexture::attachPalette(JUTPalette* param_0) {
|
||||
if (mTexInfo->indexTexture) {
|
||||
if (param_0 == NULL && mEmbPalette != NULL) {
|
||||
field_0x2c = mEmbPalette;
|
||||
mPalette = mEmbPalette;
|
||||
} else {
|
||||
field_0x2c = param_0;
|
||||
mPalette = param_0;
|
||||
}
|
||||
initTexObj(field_0x2c->getTlutName());
|
||||
initTexObj(mPalette->getTlutName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,9 +133,9 @@ void JUTTexture::init() {
|
||||
initTexObj();
|
||||
} else {
|
||||
if (mEmbPalette != NULL) {
|
||||
field_0x2c = mEmbPalette;
|
||||
mPalette = mEmbPalette;
|
||||
|
||||
initTexObj(field_0x2c->getTlutName());
|
||||
initTexObj(mPalette->getTlutName());
|
||||
} else {
|
||||
OS_REPORT("This texture is CI-Format, but EmbPalette is NULL.\n");
|
||||
}
|
||||
@@ -179,8 +179,8 @@ void JUTTexture::initTexObj(GXTlut param_0) {
|
||||
}
|
||||
|
||||
void JUTTexture::load(GXTexMapID param_0) {
|
||||
if (field_0x2c) {
|
||||
field_0x2c->load();
|
||||
if (mPalette) {
|
||||
mPalette->load();
|
||||
}
|
||||
GXLoadTexObj(&mTexObj, param_0);
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 457 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 188 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,147 @@
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: visible;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-size: 24dp;
|
||||
color: #FFFFFF;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.overlay-root {
|
||||
width: 100%;
|
||||
min-height: 45%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: stretch;
|
||||
decorator: vertical-gradient(#00000000 #151610F2);
|
||||
padding: 48dp 0 40dp 0;
|
||||
filter: opacity(0);
|
||||
transition: filter 0.2s linear-in-out;
|
||||
}
|
||||
|
||||
.overlay-root[open] {
|
||||
filter: opacity(1);
|
||||
}
|
||||
|
||||
.overlay {
|
||||
width: 100%;
|
||||
max-width: 1216dp;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24dp;
|
||||
padding: 0 32dp;
|
||||
}
|
||||
|
||||
@media (max-height: 800dp) {
|
||||
.overlay-root {
|
||||
min-height: 38%;
|
||||
padding: 32dp 0 28dp 0;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
gap: 16dp;
|
||||
padding: 0 24dp;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 24dp;
|
||||
}
|
||||
|
||||
.carousel-container {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 18dp;
|
||||
line-height: 22dp;
|
||||
color: rgba(255, 255, 255, 50%);
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 1dp 0;
|
||||
border-top: 1dp rgba(217, 217, 217, 50%);
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 24dp;
|
||||
}
|
||||
|
||||
footer-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 220dp;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-weight: bold;
|
||||
font-size: 20dp;
|
||||
line-height: 24dp;
|
||||
text-transform: uppercase;
|
||||
color: #FFFFFF;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
footer-button.return {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
footer-button.reset {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.stepped-carousel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16dp;
|
||||
width: auto;
|
||||
min-width: 246dp;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stepped-carousel-value {
|
||||
line-height: 29dp;
|
||||
min-width: 166dp;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.stepped-carousel-arrow {
|
||||
width: 24dp;
|
||||
height: 24dp;
|
||||
min-width: 24dp;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: visible;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-weight: bold;
|
||||
font-size: 18dp;
|
||||
color: #E0DBC8;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
popup {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
height: 64dp;
|
||||
background-color: rgba(21, 22, 16, 80%);
|
||||
border-bottom: 2dp #92875B;
|
||||
backdrop-filter: blur(5dp);
|
||||
transform: translateY(-64dp);
|
||||
transition: transform 0.2s cubic-in-out;
|
||||
}
|
||||
|
||||
popup[open] {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
popup tab-bar {
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
popup tab-bar tab {
|
||||
opacity: 0.35;
|
||||
color: #E0DBC8;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: "Fira Sans";
|
||||
font-weight: normal;
|
||||
font-size: 20dp;
|
||||
color: #FFFFFF;
|
||||
background-color: #000000;
|
||||
decorator: image(../prelaunch-bg.png cover left center);
|
||||
filter: opacity(0);
|
||||
transition: filter 1s 0.1s linear-in-out;
|
||||
}
|
||||
|
||||
body[open] {
|
||||
filter: opacity(1);
|
||||
}
|
||||
|
||||
content {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
filter: opacity(0);
|
||||
transition: filter 0.2s linear-in-out;
|
||||
}
|
||||
|
||||
content[open] {
|
||||
filter: opacity(1);
|
||||
}
|
||||
|
||||
menu {
|
||||
position: absolute;
|
||||
left: 96dp;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
/* Scale based on a reference screen width, 428/1216 */
|
||||
width: 35.230264vw;
|
||||
min-width: 428dp;
|
||||
max-width: 856dp;
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 48dp;
|
||||
}
|
||||
|
||||
hero {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 8dp;
|
||||
}
|
||||
|
||||
hero img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
font-family: "Alegreya SC";
|
||||
font-size: 32dp;
|
||||
}
|
||||
|
||||
@media (min-width: 1216dp) {
|
||||
.eyebrow {
|
||||
/* Same logic as .menu, 32/1216 */
|
||||
font-size: 2.631579vw;
|
||||
}
|
||||
}
|
||||
|
||||
.eyebrow span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#menu-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12dp;
|
||||
}
|
||||
|
||||
#menu-list button {
|
||||
width: 428dp;
|
||||
height: 54dp;
|
||||
padding: 8dp 16dp;
|
||||
border-radius: 8dp;
|
||||
text-transform: uppercase;
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-size: 32dp;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
/* Define a fully transparent gradient as the default state, otherwise a white flash occurs */
|
||||
decorator: horizontal-gradient(#00000000 #00000000);
|
||||
}
|
||||
|
||||
#menu-list button.anim-done {
|
||||
transition: decorator color 0.1s linear-in-out;
|
||||
}
|
||||
|
||||
#menu-list button:hover,
|
||||
#menu-list button:focus-visible {
|
||||
color: black;
|
||||
decorator: horizontal-gradient(#FEE685FF #FEE68500);
|
||||
}
|
||||
|
||||
disk-status {
|
||||
position: absolute;
|
||||
left: 96dp;
|
||||
bottom: 72dp;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8dp;
|
||||
}
|
||||
|
||||
version-info {
|
||||
position: absolute;
|
||||
right: 96dp;
|
||||
bottom: 72dp;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8dp;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.status,
|
||||
.version {
|
||||
font-size: 24dp;
|
||||
}
|
||||
|
||||
.status,
|
||||
.update {
|
||||
color: #D8F999;
|
||||
}
|
||||
|
||||
.status[bad] {
|
||||
color: #FFC9C9;
|
||||
}
|
||||
|
||||
/* TODO: Hidden until an actual update checker is introduced */
|
||||
.update {
|
||||
display: none;
|
||||
font-size: 16dp;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.detail,
|
||||
.update span {
|
||||
color: #A6A09B;
|
||||
}
|
||||
|
||||
/* Startup animation */
|
||||
.intro-item {
|
||||
opacity: 0;
|
||||
transform: translateY(10dp);
|
||||
transition: opacity transform 0.3s 0.1s cubic-in-out;
|
||||
}
|
||||
|
||||
body.animate-in .intro-item {
|
||||
opacity: 1;
|
||||
transform: translateY(0dp);
|
||||
}
|
||||
|
||||
.delay-0 {
|
||||
transition: opacity transform 0.3s 0.1s cubic-in-out;
|
||||
}
|
||||
|
||||
.delay-1 {
|
||||
transition: opacity transform 0.3s 0.2s cubic-in-out;
|
||||
}
|
||||
|
||||
.delay-2 {
|
||||
transition: opacity transform 0.3s 0.3s cubic-in-out;
|
||||
}
|
||||
|
||||
.delay-3 {
|
||||
transition: opacity transform 0.3s 0.4s cubic-in-out;
|
||||
}
|
||||
|
||||
.delay-4 {
|
||||
transition: opacity transform 0.3s 0.5s cubic-in-out;
|
||||
}
|
||||
|
||||
.delay-5 {
|
||||
transition: opacity transform 0.3s 0.6s cubic-in-out;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
tab-bar {
|
||||
display: flex;
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
overflow: auto hidden;
|
||||
clip: always;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
tab-bar scrollbarhorizontal,
|
||||
tab-bar scrollbarhorizontal sliderarrowdec,
|
||||
tab-bar scrollbarhorizontal sliderarrowinc,
|
||||
tab-bar scrollbarhorizontal slidertrack,
|
||||
tab-bar scrollbarhorizontal sliderbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
tab-bar tab {
|
||||
flex: 0 0 auto;
|
||||
padding: 0 24dp;
|
||||
line-height: 64dp;
|
||||
white-space: nowrap;
|
||||
decorator: vertical-gradient(#c2a42d00 #c2a42d00);
|
||||
transition: decorator 0.1s linear-in-out, opacity 0.1s linear-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
tab-bar tab:selected {
|
||||
opacity: 1;
|
||||
border-bottom: 4dp #C2A42D;
|
||||
font-effect: glow(0dp 4dp 0dp 4dp black);
|
||||
}
|
||||
|
||||
tab-bar tab:focus-visible,
|
||||
tab-bar tab:hover {
|
||||
opacity: 1;
|
||||
font-effect: glow(0dp 4dp 0dp 4dp black);
|
||||
decorator: vertical-gradient(#c2a42d00 #c2a42d26);
|
||||
}
|
||||
|
||||
tab-bar tab:active {
|
||||
decorator: vertical-gradient(#c2a42d10 #c2a42d40);
|
||||
}
|
||||
|
||||
tab-bar[closable] tab-end-spacer {
|
||||
display: block;
|
||||
flex: 0 0 64dp;
|
||||
width: 64dp;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
tab-bar[closable] close {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 8dp;
|
||||
right: 8dp;
|
||||
z-index: 1;
|
||||
width: 48dp;
|
||||
height: 48dp;
|
||||
font-family: "Material Symbols Rounded";
|
||||
font-weight: normal;
|
||||
font-size: 24dp;
|
||||
line-height: 48dp;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
color: rgba(224, 219, 200, 70%);
|
||||
backdrop-filter: blur(2dp);
|
||||
border-radius: 6dp;
|
||||
transition: color background-color 0.12s linear-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
tab-bar[closable] close:hover,
|
||||
tab-bar[closable] close:focus-visible {
|
||||
color: #fff;
|
||||
background-color: rgba(194, 164, 45, 24%);
|
||||
}
|
||||
|
||||
tab-bar[closable] close:active {
|
||||
color: #fff;
|
||||
background-color: rgba(194, 164, 45, 40%);
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 64dp;
|
||||
font-family: "Fira Sans";
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 15dp;
|
||||
color: #E0DBC8;
|
||||
}
|
||||
|
||||
window {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
height: 100%;
|
||||
max-width: 1088dp;
|
||||
max-height: 768dp;
|
||||
margin: auto;
|
||||
border-radius: 14dp;
|
||||
overflow: hidden;
|
||||
border: 2dp #92875B;
|
||||
backdrop-filter: blur(5dp);
|
||||
box-shadow: 0 0 25dp 5dp;
|
||||
background-color: rgba(21, 22, 16, 90%);
|
||||
filter: opacity(0);
|
||||
transform: scale(0.9);
|
||||
transform-origin: center;
|
||||
transition: filter transform 0.2s cubic-in-out;
|
||||
}
|
||||
|
||||
window[open] {
|
||||
filter: opacity(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
@media (max-height: 640dp) {
|
||||
body {
|
||||
padding: 16dp;
|
||||
}
|
||||
window {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
window tab-bar {
|
||||
flex: 0 0 64dp;
|
||||
height: 64dp;
|
||||
background-color: rgba(217, 217, 217, 10%);
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-weight: bold;
|
||||
font-size: 18dp;
|
||||
border-bottom: 2dp #92875B;
|
||||
}
|
||||
|
||||
window tab-bar tab {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
window content {
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
window content pane {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
flex: 1 1 0;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 24dp;
|
||||
padding-bottom: 0dp;
|
||||
gap: 8dp;
|
||||
overflow: hidden auto;
|
||||
font-size: 20dp;
|
||||
}
|
||||
|
||||
window content pane:not(:last-of-type) {
|
||||
border-right: 1dp #92875B;
|
||||
}
|
||||
|
||||
window content pane > * {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
window content pane > spacer {
|
||||
display: block;
|
||||
/* Completes the 24dp bottom inset after the pane's 8dp gap. */
|
||||
flex: 0 0 16dp;
|
||||
height: 16dp;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
scrollbarvertical {
|
||||
width: 8dp;
|
||||
margin: 4dp 4dp 4dp 0;
|
||||
}
|
||||
|
||||
scrollbarvertical sliderarrowdec,
|
||||
scrollbarvertical sliderarrowinc {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
scrollbarvertical slidertrack {
|
||||
width: 8dp;
|
||||
}
|
||||
|
||||
scrollbarvertical sliderbar {
|
||||
width: 8dp;
|
||||
min-height: 24dp;
|
||||
background-color: rgba(224, 219, 200, 45%);
|
||||
border-radius: 2dp;
|
||||
transition: background-color 0.2s cubic-in-out;
|
||||
}
|
||||
|
||||
scrollbarvertical sliderbar:hover,
|
||||
scrollbarvertical sliderbar:active {
|
||||
background-color: rgba(194, 164, 45, 80%);
|
||||
}
|
||||
|
||||
scrollbarhorizontal {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
scrollbarhorizontal sliderarrowdec,
|
||||
scrollbarhorizontal sliderarrowinc {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
scrollbarhorizontal slidertrack,
|
||||
scrollbarhorizontal sliderbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.section-heading {
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
font-size: 22dp;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.section-heading:not(:first-of-type) {
|
||||
padding-top: 12dp;
|
||||
}
|
||||
|
||||
button {
|
||||
text-align: center;
|
||||
background-color: rgba(17, 16, 10, 20%);
|
||||
opacity: 0.9;
|
||||
padding: 8dp 16dp;
|
||||
border-radius: 14dp;
|
||||
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
|
||||
font-size: 20dp;
|
||||
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
|
||||
cursor: pointer;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
button:not(:disabled):hover,
|
||||
button:not(:disabled):focus-visible {
|
||||
background-color: rgba(204, 184, 119, 20%);
|
||||
box-shadow: #C2A42D 0 0 0 2dp;
|
||||
}
|
||||
|
||||
button:not(:disabled):selected {
|
||||
opacity: 1;
|
||||
background-color: rgba(204, 184, 119, 40%);
|
||||
}
|
||||
|
||||
button:not(:disabled):active {
|
||||
opacity: 1;
|
||||
background-color: rgba(204, 184, 119, 40%);
|
||||
box-shadow: #C2A42D 0 0 0 2dp;
|
||||
}
|
||||
|
||||
select-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8dp;
|
||||
background-color: rgba(17, 16, 10, 20%);
|
||||
opacity: 0.9;
|
||||
padding: 8dp 16dp;
|
||||
border-radius: 14dp;
|
||||
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
|
||||
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
|
||||
cursor: pointer;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
select-button:not(:disabled):hover,
|
||||
select-button:not(:disabled):focus-visible {
|
||||
background-color: rgba(204, 184, 119, 20%);
|
||||
box-shadow: #C2A42D 0 0 0 2dp;
|
||||
}
|
||||
|
||||
select-button:not(:disabled):selected {
|
||||
opacity: 1;
|
||||
background-color: rgba(204, 184, 119, 40%);
|
||||
}
|
||||
|
||||
select-button:not(:disabled):active {
|
||||
opacity: 1;
|
||||
background-color: rgba(204, 184, 119, 40%);
|
||||
box-shadow: #C2A42D 0 0 0 2dp;
|
||||
}
|
||||
|
||||
select-button:disabled {
|
||||
opacity: 0.35;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
select-button key {
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-weight: bold;
|
||||
font-size: 18dp;
|
||||
text-transform: uppercase;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
select-button value {
|
||||
margin-left: auto;
|
||||
font-size: 20dp;
|
||||
}
|
||||
|
||||
select-button value.modified {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
select-button input {
|
||||
text-align: right;
|
||||
font-size: 20dp;
|
||||
}
|
||||
@@ -468,9 +468,20 @@ s16 cLib_targetAngleX(cXyz const* lhs, cXyz const* rhs) {
|
||||
void cLib_offsetPos(cXyz* pdest, cXyz const* psrc, s16 angle, cXyz const* vec) {
|
||||
f32 cos = cM_scos(angle);
|
||||
f32 sin = cM_ssin(angle);
|
||||
// MWCC loads vec members into registers before writing to pdest; other compilers may not,
|
||||
// which corrupts results when pdest and vec alias the same memory.
|
||||
#if !__MWERKS__
|
||||
f32 vx = vec->x;
|
||||
f32 vy = vec->y;
|
||||
f32 vz = vec->z;
|
||||
pdest->x = psrc->x + (vx * cos + vz * sin);
|
||||
pdest->y = psrc->y + vy;
|
||||
pdest->z = psrc->z + (vz * cos - vx * sin);
|
||||
#else
|
||||
pdest->x = psrc->x + (vec->x * cos + vec->z * sin);
|
||||
pdest->y = psrc->y + vec->y;
|
||||
pdest->z = psrc->z + (vec->z * cos - vec->x * sin);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "Z2AudioLib/Z2Audience.h"
|
||||
#include "Z2AudioLib/Z2SoundInfo.h"
|
||||
#if TARGET_PC
|
||||
#include "dusk/audio/DuskDsp.hpp"
|
||||
#include <cmath>
|
||||
#endif
|
||||
#include "Z2AudioLib/Z2Calc.h"
|
||||
#include "Z2AudioLib/Z2Param.h"
|
||||
#include "JSystem/JAudio2/JAISound.h"
|
||||
@@ -734,9 +738,22 @@ f32 Z2Audience::calcRelPosPan(const Vec& param_0, int camID) {
|
||||
|
||||
f32 Z2Audience::calcRelPosDolby(const Vec& param_0, int camID) {
|
||||
f32 fVar1 = param_0.z + mAudioCamera[camID].getDolbyCenterZ();
|
||||
#if TARGET_PC
|
||||
if (dusk::audio::EnableHrtf) {
|
||||
// Normalize the direction so result is purely front/back orientation,
|
||||
// independent of how far away the sound is
|
||||
f32 lenSq = param_0.x * param_0.x + param_0.y * param_0.y + param_0.z * param_0.z;
|
||||
if (lenSq < 0.0001f) {
|
||||
return 0.5f;
|
||||
}
|
||||
f32 zNorm = param_0.z / sqrtf(lenSq);
|
||||
f32 t = (zNorm + 1.0f) * 0.5f;
|
||||
return 0.5f - 0.5f * cosf(t * static_cast<f32>(M_PI));
|
||||
}
|
||||
#endif
|
||||
if (fVar1 > mSetting.field_0x48) {
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (fVar1 < mSetting.field_0x44) {
|
||||
return 0.0f;
|
||||
|
||||
@@ -4962,13 +4962,16 @@ int daAlink_c::create() {
|
||||
|
||||
setArcName(checkWolf());
|
||||
setOriginalHeap(&mpArcHeap, 0xA2800);
|
||||
JKRHEAP_NAME(mpArcHeap, "Alink ArcHeap");
|
||||
if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) {
|
||||
return cPhs_INIT_e;
|
||||
}
|
||||
|
||||
setShieldArcName();
|
||||
setOriginalHeap(&mpShieldArcHeap, 0x7000);
|
||||
if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e) {
|
||||
JKRHEAP_NAME(mpShieldArcHeap, "Alink ShieldArcHeap");
|
||||
if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e)
|
||||
{
|
||||
return cPhs_INIT_e;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include "d/actor/d_a_crod.h"
|
||||
#include "d/d_msg_object.h"
|
||||
#ifdef TARGET_PC
|
||||
#include "d/actor/d_a_obj_carry.h"
|
||||
#include "dusk/achievements.h"
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include "d/d_s_menu.h"
|
||||
@@ -677,6 +681,15 @@ BOOL daAlink_c::checkDamageAction() {
|
||||
}
|
||||
|
||||
setDamagePoint(dmg, at_mtrl == dCcD_MTRL_FIRE || at_mtrl == dCcD_MTRL_ICE, TRUE, 0);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
if (tghit_ac_name == fpcNm_Obj_Carry_e) {
|
||||
auto* carry = static_cast<daObjCarry_c*>(tghit_ac);
|
||||
if (carry->prm_chk_type_ironball() && carry->checkCannon()) {
|
||||
dusk::AchievementSystem::get().signal("iron_ball_hit_player");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (armor_no_dmg && at_mtrl != dCcD_MTRL_ELECTRIC && at_mtrl != dCcD_MTRL_ICE) {
|
||||
setGuardSe(var_r29);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "d/actor/d_a_npc_tkc.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/settings.h"
|
||||
|
||||
BOOL daAlink_c::checkEventRun() const {
|
||||
@@ -4005,6 +4006,15 @@ int daAlink_c::procGanonFinishInit() {
|
||||
|
||||
field_0x37c8 = current.pos;
|
||||
onEndResetFlg1(ERFLG1_SHIELD_BACKBONE);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.speedrunMode) {
|
||||
if (dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::m_speedrunInfo.stopRun();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ enum {
|
||||
};
|
||||
|
||||
void daAlink_c::hsChainShape_c::draw() {
|
||||
if (dusk::getSettings().game.superClawshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const int dummy = 0;
|
||||
|
||||
daAlink_c* alink = (daAlink_c*)getUserArea();
|
||||
|
||||
@@ -46,7 +46,6 @@ void daAlink_c::setOriginalHeap(JKRExpHeap** i_ppheap, u32 i_size) {
|
||||
JKRHeap* parent = mDoExt_getGameHeap();
|
||||
|
||||
JKRExpHeap* heap = JKRExpHeap::create(size + (var_r29 + var_r28), parent, true);
|
||||
JKRHEAP_NAME(heap, "Alink original");
|
||||
*i_ppheap = heap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/actor/d_a_balloon_2D.h"
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "JSystem/J2DGraph/J2DGrafContext.h"
|
||||
#include "JSystem/J2DGraph/J2DScreen.h"
|
||||
#include "JSystem/J2DGraph/J2DTextBox.h"
|
||||
@@ -438,7 +439,12 @@ void daBalloon2D_c::setComboAlpha() {
|
||||
void daBalloon2D_c::drawAddScore() {
|
||||
for (s32 i = 19; i >= 0; i--) {
|
||||
if (field_0x5f8[i].field_0xe != 0) {
|
||||
field_0x5f8[i].field_0xe--;
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::frame_interp::get_ui_tick_pending())
|
||||
#endif
|
||||
{
|
||||
field_0x5f8[i].field_0xe--;
|
||||
}
|
||||
s32 score3;
|
||||
s32 score2;
|
||||
s32 score = field_0x5f8[i].field_0xc;
|
||||
@@ -446,8 +452,13 @@ void daBalloon2D_c::drawAddScore() {
|
||||
u8 local_88 = 0xff;
|
||||
f32 dVar11 = 30.0f;
|
||||
f32 dVar9 = 30.0f;
|
||||
field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f;
|
||||
field_0x5f8[i].field_0x0.y -= 1.0f;
|
||||
#ifdef TARGET_PC
|
||||
if (dusk::frame_interp::get_ui_tick_pending())
|
||||
#endif
|
||||
{
|
||||
field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f;
|
||||
field_0x5f8[i].field_0x0.y -= 1.0f;
|
||||
}
|
||||
if (field_0x5f8[i].field_0xe < 10) {
|
||||
f32 fVar5 = field_0x5f8[i].field_0xe / 10.0f;
|
||||
local_88 = fVar5 * 255.0f;
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include <f_ap/f_ap_game.h>
|
||||
#include <dusk/autosave.h>
|
||||
#endif
|
||||
|
||||
char* daDoor20_c::getStopBmdName() {
|
||||
switch (door_param2_c::getKind(this)) {
|
||||
case 3:
|
||||
@@ -196,6 +201,7 @@ void daDoor20_c::setEventPrm() {
|
||||
} else {
|
||||
roomNo = FRoomNo;
|
||||
}
|
||||
|
||||
if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) {
|
||||
if (door_param2_c::getKind(this) == 9) {
|
||||
if (daPy_py_c::checkNowWolf()) {
|
||||
@@ -564,6 +570,11 @@ int daDoor20_c::openEnd(int param_1) {
|
||||
openEnd_1();
|
||||
break;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
triggerAutoSave();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -282,6 +282,11 @@ static void e_th_spin_B(e_th_class* i_this) {
|
||||
i_this->current.pos += spC;
|
||||
|
||||
f32 speed_target;
|
||||
|
||||
#if AVOID_UB
|
||||
speed_target = 0;
|
||||
#endif
|
||||
|
||||
f32 anm_frame = i_this->mpModelMorf->getFrame();
|
||||
|
||||
switch (i_this->mMode) {
|
||||
|
||||
@@ -463,6 +463,23 @@ int daMidna_c::createHeap() {
|
||||
JKRReadIdxResource(mBckHeap[0].getBuffer(), mBckHeap[0].getBufferSize(), 0x1DC, dComIfGp_getAnmArchive());
|
||||
J3DAnmTransform* md_anm = (J3DAnmTransform*)J3DAnmLoaderDataBase::load(mBckHeap[0].getBuffer());
|
||||
modelData = (J3DModelData*)dComIfG_getObjectRes(l_arcName, 14);
|
||||
|
||||
#if TARGET_PC
|
||||
J3DTexture* tex = modelData->getTexture();
|
||||
JUTNameTab* nametable = modelData->getTextureName();
|
||||
if (tex != NULL && nametable != NULL) {
|
||||
for (u16 i = 0; i < tex->getNum(); i++) {
|
||||
const char* name = nametable->getName(i);
|
||||
if (name != NULL && strcmp(name, "midona_eye") == 0) {
|
||||
ResTIMG* timg = tex->getResTIMG(i);
|
||||
timg->mipmapEnabled = false;
|
||||
tex->loadGXTexObj(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
JUT_ASSERT(852, modelData != NULL);
|
||||
mpMorf = JKR_NEW mDoExt_McaMorfSO(modelData, &mMorfCB, NULL, md_anm, J3DFrameCtrl::EMode_LOOP, 1.0f, 0, -1, NULL, 0, 0x11000284);
|
||||
if (mpMorf == NULL || mpMorf->getModel() == NULL) {
|
||||
|
||||
@@ -40,6 +40,7 @@ dMirror_packet_c::dMirror_packet_c() {
|
||||
void dMirror_packet_c::reset() {
|
||||
#if TARGET_PC
|
||||
mbReset = true;
|
||||
mbHadEntry = false;
|
||||
#else
|
||||
mModelCount = 0;
|
||||
#endif
|
||||
@@ -84,11 +85,21 @@ void dMirror_packet_c::calcMinMax() {
|
||||
}
|
||||
|
||||
int dMirror_packet_c::entryModel(J3DModel* i_model) {
|
||||
#if TARGET_PC
|
||||
if (mbReset) {
|
||||
mModelCount = 0;
|
||||
mbReset = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mModelCount >= 0x40) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mModels[mModelCount++] = i_model;
|
||||
#if TARGET_PC
|
||||
mbHadEntry = true;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -592,13 +603,6 @@ int daMirror_c::execute() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (mPacket.mbReset) {
|
||||
mPacket.mModelCount = 0;
|
||||
mPacket.mbReset = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
daPy_py_c* player = daPy_getLinkPlayerActorClass();
|
||||
JUT_ASSERT(0, player != NULL);
|
||||
|
||||
@@ -624,6 +628,12 @@ int daMirror_c::draw() {
|
||||
mDoExt_modelUpdateDL(mpModel);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (mPacket.mbReset && !mPacket.mbHadEntry) {
|
||||
mPacket.mModelCount = 0;
|
||||
}
|
||||
mPacket.mbHadEntry = true;
|
||||
#endif
|
||||
dComIfGd_getOpaListBG()->entryImm(&mPacket, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -956,7 +956,7 @@ static void npc_ne_tame(npc_ne_class* i_this) {
|
||||
i_this->mpMorf->setPlaySpeed(i_this->mAnmSpeed);
|
||||
|
||||
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */
|
||||
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) {
|
||||
if (IF_DUSK(dusk::getSettings().game.no2ndFishForCat) || dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) {
|
||||
if (fpcEx_Search(s_fish_sub, _this) != NULL) {
|
||||
i_this->mAction = npc_ne_class::ACT_HOME;
|
||||
i_this->mMode = 10;
|
||||
@@ -2948,8 +2948,7 @@ static int daNpc_Ne_Execute(npc_ne_class* i_this) {
|
||||
|
||||
if (i_this->mWantsFish && (i_this->mCounter & 0xf) == 0) {
|
||||
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */
|
||||
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])
|
||||
&& i_this->mDistToTarget < 1500.0f) {
|
||||
if ((IF_DUSK(dusk::getSettings().game.no2ndFishForCat) || dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) && i_this->mDistToTarget < 1500.0f) {
|
||||
if (fopAcM_SearchByName(fpcNm_MG_ROD_e) != NULL) {
|
||||
i_this->mNoFollow = false;
|
||||
} else {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "d/actor/d_a_obj_automata.h"
|
||||
#include "d/d_msg_object.h"
|
||||
#include "d/actor/d_a_obj_scannon.h"
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include <cstring>
|
||||
|
||||
const daNpc_Toby_HIOParam daNpc_Toby_Param_c::m = {
|
||||
@@ -1398,6 +1399,7 @@ int daNpc_Toby_c::cutRepairSCannon(int arg0) {
|
||||
old.pos = current.pos;
|
||||
setAngle(cM_deg2s(5.0f * f32(mPath.getArg0())));
|
||||
mEventTimer = mPath.getArg2();
|
||||
dusk::frame_interp::request_presentation_sync();
|
||||
}
|
||||
} else if (!mHide) {
|
||||
mHide = 1;
|
||||
|
||||
@@ -62,6 +62,16 @@ void daObj_Balloon_c::saveBestScore() {
|
||||
dComIfGp_setMessageCountNumber(m_balloon_score);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static void minigameReset() {
|
||||
// !@bug d_a_obj_balloon.rel unload used to zero these file-statics; with static linking they dangle across scenes.
|
||||
m_combo_type = 0xFFFFFFFF;
|
||||
m_combo_count = 0;
|
||||
m_combo_next_score = 0;
|
||||
m_balloon_score = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static u8 hio_set;
|
||||
|
||||
static daObj_Balloon_HIO_c l_HIO;
|
||||
@@ -246,6 +256,7 @@ int daObj_Balloon_c::create() {
|
||||
}
|
||||
|
||||
if (!hio_set) {
|
||||
IF_DUSK(minigameReset());
|
||||
mHIOInit = true;
|
||||
hio_set = true;
|
||||
l_HIO.field_0x04 = -1;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "d/d_bg_w.h"
|
||||
#include "d/d_cc_uty.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/settings.h"
|
||||
|
||||
struct daObjKLift00_HIO_c : public mDoHIO_entry_c {
|
||||
daObjKLift00_HIO_c();
|
||||
@@ -295,6 +297,11 @@ int daObjKLift00_c::Create() {
|
||||
if(getLock())
|
||||
mStopSwingingFrames = 5;
|
||||
|
||||
#if TARGET_PC
|
||||
mChainInterpPrevValid = false;
|
||||
mChainInterpCurrValid = false;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -436,6 +443,34 @@ int daObjKLift00_c::Execute(Mtx** i_mtx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static void klift00_interp_callback(bool isSimFrame, void* pUserWork) {
|
||||
static_cast<daObjKLift00_c*>(pUserWork)->onInterpCallback();
|
||||
}
|
||||
|
||||
void daObjKLift00_c::onInterpCallback() {
|
||||
if (!mChainInterpPrevValid || !mChainInterpCurrValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const f32 alpha = dusk::frame_interp::get_interpolation_step();
|
||||
cXyz savedPositions[64];
|
||||
|
||||
for (int i = 0; i < mNumChains; i++) {
|
||||
savedPositions[i] = mChainPositions[i].mCurrentPos;
|
||||
const cXyz& p0 = mChainInterpPrev[i];
|
||||
const cXyz& p1 = mChainInterpCurr[i];
|
||||
mChainPositions[i].mCurrentPos = p0 + (p1 - p0) * alpha;
|
||||
}
|
||||
|
||||
setMtx();
|
||||
|
||||
for (int i = 0; i < mNumChains; i++) {
|
||||
mChainPositions[i].mCurrentPos = savedPositions[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int daObjKLift00_c::Draw() {
|
||||
g_env_light.settingTevStruct(16, ¤t.pos, &tevStr);
|
||||
g_env_light.setLightTevColorType_MAJI(mpLiftPlatform, &tevStr);
|
||||
@@ -457,6 +492,22 @@ int daObjKLift00_c::Draw() {
|
||||
|
||||
dComIfGd_setList();
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableFrameInterpolation) {
|
||||
if (mChainInterpCurrValid) {
|
||||
memcpy(mChainInterpPrev, mChainInterpCurr, mNumChains * sizeof(cXyz));
|
||||
mChainInterpPrevValid = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mNumChains; i++) {
|
||||
mChainInterpCurr[i] = mChainPositions[i].mCurrentPos;
|
||||
}
|
||||
|
||||
mChainInterpCurrValid = true;
|
||||
dusk::frame_interp::add_interpolation_callback(&klift00_interp_callback, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include "d/d_path.h"
|
||||
#include "d/d_bg_w.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#endif
|
||||
|
||||
daL8Lift_HIO_c::daL8Lift_HIO_c() {
|
||||
mStopDisappearTime = 30;
|
||||
mStartMoveTime = 60;
|
||||
@@ -380,7 +384,44 @@ void daL8Lift_c::setNextPoint() {
|
||||
mCurrentPoint = next_point;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork) {
|
||||
daL8Lift_c* lift = static_cast<daL8Lift_c*>(pUserWork);
|
||||
if (lift == NULL || lift->mpModel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr);
|
||||
g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr);
|
||||
|
||||
J3DModelData* modelData = lift->mpModel->getModelData();
|
||||
J3DMaterial* materialp = modelData->getMaterialNodePointer(0);
|
||||
|
||||
if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) {
|
||||
J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo();
|
||||
if (mtx_info != NULL) {
|
||||
Mtx m;
|
||||
C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f);
|
||||
mDoMtx_stack_c::XrotS(0x4000);
|
||||
mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z);
|
||||
cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx);
|
||||
}
|
||||
}
|
||||
|
||||
lift->mBtk.entry(modelData);
|
||||
|
||||
J3DGXColor* color = materialp->getTevKColor(1);
|
||||
color->r = l_HIO.mColorR;
|
||||
color->g = l_HIO.mColorG;
|
||||
color->b = l_HIO.mColorB;
|
||||
}
|
||||
#endif
|
||||
|
||||
int daL8Lift_c::Draw() {
|
||||
#if TARGET_PC
|
||||
dusk::frame_interp::add_interpolation_callback(&daL8Lift_interp_callback, this);
|
||||
#endif
|
||||
|
||||
g_env_light.settingTevStruct(16, ¤t.pos, &tevStr);
|
||||
g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr);
|
||||
J3DModelData* modelData = mpModel->getModelData();
|
||||
|
||||
@@ -7,13 +7,8 @@
|
||||
|
||||
#include "dusk/frame_interpolation.h"
|
||||
|
||||
#if TARGET_PC
|
||||
const u16 l_J_Ohana00_64TEX__width = 64;
|
||||
const u16 l_J_Ohana00_64TEX__height = 64;
|
||||
#else
|
||||
const u16 l_J_Ohana00_64TEX__width = 63;
|
||||
const u16 l_J_Ohana00_64TEX__height = 63;
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/dvd_asset.hpp"
|
||||
@@ -136,13 +131,8 @@ l_matDL__d_a_grass(l_J_Ohana00_64TEX)
|
||||
l_matLight4DL(l_J_Ohana00_64TEX)
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
const u16 l_J_Ohana01_64128_0419TEX__width = 64;
|
||||
const u16 l_J_Ohana01_64128_0419TEX__height = 128;
|
||||
#else
|
||||
const u16 l_J_Ohana01_64128_0419TEX__width = 63;
|
||||
const u16 l_J_Ohana01_64128_0419TEX__height = 127;
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
using GameVersion = dusk::version::GameVersion;
|
||||
@@ -592,11 +582,11 @@ dFlower_packet_c::dFlower_packet_c() {
|
||||
|
||||
#if TARGET_PC
|
||||
GXInitTexObj(&mTexObj_l_J_Ohana00_64TEX, l_J_Ohana00_64TEX,
|
||||
l_J_Ohana00_64TEX__width, l_J_Ohana00_64TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
|
||||
l_J_Ohana00_64TEX__width + 1, l_J_Ohana00_64TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
|
||||
);
|
||||
|
||||
GXInitTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, l_J_Ohana01_64128_0419TEX,
|
||||
l_J_Ohana01_64128_0419TEX__width, l_J_Ohana01_64128_0419TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
|
||||
l_J_Ohana01_64128_0419TEX__width + 1, l_J_Ohana01_64128_0419TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -494,11 +494,11 @@ dGrass_packet_c::dGrass_packet_c() {
|
||||
|
||||
#if TARGET_PC
|
||||
GXInitTexObj(&mTexObj_l_M_kusa05_RGBATEX, l_M_kusa05_RGBATEX,
|
||||
l_M_kusa05_RGBATEX__width, l_M_kusa05_RGBATEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
|
||||
l_M_kusa05_RGBATEX__width + 1, l_M_kusa05_RGBATEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
|
||||
);
|
||||
|
||||
GXInitTexObj(&mTexObj_l_M_Hijiki00TEX, l_M_Hijiki00TEX,
|
||||
l_M_Hijiki00TEX__width, l_M_Hijiki00TEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
|
||||
l_M_Hijiki00TEX__width + 1, l_M_Hijiki00TEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
|
||||
);
|
||||
#endif
|
||||
|
||||
@@ -646,18 +646,14 @@ void dGrass_packet_c::draw() {
|
||||
}
|
||||
|
||||
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
|
||||
#if TARGET_PC
|
||||
GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0);
|
||||
#endif
|
||||
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
|
||||
if (sp48 <= 3) {
|
||||
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
|
||||
} else {
|
||||
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
|
||||
}
|
||||
} else {
|
||||
#if TARGET_PC
|
||||
GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0);
|
||||
#endif
|
||||
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
|
||||
GXCallDisplayList(l_Tengusa_matDL, 0xA0);
|
||||
}
|
||||
|
||||
@@ -683,12 +679,14 @@ void dGrass_packet_c::draw() {
|
||||
|
||||
while (var_r29 != NULL) {
|
||||
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
|
||||
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
|
||||
if (sp48 <= 2) {
|
||||
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
|
||||
} else {
|
||||
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
|
||||
}
|
||||
} else {
|
||||
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
|
||||
GXCallDisplayList(l_Tengusa_matDL, 0xA0);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "JSystem/J2DGraph/J2DScreen.h"
|
||||
#include "JSystem/J2DGraph/J2DTextBox.h"
|
||||
#include "d/d_msg_string.h"
|
||||
#include "dusk/livesplit.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
|
||||
dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) {
|
||||
@@ -138,6 +140,17 @@ void dBrightCheck_c::modeWait() {}
|
||||
void dBrightCheck_c::modeMove() {
|
||||
if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) {
|
||||
mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0);
|
||||
#ifdef TARGET_PC
|
||||
dusk::speedrun::start();
|
||||
|
||||
if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) {
|
||||
// start a new run if a run isn't already in progress
|
||||
if (!dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::ImGuiMenuGame::resetForSpeedrunMode();
|
||||
dusk::m_speedrunInfo.startRun();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mCompleteCheck = true;
|
||||
mMode = MODE_WAIT_e;
|
||||
}
|
||||
|
||||
+66
-42
@@ -794,16 +794,15 @@ void dCamera_c::updatePad() {
|
||||
|
||||
if (mTriggerLeftLast > mCamSetup.ManualEndVal()) {
|
||||
if (mLockLActive == 0) {
|
||||
#if TARGET_PC
|
||||
mCamParam.mManualMode = 0;
|
||||
#endif
|
||||
mLockLJustActivated = 1;
|
||||
} else {
|
||||
mLockLJustActivated = 0;
|
||||
}
|
||||
|
||||
mLockLActive = 1;
|
||||
|
||||
#if TARGET_PC
|
||||
mCamParam.mManualMode = 0;
|
||||
#endif
|
||||
} else {
|
||||
mLockLJustActivated = 0;
|
||||
mLockLActive = 0;
|
||||
@@ -1176,14 +1175,14 @@ bool dCamera_c::Run() {
|
||||
clrFlag(0x200000);
|
||||
}
|
||||
} else {
|
||||
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
|
||||
|
||||
#if TARGET_PC
|
||||
if (mCamParam.Algorythmn(mCamStyle) != 1) {
|
||||
mCamParam.mManualMode = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
|
||||
|
||||
field_0x170++;
|
||||
field_0x160++;
|
||||
mCurCamStyleTimer++;
|
||||
@@ -1488,7 +1487,7 @@ void dCamera_c::CalcTrimSize() {
|
||||
mTrimHeight += -mTrimHeight * 0.25f;
|
||||
break;
|
||||
case 2:
|
||||
#if WIDESCREEN_SUPPORT
|
||||
#if !TARGET_PC && WIDESCREEN_SUPPORT
|
||||
if (mDoGph_gInf_c::isWide() && mDoGph_gInf_c::isWideZoom()) {
|
||||
mTrimHeight += (16.0f - mTrimHeight) * 0.25f;
|
||||
break;
|
||||
@@ -3096,10 +3095,6 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
|
||||
field_0x968 *= mMonitor.field_0xc / 5.0f;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (!dusk::getSettings().game.freeCamera || !mCamParam.mManualMode) {
|
||||
#endif
|
||||
|
||||
f32 tmp = field_0x96c * (mIsWolf == 1 ? 30.0f : 30.0f);
|
||||
center += vec3.norm() * (tmp * globe.V().Sin());
|
||||
cSGlobe globe2(vec2 - center);
|
||||
@@ -3113,10 +3108,6 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
|
||||
vec = lin_chk1.GetCross();
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
if (mCamSetup.CheckFlag(0x8000)) {
|
||||
dDbVw_Report(20, 235, " U");
|
||||
@@ -4208,6 +4199,11 @@ bool dCamera_c::chaseCamera(s32 param_0) {
|
||||
chase->field_0x8 -= chase->field_0xc;
|
||||
chase->field_0x8c = 0;
|
||||
chase->field_0x90 = false;
|
||||
|
||||
#if TARGET_PC
|
||||
freeCamera();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4631,10 +4627,6 @@ bool dCamera_c::chaseCamera(s32 param_0) {
|
||||
sp110 = mViewCache.mDirection.R();
|
||||
mViewCache.mDirection.R(mViewCache.mDirection.R() + (fVar55 - mViewCache.mDirection.R()) * chase->field_0x74);
|
||||
|
||||
#if TARGET_PC
|
||||
freeCamera();
|
||||
#endif
|
||||
|
||||
chase->field_0x64 = mViewCache.mCenter + mViewCache.mDirection.Xyz();
|
||||
mViewCache.mEye = chase->field_0x64;
|
||||
|
||||
@@ -4649,6 +4641,11 @@ bool dCamera_c::chaseCamera(s32 param_0) {
|
||||
if (chase->field_0x1c != 0) {
|
||||
chase->field_0x1c--;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
freeCamera();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7096,10 +7093,12 @@ bool dCamera_c::subjectCamera(s32 param_0) {
|
||||
cXyz sp1E0(val0, val2, val1);
|
||||
|
||||
#if TARGET_PC
|
||||
f32 aspect = mDoGph_gInf_c::getAspect();
|
||||
f32 baseAspect = FB_WIDTH / FB_HEIGHT;
|
||||
if (aspect > baseAspect) {
|
||||
sp1E0.z += (aspect - baseAspect) * 4;
|
||||
if (sp13) {
|
||||
f32 aspect = mDoGph_gInf_c::getAspect();
|
||||
f32 baseAspect = FB_WIDTH / FB_HEIGHT;
|
||||
if (aspect > baseAspect) {
|
||||
sp1E0.z += (aspect - baseAspect) * 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7477,36 +7476,48 @@ bool dCamera_c::test2Camera(s32 param_0) {
|
||||
|
||||
#if TARGET_PC
|
||||
bool dCamera_c::freeCamera() {
|
||||
if (!dusk::getSettings().game.freeCamera) {
|
||||
if (dusk::getSettings().game.freeCamera && mGear == 1) {
|
||||
mGear = 0;
|
||||
}
|
||||
|
||||
if (!dusk::getSettings().game.freeCamera || mCamStyle == 70)
|
||||
{
|
||||
mCamParam.mManualMode = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mCamParam.mManualMode) {
|
||||
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
|
||||
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
|
||||
}
|
||||
|
||||
cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f};
|
||||
f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY);
|
||||
|
||||
if (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) {
|
||||
if (!mCamParam.mManualMode) {
|
||||
mCamParam.mManualMode = 1;
|
||||
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
|
||||
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
|
||||
}
|
||||
|
||||
mCamParam.mManualMode = 1;
|
||||
camMovement = camMovement.normalize();
|
||||
camMovement.x *= (dusk::getSettings().game.invertCameraXAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
|
||||
camMovement.y *= (dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
|
||||
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity;
|
||||
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity;
|
||||
camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f;
|
||||
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 5.0f;
|
||||
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 5.0f;
|
||||
}
|
||||
|
||||
if (mCamParam.mManualMode) {
|
||||
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, -35.0f, 60.0f);
|
||||
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle);
|
||||
mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle);
|
||||
mViewCache.mDirection.mRadius = std::clamp(mCamParam.freeYAngle * 15.0f, 300.0f, 10000.0f);
|
||||
fopAc_ac_c* player = dComIfGp_getPlayer(0);
|
||||
if (!mCamParam.mManualMode || player == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mCamParam.mManualMode;
|
||||
f32 minYAngle = -30.0f;
|
||||
f32 maxAngle = 50.0f;
|
||||
|
||||
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, minYAngle, maxAngle);
|
||||
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle);
|
||||
mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle);
|
||||
|
||||
cXyz finalEye = mViewCache.mCenter + mViewCache.mDirection.Xyz();
|
||||
mViewCache.mEye = finalEye;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -11149,12 +11160,25 @@ static int camera_draw(camera_process_class* i_this) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int trim_height = body->TrimHeight();
|
||||
|
||||
#if TARGET_PC
|
||||
auto trim_height = body->TrimHeight();
|
||||
|
||||
if (mDoGph_gInf_c::isWideZoom()) {
|
||||
const auto target_ar = FB_WIDTH / (FB_HEIGHT - trim_height * 2.0f);
|
||||
const auto current_ar = mDoGph_gInf_c::m_safeWidthF / mDoGph_gInf_c::m_safeHeightF;
|
||||
|
||||
if (current_ar < target_ar) {
|
||||
trim_height = FB_HEIGHT / 2.0f * (1.0f - current_ar / target_ar);
|
||||
} else {
|
||||
trim_height = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
trim_height *= viewport->height / FB_HEIGHT;
|
||||
window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f);
|
||||
#else
|
||||
int trim_height = body->TrimHeight();
|
||||
|
||||
window->setScissor(0.0f, trim_height, FB_WIDTH, FB_HEIGHT - trim_height * 2.0f);
|
||||
#endif
|
||||
|
||||
|
||||
+45
-9
@@ -22,6 +22,10 @@
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/gx_helper.h"
|
||||
#include "dusk/logging.h"
|
||||
|
||||
static const void* getInterpKey(const void* base, int idx) {
|
||||
return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(base) ^ idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
class dDlst_2Dm_c {
|
||||
@@ -1062,7 +1066,15 @@ void dDlst_shadowReal_c::reset() {
|
||||
}
|
||||
|
||||
void dDlst_shadowReal_c::imageDraw(Mtx param_0) {
|
||||
GXSetProjection(mRenderProjMtx, GX_ORTHOGRAPHIC);
|
||||
#ifdef TARGET_PC
|
||||
Mtx render_proj_mtx;
|
||||
if (dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 2), render_proj_mtx)) {
|
||||
GXSetProjection(render_proj_mtx, GX_ORTHOGRAPHIC);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
GXSetProjection(mRenderProjMtx, GX_ORTHOGRAPHIC);
|
||||
}
|
||||
JUT_ASSERT(1916, mModelNum);
|
||||
J3DModelData* model_data;
|
||||
J3DModel** models = mpModels;
|
||||
@@ -1075,7 +1087,15 @@ void dDlst_shadowReal_c::imageDraw(Mtx param_0) {
|
||||
for (u16 j = 0; j < model_data->getShapeNum(); j++) {
|
||||
if (!model_data->getShapeNodePointer(j)->checkFlag(1)) {
|
||||
shape_pkt = (*models)->getShapePacket(j);
|
||||
shape_pkt->setBaseMtxPtr(&mViewMtx);
|
||||
#ifdef TARGET_PC
|
||||
Mtx view_mtx;
|
||||
if (dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 1), view_mtx)) {
|
||||
shape_pkt->setBaseMtxPtr(&view_mtx);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
shape_pkt->setBaseMtxPtr(&mViewMtx);
|
||||
}
|
||||
shape_pkt->drawFast();
|
||||
shape_pkt->setBaseMtxPtr((Mtx*)param_0);
|
||||
}
|
||||
@@ -1096,7 +1116,18 @@ void dDlst_shadowReal_c::draw() {
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
GXSetCurrentMtx(GX_PNMTX0);
|
||||
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
|
||||
#ifdef TARGET_PC
|
||||
Mtx view_mtx, recv_proj_mtx;
|
||||
const auto have_view_mtx = dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 1), view_mtx);
|
||||
const auto have_recv_proj_mtx = dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 3), recv_proj_mtx);
|
||||
if (have_view_mtx && have_recv_proj_mtx) {
|
||||
cMtx_concat(recv_proj_mtx, view_mtx, recv_proj_mtx);
|
||||
GXLoadTexMtxImm(recv_proj_mtx, GX_TEXMTX0, GX_MTX3x4);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
|
||||
}
|
||||
mShadowRealPoly.draw();
|
||||
}
|
||||
|
||||
@@ -1253,6 +1284,13 @@ u8 dDlst_shadowReal_c::setShadowRealMtx(cXyz* param_0, cXyz* param_1, f32 param_
|
||||
cMtx_lookAt(mViewMtx, &local_64, param_1, 0);
|
||||
C_MTXOrtho(mRenderProjMtx, param_2, -param_2, -param_2, param_2, 1.0f, 10000.0f);
|
||||
C_MTXLightOrtho(mReceiverProjMtx, param_2, -param_2, -param_2, param_2, 0.5f, -0.5f, 0.5f, 0.5f);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
const auto keybase = mpModels[0];
|
||||
dusk::frame_interp::record_final_mtx(mViewMtx, getInterpKey(keybase, 1));
|
||||
dusk::frame_interp::record_final_mtx(mRenderProjMtx, getInterpKey(keybase, 2));
|
||||
dusk::frame_interp::record_final_mtx(mReceiverProjMtx, getInterpKey(keybase, 3));
|
||||
#endif
|
||||
cMtx_concat(mReceiverProjMtx, mViewMtx, mReceiverProjMtx);
|
||||
return r29;
|
||||
}
|
||||
@@ -1277,6 +1315,10 @@ u32 dDlst_shadowReal_c::set(u32 i_key, J3DModel* i_model, cXyz* param_2, f32 par
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TARGET_PC
|
||||
// provide a stable key for interpolation
|
||||
mpModels[0] = i_model;
|
||||
#endif
|
||||
field_0x1 = setShadowRealMtx(&sp60, param_2, param_3, param_4, param_7, param_5);
|
||||
|
||||
if (!field_0x1) {
|
||||
@@ -1370,12 +1412,6 @@ void dDlst_shadowSimple_c::draw() {
|
||||
GXCallDisplayList(l_shadowVolumeDL, 0x40);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static const void* getInterpKey(const void* base, int idx) {
|
||||
return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(base) ^ idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* param_3,
|
||||
s16 param_4, f32 param_5, TGXTexObj* param_6) {
|
||||
if (param_5 < 0.0f) {
|
||||
|
||||
+28
-3
@@ -5962,6 +5962,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
|
||||
fopAc_ac_c* player = dComIfGp_getPlayer(0);
|
||||
|
||||
if (evil_packet != NULL) {
|
||||
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw2"));
|
||||
|
||||
j3dSys.reinitGX();
|
||||
if (dComIfGd_getView() != NULL) {
|
||||
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx);
|
||||
@@ -6162,6 +6164,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
|
||||
}
|
||||
}
|
||||
|
||||
IF_DUSK(GXPopDebugGroup());
|
||||
|
||||
GXSetClipMode(GX_CLIP_ENABLE);
|
||||
J3DShape::resetVcdVatCache();
|
||||
}
|
||||
@@ -6199,6 +6203,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
|
||||
f32 sp60 = fabsf(cM_ssin(g_Counter.mCounter0 * 215));
|
||||
|
||||
if (evil_packet != NULL) {
|
||||
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw"));
|
||||
|
||||
j3dSys.reinitGX();
|
||||
if (dComIfGd_getView() != NULL) {
|
||||
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx);
|
||||
@@ -6231,8 +6237,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
|
||||
|
||||
GXLoadPosMtxImm(drawMtx, GX_PNMTX0);
|
||||
GXSetCurrentMtx(GX_PNMTX0);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA4, 8);
|
||||
GXClearVtxDesc();
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
||||
@@ -6255,6 +6261,19 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
|
||||
GXSetClipMode(GX_CLIP_DISABLE);
|
||||
GXSetNumIndStages(0);
|
||||
|
||||
#if TARGET_PC
|
||||
// move color_reg0 to vtx for perf
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
||||
GXSetNumChans(1);
|
||||
GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
|
||||
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
|
||||
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
|
||||
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
#endif
|
||||
|
||||
dComIfG_Ccsp()->PrepareMass();
|
||||
|
||||
for (int i = 0; i < g_env_light.field_0x1054; i++) {
|
||||
@@ -6373,7 +6392,7 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
|
||||
color_reg0.b = (115.0f * sp28) + (15.0f * fabsf(sp2C - sp64));
|
||||
}
|
||||
|
||||
GXSetTevColor(GX_TEVREG0, color_reg0);
|
||||
IF_NOT_DUSK(GXSetTevColor(GX_TEVREG0, color_reg0));
|
||||
GXSetTevColor(GX_TEVREG1, color_reg1);
|
||||
|
||||
spC8 = spA4;
|
||||
@@ -6412,12 +6431,16 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
|
||||
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
GXPosition3f32(pos[0].x, pos[0].y, pos[0].z);
|
||||
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
|
||||
GXTexCoord2s16(0, 0);
|
||||
GXPosition3f32(pos[1].x, pos[1].y, pos[1].z);
|
||||
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
|
||||
GXTexCoord2s16(0xFF, 0);
|
||||
GXPosition3f32(pos[2].x, pos[2].y, pos[2].z);
|
||||
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
|
||||
GXTexCoord2s16(0xFF, 0xFF);
|
||||
GXPosition3f32(pos[3].x, pos[3].y, pos[3].z);
|
||||
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
|
||||
GXTexCoord2s16(0, 0xFF);
|
||||
GXEnd();
|
||||
}
|
||||
@@ -6425,6 +6448,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
|
||||
}
|
||||
}
|
||||
|
||||
IF_DUSK(GXPopDebugGroup());
|
||||
|
||||
J3DShape::resetVcdVatCache();
|
||||
GXSetClipMode(GX_CLIP_ENABLE);
|
||||
|
||||
|
||||
+10
-7
@@ -13,6 +13,9 @@
|
||||
#include "SSystem/SComponent/c_math.h"
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#if TARGET_PC
|
||||
#include <dolphin/gx/GXExtra.h>
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
#if DEBUG
|
||||
@@ -539,17 +542,14 @@ void renderingAmap_c::rendering(dDrawPath_c::poly_class const* i_poly) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Enabling the following definition will modify the following function to
|
||||
* make the map look worse for extra speed in the emulator, especially in large
|
||||
* areas such as hyrule field.
|
||||
*/
|
||||
#define HYRULE_FIELD_SPEEDHACK
|
||||
|
||||
bool renderingAmap_c::isDrawOutSideTrim() {
|
||||
bool rt = false;
|
||||
|
||||
#ifdef HYRULE_FIELD_SPEEDHACK
|
||||
return 0;
|
||||
#if TARGET_PC
|
||||
if (!dusk::getSettings().game.enableMapBackground) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (getDispType() == 0 || getDispType() == 4 || getDispType() == 3 || getDispType() == 2 ||
|
||||
@@ -1218,6 +1218,9 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) {
|
||||
|
||||
void dMap_c::_remove() {
|
||||
if (mImage_p != NULL) {
|
||||
#if TARGET_PC
|
||||
GXDestroyCopyTex(mImage_p);
|
||||
#endif
|
||||
JKR_DELETE_ARRAY(mImage_p);
|
||||
mImage_p = NULL;
|
||||
}
|
||||
|
||||
+69
-8
@@ -16,6 +16,7 @@
|
||||
|
||||
#ifdef TARGET_PC
|
||||
constexpr u16 kMapResolutionMultiplier = 4;
|
||||
constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier;
|
||||
#endif
|
||||
|
||||
void dMpath_n::dTexObjAggregate_c::create() {
|
||||
@@ -32,6 +33,48 @@ void dMpath_n::dTexObjAggregate_c::create() {
|
||||
JUT_ASSERT(74, image->magFilter == GX_NEAR);
|
||||
mDoLib_setResTimgObj(image, mp_texObj[lp1], 0, NULL);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
auto hqCircle = JKR_NEW TGXTexObj();
|
||||
|
||||
static bool hqCircleDrawn = false;
|
||||
static u8 hqCircleData[kMapCircleSize * kMapCircleSize];
|
||||
|
||||
if (!hqCircleDrawn) {
|
||||
const auto center = kMapCircleSize / 2.0f;
|
||||
const auto radiusSq = center * center;
|
||||
const auto blocksAcross = kMapCircleSize >> 3;
|
||||
const auto totalPixels = sizeof(hqCircleData);
|
||||
|
||||
for (size_t i = 0; i < totalPixels; i++) {
|
||||
// 8x4 block swizzling for I8
|
||||
const auto blockIdx = i >> 5;
|
||||
const auto localIdx = i & 31;
|
||||
|
||||
const auto blockY = blockIdx / blocksAcross;
|
||||
const auto blockX = blockIdx % blocksAcross;
|
||||
|
||||
const auto localY = localIdx >> 3;
|
||||
const auto localX = localIdx & 7;
|
||||
|
||||
const auto x = (blockX << 3) + localX;
|
||||
const auto y = (blockY << 2) + localY;
|
||||
|
||||
const auto dx = (x + 0.5f) - center;
|
||||
const auto dy = (y + 0.5f) - center;
|
||||
|
||||
// the original texture is in I4 format and uses 1 to indicate if inside the circle
|
||||
// so we scale to I8 range: 255 / 15 = 17
|
||||
hqCircleData[i] = (dx * dx + dy * dy < radiusSq) ? 17 : 0;
|
||||
}
|
||||
hqCircleDrawn = true;
|
||||
}
|
||||
|
||||
GXInitTexObj(hqCircle, hqCircleData, kMapCircleSize, kMapCircleSize, GX_TF_I8, GX_CLAMP,
|
||||
GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObjLOD(hqCircle, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1);
|
||||
mp_texObj[6] = hqCircle;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMpath_n::dTexObjAggregate_c::remove() {
|
||||
@@ -497,12 +540,6 @@ void dRenderingFDAmap_c::postRenderingMap() {
|
||||
|
||||
dMpath_n::dTexObjAggregate_c dMpath_n::m_texObjAgg;
|
||||
|
||||
/* Enabling the following definition will modify the following function to
|
||||
* make the map look worse for extra speed in the emulator, especially in large
|
||||
* areas such as hyrule field.
|
||||
*/
|
||||
#define HYRULE_FIELD_SPEEDHACK
|
||||
|
||||
void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_line) {
|
||||
s32 width = getDecorationLineWidth(p_line->field_0x1);
|
||||
if (width <= 0) {
|
||||
@@ -527,8 +564,32 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
|
||||
lineColor.r = lineColor.r - 4;
|
||||
GXSetTevColor(GX_TEVREG1, lineColor);
|
||||
|
||||
#if TARGET_PC
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
|
||||
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST);
|
||||
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXBegin(GX_LINESTRIP, GX_VTXFMT0, 2 * (data_num - 1));
|
||||
for (int i = 0; i < data_num - 1; i++) {
|
||||
GXPosition1x16(data_p[i]);
|
||||
GXTexCoord2f32(0, 0);
|
||||
GXPosition1x16(data_p[i + 1]);
|
||||
GXTexCoord2f32(0, 0);
|
||||
}
|
||||
GXEnd();
|
||||
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_KONST, GX_CC_TEXC, GX_CC_C1);
|
||||
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
|
||||
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXBegin(GX_POINTS, GX_VTXFMT0, data_num);
|
||||
for (int i = 0; i < data_num; i++) {
|
||||
GXPosition1x16(data_p[i]);
|
||||
GXTexCoord2f32(0, 0);
|
||||
}
|
||||
GXEnd();
|
||||
#else
|
||||
for (int i = 0; i < data_num; i++) {
|
||||
#ifndef HYRULE_FIELD_SPEEDHACK
|
||||
if (i < data_num - 1) {
|
||||
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
|
||||
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE,
|
||||
@@ -547,7 +608,6 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
|
||||
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
|
||||
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
||||
#endif
|
||||
|
||||
GXBegin(GX_POINTS, GX_VTXFMT0, 1);
|
||||
GXPosition1x16(data_p[0]);
|
||||
@@ -555,6 +615,7 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
|
||||
GXEnd();
|
||||
data_p++;
|
||||
}
|
||||
#endif
|
||||
|
||||
setTevSettingNonTextureDirectColor();
|
||||
GXClearVtxDesc();
|
||||
|
||||
@@ -856,7 +856,46 @@ void dMenu_DmapBg_c::decGoldFrameAlphaRate() {
|
||||
setGoldFrameAlphaRate(rate);
|
||||
}
|
||||
|
||||
void dMenu_DmapBg_c::dMapBgWide() {
|
||||
// Scale Base HUD
|
||||
mBaseScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
|
||||
mBaseScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
|
||||
|
||||
// Boss Key, Compass & Map icons
|
||||
mBaseScreen->search(MULTI_CHAR('key_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
mBaseScreen->search(MULTI_CHAR('con_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
mBaseScreen->search(MULTI_CHAR('map_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
|
||||
// Text Header
|
||||
mBaseScreen->search(MULTI_CHAR('t_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
mBaseScreen->search(MULTI_CHAR('f_t_00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
|
||||
// C Button
|
||||
mBaseScreen->search(MULTI_CHAR('c_btn2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
|
||||
// Scale Buttons HUD
|
||||
mButtonScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
|
||||
mButtonScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
|
||||
|
||||
// Buttons
|
||||
mButtonScreen->search(MULTI_CHAR('cont_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
|
||||
// C Button
|
||||
mButtonScreen->search(MULTI_CHAR('c_btn'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
mButtonScreen->search(MULTI_CHAR('c_text_s'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
mButtonScreen->search(MULTI_CHAR('c_text'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
mButtonScreen->search(MULTI_CHAR('f_text_s'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
mButtonScreen->search(MULTI_CHAR('f_text'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
|
||||
// Decorations
|
||||
mButtonScreen->search(MULTI_CHAR('kazari_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
}
|
||||
|
||||
void dMenu_DmapBg_c::draw() {
|
||||
#if TARGET_PC
|
||||
dMapBgWide();
|
||||
#endif
|
||||
|
||||
u32 scissor_left;
|
||||
u32 scissor_top;
|
||||
u32 scissor_width;
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "d/d_menu_dmap_map.h"
|
||||
#include "f_op/f_op_msg_mng.h"
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
#if TARGET_PC
|
||||
#include <dolphin/gx/GXExtra.h>
|
||||
#endif
|
||||
|
||||
struct dMdm_HIO_prm_res_dst_s {
|
||||
static void* m_res;
|
||||
@@ -291,6 +294,9 @@ void dMenu_DmapMap_c::_create(u16 param_0, u16 param_1, u16 param_2, u16 param_3
|
||||
void dMenu_DmapMap_c::_delete() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (mMapImage_p[i] != NULL) {
|
||||
#if TARGET_PC
|
||||
GXDestroyCopyTex(mMapImage_p[i]);
|
||||
#endif
|
||||
JKR_DELETE_ARRAY(mMapImage_p[i]);
|
||||
}
|
||||
|
||||
|
||||
+34
-1
@@ -20,6 +20,15 @@
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
void dMenu_Fmap2DBack_c::fMapBackWide() {
|
||||
mpBaseScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
|
||||
mpBaseScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
|
||||
mpBackScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
|
||||
mpBackScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
dMenu_Fmap2DBack_c::dMenu_Fmap2DBack_c() {
|
||||
dMeter2Info_setMapDrugFlag(0);
|
||||
|
||||
@@ -267,6 +276,10 @@ dMenu_Fmap2DBack_c::~dMenu_Fmap2DBack_c() {
|
||||
}
|
||||
|
||||
void dMenu_Fmap2DBack_c::draw() {
|
||||
#if TARGET_PC
|
||||
fMapBackWide();
|
||||
#endif
|
||||
|
||||
calcBlink();
|
||||
|
||||
J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort();
|
||||
@@ -1199,7 +1212,7 @@ f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeX() {
|
||||
}
|
||||
|
||||
f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() {
|
||||
#if PLATFORM_GCN && !TARGET_PC
|
||||
#if PLATFORM_GCN
|
||||
return getMapScissorAreaSizeX();
|
||||
#else
|
||||
return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale();
|
||||
@@ -1407,6 +1420,11 @@ void dMenu_Fmap2DBack_c::stageTextureDraw() {
|
||||
mpSpotTexture->setAlpha(mAlphaRate * 255.0f * field_0xfa8 * mSpotTextureFadeAlpha);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
JUTPalette* pPalette = mpSpotTexture->getTexture(0)->getPalette();
|
||||
pPalette->dataUploaded();
|
||||
#endif
|
||||
|
||||
mpSpotTexture->draw(mTransX + getMapScissorAreaLX(), mTransZ + getMapScissorAreaLY(),
|
||||
getMapScissorAreaSizeRealX(), getMapScissorAreaSizeRealY(), false, false,
|
||||
false);
|
||||
@@ -2179,6 +2197,17 @@ void dMenu_Fmap2DBack_c::setArrowPosAxis(f32 i_posX, f32 i_posZ) {
|
||||
control_ypos = 0.0f;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
void dMenu_Fmap2DTop_c::fMapTopWide() {
|
||||
mpTitleScreen->search(MULTI_CHAR('spot0_n'))->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
|
||||
mpTitleScreen->search(MULTI_CHAR('spot2_n'))->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
|
||||
mpTitleScreen->search(MULTI_CHAR('name_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-243.0f), -169.0f);
|
||||
mpTitleScreen->search(MULTI_CHAR('sub_n_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-80.0f), -154.0f);
|
||||
mpTitleScreen->search(MULTI_CHAR('btn_i_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-241.0f), 177.0f);
|
||||
mpTitleScreen->search(MULTI_CHAR('cont_n'))->translate(mDoGph_gInf_c::ScaleHUDXRight(515.0f), 83.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
dMenu_Fmap2DTop_c::dMenu_Fmap2DTop_c(JKRExpHeap* i_heap, STControl* i_stick) {
|
||||
mpHeap = i_heap;
|
||||
mTransX = 0.0f;
|
||||
@@ -2572,6 +2601,10 @@ void dMenu_Fmap2DTop_c::setAllAlphaRate(f32 i_rate, bool i_init) {
|
||||
}
|
||||
|
||||
void dMenu_Fmap2DTop_c::draw() {
|
||||
#if TARGET_PC
|
||||
fMapTopWide();
|
||||
#endif
|
||||
|
||||
u32 scissor_left, scissor_top, scissor_width, scissor_height;
|
||||
J2DOrthoGraph* ctx = static_cast<J2DOrthoGraph*>(dComIfGp_getCurrentGrafPort());
|
||||
ctx->setup2D();
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "d/d_debug_viewer.h"
|
||||
#include "d/d_menu_fmap_map.h"
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
#if TARGET_PC
|
||||
#include <dolphin/gx/GXExtra.h>
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
static u8 twoValueLineInterpolation(u8 i_value1, u8 i_value2, f32 i_param) {
|
||||
@@ -494,6 +497,9 @@ void dMenu_FmapMap_c::_delete() {
|
||||
mResTIMG = NULL;
|
||||
}
|
||||
if (mMapImage_p != NULL) {
|
||||
#if TARGET_PC
|
||||
GXDestroyCopyTex(mMapImage_p);
|
||||
#endif
|
||||
JKR_DELETE_ARRAY(mMapImage_p);
|
||||
mMapImage_p = NULL;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#include "d/d_msg_scrn_arrow.h"
|
||||
#include "d/d_lib.h"
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "dusk/achievements.h"
|
||||
#endif
|
||||
|
||||
#if VERSION == VERSION_GCN_JPN
|
||||
#define D_MENU_LETTER_LINE_MAX 9
|
||||
#else
|
||||
@@ -514,6 +518,10 @@ void dMenu_Letter_c::read_open_init() {
|
||||
setAButtonString(0);
|
||||
setBButtonString(0);
|
||||
mpBlackTex->setAlpha(0);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
dusk::AchievementSystem::get().signal("open_letter");
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMenu_Letter_c::read_open_move() {
|
||||
|
||||
+6
-6
@@ -316,6 +316,12 @@ int dMeter2_c::_execute() {
|
||||
}
|
||||
|
||||
int dMeter2_c::_draw() {
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.disableMainHUD) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mpMap != NULL) {
|
||||
mpMap->_draw();
|
||||
}
|
||||
@@ -424,12 +430,6 @@ void dMeter2_c::setLifeZero() {
|
||||
void dMeter2_c::checkStatus() {
|
||||
mStatus = 0;
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.disableMainHUD) {
|
||||
mStatus |= 0xF0000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
field_0x12c = field_0x128;
|
||||
|
||||
field_0x128 = daPy_py_c::checkNowWolf();
|
||||
|
||||
@@ -2306,6 +2306,10 @@ void dMeter_drawHIO_c::updateOnWide() {
|
||||
// River Canoe Minigame
|
||||
g_drawHIO.mMiniGame.mCounterPosX[1] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mCounterPosX[1]);
|
||||
g_drawHIO.mMiniGame.mIconPosX[1] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mIconPosX[1]);
|
||||
|
||||
// Bulblin Count in Hidden Village
|
||||
g_drawHIO.mMiniGame.mCounterPosX[2] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mCounterPosX[2]);
|
||||
g_drawHIO.mMiniGame.mIconPosX[2] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mIconPosX[2]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1987,13 +1987,6 @@ bool jmessage_tSequenceProcessor::do_isReady() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) {
|
||||
field_0xb2 = 1;
|
||||
pReference->setSendTimer(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dComIfGp_checkMesgBgm()) {
|
||||
bool isItemMusicPlaying = true;
|
||||
if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET &&
|
||||
@@ -2066,7 +2059,7 @@ bool jmessage_tSequenceProcessor::do_isReady() {
|
||||
case 0:
|
||||
case 5:
|
||||
case 6:
|
||||
if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0) {
|
||||
if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0 IF_DUSK(|| (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)))) {
|
||||
field_0xa4 = 0;
|
||||
pReference->onBatchFlag();
|
||||
pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX);
|
||||
|
||||
+38
-1
@@ -32,6 +32,9 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
static void dMsgObject_addFundRaising(s16 param_0);
|
||||
@@ -1594,7 +1597,7 @@ u8 dMsgObject_c::isSend() {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) ||)
|
||||
if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0) && !isShopItemMessage()) ||)
|
||||
mDoCPd_c::getTrigA(0) != 0 || mDoCPd_c::getTrigB(0) != 0) {
|
||||
return 2;
|
||||
}
|
||||
@@ -1866,6 +1869,40 @@ bool dMsgObject_c::isTalkMessage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
bool dMsgObject_c::isShopItemMessage() {
|
||||
|
||||
// Probably a better way to do this than just listing every message id, but this works for now
|
||||
// Note: Keep contents sorted so we can use binary search
|
||||
const auto shopMsgIds = std::to_array<std::vector<s16>>({
|
||||
{},
|
||||
// zel_01.bmg - Seras Shop
|
||||
{7001, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7013, 7014, 7022, 7023, 7028, 7029,
|
||||
7044, 7045, 7053},
|
||||
// zel_02.bmg - Kakariko Shops
|
||||
{5251, 5253, 5254, 5256, 5258, 5259, 5653, 5654, 5656, 5660, 5661, 5664, 5665, 5697, 5698,
|
||||
5699, 5803, 5804, 5806, 5810, 5811, 5812, 5814, 5821, 5823, 5824, 5987, 5988, 5989, 5990,
|
||||
5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999},
|
||||
// zel_03.bmg - Death Mountain Shop
|
||||
{5303, 5304, 5306, 5310, 5311, 5314, 5315, 5322, 5323, 5324, 5496, 5497, 5498, 5499},
|
||||
// zel_04.bmg - Castle Town Shops
|
||||
{5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5431,
|
||||
5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5444, 5449, 5450, 5451, 5452,
|
||||
5462},
|
||||
// zel_05.bmg - Oocca Shop
|
||||
{9428, 9429, 9430, 9431, 9432, 9437, 9443, 9448, 9449, 9451, 9459}
|
||||
});
|
||||
|
||||
u16 id = mMessageID;
|
||||
s16 group = dMsgObject_getGroupID();
|
||||
if (group < shopMsgIds.size()) {
|
||||
return std::ranges::binary_search(shopMsgIds[group], id);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* dMsgObject_c::getSmellName() {
|
||||
JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20);
|
||||
char* data_ptr = (char*)info_header_p + info_header_p->header.size;
|
||||
|
||||
+16
-5
@@ -5,19 +5,20 @@
|
||||
|
||||
#include "d/dolzel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/d_s_name.h"
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/d_s_name.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "f_op/f_op_overlap_mng.h"
|
||||
#include "f_op/f_op_scene_mng.h"
|
||||
#include "m_Do/m_Do_Reset.h"
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
#include "m_Do/m_Do_machine.h"
|
||||
#include "m_Do/m_Do_mtx.h"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
#include "f_op/f_op_overlap_mng.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "m_Do/m_Do_mtx.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen)
|
||||
@@ -412,6 +413,16 @@ void dScnName_c::changeGameScene() {
|
||||
dKy_clear_game_init();
|
||||
dComIfGs_resetDan();
|
||||
dComIfGs_setRestartRoomParam(0);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) {
|
||||
// start a new run on file load if a run isn't already in progress
|
||||
if (!dusk::m_speedrunInfo.m_isRunStarted) {
|
||||
dusk::ImGuiMenuGame::resetForSpeedrunMode();
|
||||
dusk::m_speedrunInfo.startRun();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/memory.h"
|
||||
#include <dusk/autosave.h>
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
@@ -700,6 +701,10 @@ static u8 lbl_8074CAE4;
|
||||
static u32 l_sceneChangeStartTick;
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
static BOOL autoSaved;
|
||||
#endif
|
||||
|
||||
static int dScnPly_Execute(dScnPly_c* i_this) {
|
||||
#if DEBUG
|
||||
fapGm_HIO_c::startCpuTimer();
|
||||
@@ -742,6 +747,15 @@ static int dScnPly_Execute(dScnPly_c* i_this) {
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (!dComIfGp_event_runCheck() && !fopOvlpM_IsPeek() && !dComIfG_resetToOpening(i_this) &&
|
||||
!dComIfGp_isEnableNextStage() && autoSaved == FALSE)
|
||||
{
|
||||
triggerAutoSave();
|
||||
autoSaved = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
dKy_itudemo_se();
|
||||
|
||||
#if DEBUG
|
||||
@@ -1593,6 +1607,11 @@ static int dScnPly_Create(scene_class* i_this) {
|
||||
|
||||
dScnPly_c* a_this = (dScnPly_c*)i_this;
|
||||
int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this);
|
||||
|
||||
#if TARGET_PC
|
||||
autoSaved = FALSE;
|
||||
#endif
|
||||
|
||||
return phase_state;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,11 @@
|
||||
#include "lingcod/lingcod.h"
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#include <f_ap/f_ap_game.h>
|
||||
#include <dusk/autosave.h>
|
||||
#endif
|
||||
|
||||
static u8 dSv_item_rename(u8 i_itemNo) {
|
||||
switch (i_itemNo) {
|
||||
@@ -345,6 +349,10 @@ void dSv_player_item_c::setItem(int i_slotNo, u8 i_itemNo) {
|
||||
dComIfGp_setSelectItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
triggerAutoSave();
|
||||
#endif
|
||||
}
|
||||
|
||||
u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const {
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <memory>
|
||||
|
||||
#include "aurora/lib/logging.hpp"
|
||||
#include "os_report.h"
|
||||
|
||||
aurora::Module Log("dusk::osReport");
|
||||
|
||||
bool dusk::OSReportReallyForceEnable = false;
|
||||
|
||||
u8 __OSReport_disable;
|
||||
|
||||
void OSReportDisable() {
|
||||
__OSReport_disable = true;
|
||||
}
|
||||
|
||||
void OSReportEnable() {
|
||||
__OSReport_disable = false;
|
||||
}
|
||||
|
||||
static bool checkEnabled() {
|
||||
return !__OSReport_disable || dusk::OSReportReallyForceEnable;
|
||||
}
|
||||
|
||||
static std::string FormatToString(const char* msg, va_list list) {
|
||||
int ret = vsnprintf(nullptr, 0, msg, list);
|
||||
if (ret <= 0) {
|
||||
return {};
|
||||
}
|
||||
++ret;
|
||||
std::unique_ptr<char[]> buf(new char[ret]);
|
||||
vsnprintf(buf.get(), ret, msg, list);
|
||||
buf[ret - 1] = '\0';
|
||||
return {buf.get()};
|
||||
}
|
||||
|
||||
void OSReport(const char* fmt, ...) {
|
||||
if (!checkEnabled()) {
|
||||
return;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const auto str = FormatToString(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Log.info("{}", str);
|
||||
}
|
||||
|
||||
void OSPanic(const char* file, int line, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const auto str = FormatToString(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Log.fatal("[{}:{}] {}", file, line, str);
|
||||
}
|
||||
|
||||
void OSReport_Error(const char* fmt, ...) {
|
||||
if (!checkEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const auto str = FormatToString(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Log.error("{}", str);
|
||||
}
|
||||
|
||||
void OSReport_FatalError(const char* fmt, ...) {
|
||||
if (!checkEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const auto str = FormatToString(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Log.fatal("{}", str);
|
||||
}
|
||||
|
||||
void OSReport_Warning(const char* fmt, ...) {
|
||||
if (!checkEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const auto str = FormatToString(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Log.warn("{}", str);
|
||||
}
|
||||
|
||||
void OSReport_System(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
OSVAttention(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void OSVAttention(const char* fmt, va_list args) {
|
||||
if (!checkEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto str = FormatToString(fmt, args);
|
||||
|
||||
Log.info("{}", str);
|
||||
}
|
||||
|
||||
void OSAttention(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
OSVAttention(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
+127
-8
@@ -8,6 +8,7 @@
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "d/d_demo.h"
|
||||
#include "f_pc/f_pc_name.h"
|
||||
#include "f_op/f_op_actor_mng.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
@@ -46,6 +47,21 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"plumm_max",
|
||||
"Thank You Berry Much",
|
||||
"Score 61,454 points in the Plumm minigame.",
|
||||
AchievementCategory::Minigame,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
if (dComIfGs_getBalloonScore() >= 61454) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"rollgoal_8",
|
||||
@@ -258,6 +274,58 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"friendly_fire",
|
||||
"Friendly Fire",
|
||||
"Get hit by your own cannonball.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
if (AchievementSystem::get().hasSignal("iron_ball_hit_player")) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"long_jump_attack",
|
||||
"Long Jump Attack",
|
||||
"Travel more than 20 meters in a single jump attack before landing.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
static bool inJump = false;
|
||||
static float startX = 0.0f, startZ = 0.0f;
|
||||
|
||||
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
|
||||
if (link == nullptr) {
|
||||
inJump = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inJump) {
|
||||
if (link->mProcID == daAlink_c::PROC_CUT_JUMP) {
|
||||
inJump = true;
|
||||
startX = link->current.pos.x;
|
||||
startZ = link->current.pos.z;
|
||||
}
|
||||
} else if (link->mProcID == daAlink_c::PROC_CUT_JUMP_LAND) {
|
||||
inJump = false;
|
||||
const float dx = link->current.pos.x - startX;
|
||||
const float dz = link->current.pos.z - startZ;
|
||||
if (dx * dx + dz * dz >= 2000.0f * 2000.0f) {
|
||||
a.progress = 1;
|
||||
}
|
||||
} else if (link->mProcID != daAlink_c::PROC_CUT_JUMP) {
|
||||
inJump = false;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"back_in_time",
|
||||
@@ -267,18 +335,13 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
static int titleNoDemoFrames = 0;
|
||||
if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) {
|
||||
titleNoDemoFrames = 0;
|
||||
return;
|
||||
}
|
||||
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
|
||||
if (link != nullptr && dDemo_c::getMode() == 0) {
|
||||
if (++titleNoDemoFrames >= 60) {
|
||||
const auto* player = static_cast<const daPy_py_c*>(daPy_getPlayerActorClass());
|
||||
|
||||
if (player != nullptr && player->mDemo.getDemoMode() == 1) {
|
||||
a.progress = 1;
|
||||
}
|
||||
} else {
|
||||
titleNoDemoFrames = 0;
|
||||
}
|
||||
},
|
||||
{}
|
||||
@@ -345,6 +408,41 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"email_me",
|
||||
"Email Me",
|
||||
"Read a letter during the Dark Beast Ganon fight.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
void* dbgExists = fopAcM_SearchByName(fpcNm_B_MGN_e);
|
||||
if (dbgExists && AchievementSystem::get().hasSignal("open_letter")) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"heavy-hitter",
|
||||
"Heavy Hitter",
|
||||
"Wear the Iron Boots during the end credits.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
|
||||
if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
|
||||
return;
|
||||
}
|
||||
if (daPy_getPlayerActorClass()->checkEquipHeavyBoots()) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -426,6 +524,26 @@ void AchievementSystem::clearAll() {
|
||||
save();
|
||||
}
|
||||
|
||||
void AchievementSystem::signal(const char* key) {
|
||||
m_signals.insert(key);
|
||||
}
|
||||
|
||||
bool AchievementSystem::hasSignal(const char* key) const {
|
||||
return m_signals.count(key) > 0;
|
||||
}
|
||||
|
||||
void AchievementSystem::clearOne(const char* key) {
|
||||
for (auto& e : m_entries) {
|
||||
if (std::string(e.achievement.key) == key) {
|
||||
e.achievement.progress = 0;
|
||||
e.achievement.unlocked = false;
|
||||
e.extra = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
void AchievementSystem::processEntry(Entry& e) {
|
||||
if (e.achievement.unlocked) {
|
||||
return;
|
||||
@@ -458,6 +576,7 @@ void AchievementSystem::tick() {
|
||||
for (auto& e : m_entries) {
|
||||
processEntry(e);
|
||||
}
|
||||
m_signals.clear();
|
||||
if (m_dirty) {
|
||||
save();
|
||||
m_dirty = false;
|
||||
|
||||
@@ -48,6 +48,20 @@ f32 dusk::audio::MasterVolume = 1.0f;
|
||||
f32 dusk::audio::PrevMasterVolume = 1.0f;
|
||||
bool dusk::audio::EnableReverb = true;
|
||||
bool dusk::audio::DumpAudio = false;
|
||||
bool dusk::audio::EnableHrtf = false;
|
||||
f32 dusk::audio::HrtfGain = 0.5f;
|
||||
|
||||
|
||||
// 3dB at 5kHz.
|
||||
static constexpr f32 HRTF_LP_K = 0.75f;
|
||||
static constexpr f32 HRTF_ALLPASS_G = 0.3f;
|
||||
// Front never drops below (1 - HRTF_EXTRACT_MAX).
|
||||
static constexpr f32 HRTF_EXTRACT_MAX = 0.6f;
|
||||
|
||||
static f32 sHrtfLp1 = 0.0f;
|
||||
static f32 sHrtfLp2 = 0.0f;
|
||||
static f32 sHrtfApIn1 = 0.0f;
|
||||
static f32 sHrtfApOut1 = 0.0f;
|
||||
|
||||
/**
|
||||
* Validate that a DSP channel's format is actually something we know how to play.
|
||||
@@ -283,6 +297,9 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
|
||||
DspSubframe reverbInputR = {};
|
||||
bool anyReverbInput = false;
|
||||
|
||||
DspSubframe surroundBus = {};
|
||||
bool anySurroundInput = false;
|
||||
|
||||
for (int i = 0; i < channels.size(); i++) {
|
||||
auto& channel = channels[i];
|
||||
auto& channelAux = ChannelAux[i];
|
||||
@@ -324,6 +341,21 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
|
||||
}
|
||||
}
|
||||
|
||||
if (EnableHrtf && channel.mAutoMixerBeenSet) {
|
||||
f32 dolby = (channel.mAutoMixerPanDolby & 0xFF) / 127.0f;
|
||||
if (dolby > 0.0f) {
|
||||
anySurroundInput = true;
|
||||
f32 extract = dolby * HRTF_EXTRACT_MAX;
|
||||
f32 frontScale = 1.0f - extract;
|
||||
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
|
||||
f32 mono = (channelSubframe.channels[0][j] + channelSubframe.channels[1][j]) * 0.5f;
|
||||
surroundBus[j] += mono * extract;
|
||||
channelSubframe.channels[0][j] *= frontScale;
|
||||
channelSubframe.channels[1][j] *= frontScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DumpAudio && sChannelDumpFiles[i]) {
|
||||
f32 interleaved[DSP_SUBFRAME_SIZE * 2];
|
||||
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
|
||||
@@ -349,6 +381,28 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
|
||||
ReverbHasTail = wetEnergy >= REVERB_ENERGY_EPSILON;
|
||||
}
|
||||
|
||||
if (EnableHrtf && anySurroundInput) {
|
||||
// Two-pole LPF: -12 dB/oct above 3 kHz
|
||||
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
|
||||
sHrtfLp1 = (1.0f - HRTF_LP_K) * sHrtfLp1 + HRTF_LP_K * surroundBus[j];
|
||||
sHrtfLp2 = (1.0f - HRTF_LP_K) * sHrtfLp2 + HRTF_LP_K * sHrtfLp1;
|
||||
surroundBus[j] = sHrtfLp2;
|
||||
}
|
||||
|
||||
// Mix into L and R
|
||||
// L gets the filtered signal directly; R gets it allpass for mild decorrelation
|
||||
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
|
||||
f32 s = surroundBus[j];
|
||||
|
||||
subframe.channels[0][j] += s * HrtfGain;
|
||||
|
||||
f32 r = -HRTF_ALLPASS_G * s + sHrtfApIn1 + HRTF_ALLPASS_G * sHrtfApOut1;
|
||||
sHrtfApIn1 = s;
|
||||
sHrtfApOut1 = r;
|
||||
subframe.channels[1][j] += r * HrtfGain;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& channel : subframe.channels) {
|
||||
ApplyVolume(channel, channel, PrevMasterVolume, MasterVolume);
|
||||
}
|
||||
|
||||
@@ -133,4 +133,6 @@ namespace dusk::audio {
|
||||
extern f32 PrevMasterVolume;
|
||||
extern bool EnableReverb;
|
||||
extern bool DumpAudio;
|
||||
extern bool EnableHrtf;
|
||||
extern f32 HrtfGain;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "dusk/autosave.h"
|
||||
#include "imgui/ImGuiConsole.hpp"
|
||||
|
||||
u8 mSaveBuffer[QUEST_LOG_SIZE * 3];
|
||||
u8 mAutoSaveProc = 0;
|
||||
int autoSaveWriteState = 0;
|
||||
|
||||
typedef void (*AutoSaveFuncs)();
|
||||
static AutoSaveFuncs AutoSaveFuncsProc[] = {
|
||||
noAutoSave, enterAutoSave, autoSaving, waitingForWrite, endAutoSave,
|
||||
};
|
||||
|
||||
void noAutoSave() {}
|
||||
|
||||
void triggerAutoSave() {
|
||||
if (dusk::getSettings().game.autoSave && mAutoSaveProc == 0 &&
|
||||
strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0)
|
||||
{
|
||||
mAutoSaveProc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void updateAutoSave() {
|
||||
(AutoSaveFuncsProc[mAutoSaveProc])();
|
||||
}
|
||||
|
||||
void writeAutoSave() {
|
||||
int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo());
|
||||
|
||||
dComIfGs_putSave(stageNo);
|
||||
dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum());
|
||||
mDoMemCdRWm_SetCheckSumGameData(mSaveBuffer, dComIfGs_getDataNum());
|
||||
|
||||
u8* save = mSaveBuffer;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
mDoMemCdRWm_TestCheckSumGameData(save);
|
||||
save += QUEST_LOG_SIZE;
|
||||
}
|
||||
|
||||
g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0);
|
||||
}
|
||||
|
||||
void autoSaving() {
|
||||
int cardState = g_mDoMemCd_control.LoadSync(mSaveBuffer, sizeof(mSaveBuffer), 0);
|
||||
if (cardState != 0) {
|
||||
if (cardState == 2) {
|
||||
mAutoSaveProc = 1;
|
||||
} else if (cardState == 1) {
|
||||
writeAutoSave();
|
||||
mAutoSaveProc = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enterAutoSave() {
|
||||
u32 cardStatus = g_mDoMemCd_control.getStatus(0);
|
||||
|
||||
if (cardStatus != 14) {
|
||||
switch (cardStatus) {
|
||||
case 2:
|
||||
g_mDoMemCd_control.load();
|
||||
mAutoSaveProc = 2;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
break;
|
||||
default:
|
||||
mAutoSaveProc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void waitingForWrite() {
|
||||
autoSaveWriteState = g_mDoMemCd_control.SaveSync();
|
||||
|
||||
if (autoSaveWriteState == 2) {
|
||||
mAutoSaveProc = 0;
|
||||
} else if (autoSaveWriteState == 1) {
|
||||
mAutoSaveProc = 4;
|
||||
}
|
||||
}
|
||||
|
||||
void endAutoSave() {
|
||||
dusk::g_imguiConsole.AddToast("Saving...", 2.0f);
|
||||
mAutoSaveProc = 0;
|
||||
}
|
||||
@@ -76,8 +76,8 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(640, 200), ImVec2(800, 900));
|
||||
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(800, 200), ImVec2(1280, 900));
|
||||
ImGui::SetNextWindowSize(ImVec2(800, 480), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (!ImGui::Begin(
|
||||
"Achievements", &open,
|
||||
@@ -111,6 +111,7 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
{AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)},
|
||||
{AchievementCategory::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)},
|
||||
{AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 1.0f)},
|
||||
{AchievementCategory::Misc, "Misc", ImVec4(0.65f, 0.65f, 0.65f, 1.0f)},
|
||||
{AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)},
|
||||
};
|
||||
|
||||
@@ -131,7 +132,7 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string tabLabel = fmt::format("{} ({}/{})", catInfo.label, catUnlocked, catTotal);
|
||||
const std::string tabLabel = fmt::format("{} ({}/{})###{}", catInfo.label, catUnlocked, catTotal, catInfo.label);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, catInfo.color);
|
||||
const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str());
|
||||
@@ -152,6 +153,7 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
continue;
|
||||
}
|
||||
ImGui::PushID(a.key);
|
||||
ImGui::BeginGroup();
|
||||
|
||||
ImGui::PushStyleColor(
|
||||
ImGuiCol_Text,
|
||||
@@ -190,6 +192,21 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
|
||||
ImGui::OpenPopup("##ctx");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("##ctx")) {
|
||||
ImGui::TextDisabled("%s", a.name);
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Clear Achievement")) {
|
||||
AchievementSystem::get().clearOne(a.key);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuTools.hpp"
|
||||
#include <cmath>
|
||||
#include "JSystem/JAudio2/JAISeq.h"
|
||||
#include "JSystem/JAudio2/JAISeMgr.h"
|
||||
#include "JSystem/JAudio2/JAISeqMgr.h"
|
||||
#include "JSystem/JAudio2/JAIStreamMgr.h"
|
||||
@@ -15,6 +17,24 @@ static std::array<u32, DSP_CHANNELS> lastResetCounts = {};
|
||||
|
||||
static bool sortUpdateCount = true;
|
||||
|
||||
static void DrawDirectionGauge(float pan, float dolby) {
|
||||
constexpr float R = 20.0f;
|
||||
constexpr float SIZE = R * 2.0f + 4.0f;
|
||||
|
||||
ImVec2 origin = ImGui::GetCursorScreenPos();
|
||||
ImGui::Dummy(ImVec2(SIZE, SIZE));
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
ImVec2 c = ImVec2(origin.x + SIZE * 0.5f, origin.y + SIZE * 0.5f);
|
||||
|
||||
dl->AddCircle(c, R, IM_COL32(90, 90, 90, 255), 32);
|
||||
|
||||
float dx = (pan - 0.5f) * 2.0f;
|
||||
float dy = dolby * 2.0f - 1.0f;
|
||||
float len = sqrtf(dx * dx + dy * dy);
|
||||
if (len > 1.0f) { dx /= len; dy /= len; }
|
||||
dl->AddLine(c, ImVec2(c.x + dx * R, c.y + dy * R), IM_COL32(255, 200, 50, 255), 1.5f);
|
||||
}
|
||||
|
||||
static void DisplayDspChannel(int i) {
|
||||
using namespace dusk::audio;
|
||||
|
||||
@@ -52,8 +72,10 @@ static void DisplayDspChannel(int i) {
|
||||
auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f;
|
||||
auto volume = VolumeFromU16(channel.mAutoMixerVolume);
|
||||
auto pitch = channel.mPitch / 4096.0f;
|
||||
DrawDirectionGauge(pan, dolby);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(
|
||||
"Auto mixer active (pan: %f, dolby: %f, fx: %f, volume: %f, pitch %f)",
|
||||
"pan: %.2f dolby: %.2f\nfx: %.2f vol: %.2f pitch: %.2f",
|
||||
pan, dolby, fxMix, volume, pitch);
|
||||
} else {
|
||||
ImGui::Text(
|
||||
@@ -183,6 +205,10 @@ static void ShowAllJAISes() {
|
||||
if (ImGui::Button("Pause All")) {
|
||||
category->pause(true);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Resume All")) {
|
||||
category->pause(false);
|
||||
}
|
||||
|
||||
for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) {
|
||||
const auto se = seLink->getObject();
|
||||
@@ -196,6 +222,33 @@ static void ShowAllJAISes() {
|
||||
}
|
||||
|
||||
|
||||
static void ShowSeqTracks(JAISeq& seq) {
|
||||
JASTrack& root = seq.inner_.outputTrack;
|
||||
|
||||
for (int group = 0; group < 2; group++) {
|
||||
JASTrack* groupTrack = root.getChild(group);
|
||||
if (groupTrack == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < JASTrack::MAX_CHILDREN; j++) {
|
||||
JASTrack* track = groupTrack->getChild(j);
|
||||
if (track == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int trackIdx = group * 16 + j;
|
||||
char label[64];
|
||||
snprintf(label, sizeof(label), "Track %d (bank %hu, prog %hu)##%p",
|
||||
trackIdx, track->getBankNumber(), track->getProgNumber(), track);
|
||||
bool muted = track->mFlags.mute;
|
||||
if (ImGui::Checkbox(label, &muted)) {
|
||||
track->mute(muted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowAllJAISeqs() {
|
||||
auto& mgr = *JAISeqMgr::getInstance();
|
||||
|
||||
@@ -206,6 +259,26 @@ static void ShowAllJAISeqs() {
|
||||
if (ImGui::Button("Unpause")) {
|
||||
mgr.pause(false);
|
||||
}
|
||||
|
||||
ImGui::Text("Active sequences: %d", mgr.getNumActiveSeqs());
|
||||
|
||||
auto* seqList = mgr.getSeqList();
|
||||
for (auto* link = seqList->getFirst(); link != nullptr; link = link->getNext()) {
|
||||
JAISeq* seq = link->getObject();
|
||||
if (seq == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%p", seq);
|
||||
|
||||
if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
|
||||
ImGui::Text("Seq [%p]", seq);
|
||||
ShowSeqTracks(*seq);
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
void dusk::ImGuiMenuTools::ShowAudioDebug() {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dusk/config.hpp"
|
||||
#include "dusk/dusk.h"
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/livesplit.h"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
@@ -65,6 +66,10 @@ namespace dusk {
|
||||
ImGui::TextUnformatted(text.data(), text.data() + text.size());
|
||||
}
|
||||
|
||||
void DuskToast(std::string_view message, float duration) {
|
||||
g_imguiConsole.AddToast(message, duration);
|
||||
}
|
||||
|
||||
void ImGuiTextCenter(std::string_view text) {
|
||||
ImGui::NewLine();
|
||||
float fontSize = ImGui::CalcTextSize(
|
||||
@@ -315,22 +320,18 @@ namespace dusk {
|
||||
ImGuiMenuGame::ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape) && getSettings().video.enableFullscreen) {
|
||||
ImGuiMenuGame::ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (!dusk::IsGameLaunched) {
|
||||
m_preLaunchWindow.draw();
|
||||
}
|
||||
// if (!dusk::IsGameLaunched) {
|
||||
// m_preLaunchWindow.draw();
|
||||
// }
|
||||
|
||||
m_isHidden = !getSettings().backend.duskMenuOpen;
|
||||
bool showMenu = !dusk::IsGameLaunched || !CheckMenuViewToggle(ImGuiKey_F1, m_isHidden);
|
||||
if (dusk::IsGameLaunched) {
|
||||
const bool menuOpen = !m_isHidden;
|
||||
if (getSettings().backend.duskMenuOpen != menuOpen) {
|
||||
getSettings().backend.duskMenuOpen.setValue(menuOpen);
|
||||
Save();
|
||||
}
|
||||
if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) {
|
||||
m_isHidden = !m_isHidden;
|
||||
}
|
||||
bool showMenu = !m_isHidden;
|
||||
if (getSettings().backend.duskMenuOpen != showMenu) {
|
||||
getSettings().backend.duskMenuOpen.setValue(showMenu);
|
||||
Save();
|
||||
}
|
||||
|
||||
// The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg,
|
||||
@@ -360,18 +361,31 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (dusk::IsGameLaunched && !m_isLaunchInitialized) {
|
||||
m_toasts.emplace_back(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
|
||||
AddToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
|
||||
"Tap to toggle menu"s :
|
||||
"Press F1 to toggle menu"s,
|
||||
2.5f);
|
||||
4.f);
|
||||
m_isLaunchInitialized = true;
|
||||
if (getSettings().game.liveSplitEnabled) {
|
||||
dusk::speedrun::connectLiveSplit();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateDragScroll();
|
||||
|
||||
m_menuGame.windowControllerConfig();
|
||||
m_menuGame.windowInputViewer();
|
||||
if (dusk::IsGameLaunched) {
|
||||
m_menuGame.drawSpeedrunTimerOverlay();
|
||||
|
||||
if (getSettings().game.liveSplitEnabled) {
|
||||
dusk::speedrun::updateLiveSplit();
|
||||
if (dusk::speedrun::consumeConnectedEvent())
|
||||
AddToast("LiveSplit connected");
|
||||
else if (dusk::speedrun::consumeDisconnectedEvent())
|
||||
AddToast("LiveSplit disconnected");
|
||||
}
|
||||
|
||||
if (dusk::IsGameLaunched && !dusk::getSettings().game.speedrunMode) {
|
||||
m_menuTools.ShowDebugOverlay();
|
||||
m_menuTools.ShowCameraOverlay();
|
||||
m_menuTools.ShowProcessManager();
|
||||
@@ -382,8 +396,8 @@ namespace dusk {
|
||||
m_menuTools.ShowPlayerInfo();
|
||||
m_menuTools.ShowAudioDebug();
|
||||
m_menuTools.ShowSaveEditor();
|
||||
m_menuTools.ShowStateShare();
|
||||
}
|
||||
m_menuTools.ShowStateShare();
|
||||
m_menuTools.ShowAchievements();
|
||||
DuskDebugPad(); // temporary, remove later
|
||||
|
||||
@@ -556,6 +570,10 @@ namespace dusk {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImGuiConsole::AddToast(std::string_view message, float duration) {
|
||||
m_toasts.emplace_back(std::string(message), duration);
|
||||
}
|
||||
|
||||
void ImGuiConsole::ShowToasts() {
|
||||
if (m_toasts.empty()) {
|
||||
return;
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
void PostDraw();
|
||||
|
||||
static bool CheckMenuViewToggle(ImGuiKey key, bool& active);
|
||||
void AddToast(std::string_view message, float duration = 3.f);
|
||||
|
||||
private:
|
||||
struct Toast {
|
||||
@@ -70,6 +71,7 @@ std::string BytesToString(size_t bytes);
|
||||
void SetOverlayWindowLocation(int corner);
|
||||
bool ShowCornerContextMenu(int& corner, int avoidCorner);
|
||||
void ImGuiStringViewText(std::string_view text);
|
||||
void DuskToast(std::string_view message, float duration = 3.f);
|
||||
void ImGuiBeginGroupPanel(const char* name, const ImVec2& size);
|
||||
void ImGuiEndGroupPanel();
|
||||
void ImGuiTextCenter(std::string_view text);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,7 @@ static void ApplyPresetHD() {
|
||||
s.game.biggerWallets.setValue(true);
|
||||
s.game.invertCameraXAxis.setValue(true);
|
||||
s.game.freeCamera.setValue(true);
|
||||
s.game.no2ndFishForCat.setValue(true);
|
||||
}
|
||||
|
||||
static void ApplyPresetDusk() {
|
||||
@@ -43,6 +44,7 @@ static void ApplyPresetDusk() {
|
||||
s.game.enableFrameInterpolation.setValue(true);
|
||||
s.game.sunsSong.setValue(true);
|
||||
s.game.bloomMode.setValue(BloomMode::Dusk);
|
||||
s.game.autoSave.setValue(true);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
@@ -180,9 +180,9 @@ namespace dusk {
|
||||
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) {
|
||||
char title[128];
|
||||
const char* name = data.Safe ? heap->getName() : "INVALID";
|
||||
snprintf(title, sizeof(title), "Heap %s##%p", heap->getName(), static_cast<const void*>(heap));
|
||||
snprintf(title, sizeof(title), "Heap %s##%p", name, static_cast<const void*>(heap));
|
||||
|
||||
if (!ImGui::Begin(name, &open)) {
|
||||
if (!ImGui::Begin(title, &open)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
@@ -195,7 +195,7 @@ namespace dusk {
|
||||
|
||||
heap->lock();
|
||||
|
||||
ImGui::Text("Name: %s", heap->getName());
|
||||
ImGui::Text("Name: %s", name);
|
||||
const auto size = BytesToString(heap->getSize());
|
||||
const auto freeSize = BytesToString(heap->getFreeSize());
|
||||
ImGui::Text("Size: %08X (%s), free: %08X (%s)", heap->getSize(), size.c_str(), heap->getFreeSize(), freeSize.c_str());
|
||||
|
||||
+109
-437
@@ -3,29 +3,14 @@
|
||||
|
||||
#include "ImGuiEngine.hpp"
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuGame.hpp"
|
||||
#include "ImGuiConfig.hpp"
|
||||
|
||||
#include "JSystem/JUtility/JUTGamePad.h"
|
||||
#include "dusk/audio/DuskAudioSystem.h"
|
||||
#include "dusk/audio/DuskDsp.hpp"
|
||||
#include "dusk/main.h"
|
||||
#include "dusk/hotkeys.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
|
||||
#include <aurora/gfx.h>
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
|
||||
namespace {
|
||||
constexpr int kInternalResolutionScaleMax = 12;
|
||||
} // namespace
|
||||
|
||||
namespace aurora::gx {
|
||||
extern bool enableLodBias;
|
||||
}
|
||||
|
||||
namespace dusk {
|
||||
void ImGuiMenuGame::ToggleFullscreen() {
|
||||
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
|
||||
@@ -37,435 +22,17 @@ namespace dusk {
|
||||
|
||||
void ImGuiMenuGame::draw() {
|
||||
if (ImGui::BeginMenu("Settings")) {
|
||||
drawAudioMenu();
|
||||
drawCheatsMenu();
|
||||
drawGameplayMenu();
|
||||
drawGraphicsMenu();
|
||||
drawInputMenu();
|
||||
drawInterfaceMenu();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("Reset", hotkeys::DO_RESET)) {
|
||||
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
||||
}
|
||||
|
||||
if (!IsMobile && ImGui::MenuItem("Exit")) {
|
||||
dusk::IsRunning = false;
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::drawGraphicsMenu() {
|
||||
if (ImGui::BeginMenu("Graphics")) {
|
||||
ImGui::SeparatorText("Display");
|
||||
|
||||
if (!IsMobile) {
|
||||
if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) {
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Restore Default Window Size")) {
|
||||
getSettings().video.enableFullscreen.setValue(false);
|
||||
VISetWindowFullscreen(false);
|
||||
VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2);
|
||||
VICenterWindow();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
bool vsync = getSettings().video.enableVsync;
|
||||
if (ImGui::Checkbox("Enable VSync", &vsync)) {
|
||||
getSettings().video.enableVsync.setValue(vsync);
|
||||
aurora_enable_vsync(vsync);
|
||||
config::Save();
|
||||
}
|
||||
|
||||
bool lockAspect = getSettings().video.lockAspectRatio;
|
||||
if (ImGui::Checkbox("Force 4:3 Aspect Ratio", &lockAspect)) {
|
||||
getSettings().video.lockAspectRatio.setValue(lockAspect);
|
||||
|
||||
if (lockAspect) {
|
||||
AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT);
|
||||
} else {
|
||||
AuroraSetViewportPolicy(AURORA_VIEWPORT_STRETCH);
|
||||
}
|
||||
|
||||
config::Save();
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Resolution");
|
||||
|
||||
u32 internalResolutionWidth = 0;
|
||||
u32 internalResolutionHeight = 0;
|
||||
AuroraGetRenderSize(&internalResolutionWidth, &internalResolutionHeight);
|
||||
ImGui::TextDisabled("Current internal resolution: %ux%u", internalResolutionWidth,
|
||||
internalResolutionHeight);
|
||||
|
||||
int scale = std::clamp(getSettings().game.internalResolutionScale.getValue(), 0,
|
||||
kInternalResolutionScaleMax);
|
||||
if (ImGui::SliderInt("Internal Resolution", &scale, 0, kInternalResolutionScaleMax,
|
||||
scale == 0 ? "Auto" : "%dx"))
|
||||
{
|
||||
getSettings().game.internalResolutionScale.setValue(scale);
|
||||
VISetFrameBufferScale(static_cast<float>(scale));
|
||||
config::Save();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Auto renders at the native window resolution.\n"
|
||||
"Higher values scale the game's internal framebuffer.");
|
||||
}
|
||||
|
||||
config::ImGuiSliderInt("Shadow Resolution", getSettings().game.shadowResolutionMultiplier, 1, 8, "x%d");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Improves the shadow resolution, making them higher quality.");
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Post-Processing");
|
||||
|
||||
constexpr const char* bloomModeNames[] = {"Off", "Classic", "Dusk"};
|
||||
int bloomMode = static_cast<int>(getSettings().game.bloomMode.getValue());
|
||||
if (ImGui::BeginCombo("Bloom", bloomModeNames[bloomMode])) {
|
||||
for (int i = 0; i < IM_ARRAYSIZE(bloomModeNames); i++) {
|
||||
const bool selected = bloomMode == i;
|
||||
if (ImGui::Selectable(bloomModeNames[i], selected)) {
|
||||
getSettings().game.bloomMode.setValue(static_cast<BloomMode>(i));
|
||||
config::Save();
|
||||
}
|
||||
if (selected) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
bool bloomOff = bloomMode == static_cast<int>(BloomMode::Off);
|
||||
if (bloomOff) ImGui::BeginDisabled();
|
||||
float mult = getSettings().game.bloomMultiplier.getValue();
|
||||
if (ImGui::SliderFloat("Bloom Brightness", &mult, 0.0f, 1.0f, "%.2f")) {
|
||||
getSettings().game.bloomMultiplier.setValue(mult);
|
||||
config::Save();
|
||||
}
|
||||
if (bloomOff) ImGui::EndDisabled();
|
||||
|
||||
ImGui::SeparatorText("Rendering");
|
||||
|
||||
config::ImGuiCheckbox("Unlock Framerate", getSettings().game.enableFrameInterpolation);
|
||||
const bool frameInterpolationHovered = ImGui::IsItemHovered();
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.72f, 0.2f, 1.0f));
|
||||
ImGui::TextUnformatted("[EXPERIMENTAL]");
|
||||
ImGui::PopStyleColor();
|
||||
if (frameInterpolationHovered || ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Uses inter-frame interpolation to enable higher frame rates.\nVisual artifacts, animation glitches, or instability may occur.");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias);
|
||||
|
||||
config::ImGuiCheckbox("Enable Depth of Field", getSettings().game.enableDepthOfField);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::drawGameplayMenu() {
|
||||
if (ImGui::BeginMenu("Gameplay")) {
|
||||
ImGui::SeparatorText("General");
|
||||
|
||||
config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Mirrors the world horizontally, matching the Wii version of the game.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Disable Main HUD", getSettings().game.disableMainHUD);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Disables the main HUD of the game.\n"
|
||||
"Useful for recording or a more immersive experience!");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n"
|
||||
"the first released version.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Enables rotating Link in the collection menu with the C-Stick");
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Difficulty");
|
||||
|
||||
config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d");
|
||||
|
||||
config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Any hit will instantly kill you.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Heart Drops", getSettings().game.noHeartDrops);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Hearts will never drop from enemies,\n"
|
||||
"pots and various other places.");
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Quality of Life");
|
||||
|
||||
config::ImGuiCheckbox("Bigger Wallets", getSettings().game.biggerWallets);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Wallet sizes are like in the HD version. (500, 1000, 2000)");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Disable Rupee Cutscenes", getSettings().game.disableRupeeCutscenes);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Rupees won't play cutscenes after you've collected them the first time.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Faster Climbing", getSettings().game.fastClimbing);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Faster Tears of Light", getSettings().game.fastTears);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Instant Saves", getSettings().game.instantSaves);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Skip the delay when writing to the Memory Card.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Hold B for Instant Text", getSettings().game.instantText);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Make text scroll immediately by holding B.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Climbing Miss Animation", getSettings().game.noMissClimbing);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Prevents Link from playing a struggle animation\n"
|
||||
"when grabbing ledges or climbing on vines.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Rupee Returns", getSettings().game.noReturnRupees);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Link won't recoil when his sword hits walls.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Skip Warning Screen", getSettings().game.skipWarningScreen);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Skip the warning screen shown when starting the game.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Sun's Song (R+X)", getSettings().game.sunsSong);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Allows Wolf Link to howl and change the time of day.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::drawCheatsMenu() {
|
||||
if (ImGui::BeginMenu("Cheats")) {
|
||||
ImGui::SeparatorText("Resources");
|
||||
config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts);
|
||||
config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows);
|
||||
config::ImGuiCheckbox("Infinite Bombs", getSettings().game.infiniteBombs);
|
||||
config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil);
|
||||
config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen);
|
||||
config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees);
|
||||
config::ImGuiCheckbox("Items Don't Despawn", getSettings().game.enableIndefiniteItemDrops);
|
||||
ImGui::SetItemTooltip("Items Don't Despawn Unless You Load A Different Room In Which Case They Do But Even Under Some Circumstances They Don't, It Is Quite Rare Though");
|
||||
|
||||
ImGui::SeparatorText("Abilities");
|
||||
config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump);
|
||||
config::ImGuiCheckbox("Super Clawshot", getSettings().game.superClawshot);
|
||||
config::ImGuiCheckbox("Always Greatspin", getSettings().game.alwaysGreatspin);
|
||||
config::ImGuiCheckbox("Fast Iron Boots", getSettings().game.enableFastIronBoots);
|
||||
|
||||
config::ImGuiCheckbox("Can Transform Anywhere", getSettings().game.canTransformAnywhere);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Allows you to transform even if NPCs are looking.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Fast Spinner", getSettings().game.fastSpinner);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Speeds up Spinner movement when holding R.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Free Magic Armor", getSettings().game.freeMagicArmor);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Makes the magic armor work without rupees.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::drawAudioMenu() {
|
||||
if (ImGui::BeginMenu("Audio")) {
|
||||
|
||||
ImGui::SeparatorText("Volume");
|
||||
|
||||
ImGui::Text("Master Volume");
|
||||
if (config::ImGuiSliderInt("##masterVolume", getSettings().audio.masterVolume, 0, 100)) {
|
||||
dusk::audio::SetMasterVolume(getSettings().audio.masterVolume / 100.0f);
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: Implement additional settings
|
||||
ImGui::Text("Main Music Volume");
|
||||
ImGui::SliderFloat("##mainMusicVolume", &getSettings().audio.mainMusicVolume, 0, 100);
|
||||
|
||||
ImGui::Text("Sub Music Volume");
|
||||
ImGui::SliderFloat("##subMusicVolume", &getSettings().audio.subMusicVolume, 0, 100);
|
||||
|
||||
ImGui::Text("Sound Effects Volume");
|
||||
ImGui::SliderFloat("##soundEffectsVolume", &getSettings().audio.soundEffectsVolume, 0, 100);
|
||||
|
||||
ImGui::Text("Fanfare Volume");
|
||||
ImGui::SliderFloat("##fanfareVolume", &getSettings().audio.fanfareVolume, 0, 100);
|
||||
|
||||
Z2AudioMgr* audioMgr = Z2AudioMgr::getInterface();
|
||||
if (audioMgr != nullptr) {
|
||||
}
|
||||
*/
|
||||
|
||||
ImGui::SeparatorText("Effects");
|
||||
|
||||
if (config::ImGuiCheckbox("Enable Reverb", getSettings().audio.enableReverb)) {
|
||||
dusk::audio::SetEnableReverb(getSettings().audio.enableReverb);
|
||||
}
|
||||
|
||||
|
||||
ImGui::SeparatorText("Tweaks");
|
||||
|
||||
config::ImGuiCheckbox("No Low HP Sound", getSettings().game.noLowHpSound);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Disable the beeping sound when having low health.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Non-Stop Midna's Lament", getSettings().game.midnasLamentNonStop);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing.");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::drawInputMenu() {
|
||||
if (ImGui::BeginMenu("Input")) {
|
||||
ImGui::SeparatorText("Controller");
|
||||
|
||||
// TODO: Remove this once Controller Config exists in RmlUi
|
||||
if (ImGui::Button("Configure Controller")){
|
||||
m_showControllerConfig = !m_showControllerConfig;
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Camera");
|
||||
|
||||
config::ImGuiCheckbox("Free Camera", getSettings().game.freeCamera);
|
||||
|
||||
if (getSettings().game.freeCamera) {
|
||||
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
|
||||
config::ImGuiCheckbox("Invert Camera Y Axis", getSettings().game.invertCameraYAxis);
|
||||
config::ImGuiSliderFloat("Free Camera Sensitivity", getSettings().game.freeCameraSensitivity, 0.5f, 2.0f, "%.1f");
|
||||
} else {
|
||||
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Gyro");
|
||||
|
||||
config::ImGuiCheckbox("Gyro Aim", getSettings().game.enableGyroAim);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Enables the gyroscope on supported controllers\n"
|
||||
"while in look mode (C-Up) and while aiming the\n"
|
||||
"Slingshot, Gale Boomerang, Hero's Bow, Clawshot(s),\n"
|
||||
"Ball and Chain, and Dominion Rod.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Gyro Rollgoal", getSettings().game.enableGyroRollgoal);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Enables the gyroscope on supported controllers to\n"
|
||||
"tilt the Rollgoal table in Hena's Cabin.");
|
||||
}
|
||||
|
||||
if (getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal) {
|
||||
config::ImGuiSliderFloat("Gyro Pitch Sensitivity", getSettings().game.gyroSensitivityY, 0.25f, 4.0f, "%.2f");
|
||||
config::ImGuiSliderFloat("Gyro Yaw Sensitivity", getSettings().game.gyroSensitivityX, 0.25f, 4.0f, "%.2f");
|
||||
|
||||
if (getSettings().game.enableGyroRollgoal) {
|
||||
config::ImGuiSliderFloat("Rollgoal Sensitivity", getSettings().game.gyroSensitivityRollgoal, 0.25f, 4.0f, "%.2f");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Additional multiplier for scaling how strongly\n"
|
||||
"the gyroscope affects the Rollgoal table.");
|
||||
}
|
||||
}
|
||||
|
||||
config::ImGuiSliderFloat("Gyro Deadband", getSettings().game.gyroDeadband, 0.0f, 0.5f, "%.3f");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Angular rates below this magnitude are treated as zero,\n"
|
||||
"reducing drift and jitter when the controller is still.");
|
||||
}
|
||||
|
||||
config::ImGuiSliderFloat("Gyro Smoothing", getSettings().game.gyroSmoothing, 0.0f, 1.0f, "%.2f");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Low values track raw gyro input more closely,\n"
|
||||
"while higher values smooth out input over time.");
|
||||
}
|
||||
|
||||
config::ImGuiCheckbox("Invert Gyro Pitch", getSettings().game.gyroInvertPitch);
|
||||
config::ImGuiCheckbox("Invert Gyro Yaw", getSettings().game.gyroInvertYaw);
|
||||
}
|
||||
|
||||
ImGui::SeparatorText("Tools");
|
||||
|
||||
config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x.");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::drawInterfaceMenu() {
|
||||
if (ImGui::BeginMenu("Interface")) {
|
||||
config::ImGuiCheckbox("Achievement Notifications", getSettings().game.enableAchievementNotifications);
|
||||
config::ImGuiCheckbox("Skip Pre-Launch UI", getSettings().backend.skipPreLaunchUI);
|
||||
config::ImGuiCheckbox("Show Pipeline Compilation", getSettings().backend.showPipelineCompilation);
|
||||
#if DUSK_ENABLE_SENTRY_NATIVE
|
||||
config::ImGuiCheckbox("Enable Crash Reporting", getSettings().backend.enableCrashReporting);
|
||||
#endif
|
||||
if (!IsMobile) {
|
||||
config::ImGuiCheckbox("Pause on Focus Lost", getSettings().game.pauseOnFocusLost);
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
static void drawVirtualStick(const char* id, const ImVec2& stick) {
|
||||
float scale = ImGuiScale();
|
||||
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10));
|
||||
@@ -965,7 +532,7 @@ namespace dusk {
|
||||
ImGui::SameLine();
|
||||
|
||||
// Options panel
|
||||
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale));
|
||||
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1));
|
||||
|
||||
if (deadZones != nullptr) {
|
||||
if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) {
|
||||
@@ -975,9 +542,114 @@ namespace dusk {
|
||||
PADSerializeMappings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) {
|
||||
ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1));
|
||||
u16 low;
|
||||
u16 high;
|
||||
(void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high);
|
||||
float fLow = (static_cast<float>(low) / 32767.f) * 100.f;
|
||||
bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%");
|
||||
float fHigh = (static_cast<float>(high) / 32767.f) * 100.f;
|
||||
changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%");
|
||||
if (changed) {
|
||||
PADSetRumbleIntensity(m_controllerConfig.m_selectedPort,
|
||||
static_cast<u16>((fLow / 100) * 32767),
|
||||
static_cast<u16>((fHigh / 100) * 32767));
|
||||
PADSerializeMappings();
|
||||
}
|
||||
if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) {
|
||||
PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD);
|
||||
m_controllerConfig.m_isRumbling ^= 1;
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
static std::string GetFormattedTime(OSTime ticks) {
|
||||
OSCalendarTime time;
|
||||
OSTicksToCalendarTime(ticks, &time);
|
||||
|
||||
return fmt::format("{0:02}:{1:02}:{2:02}.{3:03}", time.hour, time.min, time.sec, time.msec);
|
||||
}
|
||||
|
||||
void ImGuiMenuGame::resetForSpeedrunMode() {
|
||||
// reset settings that should be off for speedrun mode
|
||||
mDoMain::developmentMode = -1;
|
||||
|
||||
getSettings().game.damageMultiplier.setValue(1);
|
||||
getSettings().game.instantDeath.setValue(false);
|
||||
getSettings().game.noHeartDrops.setValue(false);
|
||||
|
||||
getSettings().game.infiniteHearts.setValue(false);
|
||||
getSettings().game.infiniteArrows.setValue(false);
|
||||
getSettings().game.infiniteBombs.setValue(false);
|
||||
getSettings().game.infiniteOil.setValue(false);
|
||||
getSettings().game.infiniteOxygen.setValue(false);
|
||||
getSettings().game.infiniteRupees.setValue(false);
|
||||
getSettings().game.enableIndefiniteItemDrops.setValue(false);
|
||||
|
||||
getSettings().game.moonJump.setValue(false);
|
||||
getSettings().game.superClawshot.setValue(false);
|
||||
getSettings().game.alwaysGreatspin.setValue(false);
|
||||
getSettings().game.enableFastIronBoots.setValue(false);
|
||||
getSettings().game.canTransformAnywhere.setValue(false);
|
||||
getSettings().game.fastSpinner.setValue(false);
|
||||
getSettings().game.freeMagicArmor.setValue(false);
|
||||
|
||||
getSettings().game.enableTurboKeybind.setValue(false);
|
||||
}
|
||||
|
||||
SpeedrunInfo m_speedrunInfo;
|
||||
|
||||
void ImGuiMenuGame::drawSpeedrunTimerOverlay() {
|
||||
if (!getSettings().game.speedrunMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// L+R+A+Start to reset timer
|
||||
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigStart(PAD_1)) {
|
||||
m_speedrunInfo.reset();
|
||||
}
|
||||
|
||||
// L+R+A+Z to manually stop timer
|
||||
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1)) {
|
||||
if (m_speedrunInfo.m_isRunStarted) {
|
||||
m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp;
|
||||
m_speedrunInfo.m_isRunStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowBgAlpha(0.65f);
|
||||
ImGuiWindowFlags flags =
|
||||
ImGuiWindowFlags_NoResize
|
||||
| ImGuiWindowFlags_NoDocking
|
||||
| ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoScrollbar;
|
||||
|
||||
if (ImGui::Begin("##SpeedrunTimerWindow", nullptr, flags)) {
|
||||
OSTime elapsedTime = 0;
|
||||
if (m_speedrunInfo.m_isRunStarted) {
|
||||
elapsedTime = OSGetTime() - m_speedrunInfo.m_startTimestamp;
|
||||
} else if (m_speedrunInfo.m_endTimestamp != 0) {
|
||||
elapsedTime = m_speedrunInfo.m_endTimestamp;
|
||||
}
|
||||
|
||||
ImGui::Text("RTA");
|
||||
ImGui::SameLine(60.0f);
|
||||
ImGuiStringViewText(GetFormattedTime(elapsedTime));
|
||||
|
||||
if (!m_speedrunInfo.m_isPauseIGT) {
|
||||
m_speedrunInfo.m_igtTimer = elapsedTime - m_speedrunInfo.m_totalLoadTime;
|
||||
}
|
||||
|
||||
ImGui::Text("IGT");
|
||||
ImGui::SameLine(60.0f);
|
||||
ImGuiStringViewText(GetFormattedTime(m_speedrunInfo.m_igtTimer));
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,39 @@
|
||||
#include "imgui.h"
|
||||
|
||||
namespace dusk {
|
||||
struct SpeedrunInfo {
|
||||
void startRun() {
|
||||
m_isRunStarted = true;
|
||||
m_startTimestamp = OSGetTime();
|
||||
}
|
||||
|
||||
void stopRun() {
|
||||
m_isRunStarted = false;
|
||||
m_endTimestamp = OSGetTime() - m_startTimestamp;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_isRunStarted = false;
|
||||
m_startTimestamp = 0;
|
||||
m_endTimestamp = 0;
|
||||
m_isPauseIGT = false;
|
||||
m_loadStartTimestamp = 0;
|
||||
m_totalLoadTime = 0;
|
||||
m_igtTimer = 0;
|
||||
}
|
||||
|
||||
bool m_isRunStarted = false;
|
||||
OSTime m_startTimestamp = 0;
|
||||
OSTime m_endTimestamp = 0;
|
||||
|
||||
bool m_isPauseIGT = false;
|
||||
OSTime m_loadStartTimestamp = 0;
|
||||
OSTime m_totalLoadTime = 0;
|
||||
OSTime m_igtTimer = 0;
|
||||
};
|
||||
|
||||
extern SpeedrunInfo m_speedrunInfo;
|
||||
|
||||
class ImGuiMenuGame {
|
||||
public:
|
||||
ImGuiMenuGame();
|
||||
@@ -15,23 +48,20 @@ namespace dusk {
|
||||
|
||||
void windowInputViewer();
|
||||
void windowControllerConfig();
|
||||
void drawSpeedrunTimerOverlay();
|
||||
|
||||
static void ToggleFullscreen();
|
||||
|
||||
private:
|
||||
void drawAudioMenu();
|
||||
void drawInputMenu();
|
||||
void drawGraphicsMenu();
|
||||
void drawGameplayMenu();
|
||||
void drawCheatsMenu();
|
||||
void drawInterfaceMenu();
|
||||
static void resetForSpeedrunMode();
|
||||
|
||||
private:
|
||||
struct {
|
||||
int m_selectedPort = 0;
|
||||
bool m_isReading = false;
|
||||
PADButtonMapping* m_pendingButtonMapping = nullptr;
|
||||
PADAxisMapping* m_pendingAxisMapping = nullptr;
|
||||
int m_pendingPort = -1;
|
||||
bool m_isRumbling = false;
|
||||
} m_controllerConfig;
|
||||
|
||||
bool m_showControllerConfig = false;
|
||||
@@ -40,6 +70,8 @@ namespace dusk {
|
||||
bool m_showInputViewerGyro = false;
|
||||
int m_inputOverlayCorner = 3;
|
||||
std::string m_controllerName;
|
||||
|
||||
bool m_showTimerWindow = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@ static void OpenDataFolder() {
|
||||
#define DUSK_CAN_OPEN_DATA_FOLDER 0
|
||||
#endif
|
||||
|
||||
namespace aurora::gx {
|
||||
extern bool enableLodBias;
|
||||
}
|
||||
|
||||
namespace dusk {
|
||||
ImGuiMenuTools::ImGuiMenuTools() {}
|
||||
|
||||
@@ -50,10 +54,14 @@ namespace dusk {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
|
||||
ImGui::BeginDisabled(getSettings().game.speedrunMode);
|
||||
|
||||
ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor);
|
||||
ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader);
|
||||
ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare);
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (!dusk::IsGameLaunched) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
@@ -71,6 +79,8 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Debug")) {
|
||||
ImGui::BeginDisabled(getSettings().game.speedrunMode);
|
||||
|
||||
bool developmentMode = mDoMain::developmentMode == 1;
|
||||
if (ImGui::Checkbox("Development Mode", &developmentMode)) {
|
||||
mDoMain::developmentMode = developmentMode ? 1 : -1;
|
||||
@@ -85,6 +95,7 @@ namespace dusk {
|
||||
getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction);
|
||||
config::Save();
|
||||
}
|
||||
ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@@ -119,6 +130,9 @@ namespace dusk {
|
||||
}
|
||||
|
||||
ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable);
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ void fileDialogCallback(void* userdata, const char* path, const char* error) {
|
||||
}
|
||||
|
||||
self->m_selectedIsoPath = path;
|
||||
self->m_isPal = iso::isPal(path);
|
||||
getSettings().backend.isoPath.setValue(self->m_selectedIsoPath);
|
||||
config::Save();
|
||||
}
|
||||
@@ -92,6 +93,7 @@ bool ImGuiPreLaunchWindow::isSelectedPathValid() const {
|
||||
void ImGuiPreLaunchWindow::draw() {
|
||||
if (m_IsFirstDraw) {
|
||||
m_selectedIsoPath = getSettings().backend.isoPath;
|
||||
m_isPal = !m_selectedIsoPath.empty() && iso::isPal(m_selectedIsoPath.c_str());
|
||||
m_initialGraphicsBackend = getSettings().backend.graphicsBackend;
|
||||
m_IsFirstDraw = false;
|
||||
}
|
||||
@@ -193,24 +195,24 @@ void ImGuiPreLaunchWindow::drawOptions() {
|
||||
|
||||
ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set")) {
|
||||
if (ImGui::Button(m_selectedIsoPath == "" ? "Set" : "Change")) {
|
||||
ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(),
|
||||
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr,
|
||||
false);
|
||||
}
|
||||
|
||||
// TODO: Only show if PAL disc selected?
|
||||
// Language selection
|
||||
auto selectedLanguage = getSettings().game.language.getValue();
|
||||
if (ImGui::BeginCombo("Language", skLanguageNames[static_cast<u8>(selectedLanguage)])) {
|
||||
for (u8 i = 0; i < skLanguageNames.size(); ++i) {
|
||||
if (ImGui::Selectable(skLanguageNames[i])) {
|
||||
getSettings().game.language.setValue(static_cast<GameLanguage>(i));
|
||||
config::Save();
|
||||
if (m_isPal) {
|
||||
auto selectedLanguage = getSettings().game.language.getValue();
|
||||
if (ImGui::BeginCombo("Language", skLanguageNames[static_cast<u8>(selectedLanguage)])) {
|
||||
for (u8 i = 0; i < skLanguageNames.size(); ++i) {
|
||||
if (ImGui::Selectable(skLanguageNames[i])) {
|
||||
getSettings().game.language.setValue(static_cast<GameLanguage>(i));
|
||||
config::Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
AuroraBackend configuredBackend = BACKEND_AUTO;
|
||||
|
||||
@@ -18,5 +18,6 @@ public:
|
||||
|
||||
std::string m_selectedIsoPath;
|
||||
std::string m_errorString;
|
||||
bool m_isPal = false;
|
||||
};
|
||||
} // namespace dusk
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "d/actor/d_a_player.h"
|
||||
|
||||
#include <map>
|
||||
#include <bit>
|
||||
|
||||
namespace dusk {
|
||||
enum ItemType {
|
||||
@@ -1295,8 +1296,33 @@ namespace dusk {
|
||||
membit.offDungeonItem(flag);
|
||||
}
|
||||
}
|
||||
|
||||
static void genCommonAreaFlags(dSv_memBit_c& membit) {
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
|
||||
|
||||
void genMembitFlags(const char* id, dSv_memBit_c& membit) {
|
||||
genDungeonItemCheckbox(membit, "Got Map", dSv_memBit_c::MAP);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Got Compass", dSv_memBit_c::COMPASS);
|
||||
|
||||
genDungeonItemCheckbox(membit, "Got Boss Key", dSv_memBit_c::BOSS_KEY);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Saw Boss Demo", dSv_memBit_c::STAGE_BOSS_DEMO);
|
||||
|
||||
genDungeonItemCheckbox(membit, "Got Heart Container", dSv_memBit_c::STAGE_LIFE);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Defeated Boss", dSv_memBit_c::STAGE_BOSS_ENEMY);
|
||||
|
||||
genDungeonItemCheckbox(membit, "Defeated Miniboss", dSv_memBit_c::STAGE_BOSS_ENEMY_2);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Got Ooccoo", dSv_memBit_c::OOCCOO_NOTE);
|
||||
|
||||
int keyTemp = membit.getKeyNum();
|
||||
if (ImGui::SliderInt("Keys", &keyTemp, 0, 5)) {
|
||||
membit.setKeyNum(keyTemp);
|
||||
}
|
||||
}
|
||||
|
||||
static void genMembitFlags(const char* id, dSv_memBit_c& membit) {
|
||||
ImGuiBeginGroupPanel("Chest", { 100, 100 });
|
||||
for (int j = 0; j < 2; j++) {
|
||||
drawFlagList(fmt::format("##_tbox{}", j).c_str(), membit.mTbox[j]);
|
||||
@@ -1322,29 +1348,10 @@ namespace dusk {
|
||||
drawFlagList(fmt::format("##_item{}", j).c_str(), membit.mItem[j]);
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
ImVec2 post_item_custor = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
|
||||
|
||||
genDungeonItemCheckbox(membit, "Got Map", dSv_memBit_c::MAP);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Got Compass", dSv_memBit_c::COMPASS);
|
||||
|
||||
genDungeonItemCheckbox(membit, "Got Boss Key", dSv_memBit_c::BOSS_KEY);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Saw Boss Demo", dSv_memBit_c::STAGE_BOSS_DEMO);
|
||||
|
||||
genDungeonItemCheckbox(membit, "Got Heart Container", dSv_memBit_c::STAGE_LIFE);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Defeated Boss", dSv_memBit_c::STAGE_BOSS_ENEMY);
|
||||
|
||||
genDungeonItemCheckbox(membit, "Defeated Miniboss", dSv_memBit_c::STAGE_BOSS_ENEMY_2);
|
||||
ImGui::SameLine(230.0f);
|
||||
genDungeonItemCheckbox(membit, "Got Ooccoo", dSv_memBit_c::OOCCOO_NOTE);
|
||||
|
||||
int keyTemp = membit.getKeyNum();
|
||||
if (ImGui::SliderInt("Keys", &keyTemp, 0, 5)) {
|
||||
membit.setKeyNum(keyTemp);
|
||||
}
|
||||
ImGui::SetCursorPos({post_item_custor.x, post_switch_cursor.y});
|
||||
// genCommonAreaFlags(membit);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -1392,74 +1399,326 @@ namespace dusk {
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiSaveEditor::drawFlagsTab() {
|
||||
if (ImGui::TreeNode("Current Region Flags")) {
|
||||
dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit;
|
||||
genMembitFlags("##TempSceneFlags", membit);
|
||||
|
||||
static void genAreaFlagTable(uint8_t areaIndex, dSv_memBit_c& membit) {
|
||||
constexpr auto makeMask = [](uint8_t size) -> uint16_t { return (1 << size) - 1; };
|
||||
constexpr auto getByteIndexFromFlag = [](uint16_t f) -> uint8_t { return f >> 8; };
|
||||
constexpr auto getBitMaskFromFlag = [](uint16_t f) -> uint8_t { return f & 0xff; };
|
||||
constexpr auto getValueSize = [getBitMaskFromFlag](uint16_t f) -> uint8_t {
|
||||
return std::popcount(getBitMaskFromFlag(f));
|
||||
};
|
||||
|
||||
constexpr auto makeEventFlag = [](uint8_t byteIndex, uint8_t bitIndices) -> uint16_t {
|
||||
return (byteIndex << 8) | bitIndices;
|
||||
};
|
||||
|
||||
stage_stag_info_class* pstag = dComIfGp_getStageStagInfo();
|
||||
if (pstag != nullptr) {
|
||||
int stageNo = dStage_stagInfo_GetSaveTbl(pstag);
|
||||
if (ImGui::Button("Save##SaveTempFlags")) {
|
||||
dComIfGs_putSave(stageNo);
|
||||
const auto eventFlagToAreaFlag = [&](uint16_t areaFlag) -> int {
|
||||
auto byteInd = getByteIndexFromFlag(areaFlag);
|
||||
constexpr size_t areaIndexSize = 5;
|
||||
// if we're looking at 0x580, that would be byte 5, and check if 0x80 is set on that byte
|
||||
// the event flags are structured differently than area flags
|
||||
// B is byte index, b is the flag mask to check
|
||||
// event flags are BBBBBBBB bbbbbbbb
|
||||
// for area flags, they check bitIndex, not mask, i is index
|
||||
// also area uses u32 index, not byte index
|
||||
// area flags are BBBiiiii
|
||||
// so we need to convert from bit mask to index
|
||||
// also our byte index has to become a u32 index
|
||||
|
||||
// dividing byte index by sizeof(u32) gets us the u32 index
|
||||
// but in big endian, the first byte is the highest order byte of the u32
|
||||
// so we skip 24 bytes for the first byte, 16 for the second, etc
|
||||
// essentially (3 - (x % 4)), reversing the modulus, 0=3, 1=2
|
||||
auto bitsToSkip = 8 * ((sizeof(u32) - 1) - (byteInd % sizeof(u32)));
|
||||
return ((byteInd / sizeof(u32)) << areaIndexSize) | ((std::countr_zero(areaFlag) + bitsToSkip) & makeMask(areaIndexSize));
|
||||
};
|
||||
|
||||
constexpr uint8_t validTbox = sizeof(membit.mTbox);
|
||||
constexpr uint8_t validSwitch = validTbox + sizeof(membit.mSwitch);
|
||||
constexpr uint8_t validItem = validSwitch + sizeof(membit.mItem);
|
||||
constexpr uint16_t tboxConvert = 0;
|
||||
constexpr uint16_t switchConvert = sizeof(membit.mTbox) << 8;
|
||||
constexpr uint16_t itemConvert = switchConvert + (sizeof(membit.mItem) << 8);
|
||||
|
||||
const auto LoadFlag = [&](uint16_t flag) -> bool {
|
||||
const auto byteIndex = getByteIndexFromFlag(flag);
|
||||
|
||||
if (byteIndex < validTbox) {
|
||||
return membit.isTbox(eventFlagToAreaFlag(flag - tboxConvert));
|
||||
} else if (byteIndex < validSwitch) {
|
||||
return membit.isSwitch(eventFlagToAreaFlag(flag - switchConvert));
|
||||
} else if (byteIndex < validItem) {
|
||||
return membit.isItem(eventFlagToAreaFlag(flag - itemConvert));
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto SetFlag = [&](uint16_t flag, bool set) -> void {
|
||||
const auto byteIndex = getByteIndexFromFlag(flag);
|
||||
if (set) {
|
||||
if (byteIndex < validTbox) {
|
||||
membit.onTbox(eventFlagToAreaFlag(flag - tboxConvert));
|
||||
} else if (byteIndex < validSwitch) {
|
||||
membit.onSwitch(eventFlagToAreaFlag(flag - switchConvert));
|
||||
} else if (byteIndex < validItem) {
|
||||
membit.onItem(eventFlagToAreaFlag(flag - itemConvert));
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Load##LoadSaveFlags")) {
|
||||
dComIfGs_getSave(stageNo);
|
||||
} else {
|
||||
if (byteIndex < validTbox) {
|
||||
membit.offTbox(eventFlagToAreaFlag(flag - tboxConvert));
|
||||
} else if (byteIndex < validSwitch) {
|
||||
membit.offSwitch(eventFlagToAreaFlag(flag - switchConvert));
|
||||
} else if (byteIndex < validItem) {
|
||||
membit.offItem(eventFlagToAreaFlag(flag - itemConvert));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const auto LoadMultiByteFlag = [&](uint16_t flag) -> uint8_t {
|
||||
const auto bitInds = getBitMaskFromFlag(flag);
|
||||
const auto byteIndex = getByteIndexFromFlag(flag);
|
||||
|
||||
const uint16_t startingMask = std::bit_floor(bitInds);
|
||||
uint8_t val = 0;
|
||||
for (uint16_t bitIndexMask = startingMask; (bitInds & bitIndexMask) != 0;
|
||||
bitIndexMask >>= 1)
|
||||
{
|
||||
val <<= 1;
|
||||
if (LoadFlag(makeEventFlag(byteIndex, bitInds & bitIndexMask))) {
|
||||
val |= 1;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
const auto SetMultiByteFlag = [&](uint16_t flag, uint8_t val) -> void {
|
||||
const auto bitInds = getBitMaskFromFlag(flag);
|
||||
const auto byteIndex = getByteIndexFromFlag(flag);
|
||||
|
||||
const uint16_t startingMask = std::bit_floor(bitInds);
|
||||
uint16_t valueMask = 1 << (getValueSize(flag) - 1);
|
||||
|
||||
for (uint16_t bitIndexMask = startingMask; (bitInds & bitIndexMask) != 0;
|
||||
bitIndexMask >>= 1, valueMask >>= 1)
|
||||
{
|
||||
SetFlag(makeEventFlag(byteIndex, bitInds & bitIndexMask), (val & valueMask) != 0);
|
||||
}
|
||||
};
|
||||
|
||||
const auto LoadSpreadMultiByte = [&](uint16_t high, uint16_t low) -> uint8_t {
|
||||
if (low == AREA_FLAG_NONE)
|
||||
return LoadMultiByteFlag(high);
|
||||
return (LoadMultiByteFlag(high) << getValueSize(low)) | LoadMultiByteFlag(low);
|
||||
};
|
||||
|
||||
const auto SetSpreadMultiByte = [&](uint16_t high, uint16_t low, uint8_t value) -> void {
|
||||
if (low == AREA_FLAG_NONE)
|
||||
return SetMultiByteFlag(high, value);
|
||||
const auto lowerSize = getValueSize(low);
|
||||
SetMultiByteFlag(high, value >> lowerSize);
|
||||
SetMultiByteFlag(low, value & makeMask(lowerSize));
|
||||
};
|
||||
|
||||
auto iter = imguiAreaFlagLookup.find(areaIndex);
|
||||
if (iter == imguiAreaFlagLookup.end()) return;
|
||||
|
||||
auto& areaFlags = iter->second;
|
||||
|
||||
static ImGuiTextFilter filter;
|
||||
filter.Draw(); // Search bar
|
||||
|
||||
ImVec2 flagTableSize = {700, 400};
|
||||
if (ImGui::BeginTable("Area Flags", 3,
|
||||
ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX |
|
||||
ImGuiTableFlags_Sortable,
|
||||
flagTableSize))
|
||||
{
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
constexpr int COLUMN_FLAG = 0, COLUMN_BIT = 1, COLUMN_DESC = 2;
|
||||
ImGui::TableSetupColumn("Flag");
|
||||
ImGui::TableSetupColumn("Byte:Bit");
|
||||
ImGui::TableSetupColumn("Description");
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
// if we're sorting by whether the flag is set or not,
|
||||
// we want to re-sort whenever a flag updates, which means every frame cuz we don't
|
||||
// know when it changes. otherwise only re-sort when the sort is dirty
|
||||
if (auto* sort = ImGui::TableGetSortSpecs();
|
||||
sort != nullptr && sort->SpecsCount > 0 &&
|
||||
(sort->SpecsDirty || sort->Specs[0].ColumnIndex == COLUMN_FLAG))
|
||||
{
|
||||
const auto column = sort->Specs[0].ColumnIndex;
|
||||
const auto direction = sort->Specs[0].SortDirection;
|
||||
|
||||
// if we're sorting by flags, do special sort, regular sort is bad for sorting
|
||||
// bools it can swap values that are the same, and that causes constant
|
||||
// reordering
|
||||
if (column == COLUMN_FLAG) {
|
||||
if (direction == ImGuiSortDirection_Ascending) {
|
||||
sortByFlags(std::begin(areaFlags.bitFlags), std::end(areaFlags.bitFlags),
|
||||
LoadFlag);
|
||||
} else {
|
||||
sortByFlags(std::rbegin(areaFlags.bitFlags), std::rend(areaFlags.bitFlags),
|
||||
LoadFlag);
|
||||
}
|
||||
} else {
|
||||
const auto cmp = [column](const EventAreaFlags& l,
|
||||
const EventAreaFlags& r) -> bool {
|
||||
switch (column) {
|
||||
case COLUMN_DESC:
|
||||
return l.description < r.description;
|
||||
case COLUMN_BIT:
|
||||
return l.flagID < r.flagID;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (direction == ImGuiSortDirection_Ascending) {
|
||||
std::sort(std::begin(areaFlags.bitFlags), std::end(areaFlags.bitFlags),
|
||||
cmp);
|
||||
} else {
|
||||
std::sort(std::rbegin(areaFlags.bitFlags), std::rend(areaFlags.bitFlags),
|
||||
cmp);
|
||||
}
|
||||
}
|
||||
|
||||
sort->SpecsDirty = false;
|
||||
}
|
||||
|
||||
for (const auto& e : areaFlags.bitFlags) {
|
||||
std::string formattedBitLocation =
|
||||
fmt::format("{0:02X}:{1:02X}", e.byteIndex, e.bitIndex);
|
||||
|
||||
if (!filter.PassFilter(e.description.c_str()) &&
|
||||
!filter.PassFilter(formattedBitLocation.c_str()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
bool flag = LoadFlag(e.flagID);
|
||||
if (ImGui::Checkbox(fmt::format("##_unused_area_flag_{}", e.flagID).c_str(), &flag)) {
|
||||
SetFlag(e.flagID, flag);
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(formattedBitLocation.c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(e.description.c_str());
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
for (const auto& multiByteFlag : areaFlags.multibyteFlags) {
|
||||
auto flagValue = LoadSpreadMultiByte(multiByteFlag.highOrderflag, multiByteFlag.lowOrderflag);
|
||||
|
||||
const char* currentVal = "UNKNOWN";
|
||||
|
||||
auto enumValIter = multiByteFlag.enumValues.find(flagValue);
|
||||
if (enumValIter != multiByteFlag.enumValues.end()) {
|
||||
currentVal = enumValIter->second;
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo(multiByteFlag.name, currentVal)) {
|
||||
for (const auto& [val, name] : multiByteFlag.enumValues) {
|
||||
if (ImGui::Selectable(name)) {
|
||||
SetSpreadMultiByte(multiByteFlag.highOrderflag, multiByteFlag.lowOrderflag, val);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
genCommonAreaFlags(membit);
|
||||
}
|
||||
|
||||
static void drawCurrentRegionFlags()
|
||||
{
|
||||
dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit;
|
||||
auto* stageData = dComIfGp_getStageStagInfo();
|
||||
if (!stageData)
|
||||
return;
|
||||
uint8_t stageIndex = dStage_stagInfo_GetSaveTbl(stageData);
|
||||
|
||||
genAreaFlagTable(stageIndex, membit);
|
||||
|
||||
if (ImGui::TreeNode("Flag Matrix")) {
|
||||
genMembitFlags("##TempSceneFlags", membit);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
stage_stag_info_class* pstag = dComIfGp_getStageStagInfo();
|
||||
if (pstag != nullptr) {
|
||||
int stageNo = dStage_stagInfo_GetSaveTbl(pstag);
|
||||
if (ImGui::Button("Save##SaveTempFlags")) {
|
||||
dComIfGs_putSave(stageNo);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Load##LoadSaveFlags")) {
|
||||
dComIfGs_getSave(stageNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiSaveEditor::drawFlagsTab() {
|
||||
if (ImGui::TreeNode("Current Region Flags")) {
|
||||
drawCurrentRegionFlags();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Region Saved Flags")) {
|
||||
static std::array<const char*, 27> regionNames = {
|
||||
"Ordon",
|
||||
"Hyrule Sewers",
|
||||
"Faron",
|
||||
"Eldin",
|
||||
"Lanayru",
|
||||
"Reserved",
|
||||
"Hyrule Field",
|
||||
"Sacred Grove",
|
||||
"Snowpeak",
|
||||
"Castle Town",
|
||||
"Gerudo Desert",
|
||||
"Fishing Pond",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Forest Temple",
|
||||
"Goron Mines",
|
||||
"Lakebed Temple",
|
||||
"Arbiter's Grounds",
|
||||
"Snowpeak Ruins",
|
||||
"Temple of Time",
|
||||
"City in the Sky",
|
||||
"Palace of Twilight",
|
||||
"Hyrule Castle",
|
||||
"Caves",
|
||||
"Grottos",
|
||||
static const std::map<uint8_t, const char*> regionNames = {
|
||||
{ 0x00, "Ordon" },
|
||||
{ 0x01, "Hyrule Sewers" },
|
||||
{ 0x02, "Faron" },
|
||||
{ 0x03, "Eldin" },
|
||||
{ 0x04, "Lanayru" },
|
||||
{ 0x06, "Hyrule Field" },
|
||||
{ 0x07, "Sacred Grove" },
|
||||
{ 0x08, "Snowpeak" },
|
||||
{ 0x09, "Castle Town" },
|
||||
{ 0x0A, "Gerudo Desert" },
|
||||
{ 0x0B, "Fishing Pond" },
|
||||
{ 0x10, "Forest Temple" },
|
||||
{ 0x11, "Goron Mines" },
|
||||
{ 0x12, "Lakebed Temple" },
|
||||
{ 0x13, "Arbiter's Grounds" },
|
||||
{ 0x14, "Snowpeak Ruins" },
|
||||
{ 0x15, "Temple of Time" },
|
||||
{ 0x16, "City in the Sky" },
|
||||
{ 0x17, "Palace of Twilight" },
|
||||
{ 0x18, "Hyrule Castle" },
|
||||
{ 0x19, "Caves" },
|
||||
{ 0x1A, "Lake Hylia Long Cave"},
|
||||
{ 0x1B, "Grottos" }
|
||||
};
|
||||
|
||||
if (ImGui::BeginCombo("Region", regionNames[m_selectedRegion])) {
|
||||
for (int i = 0; i < regionNames.size(); i++) {
|
||||
if (strcmp(regionNames[i], "Reserved") == 0) continue;
|
||||
if (m_selectedRegion.name == nullptr)
|
||||
{
|
||||
const auto& firstRegion = *regionNames.find(0);
|
||||
m_selectedRegion = { firstRegion.first, firstRegion.second };
|
||||
}
|
||||
|
||||
if (ImGui::Selectable(regionNames[i])) {
|
||||
m_selectedRegion = i;
|
||||
if (ImGui::BeginCombo("Region", m_selectedRegion.name)) {
|
||||
for (const auto& [id, name] : regionNames) {
|
||||
if (ImGui::Selectable(name)) {
|
||||
m_selectedRegion = {id, name};
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
dSv_memBit_c* membit = &dComIfGs_getSaveData()->mSave[m_selectedRegion].mBit;
|
||||
if (membit != nullptr) {
|
||||
genMembitFlags("##SaveSceneFlags", *membit);
|
||||
dSv_memBit_c& membit = dComIfGs_getSaveData()->mSave[m_selectedRegion.id].mBit;
|
||||
|
||||
genAreaFlagTable(m_selectedRegion.id, membit);
|
||||
|
||||
if (ImGui::TreeNode("Flag Matrix")) {
|
||||
genMembitFlags("##SaveSceneFlags", membit);
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
@@ -1530,7 +1789,9 @@ namespace dusk {
|
||||
}
|
||||
|
||||
for (const auto& e : duskImguiEventFlags) {
|
||||
if (!filter.PassFilter((e.location + "\n" + e.description + "\n" + e.flagName).c_str()))
|
||||
if (!filter.PassFilter(e.location.c_str()) &&
|
||||
!filter.PassFilter(e.description.c_str()) &&
|
||||
!filter.PassFilter(e.flagName.c_str()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ namespace dusk {
|
||||
void drawConfigTab();
|
||||
|
||||
private:
|
||||
int m_selectedRegion = 0;
|
||||
struct {
|
||||
uint8_t id;
|
||||
const char* name;
|
||||
} m_selectedRegion = {0, nullptr};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,11 @@ constexpr const char* TP_GAME_IDS[] = {
|
||||
"RZDK01", // Wii KOR
|
||||
};
|
||||
|
||||
constexpr const char* PAL_GAME_IDS[] = {
|
||||
"GZ2P01", // GCN PAL
|
||||
"RZDP01", // Wii PAL
|
||||
};
|
||||
|
||||
constexpr const char* SUPPORTED_TP_GAME_IDS[] = {
|
||||
"GZ2E01", // GCN USA
|
||||
"GZ2P01", // GCN PAL
|
||||
@@ -96,6 +101,10 @@ ValidationError validate(const char* path) {
|
||||
NodHandleWrapper disc;
|
||||
|
||||
const auto sdlStream = SDL_IOFromFile(path, "rb");
|
||||
if (sdlStream == nullptr) {
|
||||
return ValidationError::IOError;
|
||||
}
|
||||
|
||||
const NodDiscStream nod_stream {
|
||||
.user_data = sdlStream,
|
||||
.read_at = StreamReadAt,
|
||||
@@ -124,4 +133,30 @@ ValidationError validate(const char* path) {
|
||||
|
||||
return ValidationError::Success;
|
||||
}
|
||||
bool isPal(const char* path) {
|
||||
NodHandleWrapper disc;
|
||||
|
||||
const auto sdlStream = SDL_IOFromFile(path, "rb");
|
||||
if (sdlStream == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const NodDiscStream nod_stream{
|
||||
.user_data = sdlStream,
|
||||
.read_at = StreamReadAt,
|
||||
.stream_len = StreamLength,
|
||||
.close = StreamClose,
|
||||
};
|
||||
|
||||
if (nod_disc_open_stream(&nod_stream, nullptr, &disc.handle) != NOD_RESULT_OK || disc.handle == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NodDiscHeader header{};
|
||||
if (nod_disc_header(disc.handle, &header) != NOD_RESULT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return matches(header.game_id, PAL_GAME_IDS);
|
||||
}
|
||||
} // namespace dusk::iso
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user