Browse Source

add box drops

pbs
jake 5 years ago
parent
commit
0d42c0ede0
  1. 246
      src/ship/drops/box_drop_table.rs
  2. 10
      src/ship/drops/mod.rs
  3. 27
      src/ship/drops/rare_drop_table.rs

246
src/ship/drops/box_drop_table.rs

@ -0,0 +1,246 @@
use std::collections::HashMap;
use rand::{Rng, SeedableRng};
use rand::distributions::{WeightedIndex, Distribution};
use serde::{Serialize, Deserialize};
use crate::entity::item::ItemDetail;
use crate::entity::item::weapon::{Weapon, WeaponType};
use crate::entity::item::armor::{Armor, ArmorType};
use crate::entity::item::shield::{Shield, ShieldType};
use crate::entity::item::unit::{Unit, UnitType};
use crate::entity::item::tool::{Tool, ToolType};
use crate::entity::character::SectionID;
use crate::ship::monster::MonsterType;
use crate::ship::room::{Difficulty, Episode};
use crate::ship::map::MapVariantType;
use crate::ship::drops::load_data_file;
use crate::ship::map::{MapObject, MapObjectType, FixedBoxDropType};
use crate::ship::drops::rare_drop_table::{RareDropTable, RareDropItem};
use crate::ship::drops::generic_weapon::GenericWeaponTable;
use crate::ship::drops::generic_armor::GenericArmorTable;
use crate::ship::drops::generic_shield::GenericShieldTable;
use crate::ship::drops::generic_unit::GenericUnitTable;
use crate::ship::drops::tool_table::ToolTable;
#[derive(Debug, Serialize, Deserialize)]
struct BoxDropRate {
weapon_rate: u32,
armor_rate: u32,
shield_rate: u32,
unit_rate: u32,
tool_rate: u32,
meseta_rate: u32,
nothing_rate: u32,
min_meseta: u32,
max_meseta: u32,
}
#[derive(Debug, Serialize, Deserialize)]
struct BoxDropRates {
area1: BoxDropRate,
area2: BoxDropRate,
area3: BoxDropRate,
area4: BoxDropRate,
area5: BoxDropRate,
area6: BoxDropRate,
area7: BoxDropRate,
area8: BoxDropRate,
area9: BoxDropRate,
area10: BoxDropRate,
}
impl BoxDropRates {
fn rates_by_area(&self, map_area: &MapVariantType) -> &BoxDropRate {
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!()
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct BoxRareRateRaw {
item: String,
rate: f32,
}
#[derive(Debug, Serialize, Deserialize)]
struct BoxRareRatesRaw {
area1: Vec<BoxRareRateRaw>,
area2: Vec<BoxRareRateRaw>,
area3: Vec<BoxRareRateRaw>,
area4: Vec<BoxRareRateRaw>,
area5: Vec<BoxRareRateRaw>,
area6: Vec<BoxRareRateRaw>,
area7: Vec<BoxRareRateRaw>,
area8: Vec<BoxRareRateRaw>,
area9: Vec<BoxRareRateRaw>,
area10: Vec<BoxRareRateRaw>,
}
struct BoxRareRate {
item: RareDropItem,
rate: f32,
}
struct BoxRareRates {
area1: Vec<BoxRareRate>,
area2: Vec<BoxRareRate>,
area3: Vec<BoxRareRate>,
area4: Vec<BoxRareRate>,
area5: Vec<BoxRareRate>,
area6: Vec<BoxRareRate>,
area7: Vec<BoxRareRate>,
area8: Vec<BoxRareRate>,
area9: Vec<BoxRareRate>,
area10: Vec<BoxRareRate>,
}
impl BoxRareRates {
fn new(raw: BoxRareRatesRaw) -> BoxRareRates {
BoxRareRates {
area1: raw.area1.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area2: raw.area2.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area3: raw.area3.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area4: raw.area4.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area5: raw.area5.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area6: raw.area6.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area7: raw.area7.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area8: raw.area8.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area9: raw.area9.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
area10: raw.area10.into_iter().map(|i| { BoxRareRate {item: RareDropItem::from_string(i.item), rate: i.rate} }).collect(),
}
}
fn rates_by_area(&self, map_area: &MapVariantType) -> &Vec<BoxRareRate> {
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 BoxDropTable {
box_rates: BoxDropRates,
rare_rates: BoxRareRates,
rare_stats: RareDropTable,
weapon_table: GenericWeaponTable,
armor_table: GenericArmorTable,
shield_table: GenericShieldTable,
unit_table: GenericUnitTable,
tool_table: ToolTable,
}
impl BoxDropTable {
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> BoxDropTable {
let rates = load_data_file(episode, difficulty, section_id, "box_rare_rate.toml");
BoxDropTable {
box_rates: load_data_file(episode, difficulty, section_id, "box_drop_rate.toml"),
rare_rates: BoxRareRates::new(rates),
rare_stats: RareDropTable::new(episode, difficulty, section_id),
weapon_table: GenericWeaponTable::new(episode, difficulty, section_id),
armor_table: GenericArmorTable::new(episode, difficulty, section_id),
shield_table: GenericShieldTable::new(episode, difficulty, section_id),
unit_table: GenericUnitTable::new(episode, difficulty, section_id),
tool_table: ToolTable::new(episode, difficulty, section_id),
}
}
fn rare_drop<R: Rng>(&self, map_area: &MapVariantType, rng: &mut R) -> Option<ItemDetail> {
self.rare_rates.rates_by_area(map_area).iter()
.filter_map(|rate| {
let rand: f32 = rng.gen();
if rand < rate.rate {
Some(self.rare_stats.apply_item_stats(map_area, rate.item, rng))
}
else {
None
}
}).nth(0)
}
fn random_box_drop<R: Rng>(&self, map_area: &MapVariantType, rng: &mut R) -> Option<ItemDetail> {
self.rare_drop(map_area, rng).or_else(|| {
let rate = self.box_rates.rates_by_area(map_area);
let type_weights = WeightedIndex::new(&[rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate,
rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap();
let btype = type_weights.sample(rng);
match btype {
0 => self.weapon_table.get_drop(map_area, rng),
1 => self.armor_table.get_drop(map_area, rng),
2 => self.shield_table.get_drop(map_area, rng),
3 => self.unit_table.get_drop(map_area, rng),
4 => self.tool_table.get_drop(map_area, rng),
//5 => meseta drop
_ => None,
}
})
}
fn fixed_box_drop<R: Rng>(&self, fixed_drop: FixedBoxDropType, map_area: &MapVariantType, rng: &mut R) -> Option<ItemDetail> {
match fixed_drop {
FixedBoxDropType::Weapon => self.weapon_table.get_drop(map_area, rng),
FixedBoxDropType::Armor => self.armor_table.get_drop(map_area, rng), // TODO: should this drop shield?
FixedBoxDropType::Tool => self.tool_table.get_drop(map_area, rng),
FixedBoxDropType::Meseta => panic!(),
FixedBoxDropType::Random => self.random_box_drop(map_area, rng),
FixedBoxDropType::Specific(value) => panic!(),
}
}
pub fn get_drop<R: Rng>(&self, map_area: &MapVariantType, object: &MapObject, rng: &mut R) -> Option<ItemDetail> {
match object.object {
MapObjectType::Box | MapObjectType::EnemyBox | MapObjectType::RuinsBox| MapObjectType::RuinsEnemyBox
| MapObjectType::CcaBox => {
self.random_box_drop(map_area, rng)
},
MapObjectType::FixedBox(f) | MapObjectType::EnemyFixedBox(f) | MapObjectType::RuinsFixedBox(f)
| MapObjectType::RuinsEnemyFixedBox(f) | MapObjectType::CcaFixedBox(f) => {
self.fixed_box_drop(f, map_area, rng)
},
_ => None,
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_box_drops() {
let mut rng = rand_chacha::ChaCha20Rng::from_seed([23;32]);
let bdt = BoxDropTable::new(Episode::One, Difficulty::Ultimate, SectionID::Skyly);
println!("{:?}", bdt.get_drop(&MapVariantType::Forest1, &MapObject {object: MapObjectType::Box}, &mut rng));
}
}

10
src/ship/drops/mod.rs

@ -6,6 +6,7 @@ mod generic_shield;
mod generic_unit;
mod tool_table;
mod tech_table;
mod box_drop_table;
use std::collections::HashMap;
use std::fs::File;
@ -25,6 +26,8 @@ use crate::ship::drops::generic_shield::GenericShieldTable;
use crate::ship::drops::generic_unit::GenericUnitTable;
use crate::ship::drops::tool_table::ToolTable;
use crate::ship::drops::rare_drop_table::RareDropTable;
use crate::ship::drops::box_drop_table::BoxDropTable;
use crate::ship::map::MapObject;
fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf {
@ -68,6 +71,7 @@ pub struct MonsterDropStats {
pub max_meseta: u32,
}
// TODO: ItemDropType
enum ItemDropItem {
Weapon,
}
@ -95,6 +99,7 @@ struct DropTable<R: Rng + SeedableRng> {
shield_table: GenericShieldTable,
unit_table: GenericUnitTable,
tool_table: ToolTable,
box_table: BoxDropTable,
rng: R,
}
@ -119,6 +124,7 @@ impl<R: Rng + SeedableRng> DropTable<R> {
shield_table: GenericShieldTable::new(episode, difficulty, section_id),
unit_table: GenericUnitTable::new(episode, difficulty, section_id),
tool_table: ToolTable::new(episode, difficulty, section_id),
box_table: BoxDropTable::new(episode, difficulty, section_id),
rng: R::from_entropy(),
}
}
@ -164,4 +170,8 @@ impl<R: Rng + SeedableRng> DropTable<R> {
_ => panic!()
}
}
pub fn get_box_drop(&mut self, map_area: &MapVariantType, object: &MapObject) -> Option<ItemDetail> {
self.box_table.get_drop(map_area, object, &mut self.rng)
}
}

27
src/ship/drops/rare_drop_table.rs

@ -7,6 +7,7 @@ use crate::entity::item::armor::{Armor, ArmorType};
use crate::entity::item::shield::{Shield, ShieldType};
use crate::entity::item::unit::{Unit, UnitType};
use crate::entity::item::tool::{Tool, ToolType};
use crate::entity::item::mag::{Mag, MagType};
use crate::entity::character::SectionID;
use crate::ship::monster::MonsterType;
use crate::ship::room::{Difficulty, Episode};
@ -18,22 +19,25 @@ use crate::ship::drops::generic_shield::GenericShieldTable;
#[derive(Debug, Copy, Clone)]
enum RareDropItem {
pub enum RareDropItem {
Weapon(WeaponType),
Armor(ArmorType),
Shield(ShieldType),
Unit(UnitType),
Tool(ToolType),
Mag(MagType)
}
impl RareDropItem {
fn from_string(name: String) -> RareDropItem {
let parse_funcs: [Box<dyn Fn(&String) -> Option<RareDropItem>>; 5] = [
pub fn from_string(name: String) -> RareDropItem {
let parse_funcs: [Box<dyn Fn(&String) -> Option<RareDropItem>>; 6] = [
Box::new(|i| Some(RareDropItem::Weapon(str::parse::<WeaponType>(&i).ok()?))),
Box::new(|i| Some(RareDropItem::Armor(str::parse::<ArmorType>(&i).ok()?))),
Box::new(|i| Some(RareDropItem::Shield(str::parse::<ShieldType>(&i).ok()?))),
Box::new(|i| Some(RareDropItem::Unit(str::parse::<UnitType>(&i).ok()?))),
Box::new(|i| Some(RareDropItem::Tool(str::parse::<ToolType>(&i).ok()?)))];
Box::new(|i| Some(RareDropItem::Tool(str::parse::<ToolType>(&i).ok()?))),
Box::new(|i| Some(RareDropItem::Mag(str::parse::<MagType>(&i).ok()?))),
];
for parse in parse_funcs.iter() {
match parse(&name) {
@ -92,7 +96,7 @@ impl RareDropTable {
}
}
fn apply_item_stats<R: Rng>(&self, map_area: &MapVariantType, item: RareDropItem, rng: &mut R) -> ItemDetail {
pub fn apply_item_stats<R: Rng>(&self, map_area: &MapVariantType, item: RareDropItem, rng: &mut R) -> ItemDetail {
match item {
RareDropItem::Weapon(weapon) => {
ItemDetail::Weapon(Weapon {
@ -133,6 +137,19 @@ impl RareDropTable {
ItemDetail::Tool(Tool {
tool: tool,
})
},
RareDropItem::Mag(mag) => {
ItemDetail::Mag(Mag {
mag: mag,
def: 500,
pow: 0,
dex: 0,
mnd: 0,
iq: 0,
synchro: 20,
photon_blast: [None; 3],
equipped: false,
})
}
}
}

Loading…
Cancel
Save