games-request@tekred.UUCP (07/10/87)
Submitted by: "Stanley T. Shebs" <shebs%orion@cs.utah.edu> Comp.sources.games: Volume 1, Issue 84 Archive-name: xconq/Part04 #! /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 4 (of 7)." # Contents: X.c atk.c city.c mplay.c # Wrapped by billr@tekred on Thu Jul 9 17:45:44 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f X.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"X.c\" else echo shar: Extracting \"X.c\" \(12854 characters\) sed "s/^X//" >X.c <<'END_OF_X.c' X/* Copyright (c) 1987 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: X.c,v 1.9 87/06/08 21:44:52 shebs Exp $ */ X X#include "xconq.h" X X/* Random bitmaps that we want to relegate to a separate file. */ X X#include "bitmaps.h" X X/* Default size of the view window. Making other sizes work would take */ X/* some fiddling around I think. */ X X#define VWID 35 X#define VHGT 35 X X/* This is the common size of all bitmaps, tiles, etc. This number is so */ X/* wired in, it makes one ashamed for using X. */ X X#define SQ 16 X X#define MAPWINSIZE (SQ*VWID) X X/* The unit/city icon font is different for each period, and is defined */ X/* in the period description file. */ X Xextern char fontname[]; X X/* Wishful thinking about what colors are available... */ X Xchar *terrcolors[] = { "sky blue", "cyan", "green", "forest green", X "yellow", "sienna", "white" }; X Xint mapmag = 1; /* size of blobs on world map */ X Xint vwid, vhgt; /* height of window screen */ Xint vwid2, vhgt2; /* half-heights rounded down */ Xint fw, fh; /* font size info */ X X/* Put starting city at center (or close to it) of first view. I guess we */ X/* can't use put_on_screen because not enough stuff is inited yet. */ X Xinit_curxy(side) XSide *side; X{ X City *city; X X for (city = citylist; city != NULL; city = city->next) { X if (city->side == side) { X side->vcx = city->x; X side->vcy = min(max(city->y, vwid2+1), (worldheight-1)-vhgt2); X } X } X} X X#ifdef XWINDOWS X X/* The very first step in using X is to open up all the desired displays. */ X/* In our case, there are many displays each with many windows. */ X/* The world map is magnified to a scale guaranteed to fit in the alloted */ X/* space, but be as large as will fit (but not too large). */ X Xopen_displays() X{ X Side *side; X X mapmag = min(5, (MAXWIDTH / worldwidth)); X vwid = min(worldwidth, VWID); X vhgt = min(worldheight, VHGT); X vwid2 = vwid/2; X vhgt2 = vhgt/2; X X for_all_sides(side) { X if (side->host != NULL) { X open_display(side); X } X } X} X X/* Open display and all the windows we'll need. Note that each window will */ X/* be attached to the current display, which is the one just opened. */ X/* All the windows start out mapped and non-overlapping, except the help */ X/* window, which exactly overlays the main map and therefore gets unmapped. */ X Xopen_display(side) XSide *side; X{ X int i, mainwidth, mainheight; X Window mainwin; X X if ((side->display = XOpenDisplay(side->host)) == NULL) { X fprintf(stderr, "Display %s could not be opened!\n", side->host); X exit(0); X } X XSetDisplay(side->display); X X get_fonts(side); X get_colors(side); X store_bitmaps(side); X X mainwidth = MAPWINSIZE + MAXWIDTH + 1; X mainheight = MAPWINSIZE + 13*fh + 3; X X side->bordertile = XMakeTile(side->bdcolor); X /* kludge test - why doesn't this work for microvaxen? */ X if (!side->fewcolors) { X side->dotpix = XMakePixmap(side->dots, side->graycolor, side->bgcolor); X } else { X side->dotpix = BlackPixmap; X } X side->main = XCreateWindow(RootWindow, 50, 3, mainwidth, mainheight, X 3, side->bordertile, side->dotpix); X mainwin = side->main; X X side->msg = XCreateWindow(mainwin, 0, 0, mainwidth, 10*fh, X 1, side->bordertile, BlackPixmap); X side->info = XCreateWindow(mainwin, 0, 10*fh+1, mainwidth, 2*fh, X 1, side->bordertile, BlackPixmap); X side->prompt = XCreateWindow(mainwin, 0, 12*fh+2, mainwidth, 1*fh, X 1, side->bordertile, BlackPixmap); X side->map = XCreateWindow(mainwin, 0, 13*fh+3, MAPWINSIZE, MAPWINSIZE, X 1, side->bordertile, BlackPixmap); X side->time = XCreateWindow(mainwin, MAPWINSIZE+fw, 13*fh+3+7, 9*fw, fh, X 1, side->bordertile, BlackPixmap); X side->clock = XCreateWindow(mainwin, X MAPWINSIZE+fw+9*fw+fw, 13*fh+3+7, 2*fw, fh, X 1, side->bordertile, BlackPixmap); X side->mode = XCreateWindow(mainwin, X MAPWINSIZE+12*fw+3*fw, 13*fh+3+7, 11*fw, fh, X 1, side->bordertile, BlackPixmap); X side->state = XCreateWindow(mainwin, MAPWINSIZE+1, 13*fh+3+7+fh+7, X MAXWIDTH, 2*fh, X 1, side->bordertile, BlackPixmap); X side->sides = XCreateWindow(mainwin, MAPWINSIZE+1, 13*fh+3+7+fh+7+2*fh+7, X MAXWIDTH, numsides*fh, X 1, side->bordertile, BlackPixmap); X side->world = XCreateWindow(mainwin, X MAPWINSIZE+1, mainheight-mapmag*worldheight, X worldwidth*mapmag, worldheight*mapmag, X 1, side->bordertile, BlackPixmap); X side->help = XCreateWindow(mainwin, 0, 13*fh+3, MAPWINSIZE, MAPWINSIZE, X 1, side->bordertile, BlackPixmap); X X XStoreName(mainwin, programname); X XMapWindow(mainwin); X XMapSubwindows(mainwin); X XUnmapWindow(side->help); X XDefineCursor(side->map, side->curs); X XSelectInput(mainwin, KeyPressed|ButtonPressed|ExposeRegion|ExposeWindow); X X /* initialize random parameters */ X /* one-char strings simplify screen refresh */ X for (i = 0; i < MAXNOTES; ++i) { X strcpy(side->noticebuf[i], " "); X } X for (i = 0; i < 1; ++i) { X strcpy(side->infobuf[i], " "); X } X side->lastvcx = -1; side->lastvcy = -1; X side->lastx = -1; side->lasty = -1; X} X X/* Xconq needs two fonts - one for normal messages and one for pictures of */ X/* all the units, cities, etc. The character font is nothing unusual, but */ X/* the icon fonts are not a standard part of X, so we look for them either */ X/* in the usual place or in the library directory. */ X Xget_fonts(side) XSide *side; X{ X char *font1, *font2; X X if ((font1 = XGetDefault(programname, "BodyFont")) == NULL) X font1 = "9x15"; X if ((side->msgfontinfo = XOpenFont(font1)) == NULL) { X perror(font1); X exit(1); X } X side->msgfont = side->msgfontinfo->id; X fw = side->msgfontinfo->width; X fh = side->msgfontinfo->height; X X if ((font2 = XGetDefault(programname, "IconFont")) == NULL) X font2 = fontname; X if ((side->iconfontinfo = XOpenFont(font2)) == NULL) { X make_lib_pathname(fontname, "onx", spbuf); X font2 = spbuf; X if ((side->iconfontinfo = XOpenFont(font2)) == NULL) { X fprintf(stderr, X "Warning: Can't open icon font - substituting letters\n"); X if ((side->iconfontinfo = XOpenFont(font1)) == NULL) { X perror(font2); X exit(1); X } X } X } X if (side->iconfontinfo->width != SQ || side->iconfontinfo->height != SQ) { X fprintf(stderr, "Warning: Icon font is %dx%d, should be %dx%d\n", X side->iconfontinfo->width, side->iconfontinfo->height, X SQ, SQ); X } X side->iconfont = side->iconfontinfo->id; X} X X/* Acquire a set of colors. There are too many to make it feasible to */ X/* customize these via .Xdefaults, so we don't even try. On the other */ X/* hand, there is a feeble effort to handle fewer colors than the 16 or */ X/* or so that xconq would really like to have available. The plan is to */ X/* set priorities on which colors are most important to have. */ X Xget_colors(side) XSide *side; X{ X int i; X X /* this set should work everywhere, though not well */ X side->bgcolor = BlackPixel; X side->owncolor = BlackPixel; X side->curscolor = BlackPixel; X side->enemycolor = BlackPixel; X side->fgcolor = WhitePixel; X side->bdcolor = WhitePixel; X side->graycolor = WhitePixel; X if (Debug) printf("%d colors available\n", DisplayCells()); X /* now try to get better colors if possible */ X if (DisplayCells() > 2) { X side->enemycolor = request_color("red"); X side->curscolor = request_color("maroon"); X } X if (DisplayCells() > 4) { X side->bdcolor = request_color("blue"); X side->graycolor = request_color("light gray"); X } X if (DisplayCells() > 15 && !Debug) { X side->fewcolors = FALSE; X for (i = 0; i < NUMTERRTYPES; ++i) { X side->sqcolor[i] = request_color(terrcolors[i]); X } X } else { X side->fewcolors = TRUE; X for (i = 0; i < NUMTERRTYPES; ++i) { X side->sqcolor[i] = WhitePixel; X } X } X} X X/* Get a color set up and warn if not getting what was asked for. */ X Xrequest_color(name) Xchar *name; X{ X Color truecolor, availcolor; X X XGetColor(name, &availcolor, &truecolor); X XGetHardwareColor(&availcolor); X if (truecolor.red != availcolor.red || X truecolor.green != availcolor.green || X truecolor.blue != availcolor.blue) { X fprintf(stderr, "Warning: %s color not exact\n", name); X fprintf(stderr, "(%d %d %d instead of %d %d %d)\n", X availcolor.red, availcolor.green, availcolor.blue, X truecolor.red, truecolor.green, truecolor.blue); X } X return availcolor.pixel; X} X X/* Do the rigmarole to convert all those short arrays into X-approved */ X/* Bitmaps. Note that this has to be for *each* display separately (!) */ X/* Also get the cursor shape. If the hardware can't hack the desired */ X/* cursor size, warn about it but try to keep going. */ X Xstore_bitmaps(side) XSide *side; X{ X int actualwidth, actualheight; X X side->ccurs = XStoreBitmap(SQ, SQ, ccurs_bits); X side->cmask = XStoreBitmap(SQ, SQ, cmask_bits); X side->bombpics[0] = XStoreBitmap(bomb1_width, bomb1_height, bomb1_bits); X side->bombpics[1] = XStoreBitmap(bomb2_width, bomb2_height, bomb2_bits); X side->bombpics[2] = XStoreBitmap(bomb3_width, bomb3_height, bomb3_bits); X side->mcurs = XStoreBitmap(SQ, SQ, mcurs_bits); X side->mmask = XStoreBitmap(SQ, SQ, mmask_bits); X side->dots = XStoreBitmap(dots_width, dots_height, dots_bits); X X/* Bobcats generate curious results on this... X XQueryCursorShape(SQ, SQ, &actualwidth, &actualheight); X if (actualwidth != SQ || actualheight != SQ) { X fprintf(stderr, "Warning: Display %s cannot support %dx%d cursors!\n", X side->host, SQ, SQ); X } X*/ X side->curs = XStoreCursor(side->mcurs, side->mmask, (SQ-1)/2, (SQ-1)/2, X side->bgcolor, side->fgcolor, GXcopy); X} X X/* Main funnel for input returns both mouse and keyboard events, and maybe */ X/* other kinds eventually. Some events like window exposure are handled */ X/* strictly locally. */ X X/* One thing this routine ought to do is look at queues from other displays */ X/* to see if any screen redrawing, quitting, or whatever should be done. */ X Xget_input(keyp, xp, yp) Xchar *keyp; Xint *xp, *yp; X{ X XEvent evt; X char *buf; X int nchar, rawx, rawy; X Window dummy; X X if (active_display(curside)) { X if (numhosts > 1 && !beepedplayer) { X beep(curside); X beepedplayer = TRUE; X } X while (TRUE) { X XNextEvent(&evt); X switch (evt.type) { X case KeyPressed: X buf = XLookupMapping(&evt, &nchar); X if (nchar > 0) { X if (Debug) printf("%c\n", *buf); X *keyp = *buf; X return KEYBOARD; X } X break; X case ButtonPressed: X XQueryMouse(curside->map, &rawx, &rawy, &dummy); X *xp = wrap((rawx / SQ) + (curside->vcx - vwid2)); X *yp = (curside->vcy + vhgt2) - (rawy / SQ); X if (Debug) printf("%d %d\n", *xp, *yp); X return MOUSE; X break; X case ExposeRegion: X case ExposeWindow: X if (evt.window == curside->main) { X XSync(TRUE); /* suppress extra exposures */ X redraw(curside); X } X break; X default: X break; X } X } X } X /* should have better error response... */ X return -1; X} X X/* Get rid of extra key/mouse clicks. */ X Xflush_input() X{ X if (active_display(curside)) X XSync(TRUE); X} X X/* A predicate that tests whether our display can safely be written to. */ X/* If so, it also sets the display (so random routines don't need to). */ X Xactive_display(side) XSide *side; X{ X if (side != NULL && side->host != NULL && X !side->lost && side->display != NULL) { X XSetDisplay(side->display); X return TRUE; X } else { X return FALSE; X } X} X X/* Completely redo a screen, making no assumptions about appearance. */ X/* This one is used frequently, especially when a window is exposed. */ X Xredraw(side) XSide *side; X{ X if (active_display(side)) { X if (side->lastx > 0) erase_cursor(side, curx, cury); X if (side->lastvcx > 0) undraw_box(side); X show_info(side); X show_note(side); X show_time(side); X show_mode(side); X show_state(side); X show_all_sides(side); X show_curside(side); X show_prompt(side); X show_map(side); X show_world(side); X draw_cursor(side, curx, cury); X flush_output(); X } X} X X/* Trivial abstraction - sometimes other routines like to ensure all output */ X/* actually on the screen. */ X Xflush_output() X{ X XFlush(); X} X X/* Shut all displays down. As it happens, we now rely on windows shutting */ X/* when program exits. */ X Xclose_displays() X{ X} X X/* Shut a single window down (for when one player quits). */ X Xclose_display(side) XSide *side; X{ X if (active_display(side)) { X XCloseDisplay(side->display); X } X} X X/* Get a boolean value from .Xdefaults - use for customization flags. */ X Xboolean_default(prog, def) Xchar *prog, *def; X{ X char *str; X X return ((str = XGetDefault(prog, def)) != NULL && strcmp(str, "on") == 0); X} X X#endif XWINDOWS END_OF_X.c if test 12854 -ne `wc -c <X.c`; then echo shar: \"X.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f atk.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"atk.c\" else echo shar: Extracting \"atk.c\" \(14041 characters\) sed "s/^X//" >atk.c <<'END_OF_atk.c' X/* Copyright (c) 1987 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: atk.c,v 1.4 87/06/04 13:01:54 shebs Exp $ */ X X#include "xconq.h" X X/* Buffers for descriptions of units and cities from each other's */ X/* point of view. */ X Xchar aabuf[BUFSIZE], aobuf[BUFSIZE], oabuf[BUFSIZE], oobuf[BUFSIZE]; X X/* Various forms of verbs for use in messages. */ X Xchar *actvoice[NUMDOMAINS] = { "defeats", "sinks", "shoots down" }; Xchar *passvoice[NUMDOMAINS] = { "destroyed", "sunk", "shot down" }; Xchar *gerund[NUMDOMAINS] = { "defeating", "sinking", "downing" }; X X#define destruct(u) (actvoice[utypes[(u)->type].domain]) X X#define passive(u) (passvoice[utypes[(u)->type].domain]) X X#define gerundify(u) (gerund[utypes[(u)->type].domain]) X X/* This routine is called anytime a unit attempts to move onto a */ X/* square occupied by another (unfriendly) unit. If on opposite sides, */ X/* the units hit each other and then we sort out who gets destroyed */ X/* (0, 1, or 2 participants possibly). */ X/* The hairiest part is the messages since there are 2*3*3 = 18 possible, */ X/* depending on which side is getting message and whether each unit was */ X/* unharmed, damaged, or destroyed. */ X/* Return true if the attacker defeated the defender, and can therefore */ X/* try to move into the defender's old position. */ X Xattack_unit(atker, other) XUnit *atker, *other; X{ X int d1, d2; X int ax = atker->x, ay = atker->y, atype = atker->type; X int ox = other->x, oy = other->y, otype = other->type; X Side *as = atker->side, *os = other->side; X X d1 = d2 = 0; X if (probability(utypes[atype].hittab[otype])) X d1 = utypes[atype].power; X if (probability(utypes[otype].hittab[atype])) X d2 = utypes[otype].power; X /* get credit for making the hit */ X adjust_score(as, d1); X adjust_score(os, d2); X /* maybe used up some extra supply during the attack */ X atker->supply -= utypes[atype].hitsupply; X other->supply -= utypes[otype].hitsupply; X /* record in the history books */ X (as->atkstats[atype][otype])++; X (os->atkstats[otype][atype])++; X as->hitstats[atype][otype] += d1; X os->hitstats[otype][atype] += d2; X /* damaged units always become visible */ X if (d2 > 0) atker->hidden = FALSE; X if (d1 > 0) other->hidden = FALSE; X X strcpy(aabuf, unit_handle(as, atker)); X strcpy(aobuf, unit_handle(as, other)); X strcpy(oobuf, unit_handle(os, other)); X strcpy(oabuf, unit_handle(os, atker)); X if (atker->hp <= d2) { X if (other->hp <= d1) { X notify(as, "%s is %s while %s %s!", X aabuf, passive(atker), gerundify(other), aobuf); X notify(os, "%s is %s while %s %s!", X oabuf, passive(atker), gerundify(other), oobuf); X } else if (d1 > 0) { X notify(as, "%s is %s while hitting %s!", X aabuf, passive(atker), aobuf); X notify(os, "%s is %s while hitting %s!", X oabuf, passive(atker), oobuf); X } else { X notify(as, "%s is %s by %s!", aabuf, passive(atker), aobuf); X notify(os, "%s is %s by %s!", oabuf, passive(atker), oobuf); X } X } else if (d2 > 0) { X if (other->hp <= d1) { X notify(as, "%s is hit while %s %s!", X aabuf, gerundify(other), aobuf); X notify(os, "%s is hit while %s %s!", X oabuf, gerundify(other), oobuf); X } else if (d1 > 0) { X notify(as, "%s and %s both hit!", aabuf, aobuf); X notify(os, "%s and %s both hit!", oabuf, oobuf); X } else { X notify(as, "%s is hit by %s!", aabuf, aobuf); X notify(os, "%s is hit by %s!", oabuf, oobuf); X } X } else { X if (other->hp <= d1) { X notify(as, "%s %s %s!", aabuf, destruct(other), aobuf); X notify(os, "%s %s %s!", oabuf, destruct(other), oobuf); X } else if (d1 > 0) { X notify(as, "%s hits %s!", aabuf, aobuf); X notify(os, "%s hits %s!", oabuf, oobuf); X } else { X notify(as, "%s and %s both miss!", aabuf, aobuf); X notify(os, "%s and %s both miss!", oabuf, oobuf); X } X } X X atker->hp -= d2; X other->hp -= d1; X /* unit is dead if hit points at or below zero */ X if (!alive(atker)) { X adjust_morale(as, -5 * utypes[atype].schedule); X adjust_morale(os, 5 * utypes[atype].schedule); X kill_unit(atker, UNITDEFEAT); X } X if (!alive(other)) { X adjust_morale(as, 5 * utypes[otype].schedule); X adjust_morale(os, -5 * utypes[otype].schedule); X kill_unit(other, UNITDEFEAT); X } X update_view(as, ax, ay); X update_view(os, ox, oy); X /* if we won, can move into new square */ X return (alive(atker) && !alive(other)); X} X X/* Assault of cities dispatches depending on what unit can do to cities. */ X/* This routine assumes unit and city are unfriendly. */ X Xattack_city(unit, city) XUnit *unit; XCity *city; X{ X Side *us = unit->side; X X /* suck some extra supply */ X unit->supply -= utypes[unit->type].hitsupply; X /* record the attack, but only for enemy cities */ X if (!neutral(city)) us->cityatks[unit->type][city->size]++; X X switch (utypes[unit->type].vscity[city->size]) { X case NOWAY: X movesuccess = FALSE; X notify(us, "%s refuses to attack a %s!", X unit_handle(us, unit), citynames[city->size]); X break; X case ASSAULT: X assault_city(unit, city); X break; X case BOMBARD: X bombard_city(unit, city); X break; X case FLATTEN: X /* atom bomb handled under bombardment now... */ X break; X default: X case_panic("city attack type", utypes[unit->type].vscity[city->size]); X } X} X X/* Units that can capture cities end up here. When a city is */ X/* captured, some of its contents may change sides. */ X X/* Idea: if unit captures, and city destroys that unit simultaneously, the */ X/* city becomes neutral... */ X Xassault_city(unit, city) XUnit *unit; XCity *city; X{ X int chance; X Unit *occ; X Side *cs = city->side, *us = unit->side; X X chance = utypes[unit->type].powervscity[city->size]; X /* better chance to capture neutral places */ X if (neutral(city)) chance += (chance / 2); X /* better chance to capture damaged places */ X chance += (ctypes[city->size].hp - city->hp); X /* worse chance to capture occupied places */ X for (occ = city->occupant; occ != NULL; occ = occ->nexthere) { X chance -= occ->hp; X } X /* make sure is non-bogus percentage */ X chance = max(1, min(100, chance)); X X if (probability(chance)) { X if (!neutral(city)) us->cityhits[unit->type][city->size]++; X capture_city(unit, city); X if (city->size > BASE) set_product(city, decide_product(city), FALSE); X } else if (probability(utypes[unit->type].cityvs[city->size])) { X city_hits_unit(city, unit); X } else { X adjust_morale(cs, 10); X adjust_morale(us, -10); X notify(us, "%s repulses %s!", X city_handle(us, city), unit_handle(us, unit)); X notify(cs, "%s repulses %s!", X city_handle(cs, city), unit_handle(cs, unit)); X /* riskier to attack from transports... */ X if (unit->transport != NULL) { X notify(us, "%s was slaughtered!", unit_handle(us, unit)); X kill_unit(unit, CITYDEFEAT); X } X } X} X X/* There are many consequences of a city being captured. */ X/* It loses hit points equal to range of unit on open ground - this is */ X/* crude measure of unit's general destructiveness in capturing things. */ X Xcapture_city(unit, city) XUnit *unit; XCity *city; X{ X int cx = city->x, cy = city->y, chp = city->hp, csize = city->size; X Side *cs = city->side, *us = unit->side; X X notify(us, "You %s %s!", X (neutral(city) ? "captured" : "liberated"), city_handle(us, city)); X notify(cs, "%s has been captured by the %s!", X city_handle(cs, city), plural_form(us->name)); X if (hit_city(city, us, utypes[unit->type].range)) { X city_changes_side(city, us, CAPTURED); X while (city->occupant != NULL) { X kill_unit(city->occupant, PRISONER); X } X if (utypes[unit->type].garrison) kill_unit(unit, GARRISON); X adjust_morale(us, 10 * csize); X } X update_view(cs, cx, cy); X update_view(us, cx, cy); X adjust_score(us, (cs == NULL ? -1 : 1) * chp); X adjust_score(cs, -1 * chp); X} X X/* Bombarding a city is what some units can do even if they can't */ X/* assault it directly. If done enough, city might get trashed. */ X Xbombard_city(unit, city) XUnit *unit; XCity *city; X{ X int hit, cx = city->x, cy = city->y; X Side *us = unit->side, *cs = city->side; X X notify(us, "%s %s %s", X unit_handle(us, unit), "bombards", city_handle(us, city)); X notify(cs, "%s %s %s", X unit_handle(cs, unit), "bombards", city_handle(cs, city)); X hit = utypes[unit->type].powervscity[city->size]; X /* record for posterity */ X us->cityhits[unit->type][city->size] += hit; X /* city's chance to get back at unit */ X if (probability(utypes[unit->type].cityvs[city->size])) { X city_hits_unit(city, unit); X } X hit_city(city, us, hit); X update_view(us, cx, cy); X update_view(cs, cx, cy); X} X X/* Hitting a city is more complex than hitting units, because a sufficiently */ X/* large city will die spectacularly if hit hard enough. Smaller hits will */ X/* cause flattening, while the smallest may only reduce it to the next */ X/* smaller type of city. */ X Xhit_city(city, us, hit) XCity *city; XSide *us; Xint hit; X{ X bool stillthere; X Side *cs = city->side; X X if (hit > ctypes[CITY].hp) { X notify_all("An atomic bomb destroys %s!", city->name); X explode_nuke(cs, us, city->x, city->y); X adjust_morale(cs, -1000); X adjust_score(us, -1000); X city_changes_side(city, NULL, NUKED); X remove_city(city); X set_square(city->x, city->y, DESERT, RURAL); X stillthere = FALSE; X } else if (hit >= city->hp) { X notify(cs, "%s has been flattened!", city_handle(cs, city)); X notify(us, "%s has been flattened!", city_handle(us, city)); X adjust_morale(cs, -100); X city_changes_side(city, NULL, FLATTENED); X remove_city(city); X stillthere = FALSE; X } else { X city->hp -= hit; X if (city->hp <= ctypes[(city->size)-1].hp) { X notify(cs, "%s has been reduced to a %s!", X city_handle(cs, city), citynames[city->size-1]); X notify(us, "%s has been reduced to a %s!", X city_handle(us, city), citynames[city->size-1]); X adjust_territory(cs, 0 - city_value(city->size), TRUE); X city->size--; X adjust_territory(cs, city_value(city->size), TRUE); X adjust_morale(cs, -100); X } X adjust_morale(cs, -5 * hit); X stillthere = TRUE; X } X return stillthere; X} X X/* Cities can also be captured by a siege. If successful, one of the */ X/* besiegers is randomly chosen to be the occupier. */ X Xcheck_siege(city) XCity *city; X{ X int chance, dir; X Unit *unit; X X chance = ctypes[city->size].siege; X if (neutral(city)) chance *= 2; X chance = max(1, min(100, chance)); X if (probability(chance)) { X dir = random_dir(); X unit = unit_at(city->x+dirx[dir], city->y+diry[dir]); X notify(unit->side, "%s has surrendered to %s!", X city_handle(unit->side, city), unit_handle(unit->side, unit)); X notify(city->side, "%s has surrendered to %s!", X city_handle(city->side, city), unit_handle(city->side, unit)); X capture_city(unit, city); X } X} X X/* City can try to hit back. If it fails to do any damage, no message */ X/* is displayed (why not?) */ X/* Amount of damage is presently one less than the size of the city. */ X Xcity_hits_unit(city, unit) XCity *city; XUnit *unit; X{ X int d1, cx = city->x, cy = city->y; X Side *cs = city->side, *us = unit->side; X X /* hit power is 2 for metropoli, 1 for towns, 0 for bases */ X d1 = city->size - 1; X X strcpy(aabuf, unit_handle(us, unit)); X strcpy(aobuf, city_handle(us, city)); X strcpy(oabuf, unit_handle(cs, unit)); X strcpy(oobuf, city_handle(cs, city)); X if (unit->hp <= d1) { X notify(us, "%s %s %s!", aobuf, destruct(unit), aabuf); X notify(cs, "%s %s %s!", oobuf, destruct(unit), oabuf); X } else if (d1 > 0) { X notify(us, "%s hits %s!", aobuf, aabuf); X notify(cs, "%s hits %s!", oobuf, oabuf); X } X unit->hp -= d1; X if (unit->hp <= 0) { X kill_unit(unit, CITYDEFEAT); X update_view(cs, cx, cy); X update_view(us, cx, cy); X } X} X X/* Nearly-raw combat statistics are hard to interpret, but they provide */ X/* a useful check against subjective evaluation of performance. */ X X#ifdef STATISTICS Xprint_unit_results(fp, side) XFILE *fp; XSide *side; X{ X int atype, dtype, reason, sum; X X fprintf(fp, X "Unit Performance (successes and attacks against enemy by type\n"); X fprintf(fp, " "); X for (dtype = 0; dtype < numutypes; ++dtype) { X fprintf(fp, " %c ", unitchars[dtype]); X } X fprintf(fp, "\n"); X for (atype = 0; atype < numutypes; ++atype) { X fprintf(fp, " %c ", unitchars[atype]); X for (dtype = 0; dtype < numutypes; ++dtype) { X if (side->atkstats[atype][dtype] > 0) { X fprintf(fp, "%3.1f/%-2d ", X ((float) side->hitstats[atype][dtype]) / X side->atkstats[atype][dtype], X side->atkstats[atype][dtype]); X } else { X fprintf(fp, " "); X } X } X fprintf(fp, "\n"); X } X fprintf(fp, "\n"); X fprintf(fp, "Unit Record (ultimate fates by cause and unit type)\n"); X fprintf(fp, " %s Total\n", REASONNAMES); X for (atype = 0; atype < numutypes; ++atype) { X sum = 0; X fprintf(fp, " %c ", unitchars[atype]); X for (reason = 0; reason < MAXREASONS; ++reason) { X if (side->losses[atype][reason] > 0) { X fprintf(fp, " %3d ", side->losses[atype][reason]); X sum += side->losses[atype][reason]; X } else { X fprintf(fp, " "); X } X } X fprintf(fp, " %3d\n", sum); X } X fprintf(fp, "\n"); X} X X/* Statistics about attacks on cities. */ X Xprint_city_results(fp, side) XFILE *fp; XSide *side; X{ X int atype, ctype; X X fprintf(fp, "City Results (successes / tries against cities)\n"); X fprintf(fp, " Base Town City\n"); X for (atype = 0; atype < numutypes; ++atype) { X fprintf(fp, " %c ", unitchars[atype]); X for (ctype = 1; ctype < numctypes; ++ctype) { X if (side->cityatks[atype][ctype]) { X fprintf(fp, "%3d/%-3d ", X side->cityhits[atype][ctype], X side->cityatks[atype][ctype]); X } else { X fprintf(fp, " "); X } X } X fprintf(fp, "\n"); X } X fprintf(fp, "\n"); X} X#endif STATISTICS END_OF_atk.c if test 14041 -ne `wc -c <atk.c`; then echo shar: \"atk.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f city.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"city.c\" else echo shar: Extracting \"city.c\" \(12579 characters\) sed "s/^X//" >city.c <<'END_OF_city.c' X/* Copyright (c) 1987 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: city.c,v 1.4 87/06/07 11:37:02 shebs Exp $ */ X X#include "xconq.h" X XCity cities[MAXCITIES]; /* The array of all cities */ XCity *citylist; /* Head of the list of all cities */ X Xint numcities; /* the number of cities in existence */ X Xchar citychars[MAXCTYPES]; /* cache of chars repning cities */ Xchar *citynames[MAXCTYPES]; /* cache of names of types of cities */ X X/* Reset each entry in the big array of city structures. */ X Xinit_cities() X{ X int i; X X for (i = 0; i < MAXCITIES; ++i) X cities[i].size = RURAL; X citylist = NULL; X} X X/* A city is specified by its size, position, and name. As an optimization */ X/* the parameter "cityn" specifies where to start in the array - this */ X/* eliminates O(n^2) behavior when initing 400 cities... */ X/* This routine is also used during game restoration, so it has to set */ X/* almost all the slots. */ X XCity * Xcreate_city(size, x, y, name, sidename, product, schedule, hp, cityn) Xint size, x, y, product, schedule, hp, cityn; Xchar *name, *sidename; X{ X int i, j; X X for (i = cityn; i < MAXCITIES; ++i) { X if (cities[i].size == RURAL) { X cities[i].x = x; cities[i].y = y; X cities[i].size = size; X cities[i].side = NULL; /* neutral, true side asgned later */ X cities[i].name = malloc(strlen(name)+2); X strcpy(cities[i].name, name); X cities[i].sname = sidename; X for (j = 0; j < numutypes; ++j) { X ((cities[i].standing)[j]).type = NONE; X cities[i].produced[j] = 0; X } X cities[i].product = product; X cities[i].schedule = schedule; X cities[i].hp = hp; X cities[i].next = citylist; X citylist = &cities[i]; X /* tweak world map to include the city */ X set_square(x, y, terrain(x, y), size); X set_city_at(x, y, citylist); X return citylist; X } X } X /* will happen if scenario too big, or players build too many bases */ X fprintf(stderr, "Cannot create more than %d cities!\n", MAXCITIES); X return NULL; X} X X/* Find a good initial city for the given side. Only requirement these */ X/* days is that it be a big city and not already used by somebody. */ X/* If enough tries, we're either extremely unlucky or something is wrong. */ X/* In either case, we don't want this game anymore. */ X XCity * Xrandom_start_city() X{ X int tries = 0; X City *city; X X while (tries++ < MAXTRIES) { X city = &cities[random(numcities)]; X if (neutral(city) && city->size == CITY) X return city; X } X /* failure here is completely fatal */ X fprintf(stderr, "Can't find a starting city!\n"); X exit(1); X} X X/* The main activity of cities is to produce units. The code here has to */ X/* be a little tricky because players need to get opportunities to cancel */ X/* and to idle cities. */ X Xproduce(city) XCity *city; X{ X int tmp, prod; X Unit *new; X X if (!neutral(city) && city->size > BASE) { X city->side->production[city->size]++; X if (!random(city->side->morale) && X city->size == TOWN && X producing(city)) { X city_revolts(city); X return; X } X if (!human(city)) X set_product(city, decide_product(city), FALSE); X if (city->schedule-- <= 0) { X if (producing(city)) { X prod = city->product; X if (create_new_unit(prod, city->side, city->x, city->y)) { X notify(city->side, "%s produces a new %s", X city_handle(city->side, city), unitnames[prod]); X city->produced[prod]++; X if (usecount) numinputs++; X city->side->completion[city->size] += utypes[prod].schedule; X } X set_product(city, prod, TRUE); X } else { X set_product(city, decide_product(city), FALSE); X } X } X } X} X X/* If a city is run by a player, then interact to find out what to produce, */ X/* error checking to we make sure we don't get battleships in the middle of */ X/* Siberia and other sillinesses. */ X Xdecide_product(city) XCity *city; X{ X int type; X X if (city->size <= BASE) { X notify(city->side, "Bases can't produce anything!"); X type = NOTHING; X } else if (human(city)) { X show_city(city); X type = read_unit_type("Production demands: "); X unshow_city(city); X } else { X type = machine_product(city); X } X return type; X} X X/* Set up new product for a city. There are two ways that the extra startup */ X/* cost will be incurred: either it has been specifically directed via an */ X/* argument, or the type is different from the current type in production. */ X Xset_product(city, type, renew) XCity *city; Xint type, renew; X{ X int sched = city->schedule; X X if (type == NOTHING) { X /* machines should never decide to produce nothing */ X } else if (type != city->product || renew) { X sched = utypes[type].schedule; X if (!renew) sched = utypes[type].startup; X#ifdef SLOWTOWNS X if (city->size == TOWN) sched += sched/2; X#endif SLOWTOWNS X } X city->product = type; X city->schedule = sched; X} X X/* City repair proceeds each turn a little. This is also a good time for */ X/* repair of any damaged units that are in town, and for checking on sieges! */ X/* These activities continue even if city changes hands, so siege check */ X/* never needs to exit early. */ X Xmake_repairs(city) XCity *city; X{ X int utype; X Unit *unit; X X if (surrounded(city->side, city->x, city->y)) { X check_siege(city); X } X if ((city->hp < ctypes[city->size].hp) && X (gametime % ctypes[city->size].recovery == 0)) { X city->hp++; X } X for (unit = city->occupant; unit != NULL; unit = unit->nexthere) { X if (alive(unit)) { X utype = unit->type; X if (unit->hp < utypes[utype].hp) { X ++(unit->hp); X } X if (unit->hp == utypes[utype].hp && utypes[utype].canhide) { X unit->hidden == TRUE; X } X unit->supply = utypes[utype].supply; X unit->cautious = TRUE; X } X } X} X X/* When city revolts, it reverts back to being neutral. All units there are */ X/* lost, and the former owner's morale drops. */ X Xcity_revolts(city) XCity *city; X{ X Unit *unit; X Side *oldside = city->side; X X notify(oldside, "%s revolts! (%s production lost)", X city->name, unitnames[city->product]); X while (city->occupant != NULL) { X kill_unit(city->occupant, PRISONER); X } X city_changes_side(city, NULL, REVOLTED); X update_view(oldside, city->x, city->y); X} X X/* Handle the general situation of a city changing allegiance from one side */ X/* to another. The main effect is on the sides' territories. */ X Xcity_changes_side(city, newside, reason) XCity *city; XSide *newside; Xint reason; X{ X int value, newterr, newmorale; X Side *oldside = city->side; X X value = city_value(city->size); X city->side = newside; X city->product = NOTHING; X adjust_territory(oldside, 0-value, TRUE); X adjust_territory(newside, value, (oldside != NULL)); X} X X/* This is a rather arbitrary scale - should be period-dependent. */ X Xcity_value(csize) Xint csize; X{ X int value = 1; X X if (csize > BASE) value *= 5; X if (csize > TOWN) value *= 5; X return value; X} X X/* City destruction is infrequent, but must be thorough, so we don't */ X/* get dangling pointers and weird behavior... */ X Xremove_city(city) XCity *city; X{ X int cx = city->x, cy = city->y; X City *head; X X while (city->occupant != NULL) { X kill_unit(city->occupant, UNITDEFEAT); X } X /* clean off the map */ X set_square(cx, cy, terrain(cx, cy), RURAL); X set_city_at(cx, cy, NULL); X city->side = NULL; X city->size = RURAL; X /* unlink from the list of cities */ X if (city == citylist) { X citylist = citylist->next; X } else { X for (head = citylist; head != NULL; head = head->next) { X if (head->next == city) { X head->next = head->next->next; X break; X } X } X } X city->next = NULL; X} X X/* Display details about city. This is long and ugly because we have to */ X/* assemble nicely formatted strings into buffers for display. */ X Xshow_city(city) XCity *city; X{ X bool flag; X int i, j, type, ucount[MAXUTYPES]; X char tmp1[BUFSIZE], prodbuf[BUFSIZE], occbuf[BUFSIZE]; X Unit *occ; X X curx = city->x; cury = city->y; X X put_on_screen(curside, curx, cury); X X if (city->side == curside || Debug) { X sprintf(spbuf2, ""); X flag = FALSE; X for (i = 0; i < numutypes; ++i) ucount[i] = 0; X for (occ = city->occupant; occ != NULL; occ = occ->nexthere) { X flag = TRUE; X ucount[occ->type]++; X } X if (flag) { X sprintf(occbuf, "Occ "); X for (i = 0; i < numutypes; ++i) { X if (ucount[i] > 0) { X sprintf(tmp1, "%d %c ", ucount[i], unitchars[i]); X strcat(occbuf, tmp1); X } X } X strcat(spbuf2, occbuf); X } X flag = FALSE; X for (type = 0; type < numutypes; ++type) X if (city->standing[type].type != NONE) flag = TRUE; X if (flag) { X sprintf(spbuf, "Orders: "); X for (type = 0; type < numutypes; ++type) { X if (city->standing[type].type != NONE) { X sprintf(prodbuf, " %ss to %s", X unitnames[type], X order_desig(city->standing[type])); X strcat(spbuf, prodbuf); X } X } X strcat(spbuf2, spbuf); X } X if (producing(city)) { X sprintf(prodbuf, " (New %s in %d turns)", X unitnames[city->product], city->schedule); X } else if (city->size > BASE) { X sprintf(prodbuf, " (Idle for %d more turns)", city->schedule); X } else { X sprintf(prodbuf, ""); X } X sprintf(tmp1, " Hp %d/%d", city->hp, ctypes[city->size].hp); X strcat(prodbuf, tmp1); X } else { X sprintf(spbuf2, ""); X sprintf(prodbuf, ""); X } X sprintf(spbuf, "%s", city_handle(curside, city)); X if (curside->showcoords) strcat(spbuf, pos_desig(city->x, city->y)); X strcat(spbuf, prodbuf); X /* spit it all onto the display */ X set_current_info(curside, spbuf, spbuf2); X show_info(curside); X draw_cursor(curside, curx, cury); X} X X/* Erase the cursor and do anything else to undo the city display. */ X Xunshow_city(city) XCity *city; X{ X erase_cursor(curside, curx, cury); X} X X/* Generate the description by which a city is called */ X Xchar citydesigbuf[BUFSIZE]; X Xchar * Xcity_handle(side, city) XSide *side; XCity *city; X{ X sprintf(citydesigbuf, ""); X if (side == NULL) return citydesigbuf; X if (side == city->side) X strcat(citydesigbuf, "your "); X else X sprintf(citydesigbuf, "the %s ", X (city->side == NULL ? "neutral" : city->side->name)); X strcat(citydesigbuf, citynames[city->size]); X strcat(citydesigbuf, " of "); X strcat(citydesigbuf, city->name); X return citydesigbuf; X} X X/* Generate a name for a base, using best acrynomese. Note that BSD will */ X/* produce garbage for second letter if not lowercase, but this isn't */ X/* exactly a critical piece of code. */ X Xchar * Xnew_base_name(side) XSide *side; X{ X char *name; X X name = malloc(10); X sprintf(name, "%c%c-%02d", X side->name[0], toupper(side->name[1]), ++side->basenum); X return name; X} X X/* City saving is complicated by the need to save all the standing orders */ X/* and their parameters. */ X Xsave_city(city, fp, savecrud) XCity *city; XFILE *fp; Xbool savecrud; X{ X int i, j; X X fprintf(fp, "%s\n%d %d %d %d %d %d %d %d ", X city->name, city->size, side_number(city->side), X city->x, city->y, city->product, city->schedule, X city->hp, savecrud); X fprintf(fp, "\n"); X if (savecrud) { X for (i = 0; i < numutypes; ++i) { X fprintf(fp, "%d %d %d ", X city->produced[i], X city->standing[i].type, city->standing[i].rept); X for (j = 0; j < NUMORDERPARMS; ++j) { X fprintf(fp, "%d ", city->standing[i].parms[j]); X } X fprintf(fp, "\n"); X } X } X} X X/* City restoration has to read the matrix of standing orders back, but */ X/* only if the appropriate flag was written out (scenarios don't care about */ X/* the orders) */ X Xrestore_city(fp) XFILE *fp; X{ X char name[BUFSIZE]; X int i, j, t1, t2, t3, t4, t5, t6, t7, savecrud; X City *city; X X fgets(name, BUFSIZE-1, fp); name[strlen(name)-1] = '\0'; X fscanf(fp, "%d %d %d %d %d %d %d %d\n", X &t1, &t2, &t3, &t4, &t5, &t6, &t7, &savecrud); X city = create_city(t1, t3, t4, name, NULL, t5, t6, t7, 0); X city->side = side_n(t2); X if (savecrud) { X for (i = 0; i < numutypes; ++i) { X fscanf(fp, "%d %d %d", &t1, &t2, &t3); X city->produced[i] = t1; X city->standing[i].type = t2; X city->standing[i].rept = t3; X for (j = 0; j < NUMORDERPARMS; ++j) { X fscanf(fp, "%d", &t1); X city->standing[i].parms[j] = t1; X } X } X fscanf(fp, "\n"); X } X adjust_territory(city->side, city_value(city->size), FALSE); X if (Debug) printf("Restored city %s\n", city->name); X} END_OF_city.c if test 12579 -ne `wc -c <city.c`; then echo shar: \"city.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f mplay.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"mplay.c\" else echo shar: Extracting \"mplay.c\" \(11237 characters\) sed "s/^X//" >mplay.c <<'END_OF_mplay.c' X/* Copyright (c) 1987 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: mplay.c,v 1.2 87/05/31 11:56:30 shebs Exp $ */ X X#include "xconq.h" X Xextern int assaulter, ttransport; X X/* Machine algorithm for deciding what a city should produce. */ X/* Since armies are the only sort of units that can capture new */ X/* cities, it is important to make sure that they are being produced */ X/* regularly. */ X/* This routine must return the type of unit decided upon. */ X X/* Rules: only produce six of aircraft or land units, or three ships, before */ X/* switching to something else. */ X Xmachine_product(city) XCity *city; X{ X int allcities, armycities, seaports, type, apcities, tmp; X int armyunits, apunits; X City *city2; X Unit *unit2; X X if (producing(city)) { X tmp = city->produced[city->product]; X if (tmp > 0 && X ((watertype(city->product) && tmp % 3 == 0) || (tmp % 6 == 0))) { X ++(city->produced[city->product]); X city->product = NOTHING; X } X } X if (city->schedule >= 0 && producing(city)) return city->product; X X allcities = armycities = apcities = seaports = 0; X armyunits = apunits = 0; X for (city2 = citylist; city2 != NULL; city2 = city2->next) { X if (city2->side == city->side) { X ++allcities; X if (city2->product == assaulter) ++armycities; X if (city2->product == ttransport) ++apcities; X if (adj_sea(city2->x, city2->y)) ++seaports; X } X } X for (unit2 = unitlist; unit2 != NULL; unit2 = unit2->next) { X if (unit2->side == city->side) { X if (unit2->type == assaulter) ++armyunits; X if (unit2->type == ttransport) ++apunits; X } X } X if (!adj_sea(city->x, city->y)) { X if (armycities < 3) X type = assaulter; X else { X tmp = 0; X while (tmp++ < MAXTRIES) { X type = random(numutypes); X if (!watertype(type)) break; X } X } X } else if (armycities > 0 && apunits < 4 && apcities < 1) X type = ttransport; X else if (apunits >= 4 && armycities >= 2) { X type = random(numutypes); X if (type == assaulter || type == ttransport) X type = random(numutypes); X } else X type = assaulter; X if (type != city->product) X notify(city->side, "%s will now build %s units", X city->name, unitnames[type]); X return type; X} X X/* Used in a search_area below. */ X Xcityp(x, y) Xint x, y; X{ X City *city = city_at(x, y); X X return (city != NULL && city->side == curside); X} X X/* True only if some sort of enemy city has been seen. */ X Xecityp(x, y) Xint x, y; X{ X int view; X Side *side; X X view = side_view(curside, x, y); X if (view != EMPTY) { X side = side_n(valign(view)); X if (vthing(view) == VCITY && enemy_side(side, curside)) return TRUE; X } X return FALSE; X} X X/* True only if some sort of defeatable enemy has been seen. */ X Xeunitp(x, y) Xint x, y; X{ X int view; X Side *side; X X view = side_view(curside, x, y); X X if (view == UNSEEN && flip_coin()) return TRUE; X if (view != EMPTY) { X side = side_n(valign(view)); X if (vthing(view) == VUNIT && X enemy_side(side, curside) && X good_unit_odds(curunit->type, vtype(view))) X return TRUE; X } X return FALSE; X} X X/* True if we found a plausible transport. */ X Xtransportp(x, y) Xint x, y; X{ X Unit *unit = unit_at(x, y); X X return (unit != NULL && !enemy_side(curunit->side, unit->side) && X can_carry(unit, curunit)); X} X X/* True if we found a plausible passenger. */ X Xpassengerp(x, y) Xint x, y; X{ X Unit *unit = unit_at(x, y); X X return (unit != NULL && !enemy_side(curunit->side, unit->side) && X can_carry(curunit, unit)); X} X X/* True if given square has not been viewed. */ X Xunseenp(x, y) Xint x, y; X{ X return (side_view(curside, x, y) == UNSEEN); X} X X/* Decide on and make a move or set orders for a machine player */ X X/* Our general setup here is stupidly aggressive - if there's an enemy */ X/* seen in the vicinity, everything will eventually go after and attack it. */ X/* There are some exceptions; if a unit cannot capture or damage a city, */ X/* it will not attack, nor if the odds are stacked greatly against it. */ X/* This lead to bizarre behavior, because the unit will move towards until */ X/* it gets adjacent, then retreat (oh well!). */ X/* When not attacking, units generally move randomly or towards unexplored */ X/* areas (no, armies are not smart about trying to cross the ocean */ X Xmachine_move(unit) XUnit *unit; X{ X int utype = unit->type, ux = unit->x, uy = unit->y, ex, ey, etype; X City *ecity; X Unit *eunit; X Side *us = unit->side; X X if (Debug) X printf("%s is deciding its move\n", unit_handle(side_n(0), unit)); X if ((low_supplies(unit) || 2*unit->hp <= utypes[utype].hp) && X probability(98)) { X if (Debug) notify(us, "%s needs to return,", unit_handle(us, unit)); X if (search_area(ux, uy, unit->supply, cityp, &ex, &ey)) { X order_moveto(unit, ex, ey); X } else { X if (Debug) notify(us, "%s can't return!", unit_handle(us, unit)); X order_movedir(unit, random_dir(), unit->supply+3); X } X } else if (adj_enemy_city(us, ux, uy, &ex, &ey)) { X if (Debug) notify(us, "%s dealing with enemy city at %d,%d", X unit_handle(us, unit), ex, ey); X ecity = city_at(ex, ey); X if (could_capture(utype, ecity->size) && probability(90)) { X order_moveto(unit, ex, ey); X } else if (unit->cargo != NULL && probability(80)) { X do_sit(1); X } else if (could_bombard(utype, ecity->size) && !neutral(ecity) && X good_bomb_odds(utype, ecity->size) && probability(80)) { X order_moveto(unit, ex, ey); X } else { X order_movedir(unit, random_dir(), 1); X } X } else if (adj_enemy_unit(us, ux, uy, &ex, &ey)) { X if (Debug) notify(us, "%s dealing with enemy unit at %d,%d", X unit_handle(us, unit), ex, ey); X eunit = unit_at(ex, ey); X etype = eunit->type; X if (good_unit_odds(utype, etype) && probability(70) && X unit->cargo == NULL) { X order_moveto(unit, ex, ey); X } else if (utypes[utype].hittab[etype] < X utypes[etype].hittab[utype]) { X order_movedir(unit, find_dir(wrap(ux - ex), uy - ey), 4); X } else { X do_sit(1); X } X } else if (adj_transport(unit, &ex, &ey) && probability(90)) { X if (Debug) notify(us, "%s getting on transport,", X unit_handle(us, unit)); X order_moveto(unit, ex, ey); X } else if (utype == ttransport) { X if (Debug) notify(us, "%s loading up,", unit_handle(us, unit)); X if (cargo_size(unit, assaulter) == 0) unit->goal = LOADING; X if (cargo_size(unit, assaulter) < 4 && unit->goal == LOADING) { X if (city_at(ux, uy) || probability(20)) { X order_movedir(unit, random_dir(), 1); X } else if (probability(50) && X search_area(ux, uy, 5, passengerp, &ex, &ey)) { X order_moveto(unit, ex, ey); X } else { X order_sentry(unit, 10); X } X } else { X unit->goal = NORMAL; X look_for_trouble(unit, 80); X } X } else if (unit->transport != NULL) { X unit->orders.type = RANDOM; X unit->orders.rept = 2; X } else { X look_for_trouble(unit, 70); X } X if (Debug) X notify(us, "%s will now %s", X unit_handle(us, unit), order_desig(unit->orders)); X} X Xlook_for_trouble(unit, chance) XUnit *unit; Xint chance; X{ X int utype = unit->type, ux = unit->x, uy = unit->y, ex, ey, etype; X City *ecity; X Unit *eunit; X Side *us = unit->side; X X if (probability(60) && X search_area(ux, uy, random(20+gametime/10), ecityp, &ex, &ey)) { X if (Debug) notify(us, "%s looking for enemy,", unit_handle(us, unit)); X order_moveto(unit, ex, ey); X } else if (probability(50) && X search_area(ux, uy, random(20+gametime/10), eunitp, &ex, &ey)) { X if (Debug) notify(us, "%s looking for enemy,", unit_handle(us, unit)); X order_moveto(unit, ex, ey); X } else if (probability(30) && X search_area(ux, uy, 10, transportp, &ex, &ey)) { X if (Debug) notify(us, "%s found a transport,", unit_handle(us, unit)); X order_moveto(unit, ex, ey); X } else if (probability(30)) { X if (Debug) notify(us, "%s being random,", unit_handle(us, unit)); X unit->orders.type = RANDOM; X unit->orders.rept = 8; X } else if (unit->transport != NULL || probability(10)) { X if (Debug) notify(us, "%s sitting a spell,", unit_handle(us, unit)); X order_sentry(unit, (unit->transport != NULL ? 40 : 2)); X } else if (probability(50) && X search_area(ux, uy, random(10+gametime/10), unseenp, &ex, &ey)) { X if (Debug) notify(us, "%s exploring,", unit_handle(us, unit)); X order_moveto(unit, ex, ey); X } else { X if (Debug) notify(us, "%s just moving,", unit_handle(us, unit)); X order_movedir(unit, random_dir(), random(12)+3); X } X} X Xcould_bombard(utype, csize) Xint utype, csize; X{ X return (utypes[utype].vscity[csize] == BOMBARD); X} X X/* This is really only plausible for ww2 period file. */ X Xgood_bomb_odds(utype, csize) Xint utype, csize; X{ X return (utypes[utype].cityvs[csize] < 50 || X utypes[utype].powervscity[csize] > 3); X} X X/* This should only be true if it's generally advisable for a unit to make */ X/* an attack */ X Xgood_unit_odds(utype, etype) Xint utype, etype; X{ X return ((utypes[utype].hittab[etype] * utypes[utype].power >= X utypes[etype].hittab[utype] * utypes[etype].power) && X utypes[utype].hittab[etype] >= 30); X} X Xadj_sea(x, y) Xint x, y; X{ X int x1, y1; X X for (x1 = x-1; x1 <= x+1; ++x1) X for (y1 = y-1; y1 <= y+1; ++y1) X if (terrain(wrap(x1), y1) == SEA) return TRUE; X return FALSE; X} X Xadj_land(x, y) Xint x, y; X{ X int x1, y1; X X for (x1 = x-1; x1 <= x+1; ++x1) X for (y1 = y-1; y1 <= y+1; ++y1) X if (terrain(wrap(x1), y1) != SEA) return TRUE; X return FALSE; X} X Xadj_transport(unit, exp, eyp) XUnit *unit; Xint *exp, *eyp; X{ X int d, ix, iy; X Unit *other; X X for (d = 0; d < 8; ++d) { X ix = unit->x + dirx[d]; iy = unit->y + diry[d]; X other = unit_at(wrap(ix), iy); X if (other != NULL && other->side == unit->side && X could_carry(other, unit)) { X *exp = wrap(ix); *eyp = iy; X return TRUE; X } X } X return FALSE; X} X X/* look for anything unfriendly */ X Xadj_enemy_city(side, x, y, exp, eyp) Xint x, y, *exp, *eyp; XSide *side; X{ X int d, ix, iy; X City *city; X X for (d = 0; d < 8; ++d) { X ix = wrap(x + dirx[d]); iy = y + diry[d]; X if ((city = city_at(ix, iy)) != NULL && enemy_side(side, city->side)) { X *exp = ix; *eyp = iy; X return TRUE; X } X } X return FALSE; X} X X/* look for anything unfriendly */ X Xadj_enemy_unit(side, x, y, exp, eyp) Xint x, y, *exp, *eyp; XSide *side; X{ X int d, ix, iy; X Unit *unit; X X for (d = 0; d < 8; ++d) { X ix = wrap(x + dirx[d]); iy = y + diry[d]; X if ((unit = unit_at(ix, iy)) != NULL && enemy_side(side, unit->side)) { X *exp = ix; *eyp = iy; X return TRUE; X } X } X return FALSE; X} X X/* for a given location, see if enemy-held */ X Xenemy_in(side, x, y) Xint x, y; XSide *side; X{ X char view; X X view = side_view(side, x, y); X X return (view != UNSEEN && X view != EMPTY && X enemy_side(side, side_n(valign(view)))); X} X X/* this routine is keyed to the intelligence of the side */ X/* smart enemies ally with each other and go after the player */ X Xenemy_side(s1, s2) XSide *s1, *s2; X{ X if (s1 == s2) return FALSE; X return (s1 == NULL || s2 == NULL || X !(s1->host == NULL && s2->host == NULL)); X} END_OF_mplay.c if test 11237 -ne `wc -c <mplay.c`; then echo shar: \"mplay.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 4 \(of 7\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 7 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 7 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0