My first Z80 assembly language program

I was cleaning an old work area when I saw my old blue notebook that I used from 1986 to 1989. It had suffered the pass of time and dust.
My old notebook from 1988
My old notebook from 1988
I thought it was the same notebook I had seen before, because I had two blue notebooks of the same model, but I lost one. And then to my surprise, I discovered it was the lost second notebook, where I put my first Z80 assembly language program!
Pretty happy, I took pictures immediately of the important pages, just in case I lose again the notebook.
And memories start coming slowly...

The history

My Karateka game: Title screen
I was 9 years old and I wanted to write amazing games. Of course, I was too young to create something in the league of the games that I was watching in magazines at the time like Compute! and Input MSX.
After four years of writing games in BASIC language, I felt like I was stopped by the slowness inherent to an interpreted language.
This game was written around June 1988, my father was giving a lecture on programming the VDP processor TMS9128. The video processor was pretty available at the time (via Digikey) because the demise of all computers using it.
My notes on the VDP 16K VRAM structure
My notes on the VDP 16K VRAM structure. Notice the register numbers.
The students had been soldering their computers based on Z80 over a copper board perforated with holes spaced by 0.1"
Unfortunately my hands weren't able at the time to handle precisely a soldering iron, so I had been watching awkwardly how the students enjoyed building their computers, how they managed to get them running, and how they troubleshooted their bugs.
My Karateka game: Inside the game
This gave me plenty of time to think about the Z80 assembler programming concept, I had been unable to grasp the concept of how to put together the instructions. The previous weeks before that Sunday (I can remember it was Sunday), while watching my father putting together the monitor/VDP/Keyboard EPROM code for the students computer, finally I had the imaginary light bulb over my head. Of course! Several instructions compose a BASIC language statement, so it was a matter of doing the same but in assembler.
The Sunday morning before class, I started writing furiously over my notebook a game about a karateka fighting a woman launching knifes. I had the whole idea on my head, now I realize for the first time I had the BASIC algorithm clearly in my mind. It was only a matter of translating it to assembler. I had realized that the line separation of BASIC was invisible on assembler, but each address could be related to that imaginary line number in BASIC language.
You can imagine the surprise of the whole class when I showed my game proudly. I remember three students copying manually the code from the RAM dump and then making Xerox copies for the other students.

Getting this to work in 2021

Here are the pictures of my notebook. You'll need to forgive my terrible kid letters. Barely any comments but anything you see will be in Spanish, because that is my first language.
While commenting each page (and analyzing my novice 9 years old myself!), I'll translate this game to tniASM v0.44 for both MSX and Colecovision (just because). We need the following translation and support layer because we don't have at hand the original ROM from the students computer:

	;
	; Karateka
	;
	; by Oscar Toledo G.
	; (c) Copyright Oscar Toledo G. 1988-2021
	; https://nanochess.org/
	;
	; Creation date: Jun/1988. I was 9 years old.
	; Revision date: May/12/2021. Ported to MSX/Colecovision.
	;

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

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

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

    if COLECO
	fname "KARATECV.ROM"

	org $8000,$9fff

	dw $aa55	; No BIOS title 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 "KARATMSX.ROM"

	org $4000,$5fff

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

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
	call SETWRT
	pop af
	out (VDP),a
	ret

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

	; Setup VDP before game
setup_vdp:
	LD BC,$0200
	CALL WRTVDP
	LD BC,$C201	; No interrupts
	CALL WRTVDP
	LD BC,$0F02	; $3C00 for pattern table
	CALL WRTVDP
	LD BC,$FF03	; $2000 for color table
	CALL WRTVDP
	LD BC,$0304	; $0000 for bitmap table
	CALL WRTVDP
	LD BC,$3605	; $1b00 for sprite attribute table
	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
	call $00d8
	or a
	ret nz
	ld a,1
	call $00d8
	or a
	ret nz
        ld a,2
        call $00d8
        or a
        ret nz
        ld a,3
        call $00d8
        or a
        ret nz
        ld a,4
        call $00d8
        ret
    endif

	;
	; Gets the joystick direction
	; 0 - No movement
	; 1 - Up
	; 2 - Up + right
	; 3 - Right
	; 4 - Right + 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
	call $00d5
	or a
	ret nz
	ld a,1
	call $00d5
	or a
	ret nz
	ld a,2
	jp $00d5
    endif

	; ROM routines I forgot

	; Clean screen
LIMPIA:	; $04cc
	LD HL,$3C00
	LD BC,$0300
	XOR A
	JP FILVRM

	; Copy string to VDP
INMEDIATO:	; $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

	;
	; Start of the game
	;
START:		; 8000
	DI
	LD SP,RAM_BASE+256
Every extra code will be added at the end of the previous code.
Page 1 of my Z80 game
Page 1 of my Z80 game, right-click for higher resolution.
So here is the page 1 of my Z80 game. The source code at right was written thinking in putting it inside an assembler program that I was going to develop (imagine that, a 9 years old ambitiously thinking in writing an assembler!).
To enter this game into the students' computer, one needs to enter only the microcode at the left. If you found an error on the right side source code is because it is mean to be as reference only.
The code basically setups the game and creates a game loop. I misspelled NAVAJA (knife) as NEVAJA. Notice how I replaced PONEHL for a similar MSX routine WRTVDP. The INMEDIATO routine copies the following bytes directly to VDP until finding a zero byte.

JUEGO:
	CALL setup_vdp	; Not in original but needed to setup VDP
	CALL LIMPIA	; Clean screen
	CALL PRESENTACION       ; Title screen
	CALL GRAFICOS	; Setup graphics
PRIN:		; 8009
	CALL PATCH	; Patch for jump
	CALL KARATEKA	; Move karateka
	CALL MALORA	; Move baddie
	CALL NEVAJA	; Move knifes
	JP PRIN		; Repeat game loop

        ; Title screen
PRESENTACION:	; 8018
	LD HL,$3C4D
	CALL SETWRT
	CALL INMEDIATO
Page 2 of my Z80 game
Page 2 of my Z80 game.
Of course, I didn't had any idea of using directives except to put a byte at once. This is the title screen. "PULSE ESPACIO" means to press the keyboard space bar. I changed it to any trigger on MSX or Colecovision.

	DB "KARATEKA",0

	LD HL,$3ECA
	CALL SETWRT
	CALL INMEDIATO
	DB "PULSE ESPACIO",0
Page 3 of my Z80 game
Page 3 of my Z80 game.
It uses an internal BIOS routine $04f5 to read the keyboard matrix, and it has been replaced with a MSX GTTRIG call (or Colecovision read of buttons). Then it setups the graphics for the karateka, the knife, and the judoka.

	; Changed from the original
TEC:	XOR A
	CALL GTTRIG
	OR A
	RET NZ
	JP TEC

	; Setup graphics for Karateka, Knife, and Judoka
GRAFICOS:
	LD HL,$3800
	LD DE,GRAFICOS_8600
	LD B,$00
.1:	LD A,(DE)
	CALL WRTVRM
	INC HL
	INC DE
	DJNZ .1

	LD HL,$0B08
	LD DE,GRAFICOS_85D8
	LD B,$28
.2:	LD A,(DE)
Page 4 of my Z80 game
Page 4 of my Z80 game.
It now setups some variables for the position of the karateka, and the knifes shoot by the enemy. Also resets the kicks_given variable. It starts filling the color for the sky and grass.

	CALL WRTVRM
	INC HL
	INC DE
	DJNZ .2

        LD A,$68
	LD (y_karateka),A
	LD A,$D0
	LD (x_karateka),A
	LD A,$00
	LD (spr_karateka),A
	LD A,$00
	LD (knife1),A
	LD A,$00
	LD (knife2),A
	LD A,$00
        LD (kicks_given),A

	LD HL,$2B00
	LD B,$08
.3:	LD A,$77	; Turquoise color
	CALL WRTVRM
	INC HL
	DJNZ .3
	LD HL,$2808
	LD B,$08
.4:	LD A,$22	; Grass color
Page 5 of my Z80 game
Page 5 of my Z80 game.
Then it cleans the screen and starts putting the characters on the screen to create visually the sky and grass. And yes, embarrassingly the 9 years old is repeating code like crazy!

	CALL WRTVRM
	INC HL
	DJNZ .4

	LD HL,$2300
	LD B,$08
.5:	LD A,$77
	CALL WRTVRM
	INC HL
	DJNZ .5

	CALL LIMPIA

	LD HL,$3C00
	LD B,$00
.6:	LD A,$60
	CALL WRTVRM
	INC HL
	DJNZ .6

	LD B,$E0
.7:	LD A,$60
	CALL WRTVRM
	INC HL
	DJNZ .7

	LD B,$20
.8:	LD A,$01
	CALL WRTVRM
	INC HL
Page 6 of my Z80 game
Page 6 of my Z80 game.
It sets the color for the enemy and then puts it on the screen by using defined characters. Then setups 3 variables, one of them is unused.

	DJNZ .8

	LD HL,$2B08
	LD B,$28
.9:	LD A,$17
	CALL WRTVRM
	INC HL
	DJNZ .9

	LD HL,$3DA2
	LD A,$61
	CALL WRTVRM
	LD HL,$3DA3
	LD A,$62
	CALL WRTVRM
	LD HL,$3DC2
	LD A,$63
	CALL WRTVRM
	LD HL,$3DC3
	LD A,$64
	CALL WRTVRM
	LD A,$00
	LD (knife_time+1),A     ; NOT USED
	LD A,$00
	LD (kicks_given),A
	LD A,$00
	LD (knife_time),A
Page 7 of my Z80 game
Page 7 of my Z80 game.
For some unclear reason I set again the Register 1 of VDP, then it setups the start position for the player. Notice the microcode says 3E 68 corrected while the source code at right reads LD A,70 putting the player under the floor.
The movement is left and right, up for punchs, and down for kicks. Again the keyboard reading has been replaced for MSX GTSTCK (translated for Colecovision).

	LD BC,$C201
	CALL WRTVDP
	LD HL,$1B00
	LD A,$68
	CALL WRTVRM
	INC HL
	LD A,$E0
	CALL WRTVRM
	INC HL
	LD A,$00
	CALL WRTVRM
	INC HL
	LD A,$0E
	CALL WRTVRM
	RET

	; Move karateka
KARATEKA:	; 8132
	XOR A
	CALL GTSTCK	; Changed from original
	CP $07
	JP Z,MIK
	CP $03
	JP Z,MDK
	CP $01
	JP Z,GODMA
Page 8 of my Z80 game
Page 8 of my Z80 game.
I think I was going through a mental compilation of BASIC to assembler, only that could explain why the code is pretty unoptimized. Optimizing it a little would have saved me lots of time re-entering the game into the computer.
Moving the karateka to left was accomplished simply by subtracting 8 to the X coordinate, and updating it also on the sprite attributes table. Also it animates the player between two frames.

	CP $05
	JP Z,GODPI
	RET

	; Move karateka to left
MIK:	; 8149
	LD A,(x_karateka)
	SUB $08
	LD (x_karateka),A
	LD HL,$1b01
	CALL WRTVRM
	LD A,(spr_karateka)
	CP $00
	JP Z,SP2
	LD A,$00
	LD (spr_karateka),A
	JP SPR

SP2:	; 8167
	LD A,$08
	LD (spr_karateka),A
SPR:	LD HL,$1b02
	CALL WRTVRM
	RET
Page 9 of my Z80 game
Page 9 of my Z80 game.
The movement to right replicates essentially the same code for left movement. It could have used the same subroutine by passing parameters on DE or BC registers.
Given it has no idea of the player direction, it checks the sprite frame to see in which direction he/she is facing. Another variable would have made it so much easier.

	; Move karateka to right
MDK:	; 8173
	LD A,(x_karateka)
	ADD A,$08
	LD (x_karateka),A
	LD HL,$1b01
	CALL WRTVRM
	LD A,(spr_karateka)
	CP $04
	JP Z,SPC
	LD A,$04
	LD (spr_karateka),A
	JP SPR0

SPC:	LD A,$0C
	LD (spr_karateka),A
SPR0:	LD HL,$1b02
	CALL WRTVRM
	RET

	; Hand fight (GOlpe De MAno)
GODMA:	; 819D
	LD A,(spr_karateka)
	CP $00
	JP Z,GAI
	CP $08
	JP Z,GAI
	CP $04
Page 10 of my Z80 game
Page 10 of my Z80 game.
The code to punch enemy to left (GAI) and right (GAD), it simply updates the sprite to the punch frame, and calls NADEO (where it checks if enemy is hit), then it does a wait (stopping the whole game!) and restores the original sprite. I still needed to grasp the concept of independent objects.

	JP Z,GAD
	CP $0C
	JP Z,GAD
	RET

GAI:	; 81B5
	LD HL,$1B02
	LD A,$10
ZON:	CALL NADEO
	LD BC,$4000
.1:	DEC BC
	LD A,B
	OR C
	JR NZ,.1
	LD A,(spr_karateka)
	JP WRTVRM

GAD:	; 81CB
	LD HL,$1B02
	LD A,$14
	JP ZON
Page 11 of my Z80 game
Page 11 of my Z80 game.
The code to handle kicks is essentially a copy of the previous code. BOLAS is essentially saying Ay Caramba!

GODPI:	; 81D3 Forgot label on code
	LD A,(spr_karateka)
	CP $00
	JP Z,IZ
	CP $08
	JP Z,IZ
	CP $04
	JP Z,DER
	CP $0C
	JP Z,DER
	RET

IZ:	; 81EB
	LD HL,$1B02
	LD A,$18
HOLA:	CALL NADEO
	LD BC,$4000
BOLAS:	DEC BC
	LD A,B
	OR C
	JR NZ,BOLAS
	LD A,(spr_karateka)
	JP WRTVRM

DER:    ; 8201
	LD HL,$1B02
	LD A,$1C
	JP HOLA
Page 12 of my Z80 game
Page 12 of my Z80 game.
After watching there was no way of avoiding the knifes, I implemented the jump for the karateka.
This is showing more thinking, like calling NEVAJA to keep the knifes moving. But still two separate routines, one to move player up, and one to move player down. Each with their own delay.

	; Karateka jump
SALTO:	; 8209
	LD A,(y_karateka)
	LD B,$04
OSC:	LD HL,$1B00
	SUB $04
	CALL WRTVRM
	PUSH HL
	PUSH AF
	CALL NEVAJA
	PUSH BC
	LD BC,$4000
.1:	DEC BC
	LD A,B
	OR C
	JR NZ,.1
	POP BC
	POP AF
	POP HL
	DJNZ OSC
	LD B,$04
KAR:	LD HL,$1B00
	ADD A,$04
	CALL WRTVRM
	PUSH HL
	PUSH AF
	CALL NEVAJA
	PUSH BC
Page 13 of my Z80 game
Page 13 of my Z80 game.
Moving the knifes is simply a running counter from left to right, updating the screen.
The kid couldn't solve how to make knifes closer to the enemy launching them, because the knifes cleared behind with spaces so these would have erased the right half of the enemy.

	LD BC,$4000
BOCHA:	DEC BC
	LD A,B
	OR C
	JR NZ,BOCHA
	POP BC
	POP AF
	POP HL
	DJNZ KAR
	RET

NEVAJA:	; 8247
	LD A,(knife1)
	ADD A,$A5
	LD H,$3D
	LD L,A
	LD A,$65
	CALL WRTVRM
	LD A,(knife1)
	ADD A,$A4
	LD H,$3D
	LD L,A
	LD A,$60
	CALL WRTVRM
	LD A,(knife1)
	INC A
Page 14 of my Z80 game
Page 14 of my Z80 game.
An amazing waste of bytes by repeating the same code to move a parallel knife on the same column by using a different variable.

	LD (knife1),A
	LD A,(knife2)
	ADD A,$C5
	LD H,$3D
	LD L,A
	LD A,$65
	CALL WRTVRM
	LD A,(knife2)
	ADD A,$C4
	LD H,$3D
	LD L,A
	LD A,$60
	CALL WRTVRM
	LD A,(knife2)
	INC A
	LD (knife2),A
	CP $1A
	CALL Z,B2
	LD A,(knife1)
	CP $1A
	CALL Z,B1
	RET

B1:	DEC A
	ADD A,$A5
	LD H,$3D
Page 15 of my Z80 game
Page 15 of my Z80 game.
Again a waste of bytes to delete each knife separately, when both come together. Probably I was thinking on having them appear on different times, but couldn't figure how to do it. The MALORA function (baddy) checks if the knifes hit the player, again checking each knife separately.

	LD L,A
	LD A,$60
	CALL WRTVRM
	LD A,$00
	LD (knife1),A
	RET

B2:	DEC A
	ADD A,$C5
	LD H,$3D
	LD L,A
	LD A,$60
	CALL WRTVRM
	LD A,$00
	LD (knife2),A
	RET

MALORA:	; 82B9
	LD A,(x_karateka)
	RRCA
	RRCA
	RRCA
	LD B,A
	LD A,(knife1)
	ADD A,$05
	CP B
	JP Z,MUERTO
	LD A,(knife2)
Page 16 of my Z80 game
Page 16 of my Z80 game.
The MUERTO (dead) function simply fills the whole color table with a random colors (Hey! That's a special visual effect!) And stops before resetting to the internal monitor. Couldn't insert a jump to the main game because the RST 00 instruction only uses one byte, and a jump uses 3 bytes (remember I wasn't using an assembler) so for this time I changed it to jump to the game.

	ADD A,$05
	CP B
	JP Z,MUERTO
	RET

MUERTO:	; 82D3
	LD HL,$2000
	LD BC,$1800
M2:	LD A,R	
	CALL WRTVRM
	INC HL
	DEC BC
	LD A,B
	OR C
	JR NZ,M2
	LD BC,$0000
M3:	DEC BC
	LD A,B
	OR C
	JR NZ,M3
	JP JUEGO	; Not in original because lack of space
Page 17 of my Z80 game
Page 17 of my Z80 game.
Finally my first working subroutine NADEO, called 4 times to check for enemy being hit. I cannot figure what I was trying to abbreviate there. The hit check is simple, if the player is standing exactly where the knifes appear, it will hit the enemy, of course I was trying to make him/her to be hit by the knifes. Unfortunately this exact position is hitting on the air, and there is no visual indication of hit...

NADEO:	; 82ED
	CALL WRTVRM
	PUSH AF
	PUSH HL
	PUSH BC
	PUSH DE
	LD A,(x_karateka)
	CP $28
	CALL Z,GOLPES
	POP DE
	POP BC
	POP HL
	POP AF
	RET

GOLPES:	; 8301
	LD A,(kicks_given)
	INC A
	LD (kicks_given),A
	CP $14
	JP Z,GANAR
	RET

GANAR:	; 830E
	CALL LIMPIA
	LD HL,$3C03
	CALL SETWRT
	CALL INMEDIATO
Page 18 of my Z80 game
Page 18 of my Z80 game.
This part is simple. Only a winning message (BIEN! or good!)

	DB "BIEN!",0
	LD BC,$0000
BION:	DEC BC
	LD A,B
	OR C
	JR NZ,BION
	JP JUEGO
Page 19 of my Z80 game
Page 19 of my Z80 game.
Obviously I wrote the whole game from my brain to paper, and didn't planned for a delay to make the game playable. This code handles it and also the jumping.
Notice how I didn't use interrupts, I didn't knew about interrupts at the time, but the simple idea of having a constant time reference in terms of video frames would have blown my mind!

PATCH:
	LD BC,$4000
.1:	DEC BC
	LD A,B
	OR C
	JR NZ,.1
	XOR A
	CALL GTTRIG
	OR A
	JP NZ,SALTO
	RET
Page 20 of my Z80 game
Page 20 of my Z80 game.
This page doesn't need to be ported as VPOKE is replaced by the WRTVRM routine. And VPEEK isn't used. By the way, this shows the influence of my Input MSX magazine readings.
Page 21 of my Z80 game
Page 21 of my Z80 game.
Page 22 of my Z80 game
Page 22 of my Z80 game.
These pages comprise the graphics for the game. There should be squared paper somewhere containing my original drawings but I don't have found them.

GRAFICOS_85D8:
	DB $00,$03,$06,$0D,$1B,$17,$03,$01	; JUDOKA
	DB $00,$C0,$00,$C0,$40,$C0,$80,$00
	DB $0F,$F3,$00,$07,$07,$02,$1C,$30
	DB $F0,$CF,$00,$E0,$E0,$40,$38,$0C

	DB $10,$10,$20,$FF,$FF,$20,$10,$10	; KNIFE

GRAFICOS_8600:
	DB $03,$07,$07,$03,$01,$03,$03,$03	; KARATEKA LEFT
	DB $03,$03,$03,$01,$01,$01,$03,$0F
	DB $C0,$E0,$E0,$C0,$80,$C0,$C0,$C0
	DB $C0,$C0,$C0,$80,$80,$80,$80,$80

	DB $03,$07,$07,$03,$01,$03,$03,$03	; KARATEKA RIGHT
	DB $03,$03,$03,$01,$01,$01,$01,$01
	DB $C0,$E0,$E0,$C0,$80,$C0,$C0,$C0
	DB $C0,$C0,$C0,$80,$80,$80,$C0,$F0

	DB $03,$07,$07,$03,$01,$03,$03,$03	; KARATEKA WALKING LEFT
	DB $03,$03,$03,$01,$02,$04,$0C,$3D
	DB $C0,$E0,$E0,$C0,$80,$C0,$C0,$C0
	DB $C0,$C0,$C0,$80,$40,$20,$60,$E0

	DB $03,$07,$07,$03,$01,$03,$03,$03	; KARATEKA WALKING RIGHT
	DB $03,$03,$03,$01,$02,$04,$06,$07
	DB $C0,$E0,$E0,$C0,$80,$C0,$C0,$C0
	DB $C0,$C0,$C0,$80,$40,$20,$30,$BC

	DB $03,$07,$07,$03,$01,$FF,$FF,$03	; KARATEKA PUNCH LEFT
	DB $03,$03,$03,$01,$01,$01,$03,$0F
	DB $C0,$E0,$E0,$C0,$80,$C0,$C0,$C0
	DB $C0,$C0,$C0,$80,$80,$80,$80,$80

	DB $03,$07,$07,$03,$01,$03,$03,$03	; KARATEKA PUNCH RIGHT
	DB $03,$03,$03,$01,$01,$01,$01,$01
	DB $C0,$E0,$E0,$C0,$80,$FF,$FF,$C0
	DB $C0,$C0,$C0,$80,$80,$80,$C0,$F0

	DB $03,$07,$07,$03,$01,$03,$C3,$C3	; KARATEKA KICK LEFT
	DB $33,$33,$0F,$07,$00,$00,$01,$07
	DB $C0,$E0,$E0,$C0,$80,$C0,$C0,$C0
	DB $C0,$C0,$C0,$80,$80,$80,$80,$80

	DB $03,$07,$07,$03,$01,$03,$03,$03	; KARATEKA KICK RIGHT
	DB $03,$03,$03,$01,$01,$01,$01,$01
	DB $C0,$E0,$E0,$C0,$80,$C0,$C3,$C3
	DB $CC,$CC,$F0,$E0,$00,$00,$80,$E0
Page 23 of my Z80 game
Page 23 of my Z80 game.
The last page contains documentation of the variables used and half of it is desynchronized, and the knife 3 wasn't implemented. It's a practical example of real documentation :P

	ORG RAM_BASE

y_karateka:	RB 1
x_karateka:	RB 1
spr_karateka:	RB 1
knife1:		RB 1
knife2:		RB 1
kicks_given:	RB 1
knife_time:    RB 1    ; NOT USED

Downloads

You can download the source code for this game.

Addendum

It only took me almost three years (Feb/11/2024) to discover that the drawings for the game were in fact in the same notebook, but the two pages were sticking together.
Knife drawing for my simple Karateka game Player and enemy drawing for my simple Karateka game
The following drawing wasn't used in the game because it looked too different from my base drawings, but I remember the leg in diagonal was inspired by it. Of course, it took me years to discover that a kick movement isn't simply the leg upwards (don't do that).
Player drawing doing a karate movement

Related links

Last modified: Feb/22/2024