From 0bc6efe99c374573f5861a074f2677275100991e Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sun, 2 Jun 2019 07:47:35 +0800 Subject: [PATCH] Import blues from a905c587 --- README.md | 8 + bb/fileio.c | 95 --------- bb/fileio.h | 15 -- p2/game.c | 11 +- p2/game.h | 43 +++- p2/level.c | 570 +++++++++++++++++++++++++++++++++++++------------- p2/monsters.c | 18 +- p2/resource.c | 14 +- p2/resource.h | 14 +- p2/screen.c | 3 - 10 files changed, 491 insertions(+), 300 deletions(-) delete mode 100644 bb/fileio.c delete mode 100644 bb/fileio.h diff --git a/README.md b/README.md index e8babf1..53617a7 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,14 @@ The data files of the DOS version, full game or [demo](http://cd.textfiles.com/c *.SQZ, *.TRK ``` +## Changes + +Compared to the original DOS executables, the rewritten engines feature : + +- horizontal scrolling +- configurable screen size +- game cheats : unlimited lifes and energy, no hit + ## Running diff --git a/bb/fileio.c b/bb/fileio.c deleted file mode 100644 index e182f1c..0000000 --- a/bb/fileio.c +++ /dev/null @@ -1,95 +0,0 @@ - -#include -#include "fileio.h" -#include "util.h" - -#define MAX_FILEIO_SLOTS 2 - -struct fileio_slot_t { - FILE *fp; - int size; -} fileio_slot_t; - -static const char *_data_path; -static struct fileio_slot_t _fileio_slots_table[MAX_FILEIO_SLOTS]; - -static int find_free_slot() { - int i, slot = -1; - for (i = 0; i < MAX_FILEIO_SLOTS; ++i) { - if (!_fileio_slots_table[i].fp) { - slot = i; - break; - } - } - return slot; -} - -void fio_init(const char *data_path) { - _data_path = data_path; - memset(_fileio_slots_table, 0, sizeof(_fileio_slots_table)); -} - -void fio_fini() { -} - -int fio_open(const char *filename, int error_flag) { - int slot = find_free_slot(); - if (slot < 0) { - print_error("Unable to find free slot for '%s'", filename); - } else { - struct fileio_slot_t *file_slot = &_fileio_slots_table[slot]; - memset(file_slot, 0, sizeof(fileio_slot_t)); - file_slot->fp = fopen_nocase(_data_path, filename); - if (!file_slot->fp) { - if (error_flag) { - print_error("Unable to open file '%s'", filename); - } else { - print_warning("Unable to open file '%s'", filename); - } - slot = -1; - } else { - fseek(file_slot->fp, 0, SEEK_END); - file_slot->size = ftell(file_slot->fp); - fseek(file_slot->fp, 0, SEEK_SET); - } - } - return slot; -} - -void fio_close(int slot) { - if (slot >= 0) { - struct fileio_slot_t *file_slot = &_fileio_slots_table[slot]; - assert(file_slot->fp); - fclose(file_slot->fp); - memset(file_slot, 0, sizeof(fileio_slot_t)); - } -} - -int fio_size(int slot) { - int size = 0; - if (slot >= 0) { - struct fileio_slot_t *file_slot = &_fileio_slots_table[slot]; - assert(file_slot->fp); - size = file_slot->size; - } - return size; -} - -int fio_read(int slot, void *data, int len) { - int sz = 0; - if (slot >= 0) { - struct fileio_slot_t *file_slot = &_fileio_slots_table[slot]; - assert(file_slot->fp); - sz = fread(data, 1, len, file_slot->fp); - } - return sz; -} - -int fio_exists(const char *filename) { - FILE *fp = fopen_nocase(_data_path, filename); - if (fp) { - fclose(fp); - return 1; - } - return 0; -} diff --git a/bb/fileio.h b/bb/fileio.h deleted file mode 100644 index 10ba0cd..0000000 --- a/bb/fileio.h +++ /dev/null @@ -1,15 +0,0 @@ - -#ifndef FILEIO_H__ -#define FILEIO_H__ - -#include "intern.h" - -extern void fio_init(const char *datapath); -extern void fio_fini(); -extern int fio_open(const char *filename, int error_flag); -extern void fio_close(int slot); -extern int fio_size(int slot); -extern int fio_read(int slot, void *data, int len); -extern int fio_exists(const char *filename); - -#endif /* FILEIO_H__ */ diff --git a/p2/game.c b/p2/game.c index 89d4fa3..dc46b8d 100644 --- a/p2/game.c +++ b/p2/game.c @@ -3,6 +3,7 @@ #include "game.h" #include "resource.h" #include "sys.h" +#include "util.h" struct vars_t g_vars; @@ -213,7 +214,6 @@ static void game_run(const char *data_path) { g_vars.starttime = g_sys.get_timestamp(); while (!g_sys.input.quit) { if (1) { - video_set_palette(); g_vars.player_lifes = 2; g_vars.player_bonus_letters_mask = 0; g_vars.player_club_power = 20; @@ -223,9 +223,12 @@ static void game_run(const char *data_path) { } do_menu(); } - video_set_palette(); - video_set_palette(); - do_level(); + uint8_t level_num; + do { + level_num = g_vars.level_num; + do_level(); + print_debug(DBG_GAME, "previous level %d current %d", level_num, g_vars.level_num); + } while (!g_res.dos_demo && g_vars.level_num != level_num); } sound_fini(); res_fini(); diff --git a/p2/game.h b/p2/game.h index aa0f667..244294e 100644 --- a/p2/game.h +++ b/p2/game.h @@ -80,8 +80,17 @@ struct object_t { 55 20 : items 75 16 : bonus scores 91 7 : decor + 98 5 : boss level 5 (tree) */ +struct boss_level5_proj_t { + int16_t x_pos, y_pos; + uint16_t spr_num; + uint16_t unk6; + uint16_t unk8; + int8_t dir; +}; + struct rotation_t { uint16_t x_pos; uint16_t y_pos; @@ -170,22 +179,25 @@ struct vars_t { bool tilemap_adjust_player_pos_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; - int8_t tilemap_scroll_dx, tilemap_scroll_dy; - uint8_t tilemap_h; - uint16_t tilemap_size; /* tilemap size h*256 */ uint16_t tilemap_start_x_pos, tilemap_start_y_pos; /* tilemap restart position */ uint8_t tile_attr2_flags; /* current tilemap tile types (eg. front) */ + uint8_t level_animated_tiles_counter; /* animated tiles update counter */ uint8_t *level_animated_tiles_current_tbl; /* pointer to current tile_tbl */ uint8_t tile_tbl1[256]; /* animated tile state 1 */ uint8_t tile_tbl2[256]; /* animated tile state 2 */ uint8_t tile_tbl3[256]; /* animated tile state 3 */ uint8_t animated_tile_flag_tbl[256]; /* 1 if tile is animated */ - uint8_t tilemap_redraw_flag2; /* tilemap needs redraw */ - uint8_t tilemap_redraw_flag1; /* force redraw even if tilemap origin did not change */ + struct { + int16_t x, y; + int16_t prev_x, prev_y; + int8_t scroll_dx, scroll_dy; + uint8_t redraw_flag2; /* tilemap needs redraw */ + uint8_t redraw_flag1; /* force redraw even if tilemap origin did not change */ + uint8_t h; + uint16_t size; /* tilemap size h*256 */ + } tilemap; struct { struct object_t *current_object; uint8_t type10_dist; @@ -193,6 +205,22 @@ struct vars_t { int16_t collide_y_dist; uint8_t type0_hdir; } monster; + struct { + int16_t x_pos, y_pos; + uint8_t hdir; + int16_t x_dist; + } boss; + struct { + uint8_t unk1; + uint8_t energy; + uint8_t state; /* 3: boss dead */ + uint8_t unk4; /* spr103_pos */ + uint8_t unk5; /* spr106_pos */ + uint8_t unk6; + uint8_t counter; + uint8_t unk8; + struct boss_level5_proj_t proj_tbl[5]; + } boss_level5; struct { int16_t x_pos, y_pos; uint16_t spr_num; @@ -263,7 +291,6 @@ extern void video_draw_number(int offset, int num); extern void video_draw_tile(const uint8_t *src, int x, int y); extern void video_convert_tiles(uint8_t *data, int len); extern void video_load_front_tiles(); -extern void video_set_palette(); extern void fade_in_palette(); extern void fade_out_palette(); extern void video_wait_vbl(); diff --git a/p2/level.c b/p2/level.c index 6b6e2e1..882b1b1 100644 --- a/p2/level.c +++ b/p2/level.c @@ -6,6 +6,8 @@ #include "sys.h" #include "util.h" +static const bool _score_8_digits = true; /* maximum score 99.999.999 */ + static const bool _redraw_tilemap = true; static const bool _redraw_panel = true; @@ -20,9 +22,9 @@ static void set_level_palette() { static int load_level_data_get_tilemap_size(int num, const uint8_t *lev, const uint8_t *uni) { static const uint8_t level_height_tbl[] = { 0x31, 0x68, 0x31, 0x2D, 0x80, 0x80, 0x80, 0x56, 0x6E, 0x0C, 0x18, 0x33, 0x33, 0x26, 0xAD, 0x54 }; - g_vars.tilemap_h = level_height_tbl[num]; + g_vars.tilemap.h = level_height_tbl[num]; const int tilemap_size = level_height_tbl[num] << 8; - g_vars.tilemap_size = tilemap_size; + g_vars.tilemap.size = tilemap_size; int offset = 0; for (int i = 0; i < 512; i += 2) { const uint16_t num = READ_LE_UINT16(lev + tilemap_size + i); @@ -41,7 +43,7 @@ static int load_level_data_get_tilemap_size(int num, const uint8_t *lev, const u static bool level_check_tilemap_offset(uint16_t offset) { const uint8_t x = offset & 255; const uint8_t y = offset >> 8; - if (y >= g_vars.tilemap_h) { + if (y >= g_vars.tilemap.h) { print_debug(DBG_GAME, "invalid tilemap offset %d (%d,%d)", (int16_t)offset, x, y); return false; } @@ -94,7 +96,7 @@ 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_offset = g_vars.tilemap.size + 512; const int tiles_count = (g_res.levellen - tiles_offset) / 128; int count = 1; for (int i = 0; i < tiles_count; ++i) { @@ -108,10 +110,10 @@ static void load_level_data_init_transparent_tiles() { } if (mask_transparent == 0) { } else if (mask_opaque == 0xFF) { - g_vars.tilemap_redraw_flag2 = 1; + g_vars.tilemap.redraw_flag2 = 1; } else { ++count; - g_vars.tilemap_redraw_flag2 = 1; + g_vars.tilemap.redraw_flag2 = 1; } } } @@ -184,6 +186,7 @@ static void load_level_data_init_password_items() { return; } qsort(items_ptr_tbl, count, sizeof(struct level_item_t *), compare_level_item_x_pos); + /* level password */ const uint16_t r = random_get_number3(g_vars.level_num); for (int j = 0; j < count; j += 4) { for (int i = 0; i < 4; ++i) { @@ -213,7 +216,7 @@ static void load_level_data(int num) { const int offset = load_level_data_get_tilemap_size(num, g_res.leveldat, data); print_debug(DBG_GAME, "tilemap offset %d", offset); load_leveldat(g_res.leveldat + offset, 0); - video_convert_tiles(g_res.leveldat + g_vars.tilemap_size + 512, offset - (g_vars.tilemap_size + 512)); + video_convert_tiles(g_res.leveldat + g_vars.tilemap.size + 512, offset - (g_vars.tilemap.size + 512)); print_debug(DBG_GAME, "start_pos %d,%d end_pos %d,%d", g_res.level.start_x_pos, g_res.level.start_y_pos, g_res.level.end_x_pos, g_res.level.end_y_pos); load_level_data_init_animated_tiles(); load_level_data_init_transparent_tiles(); @@ -228,14 +231,14 @@ static void load_level_data(int num) { } static void level_draw_tile(int tile_num, int x, int y) { - const int num = READ_LE_UINT16(g_res.leveldat + g_vars.tilemap_size + tile_num * 2); + const int num = READ_LE_UINT16(g_res.leveldat + g_vars.tilemap.size + tile_num * 2); const uint8_t *tiledat; if (num < 0x100) { - tiledat = g_res.leveldat + g_vars.tilemap_size + 512 + num * 128; + tiledat = g_res.leveldat + g_vars.tilemap.size + 512 + num * 128; } else { tiledat = g_res.uniondat + (num - 256) * 128; } - video_draw_tile(tiledat, x * 16 - g_vars.tilemap_scroll_dx, y * 16 - g_vars.tilemap_scroll_dy); + video_draw_tile(tiledat, x * 16 - g_vars.tilemap.scroll_dx, y * 16 - g_vars.tilemap.scroll_dy); } static void level_update_tilemap() { @@ -265,7 +268,7 @@ static void level_update_tilemap() { } } g_vars.tile_attr2_flags = 0; - uint16_t offset = (g_vars.tilemap_y << 8) | g_vars.tilemap_x; + uint16_t offset = (g_vars.tilemap.y << 8) | g_vars.tilemap.x; for (int y = 0; y < (TILEMAP_SCREEN_H / 16) + 1; ++y) { for (int x = 0; x < (TILEMAP_SCREEN_W / 16) + 1; ++x) { const uint8_t tile_num = level_get_tile(offset + x); @@ -283,21 +286,21 @@ static void level_draw_tilemap() { if (_redraw_tilemap) { return; } - if (g_vars.tilemap_redraw_flag1 == 0) { - const bool changed = (g_vars.tilemap_x != g_vars.tilemap_prev_x) || (g_vars.tilemap_y != g_vars.tilemap_prev_y); + if (g_vars.tilemap.redraw_flag1 == 0) { + const bool changed = (g_vars.tilemap.x != g_vars.tilemap.prev_x) || (g_vars.tilemap.y != g_vars.tilemap.prev_y); if (!changed) { return; } - g_vars.tilemap_prev_x = g_vars.tilemap_x; - g_vars.tilemap_prev_y = g_vars.tilemap_y; - if (g_vars.tilemap_redraw_flag2 == 0) { + g_vars.tilemap.prev_x = g_vars.tilemap.x; + g_vars.tilemap.prev_y = g_vars.tilemap.y; + if (g_vars.tilemap.redraw_flag2 == 0) { return; } } - g_vars.tilemap_redraw_flag1 = 0; - g_vars.tilemap_redraw_flag2 = 0; + g_vars.tilemap.redraw_flag1 = 0; + g_vars.tilemap.redraw_flag2 = 0; g_vars.tile_attr2_flags = 0; - uint16_t offset = (g_vars.tilemap_y << 8) | g_vars.tilemap_x; + uint16_t offset = (g_vars.tilemap.y << 8) | g_vars.tilemap.x; for (int y = 0; y < (TILEMAP_SCREEN_H / 16) + 1; ++y) { for (int x = 0; x < TILEMAP_SCREEN_W / 16; ++x) { const uint8_t tile_num = level_get_tile(offset + x); @@ -309,10 +312,10 @@ static void level_draw_tilemap() { } static bool level_adjust_hscroll_left() { - if (g_vars.tilemap_x == 0) { + if (g_vars.tilemap.x == 0) { return true; } - --g_vars.tilemap_x; + --g_vars.tilemap.x; return false; } @@ -327,10 +330,10 @@ static uint16_t tilemap_end_xpos() { } static bool level_adjust_hscroll_right() { - if (g_vars.tilemap_x >= tilemap_end_xpos()) { + if (g_vars.tilemap.x >= tilemap_end_xpos()) { return true; } - ++g_vars.tilemap_x; + ++g_vars.tilemap.x; return false; } @@ -338,7 +341,7 @@ static void level_adjust_x_scroll() { 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; + int tilemap_xpos = (g_vars.tilemap.x << 4) + g_vars.tilemap.scroll_dx; const int player_xpos = g_vars.objects_tbl[1].x_pos - tilemap_xpos; if (player_xpos > x2) { tilemap_xpos += (player_xpos - x2); @@ -352,14 +355,14 @@ static void level_adjust_x_scroll() { tilemap_xpos = 0; } } - g_vars.tilemap_x = (tilemap_xpos >> 4); - g_vars.tilemap_scroll_dx = (tilemap_xpos & 15); - g_vars.tilemap_scroll_dx &= ~1; + g_vars.tilemap.x = (tilemap_xpos >> 4); + g_vars.tilemap.scroll_dx = (tilemap_xpos & 15); + g_vars.tilemap.scroll_dx &= ~1; g_vars.level_xscroll_center_flag = 0; return; } - const int x_pos = (g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap_x; + const int x_pos = (g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap.x; if (x_pos >= (TILEMAP_SCREEN_W / 16) || g_vars.level_force_x_scroll_flag != 0 || g_vars.objects_tbl[1].x_velocity != 0) { if (g_vars.level_xscroll_center_flag != 0) { if (g_vars.level_xscroll_center_flag != 1) { @@ -405,34 +408,34 @@ static void level_adjust_x_scroll() { } static bool level_adjust_vscroll_down(int dl) { - const int end_y = g_vars.tilemap_h - (TILEMAP_SCREEN_H / 16); - if (g_vars.tilemap_y >= end_y) { + const int end_y = g_vars.tilemap.h - (TILEMAP_SCREEN_H / 16); + if (g_vars.tilemap.y >= end_y) { return false; } - ++g_vars.tilemap_redraw_flag1; - g_vars.tilemap_scroll_dy += dl; - if (g_vars.tilemap_scroll_dy < 16) { + ++g_vars.tilemap.redraw_flag1; + g_vars.tilemap.scroll_dy += dl; + if (g_vars.tilemap.scroll_dy < 16) { return true; } - g_vars.tilemap_scroll_dy -= 16; - ++g_vars.tilemap_y; - if (g_vars.tilemap_y >= end_y) { - g_vars.tilemap_scroll_dy = 0; + g_vars.tilemap.scroll_dy -= 16; + ++g_vars.tilemap.y; + if (g_vars.tilemap.y >= end_y) { + g_vars.tilemap.scroll_dy = 0; } return true; } static bool level_adjust_vscroll_up(int dl) { - if (g_vars.tilemap_y == 0) { + if (g_vars.tilemap.y == 0) { return false; } - ++g_vars.tilemap_redraw_flag1; - g_vars.tilemap_scroll_dy -= dl; - if (g_vars.tilemap_scroll_dy >= 0) { + ++g_vars.tilemap.redraw_flag1; + g_vars.tilemap.scroll_dy -= dl; + if (g_vars.tilemap.scroll_dy >= 0) { return true; } - g_vars.tilemap_scroll_dy += 16; - --g_vars.tilemap_y; + g_vars.tilemap.scroll_dy += 16; + --g_vars.tilemap.y; return true; } @@ -444,7 +447,7 @@ static void level_adjust_y_scroll() { if (g_vars.objects_tbl[1].data.p.y_velocity == 0) { g_vars.level_yscroll_center_flag = 0; } - const int player_yorigin_diff = (g_vars.objects_tbl[1].y_pos >> 4) - g_vars.tilemap_y; + const int player_yorigin_diff = (g_vars.objects_tbl[1].y_pos >> 4) - g_vars.tilemap.y; if (g_vars.objects_tbl[1].data.p.y_velocity != 0) { if (player_yorigin_diff >= 9) { g_vars.tilemap_yscroll_diff = 3; @@ -476,7 +479,7 @@ static void level_adjust_y_scroll() { return; } const int bottom = (g_res.level.scrolling_top + (TILEMAP_SCREEN_H / 16)) << 4; - if (g_vars.objects_tbl[1].y_pos > bottom || g_res.level.scrolling_top >= g_vars.tilemap_y - 1) { + if (g_vars.objects_tbl[1].y_pos > bottom || g_res.level.scrolling_top >= g_vars.tilemap.y - 1) { if (g_vars.level_yscroll_center_flag == 0) { return; } @@ -485,14 +488,14 @@ static void level_adjust_y_scroll() { return; } if (g_vars.tilemap_yscroll_diff < player_yorigin_diff) { - if (g_vars.objects_tbl[1].y_pos <= bottom && g_vars.tilemap_y > g_res.level.scrolling_top) { + if (g_vars.objects_tbl[1].y_pos <= bottom && g_vars.tilemap.y > g_res.level.scrolling_top) { g_vars.level_yscroll_center_flag = 0; return; } int dl = 16; if (!g_vars.tilemap_adjust_player_pos_flag) { - const int dy = g_vars.objects_tbl[1].y_pos - g_vars.tilemap_scroll_dy; - const int index = dy - ((g_vars.tilemap_y + g_vars.tilemap_yscroll_diff) << 4); + const int dy = g_vars.objects_tbl[1].y_pos - g_vars.tilemap.scroll_dy; + const int index = dy - ((g_vars.tilemap.y + g_vars.tilemap_yscroll_diff) << 4); if (index >= 0 && index < 132) { dl = vscroll_offsets_data[index]; } else { @@ -508,8 +511,8 @@ static void level_adjust_y_scroll() { } int dl = 16; if (!g_vars.tilemap_adjust_player_pos_flag) { - const int dy = g_vars.objects_tbl[1].y_pos - g_vars.tilemap_scroll_dy; - const int index = ((g_vars.tilemap_y + g_vars.tilemap_yscroll_diff) << 4) - dy; + const int dy = g_vars.objects_tbl[1].y_pos - g_vars.tilemap.scroll_dy; + const int index = ((g_vars.tilemap.y + g_vars.tilemap_yscroll_diff) << 4) - dy; if (index >= 0 && index < 132) { dl = vscroll_offsets_data[index]; } else { @@ -534,28 +537,28 @@ static void level_update_scrolling() { static void level_init_tilemap() { video_transition_close(); - g_vars.tilemap_x = 0; - g_vars.tilemap_y = 0; - g_vars.tilemap_scroll_dx = 0; - g_vars.tilemap_scroll_dy = 0; + g_vars.tilemap.x = 0; + g_vars.tilemap.y = 0; + g_vars.tilemap.scroll_dx = 0; + g_vars.tilemap.scroll_dy = 0; g_vars.level_animated_tiles_current_tbl = g_vars.tile_tbl1; do { g_vars.tilemap_adjust_player_pos_flag = true; level_update_scrolling(); g_vars.tilemap_adjust_player_pos_flag = false; } while ((g_vars.level_yscroll_center_flag | g_vars.level_xscroll_center_flag) != 0); - print_debug(DBG_GAME, "init_tilemap x_pos %d y_pos %d scrolling 0x%x", g_vars.tilemap_x, g_vars.tilemap_y, g_res.level.scrolling_mask); + print_debug(DBG_GAME, "init_tilemap x_pos %d y_pos %d scrolling 0x%x", g_vars.tilemap.x, g_vars.tilemap.y, g_res.level.scrolling_mask); if ((g_res.level.scrolling_mask & 2) == 0) { - const int x = (g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap_x; + const int x = (g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap.x; if (x >= 12) { for (int i = 0; i < 10; ++i) { level_adjust_hscroll_right(); } } } - g_vars.tilemap_redraw_flag2 = 1; - g_vars.tilemap_prev_x = _undefined; - g_vars.tilemap_prev_y = _undefined; + g_vars.tilemap.redraw_flag2 = 1; + g_vars.tilemap.prev_x = _undefined; + g_vars.tilemap.prev_y = _undefined; level_draw_tilemap(); video_transition_open(); } @@ -563,11 +566,10 @@ static void level_init_tilemap() { static void level_player_die() { g_vars.restart_level_flag = 2; if (g_vars.player_lifes != 0) { - if (g_options.cheats & CHEATS_UNLIMITED_LIFES) { - return; + if ((g_options.cheats & CHEATS_UNLIMITED_LIFES) == 0) { + --g_vars.player_lifes; + g_vars.player_energy = 0; } - --g_vars.player_lifes; - g_vars.player_energy = 0; } else { g_vars.player_death_flag = 1; } @@ -607,6 +609,9 @@ static void level_init_object_hit_from_xy_pos(int16_t x_pos, int16_t y_pos) { } static void level_update_tile_type_2() { + if (g_options.cheats & CHEATS_NO_HIT) { + return; + } level_player_die(); g_vars.restart_level_flag = 2; } @@ -912,7 +917,7 @@ static void level_reset() { g_vars.level_completed_flag = 0; g_vars.objects_tbl[1].data.p.special_anim_num = 0; - g_vars.tilemap_prev_x = _undefined; + g_vars.tilemap.prev_x = _undefined; g_vars.current_hit_object = &g_vars.objects_tbl[6]; level_reset_objects(); set_level_palette(); @@ -928,6 +933,7 @@ static void level_reset() { for (int i = 0; i < 20; ++i) { g_vars.rotation_tbl[i].x_pos = 0xFFFF; } + memset(g_vars.boss_level5.proj_tbl, 0xFF, sizeof(g_vars.boss_level5.proj_tbl)); g_vars.player_energy = 3; g_vars.decor_tile0_offset = _undefined; @@ -1073,7 +1079,7 @@ static void level_monster_update_anim(struct object_t *obj) { obj->data.m.anim = p + 2; } -static void level_monster_die(struct object_t *obj, struct level_monster_t *m, struct object_t *obj_player) { /* di, bx, si */ +static void level_monster_die(struct object_t *obj, struct level_monster_t *m, struct object_t *obj_player) { const int num = m->score + 74; static const uint8_t data[] = { 1, 2, 3, 4, 6, 8 }; int count = data[(obj->data.m.hit_jump_counter >> 3) & 7]; @@ -1156,11 +1162,11 @@ static bool level_update_found_bonus_tile(struct level_bonus_t *bonus) { const uint16_t pos = bonus->pos; bonus->pos = 0xFFFF; level_set_tile(pos, bonus->tile_num1); - int8_t al = (pos & 0xFF) - g_vars.tilemap_x; + int8_t al = (pos & 0xFF) - g_vars.tilemap.x; if (al < 0 || al >= (TILEMAP_SCREEN_W / 16)) { return false; } - int8_t ah = (pos >> 8) - g_vars.tilemap_y; + int8_t ah = (pos >> 8) - g_vars.tilemap.y; if (ah < 0 || ah >= (TILEMAP_SCREEN_H / 16) + 1) { return false; } @@ -1198,7 +1204,7 @@ static bool level_handle_bonuses_found(struct object_t *obj, struct level_bonus_ } g_vars.current_bonus.x_pos = (pos & 0xFF) << 4; g_vars.current_bonus.y_pos = (pos >> 8) << 4; - int ax, count = 1; + int x_vel, count = 1; if (bonus->count & 0x40) { if (bonus->count == 64) { bonus->count = 0; @@ -1221,15 +1227,15 @@ static bool level_handle_bonuses_found(struct object_t *obj, struct level_bonus_ } else { g_vars.current_bonus.spr_num = level_get_random_bonus_spr_num(); } - ax = 48; + x_vel = 48; if (obj < &g_vars.objects_tbl[1]) { if (g_vars.objects_tbl[1].data.p.hdir >= 0) { - ax = -ax; + x_vel = -x_vel; } } else if (obj->x_velocity >= 0) { - ax = -ax; + x_vel = -x_vel; } - level_add_object23_bonus(ax, -112, count); + level_add_object23_bonus(x_vel, -112, count); decrement_bonus: --bonus->count; if ((bonus->count & 0x80) == 0) { @@ -1304,7 +1310,254 @@ static void level_update_objects_axe() { } } -static void level_update_monsters_state() { +static void level_update_objects_boss_level5_helper() { + --g_vars.bonus_energy_counter; + if (g_vars.bonus_energy_counter < 0) { + g_vars.bonus_energy_counter = 5; + if ((g_options.cheats & CHEATS_UNLIMITED_ENERGY) == 0) { + --g_vars.player_energy; + if (g_vars.player_energy < 0) { + level_player_die(); + } + } + } + g_vars.current_bonus.x_pos = g_vars.objects_tbl[1].x_pos; + g_vars.current_bonus.y_pos = g_vars.objects_tbl[1].y_pos - 48; + g_vars.current_bonus.spr_num = 0x2046; + const int x_vel = (g_vars.bonus_energy_counter & 1) != 0 ? -48 : 48; + const int y_vel = -128; + level_add_object23_bonus(x_vel, y_vel, 1); +} + +static void level_update_boss() { + const int x = (g_vars.boss.x_pos >> 4) + g_res.level.end_x_pos; + if (x >= 0) { + if (g_res.level.boss_xmin <= x && g_res.level.boss_xmax >= x) { + g_res.level.end_x_pos = x; + } + } + g_res.level.end_y_pos += (g_vars.boss.y_pos >> 4); + if (g_vars.boss.y_pos >= 0) { + const uint8_t bh = (g_res.level.end_y_pos >> 4); + const uint8_t bl = (g_res.level.end_x_pos >> 4); + const uint8_t tile_num = level_get_tile((bh << 8) | bl); + if (g_res.level.tile_attributes1[tile_num] != 0) { + g_res.level.end_y_pos &= ~15; + if (g_vars.boss.y_pos != 0) { + g_vars.shake_screen_counter = 7; + } + g_vars.boss.y_pos = 0; + g_vars.boss.x_pos = 0; + } else { + if (g_vars.boss.y_pos < 224) { + g_vars.boss.y_pos += 16; + } + } + } else { + if (g_vars.boss.y_pos < 224) { + g_vars.boss.y_pos += 16; + } + } + g_vars.boss.hdir = (g_vars.objects_tbl[1].x_pos < g_res.level.end_x_pos) ? 1 : 0; + g_vars.boss.x_dist = abs(g_vars.objects_tbl[1].x_pos - g_res.level.end_x_pos); + if (g_vars.boss.x_dist > 400) { + return; + } + if (abs(g_vars.objects_tbl[1].y_pos - g_res.level.end_y_pos) > 250) { + return; + } + print_warning("level_update_boss unimplemented end_pos %d,%d", g_res.level.end_x_pos, g_res.level.end_y_pos); +} + +static void level_update_objects_boss_level5() { + struct object_t *obj_player = &g_vars.objects_tbl[1]; + for (int i = 0; i < 5; ++i) { + struct boss_level5_proj_t *prj = &g_vars.boss_level5.proj_tbl[i]; + struct object_t *obj = &g_vars.objects_tbl[98 + i]; + if (prj->spr_num == 0xFFFF) { + continue; + } + if (g_vars.restart_level_flag == 0 && level_objects_collide(obj_player, obj)) { + obj_player->hit_counter = 44; + g_vars.player_anim_0x40_flag = 0; + obj_player->data.p.y_velocity = -128; + obj_player->x_friction = 3; + obj_player->x_velocity = -128; + level_update_objects_boss_level5_helper(); + prj->spr_num = 0xFFFF; + obj->spr_num = 0xFFFF; + } else { + prj->y_pos += prj->unk6 >> 4; + prj->unk8 += prj->dir; + int dx = prj->unk8; + if (dx >= 32 || dx < -32) { + prj->dir = -prj->dir; + } + uint16_t spr_num = prj->spr_num; + dx >>= 4; + if (dx != 0) { + spr_num += (dx > 0) ? 1 : 2; + } + prj->x_pos += dx; + obj->x_pos = prj->x_pos; + obj->y_pos = prj->y_pos; + if (obj->y_pos > 2008) { + prj->spr_num = 0xFFFF; + obj->spr_num = 0xFFFF; + } else { + obj->spr_num = spr_num; + } + } + } + g_vars.objects_tbl[105].spr_num = 0xFFFF; + g_vars.objects_tbl[104].spr_num = 0xFFFF; + if (g_vars.boss_level5.state < 2) { + static const uint16_t pos2_data[] = { + 0x3D5, 0x7C1, 0x1A3, 0x3FA, 0x7B6, 0x1A4, 0x3E8, 0x7A8, 0x1A5, + 0x3FF, 0x788, 0x1A6, 0x3D9, 0x79B, 0x1A7, 0x3FF, 0x7A8, 0x1A8, + 0x405, 0x7A9, 0x1B0, 0, 0, 0xFFFF + }; + const uint16_t *p = &pos2_data[g_vars.boss_level5.state * 6]; + g_vars.objects_tbl[105].x_pos = p[0]; + g_vars.objects_tbl[105].y_pos = p[1]; + g_vars.objects_tbl[105].spr_num = p[2]; + g_vars.objects_tbl[104].x_pos = p[3]; + g_vars.objects_tbl[104].y_pos = p[4]; + g_vars.objects_tbl[104].spr_num = p[5]; + } + static const uint16_t pos1_data[] = { + 0x3A9, 0x7D4, 0x19D, 0x3D1, 0x7B9, 0x19E, 0x3A2, 0x7A6, 0x19F, + 0x3B4, 0x79F, 0x1A0, 0x396, 0x78A, 0x1A1, 0x3B6, 0x79C, 0x1A2, + 0x3E0, 0x795, 0x1AF, 0, 0, 0xFFFF + }; + const uint16_t *p = &pos1_data[g_vars.boss_level5.unk5 * 6]; + g_vars.objects_tbl[107].x_pos = p[0]; + g_vars.objects_tbl[107].y_pos = p[1]; + g_vars.objects_tbl[107].spr_num = p[2]; + g_vars.objects_tbl[106].x_pos = p[3]; + g_vars.objects_tbl[106].y_pos = p[4]; + g_vars.objects_tbl[106].spr_num = p[5]; + static const uint16_t pos3_data[] = { + 0x3E3, 0x773, 0x1A9, 0x3E4, 0x771, 0x1AA, 0x3E4, 0x773, 0x1AB + }; + const uint16_t *q = &pos3_data[g_vars.boss_level5.unk4 * 3]; + g_vars.objects_tbl[103].x_pos = q[0]; + g_vars.objects_tbl[103].y_pos = q[1]; + g_vars.objects_tbl[103].spr_num = (g_vars.boss_level5.state != 0) ? 0xFFFF : q[2]; + if ((g_vars.level_draw_counter & 3) == 0) { + ++g_vars.boss_level5.unk4; + if (g_vars.boss_level5.unk4 > 2) { + g_vars.boss_level5.unk4 = 0; + } + } + if (g_vars.boss_level5.unk1 >= 1) { + if (g_vars.boss_level5.unk1 == 1) { + g_vars.boss_level5.unk6 = 2; + --g_vars.boss_level5.unk5; + g_vars.boss_level5.counter += 5; + } + --g_vars.boss_level5.unk1; + } else if (g_vars.boss_level5.counter == 0) { + ++g_vars.boss_level5.unk6; + if (g_vars.boss_level5.unk6 > 2) { + g_vars.boss_level5.unk6 = 0; + } + ++g_vars.boss_level5.unk5; + if (g_vars.boss_level5.unk5 > 2) { + g_vars.boss_level5.unk5 = 0; + } + uint8_t ah = 1; + if (g_vars.boss_level5.unk5 != 0) { + ah = 3; + g_vars.shake_screen_counter = 4; + obj_player->x_pos += 2; + for (int i = 0; i < 5; ++i) { + struct boss_level5_proj_t *prj = &g_vars.boss_level5.proj_tbl[i]; + if (prj->spr_num == 0xFFFF) { + prj->spr_num = 0x1AC; + prj->y_pos = obj_player->y_pos - 150; + const uint8_t r = random_get_number(); + const int dx = r & 0x7C; + prj->x_pos = obj_player->x_pos + (((r & 4) != 0) ? dx : -dx); + prj->unk6 = ((r & 3) + 1) << 4; + prj->unk8 = 0; + prj->dir = 4; + break; + } + } + } + g_vars.boss_level5.counter = ah; + --g_vars.boss_level5.unk8; + if (g_vars.boss_level5.unk8 == 0) { + g_vars.boss_level5.unk8 = (random_get_number() & 15) << 3; + g_vars.boss_level5.counter = 64 + ((random_get_number() & 15) << 3); + g_vars.boss_level5.unk6 = 0; + } + if (g_vars.restart_level_flag == 0) { + if (level_objects_collide(obj_player, &g_vars.objects_tbl[107]) || level_objects_collide(obj_player, &g_vars.objects_tbl[106])) { + if (obj_player->y_pos <= 1979) { + obj_player->data.p.y_velocity = -160; + } else { + obj_player->data.p.y_velocity = -160; + obj_player->hit_counter = 44; + g_vars.player_anim_0x40_flag = 0; + obj_player->x_friction = 3; + obj_player->x_velocity = -128; + level_update_objects_boss_level5_helper(); + level_update_objects_boss_level5_helper(); + level_update_objects_boss_level5_helper(); + } + } + } + } else if (g_vars.restart_level_flag == 0) { + if (level_objects_collide(obj_player, &g_vars.objects_tbl[107]) && g_vars.player_jump_monster_flag) { + obj_player->data.p.y_velocity = g_vars.input.key_up ? -128 : -64; + } + } + if (g_vars.restart_level_flag == 0) { + struct object_t *_si = &g_vars.objects_tbl[103 + g_vars.boss_level5.state * 2]; + for (int i = 0; i < 6; ++i) { + struct object_t *_di = &g_vars.objects_tbl[i]; + if (_di->spr_num == 0xFFFF || _di == obj_player) { + continue; + } + g_vars.player_using_club_flag = 1; + const bool ret = level_objects_collide(_si, _di); + g_vars.player_using_club_flag = 0; + if (ret) { + _si->spr_num ^= 0x4000; + if (g_vars.boss_level5.state != 0) { + _si[-1].spr_num ^= 0x4000; + } + _di->spr_num = 0xFFFF; + g_vars.boss_level5.unk1 = 6; + if (g_vars.boss_level5.state < 2) { + g_vars.boss_level5.unk6 = 3; + g_vars.boss_level5.unk5 = 3; + } + --g_vars.boss_level5.energy; + if (g_vars.boss_level5.energy == 0) { + g_vars.boss_level5.energy = 10; + ++g_vars.boss_level5.state; + if (g_vars.boss_level5.state == 3) { + g_vars.level_completed_flag = 1; + } + } + break; + } + } + if (obj_player->x_pos > 984) { + obj_player->hit_counter = 44; + g_vars.player_anim_0x40_flag = 0; + obj_player->data.p.y_velocity = -144; + obj_player->x_friction = 3; + obj_player->x_velocity = -160; + level_update_objects_boss_level5_helper(); + } + } + if (g_vars.boss_level5.counter > 0) { + --g_vars.boss_level5.counter; + } } static int level_get_tile_monster_offset(uint8_t tile_num, struct object_t *obj) { @@ -1382,10 +1635,11 @@ 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.level.monsters_state != 0xFF) { - level_update_monsters_state(); + if (g_res.level.boss_flag != 0xFF) { + level_update_boss(); } if (g_vars.level_num == 5 && (g_res.level.scrolling_mask & ~1) == 0) { + level_update_objects_boss_level5(); } for (int i = 0; i < MONSTERS_COUNT; ++i) { struct object_t *obj = &g_vars.objects_tbl[11 + i]; @@ -1646,46 +1900,44 @@ static void level_update_objects_decors() { int a = trigger->type8.y_delta - 8; if (a < 0) { a = 0; - trigger->type8.unk7 = 0; + trigger->type8.y_velocity = 0; } trigger->type8.y_delta = a; - } - if (trigger->flags & 0x40) { - if (trigger->type8.unk7 != 0 && --trigger->type8.counter == 0) { - trigger->type8.state = 1; - trigger->type8.unk7 = 0; - } - } else { - if (trigger->type8.state == 1) { - int y = trigger->type8.unk7; - if (y < 192) { - trigger->type8.unk7 += 8; + if (trigger->flags & 0x40) { + if (trigger->type8.y_velocity != 0 && --trigger->type8.counter == 0) { + trigger->type8.state = 1; + trigger->type8.y_velocity = 0; } - y >>= 4; - g_vars.level_current_object_decor_y_pos = y; - trigger->type8.y_delta += y; - const int tile_x = trigger->x_pos >> 4; - const int tile_y = (trigger->y_pos + trigger->type8.y_delta) >> 4; - const int y2 = g_vars.tilemap_h - 1 - tile_y; - if (y2 < 0) { - if ((-y2) >= 3) { - trigger->type8.state = 2; - trigger->type8.counter = 22; - } - } else { - const uint8_t tile_num = level_get_tile((tile_y << 8) | tile_x); - const uint8_t tile_attr1 = g_res.level.tile_attributes1[tile_num]; - if (tile_attr1 != 0 && tile_attr1 != 6) { - trigger->type8.state = 2; - trigger->type8.counter = 22; - } + } + } else if (trigger->type8.state == 1) { + int y = trigger->type8.y_velocity; + if (y < 192) { + trigger->type8.y_velocity += 8; + } + y >>= 4; + g_vars.level_current_object_decor_y_pos = y; + trigger->type8.y_delta += y; + const int tile_x = trigger->x_pos >> 4; + const int tile_y = (trigger->y_pos + trigger->type8.y_delta) >> 4; + const int y2 = g_vars.tilemap.h - 1 - tile_y; + if (y2 < 0) { + if ((-y2) >= 3) { + trigger->type8.state = 2; + trigger->type8.counter = 22; } } else { - if (trigger->type8.state == 2 && (trigger->flags & 0x40) == 0 && --trigger->type8.counter == 0) { - trigger->type8.state = 0; - trigger->type8.counter = trigger->type8.unk9; + const uint8_t tile_num = level_get_tile((tile_y << 8) | tile_x); + const uint8_t tile_attr1 = g_res.level.tile_attributes1[tile_num]; + if (tile_attr1 != 0 && tile_attr1 != 6) { + trigger->type8.state = 2; + trigger->type8.counter = 22; } } + } else if (trigger->type8.state == 2) { + if ((trigger->flags & 0x40) == 0 && --trigger->type8.counter == 0) { + trigger->type8.state = 0; + trigger->type8.counter = trigger->type8.unk9; + } } trigger->y_pos += trigger->type8.y_delta; } else { @@ -1736,11 +1988,11 @@ static void level_update_objects_decors() { } } } - const int x_pos = trigger->x_pos - (g_vars.tilemap_x << 4); + const int x_pos = trigger->x_pos - (g_vars.tilemap.x << 4); if (x_pos >= TILEMAP_SCREEN_W + 32 || x_pos <= -32) { continue; } - const int y_pos = trigger->y_pos - (g_vars.tilemap_y << 4); + const int y_pos = trigger->y_pos - (g_vars.tilemap.y << 4); if (y_pos >= TILEMAP_SCREEN_H + 32 || y_pos <= -32) { continue; } @@ -2006,7 +2258,7 @@ static void level_update_player_anim_0(uint8_t al) { 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.tilemap_noscroll_flag == 0) { - const int dx = (g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap_x; + 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) { level_adjust_hscroll_right(); @@ -2158,22 +2410,21 @@ static void level_update_player_decor() { dx = 0; } const int x_pos = g_vars.objects_tbl[1].x_pos >> 4; - const int player_ypos_diff = abs((g_vars.objects_tbl[1].y_pos >> 4) - g_vars.tilemap_y); + const int player_ypos_diff = abs((g_vars.objects_tbl[1].y_pos >> 4) - g_vars.tilemap.y); if (player_ypos_diff > (TILEMAP_SCREEN_H / 16)) { level_update_tile_type_2(); } else { - const int player_xpos_diff = abs((g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap_x); + const int player_xpos_diff = abs((g_vars.objects_tbl[1].x_pos >> 4) - g_vars.tilemap.x); if (player_xpos_diff > (TILEMAP_SCREEN_W / 16)) { level_update_tile_type_2(); - } else if ((g_res.level.scrolling_mask & 4) != 0 && g_vars.objects_tbl[1].y_pos < (g_vars.tilemap_y << 4)) { + } else if ((g_res.level.scrolling_mask & 4) != 0 && g_vars.objects_tbl[1].y_pos < (g_vars.tilemap.y << 4)) { level_update_tile_type_2(); - } else if (g_vars.objects_tbl[1].y_pos >= 0 && g_vars.objects_tbl[1].y_pos > ((g_vars.tilemap_h + 1) << 4)) { + } else if (g_vars.objects_tbl[1].y_pos >= 0 && g_vars.objects_tbl[1].y_pos > ((g_vars.tilemap.h + 1) << 4)) { level_update_tile_type_2(); } } - int bx = (y_pos << 8) | x_pos; g_vars.player_tile_flags = 0; - level_update_tile0(bx); + level_update_tile0((y_pos << 8) | x_pos); if (g_vars.player_tile_flags == 1) { if (g_vars.level_force_x_scroll_flag != 0) { level_player_reset(); @@ -2190,18 +2441,18 @@ static void level_update_player_decor() { if (g_vars.objects_tbl[1].y_pos <= 0) { return; } - bx = ((dx + g_vars.objects_tbl[1].x_pos) >> 4) + (y_pos << 8); - level_update_tile1(bx); + int pos = (y_pos << 8) | ((dx + g_vars.objects_tbl[1].x_pos) >> 4); + level_update_tile1(pos); while (1) { - bx -= 0x100; - if (bx < 0) { + pos -= 0x100; + if (pos < 0) { break; } spr_h -= 16; if (spr_h <= 0) { break; } - level_update_tile2(bx); + level_update_tile2(pos); } } @@ -2391,9 +2642,6 @@ static void level_update_player_collision() { if (obj->spr_num == 0xFFFF || (obj->spr_num & 0x2000) == 0) { continue; } - if (g_options.cheats & CHEATS_NO_HIT) { - continue; - } struct level_monster_t *m = obj->data.m.ref; if (m->flags & 0x10) { continue; @@ -2401,6 +2649,9 @@ static void level_update_player_collision() { if (obj->data.m.state == 0xFF) { continue; } + if (g_options.cheats & CHEATS_NO_HIT) { + continue; + } if (!level_objects_collide(obj_player, obj)) { continue; } @@ -2408,7 +2659,7 @@ static void level_update_player_collision() { level_monster_die(obj, m, &g_vars.objects_tbl[1]); continue; } - if (!g_vars.player_jump_monster_flag && g_vars.objects_tbl[1].data.p.y_velocity < 0) { + if (!g_vars.player_jump_monster_flag || g_vars.objects_tbl[1].data.p.y_velocity < 0) { m->flags &= ~1; g_vars.objects_tbl[1].hit_counter = 44; g_vars.player_anim_0x40_flag = 0; @@ -2418,9 +2669,11 @@ static void level_update_player_collision() { if (g_vars.player_flying_flag != 0) { g_vars.player_flying_flag = 0; } else { - --g_vars.player_energy; - if (g_vars.player_energy < 0) { - level_player_die(); + if ((g_options.cheats & CHEATS_UNLIMITED_ENERGY) == 0) { + --g_vars.player_energy; + if (g_vars.player_energy < 0) { + level_player_die(); + } } } return; @@ -2685,11 +2938,11 @@ static void level_update_objects_items() { if (level_item->spr_num == 0xFFFF) { continue; } - const int16_t x = (level_item->x_pos >> 4) - g_vars.tilemap_x; + const int16_t x = (level_item->x_pos >> 4) - g_vars.tilemap.x; if (x < 0 || x > 22) { continue; } - const int16_t y = (level_item->y_pos >> 4) - g_vars.tilemap_y; + const int16_t y = (level_item->y_pos >> 4) - g_vars.tilemap.y; if (y < 0 || y > 43) { continue; } @@ -2732,23 +2985,23 @@ static void level_update_gates() { g_vars.objects_tbl[1].x_velocity = 0; g_vars.objects_tbl[1].data.p.y_velocity = 0; video_transition_close(); - g_vars.tilemap_scroll_dy = 0; + g_vars.tilemap.scroll_dy = 0; const uint8_t tmp = g_res.level.tilemap_w; g_res.level.tilemap_w = 256 - 20; const uint16_t dst_pos = gate->dst_pos; g_vars.objects_tbl[1].x_pos = (dst_pos & 255) << 4; g_vars.objects_tbl[1].y_pos = (dst_pos >> 8) << 4; const uint8_t tilemap_y = gate->tilemap_pos >> 8; - while (g_vars.tilemap_y != tilemap_y) { - if (g_vars.tilemap_y > tilemap_y) { + while (g_vars.tilemap.y != tilemap_y) { + if (g_vars.tilemap.y > tilemap_y) { level_adjust_vscroll_up(16); } else { level_adjust_vscroll_down(16); } } const uint8_t tilemap_x = gate->tilemap_pos & 255; - while (g_vars.tilemap_x != tilemap_x) { - if (g_vars.tilemap_x > tilemap_x) { + while (g_vars.tilemap.x != tilemap_x) { + if (g_vars.tilemap.x > tilemap_x) { level_adjust_hscroll_left(); } else { level_adjust_hscroll_right(); @@ -2758,6 +3011,17 @@ static void level_update_gates() { g_vars.tilemap_noscroll_flag = gate->scroll_flag; g_vars.player_action_counter = 0; if (g_vars.level_num == 5) { + /* exit to boss (tree) */ + g_res.level.scrolling_mask &= 1; + g_vars.boss_level5.unk1 = 0; + g_vars.boss_level5.energy = 10; + g_vars.boss_level5.state = 0; + g_vars.boss_level5.unk4 = 0; + g_vars.boss_level5.unk5 = 1; + g_vars.boss_level5.unk6 = 0; + g_vars.boss_level5.counter = 110; + g_vars.boss_level5.unk8 = 8; + memset(&g_vars.objects_tbl[91], 0xFF, sizeof(struct object_t) * 6); } level_draw_tilemap(); level_update_objects_decors(); @@ -2773,14 +3037,14 @@ static void level_update_gates() { static void level_draw_front_tile(uint8_t tile_num, int x, int y) { const int num = g_res.level.front_tiles_lut[tile_num]; assert(num < (g_res.frontlen / 128)); - g_sys.render_add_sprite(RENDER_SPR_FG, num, x * 16 - g_vars.tilemap_scroll_dx, y * 16 - g_vars.tilemap_scroll_dy, 0); + g_sys.render_add_sprite(RENDER_SPR_FG, num, x * 16 - g_vars.tilemap.scroll_dx, y * 16 - g_vars.tilemap.scroll_dy, 0); } static void level_draw_front_tiles() { if ((g_vars.tile_attr2_flags & 0x40) == 0) { /* no front tiles */ return; } - uint16_t offset = (g_vars.tilemap_y << 8) | g_vars.tilemap_x; + uint16_t offset = (g_vars.tilemap.y << 8) | g_vars.tilemap.x; for (int y = 0; y < (TILEMAP_SCREEN_H / 16) + 1; ++y) { for (int x = 0; x < (TILEMAP_SCREEN_W / 16) + 1; ++x) { const uint8_t tile_num = level_get_tile(offset + x); @@ -2864,11 +3128,13 @@ static void level_draw_panel() { } if (g_vars.score != g_vars.panel.score || _redraw_panel) { g_vars.panel.score = g_vars.score; + const int score_digits = _score_8_digits ? 8 : 7; + const int offset = _score_8_digits ? 0x1CF0 : 0x1CF1; int score = g_vars.score * 10; - for (int i = 0; i < 7; ++i) { + for (int i = 0; i < score_digits; ++i) { const int digit = score % 10; score /= 10; - video_draw_panel_number(0x1CF1 + (6 - i) * 16 / 8, digit); + video_draw_panel_number(offset + (score_digits - 1 - i) * 16 / 8, digit); } } if (g_vars.player_energy != g_vars.panel.energy || _redraw_panel) { @@ -2971,10 +3237,10 @@ static void level_draw_objects() { } const int spr_num = obj->spr_num & 0x1FFF; const int spr_hflip = ((obj->spr_num & 0x8000) != 0) ? 1 : 0; - int spr_y_pos = obj->y_pos - ((g_vars.tilemap_y << 4) + g_vars.tilemap_scroll_dy); + int spr_y_pos = obj->y_pos - ((g_vars.tilemap.y << 4) + g_vars.tilemap.scroll_dy); int spr_h = spr_size_tbl[2 * spr_num + 1]; spr_y_pos -= spr_h; - int spr_x_pos = obj->x_pos - ((g_vars.tilemap_x << 4) + g_vars.tilemap_scroll_dx); + int spr_x_pos = obj->x_pos - ((g_vars.tilemap.x << 4) + g_vars.tilemap.scroll_dx); int spr_w = spr_offs_tbl[2 * spr_num]; if (spr_hflip) { spr_w = spr_size_tbl[2 * spr_num] - spr_w; @@ -2999,9 +3265,9 @@ static void level_draw_rotated_tiles() { const int ry = ((int8_t)sin_tbl[p->index_tbl]) >> 2; p->y_pos += (ry * p->radius) >> 4; - const int dy = p->y_pos - g_vars.tilemap_scroll_dy - (g_vars.tilemap_y << 4); + const int dy = p->y_pos - g_vars.tilemap.scroll_dy - (g_vars.tilemap.y << 4); if (dy < TILEMAP_SCREEN_H) { - const int dx = p->x_pos - g_vars.tilemap_scroll_dx - (g_vars.tilemap_x << 4); + const int dx = p->x_pos - g_vars.tilemap.scroll_dx - (g_vars.tilemap.x << 4); if (dx < TILEMAP_SCREEN_W) { } } @@ -3057,7 +3323,7 @@ static void level_player_death_animation() { g_vars.objects_tbl[1].hit_counter = 0; g_vars.objects_tbl[1].spr_num = 33; g_vars.objects_tbl[1].data.p.y_velocity = 15; - g_vars.objects_tbl[1].x_velocity = (g_vars.objects_tbl[1].x_pos < ((g_vars.tilemap_x + 10) << 4)) ? 5 : -5; + g_vars.objects_tbl[1].x_velocity = (g_vars.objects_tbl[1].x_pos < ((g_vars.tilemap.x + 10) << 4)) ? 5 : -5; for (int i = 0; i < 60; ++i) { g_vars.objects_tbl[0].spr_num = 0xFFFF; level_update_objects_hit_animation(); @@ -3082,11 +3348,13 @@ static void level_player_death_animation() { } static void level_completed_bonuses_animation_draw_score() { + const int score_digits = _score_8_digits ? 8 : 7; + const int offset = _score_8_digits ? 0x246 : 0x247; int score = g_vars.score * 10; - for (int i = 0; i < 7; ++i) { + for (int i = 0; i < score_digits; ++i) { const int digit = score % 10; score /= 10; - video_draw_number(0x247 + (7 - i) * 16 / 8, digit); + video_draw_number(offset + (score_digits - 1 - i) * 16 / 8, digit); } } @@ -3139,10 +3407,10 @@ static void level_completed_bonuses_animation() { g_vars.light.palette_flag2 = 1; g_vars.light.palette_counter = 0; } - g_vars.objects_tbl[1].y_pos -= g_vars.tilemap_y << 4; - g_vars.objects_tbl[1].x_pos -= g_vars.tilemap_x << 4; - g_vars.tilemap_y = 0; - g_vars.tilemap_x = 0; + g_vars.objects_tbl[1].y_pos -= g_vars.tilemap.y << 4; + g_vars.objects_tbl[1].x_pos -= g_vars.tilemap.x << 4; + g_vars.tilemap.y = 0; + g_vars.tilemap.x = 0; g_vars.objects_tbl[1].data.p.hdir = 0; g_vars.objects_tbl[1].x_velocity = 0; level_completed_bonuses_animation_draw_score(); diff --git a/p2/monsters.c b/p2/monsters.c index 82f3c55..48def2d 100644 --- a/p2/monsters.c +++ b/p2/monsters.c @@ -221,11 +221,11 @@ static void monster_func1_type4(struct object_t *obj) { } else if (state == 2) { monster_rotate_pos(obj, m); if (m->type4.angle & 0x80) { - ++m->type4.unk10; + ++m->type4.angle_step; } else { - --m->type4.unk10; + --m->type4.angle_step; } - m->type4.angle = m->type4.unk10; + m->type4.angle += m->type4.angle_step; } else if (state == 0xFF) { monster_update_y_velocity(obj, m); } @@ -297,10 +297,8 @@ static void monster_func1_type6(struct object_t *obj) { if (g_vars.player_anim_0x40_flag != 0) { y += 5; } - y -= g_vars.objects_tbl[1].y_pos; - y = -y; + y = g_vars.objects_tbl[1].y_pos - y - obj->y_pos; d = 3; - y -= obj->y_pos; if (y <= 0) { y = -y; d = -d; @@ -622,11 +620,11 @@ static bool monster_init_object(struct level_monster_t *m) { } static bool monster_is_visible(int x_pos, int y_pos) { - const int dx = (x_pos >> 4) - g_vars.tilemap_x; + const int dx = (x_pos >> 4) - g_vars.tilemap.x; if (dx < -2 || dx > (TILEMAP_SCREEN_W + 2)) { return false; } - const int dy = (y_pos >> 4) - g_vars.tilemap_y; + const int dy = (y_pos >> 4) - g_vars.tilemap.y; if (dy < -2 || dy > (TILEMAP_SCREEN_H + 2)) { return false; } @@ -712,7 +710,7 @@ static bool monster_func2_type4(struct level_monster_t *m) { } m->flags = 5; m->type4.angle = 0; - m->type4.unk10 = 0; + m->type4.angle_step = 0; return true; } @@ -777,7 +775,7 @@ static bool monster_func2_type10(struct level_monster_t *m) { uint8_t bl = (obj->x_pos >> 4); uint16_t pos = (bh << 8) | bl; for (int i = 0; i < 10 && pos >= 0x300; ++i, pos -= 0x100) { - if (pos < (g_vars.tilemap_h << 8)) { + 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[pos - j * 0x100]; diff --git a/p2/resource.c b/p2/resource.c index 549818c..8ea4eea 100644 --- a/p2/resource.c +++ b/p2/resource.c @@ -153,7 +153,7 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { m->type4.radius = p[0xD]; m->type4.unkE = p[0xE]; m->type4.angle = p[0xF]; - m->type4.unk10 = p[0x10]; + m->type4.angle_step = p[0x10]; break; case 5: assert(len == 16); @@ -232,7 +232,7 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { trigger->flags = *p++; const int type = trigger->flags & 15; if (type == 8) { - trigger->type8.unk7 = *p++; + trigger->type8.y_velocity = *p++; trigger->type8.unk8 = *p++; trigger->type8.unk9 = *p++; trigger->type8.state = *p++; @@ -246,11 +246,11 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { } trigger->unkE = *p++; } - g_res.level.monsters_xmin = READ_LE_UINT16(p); p += 2; - g_res.level.monsters_xmax = READ_LE_UINT16(p); p += 2; - g_res.level.monsters_unk0 = *p++; - g_res.level.monsters_unk1 = READ_LE_UINT16(p); p += 2; - g_res.level.monsters_state = *p++; + g_res.level.boss_xmin = READ_LE_UINT16(p); p += 2; + g_res.level.boss_xmax = READ_LE_UINT16(p); p += 2; + g_res.level.boss_counter = *p++; + g_res.level.boss_energy = READ_LE_UINT16(p); p += 2; + g_res.level.boss_flag = *p++; g_res.level.end_x_pos = READ_LE_UINT16(p); p += 2; g_res.level.end_y_pos = READ_LE_UINT16(p); p += 2; const int total = p - g_res.leveldat; diff --git a/p2/resource.h b/p2/resource.h index 7ca0468..24aa5b8 100644 --- a/p2/resource.h +++ b/p2/resource.h @@ -41,7 +41,7 @@ struct level_trigger_t { uint8_t flags; union { struct { - int8_t unk7; + uint8_t y_velocity; uint8_t unk8; uint8_t unk9; uint8_t state; @@ -81,7 +81,7 @@ struct level_monster_t { uint8_t radius; uint8_t unkE; uint8_t angle; - uint8_t unk10; + uint8_t angle_step; } type4; struct { uint8_t x_range; @@ -149,11 +149,11 @@ struct level_t { uint8_t tile_attributes3[256]; struct level_item_t items_tbl[MAX_LEVEL_ITEMS]; struct level_trigger_t triggers_tbl[MAX_LEVEL_TRIGGERS]; - uint16_t monsters_xmin; - uint16_t monsters_xmax; - uint8_t monsters_unk0; - uint16_t monsters_unk1; - uint8_t monsters_state; + uint16_t boss_xmin; + uint16_t boss_xmax; + uint8_t boss_counter; + uint16_t boss_energy; + uint8_t boss_flag; /* !=255: has boss */ uint16_t end_x_pos; uint16_t end_y_pos; }; diff --git a/p2/screen.c b/p2/screen.c index 8da74f2..893fdaa 100644 --- a/p2/screen.c +++ b/p2/screen.c @@ -179,9 +179,6 @@ void video_load_front_tiles() { } } -void video_set_palette() { -} - void fade_in_palette() { if (!g_sys.input.quit) { g_sys.fade_in_palette();