Import blues from a65b79d4

This commit is contained in:
Gregory Montoir 2019-05-29 07:54:47 +08:00
parent 07e54eef74
commit 6a5f7c4646
14 changed files with 4816 additions and 4 deletions

View File

@ -4,16 +4,18 @@ SDL_LIBS := `sdl2-config --libs`
BB := decode.c fileio.c game.c level.c objects.c resource.c screen.c sound.c staticres.c tiles.c unpack.c
JA := game.c level.c resource.c screen.c sound.c staticres.c unpack.c
P2 := game.c level.c resource.c screen.c sound.c staticres.c unpack.c
BB_SRCS := $(foreach f,$(BB),bb/$f)
JA_SRCS := $(foreach f,$(JA),ja/$f)
SRCS := $(BB_SRCS) $(JA_SRCS)
P2_SRCS := $(foreach f,$(P2),p2/$f)
SRCS := $(BB_SRCS) $(JA_SRCS) $(P2_SRCS)
OBJS := $(SRCS:.c=.o)
DEPS := $(SRCS:.c=.d)
CPPFLAGS := -Wall -Wpedantic -MMD $(SDL_CFLAGS) -I. -g
CPPFLAGS += -Wall -Wpedantic -MMD $(SDL_CFLAGS) -I. -g
all: blues bbja
all: blues bbja pre2
blues: main.o sys_sdl2.o util.o $(BB_SRCS:.c=.o)
$(CC) $(LDFLAGS) -o $@ $^ $(SDL_LIBS) -lmodplug
@ -21,7 +23,10 @@ blues: main.o sys_sdl2.o util.o $(BB_SRCS:.c=.o)
bbja: main.o sys_sdl2.o util.o $(JA_SRCS:.c=.o)
$(CC) $(LDFLAGS) -o $@ $^ $(SDL_LIBS) -lmodplug
pre2: main.o sys_sdl2.o util.o $(P2_SRCS:.c=.o)
$(CC) $(LDFLAGS) -o $@ $^ $(SDL_LIBS) -lmodplug
clean:
rm -f $(OBJS) $(DEPS)
rm -f $(OBJS) $(DEPS) *.o
-include $(DEPS)

View File

@ -5,6 +5,7 @@ This is a rewrite of the [Blues Brothers](https://www.mobygames.com/game/blues-b
![Screenshot1](blues1.png) ![Screenshot2](bbja2.png)
There is also early support for [Prehistork 2](https://www.mobygames.com/game/prehistorik-2).
## Requirements
@ -26,6 +27,14 @@ The game data files of the DOS version are required.
*.EAT, *.MOD
```
### Prehistorik 2
The game data files of the DOS version are required.
```
*.SQZ, *.TRK
```
## Running

View File

@ -3,6 +3,7 @@
#define INTERN_H__
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

2
main.c
View File

@ -29,9 +29,11 @@ static struct game_t *detect_game(const char *data_path) {
#if 0
extern struct game_t bb_game;
extern struct game_t ja_game;
extern struct game_t p2_game;
static struct game_t *games[] = {
&bb_game,
&ja_game,
&p2_game,
0
};
for (int i = 0; games[i]; ++i) {

230
p2/game.c Normal file
View File

@ -0,0 +1,230 @@
#include <time.h>
#include "game.h"
#include "resource.h"
#include "sys.h"
static const bool _logos = false;
struct vars_t g_vars;
void update_input() {
g_sys.process_events();
g_vars.input.key_left = (g_sys.input.direction & INPUT_DIRECTION_LEFT) != 0 ? 0xFF : 0;
g_vars.input.key_right = (g_sys.input.direction & INPUT_DIRECTION_RIGHT) != 0 ? 0xFF : 0;
g_vars.input.key_up = (g_sys.input.direction & INPUT_DIRECTION_UP) != 0 ? 0xFF : 0;
g_vars.input.key_down = (g_sys.input.direction & INPUT_DIRECTION_DOWN) != 0 ? 0xFF : 0;
g_vars.input.key_space = g_sys.input.space ? 0xFF : 0;
g_vars.input.keystate[2] = g_sys.input.digit1;
g_vars.input.keystate[3] = g_sys.input.digit2;
g_vars.input.keystate[4] = g_sys.input.digit3;
}
static void wait_input(int timeout) {
const uint32_t end = g_sys.get_timestamp() + timeout * 10;
while (g_sys.get_timestamp() < end) {
g_sys.process_events();
if (g_sys.input.quit || g_sys.input.space) {
break;
}
g_sys.sleep(20);
}
}
static void do_programmed_in_1992_screen() {
time_t now;
time(&now);
struct tm *t = localtime(&now);
if (t->tm_year + 1900 < 1996) {
return;
}
g_sys.set_screen_palette(credits_palette_data, 0, 16, 6);
int offset = 0x960;
video_draw_string(offset, 5, "YEAAA > > >");
char str[64];
snprintf(str, sizeof(str), "MY GAME IS STILL WORKING IN %04d <<", 1900 + t->tm_year);
offset += 0x1E0;
video_draw_string(offset, 0, str);
offset = 0x1680;
video_draw_string(offset, 1, "PROGRAMMED IN 1992 ON AT >286 12MHZ>");
offset += 0x1E0;
video_draw_string(offset, 3, "> > > ENJOY OLDIES<<");
g_sys.update_screen(g_res.vga, 1);
wait_input(100);
}
static void do_credits() {
g_sys.set_screen_palette(credits_palette_data, 0, 16, 6);
int offset = 0x140;
video_draw_string(offset, 1, "CODER> DESIGNER AND ARTIST DIRECTOR>");
offset += 0x230;
video_draw_string(offset, 14, "ERIC ZMIRO");
offset += 0x460;
video_draw_string(offset, 4, ">MAIN GRAPHICS AND BACKGROUND>");
offset += 0x230;
video_draw_string(offset, 11, "FRANCIS FOURNIER");
offset += 0x460;
video_draw_string(offset, 9, ">MONSTERS AND HEROS>");
offset += 0x230;
video_draw_string(offset, 11, "LYES BELAIDOUNI");
offset = 0x1770;
video_draw_string(offset, 15, "THANKS TO");
offset = 0x1A40;
video_draw_string(offset, 2, "CRISTELLE> GIL ESPECHE AND CORINNE>");
offset += 0x1E0;
video_draw_string(offset, 0, "SEBASTIEN BECHET AND OLIVIER AKA DELTA>");
g_sys.update_screen(g_res.vga, 1);
}
static void do_titus_screen() {
uint8_t *data = load_file("TITUS.SQZ");
if (data) {
g_sys.set_screen_palette(data, 0, 256, 6);
g_sys.update_screen(data + 768, 0);
fade_in_palette();
wait_input(70);
fade_out_palette();
free(data);
}
}
static void do_present_screen() {
uint8_t *data = load_file("PRESENT.SQZ");
if (data) {
g_sys.set_screen_palette(data, 0, 256, 6);
g_sys.update_screen(data + 768, 0);
fade_in_palette();
free(data);
}
}
static void do_demo_screen() {
uint8_t *data = load_file("JOYSTICK.SQZ");
if (data) {
video_copy_img(data);
free(data);
}
}
static void do_menu() {
uint8_t *data = load_file("MENU.SQZ");
if (data) {
g_sys.set_screen_palette(data, 0, 256, 6);
g_sys.update_screen(data + 768, 0);
fade_in_palette();
free(data);
memset(g_vars.input.keystate, 0, sizeof(g_vars.input.keystate));
while (!g_sys.input.quit) {
update_input();
if (g_vars.input.keystate[2] || g_vars.input.keystate[0x4F] || g_sys.input.space) {
g_sys.input.space = 0;
fade_out_palette();
break;
}
if (g_vars.input.keystate[3] || g_vars.input.keystate[0x50]) {
fade_out_palette();
break;
}
if (g_vars.input.keystate[4] || g_vars.input.keystate[0x51]) {
break;
}
g_sys.sleep(30);
}
}
}
void input_check_ctrl_alt_w() {
if (g_vars.input.keystate[0x1D] && g_vars.input.keystate[0x38] && g_vars.input.keystate[0x11]) {
do_credits();
wait_input(60);
}
}
uint32_t timer_get_counter() {
const uint32_t current = g_sys.get_timestamp();
return ((current - g_vars.starttime) * 1193182 / 0x4000) / 1000;
}
void random_reset() {
g_vars.random.a = 5;
g_vars.random.b = 34;
g_vars.random.c = 134;
g_vars.random.d = 58765;
}
uint8_t random_get_number() {
g_vars.random.d += g_vars.random.a;
g_vars.random.a += 3 + (g_vars.random.d >> 8);
g_vars.random.b += g_vars.random.c;
g_vars.random.b *= 2;
g_vars.random.b += g_vars.random.a;
g_vars.random.c ^= g_vars.random.a;
g_vars.random.c ^= g_vars.random.b;
return g_vars.random.b;
}
static uint16_t ror16(uint16_t x, int c) {
return (x >> c) | (x << (16 - c));
}
uint16_t random_get_number2() {
const uint16_t x = g_vars.random.e + 0x9248;
g_vars.random.e = ror16(x, 3);
return g_vars.random.e;
}
static uint16_t rol16(uint16_t x, int c) {
return (x << c) | (x >> (16 - c));
}
/* original code returns a machine specific value, based on BIOS and CPU */
uint16_t random_get_number3(uint16_t x) {
x ^= 0x55a3;
x *= 0xb297; /* to match dosbox */
return rol16(x, 3);
}
static void game_run(const char *data_path) {
res_init(data_path, GAME_SCREEN_W * GAME_SCREEN_H);
sound_init();
video_convert_tiles(g_res.uniondat, g_res.unionlen);
g_vars.level_num = g_options.start_level;
if (_logos) {
do_programmed_in_1992_screen();
do_titus_screen();
play_music(3);
do_present_screen();
}
g_sys.render_set_sprites_clipping_rect(0, 0, TILEMAP_SCREEN_W, TILEMAP_SCREEN_H);
g_vars.random.e = 0x1234;
g_vars.starttime = g_sys.get_timestamp();
while (!g_sys.input.quit) {
if (1) {
video_set_palette();
g_vars.player_lifes = 2;
g_vars.player_bonus_letters_mask = 0;
g_vars.player_club_power = 20;
g_vars.player_club_type = 0;
if (g_res.dos_demo) {
do_demo_screen();
}
do_menu();
}
video_set_palette();
video_set_palette();
do_level();
}
sound_fini();
res_fini();
}
struct game_t game = {
"Prehistorik 2",
game_run
};

247
p2/game.h Normal file
View File

@ -0,0 +1,247 @@
#ifndef GAME_H__
#define GAME_H__
#include "intern.h"
extern struct options_t g_options;
#define PANEL_H 24
#define TILEMAP_SCREEN_W GAME_SCREEN_W
#define TILEMAP_SCREEN_H (GAME_SCREEN_H - PANEL_H)
#define CHEATS_NO_HIT (1 << 0)
#define CHEATS_UNLIMITED_LIFES (1 << 1)
#define CHEATS_UNLIMITED_ENERGY (1 << 2)
struct club_anim_t {
const uint8_t *anim; /* uint16_t[4] : player spr, club spr, x, y */
uint8_t a;
uint8_t power; /* damage */
uint8_t c;
};
struct player_t {
int16_t hdir; /* left:-1 right:1 */ // 0x9
uint8_t current_anim_num; // 0xB
const uint8_t *anim; // 0xC
int16_t y_velocity; // 0xE
uint8_t special_anim_num; /* idle, exhausted */ // 0x10
};
struct club_projectile_t {
const uint8_t *anim; // 0xC
int16_t y_velocity; // 0xE
};
struct thing_t {
void *ref; // 0x9
int16_t counter; // 0xC
int16_t unkE; // 0xE
};
struct object_t {
int16_t x_pos, y_pos;
uint16_t spr_num;
int16_t x_velocity;
uint8_t x_friction;
union { // 0x9 - 0x10
struct player_t p; /* objects[1] */
struct club_projectile_t c; /* objects[2..5] */
struct thing_t t;
} data;
uint8_t hit_counter; // 0x11
}; // sizeof == 18
#define OBJECTS_COUNT 108
// offset count
// 0 1 : club
// 1 1 : player
// 2 4 : axe
// 6 5 : club hitting decor frames
// 11 12 : monsters
// 23 32 : secret bonuses
// 55 20 : items
// 75 16 : bonus scores
// 91 7 : decor
struct rotation_t {
uint16_t x_pos;
uint16_t y_pos;
uint8_t index_tbl; /* cos_/sin_tbl */
uint8_t radius;
}; // sizeof == 6
struct collision_t {
uint16_t x_pos;
uint16_t y_pos;
uint8_t unk4;
uint8_t unk5;
uint8_t unk6;
uint8_t unk7;
}; // sizeof == 8
struct vars_t {
uint32_t starttime;
uint32_t timestamp;
struct {
uint8_t a, b, c;
uint16_t d, e;
} random;
struct {
bool keystate[128];
uint8_t key_left, key_right, key_down, key_up, key_space;
uint8_t key_vdir, key_hdir;
} input;
uint8_t level_num;
uint32_t score;
uint16_t score_extra_life;
uint8_t level_completed_flag;
uint8_t restart_level_flag;
uint16_t level_draw_counter;
uint8_t player_lifes;
uint8_t player_energy;
uint8_t player_death_flag;
uint8_t player_flying_flag;
uint8_t player_flying_counter;
uint8_t player_flying_anim_index;
uint8_t player_bonus_letters_mask;
uint8_t player_utensils_mask;
uint8_t player_gravity_flag; /* 0, 1 or 2 */
uint8_t player_unk_counter1;
uint8_t player_moving_counter;
uint8_t player_anim_0x40_flag;
uint8_t player_anim2_counter;
int16_t player_prev_y_pos;
uint8_t player_bonus_letters_blinking_counter;
int16_t player_monsters_unk_counter;
uint8_t player_nojump_counter;
uint8_t player_jumping_counter;
uint8_t player_action_counter;
uint8_t player_club_type;
uint8_t player_club_power;
uint8_t player_club_powerup_duration;
uint8_t player_club_anim_duration;
bool player_using_club_flag;
uint16_t player_update_counter;
uint8_t player_platform_counter;
uint8_t player_current_anim_type;
uint8_t player_tile_flags;
int16_t level_current_bonus_x_pos, level_current_bonus_y_pos, level_current_bonus_spr_num;
uint8_t level_items_count_tbl[140]; /* bonuses and items collected in the level */
uint8_t level_items_total_count;
uint8_t level_bonuses_count_tbl[80];
uint8_t bonus_energy_counter;
int16_t level_current_object_decor_x_pos, level_current_object_decor_y_pos;
uint16_t decor_tile0_offset; /* decor tile below the player */
struct collision_t collision_tbl[20]; /* reset by bonus 145 */
struct rotation_t rotation_tbl[20];
struct object_t *current_hit_object;
struct object_t objects_tbl[OBJECTS_COUNT];
uint8_t level_xscroll_center_flag, level_yscroll_center_flag;
uint8_t level_force_x_scroll_flag;
bool tilemap_adjust_player_pos_flag;
uint8_t level_noscroll_flag;
int16_t tilemap_yscroll_diff;
uint16_t tilemap_x, tilemap_y;
uint16_t tilemap_prev_x, tilemap_prev_y;
int8_t tilemap_scroll_dx, tilemap_scroll_dy;
uint8_t tilemap_h;
uint16_t tilemap_size; /* tilemap size h*256 */
uint16_t tilemap_start_x_pos, tilemap_start_y_pos; /* tilemap restart position */
uint8_t tile_attr2_flags; /* current tilemap tile types (eg. front) */
uint8_t animated_tiles_flag; /* current tilemap has animated tiles */
uint8_t level_animated_tiles_counter; /* animated tiles update counter */
uint8_t *level_animated_tiles_current_tbl; /* pointer to current tile_tbl */
uint8_t tile_tbl1[256]; /* animated tile state 1 */
uint8_t tile_tbl2[256]; /* animated tile state 2 */
uint8_t tile_tbl3[256]; /* animated tile state 3 */
uint8_t animated_tile_flag_tbl[256]; /* 1 if tile is animated */
uint8_t tilemap_redraw_flag2; /* tilemap needs redraw */
uint8_t tilemap_redraw_flag1; /* force redraw even if tilemap origin did not change */
struct {
uint16_t value;
uint16_t counter;
uint16_t random_tbl[256];
} snow;
struct {
uint8_t state; /* 1: lights off, 0: lights on */
uint8_t palette_flag1; /* palette day time */
uint8_t palette_flag2; /* palette night time */
uint8_t palette_counter;
} light;
struct {
uint32_t score;
uint8_t lifes;
uint8_t energy;
uint8_t bonus_letters_mask;
} panel;
};
extern struct vars_t g_vars;
/* staticres.c */
extern const uint8_t *palettes_tbl[16];
extern const uint8_t credits_palette_data[16 * 3];
extern const uint8_t light_palette_data[16 * 3];
extern const uint8_t spr_offs_tbl[892];
extern const uint8_t spr_size_tbl[892];
extern const uint16_t score_tbl[17];
extern const uint8_t score_spr_lut[110];
extern const uint8_t *object_anim_tbl[];
extern const struct club_anim_t club_anim_tbl[4];
extern const uint8_t player_anim_lut[32];
extern const uint8_t player_anim_data[100];
extern const uint8_t vscroll_offsets_data[132];
extern const uint8_t cos_tbl[256];
extern const uint8_t sin_tbl[256];
/* game.c */
extern void update_input();
extern void input_check_ctrl_alt_w();
extern uint32_t timer_get_counter();
extern void random_reset();
extern uint8_t random_get_number();
extern uint16_t random_get_number2();
extern uint16_t random_get_number3(uint16_t x);
extern void game_main();
/* level.c */
extern void do_level();
/* screen.c */
extern void video_draw_string(int offset, int hspace, const char *s);
extern void video_clear();
extern void video_copy_img(const uint8_t *src);
extern void video_draw_panel(const uint8_t *src);
extern void video_draw_panel_number(int offset, int num);
extern void video_draw_number(int offset, int num);
extern void video_draw_tile(const uint8_t *src, int x, int y);
extern void video_convert_tiles(uint8_t *data, int len);
extern void video_load_front_tiles();
extern void video_set_palette();
extern void fade_in_palette();
extern void fade_out_palette();
extern void video_wait_vbl();
extern void video_transition_close();
extern void video_transition_open();
extern void video_load_sprites();
extern void video_draw_sprite(int num, int x, int y, int flag);
/* sound.c */
extern void sound_init();
extern void sound_fini();
extern void play_sound(int num);
extern void play_music(int num);
#endif /* GAME_H__ */

2969
p2/level.c Normal file

File diff suppressed because it is too large Load Diff

155
p2/resource.c Normal file
View File

@ -0,0 +1,155 @@
#include "resource.h"
#include "unpack.h"
#include "util.h"
static const int BACKGROUND_SIZE = 320 * 200;
static const char *_datapath;
struct resource_t g_res;
int g_uncompressed_size;
uint8_t *load_file(const char *filename) {
FILE *fp = fopen_nocase(_datapath, filename);
if (fp) {
print_debug(DBG_RESOURCE, "Loading '%s'...", filename);
uint8_t *p = unpack(fp, &g_uncompressed_size);
print_debug(DBG_RESOURCE, "Uncompressed size %d", g_uncompressed_size);
fclose(fp);
return p;
}
print_error("Unable to open '%s'", filename);
return 0;
}
static void detect_dos_demo() {
FILE *fp = fopen_nocase(_datapath, "JOYSTICK.SQZ");
if (fp) {
g_res.dos_demo = true;
fclose(fp);
}
}
void res_init(const char *path, int vga_size) {
_datapath = path;
detect_dos_demo();
g_res.maps = load_file("MAP.SQZ");
g_res.motif = load_file("MOTIF.SQZ");
g_res.allfonts = load_file("ALLFONTS.SQZ");
g_res.sprites = load_file("SPRITES.SQZ");
g_res.frontdat = load_file("FRONT.SQZ");
g_res.frontlen = g_uncompressed_size;
g_res.uniondat = load_file("UNION.SQZ");
g_res.unionlen = g_uncompressed_size;
g_res.vga = (uint8_t *)malloc(vga_size);
if (!g_res.vga) {
print_error("Failed to allocate vga buffer, %d bytes", vga_size);
}
g_res.background = (uint8_t *)malloc(BACKGROUND_SIZE);
if (!g_res.background) {
print_error("Failed to allocate background buffer, %d bytes", BACKGROUND_SIZE);
}
if (!g_res.dos_demo) {
g_res.samples = load_file("SAMPLE.SQZ");
}
}
void res_fini() {
free(g_res.maps);
g_res.maps = 0;
free(g_res.motif);
g_res.motif = 0;
free(g_res.allfonts);
g_res.allfonts = 0;
free(g_res.sprites);
g_res.sprites = 0;
free(g_res.frontdat);
g_res.frontdat = 0;
free(g_res.uniondat);
g_res.uniondat = 0;
free(g_res.vga);
g_res.vga = 0;
free(g_res.background);
g_res.background = 0;
free(g_res.samples);
g_res.samples = 0;
}
void load_leveldat(const uint8_t *p, struct level_t *level) {
memcpy(g_res.level.tile_attributes0, p, 256); p += 256;
memcpy(g_res.level.tile_attributes1, p, 256); p += 256;
memcpy(g_res.level.tile_attributes2, p, 256); p += 256;
g_res.level.scrolling_top = READ_LE_UINT16(p); p += 2;
g_res.level.start_x_pos = READ_LE_UINT16(p); p += 2;
g_res.level.start_y_pos = READ_LE_UINT16(p); p += 2;
g_res.level.tilemap_w = READ_LE_UINT16(p); p += 2;
g_res.level.scrolling_mask = *p++;
for (int i = 0; i < 256; ++i) {
g_res.level.front_tiles_lut[i] = READ_LE_UINT16(p); p += 2;
}
for (int i = 0; i < MAX_LEVEL_GATES; ++i) {
struct level_gate_t *gate = &g_res.level.gates_tbl[i];
gate->enter_pos = READ_LE_UINT16(p); p += 2;
gate->tilemap_pos = READ_LE_UINT16(p); p += 2;
gate->dst_pos = READ_LE_UINT16(p); p += 2;
gate->scroll_flag = *p++;
}
for (int i = 0; i < MAX_LEVEL_PLATFORMS; ++i) {
struct level_platform_t *platform = &g_res.level.platforms_tbl[i];
platform->tilemap_pos = READ_LE_UINT16(p); p += 2;
platform->w = *p++;
platform->h = *p++;
platform->unk4 = READ_LE_UINT16(p); p += 2;
platform->unk6 = READ_LE_UINT16(p); p += 2;
platform->unk8 = *p++;
platform->unk9 = *p++;
}
memcpy(g_res.level.monsters_attributes, p, 0x800); p += 0x800;
g_res.level.items_spr_num_offset = READ_LE_UINT16(p); p += 2;
g_res.level.monsters_spr_num_offset = READ_LE_UINT16(p); p += 2;
for (int i = 0; i < MAX_LEVEL_BONUSES; ++i) {
struct level_bonus_t *bonus = &g_res.level.bonuses_tbl[i];
bonus->tile_num0 = *p++;
bonus->tile_num1 = *p++;
bonus->count = *p++;
bonus->pos = READ_LE_UINT16(p); p += 2;
}
memcpy(g_res.level.tile_attributes3, p, 256); p += 256;
for (int i = 0; i < MAX_LEVEL_ITEMS; ++i) {
struct level_item_t *item = &g_res.level.items_tbl[i];
item->x_pos = READ_LE_UINT16(p); p += 2;
item->y_pos = READ_LE_UINT16(p); p += 2;
item->spr_num = READ_LE_UINT16(p); p += 2;
item->y_delta = *p++;
}
for (int i = 0; i < MAX_LEVEL_TRIGGERS; ++i) {
struct level_trigger_t *trigger = &g_res.level.triggers_tbl[i];
trigger->x_pos = READ_LE_UINT16(p); p += 2;
trigger->y_pos = READ_LE_UINT16(p); p += 2;
trigger->spr_num = READ_LE_UINT16(p); p += 2;
trigger->flags = *p++;
trigger->unk7 = *p++;
trigger->unk8 = *p++;
trigger->unk9 = *p++;
trigger->state = *p++;
trigger->unkB = READ_LE_UINT16(p); p += 2;
trigger->counter = *p++;
trigger->unkE = *p++;
}
g_res.level.monsters_xmin = READ_LE_UINT16(p); p += 2;
g_res.level.monsters_xmax = READ_LE_UINT16(p); p += 2;
g_res.level.monsters_unk0 = *p++;
g_res.level.monsters_unk1 = READ_LE_UINT16(p); p += 2;
g_res.level.monsters_state = *p++;
g_res.level.end_x_pos = READ_LE_UINT16(p); p += 2;
g_res.level.end_y_pos = READ_LE_UINT16(p); p += 2;
const int total = p - g_res.leveldat;
print_debug(DBG_RESOURCE, "level total offset %d", total);
}

111
p2/resource.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef RESOURCE_H__
#define RESOURCE_H__
#include "intern.h"
struct level_gate_t {
uint16_t enter_pos; // (y << 8) | x
uint16_t tilemap_pos;
uint16_t dst_pos;
uint8_t scroll_flag;
}; // sizeof == 7
struct level_platform_t {
uint16_t tilemap_pos;
uint8_t w;
uint8_t h;
uint16_t unk4;
uint16_t unk6;
uint8_t unk8; // y_offs
uint8_t unk9;
}; // sizeof == 10
struct level_bonus_t {
uint8_t tile_num0; /* new tile */
uint8_t tile_num1; /* original tile */
uint8_t count;
uint16_t pos; // (y << 8) | x
}; // sizeof == 5
struct level_item_t {
int16_t x_pos, y_pos;
uint16_t spr_num;
int8_t y_delta;
}; // sizeof == 7
struct level_trigger_t {
uint16_t x_pos;
uint16_t y_pos;
uint16_t spr_num;
uint8_t flags;
uint8_t unk7;
uint8_t unk8;
uint8_t unk9;
uint8_t state;
uint16_t unkB;
uint8_t counter;
uint8_t unkE;
}; // sizeof == 15
#define MAX_LEVEL_GATES 20
#define MAX_LEVEL_PLATFORMS 15
#define MAX_LEVEL_BONUSES 80
#define MAX_LEVEL_ITEMS 70
#define MAX_LEVEL_TRIGGERS 16
struct level_t {
uint8_t tile_attributes0[256];
uint8_t tile_attributes1[256];
uint8_t tile_attributes2[256]; /* 0x80: animated, 0x40: front, 0x20: animate if player is on top */
uint8_t scrolling_top;
uint16_t start_x_pos;
uint16_t start_y_pos;
uint16_t tilemap_w;
uint16_t scrolling_mask; /* 4: screen scroll down 1 line, 2: no horizontal scrolling, 1: wider vertical scrolling */
uint16_t front_tiles_lut[256];
struct level_gate_t gates_tbl[MAX_LEVEL_GATES];
struct level_platform_t platforms_tbl[MAX_LEVEL_PLATFORMS];
uint8_t monsters_attributes[0x800];
uint16_t items_spr_num_offset;
uint16_t monsters_spr_num_offset;
struct level_bonus_t bonuses_tbl[MAX_LEVEL_BONUSES];
uint8_t tile_attributes3[256];
struct level_item_t items_tbl[MAX_LEVEL_ITEMS];
struct level_trigger_t triggers_tbl[MAX_LEVEL_TRIGGERS];
uint16_t monsters_xmin;
uint16_t monsters_xmax;
uint8_t monsters_unk0;
uint16_t monsters_unk1;
uint8_t monsters_state;
uint16_t end_x_pos;
uint16_t end_y_pos;
};
struct resource_t {
bool dos_demo;
uint8_t *maps;
uint8_t *motif;
uint8_t *allfonts;
uint8_t *sprites;
uint8_t *frontdat;
int frontlen;
uint8_t *uniondat;
int unionlen;
uint8_t *leveldat;
int levellen;
uint8_t *vga;
uint8_t *background;
struct level_t level, restart;
uint8_t *samples;
};
extern struct resource_t g_res;
extern int g_uncompressed_size;
extern void res_init(const char *datapath, int vga_size);
extern void res_fini();
extern void load_leveldat(const uint8_t *data, struct level_t *level);
extern uint8_t *load_file(const char *filename);
#endif

246
p2/screen.c Normal file
View File

@ -0,0 +1,246 @@
/* screen drawing */
#include "game.h"
#include "resource.h"
#include "sys.h"
#include "util.h"
#define MAX_SPRITES 445
#define MAX_SPRITESHEET_W 2048
#define MAX_SPRITESHEET_H 1024
#define MAX_FRONT_TILES 168
static void decode_planar(const uint8_t *src, uint8_t *dst, int dst_pitch, int w, int h, uint8_t transparent_color) {
const int plane_size = h * w / 8;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w / 8; ++x) {
for (int i = 0; i < 8; ++i) {
const uint8_t mask = 1 << (7 - i);
uint8_t color = 0;
for (int b = 0; b < 4; ++b) {
if (src[b * plane_size] & mask) {
color |= (1 << b);
}
}
if (color != transparent_color) {
dst[x * 8 + i] = color;
}
}
++src;
}
dst += dst_pitch;
}
}
static void convert_planar_tile_4bpp(const uint8_t *src, uint8_t *dst, int dst_pitch) {
static const int tile_h = 16;
static const int tile_w = 16;
static const int plane_size = 16 * (16 / 8);
for (int y = 0; y < tile_h; ++y) {
for (int x = 0; x < tile_w / 8; ++x) {
for (int i = 0; i < 8; ++i) {
const uint8_t mask = 1 << (7 - i);
uint8_t color = 0;
for (int b = 0; b < 4; ++b) {
if (src[b * plane_size] & mask) {
color |= (1 << b);
}
}
if (i & 1) {
dst[x * 4 + (i >> 1)] |= color;
} else {
dst[x * 4 + (i >> 1)] = color << 4;
}
}
++src;
}
dst += dst_pitch;
}
}
void video_draw_string(int offset, int hspace, const char *s) {
offset += hspace;
while (*s) {
uint8_t code = *s++;
if (code != 0x20) {
code -= 0x30;
if (code > 9) {
code -= 2;
}
decode_planar(g_res.allfonts + code * 48, g_res.vga + offset * 8, 320, 8, 12, 0);
}
++offset;
}
}
void video_draw_panel_number(int offset, int num) {
const uint8_t *fnt = g_res.allfonts + 48 * 41 + 160 * 23;
decode_planar(fnt + num * 96, g_res.vga + offset * 8, 320, 16, 12, 0);
}
void video_draw_number(int offset, int num) {
const uint8_t *fnt = g_res.allfonts + 0x1C70;
decode_planar(fnt + num * 88, g_res.vga + offset * 8, 320, 16, 11, 0);
}
void video_clear() {
memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H);
}
void video_copy_img(const uint8_t *src) {
decode_planar(src, g_res.background, 320, 320, 200, 0xFF);
}
void video_draw_panel(const uint8_t *src) {
decode_planar(src, g_res.vga + TILEMAP_SCREEN_H * 320, 320, 320, 23, 0xFF);
}
void video_draw_tile(const uint8_t *src, int x_offset, int y_offset) {
int tile_w = 16;
int tile_h = 16;
if (y_offset < 0) {
tile_h += y_offset;
src -= y_offset * 8;
y_offset = 0;
}
if (y_offset + tile_h > TILEMAP_SCREEN_H) {
tile_h = TILEMAP_SCREEN_H - y_offset;
}
if (tile_h <= 0) {
return;
}
uint8_t *dst = g_res.vga + y_offset * TILEMAP_SCREEN_W + x_offset;
for (int y = 0; y < tile_h; ++y) {
for (int x = 0; x < tile_w / 2; ++x) {
const uint8_t color = *src++;
const uint8_t c1 = color >> 4;
if (c1 != 0) {
dst[x * 2] = c1;
}
const uint8_t c2 = color & 15;
if (c2 != 0) {
dst[x * 2 + 1] = c2;
}
}
dst += TILEMAP_SCREEN_W;
}
}
void video_convert_tiles(uint8_t *data, int len) {
for (int offset = 0; offset < (len & ~127); offset += 128) {
uint8_t buffer[16 * 8];
convert_planar_tile_4bpp(data + offset, buffer, 8);
memcpy(data + offset, buffer, 16 * 8);
}
}
void video_load_front_tiles() {
g_sys.render_unload_sprites(RENDER_SPR_FG);
assert((g_res.frontlen & 127) == 0);
const int count = g_res.frontlen / (16 * 8);
assert(count <= MAX_FRONT_TILES);
struct sys_rect_t r[MAX_FRONT_TILES];
const int w = 256;
const int h = 192;
memset(g_res.vga, 0, w * h);
int tile = 0;
for (int y = 0; y < h; y += 16) {
for (int x = 0; x < w; x += 16) {
r[tile].x = x;
r[tile].y = y;
r[tile].w = 16;
r[tile].h = 16;
decode_planar(g_res.frontdat + tile * 16 * 8, g_res.vga + y * w + x, w, 16, 16, 0);
++tile;
if (tile == count) {
g_sys.render_load_sprites(RENDER_SPR_FG, count, r, g_res.vga, w, h, 0, 0x0);
return;
}
}
}
}
void video_set_palette() {
}
void fade_in_palette() {
if (!g_sys.input.quit) {
g_sys.fade_in_palette();
}
}
void fade_out_palette() {
if (!g_sys.input.quit) {
g_sys.fade_out_palette();
}
}
void video_wait_vbl() {
}
void video_transition_close() {
}
void video_transition_open() {
}
void video_load_sprites() {
const uint16_t *sprite_offsets = (const uint16_t *)spr_size_tbl;
struct sys_rect_t r[MAX_SPRITES];
uint8_t *data = (uint8_t *)calloc(MAX_SPRITESHEET_W * MAX_SPRITESHEET_H, 1);
if (data) {
int current_x = 0;
int max_w = 0;
int current_y = 0;
int max_h = 0;
int offset = 0;
int count = 0;
uint8_t value;
for (int i = 0; (value = sprite_offsets[i] & 255) != 0; ++i, ++count) {
value = (value >> 3) | ((value & 7) << 5);
if ((value & 0xE0) != 0) {
value &= ~0xE0;
++value;
}
const int h = sprite_offsets[i] >> 8;
const int w = value * 8;
assert((sprite_offsets[i] & 255) == w);
const int size = (h * value) * 4;
if (current_x + w > MAX_SPRITESHEET_W) {
current_y += max_h;
if (current_x > max_w) {
max_w = current_x;
}
current_x = 0;
max_h = h;
} else {
if (h > max_h) {
max_h = h;
}
}
decode_planar(g_res.sprites + offset, data + current_y * MAX_SPRITESHEET_W + current_x, MAX_SPRITESHEET_W, w, h, 0xFF);
offset += size;
r[i].x = current_x;
r[i].y = current_y;
r[i].w = w;
r[i].h = h;
current_x += w;
}
assert(count <= MAX_SPRITES);
assert(max_w <= MAX_SPRITESHEET_W);
assert(current_y + max_h <= MAX_SPRITESHEET_H);
g_sys.render_unload_sprites(RENDER_SPR_GAME);
g_sys.render_load_sprites(RENDER_SPR_GAME, count, r, data, MAX_SPRITESHEET_W, current_y + max_h, 0, 0x0);
free(data);
print_debug(DBG_SCREEN, "sprites total_size %d count %d", offset, count);
}
}
void video_draw_sprite(int num, int x, int y, int flag) {
g_sys.render_add_sprite(RENDER_SPR_GAME, num, x, y, flag != 0);
}

151
p2/sound.c Normal file
View File

@ -0,0 +1,151 @@
#include "game.h"
#include "resource.h"
#include "sys.h"
#include "util.h"
#include <libmodplug/modplug.h>
#define MAX_SOUNDS 11
static const bool _volume = false;
static const uint16_t sound_sizes_tbl[] = {
0x188E, 0x1C80, 0x235E, 0x19E6, 0x0AB2, 0x0912, 0x0000, 0x35D2,
0x06C4, 0x1C86, 0x0E2E
};
static const uint8_t sound_volume_tbl[] = {
0x3F,0x37,0x32,0x2F,0x2C,0x2A,0x28,0x27,0x26,0x24,0x23,0x22,0x21,0x21,0x20,0x1F,
0x1E,0x1E,0x1D,0x1C,0x1C,0x1B,0x1B,0x1A,0x1A,0x19,0x19,0x19,0x18,0x18,0x17,0x17,
0x17,0x16,0x16,0x16,0x15,0x15,0x15,0x15,0x14,0x14,0x14,0x14,0x13,0x13,0x13,0x13,
0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11,0x11,0x10,0x10,0x10,0x10,0x10,0x0F,0x0F,
0x0F,0x0F,0x0F,0x0F,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,
0x0D,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,
0x0B,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,
0x09,0x09,0x09,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x07,0x07
};
static const char *trk_names_tbl[] = {
"PRES.TRK",
"CODE.TRK",
"CARTE.TRK",
"PRESENTA.TRK",
"GLACE.TRK",
0,
0,
0,
0,
"MINES.TRK",
"MYSTERY.TRK",
0,
0,
"MONSTER.TRK",
"FINAL.TRK",
"BRAVO.TRK",
"KOOL.TRK",
"BOULA.TRK"
};
struct mixerchannel_t {
uint8_t *data;
uint32_t pos;
uint32_t step;
uint32_t size;
};
static const int _rate = SYS_AUDIO_FREQ;
static struct mixerchannel_t _channel;
static ModPlugFile *_mpf;
static uint16_t sound_offsets_tbl[MAX_SOUNDS];
static void mix(void *param, uint8_t *buf, int len) {
memset(buf, 0, len);
if (_mpf) {
const int count = ModPlug_Read(_mpf, buf, len);
if (count == 0) {
ModPlug_SeekOrder(_mpf, 0);
}
}
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 int8_t pcm = _volume ? sound_volume_tbl[(_channel.data[pos] ^ 0x80) >> 1] : _channel.data[pos];
const int sample = *(int16_t *)(buf + i) + pcm * 256;
*(int16_t *)(buf + i) = (sample < -32768 ? -32768 : (sample > 32767 ? 32767 : sample));
_channel.pos += _channel.step;
}
}
}
void sound_init() {
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);
uint16_t offset = 0;
for (int i = 0; i < MAX_SOUNDS; ++i) {
sound_offsets_tbl[i] = offset;
offset += sound_sizes_tbl[i];
}
g_sys.start_audio(mix, 0);
}
void sound_fini() {
g_sys.stop_audio();
}
void play_sound(int num) {
assert(num < MAX_SOUNDS);
print_debug(DBG_MIXER, "play_sound %d", num);
if (!g_res.samples) { /* no SAMPLE. file with demo */
return;
}
const int sample_offset = sound_offsets_tbl[num];
const int sample_size = sound_sizes_tbl[num];
print_debug(DBG_MIXER, "sample num %d offset 0x%x size %d", num, sample_offset, sample_size);
if (sample_size == 0) {
return;
}
g_sys.lock_audio();
_channel.data = g_res.samples + sample_offset;
_channel.pos = 0;
_channel.step = (8000 << 16) / _rate;
_channel.size = sample_size;
g_sys.unlock_audio();
}
void play_music(int num) {
if (g_res.dos_demo) { /* no .TRK files with demo */
return;
}
const char *filename = trk_names_tbl[num];
if (filename) {
print_debug(DBG_MIXER, "play_music '%s'", filename);
g_sys.lock_audio();
if (_mpf) {
ModPlug_Unload(_mpf);
_mpf = 0;
}
uint8_t *data = load_file(filename);
if (data) {
_mpf = ModPlug_Load(data, g_uncompressed_size);
if (_mpf) {
print_debug(DBG_MIXER, "Loaded module '%s'", ModPlug_GetName(_mpf));
}
free(data);
}
g_sys.unlock_audio();
}
}

371
p2/staticres.c Normal file
View File

@ -0,0 +1,371 @@
#include "game.h"
static const uint8_t palette_data_2df0[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x24,0x28,0x3C,0x28,
0x00,0x08,0x04,0x04,0x04,0x38,0x30,0x08,0x00,0x18,0x10,0x08,0x20,0x0C,0x08,0x30,
0x18,0x14,0x10,0x0C,0x1C,0x18,0x14,0x24,0x20,0x1C,0x2C,0x28,0x24,0x3C,0x38,0x34
};
static const uint8_t palette_data_2e50[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x10,0x28,0x38,0x28,
0x00,0x08,0x00,0x00,0x00,0x38,0x30,0x08,0x00,0x18,0x10,0x08,0x20,0x0C,0x08,0x30,
0x18,0x10,0x10,0x10,0x18,0x18,0x18,0x20,0x20,0x20,0x28,0x28,0x28,0x38,0x38,0x38
};
static const uint8_t palette_data_2dc0[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x28,0x34,0x3C,0x28,
0x00,0x08,0x04,0x04,0x04,0x38,0x30,0x08,0x00,0x14,0x18,0x00,0x20,0x1C,0x00,0x30,
0x28,0x08,0x14,0x0C,0x14,0x1C,0x14,0x20,0x28,0x20,0x28,0x30,0x28,0x38,0x3C,0x38
};
static const uint8_t palette_data_2d90[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x10,0x28,0x38,0x28,
0x00,0x08,0x04,0x04,0x04,0x38,0x30,0x08,0x00,0x14,0x14,0x00,0x20,0x14,0x08,0x30,
0x1C,0x34,0x20,0x14,0x04,0x08,0x1C,0x10,0x14,0x30,0x14,0x24,0x38,0x2C,0x34,0x3C
};
static const uint8_t palette_data_2d00[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x10,0x28,0x38,0x28,
0x00,0x08,0x04,0x04,0x00,0x38,0x30,0x08,0x18,0x00,0x00,0x28,0x04,0x00,0x3C,0x14,
0x00,0x34,0x20,0x14,0x20,0x14,0x24,0x28,0x1C,0x3C,0x2C,0x2C,0x3C,0x34,0x38,0x3C
};
static const uint8_t palette_data_2d60[] = {
0x00,0x00,0x00,0x3C,0x24,0x14,0x2C,0x0C,0x00,0x1C,0x08,0x04,0x3C,0x30,0x28,0x28,
0x00,0x08,0x04,0x04,0x04,0x3C,0x2C,0x08,0x08,0x18,0x00,0x18,0x20,0x0C,0x28,0x2C,
0x10,0x34,0x18,0x10,0x24,0x08,0x18,0x2C,0x18,0x24,0x34,0x24,0x30,0x3C,0x34,0x38
};
static const uint8_t palette_data_2ca0[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x18,0x18,0x24,0x28,
0x00,0x08,0x00,0x00,0x00,0x38,0x30,0x08,0x18,0x1C,0x2C,0x18,0x24,0x2C,0x28,0x30,
0x38,0x34,0x20,0x14,0x00,0x18,0x14,0x00,0x24,0x1C,0x14,0x34,0x2C,0x3C,0x3C,0x38
};
static const uint8_t palette_data_2d30[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x10,0x28,0x38,0x28,
0x00,0x08,0x04,0x04,0x04,0x38,0x30,0x08,0x00,0x10,0x10,0x00,0x20,0x10,0x08,0x30,
0x08,0x14,0x08,0x00,0x00,0x18,0x14,0x00,0x24,0x1C,0x14,0x34,0x2C,0x3C,0x3C,0x3C
};
static const uint8_t palette_data_2cd0[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x0C,0x08,0x14,0x28,
0x00,0x08,0x00,0x00,0x00,0x38,0x30,0x08,0x00,0x0E,0x00,0x00,0x14,0x00,0x00,0x1A,
0x00,0x0C,0x0A,0x02,0x14,0x18,0x14,0x1C,0x20,0x20,0x2C,0x28,0x2C,0x3C,0x3C,0x38
};
static const uint8_t palette_data_2e80[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x10,0x28,0x38,0x28,
0x00,0x08,0x00,0x00,0x00,0x38,0x30,0x08,0x00,0x14,0x00,0x00,0x20,0x00,0x08,0x30,
0x08,0x34,0x20,0x14,0x1C,0x08,0x08,0x28,0x14,0x14,0x3C,0x28,0x28,0x38,0x38,0x38
};
static const uint8_t palette_data_2eb0[] = {
0x00,0x00,0x00,0x38,0x28,0x20,0x28,0x18,0x10,0x20,0x10,0x08,0x10,0x28,0x38,0x28,
0x00,0x08,0x00,0x00,0x00,0x38,0x30,0x08,0x00,0x14,0x00,0x00,0x20,0x00,0x08,0x30,
0x08,0x34,0x20,0x14,0x14,0x18,0x1C,0x1C,0x20,0x24,0x28,0x28,0x2C,0x38,0x38,0x38
};
const uint8_t *palettes_tbl[] = {
palette_data_2df0,
palette_data_2e50,
palette_data_2dc0,
palette_data_2d90,
palette_data_2d00,
palette_data_2d60,
palette_data_2ca0,
palette_data_2d30,
palette_data_2cd0,
palette_data_2cd0,
palette_data_2e80,
palette_data_2e80,
palette_data_2e80,
palette_data_2eb0,
palette_data_2cd0,
palette_data_2ca0,
};
const uint8_t credits_palette_data[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x3C,
0x3C,0x1C,0x3C,0x3C,0x0C,0x3C,0x38,0x00,0x38,0x30,0x00,0x34,0x2C,0x00,0x34,0x24,
0x00,0x2C,0x24,0x00,0x24,0x1C,0x00,0x20,0x18,0x00,0x18,0x14,0x00,0x14,0x10,0x00
};
const uint8_t light_palette_data[] = {
0x00,0x00,0x00,0x0F,0x12,0x18,0x0C,0x0F,0x15,0x09,0x0C,0x12,0x00,0x0F,0x12,0x0C,
0x0C,0x12,0x00,0x00,0x00,0x00,0x15,0x18,0x00,0x0C,0x0C,0x00,0x0F,0x0F,0x06,0x12,
0x12,0x00,0x09,0x0C,0x00,0x0C,0x12,0x00,0x0F,0x18,0x00,0x12,0x1B,0x0F,0x15,0x1B
};
const uint8_t spr_offs_tbl[] = {
0x14,0x24,0x10,0x23,0x0C,0x24,0x10,0x24,0x10,0x25,0x10,0x25,0x0F,0x24,0x10,0x23,
0x0F,0x23,0x0F,0x23,0x0C,0x23,0x10,0x26,0x14,0x1F,0x18,0x1F,0x10,0x1F,0x10,0x24,
0x0C,0x20,0x14,0x1E,0x14,0x1F,0x14,0x1F,0x10,0x1E,0x0C,0x1E,0x10,0x1F,0x0C,0x1E,
0x0C,0x20,0x14,0x22,0x10,0x21,0x10,0x23,0x10,0x22,0x14,0x1F,0x14,0x20,0x14,0x1E,
0x14,0x1F,0x18,0x20,0x10,0x24,0x0C,0x20,0x10,0x20,0x10,0x21,0x0C,0x1D,0x0E,0x11,
0x09,0x10,0x0E,0x11,0x0F,0x10,0x09,0x0F,0x0A,0x0F,0x0C,0x0E,0x10,0x0B,0x0C,0x10,
0x10,0x19,0x10,0x1F,0x0C,0x21,0x10,0x1F,0x10,0x1F,0x04,0x06,0x04,0x08,0x08,0x09,
0x08,0x0B,0x08,0x0B,0x08,0x13,0x0C,0x12,0x0C,0x0D,0x08,0x10,0x08,0x10,0x08,0x10,
0x08,0x0F,0x0C,0x0F,0x0C,0x13,0x11,0x0F,0x0E,0x0D,0x07,0x0A,0x08,0x0F,0x08,0x0F,
0x08,0x0C,0x08,0x0F,0x0B,0x09,0x0C,0x09,0x0C,0x09,0x0C,0x09,0x0C,0x09,0x0C,0x09,
0x0B,0x09,0x0C,0x09,0x0C,0x09,0x0C,0x09,0x0C,0x09,0x0C,0x09,0x14,0x0D,0x17,0x0D,
0x16,0x0D,0x17,0x0D,0x1B,0x11,0x0E,0x05,0x07,0x0D,0x07,0x0D,0x07,0x0D,0x07,0x0D,
0x07,0x0D,0x06,0x13,0x0F,0x16,0x0B,0x1E,0x0B,0x1D,0x0B,0x21,0x06,0x21,0x0B,0x21,
0x0B,0x07,0x0B,0x07,0x0B,0x07,0x0B,0x07,0x0B,0x07,0x0B,0x07,0x19,0x41,0x16,0x2C,
0x16,0x20,0x13,0x2E,0x10,0x26,0x13,0x23,0x11,0x21,0x14,0x21,0x18,0x0E,0x18,0x1D,
0x18,0x1F,0x0C,0x13,0x0C,0x14,0x09,0x17,0x09,0x1B,0x0F,0x17,0x0C,0x1B,0x0C,0x1F,
0x0C,0x0E,0x08,0x0F,0x0C,0x13,0x08,0x12,0x08,0x12,0x0C,0x0C,0x0C,0x13,0x08,0x19,
0x0C,0x15,0x0C,0x17,0x08,0x1B,0x08,0x14,0x08,0x17,0x08,0x15,0x0C,0x0B,0x0C,0x0B,
0x08,0x16,0x08,0x16,0x08,0x13,0x08,0x12,0x08,0x12,0x08,0x13,0x08,0x1D,0x08,0x15,
0x08,0x1C,0x0C,0x14,0x0C,0x0F,0x08,0x0F,0x08,0x13,0x08,0x15,0x08,0x15,0x0C,0x11,
0x0C,0x0C,0x0C,0x0D,0x0C,0x0D,0x0C,0x11,0x0C,0x16,0x08,0x0D,0x08,0x10,0x08,0x18,
0x08,0x11,0x0C,0x0B,0x08,0x17,0x0C,0x12,0x0C,0x0F,0x0C,0x0F,0x0C,0x0F,0x08,0x13,
0x0C,0x14,0x08,0x12,0x04,0x17,0x08,0x15,0x08,0x12,0x08,0x0C,0x08,0x0C,0x08,0x0C,
0x0C,0x17,0x08,0x12,0x08,0x10,0x08,0x0E,0x08,0x16,0x10,0x0D,0x0C,0x10,0x0C,0x12,
0x08,0x0D,0x0C,0x0E,0x08,0x13,0x08,0x19,0x04,0x16,0x08,0x0D,0x08,0x13,0x0C,0x10,
0x0C,0x12,0x0C,0x0D,0x08,0x0F,0x08,0x1C,0x08,0x0E,0x08,0x18,0x0C,0x12,0x10,0x14,
0x10,0x11,0x08,0x0B,0x08,0x1A,0x0C,0x12,0x0C,0x0D,0x0C,0x0C,0x08,0x0F,0x08,0x13,
0x08,0x13,0x08,0x13,0x08,0x13,0x08,0x13,0x0C,0x10,0x0C,0x16,0x08,0x12,0x0C,0x10,
0x08,0x0C,0x08,0x0C,0x08,0x0B,0x10,0x10,0x14,0x0E,0x14,0x0E,0x14,0x0E,0x10,0x0E,
0x10,0x0D,0x08,0x12,0x08,0x12,0x0C,0x12,0x10,0x29,0x10,0x1D,0x0C,0x14,0x14,0x21,
0x18,0x1A,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,
0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,
0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,
0x08,0x0B,0x08,0x0B,0x08,0x0B,0x08,0x0B,0x04,0x08,0x08,0x0B,0x04,0x0B,0x04,0x05,
0x04,0x05,0x08,0x0C,0x18,0x28,0x1C,0x1E,0x18,0x30,0x10,0x33,0x22,0x46,0x13,0x46,
0x0D,0x1A,0x19,0x1D,0x1C,0x0E,0x08,0x0C,0x08,0x0C,0x08,0x0C,0x08,0x0C,0x08,0x0C,
0x08,0x0C,0x08,0x0C,0x08,0x0C,0x08,0x0C,0x08,0x0C,0x08,0x0C,0x08,0x0C,0x08,0x0C,
0x08,0x0C,0x08,0x0C,0x08,0x0C,0x10,0x15,0x04,0x0A,0x08,0x0C,0x08,0x0C,0x08,0x0C,
0x20,0x1F,0x0C,0x18,0x10,0x1D,0x0C,0x1E,0x10,0x1D,0x18,0x28,0x10,0x13,0x10,0x19,
0x0C,0x1C,0x10,0x0E,0x10,0x0F,0x10,0x0E,0x10,0x0F,0x08,0x1C,0x08,0x1C,0x08,0x1C,
0x08,0x1C,0x0C,0x15,0x0C,0x19,0x10,0x17,0x11,0x17,0x0C,0x20,0x0C,0x1F,0x10,0x16,
0x14,0x0E,0x14,0x09,0x0C,0x0F,0x0F,0x0B,0x0C,0x15,0x08,0x0A,0x08,0x09,0x04,0x0A,
0x08,0x0A,0x08,0x0A,0x0C,0x07,0x08,0x0E,0x0C,0x0C,0x0C,0x0B,0x14,0x1D,0x10,0x1C,
0x10,0x1C,0x14,0x18,0x14,0x24,0x14,0x1F,0x0C,0x20,0x0F,0x1F,0x0D,0x1F,0x10,0x1F,
0x02,0x15,0x01,0x15,0xFF,0x18,0xFF,0x18,0x10,0x14,0x10,0x14,0x0C,0x1C,0x04,0x05,
0x0C,0x07,0x10,0x0C,0x10,0x15,0x0C,0x06,0x0C,0x08,0x0C,0x16,0x10,0x1C,0x0C,0x1F,
0x14,0x1E,0x10,0x1A,0x10,0x13,0x08,0x13,0x0C,0x12,0x0C,0x0B,0x0C,0x05,0x18,0x1B,
0x18,0x1D,0x18,0x29,0x18,0x20,0x10,0x03,0x10,0x05,0x14,0x0B,0x18,0x13,0x1B,0x1A,
0x20,0x20,0x1E,0x1F,0x20,0x1F,0x21,0x20,0x18,0x27,0x18,0x1D,0x15,0x1E,0x18,0x1B,
0x20,0x22,0x1C,0x24,0x14,0x20,0x20,0x23,0x20,0x2B,0x1C,0x2D,0x10,0x25,0x10,0x25,
0x10,0x22,0x10,0x25,0x18,0x2E,0x18,0x2B,0x1C,0x1E,0x14,0x1C,0x14,0x18,0x1C,0x10,
0x10,0x31,0x10,0x3B,0x10,0x30,0x1C,0x22,0x20,0x1B,0x20,0x32,0x28,0x21,0x20,0x28,
0x14,0x15,0x10,0x20,0x10,0x1F,0x10,0x1E,0x18,0x1C,0x28,0x20,0x14,0x1E,0x14,0x23,
0x14,0x3E,0x1C,0x19,0x1C,0x19,0x1C,0x19,0x14,0x10,0x14,0x12,0x10,0x0E,0x34,0x29,
0x08,0x16,0x0C,0x17,0x0C,0x17,0x0C,0x17,0x10,0x17,0x0C,0x18,0x10,0x18,0x10,0x18,
0x10,0x17,0x10,0x1B,0x10,0x1B,0x10,0x18,0x0C,0x18,0x00,0x00
};
const uint8_t spr_size_tbl[] = {
0x28,0x24,0x20,0x23,0x18,0x24,0x20,0x22,0x20,0x25,0x20,0x25,0x20,0x24,0x20,0x23,
0x20,0x23,0x20,0x23,0x18,0x23,0x20,0x26,0x28,0x1F,0x30,0x1F,0x20,0x1F,0x20,0x24,
0x18,0x20,0x28,0x1E,0x28,0x1F,0x28,0x1F,0x20,0x1E,0x18,0x1E,0x20,0x1F,0x18,0x1E,
0x18,0x20,0x28,0x22,0x20,0x21,0x20,0x23,0x20,0x22,0x28,0x1F,0x28,0x20,0x28,0x1E,
0x28,0x1F,0x30,0x20,0x20,0x24,0x18,0x20,0x20,0x20,0x20,0x21,0x18,0x1D,0x18,0x11,
0x10,0x10,0x18,0x11,0x20,0x0E,0x18,0x0F,0x10,0x0F,0x18,0x0E,0x20,0x0B,0x18,0x10,
0x20,0x19,0x20,0x1F,0x18,0x21,0x20,0x1F,0x20,0x1F,0x08,0x06,0x08,0x08,0x10,0x09,
0x10,0x0B,0x10,0x0B,0x10,0x13,0x18,0x12,0x18,0x0D,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x0F,0x18,0x0F,0x18,0x13,0x18,0x18,0x20,0x13,0x18,0x19,0x10,0x0F,0x10,0x0F,
0x10,0x09,0x10,0x0F,0x18,0x09,0x18,0x09,0x18,0x09,0x18,0x09,0x18,0x09,0x18,0x09,
0x18,0x09,0x18,0x09,0x18,0x09,0x18,0x09,0x18,0x09,0x18,0x09,0x28,0x0D,0x30,0x0D,
0x30,0x0D,0x30,0x0D,0x38,0x11,0x18,0x13,0x10,0x0D,0x10,0x0D,0x10,0x0D,0x10,0x0D,
0x10,0x0D,0x18,0x13,0x20,0x16,0x18,0x1E,0x18,0x1D,0x18,0x21,0x10,0x21,0x18,0x21,
0x18,0x07,0x18,0x07,0x18,0x07,0x18,0x07,0x18,0x07,0x18,0x07,0x30,0x41,0x28,0x2C,
0x30,0x20,0x28,0x2E,0x20,0x26,0x28,0x23,0x30,0x21,0x28,0x21,0x30,0x0E,0x30,0x1D,
0x30,0x1F,0x30,0x13,0x30,0x14,0x30,0x17,0x30,0x1B,0x30,0x17,0x28,0x1B,0x28,0x22,
0x18,0x0E,0x10,0x0F,0x18,0x13,0x10,0x12,0x10,0x12,0x18,0x0C,0x18,0x13,0x10,0x19,
0x18,0x15,0x18,0x17,0x10,0x1B,0x10,0x14,0x10,0x17,0x10,0x15,0x18,0x0B,0x18,0x0B,
0x10,0x16,0x10,0x16,0x10,0x13,0x10,0x12,0x10,0x12,0x10,0x13,0x10,0x1D,0x10,0x15,
0x10,0x1C,0x18,0x14,0x18,0x0F,0x10,0x0F,0x10,0x13,0x10,0x15,0x10,0x15,0x18,0x11,
0x18,0x0C,0x18,0x0D,0x18,0x0D,0x18,0x11,0x18,0x16,0x10,0x0D,0x10,0x10,0x10,0x18,
0x10,0x11,0x18,0x0B,0x10,0x17,0x18,0x12,0x18,0x0F,0x18,0x0F,0x18,0x0F,0x10,0x13,
0x18,0x14,0x10,0x12,0x08,0x17,0x10,0x15,0x10,0x12,0x10,0x0C,0x10,0x0C,0x10,0x0C,
0x18,0x17,0x10,0x12,0x10,0x10,0x10,0x0E,0x10,0x16,0x20,0x0D,0x18,0x10,0x18,0x12,
0x10,0x0D,0x18,0x0E,0x10,0x13,0x10,0x19,0x08,0x16,0x10,0x0D,0x10,0x13,0x18,0x10,
0x18,0x12,0x18,0x0D,0x10,0x0F,0x10,0x1C,0x10,0x0E,0x10,0x18,0x18,0x12,0x20,0x14,
0x20,0x11,0x10,0x0B,0x10,0x1A,0x18,0x12,0x18,0x0D,0x18,0x0C,0x10,0x0F,0x10,0x13,
0x10,0x13,0x10,0x13,0x10,0x13,0x10,0x13,0x18,0x10,0x18,0x16,0x10,0x12,0x18,0x10,
0x10,0x0C,0x10,0x0C,0x10,0x0B,0x20,0x10,0x28,0x0E,0x28,0x0E,0x28,0x0E,0x20,0x0E,
0x20,0x0D,0x10,0x12,0x10,0x12,0x18,0x12,0x20,0x29,0x20,0x1D,0x18,0x14,0x28,0x21,
0x30,0x1A,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,
0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,
0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,
0x10,0x0B,0x10,0x0B,0x10,0x0B,0x10,0x0B,0x08,0x08,0x10,0x0B,0x08,0x0B,0x08,0x05,
0x08,0x05,0x10,0x0C,0x30,0x28,0x38,0x1E,0x30,0x30,0x20,0x33,0x30,0x46,0x30,0x46,
0x28,0x1B,0x30,0x1D,0x38,0x0E,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,
0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,0x10,0x0C,
0x10,0x0C,0x10,0x0C,0x10,0x0C,0x20,0x15,0x08,0x0A,0x10,0x0C,0x10,0x0C,0x10,0x0C,
0x40,0x1F,0x18,0x18,0x20,0x1D,0x18,0x1E,0x20,0x1D,0x30,0x28,0x20,0x13,0x20,0x19,
0x18,0x1C,0x20,0x0E,0x20,0x0F,0x20,0x0E,0x20,0x0F,0x10,0x1C,0x10,0x1C,0x10,0x1C,
0x10,0x1C,0x18,0x15,0x18,0x19,0x20,0x17,0x20,0x17,0x18,0x20,0x18,0x1E,0x20,0x16,
0x28,0x0E,0x28,0x0C,0x18,0x0F,0x20,0x0B,0x18,0x15,0x10,0x0A,0x10,0x09,0x08,0x0A,
0x10,0x0A,0x10,0x0A,0x18,0x07,0x10,0x0E,0x18,0x0C,0x18,0x0B,0x28,0x1D,0x20,0x1C,
0x20,0x1C,0x28,0x18,0x28,0x24,0x28,0x1F,0x18,0x20,0x20,0x1F,0x20,0x1F,0x20,0x1F,
0x10,0x15,0x10,0x15,0x10,0x18,0x18,0x18,0x28,0x14,0x28,0x12,0x20,0x1C,0x08,0x05,
0x18,0x07,0x20,0x0C,0x20,0x15,0x18,0x06,0x18,0x08,0x18,0x16,0x20,0x1C,0x18,0x1F,
0x28,0x1E,0x20,0x1A,0x20,0x13,0x10,0x13,0x18,0x12,0x18,0x0B,0x18,0x05,0x30,0x1B,
0x30,0x1D,0x30,0x29,0x30,0x20,0x20,0x03,0x20,0x05,0x28,0x0B,0x30,0x13,0x38,0x1B,
0x40,0x20,0x40,0x1F,0x40,0x1F,0x40,0x20,0x30,0x27,0x30,0x1D,0x30,0x1E,0x30,0x1B,
0x40,0x22,0x38,0x24,0x28,0x20,0x40,0x23,0x40,0x2B,0x38,0x2D,0x20,0x25,0x20,0x25,
0x20,0x22,0x20,0x25,0x30,0x2E,0x30,0x2B,0x38,0x1E,0x28,0x1C,0x28,0x18,0x38,0x10,
0x20,0x31,0x20,0x3B,0x20,0x30,0x38,0x22,0x40,0x1B,0x20,0x1E,0x20,0x1C,0x20,0x20,
0x28,0x15,0x20,0x20,0x20,0x1F,0x20,0x1E,0x30,0x1C,0x50,0x20,0x28,0x1E,0x28,0x23,
0x28,0x3E,0x38,0x16,0x38,0x18,0x38,0x17,0x28,0x10,0x28,0x12,0x20,0x0E,0x68,0x29,
0x10,0x16,0x18,0x17,0x18,0x17,0x18,0x17,0x20,0x17,0x18,0x18,0x20,0x18,0x20,0x18,
0x20,0x17,0x20,0x1B,0x20,0x1B,0x20,0x18,0x18,0x18,0x00,0x00
};
const uint16_t score_tbl[] = {
0x000A,0x0014,0x001E,0x0032,0x003C,0x0046,0x004B,0x0050,0x0064,0x00C8,0x01F4,0x0320,0x03E8,0x07D0,0x0BB8,0x1770,
0x2710
};
const uint8_t score_spr_lut[] = {
0x10,0x0F,0x0D,0x0E,0x0C,0x0C,0x0D,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0x03,0x02,0x02,0x01,0x01,0x03,0x02,0x03,0x03,0x03,0x02,0x03,0x00,
0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x03,0x03,0x01,0x03,0x03,0x01,0x03,0x0B,0x01,
0x00,0x03,0x01,0x03,0x02,0x02,0x02,0x00,0x03,0x02,0x01,0x00,0x02,0x03,0x01,0x01,
0x01,0x02,0x03,0x01,0x03,0x03,0x00,0x09,0x0A,0x08,0x08,0x09,0x0A,0x08,0x07,0x08,
0x0B,0x0A,0x04,0x06,0x04,0x07,0x05,0x04,0x04,0x05,0x07,0x04,0x0B,0x07,0x03,0x06,
0x06,0x06,0x06,0x03,0x06,0x0A,0x07,0x05,0x05,0x0B,0x0A,0x08,0x09,0x00
};
static const uint8_t object_anim_5e71[] = {
0x09,0x00,0xFE,0xFF
};
static const uint8_t object_anim_5e79[] = {
0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x03,0x00,
0x04,0x00,0x04,0x00,0x05,0x00,0x05,0x00,0xE8,0xFF
};
static const uint8_t object_anim_5ead[] = {
0x0B,0x00,0x0B,0x00,0x0B,0x00,0x0B,0x00,0x0C,0x00,0xFE,0xFF
};
static const uint8_t object_anim_5eb9[] = {
0x22,0x00,0x22,0x00,0x23,0x00,0x23,0x00,0x24,0x00,0x24,0x00,0x24,0x40,0xF2,0xFF
};
static const uint8_t object_anim_5ec9[] = {
0x15,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x16,0x00,0x16,0x00,0x16,0x00,0x16,0x00,
0x17,0x00,0x17,0x00,0x17,0x00,0x17,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,
0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x14,0x00,0x14,0x00,0x14,0x00,0x14,0x00,
0xD0,0xFF
};
static const uint8_t object_anim_5efb[] = {
0x12,0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x11,0x00,0x11,0x00,0x11,0x00,
0x11,0x00,0x11,0x00,0xEC,0xFF
};
static const uint8_t object_anim_5f11[] = {
0x25,0x00,0x25,0x00,0x25,0x00,0x26,0x00,0x26,0x00,0x26,0x00,0x0E,0x00,0x0E,0x00,
0x0E,0x40,0xEE,0xFF
};
static const uint8_t object_anim_5f25[] = {
0x0F,0x00,0x0F,0x00,0x0F,0x00,0x23,0x00,0x23,0x00,0x23,0x00,0x10,0x00,0x10,0x00,
0x10,0x40,0xEE,0xFF
};
static const uint8_t object_anim_5f39[] = {
0x21,0x00,0xFE,0xFF
};
static const uint8_t object_anim_5f4f[] = {
0x06,0x00,0x06,0x00,0x06,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x06,0x00,0x06,0x00,
0x06,0x00,0x06,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x06,0x00,0x06,0x00,
0x06,0x00,0x06,0x00,0x06,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,
0xEC,0xFF
};
static const uint8_t object_anim_5f81[] = {
0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x0A,0x00,0x0A,0x00,0x0A,0x00,0x0A,0x00,
0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,
0xE0,0xFF
};
static const uint8_t object_anim_5f3d[] = {
0x19,0x00,0x19,0x00,0x1A,0x00,0x1A,0x00,0x1B,0x00,0x1B,0x00,0x1C,0x00,0x1C,0x00,
0xF8,0xFF
};
static const uint8_t object_anim_5fa3[] = {
0x1D,0x00,0x1D,0x00,0x1D,0x00,0x1F,0x00,0x1F,0x00,0x1F,0x00,0xF4,0xFF
};
static const uint8_t object_anim_5e75[] = {
0x2F,0x00,0xFE,0xFF
};
static const uint8_t object_anim_5e93[] = {
0x27,0x00,0x27,0x00,0x28,0x00,0x28,0x00,0x29,0x00,0x29,0x00,0x2A,0x00,0x2A,0x00,
0x2B,0x00,0x2B,0x00,0x2C,0x00,0x2C,0x00,0xE8,0xFF
};
const uint8_t *object_anim_tbl[] = {
object_anim_5e71, object_anim_5e79, object_anim_5ead, object_anim_5eb9,
object_anim_5ec9, object_anim_5efb, object_anim_5f11, object_anim_5f25,
object_anim_5f39, 0, 0, 0,
0, 0, 0, 0,
object_anim_5f4f, object_anim_5f81, object_anim_5f3d, object_anim_5fa3,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
object_anim_5e75, object_anim_5e93, 0, object_anim_5e75,
object_anim_5e75, object_anim_5e75, object_anim_5e75, object_anim_5e75,
};
static const uint8_t club_anim_data[] = {
0x22,0x00,0x3A,0x00,0x0B,0x00,0x10,0x00,0x23,0x00,0x3B,0x00,0x07,0x00,0x19,0x00,
0x24,0x00,0x3C,0x00,0xE9,0xFF,0x02,0x00,0x25,0x00,0x3D,0x00,0x0B,0x00,0x03,0x00,
0x26,0x00,0x3E,0x00,0x08,0x00,0x15,0x00,0x0E,0x00,0x3F,0x00,0xEE,0xFF,0x1B,0x00,
0x0F,0x00,0x40,0x00,0x08,0x00,0x12,0x00,0x10,0x00,0x41,0x00,0xF7,0xFF,0xF6,0xFF,
0xAA,0x55,0x22,0x00,0xEB,0x00,0x0F,0x00,0x1F,0x00,0x23,0x00,0xEC,0x00,0xFA,0xFF,
0x0F,0x00,0x24,0x00,0xF0,0x00,0xE6,0xFF,0xF6,0xFF,0x25,0x00,0xEE,0x00,0x14,0x00,
0x00,0x00,0x26,0x00,0xEC,0x00,0xFA,0xFF,0x0F,0x00,0x0E,0x00,0xEF,0x00,0xE7,0xFF,
0x14,0x00,0x0F,0x00,0xEB,0x00,0x0E,0x00,0x1F,0x00,0x10,0x00,0xED,0x00,0xEE,0xFF,
0xEB,0xFF,0xAA,0x55,0x22,0x00,0x43,0x00,0x08,0x00,0x27,0x00,0x23,0x00,0x43,0x00,
0x02,0x00,0x1E,0x00,0x24,0x00,0x44,0x00,0xF4,0xFF,0x0D,0x00,0x25,0x00,0x44,0x00,
0x02,0x00,0x1E,0x00,0x0E,0x00,0x44,0x00,0x00,0x00,0x20,0x00,0x0F,0x00,0x43,0x00,
0x08,0x00,0x25,0x00,0x10,0x00,0x44,0x00,0xFA,0xFF,0x03,0x00,0xAA,0x55,0xD0,0x00,
0xC0,0xFF,0x43,0x00,0x44,0x00,0x45,0x00,0x5B,0x00,0xF8,0xFF,0x22,0x00,0x12,0x01,
0x08,0x00,0x13,0x00,0x23,0x00,0x13,0x01,0x02,0x00,0x0A,0x00,0x24,0x00,0x14,0x01,
0xF4,0xFF,0xFD,0xFF,0x25,0x00,0x15,0x01,0x02,0x00,0x0A,0x00,0x0E,0x00,0x14,0x01,
0x00,0x00,0x0C,0x00,0x0F,0x00,0x12,0x01,0x08,0x00,0x11,0x00,0x10,0x00,0x12,0x01,
0xFA,0xFF,0xEF,0xFF,0xAA,0x55,0xD0,0x00,0xE0,0xFF,0x12,0x01,0x13,0x01,0x14,0x01,
0x15,0x01,0xF8,0xFF
};
const struct club_anim_t club_anim_tbl[] = {
{ &club_anim_data[0x00], 2, 0x19, 0 },
{ &club_anim_data[0x42], 6, 0x1e, 0 },
{ &club_anim_data[0x84], 6, 0x14, 1 },
{ &club_anim_data[0xcc], 12, 0x1e, 3 },
};
const uint8_t player_anim_lut[] = {
0x00,0x03,0x05,0x07,0x02,0x06,0x00,0x00,0x01,0x03,0x04,0x07,0x02,0x06,0x01,0x00,
0x01,0x03,0x04,0x07,0x02,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
const uint8_t player_anim_data[] = {
0x7C,0x00,0x7B,0x00,0x7A,0x00,0x79,0x00,0x7D,0x00,0x7E,0x00,0x7F,0x00,0x27,0x00,
0x77,0x00,0xFE,0xEF,0x28,0x00,0x77,0x00,0x00,0xF0,0x29,0x00,0x77,0x00,0x00,0xEF,
0x2A,0x00,0x77,0x00,0x01,0xF0,0x2B,0x00,0x77,0x00,0x00,0xF1,0x2C,0x00,0x77,0x00,
0xFE,0xF1,0x2D,0x00,0x77,0x00,0x01,0xF2,0x2E,0x00,0x77,0x00,0xFF,0xF5,0x2F,0x00,
0x77,0x00,0x02,0xF0,0x30,0x00,0x79,0x00,0xFA,0xE7,0x31,0x00,0x79,0x00,0xF7,0xE1,
0x32,0x00,0x79,0x00,0xF5,0xDF,0x33,0x00,0x79,0x00,0xF3,0xE1,0x34,0x00,0x79,0x00,
0xF3,0xE1,0x00,0x00
};
const uint8_t vscroll_offsets_data[] = {
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0A,0x0A,0x0B,0x0B,
0x0C,0x0D,0x0E,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10
};
const uint8_t cos_tbl[] = {
0x00,0x01,0x03,0x04,0x06,0x07,0x09,0x0A,0x0C,0x0E,0x0F,0x11,0x12,0x14,0x15,0x17,
0x18,0x19,0x1B,0x1C,0x1E,0x1F,0x20,0x22,0x23,0x24,0x26,0x27,0x28,0x29,0x2A,0x2C,
0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x36,0x37,0x38,0x39,0x39,0x3A,
0x3B,0x3B,0x3C,0x3C,0x3D,0x3D,0x3E,0x3E,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
0x40,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3D,0x3D,0x3C,0x3C,0x3B,
0x3B,0x3A,0x39,0x39,0x38,0x37,0x36,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x2F,0x2E,
0x2D,0x2C,0x2A,0x29,0x28,0x27,0x26,0x24,0x23,0x22,0x20,0x1F,0x1E,0x1C,0x1B,0x19,
0x18,0x17,0x15,0x14,0x12,0x11,0x0F,0x0E,0x0C,0x0A,0x09,0x07,0x06,0x04,0x03,0x01,
0xFF,0xFE,0xFC,0xFB,0xF9,0xF8,0xF6,0xF5,0xF3,0xF1,0xF0,0xEE,0xED,0xEB,0xEA,0xE8,
0xE7,0xE6,0xE4,0xE3,0xE1,0xE0,0xDF,0xDD,0xDC,0xDB,0xD9,0xD8,0xD7,0xD6,0xD5,0xD3,
0xD2,0xD1,0xD0,0xCF,0xCE,0xCD,0xCC,0xCB,0xCA,0xC9,0xC9,0xC8,0xC7,0xC6,0xC6,0xC5,
0xC4,0xC4,0xC3,0xC3,0xC2,0xC2,0xC1,0xC1,0xC1,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,0xC1,0xC1,0xC2,0xC2,0xC3,0xC3,0xC4,
0xC4,0xC5,0xC6,0xC6,0xC7,0xC8,0xC9,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,
0xD2,0xD3,0xD5,0xD6,0xD7,0xD8,0xD9,0xDB,0xDC,0xDD,0xDF,0xE0,0xE1,0xE3,0xE4,0xE6,
0xE7,0xE8,0xEA,0xEB,0xED,0xEE,0xF0,0xF1,0xF3,0xF5,0xF6,0xF8,0xF9,0xFB,0xFC,0xFE
};
const uint8_t sin_tbl[] = {
0x40,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3D,0x3D,0x3C,0x3C,0x3B,
0x3B,0x3A,0x39,0x39,0x38,0x37,0x36,0x36,0x35,0x34,0x33,0x32,0x31,0x30,0x2F,0x2E,
0x2D,0x2C,0x2A,0x29,0x28,0x27,0x26,0x24,0x23,0x22,0x20,0x1F,0x1E,0x1C,0x1B,0x19,
0x18,0x17,0x15,0x14,0x12,0x11,0x0F,0x0E,0x0C,0x0A,0x09,0x07,0x06,0x04,0x03,0x01,
0x00,0xFE,0xFC,0xFB,0xF9,0xF8,0xF6,0xF5,0xF3,0xF1,0xF0,0xEE,0xED,0xEB,0xEA,0xE8,
0xE7,0xE6,0xE4,0xE3,0xE1,0xE0,0xDF,0xDD,0xDC,0xDB,0xD9,0xD8,0xD7,0xD6,0xD5,0xD3,
0xD2,0xD1,0xD0,0xCF,0xCE,0xCD,0xCC,0xCB,0xCA,0xC9,0xC9,0xC8,0xC7,0xC6,0xC6,0xC5,
0xC4,0xC4,0xC3,0xC3,0xC2,0xC2,0xC1,0xC1,0xC1,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,0xC1,0xC1,0xC2,0xC2,0xC3,0xC3,0xC4,
0xC4,0xC5,0xC6,0xC6,0xC7,0xC8,0xC9,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,
0xD2,0xD3,0xD5,0xD6,0xD7,0xD8,0xD9,0xDB,0xDC,0xDD,0xDF,0xE0,0xE1,0xE3,0xE4,0xE6,
0xE7,0xE8,0xEA,0xEB,0xED,0xEE,0xF0,0xF1,0xF3,0xF5,0xF6,0xF8,0xF9,0xFB,0xFC,0xFE,
0x00,0x01,0x03,0x04,0x06,0x07,0x09,0x0A,0x0C,0x0E,0x0F,0x11,0x12,0x14,0x15,0x17,
0x18,0x19,0x1B,0x1C,0x1E,0x1F,0x20,0x22,0x23,0x24,0x26,0x27,0x28,0x29,0x2A,0x2C,
0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x36,0x37,0x38,0x39,0x39,0x3A,
0x3B,0x3B,0x3C,0x3C,0x3D,0x3D,0x3E,0x3E,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
};

306
p2/unpack.c Normal file
View File

@ -0,0 +1,306 @@
#include "util.h"
struct unpack_eat_t {
FILE *fp;
uint8_t len;
uint16_t bits;
uint8_t *dst;
};
static struct unpack_eat_t uneat;
static int next_bit(struct unpack_eat_t *u) {
const int bit = (u->bits & (1 << (16 - u->len))) != 0;
--u->len;
if (u->len == 0) {
u->bits = fread_le16(u->fp);
u->len = 16;
}
return bit;
}
static int zero_bits(struct unpack_eat_t *u, int count) {
int i = 0;
for (; i < count; ++i) {
if (next_bit(u)) {
break;
}
}
return i;
}
static uint8_t get_bits(struct unpack_eat_t *u, int count) {
assert(count < 8);
uint8_t val = 0;
for (int i = 0; i < count; ++i) {
val = (val << 1) | next_bit(u);
}
return val;
}
static void copy_reference(struct unpack_eat_t *u, int count, int offset_hi, int offset_lo) {
const int16_t offset = offset_hi * 256 + offset_lo;
for (int i = 0; i < count; ++i) {
const uint8_t value = u->dst[offset];
*u->dst++ = value;
}
}
static int unpack_eat(FILE *in, struct unpack_eat_t *u) {
uint8_t buffer[17];
const int header_size = fread(buffer, 1, sizeof(buffer), in);
if (header_size != 17 || READ_LE_UINT16(buffer + 4) != 0x899D || READ_LE_UINT16(buffer + 6) != 0x6C64) {
print_error("Unexpected signature for .eat file");
return 0;
}
const uint16_t crc = READ_LE_UINT16(buffer + 12);
const int output_size = (buffer[14] << 14) + READ_LE_UINT16(buffer + 15);
print_debug(DBG_UNPACK, "uncompressed size %d crc 0x%04x", output_size, crc);
uint8_t *output_buffer = (uint8_t *)malloc(output_size);
if (!output_buffer) {
print_error("Failed to allocate EAT unpack buffer, %d bytes", output_size);
return 0;
}
u->fp = in;
u->dst = output_buffer;
u->len = 16;
u->bits = fread_le16(u->fp);
while (1) {
while (next_bit(u)) {
*u->dst++ = fgetc(u->fp);
}
const int b = next_bit(u);
const int offset_lo = fgetc(u->fp);
if (b) {
int offset_hi = 0xFE | next_bit(u);
if (!next_bit(u)) {
int i = 1;
for (; i < 4 && !next_bit(u); ++i) {
offset_hi = (offset_hi << 1) | next_bit(u);
}
offset_hi -= (1 << i);
}
const int n = zero_bits(u, 4);
if (n != 4) {
copy_reference(u, n + 3, offset_hi, offset_lo);
} else if (next_bit(u)) {
copy_reference(u, next_bit(u) + 7, offset_hi, offset_lo);
} else if (!next_bit(u)) {
copy_reference(u, get_bits(u, 3) + 9, offset_hi, offset_lo);
} else {
copy_reference(u, fgetc(u->fp) + 17, offset_hi, offset_lo);
}
} else {
if (next_bit(u)) {
const int offset_hi = (0xF8 | get_bits(u, 3)) - 1;
copy_reference(u, 2, offset_hi, offset_lo);
} else if (offset_lo == 0xFF) {
break;
} else {
copy_reference(u, 2, 0xFF, offset_lo);
}
}
}
assert((u->dst - output_buffer) == output_size);
u->dst = output_buffer;
return output_size;
}
struct unpack_sqz_t {
uint16_t top_code;
uint8_t code_size;
uint16_t new_codes;
uint8_t *dst;
int bits_left;
uint32_t current_bits;
uint8_t last_code;
uint16_t previous_code;
uint16_t prefix[0x1000];
uint8_t str[0x1000];
uint8_t stack[0x1000];
};
#define SQZ_CODE_WIDTH 9
#define SQZ_CODE_BASE (1 << (SQZ_CODE_WIDTH - 1))
static const int SQZ_CLEAR_CODE = SQZ_CODE_BASE;
static const int SQZ_END_CODE = SQZ_CODE_BASE + 1;
static const int SQZ_NEW_CODES = SQZ_CODE_BASE + 2;
static struct unpack_sqz_t unsqz;
static uint16_t unpack_sqz_get_bits(FILE *in, struct unpack_sqz_t *u, int count) {
u->current_bits <<= 8;
u->current_bits |= fgetc(in);
u->bits_left += 8;
if (u->bits_left < count) {
u->current_bits <<= 8;
u->current_bits |= fgetc(in);
u->bits_left += 8;
}
const uint32_t code = u->current_bits >> (u->bits_left - count);
u->bits_left -= count;
u->current_bits &= (1 << u->bits_left) - 1;
return code;
}
static uint16_t unpack_sqz_get_code(FILE *in, struct unpack_sqz_t *u) {
if (u->top_code == u->new_codes && u->code_size != 12) {
++u->code_size;
u->top_code <<= 1;
}
return unpack_sqz_get_bits(in, u, u->code_size);
}
static uint16_t unpack_sqz_clear_code(FILE *in, struct unpack_sqz_t *u) {
u->top_code = 1 << SQZ_CODE_WIDTH;
u->code_size = SQZ_CODE_WIDTH;
u->new_codes = SQZ_NEW_CODES;
const uint16_t code = unpack_sqz_get_code(in, u);
if (code != SQZ_END_CODE) {
u->previous_code = code;
*u->dst++ = u->last_code = code & 255;
}
return code;
}
static int unpack_sqz(FILE *in, struct unpack_sqz_t *u) {
uint8_t buf[4];
fread(buf, 1, sizeof(buf), in);
assert((buf[1] & 0xF0) == 0x10);
const int output_size = ((buf[0] & 15) << 16) | READ_LE_UINT16(buf + 2);
print_debug(DBG_UNPACK, "SQZ uncompressed size %d", output_size);
uint8_t *output_buffer = (uint8_t *)malloc(output_size);
if (!output_buffer) {
print_error("Failed to allocate SQZ unpack buffer, %d bytes", output_size);
return 0;
}
u->dst = output_buffer;
uint16_t code = unpack_sqz_clear_code(in, u);
assert(code != SQZ_END_CODE);
while (1) {
code = unpack_sqz_get_code(in, u);
if (code == SQZ_END_CODE) {
print_debug(DBG_UNPACK, "lzw end code");
break;
} else if (code == SQZ_CLEAR_CODE) {
print_debug(DBG_UNPACK, "lzw clear code");
unpack_sqz_clear_code(in, u);
continue;
}
const uint16_t current_code = code;
uint8_t *sp = u->stack;
if (u->new_codes <= code) {
*sp++ = u->last_code;
code = u->previous_code;
}
while (code >= SQZ_CODE_BASE) {
*sp++ = u->str[code];
code = u->prefix[code];
}
*sp++ = u->last_code = code & 255;
do {
--sp;
*u->dst++ = *sp;
} while (sp != u->stack);
const uint16_t index = u->new_codes;
if (index < 0x1000) {
u->str[index] = u->last_code;
u->prefix[index] = u->previous_code;
++u->new_codes;
}
u->previous_code = current_code;
}
const int count = (u->dst - output_buffer);
print_debug(DBG_UNPACK, "lzw output size %d (expected %d)", count, output_size);
assert(count == output_size);
u->dst = output_buffer;
return count;
}
struct unpack_sqv_t {
uint8_t dict_buf[0x200 * 2];
uint8_t rd[0x1000];
int dict_len;
uint8_t *dst;
};
static struct unpack_sqv_t unsqv;
static int unpack_sqv(FILE *in, struct unpack_sqv_t *u) {
fread(u->rd, 1, 6, in);
const int uncompressed_size = (READ_LE_UINT16(u->rd) << 16) + READ_LE_UINT16(u->rd + 2);
const int dict_len = READ_LE_UINT16(u->rd + 4);
print_debug(DBG_UNPACK, "SQV uncompressed size %d dict_len %d", uncompressed_size, dict_len);
fread(u->dict_buf, 1, dict_len, in);
uint8_t *output_buffer = (uint8_t *)malloc(uncompressed_size);
if (!output_buffer) {
print_error("Failed to allocate SQV unpack buffer, %d bytes", uncompressed_size);
return 0;
}
u->dst = output_buffer;
uint8_t *dst = output_buffer;
const uint8_t *src = u->rd;
int len = 1;
int bytes_count = 2;
uint16_t bits = 0;
uint16_t val = 0;
while ((dst - output_buffer) < uncompressed_size) {
--len;
if (len == 0) {
bytes_count -= 2;
if (bytes_count == 0) {
bytes_count = fread(u->rd, 1, 0x1000, in);
if (bytes_count == 0) {
break;
}
bytes_count += (bytes_count & 1);
src = u->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(u->dict_buf + val);
if ((val & 0x8000) == 0) {
continue;
}
*dst++ = val & 255;
val = 0;
}
assert((dst - output_buffer) == uncompressed_size);
return uncompressed_size;
}
uint8_t *unpack(FILE *in, int *uncompressed_size) {
const uint16_t sig = fread_le16(in);
fseek(in, 0, SEEK_SET);
if (sig == 0x4CB4) {
memset(&uneat, 0, sizeof(unsqz));
*uncompressed_size = unpack_eat(in, &uneat);
return uneat.dst;
} else if ((sig >> 8) == 0x10) {
memset(&unsqz, 0, sizeof(unsqz));
*uncompressed_size = unpack_sqz(in, &unsqz);
return unsqz.dst;
} else {
memset(&unsqv, 0, sizeof(unsqv));
*uncompressed_size = unpack_sqv(in, &unsqv);
return unsqv.dst;
}
*uncompressed_size = 0;
return 0;
}

9
p2/unpack.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef UNPACK_H__
#define UNPACK_H__
#include "intern.h"
extern uint8_t *unpack(FILE *in, int *uncompressed_size);
#endif /* UNPACK_H__ */