173 lines
4.7 KiB
Rust
173 lines
4.7 KiB
Rust
#[cfg(feature = "client")]
|
|
use crate::{
|
|
backpack::backpack_ui::BackpackUiState, control::BackpackButtonPress, player::LocalPlayer,
|
|
protocol::PlaySound,
|
|
};
|
|
use crate::{
|
|
cash::CashCollectEvent, global_observer, head_drop::HeadCollected, heads::HeadState,
|
|
heads_database::HeadsDatabase,
|
|
};
|
|
use bevy::prelude::*;
|
|
#[cfg(feature = "client")]
|
|
use bevy_replicon::prelude::ClientTriggerExt;
|
|
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)]
|
|
#[reflect(Component)]
|
|
pub struct Backpack {
|
|
pub heads: Vec<HeadState>,
|
|
}
|
|
|
|
impl Backpack {
|
|
pub fn reloading(&self) -> bool {
|
|
for head in &self.heads {
|
|
if !head.has_ammo() {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
pub fn contains(&self, head_id: usize) -> bool {
|
|
self.heads.iter().any(|head| head.head == head_id)
|
|
}
|
|
|
|
pub fn insert(&mut self, head_id: usize, heads_db: &HeadsDatabase) {
|
|
self.heads.push(HeadState::new(head_id, heads_db));
|
|
}
|
|
}
|
|
|
|
#[derive(Event, Serialize, Deserialize)]
|
|
pub struct BackpackSwapEvent(pub usize);
|
|
|
|
pub fn plugin(app: &mut App) {
|
|
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);
|
|
}
|
|
|
|
#[cfg(feature = "client")]
|
|
#[allow(clippy::too_many_arguments)]
|
|
fn backpack_inputs(
|
|
backpacks: Single<(&Backpack, &mut BackpackUiState), With<LocalPlayer>>,
|
|
mut backpack_inputs: MessageReader<BackpackButtonPress>,
|
|
mut commands: Commands,
|
|
time: Res<Time>,
|
|
) {
|
|
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 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 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(
|
|
trigger: On<HeadCollected>,
|
|
mut cmds: Commands,
|
|
mut backpack: Query<&mut Backpack>,
|
|
heads_db: Res<HeadsDatabase>,
|
|
) -> Result {
|
|
let HeadCollected { head, entity } = *trigger.event();
|
|
|
|
let mut backpack = backpack.get_mut(entity)?;
|
|
|
|
if backpack.contains(head) {
|
|
cmds.trigger(CashCollectEvent);
|
|
} else {
|
|
backpack.insert(head, heads_db.as_ref());
|
|
}
|
|
|
|
Ok(())
|
|
}
|