[Reverse-engineering] [th02/th04/th05] Score update and display

The TH02 version is a piece of cake…

… but TH04 starts turning it into this un-decompilable piece of
unnecessarily micro-optimized ZUN code. Couldn't have chosen anything
better for the first separate ASM translation unit.

Aside from now having to convert names of exported *variables* to
uppercase for visibility in ASM translation units, the most notable
lesson in this was the one about avoiding fixup overflows. From the
Borland C++ Version 4.0 User's Guide:

	"In an assembly language program, a fixup overflow frequently
	 occurs if you have declared an external variable within a
	 segment definition, but this variable actually exists in a
	 different segment."

Can't be restated often enough.

Completes P0032, funded by zorg.
This commit is contained in:
nmlgc 2019-09-18 18:33:38 +02:00
parent 88c05e48e5
commit e6294c2c1a
20 changed files with 462 additions and 473 deletions

View File

@ -19,6 +19,16 @@ th03:: $(TH03:\=bin\th03\)
th04:: $(TH04:\=bin\th04\)
th05:: $(TH05:\=bin\th05\)
# Shared TH04/TH05 assembly units
# -------------------------------
# Need to go into separate .obj directories since they will have different
# AFLAGS per game.
{th04}.asm{bin\th04}.obj:
$(AS) /dGAME=4 $**, $@
{th04}.asm{bin\th05}.obj:
$(AS) /dGAME=5 $**, $@
# -------------------------------
.obj.exe:
$(CC) $(CFLAGS) -ml $**
@ -73,7 +83,14 @@ bin\th04\op.exe: bin\th04\op.obj th04\op_02.c
$**
|
bin\th05\main.exe: bin\th05\main.obj th05\main_01.cpp
bin\th04\scoreupd.obj: th04\scoreupd.asm
bin\th04\main.exe: bin\th04\main.obj bin\th04\scoreupd.obj
$(CC) $(CFLAGS) -ml -DGAME=4 -nbin\th04\ -eMAIN.EXE @&&|
$**
|
bin\th05\scoreupd.obj: th04\scoreupd.asm
bin\th05\main.exe: bin\th05\main.obj bin\th05\scoreupd.obj th05\main012.cpp
$(CC) $(CFLAGS) -ml -3 -Z -DGAME=5 -nbin\th05\ -eMAIN.EXE @&&|
$**
|

View File

@ -0,0 +1,9 @@
; ReC98
; Relevant function definitions from master.h, together with the necessary
; types. Meant as a master.h equivalent for standalone, non-slice ASM
; translation units.
include libs/master.lib/macros.inc
GAIJI_PUTSA procdesc pascal far \
x:word, y:word, strp_seg:word, strp_off:word, atrb:word

View File

@ -1,9 +0,0 @@
public _POWERS_OF_10_LONG
_POWERS_OF_10_LONG label dword
dd 1000000
dd 100000
dd 10000
dd 1000
dd 100
dd 10
dd 1

71
th02/hud/score_put.asm Normal file
View File

@ -0,0 +1,71 @@
HUD_CONTINUES_X = HUD_X + ((SCORE_DIGITS - 1) * 2)
; Only prints the seven score digits, in contrast to the TH04/TH05 version!
; void pascal near hud_score_put(unsigned int y, long value);
public HUD_SCORE_PUT
hud_score_put proc near
@@result = word ptr [bp-4]
@@digit = word ptr [bp-2]
@@value = dword ptr [bp+4]
@@y = word ptr [bp+8]
push bp
mov bp, sp
sub sp, 4
push si
push di
mov si, offset _SEVEN_DIGIT_POWERS_OF_10
mov di, HUD_X
jmp short @@more_digits?
@@put:
mov eax, @@value
cdq
idiv dword ptr [si]
mov @@result, ax
movsx eax, @@result
imul eax, [si]
sub @@value, eax
add si, 4
mov ax, @@result
add ax, GB_DIGITS
mov @@digit, ax
call gaiji_putca pascal, di, @@y, ax, TX_WHITE
add di, 2
@@more_digits?:
cmp di, HUD_CONTINUES_X
jl short @@put
pop di
pop si
leave
retn 6
hud_score_put endp
; void pascal near hud_continues_put(unsigned int y, int continues_used);
public HUD_CONTINUES_PUT
hud_continues_put proc near
@@continues_displayed = word ptr [bp-2]
@@continues_used = word ptr [bp+4]
@@y = word ptr [bp+6]
push bp
mov bp, sp
sub sp, 2
push si
mov si, @@continues_used
cmp si, 10
jl short @@put
mov si, 9
@@put:
lea ax, [si+GB_DIGITS]
mov @@continues_displayed, ax
call gaiji_putca pascal, HUD_CONTINUES_X, @@y, ax, TX_WHITE
pop si
leave
retn 4
hud_continues_put endp

View File

@ -0,0 +1,9 @@
public _SEVEN_DIGIT_POWERS_OF_10
_SEVEN_DIGIT_POWERS_OF_10 label dword
dd 1000000
dd 100000
dd 10000
dd 1000
dd 100
dd 10
dd 1

View File

@ -3,7 +3,7 @@ include defconv_c.inc
include th02/hardware/input.inc
include th02/math/randring_next.inc
include th02/gaiji_boldfont.inc
include th02/gaiji/boldfont.inc
include th02/hud/hud.inc
include th02/score.inc

View File

@ -6694,81 +6694,7 @@ sub_DC4B proc near
retn
sub_DC4B endp
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
sub_DC55 proc near
var_4 = word ptr -4
var_2 = word ptr -2
arg_0 = dword ptr 4
arg_4 = word ptr 8
push bp
mov bp, sp
sub sp, 4
push si
push di
mov si, offset _POWERS_OF_10_LONG
mov di, HUD_X
jmp short loc_DC9A
; ---------------------------------------------------------------------------
loc_DC65:
mov eax, [bp+arg_0]
cdq
idiv dword ptr [si]
mov [bp+var_4], ax
movsx eax, [bp+var_4]
imul eax, [si]
sub [bp+arg_0], eax
add si, 4
mov ax, [bp+var_4]
add ax, GB_DIGITS
mov [bp+var_2], ax
call gaiji_putca pascal, di, [bp+arg_4], ax, TX_WHITE
add di, 2
loc_DC9A:
cmp di, HUD_X + ((SCORE_DIGITS - 1) * 2)
jl short loc_DC65
pop di
pop si
leave
retn 6
sub_DC55 endp
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
sub_DCA5 proc near
var_2 = word ptr -2
arg_0 = word ptr 4
arg_2 = word ptr 6
push bp
mov bp, sp
sub sp, 2
push si
mov si, [bp+arg_0]
cmp si, 0Ah
jl short loc_DCB7
mov si, 9
loc_DCB7:
lea ax, [si+GB_DIGITS]
mov [bp+var_2], ax
call gaiji_putca pascal, HUD_X + ((SCORE_DIGITS - 1) * 2), [bp+arg_2], ax, TX_WHITE
pop si
leave
retn 4
sub_DCA5 endp
include th02/hud/score_put.asm
; =============== S U B R O U T I N E =======================================
@ -6885,16 +6811,12 @@ loc_DDCE:
mov dword_218AC, eax
movzx eax, word_218B0
add dword_1E598, eax
push 6
pushd [dword_1E598]
call sub_DC55
call hud_score_put pascal, 6, large [dword_1E598]
mov eax, dword_1E598
cmp eax, dword_252F8
jle short loc_DE01
mov dword_252F8, eax
push 4
push eax
call sub_DC55
call hud_score_put pascal, 4, eax
loc_DE01:
mov bx, word_1E5B6
@ -6944,16 +6866,12 @@ sub_DE4E proc far
mov bp, sp
mov eax, dword_218AC
add dword_1E598, eax
push 6
pushd [dword_1E598]
call sub_DC55
call hud_score_put pascal, 6, large [dword_1E598]
mov eax, dword_1E598
cmp eax, dword_252F8
jle short loc_DE7A
mov dword_252F8, eax
push 4
push eax
call sub_DC55
call hud_score_put pascal, 4, eax
loc_DE7A:
mov bx, word_1E5B6
@ -7185,23 +7103,19 @@ sub_E012 proc near
push bp
mov bp, sp
call gaiji_putsa pascal, (61 shl 16) + 5, ds, offset gsSCORE, TX_YELLOW
push 6
pushd [dword_1E598]
call sub_DC55
call hud_score_put pascal, 6, large [dword_1E598]
push 6
les bx, mikoconfig
assume es:nothing
push es:[bx+mikoconfig_t.continues_used]
call sub_DCA5
call hud_continues_put
call gaiji_putsa pascal, (60 shl 16) + 3, ds, offset gsHISCORE, TX_YELLOW
push 4
pushd [dword_252F8]
call sub_DC55
call hud_score_put pascal, 4, large [dword_252F8]
push 4
mov al, byte_252FC
mov ah, 0
push ax
call sub_DCA5
call hud_continues_put
call gaiji_putsa pascal, (57 shl 16) + 17, ds, offset gsREIMU, TX_YELLOW
call sub_DF76
call gaiji_putsa pascal, (57 shl 16) + 15, ds, offset gsREIGEKI, TX_YELLOW
@ -34557,7 +34471,7 @@ bombs db 3
db 5
word_1E5B6 dw 0
dword_1E5B8 dd 9C40h
include th02/hud/number_put[data].asm
include th02/hud/score_put[data].asm
word_1E5D8 dw 4140h
word_1E5DA dw 4342h
word_1E5DC dw 44h

View File

@ -1,6 +1,6 @@
; Shared buffer for one full row of gaiji characters. Used for temporarily
; storing the two scores, and the enemy health, dream, and power bars.
HUD_TRAM_W = 8
public _hud_gaiji_row
public _HUD_GAIJI_ROW
_hud_gaiji_row db (HUD_TRAM_W + 1) dup (0)
db 0 ; (word alignment)

View File

@ -1,6 +1,6 @@
public _popup_gaiji_len, _popup_id_cur, _popup_dest_reached, _popup_shiftbuf
public _popup_cur_tram_x, _popup_dest_tram_x, _bgm_title_id, _popup_id_new
public _overlay_text_fp, _popup_fp, _popup_byte_unknown, _popup_bonus
public _popup_cur_tram_x, _popup_dest_tram_x, _bgm_title_id, _POPUP_ID_NEW
public _overlay_text_fp, _POPUP_FP, _popup_byte_unknown, _popup_bonus
_popup_gaiji_len dw ?
_popup_id_cur db ?
_popup_dest_reached db ?

View File

@ -3,17 +3,15 @@
; which is then taken "times 10" ([score_delta] += 1 → 10 more on-screen
; points).
; Also ignoring the last digit. (= 61,110 points)
SCORE_DELTA_FRAME_LIMIT = 6111
public _continues_used, _score_lebcd, _hiscore_lebcd
public _score_delta, _score_delta_frame
public _CONTINUES_USED, _SCORE_LEBCD, _HISCORE_LEBCD
public _SCORE_DELTA, _SCORE_DELTA_FRAME
label _continues_used byte
_score_lebcd db SCORE_DIGITS dup(?)
_hiscore_lebcd db SCORE_DIGITS dup(?)
if GAME eq 4
public _SCORE_UNUSED
_score_unused db ?
endif
_score_delta dd ?

View File

@ -1,2 +1,2 @@
public _is_hiscore
_is_hiscore db 0
public _HISCORE_POPUP_SHOWN
_hiscore_popup_shown db 0

300
th04/scoreupd.asm Normal file
View File

@ -0,0 +1,300 @@
.386
locals
include libs/master.lib/master.inc
include th02/hud/hud.inc
include th04/hud/popup.inc
include th02/score.inc
include th02/gaiji/boldfont.inc
SCORE_DIGIT_HIGHEST = SCORE_DIGITS - 1
; Also ignoring the last digit. (= 61,110 points)
SCORE_DELTA_FRAME_LIMIT = 6111
if SCORE_DELTA_FRAME_LIMIT ge 100000
.err "SCORE_DELTA_FRAME_LIMIT can't have more than 5 decimal digits"
endif
; Declaring everything here rather than inside a segment avoids fixup
; overflows… yup.
extrn _score_lebcd:byte:SCORE_DIGITS
extrn _hiscore_lebcd:byte:SCORE_DIGITS
extrn _hiscore_popup_shown:byte
extrn _score_delta:dword
extrn _score_delta_frame:dword
extrn _FIVE_DIGIT_POWERS_OF_10:word
extrn _hud_gaiji_row:byte:SCORE_DIGITS
extrn _popup_id_new:byte
extrn _popup_fp:word
POPUP_UPDATE_AND_RENDER procdesc near
if GAME eq 4
extrn _score_unused:byte
extrn _temp_lebcd:byte
SCORE_EXTEND_UPDATE procdesc near
else
_temp_lebcd equ _hud_gaiji_row
endif
; ----------------------------------------------------------------------------
main_01_TEXT segment word public 'CODE' use16
assume cs:main_01_TEXT
; ============================================================================
; Renders both the current and high score. In contrast to TH02, it also
; displays the continues digit.
; void pascal near hud_score_put(void);
public HUD_SCORE_PUT
hud_score_put proc pascal near
@@gaiji_p equ bx
@@score_p equ si
@@y equ di
push si
push di
mov @@score_p, offset _hiscore_lebcd[SCORE_DIGIT_HIGHEST]
mov @@y, 4
@@lebcd_to_gaiji:
mov cx, SCORE_DIGITS
mov @@gaiji_p, offset _hud_gaiji_row
@@digit_loop:
mov al, [@@score_p]
add al, GB_DIGITS
mov [@@gaiji_p], al
inc @@gaiji_p
dec @@score_p
loop @@digit_loop
call gaiji_putsa pascal, HUD_X, @@y, ds, offset _hud_gaiji_row, TX_WHITE
add @@y, 2
; Put exactly two lines, high score at (56, 4), and current score at
; (56, 6).
; You might notice that @@score_p is only assigned once. Yes, the code
; assumes that @@score_p now points at the end of _score_lebcd, which in
; turn assumes it's placed exactly before _hiscore_lebcd in memory, with
; no padding.
cmp @@y, 6
jz @@lebcd_to_gaiji
; And if that wasn't enough already, ZUN pops the registers in the wrong
; order. Good thing it doesn't matter for any caller of this function!
;
; This could have easily been fixed by either defining two (or better,
; three) LOCAL variables, or the USES directive if you *really* insist on
; using registers. Both of which would have automatically inserted the
; correct cleanup instructions before RET. Even in the 90's, "using an
; assembler" did very much *not* mean "having to manually spell out every
; instruction executed on the CPU"…
pop si
pop di
ret
hud_score_put endp
; ============================================================================
; void pascal near score_update_and_render(void);
public SCORE_UPDATE_AND_RENDER
score_update_and_render proc near
; The TH04 version is functionally identical, just less optimized.
if GAME eq 5
@@delta_remaining_word equ dx
@@delta_remaining_char equ dl
else
@@delta_remaining_word equ cx
@@delta_remaining_char equ cl
endif
mov eax, _score_delta
or eax, eax
jz short @@ret
cmp _score_delta_frame, eax
jbe short @@calculate_frame_delta
mov word ptr _score_delta_frame, ax
@@calculate_frame_delta:
shr eax, 5
or eax, eax
jnz short @@clamp_delta_to_frame_limit
inc ax
jmp short @@prefer_larger_delta
@@clamp_delta_to_frame_limit:
cmp eax, SCORE_DELTA_FRAME_LIMIT
jbe short @@prefer_larger_delta
mov ax, SCORE_DELTA_FRAME_LIMIT
@@prefer_larger_delta:
cmp word ptr _score_delta_frame, ax
jnb short @@commit_frame_delta
mov word ptr _score_delta_frame, ax
@@commit_frame_delta:
mov @@delta_remaining_word, word ptr _score_delta_frame
jmp short @@update
; ---------------------------------------------------------------------------
@@render:
cmp _hiscore_popup_shown, 0
jnz short @@subtract_frame_delta_and_render
or al, al
jz short @@subtract_frame_delta_and_render
mov _hiscore_popup_shown, 1
mov _popup_id_new, POPUP_ID_HISCORE_ENTRY
mov _popup_fp, offset popup_update_and_render
@@subtract_frame_delta_and_render:
mov eax, _score_delta_frame
sub _score_delta, eax
call hud_score_put
if GAME eq 4
mov _score_unused, 0
call score_extend_update
endif
@@ret:
retn
; ---------------------------------------------------------------------------
even
@@update:
push si
push di
if GAME eq 5
push ds
pop es
@@bcd_p equ di
@@po10_p equ bx
; Since the delta can have at most 5 digits, we only have to work on the
; range from _temp_lebcd[4] (highest) to _temp_lebcd[0] (lowest).
; Zeroing the remaining 3 digits is simply more convenient to do in a
; single 32-bit instruction if _temp_lebcd[4] is also (unnecessarily)
; zeroed.
mov dword ptr _temp_lebcd[4], 0
else
@@bcd_p equ bx
@@po10_p equ si
endif
mov @@bcd_p, offset _temp_lebcd[4]
mov @@po10_p, offset _FIVE_DIGIT_POWERS_OF_10
if GAME eq 5
; 4 divisions, the units place doesn't need a separate one.
mov cx, 4
endif
@@delta_to_bcd:
mov ax, @@delta_remaining_word
; 16-bit DIV interprets DX:AX as a 32-bit divisor…
xor dx, dx
; … and returns the remainder in DX, so we actually aren't losing
; anything here.
div word ptr [@@po10_p]
if GAME eq 5
add @@po10_p, 2
else
mov @@delta_remaining_word, dx
endif
mov [@@bcd_p], al
dec @@bcd_p
if GAME eq 5
loop @@delta_to_bcd
else
add @@po10_p, 2
cmp word ptr [@@po10_p], 1
ja @@delta_to_bcd
endif
@@last_digit:
mov [@@bcd_p], @@delta_remaining_char
; Obviously skipping the continues digit…
mov si, offset _score_lebcd[1]
; … and the last one seen from there doesn't need special BCD treatment
; either.
mov cx, SCORE_DIGITS - 2
; Yes, completely unnecessary in TH05, considering the next instruction.
xor ah, ah
; @@bcd_p == _temp_lebcd[0]
@@add_next_digit_to_score:
if GAME eq 5
movzx ax, byte ptr [@@bcd_p]
else
mov al, [@@bcd_p]
endif
add al, [si]
aaa ; AL < 9, AH = carry
mov [si], al
inc @@bcd_p
inc si
; Add the carry to next score digit. May now be 0Ah, but who cares, it's
; fixed via AAA on the next digit anyway… *except* if it's already the
; highest one, which is exactly where the infamous >100 million score
; glitch comes from.
add [si], ah
if GAME eq 4
mov ah, 0
endif
loop @@add_next_digit_to_score
mov al, [@@bcd_p]
add [si], al
; Is this the high score?
@@is_hiscore equ dl ; Never read, though
if GAME eq 4
push ds
pop es
; assume es:_DATA
endif
mov si, offset _score_lebcd[SCORE_DIGIT_HIGHEST]
mov di, offset _hiscore_lebcd[SCORE_DIGIT_HIGHEST]
xor @@is_hiscore, @@is_hiscore
mov cx, SCORE_DIGITS
cmp _hiscore_popup_shown, 0
jnz short @@hiscore_confirmed
@@check_next_digit_for_hiscore:
mov al, [si]
cmp [di], al
ja short @@hiscore_denied
jb short @@hiscore_confirmed
dec di
dec si
loop @@check_next_digit_for_hiscore
@@hiscore_confirmed:
; Copy the remaining number of digits in CX, backwards (STD!)
if GAME eq 5
cli
endif
std
rep movsb
cld
if GAME eq 5
sti
endif
inc @@is_hiscore
@@hiscore_denied:
mov al, @@is_hiscore
pop di
pop si
jmp @@render
score_update_and_render endp
main_01_TEXT ends
end

8
th04/scoreupd[data].asm Normal file
View File

@ -0,0 +1,8 @@
public _FIVE_DIGIT_POWERS_OF_10
_FIVE_DIGIT_POWERS_OF_10 dw 10000, 1000, 100, 10, 1
if GAME eq 4
; Temporary BCD conversion buffer. TH05 just uses _hud_gaiji_row instead.
public _TEMP_LEBCD
_temp_lebcd db SCORE_DIGITS dup(0)
endif

View File

@ -125,6 +125,7 @@ void pascal far explosions_small_reset(void);
/// Score
/// -----
#define score_delta SCORE_DELTA
extern unsigned long score_delta;
void pascal near score_update_and_render(void);

View File

@ -14,7 +14,7 @@ include th04/hardware/grcg.inc
include th04/hardware/input.inc
include th04/math/randring_next.inc
include th04/math/motion.inc
include th02/gaiji_boldfont.inc
include th02/gaiji/boldfont.inc
include th04/gaiji.inc
include th04/hud/popup.inc
include th02/score.inc

View File

@ -966,7 +966,7 @@ sub_B1D0 proc near
call sub_1DA1B
call main_01:sub_FFA4
call sparks_init
call main_01:sub_11692
call hud_score_put
call sub_15D74
call main_01:sub_BCB2
nopcall main_01:sub_F204
@ -6951,7 +6951,7 @@ loc_E796:
nopcall main_01:sub_EFA1
inc _continues_used
call sub_EEB0
call sub_11692
call hud_score_put
mov al, 0
jmp short loc_E7DA
; ---------------------------------------------------------------------------
@ -7760,8 +7760,8 @@ playfield_fillm_0_120_384_128 endp
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
sub_EE06 proc near
public SCORE_EXTEND_UPDATE
score_extend_update proc near
var_1 = byte ptr -1
@ -7836,7 +7836,7 @@ loc_EE8C:
locret_EEA3:
leave
retn
sub_EE06 endp
score_extend_update endp
; ---------------------------------------------------------------------------
db 0
@ -7869,7 +7869,7 @@ loc_EEBF:
mov _score_delta_frame, 0
mov _score_unused, 0
mov byte_22DA6, 0
mov _is_hiscore, 0
mov _hiscore_popup_shown, 0
pop si
pop bp
retn
@ -8311,7 +8311,7 @@ sub_F204 proc far
mov bp, sp
call gaiji_putsa pascal, (60 shl 16) + 3, ds offset gsHISCORE, TX_YELLOW
call gaiji_putsa pascal, (61 shl 16) + 5, ds offset gsSCORE, TX_YELLOW
call sub_11692
call hud_score_put
les bx, _humaconfig
cmp byte ptr es:[bx+12h], 30h ; '0'
jnz short loc_F245
@ -12550,159 +12550,11 @@ loc_1168E:
pop bp
retn
sub_11647 endp
; =============== S U B R O U T I N E =======================================
sub_11692 proc near
push si
push di
mov si, offset _hiscore_lebcd[SCORE_DIGITS - 1]
mov di, 4
loc_1169A:
mov cx, SCORE_DIGITS
mov bx, 1EC6h
loc_116A0:
mov al, [si]
add al, 0A0h
mov [bx], al
inc bx
dec si
loop loc_116A0
call gaiji_putsa pascal, 56, di, ds, offset unk_23206, TX_WHITE
add di, 2
cmp di, 6
jz short loc_1169A
pop si
pop di
retn
sub_11692 endp
; =============== S U B R O U T I N E =======================================
score_update_and_render proc near
mov eax, _score_delta
or eax, eax
jz short locret_1172C
cmp _score_delta_frame, eax
jbe short loc_116D7
mov word ptr _score_delta_frame, ax
loc_116D7:
shr eax, 5
or eax, eax
jnz short loc_116E3
inc ax
jmp short loc_116EE
; ---------------------------------------------------------------------------
loc_116E3:
cmp eax, SCORE_DELTA_FRAME_LIMIT
jbe short loc_116EE
mov ax, SCORE_DELTA_FRAME_LIMIT
loc_116EE:
cmp word ptr _score_delta_frame, ax
jnb short loc_116F7
mov word ptr _score_delta_frame, ax
loc_116F7:
mov cx, word ptr _score_delta_frame
jmp short loc_1172E
; ---------------------------------------------------------------------------
loc_116FD:
cmp _is_hiscore, 0
jnz short loc_11718
or al, al
jz short loc_11718
mov _is_hiscore, 1
mov _popup_id_new, POPUP_ID_HISCORE_ENTRY
mov _popup_fp, offset popup_update_and_render
loc_11718:
mov eax, _score_delta_frame
sub _score_delta, eax
call sub_11692
mov _score_unused, 0
call sub_EE06
locret_1172C:
retn
; ---------------------------------------------------------------------------
nop
loc_1172E:
push si
push di
mov bx, 1EC2h
mov si, 1EB4h
loc_11736:
mov ax, cx
xor dx, dx
div word ptr [si]
mov cx, dx
mov [bx], al
dec bx
add si, 2
cmp word ptr [si], 1
ja short loc_11736
mov [bx], cl
mov si, offset _score_lebcd[1]
mov cx, SCORE_DIGITS - 2
xor ah, ah
loc_11753:
mov al, [bx]
add al, [si]
aaa
mov [si], al
inc bx
inc si
add [si], ah
mov ah, 0
loop loc_11753
mov al, [bx]
add [si], al
push ds
pop es
assume es:_DATA
mov si, offset _score_lebcd[SCORE_DIGITS - 1]
mov di, offset _hiscore_lebcd[SCORE_DIGITS - 1]
xor dl, dl
mov cx, SCORE_DIGITS
cmp _is_hiscore, 0
jnz short loc_11786
loc_1177A:
mov al, [si]
cmp [di], al
ja short loc_1178C
jb short loc_11786
dec di
dec si
loop loc_1177A
loc_11786:
std
rep movsb
cld
inc dl
loc_1178C:
mov al, dl
pop di
pop si
jmp loc_116FD
score_update_and_render endp
main_01_TEXT ends
HUD_SCORE_PUT procdesc near
SCORE_UPDATE_AND_RENDER procdesc near
main_011_TEXT segment byte public 'CODE' use16
assume cs:main_01
@ -40873,34 +40725,8 @@ aVivavvvvilcvb@ db '
aPnpcuyszlB@bCa db '<27>­<EFBFBD>—ãYzÈ<E280B9>@<40>` Capriccio ',0
include th04/formats/bb_txt_load[data].asm
word_231F2 dw 10h
db 10h
db 27h ; '
db 0E8h
db 3
db 64h ; d
db 0
db 0Ah
db 0
db 1
db 0
db 0
db 0
db 0
db 0
db 0
db 0
db 0
db 0
unk_23206 db 0
db 0
db 0
db 0
db 0
db 0
db 0
db 0
db 0
db 0
include th04/scoreupd[data].asm
include th04/hud/gaiji_row[data].asm
word_23210 dw 0
byte_23212 db 0
db 0

View File

@ -15,7 +15,7 @@ pushstate
nosmart
lea di, _hud_gaiji_row + (SCORE_DIGITS - 5)
movzx edx, [bp+@@val]
lea bx, _POWERS_OF_10_LONG + (2 * 4)
lea bx, _SEVEN_DIGIT_POWERS_OF_10 + (2 * 4)
popstate
mov ax, [bp+@@atrb]
mov cx, 4
@ -43,7 +43,7 @@ hud_points_put proc far
mov di, offset _hud_gaiji_row
mov ax, TX_WHITE
mov _hud_gaiji_row[SCORE_DIGITS - 1], gb_0_ ; ("continues used" digit)
mov bx, offset _POWERS_OF_10_LONG
mov bx, offset _SEVEN_DIGIT_POWERS_OF_10
mov cx, SCORE_DIGITS - 2
hud_digits_put:

View File

@ -1,8 +1,10 @@
/* ReC98
* -----
* Code segment #1 of TH05's MAIN.EXE
* 2nd part of code segment #1 of TH05's MAIN.EXE
*/
#pragma codeseg main_01_TEXT
extern "C" {
#include "th05/th05.hpp"

View File

@ -1112,7 +1112,7 @@ sub_B55A proc near
call sub_16D67
call sub_C473
call sparks_init
call sub_143CA
call hud_score_put
call sub_C29E
nopcall sub_106F3
mov fp_23F5A, offset tiles_render_all
@ -8896,7 +8896,7 @@ loc_FBB5:
nopcall sub_104BB
inc _continues_used
call sub_10398
call sub_143CA
call hud_score_put
mov al, 0
jmp short loc_FBF7
; ---------------------------------------------------------------------------
@ -9481,7 +9481,7 @@ loc_103E9:
jg short loc_103A4
mov _score_delta, 0
mov _score_delta_frame, 0
mov _is_hiscore, 0
mov _hiscore_popup_shown, 0
pop si
pop bp
retn
@ -9865,7 +9865,7 @@ sub_106F3 proc far
mov bp, sp
call gaiji_putsa pascal, (60 shl 16) + 3, ds offset gsHISCORE, TX_YELLOW
call gaiji_putsa pascal, (61 shl 16) + 5, ds offset gsSCORE, TX_YELLOW
call sub_143CA
call hud_score_put
mov al, playchar
mov ah, 0
mov bx, ax
@ -17712,156 +17712,8 @@ loc_143C1:
retn 6
sub_1437E endp
; =============== S U B R O U T I N E =======================================
sub_143CA proc near
push si
push di
mov si, offset _hiscore_lebcd[SCORE_DIGITS - 1]
mov di, 4
loc_143D2:
mov cx, HUD_TRAM_W
mov bx, offset _hud_gaiji_row
loc_143D8:
mov al, [si]
add al, 0A0h
mov [bx], al
inc bx
dec si
loop loc_143D8
call gaiji_putsa pascal, 56, di, ds, offset _hud_gaiji_row, TX_WHITE
add di, 2
cmp di, 6
jz short loc_143D2
pop si
pop di
retn
sub_143CA endp
; =============== S U B R O U T I N E =======================================
;uth05win:CStage::StepScore()
;;_score_delta==curDelta=m_curScore-m_drawScore
public SCORE_UPDATE_AND_RENDER
score_update_and_render proc near
mov eax, _score_delta
or eax, eax ;if (eax==0)
jz short locret_1445C ; goto locret_1445C
cmp _score_delta_frame, eax ;if (m_drawScoreDelta<=m_curScore-m_drawScore)
jbe short loc_1440F ; goto loc_1440F
mov word ptr _score_delta_frame, ax;m_drawScoreDelta=curDelta;
loc_1440F:
shr eax, 5 ;curDelta/=32
or eax, eax ;if (curDelta!=0)
jnz short loc_1441B ; goto loc_1441B
inc ax ;curDelta=1
jmp short loc_14426 ;goto loc_14426
; ---------------------------------------------------------------------------
loc_1441B:
cmp eax, SCORE_DELTA_FRAME_LIMIT
jbe short loc_14426 ; goto loc_14426
mov ax, SCORE_DELTA_FRAME_LIMIT
loc_14426:
cmp word ptr _score_delta_frame, ax
jnb short loc_1442F
mov word ptr _score_delta_frame, ax
loc_1442F:
mov dx, word ptr _score_delta_frame
jmp short loc_1445E
; ---------------------------------------------------------------------------
loc_14435:
cmp _is_hiscore, 0
jnz short loc_14450
or al, al
jz short loc_14450
mov _is_hiscore, 1
mov _popup_id_new, POPUP_ID_HISCORE_ENTRY
mov _popup_fp, offset popup_update_and_render
loc_14450:
mov eax, _score_delta_frame
sub _score_delta, eax
call sub_143CA
locret_1445C:
retn
; ---------------------------------------------------------------------------
nop
loc_1445E:
push si
push di
push ds
pop es
mov dword ptr _hud_gaiji_row[4], 0
mov di, offset _hud_gaiji_row[4]
mov bx, 1FBCh
mov cx, 4
loc_14474:
mov ax, dx
xor dx, dx
div word ptr [bx]
add bx, 2
mov [di], al
dec di
loop loc_14474
mov [di], dl
mov si, offset _score_lebcd[1]
mov cx, SCORE_DIGITS - 2
xor ah, ah
loc_1448C:
movzx ax, byte ptr [di]
add al, [si]
aaa
mov [si], al
inc di
inc si
add [si], ah
loop loc_1448C
mov al, [di]
add [si], al
mov si, offset _score_lebcd[SCORE_DIGITS - 1]
mov di, offset _hiscore_lebcd[SCORE_DIGITS - 1]
xor dl, dl
mov cx, SCORE_DIGITS
cmp _is_hiscore, 0
jnz short loc_144BC
loc_144B0:
mov al, [si]
cmp [di], al
ja short loc_144C4
jb short loc_144BC
dec di
dec si
loop loc_144B0
loc_144BC:
cli
std
rep movsb
cld
sti
inc dl
loc_144C4:
mov al, dl
pop di
pop si
jmp loc_14435
score_update_and_render endp
HUD_SCORE_PUT procdesc near
SCORE_UPDATE_AND_RENDER procdesc near
BOSS_RESET procdesc near
BB_STAGE_LOAD procdesc near
BB_STAGE_FREE procdesc near
@ -38280,18 +38132,9 @@ SHOT_FUNCS label word
dw shot_yuuka_l9
byte_2297E db 0
db 0
include th02/hud/number_put[data].asm
db 10h
db 27h ; '
db 0E8h
db 3
db 64h ; d
db 0
db 0Ah
db 0
db 1
db 0
include th05/hud/gaiji_row[data].asm
include th02/hud/score_put[data].asm
include th04/scoreupd[data].asm
include th04/hud/gaiji_row[data].asm
db 0
db 0
db 3