街機遊戲《懲罰者》中無敵秘技的原理是什麼?

大概是這個場景,後面會出現一個紅帽子的敵人,抓住他不斷左右搖擺過一會兒就無敵了。請問導致無敵的原理是什麼?


知乎好玩就好玩在總有這麼有趣的問題。

比起你在其它地方能找到的信息,我會稍微講得詳細那麼一點點,至少比各種流言更靠譜一些,但是受限於專業水平,這個答案並不完美,權當拋磚引玉好了。知乎上程序員多,總有能幫我補充的。

——————————

我先從一個有點感人的故事講起吧。圖少字多,見諒。

這個故事講的是一位「Cheat Finder」——也就是熱衷於研究「作弊碼」的玩家。故事有點長,但我實在希望更多玩家知道這個人。

所謂「作弊碼」你大概能猜到是什麼意思,就是通過非常規的方式修改遊戲內存,實現在遊戲中作弊的效果,例如角色無限生命、瞬間獲得強力武器等等。
當然,具體改哪裡、怎麼改,都是有講究的,所以才會有人專門研究這個,他們尋找能夠實現作弊的特定的「地址+值」的組合,測試,然後分享出來,以此為樂。

在這個圈子中,從1998年就致力於製作/收集/整理/分享MAME作弊碼的Pugsy應該算得上是個大拿,他經常會發布最新版的作弊碼合集。時至今日你下載到的各種第三方打包MAME中,作弊碼部分基本都是從他的網站「Pugsy"s Cheats(http://cheat.retrogames.com)抓來的。

然而今天的主角並不是Pugsy君,而是一名叫做zakria的網友,真名Zakriya Aleem,年齡性別國籍不詳——看名字應該是阿拉伯裔男性。


2008年6月的一天,這位zakria在Pugsy的論壇上操著半生不熟的英語發了個帖:「求『懲罰者』作弊」
(http://www.mamecheat.co.uk/forums/viewtopic.php?t=3008)

『懲罰者』街機上有個秘技可以殺死全屏幕的敵人,誰能發一下啊?
抱歉我英語很差但是Pugsy很厲害他找到了『Eswat』無限特殊武器的作弊碼。這次我想要的作弊是在『懲罰者』中殺死屏幕上所有敵人,就像最新版作弊文件中那個『吞食天地2』清屏。(代碼)誰能發一下『懲罰者』的嗎?

Pugsy當時回復道:

這個作弊很難實現。我倒是做了個改版ROM能快速清屏的,但bug太多了而且還會死機。總之我有空再看看吧。

過了3個月,可能是zakria發了私信詢問研究進展,Pugsy再次回復了帖子(請注意文字的語氣態度):

我已經說過了這個作弊很麻煩,給我發私信求我給你RAM碼也沒用
1.我通常不看私信。如果你想要作弊碼不如直接發帖子,得到回答的幾率還高一點。這次的話題我最後回答一遍,然後你自求多福吧
2.改RAM行不通,因為角色在內存中是動態分配的,它需要使用「相對地址」,或者在ROM中改一大堆東西。
我也說過了我試過改ROM然後發現要修改和測試的地方太多了,每一種扣血都有自己的代碼,它們都需要被處理。我改了一點,就是之前說過特別bug的那個。反正短期內我也不會再關注這個問題了,所以發給你看看,強調,特別bug。如果你想自己改的話,你最好去學學「68000彙編」和「MAME debugger」。你需要幹掉所有跟敵人血量有關的sub.w d0,(36,ax)調用,有80個以上地方,而且說不定還得改別的。
代碼

就在這個回復的十幾天後,zakria又發了個帖子(還是半生不熟的英語):「『懲罰者』清屏作弊」
(http://www.mamecheat.co.uk/forums/viewtopic.php?t=3132)

我找到了『懲罰者』殺死所有敵人的作弊碼。這個碼不怎麼bug所有關卡都可以用它快速通過只有第一關不行。要幹掉第一關boss你可以用無限手槍那個作弊。如果Pugsy你想給這個碼改名請隨意。
代碼

可想而知,Pugsy驚詫了:

牛逼啊!這不光是「殺死所有敵人」,簡直就是「直接走著過關」的作弊啊,好多敵人根本連刷都不刷了。
你能堅持下來很好。你證明了我之前說的「改RAM行不通」是錯誤的(找個台階,我當時想得是另外一種改法來著)。

zakria回復:

謝謝Pugsy他給了我們很好用的作弊搜索器。
Miguelo(*另外一位表示驚奇的回復者),這個RAM作弊很簡單,我以前在街機上見過(*估計就是中國盜版)。

當年12月,zakria貢獻了另外一個作弊碼,帖子中又有了一段對話:
(http://www.mamecheat.co.uk/forums/viewtopic.php?f=4t=3199)
Pugsy:

謝謝,加好了……對了在cheats.txt的貢獻者名單中你想署哪個名字?zakria還是genesis?你的真名是什麼?

zakria:

謝謝Pugsy,我的名字是ZAKRIYA。我不需要署名。你說genesis,我完成他一兩個作弊請求我不太明白?

Pugsy:

抱歉,只是你們這兩個賬號發帖子用的是相同的IP地址,在我這種小眾論壇這可不是常事。我已經在cheat.txt中加上你的名字了,如果你不希望露真名請告訴我。

zakria:

我非常非常抱歉Pugsy,Qayoom(genesis)是我的朋友,我們去同一個網吧上的網。
所有的作弊碼都歸你。如果你願意加上我的名字,我的名字是Zakriya Aleem。

看到這裡,我鼻子有點酸。

這個非英語母語的玩家,磕磕巴巴地提了一個挺有意義的難題,卻被認為該難題無解的大V前輩甩了一通臉色、拒之門外。就這樣,憑著一點施捨性質的、微妙的線索,他竟花了不到兩星期(而且是在網吧)自己給解決了,解法還很漂亮,還絲毫不計前嫌、慷慨地分享出來,連署名都不要……

中東那邊世道亂,希望這哥們如今過得還好,不要捲入戰火。

——————————

故事講完了,回歸正題,說下『懲罰者』這個搖無敵是怎麼回事吧。

我就是順著zakria同志的作弊碼開始查的,他給出的修改很簡潔:把$FF5FA1這個位元組置為FF,所有敵人就自動全滅,道具一撿就碎,boss也不用打,和街機搖出無敵的效果一模一樣。

為什麼會有這樣的效果呢?

用MAME debugger的Watchpoint監視,可以簡單發現:在每一關的開頭,以及擊殺boss的瞬間,這個地址都會有寫入操作;讀取則相對非常頻繁。

結合實際現象,我推測:擊殺boss過關的時候,如果屏幕上還有雜兵活著,它們會立刻被一起幹掉,然後出結算畫面。$FF5FA1就是觸發這個判定用的。將它鎖成FF的話,遊戲就會一直以為你是剛剛過關的狀態,因此見誰秒誰。

這是清屏的通俗原理。

那麼,搖出來的無敵,跟zakria改出來的無敵,是不是一回事呢?

我用「可以搖無敵」的改版ROM(punipic)測試了一下,在第三關搖出無敵(紅衣機槍敵人掙脫)的瞬間,執行情況如下:

什麼意思?
我試著說一下啊——雖說我也算是個程序員,畢竟是有陣子沒怎麼親手寫代碼了,而且更沒怎麼弄過彙編,水平有限,如果解釋錯了你們不要噴我。

首先,發揮最關鍵作用的是$03BF34這句(ROM中是50EDDFA1)。DFA1反彙編顯示成-$205F,其實就是$FF5FA1,程序執行到這一句就會給這個地址賦值,也就是觸發了無敵狀態,然後再往下走到檢測時就會觸發殺死敵人的效果。換言之,大家熟知的搖無敵確實是$FF5FA1這個地址造成的。zakria改出來的無敵和你搖出來的無敵是一樣的。

然而正常遊戲中並不會出現無敵。

$03BF20這一步,程序會檢查D0寄存器的值,如果不等於#$7,就會從$03BF24直接跳到$03BF38,跳過了上述賦值。
D0寄存器的值是動態變化的,每一次執行到這裡都可能不一樣,因此即使在盜版街機上也不是100%能搖出無敵,能搖出來的前提是敵兵掙脫瞬間D0=7。可能是我手法差,總之這裡我暫且認為是隨機發生的。

如果第一步沒有攔住(原版也有可能通過第一步),那麼往下還會有一個檢查,在$03BF28(上圖標黃的內容)。它會檢查從$000AC6起的四個位元組是否等於#$0080014A,如果相等,就跳過去,直接到$03BF38

注意:000AC6是ROM中的內容,值是固定的。

繼續追查,原版遊戲ROM是這樣的:

看到0080014A了么?看見了就應該明白,原版遊戲中你怎麼搖也搖不出無敵的,程序100%會跳過觸發無敵的那一句,根本進不去。

能搖出無敵的盜版ROM,則是這樣的:

這裡被改成了0C409180,因此在BEQ判斷處不能正常跳轉,於是程序接下來會按順序執行$03BF34,然後就觸發無敵了。

——————————

(圖:THE PUNISHER || ENEMIES)

總結一下,在「中國大陸流行的盜版基板」中,觸發「無敵bug」的條件是「$03BF20語句執行時D0=#$7,從而未能跳過$03BF34」。而$03BF20會在特定敵兵「TRENCH」(即上圖的紅衣機槍手)從揪脖子狀態掙脫時執行,無論是時間到了自動掙脫,還是玩家搖出了前滾動作中止揪脖子。
之所以只有3、5、6關能無敵,是因為這個敵人只在這三關刷新。

以上是我可以確定的內容。

另外,我個人還有一些猜測,主觀認為可能性很高,但沒有徹底確定(精力有限,懶得通讀代碼):

1. 在「搖無敵」這個過程中,瘋狂左右晃動搖桿可能並沒有起到太大作用,只是盡量快速重複「揪脖子,掙脫」這個過程,反覆碰運氣而已。
2. 「無敵bug」不像是盜版dump ROM時失誤所致——盜版ROM和原版ROM不只是一兩位數據有出入,光是上面我截圖中顯示的,從$000AB2到$000B0D都大相徑庭,其它還有很多不同之處。我認為這個bug很可能是人為手動修改導致的。『懲罰者』的基板並不是普通的CPS,而是CPS"(搭載QSound晶元),盜版基板閹掉了QSound,勢必要在程序上有些改動。
3. 「無敵bug」也並不像是盜版者故意設計的秘技。就$03BF34這一句以及其附近的代碼而言,盜版ROM和原版ROM這裡是相同的。我傾向於認為它是盜版者修改程序時意外發生的副作用。

至於原版程序為什麼要在這個地方留一句進不去的代碼,抱歉,我也不知道。所以我說這個答案只是一知半解、拋磚引玉,等著大牛來個徹底解析吧。

就這些。禁止轉載。
(如有不同見解,歡迎在評論區補充)


有一個人經歷想要補充,按說是只有356關有紅色槍手出現,並可以搖無敵。不過在沒有紅色槍手的第四關即將上火車頂部時,有很小的幾率也會觸發無敵,注意:不是搖無敵。我本人只遇到過兩次,都是高一時單打用懲罰者弗蘭克遇到的,(可能以前技術太差過不了第二關所以沒發現。。)我想了想這個場景沒有槍手不過有紅色的女忍以及紅褲子的嗑藥瘦猴雜兵出現。所以我一直有個猜想是不是無敵的觸發跟顏色有關。。。

不知還有其沒有他人在第四關觸發過無敵。

另外還有盜版三國的小兵關羽的出現原理也很好奇。還有傳說中的四打恐龍島四打三國到底是不是真的存在。


我曾經是格鬥中國的romhacker,我曾經修改出了the punisher的被屏蔽的隱藏關!我仔細看了Thinkraft的說明,我覺得他說的很對。最大的可能性就是遊戲本身就設計了這段代碼,比如用於調試等作用。但是最後沒採用。不知道為什麼,盜版的ROM里可以通過搖人的方式,使得程序跳進這個無敵的代碼里去。


以前玩的時候完全沒注意過獨眼人的名字, 原來是神盾局長......


搖敵人的時候,如果被另一個敵人幹掉,會出現一些bug,比如主角動作播放問題,被搖的敵人狀態處理問題。於是程序員想能不能暫時無敵,反正出了bug別人一時半會發現不了,於是由於某個停止搖的狀態切換bug導致無敵狀態沒有結束。所謂的用一個bug去掩蓋另一個bug。


其實這是懲罰者中國盜版的bug,在原版裡面不能使用
就是下圖的紅人,抓住之後左右搖晃搖桿,就會出現人物無敵的情況
http://v.youku.com/v_show/id_XMTY0MDEwMTkwOA==.html?xsharefrom=android
(這是我錄的視頻鏈接)


我們管這個遊戲叫二百多


第四關火車上確實也能觸發無敵。我小學時非常愛玩這個遊戲,一開始也搖無敵,不過後來,我都不搖了,直接硬擼2,3,6的boss,一幣通關。有一次,竟然有個小夥伴,主動給我一個幣,讓我表演硬擼


借這個問題順便問問圓桌騎士亂步原理


這遊戲比恐龍快打好多了,角色絕招多


盜版街機主板在dump的時候數據錯誤,出現bug了。正版上面是是沒有的。

後來用模擬器玩,搖到手斷都搖不出了……


這個遊戲我小時候叫快四兒。


小時候總能打通關,但是現在完全想不起來怎麼打過去的?


推薦閱讀:

有人試過編寫個程序來炒股嗎?
回調函數(callback)是什麼?
對於一個編程基礎不是很好的學生來說,學習數據挖掘、機器學習之類的並以後從事這樣的工作靠譜嗎?
為什麼有些驗證碼看起來很容易但是沒人做自動識別的?
用 Linux 真的能學到很多平台無關的東西嗎?

TAG:遊戲 | 遊戲開發 | 編程 | 街機遊戲 |