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库
Cargo.toml
rpgstat="2.0"
这是一个相当全面的库,链接到几乎所有你可以使用的东西。由于当前形式的战斗系统尚处于初级阶段,该库仍然是工作进度中。支持TOML格式和serde。
统计信息
统计信息分为几类: Basic
、Normal
和 Advanced
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统计信息中的更详细的细节以及 Normal
和 Basic
中的所有内容,您的文件需要: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(),
},
}
}
}
类
类被分为几个类别:Basic
、Normal
和 Advanced
Basic
类是 Hero
或 Enemy
。你的文件需要: 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