diff --git a/p2/game.h b/p2/game.h index b31cdd2..a906464 100644 --- a/p2/game.h +++ b/p2/game.h @@ -42,9 +42,9 @@ struct monster_t { int16_t x_velocity; // 0x8 int16_t y_velocity; // 0xA const uint8_t *anim; // 0xC - uint8_t unkE; // 0xE - uint8_t unkF; // 0xF - uint8_t unk10; + uint8_t state; // 0xE + uint8_t energy; // 0xF + uint8_t unk10; // 0x10 }; struct thing_t { @@ -67,6 +67,7 @@ struct object_t { uint8_t hit_counter; // 0x11 }; // sizeof == 18 +#define MONSTERS_COUNT 12 #define OBJECTS_COUNT 108 // offset count // 0 1 : club diff --git a/p2/level.c b/p2/level.c index 5984e61..dae13da 100644 --- a/p2/level.c +++ b/p2/level.c @@ -1,4 +1,6 @@ +/* level main loop */ + #include "game.h" #include "resource.h" #include "sys.h" @@ -93,10 +95,12 @@ static void load_level_data_init_animated_tiles() { } static void load_level_data_init_transparent_tiles() { + const int tiles_offset = g_vars.tilemap_size + 512; + const int tiles_count = (g_res.levellen - tiles_offset) / 128; int count = 1; - for (int i = 0; i < 256; ++i) { + for (int i = 0; i < tiles_count; ++i) { const uint8_t num = i; - const uint8_t *tiledat = g_res.leveldat + g_vars.tilemap_size + 512 + num * 128; + const uint8_t *tiledat = g_res.leveldat + tiles_offset + num * 128; uint8_t mask_opaque = 0xFF; uint8_t mask_transparent = 0; for (int j = 0; j < 128; ++j) { @@ -892,8 +896,8 @@ static void level_reset_objects() { obj->spr_num = 0xFFFF; obj->hit_counter = 0; } - g_vars.objects_tbl[1].x_pos = g_res.level.start_x_pos; - g_vars.objects_tbl[1].y_pos = g_res.level.start_y_pos; + g_vars.objects_tbl[1].x_pos = (g_options.start_xpos16 < 0) ? g_res.level.start_x_pos : g_options.start_xpos16; + g_vars.objects_tbl[1].y_pos = (g_options.start_ypos16 < 0) ? g_res.level.start_y_pos : g_options.start_ypos16; } static void level_reset() { @@ -932,7 +936,7 @@ static uint16_t level_get_player_tile_pos() { return (y << 8) | x; } -static void level_add_object75_score(struct object_t *ref_obj, int num) { +static struct object_t *level_add_object75_score(struct object_t *ref_obj, int num) { const int score_index = num - 74; if (score_index >= 0 && score_index <= 16) { g_vars.score += score_tbl[score_index]; @@ -951,9 +955,10 @@ static void level_add_object75_score(struct object_t *ref_obj, int num) { item->spr_num = 0xFFFF; } } - break; + return obj; } } + return 0; } static void level_update_object_anim(const uint8_t *anim) { @@ -1054,13 +1059,57 @@ static bool level_objects_collide(const struct object_t *si, const struct object return (a + b > d); } -static bool level_collide_axe_monsters(struct object_t *obj) { - for (int i = 0; i < 12; ++i) { +static void level_monster_die(struct object_t *obj, struct level_monster_t *m) { + const int num = m->unk8 + 74; + static const uint8_t data[] = { 1, 2, 3, 4, 6, 8 }; + int count = data[obj->data.m.unk10 & 7]; + const int x_pos = obj->x_pos; + const int y_pos = obj->y_pos; + do { + struct object_t *score_obj = level_add_object75_score(obj, num); + if (score_obj) { + score_obj->data.t.counter = count << 2; + } + obj->y_pos += 7; + obj->x_pos += 9; + } while (--count != 0); + obj->x_pos = x_pos; + obj->y_pos = y_pos; + obj->data.m.state = 0xFF; + if ((m->flags & 1) == 0) { + g_vars.current_bonus.x_pos = obj->x_pos; + g_vars.current_bonus.y_pos = obj->y_pos; + g_vars.current_bonus.spr_num = 0x2046; + level_add_object23_bonus(48, -128, 6); + } else { + } +} + +static bool level_collide_axe_monsters(struct object_t *axe_obj) { + for (int i = 0; i < MONSTERS_COUNT; ++i) { struct object_t *obj = &g_vars.objects_tbl[11 + i]; if (obj->spr_num == 0xFFFF) { continue; } - print_warning("Unhandled level_collide_axe_monsters object %d", 11 + i); + if (obj->data.m.state == 0xFF) { + continue; + } + struct level_monster_t *m = obj->data.m.ref; + if (m->flags & 0x10) { + continue; + } + if (!level_objects_collide(axe_obj, obj)) { + continue; + } + obj->data.m.unk5 |= 0x40; + if (obj->data.m.energy < g_vars.player_club_power) { + level_monster_die(obj, m); + } else { + obj->data.m.energy -= g_vars.player_club_power; + obj->x_pos -= obj->data.m.x_velocity >> 2; + } + obj->spr_num = 0xFFFF; + return true; } return false; } @@ -1235,12 +1284,16 @@ extern void monster_func1(int type, struct object_t *obj); /* update */ extern bool monster_func2(int type, struct level_monster_t *m); /* init */ static void level_update_objects_monsters() { + if (!g_res.dos_demo) { + /* different monsters logic/tables */ + return; + } if (g_res.level.monsters_state != 0xFF) { level_update_monsters_state(); } if (g_vars.level_num == 5 && (g_res.level.scrolling_mask & ~1) == 0) { } - for (int i = 0; i < 12; ++i) { + for (int i = 0; i < MONSTERS_COUNT; ++i) { struct object_t *obj = &g_vars.objects_tbl[11 + i]; if (obj->spr_num == 0xFFFF) { continue; @@ -2213,7 +2266,7 @@ static void level_update_player_collision() { struct object_t *obj_player = &g_vars.objects_tbl[1]; /* monsters */ if (g_vars.objects_tbl[1].hit_counter == 0) { - for (int i = 0; i < 12; ++i) { + for (int i = 0; i < MONSTERS_COUNT; ++i) { struct object_t *obj = &g_vars.objects_tbl[11 + i]; if (obj->spr_num == 0xFFFF || (obj->spr_num & 0x2000) == 0) { continue; @@ -2222,7 +2275,7 @@ static void level_update_player_collision() { if (m->flags & 0x10) { continue; } - if (obj->data.m.unkE == 0xFF) { + if (obj->data.m.state == 0xFF) { continue; } if (!level_objects_collide(obj_player, obj)) { @@ -2372,7 +2425,7 @@ static void level_update_player_collision() { } } else if (num == 169) { play_sound(0); - for (int i = 0; i < 12; ++i) { + for (int i = 0; i < MONSTERS_COUNT; ++i) { struct object_t *obj = &g_vars.objects_tbl[11 + i]; if (obj->spr_num == 0xFFFF) { continue; @@ -2387,7 +2440,7 @@ static void level_update_player_collision() { level_add_object75_score(obj, 230); } else if (num == 170) { /* bomb */ play_sound(0); - for (int i = 0; i < 12; ++i) { + for (int i = 0; i < MONSTERS_COUNT; ++i) { struct object_t *obj = &g_vars.objects_tbl[11 + i]; if (obj->spr_num == 0xFFFF) { continue; @@ -2397,7 +2450,7 @@ static void level_update_player_collision() { } g_vars.current_bonus.x_pos = obj->x_pos; g_vars.current_bonus.y_pos = obj->y_pos; - obj->data.m.unkE = 0xFF; + obj->data.m.state = 0xFF; obj->spr_num = 0xFFFF; int x_vel = 32; int y_vel = -160; @@ -3054,6 +3107,7 @@ void do_level() { set_level_palette(); video_load_sprites(); video_load_front_tiles(); + video_clear(); level_reset(); level_reset_objects(); level_init_tilemap(); diff --git a/p2/monsters.c b/p2/monsters.c index e172dcd..fe4968b 100644 --- a/p2/monsters.c +++ b/p2/monsters.c @@ -1,11 +1,13 @@ +/* monsters logic */ + #include "game.h" #include "resource.h" #include "util.h" static void monster_func1_helper(struct object_t *obj, int16_t x_pos, int16_t y_pos) { struct level_monster_t *m = obj->data.m.ref; - if (obj->data.m.unkE == 0xFF) { + if (obj->data.m.state == 0xFF) { return; } if (obj->spr_num & 0x2000) { @@ -18,7 +20,7 @@ static void monster_func1_helper(struct object_t *obj, int16_t x_pos, int16_t y_ return; } } - if (obj->data.m.unkE < 10) { + if (obj->data.m.state < 10) { obj->spr_num = 0xFFFF; m->flags &= ~4; m->current_tick = 0; @@ -65,7 +67,7 @@ static struct rotation_t *find_rotation() { return 0; } -static void monster_rotate_pos(struct level_monster_t *m, int index, int step) { +static void monster_rotate_platform(struct level_monster_t *m, int index, int step) { step >>= 2; uint8_t radius = step; for (int i = 0; i < 3; ++i) { @@ -80,6 +82,12 @@ static void monster_rotate_pos(struct level_monster_t *m, int index, int step) { } } +static void monster_rotate_pos(struct object_t *obj, struct level_monster_t *m) { + obj->x_pos = m->x_pos + ((m->type4.unkD * (cos_tbl[m->type4.angle] >> 2)) >> 4); + obj->y_pos = m->y_pos + ((m->type4.unkD * (sin_tbl[m->type4.angle] >> 2)) >> 4); + monster_rotate_platform(m, m->type4.angle, m->type4.unkD); +} + static void monster_update_y_velocity(struct object_t *obj, struct level_monster_t *m) { if ((m->flags & 1) != 0 && ((obj->spr_num & 0x2000) != 0 || g_vars.objects_tbl[1].y_pos >= obj->y_pos)) { if (obj->data.m.y_velocity < 240) { @@ -98,27 +106,61 @@ static void monster_update_y_velocity(struct object_t *obj, struct level_monster static void monster_func1_type2(struct object_t *obj) { monster_func1_helper(obj, obj->x_pos, obj->y_pos); struct level_monster_t *m = obj->data.m.ref; - uint8_t al = obj->data.m.unkE; - if (al < 2) { - monster_rotate_pos(m, 0, obj->y_pos - m->y_pos); - if (al == 0) { + const uint8_t state = obj->data.m.state; + if (state < 2) { + monster_rotate_platform(m, 0, obj->y_pos - m->y_pos); + if (state == 0) { obj->data.m.y_velocity = m->type2.unkE << 4; const int dy = obj->y_pos - m->y_pos; if (m->type2.y_range >= dy) { return; } - obj->data.m.unkE = 1; + obj->data.m.state = 1; monster_change_next_anim(obj); - } else if (al == 1) { + } else if (state == 1) { obj->data.m.y_velocity = m->type2.unkE << 4; const int dy = obj->y_pos - m->y_pos; if (dy >= 0) { return; } - obj->data.m.unkE = 0; + obj->data.m.state = 0; monster_change_prev_anim(obj); } - } else if (al == 0xFF) { + } else if (state == 0xFF) { + monster_update_y_velocity(obj, m); + } +} + +static void monster_func1_type4(struct object_t *obj) { + monster_func1_helper(obj, obj->x_pos, obj->y_pos); + struct level_monster_t *m = obj->data.m.ref; + const uint8_t state = obj->data.m.state; + if (state == 0) { + if (monster_next_tick(m)) { + return; + } + const int dy = obj->y_pos - m->y_pos; + monster_rotate_platform(m, 0, dy); + if (m->type4.unkD > dy) { + obj->y_pos += 2; + } else { + obj->data.m.state = 1; + } + } else if (state == 1) { + monster_rotate_pos(obj, m); + m->type4.angle += 4; + if (m->type4.angle >= m->type4.unkE) { + m->type4.angle = m->type4.unkE; + obj->data.m.state = 2; + } + } else if (state == 2) { + if (m->type4.angle & 0x80) { + ++m->type4.unk10; + } else { + --m->type4.unk10; + } + m->type4.angle = m->type4.unk10; + } else if (state == 0xFF) { monster_update_y_velocity(obj, m); } } @@ -130,8 +172,8 @@ static void monster_func1_type8(struct object_t *obj) { const int dx = (obj->x_pos <= g_vars.objects_tbl[1].x_pos) ? 1 : -1; obj->data.m.x_velocity = dx; } - uint8_t al = obj->data.m.unkE; - if ((al == 0 && !monster_next_tick(m)) || (al == 12 && !monster_next_tick(m))) { + const uint8_t state = obj->data.m.state; + if ((state == 0 && !monster_next_tick(m)) || (state == 12 && !monster_next_tick(m))) { const int dx = abs(g_vars.objects_tbl[1].x_pos - obj->x_pos); if (m->type8.x_range < (dx >> 4)) { return; @@ -146,40 +188,61 @@ static void monster_func1_type8(struct object_t *obj) { x_vel = -x_vel; } obj->data.m.x_velocity = x_vel; - obj->data.m.unkE = 10; + obj->data.m.state = 10; m->flags = (m->flags & ~0x2C) | 0x2C; monster_change_next_anim(obj); - } else if (al == 10) { + } else if (state == 10) { if (obj->data.m.y_velocity < 0) { return; } - obj->data.m.unkE = 11; + obj->data.m.state = 11; monster_change_next_anim(obj); - } else if (al == 11) { + } else if (state == 11) { if (obj->data.m.y_velocity > 0) { return; } - obj->data.m.unkE = 12; + obj->data.m.state = 12; monster_change_prev_anim(obj); monster_change_prev_anim(obj); obj->data.m.x_velocity = 0; m->current_tick = 0; - } else if (al == 0xFF) { + } else if (state == 0xFF) { monster_update_y_velocity(obj, m); } } static void monster_func1_type9(struct object_t *obj) { struct level_monster_t *m = obj->data.m.ref; - if ((obj->spr_num & 0x2000) == 0 && obj->data.m.unkE != 0xFF) { - } else { - uint8_t al = obj->data.m.unkE; - if (al == 0) { - } else if (al == 1) { - } else if (al == 0xFF) { - monster_update_y_velocity(obj, m); + if ((obj->spr_num & 0x2000) == 0 && obj->data.m.state != 0xFF) { + const int dy = abs(obj->y_pos - g_vars.objects_tbl[1].y_pos); + if (dy >= 190 || (g_vars.objects_tbl[1].x_pos < m->type9.unkD && g_vars.objects_tbl[1].x_pos + 480 < m->type9.unkD) || (g_vars.objects_tbl[1].x_pos >= m->type9.unkD && m->type9.unkF + 480 <= g_vars.objects_tbl[1].x_pos)) { + obj->spr_num = 0xFFFF; + m->flags &= ~4; + return; } } + const uint8_t state = obj->data.m.state; + if (state == 0) { + obj->data.m.x_velocity = m->type9.unk11; + const int x = m->type9.unk11 + 3; + if (x <= m->type9.unk12) { + m->type9.unk11 = x; + } + if (m->type9.unkF < obj->x_pos) { + obj->data.m.state = 1; + } + } else if (state == 1) { + obj->data.m.x_velocity = m->type9.unk11; + const int x = m->type9.unk11 - 3; + if (x >= -m->type9.unk12) { + m->type9.unk11 = x; + } + if (m->type9.unkD >= obj->x_pos) { + obj->data.m.state = 1; + } + } else if (state == 0xFF) { + monster_update_y_velocity(obj, m); + } } void monster_func1(int type, struct object_t *obj) { @@ -190,6 +253,9 @@ void monster_func1(int type, struct object_t *obj) { case 2: monster_func1_type2(obj); break; + case 4: + monster_func1_type4(obj); + break; case 8: monster_func1_type8(obj); break; @@ -203,7 +269,7 @@ void monster_func1(int type, struct object_t *obj) { } static struct object_t *find_object_monster() { - for (int i = 0; i < 12; ++i) { + for (int i = 0; i < MONSTERS_COUNT; ++i) { struct object_t *obj = &g_vars.objects_tbl[11 + i]; if (obj->spr_num == 0xFFFF) { return obj; @@ -224,8 +290,8 @@ static bool monster_init_object(struct level_monster_t *m) { m->flags = 0x17; obj->data.m.x_velocity = 0; obj->data.m.y_velocity = 0; - obj->data.m.unkE = 0; - obj->data.m.unkF = m->unk5; + obj->data.m.state = 0; + obj->data.m.energy = m->energy; return true; } return false; @@ -253,24 +319,22 @@ static bool monster_func2_type1(struct level_monster_t *m) { } static bool monster_func2_type2(struct level_monster_t *m) { - const int16_t x_pos = m->x_pos; - const int16_t y_pos = m->y_pos; - if (!monster_is_visible(x_pos, y_pos)) { + if (!monster_is_visible(m->x_pos, m->y_pos)) { return false; } struct object_t *obj = find_object_monster(); if (obj) { obj->data.m.unk10 = 0; g_vars.monster.current_object = obj; - obj->x_pos = x_pos; - obj->y_pos = y_pos; + obj->x_pos = m->x_pos; + obj->y_pos = m->y_pos; obj->spr_num = m->spr_num; obj->data.m.ref = m; m->flags = 5; obj->data.m.y_velocity = 0; obj->data.m.x_velocity = 0; - obj->data.m.unkE = 0; - obj->data.m.unkF = m->unk5; + obj->data.m.state = 0; + obj->data.m.energy = m->energy; return true; } return false; @@ -315,6 +379,19 @@ static bool monster_func2_type10(struct level_monster_t *m) { if (m->total_ticks > (m->current_tick >> 2)) { return false; } + const int dx = (g_vars.objects_tbl[1].x_pos >> 4) - m->x_pos; + if (dx < 0) { + return false; + } + const int dy = (g_vars.objects_tbl[1].y_pos >> 4) - m->y_pos; + if (dy < 0) { + return false; + } + struct object_t *obj = find_object_monster(); + if (!obj) { + return false; + } + print_warning("monster_func2_type10 6579"); return true; } diff --git a/p2/resource.c b/p2/resource.c index aa3f45e..60b25b7 100644 --- a/p2/resource.c +++ b/p2/resource.c @@ -123,7 +123,7 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { m->len = len; m->type = p[1]; m->spr_num = spr_num; - m->unk5 = p[5]; + m->energy = p[5]; m->total_ticks = p[6]; m->current_tick = p[7]; m->unk8 = p[8]; @@ -133,12 +133,23 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { case 2: m->type2.y_range = p[0xD]; m->type2.unkE = p[0xE]; + case 4: + m->type4.unkD = p[0xD]; + m->type4.unkE = p[0xE]; + m->type4.angle = p[0xF]; + m->type4.unk10 = p[0x10]; + break; case 8: m->type8.x_range = p[0xD]; m->type8.unkE = p[0xE]; m->type8.unkF = p[0xF]; m->type8.y_range = p[0x10]; break; + case 9: + m->type9.unkD = READ_LE_UINT16(p + 0xD); + m->type9.unkF = READ_LE_UINT16(p + 0xF); + m->type9.unk11 = p[0x11]; + m->type9.unk12 = p[0x12]; default: break; } diff --git a/p2/resource.h b/p2/resource.h index d8fc296..620a6b9 100644 --- a/p2/resource.h +++ b/p2/resource.h @@ -63,7 +63,7 @@ struct level_monster_t { uint8_t type; uint16_t spr_num; // 0x2 uint8_t flags; // 0x4 - uint8_t unk5; + uint8_t energy; // 0x5 uint8_t total_ticks; uint8_t current_tick; uint8_t unk8; @@ -74,12 +74,24 @@ struct level_monster_t { uint8_t y_range; // 0xD int8_t unkE; // 0xE, cbw } type2; + struct { + uint8_t unkD; + uint8_t unkE; + uint8_t angle; + uint8_t unk10; + } type4; struct { uint8_t x_range; // 0xD int8_t unkE; // 0xE, cbw int8_t unkF; // 0xF, cbw uint8_t y_range; // 0x10 } type8; + struct { + int16_t unkD; // 0xD + int16_t unkF; // 0xF + int8_t unk11; // 0x11 + uint8_t unk12; // 0x12 + } type9; }; };