fmt: repo-wide baseline (WI-2, issue #2)

This commit is contained in:
Jan-Peter von Hunnius 2026-10-03 11:53:59 +02:00
parent 899fde8fc3
commit 337e9bcf2c
19 changed files with 847 additions and 335 deletions

View file

@ -1,5 +1,5 @@
use sb_shared::{Character, CharacterStats, Class, Race};
use crate::spells;
use sb_shared::{Character, CharacterStats, Class, Race};
pub struct TrainingGround {
pub stat: &'static str,
@ -8,11 +8,31 @@ pub struct TrainingGround {
}
pub const TRAINING_GROUNDS: &[TrainingGround] = &[
TrainingGround { stat: "strength", name: "The Anvil", description: "Pound steel and lift stone under the guidance of master smiths." },
TrainingGround { stat: "dexterity", name: "The Archery Range", description: "Sharpen reflexes with bow, blade, and balance drills." },
TrainingGround { stat: "constitution", name: "The Endurance Pits", description: "Push your body past its limits in grueling trials of resilience." },
TrainingGround { stat: "intelligence", name: "The Sage's Study", description: "Study ancient tomes and practice arcane disciplines." },
TrainingGround { stat: "luck", name: "Fortune's Shrine", description: "Consult oracles and tempt fate in games of chance." },
TrainingGround {
stat: "strength",
name: "The Anvil",
description: "Pound steel and lift stone under the guidance of master smiths.",
},
TrainingGround {
stat: "dexterity",
name: "The Archery Range",
description: "Sharpen reflexes with bow, blade, and balance drills.",
},
TrainingGround {
stat: "constitution",
name: "The Endurance Pits",
description: "Push your body past its limits in grueling trials of resilience.",
},
TrainingGround {
stat: "intelligence",
name: "The Sage's Study",
description: "Study ancient tomes and practice arcane disciplines.",
},
TrainingGround {
stat: "luck",
name: "Fortune's Shrine",
description: "Consult oracles and tempt fate in games of chance.",
},
];
pub struct RaceInfo {
@ -26,11 +46,51 @@ pub struct RaceInfo {
}
pub const RACES: &[RaceInfo] = &[
RaceInfo { race: Race::Human, name: "Human", str_mod: 0, int_mod: 0, dex_mod: 0, con_mod: 0, luck_mod: 0 },
RaceInfo { race: Race::Elf, name: "Elf", str_mod: -2, int_mod: 4, dex_mod: 2, con_mod: -2, luck_mod: 0 },
RaceInfo { race: Race::Dwarf, name: "Dwarf", str_mod: 2, int_mod: -2, dex_mod: -2, con_mod: 4, luck_mod: 0 },
RaceInfo { race: Race::Hobbit, name: "Hobbit", str_mod: -4, int_mod: 0, dex_mod: 2, con_mod: -2, luck_mod: 4 },
RaceInfo { race: Race::HalfElf, name: "Half-Elf", str_mod: 0, int_mod: 2, dex_mod: 2, con_mod: 0, luck_mod: 0 },
RaceInfo {
race: Race::Human,
name: "Human",
str_mod: 0,
int_mod: 0,
dex_mod: 0,
con_mod: 0,
luck_mod: 0,
},
RaceInfo {
race: Race::Elf,
name: "Elf",
str_mod: -2,
int_mod: 4,
dex_mod: 2,
con_mod: -2,
luck_mod: 0,
},
RaceInfo {
race: Race::Dwarf,
name: "Dwarf",
str_mod: 2,
int_mod: -2,
dex_mod: -2,
con_mod: 4,
luck_mod: 0,
},
RaceInfo {
race: Race::Hobbit,
name: "Hobbit",
str_mod: -4,
int_mod: 0,
dex_mod: 2,
con_mod: -2,
luck_mod: 4,
},
RaceInfo {
race: Race::HalfElf,
name: "Half-Elf",
str_mod: 0,
int_mod: 2,
dex_mod: 2,
con_mod: 0,
luck_mod: 0,
},
];
pub struct ClassInfo {
@ -43,16 +103,86 @@ pub struct ClassInfo {
}
pub const CLASSES: &[ClassInfo] = &[
ClassInfo { class: Class::Warrior, name: "Warrior", primary_stat: "strength", secondary_stat: "constitution", base_hp: 20, hp_per_con: 3.0 },
ClassInfo { class: Class::Paladin, name: "Paladin", primary_stat: "strength", secondary_stat: "luck", base_hp: 18, hp_per_con: 2.5 },
ClassInfo { class: Class::Rogue, name: "Rogue", primary_stat: "dexterity", secondary_stat: "luck", base_hp: 14, hp_per_con: 2.0 },
ClassInfo { class: Class::Bard, name: "Bard", primary_stat: "dexterity", secondary_stat: "intelligence", base_hp: 14, hp_per_con: 2.0 },
ClassInfo { class: Class::Hunter, name: "Hunter", primary_stat: "dexterity", secondary_stat: "strength", base_hp: 16, hp_per_con: 2.5 },
ClassInfo { class: Class::Monk, name: "Monk", primary_stat: "dexterity", secondary_stat: "constitution", base_hp: 15, hp_per_con: 2.5 },
ClassInfo { class: Class::Mage, name: "Mage", primary_stat: "intelligence", secondary_stat: "dexterity", base_hp: 11, hp_per_con: 1.8 },
ClassInfo { class: Class::Wizard, name: "Wizard", primary_stat: "intelligence", secondary_stat: "constitution", base_hp: 10, hp_per_con: 1.5 },
ClassInfo { class: Class::Conjurer, name: "Conjurer", primary_stat: "intelligence", secondary_stat: "luck", base_hp: 10, hp_per_con: 1.5 },
ClassInfo { class: Class::Sorcerer, name: "Sorcerer", primary_stat: "intelligence", secondary_stat: "strength", base_hp: 12, hp_per_con: 2.0 },
ClassInfo {
class: Class::Warrior,
name: "Warrior",
primary_stat: "strength",
secondary_stat: "constitution",
base_hp: 20,
hp_per_con: 3.0,
},
ClassInfo {
class: Class::Paladin,
name: "Paladin",
primary_stat: "strength",
secondary_stat: "luck",
base_hp: 18,
hp_per_con: 2.5,
},
ClassInfo {
class: Class::Rogue,
name: "Rogue",
primary_stat: "dexterity",
secondary_stat: "luck",
base_hp: 14,
hp_per_con: 2.0,
},
ClassInfo {
class: Class::Bard,
name: "Bard",
primary_stat: "dexterity",
secondary_stat: "intelligence",
base_hp: 14,
hp_per_con: 2.0,
},
ClassInfo {
class: Class::Hunter,
name: "Hunter",
primary_stat: "dexterity",
secondary_stat: "strength",
base_hp: 16,
hp_per_con: 2.5,
},
ClassInfo {
class: Class::Monk,
name: "Monk",
primary_stat: "dexterity",
secondary_stat: "constitution",
base_hp: 15,
hp_per_con: 2.5,
},
ClassInfo {
class: Class::Mage,
name: "Mage",
primary_stat: "intelligence",
secondary_stat: "dexterity",
base_hp: 11,
hp_per_con: 1.8,
},
ClassInfo {
class: Class::Wizard,
name: "Wizard",
primary_stat: "intelligence",
secondary_stat: "constitution",
base_hp: 10,
hp_per_con: 1.5,
},
ClassInfo {
class: Class::Conjurer,
name: "Conjurer",
primary_stat: "intelligence",
secondary_stat: "luck",
base_hp: 10,
hp_per_con: 1.5,
},
ClassInfo {
class: Class::Sorcerer,
name: "Sorcerer",
primary_stat: "intelligence",
secondary_stat: "strength",
base_hp: 12,
hp_per_con: 2.0,
},
];
pub fn stat_bonus(stat: i64) -> i64 {
@ -65,7 +195,10 @@ fn roll_stat(rng: &mut impl rand::Rng, modifier: i64) -> i64 {
}
pub fn roll_stats(rng: &mut impl rand::Rng, race: &Race) -> CharacterStats {
let info = RACES.iter().find(|r| &r.race == race).expect("invalid race");
let info = RACES
.iter()
.find(|r| &r.race == race)
.expect("invalid race");
CharacterStats {
strength: roll_stat(rng, info.str_mod),
intelligence: roll_stat(rng, info.int_mod),
@ -76,17 +209,26 @@ pub fn roll_stats(rng: &mut impl rand::Rng, race: &Race) -> CharacterStats {
}
pub fn calc_max_hp(class: &Class, stats: &CharacterStats) -> i32 {
let info = CLASSES.iter().find(|c| &c.class == class).expect("invalid class");
let info = CLASSES
.iter()
.find(|c| &c.class == class)
.expect("invalid class");
(info.base_hp as f64 + stats.constitution as f64 * info.hp_per_con) as i32
}
pub fn calc_max_energy(class: &Class) -> i32 {
let info = CLASSES.iter().find(|c| &c.class == class).expect("invalid class");
let info = CLASSES
.iter()
.find(|c| &c.class == class)
.expect("invalid class");
30 + info.base_hp / 3
}
pub fn calc_max_nerve(class: &Class) -> i32 {
let info = CLASSES.iter().find(|c| &c.class == class).expect("invalid class");
let info = CLASSES
.iter()
.find(|c| &c.class == class)
.expect("invalid class");
100 + info.base_hp / 2
}
@ -104,7 +246,9 @@ pub fn hp_regen_rate() -> i64 {
pub fn apply_regen(char: &mut Character, now_ms: i64) {
let elapsed = now_ms - char.last_regen;
if elapsed <= 0 { return; }
if elapsed <= 0 {
return;
}
let energy_ticks = (elapsed / energy_regen_rate()) as i32;
let nerve_ticks = (elapsed / nerve_regen_rate()) as i32;
let hp_ticks = (elapsed / hp_regen_rate()) as i32;
@ -140,7 +284,8 @@ pub fn create_character(
let max_nerve = calc_max_nerve(&class);
let known_spells: Vec<String> = if spells::is_caster_class(&class_str) {
spells::spells_for_class(&class_str, 1).iter()
spells::spells_for_class(&class_str, 1)
.iter()
.filter(|s| s.spell_level <= 1)
.map(|s| s.id.clone())
.collect()
@ -177,7 +322,9 @@ pub fn create_character(
("ring".into(), None),
("trinket".into(), None),
("instrument".into(), None),
].into_iter().collect(),
]
.into_iter()
.collect(),
inventory: Vec::new(),
active_song: None,
known_spells,
@ -191,7 +338,9 @@ pub const MAX_LEVEL: i32 = 100;
pub const XP_FACTOR: i64 = 18;
pub fn xp_for_level(level: i32) -> i64 {
if level <= 1 { return 0; }
if level <= 1 {
return 0;
}
let n = (level - 1) as f64;
XP_FACTOR * (100.0 * n * n) as i64
}
@ -227,11 +376,17 @@ pub fn level_up(char: &mut Character) -> Result<i32, &'static str> {
}
pub fn find_race_info(race: &Race) -> &'static RaceInfo {
RACES.iter().find(|r| &r.race == race).expect("invalid race")
RACES
.iter()
.find(|r| &r.race == race)
.expect("invalid race")
}
pub fn find_class_info(class: &Class) -> &'static ClassInfo {
CLASSES.iter().find(|c| &c.class == class).expect("invalid class")
CLASSES
.iter()
.find(|c| &c.class == class)
.expect("invalid class")
}
#[cfg(test)]
@ -242,15 +397,35 @@ mod tests {
fn base_char() -> Character {
Character {
id: 1, user_id: 1, name: "Test".into(),
race: Race::Human, class: Class::Warrior,
level: 1, xp: 0,
stats: CharacterStats { strength: 20, intelligence: 20, dexterity: 20, constitution: 20, luck: 20 },
hp: 80, max_hp: 80, energy: 36, max_energy: 36,
nerve: 110, max_nerve: 110, gold: 0, last_regen: 0,
equipment: HashMap::new(), inventory: Vec::new(),
active_song: None, known_spells: Vec::new(),
active_spell: None, spell_points: 0, max_spell_points: 0,
id: 1,
user_id: 1,
name: "Test".into(),
race: Race::Human,
class: Class::Warrior,
level: 1,
xp: 0,
stats: CharacterStats {
strength: 20,
intelligence: 20,
dexterity: 20,
constitution: 20,
luck: 20,
},
hp: 80,
max_hp: 80,
energy: 36,
max_energy: 36,
nerve: 110,
max_nerve: 110,
gold: 0,
last_regen: 0,
equipment: HashMap::new(),
inventory: Vec::new(),
active_song: None,
known_spells: Vec::new(),
active_spell: None,
spell_points: 0,
max_spell_points: 0,
}
}
@ -351,8 +526,20 @@ mod tests {
#[test]
fn calc_max_hp_depends_on_class_and_con() {
let stats_high = CharacterStats { strength: 10, intelligence: 10, dexterity: 10, constitution: 30, luck: 10 };
let stats_low = CharacterStats { strength: 10, intelligence: 10, dexterity: 10, constitution: 10, luck: 10 };
let stats_high = CharacterStats {
strength: 10,
intelligence: 10,
dexterity: 10,
constitution: 30,
luck: 10,
};
let stats_low = CharacterStats {
strength: 10,
intelligence: 10,
dexterity: 10,
constitution: 10,
luck: 10,
};
let hp_high = calc_max_hp(&Class::Warrior, &stats_high);
let hp_low = calc_max_hp(&Class::Warrior, &stats_low);
assert!(hp_high > hp_low);
@ -396,7 +583,7 @@ mod tests {
#[test]
fn roll_stats_returns_all_five() {
use rand:: SeedableRng;
use rand::SeedableRng;
let mut rng = rand::rngs::StdRng::seed_from_u64(42);
let stats = roll_stats(&mut rng, &Race::Human);
assert!(stats.strength >= 6 && stats.strength <= 16);
@ -408,7 +595,7 @@ mod tests {
#[test]
fn race_modifiers_apply() {
use rand:: SeedableRng;
use rand::SeedableRng;
let mut rng = rand::rngs::StdRng::seed_from_u64(42);
let human = roll_stats(&mut rng, &Race::Human);
let mut rng2 = rand::rngs::StdRng::seed_from_u64(42);