/*
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 .
*/
pub mod book;
pub mod bot;
pub mod campaign;
pub mod conveyor;
pub mod customers;
pub mod environment_effect;
pub mod item_portal;
pub mod pedestrians;
pub mod player_portal;
pub mod tram;
pub mod tutorial;
use crate::{entity::pedestrians::Pedestrians, scoreboard::ScoreboardStore};
use anyhow::Result;
use book::Book;
use campaign::{Gate, Map};
use conveyor::Conveyor;
use customers::Customers;
use environment_effect::{EnvironmentController, EnvironmentEffectController};
use hurrycurry_client_lib::Game;
use hurrycurry_data::{entities::EntityDecl, Serverdata};
use hurrycurry_locale::TrError;
use hurrycurry_protocol::{glam::IVec2, Character, Gamedata, PacketC, PacketS, PlayerID};
use item_portal::ItemPortal;
use player_portal::PlayerPortal;
use std::{
any::Any,
collections::{HashMap, VecDeque},
};
use tram::Tram;
pub type DynEntity = Box;
pub type Entities = Vec;
pub struct EntityContext<'a> {
pub game: &'a mut Game,
pub serverdata: &'a Serverdata,
pub packet_out: &'a mut VecDeque,
pub packet_in: &'a mut VecDeque,
pub score_changed: &'a mut bool,
pub load_map: &'a mut Option,
pub scoreboard: &'a ScoreboardStore,
pub replies: Option<&'a mut Vec>,
pub dt: f32,
}
pub trait Entity: Any {
fn tick(&mut self, _c: EntityContext<'_>) -> Result<()> {
Ok(())
}
fn finished(&self) -> bool {
false
}
fn constructor(&mut self, _c: EntityContext<'_>) {}
fn destructor(&mut self, _c: EntityContext<'_>) {}
fn interact(
&mut self,
_c: EntityContext<'_>,
_pos: Option,
_player: PlayerID,
) -> Result {
Ok(false)
}
}
pub fn construct_entity(decl: &EntityDecl, data: &Gamedata) -> DynEntity {
match decl.to_owned() {
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 }),
EntityDecl::Conveyor { from, to, speed } => Box::new(Conveyor {
from,
to,
max_cooldown: 1. / speed.unwrap_or(2.),
cooldown: 0.,
}),
EntityDecl::Map { name, pos } => Box::new(Map { pos, name }),
EntityDecl::Gate { condition, pos } => Box::new(Gate {
condition,
unlocked: false,
pos,
blocker_tile: data
.get_tile_by_name("fence")
.expect("asserted earlier (tm)"),
active: true,
}),
EntityDecl::Customers { scaling_factor } => {
Box::new(Customers::new(scaling_factor.unwrap_or(0.5)))
}
EntityDecl::EnvironmentEffect(config) => Box::new(EnvironmentEffectController::new(config)),
EntityDecl::Environment(names) => Box::new(EnvironmentController(names)),
EntityDecl::Tram {
length,
color,
points,
smoothing,
spacing,
} => Box::new(Tram {
length,
character: Character {
color: color.unwrap_or_default(),
hairstyle: 0,
headwear: 0,
},
ids: Vec::new(),
points,
progress: 0.,
spacing,
smoothing,
}),
EntityDecl::Pedestrians {
spawn_delay,
spawn_delay_stdev,
points,
speed,
} => Box::new(Pedestrians {
players: HashMap::new(),
points,
spawn_delay_distr: rand_distr::Normal::new(
spawn_delay,
spawn_delay_stdev.unwrap_or(0.),
)
.unwrap(),
cooldown: 0.,
speed: speed.unwrap_or(0.6),
}),
}
}