summaryrefslogtreecommitdiff
path: root/server/src/entity/campaign.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-09-02 14:17:55 +0200
committermetamuffin <metamuffin@disroot.org>2024-09-02 14:18:02 +0200
commit2c2052cf38757e3c77e1e7a6af18af3eb9f3a2eb (patch)
treef985f1ca2e294aada0cc95ef6761a70ff1fbf20d /server/src/entity/campaign.rs
parente9e1692fb34b661e7c928c9b4b440dcb655eb062 (diff)
downloadhurrycurry-2c2052cf38757e3c77e1e7a6af18af3eb9f3a2eb.tar
hurrycurry-2c2052cf38757e3c77e1e7a6af18af3eb9f3a2eb.tar.bz2
hurrycurry-2c2052cf38757e3c77e1e7a6af18af3eb9f3a2eb.tar.zst
campaign gate entity
Diffstat (limited to 'server/src/entity/campaign.rs')
-rw-r--r--server/src/entity/campaign.rs87
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}")
+ }
+ }
+ }
+}