diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..492d264 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ + +SDL_CFLAGS := `sdl2-config --cflags` +SDL_LIBS := `sdl2-config --libs` -lSDL2_mixer + +SRCS := decode.c fileio.c game.c level.c main.c opcodes.c resource.c screen.c sound.c staticres.c sys_sdl2.c triggers.c unpack.c util.c +OBJS := $(SRCS:.c=.o) +DEPS := $(SRCS:.c=.d) + +CPPFLAGS := -Wall -Wpedantic -MMD $(SDL_CFLAGS) -g + +blues: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(SDL_LIBS) -lmodplug + +clean: + rm -f *.o *.d + +-include $(DEPS) diff --git a/README.md b/README.md new file mode 100644 index 0000000..6cd9203 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ + +# Blues Brothers + +This is a rewrite of the game [Blues Brothers](https://www.mobygames.com/game/blues-brothers) developed by [Titus](https://www.mobygames.com/company/titus-interactive-sa). + +![Screenshot1](blues1.png) ![Screenshot2](blues2.png) + + +## Requirements + +The game data files of the DOS version (retail or demo) are required. + +``` +*.BIN, *.CK1, *.CK2, *.SQL, *.SQV, *.SQZ +``` + +For sounds and music, the Amiga version files need to be copied. + +``` +SOUND, ALMOST, GUNN, EVERY, SHOT +``` + +The [ExoticA](https://www.exotica.org.uk/wiki/The_Blues_Brothers) modules set can also be used. + + +## Running + +By default, the executable loads the data files from the current directory. + +This can be changed by using command line switch. + +``` +./blues --datapath DATA_dos/ +``` diff --git a/blues1.png b/blues1.png new file mode 100644 index 0000000..94d4509 Binary files /dev/null and b/blues1.png differ diff --git a/blues2.png b/blues2.png new file mode 100644 index 0000000..5f89f6b Binary files /dev/null and b/blues2.png differ diff --git a/decode.c b/decode.c new file mode 100644 index 0000000..1d0b2af --- /dev/null +++ b/decode.c @@ -0,0 +1,32 @@ + +#include "decode.h" + +void decode_ega_spr(const uint8_t *src, int src_pitch, int w, int h, uint8_t *dst, int dst_pitch, int dst_x, int dst_y, int xflip) { + assert((src_pitch & 7) == 0); + src_pitch /= 8; + assert((w & 7) == 0); + w /= 8; + const int bitplane_size = w * h; + for (int y = 0; y < h; ++y) { + const int y_offset = dst_y + y; + for (int x = 0; x < w; ++x) { + for (int i = 0; i < 8; ++i) { + int color = 0; + const int mask = 1 << (7 - i); + for (int bit = 0; bit < 4; ++bit) { + if (src[bit * bitplane_size] & mask) { + color |= 1 << (3 - bit); + } + } + if (color != 0) { + const int x_offset = dst_x + (xflip ? (w * 8 - x * 8 - i) : (x * 8 + i)); + if (x_offset >= 0 && x_offset < 320 && y_offset >= 0 && y_offset < 200) { + dst[y_offset * dst_pitch + x_offset] = color; + } + } + } + ++src; + } + src += src_pitch - w; + } +} diff --git a/decode.h b/decode.h new file mode 100644 index 0000000..a629eb9 --- /dev/null +++ b/decode.h @@ -0,0 +1,9 @@ + +#ifndef DECODE_H__ +#define DECODE_H__ + +#include "intern.h" + +extern void decode_ega_spr(const uint8_t *src, int src_pitch, int w, int h, uint8_t *dst, int dst_pitch, int dst_x, int dst_y, int xflip); + +#endif /* DECODE_H__ */ diff --git a/fileio.c b/fileio.c new file mode 100644 index 0000000..280ff3e --- /dev/null +++ b/fileio.c @@ -0,0 +1,106 @@ + +#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() { +} + +static FILE *fio_open_no_case(const char *filename) { + char buf[MAXPATHLEN]; + snprintf(buf, sizeof(buf), "%s/%s", _data_path, filename); + FILE *fp = fopen(buf, "rb"); + if (!fp) { + char *p = buf + strlen(_data_path) + 1; + string_upper(p); + fp = fopen(buf, "rb"); + } + return fp; +} + +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 = fio_open_no_case(filename); + if (!file_slot->fp) { + if (error_flag) { + print_error("Unable to open file '%s'", filename); + } + 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 = fio_open_no_case(filename); + if (fp) { + fclose(fp); + return 1; + } + return 0; +} diff --git a/fileio.h b/fileio.h new file mode 100644 index 0000000..10ba0cd --- /dev/null +++ b/fileio.h @@ -0,0 +1,15 @@ + +#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/game.c b/game.c new file mode 100644 index 0000000..3ebe0ea --- /dev/null +++ b/game.c @@ -0,0 +1,315 @@ + +#include "game.h" +#include "resource.h" +#include "sys.h" + +struct vars_t g_vars; + +void update_input() { + g_sys.process_events(); + g_vars.inp_key_left = ((g_sys.input.direction & INPUT_DIRECTION_LEFT) != 0) || g_vars.inp_keyboard[0x4B] || g_vars.inp_keyboard[0x7A]; + g_vars.inp_key_right = ((g_sys.input.direction & INPUT_DIRECTION_RIGHT) != 0) || g_vars.inp_keyboard[0x4D] || g_vars.inp_keyboard[0x79]; + g_vars.inp_key_up = ((g_sys.input.direction & INPUT_DIRECTION_UP) != 0) || g_vars.inp_keyboard[0x48] || g_vars.inp_keyboard[0x7C]; + g_vars.inp_key_down = ((g_sys.input.direction & INPUT_DIRECTION_DOWN) != 0) || g_vars.inp_keyboard[0x50] || g_vars.inp_keyboard[0x7B]; + g_vars.inp_key_space = (g_sys.input.space != 0) || g_vars.inp_keyboard[0x39] || g_vars.inp_keyboard[0x77]; + g_vars.inp_key_tab = g_vars.inp_keyboard[0xF] || g_vars.inp_keyboard[0x78]; +} + +void do_title_screen() { + // _timer_counter = 20; + load_img("pres.sqz"); + fade_in_palette(); + do { + update_input(); +// if (_timer_counter <= 0) { +// break; +// } + } while (g_sys.input.space == 0 && g_sys.input.quit == 0); +// timer_unk3(); + fade_out_palette(); + g_sys.input.space = 0; + read_file("avtmag.sqv", g_res.avt_sqv); +} + +static void check_cheat_code() { + static const uint8_t codes[] = { 0x14, 0x17, 0x27, 0x18, 0x14, 0x23, 0x12, 0x12 }; + if ((g_vars.inp_code & 0x80) == 0 && g_vars.inp_code != 0) { + if (g_vars.inp_code == codes[g_vars.cheat_code_len]) { + ++g_vars.cheat_code_len; + if (g_vars.cheat_code_len == ARRAYSIZE(codes)) { + g_vars.cheat_flag = 1; + } + } else { + g_vars.cheat_code_len = 0; + } + } +} + +void do_select_player() { + int quit = 0; + int var9 = 0; + int state = 0; + int frame1 = 1; + int frame2 = 1; + const int color_rgb = 2; + const int colors_count = 25; + load_img("choix.sqz"); + screen_clear_sprites(); + do { + screen_unk4(); + update_input(); + switch (state) { + case 0: + screen_add_sprite(95, 155, animframe_0135[frame1]); + if (frame1 < animframe_0135[0]) { + ++frame1; + } else { + frame1 = 1; + } + screen_add_sprite(190, 155, animframe_01d5[frame2]); + if (frame2 < animframe_01d5[0]) { + ++frame2; + } else { + frame2 = 1; + } + g_vars.two_players_flag = 0; + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER1] = PLAYER_JAKE; + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER2] = 100; + g_vars.player = PLAYER_JAKE; + if (g_sys.input.direction & INPUT_DIRECTION_RIGHT) { + g_sys.input.direction &= ~INPUT_DIRECTION_RIGHT; + for (int i = 0; i < colors_count; ++i) { + screen_adjust_palette_color( 2, color_rgb, 1); + screen_adjust_palette_color( 9, color_rgb, 1); + screen_adjust_palette_color( 3, color_rgb, -1); + screen_adjust_palette_color(10, color_rgb, -1); + } + screen_vsync(); + state = 1; + frame1 = frame2 = 1; + // _timer_counter = 20; + } else if (g_sys.input.direction & INPUT_DIRECTION_LEFT) { + g_sys.input.direction &= ~INPUT_DIRECTION_LEFT; + for (int i = 0; i < colors_count; ++i) { + screen_adjust_palette_color(2, color_rgb, 1); + screen_adjust_palette_color(9, color_rgb, 1); + } + screen_vsync(); + state = 2; + frame1 = frame2 = 1; + // _timer_counter = 20; + } + break; + case 1: + screen_add_sprite(95, 155, animframe_00dd[frame1]); + if (frame1 < animframe_00dd[0]) { + ++frame1; + } else { + frame1 = 4; + } + screen_add_sprite(190, 155, animframe_022d[frame2]); + if (frame2 < animframe_022d[0]) { + ++frame2; + } else { + frame2 = 1; + } + g_vars.two_players_flag = 0; + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER1] = PLAYER_ELWOOD; + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER2] = 100; + g_vars.player = PLAYER_ELWOOD; + if (g_sys.input.direction & INPUT_DIRECTION_RIGHT) { + g_sys.input.direction &= ~INPUT_DIRECTION_RIGHT; + for (int i = 0; i < colors_count; ++i) { + screen_adjust_palette_color( 3, color_rgb, 1); + screen_adjust_palette_color(10, color_rgb, 1); + } + screen_vsync(); + state = 2; + frame1 = frame2 = 1; + // _timer_counter = 20; + } else if (g_sys.input.direction & INPUT_DIRECTION_LEFT) { + g_sys.input.direction &= ~INPUT_DIRECTION_LEFT; + for (int i = 0; i < colors_count; ++i) { + screen_adjust_palette_color( 3, color_rgb, 1); + screen_adjust_palette_color(10, color_rgb, 1); + screen_adjust_palette_color( 2, color_rgb, -1); + screen_adjust_palette_color( 9, color_rgb, -1); + } + screen_vsync(); + state = 0; + frame1 = frame2 = 1; + // _timer_counter = 20; + } + break; + case 2: + screen_add_sprite(95, 155, animframe_0135[frame1]); + if (frame1 < animframe_0135[0]) { + ++frame1; + } else { + frame1 = 1; + } + screen_add_sprite(190, 155, animframe_022d[frame2]); + if (frame2 < animframe_022d[0]) { + ++frame2; + } else { + frame2 = 1; + } + g_vars.two_players_flag = 1; + if (g_sys.input.direction & INPUT_DIRECTION_RIGHT) { + g_sys.input.direction &= ~INPUT_DIRECTION_RIGHT; + for (int i = 0; i < colors_count; ++i) { + screen_adjust_palette_color(2, color_rgb, -1); + screen_adjust_palette_color(9, color_rgb, -1); + } + screen_vsync(); + state = 0; + frame1 = frame2 = 1; + // _timer_counter = 20; + } else if (g_sys.input.direction & INPUT_DIRECTION_LEFT) { + g_sys.input.direction &= ~INPUT_DIRECTION_LEFT; + for (int i = 0; i < colors_count; ++i) { + screen_adjust_palette_color( 3, color_rgb, -1); + screen_adjust_palette_color(10, color_rgb, -1); + } + screen_vsync(); + state = 1; + frame1 = frame2 = 1; + // _timer_counter = 20; + } + break; + } +// state_default_: + if (var9 == 0) { + fade_in_palette(); + var9 = 1; + for (int i = 0; i < colors_count; ++i) { + screen_adjust_palette_color( 3, color_rgb, 1); + screen_adjust_palette_color(10, color_rgb, 1); + } + continue; + } + screen_clear_last_sprite(); + screen_redraw_sprites(); + if (g_vars.cheat_flag) { + for (int i = 5; i >= 0; --i) { + if (g_vars.inp_keyboard[2 + i]) { + g_vars.level = i; + break; + } + } +// screen_draw_number_type1(_level + 1, 256, 148, 2); + } else { + check_cheat_code(); + } + screen_flip(); + screen_vsync(); + screen_vsync(); + screen_vsync(); + g_vars.screen_draw_offset ^= 0x2000; + screen_clear_sprites(); + if (g_sys.input.space || g_vars.play_demo_flag) { + quit = 1; + } + } while (!quit && g_sys.input.quit == 0); +} + +static void do_inter_screen_helper(int a, int b, int c) { + if (c != 0) { + g_vars.screen_draw_offset ^= 0x2000; + } + int xpos = a + 20; + int ypos = b - 20; + for (int i = 0; i < 40; ++i) { + --xpos; + ++ypos; + screen_add_sprite(xpos, ypos, 125); + screen_clear_last_sprite(); + screen_redraw_sprites(); + if (c != 0) { + screen_vsync(); + } + screen_clear_sprites(); + } + for (int i = 0; i < 40; ++i) { + ++xpos; + ++ypos; + screen_add_sprite(xpos, ypos, 125); + screen_clear_last_sprite(); + screen_redraw_sprites(); + if (c != 0) { + screen_vsync(); + } + screen_clear_sprites(); + } + if (c != 0) { + g_vars.screen_draw_offset ^= 0x2000; + } +} + +static void do_inter_screen() { + static const uint8_t xpos[] = { 0xFA, 0x50, 0xF0, 0xC8, 0x50, 0x50 }; + static const uint8_t ypos[] = { 0xAA, 0x37, 0x28, 0x5F, 0xA5, 0xAA }; + load_img("inter.sqz"); + g_vars.screen_h = 199; + screen_clear_sprites(); + if (g_vars.level > 1) { + for (int i = 0; i < g_vars.level - 1; ++i) { + do_inter_screen_helper(xpos[i], ypos[i], 0); + } + } + if (g_vars.level == 5) { + do_inter_screen_helper(xpos[g_vars.level], ypos[g_vars.level], 0); + } + fade_in_palette(); + if (g_vars.level > 0 && g_vars.level < 5) { + do_inter_screen_helper(xpos[g_vars.level - 1], ypos[g_vars.level - 1], 1); + } + g_vars.screen_draw_offset = 0x2000; + screen_do_transition2(); + screen_flip(); + if (g_vars.level < MAX_LEVELS - 1) { + play_sound(SOUND_2); + screen_add_sprite(xpos[g_vars.level], ypos[g_vars.level], 126); + screen_clear_last_sprite(); + screen_redraw_sprites(); + } + g_vars.screen_draw_offset = 0x2000; + screen_flip(); + g_vars.screen_h = TILEMAP_SCREEN_H; +// _timer_counter = 4; +// while (_timer_counter != 0); + fade_out_palette(); +} + +void game_main() { + g_vars.screen_w = GAME_SCREEN_W; + g_vars.screen_h = GAME_SCREEN_H; + g_vars.screen_draw_offset = 0; + screen_flip(); + screen_init(); + g_sys.set_screen_size(GAME_SCREEN_W, GAME_SCREEN_H, "Blues Brothers"); + g_vars.start_level = g_options.start_level; + load_sqv("sprite.sqv", g_res.spr_sqv, 0); + do_title_screen(); + while (g_sys.input.quit == 0) { + if (!g_vars.level_completed_flag) { +// _level_cheat_code = 0; + g_vars.game_over_flag = 0; + g_vars.play_level_flag = 1; + if (!g_vars.play_demo_flag) { + g_vars.level = 0; + do_select_player(); + } else { + g_vars.level = g_vars.start_level; + } + screen_unk5(); + } + while (g_sys.input.quit == 0 && g_vars.play_level_flag) { + if (!g_vars.game_over_flag) { + do_inter_screen(); + } + load_level_data(g_vars.level); + do_level(); + } + } +} diff --git a/game.h b/game.h new file mode 100644 index 0000000..d7df5de --- /dev/null +++ b/game.h @@ -0,0 +1,296 @@ + +#ifndef GAME_H__ +#define GAME_H__ + +#include "intern.h" + +#define GAME_SCREEN_W 320 +#define GAME_SCREEN_H 200 + +#define TILEMAP_OFFSET_Y 14 +#define TILEMAP_SCREEN_W 320 +#define TILEMAP_SCREEN_H 160 + +#define PLAYER_JAKE 0 +#define PLAYER_ELWOOD 1 + +#define MAX_DOORS 30 +#define MAX_LEVELS 6 +#define MAX_OBJECTS 41 +#define MAX_SPRITES 40 + +#define SOUND_0 0 +#define SOUND_2 2 +#define SOUND_3 3 +#define SOUND_4 4 +#define SOUND_5 5 +#define SOUND_6 6 +#define SOUND_7 7 +#define SOUND_8 8 +#define SOUND_11 11 +#define SOUND_12 12 +#define SOUND_13 13 +#define SOUND_14 14 +#define SOUND_15 15 +#define SOUND_16 16 + +#define CHEATS_NO_HIT (1 << 0) + +struct options_t { + uint32_t cheats; + int start_level; + int start_xpos16; + int start_ypos16; + bool amiga_copper_bars; + bool amiga_colors; +}; + +extern struct options_t g_options; + +struct sprite_t { + int16_t xpos; + int16_t ypos; + int16_t spr_w; + int16_t spr_h; + const uint8_t *frame; + struct sprite_t *next_sprite; + int16_t xflip; + int16_t unk16; +}; + +struct door_t { + uint16_t src_x16, src_y16; + uint16_t dst_x16, dst_y16; +}; + +#define OBJECT_DIRECTION_RIGHT 1 +#define OBJECT_DIRECTION_LEFT 2 + +#define OBJECT_DIRECTION_UP 1 + +#define OBJECT_NUM_PLAYER1 39 +#define OBJECT_NUM_PLAYER2 40 + +#define OBJECT_ANIM_DEAD 18 + +#define OBJECT_GRAB_CRATE 0 +#define OBJECT_GRAB_BALLOON 2 +#define OBJECT_GRAB_UMBRELLA 8 + +struct object_t { + uint8_t type; + uint8_t anim_frame; + uint8_t anim_num; + const uint8_t **animframes_ptr; + uint8_t facing_left; + int16_t xvelocity; + int16_t yvelocity; + int16_t xmaxvelocity; + int16_t ymaxvelocity; + int16_t screen_xpos; + int16_t xpos; + int16_t screen_ypos; + int16_t ypos; + int16_t xacc; + int16_t yacc; + int16_t unk1C; // xvelocity / 8 + int16_t unk1E; // yvelocity / 8 + uint8_t direction_lr; + uint8_t direction_ud; + int16_t xpos16; // tilemap_xpos + int16_t ypos16; // tilemap_ypos + // int16_t unk26; + int16_t floor_ypos16; + uint8_t yfriction; + uint8_t unk2B; + uint8_t sprite_type; + uint8_t unk2D; // xfriction + int16_t unk2E; + int8_t unk2F; + uint8_t op; + uint8_t grab_state; // 1:carry_crate + uint8_t grab_type; + uint8_t special_anim; // 2:flying + // uint8_t unk35; + int16_t player_xdist; + int16_t player_ydist; + uint8_t sprite3_counter; + uint8_t visible_flag; + uint8_t moving_direction; // 0:right 1:left + uint8_t unk3D; // 1:umbrella 2:balloon + uint8_t carry_crate_flag; + // int16_t unk3F; + // uint8_t unk41; + int16_t unk42; + uint8_t tile0_flags; + uint8_t tile1_flags; + uint8_t tile2_flags; + int16_t tile012_xpos; + int8_t elevator_direction; // -1,1 + const uint8_t *trigger3; + uint8_t unk4D; + // int16_t unk4E; + int16_t unk50; + uint8_t data51; // health for obj39/40, horizontal direction for other objects + uint8_t unk53; + uint8_t unk54; + uint8_t unk55; + uint8_t unk56; + int16_t vinyls_count; + uint8_t collide_flag; + int16_t unk5A; // always zero + uint8_t unk5C; + uint8_t unk5D; + uint8_t blinking_counter; + uint8_t data5F; // music instrument number for obj39/40, counter for other objects + uint8_t unk60; + uint8_t lifes_count; + uint8_t flag_end_level; // level flag, set if music instrument was found + uint8_t unk63; // restart_level_flag +}; + +struct vars_t { + int level; + int player; + int start_level; + int16_t level_xpos[MAX_OBJECTS]; + int16_t level_ypos[MAX_OBJECTS]; + int screen_w, screen_h; + int screen_tilemap_w, screen_tilemap_h; + int screen_tilemap_w16, screen_tilemap_h16; + int screen_tilemap_xorigin, screen_tilemap_yorigin; + int screen_tilemap_xoffset, screen_tilemap_yoffset; + int screen_tilemap_size_w, screen_tilemap_size_h; + int screen_scrolling_dirmask, screen_unk1; + uint16_t screen_draw_offset; + uint16_t screen_tile_lut[256]; + int level_completed_flag; + int play_level_flag; + int game_over_flag; + int found_music_instrument_flag; + int player2_dead_flag; + int player1_dead_flag; + int player2_scrolling_flag; + int play_demo_flag; + int quit_level_flag; + int music_num; + uint8_t inp_keyboard[256]; + uint8_t inp_code; + int inp_key_space; + int inp_key_tab; + int inp_key_up; + int inp_key_down; + int inp_key_right; + int inp_key_left; + int inp_key_up_prev; + int inp_key_down_prev; + int inp_key_action; + struct door_t doors[MAX_DOORS]; + int cheat_code_len; + int cheat_flag; + struct object_t objects[MAX_OBJECTS]; + int two_players_flag; + int vinyls_count; + uint16_t timer_counter3; + int triggers_counter; + int update_objects_counter; + struct sprite_t sprites_table[MAX_SPRITES]; + struct sprite_t *sprites[MAX_SPRITES]; + int sprites_count; +}; + +extern struct vars_t g_vars; + +/* staticres.c */ +extern const uint8_t animframe_00dd[]; +extern const uint8_t animframe_0135[]; +extern const uint8_t animframe_01d5[]; +extern const uint8_t animframe_022d[]; +extern const int16_t level_xpos_magasin[]; +extern const int16_t level_ypos_magasin[]; +extern const int16_t level_xpos_concert[]; +extern const int16_t level_ypos_concert[]; +extern const int16_t level_xpos_ville[]; +extern const int16_t level_ypos_ville[]; +extern const int16_t level_xpos_egou[]; +extern const int16_t level_ypos_egou[]; +extern const int16_t level_xpos_prison[]; +extern const int16_t level_ypos_prison[]; +extern const int16_t level_xpos_ent[]; +extern const int16_t level_ypos_ent[]; +extern const int16_t level_dim[]; +extern const uint8_t level_door[]; +extern const uint16_t level_tilemap_start_xpos[]; +extern const uint16_t level_tilemap_start_ypos[]; +extern const uint8_t level_objtypes[]; +extern uint8_t level_data[]; +extern const uint8_t *animframes_059d[]; +extern uint16_t level_obj_w[MAX_OBJECTS]; +extern uint16_t level_obj_h[MAX_OBJECTS]; +extern const uint16_t level_obj_type[MAX_OBJECTS]; +extern uint8_t *level_tilesdata_1e8c[]; + +/* game.c */ +extern void update_input(); +extern void game_main(); +extern void do_title_screen(); +extern void do_select_player(); + +/* level.c */ +extern void load_level_data(int num); +extern void do_level_update_tile(int x, int y, int num); +extern void do_level_update_panel_lifes(struct object_t *); +extern void do_level_enter_door(struct object_t *); +extern void do_level_player_hit(struct object_t *); +extern void do_level_drop_grabbed_object(struct object_t *); +extern void do_level_update_object38(struct object_t *obj); +extern void do_level(); + +/* opcodes.c */ +extern void level_call_object_func(struct object_t *); + +/* screen.c */ +extern void screen_init(); +extern void screen_clear_sprites(); // _sprites_count = 0 +extern void screen_add_sprite(int x, int y, int frame); +extern void screen_clear_last_sprite(); +extern void screen_redraw_sprites(); +extern void fade_in_palette(); +extern void fade_out_palette(); +extern void screen_adjust_palette_color(int color, int b, int c); +extern void screen_vsync(); +extern void screen_set_palette(); +extern void screen_draw_frame(const uint8_t *frame, int a, int b, int c, int d); +extern void screen_flip(); +extern void screen_unk4(); +extern void screen_unk5(); +extern void screen_unk6(); +extern void screen_copy_tilemap2(int a, int b, int c, int d); +extern void screen_copy_tilemap(int a); +extern void screen_do_transition1(int a); +extern void screen_clear(int a); +extern void screen_draw_tile(int tile, int dst, int type); +extern void screen_do_transition2(); +extern void screen_draw_number(int num, int x, int y, int color); +extern void screen_add_game_sprite1(int x, int y, int frame); +extern void screen_add_game_sprite2(int x, int y, int frame); +extern void screen_add_game_sprite3(int x, int y, int frame, int blinking_counter); +extern void screen_add_game_sprite4(int x, int y, int frame, int blinking_counter); + +/* sound.c */ +extern void sound_init(int rate); +extern void sound_fini(); +extern void play_sound(int num); +extern void play_music(int num); + +/* triggers.c */ +extern uint16_t triggers_get_tile_type(int x, int y); +extern uint16_t triggers_get_next_tile_flags(int x, int y); +extern uint16_t triggers_get_tile_data(struct object_t *obj); +extern uint16_t triggers_get_next_tile_num(int x, int y); +extern void level_call_trigger_func(struct object_t *obj, int y); +extern void triggers_unk3(struct object_t *obj); +extern int16_t triggers_get_dy(struct object_t *obj); +extern void triggers_unk5(struct object_t *obj); + +#endif /* GAME_H__ */ diff --git a/intern.h b/intern.h new file mode 100644 index 0000000..9ae096d --- /dev/null +++ b/intern.h @@ -0,0 +1,37 @@ + +#ifndef INTERN_H__ +#define INTERN_H__ + +#include +#include +#include +#include +#include +#include + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif +#ifndef ABS +#define ABS(a) (((a)<0)?(-(a)):(a)) +#endif +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) +#endif + +static inline uint16_t READ_BE_UINT16(const uint8_t *p) { + return (p[0] << 8) | p[1]; +} + +static inline uint32_t READ_BE_UINT32(const uint8_t *p) { + return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; +} + +static inline uint16_t READ_LE_UINT16(const uint8_t *p) { + return p[0] | (p[1] << 8); +} + +#endif diff --git a/level.c b/level.c new file mode 100644 index 0000000..9d19013 --- /dev/null +++ b/level.c @@ -0,0 +1,2153 @@ + +/* level main loop */ + +#include "decode.h" +#include "game.h" +#include "resource.h" +#include "sys.h" +#include "util.h" + +static const uint16_t _copper_data[18 * MAX_LEVELS] = { + 0x190,0x00a,0x00b,0x00c,0x00d,0x00e,0x00f,0x01f,0x02f,0x03f,0x04f,0x05f,0x06f,0x07f,0x08f,0x09f,0x0af,0x0bf, + 0x190,0x35c,0x15c,0x25c,0x35c,0x45c,0x55c,0x65b,0x75a,0x859,0x958,0xa57,0xb56,0xc55,0xd54,0xe53,0xf54,0xf64, + 0x198,0x900,0xa00,0xb00,0xc00,0xd00,0xe00,0xf00,0xf10,0xf20,0xf30,0xf40,0xf50,0xf60,0xf70,0xf80,0xf90,0xfa0, + 0x190,0x303,0x403,0x503,0x603,0x703,0x803,0x903,0xa03,0xb03,0xc03,0xd03,0xe03,0xf03,0xf04,0xf05,0xf06,0xf07, + 0x19a,0x003,0x004,0x005,0x006,0x007,0x008,0x009,0x00a,0x00b,0x00c,0x00d,0x00e,0x00f,0x10f,0x20f,0x30f,0x40f, + 0x198,0x400,0x500,0x600,0x700,0x800,0x900,0xa00,0xb00,0xc00,0xd00,0xe00,0xf00,0xf11,0xf22,0xf33,0xf44,0xf55 +}; + +static const uint16_t _colors2_data[] = { + 0x1a0,0x000,0x1a2,0xfdd,0x1a4,0x678,0x1a6,0x046,0x1a8,0x000,0x1aa,0xa20,0x1ac,0xf87,0x1ae,0x955, + 0x1b0,0xbcf,0x1b2,0xfca,0x1b4,0x30a,0x1b6,0xa9a,0x1b8,0x900,0x1ba,0x666,0x1bc,0x747,0x1be,0x020 +}; + +static const uint16_t _colors_data[16 * MAX_LEVELS] = { + 0x000,0xc77,0x989,0x669,0x147,0xfda,0xdb9,0xf87,0x4af,0x050,0x091,0x111,0xbcf,0xa20,0x630,0xfff, + 0x000,0xa67,0xb89,0x067,0x046,0xeb8,0xca5,0xf87,0x4af,0x660,0x980,0x111,0x59c,0xa25,0x635,0xfff, + 0x000,0x744,0x989,0x669,0x147,0xfda,0xdb9,0xf87,0x3ae,0x0a2,0x0d2,0x000,0xbcf,0xf30,0x950,0xfff, + 0x000,0x885,0x773,0x267,0x147,0xca8,0x75e,0xb76,0x000,0x996,0x664,0x111,0x546,0x553,0x289,0xbcf, + 0x000,0xa9a,0x753,0x868,0x407,0xfaa,0xbac,0xd67,0x38c,0xd96,0x964,0x000,0xbcd,0x000,0x705,0xfff, + 0x000,0x30b,0x747,0x446,0x006,0xfda,0x400,0xf87,0x37a,0x600,0xd63,0x000,0x000,0x800,0xdd0,0x98d +}; + +static const struct level_data_t { + const char *ck1; + const char *ck2; + const char *sql; + const char *bin; + const char *avt; + const char *sqv; + const int16_t *xpos; + const int16_t *ypos; + uint8_t music; +} _levels[MAX_LEVELS] = { + { "mag.ck1", "mag.ck2", "mag.sql", "magasin.bin", "avtmag.sqv", "enemi1.sqv", level_xpos_magasin, level_ypos_magasin, 1 }, + { "ent.ck1", "ent.ck2", "ent.sql", "entrepot.bin", "avtent.sqv", "enemi2.sqv", level_xpos_ent, level_ypos_ent, 2 }, + { "prison.ck1", "prison.ck2", "prison.sql", "prison.bin", "avtpris.sqv", "enemi3.sqv", level_xpos_prison, level_ypos_prison, 3 }, + { "egou.ck1", "egou.ck2", "egou.sql", "egou.bin", "avtegou.sqv", "enemi4.sqv", level_xpos_egou, level_ypos_egou, 1 }, + { "ville.ck1", "ville.ck2", "ville.sql", "ville.bin", "avtville.sqv", "enemi5.sqv", level_xpos_ville, level_ypos_ville, 2 }, + { "concert.ck1", "concert.ck2", "concert.sql", "concert.bin", "", "enemi6.sqv", level_xpos_concert, level_ypos_concert, 3 }, +}; + +static const char *_demo_filenames[] = { + "demomag.ck1", "demomag.ck2", "demomag.sql" +}; + +void load_level_data(int num) { + print_debug(DBG_GAME, "load_level_data num %d", num); + if (num == 0 && (g_res.flags & RESOURCE_FLAGS_DEMO)) { + load_ck(_demo_filenames[0], 0x6000); + load_ck(_demo_filenames[1], 0x8000); + load_sql(_demo_filenames[2]); + } else { + load_ck(_levels[num].ck1, 0x6000); + load_ck(_levels[num].ck2, 0x8000); + load_sql(_levels[num].sql); + } + load_bin(_levels[num].bin); + load_avt(_levels[num].avt, g_res.avt_sqv, 0); + load_sqv(_levels[num].sqv, g_res.tmp, 146); + memcpy(g_vars.level_xpos, _levels[num].xpos, MAX_OBJECTS * sizeof(int16_t)); + memcpy(g_vars.level_ypos, _levels[num].ypos, MAX_OBJECTS * sizeof(int16_t)); + if (g_vars.music_num != _levels[num].music) { + play_music(_levels[num].music); + g_vars.music_num = _levels[num].music; + } +} + +static void init_level() { + int xpos = g_options.start_xpos16; + if (xpos < 0) { + xpos = (g_vars.level_xpos[OBJECT_NUM_PLAYER1] >> 4) - 10; + } else { + g_vars.level_xpos[OBJECT_NUM_PLAYER1] = (xpos << 4) + 10; + } + if (xpos < 0) { + xpos = 0; + } + g_vars.screen_tilemap_xorigin = xpos << 4; + + int ypos = g_options.start_ypos16; + if (ypos < 0) { + ypos = (g_vars.level_ypos[OBJECT_NUM_PLAYER1] >> 4) - 6; + } else { + g_vars.level_ypos[OBJECT_NUM_PLAYER1] = (ypos << 4) + 6; + } + if (ypos < 0) { + ypos = 0; + } + g_vars.screen_tilemap_yorigin = ypos << 4; + + if (g_vars.screen_tilemap_yorigin + (TILEMAP_SCREEN_H + 16) > g_vars.screen_tilemap_h) { + g_vars.screen_tilemap_yorigin = g_vars.screen_tilemap_h - (TILEMAP_SCREEN_H + 16); + } else { + g_vars.screen_tilemap_yorigin += 16; + } + + for (int i = 0; i < MAX_OBJECTS; ++i) { + if (!g_vars.two_players_flag) { + if (g_vars.player == PLAYER_JAKE) { + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER1] = PLAYER_JAKE; + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER2] = 100; + } else { + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER1] = PLAYER_ELWOOD; + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER2] = 100; + } + } else { + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER1] = PLAYER_JAKE; + level_data[g_vars.level * MAX_OBJECTS + OBJECT_NUM_PLAYER2] = PLAYER_ELWOOD; + } + struct object_t *obj = &g_vars.objects[i]; + obj->type = level_data[g_vars.level * MAX_OBJECTS + i]; + obj->anim_frame = 0; + obj->anim_num = 1; + if (obj->type != 100) { + const int num = obj->type * 116 / 4; + assert(num < 1189); + obj->animframes_ptr = animframes_059d + num; + } else { + obj->animframes_ptr = 0; + } + obj->facing_left = 0; + obj->yvelocity = 0; + obj->xvelocity = 0; + obj->xmaxvelocity = 48; + obj->ymaxvelocity = 15; + if (obj->type < 2) { + if (obj->unk60 == 0) { + obj->xpos = g_vars.level_xpos[i]; + obj->ypos = g_vars.level_ypos[i]; + } else { + print_warning("init_level: obj #%d unk60 %d", i, obj->unk60); + } + print_debug(DBG_GAME, "init_level obj #%d pos %d,%d", i, obj->xpos, obj->ypos); + } else { + obj->xpos = g_vars.level_xpos[i]; + obj->ypos = g_vars.level_ypos[i]; + } + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->xacc = 0; + obj->yacc = 2; + obj->direction_lr = 0; + obj->direction_ud = 0; + obj->xpos16 = obj->xpos >> 4; + obj->ypos16 = obj->ypos >> 4; + obj->floor_ypos16 = 0; + // obj->unk26 = 0; + obj->yfriction = 0; + obj->unk2B = 0; + obj->sprite_type = 0; + obj->unk2D = 0; + obj->unk2E = 1; + obj->unk2F = 0; + if (obj->type != 100) { + obj->op = level_objtypes[obj->type]; + } else { + obj->op = 0; + } + obj->grab_state = 0; + obj->grab_type = 0; + obj->special_anim = 0; + // obj->unk35 = 0; + obj->player_ydist = 0; + obj->player_xdist = 0; + obj->sprite3_counter = 0; + obj->visible_flag = 1; + if (obj->type == 100) { + obj->visible_flag = 0; + } + obj->moving_direction = 0; + obj->unk3D = 0; + obj->carry_crate_flag = 0; + // obj->unk3F = 6; + // obj->unk41 = 0; + obj->unk42 = 0; + obj->tile2_flags = 0; + obj->tile1_flags = 0; + obj->tile0_flags = 0; + obj->tile012_xpos = 0; + obj->elevator_direction = -1; + obj->unk4D = 0; + obj->trigger3 = 0; + obj->unk50 = 0; + // obj->unk4E = 0; + if (obj->unk63 == 0 && obj->flag_end_level == 0 && (g_vars.level == 0 || g_vars.play_demo_flag)) { + g_vars.player1_dead_flag = 0; + g_vars.player2_scrolling_flag = 0; + obj->lifes_count = 3; + obj->data51 = 3; + obj->vinyls_count = 0; + } else if (obj->unk63 != 0) { + --obj->lifes_count; + obj->data51 = 3; + obj->vinyls_count = 0; + } + if (g_vars.cheat_flag) { + obj->lifes_count = 3; + obj->data51 = 3; + obj->vinyls_count = 0; + } + obj->unk63 = 0; + obj->flag_end_level = 0; + obj->unk53 = 0; + obj->unk54 = 0; + obj->unk55 = 0; + obj->unk56 = 0; + obj->collide_flag = 0; + obj->unk5A = 0; + obj->unk5C = 1; + obj->unk5D = 0; + if (obj->ypos > g_vars.screen_tilemap_h) { + obj->unk53 = 1; + } + obj->blinking_counter = 0; + } + for (int i = 0; i < MAX_DOORS; ++i) { + const uint8_t *p = &level_door[g_vars.level * 240 + i * 8]; + g_vars.doors[i].src_x16 = READ_LE_UINT16(p); + g_vars.doors[i].src_y16 = READ_LE_UINT16(p + 2); + g_vars.doors[i].dst_x16 = READ_LE_UINT16(p + 4); + g_vars.doors[i].dst_y16 = READ_LE_UINT16(p + 6); + } +} + +static void do_level_redraw_tilemap(int xpos, int ypos) { + const int w = TILEMAP_SCREEN_W / 16; + const int h = TILEMAP_SCREEN_H / 16; + int y = ypos >> 4; + int x = xpos >> 4; + for (int j = 0; j < h * 640; j += 640) { + const uint8_t *ptr = lookup_sql(x, y); + for (int i = 0; i < w * 2; i += 2) { + const uint8_t num = *ptr++; + if (num >= 128) { + screen_draw_tile(g_vars.screen_tile_lut[num - 128], j + i, 4); + } else { + screen_draw_tile(g_vars.screen_tile_lut[num], j + i, 3); + } + } + ++y; + } + g_vars.screen_tilemap_xoffset = 0; + g_vars.screen_tilemap_yoffset = 0; + g_vars.screen_tilemap_size_w = w; + g_vars.screen_tilemap_size_h = h; +} + +static void do_level_update_tiles_anim() { + for (int i = 0; level_tilesdata_1e8c[i]; ++i) { + uint8_t *p = level_tilesdata_1e8c[i]; + if (p[0] == p[1]) { + p[0] = 1; + } else { + ++p[0]; + } + } + int y = g_vars.screen_tilemap_yorigin >> 4; + int x = g_vars.screen_tilemap_xorigin >> 4; + for (int j = 0; j < (TILEMAP_SCREEN_H / 16) * 640; j += 640) { + uint8_t *ptr = lookup_sql(x, y); + for (int i = 0; i < (TILEMAP_SCREEN_W / 16) * 2; i += 2, ++ptr) { + uint8_t num = *ptr; + struct trigger_t *t = &g_res.triggers[num]; + const uint8_t *data = t->op_table2; + if (!data) { + continue; + } + if (t->tile_index != 0) { + num = data[t->tile_index]; + *ptr = num; + t->unk16 = num; + } else { + const int current = data[0]; + num = data[current + 1]; + t->unk16 = num; + } + if (num >= 128) { + screen_draw_tile(g_vars.screen_tile_lut[num - 128], j + i, 4); + } else { + screen_draw_tile(g_vars.screen_tile_lut[num], j + i, 3); + } + } + ++y; + } +} + +static void do_level_update_scrolling2() { + if (g_vars.screen_scrolling_dirmask & 2) { + if (g_vars.screen_tilemap_w * 16 - TILEMAP_SCREEN_W > g_vars.screen_tilemap_xorigin) { + g_vars.screen_tilemap_xorigin += 16; + // do_level_update_scrolling_left(); + } + } + if (g_vars.screen_scrolling_dirmask & 1) { + if (g_vars.screen_tilemap_xorigin > 0) { + g_vars.screen_tilemap_xorigin -= 16; + // do_level_update_scrolling_right(); + } + } + if (g_vars.screen_scrolling_dirmask & 8) { + if (g_vars.screen_tilemap_yorigin > 0) { + g_vars.screen_tilemap_yorigin -= 16; + // do_level_update_scrolling_top(); + } + } + if (g_vars.screen_scrolling_dirmask & 4) { + if (g_vars.screen_tilemap_h - TILEMAP_SCREEN_H > g_vars.screen_tilemap_yorigin) { + g_vars.screen_tilemap_yorigin += 16; + // do_level_update_scrolling_bottom(); + } + } + do_level_redraw_tilemap(g_vars.screen_tilemap_xorigin, g_vars.screen_tilemap_yorigin); + if ((g_vars.timer_counter3 & 3) == 0) { + do_level_update_tiles_anim(); + } + if (g_vars.screen_tilemap_size_w == 20) { + if (g_vars.screen_tilemap_size_h == 10) { + screen_copy_tilemap(2); + } else { + screen_copy_tilemap2(g_vars.screen_tilemap_xoffset + g_vars.screen_tilemap_yoffset, 0, g_vars.screen_tilemap_size_w, g_vars.screen_tilemap_size_h); + screen_copy_tilemap2(g_vars.screen_tilemap_yoffset, 6400 - g_vars.screen_tilemap_xoffset, g_vars.screen_tilemap_size_w, 10 - g_vars.screen_tilemap_size_h); + } + } else if (g_vars.screen_tilemap_size_h == 10) { + screen_copy_tilemap2(g_vars.screen_tilemap_xoffset + g_vars.screen_tilemap_yoffset, 0, g_vars.screen_tilemap_size_w, g_vars.screen_tilemap_size_h); + screen_copy_tilemap2(g_vars.screen_tilemap_xoffset, 40 - g_vars.screen_tilemap_yoffset, 20 - g_vars.screen_tilemap_size_w, g_vars.screen_tilemap_size_h); + } else { + screen_copy_tilemap2(g_vars.screen_tilemap_xoffset + g_vars.screen_tilemap_yoffset, 0, g_vars.screen_tilemap_size_w, g_vars.screen_tilemap_size_h); + screen_copy_tilemap2(g_vars.screen_tilemap_xoffset, 40 - g_vars.screen_tilemap_yoffset, 20 - g_vars.screen_tilemap_size_w, g_vars.screen_tilemap_size_h); + screen_copy_tilemap2(g_vars.screen_tilemap_yoffset, 6400 - g_vars.screen_tilemap_xoffset, g_vars.screen_tilemap_size_w, 10 - g_vars.screen_tilemap_size_h); + screen_copy_tilemap2(0, 40 - g_vars.screen_tilemap_yoffset + 6400 - g_vars.screen_tilemap_xoffset, 20 - g_vars.screen_tilemap_size_w, 10 - g_vars.screen_tilemap_size_h); + } +} + +void do_level_drop_grabbed_object(struct object_t *obj) { + struct object_t *obj37 = &g_vars.objects[37]; + if (obj->type != 0 && g_vars.two_players_flag) { + obj37 = &g_vars.objects[36]; + } + if (obj37->type != 100) { + obj37->grab_state = 3; + obj->grab_state = 0; + obj->unk3D = 0; + } +} + +static void do_level_add_sprite1_case0(struct object_t *obj) { + const uint8_t *anim_data = 0; + + assert(obj->animframes_ptr); + + if (obj->unk2F != 0 && obj->direction_ud == 0 && obj->direction_lr == 0) { + anim_data = obj->animframes_ptr[24 / 4]; + } else if (triggers_get_tile_type(obj->xpos16, obj->ypos16) == 4) { + anim_data = obj->animframes_ptr[28 / 4]; + } else { + if (ABS(obj->yvelocity) > 10 && obj->yvelocity > 0) { + anim_data = obj->animframes_ptr[112 / 4]; + } else { + anim_data = obj->animframes_ptr[8 / 4]; + } + } + if (obj->grab_state != 0) { + if (obj->grab_type == 0) { + anim_data = obj->animframes_ptr[52 / 4]; + } else if (obj->grab_type == 2 || obj->grab_type == 8) { + anim_data = obj->animframes_ptr[32 / 4]; + obj->xmaxvelocity = 48; + } + } + if (obj->anim_num < anim_data[0]) { + ++obj->anim_num; + } else { + obj->anim_num = 1; + } + obj->anim_frame = anim_data[obj->anim_num]; +} + +static void do_level_add_sprite1_case1(struct object_t *obj) { + const uint8_t *anim_data = 0; + assert(obj->animframes_ptr); + obj->xmaxvelocity = 48; + if ((obj->direction_lr & 1) != 0) { + if (obj->unk2E == 0) { + anim_data = obj->animframes_ptr[16 / 4]; + obj->xmaxvelocity = 24; + } else if (obj->grab_state != 0) { + if (obj->grab_type == 0 || obj->grab_type == 8) { + anim_data = obj->animframes_ptr[48 / 4]; + } else if (obj->grab_type == 2) { + anim_data = obj->animframes_ptr[32 / 4]; + } else { + anim_data = obj->animframes_ptr[4 / 4]; + } + } else { + anim_data = obj->animframes_ptr[4 / 4]; + } + } else if ((obj->direction_lr & 2) != 0) { + if (obj->unk2E == 0) { + anim_data = obj->animframes_ptr[16 / 4]; + obj->xmaxvelocity = 24; + } else if (obj->grab_state != 0) { + if (obj->grab_type == 0 || obj->grab_type == 8) { + anim_data = obj->animframes_ptr[48 / 4]; + } else if (obj->grab_type == 2) { + anim_data = obj->animframes_ptr[32 / 4]; + } else { + anim_data = obj->animframes_ptr[4 / 4]; + } + } else { + anim_data = obj->animframes_ptr[4 / 4]; + } + } else { + if (obj->unk2E == 0) { + anim_data = obj->animframes_ptr[12 / 4]; + } else if (obj->grab_state != 0) { + if (obj->grab_type == 0 || obj->grab_type == 8) { + anim_data = obj->animframes_ptr[44 / 4]; + } else if (obj->grab_type == 2) { + anim_data = obj->animframes_ptr[32 / 4]; + } else { + anim_data = obj->animframes_ptr[4 / 4]; + } + } else { + anim_data = obj->animframes_ptr[0]; + } + if (obj->unk2D < 8) { + if (ABS(obj->xvelocity) > 8) { + anim_data = obj->animframes_ptr[24 / 4]; + } + } + } + if (obj->anim_num < anim_data[0]) { + ++obj->anim_num; + } else { + obj->anim_num = 1; + } + obj->anim_frame = anim_data[obj->anim_num]; +} + +// ladder +static void do_level_add_sprite1_case2(struct object_t *obj) { + struct object_t *obj35 = &g_vars.objects[35]; + struct object_t *obj37 = &g_vars.objects[37]; + if (obj->type != 0 && g_vars.two_players_flag) { + obj35 = &g_vars.objects[34]; + obj37 = &g_vars.objects[36]; + } + if (obj37->type != 100 && obj37->grab_type != 0) { + do_level_drop_grabbed_object(obj); + } + if (obj->grab_type == 8) { + do_level_drop_grabbed_object(obj); + } + if (obj35->type != 100) { + obj35->type = 100; + } + const uint8_t *anim_data = 0; + obj->unk3D = 0; + int tile_num = triggers_get_tile_type(obj->xpos16, obj->ypos16); + if (obj->direction_ud != 0) { + if (tile_num == 7) { + anim_data = obj->animframes_ptr[20 / 4]; + } else { + anim_data = obj->animframes_ptr[0]; + } + } else if (obj->direction_lr != 0) { + if (tile_num == 7) { + anim_data = obj->animframes_ptr[20 / 4]; + } else { + anim_data = obj->animframes_ptr[4 / 4]; + } + } else { + if (tile_num == 7) { + anim_data = obj->animframes_ptr[36 / 4]; + } else if (obj->grab_state != 0) { + if (obj->grab_type == 0 || obj->grab_type == 8) { + anim_data = obj->animframes_ptr[24 / 4]; + } else if (obj->grab_type == 2) { + anim_data = obj->animframes_ptr[32 / 4]; + } else { + anim_data = obj->animframes_ptr[0]; + } + } else { + anim_data = obj->animframes_ptr[0]; + } + } + if (obj->anim_num < anim_data[0]) { + obj->anim_num += (g_vars.timer_counter3 & 1); + } else { + obj->anim_num = 1; + } + obj->anim_frame = anim_data[obj->anim_num]; +} + +// swimming +static void do_level_add_sprite1_case4(struct object_t *obj) { + struct object_t *obj35 = &g_vars.objects[35]; + struct object_t *obj37 = &g_vars.objects[37]; + if (obj->type != 0 && g_vars.two_players_flag) { + obj35 = &g_vars.objects[34]; + obj37 = &g_vars.objects[36]; + } + if (obj37->type != 100) { + do_level_drop_grabbed_object(obj); + } + const uint8_t *anim_data = 0; + obj->unk2F = 0; + int tile0_num = triggers_get_tile_type(obj->xpos16, obj->ypos16 - 2); + // int tile1_num = triggers_get_tile_type(obj->xpos16, obj->ypos16 - 1); + // int tile2_num = triggers_get_tile_type(obj->xpos16, obj->ypos16); + obj->xmaxvelocity = 16; + if (obj->direction_lr != 0) { + if (obj->direction_ud == 1) { + if (tile0_num == 0) { + obj->unk3D = 1; + } else { + obj->unk3D = 2; + } + } else if (obj->direction_ud == 2) { + obj->unk3D = 0; + } else { + obj->unk3D = 1; + } + anim_data = obj->animframes_ptr[92 / 4]; + } else { + if (obj->direction_ud == 1) { + if (tile0_num == 0) { + obj->unk3D = 1; + } else { + obj->unk3D = 2; + } + anim_data = obj->animframes_ptr[100 / 4]; + } else if (obj->direction_ud == 2) { + obj->unk3D = 0; + anim_data = obj->animframes_ptr[100 / 4]; + } else { + obj->unk3D = 1; + anim_data = obj->animframes_ptr[96 / 4]; + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 + 1) == 13) { + anim_data = obj->animframes_ptr[104 / 4]; + } + } + } + if (obj->anim_num < anim_data[0]) { + ++obj->anim_num; + } else { + obj->anim_num = 1; + } + obj->anim_frame = anim_data[obj->anim_num]; + if (tile0_num >= 11 && obj35->type == 100) { + play_sound(SOUND_15); + obj35->type = 2; + obj35->grab_type = 7; + obj35->visible_flag = 1; + if (obj->facing_left) { + obj35->xpos = obj->xpos - 8; + obj35->screen_xpos = obj->screen_xpos - 8; + } else { + obj35->xpos = obj->xpos + 8; + obj35->screen_xpos = obj->screen_xpos + 8; + } + obj35->ypos = obj->ypos - 8; + obj35->screen_ypos = obj->screen_ypos - 8; + obj35->xpos16 = obj->xpos16; + obj35->ypos16 = obj->ypos16; + obj35->anim_num = 1; + obj37->animframes_ptr = animframes_059d + (obj37->type * 116 / 4); + } else { + obj35->unk2E = 0; + const int num = triggers_get_tile_type(obj35->xpos16, obj35->ypos16); + if (num == 11 || num == 12) { + obj35->yacc = -3; + obj35->yvelocity = -3; + obj35->ypos16 = obj35->ypos >> 4; + obj35->xpos16 = obj35->xpos >> 4; + } else { + obj35->type = 100; + obj35->visible_flag = 0; + obj35->grab_type = 0; + } + } +} + +static void do_level_add_sprite1(struct object_t *obj) { + print_debug(DBG_GAME, "add_sprite1 obj->type %d", obj->type); + if (obj->type == 100) { + // print_warning("do_level_add_sprite1: obj.type 100"); + return; + } + obj->sprite3_counter = 0; + switch (obj->sprite_type) { + case 0: + do_level_add_sprite1_case0(obj); + break; + case 1: + do_level_add_sprite1_case1(obj); + break; + case 2: + do_level_add_sprite1_case2(obj); + break; + case 4: + do_level_add_sprite1_case4(obj); + break; + default: + print_warning("do_level_add_sprite1: unhandled sprite_type %d", obj->sprite_type); + break; + } + if (obj->type != 100) { + if (obj->blinking_counter != 0 && (g_vars.timer_counter3 & 1) != 0) { + if (obj->facing_left == 0) { + screen_add_game_sprite3(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame, obj->blinking_counter); + } else { + screen_add_game_sprite4(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame, obj->blinking_counter); + } + } else { + if (obj->facing_left == 0) { + screen_add_game_sprite1(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame); + } else { + screen_add_game_sprite2(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame); + } + } + } +} + +static void do_level_add_sprite2(struct object_t *obj) { + print_debug(DBG_GAME, "add_sprite2 obj->type %d", obj->type); + const uint8_t *anim_data = obj->animframes_ptr[obj->grab_type]; + if (obj->anim_num < anim_data[0]) { + ++obj->anim_num; + } else { + obj->anim_num = 1; + } + obj->anim_frame = anim_data[obj->anim_num]; + if (obj->grab_type >= 16 && obj->grab_type != 23) { + obj->yacc = -1; + obj->yvelocity = -1; + obj->facing_left = 0; + if (obj->data5F < 30) { + ++obj->data5F; + } else { + obj->data5F = 0; + obj->type = 100; + obj->visible_flag = 0; + obj->grab_type = 0; + obj->yacc = 0; + obj->yvelocity = 0; + } + } + if (obj->type != 100) { + if (obj->facing_left == 0) { + screen_add_game_sprite1(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame); + } else { + screen_add_game_sprite2(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame); + } + } +} + +static void do_level_add_sprite3(struct object_t *obj) { + print_debug(DBG_GAME, "add_sprite3 obj->type %d", obj->type); + if (!obj->animframes_ptr) return; + const uint8_t *anim_data = obj->animframes_ptr[obj->special_anim]; + if (obj->sprite3_counter == 0) { + obj->anim_num = 1; + obj->anim_frame = anim_data[obj->anim_num]; + ++obj->sprite3_counter; + } else if (obj->sprite3_counter == 1) { + if (obj->anim_num < anim_data[0]) { + if (obj->collide_flag == 0) { + obj->anim_num += (g_vars.timer_counter3 & 1); + } + obj->anim_frame = anim_data[obj->anim_num]; + } else { + if (obj->special_anim != 16) { + obj->anim_num = 1; + obj->special_anim = 0; + obj->sprite3_counter = 0; + } else if (obj->unk5A != 0) { + obj->unk5C = 4; + } + } + if (obj->special_anim == 18 && obj->anim_num > 8 && (g_vars.inp_key_up != 0 /* || g_inp_key_T != 0*/)) { + obj->anim_num = 1; + obj->special_anim = 0; + obj->sprite3_counter = 0; + if (obj->unk5A != 0) { + obj->unk5C = 4; + } + } + } + if (obj->type != 100) { + if (obj->blinking_counter != 0 && (g_vars.timer_counter3 & 1) != 0) { + if (obj->facing_left == 0) { + screen_add_game_sprite3(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame, obj->blinking_counter); + } else { + screen_add_game_sprite4(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame, obj->blinking_counter); + } + } else { + if (obj->facing_left == 0) { + screen_add_game_sprite1(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame); + } else { + screen_add_game_sprite2(obj->screen_xpos, obj->screen_ypos + 1, obj->anim_frame); + } + } + } +} + +void do_level_update_tile(int x, int y, int num) { + uint8_t *ptr = lookup_sql(x, y); + *ptr = num; + + const int w = (TILEMAP_SCREEN_W / 16) * 2; + int _si = x * 2 + g_vars.screen_tilemap_yoffset - (g_vars.screen_tilemap_xorigin >> 3); + if (_si > w - 2) { + _si -= w; + } + const int h = (TILEMAP_SCREEN_H / 16) * 640; + int _di = (y - (g_vars.screen_tilemap_yorigin >> 4)) * 640 + g_vars.screen_tilemap_xoffset; + if (_di > h - 640) { + _di -= h; + } + if ((g_vars.screen_tilemap_xorigin >> 4) > x) { + return; + } + if ((g_vars.screen_tilemap_xorigin >> 4) + (TILEMAP_SCREEN_W / 16) <= x) { + return; + } + if ((g_vars.screen_tilemap_yorigin >> 4) > y) { + return; + } + if ((g_vars.screen_tilemap_xorigin >> 4) + (TILEMAP_SCREEN_H / 16) <= y) { + return; + } + if (num >= 128) { + screen_draw_tile(g_vars.screen_tile_lut[num - 128], _di + _si, 4); + } else { + screen_draw_tile(g_vars.screen_tile_lut[num], _di + _si, 3); + } +} + +static void do_level_reset_tiles(struct object_t *obj, int dy) { + int i, y, var2, var4; + + y = obj->ypos16 + dy; + var2 = triggers_get_next_tile_num(obj->xpos16, y); + i = 1; + do { + var4 = triggers_get_next_tile_num(obj->xpos16 + i, y); + ++i; + } while (var4 == var2); + do_level_update_tile(obj->xpos16, y, var4); +} + +static int do_level_throw_crate(struct object_t *obj) { + if (obj->screen_xpos > TILEMAP_SCREEN_W + 16 || obj->screen_xpos <= -16) { + obj->moving_direction = 1; + } + if (obj->xpos < 16 || obj->xpos > g_vars.screen_tilemap_w * 16 - 16) { + obj->moving_direction = 1; + } + if (obj->moving_direction == 0) { + if (obj->facing_left == 0) { + obj->direction_lr |= 1; + obj->xvelocity = 128; + } else { + obj->direction_lr |= 2; + obj->xvelocity = -128; + } + obj->yacc = 0; + obj->yvelocity = 0; + obj->xmaxvelocity = 128; + return 0; + } else { + obj->type = 100; + obj->visible_flag = 0; + obj->xvelocity = 0; + obj->unk5D = 0; + return 1; + } +} + +static void do_level_update_grabbed_object_type8(struct object_t *obj) { + obj->direction_ud = 0; + if (obj->screen_ypos < 32 || obj->ypos - 48 <= 0) { + obj->type = 100; + obj->visible_flag = 0; + obj->grab_state = 0; + obj->grab_type = 0; + obj->yvelocity = 0; + obj->yacc = 2; + obj->unk5D = 0; + } else { + obj->yacc = -4; + obj->yvelocity = -4; + } +} + +static void do_level_update_grabbed_object(struct object_t *obj) { + struct object_t *obj37 = &g_vars.objects[37]; + + if (obj->type != 0 && g_vars.two_players_flag != 0) { + --obj37; + } + switch (obj->grab_state) { + case 0: + if (obj37->type == 100) { + obj->carry_crate_flag = 0; + obj->grab_state = 1; + play_sound(SOUND_3); + if (obj->unk2E == 0) { + obj->unk2E = 1; + } + } + break; + case 1: + obj37->type = 2; + obj37->visible_flag = 1; + obj37->xpos = obj->xpos; + obj37->ypos = obj->ypos - 30; + obj37->screen_xpos = obj->screen_xpos; + obj37->screen_ypos = obj->screen_ypos - 30; + obj37->animframes_ptr = animframes_059d + (obj37->type * 116 / 4); + obj37->anim_num = 1; + obj37->facing_left = obj->facing_left; + obj37->sprite_type = obj->sprite_type; + obj37->yvelocity = obj->yvelocity; + obj37->xvelocity = obj->xvelocity; + obj37->yacc = obj->yacc; + obj37->xacc = obj->xacc; + obj37->unk5D = obj->type; + obj37->xpos16 = obj->xpos16; + obj37->ypos16 = obj->ypos16; + obj->grab_state = 1; + if (obj->carry_crate_flag != 0) { + play_sound(SOUND_5); + obj->grab_state = 0; + obj37->grab_state = 2; + obj37->ypos += 10; + obj->unk3D = 0; + obj37->moving_direction = 0; + obj->carry_crate_flag = 0; + } + if (triggers_get_tile_type(obj37->xpos16, obj37->ypos16 - 2) > 5 || obj37->ypos < 32 || obj37->xpos < 16) { + if (obj37->grab_type == 2) { + obj->grab_state = 0; + obj->unk3D = 0; + obj->carry_crate_flag = 0; + obj37->grab_state = 3; + obj37->moving_direction = 0; + obj37->anim_num = 1; + } + } + break; + case 2: + if (obj->grab_type == 0) { + if (do_level_throw_crate(obj)) { + obj->grab_state = 0; + } + } else if (obj->grab_type == 2 || obj->grab_type == 8) { + do_level_update_grabbed_object_type8(obj); + } + break; + case 3: + if (obj->grab_type == 2 || obj->grab_type == 3) { + obj->grab_type = 3; + if (obj->anim_num >= 8) { + obj->type = 100; + obj->visible_flag = 0; + obj->grab_state = 0; + obj->grab_type = 0; + obj->yvelocity = 0; + obj->yacc = 2; + obj37->unk5D = 0; + } + } else if (obj->grab_type == 8) { + do_level_update_grabbed_object_type8(obj); + } else { + obj->type = 100; + obj->visible_flag = 0; + obj->grab_state = 0; + obj->grab_type = 0; + obj->yvelocity = 0; + obj->yacc = 2; + obj37->unk5D = 0; + } + break; + default: + print_warning("do_level_update_grabbed_object: unhandled grab_state %d", obj->grab_state); + break; + } +} + +void do_level_update_panel_lifes(struct object_t *obj) { + struct object_t *obj39 = &g_vars.objects[OBJECT_NUM_PLAYER1]; + struct object_t *obj40 = &g_vars.objects[OBJECT_NUM_PLAYER2]; + g_vars.screen_h = 172; + if (!g_vars.two_players_flag) { + static const uint16_t data[] = { 216, 232, 248, 264, 280, 296 }; + for (int i = 0; i < obj->data51; ++i) { + screen_draw_frame(g_res.spr_frames[120 + i], 12, 16, data[i], 161); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[120 + i], 12, 16, data[i], 161); + g_vars.screen_draw_offset ^= 0x2000; + } + for (int i = obj->data51; i < 5; ++i) { + screen_draw_frame(g_res.spr_frames[119 + i], 12, 16, data[i], 161); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[119 + i], 12, 16, data[i], 161); + g_vars.screen_draw_offset ^= 0x2000; + } + } else { + static const uint8_t data[] = { 18, 21, 20, 19, 19, 19 }; + if (obj->type == PLAYER_JAKE) { + screen_draw_frame(g_res.spr_frames[101 + data[obj->data51]], 12, 16, 80, 161); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[101 + data[obj->data51]], 12, 16, 80, 161); + g_vars.screen_draw_offset ^= 0x2000; + } else { + screen_draw_frame(g_res.spr_frames[101 + data[obj->data51]], 12, 16, 248, 161); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[101 + data[obj->data51]], 12, 16, 248, 161); + g_vars.screen_draw_offset ^= 0x2000; + } + } + if (obj->data51 == 0) { // health + if (!g_vars.two_players_flag) { + obj->unk63 = 1; + g_vars.game_over_flag = 1; + } else { + if (obj->lifes_count != 1) { + --obj->lifes_count; + obj->data51 = 3; + do_level_update_panel_lifes(obj); + if (obj->type == PLAYER_JAKE) { + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->lifes_count - 1, 48, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->lifes_count - 1, 48, 163, 2); + } else { + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->lifes_count - 1, 216, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->lifes_count - 1, 216, 163, 2); + } + } else if (obj->type == PLAYER_JAKE) { + g_vars.player2_scrolling_flag = 1; + g_vars.screen_unk1 = 1; + obj39->special_anim = 16; + g_vars.player2_dead_flag = 1; + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[116], 12, 16, 8, 161); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[116], 12, 16, 8, 161); + } else { // PLAYER_ELWOOD + g_vars.player2_scrolling_flag = 0; + g_vars.screen_unk1 = 1; + obj40->special_anim = 16; + g_vars.player1_dead_flag = 1; + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[118], 12, 16, 176, 161); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[118], 12, 16, 176, 161); + } + if (g_vars.player2_dead_flag && g_vars.player1_dead_flag) { + g_vars.game_over_flag = 1; + } + } + } + g_vars.screen_h = TILEMAP_SCREEN_H; +} + +static void do_level_update_panel_vinyls(struct object_t *obj) { + // if (!_screen_panel_drawn_flag) { + // return; + // } + g_vars.screen_h = 172; + if (obj->vinyls_count > 99) { + obj->vinyls_count -= 100; + if (!g_vars.two_players_flag && obj->data51 < 5) { + ++obj->data51; + } + if (g_vars.two_players_flag && obj->data51 < 3) { + ++obj->data51; + } + do_level_update_panel_lifes(obj); + } + if (!g_vars.two_players_flag) { + if (obj->vinyls_count != g_vars.vinyls_count) { + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->vinyls_count, 192, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->vinyls_count, 192, 163, 2); + } + g_vars.vinyls_count = obj->vinyls_count; + } else { + if (obj->vinyls_count != g_vars.vinyls_count) { + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->vinyls_count, 112, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->vinyls_count, 112, 163, 2); + } + g_vars.vinyls_count = obj->vinyls_count; + } + g_vars.screen_h = TILEMAP_SCREEN_H; +} + +static void do_level_update_panel_2nd_player() { + struct object_t *obj = &g_vars.objects[OBJECT_NUM_PLAYER2]; + // if (!_screen_panel_drawn_flag) { + // return; + // } + g_vars.screen_h = 172; + if (obj->vinyls_count > 99) { + obj->vinyls_count = 0; + if (!g_vars.two_players_flag && obj->data51 < 5) { + ++obj->data51; + } + if (g_vars.two_players_flag && obj->data51 < 3) { + ++obj->data51; + } + do_level_update_panel_lifes(obj); + } + if (obj->vinyls_count != g_vars.vinyls_count) { + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->vinyls_count, 280, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->vinyls_count, 280, 163, 2); + g_vars.vinyls_count = obj->vinyls_count; + } + g_vars.screen_h = TILEMAP_SCREEN_H; +} + +static void draw_level_panel() { + struct object_t *obj39 = &g_vars.objects[OBJECT_NUM_PLAYER1]; + struct object_t *obj40 = &g_vars.objects[OBJECT_NUM_PLAYER2]; + g_vars.screen_h = 172; + g_vars.vinyls_count = 0; + if (!g_vars.two_players_flag) { + screen_draw_frame(g_res.spr_frames[123], 12, 320, 0, -12); + screen_draw_frame(g_res.spr_frames[124], 12, 320, 0, 161); + if (g_vars.player == PLAYER_JAKE) { + screen_draw_frame(g_res.spr_frames[115], 12, 16, 24, 161); + } else { + screen_draw_frame(g_res.spr_frames[117], 12, 16, 24, 161); + } + for (int i = 0; i < obj39->data51; ++i) { + screen_draw_frame(g_res.spr_frames[120], 12, 16, 216 + i * 16, 161); + } + screen_draw_number(obj39->vinyls_count, 192, 163, 2); + screen_draw_number(obj39->lifes_count, 64, 163, 2); + for (int i = 0; i < 5; ++i) { + screen_draw_frame(g_res.spr_frames[135 + i], 12, 16, 80 + i * 32, -12); + } + if (obj39->data5F == 0) { + for (int i = 0; i < g_vars.level; ++i) { + screen_draw_frame(g_res.spr_frames[140 + i], 12, 16, 80 + i * 32, -12); + } + } else { + for (int i = 0; i <= g_vars.level; ++i) { + screen_draw_frame(g_res.spr_frames[140 + i], 12, 16, 80 + i * 32, -12); + } + } + } else { + screen_draw_frame(g_res.spr_frames[123], 12, 320, 0, -12); + screen_draw_frame(g_res.spr_frames[124], 12, 320, 0, 161); + screen_draw_frame(g_res.spr_frames[115], 12, 16, 8, 161); + screen_draw_frame(g_res.spr_frames[117], 12, 16, 176, 161); + do_level_update_panel_lifes(obj39); + do_level_update_panel_lifes(obj40); + screen_draw_number(obj39->vinyls_count, 112, 163, 2); + screen_draw_number(obj40->vinyls_count, 280, 163, 2); + screen_draw_number(obj39->lifes_count, 48, 163, 2); + screen_draw_number(obj40->lifes_count, 216, 163, 2); + for (int i = 0; i < 5; ++i) { + screen_draw_frame(g_res.spr_frames[135 + i], 12, 16, 80 + i * 32, -12); + } + if (obj39->data5F == 0) { + for (int i = 0; i < g_vars.level; ++i) { + screen_draw_frame(g_res.spr_frames[140 + i], 12, 16, 80 + i * 32, -12); + } + } else { + for (int i = 0; i <= g_vars.level; ++i) { + screen_draw_frame(g_res.spr_frames[140 + i], 12, 16, 80 + i * 32, -12); + } + } + } + g_vars.screen_h = TILEMAP_SCREEN_H; +} + +void do_level_enter_door(struct object_t *obj) { + static const uint8_t pos[] = { 74, 74, 77, 66, 102 }; + for (int i = 0; i < MAX_DOORS; ++i) { + if (obj->xpos16 == g_vars.doors[i].src_x16 && obj->ypos16 == g_vars.doors[i].src_y16) { + screen_do_transition1(0); + // _draw_last_sprite_flag = 0; + obj->xpos = g_vars.doors[i].dst_x16 << 4; + obj->ypos = g_vars.doors[i].dst_y16 << 4; + if (obj->ypos > g_vars.screen_tilemap_h) { + obj->unk53 = 1; + g_vars.screen_tilemap_yorigin = pos[g_vars.level] << 4; + const int w = TILEMAP_SCREEN_W / 16; + g_vars.screen_tilemap_xorigin = (((obj->xpos >> 4) / w) * w) << 4; + } else { + g_vars.screen_tilemap_xorigin = ((obj->xpos >> 4) - 10) << 4; + g_vars.screen_tilemap_yorigin = ((obj->ypos >> 4) - 6) << 4; + if (g_vars.screen_tilemap_yorigin + (TILEMAP_SCREEN_H + 16) > g_vars.screen_tilemap_h) { + g_vars.screen_tilemap_yorigin = g_vars.screen_tilemap_h - (TILEMAP_SCREEN_H + 16); + } else { + g_vars.screen_tilemap_yorigin += 16; + } + obj->unk53 = 0; + } + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + draw_level_panel(); + do_level_update_panel_vinyls(obj); + if (g_vars.two_players_flag) { + do_level_update_panel_2nd_player(); + } + screen_flip(); + g_vars.screen_draw_offset ^= 0x2000; + do_level_redraw_tilemap(g_vars.screen_tilemap_xorigin, g_vars.screen_tilemap_yorigin); + do_level_update_scrolling2(); + draw_level_panel(); + do_level_update_panel_vinyls(obj); + if (g_vars.two_players_flag) { + do_level_update_panel_2nd_player(); + } + screen_do_transition1(1); + screen_flip(); + g_vars.screen_draw_offset ^= 0x2000; + obj->unk3D = 0; + obj->sprite_type = 0; + obj->yacc = 2; + obj->yvelocity = 0; + } + } +} + +static void do_level_update_input(struct object_t *obj) { + struct object_t *obj37 = &g_vars.objects[37]; + int _si, _di; + + obj->carry_crate_flag = 0; + if (obj->unk56 != 0) { + obj->special_anim = 27; + obj->xmaxvelocity = 112; + switch (obj->unk54) { + case 1: + obj->direction_ud = 2; + break; + case 2: + obj->yacc = obj->yvelocity = -4; + break; + } + switch (obj->unk55) { + case 1: + obj->direction_lr = 1; + break; + case 2: + obj->direction_lr = 2; + break; + } + } + if (obj->special_anim != 0 && obj->special_anim != 22) { + return; + } + obj->xmaxvelocity = 48; + if (obj->unk4D == 0) { + triggers_unk3(obj); + } else { + triggers_unk5(obj); + } + if (g_vars.inp_key_space != 0 && g_vars.inp_key_up != 0 && g_vars.inp_key_up_prev == 0 && !g_vars.player2_scrolling_flag) { + obj->carry_crate_flag = 1; + do_level_enter_door(obj); + g_vars.inp_key_action = g_vars.inp_key_space; + } + if (g_vars.inp_key_space != g_vars.inp_key_action && g_vars.inp_key_up == 0) { + if (g_vars.inp_key_space != 0) { + obj->carry_crate_flag = 1; + } + g_vars.inp_key_action = g_vars.inp_key_space; + } + if (g_vars.inp_key_right != 0) { + obj->direction_lr |= OBJECT_DIRECTION_RIGHT; + } + if (g_vars.inp_key_left != 0) { + obj->direction_lr |= OBJECT_DIRECTION_LEFT; + } + _si = triggers_get_tile_type(obj->xpos16, obj->ypos16); + if (g_vars.inp_key_up != 0 && g_vars.inp_key_space == 0) { + obj->direction_ud = OBJECT_DIRECTION_UP; + if (g_vars.inp_key_up_prev == 0 && obj->sprite_type != 0) { + obj->yfriction = 0; + _di = triggers_get_tile_type(obj->xpos16, obj->ypos16 - 2); + if (_di == 10 && (_si == 0 || _si == 1)) { + if (obj->unk2E == 1 && obj->sprite_type != 4 && obj->blinking_counter == 0) { + if (obj37->type != 100) { + do_level_drop_grabbed_object(obj); + } + obj->special_anim = 18; + play_sound(SOUND_11); + } + } else { + if (obj->grab_state != 0 && obj->grab_type == 0) { + obj->yfriction = 9; + } else { + obj->yfriction = 14; + } + } + } + } else if (g_vars.inp_key_down != 0) { + obj->direction_ud = 2; + if (!g_vars.inp_key_down_prev) { + obj->unk2B = 1; + } + } else { + obj->direction_ud = 0; + } + g_vars.inp_key_up_prev = g_vars.inp_key_up; + g_vars.inp_key_down_prev = g_vars.inp_key_down; + if (obj->grab_state == 0) { + if (obj->carry_crate_flag != 0 && _si == 5) { // crate + obj->grab_type = 0; + obj->grab_state = 0; + do_level_reset_tiles(obj, 0); + g_vars.objects[37].grab_state = 0; + g_vars.objects[37].grab_type = 0; + do_level_update_grabbed_object(obj); + obj->carry_crate_flag = 0; + } else if (_si == 8) { // balloon + obj->grab_state = 0; + obj->grab_type = 2; + do_level_reset_tiles(obj, 0); + do_level_reset_tiles(obj, -1); + g_vars.objects[37].grab_state = 0; + g_vars.objects[37].grab_type = 2; + do_level_update_grabbed_object(obj); + obj->unk3D = 2; + } else if (_si == 9) { // umbrella + obj->grab_type = 8; + obj->grab_state = 0; + do_level_reset_tiles(obj, 0); + do_level_reset_tiles(obj, -1); + g_vars.objects[37].grab_state = 0; + g_vars.objects[37].grab_type = 8; + do_level_update_grabbed_object(obj); + obj->unk3D = 1; + } + } +} + +static void do_level_update_scrolling(struct object_t *obj) { + if (obj->unk53 != 0) { + g_vars.screen_scrolling_dirmask = 0; + return; + } + if (g_vars.screen_unk1) { + if (obj->screen_xpos > (TILEMAP_SCREEN_W - 144)) { + g_vars.screen_scrolling_dirmask |= 2; + } + if (obj->screen_xpos < 144) { + g_vars.screen_scrolling_dirmask |= 1; + } + if ((g_vars.screen_scrolling_dirmask & 2) != 0 && obj->screen_xpos < TILEMAP_SCREEN_W / 2) { + g_vars.screen_scrolling_dirmask &= ~2; + g_vars.screen_unk1 = 0; + g_vars.inp_keyboard[0xC1] = 0; + } + if ((g_vars.screen_scrolling_dirmask & 1) != 0 && obj->screen_xpos > TILEMAP_SCREEN_W / 2) { + g_vars.screen_scrolling_dirmask &= ~1; + g_vars.screen_unk1 = 0; + g_vars.inp_keyboard[0xC1] = 0; + } + } else { + int _si = (obj->xvelocity >> 3) + obj->unk1C; + if (obj->screen_xpos > (TILEMAP_SCREEN_W - 64) && (g_vars.screen_tilemap_w * 16 - TILEMAP_SCREEN_W) > g_vars.screen_tilemap_xorigin) { + g_vars.screen_scrolling_dirmask |= 2; + } + if (obj->screen_xpos < 64 && g_vars.screen_tilemap_xorigin > 0) { + g_vars.screen_scrolling_dirmask |= 1; + } + if ((g_vars.screen_scrolling_dirmask & 2) != 0 && (obj->screen_xpos < 48 || _si <= 0)) { + g_vars.screen_scrolling_dirmask &= ~2; + } + if ((g_vars.screen_scrolling_dirmask & 1) != 0 && (obj->screen_xpos > (TILEMAP_SCREEN_W - 48) || _si >= 0)) { + g_vars.screen_scrolling_dirmask &= ~1; + } + } + if (obj->screen_ypos < 64) { + g_vars.screen_scrolling_dirmask |= 8; + } else if (obj->screen_ypos > 144) { + g_vars.screen_scrolling_dirmask |= 4; + } + if ((g_vars.screen_scrolling_dirmask & 8) != 0 && obj->screen_ypos > 112) { + g_vars.screen_scrolling_dirmask &= ~8; + } else if ((g_vars.screen_scrolling_dirmask & 4) != 0 && obj->screen_ypos < 128) { + g_vars.screen_scrolling_dirmask &= ~4; + } +} + +static void do_level_update_object_bounds(struct object_t *obj) { + int _si = g_vars.objects[OBJECT_NUM_PLAYER1].screen_xpos - obj->screen_xpos; + int _di = g_vars.objects[OBJECT_NUM_PLAYER1].screen_ypos - obj->screen_ypos; + if (g_vars.objects[OBJECT_NUM_PLAYER1].special_anim == 16) { + _si = 320; + _di = 200; + } + if (g_vars.two_players_flag) { + int tmp_dx = g_vars.objects[OBJECT_NUM_PLAYER2].screen_xpos - obj->screen_xpos; + int tmp_dy = g_vars.objects[OBJECT_NUM_PLAYER2].screen_ypos - obj->screen_ypos; + if (g_vars.objects[OBJECT_NUM_PLAYER2].special_anim == 16) { + tmp_dx = 320; + tmp_dy = 200; + } + if (ABS(_si) >= ABS(tmp_dx) && ABS(_di) >= ABS(tmp_dy)) { + obj->player_xdist = tmp_dx; + obj->player_ydist = tmp_dy; + // obj->unk41 = 1; + return; + } + } + obj->player_xdist = _si; + obj->player_ydist = _di; + // obj->unk41 = 0; +} + +void do_level_update_object38(struct object_t *obj) { + struct object_t *obj38 = &g_vars.objects[38]; + if (obj->unk42 == 0) { + if (obj->type == 100) { + obj->special_anim = 2; + obj->unk42 = 1; + } + } else if (obj->unk42 == 1) { + if (obj38->grab_type == 10 || obj->anim_num >= 7) { + obj38->type = 2; + obj->visible_flag = 1; + static const uint8_t data[MAX_OBJECTS] = { + 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 6, 23, 0, 9, 9, 0, 10, 0, + 11, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0 + }; + obj38->grab_type = data[obj->type]; + if (obj->anim_num == 7) { + if (obj38->grab_type == 10) { + play_sound(SOUND_16); + } else { + play_sound(SOUND_4); + } + } + switch (obj38->grab_type) { + case 10: + obj38->xpos = obj->xpos; + obj38->ypos = obj->ypos; + obj38->xvelocity = 0; + break; + case 11: + case 13: + obj38->ypos = obj->ypos - 10; + obj38->xpos = obj->xpos + 32 - (obj->facing_left << 6); + obj38->xvelocity = obj38->yvelocity = 64 - (obj->facing_left << 7); + break; + case 12: + obj38->ypos = obj->ypos - 3; + obj38->xpos = obj->xpos + 16 - (obj->facing_left << 5); + obj38->xvelocity = obj38->yvelocity = 32 - (obj->facing_left << 6); + break; + } + const int num = obj38->type * 116 / 4; + assert(num < 1189); + obj38->animframes_ptr = animframes_059d + num; + obj38->anim_num = 1; + obj38->facing_left = obj->facing_left; + obj->unk42 = 0; + obj38->unk42 = 2; + obj38->unk5D = obj->type; + } + } else if (obj->unk42 == 2) { + if (obj->grab_type == 10) { + obj->yacc = 4; + obj->yvelocity = 4; + if (obj->screen_ypos > 150) { + obj->type = 0; + obj->visible_flag = 0; + obj->grab_type = 0; + obj->unk42 = 0; + obj->unk5D = 0; + } + } else { + obj->direction_lr = obj->facing_left + 1; + obj->xacc = 64; + obj->xmaxvelocity = 400; + obj->yvelocity = 0; + obj->yacc = 0; + if (obj->screen_xpos < 0 || obj->screen_xpos > GAME_SCREEN_W - 10 || obj->xpos < 32) { + obj->type = 100; + obj->visible_flag = 0; + obj->grab_type = 0; + obj->unk42 = 0; + obj->unk5D = 0; + } + } + } +} + +static void do_level_fixup_object_position(struct object_t *obj) { + int num, ret; + + num = triggers_get_tile_type(obj->xpos16, obj->ypos16); + if (obj->grab_state != 0) { + num = 0; + } + switch (num) { + case 2: + case 14: + ret = triggers_get_dy(obj); + obj->ypos = ret + (obj->ypos & ~15); + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + break; + case 3: + case 15: + --obj->ypos16; + ret = triggers_get_dy(obj); + obj->ypos = ret + (obj->ypos & ~15) - 16; + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + break; + } +} + +// gravity +static void do_level_fixup_object_unkA(struct object_t *obj) { + int16_t _si = triggers_get_tile_type(obj->xpos16, obj->ypos16); + if (obj->special_anim == 18) { + _si = 0; + obj->sprite_type = 0; + } + if (_si == 6) { + obj->yfriction = 0; + obj->sprite_type = 3; + if (obj->direction_ud == 1) { + if (triggers_get_tile_type(obj->xpos16, (obj->ypos - 2) >> 4) != 6) { + obj->yvelocity = -1; + } else { + obj->yvelocity = -2; + } + } else if (obj->direction_ud == 2) { + obj->yvelocity = 2; + } else { + obj->yvelocity = 0; + } + } else if (_si == 7) { + if (obj->direction_ud != 0 && obj->unk2E != 0) { + obj->xpos = (obj->xpos + 7) & ~15; + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->xpos16 = obj->xpos >> 4; + } + obj->yfriction = 0; + obj->sprite_type = 2; + if (obj->direction_ud == 1) { + if (triggers_get_tile_type(obj->xpos16, (obj->ypos - 2) >> 4) != 7) { + obj->yvelocity = -1; + } else { + obj->yvelocity = -2; + } + } else if (obj->direction_ud == 2) { + obj->yvelocity = 2; + } + } else { + if (_si == 11 || _si == 12) { + obj->yfriction = 0; + obj->sprite_type = 4; + } + if (obj->yfriction != 0) { + obj->yvelocity -= obj->yfriction; + obj->yfriction = 0; + } else { + obj->yvelocity += obj->yacc; + if (obj->type < 2) { + if (obj->unk3D == 1 && obj->yvelocity > 0) { + obj->yacc = 1; + obj->yvelocity = obj->yacc; + } else if (obj->unk3D == 2) { + obj->yacc = -1; + obj->yvelocity = obj->yacc; + } + } + if (obj->yvelocity > obj->ymaxvelocity) { + obj->yvelocity = obj->ymaxvelocity; + } + } + } +} + +static void do_level_fixup_object_ypos16(struct object_t *obj) { + if (obj->collide_flag == 0) { + if (obj->ypos < 32) { + obj->ypos = 32; + obj->screen_ypos = 32 - g_vars.screen_tilemap_yorigin; + obj->yvelocity = 0; + } else if (obj->ypos > g_vars.screen_tilemap_h && obj->unk53 == 0) { + obj->ypos = g_vars.screen_tilemap_h - 16; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->yvelocity = 0; + } else { + obj->ypos16 = obj->ypos >> 4; + } + } +} + +// collision with bonus +static void do_level_handle_object_bonus_collision(struct object_t *obj, struct object_t *test_obj) { + if (obj->yvelocity < 0) { + return; + } + if (test_obj->xpos + level_obj_w[test_obj->type] <= obj->xpos) { + return; + } + if (test_obj->xpos - level_obj_w[test_obj->type] >= obj->xpos) { + return; + } + if (test_obj->ypos - level_obj_h[test_obj->type] >= obj->ypos) { + return; + } + if (obj->ypos >= test_obj->ypos) { + return; + } + obj->yvelocity = test_obj->yvelocity; + obj->yacc = test_obj->yacc; + obj->unk1E = test_obj->unk1E; + obj->unk1C = test_obj->xvelocity >> 3; + obj->sprite_type = 1; + obj->ypos = test_obj->ypos - level_obj_h[test_obj->type] + 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + if ((obj->direction_ud & 2) != 0 && obj->grab_state == 0) { + obj->unk2E = 0; + } +} + +void do_level_player_hit(struct object_t *obj) { + if (obj->blinking_counter == 0) { + g_vars.screen_h = 172; + if (obj->data51 > 0) { + --obj->data51; + do_level_update_panel_lifes(obj); + } + if (obj->special_anim != 16) { + obj->blinking_counter = 75; + } + g_vars.screen_h = TILEMAP_SCREEN_H; + } +} + +static void do_level_handle_object_collision(struct object_t *obj) { + struct object_t *obj35 = &g_vars.objects[35]; + if (obj->special_anim == 16) { + return; + } + if (obj->type != 0 && g_vars.two_players_flag) { + obj35 = &g_vars.objects[34]; + } + if (obj->type < 2) { + level_obj_h[obj->type] = (obj->unk2E == 0) ? 14 : 26; + } + if (obj->unk2F != 0) { + return; + } + for (int i = 0; i < MAX_OBJECTS; ++i) { + struct object_t *current_obj = &g_vars.objects[i]; + if (!current_obj->visible_flag || current_obj->type == 100) { + continue; + } + if (current_obj->type == obj->type) { + continue; + } + const int current_obj_type = level_obj_type[current_obj->type]; + if (current_obj_type == 0) { + continue; + } + if (current_obj_type == 1) { + do_level_handle_object_bonus_collision(obj, current_obj); + continue; + } + if (current_obj_type == 2) { + if (current_obj->collide_flag != 0 || current_obj->special_anim == 16) { + continue; + } + int x2 = obj->xpos + level_obj_w[obj->type]; + int x1 = current_obj->xpos - level_obj_w[current_obj->type]; + if (x2 < x1) { + continue; + } + int y1 = current_obj->ypos - level_obj_h[current_obj->type]; + if (y1 > obj->ypos) { + continue; + } + x1 = obj->xpos - level_obj_w[obj->type]; + x2 = current_obj->xpos + level_obj_w[current_obj->type]; + if (x1 > x2) { + continue; + } + int y2 = obj->ypos - level_obj_h[obj->type]; + if (y2 > current_obj->ypos) { + continue; + } + if (obj->type == 0 || obj->type == 1) { + if (obj->blinking_counter == 0 && current_obj->type > 2 && obj->special_anim != 18 && !(g_options.cheats & CHEATS_NO_HIT)) { + if (obj->grab_state != 0) { + do_level_drop_grabbed_object(obj); + } + if (obj->sprite_type != 4) { + obj->special_anim = 18; + } + do_level_player_hit(obj); + play_sound(SOUND_11); + } + } else if (obj->type == 2) { + if (current_obj->type < 2) { + if (current_obj->blinking_counter == 0 && obj->unk5D > 1 && current_obj->special_anim != 18 && !(g_options.cheats & CHEATS_NO_HIT)) { + if (current_obj->grab_state != 0) { + do_level_drop_grabbed_object(current_obj); + } + if (current_obj->sprite_type != 4) { + current_obj->special_anim = 18; + } + do_level_player_hit(current_obj); + play_sound(SOUND_11); + } + } else if (current_obj->type > 2) { + if ((g_vars.objects[OBJECT_NUM_PLAYER1].grab_state == 0 && obj->unk5D == 0) || (g_vars.objects[OBJECT_NUM_PLAYER2].grab_state == 0 && obj->unk5D == 1)) { + if (obj35->type == 100) { + current_obj->collide_flag = 1; + current_obj->xmaxvelocity = 60; + if (obj->facing_left) { + current_obj->xvelocity = -60; + current_obj->data51 = 1; + } else { + current_obj->xvelocity = 60; + current_obj->data51 = 2; + } + current_obj->facing_left ^= 1; + if (current_obj->yvelocity >= 0) { + current_obj->yfriction = 12; + } + obj->type = 100; + obj->visible_flag = 0; + play_sound(SOUND_11); + } + } + } + } + } + } +} + +static void do_level_handle_object_unk59(struct object_t *obj) { + if (obj->collide_flag == 0) { + if (obj->type != 2) { + if (obj->sprite_type == 0) { + if (obj->yvelocity < 0) { + level_call_trigger_func(obj, -2); + } else { + level_call_trigger_func(obj, 0); + } + } else { + if (obj->yvelocity < 0) { + level_call_trigger_func(obj, -2); + } else { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16) != 7) { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16) != 6) { + level_call_trigger_func(obj, 0); + } + } + } + } + } + if (obj->type < 3) { + do_level_handle_object_collision(obj); + } + } +} + +static void do_level_fixup_object_unk8(struct object_t *obj) { + if (obj->direction_lr & OBJECT_DIRECTION_RIGHT) { + obj->facing_left = 0; + if (obj->xvelocity < obj->xmaxvelocity) { + obj->xacc = obj->unk2D; + } else { + obj->xacc = 0; + } + } else if (obj->direction_lr & OBJECT_DIRECTION_LEFT) { + obj->facing_left = 1; + if (obj->xvelocity > -obj->xmaxvelocity) { + obj->xacc = -obj->unk2D; + } else { + obj->xacc = 0; + } + } else { + if (obj->xvelocity < 0) { + obj->xacc = obj->unk2D; + if (obj->xvelocity > -obj->xacc) { + obj->xacc = -obj->xvelocity; + } + } else if (obj->xvelocity > 0) { + obj->xacc = -obj->unk2D; + if (obj->xvelocity < -obj->xacc) { + obj->xacc = -obj->xvelocity; + } + } else { + obj->xacc = 0; + } + } + obj->xvelocity += obj->xacc + obj->unk2F; + if (obj->xvelocity > obj->xmaxvelocity) { + obj->xvelocity = obj->xmaxvelocity; + } + if (obj->xvelocity < -obj->xmaxvelocity) { + obj->xvelocity = -obj->xmaxvelocity; + } +} + +static void do_level_fixup_object_xpos16(struct object_t *obj) { + int _ax, _si; + + _ax = obj->xvelocity + (obj->unk1C << 3); + if (_ax >= 0) { + _si = (obj->xvelocity >> 3) + obj->unk1C; + obj->tile012_xpos = (obj->xpos + _si + 8) >> 4; + obj->tile0_flags = triggers_get_next_tile_flags(obj->tile012_xpos, obj->ypos16); + obj->tile1_flags = triggers_get_next_tile_flags(obj->tile012_xpos, obj->ypos16 - 1); + obj->tile2_flags = triggers_get_next_tile_flags(obj->tile012_xpos, obj->ypos16 - 2); + if (obj->type != 2) { + if ((obj->tile0_flags & 1) != 0) { + obj->moving_direction ^= 1; + if (obj->sprite_type == 2) { + obj->direction_ud = 1; + } + if (obj->xvelocity > 0) { + obj->xvelocity = 0; + } + _si = 0; + } else if (obj->unk2E == 1 && (obj->tile1_flags & 1) != 0) { + obj->moving_direction ^= 1; + if (obj->xvelocity > 0) { + obj->xvelocity = 0; + } + _si = 0; + } else if (obj->unk2E == 2 && (obj->tile2_flags & 1) != 0) { + if (obj->xvelocity > 0) { + obj->xvelocity = 0; + } + _si = 0; + } + } + if (obj->xpos < g_vars.screen_tilemap_w * 16 - 16) { + obj->xpos += _si; + obj->screen_xpos += _si; + obj->xpos16 = obj->xpos >> 4; + } + } else { + if (obj->xvelocity < -8) { + _si = (obj->xvelocity >> 3) + obj->unk1C; + } else { + _si = obj->unk1C; + } + obj->tile012_xpos = (obj->xpos + _si - 8) >> 4; + obj->tile0_flags = triggers_get_next_tile_flags(obj->tile012_xpos, obj->ypos16); + obj->tile1_flags = triggers_get_next_tile_flags(obj->tile012_xpos, obj->ypos16 - 1); + obj->tile2_flags = triggers_get_next_tile_flags(obj->tile012_xpos, obj->ypos16 - 2); + if (obj->type != 2) { + if ((obj->tile0_flags & 2) != 0) { + obj->moving_direction ^= 1; + if (obj->sprite_type == 2) { + obj->direction_ud = 1; + } + if (obj->xvelocity < 0) { + obj->xvelocity = 0; + } + _si = 0; + } else if (obj->unk2E == 1 && (obj->tile1_flags & 2) != 0) { + obj->moving_direction ^= 1; + if (obj->xvelocity < 0) { + obj->xvelocity = 0; + } + _si = 0; + } else if (obj->unk2E == 2 && (obj->tile2_flags & 2) != 0) { + if (obj->xvelocity < 0) { + obj->xvelocity = 0; + } + _si = 0; + } + } + if (obj->xpos > 16) { + obj->xpos += _si; + obj->screen_xpos += _si; + obj->xpos16 = obj->xpos >> 4; + } + } +} + +static void do_level_update_object_unk2E(struct object_t *obj) { + if (obj->direction_ud & 2) { + if (obj->grab_state == 0) { + if (triggers_get_tile_data(obj) != 0) { + obj->unk2E = 0; + } + } + } else { + if (obj->tile1_flags == 0 && obj->unk2E == 0) { + obj->unk2E = 1; + } + } + const int num = triggers_get_tile_type(obj->xpos16, obj->ypos16); + if (num == 11 || num == 12) { + obj->unk2E = 0; + } +} + +static void do_level_update_objects() { + const int bounding_box_x1 = g_vars.screen_tilemap_xorigin - 140; + const int bounding_box_x2 = g_vars.screen_tilemap_xorigin + TILEMAP_SCREEN_W + 140; + const int bounding_box_y1 = g_vars.screen_tilemap_yorigin - 100; + const int bounding_box_y2 = g_vars.screen_tilemap_yorigin + TILEMAP_SCREEN_H + 190; + for (int i = 0; i < MAX_OBJECTS; ++i) { + struct object_t *obj = &g_vars.objects[i]; + print_debug(DBG_GAME, "update_objects #%d type %d pos %d,%d", i, obj->type, obj->xpos, obj->ypos); + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->unk2B = 0; + obj->direction_lr = 0; + obj->direction_ud = 0; + if (obj->type < 2) { + if (g_vars.inp_keyboard[0xC1] != 0) { // F7 + } + if (obj->blinking_counter != 0) { + --obj->blinking_counter; + } + obj->yacc = 2; + if (i == OBJECT_NUM_PLAYER1) { + if (!g_vars.player2_dead_flag) { + do_level_update_input(obj); + do_level_update_object_unk2E(obj); + do_level_update_panel_vinyls(obj); + } + if (!g_vars.player2_scrolling_flag) { + do_level_update_scrolling(obj); + } + if (obj->data5F != 0 && !g_vars.found_music_instrument_flag) { + // found music instrument + if (g_vars.level < (MAX_LEVELS - 1)) { + static const uint8_t data[] = { 94, 81, 96, 26, 26, 3, 89, 52, 15, 96, 51, 20, 72, 27, 5 }; + const uint8_t *p = data + g_vars.level * 3; + do_level_update_tile(p[0], p[1], p[2]); + } + g_vars.found_music_instrument_flag = 1; + } + } else if (g_vars.two_players_flag) { + if (!g_vars.player1_dead_flag) { + // sub_176D7(obj); + do_level_update_object_unk2E(obj); + do_level_update_panel_2nd_player(); + } + if (g_vars.player2_scrolling_flag) { + do_level_update_scrolling(obj); + } + } + } else if (obj->type > 2 && obj->collide_flag == 0) { + const int x = g_vars.level_xpos[i]; // _si + const int y = g_vars.level_ypos[i]; // _di + if (obj->type == 32) { + obj->unk5D = i; + } + if (x > bounding_box_x1 && x < bounding_box_x2 && y > bounding_box_y1 && y < bounding_box_y2) { + obj->visible_flag = 1; + level_call_object_func(obj); + } else { + obj->visible_flag = 0; + if (obj->type == 22 || obj->type == 35) { + obj->xpos = x; + obj->ypos = y; + } + } + } + if (obj->visible_flag != 0) { + do_level_update_object_bounds(obj); + if (obj->unk42 != 0) { + do_level_update_object38(obj); + } + obj->unk2D = 10; + obj->unk1C = 0; + if (obj->sprite_type != 6) { + obj->sprite_type = 0; + } + do_level_fixup_object_position(obj); + do_level_fixup_object_unkA(obj); + obj->ypos += obj->yvelocity; + obj->screen_ypos += obj->yvelocity; + do_level_fixup_object_ypos16(obj); + do_level_handle_object_unk59(obj); + do_level_fixup_object_unk8(obj); + do_level_fixup_object_xpos16(obj); + if (obj->grab_state != 0) { + do_level_update_grabbed_object(obj); + } + if (obj->collide_flag != 0) { + if (obj->screen_ypos > 200) { + obj->visible_flag = 0; + } + obj->xmaxvelocity = 60; + if (obj->data51 == 1) { + obj->xvelocity = -60; + } else { + obj->xvelocity = 60; + } + obj->facing_left ^= 1; + obj->special_anim = 1; + } + obj->floor_ypos16 = obj->ypos16; + if (obj->type != 2) { + if (obj->special_anim != 0) { + do_level_add_sprite3(obj); + } else { + do_level_add_sprite1(obj); + } + } else { + do_level_add_sprite2(obj); + } + } + } + if (g_vars.triggers_counter != 0) { + if (g_vars.triggers_counter < 10) { + screen_draw_frame(g_res.spr_frames[140 + g_vars.level], 12, 16, g_vars.level * 32 + 80, -12); + g_vars.screen_draw_offset = 0x2000; + screen_draw_frame(g_res.spr_frames[140 + g_vars.level], 12, 16, g_vars.level * 32 + 80, -12); + g_vars.screen_draw_offset ^= 0x2000; + ++g_vars.triggers_counter; + } else { + screen_draw_frame(g_res.spr_frames[145], 12, 16, g_vars.level * 32 + 80, -12); + g_vars.screen_draw_offset = 0x2000; + screen_draw_frame(g_res.spr_frames[145], 12, 16, g_vars.level * 32 + 80, -12); + g_vars.screen_draw_offset ^= 0x2000; + ++g_vars.triggers_counter; + if (g_vars.triggers_counter > 20) { + g_vars.triggers_counter = 1; + } + } + } + if (!g_vars.two_players_flag && g_vars.objects[OBJECT_NUM_PLAYER1].flag_end_level != 0) { + g_vars.level_completed_flag = 1; + } else { + if (g_vars.objects[OBJECT_NUM_PLAYER1].flag_end_level != 0 && g_vars.objects[OBJECT_NUM_PLAYER2].flag_end_level != 0) { + g_vars.level_completed_flag = 1; + } + if (g_vars.objects[OBJECT_NUM_PLAYER1].flag_end_level != 0 && g_vars.player1_dead_flag) { + g_vars.level_completed_flag = 1; + } + if (g_vars.objects[OBJECT_NUM_PLAYER2].flag_end_level != 0 && g_vars.player2_dead_flag) { + g_vars.level_completed_flag = 1; + } + } + if (g_vars.level_completed_flag) { + ++g_vars.update_objects_counter; + if (g_vars.update_objects_counter > 50) { + // _draw_last_sprite_flag = 0; + if (g_vars.level < (MAX_LEVELS - 1)) { + ++g_vars.level; + } else { + g_vars.level = 0; + g_vars.play_level_flag = 0; + g_vars.level_completed_flag = 0; + } + g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].unk60 = 0; + g_vars.objects[OBJECT_NUM_PLAYER1].data5F = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].data5F = 0; + g_vars.objects[OBJECT_NUM_PLAYER1].flag_end_level = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].flag_end_level = 0; + g_vars.screen_draw_offset -= TILEMAP_OFFSET_Y * 40; + screen_unk5(); + g_vars.screen_draw_offset += TILEMAP_OFFSET_Y * 40; + g_vars.quit_level_flag = 1; + } + } else if (g_vars.game_over_flag) { + g_vars.screen_scrolling_dirmask = 0; + if ((!g_vars.two_players_flag && g_vars.objects[OBJECT_NUM_PLAYER1].lifes_count == 1) || (g_vars.player2_dead_flag && g_vars.player1_dead_flag)) { + screen_draw_frame(g_res.spr_frames[127], 34, 160, 80, 63); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[127], 34, 160, 80, 63); + g_vars.screen_draw_offset ^= 0x2000; + g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].unk60 = 0; + g_vars.objects[OBJECT_NUM_PLAYER1].data5F = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].data5F = 0; + g_vars.objects[OBJECT_NUM_PLAYER1].unk63 = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].unk63 = 0; + g_vars.objects[OBJECT_NUM_PLAYER1].flag_end_level = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].flag_end_level = 0; + screen_vsync(); + } + if (g_vars.objects[35].screen_ypos > 90) { + g_vars.objects[35].screen_ypos = 90; + g_vars.objects[35].ypos = g_vars.screen_tilemap_yorigin + 90; + } + ++g_vars.update_objects_counter; + if (g_vars.objects[OBJECT_NUM_PLAYER1].yvelocity == 0) { + g_vars.objects[OBJECT_NUM_PLAYER1].special_anim = 21; + } else { + g_vars.objects[OBJECT_NUM_PLAYER1].special_anim = 2; + } + if (g_vars.update_objects_counter > 70) { + if (!g_vars.two_players_flag && g_vars.objects[OBJECT_NUM_PLAYER1].lifes_count == 1) { + g_vars.play_level_flag = 0; + } + // _draw_last_sprite_flag = 0; + g_vars.screen_draw_offset -= TILEMAP_OFFSET_Y * 40; + screen_unk5(); + g_vars.screen_draw_offset += TILEMAP_OFFSET_Y * 40; + g_vars.quit_level_flag = 1; + } + } +} + +static void draw_foreground_tiles() { + int x = g_vars.screen_tilemap_xorigin >> 4; + int y = g_vars.screen_tilemap_yorigin >> 4; + for (int j = 0; j < (TILEMAP_SCREEN_H / 16); ++j) { + const uint8_t *ptr = lookup_sql(x, y); + for (int i = 0; i < (TILEMAP_SCREEN_W / 16); ++i) { + uint8_t num = *ptr++; + const uint8_t *data = g_res.triggers[num].op_table2; + if (data) { + const int current = data[0]; + num = data[current + 1]; + } + const int avt_num = g_res.triggers[num].foreground_tile_num; + if (avt_num != 255) { + const int tile_y = j * 16 + 14; + const int tile_x = i * 16; + decode_ega_spr(g_res.avt[avt_num], 16, 16, 16, g_res.vga, GAME_SCREEN_W, tile_x, tile_y, 0); + } + } + ++y; + } +} + +void do_level() { + const int w = TILEMAP_SCREEN_W / 16; + for (int i = 0; i < 256; ++i) { + g_vars.screen_tile_lut[i] = (i / w) * 640 + (i % w); + } + g_vars.screen_tilemap_w = level_dim[g_vars.level * 2]; + g_vars.screen_tilemap_h = level_dim[g_vars.level * 2 + 1]; + g_vars.screen_tilemap_w16 = g_vars.screen_tilemap_w; + g_vars.screen_tilemap_h16 = g_vars.screen_tilemap_h >> 4; + for (int i = 0; i < MAX_TRIGGERS; ++i) { + g_res.triggers[i].unk16 = i; + } + g_vars.screen_unk1 = 0; + init_level(); + screen_clear(0); + do_level_redraw_tilemap(g_vars.screen_tilemap_xorigin, g_vars.screen_tilemap_yorigin); + if (g_options.amiga_copper_bars) { + g_sys.set_copper_bars(_copper_data + g_vars.level * 18); + } + if (g_options.amiga_colors) { + uint16_t palette[32]; + memcpy(palette, _colors_data + g_vars.level * 16, 16 * sizeof(uint16_t)); + for (int i = 0; i < 16; ++i) { + assert(_colors2_data[i * 2] == 0x1a0 + i * 2); + palette[16 + i] = _colors2_data[i * 2 + 1]; + } + g_sys.set_palette_amiga(palette); + } + // _time_sync_ptr[1] = 1: + g_vars.inp_keyboard[0xB9] = 0; // SPACE + g_vars.screen_draw_offset = TILEMAP_OFFSET_Y * 40; + g_vars.update_objects_counter = 0; + g_vars.game_over_flag = 0; + g_vars.level_completed_flag = 0; + g_vars.quit_level_flag = 0; + // _screen_panel_drawn_flag = 0; + g_vars.player2_scrolling_flag = 0; + g_vars.screen_h = TILEMAP_SCREEN_H; + // _draw_last_sprite_flag = 0; + g_vars.found_music_instrument_flag = 0; + do { + update_input(); + if (g_vars.inp_keyboard[0xBF] != 0) { // F5 + play_sound(SOUND_0); + g_vars.inp_keyboard[0xBF] = 0; + g_vars.quit_level_flag = 1; + g_vars.play_level_flag = 0; + g_vars.objects[OBJECT_NUM_PLAYER1].unk60 = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].unk60 = 0; + g_vars.objects[OBJECT_NUM_PLAYER1].data5F = 0; + g_vars.objects[OBJECT_NUM_PLAYER2].data5F = 0; + if (!g_vars.play_demo_flag) { + g_vars.start_level = 0; + } + } else if (g_vars.inp_keyboard[0xC4] != 0) { // F10 + play_sound(SOUND_0); + while (g_vars.inp_keyboard[0xC4] != 0 && g_vars.inp_keyboard[0xB] == 0); + while (g_vars.inp_keyboard[0xC4] != 0 && g_vars.inp_keyboard[0xB] != 0); + } + // demo + do_level_update_scrolling2(); + do_level_update_objects(); + if (1) { // if (_draw_last_sprite_flag != 0) { + screen_clear_last_sprite(); + screen_redraw_sprites(); + draw_foreground_tiles(); + } + // if (_timer_counter != _timer_sync) { + // _timer_sync = _timer_counter; + // word_21DC7 = _timer_counter2; + // _timer_counter2 = 0; + // } + // ++_timer_counter2; + ++g_vars.timer_counter3; + if (1) { // (!_screen_panel_drawn_flag) { + draw_level_panel(); + screen_unk6(); + // _screen_panel_drawn_flag = 1; + } else { + screen_flip(); + g_vars.screen_draw_offset ^= 0x2000; + } + // while (_timer_sync_ptr[1] < 3); + screen_clear_sprites(); + // _draw_last_sprite_flag = 1; + // _timer_sync_ptr[1] = 0; + + } while (g_sys.input.quit == 0 && !g_vars.quit_level_flag); + g_vars.screen_draw_offset -= TILEMAP_OFFSET_Y * 40; + screen_unk5(); + g_vars.screen_draw_offset += TILEMAP_OFFSET_Y * 40; + if (g_options.amiga_copper_bars) { + g_sys.set_copper_bars(0); + } + g_vars.inp_keyboard[0xBF] = 0; +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..e0570bf --- /dev/null +++ b/main.c @@ -0,0 +1,81 @@ + +#include +#include + +#include "fileio.h" +#include "game.h" +#include "resource.h" +#include "sys.h" +#include "util.h" + +struct options_t g_options; + +static const char *DEFAULT_DATA_PATH = "."; + +static const char *USAGE = + "Usage: %s [OPTIONS]...\n" + " --datapath=PATH Path to data files (default '.')\n" + " --level=NUM Start at level NUM\n" +; + +int main(int argc, char *argv[]) { + g_options.start_xpos16 = -1; + g_options.start_ypos16 = -1; + g_options.amiga_copper_bars = true; + g_options.amiga_colors = true; + const char *data_path = DEFAULT_DATA_PATH; + if (argc == 2) { + struct stat st; + if (stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode)) { + data_path = strdup(argv[1]); + } + } + while (1) { + static struct option options[] = { + { "datapath", required_argument, 0, 1 }, + { "level", required_argument, 0, 2 }, + { "debug", required_argument, 0, 3 }, + { "cheats", required_argument, 0, 4 }, + { "startpos", required_argument, 0, 5 }, + { 0, 0, 0, 0 }, + }; + int index; + const int c = getopt_long(argc, argv, "", options, &index); + if (c == -1) { + break; + } + switch (c) { + case 1: + data_path = strdup(optarg); + break; + case 2: + g_options.start_level = atoi(optarg); + break; + case 3: + g_debug_mask = atoi(optarg); + break; + case 4: + g_options.cheats = atoi(optarg); + break; + case 5: + sscanf(optarg, "%dx%d", &g_options.start_xpos16, &g_options.start_ypos16); + break; + default: + fprintf(stdout, USAGE, argv[0]); + return -1; + } + } + fio_init(data_path); + res_init(); + g_sys.init(); + sound_init(SYS_AUDIO_FREQ); + game_main(); + sound_fini(); + g_sys.fini(); + res_fini(); + fio_fini(); + if (data_path != DEFAULT_DATA_PATH) { + free((char *)data_path); + } + return 0; +} diff --git a/opcodes.c b/opcodes.c new file mode 100644 index 0000000..8691cd6 --- /dev/null +++ b/opcodes.c @@ -0,0 +1,477 @@ + +/* objects update and logic */ + +#include "game.h" +#include "util.h" + +static void object_func_op0(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 40; + obj->special_anim = 1; +} + +static void object_func_op1(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + obj->xvelocity = 0; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 40; + if (obj->player_ydist <= 10 && obj->player_xdist > -26 && obj->player_xdist < 26) { + if (g_vars.objects[OBJECT_NUM_PLAYER1].special_anim != 18 && g_vars.objects[OBJECT_NUM_PLAYER2].special_anim != 18) { + if (obj->player_ydist > -20) { + obj->special_anim = 2; + obj->direction_lr = 0; + } else { + obj->special_anim = 1; + } + if (obj->player_ydist < -50) { + if (obj->player_xdist < 0) { + obj->moving_direction = 1; + obj->facing_left = 1; + } else { + obj->moving_direction = 0; + obj->facing_left = 0; + } + } + } + } else if (obj->player_ydist < 0 && obj->player_ydist > -50 && obj->player_xdist > -60 && obj->player_xdist < 60) { + obj->special_anim = 1; + } +} + +// police +static void object_func_op2(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 40; + if (obj->anim_num == 12 && obj->special_anim == 2) { + obj->special_anim = 3; + obj->anim_num = 1; + } else if (obj->anim_num == 12 && obj->special_anim == 3) { + obj->special_anim = 0; + } + if (obj->player_ydist <= 0 && obj->player_xdist > -(TILEMAP_SCREEN_W / 4) && obj->player_xdist < (TILEMAP_SCREEN_W / 4) && obj->direction_ud > 196) { + if (obj->special_anim == 0 || obj->anim_num == 12) { + obj->anim_num = 1; + obj->unk42 = 0; + do_level_update_object38(obj); + } + obj->facing_left = (obj->player_xdist < 0) ? 1 : 0; + } + if (obj->special_anim != 0) { + obj->direction_lr = 0; + } +} + +static void object_func_op3(struct object_t *obj) { + if (obj->player_ydist <= 20 && obj->player_ydist > -(TILEMAP_SCREEN_W / 2) && obj->player_xdist < (TILEMAP_SCREEN_W / 2) && g_vars.objects[38].type == 100) { + if (obj->direction_ud > 226) { + if (obj->special_anim == 0 || obj->anim_num == 16) { + do_level_update_object38(obj); + } + obj->facing_left = (obj->player_xdist < 0) ? 1 : 0; + } + } else { + if (obj->anim_num == 16) { + obj->special_anim = 0; + } + } + if (obj->special_anim != 0) { + obj->direction_lr = 0; + } +} + +// elevator +static void object_func_op4(struct object_t *obj) { + obj->unk2B = 0; + obj->unk1E = 0; + obj->yacc = 0; + if (obj->elevator_direction == 1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + } else { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 + 1) == 10) { + obj->elevator_direction = -1; + obj->moving_direction = 1; + } + obj->yvelocity = 2; + obj->special_anim = 2; + } + } + if (obj->elevator_direction == -1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + } else { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 - 4) == 10) { + obj->elevator_direction = 1; + obj->moving_direction = 1; + } + obj->yvelocity = -2; + obj->special_anim = 2; + } + } +} + +static void object_func_op5(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 4 - obj->facing_left * 8, obj->ypos16) == 12) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + switch (obj->data5F) { + case 0: + obj->direction_lr |= 2; + obj->yvelocity = obj->data51 >> 3; + break; + case 1: + obj->direction_lr |= 1; + obj->yvelocity = (20 - obj->data51) >> 3; + break; + case 2: + obj->direction_lr |= 1; + obj->yvelocity = -(obj->data51 >> 3); + break; + case 3: + obj->direction_lr |= 2; + obj->yvelocity = (obj->data51 - 20) >> 3; + break; + } + if (obj->data51 > 20) { + obj->data51 = 0; + obj->data5F = (obj->data5F + 1) & 3; + } + obj->yacc = obj->yvelocity; + obj->special_anim = 1; + obj->xmaxvelocity = 32; +} + +static void object_func_op8(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 48; + obj->yacc = 0; + obj->yvelocity = 0; + if (obj->player_ydist <= 100 && obj->player_xdist > -90 && obj->player_xdist < 90 && obj->direction_ud > 196 && obj->special_anim == 0) { + obj->anim_num = 1; + obj->unk42 = 1; + do_level_update_object38(obj); + } +} + +static void object_func_op10(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 32; + if (obj->player_ydist <= 10 && obj->player_xdist > -(TILEMAP_SCREEN_W / 2) && obj->player_xdist < (TILEMAP_SCREEN_W / 2) && g_vars.objects[38].type == 100) { + if (obj->direction_ud > 226) { + if (obj->special_anim == 0 || obj->anim_num == 16) { + obj->anim_num = 1; + obj->unk42 = 0; + do_level_update_object38(obj); + } + obj->facing_left = (obj->player_xdist < 0) ? 1 : 0; + } + } else if (obj->anim_num == 16) { + obj->special_anim = 0; + } + if (obj->special_anim != 0) { + obj->direction_lr = 0; + } +} + +static void object_func_op11(struct object_t *obj) { + extern uint8_t level_tiledata_1dbf[]; + extern uint8_t level_tiledata_1dc7[]; + // extern uint8_t level_tiledata_1dc0[]; + // extern uint8_t level_tiledata_1dc8[]; + obj->unk2B = 0; + obj->unk1E = 0; + obj->yacc = 0; + if (obj->elevator_direction == 1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + level_tiledata_1dbf[0] = 1; + level_tiledata_1dc7[0] = 1; + // level_tiledata_1dc0[0] = 1; + // level_tiledata_1dc8[0] = 1; + } else { + // level_tiledata_1dc0[0] = 6; + // level_tiledata_1dc8[0] = 6; + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 + 2) == 10) { + obj->elevator_direction = -1; + obj->moving_direction = 1; + } + obj->yvelocity = 4; + obj->special_anim = 2; + if (((obj->ypos - 8) & 15) == 0) { + do_level_update_tile(obj->xpos16, obj->ypos16 - 1, triggers_get_next_tile_num(obj->xpos16, obj->ypos16 - 2)); + do_level_update_tile(obj->xpos16 - 1, obj->ypos16 - 1, triggers_get_next_tile_num(obj->xpos16 - 1, obj->ypos16 - 2)); + } + } + } + if (obj->elevator_direction == -1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + level_tiledata_1dbf[0] = 1; + level_tiledata_1dc7[0] = 1; + // level_tiledata_1dc0[0] = 1; + // level_tiledata_1dc8[0] = 1; + } else { + // level_tiledata_1dc0[0] = 6; + // level_tiledata_1dc8[0] = 6; + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 - 4) == 10) { + obj->elevator_direction = 1; + obj->moving_direction = 1; + } + obj->yvelocity = -2; + obj->special_anim = 2; + if (((obj->ypos - 8) & 15) == 0) { + do_level_update_tile(obj->xpos16, obj->ypos16 - 1, triggers_get_next_tile_num(obj->xpos16 + 1, obj->ypos16 - 1)); + do_level_update_tile(obj->xpos16 - 1, obj->ypos16 - 1, triggers_get_next_tile_num(obj->xpos16 + 2, obj->ypos16 - 1)); + } + } + } +} + +static void object_func_op12(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 64; + if (obj->sprite_type != 0) { + obj->yfriction = 8; + } + obj->special_anim = 1; +} + +static void object_func_op13(struct object_t *obj) { + obj->direction_lr = 0; + obj->xmaxvelocity = 0; + obj->special_anim = 1; +} + +static void object_func_op14(struct object_t *obj) { + obj->special_anim = 2; + // sub_1AD3B(obj->xpos, level_ypos_egou[obj->unk5D] - _screen_tilemap_yorigin, obj->xpos, obj->ypos - 5, 3); + if (obj->elevator_direction == 1) { + if (obj->moving_direction < 25) { + ++obj->moving_direction; + obj->yvelocity = 0; + } else if (triggers_get_tile_type(obj->xpos16, obj->ypos16 + 1) != 0) { + obj->elevator_direction = -1; + obj->moving_direction = 1; + obj->yacc = 0; + obj->yvelocity = 0; + } else { + obj->moving_direction = 1; + obj->yacc = 2; + obj->yvelocity = 2; + } + } + if (obj->elevator_direction == -1) { + if (obj->moving_direction < 10) { + ++obj->moving_direction; + obj->yvelocity = 0; + } else if (obj->ypos <= level_ypos_egou[obj->unk5D]) { + obj->elevator_direction = 1; + obj->moving_direction = 1; + obj->yacc = 0; + obj->yvelocity = 0; + } else { + obj->moving_direction = 1; + obj->yacc = -2; + obj->yvelocity = -2; + } + } +} + +static void object_func_op15(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 4 - obj->facing_left * 8, obj->ypos16) == 12) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->yacc = obj->yvelocity; + obj->special_anim = 1; + obj->xmaxvelocity = 32; +} + +static void object_func_op16(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 64; + obj->special_anim = 1; + if (obj->tile0_flags != 0 && obj->sprite_type != 0) { + obj->yfriction = 6; + } +} + +static void object_func_op17(struct object_t *obj) { + obj->unk2B = 0; + obj->unk1E = 0; + obj->yacc = 0; + if (obj->elevator_direction == 1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + } else { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 + 1) == 1) { + obj->elevator_direction = -1; + obj->moving_direction = 1; + } + obj->yvelocity = 2; + obj->special_anim = 2; + if (((obj->ypos - 12) & 15) == 0) { + do_level_update_tile(obj->xpos16, obj->ypos16, triggers_get_next_tile_num(obj->xpos16, obj->ypos16 - 2)); + do_level_update_tile(obj->xpos16 - 1, obj->ypos16, triggers_get_next_tile_num(obj->xpos16 - 1, obj->ypos16 - 2)); + } + } + } + if (obj->elevator_direction == -1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + } else { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 - 3) == 1) { + obj->elevator_direction = 1; + obj->moving_direction = 1; + } + obj->yvelocity = -2; + obj->special_anim = 2; + if ((obj->ypos & 15) == 0) { + do_level_update_tile(obj->xpos16, obj->ypos16 - 1, triggers_get_next_tile_num(obj->xpos16, obj->ypos16)); + do_level_update_tile(obj->xpos16 - 1, obj->ypos16 - 1, triggers_get_next_tile_num(obj->xpos16 - 1, obj->ypos16)); + } + } + } +} + +static void object_func_op18(struct object_t *obj) { + if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 1) { + obj->moving_direction ^= 1; + } + obj->direction_lr = obj->moving_direction + 1; + obj->xmaxvelocity = 40; + obj->special_anim = 1; + if (obj->sprite_type != 0) { + obj->yfriction = 2; + } +} + +static void object_func_op19(struct object_t *obj) { + obj->unk2B = 0; + obj->unk1E = 0; + obj->yacc = 0; + if (obj->elevator_direction == 1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + } else { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 + 1) != 0) { + obj->elevator_direction = -1; + obj->moving_direction = 1; + } + obj->yvelocity = 2; + obj->special_anim = 2; + } + } + if (obj->elevator_direction == -1) { + if (obj->moving_direction < 40) { + ++obj->moving_direction; + obj->yvelocity = 0; + obj->special_anim = 1; + } else { + if (triggers_get_tile_type(obj->xpos16, obj->ypos16 - 5) != 0) { + obj->elevator_direction = 1; + obj->moving_direction = 1; + } + obj->yvelocity = -2; + obj->special_anim = 2; + } + } +} + +void level_call_object_func(struct object_t *obj) { + if (obj->collide_flag == 0) { + switch (obj->op - 1) { + case 0: + object_func_op0(obj); + break; + case 1: + case 9: + object_func_op1(obj); + break; + case 2: + object_func_op2(obj); + break; + case 3: + object_func_op3(obj); + break; + case 4: + object_func_op4(obj); + break; + case 5: + object_func_op5(obj); + break; + case 8: + object_func_op8(obj); + break; + case 10: + object_func_op10(obj); + break; + case 11: + object_func_op11(obj); + break; + case 12: + object_func_op12(obj); + break; + case 13: + object_func_op13(obj); + break; + case 14: + object_func_op14(obj); + break; + case 15: + object_func_op15(obj); + break; + case 16: + object_func_op16(obj); + break; + case 17: + object_func_op17(obj); + break; + case 18: + object_func_op18(obj); + break; + case 19: + object_func_op19(obj); + break; + default: + // print_warning("level_call_object_func: unimplemented opcode %d", obj->op - 1); + obj->special_anim = 1; + break; + } + } +} diff --git a/resource.c b/resource.c new file mode 100644 index 0000000..b27060e --- /dev/null +++ b/resource.c @@ -0,0 +1,279 @@ + +#include "fileio.h" +#include "resource.h" +#include "sys.h" +#include "unpack.h" +#include "util.h" + +struct resource_data_t g_res; + +void res_init() { + static const int SQL_SIZE = 1000 * 16; + g_res.sql = (uint8_t *)malloc(SQL_SIZE); + if (!g_res.sql) { + print_error("Failed to allocate sql buffer, %d bytes", SQL_SIZE); + } + static const int SPR_SQV_SIZE = 64000; + g_res.spr_sqv = (uint8_t *)malloc(SPR_SQV_SIZE); + if (!g_res.spr_sqv) { + print_error("Failed to allocate sprite buffer, %d bytes", SPR_SQV_SIZE); + } + static const int AVT_SQV_SIZE = 437 * 16; + g_res.avt_sqv = (uint8_t *)malloc(AVT_SQV_SIZE); + if (!g_res.avt_sqv) { + print_error("Failed to allocate avt buffer, %d bytes", AVT_SQV_SIZE); + } + static const int TMP_SIZE = 32000 + 64000; + g_res.tmp = (uint8_t *)malloc(TMP_SIZE); + if (!g_res.tmp) { + print_error("Failed to allocate tmp buffer, %d bytes", TMP_SIZE); + } + static const int VGA_SIZE = 320 * 200; + g_res.vga = (uint8_t *)malloc(VGA_SIZE); + if (!g_res.vga) { + print_error("Failed to allocate vga buffer, %d bytes", VGA_SIZE); + } + static const int TILES_SIZE = 640 * 200; + g_res.tiles = (uint8_t *)malloc(TILES_SIZE); + if (!g_res.tiles) { + print_error("Failed to allocate tiles buffer, %d bytes", TILES_SIZE); + } + static const char *filename = "sound"; + if (fio_exists(filename)) { + g_res.snd = (uint8_t *)malloc(SOUND_SIZE); + if (!g_res.snd) { + print_warning("Failed to allocate sound buffer, %d bytes", SOUND_SIZE); + } else { + int f = fio_open(filename, 1); + const int filesize = fio_size(f); + if (filesize != SOUND_SIZE) { + print_warning("Unexpected '%s' file size %d", filename, filesize); + } else if (fio_read(f, g_res.snd, SOUND_SIZE) != SOUND_SIZE) { + print_error("Failed to read %d bytes from file '%s'", filesize, filename); + } + fio_close(f); + } + } + if (fio_exists("demomag.sql")) { + g_res.flags = RESOURCE_FLAGS_DEMO; + } +} + +void res_fini() { + free(g_res.sql); + free(g_res.spr_sqv); + free(g_res.avt_sqv); + free(g_res.tmp); + free(g_res.vga); + free(g_res.tiles); + free(g_res.snd); +} + +int read_file(const char *filename, uint8_t *dst) { + const int f = fio_open(filename, 1); + const int filesize = fio_size(f); + if (fio_read(f, dst, filesize) != filesize) { + print_error("Failed to read %d bytes from file '%s'", filesize, filename); + } + fio_close(f); + return filesize; +} + +int read_compressed_file(const char *filename, uint8_t *dst) { + return unpack(filename, dst); +} + +static void decode_bitplane_scanline(const uint8_t *src, int depth, int w, uint8_t *dst) { + const int plane_size = w / depth; + for (int x = 0; x < plane_size; ++x) { + for (int i = 0; i < 8; ++i) { + int color = 0; + const int mask = 1 << (7 - i); + for (int bit = 0; bit < depth; ++bit) { + if (src[bit * plane_size] & mask) { + color |= 1 << bit; + } + } + dst[i] = color; + } + ++src; + dst += 8; + } +} + +static void load_iff(const uint8_t *data, uint32_t size, uint8_t *dst, int dst_pitch) { + print_debug(DBG_RESOURCE, "load_iff size %d", size); + if (data && memcmp(data, "FORM", 4) == 0) { + int offset = 12; + while (offset < size) { + const uint8_t *buf = data + offset; + const int len = (READ_BE_UINT32(buf + 4) + 1) & ~1; + print_debug(DBG_RESOURCE, "tag '%c%c%c%c' len %d", buf[0], buf[1], buf[2], buf[3], len); + if (memcmp(buf, "BMHD", 4) == 0) { + buf += 8; + const int w = READ_BE_UINT16(buf); + const int h = READ_BE_UINT16(buf + 2); + const int planes = buf[8]; + const int compression = buf[10]; + print_debug(DBG_RESOURCE, "w %d h %d planes %d compression %d", w, h, planes, compression); + if (w != 320 || h < 200) { + print_error("Unhandled LBM dimensions %d,%d", w, h); + return; + } + if (planes != 4) { + print_error("Unhandled LBM planes count %d", planes); + return; + } + if (compression != 1) { + print_error("Unhandled LBM compression %d", compression); + return; + } + } else if (memcmp(buf, "CMAP", 4) == 0) { + buf += 8; + for (int i = 0; i < len; ++i) { + g_res.palette[i] = buf[i]; + } + } else if (memcmp(buf, "BODY", 4) == 0) { + buf += 8; + int offset = 0; + int i = 0; + int y = 0; + uint8_t scanline[160]; + while (i < len && offset < 32000) { + int code = (int8_t)buf[i++]; + if (code != -128) { + if (code < 0) { + code = 1 - code; + memset(scanline + offset % 160, buf[i], code); + ++i; + } else { + ++code; + memcpy(scanline + offset % 160, buf + i, code); + i += code; + } + offset += code; + if ((offset % 160) == 0) { + decode_bitplane_scanline(scanline, 4, 160, dst + y * dst_pitch); + ++y; + } + } + + } + print_debug(DBG_RESOURCE, "scanlines %d", y); + } + offset += 8 + len; + } + } +} + +void load_avt(const char *filename, uint8_t *dst, int offset) { + read_compressed_file(filename, dst); + const uint8_t *ptr = dst; + const int count = READ_LE_UINT16(ptr); ptr += 6; + print_debug(DBG_RESOURCE, "avt count %d", count); + for (int i = 0; i < count; ++i) { + g_res.avt[offset + i] = ptr; + ptr += 132; + } +} + +static const uint8_t *trigger_lookup_table1(uint8_t num) { + extern const uint8_t *level_triggersdata_3356[]; + assert(num < 4); + return level_triggersdata_3356[num]; +} + +static const uint8_t *trigger_lookup_table2(uint8_t num) { + if (num == 255) { + return 0; + } + extern uint8_t *level_tilesdata_1e8c[]; + if (num < 128) { + assert(num < 86); + return level_tilesdata_1e8c[num]; + } + extern uint8_t *level_tilesdata_1fe8[]; + num -= 128; + assert(num < 17); + return level_tilesdata_1fe8[num]; +} + +static const uint8_t *trigger_lookup_table3(uint8_t num) { + if (num == 255) { + return 0; + } + extern const uint8_t *level_triggersdata_2030[]; + assert(num < 61); + return level_triggersdata_2030[num]; +} + +void load_bin(const char *filename) { + uint8_t bin[MAX_TRIGGERS * 10]; + const int size = read_file(filename, bin); + assert(size == MAX_TRIGGERS * 10); + const uint8_t *p = bin; + for (int i = 0; i < MAX_TRIGGERS; ++i) { + struct trigger_t *t = &g_res.triggers[i]; + t->tile_type = p[0]; + t->tile_flags = p[1]; + t->op_func = p[2]; + t->op_table1 = trigger_lookup_table1(p[3]); + t->op_table2 = trigger_lookup_table2(p[4]); + t->unk10 = p[5]; + t->op_table3 = trigger_lookup_table3(p[6]); + t->unk16 = p[7]; + t->tile_index = p[8]; + t->foreground_tile_num = p[9]; + p += 10; + } +} + +void load_ck(const char *filename, uint16_t offset) { + const int size = read_compressed_file(filename, g_res.tmp); + switch (offset) { + case 0x6000: // page3 + offset = 0; + break; + case 0x8000: // page4 + offset = 320; + break; + default: + print_error("Unexpected offset 0x%x in load_ck()", offset); + break; + } + load_iff(g_res.tmp, size, g_res.tiles + offset, 640); + g_sys.set_screen_palette(g_res.palette, 16); +} + +void load_img(const char *filename) { + const int size = read_compressed_file(filename, g_res.tmp); + assert(size <= 32000); + load_iff(g_res.tmp, size, g_res.tmp + 32000, 320); + g_sys.set_screen_palette(g_res.palette, 16); + g_sys.update_screen(g_res.tmp + 32000, 0); + memcpy(g_res.vga, g_res.tmp + 32000, 64000); +} + +void load_sqv(const char *filename, uint8_t *dst, int offset) { + read_compressed_file(filename, dst); + const uint8_t *ptr = dst; + const int count = READ_LE_UINT16(ptr); ptr += 6; + print_debug(DBG_RESOURCE, "sqv count %d", count); + for (int i = 0; i < count; ++i) { + g_res.spr_frames[offset + i] = ptr; + const int h = READ_LE_UINT16(ptr - 4); + const int w = READ_LE_UINT16(ptr - 2); + assert((w & 3) == 0); + const int size = (w >> 1) * h + 4; + print_debug(DBG_RESOURCE, "sprite %d, dim %d,%d size %d", i, w, h, size); + ptr += size; + } +} + +void load_sql(const char *filename) { + read_compressed_file(filename, g_res.sql); +} + +uint8_t *lookup_sql(int x, int y) { + return g_res.sql + y * 128 + x; +} diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..5aa4831 --- /dev/null +++ b/resource.h @@ -0,0 +1,60 @@ + +#ifndef RESOURCE_H__ +#define RESOURCE_H__ + +#include "intern.h" + +#define TILE_NUM_CRATE 5 +#define TILE_NUM_BALLOON 8 +#define TILE_NUM_UMBRELLA 9 + +struct trigger_t { + int16_t tile_type; + int16_t tile_flags; + uint8_t op_func; + const uint8_t *op_table1; // dy for (x&15) + const uint8_t *op_table2; // tile_animation + int16_t unk10; + const uint8_t *op_table3; // tile_trigger + uint8_t unk16; // next_tile_num + uint8_t tile_index; // op_table2 + uint8_t foreground_tile_num; +}; + +#define MAX_AVT 50 +#define MAX_SPR_FRAMES 200 +#define MAX_TRIGGERS 256 +#define SOUND_SIZE 29376 + +#define RESOURCE_FLAGS_DEMO (1 << 0) + +struct resource_data_t { + uint32_t flags; + uint8_t *sql; + uint8_t *spr_sqv; + uint8_t *avt_sqv; + uint8_t *tmp; + const uint8_t *avt[MAX_AVT]; + const uint8_t *spr_frames[MAX_SPR_FRAMES]; + uint8_t palette[16 * 3]; + struct trigger_t triggers[MAX_TRIGGERS]; + uint8_t *vga; + uint8_t *tiles; + uint8_t *snd; +}; + +extern struct resource_data_t g_res; + +extern void res_init(); +extern void res_fini(); +extern int read_file(const char *filename, uint8_t *dst); +extern int read_compressed_file(const char *filename, uint8_t *dst); +extern void load_avt(const char *filename, uint8_t *dst, int offset); +extern void load_bin(const char *filename); +extern void load_ck(const char *filename, uint16_t offset); +extern void load_img(const char *filename); +extern void load_sqv(const char *filename, uint8_t *dst, int size); +extern void load_sql(const char *filename); +extern uint8_t * lookup_sql(int x, int y); + +#endif /* RESOURCE_H__ */ diff --git a/screen.c b/screen.c new file mode 100644 index 0000000..0e54dae --- /dev/null +++ b/screen.c @@ -0,0 +1,183 @@ + +#include "decode.h" +#include "game.h" +#include "resource.h" +#include "sys.h" +#include "util.h" + +#define HZ 30 + +void screen_init() { + for (int i = 0; i < MAX_SPRITES; ++i) { + g_vars.sprites[i] = &g_vars.sprites_table[i]; + } + for (int i = 0; i < MAX_SPRITES - 1; ++i) { + g_vars.sprites[i]->next_sprite = g_vars.sprites[i] + 1; + } + g_vars.sprites[MAX_SPRITES - 1]->next_sprite = 0; +} + +void screen_clear_sprites() { + g_vars.sprites_count = 0; +} + +void screen_add_sprite(int x, int y, int frame) { + assert(g_vars.sprites_count < MAX_SPRITES); + struct sprite_t *spr = g_vars.sprites[g_vars.sprites_count]; + spr->xpos = x; + spr->ypos = y; + spr->frame = g_res.spr_frames[frame]; + spr->xflip = 0; + spr->unk16 = 0; + spr->next_sprite = spr + 1; + ++g_vars.sprites_count; +} + +void screen_clear_last_sprite() { + assert(g_vars.sprites_count >= 0); + if (g_vars.sprites_count > 0) { + g_vars.sprites[g_vars.sprites_count - 1]->next_sprite = 0; + } +} + +void screen_redraw_sprites() { + for (int i = 0; i < g_vars.sprites_count; ++i) { + struct sprite_t *spr = g_vars.sprites[i]; + const uint8_t *p = spr->frame; + const int h = READ_LE_UINT16(p - 4); + const int w = READ_LE_UINT16(p - 2); + const int y = spr->ypos - h; + const int x = spr->xpos - w / 2; + decode_ega_spr(p, w, w, h, g_res.vga, GAME_SCREEN_W, x, y, spr->xflip); + } +} + +void fade_in_palette() { + g_sys.fade_in_palette(); +} + +void fade_out_palette() { + // g_sys.fade_out_palette(); +} + +void screen_adjust_palette_color(int color, int b, int c) { + g_res.palette[color * 3 + b] += c; + screen_vsync(); + screen_set_palette(); +} + +void screen_vsync() { +} + +void screen_set_palette() { + g_sys.set_screen_palette(g_res.palette, 16); +} + +void screen_draw_frame(const uint8_t *frame, int a, int b, int c, int d) { + const int h = READ_LE_UINT16(frame - 4); + assert(a <= h); + const int w = READ_LE_UINT16(frame - 2); + assert(b <= w); + const int x = c; + const int y = d + a + 2; + decode_ega_spr(frame, w, b, h, g_res.vga, GAME_SCREEN_W, x, y, 0); +} + +void screen_flip() { + g_sys.update_screen(g_res.vga, 1); + g_sys.sleep(1000 / HZ); +} + +void screen_unk4() { + memcpy(g_res.vga, g_res.tmp + 32000, 64000); +} + +void screen_unk5() { + screen_clear(0); + screen_do_transition2(); + screen_clear(0); +} + +void screen_unk6() { + // _screen_draw_offset -= 12; + // screen_do_transition2(); + // _screen_draw_offset += 12; + g_sys.update_screen(g_res.vga, 1); + g_sys.sleep(1000 / HZ); // get_time + memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H); +} + +void screen_copy_tilemap2(int a, int b, int c, int d) { +} + +void screen_copy_tilemap(int a) { +} + +static void screen_unk13(int a) { +} + +void screen_do_transition1(int a) { + int i, count, increment; + if (a != 0) { + i = 11; + count = 0; + increment = -1; + } else { + screen_clear(0); + i = 0; + count = 11; + increment = 1; + } + while (i != count) { + screen_unk13(i); + screen_unk13(19 - i); + screen_vsync(); + i += increment; + } +} + +void screen_clear(int a) { + memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H); +} + +void screen_draw_tile(int tile, int dst, int type) { + int y = (dst / 640) * 16 + TILEMAP_OFFSET_Y; + int x = (dst % 640) / 2 * 16; + const uint8_t *src = g_res.tiles + tile * 16; + if (type == 4) { + src += 320; + } + for (int i = 0; i < 16; ++i) { + memcpy(g_res.vga + (y + i) * GAME_SCREEN_W + x, src, 16); + src += 640; + } +} + +void screen_do_transition2() { + print_warning("screen_do_transition2"); +} + +void screen_draw_number(int num, int x, int y, int color) { + extern const uint8_t font_data[]; + y += TILEMAP_OFFSET_Y; + decode_ega_spr(font_data + (num / 10) * 32, 8, 8, 8, g_res.vga, GAME_SCREEN_W, x - 8, y, 0); + decode_ega_spr(font_data + (num % 10) * 32, 8, 8, 8, g_res.vga, GAME_SCREEN_W, x, y, 0); +} + +void screen_add_game_sprite1(int x, int y, int frame) { + screen_add_sprite(x, y + TILEMAP_OFFSET_Y, frame); + g_vars.sprites[g_vars.sprites_count - 1]->xflip = 0; +} + +void screen_add_game_sprite2(int x, int y, int frame) { + screen_add_sprite(x, y + TILEMAP_OFFSET_Y, frame); + g_vars.sprites[g_vars.sprites_count - 1]->xflip = 1; +} + +void screen_add_game_sprite3(int x, int y, int frame, int blinking_counter) { + print_warning("screen_add_game_sprite3"); +} + +void screen_add_game_sprite4(int x, int y, int frame, int blinking_counter) { + print_warning("screen_add_game_sprite4"); +} diff --git a/sound.c b/sound.c new file mode 100644 index 0000000..c315436 --- /dev/null +++ b/sound.c @@ -0,0 +1,123 @@ + +#include "fileio.h" +#include "game.h" +#include "resource.h" +#include "sys.h" + +#include + +#define PAULA_FREQ 3546897 + +static const struct { + uint16_t offset; // words + uint16_t size; +} _sounds_amiga[] = { + { 0x0000, 0x0256 }, + { 0x0000, 0x0256 }, + { 0x0000, 0x0256 }, + { 0x0000, 0x0256 }, + { 0x012b, 0x051a }, + { 0x03b8, 0x0532 }, + { 0x0651, 0x03e8 }, + { 0x0b51, 0x0c1c }, + { 0x115f, 0x0e40 }, + { 0x0000, 0x0256 }, + { 0x0000, 0x0256 }, + { 0x187f, 0x04c4 }, + { 0x1ae1, 0x0c14 }, + { 0x20eb, 0x1e1a }, + { 0x2ff8, 0x0610 }, + { 0x3300, 0x0420 }, + { 0x3510, 0x032c }, + { 0x36a6, 0x0574 } +}; + +// Amiga, unexotica +static const char *_modules[] = { + "ALMOST", "mod.almost", + "GUNN", "mod.bluesgunnbest", + "EVERY", "mod.every", + "SHOT", "mod.shot" +}; + +struct mixerchannel_t { + uint8_t *data; + uint32_t pos; + uint32_t step; + uint32_t size; +}; + +static int _rate = 22050; +static struct mixerchannel_t _channel; +static ModPlugFile *_mpf; + +static void mix(void *param, uint8_t *buf, int len) { + memset(buf, 0, len); + + if (_mpf) { + ModPlug_Read(_mpf, buf, len); + } + if (_channel.data) { + for (int i = 0; i < len; i += sizeof(int16_t)) { + const int pos = _channel.pos >> 16; + if (pos >= _channel.size) { + _channel.data = 0; + break; + } + const int sample = *(int16_t *)(buf + i) + ((int8_t)_channel.data[pos]) * 256; + *(int16_t *)(buf + i) = (sample < -32768 ? -32768 : (sample > 32767 ? 32767 : sample)); + _channel.pos += _channel.step; + } + } +} + +void sound_init(int rate) { + _rate = rate; + ModPlug_Settings mp_settings; + memset(&mp_settings, 0, sizeof(mp_settings)); + ModPlug_GetSettings(&mp_settings); + mp_settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION; + mp_settings.mChannels = 1; + mp_settings.mBits = 16; + mp_settings.mFrequency = rate; + mp_settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; + mp_settings.mLoopCount = -1; + ModPlug_SetSettings(&mp_settings); + g_sys.start_audio(mix, 0); +} + +void sound_fini() { + g_sys.stop_audio(); +} + +void play_sound(int num) { + if (g_res.snd) { + g_sys.lock_audio(); + _channel.data = g_res.snd + _sounds_amiga[num].offset * 2; + _channel.pos = 0; + _channel.step = ((PAULA_FREQ / 0x358) << 16) / _rate; + _channel.size = _sounds_amiga[num].size; + g_sys.unlock_audio(); + } +} + +void play_music(int num) { + g_sys.lock_audio(); + if (_mpf) { + ModPlug_Unload(_mpf); + _mpf = 0; + } + const char *filename = _modules[num * 2 + 1]; + if (fio_exists(filename)) { + int slot = fio_open(filename, 1); + int size = fio_size(slot); + uint8_t *buf = (uint8_t *)malloc(size); + if (buf) { + fio_read(slot, buf, size); + _mpf = ModPlug_Load(buf, size); + free(buf); + } + fio_close(slot); + } + g_sys.unlock_audio(); +} diff --git a/staticres.c b/staticres.c new file mode 100644 index 0000000..9628f5f --- /dev/null +++ b/staticres.c @@ -0,0 +1,1571 @@ +#include "intern.h" + +const int16_t level_xpos_magasin[] = { + 0x240,0x3a0,0x4f0,0x5e0,0x250,0x4b0,0x370,0x230,0x4d0,0x0a0,0x0a0,0x2f0,0x450,0x4a0, + 0x670,0x4f0,0x2d0,0x3f0,0x570,0x5f0,0x650,0x5f0,0x650,0x260,0x360,0x380,0x1e0,0x410, + 0x660,0x610,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x040,0x050 +}; +const int16_t level_ypos_magasin[] = { + 0x460,0x460,0x460,0x460,0x520,0x3e0,0x3e0,0x3e0,0x520,0x1f0,0x270,0x210,0x210,0x2f0, + 0x320,0x320,0x160,0x160,0x160,0x180,0x1d0,0x250,0x2e0,0x310,0x200,0x200,0x060,0x050, + 0x060,0x210,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x470,0x470 +}; +const int16_t level_xpos_concert[] = { + 0x420,0x420,0x270,0x150,0x2a0,0x240,0x4f0,0x670,0x760,0x360,0x600,0x000,0x000,0x000, + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000, + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x040,0x050 +}; +const int16_t level_ypos_concert[] = { + 0x1c0,0x2b0,0x160,0x2c0,0x2c0,0x2c0,0x250,0x2e0,0x2e0,0x160,0x050,0x000,0x000,0x000, + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000, + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x160,0x160 +}; +const int16_t level_xpos_ville[] = { + 0x030,0x350,0x3b0,0x1a0,0x710,0x6d0,0x6e0,0x140,0x250,0x170,0x160,0x200,0x220,0x0c0, + 0x2d0,0x3f0,0x360,0x2b0,0x1c0,0x1f0,0x240,0x460,0x4d0,0x5f0,0x5c0,0x000,0x5c0,0x630, + 0x5c0,0x5e0,0x760,0x770,0x780,0x760,0x000,0x000,0x000,0x000,0x000,0x040,0x050 +}; +const int16_t level_ypos_ville[] = { + 0x530,0x3e0,0x3a0,0x0f0,0x590,0x4a0,0x3b0,0x5d0,0x5d0,0x550,0x4d0,0x3e0,0x420,0x3b0, + 0x350,0x5d0,0x250,0x1c0,0x1c0,0x040,0x040,0x040,0x120,0x1c0,0x220,0x000,0x290,0x2f0, + 0x2f0,0x5d0,0x510,0x410,0x3b0,0x300,0x000,0x000,0x000,0x000,0x000,0x5e0,0x5e0 +}; +const int16_t level_xpos_egou[] = { + 0x1b0,0x2f0,0x0c0,0x4a0,0x5f0,0x530,0x3d0,0x330,0x4f0,0x1a0,0x180,0x070,0x250,0x090, + 0x100,0x260,0x3e0,0x270,0x280,0x140,0x4b0,0x690,0x570,0x480,0x5a0,0x740,0x500,0x6a0, + 0x060,0x690,0x790,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x040,0x040 +}; +const int16_t level_ypos_egou[] = { + 0x070,0x080,0x070,0x090,0x0b0,0x140,0x140,0x200,0x0b0,0x200,0x170,0x170,0x120,0x310, + 0x3b0,0x3b0,0x3b0,0x2d0,0x310,0x300,0x2c0,0x200,0x200,0x320,0x3a0,0x140,0x140,0x180, + 0x490,0x290,0x180,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x020,0x040 +}; +const int16_t level_xpos_prison[] = { + 0x1b0,0x2a0,0x3a0,0x290,0x380,0x540,0x640,0x540,0x670,0x330,0x6b0,0x4d0,0x500,0x1b0, + 0x0a0,0x1f0,0x130,0x1f0,0x290,0x140,0x4e0,0x420,0x470,0x680,0x610,0x4f0,0x730,0x320, + 0x310,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x1a0,0x1c0 +}; +const int16_t level_ypos_prison[] = { + 0x100,0x100,0x100,0x180,0x180,0x180,0x180,0x100,0x200,0x240,0x540,0x1f0,0x1f0,0x230, + 0x1d0,0x330,0x380,0x380,0x3e0,0x3e0,0x430,0x3f0,0x320,0x290,0x440,0x2d0,0x320,0x360, + 0x460,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x0b0,0x0b0 +}; +const int16_t level_xpos_ent[] = { + 0x330,0x330,0x570,0x400,0x2d0,0x250,0x4f0,0x410,0x470,0x560,0x200,0x4b0,0x4e0,0x6a0, + 0x710,0x2f0,0x7a0,0x6c0,0x690,0x690,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000, + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x040,0x050 +}; +const int16_t level_ypos_ent[] = { + 0x460,0x3d0,0x330,0x330,0x280,0x1c0,0x180,0x220,0x220,0x220,0x460,0x330,0x240,0x190, + 0x0b0,0x120,0x380,0x380,0x210,0x2a0,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000, + 0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x470,0x470 +}; +const uint16_t level_dim[] = { + 0x0080,0x0480,0x0080,0x0480,0x0080,0x0480,0x0080,0x03D0,0x0080,0x05F0,0x0080,0x0310 +}; +const uint8_t level_door[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x24,0x00,0x46,0x00,0x13,0x00,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x52,0x00,0x24,0x00,0x46,0x00, + 0x12,0x00,0x52,0x00,0x24,0x00,0x46,0x00,0x3A,0x00,0x46,0x00,0x1D,0x00,0x52,0x00, + 0x1D,0x00,0x52,0x00,0x3A,0x00,0x46,0x00,0x1C,0x00,0x52,0x00,0x3A,0x00,0x46,0x00, + 0x1E,0x00,0x52,0x00,0x3A,0x00,0x46,0x00,0x4B,0x00,0x46,0x00,0x35,0x00,0x52,0x00, + 0x4C,0x00,0x46,0x00,0x36,0x00,0x52,0x00,0x35,0x00,0x52,0x00,0x4B,0x00,0x46,0x00, + 0x36,0x00,0x52,0x00,0x4C,0x00,0x46,0x00,0x46,0x00,0x52,0x00,0x4B,0x00,0x3E,0x00, + 0x4B,0x00,0x3E,0x00,0x46,0x00,0x52,0x00,0x45,0x00,0x52,0x00,0x4B,0x00,0x3E,0x00, + 0x47,0x00,0x52,0x00,0x4B,0x00,0x3E,0x00,0x27,0x00,0x3E,0x00,0x59,0x00,0x52,0x00, + 0x28,0x00,0x3E,0x00,0x5A,0x00,0x52,0x00,0x59,0x00,0x52,0x00,0x27,0x00,0x3E,0x00, + 0x5A,0x00,0x52,0x00,0x28,0x00,0x3E,0x00,0x39,0x00,0x46,0x00,0x1D,0x00,0x52,0x00, + 0x3B,0x00,0x46,0x00,0x1D,0x00,0x52,0x00,0x4A,0x00,0x3E,0x00,0x46,0x00,0x52,0x00, + 0x4C,0x00,0x3E,0x00,0x46,0x00,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x1A,0x00,0x0B,0x00,0x09,0x00,0x54,0x00,0x1B,0x00,0x0B,0x00,0x0A,0x00,0x54,0x00, + 0x09,0x00,0x54,0x00,0x1A,0x00,0x0B,0x00,0x0A,0x00,0x54,0x00,0x1B,0x00,0x0B,0x00, + 0x1D,0x00,0x3E,0x00,0x44,0x00,0x54,0x00,0x1E,0x00,0x3E,0x00,0x45,0x00,0x54,0x00, + 0x44,0x00,0x54,0x00,0x1D,0x00,0x3E,0x00,0x45,0x00,0x54,0x00,0x1E,0x00,0x3E,0x00, + 0x18,0x00,0x3E,0x00,0x2D,0x00,0x54,0x00,0x19,0x00,0x3E,0x00,0x2E,0x00,0x54,0x00, + 0x2D,0x00,0x54,0x00,0x0F,0x00,0x3E,0x00,0x2E,0x00,0x54,0x00,0x10,0x00,0x3E,0x00, + 0x0F,0x00,0x3E,0x00,0x1C,0x00,0x54,0x00,0x10,0x00,0x3E,0x00,0x1D,0x00,0x54,0x00, + 0x1C,0x00,0x54,0x00,0x18,0x00,0x3E,0x00,0x1D,0x00,0x54,0x00,0x19,0x00,0x3E,0x00, + 0x0A,0x00,0x3E,0x00,0x5E,0x00,0x54,0x00,0x0B,0x00,0x3E,0x00,0x5F,0x00,0x54,0x00, + 0x5E,0x00,0x54,0x00,0x0A,0x00,0x3E,0x00,0x5F,0x00,0x54,0x00,0x0B,0x00,0x3E,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x26,0x00,0x70,0x00,0x54,0x00, + 0x52,0x00,0x26,0x00,0x71,0x00,0x54,0x00,0x70,0x00,0x54,0x00,0x51,0x00,0x26,0x00, + 0x71,0x00,0x54,0x00,0x52,0x00,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x17,0x00,0x1C,0x00,0x1D,0x00,0x1E,0x00,0x18,0x00,0x1C,0x00,0x1E,0x00,0x1E,0x00, + 0x1D,0x00,0x1E,0x00,0x17,0x00,0x1C,0x00,0x1E,0x00,0x1E,0x00,0x18,0x00,0x1C,0x00, + 0x1A,0x00,0x1A,0x00,0x0A,0x00,0x48,0x00,0x1B,0x00,0x1A,0x00,0x0B,0x00,0x48,0x00, + 0x0A,0x00,0x48,0x00,0x1A,0x00,0x1A,0x00,0x0B,0x00,0x48,0x00,0x1B,0x00,0x1A,0x00, + 0x1E,0x00,0x19,0x00,0x18,0x00,0x13,0x00,0x1F,0x00,0x19,0x00,0x19,0x00,0x13,0x00, + 0x18,0x00,0x13,0x00,0x1E,0x00,0x19,0x00,0x19,0x00,0x13,0x00,0x1F,0x00,0x19,0x00, + 0x1B,0x00,0x15,0x00,0x2A,0x00,0x45,0x00,0x1C,0x00,0x15,0x00,0x2B,0x00,0x45,0x00, + 0x34,0x00,0x47,0x00,0x1A,0x00,0x45,0x00,0x35,0x00,0x47,0x00,0x1B,0x00,0x45,0x00, + 0x1D,0x00,0x45,0x00,0x1B,0x00,0x15,0x00,0x1E,0x00,0x45,0x00,0x1C,0x00,0x15,0x00, + 0x5F,0x00,0x34,0x00,0x1D,0x00,0x1E,0x00,0x60,0x00,0x34,0x00,0x1E,0x00,0x1E,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x0F,0x00,0x6E,0x00,0x20,0x00,0x42,0x00,0x20,0x00,0x42,0x00,0x0F,0x00,0x6E,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x6F,0x00,0x2A,0x00,0x75,0x00,0x1A,0x00,0x75,0x00,0x1A,0x00,0x6F,0x00,0x2A,0x00, + 0x0B,0x00,0x2C,0x00,0x72,0x00,0x05,0x00,0x72,0x00,0x05,0x00,0x0B,0x00,0x2C,0x00, + 0x7B,0x00,0x0B,0x00,0x7B,0x00,0x10,0x00,0x7B,0x00,0x10,0x00,0x7B,0x00,0x0B,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_rects[] = { + 0x5E,0x00,0x51,0x00,0x60,0x00,0x1A,0x00,0x1A,0x00,0x03,0x00,0x59,0x00,0x34,0x00, + 0x0F,0x00,0x60,0x00,0x33,0x00,0x14,0x00,0x48,0x00,0x1B,0x00,0x05,0x00 +}; +const uint16_t level_tilemap_start_xpos[] = { + 0x02D0,0x02D0,0x0390,0x0390,0x0150,0x0160,0x0120,0x0130,0x03C0,0x03D0,0x0040,0x0050 +}; +const uint16_t level_tilemap_start_ypos[] = { + 0x01F0,0x01F0,0x02F0,0x02F0,0x0330,0x0330,0x0130,0x0130,0x0250,0x0250,0x0160,0x0160 +}; +const uint8_t level_objtypes[] = { + 0x00,0x00,0x00,0x02,0x03,0x04,0x01,0x05,0x01,0x01,0x07,0x02,0x02,0x08,0x0B,0x01, + 0x04,0x0B,0x02,0x09,0x0A,0x0B,0x0C,0x0B,0x01,0x02,0x06,0x0D,0x01,0x0D,0x0E,0x0D, + 0x0F,0x10,0x10,0x12,0x0B,0x01,0x13,0x02,0x14 +}; +uint8_t level_data[] = { + 0x04,0x0F,0x0F,0x04,0x14,0x0F,0x14,0x04,0x14,0x14,0x11,0x08,0x08,0x14,0x10,0x14, + 0x12,0x12,0x04,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x13,0x13,0x13,0x04,0x64,0x64, + 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x0D,0x0D,0x0C,0x0C,0x0C,0x0E,0x0B, + 0x16,0x16,0x16,0x0D,0x0C,0x0C,0x64,0x15,0x15,0x0D,0x0C,0x0D,0x0C,0x64,0x64,0x64, + 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, + 0x64,0x64,0x03,0x04,0x03,0x03,0x03,0x06,0x03,0x05,0x03,0x05,0x17,0x04,0x03,0x06, + 0x05,0x06,0x06,0x06,0x03,0x06,0x04,0x03,0x05,0x03,0x06,0x04,0x64,0x03,0x17,0x64, + 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x19,0x1B,0x1D,0x21,0x1E, + 0x1C,0x1C,0x1C,0x1A,0x1F,0x1E,0x1D,0x20,0x22,0x1F,0x1F,0x1F,0x22,0x22,0x22,0x22, + 0x19,0x20,0x22,0x22,0x19,0x1C,0x1C,0x1C,0x22,0x19,0x64,0x64,0x64,0x64,0x64,0x64, + 0x64,0x64,0x64,0x64,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x04,0x26,0x25,0x24,0x04, + 0x26,0x25,0x15,0x26,0x25,0x24,0x25,0x04,0x26,0x27,0x24,0x25,0x24,0x64,0x27,0x04, + 0x26,0x24,0x15,0x27,0x04,0x25,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x28,0x28,0x04, + 0x04,0x03,0x03,0x04,0x03,0x03,0x03,0x03,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, + 0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64, + 0x64,0x64,0x64,0x64,0x64,0x64 +}; +const uint8_t animframe_00a2[] = { + 1,0x01 +}; +const uint8_t animframe_00a4[] = { + 6,0x02,0x00,0x01,0x03,0x00,0x01 +}; +const uint8_t animframe_00ab[] = { + 1,0x07 +}; +const uint8_t animframe_00ad[] = { + 1,0x04 +}; +const uint8_t animframe_00af[] = { + 8,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06 +}; +const uint8_t animframe_00b8[] = { + 4,0x09,0x09,0x08,0x08 +}; +const uint8_t animframe_00bd[] = { + 1,0x0a +}; +const uint8_t animframe_00bf[] = { + 1,0x0b +}; +const uint8_t animframe_00c1[] = { + 1,0x27 +}; +const uint8_t animframe_00c3[] = { + 1,0x08 +}; +const uint8_t animframe_00c5[] = { + 1,0x0c +}; +const uint8_t animframe_00c7[] = { + 5,0x0e,0x0e,0x0e,0x0e,0x0e +}; +const uint8_t animframe_00cd[] = { + 6,0x0f,0x0d,0x0e,0x10,0x0d,0x0e +}; +const uint8_t animframe_00d4[] = { + 1,0x11 +}; +const uint8_t animframe_00d6[] = { + 4,0x19,0x19,0x1a,0x1a +}; +const uint8_t animframe_00db[] = { + 1,0x18 +}; +const uint8_t animframe_00dd[] = { + 50,0x15,0x15,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17 +}; +const uint8_t animframe_0110[] = { + 4,0x14,0x14,0x18,0x18 +}; +const uint8_t animframe_0115[] = { + 16,0x13,0x1e,0x1f,0x20,0x1b,0x1c,0x1d,0x1b,0x1c,0x1d,0x1b,0x1c,0x1d,0x1b,0x1c,0x1d +}; +const uint8_t animframe_0126[] = { + 1,0x12 +}; +const uint8_t animframe_0128[] = { + 12,0x28,0x28,0x29,0x29,0x2a,0x2a,0x2a,0x2a,0x29,0x29,0x28,0x28 +}; +const uint8_t animframe_0135[] = { + 52,0x23,0x23,0x24,0x24,0x25,0x25,0x26,0x26,0x21,0x21,0x22,0x22,0x23,0x23,0x24,0x24,0x25,0x25,0x26,0x26,0x21,0x21,0x22,0x22,0x23,0x23,0x24,0x24,0x25,0x25,0x26,0x26,0x21,0x21,0x22,0x22,0x23,0x23,0x24,0x24,0x25,0x25,0x26,0x26,0x21,0x21,0x22,0x22,0x23,0x23,0x24,0x24 +}; +const uint8_t animframe_016a[] = { + 2,0x2c,0x2c +}; +const uint8_t animframe_016d[] = { + 16,0x30,0x30,0x30,0x30,0x2e,0x2e,0x2f,0x2f,0x2f,0x2f,0x2f,0x2f,0x2e,0x2e,0x30,0x30 +}; +const uint8_t animframe_017e[] = { + 1,0x30 +}; +const uint8_t animframe_0180[] = { + 1,0x2d +}; +const uint8_t animframe_0182[] = { + 8,0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30 +}; +const uint8_t animframe_018b[] = { + 10,0x28,0x28,0x29,0x29,0x2a,0x2a,0x2b,0x2b,0x2c,0x2c +}; +const uint8_t animframe_0198[] = { + 1,0x2c +}; +const uint8_t animframe_019a[] = { + 1,0x33 +}; +const uint8_t animframe_019c[] = { + 6,0x34,0x32,0x33,0x35,0x32,0x33 +}; +const uint8_t animframe_01a3[] = { + 1,0x39 +}; +const uint8_t animframe_01a5[] = { + 1,0x36 +}; +const uint8_t animframe_01a7[] = { + 8,0x37,0x37,0x37,0x37,0x38,0x38,0x38,0x38 +}; +const uint8_t animframe_01b0[] = { + 4,0x3b,0x3b,0x3a,0x3a +}; +const uint8_t animframe_01b5[] = { + 1,0x3c +}; +const uint8_t animframe_01b7[] = { + 1,0x3d +}; +const uint8_t animframe_01b9[] = { + 1,0x59 +}; +const uint8_t animframe_01bb[] = { + 1,0x3a +}; +const uint8_t animframe_01bd[] = { + 1,0x3e +}; +const uint8_t animframe_01bf[] = { + 5,0x40,0x40,0x40,0x40,0x40 +}; +const uint8_t animframe_01c5[] = { + 6,0x41,0x3f,0x40,0x42,0x3f,0x40 +}; +const uint8_t animframe_01cc[] = { + 1,0x43 +}; +const uint8_t animframe_01ce[] = { + 4,0x4b,0x4b,0x4c,0x4c +}; +const uint8_t animframe_01d3[] = { + 1,0x4a +}; +const uint8_t animframe_01d5[] = { + 50,0x33,0x33,0x33,0x33,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x64,0x64,0x49,0x49,0x64,0x64,0x49,0x49,0x64,0x64,0x49,0x49,0x64,0x64,0x49,0x49,0x64,0x64,0x49,0x49,0x64,0x64,0x49,0x49,0x64,0x64,0x49,0x49,0x48,0x48,0x48,0x48,0x47,0x47,0x33,0x33,0x33,0x33 +}; +const uint8_t animframe_0208[] = { + 4,0x46,0x46,0x4a,0x4a +}; +const uint8_t animframe_020d[] = { + 16,0x45,0x50,0x51,0x52,0x4d,0x4e,0x4f,0x4d,0x4e,0x4f,0x4d,0x4e,0x4f,0x4d,0x4e,0x4f +}; +const uint8_t animframe_021e[] = { + 1,0x44 +}; +const uint8_t animframe_0220[] = { + 12,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5c,0x5b,0x5b,0x5a,0x5a +}; +const uint8_t animframe_022d[] = { + 52,0x58,0x58,0x53,0x53,0x54,0x54,0x55,0x55,0x56,0x56,0x57,0x57,0x58,0x58,0x53,0x53,0x54,0x54,0x55,0x55,0x56,0x56,0x57,0x57,0x58,0x58,0x53,0x53,0x54,0x54,0x55,0x55,0x56,0x56,0x57,0x57,0x58,0x58,0x53,0x53,0x54,0x54,0x55,0x55,0x56,0x56,0x57,0x57,0x58,0x58,0x53,0x53 +}; +const uint8_t animframe_0262[] = { + 2,0x5e,0x5e +}; +const uint8_t animframe_0265[] = { + 16,0x62,0x62,0x62,0x62,0x60,0x60,0x61,0x61,0x61,0x61,0x61,0x61,0x60,0x60,0x62,0x62 +}; +const uint8_t animframe_0276[] = { + 1,0x62 +}; +const uint8_t animframe_0278[] = { + 1,0x5f +}; +const uint8_t animframe_027a[] = { + 8,0x63,0x63,0x63,0x63,0x62,0x62,0x62,0x62 +}; +const uint8_t animframe_0283[] = { + 10,0x5a,0x5a,0x5b,0x5b,0x5c,0x5c,0x5d,0x5d,0x5e,0x5e +}; +const uint8_t animframe_0290[] = { + 1,0x5e +}; +const uint8_t animframe_0292[] = { + 12,0x94,0x94,0x94,0x93,0x93,0x93,0x92,0x92,0x92,0x93,0x93,0x93 +}; +const uint8_t animframe_029f[] = { + 1,0x93 +}; +const uint8_t animframe_02a1[] = { + 4,0x95,0x95,0x96,0x96 +}; +const uint8_t animframe_02a6[] = { + 12,0x99,0x99,0x97,0x97,0x98,0x98,0x9a,0x9a,0x97,0x97,0x98,0x98 +}; +const uint8_t animframe_02b3[] = { + 1,0x98 +}; +const uint8_t animframe_02b5[] = { + 12,0x9b,0x9b,0x9b,0x9b,0x9c,0x9c,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d +}; +const uint8_t animframe_02c2[] = { + 12,0x9d,0x9d,0x9d,0x9d,0x9d,0x9d,0x9c,0x9c,0x9b,0x9b,0x9b,0x9b +}; +const uint8_t animframe_02cf[] = { + 1,0xa9 +}; +const uint8_t animframe_02d1[] = { + 16,0xa9,0xa9,0xa9,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}; +const uint8_t animframe_02e2[] = { + 1,0xac +}; +const uint8_t animframe_02e4[] = { + 4,0xac,0xac,0xad,0xad +}; +const uint8_t animframe_02e9[] = { + 1,0x92 +}; +const uint8_t animframe_02eb[] = { + 2,0x92,0x93 +}; +const uint8_t animframe_02ee[] = { + 6,0x94,0x94,0x94,0xa0,0xa0,0xa0 +}; +const uint8_t animframe_02f5[] = { + 8,0xb2,0xb2,0xb3,0xb3,0xb4,0xb4,0xb5,0xb5 +}; +const uint8_t animframe_02fe[] = { + 1,0x93 +}; +const uint8_t animframe_0300[] = { + 12,0x94,0x94,0x92,0x92,0x93,0x93,0x95,0x95,0x92,0x92,0x93,0x93 +}; +const uint8_t animframe_030d[] = { + 8,0x96,0x96,0x96,0x96,0x97,0x97,0x97,0x97 +}; +const uint8_t animframe_0316[] = { + 1,0x99 +}; +const uint8_t animframe_0318[] = { + 12,0x9a,0x9a,0x98,0x98,0x99,0x99,0x9b,0x9b,0x98,0x98,0x99,0x99 +}; +const uint8_t animframe_0325[] = { + 8,0x9c,0x9c,0x9c,0x9c,0x9d,0x9d,0x9d,0x9d +}; +const uint8_t animframe_032e[] = { + 1,0x9f +}; +const uint8_t animframe_0330[] = { + 12,0xa0,0xa0,0x9e,0x9e,0x9f,0x9f,0xa1,0xa1,0x9e,0x9e,0x9f,0x9f +}; +const uint8_t animframe_033d[] = { + 16,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3,0xa3 +}; +const uint8_t animframe_034e[] = { + 1,0xa8 +}; +const uint8_t animframe_0350[] = { + 12,0xa9,0xa9,0xa7,0xa7,0xa8,0xa8,0xaa,0xaa,0xa7,0xa7,0xa8,0xa8 +}; +const uint8_t animframe_035d[] = { + 16,0xac,0xac,0xac,0xac,0xac,0xac,0xac,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab,0xab +}; +const uint8_t animframe_036e[] = { + 1,0x95 +}; +const uint8_t animframe_0370[] = { + 4,0x95,0x96,0x95,0x96 +}; +const uint8_t animframe_0375[] = { + 1,0xb3 +}; +const uint8_t animframe_0377[] = { + 12,0xb4,0xb4,0xb2,0xb2,0xb3,0xb3,0xb5,0xb5,0xb2,0xb2,0xb3,0xb3 +}; +const uint8_t animframe_0384[] = { + 16,0xb7,0xb7,0xb7,0xb8,0xb8,0xb8,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9,0xb9 +}; +const uint8_t animframe_0395[] = { + 1,0xac +}; +const uint8_t animframe_0397[] = { + 12,0xad,0xad,0xab,0xab,0xac,0xac,0xae,0xae,0xab,0xab,0xac,0xac +}; +const uint8_t animframe_03a4[] = { + 4,0xaf,0xaf,0xb0,0xb1 +}; +const uint8_t animframe_03a9[] = { + 1,0xa4 +}; +const uint8_t animframe_03ab[] = { + 8,0xa5,0xa5,0xa5,0xa5,0xa4,0xa4,0xa4,0xa4 +}; +const uint8_t animframe_03b4[] = { + 8,0xa1,0xa1,0xa2,0xa2,0xa3,0xa3,0xa3,0xa3 +}; +const uint8_t animframe_03bd[] = { + 1,0xbc +}; +const uint8_t animframe_03bf[] = { + 12,0xbd,0xbd,0xbb,0xbb,0xbc,0xbc,0xbe,0xbe,0xbb,0xbb,0xbc,0xbc +}; +const uint8_t animframe_03cc[] = { + 4,0xbf,0xbf,0xc0,0xc0 +}; +const uint8_t animframe_03d1[] = { + 1,0xae +}; +const uint8_t animframe_03d3[] = { + 12,0xaf,0xaf,0xad,0xad,0xae,0xae,0xb0,0xb0,0xad,0xad,0xae,0xae +}; +const uint8_t animframe_03e0[] = { + 16,0xae,0xae,0xae,0xae,0xae,0xae,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1 +}; +const uint8_t animframe_03f1[] = { + 1,0xa1 +}; +const uint8_t animframe_03f3[] = { + 12,0xa2,0xa2,0xa0,0xa0,0xa1,0xa1,0xa3,0xa3,0xa0,0xa0,0xa1,0xa1 +}; +const uint8_t animframe_0400[] = { + 16,0xa4,0xa4,0xa5,0xa5,0xa6,0xa6,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7,0xa7 +}; +const uint8_t animframe_0412[] = { + 1,0xae +}; +const uint8_t animframe_0414[] = { + 12,0xae,0xae,0xae,0xae,0xaf,0xaf,0xaf,0xaf,0xb0,0xb0,0xb0,0xb0 +}; +const uint8_t animframe_0421[] = { + 16,0xb0,0xb0,0xaf,0xaf,0xb0,0xb0,0xaf,0xaf,0xb0,0xb0,0xaf,0xaf,0xb0,0xb0,0xaf,0xaf +}; +const uint8_t animframe_0433[] = { + 1,0x93 +}; +const uint8_t animframe_0435[] = { + 12,0x94,0x94,0x92,0x92,0x93,0x93,0x95,0x95,0x92,0x92,0x93,0x93 +}; +const uint8_t animframe_0442[] = { + 8,0x96,0x96,0x96,0x96,0x97,0x97,0x97,0x97 +}; +const uint8_t animframe_044b[] = { + 12,0x98,0x98,0x98,0x98,0x99,0x99,0x99,0x99,0x9a,0x9a,0x9a,0x9a +}; +const uint8_t animframe_0458[] = { + 12,0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0x9d,0x9d,0x9d,0x9e,0x9e,0x9e +}; +const uint8_t animframe_0465[] = { + 3,0xa1,0xa2,0xa3 +}; +const uint8_t animframe_0469[] = { + 6,0xa4,0xa4,0xa4,0xa5,0xa5,0xa5 +}; +const uint8_t animframe_0470[] = { + 8,0x9f,0x9f,0xa0,0xa0,0x9f,0x9f,0xa0,0xa0 +}; +const uint8_t animframe_0479[] = { + 6,0xa6,0xa6,0xa7,0xa7,0xa8,0xa8 +}; +const uint8_t animframe_0480[] = { + 3,0xa9,0xa9,0xa9 +}; +const uint8_t animframe_0484[] = { + 2,0xa9,0xaa +}; +const uint8_t animframe_0487[] = { + 6,0xab,0xab,0xab,0xac,0xac,0xac +}; +const uint8_t animframe_048e[] = { + 1,0xa1 +}; +const uint8_t animframe_0490[] = { + 12,0xa2,0xa2,0xa0,0xa0,0xa1,0xa1,0xa3,0xa3,0xa0,0xa0,0xa1,0xa1 +}; +const uint8_t animframe_049d[] = { + 16,0xa1,0xa1,0xa1,0x94,0x94,0x94,0x95,0x95,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1,0xa1 +}; +const uint8_t animframe_04af[] = { + 1,0xa5 +}; +const uint8_t animframe_04b1[] = { + 12,0xa6,0xa6,0xa4,0xa4,0xa5,0xa5,0xa7,0xa7,0xa4,0xa4,0xa5,0xa5 +}; +const uint8_t animframe_04be[] = { + 1,0xb5 +}; +const uint8_t animframe_04c0[] = { + 2,0xb6,0xb4 +}; +const uint8_t animframe_04c3[] = { + 1,0xa9 +}; +const uint8_t animframe_04c5[] = { + 12,0xaa,0xaa,0xa8,0xa8,0xa9,0xa9,0xab,0xab,0xa8,0xa8,0xa9,0xa9 +}; +const uint8_t animframe_04d2[] = { + 4,0xac,0xac,0xb3,0xb3 +}; +const uint8_t animframe_04d7[] = { + 1,0xa0 +}; +const uint8_t animframe_04d9[] = { + 2,0xa0,0xa1 +}; +const uint8_t animframe_04dc[] = { + 1,0x66 +}; +const uint8_t animframe_04de[] = { + 1,0x65 +}; +const uint8_t animframe_04e0[] = { + 1,0x67 +}; +const uint8_t animframe_04e2[] = { + 8,0x68,0x68,0x69,0x69,0x6a,0x6a,0x6a,0x6a +}; +const uint8_t animframe_04eb[] = { + 2,0x9f,0x9e +}; +const uint8_t animframe_04ee[] = { + 1,0xab +}; +const uint8_t animframe_04f0[] = { + 1,0xa8 +}; +const uint8_t animframe_04f2[] = { + 18,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x6f,0x6f,0x6f,0x70,0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x72 +}; +const uint8_t animframe_0505[] = { + 4,0xa5,0xa6,0xa5,0xa4 +}; +const uint8_t animframe_050a[] = { + 1,0xba +}; +const uint8_t animframe_050c[] = { + 1,0x6b +}; +const uint8_t animframe_050e[] = { + 1,0xa6 +}; +const uint8_t animframe_0510[] = { + 1,0xb2 +}; +const uint8_t animframe_0512[] = { + 1,0xb3 +}; +const uint8_t animframe_0514[] = { + 1,0xb1 +}; +const uint8_t animframe_0516[] = { + 1,0x96 +}; +const uint8_t animframe_0518[] = { + 1,0x7f +}; +const uint8_t animframe_051a[] = { + 1,0x80 +}; +const uint8_t animframe_051c[] = { + 1,0x81 +}; +const uint8_t animframe_051e[] = { + 1,0x82 +}; +const uint8_t animframe_0520[] = { + 1,0x83 +}; +const uint8_t animframe_0522[] = { + 1,0x84 +}; +const uint8_t animframe_0524[] = { + 1,0x85 +}; +const uint8_t animframe_0526[] = { + 1,0x86 +}; +const uint8_t animframe_0528[] = { + 1,0xb4 +}; +const uint8_t *animframes_059d[] = { + animframe_00a2,animframe_00a4,animframe_00ab,animframe_00ad, + animframe_00af,animframe_00b8,animframe_00bd,animframe_00bf, + animframe_00c1,animframe_00c3,animframe_00c5,animframe_00c7, + animframe_00cd,animframe_00d4,animframe_00d6,animframe_00db, + animframe_00dd,animframe_0110,animframe_0115,animframe_0126, + animframe_0128,animframe_0135,animframe_016a,animframe_016d, + animframe_017e,animframe_0182,animframe_0180,animframe_018b, + animframe_0198,animframe_019a,animframe_019c,animframe_01a3, + animframe_01a5,animframe_01a7,animframe_01b0,animframe_01b5, + animframe_01b7,animframe_01b9,animframe_01bb,animframe_01bd, + animframe_01bf,animframe_01c5,animframe_01cc,animframe_01ce, + animframe_01d3,animframe_01d5,animframe_0208,animframe_020d, + animframe_021e,animframe_0220,animframe_022d,animframe_0262, + animframe_0265,animframe_0276,animframe_027a,animframe_0278, + animframe_0283,animframe_0290,animframe_04dc,animframe_04de, + animframe_04e0,animframe_04e2,animframe_04eb,animframe_04ee, + animframe_0505,animframe_04f2,animframe_050c,animframe_050a, + animframe_050e,animframe_0510,animframe_04f0,animframe_0514, + animframe_0516,animframe_0518,animframe_051a,animframe_051c, + animframe_051e,animframe_0520,animframe_0522,animframe_0524, + animframe_0526,animframe_0528, 0, 0, + 0, 0, 0,animframe_029f, + animframe_0292,animframe_02a1,animframe_0292,animframe_0292, + animframe_0292,animframe_0292,animframe_0292,animframe_0292, + animframe_0292,animframe_0292,animframe_0292,animframe_0292, + animframe_0292,animframe_0292,animframe_0292,animframe_0292, + animframe_0292,animframe_0292,animframe_0292,animframe_0292, + animframe_0292,animframe_0292,animframe_0292,animframe_0292, + animframe_0292,animframe_0292,animframe_0292,animframe_0292, + animframe_02b3,animframe_02a6,animframe_02b5,animframe_02c2, + animframe_02a6,animframe_02a6,animframe_02a6,animframe_02a6, + animframe_02a6,animframe_02a6,animframe_02a6,animframe_02a6, + animframe_02a6,animframe_02a6,animframe_02a6,animframe_02a6, + animframe_02a6,animframe_02a6,animframe_02a6,animframe_02a6, + animframe_02a6,animframe_02a6,animframe_02a6,animframe_02a6, + animframe_02a6,animframe_02a6,animframe_02a6,animframe_02a6, + animframe_02a6,animframe_02cf,animframe_02cf,animframe_02d1, + animframe_02cf,animframe_02cf,animframe_02cf,animframe_02cf, + animframe_02cf,animframe_02cf,animframe_02cf,animframe_02cf, + animframe_02cf,animframe_02cf,animframe_02cf,animframe_02cf, + animframe_02cf,animframe_02cf,animframe_02cf,animframe_02cf, + animframe_02cf,animframe_02cf,animframe_02cf,animframe_02cf, + animframe_02cf,animframe_02cf,animframe_02cf,animframe_02cf, + animframe_02cf,animframe_02cf,animframe_02e2,animframe_02e4, + animframe_02e4,animframe_02e4,animframe_02e4,animframe_02e4, + animframe_02e4,animframe_02e4,animframe_02e4,animframe_02e4, + animframe_02e4,animframe_02e4,animframe_02e4,animframe_02e4, + animframe_02e4,animframe_02e4,animframe_02e4,animframe_02e4, + animframe_02e4,animframe_02e4,animframe_02e4,animframe_02e4, + animframe_02e4,animframe_02e4,animframe_02e4,animframe_02e4, + animframe_02e4,animframe_02e4,animframe_02e4,animframe_02e9, + animframe_02e9,animframe_02eb,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02ee,animframe_02ee,animframe_02ee,animframe_02ee, + animframe_02ee,animframe_02ee,animframe_02ee,animframe_02ee, + animframe_02ee,animframe_02ee,animframe_02ee,animframe_02ee, + animframe_02ee,animframe_02ee,animframe_02ee,animframe_02ee, + animframe_02ee,animframe_02ee,animframe_02ee,animframe_02ee, + animframe_02ee,animframe_02ee,animframe_02ee,animframe_02ee, + animframe_02ee,animframe_02ee,animframe_02ee,animframe_02ee, + animframe_02ee,animframe_02f5,animframe_02f5,animframe_02f5, + animframe_02f5,animframe_02f5,animframe_02f5,animframe_02f5, + animframe_02f5,animframe_02f5,animframe_02f5,animframe_02f5, + animframe_02f5,animframe_02f5,animframe_02f5,animframe_02f5, + animframe_02f5,animframe_02f5,animframe_02f5,animframe_02f5, + animframe_02f5,animframe_02f5,animframe_02f5,animframe_02f5, + animframe_02f5,animframe_02f5,animframe_02f5,animframe_02f5, + animframe_02f5,animframe_02f5,animframe_04f2,animframe_04f2, + animframe_04f2,animframe_04f2,animframe_04f2,animframe_04f2, + animframe_04f2,animframe_04f2,animframe_04f2,animframe_04f2, + animframe_04f2,animframe_04f2,animframe_04f2,animframe_04f2, + animframe_04f2,animframe_04f2,animframe_04f2,animframe_04f2, + animframe_04f2,animframe_04f2,animframe_04f2,animframe_04f2, + animframe_04f2,animframe_04f2,animframe_04f2,animframe_04f2, + animframe_04f2,animframe_04f2,animframe_04f2,animframe_02fe, + animframe_0300,animframe_030d,animframe_0300,animframe_0300, + animframe_0300,animframe_0300,animframe_0300,animframe_0300, + animframe_0300,animframe_0300,animframe_0300,animframe_0300, + animframe_0300,animframe_0300,animframe_0300,animframe_0300, + animframe_0300,animframe_0300,animframe_0300,animframe_0300, + animframe_0300,animframe_0300,animframe_0300,animframe_0300, + animframe_0300,animframe_0300,animframe_0300,animframe_0300, + animframe_0316,animframe_0318,animframe_0325,animframe_0318, + animframe_0318,animframe_0318,animframe_0318,animframe_0318, + animframe_0318,animframe_0318,animframe_0318,animframe_0318, + animframe_0318,animframe_0318,animframe_0318,animframe_0318, + animframe_0318,animframe_0318,animframe_0318,animframe_0318, + animframe_0318,animframe_0318,animframe_0318,animframe_0318, + animframe_0318,animframe_0318,animframe_0318,animframe_0318, + animframe_0318,animframe_032e,animframe_0330,animframe_033d, + animframe_0330,animframe_0330,animframe_0330,animframe_0330, + animframe_0330,animframe_0330,animframe_0330,animframe_0330, + animframe_0330,animframe_0330,animframe_0330,animframe_0330, + animframe_0330,animframe_0330,animframe_0330,animframe_0330, + animframe_0330,animframe_0330,animframe_0330,animframe_0330, + animframe_0330,animframe_0330,animframe_0330,animframe_0330, + animframe_0330,animframe_0330,animframe_034e,animframe_0350, + animframe_035d,animframe_0350,animframe_0350,animframe_0350, + animframe_0350,animframe_0350,animframe_0350,animframe_0350, + animframe_0350,animframe_0350,animframe_0350,animframe_0350, + animframe_0350,animframe_0350,animframe_0350,animframe_0350, + animframe_0350,animframe_0350,animframe_0350,animframe_0350, + animframe_0350,animframe_0350,animframe_0350,animframe_0350, + animframe_0350,animframe_0350,animframe_0350,animframe_036e, + animframe_0370,animframe_0370,animframe_0370,animframe_0370, + animframe_0370,animframe_0370,animframe_0370,animframe_0370, + animframe_0370,animframe_0370,animframe_0370,animframe_0370, + animframe_0370,animframe_0370,animframe_0370,animframe_0370, + animframe_0370,animframe_0370,animframe_0370,animframe_0370, + animframe_0370,animframe_0370,animframe_0370,animframe_0370, + animframe_0370,animframe_0370,animframe_0370,animframe_0370, + animframe_0375,animframe_0375,animframe_0384,animframe_0375, + animframe_0375,animframe_0375,animframe_0375,animframe_0375, + animframe_0375,animframe_0375,animframe_0375,animframe_0375, + animframe_0375,animframe_0375,animframe_0375,animframe_0375, + animframe_0375,animframe_0375,animframe_0375,animframe_0375, + animframe_0375,animframe_0375,animframe_0375,animframe_0375, + animframe_0375,animframe_0375,animframe_0375,animframe_0375, + animframe_0375,animframe_0375,animframe_0377,animframe_0384, + animframe_0377,animframe_0377,animframe_0377,animframe_0377, + animframe_0377,animframe_0377,animframe_0377,animframe_0377, + animframe_0377,animframe_0377,animframe_0377,animframe_0377, + animframe_0377,animframe_0377,animframe_0377,animframe_0377, + animframe_0377,animframe_0377,animframe_0377,animframe_0377, + animframe_0377,animframe_0377,animframe_0377,animframe_0377, + animframe_0377,animframe_0377,animframe_0395,animframe_0397, + animframe_03a4,animframe_0397,animframe_0397,animframe_0397, + animframe_0397,animframe_0397,animframe_0397,animframe_0397, + animframe_0397,animframe_0397,animframe_0397,animframe_0397, + animframe_0397,animframe_0397,animframe_0397,animframe_0397, + animframe_0397,animframe_0397,animframe_0397,animframe_0397, + animframe_0397,animframe_0397,animframe_0397,animframe_0397, + animframe_0397,animframe_0397,animframe_0397,animframe_03a9, + animframe_03ab,animframe_03b4,animframe_03ab,animframe_03ab, + animframe_03ab,animframe_03ab,animframe_03ab,animframe_03ab, + animframe_03ab,animframe_03ab,animframe_03ab,animframe_03ab, + animframe_03ab,animframe_03ab,animframe_03ab,animframe_03ab, + animframe_03ab,animframe_03ab,animframe_03ab,animframe_03ab, + animframe_03ab,animframe_03ab,animframe_03ab,animframe_03ab, + animframe_03ab,animframe_03ab,animframe_03ab,animframe_03ab, + animframe_03bd,animframe_03bf,animframe_03cc,animframe_03bf, + animframe_03bf,animframe_03bf,animframe_03bf,animframe_03bf, + animframe_03bf,animframe_03bf,animframe_03bf,animframe_03bf, + animframe_03bf,animframe_03bf,animframe_03bf,animframe_03bf, + animframe_03bf,animframe_03bf,animframe_03bf,animframe_03bf, + animframe_03bf,animframe_03bf,animframe_03bf,animframe_03bf, + animframe_03bf,animframe_03bf,animframe_03bf,animframe_03bf, + animframe_03bf,animframe_03d1,animframe_03d3,animframe_03e0, + animframe_03d3,animframe_03d3,animframe_03d3,animframe_03d3, + animframe_03d3,animframe_03d3,animframe_03d3,animframe_03d3, + animframe_03d3,animframe_03d3,animframe_03d3,animframe_03d3, + animframe_03d3,animframe_03d3,animframe_03d3,animframe_03d3, + animframe_03d3,animframe_03d3,animframe_03d3,animframe_03d3, + animframe_03d3,animframe_03d3,animframe_03d3,animframe_03d3, + animframe_03d3,animframe_03d3,animframe_0512,animframe_0512, + animframe_0512,animframe_0512,animframe_0512,animframe_0512, + animframe_0512,animframe_0512,animframe_0512,animframe_0512, + animframe_0512,animframe_0512,animframe_0512,animframe_0512, + animframe_0512,animframe_0512,animframe_0512,animframe_0512, + animframe_0512,animframe_0512,animframe_0512,animframe_0512, + animframe_0512,animframe_0512,animframe_0512,animframe_0512, + animframe_0512,animframe_0512,animframe_0512,animframe_03f1, + animframe_03f3,animframe_0400,animframe_03f3,animframe_03f3, + animframe_03f3,animframe_03f3,animframe_03f3,animframe_03f3, + animframe_03f3,animframe_03f3,animframe_03f3,animframe_03f3, + animframe_03f3,animframe_03f3,animframe_03f3,animframe_03f3, + animframe_03f3,animframe_03f3,animframe_03f3,animframe_03f3, + animframe_03f3,animframe_03f3,animframe_03f3,animframe_03f3, + animframe_03f3,animframe_03f3,animframe_03f3,animframe_03f3, + animframe_0412,animframe_0414,animframe_0421,animframe_0414, + animframe_0414,animframe_0414,animframe_0414,animframe_0414, + animframe_0414,animframe_0414,animframe_0414,animframe_0414, + animframe_0414,animframe_0414,animframe_0414,animframe_0414, + animframe_0414,animframe_0414,animframe_0414,animframe_0414, + animframe_0414,animframe_0414,animframe_0414,animframe_0414, + animframe_0414,animframe_0414,animframe_0414,animframe_0414, + animframe_0414,animframe_0433,animframe_0435,animframe_0442, + animframe_0435,animframe_0435,animframe_0435,animframe_0435, + animframe_0435,animframe_0435,animframe_0435,animframe_0435, + animframe_0435,animframe_0435,animframe_0435,animframe_0435, + animframe_0435,animframe_0435,animframe_0435,animframe_0435, + animframe_0435,animframe_0435,animframe_0435,animframe_0435, + animframe_0435,animframe_0435,animframe_0435,animframe_0435, + animframe_0435,animframe_0435,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_0458, + animframe_0458,animframe_0458,animframe_0458,animframe_0458, + animframe_0458,animframe_0458,animframe_0458,animframe_0458, + animframe_0458,animframe_0458,animframe_0458,animframe_0458, + animframe_0458,animframe_0458,animframe_0458,animframe_0458, + animframe_0458,animframe_0458,animframe_0458,animframe_0458, + animframe_0458,animframe_0458,animframe_0458,animframe_0458, + animframe_0458,animframe_0458,animframe_0458,animframe_0458, + animframe_0465,animframe_0465,animframe_0465,animframe_0465, + animframe_0465,animframe_0465,animframe_0465,animframe_0465, + animframe_0465,animframe_0465,animframe_0465,animframe_0465, + animframe_0465,animframe_0465,animframe_0465,animframe_0465, + animframe_0465,animframe_0465,animframe_0465,animframe_0465, + animframe_0465,animframe_0465,animframe_0465,animframe_0465, + animframe_0465,animframe_0465,animframe_0465,animframe_0465, + animframe_0465,animframe_0469,animframe_0469,animframe_0469, + animframe_0469,animframe_0469,animframe_0469,animframe_0469, + animframe_0469,animframe_0469,animframe_0469,animframe_0469, + animframe_0469,animframe_0469,animframe_0469,animframe_0469, + animframe_0469,animframe_0469,animframe_0469,animframe_0469, + animframe_0469,animframe_0469,animframe_0469,animframe_0469, + animframe_0469,animframe_0469,animframe_0469,animframe_0469, + animframe_0469,animframe_0469,animframe_0470,animframe_0470, + animframe_0470,animframe_0470,animframe_0470,animframe_0470, + animframe_0470,animframe_0470,animframe_0470,animframe_0470, + animframe_0470,animframe_0470,animframe_0470,animframe_0470, + animframe_0470,animframe_0470,animframe_0470,animframe_0470, + animframe_0470,animframe_0470,animframe_0470,animframe_0470, + animframe_0470,animframe_0470,animframe_0470,animframe_0470, + animframe_0470,animframe_0470,animframe_0470,animframe_0479, + animframe_0479,animframe_0479,animframe_0479,animframe_0479, + animframe_0479,animframe_0479,animframe_0479,animframe_0479, + animframe_0479,animframe_0479,animframe_0479,animframe_0479, + animframe_0479,animframe_0479,animframe_0479,animframe_0479, + animframe_0479,animframe_0479,animframe_0479,animframe_0479, + animframe_0479,animframe_0479,animframe_0479,animframe_0479, + animframe_0479,animframe_0479,animframe_0479,animframe_0479, + animframe_0480,animframe_0480,animframe_0484,animframe_0480, + animframe_0480,animframe_0480,animframe_0480,animframe_0480, + animframe_0480,animframe_0480,animframe_0480,animframe_0480, + animframe_0480,animframe_0480,animframe_0480,animframe_0480, + animframe_0480,animframe_0480,animframe_0480,animframe_0480, + animframe_0480,animframe_0480,animframe_0480,animframe_0480, + animframe_0480,animframe_0480,animframe_0480,animframe_0480, + animframe_0480,animframe_0487,animframe_0487,animframe_0487, + animframe_0487,animframe_0487,animframe_0487,animframe_0487, + animframe_0487,animframe_0487,animframe_0487,animframe_0487, + animframe_0487,animframe_0487,animframe_0487,animframe_0487, + animframe_0487,animframe_0487,animframe_0487,animframe_0487, + animframe_0487,animframe_0487,animframe_0487,animframe_0487, + animframe_0487,animframe_0487,animframe_0487,animframe_0487, + animframe_0487,animframe_0487,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_044b, + animframe_044b,animframe_044b,animframe_044b,animframe_02e9, + animframe_02e9,animframe_02eb,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_02e9,animframe_02e9,animframe_02e9,animframe_02e9, + animframe_048e,animframe_0490,animframe_049d,animframe_0490, + animframe_0490,animframe_0490,animframe_0490,animframe_0490, + animframe_0490,animframe_0490,animframe_0490,animframe_0490, + animframe_0490,animframe_0490,animframe_0490,animframe_0490, + animframe_0490,animframe_0490,animframe_0490,animframe_0490, + animframe_0490,animframe_0490,animframe_0490,animframe_0490, + animframe_0490,animframe_0490,animframe_0490,animframe_0490, + animframe_0490,animframe_04af,animframe_04b1,animframe_04b1, + animframe_04b1,animframe_04b1,animframe_04b1,animframe_04b1, + animframe_04b1,animframe_04b1,animframe_04b1,animframe_04b1, + animframe_04b1,animframe_04b1,animframe_04b1,animframe_04b1, + animframe_04b1,animframe_04b1,animframe_04b1,animframe_04b1, + animframe_04b1,animframe_04b1,animframe_04b1,animframe_04b1, + animframe_04b1,animframe_04b1,animframe_04b1,animframe_04b1, + animframe_04b1,animframe_04b1,animframe_04be,animframe_04c0, + animframe_04c0,animframe_04c0,animframe_04c0,animframe_04c0, + animframe_04c0,animframe_04c0,animframe_04c0,animframe_04c0, + animframe_04c0,animframe_04c0,animframe_04c0,animframe_04c0, + animframe_04c0,animframe_04c0,animframe_04c0,animframe_04c0, + animframe_04c0,animframe_04c0,animframe_04c0,animframe_04c0, + animframe_04c0,animframe_04c0,animframe_04c0,animframe_04c0, + animframe_04c0,animframe_04c0,animframe_04c0,animframe_04c3, + animframe_04c5,animframe_04d2,animframe_04c5,animframe_04c5, + animframe_04c5,animframe_04c5,animframe_04c5,animframe_04c5, + animframe_04c5,animframe_04c5,animframe_04c5,animframe_04c5, + animframe_04c5,animframe_04c5,animframe_04c5,animframe_04c5, + animframe_04c5,animframe_04c5,animframe_04c5,animframe_04c5, + animframe_04c5,animframe_04c5,animframe_04c5,animframe_04c5, + animframe_04c5,animframe_04c5,animframe_04c5,animframe_04c5, + animframe_04d7,animframe_04d9,animframe_04d9,animframe_04d7, + animframe_04d7,animframe_04d7,animframe_04d7,animframe_04d7, + animframe_04d7,animframe_04d7,animframe_04d7,animframe_04d7, + animframe_04d7,animframe_04d7,animframe_04d7,animframe_04d7, + animframe_04d7,animframe_04d7,animframe_04d7,animframe_04d7, + animframe_04d7,animframe_04d7,animframe_04d7,animframe_04d7, + animframe_04d7,animframe_04d7,animframe_04d7,animframe_04d7, + animframe_04d7 +}; +uint16_t level_obj_w[] = { + 0x000A,0x000A,0x0008,0x000C,0x000A,0x000A,0x000A,0x0012,0x000A,0x0010,0x0000,0x000A,0x000A,0x000A,0x000A,0x000A, + 0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x000A,0x0008,0x000A,0x000A, + 0x0005,0x000A,0x000A,0x0018,0x000A,0x000A,0x000A,0x000A,0x0012 +}; +uint16_t level_obj_h[] = { + 0x001A,0x001A,0x000A,0x001C,0x001C,0x001E,0x000A,0x000F,0x0010,0x001E,0x0000,0x001E,0x001E,0x001E,0x0000,0x001E, + 0x001E,0x001E,0x001E,0x0010,0x001E,0x001E,0x001E,0x001E,0x001E,0x001E,0x001E,0x001E,0x001E,0x0010,0x001E,0x0014, + 0x0010,0x0010,0x001E,0x0014,0x001E,0x001E,0x0012,0x001E,0x000F +}; +const uint16_t level_obj_type[] = { + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0001,0x0000,0x0002,0x0000,0x0002,0x0002,0x0002,0x0000,0x0002, + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0002,0x0000,0x0002,0x0001,0x0002,0x0002,0x0002,0x0002,0x0001 +}; +uint8_t level_tiledata_1bc0[] = { + 0x01,0x10,0x61,0x61,0x61,0x61,0x5B,0x5B,0x5B,0x5B,0x61,0x61,0x61,0x61,0x5D,0x5D, + 0x5D,0x5D +}; +uint8_t level_tiledata_1bd2[] = { + 0x01,0x10,0xCE,0xCE,0xCE,0xCE,0xCF,0xCF,0xCF,0xCF,0xD0,0xD0,0xD0,0xD0,0xCF,0xCF, + 0xCF,0xCF +}; +uint8_t level_tiledata_1be4[] = { + 0x01,0x02,0x3F,0x74 +}; +uint8_t level_tiledata_1bec[] = { + 0x01,0x06,0x69,0x69,0x6A,0x69,0x6A,0x6A +}; +uint8_t level_tiledata_1bf4[] = { + 0x01,0x10,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x92,0x93,0x92,0x93,0x92, + 0x93,0x92 +}; +uint8_t level_tiledata_1c06[] = { + 0x01,0x10,0x92,0x93,0x92,0x93,0x92,0x93,0x92,0x95,0x95,0x95,0x95,0x95,0x95,0x95, + 0x95,0x95 +}; +uint8_t level_tiledata_1c18[] = { + 0x01,0x04,0xA2,0xA2,0xA3,0xA3 +}; +uint8_t level_tiledata_1c1e[] = { + 0x01,0x10,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0x95,0xA6,0xA7,0xA8,0xA7,0xA8, + 0xA6,0xA8 +}; +uint8_t level_tiledata_1c30[] = { + 0x01,0x10,0xA7,0xA8,0xA7,0xA6,0xA6,0xA8,0xA7,0x95,0x95,0x95,0x95,0x95,0x95,0x95, + 0x95,0x95 +}; +uint8_t level_tiledata_1c42[] = { + 0x01,0x1A,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9,0xA9, + 0xA9,0xA9,0xA9,0xAB,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAD,0xAB +}; +uint8_t level_tiledata_1c5e[] = { + 0x01,0x1A,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, + 0xAA,0xAA,0xAA,0xAC,0xAE,0xAE,0xAE,0xAE,0xAE,0xAE,0xAE,0xAC +}; +uint8_t level_tiledata_1c7a[] = { + 0x01,0x1C,0xAF,0xAF,0xAF,0xAF,0xAF,0xAF,0xAF,0xAF,0xAF,0xB0,0xB1,0xB1,0xB1,0xB1, + 0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB1,0xB0 +}; +uint8_t level_tiledata_1c98[] = { + 0x01,0x1C,0xB2,0xB2,0xB2,0xB2,0xB2,0xB2,0xB2,0xB2,0xB2,0xB3,0xB4,0xB4,0xB4,0xB4, + 0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB4,0xB3 +}; +uint8_t level_tiledata_1cb6[] = { + 0x01,0x02,0xB9,0xBA +}; +uint8_t level_tiledata_1cba[] = { + 0x01,0x02,0xBA,0xB9 +}; +uint8_t level_tiledata_1cbe[] = { + 0x01,0x02,0xD2,0xD3 +}; +uint8_t level_tiledata_1cc2[] = { + 0x01,0x02,0xD6,0xD7 +}; +uint8_t level_tiledata_1cc6[] = { + 0x01,0x02,0x29,0x71 +}; +uint8_t level_tiledata_1cca[] = { + 0x01,0x02,0x28,0x7A +}; +uint8_t level_tiledata_1cce[] = { + 0x01,0x04,0x93,0x92,0xA7,0x92 +}; +uint8_t level_tiledata_1cd4[] = { + 0x01,0x03,0x85,0x84,0x83 +}; +uint8_t level_tiledata_1cd9[] = { + 0x01,0x03,0x8F,0x90,0x91 +}; +uint8_t level_tiledata_1cde[] = { + 0x01,0x04,0x80,0x81,0x82,0x8C +}; +uint8_t level_tiledata_1ce4[] = { + 0x01,0x04,0xDD,0xDC,0xDB,0xDA +}; +uint8_t level_tiledata_1cea[] = { + 0x01,0x03,0x86,0x87,0x88 +}; +uint8_t level_tiledata_1cef[] = { + 0x01,0x03,0x89,0x8A,0x8B +}; +uint8_t level_tiledata_1cf4[] = { + 0x01,0x03,0xBC,0xBE,0xC0 +}; +uint8_t level_tiledata_1cf9[] = { + 0x01,0x03,0xBD,0xBF,0xC1 +}; +uint8_t level_tiledata_1cfe[] = { + 0x01,0x02,0xC2,0xC3 +}; +uint8_t level_tiledata_1d1c[] = { + 0x01,0x03,0xFD,0xFC,0xFB +}; +uint8_t level_tiledata_1d21[] = { + 0x01,0x03,0xF0,0xF1,0xF2 +}; +uint8_t level_tiledata_1d26[] = { + 0x01,0x03,0xF8,0xF9,0xFA +}; +uint8_t level_tiledata_1d2b[] = { + 0x01,0x03,0xEF,0xEE,0xED +}; +uint8_t level_tiledata_1d30[] = { + 0x01,0x03,0x72,0x73,0x74 +}; +uint8_t level_tiledata_1d35[] = { + 0x01,0x03,0x64,0x65,0x66 +}; +uint8_t level_tiledata_1d3a[] = { + 0x01,0x03,0x86,0x87,0x88 +}; +uint8_t level_tiledata_1d3f[] = { + 0x01,0x03,0x89,0x8A,0x8B +}; +uint8_t level_tiledata_1d44[] = { + 0x01,0x03,0x8C,0x8D,0x8E +}; +uint8_t level_tiledata_1d49[] = { + 0x01,0x03,0x9A,0x9B,0x9C +}; +uint8_t level_tiledata_1d4e[] = { + 0x01,0x03,0x9D,0x9E,0x9F +}; +uint8_t level_tiledata_1d53[] = { + 0x01,0x03,0xA0,0xB4,0xC8 +}; +uint8_t level_tiledata_1d58[] = { + 0x01,0x03,0xA1,0xB5,0xC9 +}; +uint8_t level_tiledata_1d5d[] = { + 0x01,0x03,0xA2,0xB6,0xCA +}; +uint8_t level_tiledata_1d62[] = { + 0x01,0x03,0xAE,0xAF,0xB0 +}; +uint8_t level_tiledata_1d67[] = { + 0x01,0x03,0xB1,0xB2,0xB3 +}; +uint8_t level_tiledata_1d6c[] = { + 0x01,0x03,0xC2,0xC3,0xC4 +}; +uint8_t level_tiledata_1d71[] = { + 0x01,0x03,0xC5,0xC6,0xC7 +}; +uint8_t level_tiledata_1d76[] = { + 0x01,0x03,0xD8,0xD9,0xDA +}; +uint8_t level_tiledata_1d7b[] = { + 0x01,0x14,0xE4,0xE4,0xE4,0xE4,0xE5,0xE5,0xE6,0xE6,0xE6,0xE6,0xE6,0xE6,0xE5,0xE5, + 0xE4,0xE4,0xE4,0xE4,0xE4,0xE4 +}; +uint8_t level_tiledata_1d91[] = { + 0x01,0x18,0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,0xF9,0xFA,0xFA,0xFB,0xFB, + 0xFB,0xFB,0xFB,0xFB,0xFA,0xFA,0xF9,0xF9,0xF9,0xF9 +}; +uint8_t level_tiledata_1dab[] = { + 0x01,0x0A,0xDF,0xE0,0xE0,0xE0,0xDF,0xE0,0xE0,0xE0,0xDF,0xE0 +}; +uint8_t level_tiledata_1db7[] = { + 0x01,0x02,0x8F,0xA3 +}; +uint8_t level_tiledata_1dbb[] = { + 0x01,0x02,0x84,0x97 +}; +uint8_t level_tiledata_1d02[] = { + 0x01,0x10,0xB8,0xB8,0xB8,0xB8,0xB9,0xB9,0xB9,0xB9,0xBA,0xBA,0xBA,0xBA,0xB9,0xB9, + 0xB9,0xB9 +}; +uint8_t level_tiledata_1d14[] = { + 0x01,0x02,0x46,0x54 +}; +uint8_t level_tiledata_1d18[] = { + 0x01,0x02,0x45,0x55 +}; +uint8_t level_tiledata_1dfb[] = { + 0x01,0x03,0x17,0x28,0x29 +}; +uint8_t level_tiledata_1dbf[] = { + 0x01,0x06,0x1B,0x3F,0x40,0x3F,0x1B,0x40 +}; +uint8_t level_tiledata_1dc7[] = { + 0x01,0x06,0x2A,0x2B,0x38,0x2B,0x2A,0x38 +}; +uint8_t level_tiledata_1dcf[] = { + 0x01,0x14,0x2C,0x2D,0x2D,0x2C,0x2D,0x2C,0x2D,0x2C,0x2D,0x2C,0x5A,0x5A,0x5A,0x5A, + 0x5A,0x5A,0x5A,0x5A,0x5A,0x5A +}; +uint8_t level_tiledata_1de5[] = { + 0x01,0x14,0x0A,0x2E,0x2F,0x26,0x2F,0x26,0x2E,0x2F,0x26,0x2E,0x26,0x0A,0x0A,0x0A, + 0x0A,0x0A,0x0A,0x0A,0x0A,0x0A +}; +uint8_t level_tiledata_1e39[] = { + 0x01,0x03,0x9F,0xA5,0xA6 +}; +uint8_t level_tiledata_1e3e[] = { + 0x01,0x03,0x3C,0x47,0x67 +}; +uint8_t level_tiledata_1e00[] = { + 0x01,0x03,0x9D,0x9E,0xAE +}; +uint8_t level_tiledata_1e05[] = { + 0x01,0x03,0xCD,0xCE,0xCF +}; +uint8_t level_tiledata_1e43[] = { + 0x01,0x03,0xF2,0xF3,0xF4 +}; +uint8_t level_tiledata_1e0f[] = { + 0x01,0x03,0xA5,0xA6,0xA7 +}; +uint8_t level_tiledata_1b54[] = { + 0x01,0x2C,0x6E,0x6E,0x6E,0x6E,0x6E,0x6E,0x6F,0x70,0x71,0x7B,0x7B,0x7B,0x7B,0x7B, + 0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B, + 0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x71,0x70,0x6F,0x6E +}; +uint8_t level_tiledata_1b82[] = { + 0x01,0x2C,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x6E,0x6F,0x70,0x71,0x7B, + 0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x7B, + 0x7B,0x7B,0x7B,0x7B,0x7B,0x7B,0x71,0x70,0x6F,0x6E,0x33,0x33,0x33,0x33 +}; +uint8_t level_tiledata_1be8[] = { + 0x01,0x02,0xD6,0xD7 +}; +uint8_t level_tiledata_1e0a[] = { + 0x01,0x03,0xEC,0xED,0xEE +}; +uint8_t level_tiledata_1e14[] = { + 0x01,0x03,0x6D,0x6E,0x6F +}; +uint8_t level_tiledata_1e19[] = { + 0x01,0x06,0x67,0x69,0x6B,0x69,0x6B,0x67 +}; +uint8_t level_tiledata_1e21[] = { + 0x01,0x06,0x68,0x6A,0x6C,0x68,0x6A,0x6C +}; +uint8_t level_tiledata_1e29[] = { + 0x01,0x06,0xE6,0xE8,0xEA,0xE8,0xEA,0xE6 +}; +uint8_t level_tiledata_1e31[] = { + 0x01,0x06,0xE7,0xE9,0xEB,0xE9,0xE7,0xEB +}; +uint8_t level_tiledata_1e48[] = { + 0x01,0x02,0x83,0xC7 +}; +uint8_t level_tiledata_1e4c[] = { + 0x01,0x02,0x95,0xD9 +}; +uint8_t level_tiledata_1e50[] = { + 0x01,0x02,0xAA,0xF7 +}; +uint8_t level_tiledata_1e54[] = { + 0x01,0x06,0xB5,0xBA,0xC4,0xCB,0xCC,0xDB +}; +uint8_t level_tiledata_1e5c[] = { + 0x01,0x06,0xF8,0xDC,0xE0,0xE1,0xE2,0xE3 +}; +uint8_t level_tiledata_1e64[] = { + 0x01,0x06,0x02,0xDE,0xDF,0xE0,0xE1,0xE2 +}; +uint8_t level_tiledata_1e6c[] = { + 0x01,0x06,0x75,0xE3,0xE4,0xE5,0xE6,0xE7 +}; +uint8_t level_tiledata_1e74[] = { + 0x01,0x06,0x30,0x32,0x50,0x52,0x64,0x66 +}; +uint8_t level_tiledata_1e7c[] = { + 0x01,0x06,0x07,0x51,0x53,0x54,0x56,0x57 +}; +uint8_t level_tiledata_1e84[] = { + 0x01,0x06,0x18,0x12,0x26,0x3A,0x48,0x49 +}; +uint8_t *level_tilesdata_1e8c[] = { + level_tiledata_1bc0,level_tiledata_1bd2,level_tiledata_1be4,level_tiledata_1bec, + level_tiledata_1bf4,level_tiledata_1c06,level_tiledata_1c18,level_tiledata_1c1e, + level_tiledata_1c30,level_tiledata_1c42,level_tiledata_1c5e,level_tiledata_1c7a, + level_tiledata_1c98,level_tiledata_1cb6,level_tiledata_1cba,level_tiledata_1cbe, + level_tiledata_1cc2,level_tiledata_1cc6,level_tiledata_1cca,level_tiledata_1cce, + level_tiledata_1cd4,level_tiledata_1cd9,level_tiledata_1cde,level_tiledata_1ce4, + level_tiledata_1cea,level_tiledata_1cef,level_tiledata_1cf4,level_tiledata_1cf9, + level_tiledata_1cfe,level_tiledata_1d1c,level_tiledata_1d21,level_tiledata_1d26, + level_tiledata_1d2b,level_tiledata_1d30,level_tiledata_1d35,level_tiledata_1d3a, + level_tiledata_1d3f,level_tiledata_1d44,level_tiledata_1d49,level_tiledata_1d4e, + level_tiledata_1d53,level_tiledata_1d58,level_tiledata_1d5d,level_tiledata_1d62, + level_tiledata_1d67,level_tiledata_1d6c,level_tiledata_1d71,level_tiledata_1d76, + level_tiledata_1d7b,level_tiledata_1d91,level_tiledata_1dab,level_tiledata_1db7, + level_tiledata_1dbb,level_tiledata_1d02,level_tiledata_1d14,level_tiledata_1d18, + level_tiledata_1dfb,level_tiledata_1dbf,level_tiledata_1dc7,level_tiledata_1dcf, + level_tiledata_1de5,level_tiledata_1e39,level_tiledata_1e3e,level_tiledata_1e00, + level_tiledata_1e05,level_tiledata_1e43,level_tiledata_1e0f,level_tiledata_1b54, + level_tiledata_1b82,level_tiledata_1be8,level_tiledata_1e0a,level_tiledata_1e14, + level_tiledata_1e19,level_tiledata_1e21,level_tiledata_1e29,level_tiledata_1e31, + level_tiledata_1e48,level_tiledata_1e4c,level_tiledata_1e50,level_tiledata_1e54, + level_tiledata_1e5c,level_tiledata_1e64,level_tiledata_1e6c,level_tiledata_1e74, + level_tiledata_1e7c,level_tiledata_1e84, 0 +}; +uint8_t level_tiledata_1afc[] = { + 0x01,0x01,0xE4,0xE5,0xE6,0xE7,0x0F +}; +uint8_t level_tiledata_1b03[] = { + 0x01,0x01,0xE8,0xE9,0xEA,0xEB,0x22 +}; +uint8_t level_tiledata_1b1f[] = { + 0x01,0x01,0xD6,0xD7,0xD8,0x14 +}; +uint8_t level_tiledata_1b25[] = { + 0x01,0x01,0xDA,0xDB,0xDC,0x00 +}; +uint8_t level_tiledata_1b2b[] = { + 0x01,0x01,0xA7,0xE7,0xE8,0x60 +}; +uint8_t level_tiledata_1b31[] = { + 0x01,0x01,0x21,0x22,0x23,0x24,0x14 +}; +uint8_t level_tiledata_1b38[] = { + 0x01,0x01,0xD6,0xD7,0xD8,0xD9,0x03 +}; +uint8_t level_tiledata_1b3f[] = { + 0x01,0x01,0x45,0x55,0x57,0x65,0x14 +}; +uint8_t level_tiledata_1b46[] = { + 0x01,0x01,0xC2,0xC3,0xC4,0xC5,0x16 +}; +uint8_t level_tiledata_1b4d[] = { + 0x01,0x01,0x92,0x93,0xB7,0xC7,0x3D +}; +uint8_t level_tiledata_1bb0[] = { + 0x01,0x01,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5 +}; +uint8_t level_tiledata_1bb8[] = { + 0x01,0x01,0xBC,0xBD,0xBE,0xBF,0xA8,0xA9 +}; +uint8_t level_tiledata_1b11[] = { + 0x01,0x01,0x2A,0x2B,0x2C,0x2D,0x05 +}; +uint8_t level_tiledata_1b18[] = { + 0x01,0x01,0x2E,0x2F,0x30,0x31 +}; +uint8_t level_tiledata_1b0a[] = { + 0x01,0x01,0xFA,0xFB,0xFC,0xFD,0xBC +}; +uint8_t *level_tilesdata_1fe8[] = { + level_tiledata_1afc,level_tiledata_1b03,level_tiledata_1b1f,level_tiledata_1b25, + level_tiledata_1b2b,level_tiledata_1b31,level_tiledata_1b38,level_tiledata_1b3f, + level_tiledata_1b46,level_tiledata_1b4d,level_tiledata_1b54,level_tiledata_1b82, + level_tiledata_1bb0,level_tiledata_1bb8,level_tiledata_1b11,level_tiledata_1b18, + level_tiledata_1b0a, 0 +}; +const uint8_t level_trigger_3316[] = { + 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F +}; +const uint8_t level_trigger_3326[] = { + 0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00 +}; +const uint8_t level_trigger_3336[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F +}; +const uint8_t level_trigger_3346[] = { + 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08 +}; +const uint8_t *level_triggersdata_3356[] = { + level_trigger_3316,level_trigger_3326,level_trigger_3336,level_trigger_3346 +}; +const uint8_t level_trigger_1831[] = { + 0x02,0x03,0x17,0x1D,0xF1,0x00,0x1D,0x1A,0xB0,0x00,0x1D,0x1B,0xB3,0x00,0x17,0x1D, + 0xF1,0x00,0x1D,0x1A,0xAF,0x00,0x1D,0x1B,0xB2,0x00 +}; +const uint8_t level_trigger_187f[] = { + 0x01,0x07,0x72,0x33,0x12,0x00,0x72,0x34,0x12,0x00,0x73,0x33,0x0F,0x00,0x73,0x34, + 0x0F,0x00,0x74,0x33,0x0F,0x00,0x74,0x34,0x0F,0x00,0x75,0x3C,0x0F,0x00 +}; +const uint8_t level_trigger_189d[] = { + 0x01,0x0A,0x0E,0x00,0x16,0x84 +}; +const uint8_t level_trigger_18a3[] = { + 0x01,0x0A,0x0A,0x00,0x16,0x8C +}; +const uint8_t level_trigger_18a9[] = { + 0x01,0x0A,0x05,0x00,0x16,0xBC +}; +const uint8_t level_trigger_18af[] = { + 0x01,0x0A,0x05,0x00,0x16,0x0C +}; +const uint8_t level_trigger_1923[] = { + 0x01,0x0B,0xE4,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_192e[] = { + 0x01,0x0B,0xE4,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1939[] = { + 0x01,0x0B,0xE4,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1944[] = { + 0x01,0x0C,0xE4,0x32,0x00,0x00,0x00,0x00,0x00,0x15,0x00 +}; +const uint8_t level_trigger_194f[] = { + 0x01,0x0C,0xE4,0x00,0x14,0x00,0x00,0x00,0x00,0x11,0x00 +}; +const uint8_t level_trigger_195a[] = { + 0x01,0x0C,0xE4,0x00,0x1E,0x00,0x00,0x00,0x00,0x12,0x00 +}; +const uint8_t level_trigger_1965[] = { + 0x01,0x0B,0xE4,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1970[] = { + 0x01,0x0B,0xE4,0x00,0x00,0x00,0x15,0x00,0x01,0x00,0x00 +}; +const uint8_t level_trigger_18b5[] = { + 0x01,0x0B,0xD6,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_18c0[] = { + 0x01,0x0B,0xDA,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_18cb[] = { + 0x01,0x0B,0xD6,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_18d6[] = { + 0x01,0x0B,0xD6,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_18e1[] = { + 0x01,0x0C,0xD6,0x32,0x00,0x00,0x00,0x00,0x00,0x15,0x00 +}; +const uint8_t level_trigger_18ec[] = { + 0x01,0x0C,0xDA,0x00,0x0A,0x00,0x00,0x00,0x00,0x10,0x00 +}; +const uint8_t level_trigger_18f7[] = { + 0x01,0x0C,0xD6,0x00,0x14,0x00,0x00,0x00,0x00,0x11,0x00 +}; +const uint8_t level_trigger_1902[] = { + 0x01,0x0B,0xA7,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00 +}; +const uint8_t level_trigger_190d[] = { + 0x01,0x0B,0xD6,0x00,0x00,0x00,0x15,0x00,0x01,0x00,0x00 +}; +const uint8_t level_trigger_1a15[] = { + 0x01,0x0B,0x21,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1a20[] = { + 0x01,0x0B,0x21,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1a2b[] = { + 0x01,0x0B,0x21,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1a36[] = { + 0x01,0x0C,0x21,0x32,0x00,0x00,0x00,0x00,0x00,0x15,0x00 +}; +const uint8_t level_trigger_1a41[] = { + 0x01,0x0C,0x21,0x00,0x14,0x00,0x00,0x00,0x00,0x11,0x00 +}; +const uint8_t level_trigger_1a4c[] = { + 0x01,0x0C,0x21,0x00,0x14,0x00,0x00,0x00,0x00,0x11,0x00 +}; +const uint8_t level_trigger_1a57[] = { + 0x01,0x0B,0xD6,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1a62[] = { + 0x01,0x0B,0xD6,0x00,0x00,0x00,0x15,0x00,0x01,0x00,0x00 +}; +const uint8_t level_trigger_1a6d[] = { + 0x01,0x0B,0xD6,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1a8e[] = { + 0x01,0x0B,0x45,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1a99[] = { + 0x01,0x0B,0x45,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1aa4[] = { + 0x01,0x0B,0x45,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1aaf[] = { + 0x01,0x0C,0xC2,0x32,0x00,0x00,0x00,0x00,0x00,0x15,0x00 +}; +const uint8_t level_trigger_1aba[] = { + 0x01,0x0C,0x45,0x00,0x14,0x00,0x00,0x00,0x00,0x11,0x00 +}; +const uint8_t level_trigger_1ac5[] = { + 0x01,0x0C,0xC2,0x00,0x28,0x00,0x00,0x00,0x00,0x13,0x00 +}; +const uint8_t level_trigger_1ad0[] = { + 0x01,0x0B,0x45,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1adb[] = { + 0x01,0x0B,0x92,0x00,0x00,0x00,0x15,0x00,0x01,0x00,0x00 +}; +const uint8_t level_trigger_199c[] = { + 0x01,0x0B,0x2A,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_19a7[] = { + 0x01,0x0B,0x2E,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_19b2[] = { + 0x01,0x0B,0x2A,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_19bd[] = { + 0x01,0x0B,0x2A,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_19c8[] = { + 0x01,0x0B,0x2E,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_19d3[] = { + 0x01,0x0C,0x2A,0x00,0x14,0x00,0x00,0x00,0x00,0x11,0x00 +}; +const uint8_t level_trigger_19de[] = { + 0x01,0x0C,0x2A,0x00,0x32,0x00,0x00,0x00,0x00,0x14,0x00 +}; +const uint8_t level_trigger_19e9[] = { + 0x01,0x0B,0x2A,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00 +}; +const uint8_t level_trigger_19f4[] = { + 0x01,0x0B,0x2A,0x00,0x00,0x00,0x15,0x00,0x01,0x00,0x00 +}; +const uint8_t level_trigger_197b[] = { + 0x01,0x0B,0xFA,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +const uint8_t level_trigger_1918[] = { + 0x01,0x0B,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00 +}; +const uint8_t level_trigger_1a78[] = { + 0x01,0x0B,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00 +}; +const uint8_t level_trigger_1986[] = { + 0x01,0x0B,0xB6,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00 +}; +const uint8_t level_trigger_184b[] = { + 0x02,0x03,0x4E,0x1C,0xF6,0x00,0x4C,0x1E,0xB0,0x00,0x4C,0x1F,0xB3,0x00,0x4E,0x1C, + 0xF6,0x00,0x4C,0x1E,0xAF,0x00,0x4C,0x1F,0xB2,0x00 +}; +const uint8_t level_trigger_1865[] = { + 0x02,0x03,0x4E,0x1C,0xF5,0x00,0x4C,0x1E,0xB0,0x00,0x4C,0x1F,0xB3,0x00,0x4E,0x1C, + 0xF5,0x00,0x4C,0x1E,0xB1,0x00,0x4C,0x1F,0xB4,0x00 +}; +const uint8_t level_trigger_1a83[] = { + 0x01,0x0C,0xD6,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x01 +}; +const uint8_t level_trigger_1991[] = { + 0x01,0x0C,0xE4,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x01 +}; +const uint8_t level_trigger_1ae6[] = { + 0x01,0x0C,0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x01 +}; +const uint8_t level_trigger_1af1[] = { + 0x01,0x0B,0xF6,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00 +}; +const uint8_t level_trigger_19ff[] = { + 0x01,0x0B,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00 +}; +const uint8_t level_trigger_1a0a[] = { + 0x01,0x0C,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x01 +}; +const uint8_t *level_triggersdata_2030[] = { + level_trigger_1831,level_trigger_187f,level_trigger_189d,level_trigger_18a3, + level_trigger_18a9,level_trigger_18af,level_trigger_1923,level_trigger_192e, + level_trigger_1939,level_trigger_1944,level_trigger_194f,level_trigger_195a, + level_trigger_1965,level_trigger_1970,level_trigger_18b5,level_trigger_18c0, + level_trigger_18cb,level_trigger_18d6,level_trigger_18e1,level_trigger_18ec, + level_trigger_18f7,level_trigger_1902,level_trigger_190d,level_trigger_1a15, + level_trigger_1a20,level_trigger_1a2b,level_trigger_1a36,level_trigger_1a41, + level_trigger_1a4c,level_trigger_1a57,level_trigger_1a62,level_trigger_1a6d, + level_trigger_1a8e,level_trigger_1a99,level_trigger_1aa4,level_trigger_1aaf, + level_trigger_1aba,level_trigger_1ac5,level_trigger_1ad0,level_trigger_1adb, + level_trigger_199c,level_trigger_19a7,level_trigger_19b2,level_trigger_19bd, + level_trigger_19c8,level_trigger_19d3,level_trigger_19de,level_trigger_19e9, + level_trigger_19f4,level_trigger_197b,level_trigger_1918,level_trigger_1a78, + level_trigger_1986,level_trigger_184b,level_trigger_1865,level_trigger_1a83, + level_trigger_1991,level_trigger_1ae6,level_trigger_1af1,level_trigger_19ff, + level_trigger_1a0a +}; +const uint8_t font_data[] = { + 0x06,0x5F,0x3F,0x3B,0x7B,0x73,0x36,0x00,0x48,0xE0,0x88,0xCC,0x84,0x84,0xC9,0x00, + 0xB7,0x57,0x7F,0x3B,0x73,0x7B,0x36,0xFF,0xB7,0x57,0x7F,0x3B,0x73,0x7B,0x36,0xFF, + 0x04,0xEF,0xEF,0xEF,0xEF,0x14,0x7B,0x00,0x08,0x20,0xE3,0xF3,0x10,0x08,0x84,0x00, + 0xF7,0x3C,0xFF,0xEF,0x0C,0xF7,0x7B,0xFF,0xF7,0x3C,0xFF,0xEF,0x0C,0xF7,0x7B,0xFF, + 0x06,0xBF,0xFF,0xEF,0xFF,0x77,0x63,0x00,0x08,0x20,0xF8,0xF1,0x00,0x00,0x9C,0x00, + 0xF7,0x77,0xFF,0xEF,0x38,0xFF,0x63,0xFF,0xF7,0x77,0xFF,0xEF,0x38,0xFF,0x63,0xFF, + 0x02,0xBB,0xFF,0xF3,0xFF,0x77,0x32,0x00,0x0C,0x24,0xF8,0xED,0x00,0x00,0xCD,0x00, + 0xF3,0x73,0xFF,0xF3,0x07,0xFF,0x32,0xFF,0xF3,0x73,0xFF,0xF3,0x07,0xFF,0x32,0xFF, + 0x06,0xEF,0x9F,0x7F,0x7F,0x0A,0x1B,0x00,0x08,0x30,0xA1,0x91,0x80,0x04,0xE4,0x00, + 0xF7,0x2E,0xDF,0x7F,0x7F,0xFB,0x1B,0xFF,0xF7,0x2E,0xDF,0x7F,0x7F,0xFB,0x1B,0xFF, + 0x07,0xDF,0xBF,0xFF,0xFF,0x75,0x32,0x00,0x18,0x60,0x81,0xF8,0x00,0x02,0xCD,0x00, + 0xE7,0x50,0xFF,0xFF,0x07,0xFD,0x32,0xFF,0xE7,0x50,0xFF,0xFF,0x07,0xFD,0x32,0xFF, + 0x06,0xEF,0x9F,0xBF,0xBF,0x75,0x32,0x00,0x08,0x20,0xAF,0xC1,0x40,0x02,0xCD,0x00, + 0xF7,0x38,0xDF,0xBF,0x37,0xFD,0x32,0xFF,0xF7,0x38,0xDF,0xBF,0x37,0xFD,0x32,0xFF, + 0x07,0xBF,0xFF,0xFB,0xFF,0x14,0x14,0x00,0x18,0x20,0xF8,0xF5,0x00,0x08,0xEB,0x00, + 0xE7,0x77,0xFF,0xFB,0x1C,0xF7,0x14,0xFF,0xE7,0x77,0xFF,0xFB,0x1C,0xF7,0x14,0xFF, + 0x0E,0xDF,0x9F,0xDB,0xFD,0x75,0x3A,0x00,0x10,0x40,0xA8,0xE5,0x02,0x02,0xC5,0x00, + 0xEF,0x77,0xDF,0xDB,0x75,0xFD,0x3A,0xFF,0xEF,0x77,0xDF,0xDB,0x75,0xFD,0x3A,0xFF, + 0x06,0xDF,0x9F,0xCF,0xFF,0x0A,0x34,0x00,0x18,0x40,0xA8,0xF0,0x00,0x04,0xCB,0x00, + 0xE7,0x77,0xDF,0xCF,0x07,0xFB,0x34,0xFF,0xE7,0x77,0xDF,0xCF,0x07,0xFB,0x34,0xFF +}; diff --git a/sys.h b/sys.h new file mode 100644 index 0000000..f092de4 --- /dev/null +++ b/sys.h @@ -0,0 +1,48 @@ + +#ifndef SYS_H__ +#define SYS_H__ + +#include "intern.h" + +#define INPUT_DIRECTION_LEFT (1 << 0) +#define INPUT_DIRECTION_RIGHT (1 << 1) +#define INPUT_DIRECTION_UP (1 << 2) +#define INPUT_DIRECTION_DOWN (1 << 3) + +#define SYS_AUDIO_FREQ 22050 + +struct input_t { + char quit; + char escape; + char space; + char direction; + char functions[12]; + char digits[10]; + char alphabet[26]; +}; + +typedef void (*sys_audio_cb)(void *, uint8_t *data, int len); + +struct sys_t { + struct input_t input; + int (*init)(); + void (*fini)(); + void (*set_screen_size)(int w, int h, const char *caption); + void (*set_screen_palette)(const uint8_t *colors, int); + void (*set_palette_amiga)(const uint16_t *colors); + void (*set_copper_bars)(const uint16_t *data); + void (*fade_in_palette)(); + void (*fade_out_palette)(); + void (*update_screen)(const uint8_t *p, int present); + void (*process_events)(); + void (*sleep)(int duration); + uint32_t (*get_timestamp)(); + void (*start_audio)(sys_audio_cb callback, void *param); + void (*stop_audio)(); + void (*lock_audio)(); + void (*unlock_audio)(); +}; + +extern struct sys_t g_sys; + +#endif /* SYS_H__ */ diff --git a/sys_sdl2.c b/sys_sdl2.c new file mode 100644 index 0000000..ef5bfea --- /dev/null +++ b/sys_sdl2.c @@ -0,0 +1,285 @@ + +#include +#include "sys.h" +#include "util.h" + +#define COPPER_BARS_H 80 + +static const int SCALE = 2; +static const int FADE_STEPS = 16; + +static int _screen_w; +static int _screen_h; +static SDL_Window *_window; +static SDL_Renderer *_renderer; +static SDL_Texture *_texture; +static SDL_PixelFormat *_fmt; +static uint32_t _screen_palette[32]; +static uint32_t *_screen_buffer; +static struct input_t *_input = &g_sys.input; +static int _copper_color; +static uint32_t _copper_palette[COPPER_BARS_H]; + +static int sdl2_init() { + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO); + SDL_ShowCursor(SDL_DISABLE); + _screen_w = _screen_h = 0; + _window = 0; + _renderer = 0; + _texture = 0; + _fmt = 0; + memset(_screen_palette, 0, sizeof(_screen_palette)); + _screen_buffer = 0; + _copper_color = -1; + return 0; +} + +static void sdl2_fini() { + if (_renderer) { + SDL_DestroyRenderer(_renderer); + _renderer = 0; + } + if (_window) { + SDL_DestroyWindow(_window); + _window = 0; + } + if (_texture) { + SDL_DestroyTexture(_texture); + _texture = 0; + } + if (_fmt) { + SDL_FreeFormat(_fmt); + _fmt = 0; + } + free(_screen_buffer); + SDL_Quit(); +} + +static void sdl2_set_screen_size(int w, int h, const char *caption) { + assert(_screen_w == 0 && _screen_h == 0); // abort if called more than once + _screen_w = w; + _screen_h = h; + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); /* nearest pixel sampling */ + const int window_w = w * SCALE; + const int window_h = h * SCALE; // * 4 / 3; + _window = SDL_CreateWindow(caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_w, window_h, 0); + _renderer = SDL_CreateRenderer(_window, -1, 0); + print_debug(DBG_SYSTEM, "set_screen_size %d,%d", _screen_w, _screen_h); + _screen_buffer = (uint32_t *)calloc(_screen_w * _screen_h, sizeof(uint32_t)); + if (!_screen_buffer) { + print_error("Failed to allocate screen buffer"); + } + static const uint32_t pfmt = SDL_PIXELFORMAT_RGB888; + _texture = SDL_CreateTexture(_renderer, pfmt, SDL_TEXTUREACCESS_STREAMING, _screen_w, _screen_h); + _fmt = SDL_AllocFormat(pfmt); +} + +static uint32_t convert_amiga_color(uint16_t color) { + uint8_t r = (color >> 8) & 15; + r |= r << 4; + uint8_t g = (color >> 4) & 15; + g |= g << 4; + uint8_t b = color & 15; + b |= b << 4; + return SDL_MapRGB(_fmt, r, g, b); +} + +static void sdl2_set_palette_amiga(const uint16_t *colors) { + for (int i = 0; i < 32; ++i) { + _screen_palette[i] = convert_amiga_color(colors[i]); + } +} + +static void sdl2_set_copper_bars(const uint16_t *data) { + if (!data) { + _copper_color = -1; + } else { + _copper_color = (data[0] - 0x180) / 2; + const uint16_t *src = data + 1; + uint32_t *dst = _copper_palette; + for (int i = 0; i < 16; ++i) { + const int j = i + 1; + *dst++ = convert_amiga_color(src[j]); + *dst++ = convert_amiga_color(src[i]); + *dst++ = convert_amiga_color(src[j]); + *dst++ = convert_amiga_color(src[i]); + *dst++ = convert_amiga_color(src[j]); + } + } +} + +static void sdl2_set_screen_palette(const uint8_t *colors, int count) { + for (int i = 0; i < count; ++i) { + _screen_palette[i] = SDL_MapRGB(_fmt, colors[0], colors[1], colors[2]); + colors += 3; + } +} + +static void fade_palette_helper(int in) { + SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND); + SDL_Rect r; + r.x = r.y = 0; + SDL_GetRendererOutputSize(_renderer, &r.w, &r.h); + for (int i = 1; i <= FADE_STEPS; ++i) { + int alpha = 256 * i / FADE_STEPS; + if (in) { + alpha = 256 - alpha; + } + SDL_SetRenderDrawColor(_renderer, 0, 0, 0, alpha); + SDL_RenderClear(_renderer); + SDL_RenderCopy(_renderer, _texture, 0, 0); + SDL_RenderFillRect(_renderer, &r); + SDL_RenderPresent(_renderer); + SDL_Delay(30); + } +} + +static void sdl2_fade_in_palette() { + fade_palette_helper(1); +} + +static void sdl2_fade_out_palette() { + fade_palette_helper(0); +} + +static void sdl2_update_screen(const uint8_t *p, int present) { + if (_copper_color != -1) { + for (int j = 0; j < _screen_h; ++j) { + for (int i = 0; i < _screen_w; ++i) { + if (*p == _copper_color && j / 2 < COPPER_BARS_H) { + _screen_buffer[j * _screen_w + i] = _copper_palette[j / 2]; + } else { + _screen_buffer[j * _screen_w + i] = _screen_palette[*p]; + } + ++p; + } + } + } else { + for (int i = 0; i < _screen_w * _screen_h; ++i) { + _screen_buffer[i] = _screen_palette[p[i]]; + } + } + SDL_UpdateTexture(_texture, 0, _screen_buffer, _screen_w * sizeof(uint32_t)); + if (present) { + SDL_RenderClear(_renderer); + SDL_RenderCopy(_renderer, _texture, 0, 0); + SDL_RenderPresent(_renderer); + } +} + +static void handle_keyevent(int keysym, int keydown) { + switch (keysym) { + case SDLK_LEFT: + if (keydown) { + _input->direction |= INPUT_DIRECTION_LEFT; + } else { + _input->direction &= ~INPUT_DIRECTION_LEFT; + } + break; + case SDLK_RIGHT: + if (keydown) { + _input->direction |= INPUT_DIRECTION_RIGHT; + } else { + _input->direction &= ~INPUT_DIRECTION_RIGHT; + } + break; + case SDLK_UP: + if (keydown) { + _input->direction |= INPUT_DIRECTION_UP; + } else { + _input->direction &= ~INPUT_DIRECTION_UP; + } + break; + case SDLK_DOWN: + if (keydown) { + _input->direction |= INPUT_DIRECTION_DOWN; + } else { + _input->direction &= ~INPUT_DIRECTION_DOWN; + } + break; + case SDLK_RETURN: + case SDLK_SPACE: + _input->space = keydown; + break; + } +} + +static int handle_event(const SDL_Event *ev) { + switch (ev->type) { + case SDL_QUIT: + _input->quit = 1; + break; + case SDL_KEYUP: + handle_keyevent(ev->key.keysym.sym, 0); + break; + case SDL_KEYDOWN: + handle_keyevent(ev->key.keysym.sym, 1); + break; + default: + return -1; + } + return 0; +} + +static void sdl2_process_events() { + SDL_Event ev; + while (SDL_PollEvent(&ev)) { + handle_event(&ev); + if (_input->quit) { + break; + } + } +} + +static void sdl2_sleep(int duration) { + SDL_Delay(duration); +} + +static uint32_t sdl2_get_timestamp() { + return SDL_GetTicks(); +} + +static void sdl2_start_audio(sys_audio_cb callback, void *param) { + SDL_AudioSpec desired; + memset(&desired, 0, sizeof(desired)); + desired.freq = SYS_AUDIO_FREQ; + desired.format = AUDIO_S16; + desired.channels = 1; + desired.samples = 2048; + desired.callback = callback; + desired.userdata = param; + if (SDL_OpenAudio(&desired, 0) == 0) { + SDL_PauseAudio(0); + } +} + +static void sdl2_stop_audio() { + SDL_CloseAudio(); +} + +static void sdl2_lock_audio() { + SDL_LockAudio(); +} + +static void sdl2_unlock_audio() { + SDL_UnlockAudio(); +} + +struct sys_t g_sys = { + .init = sdl2_init, + .fini = sdl2_fini, + .set_screen_size = sdl2_set_screen_size, + .set_screen_palette = sdl2_set_screen_palette, + .set_palette_amiga = sdl2_set_palette_amiga, + .set_copper_bars = sdl2_set_copper_bars, + .fade_in_palette = sdl2_fade_in_palette, + .fade_out_palette = sdl2_fade_out_palette, + .update_screen = sdl2_update_screen, + .process_events = sdl2_process_events, + .sleep = sdl2_sleep, + .get_timestamp = sdl2_get_timestamp, + .start_audio = sdl2_start_audio, + .stop_audio = sdl2_stop_audio, + .lock_audio = sdl2_lock_audio, + .unlock_audio = sdl2_unlock_audio, +}; diff --git a/triggers.c b/triggers.c new file mode 100644 index 0000000..3aad02b --- /dev/null +++ b/triggers.c @@ -0,0 +1,940 @@ + +/* tiles update and object triggers */ + +#include "game.h" +#include "resource.h" +#include "util.h" + +uint16_t triggers_get_tile_type(int x, int y) { + const uint8_t *p = lookup_sql(x, y); + const int num = p[0]; + return g_res.triggers[num].tile_type; +} + +uint16_t triggers_get_next_tile_flags(int x, int y) { + const uint8_t *p = lookup_sql(x, y); + int num = p[0]; + num = g_res.triggers[num].unk16; + return g_res.triggers[num].tile_flags; +} + +uint16_t triggers_get_tile_data(struct object_t *obj) { + const uint8_t *p = lookup_sql(obj->xpos16, obj->ypos16 + 1); + const int num = p[0]; + return g_res.triggers[num].unk10; +} + +uint16_t triggers_get_next_tile_num(int x, int y) { + const uint8_t *p = lookup_sql(x, y); + const int num = p[0]; + return g_res.triggers[num].unk16; +} + +static void trigger_func_op0(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->yfriction = 0; + } + obj->unk2F = 0; + obj->unk3D = 0; +} + +static void trigger_func_op1(struct object_t *obj) { + if (obj->data5F == g_vars.level + 1) { + obj->carry_crate_flag = 1; + do_level_enter_door(obj); + } + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->yfriction = 0; + } + obj->unk2F = 0; +} + +static void trigger_func_op2(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + if (!g_vars.screen_unk1) { + obj->unk1C = 5; + } + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->yfriction = 0; + } + obj->unk2F = 0; + if (g_vars.screen_unk1) { + obj->special_anim = 18; + obj->anim_num = 1; + } +} + +static void trigger_func_op3(struct object_t *obj) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + if (obj->data5F != g_vars.level + 1) { + if (obj->yfriction == 0) { + obj->yfriction = 15; + } + } else { + obj->xpos16 = 101; + obj->ypos16 = 70; + obj->xpos = obj->xpos16 << 4; + obj->ypos = obj->ypos16 << 4; + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + g_vars.screen_unk1 = 1; + } +} + +static void trigger_func_op4(struct object_t *obj) { + if (obj->unk54 == 0) { + obj->unk54 = 0; + obj->unk55 = 0; + obj->unk56 = 8; + obj->sprite_type = 6; + } else { + obj->special_anim = 22; + obj->unk54 = 0; + obj->unk55 = 0; + obj->unk56 = 0; + obj->yfriction = 8; + obj->sprite_type = 0; + } +} + +static void trigger_func_op5(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } + if (obj->unk55 == 0) { + obj->unk54 = 0; + obj->unk55 = 2; + obj->unk56 = 9; + obj->sprite_type = 6; + } else if (obj->unk56 != 9) { + obj->special_anim = 22; + obj->unk54 = 0; + obj->unk55 = 0; + obj->unk56 = 0; + obj->sprite_type = 0; + } +} + +static void trigger_func_op6(struct object_t *obj) { + if (obj->unk56 == 0) { + obj->unk54 = 2; + obj->unk55 = 0; + obj->unk56 = 7; + } else if (obj->unk56 != 7) { + obj->special_anim = 22; + obj->unk54 = 0; + obj->unk55 = 0; + obj->unk56 = 0; + obj->sprite_type = 0; + } +} + +static void trigger_func_op7(struct object_t *obj) { + if (obj->unk56 == 2 || obj->unk56 == 7) { + obj->unk54 = 2; + } + obj->unk56 = 1; +} + +static void trigger_func_op8(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } + switch (obj->unk56 - 1) { + case 0: + obj->unk55 = 1; + break; + case 2: + obj->unk54 = 2; + break; + case 3: + obj->unk54 = 2; + break; + case 4: + obj->unk55 = 1; + break; + case 5: + obj->unk55 = 1; + break; + case 7: + obj->unk55 = 1; + break; + } +} + +static void trigger_func_op9(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } + obj->unk56 = 3; + obj->unk54 = 0; +} + +static void trigger_func_op10(struct object_t *obj) { + obj->unk56 = 3; + obj->unk54 = 0; +} + +static void trigger_func_op11(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } + if (obj->unk56 == 1) { + obj->unk55 = 2; + } else if (obj->unk56 == 3) { + obj->unk54 = 2; + } + obj->unk56 = 4; +} + +static void trigger_func_op12(struct object_t *obj) { + if (obj->unk56 == 1) { + obj->unk55 = 1; + obj->unk54 = 2; + } else if (obj->unk56 == 3 || obj->unk56 == 6) { + obj->unk54 = 1; + obj->unk55 = 0; + } + obj->unk56 = 5; + obj->sprite_type = 6; +} + +static void trigger_func_op13(struct object_t *obj) { + if (obj->unk56 == 1) { + obj->unk55 = 2; + obj->unk54 = 2; + } else if (obj->unk56 == 3) { + obj->unk54 = 1; + } + obj->unk56 = 6; + obj->sprite_type = 6; +} + +static void trigger_func_op14(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + } + obj->unk2F = 0; +} + +static void trigger_func_op15(struct object_t *obj) { + if (obj->special_anim != 18) { + if (obj->floor_ypos16 < obj->ypos16 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->sprite_type = 2; + obj->unk2F = 0; + } +} + +static void trigger_func_op16(struct object_t *obj) { + if (obj->special_anim != 18) { + if (obj->floor_ypos16 < obj->ypos16 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->sprite_type = 3; + obj->unk2F = 0; + } +} + +static void trigger_func_op17(struct object_t *obj) { + if (obj->yvelocity < -2) { + obj->yvelocity -= 3; + obj->yacc = -3; + } + obj->xpos = (obj->xpos & ~15) + 7; + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->xpos16 = obj->xpos >> 4; +} + +static void trigger_func_op18(struct object_t *obj) { + if (obj->yvelocity < -2) { + obj->yvelocity -= 3; + obj->yacc = -3; + } + obj->xpos = (obj->xpos & ~15) + 17; + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->xpos16 = obj->xpos >> 4; +} + +static void trigger_func_op19(struct object_t *obj) { + if (obj->yvelocity < -2) { + obj->yvelocity -= 3; + obj->yacc = -3; + } + obj->xpos = (obj->xpos & ~15) - 1; + obj->screen_xpos = obj->xpos - g_vars.screen_tilemap_xorigin; + obj->xpos16 = obj->xpos >> 4; +} + +static void trigger_func_op20(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 0; + } + obj->unk2F = 0; +} + +static void trigger_func_op21(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->yfriction = 0; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->yfriction = 0; + } + obj->unk2F = 0; + obj->sprite_type = 4; + obj->unk2D = 1; +} + +static void trigger_func_op22(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->unk2F = 0; + obj->sprite_type = 4; + obj->unk2D = 1; +} + +static void trigger_func_op23(struct object_t *obj) { + obj->sprite_type = 4; + obj->unk2D = 1; + obj->unk2F = 0; + obj->yvelocity = 0; +} + +static void trigger_func_op24(struct object_t *obj) { + obj->yfriction = (obj->yvelocity & 255) + 6; + if (obj->floor_ypos16 < obj->ypos16 && obj->unk2B == 0) { + play_sound(SOUND_14); + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->unk3D = 0; +} + +// speedwalk (right) +static void trigger_func_op27(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->unk1C = 4; + obj->sprite_type = 1; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->unk2F = 0; +} + +// speedwalk (left) +static void trigger_func_op28(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->unk1C = -4; + obj->sprite_type = 1; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->unk2F = 0; +} + +static void trigger_func_op29(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->unk2D = 1; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->unk2F = 0; +} + +static void trigger_func_op30(struct object_t *obj) { + if (obj->floor_ypos16 < obj->ypos16 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->unk2D = 2; + } + obj->unk2F = 0; +} + +static void trigger_func_op31(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + triggers_get_dy(obj); + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 1; + obj->unk1C = 1; + obj->xvelocity = 1; + } +} + +static void trigger_func_op32(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + triggers_get_dy(obj); + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 1; + obj->unk2F = -3; + obj->unk2D = 0; + obj->facing_left = 1; + } +} + +static void trigger_func_op33(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 2; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->unk2F = -3; + obj->unk2D = 0; + obj->facing_left = 1; + } +} + +static void trigger_func_op34(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + triggers_get_dy(obj); + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 1; + obj->unk2F = 3; + obj->unk2D = 0; + obj->facing_left = 0; + } +} + +static void trigger_func_op35(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 2; + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 1; + obj->unk2F = 3; + obj->unk2D = 0; + obj->facing_left = 0; + } +} + +static void trigger_func_op36(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + triggers_get_dy(obj); + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 4; + obj->unk2D = 2; + } +} + +static void trigger_func_op37(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 2; + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 4; + obj->unk2D = 2; + } +} + +static void trigger_func_op38(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + triggers_get_dy(obj); + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 4; + obj->unk2D = 2; + } +} + +static void trigger_func_op39(struct object_t *obj) { + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 2; + obj->ypos16 = obj->ypos >> 4; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->sprite_type = 4; + obj->unk2D = 2; + } +} + +static void trigger_func_op40(struct object_t *obj) { + static int counter = 0; + g_vars.music_num = 0; + if (obj->yvelocity > 0 && obj->unk2B == 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) - 1; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + obj->sprite_type = 1; + obj->yfriction = 0; + } else if (obj->yvelocity < 0) { + obj->yvelocity = 0; + obj->ypos = (obj->ypos & ~15) + 15; + obj->screen_ypos = obj->ypos - g_vars.screen_tilemap_yorigin; + obj->ypos16 = obj->ypos >> 4; + } + obj->unk2F = 0; + obj->special_anim = 21; + // if (_timer_counter != _timer_sync) { + // _timer_sync = _timer_counter; + // } + if (counter == 0) { + play_music(g_vars.music_num); + } + if (counter == 400) { + if (!g_vars.two_players_flag) { + g_vars.level_completed_flag = 1; + } else if (g_vars.objects[OBJECT_NUM_PLAYER1].flag_end_level != 0 && g_vars.objects[OBJECT_NUM_PLAYER2].flag_end_level != 0) { + g_vars.level_completed_flag = 1; + } + } + ++counter; +} + +void level_call_trigger_func(struct object_t *obj, int y) { + const uint8_t *p = lookup_sql(obj->xpos16, obj->ypos16 + y); + int num = p[0]; + num = g_res.triggers[num].unk16; + switch (g_res.triggers[num].op_func) { + case 0: + trigger_func_op0(obj); + break; + case 1: + trigger_func_op1(obj); + break; + case 2: + trigger_func_op2(obj); + break; + case 3: + trigger_func_op3(obj); + break; + case 4: + trigger_func_op4(obj); + break; + case 5: + trigger_func_op5(obj); + break; + case 6: + trigger_func_op6(obj); + break; + case 7: + trigger_func_op7(obj); + break; + case 8: + trigger_func_op8(obj); + break; + case 9: + trigger_func_op9(obj); + break; + case 10: + trigger_func_op10(obj); + break; + case 11: + trigger_func_op11(obj); + break; + case 12: + trigger_func_op12(obj); + break; + case 13: + trigger_func_op13(obj); + break; + case 14: + trigger_func_op14(obj); + break; + case 15: + trigger_func_op15(obj); + break; + case 16: + trigger_func_op16(obj); + break; + case 17: + trigger_func_op17(obj); + break; + case 18: + trigger_func_op18(obj); + break; + case 19: + trigger_func_op19(obj); + break; + case 20: + trigger_func_op20(obj); + break; + case 21: + trigger_func_op21(obj); + break; + case 22: + trigger_func_op22(obj); + break; + case 23: + trigger_func_op23(obj); + break; + case 24: + trigger_func_op24(obj); + break; + case 25: + break; + case 27: + trigger_func_op27(obj); + break; + case 28: + trigger_func_op28(obj); + break; + case 29: + trigger_func_op29(obj); + break; + case 30: + trigger_func_op30(obj); + break; + case 31: + trigger_func_op31(obj); + break; + case 32: + trigger_func_op32(obj); + break; + case 33: + trigger_func_op33(obj); + break; + case 34: + trigger_func_op34(obj); + break; + case 35: + trigger_func_op35(obj); + break; + case 36: + trigger_func_op36(obj); + break; + case 37: + trigger_func_op37(obj); + break; + case 38: + trigger_func_op38(obj); + break; + case 39: + trigger_func_op39(obj); + break; + case 40: + trigger_func_op40(obj); + break; + default: + print_warning("level_call_trigger_func: op_func %d unimplemented", g_res.triggers[num].op_func); + break; + } +} + +void triggers_unk3(struct object_t *obj) { + struct object_t *obj35 = &g_vars.objects[35]; + struct object_t *obj37 = &g_vars.objects[37]; + if (obj->yvelocity >= 0 && obj->special_anim != 18) { + obj->special_anim = 0; + } + int _di = 0; + const uint8_t *p = lookup_sql(obj->xpos16, obj->ypos16); + int num = p[0]; + num = g_res.triggers[num].unk16; + struct trigger_t *t = &g_res.triggers[num]; + if (!t->op_table3 && obj->unk2E != 0) { + p = lookup_sql(obj->xpos16, obj->ypos16 - 1); + num = p[0]; + t = &g_res.triggers[num]; + _di = 1; + } + if (!t->op_table3) { + return; + } + p = t->op_table3; + if (p[1] == 11) { + if (obj->unk60 == 0) { + obj->unk60 = p[9]; + } + if (p[8] != 0) { + if (obj->data5F == g_vars.level + 1) { // instrument found + if (obj->flag_end_level == 0) { + play_sound(SOUND_13); + obj->flag_end_level = 1; + if (_di == 0) { + do_level_update_tile(obj->xpos16, obj->ypos16, p[2]); + } else { + do_level_update_tile(obj->xpos16, obj->ypos16 - 1, p[2]); + } + obj->special_anim = p[6]; + if (obj->special_anim == 22) { + play_sound(SOUND_11); + } + if (obj->type != 0 && g_vars.two_players_flag) { + obj37 = &g_vars.objects[36]; + } + if (obj37->type != 100) { + do_level_drop_grabbed_object(obj); + } + g_vars.triggers_counter = 0; + } + + } else if (g_vars.triggers_counter == 0) { + g_vars.triggers_counter = 1; + + } + } else { + if (_di == 0) { + do_level_update_tile(obj->xpos16, obj->ypos16, p[2]); + } else { + do_level_update_tile(obj->xpos16, obj->ypos16 - 1, p[2]); + } + if (p[3] != 0) { + play_sound(SOUND_6); + } + obj->vinyls_count += p[3]; + obj->vinyls_count -= p[4]; + if (obj->vinyls_count < 0) { + obj->vinyls_count = 0; + } + if (p[5] != 0) { + play_sound(SOUND_12); + if (!g_vars.two_players_flag && obj->data51 < 5) { + ++obj->data51; + } + if (g_vars.two_players_flag && obj->data51 < 3) { + ++obj->data51; + } + do_level_update_panel_lifes(obj); + } + obj->special_anim = p[6]; + if (obj->special_anim == 21) { + play_sound(SOUND_8); + } + if (obj->data5F == 0 && p[7] != 0) { // music instrument found + if (!g_vars.two_players_flag) { + obj->data5F = p[7]; + } else { + g_vars.objects[OBJECT_NUM_PLAYER1].data5F = p[7]; + g_vars.objects[OBJECT_NUM_PLAYER2].data5F = p[7]; + } + screen_draw_frame(g_res.spr_frames[140 + g_vars.level], 12, 16, 80 + g_vars.level * 32, -12); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_frame(g_res.spr_frames[140 + g_vars.level], 12, 16, 80 + g_vars.level * 32, -12); + g_vars.screen_draw_offset ^= 0x2000; + g_vars.found_music_instrument_flag = 1; + g_vars.triggers_counter = 0; + play_sound(SOUND_12); + } + } + } else if (p[1] == 12) { + if (obj->type != 0 && g_vars.two_players_flag) { + obj35 = &g_vars.objects[34]; + } + obj35->type = 2; + obj35->visible_flag = 1; + obj35->facing_left = 0; + obj35->grab_type = p[9]; + if (obj->facing_left != 0) { + obj35->xpos = obj->xpos; + obj35->screen_xpos = obj->screen_xpos; + } else { + obj35->xpos = obj->xpos; + obj35->screen_xpos = obj->screen_xpos; + } + obj35->ypos = obj->ypos - 18; + obj35->screen_ypos = obj->screen_ypos - 18; + obj35->xpos16 = obj->xpos16; + obj35->ypos16 = obj->ypos16; + obj35->anim_num = 1; + obj35->animframes_ptr = animframes_059d + obj35->type * 116 / 4; +// seg003:12A3 + if (_di == 0) { + do_level_update_tile(obj->xpos16, obj->ypos16, p[2]); + } else { + do_level_update_tile(obj->xpos16, obj->ypos16 - 1, p[2]); + } + if (p[3] != 0) { + play_sound(SOUND_7); + obj->vinyls_count += p[3]; + } else if (p[4] != 0) { + play_sound(SOUND_8); + obj->vinyls_count -= p[4]; + } + if (obj->vinyls_count < 0) { + obj->vinyls_count = 0; + } + if (p[5] != 0) { + play_sound(SOUND_12); + if (!g_vars.two_players_flag && obj->data51 < 5) { + ++obj->data51; + } + do_level_update_panel_lifes(obj); + } + obj->special_anim = p[6]; + if (p[10] != 0) { + play_sound(SOUND_12); + ++obj->lifes_count; + if (!g_vars.two_players_flag) { + screen_draw_number(obj->lifes_count - 1, 64, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->lifes_count - 1, 64, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + } else if (obj->type == 0) { + screen_draw_number(obj->lifes_count - 1, 48, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->lifes_count - 1, 48, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + } else { + screen_draw_number(obj->lifes_count - 1, 216, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + screen_draw_number(obj->lifes_count - 1, 216, 163, 2); + g_vars.screen_draw_offset ^= 0x2000; + } + } + } else { + obj->unk4D = p[0]; + } +} + +int16_t triggers_get_dy(struct object_t *obj) { + const uint8_t *p = lookup_sql(obj->xpos16, obj->ypos16); + const int num = p[0]; + return g_res.triggers[num].op_table1[obj->xpos & 15] - 1; +} + +void triggers_unk5(struct object_t *obj) { + int offset = 2; + int _si = offset; + const uint8_t *p = obj->trigger3; + if (p[1] < 10) { + int count = obj->unk4D - 1; + _si += (p[1] << 2) * count; + while ((p[1] << 2) > offset) { + do_level_update_tile(p[_si], p[_si + 1], p[_si + 2]); + offset += 4; + _si += 4; + } + } else if (!(g_options.cheats & CHEATS_NO_HIT)) { + obj->yfriction = p[_si]; + obj->yvelocity = p[_si + 1]; + obj->special_anim = p[_si + 2]; + if (obj->special_anim == 22) { + play_sound(SOUND_11); + } + obj->anim_num = 1; + obj->unk2F = 0; + obj->xvelocity = p[3] - 100; + obj->xmaxvelocity = ABS(obj->xvelocity); + do_level_player_hit(obj); + } + obj->unk4D = 0; +} diff --git a/unpack.c b/unpack.c new file mode 100644 index 0000000..e3af7e9 --- /dev/null +++ b/unpack.c @@ -0,0 +1,60 @@ + +#include "fileio.h" +#include "unpack.h" +#include "util.h" + +struct unpack_t { + uint8_t dict_buf[0x200 * 2]; + uint8_t rd[0x1000]; + int size; + int dict_len; +}; + +static struct unpack_t g_unpack; + +int unpack(const char *filename, uint8_t *dst) { + const int f = fio_open(filename, 1); + + fio_read(f, g_unpack.rd, 6); + g_unpack.size = (READ_LE_UINT16(g_unpack.rd) << 16) + READ_LE_UINT16(g_unpack.rd + 2); + const int dict_len = READ_LE_UINT16(g_unpack.rd + 4); + print_debug(DBG_UNPACK, "unpack '%s' size %d dict_len %d", filename, g_unpack.size, dict_len); + fio_read(f, g_unpack.dict_buf, dict_len); + + const uint8_t *src = g_unpack.rd; + int len = 1; + int bytes_count = 2; + uint16_t bits = 0; + uint16_t val = 0; + while (1) { + --len; + if (len == 0) { + bytes_count -= 2; + if (bytes_count == 0) { + bytes_count = fio_read(f, g_unpack.rd, 0x1000); + if (bytes_count == 0) { + break; + } + bytes_count += (bytes_count & 1); + src = g_unpack.rd; + } + bits = READ_BE_UINT16(src); src += 2; + len = 17; + continue; + } + const int carry = (bits & 0x8000) != 0; + bits <<= 1; + if (carry) { + val += 2; + } + assert(val < 0x400); + val = READ_LE_UINT16(g_unpack.dict_buf + val); + if ((val & 0x8000) == 0) { + continue; + } + *dst++ = val & 255; + val = 0; + } + fio_close(f); + return g_unpack.size; +} diff --git a/unpack.h b/unpack.h new file mode 100644 index 0000000..1891a3b --- /dev/null +++ b/unpack.h @@ -0,0 +1,9 @@ + +#ifndef UNPACK_H__ +#define UNPACK_H__ + +#include "intern.h" + +extern int unpack(const char *filename, uint8_t *dst); + +#endif /* UNPACK_H__ */ diff --git a/util.c b/util.c new file mode 100644 index 0000000..e7ef171 --- /dev/null +++ b/util.c @@ -0,0 +1,60 @@ + +#include +#include "util.h" + +int g_debug_mask = 0; + +void string_lower(char *p) { + for (; *p; ++p) { + if (*p >= 'A' && *p <= 'Z') { + *p += 'a' - 'A'; + } + } +} + +void string_upper(char *p) { + for (; *p; ++p) { + if (*p >= 'a' && *p <= 'z') { + *p += 'A' - 'a'; + } + } +} + +void print_debug(int debug_channel, const char *msg, ...) { + if (g_debug_mask & debug_channel) { + char buf[256]; + va_list va; + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + fprintf(stdout, "%s\n", buf); + } +} + +void print_warning(const char *msg, ...) { + char buf[256]; + va_list va; + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + fprintf(stderr, "WARNING: %s\n", buf); +} + +void print_error(const char *msg, ...) { + char buf[256]; + va_list va; + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + fprintf(stderr, "ERROR: %s!\n", buf); + exit(-1); +} + +void print_info(const char *msg, ...) { + char buf[256]; + va_list va; + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + fprintf(stdout, "%s\n", buf); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..4d0e793 --- /dev/null +++ b/util.h @@ -0,0 +1,24 @@ + +#ifndef UTIL_H__ +#define UTIL_H__ + +#include "intern.h" + +#define DBG_GAME (1 << 0) +#define DBG_FILEIO (1 << 1) +#define DBG_RESOURCE (1 << 2) +#define DBG_MIXER (1 << 3) +#define DBG_SYSTEM (1 << 4) +#define DBG_UNPACK (1 << 5) +#define DBG_SCREEN (1 << 6) + +extern int g_debug_mask; + +extern void string_lower(char *p); +extern void string_upper(char *p); +extern void print_debug(int debug_channel, const char *msg, ...); +extern void print_warning(const char *msg, ...); +extern void print_error(const char *msg, ...); +extern void print_info(const char *msg, ...); + +#endif /* UTIL_H__ */