Import blues from dd0f5cfb
This commit is contained in:
parent
54717ad915
commit
191796a951
|
@ -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)
|
|
@ -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/
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
#include <sys/param.h>
|
||||
#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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
#ifndef INTERN_H__
|
||||
#define INTERN_H__
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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");
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
|
||||
#include "fileio.h"
|
||||
#include "game.h"
|
||||
#include "resource.h"
|
||||
#include "sys.h"
|
||||
|
||||
#include <libmodplug/modplug.h>
|
||||
|
||||
#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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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__ */
|
|
@ -0,0 +1,285 @@
|
|||
|
||||
#include <SDL.h>
|
||||
#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,
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
#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);
|
||||
}
|
|
@ -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__ */
|
Loading…
Reference in New Issue