/* Hurry Curry! - a game about cooking Copyright 2024 metamuffin This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ use super::{Entity, EntityContext}; use crate::{message::TrError, scoreboard::ScoreboardStore, server::GameServerExt, trm}; use anyhow::Result; use hurrycurry_protocol::{ glam::{IVec2, Vec2}, Message, PacketC, PlayerID, TileIndex, }; use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Clone)] pub struct Map { pub location: Vec2, pub name: String, } impl Entity for Map { fn tick(&mut self, c: EntityContext) -> Result<()> { let mut activate = false; c.game .players_spatial_index .query(self.location, 0.5, |_, _| activate = true); if activate { *c.load_map = Some(self.name.clone()); } Ok(()) } } #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] pub enum GateCondition { All(Vec), Any(Vec), 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, _player: PlayerID, ) -> Result { if !self.unlocked && pos == Some(self.location) { c.packet_out.push_back(PacketC::ServerMessage { message: trm!( "s.campaign.unlock_condition", m = self.condition.show(c.scoreboard) // TODO localize ), error: false, }); 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) -> Message { match self { GateCondition::All(cs) => cs .iter() .map(|c| c.show(scoreboard)) .reduce(|a, b| trm!("s.campaign.list_helper", m = a, m = b)) .unwrap_or(Message::Text(String::new())), GateCondition::Any(cs) => cs .iter() .map(|c| c.show(scoreboard)) .reduce(|a, b| trm!("s.campaign.list_helper", m = a, m = b)) .unwrap_or(Message::Text(String::new())), GateCondition::Stars(map, thres) => { trm!( "s.campaign.condition.stars", s = thres.to_string(), s = map.to_string() ) } } } }