Now Reading
Viboritas recreation in 2K made in 1990

Viboritas recreation in 2K made in 1990

2024-02-06 23:29:56

Viboritas updated in action

I had utterly forgotten about this recreation, however luckily I made backups of my floppy disks for historic report. Not too long ago, I regarded on the floppy disk backup index, and I discovered issues as previous as 1989, and a reputation caught my consideration: Viboritas (Spanish for little snakes).

This recreation was coded round 1990, printed, and later saved onto a 5 1/4″ floppy disk, then copied once more onto a 3 1/2″ floppy disk by 1992 when these turned mainstream (the picture I discovered), and at last, it was again up round 2011. These backups survived by luck a number of onerous drive crashes until we attain 2024.

I opened the file, extracted the 2K binary, and reminiscences began coming slowly. I even caught a 34 year-old bug.

The historical past

1990 homebrew computer for students

After doing my first game in Z80 assembler in 1988, I obtained quite a lot of confidence in my skills and went to do a number of different Z80 packages. Nonetheless, I lacked entry to a correct assembler program, and as an alternative, I coded straight into machine code utilizing a monitor-style program similar to proven within the image on the proper, you possibly can even see the Z80 code being typed!

A monitor program was a small software within the ROM of the pc the place you had some fundamental instructions like reminiscence itemizing, writing to reminiscence, and executing your program. Some extras have been exit factors in your program to indicate the contents of the Z80 registers and flags.

My father gave once more a lecture about laptop constructing in 1990, and I showcased my Karateka game, however I needed to do one thing higher. I used to be 11 years previous, about to turn out to be a teen, and I had an excellent creativeness about spectacular video games.

My growth setting for this recreation was a homebrew laptop for college students with a keyboard, a TV for show, and a set of sheets from Zilog with the Z80 mnemonics and respective machine code.

The specs for this homebrew laptop have been a Zilog Z80 CPU, 2K of EPROM, 2K of RAM, a TMS9118 VDP, and a Commodore keyboard. You would plug in an growth board with an AY-3-8910 sound chip that fed from the Z80 clock. The VDP chip, AY chip, and keyboard have been available due to the 1984 crash.

Students working in the 1990 homebrew computer

College students working within the homebrew laptop. You may see a younger @nanochess within the entrance proper. Dec/1990.

Into the binary

On the time, I used to be very impressed by my favourite journal: Enter MSX, on this case challenge 12, containing screenshots of a recreation known as Future Knight, and I used to be in awe imagining how nice was it by the screenshots and cover art (later I found it’s a fairly boring recreation). In the identical challenge, there was a BASIC language recreation known as “El Castillo Embrujado” that I already had ported to the BASIC language obtainable in one other homebrew laptop constructed by my father.

For this mission, I needed to do a science fiction recreation in 2K, the place the participant would use ladders, keep away from enemies, and… I had no extra. However I used to be impressed by the ton of ladders in Future Knight. I did not know what measurement coding was, however I put the 2K restrict in my thoughts, and the opposite goal was that the sport must be coded straight into the coed’s laptop, now most often called coding in the true {hardware}.

I did not envision a ultimate for the sport, nor a historical past, or perhaps a gameplay. In spite of everything, I solely needed to have enjoyable creating video games, and naturally, showcase my recreation to the scholars. Discover that having enjoyable creating video games is not the identical as creating enjoyable video games.

I feel that that is my third recreation in machine code for Z80 processors. The binary got here from a 1992 demo disk for college students, however it was initially coded in 1990. I solely extracted the 2K of the sport from the 720K disk picture.

The binary of the sport seems to be like this:

Part of the original binary of Viboritas

Given the lack of know-how about it, I must reverse-engineer my very own recreation! The primary cross was to completely disassemble it. It sized as much as simply over one thousand strains of Z80 assembler code however extra simply learn trying like this:


            ORG $8000

        FNAME "viboritas.bin"

L04CC:      EQU $04CC
L0100:      EQU $0100
L0169:      EQU $0169
L0447:      EQU $0447

L8000:      CALL L04CC
            CALL L801B
            CALL L81BA
L8009:      CALL L8217
L800C:      CALL L8324
            CALL L8504
            JR NC,L800C
L8014:      LD HL,L87FC
            INC (HL)
            JP L8009

I separated the ROM calls, and I do not keep in mind if I’ve a replica of this laptop ROM, however I nonetheless keep in mind the operate of every name (these are the identical as in my first Z80 recreation). L0100 units a VDP handle (for VRAM or VDP registers), L0169 reads forward to ship knowledge to VRAM, L04CC cleans the display screen, and L0447 reads the keyboard. A factor that modified between 1988 and 1990 computer systems was the port numbers for the VDP.

I made positive the disassembled itemizing assembles the identical binary as the unique. Then I began individually the difference for the MSX computer systems and Colecovision consoles, each having the identical video processor, so you possibly can play the sport. Simply do not anticipate an excessive amount of from a child.

First steps

For starters, I am going to reuse the interpretation layer I made for my Karateka game in Z80 assembler. It can assist us to play this previous recreation on an MSX or Colecovision.

	;
	; Viboritas (little snakes)
	;
	; by Oscar Toledo G.
	; (c) Copyright Oscar Toledo G. 1990-2024
	; https://nanochess.org/
	;
	; Creation date: Oct/1990. I used to be 11 years previous.
	; Revision date: Jan/31/2024. Disassembled.
	; Revision date: Feb/01/2024. Ported to MSX/Colecovision.
	;

COLECO: EQU 1   ; Outline this to 0 for MSX, 1 for Colecovision

RAM_BASE:	EQU $E000-$7000*COLECO
VDP:		EQU $98+$26*COLECO

PSG:	EQU $FF	; Colecovision

PSG_ADDR:	EQU $A0	; MSX
PSG_DATA:	EQU $A1	; MSX

KEYSEL:	EQU $80
JOYSEL:	EQU $C0
JOY1:	EQU $FC
JOY2:	EQU $FF

    if COLECO
        fname "viboritas_cv.ROM"

	org $8000,$9fff

	dw $aa55	; No BIOS title display screen
	dw 0
	dw 0
	dw 0
	dw 0
	dw START

	jp 0		; RST $08
	jp 0		; RST $10
	jp 0		; RST $18
	jp 0		; RST $20
	jp 0		; RST $28
	jp 0		; RST $30
	jp 0		; RST $38

	jp 0		; No NMI handler

    else
        fname "viboritas_msx.ROM"

	org $4000,$5fff

	dw $4241
	dw START
	dw 0
	dw 0
	dw 0
	dw 0
	dw 0
	dw 0

WRTPSG: equ $0093
SNSMAT:	equ $0141

    endif

WRTVDP:
	ld a,b
	out (VDP+1),a
	ld a,c
	or $80
	out (VDP+1),a
	ret

SETWRT:
	ld a,l
	out (VDP+1),a
	ld a,h
	or $40
	out (VDP+1),a
	ret

WRTVRM:
	push af
	name SETWRT
	pop af
	out (VDP),a
	ret

FILVRM:
	push af
	name SETWRT
.1:	pop af
	out (VDP),a
	push af
	dec bc
	ld a,b
	or c
	jp nz,.1
	pop af
	ret

	; Setup VDP earlier than recreation
setup_vdp:
	LD BC,$0200
	CALL WRTVDP
	LD BC,$C201	; No interrupts
	CALL WRTVDP
	LD BC,$0F02	; $3C00 for sample desk
	CALL WRTVDP
	LD BC,$FF03	; $2000 for colour desk
	CALL WRTVDP
	LD BC,$0304	; $0000 for bitmap desk
	CALL WRTVDP
	LD BC,$3605	; $1b00 for sprite attribute desk
	CALL WRTVDP
	LD BC,$0706	; $3800 for sprites bitmaps
	CALL WRTVDP
	LD BC,$0407	; Blue border
	CALL WRTVDP
    IF COLECO
	LD HL,($006C)   ; MSX BIOS chars
	LD DE,-128
	ADD HL,DE
    ELSE
	LD HL,($0004)   ; MSX BIOS chars
	INC H
    ENDIF
        PUSH HL
        LD DE,$0100
        LD BC,$0300
        CALL LDIRVM
        POP HL
        PUSH HL
        LD DE,$0900
        LD BC,$0300
        CALL LDIRVM
        POP HL
        LD DE,$1100
        LD BC,$0300
        CALL LDIRVM

        LD HL,$2000
        LD BC,$1800
        LD A,$F4
        CALL FILVRM
	RET

LDIRVM:
        EX DE,HL
.1:     LD A,(DE)
        CALL WRTVRM
        INC DE
        INC HL
        DEC BC
        LD A,B
        OR C
        JR NZ,.1
        RET

GTTRIG:
    if COLECO
        out (KEYSEL),a
        ex (sp),hl
        ex (sp),hl
        in a,(JOY1)
        ld c,a
        in a,(JOY2)
        and c
        ld c,a
	out (JOYSEL),a
	ex (sp),hl
	ex (sp),hl
	in a,(JOY1)
        and c
        ld c,a
	in a,(JOY2)
	and c
	rlca
	rlca
	ccf
	ld a,0
	sbc a,a
	ret
    else
	xor a
	name $00d8
	or a
	ret nz
	ld a,1
	name $00d8
	or a
	ret nz
        ld a,2
        name $00d8
        or a
        ret nz
        ld a,3
        name $00d8
        or a
        ret nz
        ld a,4
        name $00d8
        ret
    endif

	;
	; Will get the joystick path
	; 0 - No motion
	; 1 - Up
	; 2 - Up + proper
	; 3 - Proper
	; 4 - Proper + down
	; 5 - Down
	; 6 - Down + left
	; 7 - Left
	; 8 - Left + Up
	;
GTSTCK:
    if COLECO
        out (JOYSEL),a
	ex (sp),hl
	ex (sp),hl
        in a,(JOY1)
	ld b,a
	in a,(JOY2)
	and b
        and $0f
        ld c,a
        ld b,0
        ld hl,joy_map
        add hl,bc
        ld a,(hl)
        ret

joy_map:
        db 0,0,0,6,0,0,8,7,0,4,0,5,2,3,1,0

    else
	xor a
	name $00d5
	or a
	ret nz
	ld a,1
	name $00d5
	or a
	ret nz
	ld a,2
	jp $00d5
    endif

	; ROM routines I forgot

	; Clear display screen
L04CC:	; $04cc
	LD HL,$3C00
	LD BC,$0300
	XOR A
	JP FILVRM

	; Choose handle or register in VDP
L0100:
	LD A,L
	OUT (VDP+1),A
	LD A,H
	ADD A,$40
	OUT (VDP+1),A
	RET


	; Copy string to VDP
L0169:	; $0169
	EX (SP),HL

.0:	LD A,(HL)
	INC HL
	OR A
	JR Z,.1
	PUSH AF
	POP AF
	OUT (VDP),A
	JR .0

.1:	EX (SP),HL
	RET

	;
	; Begin of the sport
	;
START:		; 8000
	DI			; We do not want interruptions.
	LD SP,L87F0
   if COLECO
	CALL $1FD6		; Flip off sound.
   endif
	CALL setup_vdp		; Not in unique however wanted to setup VDP.

	ld hl,$7513
	ld (L8780),hl
	ld hl,$983f
	ld (L8782),hl
	ld hl,$c9bf
	ld (L8784),hl

We now begin analyzing the code, making an attempt to find the way it works. We’ll go ahead and backward on the 2K reminiscence map and as I coded straight in machine code, there aren’t any names for labels besides for his or her corresponding handle within the unique binary.


L8000:      CALL L04CC	; Clear the display screen.
            CALL L801B	
            CALL L81BA	
L8009:      CALL L8217
L800C:      CALL L8324
            CALL L8504
            JR NC,L800C
L8014:      LD HL,L87FC
            INC (HL)
            JP L8009

The primary name is fairly apparent, it merely clears the display screen. Discover the unique recreation assumed the VDP was already initialized, however we already took care of it with CALL setup_vdp.

The following name L801B apparently does graphics arrange.


L801B:      LD HL,$0400	; VRAM bitmap knowledge $80 character.
            LD DE,L806A
            LD BC,$00C8
            CALL L805D
            LD HL,$2400	; VRAM colour knowledge $80 character (1st).
            LD DE,L8112
            LD BC,$001B
            CALL L8148
            LD HL,$2C00	; VRAM colour knowledge $80 character (2nd).
            LD DE,L8112
            LD BC,$001B
            CALL L8148
            LD HL,$3400	; VRAM colour knowledge $80 character (third).
            LD DE,L8112
            LD BC,$001B
            CALL L8148
            LD HL,$3800	; VRAM sprite bitmaps.
            LD DE,L8404
            LD BC,$0100
            CALL L805D
            LD HL,$4400	; Clearly a patch.
            JP L83FB

L83FB:      CALL L0100
            LD HL,$41C2
            JP L0100

The goal handle for VRAM is within the register HL, whereas the supply handle is in DE, and the byte depend is in BC. That is utterly reversed from the usual Z80 definitions for LDIR, or the MSX LDIRVM BIOS subroutine.

As I used to be coding in machine code, any mistake was a ache to right, particularly in case you wanted to insert extra directions! As you possibly can see the soar to $83FB continues setting register 4 of VDP to zero, after which proceeds to arrange register 1 of VDP for 16×16 sprites.

The VDP in high-resolution mode must have separate bitmap definitions for 3 64-pixel-high areas for a complete of 192 vertical rows. Setting the VDP register 4 is a trick for the VDP to repeat the highest bitmap into the opposite two display screen areas. I discovered this trick months in the past experimenting completely different values for VDP registers.

So we mark L801B as “Setup graphics”.

Then we have now the L805D subroutine that merely copies knowledge from the reminiscence to VRAM.


L805D:      CALL L0100
L8060:      LD A,(DE)
            OUT (VDP),A
            INC DE
            DEC BC
            LD A,B
            OR C
            JR NZ,L8060
            RET

Now I can see why I did it that method because the L0100 subroutine makes use of HL as VDP handle then it was simpler for me to have the supply knowledge pointed by the register DE. I’ve changed the unique port $B0 (VDP write) and $c0 (VDP learn) with the VDP definition for the present console (MSX or Colecovision).

It’s adopted by 200 bytes of bitmaps for the sport:


L806A:      db $FF,$FF,$FF,$FF  ; $806A
            db $FF,$FF,$FF,$FF  ; $806E
            db $E7,$E7,$E7,$E7  ; $8072
            db $E7,$E7,$E7,$E7  ; $8076
            db $FF,$FF,$00,$FF  ; $807A
            db $FF,$00,$FF,$FF  ; $807E
            db $42,$42,$7E,$42  ; $8082
            db $42,$7E,$42,$42  ; $8086
            db $FE,$82,$BA,$AA  ; $808A
            db $BA,$82,$FE,$00  ; $808E
            db $BA,$BA,$BA,$BA  ; $8092
            db $BA,$BA,$BA,$BA  ; $8096
            db $EE,$00,$FF,$FF  ; $809A
            db $FF,$00,$00,$00  ; $809E
            db $42,$42,$7E,$42  ; $80A2
            db $42,$7E,$42,$42  ; $80A6
            db $EF,$EF,$EF,$00  ; $80AA
            db $FE,$FE,$FE,$00  ; $80AE
            db $7E,$7E,$7E,$00  ; $80B2
            db $6E,$6E,$6E,$00  ; $80B6
            db $00,$FF,$FF,$AA  ; $80BA
            db $44,$00,$00,$00  ; $80BE
            db $42,$42,$7E,$42  ; $80C2
            db $42,$7E,$42,$42  ; $80C6
            db $EE,$EE,$EE,$00  ; $80CA
            db $EE,$EE,$EE,$00  ; $80CE
            db $40,$30,$0C,$03  ; $80D2
            db $0C,$30,$40,$40  ; $80D6
            db $00,$FF,$00,$AA  ; $80DA
            db $55,$00,$FF,$00  ; $80DE
            db $81,$81,$C3,$BD  ; $80E2
            db $81,$81,$C3,$BD  ; $80E6
            db $81,$58,$37,$47  ; $80EA
            db $39,$27,$49,$27  ; $80EE
            db $47,$49,$27,$40  ; $80F2
            db $28,$15,$12,$27  ; $80F6
            db $00,$FE,$FE,$00  ; $80FA
            db $EF,$EF,$00,$00  ; $80FE
            db $0C,$0C,$18,$18  ; $8102
            db $30,$30,$18,$18  ; $8106
            db $54,$FE,$54,$FE  ; $810A
            db $54,$FE,$54,$00  ; $810E

This consists of partitions, columns, ground, and ladders (4 characters for every degree), for a complete of 5 ranges, plus a sort of drain cowl. Subsequent is the colour desk for these bitmaps.


L8112:      db $08,$22,$08,$3C  ; $8112
            db $08,$A1,$08,$F1  ; $8116
            db $08,$74,$08,$E1  ; $811A
            db $01,$F1,$01,$11  ; $811E
            db $03,$E1,$03,$11  ; $8122
            db $08,$F1,$08,$6E  ; $8126
            db $08,$E1,$10,$F1  ; $812A
            db $08,$61,$08,$A1  ; $812E
            db $03,$F1,$02,$51  ; $8132
            db $03,$F1,$08,$E1  ; $8136
            db $08,$98,$08,$32  ; $813A
            db $01,$11,$06,$6E  ; $813E
            db $01,$11,$08,$31  ; $8142
            db $08,$F1  ; $8146

What is that this? This knowledge can’t be copied on to the VDP, as an alternative it seems to be like there are byte counts.


L8148:      CALL L0100
            LD B,C
L814C:      PUSH BC
            LD A,(DE)
            LD B,A
            INC DE
            LD A,(DE)
            INC DE
L8152:      OUT (VDP),A
            NOP
            DJNZ L8152
            POP BC
            DJNZ L814C
            RET

And that is proper, the child was sensible sufficient to create a decompressor that reads a depend of bytes and a byte to copy. So 73 bytes substitute 200 bytes of colour.

Bitmaps used for the level backgrounds.
Bitmaps used for the extent backgrounds alongside character quantity. Discover the order of wall, column, ground, and ladder.
Do you keep in mind I discussed “El Castillo Embrujado” from Enter MSX? At age 11 I wasn’t very assured in my graphical design skills, so for my recreation I reused the sprite graphics for the participant and the snakes. A few years later I found these graphics from “El Castillo Embrujado” have been in truth a replica from one other recreation, the well-known Abu-Simbel Profanation for ZX Spectrum.

Nonetheless, for this text I am going to assist my youthful myself designing all-new graphics. If you’re interested in it you possibly can see the earlier graphics set within the viboritas_orig.asm file.

Comparison of 1990 sprites versus updated sprites.
On the left you possibly can see the 1990 sprites and on the proper the up to date sprites.
The new sprite set for Viboritas.
The brand new sprite set for Viboritas.

	;
	; Sprites for the participant and half of the snakes.
	;
L8404:
	; $00 - Participant going proper (body 1).
	DB $00,$01,$05,$03,$07,$03,$07,$1e
	DB $37,$67,$77,$74,$03,$0e,$0e,$0f
	DB $00,$50,$f0,$f0,$d0,$70,$10,$e0
	DB $00,$b8,$b8,$00,$c0,$f8,$7c,$00
	; $04 - Participant going proper (body 2).
	DB $00,$02,$01,$03,$01,$03,$03,$07
	DB $07,$06,$06,$07,$03,$03,$03,$03
	DB $a8,$f8,$f8,$e8,$b8,$88,$70,$80
	DB $c0,$e0,$e0,$00,$c0,$00,$c0,$e0
	; $08 - Participant going left (body 1).
	DB $00,$0a,$0f,$0f,$0b,$0e,$08,$07
	DB $00,$1d,$1d,$00,$03,$07,$1e,$3e
	DB $00,$80,$a0,$c0,$e0,$c0,$e0,$78
	DB $ec,$e6,$ee,$2e,$c0,$70,$70,$f0
	; $0c - Participant going proper (body 2).
	DB $15,$1f,$1f,$17,$1d,$11,$0e,$01
	DB $03,$07,$07,$00,$03,$00,$03,$07
	DB $00,$40,$80,$c0,$80,$c0,$c0,$e0
	DB $e0,$60,$60,$e0,$c0,$c0,$c0,$c0
	; $10 - Participant utilizing ladder (body 1).
	DB $0a,$07,$0f,$0f,$07,$07,$03,$0c
	DB $1b,$70,$73,$02,$06,$06,$1e,$3e
	DB $a0,$c0,$e0,$e0,$ce,$ce,$98,$70
	DB $c0,$00,$c0,$60,$38,$3c,$00,$00
	; $14 - Participant utilizing ladder (body 2).
	DB $05,$03,$07,$07,$73,$73,$19,$0e
	DB $03,$00,$03,$06,$1c,$3c,$00,$00
	DB $50,$e0,$f0,$f0,$e0,$e0,$c0,$30
	DB $d8,$0e,$ce,$40,$60,$60,$78,$7c
	; $18 - Snake going left (body 1).
	DB $1b,$2nd,$2nd,$36,$1f,$7d,$9b,$03
	DB $0f,$1f,$3e,$3c,$3c,$3f,$1f,$0f
	DB $00,$00,$00,$00,$00,$80,$80,$82
	DB $02,$06,$06,$0e,$cc,$ec,$fc,$38
	; $1c - Snake going proper (body 2).
	DB $00,$0d,$16,$16,$1b,$0f,$1e,$5d
	DB $61,$0f,$1f,$1e,$1e,$1f,$0f,$07
	DB $00,$80,$80,$80,$00,$80,$c0,$c0
	DB $c0,$84,$0c,$cc,$d8,$f8,$b8,$30

Music participant

At this second of the evaluation, the next routine is not known as but.


L815B:      LD HL,L87FA
            INC (HL)
            LD A,(HL)
            CP $08
            JR NZ,L8194
            LD (HL),$00
            DEC HL
            INC (HL)
            LD A,(HL)
            CP $30
            JR NZ,L816F
            LD (HL),$01
L816F:      LD A,(HL)
            ADD A,255 AND (L8744-1)
            LD L,A
            LD H,(L8744-1)>>8
            CALL L8197
            NOP
            LD A,(HL)
            OUT ($80),A
            INC HL
            LD A,$01
            OUT ($00),A
            LD A,(HL)
            OUT ($80),A
            LD A,$07
            OUT ($00),A
            LD A,$B8
            OUT ($80),A
            LD A,$08
            OUT ($00),A
            LD A,$0A
            OUT ($80),A
L8194:      JP L8398

L8197:      LD A,(HL)
            ADD A,A
            ADD A,255 AND (L81A2-2)
            LD L,A
            LD H,(L81A2-2)>>8
            XOR A
            OUT ($00),A
            RET

L81A2:      dw $01ac
	    dw $0153
	    dw $011d
	    dw $00fe
	    dw $00f0
	    dw $0140
	    dw $00d6
	    dw $00be
	    dw $00b4
	    dw $00aa
	    dw $00a0
	    dw $00e2

L8744:      db $01,$02,$03,$04  ; $8744
            db $05,$04,$03,$02  ; $8748
            db $01,$02,$03,$04  ; $874C
            db $05,$04,$03,$02  ; $8750
            db $06,$04,$07,$08  ; $8754
            db $09,$08,$07,$04  ; $8758
            db $06,$04,$07,$08  ; $875C
            db $09,$08,$07,$04  ; $8760
            db $03,$0C,$08,$0A  ; $8764
            db $0B,$0A,$08,$0C  ; $8768
            db $06,$04,$07,$08  ; $876C
            db $09,$08,$07,$04  ; $8770

Okay, it increments a byte at L87FA, and when it reaches the worth 8 it’s reset to zero and proceeds to increment L87F9 till it reaches 48 when it’s reset to 1. In fact! L87F9 is the index quantity within the tune desk, and L87FA is the counter of observe length.

Then it makes use of the index to get the observe to play from L8744. Here’s a machine code trick that is not helpful when changing to assembler mnemonics: You recognize the information is mounted on the handle, so there isn’t any dealing with for carry to the upper handle byte.

Now we have now one other patch, this time calling L8197 to get the observe frequency to play, after which it writes to the AY-3-8910 sound chip. The $00 port handle units the AY-3-8910 index register, and the $80 port handle units the AY-3-8910 knowledge register. It even units the register 7 of PSG to $38 to disable white noise, and this worth can burn for actual some MSX1 computer systems. Allow us to substitute the sound code:


            CALL L8197
	if COLECO
	    LD A,(HL)
	    INC HL
	    LD H,(HL)
	    LD L,A
	    AND $0F
	    OR $80
	    OUT (PSG),A
	    SRL H
	    RR L
	    SRL H
	    RR L
	    SRL H
	    RR L
	    SRL H
	    RR L
	    LD A,L
	    OUT (PSG),A
	    LD A,$93
	    OUT (PSG),A
	else
	    LD E,(HL)
	    LD A,0
	    CALL WRTPSG
	    INC HL
	    LD E,(HL)
	    LD A,1
	    CALL WRTPSG
	    LD E,$0A
	    LD A,$08
	    CALL WRTPSG
	endif
L8194:      JP L8398

L8197:      LD A,(HL)
            ADD A,A
            ADD A,255 AND (L81A2-2)
            LD L,A
            LD H,(L81A2-2)>>8
            RET

Additionally at first look, I assumed this routine was written first, however then I spotted it occupies the house of an uncompressed colour desk! Once I optimized the colour desk definition to make use of compression, I added the tune participant within the freed house!

This implies the primary model of my recreation did not have any music, and there is a probability that someplace in my information exists a printout. And I simply remembered a factor: I coded the sport with out music, and a scholar had a background in music, and he handed me some musical notes that I applied terribly as a result of I did not know something about music timing.

The music is a rendition of a boogie-woogie. The music participant nonetheless goes on, and there’s a very bizarre patch leaping at L8398. However we’ll see it later, because it seems to be just like the keyboard code.

Initialization

Now we go to the subsequent unexplored code at L81BA:


L81BA:      XOR A
            LD (L87F3),A
            LD (L87F4),A
            LD (L87F7),A
            LD (L87F8),A
            LD A,$F0
            LD (L87F5),A
            LD A,$01
            LD (L87F6),A
            LD A,$0F
            LD (L8786),A
            LD A,$00
            LD (L8787),A
            LD HL,$0000
            LD (L87F9),HL
            LD A,$02
            LD (L87FB),A
            CALL L04CC
            LD HL,$3EE9
            CALL L0100
            CALL L0169
            db "(C) OTEK 1990",0
            LD HL,$3EAC
            CALL L0100
            CALL L0169
            db "VIDAS:0",0
            LD A,$01
            JP L82A5

That is trying like an initialization code (allow us to add a observe to L81BA as recreation initialization).

We’ll uncover the operate of every variable quickly. Thus far it cleans once more the display screen, units up the VDP to the final row of the display screen, and reveals the copyright message. OTEK comes from my father’s initials (Oscar Toledo Esteva) which we used as a sort of firm title.

Additionally, it reveals the variety of remaining lives (VIDAS in Spanish), and… one other patch jumps to L82A5.


L82A5:      LD (L87FC),A
            XOR A
            LD (L87FE),A
            LD (L87FF),A
            RET

It’s merely some extra variable initialization.

Display screen drawing

Now one other routine L8217 that known as instantly after in L8009:


L8217:      LD A,(L87FC)
            ADD A,A
            ADD A,A
            ADD A,$7C
            LD (L87FD),A
            LD HL,$3C00
            CALL L0100
            LD B,$A0
L8229:      PUSH BC
            LD B,$03
L822C:      LD A,(L87FD)
            OUT (VDP),A
            INC HL
            DJNZ L822C
            LD A,(L87FD)
            INC A
            OUT (VDP),A
            INC HL
            POP BC
            DJNZ L8229
            LD HL,$3C80
            LD B,$04
L8243:      PUSH BC
            PUSH HL
            CALL L0100
            LD B,$20
L824A:      LD A,(L87FD)
            ADD A,$02
            OUT (VDP),A
            INC HL
            DJNZ L824A
            POP HL
            LD BC,$00A0
            ADD HL,BC
            POP BC
            DJNZ L8243
            LD HL,$4701
            CALL L0100
            LD HL,$2000
            CALL L8277
            LD HL,$2800
            CALL L8277
            LD HL,$3000
            CALL L8277
            JP L8288

It begins by getting a variable from L87FC, multiplying by 4, including $7c, and saving the end result at L87FD. L87FC is initialized to 1. This begins at $80, it sounds just like the character quantity for degree definition. It attracts in sequence 160 partitions (3 characters) + columns (one character), then it attracts over 4 flooring beginning at row 4 ($3c80), each 32 characters vast, utilizing the character in L87FD offset by 2.

It units the border to black ($4701), after which the bottom charset ($00-$7f characters) for the three zones of the display screen is about to black (three calls to L8277)


L8277:      LD A,H
            ADD A,$04
            LD B,A
            CALL L0100
L827E:      LD A,$F1
            OUT (VDP),A
            INC HL
            LD A,H
            CP B
            JR NZ,L827E
            RET

L8288:      LD HL,$3E5E
            CALL L0100
            LD A,$94
            OUT (VDP),A
            LD HL,$3C80
            CALL L82B0
            LD HL,$3D20
            CALL L82B0
            LD HL,$3DC0
            CALL L82B0
            RET

The L8288 patch provides the “drain” character $94 on the backside proper of the display screen. I nonetheless do not perceive why I did not simply draw a 2×2 door, however most likely I felt like there have been house constraints (defining the graphics and drawing the tiles).

On the finish, it calls 3 instances the L82B0 subroutine with completely different display screen rows as the bottom:


L82B0:      LD A,(L87FC)
            LD B,A
            LD A,$06
            SUB B
            LD B,A
L82B8:      PUSH BC
            PUSH HL
            NOP
            LD D,$00
            NOP
            CALL L82CB
            LD E,A
            ADD HL,DE
            CALL L830F
            POP HL
            POP BC
            DJNZ L82B8
            RET

This L82B0 subroutine subtracts the extent quantity from 6 and calls a subroutine L82CB to get an offset, after which L830F to do one thing.


L82CB:      PUSH BC
            PUSH DE
            PUSH HL
            LD HL,(L8780)
            LD DE,(L8782)
            LD BC,(L8784)
            ADD HL,HL
            ADD HL,HL
            ADD HL,BC
            ADD HL,DE
            LD (L8780),HL
            ADD HL,DE
            ADD HL,DE
            ADD HL,BC
            ADD HL,BC
            ADD HL,BC
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            ADD HL,DE
            ADD HL,BC
            LD (L8782),HL
            ADD HL,DE
            ADD HL,DE
            ADD HL,BC
            ADD HL,HL
            ADD HL,DE
            ADD HL,BC
            ADD HL,BC
            ADD HL,BC
            ADD HL,BC
            LD (L8784),HL
            LD HL,(L8780)
            LD DE,(L8782)
            LD BC,(L8784)
            ADD HL,DE
            ADD HL,BC
            LD A,H
            ADD A,L
            AND $1F
            POP HL
            POP DE
            POP BC
            RET

It occurs L82CB seems to be so much like a random quantity generator, and solely will get a quantity between 0 and 31 within the accumulator register.


L830F:      LD B,$05
            LD A,(L87FD)
            ADD A,$03
L8316:      PUSH AF
            CALL L0100
            POP AF
            OUT (VDP),A
            LD DE,$0020
            ADD HL,DE
            DJNZ L8316
            RET

¡Thriller solved! L830F attracts a ladder on the display screen. Every ladder is 5 rows excessive, and it’s drawn utilizing the extent base character offset by 3. Within the first degree it would draw 5 ladders on every ground, whereas within the fifth degree, it would draw just one ladder for every ground. That is an try and make harder ranges.

With all this code analyzed we will mark safely L8217 as the extent drawing code.

The hero and the foes

Now we have now the primary routine known as from the principle loop and it’s L8324:


L8324:      LD HL,$1B00
            LD A,(L8786)
            CALL L8390
            INC HL
            LD A,(L8787)
            CALL L8390
            INC HL
            LD A,(L87FE)
            CALL L8390
            INC HL
            LD A,$0F
            CALL L8390
            INC HL
            LD A,$38
            CALL L8390
            INC HL
            LD DE,L87F3
            CALL L86C5
            LD A,$0E
            CALL L8390
            INC HL
            LD A,$60
            CALL L8390
            INC HL
            LD DE,L87F5
            CALL L86C5
            LD A,$0E
            CALL L8390
            INC HL
            LD A,$88
            CALL L8390
            INC HL
            LD DE,L87F7
            CALL L86C5
            LD A,$0E
            CALL L8390
            JP L815B

L8390:      PUSH AF
            CALL L0100
            POP AF
            OUT (VDP),A
            RET

It hundreds HL with $1b00, pointing to the Sprite Attribute Desk. The VRAM place the place sprites are positioned on the display screen. And it begins studying variables and writing to VRAM utilizing L8390 (fairly just like WRTVRM of MSX)

L8786 is the Y-coordinate for the participant, L8787 is the X-coordinate for the participant, L87FE is the sprite body for the participant. The participant colour is white.

It’s simply deduced subsequent that the enemies are positioned at mounted vertical positions on the display screen ($38, $60, and $88) utilizing a generic routine L86C5. Discover additionally that it chain hyperlinks to the L815B subroutine for enjoying the background music, which in flip chain hyperlinks to the keyboard decode subroutine (L8398).


L86C5:      LD A,(DE)
            CALL L8390
            INC DE
            INC HL
            LD A,(DE)
            LD B,$18
            CP $00
            JR NZ,L86D4
            LD B,$20
L86D4:      LD A,(L8788)
            XOR $01
            LD (L8788),A
            BIT 0,A
            LD A,$00
            JR Z,L86E4
            LD A,$04
L86E4:      ADD A,B
            CALL L8390
            INC HL
            PUSH HL
            LD HL,$390C
            LD DE,L8704
            LD BC,$0034
            CALL L805D
            POP HL
            RET

The primary byte pointed by DE is used for the X-coordinate of the enemy. And the subsequent byte alerts the motion path to pick the sprite body for the enemy. It additionally switches frames utilizing L8788 to get alternate motion frames (together with B set to base body $18 or $20). Then it does one thing actually bizarre, copying the reminiscence space L8704 into VRAM handle $390c. Oh, I see, it defines two sprites very late within the recreation (the 2 sprite frames for snakes shifting to the suitable), it’s sort of apparent that I did not foresee all of the required sprites for the sport.

For this up to date model of the sport, I am going to modify barely the code:


            LD HL,$3900	; Outline body sprites $20 and $24
            LD DE,L8700	; Knowledge for snake going to proper.
            LD BC,$0040	; Size of information.
            CALL L805D	; Copy to VRAM.

It could not have match by 8 bytes, or I must transfer a good portion of code to create space. On this case my possibility may have been shifting the portion of code at $8504-$8533 (the advanced enemy motion code), however I did not have a MOVE command within the monitor program. I needed to copy manually the machine code on the new place.


	;
	; Additional sprites for snakes going proper.
	;
L8700:
	DB $00,$01,$01,$01,$00,$01,$03,$03
	DB $03,$21,$30,$33,$1b,$1f,$1d,$0c
	DB $00,$b0,$68,$68,$d8,$f0,$78,$ba
	DB $86,$f0,$f8,$78,$78,$f8,$f0,$e0

	DB $00,$00,$00,$00,$00,$01,$01,$41
	DB $40,$60,$60,$70,$33,$37,$3f,$1c
	DB $d8,$b4,$b4,$6c,$f8,$be,$d9,$c0
	DB $f0,$f8,$7c,$3c,$3c,$fc,$f8,$f0

Participant motion

The music participant chain hyperlinks to the keyboard code:


L8398:      CALL L0447
            CP $10
            JP Z,L83DD
            CP $0F
            JP Z,L83B5
            CP $37
            JP Z,L85B5
            CP $38
            JP Z,L8567
            CP $02
            JP Z,L8684
            RET

Now this code is trying each second extra like spaghetti code, and it additionally must be rewritten for moveable joystick dealing with:


L8398:      CALL GTSTCK
            CP $07		; Going left?
            JP Z,L83DD
            CP $03		; Going proper?
            JP Z,L83B5
            CP $01		; Going up?
            JP Z,L85B5
            CP $05		; Taking place?
            JP Z,L8567
	    CALL GTTRIG
            CP $ff		; Button pressed?
            JP Z,L8684
            RET

The primary joystick subroutine is L83B5:


L83B5:      LD HL,L8787
            INC (HL)
            INC (HL)
            NOP
            LD A,(HL)
            CP $00
            JR NZ,L83C2
            LD (HL),$FE
L83C2:      LD A,(L87FE)
            CP $04
            JR NZ,L83CD
            LD A,$00
            JR L83CF

L83CD:      LD A,$04
L83CF:      LD (L87FE),A
            RET

At this level, we all know that L8787 is the X-coordinate of the participant (based mostly on the Sprite Attribute Desk writes), and the double increment makes clear that the participant strikes to the suitable. If the X-coordinate turns into 0, it’s rewritten with restrict $fe (254 pixels). It additionally animates the participant switching between sprite frames $00 and $04.


L83DD:      LD HL,L8787
            DEC (HL)
            DEC (HL)
            NOP
            LD A,(HL)
            CP $FE
            JR NZ,L83EA
            LD (HL),$00
L83EA:      LD A,(L87FE)
            CP $0C
            JR NZ,L83F5
            LD A,$08
            JR L83F7

L83F5:      LD A,$0C
L83F7:      LD (L87FE),A
            RET

The following subroutine is the other: Transferring the participant to the left by two pixels. It additionally checks for exceeding the left border and units the X-coordinate to zero. It animates the participant switching between sprite frames $08 and $0c.

The NOP instruction after the 2 decrements makes me assume that I thought of shifting horizontally the participant at a velocity of three pixels.

Utilizing ladders

The code to permit the participant to go up and down over the ladders is closely patched, so most likely it took me quite a lot of effort and experiments.

Allow us to begin with the code to go down (this was coded first as a result of the participant must go down from the highest ground):


	;
	; Transfer the participant downward.
	;
L8567:      LD HL,$1B00
            CALL L85A0
            CALL L85AE
            NOP
            LD D,A
            INC HL
            CALL L85A0
            CALL L85FF
            RRCA
            RRCA
            LD E,A
            LD A,D
            LD L,A
            LD H,$00
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            LD D,$00
            ADD HL,DE
            LD DE,$3C40
            ADD HL,DE
            CALL L85A0
            LD B,A
            LD A,(L87FD)
            ADD A,$03
            CP B
            RET NZ
            CALL L85E9
            ADD A,$02
L859C:      LD (L8786),A
            RET

L85A0:      LD A,L
            OUT (VDP+1),A
            LD A,H
            OUT (VDP+1),A
            NOP
            NOP
            NOP
            NOP
            NOP
            IN A,(VDP)
            RET

L85AE:      INC A
            AND $F8
            RRCA
            RRCA
            RRCA
            RET

L85E9:      LD D,$00
            ADD HL,DE
            LD A,(L87FE)
            LD B,$14
            CP $10
            JR Z,L85F7
            LD B,$10
L85F7:      LD A,B
            LD (L87FE),A
            LD A,(L8786)
            RET

L85FF:      ADD A,$04
            AND $F8
            RRCA
            RET

L8605:      ADD A,$03
            CP B
            RET Z
            POP HL
            LD A,(L8786)
            INC A
            AND $F8
            JP L8631

L8631:      DEC A
            NOP
            LD (L8786),A
            RET

The harmless child reads from VRAM the coordinates of the participant, however why on Earth? These variables have been already obtainable in RAM.

It first reads from VRAM $1b00 the Y-coordinate of the participant into register D transformed to a display screen row coordinate, and it additionally reads the X-coordinate into register E and adjusts it to a display screen column coordinate. It lastly takes each numbers to create a pointer to the VRAM display screen.

	D = (Y + 1) / 8
	E = (X + 4) / 8
	HL = D * 32 + E + $3c20

You may see I did LD A,D adopted by LD L,A once I may merely do LD L,D.

It reads the character from VRAM (CALL L85A0), and it checks if the character is a ladder (the contents of L87FD plus 3). It calls a patch L85E9 that for some purpose provides a price to the content material of HL, animates the participant utilizing the ladder (sprite frames $10 and $14), and will get the Y-coordinate of the participant to maneuver it two pixels downward.


	;
	; Transfer the participant upward.
	;
L85B5:      LD A,(L8786)
            CALL L85AE
            LD D,A
            INC HL
            LD A,(L8787)
            CALL L85FF
            RRCA
            RRCA
            LD E,A
            LD A,D
            LD L,A
            LD H,$00
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            LD D,$00
            ADD HL,DE
            LD DE,$3C20
            ADD HL,DE
            CALL L85A0
            LD B,A
            LD A,(L87FD)
            CALL L8605
            NOP
            CALL L85E9
            SUB $02
            JP L859C

The code for shifting the participant upwards is fairly comparable, and by some means I did the suitable factor on this code utilizing the prevailing coordinates in RAM. This implies I used to be reaching my limits, and having 2K of machine code within the head is not really easy!

There are a couple of variations extra just like the completely different offset on the display screen ($3c20 versus $3c40), and the actual fact it calls L8605 to do a comparability with the ladder character. If it is not a ladder, it aligns the participant vertically (once more utilizing a patch), and utilizing POP HL it returns to the principle loop as an alternative of the unique caller. If it’s a ladder, it strikes the participant two pixels upwards.

Now for the good embarrassing second: the participant can stroll over the air. As a result of the code for dealing with left and proper by no means checks if the participant is over a ground. Because the flooring are at all times in the identical vertical place, it might be merely a matter of checking if the participant is over one of many legitimate Y-coordinates, however I can keep in mind vaguely I used to be afraid of shifting the code once more. Lazy child!

Profitable the sport

As soon as the participant reaches the grid within the bottom-right of the display screen, the hearth button must be pressed to cross the extent. I watched in delight as college students forgot to press the button they usually have been caught by the snake.


	;
	; Button press to exit degree.
	; 
L8684:      LD A,(L8786)
            CP $87
            RET NZ
            LD A,(L8787)
            CP $E8
            RET C
            CP $F8
            RET NC
            LD SP,L87F0
            LD A,$0F
            LD (L8786),A
            XOR A
            LD (L8787),A
            LD A,(L87FC)
            CP $05
            JP NZ,L8014
            LD HL,$3D4A
            CALL L0100
            CALL L0169
            db "HAS GANADO !",0
            LD A,$08
            OUT ($00),A
            XOR A
            JP L87B4

L87B4:      OUT ($80),A
            JP L878A

L878A:      LD B,$05	; Massive delay.
L878C:      PUSH BC
            LD BC,$0000
L8790:      DEC BC
            LD A,B
            OR C
            JR NZ,L8790
            POP BC
            DJNZ L878C
            LD SP,L87F0	; Reset Stack Pointer.
            LD A,$0F	; Reset Y-coordinate for the participant.
            LD (L8786),A
            XOR A		; Reset X-coordinate for the participant.
            LD (L8787),A
            LD A,$01	; Restart at degree 1.
            LD (L87FC),A
            LD HL,L87F9
            LD (HL),$00
            INC HL
            LD (HL),$00
            JP L8009

The subroutine first checks for the Y-coordinate to be $87, and the X-coordinate is between $e8 and $f7 (good tolerance) and if the circumstances are met it resets the stack pointer, units the participant once more on the top-left of the display screen, and if the extent quantity is not 5 then it jumps to L8014 to extend the extent quantity else it reveals a message “HAS GANADO” (Spanish for you win) on the display screen.

It additionally turns off the music in one other tender instance of chain linking due to the closely patched code.

The sound code must be rewritten as this:


            db "HAS GANADO !",0
	if COLECO
	    ld a,$9f
	    out (PSG),a
	else
	    ld e,$00
	    ld a,$08
	    name WRTPSG
	endif
            JP L87B4

L87B4:      	
            JP L878A

The L878A routine does a giant delay so the “HAS GANADO !” message stays on the display screen, after which resets the sport, and sends the participant again to degree 1.

Enemy motion

The second subroutine known as by the principle loop of the sport is L8504, it reveals heavy patches.


L8504:      CALL L850A
            JP L83D3

It calls L850A after which L83D3. L83D3 is extra akin to a loop to make the sport run slower (I nonetheless did not know the VDP interrupt line, nor did I’ve the road related to the Z80 processor). After setting BC to $1000, it additionally updates the present variety of lives on the display screen.


L83D3:      CALL L861E
L83D6:      DEC BC
            LD A,B
            OR C
            JR NZ,L83D6
            AND A
            RET

L861E:      LD BC,$1000
            LD A,(L87FB)
            ADD A,$30
            LD HL,$3EB2
            PUSH AF
            CALL L0100
            POP AF
            OUT (VDP),A
            RET

The subroutine L850A is longer:


L850A:      LD HL,L87F3
            CALL L8517
            LD L,255 AND L87F5
            CALL L8517
            LD L,255 AND L87F7
L8517:      INC HL
            LD A,(HL)
            OR A
            LD B,$03
            JR Z,L8520
            LD B,$FD
L8520:      DEC HL
            LD A,(HL)
            ADD A,B
            LD (HL),A
            CP $FF
            JR NZ,L852D
            INC HL
            LD (HL),$01
            JR L8533

L852D:      OR A
            JR NZ,L8533
            INC HL
            LD (HL),$00
L8533:      CALL L855B
            CP B
            RET C
            CP C
            RET NC
            LD A,L
            SUB 255 AND L87F3
            RRCA
            ADD A,A
            ADD A,A
            ADD A,$04
            LD L,A
            LD H,$1B
            LD A,L
            OUT (VDP+1),A
            LD A,H
            OUT (VDP+1),A
            NOP
            NOP
            NOP
            NOP
            IN A,(VDP)
            LD B,A
            LD A,(L8786)
            INC A
            CP B
            RET NZ
            JP L8613

L855B:      DEC HL
            LD A,L
            AND $FE
            OR $01
            LD L,A
            LD B,(HL)
            JP L8738

L8738:      LD A,(L8787)
            LD C,B
            DEC B
            DEC B
            DEC B
            INC C
            INC C
            INC C
            INC C
            RET

It makes use of L8517 every time with a pointer to one of many enemies (L87F3, L87F5, and L87F7). For every enemy, it checks the present path and selects an X-displacement (-3 or +3 pixels) within the B register. If it reaches a sure coordinate it switches the motion path.

As soon as this has been executed, one other patch calls to L855B to make HL level precisely to the X-coordinate of the enemy (this code depends on the reminiscence handle of the enemy coordinates). It reads the present X-coordinate into the B register and jumps to a different patch in L8738, the place it reads the X-coordinate of the participant in A, makes a replica of B in C, subtracting 3 from B, and provides 4 to C.

When it has created a collision width (minimal is B, most is C) it does a comparability of A (participant X-coordinate) with B and returns whether it is lower than, and a comparability in opposition to C and returns whether it is equal or higher than.

Because the enemy state does not comprise its Y-coordinate, it determines the sprite from the enemy knowledge handle, reads the Sprite Attribute Desk from VRAM to get the Y-coordinate and does a comparability with the participant Y-coordinate (L8786), and returns if each aren’t equal, else it jumps to L8613 to kill the participant.

There’s a bug on this code and the participant can die by chance whereas strolling. In a tremendous instance of how bugs can perdure for years, I could not discover this unintentional kill bug for years till right this moment (Feb/06/2024) I lastly used debuging instruments of BlueMSX. It’s fairly simple as soon as discovered, when a snake is aligned with the participant it returns appropriately as a result of the participant is not in the identical ground because the snake, however it loses the worth of the register HL as a result of the VRAM learn, and the subsequent snake X-coordinate might be learn from ROM creating a hard and fast invisible snake within the subsequent ground. It can fail randomly able dependant of the platform. Do you wish to right it? Simply substitute my “sensible” optimization in L850A to load every time the complete worth of HL with the handle of the enemy knowledge as an alternative of solely the L register. Case closed, it solely took me 34 years.

Let’s proceed:


L8613:      CALL L837A
            DEC (HL)
            SCF
            LD SP,L87F0
            JP L8637

L837A:      XOR A
            OUT ($00),A
            LD A,$AE
            OUT ($80),A
            LD A,$01
            OUT ($00),A
            LD A,$06
            OUT ($80),A
            JP L8774

L8774:      LD BC,$0000
L8777:      DEC BC
            LD A,B
            OR C
            JR NZ,L8777
            JP L866F

L866F:      LD A,$08
            OUT ($00),A
            XOR A
            OUT ($80),A
            LD BC,$0000
L8679:      DEC BC
            LD A,B
            OR C
            JR NZ,L8679
            LD HL,L87FB
            JR L86F8

L86F8:      XOR A
            LD (L87F9),A
	    LD (L87FA),A
            RET

L8637:      LD A,$0F
            LD (L8786),A
            XOR A
            LD (L8787),A
            LD A,(L87FB)
            CP $FF
            JP NZ,L8009
            LD HL,$3D4A
            CALL L0100
            CALL L0169
            db "FIN DE JUEGO",0
            LD B,$05
L8660:      PUSH BC
            LD BC,$0000
L8664:      DEC BC
            LD A,B
            OR C
            JR NZ,L8664
            POP BC
            DJNZ L8660
            JP L8000

It’s fairly embarrassing this chain-linking of code, however allow us to go in components.

The primary line of code at L8613 calls L837A, the final word objective is loading HL with L87FB to level to the variety of lives of the participant and decrement it.

However L837A additionally creates a sound impact (a primary!) then jumps to L8774 for a small delay, after which jumps to L866F to show off the amount, does one other delay, hundreds HL with a pointer to the variety of lives, and resets the music participant’s variables.

After it decrements the variety of lives, it units the carry flag however clearly, I obtained misplaced on this path as a result of it’s by no means used. The stack pointer is reset, the participant is about once more to the beginning level in L8637, and if there are nonetheless lives it jumps to L8009 to proceed the sport, or else it shows a message “FIN DE JUEGO” (recreation over in Spanish), it waits an extended time, and it resets utterly the sport leaping to L8000.

We have to patch the L837A and L866F sound routines with this:


L837A:
	if COLECO
	    ld a,$8E
	    out (PSG),a
	    ld a,$2a
	    out (PSG),a
	else
	    ld e,$ae
	    ld a,$00
	    name WRTPSG
	    ld e,$06
	    ld a,$01
	    name WRTPSG
	endif
            JP L8774

L866F:
	if COLECO
	    ld a,$9f
	    out (PSG),a
	else
	    ld e,$00
	    ld a,$08
	    name WRTPSG
	endif
            LD BC,$0000
L8679:      DEC BC

The used variables

The ultimate checklist of variables contained in the code are:


L8780:      rb 2	; Random generator 1.
L8782:      rb 2	; Random generator 2.
L8784:      rb 2	; Random generator 3.
L8786:      rb 1	; Y-coordinate for the participant.
L8787:      rb 1	; X-coordinate for the participant.
L8788:      rb 1	; Animation bit for snakes.

L87F3:      rb 1	; X-coordinate of enemy 1.
L87F4:      rb 1	; X-direction of enemy 1.
L87F5:      rb 1	; X-coordinate of enemy 2.
L87F6:      rb 1	; X-direction of enemy 2.
L87F7:      rb 1	; X-coordinate of enemy 3.
L87F8:      rb 1	; X-direction of enemy 3.
L87F9:      rb 1	; Observe index for music participant.
L87FA:      rb 1	; Tick counter for music participant.
L87FB:      rb 1	; Present lives.
L87FC:      rb 1	; Present degree. 
L87FD:      rb 1	; Base character for drawing ranges.
L87FE:      rb 1	; Sprite body for the participant.
L87FF:      rb 1	; Not used, but initialized.

The stack pointer was at $87F0 for 2K RAM scholar computer systems in 1990. Later moved to $fff0 for 32K RAM (1992).

You may obtain the ROM for the sport able to be performed on a Colecovision or MSX. I’ve additionally included the commented supply code. The one distinction between this and my 1990 recreation is the redesigned graphics and changes to degree colours to boost visibility. The unique colours blended badly on trendy emulators (in 1990 I may modify distinction within the Sony Trinitron TV).

  • Obtain viboritas.zip (17.24 kb). Supply code, ROM for Colecovision and MSX, and unique binary and disassembly.

Epilogue

Quite a lot of bytes may very well be saved on this recreation by refactoring some components like utilizing an additional byte to protect the vertical place of enemies, shifting some initialization code out of the principle loop (lives replace and snake sprite definition), utilizing knowledge obtainable on RAM as an alternative of studying VRAM, and compacting the music participant code.

On the opposite facet, it displays my skills on the time. I may have nearly 2K of machine code on my head, there wasn’t a plan forward (denoted by the ton of patches). I used to be nonetheless studying learn how to code a platform recreation, and I wasn’t too ready to attract graphics.

Writing video games or different code straight in machine code is not sensible. Though at first look you possibly can have the whole lot in your head, you will neglect utterly after a couple of years, and likewise except you could have some paper documentation there are no useful feedback!

I’d have used an assembler program if these have been available, however I had none till I wrote mine some years after. The software program shops in Mexico have been scarce, additionally I by no means may discover one thing so esoteric as a Z80 assembler program when the IBM PC was already the dominant machine.

Nonetheless, my goal of creating a recreation in 2K RAM was met. College students have been shocked an actual recreation may work on their laptop. I feel I distributed a couple of copies as printed sheets with the binary and one other few copies in floppies.

I realized as I developed the sport, and I did not make once more the error of permitting the participant to stroll into the void. However nonetheless for a few years, I saved coding in machine code and doing spaghetti code once I wanted to insert code, however that could be a historical past for one more day.

Associated hyperlinks

Final modified: Feb/08/2024

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top