use super::*;
pub const SPECTATOR_EVENTS: [TideEvent; 7] = [
TideEvent::CrabMania,
TideEvent::GullMania,
TideEvent::SpeedUp,
TideEvent::SlowDown,
TideEvent::FreshSand,
TideEvent::CastleSwap,
TideEvent::RightClaws,
];
pub(super) const WINDOW: f32 = 3.0;
pub(super) const COOLDOWN: f32 = 25.0;
#[derive(Default)]
pub struct SpectatorVotes {
tally: [u16; SPECTATOR_EVENTS.len()],
open_for: f32,
cooldown: f32,
}
impl SpectatorVotes {
pub fn cast(&mut self, event: u8) {
let Some(at) = SPECTATOR_EVENTS
.iter()
.position(|e| e.index() == usize::from(event))
else {
return; };
if self.cooldown > 0.0 {
return;
}
if self.open_for <= 0.0 {
self.tally = [0; SPECTATOR_EVENTS.len()];
self.open_for = WINDOW;
}
self.tally[at] = self.tally[at].saturating_add(1);
}
pub fn settle(&mut self, seconds: f32) -> Option<TideEvent> {
self.cooldown = (self.cooldown - seconds).max(0.0);
if self.open_for <= 0.0 {
return None;
}
self.open_for -= seconds;
if self.open_for > 0.0 {
return None;
}
self.open_for = 0.0;
self.cooldown = COOLDOWN;
let (at, votes) = self
.tally
.iter()
.enumerate()
.max_by_key(|(at, votes)| (**votes, std::cmp::Reverse(*at)))?;
(*votes > 0).then(|| SPECTATOR_EVENTS[at])
}
pub fn forget_open(&mut self) {
self.open_for = 0.0;
self.tally = [0; SPECTATOR_EVENTS.len()];
}
pub fn forget_all(&mut self) {
*self = SpectatorVotes::default();
}
pub fn open(&self) -> Option<f32> {
(self.open_for > 0.0).then_some(self.open_for)
}
pub fn waiting(&self) -> Option<f32> {
(self.cooldown > 0.0).then_some(self.cooldown)
}
}
#[derive(Component)]
pub struct SpectatorCardUi;
#[derive(Resource, Default)]
pub struct SpectatorCard(pub bool);
pub fn spectator_vote_input(
mut card: ListCard<SpectatorCardUi, SpectatorCard>,
keyboard: crate::app::keycaps::KeyboardMut,
settings: Res<crate::app::settings::GameSettings>,
watching: Watching<PickCard>,
mut online: ResMut<Online>,
) {
let crate::app::keycaps::KeyboardMut { mut keys, caps } = keyboard;
if !is_spectating(&online) || !watching.free() {
if card.is_up() {
card.shut();
}
return;
}
if !card.is_up() {
if caps.just_pressed(&keys, 'E') && !watching.other_up() {
spawn_card(card.raise(), &settings);
}
return;
}
if keys.just_pressed(KeyCode::Escape) || caps.just_pressed(&keys, 'E') {
card.shut();
crate::app::menu_ui::spend(&mut keys, &[KeyCode::Escape]);
return;
}
if let Some(at) = crate::app::menu_ui::number_pressed(&keys, SPECTATOR_EVENTS.len()) {
if let Some(session) = &mut online.0 {
session.transport.send(NetMsg::SpectatorVote {
event: SPECTATOR_EVENTS[at].index() as u8,
});
}
card.shut();
}
}
pub(crate) fn spawn_card(commands: &mut Commands, settings: &crate::app::settings::GameSettings) {
let tr = settings.tr();
let rows = SPECTATOR_EVENTS.into_iter().enumerate().map(|(at, event)| {
(
format!("{} {}", at + 1, tr.events[event.index()]),
crate::app::palette::PARCHMENT,
)
});
spawn_list_card(commands, SpectatorCardUi, tr.spectator_call_title, rows);
}