]> git.pond.sub.org Git - empserver/blob - src/lib/subs/show.c
Fix trailing whitespace
[empserver] / src / lib / subs / show.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, 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-2008
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, %d hcm, 0 workers,\n",
144        buil_bt, buil_bh);
145     pr("%d available workforce, and cost $%g\n",
146        (SCT_BLD_WORK(0, buil_bh) * SCT_MINEFF + 99) / 100,
147        buil_bc);
148 }
149
150 void
151 show_tower(int tlev)
152 {
153     if (tlev < buil_tower_bt)
154         return;
155     pr("Bridge Towers require %g tech, %d hcm, 0 workers,\n",
156        buil_tower_bt, buil_tower_bh);
157     pr("%d available workforce, and cost $%g\n",
158        (SCT_BLD_WORK(0, buil_tower_bh) * SCT_MINEFF + 99) / 100,
159        buil_tower_bc);
160 }
161
162 void
163 show_nuke_stats(int tlev)
164 {
165     show_nuke_capab(tlev);
166 }
167
168 void
169 show_nuke_build(int tlev)
170 {
171     struct nchrstr *np;
172     int avail;
173
174     pr("%13s lcm hcm  oil  rad avail tech res $\n", "");
175
176     for (np = nchr; np->n_name; np++) {
177         avail = NUK_BLD_WORK(np->n_lcm, np->n_hcm, np->n_oil, np->n_rad);
178         if (np->n_tech > tlev)
179             continue;
180         pr("%-13.13s %3d %3d %4d %4d %5d %4d %3.0f $%6d\n",
181            np->n_name, np->n_lcm, np->n_hcm, np->n_oil,
182            np->n_rad, avail, np->n_tech,
183            drnuke_const > MIN_DRNUKE_CONST ?
184                 ceil(np->n_tech * drnuke_const) : 0.0,
185            np->n_cost);
186     }
187 }
188
189 void
190 show_nuke_capab(int tlev)
191 {
192     struct nchrstr *np;
193     int i, j;
194     char *p;
195
196     pr("%13s blst dam lbs tech res $%7s abilities\n", "", "");
197
198     for (np = nchr; np->n_name; np++) {
199         if (np->n_tech > tlev)
200             continue;
201         pr("%-13.13s %4d %3d %3d %4d %3.0f $%7d ",
202            np->n_name, np->n_blast, np->n_dam,
203            np->n_weight, np->n_tech,
204            drnuke_const > MIN_DRNUKE_CONST ?
205                 ceil(np->n_tech * drnuke_const) : 0.0,
206            np->n_cost);
207         for (i = j = 0; i < 32; i++) {
208             if (!(np->n_flags & bit(i)))
209                 continue;
210             if (NULL != (p = symbol_by_value(bit(i), nuke_chr_flags))) {
211                 if (j++ > 0)
212                     pr(" ");
213                 pr("%s", p);
214             }
215         }
216         pr("\n");
217     }
218 }
219
220 void
221 show_ship_build(int tlev)
222 {
223     struct mchrstr *mp;
224     int n;
225
226     pr("%25s lcm hcm avail tech $\n", "");
227     make_new_list(tlev, EF_SHIP);
228     for (n = 0; n < lookup_list_cnt; n++) {
229         mp = (struct mchrstr *)lookup_list[n].l_u.mp;
230         /* Can't show trade ships unless it's turned on */
231         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
232             continue;
233
234         pr("%-25.25s %3d %3d %5d %4d $%d\n",
235            mp->m_name, mp->m_lcm, mp->m_hcm,
236            SHP_BLD_WORK(mp->m_lcm, mp->m_hcm), mp->m_tech, mp->m_cost);
237     }
238 }
239
240 void
241 show_ship_stats(int tlev)
242 {
243     struct mchrstr *mp;
244     int scount;
245
246     pr("%25s      s  v  s  r  f  l  p  h  x", "");
247     pr("\n");
248
249     pr("%25s      p  i  p  n  i  n  l  e  p", "");
250     pr("\n");
251
252     pr("%25s def  d  s  y  g  r  d  n  l  l", "");
253     pr("\n");
254
255
256     make_new_list(tlev, EF_SHIP);
257     for (scount = 0; scount < lookup_list_cnt; scount++) {
258         mp = (struct mchrstr *)lookup_list[scount].l_u.mp;
259         /* Can't show trade ships unless it's turned on */
260         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
261             continue;
262
263         pr("%-25.25s %3d %2d %2d %2d %2d %2d ",
264            mp->m_name, m_armor(mp, tlev), m_speed(mp, tlev),
265            m_visib(mp, tlev), mp->m_vrnge,
266            m_frnge(mp, tlev), m_glim(mp, tlev));
267
268         pr("%2d ", mp->m_nland);
269         pr("%2d ", mp->m_nplanes);
270         pr("%2d ", mp->m_nchoppers);
271         pr("%2d ", mp->m_nxlight);
272         pr("\n");
273     }
274 }
275
276 void
277 show_ship_capab(int tlev)
278 {
279     struct mchrstr *mp;
280     i_type i;
281     int j;
282     int scount;
283     int n;
284     char *p;
285
286     pr("%25s cargos & capabilities\n", "");
287
288     make_new_list(tlev, EF_SHIP);
289     for (scount = 0; scount < lookup_list_cnt; scount++) {
290         mp = (struct mchrstr *)lookup_list[scount].l_u.mp;
291         /* Can't show trade ships unless it's turned on */
292         if ((mp->m_flags & M_TRADE) && !opt_TRADESHIPS)
293             continue;
294
295         pr("%-25.25s ", mp->m_name);
296
297         for (i = I_NONE + 1; i <= I_MAX; ++i)
298             if (mp->m_item[i])
299                 pr(" %d%c", mp->m_item[i], ichr[i].i_mnem);
300         pr(" ");
301         for (j = n = 0; j < 32; j++) {
302             if (!(mp->m_flags & bit(j)))
303                 continue;
304             if (NULL != (p = symbol_by_value(bit(j), ship_chr_flags))) {
305                 if (n++ > 0)
306                     pr(" ");
307                 pr("%s", p);
308             }
309         }
310         pr("\n");
311     }
312 }
313
314 void
315 show_plane_stats(int tlev)
316 {
317     struct plchrstr *pp;
318     int pcount;
319
320     pr("%25s acc load att def ran fuel stlth\n", "");
321     make_new_list(tlev, EF_PLANE);
322     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
323         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
324         pr("%-25.25s %3d %4d %3d %3d %3d %4d ",
325            pp->pl_name, pl_acc(pp, tlev), pl_load(pp, tlev),
326            pl_att(pp, tlev), pl_def(pp, tlev), pl_range(pp, tlev),
327            pp->pl_fuel);
328         pr("%4d%% ", pp->pl_stealth);
329         pr("\n");
330     }
331 }
332
333 void
334 show_plane_capab(int tlev)
335 {
336     struct plchrstr *pp;
337     int i;
338     int pcount;
339     int n;
340     char *p;
341
342     pr("%25s capabilities\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  ", pp->pl_name);
347
348         for (i = n = 0; i < 32; i++) {
349             if (!(pp->pl_flags & bit(i)))
350                 continue;
351             if (NULL != (p = symbol_by_value(bit(i), plane_chr_flags))) {
352                 if (n++ > 0)
353                     pr(" ");
354                 pr("%s", p);
355             }
356         }
357         pr("\n");
358     }
359 }
360
361 void
362 show_plane_build(int tlev)
363 {
364     struct plchrstr *pp;
365     int pcount;
366
367     pr("%25s lcm hcm crew avail tech $\n", "");
368     make_new_list(tlev, EF_PLANE);
369     for (pcount = 0; pcount < lookup_list_cnt; pcount++) {
370         pp = (struct plchrstr *)lookup_list[pcount].l_u.pp;
371         pr("%-25.25s %3d %3d %4d %5d %4d $%d\n",
372            pp->pl_name, pp->pl_lcm,
373            pp->pl_hcm, pp->pl_crew,
374            PLN_BLD_WORK(pp->pl_lcm, pp->pl_hcm), pp->pl_tech, pp->pl_cost);
375     }
376 }
377
378 void
379 show_land_build(int tlev)
380 {
381     struct lchrstr *lp;
382     int n;
383
384     pr("%25s lcm hcm guns avail tech $\n", "");
385     make_new_list(tlev, EF_LAND);
386     for (n = 0; n < lookup_list_cnt; n++) {
387         lp = (struct lchrstr *)lookup_list[n].l_u.lp;
388         if ((lp->l_flags & L_SPY) && !opt_LANDSPIES)
389             continue;
390         pr("%-25.25s %3d %3d %4d %5d %4d $%d\n",
391            lp->l_name, lp->l_lcm,
392            lp->l_hcm,
393            lp->l_gun,
394            LND_BLD_WORK(lp->l_lcm, lp->l_hcm), lp->l_tech, lp->l_cost);
395     }
396 }
397
398 void
399 show_land_capab(int tlev)
400 {
401     struct lchrstr *lcp;
402     int lcount;
403     i_type i;
404     int j, n;
405     char *p;
406
407     pr("%25s capabilities\n", "");
408
409     make_new_list(tlev, EF_LAND);
410     for (lcount = 0; lcount < lookup_list_cnt; lcount++) {
411         lcp = (struct lchrstr *)lookup_list[lcount].l_u.lp;
412         if ((lcp->l_flags & L_SPY) && !opt_LANDSPIES)
413             continue;
414
415         pr("%-25s ", lcp->l_name);
416
417         for (i = I_NONE + 1; i <= I_MAX; ++i)
418             if (lcp->l_item[i])
419                 pr(" %d%c", lcp->l_item[i], ichr[i].i_mnem);
420         pr(" ");
421         for (j = n = 0; j < 32; j++) {
422             if (!(lcp->l_flags & bit(j)))
423                 continue;
424             if (NULL != (p = symbol_by_value(bit(j), land_chr_flags))) {
425                 if (n++ > 0)
426                     pr(" ");
427                 pr("%s", p);
428             }
429         }
430         pr("\n");
431     }
432 }
433
434 void
435 show_land_stats(int tlev)
436 {
437     struct lchrstr *lcp;
438     int lcount;
439
440     pr("%25s              s  v  s  r  r  a  f  a  a  x  l\n", "");
441     pr("%25s              p  i  p  a  n  c  i  m  a  p  n\n", "");
442     pr("%25s att def vul  d  s  y  d  g  c  r  m  f  l  d\n", "");
443
444     make_new_list(tlev, EF_LAND);
445     for (lcount = 0; lcount < lookup_list_cnt; lcount++) {
446         lcp = (struct lchrstr *)lookup_list[lcount].l_u.lp;
447         if ((lcp->l_flags & L_SPY) && !opt_LANDSPIES)
448             continue;
449
450         pr("%-25s %1.1f %1.1f %3d ",
451            lcp->l_name,
452            l_att(lcp, tlev), l_def(lcp, tlev), l_vul(lcp, tlev));
453         pr("%2d %2d %2d %2d ",
454            l_spd(lcp, tlev), lcp->l_vis, lcp->l_spy, lcp->l_rad);
455         pr("%2d %2d %2d %2d %2d ",
456            l_frg(lcp, tlev), l_acc(lcp, tlev), l_dam(lcp, tlev),
457            lcp->l_ammo, lcp->l_aaf);
458         pr("\n");
459     }
460 }
461
462 void
463 show_sect_build(int foo)
464 {
465     int x, first;
466
467     pr("sector type    cost to des    cost for 1%% eff   lcms for 1%%    hcms for 1%%\n");
468     for (x = 0; dchr[x].d_name; x++) {
469         if (dchr[x].d_mnem == 0)
470             continue;
471         if (dchr[x].d_cost < 0)
472             continue;
473         if ((dchr[x].d_cost > 0) || (dchr[x].d_build != 1) ||
474             (dchr[x].d_lcms > 0) || (dchr[x].d_hcms > 0)) {
475             pr("%-14c %-14d %-17d %-14d %d\n",
476                dchr[x].d_mnem, dchr[x].d_cost, dchr[x].d_build,
477                dchr[x].d_lcms, dchr[x].d_hcms);
478         }
479     }
480     pr("other          0              1                 0              0\n");
481
482     first = 1;
483     for (x = 0; intrchr[x].in_name; x++) {
484         if (!intrchr[x].in_enable)
485             continue;
486         if (first)
487             pr("\nInfrastructure building - adding 1 point of efficiency costs:\n"
488                "       type          lcms    hcms    mobility    $$$$\n");
489         pr("%-20s %4d    %4d    %8d    %4d\n",
490            intrchr[x].in_name, intrchr[x].in_lcms, intrchr[x].in_hcms,
491            intrchr[x].in_mcost, intrchr[x].in_dcost);
492         first = 0;
493     }
494 }
495
496 void
497 show_sect_stats(int foo)
498 {
499     int x;
500     struct natstr *natp = getnatp(player->cnum);
501
502     pr("                        mob cost   max   max   naviga    packing   max\n");
503     pr("  sector type            0%% 100%%   off   def   bility      bonus   pop\n");
504
505     for (x = 0; dchr[x].d_name; x++) {
506         if (dchr[x].d_mnem == 0)
507             continue;
508         pr("%c %-21.21s", dchr[x].d_mnem, dchr[x].d_name);
509         if (dchr[x].d_mob0 < 0)
510             pr("  no way ");
511         else
512             pr(" %3.1f  %3.1f", dchr[x].d_mob0, dchr[x].d_mob1);
513         pr("  %5.2f %5.2f %7.7s %10.10s %5d\n",
514            dchr[x].d_ostr, dchr[x].d_dstr,
515            symbol_by_value(dchr[x].d_nav, sector_navigation),
516            symbol_by_value(dchr[x].d_pkg, packing),
517            max_population(natp->nat_level[NAT_RLEV], x, 100));
518     }
519 }
520
521 void
522 show_sect_capab(int foo)
523 {
524     int x;
525
526     pr("  sector type             product  p.e.\n");
527
528     for (x = 0; dchr[x].d_name; x++) {
529         if (dchr[x].d_mnem == 0 || dchr[x].d_prd < 0)
530             continue;
531         pr("%c %-23s %-7s %4d%%\n",
532            dchr[x].d_mnem, dchr[x].d_name, pchr[dchr[x].d_prd].p_sname,
533            dchr[x].d_peffic);
534     }
535 }
536
537 void
538 show_item(int tlev)
539 {
540     struct ichrstr *ip;
541
542     pr("item value sell lbs    packing     melt  item\n");
543     pr("mnem                in no wh ur bk deno  name\n");
544
545     for (ip = ichr; ip->i_name; ip++) {
546         pr("   %c %5d %4s %3d %2d %2d %2d %2d %2d %4d  %s\n",
547            ip->i_mnem, ip->i_value, ip->i_sell ? "yes" : "no", ip->i_lbs,
548            ip->i_pkg[IPKG], ip->i_pkg[NPKG], ip->i_pkg[WPKG],
549            ip->i_pkg[UPKG], ip->i_pkg[BPKG],
550            ip->i_melt_denom, ip->i_name);
551     }
552 }
553
554 void
555 show_product(int tlev)
556 {
557     struct pchrstr *pp;
558     int i;
559     char *lev;
560
561     pr("product    cost  raw materials  reso dep  level p.e.\n");
562
563     for (pp = pchr; pp->p_sname; pp++) {
564         pr("%7.7s %c  $%-3d ",
565            pp->p_sname,
566            pp->p_type < 0 ? ' ' : ichr[pp->p_type].i_mnem,
567            pp->p_cost);
568         (void)CANT_HAPPEN(MAXPRCON > 3); /* output has only three columns */
569         for (i = 0; i < 3; i++) {
570             if (i < MAXPRCON && pp->p_camt[i]
571                 && pp->p_ctype[i] > I_NONE && pp->p_ctype[i] <= I_MAX)
572                 pr(" %2d%c", pp->p_camt[i], ichr[pp->p_ctype[i]].i_mnem);
573             else
574                 pr("    ");
575         }
576         if (pp->p_nrndx)
577             pr("   %5.5s %3d  ",
578                symbol_by_value(pp->p_nrndx, resources), pp->p_nrdep);
579         else
580             pr("              ");
581         if (pp->p_nlndx < 0)
582             pr("1.0\n");
583         else {
584             lev = symbol_by_value(pp->p_nlndx, level);
585             pr("(%.4s%+d)/(%.4s%+d)\n",
586                lev, -pp->p_nlmin, lev, pp->p_nllag - pp->p_nlmin);
587         }
588     }
589 }
590
591 void
592 show_news(int tlev)
593 {
594     int i, j;
595
596     pr("id category           good will\n");
597     pr("    messsages\n");
598
599     for (i = 1; i < N_MAX_VERB + 1; i++) {
600         if (rpt[i].r_newspage == N_NOTUSED)
601             continue;
602         pr("%-2d %-20.20s %4d\n", rpt[i].r_uid,
603             page_headings[rpt[i].r_newspage].name, rpt[i].r_good_will);
604         for (j = 0; j < NUM_RPTS; j++)
605             pr("    %s\n", rpt[i].r_newstory[j]);
606     }
607 }
608
609 /*
610  * Show update policy and up to N scheduled updates.
611  */
612 void
613 show_updates(int n)
614 {
615     struct gamestr *game = game_tick_tick();
616     int demand = 0;
617     int i;
618
619     pr("%s, Turn %d, ETU %d\n", fmttime2822(time(NULL)),
620        game->game_turn, game->game_tick);
621
622     if (update_time[0]) {
623         if (update_demand == UPD_DEMAND_SCHED) {
624             pr("Demand updates occur according to schedule:\n");
625             demand = 1;
626         } else
627             pr("Updates occur according to schedule:\n");
628         for (i = 0; i < n && update_time[i]; i++)
629             pr("%3d.  %s\n", game->game_turn + i,
630                fmttime2822(update_time[i]));
631         if (update_window) {
632             pr("Updates occur within %d seconds after the scheduled time\n",
633                update_window);
634         }
635     } else
636         pr("There are no updates scheduled.\n");
637
638     if (update_demand == UPD_DEMAND_ASYNC) {
639         pr("Demand updates occur right after the demand is set.\n");
640         if (*update_demandtimes != 0) {
641             pr("Demand updates are allowed during: %s\n",
642                update_demandtimes);
643         }
644         demand = 1;
645     }
646
647     if (demand) {
648         pr("Demand updates require %d country(s) to want one.\n",
649            update_wantmin);
650     }
651
652     if (updates_disabled())
653         pr("\nUPDATES ARE DISABLED!\n");
654 }
655
656 /*
657  * Return T formatted according to RFC 2822.
658  * The return value is statically allocated and overwritten on
659  * subsequent calls.
660  */
661 static char *
662 fmttime2822(time_t t)
663 {
664     static char buf[32];
665 #if defined(_WIN32)
666     size_t n;
667     int nn;
668     TIME_ZONE_INFORMATION tzi;
669     long time_offset;
670     struct tm *time;
671
672     time = localtime(&t);
673
674     n = strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", time);
675     if (CANT_HAPPEN(n == 0)) {
676         buf[0] = 0;
677         return buf;
678     }
679     GetTimeZoneInformation(&tzi);
680     time_offset = -(tzi.Bias +
681         (time->tm_isdst ? tzi.DaylightBias : tzi.StandardBias));
682
683     nn = _snprintf(buf + n, sizeof(buf) - n, " %+03d%02d",
684         time_offset/60, abs(time_offset) % 60);
685     if (CANT_HAPPEN(nn <= 0 || nn + n >= sizeof(buf)))
686         buf[0] = 0;
687 #else
688     size_t n = strftime(buf, sizeof(buf), "%a, %d %b %Y %T %z",
689                      localtime(&t));
690     if (CANT_HAPPEN(n == 0))
691         buf[0] = 0;
692 #endif
693     return buf;
694 }