Compare commits

..

220 Commits

Author SHA1 Message Date
MelonSpeedruns 27274e7341 Merge remote-tracking branch 'origin/main' into feature/hyper-enemies
# Conflicts:
#	src/dusk/imgui/ImGuiMenuGame.cpp
#	src/dusk/settings.cpp
2026-05-03 17:23:54 -04:00
TakaRikka 1cb8b19520 Merge pull request #612 from TwilitRealm/26-05-01-gameheap-size
Increase gameHeap size by an order of magnitude
2026-05-03 00:18:37 -07:00
TakaRikka d109cd891e add note 2026-05-03 00:07:37 -07:00
doop 63c4002ca6 Fix prelaunch nav cycling 2026-05-03 05:49:53 +00:00
Lurs 6954efcd15 Should fix #636 2026-05-03 06:46:49 +02:00
Jasper St. Pierre 78c2147771 midna eye lod fix 2026-05-02 15:36:00 -07:00
Irastris c938d5468e Add Interface tab to RmlUi, remove ImGui interface menu 2026-05-02 18:16:42 -04:00
Irastris 35590c5312 Increase font size for pane text 2026-05-02 17:24:10 -04:00
Luke Street e976b10e2a UI: Avoid overlapping ImGui menu bar 2026-05-02 15:22:24 -06:00
Irastris 3949706b28 Revise gyro aim help text, remove ImGui input menu 2026-05-02 17:19:41 -04:00
Irastris ce55916845 Add Autosave to RmlUi, remove ImGui gameplay menu, formatting consistency 2026-05-02 17:01:30 -04:00
Irastris 9b252cbdd2 Remove ImGui cheats menu 2026-05-02 16:33:50 -04:00
Irastris 97fa09f6ee Add spatial sound option to RmlUi, remove ImGui audio menu 2026-05-02 16:05:57 -04:00
TakaRikka 0e7a7cccb9 Merge pull request #458 from TwilitRealm/feature/autosave
Autosave Feature
2026-05-02 13:03:29 -07:00
Irastris 1c0cdcc176 Typo 2: Electric Boogaloo 2026-05-02 15:54:42 -04:00
Irastris 280305c2ba Typo 2026-05-02 15:33:44 -04:00
Luke Street d1f1d579bc Prevent macOS crash on shutdown by tracking logging dtor (#626) 2026-05-02 13:22:28 -06:00
Irastris eeeb3ffe25 Remove ImGui graphics menu 2026-05-02 14:45:34 -04:00
Jasper St. Pierre 1ee0f862e1 map highlight fix 2026-05-02 11:45:01 -07:00
Jasper St. Pierre 6b327c9f61 disable jpa interp for now
closes #618
2026-05-02 11:44:21 -07:00
Luke Street f148e0ebc1 UI: Rework Document close handling again 2026-05-02 12:39:07 -06:00
Jasper St. Pierre 6f20f4d629 compile fix 2026-05-02 10:54:45 -07:00
Irastris 94670270d6 Fix prelaunch menu transition post-startup 2026-05-02 13:52:20 -04:00
Luke Street 8e21247a97 UI: Prelaunch fade + BG persistence 2026-05-02 11:32:59 -06:00
Luke Street aa84004cb4 Merge branch 'rmlui-integration' 2026-05-02 10:50:18 -06:00
Luke Street e1c201f4bd Make prelaunch sticky & kill ImGui prelaunch 2026-05-02 10:44:59 -06:00
MelonSpeedruns 425a1d15a0 Merge remote-tracking branch 'origin/main' into feature/autosave 2026-05-02 10:56:36 -04:00
MelonSpeedruns e3ad41792a fix respawn stageinfo when autosaving 2026-05-02 10:42:20 -04:00
MelonSpeedruns c1ba10fc8b fix mistake 2026-05-02 10:29:23 -04:00
TakaRikka 1c5686f71b Merge pull request #616 from TwilitRealm/HRTF
Emulate Surround option
2026-05-01 22:51:25 -07:00
TakaRikka b9e0f2b9ca Merge pull request #611 from TwilitRealm/26-05-01-heap-crash-log
Improve heap crash logging
2026-05-01 22:19:33 -07:00
TakaRikka ede175f141 Merge pull request #600 from TwilitRealm/fix/fix-bow-aiming
Fix bow aiming in first person
2026-05-01 22:18:14 -07:00
TakaRikka a301874e30 Merge pull request #592 from TwilitRealm/fix/free-cam-fix
Freecam Fixes
2026-05-01 22:17:21 -07:00
Irastris 9b4a9a6bd9 Initial attempt at the prelaunch document 2026-05-02 00:10:11 -04:00
Luke Street 04274b1884 Make RmlUi F1, ImGui Shift+F1 2026-05-01 21:53:48 -06:00
Luke Street ca783b8424 Merge branch 'main' into rmlui-integration
# Conflicts:
#	extern/aurora
2026-05-01 21:24:24 -06:00
Luke Street 2e4c2b5b46 UI: Add controller input 2026-05-01 21:24:12 -06:00
Luke Street 4c09d8b910 Fix restoring scroll position on pop 2026-05-01 17:40:38 -06:00
Luke Street fb1b260d09 Add Input tab to settings 2026-05-01 16:52:08 -06:00
Luke Street 98eb8f718e Add Bloom settings 2026-05-01 16:32:04 -06:00
Luke Street 68b2e0ee2d Rework Settings components 2026-05-01 16:14:20 -06:00
Luke Street 81771a0522 Editor Collection, Minigame, Config tabs 2026-05-01 14:12:12 -06:00
madeline 93c8bcc210 hrtf 2026-05-01 13:04:08 -07:00
Luke Street 176bf5f0c4 Editor inventory tab 2026-05-01 13:11:43 -06:00
Luke Street 65a5945778 Location tab in editor 2026-05-01 12:37:40 -06:00
Luke Street 8f7b9cdfdd Dual pane navigation & more player editor 2026-05-01 12:06:05 -06:00
MelonSpeedruns acecba7ff7 Reset camera zoom to 0 if freecam is enabled mid-game 2026-05-01 12:54:40 -04:00
MelonSpeedruns 507e0aadbc Merge remote-tracking branch 'origin/main' into fix/free-cam-fix 2026-05-01 12:54:12 -04:00
Jasper St. Pierre 8406d9b192 Merge pull request #613 from TwilitRealm/widescreen/wide-hidden-village
Wide Bulblin count in Hidden Village
2026-05-01 09:04:23 -07:00
Jasper St. Pierre 6f3170cb56 Merge pull request #604 from TwilitRealm/widescreen/dmap-menu
Widescreen Dungeon Map
2026-05-01 09:04:08 -07:00
Jasper St. Pierre 835582224e Merge pull request #601 from TwilitRealm/fix/fmap-widescreen
Widescreen Field Map
2026-05-01 09:04:00 -07:00
MelonSpeedruns 52879f50f0 Wide Bulblin count in Hidden Village 2026-05-01 11:47:18 -04:00
Irastris 2b505f1be4 Revise floating scrollbar margin 2026-05-01 11:19:51 -04:00
Irastris f089f9024d Centralize tab styling and other tidying 2026-05-01 11:13:14 -04:00
roeming 43fb421a93 Merge pull request #608 from TwilitRealm/location-flags-ui
Area flags UI
2026-05-01 07:26:23 -04:00
PJB3005 f06d6b50a9 Fix Plumm game score reset
Fixes #609
2026-05-01 09:27:45 +02:00
Jasper St. Pierre 2c987b0211 build fix 2026-05-01 00:17:51 -07:00
Jasper St. Pierre 3d860ad454 jpa interp start 2026-05-01 00:12:26 -07:00
Luke Street b5bf19569b Button: Selected but not active style 2026-05-01 01:01:38 -06:00
PJB3005 5a7f5cb4a7 Increase gameHeap size by an order of magnitude
Why not?
2026-05-01 08:57:37 +02:00
Luke Street 1affefbbfc Pane: Focus selected child first 2026-05-01 00:56:53 -06:00
PJB3005 e4ff38a712 Disable spammy mDoGph_Painter log line
What was this even debugging? Who knows.
2026-05-01 08:54:32 +02:00
PJB3005 f2ac4d6f44 Leave OSReport enabled. 2026-05-01 08:52:41 +02:00
PJB3005 48b98a5432 Make JKRExpHeap OOM logging more verbose 2026-05-01 08:50:55 +02:00
PJB3005 a4752154f7 Nicely plumb OSReport error/warning/etc through Aurora's logger
This makes a new implementation in the dusk src folder, and makes the existing file containing these functions not compiled anymore.

A ton of dead code is now gone.
2026-05-01 08:50:42 +02:00
Luke Street 0d973a497b Editor: Add get_item_name 2026-05-01 00:40:57 -06:00
Luke Street ab4eccf1df Some more dual pane select work 2026-05-01 00:26:04 -06:00
Luke Street e0c449f28e Improve add_child and Button APIs 2026-04-30 23:36:30 -06:00
Jasper St. Pierre ce9a5c06d5 heap name 2026-04-30 22:19:19 -07:00
Jasper St. Pierre 2bbba1e4e8 couple small fixes 2026-04-30 21:37:28 -07:00
Luke Street 39298f8d8f Preserve focused element on pop 2026-04-30 22:31:24 -06:00
Luke Street 32b4c0567a Animate overlay open/close 2026-04-30 22:17:48 -06:00
Jasper St. Pierre 7ff1b5332e Merge pull request #606 from dooplecks/trim-correction
Correct trim height for arbitrary aspect ratios
2026-04-30 20:38:03 -07:00
Jasper St. Pierre 5e77a60bd6 Merge pull request #610 from dooplecks/shadow-interp
Interpolate shadow camera
2026-04-30 20:36:53 -07:00
doop 9629c000bd Interpolate shadow camera
Fixes #454.
2026-05-01 03:25:07 +00:00
Luke Street 9dc5fed686 Fix overlay CSS 2026-04-30 21:12:25 -06:00
Luke Street 2cc9db77dd Fix overlay 2026-04-30 21:10:48 -06:00
Luke Street 8aa08c9443 Window animations & tags instead of classes 2026-04-30 20:55:21 -06:00
Irastris dca3e2eba6 Overlay: I forgot about pop_document()
This in turn fixes a bug that I was about to bother encounter about, smh
2026-04-30 21:54:52 -04:00
Irastris 57061fba38 Initial attempt at the overlay document 2026-04-30 21:39:39 -04:00
Luke Street cee6a24309 UI: Defer document destruction 2026-04-30 17:46:36 -06:00
Luke Street 62edb3abc6 UI: Implement initial document stack logic 2026-04-30 17:21:55 -06:00
Luke Street 1c9e1c0a66 Minor clean 2026-04-30 16:15:27 -06:00
Luke Street a06aeb10c1 Extract TabBar component 2026-04-30 16:13:08 -06:00
roeming b84b309e00 compilation fix attempt 3 2026-04-30 17:51:52 -04:00
roeming 62eecb3ccd compilation fix attempt 2 2026-04-30 17:48:39 -04:00
roeming ec07572ced compilation fix attempt 2026-04-30 17:45:53 -04:00
roeming b45e2fa34d swap array for named variables 2026-04-30 17:25:24 -04:00
roeming 289a718446 fix comment wording 2026-04-30 17:10:33 -04:00
roeming 292a2a6c34 fix wrong formatting, fix duplicate ui object, fix wrong flags getting set 2026-04-30 17:03:47 -04:00
Luke Street 2e8415b950 Update aurora 2026-04-30 14:43:44 -06:00
roeming dbf1f6e354 implement multibyte area flags in UI 2026-04-30 16:25:56 -04:00
roeming 9a2fe9745d Draw area flags as table 2026-04-30 15:55:59 -04:00
Irastris b5ca343fac Fix apostrophes in strings 2026-04-30 15:50:01 -04:00
doop 88c7ff63ff Fix preprocessor conditional 2026-04-30 19:48:03 +00:00
Luke Street 7a438ad30f UI: Extract a Document class 2026-04-30 13:44:33 -06:00
doop 89649de7c3 Correct trim height for arbitrary aspect ratios
Fixes #543.
2026-04-30 19:39:36 +00:00
Irastris a1960eaa33 Initial attempt at the popup menu 2026-04-30 15:30:14 -04:00
MelonSpeedruns d6820c9233 fix toast call 2026-04-30 14:53:15 -04:00
MelonSpeedruns 5c4bb8d33d Merge remote-tracking branch 'origin/main' into feature/autosave
# Conflicts:
#	src/dusk/imgui/ImGuiConsole.cpp
2026-04-30 14:51:17 -04:00
MelonSpeedruns e3ce1f01c9 Widescreen Dungeon Map 2026-04-30 14:38:24 -04:00
Luke Street 9b6b344ecf Revert "mirror clip fix"
This reverts commit 1ac6df8de7.
2026-04-30 12:09:18 -06:00
Luke Street 3db85d5b44 Merge branch 'main' into rmlui-integration
# Conflicts:
#	extern/aurora
2026-04-30 12:04:21 -06:00
roeming b5871d72d9 fix build 2026-04-30 11:47:22 -04:00
roeming b70a714f88 Remove missed randomizer flag 2026-04-30 11:45:16 -04:00
roeming cad5a8d1bc Add multibyte flags to Area iterators 2026-04-30 11:43:57 -04:00
roeming 93f8a5fa8f Move area multi flag bits to combined flags, at most 2 2026-04-30 11:11:08 -04:00
roeming b0809ea78c Add area flags 2026-04-30 11:02:18 -04:00
MelonSpeedruns b0e9033736 Widescreen Field Map 2026-04-30 10:55:53 -04:00
MelonSpeedruns ce0d89058a don't run hyper enemies while an event is running 2026-04-30 10:55:28 -04:00
Jasper St. Pierre 1ac6df8de7 mirror clip fix
closes #581
2026-04-30 07:52:44 -07:00
MelonSpeedruns 5899b2157a fix bow aiming in first person 2026-04-30 09:29:42 -04:00
Luke Street 3185f578fb Update aurora 2026-04-30 01:45:54 -06:00
Luke Street 4fc09799b6 UI: Fix section heading font 2026-04-30 01:45:25 -06:00
Irastris fe0e3cad72 Remove unused editor functions 2026-04-30 03:27:48 -04:00
Luke Street 37d1aa7f40 UI: Run builder before moving it 2026-04-30 01:07:11 -06:00
Luke Street 4a12554bf4 UI: Mobile keyboard fixes, safe area padding, & more 2026-04-30 00:06:27 -06:00
Phillip Stephens fecd1d5683 Update aurora 2026-04-29 22:33:02 -07:00
doop bce9bf6fd9 Merge pull request #597 from dooplecks/haze-fix
Correct JPADrawInfo proj matrix on widescreen
2026-04-30 00:55:32 -04:00
doop fbf63b075a Correct JPADrawInfo proj matrix on widescreen
Fixes #337.
2026-04-30 04:28:47 +00:00
Luke Street b86d6e90e2 Add Gameplay settings & make Panes scrollable 2026-04-29 21:52:33 -06:00
Luke Street 6425b452e7 Make PgUp/PgDown change tabs 2026-04-29 20:25:59 -06:00
Luke Street 1657fe8083 Split out string/number components 2026-04-29 20:19:27 -06:00
Luke Street ecd74a4cbd More settings/editor components 2026-04-29 19:54:37 -06:00
MelonSpeedruns 36dc43c602 Fix changing tunics crash while on top of mirror (#596)
* Fix changing tunics while reflection is active

* Revert "Fix changing tunics while reflection is active"

This reverts commit 89927dc7a6.

* Really fix changing tunics while reflection is active

* Fix transforming on ice again

---------

Co-authored-by: MelonSpeedruns <melonspeedruns@stratobox.net>
Co-authored-by: Irastris <irastris15@gmail.com>
2026-04-29 18:13:07 -06:00
Luke Street d92515f0d4 Begin scaffolding keyboard nav 2026-04-29 15:19:15 -06:00
MelonSpeedruns f147dcac0c Fix camera while crawling & disable freecam properly when not chasecam 2026-04-29 15:29:00 -04:00
MelonSpeedruns ee4c84f39b Fix slight spazz when changing cam type 2026-04-29 15:21:48 -04:00
MelonSpeedruns b8a83c6f59 disable freecam if not chasecamera 2026-04-29 14:37:32 -04:00
MelonSpeedruns 4462c0ef69 more optimizations to freecam code 2026-04-29 14:28:18 -04:00
Phillip Stephens c803bfb545 Update aurora 2026-04-29 09:14:51 -07:00
qwertyquerty 2623c44cab Merge pull request #583 from TheLastPocket/achievement/email-me
Email me and Heavy Hitter Achievements
2026-04-29 05:29:50 -07:00
madeline 24dd02fc81 better back in time condition 2026-04-29 05:28:28 -07:00
TakaRikka a97602b6dc Merge pull request #589 from TwilitRealm/instant-text-shop-fix
Fix instant text clearing some shop dialogue too quickly
2026-04-29 00:37:51 -07:00
TakaRikka e2943e90dc Merge pull request #590 from dooplecks/map-outline
Improve map outline rendering
2026-04-29 00:37:04 -07:00
Luke Street 3cb7fbd030 Create new component system & initial settings window 2026-04-29 00:38:26 -06:00
doop afe54f22ab Write circle pixels linearly 2026-04-29 04:16:24 +00:00
doop e15f5bcee9 Improve map outline rendering 2026-04-29 03:51:14 +00:00
Irastris 1e372a856d Attempted to start making the save editor functional 2026-04-28 22:54:47 -04:00
gymnast86 b26896cad5 includes 2026-04-28 18:05:40 -07:00
gymnast86 f75faf6b06 fix instant text clearing shop messages too early 2026-04-28 18:03:06 -07:00
Irastris b48d9aa052 Split window document and styles out to files for readability 2026-04-28 19:09:47 -04:00
Luke Street d899706208 Start UI over from scratch and add demo window 2026-04-28 16:20:45 -06:00
TakaRikka 3e05789b58 Merge pull request #586 from TwilitRealm/fix/fix-super-clawshot
Fix draw crash with Super Clawshot enabled
2026-04-28 13:34:24 -07:00
MelonSpeedruns 9a7b62cbc6 disable freecam if an event cam happens 2026-04-28 16:25:42 -04:00
MelonSpeedruns 8e0f0e878e optimize some code 2026-04-28 16:13:49 -04:00
MelonSpeedruns 79344edf0d maybe fix number 2 2026-04-28 15:19:32 -04:00
MelonSpeedruns e59bfd1a9c potential fix for freecam flashing 2026-04-28 15:01:57 -04:00
MelonSpeedruns 4d12cc8ea2 Fix draw crash with Super Clawshot enabled 2026-04-28 11:05:29 -04:00
Julian Maynes 2ed2268579 fix newline 2026-04-28 07:19:18 -07:00
Julian Maynes 94a99e8da0 Add iron boots achievement 2026-04-28 07:12:29 -07:00
madeline ddaf50c01d long jump attack achievement 2026-04-28 06:53:20 -07:00
madeline 7566949b42 fix friendly fire achievement 2026-04-28 06:21:41 -07:00
Julian Maynes bb6db3caea remove newlines 2026-04-28 06:18:40 -07:00
Julian Maynes 2dc494dc1c Finish achievement 2026-04-28 06:14:56 -07:00
madeline 3c25633ee9 speed_target avoid ub 2026-04-28 06:08:04 -07:00
madeline d99ed2729b fix achievements window sizing 2026-04-28 05:57:58 -07:00
madeline 782455d48b Merge branch 'main' of https://github.com/TakaRikka/dusk 2026-04-28 05:54:12 -07:00
madeline 47863b34c2 achievement signal system 2026-04-28 05:54:09 -07:00
TakaRikka 92391d5eb8 add overview and ai notice to readme 2026-04-28 04:06:29 -07:00
madeline 0d37cb4e54 thank you berry much achievement 2026-04-28 04:01:22 -07:00
madeline ea528ed9d9 clear single achievement and fix achievement tab moving around 2026-04-28 03:41:04 -07:00
Luke Street f7b880c5ea Small tweak to rml_string 2026-04-28 00:27:18 -06:00
Luke Street ff78bc8d6c Start using Rml::PropertyId/Property instead of strings 2026-04-28 00:18:52 -06:00
Luke Street 6503b4e7eb Add blur and shadow to window component 2026-04-27 23:44:58 -06:00
TakaRikka 30b7087f30 add option for only fishing once for sera's cat 2026-04-27 22:04:42 -07:00
Luke Street 0c1372f986 Revert "Kinda crappy initial controller support"
This reverts commit 23a91a37be.
2026-04-27 21:55:57 -06:00
Irastris 8fb4ba8924 Remove "Enable" from various options, and move DoF under post-processing 2026-04-27 22:51:56 -04:00
Irastris 5f675c6f2b Start deprecating ImGui 2026-04-27 22:44:26 -04:00
Irastris b3333241c5 Add right-pane for item descriptions 2026-04-27 22:44:26 -04:00
Irastris e39079c0f8 Initial game menu implementation 2026-04-27 22:44:26 -04:00
Irastris c3317d9232 Initial window class programming 2026-04-27 22:43:04 -04:00
MelonSpeedruns 36092f1fdb added setting 2026-04-27 18:29:14 -04:00
TakaRikka a4777045fe Merge pull request #578 from TwilitRealm/fix/fix-disable-hud
Fix bugs with Disable Main HUD
2026-04-27 15:29:02 -07:00
TakaRikka bbe8ea6aa6 Merge pull request #577 from TwilitRealm/better-freecam-code
Better Freecam code + Allow Freecam in Target mode
2026-04-27 15:28:39 -07:00
MelonSpeedruns d662db69f0 Fix bugs with Disable Main HUD 2026-04-27 17:04:42 -04:00
MelonSpeedruns 5eb3184174 Hyper Enemies (2x) 2026-04-27 16:55:43 -04:00
MelonSpeedruns 9b259143be Better Freecam code + Allow Freecam in Target mode 2026-04-27 12:05:26 -04:00
Luke Street 025cb58493 Forgor to commit 2026-04-27 01:15:19 -06:00
Luke Street b3dee825e8 Improve button/option style 2026-04-27 00:44:01 -06:00
Luke Street f6c5aac3c8 Improve disc selector 2026-04-27 00:36:56 -06:00
Luke Street 25e9064d09 Revamped prelaunch experiment w/ RmlUi 2026-04-27 00:18:31 -06:00
Irastris 5f33489465 Register interp callback for d_a_obj_lv8Lift 2026-04-27 01:04:45 -04:00
Luke Street 3e1e8f1244 Enable RmlUi 2026-04-26 21:53:39 -06:00
Luke Street 23a91a37be Kinda crappy initial controller support 2026-04-26 21:01:41 -06:00
TakaRikka a886f8a2df Merge pull request #568 from TwilitRealm/fix/d_a_obj_balloon
d_a_balloon score and interp fixes
2026-04-26 17:00:30 -07:00
TakaRikka 6df7b1e9cd Merge pull request #357 from TwilitRealm/speedrun-timer
speedrun timer
2026-04-26 16:59:47 -07:00
TakaRikka 206c02b527 fix igt timer 2026-04-26 16:51:10 -07:00
Pheenoh a05d1a9ee6 d_a_balloon score and interp fixes 2026-04-26 17:05:46 -06:00
Howard Luck ed0df01b8d Merge pull request #565 from TwilitRealm/fix/clib_offsetpos
cLib_offsetPos param aliasing fix
2026-04-26 16:09:26 -06:00
Pheenoh 0f9d563a3e cLib_offsetPos param aliasing fix 2026-04-26 15:59:45 -06:00
TakaRikka f3fb65495e Merge pull request #561 from TwilitRealm/fix/pal_lang
Only show language selection if PAL disc
2026-04-26 14:50:14 -07:00
TakaRikka 196f33005e Merge pull request #560 from TwilitRealm/fix/imgui-and-camera-x
ImGui Button name change + Fix Freecam Invert X Axis option
2026-04-26 14:49:40 -07:00
Luke Street 90c0bdded0 Use GXDestroyCopyTex on map destroy
Resolves #469
2026-04-26 14:02:28 -06:00
Pheenoh f856f871bb Only show languages if PAL disc 2026-04-26 13:58:38 -06:00
Jasper St. Pierre e75ea18ef0 map deco perf 2026-04-26 11:52:20 -07:00
Jasper St. Pierre 50e2d9d1a7 grass draw fix
closes #534
2026-04-26 11:18:25 -07:00
Jasper St. Pierre 5c84978c3c evil perf fix
closes #552
2026-04-26 10:44:52 -07:00
MelonSpeedruns 3859f39729 Fix camera radius to be smoother 2026-04-26 10:25:10 -04:00
MelonSpeedruns 3498ded9d9 ImGui Button name change + Fix Freecam Invert X Axis option 2026-04-26 10:18:47 -04:00
Phillip Stephens 8784958c40 Quick PAD rumble fixes, add button to test rumble configuration 2026-04-25 22:51:39 -07:00
Phillip Stephens c1231885fe Add rumble intensity sliders to input configurator (#558) 2026-04-25 23:17:17 -06:00
TakaRikka 6cf94b4491 remove unneeded file 2026-04-25 21:18:51 -07:00
TakaRikka 30aa2dd527 Merge branch 'main' of github.com:TwilitRealm/dusk into speedrun-timer 2026-04-25 21:16:27 -07:00
TakaRikka 8e121a7e51 update timer impl 2026-04-25 21:12:51 -07:00
roeming 0bf663141a change filter to avoid allocations 2026-04-25 14:39:47 -04:00
TakaRikka 17949e526b Merge branch 'main' of github.com:TwilitRealm/dusk into speedrun-timer 2026-04-25 06:05:50 -07:00
MelonSpeedruns d7dced7ddf don't autosave if playing a cutscene 2026-04-25 08:25:50 -04:00
MelonSpeedruns 78b0563c0e Merge remote-tracking branch 'origin/main' into feature/autosave
# Conflicts:
#	src/dusk/imgui/ImGuiMenuEnhancements.cpp
#	src/dusk/settings.cpp
#	src/f_ap/f_ap_game.cpp
2026-04-24 12:54:40 -04:00
MelonSpeedruns 871d18e294 added experimental setting for autosave 2026-04-20 13:15:37 -04:00
MelonSpeedruns c157564da6 dungeon doors now autosave 2026-04-20 13:02:25 -04:00
MelonSpeedruns ecc3b00c51 Merge remote-tracking branch 'origin/main' into feature/autosave
# Conflicts:
#	src/f_ap/f_ap_game.cpp
2026-04-20 12:55:17 -04:00
MelonSpeedruns 8afb1141ab Autosave when changing rooms 2026-04-17 13:41:56 -04:00
MelonSpeedruns 8c5673d9b8 autosave when loading scene 2026-04-17 13:12:20 -04:00
MelonSpeedruns 916dfcd9da Merge remote-tracking branch 'origin/main' into feature/autosave
# Conflicts:
#	src/dusk/imgui/ImGuiConsole.cpp
2026-04-17 12:10:24 -04:00
MelonSpeedruns 842210e539 remove scene autosave cause that's buggy atm 2026-04-16 19:56:04 -04:00
MelonSpeedruns 39d951d0cb scene saving now works 2026-04-16 19:50:20 -04:00
MelonSpeedruns a4be0841e5 autosave WIP 2026-04-16 19:30:37 -04:00
TakaRikka 0d76b90144 Merge branch 'main' of https://github.com/TakaRikka/dusk into speedrun-timer 2026-04-14 04:10:28 -07:00
madeline a6690c2052 speedrun timer 2026-04-12 23:22:25 -07:00
145 changed files with 11898 additions and 852 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
Language: Cpp Language: Cpp
Standard: C++03 Standard: C++03
AccessModifierOffset: -4 AccessModifierOffset: -4
AlignAfterOpenBracket: Align AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false AlignConsecutiveDeclarations: false
AlignOperands: true AlignOperands: true
+5
View File
@@ -100,6 +100,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
endif () endif ()
set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE) 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_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(extern/aurora EXCLUDE_FROM_ALL)
add_subdirectory(libs/freeverb) 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) list(APPEND GAME_COMPILE_DEFS DUSK_ENABLE_SENTRY_NATIVE=1 SENTRY_BUILD_STATIC=1)
endif () endif ()
if (WIN32)
list(APPEND GAME_LIBS Ws2_32)
endif ()
if (DUSK_MOVIE_SUPPORT) if (DUSK_MOVIE_SUPPORT)
if (TARGET libjpeg-turbo::turbojpeg-static) if (TARGET libjpeg-turbo::turbojpeg-static)
list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static) list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static)
+7 -1
View File
@@ -1,8 +1,12 @@
![DuskLogo](res/logo-mascot.webp) ![DuskLogo](res/logo-mascot.png)
- ### **[Official Website](https://twilitrealm.dev)** - ### **[Official Website](https://twilitrealm.dev)**
- ### **[Discord](https://discord.gg/QACynxeyna)** - ### **[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 # Setup
**⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.** **⚠️ 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 # Building
If you'd like to build Dusk from source, please read the [build instructions](docs/building.md). 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 # 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). 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).
+1 -1
+43 -1
View File
@@ -1,7 +1,7 @@
set(DOLZEL_FILES set(DOLZEL_FILES
src/m_Do/m_Do_main.cpp 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_audio.cpp
src/m_Do/m_Do_controller_pad.cpp src/m_Do/m_Do_controller_pad.cpp
#src/m_Do/m_Re_controller_pad.cpp #src/m_Do/m_Re_controller_pad.cpp
@@ -1429,6 +1429,7 @@ set(DUSK_FILES
src/dusk/globals.cpp src/dusk/globals.cpp
src/dusk/gyro.cpp src/dusk/gyro.cpp
src/dusk/gamepad_color.cpp src/dusk/gamepad_color.cpp
src/dusk/autosave.cpp
src/dusk/io.cpp src/dusk/io.cpp
src/dusk/layout.cpp src/dusk/layout.cpp
src/dusk/logging.cpp src/dusk/logging.cpp
@@ -1462,10 +1463,51 @@ set(DUSK_FILES
src/dusk/imgui/ImGuiStateShare.cpp src/dusk/imgui/ImGuiStateShare.cpp
src/dusk/imgui/ImGuiAchievements.hpp src/dusk/imgui/ImGuiAchievements.hpp
src/dusk/imgui/ImGuiAchievements.cpp 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/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/achievements.cpp
src/dusk/iso_validate.cpp src/dusk/iso_validate.cpp
src/dusk/livesplit.cpp
src/dusk/offset_ptr.cpp src/dusk/offset_ptr.cpp
src/dusk/OSContext.cpp src/dusk/OSContext.cpp
src/dusk/OSReport.cpp
src/dusk/OSThread.cpp src/dusk/OSThread.cpp
src/dusk/OSMutex.cpp src/dusk/OSMutex.cpp
src/dusk/discord_presence.cpp src/dusk/discord_presence.cpp
+1
View File
@@ -27,6 +27,7 @@ public:
/* 0x17C */ cXyz mViewScale; /* 0x17C */ cXyz mViewScale;
#if TARGET_PC #if TARGET_PC
bool mbReset = false; bool mbReset = false;
bool mbHadEntry = false;
#endif #endif
}; };
+3
View File
@@ -58,6 +58,9 @@ public:
void setNextPoint(); void setNextPoint();
int Draw(); int Draw();
int Delete(); int Delete();
#if TARGET_PC
friend void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork);
#endif
u8 getPthID() { return fopAcM_GetParamBit(this, 0, 8); } u8 getPthID() { return fopAcM_GetParamBit(this, 0, 8); }
u8 getMoveSpeed() { return fopAcM_GetParamBit(this, 8, 4); } u8 getMoveSpeed() { return fopAcM_GetParamBit(this, 8, 4); }
+4
View File
@@ -91,6 +91,10 @@ public:
void calcCursor(); void calcCursor();
void drawCursor(); void drawCursor();
#if TARGET_PC
void dMapBgWide();
#endif
void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; } void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; }
f32 getMapWidth() { return mMapWidth; } f32 getMapWidth() { return mMapWidth; }
+8
View File
@@ -81,6 +81,10 @@ public:
void calcDrawPriority(); void calcDrawPriority();
void setArrowPosAxis(f32, f32); void setArrowPosAxis(f32, f32);
#if TARGET_PC
void fMapBackWide();
#endif
virtual void draw(); virtual void draw();
virtual ~dMenu_Fmap2DBack_c(); virtual ~dMenu_Fmap2DBack_c();
@@ -330,6 +334,10 @@ public:
void setHIO(bool); void setHIO(bool);
bool isWarpAccept(); bool isWarpAccept();
#if TARGET_PC
void fMapTopWide();
#endif
virtual void draw(); virtual void draw();
virtual ~dMenu_Fmap2DTop_c(); virtual ~dMenu_Fmap2DTop_c();
+3
View File
@@ -67,6 +67,9 @@ public:
bool isStaffMessage(); bool isStaffMessage();
bool isSaveMessage(); bool isSaveMessage();
bool isTalkMessage(); bool isTalkMessage();
#if TARGET_PC
bool isShopItemMessage();
#endif
const char* getSmellName(); const char* getSmellName();
const char* getPortalName(); const char* getPortalName();
const char* getBombName(); const char* getBombName();
+9
View File
@@ -4,6 +4,8 @@
#include <functional> #include <functional>
#include <queue> #include <queue>
#include <string> #include <string>
#include <string_view>
#include <unordered_set>
#include <vector> #include <vector>
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
@@ -14,6 +16,7 @@ enum class AchievementCategory : uint8_t {
Collection, Collection,
Challenge, Challenge,
Minigame, Minigame,
Misc,
Glitched Glitched
}; };
@@ -40,6 +43,11 @@ public:
void save(); void save();
void tick(); void tick();
void clearAll(); 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; std::vector<Achievement> getAchievements() const;
bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); } bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); }
@@ -57,6 +65,7 @@ private:
void processEntry(Entry& e); void processEntry(Entry& e);
std::vector<Entry> m_entries; std::vector<Entry> m_entries;
std::unordered_set<std::string_view> m_signals;
bool m_loaded = false; bool m_loaded = false;
bool m_dirty = false; bool m_dirty = false;
std::queue<std::string> m_pendingUnlocks; std::queue<std::string> m_pendingUnlocks;
+17
View File
@@ -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
+16
View File
@@ -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();
}
+9
View File
@@ -55,6 +55,7 @@ struct UserSettings {
ConfigVar<int> soundEffectsVolume; ConfigVar<int> soundEffectsVolume;
ConfigVar<int> fanfareVolume; ConfigVar<int> fanfareVolume;
ConfigVar<bool> enableReverb; ConfigVar<bool> enableReverb;
ConfigVar<bool> enableHrtf;
} audio; } audio;
// Game settings // Game settings
@@ -71,14 +72,17 @@ struct UserSettings {
ConfigVar<bool> disableRupeeCutscenes; ConfigVar<bool> disableRupeeCutscenes;
ConfigVar<bool> noSwordRecoil; ConfigVar<bool> noSwordRecoil;
ConfigVar<int> damageMultiplier; ConfigVar<int> damageMultiplier;
ConfigVar<bool> hyperEnemies;
ConfigVar<bool> noHeartDrops; ConfigVar<bool> noHeartDrops;
ConfigVar<bool> instantDeath; ConfigVar<bool> instantDeath;
ConfigVar<bool> fastClimbing; ConfigVar<bool> fastClimbing;
ConfigVar<bool> noMissClimbing; ConfigVar<bool> noMissClimbing;
ConfigVar<bool> fastTears; ConfigVar<bool> fastTears;
ConfigVar<bool> no2ndFishForCat;
ConfigVar<bool> instantSaves; ConfigVar<bool> instantSaves;
ConfigVar<bool> instantText; ConfigVar<bool> instantText;
ConfigVar<bool> sunsSong; ConfigVar<bool> sunsSong;
ConfigVar<bool> autoSave;
// Preferences // Preferences
ConfigVar<bool> enableMirrorMode; ConfigVar<bool> enableMirrorMode;
@@ -96,6 +100,7 @@ struct UserSettings {
ConfigVar<int> internalResolutionScale; ConfigVar<int> internalResolutionScale;
ConfigVar<int> shadowResolutionMultiplier; ConfigVar<int> shadowResolutionMultiplier;
ConfigVar<bool> enableDepthOfField; ConfigVar<bool> enableDepthOfField;
ConfigVar<bool> enableMapBackground;
// Audio // Audio
ConfigVar<bool> noLowHpSound; ConfigVar<bool> noLowHpSound;
@@ -137,6 +142,10 @@ struct UserSettings {
// Controls // Controls
ConfigVar<bool> enableTurboKeybind; ConfigVar<bool> enableTurboKeybind;
// Tools
ConfigVar<bool> speedrunMode;
ConfigVar<bool> liveSplitEnabled;
} game; } game;
struct { struct {
@@ -59,6 +59,9 @@ public:
bool isActive() const { return mSeqList.getNumLinks() != 0; } bool isActive() const { return mSeqList.getNumLinks() != 0; }
int getNumActiveSeqs() const { return mSeqList.getNumLinks(); } int getNumActiveSeqs() const { return mSeqList.getNumLinks(); }
void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; } void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; }
#if TARGET_PC
JSUList<JAISeq>* getSeqList() { return &mSeqList; }
#endif
private: private:
/* 0x08 */ JAIAudience* mAudience; /* 0x08 */ JAIAudience* mAudience;
@@ -207,4 +207,11 @@ void JPARegistAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*); void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*);
void JPARegistPrmAlphaEnv(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 */ #endif /* JPABASESHAPE_H */
@@ -24,6 +24,9 @@ public:
void init_c(JPAEmitterWorkData*, JPABaseParticle*); void init_c(JPAEmitterWorkData*, JPABaseParticle*);
bool calc_p(JPAEmitterWorkData*); bool calc_p(JPAEmitterWorkData*);
bool calc_c(JPAEmitterWorkData*); bool calc_c(JPAEmitterWorkData*);
#if TARGET_PC
void interp(JPAEmitterWorkData*, void const* drawFunc);
#endif
bool canCreateChild(JPAEmitterWorkData*); bool canCreateChild(JPAEmitterWorkData*);
f32 getWidth(JPABaseEmitter const*) const; f32 getWidth(JPABaseEmitter const*) const;
f32 getHeight(JPABaseEmitter const*) const; f32 getHeight(JPABaseEmitter const*) const;
@@ -40,6 +40,9 @@ public:
JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); } JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); }
u16 getNumColors() const { return mNumColors; } u16 getNumColors() const { return mNumColors; }
ResTLUT* getColorTable() const { return mColorTable; } ResTLUT* getColorTable() const { return mColorTable; }
#if TARGET_PC
void dataUploaded();
#endif
private: private:
/* 0x00 */ GXTlutObj mTlutObj; /* 0x00 */ GXTlutObj mTlutObj;
@@ -75,6 +75,7 @@ public:
s32 getTransparency() const { return mTexInfo->alphaEnabled; } s32 getTransparency() const { return mTexInfo->alphaEnabled; }
s32 getWidth() const { return mTexInfo->width; } s32 getWidth() const { return mTexInfo->width; }
s32 getHeight() const { return mTexInfo->height; } s32 getHeight() const { return mTexInfo->height; }
JUTPalette* getPalette() const { return mPalette; }
void setCaptureFlag(bool flag) { mFlags &= 2 | flag; } void setCaptureFlag(bool flag) { mFlags &= 2 | flag; }
bool getCaptureFlag() const { return mFlags & 1; } bool getCaptureFlag() const { return mFlags & 1; }
bool getEmbPaletteDelFlag() const { return mFlags & 2; } bool getEmbPaletteDelFlag() const { return mFlags & 2; }
@@ -82,7 +83,7 @@ public:
int getTlutName() const { return mTlutName; } int getTlutName() const { return mTlutName; }
bool operator==(const JUTTexture& other) { bool operator==(const JUTTexture& other) {
return mTexInfo == other.mTexInfo return mTexInfo == other.mTexInfo
&& field_0x2c == other.field_0x2c && mPalette == other.mPalette
&& mWrapS == other.mWrapS && mWrapS == other.mWrapS
&& mWrapT == other.mWrapT && mWrapT == other.mWrapT
&& mMinFilter == other.mMinFilter && mMinFilter == other.mMinFilter
@@ -100,7 +101,7 @@ private:
/* 0x20 */ const ResTIMG* mTexInfo; /* 0x20 */ const ResTIMG* mTexInfo;
/* 0x24 */ void* mTexData; /* 0x24 */ void* mTexData;
/* 0x28 */ JUTPalette* mEmbPalette; /* 0x28 */ JUTPalette* mEmbPalette;
/* 0x2C */ JUTPalette* field_0x2c; /* 0x2C */ JUTPalette* mPalette;
/* 0x30 */ u8 mWrapS; /* 0x30 */ u8 mWrapS;
/* 0x31 */ u8 mWrapT; /* 0x31 */ u8 mWrapT;
/* 0x32 */ u8 mMinFilter; /* 0x32 */ u8 mMinFilter;
+9 -1
View File
@@ -1,6 +1,9 @@
#include "JSystem/JSystem.h" // IWYU pragma: keep #include "JSystem/JSystem.h" // IWYU pragma: keep
#include "JSystem/JAudio2/JASChannel.h" #include "JSystem/JAudio2/JASChannel.h"
#if TARGET_PC
#include "dusk/audio/DuskDsp.hpp"
#endif
#include "JSystem/JAudio2/JASAiCtrl.h" #include "JSystem/JAudio2/JASAiCtrl.h"
#include "JSystem/JAudio2/JASCalc.h" #include "JSystem/JAudio2/JASCalc.h"
#include "JSystem/JAudio2/JASDriverIF.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 pan = 0.5f;
f32 dolby = 0.0f; 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: case JAS_OUTPUT_MONO:
break; break;
case JAS_OUTPUT_STEREO: case JAS_OUTPUT_STEREO:
-1
View File
@@ -302,7 +302,6 @@ void JASKernel::setupRootHeap(JKRSolidHeap* heap, u32 size) {
JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap"); JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap");
JUT_ASSERT(787, sSystemHeap); JUT_ASSERT(787, sSystemHeap);
sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>; sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>;
JKRHEAP_NAME(sSystemHeap, "JASKernel::sCommandHeap");
JUT_ASSERT(790, sCommandHeap); JUT_ASSERT(790, sCommandHeap);
JASDram = heap; JASDram = heap;
} }
@@ -442,6 +442,7 @@ static JAUSectionHeap* JAUNewSectionHeap(JKRSolidHeap* heap, bool param_1) {
JAUSectionHeap* JAUNewSectionHeap(bool param_0) { JAUSectionHeap* JAUNewSectionHeap(bool param_0) {
s32 freeSize = JASDram->getFreeSize(); s32 freeSize = JASDram->getFreeSize();
JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true); JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true);
JKRHEAP_NAME(sectionHeap, "sectionHeap");
JUT_ASSERT(821, sectionHeap); JUT_ASSERT(821, sectionHeap);
return JAUNewSectionHeap(sectionHeap, param_0); return JAUNewSectionHeap(sectionHeap, param_0);
} }
+8 -5
View File
@@ -222,16 +222,11 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
OSReport_Error("Free block list as follows:\n"); OSReport_Error("Free block list as follows:\n");
OSReport_Error("Start | End | Size \n"); OSReport_Error("Start | End | Size \n");
int i = 0;
for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) { for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) {
if (block->mMagic) { if (block->mMagic) {
// Allocated, ignore. // Allocated, ignore.
continue; continue;
} }
if (i++ > 10) {
OSReport_Error("<more>\n");
break;
}
auto blockStart = (uintptr_t)block - (uintptr_t)mStart; auto blockStart = (uintptr_t)block - (uintptr_t)mStart;
auto blockEnd = (uintptr_t)block + block->size - (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("%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!"); CRASH("Aborting due to allocation failure!");
} }
#else #else
+255 -113
View File
@@ -9,6 +9,9 @@
#include <mtx.h> #include <mtx.h>
#include <gx.h> #include <gx.h>
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
void JPASetPointSize(JPAEmitterWorkData* work) { void JPASetPointSize(JPAEmitterWorkData* work) {
@@ -418,50 +421,95 @@ static projectionFunc p_prj[3] = {
loadPrjAnm, loadPrjAnm,
}; };
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) { #if TARGET_PC
if (param_1->checkStatus(JPAPtclStts_Invisible)) { 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; return;
} }
JGeometry::TVec3<f32> local_48; JGeometry::TVec3<f32> pos;
MTXMultVec(work->mPosCamMtx, &param_1->mPosition, &local_48); #if TARGET_PC
Mtx local_38; Mtx ptclPosMtx;
local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX; if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
local_38[0][3] = local_48.x; pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
local_38[1][1] = work->mGlobalPtclScl.y * param_1->mParticleScaleY; MTXMultVec(work->mPosCamMtx, &pos, &pos);
local_38[1][3] = local_48.y; } else
local_38[2][2] = 1.0f; #endif
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; MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
GXLoadPosMtxImm(local_38, 0); }
p_prj[work->mPrjType](work, local_38); 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)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
} }
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) { void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) { if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
JGeometry::TVec3<f32> local_48; if (work->mpRes->getUsrIdx() == 0x89d7) {
MTXMultVec(work->mPosCamMtx, &param_1->mPosition, &local_48); int a = 0;
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;
Mtx local_38; JGeometry::TVec3<f32> pos;
local_38[0][0] = cosRot * particleX; f32 sinRot, cosRot;
local_38[0][1] = -sinRot * particleY; #if TARGET_PC
local_38[0][3] = local_48.x; Mtx ptclPosMtx;
local_38[1][0] = sinRot * particleX; MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
local_38[1][1] = cosRot * particleY; if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
local_38[1][3] = local_48.y; pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
local_38[2][2] = 1.0f; sinRot = ptclPosMtx[1][0];
local_38[2][3] = local_48.z; cosRot = ptclPosMtx[0][0];
local_38[0][2] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f; MTXMultVec(work->mPosCamMtx, &pos, &pos);
GXLoadPosMtxImm(local_38, 0); } else
p_prj[work->mPrjType](work, local_38); #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)); 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][2] = work->mYBBCamMtx[2][2];
local_38[2][3] = local_48.z; 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; 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); p_prj[work->mPrjType](work, local_38);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); 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][1] = local_94 * fVar1;
local_38[2][2] = local_90; local_38[2][2] = local_90;
local_38[2][3] = local_48.z; local_38[2][3] = local_48.z;
GXLoadPosMtxImm(local_38, 0); GXLoadPosMtxImm(local_38, GX_PNMTX0);
p_prj[work->mPrjType](work, local_38); p_prj[work->mPrjType](work, local_38);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
} }
@@ -681,103 +729,197 @@ static u8* p_dl[2] = {
jpa_dl_x, jpa_dl_x,
}; };
void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) { #if TARGET_PC
if (param_1->checkStatus(JPAPtclStts_Invisible)) { 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; return;
} }
ZoneScoped; axisY.normalize();
axisZ.cross(ptcl->mBaseAxis, axisY);
JGeometry::TVec3<f32> local_6c; if (axisZ.isZero()) {
JGeometry::TVec3<f32> local_78;
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
if (local_6c.isZero()) {
return; return;
} }
local_6c.normalize(); axisZ.normalize();
local_78.cross(param_1->mBaseAxis, local_6c); ptcl->mBaseAxis.cross(axisY, axisZ);
ptcl->mBaseAxis.normalize();
if (local_78.isZero()) { Mtx posMtx;
return; f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
} f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
posMtx[0][0] = ptcl->mBaseAxis.x;
local_78.normalize(); posMtx[0][1] = axisY.x;
param_1->mBaseAxis.cross(local_6c, local_78); posMtx[0][2] = axisZ.x;
param_1->mBaseAxis.normalize(); posMtx[0][3] = ptcl->mPosition.x;
Mtx local_60; posMtx[1][0] = ptcl->mBaseAxis.y;
f32 fVar1 = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX; posMtx[1][1] = axisY.y;
f32 fVar2 = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY; posMtx[1][2] = axisZ.y;
local_60[0][0] = param_1->mBaseAxis.x; posMtx[1][3] = ptcl->mPosition.y;
local_60[0][1] = local_6c.x; posMtx[2][0] = ptcl->mBaseAxis.z;
local_60[0][2] = local_78.x; posMtx[2][1] = axisY.z;
local_60[0][3] = param_1->mPosition.x; posMtx[2][2] = axisZ.z;
local_60[1][0] = param_1->mBaseAxis.y; posMtx[2][3] = ptcl->mPosition.z;
local_60[1][1] = local_6c.y; p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
local_60[1][2] = local_78.y; dusk::frame_interp::record_final_mtx(posMtx, ptcl);
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));
} }
void JPADrawRotDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) { void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) { 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; return;
} }
ZoneScoped; ZoneScoped;
f32 sinRot = JMASSin(param_1->mRotateAngle); Mtx posMtx;
f32 cosRot = JMASCos(param_1->mRotateAngle); #if TARGET_PC
JGeometry::TVec3<f32> local_6c; if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx))
JGeometry::TVec3<f32> local_78; #endif
p_direction[param_0->mDirType](param_0, param_1, &local_6c); {
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; return;
} }
local_6c.normalize(); ZoneScoped;
local_78.cross(param_1->mBaseAxis, local_6c);
if (local_78.isZero()) { Mtx mtx1;
return; 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);
} }
MTXConcat(work->mPosCamMtx, mtx1, mtx2);
local_78.normalize(); GXLoadPosMtxImm(mtx2, GX_PNMTX0);
param_1->mBaseAxis.cross(local_6c, local_78); p_prj[work->mPrjType](work, mtx2);
param_1->mBaseAxis.normalize(); GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
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));
} }
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) { void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
@@ -204,6 +204,28 @@ void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent)
mTexAnmIdx = 0; 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) { bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
if (++mAge >= mLifeTime) { if (++mAge >= mLifeTime) {
return true; return true;
@@ -247,6 +269,17 @@ bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y, mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z); 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; return false;
} }
@@ -289,6 +322,23 @@ bool JPABaseParticle::calc_c(JPAEmitterWorkData* work) {
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y, mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z); 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; return false;
} }
+6
View File
@@ -38,3 +38,9 @@ bool JUTPalette::load() {
return check; return check;
} }
#if TARGET_PC
void JUTPalette::dataUploaded() {
GXInitTlutObjData(&mTlutObj, (void*)mColorTable);
}
#endif
+9 -9
View File
@@ -27,7 +27,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, u8 param_1) {
mTexData = (void*)((intptr_t)mTexInfo + 0x20); mTexData = (void*)((intptr_t)mTexInfo + 0x20);
} }
field_0x2c = NULL; mPalette = NULL;
mTlutName = 0; mTlutName = 0;
mWrapS = mTexInfo->wrapS; mWrapS = mTexInfo->wrapS;
mWrapT = mTexInfo->wrapT; mWrapT = mTexInfo->wrapT;
@@ -95,7 +95,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
} }
mEmbPalette = param_1; mEmbPalette = param_1;
setEmbPaletteDelFlag(false); setEmbPaletteDelFlag(false);
field_0x2c = NULL; mPalette = NULL;
if (param_1 != NULL) { if (param_1 != NULL) {
mTlutName = param_2; mTlutName = param_2;
if (param_2 != param_1->getTlutName()) { 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) { void JUTTexture::attachPalette(JUTPalette* param_0) {
if (mTexInfo->indexTexture) { if (mTexInfo->indexTexture) {
if (param_0 == NULL && mEmbPalette != NULL) { if (param_0 == NULL && mEmbPalette != NULL) {
field_0x2c = mEmbPalette; mPalette = mEmbPalette;
} else { } else {
field_0x2c = param_0; mPalette = param_0;
} }
initTexObj(field_0x2c->getTlutName()); initTexObj(mPalette->getTlutName());
} }
} }
@@ -133,9 +133,9 @@ void JUTTexture::init() {
initTexObj(); initTexObj();
} else { } else {
if (mEmbPalette != NULL) { if (mEmbPalette != NULL) {
field_0x2c = mEmbPalette; mPalette = mEmbPalette;
initTexObj(field_0x2c->getTlutName()); initTexObj(mPalette->getTlutName());
} else { } else {
OS_REPORT("This texture is CI-Format, but EmbPalette is NULL.\n"); 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) { void JUTTexture::load(GXTexMapID param_0) {
if (field_0x2c) { if (mPalette) {
field_0x2c->load(); mPalette->load();
} }
GXLoadTexObj(&mTexObj, param_0); 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.

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

+147
View File
@@ -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;
}
+45
View File
@@ -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;
}
+187
View File
@@ -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;
}
+33
View File
@@ -0,0 +1,33 @@
tab-bar {
display: flex;
min-width: 0;
overflow: auto hidden;
text-transform: uppercase;
}
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);
}
+239
View File
@@ -0,0 +1,239 @@
*, *: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 input {
text-align: right;
font-size: 20dp;
}
+11
View File
@@ -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) { void cLib_offsetPos(cXyz* pdest, cXyz const* psrc, s16 angle, cXyz const* vec) {
f32 cos = cM_scos(angle); f32 cos = cM_scos(angle);
f32 sin = cM_ssin(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->x = psrc->x + (vec->x * cos + vec->z * sin);
pdest->y = psrc->y + vec->y; pdest->y = psrc->y + vec->y;
pdest->z = psrc->z + (vec->z * cos - vec->x * sin); pdest->z = psrc->z + (vec->z * cos - vec->x * sin);
#endif
} }
/** /**
+18 -1
View File
@@ -1,5 +1,9 @@
#include "Z2AudioLib/Z2Audience.h" #include "Z2AudioLib/Z2Audience.h"
#include "Z2AudioLib/Z2SoundInfo.h" #include "Z2AudioLib/Z2SoundInfo.h"
#if TARGET_PC
#include "dusk/audio/DuskDsp.hpp"
#include <cmath>
#endif
#include "Z2AudioLib/Z2Calc.h" #include "Z2AudioLib/Z2Calc.h"
#include "Z2AudioLib/Z2Param.h" #include "Z2AudioLib/Z2Param.h"
#include "JSystem/JAudio2/JAISound.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 Z2Audience::calcRelPosDolby(const Vec& param_0, int camID) {
f32 fVar1 = param_0.z + mAudioCamera[camID].getDolbyCenterZ(); 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) { if (fVar1 > mSetting.field_0x48) {
return 1.0f; return 1.0f;
} }
if (fVar1 < mSetting.field_0x44) { if (fVar1 < mSetting.field_0x44) {
return 0.0f; return 0.0f;
+4 -1
View File
@@ -4962,13 +4962,16 @@ int daAlink_c::create() {
setArcName(checkWolf()); setArcName(checkWolf());
setOriginalHeap(&mpArcHeap, 0xA2800); setOriginalHeap(&mpArcHeap, 0xA2800);
JKRHEAP_NAME(mpArcHeap, "Alink ArcHeap");
if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) { if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) {
return cPhs_INIT_e; return cPhs_INIT_e;
} }
setShieldArcName(); setShieldArcName();
setOriginalHeap(&mpShieldArcHeap, 0x7000); 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; return cPhs_INIT_e;
} }
+13
View File
@@ -8,6 +8,10 @@
#include "d/actor/d_a_horse.h" #include "d/actor/d_a_horse.h"
#include "d/actor/d_a_crod.h" #include "d/actor/d_a_crod.h"
#include "d/d_msg_object.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 #if DEBUG
#include "d/d_s_menu.h" #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); 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) { if (armor_no_dmg && at_mtrl != dCcD_MTRL_ELECTRIC && at_mtrl != dCcD_MTRL_ICE) {
setGuardSe(var_r29); setGuardSe(var_r29);
+10
View File
@@ -23,6 +23,7 @@
#include "d/actor/d_a_npc_tkc.h" #include "d/actor/d_a_npc_tkc.h"
#include <cstring> #include <cstring>
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/settings.h" #include "dusk/settings.h"
BOOL daAlink_c::checkEventRun() const { BOOL daAlink_c::checkEventRun() const {
@@ -4005,6 +4006,15 @@ int daAlink_c::procGanonFinishInit() {
field_0x37c8 = current.pos; field_0x37c8 = current.pos;
onEndResetFlg1(ERFLG1_SHIELD_BACKBONE); 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; return 1;
} }
+4
View File
@@ -18,6 +18,10 @@ enum {
}; };
void daAlink_c::hsChainShape_c::draw() { void daAlink_c::hsChainShape_c::draw() {
if (dusk::getSettings().game.superClawshot) {
return;
}
static const int dummy = 0; static const int dummy = 0;
daAlink_c* alink = (daAlink_c*)getUserArea(); daAlink_c* alink = (daAlink_c*)getUserArea();
-1
View File
@@ -46,7 +46,6 @@ void daAlink_c::setOriginalHeap(JKRExpHeap** i_ppheap, u32 i_size) {
JKRHeap* parent = mDoExt_getGameHeap(); JKRHeap* parent = mDoExt_getGameHeap();
JKRExpHeap* heap = JKRExpHeap::create(size + (var_r29 + var_r28), parent, true); JKRExpHeap* heap = JKRExpHeap::create(size + (var_r29 + var_r28), parent, true);
JKRHEAP_NAME(heap, "Alink original");
*i_ppheap = heap; *i_ppheap = heap;
} }
} }
+14 -3
View File
@@ -6,6 +6,7 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep #include "d/dolzel_rel.h" // IWYU pragma: keep
#include "d/actor/d_a_balloon_2D.h" #include "d/actor/d_a_balloon_2D.h"
#include "dusk/frame_interpolation.h"
#include "JSystem/J2DGraph/J2DGrafContext.h" #include "JSystem/J2DGraph/J2DGrafContext.h"
#include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h" #include "JSystem/J2DGraph/J2DTextBox.h"
@@ -438,7 +439,12 @@ void daBalloon2D_c::setComboAlpha() {
void daBalloon2D_c::drawAddScore() { void daBalloon2D_c::drawAddScore() {
for (s32 i = 19; i >= 0; i--) { for (s32 i = 19; i >= 0; i--) {
if (field_0x5f8[i].field_0xe != 0) { 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 score3;
s32 score2; s32 score2;
s32 score = field_0x5f8[i].field_0xc; s32 score = field_0x5f8[i].field_0xc;
@@ -446,8 +452,13 @@ void daBalloon2D_c::drawAddScore() {
u8 local_88 = 0xff; u8 local_88 = 0xff;
f32 dVar11 = 30.0f; f32 dVar11 = 30.0f;
f32 dVar9 = 30.0f; f32 dVar9 = 30.0f;
field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f; #ifdef TARGET_PC
field_0x5f8[i].field_0x0.y -= 1.0f; 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) { if (field_0x5f8[i].field_0xe < 10) {
f32 fVar5 = field_0x5f8[i].field_0xe / 10.0f; f32 fVar5 = field_0x5f8[i].field_0xe / 10.0f;
local_88 = fVar5 * 255.0f; local_88 = fVar5 * 255.0f;
+11
View File
@@ -17,6 +17,11 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#if TARGET_PC
#include <f_ap/f_ap_game.h>
#include <dusk/autosave.h>
#endif
char* daDoor20_c::getStopBmdName() { char* daDoor20_c::getStopBmdName() {
switch (door_param2_c::getKind(this)) { switch (door_param2_c::getKind(this)) {
case 3: case 3:
@@ -196,6 +201,7 @@ void daDoor20_c::setEventPrm() {
} else { } else {
roomNo = FRoomNo; roomNo = FRoomNo;
} }
if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) { if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) {
if (door_param2_c::getKind(this) == 9) { if (door_param2_c::getKind(this) == 9) {
if (daPy_py_c::checkNowWolf()) { if (daPy_py_c::checkNowWolf()) {
@@ -564,6 +570,11 @@ int daDoor20_c::openEnd(int param_1) {
openEnd_1(); openEnd_1();
break; break;
} }
#if TARGET_PC
triggerAutoSave();
#endif
return 1; return 1;
} }
+5
View File
@@ -282,6 +282,11 @@ static void e_th_spin_B(e_th_class* i_this) {
i_this->current.pos += spC; i_this->current.pos += spC;
f32 speed_target; f32 speed_target;
#if AVOID_UB
speed_target = 0;
#endif
f32 anm_frame = i_this->mpModelMorf->getFrame(); f32 anm_frame = i_this->mpModelMorf->getFrame();
switch (i_this->mMode) { switch (i_this->mMode) {
+17
View File
@@ -463,6 +463,23 @@ int daMidna_c::createHeap() {
JKRReadIdxResource(mBckHeap[0].getBuffer(), mBckHeap[0].getBufferSize(), 0x1DC, dComIfGp_getAnmArchive()); JKRReadIdxResource(mBckHeap[0].getBuffer(), mBckHeap[0].getBufferSize(), 0x1DC, dComIfGp_getAnmArchive());
J3DAnmTransform* md_anm = (J3DAnmTransform*)J3DAnmLoaderDataBase::load(mBckHeap[0].getBuffer()); J3DAnmTransform* md_anm = (J3DAnmTransform*)J3DAnmLoaderDataBase::load(mBckHeap[0].getBuffer());
modelData = (J3DModelData*)dComIfG_getObjectRes(l_arcName, 14); 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); 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); 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) { if (mpMorf == NULL || mpMorf->getModel() == NULL) {
+17 -7
View File
@@ -40,6 +40,7 @@ dMirror_packet_c::dMirror_packet_c() {
void dMirror_packet_c::reset() { void dMirror_packet_c::reset() {
#if TARGET_PC #if TARGET_PC
mbReset = true; mbReset = true;
mbHadEntry = false;
#else #else
mModelCount = 0; mModelCount = 0;
#endif #endif
@@ -84,11 +85,21 @@ void dMirror_packet_c::calcMinMax() {
} }
int dMirror_packet_c::entryModel(J3DModel* i_model) { int dMirror_packet_c::entryModel(J3DModel* i_model) {
#if TARGET_PC
if (mbReset) {
mModelCount = 0;
mbReset = false;
}
#endif
if (mModelCount >= 0x40) { if (mModelCount >= 0x40) {
return 0; return 0;
} }
mModels[mModelCount++] = i_model; mModels[mModelCount++] = i_model;
#if TARGET_PC
mbHadEntry = true;
#endif
return 1; return 1;
} }
@@ -592,13 +603,6 @@ int daMirror_c::execute() {
return 1; return 1;
} }
#if TARGET_PC
if (mPacket.mbReset) {
mPacket.mModelCount = 0;
mPacket.mbReset = false;
}
#endif
daPy_py_c* player = daPy_getLinkPlayerActorClass(); daPy_py_c* player = daPy_getLinkPlayerActorClass();
JUT_ASSERT(0, player != NULL); JUT_ASSERT(0, player != NULL);
@@ -624,6 +628,12 @@ int daMirror_c::draw() {
mDoExt_modelUpdateDL(mpModel); mDoExt_modelUpdateDL(mpModel);
} }
#if TARGET_PC
if (mPacket.mbReset && !mPacket.mbHadEntry) {
mPacket.mModelCount = 0;
}
mPacket.mbHadEntry = true;
#endif
dComIfGd_getOpaListBG()->entryImm(&mPacket, 0); dComIfGd_getOpaListBG()->entryImm(&mPacket, 0);
return 1; return 1;
} }
+2 -3
View File
@@ -956,7 +956,7 @@ static void npc_ne_tame(npc_ne_class* i_this) {
i_this->mpMorf->setPlaySpeed(i_this->mAnmSpeed); i_this->mpMorf->setPlaySpeed(i_this->mAnmSpeed);
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */ /* 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) { if (fpcEx_Search(s_fish_sub, _this) != NULL) {
i_this->mAction = npc_ne_class::ACT_HOME; i_this->mAction = npc_ne_class::ACT_HOME;
i_this->mMode = 10; 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) { if (i_this->mWantsFish && (i_this->mCounter & 0xf) == 0) {
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */ /* 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])) && i_this->mDistToTarget < 1500.0f) {
&& i_this->mDistToTarget < 1500.0f) {
if (fopAcM_SearchByName(fpcNm_MG_ROD_e) != NULL) { if (fopAcM_SearchByName(fpcNm_MG_ROD_e) != NULL) {
i_this->mNoFollow = false; i_this->mNoFollow = false;
} else { } else {
+11
View File
@@ -62,6 +62,16 @@ void daObj_Balloon_c::saveBestScore() {
dComIfGp_setMessageCountNumber(m_balloon_score); 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 u8 hio_set;
static daObj_Balloon_HIO_c l_HIO; static daObj_Balloon_HIO_c l_HIO;
@@ -246,6 +256,7 @@ int daObj_Balloon_c::create() {
} }
if (!hio_set) { if (!hio_set) {
IF_DUSK(minigameReset());
mHIOInit = true; mHIOInit = true;
hio_set = true; hio_set = true;
l_HIO.field_0x04 = -1; l_HIO.field_0x04 = -1;
+41
View File
@@ -10,6 +10,10 @@
#include "d/d_path.h" #include "d/d_path.h"
#include "d/d_bg_w.h" #include "d/d_bg_w.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
daL8Lift_HIO_c::daL8Lift_HIO_c() { daL8Lift_HIO_c::daL8Lift_HIO_c() {
mStopDisappearTime = 30; mStopDisappearTime = 30;
mStartMoveTime = 60; mStartMoveTime = 60;
@@ -380,7 +384,44 @@ void daL8Lift_c::setNextPoint() {
mCurrentPoint = next_point; 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() { int daL8Lift_c::Draw() {
#if TARGET_PC
dusk::frame_interp::add_interpolation_callback(&daL8Lift_interp_callback, this);
#endif
g_env_light.settingTevStruct(16, &current.pos, &tevStr); g_env_light.settingTevStruct(16, &current.pos, &tevStr);
g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr); g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr);
J3DModelData* modelData = mpModel->getModelData(); J3DModelData* modelData = mpModel->getModelData();
+2 -12
View File
@@ -7,13 +7,8 @@
#include "dusk/frame_interpolation.h" #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__width = 63;
const u16 l_J_Ohana00_64TEX__height = 63; const u16 l_J_Ohana00_64TEX__height = 63;
#endif
#if TARGET_PC #if TARGET_PC
#include "dusk/dvd_asset.hpp" #include "dusk/dvd_asset.hpp"
@@ -136,13 +131,8 @@ l_matDL__d_a_grass(l_J_Ohana00_64TEX)
l_matLight4DL(l_J_Ohana00_64TEX) l_matLight4DL(l_J_Ohana00_64TEX)
#endif #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__width = 63;
const u16 l_J_Ohana01_64128_0419TEX__height = 127; const u16 l_J_Ohana01_64128_0419TEX__height = 127;
#endif
#if TARGET_PC #if TARGET_PC
using GameVersion = dusk::version::GameVersion; using GameVersion = dusk::version::GameVersion;
@@ -592,11 +582,11 @@ dFlower_packet_c::dFlower_packet_c() {
#if TARGET_PC #if TARGET_PC
GXInitTexObj(&mTexObj_l_J_Ohana00_64TEX, l_J_Ohana00_64TEX, 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, 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 #endif
+6 -8
View File
@@ -494,11 +494,11 @@ dGrass_packet_c::dGrass_packet_c() {
#if TARGET_PC #if TARGET_PC
GXInitTexObj(&mTexObj_l_M_kusa05_RGBATEX, l_M_kusa05_RGBATEX, 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, 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 #endif
@@ -646,18 +646,14 @@ void dGrass_packet_c::draw() {
} }
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) { if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
#if TARGET_PC IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0);
#endif
if (sp48 <= 3) { if (sp48 <= 3) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size); GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else { } else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size); GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
} }
} else { } else {
#if TARGET_PC IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0);
#endif
GXCallDisplayList(l_Tengusa_matDL, 0xA0); GXCallDisplayList(l_Tengusa_matDL, 0xA0);
} }
@@ -683,12 +679,14 @@ void dGrass_packet_c::draw() {
while (var_r29 != NULL) { while (var_r29 != NULL) {
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) { if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
if (sp48 <= 2) { if (sp48 <= 2) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size); GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else { } else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size); GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
} }
} else { } else {
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
GXCallDisplayList(l_Tengusa_matDL, 0xA0); GXCallDisplayList(l_Tengusa_matDL, 0xA0);
} }
+13
View File
@@ -9,6 +9,8 @@
#include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h" #include "JSystem/J2DGraph/J2DTextBox.h"
#include "d/d_msg_string.h" #include "d/d_msg_string.h"
#include "dusk/livesplit.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_controller_pad.h"
dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) { dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) {
@@ -138,6 +140,17 @@ void dBrightCheck_c::modeWait() {}
void dBrightCheck_c::modeMove() { void dBrightCheck_c::modeMove() {
if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) {
mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0); 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; mCompleteCheck = true;
mMode = MODE_WAIT_e; mMode = MODE_WAIT_e;
} }
+66 -42
View File
@@ -794,16 +794,15 @@ void dCamera_c::updatePad() {
if (mTriggerLeftLast > mCamSetup.ManualEndVal()) { if (mTriggerLeftLast > mCamSetup.ManualEndVal()) {
if (mLockLActive == 0) { if (mLockLActive == 0) {
#if TARGET_PC
mCamParam.mManualMode = 0;
#endif
mLockLJustActivated = 1; mLockLJustActivated = 1;
} else { } else {
mLockLJustActivated = 0; mLockLJustActivated = 0;
} }
mLockLActive = 1; mLockLActive = 1;
#if TARGET_PC
mCamParam.mManualMode = 0;
#endif
} else { } else {
mLockLJustActivated = 0; mLockLJustActivated = 0;
mLockLActive = 0; mLockLActive = 0;
@@ -1176,14 +1175,14 @@ bool dCamera_c::Run() {
clrFlag(0x200000); clrFlag(0x200000);
} }
} else { } else {
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
#if TARGET_PC #if TARGET_PC
if (mCamParam.Algorythmn(mCamStyle) != 1) { if (mCamParam.Algorythmn(mCamStyle) != 1) {
mCamParam.mManualMode = 0; mCamParam.mManualMode = 0;
} }
#endif #endif
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
field_0x170++; field_0x170++;
field_0x160++; field_0x160++;
mCurCamStyleTimer++; mCurCamStyleTimer++;
@@ -1488,7 +1487,7 @@ void dCamera_c::CalcTrimSize() {
mTrimHeight += -mTrimHeight * 0.25f; mTrimHeight += -mTrimHeight * 0.25f;
break; break;
case 2: case 2:
#if WIDESCREEN_SUPPORT #if !TARGET_PC && WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && mDoGph_gInf_c::isWideZoom()) { if (mDoGph_gInf_c::isWide() && mDoGph_gInf_c::isWideZoom()) {
mTrimHeight += (16.0f - mTrimHeight) * 0.25f; mTrimHeight += (16.0f - mTrimHeight) * 0.25f;
break; break;
@@ -3096,10 +3095,6 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
field_0x968 *= mMonitor.field_0xc / 5.0f; 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); f32 tmp = field_0x96c * (mIsWolf == 1 ? 30.0f : 30.0f);
center += vec3.norm() * (tmp * globe.V().Sin()); center += vec3.norm() * (tmp * globe.V().Sin());
cSGlobe globe2(vec2 - center); cSGlobe globe2(vec2 - center);
@@ -3113,10 +3108,6 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
vec = lin_chk1.GetCross(); vec = lin_chk1.GetCross();
} }
#if TARGET_PC
}
#endif
#if DEBUG #if DEBUG
if (mCamSetup.CheckFlag(0x8000)) { if (mCamSetup.CheckFlag(0x8000)) {
dDbVw_Report(20, 235, " U"); dDbVw_Report(20, 235, " U");
@@ -4208,6 +4199,11 @@ bool dCamera_c::chaseCamera(s32 param_0) {
chase->field_0x8 -= chase->field_0xc; chase->field_0x8 -= chase->field_0xc;
chase->field_0x8c = 0; chase->field_0x8c = 0;
chase->field_0x90 = false; chase->field_0x90 = false;
#if TARGET_PC
freeCamera();
#endif
return true; return true;
} }
@@ -4631,10 +4627,6 @@ bool dCamera_c::chaseCamera(s32 param_0) {
sp110 = mViewCache.mDirection.R(); sp110 = mViewCache.mDirection.R();
mViewCache.mDirection.R(mViewCache.mDirection.R() + (fVar55 - mViewCache.mDirection.R()) * chase->field_0x74); 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(); chase->field_0x64 = mViewCache.mCenter + mViewCache.mDirection.Xyz();
mViewCache.mEye = chase->field_0x64; mViewCache.mEye = chase->field_0x64;
@@ -4649,6 +4641,11 @@ bool dCamera_c::chaseCamera(s32 param_0) {
if (chase->field_0x1c != 0) { if (chase->field_0x1c != 0) {
chase->field_0x1c--; chase->field_0x1c--;
} }
#if TARGET_PC
freeCamera();
#endif
return true; return true;
} }
@@ -7096,10 +7093,12 @@ bool dCamera_c::subjectCamera(s32 param_0) {
cXyz sp1E0(val0, val2, val1); cXyz sp1E0(val0, val2, val1);
#if TARGET_PC #if TARGET_PC
f32 aspect = mDoGph_gInf_c::getAspect(); if (sp13) {
f32 baseAspect = FB_WIDTH / FB_HEIGHT; f32 aspect = mDoGph_gInf_c::getAspect();
if (aspect > baseAspect) { f32 baseAspect = FB_WIDTH / FB_HEIGHT;
sp1E0.z += (aspect - baseAspect) * 4; if (aspect > baseAspect) {
sp1E0.z += (aspect - baseAspect) * 4;
}
} }
#endif #endif
@@ -7477,36 +7476,48 @@ bool dCamera_c::test2Camera(s32 param_0) {
#if TARGET_PC #if TARGET_PC
bool dCamera_c::freeCamera() { 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; mCamParam.mManualMode = 0;
return false; 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}; 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); 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 (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) {
if (!mCamParam.mManualMode) { mCamParam.mManualMode = 1;
mCamParam.mManualMode = 1;
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
}
camMovement = camMovement.normalize(); 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;
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 * 5.0f;
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity; mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 5.0f;
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity;
} }
if (mCamParam.mManualMode) { fopAc_ac_c* player = dComIfGp_getPlayer(0);
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, -35.0f, 60.0f); if (!mCamParam.mManualMode || player == nullptr) {
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle); return false;
mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle);
mViewCache.mDirection.mRadius = std::clamp(mCamParam.freeYAngle * 15.0f, 300.0f, 10000.0f);
} }
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 #endif
@@ -11149,12 +11160,25 @@ static int camera_draw(camera_process_class* i_this) {
} }
#endif #endif
int trim_height = body->TrimHeight();
#if TARGET_PC #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; trim_height *= viewport->height / FB_HEIGHT;
window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f); window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f);
#else #else
int trim_height = body->TrimHeight();
window->setScissor(0.0f, trim_height, FB_WIDTH, FB_HEIGHT - trim_height * 2.0f); window->setScissor(0.0f, trim_height, FB_WIDTH, FB_HEIGHT - trim_height * 2.0f);
#endif #endif
+45 -9
View File
@@ -22,6 +22,10 @@
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/gx_helper.h" #include "dusk/gx_helper.h"
#include "dusk/logging.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 #endif
class dDlst_2Dm_c { class dDlst_2Dm_c {
@@ -1062,7 +1066,15 @@ void dDlst_shadowReal_c::reset() {
} }
void dDlst_shadowReal_c::imageDraw(Mtx param_0) { 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); JUT_ASSERT(1916, mModelNum);
J3DModelData* model_data; J3DModelData* model_data;
J3DModel** models = mpModels; J3DModel** models = mpModels;
@@ -1075,7 +1087,15 @@ void dDlst_shadowReal_c::imageDraw(Mtx param_0) {
for (u16 j = 0; j < model_data->getShapeNum(); j++) { for (u16 j = 0; j < model_data->getShapeNum(); j++) {
if (!model_data->getShapeNodePointer(j)->checkFlag(1)) { if (!model_data->getShapeNodePointer(j)->checkFlag(1)) {
shape_pkt = (*models)->getShapePacket(j); 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->drawFast();
shape_pkt->setBaseMtxPtr((Mtx*)param_0); shape_pkt->setBaseMtxPtr((Mtx*)param_0);
} }
@@ -1096,7 +1116,18 @@ void dDlst_shadowReal_c::draw() {
GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetCurrentMtx(GX_PNMTX0); 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(); 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); cMtx_lookAt(mViewMtx, &local_64, param_1, 0);
C_MTXOrtho(mRenderProjMtx, param_2, -param_2, -param_2, param_2, 1.0f, 10000.0f); 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); 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); cMtx_concat(mReceiverProjMtx, mViewMtx, mReceiverProjMtx);
return r29; 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); field_0x1 = setShadowRealMtx(&sp60, param_2, param_3, param_4, param_7, param_5);
if (!field_0x1) { if (!field_0x1) {
@@ -1370,12 +1412,6 @@ void dDlst_shadowSimple_c::draw() {
GXCallDisplayList(l_shadowVolumeDL, 0x40); 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, 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) { s16 param_4, f32 param_5, TGXTexObj* param_6) {
if (param_5 < 0.0f) { if (param_5 < 0.0f) {
+28 -3
View File
@@ -5962,6 +5962,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
fopAc_ac_c* player = dComIfGp_getPlayer(0); fopAc_ac_c* player = dComIfGp_getPlayer(0);
if (evil_packet != NULL) { if (evil_packet != NULL) {
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw2"));
j3dSys.reinitGX(); j3dSys.reinitGX();
if (dComIfGd_getView() != NULL) { if (dComIfGd_getView() != NULL) {
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx); 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); GXSetClipMode(GX_CLIP_ENABLE);
J3DShape::resetVcdVatCache(); J3DShape::resetVcdVatCache();
} }
@@ -6199,6 +6203,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
f32 sp60 = fabsf(cM_ssin(g_Counter.mCounter0 * 215)); f32 sp60 = fabsf(cM_ssin(g_Counter.mCounter0 * 215));
if (evil_packet != NULL) { if (evil_packet != NULL) {
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw"));
j3dSys.reinitGX(); j3dSys.reinitGX();
if (dComIfGd_getView() != NULL) { if (dComIfGd_getView() != NULL) {
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx); MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx);
@@ -6231,8 +6237,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXLoadPosMtxImm(drawMtx, GX_PNMTX0); GXLoadPosMtxImm(drawMtx, GX_PNMTX0);
GXSetCurrentMtx(GX_PNMTX0); GXSetCurrentMtx(GX_PNMTX0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA4, 8);
GXClearVtxDesc(); GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
@@ -6255,6 +6261,19 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXSetClipMode(GX_CLIP_DISABLE); GXSetClipMode(GX_CLIP_DISABLE);
GXSetNumIndStages(0); 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(); dComIfG_Ccsp()->PrepareMass();
for (int i = 0; i < g_env_light.field_0x1054; i++) { 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)); 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); GXSetTevColor(GX_TEVREG1, color_reg1);
spC8 = spA4; spC8 = spA4;
@@ -6412,12 +6431,16 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXBegin(GX_QUADS, GX_VTXFMT0, 4); GXBegin(GX_QUADS, GX_VTXFMT0, 4);
GXPosition3f32(pos[0].x, pos[0].y, pos[0].z); 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); GXTexCoord2s16(0, 0);
GXPosition3f32(pos[1].x, pos[1].y, pos[1].z); 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); GXTexCoord2s16(0xFF, 0);
GXPosition3f32(pos[2].x, pos[2].y, pos[2].z); 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); GXTexCoord2s16(0xFF, 0xFF);
GXPosition3f32(pos[3].x, pos[3].y, pos[3].z); 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); GXTexCoord2s16(0, 0xFF);
GXEnd(); GXEnd();
} }
@@ -6425,6 +6448,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
} }
} }
IF_DUSK(GXPopDebugGroup());
J3DShape::resetVcdVatCache(); J3DShape::resetVcdVatCache();
GXSetClipMode(GX_CLIP_ENABLE); GXSetClipMode(GX_CLIP_ENABLE);
+10 -7
View File
@@ -13,6 +13,9 @@
#include "SSystem/SComponent/c_math.h" #include "SSystem/SComponent/c_math.h"
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
#include "d/d_com_inf_game.h" #include "d/d_com_inf_game.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
#include <cstring> #include <cstring>
#if DEBUG #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 renderingAmap_c::isDrawOutSideTrim() {
bool rt = false; bool rt = false;
#ifdef HYRULE_FIELD_SPEEDHACK #if TARGET_PC
return 0; if (!dusk::getSettings().game.enableMapBackground) {
return 0;
}
#endif #endif
if (getDispType() == 0 || getDispType() == 4 || getDispType() == 3 || getDispType() == 2 || 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() { void dMap_c::_remove() {
if (mImage_p != NULL) { if (mImage_p != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mImage_p);
#endif
JKR_DELETE_ARRAY(mImage_p); JKR_DELETE_ARRAY(mImage_p);
mImage_p = NULL; mImage_p = NULL;
} }
+69 -8
View File
@@ -16,6 +16,7 @@
#ifdef TARGET_PC #ifdef TARGET_PC
constexpr u16 kMapResolutionMultiplier = 4; constexpr u16 kMapResolutionMultiplier = 4;
constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier;
#endif #endif
void dMpath_n::dTexObjAggregate_c::create() { void dMpath_n::dTexObjAggregate_c::create() {
@@ -32,6 +33,48 @@ void dMpath_n::dTexObjAggregate_c::create() {
JUT_ASSERT(74, image->magFilter == GX_NEAR); JUT_ASSERT(74, image->magFilter == GX_NEAR);
mDoLib_setResTimgObj(image, mp_texObj[lp1], 0, NULL); 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() { void dMpath_n::dTexObjAggregate_c::remove() {
@@ -497,12 +540,6 @@ void dRenderingFDAmap_c::postRenderingMap() {
dMpath_n::dTexObjAggregate_c dMpath_n::m_texObjAgg; 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) { void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_line) {
s32 width = getDecorationLineWidth(p_line->field_0x1); s32 width = getDecorationLineWidth(p_line->field_0x1);
if (width <= 0) { if (width <= 0) {
@@ -527,8 +564,32 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
lineColor.r = lineColor.r - 4; lineColor.r = lineColor.r - 4;
GXSetTevColor(GX_TEVREG1, lineColor); 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++) { for (int i = 0; i < data_num; i++) {
#ifndef HYRULE_FIELD_SPEEDHACK
if (i < data_num - 1) { if (i < data_num - 1) {
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); 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, 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); 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); 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); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
#endif
GXBegin(GX_POINTS, GX_VTXFMT0, 1); GXBegin(GX_POINTS, GX_VTXFMT0, 1);
GXPosition1x16(data_p[0]); GXPosition1x16(data_p[0]);
@@ -555,6 +615,7 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
GXEnd(); GXEnd();
data_p++; data_p++;
} }
#endif
setTevSettingNonTextureDirectColor(); setTevSettingNonTextureDirectColor();
GXClearVtxDesc(); GXClearVtxDesc();
+39
View File
@@ -856,7 +856,46 @@ void dMenu_DmapBg_c::decGoldFrameAlphaRate() {
setGoldFrameAlphaRate(rate); 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() { void dMenu_DmapBg_c::draw() {
#if TARGET_PC
dMapBgWide();
#endif
u32 scissor_left; u32 scissor_left;
u32 scissor_top; u32 scissor_top;
u32 scissor_width; u32 scissor_width;
+6
View File
@@ -11,6 +11,9 @@
#include "d/d_menu_dmap_map.h" #include "d/d_menu_dmap_map.h"
#include "f_op/f_op_msg_mng.h" #include "f_op/f_op_msg_mng.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
struct dMdm_HIO_prm_res_dst_s { struct dMdm_HIO_prm_res_dst_s {
static void* m_res; 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() { void dMenu_DmapMap_c::_delete() {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (mMapImage_p[i] != NULL) { if (mMapImage_p[i] != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mMapImage_p[i]);
#endif
JKR_DELETE_ARRAY(mMapImage_p[i]); JKR_DELETE_ARRAY(mMapImage_p[i]);
} }
+34 -1
View File
@@ -20,6 +20,15 @@
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include <cstring> #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() { dMenu_Fmap2DBack_c::dMenu_Fmap2DBack_c() {
dMeter2Info_setMapDrugFlag(0); dMeter2Info_setMapDrugFlag(0);
@@ -267,6 +276,10 @@ dMenu_Fmap2DBack_c::~dMenu_Fmap2DBack_c() {
} }
void dMenu_Fmap2DBack_c::draw() { void dMenu_Fmap2DBack_c::draw() {
#if TARGET_PC
fMapBackWide();
#endif
calcBlink(); calcBlink();
J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort(); J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort();
@@ -1199,7 +1212,7 @@ f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeX() {
} }
f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() { f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() {
#if PLATFORM_GCN && !TARGET_PC #if PLATFORM_GCN
return getMapScissorAreaSizeX(); return getMapScissorAreaSizeX();
#else #else
return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale(); return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale();
@@ -1407,6 +1420,11 @@ void dMenu_Fmap2DBack_c::stageTextureDraw() {
mpSpotTexture->setAlpha(mAlphaRate * 255.0f * field_0xfa8 * mSpotTextureFadeAlpha); 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(), mpSpotTexture->draw(mTransX + getMapScissorAreaLX(), mTransZ + getMapScissorAreaLY(),
getMapScissorAreaSizeRealX(), getMapScissorAreaSizeRealY(), false, false, getMapScissorAreaSizeRealX(), getMapScissorAreaSizeRealY(), false, false,
false); false);
@@ -2179,6 +2197,17 @@ void dMenu_Fmap2DBack_c::setArrowPosAxis(f32 i_posX, f32 i_posZ) {
control_ypos = 0.0f; 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) { dMenu_Fmap2DTop_c::dMenu_Fmap2DTop_c(JKRExpHeap* i_heap, STControl* i_stick) {
mpHeap = i_heap; mpHeap = i_heap;
mTransX = 0.0f; mTransX = 0.0f;
@@ -2572,6 +2601,10 @@ void dMenu_Fmap2DTop_c::setAllAlphaRate(f32 i_rate, bool i_init) {
} }
void dMenu_Fmap2DTop_c::draw() { void dMenu_Fmap2DTop_c::draw() {
#if TARGET_PC
fMapTopWide();
#endif
u32 scissor_left, scissor_top, scissor_width, scissor_height; u32 scissor_left, scissor_top, scissor_width, scissor_height;
J2DOrthoGraph* ctx = static_cast<J2DOrthoGraph*>(dComIfGp_getCurrentGrafPort()); J2DOrthoGraph* ctx = static_cast<J2DOrthoGraph*>(dComIfGp_getCurrentGrafPort());
ctx->setup2D(); ctx->setup2D();
+6
View File
@@ -8,6 +8,9 @@
#include "d/d_debug_viewer.h" #include "d/d_debug_viewer.h"
#include "d/d_menu_fmap_map.h" #include "d/d_menu_fmap_map.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
#include <cstring> #include <cstring>
static u8 twoValueLineInterpolation(u8 i_value1, u8 i_value2, f32 i_param) { static u8 twoValueLineInterpolation(u8 i_value1, u8 i_value2, f32 i_param) {
@@ -494,6 +497,9 @@ void dMenu_FmapMap_c::_delete() {
mResTIMG = NULL; mResTIMG = NULL;
} }
if (mMapImage_p != NULL) { if (mMapImage_p != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mMapImage_p);
#endif
JKR_DELETE_ARRAY(mMapImage_p); JKR_DELETE_ARRAY(mMapImage_p);
mMapImage_p = NULL; mMapImage_p = NULL;
} }
+8
View File
@@ -17,6 +17,10 @@
#include "d/d_msg_scrn_arrow.h" #include "d/d_msg_scrn_arrow.h"
#include "d/d_lib.h" #include "d/d_lib.h"
#ifdef TARGET_PC
#include "dusk/achievements.h"
#endif
#if VERSION == VERSION_GCN_JPN #if VERSION == VERSION_GCN_JPN
#define D_MENU_LETTER_LINE_MAX 9 #define D_MENU_LETTER_LINE_MAX 9
#else #else
@@ -514,6 +518,10 @@ void dMenu_Letter_c::read_open_init() {
setAButtonString(0); setAButtonString(0);
setBButtonString(0); setBButtonString(0);
mpBlackTex->setAlpha(0); mpBlackTex->setAlpha(0);
#ifdef TARGET_PC
dusk::AchievementSystem::get().signal("open_letter");
#endif
} }
void dMenu_Letter_c::read_open_move() { void dMenu_Letter_c::read_open_move() {
+6 -6
View File
@@ -316,6 +316,12 @@ int dMeter2_c::_execute() {
} }
int dMeter2_c::_draw() { int dMeter2_c::_draw() {
#if TARGET_PC
if (dusk::getSettings().game.disableMainHUD) {
return 1;
}
#endif
if (mpMap != NULL) { if (mpMap != NULL) {
mpMap->_draw(); mpMap->_draw();
} }
@@ -424,12 +430,6 @@ void dMeter2_c::setLifeZero() {
void dMeter2_c::checkStatus() { void dMeter2_c::checkStatus() {
mStatus = 0; mStatus = 0;
#if TARGET_PC
if (dusk::getSettings().game.disableMainHUD) {
mStatus |= 0xF0000000;
}
#endif
field_0x12c = field_0x128; field_0x12c = field_0x128;
field_0x128 = daPy_py_c::checkNowWolf(); field_0x128 = daPy_py_c::checkNowWolf();
+4
View File
@@ -2306,6 +2306,10 @@ void dMeter_drawHIO_c::updateOnWide() {
// River Canoe Minigame // River Canoe Minigame
g_drawHIO.mMiniGame.mCounterPosX[1] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mCounterPosX[1]); 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]); 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 #endif
} }
+1 -8
View File
@@ -1987,13 +1987,6 @@ bool jmessage_tSequenceProcessor::do_isReady() {
} }
#endif #endif
#if TARGET_PC
if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) {
field_0xb2 = 1;
pReference->setSendTimer(0);
}
#endif
if (dComIfGp_checkMesgBgm()) { if (dComIfGp_checkMesgBgm()) {
bool isItemMusicPlaying = true; bool isItemMusicPlaying = true;
if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET && if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET &&
@@ -2066,7 +2059,7 @@ bool jmessage_tSequenceProcessor::do_isReady() {
case 0: case 0:
case 5: case 5:
case 6: 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; field_0xa4 = 0;
pReference->onBatchFlag(); pReference->onBatchFlag();
pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX); pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX);
+38 -1
View File
@@ -32,6 +32,9 @@
#if TARGET_PC #if TARGET_PC
#include "dusk/settings.h" #include "dusk/settings.h"
#include <vector>
#include <array>
#include <algorithm>
#endif #endif
static void dMsgObject_addFundRaising(s16 param_0); static void dMsgObject_addFundRaising(s16 param_0);
@@ -1594,7 +1597,7 @@ u8 dMsgObject_c::isSend() {
return 2; return 2;
} }
} else { } 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) { mDoCPd_c::getTrigA(0) != 0 || mDoCPd_c::getTrigB(0) != 0) {
return 2; return 2;
} }
@@ -1866,6 +1869,40 @@ bool dMsgObject_c::isTalkMessage() {
return true; 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() { const char* dMsgObject_c::getSmellName() {
JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20); JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20);
char* data_ptr = (char*)info_header_p + info_header_p->header.size; char* data_ptr = (char*)info_header_p + info_header_p->header.size;
+16 -5
View File
@@ -5,19 +5,20 @@
#include "d/dolzel.h" // IWYU pragma: keep #include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_s_name.h"
#include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRExpHeap.h"
#include "d/d_com_inf_game.h" #include "d/d_com_inf_game.h"
#include "d/d_meter2_info.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 "f_op/f_op_scene_mng.h"
#include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_Reset.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include "m_Do/m_Do_machine.h" #include "m_Do/m_Do_machine.h"
#include "m_Do/m_Do_mtx.h"
#include "m_Do/m_Do_main.h" #include "m_Do/m_Do_main.h"
#include "f_op/f_op_overlap_mng.h" #include "m_Do/m_Do_mtx.h"
#include "dusk/memory.h"
#include "dusk/settings.h"
#if TARGET_PC #if TARGET_PC
#define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen) #define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen)
@@ -412,6 +413,16 @@ void dScnName_c::changeGameScene() {
dKy_clear_game_init(); dKy_clear_game_init();
dComIfGs_resetDan(); dComIfGs_resetDan();
dComIfGs_setRestartRoomParam(0); 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
} }
} }
+19
View File
@@ -41,6 +41,7 @@
#if TARGET_PC #if TARGET_PC
#include "dusk/memory.h" #include "dusk/memory.h"
#include <dusk/autosave.h>
#endif #endif
#if DEBUG #if DEBUG
@@ -700,6 +701,10 @@ static u8 lbl_8074CAE4;
static u32 l_sceneChangeStartTick; static u32 l_sceneChangeStartTick;
#endif #endif
#if TARGET_PC
static BOOL autoSaved;
#endif
static int dScnPly_Execute(dScnPly_c* i_this) { static int dScnPly_Execute(dScnPly_c* i_this) {
#if DEBUG #if DEBUG
fapGm_HIO_c::startCpuTimer(); 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(); dKy_itudemo_se();
#if DEBUG #if DEBUG
@@ -1593,6 +1607,11 @@ static int dScnPly_Create(scene_class* i_this) {
dScnPly_c* a_this = (dScnPly_c*)i_this; dScnPly_c* a_this = (dScnPly_c*)i_this;
int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this); int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this);
#if TARGET_PC
autoSaved = FALSE;
#endif
return phase_state; return phase_state;
} }
+8
View File
@@ -27,7 +27,11 @@
#include "lingcod/lingcod.h" #include "lingcod/lingcod.h"
#endif #endif
#if TARGET_PC
#include "dusk/settings.h" #include "dusk/settings.h"
#include <f_ap/f_ap_game.h>
#include <dusk/autosave.h>
#endif
static u8 dSv_item_rename(u8 i_itemNo) { static u8 dSv_item_rename(u8 i_itemNo) {
switch (i_itemNo) { switch (i_itemNo) {
@@ -345,6 +349,10 @@ void dSv_player_item_c::setItem(int i_slotNo, u8 i_itemNo) {
dComIfGp_setSelectItem(i); dComIfGp_setSelectItem(i);
} }
} }
#if TARGET_PC
triggerAutoSave();
#endif
} }
u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const { u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const {
+91
View File
@@ -0,0 +1,91 @@
#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);
std::string buf(ret, '\0');
vsnprintf(buf.data(), buf.size(), msg, list);
buf.pop_back();
return buf;
}
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
View File
@@ -8,6 +8,7 @@
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
#include "d/d_demo.h" #include "d/d_demo.h"
#include "f_pc/f_pc_name.h" #include "f_pc/f_pc_name.h"
#include "f_op/f_op_actor_mng.h"
#include <filesystem> #include <filesystem>
#include <algorithm> #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", "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", "back_in_time",
@@ -267,18 +335,13 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
false, 0, 0, false false, 0, 0, false
}, },
[](Achievement& a, json&) { [](Achievement& a, json&) {
static int titleNoDemoFrames = 0;
if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) { if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) {
titleNoDemoFrames = 0;
return; return;
} }
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass()); const auto* player = static_cast<const daPy_py_c*>(daPy_getPlayerActorClass());
if (link != nullptr && dDemo_c::getMode() == 0) {
if (++titleNoDemoFrames >= 60) { if (player != nullptr && player->mDemo.getDemoMode() == 1) {
a.progress = 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(); 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) { void AchievementSystem::processEntry(Entry& e) {
if (e.achievement.unlocked) { if (e.achievement.unlocked) {
return; return;
@@ -458,6 +576,7 @@ void AchievementSystem::tick() {
for (auto& e : m_entries) { for (auto& e : m_entries) {
processEntry(e); processEntry(e);
} }
m_signals.clear();
if (m_dirty) { if (m_dirty) {
save(); save();
m_dirty = false; m_dirty = false;
+54
View File
@@ -48,6 +48,20 @@ f32 dusk::audio::MasterVolume = 1.0f;
f32 dusk::audio::PrevMasterVolume = 1.0f; f32 dusk::audio::PrevMasterVolume = 1.0f;
bool dusk::audio::EnableReverb = true; bool dusk::audio::EnableReverb = true;
bool dusk::audio::DumpAudio = false; 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. * 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 = {}; DspSubframe reverbInputR = {};
bool anyReverbInput = false; bool anyReverbInput = false;
DspSubframe surroundBus = {};
bool anySurroundInput = false;
for (int i = 0; i < channels.size(); i++) { for (int i = 0; i < channels.size(); i++) {
auto& channel = channels[i]; auto& channel = channels[i];
auto& channelAux = ChannelAux[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]) { if (DumpAudio && sChannelDumpFiles[i]) {
f32 interleaved[DSP_SUBFRAME_SIZE * 2]; f32 interleaved[DSP_SUBFRAME_SIZE * 2];
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) { for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
@@ -349,6 +381,28 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
ReverbHasTail = wetEnergy >= REVERB_ENERGY_EPSILON; 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) { for (auto& channel : subframe.channels) {
ApplyVolume(channel, channel, PrevMasterVolume, MasterVolume); ApplyVolume(channel, channel, PrevMasterVolume, MasterVolume);
} }
+2
View File
@@ -133,4 +133,6 @@ namespace dusk::audio {
extern f32 PrevMasterVolume; extern f32 PrevMasterVolume;
extern bool EnableReverb; extern bool EnableReverb;
extern bool DumpAudio; extern bool DumpAudio;
extern bool EnableHrtf;
extern f32 HrtfGain;
} }
+88
View File
@@ -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;
}
+20 -3
View File
@@ -76,8 +76,8 @@ void ImGuiAchievements::draw(bool& open) {
return; return;
} }
ImGui::SetNextWindowSizeConstraints(ImVec2(640, 200), ImVec2(800, 900)); ImGui::SetNextWindowSizeConstraints(ImVec2(800, 200), ImVec2(1280, 900));
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(800, 480), ImGuiCond_FirstUseEver);
if (!ImGui::Begin( if (!ImGui::Begin(
"Achievements", &open, "Achievements", &open,
@@ -111,6 +111,7 @@ void ImGuiAchievements::draw(bool& open) {
{AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)}, {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::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)},
{AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 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)}, {AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)},
}; };
@@ -131,7 +132,7 @@ void ImGuiAchievements::draw(bool& open) {
continue; 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); ImGui::PushStyleColor(ImGuiCol_Text, catInfo.color);
const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str()); const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str());
@@ -152,6 +153,7 @@ void ImGuiAchievements::draw(bool& open) {
continue; continue;
} }
ImGui::PushID(a.key); ImGui::PushID(a.key);
ImGui::BeginGroup();
ImGui::PushStyleColor( ImGui::PushStyleColor(
ImGuiCol_Text, ImGuiCol_Text,
@@ -190,6 +192,21 @@ void ImGuiAchievements::draw(bool& open) {
ImGui::PopStyleColor(); 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::Spacing();
ImGui::PopID(); ImGui::PopID();
} }
+74 -1
View File
@@ -1,5 +1,7 @@
#include "ImGuiConsole.hpp" #include "ImGuiConsole.hpp"
#include "ImGuiMenuTools.hpp" #include "ImGuiMenuTools.hpp"
#include <cmath>
#include "JSystem/JAudio2/JAISeq.h"
#include "JSystem/JAudio2/JAISeMgr.h" #include "JSystem/JAudio2/JAISeMgr.h"
#include "JSystem/JAudio2/JAISeqMgr.h" #include "JSystem/JAudio2/JAISeqMgr.h"
#include "JSystem/JAudio2/JAIStreamMgr.h" #include "JSystem/JAudio2/JAIStreamMgr.h"
@@ -15,6 +17,24 @@ static std::array<u32, DSP_CHANNELS> lastResetCounts = {};
static bool sortUpdateCount = true; 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) { static void DisplayDspChannel(int i) {
using namespace dusk::audio; using namespace dusk::audio;
@@ -52,8 +72,10 @@ static void DisplayDspChannel(int i) {
auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f; auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f;
auto volume = VolumeFromU16(channel.mAutoMixerVolume); auto volume = VolumeFromU16(channel.mAutoMixerVolume);
auto pitch = channel.mPitch / 4096.0f; auto pitch = channel.mPitch / 4096.0f;
DrawDirectionGauge(pan, dolby);
ImGui::SameLine();
ImGui::Text( 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); pan, dolby, fxMix, volume, pitch);
} else { } else {
ImGui::Text( ImGui::Text(
@@ -183,6 +205,10 @@ static void ShowAllJAISes() {
if (ImGui::Button("Pause All")) { if (ImGui::Button("Pause All")) {
category->pause(true); category->pause(true);
} }
ImGui::SameLine();
if (ImGui::Button("Resume All")) {
category->pause(false);
}
for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) { for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) {
const auto se = seLink->getObject(); 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() { static void ShowAllJAISeqs() {
auto& mgr = *JAISeqMgr::getInstance(); auto& mgr = *JAISeqMgr::getInstance();
@@ -206,6 +259,26 @@ static void ShowAllJAISeqs() {
if (ImGui::Button("Unpause")) { if (ImGui::Button("Unpause")) {
mgr.pause(false); 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() { void dusk::ImGuiMenuTools::ShowAudioDebug() {
+36 -14
View File
@@ -19,6 +19,7 @@
#include "dusk/config.hpp" #include "dusk/config.hpp"
#include "dusk/dusk.h" #include "dusk/dusk.h"
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/livesplit.h"
#include "dusk/main.h" #include "dusk/main.h"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_controller_pad.h"
@@ -65,6 +66,10 @@ namespace dusk {
ImGui::TextUnformatted(text.data(), text.data() + text.size()); 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) { void ImGuiTextCenter(std::string_view text) {
ImGui::NewLine(); ImGui::NewLine();
float fontSize = ImGui::CalcTextSize( float fontSize = ImGui::CalcTextSize(
@@ -319,18 +324,18 @@ namespace dusk {
ImGuiMenuGame::ToggleFullscreen(); ImGuiMenuGame::ToggleFullscreen();
} }
if (!dusk::IsGameLaunched) { // if (!dusk::IsGameLaunched) {
m_preLaunchWindow.draw(); // m_preLaunchWindow.draw();
} // }
m_isHidden = !getSettings().backend.duskMenuOpen; m_isHidden = !getSettings().backend.duskMenuOpen;
bool showMenu = !dusk::IsGameLaunched || !CheckMenuViewToggle(ImGuiKey_F1, m_isHidden); if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) {
if (dusk::IsGameLaunched) { m_isHidden = !m_isHidden;
const bool menuOpen = !m_isHidden; }
if (getSettings().backend.duskMenuOpen != menuOpen) { bool showMenu = !m_isHidden;
getSettings().backend.duskMenuOpen.setValue(menuOpen); if (getSettings().backend.duskMenuOpen != showMenu) {
Save(); getSettings().backend.duskMenuOpen.setValue(showMenu);
} Save();
} }
// The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg, // The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg,
@@ -360,18 +365,31 @@ namespace dusk {
} }
if (dusk::IsGameLaunched && !m_isLaunchInitialized) { 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 : "Tap to toggle menu"s :
"Press F1 to toggle menu"s, "Press F1 to toggle menu"s,
2.5f); 4.f);
m_isLaunchInitialized = true; m_isLaunchInitialized = true;
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit();
}
} }
UpdateDragScroll(); UpdateDragScroll();
m_menuGame.windowControllerConfig(); m_menuGame.windowControllerConfig();
m_menuGame.windowInputViewer(); 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.ShowDebugOverlay();
m_menuTools.ShowCameraOverlay(); m_menuTools.ShowCameraOverlay();
m_menuTools.ShowProcessManager(); m_menuTools.ShowProcessManager();
@@ -382,8 +400,8 @@ namespace dusk {
m_menuTools.ShowPlayerInfo(); m_menuTools.ShowPlayerInfo();
m_menuTools.ShowAudioDebug(); m_menuTools.ShowAudioDebug();
m_menuTools.ShowSaveEditor(); m_menuTools.ShowSaveEditor();
m_menuTools.ShowStateShare();
} }
m_menuTools.ShowStateShare();
m_menuTools.ShowAchievements(); m_menuTools.ShowAchievements();
DuskDebugPad(); // temporary, remove later DuskDebugPad(); // temporary, remove later
@@ -556,6 +574,10 @@ namespace dusk {
return false; return false;
} }
void ImGuiConsole::AddToast(std::string_view message, float duration) {
m_toasts.emplace_back(std::string(message), duration);
}
void ImGuiConsole::ShowToasts() { void ImGuiConsole::ShowToasts() {
if (m_toasts.empty()) { if (m_toasts.empty()) {
return; return;
+2
View File
@@ -27,6 +27,7 @@ public:
void PostDraw(); void PostDraw();
static bool CheckMenuViewToggle(ImGuiKey key, bool& active); static bool CheckMenuViewToggle(ImGuiKey key, bool& active);
void AddToast(std::string_view message, float duration = 3.f);
private: private:
struct Toast { struct Toast {
@@ -70,6 +71,7 @@ std::string BytesToString(size_t bytes);
void SetOverlayWindowLocation(int corner); void SetOverlayWindowLocation(int corner);
bool ShowCornerContextMenu(int& corner, int avoidCorner); bool ShowCornerContextMenu(int& corner, int avoidCorner);
void ImGuiStringViewText(std::string_view text); 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 ImGuiBeginGroupPanel(const char* name, const ImVec2& size);
void ImGuiEndGroupPanel(); void ImGuiEndGroupPanel();
void ImGuiTextCenter(std::string_view text); void ImGuiTextCenter(std::string_view text);
File diff suppressed because it is too large Load Diff
+2
View File
@@ -30,6 +30,7 @@ static void ApplyPresetHD() {
s.game.biggerWallets.setValue(true); s.game.biggerWallets.setValue(true);
s.game.invertCameraXAxis.setValue(true); s.game.invertCameraXAxis.setValue(true);
s.game.freeCamera.setValue(true); s.game.freeCamera.setValue(true);
s.game.no2ndFishForCat.setValue(true);
} }
static void ApplyPresetDusk() { static void ApplyPresetDusk() {
@@ -43,6 +44,7 @@ static void ApplyPresetDusk() {
s.game.enableFrameInterpolation.setValue(true); s.game.enableFrameInterpolation.setValue(true);
s.game.sunsSong.setValue(true); s.game.sunsSong.setValue(true);
s.game.bloomMode.setValue(BloomMode::Dusk); s.game.bloomMode.setValue(BloomMode::Dusk);
s.game.autoSave.setValue(true);
} }
// ========================================================================= // =========================================================================
+3 -3
View File
@@ -180,9 +180,9 @@ namespace dusk {
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) { void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) {
char title[128]; char title[128];
const char* name = data.Safe ? heap->getName() : "INVALID"; 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(); ImGui::End();
return; return;
} }
@@ -195,7 +195,7 @@ namespace dusk {
heap->lock(); heap->lock();
ImGui::Text("Name: %s", heap->getName()); ImGui::Text("Name: %s", name);
const auto size = BytesToString(heap->getSize()); const auto size = BytesToString(heap->getSize());
const auto freeSize = BytesToString(heap->getFreeSize()); const auto freeSize = BytesToString(heap->getFreeSize());
ImGui::Text("Size: %08X (%s), free: %08X (%s)", heap->getSize(), size.c_str(), heap->getFreeSize(), freeSize.c_str()); ImGui::Text("Size: %08X (%s), free: %08X (%s)", heap->getSize(), size.c_str(), heap->getFreeSize(), freeSize.c_str());
+110 -437
View File
@@ -3,29 +3,14 @@
#include "ImGuiEngine.hpp" #include "ImGuiEngine.hpp"
#include "ImGuiConsole.hpp" #include "ImGuiConsole.hpp"
#include "ImGuiMenuGame.hpp"
#include "ImGuiConfig.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/main.h"
#include "dusk/hotkeys.h" #include "dusk/hotkeys.h"
#include "dusk/settings.h" #include "m_Do/m_Do_main.h"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_graphic.h"
#include <aurora/gfx.h>
#include <SDL3/SDL_gamepad.h> #include <SDL3/SDL_gamepad.h>
namespace {
constexpr int kInternalResolutionScaleMax = 12;
} // namespace
namespace aurora::gx {
extern bool enableLodBias;
}
namespace dusk { namespace dusk {
void ImGuiMenuGame::ToggleFullscreen() { void ImGuiMenuGame::ToggleFullscreen() {
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen); getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
@@ -37,435 +22,17 @@ namespace dusk {
void ImGuiMenuGame::draw() { void ImGuiMenuGame::draw() {
if (ImGui::BeginMenu("Settings")) { if (ImGui::BeginMenu("Settings")) {
drawAudioMenu(); // TODO: Remove this once Controller Config exists in RmlUi
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");
if (ImGui::Button("Configure Controller")){ if (ImGui::Button("Configure Controller")){
m_showControllerConfig = !m_showControllerConfig; 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::Checkbox("Show Input Viewer", &m_showInputViewer);
ImGui::EndMenu(); 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) { static void drawVirtualStick(const char* id, const ImVec2& stick) {
float scale = ImGuiScale(); float scale = ImGuiScale();
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10)); ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10));
@@ -965,7 +532,7 @@ namespace dusk {
ImGui::SameLine(); ImGui::SameLine();
// Options panel // Options panel
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale)); ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1));
if (deadZones != nullptr) { if (deadZones != nullptr) {
if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) { if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) {
@@ -975,9 +542,115 @@ namespace dusk {
PADSerializeMappings(); 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(); ImGuiEndGroupPanel();
ImGui::End(); 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.hyperEnemies.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();
}
} }
+39 -7
View File
@@ -8,6 +8,39 @@
#include "imgui.h" #include "imgui.h"
namespace dusk { 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 { class ImGuiMenuGame {
public: public:
ImGuiMenuGame(); ImGuiMenuGame();
@@ -15,23 +48,20 @@ namespace dusk {
void windowInputViewer(); void windowInputViewer();
void windowControllerConfig(); void windowControllerConfig();
void drawSpeedrunTimerOverlay();
static void ToggleFullscreen(); static void ToggleFullscreen();
private: static void resetForSpeedrunMode();
void drawAudioMenu();
void drawInputMenu();
void drawGraphicsMenu();
void drawGameplayMenu();
void drawCheatsMenu();
void drawInterfaceMenu();
private:
struct { struct {
int m_selectedPort = 0; int m_selectedPort = 0;
bool m_isReading = false; bool m_isReading = false;
PADButtonMapping* m_pendingButtonMapping = nullptr; PADButtonMapping* m_pendingButtonMapping = nullptr;
PADAxisMapping* m_pendingAxisMapping = nullptr; PADAxisMapping* m_pendingAxisMapping = nullptr;
int m_pendingPort = -1; int m_pendingPort = -1;
bool m_isRumbling = false;
} m_controllerConfig; } m_controllerConfig;
bool m_showControllerConfig = false; bool m_showControllerConfig = false;
@@ -40,6 +70,8 @@ namespace dusk {
bool m_showInputViewerGyro = false; bool m_showInputViewerGyro = false;
int m_inputOverlayCorner = 3; int m_inputOverlayCorner = 3;
std::string m_controllerName; std::string m_controllerName;
bool m_showTimerWindow = false;
}; };
} }
+14
View File
@@ -41,6 +41,10 @@ static void OpenDataFolder() {
#define DUSK_CAN_OPEN_DATA_FOLDER 0 #define DUSK_CAN_OPEN_DATA_FOLDER 0
#endif #endif
namespace aurora::gx {
extern bool enableLodBias;
}
namespace dusk { namespace dusk {
ImGuiMenuTools::ImGuiMenuTools() {} ImGuiMenuTools::ImGuiMenuTools() {}
@@ -50,10 +54,14 @@ namespace dusk {
ImGui::BeginDisabled(); ImGui::BeginDisabled();
} }
ImGui::BeginDisabled(getSettings().game.speedrunMode);
ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor); ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor);
ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader); ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader);
ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare); ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare);
ImGui::EndDisabled();
if (!dusk::IsGameLaunched) { if (!dusk::IsGameLaunched) {
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
@@ -71,6 +79,8 @@ namespace dusk {
} }
if (ImGui::BeginMenu("Debug")) { if (ImGui::BeginMenu("Debug")) {
ImGui::BeginDisabled(getSettings().game.speedrunMode);
bool developmentMode = mDoMain::developmentMode == 1; bool developmentMode = mDoMain::developmentMode == 1;
if (ImGui::Checkbox("Development Mode", &developmentMode)) { if (ImGui::Checkbox("Development Mode", &developmentMode)) {
mDoMain::developmentMode = developmentMode ? 1 : -1; mDoMain::developmentMode = developmentMode ? 1 : -1;
@@ -85,6 +95,7 @@ namespace dusk {
getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction); getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction);
config::Save(); config::Save();
} }
ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias);
ImGui::EndMenu(); ImGui::EndMenu();
} }
@@ -119,6 +130,9 @@ namespace dusk {
} }
ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable); ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable);
ImGui::EndDisabled();
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
+13 -11
View File
@@ -75,6 +75,7 @@ void fileDialogCallback(void* userdata, const char* path, const char* error) {
} }
self->m_selectedIsoPath = path; self->m_selectedIsoPath = path;
self->m_isPal = iso::isPal(path);
getSettings().backend.isoPath.setValue(self->m_selectedIsoPath); getSettings().backend.isoPath.setValue(self->m_selectedIsoPath);
config::Save(); config::Save();
} }
@@ -92,6 +93,7 @@ bool ImGuiPreLaunchWindow::isSelectedPathValid() const {
void ImGuiPreLaunchWindow::draw() { void ImGuiPreLaunchWindow::draw() {
if (m_IsFirstDraw) { if (m_IsFirstDraw) {
m_selectedIsoPath = getSettings().backend.isoPath; m_selectedIsoPath = getSettings().backend.isoPath;
m_isPal = !m_selectedIsoPath.empty() && iso::isPal(m_selectedIsoPath.c_str());
m_initialGraphicsBackend = getSettings().backend.graphicsBackend; m_initialGraphicsBackend = getSettings().backend.graphicsBackend;
m_IsFirstDraw = false; m_IsFirstDraw = false;
} }
@@ -193,24 +195,24 @@ void ImGuiPreLaunchWindow::drawOptions() {
ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly); ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly);
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Set")) { if (ImGui::Button(m_selectedIsoPath == "" ? "Set" : "Change")) {
ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(), ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(),
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr, skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr,
false); false);
} }
// TODO: Only show if PAL disc selected? if (m_isPal) {
// Language selection auto selectedLanguage = getSettings().game.language.getValue();
auto selectedLanguage = getSettings().game.language.getValue(); if (ImGui::BeginCombo("Language", skLanguageNames[static_cast<u8>(selectedLanguage)])) {
if (ImGui::BeginCombo("Language", skLanguageNames[static_cast<u8>(selectedLanguage)])) { for (u8 i = 0; i < skLanguageNames.size(); ++i) {
for (u8 i = 0; i < skLanguageNames.size(); ++i) { if (ImGui::Selectable(skLanguageNames[i])) {
if (ImGui::Selectable(skLanguageNames[i])) { getSettings().game.language.setValue(static_cast<GameLanguage>(i));
getSettings().game.language.setValue(static_cast<GameLanguage>(i)); config::Save();
config::Save(); }
} }
}
ImGui::EndCombo(); ImGui::EndCombo();
}
} }
AuroraBackend configuredBackend = BACKEND_AUTO; AuroraBackend configuredBackend = BACKEND_AUTO;
+1
View File
@@ -18,5 +18,6 @@ public:
std::string m_selectedIsoPath; std::string m_selectedIsoPath;
std::string m_errorString; std::string m_errorString;
bool m_isPal = false;
}; };
} // namespace dusk } // namespace dusk
+336 -75
View File
@@ -13,6 +13,7 @@
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
#include <map> #include <map>
#include <bit>
namespace dusk { namespace dusk {
enum ItemType { enum ItemType {
@@ -1295,8 +1296,33 @@ namespace dusk {
membit.offDungeonItem(flag); 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 }); ImGuiBeginGroupPanel("Chest", { 100, 100 });
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
drawFlagList(fmt::format("##_tbox{}", j).c_str(), membit.mTbox[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]); drawFlagList(fmt::format("##_item{}", j).c_str(), membit.mItem[j]);
} }
ImGuiEndGroupPanel(); ImGuiEndGroupPanel();
ImVec2 post_item_custor = ImGui::GetCursorPos();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f); ImGui::SetCursorPos({post_item_custor.x, post_switch_cursor.y});
// genCommonAreaFlags(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);
}
} }
template <typename T> template <typename T>
@@ -1392,74 +1399,326 @@ namespace dusk {
} }
} }
void ImGuiSaveEditor::drawFlagsTab() {
if (ImGui::TreeNode("Current Region Flags")) { static void genAreaFlagTable(uint8_t areaIndex, dSv_memBit_c& membit) {
dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit; constexpr auto makeMask = [](uint8_t size) -> uint16_t { return (1 << size) - 1; };
genMembitFlags("##TempSceneFlags", membit); 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(); const auto eventFlagToAreaFlag = [&](uint16_t areaFlag) -> int {
if (pstag != nullptr) { auto byteInd = getByteIndexFromFlag(areaFlag);
int stageNo = dStage_stagInfo_GetSaveTbl(pstag); constexpr size_t areaIndexSize = 5;
if (ImGui::Button("Save##SaveTempFlags")) { // if we're looking at 0x580, that would be byte 5, and check if 0x80 is set on that byte
dComIfGs_putSave(stageNo); // 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));
} }
} else {
ImGui::SameLine(); if (byteIndex < validTbox) {
membit.offTbox(eventFlagToAreaFlag(flag - tboxConvert));
if (ImGui::Button("Load##LoadSaveFlags")) { } else if (byteIndex < validSwitch) {
dComIfGs_getSave(stageNo); 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(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Region Saved Flags")) { if (ImGui::TreeNode("Region Saved Flags")) {
static std::array<const char*, 27> regionNames = { static const std::map<uint8_t, const char*> regionNames = {
"Ordon", { 0x00, "Ordon" },
"Hyrule Sewers", { 0x01, "Hyrule Sewers" },
"Faron", { 0x02, "Faron" },
"Eldin", { 0x03, "Eldin" },
"Lanayru", { 0x04, "Lanayru" },
"Reserved", { 0x06, "Hyrule Field" },
"Hyrule Field", { 0x07, "Sacred Grove" },
"Sacred Grove", { 0x08, "Snowpeak" },
"Snowpeak", { 0x09, "Castle Town" },
"Castle Town", { 0x0A, "Gerudo Desert" },
"Gerudo Desert", { 0x0B, "Fishing Pond" },
"Fishing Pond", { 0x10, "Forest Temple" },
"Reserved", { 0x11, "Goron Mines" },
"Reserved", { 0x12, "Lakebed Temple" },
"Reserved", { 0x13, "Arbiter's Grounds" },
"Reserved", { 0x14, "Snowpeak Ruins" },
"Forest Temple", { 0x15, "Temple of Time" },
"Goron Mines", { 0x16, "City in the Sky" },
"Lakebed Temple", { 0x17, "Palace of Twilight" },
"Arbiter's Grounds", { 0x18, "Hyrule Castle" },
"Snowpeak Ruins", { 0x19, "Caves" },
"Temple of Time", { 0x1A, "Lake Hylia Long Cave"},
"City in the Sky", { 0x1B, "Grottos" }
"Palace of Twilight",
"Hyrule Castle",
"Caves",
"Grottos",
}; };
if (ImGui::BeginCombo("Region", regionNames[m_selectedRegion])) { if (m_selectedRegion.name == nullptr)
for (int i = 0; i < regionNames.size(); i++) { {
if (strcmp(regionNames[i], "Reserved") == 0) continue; const auto& firstRegion = *regionNames.find(0);
m_selectedRegion = { firstRegion.first, firstRegion.second };
}
if (ImGui::Selectable(regionNames[i])) { if (ImGui::BeginCombo("Region", m_selectedRegion.name)) {
m_selectedRegion = i; for (const auto& [id, name] : regionNames) {
if (ImGui::Selectable(name)) {
m_selectedRegion = {id, name};
} }
} }
ImGui::EndCombo(); ImGui::EndCombo();
} }
dSv_memBit_c* membit = &dComIfGs_getSaveData()->mSave[m_selectedRegion].mBit; dSv_memBit_c& membit = dComIfGs_getSaveData()->mSave[m_selectedRegion.id].mBit;
if (membit != nullptr) {
genMembitFlags("##SaveSceneFlags", *membit); genAreaFlagTable(m_selectedRegion.id, membit);
if (ImGui::TreeNode("Flag Matrix")) {
genMembitFlags("##SaveSceneFlags", membit);
ImGui::TreePop();
} }
ImGui::TreePop(); ImGui::TreePop();
@@ -1530,7 +1789,9 @@ namespace dusk {
} }
for (const auto& e : duskImguiEventFlags) { 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; continue;
} }
+4 -1
View File
@@ -21,7 +21,10 @@ namespace dusk {
void drawConfigTab(); void drawConfigTab();
private: private:
int m_selectedRegion = 0; struct {
uint8_t id;
const char* name;
} m_selectedRegion = {0, nullptr};
}; };
} }
+35
View File
@@ -17,6 +17,11 @@ constexpr const char* TP_GAME_IDS[] = {
"RZDK01", // Wii KOR "RZDK01", // Wii KOR
}; };
constexpr const char* PAL_GAME_IDS[] = {
"GZ2P01", // GCN PAL
"RZDP01", // Wii PAL
};
constexpr const char* SUPPORTED_TP_GAME_IDS[] = { constexpr const char* SUPPORTED_TP_GAME_IDS[] = {
"GZ2E01", // GCN USA "GZ2E01", // GCN USA
"GZ2P01", // GCN PAL "GZ2P01", // GCN PAL
@@ -96,6 +101,10 @@ ValidationError validate(const char* path) {
NodHandleWrapper disc; NodHandleWrapper disc;
const auto sdlStream = SDL_IOFromFile(path, "rb"); const auto sdlStream = SDL_IOFromFile(path, "rb");
if (sdlStream == nullptr) {
return ValidationError::IOError;
}
const NodDiscStream nod_stream { const NodDiscStream nod_stream {
.user_data = sdlStream, .user_data = sdlStream,
.read_at = StreamReadAt, .read_at = StreamReadAt,
@@ -124,4 +133,30 @@ ValidationError validate(const char* path) {
return ValidationError::Success; 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 } // namespace dusk::iso
+1
View File
@@ -13,6 +13,7 @@ namespace dusk::iso {
}; };
ValidationError validate(const char* path); ValidationError validate(const char* path);
bool isPal(const char* path);
} }
#endif // DUSK_ISO_VALIDATE_HPP #endif // DUSK_ISO_VALIDATE_HPP
+183
View File
@@ -0,0 +1,183 @@
#if _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
using socket_t = SOCKET;
static void closeSocket(socket_t s) { closesocket(s); }
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
using socket_t = int;
static void closeSocket(socket_t s) { close(s); }
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#endif
#include <cstdio>
#include "dusk/livesplit.h"
#include "f_op/f_op_overlap_mng.h"
namespace dusk::speedrun {
static bool running = false;
static uint64_t frameCount = 0;
static socket_t sock = INVALID_SOCKET;
static bool wasLoading = false;
static bool connected = false;
static bool connectPending = false;
static bool disconnectPending = false;
static void sendCmd(const char* cmd) {
if (sock == INVALID_SOCKET) {
return;
}
char msg[64];
int len = snprintf(msg, sizeof(msg), "%s\r\n", cmd);
if (send(sock, msg, len, 0) >= 0) {
if (!connected) {
connected = connectPending = true;
}
return;
}
#if _WIN32
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK || err == WSAENOTCONN) {
return;
}
#else
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN) {
return;
}
#endif
if (connected) disconnectPending = true;
closeSocket(sock);
sock = INVALID_SOCKET;
connected = connectPending = false;
}
uint64_t getFrameCount() {
return frameCount;
}
void onGameFrame() {
if (!running) {
return;
}
bool loading = fopOvlpM_IsDoingReq() != 0;
if (loading != wasLoading) {
sendCmd(loading ? "pausegametime" : "unpausegametime");
wasLoading = loading;
}
if (!loading) {
++frameCount;
}
}
void start() {
if (running) {
return;
}
running = true;
frameCount = 0;
wasLoading = false;
sendCmd("initgametime");
sendCmd("reset");
sendCmd("starttimer");
}
void reset() {
running = false;
frameCount = 0;
wasLoading = false;
sendCmd("reset");
}
void connectLiveSplit(const char* host, int port) {
#if _WIN32
WSADATA wd{}; WSAStartup(MAKEWORD(2, 2), &wd);
#endif
if (sock != INVALID_SOCKET) {
closeSocket(sock); sock = INVALID_SOCKET;
}
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
return;
}
#if _WIN32
u_long nb = 1;
ioctlsocket(sock, FIONBIO, &nb);
#else
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
#endif
sockaddr_in addr{}; addr.sin_family = AF_INET;
addr.sin_port = htons((uint16_t)port);
inet_pton(AF_INET, host, &addr.sin_addr);
connect(sock, (sockaddr*)&addr, sizeof(addr));
sendCmd("initgametime");
}
void disconnectLiveSplit() {
if (sock != INVALID_SOCKET) {
closeSocket(sock);
sock = INVALID_SOCKET;
connected = false;
}
}
bool consumeConnectedEvent() { bool v = connectPending; connectPending = false; return v; }
bool consumeDisconnectedEvent() { bool v = disconnectPending; disconnectPending = false; return v; }
void updateLiveSplit() {
if (sock == INVALID_SOCKET) {
return;
}
if (!connected) {
sendCmd("initgametime");
return;
}
if (!running) {
return;
}
const uint64_t totalMs = frameCount * 1000 / 30;
const uint64_t totalSec = totalMs / 1000;
char cmd[32];
snprintf(cmd, sizeof(cmd), "setgametime %u:%02u:%02u.%03u",
(uint32_t)(totalSec / 3600),
(uint32_t)((totalSec / 60) % 60),
(uint32_t)(totalSec % 60),
(uint32_t)(totalMs % 1000)
);
sendCmd(cmd);
}
void shutdown() {
disconnectLiveSplit();
#if _WIN32
WSACleanup();
#endif
}
}
+48 -21
View File
@@ -1,5 +1,6 @@
#include "dusk/logging.h" #include "dusk/logging.h"
#include <array> #include <array>
#include <atomic>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@@ -32,9 +33,33 @@ static constexpr std::string_view StubFragments[] = {
}; };
namespace { namespace {
std::mutex g_logMutex; // On macOS, std::mutex becomes poisoned when its dtor is run.
FILE* g_logFile = nullptr; // We use this to check if the LogState is destroyed before attempting to acquire it.
std::string g_logFilePath; std::atomic g_logStateAlive(true);
struct LogState {
std::mutex mutex;
FILE* file = nullptr;
std::string filePath;
~LogState() {
CloseFile();
g_logStateAlive.store(false, std::memory_order_release);
}
void CloseFile() {
if (!g_logStateAlive.load(std::memory_order_acquire)) {
return;
}
std::lock_guard lock(mutex);
if (file != nullptr) {
std::fflush(file);
std::fclose(file);
file = nullptr;
}
}
};
LogState g_logState;
const char* LogLevelString(AuroraLogLevel level) { const char* LogLevelString(AuroraLogLevel level) {
switch (level) { switch (level) {
@@ -152,10 +177,10 @@ void aurora_log_callback(AuroraLogLevel level, const char* module, const char* m
FILE* out = LogStreamForLevel(level); FILE* out = LogStreamForLevel(level);
WriteLogLine(out, levelStr, module, message, len); WriteLogLine(out, levelStr, module, message, len);
{ if (g_logStateAlive.load(std::memory_order_acquire)) {
std::lock_guard lock(g_logMutex); std::lock_guard lock(g_logState.mutex);
if (g_logFile != nullptr) { if (g_logState.file != nullptr) {
WriteLogLine(g_logFile, levelStr, module, message, len); WriteLogLine(g_logState.file, levelStr, module, message, len);
} }
} }
@@ -169,8 +194,11 @@ void aurora_log_callback(AuroraLogLevel level, const char* module, const char* m
aurora::Module DuskLog("dusk"); aurora::Module DuskLog("dusk");
void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel) { void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel) {
std::lock_guard lock(g_logMutex); if (!g_logStateAlive.load(std::memory_order_acquire)) {
if (g_logFile != nullptr || configDir.empty()) { return;
}
std::lock_guard lock(g_logState.mutex);
if (g_logState.file != nullptr || configDir.empty()) {
return; return;
} }
@@ -184,31 +212,30 @@ void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraL
} }
const std::filesystem::path logPath = logsDir / MakeTimestampedLogName(); const std::filesystem::path logPath = logsDir / MakeTimestampedLogName();
g_logFile = std::fopen(logPath.string().c_str(), "wb"); g_logState.file = std::fopen(logPath.string().c_str(), "wb");
if (g_logFile == nullptr) { if (g_logState.file == nullptr) {
std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n", std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n",
logPath.string().c_str()); logPath.string().c_str());
return; return;
} }
g_logFilePath = logPath.string(); g_logState.filePath = logPath.string();
aurora::g_config.logCallback = &aurora_log_callback; aurora::g_config.logCallback = &aurora_log_callback;
aurora::g_config.logLevel = logLevel; aurora::g_config.logLevel = logLevel;
WriteLogLine(g_logFile, "INFO", "dusk", "File logging initialized", 24); WriteLogLine(g_logState.file, "INFO", "dusk", "File logging initialized", 24);
} }
void dusk::ShutdownFileLogging() { void dusk::ShutdownFileLogging() {
std::lock_guard lock(g_logMutex); if (!g_logStateAlive.load(std::memory_order_acquire)) {
if (g_logFile == nullptr) {
return; return;
} }
g_logState.CloseFile();
std::fflush(g_logFile);
std::fclose(g_logFile);
g_logFile = nullptr;
} }
const char* dusk::GetLogFilePath() { const char* dusk::GetLogFilePath() {
std::lock_guard lock(g_logMutex); if (!g_logStateAlive.load(std::memory_order_acquire)) {
return g_logFilePath.empty() ? nullptr : g_logFilePath.c_str(); return nullptr;
}
std::lock_guard lock(g_logState.mutex);
return g_logState.filePath.empty() ? nullptr : g_logState.filePath.c_str();
} }
+19 -3
View File
@@ -17,6 +17,7 @@ UserSettings g_userSettings = {
.soundEffectsVolume {"audio.soundEffectsVolume", 100}, .soundEffectsVolume {"audio.soundEffectsVolume", 100},
.fanfareVolume {"audio.fanfareVolume", 100}, .fanfareVolume {"audio.fanfareVolume", 100},
.enableReverb {"audio.enableReverb", true}, .enableReverb {"audio.enableReverb", true},
.enableHrtf {"audio.enableHrtf", false},
}, },
.game = { .game = {
@@ -31,14 +32,17 @@ UserSettings g_userSettings = {
.disableRupeeCutscenes {"game.disableRupeeCutscenes", false}, .disableRupeeCutscenes {"game.disableRupeeCutscenes", false},
.noSwordRecoil {"game.noSwordRecoil", false}, .noSwordRecoil {"game.noSwordRecoil", false},
.damageMultiplier {"game.damageMultiplier", 1}, .damageMultiplier {"game.damageMultiplier", 1},
.noHeartDrops{"game.noHeartDrops", false}, .hyperEnemies {"game.hyperEnemies", false},
.noHeartDrops {"game.noHeartDrops", false},
.instantDeath {"game.instantDeath", false}, .instantDeath {"game.instantDeath", false},
.fastClimbing {"game.fastClimbing", false}, .fastClimbing {"game.fastClimbing", false},
.noMissClimbing {"game.noMissClimbing", false}, .noMissClimbing {"game.noMissClimbing", false},
.fastTears {"game.fastTears", false}, .fastTears {"game.fastTears", false},
.no2ndFishForCat {"game.no2ndFishForCat", false},
.instantSaves {"game.instantSaves", false}, .instantSaves {"game.instantSaves", false},
.instantText {"game.instantText", false}, .instantText {"game.instantText", false},
.sunsSong {"game.sunsSong", false}, .sunsSong {"game.sunsSong", false},
.autoSave {"game.autoSave", false},
// Preferences // Preferences
.enableMirrorMode {"game.enableMirrorMode", false}, .enableMirrorMode {"game.enableMirrorMode", false},
@@ -51,10 +55,11 @@ UserSettings g_userSettings = {
.bloomMode {"game.bloomMode", BloomMode::Classic}, .bloomMode {"game.bloomMode", BloomMode::Classic},
.bloomMultiplier {"game.bloomMultiplier", 1.0f}, .bloomMultiplier {"game.bloomMultiplier", 1.0f},
.disableWaterRefraction {"game.disableWaterRefraction", false}, .disableWaterRefraction {"game.disableWaterRefraction", false},
.enableFrameInterpolation = {"game.enableFrameInterpolation", false}, .enableFrameInterpolation {"game.enableFrameInterpolation", false},
.internalResolutionScale {"game.internalResolutionScale", 0}, .internalResolutionScale {"game.internalResolutionScale", 0},
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1}, .shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
.enableDepthOfField {"game.enableDepthOfField", true}, .enableDepthOfField {"game.enableDepthOfField", true},
.enableMapBackground {"game.enableMapBackground", true},
// Audio // Audio
.noLowHpSound {"game.noLowHpSound", false}, .noLowHpSound {"game.noLowHpSound", false},
@@ -95,7 +100,11 @@ UserSettings g_userSettings = {
.restoreWiiGlitches {"game.restoreWiiGlitches", false}, .restoreWiiGlitches {"game.restoreWiiGlitches", false},
// Controls // Controls
.enableTurboKeybind {"game.enableTurboKeybind", false} .enableTurboKeybind {"game.enableTurboKeybind", false},
// Tools
.speedrunMode {"game.speedrunMode", false},
.liveSplitEnabled {"game.liveSplitEnabled", false}
}, },
.backend = { .backend = {
@@ -127,6 +136,7 @@ void registerSettings() {
Register(g_userSettings.audio.soundEffectsVolume); Register(g_userSettings.audio.soundEffectsVolume);
Register(g_userSettings.audio.fanfareVolume); Register(g_userSettings.audio.fanfareVolume);
Register(g_userSettings.audio.enableReverb); Register(g_userSettings.audio.enableReverb);
Register(g_userSettings.audio.enableHrtf);
// Game // Game
Register(g_userSettings.game.language); Register(g_userSettings.game.language);
@@ -138,13 +148,16 @@ void registerSettings() {
Register(g_userSettings.game.disableRupeeCutscenes); Register(g_userSettings.game.disableRupeeCutscenes);
Register(g_userSettings.game.noSwordRecoil); Register(g_userSettings.game.noSwordRecoil);
Register(g_userSettings.game.damageMultiplier); Register(g_userSettings.game.damageMultiplier);
Register(g_userSettings.game.hyperEnemies);
Register(g_userSettings.game.noHeartDrops); Register(g_userSettings.game.noHeartDrops);
Register(g_userSettings.game.instantDeath); Register(g_userSettings.game.instantDeath);
Register(g_userSettings.game.fastClimbing); Register(g_userSettings.game.fastClimbing);
Register(g_userSettings.game.fastTears); Register(g_userSettings.game.fastTears);
Register(g_userSettings.game.no2ndFishForCat);
Register(g_userSettings.game.instantSaves); Register(g_userSettings.game.instantSaves);
Register(g_userSettings.game.instantText); Register(g_userSettings.game.instantText);
Register(g_userSettings.game.sunsSong); Register(g_userSettings.game.sunsSong);
Register(g_userSettings.game.autoSave);
Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.enableMirrorMode);
Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.invertCameraXAxis);
Register(g_userSettings.game.invertCameraYAxis); Register(g_userSettings.game.invertCameraYAxis);
@@ -157,6 +170,7 @@ void registerSettings() {
Register(g_userSettings.game.internalResolutionScale); Register(g_userSettings.game.internalResolutionScale);
Register(g_userSettings.game.shadowResolutionMultiplier); Register(g_userSettings.game.shadowResolutionMultiplier);
Register(g_userSettings.game.enableDepthOfField); Register(g_userSettings.game.enableDepthOfField);
Register(g_userSettings.game.enableMapBackground);
Register(g_userSettings.game.enableFastIronBoots); Register(g_userSettings.game.enableFastIronBoots);
Register(g_userSettings.game.canTransformAnywhere); Register(g_userSettings.game.canTransformAnywhere);
Register(g_userSettings.game.freeMagicArmor); Register(g_userSettings.game.freeMagicArmor);
@@ -167,6 +181,8 @@ void registerSettings() {
Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.noLowHpSound);
Register(g_userSettings.game.midnasLamentNonStop); Register(g_userSettings.game.midnasLamentNonStop);
Register(g_userSettings.game.enableTurboKeybind); Register(g_userSettings.game.enableTurboKeybind);
Register(g_userSettings.game.speedrunMode);
Register(g_userSettings.game.liveSplitEnabled);
Register(g_userSettings.game.fastSpinner); Register(g_userSettings.game.fastSpinner);
Register(g_userSettings.game.infiniteHearts); Register(g_userSettings.game.infiniteHearts);
Register(g_userSettings.game.infiniteArrows); Register(g_userSettings.game.infiniteArrows);
+29
View File
@@ -0,0 +1,29 @@
#include "bool_button.hpp"
namespace dusk::ui {
BoolButton::BoolButton(Rml::Element* parent, Props props)
: BaseControlledSelectButton(parent, {std::move(props.key)}),
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
mIsDisabled(std::move(props.isDisabled)) {}
bool BoolButton::disabled() const {
if (mIsDisabled) {
return mIsDisabled();
}
return BaseControlledSelectButton::disabled();
}
Rml::String BoolButton::format_value() {
return mGetValue() ? "On" : "Off";
}
bool BoolButton::handle_nav_command(NavCommand cmd) {
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || cmd == NavCommand::Right) {
mSetValue(!mGetValue());
return true;
}
return false;
}
} // namespace dusk::ui

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