Mechanic · combat · shooter
Homing missile
A projectile that picks a target after it is fired and turns toward it in flight.
On this page
A homing missile does its aiming after it is fired. In Descent 3 it searches a cone ahead of it for the visible enemy most nearly in line, and steers at a point a tenth of a second ahead of that enemy1,2.
Games
| Game | Year | How | Note |
|---|---|---|---|
| Descent 3 | 1999 | 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 mechanic, by game (2)
References
- ^ abIn 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.
Sources
Code
- Entertainment, Outrage. 2024. “Descent 3: the source release (DescentDevelopers/Descent3, initial import).” Commit 61bb9a3. DescentDevelopers/Descent3 @ 61bb9a3 · licence, all uses