分享到新浪微博 分享到QQ空间 打印

[脚本] 教你如何用pokescript修改口袋游戏剧情!(补充入部分资料及工具下载)

教你如何用pokescript修改口袋游戏剧情!(补充入部分资料及工具下载)

嗯……看了上个帖子的人应该多少对文章有一定了解了,这个教程就是对软件pokescript的一番讲解。pokescript是什么呢?它是老外开发的一款剧情编辑工具,输入脚本,就可以直接操作ROM,相当方便。
本文是我liuyanghejerry在看了软件作者Irish witch的教程之后翻译+修改的,使得文章能让我们看的更顺眼,部分教程还做了调整,不过有些不好翻译的地方我仍旧保持着原文(看目录就知道了),如果有什么地方看不懂,大家可以跟帖表示,我会尽我所能回答的。
OK以下开始正文:
Pokescript教程
我注意到许多人来到我们论坛都会问道一个共同的问题:如何利用Pokescript制作改版?那么现在就让我来完整的回答这个问题吧.
当然,我所讲的一切都基于我的软件──Pokescript.
首先,我们需要下载两样东西:Pokescript(见附件),以及一个数据库,PkmAdv(见附件).
PokeScript的安装相当简单,通常会安装在c:/pokewitch,而PkmAdv也是一样的,注意保持它们在相同的文件夹内即可.
下面我们来看看教程的安排,也就是目录:
      0. 准备知识
      1. 基础内容
      1.1 开始学习
      1.2 显示一段文字
      1.3 写入ROM
      1.4 真正显示于游戏

      2. 关于物品赠送
      2.1 只给一次的情形处理(使用标识)
      2.2 是或不是的问题处理
      2.3 接收物品
      2.4 检查物品
      2.5 删除物品

      3. 关于精灵赠送
      3.1 让精灵消失
      3.2 给予精灵的情形处理
      3.3 给精灵起个昵称
      3.4 让图鉴工作起来
      3.5 统计精灵
      3.6 选择精灵

      4. 野外的场景
      4.1 控制NPC移动
      4.2 计算路线
      4.3 开始移动
      4.4 设置路标
      4.5 跟随NPC

      5. 道馆中的情形
      5.1 地图中的人物
      5.2 与野生精灵战斗
      5.3 寻找训练师
      5.4 基本的训练师战斗
      5.5 双人战斗
      5.6 道馆馆主
      5.7 再次相遇的战斗
      5.8 训练师的可视范围

0.准备知识      
现在让我们来接触一下需要了解的一些基础知识吧.
十六进制数字
十六进制数字是相对于十进制的一种数字表达方法,它用的不是0,1,2,3,4,5,6,7,8,9而是0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F这十六个字符.使用十六进制数字更有利于和二进制的处理器交换数据,但我们不需要深入了解.通常,我们表示时在前面加上"&H"或者"0x".
你无需使用十六进制数字去做什么艰难的工作,顶多,就是用它们写写地址之类的东西.
那么接下来要说的就是地址.
地址是什么?我没法具体的去说明它,而且也没有必要,我们只需要知道它长这样:0x800100.
但实际上在Pokescript当中我们并不(或者说很少)用到这种表达方式,我们会用到这个:$Offset,来看一段简单的示例:
code:
#inline $Variable 1 = Hi I'm John!
$Variable 1 = Hi I'm John!
以上说的什么?你完全不用理会,你需要注意的是这个$Variable.在Pokescript当中,一个英文词语前加$就可以表示一个地址,当然,这个词语当中不允许有任何符号.至于它表示的地址具体是什么,完全不必理会(至少现在如此),那是程序的任务.

注:在一些特别的时候,我们需要将地址表示为0x800100的形式,因为这是所有工具都认识的格式


下面开始进入正题:


1. 基础内容
在我的教程中,我们时刻都要考虑你的脚本需要做什么,比如现在正要说的显示信息和道具给予.


1.1开始学习
通常在整个改版过程中,我们得有一套完整的事件流程,就像一个剧本,比如:
        1. 你在地图上激活一个NPC.
        2. NPC将会问你一个问题.
        3. 如果你回答是,那么他将会给你一块饼干.
        4. 如果你已经要过饼干了,那么他会说另一段话
        
以上是一个很基本的例子,但我们现在还不到那个地步,我们得先来点更简单的:显示信息,也就是让NPC对你说一句话,然后来看看脚本是如何输出并写入ROM的.

首先打开记事本,并在其中输入以下的内容:
Code:
#ORG $ShowText
Lock
Faceplayer

以上是几条最为基本的命令,最开始的是地址标志,也就是$ShowText,前面我们曾经说过.而#ORG则表示脚本开始.这两个命令相当重要,因为它们不仅在这里要用到,而且以后几乎所有的脚本中都要用到,我们把它们看做一条命令,必须牢记.
第二行的命令Lock表示将NPC锁定,而不是让他跑动.
第三行命令更好理解,它表示面对主角.
通常开始一段对话的时候都要写以上的部分,这几乎成了惯例.
那么下一步就是:


1.2 显示一段文字
以上的那些命令在每次显示一段文字时都要用到,那么来看看下面的代码:
message $NoCookie
$NoCookie 1 = I'm not made of cookies!\lYou only get one.
boxset 6
$NoCookie的格式前面已经说过,是一个地址,但不仅仅表示地址,此处我们认为它是一个变量.(变量是编程中用到的词语,完全不懂的话可以百度一下,当然,你跟着教程也能自己悟出)
而I'm not made of cookies!\lYou only get one.则是我们想要显示的信息,其中\l表示换行.与\l类似的还有\n和\p ,区别大家可以自己体会.
boxset 是设置对话框的意思,表示这里的内容在对话框中显示,6表示普通的文本对话框.
看起来我们已经完成了所要做的,但请等一下,在末尾加上:
release
end
表示恢复NPC原始形态,并结束脚本.这样整个脚本就是:
#ORG $ShowText
Lock
Faceplayer
message $NoCookie
$NoCookie 1 = I'm not made of cookies!\lYou only get one.
boxset 6
release
end
现在我们在记事本当中,选择另存为,存为*.rbc格式即可.
接下来我们将脚本写入ROM.


1.3 写入ROM

现在在"我的电脑"中找到刚才保存好的脚本,右键可以看到"合并脚本到ROM"的相关字样(英文:complie the script),点击.这时程序会弹出两个窗口,一个类似于工作日志,我们关闭它;而另一个则是Pokescript合并器的主窗口.(如果这个窗口未能弹出,那么双击同目录生成的文件即可)
紧接着我们有两个方法来完成剩余的工作.
①比较直接的方法
单击那个好像书本一样的按钮,然后载入你想合并的ROM.
注意,如果此时底下的列表中有多项内容你希望添加,那么使用shift可以复选,否则选中一个就好.
现在就会弹出一个小窗口─此窗口会告诉你,即将写入的信息有多少以及ROM有多少剩余空间、从什么地方开始写起.如果是第一次使用,那么我们大可按照默认的地址0x800000开始写入,因为在原来的ROM中,这个地方是空的.按下你需要写入的地址,然后点"assign".
瞧,又回到主窗口了.点击"file"菜单中的"Burn",程序就开始工作了.
工作完毕后千万不要直接关闭,记下程序回显中紧跟着起始地址的一行数字,我们一会有用的哦.
②推荐的方法
回到刚才,弹出小窗口的时候.大家应该注意到"assign"按钮上有一个复选框,钩选之后按钮就会显示"Reserve",如此你所写入ROM的信息就不会覆盖到任何其它数据了(如果这不是个Clean ROM的话).

1.4 真正显示于游戏
经过刚才的步骤,脚本已经被输入到ROM当中了,但是我们并没有让脚本的内容进入游戏.
打开经典的工具Advanced Map,调至你所想要修改对话的NPC(在event view页面选中),在地图右边找到"Script Offset"一项(也就是地址了),还记得刚才我要大家记下的数字吗?粘贴替换掉现在那个,保存,测试!
那么,现在一个最基本的步骤就算结束了,后面,我们就来完成一开始的那个小剧本吧.

注意了,如果您在ROM当中发现修改后的对话成为了乱码,那么您必须参见这里解决:http://poketb.com/bbs/viewthread.php?tid=4258&extra=page%3D1

2. 关于物品赠送
学习完以上的内容,大家应该对脚本制作有一个大概的了解了.如何开始一个脚本、如何结束一个脚本以及如何使脚本在游戏中实现,都必须牢记.
现在让我们来看看关于物品赠送的部分.
以下的例子和上文中的很相似,不过这次我们给变量一个新名字:$GotCookie(上文名为$ShowText).


2.1 只给一次的情形处理(使用标识)
当然,就和前面一样,我们的脚本仍然这么开头:
#org $Startscript
Lock
Faceplayer
为了能使得游戏知道每一个事件,我们通常要用到一个命令:setflag,中文即是设立标识.这就好比公交车站牌一样,告诉公交车何时该停下.
大概有6000个标识可以使用。但是,在0x300 - 0x400 和 0x800 - 0x900 有许多游戏本身使用的,所以要避开这些去进行HACK.
标识通常写作16进制,不过我们这会还不用亲自设立标识,而只需要让游戏检查标识.
说到这大家可能晕了,什么是检查标识?我们并没有设立任何标识啊.是这样的,检查标识是一个预备性的命令,而关于设立标识,则是以后几节的重点,现在只要认得这个:
checkflag 0x200
if B_TRUE goto $GotCookie
你可能看不懂以上的脚本,没关系,我现在来讲解一下.
checkflag这个命令在检查标识0x200.
而这里,B_TRUE也可以写作1或者0x1,它们都表示"正确".
$GotCookie是我们事先写好的脚本.
也就是这么个意思:检查标识0x200,如果该标识存在,则进入脚本$GotCookie
为了能更好的理解上面所说的,我们来进入下一节.当一切联系起来的时候,你就会明了了.

2.2 是或不是的问题处理
是或不是的问题在对话时显得相当简洁,同时在结构上和之前显示对话的样式也很相似,因为它们都由对话引起.
message $AskMe
$AskMe 1 = Would you like a Lava Cookie?
boxset 5
以上的脚本和之前的很相似,唯一的区别就是命令boxset后的数字了.我们前面学过,6表示普通的文本对话框,那么5呢?5则表示一个"是或否"的选择框.游戏中我们经常见到这样的选择框,不是吗?比如在捕捉到新精灵时,系统会自动问你,要起昵称吗,此时用到的就是这个了.
与checkflag型的语法不同,语句块是不可以直接跟在if之后的,我们需要这样做:
compare LASTRESUILT B_TRUE
if B_False goto $DontGet
compare命令是在做对比,即如果以上的YES OR NO的问题中你选则了和YES不同的答案,那么将跳转到$DontGet部分的脚本.
当然,compare命令不只可以用在YES OR NO的问题判断中,它还可以处理其它多值问题当中,这一点我们将在增加精灵一节展示出来,你会发现那是多么的事半功倍.
而现在,我们得看看如何接收物品了.

2.3 接收物品
在上例中,我们最终会得到一块饼干,饼干的值是0x26.你可以从附件中的items.txt获得(L:文章的最后我会提供下载的).
在获得饼干的过程中不必担心背包已满而发生数据溢出的问题,系统会自动处理这一切:回绝别人的赠送.
紧跟着上面的代码,我们还要加一句:
setflag 0x200
很眼熟吧?这就是上节中我们检查的那个标识,有了setflag这个命令,标识0x200就被建立起来了,而当checkflag再次检查时,得到的结果就是B_TRUE了.
现在我们来结束这个脚本,写上:
Release
end
完整的脚本就是:

#org $Startscript
Lock
Faceplayer
checkflag 0x200
if B_TRUE goto $GotCookie
message $AskMe
$AskMe 1 = Would you like a Lava Cookie?
boxset 5
compare LASTRESUILT B_TRUE
if B_False goto $DontGet
giveitem 0x26 1
setflag 0x200
Release
end

#ORG $GotCookie
Lock
Faceplayer
message $NoCookie
$NoCookie 1 = I'm not made of cookies!\lYou only get one.
boxset 6
release
end

#ORG $DontGet
Lock
Faceplayer
message $AllMine
$AllMine 1 = All the more for me!
boxset 6
release
end

如果你还不能理解整个脚本,那么请让我来注释一番:

脚本$Startscript部分
锁定人物
面向主角
如果标识0x200存在,则跳转至$GotCookie部分
否则显示$AskMe部分的信息
$AskMe表示Would you like a Lava Cookie?
弹出YES OR NO选择框
对比选择框结果和 B_TRUE
如果不匹配则跳转至$DontGet部分
否则将饼干给予1块
设立标识0x200
恢复人物状态
脚本结束

脚本$GotCookie部分
锁定人物
面向主角
显示信息$NoCookie
信息$NoCookie表示I'm not made of cookies!换行You only get one.
弹出标准文本框
恢复人物状态
脚本结束

脚本$DontGet部分
锁定人物
面向主角
显示信息$AllMine
信息$AllMine表示All the more for me!
弹出标准文本框
恢复人物状态
脚本结束


2.4 检查物品
我们有时会考虑这样一种情形:
1. 首先我们激活一个NPC.
2. 如果你有一块饼干,那么她会用一个超级球作为交换.
3. 如果你在上文的脚本中没有获得饼干她会说她想要饼干.
4. 如果你给过她饼干了,再次对话时她会说十分感谢.

这个构思把我们之前所写的脚本紧紧的联系到了一起,这正体现出RPG游戏一贯严谨的剧情风格.
因为上例中我们已经使用了标识0x200,所以本次的例子我们将使用标识0x201,同时再启用一些新的地址变量,比如$GotBall.
现在来接触一下新的命令:
Checkitem 0x26

Checkitem是一个检查物品数量的命令,它返回的值是一个数字.而且这个返回值是可以被命令compare所使用的,比如:
Compare LASTRESULT 1
表示比较结果和1是否相同,结果就是上面Checkitem返回的值,那么我们就可以这么理解:
Compare Checkitem 0x26 1
当然,这只是我们所想象的过程,真正脚本在处理时必须写作:
Compare LASTRESULT 1

但是这个脚本在我们的剧本中只能用来判断有或是没有饼干,也就是比较0和1,尽管正常情况下饼干只能得到一块,但如果发生意外了呢?──难道有两块饼干就不能换超级球了么?
我们必须考虑一个范围的问题,也就是说,当背包中只要有饼干就换球,而不仅仅是1块饼干.我们用如下的命令格式来完成它:
B_<< 小于 (0)
B_== 等于 (1)
B_>> 大于 (2)
B_<= 小于等于 (3)
B_>= 大于等于 (4)
B_!= 不等于 (5)
括号内的数字表示的是另一种表达方式,我们暂且不管.
用上面的语句格式,就可以拓展我们的IF判断命令了:
#Org $StartScript
checkflag 0x201
if B_True goto $GotBall
checkitem 0x26
compare LASTRESULT 1
if B_<< goto $NoCookie


2.5 删除物品
我们来瞧瞧已经完成的脚本:
$WantBall 1 = Oh, You have a lavacookie.\pIf you give it to me I'll\lgive
you this UltraBall...\pWhat do you say?
message 5
boxset 5
compare LASTRESULT 1
if B_FALSE goto $DontGet
在这之后NPC便会给主角一个超级球,但是问题也来了:饼干仍旧在主角的背包当中,于是我们得加上这样一个命令使得交易公平起来:
removeitem 0x26 1
参数格式和giveitem命令完全一样,连在一起就是:
giveitem 0x2 1
removeitem 0x26 1
而如果我们希望5个饼干才能换取一个超级球,那么则可以这样:
compare LASTRESULT 5
if B_<< goto $NoCookie
giveitem 0x2 1
removeitem 0x26 5
最后别忘了再加上:
Release
end
现在来看看完善后的脚本:
#Org $StartScript
checkflag 0x201
if B_True goto $GotBall
checkitem 0x26
compare LASTRESULT 1
if B_<< goto $NoCookie
message $WantBall
$WantBall 1 = Oh, You have a lavacookie.\pIf you give it to me I'll\lgive you this UltraBall...\pWhat do you say?
boxset 5
compare LASTRESULT 1
if B_FALSE goto $DontGet
giveitem 0x2 1
removeitem 0x26 1
Release
end

#ORG $GotBall
Lock
Faceplayer
message $LikeCookie
$LikeCookie 1 = Thanks for the cookie!
boxset 6
release
end

#ORG $NoCookie
Lock
Faceplayer
message $LoveCookie
$LoveCookie 1 = I Absolutely LOVE Lava Cookies!\lThey're Just so Spicy!
boxset 6
release
end

#ORG $DontGet
Lock
Faceplayer
message $AAAW
$AAAW 1 = Aaw C'Mon. It's a fair trade!!\nI Love those things.
boxset 6
release
end
这次我不再翻译了,看不懂的人得再阅读上文.
以上就是第二部分的全部了.


想死你们了!

TOP

3. 关于精灵赠送
相信这个章节应该是大家最期盼的了吧?精灵赠送在游戏中总是让人感到无比兴奋,现在我们就来进入这一环节.
在本章节中,我们需要3个放置于地上或者桌子上的精灵球,但如何构造并不是我们现阶段要讨论的问题.
来构想这样一个情景:
1. 首先你激活了一个精灵球.
2. 然后系统就会告诉你里面是个什么精灵,并询问你是否要.
3. 如果你回答否,那么精灵球仍旧在那里放着
4. 如果你回答是,那么这只精灵就属于你了,同时系统问你是否想给它起个昵称.
5. 当然,如果你已经有了第一只精灵,那么系统会显示另外一段话来回绝你.
以上的情景很熟悉吧?这就是火红/叶绿开始的情节,我们每个玩家都曾经历过,不过我们也应该注意到,以上的情节中存在着两个脚本.

3.1 让精灵消失
先不要误会,这里的"让精灵消失"并不是指让你已经拥有的精灵丢失,而是指你在得到精灵球中精灵的同时,地图上的那个精灵球也要消失的过程.这个过程远比得到精灵重要,同时,这种使得精灵球从地图上消失的技巧也可以用在NPC或者其它物品上.
那么这如何做到呢?
打开Advanced map,在EVENT页面选中任意一个人物,然后在右侧的边栏中找到People ID一项.还记得前面说的标识吗?这里的People ID就是系统内置的标识,如果我们要告诉系统这个事件已经发生过了,那么只要使用Setflag加上0x再加People ID就可以让人物消失了!这时系统会自动刷新屏幕.但是,必须在Setflag命令结束之后再加一个release命令,否则会发生意外!
如果把以上的内容镶嵌到物品赠与的脚本中,就要参照这个格式:
#ORG $begin
lock
faceplayer
checkflag 0x200
if B_true goto $done
message $aidtalk
boxset 6
giveitem 0xD 1
setflag 0x200
release
end

3.2 给予精灵的情形处理
现在一切都准备停当了,我们写下精灵给予的脚本:
#org $StartChik
checkflag 0x800
if B_True goto $NoBall
message $Chick
$Chick 1 = Chikorita!\lThe Fire Bird.\pTake the Chikorita?
boxset 5
compare LASTRESULT 1
if B_False goto $PutBack
以上的部分和物品赠与完全相同,不过现在我们要添加两条命令了:一条是Jingle,Jingle就是得到物品后的声音;而另一条命令我们来看下面:
givepokemon 152 5 0
jingle
message $GotChick
$GotChick 1 = You Recieved a Chikorita
boxset 6
对了,就是givepokemon命令,这个命令含有3个参数,它们依次为:编号、等级、携带物品,需要说明的是,编号参数和全国图鉴略有不同,它有一共411个值可供选择,至于为什么这里暂不解释;而物品的编号则需参照文末即将提供的一份文本列表,这和之前物品赠与的规则是一样的;而等级参数就写作10进制的数字就好,不过一定要靠谱.
现在来看看接下来发生的事:


3.3 给精灵起个昵称
给精灵起昵称的过程并不复杂,我们像往常一样:
message $NameChick
$NameChick 1 = Would You like to give Chikorita a name?
boxset 5
compare LASTRESULT 1
if b_False goto $GiveDex
Namepokemon
瞧,Namepokemon什么参数也没有!是的,Namepokemon命令只是触发了系统的命名功能,而具体的事情并不由我们来完成.但是为了告诉系统,我们已经命名,必须在其后写一个设立标识的语句,如下:
#org $StartChik
checkflag 0x800
if B_True goto $NoBall
message $Chick
$Chick 1 = Chikorita!\lThe Fire Bird.\pTake the Chikorita?
boxset 5
compare LASTRESULT 1
if B_False goto $PutBack
givepokemon 152 5 0
jingle
message $GotChick
$GotChick 1 = You Recieved a Chikorita
boxset 6
message $NameChick
$NameChick 1 = Would You like to give Chikorita a name?
boxset 5
compare LASTRESULT 1
if b_False goto $GiveDex
Namepokemon
setflag 0x203
goto $GiveDex
最后的goto命令无条件的跳转到了下一个环节:


3.4 让图鉴工作起来
事实上无论你获得或者捕捉到什么精灵,图鉴总会立即更新,但如果你还没有图鉴呢?那么游戏会变得很奇怪并且容易出错.
因此如果这是你改版的第一个脚本,我们得加上:
setflag 0x800
setflag 0x801
事实上,标识0x800使菜单中出现"精灵"这一项,而标识0x801才是打开图鉴的标志,但是很显然,二者都不可缺少.因此完整的脚本如下:
#org $StartChik
checkflag 0x800
if B_True goto $NoBall
message $Chick
$Chick 1 = Chikorita!\lThe Fire Bird.\pTake the Chikorita?
boxset 5
compare LASTRESULT 1
if B_False goto $PutBack
givepokemon 152 5 0
jingle
message $GotChick
$GotChick 1 = You Recieved a Chikorita
boxset 6
message $NameChick
$NameChick 1 = Would You like to give Chikorita a name?
boxset 5
compare LASTRESULT 1
if b_False goto $GiveDex
Namepokemon
setflag 0x203
goto $GiveDex

#org $StartShrew
checkflag 0x800
if B_True goto $NoBall
message $Shrew
$Shrew 1 = SandShrew!\lDesert Mole.\pTake the Sandshrew?
boxset 5
compare LASTRESULT 1
if B_False goto $PutBack
givepokemon 27 5 0
jingle
message $GotChick
$GotShrew 1 = You Recieved a Sandshrew
boxset 6
message $NameShrew
$NameShrew 1 = Would You like to give Sandshrew a name?
boxset 5
compare LASTRESULT 1
if b_False goto $GiveDex
Namepokemon
setflag 0x204
goto $GiveDex

#org $StartWing
checkflag 0x800
if B_True goto $NoBall
message $Chick
$Wing 1 = Wingull!\lThe Ocean Bird.\pTake the Wingull?
boxset 5
compare LASTRESULT 1
if B_False goto $PutBack
givepokemon 152 5 0
jingle
message $GotGull
$GotGull 1 = You Recieved a Wingull
boxset 6
message $NameGull
$NameGull 1 = Would You like to give Wingull a name?
boxset 5
compare LASTRESULT 1
if b_False goto $GiveDex
Namepokemon
setflag 0x205
goto $GiveDex

#org $GiveDex
setflag 0x800
setflag 0x801
message $Pokedex
$Pokedex 1 = I hope You like your new pokemon.\pWhile your on your journeys I have\la favour to ask you.\pProf OAK and I are trying to make an\lindex of everything pokemon.\pTake this pokedex with you and it\lwill log all the pokemon you see and catch.\pIt would greatly help our studies!
boxset 6
jingle
message $GotDex
$Gotdex 1 = You got the Pokedex!
boxset 6
end

#org $PutBack
message $PutBack
$PutBack 1 = You put the pokeball back.
boxset 6
end

#org $NoBall
message $Lastball
$Lastball 1 = You already have your pokemon.\nDont be so greedy!
boxset 6

注意,以上的脚本是专为"选择初始精灵"而准备的,如果是其它情形,则脚本还可以更简单.
L:大家仔细看脚本可以发现,其实激活图鉴是在获得精灵之后的,这显然不符合逻辑,有没有更好的写法呢?大家可以试试把goto $GiveDex提前,看看会出现什么结果.


3.5 统计精灵
统计精灵其实只是为了进行一次确认──确认在得到精灵时队伍是否已满.通常我们必须这么做,否则一旦向满队伍中增加精灵,数据就会溢出.
countpokemon
compare LASTRESULT 6
if b_True goto $FullParty
以上就是一个绝好的countpokemon命令例子.但countpokemon并不是只有这一处用武之地,它还可以:
限制至少有一只精灵才能进入
compare LASTRESULT 1
if b_>> goto $EnterRoom
限制至少有两只精灵才能战斗
compare LASTRESULT 2
if b_!= goto $DualBattle
携带3只以上的精灵不能进入
compare LASTRESULT 3
if b_<= goto $EnterBattle
还有很多其它用法.

3.6 选择精灵
选择精灵这个命令很少出现,唯一记忆清晰的就是在重命名的时候会用到,示例如下:
#org $GivePoke
message $ChangeName
$WantPoke 1 = Hi! I'm the Name Rater\pI Rate pokemons name and\nallow people to change them.\pWould you like to rate the name of\lyour pokemon?
boxset 5
compare LASTRESULT 1
if B_False goto $Later
selectpokemon
message $NamePoke
$NamePoke 1 = Alright, what name shall we give it?
boxset 6
Namepokemon
message $MuchBetter
$MuchBetter 1 = You're right.\lThat's a much better name.
boxset 6
end

#org $Later
message $Banter
$Banter 1 = Ok.\lLet me know if you change your mind?
boxset 6
end

OK,关于精灵赠与部分的讲解到此就算结束了.


想死你们了!

TOP

4. 野外的场景
第4个章节我们研究的是如何安排人物的行动,这和之前的脚本在结构上会有所不同,而使用的命令也将有许多是之前未曾讲过的,所以大家务必用心.
在本章当中,我们的联系对象是"博士的研究所"当中发生的情节,各位可以拿出红蓝宝石先回味一下.
另外,本章节所需要的资料Ruby-Move.txt和FR-Move.txt会在文末一同放出.


4.1 准备行动
我们现在又开始需要Advanced Map这款软件的帮忙了,打开Advanced Map,找到"博士的研究所"并切换到Event view页面.
看到一些写着S的方框了么,但这些方框是不同的:在入口处的那个表示一个事件,而其余的则都表示标志.什么是标志呢?就是当主角激活它的时候,它只显示一段文字,好比:"电视上正播出着妈妈爱看的节目......".
"博士的研究所"中桌子上放的三个精灵球,实际上则被游戏界定为人物,因而它们都写着"P",编号为59.
现在我们不用去管标志,而将重点放在人物和事件两个方面.
在我们的脚本当中,我们希望Professor Birch和Brendan都能够动起来,所以现在得看看关于他俩的人物信息,好比是如下这样:
Professor Birch:
- 人物编号: 2
- 距离门口的S框8个格子

Brendan:
- 人物编号: 3
- 同样距离门口的S框8个格子
- 距离精灵球旁的S框4个格子.

同时为了确保两人静止,我们还必须在"Movement"一栏选择"None"(两个人都要如此).事实上只有处于这种状态之下,关于移动NPC的脚本才能够实现.
我们现在希望他们怎样呢?
1. 我们要主角移动到博士面前,然后显示得到图鉴的那个脚本.
2. 得到图鉴.
看起来上面的内容相当简单,而实际上则远比这两行字麻烦.


4.2 计算路线
当明确了人物的行动目的之后,我们就要开始盘算行动路线了,也就是计算路线.路线铺设相对比较繁琐,累计下来的脚本恐怕比得上很多给予物品的脚本,我们必须灵活的应用if和goto考虑到玩家的各种行动可能,以免意外发生.
      Code:
#org $IF_OR
checkflag 0x203
if b_True gosub $Move1
checkflag 0x204
if b_True gosub $Move2
checkflag 0x205
if b_True gosub $Move3
end

' 每一个$Move脚本在运行之后都必须用return命令来使脚本回归:
#org $IF_AND
checkflag 0x203
if b_True gosub $TestFlag2
end

#ORG $TestFlag2
checkflag 0x204
if b_True gosub $DoMove
return
以上的if...gosub命令是借鉴了VB当中的IF语句形式,如果你懂得一些,可以看看这个:
IF_OR参考:
if checkflag(0x203) then
' Move 1
endif
if checkflag(0x204) then
' Move 2
endif
if checkflag(0x205) then
' Move 3
endif
IF_AND参考:

if checkflag(0x203) then
  if checkflag(0x204) then
     ' DoMove
  endif
endif
当然,以上只是了解一下,我们在软件中也不能用以上的代码.
言规正传,我们来看完善后的脚本:
#org $GiveDex
setflag 0x800
setflag 0x801
checkflag 0x203
if b_True gosub $Move1
checkflag 0x204
if b_True gosub $Move2
checkflag 0x205
if b_True gosub $Move3
message $Pokedex
$Pokedex 1 = I hope You like your new pokemon.\pWhile your on your journeys I have\la favour to ask you.\pProf OAK and I are trying to make an\lindex of everything pokemon.\pTake this pokedex with you and it\lwill log all the pokemon you see and catch.\pIt would greatly help our studies!
boxset 6
jingle
message $GotDex
$Gotdex 1 = You got the Pokedex!
boxset 6
end
L:事实上大家可以将gosub换回我们熟悉的goto命令,因为笔者在参考了其它资料后发现只有在Irish Witch的教程中出现了这个命令,而其它人一律用的是goto.
下面来进入最最关键的步骤:


4.3 开始移动
以上都是很简单的准备性工作,当然,移动也并非很难,只是稍稍繁琐而已,来看命令:
Applymovement <人物编号> <地址>
pausemove 0
applymovement表示给人物一个起始信号,好比一个通知;而下面的pausemove暂且不管.
需要说明的是:
1.人物编号我们之前曾经说过,但当你要命令主角的时候则需要写"0xFF"
2.在移动的脚本之内,不要使用lock命令,否则人物不会移动!具体写成什么样子,看下面:
#org $Move1
applymovement 0xFF $Ball1Move
pausemove 0
return
由于无论拿到桌子上的哪只精灵都会触发走到博士旁边的动作,所以这段脚本需要写三次.

关于移动的命令
由于每个版本所需要的移动不同,故而我们需要区分版本的写命令:如果你改的是红宝石,那么你需要使用ruby-move.txt当中的命令,而如果你改的是蓝宝石或者火红/叶绿,那么你需要用到FR-Move.txt当中的命令(同样在文末送出).
L:奇怪的是,红蓝宝石的命令竟然会不同,疑为原作者笔误,还有待验证.
先来看:
Left 0 = 脚不离地的向转身
Left 1 = 向左一步
Left 2 = 快速左走2步
Left 3 = 急速走3步
也就是说,数字既代表步数,又代表了速度.同时记住,left1  left1 left1 left1 = left2 left2,它们速度虽然不同,但位移的结果却是完全相同的.
但是,以上并不是命令的真实面目,我们在写脚本时,必须在前面加命令#Binary,并且要这样写:
#Binary 0x06 0x06 0x06 0x06 0xFE
#Binary 0x0a 0x0a 0xFE
以上是红宝石中的命令,完整的就是:
#org $GiveDex
setflag 0x800
setflag 0x801
checkflag 0x203
if b_True gosub $Move1
checkflag 0x204
if b_True gosub $Move2
checkflag 0x205
if b_True gosub $Move3
message $Pokedex
$Pokedex 1 = I hope You like your new pokemon.\pWhile your on your journeys I have\la favour to ask you.\pProf OAK and I are trying to make an\lindex of everything pokemon.\pTake this pokedex with you and it\lwill log all the pokemon you see and catch.\pIt would greatly help our studies!
boxset 6
jingle
message $GotDex
$Gotdex 1 = You got the Pokedex!
boxset 6
end

#org $Move1
applymovement 0xFF $Ball1Move
pausemove 0
return
#org $Move2
applymovement 0xFF $Ball2Move
pausemove 0
return
#org $Move3
applymovement 0xFF $Ball3Move
pausemove 0
return

#org $Ball3Move
#Binary 0x06
#org $Ball2Move
#Binary 0x06
#org $Ball1Move
#Binary 0x06 0x06 0x06 0x01 0xFE
注意,移动的最终需要添加一个终止标志,在红宝石中是0xFE,而其它的则需要参考资料.
以下是火红的移动全资料:
' Specials
0x4A ' Face player
0x4B ' Face against player
0x60 ' Disappear (removes the sprite, but the person can still be interacted with)
0x62 ' "!" pops up
0x63 ' "?" pops up
0x64 ' "X" pops up (vs-seeker cant fight)
0x65 ' "!!" pops up (vs-seeker can fight)
0x66 ' "" pops up

' walking
0x01 ' step Up0
0x02 ' step Left0
0x03 ' step Right0
0x04 ' step Down0
0x08 ' step down1
0x09 ' step up1
0x0A ' step left1
0x0B ' step right1
0x0C ' step down2
0x0D ' step up2
0x0E ' step left2
0x0F ' step right2
0x10 ' step down3
0x11 ' step up3
0x12 ' step left3
0x13 ' step right3
0x1D ' step down4
0x1E ' step up4
0x1F ' step left4
0x20 ' step right4

      ' jump in place looking where it says
0x52 ' jump0 down
0x53 ' jump0 up
0x54 ' jump0 left
0x55 ' jump0 right

      ' jump in place looking in the order it says
0x56 ' jump0 down/up
0x57 ' jump0 up/down
0x58 ' jump0 left/right
0x59 ' jump0 right/left

' Jump Direction
0x4E ' jump1 down
0x4F ' jump1 up
0x50 ' jump1 left
0x51 ' jump1 right

0x14 ' jump2 down
0x15 ' jump2 up
0x16 ' jump2 left
0x17 ' jump2 right

0x46 ' jumpLookingLeft1 down
0x47 ' jumpLookingDown1 up (jump backwards)
0x48 ' jumpLookingUp1 left
0x49 ' jumpLookingLeft right (jump backwards)


These are the offsets for basic movement:
UP = 0x11
DOWN = 0x10
LEFT = 0x12
RIGHT = 0x13
实在懒得翻译了,大家稍微翻翻词典就知道注释的意思了.

4.4 设置路标
路标(var),这是个什么概念?大家可能会想起我们前边所讲的标识(flag),其实它们是差不多的,同样是为了做个标记.不过路标的英文var实际表示的是变量,这意味着什么?这意味着路标不仅可以表示"有"或"无",还可以放置一个数字!这就给我们作出多种假设方案提供了便利.
#org $LeftExit
setvar 0x4400 2
checkflag 0x800
if 0x0 gosub $UmPokemon
checkflag 0x207
if 0x0 goto $Followme
end
以上就是命令setvar在0x4400放置数字2的过程.
但是这个脚本只是一小部分,我们这次打算计划的是什么?
1.如果你想要走出研究所,那么博士的助手就会叫住我们
2.紧接着把我们带到放有精灵球的盒子旁
2b.这时给你一个超级球
3.如果你尝试绕过助手,那么脚本会强制你走到助手旁触发脚本
4.如果你已经有一个超级球,那么你什么也得不到.
结合上面的脚本,补充如下:
#org $Followme
message $HeyWait
$HeyWait 1 = Brendan: Hey Wait!\p
boxset 6
compare 0x4400 1
if 0x1 gosub $AdjustLeft
compare 0x4400 2
if 0x1 gosub $AdjustRight


4.5 跟随NPC
跟随NPC实际和上面的人物移动脚本差别并没有多大,只需要让主角走得慢NPC一步.我们为此需要一个命令:pause.pause并不是等待所有脚本结束后才开始运行,而是在等待一个特别的时机.我们来看示例:
1.首先,Brendan开始移动.
2.使主角以慢1步的形式作相同的脚本移动.
3.等到Brendan停止移动的时候.
4.主角会停止在Brendan后面,而不是撞上去
5.现在所有人都停下了.
这样我们就会得到类似的脚本:
applymovement 0x3 $Brendanwalk2
applymovement 0xff $StepRight
applymovement 0xff $Brendanwalk2
'结果是: Up0 Up2 Up2 Up2 Up1 left0 left1 left1 left1
$BrendanWalk2 1 ; 0x05 0x09 0x09 0x09 0x05 0x02 0x07 0x07 0x07 0xfe
pause 0x110

applymovement 3 $StepRight
$StepRight 1 ; #Binary 0x07 0xfe
pausemove 0

我们在这里新加了一些东西.如果你已经明白了之前的内容,那么很容易看出我们即将写:
#org $StepRight
#Binary 0x07 0xfe
因为之前也学过类似的结构:
#org $MyText
= Any old text we want!
同样的结构,但是表达上却有一点小区别.在以前的脚本中,我们常用=来赋值,而在移动的脚本中,我们却要用;
和前几个小节的脚本结合,得到如下完整的脚本:
' 脚本开始
' -------------
#org $RightExit
setvar 0x4400 1
checkflag 0x800
if 0x0 gosub $UmPokemon
checkflag 0x207
if 0x0 goto $Followme
end

#org $LeftExit
setvar 0x4400 2
checkflag 0x800
if 0x0 gosub $UmPokemon
checkflag 0x207
if 0x0 goto $Followme
end

' 如果你没有精灵
' -----------------------
#org $UmPokemon
message $WhatNoPoke
$WhatNoPoke 1 = BIRCH: Don't you want a Pokemon?
boxset 6
applymovement 0xff $TurnPlayer
$TurnPlayer 1 ; #Binary 0x05 0x09 0xfe
pausemove 0
end

' 将主角移到一旁
' -----------------
#org $AdjustRight
applymovement 0xFF $MoveLeft
$MoveLeft ; #Binary 0x56 0x02 0x06 0x03
return

#org $AdjustLeft
applymovement 0xFF $FaceRight
' This move set goes: Alert Up0 Right0
$FaceRight ; #Binary 0x56 0x01 0x03
return

' 跟随部分脚本
' ----------------
#org $Followme
message $HeyWait
$HeyWait 1 = Brendan: Hey Wait!\p
boxset 6

compare 0x4400 1
if 0x1 gosub $AdjustLeft
compare 0x4400 2
if 0x1 gosub $AdjustRight

applymovement 3 $BrendanWalk1
$BrendanWalk1 1 ; #Binary 0x08 0x08 0x08 0x08 0x02 0xfe
pausemove 0

Message $Parting
$Parting 1 = Before you leave I have something\pThat might Help you later!
boxset 6

applymovement 0x3 $Brendanwalk2
applymovement 0xff $StepRight
applymovement 0xff $Brendanwalk2
$BrendanWalk2 1 ; #Binary 0x05 0x09 0x09 0x09 0x05 0x02 0x07 0x07 0x07 0xfe
pause 0x110

applymovement 3 $StepRight
$StepRight 1 ;#Binary  0x07 0xfe
pausemove 0

message $Rummage
$Rummage 1 = Brendan Rummages in the box
boxset 6

applymovement 3 $FaceLeft
$FaceLeft 1 ; #Binary 0x02 0xfe
pausemove 0

message $UltraBall
$UltraBall 1 = Here it is!\nThis is an Ultra Ball!\pIt's one of the most powerful balls\lin existance and will catch just about\pAny pokemon. Use it wisely.
boxset 6
giveitem 0x2 1
release
end

如果你已经完全明白上面脚本的意义,那么恭喜,你已经完全掌握了移动的命令!


5. 道馆中的情形
嘛...经过前面的学习,脚本命令的基本形式大家都应该相当了解了,本章的内容主要是教会你一些命令,没有什么难度.


5.1 地图中的人物
其实在前面的内容中我们已经学习过一些关于地图上人物的知识,比如如何让人物消失.
而在本部分中,我们将制作一只在道馆外转悠的野生精灵:
1.当你和它对话时,它会叫一声
2.如果该道馆的徽章你已经取得,那么你会立即进入一场野生战斗
- 当然,打败或者捕捉、逃走的话,它就会消失.

1.精灵的叫声
游戏中有专门的命令负责在地图上、对话中让精灵的叫声出现,那就是Cry.来看例子:
#org $StartWild
lock
faceplayer
cry 5
message $charCry
$charcry 1 = Charmeleon:Raarg!
boxset 6
cry命令只有一个参数,就是精灵的编号.
在我们的例子中,我们所使用的是Charmeleon这只精灵,它的编号就是5.
当然,在和它战斗之前,我们必须确认主角是否得到了该道馆的徽章,以下是一份徽章资料:
0x807 - First Badge - Stone Badge
0x808 - Second Badge - Knuckle Badge
0x809 - Third Badge - Dyamo Badge
0x80A - Fourth Badge - Heat Badge
0x80B - Fifth Badge - Balance Badge
0x80C - Sixth Badge - Feather Badge
0x80D - Seventh Badge - Mind Badge
0x80E - Eighth Badge - Rainbow Badge
从上向下,依此是从第一至最后一个道馆的徽章,具体名称我就不再翻译了.
相信大家能够看得出来,是否拥有徽章,是用标识的形式表示的,因而我们只需要这样:
checkflag 0x808
if 0x1 goto $WildBatt
release
end
以上即可检测是否拥有第二个徽章.
下面进入战斗部分

5.2 与野生精灵战斗
来看一个极其简单的脚本:
#org $Wildbatt
lock
wildbattle 5 20 1
不错,命令wildbattle就是触发野生精灵战斗的命令,它携带了三个参数,分别是<精灵><等级><模式>.前两个参数没什么好说的,都是10进制的合法数字即可,而最后的模式,则表示战斗进行的场地类型:
0 = 草丛
1 = 水中
2 = 山地
3 = 沙漠
不过这个参数在不同版本的游戏中是不同的.
另外就是,如果在战斗中你失败了,那么会在就近的PC中复活,这一步在写脚本时是不必考虑的,唯一需要注意的则是release和lock的位置.
3为了告诉游戏我们已经和此精灵战斗过了,我们需要再设立一个标识在此之后,我们必须刷新屏幕,使那只精灵消失:
#org $StartWild
lock
faceplayer
cry 5
message $charCry
$charcry 1 = Charmeleon:Raarg!
boxset 6
checkflag 0x808
if 0x1 goto $WildBatt
release
end

#org $Wildbatt
lock
wildbattle 5 20 1
release
setflag 0x500
fadescreen 0
end
这里fadescreen 0就是刷新屏幕,具体的用法暂时不必管它.

5.3 寻找训练师
为了清楚的说明和训练师战斗的命令,我们需要三个例子:
1. 简单的对战训练师.
2. 2VS2的战斗.
3. 和道馆首领的战斗.
L:在原英文教程当中,作者还用到了Advanced Battle和Elitemap的附带程序advancebattleevo作为参照演示,本文略去.
现在来看我们的命令:
Trainerbattle <模式> <训练师> <挑战语> <结束语> <附加选项>
以下是模式参数的可选值:
0 - 普通战斗
1 - 与馆主的战斗
2 - 再次双人战斗
3 - 与馆主的再挑战
4 - 双人战斗
5 - 普通的再挑战
L:上面参数部分本人还未实践,但总觉得2和4的位置原作者写反了

5.4 基本的训练师战斗
#org $Trainer1
lock
faceplayer
trainerbattle 0 395 $MadChall $MadDefeat
$MadChall 1 = Madeline: I am mighty... I hope!
$MadDefeat 1 = Madeline: Oh poor Numel!!!!
message $MadTalk
$MadTalk 1 = I thought having a fire pokemon\iwould help make me stronger.\pI Guess I was wrong.
boxset 6
release
end

现在来看看上面这段脚本的意义,最重要的就是trainerbattle各参数的解释:
0是表示普通对战,395则是训练师的编号,$MadChall $MadDefeat两个变量分别储存了开始挑战时和挑战结束时训练师所说的话.


5.5 双人战斗
现在我们就要用到参数<附加选项>了,我们这样写:
trainerbattle 4 258 $AMChall $AMDefeat $AMNoBattle
$AMChall 1 = Anna: The others say we're not tough\lenough for this Gym.\pMeg: Well Show Em!
$AMDefeat 1 = Anna: I guess they were right!\pMeg: Dont worry, We'll improve.
$AMNoBattle 1 = Meg:On no.\pAnna: You can't battle us with\ljust one pokemon!
那么$AMNoBattle作为附加选项的作用是什么呢?如果你能够看懂英语就会知道,当双人战没有被触发而是变为单人战时,$AMNoBattle就是结束语.
完整脚本如下:
#org $Trainer2
lock
faceplayer
trainerbattle 4 258 $AMChall $AMDefeat $AMNoBattle
$AMChall 1 = Anna: The others say we're not tough\lenough for this Gym.\pMeg: Well Show Em!
$AMDefeat 1 = Anna: I guess they were right!\pMeg: Dont worry, We'll improve.
$AMNoBattle 1 = Meg:On no.\pAnna: You can't battle us with\ljust one pokemon!
message $AMTalk
$AMTalk 1 = Anna: You just wait and see!
boxset 6
release
end

5.6.道馆馆主
作为剧情的一部分,道馆馆主的战斗和一般的训练师有所不同:
#org $Trainer1
lock
faceplayer
trainerbattle 1 114 $BernChall $BernDefeat $BernCode
$BernChall 1 = Bernie: I am might... I hope!
$BernDefeat 1 = Bernie: Oh poor Numel!!!!
message $BernTalk
$BernTalk 1 = Wow.. Colour be Burned!
boxset 6
release
end
在这种一般的模式之后,还要加上这样的 部分:
#org $BernCode
message $Congrats
$Congrats 1 = BERNIE: Your a pretty good trainer!\pAs leader of this Gym it is now my Duty to give you the Knuckle Badge.
boxset 6

setflag 0x808
jingle
message $GotBadge
$Gotbadge 1 = You recieved the Knuckle Badge!\pBERNIE: That badge will allow you to control\lall pokemon above level X\nAnd will also let your pokemon perform\lTASK outside of battle.\pWhile I'm at it you can have this!
boxset 6

giveitem 0x5f 1
message $FireStone
$FireStone 1 = That is a Firestone.\nIt will evolve some Fire type pokemon.\pAlso, There's a really strong pokemon outside.\nI couldn't catch it cause my pokemon\lweren't strong enough but you\ncan go for it if you want!
boxset 6
end
瞧,附加选项$BernCode替代了以上那么一大段脚本.
现在该联系之前的脚本了:


5.7 再次相遇的战斗
在游戏当中,除非剧情需要,否则训练师是不会和你再次战斗的.同时还要确保并不是每次见面都会触发战斗,于是我们需要用到compare命令.
当trainerbattle命令执行后,如果compare命令的配套命令LASTRESULT变成1,那么再战斗就成为了可能.结合上面的脚本,我们这样写:
trainerbattle 0 395 $MadChall $MadDefeat
compare LASTRESULT 1
if B_TRUE goto $ReBattle
最后$ReBattle的脚本会和一般的战斗脚本相同,这里就不再缀述了.

5.8 训练师的可视范围
有时候训练师如果很早就看到你并走过来,那么就会挡住道路,于是我们就必须调整训练师的可视范围.训练师的可视范围并不是在脚本当中完成的,而是需要在Advancedmap的人物"View Range"属性当中改变的,它接受的数字单位为:步.


那么文章到此就结束了,祝大家改版愉快!

[ 本帖最后由 liuyanghejerry 于 2008-2-10 04:03 PM 编辑 ]


想死你们了!

TOP

items.txt
pokemon.txt
pokescript.exe
PkmAdv.exe
已经补充了部分资料和下载,其余的有空我再补上

如果上面的地址因为防盗链而无法下载,请在本地址内下载:http://liuyanghejerry.blogbus.com/logs/15350112.html
或者在附件中可下载:

附件: 您所在的用户组无法下载或查看附件


想死你们了!

TOP

好长……|||
谁不怀念苏联,谁就没有良心;谁想回到苏联,谁就没有头脑.

Woodu.ME--从零开始的博客生活

TOP

那个下载地址有问题~没出来地址

TOP

LS你仔细看文章了么??
原文我说到:“另外,关于教程中一些软件和技术文档的下载,我暂时还不提供下载,因为软件在中文操作系统中似乎还有一点小问题~”


想死你们了!

TOP

当然没有地址了……

替jerry给出个相关的:http://www.pkmncommunity.com/forumdisplay.php?f=66自己去找吧……某个爱尔兰女巫的帖子

TOP

更新上顶一下,希望我文章对大家改版有帮助~


想死你们了!

TOP

引用:
原帖由 liuyanghejerry 于 2008-2-2 13:54 发表
LS你仔细看文章了么??
原文我说到:“另外,关于教程中一些软件和技术文档的下载,我暂时还不提供下载,因为软件在中文操作系统中似乎还有一点小问题~”
灭哈哈~~~54以下这句话。我用的英文XP……

TOP

呵呵……似乎和编码以及内码有一定关系……但我脚本存了N种编码……
每次来网吧就用“王道”给PTB浇浇水……好习惯吧?

TOP

有你改好了的么?发个上来吧!

TOP

导入的时候第二种简单的方法感觉最好别用

TOP

技术帖。。估计很多人会无视。。

TOP

= =写出来总会有价值的……


想死你们了!

TOP

9494.。。而且对花子学习有帮助

TOP

花子……叫花子……?劳教?

话说在那个BBS上混真长见识……

TOP

那是,不过从目前的情况看……对改版不利了……


想死你们了!

TOP

恩?什么不利


我的pokemon title画面在哪里啊……

TOP

哈~全文更新完毕了,下一步就是补充完整随文的资料和工具下载了,大家稍候哦~


想死你们了!

TOP