From 85cdecca122157fc1622f4edd7d71d9f14f3f362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Sat, 6 May 2023 20:29:49 +0200 Subject: [PATCH] ui --- godot/mhjnr/menu.tscn | 32 +++++++++++++++++++-- rust/src/formats/mod.rs | 6 +++- rust/src/formats/ui_xml.rs | 57 ++++++++++++++++++++++++++++++++++---- rust/src/godot/ui.rs | 15 +++++++++- rust/src/main.rs | 9 +++--- 5 files changed, 104 insertions(+), 15 deletions(-) diff --git a/godot/mhjnr/menu.tscn b/godot/mhjnr/menu.tscn index f5cc5b2..26c3fec 100644 --- a/godot/mhjnr/menu.tscn +++ b/godot/mhjnr/menu.tscn @@ -7,10 +7,13 @@ [sub_resource type="GDScript" id="GDScript_oemh7"] script/source = "extends MarginContainer +const Profile = preload(\"res://mhjnr/profile/player_profile.gd\") + @export var entry: String = \"main\" @export var window_size: Vector2i = Vector2i(800, 600) var menu: Node +var profile: Profile @onready var translations: Translation = load(\"datafile://data/text.csv\") func _ready() -> void: @@ -52,15 +55,37 @@ func _on_minimize_pressed() -> void: func _on_close_pressed() -> void: get_tree().quit() +func _on_action_CheckStartGame() -> void: + var level = profile.current_level + if level == 0: + set_menu(\"screen_set1\") + else: + set_menu(\"screen_set2\") + +func _on_action_SelectProfile(id: String) -> void: + profile = load(\"user://profile_%02d.tres\" % (id.to_int() + 1)) + if profile == null: + set_menu(\"profile_create\") + else: + set_menu(\"main\") + +func _on_action_ProfileCreated() -> void: + profile = Profile.new() + profile.name = menu.find_child(\"profile1\").text + ResourceSaver.save(profile, \"user://profile_01.tres\") + set_menu(\"main\") func _on_action_SetMenu(name: String) -> void: set_menu(name) -func _on_action_CheckStartGame() -> void: - print(\"CheckStartGame\") - func _on_action_DisplayEndscreen() -> void: get_tree().quit() + +func _on_action_StartGame() -> void: + DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_RESIZE_DISABLED, false) + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) + get_tree().change_scene_to_file(\"res://mhjnr/level.tscn\") + " [node name="Root" type="MarginContainer"] @@ -71,6 +96,7 @@ grow_horizontal = 2 grow_vertical = 2 theme = ExtResource("1_o0c21") script = SubResource("GDScript_oemh7") +entry = "profile_start_select" [node name="Titlebar" type="HBoxContainer" parent="."] layout_mode = 2 diff --git a/rust/src/formats/mod.rs b/rust/src/formats/mod.rs index b0f8c7b..975d365 100644 --- a/rust/src/formats/mod.rs +++ b/rust/src/formats/mod.rs @@ -2,7 +2,7 @@ use crate::formats::datafile::FileEntry; use crate::formats::level::LevelLayer; use crate::formats::rle::RleImage; use crate::formats::sprites::Sprites; -use crate::formats::txt::{decrypt_txt, DecryptError}; +use crate::formats::txt::{decrypt_exposed_txt, decrypt_txt, DecryptError}; use crate::formats::ui_xml::UiTag; use binrw::BinRead; use encoding_rs::WINDOWS_1252; @@ -93,6 +93,10 @@ where Ok(DatafileFile::Sprites( Sprites::parse(decr.as_str()).map_err(custom_err)?, )) + } else if stem.starts_with("profile") || stem.starts_with("highscores") { + Ok(DatafileFile::Txt( + decrypt_exposed_txt(decr).map_err(custom_err)?, + )) } else { Ok(DatafileFile::Txt(decr)) } diff --git a/rust/src/formats/ui_xml.rs b/rust/src/formats/ui_xml.rs index a520369..c7f9ff9 100644 --- a/rust/src/formats/ui_xml.rs +++ b/rust/src/formats/ui_xml.rs @@ -7,6 +7,7 @@ pub enum UiTag { Image(UiImage), TextButton(UiTextButton), TextArea(UiTextArea), + TextField(UiTextField), StaticText(UiStaticText), ToggleButton(UiToggleButton), } @@ -20,6 +21,24 @@ pub struct UiMenu { pub children: Vec, } +#[derive(Debug, Clone, Deserialize)] +pub struct UiTextField { + pub name: Option, + pub text: String, + #[serde(deserialize_with = "deserialize_vec2")] + pub position: [i32; 2], + #[serde(rename = "bufferVar")] + pub buffer_var: String, + #[serde(deserialize_with = "deserialize_vec4")] + pub area: [i32; 4], + #[serde(rename = "halign", default)] + pub horizontal_align: HorizontalAlign, + #[serde(rename = "fademode")] + pub fade_mode: FadeMode, + #[serde(rename = "OnSelect")] + pub on_select: String, +} + #[derive(Debug, Clone, Deserialize)] pub struct UiImage { pub texture: String, @@ -172,12 +191,18 @@ where to_vec2::(String::deserialize(deserializer)?) } -fn to_vec2<'de, D>(buf: String) -> Result<[i32; 2], D::Error> +fn deserialize_vec4<'de, D>(deserializer: D) -> Result<[i32; 4], D::Error> where D: Deserializer<'de>, { - let mut values: Vec> = buf - .split(',') + to_vec4::(String::deserialize(deserializer)?) +} + +fn to_vec<'de, D>(buf: String) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + buf.split(',') .into_iter() .map(|value| { // there's some typos so we have to cover that... @@ -186,9 +211,29 @@ where .parse::() .map_err(|err| Error::custom(err.to_string())) }) - .collect(); - let y = values.pop().ok_or(Error::custom("InvalidField"))??; - let x = values.pop().ok_or(Error::custom("InvalidField"))??; + .collect() +} + +fn to_vec4<'de, D>(buf: String) -> Result<[i32; 4], D::Error> +where + D: Deserializer<'de>, +{ + let mut values = to_vec::(buf)?; + let w = values.pop().ok_or(Error::custom("InvalidField"))?; + let z = values.pop().ok_or(Error::custom("InvalidField"))?; + let y = values.pop().ok_or(Error::custom("InvalidField"))?; + let x = values.pop().ok_or(Error::custom("InvalidField"))?; + + Ok([x, y, z, w]) +} + +fn to_vec2<'de, D>(buf: String) -> Result<[i32; 2], D::Error> +where + D: Deserializer<'de>, +{ + let mut values = to_vec::(buf)?; + let y = values.pop().ok_or(Error::custom("InvalidField"))?; + let x = values.pop().ok_or(Error::custom("InvalidField"))?; Ok([x, y]) } diff --git a/rust/src/godot/ui.rs b/rust/src/godot/ui.rs index f8a0793..f0ff772 100644 --- a/rust/src/godot/ui.rs +++ b/rust/src/godot/ui.rs @@ -3,7 +3,7 @@ use godot::builtin::{Array, Dictionary, GodotString, ToVariant, Vector2}; use godot::engine::control::LayoutPreset; use godot::engine::global::HorizontalAlignment; use godot::engine::node::InternalMode; -use godot::engine::{load, Button, Control, Label, Node, SpinBox, TextureRect}; +use godot::engine::{load, Button, Control, Label, LineEdit, Node, SpinBox, TextureRect}; use godot::obj::{Gd, Inherits, Share}; use itertools::Itertools; @@ -43,6 +43,19 @@ pub fn convert_ui(ui: UiTag, base_path: &str) -> Gd { attach_children(&mut text_area, area.children, base_path); text_area.upcast() } + UiTag::TextField(field) => { + let mut text_field = LineEdit::new_alloc(); + if let Some(name) = field.name { + text_field.set_name(name.into()); + } + text_field.set_text(field.text.into()); + text_field.set_horizontal_alignment(field.horizontal_align.into()); + text_field.set_position(to_vec2([field.area[0], field.area[1]]), false); + text_field.set_size(to_vec2([field.area[2], field.area[3]]), false); + text_field.set_meta("buffer_var".into(), field.buffer_var.to_variant()); + attach_call_meta(&mut text_field, field.on_select); + text_field.upcast() + } UiTag::ToggleButton(toggle) => { let mut spin_box = SpinBox::new_alloc(); spin_box.set_position(to_vec2(toggle.position), false); diff --git a/rust/src/main.rs b/rust/src/main.rs index a62e023..d35c164 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -66,9 +66,7 @@ fn extract(datafile: &Datafile, file: &mut File) { } fn main() { - let file_name = Some(NullString::from( - "data\\menu\\screens\\options_controls.xml", - )); + let file_name = Some(NullString::from("data\\profile_00.txt")); let dat_path = "E:\\Games\\Schatzjäger\\data\\datafile.dat"; let mut file = File::open(dat_path).unwrap(); @@ -102,7 +100,10 @@ fn main() { let sprites = Sprites::parse(decr.as_str()).unwrap(); println!("{:#?}", sprites); } else { - println!("{}", decrypt_txt(data.into_iter()).unwrap()) + println!( + "{}", + decrypt_exposed_txt(decrypt_txt(data.into_iter()).unwrap()).unwrap() + ) } } Some("rle") => {