make backwork in multiplayer
This commit is contained in:
@@ -1,39 +0,0 @@
|
|||||||
use super::UiHeadState;
|
|
||||||
use bevy::prelude::*;
|
|
||||||
|
|
||||||
pub static BACKPACK_HEAD_SLOTS: usize = 5;
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
pub struct BackpackMarker;
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
pub struct BackpackCountText;
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
pub struct HeadSelector(pub usize);
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
pub struct HeadImage(pub usize);
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
pub struct HeadDamage(pub usize);
|
|
||||||
|
|
||||||
#[derive(Component, Default, Debug, Reflect)]
|
|
||||||
#[reflect(Component, Default)]
|
|
||||||
pub struct BackpackUiState {
|
|
||||||
pub heads: [Option<UiHeadState>; 5],
|
|
||||||
pub scroll: usize,
|
|
||||||
pub count: usize,
|
|
||||||
pub current_slot: usize,
|
|
||||||
pub open: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BackpackUiState {
|
|
||||||
pub fn relative_current_slot(&self) -> usize {
|
|
||||||
self.current_slot.saturating_sub(self.scroll)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
|
||||||
app.register_type::<BackpackUiState>();
|
|
||||||
}
|
|
||||||
@@ -6,13 +6,7 @@ use crate::{
|
|||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
#[cfg(feature = "client")]
|
|
||||||
use bevy_replicon::prelude::ClientTriggerExt;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub use ui_head_state::UiHeadState;
|
|
||||||
|
|
||||||
pub mod backpack_ui;
|
|
||||||
pub mod ui_head_state;
|
|
||||||
|
|
||||||
#[derive(Component, Default, Reflect, Serialize, Deserialize, PartialEq)]
|
#[derive(Component, Default, Reflect, Serialize, Deserialize, PartialEq)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
@@ -40,120 +34,15 @@ impl Backpack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Event, Serialize, Deserialize)]
|
#[derive(Event, Debug, Serialize, Deserialize)]
|
||||||
pub struct BackpackSwapEvent(pub usize);
|
pub struct BackpackSwapEvent(pub usize);
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.register_type::<Backpack>();
|
app.register_type::<Backpack>();
|
||||||
|
|
||||||
app.add_plugins(backpack_ui::plugin);
|
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
|
||||||
app.add_systems(FixedUpdate, (backpack_inputs, sync_on_change));
|
|
||||||
|
|
||||||
global_observer!(app, on_head_collect);
|
global_observer!(app, on_head_collect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
|
||||||
fn backpack_inputs(
|
|
||||||
backpacks: Single<
|
|
||||||
(&Backpack, &mut backpack_ui::BackpackUiState),
|
|
||||||
With<crate::player::LocalPlayer>,
|
|
||||||
>,
|
|
||||||
mut backpack_inputs: MessageReader<crate::control::BackpackButtonPress>,
|
|
||||||
mut commands: Commands,
|
|
||||||
time: Res<Time>,
|
|
||||||
) {
|
|
||||||
use crate::{control::BackpackButtonPress, protocol::PlaySound};
|
|
||||||
|
|
||||||
let (backpack, mut state) = backpacks.into_inner();
|
|
||||||
|
|
||||||
for input in backpack_inputs.read() {
|
|
||||||
match input {
|
|
||||||
BackpackButtonPress::Toggle => {
|
|
||||||
if state.count == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.open = !state.open;
|
|
||||||
commands.trigger(PlaySound::Backpack { open: state.open });
|
|
||||||
}
|
|
||||||
BackpackButtonPress::Swap => {
|
|
||||||
if !state.open {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
commands.client_trigger(BackpackSwapEvent(state.current_slot));
|
|
||||||
}
|
|
||||||
BackpackButtonPress::Left => {
|
|
||||||
if !state.open {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if state.current_slot > 0 {
|
|
||||||
state.current_slot -= 1;
|
|
||||||
|
|
||||||
commands.trigger(PlaySound::Selection);
|
|
||||||
sync_backpack_ui(backpack, &mut state, time.elapsed_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BackpackButtonPress::Right => {
|
|
||||||
if !state.open {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if state.current_slot < state.count.saturating_sub(1) {
|
|
||||||
state.current_slot += 1;
|
|
||||||
|
|
||||||
commands.trigger(PlaySound::Selection);
|
|
||||||
sync_backpack_ui(backpack, &mut state, time.elapsed_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
|
||||||
fn sync_on_change(
|
|
||||||
backpack: Query<Ref<Backpack>>,
|
|
||||||
mut state: Single<&mut backpack_ui::BackpackUiState>,
|
|
||||||
time: Res<Time>,
|
|
||||||
) {
|
|
||||||
for backpack in backpack.iter() {
|
|
||||||
if backpack.is_changed() || backpack.reloading() {
|
|
||||||
sync_backpack_ui(&backpack, &mut state, time.elapsed_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
|
||||||
fn sync_backpack_ui(backpack: &Backpack, state: &mut backpack_ui::BackpackUiState, time: f32) {
|
|
||||||
use crate::backpack::backpack_ui::BACKPACK_HEAD_SLOTS;
|
|
||||||
|
|
||||||
state.count = backpack.heads.len();
|
|
||||||
|
|
||||||
state.scroll = state
|
|
||||||
.scroll
|
|
||||||
.min(state.count.saturating_sub(BACKPACK_HEAD_SLOTS));
|
|
||||||
|
|
||||||
if state.current_slot >= state.scroll + BACKPACK_HEAD_SLOTS {
|
|
||||||
state.scroll = state.current_slot.saturating_sub(BACKPACK_HEAD_SLOTS - 1);
|
|
||||||
}
|
|
||||||
if state.current_slot < state.scroll {
|
|
||||||
state.scroll = state.current_slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..BACKPACK_HEAD_SLOTS {
|
|
||||||
if let Some(head) = backpack.heads.get(i + state.scroll) {
|
|
||||||
use crate::backpack::ui_head_state::UiHeadState;
|
|
||||||
|
|
||||||
state.heads[i] = Some(UiHeadState::new(*head, time));
|
|
||||||
} else {
|
|
||||||
state.heads[i] = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_head_collect(
|
fn on_head_collect(
|
||||||
trigger: On<HeadCollected>,
|
trigger: On<HeadCollected>,
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
use crate::heads::HeadState;
|
|
||||||
use bevy::prelude::*;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Reflect, Default, Serialize, Deserialize)]
|
|
||||||
pub struct UiHeadState {
|
|
||||||
pub head: usize,
|
|
||||||
pub health: f32,
|
|
||||||
pub ammo: f32,
|
|
||||||
pub reloading: Option<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UiHeadState {
|
|
||||||
pub fn damage(&self) -> f32 {
|
|
||||||
1. - self.health
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ammo_used(&self) -> f32 {
|
|
||||||
1. - self.ammo
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reloading(&self) -> Option<f32> {
|
|
||||||
self.reloading
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(value: HeadState, time: f32) -> Self {
|
|
||||||
let reloading = if value.has_ammo() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((time - value.last_use) / value.reload_duration)
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
|
||||||
head: value.head,
|
|
||||||
ammo: value.ammo as f32 / value.ammo_max as f32,
|
|
||||||
health: value.health as f32 / value.health_max as f32,
|
|
||||||
reloading,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState, aim::AimTarget, backpack::UiHeadState, client::ui::HeadsImages, heads::ActiveHeads,
|
GameState,
|
||||||
hitpoints::Hitpoints, loading_assets::UIAssets, npc::Npc, player::LocalPlayer,
|
aim::AimTarget,
|
||||||
|
client::ui::{HeadsImages, UiHeadState},
|
||||||
|
heads::ActiveHeads,
|
||||||
|
hitpoints::Hitpoints,
|
||||||
|
loading_assets::UIAssets,
|
||||||
|
npc::Npc,
|
||||||
|
player::LocalPlayer,
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
|||||||
98
crates/hedz_reloaded/src/client/backpack.rs
Normal file
98
crates/hedz_reloaded/src/client/backpack.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use crate::{
|
||||||
|
backpack::{Backpack, BackpackSwapEvent},
|
||||||
|
client::ui::{BACKPACK_HEAD_SLOTS, BackpackUiState, UiHeadState},
|
||||||
|
control::BackpackButtonPress,
|
||||||
|
player::LocalPlayer,
|
||||||
|
protocol::PlaySound,
|
||||||
|
};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_replicon::prelude::ClientTriggerExt;
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.add_systems(FixedUpdate, (backpack_inputs, sync_on_change));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backpack_inputs(
|
||||||
|
backpack: Single<&Backpack, With<LocalPlayer>>,
|
||||||
|
mut state: ResMut<BackpackUiState>,
|
||||||
|
mut backpack_inputs: MessageReader<crate::control::BackpackButtonPress>,
|
||||||
|
mut commands: Commands,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
for input in backpack_inputs.read() {
|
||||||
|
match input {
|
||||||
|
BackpackButtonPress::Toggle => {
|
||||||
|
if state.count == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.open = !state.open;
|
||||||
|
commands.trigger(PlaySound::Backpack { open: state.open });
|
||||||
|
}
|
||||||
|
BackpackButtonPress::Swap => {
|
||||||
|
if !state.open {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.client_trigger(BackpackSwapEvent(state.current_slot));
|
||||||
|
}
|
||||||
|
BackpackButtonPress::Left => {
|
||||||
|
if !state.open {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.current_slot > 0 {
|
||||||
|
state.current_slot -= 1;
|
||||||
|
|
||||||
|
commands.trigger(PlaySound::Selection);
|
||||||
|
sync_backpack_ui(&backpack, &mut state, time.elapsed_secs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BackpackButtonPress::Right => {
|
||||||
|
if !state.open {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.current_slot < state.count.saturating_sub(1) {
|
||||||
|
state.current_slot += 1;
|
||||||
|
|
||||||
|
commands.trigger(PlaySound::Selection);
|
||||||
|
sync_backpack_ui(&backpack, &mut state, time.elapsed_secs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_on_change(
|
||||||
|
backpack: Single<Ref<Backpack>, With<LocalPlayer>>,
|
||||||
|
mut state: ResMut<BackpackUiState>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
if backpack.is_changed() || backpack.reloading() {
|
||||||
|
sync_backpack_ui(&backpack, &mut state, time.elapsed_secs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_backpack_ui(backpack: &Backpack, state: &mut BackpackUiState, time: f32) {
|
||||||
|
state.count = backpack.heads.len();
|
||||||
|
|
||||||
|
state.scroll = state
|
||||||
|
.scroll
|
||||||
|
.min(state.count.saturating_sub(BACKPACK_HEAD_SLOTS));
|
||||||
|
|
||||||
|
if state.current_slot >= state.scroll + BACKPACK_HEAD_SLOTS {
|
||||||
|
state.scroll = state.current_slot.saturating_sub(BACKPACK_HEAD_SLOTS - 1);
|
||||||
|
}
|
||||||
|
if state.current_slot < state.scroll {
|
||||||
|
state.scroll = state.current_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..BACKPACK_HEAD_SLOTS {
|
||||||
|
if let Some(head) = backpack.heads.get(i + state.scroll) {
|
||||||
|
state.heads[i] = Some(UiHeadState::new(*head, time));
|
||||||
|
} else {
|
||||||
|
state.heads[i] = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ use bevy_trenchbroom::geometry::Brushes;
|
|||||||
|
|
||||||
pub mod aim;
|
pub mod aim;
|
||||||
pub mod audio;
|
pub mod audio;
|
||||||
|
mod backpack;
|
||||||
pub mod control;
|
pub mod control;
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod enemy;
|
pub mod enemy;
|
||||||
@@ -47,6 +48,7 @@ pub fn plugin(app: &mut App) {
|
|||||||
steam::plugin,
|
steam::plugin,
|
||||||
ui::plugin,
|
ui::plugin,
|
||||||
settings::plugin,
|
settings::plugin,
|
||||||
|
backpack::plugin,
|
||||||
));
|
));
|
||||||
|
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
|
|||||||
@@ -1,15 +1,47 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState, HEDZ_GREEN,
|
GameState, HEDZ_GREEN,
|
||||||
backpack::backpack_ui::{
|
client::ui::heads_ui::{HeadsImages, UiHeadState},
|
||||||
BACKPACK_HEAD_SLOTS, BackpackCountText, BackpackMarker, BackpackUiState, HeadDamage,
|
|
||||||
HeadImage, HeadSelector,
|
|
||||||
},
|
|
||||||
client::ui::heads_ui::HeadsImages,
|
|
||||||
loading_assets::UIAssets,
|
loading_assets::UIAssets,
|
||||||
};
|
};
|
||||||
use bevy::{ecs::spawn::SpawnIter, prelude::*};
|
use bevy::{ecs::spawn::SpawnIter, prelude::*};
|
||||||
|
|
||||||
|
pub static BACKPACK_HEAD_SLOTS: usize = 5;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct BackpackMarker;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct BackpackCountText;
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct HeadSelector(pub usize);
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct HeadImage(pub usize);
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct HeadDamage(pub usize);
|
||||||
|
|
||||||
|
#[derive(Resource, Default, Debug, Reflect)]
|
||||||
|
#[reflect(Resource)]
|
||||||
|
pub struct BackpackUiState {
|
||||||
|
pub heads: [Option<UiHeadState>; 5],
|
||||||
|
pub scroll: usize,
|
||||||
|
pub count: usize,
|
||||||
|
pub current_slot: usize,
|
||||||
|
pub open: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BackpackUiState {
|
||||||
|
pub fn relative_current_slot(&self) -> usize {
|
||||||
|
self.current_slot.saturating_sub(self.scroll)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.register_type::<BackpackUiState>();
|
||||||
|
app.init_resource::<BackpackUiState>();
|
||||||
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), setup);
|
app.add_systems(OnEnter(GameState::Playing), setup);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
FixedUpdate,
|
FixedUpdate,
|
||||||
@@ -152,10 +184,14 @@ fn spawn_head_ui(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_visibility(
|
fn update_visibility(
|
||||||
state: Single<&BackpackUiState, Changed<BackpackUiState>>,
|
state: Res<BackpackUiState>,
|
||||||
mut backpack: Single<&mut Visibility, (With<BackpackMarker>, Without<BackpackCountText>)>,
|
mut backpack: Single<&mut Visibility, (With<BackpackMarker>, Without<BackpackCountText>)>,
|
||||||
mut count: Single<&mut Visibility, (Without<BackpackMarker>, With<BackpackCountText>)>,
|
mut count: Single<&mut Visibility, (Without<BackpackMarker>, With<BackpackCountText>)>,
|
||||||
) {
|
) {
|
||||||
|
if !state.is_changed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
**backpack = if state.open {
|
**backpack = if state.open {
|
||||||
Visibility::Visible
|
Visibility::Visible
|
||||||
} else {
|
} else {
|
||||||
@@ -170,10 +206,14 @@ fn update_visibility(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_count(
|
fn update_count(
|
||||||
state: Single<&BackpackUiState, Changed<BackpackUiState>>,
|
state: Res<BackpackUiState>,
|
||||||
text: Option<Single<Entity, With<BackpackCountText>>>,
|
text: Option<Single<Entity, With<BackpackCountText>>>,
|
||||||
mut writer: TextUiWriter,
|
mut writer: TextUiWriter,
|
||||||
) {
|
) {
|
||||||
|
if !state.is_changed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let Some(text) = text else {
|
let Some(text) = text else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -182,12 +222,16 @@ fn update_count(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
state: Single<&BackpackUiState, Changed<BackpackUiState>>,
|
state: Res<BackpackUiState>,
|
||||||
heads_images: Res<HeadsImages>,
|
heads_images: Res<HeadsImages>,
|
||||||
mut head_image: Query<(&HeadImage, &mut Visibility, &mut ImageNode), Without<HeadSelector>>,
|
mut head_image: Query<(&HeadImage, &mut Visibility, &mut ImageNode), Without<HeadSelector>>,
|
||||||
mut head_damage: Query<(&HeadDamage, &mut Node), Without<HeadSelector>>,
|
mut head_damage: Query<(&HeadDamage, &mut Node), Without<HeadSelector>>,
|
||||||
mut head_selector: Query<(&HeadSelector, &mut Visibility), Without<HeadImage>>,
|
mut head_selector: Query<(&HeadSelector, &mut Visibility), Without<HeadImage>>,
|
||||||
) {
|
) {
|
||||||
|
if !state.is_changed() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (HeadImage(head), mut vis, mut image) in head_image.iter_mut() {
|
for (HeadImage(head), mut vis, mut image) in head_image.iter_mut() {
|
||||||
if let Some(head) = &state.heads[*head] {
|
if let Some(head) = &state.heads[*head] {
|
||||||
*vis = Visibility::Inherited;
|
*vis = Visibility::Inherited;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState,
|
||||||
backpack::UiHeadState,
|
heads::{ActiveHeads, HEAD_COUNT, HEAD_SLOTS, HeadState},
|
||||||
heads::{ActiveHeads, HEAD_COUNT, HEAD_SLOTS},
|
|
||||||
heads_database::HeadsDatabase,
|
heads_database::HeadsDatabase,
|
||||||
loading_assets::UIAssets,
|
loading_assets::UIAssets,
|
||||||
player::LocalPlayer,
|
player::LocalPlayer,
|
||||||
@@ -34,6 +33,43 @@ struct UiActiveHeads {
|
|||||||
selected_slot: usize,
|
selected_slot: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Reflect, Default, Serialize, Deserialize)]
|
||||||
|
pub struct UiHeadState {
|
||||||
|
pub head: usize,
|
||||||
|
pub health: f32,
|
||||||
|
pub ammo: f32,
|
||||||
|
pub reloading: Option<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UiHeadState {
|
||||||
|
pub fn damage(&self) -> f32 {
|
||||||
|
1. - self.health
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ammo_used(&self) -> f32 {
|
||||||
|
1. - self.ammo
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reloading(&self) -> Option<f32> {
|
||||||
|
self.reloading
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(value: HeadState, time: f32) -> Self {
|
||||||
|
let reloading = if value.has_ammo() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((time - value.last_use) / value.reload_duration)
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
head: value.head,
|
||||||
|
ammo: value.ammo as f32 / value.ammo_max as f32,
|
||||||
|
health: value.health as f32 / value.health_max as f32,
|
||||||
|
reloading,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.register_type::<HeadDamage>();
|
app.register_type::<HeadDamage>();
|
||||||
app.register_type::<UiActiveHeads>();
|
app.register_type::<UiActiveHeads>();
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ mod backpack_ui;
|
|||||||
mod heads_ui;
|
mod heads_ui;
|
||||||
mod pause;
|
mod pause;
|
||||||
|
|
||||||
pub use heads_ui::HeadsImages;
|
pub use backpack_ui::{BACKPACK_HEAD_SLOTS, BackpackUiState};
|
||||||
|
pub use heads_ui::{HeadsImages, UiHeadState};
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
|||||||
@@ -292,12 +292,15 @@ fn on_select_active_head(
|
|||||||
|
|
||||||
fn on_swap_backpack(
|
fn on_swap_backpack(
|
||||||
trigger: On<FromClient<BackpackSwapEvent>>,
|
trigger: On<FromClient<BackpackSwapEvent>>,
|
||||||
|
clients: ClientToController,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut query: Query<(Entity, &mut ActiveHeads, &mut Hitpoints, &mut Backpack), With<Player>>,
|
mut query: Query<(Entity, &mut ActiveHeads, &mut Hitpoints, &mut Backpack), With<Player>>,
|
||||||
) {
|
) {
|
||||||
|
let player = clients.get_controller(trigger.client_id);
|
||||||
|
|
||||||
let backpack_slot = trigger.event().0;
|
let backpack_slot = trigger.event().0;
|
||||||
|
|
||||||
let Ok((player, mut active_heads, mut hp, mut backpack)) = query.single_mut() else {
|
let Ok((player, mut active_heads, mut hp, mut backpack)) = query.get_mut(player) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState,
|
||||||
abilities::PlayerTriggerState,
|
abilities::PlayerTriggerState,
|
||||||
backpack::{Backpack, backpack_ui::BackpackUiState},
|
backpack::Backpack,
|
||||||
camera::{CameraArmRotation, CameraTarget},
|
camera::{CameraArmRotation, CameraTarget},
|
||||||
cash::{Cash, CashCollectEvent, CashInventory},
|
cash::{Cash, CashCollectEvent, CashInventory},
|
||||||
character::{AnimatedCharacter, HedzCharacter},
|
character::{AnimatedCharacter, HedzCharacter},
|
||||||
@@ -32,7 +32,7 @@ pub struct Player;
|
|||||||
|
|
||||||
#[derive(Component, Debug, Reflect)]
|
#[derive(Component, Debug, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
#[require(LocalInputs, BackpackUiState)]
|
#[require(LocalInputs)]
|
||||||
pub struct LocalPlayer;
|
pub struct LocalPlayer;
|
||||||
|
|
||||||
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Component, Default, Serialize, Deserialize, PartialEq)]
|
||||||
@@ -95,7 +95,6 @@ pub fn spawn(
|
|||||||
id,
|
id,
|
||||||
),
|
),
|
||||||
Backpack::default(),
|
Backpack::default(),
|
||||||
BackpackUiState::default(),
|
|
||||||
Inputs::default(),
|
Inputs::default(),
|
||||||
Replicated,
|
Replicated,
|
||||||
))
|
))
|
||||||
@@ -165,7 +164,7 @@ fn on_update_head_mesh(
|
|||||||
animated_characters: Query<&AnimatedCharacter>,
|
animated_characters: Query<&AnimatedCharacter>,
|
||||||
mut active_head: Query<&mut ActiveHead>,
|
mut active_head: Query<&mut ActiveHead>,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
let player_id = player_id.get(trigger.entity)?.clone();
|
let player_id = *(player_id.get(trigger.entity)?);
|
||||||
|
|
||||||
let player_body_mesh = children
|
let player_body_mesh = children
|
||||||
.get(trigger.entity)?
|
.get(trigger.entity)?
|
||||||
|
|||||||
Reference in New Issue
Block a user