diff --git a/game_core/src/world/hunger.rs b/game_core/src/world/hunger.rs index ea6ca40d117374e64139f2fbb8394a935597d726..708093ec1d336b5b0e60240928098326c406a6b3 100644 --- a/game_core/src/world/hunger.rs +++ b/game_core/src/world/hunger.rs @@ -1,14 +1,22 @@ use std::collections::HashMap; -use bevy::prelude::{Commands, Component, Entity, EventReader, Mut, Query, Res, With, Without}; +use bevy::prelude::{ + BuildChildren, Color, Commands, Component, DespawnRecursiveExt, Entity, EventReader, + EventWriter, Mut, NodeBundle, Query, Res, TextBundle, Transform, TransformBundle, Val, + VisibilityBundle, With, Without, +}; +use bevy::text::{Text, TextStyle}; +use bevy::ui::{AlignItems, FlexDirection, JustifyContent, Style, UiRect}; use serde::{Deserialize, Serialize}; use crate::assets::AssetHandles; use crate::const_data::get_goods_from_name_checked; use crate::states::Player; +use crate::system::camera::ChaseCam; +use crate::system::utilities::format_ui_distance; use crate::world::spawning::apply_skull_marker; use crate::world::travel::WorldTickEvent; -use crate::world::{TownName, TradeGood, TradingState}; +use crate::world::{DistanceTravelled, TownName, TradeGood, TradingState, WorldLinked}; #[derive(Clone, Debug, Default, Serialize, Deserialize, Component)] pub struct HungerState { @@ -148,19 +156,100 @@ fn process_hunger_state<'a>( } #[derive(Default)] -pub struct PlayerStarvedEvent; +pub struct PlayerStarvedEvent { + distance_travelled: f32, +} pub fn handle_entity_starvation( mut commands: Commands, assets: Res<AssetHandles>, food_query: Query<(Entity, &HungerState), Without<StarvationMarker>>, - player_query: Query<(), With<Player>>, + player_query: Query<(&Transform, &DistanceTravelled), With<Player>>, town_query: Query<&TownName>, + mut player_events: EventWriter<PlayerStarvedEvent>, ) { for (entity, hunger) in &food_query { if hunger.sustenance == 0 { - apply_skull_marker(&mut commands, &assets, entity); - commands.entity(entity).insert(StarvationMarker); + if town_query.contains(entity) { + apply_skull_marker(&mut commands, &assets, entity); + commands.entity(entity).insert(StarvationMarker); + } else if let Ok((transform, distance_travelled)) = player_query.get(entity) { + commands.entity(entity).despawn_recursive(); + let new_entity = commands + .spawn(( + TransformBundle::from(*transform), + VisibilityBundle::default(), + ChaseCam, + WorldLinked, + )) + .id(); + + apply_skull_marker(&mut commands, &assets, new_entity); + player_events.send(PlayerStarvedEvent { + distance_travelled: distance_travelled.0, + }) + } } } } + +pub fn handle_player_starved( + mut commands: Commands, + assets: Res<AssetHandles>, + mut events: EventReader<PlayerStarvedEvent>, +) { + for event in events.iter() { + commands + .spawn(( + NodeBundle { + style: Style { + margin: UiRect::all(Val::Auto), + flex_direction: FlexDirection::Column, + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + ..Default::default() + }, + ..Default::default() + }, + WorldLinked, + )) + .with_children(|builder| { + builder.spawn(TextBundle { + text: Text::from_section( + "You Have Perished", + TextStyle { + font_size: 64.0, + color: Color::ANTIQUE_WHITE, + font: assets.font("compass_pro"), + }, + ), + ..Default::default() + }); + builder.spawn(TextBundle { + text: Text::from_section( + format!( + "You made it: {}", + format_ui_distance(event.distance_travelled) + ), + TextStyle { + font_size: 48.0, + color: Color::ANTIQUE_WHITE, + font: assets.font("equipment_pro"), + }, + ), + ..Default::default() + }); + builder.spawn(TextBundle { + text: Text::from_section( + "Press Escape To Return To Menu", + TextStyle { + font_size: 32.0, + color: Color::ANTIQUE_WHITE, + font: assets.font("equipment_pro"), + }, + ), + ..Default::default() + }); + }); + } +} diff --git a/game_core/src/world/mod.rs b/game_core/src/world/mod.rs index e8fe8f908a5cb382837ee9d4319dc666721e21db..bb1a396ae5ca995f96dbf728a66160cab4a0c79d 100644 --- a/game_core/src/world/mod.rs +++ b/game_core/src/world/mod.rs @@ -33,6 +33,7 @@ pub use utils::{grid_to_px, px_to_grid, ActiveLevel, WorldLinked}; pub use world_query::{CameraBounds, MapQuery}; use crate::system::flow::AppState; +use crate::world::hunger::PlayerStarvedEvent; use crate::world::spawning::PopulateWorldEvent; use crate::world::travel::WorldTickEvent; @@ -49,6 +50,7 @@ impl Plugin for WorldPlugin { .init_resource::<EncounterState>() .add_event::<PopulateWorldEvent>() .add_event::<WorldTickEvent>() + .add_event::<PlayerStarvedEvent>() .add_event::<SelectEncounterOptionEvent>() .add_enter_system(AppState::InGame, |mut commands: Commands| { commands.insert_resource(ActiveLevel { @@ -96,6 +98,7 @@ impl Plugin for WorldPlugin { .with_system(encounters::notify_new_zone) .with_system(hunger::handle_entity_starvation) .with_system(encounters::handle_encounter_option_event) + .with_system(hunger::handle_player_starved) .with_system(|mut events: ResMut<Events<WorldTickEvent>>| { events.clear(); })