写给对 MUDLib 感兴趣的初学者们。
F_SKILL 是一个底层物件,它以 F_ 打头,所以是放在目录 /feature 中的,以
F_ 打头的宏定义的物件都是放在目录 /feature 中,无一例外。在
/include/globals.h 这个“大头文件”中是这样定义的:
#define F_SKILL "/feature/skill.c"
所以如果你无论在自己编写或修改的任何程序中只要你写下了 F_SKILL (前后连接
了其他字母数字或语法错误的除外),你的程序被 load 或 update 时 F_SKILL
这个字符串都会被 "/feature/skill.c" 代替,你写 F_SKILL->faint() 就会被
代替为 "/feature/skill.c"->faint(),当然 "/feature/skill.c" 这个程序
里是没有定义 faint() 这个函数的,高兴的话可以自己给它加一个,这里是打个
比方而已。
F_SKILL 唯一地被 CHARACTER 继承(关于继承的感念我就不在这里讲了),就是
说只有 CHARACTER 才会用的着 F_SKILL ,这个 CHARACTER 又是什么呢?还是
看看“大头文件”是怎么写的:
#define CHARACTER "/std/char"
character 的意思是“角色”,也就是玩家角色(Player)和非玩家角色(NPC)
喽,总不会把一只香喷喷的炸鸡腿看成角色吧。说了这么多,无非想说角色这种物
件继承了 F_SKILL ,要用到 F_SKILL 。F_SKILL 这个物件对角色来说有什么用?
思考一下:单词 feature 的意思为“特征”,放在 /feature 这个目录下的物件
都具有某方面特征,更应该说是特长吧——每个 F_ 物件都被设计来专职完成一定
的工作,F_SKILL 就是专职负责 skill 方面的工作。角色不单是有 skill 这个特
征呀!没错,CHARACTER 除了继承 F_SKILL 外还继承了很多 F_SKILL ,很多很多,
扳手指都数不过来,以后再慢慢讲其他的。
平常敲 skills 命令,比如 skills guolao ,会看到以下的内容:
张果老目前所掌握的技能有以下十二项:
□八卦阵法 (baguazhen) - 平平淡淡 70/ 0/ 5041
基本轻功 (dodge) - 平淡无奇 80/ 0/ 6561
内功心法 (force) - 平平淡淡 70/ 0/ 5041
基本锤法 (hammer) - 粗通皮毛 90/ 0/ 8281
□开山锤 (kaishan-chui) - 半生不熟 100/ 0/ 10201
读书识字 (literate) - 会 元 50/ 0/ 2601
拆招卸力之法 (parry) - 平淡无奇 80/ 0/ 6561
基本法术 (spells) - 平淡无奇 80/ 0/ 6561
□太乙仙法 (taiyi) - 平淡无奇 80/ 0/ 6561
扑击格斗之技 (unarmed) - 普普通通 60/ 0/ 3721
□五行拳 (wuxing-quan) - 普普通通 60/ 0/ 3721
□镇元神功 (zhenyuan-force) - 平平淡淡 70/ 0/ 5041
这一行行一列列这么整齐,却不是 F_SKILL 的功劳,:-(,不要奇怪,打个比方
就清楚了:在以上这些显示的内容中,F_SKILL 好比是肉体,其他程序好比是衣
服,一个是内因,一个是外因……faint,扯哪去了?sorry:-)还有平常最高兴
看到的“你的「基本内功」进步了!”之类的也是 F_SKILL 的功劳。
更进一步,看看 F_SKILL 定义了哪些函数,有些什么功能:
(先引用些源程序凑一下字数,请不要用西红柿砸我:-D)
// 神话世界·西游记·版本4.50 <- 每个程序里面都会有这两行版本信息,
/* */ <- 整齐美观,值得学习
// skill.c
#include <- 包含一些头文件,先不要管
#include <-
mapping skills;
mapping learned;
mapping skill_map;
mapping skill_prepare;
这四行定义了四个 mapping 类型的全局变量,全局变量的作用除了能在整个
物件内部发挥传递参数的作用外,在物件存储中还有特殊的用处,就是物件
被 save 的时候这些全局变量会全部被存储起来,物件被 load 的时候又会
被读出来,是不是很爽?
举个例子说说这些 mapping 的数据结构,以张果老为示范:
张果老目前所掌握的技能有以下十二项:
□八卦阵法 (baguazhen) - 平平淡淡 70/ 0/ 5041
基本轻功 (dodge) - 平淡无奇 80/ 0/ 6561
............
□镇元神功 (zhenyuan-force) - 平平淡淡 70/ 0/ 5041
在 F_SKILL 中:
skills = ([
"dodge" : 80,
"taiyi" : 80,
"literate" : 50,
"zhenyuan-force" : 70,
"kaishan-chui" : 100,
"parry" : 80,
"unarmed" : 60,
"wuxing-quan" : 60,
"spells" : 80,
"force" : 70,
"hammer" : 90,
"baguazhen" : 70,
])
注:mapping 这种数据格式的特点是小括号内包含中括号,就是这样—— ([ ]) ,
里边可以有很多子项,每一项都带一个冒号,冒号左边的是子项的名字,也就是双
引号括起来的字符串——可以括很多字符,汉字也可以,冒号右边是子项的内容,
这内容的数据格式是任意的,可以是字符串、整数、数组、映射(就是 mapping 的
中文名)……简直就像目录一样——目录下面可以有文件,也可以有子目录,子目
录下面又可以有文件和子目录……只要同一级内没有相同的子项名称就行;子项与
子项之间用逗号隔开。"dodge" 就是一个子项的名称了,80 就是这个子项的内容
了,把一个 mapping 写成多行是为了好看,如果你觉得写成一行更好些,可以自
便,就像这样:
skills = ([ "dodge" : 80, "taiyi" : 80, "literate" : 50, "zhenyuan-force"
: 70, "kaishan-chui" : 100, "parry" : 80, "unarmed" : 60, "wuxing-quan" :
60, "spells" : 80, "force" : 70, "hammer" : 90, "baguazhen" : 70 ])
呵呵,好看吗?
继续:
learned = ([
"dodge" : 0,
"taiyi" : 0,
"literate" : 0,
"zhenyuan-force" : 0,
"kaishan-chui" : 0,
"parry" : 0,
"unarmed" : 0,
"wuxing-quan" : 0,
"spells" : 0,
"force" : 0,
"hammer" : 0,
"baguazhen" : 0,
])
skill_map = ([
"dodge" : "baguazhen",
"unarmed" : "wuxing-quan",
"hammer" : "kaishan-chui",
"force" : "zhenyuan-force",
"spells" : "taiyi",
])
skill_prepare = ([ ])
怎么知道这四个变量的值呢?后面有四个函数,它们的返回值就是这四个变量的
内容,看:
⑴ mapping query_skills() { return skills; }
⑵ mapping query_learned() { return learned; }
⑶ mapping query_skill_map() { return skill_map; }
⑷ mapping query_skill_prepare() { return skill_prepare; }
如果你是巫师,能使用 call 命令,就可以使 call zhang guolao->query_skills()
来获得张果老身上的 skills 变量的值了。
这一行:
□八卦阵法 (baguazhen) - 平平淡淡 70/ 0/ 5041
前面的“□”和“八卦阵法”还有“平平淡淡”都不是 F_SKILL 的功劳,而是
skills 这个命令做的,这个命令的源程序在文件 /cmds/usr/skills.c 中,具体
怎么处理的可以去看看源程序。还有,后面的那个数字:5041 是 FoF 的发明,
也是写在 /cmds/usr/skills.c 中的。
继续:
void set_skill(string skill, int val) { ...... }
一看就知道,这个函数设置 skill 的等级,有没有见过巫师给人 call 技能?
一个命令下去就深不可测了,hoho
int delete_skill(string skill) { ...... }
这个就相反了,会删除技能,有没有试过“你决定放弃继续学习基本枪法”?
虽然你敲的是 abandon hammer 命令,但实际起作用的是这个函数
varargs void map_skill(string skill, string mapped_to) { ...... }
这个函数是把高级技能 enable 到基本技能上,敲 enable 命令就会用到它了
varargs void prepare_skill(string skill, string mapped_to) { ...... }
string query_skill_mapped(string skill) { ...... }
string query_skill_prepared(string skill) { ...... }
这三个函数没什么好说的
varargs int query_skill(string skill, int raw) { ...... }
这个函数跟前面的 set_skill() 函数是一对儿,一个存,一个取,但是,取的
内容不一定是存的内容,因为它多了一个 int 类型的 raw 参数,如果这个参数
被省略了,或者值是 0 ,函数返回的值是一个“有效技能”,如果是一项基本
技能,就返回该技能的等级的一半加上 map 到这个技能上的高级技能的等级之
和,例如 enable hammer kaishan-chui ,query_skill(hammer) 将得到
hammer / 2 + kaishan-chui ,如果是一项高级技能,就直接返回它的等级;
如果参数 raw 的值不为 0 ,函数返回的值也直接是该技能的等级。
在游戏中,有不少地方要检查玩家的基本技能,有些地方要检查有效技能,都
是通过这个 raw 参数灵活变通的。
(未完待续)
发信人: fof (格斗之迷~思考中), 信区: wiz
标 题: MUDLib 攻略之 F_SKILL(下)
发信站: 交通大学思源BBS (Wed Nov 15 00:52:49 2000), 转信
(承上)
下面的这两个函数是关于角色死亡所受到的技能惩罚的,以前玩家死于 NPC 之
手或非命的时候,会受到技能和道行、潜能的惩罚,所有技能减一级,好惨噢!
为了减轻玩家的痛楚,鼓励大家勇敢地西行灭妖,我决定修改这个函数。看看
修改日期,至今差不多一年喽!
// FoF changed 99-12-25
int skill_death_penalty()
{
string *sk;
int i, ii, n;
object obj = this_object();
if( wizardp(obj) || !mapp(skills) ) return 0;
sk = keys(skills);
if( sizeof(sk) == 0 ) return 0;
n = 4 - obj->query("kar") / 7; //先天福缘的影响
n = n + 10 - obj->query_kar() / 5; //后天福缘的影响
if ( sizeof(sk) > 8 ) n = n + sizeof(sk) / 3; //技能数量的影响
技能数越多,受到的惩罚也越多,对于三心二意的人来说可不是好事哟
n = n > sizeof(sk) / 2 ? n : sizeof(sk) / 2;
n = random(n);
受到惩罚的技能总数小于所学技能总数的一半,不痛了吧?
if( !n ) return 0;
for( i = 0; i < n; i ++ ) { // 把 learned 保存起来
ii = random(sizeof(sk));
skills[sk[ii]] --;
obj->add("death_skill_loss/" + sk[ii],
skills[sk[ii]] * skills[sk[ii]]);
if( skills[sk[ii]] <= 0 ) delete_skill(sk[ii]);
}
skill_map = 0;
return 1;
}
取得真经之后如来佛会给你三根救命毫毛,可以用来“起死回生”,恢复一些
由于被 NPC 杀死或非命所损失的道行和技能,以前铁定的是一级技能或什么都
没有,现在经过修改,恢复的与损失的是等价的。
以前的所有损失,在取得真经之后得到恢复,高兴么?
// FoF changed 99-12-25
int skill_death_recover()
{
string *sk;
object obj;
int i, amount;
if( !mapp(skills) ) return 0;
sk = keys(skills);
obj = this_object();
for( i = 0; i < sizeof(sk); i ++ ) {
amount = obj->query("death_skill_loss/" + sk[i]);
amount += learned[sk[i]];
while ( amount >= ( skills[sk[i]] + 1 ) * ( skills[sk[i]] + 1 ) )
{ // 把 learned 恢复成技能
amount -= ( skills[sk[i]] + 1 ) * ( skills[sk[i]] + 1 );
skills[sk[i]] ++; // 把损失的 learned 恢复成技能
}
learned[sk[i]] = amount;
}
obj->delete("death_skill_loss");
return 1;
}
以下这个函数是管角色技能升级的,当你敲了若干个 learn force from master
之后看到“你的「基本内功」进步了!”就是这个函数的功劳了。
升级的条件是技能的 learned 点数要超过(当前等级+1)的平方值。这里有
一个小细节,就是 int 型的参数 weak_mode ,这个参数的值不为 0 ,将会
导致即使技能的 learned 点数超过了(当前等级+1)的平方值,也不能看到
“你的「基本内功」进步了!”,而且该项技能会显示出特殊的颜色,参数
weak_mode 不为 0 的情形还不少呢:跟师父切磋、使用外功(exert)、
perform、practice、study 等情况下都有可能出现 weak_mode 不为 0 的情形,
所以看到技能的 learned 点数超过了(当前等级+1)的平方值还不升级的时
候不要奇怪。
varargs void improve_skill(string skill, int amount, int weak_mode)
{
int spi;
if( !find_object(SKILL_D(skill)) &&
file_size(SKILL_D(skill) + ".c") < 0 )
error("F_SKILL: 没有这种技能(" + skill + ")!\n");
if( !weak_mode || !userp(this_object()) ) {
if( !mapp(skills) ) skills = ([]);
if( undefinedp(skills[skill]) ) skills[skill] = 0;
}
// Give learning penalty to those learning too much skills.
spi = query("spi");
if( sizeof(learned) > spi ) amount /= sizeof(learned) - spi;
if( !amount ) amount = 0;
if( !mapp(learned) ) learned = ([ skill : amount ]);
else (int)learned[skill] += amount;
if( (!weak_mode || !userp(this_object())) &&
learned[skill] > (skills[skill] + 1) * (skills[skill] + 1) ) {
skills[skill] ++;
learned[skill] = 0;
tell_object(this_object(), HIC "你的「" +
to_chinese(skill) + "」进步了!\n" NOR);
SKILL_D(skill)->skill_improved(this_object());
}
}
下面这个函数是我增加的,目的是通过以内存换速度的办法来减轻战斗精灵
COMBAT_D 的负担。当时想的是用战斗升级法来替代传统的“鸡腿升级法”
(就是用鸡腿打潜能来学其他技能)为 MUD 的合理化作点贡献,效果不是
很好,不过 Acool 说他曾在战斗中把 dodge 提升到七十多级而没有花任何
潜能向师父学,还有人说跟芭蕉怪打把 whip 打到了近百级的事,真是意料
之中,又是意料之外了。
不足之处请多提宝贵意见!MUD 合理化之事业无限荣光!
// FoF 99-12-28 to reduce work for COMBAT_D
void reset_skill_improve_point()
{
int amount;
object ob = this_object();
if( !userp(ob) ) return;
amount = random(ob->query_int()/10) + ob->query_int()/10 +
random(ob->query_con()/8) + ob->query_con()/8;
set_temp("combat/skill_improve_point/dodge", amount); // 9 - 18 points
一次成功躲开敌人攻击使 dodge 增长的点数,当然这个“成功”包含了强弱对比
的关系。dodge 的增长与悟性和根骨两个属性相关。
amount = random(ob->query_int()/10) + ob->query_int()/10 +
random(ob->query_con()/8) + ob->query_con()/8;
if( !undefinedp(skills) && !undefinedp(skills["dodge"]) )
amount += random(skills["dodge"]/20);
set_temp("combat/skill_improve_point/map_dodge", amount); // 14 - 23 points
map 到 dodge 上的技能即高级轻功增长的点数,除了与悟性和根骨相关外,还
与 dodge 的等级相关。
amount = random(ob->query_cps()/4) + ob->query_cps()/4;
set_temp("combat/skill_improve_point/parry", amount); // 10 - 20 points
一次成功招架敌人攻击使 parry 增长的点数,当然这个“成功”也包含了强弱
对比的关系。parry 的增长与定力相关。
amount = random(ob->query_cps()/4) + ob->query_cps()/4;
if( !undefinedp(skills) && !undefinedp(skills["parry"]) )
amount += random(skills["parry"]/20);
set_temp("combat/skill_improve_point/map_parry", amount); // 15 - 25 points
map 到 parry 上的技能增长的点数,除了与定力相关外,还与 parry 的等级
相关。
amount = random(ob->query_int()/8) + ob->query_int()/ 8 +
random(ob->query_con()/5) + ob->query_con()/5;
set_temp("combat/skill_improve_point/attack", amount); // 13 - 26 points
一次成功击中敌人使基本攻击技能增长的点数,当然这个“成功”也包含了强弱
对比的关系。攻击技能的增长与悟性和根骨属性相关。
amount = random(ob->query_int()/8) + ob->query_int()/8 +
random(ob->query_con()/5) + ob->query_con()/5;
// amount += random(ob->query_skill(skill_type, 1)/20);
set_temp("combat/skill_improve_point/map_attack", amount); // 13 - 26 points
map 到基本攻击技能上的高级攻击技能增长的点数,除了与悟性和根骨相关外,
还与基本攻击技能的等级相关。
}
F_SKILL ENDS
看到这里,你知道角色身上有关 skill 的数据都有哪些,以及它们是怎么操作
的了吗?
尊重作者 转载请注明出处52mud.com