[脚本教程之五]Sphere脚本的语法详细讲解

看起来学写Sphere的脚本真的是很有趣而有充满成就感,但是学习任何一门语言都要以这样的顺序来进行:
基本变量
特殊变量
基本语句语法
循环和判断
函数
菜单
…
我看有些网站上大都流传着Belgar的那篇大作”Mini tutorial for newbie scripters”无论是中文版还是E文版,反正看得我是一头雾水,不知道从何学起。更有的一些网站和BBS上面贴满了Item变量、Command命令大全、Triggers触发大全等等之类的文章,我从玩TUS的时候就开始看,到现在也没有看明白到底这些东西该怎么用,这无疑指引我们一些初学编程写脚本的人走向了一个误区,任何一个人在学习写脚本的时候可能会很快掌握一个ITEM(物品)或NPC(非玩家角色)的定义,但一些函数和高级的应用,有想法却写不出来,因为他们的语法基础是非常脆弱,以至于经常会犯一些莫名奇妙的错误,我自己有时候也犯这样的错误,而这些错误往往对服务器来说又是非常的致命的。下面让我们一起来研究下sphere变量和高级变量吧,在学习中,如果涉及到非常多的资料,我会将相关资料对应的贴到论坛上,作为手册类资料备查。在我们学习完基本变量和语句之后,会根据我前面所提到的8大类脚本,来分别予以详细介绍。

一、基本变量
变量在编程里面意思是一个可以灵活变化多次赋值的变化的参数,比如一个角色变量name,你可以让他等于一个任意数,我们看下面的语句:
NAME=#NAMES_OGRE the Ogre
NAME=test
NAME=Mage
…
这里面的NAME就是变量,后面的字符串就是数值。
(一)、数值
让人高兴的是,SPHEREv55i脚本没有象C语言那么多的数值类型让我们来运算,反而拥有着数以千计的变量以及类型。我们经常能用到的只有六种类型的数值:
1、十六进制数(Hexadecimal) 以0开头 如:COLOR=0387

2、十进制数(Integer) 非0开头 如:DAM=34

3、字符型值(String) 由字符组成 如:DEFNAME=i_gold

4、字符串值(String Array) 由字符串组成 如:Message “Double click”

5、随机数 由一些随机域 如:VAR.Tempx=RAND(5)
数组或随机函 Magery={140.0 160.0}
数组成 ITEM={ random_jewel 1 0 1 }

6、逻辑数(Boolean) 由逻辑函数或 如:IF<SRC.NPC>
真假值代表构成 TWOHANDS=N
数的取值一般可以由小数、正整数和负整数来构成
(二)、基本变量
Sphere的变量是我所接触过的编程语言中使用最为灵活的一种,你可以随意为一个变量赋值,因为所有的物品、地图定义、NPC的基本的一切内容都是由这些变量构成,你只要给这些变量赋一个规定范围内的数值,那么这被赋值对象就会变得有声有色。根据我们使用和接触的范围,我们可以把Sphere的变量分为下面几种:
1、Item物品类变量
如:ATTR 表示物品所具备的属性

2、PC/NPC角色变量
如:BRAIN 表示角色的类型

3、Account账号变量
如:LASTCONNECTTIME 表示账号的最后连接时间

4、Regions区域变量
如:RECT 表示区域的起止范围

5、Sector环境变量
如:LIGHT 表示天气的明亮程度

6、Server服务器变量
如:VERSION 表示服务器版本

7、Skills技能变量
如:MAGERY 表示魔法技能

二、特殊变量
这些变量在不同的环境下表示不同的内容,所以称之为特殊变量,也有一些变量是由我们利用相应的语句来定义的。它们包括:
MORE1,MORE2,MOREX,MOREY,MOREZ,MOREM
TDATA1,TDATA2,TDATA3,TDATA4
LINK
VAR, TAG
EVENTS, FUNCTION
ARG
所有的这些变量的意义和描述我们会在后面的资料整理中详细说明。

三、基本语法及书写规范
写到这里,我想了好久,因为我实在想不出来SPHERE脚本有什么特殊的语句,因为Sphere的脚本大多是由命令函数、触发事件、变量+赋值、多个片断的定义来组成的一个个脚本文件,除了一些基本的循环和逻辑判断语句外,我整理了一些,严格意义上来说并不能算作语句的语句如下:
1、[XXXXXX] 语句段开始和结束标志
一个物品或NPC或其他的完整的定义,在Sphere里面以这样的形式来表示,X表示任意变量或定义语句,Sphere在解读这样的句子时,把从到这个标志和下一个标志之间视为一个部分。
如:[ITEMDEF 0eed]
[CHARDEF c_test_npc]
[Function f_testfunc]
[EVENTS e_testevent]
[HELP FAQ 36]
[AREA Field]
[COMMENT MENU MENU_ADMIN]
[MENU MENU_PAGEGM]
[Spell 0]
…
2、[EOF] 文件结束标志
一个脚本文件必须以[EOF]结尾,这样的标志被Sphere认为是有效结束标志。任何没有[EOF]为结束标志的脚本文件,可以被系统加载运行,但这样的错误会带来其他相关的一些可怕的后果,这类错误都会被我们认为是不可原谅的错误。

3、<XXXXXX> 表示一个有效的返回值
当给一些变量赋某个数值的时候,你可以把一个变量的值转移赋值给另外一个变量,这时候我们要把这个变量用<>括起来。
如:HITS=<SRC.STR>
如果是HITS=SRC.STR,这即是错误的写法

4、SRC 源目标指针
一个事件的发起者,玩家开始的行为等,比如我双击石头,让石头触发了一个Dclick事件,这时候我就是这个事件中的发起者,亦即“源”,使用的时候,在其后加”.”,然后跟相关的命令函数。
如:
ON=@DCLICK //双击的事件触发
SRC.SAY “hi” //在我的头上显示hi
RETURN 1 //返回一个真值
其实这个内容我应该放到一个指针的介绍里面,但由于Sphere的指针比较少,且应用比较频繁,所以放到这里一并介绍了。

5、ACT 当前激活的目标指针
一个事件的当前目标,比如我双击一个石头,我是源……SRC,那么石头就是当前事件的目标……ACT,这个指针同样和SRC一样的用法。
如:
ON=@UserDclick //双击事件的触发开始
ACT.SAYU “我是目标” //被双击者头上显示”我是目标”
SRC.NEWITEM = I_GOLD //源添加一个I_GOLD物品
SRC.ACT.AMOUNT= 5000 //源的当前激活目标即I_GOLD的数量设为5000
SRC.ACT.BOUNCE //把源的当前激活目标放到包里面

6、TARG 最终目标指针
一个行为动作或事件的最终指定目标,比如我使用Harm魔法,会出现目标圈定框,这时候选中的就是TARG。
如:
ON=@TARGON_ITEM //当目标是个物品
IF ( <SRC.TARG.TYPE> == t_bone ) //如果目标物品的属性是t_bone
MESSAGE You lack the skill to make bone armor. //提示信息
RETURN 1 //结束当前的动作
ELSE
RETURN 0// 返回0,继续进行前面的动作
ENDIF

7、CONT 容器或所有者指针
一个物品的所在容器或者所有者,如我装备了一把宝剑,这时候我就成了这个把剑的容器和所有者。容器类物品或者玩家、NPC都可以使用这个指针,东西在箱子里面,人骑着马,或东西在npc的包里面,CONT就是指向包容这些物品或动物的箱子、NPC、玩家等等。下面是一个头发的代码
如:
ON=@TIMER
if !<cont> // 如果没有容器类物品或生物
return 0 //返回0值允许头发到时间消失
endif
if <cont.brain> // 如果是NPC不是玩家
return 1 //返回1
endif
cont.newitem=i_hair_LONG //在这个头发的所有者或容纳者身上添加个物品
cont.act.color=<cont.findlayer(layer_hair).color> //头发颜色和原来的 //颜色同,此时ACT,指向当前活动的目标头发
cont.act.more=1 //设置more为1
cont.equip <cont.act.uid> //装备头发
return 1 //结束返回1

8、ON= 触发语句
任何sphere的触发条件都要在使用的时候在前面加上”ON=”,当sphere服务器读取到这个句话的时候,就会激活后面所提供的触发条件,任何满足这个触发条件的都会执行下面的代码直到下一个有效的标志,这个比较简单,应用也最为广泛。
如:
ON=@UserDClick //双击触发99L版本以后把Click改成了UserDClick
ON=@TIMER //时间计时触发
ON=@EQUIP //装备触发
…
还有一种应用是语言触发,如:
ON=*job*
ON=*work*
ON=*what*do*do*
ON=*profession*
ON=*occupation*
…

9、”//” 注释
前面好象提过了,//所在后面的行语句不生效
如:
//此句是注释作用,不生效

10、”变量=值” 变量赋值
给变量赋值用”=” 后面的可以是前面所提到的符合要求的任何数值
如:
TIMER=0
MOREP=0,1,3
MORE2=0
ATTR=attr_move_never|attr_invis
MORE={C_M_SKELETONARCHER 1 C_M_MUMMY 1 C_M_LICHE_LORD}

11、”.” 指针所指向对象的任何行为或事件
.前面是指针,后面是任何语句或函数、命令、赋值语句等
如:
ACT=<SRC.UID>
或下面语句是一个房子契约双击后放到地上的触发:
ON=@Targon_Ground
IF (<EVAL <SRC.FINDID.i_house_placement_memory.UID>>==0)
SRC.NEWITEM i_house_placement_memory
SRC.ACT.CONT <SRC.UID>
SRC.ACT.LINK <UID>
SRC.ACT.MORE <BASEID>
SRC.ACT.USE
RETURN 0
ELSE
SRC.FINDID.i_house_placement_memory.MORE <BASEID>
SRC.FINDID.i_house_placement_memory.USE
RETURN 0
ENDIF

12、”( ” 和”)”
对于Sphere的括号,应用的方式比较少,一个是IF或ELSEIF后面的判断条件,另外一个是用于括负数。还有一个是函数后面的值,至少其他地方我还没有见过
如:
if <sector.isdark> || (<flags>&(statf_nightsight|statf_indoors))
if ! <tag.lightstr>
return 0
endif
这是一个事件[EVENTS e_Undead]中的ON=@EnvironChange(环境变化触发,如亮度、下雨、下雪等)触发定义。
再如:
SRC.DAMAGE=<MORE>+(-<MORE2>) //more已经赋过值
SRC.HITS=<SRC.HITS>+(-5) //负数最好这样括起来

随机函数的应用:
IF RAND(10)==5

13、”{“和”}”
在Sphere脚本里面,和}中的内容表示一个随机数的范围或者随机数的取值方式。系统会根据{}内所提供的方式选择一个随机数并赋值给指定的变量。
如:
SWORDSMANSHIP={50.0 70.0}
PARRYING={45.0 60.0}
MAGICRESISTANCE={45.0 60.0}
TACTICS={50.0 70.0}
FAME={100 5000}

ITEM={ poor_gold_pile 1 backpack_poor 1 pouch_poor 1 }
ITEM={ random_bread 1 0 1 }

14、” ” 引号
用于表示一个字符串
如:
SRC.SAY “You fail to ignite the campfire”

15、”,”逗号
用于一些特殊的语句里面,比如坐标的隔点、不同物品间的普通间隔等等
如:
ADV_RATE=10.0,200.0,800.0
SHELTER=r_caves,r_dungeon
ITEM=TTM_LVL3,R99
DAM=3,15
ITEM=average_gold_pile,{1 3}

16、”|” 分割号
这里面讲解的意思不是逻辑运算符号中的”|”,是作为间隔号,在一些特殊的应用环境中。
如:
CAN=MT_USEHANDS|MT_WALK //表示NPC即可以用手,也可以走

17、其他的一些运算符号

+ 加 如:SRC.HITS=<SRC.HITS> + { 10 1 15 5 20 1 }
& 二进制与 如:if ( <flags>&statf_conjured)
| 二进制或 如:flags=<flags>|statf_conjured
= 赋值 如:SRC.DAMAGE={10 60}
== 条件或表达式等于 如:IF <SRC.OSKIN> == 020
! 逻辑非 如:IF ! (<SRC.OSKIN>==038a)
!= 不等于 如:IF ( <LINK.TOPOBJ.UID> != <SRC.UID>)
&& 并且 如:IF (<hits> <200)&&(<eval RAND(3)> == 1)
|| 或者 如:IF (<COMPLEXITY.HIGH>||<COMPLEXITY.MEDIUM>)
> 大于 如:IF ( RAND( 6 ) > 3 )
< 小于 如:IF ( RAND( 6 ) < 3 )
<= 大于等于 如:if ( <src.tinkering> <= 80.0 )
>= 小于等于 如:IF(<eval<account.TotalConnecttime>> >= 7200)

具体的一些运算符号的使用方法我们在以后使用的时候再介绍

Hmm….,让我们看看,还有哪些了?暂时想不起来那么多了,有遗漏的以后慢慢补充,也欢迎所有朋友补充。

四、条件判断和循环

1、条件判断语句
合理恰当的使用条件判断语句是非常有意义的,但应用不规范也会给系统带来非常大的麻烦。常用的Sphere条件判断语句及格式如:
格式一: IF(条件) //如果条件成立执行下面语句,否则执行ELSE后面
…
语句部分
…
ELSE
…
语句部分
…
ENDIF //结束条件判断

格式二: IF(条件) //如果条件成立执行下面语句,否则执行ELSEIF后面
…
语句部分
…
ELSEIF //上一个条件不成立,再次判断本条件,成立执行下面语句
…
语句部分
…
ELSE //ELSEIF的条件不成立,跳过上面代码执行下面语句
…
语句部分
…
ENDIF //技术条件判断

格式三:条件嵌套
IF(条件)
IF(条件)
…
语句部分
…
ELSE
…
语句部分
…
ENDIF

ELSEIF
…
语句部分
…
ELSE
…
语句部分
…
ENDIF
其实这类的嵌套用法没有办法统计到底有多少种,因为每个人都会根据自己的不同来合理运用这个条件判断,但有一条的原则非常的重要:
每一个IF语句必须有ENDIF来一一对应,否则,后果是不堪设想的……死循环?当机器
条件可以是运算后或直接的值,可以是表达式,可以是函数。

2、循环
和许多编程语言一样,Sphere脚本也有着丰富的循环语句,但遗憾的时候很少看到这样的应用,相比较来说,Sphere脚本的循环更象是一个随机数选择函数,下面分别就常用的简单介绍一下。
1、 DOSWITCH <variable>


ENDDO
这个有些类似C++里面的switch( ),如果DOSWITCH后面的变量是几,就执行对应的循环体内的第几行语句。
如:
MORE={0,2} //赋MORE一个随机值
DOSWITCH <MORE>
SRC.SYSMESSAGE MORE is 0! //如果MORE=0执行此句
SRC.SYSMESSAGE MORE is 1! //如果MORE=1执行此句
SRC.SYSMESSAGE MORE is 2! //如果MORE=2执行此句
ENDDO

2、DORAND #


ENDDO
和DOSWITCH不同的就是#只能是0开始的一个数字,执行的时候,会随机选取一个数,并读取对应的循环体内的语句行
如:
DORAND 7
SAY Might I help thee?
SAY Get gone from here.
SAY I don’t deal with thy kind.
SAY Yes?
SAY What?
SAY Hello.
SAY What’s thou need?
ENDDO

3、 BEGIN


END
一个非常有用的括号,无论你在这里括号里面放多少行语句,系统随机只读去一句,和前面提到的两个循环语句搭配适应非常有效。
如:
DOSWITCH <MORE>
BEGIN // 将下面两个句子视为单行的,当变量<MORE>==0时候
SRC.SYSMESSAGE First line MORE == 0
SRC.SYSMESSAGE Second line MORE == 0
END
SRC.SYSMESSAGE MORE = 1
SRC.SYSMESsAGE MORE = 2
ENDDO
其他的一些循环函数几乎很难看到使用的例子,如:for, forobjs, forchars, foritems OR, ENDFOR, FORITEM, FORCHAR, FOROBJS, STRCMPI, STRCMP, STRASCII, RANDBELL

和IF 与ENDIF 必须要一一对应一样,任何上面提到的三种循环语句都必须和END或ENDDO一一对应,否则同样会出现main loop这类的致命严重错误。

五、函数
可以这样理解,函数就是命令,我们所用的一些命令和语句,几乎都是Sphere官方提供的一些类似C语言中的库函数,我们同样可以定义自己的函数和函数变量。格式为:
[FUNCTION 函数名]
…
RETURN返回值
如:
[FUNCTION GoHome]
SRC.GO Vesper

[FUNCTION f_test_rand_ret]
return <eval.rand(5)>
这个具体的编写方法很简单,但应用非常之灵活,以后会在学习中慢慢体味。

六、菜单、对话框
一个良好的界面和菜单,图符等等,都会给人以很舒服的感觉。这里先简单介绍下菜单和对话框的写作格式,以后专门加以介绍。
1、菜单的写作格式:
[MENU 菜单名]
菜单描述内容
ON=0 菜单选项描述一
本选择项被选择后执行的语句
ON=0 菜单选项描述二
本选择项被选择后执行的语句


一个简单的三个选择项的菜单例子
[MENU M_TASKMENU]
Please enter your choice

ON=0 Go and visit
src.go 5211,1759

ON=0 Go and Kill
src.go 5222,1731

ON=0 Show my name
SRC.EFFECT=3,0373A,6,15,1
SRC.SOUND=SND_SPELL_PROTECTION
SRC.SAY My name is: <src.name>

2、对话框的写作格式:
[DIALOG 对话框名]
对话框界面定义语句
…
[DIALOG 对话框名 TEXT]
对话框文本定义
…
[DIALOG 对话框名 BUTTON]
对话框按钮选择后执行语句
…

下面是个履行对话框的定义
[DIALOG d_TravelTown] //TOWNS
0, 0// 开始显示的坐标
resizepic 0 0 3600 215 200
page 0
text 40 17 0 0
text 40 37 1152 1
text 40 57 1152 2
text 40 77 1152 3
text 40 97 1152 4
text 40 117 1152 5
text 40 137 1152 6
text 40 157 0 7
button 20 40 1209 1210 1 0 1
button 20 60 1209 1210 1 0 2
button 20 80 1209 1210 1 0 3
button 20 100 1209 1210 1 0 4
button 20 120 1209 1210 1 0 5
button 20 140 1209 1210 1 0 7
button 20 160 1209 1210 1 0 6

[DIALOG d_TravelTown TEXT]
Which Town?
Britain
Serpent’s Hold
Cove
Vesper
Bucaneer’s Den
Papua
Previous

[DIALOG d_TravelTown BUTTON]
ONBUTTON=0
SYSMESSAGE=Menu Aborted
ONBUTTON=1 //BRITAIN
SRC.GO 1427,1697,0
ONBUTTON=2 //SERPENTS HOLD
SRC.GO 3009,3363,15
ONBUTTON=3 //COVE
SRC.GO 2264,1202,0
ONBUTTON=4 //VESPER
SRC.GO 2892,686,0
ONBUTTON=5 //BUCANEER’S DEN
SRC.GO 2733,2160,0
ONBUTTON=6//PREVIOUS
SRC.DIALOG d_Travel
ONBUTTON=7//PAPUA
SRC.GO=5726,3205,-3

这里面要注意的就是你的TEXT选项必须和TEXT语句行一一对应,否则会非法,具体的语句介绍,我们以后再详细说明。

七、其他的一些世界定义,房屋设计等等,以后专门介绍

OooOOOoOOo,终于写完了这篇语法的介绍,不知道你看完了后有什么感受,反正我的手现在是酸酸的。最后说一句,养成良好的书写和命名规范是非常重要的,有助于你调试脚本的时候更加快捷。其实这个是废话,任何语言都是这样要求的。
比如定义ITEM物品脚本,用I_开头,如I_TASK_ITEM
定义NPC角色脚本,用C_开头,如C_TASK_CHAR
定义菜单名字,用M_开头,如M_TASK_MENU
定义对话框名字,用D_开头,如D_TASK_DIALOG
定义函数名字,用F_开头,如F_TASK_FUNC
定义事件名字,用E_开头,如E_TASK_EVENTS


这样你的脚本可读性就是非常的好了。

留言

还没有留言,来坐个沙发吧。

留个言

留个言