]> git.pond.sub.org Git - empserver/blob - src/lib/commands/spy.c
Import of Empire 4.2.12
[empserver] / src / lib / commands / spy.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  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 "misc.h"
36 #include "player.h"
37 #include "var.h"
38 #include "sect.h"
39 #include "item.h"
40 #include "nat.h"
41 #include "xy.h"
42 #include "nsc.h"
43 #include "nuke.h"
44 #include "news.h"
45 #include "deity.h"
46 #include "path.h"
47 #include "file.h"
48 #include "land.h"
49 #include "commands.h"
50 #include "optlist.h"
51
52 /*
53  * format:  spy <SECTS>
54  *
55  */
56 static void spyline(struct sctstr *sp);
57 static void insert(coord *table, int *len, coord x, coord y);
58 static int check(coord *table, int *len, coord x, coord y);
59
60 int
61 spy(void)
62 {
63         int     caught;
64         natid   own;
65         int     relat;
66         coord   x, y;
67         coord   nx, ny;
68         int     military;
69         int     savemil;
70         int     btucost;
71         int     i;
72         coord   *table;             /* sectors already seen */
73         int     t_len = 0;
74         int     vec[I_MAX+1];
75         int     dvec[I_MAX+1];
76         int     nrecon;
77         int     nunits;
78         struct nstr_sect nstr;
79         struct nstr_item ni;
80         struct natstr *natp;
81         struct sctstr from;
82         struct sctstr dsect;
83         struct lndstr land;
84         int     changed = 0;
85         int nsects;
86
87         /*
88          * first arg should be the range of sectors
89          */
90         if (!snxtsct(&nstr, player->argp[1]))
91                 return RET_SYN;
92         nsects = (nstr.range.width+1) * nstr.range.height / 2;
93         btucost = (nsects / 40) + 1;
94         natp = getnatp(player->cnum);
95         if (natp->nat_btu < btucost) {
96                 pr("You don't have the BTU's for spying on that scale!\n");
97                 return RET_FAIL;
98         }
99         /*
100          * set up all the goodies we need later
101          * 6 = neighbors, 2 = x,y
102          */
103         table = (coord *) malloc((nsects + 1) * 6 * 2 * sizeof(coord));
104         bzero((s_char *)table, (nsects + 1) * 6 * 2 * sizeof(coord));
105         pr("SPY report\n");
106         prdate();
107 pr("                 old sct rd  rl  def\n");
108 pr("   sect   de own own eff eff eff eff  civ  mil  shl gun  pet food bars lnd pln\n");
109         while (nxtsct(&nstr, &from)) {
110                 if (!player->owner && !player->god)
111                         continue;
112                 getvec(VT_ITEM, vec, (s_char *) &from, EF_SECTOR);
113                 nrecon=0;
114                 nunits=0;
115                 snxtitem_xy(&ni, EF_LAND, from.sct_x, from.sct_y);
116                 while (nxtitem(&ni, (s_char *)&land)){
117                         nunits++;
118                         if (lchr[(int)land.lnd_type].l_flags & L_RECON)
119                                 nrecon++;
120                 }
121                 if ((military = vec[I_MILIT]) == 0 && (nunits == 0))
122                         continue;
123                 x = from.sct_x;
124                 y = from.sct_y;
125                 /* Print out the units/planes in this sector */
126                 prunits(x, y);
127                 prplanes(x, y);
128                 savemil = military;
129                 /*
130                  * check the neighboring sectors.
131                  */
132                 for (i = 1; i <= 6; i++) {
133                         if ((military == 0) && (nunits == 0))
134                                 break;
135                         nx = x + diroff[i][0];
136                         ny = y + diroff[i][1];
137                         /*
138                          * if we've already seen the
139                          * sector, don't bother checking it
140                          * out.
141                          */
142                         if (check(table, &t_len, nx, ny)) {
143                                 continue;
144                         }
145                         getsect(nx, ny, &dsect);
146                         getvec(VT_ITEM, dvec, (s_char *) &dsect, EF_SECTOR);
147                         if (player->owner || (dsect.sct_type == SCT_WATER) ||
148                                 (!dvec[I_MILIT] && !dvec[I_CIVIL] &&
149                                  (num_units(nx, ny) == 0))) {
150                                 /* mark sector as seen */
151                                 insert(table, &t_len, nx, ny);
152                                 continue;
153                         }
154                         /* catch spy N/200 chance, N = # military */
155                         caught = chance((double) dvec[I_MILIT] / 200.0);
156                         own = dsect.sct_own;
157                         /* determine spyee relations with spyer */
158                         relat = getrel(getnatp(own), player->cnum);
159                         if (relat == NEUTRAL && caught) {
160                                 /* neutral spy-ee */
161                                 pr("Spy deported from %s\n", 
162                                         xyas(nx, ny, player->cnum));
163                                 if(own != 0)
164                                 wu(0, own, "%s (#%d) spy deported from %s\n",
165                                         cname(player->cnum), player->cnum,
166                                         xyas(nx, ny, own));
167                         } else if (relat < NEUTRAL && caught) {
168                                 /* at-war with spy-ee */
169                                 pr("BANG!! A spy was shot in %s\n",
170                                        xyas(nx, ny, player->cnum));
171                                 military--;
172                                 if(own != 0)
173                                 wu(0, own, "%s (#%d) spy caught in %s\n",
174                                         cname(player->cnum), player->cnum,
175                                         xyas(nx, ny, own));
176                                 nreport(player->cnum, N_SPY_SHOT, own, 1);
177                         } else {
178                                 insert(table, &t_len, nx, ny);
179                                 spyline(&dsect);
180                                 changed += map_set(player->cnum, dsect.sct_x,
181                                         dsect.sct_y,
182                                         dchr[dsect.sct_type].d_mnem, 0);
183                                 prunits(dsect.sct_x,dsect.sct_y);
184                                 prplanes(dsect.sct_x,dsect.sct_y);
185                                 if (opt_HIDDEN) {
186                                     setcont(player->cnum, own, FOUND_SPY);
187                                 }
188                         }
189                         /*
190                          * If you have a recon unit, it'll
191                          * see the sector anyway...
192                          */
193                         if (nrecon && caught){
194                                 insert(table, &t_len, nx, ny);
195                                 spyline(&dsect);
196                                 changed += map_set(player->cnum, dsect.sct_x,
197                                         dsect.sct_y,
198                                         dchr[dsect.sct_type].d_mnem, 0);
199                                 prunits(dsect.sct_x, dsect.sct_y);
200                                 prplanes(dsect.sct_x,dsect.sct_y);
201                         }
202                 }
203                 /* subtract any military if necessary */
204                 if ((savemil != military) && (savemil > 0)){
205                         if ((military < 0) || (military > savemil))
206                                 military = 0;
207                         vec[I_MILIT] = military;
208                         putvec (VT_ITEM, vec, (s_char *) &from, EF_SECTOR);
209                         putsect(&from);
210                 }
211         }
212         if (changed)
213                 writemap(player->cnum);
214         player->btused += btucost;
215         free((s_char *)table);
216         return RET_OK;
217 }
218
219
220 /*
221  * just a big printf.
222  */
223 static void
224 spyline(struct sctstr *sp)
225 {
226         int vec[I_MAX+1];
227
228         getvec(VT_ITEM, vec, (s_char *) sp, EF_SECTOR);
229         prxy("%4d,%-4d",sp->sct_x, sp->sct_y, player->cnum);
230         pr(" %c%c %3d %3d %3d %3d %3d %3d %4d %4d %4d %3d %4d %4d %4d %3d %3d\n",
231            dchr[sp->sct_type].d_mnem,
232            (sp->sct_newtype == sp->sct_type)?' ':dchr[sp->sct_newtype].d_mnem,
233            sp->sct_own,
234            sp->sct_oldown,
235            roundintby((int)sp->sct_effic, 10),
236            roundintby((int)sp->sct_road, 10),
237            roundintby((int)sp->sct_rail, 10),
238            roundintby((int)sp->sct_defense, 10),
239            roundintby(vec[I_CIVIL], 10), roundintby(vec[I_MILIT], 10),
240            roundintby(vec[I_SHELL], 10), roundintby(vec[I_GUN], 10),
241            roundintby(vec[I_PETROL], 10), roundintby(vec[I_FOOD], 10),
242            roundintby(vec[I_BAR], 10), count_sect_units(sp), count_sect_planes(sp));
243 }
244
245
246 /*
247  * insert a key into the table.
248  */
249 static void
250 insert(coord *table, int *len, coord x, coord y)
251 {
252         if (!check(table, len, x, y)) {
253            table[(*len)++] = x;
254            table[(*len)++] = y;
255         }
256 }
257 /*
258  * see if a key is in the bitmask table
259  */
260 static int
261 check(coord *table, int *len, coord x, coord y)
262 {
263         int     i;
264
265         for (i = 0; i < *len; i += 2)
266            if (table[i] == x && table[i + 1] == y)
267               return 1;
268         return 0;
269 }
270
271 int
272 num_units(int x, int y)
273 {
274     struct      lndstr land;
275     struct      nstr_item ni;
276     int n=0;
277     
278     snxtitem_xy(&ni, EF_LAND, x, y);
279     while (nxtitem(&ni, (s_char *)&land)) {
280         if ((land.lnd_own == player->cnum) || (land.lnd_own == 0))
281             continue;
282         if (land.lnd_ship >= 0 || land.lnd_land >= 0)
283             continue;
284         n++;
285     }
286     
287     return n;
288 }
289
290 void
291 prunits(int x, int y)
292 {
293     struct lndstr land;
294     struct nstr_item ni;
295     s_char      report[128];
296     double odds;
297
298     snxtitem_xy(&ni, EF_LAND, x, y);
299     while (nxtitem(&ni, (s_char *)&land)) {
300         if (land.lnd_own == player->cnum || land.lnd_own == 0)
301             continue;
302         if (land.lnd_ship >= 0 || land.lnd_land >= 0)
303             continue;
304         /* Don't always see spies */
305         if (lchr[(int)land.lnd_type].l_flags & L_SPY) {
306             odds = (double)(100 - land.lnd_effic) + 0.10;
307             if (!(chance(odds)))
308                 continue;
309         }
310         if ((land.lnd_own != player->cnum) && land.lnd_own) {
311             int rel;
312             s_char      *format;
313
314             rel = getrel(getnatp(player->cnum),land.lnd_own);
315             if (rel == ALLIED)
316                 format = "Allied (%s) unit in %s: ";
317             else if (rel == FRIENDLY || rel == NEUTRAL)
318                 format = "Neutral (%s) unit in %s: ";
319             else
320                 format = "Enemy (%s) unit in %s: ";
321             sprintf(report, format, cname(land.lnd_own),
322                     xyas(land.lnd_x, land.lnd_y,player->cnum));
323             intelligence_report(player->cnum, &land, 3, report);
324         }
325     }
326 }
327
328 void
329 prplanes(int x, int y)
330 {
331     struct plnstr plane;
332     struct nstr_item ni;
333     s_char      report[128];
334
335     snxtitem_xy(&ni, EF_PLANE, x, y);
336     while (nxtitem(&ni, (s_char *)&plane)) {
337         if (plane.pln_own == player->cnum || plane.pln_own == 0)
338             continue;
339         if (plane.pln_ship >= 0 || plane.pln_land >= 0)
340             continue;
341         if (plane.pln_flags & PLN_LAUNCHED)
342             continue;
343         if ((plane.pln_own != player->cnum) && plane.pln_own) {
344             int rel;
345             s_char      *format;
346
347             rel = getrel(getnatp(player->cnum),plane.pln_own);
348             if (rel == ALLIED)
349                 format = "Allied (%s) plane in %s: %s\n";
350             else if (rel == FRIENDLY || rel == NEUTRAL)
351                 format = "Neutral (%s) plane in %s: %s\n";
352             else
353                 format = "Enemy (%s) plane in %s: %s\n";
354             sprintf(report, format, cname(plane.pln_own),
355                     xyas(plane.pln_x, plane.pln_y,player->cnum),
356                     prplane(&plane));
357             pr(report);
358         }
359     }
360 }
361