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