【转】MUD教程--巫师入门教程4

摘要:
在MUD中,为了解决定时触发某种现象,一般有两种方法,一种是通过call_out()延时呼叫,另一种就是通过心跳。于是,对于要跨起离线前后的象做牢这类的事,大多都是采用condition。附:由于大多数MUD里的心跳是每两秒调一次,5+random是5至14次,因此可以看出每一个condition被调用的时间是平均19秒。然后它会按照condition的名字,也就是str这个变量去/kungfu/condition目录下去寻找同名的.c文件进行执行。

我们再次复习一下clean_up()函数返回1的含义,如果clean_up()函数返回1,则MUDOS在这一次的调用时不会做其的任何举动,但到了下一次想调用的时间里,还将再次调用这个对象的clean_up()函数。那么从这可以看出,有以下四种情况不会将其清除出内存:
一、非clone出来并且有no_clean_up参数的对象;
二、玩家永远不会
三、处于一个还存在的环境里
四、自己里面存在着玩家
也就是MUDOS定时摧毁内存不需要的对象是由外向内的,比如一个房间,系统只要检查这个房间里没有no_clean_up参数、里面没有玩家就可清除它,而房间里的物品、NPC都会因环境的不存在而消失。这个清除的定时时间一般都为两个小时。当然要视不同的MUDOS里的设置而看的。
再说一点题外话,如果一个房间长时间没有玩家走进来,当然会被MUDOS清出内存,而突然又有玩家进来呢?很简单,它会在一瞬间被编译进内存,进入一个已经存在在内存里的房间与进入一个刚刚编译出来进入内存的房间对于我们的玩家来说,是察觉不出它们之间的差异的。 

一 CONDITION系统分析

condition是利用系统的心跳来解决关于在一个不算太长的时间里,定时触发种现象的解决方法。在MUD中,为了解决定时触发某种现象,一般有两种方法,一种是通过call_out()延时呼叫,另一种就是通过心跳。在spock翻译的LPC及教材中曾对这两种方法进行了比较,好象是说:如果时间较长的话采用心跳比较好,时间短的话采用call_out()。紧接着又说了句,其个人看不出这两者有什么必要的区别,反正稀里糊涂的。不过,在实际运用中,两者都有不同的效果,大家看明白了本文之后,可以有自己的理解,并进行正确的选择。
call_out(other_fun,t)这个外部函数就是起一种延时呼叫的作用,后面必须要加第一个参数,指定延时呼叫的函数名,第二个参数表示延时几秒,再之后加上的参数可以作为呼叫的那个函数的参数。象这一个也就是设定在t秒钟后,呼叫other_fun这个事先指定的函数,你可以在这个函数里设定好应该进行的事情。比如,你在一个玩家进入监狱后,要做牢五分钟,如果一定要用call_out()进行的话,你可以设定成:
call_out("out_jianyu",300,ob);
意思就是在300秒后呼叫out_jianyu()这个函数,ob作为这个玩家的变量传递过去,然后在这个函数里进行将玩家从牢中放出来,告诉他做牢结束等等处理。但是,有的巫师看到这里,就会问了,如果五分钟没到,这个玩家退出游戏了怎么办?对,如果这个玩家退出游戏,这个call_out()一到时间就会找不到这个操作对象,如果程序写得不好就容易出错,即使是不会出错,那个玩家再次进入游戏后也就无法继续刚才的延时过程,也就不能够出牢。于是,对于要跨起离线前后的象做牢这类的事,大多都是采用condition。
condition的处理方法,就是在开始的时候在玩家身上设定一定的点数的记号,这些记号会通过save()保存进玩家的档案中。然后通过系统的心跳,每一次心跳就执行一次这个固定的condition的函数,函数每被执行一次就减一点记号,直至这个记号为0后,就可以触发某种效果。比如做牢,就在进牢时设定一定点数,每一次心跳减一点,减为0时,将玩家放出。由于这个记号在玩家身上,因此,在玩家离线时不会发生到有关函数对这个玩家的操作。
在ES系列MUD中。一个完整的condition系统包括三个部分:
一、首先就是调用或者说是触发它的程序,也就是/inherit/char/char.c这个
文件,这是所有玩家与NPC都共同继承的文件,在里面的heart_beat()函数,就是每一次心跳时调用执行的函数。里面有这么几句:
if( tick-- ) return;
else tick = 5 + random(10);
cnd_flag = update_condition();
解释:tick是这个文件里的一个全局变量,假设它只要>1,那么tick--就不会等于0,那么tick值就会减1,并且立即return;中止这个函数向下执行。假想如此这样经过几次减1之后,终有一次tick--就会为0,那么这时,程序就不会中止而是执行下一句的else。这时,tick被重新赋值为5+random(10)。并执行update_condition()函数,update_condition()是一个什么函数呢?在char.c里怎么也找不到。
那么我们再回头看看char.c这个文件的开头,就会看到,这个文件已经继承了/feature/condition.c文件,update_condition()这个函数正是在这个文件里面。所以下面我们就开看这个文件。
附:由于大多数MUD里的心跳是每两秒调一次,5+random(10)是5至14次,因此可以看出每一个condition被调用的时间是平均19秒。知道了这此,你才能更加有数地设定一些毒的发作时间,一些做牢的时间长短了。

二、下面就是主程序,feature目录下的condition.c文件。
程序详解:

#include "condition.h"//继承一些宏定义
mapping conditions;//定义一个映射集

/*更新函数 update_condition()
这个函数首先要检查玩家身上的每一个condition是否有效,如果出现了无效的condition,它会记录进/log/condition.err这个文件里,经常性地检查一下这个文件,可以发现并排除相当多的错误,因为一旦有一个错误,会在每一次的心跳中经常性地发生。然后它会按照condition的名字,也就是str这个变量去/kungfu/condition(某些MUDLIB下的路径是/daemon/condition)目录下去 寻找同名的.c文件进行执行。*/
nomask int update_condition()
{
mixed *cnd, err;
int i, flag, update_flag;
object cnd_d;
if( !mapp(conditions) || !(i=sizeof(conditions)) ) return 0;
//判断玩家有无condition的映射,没有就中止,毕竟不会每人都会有
cnd = keys(conditions);
//从这个映射中把关键词取出组成一个数组,实际上就是不同condition的名字
update_flag = 0;//初始化这个变量
while(i--)
//如果有1个以上的condition,就会一个个地循环执行
{
cnd_d = find_object(CONDITION_D(cnd[i]));
//到放condition的目录下寻找这个文件名,这个目录路径有宏定义的文件指定,一般在XKX风格里大多是kungfu/condition/下,xyj等放在/daemons/condition/下
if( !cnd_d )//如果没有的话,再尝试
{
err = catch(call_other(CONDITION_D(cnd[i]), "???"));//强制检验
cnd_d = find_object(CONDITION_D(cnd[i]));//再次寻找
if( err || !cnd_d )//如果强制检验与再次寻找中仍找不到,表示不存在这个condition
{
log_file("condition.err",sprintf("Failed to load condition daemon %s, removed from %O Error: %s ",CONDITION_D(cnd[i]), this_object(), err) );
//记录下来
map_delete(conditions, cnd[i]);
//删除玩家身上的这个condition
continue;//继续循环下一个
}
}
flag = call_other(cnd_d, "update_condition", this_object(), conditions[cnd[i]]);
//这个就开始执行这个conditon的设定文件里的update_condition()函数了,flag就是返回值,这个要看下面的具体设定文件的详解
if( !( flag & CND_CONTINUE ) )
map_delete(conditions, cnd[i]);
//返回值为0就表示这个conditon完毕了,就删掉
update_flag |= flag;
}
if( !sizeof(conditions) ) conditions = 0;
//检查一个也没有了,就清零
return update_flag;
}

/*改变大小函数 apply_codition(cnd,info),通过这个函数将玩家身上名叫的cnd的condition的值设为info,info可以为0,所以可以得用这个函数对玩家身上的condition进行增减。 */
nomask void apply_condition(string cnd, mixed info)
{
if( !mapp(conditions) )
conditions = ([ cnd : info ]);
//如果没有的话,就添加上,以cnd为键名,info为内容值
else
conditions[cnd] = info;
//有的话,直接改变内容值
}

/*取值函数 query_codition(cnd)通过这个函数,可以调出某个玩家身上名叫cnd的这种condition的值有多少。*/
nomask mixed query_condition(string cnd)
{
if( !mapp(conditions)||undefinedp(conditions[cnd]) )
return 0;
//如果没有conditions或者没有这个cnd的condition,就返回为0
return conditions[cnd];//否则返回具体值
}

/*清除函数 clear_condition()这个主要是在/feature/damage.c里的die()函数里调用,意思是一旦死亡,死者就会被清除所有的comdition。*/
nomask void clear_condition()
{
conditions = 0;
}
//END

三、下面就是上面说的与cnd同名.c文件--具体设定文件。一般每一种condition种类都要对应一个文件。里面只有一个update_condition()函数,通过/feature/condition.c这个程序来调用它的这个函数,可以添加一些效果或信息,比如,中毒的就会减精减气。但最主要是就每调用一次,将键名为这个cnd的内容值减少1点或多点。然后到了设定的点数,一般是到了0之后,会出现一些特殊的现象。象做牢的到了0就会被放出来,等等。
下面看一个例子:少林的做牢的condition的详解:
//kungfu/condition/bonze_jial.c
#include <ansi.h>
#include <login.h>

/*参照前面调用这个函数的/feature/condition.c文件,就可以发现,调用它的时候会传递一个玩家与他的名为bonze_jia1的这个condition的值*/
int update_condition(object me, int duration)
{
if (duration < 1)
//如果这个点数参数小于1,就表示做牢时间够了
{
me->move("/d/shaolin/guangchang1");
//从牢房里直接移到少林大门口
message("vision","只听乒地一声,你吓了一跳,定睛一看, "
"原来是一个昏昏沉沉的家伙从大门里被扔了出来! ",environment(me), me);
tell_object(me, HIY "只觉一阵腾云驾雾般,你昏昏沉沉地被扔出了少林寺! " NOR);
//出一些信息
me->set("startroom", START_ROOM);
return 0;
}
//如果不小于1,则设定减去一点,返回1,下次还会再执行
me->apply_condition("bonze_jail", duration - 1);
return 1;
}

到这里,condition的三大部分介绍完了,我们就以这少林寺的做牢为例,看一看condition执行调用的流程。
程序大约是在松林里被僧兵抓住后,进了戒律院,这个房间文件会通过apply_condition()这个函数在玩家身上被加上了名为bonze_jail的condition。于是玩家身上会多了这样的一个映射:
condition([({"bonze_jial":35},.....)])
那么通过前面的文件,就会看到,由于我们玩家是继承了char.c文件,每一个心跳中,就会检查tick,如果tick为1时,那么就会开始调用update_conditon()函数了。
这个函数首先取出玩家身上conditions映射中的关键词组成一个数组cnd:
cnd = ({"bonze_jial",......});
首先发现了bonze_jia1,于是开始到/kungfu/condition/目录下寻找名为bonze_jial.c的文件,也就是上面帖出的第三部分的文件,如果没有找到这个文件就会被记录进/log/condition.err文件里,有的话,开始传递时这个玩家与这个conditon的值,开始执行bonze_jial.c里的update_condition()函数 。第一次执行时duration也就是35,只要它大于或等1,就会被减出一点,返回值是1。会在下次tick为1的心跳是再次呼叫。这样经过若干次调用后,duration已经等于0了,那么也就是durtion < 1,于是me被move到少林的广场,出现信息:只听乒地一声,你......me又被覆盖了startroom然后返回值为0。玩家身上就会被删除这个condition。由于返回是0,那么/feature/condition.c文件里的update_condition()函数就会删除玩家身上的这个bonze_jia1的内容。

除了做牢之外,通过这样的随机调用,可以实现象毒这样不定时发作的特殊效果,每调用一次就让玩家减一些精呀气之类的,却出现一些恐怖的中毒信息症状之类的。其实,你还以设计一些特殊的毒,不但在发作的过程中伤害人体。而且要求必须在这段时间找到解毒方法或解药,否则,一旦到了最后一两点还没有彻底解毒,这个人就OVER死翘翘。呵呵,看起来有点恐怖呀,实际上我觉得这样才是最符合实际情况的呢!

采用condition处理的好处就在于,这个属性是加在玩家身上的,通过在游戏中的心跳进行调用。如果玩家离了游戏就不会调用得到。一旦玩家进入游戏中又会开始继续执行。这比call_out()一旦主呼叫者或呼叫中的参数失也就无法继续执行的缺点要灵活得多。此外,它由心跳调用,不管玩家在做什么事情,它都可以即时地主动反馈情况。

而如果你无需即时反映变化,比如说去领工资,只需要规定玩家在一定时间的间隔之内不能领两次工资的话。可以在第一次领的时候,在玩家身上记下领的时间,第二次再去领时,将当前时间与记录时间进行上减,看间隔够不够就行。象这样子就很简单,也几乎没有任何系统负责,比采用condition林节约得多。而如果你需要有时间一到就立即通知玩家去领下一次工资的话。那就必须要采用conditon。
它的缺点也显而易见,放在每一次的心跳里呼叫。如果一个MUD系统里的生物与玩家身上的condition过多过长的话,系统的负担也是不小的。

最后谈一谈有关的BUG。许多新巫师没有正确或完全理解condition的用法,就开始大范围地使用。在一些不应该用的地方也使用condition。举例,在某一个可以使玩家得到金钱等东西地方,设定任何玩家都必须间隔在线一定的时间才能去拿一次。如果这个通过condition来实现。就有可能利用死亡后清除所有condition的特点,让一个玩家反复去死亡再立即重新去拿钱拿东西。象这种情况,你或者要修改死亡后会清除所有condition,或者就不能采用它来做那些拿钱等东西的效果。
其二,象上面所讲的少林监狱的condition文件中,就隐藏着一个BUG。因为在XKX的文件里,少林的监狱并非是一定要等时间到了才会被放出来,可以通过贿赂狱卒,走五行洞先出来。而这样的话,一旦这个conditon到了最后的时候,不论这个玩家在哪里,都会被一下子Move到少林广场,然后出现你被扔出监狱等的字样。仔细想一想:如果MUD有不让你随便带东西或正常出来的地方,那么你就可以通过这个BUG跑到这种地方,把那些不能带出的东西放在身上,专心等时间一到,就会象乘飞机一样,一下子从那个地方飞到少林的广场。(例如谁与争锋里演武场)
解决方法很简单,只要在if(duration < 1)下面再加一个条件:
if(environment(me)->query("short")=="监狱")
才会move玩家出现信息。否则直接reuturn 0;就解决了。

最后,举一个毒的例子进行详解作为结束吧:
// /kungfu/condition/ice_poison.c

#include <ansi.h>
#include <condition.h>

inherit F_CLEAN_UP;

int update_condition(object me, int duration)
{
if( duration < 1 ) return 0;
if( !living(me) )
//如果对象不是清醒着,出的信息
{
message("vision", me->name() + "浑身颤抖,痛苦地哼了一声。 ", environment(me), me);
}
else//否则就清醒着
{
tell_object(me, HIB "忽然一阵奇寒从丹田升起,沁入四肢百骸,你中的寒冰绵掌发作了! " NOR );
message("vision", me->name() + "的身子突然晃了两晃,牙关格格地响了起来。 ",environment(me), me);
}
me->receive_wound("qi",15 + random(10));
me->receive_wound("jing", 10);
//伤一定的精与气
me->apply_condition("ice_poison", duration - 1);
//这个值减一点
if ( (int)me->query_temp("powerup") )
{
me->add_temp("apply/attack", -(int)(me->query_skill("force")/3));
me->add_temp("apply/dodge", -(int)(me->query_skill("force")/3));
//降低他的攻击力与躲避力
me->delete_temp("powerup");
//结束他的powerup
}
if( duration < 1 ) return 0;
//如果到了0,就返回,什么也不做,表示毒发结束,好了
return CND_CONTINUE;
}

下篇专题 系统刷新与清除分析

返回前页
三 详谈add_action()及其BUG
几年前,add_action()的当机BUG是令众多巫师极为头痛的事情,如今各显神通,有从MUDOS上解决,有从MUDLIB里调整。基本上已经看不到这种问题了。但是,如果未能了解这个BUG的产生原理,那么还有可能在其它的很多地方再次产生各种各样的新BUG,结合本人的摸索感受,试图全面介绍一下这方面的知识。

首先我们来了解一下MUD对玩家输入信息的处理流程。玩家在客户端的指令行里输入一些或长或短的字符后,系统接收到之后首先会调用在/feature/目录下的alias.c里的process_input(string str)函数
进行预处理。而那些字符也就是参数str。
(例一:玩家输入gall str==gall
例二:玩家输入c 我要go str==我要go
例三:玩家输入out  str==out
例四:玩家输入kill llm str==kill llm)
这个函数首先要对玩家的信息进行一些过滤判断,例如对于连续重复指令方面的判断呀之类的,主要是对机器人的限制。然后就是调用玩家自己设定的alias以及系统设定的alias(主要由/adm/daemons/下的aliasd.c定义)看看str里面是否有事先设定的alias,有的话就要转换成原先真正的指令,最后返回
这个经过处理过的新的字符串str。
(例一:gall 经检查发现与玩家设定gall==get all,因此str==get all
例二:c 我要go 经检查发现玩家设定c==chat,因此str==chat 我要go
例三:out 检查没发现alias,因此out==out
例四:kill llm 检查后没发现alias,因此str==kill llm )

在玩家进入MUD之后,连线程序logind.c在成功创造玩家的身体之后,会调用一个函数enable_player(),这个函数原型是在/feature/command.c里。该函数首先调用一个外部函数enable_commands(),允许它使用 add_action()所加入的命令。然后就add_action("command_hook", "", 1);
add_action()这是一个外部函数,格式如add_action(A,B,C);就是表示如果玩家输入指令第一个空格之前的单词与B相同的话,就是调用函数A,后面的参数C一般用不着,这里不细讲了。那么我们看看这里的就表示,如果玩家输入的第一个单词是"",其实就是所有的指令都符合这个条件的,那么就会调用到
函数command_hook()。而command_hook()函数就是在command.c里。str如果超过一个单词,也就是有空格,就会分成第一个为verb,后面的为arg。开始按顺序判断verb是否是方向、固定指令、emote动作、频道指令,如果是的话,就会把arg作为相应的参数传入。如果都不是,就会返回0,也就是出现“什麽”的
字样。
(例一:str==get all,get为一固定指令,调用get.c->main()参数是"all"
例二:str==chat 我要go,chat为频道名,调用channeld.c里的do_chat,
参数arg是"我要go"
例三:str==out,玩家所在场景发现有名叫out的出口,因此调用go.c->main()
参数arg是"out"
例四:str==kill llm,kill是一固定指令,调kill.c->main(),arg是"llm" )

以上是MUD处理信息的经过。
因此,MUD里所有的指令都是通过add_action()来实现的。而add_action()可以增加相同名称的指令,如果指令相同,则后加的会先执行,请注意这里,并不是说后加的“覆盖”先加的,而是“先执行”。关于一个同样的动作单词就可以有好几层的add_action。那么在上一层调用的函数如果是返回0的情况下,系统会自动再去执行下一层的add_action()调用的函数,如果是其中任意一层返回是1,就表示到此中止,不会再执行下一层的add_action(),关于这一点特性可以灵活地使用。比如一个kill指令,本身通过command_hook已经加了一个,有的房间里再次调用一个add_action("do_kill","kill"),后来进来一个NPC,NPC身上也带有一个新的add_action("do_kill","kill"),那么只要进入这个房间后,玩家身上就会有了三层有关kill的add_action()。如果这里输入kill,自然是先执行NPC身上的do_kill()。返回是0的话,再执行房间里的do_kill(),再是0的话再执行kill.c。所以,在一般我们在房间,NPC以及OBJ里做的add_action()如果与/cmds目录下的指令相同的话,都会优先于指令先行。而且如果是后加的,肯定优先于前加的。而其中任意一层一旦有返回1的话,就会立即中止。
LPMUD里基本上所有的谜题和很多特殊效果都需要借助add_action()来实现,认真理解并掌握它的用法是相当重要的。
下面我们来谈谈add_action()的 BUG吧!很多老的玩家都知道它的用法,先由一个A买一只鸡腿(包子也可以),由另一个B打昏它,然后B从A身上搜走鸡腿,再吃光鸡腿扔掉。等A醒来输入eat jitui指令,系统便会立即当机。
原因分析,传统MUDLIB的eat是一个add_action(),做在食物的标准继承food.c里。玩家买下一只鸡腿,那么这个eat的add_action()就加到了玩家身上。在正常情况下,这个物体消失(比如吃掉)或离开玩家所处环境(比如扔掉并离开),那么add_action()都会正常去掉。但是在玩家昏迷时,其它人从它身上拿走这个带add_action()的物体,这个add_action()并不能正常地从玩家身上去掉。而当玩家苏醒后,这个eat的add_action()依旧存在于他身上,他依旧可以执行这个指令,如果执行的对象,比如鸡腿还在游戏中,不论这只鸡腿被玩家B带到了多远的地方,A都可以通过eat jitui吃得到这只鸡腿。这种情况只是有点滑稽而已。但是如果这个鸡腿已经消失了,比如B吃掉了,那么它只能消除在B身上的add_action(),这时A再执行eat,系统一下子找不到jitui这个物体,就会从内存中载入一大堆莫名其妙乱七八糟的东西,迅速进入死循环,直接导致当机。所以要实现这个BUG的条件有二,一是找一件有add_action()并且可以通过正常方法摧毁的,比如食物,不值钱的东西。二是用两个ID执行。
目前新版本的MUDOS据说已经从底层上修改掉了这个BUG。同时明白了其中的原理也可以在MUDLIB上用很多方法来避免这种情况的发生。
再下面就谈一下较少有人知的另一个BUG,这个BUG表面上看起来问题不大,实际运用中有时会产生很大的问题,就是sleep对add_action()的影响。大家可以仔细看看sleep.c文件,玩家进入睡眠状态就会调用一个函数me->disable_player();这个函数原型在/feature/command.c里,最终调用disable_commands();这个外部函数,disable_commands()的用处就是让一个活物件变成「非活着」,一是add_actions 失效,二是livingp()返回0值......也就是说,去掉了身上所有的add_action()。然
后在醒来之后,再次调用me->enable_player();这个函数我在前面文章的第五段里介绍过用法与作用,它只是恢复了玩家的add_action("command_hook", "", 1);也就是所有的系统固定指令。比如玩家身上物品的add_action,所处环境的add_action都是在init()里加载的,玩家在sleep之后并没有呼叫到init(),自然就没有这些。那么问题就会出现了。假如我们在一个房间里或是在一个物体上作了一个企图覆盖掉正常指令的add_action(想覆盖掉正常指令,只要让这个add_action()调用的函数总是返回1就行)。那么,玩家只需sleep一下之后,就会让这个覆盖无效。无效之后产生的问题大小就与你当初覆盖的目的有关了。要解决这一问题,可以修改sleep.c,在玩家醒来后的一瞬间,让玩家离开原地再重新move回到所处的环境,再让玩家身上所有的东西也同样移出去再重新move回到玩家身上,这样就让系统再次加载玩家身上应该加载的add_action。
总之,MUDOS当初对于add_action的考虑并不是很完善。再加MUDLIB里的处理手法,对于象过去的昏迷、睡觉以及今后要发展的点穴、捆绑等等的处理都需要屏蔽掉指令,那么处理的前后则一定要小心,否则新东东一上,新BUG也就隆重登场。
谁与争锋 叮当 2001、04、21

新手常见问题
(本栏目欢迎江湖菜鸟来信提问:)

一、当我第一次登录谁与争锋,为何总是显示密码不正确?

二、在新人物注册时,随便填一个假的email要不要紧?

三、我密码忘了,该怎么办?

四、我在MUD中发现可以看到别人说的话,却看不到自己chat出来的话,怎么办?

五、我有一个人物突然不能get东西了,无论get什么东西,都是显示“什么?”

六、我在建一个新人时,由于选天赋,超时被踢出来,然后再连时,怎么也连不上了怎么办?

一、当我第一次点击“连线”后进入“谁与争锋”初始页面,要求我输入英文名称和密码,在我输入了ID和密码后,就显示我密码错误,同时跳出一个对话框,告诉我“你退出 MUD主机当了 网络断开 如果你使用的是SLIP/PPP:MEDOM断线或呼叫等待功能使线路断 线”,10秒后让我再次连线。但我总是无法连上线。无奈!请指教。

答:连线后,当系统要求你输入英文名时,就象是申请免费email一样,你先输入一个英文名,系统就会检查是否已经有了这个用户存在。如果你是第一次来这里,它还要求你输入密码的话,就表示这个英文名已经被别人注册了,你如果强行输入一个密码的话,一般是不会正确的,即显示密码错误,然后系统会强制你与MUD断开,一般ZMUD会弹出你所说的那个窗口,当然你不必要等10秒,直接点击“重新连线”,再输入一个新的英文名,直到系统告诉你:你所选的英文名将创造一个新人物,您确定吗?(Y/N) 就表示你可以用这个名字了,然后你输入Y就可以进行新人物的创立了! 如果你的确是从前注册过的这个名字,那么则会有三种情况:一,你密码忘记了;二,你密码被别人盗用后并改了;三、你超过三个月未连线被系统清理掉后又被别人抢注了。如果是前两种情况,可以参照第三条进行解决。

二、在新人物注册时,系统会提示要我输入一个电子邮件地址,我发现随便输一个,只要里面包含@就可以了,不知对以后会不会有影响。
答:这个电子邮件地址的作用,在于如果你的用户密码遗忘或者被别人盗用,你就可以通过这个地址向巫师组发信,请求改变成一个临时密码。巫师组受理后,会核对地址,并将新密码向你注册时的地址发去。也就是说:如果你注册时的地址是一个错误或不存在或你自己无法收到的话,那你就只能保佑你的密码不要遗忘或被人盗用了。因为这个信箱地址在注册后是不允许改动,是对于是否是你本人申请的唯一认证。为了保证这个地址的权威性与严格性,玩家注册的信箱地址在任何情况下不允许改动,(否则,只要盗用者再改一下注册信箱地址,原玩家就无法要回自己的ID了)。一旦失窃或遗忘了密码的ID的注册信箱地址是错误的,那么则不可能要回自己的密码的。同时,巫师组承诺对玩家的这些邮箱地址保密,绝不用于其它任何用途。

三、我密码忘了,该怎么办?
答:这个首先参照第二条,在玩家注册时,系统有明确提示要输入确切本人能够收到的电子邮件地址,此地址作为巫师确认玩家身份的唯一有效证据; 玩家若密码发生问题,可使用该信箱地址向我们的巫师信箱:
mud@wst.net.cn发去申请要回密码的邮件,并写明玩家id及原因。
巫师收到信后在核实该信箱地址确实是此id的注册信箱,便会在游戏中的无锡东林书院三楼post出受理玩家的姓名以及根据其经验标出该交纳的黄金数,之所以要交费,是想通过这个手段提醒玩家:记牢密码的重要性。三天两头地忘记密码,损失的就是黄金与时间。玩家可用任何ID去交费。交费后,巫师就会用临时密码覆盖掉该ID的旧密码,并发往向该信箱地址,由玩家登录后自行修改。而凡是邮件地址不符或无效地址的id,巫师则无法确认,请予以理解。一般来说,巫师在线不处理任何与密码有关的事情。

四、我在MUD中发现可以看到别人说的话,却看不到自己chat出来的话,是怎么一回事?
答:如果你用的是ZMUD4.62以下版本的话,这应该是zmud软件没有安装好的缘故。你可以再向别人问一下,问他们是不是能看到你的话。如果他们能而你自己不能,那十有八九就是这个原因了。解决的办法很简单:将ZMUD删掉,重新安装一遍即可。如果是同一个ZMUD,别的ID正常,而某一个ID不正常,就表明这两个ID用的不是同一个设置文件,将ZMUD里这个用户设置删掉即可。

五、我有一个人物突然不能get东西了,无论get什么东西,都是显示“什么?”问别的玩家,他们都是好的,为什么?
答:一般来说,类似的情况还很多,突然地不能wear了,不能give了,而其它玩家都是好的,甚至自己连一个搬搬来看都是好的,那就说明问题出在你自己的人物身上。而十有八九就是出在alias,你可以键入“alias”指令,查看一下自己设定了哪些alias。有的玩家为了图方便,用alias把get 设成get all from corpse之类的简化式。那么当他再次输入“get silver”时,实际上系统已将这里的get解释为“get all from corpse”,全句就成了“get all from corpse silver”,当然觉得有些莫名其妙的了。常用的指令出了问题,记住先查看alias,再问巫师。

六、建新人超时后,就无法再连入,怎么办?
答:这是MUD里建新人时,存档方面的一个毛病,产生了一个废了的帐号,有点象一些程序尸体一样。在以前时常发生,目前应该已经从程序上解决了,不过,万一再发生,你只有向巫师发信,由巫师经确认后将这个废帐号手工清除掉。

免责声明:文章转载自《【转】MUD教程--巫师入门教程4》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇windows命令行下批量拷贝同一后缀的文件到另外一个目录基于 WebRTC 的 RTSP 视频实时预览下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C语言的面向对象设计 —— 对 X264/FFMPEG 架构探讨

类似题目的文章已经不新鲜了,这里,我仅仅总结自己的一些代码经验,结合两款在视频开发领域比较常用的开源软件探讨C语言的应用问题。 1.为什么要用C语言 曾几何时,我也不熟悉C,最早接触C的是在大学四年级,当时已经学过pascal,过二级也是pascal。接着走上了Delphi的路,多方便的软件,写写画画,程序就出来了,本科的毕业设计就是这样出来的MIS,在当...

《Spark Python API 官方文档中文版》 之 pyspark.sql (四)

摘要:在Spark开发中,由于需要用Python实现,发现API与Scala的略有不同,而Python API的中文资料相对很少。每次去查英文版API的说明相对比较慢,还是中文版比较容易get到所需,所以利用闲暇之余将官方文档翻译为中文版,并亲测Demo的代码。在此记录一下,希望对那些对Spark感兴趣和从事大数据开发的人员提供有价值的中文资料,对PyS...

Watchdog问题实例分析

1.日志获取 Watchdog相关的问题甚至需要以下所有的日志: logcat 通过adb logcat命令输出Android的一些当前运行日志,可以通过logcat的 -b 参数指定要输出的日志缓冲区,缓冲区对应着logcat的一种日志类型。 高版本的logcat可以使用 -b all 获取到所有缓冲区的日志 event 通过android.ut...

TSQL 定义分割字符串的函数

一、按指定符号分割字符串,返回分割后的元素个数,方法很简单,就是看字符串中存在多少个分隔符号,然后再加一,就是要求的结果。 CREATEfunctionGet_StrArrayLength ( @strvarchar(1024),--要分割的字符串 @splitvarchar(10)--分隔符号 ) returnsint as begin declare...

ES6规范

一、简介 js由三部分组成:ES+DOM(文档对象模型)+ BOM(浏览器对象模型) ES作为核心,是一套标准,规范了语言的组成部分:语法、类型、语句、关键字、保留字。定义了数据结构和语法,定义了函数和对象的实现,包括原型链和作用域链的机制和实现。 JavaScript 的核心 ECMAScript 描述了该语言的语法和基本对象; DOM 描述了处理网页内...

python3 字符串base64编码

在一些项目中,接口的报文是通过base64加密传输的,所以在进行接口自动化时,需要对所传的参数进行base64编码,对拿到的响应报文进行解码; str(源字符串)--str(加密后)--str(解密) Python 2 将 strings 处理为原生的 bytes 类型,而不是 unicode, Python 3 所有的 strings 均是 unico...