diff --git a/Cargo.lock b/Cargo.lock index d204ff3..00c62e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2096,14 +2096,6 @@ dependencies = [ "thread_local", ] -[[package]] -name = "bevy_wind_waker_shader" -version = "0.6.0" -source = "git+https://github.com/lavaeater/bevy_wind_waker_shader.git#1b017c3ef6a4fbdaff115df9ec5ae4954b2fb6ba" -dependencies = [ - "bevy", -] - [[package]] name = "bevy_window" version = "0.19.0" @@ -2232,32 +2224,6 @@ dependencies = [ "varinteger", ] -[[package]] -name = "bitfields" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5a55e8cbc3b75d1f002a3b62261ab67954755f7e7866f079b8aa63a409b549" -dependencies = [ - "bitfields-impl", -] - -[[package]] -name = "bitfields-impl" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "797cb6b6e8d5e8c2ecbb5ef52b7c273596d58ce1ab79ef2a6c38fa8dca0817c5" -dependencies = [ - "derive_more", - "getset", - "proc-macro2", - "quote", - "rustversion", - "strum", - "strum_macros", - "syn 2.0.119", - "thiserror 2.0.19", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -3523,17 +3489,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "getset" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cf442baaabe4213ce7d1239afc26c039180b6456da2cededa316ae2c8a77a77" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "ggrs" version = "0.13.0" @@ -6170,9 +6125,7 @@ dependencies = [ "bevy_asset_loader", "bevy_egui", "bevy_ggrs", - "bevy_wind_waker_shader", "bincode", - "bitfields", "clap", "enum_cycling", "enum_cycling_derive", diff --git a/Cargo.toml b/Cargo.toml index 6083800..5dc950d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,7 @@ serde_json = "1.0.145" bincode = "1.3.3" gltf = "1.4.1" ron = "0.12.0" -bitfields = "3.0.0" clap = { version = "4.6.6", features = ["derive"] } -bevy_wind_waker_shader = { git = "https://github.com/lavaeater/bevy_wind_waker_shader.git" } fixed = { version = "1.31.0", features = ["serde", "serde-str"] } strum = "0.28.0" strum_macros = "0.28.0" diff --git a/src/fighter/attack/mod.rs b/src/fighter/attack/mod.rs index c9f6ef9..6696767 100644 --- a/src/fighter/attack/mod.rs +++ b/src/fighter/attack/mod.rs @@ -32,9 +32,15 @@ use crate::{ #[derive(Deref, Component, Default, Hash, Debug, Copy, Clone)] pub struct FighterKnockbackVelocity(pub FGVec2); -#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, Component, Hash)] +#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, Component, Hash, PartialEq)] pub struct FighterDamage(FGi32); +impl std::fmt::Display for FighterDamage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:.2}", self.0) + } +} + #[derive(Debug, Hash, Clone)] pub enum HitReactionKind { Flinch, @@ -48,6 +54,7 @@ pub struct FighterHitReaction { pub hitstop_frames: HitStop, pub hitstun_frames: u32, pub kind: HitReactionKind, + pub damage: FighterDamage, } #[derive(Component, DerefMut, Deref, Debug, Default, Hash, Clone)] diff --git a/src/fighter/attack/reaction.rs b/src/fighter/attack/reaction.rs index f9105f2..8d9e1ad 100644 --- a/src/fighter/attack/reaction.rs +++ b/src/fighter/attack/reaction.rs @@ -49,10 +49,11 @@ pub fn resolve_fighter_hits( }; let attack_script = attack_scripts.get(&hit.attack_script)?; let hitbox = attack_script.hitboxes.get(hit.hitbox_index)?; + dbg!(hitbox.damage.0); let damage_received = stale_move_queue .get_attack_damage_multiplier(hit.attack_kind) * hitbox.damage.0; - + dbg!(damage_received); Some(( hit.attacker, damage_received, @@ -100,6 +101,7 @@ pub fn resolve_fighter_hits( hitstun_frames: knockback.get_hitstun_frames(&game_settings), hitstop_frames: hitstop, kind: HitReactionKind::Flinch, + damage: FighterDamage(attack_damage) }, )); } diff --git a/src/fighter/state/ground_attack.rs b/src/fighter/state/ground_attack.rs index 3005266..3f60990 100644 --- a/src/fighter/state/ground_attack.rs +++ b/src/fighter/state/ground_attack.rs @@ -47,7 +47,6 @@ impl FighterStateImpl for GroundAttackState { fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(self.attack_kind.get_animation(), false); let script = state_context.attack_script_assets.scripts[&self.attack_kind].clone(); - state_context.stale_move_queue.push(self.attack_kind); state_context.hitboxes.0 = Some(crate::fighter::FighterActiveAttack { kind: self.attack_kind, script, diff --git a/src/lib.rs b/src/lib.rs index 077b068..93d25cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,13 +28,11 @@ use bevy::{ tasks::block_on, }; use bevy_asset_loader::prelude::*; -use bevy_wind_waker_shader::prelude::*; use clap::Parser; use ron_asset_manager::RonAssetPlugin; use crate::{ - camera::MatchCameraPlugin, fighter::manifest::FighterManifest, game_settings::GameSettings, - schedule::GameplaySchedulePlugin, stage::manifest::StageManifest, + camera::MatchCameraPlugin, fighter::manifest::FighterManifest, game_settings::GameSettings, schedule::GameplaySchedulePlugin, stage::manifest::StageManifest, ui::InGameUIPlugin, }; mod args; @@ -53,6 +51,7 @@ pub mod schedule; pub mod scripting; pub mod stage; pub mod texture_reference; +pub mod ui; #[derive(States, Debug, Clone, Copy, Eq, PartialEq, Hash, Default)] pub enum AppState { @@ -89,7 +88,6 @@ impl Plugin for GamePlugin { app.init_state::() .add_plugins(( SettingsPlugin::new("moe.eirteam.shinespark.debug_settings"), - WindWakerShaderPlugin::default(), // Brings up GGRS (and with it `GgrsSchedule`), so it goes first. netcode::FighterNetcodePlugin::default(), GameplaySchedulePlugin, @@ -104,6 +102,7 @@ impl Plugin for GamePlugin { RonAssetPlugin::::create("fighter.ron"), RonAssetPlugin::::create("stage.ron"), RonAssetPlugin::::create("ron"), + InGameUIPlugin, )) .add_plugins(menus::MenuPlugin) .add_loading_state( diff --git a/src/ui/battle_ui.rs b/src/ui/battle_ui.rs new file mode 100644 index 0000000..34cd379 --- /dev/null +++ b/src/ui/battle_ui.rs @@ -0,0 +1,51 @@ +use bevy::prelude::*; + +use crate::{ + fighter::manifest::{FighterManifest, FighterManifestRegistry}, match_loading::{PendingMatch}, ui::{errors::UIErrors, fighter_info::FighterInfoUI}, +}; + +#[derive(Component, FromTemplate)] +pub struct BattleUI { +} + +pub fn spawn_battle_ui(mut commands: Commands, request: Res, fighter_registry: Res, manifests: Res>) -> Result { + + let mut fighter_uis = vec![]; + + for player in &request.players { + let manifest = fighter_registry.get(player.fighter).ok_or_else(|| UIErrors::FighterManifestHandleNotFound(player.fighter))?; + let manifest = manifests.get(manifest).ok_or_else(|| UIErrors::FighterManifestNotFound(player.fighter))?; + + fighter_uis.push(FighterInfoUI::build(manifest, player)); + } + + let scene = bsn! { + BattleUI { + } + Node { + width: percent(100), + height: percent(100), + flex_direction: FlexDirection::Column, + align_items: AlignItems::Center, + justify_content: JustifyContent::End, + } + Children [ + ( + #FighterInfos + Node { + width: percent(100), + flex_direction: FlexDirection::Row, + align_items: AlignItems::End, + justify_content: JustifyContent::SpaceEvenly, + } + Children [ + {fighter_uis} + ] + ) + ] + }; + + commands.spawn_scene(scene); + + Ok(()) +} diff --git a/src/ui/errors.rs b/src/ui/errors.rs new file mode 100644 index 0000000..09ebbc7 --- /dev/null +++ b/src/ui/errors.rs @@ -0,0 +1,14 @@ +use bevy::{scene::SpawnSceneError}; + +use crate::{fighter::FighterId}; + +#[derive(thiserror::Error, Debug)] +pub enum UIErrors { + #[error("Scene spawn failed: {0:?}")] + SceneSpawnFailed(#[from] SpawnSceneError), + #[error("Fighter manifest handle not found for fighter id {0:?}")] + FighterManifestHandleNotFound(FighterId), + + #[error("Fighter manifest not found for fighter id {0:?}")] + FighterManifestNotFound(FighterId), +} diff --git a/src/ui/fighter_info.rs b/src/ui/fighter_info.rs new file mode 100644 index 0000000..75cfc3d --- /dev/null +++ b/src/ui/fighter_info.rs @@ -0,0 +1,58 @@ +use bevy::prelude::*; + +use crate::{fighter::{attack::FighterDamage, manifest::{FighterManifest}}, match_loading::MatchPlayer, player::Player}; + +#[derive(Component, FromTemplate)] +pub struct FighterInfoUI { + percentage_text: Entity, + _name_text: Entity, + player_handle: usize, + visible_damage: FighterDamage, +} + +impl FighterInfoUI { + pub fn build(_manifest: &FighterManifest, match_player: &MatchPlayer) -> impl Scene { + let fighter_name = "El grande padre"; + bsn! { + FighterInfoUI { + percentage_text: #PercentageText, + _name_text: #NameText, + player_handle: {match_player.handle} + } + Node { + flex_direction: FlexDirection::Column, + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + + } + Children [ + ( + #PercentageText + Text("0.00%") + TextFont { + font_size: px(crate::menus::style::H2_SIZE), + } + ), + ( + #NameText + Text({fighter_name}) + ) + ] + } + } +} + +pub fn update_fighter_info_damage(fighters: Query<(&Player, &FighterDamage)>, ui_elements: Query<&mut FighterInfoUI>, mut commands: Commands) { + for mut ui_element in ui_elements { + let Some((_, damage)) = fighters.iter().find(|(player, _)| { + player.handle == ui_element.player_handle + }) else { + continue; + }; + + if *damage != ui_element.visible_damage { + commands.entity(ui_element.percentage_text).insert(Text(format!("{}%", damage))); + ui_element.visible_damage = damage.clone(); + } + } +} \ No newline at end of file diff --git a/src/ui/mod.rs b/src/ui/mod.rs new file mode 100644 index 0000000..75b319f --- /dev/null +++ b/src/ui/mod.rs @@ -0,0 +1,17 @@ +use bevy::prelude::*; + +use crate::AppState; + +pub mod battle_ui; +pub mod errors; +pub mod fighter_info; + +#[derive(Default)] +pub struct InGameUIPlugin; + +impl Plugin for InGameUIPlugin { + fn build(&self, app: &mut App) { + app.add_systems(OnEnter(AppState::InMatch), battle_ui::spawn_battle_ui) + .add_systems(PostUpdate, fighter_info::update_fighter_info_damage); + } +}