Alien-A

Descripción del contenido de la página

Juego de invasores escrito en Z80 para la Sinclair ZX Spectrum.

Etiquetas:

Escribí Alien-A en 1986, como un ejercicio para hacer una versión mejorada en Z80 de un juego escrito en Sinclair BASIC. El juego original en que me inspiré (3.47 KiB), anónimo, apareció publicado en el año 1983, en las páginas 14 y 15 del primer número de la revista ZX:

página 14 de ZX 1 (190.87 KiB) página 15 de ZX 1 (209.71 KiB)

En mi versión mantuve los gráficos de un carácter y el movimiento por líneas y columnas; en ese sentido no me compliqué nada. Sin embargo cambié casi por completo el desarrollo del juego, hasta el punto de que lo único que quedó del original fue el paisaje y la forma de la mirilla.

En 2010, para publicar el programa en programandala.net, rescaté el código fuente original, que conservaba en un fichero TAP en el formato del ensamblador GENS3, y con unas sencillas manipulaciones con ayuda del editor Vim convertí el fichero TAP original en un fichero de texto preparado para ser compilado con Pasmo. Mi intención sólo era facilitar la publicación del programa, pero cuando tuve entre mis manos (mejor dicho entre mis teclas) el código fuente en un formato «moderno» no pude resistirme a hacerle una mejora tras otra al juego...

Después de veinticuatro años, le dediqué a Alien-A varias horas de concentración y diversión, a lo largo de un mes. Fue un reencuentro muy agradable con Z80, lenguaje de programación que me gusta mucho y en el que casi no había escrito durante años.

Pantallazos

El menú de inicio puede mostrarse en tres lenguas: castellano, esperanto e inglés. Se me ocurrió que la manera más fácil de cambiar de lengua, con una sola tecla, era llamar a la opción del menú «No en X», siendo «X» la lengua actual:

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

Las siguientes pantallas muestran los diferentes tipos de naves que intentan aterrizar, con los rótulos en las tres lenguas:

Nave hacia la izquierdaNave hacia abajoNave hacia la derecha

Código fuente

; *************************************************************
; 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

Descargas

Ejecutables

Dos formatos de cinta:

Dos formatos de instantánea:

Código fuente y juego de caracteres

Páginas relacionadas

Alien-B
Juego de invasores escrito en Beta BASIC para ZX Spectrum 128.