Orders¶
Improvement: global mod scripts can register custom orders (#615). The runtime resolves their
qualified names and allocates internal IDs after the original catalogue. aigeneric.infoOf
combines original and registered metadata for stack priorities, player eligibility, retaliation,
avoidance and disruption. The original catalogue remains generated and immutable. Custom
callbacks use the scripting bridge in hooks.Scripts; the engine and tools do not link Luau.
What each object is doing: flying in formation, escorting, docking, exploding, or following the player's controls. An object keeps a stack of orders, the current one on top, which the AI, the mission scripts and the player's controls push and pop, and object_orders runs the current one.
aigeneric.zig holds the stack and runs the orders, ai.zig the steering they turn by, aifuncs.zig the orders that fly a ship, a capital ship's lurch and orders 44 and 45, aieject.zig and tractor.zig those of the ejection, launch.zig the launches and jump.zig the jumps, and ai/orders.zig lists every order with its flags, priorities and routines; make order-tables transcribes that table from the executable. The names below are those make ghidra-annotate gives the Ghidra project, which names each order's routines order_ and the order's name, with _init and _exit for those two.
Ported so far: the stack (order_push, order_pop, orders_clear, orders_pop_all), what runs it (object_orders, orders_update, order_retaliate), the steering (ai_steer, ai_roll_upright) with its avoidance, and the orders Do Nothing, Fly, Run Away, Slow Rotate, the Random Spins, Match Speed, 44 and 45, Explode, the ejection's (Eject, 106, Scoop Up, Eject Spin, Eject Fighter Attack and Eject Player), Launch, the jumps (Jump In and Jump Out, each under both its numbers), Escort, Find New Target, Torpedo, Object Attach, Toggle Cloak, Mill, Make capship list left and right, and Fight with its combat maneuvers, with Player Control being the player's controls. An order OpenReliant does not run yet still holds its place on the stack, and pushing it still pops and starts what it should (#30). Not ported: the orders other players' machines queue (#55).
OpenReliant keeps each object's stack and order state in its slot rather than allocating them with its first order, and hands a fatal "Cannot set ai" back to its caller as an error. Fix: where the game stops with it, OpenReliant logs it in the game's words and the order is not taken (aigeneric.give).
The order table¶
order_groups (0x4E06E0) points at the records of each hundred order numbers: order n is
record n % 100 of group n / 100. Group 0 holds orders 0 to 45, group 1 orders 100 to 122, and
group 2 one empty record, order 200. Each record is an OrderRecord:
| Offset | Size | Field |
|---|---|---|
0x00 |
4 | init: runs before the order's first update; null for none |
0x04 |
4 | update: runs each time object_orders runs the order |
0x08 |
4 | exit: runs when the order is popped or replaced after it has started; null for none |
0x0C |
4 | Flags |
0x10 |
4 | Name: the developers' name, which fatal errors show |
0x14 |
4 | Priority |
| Flag | Name | Meaning |
|---|---|---|
0x1 |
players |
The order may be given to a player's ship. A player's ship refuses the other orders numbered below 100. |
0x2 to 0x10 |
Unknown. Set on some orders; nothing in the payload tests them. | |
0x20 |
one_shot |
The order runs its update once and pops itself, and the order below carries on without starting again. Its init never runs. |
0x40 |
retaliate |
While it runs, the ship can turn on its attacker (see Retaliation). |
0x80 |
avoidance |
While it runs, avoidance_scan (0x00492190) lists the objects the ship could hit, unless the object has no_avoidance, which SetShipAvoidance sets to disable "Avoidance code": up to ten objects with listed components whose collision spheres, widened by a constant, overlap its own, at GameObject offsets 0x6B4 (the count) and 0x6B8, and up to ten others for which 0x00401980, which projects the two objects' motion, answers yes for a time of 50 updates and a margin of 2000 units, at 0x6E0 and 0x6E4. |
0x400 |
send_flight |
While it runs, a multiplayer game sends the ship's steering inputs, throttle, rates and velocity. |
Most orders have priority 0. Warp In, Warp Out, Land, Jump In, Jump Out, the fixed gate jumps, Launch, Dock and Friendly Fire have 1; Eject Player 97, Eject and Eject Spin 98, and Explode 99.
The stack¶
An object's stack, orders (0x684), holds up to 20 OrderEntry records, the current order
first, with order_count (0x680) saying how many. It is allocated with the object's first order,
together with 0x90 bytes at order_state (0x68C) where the current order keeps whatever it
needs between updates.
| Offset | Size | Field |
|---|---|---|
0x00 |
2 | The order's number |
0x02 |
2 | Target kind: 0 a ship, 1 a flight group, 2 a squad, as in the mission's object table |
0x04 |
2 | Target: the ship's slot, or the flight group's or squad's index; -1 for none |
0x06 |
2 | Target component, or -1 for the whole ship |
0x08 |
2 | A running count from 0x5185A8 while the byte at 0x5185B1 is set, as SetAI and SetupLaunch number the orders they give, otherwise zero |
0x0A |
16 | The order's own data, zero when the order is pushed |
player_controls keeps the mouse's stick position in the first two words of its data.
order_push (0x0040CC10) takes a slot, an order and its target, and:
- fails if the ship refuses the order (
order_refused,0x0040CA00): the ship is a player's, its slot being belowplayer_slots(0x58832C), which is 1 in a single-player game and the player count or 8 in multiplayer, and the order is numbered below 100 withoutplayers; - succeeds at once if the current order is the same order with the same target;
- fails unless the current order gives way (
order_give_way,0x0040CA50); - removes any equal order, with the same target, from deeper in the stack;
- fails if the stack holds 20 orders;
- pushes the order with its data zeroed. Unless the order is one-shot, it marks the order as
starting (
order_starting,0x688), sets the word at0x620to -1 and zeroes the state.
An object that is exploding, whose pilot has ejected, or with object flag 0x10000000 takes no
order. Otherwise the current order gives way at once when there is none, when it has yet to
start, or when the new order is one-shot. A started order gives way to Explode, and to any order
when its own priority is zero or the new order's is higher, running its exit as it does. Pushing
any other order on it is a fatal error, "Cannot set ai %s on ship %s: Still %s".
order_pop (0x0040CE70) runs the current order's exit if it has started and removes it. Unless
the popped order was one-shot, the order below starts again: it is marked as starting and the state
is zeroed. orders_pop_all (0x0040CF80) pops every order, and orders_clear (0x0040CF50) drops
them all at once when the current order gives way to clearing, so only that order's exit runs.
The script command SetAI pushes an order aimed at the ship, flight group or squad it names, on
each ship it applies to, and ClearAI clears the orders of each ship that is not a player's.
Targets that name several ships¶
order_target_walk (0x00401CB0) hands each ship an order's target names to a routine, until the
routine says to stop: the ship itself, as the target names it; each ship of a flight group, whole;
and each ship of a squad (squad_walk, 0x00401D80): its members in turn from its first, while
they are its own, a ship as the member names its component, a flight group's ships whole, and a
squad's own walk. Dock, Escort, the search for a new target, the search for a pod to scoop up, the
Dark Reign's guns and Launch walk their targets so. Fix: the game walks a
squad that holds itself round for ever, reads a member no record stands for from address zero, and
stops with a fatal error at a member of a kind it does not know; OpenReliant gives a squad no
members once the walk has gone down more squads than the mission has, and passes over such a member.
Running orders¶
object_orders (0x0040C5F0) runs an object's current order:
- It starts the queued orders from other players that are due (see below).
- With a
retaliateorder, it runsorder_retaliate. - It clears the object's
afterburnerandreverse_thrust, so an order that burns sets them again each time it runs. - A one-shot order runs its update and pops itself, and
object_ordersthen runs the order below. Any other order runs itsinitfirst if it is starting, then its update. - Afterwards it clears the throttle and both burns while the object's engines are disabled
(
DisableEngines), both burns when it has no afterburner fuel, and reverse thrust unless the object hascan_reverse.
It runs from two places:
orders_update(0x0040C8F0) runsobject_ordersonce a frame for every object that is not disabled (DisableObject), the player's ship included, and after it, where the object's guns are not disabled, its turrets (object_step_turrets).mission_frame(0x004924B0),mission_run's work for each frame, calls it (see the game loop).simulation_stepruns it for the player's ship, before the objects move, while the ship's current order isPlayer Control.
So the orders of AI ships run once a frame, and the player's controls once a frame and once each simulation step.
Retaliation¶
Damage of kinds 0, 1 and 5 adds to an object's recent_damage (0x690), which orders_update
zeroes every 500 ticks, and each hit records the attacker's slot in last_attacker (0x694).
While the current order has retaliate, order_retaliate (0x0040C520) pushes Fight (105),
aimed at the attacker, once recent_damage reaches 0.7 (0x004DC484) of the ship's full armor,
six times its armor class. It does so
only when the attacker is on the other side, is not already the current order's target, and both
ships' combat stats hold 1 at +0x28, and not while the ship has do_not_disturb
(DoNotDisturb).
Unknown: what the word at +0x28 of the combat stats means.
Orders from other players¶
In a multiplayer game, orders from the other machines wait in a queue of up to 20, queued_orders
(0xB90) with queued_order_count (0xB8C). A QueuedOrder is the order's entry, a value the
sender passes, and the tick it is due. order_queue (0x00402660) adds one due a given number of
ticks after frame_start (see the game loop). An equal order already queued stays
if it is due no sooner, and is replaced otherwise; a full queue is a fatal error.
object_orders takes each queued order that is due by mission_ticks and has a priority no lower
than the current order's, pushes it with its data, and removes it from the queue. It removes a due
order without pushing it while the object has not been created.
Steering¶
Most orders that fly a ship steer with ai_steer (0x00401380), which takes a point to aim at,
a limit, an ease and flags. It sets the pitch, yaw and roll inputs from the point's direction in
the ship's frame, through ai_steer_angles (0x00401710), or ai_steer_axes (0x00401690) when
the word at +0x24 of the ship's flight stats is nonzero. It takes (1 - ease) * 6 times each turn
rate off its input and multiplies the result by 11.46, the degrees in a radian over five, so an
input fills at five degrees off; then it holds each input within the limit, at most 1. While frames
take more than 10 ticks, turns of less than a sixteenth of a turn (22.5 degrees) are halved first,
along with the limit.
ai_steer_angles banks the ship round: within 18 degrees of the nose it simply yaws at the point,
further off it rolls to bring the point overhead, and it pitches only once the roll is within 0.8
radians of where it wants it. A ship flying backwards turns toward the other way about.
ai_steer_axes turns the ship flat: it pitches and yaws at the point together and never rolls, and
with the point behind it, it yaws hard to the side the point lies on. No file sets the word: the
executable's ship_flight_stats (0x004F9E70) holds it for each ship type, and stats_load_ships
leaves it. The capital ships and most other types turn flat; the fighters bank, as do some
support ships, the Nanny and the limpet car among them. The missiles' own flight stats
(missile_flight_stats) turn every missile flat but the fuel pod.
create/flight.zig lists the types.
| Flag | Meaning |
|---|---|
0x1 |
First avoid_near (0x004028F0) moves the point around the objects with components in the ship's first avoidance list. |
0x2 |
First avoid_ahead (0x00402DC0) moves the point around the objects in the second list, projected along their motion. |
0x4 |
Unless avoidance took over, the ship also rolls toward the world's Y axis (ai_roll_upright). |
0x8 |
Pitch stays at 0.2 or more. |
When avoidance moves the point, ai_steer steers with a limit of 1, no ease and without flag
0x8, and returns true. The lists are what avoidance_scan builds, and a ship with
no_avoidance avoids nothing.
Fix: the game follows a null pointer for a ship with no flight stats, a stand-in, that steers, arrives or avoids what lies ahead, and for a collision course with such a ship on either side; OpenReliant leaves the ship's inputs as they are, counts it as not arrived, avoids nothing for it, and takes it for no collision course.
Arriving¶
ai_arrive (0x00402140), through ai_arrive_steer (0x00402160), brings a ship to a point,
turned as an orientation, at a least throttle: Follow Curve arrives so at a path's start, and Dock
and Formation use it too. It goes by where the ship stands next. Within 2000 of the point it has
arrived: its throttle is the least it was given and its turning inputs nothing. Otherwise:
- Behind the point along the way the orientation faces, within 18 degrees of that line, and itself
facing that way within 11, it steers at the point with
ai_steer, flags0x3, and rolls to stand as the orientation stands: its roll input is the roll between their up axes less 12 times its roll rate, in degrees over 40. - Otherwise it steers with
ai_steer, flags0x3, round the circle through it that meets the orientation's line at the point, in the plane of that line and the ship: aiming half a radian round the circle ahead of itself, or at the point once within the circle's last half radian. The circle's radius is at least twicespeed_per_pitch_rate(flight stats+0x20); standing ahead of the point, the ship aims across the far side of the smallest.
Either way its throttle is the way left, straight or round the circle, over 4 times its cruise
speed through its inertia (4 * cruise / (1 - inertia)), less 0.1, and never less than the least
it was given.
Avoidance¶
avoidance_scan (0x00492190) runs for each object in mission_frame's pass that draws them, the
ones it draws, while the object's current order has the avoidance flag and it has no
no_avoidance. It empties the ship's two lists (GameObject + 0x6B4 and +0x6E0, a count and ten
slots each) and fills them from the objects that are not standing in, disabled or jumping, not
planets, not the ship itself or what it fights, and where neither names the other in its first
pass-through slot:
- an object that lists components goes on the first list while its sphere, 10000 wider than the two radii, overlaps the ship's where the step takes them both;
- any other goes on the second, where the ship lists no components, while the ship is on course to
hit it within 50 steps by 2000 (
ai_collision_course,0x00401980).
ai_collision_course first asks that the two be within reach of each other over the steps, at
their cruise speeds, with both radii and the margin. Against a target without components, the
target must then lie ahead of the ship, and the ship close on it by its velocity less twice the
target's, to within both radii and the margin. Against a target with components, the ship's next
position must instead lie within the ship's cruise speed times the steps, and the margin, of a box
of one of the target's parts: of the parts in its root's child list, every part whatever it is
linked to, shown and with a collision tree, each whose sphere, that reach wider, holds the position
has each box of its tree tested, and the position is within reach of a box where it stands nearer
to the box's centre, squared, than the box's half size and the reach, each squared, together.
Fix: the game also hands back the part and the box through two pointers it does not test, which
every caller passes null. Avoid Target (order_avoid_target, 0x0040B330) asks only that its
target's type is below 0x100, not that it lacks components, so the game writes to address zero once
the ship comes within reach of a box of a ship that lists components. OpenReliant hands back
neither.
avoid_near (0x004028F0) works the first list, from the line between where the ship goes next
and the point it steers at. For each object not standing in, exploding or disabled, not farther
behind along that line than both radii, closing along it, and to be met within 250 steps: it
takes the object's box where it will then be, widened by the ship's radius, in the object's frame
and scaled by its visibility. Where the line crosses it, the point moves onto the box widened again
by the ship's radius: onto the face nearest where the line enters, at whichever is nearest the point
of four spots of it, each at the entry along one of the face's two axes and at an edge of the box
along the other. The point is scaled by the visibility again on its way back to the world, rather
than unscaled. The heading stays the one to the first point, but each object after the first tests
the line to the point the one before moved.
avoid_ahead (0x00402DC0), for a ship that lists no components, works the second list: each
object is taken where it will be once the ship has flown to where it is now at the ship's cruise
speed. Where the line to the point passes within 1000 of it, or 500 for an object of another side,
the point moves as far ahead of the ship as the object will be, and above or below the ship, away
from the object along the ship's own up and down axis, by both radii and 2000, or 1000 for another
side's.
The orders¶
Each order's routines are named after it: order_fly_init and order_fly for Fly, for example.
Many take their target's validity from order_target_valid (0x00401870): a targetable object
that is not cloaked, exploding, disabled or ejected, nor has object flag 0x10000000, and, when the
target is a component, one that is there and neither hidden nor has node flag 0x10. Random
choices come from object_random (0x004ADD10), each object's own generator: a seed at +0x638,
set from C's rand() when the object is created, that steps as seed * 0x343FD + 0x269EC3, bits
16 to 30 of it over 32767 giving a number from 0 to 1.
Every order, by its number, with what it does and whether OpenReliant runs it. An order OpenReliant does not run yet holds its place on the stack and does nothing (#30).
| Number | Order | What it does | Ported |
|---|---|---|---|
| 0 | Do Nothing | Zeroes the throttle and the turning inputs. | Yes |
| 1 | Fly Aimlessly | On starting, takes a figure from 1 to 3 from the ship's own random numbers, keeps where the ship will be next and how it will be turned, its X axis reversed where its next number is odd, and sets the throttle to 0.4 and up to 0.3 more by rand(). Each update it steers with flags 0x3 for point n of its figure, from 1, and for the next once within 1000 of it. Point n lies t = n twentieths of a turn round, (cos t - 1)(figure + 1) times 25000 along the kept X axis and sin(figure t) times 50000 along the kept Z axis from where the order began: figure 1 is a circle, and figures 2 and 3 are wider loops that swing ahead and back two and three times on the way round. It never ends. Improvement: OpenReliant computes the sine and cosine rather than reading the engine's tables (sr_sin, sr_cos). |
Yes |
| 2 | Launch Missile | One-shot: launches a missile at the target from the first of the ship's racks with missiles left that is not a Jack Hammer's (Missiles). | Yes |
| 3 | (nameless) | One-shot: as Launch Missile, from the first rack of Jack Hammers. | Yes |
| 4 | Warp In | A ship arrives through its own tunnel, emerges, then posts JumpedIn (Gates). | Yes |
| 5 | Warp Out | A ship aligns with its target, opens its tunnel and enters it, then queues Warp In with the same sequence number. | Yes |
| 6 | Fly | Flies at the speed in its data, or at full throttle for zero. With a target it flies to it and pops within 2000 units; otherwise it keeps the heading it had when it started, steering at a point 20000 units along it. It steers with flags 0x7 and halves the throttle while avoiding. An object without flight stats is moved along that heading instead; Improvement: OpenReliant draws it gliding on between the ticks (The game loop). |
Yes |
| 7 | Run Away | Flies away from the target at half throttle, for a point on the far side of the ship from the target, 100000 times as far from the ship as the target is. It moves the point round what is near (avoid_near), then steers at it with flags 0x3 and an ease of 0.1, which go round what is near and ahead again. Pops when the target's slot holds a stand-in. |
Yes |
| 8 | Land | The player's ship lands on its carrier, which ends the mission (Landing). | Partly: the Yamato's style is not (#349) |
| 9 | Escort | On starting, takes the ship its target names, or the ship at the order's number among a flight group's or a squad's ships, counting round them again past the last (escort_count_place, 0x0040AA50); OpenReliant takes none where the group has no ships, which the game walks for ever (Fix). Each update, it pops once that ship's slot holds a stand-in; otherwise it steers for a point 10000 ahead of the ship: within 5000 of it with half its turn and flags 0x4, and farther off with its full turn and flags 0x3. Its throttle is the escorted ship's speed over its own cruise speed, and 0.0001 more for each unit the escorted ship lies ahead along its own heading. |
Yes |
| 10 | Find New Target | Walks the ships its target names, weighing each it can aim at, cloaked or not, by the square of its node's distance from where the ship will be next (Picking a fight). It fights the lightest to fight, pushing Fight, or Torpedo (103) for a ship of the torpedo class; with none, it mills round the lightest to mill round, pushing Mill (120); with neither it pops. | Yes |
| 11 | Explode | A destroyed object's end, by what it is and in one of three styles (Destruction). | Yes |
| 12 | Ripper grabs target object | A Ripper carries its target off (The Ripper). | Yes |
| 13 | Object Attach | On starting, keeps where the ship will stand next in the frame its target will stand in next. Each update it puts the ship there in the target's next frame, turned as the target will be, and gives it the target's turn, velocity, speed and rates of turn, so that it rides the target. | Yes |
| 14 | Formation Regroup | Not read yet. | No |
| 15 | Patrol Route | Not read yet. | No |
| 16 | Toggle Cloak | One-shot: cloaks or uncloaks the ship if its model's header allows a cloak, and the ships being launched from it do the same. | Yes |
| 17 | Ship Follow Curve | Flies the path of the mission's curves from the curve in its data (Following a path). | Yes |
| 18 | Slow Rotate | Zero throttle, yaw input 0.1. | Yes |
| 19, 40 | Jump In | The ship arrives beside its target, flying in from far behind it; 40 first holds its place in the formation a while (Jumps). | Yes |
| 20, 41 | Jump Out | The ship turns to where it goes, charges and jumps: to its target, where Jump In of the matching number brings it in, or out of the mission where it names none; a ship jumping with the player's goes in formation behind it (Jumps). | Yes |
| 21 | Find Scoop Up | Starts at its first step, as 115 and 116 do (0x0040B1C0). The first goes on to the second, where a multiplayer game waits for every player unless the target is a ship (ai_sequence_sync, 0x00401000). The second walks the ships its target names for the nearest to where the ship will be next that it can aim at, ejected or not (0x0040B140), and pushes Scoop Up (107) at it; with none it pops. Once Scoop Up is done, the order starts again from its first step. |
Yes |
| 22 to 24 | Random Spin Slow, Medium, Fast | On starting, zero throttle and each turning input 0.1 plus a random number times 0.3, 0.5 or 0.9. Its update does nothing. | Yes |
| 25 | Fixed Gate Jump In | The ship comes in through the tunnel at the object its target names, out beyond its mouth, cut by its portal (Gates). | Partly: the Krasny's split in missions 16 and 66 is not (#407) |
| 26 | Fixed Gate Jump Out | The ship goes out through the nearest gate's tunnel, the player's riding the worm, then comes in through its target's (25) (Gates). | Yes |
| 27 | Formation | On starting, keeps its place abreast of the target, 3000 apart: the ship SetAI numbers n flies n / 2 + 1 places out, to the target's left where n is even and to its right where it is odd. Each update it pops once it can aim at the target no more; otherwise it arrives at its place in the frame the target will stand in next, turned as the target will be, at a least throttle of 0 (Arriving). |
Yes |
| 28 | Fixed Gate Open | A tunnel grows open at the object (Gates). | Yes |
| 29 | Fixed Gate Close | The object's tunnel shrinks away and goes. | Yes |
| 30 | Eject | The pilot leaves the ship in its cockpit, which becomes the pod, and the rest of the ship a new object; the pod clears the ship, and the player's waits to be picked up (Ejection). | Yes |
| 31 | Fixed Gate Collapse | The gate comes down in fireballs, its tunnel burning out (Gates). | Partly: the Krasny's split is not (#407) |
| 32 | Match Speed | Sets the throttle to the target's speed over the ship's cruise speed. Pops when the target is no longer valid. | Yes |
| 33 | Dark Reign shoot | Not read yet. | No |
| 34 | Move to spawn pos | A deathmatch's (deathmatch.cpp). Not read yet. |
No (#55) |
| 35 | Turns object lights on | Switches on the lights of the parts with the lightmap flag, with a sound, and pops. Ship type 165 instead switches on the first part's four lights one by one, then those of every lightmap part, a step each 100 ticks with a sound at each, and pops after 500 ticks. While the setting at 0x5D5618 is not 1 it pops at once. |
No |
| 36 | Make Boridin section break away | Not read yet. | No |
| 37 | Rotate Boridin breakaway warp projector | Not read yet. | No |
| 38 | Start warp projection from Boridin | The Boridin's warp projection, through a tunnel of its own (Gates). Not read in full yet. | No (#30) |
| 39 | Make ripper drop what it's carrying | A Ripper lets go of what it carries (The Ripper). | Yes |
| 42 | Turns object lights off | Switches off the lights order 35 switches on. | No |
| 43 | Huuuuuuuge explosion | The Uber Explode at the object, of size 50000 over 1500 ticks (Effects), then it pops. | Yes |
| 44 | Immediately set ship to zero velocity and rotation | object_stop (0x00403000), then it pops. |
Yes |
| 45 | Fly ship backwards | Throttle -0.5, no turning. | Yes |
| 100 | Player Control | The player's controls fly the ship (Controls). | Yes |
| 101 | Multiplayer Control | Disables the object once it has object flag 0x10000000. |
No (#55) |
| 102 | Avoid Target | Not read yet. | No |
| 103 | Torpedo | Find New Target's for a ship of the torpedo class. On starting, full throttle. Each update it pops once it can aim at its target no more; otherwise it steers with a limit of 2 and no ease at the target's node, led along the target's nose by the target's speed times the ticks the torpedo takes to get there at its top speed, less its own velocity times half those ticks, 25 at most. It goes off against what it meets (Collisions). | Yes |
| 104 | Launch | The ship leaves its carrier, in the style the carrier's type picks (Launches). | Yes |
| 105 | Fight | Fights its target by running combat maneuvers, one after another. | Yes |
| 106 | Eject | The ship a pilot has left: destroyed 200 ticks on. | Yes |
| 107 | Scoop Up | A nanny ship or the Antanov takes the player's pod aboard with its tractor beams (Ejection). | Yes |
| 108 | Eject Spin | An AI pilot's ship spins, unpowered, for 200 ticks; then the pilot ejects (Eject). | Yes |
| 109 | Dock | Docks at a port of its target (Docking). | Station, Nanny, limpet car and limpet pod styles; Czar-specific limpet docking remains (#320) |
| 110 | Dark reign shoot | The Dark Reign's ion cannon; ion_cannons_hold_lock keeps its target (Script VM). Not read in full yet. |
No |
| 111 | Ripper end drop object | A Ripper draws its forearms back once it has let go (The Ripper). | Yes |
| 112 | Ripper attach cargo pod to Mammoth | A Ripper fits a cargo pod onto a Mammoth (The Ripper). | Yes |
| 113 | Eject fighter attack | A Sabre flies at the player's pod and shoots it down (Ejection). | Yes |
| 114 | Disrupted | A Havoc's shockwave gives it (Effects). On starting, sets object flag 0x8 (unpowered), keeps the tick to end at, the duration in its data (a word) after frame_start, takes the push in its data after that (three floats) as a knock in the ship's own frame, though the shockwave gives it in the world's, and knocks each turn rate by up to 0.05 either way at random, which the ship tumbles by. It also plays fifteen electric rays over the ship, each from its centre out to its radius in a random direction, 90 either way, with a jitter of 0.6, flickering, dimming as they go dark, and lasting as long as the order, white (0.8, 0.8, 1) and blue (0.3, 0.5, 1) in turn. It pops past that tick, and its exit clears the flag. |
Yes |
| 115, 116 | Make capship list left, right | A capital ship struck by a torpedo lurches (Collisions): its update (capship_list, 0x0040C3A0) sets the roll and yaw inputs to 0.01 and 0.006 over the ship's roll and yaw rates, to the left for 115 and the right for 116, then 200 ticks on to 0.006 and 0.0048 the other way, and 300 ticks after that clears the roll and pops. |
Yes |
| 117 | Friendly Fire | The carrier recalls the player's ship for destroying a friend, and it lands (Friendly fire). | Yes |
| 118 | Eject Player | The player's ship drifts, unpowered, for 400 to 599 ticks, then explodes, unless the pilot ejects first (Destruction, Ejection). | Yes |
| 119 | Ship Follow Curve Backwards | Flies the path of Ship Follow Curve (17) backwards, from its end to its start. | Yes |
| 120 | Mill | On starting, where it can aim at its target, cloaked or not, keeps the tick and a circle facing from the target's node to where the ship will be next. Each update it pops once it can aim at the target no more or 500 ticks have passed; otherwise it flies at full throttle, steering with flags 0x3 for a point on the circle 50000 from the node, which comes round from the ship's side by 0.000005 of its cruise speed a tick. Improvement: OpenReliant computes the sine and cosine rather than reading the engine's tables (sr_sin, sr_cos). |
Yes |
| 121 | Deathmatch Respawn Effect | A deathmatch's (deathmatch.cpp). Not read yet. |
No (#55) |
| 122 | Deathmatch Dark Reign target | It has no routines: nothing to run. | Yes |
| 200 | (nameless) | It has no routines: nothing to run. | Yes |
Following a path¶
Ship Follow Curve (17) and Ship Follow Curve Backwards (119) fly a ship along a path of the mission's
curves (The director's camera): from the curve its data names, on through the
curve that carries the path on from each curve's end, over the seconds its data gives. The data holds
the curve (+0x0A), the seconds (+0x0E) and the ship that carries the path (+0x12), whose offset
from where the mission placed it, as the order starts, moves the whole path (curve_ride). Their
state:
| Offset | What it holds |
|---|---|
+0x00 |
The routine motion_follow gets its point from: 0x00403200, or 0x00403600 backwards |
+0x04 |
The fastest the ship moves, as a share of its top speed: 1 |
+0x08 |
The curve it flies now |
+0x0C |
The step |
+0x10 |
The mission's tick (mission_ticks) the curve began |
+0x14 |
The curve's share of the order's seconds, in ticks, as its length is to the path's |
+0x18 |
The path's length |
+0x28 |
Where the carrying ship stood as the order started |
+0x34 |
The share of the way along the curve to the next place a point marks, 0 for none |
| Step | What it does |
|---|---|
| 0 | It arrives (ai_arrive) at the path's start, turned toward the path's point 4 ticks on and at the throttle the path keeps between them over its cruise speed; the curve's clock holds at its start. The order backwards arrives at the path's end instead, turned toward its point 4 ticks back, its motion motion_forward |
| 1 | In a multiplayer game it waits for the other players (ai_sequence_sync, 0x00401000, not ported: #55); in a game of one, it goes on |
| 2 | It flies motion_follow along the path, or motion_follow_backwards where its motion was astern; backwards, motion_follow. The path moves it on to step 3 |
| 3 | The order pops, in a multiplayer game once the other players are there too (not ported: #55), and its exit gives the ship motion_forward, or motion_backward after motion_follow_backwards |
The path's routine, each update of the motion, gives the curve's point as far along as its ticks
have gone by mission_ticks, which runs on through a frame's simulation steps (curve_point),
carried with the carrying ship. Forward, past a place a point marks, the
point has ShipReached, with the ship (event_post_ship_reached, 0x0045AC10), one place an update.
At the curve's end the ship it ends at has ShipReached too, and the next curve begins; with none, the
step moves on. Backwards, past the curve's start, the curve before it begins, found by walking the
path again from the order's curve, or at that curve the step moves on.
Fix: the game divides by nothing for a path of no length and for a curve given no ticks, and
follows a path that comes round on itself for ever as it walks it; OpenReliant gives a curve of a
path of no length all the order's ticks, takes a curve given no ticks to its end going forward and
past its start going backwards, as the game's endless share does, and stops measuring such a path,
and walking it for the curve before one, after as many curves as the mission has
(Curves). Flying forward, it still follows such a path for ever
(#535). Walking the path backwards, the game
takes a curve's end for a ship unless its whole reference, kind and all, is 0x0000FFFF
(0x0040359E), and so walks on from a curve that ends at no ship to one that starts or ends at
none; OpenReliant stops at an end whose index is 0xFFFF. It holds a curve's ticks at 65535, where
the game takes them round from nothing. The game moves the step on, and forward posts the end's
ShipReached, at every move past the path's end, so that a second move before the order's update, a
collision's or that of a second step in the same pass, leaves the order running, to fly the path
again once the step comes round; OpenReliant moves it on once.
Docking¶
Dock (109) brings a ship into a berth at another's port. Its target names the ship and the port by
its component: the port is the ship's docking points (SHP attachment kind 9), counted part by part
over its root's children. Where the target names no port, or names a flight group or a squad, the
init (order_dock_init, 0x00406B80) takes the first free port of the ships it names, in the order
it walks them: the first port at which no other object's current order is Dock
(0x00406A90). It then picks a style by what the ship is and what it docks at, from a table of an
init, an update and an exit each (0x004E1618): the limpet car's (2), or at the Czar docked its
own (3); the limpet pod's (4); at a Nanny, the Nanny's (1); and otherwise the station's (0). The
data's first byte holds the style.
The station's style finds the docking points (0x00406C80): the ship's own, its first, and the
port, whose part plays its deploy track at 4 from its start. The port is found by counting the
component down at each docking point, so a component past the station's docking points, or a
negative one other than -1, which the init's search leaves alone, names none. A ship without a
docking point stops the game with "Docking information not defined on %s". The check of the
station's port reads the ship's own node again (0x00406E2A, +0x10 where the port's is
+0x20), so a station without the port goes on to the berth with the port's node null, as
order_push cleared the state, and faults there. The berth (0x00406E70) is where the ship's
origin stands docked: the port, less the ship's own docking point turned by the port's
orientation, in the frame the station's part is drawn at, and turned as the port is.
Fix: the game takes the ship's own docking point in its part's own frame alone (the node's
+0x18 and +0x3C, 0x00406E97), which berths a ship whose point is on a part hung from another
part off by that part's place; OpenReliant carries it up the parts it hangs from. Every shipped
model has its docking points on parts that hang from the root.
The station style's state:
| Offset | What it holds |
|---|---|
+0x00 |
The routine motion_follow gets its point from as the ship slides in: 0x00406F20 |
+0x04 |
The fastest the ship slides, a share of its top speed: 0.5 |
+0x08 |
The step |
+0x0C |
The mission's tick (mission_ticks) the slide ends at |
+0x10, +0x14 |
The ship's own docking point's node and place on it |
+0x20, +0x24, +0x30 |
The port's node, its place on it and its orientation |
+0x54 |
Whether the ship came from the port's right, which mirrors the way round |
+0x58 |
Where the ship stood as it began to slide in |
The init (0x00407010) picks the first step by where the ship stands in the port's frame: more
than 100000 behind the port, step 3 where it stands within a fifth of that to the side, and step 2
further out; nearer, step 1 behind the port and step 0 ahead of it. Steps 0 to 4 steer for a point
in the port's frame, mirrored across it for a ship that came from its right, at full throttle
(ai_steer, no flags), rolling the ship to stand as the port stands (its roll input the roll
between them less twice its roll rate, in degrees over 40, within 1), each on to the next within
2000 of its point. Holding the roll leaves the ship its pitch and yaw to come round with: a ship
that turns flat, as capital ships do, flies the whole way round, while a banking one turns only
while the point lies within 18 degrees of its nose or its tail.
| Step | Point, in the port's frame |
|---|---|
| 0 | 100000 to the side |
| 1 | 100000 to the side and 100000 behind |
| 2 | Twice the ship's cruise speed over its yaw rate to the side, 100000 behind |
| 3 | 50000 behind, on the port's line |
| 4 | 10000 behind, on the port's line |
| 5 | The ship latches on: attached, flying motion_follow, the station stopped dead, for 1000 ticks |
| 6 | It slides in: the path's point stands on the port's line behind the berth, as far back as the ship stood as it latched on, times the square of the share of the 1000 ticks left, with the port's up as the way up. Past them, the ship's motion is motion_backward, and the step moves on |
| 7 | It is stopped dead, set in its berth, heard docking (sound 0x37, dock), and has its Docked (event_post); the order pops |
Its exit, the Nanny's too (0x00407D10), leaves the ship's first pass-through slot empty. The
ship stays attached.
Fix: where the ship has no docking point the game stops, and where the station has no port that the component names it faults. OpenReliant logs either, and the order ends.
Fix: the game goes on reading the frames of a station that has gone; OpenReliant ends the order, and until then the slide in holds the ship where it is.
Nanny docking¶
dock_nanny_init (0x004073E0) enables carrier pass-through and plain motion. It stores the
selected port's point, raised by the docking ship's height. dock_nanny_run (0x00407510)
opens entry door 0 or 1, approaches a point 1500 above and 20000 ahead of the port, then
steers into it. Within 500 units it stops and closes the door. After strictly more than
500 ticks, create.rearm refits missiles through the shared create.arm path and restores
countermeasures, afterburner fuel, gun charge and rounds. Player ships retain their chosen
loadout, including modded missile racks. Hull and shields are not repaired.
Exit door 4 or 3 opens. After 400 ticks, Docked is posted and forward motion resumes. The ship uses its afterburner for another 150 ticks, then the exit door closes and the order ends. The player's locked Nanny view (43) returns to the cockpit. Fix: each door closes from its own animation time instead of using the first port's time. Invalid ports or missing carriers end the order without dereferencing missing nodes.
Limpet docking¶
dock_limpet_init (0x00407D30) shares station docking-point lookup and berth math.
dock_limpet_run (0x00407D70) approaches 10000 behind the berth, then uses the shared
slide callback for 1000 mission ticks at half speed. It stops the carrier during entry.
At the berth, clamp parts 2 and 3 play rotate at speed 4. A visible pod mesh (part 0)
is hidden and replaced by a separate limpet-pod object, attached to the carrier. If it was
already hidden, the mesh shows again and the first existing limpet pod is retired, as in
the original. Three 400-tick waits cover clamp rotation, departure and clamp return.
The order posts Docked if the pod mesh is hidden, Undocked otherwise. Its exit restores
forward motion, clears attachment and clears the first two pass-through entries. The
separate pod's update (0x004084B0) destroys it if its carrier explodes. Undocked is also
exposed to mod scripts through the event declarations.
Czar-specific limpet docking remains in #320.
Landing¶
Land (8) brings the player's ship down on its carrier, and ends the mission. PERMISSION TO LAND
gives it (permission_to_land, 0x00453DE0), which frame_controls calls outside a multiplayer
mission: heard at most once in 500 of the timer's ticks (0x0052987C), it aims Land at the ship
the player launched from (player_carrier). In a training mission (30 to 35), the flight instructor
clears the ship to land where the script's variable 10 (landing_cleared, 0x0052A418) is set. In
any other, unless the ship is landing already, the carrier refuses it, or clears it where variable
10 is set. Mission 1's script sets it as the Reliant jumps in. The pilot asks on the radio, and the
answer comes as a report 300 ticks later (Reports); where the radio's reports
are all taken, nothing answers and nothing lands.
The init (order_land_init, 0x0040EAC0) picks a style by the carrier's type, from a table of an
init and an update each (land_styles, 0x004E1FE8): the Reliant's (1) and the Yamato's (0). Any
other stops the game with "Cannot land on %s". The state's first word holds the style. The
Reliant's init (0x0040F5C0) sets the first step, due in 700 ticks, or at once where the ship is
being sent home for its friendly fire (ending 6 or 7). Its update (0x0040F940) keeps its state
as:
| Offset | What it holds |
|---|---|
+0x00 |
The style |
+0x04 |
The frame's tick the step waits for |
+0x0C |
The step |
+0x10 |
The middle of the tube the ship lands in |
| Step | What it does |
|---|---|
| 0 | Until the step is due, the player flies on (player_controls). Then the cutaway: the scene becomes the landing's (0x00587CD4 = 3), every object but the ship and its carrier is disabled (flag 0x400) and those two enabled, the ship flies by its nose (motion_plain) and passes through everything, and the upper door of the carrier's first launch tube, part 6, plays opendoor2 at 1.23 with the door's sound (0x35, dooropen) where it stands |
| 1 | The ship steers at a point 3000 over the tube's middle (ai_steer, no flags), its throttle 0.0001 for each unit it has to go, at most 0.5. Within 200 of it, it stops, its turns nothing, for 50 ticks |
| 2 | It sinks along its own Y axis, which points below it (motion_downward) |
| 3 | Its throttle is its distance from the tube's middle over 15000. Once it is less than 100 over it, along the carrier's Y axis, it stops, with the landing's sound (0x3E, shipland), for 270 ticks |
| 4 | The mission is over (mission_over) |
The cutaway (0x0040F600) switches to one of the landing's views
at random, and moves the carrier to (0, -1000000, 0), turned as the world is. The ship lands in the
carrier's first launch tube, the one the launch drops ships out of through its lower door
(Launches): its middle is halfway between the middles of the
tube's lower door, part 0, and its upper door, part 6, each the middle of the bounds of the level
its part drew last. The ship stands 20000 ahead of it and 5000 above in the carrier's frame,
looking at the point 3000 over it, stopped, its power shared evenly. The carrier's orders are all
popped, and it stops. The approach leaves the ship pitched about 6 degrees nose down, as it looked
at the point over the tube from where it started, and it sinks along its own Y axis, so that it
comes to rest ahead of the tube's middle, tilted as it came.
Improvement: the ship levels out as it approaches: the point it steers at rises from the
game's height to the ship's own as it nears the tube, eased in and out over the way it comes, so
that it arrives level. It stops dead over the tube, and sinks straight down it, coming to rest
level. Once its top is below the underside of the tube's upper door, the door closes over it, its
opening played back as fast as the launch opens the tube's doors, 2 a step, with the game's sound
of a door closing (0x36, doorclos).
--original lands it as the game does, and leaves the door open.
Fix: a landing on a ship that nothing lands on ends at once, where the game stops, and PERMISSION TO LAND does nothing where the player's ship launched from no carrier, where the game reads through a null pointer.
Not ported: the Yamato's style, whose landing OpenReliant lets go of at once (#349).
Friendly fire¶
The player's hits on friends (friendly_fire.zig):
object_damage and object_armor_damage hand a blow of the player's ship on a friendly object, a
shot's, a Screamer's or a collision's, to friendly_fire_warning (0x00474C80), the armour's only
while the object is not exploding, as component_damage does a shot's or a Screamer's on a friend's
component. The damage after the difficulty's scaling mounts (friendly_fire_damage, 0x00562CEC),
and once past 800 (0x004DC5EC) and 3000 game ticks after the last (friendly_fire_quiet_until,
0x00562CE8), Moose warns the player on the radio, one of ff_001 to ff_004, and the damage
counts from nothing again. The count of warnings (friendly_fire_count, 0x00562CF0) would pick
ff_005 to ff_008 for a second and ff_009 to ff_012 for a third, but the game takes a second
back to the first, so those are never said. friendly_fire_reset (0x00474B20) clears the three as
mission_run starts a mission.
Destroying a friend sends the player home: armour below zero from such a blow, but a collision with
a pilot's pod that anything could harm, or a friend's component destroyed by a shot or a Screamer,
calls player_friend_destroyed (0x00474E00), which marks the player's ship (+0x678, 1), as
the script's FriendlyFire (0x57) does. Each frame after the orders, mission_frame
(0x0049298C) runs friendly_fire_send_home (0x00474B40) for a player's ship in the action
and marked: while the mission goes on and the ship's current order has no priority, the mission's
ending becomes 6 (7 where the mark is 3), and the ship takes Friendly Fire (117), aimed as its
current order is, and is sent off (flag 0x10000000).
Friendly Fire keeps its stage (+0x00) and the frame's tick it ends at (+0x04):
| Stage | What happens |
|---|---|
| 0 | Its init (0x00474E60) has Moose say one of ff_013 to ff_023; the player flies on (player_controls) for 300 ticks |
| 1 | For 700 ticks the ship is steered toward the carrier the player launched from (ai_steer, limit 1, no ease, no flags), the player's controls keeping 0.7 of the throttle and of each turn, the steering 0.3 of the turns |
| 2 | The order ends and the ship, no longer sent off, takes Land on the carrier, which lands it at once (Landing), and Jump Out at itself before it where the carrier is farther than 1000000; it is sent off again. The game also clears the carrier's flag 0x20 |
Fix: the game reads the carrier through a null pointer where the player launched from none; OpenReliant lets the ship fly on as the player has it, and then ends the order.
Not ported: a multiplayer game's side of it
(#55). There, destroying a pilot's pod only a
player could harm marks the ship 2 and tells the others, whose carrier then aborts the mission
(abrt_001, said by pilot 27 for the Reliant and 28 for any other); and another player's ship
sent off jumps out.
The Ripper¶
The Ripper (type 0x1F) carries cargo pods in the tractor beams of its four back pincers
(airipper.cpp). Mission 1 has one lift sixteen pods onto a Mammoth at Fort Sherman: its script
orders the first grab, and two triggers that resume where they stopped (InterruptTriggerCode)
answer each RipperGrabbedObject with the next drop and each RipperDroppedObject with the next grab.
Two tables of 150 entries serve every Ripper, set up as a mission loads (0x0040FC90) and let go as
it ends (0x0040FCF0). rippercargo (0x00518648) pairs a Ripper with what it carries, filled in
turn from next_rippercargo (0x00518AFC); what a Ripper carries is the first entry naming it
(0x00412340). A set of beams (0x74 bytes each at 0x00518B00, the next at 0x00518640) is
four tractor beams (tractor_beam_mesh, over laser2), one from the first point of each pincer's
first point list, the first two reaching for the middle of the pod's first pair of points and the
last two for that of its second (SHP). An order shows them as it runs
(0x00412200), aimed and faded as a tractor's beams are: each from its pincer's point in the
pincer's frame, to the middle of its pair of the pod's points taken in the frame the pod's
Cargo pod part hangs from (the frame's parent, +0x10), which for the shipped pods is the pod's
own place, so the beams stay on a pod that is disabled and not framed.
The Ripper's tracks play on every part of it that has them (0x0049A400): ready to grab, its
forearms reaching out; grab pod, its pincers closing; and cabin turn. A step that waits for
the forearms or the pincers played backwards waits for the root's first child's track to be back
at its start; one that waits for the cabin to turn back waits for the Ripper Cabin part's. Each
wait for the other players between the steps (0x00401000) passes at once in a single-player
game. A Ripper comes to rest where its turning inputs and its throttle are within 0.025, and its
rates of turn within 0.02; Ripper end drop object's last turn needs its inputs and rates below
those values.
Ripper grabs target object (12) lifts its target aboard. Its init (0x0040FD10) makes the target
invulnerable, takes the beams, flies the Ripper by motion_plain, held (attached), and has the two
pass through each other. The Ripper stops 2500 above the target's component, in its frame, where the
target names one; in mission 26, 1000 below the target, which it lifts from below; else at the
target. Its steps (0x0040FF80), each timed from its start:
| Step | What happens |
|---|---|
| 1 | The Ripper steers at the point (limit 0.3): at full throttle while more than 2000 beyond where it stops, at 0.2 nearer, and not at all within 2000 of the point, or 100 lifting from below; near it and not facing it within 0.7, it holds still. At rest, it plays ready to grab at 15 |
| 2 | From below, it turns to face the target until at rest |
| 3 | 150 ticks: the beams come on, as the square of the time; then the target is heard (sound 0x3D) and no longer frozen |
| 4 | 300 ticks: the target is drawn halfway to 300 from the Ripper, toward it |
| 5 | 500 ticks: the target turns to match the Ripper, easing (cosine_ease) |
| 6 | 300 ticks: it is drawn the rest of the way; then heard (sound 0x3C), and the Ripper plays grab pod at 10 |
| 7 | 150 ticks; then the Ripper plays cabin turn at 4.5 |
| 8 | 500 ticks |
| 9 | The target's part Cargo pod hides and the Ripper's shows; the target is disabled and as invulnerable as before; the Ripper carries it and flies astern (motion_backward); the order ends, with the Ripper's RipperGrabbedObject |
Should the target go first, the Ripper takes back its motion and the order ends. Its exit
(0x00410B50) lets the Ripper go and frees the beams.
Make ripper drop what it's carrying (39) (0x00410B90, 0x00410C00) stops the Ripper, flies it by
motion_plain, held. Where the order names a ship, the Ripper fits what it carries to it instead
(order 112). Else, at rest (its speed and rates below 0.05, by their signs), it plays grab pod from
350 at -10, plays sound 0x3C on no object (-1), and lets go: what it carries stands where its own
Cargo pod is, and shows in its place; the order ends, and Ripper end drop object (111) takes
over. What it drops stays disabled.
Ripper end drop object (111) (0x00410E60, 0x00410E90) lets the Ripper go; it plays ready to
grab from 350 at -6, then backs away astern at 0.2 for 50 ticks, and plays cabin turn from 400 at
-4.5. Once its cabin is round, it turns, still flying astern, to put its tail to a point 10000 ahead
of it (limit 2) until at rest, and flies on (motion_forward): neither it nor what it dropped
passes through the other any more, it carries nothing, and it has its RipperDroppedObject.
Ripper attach cargo pod to Mammoth (112) (0x00411200, 0x00411420) fits what the Ripper carries
to the component its target names. The Ripper flies astern to 2500 above the component, in its
frame, or below it on a Sharov or a Boridin: at full throttle beyond 2000, then by motion_plain at
0.2 until within 300. At rest, it faces the component (limit 2) and plays grab pod from 350 at
-10. Then the ship is no longer frozen, and the pod stands where the Ripper's own was; over 150
ticks the beams come on, and it is heard (sound 0x3D), shown in place of the Ripper's and
enabled. Over 1000 ticks it eases onto the component, keeping its turn for the first 0.15 of the
time, then turning, easing, until half of it, to the component's orientation turned a quarter back
about its X on a Mammoth, a Sharov or a Boridin and about its Z on another. Heard as it arrives
(sound 0x3C), the Ripper plays ready to grab from 350 at -6, then cabin turn from 400 at
-4.5, and once its cabin is round turns to put its tail to a point 10000 behind it. Then the pod
is gone into the ship: disabled, no longer targetable and hidden, and the component shows; the
Ripper flies on (motion_forward) and has its RipperDroppedObject, and it carries nothing from
then on.
A Mammoth's cargo slots stay hidden until the Ripper fills them because the mission's script
hides them: it disables the components as it makes the ship (DisableObject), which hides each
assembly. Mission 1 disables a squad that holds the Loadup Mammoth's components 3 to 24 as it
creates the ship's flight group.
Fix: where the next rippercargo entry is still taken, the game stops with "Ripper Grab AI
error: Too many rippers doing their stuff at once."; where a Ripper carries nothing, it stops with
"Can't find the object the ripper grabbed!"; and for a component of a type its table of the Mammoth
and the Stalag lacks, it reads the grab point's height past the table's end. OpenReliant logs the
first and takes the entry, ends the order for the second, and stands 2500 above the component for
the third.
Fix: Ripper attach cargo pod to Mammoth never clears the Ripper's rippercargo entry once the
pod is fitted, so what the Ripper carries stays that pod: each later drop or fit by the same Ripper
takes the pod it fitted first out of the ship again, while the pod last grabbed stays hidden where
it was lifted, and RipperDroppedObject names the wrong pod. OpenReliant clears the entry, as Ripper
end drop object does.
Fix: as its cabin turns back, Ripper attach cargo pod to Mammoth waits for the root's first
child, a forearm with no cabin turn track that the step before has already seen at rest, so the
Ripper turns away while its cabin is still turning. OpenReliant waits for the Ripper Cabin part,
as Ripper end drop object does.
Fix: Make ripper drop what it's carrying takes a negative index other than -1 for a ship's
slot, and its sound 0x3C, which follows an object, plays on none; both read before the objects'
table. OpenReliant takes such an index for none, and plays nothing.
Improvement: the pod's turn as it fits divides the share past 0.15 by the span to 0.5, where
the game multiplies it by its rounded reciprocal (0x004DC540).
Improvement: the beams' orders place what they carry once a tick, and the game draws it there;
OpenReliant draws it on between the ticks, as far as a tick of the step would take it
(create.Slot.glide), as the target is drawn in (steps 4 and 6) and as the pod is carried onto the
component. --no-smooth-motion leaves it where each tick places it.
Picking a fight¶
Find New Target's walk visits each ship with 0x0040AE90, which passes over one the ship cannot aim
at, cloaked or not. It counts the objects with stats whose current order is aimed at that ship and
component: Fight, and Mill. The ship then weighs as one to fight the square of the distance times
one more than the ships that fight it, and as one to mill round, times one more than those and one
more than those that mill round it. The lightest of each is kept, but to fight only a ship that is
not cloaked, not the target set aside for the searcher (+0x6AC, which the radio's menu sets to the
player's target for 3000 ticks, 0x0045517F), and for a fighter one that fewer than two others
fight. A set-aside target whose time is up (+0x6B0 before game_ticks) is set aside no more, but
is passed over as one to fight this walk still.
Quirk: the game weighs the one to fight by 0.7 more (0x004DC484) where the count of objects it
has just walked through equals the player's slot, which never happens; it looks meant to favour the
player's ship (#314). OpenReliant weighs as
the game does.