Saturday, August 6, 2011

Crows and vultures, oh my !

Over the past couple of days, I've been laboring over the convoluted, spaghetti-like code responsible for the behavior of the "crows" (on the 2nd board with the chains, keys, and birds -- hereafter "chains"), and the "vultures" (on the 3rd board with the moving platforms, ropes, and egg-laying birds -- hereafter "eggs"), both of which share large portions of code.

Now, it's hardly worth mentioning, but this essentially was derived from the code to handle the "springs" in DK (are there any standard names for all these crazy objects/boards?). The only thing that seems to be retained is the bouncy movement of objects as they make their way onto the screen, although even this motion has been altered to accommodate the quirky, skipping entry of each bird before it's inevitable divebomb off the top platform.

What can I say about this code? Hmm.

Well, after a bird takes its initial plunge, the point at which it decides to swoop to the left is illustrated in the image above, and is internally based on the bird's record number (there are 5 total on the "eggs" stage, and 6, 8 or 10 for the "chains" board, depending on the level).

What might actually be of interest is that the 2nd to last bird introduced has a couple of special behaviors. First of all, on the "eggs" stage, it's one of two egg-droppers (the other being the 4th from last). Even so, this egg dropping behavior can be canceled completely if the player reaches a high enough point on the screen (see above image). Try climbing the chains to the far right above the top platform, and egg production will cease entirely, even if you make your way back down the board!

Secondly, it will always choose the lowest point (see above image) to come out of its initial dive and head to the left, unless it's roughly level with the player, in which case it will immediately go left (even if the player is to the right). On the "eggs" board, you can confirm this rogue behavior if the bird drops an egg at any other level above its usual "lowest point".

One last thing to note is that on the "chains" board, the birds will, upon reaching the right edge of the screen (not during its first-time plunge), dive further down once you pass the first level (i.e., the 2nd time you play the board), which explains why the crows are eventually able to reach you in your "safety zone", standing on the bottom platform.

Thursday, August 4, 2011

D. K. Jr. Arcade for Intellivision graphics preview

Just a little preview of some sprite graphics I’ve been working on for DK Jr. Arcade for Intellivision. While I am very happy with the results, it may not be possible in the end to render sprites this detailed since they will probably take at least five or six sprites to render, leaving no sprites for the enemies (or Mario at the top of the screen). However, I’ll be doing everything possible to make Jr. one of the most expressive characters ever rendered in an Intellivision game.

Falling barrel glitch (the wonders of uninitialized variables)

Today, I decided to investigate some strange behavior that occurs occasionally when DK throws a barrel. Normally when a barrel is thrown, it lightly bounces as it lands on each girder. If you watch carefully, you’ll see that occasionally the thrown barrel will miss a girder and bounce off the next girder instead.

This is due to a check at $20F0 that causes ground hits to be ignored if they happen too close together. How close? Less than 26 pixels (a little over three tile rows). It does this by recording the Y-coordinate every time the barrel hits a girder, and by comparing the current value with the last value. Despite this check, occasionally a barrel will be thrown that drops straight from DK’s hands to the bottom girder without ever hitting any girders in between.

There’s nothing intentional in the code to cause a barrel to do this. There are definitely different ways that the game will direct a thrown barrel as it touches down on successive girders, but no instructions to actually ignore them altogether.

Why does it happen? For one simple reason. The Y-coordinate mentioned above is only initialized (zero’d) at the beginning of the board. This means that once a barrel is thrown, it retains the Y-coordinate of the last girder it landed on (this is usually, if not always, the second to last girder). So, when a new thrown barrel reuses a record previously owned by another thrown barrel, the check at $20F0 causes all girders except the last to be ignored. The more barrels that are thrown, the more likely a new barrel will use an old thrown barrel’s record, and the more likely this behavior will occur.

Watch for it!

Introducing blue traps and sparks

With very few exceptions, the mechanisms used to request/introduce blue traps (and blue sparks) in DK Jr. are identical to those used in the original DK. In fact, nearly all of the machinery used to decide on forward “throws” or “skull” barrels (the unusually marked blue flammable barrels) have been retained but are, in effect, rendered inoperative. Even sections of code specifically written to update DK or erase barrels from a nearly depleted stack are still present. Presumably, they update sprites which have been moved offscreen (they still update registers in the OAM).

While there are still checks for special handling with the first three “barrels” (meant to be thrown, rolled, and rolled, respectfully), and there is still a 1 and 16 chance of “throwing” subsequent “barrels”, none of this has nearly any effect on the object introduced. In fact, the only thing that moves is Mario (and the lever he pushes and pulls on the “electricity” level). There is also some feeble (abnormally slow) animation when the blue spark is being readied to make its circuit.

One possible unusual consequence of being marked as a “skull” barrel is that the object’s pointage is probably randomly determined when squashed by a fruit. This remains to be tested, though.

Launching barrels

Since I’d like to discuss barrel introductions (the process of which is surprisingly complicated) , I’m going to limit my ramblings to just DK for the moment.
Firstly, barrel introductions are divided into two subroutines. The first (at $2C03) essentially files requests, and the other (at $2C8F) fulfills requests by animating DK grabbing the barrel and either throwing or rolling it out. Requests are only considered handled after the barrel is released — no new requests can be filed during this time.

The first three requests are very specific. The first barrel is immediately requested, and must always be thrown. The whole process takes only about 26 frames — less than one second. As soon as DK drops the barrel, a new request is put in for the second barrel, followed by the third barrel. These two barrels are ALWAYS rolled out. The code specifically forgoes the 1 in 16 random check to request a barrel be thrown.

The rest of the barrels, up to a point, are requested about once every half second. However, since it takes a little over a second and a half to actually animate the launching sequence (unless throwing, which is slightly faster), barrel requests can never be serviced at this rate. Apparently, the programmers attempted to increase the frequency of barrel introductions as the game difficulty goes up, but because requests cannot be made while barrels are being launched, the check at $2C1B has only very subtle effects on the timing of requests and launches.

There’s an interesting check at $2C33 that allows for a 50-50 chance to abort the request if the barrel stack is now half depleted. Apparently, this was intended to give the player a break after the initial onslaught of the first half. Another check involving the barrel stack occurs at $2CE6. This causes the barrel stack to the left of DK to disappear one by one as the last four barrels are launched. Since the bonus counter is decremented once every barrel launch, the barrel stack vanishing is a visual indicator of the last six seconds or so before the player dies.

Next up I’ll attempt to explain how the barrel introduction code has been “hijacked” by DK Jr. to introduce blue traps and sparks. The whole thing is an unfortunate mess that I’m certain even the original programmers poorly understood.

Descending ladders

One of the interesting things (if not the only interesting thing) about disassembling DK Jr. is that, as mentioned before, it builds on the same code used by the original DK. For example, the code that implements the fireball's AI is almost completely reused by the red traps on the "vines" and "chains" boards. In addition, the blue traps (and the blue sparks, to some extent) reuse portions of the barrel AI.

An interesting component of the barrel AI is how taking a ladder (or rolling past) is decided. Once an object is at the proper alignment to descend a ladder, the code checks a few things (if you're interested in following along, this starts at $217F).

First, the object must not be too far below the player. After all, there's not much point in taking a ladder if it's not going to cross the player's path, and it's much better to allow the barrel to scuttle off the sides of the screen and get recycled (although this is not possible for blue trap).

Second, there is a 75% chance that the process will be aborted and the barrel (or blue trap) will simply breeze by. This probability decreases as the game gets more difficult (at the highest difficulty, it's only 25%).

Third, there are checks to determine if we're likely to cross the path of the player once the descent takes place. If we're directly above the player, we always descend. If we're either side of the player and he's heading towards us, we also descend.

Notice the code makes no check to determine the slant of the girder (and hence which direction it'll take at the bottom of the ladder). It merely uses the players heading as an indication. This means, to some extent, that you can influence whether or not a ladder is taken. For example, if you want a barrel to descend rather than pass over you, you could push the joystick in the opposite direction to make it more likely that the barrel will descend and then harmlessly head off in the opposite direction. If you're on the wrong side of the ladder and you're worried a barrel will come down, you can simply stop moving and decrease the probability that it will.

Lastly, even if it doesn't appear that the barrel will cross the player's path (as described in the third step), there's still a one in four chance that it will take the ladder anyway.

As interesting as this all is, the intricacies of this process are wasted on DK Jr., since the blue traps only appear on the first board, and the logic described above only comes into play on the first platform. In fact, when a blue trap takes the leftmost or rightmost vine off the first platform, it's not even as a result of these checks (usually) . The blue sparks also have completely separate code that governs ladder descent.

Ah, well.