char creation to config

This commit is contained in:
Llywelwyn 2023-08-23 01:57:35 +01:00
parent 424bf43ed5
commit 15e8ae13d0
9 changed files with 82 additions and 46 deletions

26
src/config/char_create.rs Normal file
View file

@ -0,0 +1,26 @@
// --- GUI ---
pub const ANCESTRY_INFO_HEADER: &str = "Your ancestry grants...";
pub const CLASS_INFO_HEADER: &str = "Your class grants...";
// --- ANCESTRY RENDERABLES ---
pub const ELF_GLYPH: char = '@';
pub const ELF_COLOUR: (u8, u8, u8) = (0, 255, 0);
pub const DWARF_GLYPH: char = 'h';
pub const DWARF_COLOUR: (u8, u8, u8) = (255, 0, 0);
pub const CATFOLK_GLYPH: char = '@';
pub const CATFOLK_COLOUR: (u8, u8, u8) = (200, 200, 255);
// --- ANCESTRY BONUSES ---
pub const ELF_SPEED_BONUS: i32 = 1;
pub const ELF_TELEPATH_RANGE: i32 = 6;
pub const DWARF_DEFENCE_MOD: i32 = 1;
pub const CATFOLK_SPEED_BONUS: i32 = 2;
// --- CLASS STARTING ITEMS ---
pub const FIGHTER_STARTING_FOOD: &str = "1d2+1";
pub const FIGHTER_STARTING_WEAPON: &str = "equip_shortsword";
pub const FIGHTER_STARTING_ARMOUR: &str = "equip_body_ringmail";
pub const FIGHTER_STARTING_SHIELD: &str = "equip_mediumshield";
pub const ROGUE_STARTING_FOOD: &str = "1d2+2";
pub const WIZARD_STARTING_FOOD: &str = "1d2+1";
pub const WIZARD_MAX_SCROLL_LVL: i32 = 3;
pub const WIZARD_SCROLL_AMOUNT: &str = "1d3";
pub const WIZARD_POTION_AMOUNT: &str = "1d3-1";
pub const VILLAGER_STARTING_FOOD: &str = "1d3+2";

View file

@ -1,5 +1,12 @@
pub const DEFAULT_VIEWSHED_STANDARD: i32 = 16; // Standard viewshed radius for almost all entities. pub const DEFAULT_VIEWSHED_STANDARD: i32 = 16; // Standard viewshed radius for almost all entities.
pub const CARRY_CAPACITY_PER_STRENGTH: i32 = 8; pub const CARRY_CAPACITY_PER_STRENGTH: i32 = 8; // How much weight can be carried per point of strength.
pub const NORMAL_SPEED: i32 = 12; // Normal speed for almost all entities.
pub const NORMAL_SPEED: i32 = 12; // Normal speed for almost all entities. pub const TURN_COST_MULTIPLIER: i32 = 4; // How many ticks for NORMAL_SPEED to get a turn.
pub const TURN_COST_MULTIPLIER: i32 = 4; // How many ticks per turn for an entity with NORMAL_SPEED. pub const ATTR_BONUS_0: i32 = 10; // At this value, the attribute bonus is 0.
pub const ATTR_NEEDED_PER_POINT: i32 = 2; // How many points +- ATTR_BONUS_0 are needed per +- 1 bonus.
pub const STANDARD_HIT_DIE: i32 = 8; // Standard hit die used for rolling HP.
pub const STANDARD_HIT_DIE_0: i32 = 4; // Standard hit die used for rolling HP for level 0.
pub const STANDARD_MANA_DIE: i32 = 4; // Standard mana die used for rolling mana.
pub const MINIMUM_MANA: i32 = 0; // The minimum mana a monster can have.
pub const MINIMUM_MANA_PLAYER: i32 = 1; // The minimum mana a player can have.
pub const STANDARD_BAC: i32 = 10; // Standard BASE AC.

View file

@ -2,6 +2,7 @@ pub mod entity;
pub mod visuals; pub mod visuals;
pub mod glyphs; pub mod glyphs;
pub mod messages; pub mod messages;
pub mod char_create;
pub const SHOW_MAPGEN: bool = false; pub const SHOW_MAPGEN: bool = false;
pub const LOG_SPAWNING: bool = true; pub const LOG_SPAWNING: bool = true;

View file

@ -9,9 +9,8 @@ use crate::{
Map, Map,
Player, Player,
Pools, Pools,
DEFAULT_PARTICLE_LIFETIME,
LONG_PARTICLE_LIFETIME,
}; };
use crate::config::visuals::{ DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;

View file

@ -1,23 +1,24 @@
use super::{ Skill, Skills }; use super::{ Skill, Skills };
use crate::gui::{ Ancestry, Class }; use crate::gui::{ Ancestry, Class };
use crate::config::entity;
use rltk::prelude::*; use rltk::prelude::*;
use std::cmp::max; use std::cmp::max;
/// Returns the attribute bonus for a given attribute score, where every 2 points above /// Returns the attribute bonus for a given attribute score, where every 2 points above
/// or below 10 is an additional +1 or -1. /// or below 10 is an additional +1 or -1.
pub fn attr_bonus(value: i32) -> i32 { pub fn attr_bonus(value: i32) -> i32 {
return (value - 10) / 2; return (value - entity::ATTR_BONUS_0) / entity::ATTR_NEEDED_PER_POINT;
} }
/// Returns the number of HP gained per level for a given constitution score. /// Returns the number of HP gained per level for a given constitution score.
pub fn hp_per_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32) -> i32 { pub fn hp_per_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32) -> i32 {
return max(rng.roll_dice(1, 8) + attr_bonus(constitution), 1); return max(rng.roll_dice(1, entity::STANDARD_HIT_DIE) + attr_bonus(constitution), 1);
} }
#[allow(dead_code)] #[allow(dead_code)]
/// Returns a total HP roll for a player, based on a given constitution score and level. /// Returns a total HP roll for a player, based on a given constitution score and level.
pub fn player_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 { pub fn player_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
let mut total = 8 + attr_bonus(constitution); let mut total = entity::STANDARD_HIT_DIE + attr_bonus(constitution);
for _i in 0..level { for _i in 0..level {
total += hp_per_level(rng, constitution); total += hp_per_level(rng, constitution);
} }
@ -27,23 +28,23 @@ pub fn player_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i
/// Returns a total HP roll for an NPC, based on a given constitution score and level. /// Returns a total HP roll for an NPC, based on a given constitution score and level.
pub fn npc_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 { pub fn npc_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
if level == 0 { if level == 0 {
return rng.roll_dice(1, 4); return rng.roll_dice(1, entity::STANDARD_HIT_DIE_0);
} }
let mut total = 1; let mut total = 1;
for _i in 0..level { for _i in 0..level {
total += rng.roll_dice(1, 8) + attr_bonus(constitution); total += rng.roll_dice(1, entity::STANDARD_HIT_DIE) + attr_bonus(constitution);
} }
return total; return total;
} }
/// Returns the number of mana gained per level for a given intelligence score. /// Returns the number of mana gained per level for a given intelligence score.
pub fn mana_per_level(rng: &mut rltk::RandomNumberGenerator, intelligence: i32) -> i32 { pub fn mana_per_level(rng: &mut rltk::RandomNumberGenerator, intelligence: i32) -> i32 {
return max(rng.roll_dice(1, 4) + attr_bonus(intelligence), 1); return max(rng.roll_dice(1, entity::STANDARD_MANA_DIE) + attr_bonus(intelligence), 1);
} }
/// Returns the number of mana gained per level for a given intelligence score. /// Returns the number of mana gained per level for a given intelligence score.
pub fn mana_at_level(rng: &mut rltk::RandomNumberGenerator, intelligence: i32, level: i32) -> i32 { pub fn mana_at_level(rng: &mut rltk::RandomNumberGenerator, intelligence: i32, level: i32) -> i32 {
let mut total = 0; let mut total = entity::MINIMUM_MANA;
for _i in 0..level { for _i in 0..level {
total += mana_per_level(rng, intelligence); total += mana_per_level(rng, intelligence);
} }

View file

@ -1,5 +1,6 @@
use super::{ gamesystem::attr_bonus, gamesystem::get_attribute_rolls, Attributes, Pools, Renderable, RunState, State }; use super::{ gamesystem::attr_bonus, gamesystem::get_attribute_rolls, Attributes, Pools, Renderable, RunState, State };
use crate::config::entity::NORMAL_SPEED; use crate::config::entity;
use crate::config::char_create::*;
use crate::{ use crate::{
raws, raws,
Attribute, Attribute,
@ -181,13 +182,13 @@ pub fn character_creation(gs: &mut State, ctx: &mut Rltk) -> CharCreateResult {
ctx.print_color(x, y + 3, fg, bg, "v. Villager"); ctx.print_color(x, y + 3, fg, bg, "v. Villager");
// Selected ancestry/class benefits // Selected ancestry/class benefits
x += column_width; x += column_width;
ctx.print_color(x, y, selected_fg, bg, "Your ancestry grants..."); ctx.print_color(x, y, selected_fg, bg, ANCESTRY_INFO_HEADER);
for line in ANCESTRY_CLASS_DATA.get(race_str).unwrap().iter() { for line in ANCESTRY_CLASS_DATA.get(race_str).unwrap().iter() {
y += 1; y += 1;
ctx.print_color(x + 1, y, unselected_fg, bg, line); ctx.print_color(x + 1, y, unselected_fg, bg, line);
} }
y += 2; y += 2;
ctx.print_color(x, y, selected_fg, bg, "Your class grants..."); ctx.print_color(x, y, selected_fg, bg, CLASS_INFO_HEADER);
for line in ANCESTRY_CLASS_DATA.get(class_str).unwrap().iter() { for line in ANCESTRY_CLASS_DATA.get(class_str).unwrap().iter() {
y += 1; y += 1;
ctx.print_color(x + 1, y, unselected_fg, bg, line); ctx.print_color(x + 1, y, unselected_fg, bg, line);
@ -257,36 +258,44 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) {
Ancestry::Dwarf => { Ancestry::Dwarf => {
renderables renderables
.insert(*player, Renderable { .insert(*player, Renderable {
glyph: rltk::to_cp437('h'), glyph: rltk::to_cp437(DWARF_GLYPH),
fg: RGB::named(rltk::RED), fg: RGB::named(DWARF_COLOUR),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
render_order: 0, render_order: 0,
}) })
.expect("Unable to insert renderable component"); .expect("Unable to insert renderable component");
*player_skills.skills.entry(Skill::Defence).or_insert(0) += 1; *player_skills.skills.entry(Skill::Defence).or_insert(0) += DWARF_DEFENCE_MOD;
} }
Ancestry::Elf => { Ancestry::Elf => {
renderables renderables
.insert(*player, Renderable { .insert(*player, Renderable {
glyph: rltk::to_cp437('@'), glyph: rltk::to_cp437(ELF_GLYPH),
fg: RGB::named(rltk::GREEN), fg: RGB::named(ELF_COLOUR),
bg: RGB::named(rltk::BLACK), bg: RGB::named(rltk::BLACK),
render_order: 0, render_order: 0,
}) })
.expect("Unable to insert renderable component"); .expect("Unable to insert renderable component");
let mut telepaths = ecs.write_storage::<Telepath>(); let mut telepaths = ecs.write_storage::<Telepath>();
telepaths telepaths
.insert(*player, Telepath { telepath_tiles: Vec::new(), range: 6, dirty: true }) .insert(*player, Telepath { telepath_tiles: Vec::new(), range: ELF_TELEPATH_RANGE, dirty: true })
.expect("Unable to insert telepath component"); .expect("Unable to insert telepath component");
let mut speeds = ecs.write_storage::<Energy>(); let mut speeds = ecs.write_storage::<Energy>();
speeds speeds
.insert(*player, Energy { current: 0, speed: NORMAL_SPEED + 1 }) .insert(*player, Energy { current: 0, speed: entity::NORMAL_SPEED + ELF_SPEED_BONUS })
.expect("Unable to insert energy component"); .expect("Unable to insert energy component");
} }
Ancestry::Catfolk => { Ancestry::Catfolk => {
renderables
.insert(*player, Renderable {
glyph: rltk::to_cp437(CATFOLK_GLYPH),
fg: RGB::named(CATFOLK_COLOUR),
bg: RGB::named(rltk::BLACK),
render_order: 0,
})
.expect("Unable to insert renderable component");
let mut speeds = ecs.write_storage::<Energy>(); let mut speeds = ecs.write_storage::<Energy>();
speeds speeds
.insert(*player, Energy { current: 0, speed: NORMAL_SPEED + 2 }) .insert(*player, Energy { current: 0, speed: entity::NORMAL_SPEED + CATFOLK_SPEED_BONUS })
.expect("Unable to insert energy component"); .expect("Unable to insert energy component");
} }
_ => {} _ => {}
@ -325,11 +334,11 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
let mut pools = ecs.write_storage::<Pools>(); let mut pools = ecs.write_storage::<Pools>();
pools pools
.insert(player, Pools { .insert(player, Pools {
hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) }, hit_points: Pool { current: 8 + attr_bonus(con), max: entity::STANDARD_HIT_DIE + attr_bonus(con) },
mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) }, mana: Pool { current: 1 + attr_bonus(int), max: entity::MINIMUM_MANA_PLAYER + attr_bonus(int) },
xp: 0, xp: 0,
level: 1, level: 1,
bac: 10, bac: entity::STANDARD_BAC,
weight: 0.0, weight: 0.0,
god: false, god: false,
}) })
@ -368,26 +377,26 @@ fn get_starting_inventory(class: Class, rng: &mut RandomNumberGenerator) -> (Vec
let starting_food: &str; let starting_food: &str;
match class { match class {
Class::Fighter => { Class::Fighter => {
starting_food = "1d2+1"; starting_food = FIGHTER_STARTING_FOOD;
equipped = vec![ equipped = vec![
"equip_shortsword".to_string(), FIGHTER_STARTING_WEAPON.to_string(),
"equip_body_ringmail".to_string(), FIGHTER_STARTING_ARMOUR.to_string(),
"equip_mediumshield".to_string() FIGHTER_STARTING_SHIELD.to_string()
]; ];
} }
Class::Rogue => { Class::Rogue => {
starting_food = "1d2+2"; starting_food = ROGUE_STARTING_FOOD;
equipped = vec!["equip_rapier".to_string(), "equip_body_weakleather".to_string()]; equipped = vec!["equip_rapier".to_string(), "equip_body_weakleather".to_string()];
carried = vec!["equip_dagger".to_string(), "equip_dagger".to_string()]; carried = vec!["equip_dagger".to_string(), "equip_dagger".to_string()];
} }
Class::Wizard => { Class::Wizard => {
starting_food = "1d2+1"; starting_food = WIZARD_STARTING_FOOD;
equipped = vec!["equip_dagger".to_string(), "equip_back_protection".to_string()]; equipped = vec!["equip_dagger".to_string(), "equip_back_protection".to_string()];
pick_random_table_item(rng, &mut carried, "scrolls", "1d3", Some(3)); pick_random_table_item(rng, &mut carried, "scrolls", WIZARD_SCROLL_AMOUNT, Some(WIZARD_MAX_SCROLL_LVL));
pick_random_table_item(rng, &mut carried, "potions", "1d3-1", Some(3)); pick_random_table_item(rng, &mut carried, "potions", WIZARD_POTION_AMOUNT, Some(WIZARD_MAX_SCROLL_LVL));
} }
Class::Villager => { Class::Villager => {
starting_food = "1d3+2"; starting_food = VILLAGER_STARTING_FOOD;
pick_random_table_item(rng, &mut equipped, "villager_equipment", "1", None); pick_random_table_item(rng, &mut equipped, "villager_equipment", "1", None);
} }
} }

View file

@ -27,7 +27,7 @@ mod trigger_system;
use melee_combat_system::MeleeCombatSystem; use melee_combat_system::MeleeCombatSystem;
mod inventory; mod inventory;
mod particle_system; mod particle_system;
use particle_system::{ ParticleBuilder, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME }; use particle_system::ParticleBuilder;
mod ai; mod ai;
mod config; mod config;
mod effects; mod effects;

View file

@ -1,13 +1,7 @@
use super::{ ParticleLifetime, Position, Renderable, Rltk }; use super::{ ParticleLifetime, Position, Renderable, Rltk };
use rltk::RGB; use rltk::RGB;
use specs::prelude::*; use specs::prelude::*;
use crate::config::visuals::{ DEFAULT_PARTICLE_LIFETIME, SHORT_PARTICLE_LIFETIME };
pub const SHORT_PARTICLE_LIFETIME: f32 = 100.0;
// For things which will happen frequently - i.e. attacking.
pub const DEFAULT_PARTICLE_LIFETIME: f32 = 200.0;
// For exceptional things, like large AOEs, to make sure the
// player can actually see what's being impacted - i.e. fireball.
pub const LONG_PARTICLE_LIFETIME: f32 = 300.0;
/// Runs each tick, deleting particles who are past their expiry. /// Runs each tick, deleting particles who are past their expiry.
// Should make an addition to this to also spawn delayed particles, // Should make an addition to this to also spawn delayed particles,

View file

@ -1,6 +1,5 @@
use super::{ Raws, Reaction }; use super::{ Raws, Reaction };
use crate::components::*; use crate::components::*;
use crate::config::entity;
use crate::gamesystem::*; use crate::gamesystem::*;
use crate::gui::Ancestry; use crate::gui::Ancestry;
use crate::random_table::RandomTable; use crate::random_table::RandomTable;