use std::collections::BTreeMap; use serde::{Serialize, Deserialize}; use rand::Rng; use rand::distributions::{WeightedIndex, Distribution}; use entity::item::tool::{Tool, ToolType}; use maps::room::{Difficulty, Episode}; use maps::area::MapArea; use entity::character::SectionID; use crate::{ItemDropType, load_data_file}; use crate::tech_table::TechniqueTable; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, enum_utils::FromStr)] enum ToolRateType { Monomate, Dimate, Trimate, Monofluid, Difluid, Trifluid, Antidote, Antiparalysis, SolAtomizer, MoonAtomizer, StarAtomizer, Telepipe, TrapVision, Monogrinder, Digrinder, Trigrinder, PowerMaterial, MindMaterial, EvadeMaterial, HpMaterial, TpMaterial, DefMaterial, LuckMaterial, ScapeDoll, Technique, PhotonDrop, } /*#[derive(Debug, Serialize, Deserialize, Copy, Clone)] struct ToolRate { tool: ToolRateType, rate: u32, }*/ #[derive(Debug, Serialize, Deserialize)] struct ToolRatesRaw { area1: BTreeMap, area2: BTreeMap, area3: BTreeMap, area4: BTreeMap, area5: BTreeMap, area6: BTreeMap, area7: BTreeMap, area8: BTreeMap, area9: BTreeMap, area10: BTreeMap, } struct ToolRates { area1: BTreeMap, area2: BTreeMap, area3: BTreeMap, area4: BTreeMap, area5: BTreeMap, area6: BTreeMap, area7: BTreeMap, area8: BTreeMap, area9: BTreeMap, area10: BTreeMap, } impl ToolRates { fn new(raw: ToolRatesRaw) -> ToolRates { ToolRates { area1: raw.area1.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area2: raw.area2.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area3: raw.area3.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area4: raw.area4.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area5: raw.area5.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area6: raw.area6.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area7: raw.area7.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area8: raw.area8.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area9: raw.area9.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), area10: raw.area10.into_iter().map(|(name, rate)| (name.parse().unwrap(), rate)).collect(), } } } impl ToolRates { fn get_by_area<'a>(&'a self, map_area: &MapArea) -> &'a BTreeMap { match map_area.drop_area_value().unwrap() { 0 => &self.area1, 1 => &self.area2, 2 => &self.area3, 3 => &self.area4, 4 => &self.area5, 5 => &self.area6, 6 => &self.area7, 7 => &self.area8, 8 => &self.area9, _ => &self.area10, } } } pub struct ToolTable { rates: ToolRates, tech_table: TechniqueTable, } impl ToolTable { pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> ToolTable { let rates = load_data_file(episode, difficulty, section_id, "tool_rate.toml"); ToolTable { rates: ToolRates::new(rates), tech_table: TechniqueTable::new(episode, difficulty, section_id), } } pub fn get_drop(&self, map_area: &MapArea, rng: &mut R) -> Option { let tool_rates = self.rates.get_by_area(map_area).iter(); let tool_weights = WeightedIndex::new(tool_rates.clone().map(|(_, weights)| weights)).unwrap(); let tool = tool_rates.map(|(ttype, _)| ttype).nth(tool_weights.sample(rng)).unwrap(); let tool_type = match tool { ToolRateType::Monomate => ToolType::Monomate, ToolRateType::Dimate => ToolType::Dimate, ToolRateType::Trimate => ToolType::Trimate, ToolRateType::Monofluid => ToolType::Monofluid, ToolRateType::Difluid => ToolType::Difluid, ToolRateType::Trifluid => ToolType::Trifluid, ToolRateType::Antidote => ToolType::Antidote, ToolRateType::Antiparalysis => ToolType::Antiparalysis, ToolRateType::SolAtomizer => ToolType::SolAtomizer, ToolRateType::MoonAtomizer => ToolType::MoonAtomizer, ToolRateType::StarAtomizer => ToolType::StarAtomizer, ToolRateType::Telepipe => ToolType::Telepipe, ToolRateType::TrapVision => ToolType::TrapVision, ToolRateType::Monogrinder => ToolType::Monogrinder, ToolRateType::Digrinder => ToolType::Digrinder, ToolRateType::Trigrinder => ToolType::Trigrinder, ToolRateType::PowerMaterial => ToolType::PowerMaterial, ToolRateType::MindMaterial => ToolType::MindMaterial, ToolRateType::EvadeMaterial => ToolType::EvadeMaterial, ToolRateType::HpMaterial => ToolType::HpMaterial, ToolRateType::TpMaterial => ToolType::TpMaterial, ToolRateType::DefMaterial => ToolType::DefMaterial, ToolRateType::LuckMaterial => ToolType::LuckMaterial, ToolRateType::ScapeDoll => ToolType::ScapeDoll, ToolRateType::PhotonDrop => ToolType::PhotonDrop, ToolRateType::Technique => return self.tech_table.get_drop(map_area, rng), }; Some(ItemDropType::Tool(Tool { tool: tool_type })) } }