Classic bug: SHIELD DOWN bypasses shield repair
| Bug ID | GE-BUG-048 |
|---|---|
| Affected versions | Classic 3.2e and ge-next through 0.3.2 |
| Status | Verified in source; corrected in ge-next |
| Fixed in | ge-next 0.3.3 |
| Primary source | cmd_shields() in GECMDS.C; shielddn(), shieldstat(), shieldrep(), and shieldchg() in GEFUNCS.C
|
Summary
Classic prevents SHIELD UP while Damage Control is repairing a damaged shield, but it does not impose the same restriction on SHIELD DOWN. The down command unconditionally replaces the damaged status with the ordinary down status while leaving the shield's negative internal charge unchanged.
The player can then issue SHIELD UP. Because the damaged status has been erased, the command raises the still-damaged shield. Combat routines treat it as active, and the ordinary charging routine restores its negative charge three times as quickly as the damaged-shield repair routine would.
This allows the player to bypass the intended shield-repair lockout.
Shield state and charge are separate
Each ship stores two relevant shield values:
shieldstatrecords whether the shield is up, down, or damaged.shieldstores its current numeric charge.
An impact that damages a shield sets:
wptr->shieldstat = SHIELDDM;
It also drives shield below zero. The precise negative value depends on the shield's charge before the hit and the calculated impact.
Normal automatic repair depends on both pieces of state. On each ship-state update, shieldstat() calls shieldrep() only when the status is SHIELDDM. The repair routine adds the installed shield Mark to the negative charge:
wptr->shield += (int)(wptr->shieldtype);
When the value finally rises above zero, the routine changes the status to SHIELDDN, resets charge to zero, and reports that repairs are complete. The player can then raise the repaired but empty shield normally.
The incorrect command path
Classic checks for the damaged status only inside its SHIELD UP branch:
if (sameas(margv[1],"up")) {
if (warsptr->shieldstat == SHIELDDM) {
prfmsg(SHNORPR);
outprfge(ALWAYS,usrnum);
return;
}
/* raise shield */
}
The SHIELD DOWN branch has no equivalent guard:
else if (sameas(margv[1],"down")) {
shielddn(warsptr,usrnum);
return;
}
shielddn() then overwrites the damaged state:
wptr->shieldstat = SHIELDDN;
It does not change the negative shield value. On the next SHIELD UP, the damaged-state test no longer matches, so the shield is raised with that negative charge still present.
Reproduction
The behavior can be reproduced in classic and ge-next prior to 0.3.3 with these steps:
- Raise the ship's shields.
- Receive an impact strong enough to damage the shield system.
- Before Damage Control completes the repair, enter
SHIELD DOWN. - Enter
SHIELD UP.
The first command reports that the shields are now down rather than refusing the command. The second command reports that the shields are energizing, despite the shield's internal charge still representing unrepaired damage.
Without the intermediate SHIELD DOWN, step 4 correctly reports that Damage Control is repairing the shields.
REPORT SYSTEMS shows the shield UP with a negative charge while Damage Control reports no damage; later updates charge the negative bank.Gameplay consequences
The raised status is what combat code tests. While the value remains negative, the shield can therefore provide shielded treatment for an incoming attack. Phasers, torpedoes, and missiles can be deflected, while other shield-aware damage sources can receive their normal shielded reduction.
Another effective hit will usually damage the shield again immediately because its charge is already at or below the collapse threshold. Even so, the player may obtain protection from at least one additional attack that the intended repair state would not have allowed.
There is no cooldown on the two shield commands. A player using a command hotkey, macro, or sufficiently fast input can repeat SHIELD DOWN and SHIELD UP after each collapse. Every successful raise restores the status that shield-aware combat code recognizes, even if the numeric charge has become increasingly negative. Against individually spaced phaser, torpedo, or missile impacts, this can function as effectively unlimited shields: each attack is deflected, the system is immediately raised again, and the intended repair delay is never served.
This does not guarantee invulnerability against every damage source. Additional projectiles processed after the first collapse but before the player's commands can strike an unshielded ship, and mines, ion cannons, and self-destruct blasts can transmit reduced hull damage even while shields are up. The exploit nevertheless defeats the normal shield lifecycle against the game's principal directed weapons.
The sequence also accelerates recovery. A shield in the damaged state repairs by Mark charge units per approximately six-second update. A raised shield instead enters shieldchg(), which adds 3 * Mark units per update. It consumes the normal 100 * Mark flux cost while doing so, but can cross from a negative value to usable positive charge about three times as quickly as ordinary automatic repair.
Because shieldstat is no longer damaged, the automatic repair routine and its repair-complete transition do not run. The system instead behaves as a raised, charging shield and can eventually progress from negative charge all the way to its normal maximum.
In a 16-bit build, a sufficiently deep negative charge can make the reported percentage wrap and appear to pass 100 percent while this recovery is taking place. This is a readout artifact exposed by the invalid state, not additional shield strength: the underlying charge remains negative and continues toward the ordinary maximum, where charging stops normally.
Correction in ge-next 0.3.3
ge-next 0.3.3 moved the damaged-state test ahead of the UP and DOWN branches:
if (warsptr->shieldstat == SHIELDDM) {
prfmsg(SHNORPR);
outprfge(FLT_NONE,usrnum);
return;
}
Both shield commands now report that Damage Control is repairing the shields and leave shieldstat unchanged. Only shieldrep(), maintenance, or another legitimate repair mechanism can move the system out of its damaged state.
Home · Play · Reference · Versions & history · Sysop · Development · Classic bugs