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 #<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 #<ID_PIT_OUT_OF_RANGE

bne .setCurrentPitNumber ; unconditional branch

.checkHorizPosForPitNumber

iny ; y = 1

cmp #64 ; compare E.T. horizontal position

bcc .combineIndexForPitNumber

iny ; y = 2

bne .combineIndexForPitNumber ; unconditional branch

.setCurrentPitNumber

sta currentPitNumber

lda #ID_PIT

sta currentScreenId ; set the current screen id

jsr SetCurrentScreenData

DetermineHumanDirection

lda frameCount ; get the current frame count

and #3 ; make value 0 <= a <= 3

cmp #ID_SCIENTIST + 1

beq CheckForETCollectingCandy ; branch if out of human id range

tax ; move object id to x

lda objectScreenId,x ; get the object's screen id

bpl .multiplyScreenIdBy8 ; branch if human is active

lda humanAttributes,x ; get human attribute value

bmi CheckForETCollectingCandy ; branch if returning home

lda #ID_WASHINGTON_DC

jsr CheckForHumanOnScreen

bcs CheckForETCollectingCandy ; branch if human on WASHINGTON_DC screen

sta objectScreenId,x ; set object screen id to WASHINGTON_DC

lda HumanTargetVertPosTable,x

sta objectVertPos,x

lda HumanTargetHorizPosTable,x

sta objectHorizPos,x

lda #<(MOVE_LEFT >> 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 #<BlankIcon

sta graphicPointers+2

beq MoveET ; unconditional branch

.reduceLandingTimerValue

lda frameCount ; get the current frame count

and #$1F

bne SetCountdownClockSpriteLSB

dec shipLandingTimer ; decrement ship landing timer

bpl PlayShipLandingTimerSound

lda #<BlankIcon

sta graphicPointers+2 ; clear landing timer icon

lda powerZoneIndicatorId ; get power zone indicator id

cmp #ID_LANDING_ZONE

bne .dontLandMothership ; branch if E.T. not in landing zone

lda currentObjectId ; get the current object id

bmi .landMothership

bit SWCHB ; check console switch values

bvs .dontLandMothership ; branch if player 1 difficulty set to PRO

cmp #ID_ELLIOTT ; don't land Mothership if present human

bne .dontLandMothership ; is not Elliott

.landMothership

lda #PLAY_SOUND_CHANNEL0 | $0D

sta soundDataChannel0

lda heldCandyPieces ; get number of candy pieces held by E.T.

lsr ; shift upper nybbles to lower nybble

lsr

lsr

lsr

clc

adc collectedCandyPieces ; add in number of candy held by Elliott

sta totalCandyCollected ; save total candy pieces collected

lsr ; divide value by 2

clc ; add collected candy value back in so

adc totalCandyCollected ; value is multiplied by 1.5

cmp #16

bcs .setExtraCandyPiecesValue

lda #16

.setExtraCandyPiecesValue

sta extraCandyPieces

ldx #ID_MOTHERSHIP

jsr SetCurrentObjectData ; set current object to the MOTHERSHIP

lda #240

sta currentObjectVertPos ; set Mothership's vertical position

lda etHorizPos ; get E.T.'s horizontal position

sec

sbc #5

bpl .setMothershipHorizPos

lda #0

.setMothershipHorizPos

sta currentObjectHorizPos

lda #MOTHERSHIP_PRESENT | ET_GOING_HOME

sta mothershipStatus

jmp DetermineObjectToMove

.dontLandMothership

lda #PLAY_SOUND_CHANNEL0 | $1F

sta soundDataChannel0

bne MoveET ; unconditional branch

PlayShipLandingTimerSound

lda shipLandingTimer ; get timer value for ship landing

ldx #PLAY_SOUND_CHANNEL0 | $04

cmp #7

bcc .setSoundDataChannel0

and #7

cmp #7

bne SetCountdownClockSpriteLSB

ldx #PLAY_SOUND_CHANNEL0 | $0C

.setSoundDataChannel0

stx soundDataChannel0

SetCountdownClockSpriteLSB

lda shipLandingTimer ; get timer value for ship landing

cmp #8

bcs .setCountdownClockLSB

asl ; multiply by 8 to speed up timer icon

asl

asl

.setCountdownClockLSB

and #$38

clc

adc #<CountdownClockIcons

sta graphicPointers+2

MoveET

lda SWCHA ; read joystick values

lsr ; shift player 1 joystick values to

lsr ; lower nybbles

lsr

lsr

sta tempJoystickValues

lda etMotionValues ; get E.T. motion values

and #<(~ET_MOTION_MASK)

ora tempJoystickValues

sta etMotionValues ; set new E.T. joystick direction

bit playerState ; check current player state

bmi .checkETMotion ; branch if E.T. dead

bit INPT4 ; check player one fire button

bmi .clearETRunningStatus ; branch if fire button not pressed

lda fireResetStatus ; check to see if fire button held

bmi .checkETMotion ; branch if fire button held

ora #FIRE_BUTTON_HELD

sta fireResetStatus ; set status to show fire button held

lda SWCHA ; read joystick values

cmp #P0_NO_MOVE

bcs .skipSetETRunningFlag ; branch if joystick not moved

rol etMotionValues ; rotate E.T. motion values left

sec ; set carry and rotate value right to show

ror etMotionValues ; E.T. is running (i.e. D7 = 1)

bne .checkETMotion ; unconditional branch

.skipSetETRunningFlag

bit etMotionValues ; check E.T. motion values

bvs .checkETMotion ; branch if E.T. carried by Scientist

bit etNeckExtensionValues ; check neck extension value

bmi .checkETMotion ; branch if E.T. neck extended

dec etVertPos ; move E.T. up 1 pixel

bpl .setETNeckExtendedValue

inc etVertPos ; move E.T. down 1 pixel

.setETNeckExtendedValue

lda #NECK_EXTENDED

sta etNeckExtensionValues ; set to show E.T. neck extended

bne .checkETMotion ; unconditional branch

.clearETRunningStatus

rol fireResetStatus ; rotate fire button held status to carry

clc ; clear carry and rotate value right to

ror fireResetStatus ; clear fire button held status

rol etMotionValues ; rotate E.T. motion value left

clc ; clear carry and rotate value right to

ror etMotionValues ; set E.T. not running (i.e. D7 = 0)

.checkETMotion

bit etMotionValues ; check E.T. motion values

bvc CheckToRestrictETMovementInPit; branch if E.T. not carried Scientist

lda scientistScreenId ; get the Scientist screen id

cmp currentScreenId ; compare with current screen id

beq .setETLocationToCurrentObject

bit etMotionValues ; check E.T. motion values

bpl .setCurrentScreenId ; branch if E.T. not running

lda etMotionValues ; get E.T. motion values

and #<(~ET_CARRIED_BY_SCIENTIST)

sta etMotionValues ; release E.T. from Scientist

bne .jmpToCheckToMoveET ; unconditional branch

.setCurrentScreenId

sta currentScreenId ; set the current screen id

jsr SetCurrentScreenData

.setETLocationToCurrentObject

lda currentObjectVertPos ; get current object vertical position

sta etVertPos ; set E.T. vertical position

lda currentObjectHorizPos ; get current object horizontal position

sta etHorizPos ; set E.T. horizontal position

.jmpToCheckToMoveET

jmp CheckIfOkayToMoveET

CheckToRestrictETMovementInPit

lda etPitStatus ; get E.T. pit status values

bne .restrictETMovement ; branch if E.T. is in a pit

bit etNeckExtensionValues ; check neck extension value

bpl .jmpToCheckToMoveET ; branch if E.T. neck not extended

.restrictETMovement

and #IN_PIT_BOTTOM

beq CheckForETLevitatingInPit ; branch if E.T. not reached pit bottom

ldx etHorizPos ; get E.T.'s horizontal position

lda etMotionValues ; get E.T. motion values

and #ET_MOTION_MASK

ora #[~(MOVE_DOWN & MOVE_UP) >> 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 #<MotherShipColors+6

bcc .setMothershipColorPointer

ldx #<MotherShipColors

.setMothershipColorPointer

stx objectColorPtrs_0

.doneLandMothership

jmp SetCurrentObjectXYCoordinates

.mothershipLeavingWithoutET

dec currentObjectVertPos ; move current object up 1 pixel

lda currentObjectVertPos ; get current object vertical position

bpl .playMothershipSound

cmp #240

bcs .playMothershipSound

lda #$00

sta mothershipStatus ; clear Mothership status flags

sta graphicPointers+2

beq .doneLandMothership ; unconditional branch

.mothershipPickingUpET

ror ; shift D0 to carry

bcs .etGoingHome ; branch if Mothership leaving Earth

lda frameCount ; get the current frame count

and #3

bne .playMothershipSound

inc currentObjectVertPos ; move Mothership down 1 pixel

lda #H_MOTHERSHIP * 2

sec

sbc currentObjectVertPos

cmp #H_MOTHERSHIP / 2

bcc .setMothershipHeightForLanding

lda #H_MOTHERSHIP / 2

.setMothershipHeightForLanding

sta currentSpriteHeight

lda etVertPos ; get E.T.'s vertical position

clc ; carry clear so SBC is A = A - M ~C

sbc #4 - 1 ; A = A - 4

cmp currentObjectVertPos

bne .playMothershipSound

ror mothershipStatus ; rotate Mothership status right

sec ; set carry and rotate Mothership status

rol mothershipStatus ; left to set MOTHERSHIP_LEAVING status

bne .playMothershipSound ; unconditional branch

.etGoingHome

dec etVertPos ; move E.T. up 1 pixel

dec currentObjectVertPos ; move current object up 1 pixel

lda #H_MOTHERSHIP * 2

sec

sbc currentObjectVertPos

cmp #H_MOTHERSHIP / 2

bcc .setMothershipHeightForLeaving

lda #H_MOTHERSHIP / 2

.setMothershipHeightForLeaving

sta currentSpriteHeight

lda currentObjectVertPos ; get current object's vertical position

bpl .playMothershipSound

cmp #240

bcs .playMothershipSound

lda #$00

sta mothershipStatus ; clear Mothership status flags

jsr SetCurrentScreenToETHome

jmp SetCurrentObjectXYCoordinates

DetermineToMoveHumans

lda etNeckExtensionValues ; get neck extension value

bmi .jmpToSetETGraphicPointers ; branch if E.T. neck extended

lda #FRAME_DELAY_ONE_THIRD ; assume move humans 1 out of 3 frames

bit SWCHB ; check console switch values

bmi .calculateHumanMovementDelay ; branch if player 2 difficulty set to PRO

lda #FRAME_DELAY_ONE_FIFTH ; move humans 1 out of 5 frames

.calculateHumanMovementDelay

clc

adc humanFractionalDelay

sta humanFractionalDelay

bcs MoveHumanSprites

.jmpToSetETGraphicPointers

jmp SetETGraphicPointers

MoveHumanSprites

ldx #3

MoveHumanLoop

dex

bmi .jmpToSetETGraphicPointers

lda objectScreenId,x ; get the human's screen id

bmi MoveHumanLoop

cmp #ID_WASHINGTON_DC ; see if human is on WASHINGTON_DC screen

bne .checkForHumanOnCurrentScreen

ldy humanAttributes,x ; get the human's attributes

bpl .checkForHumanOnCurrentScreen; branch if not returning home

lda HumanTargetVertPosTable,x

sta humanTargetVertPos

ldy HumanTargetHorizPosTable,x

sty humanTargetHorizPos

cmp objectVertPos,x

bne .moveHumanToHomeArea

tya

cmp objectHorizPos,x

bne .moveHumanToHomeArea

lda #<-1

sta objectScreenId,x

txa ; move object id to accumulator

bne .checkForElliottHome ; branch if not FBI Agent

lda #<(~FBI_HAS_PHONE_PIECE) ; have FBI Agent release phone piece

and h_phonePieceAttribute

sta h_phonePieceAttribute

lda #<(~FBI_HAS_PHONE_PIECE)

and s_phonePieceAttribute

sta s_phonePieceAttribute

lda #<(~FBI_HAS_PHONE_PIECE)

and w_phonePieceAttribute

sta w_phonePieceAttribute

.checkForElliottHome

cpx #ID_ELLIOTT

bne .checkForScientistHome

bit etMotionValues ; check E.T. motion value

bvs .checkForScientistHome ; branch if E.T. carried by Scientist

bit playerState ; check player state

bmi .checkForScientistHome ; branch if E.T. is dead

lda #ELLIOTT_HAS_PHONE_PIECE

bit h_phonePieceAttribute

bne .clearElliottReturnHomeFlag ; branch if Elliott has H phone piece

bit s_phonePieceAttribute

bne .clearElliottReturnHomeFlag ; branch if Elliott has S phone piece

bit w_phonePieceAttribute

beq .checkForScientistHome ; branch if Elliott has no phone pieces

.clearElliottReturnHomeFlag

rol elliottAttributes ; rotate Elliott attributes left and

clc ; clear carry and rotate value right to

ror elliottAttributes ; clear RETURN_HOME flag (i.e. D7 = 0)

.checkForScientistHome

cpx #ID_SCIENTIST

bne .checkToClearCurrentHuman

lda etMotionValues ; get E.T. motion value

and #<(~ET_CARRIED_BY_SCIENTIST)

sta etMotionValues ; release E.T. from Scientist

.checkToClearCurrentHuman

cpx currentObjectId

bne MoveHumanLoop

lda #<-1

sta currentObjectId ; clear human as current object

lda #0

sta currentSpriteHeight

beq MoveHumanLoop ; unconditional branch

.moveHumanToHomeArea

ldy #4 ; human to go to target area

bne .moveHumanTowardTarget ; unconditional branch

.checkForHumanOnCurrentScreen

cmp currentScreenId

bne MoveHumans

ldy humanAttributes,x ; get human attribute value

bmi MoveHumans ; branch if returning home

lda objectVertPos,x

cmp HumanVerticalMaxTable,x

bcc .humanSeekOutET

dec objectVertPos,x ; move human up 1 pixel

.humanSeekOutET

ldy #0

.moveHumanTowardTarget

jsr MoveHumanTowardTarget

.nextHumanId

jmp MoveHumanLoop

MoveHumans

lda humanAttributes,x ; get human attributes

lsr ; shift MOVE_UP value to carry

bcc MoveHumanUp

lsr ; shift MOVE_DOWN value to carry

bcc MoveHumanDown

lsr ; shift MOVE_LEFT value to carry

bcs .checkForMovingRight

jmp MoveHumanLeft

.checkForMovingRight

lsr ; shift MOVE_RIGHT value to carry

bcs .nextHumanId

jmp MoveHumanRight

MoveHumanUp SUBROUTINE

dec objectVertPos,x ; move object up

bpl .nextHuman ; branch if object still on screen

ldy objectScreenId,x ; get the current screen id of the object

lda UpperScreenIdTable,y

jsr CheckForHumanOnScreen ; check to see if human on screen

bcs .moveHumanDown2Pixels ; branch if human already on the screen

sta objectScreenId,x ; set human's new screen id

cpx currentObjectId ; see if the human is the current object

bne .setHumanPosition ; branch if human not the current object

lda #<-1

sta currentObjectId ; clear human as current object (i.e. human

lda #0 ; moved off current screen)

sta currentSpriteHeight

.setHumanPosition

lda UpperScreenIdVertPosTable,y

beq .setHumanHorizontalPosition

cmp HumanVerticalMaxTable,x

bcc .setHumanVerticalPosition

lda HumanVerticalMaxTable,x

sbc #1

.setHumanVerticalPosition

sta objectVertPos,x

.setHumanHorizontalPosition

lda UpperScreenIdHorizPosTable,y

beq .checkToSetAsCurrentHuman

sta objectHorizPos,x

.checkToSetAsCurrentHuman

lda objectScreenId,x ; get the object's screen id

cmp currentScreenId ; see if object is on current screen

bne .nextHuman ; branch if object not on current screen

stx currentObjectId

jsr SetCurrentObjectData

.nextHuman

jmp MoveHumanLoop

.moveHumanDown2Pixels

inc objectVertPos,x

inc objectVertPos,x

jmp MoveHumanLoop

MoveHumanDown SUBROUTINE

inc objectVertPos,x ; move object down

lda HumanVerticalMaxTable,x ; get the object's vertical max value

cmp objectVertPos,x ; compare with object vertical position

bcs .moveNextHuman

ldy objectScreenId,x ; get the current screen id of the object

lda LowerScreenIdTable,y

jsr CheckForHumanOnScreen ; check to see if human on screen

bcs .moveHumanUp2Pixels ; branch if human already on the screen

sta objectScreenId,x ; set human's new screen id

cpx currentObjectId ; see if the human is the current object

bne .setHumanPosition

lda #<-1

sta currentObjectId ; clear human as current object (i.e. human

lda #0 ; moved off current screen)

sta currentSpriteHeight

.setHumanPosition

lda LowerScreenIdVertPosTable,y

beq .setHumanHorizontalPosition

cmp HumanVerticalMaxTable,x

bcc .setHumanVerticalPosition

lda HumanVerticalMaxTable,x

sbc #1

.setHumanVerticalPosition

sta objectVertPos,x

.setHumanHorizontalPosition

lda LowerScreenIdHorizPosTable,y

beq .checkToSetAsCurrentHuman

sta objectHorizPos,x

.checkToSetAsCurrentHuman

lda objectScreenId,x ; get the object's screen id

cmp currentScreenId ; see if object is on current screen

bne .moveNextHuman ; branch if object not on current screen

stx currentObjectId

jsr SetCurrentObjectData

.moveNextHuman

jmp MoveHumanLoop

.moveHumanUp2Pixels

dec objectVertPos,x

dec objectVertPos,x

jmp MoveHumanLoop

MoveHumanLeft SUBROUTINE

dec objectHorizPos,x ; move object left

bpl .nextHuman

ldy objectScreenId,x ; get the current screen id of the object

lda LeftScreenIdTable,y

jsr CheckForHumanOnScreen ; check to see if human on screen

bcs .moveHumanRight2Pixels ; branch if human already on the screen

sta objectScreenId,x ; set human's new screen id

cpx currentObjectId ; see if the human is the current object

bne .setHumanPosition

lda #<-1

sta currentObjectId ; clear human as current object (i.e. human

lda #0 ; moved off current screen)

sta currentSpriteHeight

.setHumanPosition

lda LeftScreenIdVertPosTable,y

beq .setHumanHorizontalPosition

cmp HumanVerticalMaxTable,x

bcc .setHumanVerticalPosition

lda HumanVerticalMaxTable,x

sbc #1

.setHumanVerticalPosition

sta objectVertPos,x

.setHumanHorizontalPosition

lda LeftScreenIdHorizPosTable,y

beq .checkToSetAsCurrentHuman

sta objectHorizPos,x

.checkToSetAsCurrentHuman

lda objectScreenId,x ; get the object's screen id

cmp currentScreenId ; see if object is on current screen

bne .nextHuman ; branch if object not on current screen

stx currentObjectId

jsr SetCurrentObjectData

.nextHuman

jmp MoveHumanLoop

.moveHumanRight2Pixels

inc objectHorizPos,x

inc objectHorizPos,x

jmp MoveHumanLoop

MoveHumanRight SUBROUTINE

inc objectHorizPos,x ; move object right

ldy objectHorizPos,x ; get the object's horizontal position

cpy #XMAX + 1

bcc .nextHuman

ldy objectScreenId,x ; get the current screen id of the object

lda RightScreenIdTable,y

jsr CheckForHumanOnScreen ; check to see if human on screen

bcs .moveHumanLeft2Pixels ; branch if human already on the screen

sta objectScreenId,x ; set human's new screen id

cpx currentObjectId ; see if the human is the current object

bne .setHumanPosition

lda #<-1

sta currentObjectId ; clear human as current object (i.e. human

lda #0 ; moved off current screen)

sta currentSpriteHeight

.setHumanPosition

lda RightScreenIdVertPosTable,y

beq .setHumanHorizontalPosition

cmp HumanVerticalMaxTable,x

bcc .setHumanVerticalPosition

lda HumanVerticalMaxTable,x

sbc #1

.setHumanVerticalPosition

sta objectVertPos,x

.setHumanHorizontalPosition

lda RightScreenIdHorizPosTable,y

beq .checkToSetAsCurrentHuman

sta objectHorizPos,x

.checkToSetAsCurrentHuman

lda objectScreenId,x ; get the object's screen id

cmp currentScreenId ; see if object is on current screen

bne .nextHuman ; branch if object not on current screen

stx currentObjectId

jsr SetCurrentObjectData

.nextHuman

jmp MoveHumanLoop

.moveHumanLeft2Pixels

dec objectHorizPos,x

dec objectHorizPos,x

jmp MoveHumanLoop

SetETGraphicPointers

bit playerState ; check player state

bpl .setETGraphicPointersNotDead ; branch if E.T. is not dead

lda #<ETDead_1

sta etGraphicPointers1

lda #<ETDead_0

sta etGraphicPointers0

lda #12 / 2

sta etHeight

bne .setETSpritePtrMSB ; unconditional branch

.setETGraphicPointersNotDead

lda etNeckExtensionValues ; get neck extension value

bpl .setNormalETGraphicPointers ; branch if neck not extended

and #3

tax

lda ETNeckExtensionHeightTable,x

sta etHeight

lda ETNeckExtensionLSBTable_A,x

sta etGraphicPointers0

lda ETNeckExtensionLSBTable_B,x

sta etGraphicPointers1

bne .setETSpritePtrMSB ; unconditional branch

.setNormalETGraphicPointers

lda #18 / 2

sta etHeight

lda SWCHA ; read joystick values

cmp #P0_NO_MOVE

bcs .setToETRestSpritePtrs ; branch if E.T. not moving

lda #3

bit etMotionValues ; check E.T. motion value

bpl .determineETAnimationIndex ; branch if E.T. is not running

lsr

.determineETAnimationIndex

and frameCount

bne .setETSpritePtrMSB

ldx etAnimationIndex ; get E.T. animation table index

dex

bpl .setETAnimationGraphicPtrs ; branch if index didn't wrap around

ldx #2

.setETAnimationGraphicPtrs

stx etAnimationIndex

lda ETAnimationLSBTable_A,x

sta etGraphicPointers0

lda ETAnimationLSBTable_B,x

sta etGraphicPointers1

bne .setETSpritePtrMSB ; unconditional branch

.setToETRestSpritePtrs

lda #<ETWalkSprite_A0

sta etGraphicPointers0

lda #<ETWalkSprite_B0

sta etGraphicPointers1

.setETSpritePtrMSB

lda #>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 #<ETWalkSprite_A0

sta etGraphicPointers0

lda #<ETWalkSprite_B0

sta etGraphicPointers1

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

lda #>DisplayKernel

sta bankSwitchRoutinePtr+1

lda #LDA_ABS

sta displayKernelBankSwitch

lda #<BANK1STROBE

sta bankSwitchStrobe

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 <WideDiamondPitPF1Graphics,<EightPitGraphics,<ArrowPitPF1Graphics

.byte <FourDiamondPitGraphics,<ForestPF1Graphics,<WashingtonPF1Graphics

.byte <PitPF1Graphics,<ETHomePF1Graphics

PF2GraphicPointersLSB

.byte <WideDiamondPitPF2Graphics,<EightPitGraphics,<ArrowPitPF2Graphics

.byte <FourDiamondPitGraphics,<ForestPF2Graphics,<WashingtonPF2Graphics

.byte <PitPF2Graphics,<ETHomePF2Graphics

LeftScreenIdHorizPosTable

.byte 119,119,119,119,68,68

RightScreenIdHorizPosTable

.byte 1,1,1,1,58,58

UpperScreenIdHorizPosTable

.byte 0,117,0,4,0,0

LowerScreenIdHorizPosTable

.byte 0,4,0,117,0,0

LeftScreenIdVertPosTable

.byte 0,0,0,0,4,53

RightScreenIdVertPosTable

.byte 0,0,0,0,4,53

UpperScreenIdVertPosTable

.byte 8,36,57,36,8,57

LowerScreenIdVertPosTable

.byte 2,28,50,28,2,50

LeftScreenIdTable

.byte ID_EIGHT_PITS,ID_ARROW_PITS,ID_WIDE_DIAMOND_PITS

.byte ID_FOUR_DIAMOND_PITS,ID_WIDE_DIAMOND_PITS,ID_EIGHT_PITS

RightScreenIdTable

.byte ID_WIDE_DIAMOND_PITS,ID_FOUR_DIAMOND_PITS,ID_EIGHT_PITS

.byte ID_ARROW_PITS,ID_EIGHT_PITS,ID_WIDE_DIAMOND_PITS

UpperScreenIdTable

.byte ID_FOREST,ID_FOREST,ID_FOREST,ID_FOREST

.byte ID_FOUR_DIAMOND_PITS,ID_FOUR_DIAMOND_PITS

LowerScreenIdTable

.byte ID_WASHINGTON_DC,ID_WASHINGTON_DC,ID_WASHINGTON_DC

.byte ID_WASHINGTON_DC,ID_ARROW_PITS,ID_ARROW_PITS

HumanTargetHorizPosTable

.byte FBI_AGENT_HORIZ_TARGET

.byte ELLIOTT_HORIZ_TARGET

.byte SCIENTIST_HORIZ_TARGET

HumanTargetVertPosTable

.byte FBI_AGENT_VERT_TARGET

.byte ELLIOTT_VERT_TARGET

.byte SCIENTIST_VERT_TARGET

HumanVerticalMaxTable

.byte FBI_AGENT_VERT_MAX

.byte ELLIOTT_VERT_MAX

.byte SCIENTIST_VERT_MAX

FlowerAnimationLSBTable_A

.byte <Flower_A0,<Flower_A1,<Flower_A2,<Flower_A3

FlowerAnimationLSBTable_B

.byte <Flower_B0,<Flower_B1,<Flower_B2,<Flower_B3

ObjectGraphicPointersMSB

.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 <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_1

.byte <FBIAgent_4,<Elliott_6,<Scientist_5,<H_PhonePiece_1,<S_PhonePiece_1

.byte <W_PhonePiece_1,<Flower_B0,<MotherShip,<Yar_0,<Yar_1,<IndySprite

ObjectColorPointersMSB

.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 <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_B

.byte <FBIAgentColors_B

.byte <ElliottColors_B

.byte <ScientistColors_B

.byte <PhonePieceColors_B

.byte <PhonePieceColors_B

.byte <PhonePieceColors_B

.byte <FlowerColors

.byte <MotherShipColors

.byte <YarColor

.byte <YarColor

.byte <IndyColors

HumanEndAnimationTable

.byte <FBIAgent_4

.byte <Elliott_5 + (H_ELLIOTT / 2) - 1

.byte <Scientist_5

SpriteHeightValues

.byte H_FBIAGENT/2, H_ELLIOTT/2, H_SCIENTIST/2, H_PHONE_PIECES/2

.byte H_PHONE_PIECES/2, H_PHONE_PIECES/2, H_FLOWER/2, H_MOTHERSHIP/2

.byte H_YAR/2, H_YAR/2, H_INDY/2

HumanAnimationRate

.byte 3,3,3

ETAnimationLSBTable_A

.byte <ETWalkSprite_A0,<ETWalkSprite_A1,<ETWalkSprite_A2

ETAnimationLSBTable_B

.byte <ETWalkSprite_B0,<ETWalkSprite_B1,<ETWalkSprite_B2

HumanDirectionTable

.byte NO_MOVE,MOVE_LEFT>>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 <ETExtensionSprite_A0,<ETExtensionSprite_A1

.byte <ETExtensionSprite_A2,<ETExtensionSprite_A3

ETNeckExtensionLSBTable_B

.byte <ETExtensionSprite_B0,<ETExtensionSprite_B1

.byte <ETExtensionSprite_B2,<ETExtensionSprite_B3

CandyStatusMaskTable

.byte ~FOUR_DIAMOND_PITS_CANDY

.byte ~EIGHT_PITS_CANDY

.byte ~ARROW_PITS_CANDY

.byte ~WIDE_DIAMOND_PITS_CANDY

CandyStatusValueTable

.byte FOUR_DIAMOND_PITS_CANDY

.byte EIGHT_PITS_CANDY

.byte ARROW_PITS_CANDY

.byte WIDE_DIAMOND_PITS_CANDY

ExtraCandyReductionTable

.byte 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0

ETNeckExtensionHeightTable

.byte 10,11,12,13

PlayMothershipSound

lda frameCount ; get the current frame count

ora #$18

sta AUDF0

and #7

sta AUDF1

lda frameCount ; get the current frame count

lsr

and #$1F

cmp #16

bcc .setVolumeAndChannel

eor #$0F

.setVolumeAndChannel

sta AUDV0

eor #$0F

sta AUDV1

lda #$0F

sta AUDC0

lda #$0D

sta AUDC1

rts

SetCurrentObjectData

lda SpriteHeightValues,x

sta currentSpriteHeight

lda ObjectGraphicPointersLSB_0,x

sta objectGraphicPtrs_0

lda ObjectGraphicPointersLSB_1,x

sta objectGraphicPtrs_1

lda ObjectGraphicPointersMSB,x

sta objectGraphicPtrs_0+1

sta objectGraphicPtrs_1+1

lda ObjectColorPointersLSB_A,x

sta objectColorPtrs_0

lda ObjectColorPointersLSB_B,x

sta objectColorPtrs_1

lda ObjectColorPointersMSB,x

sta objectColorPtrs_0+1

sta objectColorPtrs_1+1

bit easterEggSpriteFlag ; check Easter Egg sprite flags

bmi .doneSetCurrentObjectData ; branch if showing special object in pit

lda objectHorizPos,x

sta currentObjectHorizPos

lda objectVertPos,x

sta currentObjectVertPos

.doneSetCurrentObjectData

rts

ThemeMusicFrequencyTable

.byte LEAD_A3,LEAD_A3,LEAD_A3,LEAD_A3,LEAD_E4,LEAD_E4,LEAD_E4,LEAD_E4

.byte LEAD_D4,LEAD_C4_SHARP,LEAD_H3,LEAD_C4_SHARP,LEAD_A3,LEAD_A3,LEAD_A3

.byte LEAD_A3,LEAD_E3_2,LEAD_E3_2,LEAD_E3_2,LEAD_E3_2,LEAD_E3_2,LEAD_E3_2

.byte LEAD_E3_2,LEAD_E3_2,LEAD_F3_SHARP,LEAD_F3_SHARP,LEAD_F3_SHARP

.byte LEAD_F3_SHARP,LEAD_F4_SHARP,LEAD_F4_SHARP,LEAD_F4_SHARP,LEAD_F4_SHARP

.byte LEAD_E4,LEAD_D4_SHARP,LEAD_C4_SHARP,LEAD_D4_SHARP,LEAD_H3,LEAD_H3

.byte LEAD_H3,LEAD_H3,LEAD_F3_SHARP,LEAD_F3_SHARP,LEAD_F3_SHARP

.byte LEAD_F3_SHARP,LEAD_G3_SHARP,LEAD_G3_SHARP,LEAD_G3_SHARP,LEAD_H3

.byte LEAD_C4_SHARP,LEAD_A3,LEAD_E3_2,LEAD_E3_2,LEAD_E3_2,LEAD_E3_2

.byte LEAD_E3_2

BOUNDARY 0

PowerZoneMap

.byte ID_WARP_UP_ZONE << 4 | ID_RETURN_HOME_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_LANDING_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_BLANK_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_LANDING_ZONE << 4 | ID_EAT_CANDY_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_CALL_ELLIOTT_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_LANDING_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_FIND_PHONE_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_RETURN_HOME_ZONE

.byte ID_CALL_SHIP_ZONE << 4 | ID_CALL_ELLIOTT_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_FIND_PHONE_ZONE

.byte ID_BLANK_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_LANDING_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_CALL_ELLIOTT_ZONE

.byte ID_CALL_SHIP_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_CALL_ELLIOTT_ZONE

.byte ID_CALL_SHIP_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_LANDING_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_LANDING_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_BLANK_ZONE << 4 | ID_EAT_CANDY_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_BLANK_ZONE << 4 | ID_RETURN_HOME_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_LANDING_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_BLANK_ZONE << 4 | ID_RETURN_HOME_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_EAT_CANDY_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_LANDING_ZONE << 4 | ID_FIND_PHONE_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_LANDING_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_CALL_ELLIOTT_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_FIND_PHONE_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_EAT_CANDY_ZONE

.byte ID_CALL_SHIP_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_LANDING_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_CALL_SHIP_ZONE << 4 | ID_EAT_CANDY_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_FIND_PHONE_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_CALL_ELLIOTT_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_RETURN_HOME_ZONE

.byte ID_LANDING_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_LANDING_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_CALL_SHIP_ZONE << 4 | ID_EAT_CANDY_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_LANDING_ZONE << 4 | ID_RETURN_HOME_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_WARP_UP_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_FIND_PHONE_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_RETURN_HOME_ZONE << 4 | ID_LANDING_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_RIGHT_ZONE

.byte ID_CALL_SHIP_ZONE << 4 | ID_RETURN_HOME_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_FIND_PHONE_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_BLANK_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_LANDING_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_WARP_DOWN_ZONE

.byte ID_CALL_ELLIOTT_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_WARP_DOWN_ZONE << 4 | ID_WARP_UP_ZONE

.byte ID_BLANK_ZONE << 4 | ID_WARP_LEFT_ZONE

.byte ID_EAT_CANDY_ZONE << 4 | ID_LANDING_ZONE

.byte ID_WARP_RIGHT_ZONE << 4 | ID_CALL_SHIP_ZONE

.byte ID_WARP_LEFT_ZONE << 4 | ID_FIND_PHONE_ZONE

.byte ID_BLANK_ZONE << 4 | ID_RETURN_HOME_ZONE

CheckForHumanOnScreen

cmp fbiScreenId ; compare with FBI screen id

beq .doneCheckForHumanOnScreen

cmp elliottScreenId ; compare with Elliott screen id

beq .doneCheckForHumanOnScreen

cmp scientistScreenId ; compare with Scientist screen id

beq .doneCheckForHumanOnScreen

clc ; clear carry to show human not on screen

.doneCheckForHumanOnScreen

rts

IncrementETEnergy

sed

sty energyIncTensValue

lda etEnergy+1

clc

adc energyIncTensValue

sta etEnergy+1

stx energyIncHundredsValue

lda etEnergy

adc energyIncHundredsValue

sta etEnergy

bcc .doneEnergyIncrement

lda #MAX_ENERGY

sta etEnergy

sta etEnergy+1

.doneEnergyIncrement

cld

rts

SetCurrentScreenToETHome

lda #ID_ET_HOME

sta currentScreenId ; set the current screen id

sta frameCount

jsr SetCurrentScreenData

ldx #ID_ELLIOTT

stx currentObjectId ; set Elliott on current screen

jsr SetCurrentObjectData

lda #60

sta currentObjectHorizPos ; set Elliott's horizontal position

sta etHorizPos ; set E.T. horizontal position

lda #15

sta currentObjectVertPos ; set Elliott's vertical position

lda #48

sta etVertPos ; set E.T. vertical position

lda #$00

sta collectedCandyScoring ; clear collected candy scoring flags

sta etHomeElliottMovement ; clear Elliott movement flags

rts

DecrementETEnergy

sty energyDecTensValue

sed

lda etEnergy+1

sec

sbc energyDecTensValue

sta etEnergy+1

stx energyDecHundredsValue

lda etEnergy

sbc energyDecHundredsValue

sta etEnergy

bcs .doneEnergyDecrement

lda #$00

sta etEnergy

sta etEnergy+1

rol playerState ; rotate E.T. death flag to carry

sec ; set carry

ror playerState ; rotate right to set E.T. death flag

.doneEnergyDecrement

cld

rts

IF COMPILE_VERSION = NTSC

.org BANK0TOP + 4096 - 6, 0

ELSE

.org BANK0TOP + 4096 - 8, 0

.byte 0, -1

ENDIF

.word Start

.word Start

.word Start

;============================================================================

; R O M - C O D E (BANK 1)

;============================================================================

SEG Bank1

.org BANK1TOP

.rorg BANK1_REORG

BANK1Start

lda BANK0STROBE

jmp Start

.checkForEndGameKernel

cpx #64 ; 2

bcc .skipObjectDraw ; 2≥

jmp ScoreKernel ; 3

.skipObjectDraw

lda #0 ; 2

sta GRP0 ; 3 = @13

sta nextObjectGraphicData ; 3

lda frameCount ; 3 get the current frame count

lsr ; 2

and #$1F ; 2

ora #$40 ; 2

sta COLUP0 ; 3

lda temp ; 3 waste 3 cycles

nop ; 2

jmp .checkToDrawET ; 3

GameKernel

cpx candyVertPos ; 3

php ; 3 = @41 enable/disable BALL

cpx phonePieceMapVertPos ; 3

php ; 3 = @47 enable/disable M1

cpx etHeartVertPos ; 3

php ; 3 = @53 enable/disable M0

inx ; 2 increment scan line count

ldy nextETGraphicData ; 3

JumpIntoGameKernel

txa ; 2 move scan line count to accumulator

sec ; 2

sbc currentObjectVertPos ; 3 subtract object vertical position

cmp currentSpriteHeight ; 3 compare with sprite height

sty GRP1 ; 3 draw ET graphic data

sta WSYNC

;--------------------------------------

bcs .checkForEndGameKernel ; 2≥ skip object draw if greater

tay ; 2

lda (objectGraphicPtrs_0),y; 5

sta GRP0 ; 3 = @12

lda (objectColorPtrs_0),y ; 5

sta COLUP0 ; 3 = @20

lda (objectGraphicPtrs_1),y; 5

sta nextObjectGraphicData ; 3

lda (objectColorPtrs_1),y ; 5

sta nextObjectColorData ; 3

.checkToDrawET

txa ; 2

ldx #<ENABL ; 2

txs ; 2 point stack to ENABL

tax ; 2

sec ; 2

sbc etVertPos ; 3

cmp etHeight ; 3

bcs .skipETDraw ; 2≥

tay ; 2

lda (etGraphicPointers1),y ; 5

sta nextETGraphicData ; 3

lda (etGraphicPointers0),y ; 5

sta GRP1 ; 3

.drawNextObjectData

sta WSYNC

;--------------------------------------

lda nextObjectGraphicData ; 3

sta GRP0 ; 3 = @06

lda nextObjectColorData ; 3

sta COLUP0 ; 3 = @12

txa ; 2

tay ; 2

lda (pf1GraphicPtrs),y ; 5

sta PF1 ; 3 = @24

lda (pf2GraphicPtrs),y ; 5

sta PF2 ; 3 = @32

jmp GameKernel ; 3

.skipETDraw

lda #0 ; 2

sta GRP1 ; 3 = @60

sta nextETGraphicData ; 3

beq .drawNextObjectData ; 3 unconditional branch

TitleScreenKernel

.waitLoop

sta WSYNC

;--------------------------------------

inx ; 2

cpx #16 ; 2

bcc .waitLoop ; 2≥

lda #LT_RED+4 ; 2

sta COLUP0 ; 3 = @11

sta COLUP1 ; 3 = @14

lda #MSBL_SIZE2 | QUAD_SIZE; 2

sta NUSIZ0 ; 3 = @19

sta NUSIZ1 ; 3 = @22

lda #NO_REFLECT ; 2

sta REFP0 ; 3 = @27

sta REFP1 ; 3 = @30

ldx #15 ; 2

sta WSYNC

;--------------------------------------

.drawETTitle

lda ETTitle_E,x ; 4

sta GRP0 ; 3 = @07

lda ETTitle_T,x ; 4

sta GRP1 ; 3 = @14

cpx #2 ; 2

bcs .nextETTileScanline ; 2≥

lda #$0F ; 2 enable missiles for dots in E.T.

sta ENAM0 ; 3 = @23

sta ENAM1 ; 3 = @26

.nextETTileScanline

sta WSYNC

;--------------------------------------

dex ; 2

sta WSYNC

;--------------------------------------

bpl .drawETTitle ; 2≥

lda #0 ; 2

sta GRP0 ; 3 = @07

sta GRP1 ; 3 = @10

sta ENAM0 ; 3 = @13

sta ENAM1 ; 3 = @16

ldx #47 ; 2

.upperTitleWaitLoop

sta WSYNC

;--------------------------------------

inx ; 2

cpx #64 ; 2

bcc .upperTitleWaitLoop ; 2≥

sta WSYNC

;--------------------------------------

sta HMOVE ; 3

lda #THREE_COPIES ; 2

ldy #NO_REFLECT ; 2

sty REFP1 ; 3 = @10

sta NUSIZ0 ; 3 = @13

sta NUSIZ1 ; 3 = @16

sta VDELP0 ; 3 = @19 vertically delay players

sta VDELP1 ; 3 = @22

sty GRP0 ; 3 = @25 clear plaer graphics

sty GRP1 ; 3 = @28

sty GRP0 ; 3 = @31

sty GRP1 ; 3 = @34

nop ; 2

sta RESP0 ; 3 = @39 coarse position player 0 to pixel 117

sta RESP1 ; 3 = @42 coarse position player 1 to pixel 126

sty HMP1 ; 3 = @45

lda #HMOVE_R1 ; 2

sta HMP0 ; 3 = @50 position player 0 to pixel 118

sty REFP0 ; 3 = @53

sta WSYNC

;--------------------------------------

sta HMOVE ; 3

lda #>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 #<TitleETGraphics_1 ; 2

sta graphicPointers ; 3

lda #<TitleETGraphics_2 ; 2

sta graphicPointers+2 ; 3

lda #<TitleETGraphics_3 ; 2

sta graphicPointers+4 ; 3

lda #<TitleETGraphics_4 ; 2

sta graphicPointers+6 ; 3

lda #<TitleETGraphics_5 ; 2

sta graphicPointers+8 ; 3

lda #<TitleETGraphics_0 ; 2

sta graphicPointers+10 ; 3

sta WSYNC

;--------------------------------------

lda #LT_BROWN+10 ; 2

sta COLUP0 ; 3 = @05

sta COLUP1 ; 3 = @08

lda #H_ET_GRAPH-1 ; 2

sta loopCount ; 3

jsr SixDigitKernel ; 6

ldx #110 ; 2 = @08

.lowerTitleWaitLoop

sta WSYNC

;--------------------------------------

inx ; 2

cpx #128 ; 2

bcc .lowerTitleWaitLoop ; 2≥

ScoreKernel

sta WSYNC

;--------------------------------------

ldx #$FF ; 2

txs ; 2 reset stack to beginning

stx PF1 ; 3 = @07

stx PF2 ; 3 = @10

inx ; 2 x = 0

stx GRP0 ; 3 = @15 clear player graphic data

stx GRP1 ; 3 = @18

stx ENAM0 ; 3 = @21 disable missile graphics

stx ENAM1 ; 3 = @24

stx ENABL ; 3 = @27 disable BALL

sta WSYNC

;--------------------------------------

lda frameCount ; 3 get the current frame count

and #7 ; 2

bne .skipFlowerAnimation ; 2≥

lda flowerState ; 3 get flower state

bpl .skipFlowerAnimation ; 2≥ branch if flower not revived

and #<(~FLOWER_REVIVED) ; 2

cmp #FLOWER_REVIVE_ANIMATION; 2

bcs .skipFlowerAnimation ; 2≥

adc #FLOWER_REVIVED | (1 * 16); 2 increment flower animation frame

sta flowerState ; 3

lda #PLAY_SOUND_CHANNEL0 | $03; 2

sta soundDataChannel0 ; 3

.skipFlowerAnimation

sta WSYNC

;--------------------------------------

lda #GREEN ; 2

sta COLUP0 ; 3 = @05

sta COLUP1 ; 3 = @08

ldx #HMOVE_0 ; 2

stx HMP0 ; 3 = @13

sta WSYNC

;--------------------------------------

stx PF0 ; 3 = @03 remove border from around screen

stx COLUBK ; 3 = @06 set background color to BLACK

stx PF1 ; 3 = @09

stx PF2 ; 3 = @12

sta WSYNC

;--------------------------------------

sta HMOVE ; 3

lda #THREE_COPIES ; 2

ldy #NO_REFLECT ; 2

sty REFP1 ; 3 = @10

sta NUSIZ0 ; 3 = @13

sta NUSIZ1 ; 3 = @16

sta VDELP0 ; 3 = @19

sta VDELP1 ; 3 = @22

sty GRP0 ; 3 = @25

sty GRP1 ; 3 = @28

sty GRP0 ; 3 = @31

sty GRP1 ; 3 = @34

nop ; 2

sta RESP0 ; 3 = @39 coarse position GRP0 to pixel 117

sta RESP1 ; 3 = @42 coarse position GRP1 to pixel 126

sty HMP1 ; 3 = @45

lda #HMOVE_R1 ; 2

sta HMP0 ; 3 = @50 GRP0 now set to pixel 127

sty REFP0 ; 3 = @53

sta WSYNC

;--------------------------------------

sta HMOVE ; 3

lda heldCandyPieces ; 3 get number of candy pieces held by E.T.

sta tempNumberFonts ; 3

lda etEnergy ; 3

sta tempNumberFonts+1 ; 3

lda etEnergy+1 ; 3

sta tempNumberFonts+2 ; 3

lda currentScreenId ; 3 get the current screen id

cmp #ID_TITLE_SCREEN ; 2

bne .setToShowScoreOrEnergy; 2≥

bit gameState ; 3 check the game state

bmi .setToShowScoreOrEnergy; 2≥ branch if player loss the game

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 temp