作者laechan (小太保)
看板mud_sanc
标题[wizs] 成就系统
时间Tue Oct 27 09:59:30 2015
我目前有想到这东西的可行的一种解法,就是用 questing 来做,
也就是说,假设 sanc 有 n 种成就,在假设 n<1000 的情况下,
就可以用 a001~a999 来代表这 999 种成就。
> quest set laechan a001
laechan 的 a001 任务资料目前状态:
资料区:({ "a001", 0, 0, "", 0 })
暂存区:UNDEFINED
=================================================
1 to n 变更已解步骤(目前步骤值为 0).
2 to n 变更已解次数(目前次数值为 0).
3 to date 变更已解标记(目前标记值为 ).
4 to quit 离开本设定选单.
=================================================
请输入指令: 2 to 1
quest set 2: 你将 laechan 任务资料的已解次数值设为 1 了。
laechan 的 a001 任务资料目前状态:
资料区:({ "a001", 0, 1, "", 1445906263 })
暂存区:UNDEFINED
=================================================
1 to n 变更已解步骤(目前步骤值为 0).
2 to n 变更已解次数(目前次数值为 1).
3 to date 变更已解标记(目前标记值为 ).
4 to quit 离开本设定选单.
=================================================
请输入指令: 4
quest: 感谢你的使用.
执行 running code:
write(questing("check","laechan","a001",({"times",1}))+"\n");
========== 程式执行区 ==========
1
========== 程式执行区 ==========
也就是说,假设把 "a" 标记设定为成就系统专用,一开始我们可以
先划出 a001~a900(真的有 a 开头 wiz 要写任务,就从 a901 开
始写)。
接下来,任务标记有几个栏位可使用
> quest query laechan a001
quest: ({ "a001", 0, 1, "", 1445906481 })
^^^^^^^ ^^^^^^ ^^^^^^^^^^
成就编号 达成次数 达成第n次时的时间
从上面可看出「steps」栏位就是可以利用的地方,例如说假设我设
定一个任务叫做「徒步前往泰帕依城」,并假设它的必要条件是必须
依序通过房间 A、B、C、D...
那麽在第 n 个必须依序通过的房间就可以做如下判断
void init()
{
object ppl=this_player();
string names;
::init();
if(!userp(ppl)) return ;
names=ppl->query("name");
if(questing("check",names,"a001",({"steps",n-1}))!=1)
// 或使用 if(questing("check",names,"a001",({"steps"}))!=n-1)
return ;
// 设定玩家完成该成就的第 n 步骤
questing("set",names,"a001",({"steps",n}));
// 然後假设玩家此时已达成最後一个步骤
if(questing("check",names,"a001",({"times"}))==1) return ;
questing("set",names,"a001",({"times",1}));
shout("【成就系统】恭喜 "+names+" 获得 "+
achieve_name("a001")+" 成就!\n");
}
从以上可看出,关键在於 achieve_name 或类似的函数要怎麽写,
quest list 会读已注册的任务,所以可以想成 aXXX 是「虚拟任
务=成就」,它只会存在标记,因此必定要有个成就资料库可以
读取它的资料。
那怎麽做比较好呢?个人思考的方式是
一、建立 achieve 指令,如同 quest,既是给玩家查看自己已达
成哪些成就之用,也给 wiz 用以做设定之用。
二、利用 chinese 指令,目前 chinese.o 档才 13K 大小,可以
新增底下语法
chinese a001=achieve=徒步前往泰帕依城
这样在 chinesed.c 及 chinese.c 就可新增 achieve_name
全域函数。
三、在上面 quest achieve 里头还有一个 date 参数未使用,这
个参数就可以用来做成就上的分类,例如「徒步前往....」
就使用 "xxx" 这个分类,...
这样在做 achieve list 时,就可以依分类(而不是依任务编
号)来做格式化的已达成成就列表
因此剩下三种未解决项目
一、要先订出「哪些分类」,以及它们的分类名称
例如「玩家达成了几个技能练到 9900 的成就」(技能类),
「玩家第一次打到未监定防具」(打宝类),「玩家第一次使用
监定指令」(初体验类),....
但是在监定方面又可细分为「玩家第一次监定出完整防具」,
「玩家第一次监定出无瑕防具」,「玩家第一次监定出完整无
瑕防具」,....
在 achieve list 时,如何让它做底下的显示顺序
玩家第一次使用监定指令
玩家第一次监定出完整防具
玩家第一次监定出无瑕防具
玩家第一次监定出完整无瑕防具
.
.
也就是说,如何让该成就是可具备事後给予顺序性的,有一种
做法,例如初体验的成就编号是 "first",然後假设「玩家第
一次使用监定指令」这个成就是 first_01,之後我们又将该
成就做了细分时,细分的成就编号就类似
first_01_01、first_01_02、....
也就是说,我们必须储存 a001 这个成就的 name 之外,还要
储存它的成就编号,甚至可能还要储存其它的资讯,例如达成
成就可获得哪些报酬等。
(那就不能单纯以 chinese 来做为储存资料用)
二、要如何判断玩家达成某项成就?
例如技能类,玩家达成第一个技能 9900、第二个技能 9900、
....,这些要怎麽判断?例如说 sanc 目前已经有针对玩家达
成某技能 9900 时的 shout,所以可以写在该 shout 所在的
程式段里面。
但问题是,在我们设定该成就之前,就已经有玩家拥有 n 个
9900 技能了(甚至所有可以 9900 的技能都已经满了),这就
会造成这类的玩家无法取得这样的成就。
因此像这类的成就要写在什麽地方做判断,就是一个问题。
三、达成成就获得的报酬?
这个才是成就系统的核心。比方我设定「徒步走到泰帕依城」
这个成就,那可能我给定的报酬是「获得一件已监定的泰帕依
城 necklace 类防具」..
1.该项报酬怎麽放在资料库中做描述?
2.该项报酬的给予有可能制式化吗? 例如
reward: ({"give_obj","/std/new_ob/necklace","tapay",...
光是这样写就可能会有问题。
通常报酬有几种可以给,但是它们跟任务报酬是高度重叠的,
也就是说我们必须要思考的是,「获得成就的报酬」至少要与
「达成任务的报酬」是分开的,凡是可做为达成任务的报酬,
就应该给任务;一旦决定某一类报酬给成就系统,就不应把这
项报酬给任务系统。
目前确定「获得某一种 buff 类」的报酬是可以给成就系统的
,另外,像上面的「获得该区域相关的未监定防具」也可以。
然後有一种例外就是「小额报酬」或「与利益无关的报酬」,
这也是可以给成就系统的,像 D3 获得独特的旗帜就是一种与
利益无关的报酬,而像是获得经验值这类的也可以算是,虽然
某些任务解完了也能获得经验值,但是经验值改%之後,获得
经验值的报酬相对就是属於比较小额的报酬。
但无论如何,还是必须思考独特的报酬。
LAechan
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 210.61.157.53
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/mud_sanc/M.1445911174.A.7C4.html
1F:→ laechan : 我最近会先从新手可达成的成就开始规划起 10/27 10:02
※ 编辑: laechan (210.61.157.53), 10/27/2015 10:02:47
2F:推 justinj : 可以学pso2,去[成就区]就会设定那些已完成的 10/27 17:13
有些我是判断在完成的当下就广播出来,会比较有成就感。
倒是「成就区」可当成一种补遗的做法。
(我原先还有考虑在玩家 login 时、或是在 a_heal_up 每 30 秒判断区、
甚至交给 times_check 来做)
※ 编辑: laechan (122.117.106.224), 10/27/2015 18:32:37
3F:→ hlead : 我觉得可以,达到9900就去重新全部计算一次。 10/27 19:53
4F:→ hlead : 成就区好像也不错,靠玩家自己去更新就好。 10/27 19:53
我今晚试着想看看有没有什麽比较可行的实作方式。
现在的 mudos 新增 simul_efun 很麻烦,所以 achieve_name
这种全域函数基本上不可行。
但是 chinese.c 里面有一个 title_name 的全域函数,倒是
可以拿来用:
//laechan@sanc abort follows 2011/10/11 减少使用 simul_efun
string title_name(string str)
{
return "";
return CHINESE_D->title_name(str);
}
也就是说该函数目前实际上是没在使用的,就可以当 achieve
的专属函数使用。
在 chinesed.c 里面 title 被宣告为 mapping:
> call chinesed;dump_title
房间(/adm/daemons/chinesed)-> dump_title() = UNDEFINED
剩下的,就是如何做列表。其实我也有想过自订列表顺序这样
的做法,但它的问题是一旦成就多达几百个时,要排序就会变
得困难,因此前提还是「必须先分类」,这样成就至少可以依
类别列表(类似天空城农场 list -xxx 的分类列表),每一类别
要各自定义排序就会变得简单。
这个东西很重要是因为,这样就不需从最初的成就(新手成就)
开始写,比方我们都准备好了之後,我就可以把「徒步走到泰
帕依城」设为 a001,而当往後随着该类别成就的新增时,我可
以透过自定义顺序的方式,让玩家在 list 时所看到的是照我
定义的顺序。
我想应该不困难啦,最後就是实装前大家讨论一下成就报酬,
通常我有设未监定防具的区域,「徒步走到..」的成就多半都
是给一件该区域所属的未监定防具。
接着就是像这样:
第[120]级 男性龙人勇者--抠顶机器(Laechan:进阶牧师)
你目前是单身,技能总数:154,
成就总数:197,国王效忠值:0。
[男性龙人勇者]抠顶机器(Laechan:进阶牧师),等级 120 级,6624 岁。
道德:509 点,战功声望:468126 点,挪布币:521,总财产:103126696 影特币。
技能数:154,
成就总数:197,他已经玩了:1年 42周 3天 20 小时 33分 36秒。
这样就差不多了。
关於成就的报酬部份,我以前也有写过一个东西:
// who -l
if(!undefinedp(obj->query("record_data/titles")))
titles=(mixed)obj->query("
record_data/titles");
这个 "title" 可以跟 achieve 的 title 混用,比方玩家达成了
所有 skill 类的相关成就时,想要给他一个「圣殿技能大师」的
title 时:
chinese skillmaster=achieve=圣殿技能大师
这样存在 record_data/titles 的东西就是 "skillmaster" 而不
是 "圣殿技能大师"。
这东西的用意是「玩家在某一类成就上面达到一定的成就,就给予
称号」,这东西会显示在 who -l 上面。达到的成就规模越丰富,
title 就越多,例如底下就成为可能:
> who -l
(第120级男性龙人勇者) 「圣殿技能大师 <= 练出 10 个 9900 技能
防具监定专家 <= 监定出完整无瑕防具
屠龙勇者 <= 杀过圣殿所有的龙类怪物
我终於摆脱单身了 <= 已婚成就
11月要考试了」抠顶机器(Laechan) <= 自订 title
以上是概要。
(不过我是认为给制式的 title 不太好,让玩家能自订较 ok)
※ 编辑: laechan (1.165.178.185), 10/27/2015 22:03:33
5F:推 justinj : 没法子重现的才需要补..例如:技能9900的数量.. 10/28 09:02
6F:→ justinj : [监定出完整]那个就新开始就好了..... 10/28 09:03
7F:→ laechan : 对啊有些可当下,有些事後补,但要注意过度分散的问题 10/28 12:19