Compare commits

...
Sign in to create a new pull request.

54 commits

Author SHA1 Message Date
342ab5c22a Fix journalling of output ids 2008-08-02 09:04:16 -04:00
59bdc1cbcc Fix struct loststr / struct empobj mismatch corrupting lostitems
The initial parts of struct loststr and struct empobj must match.
Commit 49780e2c screwed that up for members lost_uid/uid, which also
broke the equivalence of lost_owner/own.  Since lost_uid is not used,
the former had no effect.  But the latter broke xdvisible().  Could
make xdump lost leak information.

Commit a680c811 reorderd struct loststr members to make lost_timestamp
equivalent to new struct empobj member timestamp, but failed due to
the bug in commit 49780e2c.  Commit f33b96b1 then set the timestamp
through empobj, which screwed up timestamps in lostitems, i.e. it
broke incremental xdump lost.

All of the above is in v4.3.12.

Commit 536ef0b0 (v4.3.15) added lost_seqno / seqno.  No effect,
because only seqno is used.
(cherry picked from commit eb252201b6)
2008-08-01 08:59:36 -04:00
321d6d74c7 Journal output lines instead of chunks
Output often arrives in chunks other than lines.  Hard to read in the
journal.  Delay journalling until we got a full line or our buffer is
exhausted.  This is less precise, but it'll do for now.
2008-07-30 08:26:34 -04:00
9398627ec4 New journal event output
To enable, set econfig key keep_journal to at least 2.  Output events
are *not* flushed to disk immediately.

Put it in Hvy Metal II now to gather real data for future testing of a
journal replay tool.
2008-07-29 20:38:48 -04:00
cb1c9f6a19 New journal event command
Redundant information, but makes the journal easier to read.  The
redundancy might help making a journal replay tool robust.

Put it in Hvy Metal II now to gather some real data.
2008-07-29 20:24:04 -04:00
a87f73a3b5 Use country number as journal thread ID when possible
Before, we used the value of empth_thread().  That can be mapped to
countries by tracking login and logout.  Easy for machines (except
when the journal is rotated while players are logged in), but tedious
for humans.

Quick version for Hvy Metal II.  Needs further work for the stock
code.
2008-07-29 07:32:36 -04:00
3afc1b1989 Fix interdiction to obey op-area for missiles
Never worked correctly.  Reported by Gregory E. Garland.
(cherry picked from commit 3eb58312b3)
2008-07-25 08:43:04 -04:00
b9b0710128 Fix treatment of EOF from player
Commit 79407e68 (v4.3.11) changed recvclient() to keep failing after
receiving EOF from player.  This was bad, because some places getting
input check player->aborted instead of recvclient() failure, and
player->aborted wasn't set on EOF.  Bugs caused by this:

* comm_bomb(), ship_bomb(), plane_bomb(), land_bomb() went into an
  infinite loop that eventually ate all memory.

* deli(), desi(), dist(), fly(), morale(), zdon(), att_prompt(),
  ask_move_in() interpreted EOF as empty input instead of no more
  input.

* cmd_sail_ship() dereferenced a null pointer.

Fix by setting player->aborted on EOF, too.
(cherry picked from commit b3a7a8ee11)
2008-07-15 06:37:05 -04:00
80b57b2f95 Simplify breaking of command loop
Change status() to check player->eof instead of io_error() and
io_eof().  Ignore value of command().
(cherry picked from commit 9c5854c8c9)
2008-07-15 06:33:45 -04:00
3c3912420b Change recvclient() to treat io_error() like io_eof()
This is for consistency with status() and player_login().
(cherry picked from commit b7153d095c)
2008-07-15 06:33:41 -04:00
18ae6c5f78 Oops when player thread keeps reading input unsuccessfully
Reading input fails after EOF and while the current command is
aborted.  Commands should detect that and fail.  If a command neglects
to do that in a loop, the loop can become infinite.  This is
especially bad after EOF, because then the client might not read
output anymore.  Output gets buffered until memory runs out.

Mitigate such bugs by counting how many calls have failed in a row,
oopsing on the 256th, and sleeping one minute from the 256th on.
(cherry picked from commit 49c24d7b78)
2008-07-13 08:07:53 -04:00
6aefeea2a1 Fix seqno mismatch in fly()
fly() reads the carrier, then passes it to pln_dropoff(), which writes
it back.  fly() also calls pln_oneway_to_carrier_ok(), which updates
the carrier when its plane summary information is incorrect.

The old code called it between reading the carrier and passing it to
pln_dropoff().  This made pln_dropoff() wipe out the plane summary
update, and triggered a seqno mismatch oops.  Broken by introduction
of pln_oneway_to_carrier_ok() in commit 1127762c, v4.2.17.

Fix by reading the carrier right before passing it to pln_dropoff().
(cherry picked from commit 42d9475d89)
2008-07-13 08:07:38 -04:00
1713f2d303 Don't fix up dead planes stuck in the air
Missile interdiction leaves behind used up missiles with the
PLN_LAUNCHED flag set.  This can lead to a bogus warning from
pln_zap_transient_flags() on server restart.

Change pln_zap_transient_flags() to ignore dead planes.
(cherry picked from commit 7a06a58bec)
2008-07-13 07:58:09 -04:00
84d40a6057 Fix flying commands not to let planes do double duty as escorts
Commit 7ca4f412 (v4.3.12) marked planes flying a sortie with
PLN_LAUNCHED, and made pln_arm() reject planes with that flag set.
This was designed to reject escorts that were already flying as
bombers.  It didn't work, because the test for PLN_LAUNCHED used a
stale copy of the plane created by pln_sel().  Fix by getting a fresh
copy.

The bug always existed, but the botched fix in commit 7ca4f412 made it
worse.  Before, ac_encounter() dropped escorts that were also bombers,
so the bug merely wasted plane fuel.  After, such planes were
effectively duplicated, and damage to one of them, usually the bomber,
was wiped out.  Abusable.
(cherry picked from commit 801780043f)
2008-06-28 13:07:52 -04:00
fbefc139f4 Fix seqno mismatch and use-after-free in shp_sweep()
The code wrote the swept sector after calling shp_check_one_mines().
This failed to use up the mine that hit the minesweeper, and triggered
a seqno mismatch oops.

The code wrote the minesweeper after calling shp_check_one_mines().
This used freed memory when the minesweeper got sunk there.

Broken in 4.0.17.  Fix by moving both calls before
shp_check_one_mines().
(cherry picked from commit b0644e822c)
2008-06-28 13:06:58 -04:00
c40dd61bf0 Don't unlimber when guns unsuccessfully try to fire
This happened when fire command failed becayse the gun lacked shells,
and when other ways to fire failed because the gun was inefficient,
embarked, lacked mil, guns or shells.

Broken in commit b8bdc32b, hvy-metal-2.4.
2008-06-27 06:53:43 -04:00
2b90a5230d Don't let non-light units board ships that can't carry them
ask_olist() let non-light land units board ships that can carry only
light units.  If the board succeeds, the non-light unit move onto the
ship and then are stuck there.
(cherry picked from commit 6d38a04930)
2008-06-17 20:20:02 +02:00
0a7437bc43 Update info BTU on Empire clock and work percentage
Work percentage should have been documented in commit 233fce87,
v4.3.0.

Empire clock should have been documented in commit d3e0597f, v4.3.10.
(cherry picked from commit 4a67080656)
2008-06-17 20:19:48 +02:00
d0210443ff Update info Citizens on census showing old owner
This was forgotten in commit 6b434ee3, v4.3.0.
(cherry picked from commit 860369ec7e)
2008-06-17 20:19:34 +02:00
a4b550a1a2 Fix ship interdiction targeting ships not at sea
perform_mission() needs to know whether it is targeting ships or
something else, because the rules differ: submarines interdict only
ships, land units get their damage reduced when interdicting ships,
and different news are generated.

The old code assumed it was targeting ships when the target sector was
sea.  Wrong when interdicting ships in harbors, bridges and such.
This has always been broken.  Except when checking a submarine's
target: there it tested argument s, which is gross, but at least it
works.  That code was added in v4.0.8.

Replace the broken test by the gross hack everywhere.  This fixes news
and damage from land units when ships get interdicted in non-sea
sectors.
(cherry picked from commit 3e251b474f)
2008-06-10 10:25:05 +02:00
07d2c38a73 Fix ground combat to report defending land units
Commit 092a52f2 (v4.3.4) removed the code to estimate defense, because
the use of the estimate had been disabled since v4.0.0.  This
accidentally removed the reporting of defending units, because
get_dlist() reported them when called for an estimate, and not when
called for real.

Fix by removing the unused estimate capability from get_dlist().  It
now reports defending units always.
(cherry picked from commit 64f44e9904)
2008-06-10 10:25:05 +02:00
b8bdc32b3c Fix unlimbering, it had no effect
Broken by mismerging the rebase of Hvy Metal I in commit 5d0f5e69,
except for fire command when the target was out of range.
2008-06-10 10:24:59 +02:00
dfcc13abdd Clarify info Railroad on track stopping at national borders 2008-06-09 20:07:28 +02:00
080e8db899 Avoid seqno mismatch oops in recursive land unit supply
Before s_commod() attempts to recursively supply a supply unit it
wants to use as supply source, it zaps the unit's load.  When
actually_doit is false, it later restores the old load by overwriting
the change with a saved copy of the unit.  That triggers a seqno
mismatch oops.

Avoid that by copying the new sequence number to the saved copy.
(cherry picked from commit aacd0fb754)
2008-05-28 22:33:36 +02:00
2410535a05 Don't run supply machinery to get zero units
Change supply_commod() and try_supply_commod() not to call s_commod()
when zero units are wanted.

This isn't just for efficiency, it's also for limiting exposure to
supply bugs a bit.
(cherry picked from commit 7f17369491)
2008-05-28 22:33:27 +02:00
d3a2130b26 Fix type of get_seqno() from int to unsigned
While there, document the seqno functions.
2008-05-28 22:32:03 +02:00
e1283b118a Fix crash bug in satellite maps
The value of diffx() had the wrong sign when the arguments differed by
WORLD_X / 2.  Same for diffy() and WORLD_Y / 2.  satmap() used them to
find the vector from map center to ship or land unit to put on the
map, and got incorrect values for ships and land units directly
opposite to the center in x or y.  The bug made satmap() read a
pointer out bounds of its malloced radbuf[], and then write through
that with unpredictable consequences.

Broken in 4.2.12.  The original bug was in Empire 1.1: it
miscalculated where to put ships on the map (no crash).  An incomplete
fix for radmap() and satmap() appeared in Chainsaw 2 (still no crash).
radmap() got fixed correctly in Chainsaw 3, but satmap() was
forgotten.  That one got "fixed" in 4.2.7, and again in 4.2.12, but
both "fixes" were flawed and could crash.

Fix by backing out the flawed fixes and adopting the fix from radmap()
instead.
(cherry picked from commit 0cc474bd6d)
2008-05-28 22:32:00 +02:00
7dc0f48868 Fix XNORM() and YNORM()
Broken in commit 5f764285 (v4.3.12) for negative multiples of WORLD_X
and WORLD_Y, respectively.

This could theoretically lead to buffer overruns and other
unpleasantness.  None have been reproduced, though.
(cherry picked from commit 7680acc39f)
2008-05-18 10:13:45 +02:00
e2eccc5740 Disable incorrect use of resupply_all() in load and lload
load_land_ship() and load_land_land() automatically resupply the land
units they load.  This can draw supplies from the sector where the
land units are.  When load() and lload() later update the sector, they
wipe out the update made for drawing supplies, and we get a seqno
mismatch oops.  Highly abusable.
2008-05-18 10:13:45 +02:00
c083a25277 Fix edit l, s, u, p not to wipe out concurrent updates
Make edit() bail out if the edited object changed while edit() slept
for input.
(cherry picked from commit a1f4dc9592)
2008-05-18 10:13:45 +02:00
6e69d6d9de Fix xdump nat for relations
Commit ee863c5d (v4.3.12) got opt_HIDDEN backwards in nstr_exec_val().
(cherry picked from commit 3dbb4dbb93)
2008-05-18 10:13:45 +02:00
5a2440c9d4 Fix origin command not to prompt twice for its argument
Broken in commit b69173ee, v4.3.0.
(cherry picked from commit 27c3466aa5)
2008-05-18 10:13:45 +02:00
45a6b9a1d7 Cover biofuel plant in info Quick-ref 2008-05-18 10:13:45 +02:00
542460c787 Fix markup in info Hvy-Metal 2008-05-18 10:13:45 +02:00
312b28f5fa Disable another incorrect use of supply_commod()
navi() reads the ships into a list.  When the ships get interdicted,
and lack flak shells, ac_shipflak() tries to get one and updates the
ship.  When the ship in the list is later written back, e.g. to apply
interdiction damage, the flak shell is wiped out, and we get a seqno
mismatch oops.

Disable automatic flak shell supply in ac_ship_flak() for now.  This
is related to commit f7d61817, which disabled automatic supply of
shells in ac_doflak() and shp_missile_defense().
2008-05-18 10:13:44 +02:00
e7aa3627c4 Fix edit command seqno oopses
Broken by commit dc9d847b.
2008-05-18 10:13:38 +02:00
8fe67826e6 Avoid compiler warning 2008-05-18 10:12:25 +02:00
05e5adfac8 Debug code to help catch the phantom nuke bug
Thu Apr 24 12:20:52 2008 Oops: bug in ../src/lib/subs/plnsub.c:1146

#3  0x080e64f4 in oops (msg=0x0, file=0x80ff1ca "../src/lib/subs/plnsub.c",
    line=1146) at ../src/lib/gen/log.c:141
#4  0x080bce6c in pln_damage (pp=0x8415b60, x=82, y=20, type=115 's',
    nukedamp=0x84158bc, noisy=1) at ../src/lib/subs/plnsub.c:1146
#5  0x080684f2 in launch_missile (pp=0x8415b60, sublaunch=0)
    at ../src/lib/commands/laun.c:281
#6  0x08067c79 in laun () at ../src/lib/commands/laun.c:111
2008-05-07 10:33:42 +02:00
cf4639fa74 Update info Hvy-Metal for Hvy Metal II 2008-05-07 10:33:42 +02:00
b707e2cca8 Permit ships to assault the sector they're in
Ships still have to be in a sea sector to assault an adjacent sector.
2008-05-07 10:33:42 +02:00
4e962406ff Let ships navigate bridge spans regardless of owner 2008-05-07 10:33:42 +02:00
f7d6181717 Disable some incorrect uses of supply_commod()
Because supply_commod() updates supply sources it used, the caller
must not cache objects that could be supply sources across a supply
call.  This is very easy to get wrong.

ac_doflak() supplies flak shells if the sector hasn't enough for its
guns.  It caches the sector that receives them.  If the sector has
some shells, but not enough, it supplies them to itself, causing it to
be updated from within supply_commod().  ac_doflak() then adds the
supplied shells to its cached sector, then writes that back.  This
doubles shells already there, and triggers a a seqno mismatch oops.

shp_missile_defense() has similar problems, only for ships.

Disable ac_doflak() and shp_missile_defense() for now, to at least
reduce the oopsing to manageable levels.

Most likely other calls of supply_commod() are also wrong.  Many of
them can't be just disabled, because supply is too relevant to
gameplay there.
2008-05-07 10:33:42 +02:00
b313b61cd4 Oops on sequence number mismatch
Old code only logged this, for fear of false positives.
2008-05-07 10:33:42 +02:00
e917a60371 Trains can no longer be loaded on land units, update info Railroad 2008-05-07 10:33:42 +02:00
12e34aeeb4 Fix info Railroad on spy and satellite reports
Fix explanation of "rl eff" value.  Mention satellite report.
2008-05-07 10:33:41 +02:00
fa5fa4abcc Don't store RAILWAYS track in sectors
Storing track in sectors is problematic, because we need to update
adjacent sectors when updating a sector in a way that changes its
capability to extend railway into its neighbors.  This invalidates
cached adjacent sectors, and calling code may not be prepared for
that.  Specifically, bridge building caches the bridge head, and
writes it back later, wiping out the track update.

Replace struct sctstr member sct_track by new sct_rail_track().  Make
selector track virtual.  Remove the code to keep sct_track up-to-date:
set_railway(), update_railway().

Unfortunately, this causes cyclic dependencies between link libraries:
the virtual selector needs to be referenced from src/lib/global/nsc.c,
and it needs to reference stuff from src/lib/common/file.c.  Hack
around it in Make.mk for now.
2008-05-07 10:33:41 +02:00
11100f23e5 Update info Hvy-Metal for Hvy Metal II 2008-05-07 10:33:41 +02:00
b437b7b5ec Make fairland record the island number in the deity territory
Can be useful for deities when further customizing their game setup.
2008-05-07 10:33:41 +02:00
95298986cc Don't produce food without work
We don't want to starve tiny populations, because that would require
players to move trivial amounts of food after explore and such.
growfood() used to simply grow at least 1f when a sector was about to
starve.  That food is almost never eaten by a tiny population, so we
effectively got some production without work.  Fix by taking away that
free food after people ate, in do_feed().
2008-05-07 10:33:41 +02:00
dc9d847b8b Add sequence numbers to game state (experimental)
This catches output dependency violations, e.g. two threads doing a
read-modify-write without synchronization.

New struct emptypedstr member seqno.  Make sure all members of unit
empobj_storage share it.  Set it in ef_blank() and ef_set_uid(), step
it in ef_write().  fairland and files don't use ef_set_uid(); need to
set it manually in files.c's main() and file_sct_init().

Factor do_read() out of fillcache() to make it available for
new get_seqno().
2008-05-07 10:33:41 +02:00
2aec870a14 New concept sector terrain
A sector type's terrain (struct dchrstr member d_terrain) is the
sector type of its underlying terrain.  Sector types occuring in
d_terrain are terrain types, and must have their own type in
d_terrain.  Players can change sector types only to those with the
same terrain.

The builtin configuration defines terrain types sea, mountain,
wasteland, wilderness and plains.  It gives bridge span and tower
terrain sea, and everything else terrain wilderness.  Hence, the stock
game remains unchanged.

Deities can use terrain to create sector types that can be developed
only in limited ways.
2008-05-07 10:33:41 +02:00
e3658ff2f0 Remove hard-coded differences between highways and bridge heads
Let highways build and support bridges.  Allow bridge heads anywhere,
not just on the coast.
2008-05-07 10:33:41 +02:00
Markus Armbruster
9f1b4e2c81 Document Hvy Metal refinery p.e. 2008-05-07 10:33:41 +02:00
Markus Armbruster
5d0f5e69ee Rebase of Hvy Metal I final version
Straightforward forward port.  Drop the code to reset track on
startup.  It's not necessary, and it breaks linking of empdump.
2008-05-07 10:33:41 +02:00
74 changed files with 766 additions and 243 deletions

View file

@ -284,6 +284,7 @@ ifeq ($(empthread),Windows)
$(client): src/lib/w32/getopt.o
endif
$(util): src/lib/common/move.o # FIXME hack for opt_RAILWAYS
$(util): $(libs)
lib/libas.a: $(filter src/lib/as/%, $(obj))

View file

@ -44,6 +44,7 @@ struct comstr {
/* initial part must match struct empobj */
short ef_type;
short com_uid;
unsigned com_seqno;
time_t com_timestamp;
natid com_owner;
/* end of part matching struct empobj */

View file

@ -161,6 +161,8 @@ EMPCF_OPT("INTERDICT_ATT", opt_INTERDICT_ATT,
"Interdict post-attack move in")
EMPCF_OPT("LANDSPIES", opt_LANDSPIES,
"Enable the land unit type spies")
EMPCF_OPT("LIMBER", opt_LIMBER,
"Artillery requires mobility to start firing")
EMPCF_OPT("LOANS", opt_LOANS,
"Allow bailing out of other countries via S&L scandals")
EMPCF_OPT("LOSE_CONTACT", opt_LOSE_CONTACT,
@ -179,6 +181,8 @@ EMPCF_OPT("NO_PLAGUE", opt_NO_PLAGUE,
"Disable plague")
EMPCF_OPT("PINPOINTMISSILE", opt_PINPOINTMISSILE,
"Enable marine missiles")
EMPCF_OPT("RAILWAYS", opt_RAILWAYS,
"Highways double as rail")
EMPCF_OPT("RES_POP", opt_RES_POP,
"Population is limited by research")
EMPCF_OPT("SAIL", opt_SAIL,

View file

@ -57,6 +57,7 @@ struct empobj {
*/
short ef_type;
short uid;
unsigned seqno;
time_t timestamp;
/* end of part matching struct emptypedstr */
natid own; /* valid if EFF_OWNER is in table's flags */

View file

@ -67,6 +67,7 @@ struct empfile {
struct emptypedstr {
short ef_type;
short uid;
unsigned seqno;
time_t timestamp;
};
@ -187,6 +188,7 @@ extern int ef_close(int);
extern int ef_flush(int);
extern void ef_blank(int, int, void *);
extern int ef_write(int, int, void *);
extern void ef_set_uid(int, void *, int);
extern int ef_extend(int, int);
extern int ef_ensure_space(int, int, int);
extern int ef_truncate(int, int);

View file

@ -40,6 +40,7 @@ struct gamestr {
/* initial part must match struct empobj */
short ef_type;
short game_uid;
unsigned game_seqno;
time_t game_timestamp;
/* end of part matching struct empobj */
char game_upd_disable; /* updates disabled? */

View file

@ -34,13 +34,17 @@
#ifndef JOURNAL_H
#define JOURNAL_H
struct player; /* FIXME temporary hack */
int journal_startup(void);
void journal_shutdown(void);
int journal_reopen(void);
void journal_login(void);
void journal_logout(void);
void journal_prng(unsigned);
void journal_output(struct player *, int, char *);
void journal_input(char *);
void journal_command(char *);
void journal_update(int);
#endif

View file

@ -51,6 +51,7 @@ struct lndstr {
/* initial part must match struct empobj */
short ef_type;
short lnd_uid; /* unit id (land unit) */
unsigned lnd_seqno;
time_t lnd_timestamp; /* Last time this unit was touched */
natid lnd_own; /* owner's country num */
coord lnd_x; /* x location in abs coords */
@ -190,6 +191,7 @@ extern int lnd_hardtarget(struct lndstr *);
extern int lnd_mar_one_sector(struct emp_qelem *, int, natid, int);
extern int lnd_support(natid, natid, coord, coord, int);
extern int lnd_can_attack(struct lndstr *);
extern void lnd_unlimber(struct lndstr *lp);
extern int lnd_fortify (struct lndstr *lp, int hard_amt);
extern void lnd_set_tech(struct lndstr *, int);

View file

@ -44,6 +44,7 @@ struct lonstr {
/* initial part must match struct empobj */
short ef_type;
short l_uid;
unsigned l_seqno;
time_t l_timestamp;
/* end of part matching struct empobj */
natid l_loner; /* loan shark */

View file

@ -40,7 +40,8 @@
struct loststr {
/* initial part must match struct empobj */
short ef_type;
int lost_uid;
short lost_uid;
unsigned lost_seqno;
time_t lost_timestamp; /* When it was lost */
natid lost_owner; /* Who lost it */
/* end of part matching struct empobj */

View file

@ -70,6 +70,7 @@ struct realmstr {
/* initial part must match struct empobj */
short ef_type;
short r_uid; /* realm table index */
unsigned r_seqno;
time_t r_timestamp; /* Last time this realm was touched */
natid r_cnum; /* country number */
/* end of part matching struct empobj */
@ -82,6 +83,7 @@ struct natstr {
/* initial part must match struct empobj */
short ef_type;
short nat_uid; /* equals nat_cnum */
unsigned nat_seqno;
time_t nat_timestamp;
natid nat_cnum; /* our country number */
/* end of part matching struct empobj */

View file

@ -48,6 +48,7 @@ struct nwsstr {
/* initial part must match struct empobj */
short ef_type;
short nws_uid;
unsigned nws_seqno;
time_t nws_timestamp;
/* end of part matching struct empobj */
natid nws_ano; /* "actor" country # */

View file

@ -44,6 +44,7 @@ struct nukstr {
/* initial part must match struct empobj */
short ef_type;
short nuk_uid;
unsigned nuk_seqno;
time_t nuk_timestamp; /* Last time this nuke was touched */
natid nuk_own;
coord nuk_x, nuk_y; /* current loc of device */

View file

@ -48,6 +48,7 @@ struct plnstr {
/* initial part must match struct empobj */
short ef_type;
short pln_uid; /* plane unit id */
unsigned pln_seqno;
time_t pln_timestamp; /* Last time this plane was touched */
natid pln_own; /* owning country */
coord pln_x; /* plane x-y */

View file

@ -76,8 +76,9 @@ struct player {
int simulation; /* e.g. budget command */
double dolcost;
time_t curup; /* when last input was received */
int aborted; /* interrupt cookie received? */
int aborted; /* interrupt cookie or EOF received? */
int eof; /* EOF (cookie or real) received? */
int recvfail; /* #recvclient() failures */
int curid; /* for pr, cur. line's id, -1 none */
char *map; /* pointer to in-mem map */
char *bmap; /* pointer to in-mem bmap */

View file

@ -282,8 +282,6 @@ extern int logreopen(void);
extern void logerror(char *, ...) ATTRIBUTE((format (printf, 1, 2)));
/* more in misc.h */
/* mapdist.c */
extern int diffx(int, int);
extern int diffy(int, int);
extern int deltax(int, int);
extern int deltay(int, int);
extern int mapdist(int, int, int, int);
@ -710,6 +708,7 @@ extern int wu(natid, natid, char *, ...) ATTRIBUTE((format (printf, 3, 4)));
* src/lib/update/ *.c
*/
/* age.c */
extern int age_people(int, int);
extern void age_levels(int);
/* anno.c */
extern void delete_old_announcements(void);

View file

@ -46,6 +46,7 @@ struct sctstr {
/* initial part must match struct empobj */
short ef_type;
short sct_uid; /* equals XYOFFSET(sct_x, sct_y) */
unsigned sct_seqno;
time_t sct_timestamp; /* Last time this sector was written to */
natid sct_own; /* owner's country num */
coord sct_x; /* x coord of sector */
@ -102,6 +103,7 @@ enum d_navigation {
struct dchrstr {
unsigned char d_uid;
char d_mnem; /* map symbol */
unsigned char d_terrain; /* terrain sector type */
int d_prd; /* product type */
int d_peffic; /* process efficiency, in percent */
float d_mob0, d_mob1; /* movement cost at 0 and 100% eff */
@ -169,6 +171,9 @@ extern struct dchrstr dchr[SCT_TYPE_MAX + 2];
extern struct dchrstr bigcity_dchr;
#define IS_BIG_CITY(type) (dchr[(type)].d_pkg == UPKG)
#define IS_BRIDGE_HEAD(type) \
((type) == SCT_BHEAD || (type) == SCT_HIWAY || (type) == SCT_BTOWER)
/* Minimal efficiency of sectors that can be knocked down (bridges) */
#define SCT_MINEFF 20
@ -181,6 +186,11 @@ extern struct dchrstr bigcity_dchr;
#define FORTEFF 5 /* forts must be 5% efficient to fire. */
/* Can trains enter sector SP? */
#define SCT_HAS_RAIL(sp) \
(opt_RAILWAYS ? sct_rail_track((sp)) != 0 \
: intrchr[INT_RAIL].in_enable && (sp)->sct_rail != 0)
#define MOB_MOVE 0
#define MOB_MARCH 1
#define MOB_RAIL 2
@ -216,5 +226,6 @@ struct sctintrins {
extern struct sctintrins intrchr[INT_DEF + 2];
extern int fort_fire(struct sctstr *);
extern int sct_rail_track(struct sctstr *);
#endif

View file

@ -65,6 +65,7 @@ struct shpstr {
/* initial part must match struct empobj */
short ef_type;
short shp_uid; /* unit id (ship #) */
unsigned shp_seqno;
time_t shp_timestamp; /* Last time this ship was touched. */
natid shp_own; /* owner's country num */
coord shp_x; /* x location in abs coords */

View file

@ -44,6 +44,7 @@ struct trdstr {
/* initial part must match struct empobj */
short ef_type;
short trd_uid;
unsigned trd_seqno;
time_t trd_timestamp;
natid trd_owner;
/* end of part matching struct empobj */

View file

@ -41,6 +41,7 @@ struct trtstr {
/* initial part must match struct empobj */
short ef_type;
short trt_uid;
unsigned trt_seqno;
time_t trt_timestamp;
/* end of part matching struct empobj */
natid trt_cna; /* proposer */

View file

@ -43,9 +43,9 @@
#define XYOFFSET(x, y) (((y) * WORLD_X + (x)) / 2)
#define XNORM(x) \
(((x) < 0) ? (WORLD_X - (-(x) % WORLD_X)) : ((x) % WORLD_X))
(((x) < 0) ? (WORLD_X - 1 - ((-(x) - 1) % WORLD_X)) : ((x) % WORLD_X))
#define YNORM(y) \
(((y) < 0) ? (WORLD_Y - (-(y) % WORLD_Y)) : ((y) % WORLD_Y))
(((y) < 0) ? (WORLD_Y - 1 - ((-(y) - 1) % WORLD_Y)) : ((y) % WORLD_Y))
struct range {
coord lx; /* low-range x,y */

View file

@ -14,7 +14,7 @@ do.
BTUs are generated in real-time based on the number of civilians that
are in your capital. Every time you log out and in again, the server
calculates how long you've been away, and based on that time awards
you a certain number of BTUs.
you a certain number of BTUs. The same happens at the update.
.s1
Here is the procedure for determining how many BTUs you get:
.nf
@ -27,43 +27,46 @@ they are automatically set back to the maximum.
(2) Find out how many civs are required to make one BTU in one time unit.
The "version" command will tell you how many civilians are required to
produce one BTU in one Empire Time Unit (ETU).
produce one BTU in one Empire Time Unit (ETU) in a perfectly efficient
capital.
(3) Calculate how many BTUs your cap produces in one time unit.
(3) Calculate how efficiently your capital makes BTUs. A proper
capital's BTU efficiency is sector efficiency times work percentage,
but at least 0.5%. A mountain capital's BTU efficiency is always
0.5%.
(4) Calculate how many BTUs your capital produces in one time unit.
Divide the number of civs generating BTUs (step 1) by the number of
civs required to produce one BTU in one time unit (step 2). If your
capital is in a mountain or has zero efficiency, then multiply by
1/200. Otherwise, multiply by (sector efficiency) / 100. Note that
0% capitals and mountains generate BTUs as if they were 0.5% capitals.
civs required to produce one BTU in one time unit (step 2). Multiply
by efficiency (step 3).
(4) Find out how many time units have passed.
(5) Find out how many time units have passed since you last got BTUs.
A fixed number of ETUs elapse between updates. The \*Qversion\*U
command shows how many.
(5) Calculate how many BTUs you get.
Multiply the number of BTUs your cap produces in one ETU (step 3) by
the number of ETUs which have passed (step 4). This is how many BTUs
(6) Calculate how many BTUs you get.
Multiply the number of BTUs your cap produces in one ETU (step 4) by
the number of ETUs which have passed (step 5). This is how many BTUs
you get. Note that there is a limit to how many BTUs you can have at
any given time. This number is usually 640 but can be changed by the deity.
EXAMPLE: say you had a 100% capital containing 500 civs.
Suppose that version said:
EXAMPLE: say your capital is in perfect condition (100% efficiency and
work), and has 500 civilians. Suppose that version said:
It takes 25.00 civilians to produce a BTU in one time unit
Then first you would divide 500 by 25 to get 20. Now since your cap
is 100% efficient, you would multiply 20 by (100/100) and so the civs
in your cap would produce 20 BTUs per time unit. Now suppose that
is 100% efficient and 100% working, its BTU efficiency is 100% * 100%
= 100%, i.e. your capital makes 20 BTUs per ETU. Now suppose that
version said:
An update consists of 60 empire time units.
and suppose that exactly that many had passed since the last time you
logged on.
Lastly, we multiply 20 by 60 to get 1200 BTUs. But since the
maximum is 640, we would have 640 BTUs. Note that if your capital had
been in a mountain sector, then you would have only gotten 6 BTUs in
24 hours.
got BTUs. You multiply 20 by 60 and get 1200 BTUs. But since the
maximum is 640, you'd have 640 BTUs. Note that if your capital were a
mountain sector, it would make only 20 * 0.5% = 0.1 BTUs per time
unit. You'd get only 6 BTUs then.
.fi
.s1
.SA "Innards, version, Time, Playing"

View file

@ -32,7 +32,7 @@ sector is too small, or if the sector starves, disloyalty will
increase.
.s1
If a sector is a conquered sector,
a star \*Q*\*U will be shown in the appropriate column
the old owner will be shown in the appropriate column
on the census report.
Friendly sectors allow enlistment of military,
as well as the ability to move the civilians freely about.

120
info/Hvy-Metal.t Normal file
View file

@ -0,0 +1,120 @@
.TH Concept "Hvy-Metal"
.NA Hvy-Metal "Special rules for Hvy Metal"
.LV Basic
.s1
Ship types are customized. Better check show for the details.
.s1
Dreadnoughts are more heavily armored. Frigates are more fragile.
.s1
More ships can carry choppers, and jf2 count as choppers. Some ships
are not ideal for this, and this is reflected by the lack of large
petrol and shell storage. But it gives players yet another
interesting avenue to explore, and reflects the ships better. Also
helps simulate irregular forces desperately equipping what they can for
a role. A chance for a creative player to spring surprises.
.s1
New assault ship type: Think Tarawa or Iwo Jima class ships. These
put the ASSAULT back into landings. Huge mil capacity, can operate
choppers and Harriers. Able to drop 12 marine units and a horde of
mil onto a shore, or sustain para drops and air strikes inland with
its aircraft. Go ashore in a hurry, Big Time. A fat target too, so
guard it carefully.
.s1
Ships can navigate bridge sectors regardless of owner.
.s1
Ships can assault the sector they're in.
.s1
Land unit types are heavily customized. Better check show for the
details. Non-mechanized units are slower and more vulnerable,
infantry units have capability security, marines can have amtraks,
artillery firing ranges differ, few units are light (but troop
transports and landing ships can carry non-light units), food
capacities are reduced.
.s1
Tanks and AAA can fire. \*QHey guys, why don't we shoot this big gun
on this tank at those d*mn elves on that hill instead of hanging our
laundry on it\*U? Don't expect the range of an artillery unit, which
specializes in this and has forward observers built in to the unit
cost. Watch your magazines too!
.s1
Artillery units with capability heavy can only fire at sectors and
fire offensive support. They can't target ships, return fire,
interdict, or fire defensive support.
.s1
Artillery units in mountains receive a range bonus of +0.5.
.s1
New experimental option RAILWAYS is enabled: trains run on highways
and sectors next to highways. Use sinfra to find out mobility costs.
Try sect # ?track>0 to visualize your track. Check info
\*QRailroad\*U for details.
.s1
There are more train types, BIG siege guns, etc.
.\"And we got the
.\"Mother Of All Guns: something like what was attempted a few times in
.\"history, a huge costly gun with incredible range. It CAN be moved.
.\"Slowly. Has all the problems fixed positions have. If these are not
.\"obvious, any experienced player will gladly demonstrate them for you.
.s1
Infrastructure is disabled.
.s1
New experimental option LIMBER is enabled: slow guns and heavy railway
guns use mobility to unlimber. Limbering and unlimbering is
completely automatic. See info \*QUnit-types\*U for details.
.s1
Planes are tweaked somewhat. show is your friend.
.s1
Che age just like military reserves: 1% decay per 24 ETUs. In
sufficiently loyal sectors you don't own, however, a full half of them
(rounded up) vanish each update. The anti command is disabled.
.s1
Mountains, fortresses and cities provide a respectable defensive
bonus. Cities cost real money to build. Banks cost some money, too.
Ever seen Fort Knox? Bridges cost only half as many hcms as usual.
.s1
There is no bridge head sector type. Highways can serve as bridge
heads.
.s1
New sector type freeway. You can turn plains into freeway and back,
but you can't turn either into anything else. Freeways can serve as
bridge heads.
.s1
Plains produce food.
.s1
Food is much harder to grow. Expect 20% of your population to be
farmers.
.s1
Sectors without any food get one unit of food for free to avoid
starvation. In Hvy Metal, that free food is always completely
consumed.
.s1
New sector type biofuel plant lets you make oil from food, at a cost.
.s1
Your refineries make less petrol from each barrel of oil than usual.
.s1
Natural resources gold, oil and uran deplete much slower than usual.
Fully depleting a sector will take you several updates. Oil
production does not depend on tech; you don't have to micro-manage to
conserve oil. Resources are scarce. Expect to fight over them.
.s1
Oil derricks need to set up shop before they produce: no production
while mobility is below maximum.
.s1
Automatic shell supply for sector flak, ship flak and ship missile
defense is disabled, because its bugs interfere with Hvy Metal
modifications. Same for automatic supply of land units on loading
them onto ships or land units.
.s1
Missed updates due to server problems will be forced if caught within
15 minutes of planned update time or skipped otherwise.
.s1
Everything you do in this game is logged by the deities for their own
nefarious purposes. However, the logs are treated confidentially.
.s1
Make the deities laugh and get up to 5 gold bars. 5 bars per week up
for grabs.
.s1
Source code and configuration is available from
.br
http://www.stdio.com/~rhyatt/empire/hvy_metal_II/
.s1
.SA "Introduction, Server"

View file

@ -48,6 +48,11 @@ TECH_POP: Technology costs more to make as your civilian population
grows past 50,000 civilians.
TREATIES: Sign treaties with your friends and enemies, and breaking of
them is reported in the news.
The following options are new in Hvy Metal:
LIMBER Artillery requires mobility to start firing
RAILWAYS Highways double as rail
.fi
.SA "Hidden, Server, version"

View file

@ -22,7 +22,7 @@ Sector-types:
(Petrol is per 10 units; others per unit)
Products:
Item $ Lcm Hcm Iron Dust Oil Rad Tech Production Eff.
Item $ Lcm Hcm Iron Dust Oil Food Tech Production Eff.
Shells: 3 2 1 0 0 0 0 20 (tech-20)/(tech-10)
Guns: 30 5 10 0 0 1 0 20 (tech-20)/(tech-10)
Iron: 0 0 0 0 0 0 0 0 0
@ -30,6 +30,7 @@ Dust: 0 0 0 0 0 0 0 0 0
Bars: 10 0 0 0 5 0 0 0 0
Food: 0 0 0 0 0 0 0 0 (tech+10)/(tech+20)
Oil: 0 0 0 0 0 0 0 0 (tech+10)/(tech+20)
Biofuel 10 0 0 0 0 0 5 150 (tech+150)/(tech+230)
Petrol 1 0 0 0 0 1 0 20 (tech-20)/(tech-10)
Lcm: 0 0 0 1 0 0 0 0 (tech+10)/(tech+20)
Hcm: 0 0 0 2 0 0 0 0 (tech+10)/(tech+20)

27
info/Railroad.t Normal file
View file

@ -0,0 +1,27 @@
.TH Concept "Railroad"
.NA Railroad "How railroads work"
.LV Expert
Trains are land units with capability \*Qtrain\*U. They can't be
loaded on land units, but they can be loaded on ships, subject to the
usual restrictions for non-light and heavy land units.
.s1
Unlike other units, trains can enter a sector only if it has
(operational) railroad track.
.s1
If option RAILWAYS is disabled, a sector has railroad track as long as
its rail infrastructure efficiency is non-zero. Train mobility cost
depends on rail infrastructure efficiency (see \*Qinfo Mobility\*U).
Spy and satellite reports show approximate rail infrastructure
efficiency in column \*Qrl eff\*U.
.s1
If option RAILWAYS is enabled, all highway-like sectors are railways,
and the track is operational as long as the sector is at least 5%
efficient. A sector is highway-like if its mobility cost at 100% is
zero (column mob cost in \*Qshow sect s\*u). Operational railways
additionally extend track into adjacent sectors that are at least 60%
efficient and owned by the same nation. Sector selector track gives
the number of operational railways within one sector range. Spy and
satellite reports show the presence of track in column \*Qrl eff\*U.
To visualize your railway network, try \*Qsect # ?track#0\*U.
.s1
.SA "LandUnits"

View file

@ -163,6 +163,15 @@ The number of extra-light planes the land unit can carry.
The number of land units the unit can carry (no 'heavy' units)
.in
.s1
If option LIMBER is enabled, guns need to be \*Qlimbered\*U to march
and \*Qunlimbered\*U to fire or fortify. Limbering and unlimbering is
completely automatic. Limbering is free, but unlimbering can cost
mobility, depending on the type of artillery unit: heavy railway
artillery and any artillery with a speed below 22 pay unlimber
mobility equivalent to a march with path cost 0.2, plus 1. This gains
one point of fortification. Presence of engineer units in the same
sector cut the cost by a third.
.s1
Each land unit can carry a certain amount of products and has certain
capabilities. These are listed under the cargoes & abilities section.
The cargoes give the number of each product that can be carried.
@ -196,6 +205,7 @@ the unit can fire 'general unit flak' (see "info Flak")
the unit is a spy
.L train
the unit is a train, and can't be loaded on land units
(see "info Railroad")
.L heavy
the unit cannot be carried on land units or ships, not even supply ships
.in
@ -238,4 +248,3 @@ marines 1 5f 10s xlight light marine
.FI
.s1
.SA "land, LandUnits"

View file

@ -154,13 +154,8 @@ add(void)
sect.sct_defense = 0;
sect.sct_own = 0;
sect.sct_oldown = 0;
if (sect.sct_type == SCT_BSPAN ||
sect.sct_type == SCT_BTOWER)
sect.sct_newtype = sect.sct_type = SCT_WATER;
else if (sect.sct_type != SCT_MOUNT &&
sect.sct_type != SCT_PLAINS)
sect.sct_newtype = sect.sct_type = SCT_RURAL;
/* No dist path */
sect.sct_newtype = sect.sct_type
= dchr[sect.sct_type].d_terrain;
sect.sct_dist_x = sect.sct_x;
sect.sct_dist_y = sect.sct_y;
memset(sect.sct_item, 0, sizeof(sect.sct_item));

View file

@ -528,13 +528,11 @@ build_bridge(struct sctstr *sp, short *vec)
char buf[1024];
if (opt_EASY_BRIDGES == 0) { /* must have a bridge head or tower */
if (sp->sct_type != SCT_BTOWER) {
if (sp->sct_type != SCT_BHEAD)
if (!IS_BRIDGE_HEAD(sp->sct_type))
return 0;
if (sp->sct_newtype != SCT_BHEAD)
if (sp->sct_newtype != sp->sct_type)
return 0;
}
}
if (sp->sct_effic < 60 && !player->god) {
pr("Sector %s is not 60%% efficient.\n",

View file

@ -92,12 +92,17 @@ desi(void)
pr("Only %s can make a %s!\n", cname(0), dchr[des].d_name);
continue;
}
if (dchr[des].d_terrain != dchr[sect.sct_type].d_terrain) {
pr("You can't change a %s into a %s\n",
dchr[sect.sct_type].d_name, dchr[des].d_name);
continue;
}
}
if (sect.sct_type == des && sect.sct_newtype == des)
continue;
if (sect.sct_type == SCT_SANCT)
breaksanct++;
if ((des == SCT_HARBR || des == SCT_BHEAD) && !sect.sct_coastal) {
if (des == SCT_HARBR && !sect.sct_coastal) {
pr("%s does not border on water.\n",
xyas(nstr.x, nstr.y, player->cnum));
if (player->god)
@ -129,12 +134,9 @@ desi(void)
if (sect.sct_x == cap_x && sect.sct_y == cap_y
&& des != SCT_CAPIT && des != SCT_SANCT && des != SCT_MOUNT)
pr("You have redesignated your capital!\n");
if (opt_EASY_BRIDGES == 0) { /* may cause a bridge fall */
if (n != SCT_BHEAD)
continue;
if (!opt_EASY_BRIDGES && IS_BRIDGE_HEAD(n))
bridgefall(&sect);
}
}
if (changed)
writemap(player->cnum);
if (breaksanct)

View file

@ -191,12 +191,16 @@ edit(void)
return err;
break;
case 'l':
if (!check_sect_ok(&sect))
return RET_FAIL;
if ((err = doland(thing, arg, ptr, &sect)) != RET_OK)
return err;
if (!putsect(&sect))
return RET_FAIL;
break;
case 's':
if (!check_ship_ok(&ship))
return RET_FAIL;
if ((err = doship(thing, arg, ptr, &ship)) != RET_OK)
return err;
if (!ef_ensure_space(EF_SHIP, ship.shp_uid, 50))
@ -205,6 +209,8 @@ edit(void)
return RET_FAIL;
break;
case 'u':
if (!check_land_ok(&land))
return RET_FAIL;
if ((err = dounit(thing, arg, ptr, &land)) != RET_OK)
return err;
if (!ef_ensure_space(EF_LAND, land.lnd_uid, 50))
@ -213,6 +219,8 @@ edit(void)
return RET_FAIL;
break;
case 'p':
if (!check_plane_ok(&plane))
return RET_FAIL;
if ((err = doplane(thing, arg, ptr, &plane)) != RET_OK)
return err;
if (!ef_ensure_space(EF_PLANE, plane.pln_uid, 50))
@ -584,7 +592,7 @@ doland(char op, int arg, char *p, struct sctstr *sect)
return RET_SYN;
sect->sct_x = newx;
sect->sct_y = newy;
sect->sct_uid = XYOFFSET(newx, newy);
ef_set_uid(EF_SECTOR, &sect, XYOFFSET(newx, newy));
break;
case 'D':
if (!sarg_xy(p, &newx, &newy))
@ -767,7 +775,7 @@ doship(char op, int arg, char *p, struct shpstr *ship)
ship->shp_rflags = arg;
break;
case 'U':
ship->shp_uid = arg;
ef_set_uid(EF_SHIP, ship, arg);
break;
case 'O':
if (ship->shp_own)
@ -871,7 +879,7 @@ dounit(char op, int arg, char *p, struct lndstr *land)
land->lnd_land = arg;
break;
case 'U':
land->lnd_uid = arg;
ef_set_uid(EF_LAND, land, arg);
break;
case 'O':
if (land->lnd_own)
@ -994,7 +1002,7 @@ doplane(char op, int arg, char *p, struct plnstr *plane)
plane->pln_nuketype = arg;
break;
case 'U':
plane->pln_uid = arg;
ef_set_uid(EF_PLANE, plane, arg);
break;
case 'l':
if (!sarg_xy(p, &newx, &newy))

View file

@ -87,14 +87,6 @@ fly(void)
cno = -1;
if (pln_onewaymission(&target, &cno, &wantflags) < 0)
return RET_SYN;
if (cno < 0) {
dst_ptr = &target;
dst_type = EF_SECTOR;
} else {
getship(cno, &ship);
dst_ptr = &ship;
dst_type = EF_SHIP;
}
if (ip && ip->i_uid == I_CIVIL && target.sct_own != target.sct_oldown) {
pr("Can't fly civilians into occupied sectors.\n");
@ -142,6 +134,14 @@ fly(void)
pr("No planes got through fighter defenses\n");
} else {
getsect(tx, ty, &target);
if (cno < 0) {
dst_ptr = &target;
dst_type = EF_SECTOR;
} else {
getship(cno, &ship);
dst_ptr = &ship;
dst_type = EF_SHIP;
}
pln_dropoff(&bomb_list, ip, tx, ty, dst_ptr, dst_type);
pln_newlanding(&bomb_list, tx, ty, cno);
pln_newlanding(&esc_list, tx, ty, cno);

View file

@ -603,7 +603,14 @@ load_land_ship(struct sctstr *sectp, struct shpstr *sp, int noisy,
land.lnd_ship = sp->shp_uid;
land.lnd_harden = 0;
land.lnd_mission = 0;
#if 0
/*
* FIXME if this supplies from the sector, the putsect in
* load() / lload() duplicates those supplies, causing a
* seqno mismatch
*/
resupply_all(&land);
#endif
sp->shp_nland++;
putland(land.lnd_uid, &land);
if (!has_supply(&land))
@ -1034,7 +1041,10 @@ load_land_land(struct sctstr *sectp, struct lndstr *lp, int noisy,
land.lnd_land = lp->lnd_uid;
land.lnd_harden = 0;
land.lnd_mission = 0;
#if 0
/* FIXME same issue as in load_land_ship() */
resupply_all(&land);
#endif
lp->lnd_nland++;
putland(land.lnd_uid, &land);
if (!has_supply(&land))

View file

@ -188,7 +188,7 @@ multifire(void)
}
fx = fship.shp_x;
fy = fship.shp_y;
} else if (type == EF_SECTOR) {
} else {
if (!getsect(item.sect.sct_x, item.sect.sct_y, &fsect))
continue;
if (item.sect.sct_own != player->cnum)
@ -330,6 +330,12 @@ multifire(void)
pr("Unit %d cannot fire!\n", fland.lnd_uid);
continue;
}
if (lchr[(int)fland.lnd_type].l_flags & L_HEAVY
&& target != targ_land) {
pr("%s is too ponderous to target ships!\n",
prland(&fland));
continue;
}
if (fland.lnd_item[I_GUN] == 0) {
pr("%s -- not enough guns\n", prland(&fland));
continue;
@ -349,6 +355,7 @@ multifire(void)
pr("Klick! ...\n");
continue;
}
if (target == targ_ship) {
if (chance(lnd_acc(&fland) / 100.0))
dam = ldround(dam / 2.0, 1);
@ -687,6 +694,9 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown,
/* Don't shoot yourself */
if (land.lnd_own == aown)
continue;
/* Too ponderous for counter-battery fire */
if (lchr[(int)land.lnd_type].l_flags & L_HEAVY)
continue;
rel = getrel(getnatp(land.lnd_own), own);
rel2 = getrel(getnatp(land.lnd_own), aown);

View file

@ -226,11 +226,16 @@ mission(void)
continue;
}
if ((mission == MI_INTERDICT) && (type == EF_LAND))
if ((mission == MI_INTERDICT) && (type == EF_LAND)) {
if (lchr[(int)gp->type].l_dam == 0) {
pr("%s: cannot fire at range!\n", obj_nameof(gp));
continue;
}
if (lchr[(int)gp->type].l_flags & L_HEAVY) {
pr("%s: too ponderous to interdict!\n", obj_nameof(gp));
continue;
}
}
if ((mission == MI_INTERDICT) && (type == EF_PLANE)) {
struct plchrstr *pcp;

View file

@ -47,7 +47,7 @@ orig(void)
struct natstr *np;
p = getstarg(player->argp[1], "New origin (sector or country) : ", buf);
if (!p)
if (!p || !*p)
return RET_SYN;
if (!isalpha(*p) && strchr(p, ',')) {
/* sector */

View file

@ -73,6 +73,9 @@ sinfra(void)
pr("%4d%% ", sect.sct_effic);
pr("%4d%% ", sect.sct_road);
prmobcost(&sect, MOB_MOVE);
if (opt_RAILWAYS)
pr(sct_rail_track(&sect) ? " yes " : " no ");
else
pr("%4d%% ", sect.sct_rail);
prmobcost(&sect, MOB_RAIL);
pr("%4d%% ", SCT_DEFENSE(&sect));

View file

@ -224,7 +224,7 @@ spyline(struct sctstr *sp)
sp->sct_oldown,
roundintby((int)sp->sct_effic, 10),
roundintby((int)sp->sct_road, 10),
roundintby((int)sp->sct_rail, 10),
opt_RAILWAYS ? !!sct_rail_track(sp) : roundintby(sp->sct_rail, 10),
roundintby((int)sp->sct_defense, 10),
roundintby(sp->sct_item[I_CIVIL], 10),
roundintby(sp->sct_item[I_MILIT], 10),

View file

@ -63,14 +63,14 @@ swaps(void)
/* change the location of secta to that of sectb */
secta.sct_x = sectb.sct_x;
secta.sct_y = sectb.sct_y;
secta.sct_uid = sectb.sct_uid;
ef_set_uid(EF_SECTOR, &secta, sectb.sct_uid);
secta.sct_dist_x = sectb.sct_x;
secta.sct_dist_y = sectb.sct_y;
secta.sct_coastal = sectb.sct_coastal;
/* change the location of sectb to where secta was */
sectb.sct_x = tmp.sct_x;
sectb.sct_y = tmp.sct_y;
sectb.sct_uid = tmp.sct_uid;
ef_set_uid(EF_SECTOR, &sectb, tmp.sct_uid);
sectb.sct_dist_x = tmp.sct_x;
sectb.sct_dist_y = tmp.sct_y;
sectb.sct_coastal = tmp.sct_coastal;

View file

@ -173,6 +173,8 @@ pln_zap_transient_flags(void)
/* laziness: assumes plane file is EFF_MEM */
for (i = 0; (pp = getplanep(i)) != NULL; i++) {
if (!pp->pln_own)
continue;
if (pp->pln_flags & PLN_LAUNCHED
&& (plchr[pp->pln_type].pl_flags & (P_M | P_O)) != P_O) {
pp->pln_flags &= ~PLN_LAUNCHED;

View file

@ -48,7 +48,10 @@
static int ef_realloc_cache(struct empfile *, int);
static int fillcache(struct empfile *, int);
static int do_read(struct empfile *, void *, int, int);
static int do_write(struct empfile *, void *, int, int, time_t);
static unsigned get_seqno(struct empfile *, int);
static void new_seqno(struct empfile *, void *);
static void do_blank(struct empfile *, void *, int, int);
/*
@ -300,11 +303,28 @@ ef_read(int type, int id, void *into)
*/
static int
fillcache(struct empfile *ep, int id)
{
int ret;
if (CANT_HAPPEN(!ep->cache))
return -1;
ret = do_read(ep, ep->cache, id, MIN(ep->csize, ep->fids - id));
if (ret >= 0) {
/* cache changed */
ep->baseid = id;
ep->cids = ret;
}
return ret;
}
static int
do_read(struct empfile *ep, void *buf, int id, int count)
{
int n, ret;
char *p;
if (CANT_HAPPEN(ep->fd < 0 || !ep->cache))
if (CANT_HAPPEN(ep->fd < 0 || id < 0 || count < 0))
return -1;
if (lseek(ep->fd, id * ep->size, SEEK_SET) == (off_t)-1) {
@ -313,21 +333,21 @@ fillcache(struct empfile *ep, int id)
return -1;
}
p = ep->cache;
n = MIN(ep->csize, ep->fids - id) * ep->size;
p = buf;
n = count * ep->size;
while (n > 0) {
ret = read(ep->fd, p, n);
if (ret < 0) {
if (errno != EINTR) {
logerror("Error reading %s elt %d (%s)",
ep->file,
id + (int)((p - ep->cache) / ep->size),
id + (int)((p - (char *)buf) / ep->size),
strerror(errno));
break;
}
} else if (ret == 0) {
logerror("Unexpected EOF reading %s elt %d",
ep->file, id + (int)((p - ep->cache) / ep->size));
ep->file, id + (int)((p - (char *)buf) / ep->size));
break;
} else {
p += ret;
@ -335,12 +355,7 @@ fillcache(struct empfile *ep, int id)
}
}
if (p == ep->cache)
return -1; /* nothing read, old cache still ok */
ep->baseid = id;
ep->cids = (p - ep->cache) / ep->size;
return ep->cids;
return (p - (char *)buf) / ep->size;
}
/*
@ -425,6 +440,7 @@ ef_write(int type, int id, void *from)
ep->prewrite(id, from);
if (CANT_HAPPEN((ep->flags & EFF_MEM) ? id >= ep->fids : id > ep->fids))
return 0; /* not implemented */
new_seqno(ep, from);
if (!(ep->flags & EFF_PRIVATE)) {
if (do_write(ep, from, id, 1, time(NULL)) < 0)
return 0;
@ -442,6 +458,77 @@ ef_write(int type, int id, void *from)
return 1;
}
/*
* Change element id.
* BUF is an element of table TYPE.
* ID is its new element ID.
* If table is EFF_TYPED, change id and sequence number stored in BUF.
* Else do nothing.
*/
void
ef_set_uid(int type, void *buf, int uid)
{
struct emptypedstr *elt;
struct empfile *ep;
if (ef_check(type) < 0)
return;
ep = &empfile[type];
if (!(ep->flags & EFF_TYPED))
return;
elt = buf;
if (elt->uid == uid)
return;
elt->uid = uid;
elt->seqno = get_seqno(ep, uid);
}
/*
* Return sequence number of element ID in table EP.
* Return zero if table is not EFF_TYPED (it has no sequence number
* then).
*/
static unsigned
get_seqno(struct empfile *ep, int id)
{
struct emptypedstr *elt;
if (!(ep->flags & EFF_TYPED))
return 0;
if (id < 0 || id >= ep->fids)
return 0;
if (id >= ep->baseid && id < ep->baseid + ep->cids)
elt = (void *)(ep->cache + (id - ep->baseid) * ep->size);
else {
/* need a buffer, steal last cache slot */
if (ep->cids == ep->csize)
ep->cids--;
elt = (void *)(ep->cache + ep->cids * ep->size);
if (do_read(ep, elt, id, 1) < 0)
return 0; /* deep trouble */
}
return elt->seqno;
}
/*
* Increment sequence number in BUF, which is about to be written to EP.
* Do nothing if table is not EFF_TYPED (it has no sequence number
* then).
*/
static void
new_seqno(struct empfile *ep, void *buf)
{
struct emptypedstr *elt = buf;
unsigned old_seqno;
if (!(ep->flags & EFF_TYPED))
return;
old_seqno = get_seqno(ep, elt->uid);
if (CANT_HAPPEN(old_seqno != elt->seqno))
old_seqno = MAX(old_seqno, elt->seqno);
elt->seqno = old_seqno + 1;
}
/*
* Extend table TYPE by COUNT elements.
* Any pointers obtained from ef_ptr() become invalid.
@ -504,9 +591,17 @@ ef_extend(int type, int count)
void
ef_blank(int type, int id, void *buf)
{
struct empfile *ep;
struct emptypedstr *elt;
if (ef_check(type) < 0)
return;
do_blank(&empfile[type], buf, id, 1);
ep = &empfile[type];
do_blank(ep, buf, id, 1);
if (ep->flags & EFF_TYPED) {
elt = buf;
elt->seqno = get_seqno(ep, elt->uid);
}
}
/*

View file

@ -41,34 +41,6 @@
#include "optlist.h"
#include "prototypes.h"
int
diffx(int x1, int x2)
{
int dx;
dx = x1 - x2;
dx = dx % WORLD_X;
if (dx > WORLD_X / 2)
dx = dx - WORLD_X;
if (dx < -WORLD_X / 2)
dx = dx + WORLD_X;
return dx;
}
int
diffy(int y1, int y2)
{
int dy;
dy = y1 - y2;
dy = dy % WORLD_Y;
if (dy > WORLD_Y / 2)
dy = dy - WORLD_Y;
if (dy < -WORLD_Y / 2)
dy = dy + WORLD_Y;
return dy;
}
int
deltax(int x1, int x2)
{

View file

@ -33,8 +33,10 @@
#include <config.h>
#include "file.h"
#include "misc.h"
#include "nat.h"
#include "optlist.h"
#include "path.h"
#include "sect.h"
#include "xy.h"
@ -48,6 +50,12 @@ sector_mcost(struct sctstr *sp, int mobtype)
if (base < 0)
return -1.0;
if (mobtype == MOB_RAIL && opt_RAILWAYS) {
if (!SCT_HAS_RAIL(sp))
return -1;
mobtype = MOB_MARCH;
}
/* linear function in eff, d_mob0 at 0%, d_mob1 at 100% */
base += (dchr[sp->sct_type].d_mob1 - base) * sp->sct_effic / 100;
if (CANT_HAPPEN(base < 0))
@ -83,3 +91,33 @@ speed_factor(double effspd, int tech)
{
return 480.0 / (effspd + techfact(tech, effspd));
}
/* Minimal efficiency for railway and railway extension (opt_RAILWAYS) */
#define SCT_RAIL_EFF 5
#define SCT_RAIL_EXT_EFF 60
/* Is sector SP a railway? */
#define SCT_IS_RAILWAY(sp) \
(dchr[(sp)->sct_type].d_mob1 == 0 && (sp)->sct_effic >= SCT_RAIL_EFF)
/* May sector SP have a railway extension? */
#define SCT_MAY_HAVE_RAIL_EXT(sp) \
((sp)->sct_effic >= SCT_RAIL_EXT_EFF)
/* Does railway sector SP extend railway track into sector TOSP? */
#define SCT_EXTENDS_RAIL(sp, tosp) \
((sp)->sct_own == (tosp)->sct_own && SCT_MAY_HAVE_RAIL_EXT(tosp))
int
sct_rail_track(struct sctstr *sp)
{
int i, res;
struct sctstr *nsp;
res = !!SCT_IS_RAILWAY(sp);
for (i = DIR_FIRST; i <= DIR_LAST; i++) {
nsp = getsectp(sp->sct_x + diroff[i][0],
sp->sct_y + diroff[i][1]);
if (SCT_IS_RAILWAY(nsp) && SCT_EXTENDS_RAIL(nsp, sp))
res++;
}
return res;
}

View file

@ -145,7 +145,7 @@ nstr_exec_val(struct valstr *val, natid cnum, void *ptr, enum nsc_type want)
val->val_as.lng = -1;
if (CANT_HAPPEN(((struct natstr *)ptr)->ef_type != EF_NATION))
break;
if (!opt_HIDDEN && cnum != NATID_BAD) {
if (opt_HIDDEN && cnum != NATID_BAD) {
natp = getnatp(cnum);
if (natp->nat_stat != STAT_GOD
&& !(getcontact(natp, idx) && getcontact(ptr, idx)))

View file

@ -218,8 +218,7 @@ bp_neighbors(struct as_coord c, struct as_coord *cp, void *pp)
move through it. We calculate it later. */
if (dchr[sp->sct_type].d_mob0 < 0)
continue;
if (bp->bp_mobtype == MOB_RAIL
&& (!intrchr[INT_RAIL].in_enable || sp->sct_rail == 0))
if (bp->bp_mobtype == MOB_RAIL && !SCT_HAS_RAIL(sp))
continue;
if (sp->sct_own != from->sct_own)
continue;

View file

@ -47,6 +47,7 @@
static void *nsc_ver(struct valstr *, struct natstr *, void *);
static void *nsc_ver_maxnoc(struct valstr *, struct natstr *, void *);
static void *nsc_sct_track(struct valstr *, struct natstr *, void *);
static void *nsc_pln_att(struct valstr *, struct natstr *, void *);
static void *nsc_pln_def(struct valstr *, struct natstr *, void *);
static void *nsc_lnd_att(struct valstr *, struct natstr *, void *);
@ -153,6 +154,7 @@ struct castr sect_ca[] = {
{"uran", fldoff(sct_uran), NSC_UCHAR, 0, NULL, EF_BAD, 0},
{"oldown", fldoff(sct_oldown), NSC_NATID, 0, NULL, EF_NATION, 0},
{"off", fldoff(sct_off), NSC_UCHAR, 0, NULL, EF_BAD, 0},
{"track", 0, NSC_LONG, 0, nsc_sct_track, EF_BAD, NSC_EXTRA},
NSC_IVEC(fldoff(sct_item), ""),
NSC_IVEC(fldoff(sct_dist), "_dist"),
NSC_IVEC(fldoff(sct_del), "_del"),
@ -178,6 +180,7 @@ struct castr dchr_ca[] = {
{"uid", fldoff(d_uid), NSC_UCHAR, 0, NULL, EF_SECTOR_CHR, 0},
{"name", fldoff(d_name), NSC_STRING, 0, NULL, EF_BAD, 0},
{"mnem", fldoff(d_mnem), NSC_STRINGY, 1, NULL, EF_BAD, NSC_CONST},
{"terrain", fldoff(d_terrain), NSC_UCHAR, 0, NULL, EF_SECTOR_CHR, 0},
{"prd", fldoff(d_prd), NSC_INT, 0, NULL, EF_PRODUCT, 0},
{"peffic", fldoff(d_peffic), NSC_INT, 0, NULL, EF_BAD, 0},
{"mob0", fldoff(d_mob0), NSC_FLOAT, 0, NULL, EF_BAD, 0},
@ -764,6 +767,13 @@ nsc_ver_maxnoc(struct valstr *val, struct natstr *np, void *ptr)
return NULL;
}
static void *
nsc_sct_track(struct valstr *val, struct natstr *np, void *ptr)
{
val->val_as.lng = sct_rail_track(ptr);
return NULL;
}
static void *
nsc_pln_def(struct valstr *val, struct natstr *np, void *ptr)
{

View file

@ -49,6 +49,7 @@ int opt_GUINEA_PIGS = 0;
int opt_HIDDEN = 0;
int opt_INTERDICT_ATT = 1;
int opt_LANDSPIES = 1;
int opt_LIMBER = 0;
int opt_LOANS = 1;
int opt_LOSE_CONTACT = 0;
int opt_MARKET = 0;
@ -58,6 +59,7 @@ int opt_NOMOBCOST = 1;
int opt_NO_FORT_FIRE = 0;
int opt_NO_PLAGUE = 1;
int opt_PINPOINTMISSILE = 1;
int opt_RAILWAYS = 0;
int opt_RES_POP = 0;
int opt_SAIL = 1;
int opt_SHOWPLANE = 1;

View file

@ -28,7 +28,7 @@
# sect.config: Sector characteristics
#
# Known contributors to this file:
# Markus Armbruster, 2006
# Markus Armbruster, 2006-2008
#
# Derived from sect.c; known contributors:
# Dave Pare, 1986
@ -38,14 +38,19 @@
# Steve McClure, 1998
#
# Sector terrain (column terra) is the uid of the underlying terrain
# sector type. Sector types that occur in that column are terrain
# types, and must have themselves as terrain.
# Available products (column prd) are in product.config. Navigation
# types (column nav) are in sector_navigation[]. Packing types
# (column pkg) are in packing[].
# Players can only designate sectors with a non-negative value in
# column cost. All such sectors should have the same population limit
# (column maxp), or else players can abuse redesignation to
# mass-murder people.
# column cost, and only to something with the same terrain. All
# sectors with the same terrain and non-negative cost should have the
# same population limit (column maxp), or else players can abuse
# redesignation to mass-murder people.
# A sector with urban packing (urba in column pkg) is a big city.
# Column maxp applies at 0% efficiency. The limit at 100% is ten
@ -56,41 +61,41 @@
# econfig key custom_tables.
config sect-chr
uid mnem prd peff mob0 mob1 nav pkg ostr dstr val cost bui lcm hcm maxp name
0 "." -1 0 -1 -1 sea norm 0.0 0.0 0 -1 0 0 0 0 "sea"
1 "^" dust 75 2.4 1.2 land norm 1.0 4.0 5 -1 1 0 0 100 "mountain"
2 "s" -1 0 -1 -1 land norm 0.0 99.0 127 -1 0 0 0 1000 "sanctuary"
3 "\134" -1 0 -1 -1 land norm 0.0 99.0 0 -1 0 0 0 0 "wasteland"
4 "-" -1 0 0.4 0.4 land norm 1.0 2.0 1 0 0 0 0 1000 "wilderness"
uid mnem terra prd peff mob0 mob1 nav pkg ostr dstr val cost bui lcm hcm maxp name
0 "." 0 -1 0 -1 -1 sea norm 0.0 0.0 0 -1 0 0 0 0 "sea"
1 "^" 1 dust 75 2.4 1.2 land norm 1.0 4.0 5 -1 1 0 0 100 "mountain"
2 "s" 4 -1 0 -1 -1 land norm 0.0 99.0 127 -1 0 0 0 1000 "sanctuary"
3 "\134" 3 -1 0 -1 -1 land norm 0.0 99.0 0 -1 0 0 0 0 "wasteland"
4 "-" 4 -1 0 0.4 0.4 land norm 1.0 2.0 1 0 0 0 0 1000 "wilderness"
# Uncomment one of the following two. The second one is for big cities.
5 "c" -1 0 0.4 0.2 land norm 1.0 2.0 30 0 1 0 0 1000 "capital"
# 5 "c" -1 0 0.4 0.2 cana urba 1.0 2.0 30 0 10 1 2 1000 "city"
6 "u" rad 100 0.4 0.2 land norm 1.0 2.0 15 0 1 0 0 1000 "uranium mine"
7 "p" hap 100 0.4 0.2 land norm 1.0 1.5 5 0 1 0 0 1000 "park"
8 "d" gun 100 0.4 0.2 land norm 1.0 1.5 7 0 1 0 0 1000 "defense plant"
9 "i" sh 100 0.4 0.2 land norm 1.0 1.5 6 0 1 0 0 1000 "shell industry"
10 "m" iron 100 0.4 0.2 land norm 1.0 2.0 5 0 1 0 0 1000 "mine"
11 "g" dust 100 0.4 0.2 land norm 1.0 2.0 8 0 1 0 0 1000 "gold mine"
12 "h" -1 0 0.4 0.2 harb ware 1.0 1.5 12 0 1 0 0 1000 "harbor"
13 "w" -1 0 0.4 0.2 land ware 1.0 1.5 7 0 1 0 0 1000 "warehouse"
14 "*" -1 0 0.4 0.2 land norm 1.0 1.25 12 0 1 0 0 1000 "airfield"
15 "a" food 900 0.4 0.2 land norm 1.0 1.5 2 0 1 0 0 1000 "agribusiness"
16 "o" oil 100 0.4 0.2 land norm 1.0 1.5 5 0 1 0 0 1000 "oil field"
17 "j" lcm 100 0.4 0.2 land norm 1.0 1.5 3 0 1 0 0 1000 "light manufacturing"
18 "k" hcm 100 0.4 0.2 land norm 1.0 1.5 4 0 1 0 0 1000 "heavy manufacturing"
19 "f" -1 0 0.4 0.2 land norm 2.0 4.0 10 0 5 0 1 1000 "fortress"
20 "t" tech 100 0.4 0.2 land norm 1.0 1.5 10 0 1 0 0 1000 "technical center"
21 "r" med 100 0.4 0.2 land norm 1.0 1.5 9 0 1 0 0 1000 "research lab"
22 "n" -1 0 0.4 0.2 land norm 1.0 2.0 10 0 1 0 0 1000 "nuclear plant"
23 "l" edu 100 0.4 0.2 land norm 1.0 1.5 4 0 1 0 0 1000 "library/school"
24 "+" -1 0 0.4 0.0 land norm 1.0 1.0 3 0 1 0 0 1000 "highway"
25 ")" -1 0 0.4 0.2 land norm 1.0 1.5 4 0 1 0 0 1000 "radar installation"
26 "!" -1 0 0.4 0.2 land norm 1.0 1.5 12 0 1 0 0 1000 "headquarters"
27 "#" -1 0 0.4 0.0 land norm 1.0 1.0 3 0 1 0 0 1000 "bridge head"
28 "=" -1 0 0.4 0.0 brid norm 1.0 1.0 5 -1 1 0 0 100 "bridge span"
29 "b" bars 100 0.4 0.2 land bank 1.0 2.25 10 0 1 0 0 1000 "bank"
30 "%" pet 1000 0.4 0.2 land norm 1.0 1.5 2 0 1 0 0 1000 "refinery"
31 "e" -1 0 0.4 0.2 land norm 1.0 2.0 7 0 1 0 0 1000 "enlistment center"
32 "~" -1 0 0.4 0.2 land norm 1.0 1.5 1 -1 1 0 0 100 "plains"
33 "@" -1 0 0.4 0.0 land norm 1.0 1.5 4 -1 1 0 0 100 "bridge tower"
5 "c" 4 -1 0 0.4 0.2 land norm 1.0 2.0 30 0 1 0 0 1000 "capital"
# 5 "c" 4 -1 0 0.4 0.2 cana urba 1.0 2.0 30 0 10 1 2 1000 "city"
6 "u" 4 rad 100 0.4 0.2 land norm 1.0 2.0 15 0 1 0 0 1000 "uranium mine"
7 "p" 4 hap 100 0.4 0.2 land norm 1.0 1.5 5 0 1 0 0 1000 "park"
8 "d" 4 gun 100 0.4 0.2 land norm 1.0 1.5 7 0 1 0 0 1000 "defense plant"
9 "i" 4 sh 100 0.4 0.2 land norm 1.0 1.5 6 0 1 0 0 1000 "shell industry"
10 "m" 4 iron 100 0.4 0.2 land norm 1.0 2.0 5 0 1 0 0 1000 "mine"
11 "g" 4 dust 100 0.4 0.2 land norm 1.0 2.0 8 0 1 0 0 1000 "gold mine"
12 "h" 4 -1 0 0.4 0.2 harb ware 1.0 1.5 12 0 1 0 0 1000 "harbor"
13 "w" 4 -1 0 0.4 0.2 land ware 1.0 1.5 7 0 1 0 0 1000 "warehouse"
14 "*" 4 -1 0 0.4 0.2 land norm 1.0 1.25 12 0 1 0 0 1000 "airfield"
15 "a" 4 food 900 0.4 0.2 land norm 1.0 1.5 2 0 1 0 0 1000 "agribusiness"
16 "o" 4 oil 100 0.4 0.2 land norm 1.0 1.5 5 0 1 0 0 1000 "oil field"
17 "j" 4 lcm 100 0.4 0.2 land norm 1.0 1.5 3 0 1 0 0 1000 "light manufacturing"
18 "k" 4 hcm 100 0.4 0.2 land norm 1.0 1.5 4 0 1 0 0 1000 "heavy manufacturing"
19 "f" 4 -1 0 0.4 0.2 land norm 2.0 4.0 10 0 5 0 1 1000 "fortress"
20 "t" 4 tech 100 0.4 0.2 land norm 1.0 1.5 10 0 1 0 0 1000 "technical center"
21 "r" 4 med 100 0.4 0.2 land norm 1.0 1.5 9 0 1 0 0 1000 "research lab"
22 "n" 4 -1 0 0.4 0.2 land norm 1.0 2.0 10 0 1 0 0 1000 "nuclear plant"
23 "l" 4 edu 100 0.4 0.2 land norm 1.0 1.5 4 0 1 0 0 1000 "library/school"
24 "+" 4 -1 0 0.4 0.0 land norm 1.0 1.0 3 0 1 0 0 1000 "highway"
25 ")" 4 -1 0 0.4 0.2 land norm 1.0 1.5 4 0 1 0 0 1000 "radar installation"
26 "!" 4 -1 0 0.4 0.2 land norm 1.0 1.5 12 0 1 0 0 1000 "headquarters"
27 "#" 4 -1 0 0.4 0.0 land norm 1.0 1.0 3 0 1 0 0 1000 "bridge head"
28 "=" 0 -1 0 0.4 0.0 brid norm 1.0 1.0 5 -1 1 0 0 100 "bridge span"
29 "b" 4 bars 100 0.4 0.2 land bank 1.0 2.25 10 0 1 0 0 1000 "bank"
30 "%" 4 pet 1000 0.4 0.2 land norm 1.0 1.5 2 0 1 0 0 1000 "refinery"
31 "e" 4 -1 0 0.4 0.2 land norm 1.0 2.0 7 0 1 0 0 1000 "enlistment center"
32 "~" 32 -1 0 0.4 0.2 land norm 1.0 1.5 1 -1 1 0 0 100 "plains"
33 "@" 0 -1 0 0.4 0.0 land norm 1.0 1.5 4 -1 1 0 0 100 "bridge tower"
/config

View file

@ -38,6 +38,7 @@
#include "com.h"
#include "empio.h"
#include "file.h"
#include "journal.h"
#include "match.h"
#include "misc.h"
#include "nat.h"
@ -102,6 +103,7 @@ dispatch(char *buf, char *redir)
uprnf(buf);
pr("\n");
}
journal_command(command->c_form);
switch (command->c_addr()) {
case RET_OK:
player->btused += command->c_cost;

View file

@ -110,9 +110,8 @@ player_main(struct player *p)
}
while (status()) {
if (command() == 0 && !player->aborted)
break;
player->aborted = 0;
command();
player->aborted = player->eof;
empth_yield();
}
/* #*# I put the following line in to prevent server crash -KHS */
@ -157,13 +156,9 @@ status(void)
int old_nstat, minute;
char buf[128];
if (player->state == PS_SHUTDOWN)
if (player->eof || player->state == PS_SHUTDOWN)
return 0;
natp = getnatp(player->cnum);
if (io_error(player->iop) || io_eof(player->iop)) {
putnat(natp);
return 0;
}
if (player->dolcost > 100.0)
pr("That just cost you $%.2f\n", player->dolcost);
else if (player->dolcost < -100.0)

View file

@ -46,10 +46,11 @@
* Else receive one line and store it in CMD[SIZE].
* This may block for input, yielding the processor. Flush buffered
* output when blocking, to make sure player sees the prompt.
* If the player's connection has the I/O error indicator set, or the
* line is "aborted", set the player's aborted flag and return -2.
* If the player's connection has the EOF indicator set, or the line
* is "ctld", set the player's eof flag and return -1.
* If the player's connection has the I/O error or EOF indicator set,
* or the line is "ctld", set the player's eof and aborted flag and
* return -1.
* If the line is "aborted", set the player's aborted flag and return
* -2.
* Else return the length of the line.
* Design bug: there is no way to indicate truncation of a long line.
*/
@ -59,13 +60,13 @@ recvclient(char *cmd, int size)
int count;
count = -1;
while (!player->aborted && !player->eof) {
while (!player->aborted) {
/* Try to get a line of input */
count = io_gets(player->iop, cmd, size);
if (count >= 0) {
/* got it */
if (strcmp(cmd, "ctld") == 0)
player->eof = 1;
player->aborted = player->eof = 1;
if (strcmp(cmd, "aborted") == 0)
player->aborted = 1;
journal_input(cmd);
@ -84,16 +85,23 @@ recvclient(char *cmd, int size)
/* Await more input */
io_input(player->iop, IO_WAIT);
if (io_error(player->iop))
player->aborted = 1;
else if (io_eof(player->iop))
player->eof = 1;
if (io_error(player->iop) || io_eof(player->iop))
player->aborted = player->eof = 1;
}
if (player->eof)
return -1;
if (player->aborted)
return -2;
if (player->aborted) {
player->recvfail++;
if (player->recvfail > 255) {
/*
* Looks like the thread is stuck in a loop that fails to
* check errors; oops once, then slow it down drastically.
*/
CANT_HAPPEN(player->recvfail == 256);
empth_sleep(time(NULL) + 60);
}
return player->eof ? -1 : -2;
}
player->recvfail = 0;
return count;
}

View file

@ -770,12 +770,18 @@ ac_doflak(struct emp_qelem *list, struct sctstr *from)
gun = MIN(FLAK_GUN_MAX, from->sct_item[I_GUN]);
shell = from->sct_item[I_SHELL];
#if 0
/*
* FIXME can supply from itself, causing seqno mismatch oops
* further down
*/
if (gun > shell * 2) {
shell += supply_commod(from->sct_own, from->sct_x, from->sct_y,
I_SHELL, (gun + 1) / 2 - shell);
from->sct_item[I_SHELL] = shell;
putsect(from);
}
#endif
if (gun > shell * 2)
gun = shell * 2;
@ -823,12 +829,19 @@ ac_shipflak(struct emp_qelem *list, coord x, coord y)
gun = shp_usable_guns(&ship);
if (gun) {
shell = ship.shp_item[I_SHELL];
#if 0
/*
* FIXME if this supplies the ship while it is being
* interdicted, we get a seqno mismatch when interdiction
* damage is applied.
*/
if (shell <= 0) {
shell = supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
I_SHELL, 1);
ship.shp_item[I_SHELL] = shell;
putship(ship.shp_uid, &ship);
}
#endif
}
if (gun == 0 || shell == 0)
continue;

View file

@ -461,6 +461,7 @@ att_abort(int combat_mode, struct combat *off, struct combat *def)
if (att_get_combat(off, 0) < 0)
return abort_attack();
if (off->type == EF_SHIP &&
!(off->x == def->x && off->y == def->y) &&
(!getsect(off->x, off->y, &sect) ||
sect.sct_type != SCT_WATER)) {
pr("%s can not %s from that far inland!\n",
@ -1007,6 +1008,12 @@ ask_olist(int combat_mode, struct combat *off, struct combat *def,
pr("Land units are not able to board this kind of ship\n");
return;
}
if (def->type == EF_SHIP
&& (def->shp_mcp->m_flags & (M_SUPPLY | M_SUB)) != M_SUPPLY
&& !(lcp->l_flags & L_LIGHT)) {
pr("Only light land units can board this kind of ship\n");
continue;
}
if (land.lnd_mobil <= 0) {
pr("%s is out of mobility, and cannot %s\n",
prland(&land), att_mode[combat_mode]);
@ -1229,11 +1236,8 @@ get_dlist(struct combat *def, struct emp_qelem *list, int a_spy,
continue;
if (def->type == EF_LAND && land.lnd_land != def->lnd_uid)
continue;
if (!list) { /* Just estimating the enemy strength */
intelligence_report(player->cnum, &land, a_spy,
"Scouts report defending unit:");
continue;
}
if (!(llp = malloc(sizeof(struct ulist)))) {
logerror("Malloc failed in attack!\n");
abort_attack();

View file

@ -70,7 +70,7 @@ bridge_damaged(struct sctstr *sp)
des = sp->sct_type;
if (des == SCT_BSPAN || des == SCT_BTOWER)
knockdown(sp);
if ((des == SCT_BHEAD || des == SCT_BTOWER) && !opt_EASY_BRIDGES)
if (IS_BRIDGE_HEAD(des) && !opt_EASY_BRIDGES)
bridgefall(sp);
}
@ -98,17 +98,16 @@ bridgefall(struct sctstr *sp)
if (nnx == sp->sct_x && nny == sp->sct_y)
continue;
getsect(nnx, nny, &bh_sect);
if (bh_sect.sct_type == SCT_BHEAD &&
bh_sect.sct_newtype == SCT_BHEAD)
break;
if (bh_sect.sct_type == SCT_BTOWER)
break;
/* With EASY_BRIDGES, it just has to be next to any
land */
if (opt_EASY_BRIDGES) {
if (bh_sect.sct_type != SCT_WATER &&
bh_sect.sct_type != SCT_BSPAN)
break;
} else {
if (IS_BRIDGE_HEAD(bh_sect.sct_type)
&& bh_sect.sct_newtype == bh_sect.sct_type)
break;
}
}
if (j > 6) {

View file

@ -43,7 +43,9 @@
* prng NAME SEED
* login CNUM HOSTADDR USER
* logout CNUM
* command NAME
* input INPUT
* output THREAD ID OUTPUT
* update ETU
*/
@ -64,6 +66,9 @@
static char journal_fname[] = "journal.log";
static FILE *journal;
static void journal_entry(char *fmt, ...) ATTRIBUTE((format (printf, 1, 2)));
static void journal_output_1(struct player *, int, char *, char *, int);
static FILE *
journal_open(void)
{
@ -80,7 +85,11 @@ journal_entry(char *fmt, ...)
if (journal) {
time(&now);
fprintf(journal, "%.24s %p ", ctime(&now), empth_self());
fprintf(journal, "%.24s ", ctime(&now));
if (player && player->state == PS_PLAYING)
fprintf(journal, "%d ", player->cnum);
else
fprintf(journal, "%p ", empth_self());
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
@ -93,6 +102,7 @@ journal_entry(char *fmt, ...)
fprintf(journal, "\\%03o", *p);
}
fputs("\n", journal);
if (fmt[0] != 'o') /* FIXME disgusting hack */
fflush(journal);
if (ferror(journal)) {
logerror("Error writing journal (%s)", strerror(errno));
@ -162,12 +172,61 @@ journal_logout(void)
journal_entry("logout %d", player->cnum);
}
void
journal_output(struct player *pl, int id, char *output)
{
static char buf[1024];
static struct player *bpl;
static int bid;
char *s, *e;
if (keep_journal < 2)
return;
if (buf[0] && (pl != bpl && id != bid)) {
journal_output_1(bpl, bid, buf, "", -1);
buf[0] = 0;
}
for (s = output; (e = strchr(s, '\n')); s = e + 1) {
journal_output_1(pl, id, buf, s, (int)(e + 1 - s));
buf[0] = 0;
}
if (strlen(buf) + strlen(s) < 1024) {
strcpy(buf + strlen(buf), s);
bpl = pl;
bid = id;
} else {
journal_output_1(pl, id, buf, s, -1);
buf[0] = 0;
}
}
void
journal_output_1(struct player *pl, int id,
char *buf1, char *buf2, int buf2prec)
{
if (pl && pl->state == PS_PLAYING)
journal_entry("output %d %d %s%.*s",
pl->cnum, id, buf1, buf2prec, buf2);
else
journal_entry("output %p %id %s%.*s",
pl, id, buf1, buf2prec, buf2);
}
void
journal_input(char *input)
{
journal_entry("input %s", input);
}
void
journal_command(char *cmd)
{
char *eptr = strchr(cmd, ' ');
journal_entry("command %.*s", eptr ? (int)(eptr - cmd) : -1, cmd);
}
void
journal_update(int etu)
{

View file

@ -207,6 +207,7 @@ lnd_fire(struct lndstr *lp)
I_SHELL, ammo - shells);
if (shells == 0)
return -1;
lnd_unlimber(lp);
d = landunitgun(lp->lnd_effic, guns);
if (shells < ammo) {
d *= (double)shells / (double)ammo;
@ -287,7 +288,11 @@ shp_torp_hitchance(struct shpstr *sp, int range)
double
lnd_fire_range(struct lndstr *lp)
{
return effrange(lnd_frg(lp), lp->lnd_tech);
struct sctstr sect;
getsect(lp->lnd_x, lp->lnd_y, &sect);
return effrange(lnd_frg(lp), lp->lnd_tech)
+ (sect.sct_type == SCT_MOUNT ? 0.5 : 0.0);
}
int

View file

@ -991,7 +991,7 @@ lnd_mar_one_sector(struct emp_qelem *list, int dir, natid actor,
continue;
}
}
if ((!intrchr[INT_RAIL].in_enable || sect.sct_rail == 0)
if (!SCT_HAS_RAIL(&sect)
&& lnd_mobtype(&llp->unit.land) == MOB_RAIL) {
if (together) {
pr("no rail system in %s\n", xyas(newx, newy, actor));
@ -1126,6 +1126,9 @@ lnd_support(natid victim, natid attacker, coord x, coord y, int defending)
while (nxtitem(&ni, &land)) {
if ((land.lnd_x == x) && (land.lnd_y == y))
continue;
/* Too ponderous for defensive support */
if (defending && (lchr[(int)land.lnd_type].l_flags & L_HEAVY))
continue;
rel = getrel(getnatp(land.lnd_own), attacker);
rel2 = getrel(getnatp(land.lnd_own), victim);
if ((land.lnd_own != attacker) &&
@ -1170,31 +1173,81 @@ lnd_can_attack(struct lndstr *lp)
return 1;
}
/*
* Return mobility required to unlimber LP.
*/
static double
lnd_mob_to_unlimber(struct lndstr *lp)
{
struct lchrstr *lcp = &lchr[(int)lp->lnd_type];
if (!opt_LIMBER || lcp->l_dam == 0 || lp->lnd_harden != 0)
return 0;
if (lnd_spd(lp) < 22
|| (lcp->l_flags & (L_HEAVY | L_TRAIN)) == (L_HEAVY | L_TRAIN)) {
/*
* Slow artillery is towed and needs to be unlimbered.
* Heavy railway guns need to be assembled.
*/
return lnd_pathcost(lp, 0.2);
}
return 0;
}
/*
* Unlimber land unit LP.
* No effect unless LP is limbered artillery.
*/
void
lnd_unlimber(struct lndstr *lp)
{
double unlimber_mob, mult, newmob;
unlimber_mob = lnd_mob_to_unlimber(lp);
if (unlimber_mob == 0)
return;
mult = has_helpful_engineer(lp->lnd_x, lp->lnd_y, lp->lnd_own)
? 1.5 : 1.0;
newmob = lp->lnd_mobil - (1 + unlimber_mob) / mult;
lp->lnd_mobil = (signed char)MAX(-127, floor(newmob));
CANT_HAPPEN(lp->lnd_harden != 0);
lp->lnd_harden = 1;
}
/*
* Increase fortification value of LP.
* Fortification costs mobility. Use up to MOB mobility.
* Automatically unlimbers.
* Return actual fortification increase.
*/
int
lnd_fortify(struct lndstr *lp, int mob)
{
int hard_amt;
double mob_used, mult;
double mob_used, unlimber_mob, mult;
if (lp->lnd_ship >= 0 || lp->lnd_land >= 0)
return 0;
mob_used = MIN(lp->lnd_mobil, mob);
if (mob_used < 0)
return 0;
mult = has_helpful_engineer(lp->lnd_x, lp->lnd_y, lp->lnd_own)
? 1.5 : 1.0;
unlimber_mob = lnd_mob_to_unlimber(lp);
hard_amt = (int)(mob_used * mult - unlimber_mob);
if (hard_amt < 1)
/*
* FIXME unlimber_mob > land_mob_max breaks fortify command
* FIXME > etu_per_update * land_mob_scale breaks auto-fort. at update
*/
return 0;
hard_amt = (int)(mob_used * mult);
if (lp->lnd_harden + hard_amt > land_mob_max) {
hard_amt = land_mob_max - lp->lnd_harden;
mob_used = ceil(hard_amt / mult);
mob_used = ceil((hard_amt + unlimber_mob) / mult);
}
lp->lnd_mobil -= (int)mob_used;

View file

@ -344,10 +344,10 @@ build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
if (getrel(getnatp(gp->own), sect.sct_own) > AT_WAR) {
/*
* If the player->owner of the unit isn't at war
* If the owner of the unit isn't at war
* with the victim, and doesn't own the
* sect being acted upon, and isn't the
* old player->owner of that sect, bounce them.
* old owner of that sect, bounce them.
*/
if (sect.sct_type != SCT_WATER &&
sect.sct_own != gp->own &&
@ -412,6 +412,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
natid plane_owner = 0;
int md, range, air_dam = 0;
double prb, hitchance, vrange;
int targeting_ships = *s == 's'; /* "subs" or "ships" FIXME gross! */
getsect(x, y, &sect);
@ -436,6 +437,10 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
(md > land_max_interdiction_range))
continue;
/* Too ponderous for interdiction fire */
if (lchr[(int)lp->lnd_type].l_flags & L_HEAVY)
continue;
range = roundrange(lnd_fire_range(lp));
if (md > range)
continue;
@ -445,12 +450,12 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
if (dam2 < 0)
continue;
if (sect.sct_type == SCT_WATER) {
if (targeting_ships) {
if (chance(lnd_acc(lp) / 100.0))
dam2 = ldround(dam2 / 2.0, 1);
}
dam += dam2;
if (sect.sct_type == SCT_WATER)
if (targeting_ships)
nreport(lp->lnd_own, N_SHP_SHELL, victim, 1);
else
nreport(lp->lnd_own, N_SCT_SHELL, victim, 1);
@ -487,10 +492,8 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
continue;
}
if (mcp->m_flags & M_SUB) {
/* If we aren't shooting at "subs" or "ships" don't fire at all from
a sub. */
if (*s != 's')
continue;
if (!targeting_ships)
continue; /* subs interdict only ships */
range = roundrange(torprange(sp));
if (md > range)
continue;
@ -547,7 +550,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
if (chance(prb))
dam2 /= 2;
dam += dam2;
if (sect.sct_type == SCT_WATER)
if (targeting_ships)
nreport(sp->shp_own, N_SHP_SHELL, victim, 1);
else
nreport(sp->shp_own, N_SCT_SHELL, victim, 1);
@ -680,7 +683,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
if (air_dam > 0) {
dam += air_dam;
if (sect.sct_type == SCT_WATER)
if (targeting_ships)
nreport(plane_owner, N_SHP_BOMB, victim, 1);
else
nreport(plane_owner, N_SCT_BOMB, victim, 1);

View file

@ -194,6 +194,9 @@ msl_sel(struct emp_qelem *list, coord x, coord y, natid victim,
continue;
if (mission && plane.pln_mission != mission)
continue;
if (mission &&
plane.pln_radius < mapdist(x, y, plane.pln_opx, plane.pln_opy))
continue;
if (getrel(getnatp(plane.pln_own), victim) >= NEUTRAL)
continue;
/* missiles go one way, so we can use all the range */

View file

@ -111,7 +111,7 @@ delete_old_news(void)
for (j = 0; getnews(i + j, &news); j++) {
if (news.nws_vrb == 0)
break;
news.nws_uid = j;
ef_set_uid(EF_NEWS, &news, j);
putnews(j, &news);
}
CANT_HAPPEN(i + j != news_tail);

View file

@ -89,6 +89,9 @@ nuk_prewrite(int n, void *ptr)
}
getnuke(n, &nuke);
if (nuke.nuk_plane != np->nuk_plane)
logerror("phantom nuke debug: nuk#%d plane %d->%d",
np->nuk_uid, nuke.nuk_plane, np->nuk_plane);
return 1;
}

View file

@ -132,6 +132,9 @@ pln_prewrite(int n, void *ptr)
}
}
getplane(n, &plane);
if (plane.pln_nuketype != pp->pln_nuketype)
logerror("phantom nuke debug: pln#%d nuketype %d->%d",
pp->pln_uid, plane.pln_nuketype, pp->pln_nuketype);
return 1;
}

View file

@ -559,6 +559,7 @@ pln_arm(struct emp_qelem *list, int dist, char mission, struct ichrstr *ip,
next = qp->q_forw;
plp = (struct plist *)qp;
pp = &plp->plane;
getplane(pp->pln_uid, pp);
if ((pp->pln_flags & PLN_LAUNCHED)
|| pln_equip(plp, ip, flags, mission) < 0) {
emp_remque(qp);

View file

@ -56,6 +56,7 @@
#include "com.h"
#include "empio.h"
#include "file.h"
#include "journal.h"
#include "misc.h"
#include "nat.h"
#include "player.h"
@ -124,6 +125,7 @@ pr_id(struct player *p, int id, char *format, ...)
if (p->curid >= 0) {
io_puts(p->iop, "\n");
journal_output(p, p->curid, "\n");
p->curid = -1;
}
va_start(ap, format);
@ -245,6 +247,7 @@ pr_player(struct player *pl, int id, char *buf)
bp += len;
}
}
journal_output(pl, id, buf);
}
/*
@ -299,6 +302,7 @@ upr_player(struct player *pl, int id, char *buf)
io_puts(pl->iop, printbuf);
}
}
journal_output(pl, id, buf);
}
/*

View file

@ -251,6 +251,7 @@ retreat_ship1(struct shpstr *sp, char code, int orig)
getsect(newx, newy, &sect);
if (shp_check_nav(&sect, sp) != CN_NAVIGABLE ||
(sect.sct_own && sect.sct_own != sp->shp_own &&
sect.sct_type != SCT_BSPAN &&
getrel(getnatp(sect.sct_own), sp->shp_own) < FRIENDLY)) {
wu(0, sp->shp_own, "%s %s,\nbut could not retreat to %s!\n",
prship(sp), conditions[findcondition(code)].desc[orig],

View file

@ -177,15 +177,8 @@ satmap(int x, int y, int eff, int range, int flags, int type)
}
/* If we are imaging *and* drawing the map */
if ((flags & P_I) && (type == EF_BAD)) {
/* Figure out where to put the ship */
/* First, figure out the distance from the two */
rx = diffx((int)ship.shp_x, x);
ry = diffy((int)ship.shp_y, y);
/* Next, determine which direction to add it to the center */
/* We can only do this if imaging and we have gotten the center
up above by imaging the sectors. */
rx = deltax(x, ns.range.lx) + rx;
ry = deltay(y, ns.range.ly) + ry;
rx = deltx(&ns.range, ship.shp_x);
ry = delty(&ns.range, ship.shp_y);
/* &~0x20 makes it a cap letter */
rad[ry][rx] = (*mchr[(int)ship.shp_type].m_name) & ~0x20;
}
@ -230,15 +223,8 @@ satmap(int x, int y, int eff, int range, int flags, int type)
}
/* If we are imaging *and* drawing the map */
if ((flags & P_I) && (type == EF_BAD)) {
/* Figure out where to put the unit */
/* First, figure out the distance from the two */
rx = diffx((int)land.lnd_x, x);
ry = diffy((int)land.lnd_y, y);
/* Next, determine which direction to add it to the center */
/* We can only do this if imaging and we have gotten the center
up above by imaging the sectors. */
rx = deltax(x, ns.range.lx) + rx;
ry = deltay(y, ns.range.ly) + ry;
rx = deltx(&ns.range, land.lnd_x);
ry = delty(&ns.range, land.lnd_y);
/* &~0x20 makes it a cap letter */
rad[ry][rx] = (*lchr[(int)land.lnd_type].l_name) & ~0x20;
}
@ -285,7 +271,7 @@ satdisp_sect(struct sctstr *sp, int acc)
dchr[sp->sct_type].d_mnem,
sp->sct_own, roundintby((int)sp->sct_effic, acc / 2),
roundintby((int)sp->sct_road, acc / 2),
roundintby((int)sp->sct_rail, acc / 2),
opt_RAILWAYS ? !!sct_rail_track(sp) : roundintby(sp->sct_rail, acc / 2),
roundintby((int)sp->sct_defense, acc / 2),
roundintby(sp->sct_item[I_CIVIL], acc),
roundintby(sp->sct_item[I_MILIT], acc),

View file

@ -237,13 +237,13 @@ shp_sweep(struct emp_qelem *ship_list, int verbose, int takemob, natid actor)
}
sect.sct_mines = mines;
mlp->unit.ship.shp_item[I_SHELL] = shells;
putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
putsect(&sect);
if (shp_check_one_mines(mlp)) {
stopping = 1;
emp_remque(qp);
free(qp);
}
putship(mlp->unit.ship.shp_uid, &mlp->unit.ship);
putsect(&sect);
}
if (changed)
writemap(actor);
@ -753,6 +753,7 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor,
navigate = shp_check_nav(&sect, &mlp->unit.ship);
if (navigate != CN_NAVIGABLE ||
(sect.sct_own && actor != sect.sct_own &&
sect.sct_type != SCT_BSPAN &&
getrel(getnatp(sect.sct_own), actor) < FRIENDLY)) {
if (dchr[sect.sct_type].d_nav == NAV_CANAL &&
!(((struct mchrstr *)mlp->chrp)->m_flags & M_CANAL) &&
@ -867,12 +868,18 @@ shp_missile_defense(coord dx, coord dy, natid bombown, int hardtarget)
shell = ship.shp_item[I_SHELL];
if (ship.shp_item[I_MILIT] < 1) /* do we have mil? */
continue;
#if 0
/*
* FIXME can supply from itself, causing seqno mismatch oops
* further down
*/
if (shell < 2) { /* do we need shells */
shell += supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
I_SHELL, 2);
if (shell < 2)
continue;
}
#endif
if (ship.shp_item[I_GUN] < 1) /* we need at least 1 gun */
continue;

View file

@ -124,7 +124,7 @@ resupply_commod(struct lndstr *lp, i_type type)
int
supply_commod(int own, int x, int y, i_type type, int total_wanted)
{
if (total_wanted < 0)
if (total_wanted <= 0)
return 0;
return s_commod(own, x, y, type, total_wanted, !player->simulation);
}
@ -135,7 +135,7 @@ supply_commod(int own, int x, int y, i_type type, int total_wanted)
static int
try_supply_commod(int own, int x, int y, i_type type, int total_wanted)
{
if (total_wanted < 0)
if (total_wanted <= 0)
return 0;
return s_commod(own, x, y, type, total_wanted, 0);
@ -361,6 +361,7 @@ s_commod(int own, int x, int y, i_type type, int total_wanted,
save = land;
land.lnd_item[type] = 0;
putland(land.lnd_uid, &land);
save.lnd_seqno = land.lnd_seqno;
land.lnd_item[type] =
save.lnd_item[type] + s_commod(own, land.lnd_x, land.lnd_y,

View file

@ -35,6 +35,13 @@
#include "update.h"
int
age_people(int n, int etu)
{
/* age by 1% per 24 etus */
return roundavg(n * (1.0 - etu / 2400.0));
}
void
age_levels(int etu)
{
@ -43,7 +50,6 @@ age_levels(int etu)
int i;
double level;
double delta;
int deltares;
best_tech = 0.0;
best_res = 0.0;
@ -61,14 +67,7 @@ age_levels(int etu)
delta = np->nat_level[NAT_TLEV] * etu / (100 * level_age_rate);
np->nat_level[NAT_TLEV] -= delta;
}
/*
* age reserves by 1% per every 24 etus
*/
deltares = -roundavg(np->nat_reserve * etu / 2400.0);
if (deltares != 0)
np->nat_reserve += deltares;
/* Chad Zabel - above number is negative ( was a -= there
which was wrong. */
np->nat_reserve = age_people(np->nat_reserve, etu);
}
best_tech /= 5;
best_res /= 5;

View file

@ -61,6 +61,7 @@ do_feed(struct sctstr *sp, struct natstr *np, short *vec,
int starved, sctwork;
int needed;
int maxpop;
int manna;
/* grow people & stuff */
sctwork = sp->sct_work;
@ -72,12 +73,16 @@ do_feed(struct sctstr *sp, struct natstr *np, short *vec,
maxpop));
if (sp->sct_type != SCT_SANCT) {
manna = 0;
if (opt_NOFOOD == 0) {
needed = (int)ceil(food_needed(vec, etu));
if (vec[I_FOOD] < needed) {
/* need to grow "emergency rations" */
work_avail -= 2 * growfood(sp, vec, work_avail / 2, etu);
/* It's twice as hard to grow those than norm */
if (vec[I_FOOD] == 0)
/* Conjure up 1f to make life easier for the player */
manna = vec[I_FOOD] = 1;
}
if (vec[I_FOOD] < needed && sp->sct_own == sp->sct_oldown) {
/* steal food from warehouses, headquarters,
@ -109,7 +114,21 @@ do_feed(struct sctstr *sp, struct natstr *np, short *vec,
if (!player->simulation)
sp->sct_work = sctwork;
grow_people(sp, etu, np, &work_avail, sctwork, vec);
/* age che */
if (!player->simulation) {
int oldche = sp->sct_che;
sp->sct_che = age_people(sp->sct_che, etu);
if (sp->sct_che_target == sp->sct_own && sp->sct_loyal < 40)
/* make them fade away eventually, for playability */
sp->sct_che /= 2;
if (sp->sct_che != oldche)
logerror("che in %d,%d aged from %d to %d",
sp->sct_x, sp->sct_y, oldche, sp->sct_che);
}
}
if (manna)
/* Take away food we conjured up */
vec[I_FOOD] = 0;
} else
sctwork = sp->sct_work = 100;
/* Here is where we truncate extra people, always */
@ -141,13 +160,7 @@ growfood(struct sctstr *sp, short *vec, int work, int etu)
food = MIN(food_workers, food_fertil);
if (food > ITEM_MAX - vec[I_FOOD])
food = ITEM_MAX - vec[I_FOOD];
/*
* Be nice; grow minimum one food unit.
* This makes life simpler for the player.
*/
vec[I_FOOD] += food;
if (vec[I_FOOD] == 0)
vec[I_FOOD] = 1;
work_used = food / fcrate;
return work_used;
}

View file

@ -157,7 +157,8 @@ upd_ship(struct shpstr *sp, int etus,
/* produce oil */
if (np->nat_money >= 0
&& (mp->m_flags & M_OIL) && sectp->sct_type == SCT_WATER) {
&& (mp->m_flags & M_OIL) && sectp->sct_type == SCT_WATER
&& sp->shp_mobil >= ship_mob_max) {
product = &pchr[dchr[SCT_OIL].d_prd];
oil_gained = roundavg(total_work(100, etus,
sp->shp_item[I_CIVIL],

View file

@ -1098,6 +1098,7 @@ write_sects(void)
sct->sct_type = SCT_MOUNT;
sct->sct_elev = total;
sct->sct_newtype = sct->sct_type;
sct->sct_dterr = own[sct->sct_x][y] + 1;
if (ORE)
add_resources(sct);
sct++;

View file

@ -155,6 +155,7 @@ main(int argc, char *argv[])
for (i = 1; i < MAXNOC; i++) {
nat.ef_type = EF_NATION;
nat.nat_cnum = nat.nat_uid = i;
nat.nat_seqno = 0;
putnat((&nat));
}
memset(&realm, 0, sizeof(realm));
@ -164,6 +165,7 @@ main(int argc, char *argv[])
for (j = 0; j < MAXNOR; j++) {
realm.r_realm = j;
realm.r_uid = (i * MAXNOR) + j;
realm.r_seqno = 0;
putrealm(&realm);
}
}
@ -209,6 +211,7 @@ file_sct_init(coord x, coord y, struct sctstr *ptr)
sp->ef_type = EF_SECTOR;
sp->sct_uid = XYOFFSET(x, y);
sp->sct_seqno = 0;
sp->sct_x = x;
sp->sct_y = y;
sp->sct_dist_x = x;