当前位置:铁资首页>>上古卷轴>>模组教程>>正文
MOD制作实例教学(四)
文章出处:铁资网  作者:sphinx  发布时间:2005-03-08
 

如何制作谜语和诅咒

本文是我早期翻译,改编的一篇关于脚本的文章。
 
目标:
利用脚本制作出一个谜语箱子,当玩家试图开启该箱子时会被询问一个谜语,只有回答正确才会开启该箱子。如果答错了,玩家将被诅咒,该箱子也不会开启。以下将一步一步的讲解。其间将涉及到一些脚本方面的典型问题,希望对大家有启发作用。
进入脚本编辑窗口
开启官方编辑器(TESCS)内的Edit Script window(脚本编写窗口)。在这个窗口内编写脚本。
为新脚本命名
每个脚本都要有个名字,由Begin命令引导开始,由End命令结束。例如:

Begin my_first_script

这时如果点击save按钮将显示报错信息说需要用end命令结束脚本,所以输入

End

注意,END命令要另起一行。输入END后再点保存就不会报错了。当然,这个脚本不会执行任何功能,因为还没添加内容。
侦测玩家的动作:
这一步,我们需要思考一个能侦测玩家是否试图开启该箱子的方法。通过三方面元素的组合完成:1,物体,这是指游戏中的所有生物,NPC,物品或声音等等。2,功能,这是指所有已有的脚本中的用于执行指定功能的“词汇”,可直接引用。3,命令,这是构成脚本语言的“词汇”,例如前面讲的"Begin"用来告诉编辑器要执行哪个脚本。一般来说如果要某个指定物体执行某个指定功能,按以下格式书写:

物体ID -> 功能, [参数]

其中的“功能”部分可能不包含参数,也可能包含。“参数”部分可以是其他物体的ID或数字等。

对我们要做的谜之箱子而言,要使用 OnActivate 这个功能:这个功能用来告诉编辑器玩家是否“激活”了一个物体。这个功能将回复一个数值,1或0。1代表“真”,0代表“假”。简单的说,如果该物体被激活,即说明玩家对其按了使用键(默认为空格)。那么,我们要做的就是检查OnActivate是否回复了“1”。根据以上思路编写脚本如下:

Begin my_first_script

If ( OnActivate == 1 )
; 这里我们将输入当该箱子被开启时将发生什么
endif

End

额外要解释的是"if"这个命令是专门用来检测条件的。如果其后的条件为“真”,则执行其下的代码段,直到"endif"命令为止。"=="号类似等号,用来检查该符号左边的内容是否与右边的内容一致。在本例中就是指"OnActivate"回复了“1”。与BEGIN和END命令类似,"if"这个命令必须与endif 搭配使用,如果不加endif 将报错。";"号用来引导一个注释内容,这部分内容将不在脚本执行中执行,这只相当于编写者的注释。
编写谜语内容:
现在,我们想要该箱子问玩家一个谜语。通过使用MessageBox功能来显示谜语的内容并显示可供玩家选择的选项。如下:

MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith"

第一个双引号内的内容是谜语,其他的是四个选项。双引号之间的逗号用来告诉游戏将其后的内容显示成按钮的形式。
那么怎样确保该谜语只在玩家第一次试图开启该箱子时询问呢?首先要了解一下脚本是怎样执行的。
本地脚本是如何执行的:
每个与物体或NPC关联的本地脚本都在游戏的每时每刻执行着。当包含该物体的单元被激活即开始执行,所以所有完整的脚本每秒钟都执行数十次,甚至更多。可以想像,每个本地脚本都不断的循环执行着。
这就是为什么只要玩家一进入包含与以下脚本关联的物体的单元时,就会将连续不断的显示信息框。

Begin Message_script

MessageBox “这部分是显示的内容”

End Message_script

设想一下吧,如果我们的脚本要将一个物品放到玩家的背包中或将一个怪物放到玩家旁边将发生什么。
基于以上原因,“一次性”功能显得格外重要。好,现在回归本文目标,我们需要定义一个变量来确保那个信息只显示一次。更改脚本如下:

Begin my_first_script

Short controlvar

If ( OnActivate == 1 )
If ( controlvar == 0)
MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith"
Set controlvar to 1
endif
endif

End

(注意,MessageBox命令和所引导的内容必须都在一行,也就是说不管多长都不要按换行键)

"Short controlvar"定义了一个名为"controlvar"的short类新变量。该变量可包含所有正整数和负整数。变量的意思就是可以有不同的数值,当一个变量被定义时,其初始值都为零。那个“set”命令也很容易理解,这里它将变量controlvar设为1。if ( controlvar == 0 )这一行实现了“一次性”的目的——这使我们的脚本第二次执行时将在变量被设为1之后。也就是使if 引导的条件为“假”,即不再显示信息框。
至此,我们的脚本已经可以运行了,接下来我们来实际测试:
• 保存该脚本并退出脚本编辑窗口
• 回到编辑器主界面,在Object window里选container标签栏并打开"chest_small_01"
• 更改该ID为"tutorial_chest"
• 在其脚本关联区内选择“my_first_script”
• 将该物品保存为一个新物品,然后保存该mod并退出编辑器。运行Morrowind并载入一个游戏进度。
• 按“~”键开启控制台,输入以下命令后按ENTER键。
PlaceAtPC tutorial_chest 1,1,1

以上操作的结果就是在玩家身后放了一个箱子。好,原地向后转即可看到我们的谜之箱子。点击该箱子将显示我们的谜语和选项。点击这些选项按钮将关闭该信息框,然后再次点击该箱子,应该不再显示该信息了,那么就是说我们的“一次性”成功了。
好,退出游戏并开启编辑器,载入我们的MOD。接下来要定义哪个选项是正确的。
基本思路首先要检测到玩家按了哪个选项的按钮。使用"GetButtonPressed"这个功能。这个功能将回复一个数值,该数值表示玩家鼠标点击了哪个按钮。"0"代表第一个按钮,即"bat"。1代表OLDWOMAN,2代表…..当玩家未选择任何按钮时,该功能回复“–1”。那么将我们的脚本编辑如下:

Begin my_first_script

Short controlvar
Short button

If ( OnActivate == 1 )
If ( controlvar == 0)
MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith"
Set controlvar to 1
elseif controlvar > 1
activate
endif
endif

if (controlvar == 1)
set button to GetButtonPressed
if ( button == -1 )
return
elseif ( button == 2)
MessageBox "The answer was correct"
Activate
set controlvar to 2
else
MessageBox "The answer was wrong"
set controlvar to -1
endif
endif

End

看一下以"if (controlvar == 1)"开始的部分。当该箱子被激活时,变量controlvar被设为1。现在我们检测哪个按钮被点击。通过定义一个新变量"button",并将GetButtonPressed所回复的数值设为"button"。 如前所述,这时该脚本将每时每刻都运行着,即使是在玩家还没选择按钮时,那么这种情况下要告诉游戏引擎在这段时间内停止执行该脚本。
我们这个谜语正确的答案是第二个选项——"wind"。当该按钮被点击后,我们要告诉玩家他选中了正确的答案,然后开启该箱子显示里面装的东西。其他选项意味着错误的答案,我们通过使用"else"命令来概括这种情况。
那么,在原脚本的顶端要加上以下内容:

If ( OnActivate == 1 )
If ( controlvar == 0)
MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith"
Set controlvar to 1
elseif controlvar > 1
activate
endif
endif

这部分意思就是,不管该箱子在什么时候被激活,其只会在变量controlvar的数值大于1时开启。也就是说:当玩家答错时,变量controlvar被设为–1,所以玩家将再也不能开启该箱子。当玩家答对时,变量controlvar被设为2,玩家将可开启该箱子。
你的第一个bug
现在,我们的脚本已经完成了大部分目标。再次进入游戏测试,当选中正确的选项后,该箱子并未像想像的那样开启,那到底哪里错了呢?将反映部分改为以下内容再试:

if (controlvar == 1)
set button to GetButtonPressed
if ( button == -1 )
return
elseif ( button == 2 )
MessageBox "The answer was correct"
set controlvar to 2
else
MessageBox "The answer was wrong"
set controlvar to -1
endif
elseif ( controlvar == 2 )
Activate
endif
看到我将activate命令加入到controlvar == 2的检测部分了吗?这使执行上有了更清晰的次序,编辑脚本时很重要的一点就是尽量避免一次做太多功能。好,可以运行并测试了。
好了,现在该箱子像我们想像的那样开启了。但是…..怎么鼠标移动速度这么慢呀?而且不能关闭该箱子的内容窗口!看上面的controlvar 被设为了2,我们没更改,所以造成游戏每时每刻都在连续不断的获取"Activate"命令!这就是为什么我们关闭不了该窗口,因为那个窗口会立刻又开启。所以,更改脚本如下:

elseif ( controlvar == 2 )
Activate
Set controlvar to 3
endif

再次测试:这回总算没事了。我们是不是忘了点什么?对了,还没制作当玩家答错时的诅咒效果。
在玩家身上放法术
是的,我们的谜箱将在玩家答错时诅咒玩家。
首先进入编辑器主界面左边物体窗口的spellmaking标签栏,鼠标右键点击并选择 "new"。为新法术的ID命名,例如"Frost_Curse";为新法术在游戏中显示的名字命名,例如"Frost Curse"。“TYPE”选则"curse"类型,然后设置强度,例如1-5。
现在诅咒做成了,接下来通过使用AddSpell功能将其放到玩家身上。一段时间之后我们通过使用RemoveSpell 功能驱除该诅咒。那么,我们需要设置时间,再次编辑脚本如下:

Begin my_first_script

Short controlvar
Short button
Float timer

If ( OnActivate == 1 )
If ( controlvar == 0)
MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith"
Set controlvar to 1
elseif controlvar > 1
activate
endif
endif

if (controlvar == 1)
set button to GetButtonPressed
if ( button == -1 )
return
elseif ( button == 2)
MessageBox "The answer was correct"
Activate
set controlvar to 2
else
MessageBox "The answer was wrong"
Player -> AddSpell, "Frost_Curse"
set controlvar to –1
Endif
elseif ( controlvar == 2 )
Activate
Set controlvar to 3
elseif ( controlvar == -1 )
Set timer to ( timer + GetSecondsPassed )
if timer > 10
Player -> RemoveSpell, "Frost_Curse"
set controlvar to -2
endif
endif

End

看这行:Player -> AddSpell, "Frost_Curse" 这用来将我们刚做的诅咒放到玩家身上。"Player -> "用来将后面的效果作用在玩家身上。

这部分:

Float timer
Set timer to ( timer + GetSecondsPassed )
if timer > 10

这就是如何设置时间。GetSecondsPassed 这个功能用来回复自从上一时刻所流逝的时间(秒)。由于脚本每秒都在执行,所以回复的数值通常为小数,那么我们需要定义一个新变量用来存贮十进制数。当timer流逝10秒后驱除该诅咒:
Player -> RemoveSpell, "Frost_Curse"
set controlvar to –2

好,保存并测试。进入游戏,选错的答案让玩家受诅咒,然后开启背包,注意诅咒在数秒后结束了。怎么没受伤呀?因为虽然脚本在运行,但法术效果只在游戏过程中计算,而不在玩家开启菜单时计算。所以当玩家受诅咒后只要马上开启一个窗口即可免受伤害,这是很不合理的,所以我们要让该脚本在窗口模式时停止执行,而在玩家关闭窗口回到游戏模式时继续执行。通过使用MenuMode这个功能来实现,这将在玩家开启窗口模式时回复“1”。所以我们在脚本的开头加入以下内容:

If ( MenuMode == 1 )
Return
Endif

至此,我们的目标都完成了。接下来就是使用编辑器将该箱子放到一个地点,还可以在里面加入你想要的内容,还可以给箱子设置个锁等级等。

我们最终的脚本如下:

Begin my_first_script

Short controlvar
Short button
Float timer

If ( MenuMode == 1 )
Return
Endif

If ( OnActivate == 1 )
If ( controlvar == 0 )
MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith"
Set controlvar to 1
elseif controlvar > 1
activate
endif
endif

if ( controlvar == 1 )
set button to GetButtonPressed
if ( button == -1 )
return
elseif ( button == 2 )
MessageBox "The answer was correct"
Activate
set controlvar to 2
else
MessageBox "The answer was wrong"
Player -> AddSpell, "Frost_Curse"
set controlvar to –1
Endif
elseif ( controlvar == 2 )
Activate
Set controlvar to 3
elseif ( controlvar == -1 )
Set timer to ( timer + GetSecondsPassed )
if timer > 10
Player -> RemoveSpell, "Frost_Curse"
set controlvar to -2
endif
endif

End

本文根据Morrowind Scripting for Dummies 8 by GhanBuriGhan中的部分内容改编。
祝大家玩的快乐,生活的快乐。
Sphinx于2004年11月发表

  [本文结束]

[返回顶部][责任编辑:sphinx] 

§相关文章§
·给自己弄一个全价大商人
·BSApack 用法
·MOD制作实例教学(三)
·MOD制作实例教学(二)
·MOD制作实例教学(一)
·经典MOD推荐V2.6
·控制台命令简明教程
§推荐文章§
·晨风美女MOD
·MOD制作实例教学(五)
·MOD制作实例教学(三)
·MOD制作实例教学(二)
·MOD制作实例教学(一)
·经典MOD推荐V2.6
Copyright©2003-2005 铁资网&铁血联盟资讯网.All rights reserved.
本站所有原创图文资料版权属原作者所有,转载请务必联系原作者并请注明本站出处.
Powered by: dedeCMS Version 2.1