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