Actions
斗地主插件的 5 个 Action:PLAY_CARDS / PASS / CALL_LANDLORD / ROB_LANDLORD / REVEAL_BOTTOM_CARDS,及其 Payload 类型与工厂函数。
概述
每个 Action 由三部分组成:
- Action 类型常量:如
PLAY_CARDS_ACTION = 'PLAY_CARDS',用于ActionHandler.type匹配与 RuleEngine 过滤。 - Payload 接口:描述
action.payload的形状。 - Action 类型别名:
Action<typeof XXX_ACTION, XxxPayload>,泛型化的Action。 - 工厂函数:
createXxxAction(...),构造 Action 实例。
所有工厂函数内部调用核心 createAction(...),并对入参做防御性拷贝(如 cardIds 列表会被复制)。
导出方式
斗地主的所有 Action 符号通过 decklet/doudizhu 子路径入口导出(对应 src/plugins/doudizhu/index.ts barrel):
import {
createPlayCardsAction,
createPassAction, // 斗地主版 PASS(与核心 PASS_ACTION 同名,但在子路径内互不冲突)
createCallLandlordAction,
createRobLandlordAction,
createRevealBottomCardsAction
} from 'decklet/doudizhu'由于斗地主走独立子路径,其 PASS_ACTION / createPassAction 与核心 decklet 主入口的同名符号天然隔离,无需 DDZ_ 前缀别名。
PLAY_CARDS_ACTION
从玩家手牌中打出 1..20 张牌至弃牌堆。
类型常量
const PLAY_CARDS_ACTION = 'PLAY_CARDS' as constPlayCardsPayload
interface PlayCardsPayload {
cardIds: string[]
}| 字段 | 类型 | 说明 |
|---|---|---|
cardIds | string[] | 待打出的卡牌 id 列表(顺序保留) |
PlayCardsAction
type PlayCardsAction = Action<typeof PLAY_CARDS_ACTION, PlayCardsPayload>createPlayCardsAction()
function createPlayCardsAction(
playerId: string,
cardIds: string[]
): PlayCardsAction参数
playerId: string— 出牌玩家 idcardIds: string[]— 待打出的卡牌 id 列表(会被复制以避免外部修改)
返回值
PlayCardsAction— Action 实例
行为
构造一个 PLAY_CARDS Action,payload.cardIds 为入参数组的浅拷贝 [...cardIds]。不进行任何校验——校验由 RuleEngine 完成。
示例
import { createPlayCardsAction } from 'decklet/doudizhu'
// 打出两张同点数牌(构成 PAIR)
const action = createPlayCardsAction('p1', ['ddz-♠-3', 'ddz-♥-3'])
engine.dispatch(action)PASS_ACTION
当前玩家本轮选择不出牌。
类型常量
const PASS_ACTION = 'PASS' as const复用核心的 PASS_ACTION 类型字符串 'PASS',便于订阅者统一监听 PASS 事件而无需关心具体游戏。
PassAction
type PassAction = Action<typeof PASS_ACTION, Record<string, never>>Payload 为空对象 Record<string, never>。
createPassAction()
function createPassAction(playerId: string): PassAction参数
playerId: string— 选择过牌的玩家 id
返回值
PassAction— Action 实例,payload 为{}
行为
仅当存在可压制的 lastCombination 时合法(即不是新一轮的首出)。连续两次 PASS 会重置当前轮次(由 PassEffect 强制执行)。
示例
import { createPassAction } from 'decklet/doudizhu'
engine.dispatch(createPassAction('p2'))CALL_LANDLORD_ACTION
在 BIDDING 阶段,玩家选择叫地主(true)或不叫(false)。
类型常量
const CALL_LANDLORD_ACTION = 'CALL_LANDLORD' as constCallLandlordPayload
interface CallLandlordPayload {
/** true → 成为地主候选人;false → 本轮不叫。 */
call: boolean
}| 字段 | 类型 | 说明 |
|---|---|---|
call | boolean | true 表示叫地主,false 表示不叫 |
CallLandlordAction
type CallLandlordAction = Action<typeof CALL_LANDLORD_ACTION, CallLandlordPayload>createCallLandlordAction()
function createCallLandlordAction(
playerId: string,
call: boolean
): CallLandlordAction参数
playerId: string— 执行叫地主的玩家 idcall: boolean—true表示叫地主,false表示不叫
返回值
CallLandlordAction— Action 实例
行为
Phase 5 简化流程:首位叫地主者立即成为地主候选人,副作用派发 REVEAL_BOTTOM_CARDS 终局。call=false 时玩家加入 DDZ_VAR_BIDDER_PASSED 并推进叫分人索引;若所有人不叫则触发 redeal() 重新洗牌发牌。
示例
import { createCallLandlordAction } from 'decklet/doudizhu'
// 首位叫分人叫地主
engine.dispatch(createCallLandlordAction('p1', true))ROB_LANDLORD_ACTION
在已有玩家叫地主后,后续按座位顺序的叫分人可选择"抢地主"(加价叫分)以夺取地主身份。
类型常量
const ROB_LANDLORD_ACTION = 'ROB_LANDLORD' as constRobLandlordPayload
interface RobLandlordPayload {
/** true → 抢地主(加价叫分);false → 不抢。 */
rob: boolean
}| 字段 | 类型 | 说明 |
|---|---|---|
rob | boolean | true 表示抢地主,false 表示不抢 |
RobLandlordAction
type RobLandlordAction = Action<typeof ROB_LANDLORD_ACTION, RobLandlordPayload>createRobLandlordAction()
function createRobLandlordAction(
playerId: string,
rob: boolean
): RobLandlordAction参数
playerId: string— 抢地主的玩家 idrob: boolean—true表示抢地主,false表示不抢
返回值
RobLandlordAction— Action 实例
行为
Phase 5 首版默认叫分流程不触发此 Action——首位叫地主者直接成为地主。注册此 Action 是为了让后续更完整的叫分流程可以接入而无需改动 Plugin 对外接口。详见 effects.md 中的 applyRobLandlordSideEffects。
示例
import { createRobLandlordAction } from 'decklet/doudizhu'
// 假设 p1 已叫地主,p2(按座位顺序的下一位)选择抢地主
engine.dispatch(createRobLandlordAction('p2', true))REVEAL_BOTTOM_CARDS_ACTION
将 3 张底牌从底牌 zone 移入地主手牌,并将阶段从 BIDDING 切换为 PLAYING。
类型常量
const REVEAL_BOTTOM_CARDS_ACTION = 'REVEAL_BOTTOM_CARDS' as constRevealBottomCardsAction
type RevealBottomCardsAction = Action<
typeof REVEAL_BOTTOM_CARDS_ACTION,
Record<string, never>
>无 playerId(系统派发),payload 为空对象 Record<string, never>。
createRevealBottomCardsAction()
function createRevealBottomCardsAction(): RevealBottomCardsAction参数
无。
返回值
RevealBottomCardsAction— Action 实例(无 playerId,payload 为{})
行为
Phase 5 采用系统派发的 Action(无 playerId),使该阶段切换被记录到 ActionHistory 中,并由 ReplayEngine 忠实重放。当地主身份确定后,由 CallLandlord / RobLandlord 的副作用派发。客户端不应直接派发此 Action。
示例
import { createRevealBottomCardsAction } from 'decklet/doudizhu'
// 通常不直接调用——由 CallLandlord/RobLandlord 副作用自动派发
// 但测试中可手动派发以模拟终局
const action = createRevealBottomCardsAction()
// engine.dispatch(action) // 需先设置 DDZ_VAR_LANDLORD_CANDIDATE_ID完整对照表
| Action 类型常量 | 字面值 | Payload | 工厂函数 | 是否系统派发 |
|---|---|---|---|---|
PLAY_CARDS_ACTION | 'PLAY_CARDS' | PlayCardsPayload | createPlayCardsAction(playerId, cardIds) | 否 |
PASS_ACTION | 'PASS' | Record<string, never> | createPassAction(playerId) | 否 |
CALL_LANDLORD_ACTION | 'CALL_LANDLORD' | CallLandlordPayload | createCallLandlordAction(playerId, call) | 否 |
ROB_LANDLORD_ACTION | 'ROB_LANDLORD' | RobLandlordPayload | createRobLandlordAction(playerId, rob) | 否 |
REVEAL_BOTTOM_CARDS_ACTION | 'REVEAL_BOTTOM_CARDS' | Record<string, never> | createRevealBottomCardsAction() | 是(无 playerId) |
注意事项
PLAY_CARDS的cardIds上限由DDZ_MAX_PLAYED_CARDS = 20强制(详见 rules.md 的playerOwnsCardsRule)。PASS_ACTION与核心Action.PASS_ACTION共用类型字符串'PASS'——订阅 PASS 事件时需注意区分游戏上下文。REVEAL_BOTTOM_CARDS是系统派发 Action,被doudizhuPhaseRule/doudizhuPlayerTurnRule豁免(不要求 BIDDING 阶段或当前玩家匹配);但若DDZ_VAR_LANDLORD_CANDIDATE_ID未设置,其处理器会抛错。