<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://manicpop.org/gewiki/index.php?action=history&amp;feed=atom&amp;title=Classic_bug%3A_Flux_subtraction_underflow</id>
	<title>Classic bug: Flux subtraction underflow - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://manicpop.org/gewiki/index.php?action=history&amp;feed=atom&amp;title=Classic_bug%3A_Flux_subtraction_underflow"/>
	<link rel="alternate" type="text/html" href="https://manicpop.org/gewiki/index.php?title=Classic_bug:_Flux_subtraction_underflow&amp;action=history"/>
	<updated>2026-10-20T17:56:59Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://manicpop.org/gewiki/index.php?title=Classic_bug:_Flux_subtraction_underflow&amp;diff=1553&amp;oldid=prev</id>
		<title>CodexBot: Link first command references to command pages</title>
		<link rel="alternate" type="text/html" href="https://manicpop.org/gewiki/index.php?title=Classic_bug:_Flux_subtraction_underflow&amp;diff=1553&amp;oldid=prev"/>
		<updated>2026-10-12T02:14:32Z</updated>

		<summary type="html">&lt;p&gt;Link first command references to command pages&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Classic bug&lt;br /&gt;
|id=GE-BUG-008&lt;br /&gt;
|affected=Classic 3.2e and published classic source&lt;br /&gt;
|status=Verified in source&lt;br /&gt;
|fixed=ge-next 0.3&lt;br /&gt;
|source=Flux checks and weapon, shield, cloak, and movement energy paths&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
Some classic paths can subtract more neutron-flux energy than the ship has. The ship&amp;#039;s energy field is actually a &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt;, so it does not wrap: it becomes genuinely negative. [[Report command|&amp;lt;code&amp;gt;REPORT SYSTEMS&amp;lt;/code&amp;gt;]] then converts that negative value to a 16-bit unsigned integer for display, making depleted flux look like a large value near 65,535.&lt;br /&gt;
&lt;br /&gt;
== Symptoms ==&lt;br /&gt;
After firing a missile or charging shields with very little flux remaining, &amp;lt;code&amp;gt;REP SYS&amp;lt;/code&amp;gt; can show output such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Neutron Flux............ 65136&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The apparent 65,136 flux is not usable energy. Internally, the ship may actually have -400. Commands can report insufficient power, engines can shut down, and shields or cloak can fall even though the systems report appears to show an almost full neutron-flux pile. If a flux pod remains aboard, the next periodic ship update may consume it and restore the pile to 65,000. Without a pod, the ship can remain effectively powerless while the misleading high number slowly changes.&lt;br /&gt;
&lt;br /&gt;
== Cause ==&lt;br /&gt;
Classic stores &amp;lt;code&amp;gt;WARSHP.energy&amp;lt;/code&amp;gt; as a floating-point &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt;, with a normal maximum of 65,000. It has two different energy-handling models:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;useenergy()&amp;lt;/code&amp;gt; checks a requested cost before subtracting it and leaves a 500-unit reserve.&lt;br /&gt;
* Several other paths perform their own incomplete checks and then subtract directly from &amp;lt;code&amp;gt;energy&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The latter paths can cross zero. Although this defect is commonly described as flux “underflow,” it is not unsigned arithmetic underflow in the stored field. It is an ordinary floating-point subtraction whose result is less than zero.&lt;br /&gt;
&lt;br /&gt;
=== Shield charging ===&lt;br /&gt;
Classic permits &amp;lt;code&amp;gt;SHIELDS UP&amp;lt;/code&amp;gt; whenever the pile is greater than &amp;lt;code&amp;gt;SHMINPWR&amp;lt;/code&amp;gt;, which is 200. During the periodic ship-state update, &amp;lt;code&amp;gt;shieldstat()&amp;lt;/code&amp;gt; uses the same 200-unit threshold before calling &amp;lt;code&amp;gt;shieldchg()&amp;lt;/code&amp;gt;. The charging routine, however, subtracts:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
shield mark × 100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The test therefore does not cover the actual cost for any shield above Mark-2. For example, a ship with 201 flux and Mark-5 shields passes the minimum-power test, then subtracts 500 and is left with -299. A Mark-19 shield at the same energy would subtract 1,900 and leave -1,699.&lt;br /&gt;
&lt;br /&gt;
At the beginning of a ship-state update, classic&amp;#039;s &amp;lt;code&amp;gt;fluxstat()&amp;lt;/code&amp;gt; does refill a pile below 5,000 when a flux pod is available. The negative shield result is therefore most readily produced when the ship has no pods. Without a pod, &amp;lt;code&amp;gt;fluxstat()&amp;lt;/code&amp;gt; leaves the low pile unchanged and the later shield charge can take it below zero.&lt;br /&gt;
&lt;br /&gt;
=== Missile firing ===&lt;br /&gt;
A missile&amp;#039;s payload energy is divided by the configurable &amp;lt;code&amp;gt;MISENGFC&amp;lt;/code&amp;gt; ratio to obtain its flux cost. With the default ratio of 100, a 50,000-energy missile costs 500 flux. Classic attempts to reject a missile that the pile cannot support, but compares the cost against:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
current energy + MOVENGMIN&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;code&amp;gt;MOVENGMIN&amp;lt;/code&amp;gt; is 3,000. The added margin makes the right-hand side larger and the test easier to pass, which is the opposite of the needed check. A ship with 100 flux can therefore fire the 50,000-energy missile:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
500 &amp;gt;= 100 + 3,000    /* false, so firing is allowed */&lt;br /&gt;
100 - 500 = -400&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The missile is launched and the negative result remains in the ship record.&lt;br /&gt;
&lt;br /&gt;
=== Why REP SYS shows about 65,000 ===&lt;br /&gt;
Before producing any report, classic executes the equivalent of:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
energy = (unsigned)warsptr-&amp;gt;energy + .5;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here, the destination and cast are the platform&amp;#039;s 16-bit &amp;lt;code&amp;gt;unsigned&amp;lt;/code&amp;gt; type. &amp;lt;code&amp;gt;REP SYS&amp;lt;/code&amp;gt; then prints that temporary value with &amp;lt;code&amp;gt;%u&amp;lt;/code&amp;gt;. On the original compiler, converting a small negative value produces its modulo-65,536 representation:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Actual &amp;lt;code&amp;gt;WARSHP.energy&amp;lt;/code&amp;gt; !! Value shown by &amp;lt;code&amp;gt;REP SYS&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| -1 || 65,535&lt;br /&gt;
|-&lt;br /&gt;
| -299 || 65,237&lt;br /&gt;
|-&lt;br /&gt;
| -400 || 65,136&lt;br /&gt;
|-&lt;br /&gt;
| -1,699 || 63,837&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Only the report&amp;#039;s temporary value is converted. The ship still stores the negative &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt;, which is why gameplay checks continue to recognize that the ship has no power. This conversion is also nonportable C behavior for an out-of-range floating-point value; a modern port must not depend on reproducing it.&lt;br /&gt;
&lt;br /&gt;
== Gameplay effects ==&lt;br /&gt;
The main ship-state routine checks flux before shields, cloak, and recharge. Once energy is negative:&lt;br /&gt;
&lt;br /&gt;
* If a flux pod is aboard, the next state update loads one automatically, consumes the pod, and sets energy to 65,000.&lt;br /&gt;
* If no pod is aboard, raised shields are dropped because the actual energy is below 200.&lt;br /&gt;
* An active cloak is dropped because the actual energy is below its configured per-tick cost.&lt;br /&gt;
* Rotation, acceleration, and phaser recharge fail their energy checks.&lt;br /&gt;
* Movement logic sees energy below the 3,000 minimum and orders the engines to shut down.&lt;br /&gt;
* Hyper-phasers cannot fire because their 6,000-unit minimum is not met.&lt;br /&gt;
&lt;br /&gt;
Natural recharge does not reinterpret the false 65,000 shown by the report. It adds only one unit to the actual &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt; during each ship-state update. A ship at -400 must first spend 400 updates merely reaching zero, and then thousands more reaching useful operating levels. At the normal update cadence, recovering without a pod is therefore impractically slow. The player can manually use a remaining flux pod with [[Flux command|&amp;lt;code&amp;gt;FLUX&amp;lt;/code&amp;gt;]], but a ship with no pods is effectively stranded.&lt;br /&gt;
&lt;br /&gt;
== Correction ==&lt;br /&gt;
ge-next changes &amp;lt;code&amp;gt;fluxstat()&amp;lt;/code&amp;gt; from a periodic threshold check into a request for a specific amount of energy. The caller supplies the complete cost. If the current pile is insufficient, &amp;lt;code&amp;gt;fluxstat()&amp;lt;/code&amp;gt; loads a pod when one is available; otherwise it reports failure and the caller does not perform the action or subtraction.&lt;br /&gt;
&lt;br /&gt;
Missile firing now checks the calculated flux cost at the point where a missile slot has actually been found. Shield charging checks &amp;lt;code&amp;gt;shield mark × 100&amp;lt;/code&amp;gt;, not merely the old 200-unit threshold. Movement and warp entry account for all costs that can occur during the same transition. Phaser recharge, cloaking, weapons, and other recurring users follow the same check-before-subtract rule. As a result, normal gameplay can no longer drive the energy &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt; below zero.&lt;br /&gt;
&lt;br /&gt;
== Compatibility notes ==&lt;br /&gt;
The visible value near 65,535 is a report-conversion symptom, not additional energy granted by design and not the value used by the ship simulation. A port should never reproduce it merely to match the old display. It should prevent the negative value and display the actual validated energy instead.&lt;br /&gt;
&lt;br /&gt;
[[Category:Classic bugs: Numeric correctness]]&lt;br /&gt;
[[Category:Classic bugs: Combat]]&lt;br /&gt;
&lt;br /&gt;
{{GE navigation}}&lt;/div&gt;</summary>
		<author><name>CodexBot</name></author>
	</entry>
</feed>