diff --git a/src/args.rs b/src/args.rs index 803d044..8d3da4f 100644 --- a/src/args.rs +++ b/src/args.rs @@ -211,6 +211,10 @@ pub struct Arg { /// Kirikiri language list. First language code is code for language index 1. pub kirikiri_languages: Option>, #[cfg(feature = "kirikiri")] + #[arg(long, global = true, action = ArgAction::SetTrue, alias = "kr-title")] + /// Whether to handle title in Kirikiri SCN script. + pub kirikiri_title: bool, + #[cfg(feature = "kirikiri")] #[arg(long, global = true, action = ArgAction::SetTrue, alias = "kr-no-empty-lines", alias = "kirikiri-no-empty-lines")] /// Remove empty lines in Kirikiri KS script. pub kirikiri_remove_empty_lines: bool, diff --git a/src/ext/psb.rs b/src/ext/psb.rs index 1678d70..e7ffa40 100644 --- a/src/ext/psb.rs +++ b/src/ext/psb.rs @@ -55,6 +55,36 @@ pub enum PsbValueFixed { CompilerBinaryTree, } +impl From for PsbValueFixed { + fn from(value: String) -> Self { + PsbValueFixed::String(PsbString::from(value)) + } +} + +impl From for PsbValueFixed { + fn from(value: bool) -> Self { + PsbValueFixed::Bool(value) + } +} + +impl From for PsbValueFixed { + fn from(value: i64) -> Self { + PsbValueFixed::Number(PsbNumber::Integer(value)) + } +} + +impl From for PsbValueFixed { + fn from(value: f64) -> Self { + PsbValueFixed::Number(PsbNumber::Double(value)) + } +} + +impl From for PsbValueFixed { + fn from(value: f32) -> Self { + PsbValueFixed::Number(PsbNumber::Float(value)) + } +} + impl PsbValueFixed { /// Converts this value to original PSB value type. pub fn to_psb(self, warn_on_none: bool) -> PsbValue { @@ -204,6 +234,20 @@ impl PsbValueFixed { } } + /// Pushes a new member to a list. If this value is not a list, it will be converted to a list. + pub fn push_member>(&mut self, value: T) { + match self { + PsbValueFixed::List(l) => { + l.values.push(value.into()); + } + _ => { + *self = PsbValueFixed::List(PsbListFixed { + values: vec![value.into()], + }); + } + } + } + /// Returns the resource ID if this value is a resource reference. pub fn resource_id(&self) -> Option { match self { diff --git a/src/main.rs b/src/main.rs index 46dcc7d..9e1a753 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1921,6 +1921,8 @@ fn main() { flac_compression_level: arg.flac_compression_level, #[cfg(feature = "artemis")] artemis_asb_format_lua: !arg.artemis_asb_no_format_lua, + #[cfg(feature = "kirikiri")] + kirikiri_title: arg.kirikiri_title, }; match &arg.command { args::Command::Export { input, output } => { diff --git a/src/scripts/kirikiri/scn.rs b/src/scripts/kirikiri/scn.rs index ab0b046..33d7e7a 100644 --- a/src/scripts/kirikiri/scn.rs +++ b/src/scripts/kirikiri/scn.rs @@ -116,6 +116,7 @@ pub struct ScnScript { chat_key: Option, chat_json: Option>>, custom_yaml: bool, + title: bool, } impl ScnScript { @@ -152,6 +153,7 @@ impl ScnScript { chat_key: config.kirikiri_chat_key.clone(), chat_json: config.kirikiri_chat_json.clone(), custom_yaml: config.custom_yaml, + title: config.kirikiri_title, }) } } @@ -222,6 +224,22 @@ impl Script for ScnScript { PsbValueFixed::Object(obj) => obj, _ => return Err(anyhow::anyhow!("scene at index {} is not an object", i)), }; + if self.title { + if let Some(title) = scene["title"].as_str() { + messages.push(Message { + name: None, + message: title.to_string(), + }); + } + if scene["title"].is_list() { + if let Some(title) = scene["title"][self.language_index].as_str() { + messages.push(Message { + name: None, + message: title.to_string(), + }); + } + } + } if let Some(PsbValueFixed::List(texts)) = scene.get_value("texts") { for (j, text) in texts.iter().enumerate() { if let PsbValueFixed::List(text) = text { @@ -430,6 +448,55 @@ impl Script for ScnScript { if !scene.is_object() { return Err(anyhow::anyhow!("scene at {} is not an object", i)); } + if self.title { + if scene["title"].is_string() { + let m = match cur_mes { + Some(m) => m, + None => { + return Err(anyhow::anyhow!( + "No enough messages. (title at scene {i})" + )); + } + }; + let mut title = m.message.clone(); + if let Some(replacement) = replacement { + for (key, value) in replacement.map.iter() { + title = title.replace(key, value); + } + } + if self.language_index == 0 { + scene["title"].set_string(title); + } else { + let ori_title = scene["title"].as_str().unwrap_or("").to_string(); + while scene["title"].len() < self.language_index { + scene["title"].push_member(ori_title.clone()); + } + scene["title"].push_member(title); + } + cur_mes = mes.next(); + } else if scene["title"].is_list() { + let m = match cur_mes { + Some(m) => m, + None => { + return Err(anyhow::anyhow!( + "No enough messages. (title at scene {i})" + )); + } + }; + let mut title = m.message.clone(); + if let Some(replacement) = replacement { + for (key, value) in replacement.map.iter() { + title = title.replace(key, value); + } + } + let ori_title = scene["title"][0].as_str().unwrap_or("").to_string(); + while scene["title"].len() <= self.language_index { + scene["title"].push_member(ori_title.clone()); + } + scene["title"][self.language_index].set_string(title); + cur_mes = mes.next(); + } + } if scene["texts"].is_list() { for (j, text) in scene["texts"].members_mut().enumerate() { if text.is_list() { diff --git a/src/types.rs b/src/types.rs index 240b160..ab87bb2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -419,6 +419,9 @@ pub struct ExtraConfig { #[default(true)] /// Format lua code in Artemis ASB script(.asb/.iet) when exporting. pub artemis_asb_format_lua: bool, + #[cfg(feature = "kirikiri")] + /// Whether to handle title in Kirikiri SCN script. + pub kirikiri_title: bool, } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]