LIST OFF ; *** E . T. T H E E X T R A - T E R R E S T R I A L *** ; Copyright 1982 Atari, Inc. ; Designer: Howard Scott Warshaw ; Artist: Jerome Domurat ; Analyzed, labeled and commented ; by Dennis Debro ; Last Update: July 18, 2006 ; ; *** 116 BYTES OF RAM USED 12 BYTES FREE ; ; NTSC ROM usage stats ; ------------------------------------------- ; *** 25 BYTES OF ROM FREE IN BANK0 ; *** 24 BYTES OF ROM FREE IN BANK1 ; =========================================== ; *** 49 TOTAL BYTES FREE ; ; PAL ROM usage stats ; ------------------------------------------- ; *** 23 BYTES OF ROM FREE IN BANK0 ; *** 24 BYTES OF ROM FREE IN BANK1 ; =========================================== ; *** 47 TOTAL BYTES FREE ; This is Howard Scott Warshaw's third game with Atari. It was conceived and ; developed in roughly 5 weeks! The licensing deal didn't complete until the ; end of July (in an interview Howard says July 25). Atari wanted this game ; for the Christmas season which meant Howard had to finish this game by ; September 1st! ; ; - Pits are arranged in the order of... ; 1) ID_FOUR_DIAMOND_PITS ; 2) ID_EIGHT_PITS ; 3) ID_ARROW_PITS ; 4) ID_WIDE_DIAMOND_PITS ; - Objects are never placed in the overlapping pits for ID_EIGHT_PITS ; - Playfield is a 2LK while sprites are a 1LK ; - PAL conversion adjusts E.T. movement and colors ; - It seems RAM location $8B is not used processor 6502 ; ; NOTE: You must compile this with vcs.h version 105 or greater. ; TIA_BASE_READ_ADDRESS = $30 ; set the read address base so this runs on ; the real VCS and compiles to the exact ; ROM image include macro.h include vcs.h LIST ON ;============================================================================ ; A S S E M B L E R - S W I T C H E S ;============================================================================ NTSC = 0 PAL = 1 COMPILE_VERSION = NTSC ; change this to compile for different ; regions ;============================================================================ ; T I A - M U S I C C O N S T A N T S ;============================================================================ SOUND_CHANNEL_SAW = 1 ; sounds similar to a saw waveform SOUND_CHANNEL_ENGINE = 3 ; many games use this for an engine sound SOUND_CHANNEL_SQUARE = 4 ; a high pitched square waveform SOUND_CHANNEL_BASS = 6 ; fat bass sound SOUND_CHANNEL_PITFALL = 7 ; log sound in pitfall, low and buzzy SOUND_CHANNEL_NOISE = 8 ; white noise SOUND_CHANNEL_LEAD = 12 ; lower pitch square wave sound SOUND_CHANNEL_BUZZ = 15 ; atonal buzz, good for percussion LEAD_F4_SHARP = 13 LEAD_E4 = 15 LEAD_D4_SHARP = 16 LEAD_D4 = 17 LEAD_C4_SHARP = 18 LEAD_H3 = 20 LEAD_A3 = 23 LEAD_G3_SHARP = 24 LEAD_F3_SHARP = 27 LEAD_E3_2 = 31 ;============================================================================ ; T I A - C O N S T A N T S ;============================================================================ HMOVE_L7 = $70 HMOVE_L6 = $60 HMOVE_L5 = $50 HMOVE_L4 = $40 HMOVE_L3 = $30 HMOVE_L2 = $20 HMOVE_L1 = $10 HMOVE_0 = $00 HMOVE_R1 = $F0 HMOVE_R2 = $E0 HMOVE_R3 = $D0 HMOVE_R4 = $C0 HMOVE_R5 = $B0 HMOVE_R6 = $A0 HMOVE_R7 = $90 HMOVE_R8 = $80 ; values for ENAMx and ENABL DISABLE_BM = %00 ENABLE_BM = %10 ; values for RESMPx LOCK_MISSILE = %10 UNLOCK_MISSILE = %00 ; values for REFPx: NO_REFLECT = %0000 REFLECT = %1000 ; values for NUSIZx: ONE_COPY = %000 TWO_COPIES = %001 TWO_MED_COPIES = %010 THREE_COPIES = %011 TWO_WIDE_COPIES = %100 DOUBLE_SIZE = %101 THREE_MED_COPIES = %110 QUAD_SIZE = %111 MSBL_SIZE1 = %000000 MSBL_SIZE2 = %010000 MSBL_SIZE4 = %100000 MSBL_SIZE8 = %110000 ; values for CTRLPF: PF_PRIORITY = %100 PF_SCORE = %10 PF_REFLECT = %01 PF_NO_REFLECT = %00 ; values for SWCHB P1_DIFF_MASK = %10000000 P0_DIFF_MASK = %01000000 BW_MASK = %00001000 SELECT_MASK = %00000010 RESET_MASK = %00000001 VERTICAL_DELAY = 1 ; SWCHA joystick bits: MOVE_RIGHT = %01111111 MOVE_LEFT = %10111111 MOVE_DOWN = %11011111 MOVE_UP = %11101111 P0_NO_MOVE = %11110000 P1_NO_MOVE = %00001111 NO_MOVE = P0_NO_MOVE | P1_NO_MOVE ; values for VBLANK: DUMP_PORTS = %10000000 ENABLE_LATCHES = %01000000 DISABLE_TIA = %00000010 ENABLE_TIA = %00000000 ;values for VSYNC: START_VERT_SYNC = %10 STOP_VERT_SYNC = %00 ;============================================================================ ; U S E R - C O N S T A N T S ;============================================================================ BANK0TOP = $1000 BANK1TOP = $2000 BANK0_REORG = $B000 BANK1_REORG = $F000 BANK0STROBE = $FFF8 BANK1STROBE = $FFF9 NTSC_OVERSCAN_TIME = 45 NTSC_VBLANK_TIME = 47 PAL_VBLANK_TIME = 78 PAL_OVERSCAN_TIME = 72 IF COMPILE_VERSION = NTSC VBLANK_TIME = NTSC_VBLANK_TIME OVERSCAN_TIME = NTSC_OVERSCAN_TIME ; NTSC color constants BLACK = $00 WHITE = $0E LT_RED = $20 RED = $30 ORANGE = $40 ORANGE_2 = ORANGE RED_2 = ORANGE DK_PINK = $50 DK_BLUE = $70 BLUE = $80 LT_BLUE = $90 GREEN = $C0 GREEN_2 = GREEN DK_GREEN = $D0 DK_GREEN_2 = DK_GREEN LT_BROWN = $E0 LT_BROWN_2 = LT_BROWN BROWN = $F0 NTSC_BROWN = BROWN START_LANDING_TIMER = 63 ; staring value for landing timer FRAME_DELAY_ONE_HALF = $81 ; move 1 out of 2 frames FRAME_DELAY_ONE_THIRD = $5D ; move 1 out of 3 frames FRAME_DELAY_ONE_FORTH = $3F ; move 1 out of 4 frames FRAME_DELAY_ONE_FIFTH = $3B ; move 1 out of 5 frames ELSE VBLANK_TIME = PAL_VBLANK_TIME OVERSCAN_TIME = PAL_OVERSCAN_TIME ; PAL color constants BLACK = $00 WHITE = $0E LT_RED = $20 LT_BROWN_2 = LT_RED BROWN = LT_RED GREEN_2 = $30 RED = $40 RED_2 = RED + 2 ORANGE = RED LT_BROWN = $50 DK_GREEN = LT_BROWN ORANGE_2 = $62 DK_BLUE = $70 DK_PINK = $80 LT_BLUE = $90 BLUE = $D0 DK_GREEN_2 = BLUE GREEN = $E0 NTSC_BROWN = $F0 START_LANDING_TIMER = 57 ; staring value for landing timer FRAME_DELAY_ONE_HALF = $9A ; move 1 out of 2 frames FRAME_DELAY_ONE_THIRD = $6F ; move 1 out of 3 frames FRAME_DELAY_ONE_FORTH = $4B ; move 1 out of 4 frames FRAME_DELAY_ONE_FIFTH = $46 ; move 1 out of 5 frames ENDIF LDA_ABS = $AD ; instruction to LDA $XXXX JMP_ABS = $4C ; instruction for JMP $XXXX XMIN = 0 XMAX = 119 ET_YMIN = 0 ET_YMAX = 58 OBJECT_IN_PIT_Y = 50 OBJECT_IN_PIT_X = 41 PIT_XMIN = 32 PIT_XMAX = 88 FBI_AGENT_VERT_MAX = 48 ELLIOTT_VERT_MAX = 52 SCIENTIST_VERT_MAX = 48 FBI_AGENT_VERT_TARGET = 15 ELLIOTT_VERT_TARGET = 47 SCIENTIST_VERT_TARGET = 15 FBI_AGENT_HORIZ_TARGET = 28 ELLIOTT_HORIZ_TARGET = 60 SCIENTIST_HORIZ_TARGET = 94 H_ET_GRAPH = 40 ; height of E.T. face for title screen H_FONT = 8 H_FBIAGENT = 28 H_ELLIOTT = 22 H_SCIENTIST = 28 H_PHONE_PIECES = 10 H_FLOWER = 14 H_MOTHERSHIP = 32 H_YAR = 16 H_INDY = 20 MAX_GAME_SELECTION = 3 MAX_ENERGY = $99 ; maximum energy value (BCD) MAX_HOLD_CANDY = 9 << 4 INIT_NUM_TRIES = 3 ; initial number of tries to get E.T. home NUM_PHONE_PIECES = 3 ; screen id values ID_FOUR_DIAMOND_PITS = 0 ID_EIGHT_PITS = 1 ID_ARROW_PITS = 2 ID_WIDE_DIAMOND_PITS = 3 ID_FOREST = 4 ID_WASHINGTON_DC = 5 ID_PIT = 6 ID_ET_HOME = 7 ID_TITLE_SCREEN = 8 ; pit id values ID_PIT_OUT_OF_RANGE = -1 ID_TOP_DIAMOND_PIT = 0 ID_LEFT_DIAMOND_PIT = 1 ID_RIGHT_DIAMOND_PIT = 2 ID_LOWER_DIAMOND_PIT = 3 ID_TOP_EIGHT_PITS = 4 ID_LEFT_EIGHT_PITS = 5 ID_RIGHT_EIGHT_PIT = 6 ID_BOTTOM_EIGHT_PIT = 7 ID_TOP_LEFT_ARROW_PIT = 8 ID_TOP_RIGHT_ARROW_PIT = 9 ID_LOWER_LEFT_ARROW_PIT = 10 ID_LOWER_RIGHT_ARROW_PIT = 11 ID_UPPER_LEFT_WIDE_PIT = 12 ID_UPPER_RIGHT_WIDE_PIT = 13 ID_LOWER_LEFT_WIDE_PIT = 14 ID_LOWER_RIGHT_WIDE_PIT = 15 ; object ids ID_FBIAGENT = 0 ID_ELLIOTT = 1 ID_SCIENTIST = 2 ID_H_PHONE_PIECE = 3 ID_S_PHONE_PIECE = 4 ID_W_PHONE_PIECE = 5 ID_FLOWER = 6 ID_MOTHERSHIP = 7 ID_YAR_0 = 8 ID_YAR_1 = 9 ID_INDY = 10 ; power zone indicator ids ID_BLANK_ZONE = 0 ID_WARP_LEFT_ZONE = 1 ID_WARP_RIGHT_ZONE = 2 ID_WARP_UP_ZONE = 3 ID_WARP_DOWN_ZONE = 4 ID_FIND_PHONE_ZONE = 5 ID_EAT_CANDY_ZONE = 6 ID_RETURN_HOME_ZONE = 7 ID_CALL_ELLIOTT_ZONE = 8 ID_CALL_SHIP_ZONE = 9 ID_LANDING_ZONE = 10 ID_PIT_ZONE = 11 ID_FLOWER_ZONE = 12 ; candy status values FOUR_DIAMOND_PITS_CANDY = %0001 EIGHT_PITS_CANDY = %0010 ARROW_PITS_CANDY = %0100 WIDE_DIAMOND_PITS_CANDY = %1000 SHOW_HSW_INITIALS_VALUE = $69 ; BCD value :-) ; player state values ET_DEAD = %10000000 ELLIOTT_REVIVE_ET = %01000000 ; E.T. home Elliott movement values MOVE_ELLIOTT_RIGHT = %10000000 ; collected candy scoring values COLLECT_CANDY_SCORE_INC = %01000000 CLOSED_EATING_CANDY_ICON = %00000001 ; E.T. motion values ET_RUNNING = %10000000 ET_CARRIED_BY_SCIENTIST = %01000000 ET_MOTION_MASK = %00001111 ; human attribute values RETURN_HOME = %10000000 MOTION_MASK = %00001111 ; fireResetStatus values FIRE_BUTTON_HELD = %10000000 RESET_SWITCH_HELD = %01000000 ; starting screen id values SET_STARTING_SCREEN = %10000000 STARTING_SCREEN_ID = %00001111 ; phone piece attribute values ET_HAS_PHONE_PIECE = %10000000 PHONE_PIECE_SCREEN_LOC = %01000000 FBI_HAS_PHONE_PIECE = %00100000 ELLIOTT_HAS_PHONE_PIECE = %00010000 PHONE_PIECE_PIT_NUMBER = %00001111 ; neck extension values NECK_EXTENDED = %10000000 NECK_DECENDING = %01000000 ; flower state values FLOWER_REVIVED = %10000000 FLOWER_REVIVE_ANIMATION = %00110000 FLOWER_PIT_NUMBER = %00001111 ; E.T. pit status values FALLING_IN_PIT = %10000000 LEVITATING = %01000000 IN_PIT_BOTTOM = %00100000 ; mothership status values MOTHERSHIP_PRESENT = %10000000 ET_GOING_HOME = %01000000 MOTHERSHIP_LEAVING = %00000001 ; Easter Egg sprite values SHOW_YAR_SPRITE = %10000000 SHOW_INDY_SPRITE = %11000000 ; sound data channel 0 values PLAY_SOUND_CHANNEL0 = %10000000 ; Easter Egg status values DONE_EASTER_EGG_CHECK = %10000000 DONE_EASTER_EGG_STEPS = %00000111 ;============================================================================ ; Z P - V A R I A B L E S ;============================================================================ currentScreenId = $80 frameCount = $81 secondTimer = $82 ; updates ~every second temp = $83 ;-------------------------------------- tempNumberFonts = temp ;-------------------------------------- powerZoneIndex = temp ;-------------------------------------- loopCount = temp ;-------------------------------------- tempJoystickValues = temp ;-------------------------------------- humanETHorizDistRange = temp ;-------------------------------------- pointsTensValue = temp ;-------------------------------------- pointsHundredsValue = temp ;-------------------------------------- energyIncTensValue = temp ;-------------------------------------- energyIncHundredsValue = temp ;-------------------------------------- humanDirectionIndex = temp ;-------------------------------------- newHumanDirection = temp ;-------------------------------------- totalCandyCollected = temp ;-------------------------------------- tempPitNumber = temp tempCharHolder = $84 nextETGraphicData = $86 ;-------------------------------------- energyDecTensValue = nextETGraphicData ;-------------------------------------- energyDecHundredsValue = energyDecTensValue nextObjectGraphicData = $87 nextObjectColorData = $88 ;-------------------------------------- displayKernelBankSwitch = loopCount bankSwitchStrobe = displayKernelBankSwitch+1 bankSwitchABSJmp = bankSwitchStrobe+2 bankSwitchRoutinePtr = bankSwitchABSJmp+1 fireResetStatus = $89 ; hold when fire button and RESET held soundDataChannel0 = $8A unknown = $8B currentSpriteHeight = $8C etHeight = $8D powerZoneColor = $8E timerColor = $8F telephoneColor = $90 etMotionValues = $91 etFractionalDelay = $92 humanFractionalDelay = $93 etNeckExtensionValues = $94 currentObjectHorizPos = $95 etHorizPos = $96 etHeartHorizPos = $97 phonePieceMapHorizPos = $98 candyHorizPos = $99 humanTargetHorizPos = $9A currentObjectVertPos = $9B etVertPos = $9C etHeartVertPos = $9D phonePieceMapVertPos = $9E candyVertPos = $9F humanTargetVertPos = $A0 currentObjectId = $A1 humanAttributes = $A2 ; $A2 - $A4 ;-------------------------------------- fbiAttributes = humanAttributes elliottAttributes = fbiAttributes+1 scientistAttributes = elliottAttributes+1 objectScreenId = $A5 ; $A5 - $A7 ;-------------------------------------- fbiScreenId = objectScreenId elliottScreenId = fbiScreenId+1 scientistScreenId = elliottScreenId+1 objectHorizPos = $A8 ; $A8 - $B1 ;-------------------------------------- fbiAgentHorizPos = objectHorizPos elliottHorizPos = fbiAgentHorizPos+1 scientistHorizPos = elliottHorizPos+1 objectVertPos = $AB ; $AB - $AD ;-------------------------------------- fbiAgentVertPos = objectVertPos elliottVertPos = fbiAgentVertPos+1 scientistVertPos = elliottVertPos+1 objectGraphicPointers = $AE ; $AE - $B1 ;-------------------------------------- objectGraphicPtrs_0 = objectGraphicPointers objectGraphicPtrs_1 = objectGraphicPtrs_0+2 objectColorPointers = $B2 ; $B2 - $B5 ;-------------------------------------- objectColorPtrs_0 = objectColorPointers objectColorPtrs_1 = objectColorPtrs_0+2 etGraphicsPointers = $B6 ; $B6 - $B9 ;-------------------------------------- etGraphicPointers0 = etGraphicsPointers; $B6 - $B7 etGraphicPointers1 = etGraphicPointers0+2; $B8 - $B9 playfieldGraphicPtrs = $BA ; $BA - $BD ;-------------------------------------- pf1GraphicPtrs = playfieldGraphicPtrs pf2GraphicPtrs = pf1GraphicPtrs+2 graphicPointers = $BE ; $BE - $C9 phonePieceAttributes = $CA ; $CA - $CC ;-------------------------------------- h_phonePieceAttribute = phonePieceAttributes s_phonePieceAttribute = h_phonePieceAttribute+1 w_phonePieceAttribute = s_phonePieceAttribute+1 powerZonePointer = $CD ; $CD - $CE powerZoneIndicatorId = $CF shipLandingTimer = $D0 candyStatus = $D1 heldCandyPieces = $D2 etEnergy = $D3 ; $D3 - $D4 etHMOVEValue = $D5 holdETHorizPos = $D6 holdETVertPos = $D7 holdETScreenId = $D8 etPitStatus = $D9 currentPitNumber = $DA callHomeScreenId = $DB extraCandyPieces = $DC collectedCandyPieces = $DD collectedCandyScoring = $DE playerScore = $DF ; $DF - $E1 startingScreenId = $E2 playerState = $E3 gameState = $E4 numberOfTries = $E5 flowerState = $E6 powerZoneLSBValues = $E7 ; $E7 - $E9 ;-------------------------------------- powerZoneLSBValue_01 = powerZoneLSBValues powerZoneLSBValue_02 = powerZoneLSBValue_01+1 powerZoneLSBValue_03 = powerZoneLSBValue_02+1 gameSelection = $EA mothershipStatus = $EB etAnimationIndex = $EC etHomeElliottMovement = $ED themeMusicNoteDelay = $EE themeMusicFreqIndex = $EF easterEggStatus = $F0 programmerInitialFlag = $F1 easterEggSpriteFlag = $F2 artistInitialFlag = $F3 ;============================================================================ ; R O M - C O D E (BANK 0) ;============================================================================ SEG Bank0 .org BANK0TOP .rorg BANK0_REORG lda BANK0STROBE jmp Start HorizPositionObjects ldx #> 4) sta elliottAttributes ; set Elliott attributes to move up lda currentScreenId ; get the current screen id sta elliottScreenId ; place Elliott on the current screen lda #5 sta elliottHorizPos sta elliottVertPos .checkETNeckExtension bit etNeckExtensionValues ; check neck extension value bpl CheckETPlayerCollisions ; branch if E.T. neck not extended .jmpToCheckForETOnPitScreen jmp CheckIfETOnPitScreen CheckETPlayerCollisions bit CXPPMM ; check player to player collisions bpl .jmpToCheckForETOnPitScreen ; branch if E.T. not collided with object ldx currentObjectId ; get the current object id bpl .checkCollisionObjectNotInWell; branch if object not in a well jmp .checkCollisionObjectInWell .checkCollisionObjectNotInWell lda humanAttributes,x ; get the human attribute value bmi .jmpToCheckForETOnPitScreen ; branch if returning home txa ; move current object id to accumulator bne .checkForScientistCollision ; branch if not FBI Agent ldx #NUM_PHONE_PIECES - 1 .checkToTakePhoneOrCandy lda phonePieceAttributes,x ; get phone piece attribute value bmi .fbiTakePhonePieceFromET ; branch if E.T. took phone piece dex bpl .checkToTakePhoneOrCandy lda #$0A sta heldCandyPieces ; clear carried candy from E.T. bne .setForFBITakingObjectSound ; unconditional branch .fbiTakePhonePieceFromET lda frameCount ; get the current frame count and #PHONE_PIECE_PIT_NUMBER ora #FBI_HAS_PHONE_PIECE sta phonePieceAttributes,x ; set new location for phone piece .setForFBITakingObjectSound lda #PLAY_SOUND_CHANNEL0 | $1C sta soundDataChannel0 jmp .setHumanToReturnHome .checkForScientistCollision cpx #ID_SCIENTIST bne .etCollidedWithElliott ; branch if not collided with Scientist lda etMotionValues ; get E.T. motion values ora #ET_CARRIED_BY_SCIENTIST ; set E.T. motion value to show E.T. sta etMotionValues ; carried by Scientist rol fbiAttributes ; set FBI Agent to return home sec ror fbiAttributes rol elliottAttributes ; set Elliott to return home sec ror elliottAttributes bne .setHumanToReturnHome ; unconditional branch .etCollidedWithElliott lda #PLAY_SOUND_CHANNEL0 | $0C sta soundDataChannel0 bit playerState ; check the player state bpl .checkItemExchange ; branch if E.T. is not dead ldy numberOfTries ; get number of tries bpl .reviveET ; revive E.T. for another try rol gameState ; rotate game state left sec ; set carry and rotate value right to set ror gameState ; game loss state (i.e. D7 = 1) jsr SetCurrentScreenToETHome jmp VerticalSync .reviveET dec numberOfTries ; reduce number of tries ldx #$15 ldy #$00 jsr IncrementETEnergy ; give E.T. 1500 units of energy sty currentSpriteHeight sty playerState ; reset player state dey ; y = -1 sty currentObjectId sty elliottScreenId sty elliottAttributes bne .setHumanToReturnHome ; unconditional branch .checkItemExchange ldx #0 lda #ELLIOTT_HAS_PHONE_PIECE bit h_phonePieceAttribute bne .giveElliottPhonePieceToET ; branch if Elliott has H phone piece inx bit s_phonePieceAttribute bne .giveElliottPhonePieceToET ; branch if Elliott has S phone piece inx bit w_phonePieceAttribute beq .giveCandyPiecesToElliott ; branch if Elliott has no phone pieces .giveElliottPhonePieceToET lda #ET_HAS_PHONE_PIECE sta phonePieceAttributes,x bne .setHumanToReturnHome ; unconditional branch .giveCandyPiecesToElliott lda heldCandyPieces ; get number of candy pieces held by E.T. lsr ; shift upper nybbles to lower nybbles lsr lsr lsr beq .setHumanToReturnHome ; branch if no candy pieces collected clc adc collectedCandyPieces ; increment collected candy pieces sta collectedCandyPieces lda heldCandyPieces ; get number of candy pieces held by E.T. cmp #MAX_HOLD_CANDY ; see if E.T. is holding maximum candy bcc .clearNumberHeldCandyPieces ; clear held candy count if not ldx #NUM_PHONE_PIECES - 1 lda #$F0 bit w_phonePieceAttribute beq .givePhonePieceToElliott dex bit s_phonePieceAttribute beq .givePhonePieceToElliott dex bit h_phonePieceAttribute bne .clearNumberHeldCandyPieces .givePhonePieceToElliott lda #ELLIOTT_HAS_PHONE_PIECE sta phonePieceAttributes,x .clearNumberHeldCandyPieces lda heldCandyPieces ; get number of candy pieces held by E.T. and #$0F ; mask to clear number of candy held sta heldCandyPieces .setHumanToReturnHome ldx currentObjectId ; get the current object id rol humanAttributes,x ; shift human attribute left sec ; set carry and shift value right to set ror humanAttributes,x ; RETURN_HOME flag (i.e. D7 = 1) bmi CheckIfETOnPitScreen ; unconditional branch .checkCollisionObjectInWell cpx #$80 | ID_FLOWER bcs CheckIfETOnPitScreen ; branch if E.T. didn't pick up phone piece lda #PLAY_SOUND_CHANNEL0 | $0D sta soundDataChannel0 txa ; move current object id to accumulator and #$0F ; mask pit value to keep object id sec sbc #3 ; subtract value by 3 tax cmp #3 bcs CheckIfETOnPitScreen ; branch if E.T. didn't pick up phone piece lda #ET_HAS_PHONE_PIECE sta phonePieceAttributes,x asl ; a = 0 sta currentSpriteHeight CheckIfETOnPitScreen lda currentScreenId ; get the current screen id cmp #ID_FOREST bcc CheckETPitCollisions ; branch if E.T. on a pit screen .jmpToDetermineHumanDirection jmp DetermineHumanDirection CheckETPitCollisions bit etMotionValues ; check E.T. motion values bvs .jmpToDetermineHumanDirection; branch if E.T. carried by Scientist bit CXP1FB ; check E.T. and playfield collision bmi PlaceETInPit ; branch if E.T. collided with pit lda #0 sta etPitStatus ; clear E.T. pit status flags beq .jmpToDetermineHumanDirection; unconditional branch PlaceETInPit bit etNeckExtensionValues ; check neck extension value bmi .jmpToDetermineHumanDirection; branch if E.T. neck extended lda etVertPos ; get E.T.'s vertical position sta holdETVertPos ; save for when E.T. emerges from pit lda etHorizPos ; get E.T.'s horizontal position sta holdETHorizPos ; save for when E.T. emerges from pit ldy #0 ldx currentScreenId ; get the current screen id stx holdETScreenId ; save for when E.T. emerges from pit beq SetPitNumberForDiamondPits ; branch if FOUR_DIAMOND_PITS dex beq SetPitNumberForEightPits ; branch if EIGHT_PITS dex beq SetPitNumberForArrowPits ; branch if ARROW_PITS ldx #ID_UPPER_LEFT_WIDE_PIT bne CalculateCurrentPitNumber ; unconditional branch -- WIDE_DIAMOND_PITS SetPitNumberForArrowPits ldx #ID_TOP_LEFT_ARROW_PIT CalculateCurrentPitNumber stx tempPitNumber cmp #59 ; compare E.T.'s horizontal position bcc .compareETVerticalPosition iny ; y = 1 .compareETVerticalPosition lda etVertPos ; get E.T.'s vertical position cmp #33 bcc .combineTempPitNumber iny iny .combineTempPitNumber tya ora tempPitNumber bne .setCurrentPitNumber ; unconditional branch SetPitNumberForDiamondPits cmp #41 ; compare E.T.'s horizontal position bcs .etNotInPitOne lda #ID_LEFT_DIAMOND_PIT ; show that E.T. is in pit number 1 bne .setCurrentPitNumber ; unconditional branch .etNotInPitOne cmp #81 ; compare E.T.'s horizontal position bcc .etNotInPitTwo lda #ID_RIGHT_DIAMOND_PIT ; show that E.T. is in pit number 2 bne .setCurrentPitNumber ; unconditional branch .etNotInPitTwo lda etVertPos ; get E.T.'s vertical position cmp #29 lda #ID_TOP_DIAMOND_PIT bcc .setCurrentPitNumber ; set E.T. to pit number 0 lda #ID_LOWER_DIAMOND_PIT ; show that E.T. is in pit number 3 bne .setCurrentPitNumber ; unconditional branch SetPitNumberForEightPits ldx etVertPos ; get E.T.'s vertical position cpx #19 bcc .checkForOutOfRangePit cpx #40 bcc .checkHorizPosForPitNumber ldy #3 .checkForOutOfRangePit cmp #32 ; compare E.T.'s horizontal position bcc .setToOutOfRangePitNumber cmp #96 ; compare E.T.'s horizontal position bcs .setToOutOfRangePitNumber .combineIndexForPitNumber tya ora #ID_TOP_EIGHT_PITS bne .setCurrentPitNumber ; unconditional branch .setToOutOfRangePitNumber lda #> 4) sta humanAttributes,x ; set human to move left lda #ID_WASHINGTON_DC cmp currentScreenId bne CheckForETCollectingCandy stx currentObjectId jsr SetCurrentObjectData jmp CheckForETCollectingCandy .multiplyScreenIdBy8 asl asl asl sta humanDirectionIndex lda humanAttributes,x ; get human attribute value bpl .checkToChangeHumanDirection ; branch if not returning home lda #5 clc bcc .setNewHumanDirection ; unconditional branch .checkToChangeHumanDirection lda currentScreenId ; get the current screen id cmp #ID_PIT ; if on PIT or HOME or TITLE SCREEN then bcs CheckForETCollectingCandy ; don't change human direction .setNewHumanDirection adc humanDirectionIndex tay lda HumanDirectionTable,y bmi CheckForETCollectingCandy sta newHumanDirection lda humanAttributes,x ; get human attribute value and #$F0 ; clear current human direction ora newHumanDirection ; or in new direction value sta humanAttributes,x ; set new direction value CheckForETCollectingCandy bit CXP1FB ; check E.T. collision with PF and BALL bvc .skipCandyCollection ; branch if E.T. did not collect candy ldx currentScreenId ; get the current screen id cpx #ID_FOREST bcs .skipCandyCollection ; branch if E.T. not on a pit screen lda heldCandyPieces ; get number of candy pieces held by E.T. cmp #MAX_HOLD_CANDY bcs .skipCandyCollection ; branch if E.T. holding maximum candy adc #1 * 16 ; increment held candy pieces by 1 sta heldCandyPieces lda #PLAY_SOUND_CHANNEL0 | $1C sta soundDataChannel0 lda #127 ; set candy piece vertical position to be sta candyVertPos ; out of visual range lda CandyStatusMaskTable,x and candyStatus sta candyStatus .skipCandyCollection lda secondTimer and #$0F bne CheckForETNeckExtension lda frameCount ; get the current frame count and #$3F cmp #23 bne CheckForETNeckExtension lda candyStatus ; get candy status flag value and #$0F tax lda extraCandyPieces ; get extra candy pieces value sec sbc ExtraCandyReductionTable,x bmi CheckForETNeckExtension sta extraCandyPieces lda #$0F ora candyStatus sta candyStatus CheckForETNeckExtension bit etNeckExtensionValues ; check neck extension value bmi .etNeckExtended ; branch if E.T. neck extended jmp DeterminePitPowerZone .etNeckExtended lda frameCount ; get the current frame count and #3 bne .jmpToSetPhoneHiddenLocation bvc ExtendedETNeck ; branch if extending E.T. neck bit etPitStatus ; check E.T. pit status flags bvs .jmpToSetPhoneHiddenLocation ; branch if E.T. levitating dec etNeckExtensionValues lda etNeckExtensionValues and #7 cmp #7 beq .reduceETNeckExtension inc etVertPos ; move E.T. down 1 pixel bne .jmpToSetPhoneHiddenLocation ; unconditional branch .reduceETNeckExtension lda #$00 sta etNeckExtensionValues ; clear neck extension value inc etVertPos ; move E.T. down 1 pixel ldx #NUM_PHONE_PIECES - 1 .clearHiddenPhonePieceLoc lda phonePieceAttributes,x ; get phone piece attribute value and #<(~PHONE_PIECE_SCREEN_LOC) ; clear phone piece screen location bit to sta phonePieceAttributes,x ; show phone not hidden (i.e. E.T. in pit) dex bpl .clearHiddenPhonePieceLoc .jmpToSetPhoneHiddenLocation jmp SetPhonePieceHiddenLocation ExtendedETNeck SUBROUTINE inc etNeckExtensionValues lda etNeckExtensionValues and #7 cmp #4 bcs ETNeckExtendedToMax lda etVertPos ; get E.T.'s vertical position beq .jmpToSetPhoneHiddenLocation ; branch if E.T. out of the pit dec etVertPos ; move E.T. up 1 pixel .jmpToSetPhoneHiddenLocation jmp SetPhonePieceHiddenLocation ETNeckExtendedToMax lda #NECK_EXTENDED | NECK_DECENDING | 3 sta etNeckExtensionValues ; set E.T. neck to decend ldx #$00 ldy #$19 jsr DecrementETEnergy ; reduce E.T. energy by 19 units ldy currentScreenId ; get the current screen id lda powerZoneIndicatorId ; get the power zone id asl ; multiply value by 2 tax lda PowerZoneJumpTable+1,x pha lda PowerZoneJumpTable,x pha lda gameSelection ; get the current game selection cmp #2 bcs .jumpToPowerZone lda scientistScreenId ; get the Scientist's screen id bpl .jumpToPowerZone ; branch if Scientist not at home rol scientistAttributes ; rotate Scientist attribute left and clc ; clear carry and rotate right to clear ror scientistAttributes ; RETURN_HOME flag (i.e. D7 = 0) .jumpToPowerZone rts ReviveFlower bit flowerState ; check the flower state bmi .setPhonePieceHiddenLocation ; branch if flower already revived inc numberOfTries ; increment number of tries rol flowerState ; rotate flower state left sec ; set carry flag and rotate flower state ror flowerState ; right to set FLOWER_REVIVED state bmi .setPhonePieceHiddenLocation ; unconditional branch LevitateETOutOfPit lda #LEVITATING sta etPitStatus ; set status to show E.T. levitating dec etVertPos ; move E.T. up two pixels dec etVertPos .setPhonePieceHiddenLocation jmp SetPhonePieceHiddenLocation DetermineHiddenPhonePiece ldx #NUM_PHONE_PIECES - 1 .hiddenPhonePieceLoop lda phonePieceAttributes,x ; get phone piece attribute value and #<(~PHONE_PIECE_PIT_NUMBER) ; mask PHONE_PIECE_PIT_NUMBER value bne .nextPhonePiece ; branch if phone piece not hidden lda phonePieceAttributes,x ; get phone piece attribute value and #PHONE_PIECE_PIT_NUMBER ; keep PHONE_PIECE_PIT_NUMBER value lsr ; divide pit number value by 4 lsr cmp currentScreenId ; compare with current screen id value beq .setPhoneHiddenOnScreen ; branch if phone piece hidden on screen .nextPhonePiece dex bpl .hiddenPhonePieceLoop .setHiddenPhonePieceLocation jmp SetPhonePieceHiddenLocation .setPhoneHiddenOnScreen lda phonePieceAttributes,x ; get phone piece attribute value ora #PHONE_PIECE_SCREEN_LOC ; set value to show phone hidden on screen sta phonePieceAttributes,x bne .setHiddenPhonePieceLocation ; unconditional branch WarpETRight lda RightScreenIdTable,y jmp .warpETToNewScreen WarpETLeft lda LeftScreenIdTable,y jmp .warpETToNewScreen WarpETUp lda UpperScreenIdTable,y jmp .warpETToNewScreen WarpETDown lda LowerScreenIdTable,y .warpETToNewScreen sta currentScreenId ; set the current screen id jsr SetCurrentScreenData jmp SetPhonePieceHiddenLocation ClearElliottReturnHomeFlag rol elliottAttributes ; rotate Elliott attributes left clc ; clear carry and rotate Elliott attributes ror elliottAttributes ; right to clear RETURN_HOME flag bpl SetPhonePieceHiddenLocation ; unconditional branch CallMothership ldx currentObjectId ; get the current object id bmi .checkToStartShipLandingTimer; branch if current object returning home bit SWCHB ; check console switch values bvs SetPhonePieceHiddenLocation ; branch if player 1 difficulty set to PRO cpx #ID_ELLIOTT bne SetPhonePieceHiddenLocation ; branch if current object is not Elliott .checkToStartShipLandingTimer lda shipLandingTimer ; get timer value for ship landing bpl SetPhonePieceHiddenLocation ; branch if landing timer already started bit h_phonePieceAttribute ; check H phone piece value bpl SetPhonePieceHiddenLocation ; branch if E.T. not taken H phone piece bit s_phonePieceAttribute ; check S phone piece value bpl SetPhonePieceHiddenLocation ; branch if E.T. not taken S phone piece bit w_phonePieceAttribute ; check W phone piece value bpl SetPhonePieceHiddenLocation ; branch if E.T. not taken W phone piece lda #PLAY_SOUND_CHANNEL0 | $0C sta soundDataChannel0 lda #START_LANDING_TIMER sta shipLandingTimer ; set ship landing timer value lda #RETURN_HOME | P1_NO_MOVE sta fbiAttributes ; set all human objects to return home and sta elliottAttributes ; don't move sta scientistAttributes bne SetPhonePieceHiddenLocation ; unconditional branch ReturnCurrentHumanHome ldx currentObjectId ; get the current object id bmi SetPhonePieceHiddenLocation ; branch if human set to return home rol humanAttributes,x ; rotate human attribute value left sec ; set carry and rotate value right to set ror humanAttributes,x ; RETURN_HOME flag (i.e. D7 = 1) bmi SetPhonePieceHiddenLocation ; unconditional branch EatCandyPiece lda heldCandyPieces ; get number of candy pieces held by E.T. sec sbc #1 * 16 ; reduce number of candy pieces held by 1 bcc SetPhonePieceHiddenLocation sta heldCandyPieces ldx #$03 ldy #$60 jsr IncrementETEnergy ; increment energy by 360 units SetPhonePieceHiddenLocation ldx #NUM_PHONE_PIECES - 1 bit w_phonePieceAttribute ; check W phone piece value bvs .setHiddenPhonePiecePosition ; branch if W phone piece present on screen dex bit s_phonePieceAttribute ; check S phone piece bvs .setHiddenPhonePiecePosition ; branch if S phone piece present on screen dex bit h_phonePieceAttribute ; check H phone piece bvc .turnOffHiddentPhonePiece ; branch if H phone piece not on screen .setHiddenPhonePiecePosition lda phonePieceAttributes,x ; get the phone piece attribute value and #PHONE_PIECE_PIT_NUMBER ; mask bits to keep pit number tay lda PhonePiecePitHorizPosition,y ; get phone piece pit horizontal position sta phonePieceMapHorizPos ldx PhonePiecePitVertPosition,y ; get phone piece pit vertical position lda frameCount ; get the current frame count ror ; move D2 of frame count to carry ror ; flash hidden phone piece every 8 frames ror bcc .setHiddenPhonePieceVertPos .turnOffHiddentPhonePiece ldx #127 .setHiddenPhonePieceVertPos stx phonePieceMapVertPos lda powerZoneIndicatorId ; get current power zone id jmp .setPowerZoneGraphicPtrLSB DeterminePitPowerZone lda currentScreenId ; get the current screen id cmp #ID_PIT bne DetermineCurrentPowerZone ; branch if E.T. not in pit lda currentObjectId ; get the current object id cmp #$80 | ID_FLOWER bne .setPowerZoneToPitZone ; branch if the flower not present lda etHorizPos ; get E.T.'s horizontal position sbc currentObjectHorizPos ; subtract flower horizontal position cmp #16 bcs .setPowerZoneToPitZone lda #ID_FLOWER_ZONE bne .setPowerZoneIndicatorId ; set power zone to flower zone .setPowerZoneToPitZone lda #ID_PIT_ZONE bne .setPowerZoneIndicatorId ; unconditional branch DetermineCurrentPowerZone lda etHorizPos ; get E.T.'s horizontal position lsr ; divide horizontal value by 8 lsr lsr and #$0C ; a = 0 || a = 4 || a = 8 || a = 12 sta powerZoneIndex lda etVertPos ; get E.T.'s vertical position lsr ; divide vertical value by 16 (i.e. move lsr ; upper nybble to lower nybble) lsr lsr ora powerZoneIndex ; increase value for index pointer lsr ; divide value by 2 (i.e. 0 <= x <= 7) tay lda (powerZonePointer),y bcc .checkForValidFindPhoneZone ; branch if index value was even lsr ; shift upper nybble to lower nybble lsr lsr lsr .checkForValidFindPhoneZone and #$0F cmp #ID_FIND_PHONE_ZONE bne .checkForValidCallElliottZone ldx currentScreenId ; get the current screen id cpx #ID_FOREST bcs .setPowerZoneToBlankZone ; set power zone to blank if in forest .checkForValidCallElliottZone cmp #ID_CALL_ELLIOTT_ZONE bne .checkForValidLandingZone ldx #ID_FOREST cpx currentScreenId beq .setPowerZoneToBlankZone ; set power zone to blank if in forest .checkForValidLandingZone cmp #ID_LANDING_ZONE bne .checkForValidCallShipZone ldx #ID_FOREST cpx currentScreenId bne .setPowerZoneToBlankZone ; set power zone to blank if not in forest .checkForValidCallShipZone cmp #ID_CALL_SHIP_ZONE bne .setPowerZoneIndicatorId ldx callHomeScreenId cpx currentScreenId beq .setPowerZoneIndicatorId ; set power zone if on call home screen .setPowerZoneToBlankZone lda #ID_BLANK_ZONE .setPowerZoneIndicatorId sta powerZoneIndicatorId .setPowerZoneGraphicPtrLSB asl ; multiply power zone indicator value by 8 asl ; (height of Power Zone sprites) to set asl ; graphic pointer LSB sta graphicPointers VerticalSync SUBROUTINE .waitTime lda INTIM bne .waitTime StartNewFrame lda #START_VERT_SYNC sta WSYNC ; wait for next scan line sta VSYNC ; start vertical sync (D1 = 1) inc frameCount ; increment frame count each new frame bne .firstLineOfVerticalSync bit playerState ; check player state bmi .firstLineOfVerticalSync ; branch if E.T. dead lda gameSelection ; get the current game selection cmp #MAX_GAME_SELECTION bcs .firstLineOfVerticalSync lda fbiScreenId ; get FBI Agent screen id bpl .firstLineOfVerticalSync ; branch if FBI Agent active bit etMotionValues ; check E.T. motion values bvs .firstLineOfVerticalSync ; branch if E.T. carried by Scientist lda #P1_NO_MOVE sta fbiAttributes ; set FBI Agent not to move .firstLineOfVerticalSync sta WSYNC lda #$3F and frameCount bne .secondLineOfVerticalSync inc secondTimer ; increment ~every second (i.e 63 frames) lda SWCHB ; read console switches and #SELECT_MASK bne .secondLineOfVerticalSync ; branch if SELECT not pressed ldx gameSelection ; get the current game selection inx ; increment game selection cpx #MAX_GAME_SELECTION + 1 ; see if game selection should wrap bcc .setGameSelection ldx #1 ; set game selection to 1 .setGameSelection stx gameSelection .secondLineOfVerticalSync sta WSYNC lda currentScreenId ; get the current screen id cmp #ID_TITLE_SCREEN bne .endVerticalSync ; branch if not on TITLE_SCREEN lda #24 sta currentObjectHorizPos lda #65 sta etHorizPos lda #58 sta etHeartHorizPos lda #95 sta phonePieceMapHorizPos .endVerticalSync lda #STOP_VERT_SYNC ldx #VBLANK_TIME sta WSYNC ; last line of vertical sync sta VSYNC ; end vertical sync (D1 = 0) stx TIM64T ; set timer for vertical blanking period bit mothershipStatus ; check mothership status bpl .checkToPlayThemeForTitleScreen; branch if mothership not present jmp DetermineObjectToMove .checkToPlayThemeForTitleScreen lda currentScreenId ; get the current screen id cmp #ID_TITLE_SCREEN beq PlayThemeMusic ; branch if on TITLE_SCREEN bit playerState ; check player state bpl CheckToPlayETFallingSound ; branch if E.T. not dead ldx currentObjectId ; get the current object id dex bne CheckToPlayETFallingSound ; branch if current object is not Elliott PlayThemeMusic lda #7 sta AUDV1 lda #SOUND_CHANNEL_LEAD sta AUDC1 ldx themeMusicNoteDelay ; get theme music note delay value dex bpl .playCurrentThemeNote ; hold note if not negative ldx #11 ; initial hold note delay ldy themeMusicFreqIndex ; get theme music frequency index iny ; increment frequency index cpy #55 bcc .setThemeMusicFreqIndex ldy #0 .setThemeMusicFreqIndex sty themeMusicFreqIndex .playCurrentThemeNote stx themeMusicNoteDelay ldy themeMusicFreqIndex lda ThemeMusicFrequencyTable,y sta AUDF1 lda #0 sta AUDV0 jmp .donePlayingSoundChannel1 CheckToPlayETFallingSound bit etPitStatus ; check E.T. pit value bpl CheckToPlayETLevitationSound ; branch if E.T. not falling in pit lda #SOUND_CHANNEL_SQUARE + 1 sta AUDC1 asl ; multiple value by 2 to set volume sta AUDV1 lda etVertPos ; get E.T.'s vertical position lsr ; divide value by 2 to set frequency sta AUDF1 bne .donePlayingSoundChannel1 ; unconditional branch CheckToPlayETLevitationSound bvc CheckToPlayNeckExtensionSound; branch if E.T. not levitating lda etEnergy+1 and #$0F bne .turnOffETWalkingSound lda #4 sta AUDV1 lda #$1C bne .setSoundChannel1AndFrequency; unconditional branch CheckToPlayNeckExtensionSound lda etNeckExtensionValues ; get neck extension value bpl PlayETWalkingSound ; branch if E.T. neck not extended sec rol sec rol sta AUDV1 lda #$0E bne .setSoundChannel1AndFrequency; unconditional branch PlayETWalkingSound lda SWCHA ; read joystick values cmp #P0_NO_MOVE bcs .turnOffETWalkingSound bit etMotionValues ; check E.T. motion values bpl .playETWalkingSound ; branch if E.T. not running lda frameCount ; get the current frame count lsr ; divide value by 4 lsr and #7 sta AUDF1 lda #SOUND_CHANNEL_SQUARE + 1 sta AUDC1 lda #7 sta AUDV1 bne .donePlayingSoundChannel1 ; unconditional branch .playETWalkingSound lda frameCount ; get the current frame count and #7 bne .turnOffETWalkingSound lda frameCount ; get the current frame count lsr ; divide value by 8 lsr lsr and #3 beq .turnOffETWalkingSound ldx #7 stx AUDV1 adc #$16 bne .setSoundChannel1AndFrequency .turnOffETWalkingSound lda #0 sta AUDV1 .setSoundChannel1AndFrequency sta AUDC1 sta AUDF1 .donePlayingSoundChannel1 lda currentScreenId ; get the current screen id cmp #ID_ET_HOME bne .checkIfOnTitleScreen jmp SetSpecialSpriteForPit .checkIfOnTitleScreen cmp #ID_TITLE_SCREEN bne CheckForTimeToLandMothership jmp SetCurrentObjectXYCoordinates CheckForTimeToLandMothership lda shipLandingTimer ; get ship landing timer value bpl .reduceLandingTimerValue ; branch if timer set for count down lda #> 4] & 15;don't allow E.T. to move vertically cpx #PIT_XMIN ; compare E.T. horizontal position bcs .checkForPitXMAX ora #[(~MOVE_LEFT) >> 4] & 15 ; don't allow E.T. to move left .checkForPitXMAX cpx #PIT_XMAX ; compare E.T. horizontal position bcc .setETPitMotionValue ora #[(~MOVE_RIGHT) >> 4] & 15 ; don't allow E.T. to move right .setETPitMotionValue sta etMotionValues jmp CheckIfOkayToMoveET CheckForETLevitatingInPit bit etPitStatus ; check E.T. pit values bvc ETFallingInPit ; branch if E.T. not levitating lda frameCount ; get the current frame count and #7 bne .skipEnergyDecrement ldx #$00 ldy #$01 jsr DecrementETEnergy ; decrement energy by 1 unit .skipEnergyDecrement lda currentScreenId ; get the current screen id cmp #ID_FOREST bne CheckForETInPit ; branch if E.T. not in the forest lda #0 sta etPitStatus ; clear E.T. pit status flags jmp DetermineObjectToMove CheckForETInPit cmp #ID_PIT bne CheckIfOkayToMoveET lda etVertPos ; get E.T.'s vertical position cmp #45 bcc .checkIfETOutOfPit lda #IN_PIT_BOTTOM sta etPitStatus ; set flag to show E.T. at pit bottom bne .jmpToDetermineObjectToMove ; unconditional branch .checkIfETOutOfPit cmp #2 ; compare E.T.'s vertical position bcs .restrictETHorizMovement lda holdETVertPos ; get E.T. vertical position before falling sta etVertPos ; set E.T. vertical position lda holdETHorizPos ; get E.T. horiz position before falling sta etHorizPos ; set E.T. horizontal position ldx holdETScreenId ; get E.T. screen id before falling stx currentScreenId ; set the current screen id jsr SetCurrentScreenData .jmpToDetermineObjectToMove jmp DetermineObjectToMove .restrictETHorizMovement lda etMotionValues ; get E.T. motion value and #ET_MOTION_MASK ora #[~(MOVE_RIGHT & MOVE_LEFT) >> 4] & 15; don't allow E.T. to move horiz bne .setETPitMotionValue ; unconditional branch ETFallingInPit bpl .jmpToDetermineObjectToMove ; branch if E.T. not falling ldx etVertPos ; get E.T.'s vertical position cpx #49 bcs ETReachedPitBottom inc etVertPos bne .jmpToDetermineObjectToMove ; unconditional branch ETReachedPitBottom SUBROUTINE lda #PLAY_SOUND_CHANNEL0 | $1F sta soundDataChannel0 ldx #$02 ldy #$69 ; reduce energy by 296 units for falling jsr DecrementETEnergy ; into pit lda #IN_PIT_BOTTOM sta etPitStatus ; set flag to show E.T. at pit bottom .jmpToDetermineObjectToMove jmp DetermineObjectToMove CheckIfOkayToMoveET bit playerState ; check player state bmi .jmpToDetermineObjectToMove ; branch if E.T. is dead ldx #0 lda etMotionValues ; get E.T. motion value bpl .determineETFractionalDelay ; branch if E.T. not running inx .determineETFractionalDelay and #ET_MOTION_MASK cmp #$0F beq CheckToWrapETToAdjacentScreen; branch if E.T. not moving lda etFractionalDelay ; get E.T. fractional delay value clc adc ETFrameDelayTable,x sta etFractionalDelay ; set E.T. new fractional delay value bcc CheckToWrapETToAdjacentScreen; branch if not time to move E.T. lda etMotionValues ; get E.T. motion value ldx #1 ; move E.T. jsr ObjectDirectionCheck ldx #0 ldy #1 jsr DecrementETEnergy ; reduce energy by 1 unit lda etPitStatus ; get E.T. pit value flags bne DetermineObjectToMove ; branch if E.T. is in a pit lda etMotionValues ; get E.T. motion value bpl CheckToWrapETToAdjacentScreen; branch if E.T. not running ldx #1 ; move E.T. again because he's running jsr ObjectDirectionCheck ldx #0 ldy #1 jsr DecrementETEnergy ; reduce energy by 1 unit CheckToWrapETToAdjacentScreen ldx currentScreenId ; get the current screen id lda etHorizPos ; get E.T.'s horizontal position cmp #XMAX + 1 bcc CheckToWrapETVertically ; branch if E.T. not on right screen border bpl CheckForETWrappingToRight lda LeftScreenIdHorizPosTable,x beq .setETVertPos ; never branches -- value never 0 sta etHorizPos ; set E.T. horizontal position .setETVertPos lda LeftScreenIdVertPosTable,x beq .jmpToSetScreenIdToLeftScreen sta etVertPos ; set E.T. vertical position .jmpToSetScreenIdToLeftScreen lda LeftScreenIdTable,x jmp SetCurrentScreenId CheckForETWrappingToRight SUBROUTINE lda RightScreenIdHorizPosTable,x beq .setETVertPos sta etHorizPos ; set E.T. horizontal position .setETVertPos lda RightScreenIdVertPosTable,x beq .jmpToSetScreenIdToRightScreen sta etVertPos ; set E.T. vertical position .jmpToSetScreenIdToRightScreen lda RightScreenIdTable,x jmp SetCurrentScreenId CheckToWrapETVertically SUBROUTINE lda etVertPos ; get E.T.'s vertical position cmp #59 bcc DetermineObjectToMove bpl CheckForETWrappingDown lda UpperScreenIdHorizPosTable,x beq .setETVertPos sta etHorizPos ; set E.T. horizontal position .setETVertPos lda UpperScreenIdVertPosTable,x beq .jmpToSetScreenIdToUpperScreen; never branches -- value never 0 sta etVertPos ; set E.T. vertical position .jmpToSetScreenIdToUpperScreen lda UpperScreenIdTable,x jmp SetCurrentScreenId CheckForETWrappingDown SUBROUTINE lda LowerScreenIdHorizPosTable,x beq .setETVertPos sta etHorizPos ; set E.T. horizontal position .setETVertPos lda LowerScreenIdVertPosTable,x beq .jmpToSetScreenIdToLowerScreen; never branches -- value never 0 sta etVertPos ; set E.T. vertical position .jmpToSetScreenIdToLowerScreen lda LowerScreenIdTable,x SetCurrentScreenId sta currentScreenId ; set the current screen id jsr SetCurrentScreenData DetermineObjectToMove bit mothershipStatus ; check Mothership status bmi CheckToLandMothership ; branch if Mothership is present jmp DetermineToMoveHumans CheckToLandMothership lda mothershipStatus ; get Mothership status bvs .mothershipPickingUpET ror ; shift D0 to carry bcs .mothershipLeavingWithoutET ; branch if Mothership leaving Earth lda frameCount ; get the current frame count and #3 bne .playMothershipSound inc currentObjectVertPos ; move Mothership down 1 pixel inc etVertPos ; move E.T. down 1 pixel lda currentObjectVertPos ; get current object's vertical position bmi .playMothershipSound cmp #H_MOTHERSHIP bcc .playMothershipSound ror mothershipStatus ; rotate Mothership status right sec ; set carry and rotate Mothership status rol mothershipStatus ; left to set MOTHERSHIP_LEAVING status .playMothershipSound jsr PlayMothershipSound lda frameCount ; get the current frame count and #7 bne .doneLandMothership ldx objectColorPtrs_0 inx cpx #ETSprites sta etGraphicPointers0+1 sta etGraphicPointers1+1 SetSpecialSpriteForPit lda currentObjectId ; get the current object id cmp #$80 | ID_FLOWER bne DetermineObjectAnimationPtrs bit easterEggSpriteFlag ; check Easter Egg sprite flags bpl .setFlowerGrowthAnimation ; animate flower growth ldx #ID_INDY ; assume we are showing Indy sprite bvs .setEasterEggSpriteInfo ; branch if set current object data dex ; reduce object id to be Yar wings up lda frameCount ; get the current frame count and #2 bne .setEasterEggSpriteInfo dex ; reduce object id to be Yar wings down .setEasterEggSpriteInfo jsr SetCurrentObjectData jmp SetCurrentObjectXYCoordinates .setFlowerGrowthAnimation lda flowerState ; get the flower state lsr ; move revive animation to lower nybbles lsr lsr lsr and #3 tax lda FlowerAnimationLSBTable_A,x sta objectGraphicPtrs_0 lda FlowerAnimationLSBTable_B,x sta objectGraphicPtrs_1 jmp SetCurrentObjectXYCoordinates DetermineObjectAnimationPtrs ldx currentObjectId ; get the current object id bmi SetCurrentObjectXYCoordinates lda HumanAnimationRate,x ; get human animation rate and frameCount bne SetCurrentObjectXYCoordinates; skip animation if not time lda objectGraphicPtrs_0 ; get the object's graphic LSB value clc adc SpriteHeightValues,x ; increase by sprite height cmp HumanEndAnimationTable,x bcc .setHumanAnimationGraphicPtrs lda ObjectGraphicPointersLSB_0,x sta objectGraphicPtrs_0 lda ObjectGraphicPointersLSB_1,x sta objectGraphicPtrs_1 bne SetCurrentObjectXYCoordinates; unconditional branch .setHumanAnimationGraphicPtrs sta objectGraphicPtrs_0 lda objectGraphicPtrs_1 clc adc SpriteHeightValues,x sta objectGraphicPtrs_1 SetCurrentObjectXYCoordinates lda currentScreenId ; get the current screen id cmp #ID_ET_HOME beq .setObjectsHorizPosition ldx currentObjectId ; get the current object id bmi .setObjectsHorizPosition lda objectVertPos,x sta currentObjectVertPos lda objectHorizPos,x sta currentObjectHorizPos .setObjectsHorizPosition lda etHorizPos ; get E.T.'s horizontal position pha ; push value on to stack lda #30 sta etHorizPos ; set position for status icons jmp HorizPositionObjects SetCurrentScreenData ldx currentScreenId ; get the current screen id lda PlayfieldGraphicPointersMSB,x sta pf1GraphicPtrs+1 sta pf2GraphicPtrs+1 lda PF1GraphicPointersLSB,x sta pf1GraphicPtrs lda PF2GraphicPointersLSB,x sta pf2GraphicPtrs lda #$00 sta easterEggSpriteFlag ; clear Easter Egg sprite flags sta programmerInitialFlag ; clear flag to show programmer initials ldy #<(~PHONE_PIECE_SCREEN_LOC) tya and h_phonePieceAttribute sta h_phonePieceAttribute tya and s_phonePieceAttribute sta s_phonePieceAttribute tya and w_phonePieceAttribute sta w_phonePieceAttribute lda #127 sta etHeartVertPos sta phonePieceMapVertPos sta candyVertPos bit mothershipStatus ; check Mothership status bpl CheckToEnableETHeart ; branch if Mothership not present lda #<-1 sta currentObjectId lda #61 sta etHorizPos lda #244 sta etVertPos lda #18 / 2 sta etHeight lda #ETSprites sta etGraphicPointers0+1 sta etGraphicPointers1+1 ldx #ID_MOTHERSHIP jsr SetCurrentObjectData lda #56 sta currentObjectHorizPos lda #240 sta currentObjectVertPos rts CheckToEnableETHeart cpx #ID_ET_HOME bne .checkForETInPit ; branch if E.T. not on HOME screen bit playerState ; check player state bpl .doneCheckForETHeart ; branch if E.T. is not dead lda #51 sta etHeartVertPos lda #64 sta etHeartHorizPos .doneCheckForETHeart rts .checkForETInPit cpx #ID_PIT beq PositionETInPit txa ldx #ID_SCIENTIST .findCurrentHumanLoop cmp objectScreenId,x ; see if human is on current screen beq .setCurrentHumanId ; if so then set current object attributes dex bpl .findCurrentHumanLoop lda #<-1 sta currentObjectId lda #0 sta currentSpriteHeight sta currentObjectVertPos beq CalculatePowerZonePointer ; unconditional branch .setCurrentHumanId stx currentObjectId ; set current object id jsr SetCurrentObjectData CalculatePowerZonePointer ldx currentScreenId ; get the current screen id cpx #ID_FOREST bcs .determinePowerZonePointerLSB; branch if not a well screen lda CandyStatusValueTable,x and candyStatus beq .determinePowerZonePointerLSB lda CandyVertPositionTable,x sta candyVertPos ; set candy vertical position lda CandyHorizPositionTable,x sta candyHorizPos ; set candy horizontal position .determinePowerZonePointerLSB lda currentScreenId ; get the current screen id cmp #ID_PIT bcs .doneCalculatePowerZonePointer; branch if in pit or game over lsr ; divide current screen id by 2 tax lda powerZoneLSBValues,x bcs .multi8 ; branch if odd screen id (EIGHT_PITS, FOUR_PITS, WASH) lsr ; divide value by 2 bpl .setPowerZonePointerLSB ; unconditional branch .multi8 asl asl asl .setPowerZonePointerLSB and #$78 sta powerZonePointer .doneCalculatePowerZonePointer rts CandyVertPositionTable .byte 32,32,32,32 CandyHorizPositionTable .byte 60,60,38,38 PositionETInPit lda #69 sta etHorizPos lda #3 sta etVertPos lda #FALLING_IN_PIT sta etPitStatus ; set status to show E.T. falling in a pit bit playerState ; check player state bmi .noObjectInCurrentPit ; branch if E.T. is dead ldx #NUM_PHONE_PIECES - 1 .checkPhonePieceInCurrentPit lda phonePieceAttributes,x ; get phone piece attribute value and #<(~PHONE_PIECE_PIT_NUMBER) bne .checkNextPhonePiece ; branch if phone piece taken lda phonePieceAttributes,x ; get phone piece attribute value and #PHONE_PIECE_PIT_NUMBER ; keep phone piece pit number cmp currentPitNumber ; compare with current pit number beq .setCurrentObjectToPhonePiece; branch if phone piece in current pit .checkNextPhonePiece dex bpl .checkPhonePieceInCurrentPit lda flowerState ; get flower state and #FLOWER_PIT_NUMBER ; keep flower pit number cmp currentPitNumber ; compare with current pit number bne .noObjectInCurrentPit ; branch if flower not in current pit lda #$80 | ID_FLOWER bne .setCurrentObjectIdInPit ; unconditional branch .noObjectInCurrentPit ldx #<-1 stx currentObjectId inx ; x = 0 stx currentSpriteHeight rts .setCurrentObjectToPhonePiece txa adc #$80 | ID_H_PHONE_PIECE - 1 .setCurrentObjectIdInPit sta currentObjectId and #$0F tax jsr SetCurrentObjectData lda #OBJECT_IN_PIT_Y sta currentObjectVertPos lda #OBJECT_IN_PIT_X sta currentObjectHorizPos rts BOUNDARY 0 HMOVETable .byte HMOVE_R1,HMOVE_R2,HMOVE_R3,HMOVE_R4,HMOVE_R5,HMOVE_R6,HMOVE_R7 COARSE_MOTION SET 0 REPEAT 8 COARSE_MOTION SET COARSE_MOTION + 1 .byte HMOVE_L7 | COARSE_MOTION .byte HMOVE_L6 | COARSE_MOTION .byte HMOVE_L5 | COARSE_MOTION .byte HMOVE_L4 | COARSE_MOTION .byte HMOVE_L3 | COARSE_MOTION .byte HMOVE_L2 | COARSE_MOTION .byte HMOVE_L1 | COARSE_MOTION .byte HMOVE_0 | COARSE_MOTION .byte HMOVE_R1 | COARSE_MOTION .byte HMOVE_R2 | COARSE_MOTION .byte HMOVE_R3 | COARSE_MOTION .byte HMOVE_R4 | COARSE_MOTION .byte HMOVE_R5 | COARSE_MOTION .byte HMOVE_R6 | COARSE_MOTION .byte HMOVE_R7 | COARSE_MOTION REPEND Start ; ; Set up everything so the power up state is known. ; sei ; disable interrupts cld ; clear decimal mode ldx #$FF txs ; set stack to the beginning inx ; x = 0 txa .clearLoop sta VSYNC,x dex bne .clearLoop lda #$01 sta CTRLPF sta gameSelection ; set initial game selection to 1 lda #>PowerZoneMap sta powerZonePointer+1 lda #ORANGE+10 sta telephoneColor lda #LT_BLUE+12 sta powerZoneColor lda #BROWN+10 sta timerColor lda #ID_TITLE_SCREEN sta currentScreenId ; set the current screen id jsr SetCurrentScreenData jmp StartNewFrame JumpToDisplayKernel SUBROUTINE .waitTime lda INTIM bne .waitTime sta WSYNC sta WSYNC lda #DisplayKernel sta bankSwitchRoutinePtr+1 lda #LDA_ABS sta displayKernelBankSwitch lda #BANK1STROBE sta bankSwitchStrobe+1 lda #JMP_ABS sta bankSwitchABSJmp jmp.w displayKernelBankSwitch ObjectDirectionCheck ror ; shift up motion flag to carry bcs .checkForDownMotion ; check down motion if not moving up dec currentObjectVertPos,x ; move object up .checkForDownMotion ror ; shift down motion flag to carry bcs .checkForLeftMotion ; check left motion if not moving down inc currentObjectVertPos,x ; move object down .checkForLeftMotion ror ; shift left motion flag to carry bcs .checkForRightMotion ; check right motion if not moving left dec currentObjectHorizPos,x ; move object left .checkForRightMotion ror ; shift right motion flag to carry bcs .doneObjectDirectionCheck ; done if not moving right inc currentObjectHorizPos,x ; move object right .doneObjectDirectionCheck rts MoveHumanTowardTarget lda objectVertPos,x ; get the object's vertical position cmp etVertPos,y ; compare with target's vertical position beq .checkTargetHorizPosition ; check horizontal position if the same bcs .moveObjectUpTowardTarget inc objectVertPos,x ; move object down bne .checkTargetHorizPosition ; unconditional branch .moveObjectUpTowardTarget dec objectVertPos,x ; move object up .checkTargetHorizPosition lda objectHorizPos,x ; get the object's horizontal position cmp etHorizPos,y ; compare with target's horizontal position beq .doneMoveHumanTowardTarget ; done if the same bcs .moveObjectLeftTowardTarget inc objectHorizPos,x ; move the object right .doneMoveHumanTowardTarget rts .moveObjectLeftTowardTarget dec objectHorizPos,x ; move the object left rts PhonePiecePitVertPosition .byte 19,32,32,44,11,32,32,52,21,21,45,45,15,15,47,47 PhonePiecePitHorizPosition .byte 62,25,101,62,62,30,95,62,25,100,28,96,30,95,30,95 .byte 0,0,0,0,0,10,9,11,0,6,5,7,0,14,13,15 PlayfieldGraphicPointersMSB .byte >WideDiamondPitGraphics,>EightPitGraphics,>ArrowPitGraphics .byte >FourDiamondPitGraphics,>ForestGraphics,>WashingtonDCGraphics .byte >PitGraphics,>ETHomePFGraphics PF1GraphicPointersLSB .byte FBIAgent_0,>Elliott_0,>Scientist_0,>H_PhonePiece_0,>S_PhonePiece_0 .byte >W_PhonePiece_0,>Flower_A0,>MotherShip,>Yar_0,>Yar_1,>IndySprite ObjectGraphicPointersLSB_0 .byte FBIAgentColors_A .byte >ElliottColors_A .byte >ScientistColors_A .byte >PhonePieceColors_A .byte >PhonePieceColors_A .byte >PhonePieceColors_A .byte >FlowerColors .byte >MotherShipColors .byte >YarColor .byte >YarColor .byte >IndyColors ObjectColorPointersLSB_A .byte >4,MOVE_UP>>4,MOVE_RIGHT>>4,MOVE_UP>>4,MOVE_DOWN>>4 .byte P0_NO_MOVE,P0_NO_MOVE,MOVE_RIGHT>>4,NO_MOVE,MOVE_LEFT>>4,MOVE_UP>>4 .byte MOVE_UP>>4,MOVE_DOWN>>4,P0_NO_MOVE,P0_NO_MOVE .byte MOVE_UP>>4,MOVE_RIGHT>>4,NO_MOVE,MOVE_LEFT>>4,MOVE_UP>>4,MOVE_DOWN>>4 .byte P0_NO_MOVE,P0_NO_MOVE,MOVE_LEFT>>4,MOVE_DOWN>>4,MOVE_RIGHT>>4,NO_MOVE .byte MOVE_UP>>4,MOVE_DOWN>>4,P0_NO_MOVE,P0_NO_MOVE .byte MOVE_UP>>4,MOVE_RIGHT>>4,MOVE_DOWN>>4,MOVE_LEFT>>4,NO_MOVE .byte MOVE_DOWN>>4,P0_NO_MOVE,P0_NO_MOVE,MOVE_UP>>4,MOVE_LEFT>>4 .byte MOVE_DOWN>>4,MOVE_RIGHT>>4,MOVE_UP>>4,NO_MOVE,P0_NO_MOVE,P0_NO_MOVE ETFrameDelayTable .byte FRAME_DELAY_ONE_FORTH,FRAME_DELAY_ONE_HALF PowerZoneJumpTable .word SetPhonePieceHiddenLocation - 1 .word WarpETLeft - 1 .word WarpETRight - 1 .word WarpETUp - 1 .word WarpETDown - 1 .word DetermineHiddenPhonePiece - 1 .word EatCandyPiece - 1 .word ReturnCurrentHumanHome - 1 .word ClearElliottReturnHomeFlag - 1 .word CallMothership - 1 .word SetPhonePieceHiddenLocation - 1 .word LevitateETOutOfPit - 1 .word ReviveFlower - 1 ETNeckExtensionLSBTable_A .byte TitleETGraphics ; 2 sta graphicPointers+1 ; 3 sta graphicPointers+3 ; 3 sta graphicPointers+5 ; 3 sta graphicPointers+7 ; 3 sta graphicPointers+9 ; 3 sta graphicPointers+11 ; 3 lda #Copyright_0 ; 2 set to show copyright information bne .setGraphicPointersMSB ; 3 unconditional branch .setToShowScoreOrEnergy lda #>NumberFonts ; 2 .setGraphicPointersMSB sta graphicPointers+1 ; 3 sta graphicPointers+3 ; 3 sta graphicPointers+5 ; 3 sta graphicPointers+7 ; 3 sta graphicPointers+9 ; 3 sta graphicPointers+11 ; 3 sta WSYNC ;-------------------------------------- lda currentScreenId ; 3 get the current screen id cmp #ID_ET_HOME ; 2 bcc .setGraphicPointers ; 2≥ branch if not showing the score lda playerScore ; 3 sta tempNumberFonts ; 3 lda playerScore+1 ; 3 sta tempNumberFonts+1 ; 3 lda playerScore+2 ; 3 sta tempNumberFonts+2 ; 3 .setGraphicPointers sta WSYNC ;-------------------------------------- lda #LT_BLUE+10 ; 2 sta COLUBK ; 3 = @05 lda tempNumberFonts ; 3 and #$F0 ; 2 bne .setGraphicsPointerLSB ; 2≥ lda #Copyright_0 ; 2 cmp graphicPointers+1 ; 3 bne .skipSetCopyrightInfo ; 2≥ lda #SetScreenIdFromStartingScreen sta bankSwitchRoutinePtr+1 lda #LDA_ABS sta displayKernelBankSwitch lda #BANK0STROBE sta bankSwitchStrobe+1 lda #JMP_ABS sta bankSwitchABSJmp jmp.w displayKernelBankSwitch IncrementScore sed sty pointsTensValue clc lda playerScore+2 adc pointsTensValue sta playerScore+2 stx pointsHundredsValue lda playerScore+1 adc pointsHundredsValue sta playerScore+1 lda playerScore adc #$00 sta playerScore cld Waste12Cycles rts SixDigitKernel .sixDigitLoop ldy loopCount ; 3 lda (graphicPointers),y ; 5 sta GRP0 ; 3 sta WSYNC ;-------------------------------------- lda (graphicPointers+2),y ; 5 sta GRP1 ; 3 = @08 lda (graphicPointers+4),y ; 5 sta GRP0 ; 3 = @16 lda (graphicPointers+6),y ; 5 sta tempCharHolder ; 3 lda (graphicPointers+8),y ; 5 tax ; 2 lda (graphicPointers+10),y ; 5 tay ; 2 lda tempCharHolder ; 3 sta GRP1 ; 3 = @34 stx GRP0 ; 3 = @37 sty GRP1 ; 3 = @40 sty GRP0 ; 3 = @43 dec loopCount ; 5 bpl .sixDigitLoop ; 2≥ lda #0 ; 2 sta WSYNC ;-------------------------------------- sta GRP0 ; 3 = @03 sta GRP1 ; 3 = @06 sta GRP0 ; 3 = @09 sta GRP1 ; 3 = @12 sta NUSIZ0 ; 3 = @15 set to show ONE_COPY of players sta NUSIZ1 ; 3 = @18 sta VDELP0 ; 3 = @21 turn off vertical delay sta VDELP1 ; 3 = @24 sta WSYNC ;-------------------------------------- rts ; 6 DisplayKernel StatusKernel lda #THREE_MED_COPIES ; 2 sta NUSIZ1 ; 3 lda #DK_PINK + 2 ; 2 sta COLUBK ; 3 lda #ENABLE_TIA ; 2 sta WSYNC ;-------------------------------------- sta VBLANK ; 3 enable TIA (D1 = 0) sta HMCLR ; 3 sta CXCLR ; 3 clear all collisions lda #>GameIcons ; 2 sta graphicPointers+1 ; 3 sta graphicPointers+3 ; 3 lda #>Telephone ; 2 sta graphicPointers+5 ; 3 sta WSYNC ;-------------------------------------- ldx #NUM_PHONE_PIECES ; 2 bit h_phonePieceAttribute ; 3 check H phone piece value bpl .checkForCarringSPiece ; 2≥ branch if E.T. not taken H piece dex ; 2 .checkForCarringSPiece bit s_phonePieceAttribute ; 3 check S phone piece value bpl .checkForCarringWPiece ; 2≥ branch if E.T. not taken S piece dex ; 2 .checkForCarringWPiece bit w_phonePieceAttribute ; 3 check W phone piece value bpl .setTelephoneIconLSB ; 2≥ branch if E.T. not taken W piece dex ; 2 .setTelephoneIconLSB lda TelephoneIconLSBPtrs,x ; 4 sta graphicPointers+4 ; 3 sta WSYNC ;-------------------------------------- lda #$00 ; 2 ldy currentScreenId ; 3 get the current screen id cpy #ID_ET_HOME ; 2 bcc .setupToDrawStatusIcons; 2≥ sta graphicPointers+2 ; 3 sta graphicPointers+4 ; 3 bne .setupToDrawGameSelection; 2≥ ldx #NumberFonts ; 2 sta graphicPointers+1 ; 3 lda gameSelection ; 3 get the current game selection asl ; 2 multiply game selection by 8 (i.e. asl ; 2 height of digits) asl ; 2 sta graphicPointers ; 3 .setupToDrawStatusIcons sta WSYNC ;-------------------------------------- bit mothershipStatus ; 3 check Mothership status bpl .checkToDrawArtistInitials; 2≥ branch if Mothership not present lda #$00 ; 2 sta graphicPointers+2 ; 3 sta graphicPointers+4 ; 3 .checkToDrawArtistInitials lda artistInitialFlag ; 3 beq .prepareToDrawIndicators; 2≥ lda #