• 4. 野外的场景(接上文)

    2008-02-10

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/liuyanghejerry-logs/15195156.html

    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"属性当中改变的,它接受的数字单位为:步.


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