|
|
@ -1,4 +1,4 @@ |
|
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
use rand::{Rng, SeedableRng};
|
|
|
|
use rand::distributions::{WeightedIndex, Distribution};
|
|
|
@ -9,6 +9,7 @@ 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::{shield_stats, ShieldStats};
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
@ -24,11 +25,15 @@ struct ShieldRankRates { |
|
|
|
pub struct GenericShieldTable {
|
|
|
|
rank_rates: ShieldRankRates,
|
|
|
|
shield_set: u32,
|
|
|
|
#[serde(skip)]
|
|
|
|
shield_stats: HashMap<ShieldType, ShieldStats>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GenericShieldTable {
|
|
|
|
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> GenericShieldTable {
|
|
|
|
load_data_file(episode, difficulty, section_id, "shield_rate.toml")
|
|
|
|
let mut gst: GenericShieldTable = load_data_file(episode, difficulty, section_id, "shield_rate.toml");
|
|
|
|
gst.shield_stats = shield_stats();
|
|
|
|
gst
|
|
|
|
}
|
|
|
|
|
|
|
|
fn shield_type<R: Rng>(&self, area_map: &MapVariantType, rng: &mut R) -> ShieldType {
|
|
|
@ -63,13 +68,15 @@ impl GenericShieldTable { |
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: this needs the pmt file
|
|
|
|
fn dfp_modifier<R: Rng>(&self, shield_type: &ShieldType, rng: &mut R) -> usize {
|
|
|
|
0
|
|
|
|
fn dfp_modifier<R: Rng>(&self, shield_type: &ShieldType, rng: &mut R) -> u32 {
|
|
|
|
let stats = self.shield_stats.get(shield_type).unwrap();
|
|
|
|
rng.gen_range(0, stats.dfp_modifier)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: this needs the pmt file
|
|
|
|
fn evp_modifier<R: Rng>(&self, shield_type: &ShieldType, rng: &mut R) -> usize {
|
|
|
|
0
|
|
|
|
fn evp_modifier<R: Rng>(&self, shield_type: &ShieldType, rng: &mut R) -> u32 {
|
|
|
|
let stats = self.shield_stats.get(shield_type).unwrap();
|
|
|
|
rng.gen_range(0, stats.evp_modifier)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_drop<R: Rng>(&self, area_map: &MapVariantType, rng: &mut R) -> Option<ItemDetail> {
|
|
|
@ -88,3 +95,52 @@ impl GenericShieldTable { |
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
|
|
fn test_shield_generation() {
|
|
|
|
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,
|
|
|
|
shield: Shield {
|
|
|
|
shield: ShieldType::FreezeBarrier,
|
|
|
|
dfp: 4,
|
|
|
|
evp: 1,
|
|
|
|
}
|
|
|
|
})));
|
|
|
|
assert!(gst.get_drop(&MapVariantType::Caves3, &mut rng) == Some(ItemDetail::Shield(ShieldDetail {
|
|
|
|
equipped: false,
|
|
|
|
shield: Shield {
|
|
|
|
shield: ShieldType::PsychicBarrier,
|
|
|
|
dfp: 3,
|
|
|
|
evp: 2,
|
|
|
|
}
|
|
|
|
})));
|
|
|
|
assert!(gst.get_drop(&MapVariantType::Mines2, &mut rng) == Some(ItemDetail::Shield(ShieldDetail {
|
|
|
|
equipped: false,
|
|
|
|
shield: Shield {
|
|
|
|
shield: ShieldType::ImperialBarrier,
|
|
|
|
dfp: 0,
|
|
|
|
evp: 4,
|
|
|
|
}
|
|
|
|
})));
|
|
|
|
assert!(gst.get_drop(&MapVariantType::DarkFalz, &mut rng) == Some(ItemDetail::Shield(ShieldDetail {
|
|
|
|
equipped: false,
|
|
|
|
shield: Shield {
|
|
|
|
shield: ShieldType::DivinityBarrier,
|
|
|
|
dfp: 1,
|
|
|
|
evp: 0,
|
|
|
|
}
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
}
|