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.

394 lines
9.4 KiB

;; ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
;; ██░███░█▀▄▄▀█░▄▄▀█░▄▀█░██░▄▄██
;; ██░█░█░█░██░█░▀▀▄█░█░█░██░▄▄██
;; ██▄▀▄▀▄██▄▄██▄█▄▄█▄▄██▄▄█▄▄▄██
;; ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
;; The famous word puzzle
; Include hardware-specific constants
; used all over the code.
2 years ago
include "inc/constants.asm"
2 years ago
;; Game specific constants
; Game states
STATE_MENU EQU %00000001
2 years ago
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
2 years ago
; Marker for invalid or undefined values
NULL EQU $00
2 years ago
;; Indices of special tiles
TILE_NULL EQU NULL
TILE_BLACK EQU $1b
TILE_WHITE EQU $1c
2 years ago
TILE_PLACEHOLDER EQU $1d
TILE_ENTER EQU $1e
TILE_RIGHT EQU $1f
TILE_MISPLACED EQU $20
TILE_WRONG EQU $21
2 years ago
TILE_SLASH EQU $22
2 years ago
; Vertical blanking interrupt starting address
SECTION "ENTRY_VBLANK", ROM0[$0040]
jp int_vblank ; used for game logic updates
2 years ago
; LCDC status interrupt starting address
SECTION "ENTRY_LCDCS", ROM0[$0048]
reti ; we don't use this interrupt
2 years ago
; Timer overflow interrupt starting address
SECTION "ENTRY_TIMER", ROM0[$0050]
jp int_timer ; used for generating randomness
2 years ago
; Serial transfer completion interrupt starting address
SECTION "ENTRY_SERIAL", ROM0[$0058]
reti ; we don't use this interrupt
2 years ago
; 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
2 years ago
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
2 years ago
jp nz, .in_help
2 years ago
call handle_input_menu
jp .cleanup
2 years ago
.in_help:
cp a, STATE_HELP
jp nz, .in_game
call handle_input_help
call update_hint_markings
call update_guess_objects
jp .cleanup
2 years ago
.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.
2 years ago
tiles_start:
tile_null:
include "tiles/plain-null.asm"
2 years ago
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"
2 years ago
tiles_slash:
include "tiles/sign-slash.asm"
2 years ago
tiles_logo:
include "tiles/logo.asm"
tiles_end:
;; Maps
; Each map defines a grid of tile addresses,
; which combined will form the desired image.
2 years ago
maps_start:
background:
include "maps/background.asm"
2 years ago
window_help:
include "maps/window-help.asm"
window_game:
include "maps/window-game.asm"
2 years ago
maps_end:
;; Dictionary
; A list of known words to choose from.
2 years ago
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.
2 years ago
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
2 years ago
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
2 years ago
2 years ago
;; 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.
2 years ago
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
2 years ago
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
2 years ago
DB $88, $70, 13, OBJ_ATTR_PALETTE1 ; M
DB $88, $78, 05, OBJ_ATTR_PALETTE1 ; E
2 years ago
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
2 years ago
message_unknown:
2 years ago
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
2 years ago
DB $00, $00, 0, 0
2 years ago
DB $00, $00, 0, 0
2 years ago
message_won:
2 years ago
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
2 years ago
DB $00, $00, 0, 0
DB $00, $00, 0, 0
2 years ago
DB $00, $00, 0, 0
2 years ago
message_lost:
2 years ago
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]
2 years ago
DB $00, $00, 0, 0
2 years ago
;; Address reservations within the working ram
2 years ago
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:
2 years ago
DS 36
2 years ago
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
2 years ago
random_number:
DS 2
; Saves the last keystate
input_state:
DB
; Saves the current game state (see STATE constants)
2 years ago
current_state:
DB
; Saves the subordinate state (see STATE constants)
2 years ago
sub_state:
DB
; Number of the current guess (0..5)
2 years ago
current_guess:
DB
; Position within the current guess (0..4)
2 years ago
current_char:
DB
2 years ago
; Saves the current word
current_word:
DS 5
2 years ago
; The guess attempts
guesses:
DS 30
2 years ago
; The corresponding hints
guesses_hints:
DS 30
; Message timeout (remaining number of frames)
2 years ago
message_timeout:
DB
; Horizontal position of the letter selection within the alphabet grid
2 years ago
selected_letter_x:
DB
; Vertical position of the letter selection within the alphabet grid
2 years ago
selected_letter_y:
DB