2020-03-14 10:44:27 -07:00
|
|
|
mod drop_table;
|
|
|
|
mod rare_drop_table;
|
|
|
|
mod generic_weapon;
|
|
|
|
mod generic_armor;
|
|
|
|
mod generic_shield;
|
2020-03-15 17:17:29 -07:00
|
|
|
mod generic_unit;
|
2020-03-16 18:47:30 -07:00
|
|
|
mod tool_table;
|
|
|
|
mod tech_table;
|
2020-03-28 12:06:24 -07:00
|
|
|
mod box_drop_table;
|
2020-03-14 10:44:27 -07:00
|
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::fs::File;
|
|
|
|
use std::path::PathBuf;
|
|
|
|
use std::io::Read;
|
|
|
|
use serde::{Serialize, Deserialize};
|
|
|
|
use rand::{Rng, SeedableRng};
|
|
|
|
|
|
|
|
use crate::ship::monster::MonsterType;
|
|
|
|
use crate::ship::room::{Difficulty, Episode};
|
2020-04-03 22:51:55 -07:00
|
|
|
use crate::ship::map::MapArea;
|
2020-03-14 10:44:27 -07:00
|
|
|
use crate::entity::character::SectionID;
|
2020-03-14 17:08:31 -07:00
|
|
|
use crate::ship::drops::generic_weapon::GenericWeaponTable;
|
|
|
|
use crate::ship::drops::generic_armor::GenericArmorTable;
|
2020-03-14 18:19:41 -07:00
|
|
|
use crate::ship::drops::generic_shield::GenericShieldTable;
|
2020-03-15 17:31:29 -07:00
|
|
|
use crate::ship::drops::generic_unit::GenericUnitTable;
|
2020-03-16 18:47:30 -07:00
|
|
|
use crate::ship::drops::tool_table::ToolTable;
|
2020-03-26 00:06:28 -07:00
|
|
|
use crate::ship::drops::rare_drop_table::RareDropTable;
|
2020-03-28 12:06:24 -07:00
|
|
|
use crate::ship::drops::box_drop_table::BoxDropTable;
|
|
|
|
use crate::ship::map::MapObject;
|
2020-03-29 11:54:58 -07:00
|
|
|
use crate::entity::item::{weapon, armor, shield, unit, mag, tool, tech};
|
2020-03-14 17:08:31 -07:00
|
|
|
|
|
|
|
|
|
|
|
fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf {
|
|
|
|
let mut path = PathBuf::from("data/drops/");
|
|
|
|
path.push(episode.to_string());
|
|
|
|
path.push(difficulty.to_string().to_lowercase());
|
|
|
|
path.push(section_id.to_string().to_lowercase());
|
|
|
|
path.push(filename);
|
|
|
|
path
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_data_file<T: serde::de::DeserializeOwned>(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> T {
|
|
|
|
let path = data_file_path(episode, difficulty, section_id, filename);
|
|
|
|
let mut f = File::open(path).unwrap();
|
|
|
|
let mut s = String::new();
|
|
|
|
f.read_to_string(&mut s);
|
|
|
|
|
|
|
|
toml::from_str::<T>(s.as_str()).unwrap()
|
|
|
|
}
|
2020-03-14 10:44:27 -07:00
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
|
|
|
pub enum MonsterDropType {
|
|
|
|
#[serde(rename = "weapon")]
|
|
|
|
Weapon,
|
|
|
|
#[serde(rename = "armor")]
|
|
|
|
Armor,
|
|
|
|
#[serde(rename = "shield")]
|
|
|
|
Shield,
|
|
|
|
#[serde(rename = "unit")]
|
|
|
|
Unit,
|
|
|
|
#[serde(rename = "none")]
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
|
|
|
pub struct MonsterDropStats {
|
|
|
|
pub dar: u32,
|
|
|
|
pub drop_type: MonsterDropType,
|
|
|
|
pub min_meseta: u32,
|
|
|
|
pub max_meseta: u32,
|
|
|
|
}
|
|
|
|
|
2020-03-29 11:54:58 -07:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub enum ItemDropType {
|
|
|
|
Weapon(weapon::Weapon),
|
|
|
|
Armor(armor::Armor),
|
|
|
|
Shield(shield::Shield),
|
|
|
|
Unit(unit::Unit),
|
|
|
|
Tool(tool::Tool),
|
|
|
|
TechniqueDisk(tech::TechniqueDisk),
|
|
|
|
Mag(mag::Mag),
|
|
|
|
Meseta(u32),
|
2020-03-14 10:44:27 -07:00
|
|
|
}
|
|
|
|
|
2020-03-26 00:06:28 -07:00
|
|
|
struct ItemDrop {
|
|
|
|
x: f32,
|
|
|
|
y: f32,
|
|
|
|
z: f32,
|
2020-03-29 11:54:58 -07:00
|
|
|
item: ItemDropType,
|
2020-03-14 10:44:27 -07:00
|
|
|
}
|
|
|
|
|
2020-03-29 11:54:58 -07:00
|
|
|
impl ItemDrop {
|
2020-03-26 00:06:28 -07:00
|
|
|
pub fn as_client_bytes(&self) -> u8 {
|
|
|
|
0
|
2020-03-14 10:44:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-26 00:06:28 -07:00
|
|
|
|
2020-04-03 22:51:55 -07:00
|
|
|
pub struct DropTable<R: Rng + SeedableRng> {
|
2020-03-14 10:44:27 -07:00
|
|
|
monster_stats: HashMap<MonsterType, MonsterDropStats>,
|
2020-03-26 00:06:28 -07:00
|
|
|
rare_table: RareDropTable,
|
2020-03-14 10:44:27 -07:00
|
|
|
weapon_table: GenericWeaponTable,
|
2020-03-14 17:08:31 -07:00
|
|
|
armor_table: GenericArmorTable,
|
2020-03-14 18:19:41 -07:00
|
|
|
shield_table: GenericShieldTable,
|
2020-03-15 17:31:29 -07:00
|
|
|
unit_table: GenericUnitTable,
|
2020-03-16 18:47:30 -07:00
|
|
|
tool_table: ToolTable,
|
2020-03-28 12:06:24 -07:00
|
|
|
box_table: BoxDropTable,
|
2020-03-14 10:44:27 -07:00
|
|
|
rng: R,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<R: Rng + SeedableRng> DropTable<R> {
|
2020-04-03 22:51:55 -07:00
|
|
|
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable<R> {
|
2020-04-13 01:01:06 -07:00
|
|
|
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
2020-03-14 10:44:27 -07:00
|
|
|
|
|
|
|
DropTable {
|
2020-04-13 01:01:06 -07:00
|
|
|
monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(),
|
2020-03-26 00:06:28 -07:00
|
|
|
rare_table: RareDropTable::new(episode, difficulty, section_id),
|
2020-03-14 10:44:27 -07:00
|
|
|
weapon_table: GenericWeaponTable::new(episode, difficulty, section_id),
|
2020-03-14 17:08:31 -07:00
|
|
|
armor_table: GenericArmorTable::new(episode, difficulty, section_id),
|
2020-03-14 18:19:41 -07:00
|
|
|
shield_table: GenericShieldTable::new(episode, difficulty, section_id),
|
2020-03-15 17:31:29 -07:00
|
|
|
unit_table: GenericUnitTable::new(episode, difficulty, section_id),
|
2020-03-16 18:47:30 -07:00
|
|
|
tool_table: ToolTable::new(episode, difficulty, section_id),
|
2020-03-28 12:06:24 -07:00
|
|
|
box_table: BoxDropTable::new(episode, difficulty, section_id),
|
2020-03-14 10:44:27 -07:00
|
|
|
rng: R::from_entropy(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-29 11:54:58 -07:00
|
|
|
fn generate_meseta(&mut self, monster: &MonsterDropStats) -> Option<ItemDropType> {
|
|
|
|
Some(ItemDropType::Meseta(self.rng.gen_range(monster.min_meseta, monster.max_meseta)))
|
2020-03-14 10:44:27 -07:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:51:55 -07:00
|
|
|
fn generate_typed_drop(&mut self, map_area: &MapArea, monster: &MonsterDropStats) -> Option<ItemDropType> {
|
2020-03-14 10:44:27 -07:00
|
|
|
match monster.drop_type {
|
|
|
|
MonsterDropType::Weapon => self.weapon_table.get_drop(map_area, &mut self.rng),
|
2020-03-14 18:19:41 -07:00
|
|
|
MonsterDropType::Armor => self.armor_table.get_drop(map_area, &mut self.rng),
|
|
|
|
MonsterDropType::Shield => self.shield_table.get_drop(map_area, &mut self.rng),
|
2020-03-15 17:31:29 -07:00
|
|
|
MonsterDropType::Unit => self.unit_table.get_drop(map_area, &mut self.rng),
|
2020-03-14 10:44:27 -07:00
|
|
|
MonsterDropType::None => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-03 22:51:55 -07:00
|
|
|
pub fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
|
2020-03-14 10:44:27 -07:00
|
|
|
let monster_stat = *self.monster_stats.get(monster)?;
|
|
|
|
|
|
|
|
let drop_anything = self.rng.gen_range(0, 100);
|
|
|
|
if drop_anything > monster_stat.dar {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2020-03-26 00:06:28 -07:00
|
|
|
if let Some(item) = self.rare_table.get_drop(map_area, &monster, &mut self.rng) {
|
2020-03-14 10:44:27 -07:00
|
|
|
return Some(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
let drop_type = self.rng.gen_range(0, 3);
|
|
|
|
|
|
|
|
match drop_type {
|
|
|
|
0 => {
|
|
|
|
self.generate_meseta(&monster_stat)
|
|
|
|
},
|
|
|
|
1 => {
|
2020-03-16 18:47:30 -07:00
|
|
|
self.tool_table.get_drop(map_area, &mut self.rng)
|
2020-03-14 10:44:27 -07:00
|
|
|
},
|
|
|
|
2 => {
|
|
|
|
self.generate_typed_drop(map_area, &monster_stat)
|
|
|
|
},
|
|
|
|
_ => panic!()
|
|
|
|
}
|
|
|
|
}
|
2020-03-28 12:06:24 -07:00
|
|
|
|
2020-04-03 22:51:55 -07:00
|
|
|
pub fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
|
2020-03-28 12:06:24 -07:00
|
|
|
self.box_table.get_drop(map_area, object, &mut self.rng)
|
|
|
|
}
|
2020-03-14 10:44:27 -07:00
|
|
|
}
|