TOP > プログラミング関係解説&調査 > 幕末編のザコ敵 > 固有名称処理

幕末編のザコ敵 > 固有名称処理

当ページの内容は、ある程度のプログラミングの知識を必要とする。
まず、プログラミング関係解説&調査をひととおり読んでいただきたい。

前ページの続き。
タイプ「NAME」の敵のステータス変動は前ページで説明した通りである。
戦闘開始直後、ウィンドウ上に敵の名前が表示されるまでに、1~2体目のステータスがセットされ、2体目についてはステータス変動の値が[$7E:AA13][$7E:AA16][$00:1A25][$00:1A28]に入った後の処理になる。

まずは「敵の名前」の元データがどこのアドレスに格納されているのかを説明しなければなるまい。

「敵の名前」と文字コード

デジタルデータを、特定のルールに基づいて別の符号に変換することをエンコード、その逆をデコードという。
動画や音声データでもエンコードという用語を使うので、プログラミングを知らなくても聞いたことはあるという方もいるだろう。
スーパーファミコンのゲームでいえば内部データはすべて16進数だから、ありとあらゆるデータが16進数にエンコードされていることになるが、とりあえずここではテキストデータの話に絞る。

敵の名前もだが、技名やキャラクター名といった、セリフ以外のシステム周りのテキストデータは、アドレス$D6:AC00$D6:CFFF$02:9380$02:A695に格納されている(バンク$D6については、おそらく意味のある文字列は$D6:CFC3まで)。
それらは本作の文字コード表に従って変換される。
この「ライブ・ア・ライブ用文字コード表」こそが、上でいう「特定のルール」である。
文字コード表(Google スプレッドシート)

通常の文字から文字コードに変換することがエンコード、文字コードから通常の文字に変換することがデコード、ということになる。

「ライブ・ア・ライブ用文字コード」のルールでは、1文字あたり、ひらがな・カタカナ・アルファベット・記号は1バイト、漢字は2バイトのデータを使う。
1バイトの場合は上表に対応した値をそのまま使うが、漢字は上位バイトに$1D$1E$1F、下位バイトに$00$FFの数値を入れて、$1D??, $1E??, $1F??とする。

幕末編の固有名称のあるザコ敵の固有名称は、$D6:C2B5$D6:C526に入っている。
入っているデータは16進数のデータで、そのまま日本語として読むことはできない。
16進数のデータを、上表に従って変換(デコード)してみると以下の通り。
(なお、筆者がJavaScriptで該当テキストをデコードしてみたのがこちら(JavaScript Online | paiza.IO)
実際には、名前と名前の間には$00が入っていて区切りとしてあるが、以下ではわかりやすいように表形式で区切るようにした。
開始アドレスは一部のみ抜粋。

開始アドレスデコード結果
$D6:C2B5シモフリスズメ
シロヒトリ
ヤママユ
エゾヨツメ
オオスカシバ
エダシャク
$D6:C2DDてっせん
すいれん
ばしょう
$D6:C2EEやたろう
$D6:C2F3ごんすけ
$D6:C2F8せんた
$D6:C2FCごんしち
$D6:C301さんじ
$D6:C305ごんぱち
$D6:C30Aすけろく
$D6:C30Fきんじ
$D6:C313すけぞう
$D6:C318きんじ
$D6:C31E筑波 一郎
$D6:C328早田 二郎
$D6:C332日体 三郎
$D6:C33C悪細 四郎
$D6:C346武蔵美 五郎
青山 六郎
防衛 七郎
明治 八郎
九大 九郎
北大 十郎
$D6:C384東 十一郎
$D6:C390今 育蔵
生野 矢多蔵
良和 伊蔵
原伊 太蔵
仏己 侶吹蔵
方牙 小留蔵
伊角 西蔵
$D6:C3DC三船 二郎左
小倉 予志法
猛木 刀士之
大久魔 英鬼
加藤 清文
坂口 知由市
田中 高破流
村上 影久
田中 新一
時田 獣神丸
$D6:C450ベリー
ナイス
$D6:C45A越前屋
大黒屋
越後屋
清水屋
$D6:C478日野
立川
高尾
中野
小平
$D6:C493トキ
アズサ
シオサイ
コダマ
アオバ
ホクト
マツカゼ
クロシオ
$D6:C4B7つぐみ
ひがら
ひたき
あおじ
ましこ
$D6:C4CDおまつ
おいち
おみや
おせい
おえつ
おせん
おすぎ
おたけ
おさだ
$D6:C4F3春日田の方様
$D6:C4FFキヌガサ
ベニテング
ドクササコ
ショウロ
アイゼン
コンゴウ
フドウ
$D6:C523アシュラ

「X($58)」を区切りとして、忍者(2人組)、虚無僧、奴、浪人、藩士、強藩士、外人、商人、家老、忍者(1人)、くの一、腰元、忍者(4人組)の順に名前が並んでいることがわかる。
ただ、ゲーム本編では採用されなかった名前も含まれている。いわゆる没データである。

サブルーチン

今回は前ページからの続きとして、奴×2の初戦でのサブルーチンを例に説明する。
つまり奴1体目の「やたろう」、2体目の「ごんすけ」との戦闘である。

前ページの処理の最中に、「敵データ15と$F0の論理積 + 奴の遭遇数-1」が[$7E:AD0F+ x*$10] (敵番号x)が入っていたことも、固有名称の処理で重要になってくる。
つまり、奴×2の初戦では、名称処理の前に、

アドレス数値
[$7E:AD0F]$40
[$7E:AD1F]$41

が入った状態である。

では、重要な部分のサブルーチンを見てみる。
といいつつ、$C1/3DDBからしばらくは、実質、呼び出し先アドレスを計算しているようなものなので、適当に流し見で構わない。
大雑把には、タイプ「NAME」の敵だと、$C1/3DE1でゼロフラグが立たないため、$C1/3DE3以降がNAME用の処理である。

$C1/3DDB LDA $002F,y[$00:1A2F]   ;Aに[$00:1A25](敵データ15)をロード
$C1/3DDE PLY                     ;Yレジスタに値をプル
$C1/3DDF AND #$F0                ;Aと$F0と論理積(上1桁)
$C1/3DE1 BEQ $0C    [$3DEF]      ;ゼロフラグが立っているとき[$3DEF]分岐
$C1/3DE3 LDA $7E920F,x[$7E:AD0F] ;[$7E:AD0F](=$40)をロード
$C1/3DE7 STA $DC    [$00:03DC]   ;[$00:03DC]に書き込み
$C1/3DE9 LDA #$03                ;Aに$03をロード
$C1/3DEB STA $DD    [$00:03DD]   ;[$00:03DD]に書き込み
$C1/3DED BRA $07    [$3DF6]      ;フラグにかかわりなく常に分岐[$3DF6]
$C1/3DF6 PHB                     ;DBレジスタの値をスタックに積み
$C1/3DF7 LDA #$D6                ;Aに$D6をロード
$C1/3DF9 PHA                     ;Aレジスタの内容をスタックに積み
$C1/3DFA PLB                     ;DBレジスタに値をプル
$C1/3DFB LDX #$1E00              ;Xに$1E00をロード
$C1/3DFE STX $D8    [$00:03D8]   ;Xを[$00:03D8]に書き込み
$C1/3E00 REP #$21                ;Aレジスタは16bit幅, Cフラグクリア
$C1/3E02 LDA $DC    [$00:03DC]   ;Aに[$00:03DD][$00:03DC]をロード
$C1/3E04 ASL A                   ;算術左シフト *2
$C1/3E05 ADC $0038  [$D6:0038]   ;A+[$D6:0039][$D6:0038]
$C1/3E08 TAX                     ;Aレジスタの値をXレジスタに転送
$C1/3E09 LDA $0000,x[$D6:A680]   ;Aに[$D6:A681][$D6:A680]をロード
$C1/3E0C CLC                     ;キャリーフラグクリア
$C1/3E0D ADC $0028  [$D6:0028]   ;A+[$D6:0029][$D6:0028]
$C1/3E10 STA $DC    [$00:03DC]   ;Aを[$00:03DD][$00:03DC]に書き込み = $C2EE(奴1体目の名前開始アドレス[$D6:C2EE])
$C1/3E12 SEP #$20                ;Aレジスタは8bit幅, CフラグON
$C1/3E14 PLB                     ;DBレジスタに値をプル
$C1/3E15 JSR $506C  [$C1:506C]   ;[$C1:506C]へ

$C1/3DDB$C1/3E15が、奴1体目の名称のアドレス位置の計算である。
先に記した、[$7E:AD0F]の値$40[$00:03DC]に書き込まれ、更に+1したアドレス[$00:03DD]$03が書き込まれている。
16bitモードで[$00:03DC]をロードすると、上1バイトが[$00:03DD]、下1バイトが[$00:03DC]の2バイトがAにロードされるから、A$0340が入る。
この値を算術左シフトで*2した値$0680に、[$D6:0039][$D6:0038]の数値を加算した$A680をアドレスとして、[$D6:A681][$D6:A680]の数値をロードし、更にここに[$D6:0029][$D6:0028]を加算すると奴の名前開始アドレスになる……と、何かややこしくはあるが、こんな手順でやっと、呼び出したいアドレスの位置が[$D6:C2EE]と算出されたことになる。
このあたりは、そういうものだと思っておいていただいて構わない。
ステータス計算の最中に記録した[$7E:AD0F]は、敵名称取得アドレス計算のための値だったのである。
奴2体目の場合は、[$7E:AD1F]に入っている値$41で計算していくため、$C1/3E10で計算された値は「$C2F3」になる。
つまり奴2体目の名前開始アドレスは[$D6:C2F3]である。

続いて、実際に[$D6:C2EE]以降の値をロードして、文字コードからデコードするのだが、先に述べた通り、本作の文字は漢字だと2バイト(上1バイトに$1D$1E$1Fのいずれかがつく)で、それ以外は1バイトと、文字種によって容量が変わるので、その判別も行う必要がある。

$C1/506C LDX #$B000              ;Xに$B000をロード
$C1/506F STX $D6    [$00:03D6]   ;Xを[$00:03D6]に書き込み
$C1/5071 LDA #$00                ;Aに$00をロード
$C1/5073 STZ $E0    [$00:03E0]   ;[$00:03E0] = $00
$C1/5075 RTS                     ;サブルーチン戻り
;
$C1/3E18 LDA #$10                ;Aに$10をロード
$C1/3E1A STA $E3    [$00:03E3]   ;A($10)を[$00:03E3]に書き込み
$C1/3E1C STA $E1    [$00:03E1]   ;A($10)を[$00:03E1]に書き込み
$C1/3E1E LDA #$01                ;Aに$01をロード
$C1/3E20 STA $E2    [$00:03E2]   ;A($01)を[$00:03E2]に書き込み
$C1/3E22 STZ $DF    [$00:03DF]   ;[$00:03DF] = $00
$C1/3E24 LDA #$D6                ;Aに$D6をロード
$C1/3E26 BRL $0022  [$3E4B]      ;フラグにかかわりなく常に分岐[$3E4B]
$C1/3E4B JSR $3E61  [$C1:3E61]   ;[$C1:3E61]へ
;
$C1/3E61 LDX #$0000              ;Xに$0000をロード
$C1/3E64 PHB                     ;DBレジスタの値をスタックに積み
$C1/3E65 PHA                     ;Aレジスタの内容をスタックに積み
$C1/3E66 PLB                     ;DBレジスタに値をプル
$C1/3E67 PHY                     ;Yレジスタの内容をスタックに積み
$C1/3E68 LDY $DC    [$00:03DC]   ;Yに[$00:03DD][$00:03DC](=$C2EE)をロード
$C1/3E6A CMP #$7E                ;Aと$7Eを減算比較(ステータスフラグ変更のみ)
$C1/3E6C BNE $04    [$3E72]      ;ゼロフラグが立っていないとき[$3E72]分岐
$C1/3E6E LDA #$0C                ;Aに$0Cをロード
$C1/3E70 BRA $02    [$3E74]      ;フラグにかかわりなく常に分岐[$3E74]
$C1/3E72 LDA #$60                ;Aに$60をロード
$C1/3E74 STA $08    [$00:0308]   ;A($60)を[$00:0308]に書き込み
$C1/3E76 STZ $09    [$00:0309]   ;[$00:0309] = $00

[$D6:C2EE]~をロードするための前準備になるが、[$00:0308]はループ回数計算用の値が入る。
ループ回数は、Aと、$C1/3E6A$7Eを減算比較し、ゼロフラグが立つ場合は$0C、ゼロフラグが立たない場合は$60Aに読み込み、[$00:0308]に書き込まれる。
$C1/3E6Aに入っているAは、$C1/3E24A$D6が読み込まれているから、ゼロフラグが立つことはない。
つまり[$00:0308]には$60が入る。
この後のループでは、Xの値を漢字なら+2、それ以外なら+1して、累計でX$60になったらループ停止になる。
漢字なら48文字、それ以外のひらがなやカタカナなどは96文字分、読み込むということである。
また、読み出した値は、[$7E:FF00]から順に入っていく。
今回は[$7E:FF60]まで値が入ることになる。

では、奴の1体目の最初の文字から読み込み始めると、どの文字まで読み込むのだろうか。
奴1体目の名称が取得できればそれで良いのだが、実際にはかなり余分にデータを読み込むようになっている。
ループ処理を含めて見てみる。

;名称一覧から文字呼び出しサブルーチン
$C1/3E78 LDA $0000,y             ;Aに[$D6:C2EE + n](奴の1人目名前開始地点)をロード
$C1/3E7B INY                     ;Yをインクリメント +1
$C1/3E7C CMP #$1D                ;Aと$1Dを減算比較(ステータスフラグ変更のみ)
$C1/3E7E BEQ $2D    [$3EAD]      ;ゼロフラグが立っているとき[$3EAD]分岐
$C1/3E80 CMP #$1E                ;Aと$1Eを減算比較(ステータスフラグ変更のみ)
$C1/3E82 BEQ $29    [$3EAD]      ;ゼロフラグが立っているとき[$3EAD]分岐
$C1/3E84 CMP #$1F                ;Aと$1Fを減算比較(ステータスフラグ変更のみ)
$C1/3E86 BEQ $25    [$3EAD]      ;ゼロフラグが立っているとき[$3EAD]分岐
$C1/3E88 CMP #$0E                ;Aと$0Eを減算比較(ステータスフラグ変更のみ)
$C1/3E8A BEQ $16    [$3EA2]      ;ゼロフラグが立っているとき[$3EA2]分岐
$C1/3E8C CMP #$07                ;Aと$07を減算比較(ステータスフラグ変更のみ)
$C1/3E8E BNE $26    [$3EB6]      ;ゼロフラグが立っていないとき[$3EB6]分岐
;A = $0E または $07の時 $C1/3EA2~$C1/3EAB
$C1/3EA2 LDA #$21                ;Aに$21をロード
$C1/3EA4 STA $7EFF00,x           ;Aを[$7E:FF00 + x]に書き込み
$C1/3EA8 INX                     ;Xをインクリメント + 1
$C1/3EA9 LDA #$00                ;Aに$00をロード
$C1/3EAB BRA $09    [$3EB6]      ;フラグにかかわりなく常に分岐[$3EB6]
;漢字用処理 $C1/3EAD~$C1/3EB5
$C1/3EAD STA $7EFF00,x           ;Aを[$7E:FF00 + x+1]に書き込み
$C1/3EB1 INX                     ;Xをインクリメント + 1
$C1/3EB2 LDA $0000,y             ;Aに[$D6:C2EE + n+1]をロード
$C1/3EB5 INY                     ;Yをインクリメント + 1
$C1/3EB6 STA $7EFF00,x           ;Aを[$7E:FF00 + x]に書き込み
$C1/3EBA INX                     ;Xをインクリメント + 1
$C1/3EBB CPX $08    [$00:0308]   ;Xレジスタと[$00:0308]を減算比較
$C1/3EBD BCC $B9    [$3E78]      ;キャリーフラグが立っていないとき[$3E78]分岐
;名称一覧から文字呼び出しサブルーチン ここまで

$C1/3EBF LDA #$00                ;Aに$00をロード
$C1/3EC1 STA $7EFF00,x[$7E:FF61] ;Aを[$7E:FF61]に書き込み
$C1/3EC5 PLY                     ;Yレジスタへ値をプル
$C1/3EC6 PLB                     ;DBレジスタへ値をプル
$C1/3EC7 RTS                     ;サブルーチン戻り

$C1/3E7C$C1/3E86は、値が$1D$1E$1Fかどうか、つまり漢字かどうかの判定であり、漢字の場合は$C1/3EADにジャンプする。
$C1/3EB1X+1して、次のアドレスを読み出している。
つまり、漢字2バイト分のデータの下1バイトを読み出し、同時にX+1しているので、漢字の場合はX+2される。

また、呼び出した値が$0Eまたは$07の時には、$C1/3EA2~の処理が行わえる。
A$21を上書きして[$7E:FF00 + x]に書き込み、X+1してA$00をロード、となっている。その後$C1/3EB6にジャンプである。
つまり、この時のみ、[$7E:FF00]以降に書き出す時、$21$00と書き出してX+2している。
$0Eは「!(改行)」、$07は「‥‥」なのだが、おそらくシステム上のテキストの時にはテキスト区切り処理に変更されるのだと思われる(未確認)。
とりあえず、幕末編の固定名称データの中に該当の値はないので、$C1/3EA2$C1/3EABにジャンプすることはないはずである。
基本的には、$C1/3EAD~の漢字処理か、それ以外のひらがな・カタカナなら$C1/3E8Eから$C1/3EB6にジャンプして、読み出した値を[$7E:FF00 + x]に書き出すことになる。

また、ループが終わると、[$7E:FF61]$00を書き込むことがわかる。

この処理を[$7E:FF00][$7E:FF60]まで行った結果、順に入る文字は以下のようになる。

開始アドレス名前
$7E:FF00やたろう
$7E:FF05ごんすけ
$7E:FF0Aせんた
$7E:FF0Eごんしち
$7E:FF13さんじ
$7E:FF17ごんぱち
$7E:FF1Cすけろく
$7E:FF21きんじ
$7E:FF25すけぞう
$7E:FF2Aきんじ
$7E:FF2E
$7E:FF30筑波 一郎
$7E:FF3A早田 二郎
$7E:FF44日体 三郎
$7E:FF4E悪細 四郎
$7E:FF58武蔵美 五

X0から$60に増えるまでループした結果、「武蔵美 五郎」の「武蔵美 五」まで読み込み・書き出しをしたところで[$7E:FF60]まで値が埋まり、ループが終了する。
という、中途半端なループになっているが、これは他の部分の処理との兼ね合いもあるので仕方がない。
しかも、この処理はあくまでも奴1人目の処理なので、必要なのは最初の4文字、「やたろう」の部分だけである。
強いていうならキャラ名とキャラ名の間は必ず$00で区切られているので、区切り判別のため、「やたろう」+1文字分だけで充分なのだが、実際にはこれだけデータの処理をしている。

なお、奴2人目の処理の時は、このデータを使い回す訳ではなく、新たに「ごんすけ」の「ご」のアドレス([$D6:C2F3])からループ処理を行う。

$7E:FF00~に入った具体的な値を、今回必要となる「やたろう」の部分だけ載せると以下のようになる。おまけで「ごんすけ」の分も載せておく。

開始アドレス値(文字)
$7E:FF00$D4(や)
$7E:FF01$C0(た)
$7E:FF02$DB(ろ)
$7E:FF03$B3(う)
$7E:FF04$00
$7E:FF05$EB(ご)
$7E:FF06$DD(ん)
$7E:FF07$BD(す)
$7E:FF08$B9(け)
$7E:FF09$00

さて、文字のデコードだが、スーパーファミコンの時代のゲームの場合(この前後あたりの時代もそうだろうが)、文字は画像(いわゆるドット絵)として格納されている。
(リメイク版発売の2020年代のゲームでは、文字は画像データではなく、パソコン等と同じTrueTypeフォント形式などを使用していることが大半のようだ)

「やたろう」の「や」は文字コードで$D4になるが、ここからさらに「や」の文字の「画像データ」を取り出して表示することになる。
スーパーファミコンの画像データ処理については、筆者は詳しくないので詳細は省くが、バンク$D4に画像データ(背景や文字関係)が格納されている。
キャラのドット絵、いわゆるスプライトはまた別の画像データ扱いである。
本作は戦闘において、3枚の背景の重ね+味方キャラ関係のドット絵(スプライト)を使っている。
どの画像も透過部分が設定できるようになっており、絵を重ねても透過部分は消えずに残る。透明なガラス板に絵を書いて重ねるようなイメージである。画像編集ソフトでいえばレイヤー構造である。
背景は1枚目がバトル背景、2枚目が敵グラフィック、3枚目がメッセージウィンドウ・コマンドウィンドウなど文字表示部分、となっている。これらを下から順に積み重ねて1枚の絵になっている。
背景3枚目の文字画像を呼び出す作業がこの後に行われている。

以下、そのあたりの処理をわかる程度でざっと紹介する。

$C1/3EDB LDA $7EFF00,x[$7E:FF00] ;Aに[$7E:FF00]をロード
$C1/3EDF STA $DE    [$00:03DE]   ;A([$7E:FF00])を[$00:03DE]に書き込み
$C1/3EE1 INX                     ;Xをインクリメント
$C1/3EE2 STX $DC    [$00:03DC]   ;Xを[$00:03DC]に書き込み
$C1/3EE4 CMP #$00                ;Aと$00を減算比較(ステータスフラグ変更のみ)
$C1/3EE6 BNE $03    [$3EEB]      ;ゼロフラグが立っていないとき[$3EEB]分岐
$C1/3EEB CMP #$01                ;Aと$01を減算比較(ステータスフラグ変更のみ)
$C1/3EED BNE $03    [$3EF2]      ;ゼロフラグが立っていないとき[$3EF2]分岐
$C1/3EF2 CMP #$0A                ;Aと$0Aを減算比較(ステータスフラグ変更のみ)
$C1/3EF4 BEQ $0C    [$3F02]      ;ゼロフラグが立っているとき[$3F02]分岐
$C1/3EF6 CMP #$0B                ;Aと$0Bを減算比較(ステータスフラグ変更のみ)
$C1/3EF8 BEQ $06    [$3F00]      ;ゼロフラグが立っているとき[$3F00]分岐
$C1/3EFA CMP #$0C                ;Aと$0Cを減算比較(ステータスフラグ変更のみ)
$C1/3EFC BNE $0A    [$3F08]      ;ゼロフラグが立っていないとき[$3F08]分岐
$C1/3F08 CMP #$1D                ;Aと$1Dを減算比較(ステータスフラグ変更のみ)
$C1/3F0A BEQ $08    [$3F14]      ;ゼロフラグが立っているとき[$3F14]分岐
$C1/3F0C CMP #$1E                ;Aと$1Eを減算比較(ステータスフラグ変更のみ)
$C1/3F0E BEQ $04    [$3F14]      ;ゼロフラグが立っているとき[$3F14]分岐
$C1/3F10 CMP #$1F                ;Aと$1Fを減算比較(ステータスフラグ変更のみ)
$C1/3F12 BNE $0F    [$3F23]      ;ゼロフラグが立っていないとき[$3F23]分岐
$C1/3F23 STZ $DF    [$00:03DF]   ;[$00:03DF]に$00をロード
$C1/3F25 JSR $5095  [$C1:5095]   ;[$C1:5095]にジャンプ

まず、[$7E:FF00]~に読み込んだ文字データ1文字分について何度か減算比較判定をしている。
最初は$00との比較だが、キャラ名とキャラ名の間は必ず$00が入るので、ここで名前の区切りかどうかの判定である。
以降、$01$0A$0B$0C$1D$1E$1Fと順に比較している。
$01は改行を意味している。キャラ名の場合は入っていないはずであるが、セリフテキストなら入っていることがある。改行では特定の文字をロードしないため、分岐になる。
$0A$0B$0Cは空白(スペース)周りの処理。テキストを中央寄せする時などに連続でスペースを使っているが、そういう文字というよりは空白部分の処理になる。
$1D$1E$1Fは、これまでも述べている通り、最初にこの数値が入る場合、次の1バイトと合わせて漢字になるため、処理が別になる。
以上の判定に引っかからない場合はひらがな・カタカナ・記号1文字分になる。
今回でいえば「やたろう」の最初の文字「$D4(や)」なので、以上の判定に引っかかることなく、最終的には$C1/3F23に進む。
この時点で、[$00:03DE][$7E:FF00]の値、[$00:03DF]$00を書き込んでいる。

$C1/5095 LDA $DE    [$00:03DE]   ;Aに[$00:03DE]([$7E:FF00])をロード
$C1/5097 STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の下位バイト
$C1/509A LDA $DF    [$00:03DF]   ;Aに[$00:03DF]($00)をロード
$C1/509C STA $211B  [$00:211B]   ;符号付16bit x 8bit 被乗数の下位バイト
$C1/509F LDA #$18                ;Aに$18をロード
$C1/50A1 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数
$C1/50A4 STA $211C  [$00:211C]   ;符号付16bit x 8bit 乗数
$C1/50A7 REP #$21                ;Aレジスタは16bit幅, Cフラグクリア
$C1/50A9 LDA #$9200              ;Aに$9200をロード
$C1/50AC ADC $2134  [$00:2134]   ;A + 乗算結果下位1バイト&中位1バイト
$C1/50AF TAX                     ;AレジスタをXレジスタにコピー
$C1/50B0 SEP #$20                ;Aレジスタは8bit幅, CフラグON
$C1/50B2 LDA $E0    [$00:03E0]   ;Aに[$00:03E0]をロード
$C1/50B4 AND #$01                ;Aと$01で論理積
$C1/50B6 BEQ $03    [$50BB]      ;ゼロフラグが立っているとき[$50BB]分岐
$C1/50BB PHB                     ;DBレジスタをスタックへプッシュ
$C1/50BC LDA #$7E                ;Aに$7Eをロード
$C1/50BE PHA                     ;Aレジスタをスタックへプッシュ
$C1/50BF PLB                     ;DBレジスタへ値をプル
$C1/50C0 LDY $D6    [$00:03D6]   ;Yに[$00:03D6]をロード
$C1/50C2 LDA #$0C                ;Aに$0Cをロード
$C1/50C4 STA $08    [$00:0308]   ;Aを[$00:0308]に書き込み
;
;文字画像データのロードループ処理
$C1/50C6 LDA $D40000,x[$D4:A5E0] ;Aに[$D4:A5E0+2n]をロード
$C1/50CA STA $0005,y[$7E:B005]   ;Aを[$7E:B005+2n]に書き込み
$C1/50CD LDA $D40001,x[$D4:A5E1] ;Aに[$D4:A5E1+2n]をロード
$C1/50D1 STA $0025,y[$7E:B025]   ;Aを[$7E:B025+2n]に書き込み
$C1/50D4 INX                     ;Xをインクリメント +1
$C1/50D5 INX                     ;Xをインクリメント +1
$C1/50D6 INY                     ;Yをインクリメント +1
$C1/50D7 INY                     ;Yをインクリメント +1
$C1/50D8 DEC $08    [$00:0308]   ;[$00:0308]をデクリメント -1
$C1/50DA BNE $EA    [$50C6]      ;ゼロフラグが立っていないとき[$50C6]分岐
;文字画像データのロードループ処理 ここまで
;
$C1/50DC REP #$21                ;Aレジスタは16bit幅, Cフラグクリア
$C1/50DE LDA $D6    [$00:03D6]   ;Aに[$00:03D7][$00:03D6]をロード
$C1/50E0 ADC #$0020              ;A + $0020
$C1/50E3 STA $D6    [$00:03D6]   ;Aを[$00:03D7][$00:03D6]に書き込み
$C1/50E5 SEP #$20                ;Aレジスタは8bit幅, CフラグON
$C1/50E7 INC $E0    [$00:03E0]   ;[$00:03E0]をインクリメント +1
$C1/50E9 PLB                     ;DBレジスタへ値をプル
$C1/50EA RTS                     ;サブルーチン戻り

大まかにまとめると、[$7E:FF00]の値から呼び出し先アドレスを計算し、[$D4:A5E0][$D4:A5F7]を、偶数なら[$7E:B005][$7E:B01B]、奇数なら[$7E:B025][$7E:B03B]に、アドレスを+2しつつ入れていくループになる。
これで「$D4(や)」の1文字分の処理である。
この処理が「やたろう」の分だけ繰り返しになり($7E:FF00$7E:FF03)、その後の$7E:FF04が区切りの$00なので、$C1/3EE6でゼロフラグが立って分岐になる。
この後は、[$00:03E1]に最初にセットされた$10をデクリメントしながら「$00」にあたる空白部分の処理をひたすら繰り返し、$10回、つまり10進数で16回のループを終えた時点でようやく終了である。

なぜ16回なのかというと、戦闘中、画面上部のウィンドウに表示できる文字数が、最大で16文字だからである。
戦闘開始時に「やたろう」と4文字表示する時、残り12文字分は「データなし」ではなく「空白で埋めている部分」扱いとなり、

「やたろう□□□□□□□□□□□□」

「□」部分は「透過される1文字分の大きさの画像」で埋めるのである。
このために、5回目、つまり5文字目以降は「$00」で呼び出せる空欄用の画像データを呼び出したのである。
これで奴1人目の名前表示用ウィンドウが完成したことになる。

奴2人目については、$7E:FF05から「ごんすけ」の文字が入っているから、1人目同様に、$C1/3E4E~からの処理で、

「ごんすけ□□□□□□□□□□□□」

という名前表示用ウィンドウを読み出している。

これでタイプ「NAME」の名前表示関係の説明は終了とする。



このページをシェアする

上へ