]> git.pond.sub.org Git - empserver/blob - src/lib/commands/spy.c
Make spy command require sector military
[empserver] / src / lib / commands / spy.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  *  spy.c: Spy on your neighbors
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Steve McClure, 1998-2000
33  */
34
35 #include <config.h>
36
37 #include "commands.h"
38 #include "item.h"
39 #include "land.h"
40 #include "map.h"
41 #include "news.h"
42 #include "optlist.h"
43 #include "path.h"
44 #include "plane.h"
45
46 /*
47  * format:  spy <SECTS>
48  */
49
50 static int check(coord *table, int *len, coord x, coord y);
51 static void insert(coord *table, int *len, coord x, coord y);
52 static void spy_report(struct sctstr *sp);
53 static void prplanes(int, int);
54 static void prunits(int, int);
55 static char *player_relstr(natid);
56
57 int
58 spy(void)
59 {
60     natid own;
61     int relat;
62     coord x, y;
63     coord nx, ny;
64     int military;
65     int btucost;
66     int i;
67     coord *table;               /* sectors already seen */
68     int t_len = 0;
69     int nrecon;
70     struct nstr_sect nstr;
71     struct nstr_item ni;
72     struct natstr *natp;
73     struct sctstr from;
74     struct sctstr dsect;
75     struct lndstr land;
76     int changed = 0;
77     int nsects;
78
79     /*
80      * first arg should be the range of sectors
81      */
82     if (!snxtsct(&nstr, player->argp[1]))
83         return RET_SYN;
84     nsects = (nstr.range.width + 1) * nstr.range.height / 2;
85     btucost = (nsects / 40) + 1;
86     natp = getnatp(player->cnum);
87     if (natp->nat_btu < btucost) {
88         pr("You don't have the BTU's for spying on that scale!\n");
89         return RET_FAIL;
90     }
91     /*
92      * set up all the goodies we need later
93      * 6 = neighbors, 2 = x,y
94      */
95     table = malloc((nsects + 1) * 6 * 2 * sizeof(coord));
96     memset(table, 0, (nsects + 1) * 6 * 2 * sizeof(coord));
97     pr("SPY report\n");
98     prdate();
99     pr("                 old sct rd  rl  def\n");
100     pr("   sect   de own own eff eff eff eff  civ  mil  shl gun  pet food bars\n");
101     while (nxtsct(&nstr, &from)) {
102         if (!player->owner && !player->god)
103             continue;
104         military = from.sct_item[I_MILIT];
105         if (military == 0)
106             continue;
107         x = from.sct_x;
108         y = from.sct_y;
109         nrecon = 0;
110         snxtitem_xy(&ni, EF_LAND, x, y);
111         while (nxtitem(&ni, &land)) {
112             if (lchr[(int)land.lnd_type].l_flags & L_RECON)
113                 nrecon++;
114         }
115         /* Print out the units/planes in this sector */
116         prunits(x, y);
117         prplanes(x, y);
118         /*
119          * check the neighboring sectors.
120          */
121         for (i = 1; i <= 6; i++) {
122             if (military == 0)
123                 break;
124             nx = x + diroff[i][0];
125             ny = y + diroff[i][1];
126             /*
127              * if we've already seen the
128              * sector, don't bother checking it
129              * out.
130              */
131             if (check(table, &t_len, nx, ny)) {
132                 continue;
133             }
134             getsect(nx, ny, &dsect);
135             if (player->owner || dsect.sct_type == SCT_WATER)
136                 continue;
137
138             own = dsect.sct_own;
139             relat = getrel(getnatp(own), player->cnum);
140             if (relat <= NEUTRAL
141                 && chance(dsect.sct_item[I_MILIT] / 200.0)) {
142                 /* spy caught */
143                 if (relat == NEUTRAL) {
144                     /* deport spy */
145                     pr("Spy deported from %s\n",
146                        xyas(nx, ny, player->cnum));
147                     if (own != 0)
148                         wu(0, own, "%s (#%d) spy deported from %s\n",
149                            cname(player->cnum), player->cnum,
150                            xyas(nx, ny, own));
151                 } else {
152                     /* execute spy */
153                     pr("BANG!! A spy was shot in %s\n",
154                        xyas(nx, ny, player->cnum));
155                     military--;
156                     if (own != 0)
157                         wu(0, own, "%s (#%d) spy caught in %s\n",
158                            cname(player->cnum), player->cnum,
159                            xyas(nx, ny, own));
160                 }
161                 if (opt_HIDDEN)
162                     setcont(own, player->cnum, FOUND_SPY);
163                 if (!nrecon)    /* unless you have a recon unit */
164                     continue;   /* no report from caught spy */
165             }
166
167             /* spy report */
168             insert(table, &t_len, nx, ny);
169             spy_report(&dsect);
170             changed += map_set(player->cnum, dsect.sct_x, dsect.sct_y,
171                                dchr[dsect.sct_type].d_mnem, 0);
172             if (opt_HIDDEN)
173                 setcont(player->cnum, own, FOUND_SPY);
174         }
175         /* subtract any military if necessary */
176         if (from.sct_item[I_MILIT] != military) {
177             from.sct_item[I_MILIT] = military;
178             putsect(&from);
179         }
180     }
181     if (changed)
182         writemap(player->cnum);
183     player->btused += btucost;
184     free(table);
185     return RET_OK;
186 }
187
188 static void
189 spy_report(struct sctstr *sp)
190 {
191     prxy("%4d,%-4d", sp->sct_x, sp->sct_y, player->cnum);
192     pr(" %c%c %3d %3d %3d %3d %3d %3d %4d %4d %4d %3d %4d %4d %4d\n",
193        dchr[sp->sct_type].d_mnem,
194        sp->sct_newtype == sp->sct_type ? ' ' : dchr[sp->sct_newtype].d_mnem,
195        sp->sct_own,
196        sp->sct_oldown,
197        roundintby((int)sp->sct_effic, 10),
198        roundintby((int)sp->sct_road, 10),
199        roundintby((int)sp->sct_rail, 10),
200        roundintby((int)sp->sct_defense, 10),
201        roundintby(sp->sct_item[I_CIVIL], 10),
202        roundintby(sp->sct_item[I_MILIT], 10),
203        roundintby(sp->sct_item[I_SHELL], 10),
204        roundintby(sp->sct_item[I_GUN], 10),
205        roundintby(sp->sct_item[I_PETROL], 10),
206        roundintby(sp->sct_item[I_FOOD], 10),
207        roundintby(sp->sct_item[I_BAR], 10));
208     prunits(sp->sct_x, sp->sct_y);
209     prplanes(sp->sct_x, sp->sct_y);
210 }
211
212 /*
213  * insert a key into the table.
214  */
215 static void
216 insert(coord *table, int *len, coord x, coord y)
217 {
218     if (!check(table, len, x, y)) {
219         table[(*len)++] = x;
220         table[(*len)++] = y;
221     }
222 }
223
224 /*
225  * see if a key is in the bitmask table
226  */
227 static int
228 check(coord *table, int *len, coord x, coord y)
229 {
230     int i;
231
232     for (i = 0; i < *len; i += 2)
233         if (table[i] == x && table[i + 1] == y)
234             return 1;
235     return 0;
236 }
237
238 static void
239 prunits(int x, int y)
240 {
241     struct lndstr land;
242     struct nstr_item ni;
243     char report[128];
244
245     snxtitem_xy(&ni, EF_LAND, x, y);
246     while (nxtitem(&ni, &land)) {
247         if (land.lnd_own == player->cnum || land.lnd_own == 0)
248             continue;
249         if (land.lnd_ship >= 0 || land.lnd_land >= 0)
250             continue;
251         /* Don't always see spies */
252         if (lchr[(int)land.lnd_type].l_flags & L_SPY) {
253             if (!(chance(LND_SPY_DETECT_CHANCE(land.lnd_effic))))
254                 continue;
255         }
256         sprintf(report, "%s (%s) unit in %s: ",
257                 player_relstr(land.lnd_own),
258                 cname(land.lnd_own),
259                 xyas(land.lnd_x, land.lnd_y, player->cnum));
260         intelligence_report(player->cnum, &land, 3, report);
261     }
262 }
263
264 static void
265 prplanes(int x, int y)
266 {
267     struct plnstr plane;
268     struct nstr_item ni;
269
270     snxtitem_xy(&ni, EF_PLANE, x, y);
271     while (nxtitem(&ni, &plane)) {
272         if (plane.pln_own == player->cnum || plane.pln_own == 0)
273             continue;
274         if (plane.pln_ship >= 0 || plane.pln_land >= 0)
275             continue;
276         if (plane.pln_flags & PLN_LAUNCHED)
277             continue;
278         pr("%s (%s) plane in %s: %s\n",
279            player_relstr(plane.pln_own),
280            cname(plane.pln_own),
281            xyas(plane.pln_x, plane.pln_y, player->cnum),
282            prplane(&plane));
283     }
284 }
285
286 static char *
287 player_relstr(natid them)
288 {
289     int rel = getrel(getnatp(player->cnum), them);
290
291     if (rel == ALLIED)
292         return "Allied";
293     if (rel >= NEUTRAL)
294         return "Neutral";
295     return "Enemy";
296 }