Fix transfer of loans and market lots on sack of capital
Fix caploss() to transfer only signed loans. Before, it transferred
any loan with a non-zero duration, which included loan offers, and
could claim to tranfer nonexistent loans.
Fix caploss() not to claim transfer of nonexistant market lots when
country 0 sacks a capital.
Remove useless sanctuary break logic from designate
Don't call bsanct() when desi() is redesignating a sanctuary. It's
pointless, because only deities can redesignate sanctuaries, and
bsanct() does nothing for them.
Change fire to always fire guns when the target is beyond range
multifire() drops depth charges if the target is a submarine, else it
fires guns. It fails if the target is out of range. But players
could still find out whether the target is a sub then, because depth
charge shell use differs from gun fire shell use. This loophole
existed before 4.0.6, and was reopened by commit a3ad623b (v4.3.12).
Change multifire() to always use guns if the target is out of range.
While there, treat failure from shp_dchrg() and shp_fire() the same,
so that the player can't distinguish the two cases. Failure there
should not happen.
Commit a3ad623b (v4.3.12) made depth charging fail when there's just
one shell. This let players find all submarine uids. It basically
reopened the loophole closed in commit aa26c53e (v4.2.20).
Fix by making shp_dchrg() with just one shell succeed and return
damage like fire from one gun.
Fix fire command to detect when the firing object changes
multifire() failed to take into account that the firing firing sector,
ship or land unit can change while it is getting the target argument.
It thus clobbered any updates made to the firing object while it was
sleeping for the target argument. Abusable. Broken when Chainsaw
introduced MULTIFIRE.
Journal input of special cookies "ctld" and "aborted"
The latter is necessary to interpret the journal correctly. The
former isn't, as it should always lead to a logout straight away, but
treating it just the same is simple and doesn't hurt.
Behavior differs for the following scenario: if, while the thread
sleeps in io_input() called from recvclient(), at least one line of
input arrives and the thread gets awakened by the update aborting
commands, then the old code throws away the first line of input, but
the new code doesn't.
Commit 7ca4f412 fixed tracking of planes flying a sortie by marking
them with flag PLN_LAUNCHED. It failed to write SAMs and planes
flying missions back to the plane file, in sam_intercept() and
mission_pln_arm(). The only known problem with that is fairly
harmless: when the mission damages planes on the ground, the planes
flying it get damaged as if they were still sitting in their bases,
but the damage gets wiped out when they land.
The same issue applies to missiles. So they need to be tracked as
well. Do that in msl_hit().
While there, remove a few redundant PLN_LAUNCHED sanity checks.
When fixing planes stuck in the air, we fixed them only in memory, so
when a fixed plane wasn't written to disk for other reasons before the
next game start, it had to be fixed again.
Change pln_zap_transient_flags() to write them out.
These *are* called while player->aborted. Could be avoided, but: the
reason for not wanting to prompt then is to have each prompt consume a
line of input. That's actually not feasible, because when we wait for
an argument (after prompting for it) when the update aborts commands,
we can't consume the argument we prompted for.
Checking l_ammo before lnd_dam() oopses when something attempts to
fire from a land unit type that can't fire (l_dam == 0) and uses no
ammo. Such usage is perfectly fine. Move the check to the correct
place.
Change oops() to call the new oops_handler function pointer instead of
offering a fixed set of actions. Change server's main() to install a
handler for the action requested by -E.
Some losing implementations of strptime() such as FreeBSD's happily
succeed when they fully consumed the first argument, regardless of
whether they matched the full second argument or not. This causes
lines without directives to be interpreted as "next Sunday".
babies() rounded the maximum number of babies permitted by food. When
this rounded up, grow_people() could use more food than available, and
the sector's food could become negative. Fix by always rounding down.
Ron Koenderink [Fri, 28 Mar 2008 02:07:11 +0000 (20:07 -0600)]
Add missing thread yield system call.
This change fixes a bug where the threads were not treated
fairly. Before the fix, empth_yield would only yield to
threads already waiting hThreadMutex mutex. It would not
yield to other threads ready to run from the release of other
mutexes. An example of this is that the update task did
not start when force command was issued from script sequence.
Pass struct natstr * instead of natid to virtual selectors
This is because we want to define them in src/lib/global/, and code
there can't use getnatp(), because that requires
src/lib/common/file.c. Which renders a cnum parameter pretty useless.
Virtual selectors requiring code from common/ could well come up again
in the future, but let's not worry about that now.
Replace laun()'s base checking code by pln_airbase_ok()
This outlaws launch from unowned sectors. Also, non-VTOL missiles
require an efficient airfield now, except that such missiles don't
exist currently, because init_plchr() makes all missiles VTOL.
Fix launch to require petrol for launching satellites
launch_sat() failed to call msl_equip(). Change msl_equip() to take
the mission character as argument, because the old hardcoded 'p' isn't
appropriate for satellites. Best fit for satellites is 'r' for
reconnaissance, but mission_pln_equip() doesn't accept that
(pln_equip() does). Fix that as well.
Use XYOFFSET() instead of sctoff() in sector iterators
Old code didn't check value of sctoff() for success. But it can't
fail, because we already took care of the condition that can make it
fail. Moreover, the arguments are already normalized. Therefore, we
can just call XYOFFSET().
The code to find a suitable sanctuary location is flawed: to find
space and resources around the location, it does a depth-first search
limited to 300 sectors. Pretty useless when the limit is reached. A
breadth-first search would work, but why bother? This feature is
obscure and rarely (if ever) used: no conscientious deity would use it
for a real game, and for blitzes fairland does a better job. Remove
it.
reco() uses 'r' for reconnaissance. sam_intercept() and
ac_intercept() use 0 for intercept. Switch air_defense() to use 0 as
well. No functional change, because 'r' and 0 behave the same, just
cleanup.
Planes normally sit in their base (sector or carrier), where they can
be spied, damaged, captured, loaded, unloaded, upgraded and so forth.
All this must not be possible while they fly. There are two kinds of
flying planes: satellites in orbit, and planes flying a sortie.
Satellites in orbit have always been marked with flag PLN_LAUNCHED.
Works. What didn't work was tracking planes flying a sortie.
If you look at one sortie in isolation, up to three groups of planes
can be flying at any point of time: the primary group, which carries
out the sortie's mission (bomb, transport, ...), their escorts, and a
group of hostile planes flying interception or air defense.
The old code attempted to track these planes by passing those groups
to the places that need to know whether a plane is flying. This was
complex and incomplete, and broke down completely for the pin-bombing
command.
It was complex, because the plane code needs to keep track of all the
call chains that can lead to a place that needs to know whether a
plane flies, and pass the groups down the call chains. This leads to
a rather ugly passing of plane groups all over the place.
It was incomplete, because it generally failed to pass the escorts.
And the whole scheme broke down for the pin-bombing command. That's
because pin-bombing asks the player for targets while his planes are
loitering above the target sector. This yields the processor and lets
other code run. Which does not get the flying planes passed.
The new code marks planes and SAMs (but not other missiles) flying a
sortie with flag PLN_LAUNCHED (the previous commit laid the groundwork
for that), and does away with passing around groups of flying planes.
This fixes the following bugs:
* Many commands could interact with foreign planes flying for a
pin-bombing command as if they were sitting in their base. This
includes spying, damaging, capturing, loading, or upgrading them,
and even getting intercepted by them. Any changes to those planes
were wiped out when they landed. Abusable.
* The bomb command could bomb its own escorts, directly (pin-bomb
planes) or through collateral damage, strategic sector damage,
collapsing bridges or nuke damage. The damage to the escorts was
wiped out when they landed.
* If you asked for a plane to fly both in the primary group and the
escort group, you got charged fuel for two sorties instead of one.
* pln_put1() and pln_put() now recognize planes that didn't take off,
and refrain from making them land. Intercept (since commit c64e2149) and air defense can do that. Making them land had no
ill-effects, but it was still wrong.
There's one new problem: if PLN_LAUNCHED doesn't get reset properly,
due to game crash during flight or some other bug, the plane gets
stuck in the air. Catch and fix that on game start in ef_verify().
Distinguish between planes "in orbit" and "launched"
Use new pln_is_in_orbit() when we want to test for orbit specifically,
and test PLN_LAUNCHED when we want to test whether the plane not
sitting in the sector (because it is flying). This distinction is
pointless at this time, because the only way PLN_LAUNCHED gets set is
when a satellite goes into orbit. It will become useful in a later
commit, which will use PLN_LAUNCHED to mark flying planes.
Factor out a single plane's end of sortie into new pln_put1()
Use it in pln_put() and ac_planedamage().
This changes ac_planedamage() to deal with a destroyed airbase.
Before, aborted planes happily landed there. This bug could not
actually bite, because the code neither yields nor does damage to
potential airbases between checking the landing airbase before takeoff
and aborting planes in ac_planedamage().
It changes pln_put() to cope with dead planes. Before, it made them
land as if they lived, fortunately without ill effects (complaints
about not being able to land were suppressed for dead planes).
ac_planedamage() removes dead planes, but pinflak_planedamage()
doesn't, and these end up in pln_put(). pinflak_planedamage() no
longer has to take shot down planes off their carriers, because
pln_put() now takes care of that.
Interception builds lists of planes that could intercept. Only list
nodes for missiles were freed. Broken since BSD Empire 1.1.
The fix frees interceptors that actually intercepted when
ac_intercept() returns, and the interceptors that didn't when
ac_encounter() returns.
The latter introduces a small bug: it passes planes that didn't fly to
pln_put(). pln_put() expects only planes that actually took off.
Same bug exists in air defense missions. Luckily, it has no ill
effects. To be fixed soon.