Skip to content

Commit

Permalink
[Reverse-engineering] [th04/th05] Boss explosions
Browse files Browse the repository at this point in the history
So apparently, this way of distorting a circle into an ellipse (?) by
adding a value to the angle for one of the two coordinates isn't
actually widely known in math and doesn't have a name. Fair enough.

Funded by -Tom-.
  • Loading branch information
nmlgc committed Mar 3, 2019
1 parent 1cb2c0a commit 308d1bc
Show file tree
Hide file tree
Showing 12 changed files with 521 additions and 945 deletions.
12 changes: 12 additions & 0 deletions th04/boss/explode_big.asm
@@ -0,0 +1,12 @@
; void boss_explode_big(unsigned int type);
public boss_explode_big
boss_explode_big proc near

@@type = word ptr 4

push bp
mov bp, sp
push si
mov si, offset _explosions_big
EXPLOSION_TYPED
boss_explode_big endp
69 changes: 69 additions & 0 deletions th04/boss/explode_small.asm
@@ -0,0 +1,69 @@
EXPLOSION_TYPED macro
mov [si+explosion_t.flag], 1
mov [si+explosion_t.age], 0
mov ax, _boss_pos.cur.x
mov [si+explosion_t.center.x], ax
mov ax, _boss_pos.cur.y
mov [si+explosion_t.center.y], ax
mov [si+explosion_t.EXPLOSION_radius_cur.x], 8
mov [si+explosion_t.EXPLOSION_radius_cur.y], 8
mov [si+explosion_t.EXPLOSION_radius_delta.x], (11 shl 4)
mov [si+explosion_t.EXPLOSION_radius_delta.y], (11 shl 4)
mov [si+explosion_t.angle_offset], 0
mov bx, [bp+@@type]
dec bx
cmp bx, 3
ja short @@ret
add bx, bx
jmp cs:@@switch[bx]

@@type1:
mov [si+explosion_t.angle_offset], 32
jmp short @@ret
; ---------------------------------------------------------------------------

@@type2:
mov [si+explosion_t.angle_offset], -32
jmp short @@ret
; ---------------------------------------------------------------------------

@@type3:
mov [si+explosion_t.EXPLOSION_radius_delta.x], (13 shl 4)
mov [si+explosion_t.EXPLOSION_radius_delta.y], (7 shl 4)
jmp short @@ret
; ---------------------------------------------------------------------------

@@type4:
mov [si+explosion_t.EXPLOSION_radius_delta.x], (7 shl 4)
mov [si+explosion_t.EXPLOSION_radius_delta.y], (13 shl 4)

@@ret:
call snd_se_play pascal, 15
pop si
pop bp
retn 2

@@switch label word
dw offset @@type1
dw offset @@type2
dw offset @@type3
dw offset @@type4
endm

; void boss_explode_small(unsigned int type);
public boss_explode_small
boss_explode_small proc near

@@type = word ptr 4

push bp
mov bp, sp
push si
mov si, offset _explosions_small
cmp [si+explosion_t.flag], 0
jz short @@set
add si, size explosion_t

@@set:
EXPLOSION_TYPED
boss_explode_small endp
31 changes: 31 additions & 0 deletions th04/boss/explosions[bss].asm
@@ -0,0 +1,31 @@
explosion_t struc
flag db ?
age db ?
; Stored in 1/16th-pixel playfield coordinates.
center Point <?>
EXPLOSION_radius_cur Point <?>
EXPLOSION_radius_delta Point <?>
db ?
; Offset to add to the angle for the Y coordinate, turning the circle into
; a slanted ellipse. See https://www.desmos.com/calculator/faeefi6w1u for
; a plot of the effect.
angle_offset db ?
explosion_t ends

EXPLOSION_AGE_MAX = 32
EXPLOSION_SMALL_COUNT = 2
EXPLOSION_SMALL_W = 16
EXPLOSION_SMALL_H = 16
EXPLOSION_SMALL_SPRITES = 64
EXPLOSION_BIG_SPRITES = 16

if GAME eq 5
EXPLOSION_SMALL_PATNUM = 164
else
EXPLOSION_SMALL_PATNUM = 68
endif

public _explosions_small
public _explosions_big
_explosions_small explosion_t EXPLOSION_SMALL_COUNT dup (<?>)
_explosions_big explosion_t <?>
113 changes: 113 additions & 0 deletions th04/boss/explosions_big.asm
@@ -0,0 +1,113 @@
; void explosions_big_update_and_render(void);
public explosions_big_update_and_render
explosions_big_update_and_render proc near

@@angle = byte ptr -5
@@draw_y = word ptr -4
@@i = word ptr -2

enter 6, 0
push si
push di
mov si, offset _explosions_big
cmp [si+explosion_t.flag], 0
jz @@reset_frame
mov [bp+@@i], 0
mov [bp+@@angle], 0
jmp short @@more_sprites?
; ---------------------------------------------------------------------------

@@sprite_loop:
push [si+explosion_t.center.x]
push [si+explosion_t.EXPLOSION_radius_cur.x]
mov al, [bp+@@angle]
mov ah, 0
add ax, ax
mov bx, ax
push _CosTable8[bx]
call vector1_at
mov di, ax
sar ax, 4
mov di, ax
push [si+explosion_t.center.y]
push [si+explosion_t.EXPLOSION_radius_cur.y]
mov al, [si+explosion_t.angle_offset]
add al, [bp+@@angle]
mov ah, 0
add ax, ax
mov bx, ax
push _SinTable8[bx]
call vector1_at
mov [bp+@@draw_y], ax
sar ax, 4
; Yes, these are not clipped exactly to the playfield boundaries?
add ax, -16
mov [bp+@@draw_y], ax
or di, di
jl short @@next_sprite
cmp di, 384
jg short @@next_sprite
cmp [bp+@@draw_y], 0
jl short @@next_sprite
cmp [bp+@@draw_y], 336
jg short @@next_sprite
call super_put pascal, di, ax, 3

@@next_sprite:
inc [bp+@@i]
mov al, [bp+@@angle]
add al, (256 / EXPLOSION_BIG_SPRITES)
mov [bp+@@angle], al

@@more_sprites?:
cmp [bp+@@i], EXPLOSION_BIG_SPRITES
jl short @@sprite_loop
mov ax, [si+explosion_t.EXPLOSION_radius_delta.x]
add [si+explosion_t.EXPLOSION_radius_cur.x], ax
mov ax, [si+explosion_t.EXPLOSION_radius_delta.y]
add [si+explosion_t.EXPLOSION_radius_cur.y], ax
inc [si+explosion_t.age]
cmp [si+explosion_t.age], EXPLOSION_AGE_MAX
jb short @@tone_update
mov [si+explosion_t.flag], 0

@@tone_update:
inc _explosion_big_frame
cmp _explosion_big_frame, 8
jge short @@tone_flash?
test byte ptr _explosion_big_frame, 1
jz short @@tone_flash?
mov PaletteTone, 150
jmp short @@ret_palette_changed
; ---------------------------------------------------------------------------

@@tone_flash?:
cmp _explosion_big_frame, 8
jl short @@tone_regular
cmp _explosion_big_frame, 16
jge short @@tone_regular
mov ax, _explosion_big_frame
imul ax, 6
mov dx, 196
sub dx, ax
mov PaletteTone, dx

@@ret_palette_changed:
mov _palette_changed, 1
jmp short @@ret
; ---------------------------------------------------------------------------

@@tone_regular:
mov PaletteTone, 100
jmp short @@ret_palette_changed
; ---------------------------------------------------------------------------

@@reset_frame:
mov _explosion_big_frame, 0

@@ret:
pop di
pop si
leave
retn
explosions_big_update_and_render endp
2 changes: 2 additions & 0 deletions th04/boss/explosions_big[data].asm
@@ -0,0 +1,2 @@
public _explosion_big_frame
_explosion_big_frame dw 0
10 changes: 10 additions & 0 deletions th04/boss/explosions_reset.asm
@@ -0,0 +1,10 @@
; void explosions_small_reset(void);
public explosions_small_reset
explosions_small_reset proc far
push bp
mov bp, sp
mov _explosions_small[0 * size explosion_t].flag, 0
mov _explosions_small[1 * size explosion_t].flag, 0
pop bp
retf
explosions_small_reset endp
97 changes: 97 additions & 0 deletions th04/boss/explosions_small.asm
@@ -0,0 +1,97 @@
; void explosions_small_update_and_render(void);
public explosions_small_update_and_render
explosions_small_update_and_render proc near

@@angle = byte ptr -7
@@i = word ptr -6
@@draw_y = word ptr -4
@@draw_x = word ptr -2

enter 8, 0
push si
push di
mov ax, GRAM_400
mov es, ax
assume es:nothing
call _grcg_setmode_rmw_1
mov si, offset _explosions_small
mov [bp+@@i], 0
jmp @@more_explosions?
; ---------------------------------------------------------------------------

@@explosion_loop:
cmp [si+explosion_t.flag], 0
jz @@next_explosion
xor di, di
mov [bp+@@angle], 0
jmp short @@more_sprites?
; ---------------------------------------------------------------------------

@@sprite_loop:
push [si+explosion_t.center.x]
push [si+explosion_t.EXPLOSION_radius_cur.x]
mov al, [bp+@@angle]
mov ah, 0
add ax, ax
mov bx, ax
push _CosTable8[bx]
call vector1_at
mov [bp+@@draw_x], ax
push [si+explosion_t.center.y]
push [si+explosion_t.EXPLOSION_radius_cur.y]
mov al, [si+explosion_t.angle_offset]
add al, [bp+@@angle]
mov ah, 0
add ax, ax
mov bx, ax
push _SinTable8[bx]
call vector1_at
mov [bp+@@draw_y], ax
sar ax, 4
add ax, PLAYFIELD_Y - (EXPLOSION_SMALL_H / 2)
mov dx, ax
mov ax, [bp+@@draw_x]
sar ax, 4
add ax, PLAYFIELD_X - (EXPLOSION_SMALL_W / 2)
cmp ax, PLAYFIELD_X - EXPLOSION_SMALL_W
jbe short @@next_sprite
cmp ax, PLAYFIELD_X + PLAYFIELD_W
jnb short @@next_sprite
or dx, dx
jbe short @@next_sprite
cmp dx, PLAYFIELD_Y + PLAYFIELD_H
jnb short @@next_sprite
push EXPLOSION_SMALL_PATNUM
call z_super_roll_put_tiny

@@next_sprite:
inc di
mov al, [bp+@@angle]
add al, (256 / EXPLOSION_SMALL_SPRITES)
mov [bp+@@angle], al

@@more_sprites?:
cmp di, EXPLOSION_SMALL_SPRITES
jl short @@sprite_loop
mov ax, [si+explosion_t.EXPLOSION_radius_delta.x]
add [si+explosion_t.EXPLOSION_radius_cur.x], ax
mov ax, [si+explosion_t.EXPLOSION_radius_delta.y]
add [si+explosion_t.EXPLOSION_radius_cur.y], ax
inc [si+explosion_t.age]
cmp [si+explosion_t.age], EXPLOSION_AGE_MAX
jb short @@next_explosion
mov [si+explosion_t.flag], 0

@@next_explosion:
inc [bp+@@i]
add si, size explosion_t

@@more_explosions?:
cmp [bp+@@i], 2
jl @@explosion_loop
GRCG_OFF_CLOBBERING dx
pop di
pop si
leave
retn
explosions_small_update_and_render endp

0 comments on commit 308d1bc

Please sign in to comment.