diff --git a/Cargo.toml b/Cargo.toml index d9c2ab2..573e696 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ hexen-haus = ["memchr", "utils-str"] hexen-haus-arc = ["hexen-haus"] hexen-haus-img = ["hexen-haus", "image"] kirikiri = ["emote-psb", "fancy-regex", "flate2", "json", "lz4", "utils-escape"] -kirikiri-arc = ["kirikiri", "adler", "aes", "bytes", "cbc", "fastcdc", "flate2", "int-enum", "md5", "msg_tool_xp3data", "parse-size", "sha2", "utils-case-insensitive-string", "utils-serde-base64bytes", "utils-simple-pack", "zopfli", "zstd"] +kirikiri-arc = ["kirikiri", "adler", "aes", "bytes", "cbc", "fastcdc", "flate2", "int-enum", "md5", "msg_tool_macro/kirikiri-arc", "msg_tool_xp3data", "parse-size", "sha2", "utils-case-insensitive-string", "utils-serde-base64bytes", "utils-simple-pack", "zopfli", "zstd"] kirikiri-img = ["kirikiri", "image", "libtlg-rs"] musica = [] musica-arc = ["musica", "crc32fast", "flate2", "include-flate", "utils-blowfish", "utils-rc4", "utils-serde-base64bytes", "utils-xored-stream"] diff --git a/msg_tool_build/src/kr_arc.rs b/msg_tool_build/src/kr_arc.rs index 3459844..e2d51a6 100644 --- a/msg_tool_build/src/kr_arc.rs +++ b/msg_tool_build/src/kr_arc.rs @@ -65,3 +65,43 @@ pub fn gen_cx_cb + ?Sized, D: AsRef + ?Sized>( } Ok(()) } + +/// Pack all binary files in name_list into a single archive. +pub fn gen_name_list + ?Sized, D: AsRef + ?Sized>( + json_path: &P, + outdir: &D, + level: i32, +) -> std::io::Result<()> { + let p = json_path.as_ref(); + let pb = p + .parent() + .unwrap_or_else(|| Path::new("")) + .join("name_list"); + let json_data = std::fs::read_to_string(p)?; + let json = json::parse(&json_data) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; + let mut pack = SimplePack::new(&outdir.as_ref().join("name_list.pck"))?; + let mut seen_files = HashSet::new(); + for (_, obj) in json.entries() { + if let Some(name) = obj["FileListName"].as_str() { + if seen_files.contains(name) { + continue; + } + seen_files.insert(name.to_string()); + let file_path = pb.join(name); + if !file_path.exists() { + return Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("File not found: {}", file_path.display()), + )); + } + let file = std::fs::File::open(file_path)?; + let file = std::io::BufReader::new(file); + pack.add_file(name, file)?; + } + } + if level >= 0 && level <= 22 { + pack.compress(level)?; + } + Ok(()) +} diff --git a/msg_tool_macro/Cargo.toml b/msg_tool_macro/Cargo.toml index 212f084..37f4093 100644 --- a/msg_tool_macro/Cargo.toml +++ b/msg_tool_macro/Cargo.toml @@ -11,6 +11,7 @@ proc-macro = true [features] artemis-arc = [] +kirikiri-arc = [] unstable = [] [dependencies] diff --git a/msg_tool_macro/src/lib.rs b/msg_tool_macro/src/lib.rs index b7f1097..d1b0269 100644 --- a/msg_tool_macro/src/lib.rs +++ b/msg_tool_macro/src/lib.rs @@ -62,7 +62,10 @@ pub fn struct_unpack_impl_for_num(item: TokenStream) -> TokenStream { } fn has_skip_fmt_attr(field: &syn::Field) -> bool { - field.attrs.iter().any(|attr| attr.path().is_ident("skip_fmt")) + field + .attrs + .iter() + .any(|attr| attr.path().is_ident("skip_fmt")) } #[proc_macro_derive(MyDebug, attributes(skip_fmt))] @@ -87,7 +90,11 @@ pub fn debug_macro_derive(input: TokenStream) -> TokenStream { let mut generics = generics; { let where_clause = generics.make_where_clause(); - for field in data_struct.fields.iter().filter(|field| !has_skip_fmt_attr(field)) { + for field in data_struct + .fields + .iter() + .filter(|field| !has_skip_fmt_attr(field)) + { let ty = &field.ty; where_clause .predicates @@ -959,3 +966,17 @@ pub fn default_macro_derive(input: TokenStream) -> TokenStream { } .into() } + +#[cfg(feature = "kirikiri-arc")] +#[proc_macro] +pub fn rhapsody_crypt_const_name_hash(input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input as syn::LitStr); + let s = input.value(); + let mut expanded = quote::quote! { 0u32 }; + for c in s.chars() { + expanded = quote::quote! { + RhapsodyCrypt::update_name_hash(#expanded, #c) + }; + } + TokenStream::from(expanded) +} diff --git a/msg_tool_xp3data/build.rs b/msg_tool_xp3data/build.rs index 59477e3..6af2502 100644 --- a/msg_tool_xp3data/build.rs +++ b/msg_tool_xp3data/build.rs @@ -9,15 +9,20 @@ fn main() { "cargo:rerun-if-changed={}", source_dir.join("cx_cb").display() ); - let level = level + let arc_level = level .parse::() .expect("MSG_TOOL_KIRIKIRI_ARC_GEN_LEVEL must be a valid integer"); println!("cargo:rerun-if-env-changed=MSG_TOOL_KIRIKIRI_ARC_GEN_LEVEL"); - msg_tool_build::kr_arc::gen_cx_cb(&crypt_json_path, &outdir, level).unwrap(); + msg_tool_build::kr_arc::gen_cx_cb(&crypt_json_path, &outdir, arc_level).unwrap(); let level = std::env::var("MSG_TOOL_KIRIKIRI_CRYPT_COMPRESS_LEVEL").unwrap_or("22".to_string()); let level = level .parse::() .expect("MSG_TOOL_KIRIKIRI_CRYPT_COMPRESS_LEVEL must be a valid integer"); println!("cargo:rerun-if-env-changed=MSG_TOOL_KIRIKIRI_CRYPT_COMPRESS_LEVEL"); msg_tool_build::kr_arc::gen_crypt(&crypt_json_path, &outdir, level).unwrap(); + println!( + "cargo:rerun-if-changed={}", + source_dir.join("name_list").display() + ); + msg_tool_build::kr_arc::gen_name_list(&crypt_json_path, &outdir, arc_level).unwrap(); } diff --git a/msg_tool_xp3data/crypt.json b/msg_tool_xp3data/crypt.json index 13d0286..4e73dd2 100644 --- a/msg_tool_xp3data/crypt.json +++ b/msg_tool_xp3data/crypt.json @@ -477,6 +477,11 @@ "EvenBranchOrder": "AAECAwQFBgc=", "ControlBlockName": "fate_hollow.bin" }, + "Fate/Knight Rhapsody ACT 2": { + "$type": "RhapsodyCrypt", + "FileListName": "rhapsody.lst", + "Title": "招蕩的妄想劇場 ACT 2" + }, "Fate/stay night": { "$type": "FateCrypt", "HashAfterCrypt": true diff --git a/msg_tool_xp3data/lib.rs b/msg_tool_xp3data/lib.rs index 1fd312f..09a75c6 100644 --- a/msg_tool_xp3data/lib.rs +++ b/msg_tool_xp3data/lib.rs @@ -3,6 +3,8 @@ use std::io::Read; /// Control Block data for CxEncryption packed with SimplePack. pub const CX_CB_DATA: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/cx_cb.pck")); +/// Name list data packed with SimplePack. +pub const NAME_LIST_DATA: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/name_list.pck")); const CRYPT_DATA: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/crypt.json.zst")); /// Get the crypt.json data as a string. diff --git a/msg_tool_xp3data/name_list/rhapsody.lst b/msg_tool_xp3data/name_list/rhapsody.lst new file mode 100644 index 0000000..a70aba0 --- /dev/null +++ b/msg_tool_xp3data/name_list/rhapsody.lst @@ -0,0 +1,1548 @@ +bgimage/aroom.jpg +bgimage/avalon.jpg +bgimage/Battlefield1.jpg +bgimage/Battlefield2-2.jpg +bgimage/Battlefield2.jpg +bgimage/Battlefield3.jpg +bgimage/Battlefield4.jpg +bgimage/Battlefield5.jpg +bgimage/black.jpg +bgimage/Cage.jpg +bgimage/Camp1.jpg +bgimage/Camp2.jpg +bgimage/Camp3.jpg +bgimage/castle.jpg +bgimage/cave.jpg +bgimage/ch01.jpg +bgimage/ch02.jpg +bgimage/ch03.jpg +bgimage/ch04.jpg +bgimage/ch05.jpg +bgimage/ch06.jpg +bgimage/ch07.jpg +bgimage/ch08.jpg +bgimage/ch09.jpg +bgimage/church.jpg +bgimage/city.jpg +bgimage/Cliff1.jpg +bgimage/Cliff2.jpg +bgimage/end.jpg +bgimage/end2.jpg +bgimage/Forest1.jpg +bgimage/Forest10.jpg +bgimage/Forest11.jpg +bgimage/Forest12.jpg +bgimage/Forest13.jpg +bgimage/Forest14.jpg +bgimage/Forest2.jpg +bgimage/Forest3.jpg +bgimage/Forest4.jpg +bgimage/Forest5.jpg +bgimage/Forest6.jpg +bgimage/Forest7.jpg +bgimage/Forest8.jpg +bgimage/Forest9.jpg +bgimage/GoldForest.jpg +bgimage/grassland.jpg +bgimage/groom.jpg +bgimage/Hall.jpg +bgimage/Hilltop.jpg +bgimage/hotel.jpg +bgimage/inlake.jpg +bgimage/kitchen.jpg +bgimage/kroom1.jpg +bgimage/kroom2.jpg +bgimage/lake1.jpg +bgimage/lake2.jpg +bgimage/lake3.jpg +bgimage/logo.jpg +bgimage/map_badon.jpg +bgimage/mroom.jpg +bgimage/ncastle.jpg +bgimage/Nightsky.jpg +bgimage/office.jpg +bgimage/outdoor.jpg +bgimage/Palace1.jpg +bgimage/Palace2.jpg +bgimage/Palace3.jpg +bgimage/Paper.jpg +bgimage/river.jpg +bgimage/river2.jpg +bgimage/Room1.jpg +bgimage/round.jpg +bgimage/round2.jpg +bgimage/shop.jpg +bgimage/Sky.jpg +bgimage/Square.jpg +bgimage/Square2.jpg +bgimage/Street1.jpg +bgimage/Street2.jpg +bgimage/Street3.jpg +bgimage/Street4.jpg +bgimage/Street5.jpg +bgimage/Study.jpg +bgimage/Training.jpg +bgimage/Training2.jpg +bgimage/village.jpg +bgimage/village2.jpg +bgimage/vroom.jpg +bgimage/white.jpg +bgimage/witchroom.jpg +bgimage/witchroom2_1.jpg +bgimage/witchroom2_2.jpg +bgimage/橫.jpg +bgimage/橫2.jpg +bgimage/聲明.jpg +bgm/action1.ogg +bgm/action2.ogg +bgm/action3.ogg +bgm/action4.ogg +bgm/action5.ogg +bgm/action6.ogg +bgm/action7.ogg +bgm/action8.ogg +bgm/caliburn.ogg +bgm/castle.ogg +bgm/dark.ogg +bgm/decide.ogg +bgm/dream.ogg +bgm/end1.ogg +bgm/epic1.ogg +bgm/excalibur.ogg +bgm/face.ogg +bgm/fall.ogg +bgm/fight.ogg +bgm/fight2.ogg +bgm/glad.ogg +bgm/hope2.ogg +bgm/knight.ogg +bgm/last.ogg +bgm/magic.ogg +bgm/merlin.ogg +bgm/mind.ogg +bgm/mystic.ogg +bgm/night1.ogg +bgm/night2.ogg +bgm/normal.ogg +bgm/ready.ogg +bgm/ready2.ogg +bgm/sad1.ogg +bgm/sad2.ogg +bgm/sad3.ogg +bgm/sad4.ogg +bgm/sing.ogg +bgm/story1.ogg +bgm/story2.ogg +bgm/story3.ogg +bgm/TBC.ogg +bgm/title.ogg +bgm/trial.ogg +bgm/victory.ogg +bgm/war1.ogg +bgm/war2.ogg +bgm/war3.ogg +bgm/war4.ogg +bgm/war5.ogg +bgm/war8.ogg +bgm/watch.ogg +bgm/witch.ogg +Config.tjs +face/bs_button_exit_normal.png +face/bs_button_exit_over.png +face/bs_button_title_normal.png +face/bs_button_title_over.png +face/bs_option_slider.png +face/bs_option_slider_button.png +face/dia_button_01.png +face/dia_button_02.png +face/dia_button_03.png +face/dia_button_04.png +face/dia_button_05.png +face/dia_button_06.png +face/dia_button_07.png +face/dia_button_08.png +face/dia_button_09.png +face/dia_button_on_01.png +face/dia_button_on_02.png +face/dia_button_on_03.png +face/dia_button_on_04.png +face/dia_button_on_05.png +face/dia_button_on_06.png +face/dia_button_on_07.png +face/dia_button_on_08.png +face/dia_button_on_09.png +face/log_first_normal.png +face/log_first_over.png +face/log_last_normal.png +face/log_last_over.png +face/log_play_normal.png +face/log_play_over.png +face/menu_button_01.png +face/menu_button_02.png +face/menu_button_03.png +face/menu_button_04.png +face/menu_button_05.png +face/menu_button_06.png +face/menu_button_07.png +face/menu_button_08.png +face/menu_button_on_01.png +face/menu_button_on_02.png +face/menu_button_on_03.png +face/menu_button_on_04.png +face/menu_button_on_05.png +face/menu_button_on_06.png +face/menu_button_on_07.png +face/menu_button_on_08.png +face/option_button_01.png +face/option_button_02.png +face/option_button_on_01.png +face/option_button_on_02.png +face/title_button_01.png +face/title_button_02.png +face/title_button_03.png +face/title_button_04.png +face/title_button_05.png +face/title_button_on_01.png +face/title_button_on_02.png +face/title_button_on_03.png +face/title_button_on_04.png +face/title_button_on_05.png +fgimage/2fb1b1.png +fgimage/2fb1b2.png +fgimage/2fb1ex1.png +fgimage/2fb1nor1.png +fgimage/3cb1ex1.png +fgimage/3cb1nor2.png +fgimage/3cb1sad4.png +fgimage/3cb1sil1.png +fgimage/3fb1ang1.png +fgimage/3fb1ang2.png +fgimage/3fb1ex1.png +fgimage/3fb1nor2.png +fgimage/3fb1sad3.png +fgimage/3fb1thi1.png +fgimage/ca1ach1.png +fgimage/ca1ang1.png +fgimage/ca1ang2.png +fgimage/ca1b1.png +fgimage/ca1b2.png +fgimage/ca1clo1.png +fgimage/ca1con1.png +fgimage/ca1con2.png +fgimage/ca1cry1.png +fgimage/ca1cry2.png +fgimage/ca1cry3.png +fgimage/ca1ex1.png +fgimage/ca1ex2.png +fgimage/ca1ex3.png +fgimage/ca1ex4.png +fgimage/ca1ex5.png +fgimage/ca1ex6.png +fgimage/ca1ex7.png +fgimage/ca1he1.png +fgimage/ca1hun1.png +fgimage/ca1nor1.png +fgimage/ca1nor2.png +fgimage/ca1sad1.png +fgimage/ca1sad2.png +fgimage/ca1sad3.png +fgimage/ca1sad4.png +fgimage/ca1sha1.png +fgimage/ca1sha2.png +fgimage/ca1sha3.png +fgimage/ca1smi1.png +fgimage/ca1smi2.png +fgimage/ca1smi3.png +fgimage/ca1smi4.png +fgimage/ca1sur1.png +fgimage/ca1sur2.png +fgimage/ca1sur3.png +fgimage/ca1thi1.png +fgimage/ca2ach1.png +fgimage/ca2ang1.png +fgimage/ca2ang2.png +fgimage/ca2b1.png +fgimage/ca2b2.png +fgimage/ca2clo1.png +fgimage/ca2con1.png +fgimage/ca2con2.png +fgimage/ca2ex1.png +fgimage/ca2ex2.png +fgimage/ca2ex3.png +fgimage/ca2ex4.png +fgimage/ca2ex5.png +fgimage/ca2ex6.png +fgimage/ca2ex7.png +fgimage/ca2he1.png +fgimage/ca2hun1.png +fgimage/ca2nor1.png +fgimage/ca2nor2.png +fgimage/ca2sad1.png +fgimage/ca2sad2.png +fgimage/ca2sad3.png +fgimage/ca2sha1.png +fgimage/ca2sha2.png +fgimage/ca2sha3.png +fgimage/ca2smi1.png +fgimage/ca2smi2.png +fgimage/ca2smi3.png +fgimage/ca2smi4.png +fgimage/ca2sur1.png +fgimage/ca2sur2.png +fgimage/ca2sur3.png +fgimage/ca2thi1.png +fgimage/ca3ach1.png +fgimage/ca3ang1.png +fgimage/ca3ang2.png +fgimage/ca3b1.png +fgimage/ca3b2.png +fgimage/ca3clo1.png +fgimage/ca3con1.png +fgimage/ca3con2.png +fgimage/ca3ex1.png +fgimage/ca3ex2.png +fgimage/ca3ex3.png +fgimage/ca3ex4.png +fgimage/ca3ex5.png +fgimage/ca3ex6.png +fgimage/ca3ex7.png +fgimage/ca3he1.png +fgimage/ca3nor1.png +fgimage/ca3nor2.png +fgimage/ca3sad1.png +fgimage/ca3sad2.png +fgimage/ca3sad3.png +fgimage/ca3sad4.png +fgimage/ca3sha1.png +fgimage/ca3sha2.png +fgimage/ca3sha3.png +fgimage/ca3smi1.png +fgimage/ca3smi2.png +fgimage/ca3smi3.png +fgimage/ca3smi4.png +fgimage/ca3sur1.png +fgimage/ca3sur2.png +fgimage/ca3sur3.png +fgimage/ca3thi1.png +fgimage/cb1ach1.png +fgimage/cb1ang1.png +fgimage/cb1ang2.png +fgimage/cb1b1.png +fgimage/cb1b2.png +fgimage/cb1clo1.png +fgimage/cb1ex1.png +fgimage/cb1ex2.png +fgimage/cb1ex3.png +fgimage/cb1ex4.png +fgimage/cb1he1.png +fgimage/cb1nor1.png +fgimage/cb1nor2.png +fgimage/cb1sad1.png +fgimage/cb1sad2.png +fgimage/cb1sad3.png +fgimage/cb1sad4.png +fgimage/cb1sha1.png +fgimage/cb1sha2.png +fgimage/cb1sha3.png +fgimage/cb1sil1.png +fgimage/cb1smi1.png +fgimage/cb1smi2.png +fgimage/cb1smi4.png +fgimage/cb1smi5.png +fgimage/cb1sur1.png +fgimage/cb1sur2.png +fgimage/cb1sur3.png +fgimage/cb1thi1.png +fgimage/cb2ang1.png +fgimage/cb2b1.png +fgimage/cb2nor1.png +fgimage/cb2sha2.png +fgimage/cb2smi2.png +fgimage/cb2smi5.png +fgimage/cb2sur1.png +fgimage/cb2sur2.png +fgimage/cb2thi1.png +fgimage/cb3ach1.png +fgimage/cb3ang2.png +fgimage/cb3b2.png +fgimage/cb3clo1.png +fgimage/cb3nor1.png +fgimage/cb3nor2.png +fgimage/cb3sad1.png +fgimage/cb3sad4.png +fgimage/cb3sil1.png +fgimage/cb3sur2.png +fgimage/cbo1ang1.png +fgimage/cbo1b1.png +fgimage/cbo1nor1.png +fgimage/cbo1sad2.png +fgimage/cbo1smi2.png +fgimage/cg1ang1.png +fgimage/cg1ang2.png +fgimage/cg1b1.png +fgimage/cg1b2.png +fgimage/cg1clo1.png +fgimage/cg1con1.png +fgimage/cg1cry1.png +fgimage/cg1ex1.png +fgimage/cg1he1.png +fgimage/cg1nor1.png +fgimage/cg1nor2.png +fgimage/cg1sad1.png +fgimage/cg1sad2.png +fgimage/cg1sad3.png +fgimage/cg1sad4.png +fgimage/cg1sad5.png +fgimage/cg1sha1.png +fgimage/cg1sha3.png +fgimage/cg1smi1.png +fgimage/cg1smi2.png +fgimage/cg1smi3.png +fgimage/cg1smi4.png +fgimage/cg1smi5.png +fgimage/cg1smi6.png +fgimage/cg1sur1.png +fgimage/cg1sur2.png +fgimage/cg1thi1.png +fgimage/cg2ach1.png +fgimage/cg2b1.png +fgimage/cg2ex1.png +fgimage/cg2sha2.png +fgimage/cg2smi1.png +fgimage/cg2smi3.png +fgimage/cg2smi5.png +fgimage/cg2smi6.png +fgimage/cg2sur3.png +fgimage/cg3ang1.png +fgimage/cg3smi6.png +fgimage/ck1ach1.png +fgimage/ck1ang1.png +fgimage/ck1ang2.png +fgimage/ck1b1.png +fgimage/ck1bad1.png +fgimage/ck1con1.png +fgimage/ck1ex1.png +fgimage/ck1ex2.png +fgimage/ck1he1.png +fgimage/ck1nor1.png +fgimage/ck1nor2.png +fgimage/ck1sad1.png +fgimage/ck1sha1.png +fgimage/ck1smi1.png +fgimage/ck1smi2.png +fgimage/ck1smi4.png +fgimage/ck1sur1.png +fgimage/ck1sur2.png +fgimage/ck1thi1.png +fgimage/cl1ach1.png +fgimage/cl1ang1.png +fgimage/cl1ang2.png +fgimage/cl1ang3.png +fgimage/cl1b1.png +fgimage/cl1b2.png +fgimage/cl1clo1.png +fgimage/cl1con1.png +fgimage/cl1cry1.png +fgimage/cl1ex1.png +fgimage/cl1nor1.png +fgimage/cl1nor2.png +fgimage/cl1sad1.png +fgimage/cl1sad2.png +fgimage/cl1sad3.png +fgimage/cl1sad4.png +fgimage/cl1sha1.png +fgimage/cl1sha2.png +fgimage/cl1sha3.png +fgimage/cl1smi1.png +fgimage/cl1smi2.png +fgimage/cl1smi3.png +fgimage/cl1smi4.png +fgimage/cl1sur1.png +fgimage/cl1sur2.png +fgimage/cl1sur3.png +fgimage/cl1thi1.png +fgimage/cl2ach1.png +fgimage/cl2ang1.png +fgimage/cl2b1.png +fgimage/cl2b2.png +fgimage/cl2clo1.png +fgimage/cl2ex1.png +fgimage/cl2ex2.png +fgimage/cl2nor1.png +fgimage/cl2nor2.png +fgimage/cl2sad1.png +fgimage/cl2sad2.png +fgimage/cl2sad3.png +fgimage/cl2sad4.png +fgimage/cl2sha1.png +fgimage/cl2sha3.png +fgimage/cl2smi1.png +fgimage/cl2smi2.png +fgimage/cl2smi3.png +fgimage/cl2sur1.png +fgimage/cl2sur2.png +fgimage/cl2sur3.png +fgimage/cl2thi1.png +fgimage/cl3nor2.png +fgimage/cm1ang1.png +fgimage/cm1ang2.png +fgimage/cm1b1.png +fgimage/cm1b2.png +fgimage/cm1clo1.png +fgimage/cm1con2.png +fgimage/cm1nor1.png +fgimage/cm1nor2.png +fgimage/cm1s1.png +fgimage/cm1sil1.png +fgimage/cm1smi1.png +fgimage/cm1smi2.png +fgimage/cm1smi3.png +fgimage/cm1smi4.png +fgimage/cm1smi5.png +fgimage/cm1sur1.png +fgimage/cm1sur2.png +fgimage/cm1sur3.png +fgimage/cm1thi1.png +fgimage/cm2ang1.png +fgimage/cm2nor1.png +fgimage/cm2nor2.png +fgimage/cm2smi1.png +fgimage/cm2smi2.png +fgimage/cm2sur1.png +fgimage/cm2thi1.png +fgimage/cm3ang1.png +fgimage/cm3ang2.png +fgimage/cm3b1.png +fgimage/cm3b2.png +fgimage/cm3clo1.png +fgimage/cm3con1.png +fgimage/cm3nor1.png +fgimage/cm3nor2.png +fgimage/cm3s1.png +fgimage/cm3sad1.png +fgimage/cm3sad2.png +fgimage/cm3sad3.png +fgimage/cm3sha1.png +fgimage/cm3smi1.png +fgimage/cm3smi2.png +fgimage/cm3smi3.png +fgimage/cm3smi5.png +fgimage/cm3sur2.png +fgimage/cm3thi1.png +fgimage/cmd1.png +fgimage/cmd2nor2.png +fgimage/cmo1ach1.png +fgimage/cmo1ang1.png +fgimage/cmo1ang2.png +fgimage/cmo1ang3.png +fgimage/cmo1b1.png +fgimage/cmo1b2.png +fgimage/cmo1clo1.png +fgimage/cmo1con1.png +fgimage/cmo1nor1.png +fgimage/cmo1nor2.png +fgimage/cmo1s1.png +fgimage/cmo1s2.png +fgimage/cmo1sad1.png +fgimage/cmo1sad2.png +fgimage/cmo1smi1.png +fgimage/cmo1smi2.png +fgimage/cmo1smi3.png +fgimage/cmo1smi4.png +fgimage/cmo1smi5.png +fgimage/cmo1sur1.png +fgimage/cmo1sur2.png +fgimage/cmo1thi1.png +fgimage/ct1ang1.png +fgimage/ct1ang2.png +fgimage/ct1b1.png +fgimage/ct1con1.png +fgimage/ct1he1.png +fgimage/ct1nor1.png +fgimage/ct1nor2.png +fgimage/ct1sad1.png +fgimage/ct1sad2.png +fgimage/ct1smi1.png +fgimage/ct1smi2.png +fgimage/ct1son.png +fgimage/ct1sur1.png +fgimage/fa1ach1.png +fgimage/fa1ang1.png +fgimage/fa1ang2.png +fgimage/fa1b1.png +fgimage/fa1b2.png +fgimage/fa1clo1.png +fgimage/fa1con1.png +fgimage/fa1con2.png +fgimage/fa1cry2.png +fgimage/fa1cry3.png +fgimage/fa1ex1.png +fgimage/fa1ex2.png +fgimage/fa1ex3.png +fgimage/fa1ex4.png +fgimage/fa1ex5.png +fgimage/fa1ex7.png +fgimage/fa1he1.png +fgimage/fa1hun1.png +fgimage/fa1nor1.png +fgimage/fa1nor2.png +fgimage/fa1sad1.png +fgimage/fa1sad2.png +fgimage/fa1sad3.png +fgimage/fa1sad4.png +fgimage/fa1sha1.png +fgimage/fa1sha2.png +fgimage/fa1sha3.png +fgimage/fa1smi1.png +fgimage/fa1smi2.png +fgimage/fa1smi3.png +fgimage/fa1smi4.png +fgimage/fa1sur1.png +fgimage/fa1sur2.png +fgimage/fa1sur3.png +fgimage/fa1thi1.png +fgimage/fa2ach1.png +fgimage/fa2ang1.png +fgimage/fa2ang2.png +fgimage/fa2b1.png +fgimage/fa2b2.png +fgimage/fa2clo1.png +fgimage/fa2con1.png +fgimage/fa2con2.png +fgimage/fa2ex1.png +fgimage/fa2ex2.png +fgimage/fa2ex3.png +fgimage/fa2ex4.png +fgimage/fa2ex5.png +fgimage/fa2ex6.png +fgimage/fa2ex7.png +fgimage/fa2he1.png +fgimage/fa2hun1.png +fgimage/fa2nor1.png +fgimage/fa2nor2.png +fgimage/fa2sad1.png +fgimage/fa2sad2.png +fgimage/fa2sad3.png +fgimage/fa2sha1.png +fgimage/fa2sha2.png +fgimage/fa2sha3.png +fgimage/fa2smi1.png +fgimage/fa2smi2.png +fgimage/fa2smi3.png +fgimage/fa2smi4.png +fgimage/fa2sur1.png +fgimage/fa2sur2.png +fgimage/fa2sur3.png +fgimage/fa2thi1.png +fgimage/fa3ach1.png +fgimage/fa3ang1.png +fgimage/fa3ang2.png +fgimage/fa3b1.png +fgimage/fa3b2.png +fgimage/fa3clo1.png +fgimage/fa3con1.png +fgimage/fa3con2.png +fgimage/fa3ex1.png +fgimage/fa3ex2.png +fgimage/fa3ex3.png +fgimage/fa3ex4.png +fgimage/fa3ex5.png +fgimage/fa3ex6.png +fgimage/fa3ex7.png +fgimage/fa3he1.png +fgimage/fa3nor1.png +fgimage/fa3nor2.png +fgimage/fa3sad1.png +fgimage/fa3sad2.png +fgimage/fa3sad3.png +fgimage/fa3sad4.png +fgimage/fa3sha1.png +fgimage/fa3sha2.png +fgimage/fa3sha3.png +fgimage/fa3smi1.png +fgimage/fa3smi2.png +fgimage/fa3smi3.png +fgimage/fa3smi4.png +fgimage/fa3sur1.png +fgimage/fa3sur2.png +fgimage/fa3sur3.png +fgimage/fa3thi1.png +fgimage/fb1ach1.png +fgimage/fb1ang1.png +fgimage/fb1ang2.png +fgimage/fb1b1.png +fgimage/fb1b2.png +fgimage/fb1clo1.png +fgimage/fb1ex1.png +fgimage/fb1ex2.png +fgimage/fb1ex3.png +fgimage/fb1ex4.png +fgimage/fb1he1.png +fgimage/fb1nor1.png +fgimage/fb1nor2.png +fgimage/fb1sad1.png +fgimage/fb1sad2.png +fgimage/fb1sad3.png +fgimage/fb1sad4.png +fgimage/fb1sha1.png +fgimage/fb1sha2.png +fgimage/fb1sha3.png +fgimage/fb1sil1.png +fgimage/fb1smi1.png +fgimage/fb1smi2.png +fgimage/fb1smi4.png +fgimage/fb1smi5.png +fgimage/fb1sur1.png +fgimage/fb1sur2.png +fgimage/fb1sur3.png +fgimage/fb1thi1.png +fgimage/fb2ang1.png +fgimage/fb2b1.png +fgimage/fb2nor1.png +fgimage/fb2sha2.png +fgimage/fb2smi2.png +fgimage/fb2smi5.png +fgimage/fb2sur1.png +fgimage/fb2sur2.png +fgimage/fb2thi1.png +fgimage/fb3ang1.png +fgimage/fb3ang2.png +fgimage/fb3b1.png +fgimage/fb3nor1.png +fgimage/fb3sha2.png +fgimage/fb3smi1.png +fgimage/fb3sur1.png +fgimage/fb3sur2.png +fgimage/fbo1ang1.png +fgimage/fbo1b1.png +fgimage/fbo1nor1.png +fgimage/fbo1sad2.png +fgimage/fbo1smi2.png +fgimage/fg1ang1.png +fgimage/fg1ang2.png +fgimage/fg1b1.png +fgimage/fg1b2.png +fgimage/fg1clo1.png +fgimage/fg1con1.png +fgimage/fg1cry1.png +fgimage/fg1ex1.png +fgimage/fg1he1.png +fgimage/fg1nor1.png +fgimage/fg1nor2.png +fgimage/fg1sad1.png +fgimage/fg1sad2.png +fgimage/fg1sad3.png +fgimage/fg1sad4.png +fgimage/fg1sad5.png +fgimage/fg1sha1.png +fgimage/fg1sha3.png +fgimage/fg1smi1.png +fgimage/fg1smi2.png +fgimage/fg1smi3.png +fgimage/fg1smi4.png +fgimage/fg1smi5.png +fgimage/fg1smi6.png +fgimage/fg1sur1.png +fgimage/fg1sur2.png +fgimage/fg1thi1.png +fgimage/fg2ach1.png +fgimage/fg2b1.png +fgimage/fg2ex1.png +fgimage/fg2sha2.png +fgimage/fg2smi1.png +fgimage/fg2smi3.png +fgimage/fg2smi5.png +fgimage/fg2smi6.png +fgimage/fg2sur3.png +fgimage/fg3ang1.png +fgimage/fg3b1.png +fgimage/fg3nor1.png +fgimage/fg3nor2.png +fgimage/fg3sha3.png +fgimage/fg3smi1.png +fgimage/fg3smi2.png +fgimage/fg3smi5.png +fgimage/fg3smi6.png +fgimage/fg3sur1.png +fgimage/fg3sur2.png +fgimage/fire.png +fgimage/fk1ach1.png +fgimage/fk1ang1.png +fgimage/fk1ang2.png +fgimage/fk1b1.png +fgimage/fk1bad1.png +fgimage/fk1con1.png +fgimage/fk1ex1.png +fgimage/fk1ex2.png +fgimage/fk1he1.png +fgimage/fk1nor1.png +fgimage/fk1nor2.png +fgimage/fk1sad1.png +fgimage/fk1sha1.png +fgimage/fk1smi1.png +fgimage/fk1smi2.png +fgimage/fk1smi4.png +fgimage/fk1sur1.png +fgimage/fk1sur2.png +fgimage/fk1thi1.png +fgimage/fklthi1.png +fgimage/fl1ach1.png +fgimage/fl1ang1.png +fgimage/fl1ang2.png +fgimage/fl1ang3.png +fgimage/fl1b1.png +fgimage/fl1b2.png +fgimage/fl1clo1.png +fgimage/fl1con1.png +fgimage/fl1cry1.png +fgimage/fl1ex1.png +fgimage/fl1nor1.png +fgimage/fl1nor2.png +fgimage/fl1sad1.png +fgimage/fl1sad2.png +fgimage/fl1sad3.png +fgimage/fl1sad4.png +fgimage/fl1sha1.png +fgimage/fl1sha2.png +fgimage/fl1sha3.png +fgimage/fl1smi1.png +fgimage/fl1smi2.png +fgimage/fl1smi3.png +fgimage/fl1smi4.png +fgimage/fl1sur1.png +fgimage/fl1sur2.png +fgimage/fl1sur3.png +fgimage/fl1thi1.png +fgimage/fl2ach1.png +fgimage/fl2ang1.png +fgimage/fl2b1.png +fgimage/fl2b2.png +fgimage/fl2clo1.png +fgimage/fl2ex1.png +fgimage/fl2ex2.png +fgimage/fl2nor1.png +fgimage/fl2nor2.png +fgimage/fl2sad1.png +fgimage/fl2sad2.png +fgimage/fl2sad3.png +fgimage/fl2sad4.png +fgimage/fl2sha1.png +fgimage/fl2sha3.png +fgimage/fl2smi1.png +fgimage/fl2smi2.png +fgimage/fl2smi3.png +fgimage/fl2sur1.png +fgimage/fl2sur2.png +fgimage/fl2sur3.png +fgimage/fl2thi1.png +fgimage/fl3nor1.png +fgimage/fl3nor2.png +fgimage/fl3smi1.png +fgimage/fl3smi2.png +fgimage/fl3smi4.png +fgimage/fl3sur1.png +fgimage/fm1ang1.png +fgimage/fm1ang2.png +fgimage/fm1b1.png +fgimage/fm1b2.png +fgimage/fm1clo1.png +fgimage/fm1con2.png +fgimage/fm1nor1.png +fgimage/fm1nor2.png +fgimage/fm1s1.png +fgimage/fm1sil1.png +fgimage/fm1smi1.png +fgimage/fm1smi2.png +fgimage/fm1smi3.png +fgimage/fm1smi4.png +fgimage/fm1smi5.png +fgimage/fm1sur1.png +fgimage/fm1sur2.png +fgimage/fm1sur3.png +fgimage/fm1thi1.png +fgimage/fm2nor1.png +fgimage/fm2nor2.png +fgimage/fm2sur1.png +fgimage/fm3ach1.png +fgimage/fm3ang1.png +fgimage/fm3ang2.png +fgimage/fm3b1.png +fgimage/fm3b2.png +fgimage/fm3clo1.png +fgimage/fm3con1.png +fgimage/fm3con2.png +fgimage/fm3he1.png +fgimage/fm3nor1.png +fgimage/fm3nor2.png +fgimage/fm3s1.png +fgimage/fm3sad1.png +fgimage/fm3sad2.png +fgimage/fm3sad3.png +fgimage/fm3smi1.png +fgimage/fm3smi2.png +fgimage/fm3smi3.png +fgimage/fm3smi5.png +fgimage/fm3sur2.png +fgimage/fm3thi1.png +fgimage/fmd1.png +fgimage/fmd2nor1.png +fgimage/fmd2nor2.png +fgimage/fmo1ach1.png +fgimage/fmo1ang1.png +fgimage/fmo1ang2.png +fgimage/fmo1ang3.png +fgimage/fmo1b1.png +fgimage/fmo1b2.png +fgimage/fmo1clo1.png +fgimage/fmo1con1.png +fgimage/fmo1nor1.png +fgimage/fmo1nor2.png +fgimage/fmo1s1.png +fgimage/fmo1s2.png +fgimage/fmo1sad1.png +fgimage/fmo1sad2.png +fgimage/fmo1smi1.png +fgimage/fmo1smi2.png +fgimage/fmo1smi3.png +fgimage/fmo1smi4.png +fgimage/fmo1smi5.png +fgimage/fmo1sur1.png +fgimage/fmo1sur2.png +fgimage/fmo1thi1.png +fgimage/ft1ang1.png +fgimage/ft1b1.png +fgimage/ft1con1.png +fgimage/ft1he1.png +fgimage/ft1nor1.png +fgimage/ft1nor2.png +fgimage/ft1sad1.png +fgimage/ft1sad2.png +fgimage/ft1smi1.png +fgimage/ft1smi2.png +fgimage/ft1son.png +fgimage/ft1sur1.png +fgimage/ft1thi1.png +fgimage/m_dragon.png +fgimage/m_huge.png +fgimage/m_king.png +fgimage/m_m01.png +fgimage/m_m02.png +fgimage/m_m03.png +fgimage/m_man.png +fgimage/m_snake.png +fgimage/r_b.png +fgimage/r_g.png +fgimage/r_k.png +fgimage/r_l.png +fgimage/r_t.png +image/A01.png +image/A01_2.png +image/A01_3.png +image/A02.png +image/A02_2.png +image/A03.png +image/A03r.png +image/A04.png +image/A04_2.png +image/A04_3.png +image/act01_c1.png +image/act01_c2.png +image/act01_c3.png +image/act01_e1.png +image/act01_e2.png +image/act01_e3.png +image/act02_c.png +image/act02_e.png +image/B01.png +image/B01_2.png +image/B01_3.png +image/ef01hit.png +image/ef02blood.jpg +image/ef03flylight.png +image/empty.png +image/G01.png +image/L01.png +image/line0022.png +image/M01.png +image/M01_2.png +image/name_b.png +image/name_g.png +image/name_k.png +image/name_l.png +image/name_t.png +image/O01.png +image/O01_2.png +image/O02.png +image/roundcycle.png +image/roundlight1.jpg +image/roundlight2.jpg +image/speed.png +kagplugin/AnimPlayer.ks +kagplugin/bloom.asd +kagplugin/bloom.png +kagplugin/bloom_a.png +kagplugin/DateControler.ks +kagplugin/envinit.tjs +kagplugin/FadeChLayer.tjs +kagplugin/FadeLayer.tjs +kagplugin/fch_Override.tjs +kagplugin/fire.asd +kagplugin/fire.png +kagplugin/firefly.ks +kagplugin/firefly_0.png +kagplugin/firefly_1.png +kagplugin/firefly_2.png +kagplugin/firefly_3.png +kagplugin/firefly_4.png +kagplugin/fire_a.png +kagplugin/fog.ks +kagplugin/fog_0.png +kagplugin/fog_1.png +kagplugin/fog_2.png +kagplugin/fog_3.png +kagplugin/godlight.asd +kagplugin/godlight.png +kagplugin/godlight_a.png +kagplugin/light.asd +kagplugin/light.png +kagplugin/light_a.png +kagplugin/loading.asd +kagplugin/loading.png +kagplugin/loading_a.png +kagplugin/momiji.ks +kagplugin/MoveMouseCursorPlugin.tjs +kagplugin/MovieLayerPlugin.tjs +kagplugin/MyHistoryLayer.tjs +kagplugin/MyYesNoDialog.tjs +kagplugin/oldMovie.ks +kagplugin/PicScroller.ks +kagplugin/PMultiText.tjs +kagplugin/rain.ks +kagplugin/sakura.ks +kagplugin/SharedContinuousHandler.tjs +kagplugin/show.ks +kagplugin/snow.ks +kagplugin/snow_0.png +kagplugin/snow_1.png +kagplugin/snow_2.png +kagplugin/snow_3.png +kagplugin/snow_4.png +kagplugin/staffroll.ks +kagplugin/timebar.ks +kagplugin/Utils_graphics.tjs +kagplugin/WearFilmPlugin.tjs +macro/cglist.txt +macro/macro_name.ks +macro/macro_self.ks +macro/namelist.tjs +macro/setting.tjs +macro/start.ks +macro/uicgmode.tjs +macro/uidia.tjs +macro/uihistory.tjs +macro/uiload.tjs +macro/uimenu.tjs +macro/uioption.tjs +macro/uisave.tjs +macro/uislpos.tjs +macro/uititle.tjs +map/b01.ks +map/b02.ks +map/b03.ks +map/g01.ks +map/g02.ks +map/g03.ks +map/l01.ks +map/l02.ks +map/l03.ks +map/m01.ks +map/m02.ks +map/m03.ks +map/map1.map +map/map1b.ks +map/map1g.ks +map/map1k.ks +map/map1l.ks +map/map1m.ks +map/map1t.ks +map/map2a.map +map/map2b.ks +map/map2b.map +map/map2bo.ks +map/map2g.ks +map/map2k.ks +map/map2l.ks +map/map2m.ks +map/map2t.ks +map/map3.map +map/map3b.ks +map/map3b.map +map/map3g.ks +map/map3l.ks +map/map3m.ks +map/sample.map +nvl/a03_thum.png +nvl/cgmode.ks +nvl/item.ks +nvl/l01_thum.png +nvl/load.ks +nvl/macro.ks +nvl/macro_cal.ks +nvl/macro_cg.ks +nvl/macro_data.ks +nvl/macro_edu.ks +nvl/macro_item.ks +nvl/macro_map.ks +nvl/macro_play.ks +nvl/macro_sl.ks +nvl/macro_ui.ks +nvl/main_menu.ks +nvl/MySaveLoadFunction.tjs +nvl/option.ks +nvl/rclick.ks +nvl/save.ks +others/b01-1.png +others/b01-2.png +others/b01-3.png +others/b02-1.png +others/b02-2.png +others/b02-3.png +others/b03-1.png +others/b03-2.png +others/b03-3.png +others/b04-1.png +others/b04-2.png +others/b04-3.png +others/b05-1.png +others/b05-2.png +others/b05-3.png +others/b06-1.png +others/b06-2.png +others/b06-3.png +others/b07-1.png +others/b07-2.png +others/b07-3.png +others/ba01.png +others/ba02.png +others/bar.png +others/basa01.png +others/basa02.png +others/c1.png +others/c2.png +others/cg.jpg +others/cgskin.png +others/cg_mask.png +others/cg_thum_size.png +others/ch01.png +others/ch02.png +others/choose1-1.png +others/choose1-2.png +others/choose1-3.png +others/close1-1.png +others/close1-2.png +others/close1-3.png +others/col.asd +others/col.png +others/col_a.png +others/cover1-1.png +others/cover1-2.png +others/cover1-3.png +others/do01.png +others/do02.png +others/exit1-1.png +others/exit1-2.png +others/exit1-3.png +others/font.tft +others/font_14.tft +others/ga01.png +others/ga02.png +others/gc.asd +others/gc.png +others/gc_a.png +others/his02.png +others/history.png +others/kai01.png +others/kai02.png +others/load.jpg +others/load01.png +others/load02.png +others/load1-1.png +others/load1-2.png +others/load1-3.png +others/map.jpg +others/map_button1.png +others/me01.png +others/me02.png +others/mouse.cur +others/name_frame.png +others/naxt1-1.png +others/naxt1-2.png +others/naxt1-3.png +others/no1-1.png +others/no1-2.png +others/no1-3.png +others/ok1-1.png +others/ok1-2.png +others/ok1-3.png +others/options.png +others/point.png +others/point2.asd +others/point2.png +others/point2_a.png +others/pve1-1.png +others/pve1-2.png +others/pve1-3.png +others/rb.asd +others/rb.png +others/rb_a.png +others/rd.asd +others/rd.png +others/rd_a.png +others/rg.asd +others/rg.png +others/rg_a.png +others/save.jpg +others/save01.png +others/save02.png +others/start1-1.png +others/start1-2.png +others/start1-3.png +others/system.png +others/ta1-1.png +others/ta1-2.png +others/ta1-3.png +others/ta2-1.png +others/ta2-2.png +others/ta2-3.png +others/ta3-1.png +others/ta3-2.png +others/ta3-3.png +others/ta4-1.png +others/ta4-2.png +others/ta4-3.png +others/titlebg.png +others/titlebg2_1.png +others/titlebg2_2.png +others/tmb.asd +others/tmb.png +others/tmb_a.png +others/tt.asd +others/tt.png +others/tt_a.png +others/wc.asd +others/wc.png +others/wc_a.png +others/yes1-1.png +others/yes1-2.png +others/yes1-3.png +others/yesno_frame.png +rule/00.jpg +rule/01.jpg +rule/02.jpg +rule/03.jpg +rule/04.jpg +rule/05.jpg +rule/06.jpg +rule/07.jpg +rule/08.jpg +rule/09.jpg +rule/10.jpg +rule/11.jpg +rule/12.jpg +rule/13.jpg +rule/14.jpg +rule/15.jpg +rule/16.jpg +rule/17.jpg +rule/18.jpg +rule/19.jpg +rule/20.jpg +rule/21.jpg +rule/22.jpg +rule/23.jpg +rule/24.jpg +rule/25.jpg +rule/26.jpg +rule/27.jpg +rule/28.jpg +rule/29.jpg +rule/30.jpg +rule/31.jpg +rule/32.jpg +rule/33.jpg +rule/34.jpg +rule/35.jpg +rule/36.jpg +rule/37.jpg +rule/38.jpg +rule/39.jpg +rule/40.jpg +rule/41.jpg +rule/42.jpg +rule/43.jpg +rule/44.jpg +rule/45.jpg +rule/46.jpg +rule/47.jpg +rule/48.jpg +rule/49.jpg +rule/50.jpg +rule/51.jpg +rule/52.jpg +rule/53.jpg +rule/54.jpg +rule/55.jpg +rule/56.jpg +rule/57.jpg +rule/58.jpg +rule/59.jpg +rule/60.jpg +rule/61.jpg +rule/62.jpg +rule/63.jpg +rule/64.jpg +rule/65.jpg +rule/66.jpg +rule/67.jpg +rule/67.png +rule/68.jpg +rule/69.jpg +rule/70.jpg +rule/71.jpg +rule/72.jpg +rule/73.jpg +rule/74.jpg +rule/75.jpg +rule/76.jpg +rule/rule_01.jpg +rule/rule_02.jpg +rule/rule_03.jpg +rule/rule_04.jpg +rule/rule_05.jpg +rule/rule_06.jpg +rule/rule_07.jpg +rule/rule_08.jpg +rule/rule_09.jpg +rule/rule_10.jpg +rule/rule_11.jpg +rule/rule_12.jpg +rule/rule_13.jpg +rule/rule_14.jpg +rule/rule_15.jpg +rule/rule_16.jpg +rule/rule_17.jpg +rule/rule_18.jpg +rule/rule_19.jpg +rule/rule_20.jpg +rule/rule_21.jpg +rule/rule_22.jpg +rule/rule_23.jpg +rule/rule_24.jpg +rule/rule_25.jpg +rule/rule_26.jpg +rule/rule_27.jpg +rule/rule_28.jpg +rule/rule_29.jpg +rule/rule_30.jpg +scenario/a01.ks +scenario/a02.ks +scenario/a03a.ks +scenario/a03b.ks +scenario/a03c.ks +scenario/a04a.ks +scenario/a04b.ks +scenario/a04c.ks +scenario/a05a.ks +scenario/a05b.ks +scenario/a05c.ks +scenario/a05d.ks +scenario/a05e.ks +scenario/a05f.ks +scenario/a06b.ks +scenario/a06c.ks +scenario/a07a.ks +scenario/a07b.ks +scenario/a07c.ks +scenario/a08a.ks +scenario/a08b.ks +scenario/a08c.ks +scenario/a08d.ks +scenario/a09a.ks +scenario/a09b.ks +scenario/a09c.ks +scenario/a10.ks +scenario/AfterInit.tjs +scenario/End1.ks +scenario/ex1.ks +scenario/ex2.ks +scenario/first.ks +scenario/Override.tjs +scenario/title.ks +sound/act01hand.wav +sound/bird01.wav +sound/blood01.wav +sound/blood02.wav +sound/bloom01.wav +sound/bloom02.wav +sound/book.ogg +sound/bow01.wav +sound/bow02.wav +sound/bow03.wav +sound/bow04.wav +sound/bravo.wav +sound/broke.wav +sound/chapter.wav +sound/clap.wav +sound/coin.wav +sound/confuse.wav +sound/crow.wav +sound/cry.wav +sound/disapper.wav +sound/doorclose.ogg +sound/dooropen.ogg +sound/down.wav +sound/dragon01.wav +sound/dragon02.wav +sound/drowning.wav +sound/emerge.ogg +sound/emo01.ogg +sound/fairy.wav +sound/fire.ogg +sound/heart.ogg +sound/hit.wav +sound/hit2.ogg +sound/horn.wav +sound/horse.wav +sound/horse2.wav +sound/horsecar.wav +sound/huge01.wav +sound/hungry.wav +sound/inwater.wav +sound/inwater2.wav +sound/jump1.wav +sound/jump2.wav +sound/knock.ogg +sound/lift.wav +sound/lift2.wav +sound/light.wav +sound/magic01echo.wav +sound/magic02shockwave.wav +sound/magic03focus.wav +sound/magic03focus2.wav +sound/magic04fly.wav +sound/magichit.wav +sound/magicoffset1.wav +sound/magicwater1.wav +sound/magicwind.wav +sound/magicww.wav +sound/monkey.wav +sound/monster01.wav +sound/monster02.wav +sound/monster03.ogg +sound/noisy.wav +sound/onnn.wav +sound/page.wav +sound/quake01.wav +sound/quake02.wav +sound/quake03.wav +sound/rain.wav +sound/resonance.wav +sound/ring.wav +sound/river.wav +sound/run.wav +sound/run2.wav +sound/run3.ogg +sound/sisu.ogg +sound/sword01.wav +sound/sword02.wav +sound/sword03.wav +sound/sword04x.wav +sound/sword05x.wav +sound/sword06x.wav +sound/sword07x.wav +sound/sword08x2.wav +sound/sword09x2.wav +sound/sword10b.wav +sound/sword10b2.wav +sound/sword11act3.wav +sound/sword12hit1.wav +sound/sword12hit2.wav +sound/sword13.wav +sound/sword14down.wav +sound/sword15back1.wav +sound/sword15back2.wav +sound/sword16face.wav +sound/swordbroke.wav +sound/swordout.ogg +sound/swordswings.ogg +sound/thunder.wav +sound/walk1.wav +sound/walk2.wav +sound/walk3.wav +sound/walk4.wav +sound/walk5.ogg +sound/walk6.ogg +sound/walk7.wav +sound/war1.wav +sound/war2.wav +sound/weaponhit.wav +sound/whistle.wav +sound/wind.wav +sound/window.wav +sound/wing.wav +sound/woman.wav +sound/write.wav +startup.tjs +system/Action.tjs +system/AffineLayer.tjs +system/AnimationLayer.tjs +system/autolabel.ks +system/BGM.tjs +system/BitmapFont.tjs +system/ButtonLayer.tjs +system/CheckBoxLayer.tjs +system/Conductor.tjs +system/DefaultMover.tjs +system/DialogLayer.tjs +system/EditLayer.tjs +system/GFX_Fire.tjs +system/GFX_Flash.tjs +system/GFX_Movie.tjs +system/GFX_Particle.tjs +system/GraphicLayer.tjs +system/HistoryLayer.tjs +system/Initialize.tjs +system/KAGEnvBaseLayer.tjs +system/KAGEnvBGM.tjs +system/KAGEnvCharacter.tjs +system/KAGEnvCharacterPatch.tjs +system/KAGEnvImage.tjs +system/KAGEnvironment.tjs +system/KAGEnvLayer.tjs +system/KAGEnvLevelLayer.tjs +system/KAGEnvSE.tjs +system/KAGEnvSimpleLayer.tjs +system/KAGLayer.tjs +system/LayerEx.tjs +system/MainWindow.tjs +system/MapSelectLayer.tjs +system/MapSelectLayerPatch.tjs +system/Menus.tjs +system/MessageLayer.tjs +system/Movie.tjs +system/Plugin.tjs +system/psdlayer.tjs +system/SE.tjs +system/SelectLayer.tjs +system/SliderLayer.tjs +system/StandView.tjs +system/TransLayer.tjs +system/UpdateConfig.tjs +system/UpdateRegion.tjs +system/Utils.tjs +system/Utils_graphics.tjs +system/WIN32Dialog.tjs +system/world.ks +system/world.tjs +system/YAML.tjs +system/YesNoDialog.tjs diff --git a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs index 08edb2e..691fbfe 100644 --- a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs +++ b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs @@ -43,6 +43,15 @@ pub fn default_init_crypt(archive: &mut Xp3Archive) -> Result<()> { Ok(()) } +fn default_read_name<'a>(reader: &mut Box) -> Result<(String, u64)> { + let name_length = reader.read_u16()?; + let name = reader.read_exact_vec(name_length as usize * 2)?; + Ok(( + decode_to_string(Encoding::Utf16LE, &name, true)?, + name_length as u64 * 2 + 2, + )) +} + pub trait Crypt: std::fmt::Debug { #[allow(dead_code)] /// whether Adler32 checksum should be calculated after contents have been encrypted. @@ -64,12 +73,7 @@ pub trait Crypt: std::fmt::Debug { /// Read a entry name from archive index fn read_name<'a>(&self, reader: &mut Box) -> Result<(String, u64)> { - let name_length = reader.read_u16()?; - let name = reader.read_exact_vec(name_length as usize * 2)?; - Ok(( - decode_to_string(Encoding::Utf16LE, &name, true)?, - name_length as u64 * 2 + 2, - )) + default_read_name(reader) } /// Decrypts the given stream of data for the specified entry and segment. @@ -223,6 +227,10 @@ enum CryptType { hash_table: Vec, key_table: Base64Bytes, }, + #[serde(rename_all = "PascalCase")] + RhapsodyCrypt { + file_list_name: String, + }, } #[derive(Clone, Debug, Deserialize)] @@ -346,6 +354,9 @@ impl Schema { hash_table.clone(), key_table.bytes.clone(), )?), + CryptType::RhapsodyCrypt { file_list_name } => { + Box::new(RhapsodyCrypt::new(self.base.clone(), &file_list_name)?) + } }) } } @@ -388,6 +399,19 @@ lazy_static::lazy_static! { }; } +pub fn query_filename_list(name: &str) -> Result { + let reader = MemReaderRef::new(NAME_LIST_DATA); + let mut pack = read_simple_pack(reader)?; + while let Some(mut entry) = pack.next()? { + if entry.name == name { + let mut str = String::new(); + entry.read_to_string(&mut str)?; + return Ok(str); + } + } + Err(anyhow::anyhow!("Name list entry not found: {}", name)) +} + /// Get the supported game titles for encrypted xp3 archives. pub fn get_supported_games() -> Vec<&'static str> { CRYPT_SCHEMA.keys().map(|s| s.as_str()).collect() @@ -1512,6 +1536,127 @@ impl Read for PuCaCryptReader2 { } } +#[derive(Debug)] +pub struct RhapsodyCrypt { + base: BaseSchema, + names: HashMap, +} + +impl RhapsodyCrypt { + pub fn new(base: BaseSchema, file_list_name: &str) -> Result { + let file_list = query_filename_list(file_list_name)?; + let mut names = HashMap::new(); + for name in file_list.lines() { + let name = name.trim(); + if !name.is_empty() { + names.insert(Self::get_name_hash(name.chars()), name.to_string()); + } + } + Ok(Self { base, names }) + } + fn get_name_hash>(name: T) -> u32 { + let mut hash = 0; + for c in name { + hash = Self::update_name_hash(hash, c); + } + hash + } + const fn update_name_hash(hash: u32, c: char) -> u32 { + let c = c.to_ascii_lowercase() as u32; + let mut hash = w!(0x1000193u32 * hash ^ (c & 0xFF)); + hash = w!(0x1000193u32 * hash ^ ((c >> 8) & 0xFF)); + hash + } + fn get_key(&self, hash: u32) -> [u8; 12] { + let mut key = [0u8; 12]; + key[0..4].copy_from_slice(&hash.to_le_bytes()); + key[4..8].copy_from_slice(&(0x6E1DA9B2u32).to_le_bytes()); + key[8..12].copy_from_slice(&(0x0040C800u32).to_le_bytes()); + key + } +} + +impl Crypt for RhapsodyCrypt { + base_schema_impl!(); + fn read_name<'a>(&self, reader: &mut Box) -> Result<(String, u64)> { + use msg_tool_macro::rhapsody_crypt_const_name_hash as hash; + const PNG_HASH: u32 = hash!(".png"); + const MAP_HASH: u32 = hash!(".map"); + const ASD_HASH: u32 = hash!(".asd"); + const TJS_HASH: u32 = hash!(".tjs"); + const TXT_HASH: u32 = hash!(".txt"); + const KS_HASH: u32 = hash!(".ks"); + const WAV_HASH: u32 = hash!(".wav"); + const JPG_HASH: u32 = hash!(".jpg"); + const OGG_HASH: u32 = hash!(".ogg"); + let key = reader.read_u32()?; + let name_hash = reader.read_u32()? ^ key; + if let Some(name) = self.names.get(&name_hash) { + return Ok((name.clone(), 8)); + } + let ext_hash = reader.read_u32()? ^ key; + let mut name = format!("{:08X}", name_hash); + match ext_hash { + PNG_HASH => name += ".png", + MAP_HASH => name += ".map", + ASD_HASH => name += ".asd", + TJS_HASH => name += ".tjs", + TXT_HASH => name += ".txt", + KS_HASH => name += ".ks", + WAV_HASH => name += ".wav", + JPG_HASH => name += ".jpg", + OGG_HASH => name += ".ogg", + _ => name += format!(".{:08X}", ext_hash).as_str(), + }; + Ok((name, 12)) + } + fn decrypt_supported(&self) -> bool { + true + } + fn decrypt_seek_supported(&self) -> bool { + true + } + fn decrypt<'a>( + &self, + entry: &Xp3Entry, + cur_seg: &Segment, + stream: Box, + ) -> Result> { + Ok(Box::new(RhapsodyCryptReader::new( + stream, + cur_seg, + self.get_key(entry.file_hash), + ))) + } + fn decrypt_with_seek<'a>( + &self, + entry: &Xp3Entry, + cur_seg: &Segment, + stream: Box, + ) -> Result> { + Ok(Box::new(RhapsodyCryptReader::new( + stream, + cur_seg, + self.get_key(entry.file_hash), + ))) + } +} + +seek_reader_key_impl!(RhapsodyCryptReader, [u8; 12]); + +impl Read for RhapsodyCryptReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let readed = self.inner.read(buf)?; + let mut offset = ((self.seg_start + self.pos) % 12) as usize; + for t in (&mut buf[..readed]).iter_mut() { + *t ^= self.key[offset]; + offset = (offset + 1) % 12; + } + self.pos += readed as u64; + Ok(readed) + } +} + #[test] fn test_deserialize_crypt() { for (key, schema) in CRYPT_SCHEMA.iter() {