mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Loot tables
This commit is contained in:
parent
1374900928
commit
f65cd1e771
@ -1,18 +1,29 @@
|
||||
#![deny(clippy::clone_on_ref_ptr)]
|
||||
|
||||
use std::error::Error;
|
||||
use std::{
|
||||
error::Error,
|
||||
io::Write,
|
||||
ops::{Div, Mul},
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use comp::item::{
|
||||
armor::{ArmorKind, Protection},
|
||||
tool::{Hands, MaterialStatManifest, Tool, ToolKind},
|
||||
ItemKind,
|
||||
use veloren_common::{
|
||||
assets::AssetExt,
|
||||
comp::{
|
||||
self,
|
||||
item::{
|
||||
armor::{ArmorKind, Protection},
|
||||
tool::{Hands, MaterialStatManifest, Tool, ToolKind},
|
||||
ItemKind,
|
||||
},
|
||||
},
|
||||
lottery::Lottery,
|
||||
};
|
||||
use veloren_common::comp;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct Cli {
|
||||
/// Available arguments: "armor_stats", "weapon_stats", "all_items"
|
||||
/// Available arguments: "armor-stats", "weapon-stats", "all-items",
|
||||
/// "loot-table"
|
||||
function: String,
|
||||
}
|
||||
|
||||
@ -205,6 +216,32 @@ fn all_items() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn loot_table(loot_table: &str) -> Result<(), Box<dyn Error>> {
|
||||
let mut wtr = csv::Writer::from_path("loot_table.csv")?;
|
||||
wtr.write_record(&["Item", "Relative Chance"])?;
|
||||
|
||||
let loot_table = "common.loot_tables.".to_owned() + loot_table;
|
||||
|
||||
let loot_table = Lottery::<String>::load_expect(&loot_table).read();
|
||||
|
||||
for (i, (chance, item)) in loot_table.iter().enumerate() {
|
||||
let chance = if let Some((next_chance, _)) = loot_table.iter().nth(i + 1) {
|
||||
next_chance - chance
|
||||
} else {
|
||||
loot_table.total() - chance
|
||||
}
|
||||
.mul(10_f32.powi(5))
|
||||
.round()
|
||||
.div(10_f32.powi(5))
|
||||
.to_string();
|
||||
|
||||
wtr.write_record(&[item, &chance])?;
|
||||
}
|
||||
|
||||
wtr.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Cli::from_args();
|
||||
if args.function.eq_ignore_ascii_case("armor-stats") {
|
||||
@ -219,10 +256,30 @@ fn main() {
|
||||
if let Err(e) = all_items() {
|
||||
println!("Error: {}\n", e)
|
||||
}
|
||||
} else if args.function.eq_ignore_ascii_case("loot-table") {
|
||||
let loot_table_name = get_input(
|
||||
"Specify the name of the loot table to export to csv. Assumes loot table is in \
|
||||
directory: assets.common.loot_tables.\n",
|
||||
);
|
||||
if let Err(e) = loot_table(&loot_table_name) {
|
||||
println!("Error: {}\n", e)
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"Invalid argument, available \
|
||||
arguments:\n\"armor-stats\"\n\"weapon-stats\"\n\"all-items\""
|
||||
arguments:\n\"armor-stats\"\n\"weapon-stats\"\n\"all-items\"\n\"loot-table [table]\""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_input(prompt: &str) -> String {
|
||||
// Function to get input from the user with a prompt
|
||||
let mut input = String::new();
|
||||
print!("{}", prompt);
|
||||
std::io::stdout().flush().unwrap();
|
||||
std::io::stdin()
|
||||
.read_line(&mut input)
|
||||
.expect("Error reading input");
|
||||
|
||||
String::from(input.trim())
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use veloren_common::{assets::ASSETS_PATH, comp};
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct Cli {
|
||||
/// Available arguments: "armor_stats", "weapon_stats"
|
||||
/// Available arguments: "armor-stats", "weapon-stats", "loot-table"
|
||||
function: String,
|
||||
}
|
||||
|
||||
@ -361,6 +361,48 @@ fn weapon_stats() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn loot_table(loot_table: &str) -> Result<(), Box<dyn Error>> {
|
||||
let mut rdr = csv::Reader::from_path("loot_table.csv")?;
|
||||
|
||||
let headers: HashMap<String, usize> = rdr
|
||||
.headers()
|
||||
.expect("Failed to read CSV headers")
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, x)| (x.to_string(), i))
|
||||
.collect();
|
||||
|
||||
let mut items = Vec::<(f32, String)>::new();
|
||||
|
||||
for record in rdr.records() {
|
||||
if let Ok(ref record) = record {
|
||||
let item = record.get(headers["Item"]).expect("No item");
|
||||
let chance: f32 = record
|
||||
.get(headers["Relative Chance"])
|
||||
.expect("No chance for item in entry")
|
||||
.parse()
|
||||
.expect("Not an f32 for chance in entry");
|
||||
items.push((chance, item.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
let pretty_config = PrettyConfig::new()
|
||||
.with_depth_limit(4)
|
||||
.with_decimal_floats(true);
|
||||
|
||||
let mut path = ASSETS_PATH.clone();
|
||||
path.push("common");
|
||||
path.push("loot_tables");
|
||||
path.push(loot_table);
|
||||
path.set_extension("ron");
|
||||
|
||||
let path_str = path.to_str().expect("File path not unicode?!");
|
||||
let mut writer = File::create(path_str)?;
|
||||
write!(writer, "{}", to_string_pretty(&items, pretty_config)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Cli::from_args();
|
||||
if args.function.eq_ignore_ascii_case("armor-stats") {
|
||||
@ -423,8 +465,45 @@ Would you like to continue? (y/n)
|
||||
println!("Error: {}\n", e)
|
||||
}
|
||||
}
|
||||
} else if args.function.eq_ignore_ascii_case("loot-table") {
|
||||
let loot_table_name = get_input(
|
||||
"Specify the name of the loot table to import from csv. Adds loot table to the \
|
||||
directory: assets.common.loot_tables.\n",
|
||||
);
|
||||
if get_input(
|
||||
"
|
||||
-------------------------------------------------------------------------------
|
||||
| DISCLAIMER |
|
||||
-------------------------------------------------------------------------------
|
||||
| |
|
||||
| This script will wreck the RON file for a loot table if it messes up. |
|
||||
| You might want to save a back up of the loot table or be prepared to |
|
||||
| use `git checkout HEAD -- ../assets/common/loot_tables/*` if needed. |
|
||||
| If this script does mess up your files, please fix it. Otherwise your |
|
||||
| files will be yeeted away and you will get a bonk on the head. |
|
||||
| |
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
In order for this script to work, you need to have first run the csv exporter.
|
||||
Once you have loot_table.csv you can make changes to item drops and their drop
|
||||
chance in your preferred editor. Save the csv file and then run this script
|
||||
to import your changes back to RON.
|
||||
|
||||
Would you like to continue? (y/n)
|
||||
> ",
|
||||
)
|
||||
.to_lowercase()
|
||||
== "y".to_string()
|
||||
{
|
||||
if let Err(e) = loot_table(&loot_table_name) {
|
||||
println!("Error: {}\n", e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Invalid argument, available arguments:\n\"armor-stats\"\n\"weapon-stats\"\n\"")
|
||||
println!(
|
||||
"Invalid argument, available \
|
||||
arguments:\n\"armor-stats\"\n\"weapon-stats\"\n\"loot-table\"\n\""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,8 @@ impl<T> Lottery<T> {
|
||||
pub fn choose(&self) -> &T { self.choose_seeded(thread_rng().gen()) }
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &(f32, T)> { self.items.iter() }
|
||||
|
||||
pub fn total(&self) -> f32 { self.total }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Loading…
Reference in New Issue
Block a user