作者laechan (挥泪斩马云)
看板mud_sanc
标题Fw: [闲聊] 套装(suit)的简易做法
时间Thu Oct 13 22:44:05 2022
※ [本文转录自 mud 看板 #1ZI2Gi20 ]
作者: laechan (挥泪斩马云) 看板: mud
标题: [闲聊] 套装(suit)的简易做法
时间: Thu Oct 13 22:43:52 2022
这里以 sanc 为例,sanc 穿脱的指令是
/cmds/std/_wear.c
/cmds/std/_remove.c
问题:如何不更动防具/武器继承档、不更动欲设定为套装的
防具/武器档案的情况下,实装套装设定?
解答:更改 wear/remove 指令
撰写独立的 /std/suit.c 套装判断档(假设 define 为 SUIT)
在 suit.c 里面可以宣告如下变数
mapping suit_data=([
"套装名":([
"suits":(["装备位置1":"武防档名1",
"装备位置2":"武防档名2",
.
. ]),
"effect":(["属性/效果1":属性/效果值1,
"属性/效果2":属性/效果值2,
.
. ]),
]),
.
.
]);
mixed suit_files;
然後宣告几个处理用的函数
void create()
{
string t1,t2;
// 在该物件载入时,让它读取 suit_data 来产生出 suit_files 资料
suit_files=({});
foreach(t1 in keys(suit_data))
foreach(t2 in suit_data[t1]["suits"])
suit_files[t2] ? suit_files[t2]+=({t1}) : suit_files[t2]=({t1});
}
// 判断 ob 是不是套装
int is_suit(object ob)
{
if(!ob) return 0;
if(undefinedp(suit_files[base_name(ob)])) return 0;
return 1;
}
那麽在 wear 时,针对正在处理的某物件,做如下判断:
// 若该物件 ob 是套装物件, 就执行 check_suit
if(SUIT->is_suit(ob)>0)
SUIT->wear_suit(me,ob);
int wear_suit(object user,object ob)
{
string files,t1,t2,tt;
mixed tmps=({});
object tmp;
int n;
if(!user || !ob) return 1;
files=base_name(ob);
tmps=all_inventory(user);
foreach(t1 in suit_files[files])
{
n=0;
foreach(tmp in tmps)
{
if(!tmp->query("wear")) continue;
tt=base_name(tmp);
if(member_array(tt,suit_data[t1]["suits"])!=-1)
n++;
}
// 当 已装备数量 = 该套装实际数量 时
// 才执行 add_suit_effect
if(n==sizeof(suit_data[t1]["suits"]))
add_suit_effect(user,suit_data[t1]["effect"]);
}
return 1;
}
上面的意思是说,比方 wear all,然後它看到了正在装备的是
套装物件时,它会去算你目前已经装备了某套装的几件装备了,
唯有当 已装备数量 = 该套装实际数量 时,才执行下面函数:
int add_suit_effect(object user,mapping effect)
{
string eff
// 这里假设所有的效果全部使用 add 的方式增加
// 比方 加 stat-str 50
// = user->add("effect/stat-str",50);
foreach(eff in keys(effect))
user->add("effect/"+eff,effect[eff]);
return 1;
}
remove 同理,同样先做 is_suit 判断,若该物件是套装,就呼
叫 remove_suit 函数:
int remove_suit(object user,object ob)
{
string files,t1,t2,tt;
mixed tmps=({});
object tmp;
int n;
if(!user || !ob) return 1;
files=base_name(ob);
tmps=all_inventory(user);
foreach(t1 in suit_files[files])
{
n=0;
foreach(tmp in tmps)
{
if(!tmp->query("wear")) continue;
tt=base_name(tmp);
if(member_array(tt,suit_data[t1]["suits"])!=-1)
n++;
}
// 当 该套装实际数量 - 已装备数量 = 1 时
// 才执行 remove_suit_effect
if(sizeof(suit_data[t1]["suits"]) - n == 1)
remove_suit_effect(user,suit_data[t1]["effect"]);
}
return 1;
}
int remove_suit_effect(object user,mapping effect)
{
string eff
foreach(eff in keys(effect))
{
user->add("effect/"+eff,-effect[eff]);
if((int)user->query("effect/"+eff)==0)
user->delete("effect/"+eff);
}
return 1;
}
以上只是简单写一下,实际上依各 mud 的不同,写法上会有所
差异,但概念是相通的。这样做的好处有以下几个:
1. 不管是用宣告 mapping suit_data 或是 save/restore 的方
式去储存套装资料,这些套装的设定都会集中在同一个地方,
就方便做套装资料的增删改,可以统一管理这些资料。
2. 撰写适当的指令给玩家,玩家就能自行浏览整个 mud 总共有
多少套装,以及全部装备上之後,会有什麽效果。
3. 不需要去动现有的武器/防具档,也不需要动它们的样本档,
只需要动 穿脱武防具 的指令。
4. 让 if(SUIT->is_suit(ob)>0) 的判断先行,它是最简判断,
通过了,才执行复杂处理函数 wear_suit/remove_suit。
依现在电脑的处理效能及多工性,这些都是小 case。
5. 这写法最大的好处,就是 一件武防 可同时是 A 套装与 B 套
装的内含武防。这个在 RO 很常见,即 A套装 与 B套装 都同
时包含了该武防。针对这一点,上面那些函数的判断一样有效
它唯一的缺点就是会增加 wear 与 remove 的处理复杂度,以及
SUIT 物件不能坏,我平常是不建议用 catch 去包相关的呼叫段
落,不过这也是可以考虑的--反正电脑效能很好。
另外,上面全都是纸上谈兵,我还没有在 sanc 实装过这个,即使
sanc 已经有套装,我们是传统做法,写 /std/suit.c 样本,再让
欲当做套装的武防档去 inherit 这个样本。
我现在觉得这样太..不方便了,我希望套装的设定都能集中在同一
个地方。我最近有空应该会实装新的做法。
Laechan
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 59.126.145.135 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/mud/M.1665672236.A.080.html
※ 发信站: 批踢踢实业坊(ptt.cc)
※ 转录者: laechan (59.126.145.135 台湾), 10/13/2022 22:44:05