Fixing E.T. The Extra-Terrestrial for the Atari 2600
[banner.png]
If you're reading this page, chances are that you're already well aware
that E.T. for the Atari 2600 is one of the most reviled games ever
made. I never understood why. As a child, it was one of my favorite
games. I still think it's a good game. [1]Apparently, [2]I'm not alone.
On this page I'm going to briefly explore why people hate E.T., and how
the game can be fixed.
Contents:
* [3]In case you can't wait
* [4]Downloads
* [5]Why people hate E.T.
* [6]Why people fall in wells
* [7]Fixing the falling problem
* [8]Dealing with the difficulty
* [9]E.T. is NOT green
* [10]Spit and polish
* [11]A new feature
* [12]Squashing 30-year-old bugs
* [13]Ninja E.T. easter egg
* [14]A new game mode
* [15]Summary of changes
* [16]Conclusion
In case you can't wait
Open your NTSC E.T. ROM in a hex editor and make the following changes:
-------------------------------------------
- E.T. is Not Green
-------------------------------------------
17FA: FE FC F8 F8 F8
1DE8: 04
-------------------------------------------
- Difficulty Fix (Walk, Run, Hover)
-------------------------------------------
0707: A4 F8
071B: A4 F8
0685: A4 F8
0FEF: AD 82 02 29 08 4C 4E BB
0B4D: 60 4A 4A 4A 49 01 85 F8
04F0: A5 81 29 1E
-------------------------------------------
- Falling Fix
-------------------------------------------
002A: 4C F6 BB
0BF6: A5 9C 69 07 85 F6 4C AB BC
1013: 05 D9 65 E3 65 F6 85 8B 4C 4B F0
101E: 08 E4 8B D0 06 24 13 70 02 85 2C E4 9E 08 E8
102D: A4 86 8A
1034: 85 02 84 1C
1060: A5 87 85 1B A5 88 85 06 8A A8 B1 BA 85 0E B1 BC
1070: 85 0F E4 9F 4C 1E F0
18F3: 2E F0
0B40: A9 EF
07ED: E9 04
0BA5: 22
--------------------------------------------
- BUG FIXES
--------------------------------------------
- Don't Fall Leaving Forest on Right
-------------------------------------------
0D54: 4A
0D6C: 01
-------------------------------------------
- Ship Shouldn't Crush Elliott
-------------------------------------------
07BD: 4C D9 BA
-------------------------------------------
- FIX SCORING TO MATCH MANUAL
-------------------------------------------
058E: 85 F4 A5 DD 85 F5 65 F4 85 DD 69 10 EA EA
1382: 4C 9D F3
1395: A9 99 85 D3 85 D4 D0 09 A5 F8 D0 02 AA A8
13BD: A9 01 05 DE 85 DE A2 07 A0 70 20 41 F3 EA
1341: A5 D2 C9 0A F0 08 E9 10 85 D2 A2 04 A0 90 A5 DD
1351: F8 4C E9 F7
17E9: C9 1F 90 0A 8A 09 10 AA A5 D3 E9 07 85 D3 D8 60
13FD: A9 99 85 D3 85 D4 A9 00 85 F4 85 E3
147A: A9 00 85 DD 85 D9 85 94 A5 29 C5 DC B0 02 A5 DC
148A: 4C A5 F4
Note: If you don't include the difficulty fix, make
the following change to the scoring fix:
139D: EA EA EA EA EA EA
-------------------------------------------
- Easter Egg - Ninja E.T.
-------------------------------------------
148A: A5 F4 C5 F5 D0 0C C9 03 D0 08 A9 AA 85 D2 85 D3
149A: 85 D4 4C A5 F4 EA EA EA
--------------------------------------------
- Add Extra Game Option - Scientist Only
--------------------------------------------
0471: E0 05
02ED: 29 01 F0 09
Special thanks to AtariAge users Nukey Shay, Random Terrain, KevinMos3,
iesposta, and roadrunner for their excellent comments and suggestions.
Downloads
If you don't know how to use a hex editor, or if you're just lazy, you
can download a modified .bin file here:
* [17]ET_Fixed_Final.bin
* [18]ET.bin (unmodified)
NOTE: If you want to play the game with the original difficulty, set
the B&W / Color switch to the B&W position. This will completely
disable the difficulty fix, but leave the other changes in place.
Why do people hate E.T.?
So, why do people hate E.T.? When it was released, it was well ahead of
its time. It pioneered a lot of concepts that we take for granted in
games today, but were unheard of in 1982 (Atari's Adventure and Haunted
House had some of these features, but not all):
* It was one of the first home video games with a title screen.
* It featured an open-ended world with gameplay focused on
exploration.
* It was completely non-violent. You can't hurt the bad-guys, and
they can't hurt you. There isn't even any competition!
* You could complete the game. There are also several goals that you
need to complete to win the game.
* There were multiple ways to complete goals. You can actually finish
the game without falling in a single well.
* The game not only had an ending, it also featured an animated
cut-scene as a reward.
* The game featured optional additional goals to complete (side
quests).
While that seems like a great list of features, players in 1982 weren't
prepared for that much change. You really needed to read the manual to
understand the game and how to play it. As younger children were the
primary audience, it's no surprise that it wasn't well received.
Of course, that doesn't explain why the game is so hated today. If we
can identify the reasons why, we can try to address them. Here are the
problems this page will address:
* The game seems incredibly complex. This isn't a real problem. Once
you learn how to play, it's really very simple. You just need to
[19]read the manual, or watch a [20]tutorial video, to understand
it.
* The game is incredibly hard. It's difficult for novices to complete
the game even on mode 3, the easiest setting. Fortunately, this can
be fixed.
* You spend a lot of time accidentally falling in to wells. I believe
that I know reason why this happens to so many people, and what can
be done to fix it.
* E.T. is not green. I'm really surprised that this isn't a common
complaint. We'll fix that as well.
Why people accidentally fall in to the wells
The myth: A lot of people blame poor collision detection for this
problem. That is simply not true. The collision detection in E.T. is
perfect. There are no bounding boxes like in more modern games.
Collision detection happens at the pixel level. You can't get any
better than that. If you fall in to a well, it's because your player
character visually overlaps it.
The actual problem: We don't want pixel-perfect collision detection!
The reason that people so easily fall in to wells is that they don't
expect to fall when, for example, E.T.'s head overlaps a well. After
all, his feet are clearly on solid ground!
[figure1.png]
Figure 1: E.T. appears to be standing in front of a well. However,
because collision detection is pixel perfect and some of the sprite
pixels overlap the well pixels, E.T. is sure to fall. This is a bad
thing.
E.T. uses a weird perspective not well suited for pixel-perfect
collision detection. It's an overhead view, but we see E.T. and the
other characters from the side. An [21]article on tvtropes.org calls
this "Three Quarters View" and describes it as a "tilted bird's eye
view perspective".
Nintendo's The Legend of Zelda uses the same perspective, but you don't
hear a lot of complaints about accidentally running in to enemies or
obstacles.
[figure2.png]
Figure 2: A similar perspective is used in The Legend of Zelda though
it somehow manages to be even stranger. The floor tiles and blocks, the
outer walls, and the player character are all shown from different
perspectives. This doesn't hurt the game in any way, it actually makes
it better.
Zelda uses a neat trick to make the perspective feel more natural when
playing and less like the characters are lying on their sides.
Collision detection is designed around where your player character
appears to be, not by what sprites happens to overlap. In Zelda, when
you approach an obstacle from the south, for example, it doesn't
obstruct your movement until about half of your sprite overlaps it.
[figure3.png]
Figure 3: (Left) Our player character appears to be standing in the row
of floor tiles below the block. The player assumes that they are able
to move forward as there are clearly no obstacles in the way. However,
if collision detection was pixel-perfect they would be obstructed by
the block. (Right) Thanks to good design, we can do the obvious: walk
on the tiles in front of the block.
If we can modify the collision detection in E.T. so that it's not pixel
perfect, but based on where the player character appears to be, we can
give the player the same intuitive advantages that Zelda players enjoy.
In the case of E.T., such a change is simple: we just need to ensure
that only collisions with E.T.'s feet are detected. The game will feel
much more natural, and players won't fall in to wells accidentally
nearly as often.
Fixing the falling problem
The fix is pretty simple. All we need to do is clear the collision
latches sometime before we finish drawing the E.T. sprite. One or two
scan lines before the end should work out great. That may not seem like
a lot, but it really is the most appropriate place. It'll also let us
stand on the inner edge of the "v" shaped wells. I've always thought
you should be able to do that.
[figure4.png]
Figure 4: Where no extra-terrestrial has gone before!
We don't have access to the game's source code and the disassembler I
have for 2600 games won't work if the game is over 4k. If we're going
to fix the problem, we've got to modify the ROM somehow. A good hex
editor coupled with the nifty debugger included in [22]Stella and we're
ready to go. That may be a bit optimistic. As every Atari 2600
developer knows, you rarely have and abundance of free space on the ROM
and routines (particularly in the kernel) are generally kept very tight
with little or no wasted code.
To make matters worse, to implement our fix we'll need to add some code
to the kernel. If you're following along, take a look at kernel code
starting at 1006. As it's unlikely that Howard Scott Warshaw (the
developer) included some useless code for us to replace, we may want to
consider hijacking a jump, running our routine in some unused spot on
the ROM, and returning. A quick look presents us with a candidate at
1074. We could run our routine and jump back to 1022. Unfortunately,
time is also an important factor, especially in the kernel. We don't
even have enough time to jump out and return, let alone run our
routine. We could use an extra scan line, but that does far more harm
than just making our graphics look blocky: candy won't appear and hint
areas, for the most part, won't display the location of phone parts.
Give it a try if you're feeling ambitious, just don't forget to
increment X or you'll end up with a flickering mess!
Back to the kernel we go to see what we can change. A few rounds with
the debugger and you'll notice that the code at 101C to 101E ultimately
does nothing as there is a TXA right after the jump. Useless code in
the kernel is unusual. Looking a little further back, we find that the
code starting at 1013 sets COLUP0 to some inexplicably twisted value
based on whatever is stored in 81. This is weird because 88 is used to
hold that color, as we can see from the code at 1047 to 1049. Even
stranger, this code is never called on lines where we draw GRP0. The
code from 1013 to 101E appears to do nothing but burn a few cycles.
(That's exactly what it's supposed to do, for timing.) After a good bit
of double-checking, it becomes obvious that can safely replace it. This
is great news for us as that means we have a whole 12 bytes we can
change! Since X holds the current y position, that's more than we need
for our routine. Lucky.
The idea is to strobe CXCLR before we draw the last line of the sprite
so that any collisions recorded to that point are eliminated. The
effect will be that only collisions with E.T.'s feet will be detected.
The code is pretty simple, 9C holds E.T.'s y position so we just need
to subtract some amount of E.T.'s height from our current y position
and compare it to the value at 9C to see if we can safely clear the
collision latches:
1013: TXA ; 2 ; 8A
1014: SBC #$08 ; 2 ; E9 08
1016: CMP $9C ; 3 ; C5 9C
1018: BCS $F01C ; 2 ; B0 02
101A: STA CXCLR ; 3 ; 85 2C
Give it a try. It looks like we're done, but there are still a few
problems:
* We can't pick-up phone parts. (We'll fix this a little later.)
* We need to step on candy to collect it. (This is a problem we can't
yet avoid.)
* The routine isn't called when there is another character next to
you. (Remember that we discovered the code we replaced was never
called on lines where we draw GRP0?) If part of your sprite
overlaps a well and another character approaches, the collision
latches won't get cleared and you'll fall right it!
There isn't another junk spot we can dump our routine that is always
called, so we'll need to find an additional 9 bytes that we can safely
overwrite. Constraints are tighter here, as we'll need to find some
code that we can eliminate that also happens to be called all the time,
or when our other routine isn't. That's a pretty tall order. Could we
really be that lucky or will we need to find some code that isn't
essential to the game, and deal with any unwanted consequences?
A few rounds with the debugger turns up 8 whole bytes at 1062 that look
redundant. Didn't we already handle that at 103B? It turns out that we
didn't. Take a look at 1043. The next sprite row is read and saved for
later use. Later, sadly, means at 1062. If we replace this code it
means that we won't update GRP0 and COLUP0. That means we'll end up
duplicating the previous row. We'll essentially be tossing out half of
our sprite data. It will appear as though every other line in our
sprite was overwritten by the previous line. That sounds bad, but in
the end it means that we can use these bytes without fear as the only
consequence will be that the other characters and the phone parts will
look a bit pixelated (each row being four scan lines tall). Of course,
on an Atari 2600, that's not exactly a major issue. We need at least 9
bytes for our routine, but our luck is holding out and we can safely
eliminate the WSYNC at 1060 giving us a whole 10 bytes to use as we
please. We'll also need to slightly modify our routine. If you've been
following along with a debugger, you can probably guess why.
1060: NOP ; 2 ; EA
1061: TXA ; 2 ; 8A
1062: SBC #$07 ; 2 ; E9 07
1064: CMP $9C ; 3 ; C5 9C
1066: BCS $F06A ; 2 ; B0 02
1068: STA CXCLR ; 3 ; 85 2C
Note: We subtract 7, not 8 like before.
[figure5.png]
Figure 5: The FBI Agent before and after. It looks worse when you put
them side-by-side. Only die-hard E.T. fans will notice the change
during actual play.
::UPDATE:: Thanks to the excellent suggestion of AtariAge user Nukey
Shay, we can (mostly) save our sprites. (Apparently, the die-hard E.T.
fans noticed and were not impressed!) Every other line will still be
the same color, but at least they won't be a blocky mess.
Nukey Shay's idea was to precalculate the location where we want to
strobe CXCLR. Instead calculating the position we're looking for on
every line, we do it once per frame and store the result so that we can
just do a quick CPX. This saves us a 3 bytes and 4 cycles. We can spend
these (plus 2 cycles from the NOP) on an LDA and STA to update GRP0.
That will make our sprites less blocky, but we'll still lose some color
detail. Elliott's shirt will lose its stripes and the FBI agent will
lose his hair.
Our second routine now looks like this:
1060: LDA $87 ; 3 ; A5 87
1062: STA GRP0 ; 3 ; 85 1B
1064: CPX $8B ; 3 ; E4 8B
1066: BCS $F06A ; 2 ; B0 02
1068: STA CXCLR ; 3 ; 85 2C
Note: We'll save our precalculated location at 8B, which is unus
ed.
Of course, we still need to precalculate the position and store it at
8B. We've got a little free ROM space in Bank 0, and tons of time
during VBLANK, so we can run our routine just before we wait out the
timer. We'll steal the jump to 0CAB at 002A, call our routine at 0FF0,
and then jump to 0CAB to wait out the timer.
002A: JMP $BFF0 ; 3 ; 4C F0 BF
0FF0: LDA $9C ; 3 ; A5 9C
0FF2: ADC #$07 ; 3 ; 69 07
0FF4: STA $8B ; 3 ; 85 8B
0FF6: JMP $BCAB ; 3 ; 4C AB BC
That solves the problem. Now E.T. won't fall in to a well unless his
feet are over the hole. Moving around in the game feels a lot more
natural. Of course, it doesn't matter how great the controls are if we
can't collect phone parts to complete the game!
If you've been following along, you've probably already figured out
that the reason we can't collect phone parts is because E.T.'s feet
never touch them. Hovering up to make E.T.'s feet touch them doesn't
work, which seems obvious in retrospect.
The simplest solution is to just move the phone parts down the screen a
little bit so that they're lying on the ground and not hovering in
mid-air. It's an easy fix, just one byte. Change 0BEE from 32 to 36.
0BED: LDA #$36 ; 2 ; A9 36
That's all there is to it. It's not perfect, but we'll improve it
later.
Dealing with the difficulty
The game is now actually easy to complete on easy mode and much more
fun to play in the other game modes. It may still be a bit too
difficult for some, so let's see what we can do to make the game less
punishing.
E.T. focuses heavily on exploration. Not only do you need to find the
phone parts, but also a location for your ship to land, and a suitable
spot to "phone home". There is also strategic exploration to identify
the spots where you can call Elliott, eat candy, and send the scientist
and FBI agent back to their respective buildings. Let's not forget side
quests. The problem, of course, is that the game punishes you for
exploring. Every step you take uses precious energy. Rather than a fun
activity, exploration is something to avoid whenever possible.
As there are plenty of other ways to lose energy aside from just moving
around, we can reduce the amount of energy it takes to move around to
zero without making ourselves invincible. The game will still be
challenging, just not nearly as frustrating.
E.T. loses energy by moving around in three different ways: walking,
running, and hovering upward. Using our debugger, we can step through
the code to find the place or places where we lose energy. Some people
may think that running or hovering should still take energy away.
Conveniently, there are three places we need to change. Each line
presented below is independent of the others, so just don't make the
changes for running or hovering if you don't want them.
The Original code:
0707: LDY #$01 ; 3 ; A0 01 ; Lose energy Walking
071B: LDY #$01 ; 3 ; A0 01 ; Lose energy Running
0685: LDY #$01 ; 3 ; A0 01 ; Lose energy Hovering
The New code:
0707: LDY #$00 ; 3 ; A0 00 ; Lose no energy Walking
071B: LDY #$00 ; 3 ; A0 00 ; Lose no energy Running
0685: LDY #$00 ; 3 ; A0 00 ; Lose no energy Hovering
It's easy to see how to change the code to take more energy away if
you're after additional challenge. You could, for example, double the
energy you use when running by changing 071C to 02.
::UPDATE:: AtariAge user Random Terrain noticed that there is a problem
with the sound that plays when E.T. is hovering.
That particular problem is caused by the seemingly simple difficulty
fix for hovering. It turns out that the routine that plays the hovering
sound uses the lower part of your energy (the last digit, masked off
with an AND #$0F) to pace the tones. If we set 0686 to 0, you'll either
hear an annoying tone or no sound at all, depending on the last digit
of your energy counter when you start hovering. To fix this, we'll need
modify that routine at 04EE.
We'll need to replace the reference to D4 with another memory location
with a value that changes regularly. 81 is a good candidate, but it
changes a bit too frequently. We can slow the pace to match the
original fairly well by changing the mask to 1E.
04F0: LDA $81 ; 3 ; A5 81
04F2: AND #$1E ; 2 ; 29 1E
If you still think the game is too difficult, you can skip the changes
above (except the sound fix) and make the following change:
0FD5: LDA $D3 ; 3 ; A5 D3
This change copies the upper part of your energy counter to the lower
part, making energy a non-issue. You only lose energy if you fall in to
a well and fail to catch yourself. You'd need to make that mistake 99
times before you pass-out, assuming that you don't eat any candy
between falls. If that wasn't enough, you still won't lose as Elliott
will come to revive you a few times. I don't recommend this change.
E.T. is NOT green!
Why is E.T. green? You need to ask Howard Scott Warshaw about that.
E.T. is brown, however, not green. There is absolutely no reason why
the game shouldn't use a proper color for E.T.
Here's what we know:
* The E.T. sprite uses GRP1.
* COLUP1 is not set anywhere in the kernel
* E.T.'s color changes as he loses energy
* Our energy level is stored across D3 and D4
* The values at D3 and D4 are stored as BCD
We don't know, but can assume, that GRP1 and, consequently, COLUP1 are
used in the top-bar. (It turns out that they are.) With our debugger,
we can step through the code called after the top bar has been rendered
and before we enter the kernel at 102E. We're looking for anything that
checks our energy level or that sets COLUP1. It's not long before we
find this gem:
165E: LDA $D3 ; 3 ; A5 D3
1660: LSR A ; 2 ; 4A
1661: LSR A ; 2 ; 4A
1662: LSR A ; 2 ; 4A
1663: LSR A ; 2 ; 4A
1664: LSR A ; 2 ; 4A
1665: TAX ; 2 ; AA
1666: INX ; 2 ; E8
1667: LDA F7F9, X ; 4 ; BD F9 F7
166A: STA COLUP1 ; 3 ; 85 07
It does everything: It reads the upper part of our energy level and
sets COLUP1. We now know that E.T.'s colors are stored starting at
17F9, but how many of those bytes do we need to change? Remembering
that the value stored at D3 is BCD we know that after 1163 we'll have a
value between 0 and 9. One more shift (to divide by 2) and we're left
with one of 5 possible values: 0, 1, 2, 3, and 4. Clever, isn't it?
Why the INX? You'd think that it was unnecessary as we'd need only
change F7F9 to F7FA to skip the instruction and save a precious byte of
ROM space and two cycles. If you take a look at the code a little
farther back you'll find that the byte at index 0 is used as a color,
but in a special case. (When E.T. has passed-out, if you're curious).
The important thing here is that we now know that to change E.T.'s
color, we need only change those 6 bytes starting at 17F9.
We'll need to consult a [23]TIA color chart to figure out what colors
we should use.
Original Colors:
17F9: 0E DE DC DA DA DA
New Colors:
17F9: 0E FE FC F8 F8 F8
I changed the luminance and not just the hue as FA looked too light.
Unfortunately, that choice makes E.T. practically invisible against the
gray background in the wells. Rather than give-in and use the lighter
color, we can just make the background of the well a bit darker. It's a
small difference that won't be noticeable during play.
As you've already guessed, the code to change COLUPF and COLUBK ought
to be near the code to set COLUP1: after we draw the top bar but before
we enter the main kernel. No surprise, we find the code we're
interested in just a few bytes down at 166E to 1680. The code works the
same way, reading a color from a byte array. COLUPF from 1DD9 and
COLUBK from 1DE2. Play until you fall in to a well and then take a look
at the value stored at 80 when we get to 166E to get the index we need.
(For the lazy: It's 6, giving us 1DE8.)
Between the color chart and our understanding of the code starting at
166E we can change the well foreground and background colors to
anything that we want. Gray always seemed to me to be an odd choice,
but I'll stick with tradition here and just make the background a shade
darker so that E.T. stands out.
1DE8: 04
If you want to change the well foreground color, that value is stored
at 1DDF.
[figure6.png]
Figure 6: E.T. looking sharp with his fancy new color.
Spit and Polish - Finishing the Project
Things are looking good, but they're not good enough. Let's see if we
can polish this up and make it ready for production.
Here are the problems:
* Elliott's Shirt has no stripes
* The FBI Agent lost his hair
* E.T. loses detail on the right side of the screen
* Candy Pieces are much more difficult to collect
* Objects in wells are drawn too far down, making the flower look odd
* A Big One: Elliott can't revive E.T.
As a Bonus, let's also make our difficulty fix a selectable option.
Finding some space
What purpose does M0 serve? I have absolutely no idea. It's only set to
one of two fixed vertical positions (7F and 33), and only at two fixed
horizontal positions. It's displayed only when E.T. is dead (on the sad
ending scene), about half-way across the the bottom of the play area.
It changes to various shades of red. That's from the code, I've never
actually seen it during play. I've taken the time to see if that really
does happen, and what it looks like. M0 shows up directly over a dead
E.T., giving him the appearance of being fatally wounded.
While I was hoping for a no-compromise solution, this is something I'm
willing to remove. It won't be missed. We'll trade it for an improved
kernel and a new feature much better than a bleeding E.T.
With that gone, we free up 3 bytes and 6 cycles in our kernel at 1028.
Looking a few bytes down at 102F, you'll see an obviously useless SEC.
It's actually used for timing, but we'll make up for that with our new
changes anyway. For now, it can be considered 1 free byte and 2
precious cycles. Coupled with the WSYNC we can remove at 1060, that
gives us 6 free bytes and 11 cycles. We'll use these to make a change
to our kernel to implement our falling fix while preserving sprite
colors and making it easier to collect candy.
The idea is simple: We have a lot of stuff to draw early, so do that
first. With the extra space and time, we'll check to see if we're on
the line we'd normally strobe CXCLR for our falling fix. Instead of
clearing it right away, check to make sure we haven't touched any
candy. That's going to take a whopping 10 bytes and 12 cycles.
CPX $8B ; 3 ; E4 8B
BNE +6 ; 2 ; D0 06
BIT CXP1FB ; 2 ; 24 13
BVS +2 ; 2 ; 70 02
STA CXCLR ; 3 ; 85 2C
Thankfully, we can spare the extra cycle. Though where are we going to
find an extra 4 bytes?
Remember all that dead code at 1013 we used for the first version of
our falling fix? It's just timing code, there to waste some cycles so
that everything is drawn at just the right place. We don't ultimately
need it for our falling fix (though we left it in anyway) so we're free
to use it for something else, provided we're careful about our timing.
The code we're going to change starts at 1060 and branches in to the
code at 1022. That puts us directly below the useless code at 1013. We
can snag a few bytes from there and just adjust the jump at 1074.
To start, we'll kill the WSYNC at 1060 and move everything before the
jump to 1022 (at 1074) up two bytes. We'll move the CPX at 1022 to the
hole we created at 1072 giving us:
1060: LDA $87 ; 3 ; A5 87
1062: STA GRP0 ; 3 ; 85 1B
1064: LDA $88 ; 3 ; A5 88
1066: STA COLUP0 ; 3 ; 85 06
1068: TXA ; 2 ; 8A
1069: TAY ; 2 ; A8
106A: LDA $BA, Y ; 5 ; B1 BA
106C: STA PF1 ; 3 ; 85 0E
106E: LDA $BC, Y ; 5 ; B1 BC
1070: STA PF2 ; 3 ; 85 0F
1072: CPX $9F ; 3 ; E4 9F
Next, we'll grab four bytes from our dead code by moving the jump at
101F to 101B. We'll then update our jump at 1074 (that used to point to
1022) to point to 101E.
101B: JMP F04B ; 3 ; 4C 4B F0
1074: JMP F01E ; 3 ; 4C 1E F0
Now we can clear a 10 byte spot for our routine. Move the PHP at 1024
to 101E. (We can get away with this as JMP doesn't affect any flags.)
Now move everything from the CPX at 1025 to the TXA at 102E down a
byte, overwriting the useless SEC at 102F.
Popping in our new routine at 101F, we get:
101B: JMP F04B ; 3 ; 4C 4B F0
101E: PHP ; 3 ; 08
101F: CPX $8B ; 3 ; E4 8B
1021: BNE +6 ; 2 ; D0 06
1023: BIT CXP1FB ; 2 ; 24 13
1025: BVS +2 ; 2 ; 70 02
1027: STA CXCLR ; 3 ; 85 2C
1029: CPX $9E ; 3 ; E4 9E
102B: PHP ; 3 ; 08
102C: INX ; 2 ; E8
102D: LDY $86 ; 2 ; A4 86
102F: TXA ; 2 ; 8A
If we try the game now, it'll crash. The kernel entry point is at 102E,
which now in the middle of an instruction! The CPU will think that
we're trying to STX $8A and who knows what else afterward! We'll need
to adjust our entry point down a byte. It's buried in a table at 18F3.
The address is loaded at 16A0 and shoved on to the stack. We jump in to
the kernel with an RTS at 16B5. The RTS instruction pops the address
off the stack as sets the PC, but inexplicably adds 1 in the process.
That means we'll need to specify an address 1 byte before the one we
want. It's weird. We jump to our new address ... by specifying our old
one.
18F3: $F02F ; - ; 2E F0
Now if we replace the 8 bytes from 1013 to 101A with NOP's (EA, using
up 16 cycles) we can try out our new kernel. A quick test shows that
we're clearly not done. E.T. still loses resolution on the right side
of the screen! Remember that useless SEC? We needed it to delay
updating GRP1 at 1034 until we were finished drawing the play area. The
fix is easy, just swap it with the WYSNC at 1036.
1034: STA WSYNC ; 3 ; 85 02
1036: STY GRP1 ; 3 ; 84 1C
That's a lot better, but we're still not done. Elliott still can't
revive E.T., and we still need to touch phone parts with our feet,
meaning we still need to push objects in wells down a few lines. We've
also introduced a new problem: E.T. isn't centered in the spaceship on
landing or take-off. At least that one is easy to fix. All we need to
do is adjust the starting position of the spaceship for landing (at
0B40) and take-off (at 07ED):
0B40: LDA #$EF ; 2 ; A9 EF
07ED: SBC #$04 ; 2 ; E9 04
So, why can't Elliott revive E.T.? To revive E.T., Elliott needs to
touch him. Unfortunately, the "E.T. has passed-out" sprite is much
shorter than the normal E.T. sprite, and we clear the collision latches
well below the last line. It doesn't matter where Elliott is
positioned, he'll never touch E.T. after we strobe CXCLR as there will
be nothing for him to touch.
There are a couple things we could do. Instead of adding 7 when we
calculate the position to clear the collision latches, we could do the
sensible thing and add E.T.'s height and position, then subtract 2
before storing it in 8B. That way we'll have a line for Elliott to
touch on the much shorter E.T. sprite. Unfortunately, that won't work.
Even if we move the code to calculate the position just above E.T.'s
feet to the 10 free bytes at 0BF6 (which we will anyway) we'll need 8
bytes for the math and three to jump to 0CAB. That's 11 bytes. Our luck
isn't holding out, as there doesn't seem to be any useless bytes to
spare. All the same, let's move that routine anyway in preparation for
our cool new feature.
002A: JMP $BBF6 ; 3 ; 4C F6 BB
0BF6: LDA $9C ; 3 ; A5 9C
0BF8: ADC 07 ; 3 ; 69 07
0BFA: STA $F6 ; 3 ; 85 F6
0BFC: JMP $BCAB ; 3 ; 4C AB BC
(Wait a minute! Why are we storing the result at F6 when our new kernel
is expecting that at 8B? There is a reason, as we'll soon see.)
We could alternately check to see if E.T. has passed-out, and skip
strobing CXCLR. The same trick would work for Phone Parts as well, by
checking to see if E.T. is in a well. Of course, there's absolutely no
way we can do that at the same place we do our other checks at 1023.
That shouldn't be a problem, as we only really need to do those checks
once as they're not dependent on E.T.'s vertical position. That's
great, but how do we skip clearing the collision latches? There's not
enough room for even one extra check.
We could modify our calculated value to point to some other location.
Setting it to 0 would be ideal, but what about this process has been
ideal? We also need a place to stuff our checks. A check usually costs
us a good 4 bytes, two to set flags and another two to branch. That
would make it seem like we'd need at least 10 bytes (another 2 bytes to
zero 8B). Naturally, we don't have 10 usable bytes plus 1 or 3 extra
bytes for a return. Not anywhere.
Now, we do have 8 bytes at 1013, for timing, just begging to be used in
our kernel. The problem is that not only do we need to squeeze our
routine in to 8 bytes, we must also burn through 12 to 16 cycles (no
more, no less) to keep our timing right.
Here's what we know:
* D9 is normally 0, but is set to 40 when we're hovering over a well,
20 when we're at the bottom of a well, and 80 while we're falling
in.
* E3 is normally 0, but is set to C0 when E.T. has passed out
* E.T.'s vertical position will never exceed 3A
* E.T.'s vertical position will never fall below 30 while standing in
a well
* E.T. will never collect anything or fall in a well when his
vertical position is 0
* We only draw GRP0 on the first scanline when the mothership is
taking off or landing
* That means our timing code at 1013, for all practical purposes,
will always be called on the first scanline.
What can we do with this? Adding D9 and E3 to 8B will normally do
nothing. If we're at the bottom of a well, D9 will be set to 20, and E3
will be 0 (if E.T. is healthy) and C0 (if not) That means 8B will be
around 10 (+16) or 50 (+80), in any case, well outside the area we care
about. (It'll be well above E.T. or below the play area). If we're not
in a well, D9 will be 0 and adding C0 (-64) to any possible E.T.
position will always result in a value in the range FA(-6) to C0(-64).
This is great. We can do that in 8 bytes and in precisely 12 cycles
(the minimum we need to burn). The only problem is that our little
routine will be called more than once. We can't just keep modifying 8B
and hope for the best. The simple solution is to keep an original copy
of our calculated value in a different location, run our routine using
that value, and store the result in 8B. (That's why we stored our
calculated value in F6 instead of 8B when we moved the routine to
calculate the position we want to strobe CXCLR.) Our slick little
routine looks like this:
1013: ORA $D9 ; 3 ; 05 D9
1015: ADC $E3 ; 3 ; 65 E3
1017: ADC $F6 ; 3 ; 65 F6
1019: STA $8B ; 3 ; 85 8B
Why ORA and not LDA? A will always be 0 at this point so the effect
will be the same. With needlessly cryptic things (like the SEC used
like a NOP) scattered around the code, it seemed to fit with H.S.W.'s
style.
Update: AtariAge user iesposta noticed that it's possible for E.T. to
fall in to a well if he's touching both a well and a piece of candy.
This only happens in one spot (on the screen with the "V"-shaped wells)
and you've got to be lined up near perfectly. We can prevent that from
happening by pushing that candy down a tiny bit.
0BA5: 22 ; - ; 22
We did it! The game is now virtually identical to the original except
for the changes that we wanted to make. The gore is the only exception,
but it was worth removing it for...
Our new feature
As promised, we're going to make our difficulty fix optional. No longer
will skilled E.T. players need to give up our much-needed changes in
exchange for a more challenging game. Both difficulty switches are
already used, but the B&W / Color switch is unused. All we need to do
is find a place to put our routine.
We'll need to first modify our old difficulty fix to read from a byte
in memory, rather than our explicit 1 or 0. That's the easy part. We'll
use F8, for no real reason.
0707: LDY $F8 ; 3 ; A4 F8
071B: LDY $F8 ; 3 ; A4 F8
0685: LDY $F8 ; 3 ; A4 F8
The state of the color switch is at bit 3 in SWCHB. We'll need to load
that in to memory, mask off bit 3, and check the state against that.
Naturally, we don't have the space to do all of that and store it. We'd
need 13 bytes for the obvious routine, if we magically found a place to
stuff our routine that didn't require we hijack a jump. That's not
going to happen.
The smallest routine I could manage works like this: read SWCHB, mask
off bit 3, shift right three times, store the result. That'll take 10
bytes, not including a return jump. Even if we had the 10 bytes, that
also would mean that the difficulty fix would be off by default (the
switch is set to color) which isn't optimal.
We have what appears to be 10 bytes, but is really 8 bytes, free at
0FF0 where we used to have the 9-byte routine used to calculate the
position to clear the collision latches. (I don't know how we got away
with it.) We also have the 8 bytes that set M0's horizontal and
vertical position for the gory ending scene at 0B4D. If we switch from
one group to the other, it could be enough.
We'll likely need to use 6 of those bytes just for jumps, once to
switch between our open areas, and once to complete the jump we hijack.
Luckily, the routine just before our 8 free bytes at 0FF0 ends with an
RTS. It turns out that this is the routine that decrements E.T.'s
energy. It's a bit of good luck, and a nice match for our difficulty
fix. To make things even better, there's an RTS at the end of our other
8 bytes (that set M0's position). With 16 bytes, and a return that's
ready-made, we can implement our routine, swap the functions of the
Color and B&W settings (so that Color is easy), all with a byte to
spare.
We'll overwrite the RTS at 0FEF to allow the routine to continue in to
our routine, grab SWCHB, and mask off bit 3 before the jump. We could
do an LSR here, but we'll save it for after the jump to make our
routine line-up with the existing RTS at 0B55.
0FEF: LDA SWCHB ; 4 ; AD 82 02
0FF2: AND #$08 ; 2 ; 29 08
0FF4: JMP $BB4E ; 6 ; 4C 4E BB
We'll need to use a byte to cap-off the checks to run the old routine
so that our routine doesn't accidentally run. That's why we'll enter
the second part at 0B4E instead of 0B4D.
0B4D: RTS ; 6 ; 60
0B4E: LSR ; 2 ; 4A
0B4F: LSR ; 2 ; 4A
0B50: LSR ; 2 ; 4A
0B51: EOR #$01 ; 2 ; 49 01
0B53: STA $F8 ; 3 ; 85 F8
Bit 3 of SWCHB is 1 if the B&W / Color switch is in the Color position,
0 otherwise. The EOR at 0B51 will reverse that so that we store a 0 in
F8 when the switch is set to Color instead of 1.
That's all there is to it.
Squashing some 30-year-old Bugs
E.T. has a reputation for being loaded with bugs. Bugs that make the
game "virtually unplayable". This just isn't true. There aren't
actually that many bugs, and only one that seems to impact normal
gameplay.
Bug myths and facts
There are a few oft-cited bugs that, well, aren't bugs at all. Before
we begin, let's set the record straight on the most common non-bugs:
* Myth: Some game-state variables aren't cleared when starting a new
game as evidenced by the appearance of the Scientist and FBI agent
after starting a new game on mode 3.
This simply isn't true. The Scientist and FBI agent always appear
regardless of the game mode. In every mode, all the humans are
shown returning to their respective buildings -- that includes mode
3, even from power-on. The difference, of course, is that in mode 3
they never leave.
* Myth: The first count-down timer doesn't finish ticking down like
the second, faster, timer.
This is just a misunderstanding of what the "two" timers represent.
The timer takes 64 "ticks" to complete. Every 8 ticks, a section
disappears. The second timer is a "close-up" of the last section of
the first timer. It ticks off one of its eight sections every
"tick". It's like the first timer is minutes, and the second timer
seconds. There really is just one 64-tick timer, we just see the
higher-precision ("second") view when we get to the end (the last
"minute").
* Myth: The number of times Elliott can revive E.T. is incorrect /
can be exploited to gain and extra revival.
This is simply not true. The manual states that "Elliott can merge
with E.T. three times per game." Which is correct. It also states
that "Once during a round, however, E.T. can encounter a wilted
flower hidden in the bottom of a well. If E.T. is revives the
flower, Elliott is given the ability to merge with E.T. one extra
time." This is also correct. Extra merges / lives accumulate as you
would expect from the description, though that's not explicitly
stated in the manual.
In short, there are no bugs related to the number of times Elliott
can revive E.T. (Not under any normal play circumstances anyhow. If
you accumulate more than 127 "lives", Elliott will not revive E.T.
I doubt that has ever happened!)
Real Bugs
Bug 1: On difficulty modes where Elliott is allowed to be on-screen
when the ship lands, the Ship Crushes Elliott.
This bug happens because the ship's position is overwritten by
Elliott's position immediately after the ship's position is set to
start the landing animation. The fix is simple, just skip over the code
that updates the current objects on-screen position after we start
initialize the ship landing sequence.
07BD: JMP $BAD9 ; 3 ; 4C D9 BA
Bug 2: You always fall in to a well when exiting the forest on the
right, and when exiting the city on the left
This is also an easy fix. The falling fix automatically takes care of
the bug when exiting left from the city screen. For the forest, we just
need to slightly adjust E.T.'s starting position on the next screen.
The player will be pushing right on the joystick, so we'll just move
E.T. a tiny bit up and to the right to avoid immediately falling in to
the top-center well on the screen with eight pits. E.T.'s starting
position is read from a table, so we just need to update a couple of
values:
0D54: 3A +10 ; - ; 4A
0D6C: 04 -3 ; - ; 01
We'll move E.T. 16 units to the left, and 3 units up from the original
positions.
Bug 3: Scoring is wildly incorrect.
It's consistent, for the most part, but it's very confusing. It also
doesn't even come close to matching the manual. There are some more
serious problems, however. Collecting more than 31 pieces of candy will
cause an error, often leading to the famous "Ninja E.T." bug. The
starting energy penalty and candy bonuses are also incorrect.
The code for scoring also determines other things, like E.T.'s energy
when starting a new game, so we'll need to be careful making drastic
changes to make sure we don't accidentally break anything. Of cousre,
the code is also a mess, so we will be making some rather dramatic
changes.
Right now, points for candy E.T. brings on the ship, bonus points for
candy collected beyond a certain amount, and the energy penalty are
determined by table look-ups. Normally, a look-up table is used to save
ROM space, time, or both to avoid a complex calculation or provide a
more accurate calculation. These tables just waste space as time isn't
an important factor here. Even worse, only points for E.T.'s candy are
scored correctly! We'll eliminate these awful tables and put those
bytes to better use.
Currently, scoring follows this sequence: After the ending animation
starts, you are given 1 point for every unit of remaining energy, then
490 points for every candy brought on to the ship. The candy munching
part of the animation then begins, netting you 770 points for each
candy held by Elliott; one at a time while the animation runs. When a
new round starts, you're given bonus points for collected candy above a
certain amount (21 pieces, not 31 as specified in the manual) and the
energy penalty determines your starting energy for the round.
We're going to change that. We'll start off the same way, giving one
point for every unit of remaining energy. We'll then set E.T.'s energy
to 9999. As the munching animation runs, we'll deduct energy for the
penalty, add bonus points for candies collected over a certain amount,
and add the normal 490 or 770 points for collected candy to your score.
The energy penalty code also sets E.T.'s energy at the start of a new
game. We'll need to remember that code that begins a new round is also
called when a new game starts, and add some code to make sure E.T.'s
starting energy is set to 9999 at the beginning of a new game.
Fixing the scoring code will also fix the Ninja E.T. bug. As it's
become a popular, if unintended, Easter Egg in its own right, we'll add
it to the game as an intentional effect. (Without the other strange
artifacts, of course).
Since we're fixing the scoring, it makes sense to make the scoring
match the manual. This means we'll also need to make a small change to
how much candy can be found during a round so that you can meaningfully
collect more than 31 pieces. There is technically a bug here, as the
flags that show which well screens currently have candy is never
cleared. The counter that holds how much additional candy can be found
during the round often doesn't reach zero. We'll leave this in as it
adds a nice bit of pseudo-randomness to the amount of candy you can
find.
Wait. What? There's effectively a potential +4 or -3 to the amount of
candy than can appear during a round. Remembering that candy left on
the ground from the previous round isn't cleared, there can be as many
as four pieces left on the ground from a previous round. Those won't be
deducted from the counter, effectively increasing the potential amount
of candy by as much as four pieces. The -3 is a bit more complicated.
When candy appears, it appears on every well screen. The value at DC is
reduced by the amount of candy needed to add a candy to every screen.
(If all four screens need candy, DC is reduced by four. If three
screens need candy, DC is reduced by three, and so on.) If there isn't
enough candy left to place a candy on every screen, according to DC,
then no candy is added. That means that DC can get "stuck" at 3, 2, or
1. (If all four well screens need candy when DC is less than four, no
candy is added. If three screens need candy when DC is less than 3, no
candy will be added, and so on.) If you're looking to maximize the
amount of candy you can collect, collect only one candy at a time,
allowing the candy to replenish in-between, when you get close to the
maximum.
Without further exposition, let's get started. The first thing we'll do
is make a change to the code that runs right after we finish a round.
The code we're interested in initializes the counter for remaining
candy for the next round and totals the collected candy (what Elliott
is holding plus what E.T. is holding.)
058E: STA $F4 ; 3 ; 85 F4
0590: LDA $DD ; 3 ; A5 DD
0592: STA $F5 ; 3 ; 85 F5
0594: ADC $F4 ; 3 ; 65 F4
0596: STA $DD ; 3 ; 85 DD
0598: ADC 16 ; 3 ; 69 10
059A: NOP ; 2 ; EA
059B: NOP ; 2 ; EA
Memory location DD holds the amount of candy held by Elliott, which
will now be set to the total amount of candy collected. F4 and F5 hold
the amount of candy held by E.T. and Elliott, respectively. At 0598, we
set the amount of candy available in the next round to 16 plus the
total amount of candy collected. (It will be stored in DC just after
the two NOP's). We'll come back to that later.
We only need F4 and F5 to implement the Ninja E.T. bug as an Easter
Egg, so this routine could be made much simpler.
With that out of the way, let's kill the code that scores E.T.'s candy
as we'll handle that in our new scoring routine. As we'll be deducting
energy for the penalty in our new score routine, we'll use this
opportunity to set E.T.'s energy to 9999.
1395: LDA #$99 ; 2 ; A9 99
1397: STA $D3 ; 3 ; 85 D3
1399: STA $D4 ; 3 ; 85 D4
139B: BNE +9 ; 3 ; D0 09
139D: NOP ; 2 ; EA
139E: NOP ; 2 ; EA
139F: NOP ; 2 ; EA
13A0: NOP ; 2 ; EA
13A1: NOP ; 2 ; EA
13A2: NOP ; 2 ; EA
The branch at the end skips over the jump to the routine that updates
our score.
Those six bytes are just begging to be used! As we're fixing the
scoring, let's take this opportunity to address a scoring issue with
the difficulty fix. Normally, you get 1 bonus point for every remaining
unit of energy that E.T. has at the end of a round. With the difficulty
fix in place, players essentially get tons of free points. It hardly
seems fair, so we'll add a check so that the players taking advantage
of the difficulty switch receive no bonus points for remaining energy.
139D: LDA $F8 ; 3 ; A5 F8
139F: BNE +2 ; 2 ; D0 02
13A1: TAX ; 2 ; AA
13A2: TAY ; 2 ; A8
We'll hijack the jump at 1382, pushing it back a bit so that our
routine is actually called. The routine to increment our score will be
called directly afterward like normal, only with X and Y set to 0
instead of E.T.'s remaining energy, if the difficulty fix is enabled.
1382: JMP 13A3 -6 ; 6 ; 4C 9D F3
Now we've freed up the 20 bytes that make up the table at 1341. We'll
free up the 16 bytes at 17E9 used for the energy penalty later when we
update the code that start a new round. For now, we'll assume that
they're free. That should give us 36 bytes for our new scoring routine.
We'll call our new scoring routine from the munching routine at 13AC.
We'll need to either hijack a jump or find some free bytes for our own.
Luckily, we've got four useless bytes at 13BD. All those do are store
the number 6 in 8B. It's the only place in the ROM that does anything
with 8B (our changes excepted, of course) so it's essentially useless.
We'll use those four bytes for our jump.
13BD: LDA #$01 ; 2 ; A9 01
13BF: ORA $DE ; 2 ; 05 DE
13C1: STA $DE ; 3 ; 85 DE
13C3: LDX #$07 ; 2 ; A2 07
13C5: LDY #$70 ; 2 ; A0 70
13C7: JSR $1341 ; 6 ; 20 41 F3
13CA: NOP ; 2 ; EA
We'll want to take advantage of the LDX and LDY (which hold the number
of points to score) to save a few bytes, so we'll just push everything
before that up in to the four-byte hole we made at 13BD and add our
jump. Our jump only takes three bytes, so we'll fill that extra byte
with a NOP.
Finally, we can add our new score routine! The idea here is simple.
Assume from 13C5 and 13C7 that the candy we're munching is worth 770
points. If E.T. is holding any candy, reduce that amount by one and
change the points to score to 490. Finally, check to see if the current
candy is one of the candies collected after the 31st piece. If so, add
1000 points to whatever we've planned to score and deduct 700 units of
energy as the penalty. This matches the scoring described in the
manual. The points will actually be added to the score after we return
from our routine.
1341: LDA $D2 ; 2 ; A5 D2
1343: CMP #$0A ; 2 ; C9 0A
1345: BEQ +8 ; 2 ; F0 08
1347: SBC 16 ; 3 ; E9 10
1349: STA $D2 ; 3 ; 85 D2
134B: LDX #$04 ; 2 ; A2 04
134D: LDY #$90 ; 2 ; A0 90
134F: LDA $DD ; 2 ; A5 DD
1351: SED ; 2 ; F8
1352: JMP $17E9 ; 6 ; 4C E9 F7
-----------------------------------
17E9: CMP #$1F ; 2 ; C9 1F
17EB: BCC +10 ; 2 ; 90 0A
17ED: TXA ; 2 ; 8A
17EE: ORA #$10 ; 2 ; 09 10
17EF: TAX ; 2 ; AA
17F1: LDA $D3 ; 2 ; A5 D3
17F3: SBC 7 ; 3 ; E9 07
17F5: STA $D3 ; 3 ; 85 D3
17F7: CLD ; 2 ; D8
17F8: RET ; 6 ; 60
Now we need to update the code that starts a new round to keep it from
scoring bonus points and issuing a penalty. There is an additional
problem, as the code that determines the energy penalty also sets
E.T.'s energy to 9999 for the first round, we'll need to also modify
the code that starts a new game or E.T. will start the game without any
energy!
Looking at the new game code at 13DC we initialize a lot of stuff to
zero, including things that are set later or can be set later. We won't
need the STA $EB (ship status) as that's set later. We can also safely
set DD, D9, and 94 (Elliot's candy, well flags, and E.T.'s neck height)
at the start of each round. That'll free up a few bytes to set E.T.'s
starting energy at the beginning of a new game.
13FD: LDA #$99 ; 2 ; A9 99
13FF: STA $D3 ; 3 ; 85 D3
1401: STA $D4 ; 3 ; 85 D4
1403: LDA #0 ; 2 ; A9 00
1405: STA $F4 ; 2 ; 85 F4
1407: STA $E3 ; 3 ; 85 E3
We'll also want to reset F4 (which holds the total candy collected used
for our Ninja E.T. Easter Egg) so we'll include that between the old
13FD and 13FF (now 1403 and 1407) that we pushed down to make room for
our new code.
We still need to set DD, D9, and 94 to 0 so we we'll do that at the
start of a new round. (The new round code is also called when we start
a new game.) Everything from 147A to the jump at 14A2 is free for us to
use, thanks to our new scoring routine.
147A: LDA #$0 ; 2 ; A9 00
147C: STA $DD ; 3 ; 85 DD
147E: STA $D9 ; 3 ; 85 D9
1480: STA $94 ; 3 ; 85 94
We also need to limit the amount of candy available in the next round
so that our energy penalty doesn't "wrap around" and start deducting
from the max again. Remember that DC holds the amount of candy that can
appear in the next round. We'll cap it off at 41 pieces, giving us
potentially 38 to 45 pieces in the next round. At 45 pieces our penalty
will be (45-31)*700 or 9800. Any more than that and E.T.'s energy would
wrap to 9300.
1482: LDA #$29 ; 3 ; A5 29
1484: CMP $DC ; 3 ; C5 DC
1486: BCS +2 ; 3 ; B0 02
1488: STA $DC ; 2 ; A5 DC
148A: JMP $14A5 ; 6 ; 4C A5 F4
Now scoring works exactly as stated in the manual. There's just one
thing left to do.
Adding the Ninja E.T. Easter Egg
Ninja E.T. wasn't an intentional easter egg in the original game, it
was a bug. If you collected too much candy (most sources say 33 pieces)
on the next round, E.T. would turn black and your energy would show
part of H.S.W.'s initials and other junk. This happens because a value
other than 0-9 appears in the upper nibble in the upper part of E.T.'s
energy, which will make the code "point" to the wrong image. As E.T.
changes color depending the amount of remaining energy, the color
selected will be outside of the color table, which just happens to have
a few 0's around it. We'll take advantage of that to implement Ninja
E.T. though we'll make sure that the energy counter doesn't look
broken.
With the scoring fixed, collecting 33 pieces of candy seems like a
perfectly reasonable, and likely common, amount. An easter egg
shouldn't be triggered so easily. Echoing the oft-cited trigger, we'll
enable Ninja E.T. only if a player completes a round with both E.T. and
Elliott in posession of exactly three candies.
As a bonus, we'll give Ninja E.T. ten pieces of candy to make up for
the previous candy-poor round. It'll also let Ninja E.T. make a quick
trade with Elliott for a phone part.
148A: LDA $F4 ; 2 ; A5 F4
148C: CMP $F5 ; 2 ; C5 F5
148E: BNE +12 ; 3 ; D0 0C
1490: CMP #$03 ; 2 ; C9 03
1492: BNE +8 ; 2 ; D0 08
1494: LDA #$AA ; 2 ; A9 AA
1496: STA $D2 ; 3 ; 85 D2
1498: STA $D3 ; 3 ; 85 D3
149A: STA $D4 ; 3 ; 85 D4
149C: JMP $14A5 ; 6 ; 4C A5 F4
149F: NOP ; 2 ; EA
14A0: NOP ; 2 ; EA
14A1: NOP ; 2 ; EA
Why AA? That will both give Ninja E.T. 10 pieces of candy and make the
energy counter appear to be empty. As E.T. loses energy, the counter
will return to normal, one digit at a time. When all four digits of the
counter are back to normal, Ninja E.T. will also return to normal.
An Extra Game Mode
Players looking for additional challenge above game mode 3, but not
quite as challenging as game mode 2 (with the nasty FBI Agent) have
always felt left out. AtariAge user roadrunner suggested that an extra
game mode that included just the scientist would be a welcome addition.
The various game modes remove humans by sending the Scientist or the
FBI agent home repeatedly so that they don't appear in-game. To allow
an extra mode to be selected, we just need to change the maximum game
mode from 3 to 4. The game checks to see if the current mode is one
higher than the maximum before setting the game mode back to 1, so
we'll check to see if the the game mode is 5. We'll also need to modify
the check to send the scientist back home. If we make the scientist
only option game mode 3 and push the "no humans" option to game mode 4,
we can check to see if we need to send the scientist home with an AND
and by changing the branch instruction. Ultimately, it's a four-byte
change.
0471: CPX #$05 ; 2 ; E0 05
--------------------------------------------
02ED: AND #$01 ; 2 ; 29 01
02EF: BEQ +9 ; 2 ; F0 09
All of the Final Changes
Here are all the final changes:
---------------------------------------------
- E.T. Fixed Final Version (NTSC) 2013-02-01
---------------------------------------------
-------------------------------------------
- E.T. is Not Green
-------------------------------------------
17FA: ET Colors ; - ; FE FC F8 F8 F8
1DE8: Well BG ; - ; 04
-------------------------------------------
- Difficulty Fix (Walk, Run, Hover)
-------------------------------------------
0707: LDY $F8 ; 3 ; A4 F8
071B: LDY $F8 ; 3 ; A4 F8
0685: LDY $F8 ; 3 ; A4 F8
------------------------------------------
0FEF: LDA SWCHB ; 4 ; AD 82 02
0FF2: AND #$08 ; 2 ; 29 08
0FF4: JMP $BB4E ; 6 ; 4C 4E BB
------------------------------------------
0B4D: RTS ; 6 ; 60
0B4E: LSR ; 2 ; 4A
0B4F: LSR ; 2 ; 4A
0B50: LSR ; 2 ; 4A
0B51: EOR #$01 ; 2 ; 49 01
0B53: STA $F8 ; 3 ; 85 F8
------------------------------------------
- Hovering Sound Fix
------------------------------------------
04F0: LDA $81 ; 3 ; A5 81
04F2: AND #$1E ; 2 ; 29 1E
-------------------------------------------
- Falling Fix
-------------------------------------------
002A: JMP $BBF6 ; 3 ; 4C F6 BB
0BF6: LDA $9C ; 3 ; A5 9C
0BF8: ADC 07 ; 3 ; 69 07
0BFA: STA $F6 ; 3 ; 85 F6
0BFC: JMP $BCAB ; 3 ; 4C AB BC
------------------------------------------
1013: ORA $D9 ; 3 ; 05 D9
1015: ADC $E3 ; 3 ; 65 E3
1017: ADC $F6 ; 3 ; 65 F6
1019: STA $8B ; 3 ; 85 8B
101B: JMP F04B ; 3 ; 4C 4B F0
------------------------------------------
101E: PHP ; 3 ; 08
101F: CPX $8B ; 3 ; E4 8B
1021: BNE +6 ; 2 ; D0 06
1023: BIT CXP1FB ; 2 ; 24 13
1025: BVS +2 ; 2 ; 70 02
1027: STA CXCLR ; 3 ; 85 2C
1029: CPX $9E ; 3 ; E4 9E
102B: PHP ; 3 ; 08
102C: INX ; 2 ; E8
102D: LDY $86 ; 2 ; A4 86
102F: TXA ; 2 ; 8A
-------------------------------------------
1034: STA WSYNC ; 3 ; 85 02
1036: STY GRP1 ; 3 ; 84 1C
-------------------------------------------
1060: LDA $87 ; 3 ; A5 87
1062: STA GRP0 ; 3 ; 85 1B
1064: LDA $88 ; 3 ; A5 88
1066: STA COLUP0 ; 3 ; 85 06
1068: TXA ; 2 ; 8A
1069: TAY ; 2 ; A8
106A: LDA $BA, Y ; 5 ; B1 BA
106C: STA PF1 ; 3 ; 85 0E
106E: LDA $BC, Y ; 5 ; B1 BC
1070: STA PF2 ; 3 ; 85 0F
1072: CPX $9F ; 3 ; E4 9F
1074: JMP F01E ; 3 ; 4C 1E F0
-------------------------------------------
- Change Kernel Entry Point
-------------------------------------------
18F3: $F02F ; - ; 2E F0
-------------------------------------------
- Landing / Launching Ship Position Fix
-------------------------------------------
0B40: LDA #$EF ; 2 ; A9 EF
07ED: SBC #$04 ; 2 ; E9 04
-------------------------------------------
- Move Candy on V Screen To Prevent Falls
-------------------------------------------
0BA5: 22 ; - ; 22
-------------------------------------------
--------------------------------------------
- BUG FIXES
--------------------------------------------
- Don't Fall Leaving Forest on Right
-------------------------------------------
0D54: 3A +10 ; - ; 4A
0D6C: 04 -3 ; - ; 01
-------------------------------------------
- Ship Shouldn't Crush Elliott
-------------------------------------------
07BD: JMP $BAD9 ; 3 ; 4C D9 BA
-------------------------------------------
-------------------------------------------
- FIX SCORING TO MATCH MANUAL
-------------------------------------------
058E: STA $F4 ; 3 ; 85 F4
0590: LDA $DD ; 3 ; A5 DD
0592: STA $F5 ; 3 ; 85 F5
0594: ADC $F4 ; 3 ; 65 F4
0596: STA $DD ; 3 ; 85 DD
0598: ADC 16 ; 3 ; 69 10
059A: NOP ; 2 ; EA
059B: NOP ; 2 ; EA
-------------------------------------------
1382: JMP 13A3 -6 ; 6 ; 4C 9D F3
-------------------------------------------
1395: LDA #$99 ; 2 ; A9 99
1397: STA $D3 ; 3 ; 85 D3
1399: STA $D4 ; 3 ; 85 D4
139B: BNE +9 ; 3 ; D0 09
139D: NOP ; 2 ; EA
139E: NOP ; 2 ; EA
139F: NOP ; 2 ; EA
13A0: NOP ; 2 ; EA
13A1: NOP ; 2 ; EA
13A2: NOP ; 2 ; EA
-------------------------------------------
- Score no points for remaining energy
- with the difficulty fix enabled (6 bytes)
-------------------------------------------
139D: LDA $F8 ; 3 ; A5 F8
139F: BNE +2 ; 2 ; D0 02
13A1: TAX ; 2 ; AA
13A2: TAY ; 2 ; A8
-------------------------------------------
13BD: LDA #$01 ; 2 ; A9 01
13BF: ORA $DE ; 2 ; 05 DE
13C1: STA $DE ; 3 ; 85 DE
13C3: LDX #$07 ; 2 ; A2 07
13C5: LDY #$70 ; 2 ; A0 70
13C7: JSR $1341 ; 6 ; 20 41 F3
13CA: NOP ; 2 ; EA
-------------------------------------------
1341: LDA $D2 ; 2 ; A5 D2
1343: CMP #$0A ; 2 ; C9 0A
1345: BEQ +8 ; 2 ; F0 08
1347: SBC 16 ; 3 ; E9 10
1349: STA $D2 ; 3 ; 85 D2
134B: LDX #$04 ; 2 ; A2 04
134D: LDY #$90 ; 2 ; A0 90
134F: LDA $DD ; 2 ; A5 DD
1351: SED ; 2 ; F8
1352: JMP $17E9 ; 6 ; 4C E9 F7
-------------------------------------------
17E9: CMP #$1F ; 2 ; C9 1F
17EB: BCC +10 ; 2 ; 90 0A
17ED: TXA ; 2 ; 8A
17EE: ORA #$10 ; 2 ; 09 10
17EF: TAX ; 2 ; AA
17F1: LDA $D3 ; 2 ; A5 D3
17F3: SBC 7 ; 3 ; E9 07
17F5: STA $D3 ; 3 ; 85 D3
17F7: CLD ; 2 ; D8
17F8: RET ; 6 ; 60
------------------------------------------
13FD: LDA #$99 ; 2 ; A9 99
13FF: STA $D3 ; 3 ; 85 D3
1401: STA $D4 ; 3 ; 85 D4
1403: LDA #0 ; 2 ; A9 00
1405: STA $F4 ; 2 ; 85 F4
1407: STA $E3 ; 3 ; 85 E3
------------------------------------------
147A: LDA #$0 ; 2 ; A9 00
147C: STA $DD ; 3 ; 85 DD
147E: STA $D9 ; 3 ; 85 D9
1480: STA $94 ; 3 ; 85 94
1482: LDA #$29 ; 3 ; A5 29
1484: CMP $DC ; 3 ; C5 DC
1486: BCS +2 ; 3 ; B0 02
1488: STA $DC ; 2 ; A5 DC
148A: JMP $14A5 ; 6 ; 4C A5 F4
-------------------------------------------
-------------------------------------------
- Easter Egg - Ninja E.T.
-------------------------------------------
148A: LDA $F4 ; 2 ; A5 F4
148C: CMP $F5 ; 2 ; C5 F5
148E: BNE +12 ; 3 ; D0 0C
1490: CMP #$03 ; 2 ; C9 03
1492: BNE +8 ; 2 ; D0 08
1494: LDA #$AA ; 2 ; A9 AA
1496: STA $D2 ; 3 ; 85 D2
1498: STA $D3 ; 3 ; 85 D3
149A: STA $D4 ; 3 ; 85 D4
149C: JMP $14A5 ; 6 ; 4C A5 F4
149F: NOP ; 2 ; EA
14A0: NOP ; 2 ; EA
14A1: NOP ; 2 ; EA
--------------------------------------------
--------------------------------------------
- Add Extra Game Option - Scientist Only
--------------------------------------------
0471: CPX #$05 ; 2 ; E0 05
--------------------------------------------
02ED: AND #$01 ; 2 ; 29 01
02EF: BEQ +9 ; 2 ; F0 09
--------------------------------------------
Conclusion
It turns out that E.T. isn't a bad game after all. With a few simple
changes we were able to dramatically improve an already good game by
eliminating the most common complaints. With a few additional changes,
we were able to clear up any confusion for players who care about the
score, and were confused by the differences between what the manual
claims and what actually happens in-game. Next time someone tells you
that "E.T. for the Atari 2600 is the worst game ever made" you can tell
them that this is not the case. It's been fixed, and you know how.
__________________________________________________________________
[24]Home - Last modified: February 2013
References
1.
http://www.randomterrain.com/atari-2600-memories-et.html
2.
http://www.youtube.com/watch?v=TsF7q_hA6Z8
3.
http://www.neocomputer.org/projects/et/#cantwait
4.
http://www.neocomputer.org/projects/et/#download
5.
http://www.neocomputer.org/projects/et/#whyhate
6.
http://www.neocomputer.org/projects/et/#whyfall
7.
http://www.neocomputer.org/projects/et/#fixfall
8.
http://www.neocomputer.org/projects/et/#toohard
9.
http://www.neocomputer.org/projects/et/#notgreen
10.
http://www.neocomputer.org/projects/et/#finishup
11.
http://www.neocomputer.org/projects/et/#newfeature
12.
http://www.neocomputer.org/projects/et/#bugs
13.
http://www.neocomputer.org/projects/et/#ninja
14.
http://www.neocomputer.org/projects/et/#newmode
15.
http://www.neocomputer.org/projects/et/#allchanges
16.
http://www.neocomputer.org/projects/et/#theend
17.
http://www.neocomputer.org/projects/et/ET_Fixed_Final.bin
18.
http://www.neocomputer.org/projects/et/ET.bin
19.
http://www.atariage.com/manual_html_page.html?SoftwareLabelID=157
20.
http://www.youtube.com/watch?v=r-pzdPLfy9Y
21.
http://tvtropes.org/pmwiki/pmwiki.php/Main/ThreeQuartersView
22.
http://www.neocomputer.org/projects/et/
23.
http://www.randomterrain.com/atari-2600-memories-tia-color-charts.html
24.
http://www.neocomputer.org/projects