diff --git a/p2/game.c b/p2/game.c index 6ed1c02..d3aa9f5 100644 --- a/p2/game.c +++ b/p2/game.c @@ -38,7 +38,7 @@ static void do_programmed_in_1992_screen() { if (t->tm_year + 1900 < 1996) { /* || t->tm_year + 1900 >= 2067 */ return; } - memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H); + video_clear(); g_sys.set_screen_palette(credits_palette_data, 0, 16, 6); int offset = 0x960; video_draw_string(offset, 5, "YEAAA > > >"); diff --git a/p2/game.h b/p2/game.h index af9a2b8..b8e238f 100644 --- a/p2/game.h +++ b/p2/game.h @@ -37,7 +37,7 @@ struct club_projectile_t { }; struct monster_t { - uint8_t unk5; + uint8_t flags; void *ref; int16_t x_velocity; int16_t y_velocity; @@ -169,7 +169,7 @@ struct vars_t { uint8_t level_xscroll_center_flag, level_yscroll_center_flag; uint8_t level_force_x_scroll_flag; bool tilemap_adjust_player_pos_flag; - uint8_t level_noscroll_flag; + uint8_t tilemap_noscroll_flag; int16_t tilemap_yscroll_diff; int16_t tilemap_x, tilemap_y; int16_t tilemap_prev_x, tilemap_prev_y; @@ -234,7 +234,7 @@ extern const uint8_t vscroll_offsets_data[132]; extern const uint8_t cos_tbl[256]; extern const uint8_t sin_tbl[256]; extern const uint16_t monster_spr_tbl[48]; -extern const uint8_t monster_anim_tbl[]; +extern const uint8_t monster_anim_tbl[1018]; /* game.c */ extern void update_input(); diff --git a/p2/level.c b/p2/level.c index 2994ce0..9947d0f 100644 --- a/p2/level.c +++ b/p2/level.c @@ -335,7 +335,7 @@ static bool level_adjust_hscroll_right() { } static void level_adjust_x_scroll() { - if (!g_options.dos_scrolling && g_vars.level_noscroll_flag == 0) { + if (!g_options.dos_scrolling && g_vars.tilemap_noscroll_flag == 0) { const int x1 = TILEMAP_SCROLL_W * 2; const int x2 = TILEMAP_SCREEN_W - TILEMAP_SCROLL_W * 2; int tilemap_xpos = (g_vars.tilemap_x << 4) + g_vars.tilemap_scroll_dx; @@ -523,7 +523,7 @@ static void level_adjust_y_scroll() { } static void level_update_scrolling() { - if (g_vars.level_noscroll_flag != 0) { + if (g_vars.tilemap_noscroll_flag != 0) { return; } if ((g_res.level.scrolling_mask & 2) == 0) { @@ -1105,7 +1105,7 @@ static void level_monster_die(struct object_t *obj, struct level_monster_t *m) { dy = (-dy) << 3; obj->data.m.y_velocity = dy; int dx = dy >> 1; - if ((obj->data.m.unk5 & 0x80) == 0) { + if ((obj->data.m.flags & 0x80) == 0) { dx = -dx; } obj->data.m.x_velocity = dx; @@ -1128,7 +1128,7 @@ static bool level_collide_axe_monsters(struct object_t *axe_obj) { if (!level_objects_collide(axe_obj, obj)) { continue; } - obj->data.m.unk5 |= 0x40; + obj->data.m.flags |= 0x40; obj->data.m.energy -= g_vars.player_club_power; if (obj->data.m.energy < 0) { level_monster_die(obj, m); @@ -1453,10 +1453,15 @@ static void level_update_objects_monsters() { continue; } const uint8_t *p = monster_anim_tbl; + const uint8_t *end = &monster_anim_tbl[1018]; const int spr_num = m->spr_num - 305; do { p += 2; - } while (READ_LE_UINT16(p) != 0x7D01 || READ_LE_UINT16(p + 2) != m->type); + if (p >= end) { + print_warning("level_update_objects_monsters type %d spr %d not found", m->type, spr_num); + continue; + } + } while (READ_LE_UINT16(p) != 0x7D01 || READ_LE_UINT16(p + 2) != type); p += 4; while (READ_LE_UINT16(p) != spr_num) { p += 2; @@ -1997,7 +2002,7 @@ static void level_update_player_anim_0(uint8_t al) { if ((g_vars.input.key_right & g_vars.input.key_left) != 0) { const uint8_t *anim = level_update_player_anim1_num(19, 38); level_update_object_anim(anim); - if ((g_res.level.scrolling_mask & 2) == 0 && g_vars.level_noscroll_flag == 0) { + if ((g_res.level.scrolling_mask & 2) == 0 && g_vars.tilemap_noscroll_flag == 0) { const int dx = (g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap_x; if ((g_vars.objects_tbl[1].spr_num & 0x8000) == 0) { if (dx > 2) { @@ -2743,7 +2748,7 @@ static void level_update_gates() { } } g_res.level.tilemap_w = tmp; - g_vars.level_noscroll_flag = gate->scroll_flag; + g_vars.tilemap_noscroll_flag = gate->scroll_flag; g_vars.player_action_counter = 0; if (g_vars.level_num == 5) { } diff --git a/p2/monsters.c b/p2/monsters.c index 6c3228e..61204a1 100644 --- a/p2/monsters.c +++ b/p2/monsters.c @@ -39,10 +39,10 @@ static void monster_func1_helper(struct object_t *obj, int16_t x_pos, int16_t y_ } static bool monster_next_tick(struct level_monster_t *m) { - if (m->current_tick < 255) { + if (m->current_tick < UCHAR_MAX) { ++m->current_tick; } - return ((m->current_tick >> 2) < m->total_ticks); + return ((m->current_tick >> 2) < m->respawn_ticks); } void monster_change_next_anim(struct object_t *obj) { @@ -130,6 +130,45 @@ static void monster_func1_type2(struct object_t *obj) { } } +static void monster_func1_type3(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 dx = abs(m->x_pos - g_vars.objects_tbl[1].x_pos) >> 4; + if (m->type3.unkD < dx) { + return; + } + m->flags &= ~0x10; + obj->data.m.state = 1; + obj->data.m.y_velocity = 32; + monster_change_next_anim(obj); + } else if (state == 1) { + monster_rotate_tiles(m, 0, obj->y_pos - m->y_pos); + const uint16_t pos = ((obj->y_pos >> 4) << 8) | (obj->x_pos >> 4); + const uint8_t tile_num = g_res.leveldat[pos]; + if (g_res.level.tile_attributes1[tile_num] == 0) { + return; + } + obj->y_pos &= ~15; + obj->data.m.y_velocity = 0; + obj->data.m.state = 2; + m->flags |= 0x48; + const int dx = (g_vars.objects_tbl[1].x_pos >= obj->x_pos) ? 48 : -48; + obj->data.m.x_velocity = dx; + monster_change_next_anim(obj); + } else if (state == 2) { + if (obj->x_pos < 0) { + obj->data.m.x_velocity = -obj->data.m.x_velocity; + } + } 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; @@ -165,6 +204,31 @@ static void monster_func1_type4(struct object_t *obj) { } } +static void monster_func1_type7(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) { + const int x_vel = (obj->x_pos <= g_vars.objects_tbl[1].x_pos) ? 1 : -1; + obj->data.m.x_velocity = x_vel; + const int dx = abs(g_vars.objects_tbl[1].x_pos - obj->x_pos) >> 4; + if (m->type7.unkD < dx) { + return; + } + obj->data.m.state = 10; + int x = m->type7.unkE << 4; + obj->data.m.y_velocity = x; + if (obj->data.m.x_velocity & 0x5000) { + x = -x; + } + obj->data.m.x_velocity = x; + monster_change_next_anim(obj); + } else if (state == 10) { + } else if (state == 0xFF) { + monster_update_y_velocity(obj, m); + } +} + static void monster_func1_type8_helper(struct object_t *obj, struct level_monster_t *m) { obj->data.m.y_velocity = -(m->type8.y_step << 4); int x_vel = m->type8.x_step << 4; @@ -229,22 +293,22 @@ static void monster_func1_type9(struct object_t *obj) { } 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; + obj->data.m.x_velocity = m->type9.x_step; + const int x = m->type9.x_step + 3; + if (x <= m->type9.x_dist) { + m->type9.x_step = 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; + obj->data.m.x_velocity = m->type9.x_step; + const int x = m->type9.x_step - 3; + if (x >= -m->type9.x_dist) { + m->type9.x_step = x; } if (m->type9.unkD >= obj->x_pos) { - obj->data.m.state = 1; + obj->data.m.state = 0; } } else if (state == 0xFF) { monster_update_y_velocity(obj, m); @@ -300,7 +364,7 @@ static void monster_func1_type10(struct object_t *obj) { } monster_reset(obj, m); } else if (state == 0xFF) { - if ((m->flags & 1) != 0 || (obj->data.m.unk5 & 0x20) != 0 || g_vars.objects_tbl[1].y_pos >= obj->y_pos) { + if ((m->flags & 1) != 0 || (obj->data.m.flags & 0x20) != 0 || g_vars.objects_tbl[1].y_pos >= obj->y_pos) { if (obj->data.m.y_velocity < 240) { obj->data.m.y_velocity += 15; } @@ -310,6 +374,61 @@ static void monster_func1_type10(struct object_t *obj) { } } +static void monster_func1_type11(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 (g_vars.monster.hit_mask == 0) { + return; + } + obj->data.m.state = 1; + m->flags &= ~0x10; + int x_vel = m->type11.unkD << 4; + if (g_vars.objects_tbl[1].x_pos <= obj->x_pos) { + x_vel = -x_vel; + } + obj->data.m.x_velocity = x_vel; + obj->data.m.y_velocity = -(m->type11.unkE << 4); + } else if (state == 1) { + if (obj->data.m.y_velocity < (m->type11.unkF << 4)) { + obj->data.m.y_velocity += 8; + } + } else if (state == 0xFF) { + if ((obj->data.m.flags & 0x20) != 0 || g_vars.objects_tbl[1].y_pos >= obj->y_pos) { + if (obj->data.m.y_velocity < 240) { + obj->data.m.y_velocity += 15; + } + } else { + monster_reset(obj, m); + } + } +} + +static void monster_func1_type12(struct object_t *obj) { + struct level_monster_t *m = obj->data.m.ref; + const uint8_t state = obj->data.m.state; + if (state == 0) { + int x_vel = m->type12.unkD; + if (g_vars.objects_tbl[1].x_pos < obj->x_pos) { + x_vel = -x_vel; + } + obj->data.m.x_velocity = x_vel << 4; + obj->data.m.state = 1; + } else if (state == 1) { + if (obj->data.m.flags & 0x20) { + m->current_tick = 0; + } else { + ++m->current_tick; + if (m->current_tick >= 154) { + obj->data.m.state = 0xFF; + } + } + } else if (state == 0xFF) { + monster_update_y_velocity(obj, m); + } +} + void monster_func1(int type, struct object_t *obj) { switch (type) { case 1: @@ -318,9 +437,15 @@ void monster_func1(int type, struct object_t *obj) { case 2: monster_func1_type2(obj); break; + case 3: + monster_func1_type3(obj); + break; case 4: monster_func1_type4(obj); break; + case 7: + monster_func1_type7(obj); + break; case 8: monster_func1_type8(obj); break; @@ -330,6 +455,12 @@ void monster_func1(int type, struct object_t *obj) { case 10: monster_func1_type10(obj); break; + case 11: + monster_func1_type11(obj); + break; + case 12: + monster_func1_type12(obj); + break; default: print_warning("monster_func1 unhandled monster type %d", type); break; @@ -406,6 +537,14 @@ static bool monster_func2_type2(struct level_monster_t *m) { return false; } +static bool monster_func2_type3(struct level_monster_t *m) { + if (!monster_func2_type1(m)) { + return false; + } + m->flags = 0x37; + return true; +} + static bool monster_func2_type4(struct level_monster_t *m) { if (!monster_func2_type1(m)) { return false; @@ -441,10 +580,10 @@ static bool monster_func2_type10(struct level_monster_t *m) { if (g_vars.level_num == 5 && g_vars.shake_screen_counter != 0) { return false; } - if (m->current_tick < 255) { + if (m->current_tick < UCHAR_MAX) { ++m->current_tick; } - if (m->total_ticks > (m->current_tick >> 2)) { + if (m->respawn_ticks > (m->current_tick >> 2)) { return false; } const uint16_t x = m->x_pos; @@ -475,19 +614,19 @@ static bool monster_func2_type10(struct level_monster_t *m) { obj->data.m.x_velocity = 0; uint8_t bh = (g_vars.objects_tbl[1].y_pos >> 4) + 4; uint8_t bl = (obj->x_pos >> 4); - uint16_t bp = (bh << 8) | bl; - for (int i = 0; i < 10; ++i) { - if (bp < (g_vars.tilemap_h << 8)) { + uint16_t pos = (bh << 8) | bl; + for (int i = 0; i < 10 && pos >= 0x300; ++i, pos -= 0x100) { + if (pos < (g_vars.tilemap_h << 8)) { bool init_spr = true; for (int j = 0; j < 3; ++j) { - const uint8_t tile_num = g_res.leveldat[bp - j * 0x100]; + const uint8_t tile_num = g_res.leveldat[pos - j * 0x100]; if (g_res.level.tile_attributes1[tile_num] != 0) { init_spr = false; break; } } if (init_spr) { - obj->y_pos = bh << 4; + obj->y_pos = (pos >> 8) << 4; obj->spr_num = m->spr_num; obj->data.m.ref = m; m->flags = 0x17; @@ -497,19 +636,15 @@ static bool monster_func2_type10(struct level_monster_t *m) { return true; } } - bp -= 0x100; - if (bp < 0x300) { - return false; - } } return false; } static bool monster_func2_type11(struct level_monster_t *m) { - if (m->current_tick < 255) { + if (m->current_tick < UCHAR_MAX) { ++m->current_tick; } - if (m->total_ticks > (m->current_tick >> 2) || !monster_func2_type1(m)) { + if (m->respawn_ticks > (m->current_tick >> 2) || !monster_func2_type1(m)) { return false; } m->flags = 0x37; @@ -517,12 +652,42 @@ static bool monster_func2_type11(struct level_monster_t *m) { return true; } +static bool monster_func2_type12(struct level_monster_t *m) { + if (g_vars.objects_tbl[1].y_pos <= m->y_pos) { + return false; + } + const int dx = abs(m->x_pos - g_vars.objects_tbl[1].x_pos); + if (dx >= TILEMAP_SCREEN_W * 2) { + return false; + } + if (dx <= TILEMAP_SCREEN_W) { + const int dy = g_vars.objects_tbl[1].y_pos - m->y_pos; + if (dy >= 360 || dy <= 180) { + return false; + } + } + if (m->current_tick < UCHAR_MAX) { + ++m->current_tick; + } + if (m->respawn_ticks > (m->current_tick >> 2)) { + return false; + } + if (!monster_init_object(m)) { + return false; + } + m->flags = 0x8F; + m->current_tick = 0; + return true; +} + bool monster_func2(int type, struct level_monster_t *m) { switch (type) { case 1: return monster_func2_type1(m); case 2: return monster_func2_type2(m); + case 3: + return monster_func2_type3(m); case 4: return monster_func2_type4(m); case 5: @@ -536,6 +701,8 @@ bool monster_func2(int type, struct level_monster_t *m) { return monster_func2_type10(m); case 11: return monster_func2_type11(m); + case 12: + return monster_func2_type12(m); default: print_warning("monster_func2 unhandled monster type %d", type); break; diff --git a/p2/resource.c b/p2/resource.c index 4e84651..1bb041a 100644 --- a/p2/resource.c +++ b/p2/resource.c @@ -124,7 +124,7 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { m->type = p[1]; m->spr_num = spr_num; m->energy = p[5]; - m->total_ticks = p[6]; + m->respawn_ticks = p[6]; m->current_tick = p[7]; m->score = p[8]; m->x_pos = READ_LE_UINT16(p + 0x9); @@ -138,6 +138,9 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { m->type2.y_range = p[0xD]; m->type2.unkE = p[0xE]; break; + case 3: + m->type3.unkD = p[0xD]; + break; case 4: /* rotate (eg. spider) */ assert(len == 17); m->type4.radius = p[0xD]; @@ -145,7 +148,11 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { m->type4.angle = p[0xF]; m->type4.unk10 = p[0x10]; break; - case 8: /* jumps (eg. leopard) */ + case 7: + m->type7.unkD = p[0xD]; + m->type7.unkE = p[0xE]; + break; + case 8: /* jump */ assert(len == 17); m->type8.x_range = p[0xD]; m->type8.y_step = p[0xE]; @@ -156,13 +163,22 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { assert(len == 19); 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]; + m->type9.x_step = p[0x11]; + m->type9.x_dist = p[0x12]; break; case 10: /* come out of the ground */ assert(len == 14); m->type10.unkD = p[0xD]; break; + case 11: + m->type11.unkD = p[0xD]; + m->type11.unkE = p[0xE]; + m->type11.unkF = p[0xF]; + break; + case 12: + assert(len == 14); + m->type12.unkD = p[0xD]; + break; default: print_warning("Unhandled monster type %d len %d", type, len); break; diff --git a/p2/resource.h b/p2/resource.h index 2be88ac..e9f4fe0 100644 --- a/p2/resource.h +++ b/p2/resource.h @@ -64,7 +64,7 @@ struct level_monster_t { uint16_t spr_num; uint8_t flags; uint8_t energy; - uint8_t total_ticks; + uint8_t respawn_ticks; uint8_t current_tick; uint8_t score; uint16_t x_pos; @@ -74,12 +74,19 @@ struct level_monster_t { uint8_t y_range; int8_t unkE; } type2; + struct { + uint8_t unkD; + } type3; struct { uint8_t radius; uint8_t unkE; uint8_t angle; uint8_t unk10; } type4; + struct { + uint8_t unkD; + uint8_t unkE; + } type7; struct { uint8_t x_range; int8_t y_step; @@ -89,12 +96,20 @@ struct level_monster_t { struct { int16_t unkD; int16_t unkF; - int8_t unk11; - uint8_t unk12; + int8_t x_step; + uint8_t x_dist; } type9; struct { uint8_t unkD; } type10; + struct { + uint8_t unkD; + uint8_t unkE; + uint8_t unkF; + } type11; + struct { + uint8_t unkD; + } type12; }; };