|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 12573 (0x311d) Types: TextFile Names: »side.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/X/Xconq/side.c«
/* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */ /* This program may be used, copied, modified, and redistributed freely */ /* for noncommercial purposes, so long as this notice remains intact. */ /* RCS $Header: side.c,v 1.1 88/06/21 12:30:40 shebs Exp $ */ /* The "side" structure is the repository of information about players. */ /* Surprisingly, there is not much code to manipulate side directly. */ /* Viewing code is somewhat tricky, since any hex may be viewed by any */ /* number of sides at once. */ #include "config.h" #include "misc.h" #include "dir.h" #include "period.h" #include "side.h" #include "unit.h" #include "map.h" Side sides[MAXSIDES]; /* array containing all sides (not very many) */ Side *sidelist; /* head of list of all sides */ Side *tmpside; /* temporary used in many places */ int numsides; /* number of sides in the game */ char *reasonnames[] = REASONNAMES; /* names of columns in unit record */ /* Reset any side structures that need it. */ init_sides() { int i; for (i = 0; i < MAXSIDES; ++i) { sides[i].name = NULL; } sidelist = NULL; numsides = 0; } /* Create an object representing a side. Checking to make sure all human */ /* players have displays has been done by now, so problems mean bugs. */ Side * create_side(name, person, host) char *name, *host; bool person; { int s, i; Side *newside; /* Can't have humans without displays */ if (person && host == NULL) abort(); if (name == NULL) name = "???"; for (s = 0; s < MAXSIDES; ++s) { if (sides[s].name == NULL) { newside = &(sides[s]); newside->name = copy_string(name); newside->humanp = person; if (host == NULL || strcmp(host, "*") == 0) { newside->host = NULL; } else { newside->host = copy_string(host); } newside->lost = FALSE; for_all_unit_types(i) { newside->counts[i] = 1; newside->units[i] = 0; newside->building[i] = 0; } for_all_resource_types(i) { newside->resources[i] = 0; } newside->showmode = BORDERHEX; newside->itertime = 100; newside->view = (unchar *) malloc(world.width*world.height*sizeof(unchar)); newside->coverage = (short *) malloc(world.width*world.height*sizeof(short)); init_view(newside); newside->graphical = GRAPHICAL; newside->display = 0L; init_requests(newside); link_in_side(newside); ++numsides; return newside; } } fprintf(stderr, "Cannot have more than %d sides total!\n", MAXSIDES); abort(); } /* Add the new side to the end of the list of sides - this keeps our */ /* list traversals going from top to bottom (the things we do to keep */ /* users happy...). */ link_in_side(side) Side *side; { Side *head, *last; if (sidelist == NULL) { sidelist = side; } else { for_all_sides(head) { if (head->next == NULL) last = head; } last->next = side; } side->next = NULL; } /* Initialize basic viewing structures for a side, in preparation for the */ /* placement of units. */ init_view(side) Side *side; { int x, y, cov, seen; cov = (period.allseen ? 100 : 0); seen = ((period.allseen || world.known) ? EMPTY : UNSEEN); for (x = 0; x < world.width; ++x) { for (y = 0; y < world.height; ++y) { set_cover(side, x, y, cov); set_side_view(side, x, y, seen); } } } /* Given a side, get its relative position in array of sides (the "number"). */ /* Neutrals are -1, for lack of any better ideas. */ side_number(side) Side *side; { return (side == NULL ? -1 : (side - sides)); } /* The inverse function - given a number, figure out which side it is. */ /* Return NULL for failure; hopefully callers will check on this! */ Side * side_n(n) int n; { return ((n >= 0 && n < numsides) ? &sides[n] : NULL); } /* Put the given unit on the given side, without all the fancy effects. */ /* Important to handle neutrals, because this gets called during init. */ assign_unit_to_side(unit, side) Unit *unit; Side *side; { unit->side = side; unit->number = (side != NULL ? (side->counts)[unit->type]++ : 0); } /* Being at war requires only ones of the sides to consider itself so. */ enemy_side(s1, s2) Side *s1, *s2; { if (s1 == s2) return FALSE; return (s1 != NULL && s2 != NULL && (s1->attitude[side_number(s2)] <= ENEMY || s2->attitude[side_number(s1)] <= ENEMY)); } /* A formal alliance requires the agreement of both sides. */ allied_side(s1, s2) Side *s1, *s2; { if (s1 == s2) return TRUE; return (s1 != NULL && s2 != NULL && s1->attitude[side_number(s2)] >= ALLY && s2->attitude[side_number(s1)] >= ALLY); } /* Neutralness is basically anything else. */ neutral_side(s1, s2) Side *s1, *s2; { return (!enemy_side(s1, s2) && !allied_side(s1, s2)); } /* Formal declarations of war need to do a transitive closure, as part of */ /* dragging allies in. */ declare_war(side1, side2) Side *side1, *side2; { Side *side3; notify_all("The %s and the %s have declared war!!", copy_string(plural_form(side1->name)), copy_string(plural_form(side2->name))); make_war(side1, side2); for_all_sides(side3) { if (allied_side(side3, side1)) make_war(side3, side2); if (allied_side(side3, side2)) make_war(side3, side1); } } /* Internal non-noisy function. */ make_war(side1, side2) Side *side1, *side2; { side1->attitude[side_number(side2)] = ENEMY; side2->attitude[side_number(side1)] = ENEMY; } /* Establish neutrality for both sides. */ declare_neutrality(side1, side2) Side *side1, *side2; { notify_all("The %s and the %s have agreed to neutrality.", copy_string(plural_form(side1->name)), copy_string(plural_form(side2->name))); make_neutrality(side1, side2); } /* Internal non-noisy function. */ make_neutrality(side1, side2) Side *side1, *side2; { side1->attitude[side_number(side2)] = NEUTRAL; side2->attitude[side_number(side1)] = NEUTRAL; } /* Establish the alliance for both sides, then extend it to include */ /* every other ally (only need one pass over sides to ensure transitive */ /* closure, because alliances formed one at a time). */ declare_alliance(side1, side2) Side *side1, *side2; { Side *side3; notify_all("The %s and the %s enter into an alliance.", copy_string(plural_form(side1->name)), copy_string(plural_form(side2->name))); make_alliance(side1, side2); for_all_sides(side3) { if (allied_side(side3, side1)) make_alliance(side3, side2); if (allied_side(side3, side2)) make_alliance(side3, side1); } } /* Internal non-noisy function. */ make_alliance(side1, side2) Side *side1, *side2; { if (side1 != side2) { side1->attitude[side_number(side2)] = ALLY; side2->attitude[side_number(side1)] = ALLY; } } /* General method for passing along info about one side to another. */ /* If sender is NULL, it means to pass along info about *all* sides. */ reveal_side(sender, recipient, chance) Side *sender, *recipient; int chance; { Unit *unit; for_all_units(unit) { if (alive(unit) && (unit->side == sender || sender == NULL) && probability(chance)) { see_exact(recipient, unit->x, unit->y); draw_hex(recipient, unit->x, unit->y, TRUE); } } } /* An always-seen unit has builtin spies to inform of movements. */ /* When such a unit occupies a hex, coverage is turned on and remains */ /* on until the unit leaves that hex. */ all_see_occupy(unit, x, y) Unit *unit; int x, y; { Side *side; if (utypes[unit->type].seealways) { for_all_sides(side) { if (side_view(side, x, y) != UNSEEN) { add_cover(side, x, y, 100); see_hex(side, x, y); } } } } /* Departure results in coverage being decremented, AFTER the side sees */ /* that the hex is now empty. */ all_see_leave(unit, x, y) Unit *unit; int x, y; { Side *side; if (utypes[unit->type].seealways) { for_all_sides(side) { if (side_view(side, x, y) != UNSEEN) { see_hex(side, x, y); add_cover(side, x, y, -100); } } } } /* Unit's beady eyes are now covering the immediate area. The iteration */ /* covers a hex area; since new things may be coming into view, we have */ /* to check and maybe draw lots of hexes (but only need the one flush, */ /* fortunately). */ cover_area(unit, x0, y0, onoff) Unit *unit; int x0, y0, onoff; { int u = unit->type, range, x, y, x1, y1, x2, y2, best, diff, dist, cov; Unit *eunit; Side *side = unit->side; if (neutral(unit) || period.allseen) return; range = utypes[u].seerange; best = utypes[u].seebest; diff = best - utypes[u].seeworst; y1 = y0 - range; y2 = y0 + range; for (y = y1; y <= y2; ++y) { if (between(0, y, world.height-1)) { x1 = x0 - (y < y0 ? (y - y1) : range); x2 = x0 + (y > y0 ? (y2 - y) : range); for (x = x1; x <= x2; ++x) { dist = distance(x0, y0, x, y); cov = (onoff * (best - (dist * diff) / range)) + cover(side, wrap(x), y); set_cover(side, wrap(x), y, max(0, cov)); if (onoff > 0 && see_hex(side, wrap(x), y)) { if ((eunit = unit_at(wrap(x), y)) != NULL) { if (unit->orders.flags & ENEMYWAKE) if (!allied_side(eunit->side, side)) wake_unit(unit, TRUE); } } } } } if (onoff > 0 && active_display(side)) flush_output(side); } /* Update the view of this hex for everybody's benefit. May have to write */ /* to many displays, sigh. */ all_see_hex(x, y) int x, y; { register Side *side; for_all_sides(side) see_hex(side, x, y); } /* Look at the given position, possibly not seeing anything. Return true if */ /* a unit was spotted. */ see_hex(side, x, y) Side *side; int x, y; { register bool yes = FALSE; register int u, chance, newview, terr; register Unit *unit; if (side == NULL) return FALSE; if (cover(side, x, y) > 0) { if ((unit = unit_at(x, y)) != NULL) { u = unit->type; if (unit->side == side) { yes = TRUE; } else { chance = (cover(side, x, y) * utypes[u].visibility) / 100; terr = terrain_at(x, y); chance = (chance * (100 - utypes[u].conceal[terr])) / 100; if (probability(chance)) yes = TRUE; } if (yes) { newview = buildview(side_number(unit->side), u); set_side_view(side, x, y, newview); draw_hex(side, x, y, FALSE); return TRUE; } else { return FALSE; } } else { set_side_view(side, x, y, EMPTY); draw_hex(side, x, y, FALSE); return FALSE; } } else { /* preserve old image */ return FALSE; } } /* "Bare-bones" viewing, for whenever you know exactly what's there. */ /* This is the lowest level of all viewing routines, and executed a *lot*. */ see_exact(side, x, y) Side *side; int x, y; { register int newview; register Unit *unit = unit_at(x, y); if (side == NULL) return; newview = (unit ? buildview(side_number(unit->side), unit->type) : EMPTY); set_side_view(side, x, y, newview); } /* Utility to clean up images of units from a lost side. */ remove_images(side, n) Side *side; int n; { int x, y, view; for (x = 0; x < world.width; ++x) { for (y = 0; y < world.height; ++y) { view = side_view(side, x, y); if (view != EMPTY && view != UNSEEN && vside(view) == n) { set_side_view(side, x, y, EMPTY); } } } } /* Show some overall numbers on performance of a side. */ print_side_results(fp, side) FILE *fp; Side *side; { fprintf(fp, "The %s (%s):\n", plural_form(side->name), (side->host ? side->host : "machine")); fprintf(fp, "\n"); } /* Display what is essentially a double-column bookkeeping of unit gains */ /* and losses. Tricks here include the use of "dummy reason" flags to */ /* display sums of several columns. */ print_unit_record(fp, side) FILE *fp; Side *side; { int atype, reason, sum; fprintf(fp, "Unit Record (gains and losses by cause and unit type)\n"); fprintf(fp, " "); for (reason = 0; reason < NUMREASONS; ++reason) { fprintf(fp, " %3s", reasonnames[reason]); } fprintf(fp, " Total\n"); for_all_unit_types(atype) { sum = 0; fprintf(fp, " %c ", utypes[atype].uchar); for (reason = 0; reason < NUMREASONS; ++reason) { if (side->balance[atype][reason] > 0) { fprintf(fp, " %3d", side->balance[atype][reason]); sum += side->balance[atype][reason]; } else if (reason == DUMMYREAS) { fprintf(fp, " %3d", sum); sum = 0; } else { fprintf(fp, " "); } } fprintf(fp, " %3d\n", sum); } fprintf(fp, "\n"); }