Browse Source

rare drops

pbs
jake 5 years ago
parent
commit
cfa31736c6
  1. 8
      src/ship/drops/generic_armor.rs
  2. 6
      src/ship/drops/generic_shield.rs
  3. 25
      src/ship/drops/generic_weapon.rs
  4. 67
      src/ship/drops/mod.rs
  5. 155
      src/ship/drops/rare_drop_table.rs

8
src/ship/drops/generic_armor.rs

@ -80,20 +80,18 @@ impl GenericArmorTable {
} }
} }
fn slots<R: Rng>(&self, area_map: &MapVariantType, rng: &mut R) -> usize {
pub fn slots<R: Rng>(&self, area_map: &MapVariantType, rng: &mut R) -> usize {
let slot_weights = WeightedIndex::new(&[self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2, let slot_weights = WeightedIndex::new(&[self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2,
self.slot_rates.slot3, self.slot_rates.slot4]).unwrap(); self.slot_rates.slot3, self.slot_rates.slot4]).unwrap();
slot_weights.sample(rng) slot_weights.sample(rng)
} }
// TODO: this needs the pmt file
fn dfp_modifier<R: Rng>(&self, armor_type: &ArmorType, rng: &mut R) -> u32 {
pub fn dfp_modifier<R: Rng>(&self, armor_type: &ArmorType, rng: &mut R) -> u32 {
let stats = self.armor_stats.get(armor_type).unwrap(); let stats = self.armor_stats.get(armor_type).unwrap();
rng.gen_range(0, stats.dfp_modifier) rng.gen_range(0, stats.dfp_modifier)
} }
// TODO: this needs the pmt file
fn evp_modifier<R: Rng>(&self, armor_type: &ArmorType, rng: &mut R) -> u32 {
pub fn evp_modifier<R: Rng>(&self, armor_type: &ArmorType, rng: &mut R) -> u32 {
let stats = self.armor_stats.get(armor_type).unwrap(); let stats = self.armor_stats.get(armor_type).unwrap();
rng.gen_range(0, stats.evp_modifier) rng.gen_range(0, stats.evp_modifier)
} }

6
src/ship/drops/generic_shield.rs

@ -67,14 +67,12 @@ impl GenericShieldTable {
} }
} }
// TODO: this needs the pmt file
fn dfp_modifier<R: Rng>(&self, shield_type: &ShieldType, rng: &mut R) -> u32 {
pub fn dfp_modifier<R: Rng>(&self, shield_type: &ShieldType, rng: &mut R) -> u32 {
let stats = self.shield_stats.get(shield_type).unwrap(); let stats = self.shield_stats.get(shield_type).unwrap();
rng.gen_range(0, stats.dfp_modifier) 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) -> u32 {
pub fn evp_modifier<R: Rng>(&self, shield_type: &ShieldType, rng: &mut R) -> u32 {
let stats = self.shield_stats.get(shield_type).unwrap(); let stats = self.shield_stats.get(shield_type).unwrap();
rng.gen_range(0, stats.evp_modifier) rng.gen_range(0, stats.evp_modifier)
} }

25
src/ship/drops/generic_weapon.rs

@ -220,7 +220,7 @@ impl PercentRatePatterns {
} }
} }
struct AttributeTable {
pub struct AttributeTable {
attribute_rates: AttributeRates, attribute_rates: AttributeRates,
percent_rates: PercentRatePatterns, percent_rates: PercentRatePatterns,
area_percent_patterns: AreaPercentPatterns, area_percent_patterns: AreaPercentPatterns,
@ -228,7 +228,7 @@ struct AttributeTable {
impl AttributeTable { impl AttributeTable {
fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> AttributeTable {
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> AttributeTable {
// TODO: new these // TODO: new these
let attribute_rates: AttributeRates = load_data_file(episode, difficulty, section_id, "attribute_rate.toml"); let attribute_rates: AttributeRates = load_data_file(episode, difficulty, section_id, "attribute_rate.toml");
let percent_rates: PercentRatePatterns = load_data_file(episode, difficulty, section_id, "percent_rate.toml"); let percent_rates: PercentRatePatterns = load_data_file(episode, difficulty, section_id, "percent_rate.toml");
@ -266,10 +266,7 @@ impl AttributeTable {
}) })
} }
fn generate_attributes<R: Rng>(&self, map_area: &MapVariantType, rng: &mut R) -> [Option<WeaponAttribute>; 3] {
let percent_pattern = self.area_percent_patterns.get_by_area(map_area);
let attribute_rate = self.attribute_rates.get_by_area(map_area);
fn attributes<R: Rng>(&self, percent_pattern: &AttributePercentPattern, attribute_rate: &AttributeRate, rng: &mut R) -> [Option<WeaponAttribute>; 3] {
let mut percents = vec![ let mut percents = vec![
percent_pattern.attribute1.and_then(|pattern_type| { percent_pattern.attribute1.and_then(|pattern_type| {
self.generate_attribute(&pattern_type, &attribute_rate, rng) self.generate_attribute(&pattern_type, &attribute_rate, rng)
@ -304,6 +301,22 @@ impl AttributeTable {
} }
}).0 }).0
} }
fn generate_attributes<R: Rng>(&self, map_area: &MapVariantType, rng: &mut R) -> [Option<WeaponAttribute>; 3] {
let percent_pattern = self.area_percent_patterns.get_by_area(map_area);
let attribute_rate = self.attribute_rates.get_by_area(map_area);
self.attributes(&percent_pattern, &attribute_rate, rng)
}
pub fn generate_rare_attributes<R: Rng>(&self, map_area: &MapVariantType, rng: &mut R) -> [Option<WeaponAttribute>; 3] {
let percent_pattern = AttributePercentPattern {
attribute1: Some(PercentPatternType::Pattern6),
attribute2: Some(PercentPatternType::Pattern6),
attribute3: Some(PercentPatternType::Pattern6),
};
let attribute_rate = self.attribute_rates.get_by_area(map_area);
self.attributes(&percent_pattern, &attribute_rate, rng)
}
} }

67
src/ship/drops/mod.rs

@ -7,7 +7,6 @@ mod generic_unit;
mod tool_table; mod tool_table;
mod tech_table; mod tech_table;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
@ -15,14 +14,9 @@ use std::io::Read;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use rand::{Rng, SeedableRng}; use rand::{Rng, SeedableRng};
use crate::entity::item::ItemDetail;
use crate::ship::monster::MonsterType; use crate::ship::monster::MonsterType;
use crate::ship::room::{Difficulty, Episode}; use crate::ship::room::{Difficulty, Episode};
use crate::entity::item::ItemDetail;
use crate::entity::item::weapon::WeaponType;
use crate::entity::item::armor::ArmorType;
use crate::entity::item::shield::ShieldType;
use crate::entity::item::unit::UnitType;
use crate::entity::item::tool::ToolType;
use crate::ship::map::MapVariantType; use crate::ship::map::MapVariantType;
use crate::entity::character::SectionID; use crate::entity::character::SectionID;
use crate::ship::drops::generic_weapon::GenericWeaponTable; use crate::ship::drops::generic_weapon::GenericWeaponTable;
@ -30,6 +24,7 @@ use crate::ship::drops::generic_armor::GenericArmorTable;
use crate::ship::drops::generic_shield::GenericShieldTable; use crate::ship::drops::generic_shield::GenericShieldTable;
use crate::ship::drops::generic_unit::GenericUnitTable; use crate::ship::drops::generic_unit::GenericUnitTable;
use crate::ship::drops::tool_table::ToolTable; use crate::ship::drops::tool_table::ToolTable;
use crate::ship::drops::rare_drop_table::RareDropTable;
fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf { fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf {
@ -73,60 +68,28 @@ pub struct MonsterDropStats {
pub max_meseta: u32, pub max_meseta: u32,
} }
enum RareDropItem {
Weapon(WeaponType),
Armor(ArmorType),
Shield(ShieldType),
Unit(UnitType),
Tool(ToolType),
enum ItemDropItem {
Weapon,
} }
struct RareDrop {
rate: f32,
item: RareDropItem
struct ItemDrop {
x: f32,
y: f32,
z: f32,
item: ItemDropItem,
} }
#[derive(Debug, Serialize, Deserialize)]
pub struct RareDropConfigEntity {
pub rate: f32,
pub item: String,
impl ItemDropItem {
pub fn as_client_bytes(&self) -> u8 {
0
} }
/*#[derive(Serialize, Deserialize)]
pub struct MonsterDar(pub HashMap<MonsterType, MonsterDropStats>);
/*impl MonsterDar {
fn from_f
}*/*/
struct RareDropTable {
} }
impl RareDropTable {
fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable {
RareDropTable {
}
}
fn get_drop(&self, monster: &MonsterType) -> Option<ItemDetail> {
None
}
}
struct DropTable<R: Rng + SeedableRng> { struct DropTable<R: Rng + SeedableRng> {
rare_table: RareDropTable,
monster_stats: HashMap<MonsterType, MonsterDropStats>, monster_stats: HashMap<MonsterType, MonsterDropStats>,
rare_table: RareDropTable,
weapon_table: GenericWeaponTable, weapon_table: GenericWeaponTable,
armor_table: GenericArmorTable, armor_table: GenericArmorTable,
shield_table: GenericShieldTable, shield_table: GenericShieldTable,
@ -149,8 +112,8 @@ impl<R: Rng + SeedableRng> DropTable<R> {
let monster_stats = toml::from_str(&s).unwrap(); let monster_stats = toml::from_str(&s).unwrap();
DropTable { DropTable {
rare_table: RareDropTable::new(episode, difficulty, section_id),
monster_stats: monster_stats, monster_stats: monster_stats,
rare_table: RareDropTable::new(episode, difficulty, section_id),
weapon_table: GenericWeaponTable::new(episode, difficulty, section_id), weapon_table: GenericWeaponTable::new(episode, difficulty, section_id),
armor_table: GenericArmorTable::new(episode, difficulty, section_id), armor_table: GenericArmorTable::new(episode, difficulty, section_id),
shield_table: GenericShieldTable::new(episode, difficulty, section_id), shield_table: GenericShieldTable::new(episode, difficulty, section_id),
@ -182,7 +145,7 @@ impl<R: Rng + SeedableRng> DropTable<R> {
return None; return None;
} }
if let Some(item) = self.rare_table.get_drop(&monster) {
if let Some(item) = self.rare_table.get_drop(map_area, &monster, &mut self.rng) {
return Some(item); return Some(item);
} }

155
src/ship/drops/rare_drop_table.rs

@ -0,0 +1,155 @@
use std::collections::HashMap;
use rand::Rng;
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::drops::generic_weapon::AttributeTable;
use crate::ship::drops::generic_armor::GenericArmorTable;
use crate::ship::drops::generic_shield::GenericShieldTable;
#[derive(Debug, Copy, Clone)]
enum RareDropItem {
Weapon(WeaponType),
Armor(ArmorType),
Shield(ShieldType),
Unit(UnitType),
Tool(ToolType),
}
impl RareDropItem {
fn from_string(name: String) -> RareDropItem {
let parse_funcs: [Box<dyn Fn(&String) -> Option<RareDropItem>>; 5] = [
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()?)))];
for parse in parse_funcs.iter() {
match parse(&name) {
Some(k) => return k,
None => {},
}
}
panic!()
}
}
struct RareDropRate {
rate: f32,
item: RareDropItem
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RareDropConfigEntity {
pub rate: f32,
pub item: String,
}
pub struct RareDropTable {
rates: HashMap<MonsterType, Vec<RareDropRate>>,
attribute_table: AttributeTable,
armor_stats: GenericArmorTable,
shield_stats: GenericShieldTable,
}
impl RareDropTable {
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> RareDropTable {
let cfg: HashMap<String, Vec<RareDropConfigEntity>> = load_data_file(episode, difficulty, section_id, "rare_rate.toml");
let rates = cfg.into_iter()
.map(|(monster, drops)| {
let monster = monster.parse().unwrap();
let drops = drops.into_iter().map(|drop| {
RareDropRate {
rate: drop.rate,
item: RareDropItem::from_string(drop.item),
}
}).collect();
(monster, drops)
}).collect();
RareDropTable {
rates: rates,
attribute_table: AttributeTable::new(episode, difficulty, section_id),
armor_stats: GenericArmorTable::new(episode, difficulty, section_id),
shield_stats: GenericShieldTable::new(episode, difficulty, section_id),
}
}
fn apply_item_stats<R: Rng>(&self, map_area: &MapVariantType, item: RareDropItem, rng: &mut R) -> ItemDetail {
match item {
RareDropItem::Weapon(weapon) => {
ItemDetail::Weapon(Weapon {
weapon: weapon,
special: None,
grind: 0,
attrs: self.attribute_table.generate_rare_attributes(map_area, rng),
equipped: false,
tekked: false,
})
},
RareDropItem::Armor(armor) => {
ItemDetail::Armor(Armor {
armor: armor,
dfp: self.armor_stats.dfp_modifier(&armor, rng) as u8,
evp: self.armor_stats.evp_modifier(&armor, rng) as u8,
slots: self.armor_stats.slots(map_area, rng) as u8,
equipped: false,
})
},
RareDropItem::Shield(shield) => {
ItemDetail::Shield(Shield {
shield: shield,
dfp: self.shield_stats.dfp_modifier(&shield, rng) as u8,
evp: self.shield_stats.evp_modifier(&shield, rng) as u8,
equipped: false,
})
},
RareDropItem::Unit(unit) => {
ItemDetail::Unit(Unit {
unit: unit,
modifier: None,
equipped: false,
})
},
RareDropItem::Tool(tool) => {
ItemDetail::Tool(Tool {
tool: tool,
})
}
}
}
pub fn get_drop<R: Rng>(&self, map_area: &MapVariantType, monster: &MonsterType, rng: &mut R) -> Option<ItemDetail> {
self.rates.get(monster)
.and_then(|drop_rates| {
drop_rates.iter()
.filter_map(|drop_rate| {
let rand: f32 = rng.gen();
if rand < drop_rate.rate {
Some(self.apply_item_stats(map_area, drop_rate.item, rng))
}
else {
None
}
}).nth(0)
})
}
}
Loading…
Cancel
Save