/* 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 . */ use hurrycurry_client_lib::{Involvement, Item}; use hurrycurry_protocol::{Gamedata, Recipe, Score, TileIndex}; use log::info; pub enum InteractEffect { Put, Take, Produce, } pub fn interact( data: &Gamedata, edge: bool, tile: Option, this: &mut Option, other: &mut Option, score: &mut Score, automated: bool, ) -> Option { let interactable = automated || tile .map(|tile| data.is_tile_interactable(tile)) .unwrap_or(true); if interactable && other.is_none() { if let Some(item) = this { if let Some(active) = &mut item.active { let recipe = &data.recipe(active.recipe); if recipe.supports_tile(tile) { if let Recipe::Active { outputs, .. } = recipe { if edge { active.working += 1; } else { active.working -= 1; if active.progress >= 1. { *other = outputs[0].map(|kind| Item { kind, active: None }); *this = outputs[1].map(|kind| Item { kind, active: None }); return Some(InteractEffect::Produce); } } } } } } } if !edge { return None; } if interactable { for (ri, recipe) in data.recipes() { if !recipe.supports_tile(tile) { continue; } match recipe { Recipe::Active { input, .. } => { if other.is_none() { if let Some(item) = this { if item.kind == *input && item.active.is_none() { info!("start active recipe {ri:?}"); item.active = Some(Involvement { recipe: ri, working: 1, progress: 0., warn: false, }); } } } if this.is_none() { if let Some(item) = &other { if item.kind == *input { let mut item = other.take().unwrap(); if let Some(active) = &mut item.active { active.working += 1; } else { info!("start active recipe {ri:?}"); item.active = Some(Involvement { recipe: ri, working: 1, progress: 0., warn: false, }); } *this = Some(item); score.active_recipes += 1; return Some(InteractEffect::Put); } } } } Recipe::Instant { inputs, outputs, points: pd, .. } => { let on_tile = this.as_ref().map(|i| i.kind); let in_hand = other.as_ref().map(|i| i.kind); let ok = inputs[0] == on_tile && inputs[1] == in_hand; let ok_rev = inputs[1] == on_tile && inputs[0] == in_hand; if ok || ok_rev { info!("instant recipe {ri:?} reversed={ok_rev}"); 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 }); score.points += pd; score.instant_recipes += 1; return Some(InteractEffect::Produce); } } _ => (), } } } if interactable && this.is_none() { if let Some(item) = other.take() { *this = Some(item); return Some(InteractEffect::Put); } } if other.is_none() { if let Some(item) = this.take() { *other = Some(item); return Some(InteractEffect::Take); } } None } pub enum TickEffect { Progress(bool), Produce, } pub fn tick_slot( dt: f32, data: &Gamedata, tile: Option, slot: &mut Option, score: &mut Score, ) -> Option { if let Some(item) = slot { if let Some(a) = &mut item.active { let r = &data.recipe(a.recipe); if r.supports_tile(tile) { a.progress += a.working as f32 * dt / r.duration().unwrap(); } else if let Some(revert_duration) = r.revert_duration() { a.progress -= dt / revert_duration; } if a.progress >= 1. { if let Recipe::Passive { output, .. } = &data.recipe(a.recipe) { *slot = output.map(|kind| Item { kind, active: None }); score.passive_recipes += 1; return Some(TickEffect::Produce); }; a.progress = 1.; } if a.progress < 0. { item.active = None; } return Some(TickEffect::Progress(r.warn())); } else { for (ri, recipe) in data.recipes() { if recipe.supports_tile(tile) { if let Recipe::Passive { input, warn, .. } = recipe { if *input == item.kind { item.active = Some(Involvement { recipe: ri, progress: 0., warn: *warn, working: 1, }); return Some(TickEffect::Progress(recipe.warn())); } } } } } } None }