aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-12-16 01:07:41 +0100
committermetamuffin <metamuffin@disroot.org>2025-12-16 01:07:41 +0100
commite2efb15aa58477d898f92c8959242c0da3ce62bc (patch)
treedbea74993c73c2f3f43fcf771c01dbd8d2607c5d
parent48d7482ded28ce9d3d4ff52517b48665ff1b8ebd (diff)
downloadhurrycurry-e2efb15aa58477d898f92c8959242c0da3ce62bc.tar
hurrycurry-e2efb15aa58477d898f92c8959242c0da3ce62bc.tar.bz2
hurrycurry-e2efb15aa58477d898f92c8959242c0da3ce62bc.tar.zst
Add player portal pair entity; fix tile/item remapping
-rw-r--r--data/maps/debug2.yaml21
-rw-r--r--server/data/src/entities.rs8
-rw-r--r--server/data/src/lib.rs7
-rw-r--r--server/data/src/registry.rs31
-rw-r--r--server/src/entity/mod.rs12
-rw-r--r--server/src/entity/player_portal_pair.rs97
6 files changed, 161 insertions, 15 deletions
diff --git a/data/maps/debug2.yaml b/data/maps/debug2.yaml
index b4a578da..fb5ca879 100644
--- a/data/maps/debug2.yaml
+++ b/data/maps/debug2.yaml
@@ -51,15 +51,16 @@ tiles:
"D": house-door -c
entities:
+ - !player_portal_pair { a: [5, 8], b: [10, 8] }
- !environment_effect { name: rain, on: 60, off: 40 }
- !environment_effect { name: wind, on: 60, off: 40 }
- - !tram
- length: 4
- character: 52
- points: [[5, 5], [23, 3], [23, 15], [3, 15]]
- smoothing: 3.
- spacing: 0.3625
- - !pedestrians
- points: [[7, 7], [19, 7], [19, 13], [7, 13]]
- spawn_delay: 0.5
- spawn_delay_stdev: 1
+ # - !tram
+ # length: 4
+ # character: 52
+ # points: [[5, 5], [23, 3], [23, 15], [3, 15]]
+ # smoothing: 3.
+ # spacing: 0.3625
+ # - !pedestrians
+ # points: [[7, 7], [19, 7], [19, 13], [7, 13]]
+ # spawn_delay: 0.5
+ # spawn_delay_stdev: 1
diff --git a/server/data/src/entities.rs b/server/data/src/entities.rs
index 1b0d4548..62947b05 100644
--- a/server/data/src/entities.rs
+++ b/server/data/src/entities.rs
@@ -38,6 +38,14 @@ pub enum EntityDecl {
from: Vec2,
to: Vec2,
},
+ PlayerPortalPair {
+ a: IVec2,
+ b: IVec2,
+ #[serde(default = "default_tile")]
+ in_tile: TileIndex,
+ #[serde(default = "default_tile")]
+ out_tile: TileIndex,
+ },
Customers {
scaling_factor: Option<f32>,
spawn_cooldown: Option<f32>,
diff --git a/server/data/src/lib.rs b/server/data/src/lib.rs
index a677bffd..d06aadd1 100644
--- a/server/data/src/lib.rs
+++ b/server/data/src/lib.rs
@@ -224,6 +224,13 @@ fn build_data(
*blocker_tile = reg.register_tile("conveyor".to_owned());
exclusive_tiles.entry(*blocker_tile).or_default();
}
+ EntityDecl::PlayerPortalPair {
+ in_tile, out_tile, ..
+ } => {
+ *in_tile = reg.register_tile("black-hole".to_owned());
+ *out_tile = reg.register_tile("white-hole".to_owned());
+ tile_walkable.extend([*in_tile, *out_tile]);
+ }
_ => (),
}
entities.push(e);
diff --git a/server/data/src/registry.rs b/server/data/src/registry.rs
index 6c92ecb5..372df653 100644
--- a/server/data/src/registry.rs
+++ b/server/data/src/registry.rs
@@ -83,16 +83,19 @@ pub(crate) fn filter_unused_tiles_and_items(data: &mut Gamedata, serverdata: &mu
EntityDecl::Gate {
blocker_tile: blocker,
..
- } => used_tiles.insert(*blocker),
- EntityDecl::Customers { unknown_order, .. } => used_items.insert(*unknown_order),
+ } => used_tiles.extend([*blocker]),
+ EntityDecl::Customers { unknown_order, .. } => used_items.extend([*unknown_order]),
EntityDecl::TagMinigame {
tag_item,
blocker_tile,
} => {
used_items.insert(*tag_item);
- used_tiles.insert(*blocker_tile)
+ used_tiles.insert(*blocker_tile);
}
- _ => false,
+ EntityDecl::PlayerPortalPair {
+ in_tile, out_tile, ..
+ } => used_tiles.extend([*in_tile, *out_tile]),
+ _ => (),
};
}
@@ -182,6 +185,26 @@ pub(crate) fn filter_unused_tiles_and_items(data: &mut Gamedata, serverdata: &mu
*item = item_map[item]
}
}
+ for e in &mut serverdata.entity_decls {
+ match e {
+ EntityDecl::Gate { blocker_tile, .. } => *blocker_tile = tile_map[blocker_tile],
+ EntityDecl::Customers { unknown_order, .. } => *unknown_order = item_map[unknown_order],
+ EntityDecl::TagMinigame {
+ tag_item,
+ blocker_tile,
+ } => {
+ *tag_item = item_map[tag_item];
+ *blocker_tile = tile_map[blocker_tile];
+ }
+ EntityDecl::PlayerPortalPair {
+ in_tile, out_tile, ..
+ } => {
+ *in_tile = tile_map[in_tile];
+ *out_tile = tile_map[out_tile];
+ }
+ _ => (),
+ };
+ }
data.tile_walkable = data
.tile_walkable
.clone()
diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs
index 6e1a618c..ee8a1a74 100644
--- a/server/src/entity/mod.rs
+++ b/server/src/entity/mod.rs
@@ -25,12 +25,16 @@ mod environment_effect;
mod item_portal;
mod pedestrians;
mod player_portal;
+pub mod player_portal_pair;
mod tag_minigame;
mod tram;
pub mod tutorial;
use crate::{
- entity::{demand_sink::DemandSink, pedestrians::Pedestrians, tag_minigame::TagMinigame},
+ entity::{
+ demand_sink::DemandSink, pedestrians::Pedestrians, player_portal_pair::PlayerPortalPair,
+ tag_minigame::TagMinigame,
+ },
scoreboard::ScoreboardStore,
};
use anyhow::Result;
@@ -170,5 +174,11 @@ pub fn construct_entity(decl: &EntityDecl) -> DynEntity {
speed: speed.unwrap_or(0.6),
}),
EntityDecl::DemandSink { pos } => Box::new(DemandSink { pos }),
+ EntityDecl::PlayerPortalPair {
+ a,
+ b,
+ in_tile,
+ out_tile,
+ } => Box::new(PlayerPortalPair::new(a, b, in_tile, out_tile)),
}
}
diff --git a/server/src/entity/player_portal_pair.rs b/server/src/entity/player_portal_pair.rs
new file mode 100644
index 00000000..b73f5891
--- /dev/null
+++ b/server/src/entity/player_portal_pair.rs
@@ -0,0 +1,97 @@
+/*
+ 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_locale::TrError;
+use hurrycurry_protocol::{
+ PacketC, TileIndex,
+ glam::{IVec2, Vec2, vec2},
+};
+
+#[derive(Debug, Clone)]
+pub struct PlayerPortalPair {
+ a_i: IVec2,
+ b_i: IVec2,
+ a_f: Vec2,
+ b_f: Vec2,
+ in_tile: TileIndex,
+ out_tile: TileIndex,
+ a_out: bool,
+ b_out: bool,
+}
+impl PlayerPortalPair {
+ pub fn new(a: IVec2, b: IVec2, in_tile: TileIndex, out_tile: TileIndex) -> Self {
+ Self {
+ a_i: a,
+ b_i: b,
+ a_f: a.as_vec2() + vec2(0.5, 0.5),
+ b_f: b.as_vec2() + vec2(0.5, 0.5),
+ in_tile,
+ out_tile,
+ a_out: true,
+ b_out: true,
+ }
+ }
+}
+impl Entity for PlayerPortalPair {
+ fn tick(&mut self, c: EntityContext) -> Result<(), TrError> {
+ let qn = |p, r| {
+ let mut o = None;
+ c.game
+ .players_spatial_index
+ .query(p, r, |pid, _| o = Some(pid));
+ o
+ };
+
+ if self.a_out && qn(self.a_f, 1.5).is_none() {
+ c.game.set_tile(self.a_i, Some(self.in_tile));
+ self.a_out = false;
+ return Ok(());
+ }
+
+ if self.b_out && qn(self.b_f, 1.5).is_none() {
+ c.game.set_tile(self.b_i, Some(self.in_tile));
+ self.b_out = false;
+ return Ok(());
+ }
+
+ if !self.a_out
+ && let Some(player) = qn(self.a_f, 0.5)
+ && let Some(p) = c.game.players.get_mut(&player)
+ {
+ p.movement.position = self.b_f;
+ c.packet_out.push_back(PacketC::MovementSync { player });
+ c.game.set_tile(self.b_i, Some(self.out_tile));
+ self.b_out = true;
+ return Ok(());
+ }
+
+ if !self.b_out
+ && let Some(player) = qn(self.b_f, 0.5)
+ && let Some(p) = c.game.players.get_mut(&player)
+ {
+ p.movement.position = self.a_f;
+ c.packet_out.push_back(PacketC::MovementSync { player });
+ c.game.set_tile(self.a_i, Some(self.out_tile));
+ self.a_out = true;
+ return Ok(());
+ }
+
+ Ok(())
+ }
+}