口袋妖怪綠寶石——數(shù)據(jù)提取與代碼分析(4-地圖信息提取——Advance Map配置文件)
說在前面:
????上期專欄介紹了利用Advance Map提取口袋妖怪綠寶石ROM中的地圖信息。雖然Advance Map的功能很強(qiáng)大,但是作為一個(gè)超過十年沒有更新、并且軟件作者表示再也不會修復(fù)bug的軟件,有缺陷是在所難免的。
????本期專欄的目的只有一個(gè):讓Advance Map順利地打開一個(gè)綠寶石系列游戲的ROM。

Advance Map的配置文件
????其實(shí)Advance Map不僅能打開綠寶石的ROM,紅/藍(lán)寶石、火紅/葉綠系列的ROM也能打開,但是對于這些不同的游戲版本,ROM中各種游戲數(shù)據(jù)所在的地址各不相同,Advance Map是怎樣識別ROM的游戲版本、并根據(jù)游戲版本找到正確地址上的數(shù)據(jù)呢?
????答案在于Advance Map的配置文件。
????在Advance Map安裝目錄下的Ini文件夾中,有一個(gè)名為AdvanceMap.ini的文件就是Advance Map的配置文件,可以用VS Code打開看一下:

????這個(gè)文件使用的語言甚至不是英語,而是德語。這給修改配置文件帶來了一定程度上的理解困難。本期專欄盡可能把有用的配置都說明一遍。
????第3行:
????這里列舉的是Advance Map能夠識別的游戲ROM類型,其中BPR是火紅,BPG是葉綠,BPE是綠寶石,AXP是藍(lán)寶石,AXV是紅寶石。
????112行之前的內(nèi)容對于打開ROM來說并不需要修改,雖然其中一些配置試圖把道具名稱和招式名稱的數(shù)量確定下來,但是軟件本身不支持漢化版本,即使能夠列舉出來也是亂碼,就沒有修改的必要了。
????從第112行開始,就是更改配置文件的關(guān)鍵所在,從這里之后的信息對于Advance Map能夠正確打開ROM文件至關(guān)重要!

????從第112行開始,配置文件呈現(xiàn)出段落的特點(diǎn),每個(gè)段落之間用空行隔開,每個(gè)段落描述一條配置。
????一條配置描述了一個(gè)Advance Map需要用到的游戲數(shù)據(jù),包含了它的名稱(用中括號括起來的德語單詞)、類型(art=所在的行)、尋找該數(shù)據(jù)在ROM中位置的方法(nach=所在的行,還有其他可能的尋找方法)、適用的游戲版本(spiele所在的行)。這些art, nach, spiele就是Advance Map的作者給它的配置文件定義的一種語法。接下來本專欄會把配置信息中所有可能遇到的語法都解釋一遍。

????先來解釋第一條配置:
????第一行,用中括號括起來的是游戲數(shù)據(jù)的名稱,也就是符號表中的符號。但是這里的符號是用德文寫的,為了方便理解,需要把它轉(zhuǎn)換成符號表里的英文符號,然后在源代碼項(xiàng)目里找到該符號的用法才能明白這個(gè)數(shù)據(jù)是什么含義。
????從第二行開始,每一行的格式都是“……=……”的樣子,等號前面表示這個(gè)數(shù)據(jù)的屬性,等號后面表示該屬性的取值。
????第二行,art屬性為pointer,表示這個(gè)名字叫FlugposHeader的數(shù)據(jù)類型是一個(gè)指針,也就是ROM中的4個(gè)字節(jié)。后面還會提到,有的數(shù)據(jù)的art屬性為offset,這是ROM中的一個(gè)地址。
????第三行,nach屬性的用途是告訴Advance Map要在ROM的什么位置找到這個(gè)數(shù)據(jù),等號的后面是一串字節(jié)序列,我們用HxD在原版綠寶石ROM中搜索這串字節(jié)序列:

????nach在德語中有“之后”的含義,這串字節(jié)序列后面的4字節(jié)3C F5 59 08就是FlugposHeader了,拼接起來就是0859F53C,可以在符號表中找到它的英文名是sHealLocations

????也就是說,德文名FlugposHeader對應(yīng)的是符號表里的sHealLocations,轉(zhuǎn)到它的定義:

????說明sHealLocations的含義是列舉每個(gè)城鎮(zhèn)寶可夢中心的一些信息。如果要使用Advance Map打開一個(gè)新的ROM,再搜索nach后面的字節(jié)序列可能就沒有結(jié)果了,這時(shí)就需要找到這個(gè)新ROM里面的sHealLocations在哪,然后根據(jù)指針的位置調(diào)整nach后面的字節(jié)序列,這樣才能讓Advance Map找到。
????第四行,spiele屬性表示這條數(shù)據(jù)在哪些版本中存在,F(xiàn)lugposHeader這里把5個(gè)版本都列舉出來,說明對于所有已知的版本都存在這個(gè)數(shù)據(jù)。
????之后的配置格式和第一個(gè)配置是相似的,因此接下來只解釋一些新出現(xiàn)的屬性名。

? ? 這里新出現(xiàn)了一個(gè)屬性名nummer,它表示的是字節(jié)序列的第幾個(gè)搜索結(jié)果。在HxD中搜索nach后面的字節(jié)序列,可以看到兩個(gè)結(jié)果:

????nummer=1指的是第一個(gè)搜索結(jié)果對應(yīng)到AnbindungsListe這條數(shù)據(jù)。而接下來的
????用的是同一個(gè)字節(jié)序列,但這里nummer=2,說明第二個(gè)搜索結(jié)果對應(yīng)到SpriteHeader。

????這里nach不見了,取而代之的是vor屬性,后面仍然跟著一個(gè)字節(jié)序列。vor在德文中有“之前”的含義,因此這里搜索字節(jié)序列后,不是取出字節(jié)序列后面的4個(gè)字節(jié),而是它前面的4個(gè)字節(jié):

????也就是說,在上圖中應(yīng)該取0850BE38,而不是78004804(這顯然不是一個(gè)合法的指針)

????新的屬性plus,指的是找到字節(jié)序列后,還要向后偏移多少個(gè)字節(jié)才能找到數(shù)據(jù):

????這里plus=6,也就是從找到的字節(jié)序列末尾(0008EA0A)開始,向后6個(gè)字節(jié)(0008EA10)處的4個(gè)字節(jié)拼接起來就是SpritePalHeader,也就是0850BD00。

????這個(gè)配置的spiele一行并沒有出現(xiàn)BPE,說明這個(gè)數(shù)據(jù)在綠寶石版本的游戲中是不存在的,因此也就沒有必要修改。AXP/AXV后面加上的J或者E表示這是發(fā)行在哪個(gè)國家的游戲版本,J是日本,E是北美、歐洲。

????
????新的屬性position,這是直接告知了PokemonNamen2這個(gè)指針?biāo)诘牡刂罚?0000144),只需要把這里的4個(gè)字節(jié)拼接起來就是它的取值了。000144前面的$符號表示這是一個(gè)十六進(jìn)制數(shù)。

????這里沒有新的屬性,但是nach后面的字節(jié)序列中出現(xiàn)了XXXX,這放在HxD中是沒辦法搜索的。這里的XXXX表示匹配任何字節(jié)(有點(diǎn)像正則表達(dá)式的用法)。

????這里art屬性的取值不再是pointer,而是offset,含義是這個(gè)數(shù)據(jù)表示ROM中的一個(gè)位置(同樣也是4個(gè)字節(jié),但并不是取4個(gè)字節(jié)拼接而成),nach說明是這個(gè)字節(jié)序列后面的位置。在HxD中也可以找到這個(gè)字節(jié)序列:

????圖為搜索字節(jié)序列200CE000000000的結(jié)果(因?yàn)閄X無法在HxD中搜索),這個(gè)字節(jié)序列后面的位置(也就是字節(jié)FE所在的位置)是0012388E,這就是WeltkarteGroesse的取值。

????nach配合plus屬性向后偏移,與之對應(yīng)的就是vor配合minus屬性向前偏移。

????這里FlugWert的取值是085A1E3C,也就是vor屬性的字節(jié)序列在ROM中的位置(00124EE0)向前偏移4個(gè)字節(jié)(00124EDC),在這個(gè)地址向前的4個(gè)字節(jié)拼接而成。

????新的屬性bei,這個(gè)bei的含義與nach和vor相對,既不是“在……之前”,也不是“在……之后”,而是“在……位置”的意思。結(jié)合art=offset,也就是說這個(gè)字節(jié)序列在ROM中所在的位置就是GeheimBasisZuordnung的取值:

????從HxD的搜索結(jié)果來看,GeheimBasisZuordnung的取值是000E8F9C。

????這條配置定義了兩個(gè)新的數(shù)據(jù)tileset和palette,前面的plus表示這兩個(gè)數(shù)據(jù)的地址相對于PokeNaveTownTileset的偏移(plus表示加上偏移量)。

需要修改哪些配置????
????第495行的“Einstellungen”指的是Advance Map在上一次打開時(shí)的設(shè)置情況,從這一行向后的內(nèi)容就不需要修改了。也就是說,為了成功打開ROM,只需要修改從112行到第495行之間的配置。
????如果只把打開ROM的類型限制在綠寶石系列游戲的改版上,那就并不需要修改從112行到第495行之間所有的配置,只需要修改一部分就可以了。
????每一個(gè)用德文命名的數(shù)據(jù),在符號表中都可以找到對應(yīng)的符號名稱。下面列舉出來需要修改的配置以及它對應(yīng)在符號表內(nèi)的名稱:
? ? 要成功打開一個(gè)綠寶石系列的ROM,只需要修改上面列表里提到的配置就可以了。

打開ROM的步驟
????為了成功打開ROM,利用Advance Map的報(bào)錯(cuò)信息也很關(guān)鍵,例如下面這個(gè)報(bào)錯(cuò)信息:

????這個(gè)報(bào)錯(cuò)信息說明Advance Map找不到MapBankHeader這個(gè)數(shù)據(jù)的位置,這就說明我們需要修改配置文件中的MapBankHeader這個(gè)配置,它在第117行。
????如果這一條配置已經(jīng)被修改正確,那么再次打開ROM的時(shí)候報(bào)錯(cuò)信息就會發(fā)生變化??梢愿鶕?jù)報(bào)錯(cuò)信息的提示逐一修改配置文件。
????注意:如果報(bào)錯(cuò)信息中提到的配置沒有出現(xiàn)在上面那張表格中,則可以忽略不看,此時(shí)即使有報(bào)錯(cuò)信息,Advance Map仍然能夠成功打開地圖。

地圖名稱亂碼問題
????下圖為經(jīng)過修改配置之后,使用Advance Map成功打開的某個(gè)漢化版綠寶石ROM:

????可以看到左側(cè)所有的地圖名稱都是亂碼。并且在試圖打開0號地圖庫的11號地圖時(shí),Advance Map還會報(bào)錯(cuò),這是因?yàn)槊Q中出現(xiàn)了沒有匹配的括號(有個(gè)左括號沒有右括號對應(yīng)),這也是Advance Map不支持漢化的重要缺陷,其實(shí)這個(gè)地圖的信息已經(jīng)加載到Advance Map中了,但是這個(gè)混亂的名稱導(dǎo)致它無法被打開。
????解決這個(gè)問題的方法就是向Advance Map妥協(xié):修改這個(gè)地圖的名字。所有地圖的名字以列表的形式存儲在ROM中,所以使用本系列專欄口袋妖怪綠寶石——數(shù)據(jù)提取與代碼分析(1-字符集與文本信息的提取)的方法可以把所有的地圖名稱提取出來。在原版ROM中,地圖名稱的起始地址在085a0b10處,它在符號表中的名字是sMapName_LittlerootTown。在改版的ROM中,可以通過搜索地圖名稱對應(yīng)的編碼字節(jié)序列來找到需要修改的地圖名。
????在HxD中,修改ROM十分方便,將光標(biāo)指向想要修改的地方,直接使用鍵盤輸入即可。

????
????用了一期專欄的時(shí)間來講Advance Map的配置文件如何修改的問題,但實(shí)際上有一個(gè)最關(guān)鍵的問題沒有解決。以MapBankHeader為例,在原版綠寶石中可以通過符號表、源代碼項(xiàng)目等資源來找到這個(gè)數(shù)據(jù)的位置以及它的含義,但是在沒有符號表和源代碼的改版ROM中,找到MapBankHeader的難度還是很大的,這需要對改版ROM的程序有一些基本的了解,這正是本系列專欄后續(xù)需要講到的問題。
? ? 繼續(xù)感謝眾位讀者的支持!