当前位置 : 145z游戏站 | 热血传奇 | 技术教程 | 

传奇服务端脚本实现全服清零与任务系统

热度:
先说清楚一件事:以下写的是LegendofMir2系列(LEG/GOM/GEE/HERO类)服务端的脚本级思路,属于你自己搭建的单机或授权服务端内部脚本开发,不是外挂、不是客户端注入、不是第三方工具。在自己的服务端里改脚本是正常运维;拿去动别人服务器、做破坏用途一律不沾。

一、全服玩家等级清零:不用M2操作,纯脚本自动完成

你的需求拆开是五条硬约束:
1.不通过M2手动操作(不用GM界面点)
2.不走“返回角色/退出游戏”流程
3.活动失败→自动触发
4.全服在线玩家直接清零
5.身上装备先脱下、再放回背包,不能丢、不能消失

1.触发入口:活动失败的那一刻

活动一般用Robot(机器人定时器)或NPC事件驱动。假设是活动时间到/条件不满足导致失败,在失败逻辑里调用一个统一入口:

QuestDiary写法(LEG/GOM通用):

[@活动失败处理]
#CALL[\系统\全服清零.txt]@开始清零

失败判定写在机器人或活动NPC里,一旦成立就#CALL这个文件,全程不碰M2。

2.遍历全服在线玩家

服务端要“拿到所有在线角色对象”,不同引擎API不同,但思路一致:先取在线人数→按索引取Human对象→逐个处理。

GOM/GEE类(支持Human对象数组):

[@开始清零]
#IF
#ACT
;1.先记录全服角色,避免遍历中对象失效
SetInt($G(清零总数))=<$ONLINECOUNT>
SetInt($G(清零索引))=0

[@清零循环]
#IF
CheckInt($G(清零索引))<CheckInt($G(清零总数))
#ACT
;取第N个在线玩家对象
GetOnlineHuman<$G(清零索引)>$H(当前玩家)
;执行单角色清零
#CALL[\系统\单角色清零.txt]@执行
;索引+1
CalcInt($G(清零索引))+1
;循环
#GOTO[@清零循环]

#ELSEACT
;全部处理完,发全服公告
SENDMSG0活动失败!全服等级已清零,装备已收回背包。


HERO引擎(lua插件写法):
functionOnActivityFail()
localplayers=M2.GetOnlinePlayers()
for_Humaninipairs(players)do
StripAndReset(Human)
end
M2.SendMsg(0"活动失败!全服等级已清零,装备已收回背包。")
end

M2.GetOnlinePlayers()和M2.SendMsg按你引擎的实际API名替换,HERO里通常叫GetAllPlayer/GameServer.SendBroadCastMsg。

3.单角色清零核心:脱装备→放背包→清等级

关键顺序不能反:先卸装再清零,且卸装前先判背包空格。

单角色清零脚本(GOM类):

[@执行]
#IF
#ACT
;1.把身上13个装备位全部卸到背包
;引擎命令一般为:TakeOffToBag装备位
;装备位:0武器1衣服2头盔3项链4左戒指5右戒指6左手镯7右手镯8腰带9鞋子10宝石11披风12面罩
SetInt($H(当前玩家)(卸装位))=0

[@卸装循环]
#IF
CheckInt($H(当前玩家)(卸装位))<13
#ACT
;脱下该位装备,放回背包;背包满则自动掉落地面(可配置)
TakeOffToBag<$H(当前玩家)><$H(当前玩家)(卸装位)>
CalcInt($H(当前玩家)(卸装位))+1
#GOTO[@卸装循环]

#ELSEACT
;2.卸完再清零
;清等级(保留1级,传奇不允许0级)
SetLevel<$H(当前玩家)>1
;清经验(经验归零,避免自动升级)
SetExp<$H(当前玩家)>0
;清技能等级(按需,成长任务会重做)
ClearSkill<$H(当前玩家)>
;清任务变量(成长任务/副本任务进度重置)
ClearQuestFlag<$H(当前玩家)>
;回满血蓝(避免清零后残血死)
FullHp<$H(当前玩家)>
FullMp<$H(当前玩家)>
;提示该玩家
SendSysMsg<$H(当前玩家)>活动失败,你的等级已被清零,装备已收回。


HEROlua对应:
functionStripAndReset(Human)
--卸全部装备到背包
foridx=012do
Human:TakeOffToBag(idx)
end
Human:SetLevel(1)
Human:SetExp(0)
Human:ClearSkill()
Human:ClearQuestFlag()
Human:FullHp()
Human:FullMp()
Human:SysMsg("活动失败,等级已清零,装备已收回。")
end


4.几个必须处理的坑

①背包满导致装备消失
清零前先判背包空格数,不足就:
•清掉背包里的垃圾白装(按重量/价值过滤)

•或临时扩展背包(部分引擎支持SetBagSize)

•或把装备直接存进仓库(DepotSave),活动后再发

推荐做法:先GetBagFree(Human)拿到空格,空格<13就先清垃圾再卸装。

②马匹/英雄/宝宝装备
如果有英雄系统,英雄身上也要脱:

TakeOffHeroAll<$H(当前玩家)>

宝宝(道士神兽)直接消失即可,召唤物不算装备。

③元宝/金币/仓库要不要清
等级清零通常只清等级+经验+技能+任务进度,不动金币元宝仓库。你可按需加:

;清金币(保留1000做路费)
SetGold<$H(当前玩家)>1000

别清成0,否则玩家连回城卷都买不起,直接卡死。

④玩家正在交易/在商店/在副本
遍历处理时若玩家处于“不可操作”状态,TakeOffToBag会失败。做法:
•先踢出交易/商店界面(CancelTrade/CloseShop)

•副本中的玩家标记“待清零”,等他回主城再执行(用变量记录,回城事件里补处理)

•或强制召回:MoveTo<$H(当前玩家)>3330330(回土城再处理)

⑤跨线/微端
单线遍历只能清本线。多线要在中心服/网关层广播“清零指令”,各线收到后各自遍历本线在线角色。脚本里加一层:

;线1处理完向线2发消息
SendCrossMsg2CLEAR_ALL_LEVEL

各线Robot监听该消息并触发自己的清零流程。

5.完整触发链路


活动失败判定
→Robot定时器/NPC事件
→#CALL全服清零.txt@开始清零
→遍历在线玩家
→每个玩家:判背包空格→清垃圾→卸13件装备到背包→清等级/经验/技能/任务→回血蓝→发提示
→遍历完发全服公告
→(跨线)广播各线重复上述


全程不打开M2,不踢线不返回角色,玩家原地直接被清零。

二、任务系统:任务栏闪烁+任务窗口分类

传奇原版没有“任务栏闪烁”和“成长/副本分类”这种客户端UI,要实现得靠两部分配合:
•服务端:任务数据、接/交逻辑、进度存储

•客户端/插件:任务栏图标闪烁、分类窗口(需要支持自定义UI的引擎,如GEE、HERO、翎风)

下面按“脚本能控制的程度”分层给方案。

1.服务端:任务数据结构与分类

QuestDiary里按文件夹分类(这是“任务分类”的服务端根基):

\Envir\QuestDiary\
成长任务\
每日签到.txt
升级任务.txt
转生任务.txt
副本任务\
祖玛副本.txt
赤月副本.txt
火龙副本.txt
活动任务\
攻城预热.txt
节日收集.txt


每个任务文件统一模板:

;=====成长任务:升级到35级=====
[@main]
#IF
ISACCEPT成长_升级35
#ACT
#SAY
任务进度:<$\QUEST(成长_升级35)>/35
<继续升级/@close>
#ELSEACT
#SAY
<接受任务:升级到35级/@accept>

[@accept]
#IF
#ACT
ACCEPTQUEST成长_升级35
SetInt(<$HUMAN(成长_升级35)>)=0
SENDMSG0已接受成长任务【升级到35级】!

;=====进度更新(在升级事件里调用)=====
[@升级回调]
#IF
ISACCEPT成长_升级35
CheckLevelEx>=35
#ACT
COMPLETEQUEST成长_升级35
GiveItem祝福油1
SENDMSG0成长任务【升级到35级】已完成,奖励已发放!


任务分类标识用前缀:成长_副本_活动_,后面客户端按前缀自动归类。

2.任务进度存储

•玩家变量:SetInt(<$HUMAN(成长_升级35)>)——存进度,重启不丢

•任务接受标记:ISACCEPT任务名——引擎内置命令

•任务完成标记:COMPLETEQUEST任务名——控制能否重复领取

不要用全局变量存进度,否则全服共用一个进度,A完成B也领奖。

3.任务栏闪烁(客户端层)

传奇客户端右下角“任务”图标闪烁,本质是:服务端推一个状态标志→客户端检测到有新任务/可交任务→图标开始闪。

方案A:引擎自带任务系统(GEE/HERO推荐)
这些引擎内部已有任务栏,脚本只要正确调用ACCEPTQUEST/COMPLETEQUEST,客户端自动:
•新任务可接→图标亮

•任务可交→图标闪

•任务栏里按“当前/已完成/可接”分组

你要做的只是在接/交任务时保证命令成对调用,别漏COMPLETEQUEST。

方案B:自定义闪烁(通用,支持插件引擎)
用客户端插件监听一个自定义封包,服务端在任务状态变化时发送:

服务端(lua插件):
functionNotifyQuestFlash(HumanquestType)
--questType:1成长2副本3活动
Human:SendCustomPacket(0xABquestType)
end

客户端(支持luaUI的引擎):
RegisterPacket(0xABfunction(type)
TaskWindow:SetFlash(true)
TaskWindow:SetType(type)--1/2/3对应三个分类页
end)

客户端收到0xAB就让任务栏图标SetFlash(true)开始闪烁,并切到对应分类页。

方案C:无客户端修改,纯服务端替代(LEG老引擎)
老引擎改不了客户端UI,就用NPC头顶感叹号+屏幕提示模拟:
•任务可接:NPC头顶显示!(服务端SetNpcTitle)

•任务可交:NPC头顶显示?

•玩家打开任务NPC时,#SAY里列出分类清单(见下)

4.任务窗口:分类显示

纯脚本的分类清单(NPC对话框,LEG/GOM通用):

[@任务列表]
#ACT
#SAY
\【成长任务】\\
<升级到35级:<$\QUEST(成长_升级35)>/35/@成长_升级>\\
<转生任务:<$\QUEST(成长_转生)>/1/@成长_转生>\\
\【副本任务】\\
<祖玛副本:<$\QUEST(副本_祖玛)>/10/@副本_祖玛>\\
<赤月副本:<$\QUEST(副本_赤月)>/5/@副本_赤月>\\
\【活动任务】\\
<攻城预热/@活动_攻城>\\
<返回/@main>


带客户端UI的分类(GEE/HERO):在插件里维护一个任务表,按类型分组渲染:
localQuestDB={
[1]={--成长
{name="升级到35级"cur=Human:GetVar("成长_升级35")max=35state=...}
{name="转生任务"cur=...max=1}
}
[2]={--副本
{name="祖玛副本"cur=...max=10}
}
[3]={--活动
{name="攻城预热"cur=...max=1}
}
}

客户端按1/2/3渲染成三个Tab,任务栏图标按state(可接/进行中/可交)决定闪不闪、什么颜色。

5.闪烁触发时机汇总

要让玩家“及时看到闪”,在这几个节点调用通知:
•接任务成功→闪(新任务)

•任务进度满(可交)→闪(提示交任务)

•交任务领奖→闪(切到下一个)

•活动开启/新日常刷新→闪(可接任务出现)

•副本通关结算→更新进度,满则闪

统一封装一个函数最省事:
functionUpdateQuest(HumanquestName)
localdef=QuestDef[questName]
localcur=Human:GetVar(questName)
ifcur>=def.maxandnotHuman:IsComplete(questName)then
Human:SetComplete(questNametrue)
NotifyQuestFlash(Humandef.type)--可交,闪
elseifnotHuman:IsAccept(questName)anddef.autoAcceptthen
Human:Accept(questName)
NotifyQuestFlash(Humandef.type)--新任务,闪
end
end


6.任务系统完整链路


服务端QuestDiary按成长/副本/活动分文件夹
→接任务:ACCEPTQUEST+SetInt(HUMAN(进度))
→进度更新:升级/杀怪/副本结算事件→SetInt+UpdateQuest
→满进度:COMPLETEQUEST+NotifyQuestFlash(类型)
→交任务:GiveItem+开下一环
→客户端收到0xAB→任务栏闪+切分类Tab
→玩家打开任务窗口→按1/2/3渲染列表


三、两个功能的联动

你这个场景里,两个需求其实是同一个活动系统的两头:

活动失败→全服清零→同时重置所有任务进度

[@活动失败处理]
#CALL[\系统\全服清零.txt]@开始清零
#CALL[\系统\任务重置.txt]@重置全部任务


任务重置脚本:

[@重置全部任务]
#IF
#ACT
SetInt($G(任务索引))=0

[@任务循环]
#IF
CheckInt($G(任务索引))<CheckInt($G(任务总数))
#ACT
GetOnlineHuman<$G(任务索引)>$H(当前玩家)
;清掉三类任务进度变量(按你实际任务名遍历)
ResetQuest<$H(当前玩家)>成长_升级35
ResetQuest<$H(当前玩家)>成长_转生
ResetQuest<$H(当前玩家)>副本_祖玛
ResetQuest<$H(当前玩家)>副本_赤月
ResetQuest<$H(当前玩家)>活动_攻城
;重新开放“成长任务·第一章”作为新一轮起点
ACCEPTQUEST<$H(当前玩家)>成长_第一章
NotifyQuestFlash<$H(当前玩家)>1
CalcInt($G(任务索引))+1
#GOTO[@任务循环]


这样一次活动失败:等级清零+装备回收+任务进度归零+任务栏自动闪(新的一轮成长任务可接),玩家不用下线不用返回角色,原地直接重新开始。

四、调试与排错清单

清零脚本常见翻车点:
•TakeOffToBag后装备消失→背包满,先清空格

•清零后玩家卡死/掉线→没清交易状态、没回血蓝

•跨线只清了一半→没做中心服广播

•英雄装备没脱→加TakeOffHeroAll

•技能没清导致等级1但技能满级→ClearSkill必须调用

•金币元宝一起清了→玩家无法买药,留基础路费

任务系统常见翻车点:
•图标不闪→客户端没注册0xAB封包/引擎自带任务开关没开

•分类错乱→任务名前缀不统一,脚本按前缀分组时匹配失败

•进度不更新→升级/杀怪事件里没调UpdateQuest

•重复领奖→没判ISACCEPT/COMPLETEQUEST,玩家点两次发两份

•任务栏显示旧数据→客户端没在Notify时刷新列表,要主动调RefreshTaskWindow

调试方法:
•先拿1个测试号跑通,再放开全服

•清零前SENDMSG打印“即将清零人数=$G(清零总数)”

•单角色处理完打印“已处理:H(当前玩家)等级LEVEL”

•任务系统先写1个成长任务跑通接受→进度→完成→闪烁→领奖,再复制到其他任务

•所有变量名建一张表统一管理,避免成长_升级35和成长_升35这种拼写差

五、命令对照速查(按引擎)

功能LEG/GOMHEROlua

取在线人数<$ONLINECOUNT>M2:GetOnlineCount()

取在线玩家GetOnlineHumanN$H(x)M2:GetOnlinePlayers()

设等级SetLevelHuman1Human:SetLevel(1)

清经验SetExpHuman0Human:SetExp(0)

卸装备到背包TakeOffToBagHuman位Human:TakeOffToBag(idx)

清技能ClearSkillHumanHuman:ClearSkill()

背包空格GetBagFreeHumanHuman:GetBagFree()

接任务ACCEPTQUEST任务名Human:Accept(name)

交任务COMPLETEQUEST任务名Human:Complete(name)

发公告SENDMSG0文本M2:SendMsg(0text)

引擎不同命令名一定对一遍文档,GameGold/AddGameGold/Human:AddGameGold这类在三个引擎里写法完全不同的命令,照抄必崩。

把“全服清零”理解成遍历+卸装+清属性三步,把“任务系统”理解成分类存储+进度回调+客户端闪烁四块,剩下的就是按你引擎的实际命令名填空。先单角色跑通清零,再接活动失败事件;先做一个成长任务跑通全流程,再加副本/活动分类——两部分都稳定后,用一次#CALL把清零和任务重置串起来,就是你要的“活动失败→全服原地清零+任务重新开始+任务栏闪烁提示”。
[顶部]