Initial Revision

Manic Miner for Apple II
This commit is contained in:
StewBC 2020-04-21 14:02:31 -07:00
parent ca737f490e
commit 7652ec5858
30 changed files with 11375 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
/obj/
/Makefile.options
/mminer.dsk
/mminer.apple2*

349
Makefile Normal file
View File

@ -0,0 +1,349 @@
###############################################################################
### Generic Makefile for cc65 projects - full version with abstract options ###
### V1.3.0(w) 2010 - 2013 Oliver Schmidt & Patryk "Silver Dream !" Łogiewa ###
###############################################################################
###############################################################################
### In order to override defaults - values can be assigned to the variables ###
###############################################################################
# Space or comma separated list of cc65 supported target platforms to build for.
# Default: c64 (lowercase!)
TARGETS := apple2
# Name of the final, single-file executable.
# Default: name of the current dir with target name appended
PROGRAM := mminer
# Path(s) to additional libraries required for linking the program
# Use only if you don't want to place copies of the libraries in SRCDIR
# Default: none
LIBS :=
# Custom linker configuration file
# Use only if you don't want to place it in SRCDIR
# Default: none
CONFIG :=
# Additional C compiler flags and options.
# Default: none
CFLAGS =
# Additional assembler flags and options.
# Default: none
ASFLAGS =
# Additional linker flags and options.
# Default: none
LDFLAGS =
ifeq ($(PROGRAM),)
NAME := $(notdir $(CURDIR))
else
NAME := $(PROGRAM)
endif
$(NAME).apple2: LDFLAGS +=
# Path to the directory containing C and ASM sources.
# Default: src
SRCDIR :=
# Path to the directory where object files are to be stored (inside respective target subdirectories).
# Default: obj
OBJDIR :=
# Command used to run the emulator.
# Default: depending on target platform. For default (c64) target: x64 -kernal kernal -VICIIdsize -autoload
EMUCMD :=
# On Windows machines VICE emulators may not be available in the PATH by default.
# In such case, please set the variable below to point to directory containing
# VICE emulators.
#VICE_HOME := "C:\Program Files\WinVICE-2.2-x86\"
VICE_HOME :=
#APPLEWIN_HOME := c:\users\swessels\apps\applewin
# Optional commands used before starting the emulation process, and after finishing it.
# Default: none
# Examples
#PREEMUCMD := osascript -e "tell application \"System Events\" to set isRunning to (name of processes) contains \"X11.bin\"" -e "if isRunning is true then tell application \"X11\" to activate"
#PREEMUCMD := osascript -e "tell application \"X11\" to activate"
#POSTEMUCMD := osascript -e "tell application \"System Events\" to tell process \"X11\" to set visible to false"
#POSTEMUCMD := osascript -e "tell application \"Terminal\" to activate"
#PREEMUCMD := sed "s/^al \([[0-9A-F]\+\)\ \./\1 /g" $(NAME).apple2.lbl > $(APPLEWIN_HOME)\A2_USER1.SYM
POSTEMUCMD :=
# Options state file name. You should not need to change this, but for those
# rare cases when you feel you really need to name it differently - here you are
STATEFILE := Makefile.options
###################################################################################
#### DO NOT EDIT BELOW THIS LINE, UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! ####
###################################################################################
###################################################################################
### Mapping abstract options to the actual compiler, assembler and linker flags ###
### Predefined compiler, assembler and linker flags, used with abstract options ###
### valid for 2.14.x. Consult the documentation of your cc65 version before use ###
###################################################################################
# Compiler flags used to tell the compiler to optimise for SPEED
define _optspeed_
CFLAGS += -Oris
endef
# Compiler flags used to tell the compiler to optimise for SIZE
define _optsize_
CFLAGS += -Or
endef
# Compiler and assembler flags for generating listings
define _listing_
CFLAGS += --listing $$(@:.o=.lst)
ASFLAGS += --listing $$(@:.o=.lst)
REMOVES += $(addsuffix .lst,$(basename $(OBJECTS)))
endef
# Linker flags for generating map file
define _mapfile_
LDFLAGS += --mapfile $$@.map
REMOVES += $(PROGRAM).map
endef
# Linker flags for generating VICE label file
define _labelfile_
ASFLAGS += --debug-info
LDFLAGS += -Ln $$@.lbl
REMOVES += $(PROGRAM).lbl
endef
# Linker flags for generating a debug file
define _debugfile_
LDFLAGS += -Wl --dbgfile,$$@.dbg
REMOVES += $(PROGRAM).dbg
endef
###############################################################################
### Defaults to be used if nothing defined in the editable sections above ###
###############################################################################
# Presume the C64 target like the cl65 compile & link utility does.
# Set TARGETS to override.
ifeq ($(TARGETS),)
TARGETS := c64
endif
# Presume we're in a project directory so name the program like the current
# directory. Set PROGRAM to override.
ifeq ($(PROGRAM),)
PROGRAM := $(notdir $(CURDIR))
endif
# Presume the C and asm source files to be located in the subdirectory 'src'.
# Set SRCDIR to override.
ifeq ($(SRCDIR),)
SRCDIR := src
endif
# Presume the object and dependency files to be located in the subdirectory
# 'obj' (which will be created). Set OBJDIR to override.
ifeq ($(OBJDIR),)
OBJDIR := obj
endif
TARGETOBJDIR := $(OBJDIR)/$(TARGETS)
# Default emulator commands and options for particular targets.
# Set EMUCMD to override.
c64_EMUCMD := $(VICE_HOME)x64 -kernal kernal -VICIIdsize -autoload
c128_EMUCMD := $(VICE_HOME)x128 -kernal kernal -VICIIdsize -autoload
vic20_EMUCMD := $(VICE_HOME)xvic -kernal kernal -VICdsize -autoload
pet_EMUCMD := $(VICE_HOME)xpet -Crtcdsize -autoload
plus4_EMUCMD := $(VICE_HOME)xplus4 -TEDdsize -autoload
# So far there is no x16 emulator in VICE (why??) so we have to use xplus4 with -memsize option
c16_EMUCMD := $(VICE_HOME)xplus4 -ramsize 16 -TEDdsize -autoload
cbm510_EMUCMD := $(VICE_HOME)xcbm2 -model 510 -VICIIdsize -autoload
cbm610_EMUCMD := $(VICE_HOME)xcbm2 -model 610 -Crtcdsize -autoload
atari_EMUCMD := atari800 -windowed -xl -pal -nopatchall -run
cx16_EMUCMD := x16emu -run -prg
apple2_EMUCMD := $(APPLEWIN_HOME)\AppleWin.exe -d1 $(CURDIR)\$(NAME).dsk
ifeq ($(EMUCMD),)
EMUCMD = $($(CC65TARGET)_EMUCMD)
endif
###############################################################################
### The magic begins ###
###############################################################################
# The "Native Win32" GNU Make contains quite some workarounds to get along with
# cmd.exe as shell. However it does not provide means to determine that it does
# actually activate those workarounds. Especially $(SHELL) does NOT contain the
# value 'cmd.exe'. So the usual way to determine if cmd.exe is being used is to
# execute the command 'echo' without any parameters. Only cmd.exe will return a
# non-empty string - saying 'ECHO is on/off'.
#
# Many "Native Win32" programs accept '/' as directory delimiter just fine. How-
# ever the internal commands of cmd.exe generally require '\' to be used.
#
# cmd.exe has an internal command 'mkdir' that doesn't understand nor require a
# '-p' to create parent directories as needed.
#
# cmd.exe has an internal command 'del' that reports a syntax error if executed
# without any file so make sure to call it only if there's an actual argument.
ifeq ($(shell echo),)
MKDIR = mkdir -p $1
RMDIR = rmdir $1
RMFILES = $(RM) $1
else
MKDIR = mkdir $(subst /,\,$1)
RMDIR = rmdir $(subst /,\,$1)
RMFILES = $(if $1,del /f $(subst /,\,$1))
endif
COMMA := ,
SPACE := $(N/A) $(N/A)
define NEWLINE
endef
# Note: Do not remove any of the two empty lines above !
TARGETLIST := $(subst $(COMMA),$(SPACE),$(TARGETS))
ifeq ($(words $(TARGETLIST)),1)
# Set PROGRAM to something like 'myprog.c64'.
override PROGRAM := $(PROGRAM).$(TARGETLIST)
# Set SOURCES to something like 'src/foo.c src/bar.s'.
# Use of assembler files with names ending differently than .s is deprecated!
SOURCES := $(wildcard $(SRCDIR)/*.c)
SOURCES += $(wildcard $(SRCDIR)/*.s)
SOURCES += $(wildcard $(SRCDIR)/*.asm)
SOURCES += $(wildcard $(SRCDIR)/*.a65)
# Add to SOURCES something like 'src/c64/me.c src/c64/too.s'.
# Use of assembler files with names ending differently than .s is deprecated!
SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.c)
SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.s)
SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.asm)
SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.a65)
# Set OBJECTS to something like 'obj/c64/foo.o obj/c64/bar.o'.
OBJECTS := $(addsuffix .o,$(basename $(addprefix $(TARGETOBJDIR)/,$(notdir $(SOURCES)))))
# Set DEPENDS to something like 'obj/c64/foo.d obj/c64/bar.d'.
DEPENDS := $(OBJECTS:.o=.d)
# Add to LIBS something like 'src/foo.lib src/c64/bar.lib'.
LIBS += $(wildcard $(SRCDIR)/*.lib)
LIBS += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.lib)
# Add to CONFIG something like 'src/c64/bar.cfg src/foo.cfg'.
CONFIG += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.cfg)
CONFIG += $(wildcard $(SRCDIR)/*.cfg)
# Select CONFIG file to use. Target specific configs have higher priority.
ifneq ($(word 2,$(CONFIG)),)
CONFIG := $(firstword $(CONFIG))
$(info Using config file $(CONFIG) for linking)
endif
.SUFFIXES:
.PHONY: all test clean zap love
all: $(PROGRAM)
-include $(DEPENDS)
-include $(STATEFILE)
# If OPTIONS are given on the command line then save them to STATEFILE
# if (and only if) they have actually changed. But if OPTIONS are not
# given on the command line then load them from STATEFILE. Have object
# files depend on STATEFILE only if it actually exists.
ifeq ($(origin OPTIONS),command line)
ifneq ($(OPTIONS),$(_OPTIONS_))
ifeq ($(OPTIONS),)
$(info Removing OPTIONS)
$(shell $(RM) $(STATEFILE))
$(eval $(STATEFILE):)
else
$(info Saving OPTIONS=$(OPTIONS))
$(shell echo _OPTIONS_=$(OPTIONS) > $(STATEFILE))
endif
$(eval $(OBJECTS): $(STATEFILE))
endif
else
ifeq ($(origin _OPTIONS_),file)
$(info Using saved OPTIONS=$(_OPTIONS_))
OPTIONS = $(_OPTIONS_)
$(eval $(OBJECTS): $(STATEFILE))
endif
endif
# Transform the abstract OPTIONS to the actual cc65 options.
$(foreach o,$(subst $(COMMA),$(SPACE),$(OPTIONS)),$(eval $(_$o_)))
# Strip potential variant suffix from the actual cc65 target.
CC65TARGET := $(firstword $(subst .,$(SPACE),$(TARGETLIST)))
# The remaining targets.
$(TARGETOBJDIR):
$(call MKDIR,$@)
vpath %.c $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
$(TARGETOBJDIR)/%.o: %.c | $(TARGETOBJDIR)
cl65 -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(CFLAGS) -o $@ $<
vpath %.s $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
$(TARGETOBJDIR)/%.o: %.s | $(TARGETOBJDIR)
cl65 -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $<
vpath %.asm $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
$(TARGETOBJDIR)/%.o: %.asm | $(TARGETOBJDIR)
cl65 -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $<
vpath %.a65 $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
$(TARGETOBJDIR)/%.o: %.a65 | $(TARGETOBJDIR)
cl65 -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $<
$(PROGRAM): $(CONFIG) $(OBJECTS) $(LIBS)
cl65 -t $(CC65TARGET) $(LDFLAGS) -o $@ $(patsubst %.cfg,-C %.cfg,$^)
test: $(PROGRAM)
$(PREEMUCMD)
$(EMUCMD)
$(POSTEMUCMD)
clean:
$(call RMFILES,$(OBJECTS))
$(call RMFILES,$(DEPENDS))
$(call RMFILES,$(REMOVES))
$(call RMFILES,$(PROGRAM))
else # $(words $(TARGETLIST)),1
all test clean:
$(foreach t,$(TARGETLIST),$(MAKE) TARGETS=$t $@$(NEWLINE))
endif # $(words $(TARGETLIST)),1
OBJDIRLIST := $(wildcard $(OBJDIR)/*)
zap:
$(foreach o,$(OBJDIRLIST),-$(call RMFILES,$o/*.o $o/*.d $o/*.lst)$(NEWLINE))
$(foreach o,$(OBJDIRLIST),-$(call RMDIR,$o)$(NEWLINE))
-$(call RMDIR,$(OBJDIR))
-$(call RMFILES,$(basename $(PROGRAM)).* $(STATEFILE))
love:
@echo "Not war, eh?"
###################################################################
### Place your additional targets in the additional Makefiles ###
### in the same directory - their names have to end with ".mk"! ###
###################################################################
-include *.mk

21
Makefile-dsk.mk Normal file
View File

@ -0,0 +1,21 @@
DSK = $(NAME).dsk
# For this one, see https://applecommander.github.io/
AC ?= ac.jar
# Unix or Windows
ifeq ($(shell echo),)
CP = cp $1
else
CP = copy $(subst /,\,$1)
endif
REMOVES += $(DSK)
.PHONY: dsk
dsk: $(DSK)
$(DSK): $(NAME).apple2
$(call CP, apple2/template.dsk $@)
java -jar $(AC) -p $@ $(NAME).system sys < $(NAME).apple2.loader
java -jar $(AC) -as $@ $(NAME) bin < $(NAME).apple2

274
README.md Normal file
View File

@ -0,0 +1,274 @@
# Manic Miner
Remake of the ZX Spectrum game for the Apple II.
1. INTRODUCTION
This is a game I have always loved, from the moment I saw it in a computer shop
back in the 80's. I once made an okay Commodore 64 version, in C, but this
version is a rewrite from the ground up for the Apple II, in 6502 assembly
language and I am very pleased with the outcome.
This is my first color program for the Apple II. Another learning experience :)
2. CURRENT STATUS
The game is complete.
There's a pre-built Apple II disk of the project, mminer.dsk under the
releases tab. This can be played directly in emulators.
3. DIFFERENCES FROM THE ORIGINAL
There are several differences that all have to do with Apple II hardware
limitations.
In the Apple II version, the title screen is not the high resolution picture
with the animated piano keyboard. Instead it uses the ZX Spectrum loading
screen, which has the words Manic and Miner bounce up and down. I do use the
hires screen for loading though, so it is just the opposite way ;)
The reason for not using the high resolution picture is due to a memory
limitation. If I did use some of the ROM memory for RAM, I could probably fix
this, but I didn't want to trash ProDOS and I didn't want to have to reboot the
Apple II when the program is quit.
The biggest differences have to do with the screen and keys.
The ZX Spectrum has a 32 column, 8 pixel per column, color display (256 pixels).
The Apple II can only display 20 7-pixel color columns (140 pixels). This means
I cannot fit the level on-screen at any given time. The level does need to
scroll as you play through it.
I have settled on a 3 zone scrolling method. As Willy enters a zone, the screen
will quickly scroll to the proper "camera position" for the zone Willy is in.
However, if you press the C key, the scrolling method toggles to one where the
game tries to keep Willy more or less in the middle of the screen - so as you
move around the center of the room, the game scrolls the screen all the time.
This method may be better suited to learning a room.
The scrolling method I use scrolls the game in "game columns" which means 2
bytes at a time. This is a rather coarse scroll. I did spend a lot of effort
on making run-time duplicates off all instanced data that allowed me to do a
1-byte scroll. Sadly, this turned out to be even worse as the motion became
very jerky a lot more frequently.
For the curious - if you want to draw a green line on the Apple II, starting at
column 0, for 7 pixels, you need to write the following 2 bytes (bit
representation): %00101010 %01010101. However, if you want that green line
starting at column 1, you need to write the bytes in the other order, i.e.
%01010101 %00101010. To get the speed I need, I have all data to be rendered
stored as instances that I can "blast" to the screen quickly. For a 1-byte
scroll, the whole screen needs to be rendered with the image bytes reversed, so
I needed more memory to make the reverse second set. And then that didn't pay
off :(
About the keys - The ZX Spectrum version requires keys to be held down to move.
The Apple II doesn't have a concept of keys being held down. You only know when
a key is pressed, not when it's released so you cannot tell what state a key is
in. You can also only detect one key press at a time.
In order to make the game play with the key limitation, I use the keys as
toggles. If you press P, Willy will start and keep walking, as though you are
keeping the key down. Pressing P again will stop Willy, as though you had let
go of the P key. My Apple IIe does have auto-repeat so actually holding down
the P key has an undesirable effect of stutter-walking.
I also made the game remember keys so that you can anticipate a key-press (like
you would steer early in Pac Man). This works very well but it can also cause
grief. For example, if you press Jump while in a jump, but you land somewhere
unexpected, you will still jump because of the stored anticipated jump. If, of
course, you are quick enough, just pressing the key again before it activates
would cancel the anticipation.
All in all, the key and scroll system makes the game fun and playable, I think,
as much as is possible given the limitations.
4. TECHNICAL DETAILS
The game is written in 6502 assembly language using the ca65 assembler. The
game uses memory from $0800 to $B52C.
Below is a CPU cycle profile of 1 game frame in stage 1 after a couple of
seconds of being on the level. The door isn't visible so this renders only the
one enemy and Willy, as well as the level tiles. The auidoPlayNote includes an
artificial delay that's based on the number of tiles rendered. If I didn't have
that, the really empty levels such as SkyLab would play the in-game music way
too fast. However, this does mean that the game experience is smoother with the
music turned off, since there's no artificial delay.
Hex | Dec | Frame % | Item
--- | --- | --- | ---
18A72 | 100978 | 100% | Total Frame
18 | 24 | 0% | inputGet
E8 | 232 | 0% | willyMove
80 | 128 | 0% | gameAI
5EF3 | 24307 | 24% | screenClear
123 | 291 | 0% | tilesAnimateKeys
47 | 71 | 0% | tilesAnimateConveyor
6EB | 1771 | 2% | screenDrawSprites
C55 | 3157 | 3% | screenDrawWilly
C6FD | 50941 | 50% | screenDrawLevel
DDA | 3546 | 4% | uiUpdate
3A | 58 | 0% | screenDrawSprite (door)
26 | 38 | 0% | screenSwap
51BD | 20925 | 21% | audioPlayNote
As can be seen, clearing the area where the world will be drawn takes almost 24%
of the frame and drawing the level tiles takes about 50% of the frame!
5. KEYS
After the intro music on the title screen, the game has a scrolling ticker that
shows help and keys, but these are the keys:
* Q or O - Move Willy left
* W or P - Move Willy right
* Space - Jump
* B - Toggle Black and White / Color mode
* C - Toggle scrolling mode
* M - Turn the music on/off
* S - Turn in-game audio on/off
* ESC - Quit level or in UI, return to ProDOS
The game also supports the cheat mode, as in the original. In game, enter the
cheat code 6031769 and a boot will appear next to the lives at the bottom of the
screen. Cheat mode is now enabled. Press the 6 key to start the cheat. Now
use the keys 12345 to enter the binary value for the level (0 through 19). Key
one sets bit 0, so it's reversed.
Once the appropriate room has been selected, press 6 again to start playing that
level. Note that the cheat cannot be turned off and also that the Game Win
Sequence (once you beat the last level) is disabled if you cheated. To see
that, you really have to beat all levels!
Here's a "cheat sheet" for the binary to access a level. If you enter a room
number greater than 20, the room is reset to room 0.
Cheat Key (binary 0-19 reverse) | 12345
--- | ---
Central Cavern | 00000
The Cold Room | 10000
The Menagerie | 01000
Abandoned Uranium Workings | 11000
Eugenes Lair | 00100
Processing Plant | 10100
The Vat | 01100
Miner Willy meets the Kong | 11100
Wacky Amoebatrons | 00010
The Endorian Forest | 10010
Attack of the Mutant Telephones | 01010
Return of the Alien Kong Beast | 11010
Ore Refinery | 00110
Skylab Landing Bay | 10110
The Bank | 01110
The Sixteenth Cavern | 11110
The Warehouse | 00001
Amoebatrons Revenge | 10001
Solar Power Generator | 01001
The Final Barrier | 11001
6. THE FILES
I tried to thoroughly comment all the code.
There are actually 2 programs in this. The 1st is the game, and it's in
src/apple2.
* audio.inc - Routines to make the speaker beep
* defs.inc - Constants and definitions used throughout
* game.inc - The in-game logic, AI etc. The bulk of the "game"
* input.inc - User controls for game and editor
* level.inc - Decompress a level and place the keys
* logo.hgr - 8Kb splash screen in HGR format
* logo.inc - File that simply does an incbin on logo.hgr
* mminer.asm - Where the game starts, initial setup, etc.
* mminer.cfg - ca65 configuration file
* roaudio.inc - Frequency and timing data for music and SFX
* rofont.inc - A ZX Spectrum font
* rolevels.inc - Level layout, tile usage, sprite positions, etc.
* rosprites.inc - Sprite definitions
* rosystem.inc - Helper tables (multiplication, color masks, etc.)
* rotext.inc - All text used in the game
* rotiles.inc - Background tile definitions
* screen.inc - Code related to drawing tiles, sprites, etc.
* sprite.inc - Code for making instances of sprites, coloring them, etc.
* text.inc - In game text and print functions
* ui.inc - User facing screens (title, scroller)
* variables.inc - All variables (scores, instance buffers, positions, etc.)
* Willy.inc - All logic relating to the movement of the main character, Willy
The second is the ProDos loader that will auto-load the game. It's in the
src/apple2.loader folder. It has these files (all provided to me by Oliver
Schmidt)
* loader.cfg - ca65 configuration file
* loader.s - file to load and start the game
7. BUILDING THE GAME
Making the game has a few steps. Use make and the Makefile on all OSs, that
would be the easiest.
Start by making the loader - this needs to be done once only.
make TARGETS=apple2.loader
Next, make the game with:
make
The next step is to make a bootable disk image. For this, you will need 3rd
party software. I use AppleCommander. This software will put the loader and
game into the disk image. You will need to install Java to use AppleCommander.
The apple2/template.dsk is a "blank ProDos floppy" that has the loader and the
game placed on it by AppleCommander.
To make the disc image, set an environment variable to point at apple commander
(see notes) and then use the command:
make dsk
This will make a disc named mminer.dsk which can be loaded up in an emulator.
If you want to edit the code and get into some iterative development/testing,
you can edit the Makefile. Look for, and change, apple2_EMUCMD. It is
currently configured to work with AppleWin and the path to AppleWin is expected
to be in an environment variable called APPLEWIN_HOME. Edit variables as
necessary.
If you use AppleWin and you have sed installed, you can also uncomment the
PREEMUCMD := sed... command which will copy the game symbols to the emulator for
use.
Once done, you can build and play the game with the command: make dsk test
NOTES:
1) Find AppleCommander here (I used Version 1.6.0):
https://github.com/AppleCommander/AppleCommander/releases
2) Set the environment variable (or change the Makefile-dsk.md) to point at the
apple commander jar file. Here's how it's done for different shell's:
Powershell:
$env:AC = "path to apple commander.jar"
cmd.exe
set AC="path to apple commander.jar"
bash (Unix or MacOS terminal):
export AC="path to apple commander.jar"
8. CREDITS
* Matthew Smith and BUG-BYTE for creating and publishing the game in
1983. Matthew later re-released the game with minor tweaks under the
Software Projects banner. This is not that version.
* A special call-out to Oliver Schmidt who provided me with invaluable
advice and support.
* Bill Buckels for Bmb2HDR which I used to make the logo HGR from my
GIMP exported BMP.
* Everyone involved in the Apple II projects (AppleWin | AppleCommander).
* Everyone involved in making the cc65 tools, it's very good.
9. CONTACT
Feel free to contact me at swessels@email.com if you have thoughts or
suggestions.
Thank you
Stefan Wessels
21 April 2020 - Initial Revision

BIN
apple2/template.dsk Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
#################################################################################
# #
# LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) #
# #
#################################################################################
MEMORY {
LOADER: start = $2000, size = $0200, file = %O;
}
SEGMENTS {
CODE: load = LOADER, type = ro;
DATA: load = LOADER, type = rw;
}

179
src/apple2.loader/loader.s Normal file
View File

@ -0,0 +1,179 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; LOADER.SYSTEM - an Apple][ ProDOS 8 loader for cc65 programs (Oliver Schmidt) ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
A1L := $3C
A1H := $3D
PATHNAME := $0280
MLI := $BF00
TXTCLR := $C050 ; Display graphics
TXTSET := $C051 ; Display text
MIXCLR := $C052 ; Disable 4 lines of text
LOWSCR := $C054 ; Page 1
HISCR := $C055 ; Page 2
HIRES := $C057 ; Hires graphics
VERSION := $FBB3
RDKEY := $FD0C
PRBYTE := $FDDA
COUT := $FDED
QUIT_CALL = $65
OPEN_CALL = $C8
READ_CALL = $CA
CLOSE_CALL = $CC
FILE_NOT_FOUND_ERR = $46
; ------------------------------------------------------------------------
.data
OPEN_PARAM:
.byte $03 ;PARAM_COUNT
.addr PATHNAME ;PATHNAME
.addr $4000 - $0400 ;IO_BUFFER
OPEN_REF: .byte $00 ;REF_NUM
READ_PARAM:
.byte $04 ;PARAM_COUNT
READ_REF: .byte $00 ;REF_NUM
.addr $4000 ;DATA_BUFFER
.word $FFFF ;REQUEST_COUNT
.word $0000 ;TRANS_COUNT
CLOSE_PARAM:
.byte $01 ;PARAM_COUNT
CLOSE_REF: .byte $00 ;REF_NUM
QUIT_PARAM:
.byte $04 ;PARAM_COUNT
.byte $00 ;QUIT_TYPE
.word $0000 ;RESERVED
.byte $00 ;RESERVED
.word $0000 ;RESERVED
LOADING:
.byte $0D
.asciiz "Loading "
ELLIPSES:
.byte " ...", $0D, $0D, $00
FILE_NOT_FOUND:
.asciiz "... File Not Found"
ERROR_NUMBER:
.asciiz "... Error $"
PRESS_ANY_KEY:
.asciiz " - Press Any Key "
; ------------------------------------------------------------------------
.code
; Reset stack
ldx #$FF
txs
; Remove ".SYSTEM" from pathname
lda PATHNAME
sec
sbc #.strlen(".SYSTEM")
sta PATHNAME
; Add trailing '\0' to pathname
tax
lda #$00
sta PATHNAME+1,x
; Provide some user feedback
lda #<LOADING
ldx #>LOADING
jsr PRINT
lda #<(PATHNAME+1)
ldx #>(PATHNAME+1)
jsr PRINT
lda #<ELLIPSES
ldx #>ELLIPSES
jsr PRINT
jsr MLI
.byte OPEN_CALL
.word OPEN_PARAM
bcc :+
jmp ERROR
; Copy file reference number
: lda OPEN_REF
sta READ_REF
sta CLOSE_REF
; Turn off 80-column firmware
lda VERSION
cmp #$06 ; //e ?
bne :+
lda #$15
jsr $C300
; Switch to hires page 2
: bit TXTCLR
bit MIXCLR
bit HISCR
bit HIRES
jsr MLI
.byte READ_CALL
.word READ_PARAM
bcs ERROR
jsr MLI
.byte CLOSE_CALL
.word CLOSE_PARAM
bcs ERROR
; Go for it ...
jmp $6000
PRINT:
sta A1L
stx A1H
ldx VERSION
ldy #$00
: lda (A1L),y
beq :++
cpx #$06 ; //e ?
beq :+
cmp #$60 ; lowercase ?
bcc :+
and #$5F ; -> uppercase
: ora #$80
jsr COUT
iny
bne :-- ; BRA
: rts
ERROR:
bit TXTSET
bit LOWSCR
cmp #FILE_NOT_FOUND_ERR
bne :+
lda #<FILE_NOT_FOUND
ldx #>FILE_NOT_FOUND
jsr PRINT
beq :++ ; BRA
: pha
lda #<ERROR_NUMBER
ldx #>ERROR_NUMBER
jsr PRINT
pla
jsr PRBYTE
: lda #<PRESS_ANY_KEY
ldx #>PRESS_ANY_KEY
jsr PRINT
jsr RDKEY
jsr MLI
.byte QUIT_CALL
.word QUIT_PARAM

141
src/apple2/audio.inc Normal file
View File

@ -0,0 +1,141 @@
;-----------------------------------------------------------------------------
; audio.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc audioPlayTitleNote
fixedDuration = srcPtrL
noteDuration = srcPtrH
freqTimer1 = dstPtrL
freqTimer2 = dstPtrH
ldy #0 ; load the duration
lda (musicL), y
beq reset ; on 0, the song is done
sta noteDuration
lda audioMask ; see if the note should be played or simply delayed
and #AUDIO_MUSIC
bne :+ ; audio is on, go play
jsr uiDelay ; waste time as though a note was played
jmp leave ; and move the audio pointer along
:
iny ; load the 1st timer
lda (musicL), y
sta freqTimer1
iny ; load the second timer
lda (musicL), y
sta freqTimer2
preplay:
lda #$8A ; repeat minimum this much
sta fixedDuration
play:
lda SPEAKER ; toggle the speaker
dec freqTimer1 ; timer1 down
bne :++ ; not zero, go to timer 2
ldy #1 ; reset timer 1
lda (musicL), y
sta freqTimer1
ldx #11 ; delay about 20 clock cycles
:
dex
bne :-
:
dec freqTimer2 ; dec timer 2
bne :++ ; not zero?
ldy #2 ; at zero, reset timer 2
lda (musicL), y
sta freqTimer2
ldx #11 ; and waste 20 clock cycles
:
dex
bne :-
:
dec fixedDuration ; dec the fixed repeat count
bne play ; not zero, do another loop
dec noteDuration ; dec the note delay
bne preplay ; do more loops of at least fixedDuration
leave:
clc
lda musicL ; add 3 to the music pointer
adc #3
sta musicL
bcc :+
inc musicH
clc ; leave with carry clear
:
rts
reset:
lda #<titleMusic ; played the whole tune
sta musicL ; reset to start of tune
lda #>titleMusic
sta musicH
sec ; and leave with carry set
rts
.endproc
;-----------------------------------------------------------------------------
.proc audioPlayNote
delayTime = tmpBot + 0
lda audioMask ; see if the music is on
and #AUDIO_MUSIC
bne :+
rts ; if not, return
:
lda #$FF ; calculate a delay
sec ; based on how many tiles were rendered
sbc tilesRendered ; this lets the music sound
cmp #80 ; better, esp. when a level is
bcc :+ ; very sparse (SkyLab for example)
lsr
lsr
lsr
lsr
tay
jsr uiDelay::ySet
:
ldx musicL ; get the index into the in-game music
inc musicL ; and advance that index
lda inGameMusic, x ; get the note at the index
bne :+ ; if non-zero it's a valid note
sta musicL ; reset the index to the start of the song
beq :-
:
ldy #$08 ; fixed number of iterations
freq: ; external entry point for custom fixed iterations/delay
sta delayTime ; store it in a delay counter
lda audioMask ; see if
and #AUDIO_SOUND ; audio is enabled
bne loop ; and play or ignore audio accordingly
rts
loop:
lda SPEAKER ; toggle the speaker
ldx delayTime ; and load the delay
:
dex ; count down
bne :- ; to zero
dey ; then repeat
bne loop ; for the fixed iterations
rts ; and return
.endproc

116
src/apple2/defs.inc Normal file
View File

@ -0,0 +1,116 @@
;-----------------------------------------------------------------------------
; defs.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
HGRPage1 := $2000
HGRPage2 := $4000
MLI := $BF00
SPEAKER := $C030
PLACEHOLDER := $FFFF
;-----------------------------------------------------------------------------
; Cheat Key (binary 0-19 reverse) 12345
LEVEL_Central_Cavern := 0 ; 00000
LEVEL_The_Cold_Room := 1 ; 10000
LEVEL_The_Menagerie := 2 ; 01000
LEVEL_Abandoned_Uranium_Workings := 3 ; 11000
LEVEL_Eugenes_Lair := 4 ; 00100
LEVEL_Processing_Plant := 5 ; 10100
LEVEL_The_Vat := 6 ; 01100
LEVEL_Miner_Willy_meets_the_Kong := 7 ; 11100
LEVEL_Wacky_Amoebatrons := 8 ; 00010
LEVEL_The_Endorian_Forest := 9 ; 10010
LEVEL_Attack_of_the_Mutant_Telephones := 10 ; 01010
LEVEL_Return_of_the_Alien_Kong_Beast := 11 ; 11010
LEVEL_Ore_Refinery := 12 ; 00110
LEVEL_Skylab_Landing_Bay := 13 ; 10110
LEVEL_The_Bank := 14 ; 01110
LEVEL_The_Sixteenth_Cavern := 15 ; 11110
LEVEL_The_Warehouse := 16 ; 00001
LEVEL_Amoebatrons_Revenge := 17 ; 10001
LEVEL_Solar_Power_Generator := 18 ; 01001
LEVEL_The_Final_Barrier := 19 ; 11001
LEVEL_Game_Over := 20
;-----------------------------------------------------------------------------
DATA_BLANK := $00
DATA_FLOOR1 := $10
DATA_FLOOR2 := $20
DATA_CONVEYOR := $30
DATA_WALL := $40
DATA_BUSH := $50
DATA_ROCK := $60
DATA_COLLAPSE := $70
DATA_KEY := $80
DATA_SWITCH1 := $90
DATA_SWITCH1_OPEN := $A0
DATA_SWITCH2 := $B0
DATA_SWITCH2_OPEN := $C0
DATA_DOOR := $D0
;-----------------------------------------------------------------------------
START_LIVES := 2
MAX_LIVES := 5
PLAY_ROWS := 16
PLAY_COLS := 32
VISIBLE_COLS := 20
TILES_PER_LEVEL := 8
TILE_BYTES := 16
CONVEYOR_FRAMES := 7
KEYS_FRAMES := 4
MAX_SPRITES := 10
SPRITE_BYTES := 64
MAX_SPRITE_IFRAMES := 36
AIR_STR_LEN := 5
AIR_SPEED := 14
DEMO_TIMER_DURATION := 2
DEMO_TIMER_INITAL := 18
;-----------------------------------------------------------------------------
CLASS_MOVE_Y := <bit0Mask
CLASS_FOUR_FRAME := <bit1Mask
CLASS_UNUSED := <bit2Mask
CLASS_HOLDATEND := <bit3Mask
CLASS_EUGENE := <bit4Mask
CLASS_KONG := <bit5Mask
CLASS_SKYLAB := <bit6Mask
CLASS_DOOR := <bit7Mask
;-----------------------------------------------------------------------------
CAMERA_MODE_3_ZONE := 0
CAMERA_MODE_SCROLL := 1
;-----------------------------------------------------------------------------
EVENT_OK := 0
EVENT_DIED := 1 << 0
EVENT_LEVEL_RESTART := 1 << 1
EVENT_NEXT_LEVEL := 1 << 2
EVENT_EXIT_GAME := 1 << 3
EVENT_CHEAT_JUMP := 1 << 4
;-----------------------------------------------------------------------------
UI_COMPONENT_NAME := 1 << 0
UI_COMPONENT_AIR_NAME := 1 << 1
UI_COMPONENT_AIR := 1 << 2
UI_COMPONENT_SCORE_NAME := 1 << 3
UI_COMPONENT_SCORE := 1 << 4
UI_COMPONENT_LIVES := 1 << 5
UI_COMPONENT_HIGHSCORE := 1 << 6
;-----------------------------------------------------------------------------
MASK_RIGHT := 1 << 0 ; bit0Mask
MASK_LEFT := 1 << 1 ; bit1Mask
MASK_AIR := 1 << 2 ; bit2Mask
;-----------------------------------------------------------------------------
AUDIO_MUSIC := $80
AUDIO_SOUND := $40

849
src/apple2/game.inc Normal file
View File

@ -0,0 +1,849 @@
;-----------------------------------------------------------------------------
; game.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc gameLoop
jsr gameNewGame ; init things that need 1-time game init
nextLevel:
jsr tilesPrepForLevel ; move 8 tiles for this level to tilesInstances
restart:
jsr gameInitStage ; init the stage, incl unpacking the level, tile prep etc
playLoop:
jsr inputGet ; read the keyboard
lda demoMode ; check for demo mode
beq :+ ; if not demo, move willy
jsr gameDemoTick ; tick the demo if demo mode
jmp :++ ; skip moving willy
:
jsr willyMove ; move the main character based on user input (or conveyor or gravity)
:
jsr gameAI ; run all the monster AI
ldx fullScreenClearCount ; get the flag for what level of screen clear is needed
jsr screenClear ; and clear the screen
jsr tilesAnimateKeys ; copy the 16 bytes for the next "key" frame into place
jsr tilesAnimateConveyor ; update the conveyor tile
jsr screenDrawSprites ; draw all the enemies
lda demoMode ; get the event state
bne :+ ; if so skip showing willy
jsr screenDrawWilly ; not demo - draw willy with collision detection
bcc :+ ; carry set is a collision, clear is no problem
lda eventState ; on collision, set the die event
ora #EVENT_DIED
sta eventState
:
jsr screenDrawLevel ; show all the tiles
lda updateUICount ; see if the UI needs an update
beq :+
jsr uiUpdate ; if needed, update the appropriate UI components
:
ldx numSprites ; The door's index
jsr screenDrawSprite ; render the door over everything else, no collision
jsr screenSwap ; swap to the newly rendered screen
jsr audioPlayNote ; play in-game music if needed
lda eventState ; see if any events fired
beq playLoop ; keep looping while no events
jsr gameEvent ; process the event, return value in a
bit bit1Mask ; EVENT_LEVEL_RESTART
bne restart
bit bit2Mask ; EVENT_NEXT_LEVEL
bne nextLevel
lda demoMode ; no Game Over when the demo ends
bne :+
jsr gameOver ; wasn't a demo, show Game Over
:
jsr textCheckHighScore ; game over - see if a new high score was set
rts
.endproc
;-----------------------------------------------------------------------------
.proc gameNewGame
lda #START_LIVES ; init player number of lives
sta lives
lda #LEVEL_Central_Cavern ; Init these game vars to 0
sta currLevel
lda #0 ; audioPlayNote uses muiscL as well
sta musicL ; track progress through in-game song
ldx #5 ; six, zero-based score digits
lda #'0' ; load a with '0'
:
sta score, x ; set all 6 score digits to '0'
dex
bpl :-
rts
.endproc
;-----------------------------------------------------------------------------
.proc gameInitStage
count = tmpBot + 0
spriteIdx = tmpBot + 1
instanceIdx = tmpBot + 2
ldy currLevel ; Skip some stuff for "Game Over" pseudo-level
cpy #20
bcs notDemo
jsr levelUnpack ; decompress a level to levelLayout
jsr levelPlaceKeys ; put the keys into the world
jsr textSetLevelText ; create the gfx cache for the name
ldy currLevel ; tables are indexed by level
lda demoMode ; see if this is demo mode
beq notDemo ; branch if game
lda willyx ; use willy screen 0 for willyXPos in demo (force leftEdge to 0)
bne :+
notDemo:
lda willyx, y ; set willy X up
:
sta willyXPos
ldx cameraMode
lda #CAMERA_MODE_SCROLL
sta cameraMode
jsr willyMove::positionScreen ; set the screen position based on willy's X
stx cameraMode
lda willyy, y ; set willy's Y
sta willyYPos
lda willyStartDir, y ; and see what facing direction
sta willyDir
beq :+ ; if right (0) then set that as the animFrame
lda #4 ; if left (1) set the anim frame to 4
:
sta willyFrame ; and save the anim frame
postWilly:
lda #3 ; AI will count down and runs before clearScreen
sta fullScreenClearCount ; so set to 3 to get full clear on both buffers
lda #AIR_SPEED ; set counter for ticking down air
sta airFlow
lda #32 ; set how many air cols there are
sta airCols
lda #$7f ; the air "bar" tip is a character that draws less
sta airTipGfx ; bar over time, till it rolls to the prev column
lda #$ff ; match all masks
jsr uiUpdateComponent ; so force all UI elements to draw
lda level_sprites_count, y ; get how many enemy sprites the level has
sta count ; save for init
sta numSprites ; save for the game to use
dec numSprites ; make this count 0 based
lda level_sprites_offset, y ; see where in the sprite tables this sprite starts
tay ; move the offset into x - sprite tables indexed by this
ldx #0 ; y will be an enemy instance index
stx eventState ; init he event state
stx livesFrame ; but use this 0 to init some variables
stx movementMask ; current movement for willy
stx conveyorMask ; direction conveyor under willy is moving (0=no conveyor under willy)
stx userKeyMask ; keys the user has pressed to move willy
stx willyJumpCounter ; 0 means no jump, 1-18 is in a jump, beyond is a fall height
stx spriteFramesIdx
clc ; clear carry - will always enter below with carry clear
next:
sty spriteIdx ; save which sprite is being processed (x clobbered)
stx instanceIdx ; save y, also clobbered
lda #0
sta spriteFrame, x ; init the sprite specific frame counter to 0
lda sprites_x, y ; load the basic sprite variables and put into zero page
sta spriteXPos, x ; from 0 .. numSprites - 1
lda sprites_y, y ; the addressing is unfortunate - sta ,x is zero-page 2 byte
sta spriteYPos, x ; but it's not worth swapping x and y for this bit of code
lda sprites_min, y
sta spriteMin, x
lda sprites_max, y
sta spriteMax, x
lda sprites_speed, y
sta spriteSpeed, x
sta spriteTick, x
lda sprites_dir, y
sta spriteDir, x
lda sprites_class, y
sta spriteClass, x
lda sprites_colors, y ; get the color
sta spriteColor, x
lda sprites_bitmaps, y ; get the index into the sprite data for this sprite's images
jsr spriteInstanceSpriteFrames
ldx instanceIdx ; restore y
cpx numSprites
beq prep
lda spriteClass, x
bit bit1Mask ; CLASS_FOUR_FRAME
beq :+
lda #4
bne :++
:
lda #8
:
adc spriteFramesIdx, x
sta spriteFramesIdx + 1, x
ldy spriteIdx
iny ; next sprite in sprite table
inx ; next instance
dec count
beq prep
jmp next
prep:
ldx currLevel ; some levels need special handling
cpx #LEVEL_Eugenes_Lair ; eugene needs colored copies
bne :+
jsr spriteEugeneSetup
jmp fixDoor
:
cpx #LEVEL_Miner_Willy_meets_the_Kong ; kong levels need switches
beq kong
cpx #LEVEL_Return_of_the_Alien_Kong_Beast
bne :+
kong:
lda #DATA_SWITCH1
sta levelLayout + 6
lda #DATA_SWITCH2
sta levelLayout + 18
jmp fixDoor
:
cpx #LEVEL_Skylab_Landing_Bay ; skylab needs satellites to get X values
bne :+
ldx #2 ; init the falling satellites
skyLabPos:
lda skylabXPos, x
sta spriteXPos, x
txa
sta spriteTick, x
dex
bpl skyLabPos
:
cpx #LEVEL_The_Final_Barrier
bne fixDoor
dec numSprites ; hide the victory door sprite
fixDoor:
jmp spriteDoorSetup ; sprites are set up - door is special
.endproc
;-----------------------------------------------------------------------------
.proc gameAI
lda fullScreenClearCount ; get the state
beq :+ ; if it's zero, move on
dec fullScreenClearCount ; count this down
:
dec airFlow ; deal with the air countdown. airFlow is "time" counter
bne airDone
jsr gameAirDecrease
airDone:
inc livesFrame ; move the lives anim frame along
lda livesFrame ; through the first 4 frames only
cmp #16 ; by dividing by 4 (in essence) to get a slower animation
bcc :+
lda #0 ; start at frame 0 when wrapping
:
sta livesFrame
and #3 ; only update every 4 frames (not & 3)
bne :+
lda #UI_COMPONENT_LIVES ; tell ui to update lives
jsr uiUpdateComponent
:
ldx numSprites ; now set up all the sprites for this level
loop:
lda spriteClass, x ; start with the class
bit CLASS_DOOR ; and if it's a door, treat that separate
beq :+
jmp door
:
bit CLASS_MOVE_Y ; see if it moves vertically
beq horizontal ; no - then it moves horizontally
jmp vertical ; yes - them move it vertically
horizontal:
lda spriteSpeed, x ; get speed
bit bit0Mask ; Is the speed 1
beq rtick ; if not, advance this sprite
dec spriteTick, x ; dec the ticker
bpl next ; if ge 0 then ignore sprite
sta spriteTick, x ; reset ticker to speed and fall through to run
rtick:
lda spriteDir, x ; get the direction
bne left ; 1 is left, 0 is right
right:
inc spriteFrame, x ; move the frame
lda spriteFrame, x ; load it
cmp #4 ; see if it's 4
bcc next ; if 4+, done here
inc spriteXPos, x ; up the x position
lda spriteXPos, x ; load it
cmp spriteMax, x ; see if it's ge max
bcs rightEnd ; if yes, end of going right
lda #0 ; no, reset
sta spriteFrame, x ; frame to 0
beq next ; BRA. done with this sprite
rightEnd:
dec spriteXPos, x ; set back to last valid x
lda #1 ; load left
sta spriteDir, x ; and set direction left
lda #7 ; 7 is most right position of sprite
sta spriteFrame, x ; and set the frame to that
fix4:
lda spriteClass, x ; get the class
bit CLASS_FOUR_FRAME ; see if it has the (only) 4 frames flag set
beq next ; if not, done with this sprite (frame 7 is good)
lda #3 ; drop the 7 to 3
sta spriteFrame, x ; set the frame
jmp next
left:
dec spriteFrame, x ; move the frame
lda spriteFrame ,x ; load it
cmp #$ff ; see if it is now lt 0 (3,2,1 -> 0 overflow)
beq stepLeft ; if it is, move the col left
cmp #3 ; if it's 3, (7,6,5,4 -> 3 overflow)
bne next ; if not, done with this sprite
stepLeft:
dec spriteXPos, x ; move the column left
lda spriteXPos, x ; load it
cmp spriteMin, x ; compare to minimum
bcc leftEnd ; if less than minimum, too far, past the left edge
lda #7 ; keep going, load 7
sta spriteFrame ,x ; set frame back to 7
bne fix4 ; BRA, and check for a 4-frame sprite
leftEnd:
inc spriteXPos, x ; put the column back to in range
lda #0 ; load 0
sta spriteDir, x ; set as direction (right)
sta spriteFrame, x ; and frame (most left frame)
beq next ; BRA, done with this sprite
postVMove:
lda spriteClass, x ; after a vertical update check these special cases
bit CLASS_EUGENE ; Eugene
bne eugene
bit CLASS_KONG ; Kong
beq :+
jmp kong
:
bit CLASS_SKYLAB ; skylab
beq :+
jmp skylab
:
inc spriteFrame, x ; otherwise go to next frame
lda spriteFrame, x
and #3
sta spriteFrame, x
next:
dex ; get previous sprite
bpl goTop ; if ge 0 then still a sprite to process
rts ; all sprites done - exit
goTop:
jmp loop
vertical:
lda spriteDir, x ; get direction 1 = UP, 0 = DOWN
beq down
bmi postVMove ; if the spriteDir is lt $ff, stationary sprite
up:
lda spriteYPos, x ; get the Y position
sec
sbc spriteSpeed, x ; move up by the speed
cmp spriteMin, x ; see if at top
bcc upEnd ; overshot top
sta spriteYPos, x ; update Y position
bcs postVMove ; BRA
upEnd:
lda spriteClass, x ; get the class
bit CLASS_HOLDATEND ; should it stop or bounce
bne stop ; HOLDATEND means stop
lda #0 ; change direction
sta spriteDir, x ; to DOWN (0)
beq postVMove ; BRA
down:
lda spriteYPos, x ; get the Y
clc
adc spriteSpeed, x ; add the speed
cmp spriteMax, x ; see of at end
bcs downEnd ; at or past end
sta spriteYPos, x ; still good, update Y position
bcc postVMove ; BRA
downEnd:
lda spriteClass, x ; same as upEnd
bit CLASS_HOLDATEND
bne stop
lda #1 ; but mark for moving UP (1)
sta spriteDir, x
bne postVMove ; BRA maybe down?
stop:
lda #$ff ; set the direction to -1 (lt 0)
sta spriteDir, x
bne postVMove ; BRA
door:
lda keysToCollect ; check if all keys have been collected
bne next ; no - nothing more to do
frameToggle:
dec spriteTick, x ; count down for animation
bpl next ; gt 0, nothing more
lda spriteFrame, x ; get the frame
eor #1 ; toggle between 1 and 0
sta spriteFrame, x ; update the frame
lda spriteSpeed, x ; get the anim speed
sta spriteTick, x ; save it to the tick
jmp next
eugene:
lda keysToCollect ; eugene changes behavior when all keys collected
bne eugeneNormal ; not all keys, carry on
lda #0 ; all keys - force eugene down
sta spriteDir, x
inc spriteFrame, x ; cycle through the 5 colors
lda spriteFrame, x
cmp #4
bcc :+
lda #0
:
sta spriteFrame, x ; save the new frame
eugeneNormal:
jmp next
kong:
lda spriteMax, x ; if kong's max is 0 he's still up
beq frameToggle
lda spriteDir, x ; if he's not up see what his direction is
bpl kongFall ; gt 0, then he's still falling
cmp #$FE ; $fe he's been erased so done with him
beq kongDone ; $ff he's just reached the bottom
dec spriteDir, x ; turn $ff into $fe
txa ; put the sprite index into a
pha ; and save it
lda spriteFramesIdx, x ; get the index to the 1st kong frame
tax ; put that in x
inx ; and skip the 2 frames where
inx ; kong is standing
ldy #2 ; want to clear 2 frames
jsr spriteClearFrames ; and make the falling frames blank
pla ; get the sprite index
tax ; and put it back in x
kongDone:
jmp next
kongFall:
ldx #3 ; digit 3 (100's)
lda #1 ; add 1
jsr textAddScore ; add to score
lda #UI_COMPONENT_SCORE ; show changes
jsr uiUpdateComponent
jmp frameToggle
skylab:
lda spriteDir, x ; get the direction of the falling satellite
cmp #$ff ; see if it's reached its end
beq :+ ; yes it has
jmp next
:
inc spriteFrame, x ; advance the collapsing frame
lda spriteFrame, x ; load that frame
cmp #8 ; see if it's the last
bcs :+ ; yes
jmp next
:
lda spriteTick, x ; get the tick (hich is an index in this case)
clc
adc #3 ; advance by 3 (3 satellites at a time) so next index for this satellite
cmp #12 ; (3*4 is 12) - there are 4 stating locations per satellite
bcc :+ ; not rolled over
and #3 ; reset this satellite to 1st starting location (index)
:
sta spriteTick, x ; save the tick
tay ; put into Y
lda skylabXPos, y ; get the actual start position, based on y, for this satellite
sta spriteXPos, x ; put that into the satellite
lda #0 ; reset the frame, position and direction all to 0
sta spriteFrame, x
sta spriteYPos, x
sta spriteDir, x
jmp next
.endproc
;-----------------------------------------------------------------------------
.proc gameDemoTick
dec demoTimer ; timer counts down
bne :+ ; if not yet zero, nothing to do
lda #DEMO_TIMER_DURATION ; reset the timer
sta demoTimer
lda #UI_COMPONENT_NAME ; mark the level name as needing an update
jsr uiUpdateComponent
lda leftEdge ; scroll the screen
clc
adc demoDirection ; based on the scrolling direction
sta leftEdge
beq nextDemoLevel ; if the edge is 0 then done with level
cmp #12 ; at 12, the level flips scroll direction
bne :+
lda #$ff ; at 12, the scroll direction becomes -1
sta demoDirection
:
rts
nextDemoLevel:
lda #DEMO_TIMER_INITAL ; set for a longer initial hold at a new level
sta demoTimer
lda #1 ; set the scroll direction to be right (1)
sta demoDirection
lda #0 ; set the edge to be the very left
sta leftEdge
lda #EVENT_NEXT_LEVEL ; fire a new level event
ora eventState
sta eventState
rts
.endproc
;-----------------------------------------------------------------------------
.proc gameEvent
bit bit0Mask ; EVENT_DIED
beq :+ ; if not, must be end of level
dec lives ; died, so take a life
bmi died ; all lives lost ends the game
lda #0
sta tmpBot
jsr screenInvertVisibleScreen
lda #EVENT_LEVEL_RESTART ; still alive so restart the level
rts
:
bit bit4Mask ; EVENT_CHEAT_JUMP
bne done ; if jumping, just go
lda currLevel ; check the level
cmp #19 ; is this the last level
bcc :+ ; if not, go to screen invert
lda cheatActive ; last level - got here by cheating?
bne :+ ; yes - go screen invert
lda demoMode ; is this demo mode?
bne :+ ; yes - go to screen invert
jsr gameVictory ; played properly through, get the victory
:
ldx #8 ; do an inverse screen effect
:
stx sizeL
txa
and #3
clc
adc #1
sta tmpBot
jsr screenInvertVisibleScreen
ldx sizeL
dex
bne :-
lda demoMode ; is this demo mode
bne incLevel ; skip the air/score, just go to next level
nextLevel:
jsr screenSwap::valueSwap ; do the air countdown/add score routine now, on front screen
airLoop:
ldx #5 ; digit 5 (1's)
lda #7 ; add 7
jsr textAddScore ; add to score
ldx #4 ; digit 4 (10's)
lda #1 ; add 1 (so add 17 per tick)
jsr textAddScore ; add to score
jsr gameAirDecrease ; run the decrease air
lda airCols ; get the remaining bar length
asl ; mult * 4
asl
eor #$7f ; and reverse (ignore MSB which is 0) - this is the freq
ldy #6 ; duration for the freq
jsr audioPlayNote::freq ; make a sound of this freq and duration
jsr uiUpdate ; and show the updates
lda eventState ; get the event state
bit bit0Mask ; check for EVENT_DIED
beq airLoop ; not dead means more air left
jsr screenSwap::valueSwap ; go back to the back screen
incLevel:
inc currLevel ; set the current level to the next
ldx currLevel
cpx #20 ; see if this is the last level + 1
bcc done ; if not, all is well
lda demoMode ; check again for demo
beq :+ ; if not, roll over to level 1 and keep playing
died:
lda #EVENT_DIED ; demo also ends with a death event
rts
:
ldx #0 ; not demo, past last level, start at 1st level again
stx currLevel
done:
lda #EVENT_NEXT_LEVEL ; return in a the action (next level)
rts
.endproc
;-----------------------------------------------------------------------------
.proc gameAirDecrease
lda #AIR_SPEED
sta airFlow
lda #UI_COMPONENT_AIR ; tick the air down, so update the UI
jsr uiUpdateComponent
ldx airCols ; see if it's an odd or even column
inx ; but the air draws from an odd column so the 1 bit is backwards
txa
and #1
tax ; x 0 is even, x 1 is odd
lda airTipGfx ; see what the tip looks like
cmp maskGreen, x ; if it's all green, time to drop another column
beq colDec
lsr ; not all green, so adjust the tip by dropping 2 bits (1 white pixel)
lsr
ora maskGreenHi, x ; and replace that with a green pixel (appropriate for odd/even column)
bne airOk
colDec:
dec airCols ; one less bar
bpl :+
lda eventState ; out of air causes death
ora #EVENT_DIED
sta eventState
lda #0
sta airCols ; lock airCols at 0
lda maskGreen, x ; lock to all green for the tip
bne airOk
:
lda maskNewTip, x ; start a new (mostly white) tip, appropriate for odd/even
airOk:
sta airTipGfx
rts
.endproc
;-----------------------------------------------------------------------------
.proc gameOver
iter = currLevel ; how many times to loop
bootPart:
ldx #20 ; game over level is 20 (0 based)
stx currLevel
jsr gameInitStage
ldx #0 ; clear the top part of the screen
jsr screenClear
ldx #0 ; draw the boot
jsr screenDrawSprite
ldx #$60 ; start of boot-drop freq
stx iter
lda #1 ; pretend there's a key so Boot (EUGENE) doesn't animate
sta keysToCollect ; and the "door" doesn't switch to the second frame
tax ; also draw the pedestal (door)
jsr screenDrawSprite ; draw the boot
lda #2 ; set willy to frame 2
sta willyFrame
jsr screenDrawWilly ; show willy on the pedestal
jsr screenSwap ; make it all visible
jsr screenSwap::valueSwap ; fake the front as the back
bootLoop:
jsr gameAI ; run the AI to move the boot down
dec iter ; raise freq
dec iter
lda audioMask ; see if the audio will play or skip
and #AUDIO_SOUND
beq otherDelay ; audio won't delay so "fake" an audio delay
lda iter ; get the freq
ldy #$80 ; duration for the freq (also slows the boot down)
jsr audioPlayNote::freq ; make a sound of this freq and duration
jmp :+
otherDelay:
lda iter
lsr
lsr
tay
jsr uiDelay::ySet
:
ldx #0 ; go draw the boot
jsr screenDrawSprite
lda spriteDir ; see if the boot has reached the pedestal
bpl bootLoop ; net yet, keep going
gameOverPart:
color = tmpBot + 1 ; index into color masks arrays
xPos = tmpBot + 2 ; x for string
yPos = tmpBot + 3 ; y for string
textL = tmpBot + 4 ; string pointer
textH = tmpBot + 5
len = tmpBot + 6 ; how many characters (0 based)
lda #$20
sta iter ; how many times to loop
lda #(7*8) ; Y for string
sta yPos
lda #4 ; starting color
sta color
cycleLoop:
lda #4 ; print GAME at x 4
sta xPos
lda #<roTextGame ; point at GAME text
sta textL
lda #>roTextGame
sta textH
lda #4 ; 0-3 characters
sta len
jsr textColorCycle ; show the text in color
lda #13 ; print OVER at x 13
sta xPos
lda #<roTextOver ; point at OVER text
sta textL
lda #>roTextOver
sta textH
lda #4 ; also 0-3 characters in length
sta len
jsr textColorCycle ; and show over with color
ldy #$30 ; delay the iteration of color
jsr uiDelay::ySet
dec iter ; one less iteration to do
bpl cycleLoop ; do all iterations
rts
.endproc
;-----------------------------------------------------------------------------
.proc gameVictory
lda #19 ; put willy above the door
sta willyXPos ; outside the caverns
lda #0
sta willyFrame
lda #2*8
sta willyYPos
ldx fullScreenClearCount ; get the flag for what level of screen clear is needed
jsr screenClear ; and clear the screen
jsr screenDrawSprites ; draw all the enemies
jsr screenDrawWilly ; not demo - draw willy with collision detection
jsr screenDrawLevel ; show all the tiles
ldx numSprites ; The door's index
inx
jsr screenDrawSprite ; render the door over everything else, no collision
jsr screenSwap ; swap to the newly rendered screen
audioPart:
freq = tmpBot + 0 ; freq
duration = tmpBot + 1 ; duration
iteration = tmpBot + 2 ; iteration
lda #50 ; 50 iterations
sta iteration
lda #0 ; init freq and duration
sta freq
sta duration
loop:
lda duration ; start with the duration
adc iteration ; add the iteration counter * 3
adc iteration
adc iteration
sta freq ; save as the freq
ldy duration ; put duration in Y
lda audioMask ; see if the audio will play or skip
and #AUDIO_SOUND
bne audioOn ; if on, use the freq "API"
:
ldx freq ; a bit ridiculous to redo playNote stuff here
:
dex ; but I want the audio code to all go through the
bne :- ; same "API" for consistency
dey
bne :--
beq postFreq
audioOn:
lda freq
jsr audioPlayNote::freq ; make the sound if sound enabled
postFreq:
dec iteration ; dec the iterations
bne loop ; loop till all iterations done
rts
.endproc

231
src/apple2/input.inc Normal file
View File

@ -0,0 +1,231 @@
;-----------------------------------------------------------------------------
; input.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc inputGet
lda KBD
bmi hasKey
lda cheatActive ; is the cheat code active
beq :+ ; no - normal play
lda cheatIndex ; is the 6 down
beq :+ ; no - normal play
jmp setJmpEvent ; cheat active and 6 down - keep resetting to this level
:
rts
hasKey:
bit KBDSTRB
and #$5f ; strip MSB and upper/lower case (to upper)
tax
lda demoMode
beq :+
jmp premusic
:
txa
bne right ; $5f clears space so a is 0 for jump
jump:
lda userKeyMask
eor #MASK_AIR ; AIR marks the start of a jump
sta userKeyMask
rts
right:
cmp #'W' ; go right with w (left handed) or P
beq :+
cmp #'P'
bne left
:
lda userKeyMask
and #<~MASK_LEFT ; clear left
eor #MASK_RIGHT ; activate right
sta userKeyMask
rts
left:
cmp #'Q' ; go left with q (left handed) or o
beq :+
cmp #'O'
bne camera
:
lda userKeyMask
and #<~MASK_RIGHT ; clear right
eor #MASK_LEFT ; activate left
sta userKeyMask
rts
camera:
cmp #'C' ; c toggles the scroll mode
bne cheat ; if not c maybe cheat?
lda #1 ; xor the camera mode with 1
eor cameraMode
sta cameraMode
rts ; done, can't be any other key
cheat:
ora #%00100000 ; make "normal" characters
ldx cheatActive ; see if the cheat mode is on
bne checkJump ; if yes, see if a jump needs to happen
ldx cheatIndex ; active, not on
cmp roTextCheatCode, x ; is this the next cheat code character
bne resetCheat ; no, reset the cheat
inx ; yes
stx cheatIndex ; inc the index
cpx #7 ; all 7 typed
beq :+ ; yes
rts ; not yet, so done here
:
ldx #1 ; make the cheat active
stx cheatActive
resetCheat:
ldx #0 ; set the cheat index to 0
stx cheatIndex
jumpNotActive:
and #%11011111 ; restore the acc to uppercase
bne music ; BRA
checkJump:
cmp #'6' ; is this a 6
beq jumpToggle ; if yes, toggle the jump mode on/off
bcs jumpNotActive ; gt 6, then nothing to do with cheat
ldx cheatIndex ; is 6 down
beq jumpNotActive ; no, process as non-cheat key
cmp #'1'
bcc jumpNotActive ; less than 1, not cheat code
sec
sbc #'1' ; make key 0 based
tax ; and index in x
lda bitMasks, x ; get the appropriate bit
eor currLevel ; and toggle in the current level
cmp #20 ; if the level ge 20 then set to 0
bcc :+
lda #0
:
sta currLevel
setJmpEvent:
lda #EVENT_CHEAT_JUMP ; set the jump event active
ora eventState
sta eventState
rts
jumpToggle:
lda #1 ; prep to toggle the jump state
eor cheatIndex
sta cheatIndex ; save it
beq :+ ; is it off, just leave
lda #0 ; just turned on, reset
sta currLevel ; the level to level 0
:
rts
premusic:
txa ; restore the read-key
music:
cmp #'M' ; m toggles music on/off
bne :+
LDA audioMask
eor #AUDIO_MUSIC
sta audioMask
rts
:
cmp #'B'
bne :+
lda #1
eor monochrome
sta monochrome
jmp tilesPrepForLevel
:
cmp #'S' ; s toggles in-game sound on/off
bne :+
LDA audioMask
eor #AUDIO_SOUND
sta audioMask
rts
:
cmp #$1B ; ESC
beq quit ; quit game or demo
lda demoMode ; see if this is demo
beq done ; if not, ignore all other keys, demo quit on any key
quit:
lda #0 ; set lives to zero so this die event quits
sta lives
inc demoMode ; turn demo mode if not on, so there's no end-of-level stuff
lda eventState ; and make a death event
ora #EVENT_DIED
sta eventState
done:
rts
.endproc
;-----------------------------------------------------------------------------
.proc inputUI
loop = currLevel
lda KBD ; Get the keyboard
bpl okay ; and ignore no keys
bit KBDSTRB ; reset the keyboard
and #$5f ; strip MSB and case bit
cmp #'M' ; see if it's the music toggle
bne :+
lda audioMask
eor #AUDIO_MUSIC
sta audioMask
okay:
lda #0 ; no key or M or m returns 0
rts
:
cmp #'B' ; b in the UI toggles color/mono
bne :+
lda #1
sta currLevel ; in UI so abuse currLevel as a counter
eor monochrome ; toggle mono/color
sta monochrome
beq showColor
showMono:
printXY #7, #(17*8), roTextMono, #4 ; show Mono on screen
jsr screenSwap::valueSwap ; fake swap
dec currLevel ; and do twice so both buffers updated
bpl showMono
jmp doneB
showColor:
printXY #7, #(17*8), roTextColor, #4 ; show Color on in both buffers
jsr screenSwap::valueSwap
dec currLevel
bpl showColor
doneB:
lda #0 ; if all is well, return with 0 in a
rts
: ; non-music/color toggle key
cmp #$1b ; see if it's esc
beq exit ; exit if it is
stop:
lda #1 ; non-M, B or ESC (non toggle) returns 1 (start game)
rts
exit:
lda #$ff ; -1 on ESC (quit application)
rts
.endproc

123
src/apple2/level.inc Normal file
View File

@ -0,0 +1,123 @@
;-----------------------------------------------------------------------------
; level.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
; "decompress" the stored level into a usable level in levelLayout
.proc levelUnpack
value = sizeL
len = sizeH
ldx currLevel
lda #<levelLayout ; point at the level decode area
sta store + 1
lda #>levelLayout
sta store + 2
lda levelsL, x ; get the start of the level data intp srcPtr
sta srcPtrL
lda levelsH, x
sta srcPtrH
ldx #0 ; start at 0 in read and write area
ldy #0
loop:
lda (srcPtrL), y ; read the first level byte (repeat counts)
beq done ; $00 ends level
pha ; save
iny ; point y at next byte
lsr ; get high repeat nibble into low nibble
lsr
lsr
lsr
tax ; but result in X
lda (srcPtrL), y ; read the next byte from level (values)
sta value ; save
iny ; advance y to next rep counts
lsr ; get high value nibble into low nibble
lsr
lsr
lsr
jsr :+ ; store value repeat times into level decode area
pla ; restore the rep byte
and #$0f ; only the low nibble
tax ; put in x
lda value ; restore values
and #$0f ; only low nibble
jsr :+ ; store value repeat times into level decode area
jmp loop ; repeat
:
stx len ; save the repeat count
tax ; value into x (value is a tile index)
lda mult16, x ; mult value by 16 as that's how wide a tile is
ldx len ; restore the repeat count
dex ; store index is 0+ but count is 1+ so pre-dec
store:
sta PLACEHOLDER, x ; store the tile offset into the level decode area
dex ; from back to front and
bpl store ; repeat for all repetitions
lda len ; get the repeat length
clc
adc store + 1 ; advance the stor pointer by the length
sta store + 1
bcc done
inc store + 2
done:
rts ; return to self or caller
.endproc
;-----------------------------------------------------------------------------
.proc levelPlaceKeys
lda #0
sta keysToCollect ; init to 0 keys to collect
lda currLevel
asl ; * 2
asl ; * 4
adc currLevel ; * 5 - index into key table
tax ; keep index in x
lda #4 ; Need to do 5 keys, 0-4
sta sizeL ; save count in sizeL
ldy #0 ; keep offst from ptr at 0
:
lda keyyH, x ; get the key Y hi (y=row*32 in key table)
bmi next ; if $ff then skip
inc keysToCollect ; count the key
sta dstPtrH ; save the hi
lda keyyL, x ; get the y lo
adc keyx, x ; and add the x (no carry still)
sta dstPtrL ; save as dst pointer
lda #>levelLayout ; get the scratch hi (the lo is 0 as it's aligned)
adc dstPtrH ; and add to the Y hi (and any carry)
sta dstPtrH ; and save as the dst Pointer Hi
lda #8*16 ; key tile offset * width of a tile
sta (dstPtrL), y ; poke into the unpacked level
next:
inx ; next key
dec sizeL ; one less key to do
bpl :- ; all keys done?
rts
.endproc

BIN
src/apple2/logo.hgr Normal file

Binary file not shown.

41
src/apple2/logo.inc Normal file
View File

@ -0,0 +1,41 @@
;-----------------------------------------------------------------------------
; logo.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "HGR"
.incbin "logo.hgr"
;-----------------------------------------------------------------------------
.segment "RODATA"
manicText:
.byte $88, $D8, $A8, $88, $88, $00, $00
.byte $00, $70, $88, $88, $F8, $88, $00
.byte $88, $C8, $A8, $98, $88, $00, $00
.byte $00, $00, $E0, $40, $40, $40, $E0
.byte $00, $70, $88, $80, $88, $70, $00
manicCharWidth:
.byte 6, 6, 6, 4, 5
manicColors:
.byte 2, 1, 0, 3, 4
;-----------------------------------------------------------------------------
minerText:
.byte $00, $00, $88, $D8, $A8, $88, $88
.byte $E0, $40, $40, $40, $E0, $00, $00
.byte $00, $88, $C8, $A8, $98, $88, $00
.byte $F8, $80, $F8, $80, $F8, $00, $00
.byte $00, $00, $F0, $88, $F0, $A0, $98
minerCharWidth:
.byte 6, 4, 6, 6, 5
minerColors:
.byte 3, 4, 2, 1, 0

89
src/apple2/mminer.asm Normal file
View File

@ -0,0 +1,89 @@
;-----------------------------------------------------------------------------
; mminer.asm
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc main
jsr mainInit ; do some one-time global init
jsr uiWaitForIntroEnter ; color cycle ENTER and wait for key
loop:
jsr uiTitleScreen ; go to the ui
and #EVENT_EXIT_GAME ; see if event to exit game is set
bne quit
jsr gameLoop ; not quit, so run the gameplay (or demo)
jmp loop ; go back to the ui
quit:
jsr MLI ; quit using the prodos mli
.byte $65 ; ProDOS Quit request
.addr * + 2
.byte 4
.byte 0
.word 0000
.byte 0
.word 0000
.endproc
;-----------------------------------------------------------------------------
.include "apple2.inc" ; cc65 include file for LOWSCR, etc
.include "logo.inc" ; loading bitmap, manic miner bouncy text
.include "defs.inc" ; globally used defines
.include "variables.inc" ; all game variables and buffers
.include "roaudio.inc" ; all ro files read only. This music and sfx
.include "rofont.inc" ; ZX Spectrum font
.include "rolevels.inc" ; level layout, sprite positions, colors, etc.
.include "rosprites.inc" ; sprite definitions
.include "rosystem.inc" ; useful tables for mult, color masks, etc.
.include "rotext.inc" ; all in-game text (except scores in variables)
.include "rotiles.inc" ; all tile (background) definitions
.include "screen.inc" ; code to draw, clear, etc. the screen
.include "text.inc" ; code to manipulate and show text
.include "input.inc" ; keyboard handling
.include "level.inc" ; unpack level and put keys in place
.include "sprite.inc" ; instance and color sprites, etc.
.include "tiles.inc" ; put right tiles in place and color, etc.
.include "ui.inc" ; all pre-game screens
.include "audio.inc" ; play the music and make tones
.include "willy.inc" ; user controlled character logic
.include "game.inc" ; game flow, ai, game over, etc.
;-----------------------------------------------------------------------------
.proc mainInit
lda #0 ; init some one-time globals
sta backPage
sta leftEdge
sta cameraMode
sta uiComponent
sta cheatActive
sta cheatIndex
sta monochrome
lda #AUDIO_MUSIC | AUDIO_SOUND ; turn the music and in-game sounds on
sta audioMask
lda #>HGRPage1 ; set the current hidden (back) page to page 1
sta currPageH ; (page 2 was made visible by the loader)
lda #$80 ; make a zero-page bit mask area for checking bits
ldx #7 ; from 1 to 128, set each bit (backwards)
:
sta bitMasks, x ; set the bits in the area called bitMasks
lsr
dex
bpl :-
rts
.endproc

19
src/apple2/mminer.cfg Normal file
View File

@ -0,0 +1,19 @@
SYMBOLS {
__EXEHDR__: type = import;
__FILETYPE__: type = export, value = $0006;
}
MEMORY {
ZP: file = "", start = $0050, size = $0100 - $0050;
HEADER: file = %O, start = $4000 - $003A, size = $003A;
MAIN: file = %O, define = yes, start = $4000, size = $BF00 - $4000;
LOW: file = "", start = $0800, size = $2000 - $0800;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
EXEHDR: load = HEADER, type = ro;
HGR: load = MAIN, type = rw;
CODE: load = MAIN, type = rw, start = $6000;
RODATA: load = MAIN, type = ro, align = $10;
DATA: load = MAIN, type = rw;
LOWMEM: load = LOW, type = rw;
}

68
src/apple2/roaudio.inc Normal file
View File

@ -0,0 +1,68 @@
;-----------------------------------------------------------------------------
; roaudio.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "RODATA"
;-----------------------------------------------------------------------------
titleMusic:
.byte $50, $80, $81, $50, $66, $67, $50, $56
.byte $57, $32, $56, $57, $32, $AB, $CB, $32
.byte $2B, $33, $32, $2B, $33, $32, $AB, $CB
.byte $32, $33, $40, $32, $33, $40, $32, $AB
.byte $CB, $32, $80, $81, $32, $80, $81, $32
.byte $66, $67, $32, $56, $57, $32, $60, $56
.byte $32, $AB, $C0, $32, $2B, $30, $32, $2B
.byte $30, $32, $AB, $C0, $32, $30, $44, $32
.byte $30, $44, $32, $AB, $C0, $32, $88, $89
.byte $32, $88, $89, $32, $72, $73, $32, $4C
.byte $4D, $32, $4C, $4D, $32, $AB, $C0, $32
.byte $26, $30, $32, $26, $30, $32, $AB, $C0
.byte $32, $30, $44, $32, $30, $44, $32, $AB
.byte $C0, $32, $88, $89, $32, $88, $89, $32
.byte $72, $73, $32, $4C, $4D, $32, $4C, $4D
.byte $32, $AB, $CB, $32, $26, $33, $32, $26
.byte $33, $32, $AB, $CB, $32, $33, $40, $32
.byte $33, $40, $32, $AB, $CB, $32, $80, $81
.byte $32, $80, $81, $32, $66, $67, $32, $56
.byte $57, $32, $40, $41, $32, $80, $AB, $32
.byte $20, $2B, $32, $20, $2B, $32, $80, $AB
.byte $32, $2B, $33, $32, $2B, $33, $32, $80
.byte $AB, $32, $80, $81, $32, $80, $81, $32
.byte $66, $67, $32, $56, $57, $32, $40, $41
.byte $32, $80, $98, $32, $20, $26, $32, $20
.byte $26, $32, $80, $98, $32, $26, $30, $32
.byte $26, $30, $32, $00, $00, $32, $72, $73
.byte $32, $72, $73, $32, $60, $61, $32, $4C
.byte $4D, $32, $4C, $99, $32, $4C, $4D, $32
.byte $4C, $4D, $32, $4C, $99, $32, $5B, $5C
.byte $32, $56, $57, $32, $33, $CD, $32, $33
.byte $34, $32, $33, $34, $32, $33, $CD, $32
.byte $40, $41, $32, $66, $67, $64, $66, $67
.byte $32, $72, $73, $64, $4C, $4D, $32, $56
.byte $57, $32, $80, $CB, $19, $80, $00, $19
.byte $80, $81, $32, $80, $CB, $00
inGameMusic:
.byte $E6, $CD, $B7, $AC, $9A, $B7, $9A, $9A
.byte $91, $AC, $91, $91, $9A, $B7, $9A, $9A
.byte $E6, $CD, $B7, $AC, $9A, $B7, $9A, $9A
.byte $91, $AC, $91, $91, $9A, $9A, $9A, $9A
.byte $E6, $CD, $B7, $AC, $9A, $B7, $9A, $9A
.byte $91, $AC, $91, $91, $9A, $B7, $9A, $9A
.byte $E6, $CD, $B7, $AC, $9A, $B7, $9A, $73
.byte $9A, $B7, $E6, $B7, $9A, $9A, $9A, $9A
.byte $00
jumpFreq:
.byte $40, $40, $38, $38, $30, $30, $28, $28
.byte $20, $20, $28, $28, $30, $30, $38, $38
.byte $40, $40
fallFreq:
.byte $F4, $FF, $4C, $58, $64, $70, $7C, $88
.byte $94, $A0, $AC, $B8, $C4, $D0, $DC, $E8

971
src/apple2/rofont.inc Normal file
View File

@ -0,0 +1,971 @@
;-----------------------------------------------------------------------------
; rofont.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "RODATA"
;-----------------------------------------------------------------------------
font:
font00:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
font01:
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
font02:
.byte $80, $80 ; -------------- = --------------
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
font03:
.byte $80, $80 ; -------------- = --------------
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $80, $80 ; -------------- = --------------
font04:
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $C0, $99 ; X--------XX--X = ------XX--XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $C0, $81 ; X------------X = ------XX------
font05:
.byte $80, $80 ; -------------- = --------------
.byte $8F, $98 ; ---XXXX--XX--- = XXXX------XX--
.byte $8F, $86 ; ---XXXX----XX- = XXXX----XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $8C, $9E ; ---XX----XXXX- = --XX----XXXX--
.byte $83, $9E ; -----XX--XXXX- = XX------XXXX--
.byte $80, $80 ; -------------- = --------------
font06:
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $FC, $99 ; XXXXX----XX--X = --XXXXXX--XX--
.byte $80, $80 ; -------------- = --------------
font07:
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
font08:
.byte $80, $80 ; -------------- = --------------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $80 ; -------------- = --------------
font09:
.byte $80, $80 ; -------------- = --------------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $80, $80 ; -------------- = --------------
font0A:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $80, $80 ; -------------- = --------------
font0B:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
font0C:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
font0D:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
font0E:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $80, $80 ; -------------- = --------------
font0F:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $80, $80 ; -------------- = --------------
font10:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $9E ; -----XX--XXXX- = XX------XXXX--
.byte $C3, $99 ; X----XX--XX--X = XX----XX--XX--
.byte $B3, $98 ; -XX--XX--XX--- = XX--XX----XX--
.byte $8F, $98 ; ---XXXX--XX--- = XXXX------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font11:
.byte $80, $80 ; -------------- = --------------
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font12:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $80 ; -----XX------- = XX------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font13:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font14:
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
font15:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $83, $80 ; -----XX------- = XX------------
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font16:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $80 ; -----XX------- = XX------------
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font17:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
font18:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font19:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font1A:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
font1B:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $8C, $80 ; ---XX--------- = --XX----------
font1C:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $80 ; -------------- = --------------
font1D:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
font1E:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
font1F:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
font20:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $C3, $99 ; X----XX--XX--X = XX----XX--XX--
.byte $B3, $9E ; -XX--XX--XXXX- = XX--XX--XXXX--
.byte $F3, $9F ; XXX--XX--XXXXX = XX--XXXXXXXX--
.byte $83, $80 ; -----XX------- = XX------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font21:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
font22:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font23:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font24:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $81 ; XXXXXXX------X = XXXXXXXX------
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $FF, $81 ; XXXXXXX------X = XXXXXXXX------
.byte $80, $80 ; -------------- = --------------
font25:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $83, $80 ; -----XX------- = XX------------
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font26:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $83, $80 ; -----XX------- = XX------------
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $80, $80 ; -------------- = --------------
font27:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $80 ; -----XX------- = XX------------
.byte $C3, $9F ; X----XX--XXXXX = XX----XXXXXX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font28:
.byte $80, $80 ; -------------- = --------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
font29:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font2A:
.byte $80, $80 ; -------------- = --------------
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font2B:
.byte $80, $80 ; -------------- = --------------
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $BF, $80 ; -XXXXXX------- = XXXXXX--------
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
font2C:
.byte $80, $80 ; -------------- = --------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font2D:
.byte $80, $80 ; -------------- = --------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $8F, $9E ; ---XXXX--XXXX- = XXXX----XXXX--
.byte $F3, $99 ; XXX--XX--XX--X = XX--XXXX--XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
font2E:
.byte $80, $80 ; -------------- = --------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $8F, $98 ; ---XXXX--XX--- = XXXX------XX--
.byte $B3, $98 ; -XX--XX--XX--- = XX--XX----XX--
.byte $C3, $99 ; X----XX--XX--X = XX----XX--XX--
.byte $83, $9E ; -----XX--XXXX- = XX------XXXX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
font2F:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font30:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $80 ; -----XX------- = XX------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $80, $80 ; -------------- = --------------
font31:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $B3, $98 ; -XX--XX--XX--- = XX--XX----XX--
.byte $C3, $99 ; X----XX--XX--X = XX----XX--XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font32:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
font33:
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $80 ; -----XX------- = XX------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font34:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
font35:
.byte $80, $80 ; -------------- = --------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font36:
.byte $80, $80 ; -------------- = --------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $80, $80 ; -------------- = --------------
font37:
.byte $80, $80 ; -------------- = --------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $F3, $99 ; XXX--XX--XX--X = XX--XXXX--XX--
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $80, $80 ; -------------- = --------------
font38:
.byte $80, $80 ; -------------- = --------------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
font39:
.byte $80, $80 ; -------------- = --------------
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
font3A:
.byte $80, $80 ; -------------- = --------------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font3B:
.byte $80, $80 ; -------------- = --------------
.byte $C0, $9F ; X--------XXXXX = ------XXXXXX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $9F ; X--------XXXXX = ------XXXXXX--
.byte $80, $80 ; -------------- = --------------
font3C:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $83, $80 ; -----XX------- = XX------------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $80 ; -------------- = --------------
font3D:
.byte $80, $80 ; -------------- = --------------
.byte $BF, $80 ; -XXXXXX------- = XXXXXX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $BF, $80 ; -XXXXXX------- = XXXXXX--------
.byte $80, $80 ; -------------- = --------------
font3E:
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $FC, $81 ; XXXXX--------X = --XXXXXX------
.byte $B3, $86 ; -XX--XX----XX- = XX--XX--XX----
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
font3F:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
font40:
.byte $80, $80 ; -------------- = --------------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $FF, $81 ; XXXXXXX------X = XXXXXXXX------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font41:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font42:
.byte $80, $80 ; -------------- = --------------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font43:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $80, $80 ; -------------- = --------------
font44:
.byte $80, $80 ; -------------- = --------------
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font45:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $80, $80 ; -------------- = --------------
font46:
.byte $80, $80 ; -------------- = --------------
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $80 ; -------------- = --------------
font47:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
font48:
.byte $80, $80 ; -------------- = --------------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $80, $80 ; -------------- = --------------
font49:
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $80, $80 ; -------------- = --------------
font4A:
.byte $80, $80 ; -------------- = --------------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $80 ; -------------- = --------------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $86 ; -----------XX- = --------XX----
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $F0, $81 ; XXX----------X = ----XXXX------
font4B:
.byte $80, $80 ; -------------- = --------------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $80, $80 ; -------------- = --------------
font4C:
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $80, $80 ; -------------- = --------------
font4D:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $BC, $86 ; -XXXX------XX- = --XXXX--XX----
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $80, $80 ; -------------- = --------------
font4E:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $80, $80 ; -------------- = --------------
font4F:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $80, $80 ; -------------- = --------------
font50:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
font51:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $98 ; ---------XX--- = ----------XX--
font52:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $80, $80 ; -------------- = --------------
font53:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $80, $80 ; -------------- = --------------
font54:
.byte $80, $80 ; -------------- = --------------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $FC, $81 ; XXXXX--------X = --XXXXXX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $80, $80 ; -------------- = --------------
font55:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $80, $80 ; -------------- = --------------
font56:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
font57:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $80, $80 ; -------------- = --------------
font58:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $80, $80 ; -------------- = --------------
font59:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
font5A:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $86 ; -----------XX- = --------XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $80, $80 ; -------------- = --------------
font5B:
.byte $80, $80 ; -------------- = --------------
.byte $80, $9E ; ---------XXXX- = --------XXXX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $9E ; ---------XXXX- = --------XXXX--
.byte $80, $80 ; -------------- = --------------
font5C:
.byte $80, $80 ; -------------- = --------------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $80 ; -------------- = --------------
font5D:
.byte $80, $80 ; -------------- = --------------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $9E ; ---------XXXX- = --------XXXX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $80, $80 ; -------------- = --------------
font5E:
.byte $80, $80 ; -------------- = --------------
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
font5F:
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $B3, $E0 ; -XX--XXXX----- = XX--XX------XX
.byte $B3, $E0 ; -XX--XXXX----- = XX--XX------XX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----

578
src/apple2/rolevels.inc Normal file
View File

@ -0,0 +1,578 @@
;-----------------------------------------------------------------------------
; rolevels.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "RODATA"
level_01:
.byte $1A, $40, $14, $60, $1E, $60, $2F, $40, $F2, $04, $FF, $00, $2F, $40, $F2, $04
.byte $F7, $00, $13, $50, $13, $50, $2D, $41, $41, $71, $48, $71, $2F, $40, $F2, $04
.byte $3F, $10, $C2, $04, $F1, $00, $31, $40, $19, $50, $24, $41, $3F, $03, $53, $30
.byte $2F, $40, $D2, $01, $2F, $40, $F2, $04, $B1, $05, $73, $04, $53, $71, $24, $40
.byte $FB, $10, $2F, $40, $F2, $04, $FF, $11, $01, $04
.byte $00
level_02:
.byte $1F, $40, $3E, $04, $FE, $00, $12, $64, $FF, $00, $2F, $40, $53, $07, $16, $10
.byte $2F, $40, $F2, $04, $F4, $11, $81, $04, $22, $04, $F5, $00, $41, $14, $21, $74
.byte $22, $04, $15, $17, $F3, $00, $12, $40, $12, $40, $2F, $40, $91, $04, $21, $74
.byte $22, $04, $87, $01, $91, $04, $21, $74, $22, $04, $F3, $00, $42, $70, $12, $47
.byte $12, $40, $22, $40, $4F, $30, $31, $04, $21, $74, $22, $04, $D4, $01, $71, $04
.byte $21, $74, $22, $04, $74, $07, $F4, $00, $2F, $40, $F2, $04, $FF, $11, $01, $04
.byte $00
level_03:
.byte $19, $40, $17, $60, $18, $20, $13, $60, $2F, $40, $21, $06, $C2, $04, $FF, $00
.byte $2F, $40, $F2, $04, $FF, $00, $24, $41, $FB, $77, $2F, $40, $F2, $04, $6F, $10
.byte $54, $01, $21, $42, $FE, $00, $21, $42, $46, $03, $F4, $00, $21, $42, $F8, $00
.byte $62, $14, $1C, $60, $5C, $10, $24, $40, $6F, $10, $52, $04, $F5, $00, $A2, $14
.byte $FF, $00, $2F, $41, $F1, $14
.byte $00
level_04:
.byte $16, $40, $16, $60, $F4, $44, $FF, $00, $2F, $40, $F2, $04, $F3, $00, $66, $10
.byte $2F, $40, $B4, $01, $21, $41, $51, $01, $91, $01, $D2, $04, $B2, $01, $73, $01
.byte $72, $04, $3F, $70, $C2, $04, $62, $01, $F2, $00, $32, $10, $2F, $40, $23, $01
.byte $A2, $04, $3F, $30, $B1, $01, $2B, $40, $37, $10, $36, $10, $25, $40, $2F, $10
.byte $14, $60, $32, $14, $F2, $00, $2B, $10, $2F, $40, $F2, $04, $FF, $11, $01, $04
.byte $00
level_05:
.byte $1F, $40, $41, $06, $A2, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $2F, $40
.byte $81, $05, $62, $04, $D4, $10, $46, $71, $32, $04, $FD, $00, $22, $14, $F5, $00
.byte $19, $50, $2F, $40, $2A, $03, $32, $04, $3A, $01, $F2, $00, $2F, $40, $F2, $04
.byte $2B, $71, $47, $01, $51, $01, $27, $40, $1F, $40, $72, $04, $25, $10, $15, $40
.byte $12, $40, $1D, $40, $24, $40, $12, $50, $15, $40, $12, $40, $72, $45, $52, $04
.byte $7F, $14, $17, $41, $01, $04
.byte $00
level_06:
.byte $1F, $40, $F2, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $2F, $40, $51, $06
.byte $92, $04, $73, $01, $42, $01, $45, $01, $52, $04, $22, $01, $B1, $04, $B3, $01
.byte $2F, $40, $1E, $40, $2F, $40, $75, $01, $32, $04, $2F, $10, $D2, $04, $69, $01
.byte $19, $41, $52, $04, $F1, $04, $1D, $60, $22, $40, $1C, $50, $1B, $40, $32, $14
.byte $24, $03, $F2, $01, $72, $04, $FF, $00, $2F, $41, $F1, $14
.byte $00
level_07:
.byte $1D, $40, $F4, $44, $FF, $00, $2F, $40, $F2, $04, $E2, $01, $1C, $47, $12, $04
.byte $F1, $00, $1D, $47, $26, $40, $52, $30, $31, $14, $A1, $76, $22, $74, $3D, $10
.byte $12, $47, $1A, $07, $2F, $40, $11, $04, $91, $70, $32, $74, $1F, $10, $15, $47
.byte $17, $67, $2D, $40, $31, $14, $D2, $74, $B5, $10, $11, $47, $18, $07, $12, $67
.byte $2F, $40, $11, $04, $C1, $70, $2D, $40, $45, $47, $17, $67, $28, $40, $32, $10
.byte $1F, $40, $12, $04, $D1, $04, $F1, $00, $2D, $41, $F3, $44
.byte $00
level_08:
.byte $11, $40, $17, $60, $16, $60, $12, $40, $1A, $40, $2F, $40, $11, $04, $21, $04
.byte $A2, $04, $E2, $01, $1B, $40, $22, $14, $F1, $00, $1D, $40, $2F, $40, $11, $04
.byte $D2, $04, $35, $10, $62, $10, $12, $41, $B2, $04, $F1, $00, $13, $40, $45, $10
.byte $12, $14, $13, $01, $C1, $04, $91, $01, $32, $04, $73, $01, $61, $04, $D2, $04
.byte $F1, $00, $15, $41, $82, $04, $1A, $10, $32, $10, $19, $40, $42, $14, $82, $01
.byte $61, $04, $D2, $04, $32, $01, $B1, $04, $45, $01, $42, $04, $A3, $03, $12, $40
.byte $12, $41, $B2, $04, $D1, $04, $21, $04, $51, $05, $72, $04, $FF, $11, $01, $04
.byte $00
level_09:
.byte $12, $40, $1F, $40, $C2, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $2F, $40
.byte $F2, $04, $42, $10, $32, $10, $82, $10, $32, $10, $22, $10, $2F, $40, $F2, $04
.byte $FD, $00, $22, $14, $22, $01, $23, $01, $28, $03, $B2, $04, $F6, $00, $32, $10
.byte $22, $10, $22, $41, $FD, $00, $2F, $40, $F2, $04, $22, $01, $23, $01, $28, $01
.byte $23, $01, $22, $01, $22, $04, $FD, $00, $22, $14, $FF, $00, $2F, $41, $F1, $14
.byte $00
level_10:
.byte $1A, $40, $11, $60, $31, $14, $11, $06, $11, $06, $A2, $14, $F1, $04, $41, $06
.byte $92, $04, $69, $10, $1A, $40, $42, $14, $21, $06, $C1, $04, $E2, $04, $F1, $04
.byte $4A, $10, $27, $40, $17, $17, $16, $40, $82, $14, $4B, $10, $1E, $40, $2F, $40
.byte $17, $41, $34, $70, $25, $41, $A1, $04, $E2, $04, $17, $60, $71, $14, $C2, $01
.byte $24, $41, $29, $70, $17, $41, $61, $06, $2F, $40, $16, $40, $13, $67, $42, $04
.byte $7A, $02, $D2, $04, $3F, $10, $93, $01, $2F, $40, $F1, $04, $FF, $22, $02, $02
.byte $00
level_11:
.byte $7C, $40, $1B, $60, $2F, $40, $31, $05, $B2, $04, $FF, $00, $24, $41, $FB, $00
.byte $2F, $40, $F2, $04, $46, $01, $42, $01, $72, $21, $52, $04, $F8, $00, $14, $60
.byte $22, $14, $F8, $00, $16, $60, $22, $41, $22, $03, $F2, $00, $14, $60, $22, $14
.byte $A9, $01, $41, $05, $62, $04, $B1, $06, $61, $06, $81, $01, $22, $04, $53, $07
.byte $12, $10, $16, $60, $1B, $50, $2B, $40, $1F, $50, $32, $14, $2F, $10, $53, $01
.byte $52, $04, $FF, $00, $2F, $41, $F1, $14
.byte $00
level_12:
.byte $11, $40, $17, $60, $16, $60, $13, $40, $19, $40, $2F, $40, $F2, $04, $E2, $07
.byte $E2, $04, $FF, $00, $2F, $40, $F2, $04, $35, $10, $51, $74, $21, $04, $62, $71
.byte $52, $04, $D1, $04, $21, $04, $C1, $01, $25, $40, $26, $10, $12, $40, $1D, $40
.byte $22, $40, $1A, $10, $12, $40, $17, $40, $62, $14, $94, $01, $12, $40, $1D, $40
.byte $25, $40, $1A, $10, $13, $41, $A2, $04, $F1, $00, $17, $40, $24, $10, $26, $41
.byte $A1, $04, $51, $05, $41, $05, $22, $04, $A3, $01, $12, $40, $1B, $43, $22, $04
.byte $D1, $04, $21, $04, $D2, $04, $D4, $14, $D1, $14
.byte $00
level_13:
.byte $FF, $44, $32, $40, $1F, $20, $C2, $04, $21, $02, $FC, $00, $22, $40, $13, $20
.byte $F3, $11, $24, $01, $22, $40, $1F, $20, $C2, $04, $21, $02, $FC, $00, $22, $40
.byte $13, $20, $22, $10, $42, $10, $52, $10, $42, $10, $12, $14, $21, $02, $FC, $00
.byte $22, $40, $1F, $20, $C2, $04, $21, $02, $35, $01, $23, $01, $35, $01, $24, $01
.byte $22, $40, $1F, $20, $C2, $04, $21, $02, $FC, $00, $22, $40, $13, $20, $32, $10
.byte $32, $10, $42, $10, $42, $10, $22, $14, $21, $02, $FC, $00, $22, $40, $1F, $20
.byte $C2, $04, $2F, $13, $B2, $31, $01, $04
.byte $00
level_14:
.byte $1F, $40, $F2, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $2F, $40, $F2, $04
.byte $E1, $01, $1E, $20, $22, $40, $11, $12, $61, $01, $16, $20, $11, $12, $61, $01
.byte $12, $20, $26, $40, $11, $12, $E1, $01, $16, $20, $2F, $40, $F2, $04, $41, $01
.byte $16, $20, $11, $12, $61, $01, $16, $20, $11, $12, $2F, $40, $F2, $04, $11, $12
.byte $61, $01, $14, $20, $64, $30, $11, $12, $42, $04, $FF, $00, $26, $40, $11, $12
.byte $F7, $00, $2F, $40, $FF, $04, $F3, $44
.byte $00
level_15:
.byte $15, $40, $FC, $44, $FD, $00, $22, $24, $FD, $00, $22, $24, $7F, $03, $15, $31
.byte $22, $24, $71, $06, $F4, $00, $12, $62, $25, $41, $21, $05, $F4, $00, $12, $62
.byte $2F, $40, $82, $01, $21, $06, $22, $24, $61, $07, $42, $01, $E1, $06, $22, $24
.byte $22, $01, $D2, $01, $81, $06, $22, $24, $F9, $00, $21, $10, $12, $62, $22, $41
.byte $92, $01, $E1, $05, $22, $24, $F2, $00, $29, $10, $22, $24, $43, $01, $F2, $01
.byte $42, $02, $2B, $40, $2F, $10, $22, $24, $FD, $00, $22, $24, $FF, $11, $01, $04
.byte $00
level_16:
.byte $1F, $40, $F2, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $2F, $40, $F2, $04
.byte $14, $10, $14, $10, $12, $40, $17, $40, $36, $10, $2A, $40, $12, $40, $2F, $40
.byte $23, $40, $16, $10, $12, $40, $38, $40, $62, $14, $A1, $04, $24, $04, $D2, $04
.byte $2F, $73, $94, $30, $2F, $40, $F2, $04, $92, $04, $2C, $10, $14, $10, $29, $41
.byte $F6, $00, $2F, $40, $41, $01, $51, $01, $42, $04, $F7, $00, $35, $50, $2F, $41
.byte $F1, $14
.byte $00
level_17:
.byte $1F, $40, $D4, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $25, $40, $12, $50
.byte $13, $50, $12, $50, $15, $50, $11, $50, $16, $50, $22, $41, $72, $70, $72, $70
.byte $31, $70, $22, $70, $22, $14, $21, $76, $62, $70, $72, $70, $62, $70, $22, $74
.byte $92, $70, $31, $70, $32, $70, $51, $76, $22, $07, $22, $47, $25, $07, $22, $07
.byte $52, $30, $62, $70, $22, $74, $11, $07, $25, $07, $27, $07, $26, $07, $22, $07
.byte $22, $47, $25, $07, $27, $07, $12, $07, $14, $67, $22, $07, $22, $47, $24, $07
.byte $12, $60, $E3, $70, $22, $74, $22, $70, $52, $70, $F2, $70, $22, $74, $FF, $00
.byte $2F, $40, $B4, $01, $2F, $41, $F1, $14
.byte $00
level_18:
.byte $1F, $40, $C1, $04, $22, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $2F, $40
.byte $F2, $04, $22, $01, $23, $01, $28, $01, $23, $01, $24, $01, $2F, $40, $F2, $04
.byte $2F, $10, $D2, $04, $B8, $01, $23, $01, $22, $01, $22, $04, $22, $01, $23, $01
.byte $F6, $00, $2F, $40, $D2, $01, $2F, $40, $F2, $04, $22, $01, $23, $01, $28, $01
.byte $23, $01, $22, $01, $22, $04, $2F, $10, $D2, $04, $FF, $00, $1F, $41, $F2, $11
.byte $00
level_19:
.byte $3F, $40, $D2, $04, $FF, $00, $2F, $40, $F2, $04, $FF, $00, $2F, $40, $F2, $04
.byte $22, $01, $46, $01, $97, $01, $2F, $40, $F2, $04, $F3, $00, $39, $10, $22, $41
.byte $A3, $01, $87, $01, $2F, $40, $F2, $04, $F3, $00, $2A, $10, $24, $41, $F4, $00
.byte $72, $14, $64, $03, $35, $01, $C2, $04, $FF, $00, $4F, $40, $D4, $04, $F5, $11
.byte $17, $41, $01, $04
.byte $00
level_20:
.byte $FF, $00, $FF, $00, $FF, $00, $FF, $00, $FB, $00, $EF, $40, $31, $04, $21, $04
.byte $91, $04, $F3, $00, $12, $40, $19, $40, $F5, $44, $21, $04, $92, $04, $FD, $00
.byte $22, $14, $FF, $00, $2F, $43, $73, $30, $14, $70, $28, $40, $12, $50, $14, $50
.byte $13, $50, $16, $50, $12, $10, $22, $41, $FD, $00, $24, $40, $2F, $10, $92, $04
.byte $FF, $00, $2F, $41, $F1, $14
.byte $00
;-----------------------------------------------------------------------------
levelsL:
.byte <level_01, <level_02, <level_03, <level_04, <level_05, <level_06
.byte <level_07, <level_08, <level_09, <level_10, <level_11, <level_12
.byte <level_13, <level_14, <level_15, <level_16, <level_17, <level_18
.byte <level_19, <level_20
levelsH:
.byte >level_01, >level_02, >level_03, >level_04, >level_05, >level_06
.byte >level_07, >level_08, >level_09, >level_10, >level_11, >level_12
.byte >level_13, >level_14, >level_15, >level_16, >level_17, >level_18
.byte >level_19, >level_20
;-----------------------------------------------------------------------------
; This table maps tiles (1-8) to tile representations, per level.
; space is 00, floor1 is 1 and collapse is 7 & key is 8. Only 0 through 7
; encoded in the level data. Key, door and switch added programatically to
; the level. The switch looks the same in both kong levels (only place it
; is present) so it doesn't need/get an entry. The door "tile" isn't seen,
; so isn't rendered. It's below the door sprite for collision purposes only.
;
; floor1, floor2, conveyor, wall, bush, rock, collapse, key - door & switch not here
levelTiles:
.byte $31, $00, $1C, $1F, $0D, $28, $27, $09 ; Level 1
.byte $31, $00, $1C, $1F, $0D, $28, $27, $10 ; Level 2
.byte $2E, $03, $1E, $15, $0D, $05, $2D, $09 ; Level 3
.byte $31, $00, $1C, $1F, $0D, $34, $27, $09 ; Level 4
.byte $31, $00, $07, $1F, $0D, $13, $27, $08 ; Level 5
.byte $2F, $00, $1C, $1F, $0D, $0B, $31, $09 ; Level 6
.byte $31, $00, $16, $1F, $0D, $17, $26, $09 ; Level 7
.byte $31, $35, $1D, $1F, $0D, $13, $27, $14 ; Level 8
.byte $31, $00, $07, $18, $0D, $13, $27, $09 ; Level 9
.byte $12, $30, $1C, $1B, $0D, $0F, $20, $01 ; Level 10
.byte $31, $33, $21, $1A, $04, $03, $27, $0A ; Level 11
.byte $31, $35, $1D, $1F, $0D, $13, $27, $14 ; Level 12
.byte $29, $23, $07, $18, $0D, $13, $31, $06 ; Level 13
.byte $2C, $2B, $07, $22, $00, $00, $31, $19 ; Level 14
.byte $32, $2A, $21, $1A, $04, $03, $27, $11 ; Level 15
.byte $31, $31, $1D, $1B, $0E, $13, $27, $02 ; Level 16
.byte $31, $00, $1C, $25, $0D, $0C, $26, $09 ; Level 17
.byte $31, $00, $1C, $24, $0D, $13, $27, $09 ; Level 18
.byte $31, $00, $1C, $1F, $0D, $13, $27, $09 ; Level 19
.byte $31, $00, $1C, $1F, $04, $13, $27, $09 ; Level 20
; This table says which color index to use, to color a
; tile (1-8), per level. The colors are:
; 00 White - 01 Green - 02 Orange - 03 Purple - 04 Blue
; The keys are done as a color animation so at inctance
; time they are left white.
;
; floor1, floor2, conveyor, wall, bush, rock, collapse, key - door & switch not here
levelMasks:
.byte $01, $02, $03, $02, $01, $02, $04, $00 ; Level 1
.byte $03, $02, $03, $02, $01, $02, $04, $00 ; Level 2
.byte $04, $00, $03, $04, $01, $03, $01, $00 ; Level 3
.byte $02, $00, $03, $04, $01, $00, $04, $00 ; Level 4
.byte $04, $02, $02, $01, $00, $02, $01, $00 ; Level 5
.byte $01, $00, $04, $02, $01, $00, $04, $00 ; Level 6
.byte $03, $02, $01, $04, $01, $00, $02, $00 ; Level 7
.byte $02, $00, $01, $00, $01, $02, $04, $00 ; Level 8
.byte $03, $02, $01, $02, $01, $02, $04, $00 ; Level 9
.byte $01, $00, $01, $02, $01, $01, $02, $00 ; Level 10
.byte $04, $00, $03, $02, $02, $00, $01, $00 ; Level 11
.byte $03, $00, $00, $02, $01, $02, $04, $00 ; Level 12
.byte $04, $03, $01, $02, $01, $02, $04, $00 ; Level 13
.byte $04, $03, $00, $04, $01, $02, $04, $00 ; Level 14
.byte $04, $02, $00, $00, $02, $00, $04, $00 ; Level 15
.byte $02, $03, $00, $03, $01, $02, $04, $00 ; Level 16
.byte $01, $02, $01, $02, $01, $00, $04, $00 ; Level 17
.byte $02, $02, $03, $03, $01, $02, $04, $00 ; Level 18
.byte $01, $02, $00, $02, $01, $02, $04, $00 ; Level 19
.byte $02, $02, $04, $01, $00, $02, $04, $00 ; Level 20
collapseHeight:
.byte 8, 7, 6, 5, 4, 3, 2, 1
conveyorDirections:
.byte 2, 1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2
.byte 2, 2, 1, 2, 2, 1
skylabXPos:
.byte $01, $15, $0B, $09, $1D, $13, $11, $05
.byte $1B, $19, $0D, $03
willyx:
.byte $02, $02, $02, $1D, $01, $0F, $02, $02
.byte $01, $01, $03, $02, $1D, $1D, $02, $02
.byte $01, $1D, $0E, $1B, $0F
willyy:
.byte $68, $68, $68, $68, $18, $18, $68, $68
.byte $68, $20, $08, $68, $68, $68, $68, $68
.byte $18, $68, $50, $68, $58
willyStartDir:
.byte 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 1, 1, 0, 1, 0
doorL:
.byte <(levelLayout + $1BE) ; level 0
.byte <(levelLayout + $1DE) ; level 1
.byte <(levelLayout + $17E) ; level 2
.byte <(levelLayout + $03E) ; level 3
.byte <(levelLayout + $1CF) ; level 4
.byte <(levelLayout + $01E) ; level 5
.byte <(levelLayout + $1CF) ; level 6
.byte <(levelLayout + $1CF) ; level 7
.byte <(levelLayout + $001) ; level 8
.byte <(levelLayout + $1CC) ; level 9
.byte <(levelLayout + $021) ; level 10
.byte <(levelLayout + $1CF) ; level 11
.byte <(levelLayout + $1C1) ; level 12
.byte <(levelLayout + $010) ; level 13
.byte <(levelLayout + $061) ; level 14
.byte <(levelLayout + $0CC) ; level 15
.byte <(levelLayout + $03E) ; level 16
.byte <(levelLayout + $03E) ; level 17
.byte <(levelLayout + $041) ; level 18
.byte <(levelLayout + $0B3) ; level 19
doorH:
.byte >(levelLayout + $1BE) ; level 0
.byte >(levelLayout + $1DE) ; level 1
.byte >(levelLayout + $17E) ; level 2
.byte >(levelLayout + $03E) ; level 3
.byte >(levelLayout + $1CF) ; level 4
.byte >(levelLayout + $01E) ; level 5
.byte >(levelLayout + $1CF) ; level 6
.byte >(levelLayout + $1CF) ; level 7
.byte >(levelLayout + $001) ; level 8
.byte >(levelLayout + $1CC) ; level 9
.byte >(levelLayout + $021) ; level 10
.byte >(levelLayout + $1CF) ; level 11
.byte >(levelLayout + $1C1) ; level 12
.byte >(levelLayout + $010) ; level 13
.byte >(levelLayout + $061) ; level 14
.byte >(levelLayout + $0CC) ; level 15
.byte >(levelLayout + $03E) ; level 16
.byte >(levelLayout + $03E) ; level 17
.byte >(levelLayout + $041) ; level 18
.byte >(levelLayout + $0B3) ; level 19
door_color1:
.byte $01, $03, $01, $02, $03, $04, $01, $02
.byte $03, $04, $00, $01, $01, $01, $01, $01
.byte $01, $01, $01, $01, $01
door_color2:
.byte $02, $04, $04, $03, $02, $01, $01, $02
.byte $03, $04, $01, $02, $02, $02, $02, $02
.byte $02, $02, $02, $02, $02
keyx:
.byte $09, $1D, $10, $18, $1E
.byte $07, $18, $1A, $03, $13
.byte $06, $0F, $17, $1E, $15
.byte $01, $0C, $19, $10, $1E
.byte $1E, $0A, $1D, $07, $09
.byte $0F, $11, $1E, $01, $0D
.byte $1E, $14, $1B, $13, $1E
.byte $0D, $0E, $02, $1D, $FF
.byte $10, $FF, $FF, $FF, $FF
.byte $15, $0E, $0C, $12, $1E
.byte $18, $1E, $01, $13, $1E
.byte $0F, $10, $02, $1D, $1A
.byte $1A, $0A, $13, $1A, $0B
.byte $17, $03, $1B, $10, $FF
.byte $19, $0C, $1A, $FF, $FF
.byte $1E, $0D, $01, $11, $FF
.byte $18, $0F, $01, $13, $1A
.byte $10, $FF, $FF, $FF, $FF
.byte $1E, $01, $1E, $FF, $FF
.byte $17, $1E, $0A, $0E, $13
keyyL:
.byte $00, $00, $20, $80, $C0
.byte $20, $20, $E0, $20, $80
.byte $00, $00, $00, $C0, $C0
.byte $00, $20, $20, $C0, $C0
.byte $20, $C0, $E0, $80, $80
.byte $C0, $C0, $E0, $40, $60
.byte $60, $C0, $E0, $40, $60
.byte $40, $C0, $00, $A0, $E0
.byte $20, $E0, $E0, $E0, $E0
.byte $40, $20, $C0, $00, $20
.byte $00, $20, $80, $C0, $A0
.byte $60, $E0, $C0, $A0, $A0
.byte $60, $C0, $20, $20, $80
.byte $40, $00, $E0, $E0, $E0
.byte $40, $C0, $C0, $E0, $E0
.byte $40, $E0, $00, $40, $E0
.byte $A0, $E0, $20, $40, $60
.byte $20, $E0, $E0, $E0, $E0
.byte $20, $A0, $80, $E0, $E0
.byte $A0, $C0, $60, $60, $60
keyyH:
.byte $00, $00, $00, $00, $00
.byte $00, $00, $00, $01, $01
.byte $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00
.byte $00, $00, $00, $01, $01
.byte $00, $00, $00, $01, $01
.byte $00, $00, $00, $01, $01
.byte $00, $00, $01, $01, $FF
.byte $00, $FF, $FF, $FF, $FF
.byte $00, $00, $00, $01, $00
.byte $00, $00, $00, $00, $01
.byte $00, $00, $00, $01, $00
.byte $00, $00, $01, $01, $01
.byte $00, $01, $00, $00, $FF
.byte $00, $00, $01, $FF, $FF
.byte $00, $00, $00, $01, $FF
.byte $00, $00, $01, $01, $01
.byte $00, $FF, $FF, $FF, $FF
.byte $00, $00, $01, $FF, $FF
.byte $00, $00, $01, $01, $01
sprites_x:
.byte $08, $1D, $12, $1D, $1D, $13, $10, $12
.byte $1D, $01, $07, $1D, $0C, $04, $0F, $0F
.byte $06, $0E, $08, $18, $1D, $0F, $0A, $11
.byte $0F, $09, $0B, $12, $0F, $0F, $0C, $10
.byte $05, $0A, $14, $19, $01, $09, $0C, $08
.byte $12, $0C, $0F, $0E, $0F, $0C, $03, $15
.byte $1A, $01, $09, $0B, $19, $0F, $0F, $07
.byte $10, $14, $12, $05, $01, $00, $00, $00
.byte $0F, $11, $09, $0F, $15, $01, $09, $01
.byte $12, $1A, $0C, $05, $0C, $03, $0A, $13
.byte $1B, $1D, $0C, $10, $10, $10, $05, $0A
.byte $14, $19, $1D, $18, $1C, $1D, $10, $05
.byte $0B, $10, $01, $07, $18, $13, $13, $0F
.byte $0F
sprites_y:
.byte $38, $68, $18, $68, $68, $68, $18, $18
.byte $58, $68, $68, $08, $18, $38, $01, $68
.byte $40, $40, $68, $68, $00, $08, $40, $68
.byte $68, $68, $58, $38, $00, $68, $18, $50
.byte $08, $08, $08, $08, $00, $38, $50, $68
.byte $28, $68, $18, $38, $68, $08, $20, $30
.byte $30, $08, $68, $58, $30, $00, $68, $08
.byte $20, $38, $50, $08, $68, $00, $00, $00
.byte $00, $68, $28, $40, $50, $18, $68, $50
.byte $38, $28, $28, $68, $68, $40, $40, $30
.byte $00, $08, $18, $50, $30, $68, $08, $08
.byte $08, $08, $00, $18, $30, $48, $68, $40
.byte $38, $50, $08, $68, $30, $28, $28, $00
.byte $68
sprites_min:
.byte $08, $1D, $01, $0C, $1D, $01, $01, $12
.byte $1D, $01, $06, $1D, $01, $04, $01, $0F
.byte $06, $0E, $08, $18, $1D, $0F, $02, $11
.byte $0F, $01, $0B, $12, $00, $0F, $0C, $0C
.byte $05, $05, $05, $05, $01, $09, $08, $04
.byte $11, $0C, $0F, $0E, $05, $02, $20, $30
.byte $04, $01, $01, $0B, $19, $00, $0F, $07
.byte $07, $0A, $07, $08, $01, $00, $00, $00
.byte $0F, $11, $24, $24, $20, $01, $01, $01
.byte $12, $19, $0C, $05, $0C, $40, $03, $01
.byte $04, $1D, $0C, $0C, $0C, $0C, $05, $05
.byte $05, $05, $1D, $17, $16, $17, $0D, $02
.byte $30, $04, $01, $07, $28, $13, $13, $00
.byte $0F
sprites_max:
.byte $10, $1E, $13, $1E, $1E, $14, $11, $1E
.byte $1E, $0B, $10, $1E, $0D, $0D, $58, $10
.byte $0E, $16, $15, $1E, $1E, $1E, $0B, $1E
.byte $10, $0A, $10, $16, $00, $10, $13, $13
.byte $65, $65, $65, $65, $02, $0F, $0F, $1B
.byte $16, $0D, $19, $13, $14, $39, $65, $65
.byte $65, $02, $0A, $10, $1D, $00, $10, $1E
.byte $1E, $1B, $1E, $65, $02, $49, $39, $21
.byte $10, $14, $67, $67, $69, $02, $13, $08
.byte $18, $1E, $0D, $09, $1A, $67, $61, $41
.byte $61, $1E, $13, $12, $12, $13, $69, $69
.byte $69, $69, $1E, $1E, $1E, $1E, $1E, $67
.byte $67, $51, $02, $17, $68, $14, $14, $59
.byte $10
sprites_speed:
.byte $02, $04, $02, $02, $04, $02, $02, $02
.byte $04, $02, $02, $04, $02, $02, $01, $04
.byte $02, $02, $02, $02, $04, $02, $02, $02
.byte $04, $02, $01, $02, $04, $04, $02, $01
.byte $01, $02, $01, $02, $04, $02, $01, $02
.byte $02, $04, $02, $01, $02, $02, $01, $01
.byte $02, $04, $02, $01, $02, $04, $04, $02
.byte $01, $02, $01, $02, $04, $03, $02, $01
.byte $04, $02, $02, $01, $02, $04, $02, $02
.byte $02, $01, $04, $01, $02, $02, $02, $01
.byte $04, $04, $01, $01, $02, $02, $03, $02
.byte $04, $01, $04, $02, $02, $01, $02, $03
.byte $02, $01, $04, $02, $01, $04, $04, $02
.byte $04
sprites_dir:
.byte $00, $00, $01, $01, $00, $01, $01, $00
.byte $00, $00, $00, $00, $01, $00, $00, $00
.byte $00, $01, $01, $01, $00, $00, $01, $00
.byte $00, $01, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $01, $00, $00, $00
.byte $01, $00, $01, $00, $00, $00, $00, $00
.byte $00, $01, $00, $00, $00, $00, $00, $00
.byte $00, $00, $00, $00, $01, $00, $00, $00
.byte $00, $00, $00, $00, $00, $00, $01, $00
.byte $00, $00, $00, $00, $00, $01, $00, $00
.byte $00, $00, $00, $00, $00, $01, $00, $00
.byte $01, $00, $00, $00, $00, $00, $00, $00
.byte $00
sprites_bitmaps:
.byte $00, $93, $09, $09, $94, $12, $12, $12
.byte $95, $1A, $1A, $96, $23, $23, $22, $97
.byte $2B, $2B, $2B, $2B, $98, $33, $33, $33
.byte $99, $3F, $3F, $3F, $3B, $9A, $47, $47
.byte $43, $43, $43, $43, $9B, $4B, $4B, $4B
.byte $4B, $9C, $57, $57, $57, $53, $53, $53
.byte $53, $9D, $3F, $3F, $3F, $3B, $9E, $5F
.byte $5F, $5F, $5F, $5B, $9F, $63, $63, $63
.byte $A0, $6F, $6B, $6B, $6B, $A1, $73, $73
.byte $73, $73, $A2, $7F, $7F, $7B, $7B, $7B
.byte $7B, $A3, $47, $47, $47, $47, $83, $83
.byte $83, $83, $A4, $8B, $8B, $8B, $8B, $87
.byte $87, $87, $A5, $8F, $5B, $A6, $A7, $11
.byte $08
sprites_colors:
.byte $02, $00, $02, $04, $00, $01, $03, $02
.byte $00, $02, $01, $00, $02, $00, $00, $00
.byte $02, $03, $04, $02, $00, $04, $03, $02
.byte $00, $01, $03, $04, $01, $00, $01, $04
.byte $03, $01, $04, $02, $00, $02, $00, $03
.byte $04, $00, $02, $01, $00, $03, $01, $02
.byte $04, $00, $01, $02, $04, $01, $00, $03
.byte $01, $02, $04, $00, $00, $00, $02, $04
.byte $00, $04, $02, $00, $01, $00, $01, $02
.byte $03, $04, $00, $00, $04, $04, $02, $00
.byte $03, $00, $01, $04, $03, $02, $03, $01
.byte $04, $00, $00, $00, $04, $03, $00, $00
.byte $02, $04, $00, $02, $00, $00, $04, $00
.byte $00
sprites_class:
.byte $00, $82, $00, $00, $82, $00, $00, $00
.byte $82, $00, $00, $82, $00, $00, $13, $82
.byte $00, $00, $00, $00, $82, $00, $00, $00
.byte $82, $02, $06, $02, $2B, $82, $02, $02
.byte $03, $03, $03, $03, $82, $00, $00, $00
.byte $00, $82, $02, $02, $02, $03, $03, $03
.byte $03, $82, $02, $06, $02, $2B, $82, $02
.byte $02, $02, $02, $03, $82, $49, $49, $49
.byte $82, $02, $03, $03, $03, $82, $00, $00
.byte $00, $00, $82, $02, $02, $03, $03, $03
.byte $03, $82, $02, $02, $02, $02, $03, $03
.byte $03, $03, $82, $02, $02, $02, $02, $03
.byte $03, $03, $82, $02, $03, $82, $00, $19
.byte $82
level_sprites_offset:
.byte $00, $02, $05, $09, $0C, $10, $15, $19
.byte $1E, $25, $2A, $32, $37, $3D, $41, $46
.byte $4B, $52, $5B, $63, $67
level_sprites_count:
.byte $02, $03, $04, $03, $04, $05, $04, $05
.byte $07, $05, $08, $05, $06, $04, $05, $05
.byte $07, $09, $08, $04, $02

3209
src/apple2/rosprites.inc Normal file

File diff suppressed because it is too large Load Diff

106
src/apple2/rosystem.inc Normal file
View File

@ -0,0 +1,106 @@
;-----------------------------------------------------------------------------
; rosystem.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "RODATA"
;-----------------------------------------------------------------------------
; the lo byte for the memory at the start of every screen row
rowL:
.repeat $C0, Row
.byte Row & $08 << 4 | Row & $C0 >> 1 | Row & $C0 >> 3
.endrep
;-----------------------------------------------------------------------------
; the hi byte for the memory at the start of every screen row
rowH:
.repeat $C0, Row
.byte >$0000 | Row & $07 << 2 | Row & $30 >> 4
.endrep
;-----------------------------------------------------------------------------
; multiplication lookup tables
mult1024H:
.byte $00, $04, $08, $0C, $10, $14, $18, $1C, $20
mult64H:
.repeat MAX_SPRITE_IFRAMES, Row
.byte >(Row * 64)
.endrep
mult64L:
.repeat MAX_SPRITE_IFRAMES, Row
.byte <(Row * 64)
.endrep
mult32H:
.repeat 15, Row
.byte >(Row * 32)
.endrep
mult32L:
.repeat 15, Row
.byte <(Row * 32)
.endrep
mult16:
.repeat 9, Row
.byte Row * 16
.endrep
mult8:
.repeat 24, Row
.byte Row * 8
.endrep
;-----------------------------------------------------------------------------
; color masks
masksLeft:
.byte %11111111 ; 00 MSB-BITS-11..1 White
.byte %00101010 ; 01 0-BITS-01..0 Green
.byte %10101010 ; 04 1-BITS-01..0 Orange
.byte %01010101 ; 01 0-BITS-10..1 Purple
.byte %11010101 ; 02 1-BITS-10..1 Blue
masksRight:
.byte %11111111 ; 00 MSB-BITS-11 White
.byte %01010101 ; 01 0-BITS-10..1 Green
.byte %11010101 ; 04 1-BITS-10..1 Orange
.byte %00101010 ; 01 0-BITS-01..0 Purple
.byte %10101010 ; 02 1-BITS-01..0 Blue
maskGreen:
.byte %00101010, %01010101 ; Green
maskOrange:
.byte %10101010, %11010101 ; Orange
maskGreenHi:
.byte %00100000, %01000000 ; Green
maskNewTip:
.byte %01011111, %00111111 ; White air graph tip (reversed order)
;-----------------------------------------------------------------------------
; sprite 32 to 64 byte bit-double helper table
binDouble:
.byte %00000000
.byte %00000011
.byte %00001100
.byte %00001111
.byte %00110000
.byte %00110011
.byte %00111100
.byte %00111111
.byte %11000000
.byte %11000011
.byte %11001100
.byte %11001111
.byte %11110000
.byte %11110011
.byte %11111100
.byte %11111111

60
src/apple2/rotext.inc Normal file
View File

@ -0,0 +1,60 @@
;-----------------------------------------------------------------------------
; rotext.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "RODATA"
roTextLevel:
.byte " Central Cavern "
.byte " The Cold Room "
.byte " The Menagerie "
.byte " Abandoned Uranium Workings "
.byte " Eugene's Lair "
.byte " Processing Plant "
.byte " The Vat "
.byte "Miner Willy meets the Kong Beast"
.byte " Wacky Amoebatrons "
.byte " The Endorian Forest "
.byte "Attack of the Mutant Telephones "
.byte " Return of the Alien Kong Beast "
.byte " Ore Refinery "
.byte " Skylab Landing Bay "
.byte " The Bank "
.byte " The Sixteenth Cavern "
.byte " The Warehouse "
.byte " Amoebatrons' Revenge "
.byte " Solar Power Generator "
.byte " The Final Barrier "
roTextAir:
.byte "AIR "
roTextScore:
.byte "SCORE"
roTextHighScore:
.byte "HIGH"
roTextGame:
.byte "GAME"
roTextOver:
.byte "OVER"
roTextPressEnter:
.byte "PRESS ENTER TO START"
roTextEnter := (roTextPressEnter + 6)
roTextAppleIIVersion:
.byte "Apple II version by"
roTextStefan:
.byte "Stefan Wessels, 2020"
roTextIntro:
.byte ". . . . . . . MANIC MINER . . ", $7f, " BUG-BYTE ltd. 1983 . . By "
.byte "Matthew Smith . . . Q, O & W, P = Left & Right . . Space = Jump . . M = Music "
.byte "On/Off . . S = In Game Sound On/Off . . B = Monochrome/Color . . "
.byte "C = Level scroll mode . . ESC = Quit . . . Guide Miner Willy through 20 lethal "
.byte "caverns . . . . . . ", 0
roTextMono:
.byte " MONO"
roTextColor:
.byte "COLOR"
roTextCheatCode:
.byte "6031769"

563
src/apple2/rotiles.inc Normal file
View File

@ -0,0 +1,563 @@
;-----------------------------------------------------------------------------
; rotiles.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "RODATA"
;-----------------------------------------------------------------------------
.align 16 ; don't want tiles spanning boundaries
tiles:
tile00:
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile01:
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $F3, $FF ; XXX--XXXXXXXXX = XX--XXXXXXXXXX
.byte $F3, $FF ; XXX--XXXXXXXXX = XX--XXXXXXXXXX
.byte $83, $FE ; -----XXXXXXXX- = XX------XXXXXX
.byte $8F, $E0 ; ---XXXXXX----- = XXXX--------XX
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
tile02:
.byte $C0, $FF ; X------XXXXXXX = ------XXXXXXXX
.byte $C0, $E1 ; X------XX----X = ------XX----XX
.byte $FC, $E7 ; XXXXX--XX--XXX = --XXXXXXXX--XX
.byte $8C, $FE ; ---XX--XXXXXX- = --XX----XXXXXX
.byte $BF, $86 ; -XXXXXX----XX- = XXXXXX--XX----
.byte $F3, $87 ; XXX--XX----XXX = XX--XXXXXX----
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $FF, $81 ; XXXXXXX------X = XXXXXXXX------
tile03:
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
tile04:
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
tile05:
.byte $C0, $81 ; X------------X = ------XX------
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8F, $F8 ; ---XXXXXXXX--- = XXXX------XXXX
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
tile06:
.byte $C0, $81 ; X------------X = ------XX------
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $8F, $E6 ; ---XXXXXX--XX- = XXXX----XX--XX
.byte $BC, $98 ; -XXXX----XX--- = --XXXX----XX--
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $C0, $81 ; X------------X = ------XX------
tile07:
.byte $C0, $FF ; X------XXXXXXX = ------XXXXXXXX
.byte $8F, $9E ; ---XXXX--XXXX- = XXXX----XXXX--
.byte $C0, $FF ; X------XXXXXXX = ------XXXXXXXX
.byte $8F, $9E ; ---XXXX--XXXX- = XXXX----XXXX--
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile08:
.byte $C0, $FF ; X------XXXXXXX = ------XXXXXXXX
.byte $B0, $F8 ; -XX----XXXX--- = ----XX----XXXX
.byte $8C, $FE ; ---XX--XXXXXX- = --XX----XXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C3, $FF ; X----XXXXXXXXX = XX----XXXXXXXX
.byte $C3, $9F ; X----XX--XXXXX = XX----XXXXXX--
.byte $C3, $87 ; X----XX----XXX = XX----XXXX----
.byte $FF, $81 ; XXXXXXX------X = XXXXXXXX------
tile09:
.byte $F0, $81 ; XXX----------X = ----XXXX------
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $83, $86 ; -----XX----XX- = XX------XX----
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $BC, $86 ; -XXXX------XX- = --XXXX--XX----
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $80, $E6 ; -------XX--XX- = --------XX--XX
.byte $80, $98 ; ---------XX--- = ----------XX--
tile0A:
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $FC, $99 ; XXXXX----XX--X = --XXXXXX--XX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $BF, $E6 ; -XXXXXXXX--XX- = XXXXXX--XX--XX
.byte $BF, $E6 ; -XXXXXXXX--XX- = XXXXXX--XX--XX
.byte $BF, $E6 ; -XXXXXXXX--XX- = XXXXXX--XX--XX
.byte $FC, $99 ; XXXXX----XX--X = --XXXXXX--XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
tile0B:
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $F3, $E7 ; XXX--XXXX--XXX = XX--XXXXXX--XX
.byte $BF, $FE ; -XXXXXXXXXXXX- = XXXXXX--XXXXXX
.byte $BF, $FE ; -XXXXXXXXXXXX- = XXXXXX--XXXXXX
.byte $F3, $E7 ; XXX--XXXX--XXX = XX--XXXXXX--XX
.byte $C0, $81 ; X------------X = ------XX------
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
tile0C:
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8F, $FE ; ---XXXXXXXXXX- = XXXX----XXXXXX
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $BC, $E6 ; -XXXX--XX--XX- = --XXXX--XX--XX
.byte $B3, $9E ; -XX--XX--XXXX- = XX--XX--XXXX--
.byte $FC, $E7 ; XXXXX--XX--XXX = --XXXXXXXX--XX
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $8F, $FE ; ---XXXXXXXXXX- = XXXX----XXXXXX
tile0D:
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $B3, $80 ; -XX--XX------- = XX--XX--------
.byte $BC, $E0 ; -XXXX--XX----- = --XXXX------XX
.byte $B0, $E6 ; -XX----XX--XX- = ----XX--XX--XX
.byte $BF, $9E ; -XXXXXX--XXXX- = XXXXXX--XXXX--
.byte $FC, $81 ; XXXXX--------X = --XXXXXX------
.byte $B0, $80 ; -XX----------- = ----XX--------
tile0E:
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $BC, $F8 ; -XXXX--XXXX--- = --XXXX----XXXX
.byte $BF, $FE ; -XXXXXXXXXXXX- = XXXXXX--XXXXXX
.byte $BF, $FE ; -XXXXXXXXXXXX- = XXXXXX--XXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
tile0F:
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $F3, $99 ; XXX--XX--XX--X = XX--XXXX--XX--
.byte $CC, $E7 ; X--XX--XX--XXX = --XX--XXXX--XX
.byte $C0, $99 ; X--------XX--X = ------XX--XX--
.byte $FC, $81 ; XXXXX--------X = --XXXXXX------
.byte $B3, $9E ; -XX--XX--XXXX- = XX--XX--XXXX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $8C, $F8 ; ---XX--XXXX--- = --XX------XXXX
tile10:
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $BC, $86 ; -XXXX------XX- = --XXXX--XX----
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $BC, $86 ; -XXXX------XX- = --XXXX--XX----
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $80, $98 ; ---------XX--- = ----------XX--
.byte $80, $E0 ; -------XX----- = ------------XX
tile11:
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $BC, $98 ; -XXXX----XX--- = --XXXX----XX--
.byte $CF, $FF ; X--XXXXXXXXXXX = XXXX--XXXXXXXX
.byte $83, $FE ; -----XXXXXXXX- = XX------XXXXXX
.byte $CF, $FF ; X--XXXXXXXXXXX = XXXX--XXXXXXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
tile12:
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $CF, $FF ; X--XXXXXXXXXXX = XXXX--XXXXXXXX
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
tile13:
.byte $FC, $FF ; XXXXX--XXXXXXX = --XXXXXXXXXXXX
.byte $F0, $9F ; XXX------XXXXX = ----XXXXXXXX--
.byte $C0, $9F ; X--------XXXXX = ------XXXXXX--
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $86 ; -----------XX- = --------XX----
tile14:
.byte $83, $80 ; -----XX------- = XX------------
.byte $8F, $80 ; ---XXXX------- = XXXX----------
.byte $BF, $9E ; -XXXXXX--XXXX- = XXXXXX--XXXX--
.byte $FC, $E1 ; XXXXX--XX----X = --XXXXXX----XX
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $83, $E6 ; -----XXXX--XX- = XX------XX--XX
.byte $83, $F8 ; -----XXXXXX--- = XX--------XXXX
tile15:
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $8F, $F8 ; ---XXXXXXXX--- = XXXX------XXXX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $8F, $F8 ; ---XXXXXXXX--- = XXXX------XXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
tile16:
.byte $C3, $FF ; X----XXXXXXXXX = XX----XXXXXXXX
.byte $8F, $9E ; ---XXXX--XXXX- = XXXX----XXXX--
.byte $C3, $FF ; X----XXXXXXXXX = XX----XXXXXXXX
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile17:
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B0, $86 ; -XX--------XX- = ----XX--XX----
tile18:
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
tile19:
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
tile1A:
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
tile1B:
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $F3, $E7 ; XXX--XXXX--XXX = XX--XXXXXX--XX
.byte $F3, $F9 ; XXX--XXXXXX--X = XX--XXXX--XXXX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $8F, $E6 ; ---XXXXXX--XX- = XXXX----XX--XX
.byte $8F, $E6 ; ---XXXXXX--XX- = XXXX----XX--XX
tile1C:
.byte $8F, $F8 ; ---XXXXXXXX--- = XXXX------XXXX
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $80, $80 ; -------------- = --------------
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $80, $80 ; -------------- = --------------
tile1D:
.byte $8F, $F8 ; ---XXXXXXXX--- = XXXX------XXXX
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile1E:
.byte $8F, $F8 ; ---XXXXXXXX--- = XXXX------XXXX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile1F:
.byte $CF, $E7 ; X--XXXXXX--XXX = XXXX--XXXX--XX
.byte $80, $80 ; -------------- = --------------
.byte $BC, $FE ; -XXXX--XXXXXX- = --XXXX--XXXXXX
.byte $80, $80 ; -------------- = --------------
.byte $CF, $E7 ; X--XXXXXX--XXX = XXXX--XXXX--XX
.byte $80, $80 ; -------------- = --------------
.byte $BC, $FE ; -XXXX--XXXXXX- = --XXXX--XXXXXX
.byte $80, $80 ; -------------- = --------------
tile20:
.byte $FF, $87 ; XXXXXXX----XXX = XXXXXXXXXX----
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $83, $FE ; -----XXXXXXXX- = XX------XXXXXX
.byte $C0, $87 ; X----------XXX = ------XXXX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
tile21:
.byte $FF, $E7 ; XXXXXXXXX--XXX = XXXXXXXXXX--XX
.byte $BC, $F8 ; -XXXX--XXXX--- = --XXXX----XXXX
.byte $F3, $FF ; XXX--XXXXXXXXX = XX--XXXXXXXXXX
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile22:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $F0, $E7 ; XXX----XX--XXX = ----XXXXXX--XX
.byte $C0, $F9 ; X------XXXX--X = ------XX--XXXX
.byte $C0, $FF ; X------XXXXXXX = ------XXXXXXXX
.byte $B0, $FE ; -XX----XXXXXX- = ----XX--XXXXXX
.byte $8C, $F8 ; ---XX--XXXX--- = --XX------XXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
tile23:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
tile24:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
tile25:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $F3, $F9 ; XXX--XXXXXX--X = XX--XXXX--XXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $F3, $F9 ; XXX--XXXXXX--X = XX--XXXX--XXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
tile26:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
tile27:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $CF, $E7 ; X--XXXXXX--XXX = XXXX--XXXX--XX
.byte $B3, $F8 ; -XX--XXXXXX--- = XX--XX----XXXX
.byte $B0, $98 ; -XX------XX--- = ----XX----XX--
.byte $CC, $E1 ; X--XX--XX----X = --XX--XX----XX
.byte $B0, $80 ; -XX----------- = ----XX--------
.byte $80, $86 ; -----------XX- = --------XX----
.byte $80, $80 ; -------------- = --------------
tile28:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $9F ; XXXXXXX--XXXXX = XXXXXXXXXXXX--
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $FC, $87 ; XXXXX------XXX = --XXXXXXXX----
.byte $CC, $87 ; X--XX------XXX = --XX--XXXX----
.byte $CC, $87 ; X--XX------XXX = --XX--XXXX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
tile29:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C0, $E1 ; X------XX----X = ------XX----XX
.byte $B0, $98 ; -XX------XX--- = ----XX----XX--
.byte $8C, $86 ; ---XX------XX- = --XX----XX----
.byte $C3, $81 ; X----XX------X = XX----XX------
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
tile2A:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
tile2B:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $8C, $9E ; ---XX----XXXX- = --XX----XXXX--
.byte $B0, $9E ; -XX------XXXX- = ----XX--XXXX--
.byte $C0, $9F ; X--------XXXXX = ------XXXXXX--
.byte $80, $9E ; ---------XXXX- = --------XXXX--
.byte $80, $9E ; ---------XXXX- = --------XXXX--
.byte $80, $9E ; ---------XXXX- = --------XXXX--
tile2C:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $BC, $98 ; -XXXX----XX--- = --XXXX----XX--
.byte $BC, $86 ; -XXXX------XX- = --XXXX--XX----
.byte $FC, $81 ; XXXXX--------X = --XXXXXX------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
tile2D:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $C0, $81 ; X------------X = ------XX------
.byte $FF, $99 ; XXXXXXX--XX--X = XXXXXXXX--XX--
.byte $80, $80 ; -------------- = --------------
tile2E:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $80, $80 ; -------------- = --------------
tile2F:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $C3, $E1 ; X----XXXX----X = XX----XX----XX
.byte $BC, $9E ; -XXXX----XXXX- = --XXXX--XXXX--
.byte $80, $80 ; -------------- = --------------
tile30:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $CF, $99 ; X--XXXX--XX--X = XXXX--XX--XX--
.byte $8C, $E6 ; ---XX--XX--XX- = --XX----XX--XX
.byte $B3, $98 ; -XX--XX--XX--- = XX--XX----XX--
.byte $CC, $81 ; X--XX--------X = --XX--XX------
.byte $83, $98 ; -----XX--XX--- = XX--------XX--
.byte $80, $80 ; -------------- = --------------
tile31:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $FC, $9F ; XXXXX----XXXXX = --XXXXXXXXXX--
.byte $8F, $E6 ; ---XXXXXX--XX- = XXXX----XX--XX
.byte $8C, $80 ; ---XX--------- = --XX----------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile32:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $CF, $E7 ; X--XXXXXX--XXX = XXXX--XXXX--XX
.byte $FC, $FF ; XXXXX--XXXXXXX = --XXXXXXXXXXXX
.byte $B3, $9B ; -XX--XX--XX-XX = XX--XX-XX-XX--
.byte $CC, $E4 ; X--XX--XX--X-- = --XX--X--X--XX
.byte $B0, $98 ; -XX------XX--- = ----XX----XX--
.byte $80, $80 ; -------------- = --------------
tile33:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $B3, $E6 ; -XX--XXXX--XX- = XX--XX--XX--XX
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
.byte $80, $80 ; -------------- = --------------
tile34:
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $C0, $81 ; X------------X = ------XX------
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $CF, $F9 ; X--XXXXXXXX--X = XXXX--XX--XXXX
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $CC, $99 ; X--XX----XX--X = --XX--XX--XX--
tile35:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
.byte $BC, $80 ; -XXXX--------- = --XXXX--------
tile36:
.byte $FF, $FF ; XXXXXXXXXXXXXX = XXXXXXXXXXXXXX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $83, $E0 ; -----XXXX----- = XX----------XX
.byte $8C, $98 ; ---XX----XX--- = --XX------XX--
.byte $F0, $87 ; XXX--------XXX = ----XXXXXX----
.byte $C0, $81 ; X------------X = ------XX------
.byte $80, $9E ; ---------XXXX- = --------XXXX--
.byte $80, $9E ; ---------XXXX- = --------XXXX--

1117
src/apple2/screen.inc Normal file

File diff suppressed because it is too large Load Diff

384
src/apple2/sprite.inc Normal file
View File

@ -0,0 +1,384 @@
;-----------------------------------------------------------------------------
; sprite.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
; Copy bytes from srcPtr to dstPtr
; IN: - srcPtr - start of copy
; dstPtr - start of non-overlapping destination
; size - number of bytes to copy
; Clobbers: a, y
.proc spriteCopyMemSrcToDst
ldy #0
hiCopy:
dec sizeH
bmi lowCopy
:
lda (srcPtrL), y
sta (dstPtrL), y
dey
bne :-
inc srcPtrH
inc dstPtrH
bne hiCopy
lowCopy:
ldy sizeL
dey
bmi done
:
lda (srcPtrL), y
sta (dstPtrL), y
dey
bpl :-
done:
rts
.endproc
;-----------------------------------------------------------------------------
; Look up the color, and apply those masks to the frames
; IN: x = start frame
; y = num frames
; a = color index
; Clobbers: a, y
.proc spriteApplyMaskToFrames
instanceIdx = tmpBot + 0
colMaskL = tmpBot + 1
colMaskR = tmpBot + 2
numFrames = tmpBot + 3
sty numFrames ; save y
tay ; put color index in y
lda masksLeft, y ; look up the masks for the color
sta colMaskL
lda masksRight, y
sta colMaskR
lda mult64L, x ; build a pointer to the frame
sta srcPtrL
lda mult64H, x
adc #>spriteInstances
sta srcPtrH
ldy numFrames ; convert frames to bytes
lda mult64H, y
sta sizeH
lda mult64L, y
sta sizeL
ldy #0 ; do blocks of 256
hiPass:
dec sizeH ; see if there's a hi block to do
bmi lowPass ; if none (remain) to do, move on
:
lda (srcPtrL), y ; do a left hand byte
and colMaskL
sta (srcPtrL), y
dey
lda (srcPtrL), y ; then a right hand byte
and colMaskR
sta (srcPtrL), y
dey
bne :- ; for 256 bytes
inc dstPtrH ; advance the dest ptr Hi
bne hiPass ; BRA
lowPass:
ldy sizeL ; do bytes remaining lt 256
dey
bmi done ; keep going till all done
:
lda (srcPtrL), y
and colMaskL
sta (srcPtrL), y
dey
lda (srcPtrL), y
and colMaskR
sta (srcPtrL), y
dey
bpl :-
done:
rts
.endproc
;-----------------------------------------------------------------------------
; Copy one frame to another
; IN:
; originalFrame = tmpBot + 4
; newFrame = tmpBot + 5
; Clobbers: a, x, y
.proc spriteCopyFrameToFrame
originalFrame = tmpBot + 4
newFrame = tmpBot + 5
clc
ldx originalFrame ; point srcPtr at the original frame
lda mult64L, x
sta srcPtrL
lda mult64H, x
adc #>spriteInstances
sta srcPtrH
ldx newFrame ; point dstPtr at the target frame
lda mult64L, x
sta dstPtrL
lda mult64H, x
adc #>spriteInstances
sta dstPtrH
lda #0 ; 256 or less bytes (no Hi)
sta sizeH
lda #64 ; just 64 bytes to copy
sta sizeL
jsr spriteCopyMemSrcToDst ; use copymem to copy a 64 byte frame
rts
.endproc
;-----------------------------------------------------------------------------
; Invert the pixels of a frame
; IN:
; x = frame number
.proc spriteInvertFrame
clc
lda mult64L, x ; make srcPtr point at the frame
sta srcPtrL
lda mult64H, x
adc #>spriteInstances
sta srcPtrH
ldy #SPRITE_BYTES - 1 ; do for a whole frame (0 based)
:
lda (srcPtrL), y ; get the frame byte
eor #%01111111 ; invert except for the MSB
sta (srcPtrL), y ; and save the byte
dey ; one less byte to do
bpl :- ; do for all bytes
rts
.endproc
;-----------------------------------------------------------------------------
; Clear all the pixels of a frame
; IN:
; x = frame number
; y = number of frames to clear
.proc spriteClearFrames
count = sizeL
lda mult64L, y ; turn the number of frames into num bytes
sta count ; save as a count
clc ; and clear carry
lda mult64L, x ; make srcPtr point at the
sta srcPtrL
lda mult64H, x
adc #>spriteInstances
sta srcPtrH
ldy count ; how many bytes to clear
dey ; make zero based
lda #0 ; value to write
:
sta (srcPtrL), y ; write 0 to frame
dey ; previous byte in frame
bpl :- ; do for all, incl. zero'th byte
rts
.endproc
;-----------------------------------------------------------------------------
; Make an instance of the bitmap (index in a) into the spriteInstance buffer
; while expanding the bitmap from 32 byte 1bpp into 64 byte 2bpp and masking
; the instance for the required color.
; IN:
; a - bitmapIdx
; x - instanceIdx
.proc spriteInstanceSpriteFrames
; count = tmpBot + 0
; spriteIdx = tmpBot + 1
instanceIdx = tmpBot + 2
srcIdx = tmpBot + 3
dstIdx = tmpBot + 4
colMaskL = tmpBot + 5
colMaskR = tmpBot + 6
ldy #0
sty srcPtrH
sty dstPtrH
ldy #5 ; mult * 32 (shl 5 times) since each src frame is 32 bytes
:
asl ; shift the low
rol srcPtrH ; and the hi, and move carry into hi if needed
dey ; do for all 6 iterations
bne :-
adc #<sprite08 ; add the memory offset off the non-willy src sprites
sta srcPtrL
lda #>sprite08
adc srcPtrH
sta srcPtrH ; src ptr now points at the 1st frame
lda spriteFramesIdx, x ; get the sprite dest frame
ldy #6 ; mult * 64 (shl 6 times) since each frame is 64 bytes
:
asl ; shift the lo
rol dstPtrH ; and the hi, and move carry into hi if needed
dey ; do for all 6 iterations
bne :-
sta dstPtrL ; save the lo
lda dstPtrH ; get the hi
adc #>spriteInstances ; and make relative to the buffer
sta dstPtrH ; and save the hi
lda #1 ; assume 4 frames = 256 bytes
sta sizeH
lda spriteClass, x ; get the class
bit bit1Mask ; CLASS_FOUR_FRAME is it 4 frames
bne :+ ; yes, all set
inc sizeH ; 8 frames = 512 bytes = 2 Hi
:
ldy instanceIdx ; get the instance
lda spriteColor, y ; and get the color for the instance
tay ; put the color index in y
lda masksLeft, y ; get the color mask
sta colMaskL
lda masksRight, y ; do the same for the right
sta colMaskR ; SQW - look at comments but save for second (inverse) buffer
ldy #0
sty dstIdx ; set the src and dst indices to start at 0
sty srcIdx ; srcIndex moves at 1/2 of dstIndex
copyFrames:
ldy srcIdx ; get the source index
lda (srcPtrL), y ; get a (left) src byte at the source index
pha ; save so the right nibble can be expanded later
lsr ; make the left nibble the low nibble
lsr
lsr
lsr
tax ; put the value in x
lda binDouble, x ; look up the "pixel doubled" value
ora #$80 ; and set the color msb "on"
and colMaskL ; mask it with appropriate color
ldy dstIdx ; get the destination offset
sta (dstPtrL), y ; and save to instance destination
iny ; move the destination along one
pla ; get the source byte
and #$0f ; mask so only right nibble
tax ; put it in x
lda binDouble, x ; and look up the "doubled" pixel values
sec ; set carry so a rotate will be equiv to or #$80
ror ; and rotate, making it a "right" byte
and colMaskR ; mask it with appropriate color
sta (dstPtrL), y ; and save to instance destination
iny ; move the dest index along again
sty dstIdx ; and save the index
bne :+ ; if the index rolled over
inc dstPtrH ; move the hi byte along
dec sizeH ; check if moved all required 4 * 32 src byte blocks
beq done
:
inc srcIdx ; move the src index along
bne copyFrames ; do max 256 bytes = 8 * 32 byte src frames
done:
rts
.endproc
;-----------------------------------------------------------------------------
; Copy the door frame, invert the copy, mask both and combine
.proc spriteDoorSetup
originalFrame = tmpBot + 4
newFrame = tmpBot + 5
ldx numSprites ; numSprites is the door sprite index
lda spriteFramesIdx, x
tax
stx originalFrame
inx
stx newFrame
jsr spriteCopyFrameToFrame ; make a copy y = instanceIdx, a = srcFrame, x = dstFrame
ldx newFrame
jsr spriteInvertFrame ; invert the instance frame bits (leave msb alone)
ldx currLevel
lda door_color1, x
beq :+
ldx originalFrame
ldy #1
jsr spriteApplyMaskToFrames
ldx currLevel
lda door_color2, x
beq :+
ldx newFrame
ldy #1
jmp spriteApplyMaskToFrames
:
rts
.endproc
;-----------------------------------------------------------------------------
; Make 4 copies of Eugene frame 0 into frames 1-4 and apply a different
; color mask to the additional frames
.proc spriteEugeneSetup
originalFrame = tmpBot + 4
newFrame = tmpBot + 5
count = tmpBot + 6
ldx numSprites
dex ; eugene is sprite before the door
lda spriteFramesIdx, x ; get the frame where eugene is
tax ; put in x
stx originalFrame ; and call it the original
inx ; and go to the next frame
stx newFrame ; and call it the new frame
ldx #3 ; and set the loop count to 3
stx count
:
jsr spriteCopyFrameToFrame ; make a copy of eugene, x = ori, y = new
lda count ; get the count in a (as a color mask index)
ldx newFrame ; the frame in x
ldy #1 ; and the number of frames to process in Y
jsr spriteApplyMaskToFrames ; mask the new eugene to the "count" color
inc newFrame ; go up a frame
dec count ; and dec the loop counter
bne :- ; and do for the number of loops (3)
rts ; there are now 4 eugenes, White, Green, Orange & Purple
.endproc

332
src/apple2/text.inc Normal file
View File

@ -0,0 +1,332 @@
;-----------------------------------------------------------------------------
; text.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc textSHowText
xpos = srcPtrL
ypos = srcPtrH
rows = sizeH
strIndex = sizeL
color = dstPtrL ; and H
fontL = charGfx + 1
fontH = charGfx + 2
stx xpos
sty ypos
loop:
lda #0
sta fontH ; init the pointer hi to 0 for later mult rol's
ldx strIndex ; get the index into the string
read:
lda PLACEHOLDER, x ; get the character in the string
sec
sbc #32 ; the font only starts at space (char 32 or $20)
asl ; mult by 16 as that's how wide a char is in bytes
asl
rol fontH
asl
rol fontH
asl
rol fontH ; srcPtr now points at the char but $0000 based
adc #<font ; add the font start
sta fontL
lda fontH
adc #>font
sta fontH ; srcPtr now point at the actual character memory
lda #8 ; font is 8 rows high
sta rows
ldy ypos ; start each character on the same line
iLoop:
lda strIndex ; strIndex is also col offset from xpos
asl ; but font is 2 cols wide
adc xpos ; add the xpos to get screen col
adc rowL, y ; and add the row
sta write + 1 ; lo byte of where to write to screen buffer
lda currPageH ; get the hi page
adc rowH, y ; add the row
sta write + 2 ; and complete the screen buffer write address
ldx #1 ; set up for copying 2 font bytes (1 char)
charGfx:
lda PLACEHOLDER, x ; get the font
eorMask:
eor #$00 ; eor to invert if necessary
and color, x ; and to get the color needed
write:
sta PLACEHOLDER, x ; and write to screen memory
dex ; go left a byte
bpl charGfx ; and repeat to do 2 bytes
dec rows ; done one of the 8 rows needed
beq nextChar ; repeat for all 8 rows, then done
iny ; more rows - next row in y
lda fontL ; move along 2 in the font
adc #2
sta fontL
bcc iLoop
inc fontH
bcs iLoop ; BRA
nextChar:
dec strIndex ; string done from the back, so move left in string
bpl loop ; if not all of string done, loop
done:
rts
.endproc
;-----------------------------------------------------------------------------
; Macro that takes a lo and hi for the text with optional color and invert wanted
; sets up what's needed to call textShow which does the printing
.macro printXYlh xpos, ypos, textL, textH, len, colorMask, inverse
.local color, strIndex
color = dstPtrL ; textShow expects color masks in dstPtr(L and H)
strIndex = sizeL
.ifblank colorMask
lda #$ff ; no color (white) is a mask of $ff left and right
sta color
sta color + 1
.else
ldx colorMask ; this is an index into mask[Left|Right]
lda masksLeft, x
sta color
lda masksRight, x
sta color + 1
.endif
.ifblank inverse
lda #0 ; eor o is not inverse
.else
lda #$7f ; eor $7f inverts the color (leave MSB)
.endif
sta textSHowText::eorMask + 1 ; set the eor in the code
lda textL ; set the string pointer in the code
sta textSHowText::read + 1
lda textH
sta textSHowText::read + 2
ldx len ; 0 based
stx strIndex
lda xpos ; and x/y coords in x and y registers
asl
tax
ldy ypos
jsr textSHowText ; print that string
.endmacro
;-----------------------------------------------------------------------------
; macro to take text address and split it into lo and hi (shorthand)
.macro printXY xpos, ypos, text, len, colorMask, inverse
printXYlh xpos, ypos, #<text, #>text, len, colorMask, inverse
.endmacro
;-----------------------------------------------------------------------------
; Build a memory cache of the level name since this is re-drawn much more -
; every time the level scrolls left or right and copying from a cache is
; much faster than doing a text print
.proc textSetLevelText
lda #0
sta sizeL ; index into string
sta read + 2 ; hi byte of string address
lda currLevel ; start with the level
asl ; multiply by 32
asl
asl
asl
rol read + 2
asl
rol read + 2
adc #<roTextLevel ; add the base address of the string
sta read + 1
lda #>roTextLevel
adc read + 2
sta read + 2 ; read + 1 as a ptr now points at the string for this level
lda #<levelNameGfx0 ; start at the top of the name cache
sta write + 1 ; and make write + 1 be a pointer to the cache
lda #>levelNameGfx0
sta write + 2
lda #32 ; These strings are 32 characters wide
sta dstPtrL
loop:
lda #0
sta srcPtrH ; init the pointer hi to 0 for later mult rol's
ldx sizeL ; get the index into the string
read:
lda PLACEHOLDER, x ; get the character in the string
sec
sbc #32 ; the font only starts at space (char 32 or $20)
asl ; mult by 16 as that's how wide a char is in bytes
asl
rol srcPtrH
asl
rol srcPtrH
asl
rol srcPtrH ; srcPtr now points at the char but $0000 based
adc #<font ; add the font start
sta srcPtrL
lda srcPtrH
adc #>font
sta srcPtrH ; srcPtr now point at the actual character memory
lda #8 ; copy 8 rows / character
sta sizeH
ldy #1 ; start at the right hand side character
lrLoop:
ldx #1 ; load x for the right hand side as well
copyLoop:
lda (srcPtrL), y ; get the line pixel
eor #$7f ; invert
maskName:
and maskGreen, x ; mask for color (always green but left vs right hand side)
write:
sta PLACEHOLDER, x ; store to the cache
dey ; back up a byte
dex
bpl copyLoop ; do 2 bytes, right and left hand
lda write + 1 ; get the cache ptr low
clc
step:
adc #64 ; step to the next line - 64 bytes along
sta write + 1 ; update the pointer
bcc :+
inc write + 2 ; if it wrapped, update the hi byte
:
iny ; y is now at minus 1 the last byte written
iny ; so advance it by 4 to get to the next right hand side byte
iny
iny
dec sizeH ; done one line
bne lrLoop ; if any lines left, keep going
sec
lda write + 1
sbc #<((64*8)-2)
sta write + 1
lda write + 2
sbc #>((64*8)-2)
sta write + 2
clc
inc sizeL ; move to the next character in the string
dec dstPtrL ; see if 32 characters were done
bne loop ; if not, keep going
done:
rts
.endproc
;-----------------------------------------------------------------------------
; x has digit (5 means 1's, 4 means 10's, etc)
; a is the number to add 0..9
.proc textAddScore
clc
adc score, x ; get the current digit
cmp #'9'+1 ; has it rolled over
bcc okay ; then simply increment
sec
sbc #10
sta score, x ; and save over the 9
lda #1
dex ; previous digit
bmi over ; if it rolls over 999999
cpx #1 ; if the digit is now the 010000 (1)
bne textAddScore ; no, then work with this digit
ldy lives
cpy #9 ; max out at 9 lives (keeps cheat boot on-screen)
bcs textAddScore
inc lives ; yes, then add a life
bne textAddScore ; and then work with this digit
okay:
sta score, x ; and store it
over:
lda #UI_COMPONENT_SCORE ; mark the score texts as needing an update
jmp uiUpdateComponent
done:
rts
.endproc
;-----------------------------------------------------------------------------
.proc textCheckHighScore
ldx #0 ; start at the most significant digit
:
lda score, x ; get the score
cmp highScore, x ; compare to the high score
bcc done ; if smaller then highscore gt score
bne newHigh ; if ne then highscore gt score
inx ; digits equal so check next digit
cpx #6 ; compare x to max digits (+ 1)
bcc :- ; x is 5 or less, keep checking digits
done:
rts
newHigh:
ldx #5 ; copy the 6 score digits over the highscore digits
:
lda score, x
sta highScore, x
dex
bpl :-
lda #UI_COMPONENT_HIGHSCORE
jmp uiUpdateComponent
.endproc
;-----------------------------------------------------------------------------
.proc textColorCycle
color = tmpBot + 1
xPos = tmpBot + 2
yPos = tmpBot + 3
textL = tmpBot + 4
textH = tmpBot + 5
len = tmpBot + 6
prntLoop:
printXYlh xPos, yPos, textL, textH, #0, color
dec len ; one less character to color
beq done ; all characters done?
inc xPos ; move to the next character on screen
inc textL ; and move to the next character in the sting
bne :+ ; did the string wrap a buffer
inc textH ; yes, up the Hi
:
dec color ; prev color
bpl :+ ; still ge 0
lda #4 ; no, wrap to index 4
sta color ; and save that as the color
:
jmp prntLoop ;and print this character
done:
rts
.endproc

448
src/apple2/tiles.inc Normal file
View File

@ -0,0 +1,448 @@
;-----------------------------------------------------------------------------
; tiles.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc tilesPrepForLevel
jsr tilesMakeInstances ; copy tile data to instance area
lda monochrome ; see if the game should render for monochrome
beq color ; no, apply all masks
mono:
ldy #(DATA_COLLAPSE / $10) - 1 ; apply color mask only to the conveyor tile
ldx #((DATA_COLLAPSE / $10) -1) * TILE_BYTES
lda #1
bne mask
color:
ldy #0
ldx #0
lda #TILES_PER_LEVEL
mask:
jsr tilesColorInstances ; color instance tiles by applying appropriate color masks
jsr tilesPrepKeysTiles ; make animated keys from the key tile
jmp tilesPrepConveyorTiles ; Make rotated conveyor tiles into conveyorAnimTiles
.endproc
;-----------------------------------------------------------------------------
.proc tilesMakeInstances
numTiles = sizeL
iLevelTile = sizeH
iWrite = dstPtrL
tileMemL = srcPtrL
tileMemH = srcPtrH
lda #TILES_PER_LEVEL ; for all tiles used in a level
sta numTiles
lda #TILE_BYTES - 1 ; start at the end of tile memory
sta iWrite
ldx currLevel ; find index into tile table
lda mult8, x ; 8 tiles per level
sta iLevelTile ; gives entry for the 1st tile
loop:
lda #0 ; set the hi for reading tile memory to 0
sta tileMemH
ldx iLevelTile ; get the index into the table
lda levelTiles, x ; and get the id for the tile from the table
asl ; mult tile offset * 16 (width of a tile)
asl
asl
rol tileMemH
asl
rol tileMemH ; offset of tile start (from background) now in tileMem ptr
adc #<tiles ; add tiles base address
sta tileMemL
lda #>tiles
adc tileMemH
sta tileMemH ; tileMem pointer now points at memory for the tile
ldy #TILE_BYTES - 1 ; 0 based, copy all the bytes of the tile
ldx iWrite
:
lda (tileMemL), y ; get the tile byte
sta tilesInstances, x ; and save it to instance 0
dex ; back up the tile write pointer
dey ; and completed one byte
bpl :- ; do for all bytes of a tile
dec numTiles ; done a tile
beq copyDone ; see if all tiles done
lda iWrite ; more tiles to do, adjust the tile write ptr
clc
adc #TILE_BYTES ; by moving it to the end of the next tile
sta iWrite
inc iLevelTile ; and advance the index into the table to the next tile
bne loop ; BRA to do the next tile
copyDone:
rts
.endproc
.proc tilesColorCollapsing
rts
.endproc
;-----------------------------------------------------------------------------
; Color tile instances
; IN: a - number of tiles to color
; y - index of first tile to color
; x - write address of first tile data (16 * y)
.proc tilesColorInstances
numTiles = sizeL
iLevelTile = sizeH
colMaskL = dstPtrL + 0
colMaskR = dstPtrL + 1
tileMemL = srcPtrL
tileMemH = srcPtrH
sta numTiles ; save the register parameters
sty iLevelTile
ldy currLevel ; get the offset of the tiles in the level tile table
lda mult8, y
clc
adc iLevelTile ; and add the parameter offset (0 for color and 3 for mono)
sta iLevelTile
loop:
ldy iLevelTile ; get the index
lda levelMasks, y ; and extract the masks for this tile
tay
lda masksLeft, y
sta colMaskL
lda masksRight, y
sta colMaskR
ldy #(TILE_BYTES / 2) ; 2 masks at one time, so bytes / 2
:
lda colMaskL ; instance 0 mask the left side with a left mask
and tilesInstances, x
sta tilesInstances, x
inx ; next byte
lda colMaskR ; instance 0 mask the right side with a right mask
and tilesInstances, x
sta tilesInstances, x
inx ; next byte
dey ; one more column done
bne :- ; keep going till all columns done
inc iLevelTile ; go to the next table entry
dec numTiles ; done one more tile
bne loop ; keep going till all tiles done
rts
.endproc
;-----------------------------------------------------------------------------
.proc tilesPrepKeysTiles
keyByte = tmpBot + 0
lda #4 ; init the key animation to frame 4
sta keysFrameNum
ldy #0 ; start at the 1st key byte
maskLoop:
lda tilesInstances + DATA_KEY - TILE_BYTES, y
sta keyByte ; get a byte and save it
clc
ldx #4 ; make 4 color variations
colorLoopLeft:
lda keyByte ; start with the white key byte
and masksLeft, x ; mask it for left
sta keyAnimTiles, y ; and save it to the first key frame instance 0
tya ; move y along to the next key instance
adc #TILE_BYTES
tay
dex ; and do the next color for that instance
bne colorLoopLeft ; repeat for all 4 color frames
tya ; move Y back 63 bytes, to the next white key byte
sec
sbc #63
tay
lda tilesInstances + DATA_KEY - TILE_BYTES, y
sta keyByte ; get the second (right hand byte)
clc
ldx #4 ; repeat the above but swap color masks
colorLoopRight:
lda keyByte
and masksRight, x
sta keyAnimTiles, y
tya
adc #TILE_BYTES
tay
dex
bne colorLoopRight
tya
sec
sbc #63
tay ; y is now pointing at the next left byte
cpy #TILE_BYTES ; see if the whole key has been processes
bne maskLoop
rts
.endproc
;-----------------------------------------------------------------------------
; Makes animated copies of the conveyor tile. Instead of making full tile
; copies, this should really just do the two lines affected (so use 1 tile
; of memory, not 7 * TILE_BYTES)
.proc tilesPrepConveyorTiles
frame = sizeL
count = sizeH
dir = tmpBot + 0
carry = tmpBot + 1
lda #6 ; init the conveyor frame counter
sta conveyorFrameNum
ldx currLevel
lda conveyorDirections, x ; get a local copy of the conveyor direction
sta dir
clc ; point srcPtr at the conveyor tile
lda #DATA_CONVEYOR - TILE_BYTES
sta srcPtrL
lda #>tilesInstances
sta srcPtrH
lda #<conveyorAnimTiles ; point dstPtr at the first animated tile
sta dstPtrL
lda #>conveyorAnimTiles
sta dstPtrH
ldy #TILE_BYTES - 1 ; copy the tile to the animated tiles
:
lda (srcPtrL), y
and #$7F ; clear the MSB, will be fixed later
sta (dstPtrL), y
dey
bpl :-
ldy #CONVEYOR_FRAMES - 1 ; set a counter for how many frames to process
processTile:
sty frame
clc ; move srcPtr to dstPtr (the new src)
lda dstPtrL ; and move dstPtr to the next frame to animate
sta srcPtrL
adc #TILE_BYTES
sta dstPtrL
lda dstPtrH
sta srcPtrH
bcc :+
inc dstPtrH
:
ldy #TILE_BYTES - 1 ; process a tile's bytes (0 based)
:
lda (srcPtrL), y ; copy the source
sta (dstPtrL), y ; save to the dest
dey ; copy the whole tile
bpl :-
lda dir ; different algorithm for each direction
cmp #2
beq left
right:
ldy #0 ; top row
jsr shiftLeft ; move "left" which is "wrong", the processing is going 0..CONVEYOR_FRAMES
ldy #4 ; 3rd row down, 0 based (2) * 2 byes/row is 4
jsr shiftRight ; but the animation plays back CONVEYOR_FRAMES..0
jmp nextFrame ; so this is all reversed
left:
ldy #0
jsr shiftRight
ldy #4
jsr shiftLeft
nextFrame:
ldy frame
dey ; another frame processed
bne processTile ; have all tiles been animated (0 is original the rest shifted)
jmp finalFix ; fix the MSB
shiftRight:
lda (dstPtrL), y ; left byte scroll right (apple pixels are reversed, so asl)
asl ; shift msb away, bit 0 clear
asl ; shift 1/2 a pixel, bit 1 and 0 clear
sta (dstPtrL), y ; save left shifted. carry has a pixel bit that needs to move
iny
lda (dstPtrL), y
rol ; shift right byte once, carry goes in, MSB bit out in carry
asl ; shift second time, bit 0 is now a zero, carry bit needs moving left
sta (dstPtrL), y
dey
lda #0 ; start fresh
rol ; move carry into bit 0
asl ; carry into bit 1, carry clear, bit 0 now 0
ora (dstPtrL), y ; add bit 1 to the left byte
sta (dstPtrL), y ; save the left byte
and #$80 ; extract bit 8 left that should be in right bit0
asl ; put bit 8 in carry and acc now clear
rol ; put bit 8 in bit 0
iny
ora (dstPtrL), y ; add it to the right byte
sta (dstPtrL), y ; store the right byte
and #$80 ; extract bit 8 right which should be bit 0 left
asl ; move into carry
rol ; move carry into bit 0, carry now clear
dey
ora (dstPtrL), y ; add to bit0 of left byte
sta (dstPtrL), y ; and save
rts
shiftLeft:
ldx #1
lda (dstPtrL), y ; get left byte
:
lsr ; move bit out
sta (dstPtrL), y ; save byte
lda #0 ; move bit in for next byte to bit 6
ror
lsr
sta carry
iny
lda (dstPtrL), y
ror ; move right byte one over (carry needs to go left now)
ora carry ; add bit from left
sta (dstPtrL), y ; save
lda #0 ; start fresh
ror ; move carry to bit 6
lsr
dey
ora (dstPtrL), y ; add to left byte
dex
bpl :-
sta (dstPtrL), y ; save
rts
finalFix:
ldy #(CONVEYOR_FRAMES * TILE_BYTES) - 1
lda tilesInstances + (DATA_CONVEYOR - TILE_BYTES)
and #$80 ; load a byte from original
beq clear ; and see if color bit is set
:
lda #$80 ; if set, set color on for all frames
ora conveyorAnimTiles, y
sta conveyorAnimTiles, y
dey
bpl :-
bmi done
clear:
lda #$7f ; if not set, make sure color isn't on for all
and conveyorAnimTiles, y
sta conveyorAnimTiles, y
dey
bpl clear
done:
rts
.endproc
;-----------------------------------------------------------------------------
; Copy a pre-animated key tile into the tilesInstances so it looks as
; though the key is animating
.proc tilesAnimateKeys
ldx keysFrameNum ; get the frame
dex ; step
bpl :+ ; underflow
ldx #3 ; reset - frames are 0 to 6, but go to render + 1
:
stx keysFrameNum ; save the new frame
inx ; go one frame past
lda mult16, x ; get the byte offset to the frame
tax ; put it in x
dex ; and go to the last byte of the frame needed
ldy #TILE_BYTES - 1 ; set y to copy a whole tile
:
lda keyAnimTiles, x ; read the frame and write to key tile
sta tilesInstances + DATA_KEY - TILE_BYTES, y
dex
dey
bpl :-
rts
.endproc
;-----------------------------------------------------------------------------
; Copy a pre-animated conveyor lines over the lines in the conveyor frame tile,
; in the tilesInstances area
.proc tilesAnimateConveyor
ldx conveyorFrameNum ; get the frame
dex ; step
bpl :+ ; underflow
ldx #6 ; reset - frames are 0 to 6, but go to render + 1
:
stx conveyorFrameNum ; save the new frame
lda mult16, x ; get the byte offset to the frame
tax ; put it in x
lda conveyorAnimTiles, x ; copy the 4 animated bytes for
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES
inx
lda conveyorAnimTiles, x ; instance 0 over
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES + 1
inx ; to the tile area 0
inx
inx
lda conveyorAnimTiles, x
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES + 4
inx
lda conveyorAnimTiles, x
sta tilesInstances + DATA_CONVEYOR - TILE_BYTES + 5
rts
.endproc

425
src/apple2/ui.inc Normal file
View File

@ -0,0 +1,425 @@
;-----------------------------------------------------------------------------
; ui.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
.proc uiUpdateComponent
ora uiComponent
sta uiComponent
lda #2
sta updateUICount
rts
.endproc
;-----------------------------------------------------------------------------
.proc uiUpdate
lda uiComponent
bit bit0Mask ; UI_COMPONENT_NAME
beq :+
jsr screenDrawLevelName
lda uiComponent
:
bit bit1Mask ; UI_COMPONENT_AIR_NAME
beq :+
printXY #0, #(17*8), roTextAir, #4, #2, 1
jsr screenDrawAirFrame
lda uiComponent
:
bit bit2Mask ; UI_COMPONENT_AIR
beq :+
jsr screenDrawAirRemaining
lda uiComponent
:
bit bit3Mask ; UI_COMPONENT_SCORE_NAME
beq :+
printXY #4, #(19*8), roTextHighScore, #3
printXY #11, #(19*8), roTextScore, #4
lda uiComponent
:
bit bit4Mask ; UI_COMPONENT_SCORE
beq :+
printXY #11, #(20*8), score, #5
lda uiComponent
:
bit bit5Mask ; UI_COMPONENT_LIVES
beq :+
jsr screenDrawLives
lda uiComponent
:
bit bit6Mask ; UI_COMPONENT_HIGHSCORE
beq :+
printXY #3, #(20*8), highScore, #5
:
dec updateUICount
bne :+
lda #0
sta uiComponent
:
rts
.endproc
;-----------------------------------------------------------------------------
; 28209 cycle delay from start till after rts
.proc uiDelay
ldy #$80
ySet:
ldx #0
:
dex
bne :-
dey
bne :-
rts
.endproc
;-----------------------------------------------------------------------------
; This routine shows the MANIC and MINER text on screen.
; the macro uiShowMMTextXY puts specific values appropriate for each right
; into the routine (such as the address of the character width array)
; The Manic & Miner words are stored in a "compressed" form, this also decodes
; that. Each letter "pixel" is stored as a bit.
.proc uiShowMMText
row = srcPtrL
col = srcPtrH
offset = dstPtrL
index = dstPtrH
colMaskL = sizeL
colMaskR = sizeH
width = tmpBot + 0
height = tmpBot + 1
dataByte = tmpBot + 2
dr = tmpBot + 3
dc = tmpBot + 4
dw = tmpBot + 5
pr = tmpBot + 6
sty row
stx col
lda #0
sta offset
sta index
strLoop:
ldx index
colorLoc:
lda PLACEHOLDER, x ; unpack the color masks
tay
lda masksLeft, y
sta colMaskL
lda masksRight, y
sta colMaskR
lda #6 ; the text is 6 rows high
sta height
lda row
sta dr ; set the working counter to the row
charLoop:
lda col
sta dc ; set the working counter to the column
ldx index ; get the index to the character in the string
widthLoc:
lda PLACEHOLDER, x ; get the width of the character
sta width ; save
sta dw ; and init the working width
ldx offset ; the offset is into the encoded data
dataLoc:
lda PLACEHOLDER, x ; get the next encoded character
inc offset ; and move the index
sta dataByte ; save the character
colLoop:
lda dataByte ; load the character
asl ; shift out the MSB to get the bit
sta dataByte ; save the new shifted encoded character
bcc skipPlot ; if bit was 0, blank, nothing to do
lda #8 ; 1-bit to be drawn. "pixel" is 8 pixel-rows high
sta pr ; save row draw counter
lda dr ; load the screen draw row where drawing should happen
asl ; * 8
asl
asl
tay ; store the row in Y
lda dc ; get the column
and #1 ; and see if the column is odd or even (for color mask)
tax
:
lda dc ; start with the column
adc rowL, y ; and calculate the hi-res row/col address
sta write + 1
lda rowH, y
adc currPageH ; add the page to draw to
sta write + 2
lda #$ff ; assume all bits on
and colMaskL, x ; but then mask to get appropriate color
write:
sta PLACEHOLDER ; write to the screen
iny ; next hi-res pixel-row
dec pr ; and one less row to draw
bne :- ; do all 8 rows
skipPlot:
inc dc ; go to the next column
dec dw ; one less to do in the width of the character
bpl colLoop ; if not done the whole character, keep going
inc dr ; move down to the next row of the character
dec height ; one less row to do
bpl charLoop ; keep going till the whole character height done
lda width ; move the draw col by the width of the character just drawn
clc
adc col
sta col
inc index ; and move the string index to the next character
lda index
cmp #6
bcc strLoop ; if not all 5 characters (MANIC or MINER) done, keep going
rts
.endproc
;-----------------------------------------------------------------------------
; Prep uiShowMMText internal variables with data relevant for the
; specific text the macro is called with
.macro uiShowMMTextXY column, row, data, widths, colors
lda #<data ; MANIC or MINER bit-arrays
sta uiShowMMText::dataLoc + 1
lda #>data
sta uiShowMMText::dataLoc + 2
lda #<widths
sta uiShowMMText::widthLoc + 1 ; array of letter-widths in MANIC or MINER
lda #>widths
sta uiShowMMText::widthLoc + 2
lda #<colors ; array of letter colors in the words
sta uiShowMMText::colorLoc + 1
lda #>colors
sta uiShowMMText::colorLoc + 2
ldx column ; screen location passed in x/y
ldy row
jsr uiShowMMText ; show the word on-screen
.endmacro
;-----------------------------------------------------------------------------
.proc uiTitleScreen
scrollPtrL = 0 ;tmpBot + 0
scrollPtrH = 1 ;tmpBot + 1
scrollLen = 2 ;tmpBot + 2
scrollIdx = 3 ;tmpBot + 3
titleState = 4 ;currLevel
lda #0
sta leftEdge ; reset the left edge
lda #11*8 ; position willy for the UI
sta willyYPos
lda #0
sta willyFrame
lda #18
sta willyXPos
lda #<titleMusic ; init the music ptr
sta musicL
lda #>titleMusic
sta musicH
ldx #1 ; do a full screen clear of both buffers
jsr screenClear
jsr screenSwap
ldx #1
jsr screenClear
lda #0
sta titleState ; set to bounce manic miner / audio
sta uiComponent ; and init the ui update to nothing
lda #UI_COMPONENT_SCORE_NAME | UI_COMPONENT_SCORE | UI_COMPONENT_HIGHSCORE
jsr uiUpdateComponent ; add an update for bottom part of screen
jsr screenDrawWilly ; show willy on this screen
uiShowMMTextXY #6, #6, manicText, manicCharWidth, manicColors
printXY #0, #22*8, roTextAppleIIVersion, #19
printXY #0, #23*8, roTextStefan, #19
jsr uiUpdate ; show the UI on the Manic screen
jsr screenSwap
jsr screenDrawWilly ; show willy on the other screen
uiShowMMTextXY #6, #6, minerText, minerCharWidth, minerColors
printXY #0, #22*8, roTextAppleIIVersion, #19
printXY #0, #23*8, roTextStefan, #19
jsr uiUpdate ; show the UI on the Miner screen
lda KBDSTRB
mainLoop:
jsr screenSwap ; swap screens (manic/miner) or scroll text
jsr inputUI ; read keys -1 - quit, 0 - no key, 1 - go to game
beq stayInUI ; no key
bpl playGame ; go to game
lda #EVENT_EXIT_GAME ; quit
bne exit
playGame:
lda #EVENT_OK
exit:
jmp done
stayInUI:
lda titleState ; get the state (bounce vs scroll)
beq bounce
jmp introScroll ; 0 - bounce, 1 - scroll
bounce:
jsr audioPlayTitleNote ; play the tune
bcc mainLoop ; tune done when carry is set, else bounce
lda #2
sta titleState ; use this as a temporary counter
:
ldx #0 ; clear the upper portion of the screen
jsr screenClear ; show both manic & miner
uiShowMMTextXY #6, #0, manicText, manicCharWidth, manicColors
uiShowMMTextXY #6, #8, minerText, minerCharWidth, minerColors
jsr screenDrawWilly ; show willy as well
jsr screenSwap
dec titleState ; do for both buffers
lda titleState
bne :-
lda #1 ; set the state to the scrolling screen
sta titleState
lda #<roTextIntro ;init the scrolling message text
sta scrollPtrL
lda #>roTextIntro
sta scrollPtrH
lda #0
sta scrollLen
lda #19
sta scrollIdx
introScroll: ; show the scrolling message
ldy willyYPos ; start by erasing willy so the eor draw works
lda #16 ; 16 rows from his Y
sta sizeL ; track rows in sizeL
:
clc
lda willyXPos ; start with his X
asl ; * 2 for screen coordinates
adc rowL, y ; get the hires coordinates
sta writeZero + 1
lda rowH, y
adc currPageH
sta writeZero + 2
lda #0 ; write 4 zero-bytes to each row
ldx #3
writeZero:
sta PLACEHOLDER, x
dex
bpl writeZero
iny ; next hi-res row
dec sizeL ; one more row done
bne :-
lda willyFrame ; get the current frame
clc
adc #2 ; advance by 2
and #7 ; and keep in the frame range
sta willyFrame ; update the frame
jsr screenDrawWilly ; and draw willy in the new pose
printXYlh scrollIdx, #16*8, scrollPtrL, scrollPtrH, scrollLen
lda scrollIdx ; see if scrolled all the way into the screen
beq :+ ; if printing at 0, then scrolled all the way in
dec scrollIdx ; not scrolled in all the way, so move the start left
inc scrollLen ; and increase the length to print by 1
bne :++ ; and skip moving the start of the message
:
inc scrollPtrL ; move the scroller so the left disappears off
bne :+ ; the left end of the screen
inc scrollPtrH
:
jsr uiDelay ; wait a bit so the message can be read
ldy scrollLen ; see if this is the end of the message
lda (scrollPtrL), y
bne :+ ; if not a zero, still in message
dec scrollLen ; start printing less of the message so the tail scrolls across
bmi demoTime ; when completely done, go to demo mode
:
jmp mainLoop ; repeat till fully scrolled
demoTime:
lda #DEMO_TIMER_INITAL ; set up the demo variables
sta demoTimer
lda #1
sta demoDirection
done:
sta demoMode
rts
.endproc
;-----------------------------------------------------------------------------
.proc uiWaitForIntroEnter
iter = tmpBot + 0 ; how many times to loop
color = tmpBot + 1 ; the starting color for the string
xPos = tmpBot + 2 ; x for string
yPos = tmpBot + 3 ; y for string
textL = tmpBot + 4 ; string pointer
textH = tmpBot + 5
len = tmpBot + 6 ; how many characters (0 based)
lda KBDSTRB ; clear the keyboard
jsr screenSwap::valueSwap
printXY #0, #22*8, roTextPressEnter, #19
lda #$28 ; intentionally outside the range
sta color ; it gives an interesting "materialize" effect
lda #22*8
sta yPos
cycleLoop:
lda #6 ; print ENTER at x 4
sta xPos
lda #<roTextEnter ; point at ENTER text
sta textL
lda #>roTextEnter
sta textH
lda #5
sta len
jsr textColorCycle ; show the text in color
ldy #$40
jsr uiDelay::ySet
lda KBD ; hold the load screen graphic till a key is pressed
bpl cycleLoop
lda KBDSTRB ; clear the keyboard
jsr screenSwap::valueSwap
ldx #1 ; for clear-screen, x = 1 is all clear, x = 0 is partial
jsr screenClear
jsr screenSwap ; swap to see page 1
ldx #1
jmp screenClear ; all clear page 2
.endproc

117
src/apple2/variables.inc Normal file
View File

@ -0,0 +1,117 @@
;-----------------------------------------------------------------------------
; variables.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "ZEROPAGE"
;-----------------------------------------------------------------------------
currPageH: .res 1 ; $02 or $04 - Hi for screen buffer to draw t0
backPage: .res 1 ; 0 or 1 - just used to toggle HISCR or LOSCR
monochrome: .res 1 ; 0 for color, 1 for black and white
leftEdge: .res 1 ; distance the screen has scrolled to the right
cameraMode: .res 1
tilesRendered: .res 1 ; count the number of tiles shown in a screen. Used to time music delay
willyXPos: .res 1 ; column for willy
willyYPos: .res 1 ; pixel-row for willy
willyYRow: .res 1 ; row (YPos / 8) for willy
willyFrame: .res 1 ; willy animation frame
willyDir: .res 1 ; direction willy is facing
willyJumpCounter: .res 1 ; what phase of a jump willy is in
willyFallFromJump: .res 1 ; 0 or 1. 1 when willy starts jumping. Affects falling death
numSprites: .res 1 ; how many sprites (excl. willy) to draw in a level (door is last)
spriteXPos: .res MAX_SPRITES ; col position of the sprite
spriteYPos: .res MAX_SPRITES ; pixel row
spriteDir: .res MAX_SPRITES ; facing direction
spriteMin: .res MAX_SPRITES ; min (turn/hold) point for path
spriteMax: .res MAX_SPRITES ; max point for path
spriteSpeed: .res MAX_SPRITES ; speed (frames/pixels) to move the sprite
spriteTick: .res MAX_SPRITES ; counter how often a sprite animates (spritespeed as init)
spriteFramesIdx: .res MAX_SPRITES ; Index into
spriteFrame: .res MAX_SPRITES ; which frame the sprite is on
spriteClass: .res MAX_SPRITES ; see CLASS_* in defs.inc for masks
spriteColor: .res MAX_SPRITES ; index into masks<Left|Right> in rosystem.inc
movementMask: .res 1 ; movement that happened in willyMove. See MASK_* in defs.inc
userKeyMask: .res 1 ; user desire to move based on keys pressed. See MASK_* in defs.inc
conveyorMask: .res 1 ; 0, willy not on conveyor, 2 for left, 1 for right
currLevel: .res 1 ; level that's active
lives: .res 1 ; lives in reserve
airCols: .res 1 ; screen columns that have an air bar in them
airTipGfx: .res 1 ; the bit pattern for the tip of the air bar
airFlow: .res 1 ; the "tick" till a unit of air is decreased
livesFrame: .res 1 ; anim frame for the walking willy's at the bottom
keysFrameNum: .res 1 ; animation frame for keys in the level (color)
conveyorFrameNum: .res 1 ; animation frame for conveyor tile to be active
keysToCollect: .res 1 ; number of keys that remain to be collected
eventState: .res 1 ; see EVENT_* in defs.inc for bitmask values
updateUICount: .res 1 ; updateUI is called when non-zero
uiComponent: .res 1 ; See UI_COMPONENT_* in defs.inc for mask values. What UI to update
fullScreenClearCount: .res 1 ; 0 - clear only top, non-zero all. Is counted down by gameAI
musicL: .res 1 ; pointer or index for playing music
musicH: .res 1 ; hi pointer for playing UI music
audioMask: .res 1 ; see AUDIO_* in defs.inc
demoMode: .res 1 ; 0 - not a demo, 1 when demo mode active
demoTimer: .res 1 ; in demo mode, scroll when counter is 0
demoDirection: .res 1 ; direction the demo scroll will move the screen
cheatIndex: .res 1 ; count cheat code entry or when active, if 6 is down
cheatActive: .res 1 ; non-zero when the cheat was successfully entered
;-----------------------------------------------------------------------------
tempBlock: .res 13 ; widely used z-page general memory
srcPtrL := tempBlock + 0 ; often a pointer Lo
srcPtrH := tempBlock + 1 ; often a pointer Hi
dstPtrL := tempBlock + 2 ; often a pointer Lo
dstPtrH := tempBlock + 3 ; often a pointer Hi
sizeL := tempBlock + 4 ; sometimes a size used in ptr operations
sizeH := tempBlock + 5 ; sometimes a size used in ptr operations
tmpBot := tempBlock + 6 ; start of block of 6 zp values used randomly
;-----------------------------------------------------------------------------
bitMasks: ; constant - used mostly for bit instruction
bit0Mask: .res 1 ; 1
bit1Mask: .res 1 ; 2
bit2Mask: .res 1 ; 4
bit3Mask: .res 1 ; 8
bit4Mask: .res 1 ; 16
bit5Mask: .res 1 ; 32
bit6Mask: .res 1 ; 64
bit7Mask: .res 1 ; 128
;-----------------------------------------------------------------------------
.segment "LOWMEM"
; These are instance buffers for sprites / tiles. They are copied into this
; area and then masked for color from where they are rendered
levelLayout: .res PLAY_COLS * PLAY_ROWS ; Unpacked level (tile) info - keep 1st for alignment
; Instances for display
spriteInstances: .res MAX_SPRITE_IFRAMES * SPRITE_BYTES
tilesInstances: .res TILES_PER_LEVEL * TILE_BYTES ; instances of tiles in use bitmaps
keyAnimTiles: .res KEYS_FRAMES * TILE_BYTES ; color instances of key tile
conveyorAnimTiles: .res CONVEYOR_FRAMES * TILE_BYTES ; instances of conveyor animated tiles
; cache of 8 pixel-rows for 32 double-byte characters. The level name is centered in here, and drawn from here
levelNameGfx0: .res PLAY_COLS * 2 * 8
;-----------------------------------------------------------------------------
.segment "DATA"
; The scores are updated in these text strings directly
highScore:
.byte "000000"
score:
.byte "000000"
;-----------------------------------------------------------------------------
.segment "HIMEM"

541
src/apple2/willy.inc Normal file
View File

@ -0,0 +1,541 @@
;-----------------------------------------------------------------------------
; willy.inc
; Part of manic miner, the zx spectrum game, made for Apple II
;
; Stefan Wessels, 2020
; This is free and unencumbered software released into the public domain.
;-----------------------------------------------------------------------------
.segment "CODE"
;-----------------------------------------------------------------------------
; Moves willy. Incorporates user desire (userKeyMask) and conveyor direction
; in movement and does movement and collision resolution. This code was juggled a
; whole lot to make the outcome match that of the original game. It's quite
; possibly sub-optimal, but it does what it is meant to do.
.proc willyMove
willyYPosBackup = tmpBot + 1
willyXPosBackup = tmpBot + 2
willyFrameBackup = tmpBot + 3
willyFloor = tmpBot + 4
lda movementMask
bit bit2Mask ; MASK_AIR
beq checkHorzKeys ; on ground - check horizontal keys
jmp selectDirection ; in air - check horizontal motion
checkHorzKeys:
lda userKeyMask ; get the user Key
ldx conveyorMask ; and get the conveyor direction
beq notOnConveyor ; ignore conveyor code if not on a conveyor
and conveyorMask ; and user desire with conveyor
bne onConveyor ; if same, user conveyor direction for actual
lda userKeyMask ; get the user mask and
and #<~MASK_AIR ; if it's got no horizontal component
beq onConveyor ; willy is following the conveyor
lda movementMask ; user key horiz and not same as conveyor
jmp selectDirection ; so simply keep the current movement going
onConveyor:
lda movementMask ; actual is now conveyor direction
and #<~(MASK_LEFT | MASK_RIGHT) ; clear current
ora conveyorMask ; add conveyor direction
sta movementMask ; store as actual
jmp selectDirection ; use the conveyor for sideways
notOnConveyor:
and #<~MASK_AIR ; clear the jump desire
sta movementMask ; make actual user desire
selectDirection:
and #(MASK_LEFT | MASK_RIGHT) ; see if willy is moving horizontally
bne :+ ; yes - handle horizontal movement
jmp vertical
:
and #MASK_RIGHT ; check MASK_RIGHT
bne right ; if set, move to the right
left:
lda willyDir ; see if already heading left
bne moveLeft ; if so, keep moving left
lda #0 ; when turning, no direction
sta movementMask
lda #1 ; was facing right, so turn around
sta willyDir
lda willyFrame ; flip the facing frame to left
ora #4
sta willyFrame
bne vertical
moveLeft:
ldx willyFrame ; get the frame
stx willyFrameBackup ; back it up
dex ; move one left
cpx #4 ; wrapped?
bcc :+ ; yes, move to previous column
stx willyFrame ; not wrapped, save the frame
bcc :+
jmp vertical
:
ldx #7 ; keep going, load right most frame
stx willyFrame ; set frame
ldx willyXPos ; get the column
stx willyXPosBackup ; save it
dex ; previous column
stx willyXPos ; make that current
ldy #0 ; check side (left) collisions column
beq hCollision ; BRA
right:
lda willyDir ; see if willy's already facing right
beq moveRight ; if so, move
lda #0 ; turn willy to the right
sta willyDir
sta movementMask ; and clear the movement mask
lda willyFrame
and #3 ; set right facing frame
sta willyFrame
jmp vertical
moveRight:
ldx willyFrame ; back up the animation frame
stx willyFrameBackup
inx ; next frame (to the right)
cpx #4 ; wrapped?
bcs :+ ; yes, move to next (right) column
stx willyFrame ; save the frame
bcc vertical
:
ldx #0
stx willyFrame ; set frame 0
ldx willyXPos ; back up the column
stx willyXPosBackup
inx ; move right
stx willyXPos ; save this column
ldy #1 ; check the right-hand column for collisions
hCollision:
jsr willySetWorldPtr ; set up the world pointer to check collisions
ldx #2 ; assume checking 2 rows
lda willyYPos ; get the height in pixels
and #7 ; see if willy is aligned
beq colLoop ; yes, go with 2 rows
inx ; if not aligned, willy crosses 3 rows
colLoop:
lda (srcPtrL), y ; load the world byte
beq :+ ; if air then no collision
jsr willyWorldCollision ; resolve the collision if needed
bcc :+ ; if carry clear, can move (didn't hit a wall)
lda willyXPosBackup ; hit a wall, so restore position (column)
sta willyXPos
lda willyFrameBackup ; and also restore the frame
sta willyFrame
jmp vertical
:
tya ; Y is 0 or 1 (left or right), put in a
adc #32 ; move down a row
tay ; and put back in y
dex ; x has the number of rows remaining to check
bne colLoop ; do till all rows checked
vertical:
lda movementMask
bit bit2Mask ; MASK_AIR
bne vertMove ; in the air already then move vertically
lda userKeyMask ; get the user desire
bit bit2Mask ; MASK_AIR see if user wants to jump
beq willyCollisionFeet ; if not then check feet
and #<~MASK_AIR ; clear jump from desire
sta userKeyMask ; and save
lda movementMask ; update actual
ora #MASK_AIR ; by adding a jump
sta movementMask
lda #1 ; mark this as a fall starting
sta willyFallFromJump ; from a jump - willy dies easier
vertMove:
lda willyYPos ; save the current Y position
sta willyYPosBackup
lda willyJumpCounter ; get the current jump counter for height calculation
cmp #18 ; see sbc #4 below for why 18 (up/down curve length)
bcs falling ; if jump counter gt 17 then falling (0-17 is jump)
lsr ; / 2
sec
sbc #4 ; -4, so -4, -4, -3, -3, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4
clc
adc willyYPos ; adjust willy height
sta willyYPos
ldx willyJumpCounter ; get the current jump counter for height calculation
lda jumpFreq, x
ldy #$08 ; duration for the freq
jsr audioPlayNote::freq ; make a sound of this freq and duration
inc willyJumpCounter
lda willyJumpCounter
cmp #9
bcs willyCollisionFeet ; and move the jump counter along
willyCollisionTop:
lda willyYPosBackup ; see where willy was
and #7 ; if aligned with a row, now entering a new row so check collision
bne willyCollisionFeet ; not aligned, no collision, go to feet check
jsr willySetWorldPtr ; set the srcPtr to point into the world
ldy #0 ; start with the head left
lda (srcPtrL), y ; read the world byte
beq :+ ; if air then do nothing
jsr willyWorldCollision ; not air so handle the potential collision
bcs hitHead ; carry set means wall collision, so fall
:
ldy #1 ; check the right as well
lda (srcPtrL), y
beq willyCollisionFeet ; if air, ignore
jsr willyWorldCollision
bcc willyCollisionFeet ; carry clear means no collision
hitHead:
lda willyYPosBackup
sta willyYPos
lda #18
sta willyJumpCounter
jmp willyCollisionFeet ; and check for landing immediately
falling:
lda willyJumpCounter ; get the current jump counter for height calculation
and #$0f
tax
lda fallFreq, x
ldy #$08 ; duration for the freq
jsr audioPlayNote::freq ; make a sound of this freq and duration
inc willyJumpCounter ; and move the jump counter along
lda movementMask ; strip horizontal from actual
and #<~(MASK_LEFT | MASK_RIGHT)
sta movementMask
lda willyYPos ; get willy's height
clc
adc #4 ; move him 4 down (fall speed)
sta willyYPos
willyCollisionFeet:
lda #0 ; assume not on a conveyor
sta conveyorMask
lda willyYPos ; see if willy is level with a floor
and #7
bne positionScreen ; if not, don't check the feet
lda willyJumpCounter ; see if still going up in jump
beq :+ ; if 0 then not jumping
cmp #10 ; if still going up in the jump, don't check the feet
bcc positionScreen
:
jsr willySetWorldPtr ; set up the world pointer
ldy #64 ; check the ground below willy, left
lda (srcPtrL), y
sta willyFloor ; store the byte
beq :+ ; if air, don't resolve
jsr willyFloorCollision ; resolve the collision
:
ldy #65 ; check the floor right
lda (srcPtrL), y
beq checkFloor ; if air, done with feet
tax ; save the byte
ora willyFloor ; and update the floor
sta willyFloor
txa ; restore the world byte
jsr willyFloorCollision ; and resolve it
checkFloor:
lda willyFloor ; was there something under willy's feet
bne positionScreen ; if yes, then position willy
lda willyJumpCounter ; see if willy is in a jump or fall
bne positionScreen ; yes, position screen
lda #18 ; willy was walking, so set him to fall
sta willyJumpCounter
lda movementMask ; strip horizontal from actual
and #<~(MASK_LEFT | MASK_RIGHT) ; clear left and right
ora #MASK_AIR ; set the mask that he's now in the air (fall)
sta movementMask
positionScreen: ; this is also called from gameInitStage
lda cameraMode ; see which "camera mode" is active
bne cameraScroll ; non zero is scroll mode
camera3Zone: ; zone 1: 0-19, 2: 6-25, 3: 12-31
lda willyXPos ; see where Willy is
cmp #10 ; 10 divides zones 1 and 2
bcs zone2or3 ; ge 10 means zone 2 or 3
lda leftEdge ; zone 1 - see where the edge is
cmp #0 ; if it's at 0 all is well
beq done
cameraLess:
dec leftEdge ; edge is gt 0, so move it left
bpl moveName ; BRA
zone2or3:
cmp #20 ; 20 divides zones 2 and 3
bcs cameraRight ; ge 20 means zone 3
lda leftEdge ; see where the edge is (in zone 2)
cmp #6 ; zone 2 edge wants to be at 6
beq done ; if it's there, all is well
bcs cameraLess ; if it's gt 6, then move it left
inc leftEdge ; move the edge right
bne moveName ; BRA
cameraRight:
lda leftEdge ; zone 3, see where the edge is
cmp #$0c ; if it's at 12
beq done ; then it's all good
inc leftEdge ; otherwise move it right towards 12
moveName: ; if the edge moves the text needs to move as well
lda #UI_COMPONENT_NAME ; and mark the name as needing to scroll too
jsr uiUpdateComponent
rts
cameraScroll:
lda willyXPos
sec ; col is in accumulator
sbc #$0a ; see if willy is past column 10
bcs :+
lda #0 ; not, so set the left edge to the left
bne :++ ; BRA
:
cmp #$0d ; see if the col is less than 13
bcc :+
lda #$0c ; col is 13 or greater, so clamp to 12
:
cmp leftEdge ; see if the edge needs to move
beq :+ ; don't move
sta leftEdge ; set the new left edge
lda #UI_COMPONENT_NAME ; and mark the name as needing to scroll too
jsr uiUpdateComponent
done:
rts ; done with willy's movement
.endproc
;-----------------------------------------------------------------------------
; resolves collisions for willy. Used by feet but foot collision entry is
; from willyFloorCollision. on exit, carry set means wall collision
.proc willyWorldCollision
clc
cmp #DATA_BUSH ; bushes kill willy
beq willyDies
cmp #DATA_ROCK ; rocks kill willy
bne :+
willyDies:
lda #EVENT_DIED ; simply set the die event
ora eventState
sta eventState
rts
:
cmp #DATA_WALL ; walls block willy
bne :+
rts ; carry was set by the cmp and equality. set means wall collision
:
cmp #DATA_KEY ; key's need to be counted
bne :+
jmp willyHitKey ; clears carry
:
cmp #DATA_DOOR ; added dynamically when last key found
bne :+
lda #EVENT_NEXT_LEVEL ; set event to move to next cavern/level
ora eventState
sta eventState
rts
:
cmp #DATA_SWITCH1 ; added at level init for kong screens
bne :+
jmp willyHitSwitch1
:
cmp #DATA_SWITCH2 ; added at level init for kong screens
bne done
jmp willyHitSwitch2
done:
clc ; for unhandled (floor tiles), just clear carry
rts
.endproc
;-----------------------------------------------------------------------------
.proc willyFloorCollision
cmp #DATA_FLOOR1 ; floors are landed on
beq landed
cmp #DATA_WALL ; walls can be walked on
beq landed
cmp #DATA_FLOOR2 ; special can be walked on
bne :+
landed:
lda movementMask ; see landing from a jump/fall
and #MASK_AIR
beq notFromAir ; just a foot-fall from walking, no action
clc
lda willyFallFromJump ; see if a jump
adc willyJumpCounter ; and how far
cmp #18+9 ; compare to death height
bcc fellNotTooFar ; not too far
jmp willyWorldCollision::willyDies ; fell to far, kill willy
fellNotTooFar:
lda #0 ; reset the fall from jump
sta willyFallFromJump
sta willyJumpCounter ; and reset the willy jump counter
lda #<~MASK_AIR ; clear the air bit
and movementMask
sta movementMask
notFromAir:
rts
:
cmp #DATA_CONVEYOR ; landed on a conveyor
bne :+
ldx currLevel ; get the level
lda conveyorDirections, x ; get the direction of the conveyor
sta conveyorMask ; set it as the conveyor mask (which is reset each frame)
bne landed ; and do landing code
:
cmp #DATA_COLLAPSE ; check for collapsing tiles
bcc willyWorldCollision ; less than, not collapsing
cmp #DATA_COLLAPSE + 9 ; in the collapse range
bcs willyWorldCollision ; no, check non-walk/floor tiles
jsr willyCollapse ; collapse a platform tile, returns with carry clear
bcc landed ; BRA to land code
.endproc
;-----------------------------------------------------------------------------
.proc willyHitSwitch1
clc
adc #1 ; DATA_SWITCH1 becomes DATA_SWITCH1_OPEN
sta (srcPtrL), y ; make this switch draw open
lda #0
sta levelLayout+11*32+17 ; make a hole in the wall
sta levelLayout+12*32+17
ldx #1 ; sprite 1 barrel needs to go further
lda #19 ; this is the new max for return-kong
extend:
sta spriteMax, x ; make the new max active
clc ; must leave with carry clear - not a wall collision
rts
.endproc
;-----------------------------------------------------------------------------
.proc willyHitSwitch2
clc
adc #1 ; DATA_SWITCH2 becomes DATA_SWITCH2_OPEN
sta (srcPtrL), y ; make this switch draw open
lda #0
sta levelLayout+2*32+15 ; remove kong's platform
sta levelLayout+2*32+16
ldx #3 ; kong is at index 3
lda #14*8-5 ; put the fallen-down destination for kong in place
sta spriteMax, x
lda #2 ; turn kong upside down
sta spriteFrame, x
lda #0 ; set kong's direction to down
sta spriteDir, x
rts
.endproc
;-----------------------------------------------------------------------------
.proc willyCollapse
clc
adc #1 ; move the tile-top one down
cmp #DATA_COLLAPSE + 7 ; is it all the way down
bcc :+ ; not yet
lda #0 ; yes, so erase the tile
clc
:
sta (srcPtrL), y ; make the change in the level
rts
.endproc
;-----------------------------------------------------------------------------
.proc willyHitKey
tempX = tmpBot + 5
stx tempX ; save x - it may be an index in left/right col
lda #0 ; erase the key tile in the level
sta (srcPtrL), y
ldx #3 ; add 100 (digit 3 of 6, zero based 000100)
lda #1
jsr textAddScore
dec keysToCollect ; 1 less key to collect
bne done ; all keys collected?
ldx currLevel ; get the level
lda doorL, x ; get the door location in the level (lo)
sta putDoor + 1
lda doorH, x ; and hi
sta putDoor + 2
lda #DATA_DOOR ; get the door tile
putDoor:
sta PLACEHOLDER ; and add the door tile to the level
done:
ldx tempX ; restore the saved x
clc ; make sure carry is clear
rts
.endproc
;-----------------------------------------------------------------------------
.proc willySetWorldPtr
lda willyYPos ; get the height
lsr ; divide by 8
lsr
lsr
sta willyYRow ; save the row willy's in
tax ; put the row in Y
clc
lda mult32L, x ; row * 32
adc willyXPos ; and add the X position (levelLayout is aligned so no need to add lo)
sta srcPtrL ; the low byte of the pos in the level
lda mult32H, x ; get the high byte
adc #>levelLayout ; and offset into the level
sta srcPtrH ; and now srcPtr points at willy in the level
rts
.endproc