カテゴリ 重要度 ステータス 解決状況 登録日時 最終更新
ゲームプレイ解決済み実機のバグ2008-02-22 02:452008-02-22 02:50
 
テスター-Misc Reporters-担当者 ソースsegaorun.cpp
バージョンN/A発生バージョン修正バージョン
フラグ
セット shangon
セット詳細
shangon - スーパーハングオン (シットダウン・アップライト筐体) (プロテクト無し)
 
概 要エキスパートコースを10分以上かけてクリアすると、ハイスコアテーブルの時間の部分がおかしくなる。
詳 細The time on hi-score table is wrong if you end the expert course in more than 10 minutes ...
再現手順 
追加情報This is in fact NOT a bug because of the way total time is handled ... This affects ALL "Super Hang-On" sets ('shangon', 'shangon1', 'shangon2', 'shangon3' and 'shangnle'), so I'll use the M68000 code from 'shangnle' for reference, but it's the same (with different addresses) for the other sets ... - stephh (0.118u6)

Details of the analysis:
The time on hi-score table is wrong if you end the expert course in more than 10 minutes ...

This is in fact NOT a bug because of the way total time is handled ... This affects ALL "Super Hang-On" sets ('shangon', 'shangon1', 'shangon2', 'shangon3' and 'shangnle'), so I'll use the M68000 code from 'shangnle' for reference, but it's the same (with different addresses) for the other sets ...

Here are the "coventions" I'll use for time :

  - 'm' stands for minutes
  - 's' stands for seconds
  - 'x' stands for 1/100th of seconds

The first routine calculates total time :
[code]
005B94: 42B9 0006 66EC         clr.l   $666ec.l
005B9A: 43F9 0006 66EC         lea     $666ec.l, A1
005BA0: 45F9 0006 66F0         lea     $666f0.l, A2
005BA6: 3218                   move.w  (A0)+, D1               time (ss:xx) for a specific stage
005BA8: 0281 0000 FFFF         andi.l  #$ffff, D1
005BAE: 2341 FFFC              move.l  D1, (-$4,A1)
005BB2: 023C 00EF              andi    #$ef, CCR
005BB6: 7203                   moveq   #$3, D1
005BB8: C509                   abcd    -(A1), -(A2)
005BBA: 51C9 FFFC              dbra    D1, $5bb8
005BBE: 51CA FFDA              dbra    D2, $5b9a               loop until last stage
[/code]
Register D2 is set before this routine with the number of stages (18 for expert course) ...

Total time is BCD coded on 4 bytes (format 00:ssss:xx) :

  - 0x0666ec = 0x00
  - 0x0666ed = MSB total seconds
  - 0x0666ee = LSB total seconds
  - 0x0666ef = 1/100th of seconds

So if you end the game in 9'56"87 (= 596"87), it will be stored as 0x00 0x05 0x96 0x87 ...


The second routine changes total time into mm:ss:xx format :
[code]
Step1:
005BC2: 41F9 0006 66EC         lea     $666ec.l, A0
005BC8: 2010                   move.l  (A0), D0                total time
005BCA: E088                   lsr.l   #8, D0                  only take care of total seconds
Step2:
005BCC: 6100 E916              bsr     $44e4                   conversion to hexa
005BD0: 0240 FFFF              andi.w  #$ffff, D0
Step3:
005BD4: 323C 003C              move.w  #$3c, D1
005BD8: 80C1                   divu.w  D1, D0                  /60 to get minutes
005BDA: 3080                   move.w  D0, (A0)                store minutes : ingame BUG !!!
Step4:
005BDC: 4840                   swap    D0                      get remaining seconds
Step5:
005BDE: 6100 E9C2              bsr     $45a2                   conversion to BCD
005BE2: 1140 0002              move.b  D0, ($2,A0)             store seconds
[/code]

If you have the same total time as before, you'll get the following :

  - after step 1 : D0 = 0x0596
  - after step 2 : D0 = 0x0254
  - after step 3 : D0 = 0x0009 - (A0) = 0x00099687
  - after step 4 : D0 = 0x0038
  - after step 5 : D0 = 0x0056 - (A0) = 0x00095687

This is correct, but here what happens if total time > 10 minutes (eg: 10"45"19 = 645"19) :

  - after step 1 : D0 = 0x0645
  - after step 2 : D0 = 0x0285
  - after step 3 : D0 = 0x000a - (A0) = 0x000a4519 !
  - after step 4 : D0 = 0x002d
  - after step 5 : D0 = 0x0045 - (A0) = 0x000a4519 !

This is because there is no conversion to BCD for the minutes before storing them while this is the case for the seconds ...


The third routine displays the new total time as a string of 8 numeric chars :
[code]
Step1:
005C6C: 43F9 0006 66E8         lea     $666e8.l, A1
005C72: 4291                   clr.l   (A1)
005C74: 12AB 0001              move.b  ($1,A3), (A1)           minutes
005C78: 136B 0003 0003         move.b  ($3,A3), ($3,A1)        1/100th of seconds
005C7E: 322B 0002              move.w  ($2,A3), D1             seconds
005C82: 0281 0000 FF00         andi.l  #$ff00, D1
005C88: E989                   lsl.l   #4, D1
005C8A: 8391                   or.l    D1, (A1)                format mm0ss0xx
Step2:
005C8C: 41D4                   lea     (A4), A0
005C8E: 4A93                   tst.l   (A3)
005C90: 6600 0004              bne     $5c96
005C94: 4845                   swap    D5
005C96: 3005                   move.w  D5, D0
005C98: 6100 CB7E              bsr     $2818                   call display routine
Step3:
005C9C: 397C 0019 0004         move.w  #$19, ($4,A4)           3rd char = '
005CA2: 397C 001A 000A         move.w  #$1a, ($a,A4)           6th char = "
005CA8: 38BC 0020              move.w  #$20, (A4)              1st char is a space
005CAC: 4E75                   rts
[/code]

After step 1, the new total time is stored into mm0ss0xx format ...

So according to the good example, it will be stored as 0x09056087 which causes no problem (eg: 0x6 + 0x30 = 0x36 which is - to simplify - the ASCII code for '6') ...

But when you have a bad digit as in the bogus example (0x000a4519), what happens ? After step 1, the new total time will be stored as 0x0a045019 ... And when you'll try to display the 2nd digit, you'll have an error : 0xa + 0x30 = 0x3a which isn't a "valid" char (at least not a number nor a letter) ...

After step 2, new total time will displayed as {mm0ss0xx} and after step 3, it will be displayed as { m'ss"xx} ... The first digit is "blanked", and this means that even if there was a BCD conversion before storing total minutes, it wouldn't display the leading '1' and would display { 0'45"19} 
 
添付ファイル