Alien-A

Description of the page content

Invaders game for the Sinclair ZX Spectrum, written in Z80 assembly.

Tags:

I wrote this little game in 1986, as an exercise to remake and improve, in Z80 assembly, a game written in Sinclair BASIC I found in a magazine: the original game (3.47 KiB) was anonymously published by the Spanish ZX magazine, first issue, 1983, pages 14 and 15:

page 14 de ZX 1 (190.87 KiB) page 15 de ZX 1 (209.71 KiB)

I kept the character by character movement and the UDG s. But I changed the game itself in many ways: In fact the only remaining parts were the landscape and the aim.

In 2010, in order to publish it in programandala.net, I loaded the TAP file with the original source (written with GENS3) into my favourite editor, Vim, and converted it into a simple text file ready to be compiled by Pasmo. But when I felt the old source code in my hands, in a modern format, I couldn't resist the temptation to make some changes...

Screenshots

The menu can be shown in three languages: Spanish, Esperanto and English.

Menú inicial en castellanoMenú inicial en inglésMenú inicial en esperanto

The three different alien ships, in the three languages:

Nave hacia la izquierdaNave hacia abajoNave hacia la derecha

Source code

; *************************************************************
; Alien-A

; A game for the Sinclair ZX Spectrum.

; Copyright (C) 1986,2010 Marcos Cruz (http://programandala.net)
; License/Licencia/Permesilo:
; http://programandala.net/license

; Alien-A is written in Z80 assembly, but it works the BASIC way:
; UDGs and character resolution movement.

; I hope Alien-A can be useful for someone learning Z80 assembly
; with the ZX Spectrum.

; Alien-A was inspired by a simpler program,
; written in Sinclair Basic and published in the ZX magazine
; (issue 1, pages 14-15, 1983):
; http://microhobby.speccy.cz/zx/revista_zx.htm
; http://microhobby.speccy.cz/zx/zx01/01-14.JPG
; http://microhobby.speccy.cz/zx/zx01/01-15.JPG
; http://microhobby.speccy.cz/zxsf/listados/progs/i/Invasores1.tzx 

; *************************************************************
; History

; 1986-04-27
; * First working version.
; 1986-04-30
; * Improved with record, number of landing aliens and different aliens; no more need to press fire.
; 1986-05-04
; * Improved with stars, and new graphics inspired by Star Wars. A shield bar is shown instead of the number of landing aliens.
; 1986-06-04
; * Some bugs fixed.
; 1986-06-14
; * No bugs left. Finished.
; 2010-03-23
; * The original source, in GENS3 format, was edited in order to
;   compile it with Pasmo (http://arrakis.es/~ninsesabe/pasmo/)
;   on Debian GNU/Linux.
; 2010-03-24
; * Several changes in order to make the source easier to read:
;   labeled ROM routines and system variables, renamed labels,
;   new comments...
; * Cursor keys intead of P-O-Q-R; easier for my Dvorak keyboard layout!
; * A bit faster control key routine.
; * The aim can move diagonally.
; 2010-04-07
; * Better pseudo random numbers routine.
; 2010-04-13
; * First draft of a final effect: screen fade.
; 2010-04-14
; * Fixed: the last landing alien didn't caused the sound effect
;   because the shield check was done before it.
; * The sound effects are exchanged: now aliens explode when landing.
; * Final effect: random explosions.
; * Improved: the scenery field appears quickly.
; 2010-04-15
; * Fixed: the aim flickering has been solved.
; * Final effect finished.
; * Improved: two dicker lines in the field lines.
; 2010-04-21
; * Improved: pause between the final effect and the menu, with blank screen.
; 2010-04-24
; * Improved: texts in three languages: English, Esperanto and Spanish.
; * Changed: the bar shield is printed in one single color, and it flashes when short (instead of the text).
; 2010-04-27
; * New character set, designed by Alan Grier (http://www.worldofspectrum.org/infoseekid.cgi?id=001171) in 1986, a bit modified by me.

; *************************************************************
; To do

; Check: Text positions.
; Improve: definable keys.
; Improve: don't print the "score" text every time the score changes.
; Fix: the shooted aliens not always get red. Maybe a emulator issue? 

; *************************************************************
; ROM routines

CHAN_OPEN       EQU #1601 ; open a channel (channel in A)
PR_STRING       EQU #203C ; print a string (start in DE, count in BC)
PLOT_SUB        EQU #22E5 ; the plot subroutine (coords in BC)
DRAW            EQU #24BA ; point of the DRAW_LINE routine
STACK_BC        EQU #2D2B ; stack BC register pair
FP_TO_BC        EQU #2DA2
FP_TO_A         EQU #2DD5
PRINT_FP        EQU #2DE3 ; print a floating point number

; *************************************************************
; Sytem addresses

VIDEO   EQU 16384
ATTRS   EQU 22528

; *************************************************************
; Sytem constants

VIDEO_LENGHT    EQU 6912
ATTRS_LENGHT    EQU 768
BITMAP_LENGHT   EQU VIDEO_LENGHT-ATTRS_LENGHT
COLUMNS         EQU 32

; *************************************************************
; Sytem variables

; Absolute addresses

CHARS   EQU 23606
ERR_NR  EQU 23610
BORDER  EQU 23624
SEED    EQU 23670
FRAMES  EQU 23672
UDG     EQU 23675
P_FLAG  EQU 23697
ATTR_P  EQU 23693
ATTR_T  EQU 23695

; *************************************************************
; Constants

ATTR            EQU %00000111 ; white ink, black paper
TRANSPARENT     EQU 8 ; keep the current attribute

OWN_CHARSET     EQU 1 ; compile time flag
MAX_SHIELD      EQU 32
SHIELD_ATTR     EQU %01101000 ; bright, cyan paper

INK_CHR         EQU 16
PAPER_CHR       EQU 17
BRIGHT_CHR      EQU 19
INVERSE_CHR     EQU 20
OVER_CHR        EQU 20
AT_CHR          EQU 22
SPACE_CHR       EQU 32

; *************************************************************
; Languages 

LANGUAGES               EQU 3 ; number of languages
EN                      EQU 0 ; English
EO                      EQU 1 ; Esperanto
ES                      EQU 2 ; Spanish
DEFAULT_LANGUAGE        EQU EN

; *************************************************************
; System init

ENTRY   ORG 32768

        DI

        LD A,2
        CALL CHAN_OPEN

        IF OWN_CHARSET
        LD HL,CHAR_SET-256
        LD (CHARS),HL
        ENDIF

        LD HL,ALIEN_UDGS
        LD (UDG),HL

        LD A,(FRAMES)
;        OR 1 ; make sure it's not zero
        LD (SEED),A

; *************************************************************
; Start

START
        CALL CLS

        LD DE,TITLE_TXT
        LD BC,TITLE_LEN
        CALL PR_STRING
PR_MENU
        CALL CLEAR_MENU
        LD HL,MENU_TXTS
        CALL PR_LANGUAGE_STRING
        LD DE,KEYS_TXT
        LD BC,KEYS_LEN
        CALL PR_STRING
        CALL PR_LANGUAGE

FIRST_INK
        LD A,1 ; blue ink
CHANGE_INK
        PUSH AF ; save the ink
        LD HL,ATTRS+32*3 ; from line 4
        LD DE,ATTRS+32*3+1
        LD BC,16*32-1 ; 16 lines
        LD (HL),A
        LDIR

        LD BC,#0F00 ; wait counter

CHECK_KEYS
        LD A,%10111111 ; keyboard semi row H-J-K-L-ENTER
        IN A,(#FE)
        AND %00010 ; key "L"
        JR NZ,WAIT_KEY_0
RELEASE_L
        LD A,%10111111 ; keyboard semi row H-J-K-L-ENTER
        IN A,(#FE)
        AND %00010 ; key "L"
        JR Z,RELEASE_L

        LD A,(LANGUAGE)
        INC A
CHANGE_LANGUAGE
        LD (LANGUAGE),A
        CP LANGUAGES
        JR C,PR_MENU
        POP AF ; sync the stack
        XOR A
        JR CHANGE_LANGUAGE

WAIT_KEY_0
        CALL KEY_0
        JR NZ,CHECK_KEYS_END ; jump if "0" is not pressed
RELEASE_KEY_0
        CALL KEY_0
        JR Z,RELEASE_KEY_0 ; jump until "0" is not pressed
        JR INIT

CHECK_KEYS_END
        DEC BC
        LD A,B
        OR C
        JR NZ,CHECK_KEYS

        POP AF ; restore the ink
        INC A ; next ink color
        CP 8 ; no more ink colors?
        JR Z,FIRST_INK ; then start again
        JR CHANGE_INK

; *************************************************************
; Game init

INIT
        LD HL,0
        LD (SCORE),HL
        LD A,MAX_SHIELD
        LD (SHIELD),A
        LD DE,#0A0F ; line 10, column 15
        LD (AIM_COORDS),DE

        CALL SCENERY
        CALL OVER_1
        CALL NEW_ALIEN

; *************************************************************
; Main loop

        CALL PR_AIM
        CALL PR_ALIEN

MAIN
        CALL RANDOM
        CP (IX+MOVE_PROB)
        JR NC,AIM

        CALL PR_ALIEN

        LD DE,(ALIEN_COORDS)
        CALL RANDOM
        CP (IX+GLIDE_DIR)
        JR C,RIGHT

        ; Alien

        ; Left
        LD A,E
        AND A
        JR NZ,LEFT1
        LD E,32
LEFT1
        DEC E
        AND A
        JR DOWN

RIGHT
        LD A,E
        CP 31
        JR NZ,RIGHT1
        LD E,-1
RIGHT1
        INC E

DOWN
        LD (ALIEN_COORDS),DE
        CALL RANDOM
        CP (IX+DOWN_PROB)
        JR NC,PR_COLOR_ALIEN
        INC D
        LD (ALIEN_COORDS),DE
        LD A,D
        CP 16 ; landing?
        JR NZ,PR_COLOR_ALIEN
        CALL EXPLOSION

        ; Decrement the shield

        XOR A
        CALL CHAN_OPEN
        LD A,(SHIELD)
        DEC A
        LD (SHIELD),A
        LD D,1
        LD E,A
        CALL AT
        LD A," "
        RST #10
        LD A,2
        CALL CHAN_OPEN
        LD A,(SHIELD)
        AND A
        JR Z,GAME_OVER ; no shield left
        CP 6
        JR NZ,OTHER_ALIEN

        ; Almost no shield left

        LD A,SHIELD_ATTR+128 ; add flash
        CALL PR_SHIELD_BAR_A

OTHER_ALIEN
        CALL NEW_ALIEN

PR_COLOR_ALIEN
        CALL RANDOM
        AND %01000111 ; keep the bright and the ink
        OR 1 ; but make sure the ink is not black
        LD (ATTR_T),A
        CALL PR_ALIEN
        LD A,ATTR
        LD (ATTR_T),A

AIM
        CALL KEYS
        CALL FIRE

; Hold

        CALL KEY_0
        JR NZ,RESUME
HOLD_OFF
        CALL KEY_0
        JR Z,HOLD_OFF
HOLD
        CALL KEY_0
        JR NZ,HOLD
HOLD_OFF_2
        CALL KEY_0
        JR Z,HOLD_OFF_2

RESUME
        LD BC,2500
DELAY
        DEC BC
        LD A,B
        OR C
        JR NZ,DELAY

        JP MAIN

; *************************************************************
; Game over

GAME_OVER
        LD DE,(SCORE)
        LD BC,(RECORD)
        LD A,B
        CP D
        JR C,NEW_RECORD
        JR NZ,INVASION
        LD A,E
        CP C
        JR NC,INVASION
NEW_RECORD
        LD (RECORD),DE
        CALL OVER_0
        CALL PR_RECORD

; *************************************************************
; Invasion

INVASION

        CALL OVER_1
        CALL PR_AIM ; erase the aim

        LD A,%00000001 ; blue ink
        CALL CL_ATTR_A
        CALL EXPLOSION_DELAY

        CALL RANDOM
        AND %00000111 ; max 7 explosions
        OR %00000100 ; min 4
        LD B,A

FINAL_EXPLOSION
        PUSH BC
        CALL EXPLOSION_DELAY
        LD A,%01000111 ; bright, white ink
        CALL CL_ATTR_A
        CALL EXPLOSION
        LD A,%00000001 ; blue ink
        CALL CL_ATTR_A
        POP BC
        DJNZ FINAL_EXPLOSION

        CALL EXPLOSION_DELAY
        CALL CLS
        CALL EXPLOSION_DELAY
        CALL EXPLOSION_DELAY

        JP START

; Random delay between explosions

EXPLOSION_DELAY
        PUSH BC
        CALL RANDOM
        OR %0000111
        LD B,A
EXPLOSION_DELAY_1
        PUSH BC
        LD B,8
EXPLOSION_DELAY_2
        DJNZ EXPLOSION_DELAY_2
        POP BC
        DEC BC
        LD A,B
        OR C
        JR NZ,EXPLOSION_DELAY_1
        POP BC
        RET

; *************************************************************
; Keyboard

; Is the key "0" pressed? (flag Z set if pressed)

KEY_0
        LD A,%11101111 ; keyboard semi row 6-7-8-9-0
        IN A,(#FE)
        AND %00001 ; key "0"
        RET

; Control keys

KEYS
AIM_COORDS EQU $+1
        LD DE,0

        LD A,%11101111 ; keyboard semi row 6-7-8-9-0
        IN A,(#FE)
        AND %00100 ; key "8"
        JR NZ,LEFT_KEY
        LD A,E
        CP 30 ; right limit
        JR Z,LEFT_KEY
        INC E

LEFT_KEY
        LD A,%11110111 ; keyboard semi row 5-4-3-2-1
        IN A,(#FE)
        AND %10000 ; key "5"
        JR NZ,UP_KEY
        LD A,E
        CP 1 ; left limit
        JR Z,UP_KEY
        DEC E

UP_KEY
        LD A,%11101111 ; keyboard semi row 6-7-8-9-0
        IN A,(#FE)
        AND %01000 ; key "7"
        JR NZ,DOWN_KEY
        LD A,D
        CP 2 ; up limit
        JR Z,DOWN_KEY
        DEC D

DOWN_KEY
        LD A,%11101111 ; keyboard semi row 6-7-8-9-0
        IN A,(#FE)
        AND %10000 ; key "6"
        JR NZ,KEYS_END
        LD A,D
        CP 14 ; down limit
        JR Z,KEYS_END
        INC D

KEYS_END
        LD HL,(AIM_COORDS)
        LD A,H
        CP D ; has the line changed?
        JR NZ,MOVE_AIM
        LD A,L
        CP E ; has the colum changed?
        RET Z ; return if not
        ; otherwise, go into MOVE_AIM and RET

; *************************************************************
; Aim

; Move the aim
; D = new line
; E = new column

MOVE_AIM
        PUSH DE
        CALL PR_AIM ; this erases the aim
        POP DE
        LD (AIM_COORDS),DE
        JR PR_AIM_DE ; it's faster to jump than to load DE from memory; then RET

; Print the aim

PR_AIM
        LD DE,(AIM_COORDS)
PR_AIM_DE
        PUSH DE
        DEC D
        CALL AT
        LD A,"|"
        RST #10
        POP DE
        PUSH DE
        INC D
        CALL AT
        LD A,"|"
        RST #10
        POP DE
        PUSH DE
        DEC E
        CALL AT
        LD A,"-"
        RST #10
        POP DE
        INC E
        CALL AT
        LD A,"-"
        RST #10
        RET

; Fire

FIRE
        LD DE,(ALIEN_COORDS)
        LD BC,(AIM_COORDS)
        LD A,D
        CP B ; are the lines equal?
        RET NZ
        LD A,E
        CP C ; are the columns equal?
        RET NZ

        CALL AT
        LD A,%01000010 ; bright, black paper, red ink
        LD (ATTR_T),A
        EI
        HALT
        DI
        LD A," "
        RST #10

        LD B,#FF
FIRE_1
        DJNZ FIRE_1
        CALL SHOOT
        LD A,ATTR
        LD (ATTR_T),A
        LD A,8 ; backspace
        RST #10
        LD A,(IX+GRAPHIC)
        RST #10

        LD B,0
        LD C,(IX+POINTS)
        LD HL,(SCORE)
        AND A
        ADC HL,BC
        LD DE,(ALIEN_COORDS)
        LD E,D
        LD D,0
        AND A
        SBC HL,DE
        LD (SCORE),HL
        CALL OVER_0
        CALL PR_SCORE
        CALL OVER_1
        CALL NEW_ALIEN
        JP PR_ALIEN ; and RET

; *************************************************************
; Scenery

; Print the scenery

SCENERY
        CALL CLS

        XOR A ; black paper, black ink
        CALL CL_ATTR_A
        CALL SET_ATTR_A

        CALL STARS
        CALL FIELD

        ; Prith the status line

        CALL PR_SCORE
        CALL PR_RECORD
        CALL BRIGHT_1
        CALL PR_SHIELD
        CALL BRIGHT_0

        ; Color the sky and the field

        LD A,%00000111 ; black paper, white ink
        LD HL,ATTRS+32 ; from the second line
        LD DE,ATTRS+32+1
        LD BC,22*32-1 ; 21 lines
        LD (HL),A
        LDIR
if 0 ; not used any more
        ; Color the status line
        ;LD A,%01111000 ; bright, white paper, black ink
        LD A,%01000111 ; bright, black paper,white ink
        LD HL,ATTRS ; from the top left character
        LD DE,ATTRS+1
        LD BC,1*32-1 ; one line
        LD (HL),A
        LDIR
endif
        JP SET_ATTR ; set the standard attribute and RET

; Print the stars

STARS
        LD B,255 ; stars
STAR
        PUSH BC
RANDOM_Y
        CALL RANDOM
        CP 51 ; min Y coordinate
        JR C,RANDOM_Y
        CP 166 ; max Y coordinate
        JR NC,RANDOM_Y
        PUSH AF
        CALL RANDOM
        LD C,A
        POP AF
        LD B,A
        CALL PLOT_SUB
        POP BC
        DJNZ STAR
        RET

; Print the field

FIELD
        LD BC,0
        CALL PLOT_SUB
        LD C,97
        LD B,50
        LD E,1
        LD D,1
        CALL DRAW
        LD C,255
        LD B,0
        CALL PLOT_SUB
        LD C,97
        LD B,50
        LD E,255
        LD D,1
        CALL DRAW
        LD C,137
        LD B,50
        CALL PLOT_SUB
        LD C,50
        LD B,50
        LD E,1
        LD D,255
        CALL DRAW
        LD C,117
        LD B,50
        CALL PLOT_SUB
        LD C,50
        LD B,50
        LD E,255
        LD D,255
        CALL DRAW
        LD C,127
        LD B,50
        CALL PLOT_SUB
        LD C,0
        LD B,50
        LD E,1
        LD D,255
        CALL DRAW
        LD B,50
        CALL H_LINE
        LD B,47
        CALL H_LINE
        LD B,42
        CALL H_LINE
        LD B,35
        CALL H_LINE
        LD B,24
        CALL H_LINE
        LD B,25
        CALL H_LINE
        LD B,12
        CALL H_LINE
        LD B,11
        CALL H_LINE
        LD B,10

; Draw a horizontal line
; B = Y coordinate

H_LINE
        LD C,0
        CALL PLOT_SUB
        LD C,255
        LD B,0
        LD E,1
        LD D,1
        CALL DRAW
        RET

; *************************************************************
; Screen routines

; Clear the screen

CLS
        XOR A
        OUT (#FE),A
        LD (BORDER),A
        LD HL,VIDEO
        LD DE,VIDEO+1
        LD BC,BITMAP_LENGHT-1
        LD (HL),A
        LDIR

        CALL OVER_0
        CALL SET_ATTR

; Set the attributes to A

CL_ATTR_A
        LD HL,ATTRS
        LD DE,ATTRS+1
        LD BC,ATTRS_LENGHT-1
        LD (HL),A
        LDIR
        RET

; Set the default attribute

SET_ATTR
        LD A,ATTR
SET_ATTR_A
        LD (ATTR_P),A
SET_ATTR_T_A
        LD (ATTR_T),A
        RET

; Graphic over

OVER_0
        LD A,(P_FLAG)
        AND %11111100
        JR SET_P_FLAG
OVER_1
        LD A,(P_FLAG)
        OR %00000011
SET_P_FLAG
        LD (P_FLAG),A
        RET

if 0 ; not used

; Graphic flash

FLASH_0
        LD A,(ATTR_T)
        AND %01111111
        JR SET_ATTR_T_A
FLASH_1
        LD A,(ATTR_T)
        OR %10000000
        JR SET_ATTR_T_A

endif

; Graphic bright 

BRIGHT_0
        LD A,(ATTR_T)
        AND %10111111
        JR SET_ATTR_T_A
BRIGHT_1
        LD A,(ATTR_T)
        OR %01000000
        JR SET_ATTR_T_A

; Clear the menu

CLEAR_MENU
        LD D,MENU_LINE
        CALL CLEAR_MENU_LINE
        LD D,MENU_LINE+2
        CALL CLEAR_MENU_LINE
        LD D,MENU_LINE+4
        CALL CLEAR_MENU_LINE
        LD D,MENU_LINE+6
        CALL CLEAR_MENU_LINE
        LD D,MENU_LINE+9
        CALL CLEAR_MENU_LINE
        LD D,MENU_LINE+10
        CALL CLEAR_MENU_LINE
        LD D,MENU_LINE+11

CLEAR_MENU_LINE
        LD E,MENU_INDENT
        CALL AT
        LD DE,BL_OPTION_TXT
        LD BC,BL_OPTION_LEN
        JP PR_STRING

; Print the record

PR_RECORD
        LD DE,#000F
        CALL PR_STATUS_ATTR
        LD HL,RECORD_TXTS
        CALL PR_LANGUAGE_STRING
RECORD  EQU $+1
        LD BC,0
        JR PR_NUMBER

; Print the score

PR_SCORE
        LD DE,#0000
        CALL PR_STATUS_ATTR
        LD HL,SCORE_TXTS
        CALL PR_LANGUAGE_STRING
SCORE   EQU $+1
        LD BC,0

; Print the number in BC

PR_NUMBER
        CALL STACK_BC
        CALL PRINT_FP
        LD A,INVERSE_CHR ; inverse...
        RST #10
        LD A,0 ; ...off
        RST #10
        LD A,BRIGHT_CHR ; bright...
        RST #10
        LD A,0 ; ...off
        RST #10
        RET

; Print the attributes of score and record

PR_STATUS_ATTR
        ; DE = coords
        CALL AT
        LD DE,STATUS_ATTR_TXT
        LD BC,STATUS_ATTR_LEN
        JP PR_STRING ; print the string and RET

; Print the shield

PR_SHIELD

        LD A,SHIELD_ATTR
PR_SHIELD_BAR_A
        LD HL,ATTRS + 32*23 ; first attribute's address of the 24th line
        LD DE,ATTRS + 32*23 + 1
SHIELD  EQU $+1
        LD BC,MAX_SHIELD
        DEC BC ; needed in order to store the shield in the former opcode, what is needed in order to preserve A and let the PR_SHIELD entry
        LD (HL),A
        LDIR

PR_SHIELD_TXT

        XOR A
        CALL CHAN_OPEN
        LD A,ATTR
        LD (BORDER),A
        LD DE,0
        CALL AT
        LD HL,SHIELD_TXTS
        CALL PR_LANGUAGE_STRING
        LD A,2
        JP CHAN_OPEN ; and RET

; Print the current language in the menu

PR_LANGUAGE
        CALL AT_LANGUAGE
        LD DE,BL_OPTION_TXT
        LD BC,BL_OPTION_LEN
        CALL PR_STRING
        CALL AT_LANGUAGE
        LD HL,LANGUAGE_TXTS

; Print a message depending on the language

        ; HL = address of the text table

PR_LANGUAGE_STRING
LANGUAGE EQU PR_LANGUAGE_STRING+1
        LD A,DEFAULT_LANGUAGE
        LD B,A
        ADD A,B
        ADD A,B ; every element in the table has 3 bytes, so A=A*3
        LD B,0
        LD C,A ; offset into BC
        ADD HL,BC ; point to the text start
        LD (TO_DE),HL
TO_DE   EQU $+2
        LD DE,(0)
        INC HL ; point...
        INC HL ; ...to the text length
        LD A,(HL)
        LD C,A
        JP PR_STRING ; print the string and RET

; Set the cursor at the name of the language in the main menu

AT_LANGUAGE
        LD DE,LANGUAGE_LINE*256+MENU_INDENT

; Set the cursor (coords in D and E)

AT
        LD A,AT_CHR
        RST #10
        LD A,D
        RST #10
        LD A,E
        RST #10
        RET

; *************************************************************
; Alien

; New alien

NEW_ALIEN
        CALL RANDOM
        AND %00011111 ; mask the random column (0-31)
        LD E,A
        LD D,1 ; line
        LD (ALIEN_COORDS),DE

        CALL RANDOM
        CP 64
        JR NC,NEW_ALIEN_2
        LD IX,ALIEN_1
        RET
NEW_ALIEN_2
        CP 128
        JR NC,NEW_ALIEN_3
        LD IX,ALIEN_2
        RET
NEW_ALIEN_3
        CP 192
        JR NC,NEW_ALIEN_4
        LD IX,ALIEN_3
        RET
NEW_ALIEN_4
        LD IX,ALIEN_4
        RET

; Print alien

PR_ALIEN
ALIEN_COORDS EQU $+1
        LD DE,0
        CALL AT
        LD A,(IX+GRAPHIC)
        RST #10
        RET


; *************************************************************
; Sound

; Landing

SHOOT
        LD B,5
SHOOT_1
        PUSH BC
        LD HL,#0300
SHOOT_2
        LD DE,1
        PUSH HL
        PUSH IX
        CALL #03BC ; point of the BEEPER ROM routine (#03B5)
        DI
        POP IX
        POP HL
        LD DE,16
        AND A
        SBC HL,DE
        JR NZ,SHOOT_2
        POP BC
        DJNZ SHOOT_1
        RET

; Explosion

EXPLOSION
        PUSH AF
        PUSH BC
        PUSH HL
        LD HL,2000
        LD B,0
        LD E,20
EXPLOSION_1
        PUSH BC
        LD A,(BORDER)
        SRL A
        SRL A
        SRL A
        SET 4,A
        OUT (#FE),A
        LD B,(HL)
EXPLOSION_2
        NOP
        NOP
        NOP
        DJNZ EXPLOSION_2
        RES 4,A
        OUT (#FE),A
        LD B,(HL)
EXPLOSION_3
        NOP
        NOP
        NOP
        DJNZ EXPLOSION_3
        LD B,E
EXPLOSION_4
        NOP
        NOP
        NOP
        NOP
        DJNZ EXPLOSION_4
        INC E
        INC HL
        POP BC
        DJNZ EXPLOSION_1
        POP HL
        POP BC
        POP AF
        RET

; *************************************************************
; Random

; Return a pseudo-random byte (0-255) in A

RANDOM
        PUSH HL
        PUSH BC
        LD A,(SEED)
        LD B,A
        LD A,(FRAMES)
        LD C,A
        LD A,R
        ADD A,B
        ADD A,C
        ;LD HL,509 ; ROM address with the higher number of different values (166) in 256 bytes
        LD HL,13990 ; ROM address pointing to 256 misc values; somehow its result is better
        LD B,0
        LD C,A
        ADC HL,BC
        LD A,(HL)
        LD (SEED),A
        POP BC
        POP HL
        RET

; *************************************************************
; User Defined Graphics

ALIEN_UDGS

        DEFB %00100001
        DEFB %01100011
        DEFB %11101011
        DEFB %11110111
        DEFB %11111111
        DEFB %11101011
        DEFB %01100011
        DEFB %00100001

        DEFB %01000010
        DEFB %10000001
        DEFB %10011001
        DEFB %11100111
        DEFB %10111101
        DEFB %10011001
        DEFB %10000001
        DEFB %01000010

        DEFB %10000100
        DEFB %11000110
        DEFB %11010111
        DEFB %11101111
        DEFB %11111111
        DEFB %11010111
        DEFB %11000110
        DEFB %10000100

; *************************************************************
; Alien's data

; Field offsets

GRAPHIC         EQU 0 ; alien's UDG number
GLIDE_DIR       EQU 1 ; glide direction degree: 0 (left)...center (127)...rigth (255)
DOWN_PROB       EQU 2 ; probability of the alien going down (0...255) (landing speed)
MOVE_PROB       EQU 3 ; probability of the alien moving (0...255) (general activity)
POINTS          EQU 4 ; points got when the alien is destroyed

; Data

ALIEN_1 DEFB 146 ; UDG
        DEFB 0 ; left gliding
        DEFB 55 ; landing speed
        DEFB 50 ; move probability
        DEFB 100 ; points

ALIEN_2 DEFB 145 ; UDG
        DEFB 127 ; vertical gliding
        DEFB 250 ; landing speed
        DEFB 50 ; move probability
        DEFB 200 ; points

ALIEN_3 DEFB 145 ; UDG
        DEFB 127 ; vertical gliding
        DEFB 20 ; landing speed
        DEFB 200 ; move probability
        DEFB 200 ; points

ALIEN_4 DEFB 144 ; UDG
        DEFB 255 ; right gliding
        DEFB 55 ; landing speed
        DEFB 50 ; move probability
        DEFB 100 ; points

; *************************************************************
; Texts

LANGUAGE_LINE   EQU 17

LANGUAGE_TXTS   DEFW LANGUAGE_EN_TXT
                DEFB LANGUAGE_EN_LEN
                DEFW LANGUAGE_EO_TXT
                DEFB LANGUAGE_EO_LEN
                DEFW LANGUAGE_ES_TXT
                DEFB LANGUAGE_ES_LEN
LANGUAGE_EN_TXT DEFM "Not in English"
LANGUAGE_EN_LEN EQU $-LANGUAGE_EN_TXT
LANGUAGE_EO_TXT DEFM "Ne en Esperanto"
LANGUAGE_EO_LEN EQU $-LANGUAGE_EO_TXT
LANGUAGE_ES_TXT DEFM "No en castellano"
LANGUAGE_ES_LEN EQU $-LANGUAGE_ES_TXT

BL_OPTION_TXT   DEFM "                "
BL_OPTION_LEN   EQU $-BL_OPTION_TXT

STATUS_ATTR_TXT
                DEFB PAPER_CHR,0
                DEFB INK_CHR,7
                DEFB BRIGHT_CHR,1
STATUS_ATTR_LEN EQU $-STATUS_ATTR_TXT

SCORE_TXTS      DEFW SCORE_EN_TXT
                DEFB SCORE_EN_LEN
                DEFW SCORE_EO_TXT
                DEFB SCORE_EO_LEN
                DEFW SCORE_ES_TXT
                DEFB SCORE_ES_LEN
SCORE_EN_TXT    DEFM "Score "
SCORE_EN_LEN    EQU $-SCORE_EN_TXT
SCORE_EO_TXT    DEFM "Poentoj "
SCORE_EO_LEN    EQU $-SCORE_EO_TXT
SCORE_ES_TXT    DEFM "Puntos "
SCORE_ES_LEN    EQU $-SCORE_ES_TXT

RECORD_TXTS     DEFW RECORD_EN_TXT
                DEFB RECORD_EN_LEN
                DEFW RECORD_EO_TXT
                DEFB RECORD_EO_LEN
                DEFW RECORD_ES_TXT
                DEFB RECORD_ES_LEN
RECORD_EN_TXT   DEFM "Record "
RECORD_EN_LEN   EQU $-RECORD_EN_TXT
RECORD_EO_TXT   DEFM "Rikordo "
RECORD_EO_LEN   EQU $-RECORD_EO_TXT
RECORD_ES_TXT   DEFM "Marca "
RECORD_ES_LEN   EQU $-RECORD_ES_TXT

SHIELD_TXTS     DEFW SHIELD_EN_TXT
                DEFB SHIELD_EN_LEN
                DEFW SHIELD_EO_TXT
                DEFB SHIELD_EO_LEN
                DEFW SHIELD_ES_TXT
                DEFB SHIELD_ES_LEN
SHIELD_EN_TXT   DEFM "Shield:"
SHIELD_EN_LEN   EQU $-SHIELD_EN_TXT
SHIELD_EO_TXT   DEFB 96
                DEFM "irmilo:"
SHIELD_EO_LEN   EQU $-SHIELD_EO_TXT
SHIELD_ES_TXT   DEFM "Escudo:"
SHIELD_ES_LEN   EQU $-SHIELD_ES_TXT

KEYS_INDENT     EQU 7
KEYS_TXT        DEFB AT_CHR,MENU_LINE,KEYS_INDENT
                DEFM "5"
                DEFB AT_CHR,MENU_LINE+2,KEYS_INDENT
                DEFM "6"
                DEFB AT_CHR,MENU_LINE+4,KEYS_INDENT
                DEFM "7"
                DEFB AT_CHR,MENU_LINE+6,KEYS_INDENT
                DEFM "8"
                DEFB AT_CHR,MENU_LINE+9,KEYS_INDENT
                DEFM "0"
                DEFB AT_CHR,LANGUAGE_LINE,KEYS_INDENT
                DEFM "L"
KEYS_LEN        EQU $-KEYS_TXT

MENU_TXTS       DEFW MENU_EN_TXT
                DEFB MENU_EN_LEN
                DEFW MENU_EO_TXT
                DEFB MENU_EO_LEN
                DEFW MENU_ES_TXT
                DEFB MENU_ES_LEN

MENU_LINE       EQU 4
MENU_INDENT     EQU 10

MENU_EN_TXT     DEFB AT_CHR,MENU_LINE,MENU_INDENT
                DEFM "Left"
                DEFB AT_CHR,MENU_LINE+2,MENU_INDENT
                DEFM "Down"
                DEFB AT_CHR,MENU_LINE+4,MENU_INDENT
                DEFM "Up"
                DEFB AT_CHR,MENU_LINE+6,MENU_INDENT
                DEFM "Right"
                DEFB AT_CHR,MENU_LINE+9,MENU_INDENT
                DEFM "Play/"
                DEFB AT_CHR,MENU_LINE+10,MENU_INDENT
                DEFM "Halt/"
                DEFB AT_CHR,MENU_LINE+11,MENU_INDENT
                DEFM "Continue"
MENU_EN_LEN     EQU $-MENU_EN_TXT

MENU_EO_TXT     DEFB AT_CHR,MENU_LINE,MENU_INDENT
                DEFM "Maldekstre"
                DEFB AT_CHR,MENU_LINE+2,MENU_INDENT
                DEFM "Malsupre"
                DEFB AT_CHR,MENU_LINE+4,MENU_INDENT
                DEFM "Supre"
                DEFB AT_CHR,MENU_LINE+6,MENU_INDENT
                DEFM "Dekstre"
                DEFB AT_CHR,MENU_LINE+9,MENU_INDENT
                DEFM "Ludi/"
                DEFB AT_CHR,MENU_LINE+10,MENU_INDENT
                DEFM "Haltigi/"
                DEFB AT_CHR,MENU_LINE+11,MENU_INDENT
                DEFM "Pluigi"
MENU_EO_LEN     EQU $-MENU_EO_TXT

MENU_ES_TXT     DEFB AT_CHR,MENU_LINE,MENU_INDENT
                DEFM "Izquierda"
                DEFB AT_CHR,MENU_LINE+2,MENU_INDENT
                DEFM "Abajo"
                DEFB AT_CHR,MENU_LINE+4,MENU_INDENT
                DEFM "Arriba"
                DEFB AT_CHR,MENU_LINE+6,MENU_INDENT
                DEFM "Derecha"
                DEFB AT_CHR,MENU_LINE+9,MENU_INDENT
                DEFM "Jugar/"
                DEFB AT_CHR,MENU_LINE+10,MENU_INDENT
                DEFM "Detener/"
                DEFB AT_CHR,MENU_LINE+11,MENU_INDENT
                DEFM "Continuar"
MENU_ES_LEN     EQU $-MENU_ES_TXT

TITLE_TXT       DEFB AT_CHR,0,5
                DEFB BRIGHT_CHR,1
                DEFM "A  L  I  E  N   -   A"
                DEFB AT_CHR,20,4
                DEFB 127 ; copyright character
                DEFM " 1986, 2010 Marcos Cruz"
                DEFB AT_CHR,21,4
                DEFM "http://programandala.net"
                DEFB BRIGHT_CHR,0
TITLE_LEN       EQU $-TITLE_TXT

; *************************************************************
; Character set

        IF OWN_CHARSET
CHAR_SET        INCBIN alien-a_charset.bin
        ENDIF

; *************************************************************

        END ENTRY ; set the entry point

Downloads

Executable files

Tape formats:

Snaphot formats:

Source code and character set

Related pages

Alien-B
Invaders game written in Beta BASIC for ZX Spectrum 128.