Fighters, SAMs, ABMs and anti-sats could intercept, and tactical
missiles could interdict ships or land units.
Missed when the other missions were fixed in v4.2.7.
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.
No functional change, even though this changes rel[intruder] from
NEUTRAL to ALLIED. Uses of rel[]:
* getilists() and ac_encounter() compare rel[cn] to HOSTILE. No
change, because NEUTRAL and ALLIED are both greater than HOSTILE.
* ac_encounter() compares rel[cn] to ALLIED, but only when cn !=
plane_owner. Because it passes plane_owner as argument for
getilists() parameter intruder, rel[cn] can't refer to the changed
element of rel[] here.
The new value of rel[plane_owner] permits simplifying cn ==
plane_owner || rel[cn] == ALLIED to just rel[cn] == ALLIED.
Switching from getrel() to relations_with() can change the value from
NEUTRAL to ALLIED. The change doesn't matter when the value's only
compared to HOSTILE, as both old and new value are greater than
HOSTILE. Likewise for >= NEUTRAL.
If defenders get to shoot before bombs are dropped, they surely get to
shoot before time-consuming missions like sweep and sonar.
Sweep and sonar used to happen after air defense, but before flak and
interception. Air defense existed from Chainsaw 3 to v4.3.19.
The difference between the two is that PR() buffers partial lines, and
mpr() suppresses output to country#0. Doesn't matter when printing
complete lines to a country other than #0, e.g. the owner of a unit.
Don't tell him that it's his plane, he knows that.
Put a " -- " between "takes N%" and "aborted" / "shot down" for
ordinary flak as well, not just for flak vs. pinpoint bombing.
Since Empire 3 made option NEWPAF mandatory, checkabort is always
non-zero, and show implies checkabort != 1 and other == 0. Drop
unreachable code, and remove unused parameters checkabort and other.
Pass the more obviously correct plane_owner instead of player->cnum.
They're the same, actually.
When deities could still fly foreign planes (before commit 2023b47c),
they weren't. ac_encounter() updated the plane owner's in-memory
bmap, but wrote the current player's bmap to disk.
satdisp_sect() updated the in-memory bmap, but failed to write the
updates to disk. Its callers already update bmap from other sources,
so move this update there, and connect it to the existing write back.
The only user is reco(), so the restriction is fine. Several
functions called on behalf of mission_flags assumed it already:
plane_sweep(), sathead(), satdisp_sect(), satdisp_units(). Simplify
the rest accordingly: plane_sona() and ac_encounter() itself.
These were leftovers from Chainsaw, and their only remaining effect
was a flak bonus.
The got replaced except for flak by plane selector stealth under
Chainsaw option STEALTHV, which became mandatory in Empire 2. It is
unclear why STEALTHV didn't cover flak. No planes with these
capabilities have existed in the stock game since Empire 2.
pln_arm(), pln_equip(), mission_pln_arm() mission_pln_equip() took a
mission parameter encoding the kind of sortie (strategic bomb,
pinpoint bomb, transport, ...), a flag parameter to further specify
the plane's role, and a parameter ip to specify the load.
The flags argument was always either P_F (intercept), P_F | P_ESC
(escort), or zero (any other role).
With non-zero flags, mission and ip argument were not used in any way.
Use mission 'e' and null load for escorts, and remove flags.
Intercept can still be identified by mission zero.
Also change pln_mobcost() to take a mission parameter instead of
flags, so that pln_arm() and mission_pln_arm() can simply pass on
their mission.
4.0.9 changed flak not to use up shells, but they still had to be
present. Drop that, because it doesn't really provide any value.
Moreover, this gets rid of the buggy flak shell supply code (seqno
mismatch oopses, lost supplies).
The ancients designed interception dead simple: when you overfly a
sector, you get intercepted by the sector owner. Fine print
interception rules govern which planes intercept.
Then complexity got piled on top of it.
Chainsaw 2 added an extra interception by surface ship owners, in the
target sector only.
Chainsaw 3 added an extra interception by land unit owners, in the
target sector only (Empire 4 later merged this extra land unit
interception with the extra surface ship interception).
Chainsaw 3 added an entirely separate kind of interception: air
defense missions. When you enter a sector in some air defense op
area, you get intercepted. Fine print air defense rules govern which
planes intercept. These rules differ significantly from the
interception fine print.
Additional complexity comes from these facts:
* Air defense mission interception happens in addition to non-mission
interception. You can boost your total interception by setting up
air defense. Which means you must set it up, or forgo an advantage.
* Air defense planes are not available for non-mission interception
duty. You need to decide on a split.
* In contrast to non-mission interception, interceptors flying air
defense get intercepted.
Moreover, the air defense code breaks one of the plane code's design
assumptions, namely that just one plane sortie is active at a time.
The air defense sortie runs while the sortie it intercepts is in
progress. This leads to two interceptions being active at the same
time: the one intercepting the original sortie, and the one
intercepting the air defense sortie. The same plane can fly in both
interceptions, and damage received in the interception of the air
defense sortie is wiped out, triggering a seqno mismatch oops.
The previous commit already simplified non-mission interception: you
get intercepted by anyone who owns the sector, or a surface ship or a
land unit there, whether it's the target sector or not.
Now simplify mission interception, by merging air defense back into
ordinary interception: when you overfly a sector, you get intercepted
by anyone who owns the sector, or a surface ship or land unit there,
or has an air defense mission covering the sector. That's all. No
multiple interceptions, no separate air defense rules.
Remove air_defense(). Simplify ac_encounter() and sam_intercept()
accordingly; both lose their last parameter.
Change sam_intercept() and ac_intercept() to intercept in mission op
areas. New parameter only_mission to suppress non-mission
interception. Pass zero when the intercepting country owns the sector
or a surface ship or land unit in the sector.
ac_encounter() can't efficiently predict whether a country intercepts,
so it needs to call ac_intercept() unconditionally. This kills the
optimization to collect interceptors only when needed; simplify
accordingly, replacing getilist() by getilists().
In each sector, any country owning the sector, a surface ship or a
land unit gets to intercept.
Before, only the sector owner got to intercept, except for the target
sector. There, any country owning surface ships or land units got to
intercept in addition to the sector owner. Thus, a sector owner with
surface ships or land units there got to intercept twice.
Info Intercept claimed you get to intercept once for ships and once
again for land units, which was wrong since 4.0.9.
Info bomb suggested that flak fires only in the target sector, which
was wrong since 4.2.8. Drop that.
Sectors already spotted overflying planes in every sector along the
flight path, but ships and land units did that only in the target
sector, once if you got any ships there, in ac_encounter(), once if
you got any land units there, in ac_encounter(), once for ships firing
flak, in ac_shipflak(), and once for land units firing flak, in
ac_landflak(). Remove all that, and generalize ac_encounter()'s code
for sectors to spot planes to include ships and land units. Unlike
before, ships and land units don't spot allied planes.
Planes now spot ships and land units only when flying recon or sweep,
and along all of their flight path instead of just the target sector.
It still takes a spy plane to identify ships and land units.
Before, non-spy planes spotted ships and land units only in the target
sector, regardless of type of sortie, once for all ships and land
units, in ac_encounter(), once for ships firing flak, in
ac_shipflak(), and once for land units firing flak, in ac_landflak().
Remove all that.
Change ac_encounter() to start intercepting and running air defense
missions at the assembly point instead of the first sector entered
from there.
This also fixes a coding bug: when the flight path was empty, evaded
was used uninitialized when checking whether to intercept over the
target. The compiler even warned about that. Since the uninitialized
evaded typically read non-zero, interception triggered by ships and
land units didn't work. Abusable: if you managed to make your target
sector an assembly point, e.g. by placing an own or allied ship there,
you could bomb it without getting intercepted or taking flak.
A country's SAMs launched only in the first interception of a sortie.
That was because ac_intercept() made sam_intercept() delete all SAMs
from the list of available interceptors. sam_intercept() also deleted
any SAMs out of range. Don't do that, delete unused SAMs along with
other unused interceptors on return from ac_encounter().
Planes were not subject to air defense and flak over allied sectors.
Air defense was broken when Empire 2 changed it to happen after
spotting.
Flak was broken when 4.2.8 made ships and land units fire flak in
every sector, not just the target sector. Although an allied sector
doesn't fire flak, it may still contain hostile ships and land units.
Also makes use of ilist[] more robust: before, if relations somehow
went sour after unfriendly[] was initialized, the sector intercept
would run with an invalid interceptor list, and crash.
Chainsaw had missiles flying missions together with planes, and to
make that work, aircombat.c got code for coping with missiles. Since
Empire 2, missiles fly separately and don't go through aircombat.c
anymore. The missile code there has been useless for more than a
decade. Remove it.
This simplifies ac_encounter(), sam_intercept(), ac_intercept(),
ac_airtoair(), and gets rid of count_non_missiles(), all_missiles().
ac_encounter() passed MAXNOC instead of the sector owner to setcont(),
and setcont() does nothing for such an argument. Screwed up from the
start, in commit 144c7cb5, v4.2.22.
ac_encounter() lets all owners of ships and land units in the target
sector intercept, but not more than once.
Move the interception code behind reporting of both ships and land
units. Before, it was duplicated for ships and land units. Land
units didn't get reported when no bombers got through interception
triggered by ships.