Commit 7ca4f412 (v4.3.12) marked planes flying a sortie with
PLN_LAUNCHED, and made pln_arm() reject planes with that flag set.
This was designed to reject escorts that were already flying as
bombers. It didn't work, because the test for PLN_LAUNCHED used a
stale copy of the plane created by pln_sel(). Fix by getting a fresh
copy.
The bug always existed, but the botched fix in commit 7ca4f412 made it
worse. Before, ac_encounter() dropped escorts that were also bombers,
so the bug merely wasted plane fuel. After, such planes were
effectively duplicated, and damage to one of them, usually the bomber,
was wiped out. Abusable.
The code wrote the swept sector after calling shp_check_one_mines().
This failed to use up the mine that hit the minesweeper, and triggered
a seqno mismatch oops.
The code wrote the minesweeper after calling shp_check_one_mines().
This used freed memory when the minesweeper got sunk there.
Broken in 4.0.17. Fix by moving both calls before
shp_check_one_mines().
ask_olist() let non-light land units board ships that can carry only
light units. If the board succeeds, the non-light unit move onto the
ship and then are stuck there.
Spies shot were only deduced from sector military; land units were
immune to losses; in fact they needn't have any military to spy.
Fix by requiring and using only sector military. Closes#758483.
Make spy() not skip sectors without civilians, military and land
units. There could be other interesting things to report there:
efficiency, gold bars, planes...
The values in these columns were computed by count_sect_units() and
count_sect_planes(), which included land units and planes in the count
that aren't shown by prunits() and prplanes(), namely own and embarked
units. Confusing. Moreover, count_sect_planes() and prunits() rolled
dice separately for spy units. This could leak the presence of spies
even when prunits() didn't show them.
All fixable, but not worth the trouble; just remove the counts.
perform_mission() needs to know whether it is targeting ships or
something else, because the rules differ: submarines interdict only
ships, land units get their damage reduced when interdicting ships,
and different news are generated.
The old code assumed it was targeting ships when the target sector was
sea. Wrong when interdicting ships in harbors, bridges and such.
This has always been broken. Except when checking a submarine's
target: there it tested argument s, which is gross, but at least it
works. That code was added in v4.0.8.
Replace the broken test by the gross hack everywhere. This fixes news
and damage from land units when ships get interdicted in non-sea
sectors.
Remove confusing columns Op-sect and Radius from table of available
missions. Add their code letters.
Fix efficiency required for artillery units to fire.
Firing damage reduction for range is a feature that was always there
and never really documented. Different ways to fire reduced damage
differently for range, or not at all. Fix that by dropping the
reduction everywhere.
The reduction happened randomly, with probability p = (d/m)^2, where d
is the distance to the target, and m is the maximum firing range. The
fire command printed "Wind deflects shells" when it happened.
The old fire command (before MULTIFIRE) either halved damage (50%
chance), or reduced it by a factor of 1-p.
MULTIFIRE's fire command halved damage. v4.0.2 reduced that loss to
10-20%.
Interdiction halved damage, but only when firing from ships.
Other ways to fire (support, return fire, interdiction from forts and
land units) did not reduce damage for range.
People can be delivered since v4.0.0 (the check that disabled that was
commented out), and cutoff shows these deliveries since v4.0.2. The
change was documented in info Empire4, but info pages weren't updated.
Do that, and remove the commented out code.
Commit 092a52f2 (v4.3.4) removed the code to estimate defense, because
the use of the estimate had been disabled since v4.0.0. This
accidentally removed the reporting of defending units, because
get_dlist() reported them when called for an estimate, and not when
called for real.
Fix by removing the unused estimate capability from get_dlist(). It
now reports defending units always.
Before s_commod() attempts to recursively supply a supply unit it
wants to use as supply source, it zaps the unit's load. When
actually_doit is false, it later restores the old load by overwriting
the change with a saved copy of the unit. That triggers a seqno
mismatch oops.
Avoid that by copying the new sequence number to the saved copy.
Change supply_commod() and try_supply_commod() not to call s_commod()
when zero units are wanted.
This isn't just for efficiency, it's also for limiting exposure to
supply bugs a bit.
This oopses on output dependency violations, e.g. two threads doing a
read-modify-write without synchronization, or the one thread nesting
several read-modify-writes. Such bugs are difficult to spot, and tend
to be abusable. I figure we have quite a few of them.
New struct emptypedstr member seqno. Make sure all members of unit
empobj_storage share it. Initialize it in files: main() and
file_sct_init(). Set it in ef_blank() and new ef_set_uid() by calling
new get_seqno(). Use ef_set_uid() when copying objects: swaps(),
doland(), doship(), doplane(), dounit(), delete_old_news(). Step it
in ef_write() by calling new new_seqno().
Factor do_read() out of fillcache() to make it available for
get_seqno().
Do that by making it use file.h instead of stdio.
This doesn't overwrite the sector file completely anymore, it just
sets sct_type, sct_newtype, sct_elev and sct_coastal. You really need
to run files first now.
Commit f33b96b1 (v4.3.12) made files again set timestamps. That was
intentionally suppressed in commit 990eb46b (v4.3.10), because it
facilitates attacks against the PRNG. Commit 8f98e53a (v4.3.0) had
added it as a feature.
Fix by making files's main() pass new flag EFF_NOTIME to ef_open().
Implement the flag in do_write().
do_write() sets the timestamp from a parameter. All callers pass
time(), and don't use that value themselves. Call time() in do_write
and remove the parameter.
Commit f33b96b1 made ef_flush(), ef_write() and ef_extend() update
timestamps automatically. Change ef_write() and ef_extend() to do
that even when table is privately mapped, by making do_write() cope
with privately mapped tables. Current users don't care, but it's a
saner interface.
Certain tables have a fixed size depending on configuration: EF_SECTOR
has WORLD_SZ() elements, EF_NATION, EF_MAP and EF_BMAP have MAXNOC
elements, and EF_REALM has MAXNOC * MAXNOR elements. Bad things
happen if the files backing them are shorter.
Pass expected size to ef_open(), and make it fail when the actual size
differs.
Commit 109dad1b (v4.3.5) promised to round victim fractions down, but
got it wrong for odd population when exactly half of it rounded down
could be fed. This could starve the last man on a boat or land unit.
Fix famine_victims().
The value of diffx() had the wrong sign when the arguments differed by
WORLD_X / 2. Same for diffy() and WORLD_Y / 2. satmap() used them to
find the vector from map center to ship or land unit to put on the
map, and got incorrect values for ships and land units directly
opposite to the center in x or y. The bug made satmap() read a
pointer out bounds of its malloced radbuf[], and then write through
that with unpredictable consequences.
Broken in 4.2.12. The original bug was in Empire 1.1: it
miscalculated where to put ships on the map (no crash). An incomplete
fix for radmap() and satmap() appeared in Chainsaw 2 (still no crash).
radmap() got fixed correctly in Chainsaw 3, but satmap() was
forgotten. That one got "fixed" in 4.2.7, and again in 4.2.12, but
both "fixes" were flawed and could crash.
Fix by backing out the flawed fixes and adopting the fix from radmap()
instead.