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 ; ; *** 115 BYTES OF RAM USED 13 BYTES FREE ; ; NTSC ROM usage stats ; ------------------------------------------- ; *** 25 BYTES OF ROM FREE IN BANK0 ; *** 24 BYTES OF ROM FREE IN BANK1 ; =========================================== ; *** 49 TOTAL BYTES FREE ; ; PAL50 ROM usage stats ; ------------------------------------------- ; *** 23 BYTES OF ROM FREE IN BANK0 ; *** 24 BYTES OF ROM FREE IN BANK1 ; =========================================== ; *** 47 TOTAL BYTES 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, ATARI, INC. = ; = = ; ============================================================================== ; ; 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 ; - PAL50 conversion adjusts E.T. movement and colors ; - It seems RAM locations $85 and $8B are 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 "vcs.h" include "macro.h" include "tia_constants.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 IFNCONST COMPILE_REGION COMPILE_REGION = NTSC ; change to compile for different regions ENDIF IF !(COMPILE_REGION = NTSC || COMPILE_REGION = PAL50) echo "" echo "*** ERROR: Invalid COMPILE_REGION value" echo "*** Valid values: NTSC = 0, PAL50 = 1" echo "" err ENDIF ;=============================================================================== ; F R A M E - T I M I N G S ;=============================================================================== IF COMPILE_REGION = NTSC FPS = 60 ; ~60 frames per second VBLANK_TIME = 47 OVERSCAN_TIME = 45 START_LANDING_TIMER = 63 ; staring value for landing timer FRACTIONAL_MOVEMENT_ET_RUNNING = <[(256 * 30) / FPS] + 1;~30 pixels / sec FRACTIONAL_MOVEMENT_ET_WALKING = <[(256 * 15) / FPS] - 1;~15 pixels / sec FRACTIONAL_MOVEMENT_FAST_HUMAN = <[(256 * 22) / FPS];~22 pixels / sec FRACTIONAL_MOVEMENT_SLOW_HUMAN = <[(256 * 14) / FPS];~14 pixels / sec ELSE FPS = 50 ; ~50 frames per second VBLANK_TIME = 78 OVERSCAN_TIME = 72 START_LANDING_TIMER = 57 ; staring value for landing timer FRACTIONAL_MOVEMENT_ET_RUNNING = <[(256 * 30) / FPS] + 1;~30 pixels / sec FRACTIONAL_MOVEMENT_ET_WALKING = <[(256 * 15) / FPS] - 1;~15 pixels / sec FRACTIONAL_MOVEMENT_FAST_HUMAN = <[(256 * 22) / FPS] - 1;~22 pixels / sec FRACTIONAL_MOVEMENT_SLOW_HUMAN = <[(256 * 14) / FPS] - 1;~14 pixels / sec ENDIF ;=============================================================================== ; C O L O R - C O N S T A N T S ;=============================================================================== BLACK = $00 WHITE = $0E IF COMPILE_REGION = NTSC 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 ELSE 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 ENDIF ;=============================================================================== ; 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 ;=============================================================================== ; 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 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 EXTEND_NECK_ENERGY_REDUCTION = $0019 FALLING_IN_PENALTY = $0269 ; lose 269 energy units for falling pit EAT_CANDY_ENERGY_INCREMENT = $0360 ; gain 360 energy units for eating candy ; 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 ;=============================================================================== SEG.U variables .org $80 currentScreenId ds 1 frameCount ds 1 secondTimer ds 1 ; updates ~every second temp ds 1 ;-------------------------------------- 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 ds 1 zp_Unused_01 ds 1 nextETGraphicData ds 1 ;-------------------------------------- energyDecTensValue = nextETGraphicData ;-------------------------------------- energyDecHundredsValue = energyDecTensValue nextObjectGraphicData ds 1 nextObjectColorData ds 1 ;-------------------------------------- displayKernelBankSwitch = loopCount bankSwitchStrobe = displayKernelBankSwitch + 1 bankSwitchABSJmp = bankSwitchStrobe + 2 bankSwitchRoutinePtr = bankSwitchABSJmp + 1 fireResetStatus ds 1 ; hold when fire button and RESET held soundDataChannel0 ds 1 unknown ds 1 currentSpriteHeight ds 1 etHeight ds 1 powerZoneColor ds 1 timerColor ds 1 telephoneColor ds 1 etMotionValues ds 1 etFractionalDelay ds 1 humanFractionalDelay ds 1 etNeckExtensionValues ds 1 currentObjectHorizPos ds 1 etHorizPos ds 1 etHeartHorizPos ds 1 phonePieceMapHorizPos ds 1 candyHorizPos ds 1 humanTargetHorizPos ds 1 currentObjectVertPos ds 1 etVertPos ds 1 etHeartVertPos ds 1 phonePieceMapVertPos ds 1 candyVertPos ds 1 humanTargetVertPos ds 1 currentObjectId ds 1 humanAttributes ds 3 ;-------------------------------------- fbiAttributes = humanAttributes elliottAttributes = fbiAttributes + 1 scientistAttributes = elliottAttributes + 1 objectScreenId ds 3 ;-------------------------------------- fbiScreenId = objectScreenId elliottScreenId = fbiScreenId + 1 scientistScreenId = elliottScreenId + 1 objectHorizPos ds 3 ;-------------------------------------- fbiAgentHorizPos = objectHorizPos elliottHorizPos = fbiAgentHorizPos + 1 scientistHorizPos = elliottHorizPos + 1 objectVertPos ds 3 ;-------------------------------------- fbiAgentVertPos = objectVertPos elliottVertPos = fbiAgentVertPos + 1 scientistVertPos = elliottVertPos + 1 objectGraphicPointers ds 4 ;-------------------------------------- objectGraphicPtrs_0 = objectGraphicPointers objectGraphicPtrs_1 = objectGraphicPtrs_0 + 2 objectColorPointers ds 4 ;-------------------------------------- objectColorPtrs_0 = objectColorPointers objectColorPtrs_1 = objectColorPtrs_0 + 2 etGraphicsPointers ds 4 ;-------------------------------------- etGraphicPointers0 = etGraphicsPointers etGraphicPointers1 = etGraphicPointers0 + 2 playfieldGraphicPtrs ds 4 ;-------------------------------------- pf1GraphicPtrs = playfieldGraphicPtrs pf2GraphicPtrs = pf1GraphicPtrs + 2 graphicPointers ds 12 phonePieceAttributes ds 3 ;-------------------------------------- h_phonePieceAttribute = phonePieceAttributes s_phonePieceAttribute = h_phonePieceAttribute + 1 w_phonePieceAttribute = s_phonePieceAttribute + 1 powerZonePointer ds 2 powerZoneIndicatorId ds 1 shipLandingTimer ds 1 candyStatus ds 1 heldCandyPieces ds 1 etEnergy ds 2 etHMOVEValue ds 1 holdETHorizPos ds 1 holdETVertPos ds 1 holdETScreenId ds 1 etPitStatus ds 1 currentPitNumber ds 1 callHomeScreenId ds 1 extraCandyPieces ds 1 collectedCandyPieces ds 1 collectedCandyScoring ds 1 playerScore ds 3 startingScreenId ds 1 playerState ds 1 gameState ds 1 numberOfTries ds 1 flowerState ds 1 powerZoneLSBValues ds 3 ;-------------------------------------- powerZoneLSBValue_01 = powerZoneLSBValues powerZoneLSBValue_02 = powerZoneLSBValue_01 + 1 powerZoneLSBValue_03 = powerZoneLSBValue_02 + 1 gameSelection ds 1 mothershipStatus ds 1 etAnimationIndex ds 1 etHomeElliottMovement ds 1 themeMusicNoteDelay ds 1 themeMusicFreqIndex ds 1 easterEggStatus ds 1 programmerInitialFlag ds 1 easterEggSpriteFlag ds 1 artistInitialFlag ds 1 echo "***",(* - $80 - 1)d, "BYTES OF RAM USED", ($100 - * + 1)d, "BYTES FREE" ;=============================================================================== ; R O M - C O D E (BANK 0) ;=============================================================================== SEG Bank0 .org BANK0TOP .rorg BANK0_REORG lda BANK0STROBE jmp Start HorizPositionObjects ldx #<[RESBL - RESP0] .moveObjectLoop sta WSYNC ; wait for next scan line lda currentObjectHorizPos,x ; get object's horizontal position tay lda HMOVETable,y ; get fine motion/coarse position value sta HMP0,x ; set object's fine motion value and #$0F ; mask off fine motion value tay ; move coarse move value to y .coarseMoveObject dey bpl .coarseMoveObject sta RESP0,x ; set object's coarse position dex bpl .moveObjectLoop sta WSYNC ; wait for next scan line sta HMOVE pla ; pull E.T. horizontal position from stack sta etHorizPos tax lda HMOVETable,x sta etHMOVEValue ; set E.T. horizontal move value jmp JumpToDisplayKernel SetScreenIdFromStartingScreen lda startingScreenId ; get starting screen id bpl .skipScreenIdSet ; branch if screen id already set and #<(~SET_STARTING_SCREEN) sta currentScreenId ; set screen id from starting screen id jsr SetCurrentScreenData lsr startingScreenId ; shift right to show value already set .skipScreenIdSet bit mothershipStatus ; check mothership status bmi .jmpToVerticalSync ; branch if Mothership is present lda currentScreenId ; get the current screen id cmp #ID_TITLE_SCREEN bne .checkForETHome ; branch if not on the title screen .jmpToVerticalSync jmp VerticalSync .checkForETHome lda currentScreenId ; get the current screen id cmp #ID_ET_HOME bne .checkForElliottToReviveET ; branch if not on home (game done) screen jmp VerticalSync .checkForElliottToReviveET bit playerState ; check the player state bpl .checkETNeckExtension ; branch if E.T. is not dead bvc .checkETNeckExtension ; branch if Elliott not reviving E.T. lda currentObjectId ; get the current object id bpl .checkETNeckExtension ; branch if current object still on screen ldx #ID_ELLIOTT stx currentObjectId ; set current object id to Elliott jsr SetCurrentObjectData lda #<(MOVE_UP >> 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 #EXTEND_NECK_ENERGY_REDUCTION >> 8 ldy #EXTEND_NECK_ENERGY_REDUCTION & $FF 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 #EAT_CANDY_ENERGY_INCREMENT >> 8 ldy #EAT_CANDY_ENERGY_INCREMENT & $FF 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 #FALLING_IN_PENALTY >> 8 ; reduce energy by 296 units for falling ldy #FALLING_IN_PENALTY & $FF ; into pit jsr DecrementETEnergy 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 #<[MotherShipColors + 6] bcc .setMothershipColorPointer ldx #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 FRACTIONAL_MOVEMENT_ET_WALKING, FRACTIONAL_MOVEMENT_ET_RUNNING 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 #<[Blank * 2] ; 2 .setGraphicsPointerLSB lsr ; 2 sta graphicPointers ; 3 lda tempNumberFonts ; 3 and #$0F ; 2 asl ; 2 asl ; 2 asl ; 2 sta graphicPointers + 2 ; 3 sta WSYNC ;-------------------------------------- lda tempNumberFonts + 1 ; 3 and #$F0 ; 2 lsr ; 2 sta graphicPointers + 4 ; 3 lda tempNumberFonts + 1 ; 3 and #$0F ; 2 asl ; 2 asl ; 2 asl ; 2 sta graphicPointers + 6 ; 3 sta WSYNC ;-------------------------------------- lda #SHOW_HSW_INITIALS_VALUE; 2 cmp programmerInitialFlag ; 3 bne .skipShowHSWInitials ; 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 #