Browse Source

tool shop

pbs
jake 4 years ago
parent
commit
991a71e1ca
  1. 299
      data/shops/techniques.toml
  2. 1
      data/shops/tools.toml
  3. 1
      src/ship/shops/mod.rs
  4. 268
      src/ship/shops/tool.rs

299
data/shops/techniques.toml

@ -0,0 +1,299 @@
[[techniques]]
level = 0
[techniques.techs.Foie]
probability = 18
level_divisor = 3
[techniques.techs.Barta]
probability = 18
level_divisor = 4
[techniques.techs.Zonde]
probability = 18
level_divisor = 6
[techniques.techs.Resta]
probability = 18
level_divisor = 3
[techniques.techs.Anti]
probability = 18
level_divisor = 35
[techniques.techs.Shifta]
probability = 2
set_level = 1
[techniques.techs.Deband]
probability = 3
set_level = 1
[techniques.techs.Jellen]
probability = 3
set_level = 1
[techniques.techs.Zalure]
probability = 2
set_level = 1
[techniques.techs.Gifoie]
probability = 0
set_level = 1
[techniques.techs.Gibarta]
probability = 0
set_level = 1
[techniques.techs.Gizonde]
probability = 0
set_level = 1
[techniques.techs.Ryuker]
probability = 0
set_level = 1
[techniques.techs.Reverser]
probability = 0
set_level = 1
[techniques.techs.Rafoie]
probability = 0
set_level = 1
[techniques.techs.Rabarta]
probability = 0
set_level = 1
[techniques.techs.Razonde]
probability = 0
set_level = 1
[[techniques]]
level = 10
[techniques.techs.Foie]
probability = 7
level_divisor = 6
[techniques.techs.Barta]
probability = 7
level_divisor = 7
[techniques.techs.Zonde]
probability = 7
level_divisor = 8
[techniques.techs.Resta]
probability = 7
level_divisor = 6
[techniques.techs.Anti]
probability = 7
level_divisor = 35
[techniques.techs.Shifta]
probability = 6
level_divisor = 9
[techniques.techs.Deband]
probability = 6
level_divisor = 7
[techniques.techs.Jellen]
probability = 6
level_divisor = 6
[techniques.techs.Zalure]
probability = 7
level_divisor = 8
[techniques.techs.Gifoie]
probability = 8
level_divisor = 9
[techniques.techs.Gibarta]
probability = 8
level_divisor = 12
[techniques.techs.Gizonde]
probability = 8
level_divisor = 8
[techniques.techs.Ryuker]
probability = 5
set_level = 1
[techniques.techs.Reverser]
probability = 5
set_level = 1
[techniques.techs.Rafoie]
probability = 2
set_level = 1
[techniques.techs.Rabarta]
probability = 2
set_level = 1
[techniques.techs.Razonde]
probability = 2
set_level = 1
[[techniques]]
level = 25
[techniques.techs.Foie]
probability = 5
min = 3
max = 10
[techniques.techs.Barta]
probability = 5
min = 3
max = 10
[techniques.techs.Zonde]
probability = 5
min = 3
max = 10
[techniques.techs.Resta]
probability = 6
min = 3
max = 10
[techniques.techs.Anti]
probability = 5
level_divisor = 35
[techniques.techs.Shifta]
probability = 5
level_divisor = 8
[techniques.techs.Deband]
probability = 5
level_divisor = 7
[techniques.techs.Jellen]
probability = 5
level_divisor = 5
[techniques.techs.Zalure]
probability = 5
level_divisor = 6
[techniques.techs.Gifoie]
probability = 5
level_divisor = 8
[techniques.techs.Gibarta]
probability = 5
level_divisor = 9
[techniques.techs.Gizonde]
probability = 5
level_divisor = 10
[techniques.techs.Ryuker]
probability = 6
set_level = 1
[techniques.techs.Reverser]
probability = 6
set_level = 1
[techniques.techs.Rafoie]
probability = 9
level_divisor = 10
[techniques.techs.Rabarta]
probability = 9
level_divisor = 11
[techniques.techs.Razonde]
probability = 9
level_divisor = 12
[[techniques]]
level = 42
[techniques.techs.Foie]
probability = 6
min = 4
max = 12
[techniques.techs.Barta]
probability = 6
min = 4
max = 12
[techniques.techs.Zonde]
probability = 6
min = 4
max = 12
[techniques.techs.Resta]
probability = 5
min = 4
max = 12
[techniques.techs.Anti]
probability = 5
level_divisor = 35
[techniques.techs.Shifta]
probability = 6
min = 4
max = 12
[techniques.techs.Deband]
probability = 6
min = 4
max = 12
[techniques.techs.Jellen]
probability = 6
min = 4
max = 12
[techniques.techs.Zalure]
probability = 6
min = 4
max = 12
[techniques.techs.Gifoie]
probability = 6
min = 3
max = 10
[techniques.techs.Gibarta]
probability = 6
min = 3
max = 10
[techniques.techs.Gizonde]
probability = 6
min = 3
max = 10
[techniques.techs.Ryuker]
probability = 6
set_level = 1
[techniques.techs.Reverser]
probability = 6
set_level = 1
[techniques.techs.Rafoie]
probability = 6
level_divisor = 12
[techniques.techs.Rabarta]
probability = 6
level_divisor = 13
[techniques.techs.Razonde]
probability = 6
level_divisor = 11
[[techniques]]
level = 60
[techniques.techs.Foie]
probability = 6
min = 5
max = 14
[techniques.techs.Barta]
probability = 6
min = 5
max = 14
[techniques.techs.Zonde]
probability = 6
min = 5
max = 14
[techniques.techs.Resta]
probability = 5
min = 5
max = 14
[techniques.techs.Anti]
probability = 5
level_divisor = 35
[techniques.techs.Shifta]
probability = 6
min = 5
max = 14
[techniques.techs.Deband]
probability = 6
min = 5
max = 14
[techniques.techs.Jellen]
probability = 6
min = 5
max = 14
[techniques.techs.Zalure]
probability = 6
min = 5
max = 14
[techniques.techs.Gifoie]
probability = 6
min = 4
max = 13
[techniques.techs.Gibarta]
probability = 6
min = 4
max = 13
[techniques.techs.Gizonde]
probability = 6
min = 4
max = 13
[techniques.techs.Ryuker]
probability = 6
set_level = 1
[techniques.techs.Reverser]
probability = 6
set_level = 1
[techniques.techs.Rafoie]
probability = 6
min = 3
max = 13
[techniques.techs.Rabarta]
probability = 6
min = 3
max = 13
[techniques.techs.Razonde]
probability = 6
min = 3
max = 13

1
data/shops/tools.toml

@ -0,0 +1 @@
tools = [ "Monomate", "Dimate", "Trimate", "Monofluid", "Difluid", "Trifluid", "Antidote", "Antiparalysis", "SolAtomizer", "MoonAtomizer", "StarAtomizer", "Telepipe",]

1
src/ship/shops/mod.rs

@ -1 +1,2 @@
pub mod weapon;
pub mod tool;

268
src/ship/shops/tool.rs

@ -0,0 +1,268 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use serde::Deserialize;
use rand::{Rng, SeedableRng};
use rand::distributions::{WeightedIndex, Distribution};
use rand::seq::{SliceRandom, IteratorRandom};
use crate::entity::character::SectionID;
use crate::ship::room::Difficulty;
use crate::entity::item::tool::{Tool, ToolType};
use crate::entity::item::tech::{Technique, TechniqueDisk};
#[derive(Debug, PartialEq, Eq)]
pub enum ShopTool {
Tool(ToolType),
Tech(TechniqueDisk),
}
impl Ord for ShopTool {
fn cmp(&self, other: &ShopTool) -> std::cmp::Ordering {
let a = match self {
ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(),
ShopTool::Tech(t) => t.as_bytes(),
};
let b = match other {
ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(),
ShopTool::Tech(t) => t.as_bytes(),
};
a.cmp(&b)
}
}
impl PartialOrd for ShopTool {
fn partial_cmp(&self, other: &ShopTool) -> Option<std::cmp::Ordering> {
let a = match self {
ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(),
ShopTool::Tech(t) => t.as_bytes(),
};
let b = match other {
ShopTool::Tool(t) => Tool{tool : *t}.as_individual_bytes(),
ShopTool::Tech(t) => t.as_bytes(),
};
a.partial_cmp(&b)
}
}
#[derive(Debug, Deserialize)]
struct ToolTable(Vec<ToolType>);
#[derive(Debug, Deserialize, Clone)]
#[serde(untagged)]
enum TechLevel {
Set {
set_level: usize,
},
Level {
level_divisor: usize,
},
Range {
min: usize,
max: usize,
}
}
#[derive(Debug, Deserialize, Clone)]
struct TechEntry {
probability: usize,
#[serde(flatten)]
level: TechLevel,
}
#[derive(Debug, Deserialize)]
struct TechTierDeserialize {
level: usize,
techs: HashMap<String, TechEntry>,
}
#[derive(Debug, Clone)]
struct TechTier {
level: usize,
techs: HashMap<Technique, TechEntry>,
}
#[derive(Debug)]
struct TechTable(Vec<TechTier>);
fn load_tool_table() -> ToolTable {
let path = PathBuf::from("data/shops/tools.toml");
let mut f = File::open(path).unwrap();
let mut s = String::new();
f.read_to_string(&mut s).unwrap();
let mut table: HashMap<String, Vec<ToolType>> = toml::from_str(s.as_str()).unwrap();
ToolTable(table.remove("tools".into()).unwrap())
}
fn load_tech_table() -> TechTable {
let path = PathBuf::from("data/shops/techniques.toml");
let mut f = File::open(path).unwrap();
let mut s = String::new();
f.read_to_string(&mut s).unwrap();
let mut table: HashMap<String, Vec<TechTierDeserialize>> = toml::from_str(s.as_str()).unwrap();
let techniques = table.remove("techniques".into()).unwrap();
let techniques = techniques.into_iter()
.map(|tech_tier| {
TechTier {
level: tech_tier.level,
techs: tech_tier.techs.into_iter()
.map(|(tech_name, tech_entry)| {
(tech_name.parse().unwrap(), tech_entry)
}).collect()
}
}).collect();
TechTable(techniques)
}
fn number_of_techs_to_generate(character_level: usize) -> usize {
if character_level <= 10 {
4
}
else if character_level <= 25 {
5
}
else if character_level <= 42 {
6
}
else {
7
}
}
#[derive(Debug)]
struct ToolShop<R: Rng + SeedableRng> {
tools: ToolTable,
techs: TechTable,
rng: R,
}
impl<R: Rng + SeedableRng> ToolShop<R> {
pub fn new() -> ToolShop<R> {
ToolShop {
tools: load_tool_table(),
techs: load_tech_table(),
rng: R::from_entropy(),
}
}
fn generate_tech(&mut self, character_level: usize) -> ShopTool {
let tier = self.techs.0.iter()
.filter(|t| t.level <= character_level)
.last()
.unwrap();
let mut tier = tier.techs.iter()
.map(|(tech, entry)| {
(tech, entry)
});
let tech_choice = WeightedIndex::new(tier.clone().map(|(_, e)| e.probability)).unwrap();
let tech_detail = tier.nth(tech_choice.sample(&mut self.rng)).unwrap();
let tech_level = match tech_detail.1.level {
TechLevel::Set{set_level} => set_level,
TechLevel::Level{level_divisor} => std::cmp::max(std::cmp::min(character_level, 99)/level_divisor, 1),
TechLevel::Range{min, max} => self.rng.gen_range(min, max+1),
};
ShopTool::Tech(
TechniqueDisk {
tech: *tech_detail.0,
level: tech_level as u32,
}
)
}
fn generate_tech_types(&mut self, character_level: usize) -> Vec<Technique> {
let tier = self.techs.0.iter()
.filter(|t| t.level <= character_level)
.last()
.unwrap();
let possible_techs = tier.techs.iter()
.filter(|(_, entry)| entry.probability > 0)
.collect::<Vec<_>>();
let number_of_techs = std::cmp::min(possible_techs.len(), number_of_techs_to_generate(character_level));
if number_of_techs == possible_techs.len() {
possible_techs.into_iter()
.map(|(tech, _entry)| {
tech
})
.cloned()
.collect()
}
else {
let mut techs = Vec::new();
let tier = tier.techs.iter()
.map(|(tech, entry)| {
(tech, entry)
})
.collect::<Vec<_>>();
let tech_choice = WeightedIndex::new(tier.iter().map(|(_, e)| e.probability)).unwrap();
while techs.len() < number_of_techs {
let tech_detail = tier.get(tech_choice.sample(&mut self.rng)).unwrap();
if techs.iter().find(|t| *t == tech_detail.0).is_none() {
techs.push(*tech_detail.0);
}
}
techs
}
}
fn generate_techs(&mut self, character_level: usize) -> Vec<ShopTool> {
let tier = self.techs.0.iter()
.filter(|t| t.level <= character_level)
.last()
.cloned()
.unwrap();
let tech_types = self.generate_tech_types(character_level);
tech_types.into_iter()
.map(|tech| {
let tech_detail = tier.techs.get(&tech).unwrap().clone();
let level = match tech_detail.level {
TechLevel::Set{set_level} => set_level,
TechLevel::Level{level_divisor} => std::cmp::max(std::cmp::min(character_level, 99)/level_divisor, 1),
TechLevel::Range{min, max} => self.rng.gen_range(min, max+1),
};
ShopTool::Tech(TechniqueDisk {
tech: tech,
level: level as u32,
})
})
.collect()
}
pub fn generate_tool_list(&mut self, character_level: usize) -> Vec<ShopTool> {
let mut tools = Vec::new().into_iter()
.chain(self.tools.0.clone().into_iter().map(|t| ShopTool::Tool(t)))
.chain(self.generate_techs(character_level).into_iter())
.collect::<Vec<_>>();
tools.sort();
tools
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_loading_tool_shop() {
ToolShop::<rand_chacha::ChaCha20Rng>::new();
}
}
Loading…
Cancel
Save