#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++; } const uint8_t *monster_attr = p; int monsters_count = 0; while (*p < 50) { const uint8_t len = p[0]; const uint8_t type = p[1] & 0x7F; const uint16_t spr_num = READ_LE_UINT16(p + 2); print_debug(DBG_RESOURCE, "monster %d len %d type %d spr %d", monsters_count, len, type, spr_num); assert(monsters_count < MAX_LEVEL_MONSTERS); struct level_monster_t *m = &g_res.level.monsters_tbl[monsters_count++]; m->len = len; m->type = p[1]; m->spr_num = spr_num; m->unk5 = p[5]; m->total_ticks = p[6]; m->current_tick = p[7]; m->unk8 = p[8]; m->x_pos = READ_LE_UINT16(p + 0x9); m->y_pos = READ_LE_UINT16(p + 0xB); switch (type) { case 2: m->type2.y_range = p[0xD]; m->type2.unkE = p[0xE]; case 8: m->type8.x_range = p[0xD]; m->type8.unkE = p[0xE]; m->type8.unkF = p[0xF]; m->type8.y_range = p[0x10]; break; default: break; } p += len; } g_res.level.monsters_count = monsters_count; p = monster_attr + 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++; const int type = trigger->flags & 15; if (type == 8) { trigger->type8.unk7 = *p++; trigger->type8.unk8 = *p++; trigger->type8.unk9 = *p++; trigger->type8.state = *p++; trigger->type8.y_delta = READ_LE_UINT16(p); p += 2; trigger->type8.counter = *p++; } else { trigger->other.unk7 = READ_LE_UINT16(p); p += 2; trigger->other.unk9 = *p++; trigger->other.unkA = READ_LE_UINT16(p); p += 2; trigger->other.unkC = READ_LE_UINT16(p); p += 2; } trigger->unkE = *p++; } g_res.level.monsters_xmin = READ_LE_UINT16(p); p += 2; 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); }