LIST OFF ; *** L O C K ' N ' C H A S E *** ; Copyright 1982, Mattel, Inc. ; Designer: Bruce Pedersen ; ; Analyzed, labeled and commented ; by Dennis Debro ; Last Update: September 13, 2022 ; ; *** 120 BYTES OF RAM USED 8 BYTES FREE ; ; NTSC ROM usage stats ; ------------------------------------------- ; *** 384 BYTES OF ROM FREE ; ; PAL50 ROM usage stats ; ------------------------------------------- ; *** 418 BYTES OF ROM FREE ; ; ============================================================================== ; = THIS REVERSE-ENGINEERING PROJECT IS BEING SUPPLIED TO THE PUBLIC DOMAIN = ; = FOR EDUCATIONAL PURPOSES ONLY. THOUGH THE CODE WILL ASSEMBLE INTO THE = ; = EXACT GAME ROM, THE LABELS AND COMMENTS ARE THE INTERPRETATION OF MY OWN = ; = AND MAY NOT REPRESENT THE ORIGINAL VISION OF THE AUTHOR. = ; = = ; = THE ASSEMBLED CODE IS © 1982, MATTEL, INC. = ; = = ; ============================================================================== ; processor 6502 include "macro.h" include "tia_constants.h" include "vcs.h" ; ; Make sure we are using vcs.h version 1.05 or greater. ; IF VERSION_VCS < 105 echo "" echo "*** ERROR: vcs.h file *must* be version 1.05 or higher!" echo "*** Updates to this file, DASM, and associated tools are" echo "*** available at https://dasm-assembler.github.io/" echo "" err ENDIF ; ; Make sure we are using macro.h version 1.01 or greater. ; IF VERSION_MACRO < 101 echo "" echo "*** ERROR: macro.h file *must* be version 1.01 or higher!" echo "*** Updates to this file, DASM, and associated tools are" echo "*** available at https://dasm-assembler.github.io/" echo "" err ENDIF LIST ON ;=============================================================================== ; A S S E M B L E R - S W I T C H E S ;=============================================================================== NTSC = 0 PAL50 = 1 PAL60 = 2 TRUE = 1 FALSE = 0 IFNCONST COMPILE_REGION COMPILE_REGION = NTSC ; change to compile for different regions ENDIF IF !(COMPILE_REGION = NTSC || COMPILE_REGION = PAL50 || COMPILE_REGION = PAL60) echo "" echo "*** ERROR: Invalid COMPILE_REGION value" echo "*** Valid values: NTSC = 0, PAL50 = 1, PAL60 = 2" echo "" err ENDIF ;=============================================================================== ; F R A M E T I M I N G S ;=============================================================================== IF COMPILE_REGION = NTSC || COMPILE_REGION = PAL60 VBLANK_TIME = 45 OVERSCAN_TIME = 25 ELSE VBLANK_TIME = 75 OVERSCAN_TIME = 55 ENDIF KERNEL_TIME = 238 ;=============================================================================== ; C O L O R - C O N S T A N T S ;=============================================================================== BLACK = $00 WHITE = $0E IF COMPILE_REGION = NTSC YELLOW = $10 RED_ORANGE = $20 BRICK_RED = $30 RED = $40 PURPLE = $50 COBALT_BLUE = $60 ULTRAMARINE_BLUE = $70 BLUE = $80 DK_BLUE = $90 CYAN = $A0 OLIVE_GREEN = $B0 GREEN = $C0 DK_GREEN = $D0 ORANGE_GREEN = $E0 BROWN = $F0 COLOR_LEFT_PLAYER = BRICK_RED + 4 COLOR_RIGHT_PLAYER = GREEN + 8 COLOR_GOLD_BARS = RED_ORANGE + 12 COLOR_MAZE = DK_BLUE + 4 COLOR_POLICE = DK_BLUE + 10 COLOR_LOWER_TREASURE = PURPLE + 8 COLOR_CLOSED_DOOR = PURPLE + 10 ELSE YELLOW = $20 RED_ORANGE = $20 GREEN = $30 BRICK_RED = $40 DK_GREEN = $50 RED = $60 PURPLE = $70 COLBALT_BLUE = $80 CYAN = $A0 BLUE = $B0 DK_BLUE = BLUE LT_BLUE = $C0 BLUE_2 = $D0 COLOR_LEFT_PLAYER = BRICK_RED + 4 COLOR_RIGHT_PLAYER = DK_GREEN + 8 COLOR_GOLD_BARS = BRICK_RED + 12 COLOR_MAZE = DK_BLUE + 4 COLOR_POLICE = DK_BLUE + 10 COLOR_LOWER_TREASURE = COLBALT_BLUE + 8 COLOR_CLOSED_DOOR = CYAN + 10 ENDIF COLOR_LEFT_PLAYER_REMAINING_LIVES = COLOR_LEFT_PLAYER + 8 COLOR_RIGHT_PLAYER_REMAINING_LIVES = COLOR_RIGHT_PLAYER + 4 ;=============================================================================== ; U S E R - C O N S T A N T S ;=============================================================================== ROM_BASE = $F000 H_KERNEL = 96 H_KERNEL_ZONE = 16 H_DIGITS = 7 H_POLICE = 8 H_THIEF = 8 XMIN = 5 XMAX = 144 YMIN = 8 YMAX = 88 LOWER_TREASURE_VERT_POS = 40 UPPER_TREASURE_VERT_POS = 56 LOWER_TREASURE_INDEX = 5 UPPER_TREASURE_INDEX = 7 TREASURE_HORIZ_POS = 74 KERNEL_SECTIONS = 12 INIT_THIEF_HORIZ = 74 INIT_THIEF_VERT = 98 INIT_LEFT_POLICE_HORIZ = 8 INIT_RIGHT_POLICE_HORIZ = 140 INIT_POLICE_VERT_00 = 40 INIT_POLICE_VERT_01 = 40 INIT_POLICE_VERT_02 = 56 INIT_POLICE_VERT_03 = 56 MAX_GOLD_BARS = 104 INIT_LIVES = 5 MAX_LIVES = 7 MAX_LOWER_TREASURES = 2 MAX_UPPER_TREASURES = 4 INIT_BONUS_POINT_TIMER_VALUE = 120 GOLD_BARS_MASK = $AA MAX_UPPER_TREASURE_POINT_IDX = 4 NUM_POLICE = 4 ZONE_MAX_POLICE = 2 ; maximum Police in a given zone ; ; gameState mask values ; TRAPPED_POLICE_REWARD_MASK = %10000000 ESCAPE_DOOR_MASK = %01000000 SHOW_LOWER_TREASURE_MASK = %00100000 SHOW_UPPER_TREASURE_MASK = %00010000 ROUND_START_MASK = %00001000 PAUSE_MOVEMENT_MASK = %00000100 GAME_ACTIVE_MASK = %00000010 ALTERNATE_PLAYERS_MASK = %00000001 ; ; gameState values ; GS_ALTERNATE_PLAYERS = 1 << 0 GS_NOT_ALTERNATE_PLAYERS = 0 << 0 GS_GAME_ACTIVE = 1 << 1 GS_GAME_INACTIVE = 0 << 1 GS_PAUSE_MOVEMENT = 1 << 2 GS_ALLOW_MOVEMENT = 0 << 2 GS_START_ROUND = 1 << 3 GS_NOT_START_ROUND = 0 << 3 GS_OPEN_ESCAPE_DOOR = 1 << 6 GS_CLOSE_ESCAPE_DOOR = 0 << 6 GS_TRAPPED_POLICE_REWARDED = 1 << 7 GS_TRAPPED_POLICE_NOT_REWARDED = 0 << 7 ; ; sound id values ; SOUND_ID_GOLD_BARS = 1 SOUND_ID_CLOSE_DOOR = 2 SOUND_ID_UPPER_TREASURE = 3 SOUND_ID_EXTRA_LIFE = 4 SOUND_ID_POLICE_TRAPPED = 5 SOUND_ID_TREASURE_CAPTURED = 6 SOUND_ID_THIEF_CAPTURED = 7 SOUND_ID_THIEF_ESCAPE = 8 ; ; sound volume constants ; INIT_GOLD_BAR_VOLUME = 5 CLOSE_DOOR_VOLUME = 15 UPPER_TREASURE_VOLUME = 6 TREASURE_CAPTURED_VOLUME = 15 THIEF_CAPTURED_VOLUME = 15 THIEF_ESCAPE_VOLUME = 6 ; ; sound frequency constants ; GOLD_BAR_FREQUENCY = 1 CLOSE_DOOR_FREQUENCY = 2 UPPER_TREASURE_FREQUENCY = 31 EXTRA_LIFE_FREQUENCY = 8 POLICE_TRAPPED_FREQUENCY = 8 TREASURE_CAPTURED_FREQUENCY = 31 THIEF_CAPTURED_FREQUENCY = 6 THIEF_ESCAPE_FREQUENCY = 31 ; ; sound tone constants ; GOLD_BAR_TONE = 1 CLOSE_DOOR_TONE = 2 UPPER_TREASURE_TONE = 12 EXTRA_LIFE_TONE = 12 POLICE_TRAPPED_TONE = 12 TREASURE_CAPTURED_TONE = 4 THIEF_CAPTURED_TONE = 8 THIEF_ESCAPE_TONE = 4 ; ; sound duration constants ; GOLD_BAR_SOUND_DURATION = 5 CLOSE_DOOR_SOUND_DURATION = 3 UPPER_TREASURE_SOUND_DURATION = 255 EXTRA_LIFE_SOUND_DURATION = 96 POLICE_TRAPPED_SOUND_DURATION = 111 TREASURE_CAPTURED_SOUND_DURATION = 111 THIEF_CAPTURED_SOUND_DURATION = 56 THIEF_ESCAPE_SOUND_DURATION = 96 ; ; point value constants ; POINTS_20 = $0020 POINTS_250 = $0250 POINTS_500 = $0500 POINTS_1000 = $1000 POINTS_2000 = $2000 POINTS_4000 = $4000 POINTS_250_INDEX = 0 POINTS_500_INDEX = 1 POINTS_1000_INDEX = 2 POINTS_2000_INDEX = 3 POINTS_4000_INDEX = 4 POINTS_20_INDEX = 5 ;=============================================================================== ; M A C R O S ;=============================================================================== ;------------------------------------------------------- ; FILL_BOUNDARY byte# ; Original author: Dennis Debro (borrowed from Bob Smith / Thomas Jentzsch) ; ; Push data to a certain position inside a page and keep count of how ; many free bytes the programmer will have. ; ; eg: FILL_BOUNDARY 5, 234 ; position at byte #5 in page with $EA is byte filler FREE_BYTES SET 0 .BYTES_TO_SKIP SET 0 MAC FILL_BOUNDARY IF <. > {1} .BYTES_TO_SKIP SET (256 - <.) + {1} ELSE .BYTES_TO_SKIP SET (256 - <.) - (256 - {1}) ENDIF REPEAT .BYTES_TO_SKIP FREE_BYTES SET FREE_BYTES + 1 .byte {2} REPEND ENDM ;=============================================================================== ; Z P - V A R I A B L E S ;=============================================================================== SEG.U GAME_ZP_VARIABLES .org $80 playerScore ds 6 gameLevelValues ds 2 ;-------------------------------------- leftPlayerLevel = gameLevelValues rightPlayerLevel = leftPlayerLevel + 1 remainingLives ds 2 ;-------------------------------------- leftPlayerRemainingLives = remainingLives rightPlayerRemainingLives = leftPlayerRemainingLives + 1 gameSelection ds 1 currentPlayerNumber ds 1 goldBarsTaken ds 2 ;-------------------------------------- leftPlayerGoldBarsTaken = goldBarsTaken rightPlayerGoldBarsTaken = leftPlayerGoldBarsTaken + 1 gameState ds 1 goldBarsRemaining ds 1 goldBars ds 23 ;-------------------------------------- leftGoldBars = goldBars remainingUpperTreasures = leftGoldBars + 11 rightGoldBars = leftGoldBars + 12 treasureTimerValues ds 2 ;-------------------------------------- lowerTreasureTimerValue = treasureTimerValues upperTreasureTimerValue = lowerTreasureTimerValue + 1 upperTreasurePointIndex ds 1 remainingLowerTreasures ds 1 extraLifeRewardedState ds 1 policeMovementState ds 1 frameCount ds 1 roundTransitionTimer ds 1 ;-------------------------------------- selectDebounceTimer = roundTransitionTimer bonusPointTimer ds 1 objectHorizPositions ds 5 ;-------------------------------------- thiefHorizPosition = objectHorizPositions policeHorizPositions = thiefHorizPosition + 1 objectKernelHorizPositions ds 5 ;-------------------------------------- thiefKernelHorizPosition = objectKernelHorizPositions policeKernelHorizPositions = thiefKernelHorizPosition + 1 objectVertPositions ds 5 ;-------------------------------------- thiefVertPosition = objectVertPositions policeVertPositions = thiefVertPosition + 1 objectDirectionValues ds 5 ;-------------------------------------- thiefDirectionValue = objectDirectionValues policeDirectionValues = thiefDirectionValue + 1 temporaryZPVariables ds 23 .org temporaryZPVariables ; ; Temporary directional variables ; tmpPoliceDirectionValues ds NUM_POLICE ;-------------------------------------- tmpJoystickValues = tmpPoliceDirectionValues + 1 ;-------------------------------------- tmpAdjustedHorizPosition = tmpJoystickValues tmpThiefIllegalDirections = tmpJoystickValues + 1 ;-------------------------------------- tmpHorizPosDiv16 = tmpThiefIllegalDirections .org temporaryZPVariables + 7 tmpIllegalDirections ds 1 tmpPoliceDirection = tmpIllegalDirections + 2 tmpUpperTreasurePointIndex = tmpPoliceDirection + 2 ;-------------------------------------- tmpGameLevelValues = tmpUpperTreasurePointIndex tmpPoliceTrappedState = tmpUpperTreasurePointIndex + 2 tmpThiefMazePosition = tmpPoliceTrappedState + 2 ;-------------------------------------- tmpTreasureIndex = tmpThiefMazePosition .org temporaryZPVariables + 17 tmpZonePoliceCount ds [KERNEL_SECTIONS / 2] .org temporaryZPVariables + 17 ; ; Temporary Police sort variables ; tmpPoliceIndex ds 1 tmpSortedPoliceIndexArray ds NUM_POLICE .org temporaryZPVariables ; ; Temporary display kernel variables ; thiefGraphicPtrs ds 2 policeGraphicPtrs_00 ds 2 policeGraphicPtrs_01 ds 2 graphicsPointers ds 12 ;-------------------------------------- tmpScanline = graphicsPointers + 1 ;-------------------------------------- tmpPoliceGraphicValue_00 = graphicsPointers + 3 ;-------------------------------------- tmpEscapeDoorGraphicValue = graphicsPointers + 5 ;-------------------------------------- tmpKernelSection = graphicsPointers + 7 ;-------------------------------------- tmpPoliceGraphicValue_01 = graphicsPointers + 9 ;-------------------------------------- tmpScoreAreaChar ds 1 tmpScoreAreaIndex ds 1 .org graphicsPointers + 11 tmpClosedDoorColumns ds 6 ;-------------------------------------- tmpClosedDoorColumn_00 = tmpClosedDoorColumns tmpClosedDoorColumn_01 = tmpClosedDoorColumn_00 + 1 tmpClosedDoorColumn_02 = tmpClosedDoorColumn_01 + 1 tmpClosedDoorColumn_03 = tmpClosedDoorColumn_02 + 1 tmpClosedDoorColumn_04 = tmpClosedDoorColumn_03 + 1 tmpClosedDoorColumn_05 = tmpClosedDoorColumn_04 + 1 closedDoorMazePositionValues ds 2 ;-------------------------------------- firstClosedDoorMazePosition = closedDoorMazePositionValues secondClosedDoorMazePosition = firstClosedDoorMazePosition + 1 closedDoorTimerValues ds 2 ;-------------------------------------- firstClosedDoorTimer = closedDoorTimerValues secondClosedDoorTimer = firstClosedDoorTimer + 1 previousThiefMazePosition ds 1 policeMovementDelay ds 1 kernelZonePoliceIndexValues ds KERNEL_SECTIONS thiefGraphicOffset ds 1 policeGraphicOffset_00 ds 1 policeGraphicOffset_01 ds 1 policeScanline_00 ds 1 policeScanline_01 ds 1 joystickDirectionValues ds 1 soundDurationValues ds 2 ;-------------------------------------- leftChannelSoundDurationValue = soundDurationValues rightChannelSoundDurationValue = leftChannelSoundDurationValue + 1 soundPriorityValues ds 2 ;-------------------------------------- leftChannelSoundPriorityValue = soundPriorityValues rightChannelSoundPriorityValue = leftChannelSoundPriorityValue + 1 random ds 1 echo "***",(* - $80)d, "BYTES OF RAM USED", ($100 - *)d, "BYTES FREE" ;=============================================================================== ; R O M - C O D E ;=============================================================================== SEG Bank0 .org ROM_BASE PrepareZoneForPolice_00 sta WSYNC ;-------------------------------------- sta HMOVE ; 3 lda tmpPoliceGraphicValue_01;3 sta ENAM1 ; 3 = @09 asl ; 2 asl ; 2 sta NUSIZ1 ; 3 = @16 lda tmpPoliceGraphicValue_00;3 sta GRP1 ; 3 = @22 lda tmpEscapeDoorGraphicValue;3 sta ENAM0 ; 3 = @28 dey ; 2 lda (thiefGraphicPtrs),y ; 5 sta GRP0 ; 3 = @38 lda (policeGraphicPtrs_01),y;5 sta tmpPoliceGraphicValue_01;3 sta HMM1 ; 3 = @49 lda #0 ; 2 sta tmpPoliceGraphicValue_00;3 lda kernelZonePoliceIndexValues - 1,x;4 tax ; 2 beq .skipPositionPolice_00 ; 2³ lda objectVertPositions,x ; 4 sta policeScanline_00 ; 3 lda policeGraphicOffset_00 ; 3 sta WSYNC ;-------------------------------------- sec ; 2 sbc objectVertPositions,x ; 4 sta policeGraphicPtrs_00 ; 3 lda objectKernelHorizPositions,x;4 sta HMP1 ; 3 = @16 and #$0F ; 2 .coarsePositionPolice_00 sbc #1 ; 2 bpl .coarsePositionPolice_00;2³ sta RESP1 ; 3 PrepareZoneForPolice_01 ldx tmpKernelSection ; 3 sta WSYNC ;-------------------------------------- sta HMOVE ; 3 lda tmpPoliceGraphicValue_01;3 sta ENAM1 ; 3 = @09 asl ; 2 asl ; 2 sta NUSIZ1 ; 3 = @16 lda tmpPoliceGraphicValue_00;3 sta GRP1 ; 3 = @22 dey ; 2 lda (thiefGraphicPtrs),y ; 5 sta GRP0 ; 3 = @32 lda (policeGraphicPtrs_00),y;5 sta tmpPoliceGraphicValue_00;3 sta HMCLR ; 3 = @43 lda kernelZonePoliceIndexValues,x ;4 tax ; 2 beq .skipPositionPolice_01 ; 2³ lda #0 ; 2 sta tmpPoliceGraphicValue_01;3 sta ENAM1 ; 3 = @59 sta ENAM0 ; 3 = @62 lda objectVertPositions,x ; 4 sta policeScanline_01 ; 3 lda policeGraphicOffset_01 ; 3 sta WSYNC ;-------------------------------------- sec ; 2 sbc objectVertPositions,x ; 4 sta policeGraphicPtrs_01 ; 3 lda objectKernelHorizPositions,x;4 sta HMM1 ; 3 = @16 and #$0F ; 2 .coarsePositionPolice_01 sbc #1 ; 2 bpl .coarsePositionPolice_01;2³ sta RESM1 ; 3 jmp DrawZonePlayerObjects ; 3 .skipPositionPolice_00 sta WSYNC ;-------------------------------------- lda (policeGraphicPtrs_00),y;5 sta tmpPoliceGraphicValue_00;3 cpy policeScanline_00 ; 3 bcs .prepareZoneForPolice_01;2³ sty tmpScanline ; 3 lda #PoliceGraphicData ; 2 sta policeGraphicPtrs_01 + 1;3 sta policeGraphicPtrs_00 + 1;3 lda #>ThiefGraphicData ; 2 sta thiefGraphicPtrs + 1 ; 3 lda #ScoreAreaGraphicData ; 2 sta graphicsPointers + 1 ; 3 sta graphicsPointers + 7 ; 3 sta graphicsPointers + 3 ; 3 sta graphicsPointers + 9 ; 3 sta graphicsPointers + 5 ; 3 sta graphicsPointers + 11 ; 3 sta WSYNC ;-------------------------------------- sta HMOVE ; 3 lda #$FF ; 2 sta PF1 ; 3 = @08 sta PF2 ; 3 = @11 ldx currentPlayerNumber ; 3 lda RemainingLivesColorValues,x;4 sta COLUP0 ; 3 = @21 sta COLUP1 ; 3 = @24 lda gameState ; 3 get current game state and #GAME_ACTIVE_MASK ; 2 keep GAME_ACTIVE value bne .setStatusAreaObjectColors;2³ branch if GAME_ACTIVE lda #COLOR_RIGHT_PLAYER_REMAINING_LIVES;2 sta COLUP0 ; 3 = @36 .setStatusAreaObjectColors lda bonusPointTimer ; 3 get bonus point timer value bne .blinkScore ; 2³ blink bonus point value lda remainingLives,x ; 4 get player remaining lives bne DrawScoreArea ; 2³ + 1 .blinkScore lda frameCount ; 3 get current frame count and #8 ; 2 beq DrawScoreArea ; 2³ lda BlinkingScoreAreaColors,x;4 sta COLUP0 ; 3 sta COLUP1 ; 3 DrawScoreArea ldy #H_DIGITS - 1 ; 2 .drawScoreArea sty tmpScoreAreaIndex ; 3 lda (graphicsPointers + 10),y;5 tax ; 2 sta WSYNC ;-------------------------------------- lda (graphicsPointers + 4),y;5 sta tmpScoreAreaChar ; 3 lda (graphicsPointers),y ; 5 sta GRP0 ; 3 = @16 lda (graphicsPointers + 6),y;5 sta GRP1 ; 3 = @24 lda (graphicsPointers + 2),y;5 sta GRP0 ; 3 = @32 lda (graphicsPointers + 8),y;5 tay ; 2 lda tmpScoreAreaChar ; 3 sty GRP1 ; 3 = @45 sta GRP0 ; 3 = @48 stx GRP1 ; 3 = @51 sta GRP0 ; 3 = @54 ldy tmpScoreAreaIndex ; 3 dey ; 2 bpl .drawScoreArea ; 2³ sta WSYNC ;-------------------------------------- lda #0 ; 2 sta GRP0 ; 3 = @05 sta GRP1 ; 3 = @08 sta GRP0 ; 3 = @11 sta WSYNC ;-------------------------------------- sta PF0 ; 3 = @03 sta PF1 ; 3 = @06 sta PF2 ; 3 = @09 rts ; 6 RemainingLivesColorValues .byte COLOR_LEFT_PLAYER_REMAINING_LIVES .byte COLOR_RIGHT_PLAYER_REMAINING_LIVES BlinkingScoreAreaColors .byte BLACK + 8, BLACK + 8 ResetGame ldy gameSelection ; get current game selection bne ClearRAM ; branch if TWO_PLAYER game Start ; ; Set up everything so the power up state is known. ; sei ; disable interrupts cld ; clear decimal mode ldy #0 ClearRAM lda #0 tax .clearZPRAM sta VSYNC,x dex bne .clearZPRAM sty gameSelection ; set current game selection lda #INIT_LIVES sta leftPlayerRemainingLives sta rightPlayerRemainingLives jmp InitGameVariables StartNewRound jsr WaitForTimerExpiration lda #KERNEL_TIME sta TIM64T ldx #> 8], [POINTS_500 >> 8], [POINTS_1000 >> 8] .byte [POINTS_2000 >> 8], [POINTS_4000 >> 8], [POINTS_20 >> 8] ShowBonusPointValue lda #INIT_BONUS_POINT_TIMER_VALUE sta bonusPointTimer ldx StatusAreaBonusPointLiterals,y ldy #10 .setGraphicPointerValues lda StatusAreaGraphicLSBValues,x sta graphicsPointers,y dex dey dey bpl .setGraphicPointerValues rts StatusAreaBonusPointLiterals .byte <[StatusAreaPoints_250 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaPoints_500 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaPoints_1000 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaPoints_2000 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaPoints_4000 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaPoints_250 - StatusAreaGraphicLSBValues] + 5 StatusAreaRemainingLives .byte 0 ; invalid .byte <[StatusAreaLives_00 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaLives_01 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaLives_02 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaLives_03 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaLives_04 - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaLives_05 - StatusAreaGraphicLSBValues] + 5 StatusAreaGameSelection .byte <[StatusAreaOnePlayer - StatusAreaGraphicLSBValues] + 5 .byte <[StatusAreaTwoPlayers - StatusAreaGraphicLSBValues] + 5 StatusAreaGraphicLSBValues StatusAreaPoints_500 .byte > 2] ; compare with screen mid point adc #[1 - 1] ; increment by 1 if on right half lsr ; divide position by 8 bcs .objectNotMazeIntersection tay .setMazePositionPositionValue lda objectVertPositions,x ; get object vertical position clc adc #8 ; increment position by 8 (i.e. H_OBJECT) lsr lsr lsr lsr ; divide by 16 for kernel section ora MazeHorizCoordinateValues,y ; combine with horizontal coordinate value rts .objectNotMazeIntersection ldy #0 beq .setMazePositionPositionValue;unconditional branch MazeHorizCoordinateValues .byte 0 << 3, 0 << 3, 1 << 3, 0 << 3, 0 << 3, 2 << 3, 0 << 3, 0 << 3, 3 << 3 .byte 0 << 3, 0 << 3, 4 << 3, 0 << 3, 0 << 3, 5 << 3, 0 << 3, 0 << 3, 6 << 3 .byte 0 << 3, 0 << 3 ; not used IF COMPILE_REGION != PAL50 .byte $90,$D0,$D0,$D0,$D0,$50,$30,$B0,$70,$B0,$70,$30 .byte $B0,$F0,$F0,$F0,$F0,$70,$B0,$70,$B0,$70,$B0,$70 .byte $B0,$E0,$F0,$F0,$E0,$70,$A0,$C0,$E0,$E0,$C0,$60 ENDIF DeterminePoliceDirections SUBROUTINE ldx #[KERNEL_SECTIONS / 2] - 1 lda policeMovementState ; get Police movement state beq .clearZonePoliceCountValues ; branch if Police moving rts .clearZonePoliceCountValues sta tmpZonePoliceCount,x dex bpl .clearZonePoliceCountValues sta tmpPoliceTrappedState ; clear for Police trapped state ldx currentPlayerNumber lda gameLevelValues,x ; get current game level sta tmpGameLevelValues ldx #NUM_POLICE .determinePoliceDirections lda #P0_JOYSTICK_MASK ; allow all directions ldy policeDirectionValues - 1,x ; get Police direction value beq .flipPoliceDirections lda #<~[MOVE_UP & MOVE_DOWN] ; allow vertical directions cpy #<~MOVE_LEFT bcs .flipPoliceDirections ; branch if moving horizontally lda #<~[MOVE_RIGHT & MOVE_LEFT] ; allow horizontal directions .flipPoliceDirections eor policeDirectionValues - 1,x sta policeDirectionValues - 1,x jsr DetermineAllowedDirection ldy leftPlayerLevel ; get left player game level value cpy #2 bcs .donePoliceTunnelRestrictions; branch if passed level 1 ldy policeHorizPositions - 1,x ; get Police horizontal position cpy #16 bne .restrictPoliceFromRightTunnel and #> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_R2 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE8 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE8 >> 2] | ENABLE_BM .byte HMOVE_L2 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_R3 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM PoliceMissileGraphics_01 .byte HMOVE_0 | [MSBL_SIZE2 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_R2 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE8 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE8 >> 2] | ENABLE_BM .byte HMOVE_L2 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_R3 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM PoliceMissileGraphics_02 .byte HMOVE_R2 | [MSBL_SIZE2 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_R2 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE8 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE8 >> 2] | ENABLE_BM .byte HMOVE_L2 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_R3 | [MSBL_SIZE4 >> 2] | ENABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM .byte HMOVE_0 | [MSBL_SIZE1 >> 2] | DISABLE_BM FILL_BOUNDARY 256, -1 ScoreAreaGraphicData zero .byte $FE ; |XXXXXXX.| .byte $C6 ; |XX...XX.| .byte $D6 ; |XX.X.XX.| .byte $D6 ; |XX.X.XX.| .byte $C6 ; |XX...XX.| .byte $FE ; |XXXXXXX.| .byte $00 ; |........| .byte $00 ; |........| one .byte $7E ; |.XXXXXX.| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $18 ; |...XX...| .byte $38 ; |..XXX...| .byte $00 ; |........| .byte $00 ; |........| two .byte $7E ; |.XXXXXX.| .byte $60 ; |.XX.....| .byte $7E ; |.XXXXXX.| .byte $06 ; |.....XX.| .byte $66 ; |.XX..XX.| .byte $7E ; |.XXXXXX.| .byte $00 ; |........| .byte $00 ; |........| three .byte $7E ; |.XXXXXX.| .byte $06 ; |.....XX.| .byte $06 ; |.....XX.| .byte $3C ; |..XXXX..| .byte $06 ; |.....XX.| .byte $7E ; |.XXXXXX.| .byte $00 ; |........| .byte $00 ; |........| four .byte $06 ; |.....XX.| .byte $06 ; |.....XX.| .byte $7E ; |.XXXXXX.| .byte $66 ; |.XX..XX.| .byte $66 ; |.XX..XX.| .byte $66 ; |.XX..XX.| .byte $00 ; |........| .byte $00 ; |........| five .byte $7E ; |.XXXXXX.| .byte $66 ; |.XX..XX.| .byte $06 ; |.....XX.| .byte $7E ; |.XXXXXX.| .byte $60 ; |.XX.....| .byte $7E ; |.XXXXXX.| .byte $00 ; |........| .byte $00 ; |........| six .byte $7E ; |.XXXXXX.| .byte $66 ; |.XX..XX.| .byte $66 ; |.XX..XX.| .byte $7E ; |.XXXXXX.| .byte $60 ; |.XX.....| .byte $7E ; |.XXXXXX.| .byte $00 ; |........| .byte $00 ; |........| seven .byte $30 ; |..XX....| .byte $30 ; |..XX....| .byte $18 ; |...XX...| .byte $0C ; |....XX..| .byte $06 ; |.....XX.| .byte $7E ; |.XXXXXX.| .byte $00 ; |........| .byte $00 ; |........| eight .byte $7E ; |.XXXXXX.| .byte $66 ; |.XX..XX.| .byte $66 ; |.XX..XX.| .byte $3C ; |..XXXX..| .byte $66 ; |.XX..XX.| .byte $7E ; |.XXXXXX.| .byte $00 ; |........| .byte $00 ; |........| nine .byte $7E ; |.XXXXXX.| .byte $06 ; |.....XX.| .byte $7E ; |.XXXXXX.| .byte $66 ; |.XX..XX.| .byte $66 ; |.XX..XX.| .byte $7E ; |.XXXXXX.| .byte $00 ; |........| .byte $00 ; |........| Blank .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| Plus .byte $08 ; |....X...| .byte $08 ; |....X...| .byte $3E ; |..XXXXX.| .byte $08 ; |....X...| .byte $08 ; |....X...| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| LivesIndicator .byte $66 ; |.XX..XX.| .byte $24 ; |..X..X..| .byte $7E ; |.XXXXXX.| .byte $3C ; |..XXXX..| .byte $3C ; |..XXXX..| .byte $3C ; |..XXXX..| .byte $00 ; |........| .byte $00 ; |........| FILL_BOUNDARY [H_KERNEL + 16], -1 ThiefGraphicData .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| ThiefGraphics_00 .byte $00 ; |........| .byte $00 ; |........| .byte $66 ; |.XX..XX.| .byte $24 ; |..X..X..| .byte $FF ; |XXXXXXXX| .byte $3C ; |..XXXX..| .byte $3C ; |..XXXX..| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| ThiefGraphics_01 .byte $00 ; |........| .byte $00 ; |........| .byte $06 ; |.....XX.| .byte $64 ; |.XX..X..| .byte $FF ; |XXXXXXXX| .byte $3C ; |..XXXX..| .byte $3C ; |..XXXX..| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| ThiefGraphics_02 .byte $00 ; |........| .byte $00 ; |........| .byte $60 ; |.XX.....| .byte $26 ; |..X..XX.| .byte $FF ; |XXXXXXXX| .byte $3C ; |..XXXX..| .byte $3C ; |..XXXX..| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| BlankThiefGraphics .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| .byte $00 ; |........| FILL_BOUNDARY 506, - 1 echo "***", (FREE_BYTES)d, "BYTES OF ROM FREE" .word Start ; NMI vector .word Start ; RESET vector .word Start ; BRK vector