Put the unit before recursing into its cargo. This breaks cycles in
the "is loaded on" relations. Such cycles exist only in a corrupt
game state. Mildly inefficient, because callers typically put the
unit again.
Planes and land units on ships are sold along with the ship, but trade
showed them only when SHOWPLANE was enabled. Show them always.
Planes on land units are not sold along with the land unit, but trade
showed them when SHOWPLANE was enabled. Don't.
Use new unit_wipe_orders() for violent takeover (takeover_unit() on
behalf of assault, attack, board, lboard, paradrop and pboard), and
peaceful takeover (unit_give_away() on behalf of arm, disarm, load,
unload, lload, lunload, scrap, scuttle, tend, trade).
Before, takeover_unit() cleared only group, mission and ship retreat
orders, and unit_give_away() only group and mission. Orders that
weren't cleared:
* Mission op area (visible in xdump)
* Ship autonav orders
* Ship sail path including ship to follow and mobility quota
* Plane range limit
* Land unit retreat orders and retreat percentage
Factor new takeover_unit() out of takeover_ship(), takeover_plane(),
takeover_land(). This fixes the following bugs in assault, attack,
board, lboard, paradrop and pboard:
* When the "land unit loaded on land unit" relation had a cycle,
takeover_land() went into an infinite recursion. Such cycles exist
only in a corrupt game state.
* Nukes armed on planes weren't taken over along with their plane.
Broken in commit 2e40a4bb, v4.3.3.
* Taking over land units with negative mobility increased mobility to
zero. Ditto planes embarked on ships or land units.
* Taking over planes embarked on ships or land units didn't clear
their wing.
* Taking over planes and land units updated their MOB_ACCESS timestamp
(pln_access, lnd_access), except for planes not embarked on
anything. This had no effect.
Trade code can't quite decide whether negative trd_unitid or zero
trd_owner marks unused slots. The former is a bad idea, because blank
slots have a zero trd_unitid.
Make sure to zero trd_owner when setting trd_unitid to negative value
in trad() and check_trade(). This fixes recognition of unused slots
in set (broken in commit e16e38df, v4.2.18) and xdump (never worked).
Use unit_drop_cargo() to drop a sold land unit's cargo.
Use unit_give_away() to transfer ownership. This fixes the following
bugs and misfeatures:
* Sold nuke wasn't taken off its plane. Could not happen before
commit 2e40a4bb, v4.3.3.
* Nuke on a plane wasn't sold along with the plane. Broken in commit
2e40a4bb, v4.3.3.
* Planes and land units on sold ships got their mobility zeroed.
* Planes on sold ships didn't get their wing reset.
Use unit_give_away() in gift(). This fixes a number of bugs:
* Nukes on planes weren't given away along with the plane.
* Likewise for land units on land units (can't happen in the stock
game).
* Mission was not cleared by unload land/plane, lunload land/plane,
and lload plane, except for planes on land units.
* Wing and army were never cleared.
It also happens to suppress information on planes given away along
with their land unit carriers. Shrug.
When giving away cargo by scrapping or scuttling its carrier, the
cargo's cargo wasn't given away. Happened for instance when a ship
carrying a land unit carrying a SAM got scrapped.
Also, wing, army and mission weren't cleared.
To fix, create unit_give_away() and use it in unit_drop_cargo().
Factor unit_drop_cargo() out of scra(), scuttle_ship(),
scuttle_land(), fix it up:
* Some messages were sent as bulletins instead of printing them.
* Nukes were always destroyed. They're now treated exactly like other
cargo.
* scuttle destroyed some cargo silently, and listed other cargo as
"scuttled". It now simply lets unit_update_cargo() running from
carrier prewrite callbacks list all cargo "lost".
Simplify its callers. scuttle_ship() and scuttle_land() are now
trivial, inline and remove.
When called from the scuttle command, scuttle_tradeship() asks for
confirmation when scuttling doesn't pay. When called from the autonav
code, it can't ask. Change it to fail then, and use that in
nav_ship() to avoid scuttle where it doesn't pay. Also simplify some.
Fix scuttle to ask for confirmation when scuttling a tradeship in an
unsuitable sector even when the tradeship is pirated. Broken when
commit a99bc3be (v4.2.13) suppressed that for pirated tradeships
wholesale because it let pirates ferret out where the ship was built.
You can now scrap ships in own or friendly, efficient harbors, planes
in own or allied, efficient airfields, and land units in any own or
allied sector.
When something can't be scrapped because of these rules, print a
suitable message.
Before, you could scrap ships regardless of relations to sector owner
(info claimed friendly was required), land units regardless of
relations, but not while on ships, and planes even in friendly
airfields (info claimed allied was required).
When scrapping in a deity sector, scrap claimed it gave the cargo to
POGO, which is somewhat bogus, as POGO can't own such stuff.
scra() and scut() printed their "scrapped in" / "scuttled in" message
in two parts. Messages for scrapped / scuttled cargo were printed
between the parts. Fix by printing in one go, after the cargo
messages.
Until commit 3e370da5, dead planes had to be explicitely taken off
their carrier to update load counters. This is no longer necessary;
simplify pln_put1() and scut(). scut() got it wrong, by the way: it
failed to take planes off land units.
EF_PLANE is closed before EF_LAND: if a land unit carries a plane, the
plane goes away before its carrier, and unit_onresize() oopses. Fix
by not checking cargo list consistency there when the file is already
gone.
unit_cargo_init() has a similar issue, at least theoretically: it
rebuilds cargo lists one after the other. Zap them all first.
Hackish work around for a race condition in the nightly build's
regression tests: sometimes the update starts right after the
force command yields, sometimes a bit later. If it is late, we
use one random number here, for the bye, and throwing off the
random sequence.
Treat zero owner just like efficiency below minimum. Before, cargo
was taken off carriers only when efficiency fell below minimum, not
when owner changed to zero.
Run item_prewrite() unconditionally, for simplicity.
Dynamically allocate the string space for thread
name in WIN32 (ntthread.c) thread space. This
makes the WIN32 more consistent with the other
environments. It also addresses WIN32 issue of
the print width of 17 being used and only having
space for 16 characters in the fixed allocation.
Change snxtitem_all() loops that skip everything but a carrier's cargo
to use snxtitem_cargo() in scra(), scuttle_ship(), scuttle_land(),
takeover_ship(), takeover_land(), trade_desc(), feed_ship().
The old code did not move a carrier's cargo (planes, land units,
nukes) when the carrier moved. Instead, it fixed up the location in
the postread callback. Anything not going through ef_read(), in
particular the update, saw it in its old, incorrect location, until a
fixed up copy got written back.
Moreover, the timestamp did not change when cargo moved, so
incremental dumps did not pick up the movement.
The new code moves the cargo along with the carrier.
New unit_update_cargo() moves or destroys a carrier's cargo (planes,
land units, nukes) along with the carrier. Call it from
shp_prewrite(), pln_prewrite() and lnd_prewrite() when the carrier
moves or gets destroyed.
Remove the code to destroy cargo from shp_prewrite(), pln_prewrite(),
lnd_prewrite().
Remove the code to fix up cargo location from pln_postread(),
lnd_postread(), nuk_postread().
This changes the message for ship and land unit cargo getting
destroyed from "sunk" and "MIA" to "lost".
New snxtitem_cargo() initializes an iterator for a cargo list, with
new enum ns_seltype member NS_GROUP and new struct nstr_item member
next. Extend nxtitem() and nxtitemp() to step through the list.
Members read were always set to ef_read, remove and call directly.
Member flag was only assigned to, never used, remove.
Change member group to char to match struct empobj.
The former ensures that next links are valid even for uids not on any
list. The latter oopses on adding an uid to a list when it is already
on a list, unless it is at the tail.
The WIN32 version did not block when the sleep was
already reached by the time empth_sleep() did the
time remaining calculation. The other versions
of empth_sleep() do always yield.
This ensures that no unplanned updates occur
during the nightly build sequence. Remove
unnecesary enables and disables from the script.
Remove unnecessary argument for force command.
This makes the journal easier to read, and makes journals
from the nightly build easier to diff.
Since we use only the 10 first characters of the name,
abridge existing thread names to make them unique within
that many characters.