barely functional

This commit is contained in:
Ren Kararou 2023-08-14 15:50:27 -05:00
commit 62ce8d20c4
Signed by: spicywolf
GPG key ID: B0BA4EEC0714F8E6
16 changed files with 868 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
/Cargo.lock

9
Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "broken-data"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8.5"

133
src/equipment/comp.rs Normal file
View file

@ -0,0 +1,133 @@
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct Comp {
id: String, // Unique Item ID
name: String, // Display Name
slots: u8, // Spell slots, between 1 and 10
mstorage: u8, // Spell storage, powers of 2, 16-128 (MiB)
gstorage: u8, // Program storage, powers of 2, 8-32 (GiB)
stat_mods: StatBlock, // Bufs/debufs
flavor: String, // Flavortext
description: String, // Description text
}
impl Comp {
pub fn new() -> Self {
Self {
id: String::from("COMP_BLANK"),
name: String::from("Basic DMD"),
slots: 1,
mstorage: 16,
gstorage: 8,
stat_mods: StatBlock::new_zero(),
flavor: String::from("A basic bitch digital magick device"),
description: String::from(
"One spell slot, 16MiB of spell storage, and 8GiB of program storage",
),
}
}
pub fn id(self) -> String {
self.id
}
pub fn name(self) -> String {
self.name
}
pub fn slots(self) -> u8 {
self.slots
}
pub fn spell_storage(self) -> u8 {
self.mstorage
}
pub fn program_storage(self) -> u8 {
self.gstorage
}
pub fn stat_mods(self) -> StatBlock {
self.stat_mods
}
pub fn description(self) -> String {
self.description
}
pub fn flavor(self) -> String {
self.flavor
}
// Low teir gear
pub fn cef_8080() -> Self {
Self {
id: String::from("COMP_CEF_8080"),
name: String::from("CEF 8080"),
slots: 1,
mstorage: 16,
gstorage: 8,
stat_mods: StatBlock::new_zero(),
flavor: String::from("Mass produced garbage."),
description: String::from(
"One spell slot, 16MiB of spell storage, and 8GiB of program storage.",
),
}
}
pub fn chiba_e3() -> Self {
let mut stat_mods = StatBlock::new_zero();
stat_mods.set_intellect(1);
Self {
id: String::from("COMP_CHIBA_E3"),
name: String::from("Chiba E3"),
slots: 1,
mstorage: 16,
gstorage: 8,
stat_mods,
flavor: String::from("Handmade with love by Gideon Chiba, good luck out there trainee!"),
description: String::from("+1 Intellect, 1 spell slot, 16MiB of spell storage, 8GiB of program storage."),
}
}
pub fn spiceworks_v3() -> Self {
let mut stat_mods = StatBlock::new_zero();
stat_mods.set_magick(1);
Self {
id: String::from("COMP_SPICE_V3"),
name: String::from("Spiceworks V3"),
slots: 2,
mstorage: 16,
gstorage: 8,
stat_mods,
flavor: String::from("A heart is scratched into the side."),
description: String::from("+1 Magick, 2 spell slots, 16MiB of spell storage, 8GiB of program storage."),
}
}
// Mid teir gear
pub fn chiba_d35() -> Self {
let mut mods = StatBlock::new_zero();
mods.set_intellect(3);
Self {
id: String::from("COMP_CHIBA_D35"),
name: String::from("Chiba D35"),
slots: 6,
mstorage: 64,
gstorage: 16,
stat_mods: mods,
flavor: String::from("The hottest new offering from Gideon Chiba's handcrafted digital magick devices"),
description: String::from("+3 Intellect, six spell slots, 64MiB of spell storage, and 16GiB of program storage"),
}
}
pub fn cef_8081() -> Self {
Self {
id: String::from("COMP_CEF_8081"),
name: String::from("CEF 8081"),
slots: 5,
mstorage: 128,
gstorage: 16,
stat_mods: StatBlock::new_zero(),
flavor: String::from("Mass produced garbage."),
description: String::from("Five spell slots, 128MiB of spell storage, and 16GiB of program storage."),
}
}
// Gear Sets for AI unit generation
pub fn low_level_opts() -> [Self; 3] {
[Self::cef_8080(), Self::chiba_e3(), Self::spiceworks_v3()]
}
pub fn mid_level_opts() -> [Self; 2] {
[Self::chiba_d35(), Self::cef_8081()]
}
}

66
src/equipment/gun.rs Normal file
View file

@ -0,0 +1,66 @@
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct Bullet {
id: String,
name: String,
attack: u8,
}
impl Bullet {
pub fn new() -> Self {
Self {
id: "BULLET_BLANK",
name: "BLANK",
attack: 0,
}
}
pub fn id(self) -> String {
self.id
}
pub fn name(self) -> String {
self.name
}
pub fn attack(self) -> u8 {
self.attack
}
pub fn normal() -> Self {
Self {
id: "BULLET_NORMAL",
name: "Normal Bullet",
attack: 5,
}
}
}
#[derive(Debug, Clone)]
pub struct Gun {
id: String,
name: String,
stat_mods: StatBlock,
attack: u8,
bullets: Option<Bullet>,
mag_size: u8,
description: String,
flavor: String,
}
impl Gun {
pub fn new() -> Self {
Self {
id: String::from("GUN_WATER"),
name: String::from("Water Gun"),
stat_mods: StatBlock::new_zero(),
attack: 0,
bullets: None,
mag_size: 0,
description: String::from("A cheap toy."),
flavor: String::from("Don't walk into a gun fight with this."),
}
}
pub fn attack(self) -> u8 {
self.attack
}
pub fn stat_mods(self) -> StatBlock {
self.stat_mods
}
}

18
src/equipment/hat.rs Normal file
View file

@ -0,0 +1,18 @@
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct Hat {
name: String,
stat_mods: StatBlock,
}
impl Hat {
pub fn new() -> Hat {
Hat {
name: String::from("Basic Hat"),
stat_mods: StatBlock::new_zero(),
}
}
pub fn stat_mods(self) -> StatBlock {
self.stat_mods
}
}

107
src/equipment/mod.rs Normal file
View file

@ -0,0 +1,107 @@
mod comp;
mod gun;
mod hat;
mod pants;
mod shirt;
mod shoes;
mod sword;
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct EquipmentBlock {
sword: Option<sword::Sword>,
gun: Option<gun::Gun>,
comp: Option<comp::Comp>,
head: Option<hat::Hat>,
chest: Option<shirt::Shirt>,
leg: Option<pants::Pants>,
foot: Option<shoes::Shoes>,
}
impl EquipmentBlock {
pub fn new() -> EquipmentBlock {
EquipmentBlock {
sword: None,
gun: None,
comp: None,
head: None,
chest: None,
leg: None,
foot: None,
}
}
pub fn sword(self) -> Option<sword::Sword> {
self.sword
}
pub fn gun(self) -> Option<gun::Gun> {
self.gun
}
pub fn comp(self) -> Option<comp::Comp> {
self.comp
}
pub fn hat(self) -> Option<hat::Hat> {
self.head
}
pub fn shirt(self) -> Option<shirt::Shirt> {
self.chest
}
pub fn pants(self) -> Option<pants::Pants> {
self.leg
}
pub fn shoes(self) -> Option<shoes::Shoes> {
self.foot
}
pub fn equip_sword(mut self, sword: sword::Sword) {
self.sword = Some(sword);
}
pub fn equip_gun(mut self, gun: gun::Gun) {
self.gun = Some(gun);
}
pub fn equip_comp(mut self, comp: comp::Comp) {
self.comp = Some(comp);
}
pub fn equip_hat(mut self, hat: hat::Hat) {
self.head = Some(hat);
}
pub fn equip_chest(mut self, shirt: shirt::Shirt) {
self.chest = Some(shirt);
}
pub fn equip_pants(mut self, pants: pants::Pants) {
self.leg = Some(pants);
}
pub fn equip_shoes(mut self, shoes: shoes::Shoes) {
self.foot = Some(shoes);
}
pub fn unequip_sword(mut self) {
self.sword = None;
}
pub fn unequip_gun(mut self) {
self.gun = None;
}
pub fn unequip_comp(mut self) {
self.comp = None;
}
pub fn unequip_hat(mut self) {
self.head = None;
}
pub fn unequip_shirt(mut self) {
self.chest = None;
}
pub fn unequip_pants(mut self) {
self.leg = None;
}
pub fn unequip_shoes(mut self) {
self.foot = None;
}
pub fn bonuses(self) -> StatBlock {
let mut stats = StatBlock::new_zero();
stats += self.sword.unwrap_or(sword::Sword::new()).stat_mods();
stats += self.gun.uwrap_or(gun::Gun::new()).stat_mods();
stats += self.comp.unwrap_or(comp::Comp::new()).stat_mods();
stats += self.head.unwrap_or(hat::Hat::new()).stat_mods();
stats += self.chest.unwrap_or(shirt::Shirt::new()).stat_mods();
stats += self.leg.unwrap_or(pants::Pants::new()).stat_mods();
stats += self.foot.unwrap_or(shoes::Shoes::new()).stat_mods();
stats
}
}

18
src/equipment/pants.rs Normal file
View file

@ -0,0 +1,18 @@
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct Pants {
name: String,
stat_mods: StatBlock,
}
impl Pants {
pub fn new() -> Pants {
Pants {
name: String::from("Basic Pants"),
stat_mods: StatBlock::new_zero(),
}
}
pub fn stat_mods(self) -> StatBlock {
self.stat_mods
}
}

18
src/equipment/shirt.rs Normal file
View file

@ -0,0 +1,18 @@
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct Shirt {
name: String,
stat_mods: StatBlock,
}
impl Shirt {
pub fn new() -> Shirt {
Shirt {
name: String::from("Basic Shirt"),
stat_mods: StatBlock::new_zero(),
}
}
pub fn stat_mods(self) -> StatBlock {
self.stat_mods
}
}

18
src/equipment/shoes.rs Normal file
View file

@ -0,0 +1,18 @@
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct Shoes {
name: String,
stat_mods: StatBlock,
}
impl Shoes {
pub fn new() -> Shoes {
Shoes {
name: String::from("Basic Shoes"),
stat_mods: StatBlock::new_zero(),
}
}
pub fn stat_mods(self) -> StatBlock {
self.stat_mods
}
}

84
src/equipment/sword.rs Normal file
View file

@ -0,0 +1,84 @@
use crate::statistics::StatBlock;
#[derive(Debug, Clone)]
pub struct Sword {
id: String,
name: String,
damage: u8,
stat_mods: StatBlock,
flavor: String,
description: String,
}
impl Sword {
pub fn new() -> Self {
Self {
id: String::from("SWORD_BLANK"),
name: String::from("Basic Sword"),
damage: 1u8,
stat_mods: StatBlock::new_zero(),
flavor: String::from("A basic bitch sword. It is completely useless."),
description: String::from("1 Attack Strength Sword. Literally the cheapest you can get."),
}
}
pub fn id(self) -> String {
self.id
}
pub fn name(self) -> String {
self.name
}
pub fn damage(self) -> u8 {
self.damage
}
pub fn stat_mods(self) -> StatBlock {
self.stat_mods
}
pub fn flavor(self) -> String {
self.flavor
}
pub fn description(self) -> String {
self.description
}
pub fn set_id(&mut self, id: String) {
self.id = id;
}
pub fn set_name(&mut self, name: String) {
self.name = name;
}
pub fn set_damage(&mut self, damage: u8) {
self.damage = damage;
}
pub fn set_stat_mods(&mut self, stat_mods: StatBlock) {
self.stat_mods = stat_mods;
}
pub fn set_flavor(&mut self, flavor: String) {
self.flavor = flavor;
}
pub fn set_description(&mut self, description: String) {
self.description = description;
}
pub fn sacred_blade() -> Self {
let mut buf = StatBlock::new_zero();
buf.set_strength(5);
Self {
id: String::from("SWORD_SACRED_BLADE"),
name: String::from("Sacred Blade"),
damage: 58u8,
stat_mods: buf,
flavor: String::from("Forged eons ago by master smiths and imbued with the magic of gods."),
description: String::from("+5 Strength. 58 Attack. The sacred sword of a religious cult."),
}
}
pub fn ceremonial_knife() -> Self {
let mut buf = StatBlock::new_zero();
buf.set_intellect(2);
Self {
id: String::from("SWORD_CEREMONIAL_KNIFE"),
name: String::from("Ceremonial Knife"),
damage: 27u8,
stat_mods: buf,
flavor: String::from("Used for sex parties, mostly."),
description: String::from("+2 Intellect. 27 Attack. Used by wiccans during rites."),
}
}
}

16
src/inventory.rs Normal file
View file

@ -0,0 +1,16 @@
use crate::equipment::{sword::Sword, gun::Gun, comp::Comp, hat::Hat, shirt::Shirt, pants::Pants, shoes::Shoes};
struct BagEquipment {
swords: Option<Vec<Sword>>,
guns: Option<Vec<Guns>>,
comps: Option<Vec<Comp>>,
hats: Option<Vec<Hat>>,
shirts: Option<Vec<Shirt>>,
pants: Option<Vec<Pants>>,
shoes: Option<Vec<Shoes>>,
}
struct Inventory {
equipment: Option<BagEquipment>,
}

6
src/lib.rs Normal file
View file

@ -0,0 +1,6 @@
pub mod equipment;
pub mod magic;
pub mod statistics;
pub mod unit;
pub mod inventory;
pub mod status;

1
src/magic.rs Normal file
View file

@ -0,0 +1 @@

148
src/statistics.rs Normal file
View file

@ -0,0 +1,148 @@
#[derive(Debug, Copy, Clone)]
pub struct StatBlock {
strength: i8, // determines physical attack power
magick: i8, // determines magick attack power
defense: i8, // determines damage reduction
intellect: i8, // determines magick hit chance and evasion chance
dexterity: i8, // determines physical hit chance and evasion chance
agility: i8, // determines turn order
vitality: i8, // determines HP/level
}
impl std::ops::Add for StatBlock {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
strength: self.strength + other.strength,
magick: self.magick + other.magick,
defense: self.defense + other.defense,
intellect: self.intellect + other.intellect,
dexterity: self.dexterity + other.dexterity,
agility: self.agility + other.agility,
vitality: self.vitality + other.vitality,
}
}
}
impl std::ops::AddAssign for StatBlock {
fn add_assign(&mut self, other: Self) {
*self = Self {
strength: self.strength + other.strength,
magick: self.magick + other.magick,
defense: self.defense + other.defense,
intellect: self.intellect + other.intellect,
dexterity: self.dexterity + other.dexterity,
agility: self.agility + other.agility,
vitality: self.vitality + other.vitality,
};
}
}
impl std::ops::Sub for StatBlock {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
strength: self.strength - other.strength,
magick: self.magick - other.magick,
defense: self.defense - other.defense,
intellect: self.intellect - other.intellect,
dexterity: self.dexterity - other.dexterity,
agility: self.agility - other.agility,
vitality: self.vitality - other.vitality,
}
}
}
impl StatBlock {
/// Generates a level 1 stat block
pub fn new() -> StatBlock {
StatBlock {
strength: 3,
magick: 3,
defense: 3,
intellect: 3,
dexterity: 3,
agility: 3,
vitality: 3,
}
}
/// Generates a null stat block
pub fn new_zero() -> StatBlock {
StatBlock {
strength: 0,
magick: 0,
defense: 0,
intellect: 0,
dexterity: 0,
agility: 0,
vitality: 0,
}
}
/// Generates a null stat block for use as the bonus_stat block
pub fn new_bonus() -> StatBlock {
StatBlock::new_zero()
}
pub fn strength(self) -> i8 {
self.strength
}
pub fn magick(self) -> i8 {
self.magick
}
pub fn defense(self) -> i8 {
self.defense
}
pub fn intellect(self) -> i8 {
self.intellect
}
pub fn dexterity(self) -> i8 {
self.dexterity
}
pub fn agility(self) -> i8 {
self.agility
}
pub fn vitality(self) -> i8 {
self.vitality
}
pub fn set_strength(&mut self, strength: i8) {
self.strength = strength;
}
pub fn set_magick(&mut self, magick: i8) {
self.magick = magick;
}
pub fn set_defense(&mut self, defense: i8) {
self.defense = defense;
}
pub fn set_intellect(&mut self, intellect: i8) {
self.intellect = intellect;
}
pub fn set_dexterity(&mut self, dexterity: i8) {
self.dexterity = dexterity;
}
pub fn set_agility(&mut self, agility: i8) {
self.agility = agility;
}
pub fn set_vitality(&mut self, vitality: i8) {
self.vitality = vitality;
}
pub fn add_strength(&mut self, count: i8) {
self.strength = self.strength.saturating_add(count);
}
pub fn add_magick(&mut self, count: i8) {
self.magick = self.magick.saturating_add(count);
}
pub fn add_defense(&mut self, count: i8) {
self.defense = self.defense.saturating_add(count);
}
pub fn add_intellect(&mut self, count: i8) {
self.intellect = self.intellect.saturating_add(count);
}
pub fn add_dexterity(&mut self, count: i8) {
self.dexterity = self.dexterity.saturating_add(count);
}
pub fn add_agility(&mut self, count: i8) {
self.agility = self.agility.saturating_add(count);
}
pub fn add_vitality(&mut self, count: i8) {
self.vitality = self.vitality.saturating_add(count);
}
}

11
src/status.rs Normal file
View file

@ -0,0 +1,11 @@
#[derive(Debug, Copy, Clone)]
pub enum Status {
Poison, // hp slowly decreases
Static, // chance to miss turn
Freeze, // hp slowly decreases and chance to miss turn
Burn, // hp slowly decreases and unable to cast magic
Slow, // speed is halved
Confuse, // chance to hit random target (self included)
Stop, // miss turn
Haste, // speed is doubled
}

213
src/unit.rs Normal file
View file

@ -0,0 +1,213 @@
use crate::equipment::EquipmentBlock;
use crate::statistics::StatBlock;
use crate::status::Status;
use rand::seq::SliceRandom;
use rand::Rng;
const MASC_NAMES: &'static [&'static str] = &["Antonio", "Brandon", "Charles", "Denzel", "Edgar"];
const FEMME_NAMES: &'static [&'static str] = &["Alice", "Bethany", "Cynthia", "Dawn", "Elizabeth"];
const NEUTR_NAMES: &'static [&'static str] = &["Aspen", "Blake", "Charlie", "Dekota", "Emery"];
#[derive(Debug, Copy, Clone)]
pub enum Gender {
Man,
Woman,
Nonbinary,
DemiGirl,
DemiBoy,
NoGender,
}
#[derive(Debug, Clone)]
pub struct Unit {
name: String,
level: u8,
exp: u32,
status: Option<(Option<Status>,Option<Status>)>,
gender: Gender,
base_stats: StatBlock,
hp: u16,
jel: u8,
jel_total: u8,
is_monster: bool,
equipment: Option<EquipmentBlock>,
}
impl Unit {
pub fn new() -> Unit {
let mut rng = rand::thread_rng();
let j = rng.gen_range(10..26);
Unit {
name: String::from("Basic Unit"),
level: 1,
exp: 0,
status: None,
gender: Gender::NoGender,
base_stats: StatBlock::new(),
hp: 18,
jel: j,
jel_total: j,
is_monster: true,
equipment: None,
}
}
pub fn name(self) -> String {
self.name
}
pub fn level(self) -> u8 {
self.level
}
pub fn gender(self) -> Gender {
self.gender
}
pub fn stats(self) -> StatBlock {
self.base_stats + self.stat_bonus()
}
pub fn base_stats(self) -> StatBlock {
self.base_stats
}
pub fn stat_bonus(self) -> StatBlock {
match self.equipment() {
Some(e) => e.bonuses(),
None => StatBlock::new_zero(),
}
}
pub fn hp(self) -> u16 {
self.hp
}
pub fn hp_max(self) -> u16 {
u16::from(
18u16
+ (u16::from(self.level)
* u16::from(0u8.wrapping_add_signed(self.stats().vitality()))),
)
}
pub fn jel(self) -> u8 {
self.jel
}
pub fn jel_total(self) -> u8 {
self.jel_total
}
pub fn is_monster(self) -> bool {
self.is_monster
}
pub fn equipment(self) -> Option<EquipmentBlock> {
if self.is_monster {
return None;
}
self.equipment
}
pub fn generate_gender() -> Gender {
let gender_variants = [
Gender::Man,
Gender::Woman,
Gender::Nonbinary,
Gender::DemiGirl,
Gender::DemiBoy,
];
match gender_variants.choose(&mut rand::thread_rng()) {
Some(g) => g.to_owned(),
None => Gender::NoGender,
}
}
pub fn generate_name(g: &Gender) -> String {
let names = match g {
Gender::Man => MASC_NAMES.to_vec(),
Gender::Woman => FEMME_NAMES.to_vec(),
Gender::Nonbinary => NEUTR_NAMES.to_vec(),
Gender::DemiGirl => [FEMME_NAMES, NEUTR_NAMES].concat(),
Gender::DemiBoy => [MASC_NAMES, NEUTR_NAMES].concat(),
Gender::NoGender => [MASC_NAMES, FEMME_NAMES, NEUTR_NAMES].concat(),
_ => return String::from("MISSINGNO"),
};
match names.choose(&mut rand::thread_rng()) {
Some(n) => String::from(n.clone()),
None => String::from("MISSINGNO"),
}
}
pub fn human_battle_maniac(lv: u8) -> Unit {
let mut rng = rand::thread_rng();
let mut j = rng.gen_range(10..26);
if lv > 20 {
j += rng.gen_range(10..26);
}
let g = Unit::generate_gender();
let n = format!("Battle Maniac {}", Unit::generate_name(&g)); // Excuse me, but may I
// borrow your gender for a
// moment?
let mut sb = StatBlock::new();
for _i in 0..lv {
match rng.gen_range(0..4) {
0 => sb.add_strength(1),
1 => sb.add_defense(1),
2 => sb.add_vitality(1),
3 => sb.add_intellect(1),
_ => {
eprintln!("ERROR! human_battle_maniac() stat assign out of bounds!");
sb.add_vitality(1);
},
};
}
let mut equip = EquipmentBlock::new();
//TODO: create equipment and equipment allocation algorithm
Unit {
name: n,
level: lv,
exp: 0, //TODO!! Fix this
status: None,
gender: g,
base_stats: sb.clone(),
hp: u16::from(
18u16 + (u16::from(lv) * u16::from(0u8.wrapping_add_signed(sb.vitality()))),
),
jel: j,
jel_total: j,
is_monster: false,
equipment: Some(equip),
}
}
pub fn human_street_samurai(lv: u8) -> Unit {
let mut rng = rand::thread_rng();
let mut j = rng.gen_range(10..26);
if rng.gen_range(0..100) < 25 && lv > 20 {
j += rng.gen_range(10..26);
}
let g = Unit::generate_gender();
let n = format!("Street Samurai {}", Unit::generate_name(&g));
let mut sb = StatBlock::new();
for _i in 0..lv {
match rng.gen_range(0..4) {
0 => sb.add_strength(1),
1 => sb.add_defense(1),
2 => sb.add_vitality(1),
3 => sb.add_agility(1),
_ => {
eprintln!("ERROR! human_street_samurai() stat assign out of bounds!");
sb.add_vitality(1);
},
};
}
let mut equip = EquipmentBlock::new();
//TODO: create equipment and equipment allocation algorithm
Unit {
name: n,
level: lv,
exp: 0, //TODO!! fix this
status: None,
gender: g,
base_stats: sb.clone(),
hp: u16::from(
18u16 + (u16::from(lv) * u16::from(0u8.wrapping_add_signed(sb.vitality()))),
),
jel: j,
jel_total: j,
is_monster: false,
equipment: Some(equip),
}
}
}