public static void PatchDisableMouseCapture(Stream bin, Sen1ExecutablePatchState state)
        {
            bool jp = state.IsJp;

            // change function that captures the mouse cursor to not do that
            bin.Position = state.Mapper.MapRamToRom(jp ? 0x5de6c6 : 0x5df536);
            bin.WriteUInt8(0xeb);             // jz -> jmp

            // change function that handles camera movement to not react to mouse movement
            // and not to fall back to WASD camera movement either (legacy code...?)
            using (var branch = new BranchHelper4Byte(bin, state.Mapper)) {
                bin.Position = state.Mapper.MapRamToRom(jp ? 0x4464e5 : 0x446635);
                branch.WriteJump5Byte(0xe9);
                bin.WriteUInt8(0x90);                 // nop
                branch.SetTarget(jp ? 0x44667au : 0x4467cau);
            }

            // there's a third function at 0x53c766 that seems involved here, but leaving it alone seems to work just fine...

            // remove call to ShowCursor(0)
            bin.Position = state.Mapper.MapRamToRom(jp ? 0x7be0ea : 0x7bf9ba);
            for (int i = 0; i < 8; ++i)
            {
                bin.WriteUInt8(0x90);                 // nop
            }

            // skip mouse movement processing function or something like that?
            bin.Position = state.Mapper.MapRamToRom(jp ? 0x446e3a : 0x446f8a);
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
        }
        public static void PatchThorMasterQuartzString(Stream binary, Sen1ExecutablePatchState patchInfo)
        {
            binary.Position = patchInfo.RomAddressThorMasterQuartzTextureIdTypo;
            long p = binary.Position;

            byte[] tmp = binary.ReadUInt8Array(4);
            binary.Position = p;
            binary.Write(tmp, 1, 3);
        }
 public static void PatchJumpR2NotebookSettings(Stream binary, Sen1ExecutablePatchState patchInfo)
 {
     // note: 0x6de04c might be where the game swaps the two L2/R2 options if they match after setting
     binary.Position = (long)patchInfo.Mapper.MapRamToRom((ulong)patchInfo.AddressJumpR2NotebookSettings);
     binary.WriteUInt8(0x90);             // nop
     binary.WriteUInt8(0x90);             // nop
     binary.WriteUInt8(0x90);             // nop
     binary.WriteUInt8(0x90);             // nop
     binary.WriteUInt8(0x90);             // nop
     binary.WriteUInt8(0x90);             // nop
 }
        public static void PatchDisablePauseOnFocusLoss(Stream bin, Sen1ExecutablePatchState state)
        {
            bool jp = state.IsJp;

            // 0x444AA0 -> game active setter
            // 0x444AF0 -> game active getter

            // don't silence audio output when unfocused
            using (var branch = new BranchHelper4Byte(bin, state.Mapper)) {
                bin.Position = state.Mapper.MapRamToRom(jp ? 0x447d6a : 0x447eba);
                branch.WriteJump5Byte(0xe9);
                branch.SetTarget(jp ? 0x447da6u : 0x447ef6u);
            }

            // still run main game loop when unfocused
            bin.Position = state.Mapper.MapRamToRom(jp ? 0x441c00 : 0x441d50);
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop
            bin.WriteUInt8(0x90);             // nop

            // avoid processing mouse clicks when unfocused
            // (this previously happened only implicitly because the game didn't run...)
            // carve out some now-unused code space
            uint codespaceStart = jp ? 0x447d6fu : 0x447ebfu;
            uint codespaceEnd   = jp ? 0x447da4u : 0x447ef4u;
            var  codespace      = new RegionHelper(codespaceStart, codespaceEnd - codespaceStart, "Pause on Focus Loss: Codespace Region");

            bin.Position = state.Mapper.MapRamToRom(codespace.Address);
            for (uint i = 0; i < codespace.Remaining; ++i)
            {
                bin.WriteUInt8(0xcc);                 // int 3
            }

            // and assemble some logic to skip mouse button processing when unfocused
            using (var jump_to_codespace = new BranchHelper4Byte(bin, state.Mapper))
                using (var back_to_function = new BranchHelper4Byte(bin, state.Mapper))
                    using (var skip_processing = new BranchHelper1Byte(bin, state.Mapper)) {
                        var be = EndianUtils.Endianness.BigEndian;

                        back_to_function.SetTarget(jp ? 0x479ad8u : 0x47b348u);
                        bin.Position = state.Mapper.MapRamToRom(jp ? 0x479ad4u : 0x47b344);
                        ulong GetKeyStateAddress = bin.ReadUInt32(be);
                        ulong GameStateAddress   = (jp ? 0x1361c28u : 0x01363fc8u).ToEndian(be);

                        bin.Position = state.Mapper.MapRamToRom(jp ? 0x479ad1 : 0x47b341);
                        jump_to_codespace.WriteJump5Byte(0xe9);            // jmp jump_to_codespace
                        bin.WriteUInt8(0x90);                              // nop
                        bin.WriteUInt8(0x90);                              // nop

                        bin.Position = state.Mapper.MapRamToRom(codespace.Address);
                        jump_to_codespace.SetTarget(codespace.Address);
                        bin.WriteUInt48(0x8b0d00000000u | GameStateAddress, be);           // mov ecx,[static_address_that_holds_game_state]
                        bin.WriteUInt16(0x85c9, be);                                       // test ecx,ecx
                        skip_processing.WriteJump(0x74);                                   // jz skip_processing
                        bin.WriteUInt48(0x8a89b8070000, be);                               // mov cl,byte ptr[ecx+7b8h]   ; cl now holds 0 if unfocused, 1 if focused
                        bin.WriteUInt16(0x84c9, be);                                       // test cl,cl
                        skip_processing.WriteJump(0x74);                                   // jz skip_processing
                        bin.WriteUInt48(0x8b0d00000000u | GetKeyStateAddress, be);         // mov ecx,[USER32.DLL:GetKeyState]
                        bin.WriteUInt16(0x85c9, be);                                       // test ecx,ecx
                        skip_processing.WriteJump(0x74);                                   // jz skip_processing
                        bin.WriteUInt8(0x50);                                              // push eax
                        bin.WriteUInt16(0xffd1, be);                                       // call ecx
                        back_to_function.WriteJump5Byte(0xe9);                             // jmp back_to_function
                        skip_processing.SetTarget(state.Mapper.MapRomToRam((ulong)bin.Position));
                        bin.WriteUInt16(0x33c0, be);                                       // xor eax,eax
                        back_to_function.WriteJump5Byte(0xe9);                             // jmp back_to_function

                        codespace.TakeToAddress(state.Mapper.MapRomToRam(bin.Position), "Pause on Focus Loss: don't process mouse clicks");
                    }
        }
 public static void PatchJumpR2NotebookOpen(Stream binary, Sen1ExecutablePatchState patchInfo)
 {
     binary.Position = (long)patchInfo.Mapper.MapRamToRom((ulong)patchInfo.AddressJumpR2NotebookOpen);
     binary.WriteUInt8(0x90);             // nop
     binary.WriteUInt8(0x90);             // nop
 }
 public static void PatchJumpBattleResultsAutoSkip(Stream binary, Sen1ExecutablePatchState patchInfo)
 {
     binary.Position = (long)patchInfo.Mapper.MapRamToRom((ulong)patchInfo.AddressJumpBattleResultsAutoSkip);
     binary.WriteUInt40(0xe981010000, EndianUtils.Endianness.BigEndian); // jmp
     binary.WriteUInt8(0x90);                                            // nop
 }
 public static void PatchJumpBattleAnimationAutoSkip(Stream binary, Sen1ExecutablePatchState patchInfo)
 {
     binary.Position = (long)patchInfo.Mapper.MapRamToRom((ulong)patchInfo.AddressJumpBattleAnimationAutoSkip);
     binary.WriteUInt16(0xeb07, EndianUtils.Endianness.BigEndian);             // jmp
 }
 public static void PatchButtonBattleResultsAutoSkip(Stream binary, Sen1ExecutablePatchState patchInfo, byte button)
 {
     binary.Position = (long)patchInfo.Mapper.MapRamToRom((ulong)patchInfo.AddressButtonBattleResultsAutoSkip);
     binary.WriteUInt8(button);
 }
        // button IDs:
        // 0x0 = Square
        // 0x1 = Cross
        // 0x2 = Circle
        // 0x3 = Triangle
        // 0x4 = L1
        // 0x5 = R1
        // 0x6 = L2
        // 0x7 = R2
        // 0x8 = Select
        // 0x9 = Start
        // 0xA = L3
        // 0xB = R3
        // 0xC = D-Pad Up
        // 0xD = D-Pad Right
        // 0xE = D-Pad Down
        // 0xF = D-Pad Left

        public static void PatchButtonTurboMode(Stream binary, Sen1ExecutablePatchState patchInfo, byte button)
        {
            binary.Position = (long)patchInfo.Mapper.MapRamToRom((ulong)patchInfo.AddressButtonTurboMode);
            binary.WriteUInt8(button);
        }
Exemple #10
0
        public static void PatchLanguageAppropriateVoiceTables(Stream binary, Sen1ExecutablePatchState state)
        {
            state.InitCodeSpaceIfNeeded(binary);

            var  mapper        = state.Mapper;
            var  regionStrings = state.RegionScriptCompilerFunctionStrings;
            var  regionCode    = state.RegionScriptCompilerFunction;
            bool jp            = state.IsJp;

            using (BranchHelper4Byte jump_from_function = new BranchHelper4Byte(binary, mapper))
                using (BranchHelper4Byte back_to_function = new BranchHelper4Byte(binary, mapper))
                    using (BranchHelper4Byte get_pc_config = new BranchHelper4Byte(binary, mapper))
                        using (BranchHelper4Byte pc_config__get_voice_language = new BranchHelper4Byte(binary, mapper))
                            using (BranchHelper1Byte depends_on_voice_lang = new BranchHelper1Byte(binary, mapper))
                                using (BranchHelper1Byte exit_inject = new BranchHelper1Byte(binary, mapper))
                                    using (BranchHelper1Byte use_english_string = new BranchHelper1Byte(binary, mapper))
                                        using (BranchHelper1Byte use_text_lang_string = new BranchHelper1Byte(binary, mapper)) {
                                            EndianUtils.Endianness be = EndianUtils.Endianness.BigEndian;
                                            EndianUtils.Endianness le = EndianUtils.Endianness.LittleEndian;
                                            Stream _ = binary;

                                            get_pc_config.SetTarget(jp ? 0x7bdef0u : 0x7bf7c0u);
                                            pc_config__get_voice_language.SetTarget(jp ? 0x7bd3f0u : 0x7becc0u);

                                            // inject into the asset-from-text-subfolder loader function
                                            long address_of_inject = jp ? 0x56f6d8 : 0x5708d8;
                                            _.Position = mapper.MapRamToRom(address_of_inject);
                                            ulong push_local_formatting_string    = _.PeekUInt40(be);
                                            uint  address_local_formatting_string = ((uint)(push_local_formatting_string & 0xffffffffu)).SwapEndian();
                                            jump_from_function.SetTarget(regionCode.Address);
                                            jump_from_function.WriteJump5Byte(0xe9);
                                            back_to_function.SetTarget(mapper.MapRomToRam((ulong)_.Position));
                                            ulong push_en_formatting_string;
                                            ulong push_jp_formatting_string;
                                            uint  t_vctiming_address;
                                            uint  t_voice_address;
                                            if (jp)
                                            {
                                                push_jp_formatting_string = push_local_formatting_string;
                                                t_vctiming_address        = 0xb41c68;
                                                t_voice_address           = 0xb41bdc;

                                                // english formatting string doesn't exist in the japanese executable, generate and inject it
                                                byte[] formatting_string_jp = _.ReadBytesFromLocationAndReset(mapper.MapRamToRom(address_local_formatting_string), 0x13);
                                                byte[] extra = _.ReadBytesFromLocationAndReset(0x73fd32, 0x3);
                                                byte[] formatting_string_en = new byte[formatting_string_jp.Length + 3];
                                                ArrayUtils.CopyByteArrayPart(formatting_string_jp, 0, formatting_string_en, 0, 0xb);
                                                ArrayUtils.CopyByteArrayPart(extra, 0, formatting_string_en, 0xb, 3);
                                                ArrayUtils.CopyByteArrayPart(formatting_string_jp, 0xb, formatting_string_en, 0xe, 0x8);

                                                uint nonlocal_string_address = regionStrings.Address;
                                                _.Position = mapper.MapRamToRom(regionStrings.Address);
                                                _.Write(formatting_string_en);
                                                regionStrings.TakeToAddress(mapper.MapRomToRam(_.Position), "Voice Tables: EN Formatting String");

                                                push_en_formatting_string = 0x6800000000 | (ulong)(nonlocal_string_address.SwapEndian());
                                            }
                                            else
                                            {
                                                push_en_formatting_string = push_local_formatting_string;
                                                t_vctiming_address        = 0xb43f30;
                                                t_voice_address           = 0xb43ea4;

                                                // japanese formatting string doesn't exist in the english executable, generate and inject it
                                                byte[] formatting_string_en = _.ReadBytesFromLocationAndReset(mapper.MapRamToRom(address_local_formatting_string), 0x16);
                                                byte[] formatting_string_jp = new byte[formatting_string_en.Length - 3];
                                                ArrayUtils.CopyByteArrayPart(formatting_string_en, 0, formatting_string_jp, 0, 0xb);
                                                ArrayUtils.CopyByteArrayPart(formatting_string_en, 0xe, formatting_string_jp, 0xb, 0x8);

                                                uint nonlocal_string_address = regionStrings.Address;
                                                _.Position = mapper.MapRamToRom(regionStrings.Address);
                                                _.Write(formatting_string_jp);
                                                regionStrings.TakeToAddress(mapper.MapRomToRam(_.Position), "Voice Tables: JP Formatting String");

                                                push_jp_formatting_string = 0x6800000000 | (ulong)(nonlocal_string_address.SwapEndian());
                                            }

                                            // assemble logic to select the voice-language-matching voice tables
                                            _.Position = mapper.MapRamToRom(regionCode.Address);
                                            _.WriteUInt16(0x81ff, be);                 // cmp  edi,(t_vctiming)
                                            _.WriteUInt32(t_vctiming_address, le);
                                            depends_on_voice_lang.WriteJump(0x74);     // je   depends_on_voice_lang
                                            _.WriteUInt16(0x81ff, be);                 // cmp  edi,(t_voice)
                                            _.WriteUInt32(t_voice_address, le);
                                            depends_on_voice_lang.WriteJump(0x74);     // je   depends_on_voice_lang
                                            use_text_lang_string.WriteJump(0xeb);      // jmp  use_text_lang_string

                                            depends_on_voice_lang.SetTarget(mapper.MapRomToRam((ulong)_.Position));
                                            get_pc_config.WriteJump5Byte(0xe8);                 // call get_pc_config
                                            _.WriteUInt16(0x8bc8, be);                          // mov  ecx,eax
                                            pc_config__get_voice_language.WriteJump5Byte(0xe8); // call pc_config__get_voice_language
                                            _.WriteUInt16(0x84c0, be);                          // test al,al
                                            use_english_string.WriteJump(0x74);                 // jz   use_english_string
                                            if (jp)
                                            {
                                                use_text_lang_string.SetTarget(mapper.MapRomToRam((ulong)_.Position));
                                            }
                                            _.WriteUInt40(push_jp_formatting_string, be); // push (jp_formatting_string)
                                            exit_inject.WriteJump(0xeb);                  // jmp  exit_inject

                                            use_english_string.SetTarget(mapper.MapRomToRam((ulong)_.Position));
                                            if (!jp)
                                            {
                                                use_text_lang_string.SetTarget(mapper.MapRomToRam((ulong)_.Position));
                                            }
                                            _.WriteUInt40(push_en_formatting_string, be); // push (en_formatting_string)

                                            exit_inject.SetTarget(mapper.MapRomToRam((ulong)_.Position));
                                            back_to_function.WriteJump5Byte(0xe9);     // jmp  back_to_function

                                            regionCode.TakeToAddress(mapper.MapRomToRam(_.Position), "Voice Tables: Formatting String Select Code");
                                        }
        }