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. 43
      src/ship/drops/generic_weapon.rs
  4. 69
      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,
self.slot_rates.slot3, self.slot_rates.slot4]).unwrap();
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();
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();
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();
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();
rng.gen_range(0, stats.evp_modifier)
}

43
src/ship/drops/generic_weapon.rs

@ -220,7 +220,7 @@ impl PercentRatePatterns {
}
}
struct AttributeTable {
pub struct AttributeTable {
attribute_rates: AttributeRates,
percent_rates: PercentRatePatterns,
area_percent_patterns: AreaPercentPatterns,
@ -228,7 +228,7 @@ struct 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
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");
@ -255,7 +255,7 @@ impl AttributeTable {
};
let percents = self.percent_rates.get_by_pattern(pattern);
let value_weights = WeightedIndex::new(&percents.as_array()).unwrap();
let value = value_weights.sample(rng);
let percent = ((value + 1) * 5) as i8;
@ -265,11 +265,8 @@ impl AttributeTable {
value: percent
})
}
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![
percent_pattern.attribute1.and_then(|pattern_type| {
self.generate_attribute(&pattern_type, &attribute_rate, rng)
@ -304,6 +301,22 @@ impl AttributeTable {
}
}).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)
}
}
@ -347,23 +360,23 @@ impl SpecialRates {
_ => self.area10,
}
}
fn random_special_by_rank<R: Rng>(&self, rank: u32, rng: &mut R) -> WeaponSpecial {
let specials = match rank {
1 => vec![WeaponSpecial::Draw, WeaponSpecial::Heart, WeaponSpecial::Ice, WeaponSpecial::Bind, WeaponSpecial::Heat, WeaponSpecial::Shock,
WeaponSpecial::Dim, WeaponSpecial::Panic],
2 => vec![WeaponSpecial::Drain, WeaponSpecial::Mind, WeaponSpecial::Frost, WeaponSpecial::Hold, WeaponSpecial::Fire, WeaponSpecial::Thunder,
2 => vec![WeaponSpecial::Drain, WeaponSpecial::Mind, WeaponSpecial::Frost, WeaponSpecial::Hold, WeaponSpecial::Fire, WeaponSpecial::Thunder,
WeaponSpecial::Shadow, WeaponSpecial::Riot, WeaponSpecial::Masters, WeaponSpecial::Charge],
3 => vec![WeaponSpecial::Fill, WeaponSpecial::Soul, WeaponSpecial::Freeze, WeaponSpecial::Seize, WeaponSpecial::Flame, WeaponSpecial::Storm,
3 => vec![WeaponSpecial::Fill, WeaponSpecial::Soul, WeaponSpecial::Freeze, WeaponSpecial::Seize, WeaponSpecial::Flame, WeaponSpecial::Storm,
WeaponSpecial::Dark, WeaponSpecial::Havoc, WeaponSpecial::Lords, WeaponSpecial::Charge, WeaponSpecial::Spirit, WeaponSpecial::Devils],
4 => vec![WeaponSpecial::Gush, WeaponSpecial::Geist, WeaponSpecial::Blizzard, WeaponSpecial::Arrest, WeaponSpecial::Burning, WeaponSpecial::Tempest,
4 => vec![WeaponSpecial::Gush, WeaponSpecial::Geist, WeaponSpecial::Blizzard, WeaponSpecial::Arrest, WeaponSpecial::Burning, WeaponSpecial::Tempest,
WeaponSpecial::Hell, WeaponSpecial::Chaos, WeaponSpecial::Kings, WeaponSpecial::Charge, WeaponSpecial::Berserk, WeaponSpecial::Demons],
_ => panic!(),
};
*specials.choose(rng).unwrap()
}
fn get_special<R: Rng>(&self, map_area: &MapVariantType, rng: &mut R) -> Option<WeaponSpecial> {
let rate = self.rate_by_area(map_area);
if rng.gen_range(0, 100) < rate.rate {
@ -400,7 +413,7 @@ impl GenericWeaponTable {
rank_table.insert(WeaponDropType::Cane, vec![WeaponType::Cane, WeaponType::Stick, WeaponType::Mace, WeaponType::Club]);
rank_table.insert(WeaponDropType::Rod, vec![WeaponType::Rod, WeaponType::Pole, WeaponType::Pillar, WeaponType::Striker]);
rank_table.insert(WeaponDropType::Wand, vec![WeaponType::Wand, WeaponType::Staff, WeaponType::Baton, WeaponType::Scepter]);
GenericWeaponTable {
rank_table: rank_table,
weapon_ratio: WeaponRatios::new(episode, difficulty, section_id),
@ -445,7 +458,7 @@ impl GenericWeaponTable {
valid_weapons
}
fn weapon_type<R: Rng>(&self, possible_weapon_types: &BTreeMap<WeaponDropType, WeaponRatio>, map_area: &MapVariantType, rng: &mut R) -> WeaponDropType {
let mut weapon_rates = possible_weapon_types.iter()
.map(|(weapon, stat)| {
@ -536,7 +549,7 @@ mod test {
equipped: false,
tekked: false,
})));
let gwt = GenericWeaponTable::new(Episode::One, Difficulty::Ultimate, SectionID::Skyly);
assert!(gwt.get_drop(&MapVariantType::DarkFalz, &mut rng) == Some(ItemDetail::Weapon(Weapon {
weapon: WeaponType::Vulcan,

69
src/ship/drops/mod.rs

@ -7,7 +7,6 @@ mod generic_unit;
mod tool_table;
mod tech_table;
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
@ -15,14 +14,9 @@ use std::io::Read;
use serde::{Serialize, Deserialize};
use rand::{Rng, SeedableRng};
use crate::entity::item::ItemDetail;
use crate::ship::monster::MonsterType;
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::entity::character::SectionID;
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_unit::GenericUnitTable;
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 {
@ -73,60 +68,28 @@ pub struct MonsterDropStats {
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,
}
/*#[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
impl ItemDropItem {
pub fn as_client_bytes(&self) -> u8 {
0
}
}
struct DropTable<R: Rng + SeedableRng> {
rare_table: RareDropTable,
monster_stats: HashMap<MonsterType, MonsterDropStats>,
rare_table: RareDropTable,
weapon_table: GenericWeaponTable,
armor_table: GenericArmorTable,
shield_table: GenericShieldTable,
@ -149,8 +112,8 @@ impl<R: Rng + SeedableRng> DropTable<R> {
let monster_stats = toml::from_str(&s).unwrap();
DropTable {
rare_table: RareDropTable::new(episode, difficulty, section_id),
monster_stats: monster_stats,
rare_table: 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),
@ -182,7 +145,7 @@ impl<R: Rng + SeedableRng> DropTable<R> {
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);
}

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