Fix ef_open()'s error message for file larger than static cache
The message claims the file is larger than it actually is. Broken
since commit 71908018 (v4.3.0) implemented static cache in ef_open().
Harmless, because no file-backed table has a statically allocated
cache.
Fix how empdump rejects attempt to split table sect
Split tables require the record index in the leftmost column.
defellipsis() correctly rejects "..." when the table doesn't have one.
It fails to reject it when it has one that is NSC_EXTRA, and thus not
permitted in a dump. This is the case for table sect. defellipsis()
happily succeeds, then chkflds() demands column "uid" if it's missing,
and rejects it if its present.
It missed those with more flags than just NSC_EXTRA set: table sect
name uid, table nat names passwd, xorg, yorg, contacts, rejects.
Since xundump() doesn't provide space for these, the bug could lead to
buffer overruns. Fixes flawed commit 726a8e3d, v4.3.12.
xubody() neglected to check ef_truncate()'s return value. Two failure
modes: invalid arguments, and ftruncate() failure. The former
shouldn't happen, and the latter can happen only for file-backed
tables, hence only in empdump -i.
Tables with a file name are: any game state, and any table that's
initialized from a .config file.
Tables that are no longer customizable: "updates" (customization had
no effect, because update_get_schedule() overwrote it), "table",
"meta" and the symbol tables (customization couldn't change them
anyway), and news-chr (customizing r_newsstory[] was kind of neat, but
unsafe because they are format strings for sprintf()).
"xdump updates" believes there are always 15 (UPDATE_TIME_LEN - 1)
scheduled updates. When fewer than 15 updates are scheduled, it shows
whatever crap update time happens to be in the unused part of
update_time[]: the initial zero or a previously scheduled update.
Root cause is that table EF_UPDATES has always UPDATE_TIME_LEN - 1
entries, which is incorrect when fewer updates are scheduled. Only
xdump is affected, as the other users ignore the length and stop at
the sentinel.
Fix update_get_schedule() to resize table EF_UPDATES.
Provide proper ca_table for carrier unit# selectors
Makes ef_verify() check carrier UIDs are sane. Partially protects
unit_cargo_init(), which oopses on bad carriers.
This has become possible only since commit 64a53c90 (v4.3.17) set
their values to -1 in newly created units. Before, they were zero in
units that had never been used, and a proper ca_table would have made
ef_verify() fail when unit#0 didn't exist.
The only unit# selectors left without a proper ca_table are ship's
follow, lost's id and trade's unitid. Document why.
Update examples in doc/xdump to current server's output
The NSC_CONST flags added in commit fa63f87b have always been missing
here. The previous commit changed xdump meta meta. Other than that,
it's just different encodings.
Refer to table names instead of C identifiers in .config
The C identifier permits looking up the table in the source. The
table name permits lookup with xdump.
Coders should know how to go from table name to C identifier. Deities
aren't all coders; we shouldn't ask them to guess table names from C
identifiers.
Don't ignore non-virtual NSC_EXTRA columns in ef_verify.c
These are commonly timestamps (no verification implemented), or
aliases for a non-extra column (which gets verified). Commit 49780e2c
(v4.3.12) added the exception: EF_SECTOR's uid. Proof by example that
ignoring these columns is wrong. Fix: ignore only virtual columns.
Simplify buil(): replace a switch by a function pointer
To enable that, make build_ship() & friends all take the same int type
argument instead of each one its own pointer. Passing pointers
triggered "may be used uninitialized" compiler warnings (the code was
safe despite the warnings).
Don't truncate research before multiplying with drnuke_const
For drnuke_const 0.33, research level 92.4 now suffices for a tech 280
nuke. Before, you needed 93, which was inconsistent with what
version's promise "need 0.33 times the tech level in research".
This was probably neglected when the techlists feature was added in
v4.0.0, because compiled-in nukes were sorted by tech, unlike ships,
planes and land units. Customization can break that.
Drop the bugs documented as fixed. File was last changed in Empire 2,
so these have been fixed for a while...
Remaining bugs:
The classification scheme used by report is dumb.
It still is.
You can make a sector temporarily useless by filling up all its
fields with delivery and distribution information. This is useful
when an enemy is trying to capture the sector (his mil don't have
room to move in :-) You have to halt some of the deliveries or
distributions to make room for the military to move in. (Mostly
fixed by changing the number of available fields)
Fixed since 4.2.14 eliminated `variables'. Delete.
Warehouses can't distribute all commodities simultaneously, due to
limited fields for this information. This becomes a problem if
you have a countrywide network of warehouses distributing to each
other. (Mostly fixed by changing the number of available fields)
Fixed since 4.2.14 eliminated `variables'. Delete.
You can sometimes move small quantities of certain items from
warehouses at no mobility cost, even into mountains (this is my
favorite bug, I'd hate to see it fixed :-)
Feature; delete.
Guerrillas don't seem to carry the plague.
They still don't.
You can sometimes trick someone into paying a huge price for
commodities by changing the price suddenly. Therefore one should
always check prices when buying commodities.
You can't increase prices anymore. Delete.
When two countries are attacking each other simultaneously, you
can sometimes move into a sector he is in the process of
attacking. If you get the timing right, he will take the sector
but you will get it back, along with all his military.
Can't reproduce; delete.
If a plane is out to trade, and gets shot down, it can still be
bought until the next update. If another country builds a new
plane that gets the number of the plane that was shot down, the
new plane will go on the trading market automatically. Then if
that plane is bought, the money goes to the country whose plane
was shot down, not the country that built the plane. I stole
numerous planes (including nuclear missiles :-) this way (by
deliberately putting low numbered planes up for trade, then having
them shot down).
Planes on a trading block can't get shot down, because they can't fly.
They can get destroyed on the ground, though. A new plane with the
same number still goes on the market automatically. Same for ships,
land units and nukes. check_trade() deletes a trade when the object's
owner changed. Reword the paragraph accordingly.
If a plane has negative mobility, then gets traded, mobility goes to 0.
Still correct.
Firing on sectors with land-locked sunken ships does strange
things.
Can't reproduce; delete.
If two countries are cooperating, its possible to raid an enemy
airport and steal the planes by putting them out to trade.
Still correct.
You can also strip enemy sectors of commodities using "sell", if
you have military control temporarily.
Requires mobility now. Delete.
One can make work go back to 100 everywhere in a country by moving
all civil- ians in low-work sectors onto a bridge, then collapsing
the bridge. Work then goes to 100 at the next update, if you
leave some mil in the vacated sectors. Or you can move mil out
too, letting the sector ownership change to the Deity, then move
back in from a 100% working sector, and work goes immediately to
100.
Feature; delete.
Two cooperative countries can move commodities around at no
mobility cost using the market.
Still correct.
You can collapse enemy bridges by making a lightning raid on his
bridgeheads and redesignating them, even if you only hold the
bridgehead for a short time. (In this games, bridges work
differently, see info build, info bridges")
Still correct. The parenthesis is cryptic, though; delete it.
You can map out enemy territory by raiding his radar stations.
Feature; delete.
Condition checking is very treacherous. Global commands with
conditions are unreliable. I never figured out exactly what was
wrong, although I think your method of putting conditions towards
the front of the line helped sometimes.
Can't reproduce; delete.
You can have more than 26 ships in a fleet, but only the first 26
will move when you navigate the fleet (I think 26 is the right
number, but I'm not cer- tain. It might be 32).
Can't reproduce; delete.
"Look" only spots subs (from destroyers) at a certain distance.
If you are too close you won't see them (unless you are in the
same sector).
Can't reproduce; delete.
You can only fly as many planes on a mission as you can fit on the
command line (so low numbered planes have an advantage this way).
USE WINGS
The real issue here is truncation of long input lines. Replace.
When a sector has a visible ship, radar doesn't show whether the
sector is land or sea, just the ship. This has interesting
possibilities for exploita- tion (like land-locking a battleship
in your capital in order to deceive the enemy :-)
Feature; delete.
I don't think you can land planes on a land-locked aircraft
carrier anymore.
Yes, you can. Is that good or bad? Anyway, delete.
Its common to mistakenly set the price of a plane or ship
incorrectly so one should check trade after using set.
Pilot error; delete.
The "must be accepted by" date on offered loans is bogus.
Why is it bogus? The date looks good to me. The offer expires at
that time. Delete.
buy() reads the lot, prompts for input, then writes back the lot,
triggering a generation oops. Any updates made by other threads while
buy() waits for input are wiped out, triggering a seqno mismatch oops.
Since commodities are taken from the seller when he puts them on the
market, and given to the buyer when the trade executes, the wiped out
lot's seller loses his goods without compensation, the other seller
gets to keep his goods, and the buyer receives their duplicates.
This can be abused by two conspiring countries to duplicate
commodities. The seller puts them on the market (say 100 gold bars).
The buyer starts a buy command, and waits at its last prompt for the
lot to be replaced. The seller takes them off the market (possible,
since there's no bid, yet), and sells something else (say one food)
quickly enough to get the same lot number assigned. The buyer then
completes the buy command. The seller loses one food, the buyer gains
100 gold bars.
Replaces a partial fix from v4.0.1, which only caught lots gone away,
not lots replaced by new ones.
Fix setsector and setres not to wipe out concurrent updates
setsector() reads the sector, prompts for input, then writes back the
sector, triggering a generation oops. Any updates made by other
threads while setsector() waits for input are wiped out, triggering a
seqno mismatch oops.
They can still get split by output arriving between two reads from
input, but that's unavoidable, because the client is designed to read
and write big chunks, not lines.
give() reads the sector, prompts for input, updates the sector and
writes it back, triggering a generation oops. Any updates made by
other threads during the yield are wiped out, triggering a seqno
mismatch oops.
Make generation numbers catch more potential yields on input
getstarg(), snxtitem() and snxtsct() can yield the processor, because
they call getstring(). But only for null or empty arguments. For
other arguments, we should call ef_make_stale(), to catch errors.
Problem: if a caller never passes null or empty arguments, it may rely
on these functions not yielding. We'd get false positives. In
general, we can't know whether that's the case. But we do know in the
common special case of player arguments. Call ef_make_stale() for
those.
Without ARG1, display_region_map() formats a rectangular area around
CURX,CURY, so it can use do_map(). Ugly, and duplicates some
unit_map() functionality.
Factor snxtsct_around() out of unit_map(). Inline do_map() into
display_region_map(), so we can use snxtsct_around().
Don't mess with player->condarg. Leftover from when we abused map()
here.
Split with parse() and pass first two arguments instead of the raw
tail to the map() callback. Advantages:
* Consistent with do_unit_move().
* Does the right thing when the tail is just spaces. Before, the
spaces got passed to the map() callback, which complained about
syntax. Now, they are ignored. This is what the commit I just
reverted tried to fix.
* Works better when the tail splits into more than two arguments.
Except for explore_map(), which ignores the argument(s), the map()
callbacks use display_region_map(), which split the tail at the
first space, and complained about any spaces in the second part.
Now, display_region_map() takes two argument strings instead of a
single, unsplit argument string, and extra arguments get silently
ignored, as usual.
parse_map_flags() silently truncates map flags after the first 't' or
'r'. This makes it accept arguments "true" and "revert". However, it
also breaks the perfectly sensible argument "ts", which should show
ships just like "st", but doesn't.
info bmap & friends document arguments "true" and "revert", and also
suggest flags 't' and 'r'. What a mess.
Make argument "revert" a special case. Deprecate flag 'r', and clean
up truncation there.
Don't truncate after flag 't'. If any bad flags follow, ignore
everything after 't', but deprecate that usage.
Drop useless checks for player->aborted in draw_map()
player->aborted gets set when we get an interrupt or EOF cookie from
the player, when update or shutdown abort commands, and when we abort
an attack (not relevant here).
The checks are useless: player interrupt and EOF are checked
elsewhere, and update/shutdown can run only when we yield the
processor, which we never do (output doesn't yield because C_MOD is
set).
It misuses snxtsct() and snxtitem() to find out whether the first
argument looks like sectors or like ships, which doesn't work with a
bad conditional argument.
Not worth fixing now; it's been disabled since 4.0.1, and broken at
least since commit 2fc1e74a (v4.3.0) broke its sector/ship
disambiguation via third argument.
Fix do_map()'s misuse of snxtsct() for testing argument syntax
It assumes snxtsct() fails only when the argument can't be parsed. It
can also fail when the condition argument has errors. `map # ?xxx'
first complains about xxx, then maps around ship#0. Broken since
Chainsaw 2 introduced smap, pmap and lmap.
Use sarg_type() to recognize sectors vs. unit argument. `map # ?xxx'
now fails as it should.
Subtle side effect: do_map() no longer prompts for argument "",
because snxtsct() is now guarded by sarg_type(). Impact on callers:
* display_region_map() is not affected, because it never passes "".
* map() passes on "" arguments. Change it to prompt in that case.
Consistent with how other commands behave. No functional change.
* do_unit_move() passes on "" arguments. Keep it that way. This
changes navigate and march sub-commands 'M' and 'B' not to prompt
for "" arguments, which is consistent with sub-command 'm' of move,
test and transport.