diff --git a/HackSources/Ghosts/additional hacks.txt b/HackSources/Ghosts/additional hacks.txt index 41aa8165e..8364a9bed 100644 --- a/HackSources/Ghosts/additional hacks.txt +++ b/HackSources/Ghosts/additional hacks.txt @@ -1,5 +1,5 @@ <--- Hooks the ghost update function into area_update_objects ---> -US: +US: 8027B188: 0C 10 20 00 JP: diff --git a/HackSources/Ghosts/export_moving_code_references.asm b/HackSources/Ghosts/export_moving_code_references.asm new file mode 100644 index 000000000..30e144b92 --- /dev/null +++ b/HackSources/Ghosts/export_moving_code_references.asm @@ -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 diff --git a/HackSources/Ghosts/geo_switch_mario_cap_effect.asm b/HackSources/Ghosts/geo_switch_mario_cap_effect.asm index 2d69133d3..269a8f393 100644 --- a/HackSources/Ghosts/geo_switch_mario_cap_effect.asm +++ b/HackSources/Ghosts/geo_switch_mario_cap_effect.asm @@ -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 \ No newline at end of file +or v0, r0, r0 \ No newline at end of file diff --git a/HackSources/Ghosts/gfx_generate_colored_hats.asm b/HackSources/Ghosts/gfx_generate_colored_hats.asm index e0b4642ed..b295447e8 100644 --- a/HackSources/Ghosts/gfx_generate_colored_hats.asm +++ b/HackSources/Ghosts/gfx_generate_colored_hats.asm @@ -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 @@ -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 @@ -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 \ No newline at end of file +addiu sp, sp, 0x40 diff --git a/HackSources/Ghosts/ghost_hack_JP.asm b/HackSources/Ghosts/ghost_hack_JP.asm index c5dd45219..289e82e0e 100644 --- a/HackSources/Ghosts/ghost_hack_JP.asm +++ b/HackSources/Ghosts/ghost_hack_JP.asm @@ -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 \ No newline at end of file +.close + +.include "./export_moving_code_references.asm" diff --git a/HackSources/Ghosts/ghost_hack_US.asm b/HackSources/Ghosts/ghost_hack_US.asm index 3d58cee6b..84c787cc4 100644 --- a/HackSources/Ghosts/ghost_hack_US.asm +++ b/HackSources/Ghosts/ghost_hack_US.asm @@ -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 \ No newline at end of file +.close + +.include "./export_moving_code_references.asm" diff --git a/HackSources/Ghosts/ghost_loop.asm b/HackSources/Ghosts/ghost_loop.asm index 6566928f7..7d213cd96 100644 --- a/HackSources/Ghosts/ghost_loop.asm +++ b/HackSources/Ghosts/ghost_loop.asm @@ -8,7 +8,7 @@ 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 @@ -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) @@ -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 @@ -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 @@ -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) @@ -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 addu t0, t0, at addiu t0, t0, 0x9B00 @@ -147,25 +152,27 @@ sh t1, 0x40 (RegCurrentGhost) 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) @@ -175,6 +182,6 @@ lw RegCurrentGhost, 0x28 (SP) lw RegPointerToCurrentGhost, 0x24 (SP) lw RegProcessedGhostCount, 0x20 (SP) -@@EARLY_RETURN: +@EARLY_RETURN: jr ra addiu SP, SP, 0x40 diff --git a/STROOP/Resources/Hacks/GhostHackJP.hck b/STROOP/Resources/Hacks/GhostHackJP.hck index df2629e62..f83067165 100644 --- a/STROOP/Resources/Hacks/GhostHackJP.hck +++ b/STROOP/Resources/Hacks/GhostHackJP.hck @@ -10,4 +10,4 @@ 80276AF4: 27 BD FF D0 AF BF 00 14 24 01 00 01 14 81 00 1A 00 00 10 25 00 A0 20 25 3C 08 80 34 25 08 A0 40 8C B8 00 18 00 18 C8 80 03 38 C8 21 00 19 C8 C0 03 28 48 21 3C 08 80 33 8D 08 CF A0 3C 01 80 36 8C 21 FD E8 15 01 00 06 85 2C 00 08 31 8D 01 00 11 A0 00 07 34 05 00 FF 10 00 00 05 31 85 00 FF 81 18 00 61 13 00 00 02 34 05 00 FF 34 05 00 7F 0C 09 DA 78 00 00 00 00 8F BF 00 14 03 E0 00 08 27 BD 00 30 -80277128: 27 BD FF F8 3C 19 80 34 27 39 A0 40 3C 08 80 33 8D 08 CF A0 81 0A 00 61 11 40 00 07 83 09 00 08 A4 A9 00 1E 3C 01 80 36 8C 21 FD E8 11 01 00 02 00 00 00 00 A4 AA 00 1E 00 00 10 25 03 E0 00 08 27 BD 00 08 +80277128: 3C 08 80 33 8D 08 CF A0 3C 01 80 36 8C 21 FD E8 15 01 00 05 3C 19 80 34 87 2A A0 48 00 0A 52 02 10 00 00 03 A4 AA 00 1E 81 0A 00 61 A4 AA 00 1E 03 E0 00 08 00 00 10 25 \ No newline at end of file diff --git a/STROOP/Resources/Hacks/GhostHackUS.hck b/STROOP/Resources/Hacks/GhostHackUS.hck index d0067db58..aef9fd76a 100644 --- a/STROOP/Resources/Hacks/GhostHackUS.hck +++ b/STROOP/Resources/Hacks/GhostHackUS.hck @@ -10,4 +10,4 @@ 802770A4: 27 BD FF D0 AF BF 00 14 24 01 00 01 14 81 00 1A 00 00 10 25 00 A0 20 25 3C 08 80 34 25 08 B3 B0 8C B8 00 18 00 18 C8 80 03 38 C8 21 00 19 C8 C0 03 28 48 21 3C 08 80 33 8D 08 DF 00 3C 01 80 36 8C 21 11 58 15 01 00 06 85 2C 00 08 31 8D 01 00 11 A0 00 07 34 05 00 FF 10 00 00 05 31 85 00 FF 81 18 00 61 13 00 00 02 34 05 00 FF 34 05 00 7F 0C 09 DB E4 00 00 00 00 8F BF 00 14 03 E0 00 08 27 BD 00 30 -802776D8: 27 BD FF F8 3C 19 80 34 27 39 B3 B0 3C 08 80 33 8D 08 DF 00 81 0A 00 61 11 40 00 07 83 09 00 08 A4 A9 00 1E 3C 01 80 36 8C 21 11 58 11 01 00 02 00 00 00 00 A4 AA 00 1E 00 00 10 25 03 E0 00 08 27 BD 00 08 +802776D8: 3C 08 80 33 8D 08 DF 00 3C 01 80 36 8C 21 11 58 15 01 00 05 3C 19 80 34 87 2A B3 B8 00 0A 52 02 10 00 00 03 A4 AA 00 1E 81 0A 00 61 A4 AA 00 1E 03 E0 00 08 00 00 10 25 diff --git a/STROOP/Structs/RomHack.cs b/STROOP/Structs/RomHack.cs index 7575a111e..1e912cc62 100644 --- a/STROOP/Structs/RomHack.cs +++ b/STROOP/Structs/RomHack.cs @@ -76,7 +76,7 @@ void LoadHackFromFile(string hackFileName) } while (nextEnd != -1); } - public void LoadPayload() + public void LoadPayload(Dictionary destinationRemap = null) { bool success = true; @@ -85,10 +85,11 @@ public void LoadPayload() using (Config.Stream.Suspend()) { - foreach (var (address, data) in _payload) + foreach (var (originalAddress, data) in _payload) { - // Hacks are entered as big endian; we need to swap the address endianess before writing - var fixedAddress = EndiannessUtilities.SwapAddressEndianness(address, data.Length); + var effectiveAddress = destinationRemap?.GetValueOrDefault(originalAddress, originalAddress) ?? originalAddress; + // Hacks are entered as big endian; we need to swap the address endianess before writing + var fixedAddress = EndiannessUtilities.SwapAddressEndianness(effectiveAddress, data.Length); // Read original memory before replacing _originalMemory.Add(new Tuple(fixedAddress, Config.Stream.ReadRam((UIntPtr)fixedAddress, data.Length, EndiannessType.Big))); diff --git a/STROOP/Tabs/GhostTab/ColoredHats.cs b/STROOP/Tabs/GhostTab/ColoredHats.cs index ea56fd809..14c01c9fd 100644 --- a/STROOP/Tabs/GhostTab/ColoredHats.cs +++ b/STROOP/Tabs/GhostTab/ColoredHats.cs @@ -15,6 +15,8 @@ partial class GhostTab { // <--- static utility and information ---> + const uint COLORED_HATS_CODE_OFFSET = 0x8200u; + private static int defaultGhostColorCounter = 1; private static readonly Vector4[] DefaultGhostColors = new[] @@ -29,17 +31,16 @@ partial class GhostTab new Vector4(0.2f, 0.2f, 0.2f, 1), }; - Vector4 marioHatColor = new Vector4(1, 0, 0, 1); - const uint VANILLA_BANK_04_OFFSET_US = 0x0007EC20; const uint VANILLA_BANK_04_OFFSET_JP = 0x0007BDC0; const uint S_SEGMENT_TABLE_OFFSET_JP = 0x8033a090; const uint S_SEGMENT_TABLE_OFFSET_US = 0x8033b400; - const uint COLORED_HATS_CODE_TARGET_ADDR = 0x80408200; - const uint COLORED_HATS_LIGHTS_ADDR = 0x80408300; + Vector4 marioHatColor = new Vector4(1, 0, 0, 1); + + uint COLORED_HATS_LIGHTS_ADDR => ghostRegionBase + 0x8300u; - private static void EnableColoredHats() + private void EnableColoredHats() { using (Config.Stream.Suspend()) { @@ -68,7 +69,7 @@ private static void EnableColoredHats() var foundPointer = Config.Stream.GetUInt32(addr + 0x14); if (Array.IndexOf(originalDisplayListPointers, foundPointer) != -1) { - Config.Stream.SetValue(COLORED_HATS_CODE_TARGET_ADDR, addr + 0x14); + Config.Stream.SetValue(ghostRegionBase + COLORED_HATS_CODE_OFFSET, addr + 0x14); Config.Stream.SetValue((ushort)0x12A, addr); } } diff --git a/STROOP/Tabs/GhostTab/GhostTab.Designer.cs b/STROOP/Tabs/GhostTab/GhostTab.Designer.cs index 84281af1e..4226058b4 100644 --- a/STROOP/Tabs/GhostTab/GhostTab.Designer.cs +++ b/STROOP/Tabs/GhostTab/GhostTab.Designer.cs @@ -22,513 +22,581 @@ protected override void Dispose(bool disposing) #region Vom Komponenten-Designer generierter Code - /// - /// Erforderliche Methode für die Designerunterstützung. - /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. /// private void InitializeComponent() { - this.groupBoxGhosts = new System.Windows.Forms.GroupBox(); - this.listBoxGhosts = new System.Windows.Forms.ListBox(); - this.buttonMarioColor = new System.Windows.Forms.Button(); - this.buttonWatchGhostFile = new System.Windows.Forms.Button(); - this.buttonLoadGhost = new System.Windows.Forms.Button(); - this.groupBoxGhostInfo = new System.Windows.Forms.GroupBox(); - this.checkTransparentGhosts = new System.Windows.Forms.CheckBox(); - this.buttonGhostColor = new System.Windows.Forms.Button(); - this.textBoxGhostName = new System.Windows.Forms.TextBox(); - this.labelNumFrames = new System.Windows.Forms.Label(); - this.labelName = new System.Windows.Forms.Label(); - this.labelGhostFile = new System.Windows.Forms.Label(); - this.labelGhostPlaybackStart = new System.Windows.Forms.Label(); - this.lblPlaybackOffset = new System.Windows.Forms.Label(); - this.numericUpDownPlaybackOffset = new System.Windows.Forms.NumericUpDown(); - this.labelBaseGlobalTimer = new System.Windows.Forms.Label(); - this.numericUpDownStartOfPlayback = new System.Windows.Forms.NumericUpDown(); - this.buttonSaveGhost = new System.Windows.Forms.Button(); - this.buttonTutorialRecord = new System.Windows.Forms.Button(); - this.groupGhostHack = new System.Windows.Forms.GroupBox(); - this.labelHackActiveState = new System.Windows.Forms.Label(); - this.buttonDisableGhostHack = new System.Windows.Forms.Button(); - this.buttonEnableGhostHack = new System.Windows.Forms.Button(); - this._variablePanelGhost = new STROOP.Controls.VariablePanel.VariablePanel(); - this.groupBoxVariables = new System.Windows.Forms.GroupBox(); - this.groupBoxHelp = new System.Windows.Forms.GroupBox(); - this.buttonTutorialFileWatch = new System.Windows.Forms.Button(); - this.buttonHelpGfxPool = new System.Windows.Forms.Button(); - this.buttonTutorialPlayback = new System.Windows.Forms.Button(); - this.buttonTutorialNotes = new System.Windows.Forms.Button(); - this.groupBoxGfxPool = new System.Windows.Forms.GroupBox(); - this.textBoxPoolSize = new System.Windows.Forms.TextBox(); - this.textBoxPoolAddr2 = new System.Windows.Forms.TextBox(); - this.textBoxPoolAddr1 = new System.Windows.Forms.TextBox(); - this.labelPoolSize = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.labelPool1Address = new System.Windows.Forms.Label(); - this.buttonMoveGfxPool = new System.Windows.Forms.Button(); - this.groupBoxGhosts.SuspendLayout(); - this.groupBoxGhostInfo.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPlaybackOffset)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDownStartOfPlayback)).BeginInit(); - this.groupGhostHack.SuspendLayout(); - this.groupBoxVariables.SuspendLayout(); - this.groupBoxHelp.SuspendLayout(); - this.groupBoxGfxPool.SuspendLayout(); - this.SuspendLayout(); + groupBoxGhosts = new System.Windows.Forms.GroupBox(); + listBoxGhosts = new System.Windows.Forms.ListBox(); + buttonMarioColor = new System.Windows.Forms.Button(); + buttonWatchGhostFile = new System.Windows.Forms.Button(); + buttonLoadGhost = new System.Windows.Forms.Button(); + groupBoxGhostInfo = new System.Windows.Forms.GroupBox(); + checkTransparentGhosts = new System.Windows.Forms.CheckBox(); + buttonGhostColor = new System.Windows.Forms.Button(); + textBoxGhostName = new System.Windows.Forms.TextBox(); + labelNumFrames = new System.Windows.Forms.Label(); + labelName = new System.Windows.Forms.Label(); + labelGhostFile = new System.Windows.Forms.Label(); + labelGhostPlaybackStart = new System.Windows.Forms.Label(); + lblPlaybackOffset = new System.Windows.Forms.Label(); + numericUpDownPlaybackOffset = new System.Windows.Forms.NumericUpDown(); + labelBaseGlobalTimer = new System.Windows.Forms.Label(); + numericUpDownStartOfPlayback = new System.Windows.Forms.NumericUpDown(); + buttonSaveGhost = new System.Windows.Forms.Button(); + buttonTutorialRecord = new System.Windows.Forms.Button(); + groupGhostHack = new System.Windows.Forms.GroupBox(); + labelHackActiveState = new System.Windows.Forms.Label(); + buttonDisableGhostHack = new System.Windows.Forms.Button(); + buttonEnableGhostHack = new System.Windows.Forms.Button(); + _variablePanelGhost = new STROOP.Controls.VariablePanel.VariablePanel(); + groupBoxVariables = new System.Windows.Forms.GroupBox(); + groupBoxHelp = new System.Windows.Forms.GroupBox(); + buttonTutorialFileWatch = new System.Windows.Forms.Button(); + buttonHelpGfxPool = new System.Windows.Forms.Button(); + buttonTutorialPlayback = new System.Windows.Forms.Button(); + buttonTutorialNotes = new System.Windows.Forms.Button(); + groupBoxGfxPool = new System.Windows.Forms.GroupBox(); + textBoxPoolSize = new System.Windows.Forms.TextBox(); + textBoxPoolAddr2 = new System.Windows.Forms.TextBox(); + textBoxPoolAddr1 = new System.Windows.Forms.TextBox(); + labelPoolSize = new System.Windows.Forms.Label(); + label1 = new System.Windows.Forms.Label(); + labelPool1Address = new System.Windows.Forms.Label(); + buttonMoveGfxPool = new System.Windows.Forms.Button(); + lblRAMOffsetBase = new System.Windows.Forms.Label(); + txtRAMOffsetBase = new System.Windows.Forms.TextBox(); + groupBoxGhosts.SuspendLayout(); + groupBoxGhostInfo.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)numericUpDownPlaybackOffset).BeginInit(); + ((System.ComponentModel.ISupportInitialize)numericUpDownStartOfPlayback).BeginInit(); + groupGhostHack.SuspendLayout(); + groupBoxVariables.SuspendLayout(); + groupBoxHelp.SuspendLayout(); + groupBoxGfxPool.SuspendLayout(); + SuspendLayout(); // // groupBoxGhosts // - this.groupBoxGhosts.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBoxGhosts.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.groupBoxGhosts.Controls.Add(this.listBoxGhosts); - this.groupBoxGhosts.Controls.Add(this.buttonMarioColor); - this.groupBoxGhosts.Controls.Add(this.buttonWatchGhostFile); - this.groupBoxGhosts.Controls.Add(this.buttonLoadGhost); - this.groupBoxGhosts.Controls.Add(this.groupBoxGhostInfo); - this.groupBoxGhosts.Controls.Add(this.buttonSaveGhost); - this.groupBoxGhosts.Location = new System.Drawing.Point(170, 3); - this.groupBoxGhosts.Name = "groupBoxGhosts"; - this.groupBoxGhosts.Size = new System.Drawing.Size(515, 457); - this.groupBoxGhosts.TabIndex = 2; - this.groupBoxGhosts.TabStop = false; - this.groupBoxGhosts.Text = "Ghosts"; + groupBoxGhosts.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)); + groupBoxGhosts.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + groupBoxGhosts.Controls.Add(listBoxGhosts); + groupBoxGhosts.Controls.Add(buttonMarioColor); + groupBoxGhosts.Controls.Add(buttonWatchGhostFile); + groupBoxGhosts.Controls.Add(buttonLoadGhost); + groupBoxGhosts.Controls.Add(groupBoxGhostInfo); + groupBoxGhosts.Controls.Add(buttonSaveGhost); + groupBoxGhosts.Location = new System.Drawing.Point(198, 3); + groupBoxGhosts.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxGhosts.Name = "groupBoxGhosts"; + groupBoxGhosts.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxGhosts.Size = new System.Drawing.Size(601, 527); + groupBoxGhosts.TabIndex = 2; + groupBoxGhosts.TabStop = false; + groupBoxGhosts.Text = "Ghosts"; // // listBoxGhosts // - this.listBoxGhosts.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.listBoxGhosts.FormattingEnabled = true; - this.listBoxGhosts.Location = new System.Drawing.Point(9, 12); - this.listBoxGhosts.Name = "listBoxGhosts"; - this.listBoxGhosts.Size = new System.Drawing.Size(350, 316); - this.listBoxGhosts.TabIndex = 5; - this.listBoxGhosts.SelectedIndexChanged += new System.EventHandler(this.listBoxGhosts_SelectedIndexChanged); + listBoxGhosts.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)); + listBoxGhosts.FormattingEnabled = true; + listBoxGhosts.ItemHeight = 15; + listBoxGhosts.Location = new System.Drawing.Point(10, 14); + listBoxGhosts.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + listBoxGhosts.Name = "listBoxGhosts"; + listBoxGhosts.Size = new System.Drawing.Size(408, 364); + listBoxGhosts.TabIndex = 5; + listBoxGhosts.SelectedIndexChanged += listBoxGhosts_SelectedIndexChanged; // // buttonMarioColor // - this.buttonMarioColor.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonMarioColor.BackColor = System.Drawing.Color.Red; - this.buttonMarioColor.Location = new System.Drawing.Point(365, 118); - this.buttonMarioColor.Name = "buttonMarioColor"; - this.buttonMarioColor.Size = new System.Drawing.Size(115, 23); - this.buttonMarioColor.TabIndex = 5; - this.buttonMarioColor.Text = "Main Mario Color"; - this.buttonMarioColor.UseVisualStyleBackColor = false; - this.buttonMarioColor.Click += new System.EventHandler(this.buttonMarioColor_Click); + buttonMarioColor.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)); + buttonMarioColor.BackColor = System.Drawing.Color.Red; + buttonMarioColor.Location = new System.Drawing.Point(426, 136); + buttonMarioColor.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonMarioColor.Name = "buttonMarioColor"; + buttonMarioColor.Size = new System.Drawing.Size(134, 27); + buttonMarioColor.TabIndex = 5; + buttonMarioColor.Text = "Main Mario Color"; + buttonMarioColor.UseVisualStyleBackColor = false; + buttonMarioColor.Click += buttonMarioColor_Click; // // buttonWatchGhostFile // - this.buttonWatchGhostFile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonWatchGhostFile.Location = new System.Drawing.Point(365, 12); - this.buttonWatchGhostFile.Name = "buttonWatchGhostFile"; - this.buttonWatchGhostFile.Size = new System.Drawing.Size(143, 23); - this.buttonWatchGhostFile.TabIndex = 0; - this.buttonWatchGhostFile.Text = "Edit File Watch List"; - this.buttonWatchGhostFile.UseVisualStyleBackColor = true; - this.buttonWatchGhostFile.Click += new System.EventHandler(this.buttonWatchGhostFile_Click); + buttonWatchGhostFile.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)); + buttonWatchGhostFile.Location = new System.Drawing.Point(426, 14); + buttonWatchGhostFile.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonWatchGhostFile.Name = "buttonWatchGhostFile"; + buttonWatchGhostFile.Size = new System.Drawing.Size(167, 27); + buttonWatchGhostFile.TabIndex = 0; + buttonWatchGhostFile.Text = "Edit File Watch List"; + buttonWatchGhostFile.UseVisualStyleBackColor = true; + buttonWatchGhostFile.Click += buttonWatchGhostFile_Click; // // buttonLoadGhost // - this.buttonLoadGhost.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonLoadGhost.Location = new System.Drawing.Point(365, 60); - this.buttonLoadGhost.Name = "buttonLoadGhost"; - this.buttonLoadGhost.Size = new System.Drawing.Size(143, 23); - this.buttonLoadGhost.TabIndex = 0; - this.buttonLoadGhost.Text = "Load Ghost"; - this.buttonLoadGhost.UseVisualStyleBackColor = true; - this.buttonLoadGhost.Click += new System.EventHandler(this.buttonLoadGhost_Click); + buttonLoadGhost.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)); + buttonLoadGhost.Location = new System.Drawing.Point(426, 69); + buttonLoadGhost.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonLoadGhost.Name = "buttonLoadGhost"; + buttonLoadGhost.Size = new System.Drawing.Size(167, 27); + buttonLoadGhost.TabIndex = 0; + buttonLoadGhost.Text = "Load Ghost"; + buttonLoadGhost.UseVisualStyleBackColor = true; + buttonLoadGhost.Click += buttonLoadGhost_Click; // // groupBoxGhostInfo // - this.groupBoxGhostInfo.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBoxGhostInfo.Controls.Add(this.checkTransparentGhosts); - this.groupBoxGhostInfo.Controls.Add(this.buttonGhostColor); - this.groupBoxGhostInfo.Controls.Add(this.textBoxGhostName); - this.groupBoxGhostInfo.Controls.Add(this.labelNumFrames); - this.groupBoxGhostInfo.Controls.Add(this.labelName); - this.groupBoxGhostInfo.Controls.Add(this.labelGhostFile); - this.groupBoxGhostInfo.Controls.Add(this.labelGhostPlaybackStart); - this.groupBoxGhostInfo.Controls.Add(this.lblPlaybackOffset); - this.groupBoxGhostInfo.Controls.Add(this.numericUpDownPlaybackOffset); - this.groupBoxGhostInfo.Controls.Add(this.labelBaseGlobalTimer); - this.groupBoxGhostInfo.Controls.Add(this.numericUpDownStartOfPlayback); - this.groupBoxGhostInfo.Location = new System.Drawing.Point(9, 343); - this.groupBoxGhostInfo.Name = "groupBoxGhostInfo"; - this.groupBoxGhostInfo.Size = new System.Drawing.Size(499, 108); - this.groupBoxGhostInfo.TabIndex = 1; - this.groupBoxGhostInfo.TabStop = false; - this.groupBoxGhostInfo.Text = "Ghost Info"; + groupBoxGhostInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)); + groupBoxGhostInfo.Controls.Add(checkTransparentGhosts); + groupBoxGhostInfo.Controls.Add(buttonGhostColor); + groupBoxGhostInfo.Controls.Add(textBoxGhostName); + groupBoxGhostInfo.Controls.Add(labelNumFrames); + groupBoxGhostInfo.Controls.Add(labelName); + groupBoxGhostInfo.Controls.Add(labelGhostFile); + groupBoxGhostInfo.Controls.Add(labelGhostPlaybackStart); + groupBoxGhostInfo.Controls.Add(lblPlaybackOffset); + groupBoxGhostInfo.Controls.Add(numericUpDownPlaybackOffset); + groupBoxGhostInfo.Controls.Add(labelBaseGlobalTimer); + groupBoxGhostInfo.Controls.Add(numericUpDownStartOfPlayback); + groupBoxGhostInfo.Location = new System.Drawing.Point(10, 396); + groupBoxGhostInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxGhostInfo.Name = "groupBoxGhostInfo"; + groupBoxGhostInfo.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxGhostInfo.Size = new System.Drawing.Size(582, 125); + groupBoxGhostInfo.TabIndex = 1; + groupBoxGhostInfo.TabStop = false; + groupBoxGhostInfo.Text = "Ghost Info"; // // checkTransparentGhosts // - this.checkTransparentGhosts.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.checkTransparentGhosts.AutoSize = true; - this.checkTransparentGhosts.CheckAlign = System.Drawing.ContentAlignment.MiddleRight; - this.checkTransparentGhosts.Checked = true; - this.checkTransparentGhosts.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkTransparentGhosts.Location = new System.Drawing.Point(374, 15); - this.checkTransparentGhosts.Name = "checkTransparentGhosts"; - this.checkTransparentGhosts.Size = new System.Drawing.Size(119, 17); - this.checkTransparentGhosts.TabIndex = 6; - this.checkTransparentGhosts.Text = "Transparent Ghosts"; - this.checkTransparentGhosts.UseVisualStyleBackColor = true; - this.checkTransparentGhosts.CheckedChanged += new System.EventHandler(this.checkTransparentGhosts_CheckedChanged); + checkTransparentGhosts.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)); + checkTransparentGhosts.AutoSize = true; + checkTransparentGhosts.CheckAlign = System.Drawing.ContentAlignment.MiddleRight; + checkTransparentGhosts.Checked = true; + checkTransparentGhosts.CheckState = System.Windows.Forms.CheckState.Checked; + checkTransparentGhosts.Location = new System.Drawing.Point(449, 17); + checkTransparentGhosts.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + checkTransparentGhosts.Name = "checkTransparentGhosts"; + checkTransparentGhosts.Size = new System.Drawing.Size(126, 19); + checkTransparentGhosts.TabIndex = 6; + checkTransparentGhosts.Text = "Transparent Ghosts"; + checkTransparentGhosts.UseVisualStyleBackColor = true; + checkTransparentGhosts.CheckedChanged += checkTransparentGhosts_CheckedChanged; // // buttonGhostColor // - this.buttonGhostColor.Enabled = false; - this.buttonGhostColor.Location = new System.Drawing.Point(156, 11); - this.buttonGhostColor.Name = "buttonGhostColor"; - this.buttonGhostColor.Size = new System.Drawing.Size(49, 23); - this.buttonGhostColor.TabIndex = 5; - this.buttonGhostColor.Text = "Color"; - this.buttonGhostColor.UseVisualStyleBackColor = true; - this.buttonGhostColor.Click += new System.EventHandler(this.buttonGhostColor_Click); + buttonGhostColor.Enabled = false; + buttonGhostColor.Location = new System.Drawing.Point(182, 13); + buttonGhostColor.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonGhostColor.Name = "buttonGhostColor"; + buttonGhostColor.Size = new System.Drawing.Size(57, 27); + buttonGhostColor.TabIndex = 5; + buttonGhostColor.Text = "Color"; + buttonGhostColor.UseVisualStyleBackColor = true; + buttonGhostColor.Click += buttonGhostColor_Click; // // textBoxGhostName // - this.textBoxGhostName.Location = new System.Drawing.Point(50, 13); - this.textBoxGhostName.Name = "textBoxGhostName"; - this.textBoxGhostName.Size = new System.Drawing.Size(100, 20); - this.textBoxGhostName.TabIndex = 4; - this.textBoxGhostName.TextChanged += new System.EventHandler(this.textBoxGhostName_TextChanged); + textBoxGhostName.Location = new System.Drawing.Point(58, 15); + textBoxGhostName.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + textBoxGhostName.Name = "textBoxGhostName"; + textBoxGhostName.Size = new System.Drawing.Size(116, 23); + textBoxGhostName.TabIndex = 4; + textBoxGhostName.TextChanged += textBoxGhostName_TextChanged; // // labelNumFrames // - this.labelNumFrames.AutoSize = true; - this.labelNumFrames.Location = new System.Drawing.Point(6, 53); - this.labelNumFrames.Name = "labelNumFrames"; - this.labelNumFrames.Size = new System.Drawing.Size(93, 13); - this.labelNumFrames.TabIndex = 3; - this.labelNumFrames.Text = "Number of frames:"; + labelNumFrames.AutoSize = true; + labelNumFrames.Location = new System.Drawing.Point(7, 61); + labelNumFrames.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelNumFrames.Name = "labelNumFrames"; + labelNumFrames.Size = new System.Drawing.Size(107, 15); + labelNumFrames.TabIndex = 3; + labelNumFrames.Text = "Number of frames:"; // // labelName // - this.labelName.AutoSize = true; - this.labelName.Location = new System.Drawing.Point(6, 16); - this.labelName.Name = "labelName"; - this.labelName.Size = new System.Drawing.Size(38, 13); - this.labelName.TabIndex = 3; - this.labelName.Text = "Name:"; + labelName.AutoSize = true; + labelName.Location = new System.Drawing.Point(7, 18); + labelName.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelName.Name = "labelName"; + labelName.Size = new System.Drawing.Size(42, 15); + labelName.TabIndex = 3; + labelName.Text = "Name:"; // // labelGhostFile // - this.labelGhostFile.AutoSize = true; - this.labelGhostFile.Location = new System.Drawing.Point(6, 40); - this.labelGhostFile.Name = "labelGhostFile"; - this.labelGhostFile.Size = new System.Drawing.Size(26, 13); - this.labelGhostFile.TabIndex = 3; - this.labelGhostFile.Text = "File:"; + labelGhostFile.AutoSize = true; + labelGhostFile.Location = new System.Drawing.Point(7, 46); + labelGhostFile.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelGhostFile.Name = "labelGhostFile"; + labelGhostFile.Size = new System.Drawing.Size(28, 15); + labelGhostFile.TabIndex = 3; + labelGhostFile.Text = "File:"; // // labelGhostPlaybackStart // - this.labelGhostPlaybackStart.AutoSize = true; - this.labelGhostPlaybackStart.Location = new System.Drawing.Point(6, 66); - this.labelGhostPlaybackStart.Name = "labelGhostPlaybackStart"; - this.labelGhostPlaybackStart.Size = new System.Drawing.Size(117, 13); - this.labelGhostPlaybackStart.TabIndex = 3; - this.labelGhostPlaybackStart.Text = "Original Playback Start:"; + labelGhostPlaybackStart.AutoSize = true; + labelGhostPlaybackStart.Location = new System.Drawing.Point(7, 76); + labelGhostPlaybackStart.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelGhostPlaybackStart.Name = "labelGhostPlaybackStart"; + labelGhostPlaybackStart.Size = new System.Drawing.Size(129, 15); + labelGhostPlaybackStart.TabIndex = 3; + labelGhostPlaybackStart.Text = "Original Playback Start:"; // // lblPlaybackOffset // - this.lblPlaybackOffset.AutoSize = true; - this.lblPlaybackOffset.Location = new System.Drawing.Point(291, 88); - this.lblPlaybackOffset.Name = "lblPlaybackOffset"; - this.lblPlaybackOffset.Size = new System.Drawing.Size(83, 13); - this.lblPlaybackOffset.TabIndex = 3; - this.lblPlaybackOffset.Text = "Playback offset:"; + lblPlaybackOffset.AutoSize = true; + lblPlaybackOffset.Location = new System.Drawing.Point(340, 102); + lblPlaybackOffset.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + lblPlaybackOffset.Name = "lblPlaybackOffset"; + lblPlaybackOffset.Size = new System.Drawing.Size(90, 15); + lblPlaybackOffset.TabIndex = 3; + lblPlaybackOffset.Text = "Playback offset:"; // // numericUpDownPlaybackOffset // - this.numericUpDownPlaybackOffset.Location = new System.Drawing.Point(379, 86); - this.numericUpDownPlaybackOffset.Maximum = new decimal(new int[] { - -1, - 0, - 0, - 0}); - this.numericUpDownPlaybackOffset.Minimum = new decimal(new int[] { - -1, - 0, - 0, - -2147483648}); - this.numericUpDownPlaybackOffset.Name = "numericUpDownPlaybackOffset"; - this.numericUpDownPlaybackOffset.Size = new System.Drawing.Size(92, 20); - this.numericUpDownPlaybackOffset.TabIndex = 2; - this.numericUpDownPlaybackOffset.ValueChanged += new System.EventHandler(this.numericUpDownPlaybakcOffset_ValueChanged); + numericUpDownPlaybackOffset.Location = new System.Drawing.Point(442, 99); + numericUpDownPlaybackOffset.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + numericUpDownPlaybackOffset.Maximum = new decimal(new int[] + { + -1, + 0, + 0, + 0 + }); + numericUpDownPlaybackOffset.Minimum = new decimal(new int[] + { + -1, + 0, + 0, + -2147483648 + }); + numericUpDownPlaybackOffset.Name = "numericUpDownPlaybackOffset"; + numericUpDownPlaybackOffset.Size = new System.Drawing.Size(107, 23); + numericUpDownPlaybackOffset.TabIndex = 2; + numericUpDownPlaybackOffset.ValueChanged += numericUpDownPlaybakcOffset_ValueChanged; // // labelBaseGlobalTimer // - this.labelBaseGlobalTimer.AutoSize = true; - this.labelBaseGlobalTimer.Location = new System.Drawing.Point(6, 88); - this.labelBaseGlobalTimer.Name = "labelBaseGlobalTimer"; - this.labelBaseGlobalTimer.Size = new System.Drawing.Size(153, 13); - this.labelBaseGlobalTimer.TabIndex = 3; - this.labelBaseGlobalTimer.Text = "Start Playback at Global Timer:"; + labelBaseGlobalTimer.AutoSize = true; + labelBaseGlobalTimer.Location = new System.Drawing.Point(7, 102); + labelBaseGlobalTimer.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelBaseGlobalTimer.Name = "labelBaseGlobalTimer"; + labelBaseGlobalTimer.Size = new System.Drawing.Size(167, 15); + labelBaseGlobalTimer.TabIndex = 3; + labelBaseGlobalTimer.Text = "Start Playback at Global Timer:"; // // numericUpDownStartOfPlayback // - this.numericUpDownStartOfPlayback.Location = new System.Drawing.Point(165, 86); - this.numericUpDownStartOfPlayback.Maximum = new decimal(new int[] { - -1, - 0, - 0, - 0}); - this.numericUpDownStartOfPlayback.Name = "numericUpDownStartOfPlayback"; - this.numericUpDownStartOfPlayback.Size = new System.Drawing.Size(120, 20); - this.numericUpDownStartOfPlayback.TabIndex = 2; - this.numericUpDownStartOfPlayback.ValueChanged += new System.EventHandler(this.numericUpDownStartOfPlayback_ValueChanged); + numericUpDownStartOfPlayback.Location = new System.Drawing.Point(192, 99); + numericUpDownStartOfPlayback.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + numericUpDownStartOfPlayback.Maximum = new decimal(new int[] + { + -1, + 0, + 0, + 0 + }); + numericUpDownStartOfPlayback.Name = "numericUpDownStartOfPlayback"; + numericUpDownStartOfPlayback.Size = new System.Drawing.Size(140, 23); + numericUpDownStartOfPlayback.TabIndex = 2; + numericUpDownStartOfPlayback.ValueChanged += numericUpDownStartOfPlayback_ValueChanged; // // buttonSaveGhost // - this.buttonSaveGhost.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonSaveGhost.Location = new System.Drawing.Point(365, 89); - this.buttonSaveGhost.Name = "buttonSaveGhost"; - this.buttonSaveGhost.Size = new System.Drawing.Size(143, 23); - this.buttonSaveGhost.TabIndex = 0; - this.buttonSaveGhost.Text = "Save Selected"; - this.buttonSaveGhost.UseVisualStyleBackColor = true; - this.buttonSaveGhost.Click += new System.EventHandler(this.buttonSaveGhost_Click); + buttonSaveGhost.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)); + buttonSaveGhost.Location = new System.Drawing.Point(426, 103); + buttonSaveGhost.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonSaveGhost.Name = "buttonSaveGhost"; + buttonSaveGhost.Size = new System.Drawing.Size(167, 27); + buttonSaveGhost.TabIndex = 0; + buttonSaveGhost.Text = "Save Selected"; + buttonSaveGhost.UseVisualStyleBackColor = true; + buttonSaveGhost.Click += buttonSaveGhost_Click; // // buttonTutorialRecord // - this.buttonTutorialRecord.Location = new System.Drawing.Point(9, 52); - this.buttonTutorialRecord.Name = "buttonTutorialRecord"; - this.buttonTutorialRecord.Size = new System.Drawing.Size(146, 23); - this.buttonTutorialRecord.TabIndex = 7; - this.buttonTutorialRecord.Text = "Recording Ghosts"; - this.buttonTutorialRecord.UseVisualStyleBackColor = true; - this.buttonTutorialRecord.Click += new System.EventHandler(this.buttonTutorialRecord_Click); + buttonTutorialRecord.Location = new System.Drawing.Point(10, 60); + buttonTutorialRecord.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonTutorialRecord.Name = "buttonTutorialRecord"; + buttonTutorialRecord.Size = new System.Drawing.Size(170, 27); + buttonTutorialRecord.TabIndex = 7; + buttonTutorialRecord.Text = "Recording Ghosts"; + buttonTutorialRecord.UseVisualStyleBackColor = true; + buttonTutorialRecord.Click += buttonTutorialRecord_Click; // // groupGhostHack // - this.groupGhostHack.Controls.Add(this.labelHackActiveState); - this.groupGhostHack.Controls.Add(this.buttonDisableGhostHack); - this.groupGhostHack.Controls.Add(this.buttonEnableGhostHack); - this.groupGhostHack.Location = new System.Drawing.Point(3, 3); - this.groupGhostHack.Name = "groupGhostHack"; - this.groupGhostHack.Size = new System.Drawing.Size(161, 164); - this.groupGhostHack.TabIndex = 3; - this.groupGhostHack.TabStop = false; - this.groupGhostHack.Text = "Ghost Hack"; + groupGhostHack.Controls.Add(txtRAMOffsetBase); + groupGhostHack.Controls.Add(lblRAMOffsetBase); + groupGhostHack.Controls.Add(labelHackActiveState); + groupGhostHack.Controls.Add(buttonDisableGhostHack); + groupGhostHack.Controls.Add(buttonEnableGhostHack); + groupGhostHack.Location = new System.Drawing.Point(4, 3); + groupGhostHack.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupGhostHack.Name = "groupGhostHack"; + groupGhostHack.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupGhostHack.Size = new System.Drawing.Size(188, 189); + groupGhostHack.TabIndex = 3; + groupGhostHack.TabStop = false; + groupGhostHack.Text = "Ghost Hack"; // // labelHackActiveState // - this.labelHackActiveState.AutoSize = true; - this.labelHackActiveState.Location = new System.Drawing.Point(6, 82); - this.labelHackActiveState.Name = "labelHackActiveState"; - this.labelHackActiveState.Size = new System.Drawing.Size(131, 13); - this.labelHackActiveState.TabIndex = 3; - this.labelHackActiveState.Text = "Ghost hack is not enabled"; + labelHackActiveState.AutoSize = true; + labelHackActiveState.Location = new System.Drawing.Point(7, 95); + labelHackActiveState.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelHackActiveState.Name = "labelHackActiveState"; + labelHackActiveState.Size = new System.Drawing.Size(143, 15); + labelHackActiveState.TabIndex = 3; + labelHackActiveState.Text = "Ghost hack is not enabled"; // // buttonDisableGhostHack // - this.buttonDisableGhostHack.Location = new System.Drawing.Point(6, 48); - this.buttonDisableGhostHack.Name = "buttonDisableGhostHack"; - this.buttonDisableGhostHack.Size = new System.Drawing.Size(143, 23); - this.buttonDisableGhostHack.TabIndex = 0; - this.buttonDisableGhostHack.Text = "Disable Ghost Hack"; - this.buttonDisableGhostHack.UseVisualStyleBackColor = true; - this.buttonDisableGhostHack.Click += new System.EventHandler(this.buttonDisableGhostHack_Click); + buttonDisableGhostHack.Location = new System.Drawing.Point(7, 55); + buttonDisableGhostHack.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonDisableGhostHack.Name = "buttonDisableGhostHack"; + buttonDisableGhostHack.Size = new System.Drawing.Size(167, 27); + buttonDisableGhostHack.TabIndex = 0; + buttonDisableGhostHack.Text = "Disable Ghost Hack"; + buttonDisableGhostHack.UseVisualStyleBackColor = true; + buttonDisableGhostHack.Click += buttonDisableGhostHack_Click; // // buttonEnableGhostHack // - this.buttonEnableGhostHack.Location = new System.Drawing.Point(6, 19); - this.buttonEnableGhostHack.Name = "buttonEnableGhostHack"; - this.buttonEnableGhostHack.Size = new System.Drawing.Size(143, 23); - this.buttonEnableGhostHack.TabIndex = 0; - this.buttonEnableGhostHack.Text = "Enable Ghost Hack"; - this.buttonEnableGhostHack.UseVisualStyleBackColor = true; - this.buttonEnableGhostHack.Click += new System.EventHandler(this.buttonEnableGhostHack_Click); - // - // watchVariablePanelGhost - // - this._variablePanelGhost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this._variablePanelGhost.AutoScroll = true; - this._variablePanelGhost.DataPath = "Config/GhostData.xml"; - this._variablePanelGhost.elementNameWidth = null; - this._variablePanelGhost.elementValueWidth = null; - this._variablePanelGhost.Location = new System.Drawing.Point(6, 19); - this._variablePanelGhost.Name = "_variablePanelGhost"; - this._variablePanelGhost.Size = new System.Drawing.Size(209, 432); - this._variablePanelGhost.TabIndex = 4; + buttonEnableGhostHack.Location = new System.Drawing.Point(7, 22); + buttonEnableGhostHack.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonEnableGhostHack.Name = "buttonEnableGhostHack"; + buttonEnableGhostHack.Size = new System.Drawing.Size(167, 27); + buttonEnableGhostHack.TabIndex = 0; + buttonEnableGhostHack.Text = "Enable Ghost Hack"; + buttonEnableGhostHack.UseVisualStyleBackColor = true; + buttonEnableGhostHack.Click += buttonEnableGhostHack_Click; + // + // _variablePanelGhost + // + _variablePanelGhost.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)); + _variablePanelGhost.AutoScroll = true; + _variablePanelGhost.DataPath = "Config/GhostData.xml"; + _variablePanelGhost.elementNameWidth = null; + _variablePanelGhost.elementValueWidth = null; + _variablePanelGhost.Location = new System.Drawing.Point(7, 22); + _variablePanelGhost.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + _variablePanelGhost.Name = "_variablePanelGhost"; + _variablePanelGhost.Size = new System.Drawing.Size(244, 498); + _variablePanelGhost.TabIndex = 4; // // groupBoxVariables // - this.groupBoxVariables.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBoxVariables.Controls.Add(this._variablePanelGhost); - this.groupBoxVariables.Location = new System.Drawing.Point(691, 3); - this.groupBoxVariables.Name = "groupBoxVariables"; - this.groupBoxVariables.Size = new System.Drawing.Size(221, 457); - this.groupBoxVariables.TabIndex = 5; - this.groupBoxVariables.TabStop = false; - this.groupBoxVariables.Text = "Variables"; + groupBoxVariables.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right)); + groupBoxVariables.Controls.Add(_variablePanelGhost); + groupBoxVariables.Location = new System.Drawing.Point(806, 3); + groupBoxVariables.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxVariables.Name = "groupBoxVariables"; + groupBoxVariables.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxVariables.Size = new System.Drawing.Size(258, 527); + groupBoxVariables.TabIndex = 5; + groupBoxVariables.TabStop = false; + groupBoxVariables.Text = "Variables"; // // groupBoxHelp // - this.groupBoxHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.groupBoxHelp.Controls.Add(this.buttonTutorialFileWatch); - this.groupBoxHelp.Controls.Add(this.buttonHelpGfxPool); - this.groupBoxHelp.Controls.Add(this.buttonTutorialPlayback); - this.groupBoxHelp.Controls.Add(this.buttonTutorialNotes); - this.groupBoxHelp.Controls.Add(this.buttonTutorialRecord); - this.groupBoxHelp.Location = new System.Drawing.Point(3, 288); - this.groupBoxHelp.Name = "groupBoxHelp"; - this.groupBoxHelp.Size = new System.Drawing.Size(161, 172); - this.groupBoxHelp.TabIndex = 8; - this.groupBoxHelp.TabStop = false; - this.groupBoxHelp.Text = "Help"; + groupBoxHelp.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)); + groupBoxHelp.Controls.Add(buttonTutorialFileWatch); + groupBoxHelp.Controls.Add(buttonHelpGfxPool); + groupBoxHelp.Controls.Add(buttonTutorialPlayback); + groupBoxHelp.Controls.Add(buttonTutorialNotes); + groupBoxHelp.Controls.Add(buttonTutorialRecord); + groupBoxHelp.Location = new System.Drawing.Point(4, 332); + groupBoxHelp.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxHelp.Name = "groupBoxHelp"; + groupBoxHelp.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxHelp.Size = new System.Drawing.Size(188, 198); + groupBoxHelp.TabIndex = 8; + groupBoxHelp.TabStop = false; + groupBoxHelp.Text = "Help"; // // buttonTutorialFileWatch // - this.buttonTutorialFileWatch.Location = new System.Drawing.Point(9, 139); - this.buttonTutorialFileWatch.Name = "buttonTutorialFileWatch"; - this.buttonTutorialFileWatch.Size = new System.Drawing.Size(146, 23); - this.buttonTutorialFileWatch.TabIndex = 7; - this.buttonTutorialFileWatch.Text = "Using File Watchers"; - this.buttonTutorialFileWatch.UseVisualStyleBackColor = true; - this.buttonTutorialFileWatch.Click += new System.EventHandler(this.buttonTutorialFileWatch_Click); + buttonTutorialFileWatch.Location = new System.Drawing.Point(10, 160); + buttonTutorialFileWatch.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonTutorialFileWatch.Name = "buttonTutorialFileWatch"; + buttonTutorialFileWatch.Size = new System.Drawing.Size(170, 27); + buttonTutorialFileWatch.TabIndex = 7; + buttonTutorialFileWatch.Text = "Using File Watchers"; + buttonTutorialFileWatch.UseVisualStyleBackColor = true; + buttonTutorialFileWatch.Click += buttonTutorialFileWatch_Click; // // buttonHelpGfxPool // - this.buttonHelpGfxPool.Location = new System.Drawing.Point(9, 110); - this.buttonHelpGfxPool.Name = "buttonHelpGfxPool"; - this.buttonHelpGfxPool.Size = new System.Drawing.Size(146, 23); - this.buttonHelpGfxPool.TabIndex = 7; - this.buttonHelpGfxPool.Text = "Moving the GFX Pool"; - this.buttonHelpGfxPool.UseVisualStyleBackColor = true; - this.buttonHelpGfxPool.Click += new System.EventHandler(this.buttonHelpGfxPool_Click); + buttonHelpGfxPool.Location = new System.Drawing.Point(10, 127); + buttonHelpGfxPool.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonHelpGfxPool.Name = "buttonHelpGfxPool"; + buttonHelpGfxPool.Size = new System.Drawing.Size(170, 27); + buttonHelpGfxPool.TabIndex = 7; + buttonHelpGfxPool.Text = "Moving the GFX Pool"; + buttonHelpGfxPool.UseVisualStyleBackColor = true; + buttonHelpGfxPool.Click += buttonHelpGfxPool_Click; // // buttonTutorialPlayback // - this.buttonTutorialPlayback.Location = new System.Drawing.Point(9, 81); - this.buttonTutorialPlayback.Name = "buttonTutorialPlayback"; - this.buttonTutorialPlayback.Size = new System.Drawing.Size(146, 23); - this.buttonTutorialPlayback.TabIndex = 7; - this.buttonTutorialPlayback.Text = "Playing Ghosts back"; - this.buttonTutorialPlayback.UseVisualStyleBackColor = true; - this.buttonTutorialPlayback.Click += new System.EventHandler(this.buttonTutorialPlayback_Click); + buttonTutorialPlayback.Location = new System.Drawing.Point(10, 93); + buttonTutorialPlayback.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonTutorialPlayback.Name = "buttonTutorialPlayback"; + buttonTutorialPlayback.Size = new System.Drawing.Size(170, 27); + buttonTutorialPlayback.TabIndex = 7; + buttonTutorialPlayback.Text = "Playing Ghosts back"; + buttonTutorialPlayback.UseVisualStyleBackColor = true; + buttonTutorialPlayback.Click += buttonTutorialPlayback_Click; // // buttonTutorialNotes // - this.buttonTutorialNotes.Location = new System.Drawing.Point(9, 19); - this.buttonTutorialNotes.Name = "buttonTutorialNotes"; - this.buttonTutorialNotes.Size = new System.Drawing.Size(146, 23); - this.buttonTutorialNotes.TabIndex = 7; - this.buttonTutorialNotes.Text = "General Notes"; - this.buttonTutorialNotes.UseVisualStyleBackColor = true; - this.buttonTutorialNotes.Click += new System.EventHandler(this.buttonTutorialNotes_Click); + buttonTutorialNotes.Location = new System.Drawing.Point(10, 22); + buttonTutorialNotes.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonTutorialNotes.Name = "buttonTutorialNotes"; + buttonTutorialNotes.Size = new System.Drawing.Size(170, 27); + buttonTutorialNotes.TabIndex = 7; + buttonTutorialNotes.Text = "General Notes"; + buttonTutorialNotes.UseVisualStyleBackColor = true; + buttonTutorialNotes.Click += buttonTutorialNotes_Click; // // groupBoxGfxPool // - this.groupBoxGfxPool.Controls.Add(this.textBoxPoolSize); - this.groupBoxGfxPool.Controls.Add(this.textBoxPoolAddr2); - this.groupBoxGfxPool.Controls.Add(this.textBoxPoolAddr1); - this.groupBoxGfxPool.Controls.Add(this.labelPoolSize); - this.groupBoxGfxPool.Controls.Add(this.label1); - this.groupBoxGfxPool.Controls.Add(this.labelPool1Address); - this.groupBoxGfxPool.Controls.Add(this.buttonMoveGfxPool); - this.groupBoxGfxPool.Location = new System.Drawing.Point(3, 171); - this.groupBoxGfxPool.Name = "groupBoxGfxPool"; - this.groupBoxGfxPool.Size = new System.Drawing.Size(155, 111); - this.groupBoxGfxPool.TabIndex = 9; - this.groupBoxGfxPool.TabStop = false; - this.groupBoxGfxPool.Text = "Gfx Pool"; + groupBoxGfxPool.Controls.Add(textBoxPoolSize); + groupBoxGfxPool.Controls.Add(textBoxPoolAddr2); + groupBoxGfxPool.Controls.Add(textBoxPoolAddr1); + groupBoxGfxPool.Controls.Add(labelPoolSize); + groupBoxGfxPool.Controls.Add(label1); + groupBoxGfxPool.Controls.Add(labelPool1Address); + groupBoxGfxPool.Controls.Add(buttonMoveGfxPool); + groupBoxGfxPool.Location = new System.Drawing.Point(4, 197); + groupBoxGfxPool.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxGfxPool.Name = "groupBoxGfxPool"; + groupBoxGfxPool.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxGfxPool.Size = new System.Drawing.Size(181, 128); + groupBoxGfxPool.TabIndex = 9; + groupBoxGfxPool.TabStop = false; + groupBoxGfxPool.Text = "Gfx Pool"; // // textBoxPoolSize // - this.textBoxPoolSize.Location = new System.Drawing.Point(80, 57); - this.textBoxPoolSize.Name = "textBoxPoolSize"; - this.textBoxPoolSize.Size = new System.Drawing.Size(69, 20); - this.textBoxPoolSize.TabIndex = 2; - this.textBoxPoolSize.Text = "FFF00"; + textBoxPoolSize.Location = new System.Drawing.Point(93, 66); + textBoxPoolSize.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + textBoxPoolSize.Name = "textBoxPoolSize"; + textBoxPoolSize.Size = new System.Drawing.Size(80, 23); + textBoxPoolSize.TabIndex = 2; + textBoxPoolSize.Text = "FFF00"; // // textBoxPoolAddr2 // - this.textBoxPoolAddr2.Location = new System.Drawing.Point(80, 35); - this.textBoxPoolAddr2.Name = "textBoxPoolAddr2"; - this.textBoxPoolAddr2.Size = new System.Drawing.Size(69, 20); - this.textBoxPoolAddr2.TabIndex = 2; - this.textBoxPoolAddr2.Text = "80700000"; + textBoxPoolAddr2.Location = new System.Drawing.Point(93, 40); + textBoxPoolAddr2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + textBoxPoolAddr2.Name = "textBoxPoolAddr2"; + textBoxPoolAddr2.Size = new System.Drawing.Size(80, 23); + textBoxPoolAddr2.TabIndex = 2; + textBoxPoolAddr2.Text = "80700000"; // // textBoxPoolAddr1 // - this.textBoxPoolAddr1.Location = new System.Drawing.Point(80, 13); - this.textBoxPoolAddr1.Name = "textBoxPoolAddr1"; - this.textBoxPoolAddr1.Size = new System.Drawing.Size(69, 20); - this.textBoxPoolAddr1.TabIndex = 2; - this.textBoxPoolAddr1.Text = "80600000"; + textBoxPoolAddr1.Location = new System.Drawing.Point(93, 15); + textBoxPoolAddr1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + textBoxPoolAddr1.Name = "textBoxPoolAddr1"; + textBoxPoolAddr1.Size = new System.Drawing.Size(80, 23); + textBoxPoolAddr1.TabIndex = 2; + textBoxPoolAddr1.Text = "80600000"; // // labelPoolSize // - this.labelPoolSize.AutoSize = true; - this.labelPoolSize.Location = new System.Drawing.Point(23, 60); - this.labelPoolSize.Name = "labelPoolSize"; - this.labelPoolSize.Size = new System.Drawing.Size(51, 13); - this.labelPoolSize.TabIndex = 1; - this.labelPoolSize.Text = "Pool Size"; - this.labelPoolSize.TextAlign = System.Drawing.ContentAlignment.TopRight; + labelPoolSize.AutoSize = true; + labelPoolSize.Location = new System.Drawing.Point(27, 69); + labelPoolSize.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelPoolSize.Name = "labelPoolSize"; + labelPoolSize.Size = new System.Drawing.Size(54, 15); + labelPoolSize.TabIndex = 1; + labelPoolSize.Text = "Pool Size"; + labelPoolSize.TextAlign = System.Drawing.ContentAlignment.TopRight; // // label1 // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 38); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(68, 13); - this.label1.TabIndex = 1; - this.label1.Text = "Pool Addr. 2:"; + label1.AutoSize = true; + label1.Location = new System.Drawing.Point(7, 44); + label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label1.Name = "label1"; + label1.Size = new System.Drawing.Size(75, 15); + label1.TabIndex = 1; + label1.Text = "Pool Addr. 2:"; // // labelPool1Address // - this.labelPool1Address.AutoSize = true; - this.labelPool1Address.Location = new System.Drawing.Point(6, 16); - this.labelPool1Address.Name = "labelPool1Address"; - this.labelPool1Address.Size = new System.Drawing.Size(68, 13); - this.labelPool1Address.TabIndex = 1; - this.labelPool1Address.Text = "Pool Addr. 1:"; + labelPool1Address.AutoSize = true; + labelPool1Address.Location = new System.Drawing.Point(7, 18); + labelPool1Address.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelPool1Address.Name = "labelPool1Address"; + labelPool1Address.Size = new System.Drawing.Size(75, 15); + labelPool1Address.TabIndex = 1; + labelPool1Address.Text = "Pool Addr. 1:"; // // buttonMoveGfxPool // - this.buttonMoveGfxPool.Location = new System.Drawing.Point(52, 82); - this.buttonMoveGfxPool.Name = "buttonMoveGfxPool"; - this.buttonMoveGfxPool.Size = new System.Drawing.Size(97, 23); - this.buttonMoveGfxPool.TabIndex = 0; - this.buttonMoveGfxPool.Text = "Move GFX Pool"; - this.buttonMoveGfxPool.UseVisualStyleBackColor = true; - this.buttonMoveGfxPool.Click += new System.EventHandler(this.buttonMoveGfxPool_Click); + buttonMoveGfxPool.Location = new System.Drawing.Point(61, 95); + buttonMoveGfxPool.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + buttonMoveGfxPool.Name = "buttonMoveGfxPool"; + buttonMoveGfxPool.Size = new System.Drawing.Size(113, 27); + buttonMoveGfxPool.TabIndex = 0; + buttonMoveGfxPool.Text = "Move GFX Pool"; + buttonMoveGfxPool.UseVisualStyleBackColor = true; + buttonMoveGfxPool.Click += buttonMoveGfxPool_Click; + // + // lblRAMOffsetBase + // + lblRAMOffsetBase.Anchor = ((System.Windows.Forms.AnchorStyles)(System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)); + lblRAMOffsetBase.Location = new System.Drawing.Point(11, 160); + lblRAMOffsetBase.Name = "lblRAMOffsetBase"; + lblRAMOffsetBase.Size = new System.Drawing.Size(126, 23); + lblRAMOffsetBase.TabIndex = 4; + lblRAMOffsetBase.Text = "RAM offset base:"; + lblRAMOffsetBase.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtRAMOffsetBase + // + txtRAMOffsetBase.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)); + txtRAMOffsetBase.Location = new System.Drawing.Point(143, 160); + txtRAMOffsetBase.Name = "txtRAMOffsetBase"; + txtRAMOffsetBase.Size = new System.Drawing.Size(38, 23); + txtRAMOffsetBase.TabIndex = 5; + txtRAMOffsetBase.Text = "8040"; // // GhostTab // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.Controls.Add(this.groupBoxGfxPool); - this.Controls.Add(this.groupBoxHelp); - this.Controls.Add(this.groupBoxVariables); - this.Controls.Add(this.groupBoxGhosts); - this.Controls.Add(this.groupGhostHack); - this.Name = "GhostTab"; - this.groupBoxGhosts.ResumeLayout(false); - this.groupBoxGhostInfo.ResumeLayout(false); - this.groupBoxGhostInfo.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPlaybackOffset)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDownStartOfPlayback)).EndInit(); - this.groupGhostHack.ResumeLayout(false); - this.groupGhostHack.PerformLayout(); - this.groupBoxVariables.ResumeLayout(false); - this.groupBoxHelp.ResumeLayout(false); - this.groupBoxGfxPool.ResumeLayout(false); - this.groupBoxGfxPool.PerformLayout(); - this.ResumeLayout(false); - + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + Controls.Add(groupBoxGfxPool); + Controls.Add(groupBoxHelp); + Controls.Add(groupBoxVariables); + Controls.Add(groupBoxGhosts); + Controls.Add(groupGhostHack); + Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + groupBoxGhosts.ResumeLayout(false); + groupBoxGhostInfo.ResumeLayout(false); + groupBoxGhostInfo.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)numericUpDownPlaybackOffset).EndInit(); + ((System.ComponentModel.ISupportInitialize)numericUpDownStartOfPlayback).EndInit(); + groupGhostHack.ResumeLayout(false); + groupGhostHack.PerformLayout(); + groupBoxVariables.ResumeLayout(false); + groupBoxHelp.ResumeLayout(false); + groupBoxGfxPool.ResumeLayout(false); + groupBoxGfxPool.PerformLayout(); + ResumeLayout(false); } + private System.Windows.Forms.Label lblRAMOffsetBase; + private System.Windows.Forms.TextBox txtRAMOffsetBase; + #endregion private System.Windows.Forms.GroupBox groupBoxGhosts; diff --git a/STROOP/Tabs/GhostTab/GhostTab.cs b/STROOP/Tabs/GhostTab/GhostTab.cs index a571e2f25..962c50140 100644 --- a/STROOP/Tabs/GhostTab/GhostTab.cs +++ b/STROOP/Tabs/GhostTab/GhostTab.cs @@ -13,12 +13,36 @@ using STROOP.Variables; using STROOP.Variables.SM64MemoryLayout; using STROOP.Variables.Utilities; +using System.Globalization; namespace STROOP.Tabs.GhostTab { public partial class GhostTab : STROOPTab { - const uint bufferBaseAddress = 0x80409B00; + + const uint GHOST_LOOP_CODE_OFFSET = 0x8000u; + const uint HACK_FILE_BASE_OFFSET = 0x80400000; + + // These numbers are the 4 byte words, in order, as exported into "DynamicOffsets.bin". + const uint FirstAnimationBufferAddrHi_LUI_1 = 0x50; + const uint GhostBaseHi_LUI_PLUS_1 = 0xF8; + const uint COLORED_HATS_GhostBaseHi_LUI = 0x70; + static readonly uint[] GhostBaseHi_LUI = [0x44, 0x78, 0x170]; + + /// The variable part to move the ghost loop and colored hats code with. + ushort ghostHackBaseHi => + ushort.TryParse(txtRAMOffsetBase.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var parsed) + ? parsed + : (ushort)0x8040; + + uint ghostRegionBase => (uint)ghostHackBaseHi << 0x10; + + // These offsets mirror NumRequestedGhosts / PointerToFirstGhost in ghost_loop.asm. + uint numGhostsAddr => ghostRegionBase + 0x7FFFu; + uint firstGhostPointerAddr => ghostRegionBase + 0x7FF8u; + uint disableRequestAddr => ghostRegionBase + 0x7FFCu; + + uint bufferBaseAddress => ghostRegionBase + 0x9B00u; static IEnumerable GetActiveGhostIndices() { @@ -49,7 +73,6 @@ static void AddSpecialVariables() int lastGlobalTimer; Ghost selectedGhost => listBoxGhosts.SelectedItem as Ghost; - GhostFrame lastValidPlaybackFrame => selectedGhost?.lastValidPlaybackFrame ?? default(GhostFrame); public GhostTab() { @@ -85,7 +108,7 @@ public override void Update(bool active) int numGhosts = Math.Max(1, ghostArr.Length); if (updateGhostData) { - Config.Stream.SetValue((byte)numGhosts, 0x80407FFF); + Config.Stream.SetValue((byte)numGhosts, numGhostsAddr); WriteMarioColorToStream(); } @@ -165,7 +188,7 @@ public override void Update(bool active) WriteGhostColorToStream(ghostIndex, ghostArr); - var ptr = Config.Stream.GetUInt32((uint)(0x80407ff8 - ghostIndex * 0x68)); + var ptr = Config.Stream.GetUInt32((uint)(firstGhostPointerAddr - ghostIndex * 0x68)); Config.Stream.SetValue((byte)(ghostTransparent ? 1 : 0), ptr + 0x61); lastGlobalTimer = globalTimer; } @@ -248,16 +271,16 @@ bool UpdateHackStatus() if (ghostHack?.Name != expectedHackName) ghostHack = new RomHack($"Resources/Hacks/GhostHack{RomVersionConfig.Version}.hck", expectedHackName); - var ghostPointer = Config.Stream.GetInt32(0x80407FF8); + var ghostPointer = Config.Stream.GetInt32(firstGhostPointerAddr); bool ghostsActive = (ghostPointer & 0xFF000000) == 0x80000000; - bool shouldDisable = Config.Stream.GetByte(0x80407FFC) == 0xFF; + bool shouldDisable = Config.Stream.GetByte(disableRequestAddr) == 0xFF; if (shouldDisable) { labelHackActiveState.Text = "Disabling Ghost hack...\nInside a level, frame advance\nthen save state and load state.\nNot doing so will crash.\n(Not on Pure Interpreter)"; if (!ghostsActive) { ghostHack.ClearPayload(); - Config.Stream.SetValue((byte)0, 0x80407FFC); + Config.Stream.SetValue((byte)0, disableRequestAddr); } else return true; @@ -267,6 +290,8 @@ bool UpdateHackStatus() bool enabled = ghostHack.Status != RomHack.EnabledStatus.Disabled; labelHackActiveState.Text = (ghostsActive && enabled) ? "Ghost hack is enabled." : (enabled ? "Ghost hack is enabled\nbut not running.\nInside a level,\nsave state and load state,\nthen frame advance." : "Ghost hack is disabled."); buttonDisableGhostHack.Enabled = enabled; + lblRAMOffsetBase.Visible = !enabled; + txtRAMOffsetBase.Visible = !enabled; return true; } @@ -344,14 +369,36 @@ private void buttonEnableGhostHack_Click(object sender, EventArgs e) { if (Config.Stream.GetInt32(0x80000000) != 0) { - ghostHack.LoadPayload(); - Config.Stream.WriteRam(new byte[4], 0x80407FFC, EndiannessType.Little); - Config.Stream.WriteRam(new byte[0x70], 0x80407F90, EndiannessType.Little); + ghostHack.LoadPayload(new() + { + [HACK_FILE_BASE_OFFSET + GHOST_LOOP_CODE_OFFSET] = ghostRegionBase + GHOST_LOOP_CODE_OFFSET, + [HACK_FILE_BASE_OFFSET + COLORED_HATS_CODE_OFFSET] = ghostRegionBase + COLORED_HATS_CODE_OFFSET, + }); + Config.Stream.WriteRam(new byte[4], disableRequestAddr, EndiannessType.Little); + Config.Stream.WriteRam(new byte[0x70], ghostRegionBase + 0x7F90u, EndiannessType.Little); EnableColoredHats(); //Tell ROM Hacks to suck it and get rid of the 01010101 pattern - Config.Stream.WriteRam(new byte[0x1000], 0x80408000 - 0x1000, EndiannessType.Big); + Config.Stream.WriteRam(new byte[0x1000], ghostRegionBase + GHOST_LOOP_CODE_OFFSET - 0x1000u, EndiannessType.Big); + + // Modify code for moving parts + ushort luiGhostBaseValue = ghostHackBaseHi; + ushort luiFirstAnimationValue = (ushort)(luiGhostBaseValue + 0x10); + + ApplyLui((ushort)(luiGhostBaseValue + 1), ghostRegionBase + GHOST_LOOP_CODE_OFFSET + GhostBaseHi_LUI_PLUS_1); + foreach (var offset in GhostBaseHi_LUI) + ApplyLui(luiGhostBaseValue, ghostRegionBase + GHOST_LOOP_CODE_OFFSET + offset); + ApplyLui(luiFirstAnimationValue, ghostRegionBase + GHOST_LOOP_CODE_OFFSET + FirstAnimationBufferAddrHi_LUI_1); + + ApplyLui(luiGhostBaseValue, ghostRegionBase + COLORED_HATS_CODE_OFFSET + COLORED_HATS_GhostBaseHi_LUI); + + var jalTarget = 0x00FFFFFF & (ghostRegionBase + GHOST_LOOP_CODE_OFFSET); + var hookPoint = RomVersionConfig.Version == RomVersion.JP ? 0x8027ABD8 : 0x8027B188; + Config.Stream.SetValue((uint)((0x0C << 0x18) | (jalTarget / 4)), hookPoint); + + void ApplyLui(ushort value, uint address) + => Config.Stream.SetValue(value, address + 2); } } @@ -366,8 +413,8 @@ It is recommended that you load a savestate without the hack enabled instead. Are you sure you want to continue?"; if (MessageBox.Show(txt, "You should not have to do this.", MessageBoxButtons.YesNo) == DialogResult.Yes) { - Config.Stream.SetValue((byte)0, 0x80407FFF); - Config.Stream.SetValue((byte)0xFF, 0x80407FFC); + Config.Stream.SetValue((byte)0, numGhostsAddr); + Config.Stream.SetValue((byte)0xFF, disableRequestAddr); } } diff --git a/STROOP/Tabs/GhostTab/GhostTabHelp.cs b/STROOP/Tabs/GhostTab/GhostTabHelp.cs index dca138664..20ada9275 100644 --- a/STROOP/Tabs/GhostTab/GhostTabHelp.cs +++ b/STROOP/Tabs/GhostTab/GhostTabHelp.cs @@ -47,7 +47,7 @@ Always make sure your runs work from a clean savestate. private void buttonTutorialNotes_Click(object sender, EventArgs e) { Forms.InfoForm frm = new Forms.InfoForm(); - frm.Size = new System.Drawing.Size(900, 400); + frm.Size = new System.Drawing.Size(900, 570); frm.SetText("Ghost Help", "Notes", @"The ghost hack works on the US and JP versions of Super Mario 64 (and therefore also on numerous ROM hacks). @@ -59,6 +59,9 @@ Always verify that your runs work without the hack. Rendering too many ghosts at once can cause a game crash. This number is usually somewhere around 15 to 18, but can be increased by moving the game's Gfx pool. See ""Moving the GFX pool"" for details. +For Usamune ROMs (and perhaps other ROMs as well), you will need to change the ""RAM offset base"" to a higher value (e.g. 8060) before enabling the hack, in order to not conflict with the ROM hack's own memory allocations. +(Reasonable values are between 8040 and 8060 for this hack due to its own memory requirements.) + Disabling the ghost hack via the 'Disable Ghost hack' button may have unintended side effects, including crashing the game. Try to keep a savestate around that doesn't have the hack enabled instead.