Necessary to give the deity a chance to catch unexpected changes,
e.g. a player moving away stuff right before a give command, leaving
fewer items than the deity intends to take.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
give() silently caps the resulting number of items to 0..ITEM_MAX.
However, its test for "< 0" suffers integer overflow on two's
complement machines (i.e. practically everywhere) when the amount
argument is INT_MIN. give() proceeds as if the result was in range:
it sets the number of items to (short)(n + INT_MIN), telexes the owner
that INT_MIN items were stolen (obviously bogus), and tells the deity
that there are now n + INT_MIN items in X,Y.
On common machines, (short)(n + INT_MIN) == n, i.e. nothing is given.
On an oddball machine with short as wide as int, the cast to short
does nothing, item_prewrite() oopses, and corrects the number of items
to zero.
In both cases, output and telegram lie.
Likewise, its test for "> ITEM_MAX" suffers integer overflow for
sufficiently big amount arguments. Again, give() proceeds as if the
result was in range: it sets the number of items to (short)(n + amt),
telexes the owner that -amt items were stolen (obviously bogus), and
tells the deity that there are now close to INT_MIN items in X,Y.
On common machines, (short)(n + amt) = n + INT_MAX - amt - 1,
i.e. some items are stolen.
On an oddball machine with short as wide as int, the cast to short
does nothing, item_prewrite() oopses, and corrects the number of items
to zero.
Again, output and telegram lie.
Aside: setsector can suffer similar overflows, but it reports the
resulting change correctly. Good enough.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Only one of struct lndstr members lnd_ship, lnd_land may be
non-negative. When a deity screws that up, the server oopses. Be
nice: when setting one, zap the other.
Same for struct plnstr members pln_ship, pln_land.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Upper bounds corrected:
cmd key struct member wrong correct notes
-------------------------------------------------
edit l m sct_mobil 255 127 1
t sct_ptime 255 32767
edit c b nat_btu 1024 max_btus
edit p m pln_mobil 255 127 1
edit u F lnd_harden 255 127 1
Missing bounds supplied, arguments out of bounds are silently clipped
unless noted otherwise:
cmd key struct member bounds notes
---------------------------------------------------
edit c t nat_tgms 0 USHRT_MAX 2
m nat_reserve 0 INT_MAX
T... nat_level[] 0 infinity
edit s a shp_pstage 0 PLG_EXPOSED 3
b shp_ptime 0 32767
M shp_mobil -127 127
c... shp_item[] 0 load limit 4
edit u Y lnd_land -1 size of table 5
M lnd_mobil -127 127
S lnd_ship -1 size of table 5
Z lnd_retreat 0 100
c... lnd_item[] 0 load limit 4
edit p r pln_range 0 max range
s pln_ship -1 size of table 5
y pln_land -1 size of table 5
Notes:
1. Values between SCHAR_MAX and 255 were cast to signed char, changing
the sign.
2. The real upper bound is the number of telegrams in the mailbox, but
counting them isn't worth it.
3. This check is particularly important, because values out of bounds
make the server refuse to start without -F, and empdump -x warn
"export has errors, not importable as is".
4. Values outside 0..ITEM_MAX got caught and clipped by
item_prewrite(). This check avoids the oops, and tightens the upper
bound for units.
5. Argument out-of-bounds are rejected. This check is particularly
important, because unit numbers beyond the size of the table trigger
oopses.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Negative numbers and numbers greater or equal than MAXNOC are invalid.
edit handles such arguments inconsistently:
cmd key struct member arg < 0 arg >= MAXNOC
---------------------------------------------------
edit l o sct_own reject MAXNOC - 1
O sct_oldown reject MAXNOC - 1
X sct_che_target 0 MAXNOC - 1
edit s O shp_own cast skip
edit u O lnd_own cast skip
edit p O pln_own cast skip
Legend:
0 replace arg by 0
MAXNOC - 1 replace arg by MAXNOC - 1
reject command fails
cast replace arg by (natid)arg
bug: can be >= MAXNOC!
skip ignore this key and arg
bug: telexes the owner he lost the unit, which is a lie
Unify to reject. Matches setsector.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
doland() edits a sector, not a land unit. That one's called dounit().
Lacks taste. Call the helper for editing a FOO edit_FOO(), and make
the FOO * the first parameter instead of the last.
Rename the print helpers to print_FOO(), for consistency. Also frees
up identifier prnat for the next commit.
While there, clean up an unused #define.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
When formatting coordinates for fixed-width output, the width should
be at least four characters.
cutoff was fine until 4.0.2 reduced coordinate width to three to make
space for civilian and military delivery thresholds.
level has always used width three.
Can't fix either without making lines too long or dropping
information, so just document the problem for now.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
When formatting coordinates for fixed-width output, the width should
be at least four characters.
Columns x,y and op-sect use three. Has always been that way. Widen
them both to four. This cleans up output for world sizes between 200
and 1998.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
When formatting coordinates for fixed-width output, the width should
be at least four characters.
Columns x,y, start and end use three. Has always been that way,
except for end, which used two until commit e07fb30 (v4.2.13).
Widen them all to four. This cleans up output for world sizes between
200 and 1998.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Coordinates run into army when the y coordinate is wider than three
characters. Has always been broken. Insert a separating space.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Also end URIs with '/' where appropriate.
Refrain from touching scripts/ and Stephen Crane's LWP authorship
note.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
produce() limits production to how many units the workers can produce,
rounding randomly. It charges work for the units actually produced,
discarding fractions.
If you get lucky with the random rounding, you may get a bit of extra
work done for free. Else, you get to keep the unused work, and may
even be undercharged a tiny bit of work. Has always been that way.
The production command assumes the random rounding rounds up if and
only if the probability to do so is at least 50%. Thus, it's
frequently off by one for sectors producing at their worker limit.
The budget command runs the update code, and is therefore also off by
one, only differently.
Rather annoying for tech and research centers, where a single unit
matters. A tech center with full civilian population can produce 37.5
units in 60 etus. Given enough materials, it'll fluctuate between 37
and 38. Production consistently predicts 38, and budget randomly
predicts either 37 or 38. Both are off by one half the time.
Fix this as follows: limit production to the amount the workers can
produce (no rounding). Work becomes a hard limit, not subject to
random fluctuations. Randomly round the work charged for actual
production. On average, this charges exactly the work that's used.
More importantly, production and budget now predict how much gets
produced more accurately. They're still not exact, as the amount of
work available for production remains slightly random.
This also "fixes" the smoke test on a i686 Debian 6 box for me. The
root problem is that floating-point subexpressions may either be
computed in double precision or extended precision. Different
machines (or different compilers, or even different compiler flags)
may use different precision, and get different results.
Example: producing 108 units at one work per unit, sector p.e. 0.4
needs to charge 108 / 0.4 work. Computed in double precision, this
gets rounded to 270.0, then truncated to 270. In 80 bit extended
precision, it gets rounded to 269.999999999, then truncated to 269.
With random rounding instead of truncation, the probability for a
different result is vanishingly small. However, this commit
introduces truncation in another place. It just happens not to mess
up the smoke test there. I doubt this is the last time this kind of
problem upsets the smoke test.
How qsort() sorts members that compare equal is unspecified. Can
upset the smoke test. Observed under FreeBSD 8.3.
Break ties in power by comparing country numbers. Countries equal in
power are now sorted by increasing country number.
Lots stay on the market until there's a bid and bidding time expires.
When the highest bidder changes, and less than five minutes of bidding
time are left, it gets extended by five minutes (since 4.0.7, actually
works since 4.0.9).
Normally, this ensures that the competition has at least five minutes
to react. Except when this is the first bid, bidding time may have
expired already. If it expired less than five minutes ago, the
competition still gets time to react, just less than it should. If it
expired earlier, the sale is executed immediately for units. For
commodities, the bidding time is set to expire in five minutes (since
4.2.0).
Instead of extending bidding time by five minutes, set it to expire in
five minutes, both for commodities and for units.
check_trade() converts the price to float, which can lose precision,
although only for ridiculously high prices. Has been broken since
4.0.0 introduced the market.
Avoid the conversion. Bulletins now show pre-tax price as $N instead
of $N.00.
Code dealing with money mixes int and long pretty haphazardly.
Harmless, because practical amounts of money fit into int on any
machine capable of running the server. Clean up anyway.
Code dealing with reserves mixes int and long pretty haphazardly.
Harmless, because practical reserves fit easily on any machine capable
of running the server. Clean up anyway.
Code dealing with counting people mixes int and long pretty
haphazardly. Harmless, because practical populations fit into int
easily on any machine capable of running the server. Clean up anyway.
Newly built ships and land units are given to the player, planes and
nukes to the sector owner. Matters only for deities, because only
deities can build in foreign sectors. Stupid all the same.
This has always been inconsistent. Empire 1 gave ships and nukes to
the player, and planes to the sector owner. Chainsaw 3 added land
units, and gave them to the player. Empire 2 changed build to give
nukes to the sector owner.
Building doesn't work when the unit built is given to POGO, because
giving a unit to POGO destroys it. When build gives to the sector
owner, deities can't build in unowned sectors. When build gives to
the player, POGO can't build at all. That's more limiting, so change
build to always give to the sector owner.
setsector() and setres() continue after check_sect_ok() fails.
Clobbers the updates that made check_sect_ok() fail, triggering a
seqno mismatch oops.
Commit 04a332a8 (v4.3.27) claimed to fix this, but actually only
suppressed the generation oops.
give() continues after check_sect_ok() fails. Clobbers the updates
that made check_sect_ok() fail, triggering a seqno mismatch oops.
Commit b58c37e2 (v4.3.27) claimed to fix this, but actually only
suppressed the generation oops.
When the deity sets the number of mines with setsector, the sector
owner (if any) is told the resulting number of mines. Even for
occupied sectors, where mines belong to the old owner, and thus
shouldn't be disclosed. Oops.
Fix setsector not to tell the sector owner anything then.
Capital takes a <SECTS> argument, and picks the first suitable sector
it finds there. It fails if none can be found, or if the first one
found already is the capital (even when more suitable sectors follow).
Has always worked that way, but never documented.
I don't think the search feature is really useful, and documenting it
isn't worth my while. Change the command to take a <SECT> argument
instead, as documented.