The area of Mist is covered in a fog effect, which to this day feels impressive for an NES game. The implementation of the effect is actually quite simple, and is composed of the following: 1. **Multiple types of fog tiles.** These aren't part of an animation, but rather are different shading or configurations of the fog "particles" (the pixels making up the fog). 2. **Foreground placement.** The tiles are placed in the foreground, appearing to overlap the player, enemies, and blocks. 3. **Fog generator.** The Fog Generator is a block of code that computes some state (a fog state index and a fog tile index). The fog tile index ultimately maps to the lower byte of an address for a fog tile. 3. **Fog tile updates/animation.** The fog tile index's computed lower byte of an address is paired with an upper byte (hard-coded as `$18`). This becomes a fog tile address. This is then referenced by scheduling a [[PPU Buffer]] draw command: Rotate Sprite Right. This command takes a tile and shifts all pixels to the right one, creating the effect of fog moving to the right. Through this simple effect, and good placement of different static and animating-capable fog tiles in the foreground and in the background, the game can create a really effective fog atmosphere. # Addresses Fog generation uses the following addresses in memory: | Address | Name | Comment | | ------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | $001D | Fog tile index (0..7) | Incremented by 2 every drawing tick.<br><br>Decremented by 1 every non-drawing tick.<br><br>When wrapped up to 0 during drawing, a new value will be computed based on a lookup table.<br><br>The value is multiplied by 16 (tile data size) to get a lower byte of the tile address. | | $001E | Fog state index | When odd, fog animation occurs.<br><br>When even, the fog generator decrements until it hits 0, and then the fog index is incremented. | Functions include: | Address | Purpose | | ------- | ---------------------------------------------------------- | | $DFC5 | On-tick fog calculations and draw scheduling. | | $DFDE | Fog drawing (schedules the rotate-right PPU draw command). | # Algorithm ```c static char fogTileIndex = 0; static char fogStateIndex = 0; static char FOG_START_TILE_INDEXES = [ 0x18, 0x06, 0x30, 0x0C, ]; void onTick() { /* Limit this to the Mist area, which has the tiles to animate. */ if (!inMist) { return; } if ((fogStateIndex & 1) == 0) { /* On odd indexes, rotate a fog tile right. */ updateFogTiles(); } else { /* On even indexes, decrement the fog generator. */ fogTileIndex--; if (fogTileIndex == 0) { /* If that hits 0, increment the fog index. */ fogStateIndex++; } } } void updateFogTiles() { rotateTileRight( 0x18, // Upper byte for address fogGenerator * 16); // Lower byte for address /* Increment the fog generator by 2, but cap from values 0..7. */ fogTileIndex = (fogTileIndex + 2) & 7; if (fogTileIndex == 0) { /* The fog generator wrapped. Increment the lookup index. */ fogStateIndex++; /* Calculate new start position based on the index. */ fogTileIndex = FOG_START_TILE_INDEXES[(fogStateIndex / 2) & 3]; } } ```