这里以 sanc 为例,sanc 穿脱的指令是
/cmds/std/_wear.c
/cmds/std/_remove.c
问题:如何不更动防具/武器继承档、不更动欲设定为套装的
防具/武器档案的情况下,实装套装设定?
解答:更改 wear/remove 指令
撰写独立的 /std/suit.c 套装判断档(假设 define 为 SUIT)
在 suit.c 里面可以宣告如下变量
mapping suit_data=([
"套装名":([
"suits":({"武防档名1","武防档名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 是套装物件, 就执行 wear_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 去包相关的呼叫段
落,不过这也是可以考虑的