use crate::{ game::ActiveRecipe, protocol::{ItemIndex, TileIndex}, recipes::{Action, Gamedata}, }; use log::{debug, info}; use std::collections::BTreeSet; use Out::*; pub enum Out { Take(usize), Put, Produce(ItemIndex), Consume(usize), } pub fn interact( data: &Gamedata, edge: bool, tile: TileIndex, active: &mut Option, mut items: Vec, mut hand: Option, mut out: impl FnMut(Out), ) { let mut allowed = BTreeSet::new(); for r in &data.recipes { if r.tile == tile { allowed.extend(r.inputs.clone()) } } if !edge { if let Some(ac) = active { if matches!(data.recipes[ac.recipe].action, Action::Active(_)) { ac.working -= 1; } } return; } if !items.is_empty() && hand.is_none() { out(Take(items.len() - 1)); return; } if let Some(hi) = hand { if allowed.contains(&hi) { out(Put); items.push(hi); hand = None; } } if hand.is_none() { 'rloop: for (ri, r) in data.recipes.iter().enumerate() { if tile != r.tile { continue; } let mut inputs = r.inputs.clone(); for i in &items { debug!("take {i:?} {inputs:?}"); let Some(pos) = inputs.iter().position(|e| e == i) else { continue 'rloop; }; inputs.remove(pos); } debug!("end {inputs:?}"); if !inputs.is_empty() { continue; } match r.action { Action::Passive(_) => { info!("use recipe {r:?}"); *active = Some(ActiveRecipe { recipe: ri, progress: 0., working: 0, }); break 'rloop; } Action::Active(_) => {} Action::Instant => { info!("use recipe {r:?}"); for i in 0..items.len() { out(Consume(i)) } for i in &r.outputs { out(Produce(*i)); } if !r.outputs.is_empty() { out(Take(r.outputs.len() - 1)); } items.clear(); break 'rloop; } Action::Never => (), } } } }