"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,
"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,
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);
extern int sct_postread(int, void *);
extern int sct_prewrite(int, void *);
extern void item_prewrite(short *);
+extern void set_railway(struct sctstr *);
extern int issector(char *);
/* sectdamage.c */
extern int sect_damage(struct sctstr *, int);
* 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);
natid sct_oldown; /* old owner of sector (for liberation) */
unsigned char sct_updated; /* Has this sect been updated? */
unsigned char sct_off; /* Should this sector produce? */
+ unsigned char sct_track; /* nearby railways (RAILWAYS) */
short sct_item[I_MAX+1]; /* amount of items stored here */
short sct_del[I_MAX+1]; /* delivieries */
short sct_dist[I_MAX+1]; /* distribution thresholds */
#define FORTEFF 5 /* forts must be 5% efficient to fire. */
+/* Can trains enter sector SP? */
+#define SCT_HAS_RAIL(sp) \
+ (opt_RAILWAYS ? (sp)->sct_track != 0 \
+ : intrchr[INT_RAIL].in_enable && (sp)->sct_rail != 0)
+
#define MOB_MOVE 0
#define MOB_MARCH 1
#define MOB_RAIL 2
--- /dev/null
+.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 Io 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
+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 have amtraks,
+artilley 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 \*Qinfo
+Railroad\*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 need construction
+materials to build efficiency. Ever seen Fort Knox? Bridges are
+cheaper than usual.
+.s1
+Food is much harder to grow. Expect 20% of your population to be
+farmers.
+.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
+New experimental option AUTO_POWER is enabled: the power report is
+only updated automatically, at the update. No more tactical abuse.
+.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/
+.s1
+.SA "Introduction, Server"
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"
--- /dev/null
+.TH Concept "Railroad"
+.NA Railroad "How railroads work"
+.LV Expert
+Trains are land units with capability \*Qtrain\*U.
+.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 reports show the rail infrastructure efficiency in colum \*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. Sector selector track gives the number of operational
+railways within one sector range. This number is also shown by spy
+report column \*Qrl eff\*U. To visualize your railway network, try
+\*Qsect # ?track#0\*U.
+.s1
+.SA "LandUnits"
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.
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
.FI
.s1
.SA "land, LandUnits"
-
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;
pr("Klick! ...\n");
continue;
}
+
+ lnd_unlimber(&fland);
if (target == targ_ship) {
if (chance(lnd_acc(&fland) / 100.0))
dam = ldround(dam / 2.0, 1);
/* 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);
if (dam2 < 0)
continue;
+ lnd_unlimber(&land);
(*nfiring)++;
if (!fp)
add_to_flist(list, (struct empobj *)&land, dam2, 0);
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;
pr("%4d%% ", sect.sct_effic);
pr("%4d%% ", sect.sct_road);
prmobcost(§, MOB_MOVE);
- pr("%4d%% ", sect.sct_rail);
+ if (opt_RAILWAYS)
+ pr(sect.sct_track ? " yes " : " no ");
+ else
+ pr("%4d%% ", sect.sct_rail);
prmobcost(§, MOB_RAIL);
pr("%4d%% ", SCT_DEFENSE(§));
pr("%5.2f\n", sector_strength(§));
sp->sct_oldown,
roundintby((int)sp->sct_effic, 10),
roundintby((int)sp->sct_road, 10),
- roundintby((int)sp->sct_rail, 10),
+ opt_RAILWAYS ? !!sp->sct_track : 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),
#include "misc.h"
#include "nat.h"
+#include "optlist.h"
#include "path.h"
#include "sect.h"
#include "xy.h"
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))
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;
{"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", fldoff(sct_track), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA},
NSC_IVEC(fldoff(sct_item), ""),
NSC_IVEC(fldoff(sct_dist), "_dist"),
NSC_IVEC(fldoff(sct_del), "_del"),
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;
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;
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, §);
+ return effrange(lnd_frg(lp), lp->lnd_tech)
+ + (sect.sct_type == SCT_MOUNT ? 0.5 : 0.0);
}
int
continue;
}
}
- if ((!intrchr[INT_RAIL].in_enable || sect.sct_rail == 0)
+ if (!SCT_HAS_RAIL(§)
&& lnd_mobtype(&llp->unit.land) == MOB_RAIL) {
if (together) {
pr("no rail system in %s\n", xyas(newx, newy, actor));
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) &&
if (dam2 < 0)
continue;
+ lnd_unlimber(&land);
if (defending)
nreport(land.lnd_own, N_FIRE_BACK, victim, 1);
else
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;
(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;
if (dam2 < 0)
continue;
+ lnd_unlimber(lp);
if (sect.sct_type == SCT_WATER) {
if (chance(lnd_acc(lp) / 100.0))
dam2 = ldround(dam2 / 2.0, 1);
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 ? !!sp->sct_track : 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),
#include "nat.h"
#include "nsc.h"
#include "optlist.h"
+#include "path.h"
#include "plane.h"
#include "player.h"
#include "prototypes.h"
#include "xy.h"
static int checksect(struct sctstr *);
+static void update_railway(struct sctstr *, struct sctstr *);
int
sct_postread(int id, void *ptr)
bridge_damaged(sp);
checksect(sp);
getsect(sp->sct_x, sp->sct_y, §);
+ if (opt_RAILWAYS)
+ update_railway(sp, §);
return 1;
}
return 1;
}
+/* 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))
+
+static void
+update_railway(struct sctstr *sp, struct sctstr *oldsp)
+{
+ struct sctstr sect;
+ int was_railway = SCT_IS_RAILWAY(oldsp);
+ int is_railway = SCT_IS_RAILWAY(sp);
+ int i;
+
+ if (was_railway == is_railway
+ && sp->sct_own == oldsp->sct_own
+ && SCT_MAY_HAVE_RAIL_EXT(sp) == SCT_MAY_HAVE_RAIL_EXT(oldsp))
+ return;
+
+ if (was_railway)
+ sp->sct_track--;
+ if (is_railway)
+ sp->sct_track++;
+
+ for (i = DIR_FIRST; i <= DIR_LAST; i++) {
+ getsect(sp->sct_x + diroff[i][0],
+ sp->sct_y + diroff[i][1],
+ §);
+ if (SCT_IS_RAILWAY(§) && SCT_EXTENDS_RAIL(§, oldsp))
+ sp->sct_track--;
+ if (SCT_IS_RAILWAY(§) && SCT_EXTENDS_RAIL(§, sp))
+ sp->sct_track++;
+ if (was_railway && SCT_EXTENDS_RAIL(oldsp, §))
+ sect.sct_track--;
+ if (is_railway && SCT_EXTENDS_RAIL(sp, §))
+ sect.sct_track++;
+ putsect(§);
+ }
+}
+
+void
+set_railway(struct sctstr *sp)
+{
+ int i;
+ struct sctstr *nsp;
+
+ sp->sct_track = !!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))
+ sp->sct_track++;
+ }
+}
+
int
issector(char *arg)
{
#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)
{
int i;
double level;
double delta;
- int deltares;
best_tech = 0.0;
best_res = 0.0;
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;
/* Wipe it clean */
memset(g_distptrs, 0, WORLD_SZ() * sizeof(*g_distptrs));
+ if (opt_RAILWAYS) {
+ for (n = 0; NULL != (sp = getsectid(n)); n++)
+ set_railway(sp);
+ }
+
logerror("delivering...\n");
/* Do deliveries */
for (n = 0; NULL != (sp = getsectid(n)); n++) {
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);
+ }
}
} else
sctwork = sp->sct_work = 100;
/* 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],