implement a demo mode

This commit is contained in:
hkz 2025-09-06 09:58:24 +02:00
commit 8a4559d4f9
5 changed files with 95 additions and 60 deletions

View file

@ -29,7 +29,7 @@ GAME_ASM_SRCS = tk2k_startup_module.s preserve_zero_pages.s input_asm.s sound.s
GAME_C_SRCS = game_main.c input.c utility.c game_graphics.c line_data.c game_logic.c arrows_pic.c tiles.c graph_misc_data.c GAME_C_SRCS = game_main.c input.c utility.c game_graphics.c line_data.c game_logic.c arrows_pic.c tiles.c graph_misc_data.c
DEMO_ASM_SRCS = tk2k_startup_module.s preserve_zero_pages.s input_asm.s sound.s DEMO_ASM_SRCS = tk2k_startup_module.s preserve_zero_pages.s input_asm.s sound.s
DEMO_C_SRCS = demo_main.c input.c utility.c game_graphics.c line_data.c game_logic.c arrows_pic.c tiles.c graph_misc_data.c DEMO_C_SRCS = demo_main.c input.c utility.c game_graphics_demo.c line_data.c game_logic.c arrows_pic.c tiles.c graph_misc_data.c
# Object files # Object files
MASTER_OBJS = $(MASTER_ASM_SRCS:%.s=%.o) $(MASTER_C_SRCS:%.c=%.o) MASTER_OBJS = $(MASTER_ASM_SRCS:%.s=%.o) $(MASTER_C_SRCS:%.c=%.o)

View file

@ -31,7 +31,8 @@
#define HIGH_TEXT_X 32 #define HIGH_TEXT_X 32
#define HIGH_TEXT_Y 107 #define HIGH_TEXT_Y 107
#define WIN_SCORE_BONUS 10000 #define KEY_LOOP_LEN 0x2FFF
#define MAX_DEMO_MOVES 30
static state_page_data* state_page = (state_page_data*)STATE_PAGE; static state_page_data* state_page = (state_page_data*)STATE_PAGE;
static shared_page_data *shared_page = (shared_page_data*)SHARED_PAGE; static shared_page_data *shared_page = (shared_page_data*)SHARED_PAGE;
@ -53,18 +54,6 @@ void main(void) {
// Reset the game, calculate the initial score depending on which tiles we randomly get // Reset the game, calculate the initial score depending on which tiles we randomly get
score = reset_game(); score = reset_game();
// Load the game
if(gad->mode == GAME_MODE_LOAD) {
gad->mode = GAME_MODE_NORMAL;
memcpy(get_front_grid(), (void*)(state_page->save_grid), GRID_SIDE * GRID_SIDE);
moves_count = state_page->saved_moves_count;
score = calculate_score();
// We loaded an empty save, just restart the game
if (!score) score = reset_game();
}
// Draw the initial state of the game // Draw the initial state of the game
draw_game_background(state_page->hi_score); draw_game_background(state_page->hi_score);
@ -76,51 +65,51 @@ void main(void) {
swap_display_buffers(); swap_display_buffers();
while(1) { // Game loop while(1) { // Game loop
lfsr_update(); uint16_t lfsr = lfsr_update();
switch(read_kb()) { // Any key will let us out of this, wait some time for a keypress
case K_UP: uint16_t k_loop_count = KEY_LOOP_LEN;
SND_TAP(); while(k_loop_count--) {
done = step_game(GAME_STEP_UP); if(read_any_key()) {
ddraw_direction_arrows(GRAPH_ARROW_UP);
break;
case K_DOWN:
SND_TAP();
done = step_game(GAME_STEP_DOWN);
ddraw_direction_arrows(GRAPH_ARROW_DOWN);
break;
case K_LEFT:
SND_TAP();
done = step_game(GAME_STEP_LEFT);
ddraw_direction_arrows(GRAPH_ARROW_LEFT);
break;
case K_RIGHT:
SND_TAP();
done = step_game(GAME_STEP_RIGHT);
ddraw_direction_arrows(GRAPH_ARROW_RIGHT);
break;
case K_CTRL_R:
snd_mod_button(); snd_mod_button();
score = 0; // We'll reset the score done = 1;
done = -1;
break; break;
case K_CTRL_S: // The following two will return early }
snd_mod_button();
memcpy((void*)(state_page->save_grid), get_front_grid(), GRID_SIDE * GRID_SIDE);
state_page->saved_moves_count = moves_count;
shared_page->master_command = MASTER_COMMAND_SAVE;
case K_CTRL_L:
snd_mod_button();
sync_display1_buffer();
shared_page->next_module_idx = 4;
gad->mode = GAME_MODE_LOAD;
return;
default:
continue; // Do nothing, loop again
} }
if(!done) {
switch((lfsr & 0x0003) + 1) {
case K_UP:
SND_TAP();
done = step_game(GAME_STEP_UP);
ddraw_direction_arrows(GRAPH_ARROW_UP);
break;
case K_DOWN:
SND_TAP();
done = step_game(GAME_STEP_DOWN);
ddraw_direction_arrows(GRAPH_ARROW_DOWN);
break;
case K_LEFT:
SND_TAP();
done = step_game(GAME_STEP_LEFT);
ddraw_direction_arrows(GRAPH_ARROW_LEFT);
break;
case K_RIGHT:
SND_TAP();
done = step_game(GAME_STEP_RIGHT);
ddraw_direction_arrows(GRAPH_ARROW_RIGHT);
break;
default:
continue; // Do nothing, loop again
}
}
// Increase the count of moves we made (unless we lost or reset the game) // Increase the count of moves we made (unless we lost or reset the game)
if(done >= 0) moves_count++; if(done >= 0) {
moves_count++;
done = done || (moves_count >= MAX_DEMO_MOVES);
}
// Draw the number of moves // Draw the number of moves
draw_number(moves_count, MOVES_TEXT_WIDTH, MOVES_TEXT_X, MOVES_TEXT_Y); draw_number(moves_count, MOVES_TEXT_WIDTH, MOVES_TEXT_X, MOVES_TEXT_Y);
@ -130,7 +119,6 @@ void main(void) {
// If we have won, or we got a reset request, break out of this loop // If we have won, or we got a reset request, break out of this loop
if(done) { if(done) {
score += (done > 0) ? WIN_SCORE_BONUS : 0;
draw_number(score, SCORE_TEXT_WIDTH, SCORE_TEXT_X, SCORE_TEXT_Y); draw_number(score, SCORE_TEXT_WIDTH, SCORE_TEXT_X, SCORE_TEXT_Y);
swap_display_buffers(); // Make sure we show the latest changes swap_display_buffers(); // Make sure we show the latest changes
break; break;
@ -157,9 +145,11 @@ void main(void) {
// Sync the display buffers // Sync the display buffers
sync_display1_buffer(); sync_display1_buffer();
dld->mode = (done > 0) ? DLOG_MODE_WIN : DLOG_MODE_LOSE; // Always go back to the start dialog
dld->score = score; dld->mode = DLOG_MODE_START;
dld->score = 0;
clear_display_buffers();
return; return;
} }

View file

@ -21,7 +21,10 @@
static state_page_data* state_page = (state_page_data*)STATE_PAGE; static state_page_data* state_page = (state_page_data*)STATE_PAGE;
static shared_page_data *shared_page = (shared_page_data*)SHARED_PAGE; static shared_page_data *shared_page = (shared_page_data*)SHARED_PAGE;
#define WAIT_COUNTER_END 0xFFFF
void main(void) { void main(void) {
uint16_t wait_counter = 0;
dlog_data *dld = (dlog_data *)(shared_page->module_data); dlog_data *dld = (dlog_data *)(shared_page->module_data);
game_data *gad = (game_data *)(shared_page->module_data); game_data *gad = (game_data *)(shared_page->module_data);
@ -54,10 +57,16 @@ void main(void) {
shared_page->next_module_idx = 4; // Go to the GAME module shared_page->next_module_idx = 4; // Go to the GAME module
gad->mode = GAME_MODE_NORMAL; // Set the proper start mode for the game gad->mode = GAME_MODE_NORMAL; // Set the proper start mode for the game
while(!read_any_key()) { while(!read_any_key() && (wait_counter != WAIT_COUNTER_END)) {
wait_counter++;
lfsr_update(); lfsr_update();
} }
if (wait_counter == WAIT_COUNTER_END) {
shared_page->next_module_idx = 5; // Actually go to the DEMO module
return;
}
snd_mod_button(); snd_mod_button();
return; return;

View file

@ -78,7 +78,7 @@ static const uint8_t box_content_start[BOX_CONTENT_SIZE] = {
0, 0, 0, 0, 0, 0, 0,203, 77, 0, 0, 77, 0, 0, 77,192, 77, 0, 77, 77,211, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,203, 77, 0, 0, 77, 0, 0, 77,192, 77, 0, 77, 77,211, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 77, 77,211, 0, 0, 77, 0, 0, 77, 0, 77, 0, 77,198, 84, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77,211, 0, 0, 77, 0, 0, 77, 0, 77, 0, 77,198, 84, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 20, 11, 50, 48, 52, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 50, 46, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 11, 50, 48, 52, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 50, 46, 49, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -109,6 +109,27 @@ static const uint8_t instruction_box[INSTR_BOX_SIZE] = {
79, 0, 50, 48, 50, 53, 0, 50, 46, 48, 0, 79 79, 0, 50, 48, 50, 53, 0, 50, 46, 48, 0, 79
}; };
static const uint8_t demo_box[INSTR_BOX_SIZE] = {
4, 5, 13, 15, 0, 0, 13, 15, 4, 5, 0, 0,
0, 4, 5, 13, 15, 0, 0, 13, 15, 4, 5, 0,
0, 0, 4, 5, 13, 15, 0, 0, 13, 15, 4, 5,
5, 0, 0, 4, 5, 13, 15, 0, 0, 13, 15, 4,
4, 5, 0, 0, 4, 5, 13, 15, 0, 0, 13, 15,
15, 4, 5, 0, 0, 4, 5, 13, 15, 0, 0, 13,
13, 15, 4, 5, 0, 0, 4, 5, 13, 15, 0, 0,
79, 0, 50, 48, 50, 53, 0, 50, 46, 48, 0, 79
};
#ifdef _DEMO_MODE_
#define DEMO_TOP_TEXT_WIDTH 14
#define DEMO_TOP_TEXT_HEIGHT 1
#define DEMO_TOP_TEXT_X 7
#define DEMO_TOP_TEXT_Y 0
static const uint8_t demo_top_text[DEMO_TOP_TEXT_WIDTH * DEMO_TOP_TEXT_HEIGHT] = {
32, 16, 21, 19, 8, 32, 1, 14, 25, 32, 11, 5, 25, 32
};
#endif /* _DEMO_MODE_ */
// The grid is 5x5 squares, // The grid is 5x5 squares,
// It is offset on the left side by 7 pixels and on the top by 14 // It is offset on the left side by 7 pixels and on the top by 14
@ -135,6 +156,10 @@ void draw_game_background(uint16_t hi_score) {
// Draw the borders // Draw the borders
draw_field_borders_on_buffer(0x0F, buf); draw_field_borders_on_buffer(0x0F, buf);
#ifdef _DEMO_MODE_
draw_graph_char_box(DEMO_TOP_TEXT_X, DEMO_TOP_TEXT_Y, DEMO_TOP_TEXT_WIDTH, DEMO_TOP_TEXT_HEIGHT, demo_top_text, front_buf);
#endif
// Draw required pics // Draw required pics
draw_picture(SCORE_PIC_WIDTH_BYTES, SCORE_PIC_HEIGHT, 31, 14, score_pic_data, buf); draw_picture(SCORE_PIC_WIDTH_BYTES, SCORE_PIC_HEIGHT, 31, 14, score_pic_data, buf);
draw_picture(MOVES_PIC_WIDTH_BYTES, MOVES_PIC_HEIGHT, 31, 45, moves_pic_data, buf); draw_picture(MOVES_PIC_WIDTH_BYTES, MOVES_PIC_HEIGHT, 31, 45, moves_pic_data, buf);
@ -144,8 +169,12 @@ void draw_game_background(uint16_t hi_score) {
// Draw the high-score. This won't change at every turn, so makes sense to just draw once // Draw the high-score. This won't change at every turn, so makes sense to just draw once
direct_draw_number(hi_score, HIGH_TEXT_WIDTH, HIGH_TEXT_X, HIGH_TEXT_Y, front_buf); direct_draw_number(hi_score, HIGH_TEXT_WIDTH, HIGH_TEXT_X, HIGH_TEXT_Y, front_buf);
// Draw instruction box // Draw demo or instruction box
#ifdef _DEMO_MODE_
draw_graph_char_box(INSTR_BOX_X, INSTR_BOX_Y, INSTR_BOX_WIDTH, INSTR_BOX_HEIGHT, demo_box, front_buf);
#else
draw_graph_char_box(INSTR_BOX_X, INSTR_BOX_Y, INSTR_BOX_WIDTH, INSTR_BOX_HEIGHT, instruction_box, front_buf); draw_graph_char_box(INSTR_BOX_X, INSTR_BOX_Y, INSTR_BOX_WIDTH, INSTR_BOX_HEIGHT, instruction_box, front_buf);
#endif
// Copy the data from display page 1 to 2 // Copy the data from display page 1 to 2
memcpy((void*)DISPLAY_PAGE_2, (void*)DISPLAY_PAGE_1, DISPLAY_PAGE_SIZE); memcpy((void*)DISPLAY_PAGE_2, (void*)DISPLAY_PAGE_1, DISPLAY_PAGE_SIZE);
@ -207,6 +236,10 @@ void draw_tiles(void) {
// Re-draw the borders, to restore the correct width // Re-draw the borders, to restore the correct width
draw_field_borders_on_buffer(0x0F, back_buf); draw_field_borders_on_buffer(0x0F, back_buf);
#ifdef _DEMO_MODE_
draw_graph_char_box(DEMO_TOP_TEXT_X, DEMO_TOP_TEXT_Y, DEMO_TOP_TEXT_WIDTH, DEMO_TOP_TEXT_HEIGHT, demo_top_text, back_buf);
#endif
} }
#define ENDGAME_BOX_X_OFFSET 2 #define ENDGAME_BOX_X_OFFSET 2

3
src/game_graphics_demo.c Normal file
View file

@ -0,0 +1,3 @@
#define _DEMO_MODE_ 1
#include "game_graphics.c"