diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0dbc1c9c3f73f9dbecf6e209c998f1c0a65bc5be..2e61350b62f06c49400c0c3d974a2a80e6c789c6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,6 +3,7 @@ image: "r.lcr.gr/microhacks/bevy-builder:latest" variables: BINARY_FOLDER: game_core BINARY_NAME: game_core + OUTPUT_NAME: TraderTales stages: - build @@ -52,97 +53,23 @@ build-linux: only: - trunk -#build-arm64: -# image: "r.lcr.gr/microhacks/bevy-builder:arm64" -# tags: -# - arm64 -# stage: build -# before_script: -# - export CARGO_HOME="${CI_PROJECT_DIR}/.cargo" -# - export PATH="${CI_PROJECT_DIR}/.cargo/bin:$PATH" -# cache: -# key: build-cache-arm64 -# paths: -# - .cargo/registry/cache -# - .cargo/registry/index -# - .cargo/git/db -# - .cargo/bin/ -# - target/ -# script: -# - cargo build --release -p ${BINARY_FOLDER} --target aarch64-unknown-linux-gnu -# artifacts: -# expire_in: 1 day -# paths: -# - target/aarch64-unknown-linux-gnu/release/game_core -# only: -# - trunk - -#build-web: -# stage: build -# before_script: -# - export CARGO_HOME="${CI_PROJECT_DIR}/.cargo" -# - export PATH="${CI_PROJECT_DIR}/.cargo/bin:$PATH" -# cache: -# key: build-cache-web -# paths: -# - .cargo/registry/cache -# - .cargo/registry/index -# - .cargo/git/db -# - .cargo/bin/ -# - target/ -# script: -# - mkdir -p "${CI_PROJECT_DIR}/${BINARY_FOLDER}/fonts" -# - mkdir "${CI_PROJECT_DIR}/${BINARY_FOLDER}/dist" -# - make assets -# - sed -i 's#public_url = "/"#public_url = "./"#' "${CI_PROJECT_DIR}/${BINARY_FOLDER}/Trunk.toml" -# - cd "${CI_PROJECT_DIR}/${BINARY_FOLDER}" && trunk build --release -# - cd "${CI_PROJECT_DIR}" -# artifacts: -# expire_in: 1 day -# paths: -# - game_core/dist/ -# only: -# - trunk - package-all: stage: package script: - mkdir -p dist/ - make assets - cp -r assets dist/assets - - cp target/x86_64-unknown-linux-gnu/release/${BINARY_NAME} "dist/${BINARY_NAME}" - - cp target/x86_64-pc-windows-gnu/release/${BINARY_NAME}.exe "dist/${BINARY_NAME}.exe" -# - cp target/aarch64-unknown-linux-gnu/release/${BINARY_NAME} "dist/${BINARY_NAME}.arm64" - - cd "${CI_PROJECT_DIR}/dist" && zip -r "windows.zip" "./${BINARY_NAME}.exe" ./assets - - cd "${CI_PROJECT_DIR}/dist" && zip -r "linux.x86.zip" "./${BINARY_NAME}" ./assets -# - cd "${CI_PROJECT_DIR}/dist" && zip -r "linux.arm64.zip" "./${BINARY_NAME}.arm64" ./assets -# - cd "${CI_PROJECT_DIR}/${BINARY_FOLDER}/dist" && zip -r "web.zip" ./* -# - cd "${CI_PROJECT_DIR}" && mv "${CI_PROJECT_DIR}/game_core/dist/web.zip" "${CI_PROJECT_DIR}/dist/web.zip" + - cp target/x86_64-unknown-linux-gnu/release/${BINARY_NAME} "dist/${OUTPUT_NAME}" + - cp target/x86_64-pc-windows-gnu/release/${BINARY_NAME}.exe "dist/${OUTPUT_NAME}.exe" + - cd "${CI_PROJECT_DIR}/dist" && zip -r "windows.zip" "./${OUTPUT_NAME}.exe" ./assets + - cd "${CI_PROJECT_DIR}/dist" && zip -r "linux.x86.zip" "./${OUTPUT_NAME}" ./assets dependencies: - build-windows - build-linux -# - build-arm64 -# - build-web artifacts: expire_in: 7 days paths: - - dist/web.zip - dist/windows.zip - dist/linux.x86.zip -# - dist/linux.arm64.zip only: - trunk - -#pages: -# stage: package -# script: -# - mkdir -p public/ -# - cp -r ${BINARY_FOLDER}/dist/* public/ -# artifacts: -# expire_in: 7 days -# paths: -# - public -# dependencies: -# - build-web -# only: -# - trunk \ No newline at end of file diff --git a/CREDITS.toml b/CREDITS.toml index c43b422d4cea1d907c8cf6e5a334319f42710b12..d34acc3a9037490f5f3fd9cacb35c8b5392b234c 100644 --- a/CREDITS.toml +++ b/CREDITS.toml @@ -1,5 +1,11 @@ [[font]] -name = "compass_pro.ttf" +name = "CompassPro.ttf" author = "Eeve Somepx" website = "https://somepx.itch.io/humble-fonts-free" -usage = "Main game font" \ No newline at end of file +usage = "Header and title font" + +[[font]] +name = "EquipmentPro.ttf" +author = "Eeve Somepx" +website = "https://somepx.itch.io/humble-fonts-free" +usage = "Interface body font" \ No newline at end of file diff --git a/Makefile b/Makefile index d6226624a5fd57e7b658cdb15e92f518dd766931..d9f31ce08f37dd9b13bfb1f81f81f5de6d0afaba 100644 --- a/Makefile +++ b/Makefile @@ -30,11 +30,12 @@ run-web: check: cargo check --release --features "bevy/dynamic" -p game_core -pak: +pak: msdf cd raw_assets && tar -cJf ../assets/resources.apack ./ msdf: - msdf-atlas-gen -font raw_assets/fonts/CompassPro.ttf -type msdf -minsize 18 -format png -imageout raw_assets/fonts/CompassPro.png -json raw_assets/fonts/CompassPro.kayak_font + @msdf-atlas-gen -font raw_assets/fonts/CompassPro.ttf -type msdf -minsize 32 -format png -imageout raw_assets/fonts/CompassPro.png -json raw_assets/fonts/CompassPro.kayak_font + @msdf-atlas-gen -font raw_assets/fonts/EquipmentPro.ttf -type msdf -minsize 32 -format png -imageout raw_assets/fonts/EquipmentPro.png -json raw_assets/fonts/EquipmentPro.kayak_font build-windows: clean_dist top_tail docker run --rm --name "${PROJECT_NAME}-build-windows" -v "$(CURRENT_DIRECTORY):/app" -w /app --user $(shell id -u):$(shell id -g) r.lcr.gr/microhacks/bevy-builder \ diff --git a/assets/resources.apack b/assets/resources.apack index b5f38dd40c9edcb6b709447ec6c4d9140f8ccf35..7db455ac57e9cdf7a2613e753ddcba42dc63d082 100644 --- a/assets/resources.apack +++ b/assets/resources.apack @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcb87c1d8969f1007611545f2b08107140ca49189883bc51fc1ac7d4b3e8d73a -size 105084 +oid sha256:63fc5d48bdcc9ef1268da7877f399916b45d0463cb3f7a116594220ad5fdfa00 +size 110420 diff --git a/game_core/src/states/menu_state.rs b/game_core/src/states/menu_state.rs index cf9891ce4a751ee94c203c4503ccecaa5c5a8d3b..40ea5502d7384f88e19ad01c27e166200f6e8343 100644 --- a/game_core/src/states/menu_state.rs +++ b/game_core/src/states/menu_state.rs @@ -6,7 +6,6 @@ use bevy_tweening::{Animator, EaseFunction, RepeatCount, RepeatStrategy, Tween}; use iyes_loopless::state::NextState; use crate::assets::AssetHandles; -use crate::graphics::AlignedBackground; use crate::system::flow::AppState; #[derive(Component)] @@ -16,6 +15,7 @@ pub fn spawn_menu_entities(mut commands: Commands, assets: Res<AssetHandles>) { commands.spawn(( SpriteBundle { texture: assets.image("menu_background"), + transform: Transform::from_scale(Vec3::splat(0.85)), ..Default::default() }, MenuStateEntity, diff --git a/game_core/src/ui/components/button.rs b/game_core/src/ui/components/button.rs index 201720adbc4f38b6a59131819881ebafdc386f33..58bc3a6c75a377e97202c4681fded3fca8199a51 100644 --- a/game_core/src/ui/components/button.rs +++ b/game_core/src/ui/components/button.rs @@ -1,16 +1,18 @@ use bevy::prelude::*; use kayak_ui::prelude::*; use kayak_ui::widgets::{NinePatch, NinePatchBundle, TextProps, TextWidgetBundle}; -use kayak_ui::DEFAULT_FONT; use num_traits::AsPrimitive; use crate::assets::AssetHandles; use crate::parent_widget; +use crate::ui::components::{IconContent, InsetIconProps, InsetIconWidget}; use crate::ui::prelude::{edge_px, px, stretch, val_auto, value}; #[derive(Component, Clone, PartialEq, Default)] pub struct ButtonWidgetProps { pub text: String, + pub left_icon: IconContent, + pub right_icon: IconContent, pub font_size: f32, pub is_disabled: bool, pub is_fixed: bool, @@ -32,6 +34,8 @@ pub fn button_props(text: impl ToString, is_disabled: bool, is_fixed: bool) -> B is_fixed, is_disabled, font_size: 32.0, + left_icon: IconContent::None, + right_icon: IconContent::None, } } @@ -132,20 +136,22 @@ pub fn render_button_widget( } }; - let padding = if state.is_pressed { - StyleProp::Value(Edge::new( - Units::Pixels(6.0), - Units::Stretch(1.0), - Units::Pixels(16.0), - Units::Stretch(1.0), - )) + let sizing = if state.is_pressed { + KStyle { + top: px(11.0), + right: stretch(1.0), + bottom: px(11.0), + left: stretch(1.0), + ..Default::default() + } } else { - StyleProp::Value(Edge::new( - Units::Pixels(3.0), - Units::Stretch(1.0), - Units::Pixels(19.0), - Units::Stretch(1.0), - )) + KStyle { + top: px(8.0), + right: stretch(1.0), + bottom: px(14.0), + left: stretch(1.0), + ..Default::default() + } }; *computed = KStyle { @@ -160,14 +166,32 @@ pub fn render_button_widget( .into(); let ninepatch_styles = KStyle { - padding, + layout_type: value(LayoutType::Row), + col_between: px(15.0), ..Default::default() }; let text_style = KStyle { color: value(Color::BLACK), ..Default::default() - }; + } + .with_style(if state.is_pressed { + KStyle { + top: px(6.0), + right: stretch(1.0), + bottom: px(16.0), + left: stretch(1.0), + ..Default::default() + } + } else { + KStyle { + top: px(3.0), + right: stretch(1.0), + bottom: px(19.0), + left: stretch(1.0), + ..Default::default() + } + }); rsx! { <NinePatchBundle @@ -175,6 +199,15 @@ pub fn render_button_widget( nine_patch={nine_vals} styles={ninepatch_styles} > + { if !props.left_icon.is_none() { + constructor!( + <InsetIconWidget + styles={sizing.clone()} + + props={InsetIconProps { image: props.left_icon.clone(), size: props.font_size }} + /> + ); + }} <TextWidgetBundle text={TextProps { content: props.text.clone(), @@ -186,6 +219,15 @@ pub fn render_button_widget( }} styles={text_style} /> + + { if !props.right_icon.is_none() { + constructor!( + <InsetIconWidget + styles={sizing.clone()} + props={InsetIconProps { image: props.right_icon.clone(), size: props.font_size }} + /> + ); + }} </NinePatchBundle> } } diff --git a/game_core/src/ui/components/inset_icon.rs b/game_core/src/ui/components/inset_icon.rs new file mode 100644 index 0000000000000000000000000000000000000000..ac4b68c49b0c819b37e3b2fb99472c7192a12391 --- /dev/null +++ b/game_core/src/ui/components/inset_icon.rs @@ -0,0 +1,109 @@ +use bevy::prelude::*; +use kayak_ui::prelude::*; +use kayak_ui::widgets::{KImage, KImageBundle, TextureAtlasBundle, TextureAtlasProps}; + +use crate::assets::AssetHandles; +use crate::parent_widget; +use crate::ui::prelude::*; + +#[derive(Clone, Default, Eq, PartialEq)] +pub enum IconContent { + Image(String), + Atlas(String, usize), + #[default] + None, +} + +impl IconContent { + pub fn is_none(&self) -> bool { + match self { + Self::None => true, + _ => false, + } + } +} + +#[derive(Clone, Component, PartialEq)] +pub struct InsetIconProps { + pub image: IconContent, + pub size: f32, +} + +impl Default for InsetIconProps { + fn default() -> Self { + Self { + image: IconContent::None, + size: 48.0, + } + } +} + +impl Widget for InsetIconProps {} + +parent_widget!(InsetIconProps => InsetIconWidget); + +pub fn render_inset_icon_widget( + In((mut widget_context, entity)): In<(KayakWidgetContext, Entity)>, + mut commands: Commands, + mut query: Query<(&InsetIconProps, &mut ComputedStyles, &KStyle)>, + assets: Res<AssetHandles>, + atlass: Res<Assets<TextureAtlas>>, +) -> bool { + let parent_id = Some(entity); + + if let Ok((props, mut computed, style)) = query.get_mut(entity) { + *computed = KStyle { + render_command: value(RenderCommand::Layout), + min_height: px(32.0), + min_width: px(32.0), + height: px(props.size), + width: px(props.size), + padding: value(Edge::all(Units::Stretch(0.0))), + ..Default::default() + } + .with_style(style) + .into(); + + let image_styles = KStyle { + width: stretch(1.0), + height: stretch(1.0), + ..Default::default() + }; + + match &props.image { + IconContent::Image(name) => { + let handle = assets.image(name); + + rsx! { + <KImageBundle + image={KImage(handle)} + styles={image_styles} + /> + } + } + IconContent::Atlas(name, index) => { + let atlas_handle = assets.atlas(name); + let image_handle = assets.image(name); + if let Some(atlas) = atlass.get(&atlas_handle) { + let rect = atlas.textures[*index]; + let position = rect.min; + let tile_size = rect.max - rect.min; + + rsx! { + <TextureAtlasBundle + atlas={TextureAtlasProps { + tile_size, + position, + handle: image_handle, + }} + styles={image_styles} + /> + } + } + } + IconContent::None => {} + } + } + + true +} diff --git a/game_core/src/ui/components/mod.rs b/game_core/src/ui/components/mod.rs index fe7558c26d5fd8de55f1202afe9c94b3bb9b242e..7a1147c971b6958abb76740e606f7758a1f9deea 100644 --- a/game_core/src/ui/components/mod.rs +++ b/game_core/src/ui/components/mod.rs @@ -4,6 +4,7 @@ mod a_text_box; mod button; mod debug_info; mod image_button; +mod inset_icon; mod panel; mod v_divider; @@ -17,5 +18,8 @@ pub use self::debug_info::{render_debug_info, DebugInfoProps, DebugInfoWidget}; pub use self::image_button::{ render_image_button_widget, ImageButtonWidget, ImageButtonWidgetProps, ImageButtonWidgetState, }; +pub use self::inset_icon::{ + render_inset_icon_widget, IconContent, InsetIconProps, InsetIconWidget, +}; pub use self::panel::{render_panel_widget, PanelProps, PanelVariant, PanelWidget}; pub use self::v_divider::{render_v_divider, VDividerWidget, VDividerWidgetProps}; diff --git a/game_core/src/ui/mod.rs b/game_core/src/ui/mod.rs index d8151710891543860ee6a0c5b9b2be90ac90ca83..8d2581bd60d41e7ebd5f1d55b4633c34a6e9a7e4 100644 --- a/game_core/src/ui/mod.rs +++ b/game_core/src/ui/mod.rs @@ -5,9 +5,9 @@ use kayak_ui::widgets::KayakWidgets; // pub mod clrs; pub mod components; pub mod screens; -pub mod utilities; -// pub mod widgets; pub mod sync; +pub mod utilities; +pub mod widgets; pub mod prelude { use bevy::prelude::FromReflect; @@ -78,7 +78,8 @@ mod _config { mut font_mapping: ResMut<FontMapping>, ) { log::info!("Configuring Fonts And UI"); - font_mapping.set_default(assets.kayak_font("compass_pro")); + font_mapping.set_default(assets.kayak_font("equipment_pro")); + font_mapping.add("header", assets.kayak_font("compass_pro")); } pub fn remove_ui(mut commands: Commands, query: Query<Entity, With<StateUIRoot>>) { diff --git a/game_core/src/ui/screens/in_game.rs b/game_core/src/ui/screens/in_game.rs index 3638d0e6dc2b00dbd31acfd67368d91ded5fb4ef..a24c440d43883d0d36003a656b2007859e35546b 100644 --- a/game_core/src/ui/screens/in_game.rs +++ b/game_core/src/ui/screens/in_game.rs @@ -2,66 +2,20 @@ use bevy::prelude::*; use kayak_ui::prelude::*; use kayak_ui::widgets::{ElementBundle, KayakAppBundle, TextProps, TextWidgetBundle}; -use crate::assets::AssetHandles; -use crate::states::Player; -use crate::ui::components::*; -use crate::ui::prelude::{edge_px, pct, px, stretch, value}; +use crate::ui::prelude::{px, stretch, value}; use crate::ui::sync::UITravelInfo; use crate::ui::utilities::context::create_root_context; -use crate::ui::utilities::{widget_update_with_resource, StateUIRoot}; -use crate::world::{CurrentResidence, MapQuery, TownPaths}; -use crate::{ - empty_props, on_button_click, parent_widget, register_widget_with_resource, - register_widget_with_update, -}; +use crate::ui::utilities::StateUIRoot; +use crate::ui::widgets::*; +use crate::{empty_props, parent_widget, register_widget_with_resource}; empty_props!(InGameProps); parent_widget!(InGameProps => InGameLayout); -pub fn transit_button_factory(target: String) -> OnEvent { - let target = target.clone(); - on_button_click!( - ParamSet<( - Commands, - Res<TownPaths>, - Query<(Entity, &CurrentResidence), With<Player>>, - MapQuery, - )>, - |mut params: ParamSet<( - Commands, - Res<TownPaths>, - Query<(Entity, &CurrentResidence), With<Player>>, - MapQuery, - )>| { - let target = target.clone(); - let (entity, current) = { - match params.p2().get_single() { - Ok((entity, current)) => (entity.clone(), (current.get_location()).clone()), - _ => return, - } - }; - - let places = match params.p1().routes.get(¤t) { - Some(places) => places.clone(), - None => return, - }; - - let bundle = match params.p3().get_active_level() { - Some(level) => places.create_route_bundle_for(target, level).unwrap(), - None => return, - }; - - params.p0().entity(entity).insert(bundle); - } - ) -} - pub fn render_game_panels( In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, mut commands: Commands, ui_data: Res<UITravelInfo>, - assets: Res<AssetHandles>, - places: Res<TownPaths>, ) -> bool { let parent_id = Some(entity); @@ -74,29 +28,8 @@ pub fn render_game_panels( ..Default::default() }; - let panel_style = KStyle { - position_type: value(KPositionType::SelfDirected), - width: pct(65.0), - height: pct(80.0), - min_width: px(400.0), - min_height: px(300.0), - max_width: px(850.0), - max_height: px(550.0), - top: stretch(1.0), - left: stretch(1.0), - right: stretch(1.0), - bottom: stretch(1.0), - layout_type: value(LayoutType::Column), - row_between: px(20.0), - ..Default::default() - }; - rsx! { - <ElementBundle - styles={KStyle { - ..Default::default() - }} - > + <ElementBundle> { if ui_data.distance_remaining > 0.1 { constructor! { <TextWidgetBundle @@ -111,66 +44,8 @@ pub fn render_game_panels( }} {if ui_data.is_in_town { - if let Some(ref place) = ui_data.current_town { - constructor! { - <PanelWidget - styles={panel_style} - > - <TextWidgetBundle - text={TextProps { - content: format!("Hark! You enter {}", &place), - size: 48.0, - ..Default::default() - }} - styles={KStyle { - color: value(Color::BLACK), - padding: edge_px(20.0), - left: stretch(1.0), - right: stretch(1.0), - ..Default::default() - }} - /> - - <VDividerWidget props={VDividerWidgetProps { height: 4.0, padding: 5.0, color: Color::rgb(0.52, 0.369, 0.18)}} /> - - <TextWidgetBundle - text={TextProps { - content: format!("Set off for:"), - size: 32.0, - ..Default::default() - }} - styles={KStyle { - color: value(Color::BLACK), - padding: edge_px(20.0), - left: stretch(1.0), - right: stretch(1.0), - ..Default::default() - }} - /> - - { - for (place, distance) in ui_data.travel_options.iter() { - constructor! { - <ButtonWidget - styles={ - KStyle { - left: stretch(1.0), - right: stretch(1.0), - width: pct(70.0), - min_width: px(300.0), - max_width: px(600.0), - bottom: px(10.0), - ..Default::default() - } - } - props={ButtonWidgetProps::text(format!("{}: {:.2}KM", &place, distance), 28.0)} - on_event={transit_button_factory(place.clone())} - /> - } - } - } - </PanelWidget> - } + constructor! { + <TownMenuPanel /> } }} </ElementBundle> diff --git a/game_core/src/ui/utilities.rs b/game_core/src/ui/utilities.rs index 54c2ca887fef587d356ed7a67a01b8dea5558b26..5dfb3276879c7f67cd683eb80c349b089ede87e7 100644 --- a/game_core/src/ui/utilities.rs +++ b/game_core/src/ui/utilities.rs @@ -138,6 +138,8 @@ pub mod context { use crate::register_widget; use crate::ui::components::*; + use crate::ui::sync::UITravelInfo; + use crate::ui::widgets::*; pub fn create_root_context() -> KayakRootContext { let mut widget_context = KayakRootContext::new(); @@ -180,6 +182,19 @@ pub mod context { ATextBoxState, render_text_box_widget ); + register_widget!( + widget_context, + InsetIconProps, + EmptyState, + render_inset_icon_widget + ); + register_widget_with_resource!( + widget_context, + TownMenuPanelProps, + EmptyState, + UITravelInfo, + render_town_menu_panel + ); } } } diff --git a/game_core/src/ui/widgets/mod.rs b/game_core/src/ui/widgets/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..7acc2b1c34bb12a4c5fc92d508487f17edd4970a --- /dev/null +++ b/game_core/src/ui/widgets/mod.rs @@ -0,0 +1,3 @@ +mod town_menu; + +pub use town_menu::{render_town_menu_panel, TownMenuPanel, TownMenuPanelProps}; diff --git a/game_core/src/ui/widgets/town_menu.rs b/game_core/src/ui/widgets/town_menu.rs new file mode 100644 index 0000000000000000000000000000000000000000..b7e75c147a79dccb5c4df4ee666e177ca5ca4322 --- /dev/null +++ b/game_core/src/ui/widgets/town_menu.rs @@ -0,0 +1,159 @@ +use bevy::prelude::*; +use kayak_ui::prelude::*; +use kayak_ui::widgets::{ + ElementBundle, ScrollBoxBundle, ScrollBoxProps, ScrollContextProviderBundle, TextProps, + TextWidgetBundle, +}; + +use crate::assets::AssetHandles; +use crate::states::Player; +use crate::ui::components::*; +use crate::ui::prelude::*; +use crate::ui::sync::UITravelInfo; +use crate::ui::widgets::*; +use crate::world::{CurrentResidence, MapQuery, TownPaths}; +use crate::{basic_widget, empty_props, on_button_click}; + +pub fn transit_button_factory(target: String) -> OnEvent { + let target = target.clone(); + on_button_click!( + ParamSet<( + Commands, + Res<TownPaths>, + Query<(Entity, &CurrentResidence), With<Player>>, + MapQuery, + )>, + |mut params: ParamSet<( + Commands, + Res<TownPaths>, + Query<(Entity, &CurrentResidence), With<Player>>, + MapQuery, + )>| { + let target = target.clone(); + let (entity, current) = { + match params.p2().get_single() { + Ok((entity, current)) => (entity.clone(), (current.get_location()).clone()), + _ => return, + } + }; + + let places = match params.p1().routes.get(¤t) { + Some(places) => places.clone(), + None => return, + }; + + let bundle = match params.p3().get_active_level() { + Some(level) => places.create_route_bundle_for(target, level).unwrap(), + None => return, + }; + + params.p0().entity(entity).insert(bundle); + } + ) +} + +empty_props!(TownMenuPanelProps); +basic_widget!(TownMenuPanelProps => TownMenuPanel); + +pub fn render_town_menu_panel( + In((widget_context, entity)): In<(KayakWidgetContext, Entity)>, + mut commands: Commands, + ui_data: Res<UITravelInfo>, + places: Res<TownPaths>, +) -> bool { + let parent_id = Some(entity); + + let distance_style = KStyle { + position_type: value(KPositionType::SelfDirected), + top: stretch(1.0), + left: stretch(1.0), + right: stretch(1.0), + bottom: px(50.0), + ..Default::default() + }; + + let panel_style = KStyle { + position_type: value(KPositionType::SelfDirected), + width: pct(65.0), + height: pct(80.0), + min_width: px(400.0), + min_height: px(300.0), + max_width: px(850.0), + max_height: px(550.0), + top: stretch(1.0), + left: stretch(1.0), + right: stretch(1.0), + bottom: stretch(1.0), + layout_type: value(LayoutType::Column), + row_between: px(20.0), + ..Default::default() + }; + + if let Some(ref place) = ui_data.current_town { + rsx! { + <PanelWidget + styles={panel_style} + > + <TextWidgetBundle + text={TextProps { + font: Some(String::from("header")), + content: format!("Hark! You enter {}", &place), + size: 48.0, + ..Default::default() + }} + styles={KStyle { + color: value(Color::BLACK), + padding: edge_px(20.0), + left: stretch(1.0), + right: stretch(1.0), + ..Default::default() + }} + /> + + <VDividerWidget props={VDividerWidgetProps { height: 4.0, padding: 5.0, color: Color::rgb(0.52, 0.369, 0.18)}} /> + + <TextWidgetBundle + text={TextProps { + content: format!("Set off for:"), + size: 32.0, + ..Default::default() + }} + styles={KStyle { + color: value(Color::BLACK), + padding: edge_px(20.0), + left: stretch(1.0), + right: stretch(1.0), + ..Default::default() + }} + /> + + { + for (place, distance) in ui_data.travel_options.iter() { + constructor! { + <ButtonWidget + styles={ + KStyle { + left: stretch(1.0), + right: stretch(1.0), + width: pct(70.0), + min_width: px(300.0), + max_width: px(600.0), + bottom: px(10.0), + ..Default::default() + } + } + props={ButtonWidgetProps { + left_icon: IconContent::Atlas(String::from("characters"), 0), + ..ButtonWidgetProps::text(format!("{}: {:.2}KM", &place, distance), 28.0) + }} + on_event={transit_button_factory(place.clone())} + /> + } + } + } + </PanelWidget> + } + } + + true +} diff --git a/raw_assets/manifest.toml b/raw_assets/manifest.toml index 0bd6b567f23769667a42ccee6ee51c1500a6b2a9..c2b8e6e6e862c09a97b9f82f843be0b39b571ba6 100644 --- a/raw_assets/manifest.toml +++ b/raw_assets/manifest.toml @@ -49,6 +49,12 @@ ttf = "fonts/CompassPro.ttf" image = "fonts/CompassPro.png" msdf = "fonts/CompassPro.kayak_font" +[[fonts]] +name = "equipment_pro" +ttf = "fonts/EquipmentPro.ttf" +image = "fonts/EquipmentPro.png" +msdf = "fonts/EquipmentPro.kayak_font" + [[ldtk]] path = "ldtk/overworld_maps.ldtk" name = "overworld" \ No newline at end of file