data/claims/descent3.yamlDescent 3 (Outrage's source release, DescentDevelopers/Descent3 at the initial import)
Game: Descent 3.
The README of the Descent 3 source release, at its initial import, calls it "the latest version of the Descent 3 source code" and says it "includes the '1.5' patch that Jeff Slutter and Kevin Bentley wrote several years ago"; the SourceSafe header comment of WeaponFire.cpp gives its last revision as 279, dated 9/20/01. descent3/source-version
Value: 1.5
CodeDescent 3: the source release (DescentDevelopers/Descent3, initial import) ·README.md#L3This is the latest version of the Descent 3 source code. This includes the '1.5' patch that Jeff Slutter and Kevin Bentley wrote several years ago.Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L2-L4* $Logfile: /DescentIII/Main/WeaponFire.cpp $
* $Revision: 279 $
* $Date: 9/20/01 5:33p $Checked by claude, 2026-10-22 — read the README and WeaponFire.cpp's header comment at the pinned commitThe game shipped in 1999, so the released code is later than the retail build. The headers of other cited files are dated from March 2000 (object.cpp) to September 2001 (player.h); physics/physics.cpp has none. The 1.5 patch was never released as a patch.
Cited by: Descent 3
In Descent 3's released source, which includes the unreleased "1.5" patch, the player ship's thrust is the sum of a forward, an up, and a sideways push along the ship's own axes, each the control's value times full_thrust, the whole scaled by the player's movement_scalar and by 1.3 outdoors; the physics then moves a thrusting object against a drag proportional to velocity, solved in closed form over the frame: v = (v₀ − F/d)·e^(−(d/m)·t) + F/d. Computed from that formula, drag acts while the ship thrusts too, and speed levels off at F/d, as in Doom, whose floor friction multiplies momentum by 0.90625 each tic thrust or not; Quake's ground acceleration instead stops at the wish speed. descent3/ship-thrust
Value
{
"settled_speed": "full_thrust / drag",
"outdoor_scale": 1.3
}Descent3/object.cpp#L2580-L2585if (OBJECT_OUTSIDE (objp))
speed_scalar*=1.3f;
…
objp->mtype.phys_info.thrust = speed_scalar*Players[objp->id].movement_scalar * ((objp->orient.fvec * controls.forward_thrust * objp->mtype.phys_info.full_thrust) +
(objp->orient.uvec * controls.vertical_thrust * objp->mtype.phys_info.full_thrust) +
(objp->orient.rvec * controls.sideways_thrust * objp->mtype.phys_info.full_thrust));Descent 3: the source release (DescentDevelopers/Descent3, initial import) · physics/physics.cpp#L994-L998if (obj->mtype.phys_info.drag != 0.0)
{
if (obj->mtype.phys_info.flags & PF_USES_THRUST)
{
total_force += obj->mtype.phys_info.thrust;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · physics/physics.cpp#L279-L293// Standard motion with a linear air drag (drag is proportional to velocity)
…
const double oneOverDrag = 1.0 / drag;
const double massOverDrag = mass / drag;
const double forceOverDrag[3] = { force.x * oneOverDrag, force.y * oneOverDrag, force.z * oneOverDrag };
…
const double expDoMDt = exp( (-1.0 / massOverDrag) * dt );
…
newVel.x = static_cast<float>( (objVel[0] - forceOverDrag[0]) * expDoMDt + forceOverDrag[0] );DOOM: the Linux source release (id-Software/DOOM, linuxdoom-1.10) · linuxdoom-1.10/p_mobj.c#L238-L239mo->momx = FixedMul (mo->momx, FRICTION);
mo->momy = FixedMul (mo->momy, FRICTION);DOOM: the Linux source release (id-Software/DOOM, linuxdoom-1.10) · linuxdoom-1.10/p_mobj.c#L112#define FRICTION 0xe800Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/sv_user.c#L195-L201currentspeed = DotProduct (velocity, wishdir);
addspeed = wishspeed - currentspeed;
…
accelspeed = sv_accelerate.value*host_frametime*wishspeed;
if (accelspeed > addspeed)
accelspeed = addspeed;Checked by claude, 2026-10-22 — read the player branch of the controls-to-physics code in object.cpp, do_physics_sim's force sum and PhysicsApplyConstantForce at the pinned commit; at t → ∞ the exponential term vanishes, leaving v = F/d; the Doom and Quake lines are the ones their own claims citeThe ship's mass, drag, and full_thrust are in the game's data tables, not the source, so the settled speed in units per second isn't known here. Doom's friction applies only on the floor (doom/friction). The code is the release's, not the 1999 retail build's.
Cited by: Descent 3, Six degrees of freedom
Descent 3's released source turns the player ship on three axes the same way it moves it on three: pitch, heading, and bank each take the control's value times full_rotthrust times the player's turn_scalar, and an object flagged PF_USES_THRUST with a rotational drag above 0 has its turning speed solved against that drag with the same closed form, ω = (ω₀ − R/d)·e^(−(d/m)·t) + R/d. Computed from it, a held turn levels off at R/d and a released one fades out at rate d/m. The input code clamps pitch to 0.75 and heading and bank to 1, except in a Macintosh build, which skips those three clamps; before the drag step, PhysicsDoSimRot can add auto-leveling thrust to pitch and bank, which this claim doesn't cover. descent3/ship-rotation
About: Descent 3 Six degrees of freedom
Value
{
"pitch_limit": 0.75,
"heading_limit": 1,
"bank_limit": 1
}Descent3/object.cpp#L2566-L2568objp->mtype.phys_info.rotthrust.x = controls.pitch_thrust * objp->mtype.phys_info.full_rotthrust * playp->turn_scalar;
objp->mtype.phys_info.rotthrust.z = controls.bank_thrust * objp->mtype.phys_info.full_rotthrust * playp->turn_scalar;
objp->mtype.phys_info.rotthrust.y = controls.heading_thrust * objp->mtype.phys_info.full_rotthrust * playp->turn_scalar;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/Controls.cpp#L430-L432#define LIMIT_PITCH 0.75f
#define LIMIT_HEADING 1.0f
#define LIMIT_BANK 1.0fDescent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/Controls.cpp#L887-L895#ifndef MACINTOSH
// clip controller values
if (controls->pitch_thrust > LIMIT_PITCH) controls->pitch_thrust = LIMIT_PITCH;
…
if (controls->bank_thrust < -LIMIT_BANK) controls->bank_thrust = -LIMIT_BANK;
#endifDescent 3: the source release (DescentDevelopers/Descent3, initial import) · physics/physics.cpp#L714-L721if (pi->rotdrag > 0.0f)
{
if(!(pi->flags & PF_USES_THRUST))
{
*rotthrust = Zero_vector;
}
…
PhysicsApplyConstRotForce(*obj, *rotthrust, *rotvel, frame_time);Descent 3: the source release (DescentDevelopers/Descent3, initial import) · physics/physics.cpp#L245-L252// Standard angular motion with a linear air drag (drag is proportional to angular velocity)
const double oneOverDrag = 1.0 / drag;
const double rotForceOverDrag[3] = { double(rotforce.x) * oneOverDrag, double(rotforce.y) * oneOverDrag, double(rotforce.z) * oneOverDrag };
const double dragOverMass = drag / mass;
const double expDoMDt = exp( -dragOverMass * double(deltaTime) );
…
newRotVel[0] = ( double(rotvel.x) - rotForceOverDrag[0] ) * expDoMDt + rotForceOverDrag[0];Descent 3: the source release (DescentDevelopers/Descent3, initial import) · physics/physics.cpp#L684rotthrust->z -= scale * BANK_AUTOLEVEL_SPEED_SCALAR * obj->mtype.phys_info.full_rotthrust;Checked by claude, 2026-10-22 — read the rotation lines of the controls-to-physics code, the clamp block in Controls.cpp, the drag step at the end of PhysicsDoSimRot and PhysicsApplyConstRotForce at the pinned commit; the limit at t → ∞ and the decay rate follow from the formulaThe comments in both force functions call the drag "linear air drag". Auto-leveling (bank, and a pitch leveling for new pilots) runs earlier in PhysicsDoSimRot under several settings and is left for a later claim.
Cited by: Descent 3, Six degrees of freedom
Descent 3's input code clamps the forward, up, and sideways thrust controls to ±1 each, separately, and the released source adds the three pushes along the ship's perpendicular axes, so all three held at once push √3 ≈ 1.73 times as hard as forward alone, and, computed from the linear drag, the ship settles at 1.73 times the speed; Doom does the same with two axes, clamping its forward and side moves apart and thrusting them at 90°. descent3/summed-axes
About: Descent 3 Strafe-running
Value: 1.73 ×
CodeDescent 3: the source release (DescentDevelopers/Descent3, initial import) ·Descent3/Controls.cpp#L896-L902if (controls->sideways_thrust > LIMIT_HORIZ) controls->sideways_thrust = LIMIT_HORIZ;
…
if (controls->vertical_thrust > LIMIT_VERT) controls->vertical_thrust = LIMIT_VERT;
…
if (controls->forward_thrust > LIMIT_FORWARD) controls->forward_thrust = LIMIT_FORWARD;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/Controls.cpp#L433-L435#define LIMIT_HORIZ 1.0f
#define LIMIT_VERT 1.0f
#define LIMIT_FORWARD 1.0fDescent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/object.cpp#L2583-L2585objp->mtype.phys_info.thrust = speed_scalar*Players[objp->id].movement_scalar * ((objp->orient.fvec * controls.forward_thrust * objp->mtype.phys_info.full_thrust) +
(objp->orient.uvec * controls.vertical_thrust * objp->mtype.phys_info.full_thrust) +
(objp->orient.rvec * controls.sideways_thrust * objp->mtype.phys_info.full_thrust));DOOM: the Linux source release (id-Software/DOOM, linuxdoom-1.10) · linuxdoom-1.10/p_user.c#L160-L164if (cmd->forwardmove && onground)
P_Thrust (player, player->mo->angle, cmd->forwardmove*2048);
…
if (cmd->sidemove && onground)
P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048);DOOM: the Linux source release (id-Software/DOOM, linuxdoom-1.10) · linuxdoom-1.10/g_game.c#L413-L420if (forward > MAXPLMOVE)
forward = MAXPLMOVE;
…
if (side > MAXPLMOVE)
side = MAXPLMOVE;Checked by claude, 2026-10-22 — read the clamp block and limits in Controls.cpp and the thrust sum in object.cpp; fvec, uvec and rvec are the orientation matrix's rows, so three unit pushes sum to length √3; with drag linear per axis the settled velocity is the force over the drag, so the speed ratio is the same; the Doom lines are those doom/strafe-running citesThe afterburner replaces the forward control with a larger value (descent-3/afterburner), so the ratio differs while it burns. Whether 1999's retail build summed the axes the same way is not checked.
Cited by: Descent 3, Strafe-running
Descent 3's released source gives the afterburner a 5-second tank (AFTERBURN_TIME, 5000 in an E3 demo build): while it is held and time is left, the forward control is replaced by the afterburner control times 1.6, and times a punch factor of 1.8 while over 90% of the tank is left, the factor easing to 1 by 80%, and the tank drains by the frame time. Let go, the tank refills by the frame time, or twice that with the "Afterburner" item in the inventory, but only while energy is above 5, and energy drops by the same amount, so a full refill costs 5 energy (computed) whichever rate applies. descent3/afterburner
About: Descent 3 Boost meter
Value
{
"tank_s": 5,
"thrust": 1.6,
"opening_punch": 1.8,
"refill_energy": 5
}Descent3/player.h#L372-L377// How long afterburner lasts before it has to be recharged
#ifdef E3_DEMO
#define AFTERBURN_TIME 5000.0
#else
#define AFTERBURN_TIME 5.0
#endifDescent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/object.cpp#L2289-L2317if (controls->afterburn_thrust>0)
…
if (Players[slot].afterburn_time_left>0)
{
float punch_scalar=1.0;
…
if (Players[slot].afterburn_time_left>(AFTERBURN_TIME*.90))
punch_scalar=1.8f;
else if (Players[slot].afterburn_time_left>(AFTERBURN_TIME*.80) && Players[slot].afterburn_time_left<(AFTERBURN_TIME*.90))
{
float norm=Players[slot].afterburn_time_left-(AFTERBURN_TIME*.80);
norm/=(AFTERBURN_TIME*.1);
…Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/object.cpp#L2325-L2345else
{
…
if (Players[slot].afterburn_time_left<AFTERBURN_TIME)
{
if (Players[slot].energy>5.0)
{
…
if( afterburner_id!=-1 && Players[slot].inventory.CheckItem(OBJ_POWERUP,afterburner_id))
useage = Frametime*2;
else
useage = Frametime;
…Checked by claude, 2026-10-22 — read DoPlayerAfterburnControl and the AFTERBURN_TIME define at the pinned commit; refilling 5 seconds of tank adds 5 to afterburn_time_left and takes the same 5 from energy, at one or two units per secondThe burn itself costs no energy; the refill does. The player starts with 100 energy and can hold up to 200 (INITIAL_ENERGY and MAX_ENERGY in player_external.h). A player whose controller flags lack PCBF_AFTERBURNER has the control zeroed first (object.cpp), which the atlas reads as a lock the game can set.
Cited by: Descent 3
In Descent 3's released source a homing weapon with thrust left starts homing 0.1 s after it is created, unless it is guided. Without a target, it scans every object in a room the missile's room can see: robots, players, and buildings with AI, not its own shooter, not cloaked, and only enemies of the shooter, inside a cone where the dot product of the direction to it with the missile's facing exceeds the weapon's homing_fov. In object order, a chaff chunk ends the scan (by a 1-in-4 roll in single player) and so does anything within 15 units (the distance between centers less both objects' sizes); otherwise the missile takes the object within 500 units most nearly straight ahead with a clear line to it. A target it has is kept while it stays inside the cone and either within 15 units, or within 500 units, in a visible room, with a clear line. descent3/homing-target
About: Descent 3 Homing missile
Value
{
"start_s": 0.1,
"close_units": 15,
"range_units": 500,
"chaff_chance": 0.25
}Descent3/WeaponFire.cpp#L1719-L1726if((obj->mtype.phys_info.flags & PF_USES_THRUST) && (obj->ctype.laser_info.thrust_left >= 0.0))
{
obj->ctype.laser_info.thrust_left -= Frametime;
…
if((obj->creation_time + 0.1f < Gametime) && (obj->mtype.phys_info.flags & PF_HOMING) && !(obj->mtype.phys_info.flags & PF_GUIDED))
{
obj->ctype.laser_info.last_track_time = Gametime - HOMING_CHECK_VIS_INTERVAL;
HomingDoFrame(obj);Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L1461-L1462#define MAX_HOMING_DIST 500.0f
#define CLOSE_HOMING_DIST 15.0Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L1604-L1621for(i = 0; i <= Highest_object_index; i++)
{
if(BOA_IsVisible(obj->roomnum, Objects[i].roomnum))
{
if((i != OBJNUM(weapon_parent)) && ((Objects[i].type == OBJ_BUILDING && Objects[i].ai_info) || (Objects[i].type == OBJ_ROBOT) || (Objects[i].type == OBJ_PLAYER)))
…
if(Objects[i].effect_info && Objects[i].effect_info->type_flags & EF_CLOAKED)
continue;
…
if(weapon_parent && !AIObjEnemy(ObjGetUltimateParent(weapon_parent), ObjGetUltimateParent(&Objects[i])))
continue;
…
…Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L1623-L1659//Pick chaff over other objects
if ((Objects[i].type == OBJ_ROBOT) && (Objects[i].id == GENOBJ_CHAFFCHUNK))
…
if (ps_rand() < RAND_MAX/4)
{ // 1/4 chance of picking chaff
best_index = i;
break;
…
else if(dist_to_target < CLOSE_HOMING_DIST)
{
best_index = i;
break;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L1660-L1681else if(dist_to_target < MAX_HOMING_DIST)
{
if(cur_dot > best_dot)
…
if(hit_info.hit_type[0] == HIT_NONE)
{
best_index = i;
best_dist = dist_to_target;
best_dot = cur_dot;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L1497-L1580else if(to_target * obj->orient.fvec > Weapons[obj->id].homing_fov)
…
if(dist_to_target < CLOSE_HOMING_DIST)
{
f_locked = true;
}
else if(dist_to_target < MAX_HOMING_DIST)
{
if(BOA_IsVisible(obj->roomnum, track_goal->roomnum))
…
if(hit_info.hit_type[0] == HIT_NONE)
{
…Checked by claude, 2026-10-22 — read WeaponDoFrame's homing branch and HomingAquireTarget at the pinned commit; distances are center to center less both objects' sizes; homing_fov is compared with the dot product of two unit vectors, so it is the cosine of the cone's half-anglehoming_fov is per weapon, from the data tables. In multiplayer the chaff pick is by object number (every fourth) instead of a roll. In the keep-a-target branch the tests for a ghost, a dead player, and a cloak read the missile (obj), not its target (WeaponFire.cpp lines 1489–1496), so they don't drop a target that cloaks after the lock; the head of the community tree still has them. Because WeaponDoFrame backdates last_track_time by 0.25 s before every homing step, the 0.20 s search interval is always past and a missile without a target searches every frame. When thrust_left runs out the missile stops thrusting and homing, and falls under gravity with drag 0.005.
Cited by: Descent 3, Homing missile
Descent 3's released source steers a homing weapon at the target's position plus a tenth of the target's velocity when the target moves under physics or walks. A weapon with rotational drag fires full full_rotthrust left or right and up or down, by which side of the missile the aim point is on, with no roll; one without it turns straight toward the aim point by at most full_rotthrust × the frame time and has its velocity set along its new facing at full_thrust/drag. A weapon whose shooter is not a player has its turning scaled by difficulty: 0.20, 0.70, 1.00, 1.20, and 1.40 from Trainee to Insane. descent3/homing-steer
About: Descent 3 Homing missile
Value
{
"lead_s": 0.1,
"robot_turn_scale": [
0.2,
0.7,
1,
1.2,
1.4
]
}Descent3/WeaponFire.cpp#L1413-L1418if(target->movement_type == MT_PHYSICS || target->movement_type == MT_WALKING)
{
movement = 0.1f * (target->mtype.phys_info.velocity);
}
…
dir_to_target = target->pos + movement - weapon->pos;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L1420-L1443if(weapon->mtype.phys_info.rotdrag > 0.0f)
{
if(dir_to_target * weapon->orient.rvec > 0.0)
{
weapon->mtype.phys_info.rotthrust.y = weapon->mtype.phys_info.full_rotthrust;
…
if(dir_to_target * weapon->orient.uvec > 0.0)
{
weapon->mtype.phys_info.rotthrust.x = -weapon->mtype.phys_info.full_rotthrust;
…
weapon->mtype.phys_info.rotthrust.z = 0.0;
…
…Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/WeaponFire.cpp#L1445-L1457else
{
…
if(!ObjGet(weapon->parent_handle) || ObjGet(weapon->parent_handle)->type != OBJ_PLAYER)
scalar = Diff_homing_strength[DIFF_LEVEL];
else
scalar = 1.0f;
…
AITurnTowardsDir(weapon, &dir_to_target, weapon->mtype.phys_info.full_rotthrust * scalar);
weapon->mtype.phys_info.velocity = weapon->orient.fvec * weapon->mtype.phys_info.full_thrust/weapon->mtype.phys_info.drag;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/AImain.cpp#L2206-L2208max_angle = turn_rate * Frametime;
…
if((float)goal_angle > max_angle)Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/difficulty.cpp#L16float Diff_homing_strength[5] = {0.20f, 0.70f, 1.00f, 1.20f, 1.40f};Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/difficulty_external.h#L7-L11#define DIFFICULTY_TRAINEE 0
#define DIFFICULTY_ROOKIE 1
#define DIFFICULTY_HOTSHOT 2
#define DIFFICULTY_ACE 3
#define DIFFICULTY_INSANE 4Checked by claude, 2026-10-22 — read HomingTurnTowardObj, the turn-rate cap in AITurnTowardsDir, the difficulty table and the level names at the pinned commitAITurnTowardsDir also skips any turn of less than one degree, and five degrees for objects larger than 32 units. For a weapon with rotational drag, the physics re-points its thrust along its new facing each frame (physics.cpp, "Updates the thrust vector to the orientation for homing weapons", in the code's comment). The turn rates themselves are per weapon, in the data tables.
Cited by: Descent 3, Homing missile
In Descent 3's released source, every 3 to 5 seconds an AI object that is more than barely aware and has its fourth goal slot free can take fright, by one of three tests on its own life_preservation (lp), the first two only for generic objects (robots, buildings, clutter, and powerups): its shields are under lp of its hit points, it dodged an enemy shot since the last check, it has fewer than 2 friends near, and a random number below lp; or it lost more than 25% × (1 − lp) of the shields it had some checks ago, and a random number below lp; or lp is over 0.5 and the friends it had are gone while enemies remain. Frightened, it wanders at its flee speed, facing the way it moves, for 10 × lp + 5 seconds. descent3/robot-fear
Value
{
"check_s": [
3,
5
],
"duration": "10 × lp + 5 s"
}Descent3/AImain.cpp#L6704-L6709if(ai_info->mem_time_till_next_update <= 0.0f)
{
…
// Compute next analyze time
ai_info->mem_time_till_next_update = 3.0f + (float)ps_rand()/(float)RAND_MAX * 2.0f;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/AImain.cpp#L6640-L6645int fear_depth = (ai_info->life_preservation) * (AI_MEM_DEPTH - 1) + 1;
…
if(fear_depth >= AI_MEM_DEPTH)
fear_depth = AI_MEM_DEPTH - 1;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/AImain.cpp#L6651-L6686if(ai_info->goals[3].used == 0 && ai_info->awareness > AWARE_BARELY)
{
if(IS_GENERIC(obj->type) &&
mem[0].shields/Object_info[obj->id].hit_points < ai_info->life_preservation &&
mem[0].num_enemy_shots_dodged > 0 &&
mem[0].num_friends < 2 &&
(float)ps_rand()/(float)RAND_MAX < ai_info->life_preservation)
{
float time = 10.0f * ai_info->life_preservation + 5.0f;
…
GoalAddGoal(obj, AIG_WANDER_AROUND, NULL, 3, 2.0f, GF_SPEED_FLEE | GF_ORIENT_VELOCITY | GF_NONFLUSHABLE);
GoalAddEnabler(obj, 3, AIE_CLEAR_TIME, (void *)&time, 1.0, 0.0);
…Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/AImain.cpp#L4995-L4996case GF_SPEED_FLEE:
n_speed = obj->ai_info->flee_vel_percent;Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/AIGoal.cpp#L1700-L1706case(AIE_CLEAR_TIME):
{
f_enabled = e_info->time >= Gametime - cur_goal->creation_time;
if(!f_enabled)
{
GoalClearGoal(obj, cur_goal);
}Descent 3: the source release (DescentDevelopers/Descent3, initial import) · Descent3/object_external.h#L172#define IS_GENERIC(type) ((type == OBJ_CLUTTER) || (type == OBJ_BUILDING) || (type == OBJ_ROBOT) || (type == OBJ_POWERUP))Checked by claude, 2026-10-22 — read AIDoMemFrame and AIDoFreud, the flee-speed case in the movement code, and the AIE_CLEAR_TIME enabler at the pinned commit; the memory shifts one slot each check, so "some checks ago" is slot fear_depth = lp × 4 + 1, truncated and capped at 4The third test has no random roll. The routine's name, AIDoFreud, and its "Fear!!!!" debug line are the code's own; life_preservation, flee_vel_percent and hit points are per robot, in the data tables.
Cited by: Descent 3