Classic bug: Droid phasers fire straight ahead

Bug ID GE-BUG-057
Affected versions Classic GE 3.2e Murdonian Transport and Vakory Survey Drone
Status Verified in classic source; corrected in ge-next 0.2
Fixed in ge-next 0.2 Droid rewrite
Primary source droid_act_class_11() and droid_act_class_12() in classic GEDROIDS.C; firep() in classic GECMDS.C; droid_phaser() in ge-next GEDROIDS.C

Summary

When the classic Murdonian Transport or Vakory Survey Drone retaliates with standard phasers at impulse, it fires along its current heading instead of aiming at the attacker. A nearby attacker outside that narrow forward firing arc can avoid the shot even when the Droid has identified the attacker and is ready to fire. The same Droids calculate a bearing to the attacker for hyper-phaser fire when both ships are at warp.

The Lydorian Garbage Scow has an installed phaser but its classic AI never calls either phaser firing routine, so it does not have this particular aiming failure. No other classic Droid classes have dedicated behavior in the distributed 3.2e GEDROIDS.C.

Cause and effect

Both affected routines find the ship recorded as the last attacker and enter a retaliation branch. Their warp branch sets ptr->degrees from cbearing() before calling firehp(). Their impulse branch instead sets ptr->degrees = 0, sets spread to 2, and calls firep() if the phaser is ready and the attacker is not fully cloaked.

firep() centers its firing arc on the Droid's heading plus ptr->degrees. Zero is therefore straight ahead, not a request to aim automatically at the recorded attacker. With the default phaser bias of 2, spread 2 tests targets at an angular offset strictly less than four degrees from that centerline. A ship in that arc can still be hit, whether or not it is the attacker; a ship outside it is not hit merely because it provoked the retaliation. The phaser charge is spent on an accepted shot even if the sweep misses.

The two classic routines use the same straight-ahead assignment. This could be read as deliberate forward-only firing, but neither routine checks whether the attacker is ahead, and the same retaliation path aims its hyper-phaser at the attacker. Classic Cybertron combat also calculates a target bearing before standard phaser fire. Taken together, the code points to an omitted aiming step rather than a stated Droid weapon restriction.

Correction in ge-next 0.2

ge-next 0.2 reworked the existing Droids and introduced new ones. Their firing paths use the shared droid_phaser() helper, which calculates the relative bearing to the chosen target before calling either firep() or firehp(). Thus both standard and hyper-phaser shots are aimed at that target, subject to the normal visibility, range, readiness, and firing rules. This is part of the 0.2 Droid rewrite, not a separate later phaser change.

See also