Why upgrade? I'm not a lawyer, but here's my take on the differences
to version 2:
* Software patents: better protection against abuse of patents to
prevent users from exercising the rights under the GPL. I doubt
we'll get hit with a patent suit, but it's a good move just on
general principles.
* License compatibility: compatible with more free licenses, i.e. can
"steal" more free software for use in Empire. I don't expect to steal
much, but it's nice to have the option.
* Definition of "source code": modernization of some details for today's
networked world, to make it easier to distribute the software. Not
really relevant to us now, as we normally distribute full source code.
* Tivoization: this is about putting GPL-licensed software in hardware,
then make the hardware refuse to run modified software. "Neat" trick
to effectively deny its users their rights under the GPL. Abuse was
"pioneered" by TiVo (popular digital video recorders). GPLv3 forbids
it. Unlikely to become a problem for us.
* Internationalization: more careful wording, to harden the license
outside the US. The lawyers tell us it better be done that way.
* License violations: friendlier way to deal with license violations.
This has come out of past experience enforcing the GPL.
* Additional permissions: Probably not relevant to us.
Also include myself in the list of principal authors.
Commit 221e88f1 (v4.3.15) made caploss() expect the new owner in
sct_own, so it can distinguish between sack and obliteration. Commit
0d139ee1 (v4.3.17) broke that in sct_prewrite(): it moved zapping the
sector owner after caploss(), and passed 0 instead of the old owner to
caploss(). Because of that, obliterating a capital didn't make the
news and didn't cost the victim money. Fix that.
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.
It used literal 127 instead of sect_mob_max, it didn't check the lower
bound, and it didn't report the corruption. From Chainsaw 3.
Having *working* sanity checks there would be nice. Left for another
day.
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.
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.
Make caploss() transfer money, loans and market lots to the player
only if he actually took the capital, not if he obliterated it to
deity.
To make this work, caploss() needs to be called after the sector is
updated for damage and change of ownership. Change callers
accordingly.
Closes#914049.
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().
A bridge (span or tower) must be splashed when it gets damaged below
SCT_MINEFF. Likewise when its last supporting sector (bridge head or
tower) gets damaged below SCT_MINEFF, unless EASY_BRIDGES is enabled.
We need to check this whenever a bridge head, span or tower gets
damaged. This is done in three places, and all of them screw up:
* checksect() ignores damage to bridge heads. It also leaves writing
back the sector it checks to the caller, which never happens when
it's called from sct_postread().
Note that checksect() drowns all planes on bridges it splashes.
Functions that need to exempt flying planes from such a fate have to
splash bridges themselves.
* sect_damage() ignores damage to bridge towers, and damage to bridge
spans unless EASY_BRIDGES is enabled. It then runs checksect(),
which compensates for these omissions, but happily drowns the planes
sect_damage() attempts to protect.
* eff_bomb() ignores damage to bridge heads. Collateral damage makes
sect_damage() run, which compensates for the omission.
This causes the following bugs:
* Efficiency damage going through sect_damage() can drown planes it
shouldn't. This affects pinpoint bombing when collateral damage
splashes a bridge, and strategic bombing. The drowned planes then
crash and burn when they attempt to land at their (just splashed)
base.
* Efficiency damage to bridge heads not going through sect_damage()
fails to collapse unsupported bridges. This affects pin-bombing
efficiency without collateral damage, and ground combat. Also deity
commands edit, setsector and add, but that could be regarded as a
feature.
* If the sector file somehow ends up with an inefficient bridge span,
it collapses on every read again and again, until it collapses on a
write. Related problems exist with other actions of checksect(),
and they're not addressed here.
* If the sector file somehow ends up with adjacent inefficient bridge
towers, checksect() on any of them recurses infinitely:
- checksect() inefficient tower T1
- knockdown() T1, but don't write that back to the sector file
- bridgefall() T1; this reads all adjacent sectors, including
inefficient towert T2
- checksect() T2
- knockdown() T2, but don't write that back to the sector file
- bridgefall() T1; this reads adjacent sectors including T1
- checksect() T1
...
This commit creates a new function bridge_damaged() to splash any
bridges that became inefficient or unsupported after damage to a
sector. To avoid the inifinite recursion, we call it in
sct_prewrite() instead of checksect().
No uses knockdown() outside bridgefall.c remain, so give it internal
linkage.
other. Ensure headers in include/ can be included in any order
(except for econfig-spec.h, which is special). New header types.h to
help avoid inclusion cycles. Sort include directives. Remove some
superflous includes.
regardless of the option, but forced to sct_effic when disabled. This
screws up sct_defense when you disable DEFENSE_INFRA. Implement it
more like FALLOUT: use sct_defense if enabled, else sct_effic. The
change should be invisible except in xdump, which shows the real
sct_defense. Closes#804641.
(SCT_DEFENSE): New.
(dump, sinfra, sector_strength): Use it.
(eff_bomb, build_bridge, build_tower, new, buildeff, sect_damage)
(put_combat, checksect, produce_sect): Don't force sct_defense to
sct_effic when DEFENSE_INFRA is disabled.
agribusiness. That was done when the occupier abandons the old-owners
capital or it revolts, to prevent players from sacking the same
capital many timers. The server has a much better way to prevent that
since 4.2.7, so this weird hack is no longer useful. Thanks to Pat
Loney for pointing this out.
be skipped or stored in arrays of size I_MAX. I_NONE's int equivalent
becomes -1 by this patch, so all array indices of type i_type have been
checked not to use I_NONE as index. This change reduces the size of the
arrays stored in files.
NUK_BLD_WORK): New, to encapsulate the formula in one place.
(SCT_MINEFF): New. Use it instead of literal 20.
(buil): Use CANT_HAPPEN() for internal error.
(build_ship, build_land, build_bridge, build_nuke, build_plane,
build_tower): Simplify avail calculation.
(lupgr, supgr, pupgr): Charge 15% of total build avail instead of an
undocumented amount computed from build lcm and hcm.
(build_ship, build_land, build_bridge, build_nuke, build_plane,
build_tower, lupgr, supgr, pupgr): Fix reporting of required avail
when there's not enough. Closes#942823.
(lupgr, supgr, pupgr): Code printed cost rounded down, but required
and charged unrounded cost. Confusing. Round cost down, like the
build command. Closes#942811.
(UPGR_COST, UPGR_EFF, lupgr, supgr, pupgr): New UPGR_COST, UPGR_COST replace
literal values.
(show_bridge, show_tower): Don't claim bridge building requires
`workers' (whatever that is), since it doesn't.
To save space, the ancients invented `variables': a collection of
key-value pairs, missing means zero value, space for `enough' keys.
This complicates the code, as assigning to a `variable' can fail for
lack of space. Over time, `enough' increased, and for quite some time
now `variables' have been *wasting* space. This changeset replaces
them, except in struct mchrstr, struct lchrstr and struct pchrstr,
where they are read-only, and will be replaced later. It is only a
first step; further cleanup is required. To simplify and minimize
this necessarily huge changeset, the new item[] arrays have an unused
slot 0, and the old variable types V_CIVIL, ... are still defined, but
must have the same values as the item types I_CIVIL, ...