背景:
阅读文章

巫师编程

wiz编程杂谈(1)

[日期:2007-05-05] 来源:  作者:佚名 [字体: ]

关于notifal_fail

usage: notofy_fail(string | function str);
请注意:notify_fail() always returns 0.

nofify_fail() 的作用是设置本次命令的失败信息。嗯,听起来好像很复杂 :P
其实就是取代“什么?”这句话的东东啦。比如我们打一个命令(包括动作什么的)。


要是此命令的程序return 0 的话,系统就会给个错误信息 “什么?”但假如我们
在命令的程序里面有notify_fail() ,那么假如命令最后返回 0 。那系统就给出
本命令执行的最后一个notify_fail() 所设定的错误信息,否则就是“什么?”。

其中notify 的参数可以是一个str 的function 。就是把这个func 所返回的
string 做错误信息了。

例如:help 命令里的一段:

if( stringp(file = me->find_command(arg)) ) {
notify_fail("有这个指令存在,但是并没有详细的说明文件。\n");
//在执行notify_fail 的时候并没显示,只是在最后返回0 值时才显示此信息。
return file->help(me);
}

//要是return file->help(me) == 0 的话。
//就会给出错误信息"有这个指令存在,但是并没有详细的说明文件。\n"
//假如没notify_fail 这句,错误信息就是 “什么?”


标 题: room的制作


/doc/build/room
□ 如何建造一个房间

房间是构成这整个世界的要素之一,在此我们提供了一个房间的标准物件来让
所有的房间继承。而如同其他的物件一般,你需要写一个 create() 来设定房间中
的叙述、出口、物品、生物等等。这里,我喜欢说你用 create() 这个函式来赋予
这个房间的属性。一般来说,要建造一个简单的房间,你只要赋予它基本的属性即
可。当然,我们不认为一个区域中几十个房间没有任何的机关或秘密,是个会吸引
玩家一游的好地方。

下面,提到了一些建造房间所需要留意的事项,也会配合一些例子来说明。

一、基本篇

一个基本的房间,要有 short <短叙述> 、 long <长叙述>、 exits <出口>

□ 当你在写一个房间的 long <长叙述>时,其格式为:

set("long", @LONG

房间的叙述…….

LONG
);

其中 @LONG 和 LONG 是互相对应的,你可以用任何字接在 @ 後面,但是前
後两个字一定要一样,这样系统才能判别,而房间的叙述写完时,一定要换行後再
接第二个 LONG ,且同一行不能再有其他任何的字元,不然系统无法判定叙述是否
该结束了,会造成编译时的错误。

而为求区域看起来外观上整齐、统一,房间的长叙述中每一行的长度必须一样
,而一行的长度建议为 29 到 32 个中文字,约占萤幕的三分之二。并且一个房间
的叙述最好不要低於三行,区域各个房间的叙述重复性降到越低越好,这样你的区
域看起来才不会太过阳春。当然,有时候为了某些目的,比如一个迷宫,你可能会
相邻的几个房间都用到一样的叙述,那自然不在此限。

□ 一个房间的出口则以下列格式赋予: set("exits", ([
"方向" : "连接到的房间之档名",
………..
]);

在这里,为了一个以後区域开放後搬移目录的便利性,建议采用__DIR__ 这个
由系统提供的巨集来写路径,比如说:

"west" : __DIR__"path3",

"west" : "/u/d/davidoff/goathill/path3",

是完全一样的。但前者显然在以後目录的搬移上方便的多。而在下面会提到设定房
间中的物品或生物时,也建议采用这种方式写作。 □ item_desc 这是用来设定个别景物的描述,当玩家用 look 这个指令时就会作
用。其格式为:

set("item_desc", ([
"景物名称" : "景物叙述",
………..
]);

其中景物叙述可以是字串或是一个 function ,所以你可以利用这个功能加以
变化,当玩家 look 一个景物时,可能看到叙述,也可能发生一些特殊的事件,而
你就可以在被呼叫的函式中写下这些事件。

□ objects 可以让这个房间在每次 reset时载入某些生物或某些物品:

set("objects", ([
"物品或生物的档名" : 数量,
………..
]);

如同前面所提到的,建议采用 __DIR__来编写你的路径,而数量则要用整数。

□ 要为这个房间添上门户时,记得前面必须先 #include <room.h>。而格式为:

create_door("出口方向", "门的名称", "进入方向", 预设状态);

比如说,这里明显的出口有 west、east 和 up。 而你要让西边有一个关上的
红木门,你可以这样写:

create_door("west", "红木门", "east", DOOR_CLOSED);

当玩家进入这个房间时,他会看到: 这里明显的出口有 east 和 up。

而当他 look west 时,会看到:这个红木门是关上的。


其他的一些属性,你可以参考 /doc/build/room_prop 或是读一下标准物件的
room.c。也建议你可以多用 more here来观看一间特殊的 room。

二、进阶篇

要让你的区域中富有变化,生动有趣,除了文字叙述的丰富度以外,你更可以
利用 init() 这个函式为你的房间增加一些「机关」或「秘密」。

这里,先让我们了解一下 init() 的用途为何,和为什麽要用到它。每一个房
间的 create() 只有当 reset时才会被呼叫到,而 init() 则是在 B物件进入到 A
物件时都会呼叫到 A物件的 init() 。看到这,你应该可以看出差别了,我们希望
当一个物件(此处较多是玩家)进到一个房间时,能够经由某个动作启动这个房间
的机关的话,自然是利用 init() 来编写。

一般的使用方式,是在 init() 中利用 add_action() 来呼叫你写的函式,其
格式为:
add_action("function type", "action");

function type 即是被呼叫的函式名 action 是启动的动作

而你就可以将被 action 启动後要发生的事,都写在被呼叫的函式里面。理论
上来说,利用这个方式我们可以做到任何事,当然,能不能达成就看写程式的功力
了。下面举个简单的例子:

void init()
{
add_action("do_pick", "pick");
}

int do_pick(string arg)
{
object me;

me = this_player();
if ( !arg || ( arg != "flower" ) ) return
notify_fail("你要摘什麽?\n");

else if ( random((int)me->query("kar")) < 7 )
message_vision("$N将花摘了下来,但一不小心被刺了一下。\n",
me);

else
message_vision("$N摘下一朵美丽的血红色鲜花。\n", me);

return 1;
}

当玩家利用 pick 这个指令时就会呼叫到 do_pick() 这个 function,而启动了
这个房间的机关。

这里特别提到一点,一个简单的 room 我们为了使记忆体的使用量降到最低,会
在 create() 最後加上一行 replace_program(ROOM); 。这是因为在房间的标准物件
中有定义了如 init() 等其他的函式,而一个简单的房间根本没有用到,所以我们用
replace_program() 来将原本的被继承的标准物件「重置」(或说取代)掉,但是一
旦房间中用到了 init() 来编写时,就绝对不可以用 replace_program(),因为系统
届时找不到 init() 便会随便呼叫一个记忆体中的位址而随便传进一些乱七八糟的东
西,情况严重时,甚至可以让整个 mud crash。但是,我们自不可因噎废食,该用的
时候还是要用,这些应该是一个好的程式写作人员自己必须留意的,发生状况要自己
负责。

三、建议

这里我们提供了一个工具来让巫师们可以方便的编写一个房间,那就是房间编辑
器(Roommaker) ,你可以 clone /obj/roommaker 来使用它。一般的步骤是,先利用
mkroom来造一个空房间,然後利用 goto 这个指令到房间里去,再用 rset short 和
connect 来设定这个房间的短叙述及出口,而像其他的一些属性例如 outdoors 等等
也都可以利用他来做到,接著用 to rset long 来设定这个房间的长叙述,最後再用
saveroom将这个房间存档。要是这只是一个基本的房间,那到这里就大功告成了,要
是□想让这个房间富有变化,那就再用线上编辑器 edit 或将这个房间的档案 ftp
回去继续修改。

Subject: room的属性 (fwd)

/doc/build/room_pro

□ 房间属性

"short" (string)

房间的短叙述。

"long" (string)

房间的长叙述。

"item_desc" (mapping)

房间中个别景物的叙述,格式为:([ <景物名称>:<景物叙述>, …. ])。
其中<景物叙述>可以是字串或 function type。

"exits" (mapping)

房间的出口,包括有门的方向,格式为:([ <出口>:<房间档名>, …. ])。

"objects" (mapping)

房间中的物品、生物,格式:([ <物品或生物档名>:<数量>, …. ])。

"outdoors" (string)

房间是否为「户外」,户外房间可以看到天色变化与气候影响。字串的意义
表示房间的气候区,通常和该区域的 domain (即 /d 下的目录名称) 同。

"no_fight" (int)

房间是为禁止作战区域。

"no_magic" (int)

房间是为禁止施法区域。

**************************************************************************************
***********************************************************************************

1。LPC入门(上)


LPC就是我们用来写MUD的语言啦,它的语法和C 基本一样。它独特之处在于有简单的
OOP特性(简单但很有用:PP),还有一个C里面没有的HASH表的类型:MAPPING
LPC和C还有一个不同是其主函数是CREATE()而不是MAIN()。Create()别写错哦:PP

LPC里面主要的(也是写MUD所足够的)数据类型有int,string,mapping,object,
mixed。下面主要讲一下这些类型了。

因为整数类型对于写MUD已经足够,所以不用FLOAT了。同样的,因为我们的
汉字是双字节的,所以CHAR类型其实也没用,只需要STRING 类型就可以了。
STRING的定义,这里要提一下:string常量的赋值,假如是常量的话可以只用
“连接”的办法代替string,例如:
string str = "我" "们" ;那么结果是str == "我们"
同样的str =
"我"
"们";也是一样,空格与换行在LPC编译时是被忽略的,所以我们
写MUD的时侯不仿多些TAB和换行,这样程序容易看些。
当然,除了直接连接之外还可以用 + 连接。在有变量的时侯就要用了。例如:
string str0 = "我们";
string str1 = "和"+str0+"大家";
结果是str1 == "和我们大家"

mixed是一个比较特别的类型。Mixed 类型的变量可以赋任何其他类型的值。
这在未知变量类型的时侯非常有用。不过一般情况下很少会用到mixed。

LPC里面没有“指针”的概念。在变量名前面加 * 的定义表示数组。如int *a
表示a 是整数数组。一般来说我们定义数组时是未知其大小的。所以定义时不用象
C 那样给定大小。数组和MAPPING有些类似,所以将在下面和MAPPING一起讲它们
的操作。

**************************************************************************************
*********************************************************************************

LPC入门 (中)


LPC里面没有“指针”的概念。在变量名前面加 * 的定义表示数组。如int *a
表示a 是整数数组。一般来说我们定义数组时是未知其大小的。所以定义时不用象
C 那样给定大小。数组和MAPPING有些类似,所以将在下面和MAPPING一起讲它们
的操作。

object, 是OOP概念了,在LPC里面好象有CREATE()的都可以做object 类型变量
了。Object 我们称为“对象”,在MUD里就是一件物品,一个房间或任何一个“具
体”的东西,都是OBJECT。“对象”,在OOP中是一些数据与基于这些数据的函数的
集合(好象文诌诌的? :PP)嗯,object 中的数据一般不能直接操作(至少在LPC
里面不能的 :PP),所以对object的操作只有赋值(对object类型的赋直 )和执行
object的函数( private函数不能被外部调用 )。
函数调用格式:
eg. Object ob;
ob->test(1,2);

基本格式: object类型变量名->函数名(函数参数列);
其中若该object 中未定义该函数名的函数则返回 0 值(呵呵,不会有出错信息的哦,
所以千万别写错名字了)。

写了这么多终于写到LPC 最有特色的两个类型了,mapping和数组。
mapping和数组在“外观”上有些类似,所以在一起写了。前面提到过:mapping是
散列表,具体如何这里不详述了,只希望大家一定要记住mapping的格式!!( 实际
上这格式只在给变量赋初值时用到 )mapping 格式如下:
eg. Mapping a = ([ "ab" : 1 ,
"cd": 2 ,
])
标准格式:
mapping 变量名 = ([
key1 : value1 ,
key2 : value2 ,
……….
……….
]);
其中key可以是除了int以外的任何值!! (好象char也不行吧 :P ),包括任何数组
甚至mapping也可以做key ,而value则可以是任意所有值。Mapping的应用在于:
可以用key来index得到相应的value值。如上面eg的,我们有:a["cd"] == 2,….
因为要用key来index的关系,在mapping中key值不能相等,若相等则覆盖掉原来该
key对应的value。写的有些乱了,SORRY :P

那么一个mapping怎么改变它的值呢?有两个方法(下面设mapping map )。
1. Map[key] = value;
2. Map += ([key : value ]);
请大家留意第二种赋值方法,它跟我们将要提到的数组的方法一样的 。
在mapping中“删除”一个key (其相应value当然也没了)方法是:
map_delete(map,key);
lpc里面的系统函数(efun)的命名一般按参数顺序来取名( map_delete的参数就是

map在前,被delete的key在后的 ),希望大家注意。
另外mapping的efun还有values,keys,undefinedp
大家可以直接在MUD里 help efunname 来看帮助,也可以参阅 /doc/lpc/types/mapping
这一文件
                   尊重作者 转载请注明出处52mud.com

【内容导航】
第1页: 第2页:wiz编程杂谈(1)
收藏 推荐 打印 | 录入:sbso | 阅读:
相关内容      
本文评论   [发表评论]   全部评论 (0)
内容推送
52mud提供
一起回忆泥巴游戏QQ群68186072
52mud官方微信公众平台
热门评论