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>
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 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>
New struct relatstr is basically empty so far. The next commit will
move relations state from struct natstr to struct relatstr.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
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>
New struct rejectstr is basically empty so far. The next commit will
move reject state from struct natstr to struct rejectstr.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
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>
New struct contactstr is basically empty so far. The next commit will
move contact state from struct natstr to struct contactstr.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
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>
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>
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>
The cost is meant to be proportional to efficiency / 100, but the code
truncates the fraction to zero. Broken in Empire 2.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
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>
This reverts commit c3a839934f.
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
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>
It's only printed for ships. Looks misplaced when it's followed by
"sunk" or other damage reports.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Instead of listing all the ships or land units ordered, just print how
many got ordered, and describe the order, like this:
[0:640] Command : retr 2/3 bg itb
2 ships ordered to retreat along path bg when injured, torpedoed, bombed
[0:640] Command : retr 2 h
1 ship ordered not to retreat
fleetadd doesn't list the ships it reassigns, either. On the other
hand, stop lists the sectors it stops. Perhaps it should be gagged,
too.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
It's redundant; retreat path 'h' cancels orders just fine. Document
that instead. 'c' still works, and I don't plan to break it as long
as it doesn't get in the way, which seems unlikely.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Optional arguments can save typing. Mandatory arguments are more
easily discoverable: just run the command and answer its prompts.
Empire traditionally uses optional arguments only for expert features.
Consider mission:
[0:640] Command : mission
Ship, plane or land unit (p,sh,la)? s
ship(s)? 0
Mission (int, sup, osup, dsup, esc, res, air, query, clear)? int
operations point? .
frg frigate Early Bird(#0) on an interdiction mission, centered on 21,-3, radius 0
1 ship
Compare retreat:
[0:638] Command : retreat
ship(s)? 0
shp# ship type x,y fl path as flt? flags
0 frg frigate 21,-3
1 ship
Arguments are not discoverable this way.
Change retreat to work like mission: make the second argument
mandatory, and if it's 'q', show retreat orders, else treat it as path
and ask for conditions:
[0:637] Command : retreat
ship(s)? 0
Retreat path, or q to query? jj
Retreat conditions ('?' to list available ones)? i
shp# ship type x,y fl path as flt? flags
0 frg frigate 21,-3 jj i
1 ship
To reduce smart client and script breakage, keep retreat with one
argument working as before, but print a deprecation warning.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Has no effect now. Before the recent rewrite of automatic retreat, it
could be used to trigger group retreat while staying put.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
"torped" comes from symbol table retreat_flags. Visible in output of
edit, retreat, lretreat and xdump. Tolerable in edit, but player
commands like retreat should really use proper words.
Fixing it in retreat_flags changes xdump output, thus risks breaking
clients. Do it anyway, since no known client recognizes this
particular symbol value.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Much of the retreat code duplicates navigate and march code. Worse,
retreat's version is full of bugs:
* Land units can sometimes retreat when they couldn't march: while on
the trading block (forbidden with march since 4.0.9), crewless
(likewise since 4.0.0), kidnapped in a foreign sector (inconsistent
since land units were added in Chainsaw 3), loaded on a ship
(likewise) or a land unit (inconsistent since trains were added in
4.0.0).
* Ships can retreat while on the trading block (forbidden with
navigate since 4.0.9)
* Land units can't retreat into foreign sectors even though they could
march there, namely when sector is allied or the land unit is a spy.
They can march there since 4.0.0.
* Land units keep their fortification on retreat. Has been that way
since retreat was added in Chainsaw.
Then there's group retreat. It's basically crazy:
* It triggers retreat for everyone in the same fleet or army, one
after the other, regardless of retreat path, conditions (including
group retreat), or even location. The latter is quite abusable
since retreats aren't interdicted. Has been that way since retreat
was added in Chainsaw.
* Group retreat fails to trigger when the originally retreating ship
or land unit has no retreat path left when it's done. Broken in
commit b860123.
Finally, the reporting to the owner is sub-par:
* When a retreat is cut short by insufficient mobility or
obstructions, its end sector isn't reported, leaving the player
guessing.
* Non-retreats can be confusingly reported as retreat to the same
sector. Can happen when the retreat path starts with 'h' (obscure
feature to suppress a single retreat), or when a group retreat
includes a ship or land unit without retreat orders.
* Interaction with mines during retreat is reported before the retreat
itself, which can be quite confusing.
* Sweeping landmines isn't reported at all.
* Much code and much bulletin text is dedicated to reporting what
caused the retreat, even though it should be perfectly obvious.
Rewrite this on top of common navigate and march code. Reuse of
common code fixes the "can retreat when it couldn't navigate/march"
and the "can't retreat into sectors it could navigate or march into"
bugs, and improves the reporting.
One special case isn't a bug fix but a rule change: mountains. The
old code forbids that explicitly, and it's clearly intentional, if
undocumented. The new code allows it by not doing anything special.
Turn group retreat into an actual group retreat: everyone in the same
fleet and sector with the the same retreat path and group retreat
condition joins the group. The group retreats together, just like in
navigate and march.
Take care to always report the end sector. When retreat is
impossible, report "can't retreat". When retreat is partial, report
"and stays in X,Y". When it's complete, report "stopped at X,Y".
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This reverts commit df8a1ffc1b.
Because it breaks group retreat. Trivial conflicts due to the removal
of option SAIL.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Conflicts:
src/lib/subs/retreat.c
tests/retreat/journal.log
This exposes more bugs. They're marked "BUG:" in the test input. A
few bugs get masked, but I'll unmask them again in the next commit.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
To reduce coupling between test cases.
Lucky dice expose another bug. It's marked "BUG:" in the test input.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
setup-POGO unintentionally gives dead ships, planes and land units
mobility, which makes them show up in final.xdump. Rearrange to avoid
that, and for clarity. While there, improve comments.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
It sets the new type, then falls through to setting tech if the new
type requires more than the plane currently has. Two problems with
that:
* If we fall through, the plane is invalid: it has less tech than
required. Its only use before it gets overwritten is pln_set_tech()
calling pln_range_max() to find out whether the range is limited.
Passes a negative number to log(). Not fatal, but pln_set_tech()'s
range adjustment is unlikely to work.
* If we don't fall through, the range may still need adjustment,
either up (to keep it unlimited if the new type has more range), or
down (to keep it within the new type's shorter range).
Screwed up when the key was added in commit 6b0b6f17. Fix by
adjusting tech first, then setting the type, then adjusting the range.
The latter relies on pln_set_tech() coping with ranges exceeding the
type's maximum, which it does.
Change the other type edits similarly for consistency.
When a type edit triggers a tech change, the tech change is now
silent.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
torp() applies torpedo damage after retreat. Wrong, because mobility
cost increases with damage. Broken since retreat was added in
Chainsaw.
Fix by applying damage before retreat. Bonus: bulletins make more
sense.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
SAIL has issues:
* Sail orders are executed at the update. Crafty players can use them
to get around the update window.
* The route is fixed at command time. You can't let the update find
the best route, like it does for distribution.
* The info pages documenting it amount to almost 100 non-blank lines
formatted. They claim you can follow friendly ships. This is
wrong. They also show incorrect follow syntax. Unlikely to be the
only errors.
* Few players use it. Makes it a nice hidey-hole for bugs. Here are
two nice ones:
- If follow's second argument is negative, the code attempts to
follow an uninitialized ship. Could well be a remote hole.
- If ship #1 follows #2 follows #3 follows #2, the update goes into
an infinite loop.
* It's more than 500 lines of rather crufty code nobody wants to
touch. Thanks to a big effort in Empire 2, it shares some code with
the navigation command. It still duplicates other navigation code.
The sharing complicates fixing the bugs demonstrated by
navi-march-test.
Reviewing, fixing and testing this mess isn't worth the opportunity
cost. Remove it instead. Drop commands follow, mquota, sail and
unsail. Drop ship selectors mquota, path, follow.
struct shpstr shrinks some more, on my system from 160 to 120 bytes.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
The autonavigation feature has issues:
* Autonavigation orders are executed at the update. Crafty players
can use them to get around the update window.
* Usability is poor:
- The order command is overly complex, not least because it can do
five different things: clear, suspend, resume, declare route, set
cargo levels.
- Unlike every other command involving movement, order does not let
you specify routes, only destination sectors.
- Setting cargo levels can silently swap start and end point of a
circular route, because "this keeps the load_it() procedure
happy". Maybe it does, but it surely keeps players confused.
- Setting "start" cargo levels actually sets the "end" levels, and
vice versa. Has always been broken that way.
- Predicting what exactly autonavigation will do at the update isn't
easy.
* The info pages documenting it amount to almost 400 non-blank lines
formatted. They claim only merchant ships can be given orders.
This is wrong. Unlikely to be the only error.
* Few players use it, and its workings at the update a fairly opaque.
Makes it a nice hidey-hole for bugs. Here are two:
- Unlike the scuttle command, autonavigation happily scuttles trade
ships while they're on the trading block.
- Unlike the load command, autonavigation can load in friendly and
allied sectors.
* It's more than 700 lines of rather crufty code nobody wants to
touch. Thanks to a big effort in Empire 2, it shares code with the
navigation command. It still duplicates load code. The sharing
complicates fixing the bugs demonstrated by navi-march-test.
Reviewing, fixing and testing this mess isn't worth the opportunity
cost. Remove it instead. Drop commands order, qorder and sorder.
Drop ship selectors xstart, xend, ystart, yend, cargostart, cargoend,
amtstart, amtend, autonav.
xdump ship sheds almost half its columns. struct shpstr shrinks, on
my system from 200 to 160 bytes.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
When a player moves more than 1023 sectors in a single navigate
command, we overrun the buffer holding the path taken. Remote hole,
but it requires a ship that can go that far, and even a ship with
speed 1000 would need a tech level well in excess of 1000 for that.
Thus, the hole is purely theoretical for even remotely sane game
configurations.
First known version with the flaw is 4.0.0.
Fix by going back the older behavior: don't print the total path
taken, but do print what the path finder does. Context diff of an
example:
[0:634] Command : nav 3 6,0
Flagship is od oil derrick (#3)
+Using path 'n'
h =
k . .
j d
<67.2:67.2: 6,0> h
od oil derrick (#3) stopped at 6,0
-Path taken: n
This is how march works.
Removes the only use of shp_nav_one_sector()'s unusual return value 2.
Return 1 instead.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Does not cover scattered navigate and march, RAILWAYS 0, enemy action
while sitting at the prompt, and interdiction.
The test exposes bugs. They're marked "BUG:" in the test input.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
Cuts size of export files in test suite by a factor of four. Not a
big deal for disk usage, as export files compress very well, and disk
space is cheap anyway. Export files are simply easier to work with
when they aren't full of redundant crap.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>