#include #include #include #include "vdp_utils.h" #include "game_vdp_graphics.h" #include "monitor_subroutines.h" #include "utility.h" #include "mem_map.h" #include "mem_registers.h" #include "shared_page.h" #include "state_page.h" #include "dlog_data.h" #include "game_data.h" #include "input.h" #include "game_logic.h" #include "monitor_subroutines.h" #include "sound.h" #include "module_list.h" // External initialization requirements #pragma require __preserve_zp #pragma require __data_initialization_needed #define HSCORE_TEXT_X 27 #define HSCORE_TEXT_Y 13 #define SCORE_TEXT_X 27 #define SCORE_TEXT_Y 4 #define MOVES_TEXT_X 27 #define MOVES_TEXT_Y 8 #define BOTTOM_TEXT_X 1 #define BOTTOM_TEXT_Y 23 #define WIN_SCORE_BONUS 10000 static state_page_data* state_page = (state_page_data*)STATE_PAGE; static shared_page_data *shared_page = (shared_page_data*)SHARED_PAGE; static uint8_t text_buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; void main(void) { uint16_t moves_count = 0; uint16_t score = 0; int8_t done = 0; __disable_interrupts(); // Make sure the interrupts are disabled // By default, once we return from this, return to the DLOG module and give the master no command to execute shared_page->master_command = MASTER_COMMAND_NONE; shared_page->next_module_idx = MODULE_DLOG_VDP; // Go to the dialog module dlog_data *dld = (dlog_data *)(shared_page->module_data); dlog_data *gad = (dlog_data *)(shared_page->module_data); // Make sure the buffers are pointing to the correct memory and are clear vdp_hide_sprites(); vdp_clear_gamegrid(); vdp_switch_nt(0); // Make sure VDP shows the gamegrid // Setup the IRQ handler POKEW(IRQ_HANDLER_ADDRESS, (uint16_t)vdp_irq_handler); // Reset the game, calculate the initial score depending on which tiles we randomly get 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 vdp_print_string(0, BOTTOM_TEXT_X, BOTTOM_TEXT_Y, "hkz@social.chinwag.org 2025"); num_to_decbuf(state_page->hi_score, 5, text_buf); // High score decbuf_to_ascii(5, text_buf); vdp_print_string(0, HSCORE_TEXT_X, HSCORE_TEXT_Y, (char*)text_buf); num_to_decbuf(moves_count, 5, text_buf); // Moves count decbuf_to_ascii(5, text_buf); vdp_print_string(0, MOVES_TEXT_X, MOVES_TEXT_Y, (char*)text_buf); num_to_decbuf(score, 5, text_buf); // Score decbuf_to_ascii(5, text_buf); vdp_print_string(0, SCORE_TEXT_X, SCORE_TEXT_Y, (char*)text_buf); vdp_draw_joystick(JS_POS_CENTER); // Center the joystick vdp_redraw_tiles(get_front_grid()); __enable_interrupts(); while(1) { // Game loop lfsr_update(); __disable_interrupts(); switch(read_kb()) { case K_UP: SND_TAP(); vdp_draw_joystick(JS_POS_UP); done = step_game(GAME_STEP_UP); break; case K_DOWN: SND_TAP(); vdp_draw_joystick(JS_POS_DOWN); done = step_game(GAME_STEP_DOWN); break; case K_LEFT: SND_TAP(); vdp_draw_joystick(JS_POS_LEFT); done = step_game(GAME_STEP_LEFT); break; case K_RIGHT: SND_TAP(); vdp_draw_joystick(JS_POS_RIGHT); done = step_game(GAME_STEP_RIGHT); break; case K_CTRL_R: snd_mod_button(); score = 0; // We'll reset the score done = -1; 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(); shared_page->next_module_idx = MODULE_GAME_VDP; gad->mode = GAME_MODE_LOAD; return; default: __enable_interrupts(); continue; // Do nothing, loop again } // Increase the count of moves we made (unless we lost or reset the game) if(done >= 0) moves_count++; num_to_decbuf(moves_count, 5, text_buf); // Moves count decbuf_to_ascii(5, text_buf); vdp_print_string(0, MOVES_TEXT_X, MOVES_TEXT_Y, (char*)text_buf); // If we have won, or we got a reset request, break out of this loop if(done) { score += (done > 0) ? WIN_SCORE_BONUS : 0; num_to_decbuf(score, 5, text_buf); // Score decbuf_to_ascii(5, text_buf); vdp_print_string(0, SCORE_TEXT_X, SCORE_TEXT_Y, (char*)text_buf); break; } // Unable to add a tile: we ran out of space and lost!!! uint8_t random_tile_off = add_random_tile(); if(!random_tile_off) { done = -1; // Lost the game break; } score = calculate_score(); // Draw the score num_to_decbuf(score, 5, text_buf); // Score decbuf_to_ascii(5, text_buf); vdp_print_string(0, SCORE_TEXT_X, SCORE_TEXT_Y, (char*)text_buf); vdp_redraw_tiles(get_front_grid()); vdp_draw_joystick(JS_POS_CENTER); __enable_interrupts(); } dld->mode = (done > 0) ? DLOG_MODE_WIN : DLOG_MODE_LOSE; dld->score = score; vdp_redraw_tiles(get_front_grid()); WAIT(0xFF); __disable_interrupts(); return; }