作者laechan (挥泪斩马云)
看板mud_sanc
标题Re: [wizs] 几个东西
时间Sat Feb 8 04:45:52 2025
再来讲任务的随机性部份,因为这篇可能有点长就跟前一篇切开。
(前一篇也可能还有啥要补充的)
任务受限於我在撰写时的架构,使得它之後要弄一些东西时变得碍
手碍脚(比方 nonseq 就是一例)。後面我也想了很多方法要来突破
这些架构上的障碍,最近才想到怎麽做。
首先是任务进行中的 input_to 做法,这个我在
/open/cmds/quest/l/l002 有实验过是可行的,然後链金术士转职
任务 l011 也有这样的应用:
write("请十秒内回答将空格应输入的符号列出:\n"+datas[0]);
input_to("cala_over",0,ppl,datas[1],0,str);
因为任务的随机性里头很常遇到「让玩家先做出某种选择,然後才
依玩家的选择产生不同的路线或结果」这样的情况,所以这部份先
提(包括范例在哪)。
那简单的说,假设我们希望任务第 n 步骤有随机性,这里提供一个
超级简单的做法,就是「自订第 n 步骤」即可,就是土法炼钢去模
拟第 n 步骤的进行。
以 quest 指令进行第 n 步骤的流程是
1. stepn_check
2. 通过 stepn_check 後的对话演示
3. stepn_end
玩家会获得完成第 n 步骤的任务标记
那所谓 土法炼钢去模拟第 n 步骤的进行 的意思就是
1. stepn_check
这里就直接呼叫所在房间的某函数
2. 让某函数利用 call_out 去跑任务对话
然後在某函数里面 wiz 就想做什麽变化都可以
3. stepn_end
玩家会获得完成第 n 步骤的任务标记
然後把 选择 跟 土法炼钢写函数 切开,弄成两个步骤,比方先在
前一步骤让玩家选择,然後才进行下一步骤跑自定函数,并在自定
函数中依玩家在前一步骤的选择,跑不同的流程或结果。
然後不管如何玩家都会获得完成任务第 n 步骤的标记,因此若想让
玩家在前一步骤依选择的不同,可能某些选择是无法完成该任务步
骤时,那就应该在前一个流程的选择那边,就直接挡掉。
比方玩家选 1 或选 2 是错的,那就要在选择後就直接挡掉,或是
亦可在选择後的次一步骤的 stepn_check 时挡掉。
(毕竟 stepn_check 函数也可以自订)
接着是模拟对话,语速通常两秒跑一次,因此先把一串对话打好
mixed chats=({
"对话1",
"对话2",
.
.
.
});
i=0;
foreach(tmp in chats)
call_out("show_talk",i++2,tmp);
void show_talk(string tmp)
{
write(tmp);
}
以上是最基本的土法炼钢对话模拟,那建议参考
/open/cmds/quest/quest_data/quest_data.c
的 heart_beat 函数中关於 msg_buf 的部份:
msgs=msg_buf[tmps[i]];
jj=sizeof(msgs);
for(ii=0;ii<jj;ii++)
{
if(msgs[ii][0] && msgs[ii][1] &&
environment(msgs[ii][0])==msgs[ii][1])
tell_object(msgs[ii][0],""+msgs[ii][2]+"\n");
也就是玩家若提早离开房间,是否仍持续显示,wiz 可自行
决定,预设的 msg_buf 是玩家若提早离开房间就不会再继续
看到对话。
然後随机性指的就是,比方第 n 步骤,透过土法链钢,就能
告知玩家,任务指定要的东西或是需达成的条件,拥有两种以
上可能的情况,这时玩家若不完整看完对话,就可能有不知道
到底要达成的是哪一种的情况,但没关系,可以在 n+1 步骤
的 check 告知
第 n+1 步骤: stepX_check,这里先判断第 n 步骤 npc 要玩
家满足的条件或是要取得的东西是什麽,然後就
在这里告诉玩家即可。
这样玩家就算跳过对话(第 n 步骤已完成),也可以透过 quest
指令得知刚刚那个步骤,它要满足的条件或取得的东西是什麽。
虽然麻烦了些,但土法链钢应用在这部份上面好处多多,可突
破 quest 既有架构的先天限制,并且可让 wiz 随心所欲。
我最近就会将这东西应用在 /open/cmds/quest/l/l013 绝顶改
装上头:
.
.
$N读完 Page.49 後,将书本阖上後放回原位。
$N: 以苹果做成的美味甜点吗......##
step6_npc=/u/l/laechan/special/mob/zero##
step6_msg=
$M: 你来啦? 吾辈一直在等你哪
$N: 是的,魔女大人,这就是以苹果做成的美味甜点。
$M: 喔喔,这...这是!! (≧▽≦)b
$M双眼发亮,很快地收下了你准备的苹果派
.
.
目前零固定要求玩家献上苹果派,但若自写函数来模拟第 5 步
骤,就可以要求玩家献上不同的东西,然後
step6_check()
{
先读取 step5 里头它随机要求的东西是什麽;
再判断玩家是否满足条件:
若不满足就告知玩家需满足什麽条件;
}
以零那格的写法因为零不是 NPC 因此自订函数我写在零上面,
或是零所在的那格都可以。
这东西因为与链金术士有关,若写好我也会回链金术士讨论串
那篇文,来说明绝顶改装任务改版後的流程说明。
到时就有范例,然後 wiz 也可以先自行实验,虽说目前仅止於
理论,但应该是可行的,就任务标记要自行追加,以及要用一
些栏位来纪录随机这部份,比方魔女要求苹果派时,如何让这
个要求被记住:
1. 建议仍是用 record_data
2. 或是 myhome 的 my_data
3. 或是撰写玩家可重新回到随机前状态或是重接任务的机制
说到这个,让玩家重接任务或是倒回第 n 步骤,建议可使用
void init()
的指令宣告方式,看要写在哪,提示玩家可透过去哪里下什麽
指令来重新接取这个任务、或是倒回第 n 步骤。若以这东西
的存在为前提时,则比方苹果派的任务就能设定在 temp_data
区,玩家知道三种要求的东西里面,苹果派最难,他希望能放
弃重选时,玩家只要去某地方下某指令即可。
(当然前提是玩家必须知道去哪里、下什麽指令)
Laechan
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.33.120.231 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/mud_sanc/M.1738961155.A.C61.html
补充,读取、设定任务标记的做法
quest query laechan l013
quest: ({ "l013", 5, 0, "2023/07/01", 1688199903 })
UNDEFINED
任务编号 l013
完成了第几步骤 5
该任务是否done 0 若是 1,该任务除非有 repeat 参数不然不能再接
任务更新标记 "2023/07/01"
任务完成时间 1688199903 这两个也可能颠倒,反正平常用不到
在 /open/cmds/quest/quest_data/quest_data.c 里头
主要看 quested 函数:
varargs mixed quested(string kind,string names,string quest_num,mixed vars)
{
switch(kind)
{
case "set":
// 采严格设定法,没有列入的参数均不准设
if((string)vars[0]=="times" && intp(vars[1]))
set_quest_data(names,quest_num,qq[1],vars[1],qq[3]);
else if((string)vars[0]=="steps" && intp(vars[1]))
set_quest_data(names,quest_num,vars[1],qq[2],qq[3]);
else
return -1;
case "check":
// 第一种 check: 确认 names 有没有解过 quest_num, 以及有没有满足解到几次
if((string)vars[0]=="times")
// 第二种 check: 确认 names 是否已经解 quest_num 解到第 n 步骤
// vars 没给第二参数时就预设判断有没有解第一步骤
if((string)vars[0]=="steps")
该 quested 可用 questing 全域函数来呼叫,後面接的参数都一样,
所以以 set 为例,语法是
questing("set","玩家id","任务编号",
({"times",1 })); // 设定任务解了几次
({"steps",5 })); // 设定任务已解了第几步骤
以 check 为例,语法市
questing("check","玩家id","任务编号",
({"times",1 })); // 该任务已解次数是否为 1
({"steps",5 })); // 该任务是否已解到第 5 步骤
check 可不需要第 2 参数,比方
questing("check","玩家id","任务编号",({"times"})); // 判断有无解过
questing("check","玩家id","任务编号",({"steps"})); // 判断有无完成第1步骤
以上供参,也是备忘,因为我自己很容易忘记这些东西^^;
※ 编辑: laechan (114.33.120.231 台湾), 02/08/2025 10:08:16
我刚刚看 quested 函数,里面有关於 msg_buf 的部份
case "msg_buf":
switch(names)
{
case "add":
if(ob=find_player(quest_num))
{
if(tmp_ob=environment(ob))
{
if(stringp(vars))
add_msg_buf(ob,tmp_ob,({vars}));
else if(arrayp(vars))
add_msg_buf(ob,tmp_ob,vars);
}
}
break;
}
break;
我原本以为这是 query msg_buf,但反正它只有 "add",或许我之後
会新增 query 的部份,理论上是
questing("msg_buf","query","任务编号",({可能第几步骤}));
说到这个我想起我好像有写任务对话总览的指令
quest check_msg 脚本编号 msg 确认
j=quest_ob->query_quest_steps();
for(i=1;i<=j;i++)
{
if(steps>0 && steps!=i) continue;
if(tmps=quest_ob->query_quest_msg(i))
看起来就是若已读取了 quest_ob 物件就直接取得 steps 及 msg,
反之,若不想读 quest_ob 就以 questing 呼叫,而写在questing
内的判断就必须包含 steps 的可用范围判断。
※ 编辑: laechan (114.33.120.231 台湾), 02/08/2025 12:06:28
1F:→ laechan : 大概是这样,连同上一篇,我都列入2025的发展重点 02/08 12:06
2F:→ laechan : 然後还有个东西,任务串OX,但这个我想等实作出来再写 02/08 12:07
3F:→ laechan : 我後来想了一下说它是任务也不太对,它只是借用任务 02/08 12:08
4F:→ laechan : 的壳,至於怎麽借壳我还在研究 02/08 12:08