#rpg #dnd #game #jrpg

bin+lib rpg-stat

用于RPG游戏开发的计算机统计库

22个版本 (稳定版)

2021.12.16 2021年12月16日
2021.12.9 2021年12月9日
3.0.0 2021年11月12日
2.0.1 2021年11月10日
0.1.3 2021年9月25日

#220 in 游戏开发


vectorview使用

自定义许可

320KB
8K SLoC

RPG Stat库

Documentation Crates.io

Cargo.toml

rpgstat="2.0"

这是一个相当全面的库,链接到几乎所有你可以使用的东西。由于当前形式的战斗系统尚处于初级阶段,该库仍然是工作进度中。支持TOML格式和serde

统计信息

统计信息分为几类: BasicNormalAdvanced

Basic 包含通用游戏最需要的统计信息,您的文件需要:use rpgstat::stats::Basic as Stats

  • id
  • xp
  • xp_next
  • level
  • gp
  • hp
  • mp
  • hp_max
  • mp_max
  • speed

Normal 包含一些通用RPG战斗系统的统计信息以及 Basic 中的所有内容,您的文件需要:use rpgstat::stats::Normal as Stats

  • atk
  • def
  • m_atk
  • m_def

Advanced 包含桌面RPG统计信息中的更详细的细节以及 NormalBasic 中的所有内容,您的文件需要:use rpgstat::stats::Advanced as Stats

  • agility
  • strength
  • dexterity
  • constitution
  • intelligence
  • charisma
  • wisdom
  • age

Serde + TOML/INI

是的,你可以使用serde与提供的任何assets/characters/文件一起使用。你可以在自定义结构体中使用它们。你可以实现预制统计信息,以便拥有mystruct.hp()而不是以下类似的内容mystruct.stats.hp

use std::fs::File;
use std::io::Read;
use toml::*;
use serde::{Deserialize, Serialize};
use rpgstat::legendary::Legendary;
use rpgstat::stats::Basic as Stats;
use rpgstat::stats::Builder;

#[derive(Serialize, Deserialize)]
pub struct Character {
    pub name:String,
    pub stats:Stats<f64>,
}
let filename = "assets/characters/EasterBilby.ini";
    match File::open(filename) {
    Ok(mut file) => {
        let mut content = String::new();
        file.read_to_string(&mut content).unwrap();
        let decoded: Stats<f64> = toml::from_str(content.as_str()).unwrap();
        assert_eq!(decoded.hp, 10.0);
        let decoded2: Character = toml::from_str(content.as_str()).unwrap();
        assert_eq!(decoded2.stats.hp, 10.0);
        let sc:Legendary = Legendary::SantaClaus;
        let stats:Stats<f64> = sc.build_basic(0.0,1.0);
        let toml = toml::to_string(&stats).unwrap();

    },
    Err(e) => println!("Error:{} opening File:{}", e, filename),
}

自定义toml/ini与serde

use serde::{Deserialize, Serialize};
use rpgstat::attributes::{Effectiveness, Value};
use rpgstat::class::Basic as Class;
use rpgstat::stats::Basic as Stats;

// example program
const INI_FILE:&str = r#"name="test"
class="Hero"
effectiveness="None"
image="/path/to/file"
[stats]
id = 1
hp = 10
mp = 10
xp = 10
level = 1
hp_max = 10
mp_max = 10
xp_next = 10
gp = 10
speed = 10
atk = 10
def = 10
m_atk = 10
m_def = 10
agi = 10
str = 10
int = 10
dex = 10
con = 10
char = 10
wis = 10
age = 10"#;

#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct OccasionalEnemy {
    pub name:String,
    pub image:String,
    pub stats:Stats<f64>,
    pub effectiveness:Effectiveness,
    pub class:Class,
}
let decoded: OccasionalEnemy = toml::from_str(INI_FILE).unwrap();
assert_eq!(decoded.stats.hp, 10.0);
assert_eq!(decoded.effectiveness, Effectiveness::None);
// Value trait used here:
assert_eq!(0.0, Effectiveness::None.value(decoded.stats.hp));
assert_eq!(decoded.name, String::from("test"));
assert_eq!(decoded.class.to_string(), String::from("Hero"));

构建器

自1.X版本以来,rpg-stat 包含了一个 Builder 特性。该特性正在被用于所有枚举,例如 rpgstat::class::* 以及 rpgstat::creature::*

这允许你做

// feel free to use `Normal` or `Advanced` instead of `Basic`
use rpgstat::stats::Basic as Stats;
use rpgstat::class::Basic as Class;
use rpgstat::creature::Animal;
// this is the thing we need!
use rpgstat::stats::Builder;

// get bear stats for our program
fn bear_stats () -> Stats<f64> {
    // make the bear enum
    let bear:Animal = Animal::Bear;
    // this number only matters if you want
    let id:f64 = 0.0;
    // this effects the stats returned
    let level:f64 = 1.0;
    // use the basic `Builder`
    let bear_stats:Stats<f64> = bear.build_basic(id, level);
    // that was easy!
    bear_stats
}

// get Hero stats for our program
fn hero_stats () -> Stats<f64> {
    // make the hero enum
    let hero:Class = Class::Hero;
    // this number only matters if you want
    let id:f64 = 0.0;
    // this effects the stats returned
    let level:f64 = 1.0;
    // use the basic `Builder`
    let hero_stats:Stats<f64> = hero.build_basic(id, level);
    // that was easy!
    hero_stats
}

// TODO make them meet...

自己构建!

如果你不想使用我制作的统计信息,你可以实现自己的构建器

use rpgstat::stats::Basic as BasicStats;
use rpgstat::stats::Normal as NormalStats;
use rpgstat::stats::Advanced as AdvancedStats;
use rpgstat::stats::Builder;
use std::ops::{Add, AddAssign,  Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign};

// gee maybe I should make stats for these awesome libre characters
pub enum MyAwesomeThing {
    Tux,
    Pepper,
    Gnu,
    Kiki,
    Sara,
    Konqi,
    Suzanne,
    Xue,
    Wilber,
    Pidgin,
}

impl<T:Copy 
    + Default
    + AddAssign
    + Add<Output = T>
    + Div<Output = T>
    + DivAssign
    + Mul<Output = T>
    + MulAssign
    + Neg<Output = T>
    + Rem<Output = T>
    + RemAssign
    + Sub<Output = T>
    + SubAssign
    + std::cmp::PartialOrd
    + num::NumCast> Builder<T> for MyAwesomeThing {
    /// Build a `Basic` stat
    fn build_basic(&self, id:T, level:T) -> BasicStats<T>{
        match *self {
            // make basic
            _=>
            BasicStats {
                id: Default::default(),
                xp: Default::default(),
                xp_next: Default::default(),
                level: Default::default(),
                gp: Default::default(),
                hp: Default::default(),
                mp: Default::default(),
                hp_max: Default::default(),
                mp_max: Default::default(),
                speed: Default::default(),
            },
        }
    }
    fn build_normal(&self, id:T, level:T) -> NormalStats<T>{
        match *self {
            _=>
            // make normal
            NormalStats {
                id: Default::default(),
                xp: Default::default(),
                xp_next: Default::default(),
                level: Default::default(),
                gp: Default::default(),
                hp: Default::default(),
                mp: Default::default(),
                hp_max: Default::default(),
                mp_max: Default::default(),
                speed: Default::default(),
                atk:Default::default(),
                def:Default::default(),
                m_atk:Default::default(),
                m_def:Default::default(),
            },
        }
    }
    fn build_advanced(&self, id:T, level:T) -> AdvancedStats<T>{
        match *self {
            // make advanced
            // TODO make Tux destroy the other characters stats
            // well maybe not Pepper since she gives out free paint brushes...
            _=>
            AdvancedStats {
                id: Default::default(),
                xp: Default::default(),
                xp_next: Default::default(),
                level: Default::default(),
                gp: Default::default(),
                hp: Default::default(),
                mp: Default::default(),
                hp_max: Default::default(),
                mp_max: Default::default(),
                speed: Default::default(),
                atk:Default::default(),
                def:Default::default(),
                m_atk:Default::default(),
                m_def:Default::default(),
                agility:Default::default(),
                strength:Default::default(),
                dexterity:Default::default(),
                constitution:Default::default(),
                intelligence:Default::default(),
                charisma:Default::default(),
                wisdom:Default::default(),
                age:Default::default(),
            },
        }
    }
}

类被分为几个类别:BasicNormalAdvanced

Basic 类是 HeroEnemy。你的文件需要: use rpgstat::class::Basic as Class

Normal 类包含了一系列战斗游戏中的角色类。你的文件需要: use rpgstat::class::Normal as Class

Advanced 包含了更多适合交互式角色游戏的角色,而不仅仅是战斗游戏。你的文件需要: use rpgstat::class::Advanced as Class

所有类都实现了 Builder 统计,并且可以轻松使用

use rpgstat::stats::Normal as Stats;
use rpgstat::class::Normal as Class;
// *Use this*
use rpgstat::stats::Builder;

// get Hero stats for our program
fn hero_stats () -> Stats<f64> {
    // make the hero enum
    let hero:Class = Class::Alchemist;
    // this number only matters if you want
    let id:f64 = 0.0;
    // this effects the stats returned
    let level:f64 = 1.0;
    // use the basic `Builder`
    let hero_stats:Stats<f64> = hero.build_normal(id, level);
    // that was easy!
    hero_stats
}

生物

比较

根据此图表,已为 Normal 实现了 Compare 特性

use rpgstat::types::Normal as Type;
// to check effectiveness
use rpgstat::types::Compare;
// need effectiveness too!
use rpgstat::attributes::Effectiveness;

let rock = Type::Rock;
let wind = Type::Wind;
assert_eq!(rock.effectiveness(wind), Effectiveness::None);
assert_eq!(wind.effectiveness(rock), Effectiveness::Double);

特殊

这些是 Special 技能的名称。

use rpgstat::special::Normal as Special;
let grind:Special = Special::Grind;

你可以获取预构建的 mp_cost()

use rpgstat::special::ManaCost;
use rpgstat::special::Normal as Special;
let grind:Special = Special::Grind;
assert_eq!(grind.mp_cost(0), 7);

效果

这组合了与角色统计数据相关的游戏中各种效果

属性

这些是将抽象术语定义为代码的代码

发生率

use rpgstat::attributes::Rate;
let yes:Rate = Rate::Always;
assert_eq!(yes.worked(), true);
let no:Rate = Rate::None;
assert_eq!(no.worked(), false);
let hmmm:Rate = Rate::Some;
// who knows....

有效性

这种有效性可以存储在结构体中,你可以为 value(T) 实现包装器

use rpgstat::attributes::{Effectiveness, Value};

pub struct Item {
    pub name:String,
    pub amount:i32,
    pub effectiveness:Effectiveness,
}
impl Item {
    // much easier to use now!
    pub fn value(&self) -> i32 {
        self.effectiveness.value(self.amount)
    }
}
use rpgstat::attributes::{Effectiveness, Value};
let hp:i32 = 50;
// later on we use an item and check the effectiveness of it
assert_eq!(Effectiveness::Half.value(hp), 25);

阶段

use rpgstat::attributes::Stage;

这包括生命的 Stage<T>。这与类似养生物游戏中的“进化”类似,但基于现实。在现实生活中,没有生物会在某人面前随机进化,但它们确实会变老并改变“形态”。有八种形态

  • 婴儿
  • 幼儿
  • 孩子
  • 青少年
  • 年轻人
  • 成年人
  • 中年人
  • 老人
use rpgstat::attributes::Stage;
let stage:Stage<i32> = Stage::current(15);
// Yup 15 is teen
assert_eq!(stage, Stage::Teen(15));

身体

目前,随着 makesvg 功能,身体包含 VectorView 特性,该特性可以从参数创建矢量(SVG)图像。工作将致力于将其用于其他事物,例如类型。

RPG Stat 命令行工具

WIP 理想情况下,这将使用 clap 并仅支持一些非常特定的统计特性。

据我所知,界面最终将看起来像: rpgstat class normal Archer stat normal hp

但到目前为止,这项工作还没有开始,我愿意听取意见。

依赖关系

~2–5MB
~98K SLoC