本帖最后由 2bman 于 2021-11-22 04:26 编辑
依照之前承诺(物品“道具功能”、“特殊功能”全解析),这次来介绍如何使用Lua来扩展物品的自定义功能。
在魔力的道具中有“再生剧药”可以重置人物加点,然而却没有宠物版的再生剧药,如果宠物加错点就只能用重来的种子慢慢调整。
那有没有办法制作出一个宠物版的再生剧药呢?
这次我就利用Lua脚本来制作一个宠物版的再生剧药、以及重生和洗档剧药。
此文的示例及代码参考自cgmsv自带的 lua\Module\nofix\RebirthPet.lua 脚本,我做了一些修改与优化,如果懒得看示例可以下载完整版的附件。
首先,我们需要先注册道具的处理函数:
- Delegate.RegInit("PetRebirth_Init")
-
- function PetRebirth_Init()
- --注册宠物再生剧药处理函数
- NL.RegItemString(nil,"usePetRebirth","LUA_usePetRebirth")
- --创建NPC,用于提供对话框
- createPetRebirthNPC1()
- createPetRebirthNPC2()
- createPetRebirthNPC3()
- end
复制代码
我们注册一个名为 LUA_usePetRebirth 的处理函数,并使用 usePetRebirth 这个方法来处理,而在道具功能中即可使用此函数来激活我们自定义脚本功能。
在注册完函数后,我们创建了三个NPC,用于给我们的脚本提供对话框与交互处理。
NPC创建函数示例:
- function PetRebirth_initialize()
- return true
- end
复制代码
- function createPetRebirthNPC1()
- if (PetRebirthNPC1 == nil) then
- PetRebirthNPC1 = NL.CreateNpc(nil, "PetRebirth_initialize")
- Char.SetData(PetRebirthNPC1, %对象_形象%, 106089) --%对象_形象%
- Char.SetData(PetRebirthNPC1, %对象_原形%, 106089) --%对象_原形%
- Char.SetData(PetRebirthNPC1, %对象_地图%, 777) --%对象_地图%
- Char.SetData(PetRebirthNPC1, %对象_X%, 30) --%对象_X%
- Char.SetData(PetRebirthNPC1, %对象_Y%, 30) --%对象_Y%
- Char.SetData(PetRebirthNPC1, %对象_方向%, %右下%) --%对象_方向%, %右下%
- Char.SetData(PetRebirthNPC1, %对象_原名%, "宠物再生大师") --%对象_原名%
- NLG.UpChar(PetRebirthNPC1)
- if (Char.SetTalkedEvent(nil, "PetRebirth1_Talked", PetRebirthNPC1) < 0) then
- print("PetRebirth1_Talked 注册事件失败。")
- return false
- end
- if (Char.SetWindowTalkedEvent(nil, "PetRebirth1_WindowTalked", PetRebirthNPC1) < 0) then
- print("PetRebirth1_WindowTalked 注册事件失败。")
- return false
- end
- end
- return true
- end
复制代码
PetRebirth_initialize 是 NL.CreateNpc 的回调函数,必须返回 true。
其他的设置可随意,最好将此NPC放到一个普通玩家无法访问的地图中去,因为我们只会在脚本中调用此NPC的功能。
之后我们为NPC注册 SetTalkedEvent 与 SetWindowTalkedEvent 事件,这两个事件是我们与NPC的对话与回调事件。
宠物再生剧药NPC的对话完整示例:
- function PetRebirth1_Talked(npc,player)
- NLG.ShowWindowTalked(player,npc,0,12,0,"\n你想重新分配宠物点数吗?")
- return
- end
复制代码
- function PetRebirth1_WindowTalked(npc,player,_seqno,_select,_data)
- if (_select==8) then
- --NLG.ShowWindowTalked(player,npc,0,1,11,"已取消操作。")
- return
- end
- local tab={}
- if (_seqno==0) then
- for t = 1,5 do
- local PetIndex = Char.GetPet(player,t-1)
- if (PetIndex>0) then
- tab[t] = "Lv."..Char.GetData(PetIndex, %对象_等级%).." "..Char.GetData(PetIndex, %对象_原名%)
- else
- tab[t] = "无宠物"
- end
- end
- NLG.ShowWindowTalked(player,npc,2,2,1,
- "2\n请选择宠物:\n"..
- "\n "..tab[1]..
- "\n "..tab[2]..
- "\n "..tab[3]..
- "\n "..tab[4]..
- "\n "..tab[5]
- )
- end
-
- if (_seqno==1) then
- local petinx=Char.GetPet(player,tonumber(_data)-1)
- if (petinx<0) then
- --NLG.ShowWindowTalked(player,npc,0,1,11,"无效的宠物索引")
- return
- elseif (Char.GetData(petinx,%对象_等级%)==1) then
- NLG.ShowWindowTalked(player,npc,0,1,11,"1级宠物没必要还原!")
- elseif (Char.HaveItem(player,PetRebirthID1) < 0) then
- NLG.ShowWindowTalked(player,npc,0,1,11,"抱歉,你没有宠物再生剧药!")
- elseif (petinx>=0 and Char.GetData(petinx,%对象_等级%)>1) then
- Char.DelItem(player,PetRebirthID1,1)
- repetlevel(player, petinx)
- NLG.SystemMessage(player,"你的宠物 "..Char.GetData(petinx,%对象_名字%).." 点数已重置!")
- end
- end
- end
复制代码
- function repetlevel(pid, petid)
- local petlvl = Char.GetData(petid,%对象_等级%)
- local exps = 0
- exps = Char.GetData(petid,%对象_经验%) --宠物的额外经验
- for i = petlvl,2,-1 do
- exps = exps + Char.GetLevelExp(i)
- end
-
- Pet.ReBirth(pid, petid)
- Char.SetData(petid,%对象_经验%,exps)
- Pet.UpPet(pid, petid)
- end
复制代码
PetRebirth1_Talked 是我们与NPC首次对话时显示的窗体,我们不需要过多关心它,只需要为它设置好窗体样式即可,主要的回调参数都在 PetRebirth1_WindowTalked 之中。
PetRebirth1_WindowTalked 的参数 _select 是玩家所选择的按钮,如果为8表示点了否,则不对接下来的代码做处理。
_seqno 是玩家选择按钮的序号,玩家点选了列出的宠物之后,就会返回一个大于0的 _seqno 给函数。
最后我们从玩家的宠物序列中找到目标宠物,对目标宠物进行“重生”。
但在这里有一个问题:如果我们直接让宠物重生,再设置宠物的等级,此宠物并不会进行成长,同时也不会得到升级的BP。
为此,我们需要为宠物设置足够等级的经验值,才能让宠物得到BP点。
然而又出现了一个新问题,如何才能获取到指定等级的经验值数量呢?
我通过研究发现,魔力的宠物在升级后,会重置当前等级与升级所需要的经验值,也就是经验值不会随着等级而累加。
脚本内置方法中的 Char.GetLevelExp 虽然可以获得升级所需要的经验,但是这个经验是指“等级-1”升级到“等级”所需要的经验值。
为此,我专门写了一个 repetlevel 方法来解决升级到指定等级需要累加经验的过程。
设置完经验后,我们再将宠物的封包发送给玩家,这样玩家就可以重新给宠物加点,同时也不会改变宠物的等级与档次。
宠物重生剧药、宠物洗档剧药也是类似的原理,只需要根据需求改写 PetRebirth_WindowTalked 的回调事件即可。
最后,就是 usePetRebirth 的处理函数激活示例了:
- function usePetRebirth(player,target,slot)
- -- 根据物品ID调用NPC对话
- local iteminx = Char.GetItemIndex(player,slot)
- local itemid = Item.GetData(iteminx,%道具_ID%)
- if itemid == 80000 then
- PetRebirth1_Talked(PetRebirthNPC1,player)
- elseif itemid == 80001 then
- PetRebirth2_Talked(PetRebirthNPC2,player)
- elseif itemid == 80002 then
- PetRebirth3_Talked(PetRebirthNPC3,player)
- else
- NLG.SystemMessage(player,"无法识别道具")
- end
- end
复制代码
当用户双击了使用 LUA_usePetRebirth 作为功能的道具时,就会激活 usePetRebirth 这个函数。
我将宠物再生剧药设为80000、重生剧药设为80001、洗档剧药设为80002,函数会根据道具的ID打开不同的NPC对话框,然后再根据回调事件执行不同的命令。
如有建议或疑问请留言。
补充内容 (2021-11-28 01:40):
_seqno 的描述是错误的,其值来自于对话框设定的数值,这个数值可以由脚本自己决定,也是唯一可以给回调函数传递参数的方法。 |