rare drops
This commit is contained in:
parent
e41f79f41a
commit
cfa31736c6
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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…
x
Reference in New Issue
Block a user