Skip to content

Chapter 16

The enemy

Chapter 15 gave the player weapons and ground targets; this chapter is about what fights back. By its end you will know how the game keeps and flies an enemy aircraft, where the aircraft come from, why shooting one down takes long, how the ships shoot and sink, how the carrier is defended, and what the dashboard's 3-D view shows of them. The port and its instruments are gathered at the end.

Four records

The manual sends two kinds of enemy aircraft and ships to be sunk (pages 1, 10 and 11). Torpedo planes attack the player's carrier with torpedoes; fighters hunt the player's aircraft. The game keeps every one of them in an enemy aircraft record: one of four records of 52 bytes in a fixed table. A flight has to remember from one tick to the next where it is against the player, its speeds and height, its health and its timers; those are its fields. Every launch needs a free record, so no more than four enemy aircraft are ever in the air.

The record's first word, its state, says whether it is free, flying, shot down and falling, or burning on land; the routine that steps the records, below, has cases for two more values, which nothing ever sets, and no note says why. While the aircraft flies, its mode says what it is doing. The mode is a set of bits, one for each task: a fighter cruising, a fighter on the player's tail, a torpedo plane, a torpedo plane that has dropped its torpedo; a bit more is added while it turns. The diagram gives the numbers.

A diagram of the states and the modes, free, flying, falling and burning, with the arrows that change them.

The states and modes of an enemy aircraft record, the words' values in the boxes; on the arrows what moves a record on: a launch; first in the order within 160 pixels; the drop; health below 96; beyond 2,600 pixels, at rest away from land, or after about 100 ticks of burning.

Every tick the game works out the relation of each record in use, where it stands against the player: 1 behind him flying the same way, 3 ahead of him the same way; 2 flying the other way east of him, 4 the other way west of him. Among those behind him the same way it counts an order, 1 for the nearest. The record also keeps a health, 240 at the launch; a burst count, the ticks of hits the player's guns need for one burst, each burst taking 8 of the health; a hit flag; and two timers for its turns.

Its speed, in hundredths of a pixel a tick, chases a wanted speed while it flies: speeding up, by half the gap plus 5 a tick; slowing, by half the gap less 5, so it comes to rest about 10 above the wanted speed. A floor of 900 for a slowing aircraft can never act, since the wanted speed is held at 900 or more first. The height steps towards a wanted height, and the x moves by the speed times the factor of the attitude, the stage of a turn, on the ROM's floating point, as the player's does (chapter 14).

enemy_aircraft_step walks the four records once a tick. For each in use it takes the relation and the order, then acts by the state: a flying aircraft flies by its mode, trailing smoke by its damage; a shot-down one falls; a wreck burns. Then it eases the speed of one that flies, moves it unless it burns, and picks its frame. The compiler made the switch on the state a chain of subtractions: on the left, subq.l takes 1 off the state, then 1, 2, 4 and 8 more, a running total of 1, 2, 4, 8 and 16, and each beq lands on the case of the state that total matches. The port's C on the right walks the same way.

; re/Wings.lst 0x01E86A-0x01E8B6: enemy_aircraft_step [C], a part of 0x01E7D6-0x01E8B7
loc_01e86a:
01e86a  5380                 subq.l     #$1, d0
01e86c  67e0                 beq.b      $1e84e
01e86e  5380                 subq.l     #$1, d0
01e870  67ae                 beq.b      $1e820
01e872  5580                 subq.l     #$2, d0
01e874  679e                 beq.b      $1e814
01e876  5980                 subq.l     #$4, d0
01e878  67ec                 beq.b      $1e866
01e87a  5180                 subq.l     #$8, d0
01e87c  67dc                 beq.b      $1e85a
01e87e  60e8                 bra.b      $1e868
loc_01e880:
01e880  2f2dfffc             move.l     -$4(a5), -(a7)
01e884  4ebafdc8             jsr        $1e64e(pc)                             ; aircraft_speed
01e888  584f                 addq.w     #$4, a7
01e88a  206dfffc             movea.l    -$4(a5), a0
01e88e  0c500010             cmpi.w     #$10, (a0)
01e892  670a                 beq.b      $1e89e
01e894  2f2dfffc             move.l     -$4(a5), -(a7)
01e898  4ebaeefc             jsr        $1d796(pc)                             ; aircraft_motion
01e89c  584f                 addq.w     #$4, a7
loc_01e89e:
01e89e  2f2dfffc             move.l     -$4(a5), -(a7)
01e8a2  4ebaeab6             jsr        $1d35a(pc)                             ; aircraft_frame_index
01e8a6  584f                 addq.w     #$4, a7
loc_01e8a8:
01e8a8  5244                 addq.w     #$1, d4
01e8aa  b87c0004             cmp.w      #$4, d4
01e8ae  6d00ff32             blt.w      $1e7e2
01e8b2  281f                 move.l     (a7)+, d4
01e8b4  4e5d                 unlk       a5
01e8b6  4e75                 rts
/* src/enemy.c, lines 640-679 */
/* orig 0x01E7D6 enemy_aircraft_step - every record in use: its relation and the order, then
 * by its state 1 nothing, 2 its flight (and +0x24 at least 0x21 unless a torpedo plane),
 * 4 its fall, 8 nothing, 0x10 its burning; then, whatever the state has become, its
 * speed, its motion unless burning, and its frame. */
void wof_enemy_aircraft_step(void)
{
    wof_g.g_027e66 = 0;
    for (int16_t i = 0; i < 4; i++) {
        aircraft_t *a = &wof_m.aircraft_records[i];

        if (a->state == 0)
            continue;
        aircraft_relation(a);
        aircraft_order();
        switch (a->state) {
        case 1:
            aircraft_idle(a);
            break;
        case 2:
            aircraft_fly(a);
            if (!(a->mode & 4) && a->want_y < 0x21)
                a->want_y = 0x21;
            break;
        case 4:
            aircraft_falling(a);
            break;
        case 8:
            break;
        case 0x10:
            aircraft_burning(a);
            break;
        default:
            break;
        }
        aircraft_speed(a);
        if (a->state != 0x10)
            aircraft_motion(a);
        wof_aircraft_frame_index(a);
    }
}

How they fly

A cruising fighter goes by its relation: behind the player it wants a speed of his airspeed plus the distance between them; within 0xA0 pixels, 160, the first in the order goes onto his tail, and the others hang back at his height. Coming the other way east of him, it turns about, or slows while he turns; west of him, it slows, moves 32 pixels above or below his height and turns. Ahead of him the same way it lets him catch up and jinks, dodging between heights of 35 and 95. It turns when any of three things happens: after 550 ticks, when he turns, or 8 to 13 ticks after his guns hit it.

On the tail it keeps about 130 pixels behind him and takes his height. It fires only while it is first in the order, flying straight, its attitude 0, within 160 pixels and less than 8 of height: on the left, cmpi.w #$1,$c(a0) is the order's test, the others follow, and move.w #$1,$12(a0) sets its firing word, by which the pass draws its guns' flash. The flash does no harm; the hit count does, the word of the player's record that chapter 15's targets count down. At exactly his height, every other tick, the fighter counts it down too; when it runs out his oil falls by 8 and his fuel by up to 31, and a new count of 6 to 10 begins.

; re/Wings.lst 0x01DDDA-0x01DE30: fighter_attack [C], a part of 0x01DCCC-0x01DEA3
01ddda  4a6dfffc             tst.w      -$4(a5)
01ddde  670000b8             beq.w      $1de98
01dde2  206d0008             movea.l    $8(a5), a0
01dde6  0c680001000c         cmpi.w     #$1, $c(a0)
01ddec  660000aa             bne.w      $1de98
01ddf0  0c6d0008fffe         cmpi.w     #$8, -$2(a5)
01ddf6  6c0000a0             bge.w      $1de98
01ddfa  206d0008             movea.l    $8(a5), a0
01ddfe  4a680016             tst.w      $16(a0)
01de02  66000094             bne.w      $1de98
01de06  206d0008             movea.l    $8(a5), a0
01de0a  0c6800a00028         cmpi.w     #$a0, $28(a0)
01de10  6c000086             bge.w      $1de98
01de14  4a6dfffa             tst.w      -$6(a5)
01de18  677e                 beq.b      $1de98
01de1a  206ccdee             movea.l    -$3212(a4), a0                         ; player_record
01de1e  302dfff8             move.w     -$8(a5), d0
01de22  32280014             move.w     $14(a0), d1
01de26  b141                 eor.w      d0, d1
01de28  4a41                 tst.w      d1
01de2a  6c6c                 bge.b      $1de98
01de2c  206d0008             movea.l    $8(a5), a0
01de30  317c00010012         move.w     #$1, $12(a0)
/* src/enemy.c, lines 362-374, a part of fighter_attack (lines 334-376) */
if (on && a->order == 1 && dy < 8 && a->attitude == 0 && a->distance < 0xA0 && same &&
    (int16_t)(dx ^ P.facing) < 0) {
    a->firing = 1;
    if (!wof_g.g_026f72 && a->y == P.y && wof_g.g_027346) {
        P.w10--;
        if (P.w10 <= 0) {
            P.oil = (int16_t)(P.oil - 8);
            P.fuel = (int16_t)(P.fuel - (int16_t)wof_rand_mod(0x20));
            P.w10 = (int16_t)(wof_rand_mod(5) + 6);
        }
    }
} else {
    a->firing = 0;

A white enemy fighter at the top left, a yellow flash at its nose; ahead of it the blue Hellcat, trailing smoke.

The oil run, a replay of the script oil_d, about 58 seconds into map d's mission: the airfield's fighter on the player's tail. The run checks the fighter's record there: state 2, mode 2, relation 1, its firing word set.

A torpedo plane flies at the carrier at 9 pixels a tick, at a height of 50. Within 1,000 pixels before the deck it comes down to 20, and once at that height and flying straight it drops its torpedo into the sixteenth object record, chapter 15's, still short of the deck; the torpedo runs on in the sea into the carrier. Chased from behind, it keeps about 150 pixels ahead of the player, jinking. Once it has dropped, it climbs to 60 and flies on, and 2,600 pixels from the player its record is freed.

A turn steps the attitude by one every third tick; at 14 the facing turns, and past 25 the turn is over. The horizontal speed follows chapter 14's factor of the attitude, which falls to 0 in the middle of a turn, so an enemy aircraft almost stands still there. A fighter's wait before its next turn, its distance times 100 over its speed, is chapter 3's example of the 16-bit int; whether a distance that overflows it is ever reached, no run has measured. A cruising fighter ahead of him at attitude 13, mid-turn, keeps the player's aircraft from turning; no note says why.

The frame's number is the attitude, 0 to 25, plus 28 when the aircraft faces east. Two tables of 28 names, one for each facing, give its shape in japplane.shp, with 26 a torpedo plane flying straight and 27 the wreck:

Small white aircraft with red discs: two turns; a torpedo plane with its torpedo slung under it, and a burnt wreck.

A turn from west to east passes through jp1b to jp1f, one from east to west through jp13 to jp17, each name shown once where the attitude holds it for two or three steps; below, a torpedo plane flying straight and the wreck, each facing both ways.

Where they come from

Every launch goes through one routine, aircraft_launch, given a kind, an x, a height and a facing. It walks the four records and keeps the last free one it meets, where chapter 15's drop takes the first; no note says why. It launches a torpedo plane only while no other that has not yet dropped holds a record, flying or falling: it tests the torpedo plane's bit of the mode, which the 3-D view's arrow looks for too. A launch gives the record full health, a speed of 900 and a first burst of 5 to 7.

Three things call it. The first is the enemy's countdown, the player's record's field whose counting chapter 14 told. When it reaches 0, a torpedo plane comes 6,144 pixels from the player, on the carrier's side of him, flying towards him; over the deck a draw of the beam picks the side. The launch also needs the player more than 6,656 pixels short of x 32,767, the largest number a 16-bit word holds, which keeps the new aircraft's x inside a word; only the far east of the two longest maps fails the test. The launch is tried on that one tick: after each drop the countdown is 500 again, but a torpedo plane shot down before its drop, or a launch that failed, leaves it at 0, and none comes until a visit to the hold or the next aircraft sets it again.

The second is an airfield, a runway on an island from which fighters take off, its parked aircraft and its most fighters up given by the map's table. With the player within 480 pixels of it and fewer fighters up than its most, a parked aircraft rolls from its end, a pixel a tick faster every eight ticks up to 7, and takes off at the far end as a fighter. The roll starts a cooldown of 100 ticks, shared with the ships.

The third is a ship. Every enemy ship carries two to seven aircraft parked on its deck, with the most it lets up and a range of the player's x, from the map's tables. Afloat with hits left, with the player in its range and fewer fighters up, it sends up the last of its parked aircraft, always facing west. The Japanese carrier, the enemy's own carrier, readies one at a time on its deck instead and rolls it west, faster each tick towards 8 pixels a tick, until it leaves the ship's west end.

Shot down

While the guns fire (chapter 15), the tick tests every record. A record ahead of the player the same way, within 160 pixels and 0x14, 20, of his height, is hit while he leaves the stick alone, the pitch's target at 0. The hit flag is set and each tick of hits counts the burst down; at a burst's end the aircraft smokes and loses 8 of its health, and a new burst of 6 to 9 begins. Below 0x60, 96, it is shot down: 350 points and state 4.

From 240 that takes nineteen bursts, a first of 5 to 7 ticks of hits and eighteen of 6 to 9, 113 to 169 ticks; and they do not come at once, because every hit starts the aircraft's evasion, a turn 8 to 13 ticks later. On the left, the first test is cmpi.w #$3,$4(a0), the relation, and nothing tests the state. A freed record keeps the relation it last had, so a free record left at 3 near the player would be hit too, and below 96 paid for and set falling; no run has shown it, and the port does the same.

; re/Wings.lst 0x01B6A2-0x01B75C: guns [C], a part of 0x01B682-0x01B7BB
loc_01b6a2:
01b6a2  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b6a6  0c6800030004         cmpi.w     #$3, $4(a0)
01b6ac  660000f0             bne.w      $1b79e
01b6b0  206ccdee             movea.l    -$3212(a4), a0                         ; player_record
01b6b4  226ccdf2             movea.l    -$320e(a4), a1                         ; g_027df0
01b6b8  30280002             move.w     $2(a0), d0
01b6bc  90690020             sub.w      $20(a1), d0
01b6c0  3b40fff4             move.w     d0, -$c(a5)
01b6c4  4a40                 tst.w      d0
01b6c6  6c04                 bge.b      $1b6cc
01b6c8  446dfff4             neg.w      -$c(a5)
loc_01b6cc:
01b6cc  206ccdee             movea.l    -$3212(a4), a0                         ; player_record
01b6d0  226ccdf2             movea.l    -$320e(a4), a1                         ; g_027df0
01b6d4  3a10                 move.w     (a0), d5
01b6d6  9a690026             sub.w      $26(a1), d5
01b6da  4a45                 tst.w      d5
01b6dc  6c02                 bge.b      $1b6e0
01b6de  4445                 neg.w      d5
loc_01b6e0:
01b6e0  0c6d00a0fff4         cmpi.w     #$a0, -$c(a5)
01b6e6  6c0000b6             bge.w      $1b79e
01b6ea  ba7c0014             cmp.w      #$14, d5
01b6ee  6c0000ae             bge.w      $1b79e
01b6f2  4a6ca404             tst.w      -$5bfc(a4)                             ; pitch_target
01b6f6  660000a6             bne.w      $1b79e
01b6fa  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b6fe  317c00010006         move.w     #$1, $6(a0)
01b704  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b708  5368000a             subq.w     #$1, $a(a0)
01b70c  4a68000a             tst.w      $a(a0)
01b710  6e00008c             bgt.w      $1b79e
01b714  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b718  30280026             move.w     $26(a0), d0
01b71c  d07c000a             add.w      #$a, d0
01b720  3f00                 move.w     d0, -(a7)
01b722  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b726  30280020             move.w     $20(a0), d0
01b72a  907c0010             sub.w      #$10, d0
01b72e  3f00                 move.w     d0, -(a7)
01b730  3f3c0006             move.w     #$6, -(a7)
01b734  4267                 clr.w      -(a7)
01b736  4eba13a8             jsr        $1cae0(pc)                             ; burn_smoke
01b73a  504f                 addq.w     #$8, a7
01b73c  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b740  51680008             subq.w     #$8, $8(a0)
01b744  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b748  0c6800600008         cmpi.w     #$60, $8(a0)
01b74e  6c36                 bge.b      $1b786
01b750  06ac0000015ea34e     addi.l     #$15e, -$5cb2(a4)                      ; player_score
01b758  206ccdf2             movea.l    -$320e(a4), a0                         ; g_027df0
01b75c  30bc0004             move.w     #$4, (a0)
/* src/player.c, lines 467-485, a part of wof_guns (lines 452-493) */
if (a->relation != 3)
    continue;
dx = (int16_t)(P.x - a->x);
if (dx < 0)
    dx = (int16_t)-dx;
dy = (int16_t)(P.y - a->y);
if (dy < 0)
    dy = (int16_t)-dy;
if (dx >= 0xA0 || dy >= 0x14 || wof_g.pitch_target != 0)
    continue;
a->hit = 1;
a->burst--;
if (a->burst > 0)
    continue;
wof_burn_smoke(0, 6, (int16_t)(a->x - 0x10), (int16_t)(a->y + 0x0A));
a->health = (int16_t)(a->health - 8);
if (a->health < 0x60) {
    wof_g.player_score += 0x15E;
    a->state = 4;

A shot-down aircraft trails smoke and comes down; on the ground it slides, killing the soldiers within 20 pixels and hitting the map record under it as a crash does while faster than 500. When its speed falls below 100, the enemy plane counter on the dashboard counts the kill, on land or on the sea. On land the wreck then burns for about a hundred ticks and leaves its wreck's word, its x, negative when it faced west, in a list from which the pass draws it, and its record is freed; anywhere else the record is freed at once. The word goes to the list's start plus twice the count of wrecks, whatever the count: the list holds forty words, and a forty-first would land in the enemy aircraft records behind it. Chapter 20 returns to it among the original's quirks.

The pass draws the wrecks first, then every aircraft in use, at an eighth in the eighth-scale view; one that fires draws its guns' flash every other pass with chapter 12's exclusive-or blit. Ships and airfields show their parked aircraft, on an airfield 64 pixels apart.

The ships

The game keeps five ship records of 30 bytes: the destroyer, the battleship, the cruise ship, the Japanese carrier and the player's carrier. The cruise ship is the notes' name for the smallest, with four guns. The map's scan fills each record from the slot that introduces the ship (chapter 13), and it takes only the first of each kind, so a map can carry at most one ship of each.

Ship Guns Hits Deck height Score
destroyer 8 1 27 2,500
battleship 14 2 27 4,500
cruise ship 4 1 28 1,000
Japanese carrier 15 3 21 6,000
the player's carrier none 4 33 0

Maps a to c have no enemy ship and no airfield; the first ship comes on map f, and map o carries three, the most; chapter 13's table gives them map by map, and every map gets the countdown's torpedo planes.

Each gun has an entry of 14 bytes in the ship's list. While the player flies, every standing gun of every enemy ship afloat with hits left takes a shot at him in every pass, by draws of the beam, and fires on the aircraft as a target's gun does, chapter 15's.

The figures

A ship's gun's shot
The shot a draw below 512 must exceed the gun's distance from the player
His height at most 200
The splash six times in sixteen, within 32 pixels of him
A torpedo destroyed his or a torpedo plane's, within 10 pixels of the splash
A gun destroyed the first standing one within 16 pixels of a rocket, of a torpedo falling onto the deck, or of a crash: 200 points, then 49 puffs of smoke

The torpedo run and the sinking

A torpedo running in the sea that reaches a ship takes one of the ship's hits and flashes the sky red, chapter 11's sky flash, which a torpedo never makes on land. The manual asks for the ship's guns to be disabled before the torpedo run (page 7); the code counts the hit whatever the guns do. At 0 hits the ship sinks, drawn a row of pixels lower after each interval, which starts at 20 ticks and shortens by one with every row; the battleship, whose first interval the scan leaves at 0, takes its first row at once. Ten rows down an enemy ship pays its score, the ticker names it, the name chosen by its score, and one ship fewer is left. With no ship and no island left the mission is won, chapter 17's subject. At 120 rows the ship is gone and its map records are cleared.

Two places in this routine decided how the port had to be written. The carrier and an enemy ship take different paths at every row, and what tells them apart is the carrier's score of 0. The listing compares the rows with 1, cmpi.w #$1,$14(a1), then loads the score, move.w $12(a1),d0, and only then branches with beq. A move sets the flags from the value it moves, so the branch reads the score: the comparison's result is overwritten and decides nothing, and a score of 0 takes the carrier's path.

The second is the last ship. subq.b #$1 takes one off the count of ships left, and bgt branches while ships remain. But bgt judges the true result of the subtraction, overflow included, not the byte it leaves: from 0x80, −128 as a signed byte, the byte becomes 0x7F with the overflow flag set, and the branch is not taken. With no island left, the mission would be won with 127 ships still to sink. The port tests the byte before the decrement, as a signed number, against 1, which is what bgt decides. One of the oracle's random states, its case 508 of the sinking, found it; no map has more than three enemy ships.

; re/Wings.lst 0x011CD8-0x011D2C: ship_sinking [asm], a part of 0x011CD8-0x011DE3
ship_sinking:
011cd8  48e7c0e0             movem.l    d0-d1/a0-a2, -(a7)
011cdc  53690016             subq.w     #$1, $16(a1)
011ce0  6e0000fc             bgt.w      $11dde
011ce4  52690014             addq.w     #$1, $14(a1)
011ce8  336900180016         move.w     $18(a1), $16(a1)
011cee  67000006             beq.w      $11cf6
011cf2  53690018             subq.w     #$1, $18(a1)
loc_011cf6:
011cf6  0c6900010014         cmpi.w     #$1, $14(a1)
011cfc  30290012             move.w     $12(a1), d0
011d00  6700002e             beq.w      $11d30
011d04  0c69000a0014         cmpi.w     #$a, $14(a1)
011d0a  66000052             bne.w      $11d5e
011d0e  48c0                 ext.l      d0
011d10  d1aca34e             add.l      d0, -$5cb2(a4)                         ; player_score
011d14  4eba392a             jsr        $15640(pc)                             ; ship_sunk_message
011d18  532ca373             subq.b     #$1, -$5c8d(a4)                        ; ships_left
011d1c  6e000034             bgt.w      $11d52
011d20  4a2ca385             tst.b      -$5c7b(a4)                             ; islands_left
011d24  6600002c             bne.w      $11d52
011d28  4eac8170             jsr        -$7e90(a4)                             ; -> mission_won
011d2c  600000b0             bra.w      $11dde
/* src/tick.c, lines 543-552, a part of ship_sinking (lines 519-584) */
} else if (s->w14 == 10) {
    wof_g.player_score += (uint32_t)(int32_t)s->w12;
    wof_ship_sunk_message(s);
    /* subq.b #1 then bgt: the signed result before its byte wraps, so 0x80 is not > 0 */
    if ((int8_t)wof_g.ships_left-- > 1 || wof_g.islands_left != 0) {
        if (wof_g.ticker_message == 0)                    /* 0x01555A: ticker_text */
            wof_g.ticker_message = 0x02716Au;
        return;
    }
    wof_mission_won();

The carrier's defence

The player's carrier takes four hits, one for each torpedo plane's torpedo that runs into it, and goes down as a ship does. At every row while the player is aboard, in the hold, the code puts him back on the lift with the weapon menu closed; at 33 rows his aircraft, if it stands on the deck, goes into the sea, the lives are taken and the count to the game's end starts, chapter 17's. The enemy's countdown stops.

What defends the carrier is the manual's (page 11): shoot the torpedo plane down before it drops, or destroy its torpedo in the water. The walk of the torpedoes in the sea tests the sixteenth object record whatever its type, so the enemy's torpedo is destroyed by the same things as the player's: the bullets' splashes, a bomb or a rocket nearby, and an enemy ship's shot. An arrow at the top of the 3-D view points west or east to the first torpedo plane that has not yet dropped.

The 3-D view

The 3-D view is the window in the middle of the dashboard, the manual's view from the cockpit (page 8). It shows the sky and the sea, the map records ahead of the aircraft in eleven rows of the window from the horizon down, and a cursor whose row follows the height, the manual's artificial horizon. An enemy aircraft ahead is drawn on the row of the window that holds its distance, in the window's middle, a quarter of its height plus 4 above the row, with a frame picked by its own frame and that row from the dashboard's small pictures of the enemy.

The 3-D view enlarged: the cursor's ring, a small white aircraft below it, a red arrow pointing east.

The countdown run, a replay of countdown_b, about 146 seconds into map b's mission: the torpedo plane coming at the player, below the cursor, and the arrow to it. The run checks the plane's state, mode and relation, 2, 4 and 2, and the player's facing.

Under the score, the enemy plane counter shows the kills, a kill icon for each, seven to a row in two rows: after fourteen the icons stop, and the digits go on to 99 (page 9).

The figures

The times, on PAL, derived Ticks Seconds
The next torpedo plane after a drop, without the button 500 40
An enemy aircraft's turn 25 steps × 3 about 6
A kill: nineteen bursts of hits 113 to 169 9 to 14
A fighter at his height: from full oil to the engine's end about 60 to 100 about 5 to 8
The cooldown, from the start of a roll 100 8
A ship sunk in torpedo_f, observed: its score, and gone 163; 328 13; about 26

What the port made of it

src/enemy.c holds the original's compiled C behind the walk, routine by routine in the original's order, each with its orig comment and the 16-bit widths, the record's fields named in src/records.def. The two speed limits, 900 and 2,600 hundredths, 9 and 26 pixels a tick, are words of the original's data that nothing writes, registered all the same; 2,600 is also the distance in pixels at which a dropped torpedo plane is freed, a constant written into the code there.

The wreck's word is stored by its original address: the port writes its two bytes, big-endian, into whichever registered variable or table covers that address, so a forty-first word lands in the aircraft records as the original's does. Where the ships' guns hand on the upper words of two registers to the targets' fire, the port passes them, chapter 9's family of upper words. The sounds of these routines are chapter 18's.

How it is held

Twenty-five mission scripts fly the enemy, by the autopilot of chapter 8 with new parts: the countdown left to run, the dogfight, the torpedo at a ship, the crash on a ship and the wait in the hold. Every script runs in the closed loop, every tick and pass compared, five only in the suite's long run and two also at one and three VBlanks a pass, and in the open loop with its differences attributed: one is allowed only where a later milestone's stand-in was reached, and none differed. The completeness list accounts for every address they write, and the tables the pass walks are held against all fifteen maps.

Under the oracle, each routine of the module that takes a record is held over 1,200 random settings of the registered state, and the cases run every stretch of the code no script reached. The enemy's guns' flash is a second test of chapter 12's exclusive-or blit. The page test flies map d from the keyboard and finds the airfield's fighter in the picture by its frame's pixels, since colour alone could not tell it (chapter 24). Fourteen controls broke the port on purpose, and the loops caught each:

Control Script Caught
the countdown after a drop 501 for 500 countdown_b at tick 2021
the kill icons 12 pixels apart for 13 kills_a in the first pass

No flight shot an enemy aircraft down over land. Over map a's island the dug-outs' fire took the oil in the low chase; against the airfields' fighters, seven plans of up to 15,000 ticks brought none down: hit, a fighter turns away, jinks down to 35 pixels, where the chase flies into the ground, and on the tail takes the oil. A poke reaches the fall on land instead: a fighter shot down high over map a's island, placed in a record.

Here is the dogfight's close chase: it holds the button from 400 pixels, though a hit needs 160, because the guns fire only after ten VBlanks held, and it pushes the stick forward or back always with the direction of flight, since forward alone, flying west, is the landing stall.

# tools/m6_autopilot.py, lines 282-294, a part of dogfight (lines 244-294)
# The chase.  A torpedo plane chased from behind (0x01DEB0) wants the player's airspeed
# less the gap beyond 150 (+0x1E from +0x28), so it keeps about 150 pixels ahead by
# itself, inside the guns' reach, and jinks to heights of 35 to 95; the chase holds full
# speed and follows the height with short pushes, each with the direction, because
# forward alone while flying left is the stall (0x025AAA).
# The button is held through the whole close chase, corrections included: the guns need
# it held for ten VBlanks before they fire (the hold latch), and a press let go sooner
# would drop the other weapon (the tap latch).
push = way if gap > 100 or s['air'] < 1000 else ''
fire = 'F' if 0 < gap < 400 else ''
if abs(dy) >= 14 or s['y'] < low:
    return way + m5_autopilot.hold_height(s, max(e['y'], low), gain=2.0, limit=3) + fire
return push + fire

For the developer

Other routines: fighter_cruise 0x01D9C6, torpedo_plane 0x01DEA4, aircraft_launch 0x01E4D0, window_strip 0x014206. The Japanese carrier draws one shape more, its thirteenth name, which japcarrier.shp does not hold, so the call draws nothing; the port makes the same call. The unread word after the speed limits is registered too, so that the C structure of the globals needs no padding. The wreck's word is stored by wof_original_store16 in src/core.c; the scripts are tools/m6_scripts.py, their schedules tools/m6_runs.py.

What comes next

The chapter in one sentence: four records fly the enemy aircraft by state, mode and relation, launched by the countdown, airfields and ships and shot down in nineteen bursts; five records keep the ships, which shoot and sink row by row. Chapter 17 takes up the campaign: the mission won and lost, the ranks the maps belong to, the night, and the game's end after the carrier sinks.

Further reading

Outside the repository: Wikipedia's "Fighter aircraft" and "Torpedo bomber", for the real kinds.