Add support for loading stages from a file

This commit is contained in:
Juhani Krekelä 2022-01-16 16:28:06 +00:00
parent 19f0ce06f6
commit 40f3e4e3bf
2 changed files with 124 additions and 12 deletions

26
example-bundle.txt Normal file
View File

@ -0,0 +1,26 @@
Example bundle
Stages are separated by ten dashes, and each stage must be 10 lines of 10
characters each. At the top of the file is a free-form comment field.
----------
!
gggggggggg
----------
!
D 4
C 3 44
3 3 4
B
222 2 2
A 1 111
@g
gd

View File

@ -17,6 +17,7 @@
enum game_mode { TITLESCREEN, STAGE };
enum game_mode game_mode = TITLESCREEN;
bool stages_beat[STAGES];
size_t stages_num;
#define PLAYFIELD_SIDE 100
#define TILE_SIDE 10
@ -93,7 +94,8 @@ static enum palette playfield[PLAYFIELD_SIDE * PLAYFIELD_SIDE];
#include "rebind_rebind1_alt_tile.inc"
static char tilemap[TILES * TILES + 1];
static char *stages[] = {
static char *stages[STAGES];
static char *builtin_stages[] = {
" "
" "
" "
@ -446,7 +448,7 @@ static void update_stage(struct timespec now, struct timespec dt_timespec) {
switch(sample_tilemap(midpoint_x, midpoint_y)) {
case '!':
stages_beat[selection_index] = true;
if (selection_index < STAGES - 1)
if (selection_index + 1 < stages_num)
selection_index++;
game_mode = TITLESCREEN;
initialize();
@ -473,7 +475,7 @@ static void update_titlescreen(struct timespec now, struct timespec dt_timespec)
(void) dt_timespec;
if (keys_released && left_held && selection_index > 0)
selection_index--;
if (keys_released && right_held && selection_index < STAGES - 1)
if (keys_released && right_held && selection_index + 1 < stages_num)
selection_index++;
if (keys_released && jump_held)
stage_selected = true;
@ -549,20 +551,20 @@ static void draw_stage(struct timespec now) {
static void draw_titlescreen(struct timespec now) {
(void) now;
for (size_t i = 0; i < STAGES; i++) {
for (size_t i = 0; i < stages_num; i++) {
size_t x = i * TILE_SIDE + TILE_SIDE;
size_t y = 0;
if (stages_beat[i])
draw_tile(star_tile, x, y);
}
draw_tile(stage1_tile, 1 * TILE_SIDE, TILE_SIDE);
draw_tile(stage2_tile, 2 * TILE_SIDE, TILE_SIDE);
draw_tile(stage3_tile, 3 * TILE_SIDE, TILE_SIDE);
draw_tile(stage4_tile, 4 * TILE_SIDE, TILE_SIDE);
draw_tile(stage5_tile, 5 * TILE_SIDE, TILE_SIDE);
draw_tile(stage6_tile, 6 * TILE_SIDE, TILE_SIDE);
draw_tile(stage7_tile, 7 * TILE_SIDE, TILE_SIDE);
draw_tile(stage8_tile, 8 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 1) draw_tile(stage1_tile, 1 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 2) draw_tile(stage2_tile, 2 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 3) draw_tile(stage3_tile, 3 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 4) draw_tile(stage4_tile, 4 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 5) draw_tile(stage5_tile, 5 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 6) draw_tile(stage6_tile, 6 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 7) draw_tile(stage7_tile, 7 * TILE_SIDE, TILE_SIDE);
if (stages_num >= 8) draw_tile(stage8_tile, 8 * TILE_SIDE, TILE_SIDE);
size_t underline_y = 2 * TILE_SIDE + 1;
size_t underline_x = selection_index * TILE_SIDE + TILE_SIDE + 2;
for (size_t x = 0; x < TILE_SIDE - 4; x++)
@ -605,7 +607,91 @@ static void draw(struct timespec now) {
}
}
static void load_stages(char *path) {
FILE *f = fopen(path, "r");
if (!f)
err(1, "%s", path);
stages_num = 0;
bool in_comment = true;
size_t linenum = 0;
size_t stage_fill = 0;
char *stage[10];
while (true) {
linenum++;
char *line = NULL;
size_t size = 0;
ssize_t length = getline(&line, &size, f);
if (length < 0) {
break;
free(line);
}
if (line[length - 1] == '\n') {
line[length - 1] = 0;
length--;
}
if (!strcmp(line, "----------")) {
if (in_comment) {
in_comment = false;
continue;
} else {
if (stages_num == STAGES)
errx(1, "%s: %zu: Too many stages (maximum %zu)", path, linenum, (size_t)STAGES);
free(line);
if (stage_fill < 10)
errx(1, "%s: %zu: Not enough lines for a stage (expected 10, got %zu)", path, linenum, stage_fill);
char *stage_str;
asprintf(&stage_str, "%s%s%s%s%s%s%s%s%s%s", stage[0], stage[1], stage[2], stage[3], stage[4], stage[5], stage[6], stage[7], stage[8], stage[9]);
stages[stages_num++] = stage_str;
for (size_t i = 0; i < stage_fill; i++)
free(stage[i]);
stage_fill = 0;
continue;
}
} else if (stage_fill == 10)
errx(1, "%s: %zu: Too many lines for a stage (expected 10)", path, linenum);
if (in_comment)
free(line);
else if (length < 10)
errx(1, "%s: %zu: Line too short (expected 10 character, got %zd)", path, linenum, length);
else if (length > 10)
errx(1, "%s: %zu: Line too long (expected 10 character, got %zd)", path, linenum, length);
else
stage[stage_fill++] = line;
}
if (stage_fill) {
if (stages_num == STAGES)
errx(1, "%s: %zu: Too many stages (maximum %zu)", path, linenum, (size_t)STAGES);
if (stage_fill < 10)
errx(1, "%s: %zu: Not enough lines for a stage (expected 10, got %zu)", path, linenum, stage_fill);
char *stage_str;
asprintf(&stage_str, "%s%s%s%s%s%s%s%s%s%s", stage[0], stage[1], stage[2], stage[3], stage[4], stage[5], stage[6], stage[7], stage[8], stage[9]);
stages[stages_num++] = stage_str;
for (size_t i = 0; i < stage_fill; i++)
free(stage[i]);
}
if (!stages_num)
errx(1, "%s: Bundle did not contain any stages", path);
fclose(f);
}
int main(int argc, char *argv[]) {
if (argc == 1) {
stages_num = sizeof(builtin_stages) / sizeof(*builtin_stages);
for (size_t i = 0; i < stages_num; i++) {
stages[i] = builtin_stages[i];
}
} else if (argc == 2)
load_stages(argv[1]);
else {
printf("Usage: %s [/path/to/stage-bundle]\n", argv[0]);
return 1;
}
struct display_connection *connection = display_connect_default();
if (!connection && errno == ECONNREFUSED)
display_spawn(argc, argv);