Compare commits
No commits in common. "13007c8fa4dfc3a1d5d746acbf3bff90a84bd948" and "e8ce7b7216d5b6f1c93f49a94911600e2ae02ba2" have entirely different histories.
13007c8fa4
...
e8ce7b7216
|
|
@ -1,92 +0,0 @@
|
||||||
# 要求
|
|
||||||
|
|
||||||
编写ttrpg冒险。冒险将要使用./system.md描述的规则运行。
|
|
||||||
|
|
||||||
每个冒险应该包含以下要素:
|
|
||||||
|
|
||||||
- 简报:地理、环境、当前态势。
|
|
||||||
- 后果:如果玩家什么都不做,将会默认发生的后果。
|
|
||||||
- 压力:一些随机遭遇,将在冒险中随机发生。
|
|
||||||
- 主线:一些逻辑上连续的遭遇。
|
|
||||||
- 支线:一些独立的支线遭遇,完成可以获得资源帮助。
|
|
||||||
|
|
||||||
## 简报
|
|
||||||
|
|
||||||
应当确立以下内容:
|
|
||||||
|
|
||||||
- 环境:地理特征,社会风貌,政治态势。
|
|
||||||
- 当前态势:冒险要解决的事件当前的状态。
|
|
||||||
- 势力:1-2种与事件相关的势力。
|
|
||||||
- 玩家角色:玩家的身份,以及初始任务目标。
|
|
||||||
|
|
||||||
设计势力时,应当确立以下内容:
|
|
||||||
|
|
||||||
- 1-2 名代表性NPC。
|
|
||||||
- 势力当前的计划以及障碍。
|
|
||||||
- 势力掌握的资源。
|
|
||||||
|
|
||||||
## 后果
|
|
||||||
|
|
||||||
随着时间的推移,如果玩家未能解决事件,则不好的事情会逐渐发生。
|
|
||||||
|
|
||||||
后果分三个阶段,每个阶段会引入新的规则,为玩家行动制造额外障碍。
|
|
||||||
|
|
||||||
在第三个阶段发生后,玩家行动将会遭受极大挑战,很可能很快失败。
|
|
||||||
|
|
||||||
## 压力
|
|
||||||
|
|
||||||
设计10条随机遭遇,用于玩家冒险中遇到的意外。
|
|
||||||
|
|
||||||
大部分应该为玩家制造危险。随着后果的发生,随机遭遇的危险程度也会随之提升。
|
|
||||||
|
|
||||||
## 主线
|
|
||||||
|
|
||||||
设计6条逻辑连续的遭遇,完成一条遭遇后会揭露下一条遭遇。
|
|
||||||
|
|
||||||
在完成最后一条遭遇后,玩家可以解决事件。
|
|
||||||
|
|
||||||
## 支线
|
|
||||||
|
|
||||||
设计6条逻辑独立的遭遇,每个遭遇会给玩家提供一些可能的资源。
|
|
||||||
|
|
||||||
每个遭遇位于一个独立地点,需要玩家投入时间探索或完成挑战。
|
|
||||||
|
|
||||||
## 地图设计
|
|
||||||
|
|
||||||
描述冒险发生的地理布局及各遭遇点之间的逻辑连接。
|
|
||||||
|
|
||||||
- 区域布局:描述主要地标及其空间关系。
|
|
||||||
- 路径与环境:描述连接地点的路径特征及旅行中的风险。
|
|
||||||
- 地点标注:明确主线遭遇(M1-M6)和支线遭遇(S1-S6)所在的地理位置。
|
|
||||||
|
|
||||||
使用`mermaid`语法绘制地图,并插入冒险文件中。
|
|
||||||
|
|
||||||
## 遭遇的设计
|
|
||||||
|
|
||||||
设计一项遭遇时,如果有NPC出现,则为出现的NPC设计动机、当前计划、当前遇到的障碍,以便玩家交互。
|
|
||||||
|
|
||||||
如果没有NPC,则设计2-4种可以交互的环境元素,尽量覆盖不同的玩家属性以及不同的交互性质。
|
|
||||||
|
|
||||||
每条遭遇都需要明确描述发生的场景地点。尽量设计不同风格的地点。
|
|
||||||
|
|
||||||
## 文本格式
|
|
||||||
|
|
||||||
输出时,使用markdown格式。
|
|
||||||
|
|
||||||
对于遭遇表而言,放在`csv`文件里:
|
|
||||||
|
|
||||||
```csv
|
|
||||||
label,body
|
|
||||||
1,遭遇内容的markdown文本
|
|
||||||
2,遭遇内容的markdown文本
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
在冒险本体的markdown里,使用以下语法引用遭遇表:
|
|
||||||
`:md-table[./encounters.csv]`
|
|
||||||
|
|
||||||
主线、支线、压力等每个类型,需要有独特的csv文件。
|
|
||||||
|
|
||||||
## 文件结构
|
|
||||||
|
|
||||||
为每个冒险创建一个新文件夹。冒险本体以`adventure.md`保存。
|
|
||||||
|
|
@ -1,15 +1,3 @@
|
||||||
# Commander Test
|
# Commander Test
|
||||||
|
|
||||||
:md-commander[./commands.csv]
|
:md-commander[./commands.csv]
|
||||||
|
|
||||||
## Lonelog
|
|
||||||
|
|
||||||
`我` 走进酒吧。
|
|
||||||
|
|
||||||
`oracle` 酒吧里人多吗?
|
|
||||||
|
|
||||||
`roll` d20 = 18 `prompt` 是的
|
|
||||||
|
|
||||||
`fact` 酒吧里有很多人。
|
|
||||||
|
|
||||||
:[blah]
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
# 系统
|
|
||||||
|
|
||||||
## 玩家角色
|
|
||||||
|
|
||||||
只有一个玩家角色。
|
|
||||||
|
|
||||||
### 基本属性
|
|
||||||
|
|
||||||
玩家角色具有以下基本属性:
|
|
||||||
|
|
||||||
- 力量
|
|
||||||
- 体质
|
|
||||||
- 敏捷
|
|
||||||
- 感知
|
|
||||||
- 智力
|
|
||||||
- 魅力
|
|
||||||
|
|
||||||
每个基本属性范围1-19,会用于属性检定,掷D20小于等于属性则检定成功。
|
|
||||||
|
|
||||||
属性可能遭受损伤扣减,损伤需要通过休息来缓慢回复。
|
|
||||||
|
|
||||||
一次受到超过当前一半属性损伤时,会遭受严重创伤,该属性即使休息也不会回复损伤。
|
|
||||||
|
|
||||||
必须通过专家、专门地点或道具来解除严重创伤。
|
|
||||||
|
|
||||||
### 耐受
|
|
||||||
|
|
||||||
玩家具有一条耐受度属性,只需几分钟的调整即可完全恢复。
|
|
||||||
|
|
||||||
耐受度随玩家角色成长而提升,初始范围为1-6。
|
|
||||||
|
|
||||||
在玩家l做好准备时,可消耗耐受用于抵抗属性损伤,每点耐受抵抗1点损伤。
|
|
||||||
|
|
||||||
### 时间
|
|
||||||
|
|
||||||
每天有24小时,玩家的每次基本行动花费1小时。
|
|
||||||
|
|
||||||
白天6点到晚上0点属于行动时间:
|
|
||||||
|
|
||||||
- 在条件允许的情况下可以进行休息,每小时随机恢复1点属性损伤。
|
|
||||||
|
|
||||||
晚上0点到凌晨6点属于睡眠时间:
|
|
||||||
|
|
||||||
- 若睡觉休息,每小时随机恢复1点属性损伤。
|
|
||||||
- 若条件不允许,则即使休息也不能回复损伤。
|
|
||||||
- 若不休息,则每小时随机遭受1点属性损伤。
|
|
||||||
|
|
||||||
### 属性骰
|
|
||||||
|
|
||||||
随机回复/扣减属性时,使用D6属性骰来决定随机回复/扣减的属性。
|
|
||||||
|
|
||||||
若掷恢复时,掷出的属性已满,则本次随机恢复没有效果。
|
|
||||||
|
|
||||||
### 基本行动
|
|
||||||
|
|
||||||
除休息外,玩家可进行以下行动,每次花费1小时:
|
|
||||||
|
|
||||||
- 旅行:移动到另一地点。若旅途超过1小时,可能在半路遭遇随机遭遇。
|
|
||||||
- 调查:检查当前地点,揭露更多线索或交互对象。
|
|
||||||
- 交互:根据交互性质而定,可能有不同的检定、难度、机会。
|
|
||||||
|
|
||||||
### 交互行动
|
|
||||||
|
|
||||||
每条交互需要三种属性:
|
|
||||||
|
|
||||||
- 主属性:玩家需要使用什么属性来进行此交互。
|
|
||||||
- 难度:玩家需要积累多少成功进度来成功完成此交互。
|
|
||||||
- 机会:玩家积累多少失败进度后交互失败,且玩家不可再尝试。
|
|
||||||
|
|
||||||
如:`力量3/1`(力量,难度3,机会1)表示玩家使用力量属性检定,3成功进度后交互成功完成,1失败进度后交互失败且不可再尝试。
|
|
||||||
|
|
||||||
每次进行交互时,掷D20检定骰,以及D4进度骰。
|
|
||||||
若检定骰小于等于玩家当前主属性,则获得进度骰数量成功进度,否则获得对应数量失败进度。
|
|
||||||
|
|
||||||
根据交互的挑战性质设计效果:
|
|
||||||
|
|
||||||
- 应变:难度/机会都低,即使失败也能达到成功的效果,仅受到不可耐受的属性损伤。
|
|
||||||
- 挑战:难度高/机会低,失败后根据进度获取收益,且交互可再次尝试。
|
|
||||||
- 努力:难度/机会都高,失败无事发生。
|
|
||||||
- 风险:难度低/机会高,失败有较重大损失。
|
|
||||||
|
|
||||||
检定的难度/机会不会告知玩家。若没有触发成功也没有触发失败,则检定后仅告知当前成功/失败进度。
|
|
||||||
|
|
||||||
### 状态
|
|
||||||
|
|
||||||
玩家状态
|
|
||||||
|
|
||||||
- 属性损伤:属性类型+当前值
|
|
||||||
- 严重创伤:属性类型
|
|
||||||
- 标签:类型+持续事件,用于疾病、祝福、中毒等
|
|
||||||
- 资源:类型+数量,用于物品、金钱等
|
|
||||||
- 成就:类型+等级,用于声望、技能等
|
|
||||||
|
|
||||||
世界状态
|
|
||||||
|
|
||||||
- 进度:类型+id+成功进度+失败进度,用于势力计划、事件进展等。
|
|
||||||
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
|
@ -32,25 +32,23 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@solidjs/router": "^0.15.0",
|
"@solidjs/router": "^0.15.0",
|
||||||
"chokidar": "^5.0.0",
|
"chokidar": "^5.0.0",
|
||||||
"commander": "^14.0.3",
|
"commander": "^12.1.0",
|
||||||
"csv-parse": "^6.1.0",
|
"csv-parse": "^5.5.6",
|
||||||
"js-yaml": "^4.1.1",
|
"js-yaml": "^4.1.1",
|
||||||
"marked": "^17.0.3",
|
"marked": "^14.1.0",
|
||||||
"marked-alert": "^2.1.2",
|
"marked-alert": "^2.1.2",
|
||||||
"marked-directive": "^1.0.7",
|
"marked-directive": "^1.0.7",
|
||||||
"marked-gfm-heading-id": "^4.1.3",
|
|
||||||
"mermaid": "^11.0.0",
|
|
||||||
"solid-element": "^1.9.1",
|
"solid-element": "^1.9.1",
|
||||||
"solid-js": "^1.9.3"
|
"solid-js": "^1.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rsbuild/core": "^1.1.8",
|
"@rsbuild/core": "^1.1.8",
|
||||||
"@rsbuild/plugin-babel": "^1.1.0",
|
"@rsbuild/plugin-babel": "^1.1.0",
|
||||||
"@rsbuild/plugin-solid": "^1.1.0",
|
"@rsbuild/plugin-solid": "^1.0.7",
|
||||||
"@tailwindcss/postcss": "^4.2.1",
|
"@tailwindcss/postcss": "^4.2.1",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
"@tailwindcss/vite": "^4.0.0",
|
"@tailwindcss/vite": "^4.0.0",
|
||||||
"@types/node": "^22.19.13",
|
"@types/node": "^22.10.2",
|
||||||
"tailwindcss": "^4.0.0",
|
"tailwindcss": "^4.0.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.7.2"
|
"typescript": "^5.7.2"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { Component, createSignal, createEffect, onCleanup, Show, createResource } from 'solid-js';
|
import { Component, createSignal, createEffect, onCleanup, Show, createResource } from 'solid-js';
|
||||||
import { parseMarkdown } from '../markdown';
|
import { parseMarkdown } from '../markdown';
|
||||||
import { fetchData, extractSection } from '../data-loader';
|
import { fetchData, extractSection } from '../data-loader';
|
||||||
import mermaid from 'mermaid';
|
|
||||||
|
|
||||||
export interface ArticleProps {
|
export interface ArticleProps {
|
||||||
src: string;
|
src: string;
|
||||||
|
|
@ -31,8 +30,6 @@ export const Article: Component<ArticleProps> = (props) => {
|
||||||
const data = content();
|
const data = content();
|
||||||
if (data) {
|
if (data) {
|
||||||
props.onLoaded?.();
|
props.onLoaded?.();
|
||||||
// 内容加载完成后,渲染 mermaid 图表
|
|
||||||
void mermaid.run();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,16 +87,6 @@ export const HeadingNode: Component<{
|
||||||
const handleClick = (e: MouseEvent) => {
|
const handleClick = (e: MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
navigate(href);
|
navigate(href);
|
||||||
// 滚动到目标元素,考虑导航栏高度偏移
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
const element = document.getElementById(anchor);
|
|
||||||
if (element) {
|
|
||||||
const navBarHeight = 80;
|
|
||||||
const elementPosition = element.getBoundingClientRect().top;
|
|
||||||
const offsetPosition = window.scrollY + elementPosition - navBarHeight;
|
|
||||||
window.scrollTo({ top: offsetPosition, behavior: "smooth" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const indent = props.depth * 12;
|
const indent = props.depth * 12;
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,10 @@ import { Marked } from 'marked';
|
||||||
import {createDirectives, presetDirectiveConfigs} from 'marked-directive';
|
import {createDirectives, presetDirectiveConfigs} from 'marked-directive';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import markedAlert from "marked-alert";
|
import markedAlert from "marked-alert";
|
||||||
import markedMermaid from "./mermaid";
|
|
||||||
import {gfmHeadingId} from "marked-gfm-heading-id";
|
|
||||||
|
|
||||||
// 使用 marked-directive 来支持指令语法
|
// 使用 marked-directive 来支持指令语法
|
||||||
const marked = new Marked()
|
const marked = new Marked()
|
||||||
.use(gfmHeadingId())
|
|
||||||
.use(markedAlert())
|
.use(markedAlert())
|
||||||
.use(markedMermaid())
|
|
||||||
.use(createDirectives([
|
.use(createDirectives([
|
||||||
...presetDirectiveConfigs,
|
...presetDirectiveConfigs,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import type {MarkedExtension} from "marked";
|
|
||||||
import mermaid from "mermaid";
|
|
||||||
|
|
||||||
mermaid.initialize({
|
|
||||||
theme: 'dark'
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function markedMermaid(): MarkedExtension {
|
|
||||||
return {
|
|
||||||
renderer: {
|
|
||||||
code: (code) => {
|
|
||||||
// Use default render for other languages
|
|
||||||
if (code.lang !== 'mermaid') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use Mermaid to render the diagram
|
|
||||||
return `<pre class="mermaid">${code.text}</pre>`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue