作者laechan (小太保)
看板mud_sanc
标题[闲聊] 任务「脚本」的设计原则
时间Tue Dec 18 09:48:17 2012
基本上,我本身比较不乐见看到「脚本」里面有自订函数的
程式段,因为这并不符合「脚本」的意义。
既然是「脚本」:
1.其构成必然简单,不复杂
2.不应存在程式段落
换言之,现行的脚本,其实是「脚本」+「自订函数」的综
合体,简单的任务就只有脚本,复杂一点的任务则再搭配自
订函数这样。
这是必须接受的事实。
然後一般任务进行时必然具备四个条件:
1.quest 的对象 stepX_npc
2.quest 前判断 stepX_check
3.quest 中讯息 stepX_msg
4.quest 後结果 stepX_end
然後还需要知道一个函数:questing
所以 justin 你应根据上面,先判断:
1.这四个条件以及该函数是否为基本足够?
2.为何你的任务,无法使用现行的 quest 来做?
比方说,你希望玩家在任务步骤 2 跟 3 可以随意决定顺序
、并只需完成它们其中一个即可:
问题:nonseq 需不需要写?
解答:需要。所以你建议了,我才会写。因为根据内定流程
,你要接任务 3 就必须先接任务 2。
它是比 stepX_check 更优先的内定判断。
将它作为内定判断是因为大部份的任务都是如此。
问题:anyone 需不需要写?
解答:不一定需要。因为它可以先用 nonseq 及 stepX_end
去模拟「你只要接了它们其中一个就代表接完全部」
那我为什麽写?因为我评估无风险。
然後,「自定函数」其实是很简单的东西,我们随便 more
一个有自定函数的任务档
:::::::::::::: /open/cmds/quest/l/l002.c ::::::::::::::
inherit "/open/cmds/quest/quest_d.c";
int step5_end(object ppl,object npc,string key);
int step4_check(object ppl,object npc,string key);
.
.
你需要了解的就是,stepX_check 函数就是「任务步骤结
束前的插断判断」,stepX_end 函数就是「任务步骤结束
後的附加执行」。结束前跟结束後的差异,就在於 steps
参数是否已经变更(玩家身上的),有变更就代表玩家已结
束该任务。
other=
int step1_check(object ppl,object npc,string key)
{
if(ppl->query("level")<120)
{
write("你的等级要满 120 级才能接这个任务喔。\n");
return 1;
}
return 0; // 代表可接
}
int step1_end(object ppl,object npc,string key)
{
// 设定玩家接该任务的时间
ppl->set_temp("time_record/l002_times",time());
return 1;
}
##
比方你要设定任务步骤第 4-7 的各个接取条件,我认为,
用 stepX_check 及 stepX_end 及一些附加判断即可具现
最後我要讲的东西就是,比方某一个 stepX_check..
int stepX_check(object ppl,object npc,string key)
{
if(ppl->query("race")=="human" ||
((ppl->query("race")=="elf" && ppl->query("pri_guild")=="mage")) ||
(ppl->query("race")=="devil" && ppl->query("pri_guild")=="fister"))))
{
write("你的 bla bla ... 必须满足条件喔,抱歉,我必须将你踢出。\n");
ppl->move_player("/d/wiz/room/disc","SNEAK");
return 1;
}
return 0; // 代表可接
}
为什麽我不将上面的东西用「脚本式设定」来处理?
因为没效率。假设真的存在一种设定可以满足上面,那麽
可以预知两个结果:
一、脚本的该部份段落「会很像程式」,例如..
stepX_check=
race=human or bla bla bla##
那脚本化有何意义?
二、程式为了配合这样的东西,「必须把所有的可能都纳
入」,结果却只是给极少数的任务设定极少样性的条
件使用,何必呢?
我的意思就是,在「脚本」跟「程式」之间,我们实际上
需要取得的是一个有效率的平衡点。我并不反对将 quest
改的更理想,只是我要先让你知道我在想什麽,这样我们
改良的方向才会正确,这其中亦包含了 debug 的部份。
Laechan
--
※ 发信站: 批踢踢实业坊(ptt.cc)
※ 编辑: laechan 来自: 210.61.157.53 (12/18 10:09)
1F:推 justinj :那我再提几个好了...一个是刚刚发现的..另一个还没找 12/18 10:38
2F:→ justinj :到方法... 12/18 10:38
3F:→ justinj :1.我原本设定 macro #define AA MM"CCC"後,然後在 12/18 10:40
4F:→ justinj :step_npc时用=$AA$TTTT##的写法好像没法子用marco.. 12/18 10:42
你可以把 quest read xxxx 後的 xxxx.c 档内容前半贴
出来。规则是「跟 xxx.h 的定义法一样」。
5F:→ justinj :2.我比较喜欢任务里有失败的条件,所以我会将最後一步 12/18 10:43
6F:→ justinj :设定成fail...然後可能会这样走1->2->4->7(fail) 12/18 10:44
7F:→ justinj :或者是1->2->5->6(成功)...这样..也许里面有写..所以 12/18 10:45
8F:→ justinj :我还要再找找有没有这种用法..) 12/18 10:46
就我说的:用自定函数的做法。
我上面提过,如果玩家走 1,2,4,7,那你就在 stepX_end
(X=1,2,4,7) 都自订,例如..
step1_end=
ppl->set_temp("time_record/xxxx_1",1)##
step2_end=
ppl->set_temp("time_record/xxxx_2",1)##
step4_end=
ppl->set_temp("time_record/xxxx_4",1)##
other=
int step7_end(object ppl,object npc,string key)
{
if(ppl->query_temp("time_record/xxxx_1") &&
ppl->query_temp("time_record/xxxx_2") &&
ppl->query_temp("time_record/xxxx_4"))
{
write("任务失败。\n");
// 将任务移除要玩家重接
// 使其造成的结果相当於 quest del justin xxxx
questing("相关功能",bla bla...);
// 若该功能没有就自己写,或提出需求由我来改 quest_data_d.c
return 1;
}
return 1;
}##
※ 编辑: laechan 来自: 210.61.157.53 (12/18 10:56)
9F:推 justinj :果然看内容可以找到用法..step1_npc="+ROOT"child## 12/18 13:13
10F:→ justinj :用这样写就可以设定代码了..(虽然看起来怪怪的...) 12/18 13:14
喔,这样实在没必要,不过也是可以...
这是因为 str = "路径+档名", 它是没有 " " 的, 这时候
ROOT 就变成字串而不是代号。
如果你那时就举这个例子,我就知道你的意思,我就可以配
合修改。
不过话说回来,它也不是那麽好改的,这时就变成,我会建
议你,在你移目录时,脚本档目录的部份就跟着改掉,或者
就像你上面那样的变通做法亦可。
还有,脚本档的读入你可以想成有做底下这行..
sscanf(str,"%s=%s##",s1,s2);
这是非常直觉的。然後它最终的结果则是
quest_data["s1"] = "s2";
从这里就可推测若 s2 = "ROOT"child##, 上面就会变成
quest_data["s1"] = ""ROOT"child";
这个在以前用 change 去写房间档时也用过, 如..
short: "HIG"大草原"NOR"##
也就是说,你可以把 "ROOT" 当成 #define 变数的引用语
法,我希望大家也都可以这样子想。
11F:→ laechan :你可以试试 "ROOT"child## 看是不是也可以 12/18 13:38
※ 编辑: laechan 来自: 210.61.157.53 (12/18 13:39)
12F:推 justinj :问一下哦...要怎麽跳步骤...不会跳..唉 12/18 16:33
14F:推 justinj :测试的结果...anyone是只能执行任何一个... 12/19 09:59
15F:→ justinj :我是想要这样..2->3->4或3->2->4或2->4,3->4... 12/19 10:00