    ;; This example demonstrates a method to plot sprites using the firmware
    ;; and the character set.
    ;;
    ;; - The sprites are defined using the character set matrices.
    ;;
    ;; - Each sprite is therefore composed of multiple 8x8 character matrices.
    ;;
    ;; - The display mode is set to mode 2 (640x200) which uses 1 bit per pixel
    ;;   Each line of the character matrix is represented by 1 byte.
    ;;
    ;; - When the character is displayed in mode 2, each line of the character
    ;;   matrix is written direct to the screen memory without conversion.
    ;;   This is an important fact for this example.
    ;;   (Normally, the character matrix data is converted into mode 1 or mode 2
    ;;   pixel data)
    ;;
    ;; - The display mode is changed, without informing the firmware functions.
    ;;   The characters will be plotting using the mode 2 method, regardless
    ;;   of the forced video mode. This is an important fact for this example.
    ;;
    ;;   If the character matrix data is setup so that each byte represents
    ;;   a byte of mode 1 or mode 0 screen pixel data, then multi-coloured
    ;;   sprites can be plotted, by the firmware, using the standard character
    ;;   plot routines. The only problem, is that each character matrix
    ;;   represents 4x8 pixels in mode 1, and 2x8 pixels in mode 0. So many
    ;;   matrices may be required to hold the pixel data for each sprite.
    ;;
    ;; - graphics coordinates, if used, must be defined so that the sprite
    ;;   is plotted on a byte boundary. e.g. x must be a integer multiple of 8.
    ;;
    ;; This method may be useful for plotting sprites for games in a
    ;; 1K games competition.

    .scr_set_mode equ &bc0e
    .mc_set_mode equ &bd1c
    .km_read_char equ &bb09
    .mc_wait_flyback equ &bd19
    .txt_output equ &bb5a
    .txt_set_matrix equ &bba8
    .gra_move_absolute equ &bbc0
    .gra_move_relative equ &bbc3
    .gra_wr_char equ &bbfc
    .scr_access equ &bc59

    org &4000
    nolist

    ;;-----------------------------------------------------------------------

    ;; set display mode 2
    ld a,2
    call scr_set_mode

    ;; force display mode 1
    ;; - the firmware will plot characters using the method for mode 2.

    ld a,1
    call mc_set_mode

    ;;-----------------------------------------------------------------------
    ;; set screen write mode to XOR
    ;;
    ;; - plot sprite using XOR to display, plot sprite using XOR in same position
    ;; to erase.
    ;; - if sprite moves over any other graphics, some pixels will change colour.

    ld a,1
    call scr_access

    ;;-----------------------------------------------------------------------

    ;; initialise sprite data

    ld hl,pixel_data          ;; location of character matrix data
    ld a,248                  ;; id of first character matrix
    ld b,8                    ;; number of characters to define matrix for
    .sch
    push af
    push bc
    push hl
    call txt_set_matrix       ;; set character matrix
    pop hl

    ld bc,8                   ;; number of bytes per character matrix
    add hl,bc

    pop bc
    pop af
    inc a
    djnz sch

    ;;--------------------------------------------------------------------------

    ;; plot sprite
    ld a,248
    ld de,(sprite_x)
    ld hl,(sprite_y)
    call draw_sprite

    .loop
    call mc_wait_flyback

    ;; erase sprite
    ld a,248
    ld de,(sprite_x)
    ld hl,(sprite_y)
    call draw_sprite

    call controls

    ;; plot sprite (in new position
    ;; if sprite's coordinates have changed)
    ld a,248
    ld de,(sprite_x)
    ld hl,(sprite_y)
    call draw_sprite

    jp loop

    .controls
    call km_read_char
    ret nc
    and &df
    cp "Q"
    jp z,moveup
    cp "A"
    jp z,movedown
    cp "O"
    jr z,moveleft
    cp "P"
    jr z,moveright
    ret

    ;; adjust y coordinate of sprite
    ;; to move it up the screen.
    ;; - Each scan-line is 2 graphics y coordinates.
    ;; - origin of graphics coordinates is bottom-left
    .moveup
    ld hl,(sprite_y)
    inc hl
    inc hl
    ld (sprite_y),hl
    ret

    ;; adjust y coordinate of sprite
    ;; to move it down the screen.
    .movedown
    ld hl,(sprite_y)
    dec hl
    dec hl
    ld (sprite_y),hl
    ret

    ;; adjust x coordinate of sprite
    ;; to move it left accross the screen.
    ;; - each byte is 8 graphics x coordinates
    .moveleft
    ld hl,(sprite_x)
    ld bc,8
    or a
    sbc hl,bc
    ld (sprite_x),hl
    ret

    ;; adjust x coordinate of sprite
    ;; to move it right accross screen
    .moveright
    ld hl,(sprite_x)
    ld bc,8
    add hl,bc
    ld (sprite_x),hl
    ret

    ;;-------------------------------------------------------------
    ;; A = id of first character used by sprite data
    ;; DE = x graphics coordinate
    ;; HL = y graphics coordinate

    .draw_sprite
    ;; move to initial position
    push af
    call gra_move_absolute
    pop af

    ld b,2          ;; number of character matrices occupied by sprite in
                    ;; y dimension
    .ps1
    push bc
    push af

    ld c,4          ;; number of character matrices occupied by sprite in
                    ;; x dimension

    .ps2
    push bc
    push af

    ;; plot character at graphics coordinate position
    ;; and update graphics coordinate position for next
    ;; character
    call gra_wr_char

    pop af
    pop bc
    add 2           ;; increment character id
                    ;; (see character matrix usage below)
    dec c
    jr nz,ps2

    ;; adjust graphics character position for next row
    ;; of characters

    ld de,-8*4
    ld hl,-16
    call gra_move_relative

    pop af

    ;; increment character id
    ;; (see character matrix usage below)
    inc a

    pop bc
    djnz ps1
    ret

    ;;-----------------------------------------------------------------------

    ;; graphics coordinates for sprites position
    .sprite_x defw 320
    .sprite_y defw 100

    ;; sprite is:
    ;; - 16 mode 1 pixels wide = 4 bytes wide = 4 mode 2 characters wide
    ;; - 16 mode 1 pixels tall = 2 mode 2 characters tall
    ;;
    ;; sprite data is stored as:
    ;;
    ;; char 248   char 250  char 252  char 254
    ;; char 249   char 251  char 253  char 255

    .pixel_data
    defb &00                  ;; char 248
    defb &00
    defb &10
    defb &20
    defb &40
    defb &40
    defb &80
    defb &80

    defb &80                  ;; char 249
    defb &80
    defb &40
    defb &51
    defb &31
    defb &10
    defb &00
    defb &00

    defb &30                  ;; char 250
    defb &C0
    defb &00
    defb &00
    defb &06
    defb &0C
    defb &0C
    defb &04

    defb &00                  ;; char 251
    defb &00
    defb &AA
    defb &55
    defb &FF
    defb &FD
    defb &F2
    defb &30

    defb &C0                  ;; char 252
    defb &30
    defb &00
    defb &00
    defb &00
    defb &00
    defb &00
    defb &11

    defb &22                  ;; char 253
    defb &55
    defb &BA
    defb &75
    defb &FA
    defb &F5
    defb &F8
    defb &C0

    defb &00                  ;; char 254
    defb &00
    defb &80
    defb &40
    defb &20
    defb &20
    defb &32
    defb &76

    defb &FA                  ;; char 255
    defb &F4
    defb &E8
    defb &E4
    defb &C8
    defb &80
    defb &00
    defb &00