Skip to content

Shylosia/osr-trpg-engine

 
 

Repository files navigation

OSR TRPG 规则引擎

Python Version License

一个轻量级、可扩展的旧式角色扮演游戏(OSR TRPG)规则引擎,基于B/X D&D规则设计,提供灵活的实体管理、骰子系统和可配置的规则加载机制。

📋 目录

📖 项目介绍

OSR TRPG 规则引擎是一个专为旧式角色扮演游戏(Old School Renaissance)设计的强大灵活框架,提供了构建TRPG系统所需的核心组件。该引擎基于经典的B/X D&D规则设计,同时保持高度的可扩展性,允许开发者轻松实现自定义规则和游戏机制。

最新版本的引擎配备了增强版骰子系统,支持完整的四则运算、括号表达式和复杂表达式计算,为游戏规则的实现提供了更强大的数学基础。无论是简单的属性检定,还是复杂的伤害计算或特殊能力效果,都能通过直观的表达式轻松实现。

✨ 核心功能

  • 强大的骰子系统:支持完整四则运算(加、减、乘、除)、括号表达式、百分骰和变量替换,可处理复杂表达式如 (2d6+str_mod)*level
  • 强大的实体管理:提供属性叠加、来源管理和能力检定功能
  • 可配置的规则加载:通过YAML文件定义规则,支持多来源数值叠加
  • B/X D&D规则实现:内置经典规则集,包括能力值、职业、种族和等级系统
  • 安全性保障:骰子系统内置表达式验证和安全检查,防止潜在风险
  • 扩展性:模块化设计,易于扩展和定制

📦 安装与设置

前提条件

  • Python 3.10 或更高版本
  • uv 包管理器(推荐)或 pip

安装步骤

  1. 克隆仓库
git clone https://github.com/yourusername/osr_trpg_engine.git
cd osr_trpg_engine
  1. 创建虚拟环境
python -m venv .venv
  1. 激活虚拟环境
  • Windows:
    .venv\Scripts\activate
  • Linux/macOS:
    source .venv/bin/activate
  1. 安装依赖

使用 uv:

# 安装项目依赖,包括新增的asteval库
uv install

或使用 pip:

pip install -e .

主要依赖

  • asteval: 安全的表达式解析和计算库,用于支持骰子系统的复杂数学表达式计算

🚀 快速开始

以下是一个全面的示例,展示如何使用引擎创建角色、进行检定,以及使用增强版骰子系统进行复杂表达式计算:

from rules.basic1981 import Basic1981Rulebook, create_character
from engine.dice import roll

# 创建规则书实例
rulebook = Basic1981Rulebook()

# 创建角色
character = create_character(
    rulebook,
    character_class="fighter",
    race="human",
    name="Aragorn"
)

# 查看角色信息
print(f"角色名称: {character.get('name')}")
print(f"生命值: {character.get('hp')}")
print(f"力量: {character.get('str')} (+{character.get('str_mod')})")

# 进行基本检定
result = character.check("d20+str_mod", difficulty=15)
print(f"力量检定结果: {'通过' if result else '失败'}")

# 使用增强版骰子系统进行复杂表达式计算
# 直接使用roll函数
print("\n=== 高级骰子表达式示例 ===")
print(f"武器伤害计算 (2d6+力量修正): {roll('2d6+3')}")
print(f"复杂表达式: (2d6+4)*2: {roll('(2d6+4)*2')}")
print(f"带变量的表达式: level*d8+con_mod: {roll('3*d8+2', {'level': 3, 'con_mod': 2})}")

# 在角色检定中使用复杂表达式
print("\n=== 角色能力检定示例 ===")
# 设置角色属性以便使用
character.set("level", 5)
character.set("proficiency", 2)

# 使用复杂表达式进行攻击检定
attack_roll = character.get("d20+str_mod+proficiency")
print(f"攻击骰结果: {attack_roll}")

# 计算伤害(使用力量修正、武器加值和等级调整)
damage = character.get("2d6+str_mod+(level/2)")
print(f"伤害计算结果: {damage}")

🔧 使用指南

骰子系统

骰子系统允许解析和计算各种骰子表达式,支持基础掷骰、完整四则运算、括号表达式、变量替换和表达式评估:

from engine.dice import roll

# 基本掷骰
print(roll("d20"))          # 掷1个20面骰子
print(roll("3d6"))         # 掷3个6面骰子并求和
print(roll("d%"))          # 掷1个100面骰子(百分骰)
print(roll("2d20"))        # 掷2个20面骰子并求和

# 带修饰符的掷骰
print(roll("d20+5"))       # 掷1个20面骰子加5
print(roll("3d8+1d4+3"))   # 掷3个8面骰子和1个4面骰子,总和加3
print(roll("2d6-2"))       # 掷2个6面骰子减2(支持减法)

# 四则运算和括号表达式
print(roll("(d20+4)*2"))   # 掷1个20面骰子加4,结果乘以2
print(roll("(2d6/2)+3"))   # 掷2个6面骰子除以2(整除),加3
print(roll("2 + 3 * (4 - 1)"))  # 常规数学表达式,支持空格

# 使用变量进行计算
variables = {"str_mod": 3, "prof": 2, "level": 5}
print(roll("d20+str_mod+prof", variables))  # 掷1个20面骰子加力量修正和熟练加值
print(roll("level*d8+con_mod", {"level": 3, "con_mod": 2}))  # 等级乘以d8加体质修正
print(roll("3d6+str_mod+(level/2)", {"str_mod": 2, "level": 7}))  # 复杂变量表达式

实体管理

实体系统是游戏对象(如角色、怪物、物品)的基础:

from engine.entity import Entity
from engine.source import Source

# 创建规则书类(简化示例)
class SimpleRulebook:
    pass

# 创建实体
rulebook = SimpleRulebook()
entity = Entity(rulebook)

# 设置属性
entity.set("name", "Goblin")
entity.set("hp", 7)
entity.set("str", 8)
entity.set("str_mod", -1)

# 获取属性
print(entity.get("name"))  # 输出: Goblin
print(entity.get("hp"))    # 输出: 7

# 创建自定义来源
class MonsterSource(Source):
    def priority(self):
        return 10
    
    def keys(self):
        return ["attack", "damage"]
    
    def get(self, key):
        values = {"attack": "d20+0", "damage": "1d6"}
        return values[key]

# 附加来源
monster_source = MonsterSource()
entity.attach(monster_source)

# 获取带骰子表达式的值(会自动计算)
print(entity.get("attack"))  # 输出: 掷骰结果 (如 12)
print(entity.get("damage"))  # 输出: 掷骰结果 (如 4)

规则加载

使用YAML文件定义和加载规则:

from engine.yaml_source import YamlSource, load_yaml_folder
import os

# 从单个YAML文件加载规则
source = YamlSource("rules/yaml/fighter.yml")
print(f"规则名称: {source.name}")
print(f"提供的键: {source.keys()}")

# 从文件夹加载所有规则
yaml_folder = "rules/yaml"
if os.path.exists(yaml_folder):
    sources = load_yaml_folder(yaml_folder)
    for src in sources:
        print(f"加载规则: {src.name}, 优先级: {src.priority()}")

YAML规则文件示例:

name: "Fighter"
priority: 10
description: "战士是精通战斗的专家"
attributes:
  attack_bonus:
    value: "level-1"
    mode: "add"
  weapon_proficiency:
    value: "all"
    mode: "override"

角色创建

使用内置的B/X D&D规则创建角色:

from rules.basic1981 import Basic1981Rulebook, create_character

# 创建规则书
rulebook = Basic1981Rulebook()

# 方法1: 创建随机角色
random_character = create_character(rulebook)

# 方法2: 创建指定职业和种族的角色
specific_character = create_character(
    rulebook,
    character_class="magic-user",
    race="elf",
    name="Legolas"
)

# 检查种族职业组合是否有效
if rulebook.is_class_available_for_race("thief", "dwarf"):
    print("矮人可以选择盗贼职业")

# 获取等级上限
max_level = rulebook.get_max_level("fighter", "elf")
print(f"精灵战士的等级上限: {max_level}")

📁 项目结构

osr_trpg_engine/
├── engine/             # 核心引擎模块
│   ├── __init__.py     # 模块初始化
│   ├── dice.py         # 增强版骰子解析和计算系统
│   ├── entity.py       # 角色实体类
│   ├── source.py       # 数值来源抽象
│   └── yaml_source.py  # YAML数据驱动
├── rules/              # 规则实现
│   ├── __init__.py     # 模块初始化
│   ├── basic1981.py    # B/X D&D规则
│   └── yaml/           # YAML规则文件
│       ├── cleric.yml  # 牧师职业规则
│       ├── dwarf.yml   # 矮人种族规则
│       ├── elf.yml     # 精灵种族规则
│       ├── fighter.yml # 战士职业规则
│       ├── halfling.yml # 半身人种族规则
│       ├── human.yml   # 人类种族规则
│       ├── magic_user.yml # 法师职业规则
│       └── thief.yml   # 盗贼职业规则
├── tests/              # 测试文件
│   ├── test_dice.py    # 骰子系统测试
│   ├── test_entity.py  # 实体系统测试
│   ├── test_rules.py   # 规则系统测试
│   └── ...             # 其他测试文件
├── main.py             # 主程序入口
├── main_plan.md        # 项目计划文档
├── main_plan_v2.md     # 增强版计划文档(包含骰子系统更新)
├── pyproject.toml      # 项目配置
├── README.md           # 项目文档
└── verify.bat          # 验证脚本(Windows)

🎲 骰子系统详解

功能概述

增强版骰子系统是引擎的核心组件,提供了强大而灵活的表达式解析和计算能力:

  • 完整的四则运算支持:加(+)、减(-)、乘(*)、除(/)操作
  • 括号表达式:支持多层嵌套括号,如 (2d6+4)*(d20-5)
  • 骰子表达式:支持标准骰子表示法 XdY,其中X是骰子数量,Y是面数
  • 百分骰支持:使用 d% 表示掷100面骰子
  • 变量支持:可以在表达式中使用变量,如 level*d8+con_mod
  • 安全性保障:内置表达式验证和安全检查,防止潜在风险

骰子表达式语法

骰子系统支持以下表达式语法:

  • 基本骰子d6, 2d20, 3d8
  • 百分骰d% 等同于 d100
  • 四则运算d20+5, 3d6-2, 4*d4, 8/2
  • 括号表达式(d20+4)*2, 3d6+(2d8-1)
  • 带变量的表达式d20+str_mod, level*d6+bonus
  • 复杂组合(2d6+str_mod)*(level/2+1), d20+proficiency+(advantage?2:0)

安全性考虑

骰子系统包含多层安全措施,确保表达式计算的安全性:

  • 表达式长度限制:防止过长表达式导致的性能问题
  • 危险字符过滤:禁止使用可能导致安全风险的字符和模式
  • 变量验证:确保提供的变量符合安全要求
  • 计算结果限制:防止计算结果过大
  • 异常处理:捕获并适当地处理各种可能的错误情况,如除零错误

性能优化

骰子系统经过优化,可以高效处理各种表达式:

  • 使用正则表达式高效识别骰子表达式
  • 利用asteval库进行安全快速的表达式计算
  • 实现了针对骰子表达式的特殊处理逻辑
  • 优化了变量替换和表达式验证过程

常见用例

战斗系统

# 攻击检定
attack_roll = character.get("d20+str_mod+proficiency")

# 伤害计算
weapon_damage = character.get("2d6+str_mod")

# 暴击伤害
critical_damage = character.get("2d6*2+str_mod")

技能检定

# 攀爬检定(带困难度调整)
climb_check = character.get("d20+dex_mod+(skill_level/2)")

# 感知检定(带环境修正)
surprise_check = character.get("d20+wis_mod+perception_bonus-2")

角色创建

# 能力值生成(4d6取最高3个)
strength = roll("sum(sorted([d6, d6, d6, d6])[1:])")

# 生命值计算(战士职业)
hp = roll("level*d8+con_mod")

🧩 扩展开发

添加新的规则集

  1. 创建新的规则书类,继承或参考Basic1981Rulebook
  2. 实现自定义的角色创建、属性计算等方法
  3. 为新规则创建对应的YAML文件

创建自定义数据源

  1. 创建新类继承Source抽象基类
  2. 实现必要的方法:priority(), keys(), get()
  3. 可选实现:mode()以支持自定义叠加模式

📝 添加新规则指南

本节将指导您如何从规则书中提取游戏规则,并将其以Python或YAML形式实现到/rules目录中。

1. 规则分析与提取

当您要实现一个新规则时,首先需要系统性地分析规则书:

  1. 识别核心机制:找出规则书中的核心计算方法、属性关系和触发条件
  2. 分解成数值关系:将复杂规则分解为可计算的数值表达式
  3. 确定优先级:决定规则相对于其他规则的优先级顺序
  4. 定义适用条件:确定规则在什么情况下适用

示例:分析B/X D&D中的战士攻击加值规则

规则描述:"战士每级获得+1攻击加值"

  • 核心机制:等级与攻击加值的线性关系
  • 数值表达式:attack_bonus = level - 1
  • 优先级:中等(10),确保基础规则不被覆盖
  • 适用条件:所有战士职业角色

2. 使用YAML实现规则(推荐)

对于大多数常规规则,使用YAML文件是最简单的方法。这些文件应该放在/rules/yaml/目录下。

YAML规则文件结构

name: "规则名称"
priority: 优先级数值
description: "规则描述"
attributes:
  属性名1:
    value: "属性值或表达式"
    mode: "叠加模式(override/add/mul)"
  属性名2:
    value: "属性值或表达式"
    mode: "叠加模式"

实现示例:战士职业规则

name: "fighter"
priority: 10
description: "战士是精通战斗的专家"
attributes:
  hit_dice: "1d8"
  hit_points: "level * d8 + con_mod"
  attack_bonus: "level - 1"
  weapon_proficiency: "all"
  armor_proficiency: "all"
  max_level: 14

3. 使用Python实现复杂规则

对于包含复杂逻辑、条件判断或特殊计算的规则,应使用Python类实现。

实现步骤

  1. /rules/目录下创建新的Python模块
  2. 参考basic1981.py创建规则书类
  3. 实现核心方法:
    • 规则加载方法
    • 角色创建方法
    • 能力值生成和修正计算
    • 自定义检定或计算方法

复杂规则实现示例

class AdvancedRulebook:
    def __init__(self):
        self.races = {}
        self.classes = {}
        # 加载YAML规则文件
        self._load_rules()
    
    def _load_rules(self):
        # 从YAML文件夹加载规则
        # ...
    
    def create_character(self, character_class=None, race=None, name=None):
        # 实现角色创建逻辑
        # 包含复杂的条件判断和计算
        # ...
    
    def custom_check(self, entity, check_type, difficulty):
        # 实现自定义检定逻辑
        # ...

4. 规则优先级和叠加模式

规则引擎支持三种主要的属性叠加模式:

  • override (覆盖):直接替换现有值
  • add (加法):将值加到现有值上(支持数字和骰子表达式)
  • mul (乘法):将现有值乘以指定因子

优先级决定了规则应用的顺序:数字越小,优先级越高。

5. 测试您的新规则

添加新规则后,确保进行充分测试:

  1. 编写单元测试验证规则计算正确性
  2. 测试规则与其他规则的交互
  3. 验证边缘情况和特殊条件
# 测试示例
def test_fighter_rules():
    rulebook = Basic1981Rulebook()
    fighter = create_character(rulebook, character_class="fighter")
    
    # 验证攻击加值计算正确
    assert fighter.get("attack_bonus") == fighter.get("level") - 1
    
    # 验证生命值计算
    assert fighter.get("hp") > 0  # 应该有正的生命值

6. 最佳实践

  • 保持简单:尽可能使用YAML实现简单规则
  • 模块化:将复杂规则拆分为逻辑组件
  • 文档化:为每个规则添加清晰的描述和注释
  • 一致性:遵循现有规则的命名和结构约定
  • 可扩展性:设计规则时考虑未来可能的扩展

🧪 测试

项目使用pytest进行全面测试,确保所有功能正常工作并保持向后兼容。

运行测试

运行所有测试:

python -m pytest

仅运行骰子系统测试:

python -m pytest tests/test_dice.py -v

运行特定测试用例:

python -m pytest tests/test_dice.py::test_basic_operations -v

测试覆盖

项目测试涵盖了以下关键领域:

  • 骰子系统测试:验证基本掷骰、四则运算、括号表达式、变量替换和错误处理
  • 实体系统测试:测试属性设置、获取、叠加和来源管理
  • 规则系统测试:验证规则加载、属性计算和职业种族组合

使用验证脚本

使用预配置的验证脚本运行所有检查:

Windows:

verify.bat

添加新测试

添加新功能时,请确保同时添加相应的测试用例:

  1. tests/ 目录中创建或更新相应的测试文件
  2. 使用pytest的测试函数格式编写测试
  3. 确保测试覆盖正常情况、边界情况和错误处理
  4. 运行测试以验证实现

🤝 贡献指南

欢迎贡献代码、报告问题或提供建议!请遵循以下步骤:

  1. Fork 仓库
  2. 创建功能分支 (git checkout -b feature/amazing-feature)
  3. 提交更改 (git commit -m 'Add some amazing feature')
  4. 推送到分支 (git push origin feature/amazing-feature)
  5. 开启 Pull Request

📄 许可证

本项目使用MIT许可证。详情请参见LICENSE文件。

About

A flexible and powerful OSR tabletop role-playing game rule engine, supporting a dice system with full arithmetic operations, entity management, and rule loading

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 99.2%
  • Batchfile 0.8%