diff --git a/bb/decode.c b/bb/decode.c index 03d9b05..336f753 100644 --- a/bb/decode.c +++ b/bb/decode.c @@ -64,6 +64,9 @@ void decode_amiga_gfx(uint8_t *dst, int dst_pitch, int w, int h, int depth, cons color |= 1 << bit; } } + if (palette_mask == 0 && color == 0) { + continue; + } dst[x * 16 + i] = palette_mask | color; } } diff --git a/bb/game.c b/bb/game.c index 4e832c2..8ff329c 100644 --- a/bb/game.c +++ b/bb/game.c @@ -75,7 +75,9 @@ static void do_select_player() { const int color_rgb = 2; const int colors_count = 25; load_img(g_res.amiga_data ? "choix.lbm" : "choix.sqz", GAME_SCREEN_W, g_options.cga_colors ? 1 : -1); - screen_load_graphics(g_options.cga_colors ? g_res.cga_lut_sqv : 0, 0); + if (g_res.spr_count <= SPRITES_COUNT) { + screen_load_graphics(g_options.cga_colors ? g_res.cga_lut_sqv : 0, 0); + } screen_clear_sprites(); do { update_input(); diff --git a/bb/screen.c b/bb/screen.c index afdbc4c..5644ca6 100644 --- a/bb/screen.c +++ b/bb/screen.c @@ -42,6 +42,24 @@ static void add_game_sprite(int x, int y, int frame, int xflip) { } void screen_add_sprite(int x, int y, int frame) { + if (g_res.amiga_data) { + switch (frame) { + case 125: { + extern const uint8_t spr71a6_amiga[]; + static const int w = 16; + static const int h = 6; + decode_amiga_gfx(g_res.vga + (y - h) * GAME_SCREEN_W + (x - w / 2), GAME_SCREEN_W, w, h, 4, spr71a6_amiga, w, 0x0, 0xFFFF); + } + return; + case 126: { + extern const uint8_t spr71da_amiga[]; + static const int w = 48; + static const int h = 34; + decode_amiga_gfx(g_res.vga + (y - h) * GAME_SCREEN_W + (x - w / 2), GAME_SCREEN_W, w, h, 4, spr71da_amiga, w, 0x0, 0xFFFF); + } + return; + } + } add_game_sprite(x, y, frame, 0); } diff --git a/bb/sound.c b/bb/sound.c index 572252f..9e0b9bc 100644 --- a/bb/sound.c +++ b/bb/sound.c @@ -3,6 +3,7 @@ #include "game.h" #include "resource.h" #include "sys.h" +#include "util.h" #include @@ -34,10 +35,10 @@ static const struct { // Amiga, ExoticA static const char *_modules[] = { - "ALMOST", "mod.almost", - "GUNN", "mod.bluesgunnbest", - "EVERY", "mod.every", - "SHOT", "mod.shot" + "almost", "mod.almost", + "gunn", "mod.bluesgunnbest", + "every", "mod.every", + "shot", "mod.shot" }; struct mixerchannel_t { @@ -119,29 +120,35 @@ void play_music(int num) { // append samples to the end of the buffer static const int SONG_INFO_LEN = 20; static const int NUM_SAMPLES = 8; + struct { + char *name; + int size; + } samples[8]; int samples_size = 0; int offset = SONG_INFO_LEN; for (int i = 0; i < NUM_SAMPLES; ++i, offset += 30) { - const char *sample_name = (const char *)&buf[offset]; - if (sample_name[0]) { - samples_size += READ_BE_UINT16(&buf[offset + 22]) * 2; - } + samples[i].name = (char *)&buf[offset]; + samples[i].size = READ_BE_UINT16(&buf[offset + 22]) * 2; + string_lower(samples[i].name); + samples_size += samples[i].size; } buf = (uint8_t *)realloc(buf, size + samples_size); if (buf) { - offset = SONG_INFO_LEN; - for (int i = 0; i < NUM_SAMPLES; ++i, offset += 30) { - const char *sample_name = (const char *)&buf[offset]; - const int sample_size = READ_BE_UINT16(&buf[offset + 22]) * 2; - if (sample_name[0]) { - int sample_slot = fio_open(sample_name, 0); - if (!(sample_slot < 0)) { - fio_read(sample_slot, buf + size, sample_size); - size += sample_size; + memset(buf + size, 0, samples_size); + for (int i = 0; i < NUM_SAMPLES; ++i) { + if (samples[i].size != 0) { + if (samples[i].name[0]) { + const int sample_slot = fio_open(samples[i].name, 0); + if (sample_slot < 0) { + print_warning("Unable to open instrument '%s'", samples[i].name); + } else { + fio_read(sample_slot, buf + size, samples[i].size); + fio_close(sample_slot); + } } - fio_close(sample_slot); + size += samples[i].size; } } _mpf = ModPlug_Load(buf, size); diff --git a/bb/staticres.c b/bb/staticres.c index 4459ded..1568bae 100644 --- a/bb/staticres.c +++ b/bb/staticres.c @@ -1807,3 +1807,63 @@ const uint8_t dither_cga_table[] = { 0x00,0x00,0x00,0x00,0xAA,0xAA,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x55,0x55, 0x55,0x55,0x00,0x00,0xAA,0xAA,0x00,0x00,0xFF,0xFF,0xAA,0xAA,0x55,0x55,0xFF,0xFF }; +const uint8_t spr71a6_amiga[] = { + 0x03,0x80,0x07,0xc0,0x07,0xe0,0x07,0xe0,0x03,0xe0,0x01,0xc0,0x00,0x00,0x00,0x00, + 0x00,0x20,0x00,0x20,0x00,0x60,0x01,0xc0,0x03,0x80,0x07,0xc0,0x07,0xc0,0x07,0xc0, + 0x03,0x80,0x00,0x00,0x03,0x80,0x07,0xc0,0x07,0xe0,0x07,0xe0,0x03,0xe0,0x01,0xc0, + 0x00,0x22,0x00,0x30 +}; +const uint8_t spr71da_amiga[] = { + 0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x07, + 0x80,0x00,0x00,0x00,0x00,0x78,0x07,0x00,0x00,0x00,0x07,0x80,0x7f,0x00,0x00,0x00, + 0x78,0x07,0xf8,0x00,0x00,0x03,0x80,0x7f,0x87,0x00,0x00,0x00,0x07,0xf8,0x7b,0x00, + 0x00,0x00,0x7f,0x87,0x8b,0x00,0x00,0x03,0xf8,0x78,0x0b,0x00,0x00,0x03,0x87,0x80, + 0x0b,0x00,0x00,0x00,0x78,0x00,0x0b,0x00,0x00,0x03,0xc0,0x00,0x0b,0x00,0x00,0x02, + 0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00,0x0b,0x00, + 0x00,0x02,0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00, + 0x0b,0x00,0x00,0x02,0xc0,0x00,0xfb,0x00,0x00,0x02,0xc0,0x01,0x0f,0x00,0x00,0x02, + 0xc0,0x02,0x07,0x00,0x00,0x02,0xc0,0x04,0x7b,0x00,0x00,0x3e,0xc0,0x04,0xff,0x00, + 0x00,0x43,0xc0,0x05,0xff,0x00,0x00,0x81,0xc0,0x05,0xfd,0x00,0x01,0x1e,0xc0,0x07, + 0xf9,0x00,0x01,0x3f,0xc0,0x03,0x62,0x00,0x01,0x7f,0xc0,0x01,0x84,0x00,0x01,0x7f, + 0x40,0x00,0xf8,0x00,0x01,0xfe,0x40,0x00,0x00,0x00,0x00,0xdc,0x80,0x00,0x00,0x00, + 0x00,0x61,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x07,0x00,0x00,0x00,0x00,0x00,0x79,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0x00,0x00, + 0x00,0x78,0x07,0x00,0x00,0x00,0x07,0x80,0x7f,0x00,0x00,0x00,0x78,0x07,0xf8,0x00, + 0x00,0x03,0x80,0x7f,0x87,0x00,0x00,0x02,0x07,0xf8,0x7b,0x00,0x00,0x00,0x7f,0x87, + 0x8f,0x00,0x00,0x03,0xf8,0x78,0x0b,0x00,0x00,0x03,0x87,0x80,0x0b,0x00,0x00,0x00, + 0x78,0x00,0x0b,0x00,0x00,0x03,0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00,0x0b,0x00, + 0x00,0x03,0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00, + 0x0b,0x00,0x00,0x02,0xc0,0x00,0x0b,0x00,0x00,0x02,0xc0,0x00,0x0f,0x00,0x00,0x02, + 0xc0,0x00,0xfb,0x00,0x00,0x02,0xc0,0x01,0xbf,0x00,0x00,0x02,0xc0,0x02,0x0f,0x00, + 0x00,0x03,0xc0,0x06,0x7b,0x00,0x00,0x3e,0xc0,0x04,0xff,0x00,0x00,0x6f,0xc0,0x07, + 0xff,0x00,0x00,0x83,0xc0,0x05,0xfd,0x00,0x01,0x9e,0xc0,0x07,0xf9,0x00,0x01,0x3f, + 0xc0,0x03,0x62,0x00,0x01,0xff,0xc0,0x01,0x84,0x00,0x01,0x7f,0x40,0x00,0xf8,0x00, + 0x01,0xfe,0x40,0x00,0x00,0x00,0x00,0xdc,0x80,0x00,0x00,0x00,0x00,0x61,0x00,0x00, + 0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,0x00,0x00,0x07,0xf8,0x00, + 0x00,0x00,0x00,0x7f,0x80,0x00,0x00,0x00,0x07,0xf8,0x07,0x00,0x00,0x00,0x7f,0x80, + 0x78,0x00,0x00,0x01,0xf8,0x07,0x84,0x00,0x00,0x03,0x80,0x78,0x00,0x00,0x00,0x00, + 0x07,0x80,0x04,0x00,0x00,0x00,0x78,0x00,0x04,0x00,0x00,0x03,0x80,0x00,0x04,0x00, + 0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x04,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0x01, + 0x00,0x00,0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x04,0x00, + 0x00,0x01,0x00,0x00,0x40,0x00,0x00,0x01,0x00,0x01,0x70,0x00,0x00,0x00,0x00,0x00, + 0x84,0x00,0x00,0x01,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x5c, + 0x00,0x02,0x02,0x00,0x00,0x21,0x00,0x00,0x06,0x00,0x00,0xc0,0x00,0x00,0x9c,0x00, + 0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x01,0x80,0x00, + 0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x7e,0x00, + 0x00,0x00,0x00,0x07,0xf8,0x00,0x00,0x00,0x00,0x7f,0x87,0x00,0x00,0x00,0x07,0xf8, + 0x7f,0x00,0x00,0x00,0x7f,0x87,0xf8,0x00,0x00,0x03,0xf8,0x7f,0x87,0x00,0x00,0x01, + 0x87,0xf8,0x7b,0x00,0x00,0x00,0x7f,0x87,0x8b,0x00,0x00,0x03,0xf8,0x78,0x0f,0x00, + 0x00,0x03,0x87,0x80,0x0f,0x00,0x00,0x00,0x78,0x00,0x0f,0x00,0x00,0x03,0xc0,0x00, + 0x0f,0x00,0x00,0x02,0xc0,0x00,0x0f,0x00,0x00,0x02,0xc0,0x00,0x0f,0x00,0x00,0x03, + 0xc0,0x00,0x0f,0x00,0x00,0x03,0xc0,0x00,0x0f,0x00,0x00,0x03,0xc0,0x00,0x0f,0x00, + 0x00,0x03,0xc0,0x00,0x0b,0x00,0x00,0x03,0xc0,0x00,0xfb,0x00,0x00,0x03,0xc0,0x01, + 0x4f,0x00,0x00,0x03,0xc0,0x03,0x87,0x00,0x00,0x02,0xc0,0x05,0x7b,0x00,0x00,0x3e, + 0xc0,0x06,0xff,0x00,0x00,0x53,0xc0,0x05,0xff,0x00,0x00,0xe1,0xc0,0x05,0xfd,0x00, + 0x01,0x5e,0xc0,0x07,0xf9,0x00,0x01,0xbf,0xc0,0x03,0x62,0x00,0x01,0x7f,0xc0,0x01, + 0x84,0x00,0x01,0x7f,0x40,0x00,0xf8,0x00,0x01,0xfe,0x40,0x00,0x00,0x00,0x00,0xdc, + 0x80,0x00,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00, + 0x00,0x22,0x00,0xa0 +}; diff --git a/p2/game.c b/p2/game.c index 9c345a7..e622518 100644 --- a/p2/game.c +++ b/p2/game.c @@ -37,7 +37,7 @@ static void do_programmed_in_1992_screen() { time_t now; time(&now); struct tm *t = localtime(&now); - if (t->tm_year + 1900 < 1996) { + if (t->tm_year + 1900 < 1996) { /* || t->tm_year + 1900 >= 2067 */ return; } g_sys.set_screen_palette(credits_palette_data, 0, 16, 6); @@ -127,9 +127,6 @@ static void do_menu() { fade_out_palette(); break; } - if (g_vars.input.keystate[4] || g_vars.input.keystate[0x51]) { - break; - } g_sys.sleep(30); } } diff --git a/p2/game.h b/p2/game.h index 82d737c..9c56d27 100644 --- a/p2/game.h +++ b/p2/game.h @@ -10,6 +10,7 @@ extern struct options_t g_options; #define TILEMAP_SCREEN_W GAME_SCREEN_W #define TILEMAP_SCREEN_H (GAME_SCREEN_H - PANEL_H) +#define TILEMAP_SCROLL_W 64 #define CHEATS_NO_HIT (1 << 0) #define CHEATS_UNLIMITED_LIFES (1 << 1) @@ -35,6 +36,11 @@ struct club_projectile_t { int16_t y_velocity; // 0xE }; +struct monster_t { + void *ref; // 0x6 + uint8_t unkE; // 0xE +}; + struct thing_t { void *ref; // 0x9 int16_t counter; // 0xC @@ -49,6 +55,7 @@ struct object_t { union { // 0x9 - 0x10 struct player_t p; /* objects[1] */ struct club_projectile_t c; /* objects[2..5] */ + struct monster_t m; /* objects[11..22] */ struct thing_t t; } data; uint8_t hit_counter; // 0x11 @@ -104,6 +111,9 @@ struct vars_t { uint16_t level_draw_counter; + uint8_t shake_screen_counter; + uint16_t shake_screen_voffset; + uint8_t player_lifes; uint8_t player_energy; uint8_t player_death_flag; @@ -129,11 +139,9 @@ struct vars_t { uint8_t player_club_anim_duration; bool player_using_club_flag; uint16_t player_update_counter; - uint8_t player_platform_counter; uint8_t player_current_anim_type; uint8_t player_tile_flags; - int16_t level_current_bonus_x_pos, level_current_bonus_y_pos, level_current_bonus_spr_num; uint8_t level_items_count_tbl[140]; /* bonuses and items collected in the level */ uint8_t level_items_total_count; uint8_t level_bonuses_count_tbl[80]; @@ -152,8 +160,8 @@ struct vars_t { bool tilemap_adjust_player_pos_flag; uint8_t level_noscroll_flag; int16_t tilemap_yscroll_diff; - uint16_t tilemap_x, tilemap_y; - uint16_t tilemap_prev_x, tilemap_prev_y; + 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 */ @@ -169,6 +177,10 @@ struct vars_t { 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_pos, y_pos; + uint16_t spr_num; + } current_bonus; /* bonus added */ struct { uint16_t value; uint16_t counter; diff --git a/p2/level.c b/p2/level.c index 68b4cab..dff2bd0 100644 --- a/p2/level.c +++ b/p2/level.c @@ -262,7 +262,7 @@ static void level_update_tilemap() { g_vars.animated_tiles_flag = 0; 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) { + for (int x = 0; x < (TILEMAP_SCREEN_W / 16) + 1; ++x) { const uint8_t tile_num = level_get_tile(offset + x); g_vars.tile_attr2_flags |= g_res.level.tile_attributes2[tile_num]; if (_redraw_tilemap || g_vars.animated_tile_flag_tbl[tile_num] != 0) { @@ -305,18 +305,6 @@ static void level_draw_tilemap() { } static bool level_adjust_hscroll_left() { - if (!g_options.dos_scrolling && 0) { - if (g_vars.tilemap_scroll_dx >= 0) { - return false; - } - g_vars.tilemap_scroll_dx += 4; - --g_vars.tilemap_x; - if (g_vars.tilemap_x < 0) { - g_vars.tilemap_x = 0; - g_vars.tilemap_scroll_dx = 0; - } - return true; - } if (g_vars.tilemap_x == 0) { return true; } @@ -324,22 +312,18 @@ static bool level_adjust_hscroll_left() { return false; } -static bool level_adjust_hscroll_right() { - if (!g_options.dos_scrolling && 0) { - if (g_vars.tilemap_scroll_dx < 4) { - return false; - } - g_vars.tilemap_scroll_dx -= 4; - ++g_vars.tilemap_x; - return true; - } +static uint16_t tilemap_end_xpos() { int end_x = (g_vars.objects_tbl[1].x_pos >> 4) - (TILEMAP_SCREEN_W / 16); if (g_res.level.tilemap_w < end_x) { end_x = 256 - (TILEMAP_SCREEN_W / 16); } else { end_x = g_res.level.tilemap_w; } - if (g_vars.tilemap_x >= end_x) { + return end_x; +} + +static bool level_adjust_hscroll_right() { + if (g_vars.tilemap_x >= tilemap_end_xpos()) { return true; } ++g_vars.tilemap_x; @@ -347,6 +331,30 @@ static bool level_adjust_hscroll_right() { } static void level_adjust_x_scroll() { + if (!g_options.dos_scrolling && g_vars.level_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; + const int player_xpos = g_vars.objects_tbl[1].x_pos - tilemap_xpos; + if (player_xpos > x2) { + tilemap_xpos += (player_xpos - x2); + const int tilemap_xend = tilemap_end_xpos() << 4; + if (tilemap_xpos > tilemap_xend) { + tilemap_xpos = tilemap_xend; + } + } else if (player_xpos < x1) { + tilemap_xpos += (player_xpos - x1); + if (tilemap_xpos < 0) { + 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.level_xscroll_center_flag = 0; + return; + } + 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) { @@ -645,7 +653,7 @@ static void level_update_tile_attr1_helper(uint16_t offset) { if (dy >= 32 && g_vars.objects_tbl[1].data.p.y_velocity >= 80) { g_vars.player_prev_y_pos = g_vars.objects_tbl[1].y_pos; if (g_vars.player_jumping_counter >= 20 && g_vars.objects_tbl[1].data.p.y_velocity > 160) { - g_vars.player_platform_counter = 8; + g_vars.shake_screen_counter = 8; } if (g_vars.player_jumping_counter > 10) { if ((g_res.level.scrolling_mask & 1) == 0) { @@ -978,11 +986,11 @@ static void level_add_object23_bonus(int x_vel, int y_vel, int count) { for (int i = 0; i < 32; ++i) { struct object_t *obj = &g_vars.objects_tbl[23 + i]; if (obj->spr_num == 0xFFFF) { - obj->spr_num = g_vars.level_current_bonus_spr_num; + obj->spr_num = g_vars.current_bonus.spr_num; obj->hit_counter = 0; obj->data.t.counter = 198; - obj->x_pos = g_vars.level_current_bonus_x_pos; - obj->y_pos = g_vars.level_current_bonus_y_pos; + obj->x_pos = g_vars.current_bonus.x_pos; + obj->y_pos = g_vars.current_bonus.y_pos; obj->x_velocity = x_vel; obj->data.p.y_velocity = y_vel; x_vel = -x_vel; @@ -1090,8 +1098,8 @@ static bool level_handle_bonuses_found(struct object_t *obj, struct level_bonus_ if (bonus->count & 0x80) { return false; } - g_vars.level_current_bonus_x_pos = (pos & 0xFF) << 4; - g_vars.level_current_bonus_y_pos = (pos >> 8) << 4; + g_vars.current_bonus.x_pos = (pos & 0xFF) << 4; + g_vars.current_bonus.y_pos = (pos >> 8) << 4; int num = 0; while (1) { num = random_get_number() & 7; @@ -1099,8 +1107,8 @@ static bool level_handle_bonuses_found(struct object_t *obj, struct level_bonus_ break; } } - g_vars.level_current_bonus_spr_num = 110 + num; - g_vars.level_current_bonus_y_pos -= 112; + g_vars.current_bonus.spr_num = 110 + num; + g_vars.current_bonus.y_pos -= 112; level_add_object23_bonus(0, 0, 1); } else { static uint8_t draw_counter = 0; @@ -1109,30 +1117,30 @@ static bool level_handle_bonuses_found(struct object_t *obj, struct level_bonus_ if (diff < 6) { return true; } - g_vars.level_current_bonus_x_pos = (pos & 0xFF) << 4; - g_vars.level_current_bonus_y_pos = (pos >> 8) << 4; + g_vars.current_bonus.x_pos = (pos & 0xFF) << 4; + g_vars.current_bonus.y_pos = (pos >> 8) << 4; int ax, count = 1; if (bonus->count & 0x40) { if (bonus->count == 64) { bonus->count = 0; if (g_vars.level_num == 7 || g_vars.level_num == 6) { - g_vars.level_current_bonus_spr_num = 300; + g_vars.current_bonus.spr_num = 300; level_add_object23_bonus(32, -48, 2); - g_vars.level_current_bonus_spr_num = 229; + g_vars.current_bonus.spr_num = 229; count = 4; } else { - g_vars.level_current_bonus_spr_num = 229; + g_vars.current_bonus.spr_num = 229; count = 1; } } else { if (g_vars.level_num == 7 || g_vars.level_num == 6) { - g_vars.level_current_bonus_spr_num = 300; + g_vars.current_bonus.spr_num = 300; level_add_object23_bonus(48, -96, 4); } goto decrement_bonus; } } else { - g_vars.level_current_bonus_spr_num = level_get_random_bonus_spr_num(); + g_vars.current_bonus.spr_num = level_get_random_bonus_spr_num(); } ax = 48; if (obj < &g_vars.objects_tbl[1]) { @@ -1408,61 +1416,60 @@ static void level_update_objects_decors() { } if ((trigger->flags & 15) == 8) { g_vars.level_current_object_decor_x_pos = 0; - trigger->y_pos -= trigger->unkB; - if (trigger->state == 0) { - int a = trigger->unkB - 8; + trigger->y_pos -= trigger->type8.y_delta; + if (trigger->type8.state == 0) { + int a = trigger->type8.y_delta - 8; if (a < 0) { a = 0; - trigger->unk7 = 0; + trigger->type8.unk7 = 0; } - trigger->unkB = a; + trigger->type8.y_delta = a; } if (trigger->flags & 0x40) { - if (trigger->unk7 != 0 && --trigger->counter == 0) { - trigger->state = 1; - trigger->unk7 = 0; + if (trigger->type8.unk7 != 0 && --trigger->type8.counter == 0) { + trigger->type8.state = 1; + trigger->type8.unk7 = 0; } } else { - if (trigger->state == 1) { - int y = trigger->unk7; + if (trigger->type8.state == 1) { + int y = trigger->type8.unk7; if (y < 192) { - trigger->unk7 += 8; + trigger->type8.unk7 += 8; } y >>= 4; g_vars.level_current_object_decor_y_pos = y; - trigger->unkB += y; - int bx = trigger->x_pos >> 4; - int dx = (trigger->y_pos + trigger->unkB) >> 4; - int ax = g_vars.tilemap_h - 1 - dx; - if (ax < 0) { - ax = -ax; - if (ax >= 3) { - trigger->state = 2; - trigger->counter = 22; + 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((dx << 8) | bx); + 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->state = 2; - trigger->counter = 22; + trigger->type8.state = 2; + trigger->type8.counter = 22; } } } else { - if (trigger->state == 2 && (trigger->flags & 0x40) == 0 && --trigger->counter == 0) { - trigger->state = 0; - trigger->counter = trigger->unk9; + if (trigger->type8.state == 2 && (trigger->flags & 0x40) == 0 && --trigger->type8.counter == 0) { + trigger->type8.state = 0; + trigger->type8.counter = trigger->type8.unk9; } } } - trigger->y_pos += trigger->unkB; + trigger->y_pos += trigger->type8.y_delta; } else { g_vars.level_current_object_decor_x_pos = 0; g_vars.level_current_object_decor_y_pos = 0; - if (trigger->unkE != 0 || trigger->unk7 < 0 || (trigger->flags & 0xC0) != 0) { - if (trigger->unk7 > trigger->unkE) { + if (trigger->unkE != 0 || trigger->other.unk7 < 0 || (trigger->flags & 0xC0) != 0) { + if (trigger->other.unk7 > trigger->unkE) { ++trigger->unkE; - } else if (trigger->unk7 < trigger->unkE) { + } else if (trigger->other.unk7 < trigger->unkE) { --trigger->unkE; } int al = trigger->unkE; @@ -1494,7 +1501,13 @@ static void level_update_objects_decors() { trigger->x_pos += al; g_vars.level_current_object_decor_y_pos = (int8_t)dl; trigger->y_pos += dl; - if (trigger->unk7 == trigger->unkE) { + if (trigger->other.unk7 == trigger->unkE) { + int16_t ax = trigger->other.unkC + 1; + if (trigger->other.unkA == ax) { + trigger->other.unk7 = -trigger->other.unk7; + ax = 0; + } + trigger->other.unkC = ax; } } } @@ -2109,8 +2122,8 @@ update_pos: if (g_vars.player_club_anim_duration > 0) { --g_vars.player_club_anim_duration; } - if (g_vars.player_platform_counter > 0) { - --g_vars.player_platform_counter; + if (g_vars.shake_screen_counter > 0) { + --g_vars.shake_screen_counter; } if (g_vars.restart_level_flag > 0) { --g_vars.restart_level_flag; @@ -2159,7 +2172,7 @@ static void level_update_player_collision() { if (!level_objects_collide(obj, obj_player)) { continue; } - g_vars.level_current_bonus_spr_num = obj->spr_num; + g_vars.current_bonus.spr_num = obj->spr_num; const int num = (obj->spr_num & 0x1FFF) - 53; obj->spr_num = 0xFFFF; if (num == 226) { @@ -2235,10 +2248,10 @@ static void level_update_player_collision() { int x = 32; if ((random_get_number() & 1) != 0) { x = -x; - g_vars.player_platform_counter = 7; + g_vars.shake_screen_counter = 7; } obj->x_velocity = x; - obj->spr_num = g_vars.level_current_bonus_spr_num; + obj->spr_num = g_vars.current_bonus.spr_num; } else { const int index = num - 57; ++g_vars.level_items_count_tbl[index]; @@ -2268,16 +2281,16 @@ static void level_update_player_collision() { g_vars.objects_tbl[1].hit_counter = 44; g_vars.objects_tbl[1].data.p.special_anim_num = 0; g_vars.objects_tbl[1].data.p.current_anim_num = 8; - g_vars.level_current_bonus_x_pos = g_vars.objects_tbl[1].x_pos; - g_vars.level_current_bonus_y_pos = g_vars.objects_tbl[1].y_pos - 48; + 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; const int count = g_vars.player_energy * 6 + g_vars.bonus_energy_counter; if (count != 0) { g_vars.player_energy = 0; g_vars.bonus_energy_counter = 0; - g_vars.level_current_bonus_spr_num = 0x2046; + g_vars.current_bonus.spr_num = 0x2046; level_add_object23_bonus(48, -128, count); } - g_vars.player_platform_counter = 7; + g_vars.shake_screen_counter = 7; level_clear_item(obj); level_add_object75_score(obj, 228); } else if (num == 173) { @@ -2288,10 +2301,46 @@ static void level_update_player_collision() { } } else if (num == 169) { play_sound(0); - print_warning("Unhandled bonus num 169"); + for (int i = 0; i < 12; ++i) { + struct object_t *obj = &g_vars.objects_tbl[11 + i]; + if (obj->spr_num == 0xFFFF) { + continue; + } + if ((obj->spr_num & 0x2000) == 0) { + continue; + } + print_warning("Unhandled bonus num 169"); + } + g_vars.shake_screen_counter = 9; + level_clear_item(obj); + level_add_object75_score(obj, 230); } else if (num == 170) { /* bomb */ play_sound(0); - print_warning("Unhandled bonus num 170"); + for (int i = 0; i < 12; ++i) { + struct object_t *obj = &g_vars.objects_tbl[11 + i]; + if (obj->spr_num == 0xFFFF) { + continue; + } + if ((obj->spr_num & 0x2000) == 0) { + continue; + } + g_vars.current_bonus.x_pos = obj->x_pos; + g_vars.current_bonus.y_pos = obj->y_pos; + obj->data.m.unkE = 0xFF; + obj->spr_num = 0xFFFF; + int x_vel = 32; + int y_vel = -160; + for (int i = 0; i < 4; ++i) { + g_vars.current_bonus.spr_num = level_get_random_bonus_spr_num(); + level_add_object23_bonus(x_vel, y_vel, 4); + x_vel = -x_vel; + if (x_vel >= 0) { + x_vel -= 16; + y_vel -= 16; + } + } + } + level_clear_item(obj); } else if (num == 181) { /* light off */ if (g_vars.light.state != 1) { play_sound(1); @@ -2303,8 +2352,8 @@ static void level_update_player_collision() { level_clear_item(obj); } else if (num == 180) { /* light on */ if (g_vars.light.state != 0) { - g_vars.light.palette_flag2 = 0; - g_vars.light.palette_flag1 = 1; + g_vars.light.palette_flag1 = 0; + g_vars.light.palette_flag2 = 1; g_vars.light.palette_counter = 0; g_vars.light.state = 0; } @@ -2607,8 +2656,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; - const int spr_y_pos = obj->y_pos - ((g_vars.tilemap_y << 4) + g_vars.tilemap_scroll_dy) - spr_size_tbl[2 * spr_num + 1]; - int spr_x_pos = obj->x_pos - ((g_vars.tilemap_x << 4) + (g_vars.tilemap_scroll_dx << 2)); + 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_w = spr_offs_tbl[2 * spr_num]; if (spr_hflip) { spr_w = spr_size_tbl[2 * spr_num] - spr_w; @@ -2659,9 +2710,9 @@ static void level_draw_snow() { static void level_update_player_bonuses() { if (g_vars.player_bonus_letters_mask == 0x1F) { /* found the 5 bonuses */ - g_vars.level_current_bonus_x_pos = g_vars.objects_tbl[1].x_pos; - g_vars.level_current_bonus_y_pos = g_vars.objects_tbl[1].y_pos - 112; - g_vars.level_current_bonus_spr_num = 110; + 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 - 112; + g_vars.current_bonus.spr_num = 110; level_add_object23_bonus(0, 0, 1); g_vars.player_bonus_letters_mask = 0; g_vars.player_bonus_letters_blinking_counter = 44; /* blink the letters in the panel */ @@ -2671,16 +2722,19 @@ static void level_update_player_bonuses() { } } -static void level_fixup_player_y_pos() { - if (g_vars.player_platform_counter < 1) { +static void level_shake_screen() { + if (g_vars.shake_screen_counter < 1) { return; - } else if (g_vars.player_platform_counter == 1) { + } else if (g_vars.shake_screen_counter == 1) { + g_vars.shake_screen_voffset = 0; } else if ((g_vars.level_draw_counter & 1) == 0) { + g_vars.shake_screen_voffset = 0; } else { if (g_vars.objects_tbl[1].data.p.current_anim_num != 5 && g_vars.objects_tbl[1].data.p.current_anim_num != 32) { g_vars.objects_tbl[1].y_pos -= 12; } - ++g_vars.player_platform_counter; + ++g_vars.shake_screen_counter; + g_vars.shake_screen_voffset = g_vars.shake_screen_counter; } } @@ -2964,6 +3018,6 @@ void do_level() { level_sync(); level_update_light_palette(); level_update_player_bonuses(); - level_fixup_player_y_pos(); + level_shake_screen(); } } diff --git a/p2/resource.c b/p2/resource.c index c9c1d98..f46a313 100644 --- a/p2/resource.c +++ b/p2/resource.c @@ -3,6 +3,8 @@ #include "unpack.h" #include "util.h" +static const bool _dump_data = true; + static const int BACKGROUND_SIZE = 320 * 200; static const char *_datapath; @@ -112,6 +114,16 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { platform->unk9 = *p++; } memcpy(g_res.level.monsters_attributes, p, 0x800); p += 0x800; + if (_dump_data) { + const uint8_t *p = g_res.level.monsters_attributes; + for (int i = 0; *p < 50; ++i) { + const uint8_t len = p[0]; + const uint8_t type = p[1] & 0x7F; + const uint16_t spr_num = READ_LE_UINT16(p + 2); + print_debug(DBG_RESOURCE, "monster %d len %d type %d spr %d", i, len, type, spr_num); + p += len; + } + } g_res.level.items_spr_num_offset = READ_LE_UINT16(p); p += 2; g_res.level.monsters_spr_num_offset = READ_LE_UINT16(p); p += 2; for (int i = 0; i < MAX_LEVEL_BONUSES; ++i) { @@ -135,12 +147,20 @@ void load_leveldat(const uint8_t *p, struct level_t *level) { trigger->y_pos = READ_LE_UINT16(p); p += 2; trigger->spr_num = READ_LE_UINT16(p); p += 2; trigger->flags = *p++; - trigger->unk7 = *p++; - trigger->unk8 = *p++; - trigger->unk9 = *p++; - trigger->state = *p++; - trigger->unkB = READ_LE_UINT16(p); p += 2; - trigger->counter = *p++; + const int type = trigger->flags & 15; + if (type == 8) { + trigger->type8.unk7 = *p++; + trigger->type8.unk8 = *p++; + trigger->type8.unk9 = *p++; + trigger->type8.state = *p++; + trigger->type8.y_delta = READ_LE_UINT16(p); p += 2; + trigger->type8.counter = *p++; + } else { + trigger->other.unk7 = READ_LE_UINT16(p); p += 2; + trigger->other.unk9 = *p++; + trigger->other.unkA = READ_LE_UINT16(p); p += 2; + trigger->other.unkC = READ_LE_UINT16(p); p += 2; + } trigger->unkE = *p++; } g_res.level.monsters_xmin = READ_LE_UINT16(p); p += 2; diff --git a/p2/resource.h b/p2/resource.h index 04bd026..c8a5587 100644 --- a/p2/resource.h +++ b/p2/resource.h @@ -39,12 +39,22 @@ struct level_trigger_t { uint16_t y_pos; uint16_t spr_num; uint8_t flags; - uint8_t unk7; - uint8_t unk8; - uint8_t unk9; - uint8_t state; - uint16_t unkB; - uint8_t counter; + union { + struct { + int8_t unk7; + uint8_t unk8; + uint8_t unk9; + uint8_t state; // 0xA + uint16_t y_delta; // 0xB + uint8_t counter; // 0xD + } type8; + struct { + int16_t unk7; + uint8_t unk9; + int16_t unkA; + int16_t unkC; + } other; + }; uint8_t unkE; }; // sizeof == 15 diff --git a/p2/screen.c b/p2/screen.c index bf68c56..6d8d83e 100644 --- a/p2/screen.c +++ b/p2/screen.c @@ -98,6 +98,17 @@ void video_draw_panel(const uint8_t *src) { void video_draw_tile(const uint8_t *src, int x_offset, int y_offset) { int tile_w = 16; + if (x_offset < 0) { + tile_w += x_offset; + src -= x_offset / 2; + x_offset = 0; + } + if (x_offset + tile_w > TILEMAP_SCREEN_W) { + tile_w = TILEMAP_SCREEN_W - x_offset; + } + if (tile_w <= 0) { + return; + } int tile_h = 16; if (y_offset < 0) { tile_h += y_offset; @@ -113,7 +124,7 @@ void video_draw_tile(const uint8_t *src, int x_offset, int y_offset) { uint8_t *dst = g_res.vga + y_offset * TILEMAP_SCREEN_W + x_offset; for (int y = 0; y < tile_h; ++y) { for (int x = 0; x < tile_w / 2; ++x) { - const uint8_t color = *src++; + const uint8_t color = src[x]; const uint8_t c1 = color >> 4; if (c1 != 0) { dst[x * 2] = c1; @@ -123,6 +134,7 @@ void video_draw_tile(const uint8_t *src, int x_offset, int y_offset) { dst[x * 2 + 1] = c2; } } + src += 8; dst += TILEMAP_SCREEN_W; } } diff --git a/sys_sdl2.c b/sys_sdl2.c index 86cab35..68c9d1f 100644 --- a/sys_sdl2.c +++ b/sys_sdl2.c @@ -475,10 +475,19 @@ static void handle_joystickbutton(int button, int pressed) { } } -static int handle_event(const SDL_Event *ev) { +static int handle_event(const SDL_Event *ev, bool *paused) { switch (ev->type) { case SDL_QUIT: - _input->quit = 1; + _input->quit = true; + break; + case SDL_WINDOWEVENT: + switch (ev->window.event) { + case SDL_WINDOWEVENT_FOCUS_GAINED: + case SDL_WINDOWEVENT_FOCUS_LOST: + *paused = (ev->window.event == SDL_WINDOWEVENT_FOCUS_LOST); + SDL_PauseAudio(*paused); + break; + } break; case SDL_KEYUP: handle_keyevent(ev->key.keysym.sym, 0); @@ -543,12 +552,19 @@ static int handle_event(const SDL_Event *ev) { } static void sdl2_process_events() { - SDL_Event ev; - while (SDL_PollEvent(&ev)) { - handle_event(&ev); - if (_input->quit) { + bool paused = false; + while (1) { + SDL_Event ev; + while (SDL_PollEvent(&ev)) { + handle_event(&ev, &paused); + if (_input->quit) { + break; + } + } + if (!paused) { break; } + SDL_Delay(100); } }