Commit graph

5435 commits

Author SHA1 Message Date
8e00a61812 client: Drop use of getpass()
getpass() is traditional Unix, but has been withdrawn from POSIX.  We
still use it when it's available, and fall back to portable code only
when it's not.

The portable code behaves differently: it reads stdin instead of
/dev/tty, and in noncanonical mode.

Simplify things: always use the replacement.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
54b1e7e167 client: Make get_password() not echo with POSIX && !HAVE_GETPASS
getpass() is traditional Unix, but has been withdrawn from POSIX.  We
provide a replacement in case it's missing.  The one for Windows
suppresses echo, like getpass() does.  Implement that for POSIX.  The
other differences to getpass() remain.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
691d0a27c1 client: Factor set_echo_if_tty() out of get_password()
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
c1f1344afe client: Move get_password() from login.c to getpass.c
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
f7ae50261f client: New get_password()
I'm going to drop use of getpass().  As a first step, weaken the bond
by hiding it in a separate function.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
2ae769bec4 client: Reorder misc.h, and point to the .c
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
37f2076a7d lwp: Simplify lwpSigWait() interface
lwpSigWait() was designed to resemble sigwait().  It doesn't anymore.
Drop the awkward argument, and use the return value instead.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
40cee426b7 lwp: Rename two variables for clarity
Rename LwpSigCaught to LwpPendingSig, and lwpCatchAwaitedSig() to
lwpHandleAwaitedSig().

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
2e4793408c lwp: Rewrite signal wait code for portability and safety
LWP's use of sigset_t is problematic.

To iterate over a sigset_t, it uses NSIG, which is not portable: BSD
and System V provide it, but it's not POSIX.

To record signals caught, it updates a sigset_t variable from a signal
handler.  The variable isn't volatile, because we'd have to cast away
volatile for sigaddset().

Replace sigset_t by an array of signal numbers terminated with 0.

Since lwpInitSigWait() needs to store the signal set for
lwpCatchAwaitedSig() anyway, there is no need to pass it to
lwpSigWait().  Drop its parameter.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
460cc9e2ee lwp: Fix signal wait screwup for multiple different signals
lwpSigWait() clears LwpSigCheck even when signals remain in
LwpSigCaught.  The next empth_wait_for_signal() will then wait until
another one gets caught.  Broken in commit fe2de3d74, v4.3.10.

Fix by clearing it only when LwpSigCaught is empty.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
aae823507c lwp: Fix handling of sigismember() failure
sigismember() fails when passed an invalid or unsupported signal
number.  lwpInitSigWait() and lwpGetSig() treat sigismember() failure
like "is a member".  lwpInitSigWait() will then sigaction()
unsuccessfully.  Harmless.  lwpGetSig() returns the bad signal number
when it's greater than any caught signal's number.  The bad signal
number then gets returned to main(), which shuts down the server.

Fix by treating failure like "is not a member".

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
f15bb68b63 lwp: Fix unsafe update of LwpSigCaught
lwpCatchAwaitedSig() is not reentrant.  lwpInitSigWait() attempts to
protect it by setting an appropriate signal mask, but screws up.  This
could conceivably lose signals.  Messed up when it got added in commit
7183516d9, v4.3.6.  Fix it.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
2c12238ecb lwp: Drop inappropriate oops in lwpSigWait()
lwpSigWait()'s contract specifies failure, which means oopsing is
wrong.  Harmless, as its only caller empth_wait_for_signal() oopses on
failure.  Drop it anyway.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
7b9e579408 info: Use S_ISREG() instead of S_IFREG for readability
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
566b9fdbbe info: Add #include <strings.h> for portability
We get strncasecmp() from <string.h>.  This is a BSDism; POSIX
provides it in <strings.h>.  Missed in commit 8fdd0259f2, v4.2.19.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
168db3b248 Make: Fix build with tool chains that require depcomp
Commit fad8e7f7b "Move auxiliary build tools to build-aux/" moved
depcomp, but neglected to adjust Make.mk.  This broke the build with
tool chains that actually use depcomp.  Modern GCC and Clang don't.
Fix the obvious way.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
10356f9ecf build-aux/git-version-gen: Refresh from Gnulib commit 4f78c231f4
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
53591e85d5 build-aux INSTALL: Refresh from automake 1.16.3
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
015b93b71c m4: Refresh macros from autoconf-archive commit fd1d25c148
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
f57c71da92 config: Enlarge configuration tables that have variable size
Configuration tables product, sect-chr, ship-chr, plane-chr, land-chr,
nuke-chr have a bit of extra space deities can use for customizing
their games.  Give them more: enlarge product from 23 to 31
entries (plus one sentinel), sect-chr from 39 to 63, ship-chr from 47
to 127, plane-chr from 47 to 127, land-chr from 31 to 127, and
nuke-chr from 20 to 63.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:08:03 +01:00
e7583a519e config: Slightly neater configuration table size macros
Macro SHP_TYPE_MAX is the largest possible ship type number.  It is
only used to size mchr[], and we need + 2 there.  Replace by MCHR_SZ
for simplicity.

Same for LND_TYPE_MAX, PLN_TYPE_MAX, P_MAX, and SCT_TYPE_MAX: replace
by LCHR_SZ, PLCHR_SZ, PCHR_SZ, and DCHR_SZ.

Same for N_MAXNUKE, except that one is more than the largest type
number.  Replace by NCHR_SZ.

For consistency, define ICHR_SZ and INTRCHR_SZ for sizing ichr[] and
intrchr_sz[].

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-23 07:07:58 +01:00
6bad464348 Avoid SCT_TYPE_MAX, use ARRAY_SIZE() instead
The next commit will get rid of SCT_TYPE_MAX.  Prepare.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:56:38 +01:00
d1b844c6eb New macro ARRAY_SIZE()
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:56:38 +01:00
c506cd7ed2 econfig: Fix documentation of key assault_penalty
Messed up when keys got documented in 4.2.0.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:56:38 +01:00
2e95ea6d80 info/Empire4.4: Fix more 4.4.0 change log entry typos
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:56:38 +01:00
90bb0f7fa3 fairland: Tidy up comments
Don't use ALL CAPS for headings.  Reformat them in the style
recommended by doc/coding.  Drop a few comments that aren't pulling
their weight, and fix the odd typo.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:56:38 +01:00
6babfefdb0 fairland: Rename fl_move() to drift_capital()
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:56:35 +01:00
82ed4c9d25 fairland: Move qprint() and NUMTRIES
qprint() was carelessly added at the end of the file in Empire 2,
where it's under the "Write a script for placing capitals" headline.
Move it to a more sensible place.

NUMTRIES was added behind the global variables in Empire 2.  Move it
before them, and reformat its comment.

The order of forward declarations of static functions looks random.
Reorder them to match the order of definitions.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:55:21 +01:00
8dab67c116 fairland: Fuse capx[], capy[] into cap[]
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:35 +01:00
ec9633b901 fairland: Fuse sectx[], secty[] into sect[]
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:35 +01:00
524c70659c fairland: Simplify how write_sect() iterates over sectors
Iterating over IDs is slightly simpler than iterating over
coordinates, so do that.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:35 +01:00
e59451f0d9 fairland: Represent sector ownership more efficiently
Replace own[x][y] by own[XYOFFSET(x, y)], and narrow the element type
from int to short.  Takes a fourth the space.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
6642878d5f fairland: Tweak rural iron, fert, oil for simplicity
The previous commit's interpolation tables reproduce the historical
linear functions faithfully.  This exact fit requires an awkward data
point in each of the tables for iron fertility and oil.  Drop them.

No double-valued data points remain.  Adjust struct resource_point
member @res to int.

This results in slightly less rural iron (33 elevations down one
point), fertility (10 elevations down one point) and oil (14
elevations down one point, 5 down two points).  Only resource values
less than 100 are affected.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
8c15a3fe32 fairland: Compute resources by interpolating tables
The functions mapping elevation to resources are piecewise linear.
Replace them by linear interpolation on data points defined in tables.
Tables are easier to tweak for deities than code.

The data points are a bit awkward because the functions they replace
are.  The next commit will tweak them to address that.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
b6b32f02be fairland: Tweak sea oil & mountain gold for simplicity
The functions mapping elevation to resources are piecewise linear,
except for set_oil(), which randomly adds 1 to sea oil, and
set_gold(), which is isn't linear for mountains, but very close.

Drop the random oil bit, and replace the non-liner gold function by a
linear one.  Both resources decrease at most by one point.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
6880908937 fairland: Rewrite complicated, buggy & boring elevation code
Land elevation is computed by first placing mountains, then elevating
land to fit.

Mountains placement is a weighted random sampling.  A sector's weight
is its distance to sea capped at five and squared.

Non-mountain, non-capital sectors get assigned equidistant elevations
from 1 up to 97 rounded to integer in an order that depends on
distance to mountain and distance to sea, both capped at 5.  Mountains
get equidistant elevations starting at 98 (see recent commit
"fairland: Fair mountain resources").  Capitals get 36.

Sea elevation is randomly chosen from a range that depends on the
sector's distance to land.  The range increases from [-27,-1] next to
land to [-127,-1] for distance 5 and up.

Without mountains, the result is boring: elevation increases pretty
much linearly with the distance from the coast, i.e. each islands is a
single cone.  With mountains, we get one cone per mountain.  The sea
sea elevations are basically noise.

Worse, it's buggy: mountain placement can place fewer mountains than
requested.  The weighted random sampling assigns weights even to
sectors that cannot be picked (capitals and sectors that have been
picked already).  When the dice land on such a sector, it instead
picks the next one (in island growth order) that can be picked.  If
there is no next one, the mountain is not placed.  This is a fairness
issue.

Impact varies with fairland parameters.  For 60 sector islands with 5%
mountains, around one in 10000 islands is short one mountain in my
testing.  For 10 sector islands with 50% mountains, some 760 out of
10000 islands are short one sector, 80 short two, and five short
three.  The numbers get worse as spikiness increases.

Undocumented misfeature: the placement loop is limited to 1000
iterations, supposedly to catch a runaway loop.  Since the loop
iterates exactly once per mountain, all this accomplishes it limiting
mountains to 1000 per island.

When too few mountains are placed, the loop assigning elevations to
non-mountain, non-capital decrements elevations below 1.  Since
Chainsaw 3, such elevations then get mapped to 1, plastering over the
bug.  We get non-mountain sectors with elevation 1 instead of
mountains.

Rewrite as follows.

Use a simple random hill algorithm to assign raw elevations:
initialize elevation to zero, then randomly raise circular hills on
land / lower circular depressions at sea.  Their size and height
depends on the distance to the coast, capped at 3.  After a sufficient
number of iterations, the resulting terrain has a "natural" look.
This is elevate_prep().

elevate_land() then sorts non-capital sectors by raw elevation.  The
highest become mountains.  Sectors get assigned the same equidistant
elevations as before, just in raw elevation order.

elevate_sea() simply normalizes raw elevation to [-127,-1].

Elevations now show a nice undulating pattern independent of mountain
percentage.

Implementation detail: replace elev[x][y] by elev[XYOFFSET(x, y)], and
narrow the element type from int to short.  Takes a fourth the space.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
dd9bda62eb fairland: Tweak rural elevations for simplicity
elevate_land() computes the sequence of elevations 97, 97 - delta,
... in fixed point with a scaling factor of 100.  Switch to
floating-point, because it's simpler.  Elevations (and thus resources)
change slightly due to reduced rounding errors.

Note that we map elevations less than 1 to 1 both before and after the
patch.  Odd.  Turns out this mitigates a bug: mountain placement can
place fewer mountains than it should, and when that happens,
elevations go below 1 here.  The next commit will fix this.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
7ce7440a34 fairland: Drop unused elevation band for coastal mountains
Elevations 34 and 35 are reserved for coastal mountains.  When an
elevation computed for a non-mountain falls in that band, it's
adjusted to 36.

This is unnecessary since the previous commit; drop.  Test output
shows the dropped elevation adjustment.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
aed94594f1 fairland: Fair mountain resources
For fairness, fairland aims to make islands of the same size consist
of the exact same sectors, just individually arranged.

It fails to achieve its aim for mountains: their elevation is random,
34 or 35 for coastal mountains, and between 98 and 254 (two dice) for
non-coastal ones.  Elevation determines resources.  Mountains get 89
gold on average (between 80 and 93), except for coastal mountains,
which get none.  It didn't really matter until Empire 3 made mountains
produce gold dust.  Since then, it's unfair.

Set mountain elevation to 98 + i * delta, where i is the mountain
number (starting at zero), delta is (127 - 98) / max_mn, and max_mn is
the maximum number of mountains an island could have.  This puts the
highest mountains on the largest islands.

Non-coastal mountains have slightly less gold than before, coastal
mountains have much more.

Mountains can still be unfair, because fairland can screw up their
number.  To be fixed soon.

Avoid elevations 34 and 35 for non-mountain, non-capital sectors
doesn't make sense anymore.  The next commit will get rid of it.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
b3d564c8ae fairland: Use zero elevation for "not yet elevated"
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
72f88eefd8 fairland: Eliminate sectc[][], use adj_land[] instead
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
fb2bd2408e fairland: Replace distance_to_land(), distance_to_sea()
distance_to_land() searches for closest land sector, and
distance_to_sea() for the closest sea sector.  We already have a more
efficient alternative: the breadth-first search recently added for
spheres of influence can precompute these distances.  Put it to use,
and retire distance_to_land() and distance_to_sea().

distance_to_what() could now be simplified.  Don't bother, because
it'll soon be deleted entirely.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
7f1bbcad94 fairland: Eliminate macro ELEV, it's an abomination
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
fd164c5860 fairland: Prefer placing islands away from the edge of the sphere
When an island gets placed too close to the edge of the sphere of
influence, its side facing the edge will likely be formed by the edge.
Looks unnatural, and can give a clue on the location of the other
continent.

Make place_island() prefer sectors away from the edge: instead of
picking one of the admissible sectors with equal probability, reduce
the probability as we get closer to the edge.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
56c014806e fairland: Try harder to deliver the requested amount of land
Planned island sizes are random with an expected value that matches
the average size requested by the user.  Can be off quite a bit when
the number of islands is small.  Also, actual island size can be
smaller than planned size when space is tight.

Instead of picking random island sizes independently, pick a random
split of their requested total size.

To reduce the probability of islands not growing to their planned
size, grow large islands before smaller ones.

To compensate for inability to grow, carry the difference over to the
next island size.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
696d31460c fairland: Make actual island sizes fair
The previous commit reduced the difference in island size within the
same batch of islands to at most one.  Eliminate the remaining
difference by shrinking the bigger islands by one sector.

This invalidates the precomputed exclusive zones, so recompute them.

fairland-test needs a tweak to avoid loss of test coverage.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
8d0c196c8b fairland: Grow islands interleaved
The previous commits changed grow_island() to create islands in
batches consisting of one island per continent, all of the same
planned size.  grow_island() still places and grows one island after
the other.  When an island can't grow to the actual size, the others
in the same batch are not affected.  Island size can therefore differ
a lot within the same batch.

Change grow_island() to interleave the work on a batch's island: first
place them all, then add one sector to each in turn.  Stop after all
reached the planned size, or one or more could not be grown further.

This is similar to how we grow continents: drift() places them all,
and grow_continent() adds one sector to each continent in turn.

Island size within the same batch can now differ at most by one
sector.  The next commit will eliminate that remaining difference.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
ae988c00ba fairland: Make planned island sizes fair
The previous two commits put the same number of islands closest to
each continent.  This one makes their planned sizes match: instead of
rolling dice separately for each island's size, we roll dice only for
the first continent's islands.  The other continent's islands get the
same sizes.

Actual island sizes still differ when islands can't be grown to their
planned size.  To be addressed next.

fairland-test needs a tweak to avoid loss of test coverage.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
00bfeb833e fairland: Fail when island can't be placed, for fairness
The previous commit made island distribution more fair by placing
islands close to a continent in turn.  This is still unfair when
fairland can't place all the islands.

Make grow_islands() fail when it can't place all islands, and main()
start over then, just like it does when grow_continents() fails.

Deities can no longer fill the world with islands by asking for a
impossibly high number of islands.  Tolerable loss, I think.

fairland-test needs a tweak to avoid loss of test coverage.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00
d434e0cc87 fairland: Distribute islands more fairly among continents
fairland places islands of random size in random places, subject to
minimum distances.  Results are often less than fair, in particular
when the number of islands per continent is low: some continents have
more land nearby than others.  Increasing distances between islands
doesn't help much.  Deities commonly run fairland until they find the
result acceptable.

The next few commits will tackle this issue.  As a first step, this
one places islands closest to continents in turn, so that each
continent is closest to the same number of islands.  A continent is
closest to an island when it is closest to each of its sectors.

The number of islands must be a multiple of the number of continents
now.

Since fairland may be unable to place all islands, a continent may
still get fewer islands than it should.  The next commit will address
that.

Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
2021-01-19 08:27:34 +01:00