Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0ae71f7
rotate Discord invite link
FramePerfection Jun 30, 2026
f7b7932
Merge remote-tracking branch 'origin/release-0.8.0' into Development
FramePerfection Jul 3, 2026
5f3021b
Merge pull request #54 from hugou74130/fix/map-popout-gl-rendering
hugou74130 Jul 6, 2026
c216f8e
fix null value treatment in VariableSelectionUtilities.GetNumberValue
FramePerfection Jul 18, 2026
154e5fe
make VariableAngleCell implement INumberVariableCell
FramePerfection Jul 18, 2026
0790099
implement CreateDummyVariable
FramePerfection Jul 18, 2026
9ea1db0
remove unused variable
FramePerfection Jul 18, 2026
eb9c900
Merge pull request #58 from FramePerfection/implement-dummy-variables
FramePerfection Jul 18, 2026
fa4e676
fix geo_switch_mario_cap_effect.asm
FramePerfection Aug 21, 2026
13595b1
make it moveable
FramePerfection Aug 21, 2026
0a3d745
create simple ghost base UI (screw the WinForms designers)
FramePerfection Aug 24, 2026
3fc8891
adjust property casing
FramePerfection Aug 24, 2026
25a59a8
expand 'Ghost Help' 'Notes' page for Usamune use-case
FramePerfection Aug 24, 2026
15f72cc
fix misplaced address for clearing memory
FramePerfection Aug 25, 2026
68c69b1
fix typo
FramePerfection Aug 25, 2026
953c9a1
Merge pull request #62 from FramePerfection/moveable-ghost-hack
FramePerfection Aug 26, 2026
66a4d68
stabilize core loop timing
FramePerfection Aug 1, 2026
ff5b045
fix 2D Distance crash
FramePerfection Aug 31, 2026
8798b88
render all tape measure diffs in all view modes
FramePerfection Aug 31, 2026
414aff0
add UI toggles for shown tape measure dimensions
FramePerfection Aug 31, 2026
faaee66
Decouple map tab view modes
FramePerfection Jul 31, 2026
e8ab1e1
manage multiple views via context menu
FramePerfection Aug 6, 2026
a28ffcb
add view context menu to map popouts as well
FramePerfection Aug 6, 2026
1c0b1c8
update flying controls on all popouts as well
FramePerfection Aug 7, 2026
26c01a5
add hovering capabilities to popouts
FramePerfection Aug 7, 2026
e37439e
chore: update to .NET 10
abart27 May 16, 2026
d0a9c2f
fix workflows
abart27 May 16, 2026
eebd8ca
hush dumb errors
abart27 Jul 6, 2026
5e6edd9
update readme
FramePerfection Sep 4, 2026
35540f6
Merge pull request #52 from FramePerfection/net-10
FramePerfection Sep 4, 2026
71ae6a4
optionally show indicators for non-4/4-quarter-step frames in previou…
FramePerfection Sep 1, 2026
cd8a1c8
Merge pull request #63 from FramePerfection/feat/map-tab-improvements
FramePerfection Sep 18, 2026
c50ef50
add rudimentary object ghost support
FramePerfection Aug 24, 2026
f924ce0
add section about SM64LuaRedux object ghost recording to ghost help
FramePerfection Sep 18, 2026
0bb4947
Merge pull request #60 from FramePerfection/object-ghosts
FramePerfection Sep 18, 2026
50b0a84
send ghosts with no information of a frame 'far' away
FramePerfection Sep 19, 2026
db10555
Merge pull request #68 from FramePerfection/cull-ghosts
FramePerfection Sep 19, 2026
7c8285a
bump version
FramePerfection Sep 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-debug.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# .github/workflows/debug-build.yml
# .github/workflows/debug-build.yml
name: PR Debug Build (Development)

on:
Expand All @@ -16,7 +16,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore
Expand Down
2 changes: 1 addition & 1 deletion HackSources/Ghosts/additional hacks.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<--- Hooks the ghost update function into area_update_objects --->
US:
US:
8027B188: 0C 10 20 00

JP:
Expand Down
8 changes: 8 additions & 0 deletions HackSources/Ghosts/export_moving_code_references.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.create "./build/DynamicOffsets.bin", 0x00000000
.word orga(FirstAnimationBufferAddrHi_LUI_1)
.word orga(GhostBaseHi_LUI_PLUS_1)
.word orga(GhostBaseHi_LUI_1)
.word orga(GhostBaseHi_LUI_2)
.word orga(GhostBaseHi_LUI_3)
.word orga(GhostBaseHi_LUI_4)
.close
25 changes: 13 additions & 12 deletions HackSources/Ghosts/geo_switch_mario_cap_effect.asm
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
.n64

addiu SP, SP, 0xFFF8
lui t9, gBodyStatesAddrHi
addiu t9, t9, gBodyStatesAddrLo
lui t0, gCurGraphNodeObjectHi
lw t0, gCurGraphNodeObjectLo (t0)
lb t2, 0x61 (t0)
beq t2, r0, @@RETURN
lb t1, 0x8 (t8)
sh t1, 0x1E (a1)
lui at, MarioObjectAddrHi
lw at, MarioObjectAddrLo (at)
beq t0, at, @@RETURN
nop
bne t0, at, @@IsGhost

; render Mario as usual
lui t9, gBodyStatesAddrHi
lh t2, gBodyStatesAddrLo + 0x8 (t9)
srl t2, t2, 0x8
beq r0, r0, @@RETURN
sh t2, 0x1e (a1)

@@IsGhost:
; apply the chosen effect from the ghost node
lb t2, 0x61 (t0)
sh t2, 0x1e (a1)

@@RETURN:
or v0, r0, r0
jr ra
addiu SP, SP, 0x0008
or v0, r0, r0
14 changes: 8 additions & 6 deletions HackSources/Ghosts/gfx_generate_colored_hats.asm
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ lui at, MarioObjectAddrHi
lw at, MarioObjectAddrLo (at)
lui t8, gCurGraphNodeObjectHi
lw t8, gCurGraphNodeObjectLo (t8)
beq t8, at, @@SkipGhostRead
beq t8, at, @SkipGhostRead
or t2, r0, r0
lb t2, 0x60 (t8)

@@SkipGhostRead:
@SkipGhostRead:
ori t1, t1, 0x1978

sw t0, 0x18 (sp)
sw t1, 0x1C (sp)
sw t2, 0x20 (sp)
addiu at, r0, 0x1
bne at, a0, @@FinishTheJob
bne at, a0, @FinishTheJob
ori a0, r0, 0x38
jal alloc_display_list
nop
Expand All @@ -32,7 +32,9 @@ lui at, 0x0388
ori at, at, 0x0010
sw at, 0x18 (v0)
sw at, 0x0 (v0)
lui t0, 0x8040

GhostBaseHi_LUI_1:
lui t0, GhostBaseHi ; defined in ghost_loop.asm (included first); with the ori below, must match COLORED_HATS_LIGHTS_ADDR in ColoredHats.cs
ori t0, t0, 0x8300
lw t1, 0x20 (sp)
sll t1, t1, 0x5
Expand All @@ -49,10 +51,10 @@ sw t3, 0xC (v0)
sw t4, 0x28 (v0)
lw t0, 0x1C (sp)

@@FinishTheJob:
@FinishTheJob:
sw t0, 0x2C (v0)
lui at, 0xB800
sw at, 0x30 (v0)
lw ra, 0x14 (sp)
jr ra
addiu sp, sp, 0x40
addiu sp, sp, 0x40
4 changes: 3 additions & 1 deletion HackSources/Ghosts/ghost_hack_JP.asm
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ alloc_display_list equ 0x8027897c

.create "./build/JP_80408200_gfx_generate_colored_hats.bin", 0x00000000
.include "./gfx_generate_colored_hats.asm"
.close
.close

.include "./export_moving_code_references.asm"
4 changes: 3 additions & 1 deletion HackSources/Ghosts/ghost_hack_US.asm
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ alloc_display_list equ 0x80278f2c

.create "./build/US_80408200_gfx_generate_colored_hats.bin", 0x00000000
.include "./gfx_generate_colored_hats.asm"
.close
.close

.include "./export_moving_code_references.asm"
79 changes: 48 additions & 31 deletions HackSources/Ghosts/ghost_loop.asm
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ RegPointerToCurrentGhost equ s1 ; Pointer to the currently processed ghost node
RegProcessedGhostCount equ s0 ; Iteration counter for loops that process all ghosts

; hardcoded offsets
ExtendedRAMStartHi equ 0x8040 ; The Hi part of the address pointing to the start of extended RAM
GhostBaseHi equ 0x8040 ; The Hi part of the address pointing to the start of extended RAM
NumRequestedGhosts equ 0x7FFF ; Offset from extended RAM start to the byte indicating the number of ghosts to display. This value is written by STROOP.
PointerToFirstGhost equ 0x7FF8 ; Offset from extended RAM start to the 4 byte pointer to the first ghost node
NegativeGhostStructSize equ 0xFF98 ; The negative size of a single ghost node, used to iterate ghosts like a reversed array
AnimationBufferSize equ 0x4000 ; The number of bytes reserved for animation data for each ghost
FirstAnimationBufferAddrHi equ 0x8050 ; The Hi part of the address pointing to the animation buffer used by the first ghost
FirstAnimationBufferAddrHi equ GhostBaseHi + 0x10 ; The Hi part of the address pointing to the animation buffer used by the first ghost
InitializedGhostsFlag equ 0x40 ; A custom bit flag that can be set on the Mario object, indicating whether the ghost hack is active

.n64
Expand All @@ -22,7 +22,7 @@ addiu SP, SP, 0xFFC0
; return early if there's no Mario object
lui t0, MarioObjectAddrHi
lw t0, MarioObjectAddrLo (t0)
beq r0, t0, @@EARLY_RETURN
beq r0, t0, @EARLY_RETURN

; push static registers to stack
sw ra, 0x34 (SP)
Expand All @@ -36,20 +36,22 @@ sw RegProcessedGhostCount, 0x20 (SP)
or RegMarioObject, r0, t0
lh t0, 0x2 (RegMarioObject)
andi t1, t0, InitializedGhostsFlag
bnez t1, @@SKIP_INIT
bnez t1, @SKIP_INIT

; set initialized flag on Mario object
ori t1, t0, InitializedGhostsFlag
sh t1, 0x2 (RegMarioObject)
beq r0, r0, @@RETURN
beq r0, r0, @RETURN

; clean up (this can cause failure?)
lui RegPointerToCurrentGhost, ExtendedRAMStartHi
beq r0, r0, @@CLEAN_UP_EARLY
GhostBaseHi_LUI_2:
lui RegPointerToCurrentGhost, GhostBaseHi
beq r0, r0, @CLEAN_UP_EARLY
ori RegPointerToCurrentGhost, RegPointerToCurrentGhost, PointerToFirstGhost
@@SKIP_INIT:
@SKIP_INIT:

; set up dummy Mario struct
FirstAnimationBufferAddrHi_LUI_1:
lui RegAnimationBuffer, FirstAnimationBufferAddrHi
lui t8, 0x8037
ori at, r0, 0xBD
Expand All @@ -61,17 +63,18 @@ sw at, 0x5B8 (t8)

; clean up if no ghosts are requested
or RegProcessedGhostCount, r0, r0
lui at, ExtendedRAMStartHi
GhostBaseHi_LUI_3:
lui at, GhostBaseHi
ori RegPointerToCurrentGhost, at, PointerToFirstGhost
lb at, NumRequestedGhosts (at)
beq r0, at, @@CLEAN_UP_EARLY
beq r0, at, @CLEAN_UP_EARLY
nop

@@ITERATE_GHOSTS:
@ITERATE_GHOSTS:

; skip initialization if ghost already exists
lw t0, 0x0 (RegPointerToCurrentGhost)
bnez t0, @@GHOST_EXISTS
bnez t0, @GHOST_EXISTS

; create a new ghost object graph node
or a0, r0, r0
Expand All @@ -91,7 +94,7 @@ lw a0, 0xC (RegMarioObject)
jal 0x8037C044
or a1, v0, r0

@@GHOST_EXISTS:
@GHOST_EXISTS:

; copy Mario's area and animation ID into the ghost node
lw RegCurrentGhost, 0x0 (RegPointerToCurrentGhost)
Expand All @@ -107,7 +110,9 @@ andi t0, t0, 0x7F
sll t0, t0, 0x5
sll t1, RegProcessedGhostCount, 0xC
addu t0, t0, t1
lui at, 0x8041

GhostBaseHi_LUI_PLUS_1:
lui at, GhostBaseHi + 1 ; +1 because the addiu 0x9B00 below sign-extends; the pair lands at base + 0x9B00
addu t0, t0, at
addiu t0, t0, 0x9B00

Expand All @@ -121,51 +126,63 @@ sw t1, 0x24 (RegCurrentGhost)
lw t1, 0x08 (t0)
sw t1, 0x28 (RegCurrentGhost)

; angles (TODO: store angles as s16 in file?)
lw t1, 0x10 (t0)
; angles
lh t1, 0x10 (t0)
sh t1, 0x1A (RegCurrentGhost)
lw t1, 0x14 (t0)
lh t1, 0x12 (t0)
sh t1, 0x1C (RegCurrentGhost)
lw t1, 0x18 (t0)
lh t1, 0x14 (t0)
sh t1, 0x1E (RegCurrentGhost)

lw t1, 0x18 (t0) ; "graphics" in STROOP
lw t3, 0x0C (t0) ; "animation" in STROOP
bnez t1, @TREAT_AS_OBJECT
lh t2, 0x16 (t0) ; animation frame
; do the hacky thing with Mario animations
lui t8, 0x8037
sw RegCurrentGhost, 0x0580 (t8)
sw RegAnimationBuffer, 0x05C0 (t8)
lh t1, 0x1C (t0)
sh t1, 0x38 (SP)
sh t2, 0x38 (SP)
ori a0, t8, 0x04F8
sh r0, 0x38 (RegCurrentGhost)
sw r0, 0x05BC (t8)
jal set_mario_animation
lw a1, 0xC (t0)
lh t1, 0x38 (SP)
sh t1, 0x40 (RegCurrentGhost)
lh t2, 0x38 (SP)
lui t1, 0x800F
ori t1, t1, 0x0860
beq r0, r0, @COMMON_SETTERS
addiu RegAnimationBuffer, RegAnimationBuffer, AnimationBufferSize
@TREAT_AS_OBJECT:
sw t3, 0x3C (RegCurrentGhost)
@COMMON_SETTERS:
sw t1, 0x14 (RegCurrentGhost)
sh t2, 0x40 (RegCurrentGhost)

; move on to next ghost
addiu RegAnimationBuffer, RegAnimationBuffer, AnimationBufferSize
addiu RegPointerToCurrentGhost, RegPointerToCurrentGhost, NegativeGhostStructSize
addiu RegProcessedGhostCount, RegProcessedGhostCount, 0x1
lui at, ExtendedRAMStartHi

GhostBaseHi_LUI_4:
lui at, GhostBaseHi
lb at, NumRequestedGhosts (at)
sltu t0, RegProcessedGhostCount, at
bnez t0, @@ITERATE_GHOSTS
bnez t0, @ITERATE_GHOSTS
sb RegProcessedGhostCount, 0x60 (RegCurrentGhost)

; delete leftover ghosts
lw RegCurrentGhost, 0x0 (RegPointerToCurrentGhost)
beq RegCurrentGhost, r0, @@RETURN
beq RegCurrentGhost, r0, @RETURN
or a0, r0, RegCurrentGhost
@@CLEAN_UP_LOOP:
@CLEAN_UP_LOOP:
jal 0x8037C0BC
sw r0, 0x0 (RegPointerToCurrentGhost)
@@CLEAN_UP_EARLY:
@CLEAN_UP_EARLY:
lw a0, 0x0 (RegPointerToCurrentGhost)
bnez a0, @@CLEAN_UP_LOOP
bnez a0, @CLEAN_UP_LOOP
addiu RegPointerToCurrentGhost, RegPointerToCurrentGhost, NegativeGhostStructSize

@@RETURN:
@RETURN:

; pop static registers from stack
lw ra, 0x34 (SP)
Expand All @@ -175,6 +192,6 @@ lw RegCurrentGhost, 0x28 (SP)
lw RegPointerToCurrentGhost, 0x24 (SP)
lw RegProcessedGhostCount, 0x20 (SP)

@@EARLY_RETURN:
@EARLY_RETURN:
jr ra
addiu SP, SP, 0x40
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ If this updated feature set doesn't suit your needs, you can of course still get
As of the current build, STROOP has the following system requirements:
* Windows 11 / Windows 10 / Windows 8.1 / Windows 8 / Windows 7 64-bit or 32-bit
* OpenGL 3.2 or greater
* [.NET 8.0 Runtime](https://dotnet.microsoft.com/download/dotnet/8.0) or higher
* [.NET 10.0 Runtime](https://dotnet.microsoft.com/download/dotnet/10.0) or higher
* [Mupen](https://mupen64.com/) is recommended for TASing. (Nemu64 and some other emulators may work, but that's a bit of a shot in the dark)
* 64 Marios (Must be super)
* Marios must be American, Japanese or PAL

## Building

Requirements:
* A [dotnet 8.0 (or higher) SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) in any capacity
* A [dotnet 10.0 (or higher) SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0) in any capacity
* An internet connection for the [NuGet](https://nuget.org) package dependencies, such as OpenTK.

A simple `dotnet build` in the repository root directory will create a debug build.<br>
Expand All @@ -46,17 +46,19 @@ This refactor is ongoing and has diverged severely from the main repository in o

Features from the main branch are partially missing or work in different ways.

I hope to eventually get STROOP back onto a single track again, whether that be the main branch or this fork remains to be seen however. If you are capable and willing to take a heavy load, I'd invite you to discuss details with me on how that should happen on this barebones [Discord](https://discord.gg/QdcwCgXn) server (will adjust as the needs arise).
I hope to eventually get STROOP back onto a single track again, whether that be the main branch or this fork remains to be seen however. If you are capable and willing to take a heavy load, I'd invite you to discuss details with me on how that should happen on this barebones [Discord] server (will adjust as the needs arise).

## Contributing

I'd love to develop this version of STROOP into something that everyone involved with SM64 TASing and beyond can get great value from.<br>
If you are a user of this STROOP version in any capacity, all of your suggestions for improvements will be appreciated (and ideally eventually implemented).<br>
You may submit your feedback either via an [issue](../../issues) or just speak your mind in this barebones [Discord](https://discord.gg/YHgau6tg2d) server.
You may submit your feedback either via an [issue](../../issues) or just speak your mind in this barebones [Discord] server.

If you choose to contribute code via a [pull request](../../pulls), please make an effort to keep your changes free of noise, especially regarding code formatting.<br>
While I do not enforce any specific style and do not intend to do so, the result of `dotnet format` should be taken as a baseline.
**Please don't let your IDE automatically break long lines in edited files!**<br>
These line breaks usually don't facilitate readability at all, and the never-ending war about the "optimal maximum line length" makes it so the noise from added or removed line breaks remains constant in every pull request when different developers with different settings work on the same files.<br>
Particularly, JetBrains Rider has a setting to `Wrap long lines` in the `Editor->Code Style->C#` section, **which I have turned off to prevent it from introducing meaningless line breaks.**<br>
If you feel the need to break long lines for better readability, please do so manually with intent.

[Discord]: https://discord.gg/FAEACwrqEr
Loading
Loading