Compare commits
2 commits
64e081aeb7
...
899fde8fc3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
899fde8fc3 | ||
|
|
61fef27917 |
2 changed files with 44 additions and 7 deletions
|
|
@ -25,6 +25,11 @@ use sb_shared::{
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
fn request_rng() -> rand::rngs::StdRng {
|
||||||
|
use rand::SeedableRng;
|
||||||
|
rand::rngs::StdRng::from_os_rng()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct AppState {
|
pub(crate) struct AppState {
|
||||||
users: RwLock<Vec<User>>,
|
users: RwLock<Vec<User>>,
|
||||||
items: Vec<Item>,
|
items: Vec<Item>,
|
||||||
|
|
@ -285,7 +290,10 @@ async fn create_character(
|
||||||
return Err(axum::http::StatusCode::BAD_REQUEST);
|
return Err(axum::http::StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut char = character::create_character(user_id, name, input.race, input.class);
|
let mut char = {
|
||||||
|
let mut rng = request_rng();
|
||||||
|
character::create_character(&mut rng, user_id, name, input.race, input.class)
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut id = state.next_char_id.write().await;
|
let mut id = state.next_char_id.write().await;
|
||||||
|
|
@ -424,6 +432,8 @@ async fn run_adventure(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_millis() as i64;
|
.as_millis() as i64;
|
||||||
|
|
||||||
|
let mut rng = request_rng();
|
||||||
|
|
||||||
let (char, enemy_def) = {
|
let (char, enemy_def) = {
|
||||||
let mut chars = state.characters.write().await;
|
let mut chars = state.characters.write().await;
|
||||||
let char = chars.iter_mut().find(|c| c.id == char_id)
|
let char = chars.iter_mut().find(|c| c.id == char_id)
|
||||||
|
|
@ -439,7 +449,6 @@ async fn run_adventure(
|
||||||
}
|
}
|
||||||
char.nerve -= zone.nerve_cost;
|
char.nerve -= zone.nerve_cost;
|
||||||
|
|
||||||
let mut rng = rand::rng();
|
|
||||||
let enemy = domain::pick_enemy(&mut rng, &zone.encounters, &state.enemies);
|
let enemy = domain::pick_enemy(&mut rng, &zone.encounters, &state.enemies);
|
||||||
(char.clone(), enemy)
|
(char.clone(), enemy)
|
||||||
};
|
};
|
||||||
|
|
@ -494,14 +503,13 @@ async fn run_adventure(
|
||||||
songs::BARD_SONGS.iter().find(|s| s.id == sid).map(|s| s.combat_effect)
|
songs::BARD_SONGS.iter().find(|s| s.id == sid).map(|s| s.combat_effect)
|
||||||
}),
|
}),
|
||||||
spell_effect.as_ref(),
|
spell_effect.as_ref(),
|
||||||
&mut rand::rng(),
|
&mut rng,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (loot_names, updated_char) = {
|
let (loot_names, updated_char) = {
|
||||||
let mut chars = state.characters.write().await;
|
let mut chars = state.characters.write().await;
|
||||||
let dropped_ids: Vec<String> = if let Some(c) = chars.iter_mut().find(|c| c.id == char_id) {
|
let dropped_ids: Vec<String> = if let Some(c) = chars.iter_mut().find(|c| c.id == char_id) {
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
let mut rng = rand::rng();
|
|
||||||
|
|
||||||
if log.winner == c.name {
|
if log.winner == c.name {
|
||||||
c.xp += log.xp_gained as i64;
|
c.xp += log.xp_gained as i64;
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,15 @@ pub fn training_cost(stat: i64) -> i32 {
|
||||||
(5.0_f64 * 1.3_f64.powi(scaled)) as i32
|
(5.0_f64 * 1.3_f64.powi(scaled)) as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_character(user_id: u32, name: String, race: Race, class: Class) -> Character {
|
pub fn create_character(
|
||||||
let mut rng = rand::rng();
|
rng: &mut impl rand::Rng,
|
||||||
|
user_id: u32,
|
||||||
|
name: String,
|
||||||
|
race: Race,
|
||||||
|
class: Class,
|
||||||
|
) -> Character {
|
||||||
let class_str = class.as_str().to_string();
|
let class_str = class.as_str().to_string();
|
||||||
let stats = roll_stats(&mut rng, &race);
|
let stats = roll_stats(rng, &race);
|
||||||
let max_hp = calc_max_hp(&class, &stats);
|
let max_hp = calc_max_hp(&class, &stats);
|
||||||
let max_energy = calc_max_energy(&class);
|
let max_energy = calc_max_energy(&class);
|
||||||
let max_nerve = calc_max_nerve(&class);
|
let max_nerve = calc_max_nerve(&class);
|
||||||
|
|
@ -412,4 +417,28 @@ mod tests {
|
||||||
assert!(dwarf.strength > human.strength);
|
assert!(dwarf.strength > human.strength);
|
||||||
assert!(dwarf.intelligence < human.intelligence);
|
assert!(dwarf.intelligence < human.intelligence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_character_is_deterministic_under_seeded_rng() {
|
||||||
|
use rand::SeedableRng;
|
||||||
|
let first = create_character(
|
||||||
|
&mut rand::rngs::StdRng::seed_from_u64(42),
|
||||||
|
7,
|
||||||
|
"Twin".into(),
|
||||||
|
Race::Human,
|
||||||
|
Class::Warrior,
|
||||||
|
);
|
||||||
|
let second = create_character(
|
||||||
|
&mut rand::rngs::StdRng::seed_from_u64(42),
|
||||||
|
7,
|
||||||
|
"Twin".into(),
|
||||||
|
Race::Human,
|
||||||
|
Class::Warrior,
|
||||||
|
);
|
||||||
|
assert_eq!(format!("{:?}", first.stats), format!("{:?}", second.stats));
|
||||||
|
assert_eq!(first.hp, second.hp);
|
||||||
|
assert_eq!(first.max_hp, second.max_hp);
|
||||||
|
assert_eq!(first.energy, second.energy);
|
||||||
|
assert_eq!(first.nerve, second.nerve);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue