[脚本教程之十五]如何编写NPCs及EVENTS事件的脚本

[十五]如何编写NPCs及EVENTS事件的脚本
前14篇教程到现在这篇,整整搁置了近半年,真是让我惭愧,这其中出现了太多太多的事情,最让我沮丧的是本来已经写好的15和16篇因笔记本硬盘损坏而丢失,导致教程的整理搁浅,也感谢众多热爱UO的和热爱SPHERE脚本编写的玩家和朋友们对我的信任和支持,在今后的脚本整理过程中我会尽我最大的努力把自己对UO的理解和对脚本编写的体会全部奉献给大家,以便能够让更多的人热爱这个虚拟的世界,和我们一起分享她带给我们的快乐,我想这也是大多数优秀UO站点的Staffs们的共同愿望吧… ….几天前的不幸遭遇让我在鬼门关前go了一圈,更加感受到生活在这个世界上的对生存的意义的深深体会。尽管现在躺在病床上的我很无助也很无奈,但我的思绪仍旧没有停止,我的右手还可以动,信息化时代的便捷让我可以从容以笔写的方式来继续这篇教程。。。
一、如何编写NPCs的脚本
写NPC的脚本是件比写物品脚本还有趣的工作,当你看到自己设计的NPC穿着你为他设计的服装和语言以及充满灵气般站在你的面前的时候,是件非常让人兴奋和成就感的事情。记得我曾经在Jarry站修改过一个四处收集过来模仿NPC的脚本,带给大家的是非常快乐的回忆。可以想象一下这样的场面:
在Britain Bank的旁边,一个提着灯笼的NPC在四处游荡,忽然一个衣着入时的PLMM和PLGG出现在他面前,这个NPC忽然变成了和PLGG一摸一样的同样名字的人,于是PLMM头上出现了若干个”?”和”!”,PLGG愤怒起来,大声说道”!!!靠,这是什么?”
哈哈,是不是很funny啊?!今天让我们就以这个脚本为例,和大家探讨一下NPC的脚本的编写。
SPHERE的NPC脚本和物品脚本一样,SPHERE读取脚本的时候,把一个[CHARDEF C_XXXX]这样的语句认为是一个NPC的定义,C_XXXX可以是你任意指定的一个NPC的ID,同样可以用16进制数字来替代。比如是[CHARDEF C_TEST_NPC]这样语句,在游戏里面你就可以用”.ADDNPC C_TEST_NPC”这样的命令行来添加他。前提是这个C_XXXX不可以重复。
更多的时候,我认为SPHERE的脚本不能成为编程,应该说是一个填写表格而已,等于这个表格的行、列名字系统已经帮你命名好并填好了,你只要填写对应的数据就行了。
幻想一下这样的表格:


|| 变量 || ITEM || NPCS ||


|| NAMES || I_Custom_dye || C_Custom_man ||


|| ID || I_dye_tub || 0190 ||


|| CATEGORY || Custom Items || Custom npcs ||


|| … || … || … ||

黑体部分为系统内定的,也就是我前面几个教程所说的那些变量和参数,这些变量和参数分为前面所说的几个大类:角色类、物品类、服务器类等等。其他的则需要你填写的,只是要写成一行行的脚本。而你所填写的就是这些变量或者参数的值。OK,让我们来填写一个NPC的表格吧:

[CHARDEF C_Test_Clonenpc] //NPC定义开始标记,C_TASK…后面的表示NPC的ID
ID=C_MAN //该NPC所具备的外形形态,外形为人
NAME=#NAMES_HUMANMALE the Clone Man //NPC的名字和TITLE,#NAMES_HUMANMALE是一个
名字的序列,详细列表可以参看spherename.scp里面的定义,系统会随机读取里面的名字。
CAN=MT_WALK|MT_RUN|MT_USEHANDS|MT_EQUIP //NPC具备的能力,详细参考角色及NPC变量
DAM=25,40 //NPC攻击玩家成功的时候伤害值的范围。
ARMOR=70 //NPC的防御等级
TSPEECH=spk_human_prime //NPC的谈话触发
TSPEECH=spk_human_default
TEVENTS=e_Custom_CloneAI //NPC的事件触发,这里面是单独定义了一个EVENTS序列。CATEGORY=Custom Npcs //NPC在AXIS里面SPAWNS属性页里面显示的种类名字
SUBSECTION=Boss NPCs //NPC的AXIS里面SPAWNS属性页里面显示的子类别
DESCRIPTION=Clone NPCs //NPC的AXIS里面SPAWNS属性页里面显示的名字

ON=@Create //NPC在被创建的时候触发
NPC=BRAIN_HUMAN //NPC的头脑类型
COLOR=083f3 //NPC的身体颜色或者用BLOODCOLOR表示血的颜色
FAME ={2000 4000} //NPC的FAME名望值
KARMA={-4000 -5000} //NPC的KARMA善恶值
STR={257 400} //NPC的STR力量值
DEX={254 572} //NPC的DEX力量值
INT={1476 1573} //NPC的INT力量值
wrestling={110.0 130.0} //NPC的拳术技能值
Magery={100.0 160.0} //NPC的魔法技能值
tactics={150.0 170.0}
PARRYING ={90.0 119.0}
ITEMNEWBIE=i_hair_long //NPC的头发类型
COLOR={0482 0498} //NPC的头发颜色
ITEM=i_platemail_gloves //盔甲,创建后NPC会自动装备,前提是具备MT_EQUIP能力
ITEM=i_platemail_arms //盔甲
ITEM=i_platemail_gorget
ITEM=i_platemail_chest
ITEM=i_platemail_leggings
ITEM=random_coin_purse
ITEM=i_mt_ostard_forest //NPC的坐骑

ON=@NPCRESTOCK //NPC的背包里面的物品,死后可以loot的物品,对于店员NPC的BUY和
// SELL的物品必须放在这个触发后面,想让NPC死后可以从身上LOOT
//指定物品可以放在这里触发语句后面。NPC每次刷新的时候都会触发

ITEM=i_gold,{500 800} //物品类型及数量
ITEM=RANDOM_JEWEL //物品类型及数量
ITEM={ RANDOM_WAND_FIVE 1 RICH_GOLD_PILE 1 RANDOM_JEWEL 1 RANDOM_WEAPON 1 }
ITEM={ random_jewel 1 0 1 } //物品类型及数量

这样一个NPC的脚本就算写好,之后你再定义一下e_Custom_CloneAI,因为这个是我们自己定义的,也就是所谓NPC的特定的AI,这个需要我们在定义EVENTS事件脚本中详细定义。同样,你也可以把EVENTS中的内容放在NPC脚本后面,只是这样作是为了该事件内的脚本可以重复被多个NPC调用而不会造成脚本过多,从而提高脚本运行的效率。
e_Custom_CloneAI中的内容详细见下面的说明。你可以把这段脚本放在任意一个SPHERE里面带的脚本里面或者自己定义的文件扩展名为.SCP的文件中,但最好不要放在一些特殊的脚本文件里面,比如spheremap.scp、spheredefs.scp、speretables.scp等几个文件里面,因为一方面再刷新的时候会有影响,另一方面在系统读取的时候同样也会报错,我建议您在写这类的脚本的时候最好自己建立一个文件名字(这在sphere55i版本以后使用)
让我们再看一个店员NPC和骑宠的脚本:
下面是一个铁匠铺的NPC,可以出售一些铁匠工具类物品

[CHARDEF 0557] //NPC定义开始标记
DEFNAME=C_H_BLACKSMITH_F //在ADDNPC的时候,C_H_BLACKSMITH_F等同于0557
NAME=#NAMES_HUMANFEMALE the Blacksmith //同上一例的说明
ID=C_WOMAN //NPC的外形
DESIRES=i_gold,e_notoriety //NPC喜欢的物品
AVERSIONS=t_TRAP,t_eerie_stuff //npc讨厌的类型

TSPEECH=spk_human_prime //NPC的谈话触发
TSPEECH=jobBlacksmith
TSPEECH=spk_shopkeep
TSPEECH=spk_needs
TSPEECH=spk_rehello
TSPEECH=spk_human_default

TEVENTS=e_Human_HearUnk //NPC的事件触发序列
TEVENTS=e_Human_Needs
TEVENTS=e_Human_ConvInit
TEVENTS=e_Human_Greet
TEVENTS=e_Human_Space
TEVENTS=e_Human_Refuse
TEVENTS=e_Human_Environ

ON=@Create //NPC创建的时候触发
NPC=brain_vendor //NPC的头脑类型
COLOR=colors_skin //NPC的皮肤颜色
STR={86 100} //NPC的STR属性值
DEX={66 80}
INT={61 75}

MINING={35.0 55.0} //NPC的技能值
ARMSLORE={65.0 88.0}
BLACKSMITHING={55.0 78.0}
FENCING={35.0 55.0}
PARRYING={35.0 50.0}
SWORDSMANSHIP={35.0 50.0}
WRESTLING={45.0 68.0}
MACEFIGHTING={35.0 50.0}
TACTICS={35.0 55.0}

ITEMNEWBIE=random_female_hair //npc的头发
COLOR=colors_hair

ON=@NPCRestock //NPC刷新的时候触发
ITEM=RANDOM_LIGHT //物品
ITEM=i_shirt_plain
COLOR=colors_all
ITEM=random_skirt
COLOR=colors_all
ITEM=i_apron_full
COLOR=colors_all
ITEM=i_boots_calf
COLOR=colors_neutral
ITEM=random_weapon
ITEM=random_coin_purse

SELL=VENDOR_S_ARMORER_RING //卖的物品的模板清单
SELL=VENDOR_S_ARMORER_CHAIN
SELL=VENDOR_S_ARMORER_PLATE
SELL=VENDOR_S_ARMORER_SHIELDS
SELL=VENDOR_S_WEAPONS_BLADED
SELL=VENDOR_S_WEAPONS_BLUNT
SELL=VENDOR_S_BLACKSMITH
SELL=VENDOR_S_COLOURED_ARMOR
SELL=VENDOR_S_MAGIC_ARMOR
SELL=VENDOR_S_MAGIC_WEAPONS
BUY=VENDOR_B_ARMORER_RING //从玩家手里买的物品的模板清单
BUY=VENDOR_B_ARMORER_CHAIN //这些物品模板可以参考spheretemp_vend.scp里面的相关定义
BUY=VENDOR_B_ARMORER_PLATE
BUY=VENDOR_B_ARMORER_SHIELDS
BUY=VENDOR_B_WEAPONS_BLADED
BUY=VENDOR_B_WEAPONS_BLUNT
BUY=VENDOR_B_BLACKSMITH
BUY=VENDOR_B_COLOURED_ARMOR
BUY=VENDOR_B_MAGIC_ARMOR
BUY=VENDOR_B_MAGIC_WEAPONS

CATEGORY=Civilized //AXIS里面的spawns属性页类别名字
SUBSECTION=Tradesmen //AXIS里面的分类属性页名字
DESCRIPTION=Blacksmith (female) //AXIS里面的显示的名字

再看一个系统自带的一个Mustang野马的脚本:

[CHARDEF 01114] //npc的定义开始标记
DEFNAME=C_A_MUSTANG_BLACK
NAME=Mustang
SOUND=snd_ANIMALS_HORSE1 //NPC能发出的声音,可选清单见spheredefs.scp里面的定义
ID=c_horse_brown_dk //外形
ICON=i_pet_horse_brown_dk //诸如在追踪技能显示出来的小的图标外形
DAM=3,4
ARMOR=9
RESOURCES=15 i_ribs_raw,10 i_hide //死后被解剖的物品
CAN=MT_WALK|MT_RUN
FOODTYPE=55 t_crops, 55 t_fruit, 55 t_grain, 64 t_grass //可以吃的食物类型
DESIRES=e_horses,c_man,c_woman //希望的喜欢的东西
TEVENTS=e_horses //具备的触发事件队列
SHELTER=r_stables,e_Human_Greet //隐蔽地点
AVERSIONS=e_carnivores3 //厌恶的东西和地方
DESCRIPTION=Horse (Black Mustang) //AXIS里面显示的名字
SUBSECTION=Land (Wild)
CATEGORY=Animals

ON=@Create //创建时候触发
COLOR=0455
STR={100 180} //NPC的力量值
DEX={90 130}
INT={6 10}

PARRYING={35.0 45.0} //NPC的技能值
MAGICRESISTANCE={25.0 30.0}
TACTICS={29.0 44.0}
WRESTLING={29.0 44.0}
TAMING=98.0

NPC=brain_animal

FAME=0 //npc的fame值
KARMA={-1 -99}

二、如何编写EVENTS事件脚本
所谓事件脚本,就是一些触发事件的组合,在遇到这些触发条件触发时,可以执行下面的相关语句。对于一些重复的触发代码,我们就可以定义一个EVENTS,这样在需要调用这些触发的地方用TEVENTS或者EVENTS变量调用就行了。
和CHARDEF和ITEMDEF一样,事件的定义标记是EVENTS,上面我们讲解NPC脚本的时候曾经引用了一个e_Custom_CloneAI事件,下面我就把这个事件的完整脚本列出来和大家一起分析一下:

[EVENTS e_Custom_CloneAI] //事件定义标记

ON=@NPCSEENEWPLAYER //看见新玩家的时候触发
IF <SRC.FLAGS>&02 //如果该角色的标记是02即鬼魂
RETURN 0 //结束返回0,继续动作,如果是1就停止执行下面的语句
ENDIF //结束IF语句
if <src.npc> //如果看见的是NPC
return 0 //结束这个判断继续下面的语句
endif //结束IF语句

IF !(<SRC.COLOR>==<COLOR>) //如果看到的对象的颜色和自己的颜色不相同
COLOR=<SRC.COLOR> //颜色和看到的对象的皮肤颜色相同
BODY=<SRC.BODY> //身体外形和看到的对象的身体外形相同
NAME=<SRC.NAME> //名字和看到的对象的名字相同
ENDIF //结束IF判断语句

FINDLAYER(1).REMOVE //删除自己的LAYER(1),关于LAYER可以参考以前的教程里面描述
FINDLAYER(2).REMOVE //左手
FINDLAYER(3).REMOVE
FINDLAYER(4).REMOVE
FINDLAYER(5).REMOVE
FINDLAYER(6).REMOVE
FINDLAYER(7).REMOVE
FINDLAYER(8).REMOVE
FINDLAYER(9).REMOVE
FINDLAYER(10).REMOVE
FINDLAYER(11).REMOVE
FINDLAYER(12).REMOVE
FINDLAYER(13).REMOVE
FINDLAYER(14).REMOVE
FINDLAYER(15).REMOVE
FINDLAYER(16).REMOVE
FINDLAYER(17).REMOVE
FINDLAYER(18).REMOVE
FINDLAYER(19).REMOVE
FINDLAYER(20).REMOVE
FINDLAYER(22).REMOVE
FINDLAYER(24).REMOVE
FINDLAYER(25).REMOVE

IF <FINDID.i_spellbook> //如果发现魔法书
FINDID.i_spellbook.REMOVE //删除
ENDIF //结束IF

IF <SRC.FINDID.i_spellbook> //如果看到对象身上有魔法书
SRC.NEWITEM i_spellbook //添加一本魔法书
SRC.ACT.MORE1=<SRC.FINDID.i_spellbook.MORE1>&06c2a0885 //设置魔法书的内容
SRC.ACT.MORE2=<SRc.FINDID.i_spellbook.MORE2>&0fb576671 //同上,设置为攻击类魔法
SRC.ACT.CONT=<FINDLAYER(21).SERIAL> //设置该物品的容器为自己的背包
ENDIF

IF <SRC.FINDLAYER(1)> //如果发现对象的右手上有东西
SRC.NEWITEM <SRC.FINDLAYER(1).ID> //添加一个相同ID的物品
SRC.ACT.NAME=<SRC.FINDLAYER(1).NAME> //名字相同
SRC.ACT.COLOR=<SRC.FINDLAYER(1).COLOR> //颜色相同
SRC.ACT.MOREP=<SRC.FINDLAYER(1).MOREP> //morep值相同
SRC.ACT.ATTR=<SRC.FINDLAYER(1).ATTR>|04 //属性为不新人属性
EQUIP <SRC.ACT.SERIAL> //装备这个物品
ENDIF //结束IF语句

IF <SRC.FINDLAYER(2)> //同上
SRC.NEWITEM <SRC.FINDLAYER(2).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(2).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(2).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(2).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(2).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(3)>
SRC.NEWITEM <SRC.FINDLAYER(3).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(3).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(3).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(3).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(3).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(4)>
SRC.NEWITEM <SRC.FINDLAYER(4).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(4).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(4).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(4).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(4).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(5)>
SRC.NEWITEM <SRC.FINDLAYER(5).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(5).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(5).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(5).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(5).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(6)>
SRC.NEWITEM <SRC.FINDLAYER(6).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(6).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(6).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(6).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(6).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(7)>
SRC.NEWITEM <SRC.FINDLAYER(7).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(7).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(7).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(7).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(7).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(8)>
SRC.NEWITEM <SRC.FINDLAYER(8).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(8).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(8).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(8).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(8).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(9)>
SRC.NEWITEM <SRC.FINDLAYER(9).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(9).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(9).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(9).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(9).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(10)>
SRC.NEWITEM <SRC.FINDLAYER(10).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(10).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(10).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(10).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(10).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(11)>
SRC.NEWITEM <SRC.FINDLAYER(11).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(11).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(11).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(11).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(11).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(12)>
SRC.NEWITEM <SRC.FINDLAYER(12).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(12).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(12).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(12).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(12).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(13)>
SRC.NEWITEM <SRC.FINDLAYER(13).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(13).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(13).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(13).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(13).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(14)>
SRC.NEWITEM <SRC.FINDLAYER(14).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(14).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(14).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(14).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(14).ATTR>|04
EQUIP <SRC.ACT.SERIAL>
ENDIF

IF <SRC.FINDLAYER(15)>
SRC.NEWITEM <SRC.FINDLAYER(15).ID>
SRC.ACT.NAME=<SRC.FINDLAYER(15).NAME>
SRC.ACT.COLOR=<SRC.FINDLAYER(15).COLOR>
SRC.ACT.MOREP=<SRC.FINDLAYER(15).MOREP>
SRC.ACT.ATTR=<SRC.FINDLAYER(15).ATTR>|04
EQUIP <SRC.ACT.SERIAL>

留言

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

留个言

留个言