damage: Shield embarked planes and land units from sector damage Damage to a ship or land unit, say via pinpoint bombing, doesn't damage loaded planes and land units. Damage to a sector, say via strategic bombing, doesn't damage ships there, but it does damage planes, even when loaded on a land unit (but not when loaded on a ship), and land units, even when loaded on a land unit or a ship. This makes no sense. Sector damage spills over to land units that way since Chainsaw 3 added them, and to planes since 4.0.9. Change sectdamage() not to damage land units and planes loaded on ships or land units. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
edit: Fix fortification limit of embarked planes and land units We generally preserve the invariant "land units and missiles loaded on a land unit or ship are never fortified / hardened": fortify and harden refuse to touch embarked land units and missiles, load and lload zap land unit fortification on load, and refuse to load hardened missiles. The exception is edit, which happily fortifies embarked land units (edit u key 'F'), hardens embarked missiles (edit p key 'F'), loads fortified land units (edit u keys 'S' and 'Y') and hardened planes (edit p keys 's' and 'y'). Fix the first two by correcting the new value's upper limit to zero for embarked land units and planes. The next commit will take care of the rest. The fix is visible in tests where test setup fortifies land units with "edit u * F ?..." without excepting embarked ones. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
relations: Move relations state from struct natstr to relatstr Relations state is relatively bulky: it's a big chunk of struct natstr, and adds 200 bytes per country to xdump nat. Relations change rarely. Rewriting it to disk on every nation update and retransmitting it in every xdump nat is wasteful. To avoid this waste, move relations state to its own struct relatstr. This is of course an xdump compatibility break. We're not maintaining xdump compatibility in this release. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
reject: Move reject state from struct natstr to rejectstr Reject state is relatively bulky: it's a big chunk of struct natstr, and adds almost 200 bytes per country to xdump nat. Reject state changes rarely. Rewriting it to disk on every nation update and retransmitting it in every xdump nat is wasteful. To avoid this waste, move reject state to its own struct rejectstr. This is of course an xdump compatibility break. We're not maintaining xdump compatibility in this release. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
contact: Move contact state from struct natstr to contactstr Contact state is relatively bulky: it's a big chunk of struct natstr, and adds almost 200 bytes per country to xdump nat for deities. Contact changes rarely. Since we avoid unnecessary updates, it doesn't change at all unless option HIDDEN is enabled. Rewriting it to disk on every nation update and retransmitting it in every deity xdump nat is wasteful. To avoid this waste, move contact state to its own struct contactstr. This is of course an xdump compatibility break. We're not maintaining xdump compatibility in this release. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
contact: Initialize contact state properly A country must always be in contact of itself when option HIDDEN is enabled. The code ensures this by establishing contact whenever a player logs in, in init_nats(). This is not the proper place. Game state should be initialized in empfile's oninit() callback, in this case nat_oninit(). Do that, and drop the putcontact() from init_nats(). Note that option LOSE_CONTACT only affects contact to other countries: agecontact() doesn't age the country's contact to itself. Use the opportunity to initialize contact so that getcontact() works even when HIDDEN is disabled. Just cleanup, it isn't actually called then. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
sect: Keep work percentage without civilians at 100% We maintain a few sector invariants in sct_prewrite(). Since the update bypasses sct_prewrite(), it needs to maintain them itself. The two should be consistent. sct_prewrite() resets work percentage of owned sectors to 100% when there are no civilians. The update's populace() resets it for unowned sectors as well, if they have military. Change sct_prewrite() to reset sct_work = 100 regardless of owner. Also change sct_oninit() to initialize sct_work = 100, so it doesn't change on first write. Update tests/smoke/fairland.xdump for the same reason. The massive test output differences are all due to sct_work. Inconsistencies with the update remain. They will be fixed next. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
torpedo fire: Reveal sub hit by return fire or depth charge This partly reverts a change made in Empire 2.3 to tell a submarine's opponent only that he's dealing with a "sub" instead of the submarine's UID and type. Hiding submarines is done by prsub(). Uses: * Command torpedo: defender depth charges or torpedoes an attacking submarine If you can attack a submarine reactively, you should be able to attack it actively, too. But that requires its UID. Reveal it again, but keep the type hidden. * Command fire: defender fires back at a submarine using its deck gun Submarines need to surface to fire deck guns, so they shouldn't be treated any different than surface ships. Revert Empire 2.3's change entirely there, i.e. defender learns type as well as UID. * Command torpedo: attacking submarine hits its target Keep the submarine hidden. * Commands torpedo and fire: attacking ship hits a submarine The attacker passed the UID as command argument, so it doesn't matter whether we print it or not. Printing it is simpler to code, so do that. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
retreat: Fix group retreat after failed board sinks ship Group retreat still doesn't work, because when boar() passes a sunk ship to retreat_ship(), its owner has been reset to POGO already. This makes it impossible to find the group to retreat. Instead, it attempts to retreat ships that sank in the same sector with group retreat orders and with the same fleet letter assigned. If any exist, shp_may_nav() oopses, and prevents actual retreat of these ghosts. The other retreat conditions don't have this problem, because they call putship(), which resets the owner, only after retreat_ship(). Making boar() work the same is not practical. Instead, add an owner parameter to retreat_ship(), and for symmetry also to retreat_land(). Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Revert "retreat: Oops on retreating ghosts" This reverts commit c3a839934f159b72b510cecb45c8c396efb38119. The commit message's claim that the code never actually retreats ghosts is wrong: boar() does. Signed-off-by: Markus Armbruster <armbru@pond.sub.org> Conflicts: src/lib/subs/retreat.c
board: Don't retreat ship#0 after failed board sinks ship The root cause is in put_combat(): after it sinks the ship, it calls att_get_combat(), which treats a combat object with a dead ship as an error, tells the attacker "not in the same sector!", and "recovers" by putting the combat object into an error state. Too hard for me to fix right now, so put in a FIXME comment. The error state trips up retreat. boar() uses the victim's ship number in the combat object to find the ship it may have to retreat. Putting the combat object into an error state sets this number to zero. If that ship exists, and isn't owned by the attacker, and has RET_BOARDED set, it retreats. Oops. Broken when Empire 2 factored out common combat code. Fix by saving the ship number while it's still valid. This uncovers the next bug: we now pass a dead ship to retreat_ship(). Oopses since commit f743f37. Its commit message says "Harmless, but avoid it anyway." Going to revert. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
tests/retreat: Cover retreat after failed board sinks victim Should trigger group retreat, but doesn't; marked "BUG:" in the test input. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>