refactor: add status cards and rules.
This commit is contained in:
parent
7b954bb5a5
commit
6984e54bdf
|
|
@ -3,14 +3,17 @@ import encounterDesertCsv from './encounterDesert.csv';
|
||||||
import enemyDesertCsv from './enemyDesert.csv';
|
import enemyDesertCsv from './enemyDesert.csv';
|
||||||
import enemyIntentDesertCsv from './enemyIntentDesert.csv';
|
import enemyIntentDesertCsv from './enemyIntentDesert.csv';
|
||||||
import effectDesertCsv from './effectDesert.csv';
|
import effectDesertCsv from './effectDesert.csv';
|
||||||
|
import statusCardDesertCsv from './statusCardDesert.csv';
|
||||||
|
|
||||||
export const heroItemFighter1Data = heroItemFighter1Csv();
|
export const heroItemFighter1Data = heroItemFighter1Csv();
|
||||||
export const encounterDesertData = encounterDesertCsv();
|
export const encounterDesertData = encounterDesertCsv();
|
||||||
export const enemyDesertData = enemyDesertCsv();
|
export const enemyDesertData = enemyDesertCsv();
|
||||||
export const enemyIntentDesertData = enemyIntentDesertCsv();
|
export const enemyIntentDesertData = enemyIntentDesertCsv();
|
||||||
export const effectDesertData = effectDesertCsv();
|
export const effectDesertData = effectDesertCsv();
|
||||||
|
export const statusCardDesertData = statusCardDesertCsv();
|
||||||
|
|
||||||
export { default as encounterDesertCsv, type EncounterDesert } from './encounterDesert.csv';
|
export { default as encounterDesertCsv, type EncounterDesert } from './encounterDesert.csv';
|
||||||
export { default as enemyDesertCsv, type EnemyDesert } from './enemyDesert.csv';
|
export { default as enemyDesertCsv, type EnemyDesert } from './enemyDesert.csv';
|
||||||
export { default as enemyIntentDesertCsv, type EnemyIntentDesert } from './enemyIntentDesert.csv';
|
export { default as enemyIntentDesertCsv, type EnemyIntentDesert } from './enemyIntentDesert.csv';
|
||||||
export { default as effectDesertCsv, type EffectDesert } from './effectDesert.csv';
|
export { default as effectDesertCsv, type EffectDesert } from './effectDesert.csv';
|
||||||
|
export { default as statusCardDesertCsv, type StatusCardDesert } from './statusCardDesert.csv';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
# 战斗规则
|
||||||
|
|
||||||
|
## 战斗状态
|
||||||
|
|
||||||
|
角色表:
|
||||||
|
- 敌方角色表
|
||||||
|
- 我方角色表
|
||||||
|
|
||||||
|
角色状态:
|
||||||
|
- hp/最大hp
|
||||||
|
- buff表(名称->层数,同名buff合并叠加)
|
||||||
|
|
||||||
|
战利品表:
|
||||||
|
- 类型
|
||||||
|
- 数量
|
||||||
|
|
||||||
|
触发规则表:
|
||||||
|
- 类型
|
||||||
|
- 层数
|
||||||
|
|
||||||
|
## 战斗开始
|
||||||
|
|
||||||
|
战斗开始时,首先进行敌方角色的战斗开始结算,然后进行玩家的战斗开始结算。
|
||||||
|
|
||||||
|
战斗开始会让玩家抓5张起始手牌,让敌方角色初始化意图。
|
||||||
|
|
||||||
|
## 回合
|
||||||
|
|
||||||
|
进行一个玩家回合,然后进行一个敌方回合,以此重复,直到不存在玩家或敌方角色存活。
|
||||||
|
|
||||||
|
玩家回合包含以下阶段:
|
||||||
|
|
||||||
|
- buff更新:temporary buff清空,lingering buff层数-1。
|
||||||
|
- 回合开始:触发回合开始结算的效果。
|
||||||
|
- 玩家行动:玩家可以花费能量打出手牌。点结束来结束行动。
|
||||||
|
- 回合结束:触发回合结束结算的效果。
|
||||||
|
- 重置手牌:弃掉剩余的手牌,重新抓5张手牌。
|
||||||
|
- 重置能量:重置到3点能量。
|
||||||
|
|
||||||
|
敌人回合包含以下阶段:
|
||||||
|
|
||||||
|
- buff更新:每个敌人的temporary buff清空,lingering buff层数-1。
|
||||||
|
- 回合开始:触发回合开始结算的效果。
|
||||||
|
- 敌人行动:每个敌人的意图依次生效,然后更新下一个意图。
|
||||||
|
- 回合结束:触发回合结束结算的效果。
|
||||||
|
|
||||||
|
## 效果
|
||||||
|
|
||||||
|
效果结算时,具有以下上下文:
|
||||||
|
- name: 效果名称
|
||||||
|
- stacks: 层数
|
||||||
|
- target: 目标角色,如果有
|
||||||
|
- source:来源角色,如果有
|
||||||
|
- card:来源卡牌,如果有
|
||||||
|
|
||||||
|
效果有以下类型:
|
||||||
|
|
||||||
|
- Instant: 立即结算。
|
||||||
|
|
||||||
|
- Buff: 施加为buff,持续整场战斗。
|
||||||
|
- BuffTemporary: 施加为buff,下次buff更新时清空。
|
||||||
|
- BuffLingering: 施加为buff,下次buff更新时层数-1。
|
||||||
|
- BuffPosture: 施加为buff,受到伤害时扣除等量层数。
|
||||||
|
|
||||||
|
- Item: 施加为物品buff,对来源卡牌对应的物品周围的物品生效。
|
||||||
|
- ItemUntilPlayed:施加为物品buff,对来源卡牌对应的物品生效,生效一次后失效。
|
||||||
|
- ItemTemporary: 施加为物品buff,对来源卡牌对应的物品生效,下次buff更新时清空。
|
||||||
|
- ItemPermanent: 施加为物品buff,对来源卡牌对应的物品生效,战斗结束后依然有效。
|
||||||
|
|
||||||
|
- Card: 施加为状态卡牌,洗入玩家弃牌堆。对敌人无效。
|
||||||
|
- CardDraw:洗入抓牌堆。
|
||||||
|
- CardHand:加入手牌。
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# 状态牌:由某些效果创建,洗入玩家牌堆或手牌
|
||||||
|
# unplayable: 是否不可打出
|
||||||
|
# effects: 状态牌在场时施加的效果
|
||||||
|
|
||||||
|
id, name, desc, unplayable, effects
|
||||||
|
string, string, string, boolean, ['self'; @effectDesert; number][]
|
||||||
|
wound, 伤口, 无效果,占用手牌和牌堆, true,
|
||||||
|
venom, 蛇毒, 弃掉超过1张蛇毒时受到6伤害, true, [self; venom; 1]
|
||||||
|
curse, 诅咒, 受攻击时物品攻击-1,直到弃掉一张该物品的牌, true, [self; curse; 1]
|
||||||
|
static, 静电, 在手里时受电击伤害+1, true, [self; static; 1]
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import type { EffectDesert } from './effectDesert.csv';
|
||||||
|
|
||||||
|
type StatusCardDesertTable = readonly {
|
||||||
|
readonly id: string;
|
||||||
|
readonly name: string;
|
||||||
|
readonly desc: string;
|
||||||
|
readonly unplayable: boolean;
|
||||||
|
readonly effects: readonly ["self", EffectDesert, number];
|
||||||
|
}[];
|
||||||
|
|
||||||
|
export type StatusCardDesert = StatusCardDesertTable[number];
|
||||||
|
|
||||||
|
declare function getData(): StatusCardDesertTable;
|
||||||
|
export default getData;
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
enemyDesertData,
|
enemyDesertData,
|
||||||
enemyIntentDesertData,
|
enemyIntentDesertData,
|
||||||
effectDesertData,
|
effectDesertData,
|
||||||
|
statusCardDesertData,
|
||||||
} from '@/samples/slay-the-spire-like/data';
|
} from '@/samples/slay-the-spire-like/data';
|
||||||
|
|
||||||
describe('heroItemFighter1.csv import', () => {
|
describe('heroItemFighter1.csv import', () => {
|
||||||
|
|
@ -258,3 +259,53 @@ describe('enemyIntentDesert.csv import', () => {
|
||||||
expect(enemyIds.size).toBe(14);
|
expect(enemyIds.size).toBe(14);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('statusCardDesert.csv import', () => {
|
||||||
|
it('should import data as an array', () => {
|
||||||
|
expect(Array.isArray(statusCardDesertData)).toBe(true);
|
||||||
|
expect(statusCardDesertData.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have expected number of status cards', () => {
|
||||||
|
expect(statusCardDesertData.length).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have correct fields for each status card', () => {
|
||||||
|
for (const card of statusCardDesertData) {
|
||||||
|
expect(card).toHaveProperty('id');
|
||||||
|
expect(card).toHaveProperty('name');
|
||||||
|
expect(card).toHaveProperty('desc');
|
||||||
|
expect(card).toHaveProperty('unplayable');
|
||||||
|
expect(card).toHaveProperty('effects');
|
||||||
|
expect(typeof card.id).toBe('string');
|
||||||
|
expect(typeof card.name).toBe('string');
|
||||||
|
expect(typeof card.desc).toBe('string');
|
||||||
|
expect(typeof card.unplayable).toBe('boolean');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have all cards unplayable', () => {
|
||||||
|
for (const card of statusCardDesertData) {
|
||||||
|
expect(card.unplayable).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have effects with target, effect ref, and value', () => {
|
||||||
|
for (const card of statusCardDesertData) {
|
||||||
|
expect(Array.isArray(card.effects)).toBe(true);
|
||||||
|
for (const [target, effect, value] of card.effects) {
|
||||||
|
expect(target).toBe('self');
|
||||||
|
expect(typeof effect === 'string' || typeof effect === 'object').toBe(true);
|
||||||
|
expect(typeof value).toBe('number');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain expected status cards by id', () => {
|
||||||
|
const ids = statusCardDesertData.map(c => c.id);
|
||||||
|
expect(ids).toContain('wound');
|
||||||
|
expect(ids).toContain('venom');
|
||||||
|
expect(ids).toContain('curse');
|
||||||
|
expect(ids).toContain('static');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue