diff options
| author | metamuffin <metamuffin@disroot.org> | 2025-10-15 16:30:20 +0200 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2025-10-15 16:30:20 +0200 |
| commit | a47a61ec1ffb0d597783870a053cbe0760544301 (patch) | |
| tree | d2516f94445eb1f27614bf5618cbc5e4298eee7b /server | |
| parent | f9be1a87bbdfdfbeb316cc335b7a2dbbf42b06f2 (diff) | |
| download | hurrycurry-a47a61ec1ffb0d597783870a053cbe0760544301.tar hurrycurry-a47a61ec1ffb0d597783870a053cbe0760544301.tar.bz2 hurrycurry-a47a61ec1ffb0d597783870a053cbe0760544301.tar.zst | |
Add tag minigame (hidden map + entity)
Diffstat (limited to 'server')
| -rw-r--r-- | server/data/src/entities.rs | 4 | ||||
| -rw-r--r-- | server/data/src/lib.rs | 10 | ||||
| -rw-r--r-- | server/data/src/registry.rs | 6 | ||||
| -rw-r--r-- | server/src/entity/mod.rs | 7 | ||||
| -rw-r--r-- | server/src/entity/tag_minigame.rs | 96 |
5 files changed, 119 insertions, 4 deletions
diff --git a/server/data/src/entities.rs b/server/data/src/entities.rs index 04d4e1c5..fdd451a0 100644 --- a/server/data/src/entities.rs +++ b/server/data/src/entities.rs @@ -70,6 +70,10 @@ pub enum EntityDecl { speed: Option<f32>, points: Vec<Vec2>, }, + TagMinigame { + #[serde(default = "default_item")] + tag_item: ItemIndex, + }, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/server/data/src/lib.rs b/server/data/src/lib.rs index 78ec21b3..445e59b9 100644 --- a/server/data/src/lib.rs +++ b/server/data/src/lib.rs @@ -214,8 +214,14 @@ fn build_data( } for mut e in map_in.entities.clone() { - if let EntityDecl::Customers { unknown_order, .. } = &mut e { - *unknown_order = reg.register_item("unknown-order".to_owned()) + match &mut e { + EntityDecl::Customers { unknown_order, .. } => { + *unknown_order = reg.register_item("unknown-order".to_owned()) + } + EntityDecl::TagMinigame { tag_item } => { + *tag_item = reg.register_item("lettuce".to_owned()) + } + _ => (), } entities.push(e); } diff --git a/server/data/src/registry.rs b/server/data/src/registry.rs index e7dc7f77..9d513c90 100644 --- a/server/data/src/registry.rs +++ b/server/data/src/registry.rs @@ -80,8 +80,12 @@ pub(crate) fn filter_unused_tiles_and_items(data: &mut Gamedata, serverdata: &mu } for e in &serverdata.entity_decls { match e { - EntityDecl::Gate { blocker_tile: blocker, .. } => used_tiles.insert(*blocker), + EntityDecl::Gate { + blocker_tile: blocker, + .. + } => used_tiles.insert(*blocker), EntityDecl::Customers { unknown_order, .. } => used_items.insert(*unknown_order), + EntityDecl::TagMinigame { tag_item, .. } => used_items.insert(*tag_item), _ => false, }; } diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs index 6418d0c7..01cb9462 100644 --- a/server/src/entity/mod.rs +++ b/server/src/entity/mod.rs @@ -24,10 +24,14 @@ pub mod environment_effect; pub mod item_portal; pub mod pedestrians; pub mod player_portal; +pub mod tag_minigame; pub mod tram; pub mod tutorial; -use crate::{entity::pedestrians::Pedestrians, scoreboard::ScoreboardStore}; +use crate::{ + entity::{pedestrians::Pedestrians, tag_minigame::TagMinigame}, + scoreboard::ScoreboardStore, +}; use anyhow::Result; use book::Book; use campaign::{Gate, Map}; @@ -82,6 +86,7 @@ pub trait Entity: Any { pub fn construct_entity(decl: &EntityDecl) -> DynEntity { match decl.to_owned() { + EntityDecl::TagMinigame { tag_item } => Box::new(TagMinigame::new(tag_item)), EntityDecl::Book { pos } => Box::new(Book(pos)), EntityDecl::ItemPortal { from, to } => Box::new(ItemPortal { from, to }), EntityDecl::PlayerPortal { from, to } => Box::new(PlayerPortal { from, to }), diff --git a/server/src/entity/tag_minigame.rs b/server/src/entity/tag_minigame.rs new file mode 100644 index 00000000..02c3726f --- /dev/null +++ b/server/src/entity/tag_minigame.rs @@ -0,0 +1,96 @@ +/* + Hurry Curry! - a game about cooking + Copyright (C) 2025 Hurry Curry! Contributors + + 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 <https://www.gnu.org/licenses/>. + +*/ +use super::{Entity, EntityContext}; +use anyhow::Result; +use hurrycurry_client_lib::Item; +use hurrycurry_protocol::{Hand, ItemIndex, ItemLocation, Message, PacketC, PlayerID}; +use std::{collections::HashMap, fmt::Write}; + +#[derive(Debug, Clone)] +pub struct TagMinigame { + scores: HashMap<PlayerID, f32>, + report_cooldown: f32, + init_done: bool, + tag_item: ItemIndex, +} +impl TagMinigame { + pub fn new(tag_item: ItemIndex) -> Self { + Self { + init_done: false, + report_cooldown: 0., + scores: HashMap::new(), + tag_item, + } + } +} +impl Entity for TagMinigame { + fn tick(&mut self, c: EntityContext) -> Result<()> { + if !self.init_done { + self.init_done = true; + // Hand out item every but one player (not random yet) + for (id, player) in c.game.players.iter_mut().skip(1) { + if let Some(slot) = player.items.get_mut(0) { + *slot = Some(Item { + active: None, + kind: self.tag_item, + }); + c.packet_out.push_back(PacketC::SetItem { + location: ItemLocation::Player(*id, Hand(0)), + item: Some(self.tag_item), + }); + } + } + } + + // Award points to players with the item + for (&id, player) in &c.game.players { + if let Some(slot) = player.items.get(0) + && let Some(item) = slot + && item.kind == self.tag_item + { + *self.scores.entry(id).or_default() += c.dt + } + } + + // Send out a scoreboard message every 0.1s + self.report_cooldown -= c.dt; + if self.report_cooldown < 0. { + self.report_cooldown = 0.1; + let mut scores = self + .scores + .iter() + .map(|(x, y)| ((y * 10.) as i64, *x)) + .collect::<Vec<_>>(); + scores.sort_by_key(|(s, _)| -s); + + let mut o = String::new(); + writeln!(o, "Tag Minigame — Try to not have your lettuce stolen!").unwrap(); + for ((score, player), rank) in scores.into_iter().zip(1..) { + let name = c.game.players.get(&player).map_or("unknown", |p| &p.name); + writeln!(o, "{rank:>2} {score:>4} {name}").unwrap(); + } + o.pop(); // newline + c.packet_out.push_back(PacketC::ServerMessage { + error: false, + message: Message::Text(o), + }); + } + + Ok(()) + } +} |