summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-06-29 16:10:07 +0200
committermetamuffin <metamuffin@disroot.org>2024-06-29 16:10:07 +0200
commit58f4ab0b26948bec13ba853c90298271e472169f (patch)
tree9fa6e4443addf067310ff9ba868ec72b9e237637
parentb0042dce860406431f2e486112b14987c665f6a8 (diff)
downloadhurrycurry-58f4ab0b26948bec13ba853c90298271e472169f.tar
hurrycurry-58f4ab0b26948bec13ba853c90298271e472169f.tar.bz2
hurrycurry-58f4ab0b26948bec13ba853c90298271e472169f.tar.zst
implement points
-rw-r--r--data/demands/default.yaml35
-rw-r--r--data/recipes/default.ts5
-rw-r--r--server/src/bin/graph.rs22
-rw-r--r--server/src/customer/mod.rs16
-rw-r--r--server/src/data.rs19
-rw-r--r--server/src/game.rs44
-rw-r--r--server/src/interaction.rs8
-rw-r--r--server/src/protocol.rs1
-rw-r--r--test-client/main.ts2
-rw-r--r--test-client/protocol.ts2
-rw-r--r--test-client/visual.ts8
11 files changed, 116 insertions, 46 deletions
diff --git a/data/demands/default.yaml b/data/demands/default.yaml
index f6be0911..26bbac09 100644
--- a/data/demands/default.yaml
+++ b/data/demands/default.yaml
@@ -1,26 +1,37 @@
# Undercooked - 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 <https://www.gnu.org/licenses/>.
-#
-- { from: bread-slice-plate, to: dirty-plate, duration: 10 }
-- { from: steak-plate, to: dirty-plate, duration: 10 }
-- { from: sliced-tomato-plate, to: dirty-plate, duration: 10 }
+#
+- { from: sliced-tomato-plate, to: dirty-plate, duration: 10, points: 2 }
+- { from: bread-slice-plate, to: dirty-plate, duration: 10, points: 3 }
+- { from: steak-plate, to: dirty-plate, duration: 10, points: 4 }
-- { from: bread-slice-steak-plate, to: dirty-plate, duration: 15 }
-- { from: bread-slice-sliced-tomato-plate, to: dirty-plate, duration: 15 }
-- { from: sliced-tomato-steak-plate, to: dirty-plate, duration: 15 }
+- { from: bread-slice-steak-plate, to: dirty-plate, duration: 15, points: 6 }
+- {
+ from: bread-slice-sliced-tomato-plate,
+ to: dirty-plate,
+ duration: 15,
+ points: 5,
+ }
+- { from: sliced-tomato-steak-plate, to: dirty-plate, duration: 15, points: 5 }
-- { from: bread-slice-sliced-tomato-steak-plate, to: dirty-plate, duration: 20 }
+- {
+ from: bread-slice-sliced-tomato-steak-plate,
+ to: dirty-plate,
+ duration: 20,
+ points: 10,
+ }
-- { from: tomato-soup-plate, to: dirty-plate, duration: 20 }
+- { from: tomato-soup-plate, to: dirty-plate, duration: 10, points: 5 }
+- { from: bread, duration: 0, points: 4 }
diff --git a/data/recipes/default.ts b/data/recipes/default.ts
index dd662081..db106e54 100644
--- a/data/recipes/default.ts
+++ b/data/recipes/default.ts
@@ -25,7 +25,8 @@ export interface Recipe {
action: "instant" | "passive" | "active" | "demand"
duration?: number
revert_duration?: number,
- warn?: boolean
+ warn?: boolean,
+ points?: number,
}
export const all_items = new Set<string>()
@@ -76,7 +77,7 @@ export function bake(from: string, to?: string) {
out({ action: "passive", duration: 15, revert_duration: 20, tile: "oven", inputs: [o], outputs: ["burned"], warn: true })
}
export function crate(item: string) {
- out({ action: "instant", tile: item + "-crate", inputs: [], outputs: [item], })
+ out({ action: "instant", tile: item + "-crate", inputs: [], outputs: [item], points: -1 })
}
export function get_container(ifull: string): [string, string | null] {
diff --git a/server/src/bin/graph.rs b/server/src/bin/graph.rs
index deae2034..024512c6 100644
--- a/server/src/bin/graph.rs
+++ b/server/src/bin/graph.rs
@@ -17,7 +17,7 @@
*/
use anyhow::{anyhow, Result};
use undercooked::{
- data::DataIndex,
+ data::{DataIndex, Demand},
interaction::Recipe,
protocol::{ItemIndex, RecipeIndex},
};
@@ -59,14 +59,24 @@ fn main() -> Result<()> {
}
}
- for (di, d) in data.demands.iter().enumerate() {
+ for (
+ di,
+ Demand {
+ duration,
+ from: ItemIndex(from),
+ to,
+ points,
+ },
+ ) in data.demands.iter().enumerate()
+ {
let color = "#c4422b";
println!(
- "d{di} [label=\"Demand\\ntakes {}s\" shape=box color={color:?} fillcolor={color:?} style=filled]",
- d.duration
+ "d{di} [label=\"Demand\\ntakes {duration}s\\n{points} points\" shape=box color={color:?} fillcolor={color:?} style=filled]",
);
- println!("i{} -> d{di}", d.from.0);
- println!("d{di} -> i{}", d.to.0);
+ println!("i{from} -> d{di}");
+ if let Some(ItemIndex(to)) = to {
+ println!("d{di} -> i{to}");
+ }
}
println!("}}");
diff --git a/server/src/customer/mod.rs b/server/src/customer/mod.rs
index 9e474b8f..d1f49655 100644
--- a/server/src/customer/mod.rs
+++ b/server/src/customer/mod.rs
@@ -104,6 +104,7 @@ impl DemandState {
tiles: &mut HashMap<IVec2, Tile>,
data: &Gamedata,
dt: f32,
+ points: &mut i64,
) -> Result<()> {
if self.customers.len() < 5 {
self.customer_id_counter.0 -= 1;
@@ -165,6 +166,7 @@ impl DemandState {
.expect("no path to exit");
*self.chairs.get_mut(&chair).unwrap() = true;
self.failed += 1;
+ *points -= 1;
self.score_changed = true;
p.state = CustomerState::Exiting { path }
} else {
@@ -212,14 +214,11 @@ impl DemandState {
let demand = data.demand(*demand);
*progress += dt / demand.duration;
if *progress >= 1. {
- packets_out.push((
- id,
- PacketS::ReplaceHand {
- item: Some(demand.to),
- },
- ));
- for edge in [true, false] {
- packets_out.push((id, PacketS::Interact { pos: *target, edge }))
+ packets_out.push((id, PacketS::ReplaceHand { item: demand.to }));
+ if demand.to.is_some() {
+ for edge in [true, false] {
+ packets_out.push((id, PacketS::Interact { pos: *target, edge }))
+ }
}
let path = find_path(
&self.walkable,
@@ -229,6 +228,7 @@ impl DemandState {
.ok_or(anyhow!("no path to exit"))?;
*self.chairs.get_mut(&chair).unwrap() = true;
self.completed += 1;
+ *points += demand.points;
self.score_changed = true;
p.state = CustomerState::Exiting { path }
}
diff --git a/server/src/data.rs b/server/src/data.rs
index 763a67bc..46f7ed28 100644
--- a/server/src/data.rs
+++ b/server/src/data.rs
@@ -56,6 +56,8 @@ pub struct RecipeDecl {
revert_duration: Option<f32>,
#[serde(default)]
duration: Option<f32>,
+ #[serde(default)]
+ points: Option<i64>,
}
#[derive(Debug, Clone, Deserialize)]
@@ -72,15 +74,17 @@ pub struct InitialMap {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DemandDecl {
from: String,
- to: String,
+ to: Option<String>,
duration: f32,
+ points: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Demand {
pub from: ItemIndex,
- pub to: ItemIndex,
+ pub to: Option<ItemIndex>,
pub duration: f32,
+ pub points: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
@@ -161,7 +165,7 @@ impl Gamedata {
let mut recipes = Vec::new();
let mut demands = Vec::new();
- for r in recipes_in {
+ for mut r in recipes_in {
let r2 = r.clone();
let mut inputs = r
.inputs
@@ -190,21 +194,24 @@ impl Gamedata {
}),
Action::Instant => {
recipes.push(Recipe::Instant {
+ points: r.points.take().unwrap_or(0),
tile,
inputs: [inputs.next(), inputs.next()],
outputs: [outputs.next(), outputs.next()],
});
}
}
- assert_eq!(inputs.next(), None, "{r2:?}");
- assert_eq!(outputs.next(), None, "{r2:?}");
+ assert_eq!(inputs.next(), None, "{r2:?} inputs left over");
+ assert_eq!(outputs.next(), None, "{r2:?} outputs left over");
+ assert_eq!(r.points, None, "points specified where not possible")
}
for d in demands_in {
demands.push(Demand {
from: ItemIndex(register(&item_names, d.from)),
- to: ItemIndex(register(&item_names, d.to)),
+ to: d.to.map(|to| ItemIndex(register(&item_names, to))),
duration: d.duration,
+ points: d.points,
})
}
diff --git a/server/src/game.rs b/server/src/game.rs
index 23900559..72f653c4 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -65,6 +65,7 @@ pub struct Game {
players: HashMap<PlayerID, Player>,
packet_out: VecDeque<PacketC>,
demand: Option<DemandState>,
+ points: i64,
}
impl Game {
@@ -75,11 +76,13 @@ impl Game {
players: Default::default(),
tiles: Default::default(),
demand: None,
+ points: 0,
}
}
fn unload(&mut self) {
- self.packet_out.push_back(PacketC::SetIngame { state: false });
+ self.packet_out
+ .push_back(PacketC::SetIngame { state: false });
for (id, _) in self.players.drain() {
self.packet_out.push_back(PacketC::RemovePlayer { id })
}
@@ -189,18 +192,22 @@ impl Game {
})
}
}
- out.push(PacketC::Score {
+ out.push(self.score());
+ out.push(PacketC::SetIngame { state: true });
+ out
+ }
+
+ pub fn score(&self) -> PacketC {
+ PacketC::Score {
+ points: self.points,
demands_failed: self.demand.as_ref().map(|d| d.failed).unwrap_or_default(),
demands_completed: self
.demand
.as_ref()
.map(|d| d.completed)
.unwrap_or_default(),
- });
- out.push(PacketC::SetIngame { state: true });
- out
+ }
}
-
pub fn packet_in(&mut self, player: PlayerID, packet: PacketS) -> Result<()> {
match packet {
PacketS::Join { name, character } => {
@@ -315,6 +322,7 @@ impl Game {
tile.kind,
&mut tile.item,
&mut player.item,
+ &mut self.points,
) {
match effect {
InteractEffect::Put => self.packet_out.push_back(PacketC::PutItem {
@@ -363,6 +371,21 @@ impl Game {
item: Some(i.kind),
});
}
+ self.packet_out.push_back({
+ PacketC::Score {
+ points: self.points,
+ demands_failed: self
+ .demand
+ .as_ref()
+ .map(|d| d.failed)
+ .unwrap_or_default(),
+ demands_completed: self
+ .demand
+ .as_ref()
+ .map(|d| d.completed)
+ .unwrap_or_default(),
+ }
+ })
}
}
}
@@ -396,11 +419,18 @@ impl Game {
pub fn tick(&mut self, dt: f32) {
if let Some(demand) = &mut self.demand {
let mut packet_out = Vec::new();
- if let Err(err) = demand.tick(&mut packet_out, &mut self.tiles, &self.data, dt) {
+ if let Err(err) = demand.tick(
+ &mut packet_out,
+ &mut self.tiles,
+ &self.data,
+ dt,
+ &mut self.points,
+ ) {
warn!("demand tick {err}");
}
if demand.score_changed {
self.packet_out.push_back(PacketC::Score {
+ points: self.points,
demands_failed: demand.failed,
demands_completed: demand.completed,
});
diff --git a/server/src/interaction.rs b/server/src/interaction.rs
index e3dccfba..69fc9e70 100644
--- a/server/src/interaction.rs
+++ b/server/src/interaction.rs
@@ -43,6 +43,7 @@ pub enum Recipe {
tile: Option<TileIndex>,
inputs: [Option<ItemIndex>; 2],
outputs: [Option<ItemIndex>; 2],
+ points: i64,
},
}
@@ -120,6 +121,7 @@ pub fn interact(
tile_kind: TileIndex,
this: &mut Option<Item>,
other: &mut Option<Item>,
+ points: &mut i64,
) -> Option<InteractEffect> {
let interactable = data.is_tile_interactable(tile_kind);
if interactable && other.is_none() {
@@ -188,7 +190,10 @@ pub fn interact(
}
}
Recipe::Instant {
- inputs, outputs, ..
+ inputs,
+ outputs,
+ points: pd,
+ ..
} => {
let on_tile = this.as_ref().map(|i| i.kind);
let in_hand = other.as_ref().map(|i| i.kind);
@@ -199,6 +204,7 @@ pub fn interact(
let ok_rev = ok_rev as usize;
*other = outputs[1 - ok_rev].map(|kind| Item { kind, active: None });
*this = outputs[ok_rev].map(|kind| Item { kind, active: None });
+ *points += pd;
return Some(InteractEffect::Produce);
}
}
diff --git a/server/src/protocol.rs b/server/src/protocol.rs
index 16c379b9..9355f90a 100644
--- a/server/src/protocol.rs
+++ b/server/src/protocol.rs
@@ -131,6 +131,7 @@ pub enum PacketC {
message: Option<Message>,
},
Score {
+ points: i64,
demands_failed: usize,
demands_completed: usize,
},
diff --git a/test-client/main.ts b/test-client/main.ts
index 4d1e9c53..72e88c90 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -99,6 +99,7 @@ export const items_removed = new Set<ItemData>()
export let data: Gamedata = { item_names: [], tile_names: [], spawn: [0, 0], tile_collide: [], tile_interact: [] }
export let my_id: PlayerID = -1
+export let points = 0
export let demands_completed = 0
export let demands_failed = 0
export const camera: V2 = { x: 0, y: 0 }
@@ -197,6 +198,7 @@ function packet(p: PacketC) {
case "score":
demands_completed = p.demands_completed
demands_failed = p.demands_failed
+ points = p.points
break;
case "error":
console.warn(p.message)
diff --git a/test-client/protocol.ts b/test-client/protocol.ts
index ba6a630c..28ed6d11 100644
--- a/test-client/protocol.ts
+++ b/test-client/protocol.ts
@@ -48,7 +48,7 @@ export type PacketC =
| { type: "set_active", tile: Vec2, progress?: number, warn: boolean } // A tile is doing something. progress goes from 0 to 1, then null when finished
| { type: "update_map", tile: Vec2, kind: TileIndex | null, neighbors: [TileIndex | null] } // A map tile was changed
| { type: "communicate", player: PlayerID, message?: Message } // A player wants to communicate something, message is null when cleared
- | { type: "score", demands_failed: number, demands_completed: number, } // Supplies information for score OSD
+ | { type: "score", points: number, demands_failed: number, demands_completed: number, } // Supplies information for score OSD
| { type: "set_ingame", state: boolean } // Set to false when entering the game or switching maps
| { type: "error", message?: Message } // Your client did something wrong.
diff --git a/test-client/visual.ts b/test-client/visual.ts
index 1b4363e8..19866710 100644
--- a/test-client/visual.ts
+++ b/test-client/visual.ts
@@ -15,7 +15,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import { ItemData, MessageData, PlayerData, TileData, camera, camera_scale, canvas, ctx, data, demands_completed, demands_failed, get_interact_target, interact_active_anim, interact_possible_anim, interact_target_anim, items_removed, keys_down, my_id, players, tiles } from "./main.ts";
+import { ItemData, MessageData, PlayerData, TileData, camera, camera_scale, canvas, ctx, data, demands_completed, demands_failed, get_interact_target, interact_active_anim, interact_possible_anim, interact_target_anim, items_removed, keys_down, my_id, players, points, tiles } from "./main.ts";
import { PLAYER_SIZE } from "./movement.ts";
import { FALLBACK_TILE, ITEMS, TILES, FALLBACK_ITEM } from "./tiles.ts";
import { V2, ceil_v2, floor_v2 } from "./util.ts";
@@ -77,9 +77,11 @@ export function draw_ingame() {
ctx.fillStyle = "white"
ctx.textAlign = "left"
ctx.textBaseline = "bottom"
+ ctx.font = "30px sans-serif"
+ ctx.fillText(`Points: ${points}`, 10, canvas.height - 60)
ctx.font = "20px sans-serif"
- ctx.fillText(`Completed: ${demands_completed}`, 10, canvas.height - 10)
- ctx.fillText(`Failed: ${demands_failed}`, 10, canvas.height - 30)
+ ctx.fillText(`Completed: ${demands_completed}`, 10, canvas.height - 30)
+ ctx.fillText(`Failed: ${demands_failed}`, 10, canvas.height - 10)
if (keys_down.has("KeyP")) {
draw_debug()