1 | /*
2 | * $Log: summary.c,v $
3 | * Revision 1.17 2003/07/15 22:47:07 millis
4 | * Fix Bug 185 (call smail for each email individually)
5 | *
6 | * Revision 1.16 2003/02/12 07:46:07 nzmb
7 | * Fixed several bugs in the concession handling code, including a severe one
8 | *
9 | * that could, in rare circumstances, lead to an undeserved concession being
10 | * granted
11 | *
12 | * Revision 1.15 2003/01/18 23:57:43 millis
13 | * Updated from USTV
14 | *
15 | * Revision 1.14 2002/08/27 22:27:58 millis
16 | * Updated for automake/autoconf functionality
17 | *
18 | * Revision 1.13 2002/06/12 21:08:30 millis
19 | * second value in player record is hex, thus us %x and not %d
20 | *
21 | * Revision 1.12 2002/04/23 11:08:35 miller
22 | * Spelling change "Svmebody" -> "Somebody"
23 | *
24 | * Revision 1.11 2002/04/18 04:44:34 greg
25 | * Added the following commands:
26 | * - unstart
27 | * - set secret
28 | * - set [prflist|prfrand|prfboth]
29 | *
30 | * Fixed Set Absence so that "to" is not case sensitive
31 | *
32 | * Fixed Quiet games so that new players are announced
33 | * before the game starts
34 | *
35 | * Fixed ascii_to_ded.c so thatit no longer generates an
36 | * error when compiled
37 | *
38 | * Revision 1.10 2002/03/05 23:38:50 miller
39 | * Replaced lost changes revison 1.8
40 | *
41 | * Revision 1.9 2002/03/05 23:05:47 miller
42 | * Fixed Machiavelli summary problem
43 | *
44 | * Revision 1.8 2002/02/03 03:45:43 nzmb
45 | * Fixed bug in plyrdata.c and readded some concession
46 | * handler code to summary.c
47 | *
48 | * Revision 1.7 2001/10/20 12:11:16 miller
49 | * Merged in changes from DEMA and USTV CVS
50 | *
51 | * Revision 1.6.2.1 2001/10/15 22:30:45 ustv
52 | * Added display of duality stuff
53 | *
54 | * Revision 1.6 2001/08/18 07:11:36 nzmb
55 | * Show concessions if applicable
56 | *
57 | * Revision 1.5 2001/07/15 09:20:27 greg
58 | * added support for game directories in a sub directory
59 | *
60 | * Revision 1.4 2001/07/01 23:19:29 miller
61 | * Add storm table
62 | *
63 | * Revision 1.3 2001/03/16 00:06:17 miller
64 | * Fix 'C' parameter so that next one is not squashed
65 | *
66 | * Revision 1.2 2000/11/14 14:27:37 miller
67 | * Accept -C option to specify config_dir
68 | * Handle blind summaries differently (if not master)
69 | *
70 | * Revision 1.1 1998/02/28 17:49:42 david
71 | * Initial revision
72 | *
73 | * Revision 1.1 1996/10/20 12:29:45 rpaar
74 | * Morrolan v9.0
75 | */
76 |
77 | /* summary.c -- Generate a game summary file
78 | * Copyright 1987, Lowe.
79 | *
80 | * Diplomacy is a trademark of the Avalon Hill Game Company, Baltimore,
81 | * Maryland, all rights reserved; used with permission.
82 | *
83 | * Redistribution and use in source and binary forms are permitted
84 | * provided that it is for non-profit purposes, that this and the
85 | * above notices are preserved and that due credit is given to Mr.
86 | * Lowe.
87 | */
88 |
89 | #include <stdlib.h>
90 | #include <string.h>
91 |
92 | #include "config.h"
93 | #include "dip.h"
94 | #include "porder.h"
95 | #include "mach.h"
96 | #include "conf.h"
97 | #include "functions.h"
98 | #include "diplog.h"
99 |
100 | static int variant = 0; /* The currently loaded variant */
101 |
102 | #define MAXADDR 100
103 | #define MAXNAME 80
104 | #define MAXTURN 200
105 | #define MAXPHASE 10
106 | #define YPL 10 /* Ten years per line */
107 | #define CPL 36 /* 36 supply centers per line */
108 |
109 | static char addrs[MAXUSER][MAXADDR], addr[MAXADDR];
110 | static char names[MAXUSER][MAXNAME];
111 | /* this was called "phase", but that conflicted with a function of
112 | * the same name, so i renamed it -- nw Sun Jun 8 00:57:19 GMT 1997 */
113 | static char phaze[MAXTURN][MAXPHASE];
114 | static char owner[MAXTURN][NPROV];
115 | static char cownr[MAXTURN][NPROV];
116 | static char homes[MAXTURN][NPROV];
117 | static int units[MAXTURN][MASTER + 1];
118 | static int centers[MAXTURN][MASTER + 1];
119 | static int player[MAXTURN][MASTER + 1];
120 | static short prov[NPROV], city[NPROV];
121 | static int sqrs[YPL];
122 |
123 | static FILE *tfp;
124 |
125 |
126 | static char outc[] =
127 | {' ', '*', '&', '+', '%', '^', '$', '#', '!', '~', '@', '(',
128 | ')', '=', '-', '_', '|', '\\', '/', '?', '>', '<', '[', ']',
129 | '{', '}', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
130 | 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
131 | 'w', 'x', 'y', 'z'};
132 | static int outn[sizeof(outc)];
133 |
134 | /* todo: move these globals to global.c */
135 | FILE *mfp; /* Master File pointer */
136 | int gflg = 0; /* Nonzero indicates gunboat mode */
137 | int mflg = 0; /* Nonzero indicates master mode */
138 | int bflg = 0; /* Nonzero indicates blind mode */
139 | int main(int argc, char **argv)
140 | {
141 |
142 | /*
143 | * Initialize, read the data structures off the input files.
144 | */
145 |
146 | int i, j, k, n, m, p;
147 | int nprov, cs, ce, ncity, lname = 0, turn, years = 0;
148 | int ix[60], sy, gotent;
149 | char string[30], *s, *t, *name;
150 | char exe_name[100];
151 | int lflg=0;
152 | int tooMany = 0; /* Set to 1 if too many builds were made */
153 |
154 | variant = 1;
155 | name = NULL;
156 | log_fp = stderr;
157 | gotent = 0;
158 |
159 | for (i = 1; i < argc; i++) {
160 | if (*argv[i] == '-') {
161 | for (s = argv[i] + 1; *s; s++) {
162 | switch (*s) {
163 | case 'g':
164 | gflg++;
165 | lname = mflg ? 0 : sizeof("Somebody #00");
166 | break;
167 |
168 | case 'l':
169 | lflg++;
170 | break;
171 |
172 | case 'm':
173 | mflg++;
174 | lname = 0;
175 | break;
176 |
177 | case 'q':
178 | qflg++;
179 | break;
180 |
181 | case 'b':
182 | bflg++;
183 | break;
184 |
185 | case 'C':
186 | if (*++s)
187 | CONFIG_DIR = s;
188 | else if (i+1 < argc)
189 | CONFIG_DIR = argv[i+1];
190 | else {
191 | fprintf(stderr, "Directory must follow C option.\n");
192 | goto usage;
193 | }
194 | i++;
195 | s = " ";
196 | break;
197 |
198 |
199 | case 'c':
200 | /* ignore 'c' options */
201 | break;
202 |
203 |
204 | case 'v':
205 | if (isdigit(*(s + 1))) {
206 | variant = atoi(++s);
207 | while (isdigit(*s))
208 | s++;
209 | s--;
210 | } else {
211 | if (++i < argc) {
212 | variant = atoi(argv[i]);
213 | } else {
214 | fprintf(log_fp, "sum: Missing variant number.\n");
215 | goto usage;
216 | }
217 | }
218 | break;
219 |
220 | default:
221 | fprintf(log_fp, "sum: Unknown option '%c'.\n", *s);
222 | goto usage;
223 | }
224 | }
225 | } else {
226 | if (name)
227 | goto usage;
228 | name = argv[i];
229 | }
230 | }
231 |
232 | /*
233 | * read in the configuration, first from config file,
234 | * finally from the command line
235 | * TODO: fold in command line processing for configuration
236 | * variables with regular argument processing.
237 | */
238 | conf_init();
239 | conf_readfile(CONFIG_DIR, CONFIG_FILE);
240 | conf_cmdline(argc, argv);
241 |
242 | if (lflg) {
243 | if (!(log_fp = fopen(LOG_FILE, "a"))) {
244 | fprintf(stderr, "sum: Unable to open log file.\n");
245 | exit(1);
246 | }
247 | }
248 |
249 | mfp = fopen(MASTER_FILE, "r");
250 | sprintf(exe_name,"%s-%s", JUDGE_CODE, "dip");
251 |
252 | OPENDIPLOG(exe_name);
253 | DIPINFO("Started summary");
254 |
255 |
256 | /*
257 | * We only want to generate the master summary if the gunboat flag
258 | * is enabled. Otherwise the master can look at the regular players'
259 | * summary.
260 | */
261 |
262 | if (mflg) bflg = 0; /* Master is never blind! */
263 |
264 | if (mflg && gflg) {
265 | gflg = 0;
266 | } else {
267 | mflg = 0;
268 | }
269 |
270 | if (!variant) {
271 | fprintf(log_fp, "sum: Invalid numeric variant specified.\n");
272 | goto usage;
273 | }
274 | if (!name) {
275 | usage:
276 | fprintf(log_fp, "sum: Usage: %s [-c<CONFIG>=<value>] [-C<directory>] [-mbglv#] game\n", argv[0]);
277 | fprintf(log_fp, " -c<CONFIG>=<value>: Set <CONFIG> setting to <value>.\n");
278 | fprintf(log_fp, " C: Set directory for dip.conf file.\n");
279 | fprintf(log_fp, " m: Master, don't hide identities in msummary\n");
280 | fprintf(log_fp, " b: Blind game, limits output\n");
281 | fprintf(log_fp, " g: Gunboat, hide identities.\n");
282 | fprintf(log_fp, " l: Send errors to log file.\n");
283 | fprintf(log_fp, " v: Specify alternate variant.\n");
284 | exit(1);
285 | }
286 |
287 |
288 | /*
289 | * Spin through the Gxxx files to find variant
290 | */
291 |
292 | for (turn = 1; turn < MAXTURN; turn++) {
293 | /* TODO: 0 flag for printf(3) is not POSIX, once someone confirms that
294 | * '0' is the default pad for integers, the 0 should be gotten rid of
295 | */
296 | sprintf(line, "%s%s/G%03d", GAME_DIR, name, turn);
297 | if (!(ifp = fopen(line, "r")))
298 | break;
299 | fclose(ifp);
300 | }
301 | if (turn <= 2) {
302 | fprintf(log_fp, "sum: Attempt to obtain summary before 1st turn: %s\n", name);
303 | exit(1);
304 | }
305 | /* TODO: 0 flag for printf(3) is not POSIX, once someone confirms that
306 | * '0' is the default pad for integers, the 0 should be gotten rid of */
307 | sprintf(line, "%s%s/G%03d", GAME_DIR, name, turn - 1);
308 | if ((ifp = fopen(line, "r"))) {
309 | /*
310 | * Skip to dipent
311 | */
312 | while (fgets(line, sizeof(line), ifp) && !(line[0] == '-' && line[1] == '2'));
313 | getdipent(ifp);
314 | fclose(ifp);
315 | }
316 | variant = dipent.variant;
317 |
318 | newdipent(name, variant);
319 |
320 | variant = dipent.variant;
321 |
322 | /*** TODO: Make summary.c and po-init.c use the same code!!!
323 | I am fixing a bug due only to this now! MLM 05/03/2002 ***/
324 |
325 | sprintf(line, "map.%d", variant);
326 | if ((ifp = fopen(line, "r")) == NULL) {
327 | fprintf(log_fp, "sum: Error opening map data file %s.\n", line);
328 | exit(1);
329 | }
330 | if (fread(&npr, sizeof(npr), 1, ifp) != 1 ||
331 | fread(&hp, sizeof(hp), 1, ifp) != 1 ||
332 | fread(&nv, sizeof(nv), 1, ifp) != 1) {
333 | fprintf(log_fp, "sum: Error reading map file npr/hp/nv, %s.\n", line);
334 | return E_FATAL;
335 | }
336 | maxheap = hp + 2048;
337 | if (!(heap = (unsigned char *) malloc(maxheap + 10))) {
338 | fprintf(log_fp, "sum: Unable to allocate heap.\n");
339 | return E_FATAL;
340 | }
341 |
342 | for (i = 1; i <= npr; i++) {
343 | if (fread(cmap, sizeof(cmap[0]), CMAP_SIZE, ifp) != CMAP_SIZE) {
344 | fprintf(log_fp, "sum: cmap read error city = %d, %s.\n", i, line);
345 | return E_FATAL;
346 | }
347 | pr[i].name = (char *) &heap[cmap[CMAP_NAME]];
348 | pr[i].move = (unsigned char *) &heap[cmap[CMAP_MOVE]];
349 | pr[i].type = cmap[CMAP_TYPE];
350 | pr[i].flags = cmap[CMAP_FLAG];
351 | pr[i].type2 = cmap[CMAP_TYPE2];
352 | n = islower(pr[i].type) ? 0 : power(pr[i].type);
353 | pr[i].owner = n;
354 | pr[i].cown = n;
355 | pr[i].home = n;
356 | pr[i].unit = 0;
357 | pr[i].gunit = 0;
358 | }
359 |
360 | if ((i = fread(heap, sizeof(unsigned char), hp, ifp)) != hp) {
361 | fprintf(log_fp, "sum: cmap heap read error, %d of %d, %s.\n", i, hp, line);
362 | return E_FATAL;
363 | }
364 | if (nv > MAXVINC) {
365 | fprintf(log_fp, "sum: Maximum variable income exceeded.\n");
366 | return E_FATAL;
367 | }
368 | if (nv > 0) {
369 | if ((i = fread(vincome, sizeof(vincome[0]), nv, ifp)) != nv) {
370 | fprintf(log_fp, "sum: cmap income read error, %d of %d, %s.\n", i, nv, line);
371 | return E_FATAL;
372 | }
373 | if ((i = fread(ftab, sizeof(ftab), 1, ifp)) != 1) {
374 | fprintf(log_fp, "sum: cmap ftab read error, %d. %s\n", i, line);
375 | return E_FATAL;
376 | }
377 | if ((i = fread(ptab, sizeof(ptab), 1, ifp)) != 1) {
378 | fprintf(log_fp, "sum: cmap ptab read error, %d. %s\n", i, line);
379 | return E_FATAL;
380 | }
381 | if ((i = fread(stab, sizeof(stab), 1, ifp)) != 1) {
382 | fprintf(log_fp, "sum: cmap stab read error, %d. %s\n", i, line);
383 | return E_FATAL;
384 | }
385 | if ((i = fread(permitted_units, sizeof(permitted_units), 1, ifp)) != 1) {
386 | fprintf(rfp, "cmap permitted_units read error, %d. %s\n", i, line);
387 | return E_FATAL;
388 | }
389 | if ((i = fread(&initial_money, sizeof(initial_money), 1, ifp)) != 1) {
390 | fprintf(rfp, "cmap initial_money read error, %d. %s\n", i, line);
391 | return E_FATAL;
392 | }
393 | }
394 | /* Now read colonial hk, gw and rw settings */
395 | if (fread(&nhk, sizeof(nhk),1, ifp) != 1) {
396 | /* Serious error, what to do? */
397 | nhk = 0;
398 | }
399 | if (nhk > 0) {
400 | if(fread(hk, sizeof(hk[0]), nhk, ifp) != nhk) {
401 | fprintf(ifp, "Mismatch on number of hk records.\n");
402 | exit(1);
403 | }
404 | }
405 | if (fread(&ngw, sizeof(ngw),1, ifp) != 1) {
406 | /* Serious error, what to do? */
407 | ngw = 0;
408 | }
409 | if (ngw > 0) {
410 | if(fread(gw, sizeof(gw[0]), ngw, ifp) != ngw) {
411 | fprintf(ifp, "Mismatch on number of gw records.\n");
412 | exit(1);
413 | }
414 | }
415 | if (fread(&nrw, sizeof(nrw),1, ifp) != 1) {
416 | /* Serious error, what to do? */
417 | nrw = 0;
418 | }
419 | if (nrw > 0) {
420 | if(fread(rw, sizeof(rw[0]), nrw, ifp) != nrw) {
421 | fprintf(ifp, "Mismatch on number of rw records.\n");
422 | exit(1);
423 | }
424 | }
425 |
426 | /*
427 | * Get the province/supply center ordering.
428 | */
429 |
430 | if ((i = fread(&nprov, sizeof(nprov), 1, ifp)) != 1 || nprov == 0) {
431 | fclose(ifp);
432 | sprintf(line, "%s%s/%ssummary", GAME_DIR, dipent.name, mflg ? "m" : "");
433 | if (!(ifp = fopen(line, "w"))) {
434 | perror(line);
435 | exit(1);
436 | }
437 | fprintf(ifp, "Sorry, summary not supported for the %s variant.\n",
438 | variants[variant]);
439 | exit(0);
440 | }
441 |
442 | if (nprov > NPROV) {
443 | fprintf(log_fp, "sum: Too many prov records: %d of %d.\n", nprov, NPROV);
444 | exit(1);
445 | }
446 | if ((i = fread(prov, sizeof(prov[0]), nprov, ifp)) != nprov) {
447 | fprintf(log_fp, "sum: prov read error, %d of %d.\n", i, nprov);
448 | exit(1);
449 | }
450 | /*
451 | * Get the city ordering.
452 | */
453 |
454 | if ((i = fread(&ncity, sizeof(ncity), 1, ifp)) != 1) {
455 | ncity = 0;
456 | }
457 | if (ncity > NPROV) {
458 | fprintf(log_fp, "sum: Too many city records: %d of %d.\n", ncity, NPROV);
459 | exit(1);
460 | }
461 | if ((i = fread(city, sizeof(city[0]), ncity, ifp)) != ncity) {
462 | fprintf(log_fp, "sum: city read error, %d of %d.\n", i, ncity);
463 | exit(1);
464 | }
465 | fclose(ifp);
466 |
467 | /*
468 | * Get the real names for the players.
469 | */
470 |
471 | if ((ifp = fopen("dip.whois", "r"))) {
472 | while (fgets(line, sizeof(line), ifp)) {
473 | for (s = line; isspace(*s); s++); /* skip any leading whitespace */
474 | if (!strncmp(s, "User:", 5)) {
475 | sscanf(s, "User: %d", &i);
476 | } else if (!strncasecmp(s, "Name:", 5)) {
477 | for (s += 5; isspace(*s); s++);
478 | for (t = names[i]; t < names[i] + MAXNAME && *s && *s != '\n';
479 | *t++ = *s++);
480 | *t = '\0';
481 | }
482 | }
483 | }
484 | /*
485 | * Spin through the Gxxx files and gather up stats.
486 | */
487 |
488 | for (turn = 1; turn < MAXTURN; turn++) {
489 | /* TODO remove non-posix 0 flag */
490 | sprintf(line, "%s%s/G%03d", GAME_DIR, dipent.name, turn);
491 | if (!(ifp = fopen(line, "r")))
492 | break;
493 |
494 | /*
495 | * Get the phase.
496 | */
497 |
498 | fgets(phaze[turn], sizeof(phaze[turn]), ifp);
499 | if ((s = strchr(phaze[turn], '\n')))
500 | *s = '\0';
501 |
502 | /*
503 | * Skip unit locations.
504 | */
505 |
506 | while (fgets(line, sizeof(line), ifp) && *line != '-');
507 |
508 | /*
509 | * Get the supply center ownerships.
510 | */
511 |
512 | fgets(line, sizeof(line), ifp);
513 | if (*line != '-') {
514 | if (line[1] == ':') {
515 | j = 1;
516 | while (fgets(line, sizeof(line), ifp) && line[1] == ':') {
517 | switch (*line) {
518 |
519 | /*
520 | * C: City ownership
521 | */
522 |
523 | case 'C':
524 | for (i = j, t = line + 2; *t && !isspace(*t); i++, t++)
525 | if (!isalnum(*t))
526 | *t = '.';
527 | strcpy(cownr[turn] + j - 1, line + 2);
528 | break;
529 |
530 | /*
531 | * H: Province home ownership
532 | */
533 |
534 | case 'H':
535 | for (i = j, t = line + 2; *t && !isspace(*t); i++, t++)
536 | if (!isalnum(*t))
537 | *t = '.';
538 | strcpy(homes[turn] + j - 1, line + 2);
539 | break;
540 |
541 | /*
542 | * N: Comment, province name. Note: OCHF must follow N.
543 | */
544 |
545 | case 'N':
546 | j = i;
547 | break;
548 |
549 | /*
550 | * O: Province ownership.
551 | */
552 |
553 | case 'O':
554 | for (i = j, t = line + 2; *t && !isspace(*t); i++, t++)
555 | if (!isalnum(*t))
556 | *t = '.';
557 | strcpy(owner[turn] + j - 1, line + 2);
558 | break;
559 | }
560 | }
561 |
562 | } else { /* Old pre-Machiavelli format */
563 |
564 | strcpy(owner[turn], line);
565 | fgets(line, sizeof(line), ifp);
566 |
567 | }
568 |
569 | /*
570 | * Read in player list.
571 | */
572 |
573 | n = 0;
574 | while (*line != '-') {
575 | get_power(line, &p);
576 | if (!p && *line == 'M')
577 | p = MASTER;
578 | if (p) {
579 | n++;
580 | j = sscanf(line, "%s %x %d %d %d %d %d %s", string, &i,
581 | &units[turn][p], ¢ers[turn][p], &player[turn][p], &i, &i, addr);
582 |
583 | if (j != 8) {
584 | fprintf(log_fp, "sum: Bad G%3.3d line, %d: %s", turn - 1, j, line);
585 | }
586 | if ((i = player[turn][p]) < MAXUSER) {
587 | if (*addr != '*')
588 | strcpy(addrs[i], addr);
589 | if ((s = strchr(addrs[i], '\n')))
590 | *s = '\0';
591 | if (!gflg || p == MASTER) {
592 | if ((j = strlen(names[i])) > lname)
593 | lname = j;
594 | }
595 | } else {
596 | player[turn][p] = MAXUSER - 1;
597 | strcpy(names[MAXUSER - 1], "Unknown");
598 | }
599 |
600 | }
601 | if (!fgets(line, sizeof(line), ifp))
602 | break;
603 | }
604 |
605 | if (!n) {
606 | for (i = 0; i <= npr; i++) {
607 | if ((p = power(owner[turn][i]))) {
608 | centers[turn][p]++;
609 | }
610 | }
611 | }
612 | /*
613 | * Get any dipent entry we run across. (only last is retained)
614 | */
615 |
616 | if (line[0] == '-' && line[1] == '2') {
617 | gotent = 1;
618 | getdipent(ifp);
619 | }
620 | } else {
621 |
622 | /*
623 | * Use default supply center ownerships--'x' = unowned center, 'l' =
624 | * land non-center, & 'w' = water non-center, so don't count those.
625 | */
626 |
627 | for (i = 0; i <= npr; i++) {
628 | if ((pr[i + 1].type != 'x') && (pr[i + 1].type != 'l') &&
629 | (pr[i + 1].type != 'w')) {
630 | owner[turn][i] = cownr[turn][i] = homes[turn][i] = pr[i + 1].type;
631 | } else {
632 | owner[turn][i] = cownr[turn][i] = homes[turn][i] = '.';
633 | }
634 | centers[turn][power(owner[turn][i])]++;
635 | units[turn][power(owner[turn][i])]++;
636 | }
637 | owner[turn][i] = cownr[turn][i] = homes[turn][i] = '\n';
638 |
639 | }
640 |
641 | fclose(ifp);
642 |
643 | }
644 |
645 | if (phaze[1][0] == 'S' && phaze[1][5] == 'M') {
646 | sprintf(phaze[0], "x%4.4dB", atoi(phaze[1] + 1) - 1);
647 | } else {
648 | sprintf(phaze[0], "x%4.4dx", atoi(phaze[1] + 1));
649 | }
650 | memcpy(owner[0], owner[1], sizeof(owner[0]));
651 | memcpy(cownr[0], cownr[1], sizeof(cownr[0]));
652 | memcpy(homes[0], homes[1], sizeof(homes[0]));
653 | memcpy(centers[0], centers[1], sizeof(centers[0]));
654 | memcpy(units[0], units[1], sizeof(units[0]));
655 |
656 | if (dipent.flags & F_MACH) {
657 | for (p = 1; p < WILD_PLAYER; p++) {
658 | if (dipent.pl[p] == 'x')
659 | continue;
660 | centers[1][p] = centers[2][p] + 3 * units[2][p];
661 | }
662 | }
663 | /*
664 | * Oh boy, now we write out the report. First the player list.
665 | */
666 |
667 | sprintf(line, "%s%s/%ssummary", GAME_DIR, dipent.name, mflg ? "m" : "");
668 | if (!(ifp = fopen(line, "w"))) {
669 | perror(line);
670 | exit(1);
671 | }
672 | fprintf(ifp, "Summary of game '%s' through %s.\n\n", dipent.name, phaze[turn - 2]);
673 |
674 | k = 1;
675 | for (p = MASTER; p < WILD_PLAYER || p == MASTER; p++) {
676 | if (dipent.pl[p] == 'x')
677 | continue;
678 | i = 0;
679 | for (j = 1; j < turn; j++) {
680 | if (qflg && gflg && !mflg) { /* Don't show power transfer if quiet */
681 | if (i)
682 | player[j][p] = i;
683 | }
684 | if ((n = player[j][p]) && i != n) {
685 | if (!i) {
686 | while (i < j)
687 | player[i++][p] = n;
688 | fprintf(ifp, " %s:%*s", powers[p], (int) (14 - strlen(powers[p])), "");
689 | } else {
690 | fprintf(ifp, " from %6.6s: ", phaze[j - 1]);
691 | }
692 | i = n;
693 | if (gflg && p != MASTER) {
694 | if (strncmp(names[i], "Somebody #", 10)) {
695 | strcpy(addrs[i], "someone@somewhere");
696 | if (dipent.x2flags & X2F_SECRET) {
697 | sprintf(names[i], "Somebody ");
698 | } else {
699 | sprintf(names[i], "Somebody #%d", k++);
700 | }
701 | }
702 | }
703 | addrs[i][120 - 14 - 1 - 2 - lname - 3] = '\0';
704 | fprintf(ifp, "%-*s %s\n", lname, names[i], addrs[i]);
705 | }
706 | }
707 |
708 | if (p == MASTER)
709 | p = 0;
710 | }
711 |
712 | /*
713 | ** We'll output the parameters if we managed to find a dipent entry.
714 | (this routine is not used at the moment, it gets the dipent from
715 | the dip.master file. The current assumption is that the most
716 | recent dipent in the data files is better)
717 | strcpy(name, dipent.name);
718 | while (getdipent(mfp)) {
719 | if (strcmp(dipent.name,name) == 0)
720 | break;
721 | };
722 | */
723 |
724 | if (gotent) {
725 | fprintf(ifp, "\n\nGame parameters are/were as follows:\n");
726 | params(ifp);
727 | }
728 | fprintf(ifp, " Judge: %s.\n", JUDGE_CODE);
729 |
730 | /*
731 | * Game start date
732 | */
733 |
734 | sprintf(line, "%s%s/start", GAME_DIR, dipent.name);
735 | if ((tfp = fopen(line, "r"))) {
736 | fputs("\n", ifp);
737 | while (fgets(line, sizeof(line), tfp))
738 | fputs(line, ifp);
739 | fclose(tfp);
740 | }
741 | /*
742 | * Draw if there is one, is next
743 | */
744 |
745 | sprintf(line, "%s%s/draw", GAME_DIR, dipent.name);
746 | if ((tfp = fopen(line, "r"))) {
747 | while (fgets(line, sizeof(line), tfp))
748 | fputs(line, ifp);
749 | fclose(tfp);
750 | }
751 | /*
752 |
753 | * or concession ...
754 |
755 | */
756 |
757 | sprintf(line, "%s%s/conc", GAME_DIR, dipent.name);
758 |
759 | if((tfp = fopen(line, "r"))) {
760 |
761 | while(fgets(line, sizeof(line), tfp))
762 |
763 | fputs(line, ifp);
764 |
765 | fclose(tfp);
766 |
767 | }
768 | /*
769 | * Comments if any are next.
770 | */
771 |
772 | sprintf(line, "%s%s/info", GAME_DIR, dipent.name);
773 | if ((tfp = fopen(line, "r"))) {
774 | fputs("\n", ifp);
775 | while (fgets(line, sizeof(line), tfp))
776 | fputs(line, ifp);
777 | fclose(tfp);
778 | }
779 | /*
780 | * Next we take care of the supply center ownership.
781 | */
782 |
783 | /* Only display this section if not blind or for master */
784 |
785 | if (!bflg) for (cs = 0; cs < nprov; cs += CPL) {
786 | ce = nprov < cs + CPL ? nprov : cs + CPL;
787 |
788 | if (dipent.flags & F_MACH) {
789 | fprintf(ifp, "\n\nHistorical Province Summary%s\n", cs ? " (cont)" : "");
790 | fprintf(ifp, "---------------------------%s\n", cs ? "-------" : "");
791 | } else {
792 | fprintf(ifp, "\n\nHistorical Supply Center Summary%s\n", cs ? " (cont)" : "");
793 | fprintf(ifp, "--------------------------------%s\n", cs ? "-------" : "");
794 | }
795 | fprintf(ifp, " ");
796 | for (i = cs; i < ce; i += 2) {
797 | s = pr[prov[i]].name;
798 | while (*s)
799 | s++;
800 | s++;
801 | s++;
802 | if (!*s)
803 | s = pr[prov[i]].name;
804 | if (islower(*s))
805 | *s = toupper(*s);
806 | fprintf(ifp, " %-3.3s", s);
807 | }
808 |
809 | fprintf(ifp, "\nYear ");
810 | for (i = cs + 1; i < ce; i += 2) {
811 | s = pr[prov[i]].name;
812 | while (*s)
813 | s++;
814 | s++;
815 | s++;
816 | if (!*s)
817 | s = pr[prov[i]].name;
818 | if (islower(*s))
819 | *s = toupper(*s);
820 | fprintf(ifp, " %-3.3s", s);
821 | }
822 | fputc('\n', ifp);
823 |
824 | years = 0;
825 | for (i = 0; i < turn; i++) {
826 | if (phaze[i][5] == 'B' || phaze[i][5] == 'A' ||
827 | ((i == (turn - 1)) && (phaze[i][6] == 'X')) ||
828 | ((i != 0) && (i < turn - 1) && (phaze[i + 1][4] != phaze[i][4]))) {
829 | fprintf(ifp, "%4.4d", atoi(phaze[i] + 1));
830 | for (p = cs; p < ce; p++)
831 | fprintf(ifp, " %c", owner[i][prov[p] - 1]);
832 | fputc('\n', ifp);
833 | ix[years++] = i;
834 | }
835 | }
836 | }
837 |
838 | /*
839 | * Similarly the city ownerships.
840 | */
841 |
842 | if (!bflg) for (cs = 0; cs < ncity; cs += CPL) {
843 | ce = ncity < cs + CPL ? ncity : cs + CPL;
844 |
845 | fprintf(ifp, "\n\nHistorical City Summary%s\n", cs ? " (cont)" : "");
846 | fprintf(ifp, "-----------------------%s\n", cs ? "-------" : "");
847 | fprintf(ifp, " ");
848 | for (i = cs; i < ce; i += 2) {
849 | s = pr[city[i]].name;
850 | while (*s)
851 | s++;
852 | s++;
853 | s++;
854 | if (!*s)
855 | s = pr[city[i]].name;
856 | if (islower(*s))
857 | *s = toupper(*s);
858 | fprintf(ifp, " %-3.3s", s);
859 | }
860 |
861 | fprintf(ifp, "\nYear ");
862 | for (i = cs + 1; i < ce; i += 2) {
863 | s = pr[city[i]].name;
864 | while (*s)
865 | s++;
866 | s++;
867 | s++;
868 | if (!*s)
869 | s = pr[city[i]].name;
870 | if (islower(*s))
871 | *s = toupper(*s);
872 | fprintf(ifp, " %-3.3s", s);
873 | }
874 | fputc('\n', ifp);
875 |
876 | for (i = 0; i < years; i++) {
877 | fprintf(ifp, "%4.4d", atoi(phaze[ix[i]] + 1));
878 | for (p = cs; p < ce; p++)
879 | fprintf(ifp, " %c", cownr[ix[i]][city[p] - 1]);
880 | fputc('\n', ifp);
881 | }
882 | }
883 |
884 | /*
885 | * Next we take care of supply center counts..
886 | */
887 |
888 | if (dipent.flags & F_MACH) {
889 | fprintf(ifp, "\n\nHistory of Treasury for Adjustments\n");
890 | fprintf(ifp, "-----------------------------------\n");
891 | } else {
892 | fprintf(ifp, "\n\nHistory of Supply Center Counts\n");
893 | fprintf(ifp, "-------------------------------\n");
894 | }
895 |
896 | for (sy = 0; sy < years; sy += YPL) {
897 |
898 | fprintf(ifp, "Power %4.4s", phaze[ix[sy]] + 1);
899 | for (i = 1; i < YPL && i + sy < years; i++)
900 | fprintf(ifp, " '%2.2s", phaze[ix[i + sy]] + 3);
901 | fprintf(ifp, "%*sPlayer\n", 4 * (YPL - i) + 3, "");
902 |
903 | for (p = 1; p < WILD_PLAYER; p++) {
904 | if (dipent.pl[p] == 'x' || !centers[ix[sy]][p])
905 | continue;
906 | fprintf(ifp, "%-10.10s", powers[p]);
907 | j = 0;
908 | for (i = 0; i < YPL && i + sy < years; i++) {
909 | if (!qflg && player[ix[i + sy]][p] != player[ix[j + sy]][p]) {
910 | if (player[ix[j + sy]][p]) {
911 | fprintf(ifp, "\\%*s%s\n%*s", 4 * (YPL - i) - 1 + 2, "",
912 | names[player[ix[j + sy]][p]], 10 + 4 * i, "");
913 | }
914 | j = i;
915 | }
916 | if (!centers[ix[i + sy]][p])
917 | break;
918 | m = centers[ix[i + sy]][p];
919 | n = (ix[i + sy] == turn - 1) || (dipent.flags & F_MACH) ?
920 | m : units[ix[i + sy] + 1][p];
921 | if (!bflg) {
922 |
923 | if (n > m) {
924 | fprintf(ifp, "%3dX", m);
925 | tooMany = 1;
926 | }
927 | else
928 | fprintf(ifp, "%3d%c", m, outc[m - n]);
929 | } else {
930 | fprintf(ifp, "%3d ", m);
931 | }
932 | if (n <= m) outn[m - n]++;
933 | sqrs[i] += m * m;
934 | }
935 | fprintf(ifp, "%*s%s\n", 4 * (YPL - i) + 2, "", names[player[ix[j + sy]][p]]);
936 | }
937 |
938 | if (!(dipent.flags & F_MACH)) {
939 | fprintf(ifp, "Index: ");
940 | for (i = 0; i < YPL && i + sy < years; i++) {
941 | fprintf(ifp, "%4d", sqrs[i] / dipent.np);
942 | sqrs[i] = 0;
943 | }
944 | }
945 | fprintf(ifp, "\n\n");
946 |
947 | }
948 |
949 | if (!bflg) {
950 | if (tooMany)
951 | fprintf(ifp, "X = too many build(s).\n");
952 |
953 | for (i = 1; i < sizeof(outc); i++) {
954 | if (outn[i]) {
955 | fprintf(ifp, "%c = %d unused build%s.\n", outc[i], i, i == 1 ? "" : "s");
956 | }
957 | }
958 | }
959 | /*
960 | * Next we take care of the rest of the info...
961 | */
962 |
963 | if (!(dipent.flags & F_MACH)) {
964 | fprintf(ifp, "\nIndex is the sum of squares of the number of supply centers divided by the\n");
965 | fprintf(ifp, "number of players. It is a measure of how far the game has progressed.\n");
966 | }
967 | fclose(ifp);
968 | return 0;
969 | }