use crate::{ data::Gamedata, game::{Involvement, Item, Player, Tile}, protocol::{ItemIndex, TileIndex}, }; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Recipe { Passive { duration: f32, tile: Option, input: ItemIndex, output: Option, }, Active { duration: f32, tile: Option, input: ItemIndex, outputs: [Option; 2], }, Instant { tile: Option, inputs: [Option; 2], outputs: [Option; 2], }, } impl Recipe { pub fn tile(&self) -> Option { match self { Recipe::Passive { tile, .. } => *tile, Recipe::Active { tile, .. } => *tile, Recipe::Instant { tile, .. } => *tile, } } pub fn duration(&self) -> Option { match self { Recipe::Passive { duration, .. } => Some(*duration), Recipe::Active { duration, .. } => Some(*duration), _ => None, } } pub fn supports_tile(&self, tile: TileIndex) -> bool { if let Some(tile_constraint) = self.tile() { if tile != tile_constraint { false } else { true } } else { true } } } pub enum InteractEffect { Put, Take, Produce, } pub fn interact( data: &Gamedata, edge: bool, tile: &mut Tile, player: &mut Player, ) -> Option { if !edge { return None; } for recipe in &data.recipes { if !recipe.supports_tile(tile.kind) { continue; } match recipe { Recipe::Instant { inputs, outputs, .. } => { let on_tile = tile.item.as_ref().map(|i| i.kind); let in_hand = player.item.as_ref().map(|i| i.kind); let ok = (inputs[0] == on_tile && inputs[1] == in_hand) || (inputs[1] == on_tile && inputs[0] == in_hand); if ok { player.item = outputs[0].map(|kind| Item { kind, active: None }); tile.item = outputs[1].map(|kind| Item { kind, active: None }); return Some(InteractEffect::Produce); } } _ => (), } } if tile.item.is_none() { if let Some(item) = player.item.take() { tile.item = Some(item); return Some(InteractEffect::Put); } } if player.item.is_none() { if let Some(item) = tile.item.take() { player.item = Some(item); return Some(InteractEffect::Take); } } None } pub enum TickEffect { Progress, Produce, } pub fn tick_tile(dt: f32, data: &Gamedata, tile: &mut Tile) -> Option { if let Some(item) = &mut tile.item { if let Some(a) = &mut item.active { let r = &data.recipes[a.recipe]; if r.supports_tile(tile.kind) { a.progress += a.working as f32 * dt / r.duration().unwrap(); if a.progress >= 1. { let Recipe::Passive { output, .. } = &data.recipes[a.recipe] else { unreachable!() }; tile.item = output.map(|kind| Item { kind, active: None }); return Some(TickEffect::Produce); } return Some(TickEffect::Progress); } } else { for (ri, recipe) in data.recipes.iter().enumerate() { if let Some(tile_constraint) = recipe.tile() { if tile.kind != tile_constraint { continue; } } if let Recipe::Passive { input, .. } = recipe { if *input == item.kind { item.active = Some(Involvement { recipe: ri, progress: 0., working: 1, }) } } } return Some(TickEffect::Progress); } } None }