Chapter 14
The player¶
Chapter 13 laid out the strip of records the aircraft flies over; this chapter is about the aircraft. By its end you will know what the game keeps of the player; how one logic tick turns the stick into a motion, partly on the floating point of the Amiga's ROM; the take-off and the landing, and why the landing needs the stick held forward; the lift and the hold; the fuel and the oil; every way an aircraft is lost and how the next comes; and what the fire button does besides firing. It ends with what the port made of it and the instruments that hold it.
What the game keeps of the player¶
Everything a tick does to the aircraft goes through one place, the player's record: thirty bytes at a fixed address that say where the aircraft is, how fast it moves and what it is doing. With a few variables beside it and the mirror markers of chapter 12, it is the player's state, which the loops of chapter 8 compare after every tick.
| Field | What it holds |
|---|---|
| height | pixels above the water line, the sea's surface |
| x | the world x, pixels from the map's west end |
| frame | the shape it is drawn with, a pointer and a name |
| state | what the tick does with the aircraft, the table below |
| fuel | 0xC0 when full |
| oil | 0x80 when full |
| the hit count | the hits of a gun still to come before the oil and the fuel fall, 6 to 9 at a reset |
| facing | +1 flying east, −1 west |
| two speeds | horizontal and vertical, pixels a tick |
| the enemy's countdown | ticks |
One more word has no use that the notes name.
The state word picks what the player's update, run once a tick, does with the aircraft.
| State | The aircraft |
|---|---|
| 0 | in the air |
| 1 | on the deck, or standing in the hold |
| 4 | coming down |
| 6 | in the sea, or a wreck at rest on a ship's deck below a height of 20 |
| 7 | held by an arresting cable |
| 8 | burning, a wreck at rest on land or higher on a ship |
| 11 | on the lift while it moves |
Five more values, 2, 3, 5, 9 and 10, share the lift's branch or do nothing, and are never set. Beside the record lie the variables of the flight. The airspeed is a number from 0 to 1,400 that scales both speeds. There is no throttle lever: the stick is the throttle, as the manual's diagram says (page 5). Pushed the way the aircraft faces, it raises the airspeed each tick by the airspeed's step, which grows by one a tick up to 8; left alone, the step shrinks to 4 and the airspeed falls by it, in the air to 1,000. The pitch is the aircraft's angle in hundredths of a degree, positive with the nose up, which moves towards a target the stick sets; a step of the target is 6 degrees. The attitude, the notes' name for the stage of a turn, is 0 when the aircraft flies straight and 1 to 25 while it turns.
The flight model¶
Once a tick, while the aircraft is in the air, the routine player_motion turns the pitch and the airspeed into a move. It moves the pitch a quarter of the way to its target, so that the nose swings over a few ticks when the stick moves the target; the division rounds towards zero, so the pitch stops a few hundredths short.
The sine and the cosine of the angle come from a table of sines, one for each whole degree from 0 to 90; the cosine is the sine of 90 degrees less the angle. From them the routine splits the airspeed into a horizontal speed and a vertical speed, each divided by 100. The horizontal speed is also multiplied by a factor for the attitude, which falls from 1 in straight flight to 0 at the middle of a turn, the stage where the facing changes, and has 50 added before the division, so that it is rounded to the nearest whole pixel. In level flight, then, the airspeed counts hundredths of a pixel a tick.
One tick of the flight model: the two speeds from the pitch and the airspeed, the ceiling the aircraft bounces off, and the airspeed below which it sinks.
On the left, the horizontal speed: the factor times the airspeed made floating point (ffp_flt), times the cosine, plus 0xC8000046, which is 50 (a mantissa of 0.78125 times 2 to the 6th), divided by 100 and cut to a whole number (ffp_fix); muls.w multiplies it by the facing and adds it to the x. The vertical speed follows with the sine, without the factor and without the 50. On the right, the port's C makes the same calls on the same values.
; re/Wings.lst 0x01BEC4-0x01BF50: player_motion [C], a part of 0x01BDFA-0x01BFF3
loc_01bec4:
01bec4 302ca410 move.w -$5bf0(a4), d0 ; attitude_index
01bec8 48c0 ext.l d0
01beca e580 asl.l #$2, d0
01becc 41ecab0e lea.l -$54f2(a4), a0 ; attitude_factor
01bed0 2200 move.l d0, d1
01bed2 20301800 move.l (a0, d1.l), d0
01bed6 322ca416 move.w -$5bea(a4), d1 ; airspeed
01beda 48c1 ext.l d1
01bedc 2f00 move.l d0, -(a7)
01bede 2001 move.l d1, d0
01bee0 4eba5e00 jsr $21ce2(pc) ; ffp_flt
01bee4 2200 move.l d0, d1
01bee6 201f move.l (a7)+, d0
01bee8 4eba5e02 jsr $21cec(pc) ; ffp_mul
01beec 222dfff8 move.l -$8(a5), d1
01bef0 4eba5dfa jsr $21cec(pc) ; ffp_mul
01bef4 223cc8000046 move.l #$c8000046, d1
01befa 4eba5da0 jsr $21c9c(pc) ; ffp_add
01befe 223cc8000047 move.l #$c8000047, d1
01bf04 4eba5dd2 jsr $21cd8(pc) ; ffp_div
01bf08 4eba5dba jsr $21cc4(pc) ; ffp_fix
01bf0c 206ccdee movea.l -$3212(a4), a0 ; player_record
01bf10 31400016 move.w d0, $16(a0)
01bf14 206ccdee movea.l -$3212(a4), a0 ; player_record
01bf18 226ccdee movea.l -$3212(a4), a1 ; player_record
01bf1c 2c6ccdee movea.l -$3212(a4), a6 ; player_record
01bf20 30290016 move.w $16(a1), d0
01bf24 c1ee0014 muls.w $14(a6), d0
01bf28 d1680002 add.w d0, $2(a0)
01bf2c 302ca416 move.w -$5bea(a4), d0 ; airspeed
01bf30 48c0 ext.l d0
01bf32 4eba5dae jsr $21ce2(pc) ; ffp_flt
01bf36 222dfffc move.l -$4(a5), d1
01bf3a 4eba5db0 jsr $21cec(pc) ; ffp_mul
01bf3e 223cc8000047 move.l #$c8000047, d1
01bf44 4eba5d92 jsr $21cd8(pc) ; ffp_div
01bf48 4eba5d7a jsr $21cc4(pc) ; ffp_fix
01bf4c 206ccdee movea.l -$3212(a4), a0 ; player_record
01bf50 31400018 move.w d0, $18(a0)
/* src/player.c, lines 688-698, a part of wof_player_motion (lines 661-715) */
v = wof_ffp_mul(wof_image32(0x025B0Cu + 4u * (uint32_t)(int32_t)wof_g.attitude_index),
wof_ffp_flt((uint32_t)(int32_t)wof_g.airspeed));
v = wof_ffp_mul(v, along);
v = wof_ffp_add(v, 0xC8000046u); /* + 50 */
v = wof_ffp_div(v, 0xC8000047u); /* / 100 */
P.speed_x = (int16_t)wof_ffp_fix(v);
P.x = (int16_t)(P.x + (int16_t)(P.speed_x * P.facing));
v = wof_ffp_mul(wof_ffp_flt((uint32_t)(int32_t)wof_g.airspeed), across);
v = wof_ffp_div(v, 0xC8000047u);
P.speed_y = (int16_t)wof_ffp_fix(v);
Climbing and diving leave the airspeed as it is (the sidebar has the one line that seems to say otherwise).
Below an airspeed of 1,000 the aircraft sinks: the vertical speed loses another pixel a tick for every hundred the airspeed lacks, and the pitch's target drops by half a step a tick unless the stick is held forward. A player sees it after a slow take-off, the aircraft sagging towards the sea before it climbs; it is not the game's stall, which the next section tells. The tests hold the motion against a model too: tests/ffp_model.py states in Python what the routine computes, the floating point handed in, and reproduces every value the original computed in the flights observed. Its part for the slow flight, g_025414 the airspeed and g_026d43 the input byte, whose bit 0 is the stick forward:
# tests/ffp_model.py, lines 176-185, a part of model_01bdfa (lines 115-201)
# 0x01BF2C: vertical speed = airspeed x across / 100, less a drop while slow.
climb = ffp(0x01BF3A, 'mul', ffp(0x01BF32, 'flt', s32(g_025414)), across)
climb = ffp(0x01BF44, 'div', climb, 0xC8000047) # 100.0
player_18 = s16(ffp(0x01BF48, 'fix', climb))
if g_025414 < 0x3E8 and player_c == 0:
if not g_026d43 & 1:
g_025402 = s16(g_025402 - divs_w(g_025f16, 2))
if g_025402 < s16(0xEE6C):
g_025402 = s16(0xEE6C)
player_18 = s16(player_18 - divs_w(s16(0x3E8 - g_025414), 100))
Last, the height moves by the vertical speed. Above 1,100 it is held at 1,100, the vertical speed is halved and turned round and the pitch's target turned round, so the aircraft bounces off a ceiling; below −4 it is held at −4.
Only the dozen calls that make the two speeds are the fast floating point of the Kickstart ROM, six of its nine operations; the easing, the sinking and the bounds are the 68000's integer arithmetic. The port does the floating point with the ROM's routines transliterated into integer code (chapter 5), because a browser's rounds differently and the speeds are cut to whole pixels: a last bit that differs would tip a rounding sooner or later, and the two flights would part for good. Under the oracle the motion is held over 3,000 random settings of the registered state, the ceiling and the airspeed's floor of 1,000 among them, against the original on the ROM's routines and against the model on the port's floating point.
The stick¶
The stick reaches the logic only through the input byte of chapter 7, four bits for the directions and two for the button. As chapter 1 said, pushing it forward climbs; in the air it works much as the manual's diagram lays it out (page 5):
| The stick | In the air |
|---|---|
| forward, with left or right | a climb: the target up a step a tick, to 30 degrees; less below an airspeed of 1,000 |
| forward alone | flying west, the stall the landing needs; flying east, the target lowered, for no reason the notes give |
| back, with left or right | a dive: the target down a step a tick, half while turning, to 45 degrees down |
| back alone | a steep dive, two steps a tick |
| towards the facing | full throttle: the airspeed up by its step, to 1,400 |
| against the facing | a turn |
| left alone | a climb levels out, the airspeed falls to 1,000, a turn goes on or unwinds |
While the aircraft turns with neither forward nor back, the pitch's target sinks by a quarter of a step a tick, so a turn loses height unless the stick is pushed forward; the manual asks for more lift while turning (page 5).
A turn runs the attitude from 0 to 25, one stage every second tick. At 14 the facing changes, and after 25 the attitude is 0 again, the aircraft flying the other way. For each attitude a table gives the frame, one table for each facing, and the turn's frames are drawn as the container stores them; only the frames of straight flight, chosen by the pitch's target, and those on the deck are mirrored in place through the mirror marker of chapter 12. A turn begun facing west shows these frames:

The frames of a turn from facing west to facing east, in the order the attitude shows them, each drawn as hellcat.shp stores it. The facing changes at stage 14 while hc32 holds for five stages, so 25 stages show 21 frames.
The stick left alone lets a turn finish once it is past its sixth stage; earlier, the aircraft rolls back, one stage a tick.
Since straight flight takes its frame from the pitch's target, not from the pitch, the frame shows where the nose is going. The landing stall is a flag that the stick forward alone sets while the aircraft flies west, and every other input clears. The same input moves the target to 6 degrees up, so the aircraft is drawn nose up; but while the flag is set and the target stands there, the motion eases the pitch towards 8 degrees down instead, and the aircraft drops. A player knows it as the stall the manual teaches for the landing (page 6): the nose raised, the stick forward alone, the aircraft sinking onto the deck.
On the deck and off it¶
On the deck another routine reads the stick. Pushed towards the facing it raises the airspeed by its step, as in the air; against the facing it takes 8 off the airspeed a tick and, once the aircraft stands, turns it round on the spot, one stage a tick; left alone the airspeed falls by 8 a tick to 0. Each tick the aircraft rolls a hundredth of its airspeed along the deck, rounded. The deck runs between two ends, sixteen pixels in from the carrier's sides; past either end the aircraft is in the air, state 0, with the airspeed the roll gave it, and too slow to climb it comes down in the sea.
The figures below follow one flight, the landing run, a run of the port made for this book: it replays the landing chapter 8's autopilot flew, from the schedule the headless original recorded, and meets the original's states at the same VBlanks. On the lift facing west, the aircraft is turned round with the stick against the facing and rolled east along the deck; it leaves the deck's east end slower than 1,000, sags towards the sea and climbs with the stick pushed east and forward, much as the manual's take-off asks (page 5).
The landing¶
The approach comes from the east, the aircraft facing west, as the manual teaches (page 6). When the aircraft touches what lies under it, its wheels below the ground height of chapter 13 or at or below the water line, the routine of the ground decides. It counts the aircraft over the deck when its x lies between the deck's ends, its attitude is 0, its wheels are no more than 4 pixels below the deck and the carrier is afloat. Then it lands only facing west with the landing stall set; anything else over the deck bounces.
After the test of the deck, the listing tests the facing, cmpi.w #$ffff,$14(a0), and the flag, tst.w landing_stall; a landing writes 1, the deck's state, into the record (move.w #$1,$c(a0)). The bounce turns the vertical speed and the pitch's target round with two neg.w and lifts the aircraft 6 pixels (addq.w #$6,(a0)). Both sound the screech.
; re/Wings.lst 0x01BB18-0x01BB7E: ground_contact [C], a part of 0x01BA80-0x01BC01
01bb18 4a6dfff6 tst.w -$a(a5)
01bb1c 6766 beq.b $1bb84
01bb1e 206ccdee movea.l -$3212(a4), a0 ; player_record
01bb22 0c68ffff0014 cmpi.w #$ffff, $14(a0)
01bb28 663e bne.b $1bb68
01bb2a 4a6caaac tst.w -$5554(a4) ; landing_stall
01bb2e 6738 beq.b $1bb68
01bb30 206ccdee movea.l -$3212(a4), a0 ; player_record
01bb34 317c0001000c move.w #$1, $c(a0)
01bb3a 397cffffaaa0 move.w #$ffff, -$5560(a4) ; g_025a9e
01bb40 4eac8086 jsr -$7f7a(a4) ; -> sound_screech
01bb44 206ccdee movea.l -$3212(a4), a0 ; player_record
01bb48 2f08 move.l a0, -(a7)
01bb4a 4ebaef9e jsr $1aaea(pc) ; wheel_height
01bb4e 205f movea.l (a7)+, a0
01bb50 3f00 move.w d0, -(a7)
01bb52 2f08 move.l a0, -(a7)
01bb54 2f2dfffc move.l -$4(a5), -(a7)
01bb58 4eba9bb6 jsr $15710(pc) ; sub_015710
01bb5c 584f addq.w #$4, a7
01bb5e 205f movea.l (a7)+, a0
01bb60 321f move.w (a7)+, d1
01bb62 d240 add.w d0, d1
01bb64 3081 move.w d1, (a0)
01bb66 601a bra.b $1bb82
loc_01bb68:
01bb68 206ccdee movea.l -$3212(a4), a0 ; player_record
01bb6c 226ccdee movea.l -$3212(a4), a1 ; player_record
01bb70 44680018 neg.w $18(a0)
01bb74 446ca404 neg.w -$5bfc(a4) ; pitch_target
01bb78 206ccdee movea.l -$3212(a4), a0 ; player_record
01bb7c 5c50 addq.w #$6, (a0)
01bb7e 4eac8086 jsr -$7f7a(a4) ; -> sound_screech
/* src/player.c, lines 568-580, a part of ground (lines 554-589) */
if (deck) {
if (P.facing == -1 && wof_g.landing_stall) {
P.on_deck = 1;
wof_g.g_025a9e = -1;
wof_sound_screech(); /* 0x012380 */
P.y = (int16_t)(wof_ground_height(at) + wof_wheel_height());
} else {
P.speed_y = (int16_t)-P.speed_y;
wof_g.pitch_target = (int16_t)-wof_g.pitch_target;
P.y = (int16_t)(P.y + 6);
wof_sound_screech(); /* 0x012380 */
}
return;
Anywhere else, touching is a crash, state 4.
On the deck the tailhook does the rest. An arresting cable is one of four wires across the deck that stop the aircraft when its tailhook catches one:
The figures
| The cables | |
|---|---|
| The tailhook | 24 pixels behind the aircraft |
| The cables, numbered west to east | the first 70 pixels east of where the aircraft stands on the lift, the others 56 apart |
| Caught | within 8 pixels of a cable |
| At an airspeed of | 600 or more, with the deck's flag clear |
| The pull | 110 off the airspeed a tick, to a stop |
| The deck, in map a | from world x 6,608 to 7,344 |
The deck's flag is the catch. While the aircraft rolls along the deck faster than 600, its routine sets the flag whenever the stick is not held forward; the aircraft is then drawn in its frame of straight flight, and the tailhook does not catch. What the flag stands for in play the notes do not say. So the stick must stay forward after the touch-down, as the autopilot of chapter 8 found. An aircraft the tailhook misses rolls on, slowing by 8 a tick with the stick left alone, and past the deck's west end it flies or, too slow, falls into the sea. In the listing, look at cmpi.w #$258, the airspeed of 600, then tst.w g_025a9c and the loop of four: the cable's x minus and plus 8 against the tailhook's, then addi.w #$38 to the next cable. A catch writes 7 into the record's state and keeps the cable's x for the drawing.
; re/Wings.lst 0x01B92E-0x01B9BA: cable_hook [C]
; cable_hook [C] frame=2
; C. the hook catches one of four cables: state 7
; callers: player_update
cable_hook:
01b92e 4e55fffe link.w a5, #$fffe
01b932 48e70c00 movem.l d4-d5, -(a7)
01b936 0c6c0258a416 cmpi.w #$258, -$5bea(a4) ; airspeed
01b93c 6d76 blt.b $1b9b4
01b93e 4a6caa9e tst.w -$5562(a4) ; g_025a9c
01b942 6670 bne.b $1b9b4
01b944 206ccdee movea.l -$3212(a4), a0 ; player_record
01b948 3a280002 move.w $2(a0), d5
01b94c 206ccdee movea.l -$3212(a4), a0 ; player_record
01b950 0c68ffff0014 cmpi.w #$ffff, $14(a0)
01b956 6606 bne.b $1b95e
01b958 da7c0018 add.w #$18, d5
01b95c 6004 bra.b $1b962
loc_01b95e:
01b95e 9a7c0018 sub.w #$18, d5
loc_01b962:
01b962 7800 moveq #$0, d4
01b964 206ccdf6 movea.l -$320a(a4), a0 ; g_027df4
01b968 3010 move.w (a0), d0
01b96a d07c0046 add.w #$46, d0
01b96e 3940a40e move.w d0, -$5bf2(a4) ; g_02540c
01b972 603a bra.b $1b9ae
loc_01b974:
01b974 302ca40e move.w -$5bf2(a4), d0 ; g_02540c
01b978 5140 subq.w #$8, d0
01b97a ba40 cmp.w d0, d5
01b97c 6d28 blt.b $1b9a6
01b97e 302ca40e move.w -$5bf2(a4), d0 ; g_02540c
01b982 5040 addq.w #$8, d0
01b984 ba40 cmp.w d0, d5
01b986 6e1e bgt.b $1b9a6
01b988 206ccdee movea.l -$3212(a4), a0 ; player_record
01b98c 317c0007000c move.w #$7, $c(a0)
01b992 397cffffaaa0 move.w #$ffff, -$5560(a4) ; g_025a9e
01b998 197c0004a361 move.b #$4, -$5c9f(a4) ; g_02535f
01b99e 396ca40ebd3c move.w -$5bf2(a4), -$42c4(a4) ; g_02540c | g_026d3a
01b9a4 600e bra.b $1b9b4
loc_01b9a6:
01b9a6 5244 addq.w #$1, d4
01b9a8 066c0038a40e addi.w #$38, -$5bf2(a4) ; g_02540c
loc_01b9ae:
01b9ae b87c0004 cmp.w #$4, d4
01b9b2 6dc0 blt.b $1b974
loc_01b9b4:
01b9b4 4cdf0030 movem.l (a7)+, d4-d5
01b9b8 4e5d unlk a5
01b9ba 4e75 rts
/* src/player.c, lines 508-533 */
/* orig 0x01B92E - the hook: at 600 or more of airspeed and with 0x025A9C clear, the hook
* 0x18 behind the aircraft within 8 of one of the four cables, 0x38 apart from
* player_start_x + 0x46, catches it: state 7. */
static void hook(void)
{
int16_t hook_x;
if (wof_g.airspeed < 0x258 || wof_g.g_025a9c != 0)
return;
hook_x = P.x;
if (P.facing == -1)
hook_x = (int16_t)(hook_x + 0x18);
else
hook_x = (int16_t)(hook_x - 0x18);
wof_g.g_02540c = (int16_t)(wof_g.player_start_x + 0x46);
for (int16_t i = 0; i < 4; i++) {
if (hook_x >= (int16_t)(wof_g.g_02540c - 8) && hook_x <= (int16_t)(wof_g.g_02540c + 8)) {
P.on_deck = 7;
wof_g.g_025a9e = -1;
wof_g.g_02535f = 4;
wof_g.g_026d3a = wof_g.g_02540c;
return;
}
wof_g.g_02540c = (int16_t)(wof_g.g_02540c + 0x38);
}
}
Held by the cable, the aircraft loses 110 of its airspeed a tick until it stands, and the state is 1 again. Meanwhile the pass draws the cable with the line routine chapter 8 named, the only line the game draws. In the landing run the autopilot touched down at an airspeed of 1,400, the most there is, where the cable needs 600; four ticks later the tailhook caught the fourth cable, the first an aircraft flying west meets.

The landing run about 29 seconds into the mission: the cable at world x 7,270 holds the aircraft, its airspeed down to 1,148.

The landing run tick by tick, from the deck to the hold, the height over the world x coloured by the record's state: the take-off at an airspeed of 708, the dip to 18, the climb to 145, past the 131 above which the horizon moves (chapter 13); the caught cable in gold; the height drawn four times as tall as the x.
The lift and the hold¶
The lift carries the aircraft between the carrier's deck and the hold below it, where the aircraft is refuelled, repaired and rearmed. The fire button on the lift, with the aircraft standing and the carrier afloat, takes it down, state 11. The lift sinks one step a pass, 32 steps, by a count of passes the tick reads, one of chapter 7's couplings; the aircraft's height follows, since the ground under it is the deck less the lift (chapter 13). At the bottom the aircraft is reset: the tank filled, the oil restored, the weapons loaded and the weapon menu raised, which chapter 15 tells. While the menu is up the aircraft cannot move; the stick forward and back steps through the weapons, and the button closes the menu and sends the lift up, a step a pass.
Fuel and oil¶
The fuel starts at 0xC0 and falls by one every 28 ticks, only in the air; it never rises but in the hold. The oil starts at 0x80, the engine's oil pressure of the manual (page 8), and stays there while nothing hits the aircraft. The guns of islands and ships take oil, and fuel, when they hit (chapters 15 and 16), and once the oil is below full it leaks one more every 80 ticks in the air; the enemy's fighters take it too (chapter 16).
In the air with the fuel below 0, or the oil below 0x60, the update sets state 4 and the aircraft comes down. The dashboard's two gauges show both (chapter 11), each with the manual's red warning light (pages 8 and 9): the oil's blinks below 0x74, the fuel's at 0x40 or below, in the air, on the deck and on the cable, and both stay dark while the aircraft comes down, lies wrecked or rides the lift. The script fuel flies until the tank is empty and the aircraft falls into the sea.
The figures
| The times, on PAL | Ticks | Seconds |
|---|---|---|
| A full tank, in the air | 193 × 28 | about 430 |
| From the fuel's light to the end | 65 × 28 | about 145 |
| The oil's leak, from the first hit to the end | 32 × 80 | about 205 at most |
| A turn | 26 stages × 2 | about 4 |
| The wait after a loss | 150, or 31 with the button | 12, or about 2.5 |
| The enemy's countdown, and after a press | 1,350; 750 | 108; 60 |
| Full speed, level | 14 pixels a tick | 175 pixels a second |
Losing an aircraft¶
The crash's routine looks at what lies under the aircraft, and the attitude levels out two stages a tick while it comes down.
| Where, or why | What follows |
|---|---|
| the sea, after a crash or a take-off too slow | at rest in the water, state 6, sinking a pixel every third tick |
| out of fuel, or the oil too low | state 4, then the sea or the land below |
| land | the wreck burns at rest, state 8; the map record under it is hit as by a rocket, and the soldiers under it die (chapter 15) |
| a ship | on its deck the wreck rests; into its hull below the deck, it slides back with a red sky flash and ends in the sea |
| shot down | chapter 16 |
At rest, a wait counts the ticks: after 150, or after 30 with the fire button, the next aircraft comes. It costs a life; it stands on the lift in the hold, facing west, with the weapon menu up. With no life left, or the carrier sunk, the game is over, chapter 17's subject. Before the next aircraft appears, the tick itself clears the playfield, shows it and waits for the VBlank twenty-one times, twenty counting a number down from 20 and one more finding it at zero: twenty-one VBlanks inside one tick (chapter 7 told that the tick draws too). On the left the clearing, flip_buffers and the two loops on gfx_WaitTOF; on the right each wait is a CO_WAIT of a coroutine, a routine that can stop at a wait and go on at the next VBlank (chapter 22).
; re/Wings.lst 0x013630-0x01367A: player_lost_restart [asm], a part of 0x0135D8-0x013683
013630 4a6cc454 tst.w -$3bac(a4) ; g_027452
013634 67000044 beq.w $1367a
013638 4eac8128 jsr -$7ed8(a4) ; -> clip_playfield
01363c 206cbe1e movea.l -$41e2(a4), a0 ; back_rastport
013640 4eac835c jsr -$7ca4(a4) ; -> draw_set_target
013644 4eac836e jsr -$7c92(a4) ; -> blit_begin
013648 2c6cb93a movea.l -$46c6(a4), a6 ; custom_base
01364c 7000 moveq #$0, d0
01364e 7200 moveq #$0, d1
013650 343c013f move.w #$13f, d2
013654 363c00a1 move.w #$a1, d3
013658 7800 moveq #$0, d4
01365a 4eac8344 jsr -$7cbc(a4) ; -> rect_fill
01365e 4eac8374 jsr -$7c8c(a4) ; -> blit_end
013662 4ebacca8 jsr $1030c(pc) ; flip_buffers
loc_013666:
013666 4eac8452 jsr -$7bae(a4) ; -> gfx_WaitTOF
01366a 536cc454 subq.w #$1, -$3bac(a4) ; g_027452
01366e 66f6 bne.b $13666
loc_013670:
013670 4eac8452 jsr -$7bae(a4) ; -> gfx_WaitTOF
013674 4a6cc454 tst.w -$3bac(a4) ; g_027452
013678 66f6 bne.b $13670
loc_01367a:
01367a 426cc454 clr.w -$3bac(a4) ; g_027452
/* src/mission.c, lines 335-345, a part of wof_player_lost_restart (lines 310-350) */
if (wof_g.g_027452 != 0) {
wof_clip_playfield();
wof_draw_set_target(wof_back_vport());
wof_rect_fill(0, 0, 0x13F, 0xA1, 0);
wof_flip_buffers();
do {
CO_WAIT(c); /* WaitTOF */
} while (--wof_g.g_027452 != 0);
do {
CO_WAIT(c); /* WaitTOF */
} while (wof_g.g_027452 != 0);
What the button does besides firing¶
Tapped in the air, the fire button drops the chosen weapon; held, it fires the guns while the aircraft flies straight (chapter 15). Besides these and its work on the lift, in the menu and after a loss, it has one use more. The record's last field counts down to the enemy: set to 1,350 for each new aircraft, it loses one in each tick without a fire bit while the carrier is afloat with hits left, and at 0 an enemy aircraft comes, on conditions chapter 16 tells. A fire bit puts it back to 750 if it has fallen below, but not once it is 0. So the scripts of the first milestones held the button inside their turns, where a hold neither fires nor drops: the enemy aircraft were a later milestone's.
What the port made of it¶
src/player.c holds the original's C routines from 0x01AA6E to 0x01CBB2 in their order, but for two helpers placed first and the update last, each with its orig comment, every width of the listing kept, the 16-bit int included. The code indexes small constant tables by attitude, frame and pitch, and an index can run past a table's end into the variables behind it: the wheel table, the wheels' height below the aircraft's reference point by attitude, reads at attitude 9 a variable the deck's routine writes. Nothing of it shows, but a port that read a constant there would part from the original; the port reads such a table by its original address, from the registered variable where one covers the byte and from the executable's bytes elsewhere, and the oracle test of the deck found the case.
The oracle holds fifteen of the update's routines, the stick's in the air and on the deck, the touch-down, the tailhook, the crash, the deck's and the countdown's among them, each over 1,500 random settings of the registered state, more than 1,000 of them compared after every call, and a turn's step through every attitude. The mission scripts of the first mission milestone fly them in both loops of chapter 8, every pass and tick compared, the VBlanks a tick waited included: the aircraft left on the deck, a flight, a climb to the ceiling, an aircraft rolled off the deck into the sea, the game over, the weapon menu, the turns, the landing with the lift and the hold and, in the suite's long run, the fuel flight. A wreck on land or on a ship and the loss of oil come in the weapons' and the enemy's scripts (chapters 15 and 16).
For the developer
One line of player_motion takes the vertical part, cut to a whole number by SPFix, out of the airspeed's step. SPFix truncates towards zero, every sine in the table short of 90 degrees is below 1, the largest 0.99985, and the clamps keep the pitch far from 90 degrees, so the line takes 0 at every angle the game reaches.
In the port: src/player.c, src/tick.c, src/mission.c, src/ffp.h; the fifteen routines are PLAYER_ROUTINES in tests/test_oracle_m4.py, the loops tests/test_world.py.
What comes next¶
The chapter in one sentence: the player is one record and a few variables, moved once a tick by the stick through a flight model partly on the ROM's floating point, landed by a rule and a cable, refuelled in the hold and brought back after every loss. Chapter 15 takes up what the button drops and fires, and the targets it hits.
Further reading¶
re/notes/objects.md, "The player's record".re/notes/ffp.md: "player_motion0x01BDFA, once per tick from0x01C70E" and "The two tables of constants".re/notes/porting-m4.md: "The tick", "The player's states", "Landing, refuelling, rearming", "Every way an aircraft is lost" and "The scripts of part 2".SPEC.md, sections 3.4, "Operating system and hardware use", the row of mathffp; 6.3, "Blocking code becomes coroutines".src/player.c;tests/ffp_model.py,tests/test_oracle_m4.pyandtools/m4_scripts.py.original/manual.txt, the game's manual: pages 5 and 6 for the stick, the take-off and the landing, 8 and 9 for the gauges.
Outside the repository: Wikipedia's "Arresting gear", for the real cables and tailhooks of a carrier.