Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
genemedic/genemedic.asm
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
2930 lines (2268 sloc)
100 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; This is Gene Medic version 1.0 | |
; by Jason H. Moore, Ph.D. | |
; File genemedic.asm | |
; Last updated 12/29/17 | |
; Compile with DASM genemedic.asm -ogenemedic.bin -f3 | |
; The goal of the game is to save a patient with a common | |
; disease such as cancer by editing mutations in their | |
; genes. Mutations can have known or unknown consequences upon | |
; editing (joystick down) with some revealed by consulting the | |
; electronic health record powerup (computer) or the scientific | |
; literature (text) power ups (joystick up). Each gene edit costs | |
; money that can be replenished with the money bag power up. | |
; The goal is to improve the patient health ("P" top score) | |
; before the financial resources are exhausted ("$" lower score). | |
; For more information see http://GeneMedic.org | |
; Special thanks to Andrew Davies and Darrell Spice for their | |
; great tutorials that helped with the development of this | |
; edutainment game. Thanks to countless others who posted | |
; useful comments and code on various websites and forums | |
; including the Stella mailing list and AtariAge.com. | |
; I also found the book "Making games for the Atari 2600" | |
; by Steven Hugg to be useful. I have tried to comment the code | |
; as much as I possibly can without writing my own book. | |
; Programming for the 2600 is not easy! You have been warned :) | |
; **************************************************************** | |
; Tell the assembler we are working with the 6502 processor | |
; **************************************************************** | |
PROCESSOR 6502 | |
; **************************************************************** | |
; Include the vcs header file with the 2600 register and | |
; memory map definitions. Also include the macro file that | |
; has some useful functions such as 'sleep' used here. | |
; **************************************************************** | |
INCLUDE VCS.h | |
INCLUDE macro.h | |
; **************************************************************** | |
; Constants set here | |
; **************************************************************** | |
P0HEIGHT = 55 ; height of player 0 sprite in scanlines | |
PUHEIGHT = 16 ; height of powerup sprite in scanlines | |
SCHEIGHT = 14 ; height of the score playfield | |
CYTHEIGHT = 14 ; height of the cytoplasm playfield | |
DNAHEIGHT = 11 ; height of the DNA helix playfield | |
HHEIGHT = 36 ; height of the heart playfield | |
GHEIGHT = 14 ; height of the gene name playfield | |
JHEIGHT = 14 ; height of the jockey name playfield | |
XMAX = 150 ; max X position to right for player | |
XMIN = 5 ; min X position to left for player | |
P0XSTART = 20 ; player 0 starting X position | |
P0YSTART = 80 ; player 0 starting Y position | |
P1RESX = 38 ; player 1 starting X position for research | |
; powerup - in sleep cycles | |
P1MONX = 54 ; player 1 starting X position for money | |
; bag powerup - in sleep cycles | |
P1EHRX = 22 ; player 1 starting X position for EHR | |
; powerup - in sleep cycles | |
M0X = 28 ; missile 0 starting X position for in sleep | |
; cycles. This M is used to queue position | |
; of nucleotide to edit triggering tricorder | |
; graphic above player 0. | |
; **************************************************************** | |
; Tell the assembler the memory locations of our game variables. | |
; ds is a pseudo-op for assembler that stands for 'define space' | |
; ds 1 = one byte and ds 2 = two bytes. Remember that the 2600 | |
; only has 128 bytes of RAM! | |
; **************************************************************** | |
SEG.U variables ; pseudo-op for the assembler | |
ORG $80 ; the starting location of RAM | |
P0X ds 1 ; player 0 X coordinate | |
P0Y ds 1 ; player 0 Y coordinate | |
P0Pos ds 1 ; byte for P0 fine (high nibble) and | |
; course (low nibble) horizontal position | |
P0LineColor ds 1 ; player 0 color slice for that scanline | |
P0GfxFlag ds 1 ; flag for which P0 graphic to use | |
; 1 = no tricorder | |
; 2 = health tricorder [+] | |
; 3 = harm tricorder [!] | |
; 4 = unknown tricorder [-] | |
; 5 = context dependent tricorder [::] | |
ResearchFlag ds 1 ; flag for drawing the research powerup | |
; 1 = draw, 0 = don't draw | |
EHRFlag ds 1 ; flag for drawing the EHR powerup | |
; 1 = draw, 0 = don't draw | |
MoneyFlag ds 1 ; flag for drawing the money bag powerup | |
; 1 = draw, 0 = don't draw | |
NewLevelFlag ds 1 ; time to draw a new playfield? This gets set | |
; to 1 when player reaches right side of screen | |
ScreenFlag ds 1 ; which screen to draw? A or B? | |
; this help set up alternating screens with | |
; different playfield graphics for sense | |
; of movement through the cell | |
PScore ds 1 ; this is the patient health score | |
DScore ds 1 ; this is the dollars score | |
DScoreFLag ds 1 ; flag to indicate whether DScore = 0 | |
; to prevent going negative | |
ScoreGfx ds 1 ; holds the current score graphics line | |
UpFlag ds 1 ; flag for joystick moved up (for power ups) | |
DownFlag ds 1 ; flag for joystick moved down (for edits) | |
MutationFlag ds 1 ; holds info about nature of mutation | |
; set each screen by a random number | |
; 0 = no mutation | |
; 1 = mutation - known, helpful | |
; 2 = mutation - known, harmful | |
; 3 = mutation - unknown, helpful | |
; 4 = mutation - unknown, harmful | |
; 5 = mutation - context dependent, helpful | |
; 6 = mutation - context dependent, harmful | |
EditFlag ds 1 ; keeps track of successful edits | |
; so score only modified once per screen | |
MBUsedFlag ds 1 ; keeps track of whether money bag powerup | |
; has been used for that screen. Only used once. | |
WinFlag ds 1 ; this indicates that the player has won the game | |
LoseFlag ds 1 ; this indicates that the player has lost the game | |
EndSoundFlag ds 1 ; flag indicating final sound effects are done | |
; so they only play once at end of game | |
RandomPU ds 1 ; holds 8-bit pseudo random number for powerups | |
RandomMut ds 1 ; holds 8-bit pseudo random number for mutations | |
GameLaunchFlag ds 1 ; a flag for indicating the game has booted. | |
; this is used to indicate the start screen | |
; should be drawn until fire button pressed | |
SFX_LEFT ds 1 ; index for sound effect functions | |
SFX_RIGHT ds 1 ; index for sound effect functions | |
; **************************************************************** | |
; Tell the assembler where the origin (ORG) of the program is | |
; ROM is memory location $F000 to $FFFF | |
; **************************************************************** | |
SEG ; pseudo-op to set current segment | |
ORG $F000 ; let the assembler know start address | |
; **************************************************************** | |
; This initializes the RAM and TIA registers by writing 0s. | |
; It also initalizes the stack pointer to $FF. This code comes | |
; from Andrew Davie's tutorial. Note just clearing the RAM did | |
; not work well on the original 2600 hardware. | |
; **************************************************************** | |
Reset | |
ldx #0 ; load the X register with a 0 | |
txa ; transfer X to accumulator | |
Clear | |
dex ; decrement X register | |
txs ; transfer X to stack pointer | |
pha ; push accumulator onto stack | |
bne Clear ; branch to Clear if accumulator != 0 | |
; **************************************************************** | |
; This initializes the random seed for the GetRandom subroutine | |
; Using two different random numbers to prevent dependencies | |
; between powerups and mutations. | |
; **************************************************************** | |
SetRandomSeed | |
lda INTIM ; this is an unknown value | |
eor #$FF ; XOR to flip bits so seed is not 0 | |
sta RandomPU ; Seed for GetRandomPU | |
lda INTIM ; this is an unknown value | |
eor #$FF ; XOR to flip bits so seed is not 0 | |
sta RandomMut ; Seed for GetRandomMut | |
; **************************************************************** | |
; This initializes the game launch flag for drawing start screen | |
; when game is first booted. | |
; **************************************************************** | |
lda #1 ; load accumulator with a 1 | |
sta GameLaunchFlag ; set game launch flag to draw start | |
; screen first time through until | |
; reset switch is pressed then flag=0 | |
jmp PlayfieldInit ; bypass the next bit of code on boot | |
; **************************************************************** | |
; This is marks the place in the code to jump to when starting a | |
; game after fire button is pressed from start screen. | |
; **************************************************************** | |
StartHere | |
lda #0 ; load accumulator with a 0 | |
sta GameLaunchFlag ; reset game launch flag so start | |
; screen isn't drawn anymore after | |
; reset switch is pressed | |
; **************************************************************** | |
; This initializes the player and playfield color registers | |
; **************************************************************** | |
PlayfieldInit | |
lda #$80 ; load accumulator with dark blue | |
sta COLUBK ; store in the background color memory | |
lda #1 ; load the accumulator with 1 | |
sta CTRLPF ; storing a 1 here indicates a | |
; reflected playfield | |
lda #$1E ; Load the player 1 color | |
sta COLUP1 ; set player 1 color register | |
; **************************************************************** | |
; This initializes the player X and Y position. | |
; **************************************************************** | |
lda #P0XSTART ; load accumulator with X position | |
sta P0X ; set P0 starting X position | |
lda #P0YSTART ; load accumulator with Y position | |
sta P0Y ; set P0 starting Y position | |
; **************************************************************** | |
; This initializes the patient (top) and money (bottom) scores | |
; that are presented to the player as colors. Brighter yellow for | |
; the patient score is an indication of health. Brighter yellow | |
; for the money score means more resources have been spent on the | |
; patient. The game is over when the max patient score (win), min | |
; patient score (loss), or max money score (loss) are reached. | |
; **************************************************************** | |
lda #1 ; load accumulator with 1 | |
sta PScore ; set left score to 1 | |
lda #1 ; load accumulator with 1 | |
sta DScore ; set left score to 1 | |
; **************************************************************** | |
; This initializes the game flags for tracking score and powerups. | |
; Most are set to 0 with only th P0 graphics flag set to 1. | |
; **************************************************************** | |
lda #1 ; load accumulator with flag = 1 to start | |
sta P0GfxFlag ; set player 0 graphic flag = 1 | |
; this draws player without tricorder. | |
; tricorder comes on when P0 collides | |
; with M0 that is present when mutation | |
; flag > 0 | |
lda #0 ; load accumulator with flag = 0 to start | |
sta UpFlag ; set joystick Up Flag = 0 | |
sta DownFlag ; set joystick Down Flag = 0 | |
sta EHRFlag ; set EHR Flag = 0 | |
sta MoneyFlag ; set Money Bag Flag = 0 | |
sta ResearchFlag ; set Research Flag = 0 | |
sta ScreenFlag ; set Screen Flag = 0 | |
sta EditFlag ; set Edit Flag = 0 to start, no edit | |
sta MBUsedFlag ; set Money Bag used Flag = 0 to start | |
sta WinFlag ; set the Win Flag = 0 to start, 1=win | |
sta LoseFlag ; set the Lose Flag = 0 to start, 1=lose | |
sta MutationFlag ; set Flag = 0, no mutation first screen | |
sta EndSoundFlag ; set Flag = 0 until end of game | |
sta NewLevelFlag ; time to draw new playfield? This gets | |
; set to 1 when player reaches right side | |
; of screen | |
; **************************************************************** | |
; The first part of a 2600 program is the vertical sync that | |
; tells the TV to get ready to draw a picture. The CPU needs | |
; to wait for three scanlines for the TV to get ready. This | |
; is done with VSYNC to start this process and WSYNC (x2) to | |
; wait for the scanlines to finish. | |
; **************************************************************** | |
VerticalSYNC ; The start of the new frame | |
; Main game loop starts here | |
lda #2 ; load the accumulator with a 2 | |
sta VSYNC ; store 2 in VSYNC memory to start | |
sta WSYNC ; wait for scanline to finish | |
sta WSYNC ; second WSYNC (need at least 2) | |
lda #0 ; load the accumulator with a 0 | |
sta VSYNC ; store 0 in VSYNC memory to end | |
; **************************************************************** | |
; The second part of a 2600 program is the vertical blank | |
; with an additional 37 scanlines of time before the screen | |
; is actually drawn on the TV. Can do some game computations | |
; here but must count the scanlines to add up to 37 total. | |
; 37 scanlines at 76 cycles each works out to be 43 ticks of | |
; the timer. Will set TIM64T to 43 to keep track of cycles. | |
; Will use this time for horizontal positioning of the sprites. | |
; Will also use this time for game calculations. | |
; **************************************************************** | |
lda #43 ; we have 43 ticks of the timer here | |
sta TIM64T ; start the timer for VBLANC | |
GameOverCheck1 ; check win & lose flags for game over | |
; if game over skip game calculations | |
; so no player movement during final screen | |
lda WinFlag ; load accumulator with Win Flag | |
beq GameOverCheck2 ; check lose flag if win flag = 0 | |
jmp VerticalBLANK ; skip game calcs if flag = 1 | |
GameOverCheck2 | |
lda LoseFlag ; load accumulator with Lose Flag | |
beq NewLevelCheck ; move on to game calcs if lose flag = 0 | |
jmp VerticalBLANK ; skip game calcs if flag = 1 | |
NewLevelCheck ; time to draw new level with new random | |
; powerup and gameplay flags? | |
lda NewLevelFlag ; if flag = 1 then it is a new level | |
bne NewLevel ; if flag = 0 then do game calculations | |
jmp CheckWin ; but skip setting new gameplay flags | |
; using jmp here to avoid error due to | |
; a branch that is too long. | |
; the new level flag gets set to 1 when | |
; the player gets to far right side of PF | |
NewLevel ; start here when it is a new level | |
; and new flags need to be set | |
; e.g. new powerup flags get set here | |
SetEditFlag ; set this flag to 0 on new level | |
lda #0 ; load accumulator with a 0 | |
sta EditFlag ; make sure Edit Flag = 0 on new screen | |
; this flag prevents multiple changes to | |
; score on same screen. | |
sta MBUsedFlag ; reset this flag that keeps track of | |
; whether the money bag powerup was used | |
sta WSYNC ; wait for finish of scanline | |
SetScreenFlag ; set the flag used to track which screen | |
; is drawn for cyto and nuc parts of PF | |
; this flag alternates between 0 and 1 | |
lda ScreenFlag ; load accumulator with flag value | |
beq ScreenFlagSet1 ; flag is zero so need to change to 1 | |
ScreenFlagSet0 ; flag = 1 so change to a 0 | |
lda #0 ; load accumulator with a 0 | |
sta ScreenFlag ; flag is 1 so need to change to 0 | |
jmp SetPUFlags ; done setting helix flag | |
ScreenFlagSet1 ; change this flag to a 1 | |
lda #1 ; load accumulator with a 1 | |
sta ScreenFlag ; flag is 0 so need to change to 1 | |
SetPUFlags ; set new flags for the powerups | |
lda #0 ; make sure all flags are reset to 0 | |
; when a new level starts | |
sta EHRFlag ; set flag to 0 | |
sta ResearchFlag ; set flag to 0 | |
sta MoneyFlag ; set flag to 0 | |
jsr GetRandomPU ; generate a random number from 0-255 | |
; number is returned in accumulator | |
and #%00000011 ; limit number to 0-3 | |
tax ; transfer accumulator to X register | |
sta WSYNC ; wait for finish of scanline | |
CheckEHR ; display EHR powerup? | |
cpx #0 ; if Random=0 then set EHR flag to 1 | |
bne CheckRes ; if != 1 check research powerup | |
lda #1 ; load accumulator with a 1 | |
sta EHRFlag ; set flag = 1 | |
sta WSYNC ; wait for finish of scanline | |
CheckRes ; display research powerup? | |
cpx #1 ; if Random=1 then set research flag to 1 | |
bne CheckMon ; now check money bag powerup | |
lda #1 ; load accumulator with a 1 | |
sta ResearchFlag ; set flag = 1 | |
sta WSYNC ; wait for finish of scanline | |
CheckMon ; display money bag powerup? | |
cpx #2 ; if Random=2 then set money bag flag to 1 | |
bne CheckDone ; done setting powerup flags | |
lda #1 ; load accumulator with a 1 | |
sta MoneyFlag ; set flag = 1 | |
sta WSYNC ; wait for finish of scanline | |
CheckDone ; if Random=3 then no powerup | |
; on that screen and all powerup | |
; flags = 0 | |
lda #0 ; load accumulator with a 0 | |
sta NewLevelFlag ; set this flag = 0 to reset this flag | |
; no longer a new level | |
SetMutFlags ; set new flags for the mutation | |
lda #0 ; make sure flag is reset to 0 | |
sta MutationFlag ; set flag to 0 | |
jsr GetRandomMut ; generate a random number from 0-255 | |
; number is returned in accumulator | |
and #%00000111 ; limit number to 0-7 | |
sta MutationFlag ; store value in mutation flag | |
sta WSYNC ; wait for finish of scanline | |
CheckWin ; is the game over? winner? | |
ldx PScore ; load the X register with the patient score | |
cpx #9 ; is the patient healed? | |
bne CheckLose1 ; branch if PScore != 9, not healed | |
lda #1 ; load accumulator with a 1 | |
sta WinFlag ; winner! Set WinFlag = 1 | |
jmp VerticalBLANK ; move on to draw final screen | |
CheckLose1 ; check for loss based on patient score = 0 | |
sta WSYNC ; wait for finish of scanline | |
lda PScore ; load accumulator with the patient score | |
bne CheckLose2 ; branch if PScore != 0 | |
lda #1 ; load accumulator with a 1 | |
sta LoseFlag ; loser! Set LoseFlag = 1 | |
jmp VerticalBLANK ; move on to draw final screen | |
CheckLose2 ; check for loss based on dollar score = 9 | |
ldx DScore ; load the X register with the patient score | |
cpx #9 ; is the player out of money? | |
bne MinDScore ; branch if DScore != 9 | |
lda #1 ; load accumulator with a 1 | |
sta LoseFlag ; loser! Set LoseFlag = 1 | |
jmp VerticalBLANK ; move on to draw final screen | |
MinDScore ; this keep the DScore from falling below 1 | |
lda DScore ; load X register with DScore value | |
bne SetM0X ; branch if X != 0 | |
lda #1 ; load accumulator with a 1 | |
sta DScore ; store the 1 in DScore to prevent 0 | |
SetM0X ; setting the X position for missile 0 | |
sleep M0X ; sleep this many cycles to set M0 | |
; in middle of screen | |
sta RESM0 ; trigger X position for missile 0 | |
; this never changes and is used as | |
; position marker for player 0 | |
sta WSYNC ; wait for finish of scanline | |
; next section sets the horizontal | |
; position of player 1 with unique | |
; X positions for each powerup. | |
; no fine positioning needed here | |
; because P1 is static | |
SetP1XEHR ; set powerup X pos if EHR flag = 1 | |
lda EHRFlag ; load the accumulator with EHR flag | |
beq SetP1XRes ; jump to next if flag = 0 | |
sleep P1EHRX ; delay to horizontally position sprite | |
sta RESP1 ; set sprite X pos by writing to RESP1 | |
sta WSYNC ; wait for finish of scanline | |
jmp StartHMoveP0 ; go to next section for P0 positioning | |
SetP1XRes ; set powerup X pos if research flag = 1 | |
sta WSYNC ; wait for finish of scanline | |
lda ResearchFlag ; load the accumulator with research flag | |
beq SetP1XMon ; jump to next if flag = 0 | |
sleep P1RESX ; delay to horizontally position sprite | |
sta RESP1 ; set sprite X pos by writing to RESP1 | |
sta WSYNC ; wait for finish of scanline | |
jmp StartHMoveP0 ; go to next section for P0 positioning | |
SetP1XMon ; set powerup X pos if money bag flag = 1 | |
sta WSYNC ; wait for finish of scanline | |
lda MoneyFlag ; load the accumulator with money bag flag | |
beq StartHMoveP0 ; jump to next if flag = 0 | |
sleep P1MONX ; delay to horizontally position sprite | |
sta RESP1 ; set sprite X pos by writing to RESP1 | |
StartHMoveP0 ; process P0 horizontal move here | |
; this bit of code from Battlezone game | |
; commonly used for horizontal positioning | |
sta WSYNC ; wait for finish of scanline | |
; timing of this WSYNC and next important | |
; for correct horizontal movement | |
lda P0X ; load accumulator with P0 X position | |
sec ; set the carry flag | |
DivideLoop ; divide by 15 | |
sbc #15 ; subtract 15 | |
bcs DivideLoop ; branch until negative | |
eor #7 ; calculate the fine offset | |
asl ; arithmetic shift left | |
asl | |
asl | |
asl | |
sta RESP0 ; fix the course position | |
sta WSYNC ; wait for finish of scanline | |
sta HMP0 ; set the fine offset | |
CheckMoneyBag ; is the money bag powerup activated? | |
lda MoneyFlag ; check if money bag powerup present | |
beq CheckP0M0Col1 ; if=0 then powerup not present | |
lda UpFlag ; is the jostick up? | |
beq CheckP0M0Col1 ; if=0 then joystick not up and skip | |
lda MBUsedFlag ; has the money bag powerul been used? | |
beq MBUse ; branch to use money bag if flag = 0 | |
jmp CheckP0M0Col1 ; jump because powerup already used | |
MBUse | |
dec DScore ; powerup activated - decrease DScore | |
lda #1 ; load accumulator with a 1 | |
sta MBUsedFlag ; store the 1 in MBUsedFlag so can't use | |
ldy #sfxPING ; select ping sound effect | |
jsr SFX_TRIGGER ; execute the sound | |
CheckP0M0Col1 ; This checks for a P0 - M0 collision | |
lda #1 ; load the accumulator with a 1 | |
sta P0GfxFlag ; set the P0 graphics flag to | |
; tricorder off | |
lda #%01000000 ; load the D6 bit in accumulator | |
bit CXM0P ; bit compare to what is in col register | |
bne Collision1 ; branch if collision = 1 | |
jmp VerticalBLANK ; skip to Vertical BLANK if no collision | |
; using jmp here because branch too long | |
Collision1 | |
lda MutationFlag ; load accumulator with mutation flag | |
tax ; transfer accumulator to X register | |
cpx #7 ; compare X register to 7 | |
bne Collision2 ; branch if != 7 | |
ldx #5 ; change the 7 to a 5 | |
; need to do something with the 7 since | |
; we only have 6 choices to map below | |
; this creates a slight excess of context | |
; dependent mutations that are helpful | |
; this is ok because I like these best | |
Collision2 | |
lda DownFlag ; load accumulator with down joystick flag | |
tay ; transfer accumulator to Y register | |
cpx #0 ; is there a mutation? no mutation = 0 | |
bne MutationYes ; if yes process type of mutation | |
jmp MutationDone ; if no jump to mutation done and VBLANK | |
MutationYes | |
sta WSYNC ; wait for finish of scanline | |
MutKnownPos ; known helpful mutation? | |
cpx #1 ; is mutation flag = 1? | |
bne MutKnownNeg ; branch if flag != 1 | |
lda #2 ; load the accumulator with 2 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right tricorder visible | |
lda EditFlag ; load edit flag to see if edit already made | |
beq MKPEdit ; branch if edit = 0 | |
jmp MutationDone ; otherwise we are done | |
MKPEdit ; let's edit if joystick is down | |
cpy #1 ; is joystick down? Did a tay earlier | |
bne MutKnownNeg ; skip if not | |
inc PScore ; helpful editing has occured, inc score | |
inc DScore ; money used to edit, inc score | |
ldy #sfxHELP ; select sound effect for helpful edit | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EditFlag ; reset edit flag = 1 to indicate no more | |
; edits this level | |
sta WSYNC ; wait for finish of scanline | |
jmp MutationDone ; all done - move on to VBLANK | |
MutKnownNeg ; known harmful mutation? | |
cpx #2 ; is mutation flag = 2? | |
bne MutUnknownPos ; branch if flag != 2 | |
lda #3 ; load the accumulator with 3 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right tricorder visible | |
lda EditFlag ; load edit flag to see if edit already made | |
beq MKNEdit ; branch if edit = 0 | |
jmp MutationDone ; otherwise we are done | |
MKNEdit ; let's edit if joystick is down | |
cpy #1 ; is joystick down? | |
bne MutUnknownPos ; skip if not | |
dec PScore ; harmful editing has occured, dec score | |
inc DScore ; money used to edit, inc score | |
ldy #sfxHARM ; select sound effect for harmful edit | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EditFlag ; reset edit flag = 1 to indicate no more | |
; edits this level | |
sta WSYNC ; wait for finish of scanline | |
jmp MutationDone ; all done - move on to VBLANK | |
MutUnknownPos ; unknown positive mutation - player must guess | |
; or use research powerup to reveal effect | |
cpx #3 ; is mutation flag = 3? | |
bne MutUnknownNeg ; branch if flag != 3 | |
lda ResearchFlag ; now check if research powerup present | |
beq MUPP04 ; if=0 then powerup not present | |
; and player doesn't know type of mutation | |
lda UpFlag ; is the jostick up? | |
beq MUPP04 ; if=0 then not up and draw tricorder 4 | |
; with symbol for unknown mutation | |
lda #2 ; load the accumulator with 2 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right helpful tricorder visible | |
jmp MUPP02 ; skip the next section | |
MUPP04 ; draw the neutral tricorder since | |
; mutation unknown to player | |
lda #4 ; load the accumulator with 4 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right tricorder visible | |
MUPP02 | |
lda EditFlag ; load edit flag to see if edit already made | |
beq MUPEdit ; branch if edit = 0 | |
jmp MutationDone ; otherwise we are done | |
MUPEdit ; let's edit if joystick is down | |
cpy #1 ; is joystick down? | |
bne MutUnknownNeg ; skip if not | |
inc PScore ; helpful editing has occured, inc score | |
inc DScore ; money used to edit, inc score | |
ldy #sfxHELP ; select sound effect for helpful edit | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EditFlag ; reset edit flag = 1 to indicate no more | |
; edits this level | |
sta WSYNC ; wait for finish of scanline | |
jmp MutationDone ; all done - move on to VBLANK | |
MutUnknownNeg ; unknown positive mutation - player must guess | |
; or use research powerup to reveal effect | |
cpx #4 ; is mutation flag = 4? | |
bne MutContextPos ; branch if flag != 4 | |
lda ResearchFlag ; now check if research powerup present | |
beq MUNP04 ; if=0 then powerup not present | |
; and player doesn't know type of mutation | |
lda UpFlag ; is the jostick up? | |
beq MUNP04 ; if=0 then not up and draw tricorder 4 | |
; with symbol for context-dependent mutation | |
lda #3 ; load the accumulator with 3 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right helpful tricorder visible | |
jmp MUNP03 ; skip the next section | |
MUNP04 ; draw the neutral tricorder since | |
; mutation unknown to player | |
lda #4 ; load the accumulator with 4 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right tricorder visible | |
MUNP03 | |
lda EditFlag ; load edit flag to see if edit already made | |
beq MUNEdit ; branch if edit = 0 | |
jmp MutationDone ; otherwise we are done | |
MUNEdit ; let's edit if joystick is down | |
cpy #1 ; is joystick down? | |
bne MutContextPos ; skip if not | |
dec PScore ; harmful editing has occured, dec score | |
inc DScore ; money used to edit, inc score | |
ldy #sfxHARM ; select sound effect for harmful edit | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EditFlag ; reset edit flag = 1 to indicate no more | |
; edits this level | |
sta WSYNC ; wait for finish of scanline | |
jmp MutationDone ; all done - move on to VBLANK | |
MutContextPos ; context-dependent positive mutation | |
; player must guess or use EHR powerup | |
cpx #5 ; is mutation flag = 5? | |
bne MutContextNeg ; branch if flag != 5 | |
lda EHRFlag ; now check if EHR powerup present | |
beq MCPP05 ; if=0 then powerup not present | |
; and player doesn't know type of mutation | |
lda UpFlag ; is the jostick up? | |
beq MCPP05 ; if=0 then not up and draw tricorder 5 | |
; with symbol for context-depentent mutation | |
lda #2 ; load the accumulator with 2 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right helpful tricorder visible | |
jmp MCPP02 ; skip the next section | |
MCPP05 ; draw the neutral tricorder since | |
; mutation unknown to player | |
lda #5 ; load the accumulator with 5 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right tricorder visible | |
MCPP02 | |
lda EditFlag ; load edit flag to see if edit already made | |
beq MCPEdit ; branch if edit = 0 | |
jmp MutationDone ; otherwise we are done | |
MCPEdit ; let's edit if joystick is down | |
cpy #1 ; is joystick down? | |
bne MutContextNeg ; skip if not | |
inc PScore ; helpful editing has occured, inc score | |
inc DScore ; money used to edit, inc score | |
ldy #sfxHELP ; select sound effect for helpful edit | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EditFlag ; reset edit flag = 1 to indicate no more | |
; edits this level | |
sta WSYNC ; wait for finish of scanline | |
jmp MutationDone ; all done - move on to VBLANK | |
MutContextNeg ; context-dependent negative mutation | |
; player must guess or use EHR powerup | |
cpx #6 ; is mutation flag = 6? | |
bne MutationDone ; branch to done if flag != 6 | |
; this allow nothing to happen when flag = 7 | |
lda EHRFlag ; now check if EHR powerup present | |
beq MCNP05 ; if=0 then powerup not present | |
; and player doesn't know type of mutation | |
lda UpFlag ; is the jostick up? | |
beq MCNP05 ; if=0 then not up and draw tricorder 5 | |
; with symbol for context-depentent mutation | |
lda #3 ; load the accumulator with 3 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right helpful tricorder visible | |
jmp MCNP03 ; skip the next section | |
MCNP05 ; draw the neutral tricorder since | |
; mutation unknown to player | |
lda #5 ; load the accumulator with 5 | |
sta P0GfxFlag ; set the P0 graphics flag | |
; to have right tricorder visible | |
MCNP03 | |
lda EditFlag ; load edit flag to see if edit already made | |
beq MCNEdit ; branch if edit = 0 | |
jmp MutationDone ; otherwise we are done | |
MCNEdit ; let's edit if joystick is down | |
cpy #1 ; is joystick down? | |
bne MutationDone ; skip if not | |
dec PScore ; harmful editing has occured, dec score | |
inc DScore ; money used to edit, inc score | |
ldy #sfxHARM ; select sound effect for harmful edit | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EditFlag ; reset edit flag = 1 to indicate no more | |
; edits this level | |
sta WSYNC ; wait for finish of scanline | |
MutationDone ; all done checking mutations | |
sta CXCLR ; clear the collision registers | |
sta WSYNC ; wait for finish of scanline | |
VerticalBLANK ; The finish vertical blank loop | |
; This burns the scanlines left over | |
lda INTIM ; load timer value into accumulator | |
bne VerticalBLANK ; loop if timer not zero | |
sta WSYNC ; wait for scanline to finish | |
sta HMOVE ; finalize the horizontal move of P0 | |
; this triggers execution of motion | |
; degree of move controlled by HMP0/1 | |
; must be done at this point in code | |
sta WSYNC ; wait for scanline to finish | |
sta VBLANK ; store 0 in VBLANK memory to end | |
; and start drawing the picture by | |
; turning the TV beam on | |
; **************************************************************** | |
; The third part of a 2600 program is the screen drawing | |
; routine that is often called the kernel. This is where | |
; the players, missiles, and playfield are drawn. There | |
; are 192 scanlines to be drawn with 228 color clocks per line. | |
; There are 192 * 228 = 43,776 color clocks. There are 3 | |
; machine cycles per color clock. This give 14,592 machine | |
; cycles. Dividing this by 64 gives 228 timer ticks. So, we store | |
; 228 in TIM64T to start the timer that is used to draw screen. | |
; We are using the Y register to keep track of 192 scanlines. | |
; We will draw the screen in chunks starting with the scores. | |
; **************************************************************** | |
ldy #192 ; load the Y register with 192 | |
; this is the first scanline at top | |
; of the screen | |
lda #228 ; 228 timer ticks | |
sta TIM64T ; start the timer | |
lda #$00 ; load accumulator with PF color | |
sta COLUPF ; set the PF color to black | |
lda #%11111111 ; draw solid pattern for initial PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
DrawScreenTop ; Draw very top part of screen in black | |
dey ; decrement Y to burn a scanline | |
sta WSYNC ; wait for scanline to finish | |
cpy #188 ; Have 4 score scanlines passed? | |
bne DrawScreenTop ; loop until Y = 188 then set up the | |
; score part of PF | |
ldx PScore ; Load X with current patient score | |
lda PScoreColor,x ; use the score to get the PF color | |
sta COLUPF ; score-based color of PF for patient | |
dey ; burn scanline 187 to create border | |
sta WSYNC ; wait for scanline to finish | |
ldx (#SCHEIGHT-1) ; set up the score line counter | |
DrawPScore ; Draw score for patient health | |
lda PatientGfx,x ; Load patient graphics for this line | |
sta PF1 ; Draw the "P" for patient | |
SLEEP 21 ; kill time so this is only part of PF | |
; drawn | |
lda BlankGfx1,x ; Blank graphics to erase 2nd PF1 | |
sta PF1 ; Draw the blank PF1 graphics | |
dex ; decrement our line counter | |
dey ; decrement the Y register | |
cpy #173 ; Have 14 score scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawPScore ; loop until Y = 173 then set up the | |
; dollar score part of PF | |
dey ; burn scanline 172 to create border | |
sta WSYNC ; wait for scanline to finish | |
lda #$00 ; load accumulator with PF color | |
sta COLUPF ; set the PF color to black | |
DrawDivider1 ; Draw 4 scanline black divider between | |
; the patient and dollar scores | |
dey ; decrement the Y register | |
sta WSYNC ; wait for scanline to finish | |
cpy #168 ; Have 4 score scanlines passed? | |
bne DrawDivider1 ; loop until Y = 168 then draw the | |
; dollar score part of PF | |
ldx DScore ; Load X with current Left Score | |
lda DScoreColor,x ; use the score to get the PF color | |
sta COLUPF ; score-based color of PF for patient | |
sleep 16 ; kill some cycles here to keep the PF | |
; in sync | |
ldx (#SCHEIGHT-1) ; set up the score line counter | |
dey ; burn scanline 167 to create border | |
sta WSYNC ; wait for scanline to finish | |
DrawDScore ; Draw score for dollars | |
lda DollarGfx,x ; Load dollar graphics for this line | |
sta PF1 ; Draw the "D" for dollar | |
SLEEP 20 ; kill time so this is only part of PF | |
; drawn | |
lda BlankGfx1,x ; Blank graphics to erase 2nd PF1 | |
sta PF1 ; Draw the blank PF1 graphics | |
dex ; decrement our line counter | |
dey ; decrement the Y register | |
cpy #153 ; Have 14 score scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawDScore ; loop until Y = 153 then set up the | |
; dollar score part of PF | |
dey ; burn scanline 152 to create border | |
sta WSYNC ; wait for scanline to finish | |
lda #$00 ; load accumulator with PF color | |
sta COLUPF ; set the PF color to black | |
DrawDivider2 ; Draw 4 scanline black divider between | |
; scores and the rest of the playfield | |
dey ; decrement the Y register | |
sta WSYNC ; wait for scanline to finish | |
cpy #148 ; Have 4 score scanlines passed? | |
bne DrawDivider2 ; loop until Y = 148 then draw the | |
; dollar score part of PF | |
lda #$F0 ; load accumulator with powerup bar color | |
sta COLUPF ; set the PF color | |
dey ; burn scanline 147 | |
sta WSYNC ; wait for scanline to finish | |
DrawPowerBar ; draw the next section that displays | |
; research, money bag, and EHR powerups | |
CheckResearch ; check the research powerup flag | |
ldx ResearchFlag ; load the accumulator with res flag | |
cpx #0 ; compare X to 0 | |
beq CheckEHRFlag ; skip drawing this powerup if X=0 | |
ldx (#PUHEIGHT-1) ; get line count to draw player 1 | |
DrawResearch | |
lda #$0E ; set the research powerup color to white | |
sta COLUP1 ; write the color to the P1 color register | |
lda Research,x ; load player 1 (object) graphic | |
sta GRP1 ; set the graphic for this line | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #131 ; allow 16 scanlines to draw powerups | |
bne DrawResearch ; loop back to continue drawing powerup | |
; part of screen | |
jmp PowerDrawDone ; done drawing powerups | |
CheckEHRFlag ; check the EHR powerup flag | |
ldx EHRFlag ; load the accumulator with EHR flag | |
cpx #0 ; compare X to 0 | |
beq CheckMoneyFlag ; skip drawing this powerup if X=0 | |
ldx (#PUHEIGHT-1) ; get line count to draw player 1 | |
DrawEHR | |
lda #$FC ; set the EHR powerup color to orange | |
sta COLUP1 ; write the color to the P1 color register | |
lda EHR,x ; load player 1 (object) graphic | |
sta GRP1 ; set the graphic for this line | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #131 ; allow 16 scanlines to draw powerups | |
bne DrawEHR ; loop back to continue drawing powerup | |
; part of screen | |
jmp PowerDrawDone ; done drawing powerups | |
CheckMoneyFlag ; check the money bag powerup flag | |
ldx MoneyFlag ; load accumulator with money bag flag | |
cpx #0 ; compare X to 0 | |
beq PowerDrawDone ; skip drawing this powerup if X=0 | |
ldx (#PUHEIGHT-1) ; get line count to draw player 1 | |
DrawMoney | |
lda #$CA ; set the money powerup color to green | |
sta COLUP1 ; write the color to the P1 color register | |
lda MoneyBag,x ; load player 1 (object) graphic | |
sta GRP1 ; set the graphic for this line | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #131 ; allow 16 scanlines to draw powerups | |
bne DrawMoney ; loop back to continue drawing powerup | |
; part of screen | |
PowerDrawDone | |
lda #0 ; load accumulator with a 0 | |
sta GRP1 ; zero out player 1 graphics | |
DrawDivider3 ; Draw 3 scanline divider between | |
; scores and the rest of the playfield | |
dey ; burn a scanline | |
sta WSYNC ; wait for scanline to finish | |
cpy #128 ; Have 3 score scanlines passed? | |
bne DrawDivider3 ; loop until Y = 128 then draw the | |
; cell membrane part of PF | |
lda #$02 ; load accumulator with cell mem color | |
sta COLUPF ; set the PF color | |
DrawCellMem ; Draw cell membrane loop | |
; PF registers already set from above | |
dey ; decrement the Y register | |
cpy #120 ; Have 8 scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawCellMem ; loop until Y = 120 then set up the | |
; pattern for the cytoplasm part of PF | |
lda #$80 ; load accumulator with cyto color | |
sta COLUPF ; set the PF color | |
DrawCytTop ; draw the next section that represents | |
; the cytoplasm part of the cell PF | |
; draw top part first | |
dey ; decrement the Y register | |
cpy #110 ; Have 10 scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawCytTop ; this is the first part of cyoplasm PF | |
ldx (#CYTHEIGHT-1) ; set up the cytoplasm line counter | |
dey ; decrement the Y register | |
sta WSYNC ; burn scanline 109 to save a few cycles | |
; so we can draw asymmetrical PF next | |
lda #$48 ; load accumulator with cyto color | |
sta COLUPF ; set the PF color | |
DrawCytOrgs ; Draw the cytoplasmic organelles next | |
lda ScreenFlag ; flag for which screen to draw | |
beq DrawOrgB ; if flag = 0 branch to organelles B | |
DrawOrgA ; draw organelles option A | |
lda BlankGfx2,x ; Load blank graphics for this line | |
sta PF0 ; Draw the blank line | |
lda MitoGfx,x ; Load mitochondria graphics for this line | |
sta PF1 ; Draw the mitochondria line | |
lda BlankGfx2,x ; Load blank graphics for this line | |
sta PF2 ; Draw the blank line | |
SLEEP 18 ; kill time for asymmetric playfield | |
; so we can draw both mito and ER | |
lda ERGfx,x ; Load ER graphics for this line | |
sta PF1 ; Draw the ER line | |
jmp DrawOrgDone ; skip the next section | |
DrawOrgB ; draw organelles option B | |
lda BlankGfx2,x ; Load blank graphics for this line | |
sta PF0 ; Draw the blank line | |
lda ERGfx,x ; Load mitochondria graphics for this line | |
sta PF1 ; Draw the mitochondria line | |
lda BlankGfx2,x ; Load blank graphics for this line | |
sta PF2 ; Draw the blank line | |
SLEEP 18 ; kill time for asymmetric playfield | |
; so we can draw both mito and ER | |
lda MitoGfx,x ; Load ER graphics for this line | |
sta PF1 ; Draw the ER line | |
DrawOrgDone ; done drawing the organelles | |
dex ; decrement our line counter | |
dey ; decrement the Y register | |
sta WSYNC ; wait for scanline to finish | |
cpy #95 ; Have 14 score scanlines passed? | |
bne DrawCytOrgs ; loop until Y = 96 then set up the | |
; dollar score part of PF | |
lda #$80 ; load accumulator with cyto color | |
sta COLUPF ; set the PF color | |
lda #%11111111 ; draw solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
DrawCytBot | |
dey ; decrement the Y register | |
cpy #85 ; Have 10 scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawCytBot ; this is the bottom part of cyoplasm PF | |
lda #$02 ; load accum with nucleur membrane color | |
sta COLUPF ; set the PF color | |
DrawNucMem ; draw the next section that represents | |
; the nuclear membrane part of the cell PF | |
dey ; decrement the Y register | |
cpy #81 ; Have 4 scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawNucMem ; loop until Y = 81 then set up the | |
; pattern for the nucleus part of PF | |
lda #$70 ; load accumulator with nucleus color | |
sta COLUPF ; set the PF color | |
ldx P0GfxFlag ; load accumulator with value for flag | |
StartScreenSwitch ; check the game launch flag to see if | |
; the start screen should be drawn | |
lda GameLaunchFlag ; load accumulator with game launch flag | |
beq WinSwitch ; if flag = 0 then don't draw new screen | |
ldx (#GHEIGHT-1) ; load X register with gene line count | |
jmp DrawNuc8 ; if flag = 1 then draw start screen | |
WinSwitch ; if win flag set draw final PF | |
lda WinFlag ; load accumulator with flag value | |
beq LoseSwitch ; if flag = 0 branch to next | |
ldx (#HHEIGHT-1) ; load X register with line count | |
jmp DrawNuc6 ; if flag = 1 then draw win screen | |
LoseSwitch ; if lose flag set draw final PF | |
lda LoseFlag ; load accumulator with flag value | |
beq P0GfxSwitch1 ; if flag = 0 branch to next | |
ldx (#HHEIGHT-1) ; load X register with line count | |
jmp DrawNuc7 ; if flag = 1 then draw win screen | |
P0GfxSwitch1 ; this set of switches determine what | |
; graphics to use for player 0 | |
cpx #1 ; compare X register to 1 | |
bne P0GfxSwitch2 ; if not = 1 then branch to next | |
ldx (#P0HEIGHT-1) ; load X register with P0 line count | |
dey ; burn scanline 80 to save some cycles | |
sta WSYNC ; for drawing first line of player 0 | |
jmp DrawNuc1 ; go draw nucleus 1 with P0Graphic1 | |
P0GfxSwitch2 | |
cpx #2 ; compare X register to 2 | |
bne P0GfxSwitch3 ; if not = 2 then branch to next | |
ldx (#P0HEIGHT-1) ; load X register with P0 line count | |
dey ; burn scanline 80 to save some cycles | |
sta WSYNC ; for drawing first line of player 0 | |
jmp DrawNuc2 ; go draw nucleus 2 with P0Graphic2 | |
P0GfxSwitch3 | |
cpx #3 ; compare X register to 3 | |
bne P0GfxSwitch4 ; if not = 3 then branch to next | |
ldx (#P0HEIGHT-1) ; load X register with P0 line count | |
dey ; burn scanline 80 to save some cycles | |
sta WSYNC ; for drawing first line of player 0 | |
jmp DrawNuc3 ; go draw nucleus 3 with P0Graphic3 | |
P0GfxSwitch4 | |
cpx #4 ; compare X register to 4 | |
bne P0GfxSwitch5 ; if not = 4 then branch to next | |
ldx (#P0HEIGHT-1) ; load X register with P0 line count | |
dey ; burn scanline 80 to save some cycles | |
sta WSYNC ; for drawing first line of player 0 | |
jmp DrawNuc4 ; go draw nucleus 4 with P0Graphic4 | |
P0GfxSwitch5 | |
cpx #5 ; compare X register to 5 | |
bne SwitchDone ; if not = 5 then branch to next | |
ldx (#P0HEIGHT-1) ; load X register with P0 line count | |
dey ; burn scanline 80 to save some cycles | |
sta WSYNC ; for drawing first line of player 0 | |
jmp DrawNuc5 ; go draw nucleus 5 with P0Graphic5 | |
SwitchDone | |
dey ; burn scanline 80 to save some cycles | |
sta WSYNC ; for drawing first line of player 0 | |
DrawNuc1 ; Draw the nucleus screen loop with P0 | |
; graphics 1 (no tricorder) | |
lda P0Graphic1,x ; load player 0 graphic 1 | |
sta GRP0 | |
lda P0Color,x ; grab the color of P0 for this line | |
sta COLUP0 ; set color for P0 each scanline | |
lda #0 ; load accumulator with 0 | |
sta ENAM0 ; make sure missile 0 is off until later | |
MissileOn1 ; this bit turns on missile 0 at the | |
; right scanline. Used to check for | |
; collision with P0 for turning on | |
; tricorder for editing the DNA | |
cpy #47 ; check for scanline 47 | |
bne SkipMissile1 ; skip if not right scanline | |
lda #2 ; load accumulator with 2 | |
sta ENAM0 ; use the 2 to turn on missile 0 | |
SkipMissile1 ; skip turning on the missile | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #25 ; time to draw the DNA PF? | |
bne DrawNuc1 ; loop back to continue drawing nucleus | |
; part of screen with PF and player | |
jmp DrawDNAPrep ; done drawing P0 - let's draw the DNA | |
; part of the playfield | |
DrawNuc2 ; Draw the nucleus screen loop with P0 | |
; graphics 1 (no tricorder) | |
lda P0Graphic2,x ; load player 0 graphic 2 | |
sta GRP0 | |
lda P0Color,x ; grab the color of P0 for this line | |
sta COLUP0 ; set color for P0 each scanline | |
lda #0 ; load accumulator with 0 | |
sta ENAM0 ; make sure missile 0 is off until later | |
MissileOn2 ; this bit turns on missile 0 at the | |
; right scanline. Used to check for | |
; collision with P0 for turning on | |
; tricorder for editing the DNA | |
cpy #47 ; check for scanline 47 | |
bne SkipMissile2 ; skip if not right scanline | |
lda #2 ; load accumulator with 2 | |
sta ENAM0 ; use the 2 to turn on missile 0 | |
SkipMissile2 | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #25 ; time to draw the DNA PF? | |
bne DrawNuc2 ; loop back to continue drawing nucleus | |
; part of screen with PF and player | |
jmp DrawDNAPrep ; done drawing P0 - let's draw the DNA | |
; part of the playfield | |
DrawNuc3 ; Draw the nucleus screen loop with P0 | |
; graphics 3 (tricorder harm !) | |
lda P0Graphic3,x ; load player 0 graphic 3 | |
sta GRP0 | |
lda P0Color,x ; grab the color of P0 for this line | |
sta COLUP0 ; set color for P0 each scanline | |
lda #0 ; load accumulator with 0 | |
sta ENAM0 ; make sure missile 0 is off until later | |
MissileOn3 ; this bit turns on missile 0 at the | |
; right scanline. Used to check for | |
; collision with P0 for turning on | |
; tricorder for editing the DNA | |
cpy #47 ; check for scanline 47 | |
bne SkipMissile3 ; skip if not right scanline | |
lda #2 ; load accumulator with 2 | |
sta ENAM0 ; use the 2 to turn on missile 0 | |
SkipMissile3 | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #25 ; time to draw the DNA PF? | |
bne DrawNuc3 ; loop back to continue drawing nucleus | |
; part of screen with PF and player | |
jmp DrawDNAPrep ; done drawing P0 - let's draw the DNA | |
; part of the playfield | |
DrawNuc4 ; Draw the nucleus screen loop with P0 | |
; graphics 4 (unknown tricorder) | |
lda P0Graphic4,x ; load player 0 graphic 4 | |
sta GRP0 | |
lda P0Color,x ; grab the color of P0 for this line | |
sta COLUP0 ; set color for P0 each scanline | |
lda #0 ; load accumulator with 0 | |
sta ENAM0 ; make sure missile 0 is off until later | |
MissileOn4 ; this bit turns on missile 0 at the | |
; right scanline. Used to check for | |
; collision with P0 for turning on | |
; tricorder for editing the DNA | |
cpy #47 ; check for scanline 47 | |
bne SkipMissile4 ; skip if not right scanline | |
lda #2 ; load accumulator with 2 | |
sta ENAM0 ; use the 2 to turn on missile 0 | |
SkipMissile4 | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #25 ; time to draw the DNA PF? | |
bne DrawNuc4 ; loop back to continue drawing nucleus | |
; part of screen with PF and player | |
jmp DrawDNAPrep ; done drawing P0 - let's draw the DNA | |
; part of the playfield | |
DrawNuc5 ; Draw the nucleus screen loop with P0 | |
; graphics 5 (context-dependent tricorder) | |
lda P0Graphic5,x ; load player 0 graphic 5 | |
sta GRP0 | |
lda P0Color,x ; grab the color of P0 for this line | |
sta COLUP0 ; set color for P0 each scanline | |
lda #0 ; load accumulator with 0 | |
sta ENAM0 ; make sure missile 0 is off until later | |
MissileOn5 ; this bit turns on missile 0 at the | |
; right scanline. Used to check for | |
; collision with P0 for turning on | |
; tricorder for editing the DNA | |
cpy #47 ; check for scanline 47 | |
bne SkipMissile5 ; skip if not right scanline | |
lda #2 ; load accumulator with 2 | |
sta ENAM0 ; use the 2 to turn on missile 0 | |
SkipMissile5 | |
dex ; decrease the line counter | |
dey ; decrease the scanline count | |
sta WSYNC ; wait for scanline to finish | |
cpy #25 ; time to draw the DNA PF? | |
bne DrawNuc5 ; loop back to continue drawing nucleus | |
; part of screen with PF and player | |
jmp DrawDNAPrep ; done drawing P0 - let's draw the DNA | |
; part of the playfield | |
DrawNuc6 ; this draws the final screen with | |
; a colored heart for healed patient (red) | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
dey ; decrement the Y register | |
cpy #71 ; Have 10 DNA scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawNuc6 ; loop until Y = 71 then set up the | |
; pattern for heart PF | |
DrawHeartWin | |
lda #$30 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for rest of PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
lda HeartGfx,x ; load the heart graphics for this line | |
sta PF2 ; set the PF2 register | |
dex ; decrement our line counter | |
dey ; decrement the Y register | |
cpy #35 ; Have 24 DNA scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawHeartWin ; loop until Y = 47 then set up the | |
; pattern for last part of nucleaus PF | |
FinHeartWin | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
dey ; decrement the Y register | |
cpy #23 ; On scanline 23? | |
sta WSYNC ; wait for scanline to finish | |
bne FinHeartWin ; loop until Y = 23 then set up the | |
; DNA PF | |
jmp DrawDNAPrep ; done drawing P0 - let's draw the DNA | |
; part of the playfield | |
DrawNuc7 ; this draws the final screen with | |
; a colored heart for dead patient (grey) | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
dey ; decrement the Y register | |
cpy #71 ; Have 10 DNA scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawNuc7 ; loop until Y = 71 then set up the | |
; pattern for heart PF | |
DrawHeartLose | |
lda #$06 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for rest of PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
lda HeartGfx,x ; load the heart graphics for this line | |
sta PF2 ; set the PF2 register | |
dex ; decrement our line counter | |
dey ; decrement the Y register | |
cpy #35 ; Have 24 DNA scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawHeartLose ; loop until Y = 47 then set up the | |
; pattern for last part of nucleaus PF | |
FinHeartLose | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
dey ; decrement the Y register | |
cpy #23 ; On scanline 23? | |
sta WSYNC ; wait for scanline to finish | |
bne FinHeartLose ; loop until Y = 23 then set up the | |
; DNA PF | |
jmp DrawDNAPrep ; get ready draw DNA helix | |
DrawNuc8 ; this draws the start screen with | |
; the name of the game on boot up | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
dey ; decrement the Y register | |
cpy #70 ; Have 10 DNA scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawNuc8 ; loop until Y = 70 then set up the | |
; pattern for heart PF | |
;lda #$0E ; load the accumulator with color number | |
;sta COLUPF ; store in the playfield color memory | |
DrawGeneName ; draw "Gene" on playfield | |
lda GeneColor,x ; load the colors for the name | |
sta COLUPF ; write the colors to the register | |
lda Gene1Gfx,x ; load gene name graphics for this line | |
sta PF1 ; set the PF1 register | |
lda Gene2Gfx,x ; load gene name graphics for this line | |
sta PF2 ; set the PF2 register | |
sleep 10 ; burn cycles for asymmetrical playfield | |
lda BlankGfx2,x ; load gene name graphics for this line | |
sta PF1 ; set the PF1 register | |
lda BlankGfx2,x ; load gene name graphics for this line | |
sta PF2 ; set the PF2 register | |
dex ; decrement our line counter | |
dey ; decrement the Y register | |
cpy #56 ; Have 14 DNA scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawGeneName ; loop until Y = 56 then set up the | |
; pattern for last part of nucleaus PF | |
DrawNameGap ; this draws some blank PF lines between | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
dey ; decrement the Y register | |
cpy #52 ; On scanline 52? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawNameGap ; loop until Y = 52 then draw the | |
; jockey name part of playfield | |
ldx (#JHEIGHT-1) ; load X register with jockey line count | |
DrawMedicName ; draw "Medic" on playfield | |
lda MedicColor,x ; load the colors for the name | |
sta COLUPF ; write the colors to the register | |
lda Medic1Gfx,x ; load medic name graphics for this line | |
sta PF1 ; set the PF1 register | |
lda Medic2Gfx,x ; load medic name graphics for this line | |
sta PF2 ; set the PF2 register | |
sleep 11 ; burn cycles for asymmetrical playfield | |
lda BlankGfx2,x ; load gene name graphics for this line | |
sta PF1 ; set the PF1 register | |
lda BlankGfx2,x ; load gene name graphics for this line | |
sta PF2 ; set the PF2 register | |
dex | |
dey ; decrement the Y register | |
cpy #38 ; On scanline 38? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawMedicName ; loop until Y = 38 then draw remaining | |
; blank lines of nucleus | |
FinDrawNames ; finish drawing the start screen nucleus | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
lda #%00000000 ; solid pattern for PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
dey ; decrement the Y register | |
cpy #23 ; On scanline 23? | |
sta WSYNC ; wait for scanline to finish | |
bne FinDrawNames ; loop until Y = 23 then draw the | |
; DNA helix part of playfield | |
DrawDNAPrep ; Time to get ready to draw the DNA helix | |
ldx (#DNAHEIGHT-1) ; set up the DNA line counter | |
dey ; decrement the scanline count | |
sta WSYNC ; burn scanline 24 to save a few cycles | |
; for drawing the helices | |
lda #$1E ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
DrawDNA | |
lda ScreenFlag ; flag for which screen to draw | |
beq DrawHelixB ; if flag = 0 branch to draw helix B | |
DrawHelixA ; draw helix option A | |
lda HelixA0,x ; Load helix graphics for this line | |
sta PF0 ; Draw helix A | |
lda HelixA1,x ; Load helix graphics for this line | |
sta PF1 ; Draw helix A | |
lda HelixA2,x ; Load helix graphics for this line | |
sta PF2 ; Draw helix A | |
jmp HelixDone ; done loading helix graphics | |
DrawHelixB ; draw helix option B | |
lda HelixB0,x ; Load helix graphics for this line | |
sta PF0 ; Draw helix B | |
lda HelixB1,x ; Load helix graphics for this line | |
sta PF1 ; Draw helix B | |
lda HelixB2,x ; Load helix graphics for this line | |
sta PF2 ; Draw helix B | |
HelixDone ; done loading helix graphics | |
dex ; decrement our line counter | |
dey ; decrement the Y register | |
cpy #13 ; Have 11 DNA scanlines passed? | |
sta WSYNC ; wait for scanline to finish | |
bne DrawDNA ; loop until Y = 11 then set up the | |
; pattern for bottom strand of DNA PF | |
lda #%11111111 ; solid pattern for rest of PF | |
sta PF0 ; set the PF0 register | |
sta PF1 ; set the PF1 register | |
sta PF2 ; set the PF2 register | |
lda #$80 ; load the accumulator with color number | |
sta COLUPF ; store in the playfield color memory | |
DrawBot ; draw the very bottom part of screen | |
; until timer runs out | |
sta WSYNC ; wait for the scanline to finish | |
lda INTIM ; check timer count | |
bne DrawBot ; loop if timer not 0 | |
lda #2 ; load accumulator with 2 binary 0010 | |
sta VBLANK ; turn off screen for overscan | |
; **************************************************************** | |
; The final part of a 2600 program is the overscan that waits a | |
; final 30 scanlines to finish one complete frame on TV screen | |
; We will use this time to check for joystick movement. Note | |
; that this game is side to side only. No up or down movement. | |
; SWCHA data bits D7 to D4 = 1 for P0 right, left, down, up | |
; D3 to D0 are used for P1. Also checking for game reset switch | |
; and firebutton for starting a game. Also doing win/lose sound | |
; here. | |
; **************************************************************** | |
lda #35 ; load the X register with 35 ticks | |
sta TIM64T ; initialize the timer | |
GameResetCheck ; has the reset switch been pressed? | |
; if so branch up to Reset to clear | |
; memory and reset the whole game | |
lda SWCHB ; load accumulator with state of reset | |
; switch | |
and #%00000001 ; reset game? and returns a 1 if so | |
bne SoundUpdate ; move on if no reset switch | |
jmp Reset ; if reset switch pushed then reboot game | |
SoundUpdate | |
jsr SFX_UPDATE ; update sound effects | |
MoveLeft | |
lda #%01000000 ; D6 = 1 for P0 stick right | |
bit SWCHA ; bit compare to SWCHA register | |
bne MoveRight ; check move right if no left joystick | |
ldx P0X ; load X register with P0 X position | |
cpx #XMIN ; is P0 at left edge of screen? | |
beq MoveRight ; if so left move check is done | |
dec P0X ; otherwise decrease the P0 X position | |
lda #%00001000 ; a 1 in D3 of REFP0 says mirror | |
sta REFP0 ; reflection of P0 in mirror image | |
MoveRight | |
lda #%10000000 ; D7 = 1 for P0 stick right | |
bit SWCHA ; bit compare to SWCHA register | |
bne StickUp ; moving to StickUp if no right joystick | |
ldx P0X ; load X register with P0 X position | |
cpx #XMAX ; is P0 at right edge of screen? | |
beq AtEdge ; if so move to AtEdge to set flag | |
; and set P0X = XMIN | |
inc P0X ; otherwise increase the P0 X position | |
lda #%00000000 ; a 0 in D3 of REFP0 says no mirror | |
sta REFP0 ; no reflection of P0 | |
jmp StickUp ; bypass the new level flag for stick up | |
AtEdge ; this gets executed if end of PF reached | |
lda #1 ; load accumulator with a 1 | |
sta NewLevelFlag ; set flag = 1 to indicate new level | |
; needs to be drawn. Gets checked in | |
; vertical blank above. | |
lda #XMIN ; load accumulator with X min value | |
sta P0X ; set the P0 horizontal location to XMIN | |
StickUp | |
lda #0 ; load the accumulator with a 0 | |
sta UpFlag ; zero out the stick up flag | |
lda #%00010000 ; D4 = 1 for P0 stick up | |
bit SWCHA ; bit compare to SWCHA register | |
bne StickDown ; moving to StickDown if no up joystick | |
lda #1 ; load the accumulator with a 1 | |
sta UpFlag ; indicate with flag that stick up | |
StickDown | |
lda #0 ; load the accumulator with a 0 | |
sta DownFlag ; zero out the stick down flag | |
lda #%00100000 ; D3 = 1 for P0 stick down | |
bit SWCHA ; bit compare to SWCHA register | |
bne MoveDone ; moving done if no down joystick | |
lda #1 ; load the accumulator with a 1 | |
sta DownFlag ; indicate with flag that stick down | |
MoveDone ; done checking joysticks for movement | |
lda EndSoundFlag ; only play end sounds once if Flag=0 | |
bne StartButton ; skip end game sounds if Flag=1 | |
WinSound ; Game over? Play win sound effects | |
lda WinFlag ; load accumulator with win flag | |
beq LoseSound ; branch if win flag not set | |
ldy #sfxWIN1 ; sound effect 1 for win | |
jsr SFX_TRIGGER ; execute the sound | |
ldy #sfxWIN2 ; sound effect 2 for win | |
jsr SFX_TRIGGER ; execute the sound | |
ldy #sfxWIN3 ; sound effect 3 for win | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EndSoundFlag ; set Flag=1 so sound done | |
jmp StartButton ; skip the lose sound check | |
LoseSound ; Game over? Play loss sound effects | |
lda LoseFlag ; load accumulator with lose flag | |
beq StartButton ; branch if lose flag not set | |
ldy #sfxLOSE1 ; sound effect 1 for loss | |
jsr SFX_TRIGGER ; execute the sound | |
ldy #sfxLOSE2 ; sound effect 2 for loss | |
jsr SFX_TRIGGER ; execute the sound | |
ldy #sfxLOSE3 ; sound effect 3 for loss | |
jsr SFX_TRIGGER ; execute the sound | |
lda #1 ; load accumulator with a 1 | |
sta EndSoundFlag ; set Flag=1 so sound done | |
StartButton ; check if button pressed on startup screen | |
lda GameLaunchFlag ; load the game launch flag | |
beq OverScan ; branch to OverScan when flag = 0 | |
lda INPT4 ; load accumulator with button value | |
bmi OverScan ; If INPT4 D7 = 1 then continue | |
jmp StartHere ; If INPT4 D7 = 0 then button pressed | |
; jumpt to Start Here to start new game | |
OverScan ; The overscan loop | |
lda INTIM ; Load the timer into the accumulator | |
bne OverScan ; Loop if timer not yet zero | |
jsr GetRandomPU ; ping the random number generators once | |
jsr GetRandomMut ; per frame to make the sequence less | |
; predictable when needed by the player | |
; crossing a mutation or new screen. | |
sta WSYNC ; wait for scanline to finish | |
jmp VerticalSYNC ; start the entire process over! | |
; **************************************************************** | |
; This is the 8-bit random number generator subroutine that uses | |
; the Galois linear feedback shift register (LFSR) approach. | |
; This generates and returns a number between 0-255. | |
; Have two of these to avoid dependencies between powerups and | |
; mutations. | |
; **************************************************************** | |
GetRandomPU ; this is for powerups | |
lda RandomPU ; load the accumulator with a seed | |
lsr ; logical shift right | |
bcc SkipEor1 ; branch on carry clear | |
eor #$D4 ; exclusive OR (i.e. XOR) function | |
SkipEor1 | |
sta RandomPU ; store the random number in variable | |
rts ; return from subroutine | |
GetRandomMut ; this is for mutation flag | |
lda RandomMut ; load the accumulator with a seed | |
lsr ; logical shift right | |
bcc SkipEor2 ; branch on carry clear | |
eor #$A9 ; exclusive OR (i.e. XOR) function | |
; $A9 generates inverse sequence | |
SkipEor2 | |
sta RandomMut ; store the random number in variable | |
rts ; return from subroutine | |
; **************************************************************** | |
; The graphics for player 0 | |
; **************************************************************** | |
P0Graphic1 ; 55 scanlines total | |
; extra scanlines help position P0 without | |
; keeping track of scanlines. This buys some cycles | |
; during the player drawing routine. | |
; This is P0 without the tricorder | |
.byte %00000000 ; | | | |
.byte %10000000 ; |X | | |
.byte %10000000 ; |X | | |
.byte %11000011 ; |XX XX| | |
.byte %01100010 ; | XX X | | |
.byte %01100010 ; | XX X | | |
.byte %00110110 ; | XX XX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00011100 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00111100 ; | XXXX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00111010 ; | XXX X | | |
.byte %00111000 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00010000 ; | X | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %11111111 ; | | <- invisible blue line for missile here | |
.byte %00000000 ; | | for collision detection | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | 42nd scanline here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | 55th scanline | |
P0Graphic2 ; 55 scanlines total | |
; This is P0 with a tricorder | |
; tricorder has health screen | |
.byte %00000000 ; | | | |
.byte %10000000 ; |X | | |
.byte %10000000 ; |X | | |
.byte %11000011 ; |XX XX| | |
.byte %01100010 ; | XX X | | |
.byte %01100010 ; | XX X | | |
.byte %00110110 ; | XX XX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00011100 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00111100 ; | XXXX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00111010 ; | XXX X | | |
.byte %00111000 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00010000 ; | X | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %11111111 ; | | <- invisible blue line here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %01111110 ; | XXXXXX | tricorder | |
.byte %11111111 ; |XXXXXXXX| health screen | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10000001 ; |X X| | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %11000011 ; |XX XX| | |
.byte %01111110 ; | XXXXXX | 42nd scanline here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
P0Graphic3 ; 55 scanlines total | |
; This is P0 with a tricorder | |
; tricorder has hurt screen | |
.byte %00000000 ; | | Doctor | |
.byte %10000000 ; |X | | |
.byte %10000000 ; |X | | |
.byte %11000011 ; |XX XX| | |
.byte %01100010 ; | XX X | | |
.byte %01100010 ; | XX X | | |
.byte %00110110 ; | XX XX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00011100 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00111100 ; | XXXX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00111010 ; | XXX X | | |
.byte %00111000 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00010000 ; | X | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %11111111 ; | | <- invisible blue line here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | 25th scanline here | |
.byte %00000000 ; | | | |
.byte %01111110 ; | XXXXXX | tricorder | |
.byte %11111111 ; |XXXXXXXX| hurt screen | |
.byte %10000001 ; |X X| exclamation point | |
.byte %10011001 ; |X XX X| | |
.byte %10000001 ; |X X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10011001 ; |X XX X| | |
.byte %10000001 ; |X X| | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %11000011 ; |XX XX| | |
.byte %01111110 ; | XXXXXX | 42nd scanline here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
P0Graphic4 ; 55 scanlines total | |
; This is P0 with a tricorder | |
; tricorder has neutral screen | |
.byte %00000000 ; | | | |
.byte %10000000 ; |X | | |
.byte %10000000 ; |X | | |
.byte %11000011 ; |XX XX| | |
.byte %01100010 ; | XX X | | |
.byte %01100010 ; | XX X | | |
.byte %00110110 ; | XX XX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00011100 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00111100 ; | XXXX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00111010 ; | XXX X | | |
.byte %00111000 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00010000 ; | X | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %11111111 ; | | <- invisible blue line here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %01111110 ; | XXXXXX | tricorder | |
.byte %11111111 ; |XXXXXXXX| neutral screen | |
.byte %10000001 ; |X X| hurt or heal? | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %11000011 ; |XX XX| | |
.byte %01111110 ; | XXXXXX | 42nd scanline here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
P0Graphic5 ; 55 scanlines total | |
; This is P0 with a tricorder | |
; tricorder has context-dependent screen | |
.byte %00000000 ; | | | |
.byte %10000000 ; |X | | |
.byte %10000000 ; |X | | |
.byte %11000011 ; |XX XX| | |
.byte %01100010 ; | XX X | | |
.byte %01100010 ; | XX X | | |
.byte %00110110 ; | XX XX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00011100 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00111100 ; | XXXX | | |
.byte %00111110 ; | XXXXX | | |
.byte %00111010 ; | XXX X | | |
.byte %00111000 ; | XXX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00010000 ; | X | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %00011000 ; | XX | | |
.byte %11111111 ; | | <- invisible blue line here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %01111110 ; | XXXXXX | tricorder | |
.byte %11111111 ; |XXXXXXXX| context-dependent screen | |
.byte %10000001 ; |X X| hurt or heal? | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10100101 ; |X X X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10100101 ; |X X X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %10000001 ; |X X| | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %11000011 ; |XX XX| | |
.byte %01111110 ; | XXXXXX | 42nd scanline here | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
P0Color ; one color for each of the 55 P0 scanlines | |
.byte $00 | |
.byte $02 | |
.byte $04 | |
.byte $04 | |
.byte $04 | |
.byte $04 | |
.byte $04 | |
.byte $04 | |
.byte $02 | |
.byte $08 | |
.byte $08 | |
.byte $0A | |
.byte $0A | |
.byte $0C | |
.byte $0C | |
.byte $0E | |
.byte $0E | |
.byte $02 | |
.byte $04 | |
.byte $04 | |
.byte $02 | |
.byte $80 ; <- this color matches background | |
.byte $00 ; that is used as a marker of the | |
.byte $00 ; nucleotide to edit - this makes | |
.byte $00 ; missile 0 invisible but open to | |
.byte $00 ; collision detection | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A ; 42nd scanline | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
.byte $0A | |
; **************************************************************** | |
; The 8 colors for the patient and dollar score playfields | |
; **************************************************************** | |
PScoreColor | |
.byte $06 | |
.byte $F0 | |
.byte $F2 | |
.byte $F4 | |
.byte $F6 | |
.byte $F8 | |
.byte $FA | |
.byte $FC | |
.byte $FE | |
.byte $30 | |
DScoreColor | |
.byte $00 | |
.byte $F0 | |
.byte $F2 | |
.byte $F4 | |
.byte $F6 | |
.byte $F8 | |
.byte $FA | |
.byte $FC | |
.byte $FE | |
.byte $06 | |
; **************************************************************** | |
; The graphics for the score "P" and "$" - 14 scanlines each | |
; **************************************************************** | |
PatientGfx | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%00111100 ; |XX XX| | |
.byte #%00111100 ; |XX XX| | |
.byte #%00111100 ; |XX XX| | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%00000000 ; |XXXXXXXX| | |
DollarGfx | |
.byte #%11101111 ; | X | | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%11111100 ; | XX| | |
.byte #%11111100 ; | XX| | |
.byte #%11111100 ; | XX| | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00111111 ; |XX | | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%00000000 ; |XXXXXXXX| | |
.byte #%11101111 ; | X | | |
; **************************************************************** | |
; Blank graphics for use in the playfield - 14 scanlines | |
; **************************************************************** | |
BlankGfx1 | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
.byte #%11111111 ; | | | |
BlankGfx2 | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
.byte #%00000000 ; | | | |
; **************************************************************** | |
; The graphics for the "gene medic" name part of start screen | |
; **************************************************************** | |
Gene1Gfx ; graphic for "GE" part of "GENE" | |
.byte #%11101110 ; |XXX XXX | | |
.byte #%11101110 ; |XXX XXX | | |
.byte #%10101000 ; |X X X | | |
.byte #%10101000 ; |X X X | | |
.byte #%10101000 ; |X X X | | |
.byte #%10101000 ; |X X X | | |
.byte #%11101110 ; |XXX XXX | | |
.byte #%11101110 ; |XXX XXX | | |
.byte #%10001000 ; |X X | | |
.byte #%10001000 ; |X X | | |
.byte #%10001000 ; |X X | | |
.byte #%10001000 ; |X X | | |
.byte #%11101110 ; |XXX XXX | | |
.byte #%11101110 ; |XXX XXX | | |
Gene2Gfx ; graphic for "NE" part of "GENE" | |
.byte #%01110101 ; | XXX X X| | |
.byte #%01110101 ; | XXX X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%01110101 ; | XXX X X| | |
.byte #%01110101 ; | XXX X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%00010101 ; | X X X| | |
.byte #%01110111 ; | XXX XXX| | |
.byte #%01110111 ; | XXX XXX| | |
Medic1Gfx ; graphic for "ME" part of "MEDIC" | |
.byte #%10101110 ; |XX XXX X| | |
.byte #%10101110 ; |XX XXX X| | |
.byte #%10101000 ; |XX X X X| | |
.byte #%10101000 ; |XX X X X| | |
.byte #%10101000 ; | X X X X| | |
.byte #%10101000 ; | X X X X| | |
.byte #%10101110 ; | X X X X| | |
.byte #%10101110 ; | X X X X| | |
.byte #%10101000 ; | X X X X| | |
.byte #%10101000 ; | X X X X| | |
.byte #%11101000 ; | X X X X| | |
.byte #%11101000 ; | X X X X| | |
.byte #%10101110 ; | X XXX X| | |
.byte #%10101110 ; | X XXX X| | |
Medic2Gfx ; graphic for "DIC" part of "MEDIC" | |
.byte #%11010011 ; | X X XX| | |
.byte #%11010111 ; | X X XX| | |
.byte #%01010101 ; | X X X | | |
.byte #%01010101 ; | XX X X | | |
.byte #%01010101 ; | XX X X | | |
.byte #%01010101 ; | XXX | | |
.byte #%01010101 ; | XX | | |
.byte #%01010101 ; | XX | | |
.byte #%01010101 ; | XXX | | |
.byte #%01010101 ; | XX X | | |
.byte #%01010101 ; | XX X | | |
.byte #%01010101 ; | X X | | |
.byte #%11010111 ; | X X XX| | |
.byte #%11010011 ; | X X XX| | |
GeneColor ; one color for each of the 14 scanlines | |
; for each of the start screen game names | |
; The colors for Gene in Gene Medic | |
.byte $02 | |
.byte $02 | |
.byte $04 | |
.byte $04 | |
.byte $06 | |
.byte $06 | |
.byte $08 | |
.byte $08 | |
.byte $0A | |
.byte $0A | |
.byte $0C | |
.byte $0C | |
.byte $0E | |
.byte $0E | |
MedicColor ; one color for each of the 14 scanlines | |
; for each of the start screen game names | |
; The colors for Medic in Gene Medic | |
.byte $12 | |
.byte $12 | |
.byte $14 | |
.byte $14 | |
.byte $16 | |
.byte $16 | |
.byte $18 | |
.byte $18 | |
.byte $1A | |
.byte $1A | |
.byte $1C | |
.byte $1C | |
.byte $1E | |
.byte $1E | |
; **************************************************************** | |
; The graphics for the mitochondria and endoplasmic reticulum | |
; cytoplasmic elements | |
; **************************************************************** | |
MitoGfx ; graphic for the mitochodria | |
.byte #%01111110 ; | XXXXXX | | |
.byte #%11111111 ; |XXXXXXXX| | |
.byte #%10100001 ; |X X X| | |
.byte #%10100001 ; |X X X| | |
.byte #%10100001 ; |X X X| | |
.byte #%10100001 ; |X X X| | |
.byte #%10100101 ; |X X X X| | |
.byte #%10100101 ; |X X X X| | |
.byte #%10100101 ; |X X X X| | |
.byte #%10000101 ; |X X X| | |
.byte #%10000101 ; |X X X| | |
.byte #%10000101 ; |X X X| | |
.byte #%11111111 ; |XXXXXXXX| | |
.byte #%01111110 ; | XXXXXX | | |
ERGfx ; graphic for the endoplasmic reticulum | |
.byte #%00000000 ; | | | |
.byte #%00011000 ; | XX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%00011000 ; | XX | | |
.byte #%00111111 ; | XXXXXX| | |
.byte #%00111111 ; | XXXXXX| | |
.byte #%00011000 ; | XX | | |
.byte #%01111100 ; | XXXXX | | |
.byte #%01111100 ; | XXXXX | | |
.byte #%00110000 ; | XX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%00110000 ; | XX | | |
; **************************************************************** | |
; The playfield graphics for the DNA double helix A | |
; Used on alternating screens to simulate movement through cell | |
; **************************************************************** | |
HelixA0 ; PF0 - only first four bits are read | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %10000000 ; |X | | |
.byte %01000000 ; | X | | |
.byte %00100000 ; | X | | |
.byte %00010000 ; | X | | |
.byte %00100000 ; | X | | |
.byte %01000000 ; | X | | |
.byte %10000000 ; |X | | |
.byte %00000000 ; | | | |
HelixA1 ; PF1 | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %11000001 ; |XX X| | |
.byte %00100010 ; | X X | | |
.byte %00010100 ; | X X | | |
.byte %00001000 ; | X | | |
.byte %00010100 ; | X X | | |
.byte %00100010 ; | X X | | |
.byte %11000001 ; |XX X| | |
.byte %00000000 ; | | | |
HelixA2 ; PF2 | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %10000011 ; |X XX| | |
.byte %01000100 ; | X X | | |
.byte %00101000 ; | X X | | |
.byte %00010000 ; | X | | |
.byte %00101000 ; | X X | | |
.byte %01000100 ; | X X | | |
.byte %10000011 ; |X XX| | |
.byte %00000000 ; | | | |
; **************************************************************** | |
; The playfield graphics for the DNA double helix B | |
; Used on alternating screens to simulate movement through cell | |
; **************************************************************** | |
HelixB0 ; PF0 - only first four bits are read | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %10000000 ; |X | | |
.byte %01000000 ; | X | | |
.byte %00100000 ; | X | | |
.byte %00010000 ; | X | | |
.byte %00100000 ; | X | | |
.byte %01000000 ; | X | | |
.byte %10000000 ; |X | | |
.byte %00000000 ; | | | |
HelixB1 ; PF1 | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %10000011 ; |X XX| | |
.byte %01000100 ; | X X | | |
.byte %00101000 ; | X X | | |
.byte %00010000 ; | X | | |
.byte %00101000 ; | X X | | |
.byte %01000100 ; | X X | | |
.byte %10000011 ; |X XX| | |
.byte %00000000 ; | | | |
HelixB2 ; PF2 | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %00000000 ; | | | |
.byte %11000001 ; |XX X| | |
.byte %00100010 ; | X X | | |
.byte %00010100 ; | X X | | |
.byte %00001000 ; | X | | |
.byte %00010100 ; | X X | | |
.byte %00100010 ; | X X | | |
.byte %11000001 ; |XX X| | |
.byte %00000000 ; | | | |
; **************************************************************** | |
; The graphics for the heart used to indicate win-loss at end | |
; **************************************************************** | |
HeartGfx ; graphics for the final heart | |
; only half is needed because it is | |
; refelected in symmatrical playfield | |
; need 36 scanlines to draw | |
.byte #%10000000 ; |X | | |
.byte #%10000000 ; |X | | |
.byte #%10000000 ; |X | | |
.byte #%11000000 ; |XX | | |
.byte #%11000000 ; |XX | | |
.byte #%11000000 ; |XX | | |
.byte #%11100000 ; |XXX | | |
.byte #%11100000 ; |XXX | | |
.byte #%11100000 ; |XXX | | |
.byte #%11110000 ; |XXXX | 10 scanline | |
.byte #%11110000 ; |XXXX | | |
.byte #%11110000 ; |XXXX | | |
.byte #%11111000 ; |XXXXX | | |
.byte #%11111000 ; |XXXXX | | |
.byte #%11111000 ; |XXXXX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111110 ; |XXXXXXX | 20 scanline | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111110 ; |XXXXXXX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%11111100 ; |XXXXXX | | |
.byte #%11111100 ; |XXXXXX | 30 scanline | |
.byte #%11111000 ; |XXXXX | | |
.byte #%11111000 ; |XXXXX | | |
.byte #%01110000 ; | XXX | | |
.byte #%01110000 ; | XXX | | |
.byte #%00110000 ; | XX | | |
.byte #%00110000 ; | XX | 36 scanline | |
; **************************************************************** | |
; The graphics for the money bag and research powerups | |
; **************************************************************** | |
MoneyBag ; Money Bag powerup graphic | |
; 16 scanlines | |
.byte %00000000 ; | | | |
.byte %00111110 ; | XXXXX | | |
.byte %01110111 ; | XXX XXX| | |
.byte %01110111 ; | XXX XXX| | |
.byte %01100011 ; | XX XX| | |
.byte %01111011 ; | XXXX XX| | |
.byte %01100011 ; | XX XX| | |
.byte %01101111 ; | XX XXXX| | |
.byte %01100011 ; | XX XX| | |
.byte %00110110 ; | XX XX | | |
.byte %00110110 ; | XX XX | | |
.byte %00011100 ; | XXX | | |
.byte %00001000 ; | X | | |
.byte %00011100 ; | XXX | | |
.byte %00110110 ; | XX XX | | |
.byte %00000000 ; | | | |
Research ; Research powerup graphic | |
; 16 scanlines | |
.byte %00000000 ; | | | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %10000001 ; |X X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10000001 ; |X X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10000001 ; |X X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10000001 ; |X X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10000001 ; |X X| | |
.byte %10001101 ; |X XX X| | |
.byte %10000001 ; |X X| | |
.byte %10100001 ; |X X X| | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %00000000 ; | | | |
EHR ; EHR computer powerup graphic | |
; 16 scanlines | |
.byte %00000000 ; | | | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %00000000 ; | | | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %10000001 ; |X X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10111101 ; |X XXXX X| | |
.byte %10000001 ; |X X| | |
.byte %10111001 ; |X XXX X| | |
.byte %10111001 ; |X XXX X| | |
.byte %10111001 ; |X XXX X| | |
.byte %10000001 ; |X X| | |
.byte %11111111 ; |XXXXXXXX| | |
.byte %00000000 ; | | | |
; **************************************************************** | |
; The sound effect subroutines and data called from the main loop. | |
; These came directly from Darrell Spice's tutorial with some | |
; modifications. See sfx.asm file for more detailed comments. | |
; See https://is.gd/YDAPkE for information and credit. Thanks! | |
; **************************************************************** | |
SFX_F ; frequencies | |
.byte 0, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0 ; harmful edit | |
.byte 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 ; helpful edit | |
.byte 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; ping | |
.byte 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 ; win1 | |
.byte 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 ; win2 | |
.byte 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 ; win3 | |
.byte 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 ; lose1 | |
.byte 0, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25 ; lose2 | |
.byte 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 ; lose3 | |
SFX_CV ; channel and volume | |
.byte 0,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f ; harmful edit | |
sfxHARM = *-SFX_CV-1 | |
.byte 0,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f,$6f ; helpful edit | |
sfxHELP = *-SFX_CV-1 | |
.byte 0,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c ; ping | |
sfxPING = *-SFX_CV-1 | |
.byte 0,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf ; win1 | |
sfxWIN1 = *-SFX_CV-1 | |
.byte 0,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf ; win2 | |
sfxWIN2 = *-SFX_CV-1 | |
.byte 0,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf ; win3 | |
sfxWIN3 = *-SFX_CV-1 | |
.byte 0,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf ; lose1 | |
sfxLOSE1 = *-SFX_CV-1 | |
.byte 0,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf ; lose2 | |
sfxLOSE2 = *-SFX_CV-1 | |
.byte 0,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf,$cf ; lose3 | |
sfxLOSE3 = *-SFX_CV-1 | |
SFX_OFF | |
ldx #0 ; silence sound output | |
stx SFX_LEFT ; reset to 0 | |
stx SFX_RIGHT ; reset to 0 | |
stx AUDV0 ; reset volume to 0 | |
stx AUDV1 ; reset volume to 1 | |
stx AUDC0 ; reset channel to 0 | |
stx AUDC1 ; reset channel to 1 | |
rts ; return | |
SFX_TRIGGER | |
ldx SFX_LEFT ; test left channel | |
lda SFX_CV,x ; CV value will be 0 if channel is idle | |
bne .leftnotfree ; if not 0 then skip ahead | |
sty SFX_LEFT ; channel is idle, use it | |
rts ; all done | |
.leftnotfree | |
ldx SFX_RIGHT ; test right channel | |
lda SFX_CV,x ; CV value will be 0 if channel is idle | |
bne .rightnotfree ; if not 0 then skip ahead | |
sty SFX_RIGHT ; channel is idle, use it | |
rts ; all done | |
.rightnotfree | |
cpy SFX_LEFT ; test sfx priority with left channel | |
bcc .leftnotlower ; skip ahead if new sfx has lower priority than active sfx | |
sty SFX_LEFT ; new sfx has higher priority so use left channel | |
rts ; all done | |
.leftnotlower | |
cpy SFX_RIGHT ; test sfx with right channel | |
bcc .rightnotlower ; skip ahead if new sfx has lower priority than active sfx | |
sty SFX_RIGHT ; new sfx has higher priority so use right channel | |
.rightnotlower | |
rts | |
SFX_UPDATE | |
ldx SFX_LEFT ; get the pointer for the left channel | |
lda SFX_F,x ; get the Frequency value | |
sta AUDF0 ; update the Frequency register | |
lda SFX_CV,x ; get the combined Control and Volume value | |
sta AUDV0 ; update the Volume register | |
lsr ; prep the Control value, | |
lsr ; it's stored in the upper nybble | |
lsr ; but must be in the lower nybble | |
lsr ; when Control is updated | |
sta AUDC0 ; update the Control register | |
beq .skipleftdec ; skip ahead if Control = 0 | |
dec SFX_LEFT ; update pointer for left channel | |
.skipleftdec: | |
ldx SFX_RIGHT ; get the pointer for the right channel | |
lda SFX_F,x ; get the Frequency value | |
sta AUDF1 ; update the Frequency register | |
lda SFX_CV,x ; get the combined Control and Volume value | |
sta AUDV1 ; update the Volume register | |
lsr ; prep the Control value, | |
lsr ; it's stored in the upper nybble | |
lsr ; but must be in the lower nybble | |
lsr ; when Control is updated | |
sta AUDC1 ; update the Control register | |
beq .skiprightdec ; skip ahead if Control = 0 | |
dec SFX_RIGHT ; update pointer for right channel | |
.skiprightdec | |
rts ; all done | |
; **************************************************************** | |
; The Interrupts are are used to help rescue the 6502 if it fails | |
; 2/3 are not used by 6507 chip. | |
; **************************************************************** | |
ORG $FFFA ; address for the interrupt vectors | |
InterruptVectors | |
.word Reset ; NMI | |
.word Reset ; RESET | |
.word Reset ; IRQ | |
END |