From 4fb78048e533541b3a5d9aa947a99c36edcfc356 Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 15 Mar 2020 17:17:29 -0700 Subject: [PATCH] cool unique server features --- src/entity/item/unit.rs | 2 +- src/ship/drops/generic_shield.rs | 4 - src/ship/drops/generic_unit.rs | 129 +++++++++++++++++++++++++++++++ src/ship/drops/mod.rs | 1 + src/ship/item_stats.rs | 18 ++--- 5 files changed, 140 insertions(+), 14 deletions(-) diff --git a/src/entity/item/unit.rs b/src/entity/item/unit.rs index 2162a16..6d2309d 100644 --- a/src/entity/item/unit.rs +++ b/src/entity/item/unit.rs @@ -1,7 +1,7 @@ use serde::{Serialize, Deserialize}; -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, enum_utils::FromStr, derive_more::Display)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, enum_utils::FromStr, derive_more::Display)] pub enum UnitType { KnightPower, GeneralPower, diff --git a/src/ship/drops/generic_shield.rs b/src/ship/drops/generic_shield.rs index 0169626..93db1b1 100644 --- a/src/ship/drops/generic_shield.rs +++ b/src/ship/drops/generic_shield.rs @@ -105,10 +105,6 @@ mod test { let mut rng = rand_chacha::ChaCha20Rng::from_seed([23;32]); let gst = GenericShieldTable::new(Episode::One, Difficulty::Ultimate, SectionID::Skyly); - //println!("{:?}", gst.get_drop(&MapVariantType::Forest1, &mut rng)); - //println!("{:?}", gst.get_drop(&MapVariantType::Caves3, &mut rng)); - //println!("{:?}", gst.get_drop(&MapVariantType::Mines2, &mut rng)); - //println!("{:?}", gst.get_drop(&MapVariantType::DarkFalz, &mut rng)); assert!(gst.get_drop(&MapVariantType::Forest1, &mut rng) == Some(ItemDetail::Shield(ShieldDetail { equipped: false, diff --git a/src/ship/drops/generic_unit.rs b/src/ship/drops/generic_unit.rs index e69de29..402701f 100644 --- a/src/ship/drops/generic_unit.rs +++ b/src/ship/drops/generic_unit.rs @@ -0,0 +1,129 @@ +use std::collections::BTreeMap; +use serde::{Serialize, Deserialize}; +use rand::{Rng, SeedableRng}; +use rand::distributions::{WeightedIndex, Distribution}; +use rand::seq::IteratorRandom; + +use crate::entity::item::{ItemDetail, Unit as UnitDetail}; +use crate::entity::item::unit::{UnitType, Unit, UnitModifier}; +use crate::ship::room::{Difficulty, Episode}; +use crate::ship::map::MapVariantType; +use crate::entity::character::SectionID; +use crate::ship::drops::load_data_file; +use crate::ship::item_stats::{unit_stats, UnitStats}; + + + +#[derive(Debug, Serialize, Deserialize)] +struct UnitLevels { + area1: u32, + area2: u32, + area3: u32, + area4: u32, + area5: u32, + area6: u32, + area7: u32, + area8: u32, + area9: u32, + area10: u32, +} + +impl UnitLevels { + fn level_by_area(&self, map_area: &MapVariantType) -> u32 { + match map_area.area_value().unwrap() { + 0 => self.area1, + 1 => self.area2, + 2 => self.area3, + 3 => self.area1, + 4 => self.area1, + 5 => self.area6, + 6 => self.area7, + 7 => self.area8, + 8 => self.area9, + 9 => self.area10, + _ => panic!() + } + } +} + +pub struct GenericUnitTable { + unit_levels: UnitLevels, + unit_stats: BTreeMap, +} + + + +impl GenericUnitTable { + pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> GenericUnitTable { + GenericUnitTable { + unit_levels: load_data_file(episode, difficulty, section_id, "unit_rate.toml"), + unit_stats: unit_stats(), + } + } + + fn unit_type_and_modifier(&self, area_map: &MapVariantType, rng: &mut R) -> Option<(UnitType, Option)> { + let level = self.unit_levels.level_by_area(area_map) as i32; + if level == 0 { + return None; + } + let units = self.unit_stats + .iter() + .filter(|(_, stats)| { + stats.stars < 9 + }) + .filter_map(|(utype, stats)| { + match level - stats.stars as i32 { + -1 if stats.modifier != 0 => Some(vec![(*utype, Some(UnitModifier::Minus)), (*utype, Some(UnitModifier::MinusMinus))]), + 0 => Some(vec![(*utype, None)]), + 1 if stats.modifier != 0 => Some(vec![(*utype, Some(UnitModifier::Plus)), (*utype, Some(UnitModifier::PlusPlus))]), + _ => None, + } + }) + .flatten(); + + Some(units.choose(rng).unwrap()) + } + + pub fn get_drop(&self, area_map: &MapVariantType, rng: &mut R) -> Option { + let unit_type_modifier = self.unit_type_and_modifier(area_map, rng); + + unit_type_modifier.map(|(unit_type, unit_modifier)| { + ItemDetail::Unit(UnitDetail { + equipped: false, + unit: Unit { + unit: unit_type, + modifier: unit_modifier, + } + }) + }) + } +} + + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_unit_drops() { + let mut rng = rand_chacha::ChaCha20Rng::from_seed([23;32]); + + let gut = GenericUnitTable::new(Episode::One, Difficulty::Normal, SectionID::Skyly); + assert!(gut.get_drop(&MapVariantType::Forest1, &mut rng) == None); + + let gut = GenericUnitTable::new(Episode::One, Difficulty::Hard, SectionID::Skyly); + + let unit_tests = vec![(MapVariantType::Forest1, UnitType::ResistFreeze, Some(UnitModifier::PlusPlus)), + (MapVariantType::Caves3, UnitType::GeneralTP, None), + (MapVariantType::Mines2, UnitType::ResistEvil, Some(UnitModifier::PlusPlus)), + (MapVariantType::DarkFalz, UnitType::DragonHP, Some(UnitModifier::Minus))]; + for (area, unit, umod) in unit_tests { + assert!(gut.get_drop(&area, &mut rng) == Some(ItemDetail::Unit(UnitDetail { + equipped: false, + unit: Unit { + unit: unit, + modifier: umod, + } + }))); + } + } +} diff --git a/src/ship/drops/mod.rs b/src/ship/drops/mod.rs index ed6c3a6..c1780aa 100644 --- a/src/ship/drops/mod.rs +++ b/src/ship/drops/mod.rs @@ -3,6 +3,7 @@ mod rare_drop_table; mod generic_weapon; mod generic_armor; mod generic_shield; +mod generic_unit; use std::collections::HashMap; diff --git a/src/ship/item_stats.rs b/src/ship/item_stats.rs index f7744d3..ff3f95f 100644 --- a/src/ship/item_stats.rs +++ b/src/ship/item_stats.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, BTreeMap}; use serde::{Serialize, Deserialize}; use std::fs::File; use std::io::Read; @@ -54,12 +54,12 @@ pub struct ShieldStats { } #[derive(Debug, Copy, Clone, Serialize, Deserialize)] -struct UnitStats { - stars: u32, - stat: u32, - amount: u32, - team_points: u32, - modifier: u32, +pub struct UnitStats { + pub stars: u32, + pub stat: u32, + pub amount: u32, + pub team_points: u32, + pub modifier: u32, } @@ -79,8 +79,8 @@ pub fn shield_stats() -> HashMap { }).collect() } -fn unit_stats() -> HashMap { - let unit_stats: HashMap = load_data_file("data/item_stats/unit_stats.toml"); +pub fn unit_stats() -> BTreeMap { + let unit_stats: BTreeMap = load_data_file("data/item_stats/unit_stats.toml"); unit_stats.iter() .map(|(name, stats)| { (name.parse().unwrap(), *stats)