games@tekred.TEK.COM (07/02/88)
Submitted by: "Stanley T. Shebs" <shebs%defun@cs.utah.edu> Comp.sources.games: Volume 4, Issue 101 Archive-name: xconq5/Part13 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 13 (of 18)." # Contents: attack.c lib/mapfiles mkmap.c period.h side.c # Wrapped by billr@saab on Wed Jun 29 08:55:58 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f attack.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"attack.c\" else echo shar: Extracting \"attack.c\" \(13114 characters\) sed "s/^X//" >attack.c <<'END_OF_attack.c' X/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */ X/* This program may be used, copied, modified, and redistributed freely */ X/* for noncommercial purposes, so long as this notice remains intact. */ X X/* RCS $Header: attack.c,v 1.2 88/06/28 10:38:26 shebs Exp $ */ X X/* Although conducting xconq combat is rather simple (i.e. try to move */ X/* into the hex), the outcome is under the control of many parameters. */ X X/* Rules of combat: the attacker hits the defender ("other") unit and its */ X/* occupants, but the damage does not take effect right away. If counter */ X/* attacks are possible in this period, the defender always does so, with */ X/* the same odds. If the defender dies, then the attacker moves into the */ X/* hex. If the attacker dies, nothing happens. If both survive, then the */ X/* attacker may attempt to capture the defender. */ X X#include "config.h" X#include "misc.h" X#include "period.h" X#include "side.h" X#include "unit.h" X#include "map.h" X#include "global.h" X Xextern int occdeath[]; X Xchar *summarize_units(); X X/* Buffers for verbal descriptions of units from each other's */ X/* point of view. */ X Xchar aabuf[BUFSIZE], aobuf[BUFSIZE], oabuf[BUFSIZE], oobuf[BUFSIZE]; Xchar hitbuf[BUFSIZE], killbuf[BUFSIZE]; X X/* Remember what the main units involved are, so display is handled relative */ X/* to them and not to any occupants. */ X XUnit *amain, *omain; X X/* Hits on main units saved up, hits on occupants happen immediately. */ X Xint ahit, ohit; X X/* ... but the data is saved anyway, for message generation. */ X Xint occhits[MAXUTYPES], occkills[MAXUTYPES]; X X/* Return true if the attacker defeated the defender, and can therefore */ X/* try to move into the defender's old position. */ X Xattack(atker, other) XUnit *atker, *other; X{ X int u, ax = atker->x, ay = atker->y, ox = other->x, oy = other->y; X Side *as = atker->side, *os = other->side; X X amain = atker; omain = other; X ahit = ohit = 0; X for_all_unit_types(u) occhits[u] = occkills[u] = 0; X attack_unit(atker, other); X if (period.counterattack || utypes[atker->type].counterable) X attack_unit(other, atker); X reckon_damage(); X see_exact(as, ax, ay); X see_exact(as, ox, oy); X see_exact(os, ax, ay); X see_exact(os, ox, oy); X draw_hex(as, ax, ay, TRUE); X draw_hex(as, ox, oy, TRUE); X draw_hex(os, ax, ay, TRUE); X draw_hex(os, ox, oy, TRUE); X all_see_hex(ax, ay); X all_see_hex(ox, oy); X attempt_to_capture_unit(atker, other); X return (alive(atker) && unit_at(ox, oy) == NULL); X} X X/* Test to see if enough ammo is available to make the attack. */ X/* Need enough of *all* types - semi-bogus but too complicated otherwise? */ X Xenough_ammo(atker, other) XUnit *atker, *other; X{ X int r; X X for_all_resource_types(r) { X if (utypes[other->type].hitby[r] > 0 && X atker->supply[r] < utypes[atker->type].hitswith[r]) return FALSE; X } X return TRUE; X} X X/* Single attack, no counterattack. Check and use ammo - usage independent */ X/* of outcome, but types used depend on unit types involved. */ X Xattack_unit(atker, other) XUnit *atker, *other; X{ X int r; X X wake_unit(other, FALSE); X if (alive(atker) && alive(other)) { X if (enough_ammo(atker, other)) { X hit_unit(atker, other); X for_all_resource_types(r) { X if (utypes[other->type].hitby[r] > 0) { X atker->supply[r] -= utypes[atker->type].hitswith[r]; X } X } X atker->movesleft -= utypes[atker->type].hittime; X } X } X} X X/* Make a single hit and maybe hit some passengers also. Power of hit */ X/* is constant, but chance is affected by neutrality, terrain, quality, */ X/* and occupants' protective abilities. If a hit is successful, it may */ X/* have consequences on the defender's occupants, but limited by the */ X/* protection that the transport provides. */ X Xhit_unit(atker, other) XUnit *atker, *other; X{ X int chance, terr, hit = 0, a = atker->type, o = other->type; X Unit *occ; X Side *as = atker->side; X X chance = utypes[a].hit[o]; X if (neutral(atker)) chance += period.neutrality; X terr = terrain_at(other->x, other->y); X chance -= (chance * utypes[o].defense[terr]) / 100; X if (utypes[a].maxquality > 0) { X chance += ((chance * atker->quality * utypes[a].skillf) / X utypes[a].maxquality) / 100; X } X if (utypes[o].maxquality > 0) { X chance -= ((chance * other->quality * utypes[o].disciplinef) / X utypes[o].maxquality) / 100; X } X for_all_occupants(other, occ) { X chance -= (chance * utypes[occ->type].protect[o]) / 100; X } X if (probability(chance)) hit = utypes[a].damage[o]; X if (as != NULL) { X as->atkstats[a][o]++; X as->hitstats[a][o] += hit; X } X if (hit_unit_aux(atker, other, hit)) { X for_all_occupants(other, occ) { X if (probability(100 - utypes[o].protect[occ->type])) { X hit_unit(atker, occ); X } X } X } X} X X/* Do the hit itself. Occupants are always hit/killed immediately, while */ X/* the "main units" of the hexes don't get it till later. In any case, */ X/* messages are delayed. Return true if the victim was hit but not killed. */ X Xhit_unit_aux(atker, other, hit) XUnit *atker, *other; Xint hit; X{ X int o = other->type, a = atker->type, chance, i; X Side *as = atker->side, *os = other->side; X X if (hit >= period.nukehit) { X notify_all("%s has been hit by a nuclear attack!!!", X unit_handle(NULL, other)); X set_terrain_at(other->x, other->y, X ttypes[terrain_at(other->x, other->y)].nuked); X } X if (hit > 0 && mobile(o)) { X chance = utypes[o].retreat; X /* should adjust chance by morale etc */ X if (probability(chance)) { X if (retreat_unit(other)) { X notify(as, "%s runs away!", unit_handle(as, other)); X notify(os, "%s runs away!", unit_handle(os, other)); X hit = 0; X } X } X } X if (other == omain) { X ohit = hit; X } else if (other == amain) { X ahit = hit; X } else { X if (hit >= other->hp) { X occkills[o]++; X kill_unit(other, COMBAT); X for_all_unit_types(i) occkills[i] += occdeath[i]; X } else if (hit > 0) { X occhits[o]++; X other->hp -= hit; X } X if (utypes[a].selfdestruct) { X kill_unit(atker, COMBAT); X } X } X return (alive(other) && hit > 0); X} X X/* Hits on the main units have to be done later, so that mutual */ X/* destruction is possible. This function also does all the notifying. */ X/* (Only the main units of a hex rate messages, occupants' fates are */ X/* summarized briefly.) */ X Xreckon_damage() X{ X int o = omain->type, a = amain->type, i; X Side *as = amain->side, *os = omain->side; X X strcpy(aabuf, unit_handle(as, amain)); X strcpy(aobuf, unit_handle(as, omain)); X strcpy(oabuf, unit_handle(os, amain)); X strcpy(oobuf, unit_handle(os, omain)); X X if (ahit > 0) draw_blast(amain, omain->side, ahit); X if (ohit > 0) draw_blast(omain, amain->side, ohit); X if (ohit >= omain->hp) { X notify(as, "%s %s %s!", aabuf, utypes[o].destroymsg, aobuf); X notify(os, "%s %s %s!", oabuf, utypes[o].destroymsg, oobuf); X kill_unit(omain, COMBAT); X for_all_unit_types(i) occkills[i] += occdeath[i]; X } else if (ohit > 0) { X notify(as, "%s hits %s!", aabuf, aobuf); X notify(os, "%s hits %s!", oabuf, oobuf); X omain->hp -= ohit; X } else { X /* messages about missing not too useful */ X } X summarize_units(hitbuf, occhits); X summarize_units(killbuf, occkills); X if (strlen(hitbuf) > 0) { X if (strlen(killbuf) > 0) { X notify(as, " (Also hit%s, killed%s)", hitbuf, killbuf); X notify(os, " (%s hurt, %s killed)", hitbuf, killbuf); X } else { X notify(as, " (Also hit%s)", hitbuf); X notify(os, " (%s hurt)", hitbuf); X } X } else { X if (strlen(killbuf) > 0) { X notify(as, " (Also killed%s)", killbuf); X notify(os, " (%s killed)", killbuf); X } X } X if (ahit >= amain->hp) { X notify(as, "%s %s %s!", aobuf, utypes[a].destroymsg, aabuf); X notify(os, "%s %s %s!", oobuf, utypes[a].destroymsg, oabuf); X kill_unit(amain, COMBAT); X } else if (ahit > 0) { X notify(as, "%s hits %s!", aobuf, aabuf); X notify(os, "%s hits %s!", oobuf, oabuf); X amain->hp -= ahit; X } else { X /* messages about missing not too useful */ X } X if (utypes[a].selfdestruct) kill_unit(amain, COMBAT); X if (utypes[o].selfdestruct) kill_unit(omain, COMBAT); X} X X/* Handle capture possibility and repulse/slaughter. */ X X/* The chance to capture an enemy is modified by several factors. */ X/* Neutrals have a different chance to be captured, and presence of */ X/* occupants should also has an effect. Can't capture anything that is */ X/* on a kind of terrain that the capturer can't go on, unless victim has */ X/* "bridge effect". */ X Xattempt_to_capture_unit(atker, other) XUnit *atker, *other; X{ X int a = atker->type, o = other->type, chance; X int ox = other->x, oy = other->y; X Unit *occ; X Side *as = atker->side, *os = other->side; X X if (alive(atker) && alive(other) && could_capture(a, o)) { X if (impassable(atker, ox, oy) && !utypes[o].bridge[a]) return; X chance = utypes[a].capture[o]; X if (neutral(other)) chance -= period.neutrality; X if (utypes[a].maxquality > 0) { X chance += ((chance * atker->quality * utypes[a].skillf) / X utypes[a].maxquality) / 100; X } X for_all_occupants(other, occ) { X chance -= (chance * utypes[occ->type].protect[o]) / 100; X } X if (probability(chance)) { X capture_unit(atker, other); X if (global.setproduct && utypes[o].maker) { X request_new_product(other); X other->movesleft = 1; X move_1(other->side, other); X } X } else if (atker->transport != NULL && X (impassable(atker, ox, oy) || X impassable(atker, atker->x, atker->y))) { X notify(as, "Resistance... %s was slaughtered!", X unit_handle(as, atker)); X notify(os, "Resistance... %s was slaughtered!", X unit_handle(os, atker)); X kill_unit(atker, COMBAT); X } else { X strcpy(aabuf, unit_handle(as, atker)); X notify(as, "%s repulses %s!", unit_handle(as, other), aabuf); X strcpy(oabuf, unit_handle(os, atker)); X notify(os, "%s repulses %s!", unit_handle(os, other), oabuf); X } X atker->movesleft -= utypes[a].hittime; X } X} X X/* There are many consequences of a unit being captured. */ X/* If the capturer is needed as a garrison, unload any occupants first. */ X/* (what if erstwhile occupants can't stay there?) */ X Xcapture_unit(unit, pris) XUnit *unit, *pris; X{ X int u = unit->type, u2, px = pris->x, py = pris->y, i; X int occs[MAXUTYPES], gains[MAXUTYPES], kills[MAXUTYPES]; X Unit *occ; X Side *ps = pris->side, *us = unit->side; X X for_all_unit_types(u2) occs[u2] = gains[u2] = kills[u2] = 0; X notify(us, "You captured %s!", unit_handle(us, pris)); X notify(ps, "%s has been captured by the %s!", X unit_handle(ps, pris), plural_form(us->name)); X if (global.setproduct) { X set_product(pris, NOTHING); X pris->schedule = 0; X } X for_all_occupants(pris, occ) { X occs[occ->type]++; X if (utypes[occ->type].changeside || could_capture(u, occ->type)) { X gains[occ->type]++; X /* side changing happens when whole unit changes */ X } else { X kills[occ->type]++; X kill_unit(occ, COMBAT); X for_all_unit_types(i) kills[i] += occdeath[i]; X } X } X summarize_units(hitbuf, gains); X summarize_units(killbuf, kills); X summarize_units(spbuf, occs); X if (strlen(hitbuf) > 0) { X if (strlen(killbuf) > 0) { X notify(us, " (Also captured%s, killed%s)", hitbuf, killbuf); X } else { X notify(us, " (Also captured%s)", hitbuf); X } X } else if (strlen(killbuf) > 0) { X notify(us, " (Also killed%s)", killbuf); X } X if (strlen(spbuf) > 0) { X notify(ps, " (Lost%s)", spbuf); X } X /* The sad event itself */ X unit_changes_side(pris, us, CAPTURE, PRISONER); X /* Guard the prisoner */ X if (utypes[u].guard[pris->type] > 0) { X for_all_occupants(unit, occ) { X if (can_carry(pris, occ)) { X leave_hex(occ); X occupy_hex(occ, px, py); X } X } X /* This may kill some of the guard's occupants unnecessarily, but */ X /* I can't think of a better solution */ X kill_unit(unit, GARRISON); X } else if (can_carry(pris, unit)) { X leave_hex(unit); X occupy_hex(unit, px, py); X } else { X /* Capturer doesn't guard or enter, so nothing to do */ X } X see_exact(ps, px, py); X all_see_hex(px, py); X} X X/* Nearly-raw combat statistics are hard to interpret, but they provide */ X/* a useful check against subjective evaluation of performance. */ X Xprint_combat_results(fp, side) XFILE *fp; XSide *side; X{ X int a, d; X X fprintf(fp, X "Unit Performance (successes and attacks against enemy by type\n"); X fprintf(fp, " "); X for_all_unit_types(d) { X fprintf(fp, " %c ", utypes[d].uchar); X } X fprintf(fp, "\n"); X for_all_unit_types(a) { X fprintf(fp, " %c ", utypes[a].uchar); X for_all_unit_types(d) { X if (side->atkstats[a][d] > 0) { X fprintf(fp, " %3.1f ", X ((float) side->hitstats[a][d]) / X side->atkstats[a][d]); X } else { X fprintf(fp, " "); X } X } X fprintf(fp, "\n "); X for_all_unit_types(d) { X if (side->atkstats[a][d] > 0) { X fprintf(fp, " %3d ", side->atkstats[a][d]); X } else { X fprintf(fp, " "); X } X } X fprintf(fp, "\n"); X } X fprintf(fp, "\n"); X} END_OF_attack.c if test 13114 -ne `wc -c <attack.c`; then echo shar: \"attack.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f lib/mapfiles -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"lib/mapfiles\" else echo shar: Extracting \"lib/mapfiles\" \(570 characters\) sed "s/^X//" >lib/mapfiles <<'END_OF_lib/mapfiles' XScenarios Xhill King of the Hill Xeurope42 Axis vs Allies in Europe XPeriods Xempire Old (WB) Empire Xflattop Operational-level carrier battles Xgreek The ancient Greeks Xnapoleon The Age of Napoleon Xfred Frederick the Great Xfuture A strange future XMaps Xcrater Map with a crater lake Xearth1 Big (360x122) map of the Earth Xearth2 Smaller (180x60) map of the Earth Xsteppes All land and nothing else Xsea All sea and nothing else Xthree Three identical islands Xhard Single continent Xharder Single continent, everybody inland XEnd END_OF_lib/mapfiles if test 570 -ne `wc -c <lib/mapfiles`; then echo shar: \"lib/mapfiles\" unpacked with wrong size! fi # end of overwriting check fi if test -f mkmap.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"mkmap.c\" else echo shar: Extracting \"mkmap.c\" \(14026 characters\) sed "s/^X//" >mkmap.c <<'END_OF_mkmap.c' X/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */ X/* This program may be used, copied, modified, and redistributed freely */ X/* for noncommercial purposes, so long as this notice remains intact. */ X X/* RCS $Header: mkmap.c,v 1.1 88/06/21 12:30:21 shebs Exp $ */ X X/* Terrain generation is based on fractal ideas, although this version */ X/* is not directly derived from a published technique. */ X/* Speed is important; most of the code has been integerized. */ X/* Extra steps produce maps more suitable for conquest, including a way to */ X/* control the amount of each type of terrain appearing in the result. */ X/* The process is actually done for elevation and water separately, then */ X/* the terrain type is dependent on both. */ X X/* (Note that this is no longer a separate program as in the first version.) */ X X#include "config.h" X#include "misc.h" X#include "period.h" X#include "dir.h" X#include "map.h" X X/* Values of altitude and moisture must be firmly bounded, so that */ X/* histogramming doesn't take too much space. */ X X#define MAXALT 16384 X X/* Abstraction of 2D malloced array references. Names from Lisp... */ X X#define aref(m,x,y) ((m)[(x)+world.width*(y)]) X X#define aset(m,x,y,v) ((m)[(x)+world.width*(y)] = (v)) X X#define aadd(m,x,y,v) ((m)[(x)+world.width*(y)] += (v)) X X/* Values ultimately arriving from the command line. */ X Xextern int givenwidth, givenheight, givenseen; X X/* Arrays here should contain only nonnegative values (for simplicity). */ X/* They are potentially large and used only once, so we malloc and free... */ X Xint *relief; /* pointer to array of elevations */ Xint *water; /* pointer to array of moisture levels */ Xint *aux; /* auxiliary array */ Xint *histo; /* histogram array */ Xint *alts; /* percentile for each elevation */ Xint *wets; /* percentile for level of moisture */ X X/* The main function looks a little strange in spots, since it is derived */ X/* from a former standalone program (the mkmap of version 1). */ X Xmake_up_map() X{ X int width, height; X X width = givenwidth; height = givenheight; X if (Debug) printf("Going to make up a %dx%d map ...\n", width, height); X /* Heuristic limit - algorithms get weird on small maps */ X if (width < 9 || height < 9) { X fprintf(stderr, "Cannot generate such a small map!\n"); X exit(1); X } X world.width = width; world.height = height; X world.scale = period.scale; X world.known = givenseen; X relief = (int *) malloc(world.width * world.height * sizeof(int)); X aux = (int *) malloc(world.width * world.height * sizeof(int)); X water = (int *) malloc(world.width * world.height * sizeof(int)); X histo = (int *) malloc(MAXALT * sizeof(int)); X alts = (int *) malloc(MAXALT * sizeof(int)); X wets = (int *) malloc(MAXALT * sizeof(int)); X /* Build a full relief map */ X make_bumps(relief, period.altroughness); X smooth_map(relief); X add_curves(relief, period.altroughness); X smooth_map(relief); X limit_map(relief, MAXALT-1, 0); X percentile(relief, alts); X /* Build a "moisture relief" map */ X make_bumps(water, period.wetroughness); X smooth_map(water); X smooth_map(water); X limit_map(water, MAXALT-1, 0); X percentile(water, wets); X /* Put it all together */ X compose_map(); X free(relief); X free(water); X free(aux); X free(histo); X free(alts); X free(wets); X if (Debug) printf("... Done making up a map.\n"); X} X X/* The main map generators produces bumps, of sizes and numbers dictated */ X/* by the roughness. The size is a percentage of map dimensions, while */ X/* number is set to approximately cover the entire map. Each bump is a */ X/* hexagonal shape, and the elevation of interior points varies. */ X Xmake_bumps(map, roughness) Xint *map, roughness; X{ X int blocks, i, scale, var, dx, dy, tries; X int x0, y0, x1, y1, d0, d1, xt, yt, flag, x, y, dz, z, oz; X int dn1, dn2, dn3, dn4, dn5, dn6, numer1, denom1, numer2, denom2; X int farx[10], fary[10]; X int peakx[10], peaky[10], peakz[10], peakf[10], numpeaks = 0, p; X X scale = max(1, ((100 - roughness) * min(world.width, world.height)) / 100); X var = MAXALT/8 + (MAXALT/8 * roughness) / 100; X blocks = (world.width * world.height) / (scale * scale); X blocks *= 2; X if (Debug) printf("Playing with blocks (%d)...\n", blocks); X for (x = 0; x < world.width; ++x) { X for (y = 0; y < world.height; ++y) { X aset(map, x, y, MAXALT/2); X } X } X for (i = 0; i < blocks; ++i) { X flag = ((i == 0 || flip_coin()) ? 1 : -1); X if (scale <= 1) { X x = random(world.width) + world.width; X y = random(world.height); X z = var + random(var/2); X aadd(map, wrap(x), y, flag * z); X } else { X dx = scale/2 + random(scale/2); X dy = scale/2 + random(scale/2); X /* All x values shifted, so as to avoid negatives */ X x0 = random(world.width) + world.width; X y0 = random(world.height - dy - 1); X x1 = x0 + dx + 1; X y1 = y0 + dy + 1; X d0 = min(x1 - x0, y1 - y0) / 4; X d0 = d0 + random(3*d0); X d1 = min(x1 - x0, y1 - y0) / 4; X d1 = d1 + random(3*d1); X /* Cheap way to ensure most high points actually within hexagon */ X xt = yt = -1; tries = 10; X while (((xt-x0+yt-y0 < d0) || (x1-xt+y1-yt > d1)) && tries-- > 0) { X xt = x0 + (random(x1 - x0) + random(x1 - x0)) / 2; X yt = y0 + (random(y1 - y0) + random(y1 - y0)) / 2; X } X /* Compute distances from high point to hexagon corners */ X dn1 = distance(xt, yt, x1-d1, y1); X dn2 = distance(xt, yt, x1, y1-d1); X dn3 = distance(xt, yt, x1, y0); X dn4 = distance(xt, yt, x0+d0, y0); X dn5 = distance(xt, yt, x0, y0+d0); X dn6 = distance(xt, yt, x0, y1); X for (y = y0; y <= y1; ++y) { X for (x = x0; x <= x1; ++x) { X if ((x-x0+y-y0 > d0) && (x1-x+y1-y > d1)) { X dx = x - xt; dy = y - yt; X if (dx > 0) { X if (dy > 0) { X numer1 = distance(x, y, x1, y1-d1); X denom1 = dn2; X numer2 = distance(x, y, x1-d1, y1); X denom2 = dn1; X } else if (dy > (0 - dx)) { X numer1 = distance(x, y, x1, y0); X denom1 = dn3; X numer2 = distance(x, y, x1, y1-d1); X denom2 = dn2; X } else { X numer1 = distance(x, y, x0+d0, y0); X denom1 = dn4; X numer2 = distance(x, y, x1, y0); X denom2 = dn3; X } X } else { X if (dy < 0) { X numer1 = distance(x, y, x0, y0+d0); X denom1 = dn5; X numer2 = distance(x, y, x0+d0, y0); X denom2 = dn4; X } else if (dy < (0 - dx)) { X numer1 = distance(x, y, x0, y1); X denom1 = dn6; X numer2 = distance(x, y, x0, y0+d0); X denom2 = dn5; X } else { X numer1 = distance(x, y, x1-d1, y1); X denom1 = dn1; X numer2 = distance(x, y, x0, y1); X denom2 = dn6; X } X } X if (denom1 == 0) denom1 = 1; X if (denom2 == 0) denom2 = 1; X dz = (flag * ((var * numer1) / denom1 + X (var * numer2) / denom2)); X oz = aref(map, wrap(x), y); X if (!between(0, dz + oz, MAXALT)) dz /= 2; X aset(map, wrap(x), y, oz + dz + random(var/2)); X } X } X } X } X /* Remember some high points for use in hitting untouched areas */ X if (numpeaks < 10) { X peakx[numpeaks] = wrap(xt); X peaky[numpeaks] = yt; X peakf[numpeaks] = flag; X peakz[numpeaks] = var; X farx[numpeaks] = wrap(xt+world.width/2); X fary[numpeaks] = random(world.height); X numpeaks++; X } X } X /* This is to make smoothly varying terrain in formerly flat areas */ X for (x = 0; x < world.width; ++x) { X for (y = 0; y < world.height; ++y) { X if (aref(map, x, y) == MAXALT/2) { X z = 0; X for (p = 0; p < numpeaks; ++p) { X dz = ((peakz[p] * cyldist(x, y, farx[p], fary[p])) / X (cyldist(peakx[p], peaky[p], farx[p], fary[p])+1)); X dz -= (peakz[p] * scale) / world.width; X z += peakf[p] * dz; X } X z /= numpeaks; X aadd(map, x, y, z + random(var/4)); X } X } X } X limit_map(map, MAXALT-1, 0); X} X X/* Returns shortest distance around the world (can be either direction). */ X Xcyldist(x1, y1, x2, y2) Xint x1, y1, x2, y2; X{ X int dist = distance(x1, y1, x2, y2), dist2; X X if ((dist2 = distance(x1+world.width, y1, x2, y2)) < dist) { X dist = dist2; X } else if ((dist2 = distance(x1, y1, x2+world.width, y2)) < dist) { X dist = dist2; X } X return dist; X} X X/* Exponent with *small* integer power. (used with Bezier curves) */ X Xfloat Xexpt(f, i) Xfloat f; Xint i; X{ X float rslt = 1.0; X X while (i-- > 0) rslt = rslt * f; X return rslt; X} X X/* Combination of n objects taken i at a time. (used for Bezier) */ X Xcomb(n, i) Xint n, i; X{ X if (i <= 0) return 1; X else if (n <= 0) return 0; X else return (comb(n-1, i) + comb(n-1,i-1)); X} X X/* Put in random Bezier mountain chains. Number and size are scaled to */ X/* the size of the map. To prevent criss-crossing from creating very */ X/* high spots, just set the aux map to values, and only add in later. */ X Xadd_curves(map, roughness) Xint *map, roughness; X{ X int i, j, n, x, y, flag, curves, mindim, var; X float u, f, cpx[4], cpy[4], px[500], py[500]; X X curves = (world.width * world.height * roughness) / 50000; X if (Debug) printf("Throwing curves (%d)...\n", curves); X for (x = 0; x < world.width; ++x) { X for (y = 0; y < world.height; ++y) { X aset(aux, x, y, 0); X } X } X mindim = min(500, min(world.width, world.height)); X var = (MAXALT/8 * roughness) / 100; X for (n = 0; n < curves; ++n) { X cpx[0] = 1.0 * (random(world.width-2)+1); X cpy[0] = 1.0 * (random(world.height-2)+1); X for (j = 1; j < 4; ++j) { X cpx[j] = cpx[0] + (random(mindim) - mindim/2); X if (cpx[j] > world.width-1) cpx[j] = world.width-1; X if (cpx[j] < 0) cpx[j] = 0; X cpy[j] = cpy[0] + (random(mindim) - mindim/2); X if (cpy[j] > world.height-1) cpy[j] = world.height-1; X if (cpy[j] < 0) cpy[j] = 0; X } X for (i = 0; i < mindim; ++i) { X u = (1.0 * i) / mindim; X px[i] = py[i] = 0.0; X for (j = 0; j < 4; ++j) { X f = comb(3,j)*expt(u,j)*expt(1-u,3-j); X px[i] += cpx[j]*f; X py[i] += cpy[j]*f; X } X } X flag = random(3) ? 1 : -1; X for (i = 0; i < mindim; ++i) { X x = (int) px[i]; y = (int) py[i]; X aset(aux, x, y, flag * (MAXALT/8 + var)); X } X } X add_maps(map, aux, map); X limit_map(map, MAXALT-1, 0); X} X X/* Ensure that map values stay within given range. */ X Xlimit_map(map, hi, lo) Xint *map, hi, lo; X{ X int x, y, m; X X for (x = 0; x < world.width; ++x) { X for (y = 0; y < world.height; ++y) { X m = aref(map, x, y); X aset(map, x, y, max(lo, min(m, hi))); X } X } X} X X/* Form the point-wise sum of two maps into a third one. */ X Xadd_maps(m1, m2, rslt) Xint *m1, *m2, *rslt; X{ X int x, y; X X for (x = 0; x < world.width; ++x) { X for (y = 0; y < world.height; ++y) { X aset(rslt, x, y, aref(m1, x, y) + aref(m2, x, y)); X } X } X} X X/* Average out things to keep peaks from getting too sharp. */ X/* The array "aux" is the buffer for this operation. */ X/* The edges of the map remain unaltered. (dubious) */ X Xsmooth_map(map) Xint *map; X{ X int x, y, nx, px, sum; X X if (Debug) printf("Smoothing...\n"); X for (x = 0; x < world.width; ++x) { X nx = wrap(x+1); px = wrap(x-1); X for (y = 1; y < world.height-1; ++y) { X sum = aref(map, x, y); X sum += aref(map, x, y+1); X sum += aref(map, nx, y); X sum += aref(map, nx, y-1); X sum += aref(map, x, y-1); X sum += aref(map, px, y); X sum += aref(map, px, y+1); X aset(aux, x, y, sum / 7); X } X } X for (x = 0; x < world.width; ++x) { X for (y = 1; y < world.height-1; ++y) { X aset(map, x, y, aref(aux, x, y)); X } X } X} X X/* Terrain types are specified in terms of percentage cover on a map, so */ X/* for instance the Earth is 70% sea. Since each of several types will have */ X/* its own percentages (both for elevation and moisture), the simplest thing */ X/* to do is to calculate the percentile for each elevation and moisture */ X/* level, and save them all away. This would be a one-liner in APL... */ X X/* Percentile computation is inefficient, should be done incrementally */ X/* somehow instead of with * and / */ X Xpercentile(map, percentiles) Xint *map, *percentiles; X{ X int i, x, y, total; X X if (Debug) printf("Computing percentiles...\n"); X for (i = 0; i < MAXALT; ++i) { X histo[i] = 0; X percentiles[i] = 0; X } X /* Make the basic histogram, but don't count the edges */ X for (x = 0; x < world.width; ++x) { X for (y = 1; y < world.height-1; ++y) { X ++histo[aref(map, x, y)]; X } X } X /* Integrate over the histogram */ X for (i = 1; i < MAXALT; ++i) X histo[i] += histo[i-1]; X /* Total here should actually be the same as number of cells in the map */ X total = histo[MAXALT-1]; X /* Compute the percentile position */ X for (i = 0; i < MAXALT; ++i) X percentiles[i] = (100 * histo[i]) / total; X} X X/* Final creation and output of the map. */ X Xcompose_map() X{ X int x, y; X X if (Debug) printf("Assigning terrain types...\n"); X allocate_map(); X for (y = 0; y < world.height; ++y) { X for (x = 0; x < world.width; ++x) { X set_terrain_at(x, y, terrain(x, y)); X set_unit_at(x, y, NULL); X } X } X /* Add a border if specified */ X if (period.edgeterrain >= 0) { X for (x = 0; x < world.width; ++x) { X set_terrain_at(x, 0, period.edgeterrain); X set_terrain_at(x, world.height-1, period.edgeterrain); X } X } X} X X/* Do final output of terrain types. This is basically a process of */ X/* checking the percentile limits on each type against what is actually */ X/* there. (could and maybe should be more efficient) */ X/* Error checking important for period designers... */ X Xterrain(x, y) Xint x, y; X{ X int t, a = aref(relief, x, y), w = aref(water, x, y); X X for_all_terrain_types(t) { X if (between(ttypes[t].minalt, alts[a], ttypes[t].maxalt) && X between(ttypes[t].minwet, wets[w], ttypes[t].maxwet)) { X return t; X } X } X printf("Unknown terrain in percentiles alt %d, wet %d.\n", X alts[a], wets[w]); X /* Not great, but valid if nothing else */ X return (max(0, period.defaultterrain)); X} END_OF_mkmap.c if test 14026 -ne `wc -c <mkmap.c`; then echo shar: \"mkmap.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f period.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"period.h\" else echo shar: Extracting \"period.h\" \(10836 characters\) sed "s/^X//" >period.h <<'END_OF_period.h' X/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */ X/* This program may be used, copied, modified, and redistributed freely */ X/* for noncommercial purposes, so long as this notice remains intact. */ X X/* RCS $Header: period.h,v 1.1 88/06/21 12:29:45 shebs Exp $ */ X X/* Structures containing period parameters. */ X/* To simplify period compilation, the slots are arranged so that scalar */ X/* values are generally grouped together. However, we're not too hardnosed */ X/* about it, and do segregate by general classes of values. In any case, */ X/* the period compiler *must* be kept consistent with these structures. */ X X/* There is only one period object, but it's useful to get all global */ X/* period parameters glued into a single structure. */ X Xtypedef struct a_period { X char *name; /* name of period */ X char **notes; /* designer's notes for period */ X char *fontname; /* name of font for period (optional) */ X short scale; /* default width of hex in km */ X short countrysize; /* radius of country in hexes */ X short mindistance; /* distance between countries in hexes */ X short maxdistance; /* distance between countries in hexes */ X short numutypes; /* number of unit types */ X short numrtypes; /* number of resource types */ X short numttypes; /* number of terrain types */ X short numsnames; /* number of random side names */ X short numunames; /* number of random unit names */ X short firstutype; /* starting unit if only one */ X short firstptype; /* what it will try to produce (check plaus) */ X short knownradius; /* area around the country that has been seen */ X short allseen; /* true if all units always seen */ X short counterattack; /* true if attacks go both ways */ X short nukehit; /* how big a hit to qualify as nuke */ X short neutrality; /* how much more difficult to get neutrals */ X short efficiency; /* efficiency of unit recycling */ X short population; /* occurrence of populations */ X short hostility; /* hostility of populace towards units */ X short altroughness; /* fractal dimension for altitude */ X short wetroughness; /* fractal dimension for moisture */ X short defaultterrain; /* type of terrain to subst if unknown */ X short edgeterrain; /* type of terrain to put on N/S edge */ X short spychance; /* chance of spying each turn */ X short spyquality; /* percentage of info gathered when spying */ X} Period; X X/* Unit type descriptions go into a single structure. This structure */ X/* contains every single piece of information about all unit types. */ X Xtypedef struct utype { X char uchar; /* character used in prompts */ X char *name; /* the name (frequently used!) */ X char *help; /* one-line description */ X char **notes; /* longer description */ X char *bitmapname; /* name of icon file (optional) */ X /* attributes for initialization */ X short incountry; /* number that a side starts out with */ X short density; /* number of units per ten thousand hexes */ X short named; /* true if unit gets randomly-assigned name */ X short alreadyseen; /* true if unit seen at the outset */ X short favored[MAXTTYPES]; /* chance to be found on given terrain */ X short stockpile[MAXRTYPES]; /* percentage of supply at outset */ X /* attributes for revolt phase */ X short revolt; /* chance to revolt */ X short surrender; /* base chance to surrender to nearby unit */ X short siege; /* extra chance to be captured in siege */ X short attdamage; /* damage when attrition happens */ X char *attritionmsg; /* what to say when attrition happens */ X char *accidentmsg; /* what to say when an accident happens */ X short attrition[MAXTTYPES]; /* chance to lose hp */ X short accident[MAXTTYPES]; /* chance to lose totally */ X /* attributes for build phase */ X short maker; /* true if unit always builds */ X short startup; /* extra prod schedule for first from unit */ X short research; /* extra production schedule for first on side */ X short make[MAXUTYPES]; /* base time to build a unit */ X short tomake[MAXRTYPES]; /* amount of resource needed to build */ X short repair[MAXUTYPES]; /* how many turns to regain a hit point */ X /* attributes for supply phase */ X short survival; /* how long unit can starve */ X char *starvemsg; /* what to say when unit runs out of supplies */ X short produce[MAXRTYPES]; /* rate of supply production */ X short productivity[MAXTTYPES]; /* effect of terrain on production */ X short storage[MAXRTYPES]; /* capacity for each type of resource */ X short consume[MAXRTYPES]; /* overhead consumption in each turn */ X short inlength[MAXRTYPES]; /* length of supply line coming in */ X short outlength[MAXRTYPES]; /* length of supply line going out */ X /* attributes for move phase */ X short freemove; /* true if last move not constrained */ X short speed; /* maximum theoretical speed in hexes/turn */ X short onemove; /* true if unit gets exactly one move order */ X short jumpmove; /* true if unit can jump over other units */ X short moves[MAXTTYPES]; /* additional overhead due to terrain */ X short randommove[MAXTTYPES]; /* randomness of move (.01% per turn) */ X short tomove[MAXRTYPES]; /* supplies used to move with */ X /* attributes for transportation */ X short volume; /* how much space one part takes */ X short holdvolume; /* space for passengers */ X short capacity[MAXUTYPES]; /* carrying capacity, by unit type */ X short entertime[MAXUTYPES]; /* moves to get on transport */ X short leavetime[MAXUTYPES]; /* moves to get off transport */ X short bridge[MAXUTYPES]; /* true if transport accessible across terr */ X short mobility[MAXUTYPES]; /* true if unit is useless as occupant */ X /* attributes for viewing */ X short seealways; /* true if unit view always up-to-date */ X short seebest; /* chance of seeing other units */ X short seeworst; /* see chance at max range */ X short seerange; /* how far unit can see another */ X short visibility; /* how easily others can see us */ X short conceal[MAXTTYPES]; /* how visible in given terrain */ X /* attributes for combat */ X short parts; /* max number of parts */ X short hp; /* max number of hit points */ X short crippled; /* hp at which unit loses functionality */ X short hitrange; /* how far away we can shoot from */ X short selfdestruct; /* true if unit always dies in attack */ X short changeside; /* chance of actually changing sides */ X short hittime; /* extra moves to attack */ X short retreat; /* chance of retreat to avoid a hit */ X short counterable; /* true if can counterattack */ X short arearadius; /* how big an area is hit */ X char *destroymsg; /* what to say when unit dies in combat */ X short hit[MAXUTYPES]; /* chance of hitting other units */ X short defense[MAXTTYPES]; /* how easy to hit in given terrain */ X short damage[MAXUTYPES]; /* how many points it hits for */ X short hitswith[MAXRTYPES]; /* amount of supply used for ammo */ X short hitby[MAXRTYPES]; /* kind of ammo that hits unit */ X short capture[MAXUTYPES]; /* chance of capturing a unit */ X short guard[MAXUTYPES]; /* num parts needed to garrison/guard a capture */ X short protect[MAXUTYPES]; /* effect on occupant on transport etc */ X /* random general attributes */ X short territory; /* territorial value of unit */ X short isneutral; /* true if unit can change side or be neutral */ X short maxquality; /* most veteranness achievable */ X short skillf; /* effect of quality on attack */ X short disciplinef; /* effect of quality on defense etc */ X short maxmorale; /* most possible morale */ X short moralef; /* effect of morale on combat */ X short control; /* chance of unit obeying orders */ X short disband; /* true if unit can be gotten rid of */ X} Utype; X X/* Definition of resource types. These could maybe go in with utype stuff, */ X/* but are more conveniently separated. */ X Xtypedef struct rtype { X char rchar; /* char representing resource */ X char *name; /* short name of resource */ X char *help; /* help string about resource */ X} Rtype; X X/* Definition of terrain types. Most parameters are to get generation */ X/* right; unit interactions are all in utypes. */ X Xtypedef struct ttype { X char tchar; /* char representing type */ X char *name; /* name of terrain */ X char *color; /* name of a color for color displays */ X short dark; /* true if terrain is "dark" */ X short nuked; /* terrain type after being nuked */ X short minalt; /* lowest altitude percentile for this type */ X short maxalt; /* highest altitude percentile for this type */ X short minwet; /* lowest moisture percentile */ X short maxwet; /* highest moisture percentile */ X short inhabitants; /* density of population */ X short independence; /* character of population */ X} Ttype; X X/* Macros for iterating over period description structures. */ X X#define for_all_unit_types(v) for (v = 0; v < period.numutypes; ++v) X X#define for_all_resource_types(v) for (v = 0; v < period.numrtypes; ++v) X X#define for_all_terrain_types(v) for (v = 0; v < period.numttypes; ++v) X X/* Macros to reduce the number of brackets and explicit structure refs. */ X X#define could_make(u1,u2) (utypes[u1].make[u2] > 0) X X#define could_repair(u1, u2) (utypes[u1].repair[u2] > 0) X X#define could_move(u,t) (utypes[u].moves[t] >= 0) X X#define could_carry(u1,u2) (utypes[u1].capacity[u2] > 0) X X#define could_hit(u1,u2) (utypes[u1].hit[u2] > 0) X X#define could_capture(u1,u2) (utypes[u1].capture[u2] > 0) X X#define impassable(u, x, y) (!could_move((u)->type, terrain_at((x), (y)))) X X/* Declarations of the period description structures. The structures */ X/* themselves will be in a compiled period description. */ X Xextern Period period; X Xextern Utype utypes[]; X Xextern Rtype rtypes[]; X Xextern Ttype ttypes[]; X Xextern char *snames[], *unames[]; END_OF_period.h if test 10836 -ne `wc -c <period.h`; then echo shar: \"period.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f side.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"side.c\" else echo shar: Extracting \"side.c\" \(12573 characters\) sed "s/^X//" >side.c <<'END_OF_side.c' X/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */ X/* This program may be used, copied, modified, and redistributed freely */ X/* for noncommercial purposes, so long as this notice remains intact. */ X X/* RCS $Header: side.c,v 1.1 88/06/21 12:30:40 shebs Exp $ */ X X/* The "side" structure is the repository of information about players. */ X/* Surprisingly, there is not much code to manipulate side directly. */ X/* Viewing code is somewhat tricky, since any hex may be viewed by any */ X/* number of sides at once. */ X X#include "config.h" X#include "misc.h" X#include "dir.h" X#include "period.h" X#include "side.h" X#include "unit.h" X#include "map.h" X XSide sides[MAXSIDES]; /* array containing all sides (not very many) */ XSide *sidelist; /* head of list of all sides */ XSide *tmpside; /* temporary used in many places */ X Xint numsides; /* number of sides in the game */ X Xchar *reasonnames[] = REASONNAMES; /* names of columns in unit record */ X X/* Reset any side structures that need it. */ X Xinit_sides() X{ X int i; X X for (i = 0; i < MAXSIDES; ++i) { X sides[i].name = NULL; X } X sidelist = NULL; X numsides = 0; X} X X/* Create an object representing a side. Checking to make sure all human */ X/* players have displays has been done by now, so problems mean bugs. */ X XSide * Xcreate_side(name, person, host) Xchar *name, *host; Xbool person; X{ X int s, i; X Side *newside; X X /* Can't have humans without displays */ X if (person && host == NULL) abort(); X if (name == NULL) name = "???"; X for (s = 0; s < MAXSIDES; ++s) { X if (sides[s].name == NULL) { X newside = &(sides[s]); X newside->name = copy_string(name); X newside->humanp = person; X if (host == NULL || strcmp(host, "*") == 0) { X newside->host = NULL; X } else { X newside->host = copy_string(host); X } X newside->lost = FALSE; X for_all_unit_types(i) { X newside->counts[i] = 1; X newside->units[i] = 0; X newside->building[i] = 0; X } X for_all_resource_types(i) { X newside->resources[i] = 0; X } X newside->showmode = BORDERHEX; X newside->itertime = 100; X newside->view = X (unchar *) malloc(world.width*world.height*sizeof(unchar)); X newside->coverage = X (short *) malloc(world.width*world.height*sizeof(short)); X init_view(newside); X newside->graphical = GRAPHICAL; X newside->display = 0L; X init_requests(newside); X link_in_side(newside); X ++numsides; X return newside; X } X } X fprintf(stderr, "Cannot have more than %d sides total!\n", MAXSIDES); X abort(); X} X X/* Add the new side to the end of the list of sides - this keeps our */ X/* list traversals going from top to bottom (the things we do to keep */ X/* users happy...). */ X Xlink_in_side(side) XSide *side; X{ X Side *head, *last; X X if (sidelist == NULL) { X sidelist = side; X } else { X for_all_sides(head) { X if (head->next == NULL) last = head; X } X last->next = side; X } X side->next = NULL; X} X X/* Initialize basic viewing structures for a side, in preparation for the */ X/* placement of units. */ X Xinit_view(side) XSide *side; X{ X int x, y, cov, seen; X X cov = (period.allseen ? 100 : 0); X seen = ((period.allseen || world.known) ? EMPTY : UNSEEN); X for (x = 0; x < world.width; ++x) { X for (y = 0; y < world.height; ++y) { X set_cover(side, x, y, cov); X set_side_view(side, x, y, seen); X } X } X} X X/* Given a side, get its relative position in array of sides (the "number"). */ X/* Neutrals are -1, for lack of any better ideas. */ X Xside_number(side) XSide *side; X{ X return (side == NULL ? -1 : (side - sides)); X} X X/* The inverse function - given a number, figure out which side it is. */ X/* Return NULL for failure; hopefully callers will check on this! */ X XSide * Xside_n(n) Xint n; X{ X return ((n >= 0 && n < numsides) ? &sides[n] : NULL); X} X X/* Put the given unit on the given side, without all the fancy effects. */ X/* Important to handle neutrals, because this gets called during init. */ X Xassign_unit_to_side(unit, side) XUnit *unit; XSide *side; X{ X unit->side = side; X unit->number = (side != NULL ? (side->counts)[unit->type]++ : 0); X} X X/* Being at war requires only ones of the sides to consider itself so. */ X Xenemy_side(s1, s2) XSide *s1, *s2; X{ X if (s1 == s2) return FALSE; X return (s1 != NULL && s2 != NULL && X (s1->attitude[side_number(s2)] <= ENEMY || X s2->attitude[side_number(s1)] <= ENEMY)); X} X X/* A formal alliance requires the agreement of both sides. */ X Xallied_side(s1, s2) XSide *s1, *s2; X{ X if (s1 == s2) return TRUE; X return (s1 != NULL && s2 != NULL && X s1->attitude[side_number(s2)] >= ALLY && X s2->attitude[side_number(s1)] >= ALLY); X} X X/* Neutralness is basically anything else. */ X Xneutral_side(s1, s2) XSide *s1, *s2; X{ X return (!enemy_side(s1, s2) && !allied_side(s1, s2)); X} X X/* Formal declarations of war need to do a transitive closure, as part of */ X/* dragging allies in. */ X Xdeclare_war(side1, side2) XSide *side1, *side2; X{ X Side *side3; X X notify_all("The %s and the %s have declared war!!", X copy_string(plural_form(side1->name)), X copy_string(plural_form(side2->name))); X make_war(side1, side2); X for_all_sides(side3) { X if (allied_side(side3, side1)) make_war(side3, side2); X if (allied_side(side3, side2)) make_war(side3, side1); X } X} X X/* Internal non-noisy function. */ X Xmake_war(side1, side2) XSide *side1, *side2; X{ X side1->attitude[side_number(side2)] = ENEMY; X side2->attitude[side_number(side1)] = ENEMY; X} X X/* Establish neutrality for both sides. */ X Xdeclare_neutrality(side1, side2) XSide *side1, *side2; X{ X notify_all("The %s and the %s have agreed to neutrality.", X copy_string(plural_form(side1->name)), X copy_string(plural_form(side2->name))); X make_neutrality(side1, side2); X} X X/* Internal non-noisy function. */ X Xmake_neutrality(side1, side2) XSide *side1, *side2; X{ X side1->attitude[side_number(side2)] = NEUTRAL; X side2->attitude[side_number(side1)] = NEUTRAL; X} X X/* Establish the alliance for both sides, then extend it to include */ X/* every other ally (only need one pass over sides to ensure transitive */ X/* closure, because alliances formed one at a time). */ X Xdeclare_alliance(side1, side2) XSide *side1, *side2; X{ X Side *side3; X X notify_all("The %s and the %s enter into an alliance.", X copy_string(plural_form(side1->name)), X copy_string(plural_form(side2->name))); X make_alliance(side1, side2); X for_all_sides(side3) { X if (allied_side(side3, side1)) make_alliance(side3, side2); X if (allied_side(side3, side2)) make_alliance(side3, side1); X } X} X X/* Internal non-noisy function. */ X Xmake_alliance(side1, side2) XSide *side1, *side2; X{ X if (side1 != side2) { X side1->attitude[side_number(side2)] = ALLY; X side2->attitude[side_number(side1)] = ALLY; X } X} X X/* General method for passing along info about one side to another. */ X/* If sender is NULL, it means to pass along info about *all* sides. */ X Xreveal_side(sender, recipient, chance) XSide *sender, *recipient; Xint chance; X{ X Unit *unit; X X for_all_units(unit) { X if (alive(unit) && X (unit->side == sender || sender == NULL) && X probability(chance)) { X see_exact(recipient, unit->x, unit->y); X draw_hex(recipient, unit->x, unit->y, TRUE); X } X } X} X X/* An always-seen unit has builtin spies to inform of movements. */ X/* When such a unit occupies a hex, coverage is turned on and remains */ X/* on until the unit leaves that hex. */ X Xall_see_occupy(unit, x, y) XUnit *unit; Xint x, y; X{ X Side *side; X X if (utypes[unit->type].seealways) { X for_all_sides(side) { X if (side_view(side, x, y) != UNSEEN) { X add_cover(side, x, y, 100); X see_hex(side, x, y); X } X } X } X} X X/* Departure results in coverage being decremented, AFTER the side sees */ X/* that the hex is now empty. */ X Xall_see_leave(unit, x, y) XUnit *unit; Xint x, y; X{ X Side *side; X X if (utypes[unit->type].seealways) { X for_all_sides(side) { X if (side_view(side, x, y) != UNSEEN) { X see_hex(side, x, y); X add_cover(side, x, y, -100); X } X } X } X} X X/* Unit's beady eyes are now covering the immediate area. The iteration */ X/* covers a hex area; since new things may be coming into view, we have */ X/* to check and maybe draw lots of hexes (but only need the one flush, */ X/* fortunately). */ X Xcover_area(unit, x0, y0, onoff) XUnit *unit; Xint x0, y0, onoff; X{ X int u = unit->type, range, x, y, x1, y1, x2, y2, best, diff, dist, cov; X Unit *eunit; X Side *side = unit->side; X X if (neutral(unit) || period.allseen) return; X range = utypes[u].seerange; X best = utypes[u].seebest; X diff = best - utypes[u].seeworst; X y1 = y0 - range; X y2 = y0 + range; X for (y = y1; y <= y2; ++y) { X if (between(0, y, world.height-1)) { X x1 = x0 - (y < y0 ? (y - y1) : range); X x2 = x0 + (y > y0 ? (y2 - y) : range); X for (x = x1; x <= x2; ++x) { X dist = distance(x0, y0, x, y); X cov = (onoff * (best - (dist * diff) / range)) + X cover(side, wrap(x), y); X set_cover(side, wrap(x), y, max(0, cov)); X if (onoff > 0 && see_hex(side, wrap(x), y)) { X if ((eunit = unit_at(wrap(x), y)) != NULL) { X if (unit->orders.flags & ENEMYWAKE) X if (!allied_side(eunit->side, side)) X wake_unit(unit, TRUE); X } X } X } X } X } X if (onoff > 0 && active_display(side)) flush_output(side); X} X X/* Update the view of this hex for everybody's benefit. May have to write */ X/* to many displays, sigh. */ X Xall_see_hex(x, y) Xint x, y; X{ X register Side *side; X X for_all_sides(side) see_hex(side, x, y); X} X X/* Look at the given position, possibly not seeing anything. Return true if */ X/* a unit was spotted. */ X Xsee_hex(side, x, y) XSide *side; Xint x, y; X{ X register bool yes = FALSE; X register int u, chance, newview, terr; X register Unit *unit; X X if (side == NULL) return FALSE; X if (cover(side, x, y) > 0) { X if ((unit = unit_at(x, y)) != NULL) { X u = unit->type; X if (unit->side == side) { X yes = TRUE; X } else { X chance = (cover(side, x, y) * utypes[u].visibility) / 100; X terr = terrain_at(x, y); X chance = (chance * (100 - utypes[u].conceal[terr])) / 100; X if (probability(chance)) yes = TRUE; X } X if (yes) { X newview = buildview(side_number(unit->side), u); X set_side_view(side, x, y, newview); X draw_hex(side, x, y, FALSE); X return TRUE; X } else { X return FALSE; X } X } else { X set_side_view(side, x, y, EMPTY); X draw_hex(side, x, y, FALSE); X return FALSE; X } X } else { X /* preserve old image */ X return FALSE; X } X} X X/* "Bare-bones" viewing, for whenever you know exactly what's there. */ X/* This is the lowest level of all viewing routines, and executed a *lot*. */ X Xsee_exact(side, x, y) XSide *side; Xint x, y; X{ X register int newview; X register Unit *unit = unit_at(x, y); X X if (side == NULL) return; X newview = (unit ? buildview(side_number(unit->side), unit->type) : EMPTY); X set_side_view(side, x, y, newview); X} X X/* Utility to clean up images of units from a lost side. */ X Xremove_images(side, n) XSide *side; Xint n; X{ X int x, y, view; X X for (x = 0; x < world.width; ++x) { X for (y = 0; y < world.height; ++y) { X view = side_view(side, x, y); X if (view != EMPTY && view != UNSEEN && vside(view) == n) { X set_side_view(side, x, y, EMPTY); X } X } X } X} X X/* Show some overall numbers on performance of a side. */ X Xprint_side_results(fp, side) XFILE *fp; XSide *side; X{ X fprintf(fp, "The %s (%s):\n", X plural_form(side->name), (side->host ? side->host : "machine")); X fprintf(fp, "\n"); X} X X/* Display what is essentially a double-column bookkeeping of unit gains */ X/* and losses. Tricks here include the use of "dummy reason" flags to */ X/* display sums of several columns. */ X Xprint_unit_record(fp, side) XFILE *fp; XSide *side; X{ X int atype, reason, sum; X X fprintf(fp, "Unit Record (gains and losses by cause and unit type)\n"); X fprintf(fp, " "); X for (reason = 0; reason < NUMREASONS; ++reason) { X fprintf(fp, " %3s", reasonnames[reason]); X } X fprintf(fp, " Total\n"); X for_all_unit_types(atype) { X sum = 0; X fprintf(fp, " %c ", utypes[atype].uchar); X for (reason = 0; reason < NUMREASONS; ++reason) { X if (side->balance[atype][reason] > 0) { X fprintf(fp, " %3d", side->balance[atype][reason]); X sum += side->balance[atype][reason]; X } else if (reason == DUMMYREAS) { X fprintf(fp, " %3d", sum); X sum = 0; X } else { X fprintf(fp, " "); X } X } X fprintf(fp, " %3d\n", sum); X } X fprintf(fp, "\n"); X} END_OF_side.c if test 12573 -ne `wc -c <side.c`; then echo shar: \"side.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 13 \(of 18\). cp /dev/null ark13isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 18 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0