From 5d0f5e69ee13ec6315827f1d46d6833519c03057 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 19 Jan 2008 15:19:13 +0100 Subject: [PATCH 01/54] 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. --- include/econfig-spec.h | 4 ++ include/land.h | 1 + include/prototypes.h | 2 + include/sect.h | 6 +++ info/Hvy-Metal.t | 97 ++++++++++++++++++++++++++++++++++++++++ info/Options.t | 5 +++ info/Railroad.t | 25 +++++++++++ info/Unit-types.t | 11 ++++- src/lib/commands/mfir.c | 12 +++++ src/lib/commands/miss.c | 7 ++- src/lib/commands/sinf.c | 5 ++- src/lib/commands/spy.c | 2 +- src/lib/common/move.c | 7 +++ src/lib/common/path.c | 3 +- src/lib/global/nsc.c | 1 + src/lib/global/options.c | 2 + src/lib/subs/landgun.c | 6 ++- src/lib/subs/lndsub.c | 68 +++++++++++++++++++++++++--- src/lib/subs/mission.c | 5 +++ src/lib/subs/satmap.c | 2 +- src/lib/subs/sect.c | 67 +++++++++++++++++++++++++++ src/lib/update/age.c | 17 ++++--- src/lib/update/finish.c | 5 +++ src/lib/update/human.c | 11 +++++ src/lib/update/ship.c | 3 +- 25 files changed, 349 insertions(+), 25 deletions(-) create mode 100644 info/Hvy-Metal.t create mode 100644 info/Railroad.t diff --git a/include/econfig-spec.h b/include/econfig-spec.h index bc4ccc6a..d426e58a 100644 --- a/include/econfig-spec.h +++ b/include/econfig-spec.h @@ -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, diff --git a/include/land.h b/include/land.h index f3923066..feb47c6a 100644 --- a/include/land.h +++ b/include/land.h @@ -190,6 +190,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); diff --git a/include/prototypes.h b/include/prototypes.h index 5edadd96..a82f9f7a 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -627,6 +627,7 @@ extern void sathead(void); 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); @@ -710,6 +711,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); diff --git a/include/sect.h b/include/sect.h index c0d78222..da0e9cb1 100644 --- a/include/sect.h +++ b/include/sect.h @@ -76,6 +76,7 @@ struct sctstr { 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 */ @@ -181,6 +182,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 ? (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 diff --git a/info/Hvy-Metal.t b/info/Hvy-Metal.t new file mode 100644 index 00000000..95ca4392 --- /dev/null +++ b/info/Hvy-Metal.t @@ -0,0 +1,97 @@ +.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" diff --git a/info/Options.t b/info/Options.t index 07f165c5..99450c9c 100644 --- a/info/Options.t +++ b/info/Options.t @@ -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" diff --git a/info/Railroad.t b/info/Railroad.t new file mode 100644 index 00000000..f4ae420f --- /dev/null +++ b/info/Railroad.t @@ -0,0 +1,25 @@ +.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" diff --git a/info/Unit-types.t b/info/Unit-types.t index 1a0cca53..5c956734 100644 --- a/info/Unit-types.t +++ b/info/Unit-types.t @@ -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" - diff --git a/src/lib/commands/mfir.c b/src/lib/commands/mfir.c index 0e0aa697..88ec909a 100644 --- a/src/lib/commands/mfir.c +++ b/src/lib/commands/mfir.c @@ -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,8 @@ multifire(void) pr("Klick! ...\n"); continue; } + + lnd_unlimber(&fland); if (target == targ_ship) { if (chance(lnd_acc(&fland) / 100.0)) dam = ldround(dam / 2.0, 1); @@ -687,6 +695,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); @@ -708,6 +719,7 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown, if (dam2 < 0) continue; + lnd_unlimber(&land); (*nfiring)++; if (!fp) add_to_flist(list, (struct empobj *)&land, dam2, 0); diff --git a/src/lib/commands/miss.c b/src/lib/commands/miss.c index abf9d16f..f44656db 100644 --- a/src/lib/commands/miss.c +++ b/src/lib/commands/miss.c @@ -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; diff --git a/src/lib/commands/sinf.c b/src/lib/commands/sinf.c index e17cf3f7..e316f982 100644 --- a/src/lib/commands/sinf.c +++ b/src/lib/commands/sinf.c @@ -73,7 +73,10 @@ sinfra(void) 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(§)); diff --git a/src/lib/commands/spy.c b/src/lib/commands/spy.c index 291ab46b..8c3151f3 100644 --- a/src/lib/commands/spy.c +++ b/src/lib/commands/spy.c @@ -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 ? !!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), diff --git a/src/lib/common/move.c b/src/lib/common/move.c index 18d748fe..f3377fe6 100644 --- a/src/lib/common/move.c +++ b/src/lib/common/move.c @@ -35,6 +35,7 @@ #include "misc.h" #include "nat.h" +#include "optlist.h" #include "path.h" #include "sect.h" #include "xy.h" @@ -48,6 +49,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)) diff --git a/src/lib/common/path.c b/src/lib/common/path.c index 61bf4e7b..53149a6e 100644 --- a/src/lib/common/path.c +++ b/src/lib/common/path.c @@ -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; diff --git a/src/lib/global/nsc.c b/src/lib/global/nsc.c index 205ae005..a67edc5c 100644 --- a/src/lib/global/nsc.c +++ b/src/lib/global/nsc.c @@ -153,6 +153,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", 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"), diff --git a/src/lib/global/options.c b/src/lib/global/options.c index 02753e45..67dd12be 100644 --- a/src/lib/global/options.c +++ b/src/lib/global/options.c @@ -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; diff --git a/src/lib/subs/landgun.c b/src/lib/subs/landgun.c index 151679a4..a6a21da9 100644 --- a/src/lib/subs/landgun.c +++ b/src/lib/subs/landgun.c @@ -287,7 +287,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, §); + return effrange(lnd_frg(lp), lp->lnd_tech) + + (sect.sct_type == SCT_MOUNT ? 0.5 : 0.0); } int diff --git a/src/lib/subs/lndsub.c b/src/lib/subs/lndsub.c index 395ffcf2..578c1af0 100644 --- a/src/lib/subs/lndsub.c +++ b/src/lib/subs/lndsub.c @@ -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(§) && 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) && @@ -1144,6 +1147,7 @@ lnd_support(natid victim, natid attacker, coord x, coord y, int defending) if (dam2 < 0) continue; + lnd_unlimber(&land); if (defending) nreport(land.lnd_own, N_FIRE_BACK, victim, 1); else @@ -1170,31 +1174,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; diff --git a/src/lib/subs/mission.c b/src/lib/subs/mission.c index e038c12c..340f2f57 100644 --- a/src/lib/subs/mission.c +++ b/src/lib/subs/mission.c @@ -436,6 +436,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,6 +449,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list, 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); diff --git a/src/lib/subs/satmap.c b/src/lib/subs/satmap.c index cc4b06db..8e5fcb4f 100644 --- a/src/lib/subs/satmap.c +++ b/src/lib/subs/satmap.c @@ -285,7 +285,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 ? !!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), diff --git a/src/lib/subs/sect.c b/src/lib/subs/sect.c index 541b9b9b..87dd3fed 100644 --- a/src/lib/subs/sect.c +++ b/src/lib/subs/sect.c @@ -42,6 +42,7 @@ #include "nat.h" #include "nsc.h" #include "optlist.h" +#include "path.h" #include "plane.h" #include "player.h" #include "prototypes.h" @@ -49,6 +50,7 @@ #include "xy.h" static int checksect(struct sctstr *); +static void update_railway(struct sctstr *, struct sctstr *); int sct_postread(int id, void *ptr) @@ -71,6 +73,8 @@ sct_prewrite(int id, void *ptr) bridge_damaged(sp); checksect(sp); getsect(sp->sct_x, sp->sct_y, §); + if (opt_RAILWAYS) + update_railway(sp, §); return 1; } @@ -128,6 +132,69 @@ checksect(struct sctstr *sp) 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) { diff --git a/src/lib/update/age.c b/src/lib/update/age.c index 29dca549..98cecaab 100644 --- a/src/lib/update/age.c +++ b/src/lib/update/age.c @@ -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; diff --git a/src/lib/update/finish.c b/src/lib/update/finish.c index da03cee1..8c2693ce 100644 --- a/src/lib/update/finish.c +++ b/src/lib/update/finish.c @@ -87,6 +87,11 @@ finish_sects(int etu) /* 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++) { diff --git a/src/lib/update/human.c b/src/lib/update/human.c index 1a7b1c5f..9206edf1 100644 --- a/src/lib/update/human.c +++ b/src/lib/update/human.c @@ -109,6 +109,17 @@ 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); + } } } else sctwork = sp->sct_work = 100; diff --git a/src/lib/update/ship.c b/src/lib/update/ship.c index 59546ddb..cccbe260 100644 --- a/src/lib/update/ship.c +++ b/src/lib/update/ship.c @@ -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], From 9f1b4e2c814524cf54d1a074f1ee51063a71049c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 19 Jan 2008 15:25:04 +0100 Subject: [PATCH 02/54] Document Hvy Metal refinery p.e. --- info/Hvy-Metal.t | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/info/Hvy-Metal.t b/info/Hvy-Metal.t index 95ca4392..4be6ba12 100644 --- a/info/Hvy-Metal.t +++ b/info/Hvy-Metal.t @@ -23,7 +23,7 @@ guard it carefully. 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 +artillery firing ranges differ, few units are light (but troop transports and landing ships can carry non-light units), food capacities are reduced. .s1 @@ -70,6 +70,8 @@ cheaper than usual. Food is much harder to grow. Expect 20% of your population to be farmers. .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 From e3658ff2f02fcc7e680645386e69848659321554 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 12 Feb 2008 07:10:33 +0100 Subject: [PATCH 03/54] Remove hard-coded differences between highways and bridge heads Let highways build and support bridges. Allow bridge heads anywhere, not just on the coast. --- include/sect.h | 3 +++ src/lib/commands/buil.c | 10 ++++------ src/lib/commands/desi.c | 7 ++----- src/lib/subs/bridgefall.c | 11 +++++------ 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/include/sect.h b/include/sect.h index da0e9cb1..60fb72b7 100644 --- a/include/sect.h +++ b/include/sect.h @@ -170,6 +170,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 diff --git a/src/lib/commands/buil.c b/src/lib/commands/buil.c index c9ea788a..bb3d2d6e 100644 --- a/src/lib/commands/buil.c +++ b/src/lib/commands/buil.c @@ -528,12 +528,10 @@ 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) - return 0; - if (sp->sct_newtype != SCT_BHEAD) - return 0; - } + if (!IS_BRIDGE_HEAD(sp->sct_type)) + return 0; + if (sp->sct_newtype != sp->sct_type) + return 0; } if (sp->sct_effic < 60 && !player->god) { diff --git a/src/lib/commands/desi.c b/src/lib/commands/desi.c index cee4e2d8..ce14be61 100644 --- a/src/lib/commands/desi.c +++ b/src/lib/commands/desi.c @@ -97,7 +97,7 @@ desi(void) 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,11 +129,8 @@ 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(§); - } } if (changed) writemap(player->cnum); diff --git a/src/lib/subs/bridgefall.c b/src/lib/subs/bridgefall.c index f407f32f..624b0a95 100644 --- a/src/lib/subs/bridgefall.c +++ b/src/lib/subs/bridgefall.c @@ -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) { From 2aec870a145af4fed8f9f9231ddc745b0ad9724a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2008 20:54:08 +0100 Subject: [PATCH 04/54] 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. --- include/sect.h | 1 + src/lib/commands/add.c | 9 +--- src/lib/commands/desi.c | 5 +++ src/lib/global/nsc.c | 1 + src/lib/global/sect.config | 85 ++++++++++++++++++++------------------ 5 files changed, 54 insertions(+), 47 deletions(-) diff --git a/include/sect.h b/include/sect.h index 60fb72b7..d8a109af 100644 --- a/include/sect.h +++ b/include/sect.h @@ -103,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 */ diff --git a/src/lib/commands/add.c b/src/lib/commands/add.c index eba4d33e..fb83eacb 100644 --- a/src/lib/commands/add.c +++ b/src/lib/commands/add.c @@ -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)); diff --git a/src/lib/commands/desi.c b/src/lib/commands/desi.c index ce14be61..20e27863 100644 --- a/src/lib/commands/desi.c +++ b/src/lib/commands/desi.c @@ -92,6 +92,11 @@ 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; diff --git a/src/lib/global/nsc.c b/src/lib/global/nsc.c index a67edc5c..c2bd8faa 100644 --- a/src/lib/global/nsc.c +++ b/src/lib/global/nsc.c @@ -179,6 +179,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}, diff --git a/src/lib/global/sect.config b/src/lib/global/sect.config index 2e4032fd..4608ce6e 100644 --- a/src/lib/global/sect.config +++ b/src/lib/global/sect.config @@ -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 From dc9d847b8ba8bcf7da2ca7b47695abf51745f3eb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 21 Mar 2008 14:22:07 +0100 Subject: [PATCH 05/54] 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(). --- include/commodity.h | 1 + include/empobj.h | 1 + include/file.h | 2 + include/game.h | 1 + include/land.h | 1 + include/loan.h | 1 + include/lost.h | 1 + include/nat.h | 2 + include/news.h | 1 + include/nuke.h | 1 + include/plane.h | 1 + include/sect.h | 1 + include/ship.h | 1 + include/trade.h | 1 + include/treaty.h | 1 + src/lib/commands/edit.c | 6 +-- src/lib/commands/swap.c | 4 +- src/lib/common/file.c | 110 +++++++++++++++++++++++++++++++++++----- src/lib/subs/nreport.c | 2 +- src/util/files.c | 3 ++ 20 files changed, 124 insertions(+), 18 deletions(-) diff --git a/include/commodity.h b/include/commodity.h index c3757661..d515364e 100644 --- a/include/commodity.h +++ b/include/commodity.h @@ -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 */ diff --git a/include/empobj.h b/include/empobj.h index 2610c18e..63931c10 100644 --- a/include/empobj.h +++ b/include/empobj.h @@ -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 */ diff --git a/include/file.h b/include/file.h index 79517784..9d724f65 100644 --- a/include/file.h +++ b/include/file.h @@ -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); diff --git a/include/game.h b/include/game.h index 8a52509c..1a343c7f 100644 --- a/include/game.h +++ b/include/game.h @@ -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? */ diff --git a/include/land.h b/include/land.h index feb47c6a..73ca0b82 100644 --- a/include/land.h +++ b/include/land.h @@ -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 */ diff --git a/include/loan.h b/include/loan.h index 542af6c8..d18c4d88 100644 --- a/include/loan.h +++ b/include/loan.h @@ -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 */ diff --git a/include/lost.h b/include/lost.h index c371f936..1bb93079 100644 --- a/include/lost.h +++ b/include/lost.h @@ -41,6 +41,7 @@ struct loststr { /* initial part must match struct empobj */ short ef_type; int 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 */ diff --git a/include/nat.h b/include/nat.h index b2f2bd5f..58b8067f 100644 --- a/include/nat.h +++ b/include/nat.h @@ -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 */ diff --git a/include/news.h b/include/news.h index c7361144..5665a92f 100644 --- a/include/news.h +++ b/include/news.h @@ -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 # */ diff --git a/include/nuke.h b/include/nuke.h index 2f7fcdaa..054cdb4c 100644 --- a/include/nuke.h +++ b/include/nuke.h @@ -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 */ diff --git a/include/plane.h b/include/plane.h index 2133f362..485ebb51 100644 --- a/include/plane.h +++ b/include/plane.h @@ -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 */ diff --git a/include/sect.h b/include/sect.h index d8a109af..408b1600 100644 --- a/include/sect.h +++ b/include/sect.h @@ -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 */ diff --git a/include/ship.h b/include/ship.h index 1f7fbf8a..d09a07b0 100644 --- a/include/ship.h +++ b/include/ship.h @@ -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 */ diff --git a/include/trade.h b/include/trade.h index 307f990b..074a77da 100644 --- a/include/trade.h +++ b/include/trade.h @@ -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 */ diff --git a/include/treaty.h b/include/treaty.h index d5efd77e..31491eef 100644 --- a/include/treaty.h +++ b/include/treaty.h @@ -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 */ diff --git a/src/lib/commands/edit.c b/src/lib/commands/edit.c index 52279b84..cabcbabf 100644 --- a/src/lib/commands/edit.c +++ b/src/lib/commands/edit.c @@ -584,7 +584,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, §, XYOFFSET(newx, newy)); break; case 'D': if (!sarg_xy(p, &newx, &newy)) @@ -767,7 +767,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 +871,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_SHIP, land, arg); break; case 'O': if (land->lnd_own) diff --git a/src/lib/commands/swap.c b/src/lib/commands/swap.c index a28b8991..309977c5 100644 --- a/src/lib/commands/swap.c +++ b/src/lib/commands/swap.c @@ -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, §a, 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, §b, tmp.sct_uid); sectb.sct_dist_x = tmp.sct_x; sectb.sct_dist_y = tmp.sct_y; sectb.sct_coastal = tmp.sct_coastal; diff --git a/src/lib/common/file.c b/src/lib/common/file.c index 9586bc4d..ce13d14b 100644 --- a/src/lib/common/file.c +++ b/src/lib/common/file.c @@ -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 int 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,68 @@ ef_write(int type, int id, void *from) return 1; } +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); +} + +static int +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; +} + +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 0 + if (CANT_HAPPEN(old_seqno != elt->seqno)) + old_seqno = MAX(old_seqno, elt->seqno); +#else + if (old_seqno != elt->seqno) { + logerror("seqno mismatch ef_type=%d uid=%d: %d!=%d", + ep->uid, elt->uid, old_seqno, elt->seqno); + old_seqno = MAX(old_seqno, elt->seqno); + } +#endif + elt->seqno = old_seqno + 1; +} + /* * Extend table TYPE by COUNT elements. * Any pointers obtained from ef_ptr() become invalid. @@ -504,9 +582,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); + } } /* diff --git a/src/lib/subs/nreport.c b/src/lib/subs/nreport.c index 8a53cbee..2dffb268 100644 --- a/src/lib/subs/nreport.c +++ b/src/lib/subs/nreport.c @@ -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); diff --git a/src/util/files.c b/src/util/files.c index 4618ba6e..a7c802b7 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -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; From 95298986cc17d5b106508770f3820bdc54237447 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 1 Apr 2008 20:17:52 +0200 Subject: [PATCH 06/54] 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(). --- src/lib/update/human.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib/update/human.c b/src/lib/update/human.c index 9206edf1..d36b9e15 100644 --- a/src/lib/update/human.c +++ b/src/lib/update/human.c @@ -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, @@ -121,6 +126,9 @@ do_feed(struct sctstr *sp, struct natstr *np, short *vec, 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 */ @@ -152,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; } From b437b7b5ecf8d5f57612698f1c665098def728c3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 5 Apr 2008 16:09:24 +0200 Subject: [PATCH 07/54] Make fairland record the island number in the deity territory Can be useful for deities when further customizing their game setup. --- src/util/fairland.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/fairland.c b/src/util/fairland.c index 8a5696d1..6e2e8eb3 100644 --- a/src/util/fairland.c +++ b/src/util/fairland.c @@ -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++; From 11100f23e5ba925da2e26c2f91dc3086635ef5a2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 5 Apr 2008 16:11:11 +0200 Subject: [PATCH 08/54] Update info Hvy-Metal for Hvy Metal II --- info/Hvy-Metal.t | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/info/Hvy-Metal.t b/info/Hvy-Metal.t index 4be6ba12..b9e8dedf 100644 --- a/info/Hvy-Metal.t +++ b/info/Hvy-Metal.t @@ -13,8 +13,8 @@ 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 +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 @@ -22,7 +22,7 @@ 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, +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. @@ -44,11 +44,12 @@ 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. +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 @@ -63,13 +64,25 @@ 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. +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 Your refineries make less petrol from each barrel of oil than usual. .s1 Natural resources gold, oil and uran deplete much slower than usual. @@ -94,6 +107,6 @@ for grabs. .s1 Source code and configuration is available from .br -http://www.stdio.com/~rhyatt/empire/hvy_metal/ +http://www.stdio.com/~rhyatt/empire/hvy_metal_II/ .s1 .SA "Introduction, Server" From fa5fa4abcc41ff4b11cce852e3aa30c735e659c8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Apr 2008 07:57:03 +0200 Subject: [PATCH 09/54] 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. --- Make.mk | 1 + include/prototypes.h | 1 - include/sect.h | 4 +-- src/lib/commands/sinf.c | 2 +- src/lib/commands/spy.c | 2 +- src/lib/common/move.c | 31 +++++++++++++++++++ src/lib/global/nsc.c | 10 +++++- src/lib/subs/satmap.c | 2 +- src/lib/subs/sect.c | 67 ----------------------------------------- src/lib/update/finish.c | 5 --- 10 files changed, 46 insertions(+), 79 deletions(-) diff --git a/Make.mk b/Make.mk index 97e44e5d..26985515 100644 --- a/Make.mk +++ b/Make.mk @@ -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)) diff --git a/include/prototypes.h b/include/prototypes.h index a82f9f7a..cc4fd26a 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -627,7 +627,6 @@ extern void sathead(void); 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); diff --git a/include/sect.h b/include/sect.h index 408b1600..b0237a3c 100644 --- a/include/sect.h +++ b/include/sect.h @@ -77,7 +77,6 @@ struct sctstr { 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 */ @@ -189,7 +188,7 @@ extern struct dchrstr bigcity_dchr; /* Can trains enter sector SP? */ #define SCT_HAS_RAIL(sp) \ - (opt_RAILWAYS ? (sp)->sct_track != 0 \ + (opt_RAILWAYS ? sct_rail_track((sp)) != 0 \ : intrchr[INT_RAIL].in_enable && (sp)->sct_rail != 0) #define MOB_MOVE 0 @@ -227,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 diff --git a/src/lib/commands/sinf.c b/src/lib/commands/sinf.c index e316f982..43780c6e 100644 --- a/src/lib/commands/sinf.c +++ b/src/lib/commands/sinf.c @@ -74,7 +74,7 @@ sinfra(void) pr("%4d%% ", sect.sct_road); prmobcost(§, MOB_MOVE); if (opt_RAILWAYS) - pr(sect.sct_track ? " yes " : " no "); + pr(sct_rail_track(§) ? " yes " : " no "); else pr("%4d%% ", sect.sct_rail); prmobcost(§, MOB_RAIL); diff --git a/src/lib/commands/spy.c b/src/lib/commands/spy.c index 8c3151f3..020b42c8 100644 --- a/src/lib/commands/spy.c +++ b/src/lib/commands/spy.c @@ -224,7 +224,7 @@ spyline(struct sctstr *sp) sp->sct_oldown, roundintby((int)sp->sct_effic, 10), roundintby((int)sp->sct_road, 10), - opt_RAILWAYS ? !!sp->sct_track : roundintby(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), diff --git a/src/lib/common/move.c b/src/lib/common/move.c index f3377fe6..7cbabf82 100644 --- a/src/lib/common/move.c +++ b/src/lib/common/move.c @@ -33,6 +33,7 @@ #include +#include "file.h" #include "misc.h" #include "nat.h" #include "optlist.h" @@ -90,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; +} diff --git a/src/lib/global/nsc.c b/src/lib/global/nsc.c index c2bd8faa..0abe19ac 100644 --- a/src/lib/global/nsc.c +++ b/src/lib/global/nsc.c @@ -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,7 +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", fldoff(sct_track), NSC_UCHAR, 0, NULL, EF_BAD, NSC_EXTRA}, + {"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"), @@ -766,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) { diff --git a/src/lib/subs/satmap.c b/src/lib/subs/satmap.c index 8e5fcb4f..f4def5df 100644 --- a/src/lib/subs/satmap.c +++ b/src/lib/subs/satmap.c @@ -285,7 +285,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), - opt_RAILWAYS ? !!sp->sct_track : roundintby(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), diff --git a/src/lib/subs/sect.c b/src/lib/subs/sect.c index 87dd3fed..541b9b9b 100644 --- a/src/lib/subs/sect.c +++ b/src/lib/subs/sect.c @@ -42,7 +42,6 @@ #include "nat.h" #include "nsc.h" #include "optlist.h" -#include "path.h" #include "plane.h" #include "player.h" #include "prototypes.h" @@ -50,7 +49,6 @@ #include "xy.h" static int checksect(struct sctstr *); -static void update_railway(struct sctstr *, struct sctstr *); int sct_postread(int id, void *ptr) @@ -73,8 +71,6 @@ sct_prewrite(int id, void *ptr) bridge_damaged(sp); checksect(sp); getsect(sp->sct_x, sp->sct_y, §); - if (opt_RAILWAYS) - update_railway(sp, §); return 1; } @@ -132,69 +128,6 @@ checksect(struct sctstr *sp) 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) { diff --git a/src/lib/update/finish.c b/src/lib/update/finish.c index 8c2693ce..da03cee1 100644 --- a/src/lib/update/finish.c +++ b/src/lib/update/finish.c @@ -87,11 +87,6 @@ finish_sects(int etu) /* 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++) { From 12e34aeeb4bf53f3841f8c4ccce6b51fe217fdf0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Apr 2008 08:05:46 +0200 Subject: [PATCH 10/54] Fix info Railroad on spy and satellite reports Fix explanation of "rl eff" value. Mention satellite report. --- info/Railroad.t | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/info/Railroad.t b/info/Railroad.t index f4ae420f..3f4d19f0 100644 --- a/info/Railroad.t +++ b/info/Railroad.t @@ -9,8 +9,8 @@ Unlike other units, trains can enter a sector only if it has 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. +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% @@ -18,8 +18,8 @@ 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. +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" From e917a60371f6966d05138466c010c9f2b3bd5009 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 21 Apr 2008 22:00:06 +0200 Subject: [PATCH 11/54] Trains can no longer be loaded on land units, update info Railroad --- info/Railroad.t | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/info/Railroad.t b/info/Railroad.t index 3f4d19f0..82e6eea1 100644 --- a/info/Railroad.t +++ b/info/Railroad.t @@ -1,7 +1,9 @@ .TH Concept "Railroad" .NA Railroad "How railroads work" .LV Expert -Trains are land units with capability \*Qtrain\*U. +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. From b313b61cd431b4260204ccf2b912b768efef0212 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 21 Apr 2008 22:03:36 +0200 Subject: [PATCH 12/54] Oops on sequence number mismatch Old code only logged this, for fear of false positives. --- src/lib/common/file.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/lib/common/file.c b/src/lib/common/file.c index ce13d14b..d89256a4 100644 --- a/src/lib/common/file.c +++ b/src/lib/common/file.c @@ -507,16 +507,8 @@ new_seqno(struct empfile *ep, void *buf) if (!(ep->flags & EFF_TYPED)) return; old_seqno = get_seqno(ep, elt->uid); -#if 0 if (CANT_HAPPEN(old_seqno != elt->seqno)) old_seqno = MAX(old_seqno, elt->seqno); -#else - if (old_seqno != elt->seqno) { - logerror("seqno mismatch ef_type=%d uid=%d: %d!=%d", - ep->uid, elt->uid, old_seqno, elt->seqno); - old_seqno = MAX(old_seqno, elt->seqno); - } -#endif elt->seqno = old_seqno + 1; } From f7d61817176b166a837961410026f1d028b3be24 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 24 Apr 2008 20:18:23 +0200 Subject: [PATCH 13/54] 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. --- src/lib/subs/aircombat.c | 6 ++++++ src/lib/subs/shpsub.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/lib/subs/aircombat.c b/src/lib/subs/aircombat.c index 11616ee9..106b7977 100644 --- a/src/lib/subs/aircombat.c +++ b/src/lib/subs/aircombat.c @@ -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; diff --git a/src/lib/subs/shpsub.c b/src/lib/subs/shpsub.c index 7ceebb7a..bcdd5869 100644 --- a/src/lib/subs/shpsub.c +++ b/src/lib/subs/shpsub.c @@ -867,12 +867,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; From 4e962406ff38fa2c44dd7f973bc3595925b3a475 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 24 Apr 2008 20:25:48 +0200 Subject: [PATCH 14/54] Let ships navigate bridge spans regardless of owner --- src/lib/subs/retreat.c | 1 + src/lib/subs/shpsub.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/lib/subs/retreat.c b/src/lib/subs/retreat.c index 57eceeae..b3fb5ef7 100644 --- a/src/lib/subs/retreat.c +++ b/src/lib/subs/retreat.c @@ -251,6 +251,7 @@ retreat_ship1(struct shpstr *sp, char code, int orig) getsect(newx, newy, §); if (shp_check_nav(§, 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], diff --git a/src/lib/subs/shpsub.c b/src/lib/subs/shpsub.c index bcdd5869..f5b90fd9 100644 --- a/src/lib/subs/shpsub.c +++ b/src/lib/subs/shpsub.c @@ -753,6 +753,7 @@ shp_nav_one_sector(struct emp_qelem *list, int dir, natid actor, navigate = shp_check_nav(§, &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) && From b707e2cca8837b53d77e72c95796724d0761b732 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 24 Apr 2008 20:38:57 +0200 Subject: [PATCH 15/54] Permit ships to assault the sector they're in Ships still have to be in a sea sector to assault an adjacent sector. --- src/lib/subs/attsub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/subs/attsub.c b/src/lib/subs/attsub.c index 5183b2a5..d3d6c5c3 100644 --- a/src/lib/subs/attsub.c +++ b/src/lib/subs/attsub.c @@ -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.sct_type != SCT_WATER)) { pr("%s can not %s from that far inland!\n", From cf4639fa7497dabc6f8bb9a6c3ef78ef70e88000 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 24 Apr 2008 21:13:06 +0200 Subject: [PATCH 16/54] Update info Hvy-Metal for Hvy Metal II --- info/Hvy-Metal.t | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/info/Hvy-Metal.t b/info/Hvy-Metal.t index b9e8dedf..d0919966 100644 --- a/info/Hvy-Metal.t +++ b/info/Hvy-Metal.t @@ -20,6 +20,10 @@ 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, @@ -83,6 +87,8 @@ 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. @@ -93,8 +99,8 @@ conserve oil. Resources are scarce. Expect to fight over them. 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. +Automatic shell supply for sector flak and ship missile defense is +disabled, because its bugs interfere with Hvy Metal modifications. .s1 Missed updates due to server problems will be forced if caught within 15 minutes of planned update time or skipped otherwise. From 05e5adfac83e42101025b395d2f414df022bce15 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 26 Apr 2008 09:53:47 +0200 Subject: [PATCH 17/54] 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 --- src/lib/subs/nuke.c | 3 +++ src/lib/subs/plane.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/lib/subs/nuke.c b/src/lib/subs/nuke.c index fe71e7ba..363621f3 100644 --- a/src/lib/subs/nuke.c +++ b/src/lib/subs/nuke.c @@ -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; } diff --git a/src/lib/subs/plane.c b/src/lib/subs/plane.c index aaaaf845..17554dd1 100644 --- a/src/lib/subs/plane.c +++ b/src/lib/subs/plane.c @@ -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; } From 8fe67826e6d7437e2f209659907b1f81a9604f45 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 5 May 2008 21:54:02 +0200 Subject: [PATCH 18/54] Avoid compiler warning --- src/lib/commands/mfir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/commands/mfir.c b/src/lib/commands/mfir.c index 88ec909a..68677b49 100644 --- a/src/lib/commands/mfir.c +++ b/src/lib/commands/mfir.c @@ -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) From e7aa3627c44926d9b1f23c1460ffb57027fdf85f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 5 May 2008 21:26:12 +0200 Subject: [PATCH 19/54] Fix edit command seqno oopses Broken by commit dc9d847b. --- src/lib/commands/edit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/commands/edit.c b/src/lib/commands/edit.c index cabcbabf..0b3108c0 100644 --- a/src/lib/commands/edit.c +++ b/src/lib/commands/edit.c @@ -871,7 +871,7 @@ dounit(char op, int arg, char *p, struct lndstr *land) land->lnd_land = arg; break; case 'U': - ef_set_uid(EF_SHIP, land, arg); + ef_set_uid(EF_LAND, land, arg); break; case 'O': if (land->lnd_own) @@ -994,7 +994,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)) From 312b28f5fa15a2e387c3588330d5c97178c28ef5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 10 May 2008 09:27:52 +0200 Subject: [PATCH 20/54] 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(). --- src/lib/subs/aircombat.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/subs/aircombat.c b/src/lib/subs/aircombat.c index 106b7977..ad6d8439 100644 --- a/src/lib/subs/aircombat.c +++ b/src/lib/subs/aircombat.c @@ -829,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; From 542460c7873fc92a07c3046dc1da77909ba2ed80 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 10 May 2008 12:48:24 +0200 Subject: [PATCH 21/54] Fix markup in info Hvy-Metal --- info/Hvy-Metal.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/info/Hvy-Metal.t b/info/Hvy-Metal.t index d0919966..beb74cdb 100644 --- a/info/Hvy-Metal.t +++ b/info/Hvy-Metal.t @@ -45,8 +45,8 @@ 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. +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 From 45a6b9a1d71de001a5f7c25b725e9fe71b64c3c7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 10 May 2008 12:49:02 +0200 Subject: [PATCH 22/54] Cover biofuel plant in info Quick-ref --- info/Quick-ref.t | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/info/Quick-ref.t b/info/Quick-ref.t index ea828824..df870788 100644 --- a/info/Quick-ref.t +++ b/info/Quick-ref.t @@ -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) From 5a2440c9d49a2aa5f8d34837a5b2beed40d84b7f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 7 May 2008 22:05:22 +0200 Subject: [PATCH 23/54] Fix origin command not to prompt twice for its argument Broken in commit b69173ee, v4.3.0. (cherry picked from commit 27c3466aa5669b442eca850495107aee8110c228) --- src/lib/commands/orig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/commands/orig.c b/src/lib/commands/orig.c index 4063893e..d8c91f76 100644 --- a/src/lib/commands/orig.c +++ b/src/lib/commands/orig.c @@ -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 */ From 6e69d6d9dea80a39685a312496d469d9d8988ac7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 10 May 2008 08:36:45 +0200 Subject: [PATCH 24/54] Fix xdump nat for relations Commit ee863c5d (v4.3.12) got opt_HIDDEN backwards in nstr_exec_val(). (cherry picked from commit 3dbb4dbb9364100d1e3862994202f2835c78ba5a) --- src/lib/common/nstreval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/common/nstreval.c b/src/lib/common/nstreval.c index 7c2f5e8b..10a44110 100644 --- a/src/lib/common/nstreval.c +++ b/src/lib/common/nstreval.c @@ -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))) From c083a252770f322f05d984525a451959e4e4bd0a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 10 May 2008 08:40:48 +0200 Subject: [PATCH 25/54] 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 a1f4dc95920e579432dfbd0e7664558f8c3ca1fc) --- src/lib/commands/edit.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/commands/edit.c b/src/lib/commands/edit.c index 0b3108c0..a55a7856 100644 --- a/src/lib/commands/edit.c +++ b/src/lib/commands/edit.c @@ -191,12 +191,16 @@ edit(void) return err; break; case 'l': + if (!check_sect_ok(§)) + return RET_FAIL; if ((err = doland(thing, arg, ptr, §)) != RET_OK) return err; if (!putsect(§)) 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)) From e2eccc57405020901a90ea0cd06c9ea9501af1e3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 12 May 2008 17:22:39 +0200 Subject: [PATCH 26/54] 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. --- info/Hvy-Metal.t | 6 ++++-- src/lib/commands/load.c | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/info/Hvy-Metal.t b/info/Hvy-Metal.t index beb74cdb..4d6ca557 100644 --- a/info/Hvy-Metal.t +++ b/info/Hvy-Metal.t @@ -99,8 +99,10 @@ conserve oil. Resources are scarce. Expect to fight over them. Oil derricks need to set up shop before they produce: no production while mobility is below maximum. .s1 -Automatic shell supply for sector flak and ship missile defense is -disabled, because its bugs interfere with Hvy Metal modifications. +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. diff --git a/src/lib/commands/load.c b/src/lib/commands/load.c index b677d3ea..67f9b60e 100644 --- a/src/lib/commands/load.c +++ b/src/lib/commands/load.c @@ -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)) From 7dc0f48868db15a116cf67d5642bc01c12b93086 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 12 May 2008 18:45:11 +0200 Subject: [PATCH 27/54] 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 7680acc39fd63684c6854f27e99a2a5e18712473) --- include/xy.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xy.h b/include/xy.h index 9f1f06c2..574c1b67 100644 --- a/include/xy.h +++ b/include/xy.h @@ -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 */ From e1283b118a6c9054403027c7422622eef4bf1f9a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 13 May 2008 08:36:06 +0200 Subject: [PATCH 28/54] 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 0cc474bd6dd095235330f4e15141c9d5e5adc4b4) --- include/prototypes.h | 2 -- src/lib/common/mapdist.c | 28 ---------------------------- src/lib/subs/satmap.c | 22 ++++------------------ 3 files changed, 4 insertions(+), 48 deletions(-) diff --git a/include/prototypes.h b/include/prototypes.h index cc4fd26a..450e69b7 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -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); diff --git a/src/lib/common/mapdist.c b/src/lib/common/mapdist.c index cac702f4..50d90c00 100644 --- a/src/lib/common/mapdist.c +++ b/src/lib/common/mapdist.c @@ -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) { diff --git a/src/lib/subs/satmap.c b/src/lib/subs/satmap.c index f4def5df..15a06020 100644 --- a/src/lib/subs/satmap.c +++ b/src/lib/subs/satmap.c @@ -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; } From d3a2130b267842619897d907c81091c683b9461d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 16 May 2008 07:33:20 +0200 Subject: [PATCH 29/54] Fix type of get_seqno() from int to unsigned While there, document the seqno functions. --- src/lib/common/file.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/lib/common/file.c b/src/lib/common/file.c index d89256a4..6a3fd28a 100644 --- a/src/lib/common/file.c +++ b/src/lib/common/file.c @@ -50,7 +50,7 @@ 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 int get_seqno(struct empfile *, int); +static unsigned get_seqno(struct empfile *, int); static void new_seqno(struct empfile *, void *); static void do_blank(struct empfile *, void *, int, int); @@ -458,6 +458,13 @@ 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) { @@ -476,7 +483,12 @@ ef_set_uid(int type, void *buf, int uid) elt->seqno = get_seqno(ep, uid); } -static int +/* + * 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; @@ -498,6 +510,11 @@ get_seqno(struct empfile *ep, int id) 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) { From 2410535a052d1af76a65f52396a48632ef61e885 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 28 May 2008 07:35:22 +0200 Subject: [PATCH 30/54] 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 7f17369491f9d6a01f35d1017d9da49b308f80b4) --- src/lib/subs/supply.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/subs/supply.c b/src/lib/subs/supply.c index 96b2d2cc..1aa46b47 100644 --- a/src/lib/subs/supply.c +++ b/src/lib/subs/supply.c @@ -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); From 080e8db899129467ff6025677dc9b180a5c90d63 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 28 May 2008 22:30:36 +0200 Subject: [PATCH 31/54] 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 aacd0fb754ef060af92bb08907c5cda196bf34e3) --- src/lib/subs/supply.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/subs/supply.c b/src/lib/subs/supply.c index 1aa46b47..ed5ae769 100644 --- a/src/lib/subs/supply.c +++ b/src/lib/subs/supply.c @@ -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, From dfcc13abddd9ebb46263ca4da5440702dd2cca56 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 9 Jun 2008 20:07:28 +0200 Subject: [PATCH 32/54] Clarify info Railroad on track stopping at national borders --- info/Railroad.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/info/Railroad.t b/info/Railroad.t index 82e6eea1..88649998 100644 --- a/info/Railroad.t +++ b/info/Railroad.t @@ -19,9 +19,9 @@ 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. Spy and satellite reports show the -presence of track in column \*Qrl eff\*U. To visualize your railway -network, try \*Qsect # ?track#0\*U. +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" From b8bdc32b3cf608b63e025836d33964ebfa81fba1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 10 Jun 2008 07:29:04 +0200 Subject: [PATCH 33/54] 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. --- src/lib/commands/mfir.c | 4 ++-- src/lib/subs/lndsub.c | 2 +- src/lib/subs/mission.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/commands/mfir.c b/src/lib/commands/mfir.c index 68677b49..d277727b 100644 --- a/src/lib/commands/mfir.c +++ b/src/lib/commands/mfir.c @@ -349,6 +349,7 @@ multifire(void) range2 = -1; } + lnd_unlimber(&fland); dam = lnd_fire(&fland); putland(fland.lnd_uid, &fland); if (dam < 0) { @@ -356,7 +357,6 @@ multifire(void) continue; } - lnd_unlimber(&fland); if (target == targ_ship) { if (chance(lnd_acc(&fland) / 100.0)) dam = ldround(dam / 2.0, 1); @@ -713,13 +713,13 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown, if (fp) dam2 = fp->defdam; else { + lnd_unlimber(&land); dam2 = lnd_fire(&land); putland(land.lnd_uid, &land); } if (dam2 < 0) continue; - lnd_unlimber(&land); (*nfiring)++; if (!fp) add_to_flist(list, (struct empobj *)&land, dam2, 0); diff --git a/src/lib/subs/lndsub.c b/src/lib/subs/lndsub.c index 578c1af0..62cfd821 100644 --- a/src/lib/subs/lndsub.c +++ b/src/lib/subs/lndsub.c @@ -1142,12 +1142,12 @@ lnd_support(natid victim, natid attacker, coord x, coord y, int defending) if (dist > range) continue; + lnd_unlimber(&land); dam2 = lnd_fire(&land); putland(land.lnd_uid, &land); if (dam2 < 0) continue; - lnd_unlimber(&land); if (defending) nreport(land.lnd_own, N_FIRE_BACK, victim, 1); else diff --git a/src/lib/subs/mission.c b/src/lib/subs/mission.c index 340f2f57..129448c1 100644 --- a/src/lib/subs/mission.c +++ b/src/lib/subs/mission.c @@ -444,12 +444,12 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list, if (md > range) continue; + lnd_unlimber(lp); dam2 = lnd_fire(lp); putland(lp->lnd_uid, lp); 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); From 07d2c38a7342ccafe568321ff8fa4709cc6fbb61 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 31 May 2008 10:35:47 +0200 Subject: [PATCH 34/54] 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 64f44e99044a8b28b8631a27fc882a959f737f84) --- src/lib/subs/attsub.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib/subs/attsub.c b/src/lib/subs/attsub.c index d3d6c5c3..75e86e3c 100644 --- a/src/lib/subs/attsub.c +++ b/src/lib/subs/attsub.c @@ -1230,11 +1230,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; - } + intelligence_report(player->cnum, &land, a_spy, + "Scouts report defending unit:"); if (!(llp = malloc(sizeof(struct ulist)))) { logerror("Malloc failed in attack!\n"); abort_attack(); From a4b550a1a2d85afbe7d6141ef5f894dad8e1f890 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 8 Jun 2008 11:35:04 +0200 Subject: [PATCH 35/54] 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 3e251b474fb90089c15ea8b5ece4c4f74962d0c0) --- src/lib/subs/mission.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/lib/subs/mission.c b/src/lib/subs/mission.c index 129448c1..f4d1bf13 100644 --- a/src/lib/subs/mission.c +++ b/src/lib/subs/mission.c @@ -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, §); @@ -450,12 +451,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); @@ -492,10 +493,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; @@ -552,7 +551,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); @@ -685,7 +684,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); From d0210443ffec5ae5ae3b4be03aad304d9e2a618b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 15 Jun 2008 07:38:18 +0200 Subject: [PATCH 36/54] Update info Citizens on census showing old owner This was forgotten in commit 6b434ee3, v4.3.0. (cherry picked from commit 860369ec7e968417cb7aad2af96f070dfb96addf) --- info/Citizens.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info/Citizens.t b/info/Citizens.t index b5177421..04e69a53 100644 --- a/info/Citizens.t +++ b/info/Citizens.t @@ -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. From 0a7437bc430657b6cbe8041d1477f6da75cd542e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 15 Jun 2008 08:45:15 +0200 Subject: [PATCH 37/54] 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 4a670806566151254681abbf85e41ee5330566cb) --- info/BTU.t | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/info/BTU.t b/info/BTU.t index ddc7e6c6..309a762e 100644 --- a/info/BTU.t +++ b/info/BTU.t @@ -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" From 2b90a5230d36bb49f42d665a0539d299eb10cc09 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 17 Jun 2008 20:16:27 +0200 Subject: [PATCH 38/54] 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 6d38a0493032b3b13adbbcbd07b65663e7368be3) --- src/lib/subs/attsub.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/subs/attsub.c b/src/lib/subs/attsub.c index 75e86e3c..c2dacacf 100644 --- a/src/lib/subs/attsub.c +++ b/src/lib/subs/attsub.c @@ -1008,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]); From c40dd61bf0639414fa94312b950112469bebad67 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 27 Jun 2008 06:53:43 -0400 Subject: [PATCH 39/54] 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. --- src/lib/commands/mfir.c | 2 -- src/lib/subs/landgun.c | 1 + src/lib/subs/lndsub.c | 1 - src/lib/subs/mission.c | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib/commands/mfir.c b/src/lib/commands/mfir.c index d277727b..5c65583c 100644 --- a/src/lib/commands/mfir.c +++ b/src/lib/commands/mfir.c @@ -349,7 +349,6 @@ multifire(void) range2 = -1; } - lnd_unlimber(&fland); dam = lnd_fire(&fland); putland(fland.lnd_uid, &fland); if (dam < 0) { @@ -713,7 +712,6 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown, if (fp) dam2 = fp->defdam; else { - lnd_unlimber(&land); dam2 = lnd_fire(&land); putland(land.lnd_uid, &land); } diff --git a/src/lib/subs/landgun.c b/src/lib/subs/landgun.c index a6a21da9..160b403d 100644 --- a/src/lib/subs/landgun.c +++ b/src/lib/subs/landgun.c @@ -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; diff --git a/src/lib/subs/lndsub.c b/src/lib/subs/lndsub.c index 62cfd821..12f8ecc7 100644 --- a/src/lib/subs/lndsub.c +++ b/src/lib/subs/lndsub.c @@ -1142,7 +1142,6 @@ lnd_support(natid victim, natid attacker, coord x, coord y, int defending) if (dist > range) continue; - lnd_unlimber(&land); dam2 = lnd_fire(&land); putland(land.lnd_uid, &land); if (dam2 < 0) diff --git a/src/lib/subs/mission.c b/src/lib/subs/mission.c index f4d1bf13..2f147f47 100644 --- a/src/lib/subs/mission.c +++ b/src/lib/subs/mission.c @@ -445,7 +445,6 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list, if (md > range) continue; - lnd_unlimber(lp); dam2 = lnd_fire(lp); putland(lp->lnd_uid, lp); if (dam2 < 0) From fbefc139f4fe6b9ba6068d6493a900f7b7d77b22 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 28 Jun 2008 09:15:49 -0400 Subject: [PATCH 40/54] 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 b0644e822cd10d93c1168f7b356068fabc02b2bf) --- src/lib/subs/shpsub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/subs/shpsub.c b/src/lib/subs/shpsub.c index f5b90fd9..9a97c2c5 100644 --- a/src/lib/subs/shpsub.c +++ b/src/lib/subs/shpsub.c @@ -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(§); if (shp_check_one_mines(mlp)) { stopping = 1; emp_remque(qp); free(qp); } - putship(mlp->unit.ship.shp_uid, &mlp->unit.ship); - putsect(§); } if (changed) writemap(actor); From 84d40a6057a4f858f5a7bef7bb7c73b4614128f3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 28 Jun 2008 11:24:43 -0400 Subject: [PATCH 41/54] 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 801780043fd2629b0859013d12caada2e8060688) --- src/lib/subs/plnsub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/subs/plnsub.c b/src/lib/subs/plnsub.c index d2b811f5..9d0037fa 100644 --- a/src/lib/subs/plnsub.c +++ b/src/lib/subs/plnsub.c @@ -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); From 1713f2d3039dd40593a617ebafab32c5366c5445 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Jul 2008 19:35:51 -0400 Subject: [PATCH 42/54] 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 7a06a58bec0435a66a682269397193d8d17461de) --- src/lib/common/ef_verify.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/common/ef_verify.c b/src/lib/common/ef_verify.c index 62c5cab2..3c51d588 100644 --- a/src/lib/common/ef_verify.c +++ b/src/lib/common/ef_verify.c @@ -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; From 6aefeea2a168338a6eb13e9d096c4373f141a6a9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 12 Jul 2008 10:56:30 -0400 Subject: [PATCH 43/54] 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 42d9475d894f6779dab17655cd5082b66b9acac9) --- src/lib/commands/fly.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/commands/fly.c b/src/lib/commands/fly.c index ed55fbca..1fdfef90 100644 --- a/src/lib/commands/fly.c +++ b/src/lib/commands/fly.c @@ -87,14 +87,6 @@ fly(void) cno = -1; if (pln_onewaymission(&target, &cno, &wantflags) < 0) return RET_SYN; - if (cno < 0) { - dst_ptr = ⌖ - 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 = ⌖ + 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); From 18ae6c5f7860a4a3ed62e1928ad5e7fe4a71e6bb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 12 Jul 2008 22:41:52 -0400 Subject: [PATCH 44/54] 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 49c24d7b78d728f84ab4932572914aab71ddbc1e) --- include/player.h | 1 + src/lib/player/recvclient.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/player.h b/include/player.h index 584c613f..52edb336 100644 --- a/include/player.h +++ b/include/player.h @@ -78,6 +78,7 @@ struct player { time_t curup; /* when last input was received */ int aborted; /* interrupt cookie 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 */ diff --git a/src/lib/player/recvclient.c b/src/lib/player/recvclient.c index 169a1424..5757aa40 100644 --- a/src/lib/player/recvclient.c +++ b/src/lib/player/recvclient.c @@ -90,10 +90,19 @@ recvclient(char *cmd, int size) player->eof = 1; } - if (player->eof) - return -1; - if (player->aborted) - return -2; + if (player->aborted || player->eof) { + 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; } From 3c3912420bc1dd7dbdef4edb13ba9fef43f5d51a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 14 Jul 2008 22:24:42 -0400 Subject: [PATCH 45/54] Change recvclient() to treat io_error() like io_eof() This is for consistency with status() and player_login(). (cherry picked from commit b7153d095ccab8b397a3eaa3326a1806a6f616fa) --- src/lib/player/recvclient.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/lib/player/recvclient.c b/src/lib/player/recvclient.c index 5757aa40..d209214a 100644 --- a/src/lib/player/recvclient.c +++ b/src/lib/player/recvclient.c @@ -46,10 +46,10 @@ * 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 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. */ @@ -84,9 +84,7 @@ 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)) + if (io_error(player->iop) || io_eof(player->iop)) player->eof = 1; } From 80b57b2f955f30bbe739500240139c35fb167f44 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 14 Jul 2008 22:30:28 -0400 Subject: [PATCH 46/54] 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 9c5854c8c93979c1744c97c90df672070e080a99) --- src/lib/player/player.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/lib/player/player.c b/src/lib/player/player.c index f6f1e34e..0c8a865d 100644 --- a/src/lib/player/player.c +++ b/src/lib/player/player.c @@ -110,8 +110,7 @@ player_main(struct player *p) } while (status()) { - if (command() == 0 && !player->aborted) - break; + command(); player->aborted = 0; empth_yield(); } @@ -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) From b9b0710128f4460996c98f17066da4a895b6e124 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 14 Jul 2008 22:37:02 -0400 Subject: [PATCH 47/54] 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 b3a7a8ee11595aac2bd27f76b3adf9e4c48bb0eb) --- include/player.h | 2 +- src/lib/player/player.c | 2 +- src/lib/player/recvclient.c | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/player.h b/include/player.h index 52edb336..f6ab9b56 100644 --- a/include/player.h +++ b/include/player.h @@ -76,7 +76,7 @@ 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 */ diff --git a/src/lib/player/player.c b/src/lib/player/player.c index 0c8a865d..f87db4da 100644 --- a/src/lib/player/player.c +++ b/src/lib/player/player.c @@ -111,7 +111,7 @@ player_main(struct player *p) while (status()) { command(); - player->aborted = 0; + player->aborted = player->eof; empth_yield(); } /* #*# I put the following line in to prevent server crash -KHS */ diff --git a/src/lib/player/recvclient.c b/src/lib/player/recvclient.c index d209214a..32decde7 100644 --- a/src/lib/player/recvclient.c +++ b/src/lib/player/recvclient.c @@ -47,7 +47,8 @@ * 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 or EOF indicator set, - * or the line is "ctld", set the player's eof flag and return -1. + * 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. @@ -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); @@ -85,10 +86,10 @@ recvclient(char *cmd, int size) /* Await more input */ io_input(player->iop, IO_WAIT); if (io_error(player->iop) || io_eof(player->iop)) - player->eof = 1; + player->aborted = player->eof = 1; } - if (player->aborted || player->eof) { + if (player->aborted) { player->recvfail++; if (player->recvfail > 255) { /* From 3afc1b1989050485ce906859d06ff44ae2e775d7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 25 Jul 2008 08:40:01 -0400 Subject: [PATCH 48/54] Fix interdiction to obey op-area for missiles Never worked correctly. Reported by Gregory E. Garland. (cherry picked from commit 3eb58312b32ebb5e056679eb68e11749b61b72cc) --- src/lib/subs/mslsub.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/subs/mslsub.c b/src/lib/subs/mslsub.c index 3345b2a5..ebd5af5b 100644 --- a/src/lib/subs/mslsub.c +++ b/src/lib/subs/mslsub.c @@ -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 */ From a87f73a3b575e660fa2f8cdb596251a8a36e1d1a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 29 Jul 2008 07:32:36 -0400 Subject: [PATCH 49/54] 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. --- src/lib/subs/journal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index 7f450524..bfb1e9ec 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -80,8 +80,12 @@ 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); va_end(ap); From cb1c9f6a19250002603e4e443a774fbc607744fa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 29 Jul 2008 07:48:28 -0400 Subject: [PATCH 50/54] 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. --- include/journal.h | 1 + src/lib/player/dispatch.c | 2 ++ src/lib/subs/journal.c | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/include/journal.h b/include/journal.h index bd35399f..eed66ff2 100644 --- a/include/journal.h +++ b/include/journal.h @@ -41,6 +41,7 @@ void journal_login(void); void journal_logout(void); void journal_prng(unsigned); void journal_input(char *); +void journal_command(char *); void journal_update(int); #endif diff --git a/src/lib/player/dispatch.c b/src/lib/player/dispatch.c index 10d16c17..edf50371 100644 --- a/src/lib/player/dispatch.c +++ b/src/lib/player/dispatch.c @@ -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; diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index bfb1e9ec..20d32568 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -43,6 +43,7 @@ * prng NAME SEED * login CNUM HOSTADDR USER * logout CNUM + * command NAME * input INPUT * update ETU */ @@ -172,6 +173,13 @@ 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) { From 9398627ec4e4c8d96f76180b47b224a874ef38e8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 29 Jul 2008 20:38:48 -0400 Subject: [PATCH 51/54] 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. --- include/journal.h | 3 +++ src/lib/subs/journal.c | 15 ++++++++++++++- src/lib/subs/pr.c | 3 +++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/journal.h b/include/journal.h index eed66ff2..7ef10ae1 100644 --- a/include/journal.h +++ b/include/journal.h @@ -34,12 +34,15 @@ #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); diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index 20d32568..d2521f12 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -45,6 +45,7 @@ * logout CNUM * command NAME * input INPUT + * output THREAD ID OUTPUT * update ETU */ @@ -98,7 +99,8 @@ journal_entry(char *fmt, ...) fprintf(journal, "\\%03o", *p); } fputs("\n", journal); - fflush(journal); + if (fmt[0] != 'o') /* FIXME disgusting hack */ + fflush(journal); if (ferror(journal)) { logerror("Error writing journal (%s)", strerror(errno)); clearerr(journal); @@ -167,6 +169,17 @@ journal_logout(void) journal_entry("logout %d", player->cnum); } +void +journal_output(struct player *pl, int id, char *output) +{ + if (keep_journal < 2) + return; + if (pl && pl->state == PS_PLAYING) + journal_entry("output %d %d %s", pl->cnum, id, output); + else + journal_entry("output %p %d %s", pl, id, output); +} + void journal_input(char *input) { diff --git a/src/lib/subs/pr.c b/src/lib/subs/pr.c index 711dd3f4..44f5aee7 100644 --- a/src/lib/subs/pr.c +++ b/src/lib/subs/pr.c @@ -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" @@ -245,6 +246,7 @@ pr_player(struct player *pl, int id, char *buf) bp += len; } } + journal_output(pl, id, buf); } /* @@ -299,6 +301,7 @@ upr_player(struct player *pl, int id, char *buf) io_puts(pl->iop, printbuf); } } + journal_output(pl, id, buf); } /* From 321d6d74c7784eec79f9e8c02d6ba916a727caf9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 30 Jul 2008 08:26:34 -0400 Subject: [PATCH 52/54] 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. --- include/journal.h | 2 +- src/lib/subs/journal.c | 30 +++++++++++++++++++++++++++--- src/lib/subs/pr.c | 6 ++++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/include/journal.h b/include/journal.h index 7ef10ae1..247e40c3 100644 --- a/include/journal.h +++ b/include/journal.h @@ -42,7 +42,7 @@ 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_output(struct player *, char *); void journal_input(char *); void journal_command(char *); void journal_update(int); diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index d2521f12..85f68ce8 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -66,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 *, char *, char *, int); + static FILE * journal_open(void) { @@ -170,14 +173,35 @@ journal_logout(void) } void -journal_output(struct player *pl, int id, char *output) +journal_output(struct player *pl, char *output) { + static char buf[1024]; + char *s, *e; + if (keep_journal < 2) return; + + for (s = output; (e = strchr(s, '\n')); s = e + 1) { + journal_output_1(pl, buf, s, (int)(e + 1 - s)); + buf[0] = 0; + } + if (strlen(buf) + strlen(s) < 1024) + strcpy(buf + strlen(buf), s); + else { + journal_output_1(pl, buf, s, -1); + buf[0] = 0; + } +} + +void +journal_output_1(struct player *pl, char *buf1, char *buf2, int buf2prec) +{ if (pl && pl->state == PS_PLAYING) - journal_entry("output %d %d %s", pl->cnum, id, output); + journal_entry("output %d %s%.*s", + pl->cnum, buf1, buf2prec, buf2); else - journal_entry("output %p %d %s", pl, id, output); + journal_entry("output %p %s%.*s", + pl, buf1, buf2prec, buf2); } void diff --git a/src/lib/subs/pr.c b/src/lib/subs/pr.c index 44f5aee7..0b8146ef 100644 --- a/src/lib/subs/pr.c +++ b/src/lib/subs/pr.c @@ -125,6 +125,7 @@ pr_id(struct player *p, int id, char *format, ...) if (p->curid >= 0) { io_puts(p->iop, "\n"); + journal_output(p, "\n"); p->curid = -1; } va_start(ap, format); @@ -246,7 +247,7 @@ pr_player(struct player *pl, int id, char *buf) bp += len; } } - journal_output(pl, id, buf); + journal_output(pl, buf); } /* @@ -301,7 +302,7 @@ upr_player(struct player *pl, int id, char *buf) io_puts(pl->iop, printbuf); } } - journal_output(pl, id, buf); + journal_output(pl, buf); } /* @@ -323,6 +324,7 @@ outid(struct player *pl, int n) buf[1] = ' '; buf[2] = '\0'; io_puts(pl->iop, buf); + journal_output(pl, buf); pl->curid = n; } From 59bdc1cbcc031e33bca56155342247f95344a5b0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 1 Aug 2008 08:50:24 -0400 Subject: [PATCH 53/54] 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 eb252201b69a591523e8a68b41c01f4a80e7b731) --- include/lost.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lost.h b/include/lost.h index 1bb93079..a6624637 100644 --- a/include/lost.h +++ b/include/lost.h @@ -40,7 +40,7 @@ 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 */ From 342ab5c22aad4de2a0f8ee338c1ae66125fe1b6a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 2 Aug 2008 09:04:16 -0400 Subject: [PATCH 54/54] Fix journalling of output ids --- include/journal.h | 2 +- src/lib/subs/journal.c | 34 ++++++++++++++++++++++------------ src/lib/subs/pr.c | 7 +++---- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/journal.h b/include/journal.h index 247e40c3..7ef10ae1 100644 --- a/include/journal.h +++ b/include/journal.h @@ -42,7 +42,7 @@ int journal_reopen(void); void journal_login(void); void journal_logout(void); void journal_prng(unsigned); -void journal_output(struct player *, char *); +void journal_output(struct player *, int, char *); void journal_input(char *); void journal_command(char *); void journal_update(int); diff --git a/src/lib/subs/journal.c b/src/lib/subs/journal.c index 85f68ce8..bc37262c 100644 --- a/src/lib/subs/journal.c +++ b/src/lib/subs/journal.c @@ -67,7 +67,7 @@ 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 *, char *, char *, int); +static void journal_output_1(struct player *, int, char *, char *, int); static FILE * journal_open(void) @@ -173,35 +173,45 @@ journal_logout(void) } void -journal_output(struct player *pl, char *output) +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; - for (s = output; (e = strchr(s, '\n')); s = e + 1) { - journal_output_1(pl, buf, s, (int)(e + 1 - s)); + if (buf[0] && (pl != bpl && id != bid)) { + journal_output_1(bpl, bid, buf, "", -1); buf[0] = 0; } - if (strlen(buf) + strlen(s) < 1024) + + 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); - else { - journal_output_1(pl, buf, s, -1); + bpl = pl; + bid = id; + } else { + journal_output_1(pl, id, buf, s, -1); buf[0] = 0; } } void -journal_output_1(struct player *pl, char *buf1, char *buf2, int buf2prec) +journal_output_1(struct player *pl, int id, + char *buf1, char *buf2, int buf2prec) { if (pl && pl->state == PS_PLAYING) - journal_entry("output %d %s%.*s", - pl->cnum, buf1, buf2prec, buf2); + journal_entry("output %d %d %s%.*s", + pl->cnum, id, buf1, buf2prec, buf2); else - journal_entry("output %p %s%.*s", - pl, buf1, buf2prec, buf2); + journal_entry("output %p %id %s%.*s", + pl, id, buf1, buf2prec, buf2); } void diff --git a/src/lib/subs/pr.c b/src/lib/subs/pr.c index 0b8146ef..496bde49 100644 --- a/src/lib/subs/pr.c +++ b/src/lib/subs/pr.c @@ -125,7 +125,7 @@ pr_id(struct player *p, int id, char *format, ...) if (p->curid >= 0) { io_puts(p->iop, "\n"); - journal_output(p, "\n"); + journal_output(p, p->curid, "\n"); p->curid = -1; } va_start(ap, format); @@ -247,7 +247,7 @@ pr_player(struct player *pl, int id, char *buf) bp += len; } } - journal_output(pl, buf); + journal_output(pl, id, buf); } /* @@ -302,7 +302,7 @@ upr_player(struct player *pl, int id, char *buf) io_puts(pl->iop, printbuf); } } - journal_output(pl, buf); + journal_output(pl, id, buf); } /* @@ -324,7 +324,6 @@ outid(struct player *pl, int n) buf[1] = ' '; buf[2] = '\0'; io_puts(pl->iop, buf); - journal_output(pl, buf); pl->curid = n; }