mirror of https://github.com/nmlgc/ReC98.git
[Reverse-engineering] [th04/th05] Stage enemy structure
Last one of the shared entity types! The TH05 version of the .STD enemy VM would now be ready for decompilation in one single future push. Completes P0088, funded by -Tom-.
This commit is contained in:
parent
ba66fcc801
commit
da6b856dc5
|
@ -0,0 +1 @@
|
|||
#define ENEMY_KILL_CELS 8
|
|
@ -0,0 +1 @@
|
|||
ENEMY_KILL_CELS = 8
|
|
@ -0,0 +1,15 @@
|
|||
ENEMY_W = 32
|
||||
ENEMY_H = 32
|
||||
|
||||
EF_FREE = 0
|
||||
EF_ALIVE = 1
|
||||
EF_KILLED = 2
|
||||
EF_ALIVE_FIRST_FRAME = 3
|
||||
EF_KILL_ANIM = 80h
|
||||
|
||||
ENEMY_COUNT = 32
|
||||
|
||||
ENEMY_POS_RANDOM = (999 shl 4)
|
||||
|
||||
public _enemies
|
||||
_enemies enemy_t ENEMY_COUNT dup (<?>)
|
|
@ -0,0 +1,90 @@
|
|||
#define ENEMY_W 32
|
||||
#define ENEMY_H 32
|
||||
|
||||
enum enemy_flag_t {
|
||||
EF_FREE = 0,
|
||||
EF_ALIVE = 1,
|
||||
EF_KILLED = 2,
|
||||
EF_ALIVE_FIRST_FRAME = 3,
|
||||
|
||||
// Yes, the kill animation doesn't use the perfectly suitable animation
|
||||
// system, but is implemented in terms of the [flag].
|
||||
EF_KILL_ANIM = 0x80,
|
||||
EF_KILL_ANIM_last = (EF_KILL_ANIM + PAT_ENEMY_KILL - 1)
|
||||
};
|
||||
|
||||
#if GAME == 4
|
||||
struct enemy_t {
|
||||
unsigned char flag;
|
||||
unsigned char age;
|
||||
motion_t pos;
|
||||
unsigned char patnum_base;
|
||||
int8_t unused_1;
|
||||
int hp;
|
||||
int16_t unused_2;
|
||||
int score;
|
||||
unsigned char near *script;
|
||||
int script_ip;
|
||||
|
||||
// Certain instructions are executed once per frame, up to a number of
|
||||
// frames given in some parameter of the instruction, before [script_ip]
|
||||
// is pointed to the next one. This member tracks the current frame of
|
||||
// this enemy's currently running blocking multi-frame instruction.
|
||||
unsigned char cur_instr_frame;
|
||||
|
||||
// Current loop counter for the LOOP instruction. Resets to 0 once the
|
||||
// amount of loops given in the instruction's parameter has been reached,
|
||||
// allowing a new loop to run. Since there's only one such counter, LOOP
|
||||
// instructions can't be nested.
|
||||
unsigned char loop_i;
|
||||
|
||||
Subpixel speed;
|
||||
unsigned char angle;
|
||||
|
||||
// Certain instructions add this to [angle] for every frame they are
|
||||
// executed.
|
||||
unsigned char angle_delta;
|
||||
|
||||
// Clips the enemy once it leaves the playfield. If not clipped along the
|
||||
// X or Y axis, the [script] will continue to run if the enemy has left
|
||||
// the playfield on that axis, and it will continue to take up a slot in
|
||||
// [enemies].
|
||||
bool clip_x;
|
||||
bool clip_y;
|
||||
|
||||
int8_t unused_3;
|
||||
item_type_t item;
|
||||
bool damaged_this_frame;
|
||||
|
||||
// Animation parameters. Final patnum is
|
||||
// [patnum_base] + (([age] / [anim_frames_per_cel]) % [anim_cels]
|
||||
unsigned char anim_cels;
|
||||
unsigned char anim_frames_per_cel;
|
||||
unsigned char anim_cur_cel; // technically unnecessary
|
||||
|
||||
bool can_be_damaged;
|
||||
bool autofire;
|
||||
bool kills_player_on_collision;
|
||||
|
||||
// Not updated to reflect the current playfield half the enemy is in!
|
||||
bool spawned_in_left_half;
|
||||
|
||||
bullet_template_t bullet_template;
|
||||
|
||||
// If [autofire] is true, the enemy fires bullets, according to its
|
||||
// template, every [autofire_interval] number of frames, with
|
||||
// [autofire_cur_frame] tracking the current one.
|
||||
unsigned char autofire_cur_frame;
|
||||
unsigned char autofire_interval;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ENEMY_COUNT 32
|
||||
|
||||
extern enemy_t enemies[ENEMY_COUNT];
|
||||
extern enemy_t near *enemy_cur;
|
||||
|
||||
#define ENEMY_POS_RANDOM 999.0f
|
||||
|
||||
void pascal near enemies_invalidate(void);
|
||||
void pascal near enemies_render(void);
|
|
@ -0,0 +1,33 @@
|
|||
enemy_t struc
|
||||
flag db ?
|
||||
age db ?
|
||||
pos motion_t <?>
|
||||
E_patnum_base db ?
|
||||
db ?
|
||||
E_hp dw ?
|
||||
db ?
|
||||
db ?
|
||||
E_score dw ?
|
||||
E_script dw ?
|
||||
E_script_ip dw ?
|
||||
E_cur_instr_frame db ?
|
||||
E_loop_i db ?
|
||||
E_speed dw ?
|
||||
E_angle db ?
|
||||
E_angle_delta db ?
|
||||
E_clip_x db ?
|
||||
E_clip_y db ?
|
||||
db ?
|
||||
E_item db ?
|
||||
E_damaged_this_frame db ?
|
||||
E_anim_cels db ?
|
||||
E_anim_frames_per_cel db ?
|
||||
E_anim_cur_cel db ?
|
||||
E_can_be_damaged db ?
|
||||
E_autofire db ?
|
||||
E_kills_player_on_collision db ?
|
||||
E_spawned_in_left_half db ?
|
||||
E_bullet_template bullet_template_t <?>
|
||||
E_autofire_cur_frame db ?
|
||||
E_autofire_interval db ?
|
||||
enemy_t ends
|
|
@ -0,0 +1,24 @@
|
|||
public ENEMIES_INVALIDATE
|
||||
enemies_invalidate proc near
|
||||
push si
|
||||
push di
|
||||
mov _tile_invalidate_box, (ENEMY_W shl 16) or ENEMY_H
|
||||
mov si, offset _enemies
|
||||
mov di, ENEMY_COUNT
|
||||
|
||||
@@loop:
|
||||
cmp [si+enemy_t.flag], EF_FREE
|
||||
jz short @@next
|
||||
cmp [si+enemy_t.flag], EF_ALIVE_FIRST_FRAME
|
||||
jz short @@next
|
||||
call tiles_invalidate_around pascal, large dword ptr [si+enemy_t.pos.prev]
|
||||
|
||||
@@next:
|
||||
add si, size enemy_t
|
||||
dec di
|
||||
jnz short @@loop
|
||||
pop di
|
||||
pop si
|
||||
retn
|
||||
enemies_invalidate endp
|
||||
even
|
|
@ -0,0 +1,98 @@
|
|||
public ENEMIES_RENDER
|
||||
enemies_render proc near
|
||||
|
||||
@@patnum = byte ptr -5
|
||||
@@top = word ptr -4
|
||||
@@i = word ptr -2
|
||||
|
||||
enter 6, 0
|
||||
push si
|
||||
push di
|
||||
mov si, offset _enemies
|
||||
mov [bp+@@i], 0
|
||||
jmp @@more?
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@loop:
|
||||
cmp byte ptr [si+enemy_t.flag], EF_ALIVE
|
||||
jz short @@outside_playfield?
|
||||
cmp byte ptr [si+enemy_t.flag], EF_KILL_ANIM
|
||||
jb @@next
|
||||
|
||||
@@outside_playfield?:
|
||||
cmp [si+enemy_t.pos.prev.y], (-(ENEMY_H / 2) shl 4)
|
||||
jle @@next
|
||||
cmp [si+enemy_t.pos.prev.y], ((PLAYFIELD_H + (ENEMY_H / 2)) shl 4)
|
||||
jge @@next
|
||||
mov al, [si+enemy_t.E_patnum_base]
|
||||
mov [bp+@@patnum], al
|
||||
cmp [si+enemy_t.E_anim_cels], 1
|
||||
jbe short @@put
|
||||
mov al, [si+enemy_t.age]
|
||||
mov ah, 0
|
||||
mov dl, [si+enemy_t.E_anim_frames_per_cel]
|
||||
mov dh, 0
|
||||
push dx
|
||||
cwd
|
||||
pop bx
|
||||
idiv bx
|
||||
or dx, dx
|
||||
jnz short @@still_same_cel
|
||||
inc [si+enemy_t.E_anim_cur_cel]
|
||||
mov al, [si+enemy_t.E_anim_cur_cel]
|
||||
cmp al, [si+enemy_t.E_anim_cels]
|
||||
jb short @@still_same_cel
|
||||
mov [si+enemy_t.E_anim_cur_cel], 0
|
||||
|
||||
@@still_same_cel:
|
||||
mov al, [si+enemy_t.E_anim_cur_cel]
|
||||
add [bp+@@patnum], al
|
||||
|
||||
@@put:
|
||||
mov ax, [si+enemy_t.cur.pos.x]
|
||||
sar ax, 4
|
||||
add ax, (PLAYFIELD_X - (ENEMY_W / 2))
|
||||
mov di, ax
|
||||
call scroll_subpixel_y_to_vram_seg1 pascal, [si+enemy_t.pos.cur.y]
|
||||
mov [bp+@@top], ax
|
||||
or di, di
|
||||
jle short @@next
|
||||
cmp di, PLAYFIELD_RIGHT
|
||||
jge short @@next
|
||||
cmp [si+enemy_t.pos.cur.y], (-(ENEMY_H / 2) shl 4)
|
||||
jle short @@next
|
||||
cmp [si+enemy_t.pos.cur.y], ((PLAYFIELD_H + (ENEMY_H / 2)) shl 4)
|
||||
jge short @@next
|
||||
cmp [si+enemy_t.E_damaged_this_frame], 0
|
||||
jnz short @@damaged
|
||||
push di
|
||||
push ax
|
||||
mov al, [bp+@@patnum]
|
||||
mov ah, 0
|
||||
push ax
|
||||
call super_roll_put
|
||||
jmp short @@next
|
||||
; ---------------------------------------------------------------------------
|
||||
|
||||
@@damaged:
|
||||
push di
|
||||
push [bp+@@top]
|
||||
mov al, [bp+@@patnum]
|
||||
mov ah, 0
|
||||
push ax
|
||||
pushd PLANE_PUT or GC_BRGI
|
||||
call super_roll_put_1plane
|
||||
mov [si+enemy_t.E_damaged_this_frame], 0
|
||||
|
||||
@@next:
|
||||
inc [bp+@@i]
|
||||
add si, size enemy_t
|
||||
|
||||
@@more?:
|
||||
cmp [bp+@@i], ENEMY_COUNT
|
||||
jl @@loop
|
||||
pop di
|
||||
pop si
|
||||
leave
|
||||
retn
|
||||
enemies_render endp
|
|
@ -1,4 +1,8 @@
|
|||
enum item_type_t {
|
||||
#if GAME == 5
|
||||
IT_NONE = -2,
|
||||
#endif
|
||||
IT_ENEMY_DROP_NEXT = -1,
|
||||
IT_POWER = 0,
|
||||
IT_POINT = 1,
|
||||
IT_DREAM = 2,
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
; item_type_t
|
||||
if GAME eq 5
|
||||
IT_NONE = -2
|
||||
endif
|
||||
IT_ENEMY_DROP_NEXT = -1
|
||||
IT_POWER = 0
|
||||
IT_POINT = 1
|
||||
IT_DREAM = 2
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/// Animation frame counts
|
||||
/// ----------------------
|
||||
#include "th02/sprites/cels.h"
|
||||
|
||||
#define HITSHOT_CELS 4
|
||||
#define BULLET_CLOUD_CELS 4
|
||||
#define BULLET_DECAY_CELS 4
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
include th02/sprites/cels.inc
|
||||
|
||||
HITSHOT_CELS = 4
|
||||
BULLET_CLOUD_CELS = 4
|
||||
BULLET_DECAY_CELS = 4
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
typedef enum {
|
||||
// miko32.bft
|
||||
// ----------
|
||||
PAT_ENEMY_KILL = 4,
|
||||
PAT_ENEMY_KILL_last = (PAT_ENEMY_KILL + ENEMY_KILL_CELS - 1),
|
||||
PAT_CLOUD_BULLET16_BLUE = 20,
|
||||
PAT_CLOUD_BULLET16_BLUE_last = (PAT_CLOUD_BULLET16_BLUE + BULLET_CLOUD_CELS - 1),
|
||||
PAT_CLOUD_BULLET16_RED,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
include th04/sprites/cels.inc
|
||||
|
||||
PAT_ENEMY_KILL = 4
|
||||
PAT_CLOUD_BULLET16_BLUE = 20
|
||||
PAT_CLOUD_BULLET16_RED = 24
|
||||
PAT_OPTION_REIMU = 38
|
||||
|
|
853
th04_main.asm
853
th04_main.asm
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
|||
#define ENEMY_CLIP_NONE 0x00
|
||||
#define ENEMY_CLIP_X 0x01
|
||||
#define ENEMY_CLIP_Y 0x10
|
||||
|
||||
// See TH04's version for documentation on the fields that originated in that
|
||||
// game.
|
||||
struct enemy_t {
|
||||
unsigned char flag;
|
||||
unsigned char age;
|
||||
motion_t pos;
|
||||
int hp;
|
||||
int score;
|
||||
unsigned char near *script;
|
||||
int script_ip;
|
||||
SubpixelLength8 speed;
|
||||
unsigned char patnum_base;
|
||||
unsigned char cur_instr_frame;
|
||||
unsigned char loop_i;
|
||||
unsigned char angle;
|
||||
unsigned char angle_delta;
|
||||
unsigned char anim_cels;
|
||||
unsigned char anim_frames_per_cel;
|
||||
unsigned char anim_cur_cel; // still technically unnecessary
|
||||
|
||||
char clip;
|
||||
|
||||
item_type_t item;
|
||||
bool damaged_this_frame;
|
||||
bool can_be_damaged;
|
||||
bool autofire;
|
||||
bool kills_player_on_collision;
|
||||
bool spawned_in_left_half;
|
||||
unsigned char autofire_cur_frame;
|
||||
unsigned char autofire_interval;
|
||||
bullet_template_t bullet_template;
|
||||
|
||||
// Custom type ID, set in the spawn parameters. Can be used to parametrize
|
||||
// scripts via conditional jumps based on this value.
|
||||
unsigned char subtype;
|
||||
|
||||
int8_t unused_1;
|
||||
int16_t unused_2;
|
||||
int8_t unused_3;
|
||||
int8_t padding[5];
|
||||
};
|
||||
|
||||
#include "th04/main/enemy/enemy.hpp"
|
|
@ -0,0 +1,33 @@
|
|||
ENEMY_CLIP_X = 01h
|
||||
ENEMY_CLIP_Y = 10h
|
||||
|
||||
enemy_t struc
|
||||
flag db ?
|
||||
age db ?
|
||||
pos motion_t <?>
|
||||
E_hp dw ?
|
||||
E_score dw ?
|
||||
E_script dw ?
|
||||
E_script_ip dw ?
|
||||
E_speed db ?
|
||||
E_patnum_base db ?
|
||||
E_cur_instr_frame db ?
|
||||
E_loop_i db ?
|
||||
E_angle db ?
|
||||
E_angle_delta db ?
|
||||
E_anim_cels db ?
|
||||
E_anim_frames_per_cel db ?
|
||||
E_anim_cur_cel db ?
|
||||
E_clip db ?
|
||||
E_item db ?
|
||||
E_damaged_this_frame db ?
|
||||
E_can_be_damaged db ?
|
||||
E_autofire db ?
|
||||
E_kills_player_on_collision db ?
|
||||
E_spawned_in_left_half db ?
|
||||
E_autofire_cur_frame db ?
|
||||
E_autofire_interval db ?
|
||||
E_bullet_template bullet_template_t <?>
|
||||
E_subtype db ?
|
||||
db 9 dup(?)
|
||||
enemy_t ends
|
|
@ -10,7 +10,9 @@
|
|||
typedef enum {
|
||||
// miko32.bft
|
||||
// ----------
|
||||
PAT_CLOUD_BULLET16_BLUE = 12,
|
||||
PAT_ENEMY_KILL = 4,
|
||||
PAT_ENEMY_KILL_last = (PAT_ENEMY_KILL + ENEMY_KILL_CELS - 1),
|
||||
PAT_CLOUD_BULLET16_BLUE,
|
||||
PAT_CLOUD_BULLET16_BLUE_last = (PAT_CLOUD_BULLET16_BLUE + BULLET_CLOUD_CELS - 1),
|
||||
PAT_CLOUD_BULLET16_RED,
|
||||
// ----------
|
||||
|
|
|
@ -3,6 +3,7 @@ include th04/sprites/cels.inc
|
|||
PARTICLE_CELS = 4
|
||||
B4BALL_CELS = 4
|
||||
|
||||
PAT_ENEMY_KILL = 4
|
||||
PAT_CLOUD_BULLET16_BLUE = 12
|
||||
PAT_CLOUD_BULLET16_RED = 16
|
||||
PAT_SHOT_SUB = 22
|
||||
|
|
783
th05_main.asm
783
th05_main.asm
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue