Disable incorrect autmatic supply in load and lload
load_land_ship() and load_land_land() automatically resupply the land
units they load. This can draw supplies from the sector where the
land units are. When load() and lload() later update the sector, they
wipe out the update made for drawing supplies, and we get a seqno
mismatch oops. Highly abusable. Disable for now.
Make unit_give_away() immune to infinite recursion
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.
Wipe orders when ship, plane, land unit or nuke changes owner
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
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).
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 when scuttle_tradeship() asks for confirmation
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.
Fix scrap and scuttle output when there's output about cargo
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.
Ron Koenderink [Sat, 13 Sep 2008 23:33:24 +0000 (17:33 -0600)]
Do not update player's bank balance when the change is zero
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.
Ron Koenderink [Sat, 13 Sep 2008 21:18:29 +0000 (15:18 -0600)]
Allow any length thread names for WIN32
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.
Use new snxtitem_cargo() to simplify a couple of loops
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().
Rewrite the broken code to move cargo with its carrier
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".
Make the item iterator capable of iterating over a cargo list
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.
Zap next uid in clink_rem(), check it in clink_add()
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.
Ron Koenderink [Fri, 12 Sep 2008 01:06:10 +0000 (19:06 -0600)]
Ensure the empth_sleep() always yields for WIN32
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.
Ron Koenderink [Thu, 11 Sep 2008 20:58:32 +0000 (14:58 -0600)]
Use empty schedule file for the nightly build
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.
Instead of counting the load with lnd_nland() / lnd_nxlight(), check
whether there's at least one loaded with lnd_first_on_land() /
pln_first_on_land().
Load counters are redundant; they can be computed from the carrier
uids. Keeping them up-to-date as the carriers change is a pain, and
we never got that quite complete.
Computing load counters straight from the carrier uids every time we
need them would be rather inefficient, but computing them from cargo
lists is not. So do that.
Remove the load counters: struct shpstr members shp_nplane,
shp_nchoppers, shp_nxlight, shp_nland, and struct lndstr members
lnd_nxlight and lnd_nland.
Nothing left in fit_plane_off_ship(), fit_plane_off_land(), so remove
them.
load_land_ship(), load_land_land(), check_trade(), pln_newlanding(),
put_plane_on_ship(), take_plane_off_ship(), put_plane_on_land(),
take_plane_off_land() no longer change the carrier, so don't put it.
Remove functions to recompute the load counters from carrier uids:
count_units(), lnd_count_units(), count_planes(), count_land_planes(),
pln_fixup() and lnd_fixup(), along with the latter two's private
copies of fit_plane_on_ship() and fit_plane_on_land().
New cargo list functions to compute load counts: unit_cargo_count()
and unit_nplane(), with convenience wrappers shp_nplane(),
shp_nland(), lnd_nxlight(), lnd_nland().
Use them to make ship selectors nplane, nchoppers, nxlight, nland
virtual. They now reflect what is loaded, not how the load uses the
available slots. This makes a difference when x-light planes or
choppers use plane slots.
Use them to make land unit selectors nxlight and nland virtual.
Use them to get load counts in land(), ldump(), load_plane_ship(),
load_land_ship(), load_plane_land(), load_land_land(), sdump(), shi(),
tend_land(), fit_plane_on_land(), trade_desc(), unit_list().
Rewrite fit_plane_on_ship() and could_be_on_ship() to use
shp_nplane(). could_be_on_ship() now takes load count arguments, as
computed by shp_nplane(), so it can be used for checking against an
existing load as well.
Cargo lists storing lists of cargo for each carrier
Persistent game state encodes "who carries what" by storing the
carrier uid in the cargo. Cargo lists augment that: they store lists
of cargo for each carrier. They are not persistent.
New unit_cargo_init() to compute the cargo lists from game state.
Call it in ef_init_srv() and at the end of update_main().
New unit_onresize() to resize the cargo list data structure.
Installed as units' struct empfile callback onresize to make them
resize automatically with the unit files.
New unit_carrier_change() to update cargo lists when carriers change
in game state. Convenience wrappers pln_carrier_change(),
lnd_carrier_change() and nuk_carrier_change(). Call them from
prewrite callbacks to keep cargo lists in sync with game state.
To make that work, unused units must not point to a carrier. Add new
pln_oninit(), lnd_oninit() and nuk_oninit() take care of newly created
units. Change lnd_prewrite() and nuk_prewrite() to take dead land
units and nukes off their carrier. pln_prewrite() did that already.
New unit_cargo_first(), unit_cargo_next() to traverse cargo lists.
Convenience wrappers lnd_first_on_ship(), lnd_first_on_land(),
lnd_next_on_unit(), pln_first_on_ship(), pln_first_on_land(),
pln_next_on_unit() and nuk_on_plane(). The latter is disabled for now
because it clashes with an existing function.
Move selector code from src/lib/global to src/lib/common
Future virtual selectors will need to access game state. This depends
on common/file.c, which can't be used from global without creating a
cyclic dependency between libglobal.a and libcommon.a.
Move nsc.c to src/lib/common. file.c depends on it, so move it as
well, renamed to filetable.c so it doesn't clash with the existing
file.c.
Losses of sectors, ships, planes, land units and nukes are tracked in
the lost file. To keep it current, makelost() and makenotlost() were
called whenever one of these changed owners. Cumbersome and
error-prone. In fact, the lost file was never perfectly accurate.
Detect the ownership change in the prewrite callback and call
makelost() / makenotlost() from there. Remove lost file updates from
where they're no longer needed: right before a put. takeover() is a
bit more involved: it doesn't put the sectors, but all callers do,
except for guerrilla(). So remove the lost file update from
takeover(), but add it to guerrilla().
This takes care of lost file update for all ownership changes that go
through ef_write(). It can't take care of any missing updates for
changes that don't go through it.
Don't execute pre-write checks from sct_postread()
Chainsaw 3 factored out most checks from sct_prewrite() into
checksect(), and called that from sct_postread() as well. Revert
this, because it was a bad idea: whenever checksect() called from
ef_read() found something to change, it was actually a bug, and
changing it just hid the bug from whatever called ef_read(). But it
couldn't hide it from code going through ef_ptr(). So, instead of
having bugs visible everywhere, including census and such, they were
hidden in hard to observe places. For instance, the previous commit
fixed one that was visible to the path finder, but not the actual path
user, which led to the path user choking on an incorrect path in a
rather obscure manner.
Things no longer "corrected" on read: excessive mobility, low work
despite no civilians present, sector owned despite neither civilians,
military nor land units. The latter had a scary-looking caploss(),
but NF_SACKED should have rendered that harmless.
Don't revert sectors without military to old owner
Change checksect() not to abandon occupied sectors to the old owner
when there is no military and no land units. This effectively
restores pre-Chainsaw 3 behavior. Matching change to would_abandon().
Rationale. Traditional ways to change sector owner:
(1) Attack, assault, paradrop can transfer a sector to the attacker,
in take_def().
(2) Guerrilla warfare at the update can transfer a sector to the old
owner, in guerilla(). This happens when che kill all military and
the sector is sufficiently disloyal to the owner.
(3) Whenever all civilians, military and land units are removed from a
sector, no matter how, it silently reverts to the deity, in
checksect().
Chainsaw 3 added:
(4) Whenever all military and land units are removed from an occupied
sector, no matter how, it silently reverts to the old owner, in
checksect().
This addition isn't seamless. Funnies include:
* When che kill all military and land units, but the sector is loyal,
(3) doesn't transfer to the old owner. But since there's no
military and land units left, (4) transfers it anyway, only without
telling the lucky old owner. The latter transfer is buggy:
checksect() runs only on ef_read() and ef_write(), not the update
(bug#1010856), so the silent transfer is delayed until the next
ef_write(). But code using ef_read() sees it right away. For
instance, the path finder, which doesn't use ef_read(), can route a
path through a sector lost that way. The actual move, which does
use ef_read(), then chokes on that path.
* When you attack a sector, and get defeated with the help of reacting
land units, but succeed in killing the *local* defenders, (4) makes
the sector silently revert to the old owner. Which might be
somebody who wasn't involved in the fight, and gets no notification
whatsoever of his windfall.
* You can abandon a sector to the old-owner by removing all military
and land units from it, in a myriad of ways. Some ways ask you for
confirmation (move, march, load), many don't (navigate, plane
construction, delivery; arguably bugs), and others simply don't let
you (paradrop, fly, distribution).
This problem also exists for abandoning to deity, i.e. through (3)
instead of (4). Some ways to move out civilians don't let you do
that (distribute), but most do. However, accidentally abandoning an
empty sector to deity is less serious than a populated one to
another player.
In my opinion, (4) doesn't add much to the game, and fixing the
funnies isn't worth the effort.
Empire3's C_SYNC code added these to sct_prewrite(), shp_prewrite(),
pln_prewrite(), lnd_prewrite() and nuk_prewrite(). They weren't
removed when C_SYNC was ripped out in 4.0.0.
Really belongs there, because it manipulates empfile[].
New ef_open_view() to replace ef_init_view(). Make ef_close() cope
with views, and remove ef_fina_view(). Make ef_extend() and
ef_truncate() oops on views.
ef_elt_by_name(), xdprval_sym() and symval() checked whether a file
type T is a symbol table by comparing ef_cadef(T) to symbol_ca, even
though T may be EF_BAD. Before commit 50cfdcb5, ef_cadef(EF_BAD)
accessed empfile[] out of bounds, which could conceivably crash or
somehow happen to yield symbol_ca. Since then, it oopses and returns
null.
Fix by testing the file type before calling ef_cadef().
Xundump had special hackery to maintain configuration tables'
sentinels: xubody() and getobj() added a sentinel element when
initializing or growing a table, which xubody() stripped off again
before returning. The latter was an unclean hack.
Replace this by building knowledge of sentinels into struct empfile:
new flag EFF_SENTINEL, set for the appropriate members of empfile[],
obeyed by ef_extend() and ef_truncate().
Fix/improve logging in ef_close(), ef_extend(), ef_truncate()
Change ef_close() to log ep->file instead of ep->name, to match
ef_open().
Fix ef_extend() to log ep->name instead of ep->file, which could be
null. Also fix ef_ensure_space()'s function comment. Both broken in
commit 2eb8672b.
ef_truncate()'s error logging lacked detail when ef_realloc_cache()
failed, fix.
It became needlessly complicated in 4.0.1 to fix a "bug in mapdist not
taking world edges into account nicely enough." That "fix" had no
effect, which was good, because it wasn't broken.
Include destination in interception and plane mission messages
Interception and missions launch planes automatically. The plane
owner (and for missions, the base sector owner) gets a message.
Destination coordinates are often obvious from the context, but not
always, e.g. when flying in support of allies, or when the mission
gets interepted and aborts. Include the destination coordinates in
the messages. Reported by Ulrich Hannemann.
Fix client code for catching rogue redirections and executes
The client permits redirection and execute only if it recently saw
them in player input. The caching of recent player input for this
purpose was broken.
When save_input() evicted a line, it kept its newline. This could
make the recent_input ring buffer fill up, which then got redirections
and execute misdiagnosed as rogue.
save_input() also screwed up when evicting one line didn't make
sufficient room for the line to be saved. This could cause assertion
failure in forget_input().
Fix spy to reliably avoid spying same sector more than once
spy() stored coordinates of sectors successfully spied in an array.
Since it didn't bother to normalize coordinates, it could spy sectors
near the "seams" of the world more than once. The array was also
wastefully large.
Fix by using a sector bitmap instead, like do_look().
GCFx() and GCFy() pointlessly duplicate sctoff(), and don't work when
the argument is less than -WORLD_X or -WORLD_Y, respectively. With
current code, this happens only for impractically tiny worlds:
emp_setbitmap() writes to bitmap[] out of bounds, and smashes the
heap.
Fix move_ground() to pass coordinate arguments normalized
move_ground() passes curx, cury to various functions that should
probably be called with normalized coordinate arguments. Make sure
curx, cury are normalized.
launch_sat() failed to normalize the satellite's coordinates when it
added a random course deviation. Satellites with screwed up
coordinates were missed by skywatch, and possibly in other places.
Fix recently introduced memory corrupter in path()
path() failed to normalize coordinate argument for deltx() and
delty(). This could subscript map[] and mapbuf[] out of bounds.
Broken in commit 3ca88271.
Ron Koenderink [Sun, 24 Aug 2008 15:09:22 +0000 (09:09 -0600)]
Add server.log and journal.log to nightly build
Turn on journaling using journal.econfig.
Append the server.log and journal.log files
to the nightly build log in the SERVERSTOP step.
Remove the server.log and journal.log in the
SERVERSTART step to ensure only this run's log
events are included in the nightly build log.
Add the construction of a econfig in the
generate step using *.econfig in the patches
directory in a same way code patches are applied.
The mingw.patch was removed and replaced with the
mingw.econfig. The mingw.econfig also required
the addition of exports to the win32.i386.config.