aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-03-11 21:18:12 +0100
committermetamuffin <metamuffin@disroot.org>2026-03-11 21:18:36 +0100
commit4a9314f235bd3c556cec4f70177d8f7438d59559 (patch)
treed021352543a01d1eb325e202be7ee8b9c936eda4
parent93fbbf687de7e3b3b27e150c455cef2ac4d4c303 (diff)
downloadhurrycurry-4a9314f235bd3c556cec4f70177d8f7438d59559.tar
hurrycurry-4a9314f235bd3c556cec4f70177d8f7438d59559.tar.bz2
hurrycurry-4a9314f235bd3c556cec4f70177d8f7438d59559.tar.zst
buttons server-side code
-rw-r--r--data/maps/lobby.yaml8
-rw-r--r--data/palettes.yaml2
-rw-r--r--server/data/src/entities.rs15
-rw-r--r--server/data/src/lib.rs28
-rw-r--r--server/protocol/src/lib.rs1
-rw-r--r--server/src/entity/button.rs (renamed from server/src/entity/book.rs)23
-rw-r--r--server/src/entity/mod.rs6
7 files changed, 58 insertions, 25 deletions
diff --git a/data/maps/lobby.yaml b/data/maps/lobby.yaml
index 920d9efc..a573ce2a 100644
--- a/data/maps/lobby.yaml
+++ b/data/maps/lobby.yaml
@@ -47,7 +47,7 @@ tiles:
"h": floor counter rolling-board
"e": stove -i=pot
"f": stove -i=pan
- "x": floor counter book --book
+ "x": floor counter book --button=book
"o": oven
"a": counter -i=foodprocessor
"Z": freezer
@@ -56,9 +56,9 @@ tiles:
"i": counter deep-fryer -i=basket
"S": floor screen
- "b": floor button-base button:reject
- "j": floor button-base
- "d": floor button-base button:accept
+ "b": floor button-base button:reject --button=vote-no
+ "j": floor button-base --button=map-selector
+ "d": floor button-base button:accept --button=vote-yes
"0": floor crate:rice
"1": floor crate:steak
diff --git a/data/palettes.yaml b/data/palettes.yaml
index 2e2c63b0..c86039df 100644
--- a/data/palettes.yaml
+++ b/data/palettes.yaml
@@ -14,7 +14,7 @@ default:
"d": floor counter deep-fryer -i=basket
"r": floor counter rolling-board
"e": floor counter cutting-board
- "h": floor counter book --book
+ "h": floor counter book --button=book
"A": floor crate:steak
"B": floor crate:coconut
diff --git a/server/data/src/entities.rs b/server/data/src/entities.rs
index 5c874441..135e4b78 100644
--- a/server/data/src/entities.rs
+++ b/server/data/src/entities.rs
@@ -16,6 +16,7 @@
*/
+use clap::ValueEnum;
use hurrycurry_protocol::{
ItemIndex, TileIndex,
glam::{IVec2, Vec2},
@@ -72,8 +73,9 @@ pub enum EntityDecl {
spacing: f32,
smoothing: f32,
},
- Book {
+ Button {
pos: IVec2,
+ action: ButtonAction,
},
Pedestrians {
spawn_delay: f32,
@@ -98,8 +100,17 @@ pub enum EntityDecl {
},
}
+#[derive(Debug, Clone, Copy, Deserialize, Serialize, ValueEnum)]
+#[serde(rename_all = "snake_case")]
+pub enum ButtonAction {
+ Book,
+ VoteYes,
+ VoteNo,
+ MapSelector,
+}
+
#[derive(Debug, Clone, Deserialize, Serialize)]
-#[serde(rename_all = "kebab-case")]
+#[serde(rename_all = "snake_case")]
pub enum GateCondition {
All(Vec<GateCondition>),
Any(Vec<GateCondition>),
diff --git a/server/data/src/lib.rs b/server/data/src/lib.rs
index d09c3ca3..06233d1e 100644
--- a/server/data/src/lib.rs
+++ b/server/data/src/lib.rs
@@ -24,7 +24,7 @@ pub mod registry;
use crate::{
book::book,
- entities::EntityDecl,
+ entities::{ButtonAction, EntityDecl},
recipes::{RecipeDecl, load_recipes},
registry::{ItemTileRegistry, filter_unused_tiles_and_items},
};
@@ -71,8 +71,8 @@ fn default_recipes() -> String {
#[derive(Parser)]
struct TileArgs {
tiles: Vec<String>,
- #[clap(long)]
- book: bool,
+ #[clap(short, long)]
+ button: Option<ButtonAction>,
#[clap(long)]
chef_spawn: bool,
#[clap(long)]
@@ -146,6 +146,7 @@ pub fn build_gamedata(
let mut chef_spawn = None;
let mut customer_spawn = None;
let mut initial_map = HashMap::new();
+ let mut interactable_empty_extra = HashSet::new();
for (y, line) in map_in.map.iter().enumerate() {
for (x, char) in line.chars().enumerate() {
@@ -163,7 +164,10 @@ pub fn build_gamedata(
.iter()
.cloned()
.map(|t| reg.register_tile(t))
- .collect();
+ .collect::<Vec<_>>();
+ let Some(top) = tiles.last().copied() else {
+ continue;
+ };
let item = ts.item.clone().map(|i| reg.register_item(i));
initial_map.insert(pos, (tiles, item));
@@ -173,8 +177,9 @@ pub fn build_gamedata(
if ts.customer_spawn {
customer_spawn = Some(pos.as_vec2() + Vec2::splat(0.5));
}
- if ts.book {
- entities.push(EntityDecl::Book { pos });
+ if let Some(action) = ts.button {
+ interactable_empty_extra.insert(top);
+ entities.push(EntityDecl::Button { pos, action });
}
if ts.demand_sink {
entities.push(EntityDecl::DemandSink { pos });
@@ -194,7 +199,6 @@ pub fn build_gamedata(
}
let chef_spawn = chef_spawn.ok_or(anyhow!("map has no chef spawn"))?;
-
for mut e in map_in.entities.clone() {
match &mut e {
EntityDecl::Customers { unknown_order, .. } => {
@@ -249,6 +253,9 @@ pub fn build_gamedata(
),
tile_placeable_any: tiles_flagged(&tile_flags, &tiles, 'a'),
tile_interactable_empty: tiles_flagged(&tile_flags, &tiles, 'e')
+ .union(&interactable_empty_extra)
+ .copied()
+ .collect::<HashSet<_>>()
.union(&tile_interactable_empty_bc_recipe(&recipes))
.copied()
.collect(),
@@ -357,9 +364,10 @@ fn tiles_flagged(
for (i, tile) in tiles.iter().enumerate() {
let (kind, _params) = tile.split_once(":").unwrap_or((tile, ""));
if let Some(flags) = tile_flags.get(kind)
- && flags.contains(flag) {
- out.insert(TileIndex(i));
- }
+ && flags.contains(flag)
+ {
+ out.insert(TileIndex(i));
+ }
}
out
}
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index a276a29a..9dfcc4dd 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -321,6 +321,7 @@ pub enum Menu {
Score(Score),
Scoreboard(Scoreboard),
Book(Book),
+ MapSelector,
AnnounceStart,
}
diff --git a/server/src/entity/book.rs b/server/src/entity/button.rs
index e8456591..74726253 100644
--- a/server/src/entity/book.rs
+++ b/server/src/entity/button.rs
@@ -17,22 +17,35 @@
*/
use super::{Entity, EntityContext};
use anyhow::Result;
+use hurrycurry_data::entities::ButtonAction;
use hurrycurry_locale::TrError;
use hurrycurry_protocol::{ItemLocation, Menu, PacketC, PlayerID, glam::IVec2};
#[derive(Debug, Clone)]
-pub struct Book(pub IVec2);
+pub struct Button {
+ pub pos: IVec2,
+ pub action: ButtonAction,
+}
-impl Entity for Book {
+impl Entity for Button {
fn interact(
&mut self,
c: EntityContext<'_>,
pos: Option<ItemLocation>,
_player: PlayerID,
) -> Result<bool, TrError> {
- if pos == Some(ItemLocation::Tile(self.0)) {
- if let Some(r) = c.replies {
- r.push(PacketC::Menu(Menu::Book(c.serverdata.book.clone())));
+ if pos == Some(ItemLocation::Tile(self.pos)) {
+ match self.action {
+ ButtonAction::Book => {
+ c.replies
+ .unwrap()
+ .push(PacketC::Menu(Menu::Book(c.serverdata.book.clone())));
+ }
+ ButtonAction::VoteYes => {}
+ ButtonAction::VoteNo => {}
+ ButtonAction::MapSelector => {
+ c.replies.unwrap().push(PacketC::Menu(Menu::MapSelector));
+ }
}
return Ok(true);
}
diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs
index 8a78202b..604daf98 100644
--- a/server/src/entity/mod.rs
+++ b/server/src/entity/mod.rs
@@ -15,8 +15,8 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-mod book;
pub mod bot;
+mod button;
mod campaign;
mod conveyor;
mod ctf_minigame;
@@ -39,7 +39,7 @@ use crate::{
scoreboard::ScoreboardStore,
};
use anyhow::Result;
-use book::Book;
+use button::Button;
use campaign::{Gate, Map};
use conveyor::Conveyor;
use customers::Customers;
@@ -111,7 +111,7 @@ pub fn construct_entity(decl: &EntityDecl) -> DynEntity {
tag_item,
blocker_tile,
} => Box::new(TagMinigame::new(tag_item, blocker_tile)),
- EntityDecl::Book { pos } => Box::new(Book(pos)),
+ EntityDecl::Button { pos, action } => Box::new(Button { pos, action }),
EntityDecl::ItemPortal { from, to } => Box::new(ItemPortal { from, to }),
EntityDecl::PlayerPortal { from, to } => Box::new(PlayerPortal { from, to }),
EntityDecl::Conveyor { from, to, speed } => Box::new(Conveyor {