~quf/no-cutscene-kiseki

9de49cfff5568307245e66bb0fc4d10d612cd4b4 — Lukas Himbert 1 year, 7 months ago dbb59c3
support for JP v1.05
2 files changed, 37 insertions(+), 20 deletions(-)

M src/patch.rs
M x.gdb
M src/patch.rs => src/patch.rs +30 -13
@@ 88,7 88,7 @@ pub fn find_install_path() -> Option<std::path::PathBuf> {
}

struct Patch<'a> {
    name: &'a str,
    description: &'a str,
    offset: usize,
    expected: &'a [u8],
    replacement: Option<&'a [u8]>,


@@ 114,7 114,7 @@ unsafe fn apply_patch(
        Err(anyhow::Error::msg("unexpected value: patch may have been applied already!"))
    } else {
        Err(anyhow::Error::msg(format!(
            "unexpected values at offset {:x}: expected {:?}, got {:?}",
            "unexpected values at offset 0x{:x}: expected {:x?}, got {:x?}",
            patch.offset, patch.expected, buf
        )))
    }


@@ 128,17 128,17 @@ unsafe fn apply_patches(
    // before patching anything, confirm that all target data is correct
    for patch in patches {
        let p = Patch {
            name: patch.name,
            description: patch.description,
            offset: patch.offset,
            expected: patch.expected,
            replacement: None,
        };
        assert!(buf.len() >= patch.expected.len());
        apply_patch(handle, &p, &mut buf[..patch.expected.len()]).with_context(|| format!("couldn't apply patch {}", patch.name))?;
        apply_patch(handle, &p, &mut buf[..patch.expected.len()]).with_context(|| format!("couldn't patch {}", patch.description))?;
    }
    // now actually apply the patches
    for patch in patches {
        apply_patch(handle, patch, &mut buf[..patch.expected.len()]).with_context(|| format!("couldn't apply patch {}", patch.name))?;
        apply_patch(handle, patch, &mut buf[..patch.expected.len()]).with_context(|| format!("couldn't patch {}", patch.description))?;
    }
    Ok(())
}


@@ 226,36 226,53 @@ pub fn run_and_patch(path: &std::path::Path, version: ExeVersion) -> anyhow::Res
        },
    };

    let patches = match version {
    let patches: &[Patch] = match version {
        ExeVersion::NisaV1_05En => &[
            Patch {
                name: "game version",
                description: "game version",
                offset: 0x140825d68,
                expected: b"ToCSIII PC Version 1.05\0",
                replacement: Some(b"ToCS3 1.05 autoskip mod\0"),
            },
            Patch {
                name: "skip flag setter",
                description: "the part that sets the flag when starting a new cutscene", // or something like that
                offset: 0x14032a5b1,
                expected: &[0xc6, 0x83, 0x3d, 0x3d, 0x00, 0x00, 0x00],          // MOV byte ptr [RBX + 0x3d3d],0x00
                replacement: Some(&[0xc6, 0x83, 0x3d, 0x3d, 0x00, 0x00, 0x01]), // MOV byte ptr [RBX + 0x3d3d],0x01
            },
            Patch {
                name: "skip flag setter",
                description: "the part that resets the flag at the end of a skipped scene",
                offset: 0x1403dfda3,
                expected: &[0xc6, 0x80, 0x3d, 0x3d, 0x00, 0x00, 0x00],          // MOV byte ptr [RAX + 0x3d3d],0x00
                replacement: Some(&[0xc6, 0x80, 0x3d, 0x3d, 0x00, 0x00, 0x01]), // MOV byte ptr [RAX + 0x3d3d],0x01
            },
            Patch {
                name: "skip flag",
                description: "skip flag",
                offset: 0x1416c535d,
                expected: &[0x00],
                replacement: Some(&[0x01]),
            },
        ],
        ExeVersion::NisaV1_05Jp => {
            return Err(anyhow::Error::msg("TODO: japanese is not supported yet"));
        }
        ExeVersion::NisaV1_05Jp => &[
            Patch {
                description: "game version",
                offset: 0x140811320,
                expected: b"ToCSIII PC Version 1.05\0",
                replacement: Some(b"ToCS3 1.05 autoskip mod\0"),
            },
            Patch {
                description: "the part that resets the flag at the end of a skipped scene", // and probably at other times too because it seems we only need to patch this
                offset: 0x1403210a1,
                expected: &[0xc6, 0x83, 0x3d, 0x3d, 0x00, 0x00, 0x00],          // MOV byte ptr [RBX + 0x3d3d],0x00
                replacement: Some(&[0xc6, 0x83, 0x3d, 0x3d, 0x00, 0x00, 0x01]), // MOV byte ptr [RBX + 0x3d3d],0x01
            },
            Patch {
                description: "skip flag",
                offset: 0x1416af22d,
                expected: &[0x00],
                replacement: Some(&[0x01]),
            },
        ],
    };

    // check patches

M x.gdb => x.gdb +7 -7
@@ 23,20 23,20 @@ handle SIGUSR1 pass nostop noprint
## JP

# cutscene skip flag
set *(unsigned char *) 0x1416af22d = 1
#set *(unsigned char *) 0x1416af22d = 1

# cutscene skip flag setters: set to 1 instead of 0
set *(unsigned char *) 0x1403210a7 = 1
set *(unsigned char *) (0x14030acda + 8) = 1
set *(unsigned char *) 0x1403d5949 = 1
#set *(unsigned char *) 0x1403210a7 = 1
#set *(unsigned char *) (0x14030acda + 8) = 1
#set *(unsigned char *) 0x1403d5949 = 1

# watch cutscene skip flag changes
watch *(unsigned char *) 0x1416af22d
#watch *(unsigned char *) 0x1416af22d
# except from "known" locations
condition 1 ($rip != 0x1402f5a36) && ($rip != 0x1403210a8) && ($rip != 0x14030ace5) && ($rip != 0x1403d594a)
#condition 1 ($rip != 0x1402f5a36) && ($rip != 0x1403210a8) && ($rip != 0x14030ace5) && ($rip != 0x1403d594a)

# watch cutscene skip flag setters
#watch *0x1403210a1 if $rbx != 0x1416ab4f0
watch *0x1403210a1 if $rbx != 0x1416ab4f0
#watch *0x14030acda if $rbx != 0x1416ab4f0
#watch *0x1403d5943 if $rax != 0x1416ab4f0