Import blues from abd80e9b

This commit is contained in:
Gregory Montoir 2018-07-12 19:21:15 +08:00
parent ef58debe84
commit ec71a464eb
12 changed files with 407 additions and 117 deletions

View File

@ -1,7 +1,7 @@
#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) {
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) {
assert((src_pitch & 7) == 0);
src_pitch /= 8;
assert((w & 7) == 0);
@ -19,12 +19,10 @@ void decode_ega_spr(const uint8_t *src, int src_pitch, int w, int h, uint8_t *ds
}
}
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) {
const int x_offset = dst_x + (x * 8 + i);
dst[y_offset * dst_pitch + x_offset] = color;
}
}
}
++src;
}
src += src_pitch - w;

View File

@ -4,6 +4,6 @@
#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);
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);
#endif /* DECODE_H__ */

23
game.c
View File

@ -47,13 +47,14 @@ static void check_cheat_code() {
void do_select_player() {
int quit = 0;
int var9 = 0;
int fade = 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_load_graphics();
screen_clear_sprites();
do {
screen_unk4();
@ -174,9 +175,9 @@ void do_select_player() {
break;
}
// state_default_:
if (var9 == 0) {
if (!fade) {
fade_in_palette();
var9 = 1;
fade = 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);
@ -208,16 +209,12 @@ void do_select_player() {
} while (!quit && !g_sys.input.quit);
}
static void do_inter_screen_helper(int a, int b, int c) {
static void do_inter_screen_helper(int xpos, int ypos, 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_add_sprite(xpos + 20 - 1 - i, ypos - 20 + 1 + i, 125);
screen_clear_last_sprite();
screen_redraw_sprites();
if (c != 0) {
@ -226,9 +223,7 @@ static void do_inter_screen_helper(int a, int b, int c) {
screen_clear_sprites();
}
for (int i = 0; i < 40; ++i) {
++xpos;
++ypos;
screen_add_sprite(xpos, ypos, 125);
screen_add_sprite(xpos - 20 + 1 + i, ypos - 20 + 1 + i, 125);
screen_clear_last_sprite();
screen_redraw_sprites();
if (c != 0) {
@ -288,7 +283,7 @@ void game_main() {
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;
g_vars.start_level = 0;
load_sqv("sprite.sqv", g_res.spr_sqv, 0);
do_title_screen();
while (g_sys.input.quit == 0) {
@ -297,7 +292,7 @@ void game_main() {
g_vars.game_over_flag = 0;
g_vars.play_level_flag = 1;
if (!g_vars.play_demo_flag) {
g_vars.level = 0;
g_vars.level = g_options.start_level;
do_select_player();
} else {
g_vars.level = g_vars.start_level;

21
game.h
View File

@ -17,7 +17,6 @@
#define MAX_DOORS 30
#define MAX_LEVELS 6
#define MAX_OBJECTS 41
#define MAX_SPRITES 40
#define SOUND_0 0
#define SOUND_2 2
@ -47,17 +46,6 @@ struct options_t {
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;
@ -96,7 +84,7 @@ struct object_t {
int16_t unk1C; // xvelocity / 8
int16_t unk1E; // yvelocity / 8
uint8_t direction_lr;
uint8_t direction_ud;
int8_t direction_ud;
int16_t xpos16; // tilemap_xpos
int16_t ypos16; // tilemap_ypos
// int16_t unk26;
@ -194,9 +182,6 @@ struct vars_t {
uint16_t level_loop_counter;
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;
@ -243,7 +228,7 @@ 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_update_projectile(struct object_t *obj);
extern void do_level();
/* opcodes.c */
@ -259,7 +244,6 @@ 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();
@ -276,6 +260,7 @@ 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);
extern void screen_load_graphics();
/* sound.c */
extern void sound_init(int rate);

96
level.c
View File

@ -1,7 +1,6 @@
/* level main loop */
#include "decode.h"
#include "game.h"
#include "resource.h"
#include "sys.h"
@ -66,13 +65,14 @@ void load_level_data(int num) {
}
load_bin(_levels[num].bin);
load_avt(_levels[num].avt, g_res.avt_sqv, 0);
load_sqv(_levels[num].sqv, g_res.tmp, 146);
load_sqv(_levels[num].sqv, g_res.tmp, SPRITES_COUNT);
memcpy(g_vars.level_xpos, _levels[num].xpos, MAX_OBJECTS * sizeof(int16_t));
memcpy(g_vars.level_ypos, _levels[num].ypos, MAX_OBJECTS * sizeof(int16_t));
if (g_vars.music_num != _levels[num].music) {
play_music(_levels[num].music);
g_vars.music_num = _levels[num].music;
}
screen_load_graphics();
}
static void init_level() {
@ -502,6 +502,64 @@ static void do_level_add_sprite1_case2(struct object_t *obj) {
obj->anim_frame = anim_data[obj->anim_num];
}
static void do_level_add_sprite1_case3(struct object_t *obj) {
struct object_t *obj35 = &g_vars.objects[35];
struct object_t *obj37 = &g_vars.objects[37];
if (obj->type != 0 && g_vars.two_players_flag) {
obj35 = &g_vars.objects[34];
obj37 = &g_vars.objects[36];
}
if (obj37->type != 100 && obj37->grab_type != 0) {
do_level_drop_grabbed_object(obj);
}
obj->unk3D = 0;
if (obj35->type != 100) {
obj35->type = 100;
obj35->visible_flag = 0;
}
const uint8_t *anim_data = 0;
obj->unk3D = 0;
int tile_num = triggers_get_tile_type(obj->xpos16, obj->ypos16);
obj->xmaxvelocity = 8;
obj->xacc = 0;
obj->unk2D = 10;
if (obj->direction_lr != 0) {
if (obj->direction_ud != 0) {
if (tile_num == 6) {
anim_data = obj->animframes_ptr[56 / 4];
} else {
anim_data = obj->animframes_ptr[0];
}
} else {
if (tile_num == 6) {
anim_data = obj->animframes_ptr[68 / 4];
} else {
anim_data = obj->animframes_ptr[4 / 4];
}
}
} else {
if (obj->direction_ud != 0) {
if (tile_num == 6) {
anim_data = obj->animframes_ptr[56 / 4];
} else {
anim_data = obj->animframes_ptr[0];
}
} else {
if (tile_num == 6) {
anim_data = obj->animframes_ptr[68 / 4];
} else {
anim_data = obj->animframes_ptr[4 / 4];
}
}
}
if (obj->anim_num < anim_data[0]) {
obj->anim_num += (g_vars.level_loop_counter & 1);
} else {
obj->anim_num = 1;
}
obj->anim_frame = anim_data[obj->anim_num];
}
// swimming
static void do_level_add_sprite1_case4(struct object_t *obj) {
struct object_t *obj35 = &g_vars.objects[35];
@ -608,6 +666,9 @@ static void do_level_add_sprite1(struct object_t *obj) {
case 2:
do_level_add_sprite1_case2(obj);
break;
case 3:
do_level_add_sprite1_case3(obj);
break;
case 4:
do_level_add_sprite1_case4(obj);
break;
@ -1335,17 +1396,17 @@ static void do_level_update_object_bounds(struct object_t *obj) {
// obj->unk41 = 0;
}
void do_level_update_object38(struct object_t *obj) {
void do_level_update_projectile(struct object_t *obj) {
struct object_t *obj38 = &g_vars.objects[38];
if (obj->unk42 == 0) {
if (obj->type == 100) {
if (obj38->type == 100) {
obj->special_anim = 2;
obj->unk42 = 1;
}
} else if (obj->unk42 == 1) {
if (obj38->grab_type == 10 || obj->anim_num >= 7) {
obj38->type = 2;
obj->visible_flag = 1;
obj38->visible_flag = 1;
static const uint8_t data[MAX_OBJECTS] = {
0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 6, 23, 0, 9, 9, 0, 10, 0,
11, 0, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0
@ -1375,6 +1436,11 @@ void do_level_update_object38(struct object_t *obj) {
obj38->xpos = obj->xpos + 16 - (obj->facing_left << 5);
obj38->xvelocity = obj38->yvelocity = 32 - (obj->facing_left << 6);
break;
default:
obj38->ypos = obj->ypos - 18;
obj38->xpos = obj->xpos + 32 - (obj->facing_left << 6);
obj38->xvelocity = obj38->yvelocity = 64 - (obj->facing_left << 7);
break;
}
const int num = obj38->type * 116 / 4;
assert(num < 1189);
@ -1842,7 +1908,17 @@ static void do_level_update_objects() {
obj->direction_lr = 0;
obj->direction_ud = 0;
if (obj->type < 2) {
if (g_vars.inp_keyboard[0xC1] != 0) { // F7
if (g_vars.inp_keyboard[0xC1] != 0) { // F7, change player
if (!g_vars.screen_unk1 && g_vars.two_players_flag) {
if (!g_vars.player2_scrolling_flag && g_vars.objects[OBJECT_NUM_PLAYER1].unk53 == 0) {
g_vars.player2_scrolling_flag = 1;
g_vars.screen_unk1 = 1;
} else if (g_vars.player2_scrolling_flag && g_vars.objects[OBJECT_NUM_PLAYER2].unk53 == 0) {
g_vars.player2_scrolling_flag = 1;
g_vars.screen_unk1 = 1;
}
}
g_vars.inp_keyboard[0xC1] = 0;
}
if (obj->blinking_counter != 0) {
--obj->blinking_counter;
@ -1896,7 +1972,7 @@ static void do_level_update_objects() {
if (obj->visible_flag != 0) {
do_level_update_object_bounds(obj);
if (obj->unk42 != 0) {
do_level_update_object38(obj);
do_level_update_projectile(obj);
}
obj->unk2D = 10;
obj->unk1C = 0;
@ -2046,9 +2122,9 @@ static void draw_foreground_tiles() {
}
const int avt_num = g_res.triggers[num].foreground_tile_num;
if (avt_num != 255) {
const int tile_y = j * 16 + 14;
const int tile_y = j * 16 + TILEMAP_OFFSET_Y;
const int tile_x = i * 16;
decode_ega_spr(g_res.avt[avt_num], 16, 16, 16, g_res.vga, GAME_SCREEN_W, tile_x, tile_y, 0);
render_add_sprite(RENDER_SPR_FG, avt_num, tile_x, tile_y, 0);
}
}
++y;
@ -2098,7 +2174,7 @@ void do_level() {
do {
const uint32_t timestamp = g_sys.get_timestamp();
update_input();
if (g_vars.inp_keyboard[0xBF] != 0) { // F5
if (g_vars.inp_keyboard[0xBF] != 0) { // F5, quit game
play_sound(SOUND_0);
g_vars.inp_keyboard[0xBF] = 0;
g_vars.quit_level_flag = 1;

View File

@ -49,18 +49,18 @@ static void object_func_op2(struct object_t *obj) {
obj->moving_direction ^= 1;
}
obj->direction_lr = obj->moving_direction + 1;
obj->xmaxvelocity = 40;
obj->xmaxvelocity = 24;
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->player_ydist <= 20 && obj->player_xdist > -(TILEMAP_SCREEN_W / 4) && obj->player_xdist < (TILEMAP_SCREEN_W / 4) && obj->direction_ud > -60) {
if (obj->special_anim == 0 || obj->anim_num == 12) {
obj->anim_num = 1;
obj->unk42 = 0;
do_level_update_object38(obj);
do_level_update_projectile(obj);
}
obj->facing_left = (obj->player_xdist < 0) ? 1 : 0;
}
@ -71,9 +71,9 @@ static void object_func_op2(struct object_t *obj) {
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->direction_ud > -30) {
if (obj->special_anim == 0 || obj->anim_num == 16) {
do_level_update_object38(obj);
do_level_update_projectile(obj);
}
obj->facing_left = (obj->player_xdist < 0) ? 1 : 0;
}
@ -154,6 +154,37 @@ static void object_func_op5(struct object_t *obj) {
obj->xmaxvelocity = 32;
}
static void object_func_op7(struct object_t *obj) {
if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) == 12) {
obj->moving_direction ^= 1;
}
obj->direction_lr = obj->moving_direction + 1;
obj->xmaxvelocity = 32;
if (g_vars.objects[OBJECT_NUM_PLAYER1].special_anim != 18 && g_vars.objects[OBJECT_NUM_PLAYER2].special_anim != 18) {
if (obj->player_ydist <= 10 && obj->player_xdist > -(TILEMAP_SCREEN_W / 4) && obj->player_xdist < (TILEMAP_SCREEN_W / 4) && g_vars.objects[38].type == 100) {
if (obj->direction_ud > -30) {
if (obj->special_anim == 0 || obj->anim_num == 16) {
obj->anim_num = 1;
obj->unk42 = 0;
do_level_update_projectile(obj);
}
if (obj->player_xdist < 0) {
obj->facing_left = 1;
} else {
obj->facing_left = 0;
}
}
} else {
if (obj->anim_num == 16) {
obj->special_anim = 0;
}
}
}
if (obj->special_anim != 0) {
obj->direction_lr = 0;
}
}
// bird
static void object_func_op8(struct object_t *obj) {
if (triggers_get_tile_type(obj->xpos16 + 2 - obj->facing_left * 4, obj->ypos16) != 1) {
@ -163,10 +194,10 @@ static void object_func_op8(struct object_t *obj) {
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) {
if (obj->player_ydist <= 100 && obj->player_xdist > -90 && obj->player_xdist < 90 && obj->direction_ud > -60 && obj->special_anim == 0) {
obj->anim_num = 1;
obj->unk42 = 1;
do_level_update_object38(obj);
do_level_update_projectile(obj);
}
}
@ -177,11 +208,11 @@ static void object_func_op10(struct object_t *obj) {
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->direction_ud > -30) {
if (obj->special_anim == 0 || obj->anim_num == 16) {
obj->anim_num = 1;
obj->unk42 = 0;
do_level_update_object38(obj);
do_level_update_projectile(obj);
}
obj->facing_left = (obj->player_xdist < 0) ? 1 : 0;
}
@ -436,6 +467,9 @@ void level_call_object_func(struct object_t *obj) {
case 5:
object_func_op5(obj);
break;
case 7:
object_func_op7(obj);
break;
case 8:
object_func_op8(obj);
break;

View File

@ -175,6 +175,7 @@ void load_avt(const char *filename, uint8_t *dst, int offset) {
g_res.avt[offset + i] = ptr;
ptr += 132;
}
g_res.avt_count = count;
}
static const uint8_t *trigger_lookup_table1(uint8_t num) {
@ -259,6 +260,7 @@ void load_sqv(const char *filename, uint8_t *dst, int offset) {
const uint8_t *ptr = dst;
const int count = READ_LE_UINT16(ptr); ptr += 6;
print_debug(DBG_RESOURCE, "sqv count %d", count);
assert(offset + count <= MAX_SPR_FRAMES);
for (int i = 0; i < count; ++i) {
g_res.spr_frames[offset + i] = ptr;
const int h = READ_LE_UINT16(ptr - 4);
@ -268,6 +270,7 @@ void load_sqv(const char *filename, uint8_t *dst, int offset) {
print_debug(DBG_RESOURCE, "sprite %d, dim %d,%d size %d", i, w, h, size);
ptr += size;
}
g_res.spr_count = offset + count;
}
void load_sql(const char *filename) {

View File

@ -25,6 +25,7 @@ struct trigger_t {
#define MAX_SPR_FRAMES 200
#define MAX_TRIGGERS 256
#define SOUND_SIZE 29376
#define SPRITES_COUNT 146
#define RESOURCE_FLAGS_DEMO (1 << 0)
@ -34,7 +35,9 @@ struct resource_data_t {
uint8_t *spr_sqv;
uint8_t *avt_sqv;
uint8_t *tmp;
int avt_count;
const uint8_t *avt[MAX_AVT];
int spr_count;
const uint8_t *spr_frames[MAX_SPR_FRAMES];
uint8_t palette[16 * 3];
struct trigger_t triggers[MAX_TRIGGERS];

141
screen.c
View File

@ -5,49 +5,36 @@
#include "sys.h"
#include "util.h"
#define MAX_SPRITESHEET_W 1024
#define MAX_SPRITESHEET_H 512
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;
render_clear_sprites();
}
static void add_game_sprite(int x, int y, int frame, int xflip) {
const uint8_t *p = g_res.spr_frames[frame];
const int h = READ_LE_UINT16(p - 4);
const int w = READ_LE_UINT16(p - 2);
int spr_type = RENDER_SPR_GAME;
if (frame >= SPRITES_COUNT) {
spr_type = RENDER_SPR_LEVEL;
frame -= SPRITES_COUNT;
}
render_add_sprite(spr_type, frame, x - w / 2, y - h, xflip);
}
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;
add_game_sprite(x, y, frame, 0);
}
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() {
@ -61,16 +48,12 @@ void 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();
g_sys.set_screen_palette(g_res.palette, 16);
}
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);
@ -78,7 +61,7 @@ void screen_draw_frame(const uint8_t *frame, int a, int b, int c, int d) {
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);
decode_ega_spr(frame, w, b, h, g_res.vga, GAME_SCREEN_W, x, y);
}
void screen_flip() {
@ -96,9 +79,9 @@ void screen_unk5() {
}
void screen_unk6() {
// _screen_draw_offset -= 12;
// g_vars.screen_draw_offset -= 12;
// screen_do_transition2();
// _screen_draw_offset += 12;
// g_vars.screen_draw_offset += 12;
g_sys.update_screen(g_res.vga, 1);
memset(g_res.vga, 0, GAME_SCREEN_W * GAME_SCREEN_H);
}
@ -156,24 +139,90 @@ void 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);
decode_ega_spr(font_data + (num / 10) * 32, 8, 8, 8, g_res.vga, GAME_SCREEN_W, x - 8, y);
decode_ega_spr(font_data + (num % 10) * 32, 8, 8, 8, g_res.vga, GAME_SCREEN_W, x, y);
}
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;
add_game_sprite(x, y + TILEMAP_OFFSET_Y, frame, 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;
add_game_sprite(x, y + TILEMAP_OFFSET_Y, frame, 1);
}
void screen_add_game_sprite3(int x, int y, int frame, int blinking_counter) {
print_warning("screen_add_game_sprite3");
// 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");
// print_warning("screen_add_game_sprite4");
}
static void decode_graphics(int spr_type, int start, int end) {
struct sys_rect_t r[MAX_SPR_FRAMES];
uint8_t *data = (uint8_t *)calloc(MAX_SPRITESHEET_W * MAX_SPRITESHEET_H, 1);
if (data) {
int current_x = 0;
int max_w = 0;
int current_y = 0;
int max_h = 0;
for (int i = start; i < end; ++i) {
const uint8_t *ptr = g_res.spr_frames[i];
const int h = READ_LE_UINT16(ptr - 4);
const int w = READ_LE_UINT16(ptr - 2);
const int j = i - start;
if (current_x + w > MAX_SPRITESHEET_W) {
current_y += max_h;
if (current_x > max_w) {
max_w = current_x;
}
current_x = 0;
max_h = h;
decode_ega_spr(ptr, w, w, h, data, MAX_SPRITESHEET_W, current_x, current_y);
r[j].x = current_x;
r[j].y = current_y;
} else {
decode_ega_spr(ptr, w, w, h, data, MAX_SPRITESHEET_W, current_x, current_y);
r[j].x = current_x;
r[j].y = current_y;
current_x += w;
if (h > max_h) {
max_h = h;
}
}
r[j].w = w;
r[j].h = h;
}
assert(max_w <= MAX_SPRITESHEET_W);
assert(current_y + max_h <= MAX_SPRITESHEET_H);
render_unload_sprites(spr_type);
render_load_sprites(spr_type, end - start, r, data, MAX_SPRITESHEET_W, current_y + max_h);
free(data);
}
}
void screen_load_graphics() {
if (g_res.spr_count <= SPRITES_COUNT) {
decode_graphics(RENDER_SPR_GAME, 0, SPRITES_COUNT);
} else {
decode_graphics(RENDER_SPR_LEVEL, SPRITES_COUNT, g_res.spr_count);
struct sys_rect_t r[MAX_SPR_FRAMES];
static const int FG_TILE_W = 16;
static const int FG_TILE_H = 16;
uint8_t *data = (uint8_t *)malloc(g_res.avt_count * FG_TILE_W * FG_TILE_H);
if (data) {
const int pitch = g_res.avt_count * FG_TILE_W;
for (int i = 0; i < g_res.avt_count; ++i) {
decode_ega_spr(g_res.avt[i], FG_TILE_W, FG_TILE_W, FG_TILE_H, data, pitch, i * FG_TILE_W, 0);
r[i].x = i * FG_TILE_W;
r[i].y = 0;
r[i].w = FG_TILE_W;
r[i].h = FG_TILE_H;
}
render_unload_sprites(RENDER_SPR_FG);
render_load_sprites(RENDER_SPR_FG, g_res.avt_count, r, data, g_res.avt_count * FG_TILE_W, FG_TILE_H);
free(data);
}
}
}

50
sound.c
View File

@ -32,7 +32,7 @@ static const struct {
{ 0x36a6, 0x0574 }
};
// Amiga, unexotica
// Amiga, ExoticA
static const char *_modules[] = {
"ALMOST", "mod.almost",
"GUNN", "mod.bluesgunnbest",
@ -47,7 +47,7 @@ struct mixerchannel_t {
uint32_t size;
};
static int _rate = 22050;
static const int _rate = SYS_AUDIO_FREQ;
static struct mixerchannel_t _channel;
static ModPlugFile *_mpf;
@ -74,7 +74,6 @@ static void mix(void *param, uint8_t *buf, int len) {
}
void sound_init(int rate) {
_rate = rate;
ModPlug_Settings mp_settings;
memset(&mp_settings, 0, sizeof(mp_settings));
ModPlug_GetSettings(&mp_settings);
@ -109,7 +108,49 @@ void play_music(int num) {
ModPlug_Unload(_mpf);
_mpf = 0;
}
const char *filename = _modules[num * 2 + 1];
const char *filename = _modules[num * 2];
if (fio_exists(filename)) { // Amiga
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);
// append samples to the end of the buffer
static const int SONG_INFO_LEN = 20;
static const int NUM_SAMPLES = 8;
int samples_size = 0;
int offset = SONG_INFO_LEN;
for (int i = 0; i < NUM_SAMPLES; ++i, offset += 30) {
const char *sample_name = (const char *)&buf[offset];
if (sample_name[0]) {
samples_size += READ_BE_UINT16(&buf[offset + 22]) * 2;
}
}
buf = (uint8_t *)realloc(buf, size + samples_size);
if (buf) {
offset = SONG_INFO_LEN;
for (int i = 0; i < NUM_SAMPLES; ++i, offset += 30) {
const char *sample_name = (const char *)&buf[offset];
const int sample_size = READ_BE_UINT16(&buf[offset + 22]) * 2;
if (sample_name[0]) {
int sample_slot = fio_open(sample_name, 0);
if (!(sample_slot < 0)) {
fio_read(sample_slot, buf + size, sample_size);
size += sample_size;
}
fio_close(sample_slot);
}
}
_mpf = ModPlug_Load(buf, size);
}
free(buf);
}
fio_close(slot);
} else { // ExoticA
filename = _modules[num * 2 + 1];
if (fio_exists(filename)) {
int slot = fio_open(filename, 1);
int size = fio_size(slot);
@ -121,5 +162,6 @@ void play_music(int num) {
}
fio_close(slot);
}
}
g_sys.unlock_audio();
}

17
sys.h
View File

@ -23,6 +23,11 @@ struct input_t {
typedef void (*sys_audio_cb)(void *, uint8_t *data, int len);
struct sys_rect_t {
int x, y;
int w, h;
};
struct sys_t {
struct input_t input;
int (*init)();
@ -45,4 +50,16 @@ struct sys_t {
extern struct sys_t g_sys;
#define RENDER_SPR_GAME 0 /* player sprites */
#define RENDER_SPR_LEVEL 1 /* level sprites */
#define RENDER_SPR_FONT 2 /* font (digits) */
#define RENDER_SPR_FG 3 /* foreground tiles */
extern void render_load_sprites(int spr_type, int count, const struct sys_rect_t *r, const uint8_t *data, int w, int h);
extern void render_unload_sprites(int spr_type);
extern void render_add_sprite(int spr_type, int frame, int x, int y, int xflip);
extern void render_clear_sprites();
extern void render_draw_tilemap(int x, int y);
extern void render_draw_image();
#endif /* SYS_H__ */

View File

@ -8,6 +8,24 @@
static const int SCALE = 2;
static const int FADE_STEPS = 16;
struct spritesheet_t {
int count;
SDL_Rect *r;
SDL_Texture *texture;
};
static struct spritesheet_t _spritesheets[4];
struct sprite_t {
int sheet;
int num;
int x, y;
bool xflip;
};
static struct sprite_t _sprites[128];
static int _sprites_count;
static int _screen_w;
static int _screen_h;
static SDL_Window *_window;
@ -62,7 +80,7 @@ static void sdl2_set_screen_size(int w, int h, const char *caption) {
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);
_window = SDL_CreateWindow(caption, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_w, window_h, SDL_WINDOW_RESIZABLE);
_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));
@ -97,7 +115,7 @@ static void sdl2_set_copper_bars(const uint16_t *data) {
_copper_color = (data[0] - 0x180) / 2;
const uint16_t *src = data + 1;
uint32_t *dst = _copper_palette;
for (int i = 0; i < 16; ++i) {
for (int i = 0; i < COPPER_BARS_H / 5; ++i) {
const int j = i + 1;
*dst++ = convert_amiga_color(src[j]);
*dst++ = convert_amiga_color(src[i]);
@ -145,14 +163,17 @@ static void sdl2_fade_out_palette() {
static void sdl2_update_screen(const uint8_t *p, int present) {
if (_copper_color != -1) {
for (int j = 0; j < _screen_h; ++j) {
if (j / 2 < COPPER_BARS_H) {
const uint32_t line_color = _copper_palette[j / 2];
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];
_screen_buffer[j * _screen_w + i] = (p[i] == _copper_color) ? line_color : _screen_palette[p[i]];
}
} else {
_screen_buffer[j * _screen_w + i] = _screen_palette[*p];
for (int i = 0; i < _screen_w; ++i) {
_screen_buffer[j * _screen_w + i] = _screen_palette[p[i]];
}
++p;
}
p += _screen_w;
}
} else {
for (int i = 0; i < _screen_w * _screen_h; ++i) {
@ -163,6 +184,23 @@ static void sdl2_update_screen(const uint8_t *p, int present) {
if (present) {
SDL_RenderClear(_renderer);
SDL_RenderCopy(_renderer, _texture, 0, 0);
// sprites
for (int i = 0; i < _sprites_count; ++i) {
struct sprite_t *spr = &_sprites[i];
struct spritesheet_t *sheet = &_spritesheets[spr->sheet];
SDL_Rect r;
r.x = spr->x * SCALE;
r.y = spr->y * SCALE;
r.w = sheet->r[spr->num].w * SCALE;
r.h = sheet->r[spr->num].h * SCALE;
if (!spr->xflip) {
SDL_RenderCopy(_renderer, sheet->texture, &sheet->r[spr->num], &r);
} else {
SDL_RenderCopyEx(_renderer, sheet->texture, &sheet->r[spr->num], &r, 0., 0, SDL_FLIP_HORIZONTAL);
}
}
SDL_RenderPresent(_renderer);
}
}
@ -283,3 +321,53 @@ struct sys_t g_sys = {
.lock_audio = sdl2_lock_audio,
.unlock_audio = sdl2_unlock_audio,
};
void render_load_sprites(int spr_type, int count, const struct sys_rect_t *r, const uint8_t *data, int w, int h) {
assert(spr_type < ARRAYSIZE(_spritesheets));
struct spritesheet_t *spr_sheet = &_spritesheets[spr_type];
spr_sheet->count = count;
spr_sheet->r = (SDL_Rect *)malloc(count * sizeof(SDL_Rect));
for (int i = 0; i < count; ++i) {
SDL_Rect *rect = &spr_sheet->r[i];
rect->x = r[i].x;
rect->y = r[i].y;
rect->w = r[i].w;
rect->h = r[i].h;
}
uint32_t *argb = (uint32_t *)malloc(w * h * sizeof(uint32_t));
if (!argb) {
print_warning("Failed to allocate RGB buffer for sprites type %d", spr_type);
} else {
spr_sheet->texture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, w, h);
SDL_SetTextureBlendMode(spr_sheet->texture, SDL_BLENDMODE_BLEND);
for (int i = 0; i < w * h; ++i) {
argb[i] = (data[i] == 0) ? 0 : (0xFF000000 | _screen_palette[data[i]]);
}
SDL_UpdateTexture(spr_sheet->texture, 0, argb, w * sizeof(uint32_t));
free(argb);
}
}
void render_unload_sprites(int spr_type) {
struct spritesheet_t *spr_sheet = &_spritesheets[spr_type];
free(spr_sheet->r);
if (spr_sheet->texture) {
SDL_DestroyTexture(spr_sheet->texture);
}
memset(spr_sheet, 0, sizeof(struct spritesheet_t));
}
void render_add_sprite(int spr_type, int frame, int x, int y, int xflip) {
assert(_sprites_count < ARRAYSIZE(_sprites));
struct sprite_t *spr = &_sprites[_sprites_count];
spr->sheet = spr_type;
spr->num = frame;
spr->x = x;
spr->y = y;
spr->xflip = xflip;
++_sprites_count;
}
void render_clear_sprites() {
_sprites_count = 0;
}