]> git.pond.sub.org Git - empserver/blob - src/lib/commands/look.c
Update copyright notice.
[empserver] / src / lib / commands / look.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  *  look.c: Lookout from a ship or land unit
29  * 
30  *  Known contributors to this file:
31  *     
32  */
33
34 #include <config.h>
35
36 #include "commands.h"
37 #include "land.h"
38 #include "map.h"
39 #include "optlist.h"
40 #include "path.h"
41 #include "plane.h"
42 #include "ship.h"
43
44 static void look_ship(struct shpstr *lookship);
45 static void look_land(struct lndstr *lookland);
46
47 int
48 look(void)
49 {
50     int i;
51     struct nstr_item ni;
52     struct shpstr myship;
53     struct sctstr sect;
54     int x, y;
55     int civ;
56     int mil;
57     unsigned char *bitmap;
58     int changed = 0;
59
60     if (!snxtitem(&ni, EF_SHIP, player->argp[1]))
61         return RET_SYN;
62     if ((bitmap = malloc((WORLD_X * WORLD_Y) / 8)) == 0) {
63         logerror("malloc failed in look\n");
64         pr("Memory error.  Tell the deity.\n");
65         return RET_FAIL;
66     }
67     memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
68     while (nxtitem(&ni, &myship)) {
69         if (!player->owner)
70             continue;
71         look_ship(&myship);
72         for (i = 0; i <= 6; i++) {
73             x = diroff[i][0] + myship.shp_x;
74             y = diroff[i][1] + myship.shp_y;
75             if (emp_getbit(x, y, bitmap))
76                 continue;
77             emp_setbit(x, y, bitmap);
78             getsect(x, y, &sect);
79             if (sect.sct_type == SCT_WATER)
80                 continue;
81             if (player->owner)
82                 pr("Your ");
83             else
84                 pr("%s (#%d) ", cname(sect.sct_own), sect.sct_own);
85             pr("%s", dchr[sect.sct_type].d_name);
86             changed += map_set(player->cnum, x, y,
87                                dchr[sect.sct_type].d_mnem, 0);
88             pr(" %d%% efficient ", player->owner ? sect.sct_effic :
89                roundintby((int)sect.sct_effic, 10));
90             civ = sect.sct_item[I_CIVIL];
91             mil = sect.sct_item[I_MILIT];
92             if (civ)
93                 pr("with %s%d civ ",
94                    player->owner ? "" : "approx ",
95                    player->owner ? civ : roundintby(civ, 10));
96             if (mil)
97                 pr("with %s%d mil ",
98                    player->owner ? "" : "approx ",
99                    player->owner ? mil : roundintby(mil, 10));
100             pr("@ %s\n", xyas(x, y, player->cnum));
101             if (opt_HIDDEN) {
102                 setcont(player->cnum, sect.sct_own, FOUND_LOOK);
103             }
104         }
105     }
106     if (changed)
107         writemap(player->cnum);
108     free(bitmap);
109     return RET_OK;
110 }
111
112 static void
113 look_ship(struct shpstr *lookship)
114 {
115     struct shpstr *sp;
116     struct mchrstr *smcp;
117     struct mchrstr *tmcp;
118     struct sctstr sect;
119     int range;
120     int vrange;
121     int i;
122     int dist;
123
124     range = (int)techfact(lookship->shp_tech,
125                           mchr[(int)lookship->shp_type].m_vrnge);
126     range = range * (lookship->shp_effic / 100.0);
127     smcp = &mchr[(int)lookship->shp_type];
128     if (smcp->m_flags & M_SUB)
129         range = MIN(range, 1);
130     for (i = 0; NULL != (sp = getshipp(i)); i++) {
131         if (sp->shp_own == player->cnum || sp->shp_own == 0)
132             continue;
133         dist = mapdist(sp->shp_x, sp->shp_y,
134                        lookship->shp_x, lookship->shp_y);
135         if (dist > ship_max_interdiction_range)
136             continue;
137         tmcp = &mchr[(int)sp->shp_type];
138         if (smcp->m_flags & M_SUB)
139             vrange = (int)(sp->shp_visib * range / 30.0);
140         else
141             vrange = (int)(sp->shp_visib * range / 20.0);
142         getsect(sp->shp_x, sp->shp_y, &sect);
143         if (sect.sct_type != SCT_WATER)
144             vrange = MAX(1, vrange);
145         if (dist > vrange)
146             continue;
147         if (smcp->m_flags & M_SUB) {
148             if (tmcp->m_flags & M_SONAR && dist < 2) {
149                 if (sp->shp_own != 0)
150                     wu(0, sp->shp_own,
151                        "%s detected surfacing noises in %s.\n",
152                        prship(sp),
153                        xyas(lookship->shp_x, lookship->shp_y,
154                             sp->shp_own));
155             }
156             if (dist == 0 && (tmcp->m_flags & M_SUB) == 0)
157                 if (sp->shp_own != 0)
158                     wu(0, sp->shp_own,
159                        "Periscope spotted in %s by %s\n",
160                        xyas(lookship->shp_x, lookship->shp_y,
161                             sp->shp_own), prship(sp));
162         }
163         /* subs at sea only seen by sonar */
164         if (tmcp->m_flags & M_SUB && sect.sct_type == SCT_WATER)
165             continue;
166         pr("%s (#%d) %s @ %s\n",
167            cname(sp->shp_own), sp->shp_own, prship(sp),
168            xyas(sp->shp_x, sp->shp_y, player->cnum));
169         if (opt_HIDDEN)
170             setcont(player->cnum, sp->shp_own, FOUND_LOOK);
171     }
172 }
173
174 int
175 llook(void)
176 {
177     int i;
178     struct nstr_item ni;
179     struct lndstr myland;
180     struct sctstr sect;
181     int x, y;
182     int civ;
183     int mil;
184     unsigned char *bitmap;
185     int changed = 0;
186
187     if (!snxtitem(&ni, EF_LAND, player->argp[1]))
188         return RET_SYN;
189     if ((bitmap = malloc((WORLD_X * WORLD_Y) / 8)) == 0) {
190         logerror("malloc failed in llook\n");
191         pr("Memory error.  Tell the deity.\n");
192         return RET_FAIL;
193     }
194     memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
195     while (nxtitem(&ni, &myland)) {
196         if (!player->owner)
197             continue;
198         if (myland.lnd_ship >= 0)
199             continue;
200         if (myland.lnd_land >= 0)
201             continue;
202         /* Spies don't need military to do a "llook".  Other
203            units do */
204         if ((myland.lnd_item[I_MILIT] <= 0) &&
205             !(lchr[(int)myland.lnd_type].l_flags & L_SPY))
206             continue;
207         look_land(&myland);
208         for (i = 0; i <= 6; i++) {
209             x = diroff[i][0] + myland.lnd_x;
210             y = diroff[i][1] + myland.lnd_y;
211             if (emp_getbit(x, y, bitmap))
212                 continue;
213             emp_setbit(x, y, bitmap);
214             getsect(x, y, &sect);
215             if (sect.sct_type == SCT_WATER)
216                 continue;
217             if (player->owner)
218                 pr("Your ");
219             else
220                 pr("%s (#%d) ", cname(sect.sct_own), sect.sct_own);
221             pr("%s", dchr[sect.sct_type].d_name);
222             changed += map_set(player->cnum, x, y,
223                                dchr[sect.sct_type].d_mnem, 0);
224             pr(" %d%% efficient ", player->owner ? sect.sct_effic :
225                roundintby((int)sect.sct_effic, 10));
226             civ = sect.sct_item[I_CIVIL];
227             mil = sect.sct_item[I_MILIT];
228             if (civ)
229                 pr("with %s%d civ ", player->owner ? "" :
230                    "approx ", player->owner ? civ : roundintby(civ, 10));
231             if (mil)
232                 pr("with %s%d mil ", player->owner ? "" :
233                    "approx ", player->owner ? mil : roundintby(mil, 10));
234             pr("@ %s\n", xyas(x, y, player->cnum));
235             if (opt_HIDDEN) {
236                 setcont(player->cnum, sect.sct_own, FOUND_LOOK);
237             }
238         }
239     }
240     if (changed)
241         writemap(player->cnum);
242     free(bitmap);
243     return RET_OK;
244 }
245
246 static void
247 look_land(struct lndstr *lookland)
248 {
249     struct plnstr *pp;
250     struct lndstr *lp;
251     double drange;
252     int range;
253     int vrange;
254     int i;
255     int dist;
256
257     drange = techfact(lookland->lnd_tech, lookland->lnd_spy);
258     drange *= lookland->lnd_effic / 100.0;
259     range = ldround(drange, 1);
260
261     if (range == 0)
262         return;
263
264     for (i = 0; NULL != (lp = getlandp(i)); i++) {
265         if (lp->lnd_own == player->cnum || lp->lnd_own == 0)
266             continue;
267         if (lp->lnd_ship >= 0)
268             continue;
269         /* Don't always see spies */
270         if (lchr[(int)lp->lnd_type].l_flags & L_SPY) {
271             /* If it's on a ship or unit, assume it's hidden
272                enough not to be seen */
273             if (lp->lnd_ship >= 0 || lp->lnd_land >= 0)
274                 continue;
275             if (!(chance(LND_SPY_DETECT_CHANCE(lp->lnd_effic))))
276                 continue;
277         }
278         vrange = ldround((lp->lnd_vis * range) / 20.0, 1);
279         dist = mapdist(lp->lnd_x, lp->lnd_y,
280                        lookland->lnd_x, lookland->lnd_y);
281         if (dist > vrange)
282             continue;
283
284         pr("%s (#%d) %s (approx %d mil) @ %s\n",
285            cname(lp->lnd_own), lp->lnd_own,
286            prland(lp), roundintby(lp->lnd_item[I_MILIT], 20),
287            xyas(lp->lnd_x, lp->lnd_y, player->cnum));
288         if (opt_HIDDEN)
289             setcont(player->cnum, lp->lnd_own, FOUND_LOOK);
290     }
291     for (i = 0; NULL != (pp = getplanep(i)); i++) {
292         if (pp->pln_own == player->cnum || pp->pln_own == 0)
293             continue;
294         if (pp->pln_ship >= 0)
295             continue;
296         if (pp->pln_flags & PLN_LAUNCHED)
297             continue;
298         vrange = ldround((10 * range) / 20.0, 1);
299         dist = mapdist(pp->pln_x, pp->pln_y,
300                        lookland->lnd_x, lookland->lnd_y);
301         if (dist > vrange)
302             continue;
303
304         pr("%s (#%d) %s @ %s\n",
305            cname(pp->pln_own), pp->pln_own,
306            prplane(pp), xyas(pp->pln_x, pp->pln_y, player->cnum));
307         if (opt_HIDDEN)
308             setcont(player->cnum, pp->pln_own, FOUND_LOOK);
309     }
310 }