From 40ec27ef168c52aa690ebe2d4f3e76e3f0287b1e Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sun, 9 Jun 2019 08:43:49 +0800 Subject: [PATCH] Import blues from fd9efcd2 --- p2/bosses.c | 9 +++- p2/game.c | 59 ++++++++++++++++++++++++- p2/game.h | 12 +++-- p2/level.c | 118 +++++++++++++++++++++++++++++++++++++++++-------- p2/staticres.c | 8 +++- p2/unpack.c | 56 +++++++++++++++++++---- 6 files changed, 230 insertions(+), 32 deletions(-) diff --git a/p2/bosses.c b/p2/bosses.c index 97257d7..f570a84 100644 --- a/p2/bosses.c +++ b/p2/bosses.c @@ -59,6 +59,7 @@ static void level_update_boss_gorilla_collide_proj(struct object_t *obj_player, return; } level_update_objects_boss_hit_player(); + play_sound(1); obj_player->hit_counter = 44; g_vars.player_anim_0x40_flag = 0; obj_player->data.p.y_velocity = -128; @@ -75,7 +76,12 @@ static void level_update_boss_gorilla_hit_player() { level_update_boss_gorilla_collide_proj(&g_vars.objects_tbl[1], g_vars.boss.obj1); if (level_objects_collide(&g_vars.objects_tbl[1], g_vars.boss.obj3)) { if (g_vars.player_jump_monster_flag != 0) { - g_vars.objects_tbl[1].data.p.y_velocity = (g_vars.input.key_up != 0) ? -128 : -64; + int y_vel = -64; + if (g_vars.input.key_up != 0) { + play_sound(3); + y_vel = -128; + } + g_vars.objects_tbl[1].data.p.y_velocity = y_vel; } } } @@ -182,6 +188,7 @@ static void level_update_boss_gorilla_helper2() { if (abs(g_vars.level_draw_counter - g_vars.boss.draw_counter) <= 22) { break; } + play_sound(8); g_vars.boss.draw_counter = g_vars.level_draw_counter; for (int j = 103; j <= 107; ++j) { g_vars.objects_tbl[j].spr_num |= 0x4000; diff --git a/p2/game.c b/p2/game.c index c807067..07356cc 100644 --- a/p2/game.c +++ b/p2/game.c @@ -117,7 +117,33 @@ static void do_present_screen() { } } +static const uint8_t joystick_palette_data[] = { + 0x08,0x14,0x22,0x10,0x00,0x00,0x18,0x00,0x00,0x20,0x00,0x08,0x06,0x0F,0x1A,0x28, + 0x10,0x08,0x28,0x18,0x08,0x30,0x20,0x08,0x30,0x28,0x08,0x38,0x30,0x10,0x38,0x30, + 0x18,0x38,0x30,0x20,0x38,0x30,0x28,0x38,0x30,0x30,0x38,0x38,0x38,0x00,0x00,0x00 +}; + static void do_demo_screen() { + uint8_t *data = load_file("JOYSTICK.SQZ"); + if (data) { + video_copy_img(data); + g_sys.set_screen_palette(joystick_palette_data, 0, 16, 6); + update_screen_img(g_res.background); + g_sys.fade_in_palette(); + free(data); + wait_input(1000); + } +} + +static void do_castle_screen() { + uint8_t *data = load_file("CASTLE.SQZ"); + if (data) { + g_sys.set_screen_palette(data, 0, 256, 6); + update_screen_img(data + 768); + g_sys.fade_in_palette(); + free(data); + wait_input(1000); + } } static void do_menu() { @@ -144,6 +170,15 @@ static void do_menu() { } } +static void do_photos_screen() { +} + +void input_check_ctrl_alt_e() { + if (g_vars.input.keystate[0x1D] && g_vars.input.keystate[0x38] && g_vars.input.keystate[0x12]) { + do_photos_screen(); + } +} + void input_check_ctrl_alt_w() { if (g_vars.input.keystate[0x1D] && g_vars.input.keystate[0x38] && g_vars.input.keystate[0x11]) { do_credits(); @@ -151,6 +186,24 @@ void input_check_ctrl_alt_w() { } } +void do_theend_screen() { + uint8_t *data = load_file("THEEND.SQZ"); + if (data) { + g_sys.set_screen_palette(data, 0, 256, 6); + update_screen_img(data + 768); + g_sys.fade_in_palette(); + free(data); + wait_input(1000); + } + time_t now; + time(&now); + struct tm *t = localtime(&now); + if (t->tm_year + 1900 < 1994) { + return; + } + do_photos_screen(); +} + uint32_t timer_get_counter() { const uint32_t current = g_sys.get_timestamp(); return ((current - g_vars.starttime) * 1193182 / 0x4000) / 1000; @@ -204,7 +257,7 @@ static void game_run(const char *data_path) { video_convert_tiles(g_res.uniondat, g_res.unionlen); g_vars.level_num = g_options.start_level; do_programmed_in_1992_screen(); - if (!g_sys.input.space) { + if (!g_sys.input.space && !g_sys.input.quit) { do_titus_screen(); play_music(3); do_present_screen(); @@ -226,6 +279,10 @@ static void game_run(const char *data_path) { uint8_t level_num; do { level_num = g_vars.level_num; + if (g_vars.level_num >= 8 && g_vars.level_num < 10 && 0 /* !g_vars.level_expert_flag */ ) { + do_castle_screen(); + break; + } 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); diff --git a/p2/game.h b/p2/game.h index bda5d48..33a0ad8 100644 --- a/p2/game.h +++ b/p2/game.h @@ -15,6 +15,7 @@ extern struct options_t g_options; #define CHEATS_NO_HIT (1 << 0) #define CHEATS_UNLIMITED_LIFES (1 << 1) #define CHEATS_UNLIMITED_ENERGY (1 << 2) +#define CHEATS_NO_WIND (1 << 3) struct club_anim_t { const uint8_t *anim; /* uint16_t[4] : player spr, club spr, x, y */ @@ -257,8 +258,9 @@ struct vars_t { uint16_t spr_num; } current_bonus; /* bonus added */ struct { - uint16_t value; + uint16_t value; /* wind */ uint16_t counter; + const uint16_t *pattern; uint16_t random_tbl[256]; } snow; struct { @@ -288,7 +290,7 @@ extern const uint8_t score_spr_lut[110]; extern const uint8_t *object_anim_tbl[]; extern const struct club_anim_t club_anim_tbl[4]; extern const uint8_t player_anim_lut[32]; -extern const uint8_t player_anim_data[100]; +extern const uint8_t player_flying_anim_data[100]; /* uint16_t: player_spr_num, uint16_t: flying_spr_num, int8_t: dx, int8_t: dy */ extern const uint8_t vscroll_offsets_data[132]; extern const uint8_t cos_tbl[256]; extern const uint8_t sin_tbl[256]; @@ -296,11 +298,15 @@ extern const uint16_t monster_spr_tbl[48]; extern const uint8_t monster_anim_tbl[1100]; extern const uint8_t boss_minotaur_seq_data[86]; extern const uint16_t boss_gorilla_data[19 * 10]; -extern const uint16_t boss_gorilla_spr_tbl[46 * 3]; /* uint16_t: spr1_num, uint16_t: spr2_num, uint8_t: dx, uint8_t: dy */ +extern const uint16_t boss_gorilla_spr_tbl[46 * 3]; /* uint16_t: spr1_num, uint16_t: spr2_num, int8_t: dx, int8_t: dy */ +extern const uint16_t snow_pattern1_data[11]; +extern const uint16_t snow_pattern2_data[10]; /* game.c */ extern void update_input(); +extern void input_check_ctrl_alt_e(); extern void input_check_ctrl_alt_w(); +extern void do_theend_screen(); extern uint32_t timer_get_counter(); extern void random_reset(); extern uint8_t random_get_number(); diff --git a/p2/level.c b/p2/level.c index 21e69ac..b910e94 100644 --- a/p2/level.c +++ b/p2/level.c @@ -262,6 +262,7 @@ static void load_level_data(int num) { print_debug(DBG_GAME, "start_pos %d,%d", g_res.level.start_x_pos, g_res.level.start_y_pos); load_level_data_init_animated_tiles(); load_level_data_init_transparent_tiles(); + g_vars.snow.pattern = (g_vars.level_num != 15) ? snow_pattern1_data : snow_pattern2_data; g_vars.snow.counter = 0; g_vars.tilemap_start_x_pos = g_res.level.start_x_pos; g_vars.tilemap_start_y_pos = g_res.level.start_y_pos; @@ -667,6 +668,10 @@ 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_vars.level_num == 14) { + g_vars.player_death_flag = 0xFF; + return; + } if (g_options.cheats & CHEATS_NO_HIT) { return; } @@ -974,11 +979,14 @@ static void level_reset_objects() { } static void level_reset() { + g_vars.tilemap_noscroll_flag = 0; g_vars.player_nojump_counter = 0; g_vars.player_action_counter = 0; g_vars.restart_level_flag = 0; g_vars.player_death_flag = 0; g_vars.level_completed_flag = 0; + g_vars.light.palette_flag1 = 0; + g_vars.light.palette_flag2 = 0; g_vars.objects_tbl[1].data.p.special_anim_num = 0; g_vars.tilemap.prev_x = _undefined; @@ -1203,6 +1211,7 @@ static bool level_collide_axe_monsters(struct object_t *axe_obj) { obj->data.m.flags |= 0x40; obj->data.m.energy -= g_vars.player_club_power; if (obj->data.m.energy < 0) { + play_sound(2); level_monster_die(obj, m, axe_obj); } else { obj->x_pos -= obj->data.m.x_velocity >> 2; @@ -1901,7 +1910,9 @@ static void level_update_player_hdir_x_velocity(int x_vel) { } static void level_update_screen_x_velocity() { - g_vars.objects_tbl[1].x_velocity -= g_vars.snow.value >> 3; + if ((g_options.cheats & CHEATS_NO_WIND) == 0) { + g_vars.objects_tbl[1].x_velocity -= g_vars.snow.value >> 3; + } if (g_vars.objects_tbl[1].x_velocity < -96) { g_vars.objects_tbl[1].x_velocity = -96; } @@ -1990,6 +2001,13 @@ static void level_update_player_anim_3_6_7(uint8_t al) { g_vars.player_anim_0x40_flag = (g_vars.player_current_anim_type & 0x40) ^ 0x40; if (g_vars.player_anim_0x40_flag == 0) { g_vars.player_club_anim_duration = club_anim_tbl[g_vars.player_club_type].a; + if (g_vars.player_club_type == 0) { + play_sound(5); + } else if (g_vars.player_club_type == 1) { + play_sound(0); + } else { + play_sound(10); + } int16_t dy = 0; al = g_vars.objects_tbl[1].data.p.current_anim_num; if (al != 6) { @@ -2302,7 +2320,51 @@ static void level_update_player_flying() { if (g_vars.player_flying_flag == 0) { return; } - print_warning("Unimplemented level_update_player_flying"); + if (g_vars.player_gravity_flag != 0) { + g_vars.objects_tbl[1].spr_num &= 0x8000; + const int x_vel = abs(g_vars.objects_tbl[1].x_velocity); + int num = 48; + if (x_vel < 64) { + ++num; + if (x_vel < 32) { + ++num; + } + } + if (g_vars.player_flying_anim_index < 3) { + num = 51 - g_vars.player_flying_anim_index; + } + g_vars.objects_tbl[1].spr_num |= num; + } + const uint8_t *p = &player_flying_anim_data[14]; + if ((g_vars.input.key_up | g_vars.input.key_down) == 0 && g_vars.player_flying_anim_index != 3) { + if (g_vars.player_flying_anim_index < 3) { + ++g_vars.player_flying_anim_index; + } else { + --g_vars.player_flying_anim_index; + } + } + const uint16_t player_spr_num = g_vars.objects_tbl[1].spr_num; + for (uint16_t num; (num = READ_LE_UINT16(p)) != 0; p += 6) { + if (num != (player_spr_num & 0x1FFF)) { + continue; + } + int x_delta = (int8_t)p[4]; + int spr_num = READ_LE_UINT16(p + 2); + if (spr_num >= 121) { + spr_num = READ_LE_UINT16(player_flying_anim_data + g_vars.player_flying_anim_index * 2); + } + if (player_spr_num & 0x8000) { + spr_num |= 0x8000; + x_delta = -x_delta; + } + if (g_vars.player_unk_counter1 > 24 && (spr_num & 0x1FFF) < 121) { + ++spr_num; + } + g_vars.objects_tbl[0].spr_num = spr_num; + g_vars.objects_tbl[0].x_pos += x_delta; + g_vars.objects_tbl[0].y_pos += (int8_t)p[5]; + break; + } } static void level_update_player() { @@ -2514,6 +2576,7 @@ static void level_update_player_collision() { continue; } if (!g_vars.player_jump_monster_flag || g_vars.objects_tbl[1].data.p.y_velocity < 0) { + play_sound(9); m->flags &= ~1; g_vars.objects_tbl[1].hit_counter = 44; g_vars.player_anim_0x40_flag = 0; @@ -2534,6 +2597,7 @@ static void level_update_player_collision() { } if (!g_vars.player_gravity_flag) { /* jumping on a monster */ + play_sound(3); int num = obj->data.m.hit_jump_counter >> 2; if (num != 11) { obj->data.m.hit_jump_counter += 4; @@ -2973,9 +3037,8 @@ static bool level_update_objects_anim() { if (g_vars.level_completed_flag == 1) { if (g_vars.level_num < 10) { level_completed_bonuses_animation(); - } else { - ++g_vars.level_num; } + ++g_vars.level_num; level_reset(); return false; } else if (g_vars.level_completed_flag & 0x80) { @@ -3027,9 +3090,14 @@ static bool level_update_objects_anim() { } } else if (g_vars.player_death_flag == 1) { level_player_death_animation(); + } else if (g_vars.player_death_flag == 0xFF) { + do_theend_screen(); + return false; } else { return true; } + input_check_ctrl_alt_e(); + play_music(17); g_vars.objects_tbl[1].spr_num = 13; g_vars.level_num = 0; g_vars.score = 0; @@ -3109,28 +3177,25 @@ static void level_update_light_palette() { if ((g_vars.light.palette_flag1 | g_vars.light.palette_flag2) != 0) { ++g_vars.light.palette_counter; uint8_t palette[16 * 3]; - const uint8_t *si = palettes_tbl[g_vars.level_num]; - const uint8_t *bx = light_palette_data; + const uint8_t *src_pal = palettes_tbl[g_vars.level_num]; + const uint8_t *dst_pal = light_palette_data; bool changed = false; if (g_vars.light.palette_flag2 != 0) { - SWAP(si, bx); + SWAP(src_pal, dst_pal); } for (int i = 0; i < 16 * 3; ++i) { - int al = *si++; - const int ah = *bx++; - int dh = g_vars.light.palette_counter; - al -= ah; - if (al < 0) { - al = -al; - dh = -dh; + int diff = src_pal[i] - dst_pal[i]; + int step = g_vars.light.palette_counter; + if (diff < 0) { + diff = -diff; + step = -step; } - if (al <= g_vars.light.palette_counter) { - al = ah; + if (diff <= g_vars.light.palette_counter) { + palette[i] = dst_pal[i]; } else { - al = si[-1] - dh; + palette[i] = src_pal[i] - step; changed = true; } - palette[i] = al; } if (!changed) { g_vars.light.palette_flag1 = 0; @@ -3268,6 +3333,16 @@ static void level_draw_flies() { static void level_draw_snow() { ++g_vars.snow.counter; if ((g_vars.level_draw_counter & 3) == 0) { + const uint16_t *p = g_vars.snow.pattern; + if (p[0] != 0xFFFF) { + if (p[0] < g_vars.snow.counter) { + g_vars.snow.value += p[1]; + if (p[3] < g_vars.snow.counter) { + g_vars.snow.counter += 3; + } + } + g_vars.snow.value = MIN(g_vars.snow.value, p[2]); + } } if (g_vars.snow.value == 0) { return; @@ -3276,12 +3351,18 @@ static void level_draw_snow() { uint16_t *p = g_vars.snow.random_tbl; for (int i = 0; i < g_vars.snow.value; ++i) { p[i] += 79; + uint8_t al = p[i]; + uint8_t cl = ((al << 1) | (al >> 7)) & 3; uint16_t pos = (p[i] - g_vars.tilemap.x) & 0x1FFF; if (pos >= 7000) { pos -= 7000; p[i] = pos; } + const int y_pos = (pos / 40); + const int x_pos = (pos % 40) * 8 + cl * 2; + video_put_pixel(x_pos, y_pos, 15); if ((g_vars.snow.value - i) > half) { + video_put_pixel(x_pos, y_pos + 1, 15); } } const uint8_t num = random_get_number(); @@ -3321,6 +3402,7 @@ static void level_shake_screen() { } static void level_player_death_animation() { + play_sound(7); 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; diff --git a/p2/staticres.c b/p2/staticres.c index 3da754d..594b269 100644 --- a/p2/staticres.c +++ b/p2/staticres.c @@ -317,7 +317,7 @@ const uint8_t player_anim_lut[] = { 0x00,0x03,0x05,0x07,0x02,0x06,0x00,0x00,0x01,0x03,0x04,0x07,0x02,0x06,0x01,0x00, 0x01,0x03,0x04,0x07,0x02,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; -const uint8_t player_anim_data[] = { +const uint8_t player_flying_anim_data[] = { 0x7C,0x00,0x7B,0x00,0x7A,0x00,0x79,0x00,0x7D,0x00,0x7E,0x00,0x7F,0x00,0x27,0x00, 0x77,0x00,0xFE,0xEF,0x28,0x00,0x77,0x00,0x00,0xF0,0x29,0x00,0x77,0x00,0x00,0xEF, 0x2A,0x00,0x77,0x00,0x01,0xF0,0x2B,0x00,0x77,0x00,0x00,0xF1,0x2C,0x00,0x77,0x00, @@ -482,3 +482,9 @@ const uint16_t boss_gorilla_spr_tbl[] = { 0x819E,0xE42C,0x0199,0x01A0,0x1012,0x019A,0x819D,0xEE18,0x019A,0x819E,0xEA29,0x019A,0x01A0,0x1309,0x019B,0x819D, 0xF91A,0x019B,0x819E,0xF329,0x019B,0x01A0,0x1E0C,0x019A,0x81A0,0x16EC }; +const uint16_t snow_pattern1_data[] = { + 0xFFFF +}; +const uint16_t snow_pattern2_data[] = { + 0x01B8,0x0001,0x0028,0x0370,0x0006,0x0064,0x0528,0x0001,0x00FF,0xFFFF +}; diff --git a/p2/unpack.c b/p2/unpack.c index 131bc8a..a4a5228 100644 --- a/p2/unpack.c +++ b/p2/unpack.c @@ -234,6 +234,7 @@ static int unpack_sqv(FILE *in, struct unpack_sqv_t *u) { const int uncompressed_size = (READ_LE_UINT16(u->rd) << 16) + READ_LE_UINT16(u->rd + 2); const int dict_len = READ_LE_UINT16(u->rd + 4); print_debug(DBG_UNPACK, "SQV uncompressed size %d dict_len %d", uncompressed_size, dict_len); + assert(dict_len <= 0x400); fread(u->dict_buf, 1, dict_len, in); uint8_t *output_buffer = (uint8_t *)malloc(uncompressed_size); @@ -245,13 +246,16 @@ static int unpack_sqv(FILE *in, struct unpack_sqv_t *u) { uint8_t *dst = output_buffer; const uint8_t *src = u->rd; - int len = 1; + int bits_count = 1; int bytes_count = 2; + int state = 0; + int count = 0; + uint8_t code, prev; uint16_t bits = 0; uint16_t val = 0; while ((dst - output_buffer) < uncompressed_size) { - --len; - if (len == 0) { + --bits_count; + if (bits_count == 0) { bytes_count -= 2; if (bytes_count == 0) { bytes_count = fread(u->rd, 1, 0x1000, in); @@ -262,20 +266,56 @@ static int unpack_sqv(FILE *in, struct unpack_sqv_t *u) { src = u->rd; } bits = READ_BE_UINT16(src); src += 2; - len = 17; - continue; + bits_count = 16; } - const int carry = (bits & 0x8000) != 0; + const bool carry = (bits & 0x8000) != 0; bits <<= 1; if (carry) { val += 2; } - assert(val < 0x400); + assert((val & 1) == 0); + assert(val < dict_len); val = READ_LE_UINT16(u->dict_buf + val); if ((val & 0x8000) == 0) { continue; } - *dst++ = val & 255; + val &= ~0x8000; + switch (state) { + case 0: + code = val & 255; + if (val >> 8) { + switch (code) { + case 0: + state = 1; + break; + case 1: + state = 2; + break; + default: + memset(dst, prev, code); + dst += code; + break; + } + } else { + *dst++ = prev = code; + } + break; + case 1: + memset(dst, prev, val); + dst += val; + state = 0; + break; + case 2: + count = (val & 255) << 8; + state = 3; + break; + case 3: + count |= val & 255; + memset(dst, prev, count); + dst += count; + state = 0; + break; + } val = 0; } assert((dst - output_buffer) == uncompressed_size);