use crate::Currency; use crate::game::{Game, State}; use std::collections::VecDeque; use std::fmt::{Debug, Formatter, format}; use std::ops::Mul; #[derive(Debug)] pub(crate) struct UnlockSystem { bought: usize, last_unlock: Option, unlock_queue: VecDeque, } pub(crate) struct Unlock { pub(crate) name: String, pub(crate) cost: Currency, pub(crate) apply: Box, } impl Debug for Unlock { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( "Upgrade {{ name: {:?}, cost: {:?} }}", self.name, self.cost )) } } impl UnlockSystem { pub(crate) fn new(start_state: &State) -> Self { let mut upgrades = start_state .bars .iter() .enumerate() .flat_map(|(index, bar)| { let initial_cost = 10usize.pow(index as u32); [ Unlock { name: format!("Start {}", bar.name()), cost: initial_cost as f64, apply: Box::new(move |game| { game.bars[index].enabled = true; }), }, Unlock { name: format!("{} productivity", bar.name()), cost: initial_cost.mul(2) as f64, apply: Box::new(move |game| { game.bars[index].productivity *= 2.0; }), }, Unlock { name: format!("{} speed", bar.name()), cost: initial_cost.mul(20) as f64, apply: Box::new(move |game| { game.bars[index].speed *= 1.5; }), }, ] }) .chain( (1..10).map(|level| Unlock { name: format!("The answer {}", level), cost: (42usize * 10usize.pow(level)) as f64, apply: Box::new(move |game| { game.speed *= 1.1; }), } ) ) .chain( (1..10).map(|level| Unlock { name: format!("??? {}", level), cost: (23usize * 10usize.pow(level)) as f64, apply: Box::new(move |game| { game.productivity *= 1.1; }), }, ) ) .collect::>(); upgrades.sort_by(|l, r| l.cost.total_cmp(&r.cost)); let unlock_queue = upgrades.into(); Self { unlock_queue, bought: 0, last_unlock: None } } pub(crate) fn peek_next(&self) -> Option<&Unlock> { self.unlock_queue.front() } pub(crate) fn check_next(&mut self, state: &mut State) { if let Some(next_upgrade) = self.peek_next() { if next_upgrade.cost <= state.currency { log::info!("Applying upgrade {:?}", next_upgrade); let next_upgrade = self.unlock_queue.pop_front().unwrap(); state.currency -= next_upgrade.cost; (next_upgrade.apply)(state); self.last_unlock = Some(next_upgrade.name); self.bought += 1; } } } pub(crate) fn bought(&self) -> usize { self.bought } pub(crate) fn previous(&self) -> Option<&String> { self.last_unlock.as_ref() } }