]> git.pond.sub.org Git - empserver/blob - src/lib/subs/show.c
(fmttime2822): Changed return type for strftime() to size_t.
[empserver] / src / lib / subs / show.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  show.c: General show routines
29  * 
30  *  Known contributors to this file:
31  *     Julian Onions, 1988
32  *     Jeff Bailey, 1990
33  *     Steve McClure, 1996
34  *     Ron Koenderink, 2005
35  *     Markus Armbruster, 2006-2007
36  */
37
38 #include <config.h>
39
40 #if defined(_WIN32)
41 #include <Windows.h>
42 #endif
43
44 #include <math.h>
45 #include "file.h"
46 #include "game.h"
47 #include "item.h"
48 #include "land.h"
49 #include "nat.h"
50 #include "news.h"
51 #include "nuke.h"
52 #include "optlist.h"
53 #include "plane.h"
54 #include "player.h"
55 #include "product.h"
56 #include "prototypes.h"
57 #include "sect.h"
58 #include "server.h"
59 #include "ship.h"
60
61 static char *fmttime2822(time_t);
62
63 struct look_list {
64     union {
65         struct lchrstr *lp;
66         struct plchrstr *pp;
67         struct mchrstr *mp;
68     } l_u;
69     int tech;
70 };
71
72 /*
73  * Change this if there are ever more than 200 ships, plane or land
74  * unit types.
75  */
76 static struct look_list lookup_list[200];
77 static int lookup_list_cnt = 0;
78
79 static void
80 sort_lookup_list(void)
81 {
82     struct natstr *np = getnatp(player->cnum);
83     struct look_list tmp;
84     int i;
85     int j;
86
87     if (!(np->nat_flags & NF_TECHLISTS))
88         return;
89     for (i = 0; i < lookup_list_cnt; i++) {
90         for (j = i; j < lookup_list_cnt; j++) {
91             if (lookup_list[j].tech < lookup_list[i].tech) {
92                 tmp = lookup_list[j];
93                 lookup_list[j] = lookup_list[i];
94                 lookup_list[i] = tmp;
95             }
96         }
97     }
98 }
99
100 static void
101 make_new_list(int tlev, int type)
102 {
103     struct plchrstr *pp;
104     struct lchrstr *lp;
105     struct mchrstr *mp;
106
107     lookup_list_cnt = 0;
108     if (type == EF_PLANE) {
109         for (pp = plchr; pp->pl_name; pp++) {
110             if (pp->pl_tech > tlev)
111                 continue;
112             lookup_list[lookup_list_cnt].l_u.pp = pp;
113             lookup_list[lookup_list_cnt].tech = pp->pl_tech;
114             lookup_list_cnt++;
115         }
116     } else if (type == EF_SHIP) {
117         for (mp = mchr; mp->m_name; mp++) {
118             if (mp->m_tech > tlev)
119                 continue;
120             lookup_list[lookup_list_cnt].l_u.mp = mp;
121             lookup_list[lookup_list_cnt].tech = mp->m_tech;
122             lookup_list_cnt++;
123         }
124     } else if (type == EF_LAND) {
125         for (lp = lchr; lp->l_name; lp++) {
126             if (lp->l_tech > tlev)
127                 continue;
128             lookup_list[lookup_list_cnt].l_u.lp = lp;
129             lookup_list[lookup_list_cnt].tech = lp->l_tech;
130             lookup_list_cnt++;
131         }
132     } else
133         return;
134
135     sort_lookup_list();
136 }
137
138 void
139 show_bridge(int tlev)
140 {
141     if (tlev < buil_bt)
142         return;
143     pr("Bridges require %g tech,", buil_bt);
144     pr(" %d hcm,", buil_bh);
145     pr(" %d workers,\n", 0);
146     pr("%d available workforce, and cost $%g\n",
147        (SCT_BLD_WORK(0, buil_bh) * SCT_MINEFF + 99) / 100,
148        buil_bc);
149 }
150
151 void
152 show_tower(int tlev)
153 {
154     if (tlev < buil_tower_bt)
155         return;
156     pr("Bridge Towers require %g tech,", buil_tower_bt);
157     pr(" %d hcm,", buil_tower_bh);
158     pr(" %d workers,\n", 0);
159     pr("%d available workforce, and cost $%g\n",
160        (SCT_BLD_WORK(0, buil_tower_bh) * SCT_MINEFF + 99) / 100,
161        buil_tower_bc);
162 }
163
164 void
165 show_nuke_stats(int tlev)
166 {
167     show_nuke_capab(tlev);
168 }
169
170 void
171 show_nuke_build(int tlev)
172 {
173     struct nchrstr *np;
174     int avail;
175
176     pr("%13s lcm hcm  oil  rad avail tech res $\n", "");
177
178     for (np = nchr; np->n_name; np++) {
179         avail = NUK_BLD_WORK(np->n_lcm, np->n_hcm, np->n_oil, np->n_rad);
180         if (np->n_tech > tlev)
181             continue;
182         pr("%-13.13s %3d %3d %4d %4d %5d %4d %3.0f $%6d\n",
183            np->n_name, np->n_lcm, np->n_hcm, np->n_oil,
184            np->n_rad, avail, np->n_tech,
185            drnuke_const > MIN_DRNUKE_CONST ?
186                 ceil(np->n_tech * drnuke_const) : 0.0,
187            np->n_cost);
188     }
189 }
190
191 void
192 show_nuke_capab(int tlev)
193 {
194     struct nchrstr *np;
195     int i, j;
196     char *p;
197
198     pr("%13s blst dam lbs tech res $%7s abilities\n", "", "");
199
200     for (np = nchr; np->n_name; np++) {
201         if (np->n_tech > tlev)
202             continue;
203         pr("%-13.13s %4d %3d %3d %4d %3.0f $%7d ",
204            np->n_name, np->n_blast, np->n_dam,
205            np->n_weight, np->n_tech,
206            drnuke_const > MIN_DRNUKE_CONST ?
207                 ceil(np->n_tech * drnuke_const) : 0.0,
208            np->n_cost);
209         for (i = j = 0; i < 32; i++) {
210             if (!(np->n_flags & bit(i)))
211                 continue;
212             if (NULL != (p = symbol_by_value(bit(i), nuke_chr_flags))) {
213                 if (j++ > 0)
214                     pr(" ");
215                 pr("%s", p);
216             }
217         }
218         pr("\n");
219     }
220 }
221
222 void
223 show_ship_build(int tlev)
224 {
225     struct mchrstr *mp;
226     int n;
227
228     pr("%25s lcm hcm avail tech $\n", "");
229     make_new_list(tlev, EF_SHIP);
230     for (n = 0; n < lookup_list_cnt; n++) {
231         mp = (struct mchrstr *)lookup_list[n].l_u.mp;
232         /* Can't show trade ships unless it's turned on */
233         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
234             continue;
235
236         pr("%-25.25s %3d %3d %5d %4d $%d\n",
237            mp->m_name, mp->m_lcm, mp->m_hcm,
238            SHP_BLD_WORK(mp->m_lcm, mp->m_hcm), mp->m_tech, mp->m_cost);
239     }
240 }
241
242 void
243 show_ship_stats(int tlev)
244 {
245     struct mchrstr *mp;
246     int scount;
247     int techdiff;
248
249     pr("%25s      s  v  s  r  f  l  p", "");
250     pr("  h");
251     pr("  x");
252     if (opt_FUEL)
253         pr("  fuel");
254     pr("\n");
255
256     pr("%25s      p  i  p  n  i  n  l", "");
257     pr("  e");
258     pr("  p");
259     if (opt_FUEL)
260         pr("   c/u");
261     pr("\n");
262
263     pr("%25s def  d  s  y  g  r  d  n", "");
264     pr("  l");
265     pr("  l");
266     if (opt_FUEL)
267         pr("      ");
268     pr("\n");
269
270
271     make_new_list(tlev, EF_SHIP);
272     for (scount = 0; scount < lookup_list_cnt; scount++) {
273         mp = (struct mchrstr *)lookup_list[scount].l_u.mp;
274         /* Can't show trade ships unless it's turned on */
275         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
276             continue;
277
278         techdiff = (int)(tlev - mp->m_tech);
279         pr("%-25.25s %3d %2d %2d %2d %2d %2d ",
280            mp->m_name,
281            (short)SHP_DEF(mp->m_armor, techdiff),
282            (short)SHP_SPD(mp->m_speed, techdiff),
283            (short)SHP_VIS(mp->m_visib, techdiff),
284            mp->m_vrnge,
285            (short)SHP_RNG(mp->m_frnge, techdiff),
286            (short)SHP_FIR(mp->m_glim, techdiff));
287
288         pr("%2d ", mp->m_nland);
289         pr("%2d ", mp->m_nplanes);
290         pr("%2d ", mp->m_nchoppers);
291         pr("%2d ", mp->m_nxlight);
292         if (opt_FUEL)
293             pr("%3d/%1d ", mp->m_fuelc, mp->m_fuelu);
294         pr("\n");
295     }
296 }
297
298 void
299 show_ship_capab(int tlev)
300 {
301     struct mchrstr *mp;
302     i_type i;
303     int j;
304     int scount;
305     int n;
306     char *p;
307
308     pr("%25s cargos & capabilities\n", "");
309
310     make_new_list(tlev, EF_SHIP);
311     for (scount = 0; scount < lookup_list_cnt; scount++) {
312         mp = (struct mchrstr *)lookup_list[scount].l_u.mp;
313         /* Can't show trade ships unless it's turned on */
314         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
315             continue;
316
317         pr("%-25.25s ", mp->m_name);
318
319         for (i = I_NONE + 1; i <= I_MAX; ++i)
320             if (mp->m_item[i])
321                 pr(" %d%c", mp->m_item[i], ichr[i].i_mnem);
322         pr(" ");
323         for (j = n = 0; j < 32; j++) {
324             if (!(mp->m_flags & bit(j)))
325                 continue;
326             if (NULL != (p = symbol_by_value(bit(j), ship_chr_flags))) {
327                 if (n++ > 0)
328                     pr(" ");
329                 pr("%s", p);
330             }
331         }
332         pr("\n");
333     }
334 }
335
336 void
337 show_plane_stats(int tlev)
338 {
339     struct plchrstr *pp;
340     int pcount;
341
342     pr("%25s acc load att def ran fuel stlth\n", "");
343     make_new_list(tlev, EF_PLANE);
344     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
345         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
346         pr("%-25.25s %3d %4d %3d %3d %3d %4d ",
347            pp->pl_name,
348            (int)PLN_ACC(pp->pl_acc, (int)(tlev - pp->pl_tech)),
349            (int)PLN_LOAD(pp->pl_load, (int)(tlev - pp->pl_tech)),
350            (int)PLN_ATTDEF(pp->pl_att, (int)(tlev - pp->pl_tech)),
351            (int)PLN_ATTDEF(pp->pl_def, (int)(tlev - pp->pl_tech)),
352            (int)PLN_RAN(pp->pl_range, (int)(tlev - pp->pl_tech)),
353            pp->pl_fuel);
354         pr("%4d%% ", pp->pl_stealth);
355         pr("\n");
356     }
357 }
358
359 void
360 show_plane_capab(int tlev)
361 {
362     struct plchrstr *pp;
363     int i;
364     int pcount;
365     int n;
366     char *p;
367
368     pr("%25s capabilities\n", "");
369     make_new_list(tlev, EF_PLANE);
370     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
371         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
372         pr("%-25.25s  ", pp->pl_name);
373
374         for (i = n = 0; i < 32; i++) {
375             if (!(pp->pl_flags & bit(i)))
376                 continue;
377             if (NULL != (p = symbol_by_value(bit(i), plane_chr_flags))) {
378                 if (n++ > 0)
379                     pr(" ");
380                 pr("%s", p);
381             }
382         }
383         pr("\n");
384     }
385 }
386
387 void
388 show_plane_build(int tlev)
389 {
390     struct plchrstr *pp;
391     int pcount;
392
393     pr("%25s lcm hcm crew avail tech $\n", "");
394     make_new_list(tlev, EF_PLANE);
395     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
396         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
397         pr("%-25.25s %3d %3d %4d %5d %4d $%d\n",
398            pp->pl_name, pp->pl_lcm,
399            pp->pl_hcm, pp->pl_crew,
400            PLN_BLD_WORK(pp->pl_lcm, pp->pl_hcm), pp->pl_tech, pp->pl_cost);
401     }
402 }
403
404 void
405 show_land_build(int tlev)
406 {
407     struct lchrstr *lp;
408     int n;
409
410     pr("%25s lcm hcm guns avail tech $\n", "");
411     make_new_list(tlev, EF_LAND);
412     for (n = 0; n < lookup_list_cnt; n++) {
413         lp = (struct lchrstr *)lookup_list[n].l_u.lp;
414         if ((lp->l_flags & L_SPY) && !opt_LANDSPIES)
415             continue;
416         pr("%-25.25s %3d %3d %4d %5d %4d $%d\n",
417            lp->l_name, lp->l_lcm,
418            lp->l_hcm,
419            lp->l_gun,
420            LND_BLD_WORK(lp->l_lcm, lp->l_hcm), lp->l_tech, lp->l_cost);
421     }
422 }
423
424 void
425 show_land_capab(int tlev)
426 {
427     struct lchrstr *lcp;
428     int lcount;
429     i_type i;
430     int j, n;
431     char *p;
432
433     pr("%25s capabilities\n", "");
434
435     make_new_list(tlev, EF_LAND);
436     for (lcount = 0; lcount < lookup_list_cnt; lcount++) {
437         lcp = (struct lchrstr *)lookup_list[lcount].l_u.lp;
438         if ((lcp->l_flags & L_SPY) && !opt_LANDSPIES)
439             continue;
440
441         pr("%-25s ", lcp->l_name);
442
443         for (i = I_NONE + 1; i <= I_MAX; ++i)
444             if (lcp->l_item[i])
445                 pr(" %d%c", lcp->l_item[i], ichr[i].i_mnem);
446         pr(" ");
447         for (j = n = 0; j < 32; j++) {
448             if (!(lcp->l_flags & bit(j)))
449                 continue;
450             if (NULL != (p = symbol_by_value(bit(j), land_chr_flags))) {
451                 if (n++ > 0)
452                     pr(" ");
453                 pr("%s", p);
454             }
455         }
456         pr("\n");
457     }
458 }
459
460 void
461 show_land_stats(int tlev)
462 {
463     struct lchrstr *lcp;
464     int lcount;
465     int ourtlev;
466
467     pr("%25s              s  v  s  r  r  a  f  a  a        x  l\n", "");
468     pr("%25s              p  i  p  a  n  c  i  m  a  f  f  p  n\n", "");
469     pr("%25s att def vul  d  s  y  d  g  c  r  m  f  c  u  l  d\n", "");
470
471     make_new_list(tlev, EF_LAND);
472     for (lcount = 0; lcount < lookup_list_cnt; lcount++) {
473         lcp = (struct lchrstr *)lookup_list[lcount].l_u.lp;
474         if ((lcp->l_flags & L_SPY) && !opt_LANDSPIES)
475             continue;
476
477         ourtlev = (int)(tlev - lcp->l_tech);
478         pr("%-25s %1.1f %1.1f %3d ",
479            lcp->l_name,
480            LND_ATTDEF(lcp->l_att, ourtlev),
481            LND_ATTDEF(lcp->l_def, ourtlev),
482            (int)LND_VUL(lcp->l_vul, ourtlev));
483         pr("%2d %2d %2d %2d ",
484            (int)LND_SPD(lcp->l_spd, ourtlev),
485            (int)LND_VIS(lcp->l_vis, ourtlev),
486            (int)LND_SPY(lcp->l_spy, ourtlev),
487            (int)LND_RAD(lcp->l_rad, ourtlev));
488         pr("%2d %2d %2d %2d %2d ",
489            (int)LND_FRG(lcp->l_frg, ourtlev),
490            (int)LND_ACC(lcp->l_acc, ourtlev),
491            (int)LND_DAM(lcp->l_dam, ourtlev),
492            (int)LND_AMM(lcp->l_ammo, ourtlev),
493            (int)LND_AAF(lcp->l_aaf, ourtlev));
494         pr("%2d %2d %2d %2d ",
495            (int)LND_FC(lcp->l_fuelc, ourtlev),
496            (int)LND_FU(lcp->l_fuelu, ourtlev),
497            (int)LND_XPL(lcp->l_nxlight, ourtlev),
498            (int)LND_MXL(lcp->l_nland, ourtlev));
499
500         pr("\n");
501     }
502 }
503
504 void
505 show_sect_build(int foo)
506 {
507     int x, first;
508
509     first = 1;
510     for (x = 0; dchr[x].d_name; x++) {
511         if (dchr[x].d_mnem == 0)
512             continue;
513         if (dchr[x].d_cost < 0)
514             continue;
515         if ((dchr[x].d_cost > 0) || (dchr[x].d_build != 1) ||
516             (dchr[x].d_lcms > 0) || (dchr[x].d_hcms > 0)) {
517             if (first) {
518                 pr("sector type    cost to des    cost for 1%% eff   lcms for 1%%    hcms for 1%%\n");
519                 first = 0;
520             }
521             pr("%-14c %-14d %-17d %-14d %d\n",
522                dchr[x].d_mnem, dchr[x].d_cost, dchr[x].d_build,
523                dchr[x].d_lcms, dchr[x].d_hcms);
524         }
525     }
526
527     first = 1;
528     for (x = 0; intrchr[x].in_name; x++) {
529         if (!intrchr[x].in_enable)
530             continue;
531         if (first)
532             pr("\nInfrastructure building - adding 1 point of efficiency costs:\n"
533                "       type          lcms    hcms    mobility    $$$$\n");
534         pr("%-20s %4d    %4d    %8d    %4d\n",
535            intrchr[x].in_name, intrchr[x].in_lcms, intrchr[x].in_hcms,
536            intrchr[x].in_mcost, intrchr[x].in_dcost);
537         first = 0;
538     }
539 }
540
541 void
542 show_sect_stats(int foo)
543 {
544     int x, first = 1;
545     struct natstr *natp;
546
547     natp = getnatp(player->cnum);
548     for (x = 0; dchr[x].d_name; x++) {
549         if (dchr[x].d_mnem == 0)
550             continue;
551         if (first) {
552             pr("                        mob cost   max   max   --  packing bonus  --   max\n");
553             pr("  sector type            0%% 100%%   off   def   mil  uw civ bar other   pop\n");
554             first = 0;
555         }
556         pr("%c %-21.21s", dchr[x].d_mnem, dchr[x].d_name);
557         if (dchr[x].d_mob0 < 0)
558             pr("  no way ");
559         else
560             pr(" %3.1f  %3.1f", dchr[x].d_mob0, dchr[x].d_mob1);
561         pr("  %5.2f %5.2f   %3d %3d %3d %3d %5d %5d\n",
562            dchr[x].d_ostr, dchr[x].d_dstr,
563            ichr[I_MILIT].i_pkg[dchr[x].d_pkg],
564            ichr[I_UW].i_pkg[dchr[x].d_pkg],
565            ichr[I_CIVIL].i_pkg[dchr[x].d_pkg],
566            ichr[I_BAR].i_pkg[dchr[x].d_pkg],
567            ichr[I_LCM].i_pkg[dchr[x].d_pkg],
568            max_population(natp->nat_level[NAT_RLEV], x, 100));
569     }
570 }
571
572 void
573 show_sect_capab(int foo)
574 {
575     int x, first = 1, i, j;
576     char *tmpstr;
577
578     for (x = 0; dchr[x].d_name; x++) {
579         if (dchr[x].d_mnem == 0 || dchr[x].d_prd < 0)
580             continue;
581         if (first) {
582             pr("                                                 --- level ---          reso \n");
583             pr("  sector type             product use1 use2 use3 level min lag eff%% $$$ dep c\n");
584             first = 0;
585         }
586
587         j = dchr[x].d_prd;
588
589         pr("%c %-23s %-7s ",
590            dchr[x].d_mnem, dchr[x].d_name, pchr[j].p_sname);
591         (void)CANT_HAPPEN(MAXPRCON > 3); /* output has only three columns */
592         for (i = 0; i < 3; i++) {
593             if (i < MAXPRCON
594                 && pchr[j].p_camt[i]
595                 && pchr[j].p_ctype[i] > I_NONE
596                 && pchr[j].p_ctype[i] <= I_MAX) {
597                 pr("%2d %c ", pchr[j].p_camt[i],
598                    ichr[pchr[j].p_ctype[i]].i_name[0]);
599             } else {
600                 pr("     ");
601             }
602         }
603         switch (pchr[j].p_nlndx) {
604         case NAT_TLEV:
605             tmpstr = "tech";
606             break;
607         case NAT_ELEV:
608             tmpstr = "edu";
609             break;
610         case NAT_RLEV:
611             tmpstr = "res";
612             break;
613         case NAT_HLEV:
614             tmpstr = "hap";
615             break;
616         default:
617             tmpstr = " ";
618             break;
619         }
620         pr("%-5s %3d %3d %4d %3d %3d %c",
621            tmpstr,
622            pchr[j].p_nlmin,
623            pchr[j].p_nllag,
624            dchr[x].d_peffic, pchr[j].p_cost, pchr[j].p_nrdep,
625            pchr[j].p_type != I_NONE ? ichr[pchr[j].p_type].i_mnem : ' ');
626
627         pr("\n");
628     }
629 }
630
631 void
632 show_item(int tlev)
633 {
634     struct ichrstr *ip;
635
636     pr("item value sell lbs    packing     melt  item\n");
637     pr("mnem                in rg wh ur bk deno  name\n");
638
639     for (ip = ichr; ip->i_name; ip++) {
640         pr("   %c %5d %4s %3d %2d %2d %2d %2d %2d %4d  %s\n",
641            ip->i_mnem, ip->i_value, ip->i_sell ? "yes" : "no", ip->i_lbs,
642            ip->i_pkg[IPKG], ip->i_pkg[NPKG], ip->i_pkg[WPKG],
643            ip->i_pkg[UPKG], ip->i_pkg[BPKG],
644            ip->i_melt_denom, ip->i_name);
645     }
646 }
647
648 void
649 show_news(int tlev)
650 {
651     int i, j;
652     
653     pr("id category           good will\n");
654     pr("    messsages\n");
655
656     for (i = 1; i < N_MAX_VERB + 1; i++) {
657         if (rpt[i].r_newspage == N_NOTUSED)
658             continue;
659         pr("%-2d %-20.20s %4d\n", rpt[i].r_uid,
660             page_headings[rpt[i].r_newspage].name, rpt[i].r_good_will);
661         for (j = 0; j < NUM_RPTS; j++)
662             pr("    %s\n", rpt[i].r_newstory[j]);
663     }
664 }
665
666 /*
667  * Show update policy and up to N scheduled updates.
668  */
669 void
670 show_updates(int n)
671 {
672     struct gamestr *game = game_tick_tick();
673     int demand = 0;
674     int i;
675
676     pr("%s, Turn %d, ETU %d\n", fmttime2822(time(NULL)),
677        game->game_turn, game->game_tick);
678
679     if (update_time[0]) {
680         if (update_demand == UPD_DEMAND_SCHED) {
681             pr("Demand updates occur according to schedule:\n");
682             demand = 1;
683         } else
684             pr("Updates occur according to schedule:\n");
685         for (i = 0; i < n && update_time[i]; i++)
686             pr("%3d.  %s\n", game->game_turn + i,
687                fmttime2822(update_time[i]));
688         if (update_window) {
689             pr("Updates occur within %d seconds after the scheduled time\n",
690                update_window);
691         }
692     } else
693         pr("There are no updates scheduled.\n");
694
695     if (update_demand == UPD_DEMAND_ASYNC) {
696         pr("Demand updates occur right after the demand is set.\n");
697         if (*update_demandtimes != 0) {
698             pr("Demand updates are allowed during: %s\n",
699                update_demandtimes);
700         }
701         demand = 1;
702     }
703
704     if (demand) {
705         pr("Demand updates require %d country(s) to want one.\n",
706            update_wantmin);
707     }
708
709     if (updates_disabled())
710         pr("\nUPDATES ARE DISABLED!\n");
711 }
712
713 /*
714  * Return T formatted according to RFC 2822.
715  * The return value is statically allocated and overwritten on
716  * subsequent calls.
717  */
718 static char *
719 fmttime2822(time_t t)
720 {
721     static char buf[32];
722 #if defined(_WIN32)
723     size_t n;
724     int nn;
725     TIME_ZONE_INFORMATION tzi;
726     long time_offset;
727     struct tm time;
728     
729     localtime_s(&time, &t);
730
731     n = strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", &time);
732     if (CANT_HAPPEN(n == 0)) {
733         buf[0] = 0;
734         return buf;
735     }
736     GetTimeZoneInformation(&tzi);
737     time_offset = -(tzi.Bias +
738         (time.tm_isdst ? tzi.DaylightBias : tzi.StandardBias));
739
740     nn = _snprintf_s(buf + n, sizeof(buf) - n, sizeof(buf) - n -1,
741         " %+03d%02d",   time_offset/60, abs(time_offset) % 60);
742     if (CANT_HAPPEN(nn <= 0))
743         buf[0] = 0;
744 #else
745     size_t int n = strftime(buf, sizeof(buf), "%a, %d %b %Y %T %z",
746                      localtime(&t));
747     if (CANT_HAPPEN(n == 0))
748         buf[0] = 0;
749 #endif
750     return buf;
751 }