<?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=Integer_and_storage_assumptions</id>
	<title>Integer and storage assumptions - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://manicpop.org/gewiki/index.php?action=history&amp;feed=atom&amp;title=Integer_and_storage_assumptions"/>
	<link rel="alternate" type="text/html" href="https://manicpop.org/gewiki/index.php?title=Integer_and_storage_assumptions&amp;action=history"/>
	<updated>2026-10-20T14:43:03Z</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=Integer_and_storage_assumptions&amp;diff=2150&amp;oldid=prev</id>
		<title>CodexBot: Link Btrieve explanation at first mention</title>
		<link rel="alternate" type="text/html" href="https://manicpop.org/gewiki/index.php?title=Integer_and_storage_assumptions&amp;diff=2150&amp;oldid=prev"/>
		<updated>2026-10-18T17:53:44Z</updated>

		<summary type="html">&lt;p&gt;Link Btrieve explanation at first mention&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Classic GE was written for 16-bit x86 C and [[Btrieve]]. Its calculations, in-memory structures, database records, and output conventions do not all have the same width. These details matter when investigating a classic bug or porting the game; see [[Porting Galactic Empire]] for the wider workflow.&lt;br /&gt;
&lt;br /&gt;
== Integer and floating-point widths ==&lt;br /&gt;
In the original 16-bit environment, &amp;lt;code&amp;gt;char&amp;lt;/code&amp;gt; and GE&amp;#039;s &amp;lt;code&amp;gt;byte&amp;lt;/code&amp;gt; are one byte, &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;unsigned&amp;lt;/code&amp;gt; are two bytes, and &amp;lt;code&amp;gt;long&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;unsigned long&amp;lt;/code&amp;gt; are four bytes. GE also stores positions, headings, speeds, damage, and some energy values as &amp;lt;code&amp;gt;double&amp;lt;/code&amp;gt;. A field&amp;#039;s declared type, not a modern compiler&amp;#039;s &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt; size, controls what can be saved in it.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;code&amp;gt;WARUSR.score&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;WARUSR.cash&amp;lt;/code&amp;gt; are 32-bit unsigned values in the 16-bit code, but ship and user kill counters are 16-bit &amp;lt;code&amp;gt;unsigned&amp;lt;/code&amp;gt; values. &amp;lt;code&amp;gt;WARSHP.shield&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;WARSHP.lastfired&amp;lt;/code&amp;gt; are 16-bit signed &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt; values; ship inventory quantities are 32-bit &amp;lt;code&amp;gt;unsigned long&amp;lt;/code&amp;gt;. Broad statements such as “scores are 32-bit” do not describe every counter in a record.&lt;br /&gt;
&lt;br /&gt;
The 32-bit port uses MajorBBS types such as &amp;lt;code&amp;gt;SHORT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;USHORT&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;ULONG&amp;lt;/code&amp;gt; in persistent structures. This is necessary because a native 32-bit &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt; can change intermediate arithmetic even if the destination field is narrow. ge-next32&amp;#039;s &amp;lt;code&amp;gt;gernd()&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;USHORT&amp;lt;/code&amp;gt; to preserve 16-bit unsigned behavior at callers that depend on it. Fixed-width fields alone are not enough: promotions, casts, and the point at which a result is narrowed also matter.&lt;br /&gt;
&lt;br /&gt;
== Arithmetic and display ==&lt;br /&gt;
* Multiplication may overflow before a later division reduces the result. Widen the operands before multiplying if the larger intermediate is intended.&lt;br /&gt;
* Subtracting from an unsigned value can wrap instead of producing a negative number. Check availability before changing inventory or energy.&lt;br /&gt;
* Converting a floating-point result to an integer truncates its fractional part. Moving the conversion earlier or later changes distance, damage, or production.&lt;br /&gt;
* A stored unsigned value may be displayed or sorted as signed. Classic&amp;#039;s roster score key is one example: storage type, Btrieve key interpretation, and printed representation must be checked separately. See [[Roster command]].&lt;br /&gt;
* MajorBBS message resources have their own formatter conventions. A C &amp;lt;code&amp;gt;printf()&amp;lt;/code&amp;gt; format is not automatically valid in an MSG file; the expected argument width must match the directive.&lt;br /&gt;
&lt;br /&gt;
These are not theoretical hazards. See [[Classic bug: Cargo weight overflow]], [[Classic bug: Cash and counter wraparound]], and [[Classic bug: Flux subtraction underflow]] for gameplay consequences.&lt;br /&gt;
&lt;br /&gt;
== Byte sentinels and slot limits ==&lt;br /&gt;
Byte-sized fields often use a value outside the valid slot range as a sentinel, but the meaning is specific to each field. For mines in ge-next, &amp;lt;code&amp;gt;MINE_UNUSED&amp;lt;/code&amp;gt; is 255 and &amp;lt;code&amp;gt;MINE_NO_USER&amp;lt;/code&amp;gt; is 254: an unused mine and a live mine without a player owner are different states. Classic did not make that distinction in the same way. A port must reserve sentinel values when sizing channel or ship tables and must not turn one field&amp;#039;s “255” into another field&amp;#039;s “no user.” See [[Mines]] and [[Ship slot]].&lt;br /&gt;
&lt;br /&gt;
== Btrieve record sizes and layout ==&lt;br /&gt;
The shipped classic 16-bit Btrieve templates use 246-byte user records, 501-byte ship records, and 493-byte sector/planet/wormhole records. The corresponding classic C structures are larger: 255, 514, and 512 bytes respectively. GE&amp;#039;s Btrieve calls use the configured record length, so copying &amp;lt;code&amp;gt;sizeof(struct)&amp;lt;/code&amp;gt; bytes as though it were the on-disk format would be wrong. 16-bit ge-next made its structures match the actual 246/501/493-byte records.&lt;br /&gt;
&lt;br /&gt;
Elwynor&amp;#039;s V10 port and ge-next32 use 256-byte user records and 512-byte ship and planet-family records, with matching structure sizes. Those are not byte-for-byte interchangeable with 16-bit files just because the field names look alike. ge-next32 uses explicit filler and compile-time size checks. The ge-arena builds place some newer fields in reserved record space rather than silently enlarging the files. [[Data structures]] gives the complete record table, key layout, and evolution of the fields.&lt;br /&gt;
&lt;br /&gt;
Btrieve keys make offsets and signedness as important as total size. Field order, padding, string width, and key interpretation must be verified against the real file definition. A size check cannot catch a field moved to the wrong offset. Do not infer disk layout solely from a compiler&amp;#039;s default packing or a later port&amp;#039;s structure.&lt;br /&gt;
&lt;br /&gt;
== Porting rule ==&lt;br /&gt;
First establish the valid range and intended result for each operation. Then choose whether invalid input is rejected, an internal result is clamped, or a genuine classic wrap is deliberately retained. Document that choice and test the relevant boundaries. Widening every calculation or preserving every overflow without inspection can each change the game in unintended ways.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data structures]]&lt;br /&gt;
* [[Porting Galactic Empire]]&lt;br /&gt;
* [[Classic bug database]]&lt;br /&gt;
* [[Roster command]]&lt;br /&gt;
&lt;br /&gt;
{{GE navigation}}&lt;br /&gt;
[[Category:Development]]&lt;br /&gt;
[[Category:Classic bugs: Numeric correctness]]&lt;/div&gt;</summary>
		<author><name>CodexBot</name></author>
	</entry>
</feed>