mirror of https://github.com/nmlgc/ReC98.git
[Decompilation] [th05] Lasers: Update function
In which the shrink types """conveniently""" use a signed comparison
that effectively limits their width to 127 pixels, which forces a
shrink/nonshrink distinction upon the entire rest of the code. 🙄
Part of P0228, funded by [Anonymous] and nrook.
This commit is contained in:
parent
c8997cd500
commit
034a7db98c
|
@ -299,7 +299,7 @@ void near pattern_dense_spreads_and_random_balls_within_laser_walls(void)
|
|||
laser_template.coords.origin = boss.pos.cur;
|
||||
laser_template.coords.angle = (-0x40 + 0x20);
|
||||
laser_template.col = 8;
|
||||
laser_template.coords.width = 8;
|
||||
laser_template.coords.width.nonshrink = 8;
|
||||
laser_manual_fixed_spawn(X_RIGHT);
|
||||
|
||||
laser_template.coords.angle = (-0x40 - 0x20);
|
||||
|
|
|
@ -513,7 +513,7 @@ void near pattern_devil(void)
|
|||
// Laser activation
|
||||
if((boss.hp <= HP_PHASE_10_DEVIL_LASER) || (boss.phase_frame >= 1800)) {
|
||||
if(laser_grow_delay == 0) {
|
||||
laser_template.coords.width = 6;
|
||||
laser_template.coords.width.nonshrink = 6;
|
||||
laser_template.coords.angle = 0x40;
|
||||
laser_template.col = 0xE;
|
||||
|
||||
|
|
|
@ -8,10 +8,122 @@ extern "C" {
|
|||
#include "th04/math/vector.hpp"
|
||||
#include "th04/snd/snd.h"
|
||||
#include "th04/main/playfld.hpp"
|
||||
#include "th04/main/bullet/clearzap.hpp"
|
||||
#include "th05/main/playperf.hpp"
|
||||
}
|
||||
#include "th05/main/bullet/laser.hpp"
|
||||
|
||||
// Segment 1 (as allocated in the header)
|
||||
// ---------
|
||||
|
||||
// ZUN bloat: Needed to circumvent 16-bit promotion in comparisons.
|
||||
inline int8_t laser_width_min(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void near lasers_update(void)
|
||||
{
|
||||
#define shootout_update(laser) { \
|
||||
if(laser->coords.starts_at_distance < to_sp(LASER_DISTANCE_MAX)) { \
|
||||
laser->coords.ends_at_distance.v += laser->shootout_speed.v; \
|
||||
} \
|
||||
if(laser->age >= laser->active_at_age.moveout) { \
|
||||
laser->coords.starts_at_distance.v += laser->shootout_speed.v; \
|
||||
} \
|
||||
}
|
||||
|
||||
Laser near *laser;
|
||||
int i;
|
||||
for((laser = lasers, i = 0); i < LASER_COUNT; (i++, laser++)) {
|
||||
if(laser->flag == LF_FREE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(bullet_clear_time || bullet_zap.active) {
|
||||
if(laser->flag == LF_SHOOTOUT) {
|
||||
laser->flag = LF_SHOOTOUT_DECAY;
|
||||
laser->shootout_speed.v /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
switch(laser->flag) {
|
||||
case LF_SHOOTOUT:
|
||||
shootout_update(laser);
|
||||
laser_hittest(*laser);
|
||||
break;
|
||||
|
||||
case LF_FIXED_WAIT_TO_GROW:
|
||||
if(laser->active_at_age.grow > 0) {
|
||||
if(laser->age >= laser->active_at_age.grow) {
|
||||
// laser->flag = LF_FIXED_GROW;
|
||||
static_cast<uint8_t>(laser->flag)++;
|
||||
snd_se_play(6);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_FIXED_GROW:
|
||||
if(laser->age & 1) {
|
||||
laser->coords.width.nonshrink += 2;
|
||||
}
|
||||
if(laser->coords.width.nonshrink >= laser->grow_to_width) {
|
||||
// laser->flag = LF_FIXED_ACTIVE;
|
||||
static_cast<uint8_t>(laser->flag)++;
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_FIXED_ACTIVE:
|
||||
laser_hittest(*laser);
|
||||
if(laser->shrink_at_age > 0) {
|
||||
if(laser->age >= laser->shrink_at_age) {
|
||||
// laser->flag = LF_FIXED_SHRINK;
|
||||
static_cast<uint8_t>(laser->flag)++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_FIXED_SHRINK:
|
||||
if(laser->age & 1) {
|
||||
// MODDERS: The necessary clamp to 0 here is caught by the
|
||||
// signed comparison below.
|
||||
laser->coords.width.shrink -= 2;
|
||||
}
|
||||
if(laser->coords.width.shrink < laser_width_min()) {
|
||||
laser->flag = LF_FREE;
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_FIXED_SHRINK_AND_WAIT_TO_GROW:
|
||||
if(laser->age & 1) {
|
||||
// MODDERS: See above… except that the signed comparison
|
||||
// wouldn't even have been needed here, as the condition is
|
||||
// `true` for both 1 and 0.
|
||||
laser->coords.width.shrink -= 2;
|
||||
}
|
||||
if(laser->coords.width.shrink <= laser_width_min()) {
|
||||
laser->flag = LF_FIXED_WAIT_TO_GROW;
|
||||
laser->age = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case LF_SHOOTOUT_DECAY:
|
||||
shootout_update(laser);
|
||||
laser->coords.width.nonshrink += 2;
|
||||
if(
|
||||
laser->coords.width.nonshrink >=
|
||||
LASER_SHOOTOUT_DECAY_WIDTH_MAX
|
||||
) {
|
||||
laser->flag = LF_FREE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
laser->age++;
|
||||
}
|
||||
|
||||
#undef shootout_update
|
||||
}
|
||||
// ---------
|
||||
|
||||
// Segment 3 (as allocated in the header)
|
||||
// ---------
|
||||
|
||||
|
@ -33,7 +145,7 @@ void near lasers_shootout_add(void)
|
|||
laser->col = laser_template.col;
|
||||
laser->shootout_speed.v = speed;
|
||||
laser->grow_to_width = 6;
|
||||
laser->coords.width = 6;
|
||||
laser->coords.width.nonshrink = 6;
|
||||
laser->coords.angle = laser_template.coords.angle;
|
||||
vector2_at(
|
||||
laser->coords.origin,
|
||||
|
@ -57,8 +169,8 @@ void pascal near laser_fixed_spawn(int slot)
|
|||
laser.active_at_age.grow = laser_template.active_at_age.grow;
|
||||
laser.shrink_at_age = laser_template.shrink_at_age;
|
||||
laser.col = laser_template.col;
|
||||
laser.grow_to_width = laser_template.coords.width;
|
||||
laser.coords.width = 1;
|
||||
laser.grow_to_width = laser_template.coords.width.nonshrink;
|
||||
laser.coords.width.nonshrink = 1;
|
||||
laser.coords.angle = laser_template.coords.angle;
|
||||
snd_se_play(5);
|
||||
}
|
||||
|
@ -73,8 +185,8 @@ void pascal near laser_manual_fixed_spawn(int slot)
|
|||
laser.active_at_age.grow = -1;
|
||||
laser.shrink_at_age = -1;
|
||||
laser.col = laser_template.col;
|
||||
laser.coords.width = 1;
|
||||
laser.grow_to_width = laser_template.coords.width;
|
||||
laser.coords.width.nonshrink = 1;
|
||||
laser.grow_to_width = laser_template.coords.width.nonshrink;
|
||||
laser.coords.angle = laser_template.coords.angle;
|
||||
snd_se_play(5);
|
||||
}
|
||||
|
@ -93,10 +205,10 @@ void pascal near laser_stop(int slot)
|
|||
if(lasers[slot].flag == LF_FIXED_ACTIVE) {
|
||||
lasers[slot].flag = LF_FIXED_SHRINK;
|
||||
} else if (lasers[slot].flag == LF_SHOOTOUT) {
|
||||
lasers[slot].flag = LF_DECAY;
|
||||
lasers[slot].flag = LF_SHOOTOUT_DECAY;
|
||||
} else if (
|
||||
(lasers[slot].flag != LF_FIXED_SHRINK) &&
|
||||
(lasers[slot].flag != LF_DECAY)
|
||||
(lasers[slot].flag != LF_SHOOTOUT_DECAY)
|
||||
) {
|
||||
lasers[slot].flag = LF_FREE;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#define LASER_DISTANCE_MIN 16.0f
|
||||
#define LASER_DISTANCE_MAX 550.0f /* Far away enough? */
|
||||
|
||||
static const pixel_t LASER_SHOOTOUT_DECAY_WIDTH = 6;
|
||||
static const pixel_t LASER_SHOOTOUT_DECAY_WIDTH_MAX = 28;
|
||||
|
||||
enum laser_flag_t {
|
||||
LF_FREE = 0,
|
||||
LF_SHOOTOUT = 1,
|
||||
|
@ -11,9 +14,15 @@ enum laser_flag_t {
|
|||
// player on contact.
|
||||
LF_FIXED_ACTIVE = 4,
|
||||
|
||||
// Fixed laser will shrink to a width of 1 and then either be removed
|
||||
// (LF_FIXED_SHRINK) or go back to LF_FIXED_WAIT_TO_GROW with its [age]
|
||||
// reset to 0 (LF_FIXED_SHRINK_AND_WAIT_TO_GROW).
|
||||
LF_FIXED_SHRINK = 5,
|
||||
LF_FIXED_SHRINK_AND_WAIT_TO_GROW = 6,
|
||||
LF_DECAY = 7,
|
||||
|
||||
LF_SHOOTOUT_DECAY = 7,
|
||||
|
||||
_laser_flag_t_FORCE_UINT8 = 0xFF
|
||||
};
|
||||
|
||||
struct laser_coords_t {
|
||||
|
@ -25,7 +34,22 @@ struct laser_coords_t {
|
|||
Subpixel ends_at_distance;
|
||||
|
||||
unsigned char angle;
|
||||
unsigned char width; // pixel_t
|
||||
|
||||
// In pixels.
|
||||
union {
|
||||
// ZUN bug: LF_FIXED_SHRINK and LF_FIXED_SHRINK_AND_WAIT_TO_GROW are
|
||||
// effectively limited to a maximum width of 127 pixels due to an
|
||||
// implementation convenience in their update code. For larger values,
|
||||
// their shrink animation wouldn't play, and the laser will transition
|
||||
// to its next flag immediately.
|
||||
int8_t shrink;
|
||||
|
||||
// Other types have no limit besides the 8-bit one inherent to the
|
||||
// type. Shootout lasers should probably still be kept below
|
||||
// LASER_SHOOTOUT_DECAY_WIDTH_MAX though, as any larger value would
|
||||
// skip the decay animation.
|
||||
uint8_t nonshrink;
|
||||
} width;
|
||||
};
|
||||
|
||||
struct Laser {
|
||||
|
|
|
@ -164,7 +164,7 @@ bool16 pascal near laser_render_ray(const laser_coords_t near& coords)
|
|||
SpaceChangingPoint bp[8];
|
||||
} ps;
|
||||
|
||||
v_length_low = coords.width;
|
||||
v_length_low = coords.width.nonshrink;
|
||||
v_length_high = 0;
|
||||
v_length <<= (SUBPIXEL_BITS - 1);
|
||||
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
LF_FREE = 0
|
||||
LF_SHOOTOUT = 1
|
||||
LF_FIXED_WAIT_TO_GROW = 2
|
||||
LF_FIXED_GROW = 3
|
||||
LF_FIXED_ACTIVE = 4
|
||||
LF_FIXED_SHRINK = 5
|
||||
LF_FIXED_SHRINK_AND_WAIT_TO_GROW = 6
|
||||
LF_DECAY = 7
|
||||
LF_SHOOTOUT_DECAY = 7
|
||||
|
||||
laser_coords_t struc
|
||||
origin Point <?>
|
||||
|
|
|
@ -1,179 +1,5 @@
|
|||
@LASER_RENDER_RAY$QRX14LASER_COORDS_T procdesc pascal near \
|
||||
coords:word
|
||||
@LASER_HITTEST$QR5LASER procdesc pascal near \
|
||||
laser:word
|
||||
|
||||
public @lasers_update$qv
|
||||
@lasers_update$qv proc near
|
||||
push bp
|
||||
mov bp, sp
|
||||
push si
|
||||
push di
|
||||
mov si, offset _lasers
|
||||
xor di, di
|
||||
jmp @@more?
|
||||
|
||||
@@loop:
|
||||
cmp [si+laser_t.flag], LF_FREE
|
||||
jz @@next
|
||||
cmp _bullet_clear_time, 0
|
||||
jnz short @@shootout
|
||||
cmp _bullet_zap_active, 0
|
||||
jz short @@switch
|
||||
|
||||
@@shootout:
|
||||
cmp [si+laser_t.flag], LF_SHOOTOUT
|
||||
jnz short @@switch
|
||||
mov [si+laser_t.flag], LF_DECAY
|
||||
mov ax, [si+laser_t.shootout_speed]
|
||||
cwd
|
||||
sub ax, dx
|
||||
sar ax, 1
|
||||
mov [si+laser_t.shootout_speed], ax
|
||||
|
||||
@@switch:
|
||||
mov al, [si+laser_t.flag]
|
||||
mov ah, 0
|
||||
dec ax
|
||||
mov bx, ax
|
||||
cmp bx, 6
|
||||
ja @@age_inc
|
||||
add bx, bx
|
||||
jmp cs:lasers_update_switch[bx]
|
||||
|
||||
laser_update_shootout:
|
||||
cmp [si+laser_t.coords.starts_at_distance], (550 shl 4)
|
||||
jge short loc_FC52
|
||||
mov ax, [si+laser_t.shootout_speed]
|
||||
add [si+laser_t.coords.ends_at_distance], ax
|
||||
|
||||
loc_FC52:
|
||||
mov ax, [si+laser_t.LASER_age]
|
||||
cmp ax, [si+laser_t.moveout_at_age]
|
||||
jl short loc_FC60
|
||||
mov ax, [si+laser_t.shootout_speed]
|
||||
add [si+laser_t.coords.starts_at_distance], ax
|
||||
|
||||
loc_FC60:
|
||||
call @laser_hittest$qr5Laser pascal, si
|
||||
jmp @@age_inc
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
laser_update_fixed_wait_to_grow:
|
||||
cmp [si+laser_t.grow_at_age], 0
|
||||
jle @@age_inc
|
||||
mov ax, [si+laser_t.LASER_age]
|
||||
cmp ax, [si+laser_t.grow_at_age]
|
||||
jl @@age_inc
|
||||
inc [si+laser_t.flag]
|
||||
call snd_se_play pascal, 6
|
||||
jmp @@age_inc
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
laser_update_fixed_grow:
|
||||
test byte ptr [si+laser_t.LASER_age], 1
|
||||
jz short @@grow_step
|
||||
mov al, [si+laser_t.coords.LASER_width]
|
||||
add al, 2
|
||||
mov [si+laser_t.coords.LASER_width], al
|
||||
|
||||
@@grow_step:
|
||||
mov al, [si+laser_t.coords.LASER_width]
|
||||
cmp al, [si+laser_t.grow_to_width]
|
||||
jb short @@age_inc
|
||||
jmp short @@next_mode
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
laser_update_fixed_active:
|
||||
call @laser_hittest$qr5Laser pascal, si
|
||||
cmp [si+laser_t.shrink_at_age], 0
|
||||
jle short @@age_inc
|
||||
mov ax, [si+laser_t.LASER_age]
|
||||
cmp ax, [si+laser_t.shrink_at_age]
|
||||
jl short @@age_inc
|
||||
|
||||
@@next_mode:
|
||||
inc [si+laser_t.flag]
|
||||
jmp short @@age_inc
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
laser_update_fixed_shrink:
|
||||
test byte ptr [si+laser_t.LASER_age], 1
|
||||
jz short @@delete?
|
||||
mov al, [si+laser_t.coords.LASER_width]
|
||||
add al, -2
|
||||
mov [si+laser_t.coords.LASER_width], al
|
||||
|
||||
@@delete?:
|
||||
cmp [si+laser_t.coords.LASER_width], 1
|
||||
jge short @@age_inc
|
||||
jmp short @@delete
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
laser_update_fixed_shrink_and_wait_to_grow:
|
||||
test byte ptr [si+laser_t.LASER_age], 1
|
||||
jz short @@shrink_and_wait_to_grow_step
|
||||
mov al, [si+laser_t.coords.LASER_width]
|
||||
add al, -2
|
||||
mov [si+laser_t.coords.LASER_width], al
|
||||
|
||||
@@shrink_and_wait_to_grow_step:
|
||||
cmp [si+laser_t.coords.LASER_width], 1
|
||||
jg short @@age_inc
|
||||
mov [si+laser_t.flag], LF_FIXED_WAIT_TO_GROW
|
||||
mov [si+laser_t.LASER_age], 0
|
||||
jmp short @@age_inc
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
laser_update_decay:
|
||||
cmp [si+laser_t.coords.starts_at_distance], (550 shl 4)
|
||||
jge short loc_FCF4
|
||||
mov ax, [si+laser_t.shootout_speed]
|
||||
add [si+laser_t.coords.ends_at_distance], ax
|
||||
|
||||
loc_FCF4:
|
||||
mov ax, [si+laser_t.LASER_age]
|
||||
cmp ax, [si+laser_t.moveout_at_age]
|
||||
jl short loc_FD02
|
||||
mov ax, [si+laser_t.shootout_speed]
|
||||
add [si+laser_t.coords.starts_at_distance], ax
|
||||
|
||||
loc_FD02:
|
||||
mov al, [si+laser_t.coords.LASER_width]
|
||||
add al, 2
|
||||
mov [si+laser_t.coords.LASER_width], al
|
||||
cmp [si+laser_t.coords.LASER_width], 28
|
||||
jb short @@age_inc
|
||||
|
||||
@@delete:
|
||||
mov [si+laser_t.flag], LF_FREE
|
||||
|
||||
@@age_inc:
|
||||
inc [si+laser_t.LASER_age]
|
||||
|
||||
@@next:
|
||||
inc di
|
||||
add si, size laser_t
|
||||
|
||||
@@more?:
|
||||
cmp di, LASER_COUNT
|
||||
jl @@loop
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
retn
|
||||
@lasers_update$qv endp
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
lasers_update_switch label word
|
||||
dw offset laser_update_shootout
|
||||
dw offset laser_update_fixed_wait_to_grow
|
||||
dw offset laser_update_fixed_grow
|
||||
dw offset laser_update_fixed_active
|
||||
dw offset laser_update_fixed_shrink
|
||||
dw offset laser_update_fixed_shrink_and_wait_to_grow
|
||||
dw offset laser_update_decay
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
public @lasers_render$qv
|
||||
@lasers_render$qv proc near
|
||||
|
@ -217,7 +43,7 @@ public @lasers_render$qv
|
|||
sar ax, 4
|
||||
add ax, 16
|
||||
mov [bp+@@draw_y], ax
|
||||
cmp [si+laser_t.flag], LF_DECAY
|
||||
cmp [si+laser_t.flag], LF_SHOOTOUT_DECAY
|
||||
jz @@decay
|
||||
cmp [bp+@@radius], 2
|
||||
jnb short @@draw_outer_circle?
|
||||
|
|
|
@ -4368,6 +4368,8 @@ loc_FBF7:
|
|||
leave
|
||||
retn
|
||||
sub_FAA3 endp
|
||||
|
||||
@lasers_update$qv procdesc near
|
||||
main__TEXT ends
|
||||
|
||||
PLAYFLD_TEXT segment byte public 'CODE' use16
|
||||
|
|
Loading…
Reference in New Issue