DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T o

⟦1c873d67c⟧ TextFile

    Length: 14740 (0x3994)
    Types: TextFile
    Names: »output.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Xconq/output.c« 

TextFile

/* 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);
}