You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
9.4 KiB
393 lines
9.4 KiB
;; ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ |
|
;; ██░███░█▀▄▄▀█░▄▄▀█░▄▀█░██░▄▄██ |
|
;; ██░█░█░█░██░█░▀▀▄█░█░█░██░▄▄██ |
|
;; ██▄▀▄▀▄██▄▄██▄█▄▄█▄▄██▄▄█▄▄▄██ |
|
;; ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ |
|
;; The famous word puzzle |
|
|
|
; Include hardware-specific constants |
|
; used all over the code. |
|
include "inc/constants.asm" |
|
|
|
|
|
;; Game specific constants |
|
; Game states |
|
STATE_MENU EQU %00000001 |
|
STATE_MENU_START EQU %01000000 |
|
STATE_MENU_HELP EQU %10000000 |
|
STATE_HELP EQU %00000010 |
|
STATE_GAME EQU %00000100 |
|
STATE_LOST EQU %00001000 |
|
STATE_WON EQU %00011000 |
|
|
|
; Marker for invalid or undefined values |
|
NULL EQU $00 |
|
|
|
;; Indices of special tiles |
|
TILE_NULL EQU NULL |
|
TILE_BLACK EQU $1b |
|
TILE_WHITE EQU $1c |
|
TILE_PLACEHOLDER EQU $1d |
|
TILE_ENTER EQU $1e |
|
TILE_RIGHT EQU $1f |
|
TILE_MISPLACED EQU $20 |
|
TILE_WRONG EQU $21 |
|
TILE_SLASH EQU $22 |
|
|
|
|
|
|
|
; Vertical blanking interrupt starting address |
|
SECTION "ENTRY_VBLANK", ROM0[$0040] |
|
jp int_vblank ; used for game logic updates |
|
|
|
|
|
; LCDC status interrupt starting address |
|
SECTION "ENTRY_LCDCS", ROM0[$0048] |
|
reti ; we don't use this interrupt |
|
|
|
|
|
; Timer overflow interrupt starting address |
|
SECTION "ENTRY_TIMER", ROM0[$0050] |
|
jp int_timer ; used for generating randomness |
|
|
|
|
|
; Serial transfer completion interrupt starting address |
|
SECTION "ENTRY_SERIAL", ROM0[$0058] |
|
reti ; we don't use this interrupt |
|
|
|
|
|
; Program starting address |
|
SECTION "ENTRY_START", ROM0[$0100] |
|
jp main |
|
|
|
|
|
|
|
SECTION "MAIN", ROM0[$0150] |
|
main: |
|
; turn the screen off until everything is initialized, |
|
; or wild glitches will appear |
|
ld a, DISPLAY_OFF |
|
ld [LCD_CONTROL_REGISTER], a |
|
ld [LCD_STATUS_REGISTER], a |
|
|
|
; set the stack pointer |
|
ld sp, INITIAL_STACK_POINTER |
|
|
|
; load the video data |
|
call init_palettes |
|
call load_tiles |
|
call load_background_map |
|
|
|
; initialise the objects |
|
call init_oam_copy |
|
call update_oam |
|
|
|
; initialise the game state |
|
call init_state_menu |
|
|
|
; enable specific interrupts |
|
ld a, INT_VBLANK_ON + INT_TIMER_ON |
|
ld [INTERRUPT_SETTINGS], a |
|
|
|
; configure the timer |
|
ld a, TIMER_START + TIMER_16KHZ |
|
ld [TIMER_SETTINGS], a |
|
|
|
|
|
|
|
; Every frame consists of the phases: |
|
; 1) The display will be updated. |
|
; Within this period we can't alter the graphics data. |
|
; We use this time to handle input and calculate stuff. |
|
; 2) The display was updated. |
|
; Now we have a limited time frame where we can update |
|
; all graphic related memory locations. |
|
main_loop: |
|
ld a, [vblank_flag] |
|
cp a, 0 |
|
jp z, main_loop |
|
|
|
.within_vblank: |
|
call update_oam |
|
call read_input |
|
ld a, [current_state] |
|
|
|
.in_menu: |
|
cp a, STATE_MENU |
|
jp nz, .in_help |
|
call handle_input_menu |
|
jp .cleanup |
|
|
|
.in_help: |
|
cp a, STATE_HELP |
|
jp nz, .in_game |
|
call handle_input_help |
|
call update_hint_markings |
|
call update_guess_objects |
|
jp .cleanup |
|
|
|
.in_game: |
|
cp a, STATE_GAME |
|
jp nz, .in_won |
|
call handle_input_game |
|
call update_hint_markings |
|
call update_guess_objects |
|
call update_cursor_objects |
|
jp .cleanup |
|
|
|
.in_won: |
|
cp a, STATE_WON |
|
jp nz, .in_lost |
|
call handle_input_after |
|
call update_hint_markings |
|
jp .cleanup |
|
|
|
.in_lost: |
|
cp a, STATE_LOST |
|
jp nz, .cleanup |
|
call handle_input_after |
|
call update_hint_markings |
|
jp .cleanup |
|
|
|
.cleanup: |
|
; reset vblank flag |
|
ld a, 0 |
|
ld [vblank_flag], a |
|
|
|
call check_message_timeout |
|
jp main_loop |
|
|
|
|
|
|
|
include "inc/init.asm" |
|
include "inc/math.asm" |
|
include "inc/oam.asm" |
|
include "inc/dict.asm" |
|
include "inc/input.asm" |
|
include "inc/guess.asm" |
|
include "inc/hints.asm" |
|
include "inc/messages.asm" |
|
include "inc/wincondition.asm" |
|
include "inc/interrupts.asm" |
|
|
|
|
|
|
|
;; Game data |
|
SECTION "DATA0", ROM0[$1000] |
|
|
|
;; Tiles |
|
; Small 8x8 pixel images, which are addressable |
|
; and will be used for sprite maps and objects. |
|
tiles_start: |
|
tile_null: |
|
include "tiles/plain-null.asm" |
|
tiles_alphabet: |
|
include "tiles/alphabet.asm" |
|
tile_black: |
|
include "tiles/plain-black.asm" |
|
tile_white: |
|
include "tiles/plain-white.asm" |
|
tiles_placeholder: |
|
include "tiles/sign-placeholder.asm" |
|
tiles_enter: |
|
include "tiles/sign-enter.asm" |
|
tiles_right: |
|
include "tiles/sign-right.asm" |
|
tile_misplaced: |
|
include "tiles/sign-misplaced.asm" |
|
tiles_wrong: |
|
include "tiles/sign-wrong.asm" |
|
tiles_slash: |
|
include "tiles/sign-slash.asm" |
|
tiles_logo: |
|
include "tiles/logo.asm" |
|
tiles_end: |
|
|
|
|
|
;; Maps |
|
; Each map defines a grid of tile addresses, |
|
; which combined will form the desired image. |
|
maps_start: |
|
background: |
|
include "maps/background.asm" |
|
window_help: |
|
include "maps/window-help.asm" |
|
window_game: |
|
include "maps/window-game.asm" |
|
maps_end: |
|
|
|
|
|
;; Dictionary |
|
; A list of known words to choose from. |
|
dictionary: |
|
incbin "dict/en.dat" |
|
dictionary_end: |
|
|
|
|
|
;; Help data |
|
; The help screen will reuse the normal |
|
; game mechanics to provide a manual |
|
; how to play this game. |
|
; Now following is hard coded-data |
|
; to provide a set of information. |
|
help_word: |
|
DB $12, $09, $07, $08, $14 ; right |
|
|
|
help_guess: |
|
DB $06, $01, $15, $0c, $14 ; fault |
|
DB $07, $09, $12, $14, $08 ; girth |
|
DB $12, $09, $07, $08, $14 ; right |
|
DB $0f, $0e, $0c, $19, $00 ; only |
|
DB $13, $09, $18, $00, $00 ; six |
|
DB $14, $12, $09, $05, $13 ; tries |
|
|
|
help_guess_hints: |
|
DB TILE_WRONG, TILE_WRONG, TILE_WRONG, TILE_WRONG, TILE_RIGHT |
|
DB TILE_MISPLACED, TILE_MISPLACED, TILE_MISPLACED, TILE_MISPLACED, TILE_MISPLACED |
|
DB TILE_RIGHT, TILE_RIGHT, TILE_RIGHT, TILE_RIGHT, TILE_RIGHT |
|
DB TILE_WHITE, TILE_WHITE, TILE_WHITE, TILE_WHITE, TILE_WHITE |
|
DB TILE_WHITE, TILE_WHITE, TILE_WHITE, TILE_WHITE, TILE_WHITE |
|
DB TILE_WHITE, TILE_WHITE, TILE_WHITE, TILE_WHITE, TILE_WHITE |
|
|
|
|
|
;; Messages |
|
; This game uses a message system to |
|
; provide feedback to the user. |
|
; For this, nine objects are reserved |
|
; and can be used at will. |
|
message_clear: |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
DB $00, $00, $00, $00 |
|
|
|
message_menu_start: |
|
DB $88, $30, 19, OBJ_ATTR_PALETTE1 ; S |
|
DB $88, $38, 20, OBJ_ATTR_PALETTE1 ; T |
|
DB $88, $40, 01, OBJ_ATTR_PALETTE1 ; A |
|
DB $88, $48, 18, OBJ_ATTR_PALETTE1 ; R |
|
DB $88, $50, 20, OBJ_ATTR_PALETTE1 ; T |
|
DB $88, $60, 07, OBJ_ATTR_PALETTE1 ; G |
|
DB $88, $68, 01, OBJ_ATTR_PALETTE1 ; A |
|
DB $88, $70, 13, OBJ_ATTR_PALETTE1 ; M |
|
DB $88, $78, 05, OBJ_ATTR_PALETTE1 ; E |
|
|
|
message_menu_help: |
|
DB $90, $30, 08, OBJ_ATTR_PALETTE1 ; H |
|
DB $90, $38, 15, OBJ_ATTR_PALETTE1 ; O |
|
DB $90, $40, 23, OBJ_ATTR_PALETTE1 ; W |
|
DB $90, $50, 20, OBJ_ATTR_PALETTE1 ; T |
|
DB $90, $58, 15, OBJ_ATTR_PALETTE1 ; O |
|
DB $90, $68, 16, OBJ_ATTR_PALETTE1 ; P |
|
DB $90, $70, 12, OBJ_ATTR_PALETTE1 ; L |
|
DB $90, $78, 01, OBJ_ATTR_PALETTE1 ; A |
|
DB $90, $80, 25, OBJ_ATTR_PALETTE1 ; Y |
|
|
|
message_unknown: |
|
DB $74, $38, 21, OBJ_ATTR_PALETTE1 ; U |
|
DB $74, $40, 14, OBJ_ATTR_PALETTE1 ; N |
|
DB $74, $48, 11, OBJ_ATTR_PALETTE1 ; k |
|
DB $74, $50, 14, OBJ_ATTR_PALETTE1 ; N |
|
DB $74, $58, 15, OBJ_ATTR_PALETTE1 ; O |
|
DB $74, $60, 23, OBJ_ATTR_PALETTE1 ; W |
|
DB $74, $68, 14, OBJ_ATTR_PALETTE1 ; N |
|
DB $00, $00, 0, 0 |
|
DB $00, $00, 0, 0 |
|
|
|
message_won: |
|
DB $74, $38, 25, OBJ_ATTR_PALETTE1 ; Y |
|
DB $74, $40, 15, OBJ_ATTR_PALETTE1 ; O |
|
DB $74, $48, 21, OBJ_ATTR_PALETTE1 ; U |
|
DB $74, $58, 23, OBJ_ATTR_PALETTE1 ; W |
|
DB $74, $60, 15, OBJ_ATTR_PALETTE1 ; O |
|
DB $74, $68, 14, OBJ_ATTR_PALETTE1 ; N |
|
DB $00, $00, 0, 0 |
|
DB $00, $00, 0, 0 |
|
DB $00, $00, 0, 0 |
|
|
|
message_lost: |
|
DB $74, $30, 9, OBJ_ATTR_PALETTE1 ; I |
|
DB $74, $38, 20, OBJ_ATTR_PALETTE1 ; T |
|
DB $74, $40, 19, OBJ_ATTR_PALETTE1 ; S |
|
DB $74, $50, 0, OBJ_ATTR_PALETTE1 ; guess[0] |
|
DB $74, $58, 0, OBJ_ATTR_PALETTE1 ; guess[1] |
|
DB $74, $60, 0, OBJ_ATTR_PALETTE1 ; guess[2] |
|
DB $74, $68, 0, OBJ_ATTR_PALETTE1 ; guess[3] |
|
DB $74, $70, 0, OBJ_ATTR_PALETTE1 ; guess[4] |
|
DB $00, $00, 0, 0 |
|
|
|
|
|
|
|
;; Address reservations within the working ram |
|
SECTION "RAM", WRAM0 |
|
; The first 160 Bytes are reserved for a copy |
|
; of the OAM data, which will be updated via DMA. |
|
obj_start: |
|
obj_selected_letter: |
|
DS 4 |
|
obj_guess_letters: |
|
DS 120 |
|
obj_message_letters: |
|
DS 36 |
|
obj_end: |
|
obj_dma_padding: |
|
DS 160 - (obj_end - obj_start) |
|
|
|
|
|
; Will be set to 1 after each vblank interrupt |
|
vblank_flag: |
|
DB |
|
|
|
; Saves the current random number consisting of 16 bits |
|
random_number: |
|
DS 2 |
|
|
|
; Saves the last keystate |
|
input_state: |
|
DB |
|
|
|
; Saves the current game state (see STATE constants) |
|
current_state: |
|
DB |
|
|
|
; Saves the subordinate state (see STATE constants) |
|
sub_state: |
|
DB |
|
|
|
; Number of the current guess (0..5) |
|
current_guess: |
|
DB |
|
|
|
; Position within the current guess (0..4) |
|
current_char: |
|
DB |
|
|
|
; Saves the current word |
|
current_word: |
|
DS 5 |
|
|
|
; The guess attempts |
|
guesses: |
|
DS 30 |
|
|
|
; The corresponding hints |
|
guesses_hints: |
|
DS 30 |
|
|
|
; Message timeout (remaining number of frames) |
|
message_timeout: |
|
DB |
|
|
|
; Horizontal position of the letter selection within the alphabet grid |
|
selected_letter_x: |
|
DB |
|
|
|
; Vertical position of the letter selection within the alphabet grid |
|
selected_letter_y: |
|
DB |
|
|
|
|