|
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 o
Length: 14740 (0x3994) Types: TextFile Names: »output.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/X/Xconq/output.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: output.c,v 1.1 88/06/21 12:30:32 shebs Exp $ */ /* This file concentrates on the more textual parts of the interface, mainly */ /* the windows dedicated to messages and the like. */ #include "config.h" #include "misc.h" #include "period.h" #include "side.h" #include "unit.h" #include "map.h" #include "global.h" extern int giventime; /* used here to decide if chess clock in use */ char *modenames[] = MODENAMES; /* names of the modes */ char tmpnbuf[BUFSIZE]; /* tmp buf for notices only. */ /* Variables for the "window printf" utility. */ bool wprintmode; /* true when printing is going into a file */ char wbuf[BUFSIZE]; /* accumulated line of text */ int wline; /* current position of output */ FILE *wfp; /* file pointer for wprintf */ /* Send a message to everybody who's got a screen. */ /*VARARGS*/ notify_all(control, a1, a2, a3, a4, a5, a6) char *control, *a1, *a2, *a3, *a4, *a5, *a6; { Side *side; for_all_sides(side) notify(side, control, a1, a2, a3, a4, a5, a6); } /* Main message-sending routine - does its own formatting and spits out to */ /* the given side. Scrolling is by copying strings... :-( */ /*VARARGS*/ notify(side, control, a1, a2, a3, a4, a5, a6) Side *side; char *control, *a1, *a2, *a3, *a4, *a5, *a6; { int i; if (active_display(side)) { for (i = side->nh-1; i > 0; --i) { strcpy(side->noticebuf[i], side->noticebuf[i-1]); } sprintf(tmpnbuf, control, a1, a2, a3, a4, a5, a6); if (islower(tmpnbuf[0])) tmpnbuf[0] = toupper(tmpnbuf[0]); sprintf(side->noticebuf[0], "%d: %s", global.time, tmpnbuf); show_note(side); flush_output(side); if (Debug) printf("%s\n", side->noticebuf[0]); } } /* Notice area refresher. All notes except the most recent one are grayed */ /* out (no effect for monochrome). */ show_note(side) Side *side; { int i, sy = 0; if (active_display(side)) { clear_window(side, side->msg); for (i = side->nh-1; i >= 0; --i) { draw_text(side, side->msg, side->margin, sy, side->noticebuf[i], ((i == 0) ? side->fgcolor : side->graycolor)); sy += side->fh; } } } /* Info about a unit is complicated by the overriding requirement that it */ /* be quickly graspable. Graphics is helpful, so is fixed format (trains */ /* eyes to get a value of interest from same place each time). */ /* Verbal description of what you can see in your view. Can't always show */ /* names because the view doesn't store them, and the unit at that spot may */ /* not exist anymore. Units that are "always seen" (like cities) can be */ /* described in more detail, however. */ show_info(side) Side *side; { bool more = (Debug || Build); int view, u; Unit *unit = side->curunit, *realunit; Side *side2; if (active_display(side)) { if (side->curx >= 0 && side->cury >= 0) { view = side_view(side, side->curx, side->cury); realunit = unit_at(side->curx, side->cury); put_on_screen(side, side->curx, side->cury); if (unit != NULL) { sprintf(tmpbuf, "%s", unit_handle(side, unit)); more = TRUE; } else { if (view == EMPTY || view == UNSEEN) { sprintf(tmpbuf, ""); } else { side2 = side_n(vside(view)); u = vtype(view); if ((utypes[u].seealways || more) && realunit != NULL) { sprintf(tmpbuf, "%s", unit_handle(side, realunit)); } else { sprintf(tmpbuf, "%s %s", (side2 == NULL ? "neutral" : side2->name), utypes[u].name); } } } draw_fg_text(side, side->info, side->margin, 0, tmpbuf); /* put here so overwrites any spillover from name writing */ if (more) { if (unit == NULL) unit = realunit; if (unit != NULL) show_intimate_details(side, unit); } } } } /* Display all the details that only the owner or God (== debugger) sees. */ show_intimate_details(side, unit) Side *side; Unit *unit; { int i, u = unit->type, r, nums[MAXUTYPES], xpos, p = unit->product; Unit *occ; if (unit->transport != NULL) { sprintf(spbuf, "In %s", short_unit_handle(unit->transport)); draw_fg_text(side, side->info, side->margin, 1*side->fh, spbuf); } if (unit->occupant != NULL) { strcpy(spbuf, "Occ "); for_all_unit_types(i) nums[i] = 0; for_all_occupants(unit, occ) nums[occ->type]++; for_all_unit_types(i) { if (nums[i] > 0) { sprintf(tmpbuf, "%d %c ", nums[i], utypes[i].uchar); strcat(spbuf, tmpbuf); } } draw_fg_text(side, side->info, side->margin, 2*side->fh, spbuf); } sprintf(spbuf, "%s %s Moves %d", order_desig(&(unit->orders)), (unit->standing != NULL ? "*" : ""), unit->movesleft); draw_fg_text(side, side->info, side->margin, 3*side->fh, spbuf); if (side->graphical && bar_graphs(side)) { xpos = 0; draw_graph(side, xpos++, unit->hp, utypes[u].hp, utypes[u].crippled, "HP"); if (utypes[u].maxquality > 0) draw_graph(side, xpos++, unit->quality, utypes[u].maxquality, 0,"Qual"); if (utypes[u].maxmorale > 0) draw_graph(side, xpos++, unit->morale, utypes[u].maxmorale, 0, "Mrle"); if (producing(unit)) { draw_graph(side, xpos++, unit->schedule, utypes[u].make[p], 0, utypes[p].name); } for_all_resource_types (r) { if (utypes[u].storage[r] > 0) { draw_graph(side, xpos++, unit->supply[r], utypes[u].storage[r], utypes[u].storage[r]/2, rtypes[r].name); } } } else { sprintf(spbuf, "HP %d/%d", unit->hp, utypes[u].hp); if (utypes[u].maxquality > 0) { sprintf(tmpbuf, " Quality %d/%d", unit->quality, utypes[u].maxquality); strcat(spbuf, tmpbuf); } if (utypes[u].maxmorale > 0) { sprintf(tmpbuf, " Morale %d/%d", unit->morale, utypes[u].maxmorale); strcat(spbuf, tmpbuf); } draw_fg_text(side, side->info, side->margin+30*side->fw, 0, spbuf); if (producing(unit)) { sprintf(spbuf, "New %s in %d turns", utypes[p].name, unit->schedule); draw_fg_text(side, side->info, side->margin+30*side->fw, 1*side->fh, spbuf); } sprintf(spbuf, ""); for_all_resource_types(r) { if (utypes[u].storage[r] > 0) { sprintf(tmpbuf, "%s %d/%d ", rtypes[r].name, unit->supply[r], utypes[u].storage[r]); strcat(spbuf, tmpbuf); } } draw_fg_text(side, side->info, side->margin+30*side->fw, 3*side->fh, spbuf); } } /* Erase the info window. This is done frequently so worthless stuff isn't */ /* hanging around, such as during someone else's turn. */ clear_info(side) Side *side; { if (active_display(side)) { clear_window(side, side->info); } } /* The prompt window consists of exactly one line, but we have to keep track */ /* of where the blank space begins, for when people type into it. */ show_prompt(side) Side *side; { if (active_display(side)) { clear_window(side, side->prompt); draw_fg_text(side, side->prompt, side->margin, 0, side->promptbuf); } } /* Spit a char onto the prompt line, hopefully after the previous one. */ echo_at_prompt(side, ch) Side *side; char ch; { char tmp[2]; if (active_display(side)) { sprintf(tmp, "%c", ch); draw_fg_text(side, side->prompt, side->reqcurstr * side->fw + side->margin, 0, tmp); flush_output(side); } } /* Spit a cursor onto the prompt line. */ write_str_cursor(side) Side *side; { char tmp[3]; if (active_display(side)) { sprintf(tmp, "_ "); draw_fg_text(side, side->prompt, side->reqcurstr * side->fw + side->margin, 0, tmp); flush_output(side); } } /* Clear the prompt line. */ clear_prompt(side) Side *side; { if (active_display(side)) { clear_window(side, side->prompt); sprintf(side->promptbuf, " "); } } /* Show a list of all sides in action, drawing a line through any that have */ /* lost out. This has to be called for each side if everybody's list is */ /* to be updated. */ /* Highlight the side whose turn it is, using reverse video for current */ /* player's own display (to wake she/he/it up) and white instead of gray */ /* for everybody else. Also add a star for the benefit of monochrome. */ show_all_sides(side) Side *side; { int sx = side->margin + 2 * side->fw, sy = 0; Side *side2; if (active_display(side)) { clear_window(side, side->sides); for_all_sides(side2) { sprintf(spbuf, " %d", side_number(side2)); draw_text(side, side->sides, side->margin, sy, spbuf, side_color(side, side2)); sprintf(tmpbuf, ""); if (side2->host != NULL) sprintf(tmpbuf, "(%s)", side2->host); sprintf(spbuf, ": The %s %s", plural_form(side2->name), tmpbuf); draw_text(side, side->sides, sx, sy, spbuf, (side == side2 ? side->fgcolor : side->graycolor)); if (side2->lost) draw_scratchout(side, sy + side->fh / 2); sy += side->fh; } } update_sides(side); } /* The side color here reflects ally/neutral/enemy status. */ side_color(side, side2) Side *side, *side2; { if (side == side2 || allied_side(side, side2)) return side->altcolor; if (enemy_side(side, side2)) return side->enemycolor; return side->neutcolor; } /* This is to pass the current turn marker around. */ /* (Can this be made more efficient if only one turn marker at a time? */ /* How to know which one to erase?) */ update_sides(side) Side *side; { int sx = side->margin, sy = 0; Side *side2; if (active_display(side)) { for_all_sides(side2) { if (!side2->lost) { draw_text(side, side->sides, sx, sy, ((side2 == curside) ? "*" : " "), (side == side2 ? side->fgcolor : side->graycolor)); } sy += side->fh; } flush_output(side); } } /* Update the turn number and game mode display. The mode is inverted */ /* so will stand out (it governs what player input will be accepted, so */ /* quite important). */ show_timemode(side) Side *side; { if (active_display(side)) { clear_window(side, side->timemode); sprintf(spbuf, "Turn%4d", global.time); draw_fg_text(side, side->timemode, side->margin, 0, spbuf); sprintf(spbuf, "%s%s", modenames[side->mode], (side->teach ? "*" : (Build ? "B" : " "))); draw_text(side, side->timemode, side->margin, side->fh, spbuf, (side == curside ? side->bgcolor : side->fgcolor)); flush_output(side); } } /* The state display summarizes all the units and any other global info. */ show_state(side) Side *side; { int u; if (active_display(side)) { clear_window(side, side->state); draw_unit_list(side, side->bvec); for_all_unit_types(u) update_state(side, u); } } /* Alter the numbers for a single type of unit. Should be called right */ /* after any changes. Formatted to look nice, but kind of messy to set */ /* up correctly - Cobol isn't all bad! */ update_state(side, u) Side *side; int u; { int ypos; if (active_display(side)) { sprintf(spbuf, ""); if (side->units[u] > 0) sprintf(tmpbuf, "%3d", side->units[u]); else sprintf(tmpbuf, " "); strcat(spbuf, tmpbuf); if (side->building[u] > 0) { strcat(spbuf, "("); sprintf(tmpbuf, "%d", side->building[u]); strcat(spbuf, tmpbuf); strcat(spbuf, ")"); } sprintf(tmpbuf, " "); strcat(spbuf, tmpbuf); if (total_gain(side, u) > 0) { sprintf(tmpbuf, "%4d", total_gain(side, u)); sprintf(spbuf+8, "%s", tmpbuf); } sprintf(tmpbuf, " "); strcat(spbuf, tmpbuf); if (total_loss(side, u) > 0) { sprintf(tmpbuf, "- %d", total_loss(side, u)); sprintf(spbuf+13, "%s", tmpbuf); } ypos = u * max(side->hh, side->fh) + (side->hh-side->fh) / 2; draw_fg_text(side, side->state, side->hw+side->margin, ypos, spbuf); } } /* Would be faster to stash these, but enough difference to care? */ total_gain(side, u) Side *side; int u; { int i, total = 0; for (i = 0; i < DUMMYREAS; ++i) total += side->balance[u][i]; return total; } total_loss(side, u) Side *side; int u; { int i, total = 0; for (i = DUMMYREAS+1; i < NUMREASONS; ++i) total += side->balance[u][i]; return total; } /* To get the traditional digital clock display, we need fixed-format digit */ /* printing. There will *never* be an option for analog display... */ show_clock(side) Side *side; { int time = side->timeleft, hour, minute, second; hour = time / 3600; minute = (time / 60) % 60; second = time % 60; if (active_display(side) && giventime > 0) { clear_window(side, side->clock); sprintf(spbuf, "%s%d:%s%d:%s%d", (hour < 10 ? "0" : ""), hour, (minute < 10 ? "0" : ""), minute, (second < 10 ? "0" : ""), second); draw_fg_text(side, side->clock, 0, 0, spbuf); } } /* Updates to clock need to be sure that display changes immediately. */ update_clock(side) Side *side; { show_clock(side); flush_output(side); } /* Dump a file into the help window. This routine is neither sophisticated */ /* nor robust - lines must be short enough and file must be one page. */ /* Returns success or failure of file opening. */ show_file(side, fname) Side *side; char *fname; { FILE *fp; if ((fp = fopen(fname, "r")) != NULL) { while (fgets(spbuf, BUFSIZE, fp)) { spbuf[strlen(spbuf)-1] = '\0'; /* cut off newline */ wprintf(side, spbuf); } fclose(fp); return TRUE; } else { return FALSE; } } /* Init our counters or open a file. */ init_wprintf(side, fname) Side *side; char *fname; { wline = 0; if (fname != NULL) { wprintmode = TRUE; wfp = fopen(fname, "w"); if (wfp == NULL) { notify(side, "Warning: open failed."); } } else { wprintmode = FALSE; clear_window(side, side->help); } } /* Make like printf, but to the help window. This is pretty crude - has an */ /* automatic newlining (mis)feature, and doesn't do anything about long */ /* lines, but it's good enough. */ /*VARARGS*/ wprintf(side, control, a1, a2, a3, a4, a5, a6) Side *side; char *control, *a1, *a2, *a3, *a4, *a5, *a6; { if (active_display(side)) { sprintf(wbuf, control, a1, a2, a3, a4, a5, a6); if (wprintmode && wfp != NULL) { fprintf(wfp, "%s\n", wbuf); } else { if (strlen(wbuf) > 0) { draw_fg_text(side, side->help, side->margin, wline*side->fh, wbuf); } wline++; } } } /* If we were actually printing to a file, close it down. */ finish_wprintf() { if (wprintmode && wfp != NULL) fclose(wfp); } /* Frequently-called routine to draw text in the foreground color. */ draw_fg_text(side, win, x, y, str) Side *side; int win, x, y; char *str; { draw_text(side, win, x, y, str, side->fgcolor); }