Descent 3
Outrage Entertainment's 1999 shooter of free flight through mines and over planet surfaces, read through the source code released in 2024.
On this page
The atlas reads Descent 3 through the source code Outrage’s Kevin Bentley released in 2024, at its initial import. That code includes the unreleased “1.5” patch, and its files carry revisions as late as 20011, so every claim here describes the released code rather than the 1999 retail build. The game’s data tables aren’t in the release, so the ships’ and weapons’ own numbers are not known here.
The ship has inertia on all three axes. Its thrust is a forward, an up, and a sideways push, and a drag proportional to speed works against it every frame, thrusting or not, so the ship levels off at thrust over drag, as Doom’s player does against floor friction2. Turning works the same way about three axes, for six degrees of freedom in all3. Each push is capped on its own, so holding all three moves the ship 1.73 ×4 as fast as forward alone, the three-axis form of Doom’s strafe-running4.
The afterburner is a boost meter: a 5-second tank that multiplies forward thrust by 1.6 and refills when let go, taking energy as it does5.
A homing missile looks for the enemy most nearly ahead of it inside its weapon’s cone, within 500 units and with a clear line to it, and steers at a point a tenth of a second ahead of it6,7. Robots’ missiles turn at 0.2 times their rate on Trainee and 1.4 times on Insane7.
Robots can lose their nerve. Every few seconds a robot weighs its shields, the friends near it, and a per-robot life_preservation value, and a frightened robot flees for 10 × life_preservation + 5 seconds8.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Inertia | Drag always | thrust on three axes against a drag proportional to speed, solved exactly each frame, so the ship settles at thrust over drag |
| Six degrees of freedom | Damped | pitch, heading, and bank take thrust like movement does and fade under their own drag when let go |
| Strafe-running | Separately capped axes | forward, up, and sideways are capped apart and summed, so all three at once push 1.73 times as hard as forward alone |
| Boost meter | Free refill | a 5-second afterburner tank at 1.6 times forward thrust, refilled while let go at a cost in energy |
| Homing missile | Cone and turn | the target most nearly ahead in the weapon's cone within 500 units, led by a tenth of a second, with robots' missiles turning slower or faster by difficulty |
Every claim about this game, by concept (8)
References
- ^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.cppgives its last revision as 279, dated 9/20/01.CodeDescentDevelopers/Descent3How we know
This 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.
README.md#L3 · upstream ↗ 2 * $Logfile: /DescentIII/Main/WeaponFire.cpp $ 3 * $Revision: 279 $ 4 * $Date: 9/20/01 5:33p $
Descent3/WeaponFire.cpp lines 2–4 at 61bb9a3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^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'smovement_scalarand 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.CodeDescentDevelopers/Descent3 · id-Software/DOOM · id-Software/QuakeHow we know
2580 if (OBJECT_OUTSIDE (objp)) 2581 speed_scalar*=1.3f; ⋮ 2583 objp->mtype.phys_info.thrust = speed_scalar*Players[objp->id].movement_scalar * ((objp->orient.fvec * controls.forward_thrust * objp->mtype.phys_info.full_thrust) + 2584 (objp->orient.uvec * controls.vertical_thrust * objp->mtype.phys_info.full_thrust) + 2585 (objp->orient.rvec * controls.sideways_thrust * objp->mtype.phys_info.full_thrust));
Descent3/object.cpp lines 2580–2585 at 61bb9a3 · upstream ↗ 994 if (obj->mtype.phys_info.drag != 0.0) ⋮ 996 if (obj->mtype.phys_info.flags & PF_USES_THRUST) ⋮ 998 total_force += obj->mtype.phys_info.thrust;
physics/physics.cpp lines 994–998 at 61bb9a3 · upstream ↗ 279 // Standard motion with a linear air drag (drag is proportional to velocity) ⋮ 281 const double oneOverDrag = 1.0 / drag; 282 const double massOverDrag = mass / drag; 283 const double forceOverDrag[3] = { force.x * oneOverDrag, force.y * oneOverDrag, force.z * oneOverDrag }; ⋮ 285 const double expDoMDt = exp( (-1.0 / massOverDrag) * dt ); ⋮ 291 newVel.x = static_cast<float>( (objVel[0] - forceOverDrag[0]) * expDoMDt + forceOverDrag[0] );
physics/physics.cpp lines 279–293 at 61bb9a3 · upstream ↗ 238 mo->momx = FixedMul (mo->momx, FRICTION); 239 mo->momy = FixedMul (mo->momy, FRICTION);
linuxdoom-1.10/p_mobj.c lines 238–239 at a77dfb9 · upstream ↗ 112#define FRICTION 0xe800linuxdoom-1.10/p_mobj.c line 112 at a77dfb9 · upstream ↗ 195 currentspeed = DotProduct (velocity, wishdir); 196 addspeed = wishspeed - currentspeed; ⋮ 199 accelspeed = sv_accelerate.value*host_frametime*wishspeed; 200 if (accelspeed > addspeed) 201 accelspeed = addspeed;
WinQuake/sv_user.c lines 195–201 at bf4ac42 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^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_rotthrusttimes the player'sturn_scalar, and an object flaggedPF_USES_THRUSTwith 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,PhysicsDoSimRotcan add auto-leveling thrust to pitch and bank, which this claim doesn't cover.CodeDescentDevelopers/Descent3How we know
2566 objp->mtype.phys_info.rotthrust.x = controls.pitch_thrust * objp->mtype.phys_info.full_rotthrust * playp->turn_scalar; 2567 objp->mtype.phys_info.rotthrust.z = controls.bank_thrust * objp->mtype.phys_info.full_rotthrust * playp->turn_scalar; 2568 objp->mtype.phys_info.rotthrust.y = controls.heading_thrust * objp->mtype.phys_info.full_rotthrust * playp->turn_scalar;
Descent3/object.cpp lines 2566–2568 at 61bb9a3 · upstream ↗ 430#define LIMIT_PITCH 0.75f 431#define LIMIT_HEADING 1.0f 432#define LIMIT_BANK 1.0f
Descent3/Controls.cpp lines 430–432 at 61bb9a3 · upstream ↗ 887#ifndef MACINTOSH 888// clip controller values 889 if (controls->pitch_thrust > LIMIT_PITCH) controls->pitch_thrust = LIMIT_PITCH; ⋮ 894 if (controls->bank_thrust < -LIMIT_BANK) controls->bank_thrust = -LIMIT_BANK; 895#endif
Descent3/Controls.cpp lines 887–895 at 61bb9a3 · upstream ↗ 714 if (pi->rotdrag > 0.0f) ⋮ 716 if(!(pi->flags & PF_USES_THRUST)) ⋮ 718 *rotthrust = Zero_vector; ⋮ 721 PhysicsApplyConstRotForce(*obj, *rotthrust, *rotvel, frame_time);
physics/physics.cpp lines 714–721 at 61bb9a3 · upstream ↗ 245 // Standard angular motion with a linear air drag (drag is proportional to angular velocity) 246 const double oneOverDrag = 1.0 / drag; 247 const double rotForceOverDrag[3] = { double(rotforce.x) * oneOverDrag, double(rotforce.y) * oneOverDrag, double(rotforce.z) * oneOverDrag }; 248 const double dragOverMass = drag / mass; 249 const double expDoMDt = exp( -dragOverMass * double(deltaTime) ); ⋮ 252 newRotVel[0] = ( double(rotvel.x) - rotForceOverDrag[0] ) * expDoMDt + rotForceOverDrag[0];
physics/physics.cpp lines 245–252 at 61bb9a3 · upstream ↗ 684 rotthrust->z -= scale * BANK_AUTOLEVEL_SPEED_SCALAR * obj->mtype.phys_info.full_rotthrust;physics/physics.cpp line 684 at 61bb9a3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abDescent 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°.CodeDescentDevelopers/Descent3 · id-Software/DOOM
How we know
896 if (controls->sideways_thrust > LIMIT_HORIZ) controls->sideways_thrust = LIMIT_HORIZ; ⋮ 898 if (controls->vertical_thrust > LIMIT_VERT) controls->vertical_thrust = LIMIT_VERT; ⋮ 901 if (controls->forward_thrust > LIMIT_FORWARD) controls->forward_thrust = LIMIT_FORWARD;
Descent3/Controls.cpp lines 896–902 at 61bb9a3 · upstream ↗ 433#define LIMIT_HORIZ 1.0f 434#define LIMIT_VERT 1.0f 435#define LIMIT_FORWARD 1.0f
Descent3/Controls.cpp lines 433–435 at 61bb9a3 · upstream ↗ 2583 objp->mtype.phys_info.thrust = speed_scalar*Players[objp->id].movement_scalar * ((objp->orient.fvec * controls.forward_thrust * objp->mtype.phys_info.full_thrust) + 2584 (objp->orient.uvec * controls.vertical_thrust * objp->mtype.phys_info.full_thrust) + 2585 (objp->orient.rvec * controls.sideways_thrust * objp->mtype.phys_info.full_thrust));
Descent3/object.cpp lines 2583–2585 at 61bb9a3 · upstream ↗ 160 if (cmd->forwardmove && onground) 161 P_Thrust (player, player->mo->angle, cmd->forwardmove*2048); ⋮ 163 if (cmd->sidemove && onground) 164 P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048);
linuxdoom-1.10/p_user.c lines 160–164 at a77dfb9 · upstream ↗ 413 if (forward > MAXPLMOVE) 414 forward = MAXPLMOVE; ⋮ 417 if (side > MAXPLMOVE) 418 side = MAXPLMOVE;
linuxdoom-1.10/g_game.c lines 413–420 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^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.CodeDescentDevelopers/Descent3revisedHow we know
372// How long afterburner lasts before it has to be recharged 373#ifdef E3_DEMO 374#define AFTERBURN_TIME 5000.0 375#else 376#define AFTERBURN_TIME 5.0 377#endif
Descent3/player.h lines 372–377 at 61bb9a3 · upstream ↗ 2289 if (controls->afterburn_thrust>0) ⋮ 2293 if (Players[slot].afterburn_time_left>0) ⋮ 2295 float punch_scalar=1.0; ⋮ 2300 if (Players[slot].afterburn_time_left>(AFTERBURN_TIME*.90)) 2301 punch_scalar=1.8f; 2302 else if (Players[slot].afterburn_time_left>(AFTERBURN_TIME*.80) && Players[slot].afterburn_time_left<(AFTERBURN_TIME*.90)) ⋮ 2304 float norm=Players[slot].afterburn_time_left-(AFTERBURN_TIME*.80); 2305 norm/=(AFTERBURN_TIME*.1); 2306 punch_scalar=1.0+(norm*.8); ⋮ 2310 controls->forward_thrust=controls->afterburn_thrust*1.6*punch_scalar; 2311 else 2312 controls->forward_thrust=controls->afterburn_thrust*1.6*punch_scalar; ⋮
Descent3/object.cpp lines 2289–2317 at 61bb9a3 · upstream ↗ 2325 else ⋮ 2329 if (Players[slot].afterburn_time_left<AFTERBURN_TIME) ⋮ 2331 if (Players[slot].energy>5.0) ⋮ 2337 if( afterburner_id!=-1 && Players[slot].inventory.CheckItem(OBJ_POWERUP,afterburner_id)) 2338 useage = Frametime*2; 2339 else 2340 useage = Frametime; ⋮ 2342 Players[slot].afterburn_time_left+=useage; 2343 Players[slot].afterburn_time_left=min (AFTERBURN_TIME,Players[slot].afterburn_time_left); ⋮ 2345 Players[slot].energy-=(useage);
Descent3/object.cpp lines 2325–2345 at 61bb9a3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^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.CodeDescentDevelopers/Descent3How we know
1719 if((obj->mtype.phys_info.flags & PF_USES_THRUST) && (obj->ctype.laser_info.thrust_left >= 0.0)) ⋮ 1721 obj->ctype.laser_info.thrust_left -= Frametime; ⋮ 1723 if((obj->creation_time + 0.1f < Gametime) && (obj->mtype.phys_info.flags & PF_HOMING) && !(obj->mtype.phys_info.flags & PF_GUIDED)) ⋮ 1725 obj->ctype.laser_info.last_track_time = Gametime - HOMING_CHECK_VIS_INTERVAL; 1726 HomingDoFrame(obj);
Descent3/WeaponFire.cpp lines 1719–1726 at 61bb9a3 · upstream ↗ 1461#define MAX_HOMING_DIST 500.0f 1462#define CLOSE_HOMING_DIST 15.0
Descent3/WeaponFire.cpp lines 1461–1462 at 61bb9a3 · upstream ↗ 1604 for(i = 0; i <= Highest_object_index; i++) ⋮ 1606 if(BOA_IsVisible(obj->roomnum, Objects[i].roomnum)) ⋮ 1608 if((i != OBJNUM(weapon_parent)) && ((Objects[i].type == OBJ_BUILDING && Objects[i].ai_info) || (Objects[i].type == OBJ_ROBOT) || (Objects[i].type == OBJ_PLAYER))) ⋮ 1612 if(Objects[i].effect_info && Objects[i].effect_info->type_flags & EF_CLOAKED) 1613 continue; ⋮ 1615 if(weapon_parent && !AIObjEnemy(ObjGetUltimateParent(weapon_parent), ObjGetUltimateParent(&Objects[i]))) 1616 continue; ⋮ 1619 float cur_dot = to_target * obj->orient.fvec; ⋮ 1621 if(cur_dot > Weapons[obj->id].homing_fov)
Descent3/WeaponFire.cpp lines 1604–1621 at 61bb9a3 · upstream ↗ 1623 //Pick chaff over other objects 1624 if ((Objects[i].type == OBJ_ROBOT) && (Objects[i].id == GENOBJ_CHAFFCHUNK)) ⋮ 1634 break; ⋮ 1637 else ⋮ 1642 break; ⋮ 1646 else ⋮ 1648 if (ps_rand() < RAND_MAX/4) 1649 { // 1/4 chance of picking chaff 1650 best_index = i; 1651 break; ⋮ 1655 else if(dist_to_target < CLOSE_HOMING_DIST) ⋮ 1657 best_index = i; ⋮
Descent3/WeaponFire.cpp lines 1623–1659 at 61bb9a3 · upstream ↗ 1660 else if(dist_to_target < MAX_HOMING_DIST) ⋮ 1662 if(cur_dot > best_dot) ⋮ 1677 if(hit_info.hit_type[0] == HIT_NONE) ⋮ 1679 best_index = i; 1680 best_dist = dist_to_target; 1681 best_dot = cur_dot;
Descent3/WeaponFire.cpp lines 1660–1681 at 61bb9a3 · upstream ↗ 1497 else if(to_target * obj->orient.fvec > Weapons[obj->id].homing_fov) ⋮ 1509 else ⋮ 1539 if(hit_info.hit_type[0] == HIT_NONE) ⋮ 1549 if(dist_to_target < CLOSE_HOMING_DIST) ⋮ 1551 f_locked = true; ⋮ 1553 else if(dist_to_target < MAX_HOMING_DIST) ⋮ 1555 if(BOA_IsVisible(obj->roomnum, track_goal->roomnum)) ⋮ 1572 if(hit_info.hit_type[0] == HIT_NONE) ⋮ 1574 f_locked = true; ⋮ 1577 else ⋮ 1579 f_locked = true;
Descent3/WeaponFire.cpp lines 1497–1580 at 61bb9a3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abDescent 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_rotthrustleft 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 mostfull_rotthrust× the frame time and has its velocity set along its new facing atfull_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.CodeDescentDevelopers/Descent3How we know
1413 if(target->movement_type == MT_PHYSICS || target->movement_type == MT_WALKING) ⋮ 1415 movement = 0.1f * (target->mtype.phys_info.velocity); ⋮ 1418 dir_to_target = target->pos + movement - weapon->pos;
Descent3/WeaponFire.cpp lines 1413–1418 at 61bb9a3 · upstream ↗ 1420 if(weapon->mtype.phys_info.rotdrag > 0.0f) ⋮ 1422 if(dir_to_target * weapon->orient.rvec > 0.0) ⋮ 1424 weapon->mtype.phys_info.rotthrust.y = weapon->mtype.phys_info.full_rotthrust; ⋮ 1431 if(dir_to_target * weapon->orient.uvec > 0.0) ⋮ 1433 weapon->mtype.phys_info.rotthrust.x = -weapon->mtype.phys_info.full_rotthrust; ⋮ 1440 weapon->mtype.phys_info.rotthrust.z = 0.0; ⋮ 1442 if(!ObjGet(weapon->parent_handle) || ObjGet(weapon->parent_handle)->type != OBJ_PLAYER) 1443 weapon->mtype.phys_info.rotthrust *= Diff_homing_strength[DIFF_LEVEL];
Descent3/WeaponFire.cpp lines 1420–1443 at 61bb9a3 · upstream ↗ 1445 else ⋮ 1450 if(!ObjGet(weapon->parent_handle) || ObjGet(weapon->parent_handle)->type != OBJ_PLAYER) 1451 scalar = Diff_homing_strength[DIFF_LEVEL]; 1452 else 1453 scalar = 1.0f; ⋮ 1455 AITurnTowardsDir(weapon, &dir_to_target, weapon->mtype.phys_info.full_rotthrust * scalar); 1456 weapon->mtype.phys_info.velocity = weapon->orient.fvec * weapon->mtype.phys_info.full_thrust/weapon->mtype.phys_info.drag;
Descent3/WeaponFire.cpp lines 1445–1457 at 61bb9a3 · upstream ↗ 2206 max_angle = turn_rate * Frametime; ⋮ 2208 if((float)goal_angle > max_angle)
Descent3/AImain.cpp lines 2206–2208 at 61bb9a3 · upstream ↗ 16float Diff_homing_strength[5] = {0.20f, 0.70f, 1.00f, 1.20f, 1.40f};Descent3/difficulty.cpp line 16 at 61bb9a3 · upstream ↗ 7#define DIFFICULTY_TRAINEE 0 8#define DIFFICULTY_ROOKIE 1 9#define DIFFICULTY_HOTSHOT 2 10#define DIFFICULTY_ACE 3 11#define DIFFICULTY_INSANE 4
Descent3/difficulty_external.h lines 7–11 at 61bb9a3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^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.CodeDescentDevelopers/Descent3How we know
6704 if(ai_info->mem_time_till_next_update <= 0.0f) ⋮ 6708 // Compute next analyze time 6709 ai_info->mem_time_till_next_update = 3.0f + (float)ps_rand()/(float)RAND_MAX * 2.0f;
Descent3/AImain.cpp lines 6704–6709 at 61bb9a3 · upstream ↗ 6640 int fear_depth = (ai_info->life_preservation) * (AI_MEM_DEPTH - 1) + 1; ⋮ 6644 if(fear_depth >= AI_MEM_DEPTH) 6645 fear_depth = AI_MEM_DEPTH - 1;
Descent3/AImain.cpp lines 6640–6645 at 61bb9a3 · upstream ↗ 6651 if(ai_info->goals[3].used == 0 && ai_info->awareness > AWARE_BARELY) ⋮ 6653 if(IS_GENERIC(obj->type) && 6654 mem[0].shields/Object_info[obj->id].hit_points < ai_info->life_preservation && 6655 mem[0].num_enemy_shots_dodged > 0 && 6656 mem[0].num_friends < 2 && 6657 (float)ps_rand()/(float)RAND_MAX < ai_info->life_preservation) ⋮ 6659 float time = 10.0f * ai_info->life_preservation + 5.0f; ⋮ 6661 GoalAddGoal(obj, AIG_WANDER_AROUND, NULL, 3, 2.0f, GF_SPEED_FLEE | GF_ORIENT_VELOCITY | GF_NONFLUSHABLE); 6662 GoalAddEnabler(obj, 3, AIE_CLEAR_TIME, (void *)&time, 1.0, 0.0); ⋮ 6669 if(IS_GENERIC(obj->type) && 6670 (mem[fear_depth].shields - mem[0].shields)/mem[fear_depth].shields > 0.25f * (1.0f - ai_info->life_preservation) && 6671 (float)ps_rand()/(float)RAND_MAX < ai_info->life_preservation) ⋮
Descent3/AImain.cpp lines 6651–6686 at 61bb9a3 · upstream ↗ 4995 case GF_SPEED_FLEE: 4996 n_speed = obj->ai_info->flee_vel_percent;
Descent3/AImain.cpp lines 4995–4996 at 61bb9a3 · upstream ↗ 1700 case(AIE_CLEAR_TIME): ⋮ 1702 f_enabled = e_info->time >= Gametime - cur_goal->creation_time; 1703 if(!f_enabled) ⋮ 1705 GoalClearGoal(obj, cur_goal);
Descent3/AIGoal.cpp lines 1700–1706 at 61bb9a3 · upstream ↗ 172#define IS_GENERIC(type) ((type == OBJ_CLUTTER) || (type == OBJ_BUILDING) || (type == OBJ_ROBOT) || (type == OBJ_POWERUP))Descent3/object_external.h line 172 at 61bb9a3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
Sources
Code
- Entertainment, Outrage. 2024. “Descent 3: the source release (DescentDevelopers/Descent3, initial import).” Commit 61bb9a3. DescentDevelopers/Descent3 @ 61bb9a3 · licence, all uses
- Software, id. 2024. “DOOM: the Linux source release (id-Software/DOOM, linuxdoom-1.10).” Commit a77dfb9. id-Software/DOOM @ a77dfb9 · licence, all uses
- Software, id. 2012. “Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld).” Commit bf4ac42. id-Software/Quake @ bf4ac42 · licence, all uses