从零设计 MUD 任务系统:状态机与 trigger 协作

任务系统是 MUD 里最容易被做歪的模块之一。这篇整理我们自己世界里的做法:把任务拆成状态流转、条件判定、奖励发放三件事,各自用最直接的方式实现。

三态状态机

每个任务只保留三个状态:未接、进行中、已完成,存在玩家对象的 mapping 里,以任务 ID 为键。状态只由明确的事件推进,不允许多个入口同时改写。

#define NOT_STARTED 0
#define RUNNING     1
#define DONE        2

mapping quests = ([]);

void set_quest(string qid, int state) {
    quests[qid] = state;
    save();
}

条件判定挂在 trigger 上,不要轮询

早期版本把任务条件放在 heart_beat() 里每隔几秒扫一遍,玩家一多 CPU 就顶不住。现在改为在关键行为上挂 trigger:击杀、给予、到达、使用,事件发生了才判定。

// 玩家击杀 NPC 时由战斗模块调用
void on_kill(object victim) {
    string qid = "kill_bandit_10";
    if (query_quest(qid) != RUNNING) return;
    add_quest_progress(qid, 1);
    if (query_quest_progress(qid) >= 10) {
        set_quest(qid, DONE);
        tell_object(this_object(), "任务完成,回去找捕头领取赏金。\n");
    }
}

配置与代码分离

任务描述、对话树、奖励清单全部放独立配置文件,代码只负责读取和执行。这样加新任务不需要动任何核心逻辑,也方便让不写代码的策划直接维护内容。

奖励发放要幂等

以「状态置为已完成」作为发放闸门,且发放与状态更新在同一个同步流程里完成。重复交任务、刷新页面重复请求,都只会发一次奖——这是被玩家真实测出来过的教训。

任务系统的复杂度不在代码量,而在边界:谁能改状态、什么时候改、改错了怎么修。这三件事想清楚,功能就很稳。
← 上一篇:FluffOS 编译部署 下一篇:Telnet 协议浅析 →