thwaite notes

By Damian Yerrick

When making Thwaite better, it is important to know how it works.

Characters

There are ten houses and two missile silos. Each non-player character (NPC) has a specific role in cut scenes.

#NameSexRole
0TildaFParanoid
1MegFLaid back
2MiloMPlayer 1
3IscaFDetective
4GnivadMDetective
5JustinMLaid back
6BriarFParanoid
7AchaFDetective
8TorbenMParanoid
9StaisyFPlayer 2
10ThadMLaid back
11OliverMDetective

The NPC personalities correspond loosely to the three personalities for each sex in Animal Crossing series:

To avoid any appearance of impropriety, I intentionally avoided using any names from Animal Crossing series. Villagers 5 and 8 were the last to be named. Snowy suggested "Trop", "Justin", "Willie", and one other that I forget. I chose "Torben" for 8, which sounds like "Trop" but doesn't call to mind TV Tropes, and I used "Justin" for 5, leading to plenty of Justin Bieber jokes among play testers who would intentionally let Justin's house get blown up. Interestingly enough, there were no Justin Timberlake jokes, proving once again that no one has a memory over two years old.

Missiles

Waves

The game consists of seven days: Sunday through Saturday. Each day consists of five waves, one in each hour from 01: to 05:

Missile types

There are seven types of salvo: 1 to 5 normal missiles, one balloon, and one MIRV missile. Each wave has from 10 to 40 incoming enemy missiles, with a few exceptions. A new salvo is generated once every time period that the wave specifies.

Normal missiles

Each of one to five missiles in a salvo is generated at a random (start X, destination target).

Balloons

Instead of a salvo of missiles, occasionally a balloon carrying a crate slowly drifts in from the left. It moves at half the speed of an ordinary missile. This costs two missiles and is timed to activate over a randomly chosen house (1-10). If the player doesn't blow it up, it drops a missile over that house, one to the left, and one to the right. Creating a balloon costs two missiles.

MIRV

Occasionally, the first missile in a salvo is replaced with a MIRV (stands for "multiple independent reentry vehicles"). When a MIRV crosses 128 pixels above the impact line, it becomes three missiles. One follows the original track, another aims two houses to one side, and the third aims either two houses to the other side or (if that'd be off the playfield) between the two. Creating a MIRV costs two missiles.

The original formula for targeting the MIRVs was as follows.

building_dx = building_x[target[new]] - building_x[target[old]]
yspeed[new] = yspeed[old]
xspeed[new] = xspeed[old] + yspeed[old] * building_dx

Gimmick waves

There are a couple special kinds of waves intended to provide a change of pace that surprises complacent players. Fast waves are shorter and have smaller salvos of 1 and 2 missiles that have substantially increased travel speeds to test the player's reaction time and speed of precise ABM placement. Balloon Fever waves have a salvo set of 75% balloons and 25% MIRV, moderately increased travel rates, and substantially increased missile (40 to 50) balanced by the higher cost of splitting missiles. Because all balloons come in from the left, the player is tempted to overuse Milo's silo and leave Staisy's underused. (They're named after an inside joke on a Dance Dance Revolution fan forum.)

Scheduling

Each second is split into ten tenths, and each tenth is split into six (NTSC) or five (PAL) frames. To spread the CPU load across multiple frames, some parts of the logic execute only on one frame of the tenth.

  1. Spawn new missiles
  2. Look for threatened buildings (scurry.s)
  3. Remove expired tip from screen
  4. Move half the villagers by one step (scurry.s)
  5. Nothing yet
  6. Do not schedule anything for this frame, as it doesn't exist on PAL.

Scurrying villagers

Check

A building is threatened (or in "check") when all of the following are true:

When a missile aimed at a threatened building collides with an explosion, the building it was targeting is removed from threat. Its state may change back to threat on the next frame if another missile is targeting it as well. But because regular missiles are subject to LRU limits on attacking a single building, this usually happens for missiles split from MIRVs and balloons.

Villager behavior

There are 12 villagers, one for each building. Each starts in its own building. If not inside its target building, each villager takes a step toward its target building every two tenths of a second. If a villager is inside a threatened building in check, the villager will run toward a nearby building that is not threatened.

Villager display

For dropout control purposes, out villagers should be drawn odd first then even first in alternate frames, but this shouldn't matter too much until the player is almost dead anyway.

Game states

STATE_NEW_LEVEL

Start displaying the level's tip and copy the wave's data into the level registers.

STATE_ACTIVE

Player and enemy missiles launch only during this state. Track whether the player has lost a building during the level. Once all enemy missiles have been destroyed, stop the music, and if there is at least one silo and at least one house, go to STATE_LEVEL_REWARD; otherwise go to STATE_GAMEOVER.

STATE_LEVEL_REWARD

Calculate 10 points for each missile and 100 for each house, add it to the player's score, and display a tip:

         Nice Job!
Left: 10⌂ 12⬋   Bonus: 11200

Once the tip finishes, go to STATE_REBUILD_SILO.

STATE_REBUILD_SILO

If the player has not lost a building during the wave or the wave is the fifth in the day, and there is only one silo left, repair the other silo and display a tip "Silo repair complete". Once the tip finishes displaying, go to STATE_CUTSCENE.

STATE_CUTSCENE

Go to the next hour. If we haven't passed 05:59, go to STATE_NEW_LEVEL. If a house has been destroyed for the first time, and the house's owner is not the current paranoid actor, choose new actors as described in "Choice of actors" below. Then choose the cut scene based on the first of the following rules that applies: If no building has been destroyed, show the cut scene for the current day from the perfect sequence. If the damage class has increased since last cut scene, show the cut scene for the new damage class. Otherwise, show the next cut scene from the investigation sequence and then go to STATE_REBUILD_HOUSE.

STATE_REBUILD_HOUSE

If this is not the last day (SAT), and at least one house is destroyed, choose a house that is destroyed, rebuild it, and display a tip "House rebuilt". Otherwise go to STATE_NEW_LEVEL. But if the tip has been displayed, then wait for it to end, and go to STATE_NEW_LEVEL.

STATE_GAMEOVER

Display a tip "GAME OVER", and zero out the game state. Once state is zeroed, the game loop ends.

Cut scenes

After the 5 AM round of each day, the game shows a scene with the center 6 houses drawn twice as big (4x4 tiles each instead of 2x2), with their left tile at x=1, 6, 11, 16, 21, 26. (This is slightly biased to the left, but the NES's video signal is biased to the right anyway.) Houses destroyed in the game are shown destroyed in the cut scene. Villagers are standing in front, also twice as big but still only 8px tall.

Choice of actors

There are ten villagers with two sexes and four personalities (see villager names.txt). At two points in the game, the program chooses one character of each personality. And if the paranoid and laid-back character are the same sex, the detective has to be of the opposite sex. The steps are as follows:

  1. Choose the paranoid one
  2. Choose the laid-back one
  3. Choose the detective
  4. If all three are of the same sex, choose a different detective

Once a house is blown up for the first time, if it isn't the one belonging to the chosen paranoid, then set the owner of that house as the new paranoid and choose a new laid-back and detective.

Town damage classes

The dialog between 6 AM and the next night depends on how well the player is defending buildings. The value in Y after jsr countHousesLeft can be

Each damage class has dialogue for the first day it was seen.

The script has two branches: perfect and at least one mistake. In the later stages of perfect (Wed-next Sun), it toys with the TASing player. (grep tas /usr/share/dict/words)

TAS mockery

To get on track for the canon ending, the player must do well but not perfect. Player doesn't learn who's behind this until something is blown up. If the player stays perfect even through Wednesday, the villagers begin to suspect something about the silos. Are they robotic?

A 100% run will not reveal the culprit, not even in the ending. The troubador returns to the Roost and continues to play as if nothing had happened that week. Next Sunday, the game runs for 20 seconds without a missile in sight.

Choice of cut scene

At the end of a game day, the game calculates the town's damage class and displays a cut scene based on the first rule that applies:

  1. If the damage class has remained perfect the whole game, display this hour's perfect cut scene.
  2. If the day is Saturday, display the ending cut scene.
  3. If the damage class has increased (from perfect to some or from perfect or some to most), show the appropriate cut scene for this damage class.
  4. Show the next cut scene in the "investigation" track.

Cut scene data format

Each scene starts with 4 bytes representing actors:

Most scenes will start with 'XYZM' or the like.

Following that is a set of control codes:

$00
Fade out and end cut scene.
$1A nn
Unknown
$09 nn xx
Actor n ('A'-'Z') walks toward horizontal position x ($00-$FF). Not yet implemented.
$0A
Advance subtitle cursor to next line.
$0C nn
Clear subtitle area and write actor name n ($31-$38).
$24 nn
Write name of actor n ('A'-'Z') to subtitle
$24 $24
Write '$' to subtitle
$20-$FF
Add character to subtitle

Ultimately, the player will see the house rebuilt as the sun rises and sets. http://iweb.tntech.edu/rhaggard/4120s10/Project/missile_command_specs.htm

Calling convention

Once, I ran into a problem where temporary variables used for collision were getting overwritten by the subroutine that starts a sound effect. After that, I established a calling convention, which I call "LOCAL-8":

Music inspiration

The music is a so-called Jimmy Hart Version of the early morning music from Animal Crossing series, with several of the melodies replaced by pieces of Ludwig Beethoven's Piano Sonata No. 8 in C minor (Pathétique). All music is in compound (swung) time at 100 (dotted?) quarter notes per minute, mostly cut time. The dissonance between the action and the music parallels the dissonance between the action and the ordinary experience during the wee hours of the morning in a sleepy little village.

Daytime
ACPG 4 AM, mixed with a song from episode "7 Continents for 7 Koopas from The Adventures of Super Mario Bros. 3. (Double Crossing anyone?)
1 AM
Not yet composed; uses 4 AM
2 AM
Pathétique, second movement, borrowing rhythm from ACWW 2 AM
3 AM
ACPG 4 AM
4 AM
ACWW 4 AM, mixed with ACWW 12 AM
5 AM
Not yet transcribed; uses 3 AM. A song has been prototyped in S3M that uses Pathétique, third movement, mixed with ACPG 5 AM.

Legal

Copyright © 2011 Damian Yerrick. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty.