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 CARRY_CAPACITY_PER_STRENGTH: i32 = 8;
pub const NORMAL_SPEED: i32 = 12; // Normal speed for almost all entities.
pub const TURN_COST_MULTIPLIER: i32 = 4; // How many ticks per turn for an entity with NORMAL_SPEED.
pub const DEFAULT_VIEWSHED_STANDARD: i32 = 16; // Standard viewshed radius for almost all entities.
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 TURN_COST_MULTIPLIER: i32 = 4; // How many ticks for NORMAL_SPEED to get a turn.
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 glyphs;
pub mod messages;
pub mod char_create;
pub const SHOW_MAPGEN: bool = false;
pub const LOG_SPAWNING: bool = true;

View file

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

View file

@ -1,23 +1,24 @@
use super::{ Skill, Skills };
use crate::gui::{ Ancestry, Class };
use crate::config::entity;
use rltk::prelude::*;
use std::cmp::max;
/// Returns the attribute bonus for a given attribute score, where every 2 points above
/// or below 10 is an additional +1 or -1.
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.
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)]
/// 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 {
let mut total = 8 + attr_bonus(constitution);
let mut total = entity::STANDARD_HIT_DIE + attr_bonus(constitution);
for _i in 0..level {
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.
pub fn npc_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
if level == 0 {
return rng.roll_dice(1, 4);
return rng.roll_dice(1, entity::STANDARD_HIT_DIE_0);
}
let mut total = 1;
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;
}
/// 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 {
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.
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 {
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 crate::config::entity::NORMAL_SPEED;
use crate::config::entity;
use crate::config::char_create::*;
use crate::{
raws,
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");
// Selected ancestry/class benefits
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() {
y += 1;
ctx.print_color(x + 1, y, unselected_fg, bg, line);
}
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() {
y += 1;
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 => {
renderables
.insert(*player, Renderable {
glyph: rltk::to_cp437('h'),
fg: RGB::named(rltk::RED),
glyph: rltk::to_cp437(DWARF_GLYPH),
fg: RGB::named(DWARF_COLOUR),
bg: RGB::named(rltk::BLACK),
render_order: 0,
})
.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 => {
renderables
.insert(*player, Renderable {
glyph: rltk::to_cp437('@'),
fg: RGB::named(rltk::GREEN),
glyph: rltk::to_cp437(ELF_GLYPH),
fg: RGB::named(ELF_COLOUR),
bg: RGB::named(rltk::BLACK),
render_order: 0,
})
.expect("Unable to insert renderable component");
let mut telepaths = ecs.write_storage::<Telepath>();
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");
let mut speeds = ecs.write_storage::<Energy>();
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");
}
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>();
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");
}
_ => {}
@ -325,11 +334,11 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
let mut pools = ecs.write_storage::<Pools>();
pools
.insert(player, Pools {
hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) },
mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) },
hit_points: Pool { current: 8 + attr_bonus(con), max: entity::STANDARD_HIT_DIE + attr_bonus(con) },
mana: Pool { current: 1 + attr_bonus(int), max: entity::MINIMUM_MANA_PLAYER + attr_bonus(int) },
xp: 0,
level: 1,
bac: 10,
bac: entity::STANDARD_BAC,
weight: 0.0,
god: false,
})
@ -368,26 +377,26 @@ fn get_starting_inventory(class: Class, rng: &mut RandomNumberGenerator) -> (Vec
let starting_food: &str;
match class {
Class::Fighter => {
starting_food = "1d2+1";
starting_food = FIGHTER_STARTING_FOOD;
equipped = vec![
"equip_shortsword".to_string(),
"equip_body_ringmail".to_string(),
"equip_mediumshield".to_string()
FIGHTER_STARTING_WEAPON.to_string(),
FIGHTER_STARTING_ARMOUR.to_string(),
FIGHTER_STARTING_SHIELD.to_string()
];
}
Class::Rogue => {
starting_food = "1d2+2";
starting_food = ROGUE_STARTING_FOOD;
equipped = vec!["equip_rapier".to_string(), "equip_body_weakleather".to_string()];
carried = vec!["equip_dagger".to_string(), "equip_dagger".to_string()];
}
Class::Wizard => {
starting_food = "1d2+1";
starting_food = WIZARD_STARTING_FOOD;
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, "potions", "1d3-1", 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", WIZARD_POTION_AMOUNT, Some(WIZARD_MAX_SCROLL_LVL));
}
Class::Villager => {
starting_food = "1d3+2";
starting_food = VILLAGER_STARTING_FOOD;
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;
mod inventory;
mod particle_system;
use particle_system::{ ParticleBuilder, DEFAULT_PARTICLE_LIFETIME, LONG_PARTICLE_LIFETIME };
use particle_system::ParticleBuilder;
mod ai;
mod config;
mod effects;

View file

@ -1,13 +1,7 @@
use super::{ ParticleLifetime, Position, Renderable, Rltk };
use rltk::RGB;
use specs::prelude::*;
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;
use crate::config::visuals::{ DEFAULT_PARTICLE_LIFETIME, SHORT_PARTICLE_LIFETIME };
/// Runs each tick, deleting particles who are past their expiry.
// Should make an addition to this to also spawn delayed particles,

View file

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