/*
* This file is part of laurelin_client
* Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
*
* Licensed under GPL-3.0-only.
* See LICENSE for licensing information.
*/
use bevy::prelude::*;
use bevy_mod_picking::prelude::*;
use bevy_rapier3d::prelude::*;
use crate::{plugins::GameActionCreateCallEvent, api::game::{Action, Command}, Global, game_status::PlayerState};
use super::{
card::{visual_card_kind, VisualCard, VisualCardBundle, ClickedCard},
GameData,
};
pub struct SupplyPlugin;
impl Plugin for SupplyPlugin {
fn build(&self, app: &mut App) {
app.add_event::<SpawnSupplyPilesEvent>()
.add_event::<PositionSupplyPilesEvent>()
.add_system(spawn_supply_piles.run_if(on_event::<SpawnSupplyPilesEvent>()))
.add_system(position_supply_piles.run_if(on_event::<PositionSupplyPilesEvent>()))
.add_system(handle_clicked_supply_pile);
}
}
pub struct SpawnSupplyPilesEvent;
fn spawn_supply_piles(
mut commands: Commands,
game_data: Res<GameData>,
mut psp_ev_w: EventWriter<PositionSupplyPilesEvent>,
mut pile_query: Query<Entity, With<visual_card_kind::Supply>>,
) {
let Some(status) = &game_data.game_status else {
warn!("game_status was none");
return;
};
// despawn possible existing supply piles
for entity in pile_query.iter() {
commands.entity(entity).despawn_recursive();
}
for (index, pile) in status.supply_piles.iter().enumerate() {
commands
.spawn(VisualCardBundle {
visual_card: VisualCard {
card: pile.card.clone(),
},
rigid_body: RigidBody::Fixed,
..Default::default()
})
.insert(visual_card_kind::Supply(index))
.insert(OnPointer::<Over>::target_component_mut::<Transform>(|_over, transform| {
transform.translation.y += 0.2;
}))
.insert(OnPointer::<Out>::target_component_mut::<Transform>(|_over, transform| {
transform.translation.y -= 0.2;
}));
}
psp_ev_w.send(PositionSupplyPilesEvent);
}
pub struct PositionSupplyPilesEvent;
fn position_supply_piles(
mut pile_query: Query<(&VisualCard, &mut Transform), With<visual_card_kind::Supply>>,
) {
let mut piles: Vec<(&VisualCard, Mut<Transform>)> = pile_query.iter_mut().collect::<Vec<_>>();
piles.sort_by_key(|(vc, _t)| vc.card.name.clone());
piles.sort_by_key(|(vc, _t)| vc.card.cost);
// split piles into top and bottom row
let mid = piles.len() / 2;
let (p1, p2) = piles.split_at_mut(mid);
// keep track of offset between cards
let mut offset = 0.;
// top row
for (_, t) in p1 {
t.translation.x += offset;
offset += 1.0;
}
// reset offset when changing rows
offset = 0.;
// bottom row
for (_, t) in p2 {
t.translation.z += 1.5;
t.translation.x += offset;
offset += 1.0;
}
}
fn handle_clicked_supply_pile(
mut commands: Commands,
mut card_query: Query<(Entity, &VisualCard, &visual_card_kind::Supply), (With<visual_card_kind::Supply>, With<ClickedCard>)>,
mut gac_ev_w: EventWriter<GameActionCreateCallEvent>,
game_data: Res<GameData>,
global: Res<Global>,
) {
let Ok((entity, card, card_kind)) = card_query.get_single() else {
return;
};
commands.entity(entity).remove::<ClickedCard>();
let player = game_data.game_status.as_ref().unwrap()
.players.get(&global.user.as_ref().unwrap().id).unwrap();
if player.state != PlayerState::BuyPhase {
// we ain't buying rn
return;
} else if player.currency < card.card.cost {
// not enough currency
return;
} else if game_data.game_status.as_ref().unwrap()
.supply_piles.get(card_kind.0).unwrap().amount <= 0 {
// no cards in supply
return;
}
gac_ev_w.send(GameActionCreateCallEvent {
action: Action::new(
&game_data.game.as_ref().unwrap().id,
&global.user.as_ref().unwrap().id,
&global.user.as_ref().unwrap().id,
&Command::TakeFromPile {
index: card_kind.0,
for_cost: card.card.cost,
},
fastrand::u64(u64::MIN..=u64::MAX),
),
});
}