从零设计 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");
}
}
配置与代码分离
任务描述、对话树、奖励清单全部放独立配置文件,代码只负责读取和执行。这样加新任务不需要动任何核心逻辑,也方便让不写代码的策划直接维护内容。
奖励发放要幂等
以「状态置为已完成」作为发放闸门,且发放与状态更新在同一个同步流程里完成。重复交任务、刷新页面重复请求,都只会发一次奖——这是被玩家真实测出来过的教训。
任务系统的复杂度不在代码量,而在边界:谁能改状态、什么时候改、改错了怎么修。这三件事想清楚,功能就很稳。