diff options
Diffstat (limited to 'server/src/entity/campaign.rs')
-rw-r--r-- | server/src/entity/campaign.rs | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/server/src/entity/campaign.rs b/server/src/entity/campaign.rs index c4c8ab52..934f7542 100644 --- a/server/src/entity/campaign.rs +++ b/server/src/entity/campaign.rs @@ -16,8 +16,14 @@ */ use super::{Entity, EntityContext}; +use crate::{scoreboard::ScoreboardStore, server::GameServerExt}; use anyhow::Result; -use hurrycurry_protocol::glam::Vec2; +use hurrycurry_protocol::{ + glam::{IVec2, Vec2}, + PacketC, PlayerID, TileIndex, +}; +use serde::{Deserialize, Serialize}; +use std::fmt::Write; #[derive(Debug, Default, Clone)] pub struct Map { @@ -39,3 +45,82 @@ impl Entity for Map { Ok(()) } } + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum GateCondition { + All(Vec<GateCondition>), + Any(Vec<GateCondition>), + Stars(String, u8), +} + +#[derive(Debug, Clone)] +pub struct Gate { + pub active: bool, + pub unlocked: bool, + pub location: IVec2, + pub blocker_tile: TileIndex, + pub condition: GateCondition, +} +impl Entity for Gate { + fn tick(&mut self, c: EntityContext<'_>) -> Result<()> { + if self.active { + self.active = false; + self.unlocked = self.condition.check(c.scoreboard); + if !self.unlocked { + c.game + .set_tile(self.location, Some(self.blocker_tile), c.packet_out) + } + } + Ok(()) + } + fn interact( + &mut self, + c: EntityContext<'_>, + pos: Option<IVec2>, + _player: PlayerID, + ) -> Result<bool> { + if !self.unlocked && pos == Some(self.location) { + c.packet_out.push_back(PacketC::ServerMessage { + text: format!("To unlock: \n\n{}", self.condition.show(c.scoreboard)), + }); + return Ok(true); + } + Ok(false) + } +} + +impl GateCondition { + fn check(&self, scoreboard: &ScoreboardStore) -> bool { + match self { + GateCondition::All(cs) => cs.iter().all(|c| c.check(scoreboard)), + GateCondition::Any(cs) => cs.iter().any(|c| c.check(scoreboard)), + GateCondition::Stars(map, thres) => scoreboard.get(map).map_or(false, |s| { + s.best.first().map_or(false, |b| b.score.stars >= *thres) + }), + } + } + pub fn show(&self, scoreboard: &ScoreboardStore) -> String { + match self { + GateCondition::All(cs) => { + let mut o = String::new(); + for c in cs { + if !c.check(scoreboard) { + writeln!(o, "- {}", c.show(scoreboard)).unwrap(); + } + } + o + } + GateCondition::Any(cs) => { + let mut o = String::new(); + for c in cs { + writeln!(o, "- {}", c.show(scoreboard)).unwrap(); + } + o + } + GateCondition::Stars(map, thres) => { + format!("Reach at least {thres} stars in {map}") + } + } + } +} |