/*
Hurry Curry! - 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 .
*/
pub mod bot;
pub mod campaign;
pub mod conveyor;
pub mod customers;
pub mod environment_effect;
pub mod item_portal;
pub mod player_portal;
use crate::{data::ItemTileRegistry, scoreboard::ScoreboardStore};
use anyhow::{anyhow, Result};
use campaign::{Gate, GateCondition, Map};
use conveyor::Conveyor;
use customers::Customers;
use environment_effect::{EnvironmentController, EnvironmentEffect, EnvironmentEffectController};
use hurrycurry_client_lib::Game;
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
PacketC, PacketS, PlayerID,
};
use item_portal::ItemPortal;
use player_portal::PlayerPortal;
use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
pub type DynEntity = Box;
pub type Entities = Vec;
pub struct EntityContext<'a> {
pub game: &'a mut Game,
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 dt: f32,
}
pub trait Entity {
fn tick(&mut self, c: EntityContext<'_>) -> Result<()>;
fn destructor(&mut self, _c: EntityContext<'_>) {}
fn interact(
&mut self,
_c: EntityContext<'_>,
_pos: Option,
_player: PlayerID,
) -> Result {
Ok(false)
}
}
// macro_rules! entities {
// ($($e:ident),*) => {
// pub enum DynEntity { $($e($e)),* }
// impl Entity for DynEntity {
// fn tick(&mut self, c: EntityContext<'_>) -> Result<()> {
// match self { $(DynEntity::$e(x) => x.tick(c)),*, }
// }
// fn destructor(&mut self, c: EntityContext<'_>) {
// match self { $(DynEntity::$e(x) => x.destructor(c)),*, }
// }
// }
// };
// }
// entities!(
// Conveyor,
// ItemPortal,
// PlayerPortal,
// Customers,
// EnvironmentEffectController,
// EnvironmentController
// );
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EntityDecl {
Conveyor {
from: Option,
to: Option,
filter_dir: Option,
filter: Option,
dir: Option,
speed: Option,
},
ItemPortal {
from: Option,
to: IVec2,
},
PlayerPortal {
from: Option,
to: Vec2,
},
Customers {},
Map {
name: String,
location: Option,
},
EnvironmentEffect(EnvironmentEffect),
Environment(Vec),
Gate {
location: Option,
condition: GateCondition,
},
}
pub fn construct_entity(
pos: Option,
decl: &EntityDecl,
reg: &ItemTileRegistry,
) -> Result {
Ok(match decl.to_owned() {
EntityDecl::ItemPortal { from, to } => Box::new(ItemPortal {
from: from
.or(pos)
.ok_or(anyhow!("Item portal start without start"))?,
to,
}),
EntityDecl::PlayerPortal { from, to } => Box::new(PlayerPortal {
from: from
.or(pos.map(|v| v.as_vec2()))
.ok_or(anyhow!("Player portal without start"))?,
to,
}),
EntityDecl::Conveyor {
from,
to,
speed,
dir,
filter,
filter_dir,
} => {
let from = from.or(pos).ok_or(anyhow!("Conveyor has no start"))?;
let to = to
.or(dir.map(|s| s + from))
.ok_or(anyhow!("Conveyor has no destination"))?;
Box::new(Conveyor {
from,
to,
max_cooldown: 1. / speed.unwrap_or(2.),
filter_tile: filter_dir.map(|o| to + o),
filter_item: filter.map(|name| reg.register_item(name)),
cooldown: 0.,
})
}
EntityDecl::Map { name, location } => Box::new(Map {
location: location
.or(pos.map(|p| p.as_vec2() + 0.5))
.ok_or(anyhow!("no location"))?,
name,
}),
EntityDecl::Gate {
condition,
location,
} => Box::new(Gate {
condition,
unlocked: false,
location: location.or(pos).ok_or(anyhow!("no location"))?,
blocker_tile: reg.register_tile("fence".to_string()),
active: true,
}),
EntityDecl::Customers {} => Box::new(Customers::new()?),
EntityDecl::EnvironmentEffect(config) => Box::new(EnvironmentEffectController::new(config)),
EntityDecl::Environment(names) => Box::new(EnvironmentController(names)),
})
}