トラキア776にはワープ/リワープの操作をキャンセルしたときにカーソルの内部値が狂うバグがあります。これの動作原理や、ロムハックでの修正方法について記載します。
Contents
ワープのカーソルバグとは何か
ワープ/リワープでの飛ばし先を指定するカーソル操作をキャンセルしたときに、カーソル位置の内部値が上書きされるバグです。ワープやリワープでカーソルを該当座標に合わせてキャンセルすると「秘密店」コマンドが出るバグとして有名なやつです。
内部的には、操作中のユニットのX座標・Y座標、カーソルのX座標・Y座標、そしてそれらをプログラムが扱いやすくした座標値をメモリに持っています。これらは行動コマンドを表示する際には一致していることを期待して各処理が実装されていますが、ワープの操作をキャンセルすると、カーソル位置が上書きされたままになっているため、乖離してしまいます。
ユニットのコマンドの表示・非表示は、操作中のユニットの移動先(各ユニットが持っている座標)で判定されますが、店などのイベント内容を参照する際はカーソル位置をもとにしているため、上記の乖離が発生すると誤った内容を読み出してしまう問題がありました。
不具合の実演動画(日本語音声、英語字幕あり)
この動画では、リモート訪問バグ、宝箱訪問バグ、リモート開錠バグについて実演しています。発生する原因はどれも同じです。
修正内容の概要
ユニットの行動コマンドの表示処理をフックし、座標リセット処理を追加すると、この不具合は発生しなくなります。
既存処理の変更
各コードは Asar の構文に従っています。
行動コマンド定義読み出しをフック
org $878391 jsl l_878358_sub warnpc $878396 padbyte $ea : pad $878396
追加処理
以下の追加処理は適当な空き領域に入れます。
座標リセット処理の呼び出し
l_878358_sub: lda.w #$8000 ; sta $2F ; jsl reset_map_cursor_pos jsl reset_map_cursor_coordinate_value rtl
カーソル位置をリセットする
reset_map_cursor_pos: sep #$20 ; A:8 lda $0E72 ; Active unit X coordinate sta $0E4D ; Map cursor X coordinate lda $0E73 ; Active unit Y coordinate sta $0E4F ; Map cursor Y coordinate rep #$20 ; A:16 rtl ;
座標値の再計算
reset_map_cursor_coordinate_value: phx ; lda $0E4F ; Map cursor Y coordinate asl A ; tax ; lda $5142,X ; Map Y direction, Each row coordinate origin clc ; adc $0E4D ; Map cursor X coordinate plx ; sta $0E4B ; Map cursor coordinate value rtl