ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/los.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:11:36 2006 UTC (18 years, 3 months ago) by root
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_02_03
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

# User Rev Content
1 root 1.1 /*
2     * static char *rcsid_los_c =
3     * "$Id: los.c,v 1.16 2005/12/05 23:34:03 akirschbaum Exp $";
4     */
5    
6     /*
7     CrossFire, A Multiplayer game for X-windows
8    
9     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10     Copyright (C) 1992 Frank Tore Johansen
11    
12     This program is free software; you can redistribute it and/or modify
13     it under the terms of the GNU General Public License as published by
14     the Free Software Foundation; either version 2 of the License, or
15     (at your option) any later version.
16    
17     This program is distributed in the hope that it will be useful,
18     but WITHOUT ANY WARRANTY; without even the implied warranty of
19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20     GNU General Public License for more details.
21    
22     You should have received a copy of the GNU General Public License
23     along with this program; if not, write to the Free Software
24     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25    
26     The authors can be reached via e-mail at crossfire-devel@real-time.com
27     */
28    
29     /* Nov 95 - inserted USE_LIGHTING code stuff in here - b.t. */
30    
31     #include <global.h>
32     #include <funcpoint.h>
33     #include <math.h>
34    
35    
36     /* Distance must be less than this for the object to be blocked.
37     * An object is 1.0 wide, so if set to 0.5, it means the object
38     * that blocks half the view (0.0 is complete block) will
39     * block view in our tables.
40     * .4 or less lets you see through walls. .5 is about right.
41     */
42    
43     #define SPACE_BLOCK 0.5
44    
45     typedef struct blstr {
46     int x[4],y[4];
47     int index;
48     } blocks;
49    
50     blocks block[MAP_CLIENT_X][MAP_CLIENT_Y];
51    
52     /*
53     * Used to initialise the array used by the LOS routines.
54     * What this sets if that x,y blocks the view of bx,by
55     * This then sets up a relation - for example, something
56     * at 5,4 blocks view at 5,3 which blocks view at 5,2
57     * etc. So when we check 5,4 and find it block, we have
58     * the data to know that 5,3 and 5,2 and 5,1 should also
59     * be blocked.
60     */
61    
62     void set_block(int x,int y,int bx, int by) {
63     int index=block[x][y].index,i;
64    
65     /* Due to flipping, we may get duplicates - better safe than sorry.
66     */
67     for (i=0; i<index; i++) {
68     if (block[x][y].x[i] == bx && block[x][y].y[i] == by) return;
69     }
70    
71     block[x][y].x[index]=bx;
72     block[x][y].y[index]=by;
73     block[x][y].index++;
74     #ifdef LOS_DEBUG
75     LOG(llevDebug, "setblock: added %d %d -> %d %d (%d)\n", x, y, bx, by,
76     block[x][y].index);
77     #endif
78     }
79    
80     /*
81     * initialises the array used by the LOS routines.
82     */
83    
84     /* since we are only doing the upper left quadrant, only
85     * these spaces could possibly get blocked, since these
86     * are the only ones further out that are still possibly in the
87     * sightline.
88     */
89    
90     void init_block(void) {
91     int x,y, dx, dy, i;
92     static int block_x[3] = {-1, -1, 0}, block_y[3] = {-1, 0, -1};
93    
94     for(x=0;x<MAP_CLIENT_X;x++)
95     for(y=0;y<MAP_CLIENT_Y;y++) {
96     block[x][y].index=0;
97     }
98    
99    
100     /* The table should be symmetric, so only do the upper left
101     * quadrant - makes the processing easier.
102     */
103     for (x=1; x<=MAP_CLIENT_X/2; x++) {
104     for (y=1; y<=MAP_CLIENT_Y/2; y++) {
105     for (i=0; i< 3; i++) {
106     dx = x + block_x[i];
107     dy = y + block_y[i];
108    
109     /* center space never blocks */
110     if (x == MAP_CLIENT_X/2 && y == MAP_CLIENT_Y/2) continue;
111    
112     /* If its a straight line, its blocked */
113     if ((dx == x && x == MAP_CLIENT_X/2) ||
114     (dy==y && y == MAP_CLIENT_Y/2)) {
115     /* For simplicity, we mirror the coordinates to block the other
116     * quadrants.
117     */
118     set_block(x, y, dx, dy);
119     if (x == MAP_CLIENT_X/2) {
120     set_block(x, MAP_CLIENT_Y - y -1, dx, MAP_CLIENT_Y - dy-1);
121     } else if (y == MAP_CLIENT_Y/2) {
122     set_block(MAP_CLIENT_X - x -1, y, MAP_CLIENT_X - dx - 1, dy);
123     }
124     } else {
125     float d1, r, s,l;
126    
127     /* We use the algorihm that found out how close the point
128     * (x,y) is to the line from dx,dy to the center of the viewable
129     * area. l is the distance from x,y to the line.
130     * r is more a curiosity - it lets us know what direction (left/right)
131     * the line is off
132     */
133    
134     d1 = (float) (pow(MAP_CLIENT_X/2 - dx, 2) + pow(MAP_CLIENT_Y/2 - dy,2));
135     r = (float)((dy-y)*(dy - MAP_CLIENT_Y/2) - (dx-x)*(MAP_CLIENT_X/2-dx))/d1;
136     s = (float)((dy-y)*(MAP_CLIENT_X/2 - dx ) - (dx-x)*(MAP_CLIENT_Y/2-dy))/d1;
137     l = FABS(sqrt(d1) * s);
138    
139     if (l <= SPACE_BLOCK) {
140     /* For simplicity, we mirror the coordinates to block the other
141     * quadrants.
142     */
143     set_block(x,y,dx,dy);
144     set_block(MAP_CLIENT_X - x -1, y, MAP_CLIENT_X - dx - 1, dy);
145     set_block(x, MAP_CLIENT_Y - y -1, dx, MAP_CLIENT_Y - dy - 1);
146     set_block(MAP_CLIENT_X -x-1, MAP_CLIENT_Y -y-1, MAP_CLIENT_X - dx-1, MAP_CLIENT_Y - dy-1);
147     }
148     }
149     }
150     }
151     }
152     }
153    
154     /*
155     * Used to initialise the array used by the LOS routines.
156     * x,y are indexes into the blocked[][] array.
157     * This recursively sets the blocked line of sight view.
158     * From the blocked[][] array, we know for example
159     * that if some particular space is blocked, it blocks
160     * the view of the spaces 'behind' it, and those blocked
161     * spaces behind it may block other spaces, etc.
162     * In this way, the chain of visibility is set.
163     */
164    
165     static void set_wall(object *op,int x,int y) {
166     int i;
167    
168     for(i=0;i<block[x][y].index;i++) {
169     int dx=block[x][y].x[i],dy=block[x][y].y[i],ax,ay;
170    
171     /* ax, ay are the values as adjusted to be in the
172     * socket look structure.
173     */
174     ax = dx - (MAP_CLIENT_X - op->contr->socket.mapx)/2;
175     ay = dy - (MAP_CLIENT_Y - op->contr->socket.mapy)/2;
176    
177     if (ax < 0 || ax>=op->contr->socket.mapx ||
178     ay < 0 || ay>=op->contr->socket.mapy) continue;
179     #if 0
180     LOG(llevDebug, "blocked %d %d -> %d %d\n",
181     dx, dy, ax, ay);
182     #endif
183     /* we need to adjust to the fact that the socket
184     * code wants the los to start from the 0,0
185     * and not be relative to middle of los array.
186     */
187     op->contr->blocked_los[ax][ay]=100;
188     set_wall(op,dx,dy);
189     }
190     }
191    
192     /*
193     * Used to initialise the array used by the LOS routines.
194     * op is the object, x and y values based on MAP_CLIENT_X and Y.
195     * this is because they index the blocked[][] arrays.
196     */
197    
198     static void check_wall(object *op,int x,int y) {
199     int ax, ay;
200    
201     if(!block[x][y].index)
202     return;
203    
204     /* ax, ay are coordinates as indexed into the look window */
205     ax = x - (MAP_CLIENT_X - op->contr->socket.mapx)/2;
206     ay = y - (MAP_CLIENT_Y - op->contr->socket.mapy)/2;
207    
208     /* If the converted coordinates are outside the viewable
209     * area for the client, return now.
210     */
211     if (ax < 0 || ay < 0 || ax >= op->contr->socket.mapx || ay >= op->contr->socket.mapy)
212     return;
213    
214     #if 0
215     LOG(llevDebug, "check_wall, ax,ay=%d, %d x,y = %d, %d blocksview = %d, %d\n",
216     ax, ay, x, y, op->x + x - MAP_CLIENT_X/2, op->y + y - MAP_CLIENT_Y/2);
217     #endif
218    
219     /* If this space is already blocked, prune the processing - presumably
220     * whatever has set this space to be blocked has done the work and already
221     * done the dependency chain.
222     */
223     if (op->contr->blocked_los[ax][ay] == 100) return;
224    
225    
226     if(get_map_flags(op->map, NULL,
227     op->x + x - MAP_CLIENT_X/2, op->y + y - MAP_CLIENT_Y/2,
228     NULL, NULL) & (P_BLOCKSVIEW | P_OUT_OF_MAP))
229     set_wall(op,x,y);
230     }
231    
232     /*
233     * Clears/initialises the los-array associated to the player
234     * controlling the object.
235     */
236    
237     void clear_los(object *op) {
238     /* This is safer than using the socket->mapx, mapy because
239     * we index the blocked_los as a 2 way array, so clearing
240     * the first z spaces may not not cover the spaces we are
241     * actually going to use
242     */
243     (void)memset((void *) op->contr->blocked_los,0,
244     MAP_CLIENT_X * MAP_CLIENT_Y);
245     }
246    
247     /*
248     * expand_sight goes through the array of what the given player is
249     * able to see, and expands the visible area a bit, so the player will,
250     * to a certain degree, be able to see into corners.
251     * This is somewhat suboptimal, would be better to improve the formula.
252     */
253    
254     void expand_sight(object *op)
255     {
256     int i,x,y, dx, dy;
257    
258     for(x=1;x<op->contr->socket.mapx-1;x++) /* loop over inner squares */
259     for(y=1;y<op->contr->socket.mapy-1;y++) {
260     if (!op->contr->blocked_los[x][y] &&
261     !(get_map_flags(op->map,NULL,
262     op->x-op->contr->socket.mapx/2+x,
263     op->y-op->contr->socket.mapy/2+y,
264     NULL, NULL) & (P_BLOCKSVIEW | P_OUT_OF_MAP))) {
265    
266     for(i=1;i<=8;i+=1) { /* mark all directions */
267     dx = x + freearr_x[i];
268     dy = y + freearr_y[i];
269     if(op->contr->blocked_los[dx][dy] > 0) /* for any square blocked */
270     op->contr->blocked_los[dx][dy]= -1;
271     }
272     }
273     }
274    
275     if(MAP_DARKNESS(op->map)>0) /* player is on a dark map */
276     expand_lighted_sight(op);
277    
278    
279     /* clear mark squares */
280     for (x = 0; x < op->contr->socket.mapx; x++)
281     for (y = 0; y < op->contr->socket.mapy; y++)
282     if (op->contr->blocked_los[x][y] < 0)
283     op->contr->blocked_los[x][y] = 0;
284     }
285    
286    
287    
288    
289     /* returns true if op carries one or more lights
290     * This is a trivial function now days, but it used to
291     * be a bit longer. Probably better for callers to just
292     * check the op->glow_radius instead of calling this.
293     */
294    
295     int has_carried_lights(object *op) {
296     /* op may glow! */
297     if(op->glow_radius>0) return 1;
298    
299     return 0;
300     }
301    
302     void expand_lighted_sight(object *op)
303     {
304     int x,y,darklevel,ax,ay, basex, basey, mflags, light, x1, y1;
305     mapstruct *m=op->map;
306     sint16 nx, ny;
307    
308     darklevel = MAP_DARKNESS(m);
309    
310     /* If the player can see in the dark, lower the darklevel for him */
311     if(QUERY_FLAG(op,FLAG_SEE_IN_DARK)) darklevel -= 2;
312    
313     /* add light, by finding all (non-null) nearby light sources, then
314     * mark those squares specially. If the darklevel<1, there is no
315     * reason to do this, so we skip this function
316     */
317    
318     if(darklevel<1) return;
319    
320     /* Do a sanity check. If not valid, some code below may do odd
321     * things.
322     */
323     if (darklevel > MAX_DARKNESS) {
324     LOG(llevError,"Map darkness for %s on %s is too high (%d)\n",
325     op->name, op->map->path, darklevel);
326     darklevel = MAX_DARKNESS;
327     }
328    
329     /* First, limit player furthest (unlighted) vision */
330     for (x = 0; x < op->contr->socket.mapx; x++)
331     for (y = 0; y < op->contr->socket.mapy; y++)
332     if(op->contr->blocked_los[x][y]!=100)
333     op->contr->blocked_los[x][y]= MAX_LIGHT_RADII;
334    
335     /* the spaces[] darkness value contains the information we need.
336     * Only process the area of interest.
337     * the basex, basey values represent the position in the op->contr->blocked_los
338     * array. Its easier to just increment them here (and start with the right
339     * value) than to recalculate them down below.
340     */
341     for (x=(op->x - op->contr->socket.mapx/2 - MAX_LIGHT_RADII), basex=-MAX_LIGHT_RADII;
342     x <= (op->x + op->contr->socket.mapx/2 + MAX_LIGHT_RADII); x++, basex++) {
343    
344     for (y=(op->y - op->contr->socket.mapy/2 - MAX_LIGHT_RADII), basey=-MAX_LIGHT_RADII;
345     y <= (op->y + op->contr->socket.mapy/2 + MAX_LIGHT_RADII); y++, basey++) {
346     m = op->map;
347     nx = x;
348     ny = y;
349    
350     mflags = get_map_flags(m, &m, nx, ny, &nx, &ny);
351    
352     if (mflags & P_OUT_OF_MAP) continue;
353    
354     /* This space is providing light, so we need to brighten up the
355     * spaces around here.
356     */
357     light = GET_MAP_LIGHT(m, nx, ny);
358     if (light != 0) {
359     #if 0
360     LOG(llevDebug, "expand_lighted_sight: Found light at x=%d, y=%d, basex=%d, basey=%d\n",
361     x, y, basex, basey);
362     #endif
363     for (ax=basex - light; ax<=basex+light; ax++) {
364     if (ax<0 || ax>=op->contr->socket.mapx) continue;
365     for (ay=basey - light; ay<=basey+light; ay++) {
366     if (ay<0 || ay>=op->contr->socket.mapy) continue;
367    
368     /* If the space is fully blocked, do nothing. Otherwise, we
369     * brighten the space. The further the light is away from the
370     * source (basex-x), the less effect it has. Though light used
371     * to dim in a square manner, it now dims in a circular manner
372     * using the the pythagorean theorem. glow_radius still
373     * represents the radius
374     */
375     if(op->contr->blocked_los[ax][ay]!=100) {
376     x1 = abs(basex-ax)*abs(basex-ax);
377     y1 = abs(basey-ay)*abs(basey-ay);
378     if (light > 0) op->contr->blocked_los[ax][ay]-= MAX((light - isqrt(x1 + y1)), 0);
379     if (light < 0) op->contr->blocked_los[ax][ay]-= MIN((light + isqrt(x1 + y1)), 0);
380     }
381     } /* for ay */
382     } /* for ax */
383     } /* if this space is providing light */
384     } /* for y */
385     } /* for x */
386    
387     /* Outdoor should never really be completely pitch black dark like
388     * a dungeon, so let the player at least see a little around themselves
389     */
390     if (op->map->outdoor && darklevel > (MAX_DARKNESS - 3)) {
391     if (op->contr->blocked_los[op->contr->socket.mapx/2][op->contr->socket.mapy/2] > (MAX_DARKNESS-3))
392     op->contr->blocked_los[op->contr->socket.mapx/2][op->contr->socket.mapy/2] = MAX_DARKNESS - 3;
393    
394     for (x=-1; x<=1; x++)
395     for (y=-1; y<=1; y++) {
396     if (op->contr->blocked_los[x + op->contr->socket.mapx/2][y + op->contr->socket.mapy/2] > (MAX_DARKNESS-2))
397     op->contr->blocked_los[x + op->contr->socket.mapx/2][y + op->contr->socket.mapy/2] = MAX_DARKNESS - 2;
398     }
399     }
400     /* grant some vision to the player, based on the darklevel */
401     for(x=darklevel-MAX_DARKNESS; x<MAX_DARKNESS + 1 -darklevel; x++)
402     for(y=darklevel-MAX_DARKNESS; y<MAX_DARKNESS + 1 -darklevel; y++)
403     if(!(op->contr->blocked_los[x+op->contr->socket.mapx/2][y+op->contr->socket.mapy/2]==100))
404     op->contr->blocked_los[x+op->contr->socket.mapx/2][y+op->contr->socket.mapy/2]-=
405     MAX(0,6 -darklevel - MAX(abs(x),abs(y)));
406     }
407    
408     /* blinded_sight() - sets all veiwable squares to blocked except
409     * for the one the central one that the player occupies. A little
410     * odd that you can see yourself (and what your standing on), but
411     * really need for any reasonable game play.
412     */
413    
414     void blinded_sight (object *op) {
415     int x,y;
416    
417     for (x = 0; x < op->contr->socket.mapx; x++)
418     for (y = 0; y < op->contr->socket.mapy; y++)
419     op->contr->blocked_los[x][y] = 100;
420    
421     op->contr->blocked_los[ op->contr->socket.mapx/2][ op->contr->socket.mapy/2] = 0;
422     }
423    
424     /*
425     * update_los() recalculates the array which specifies what is
426     * visible for the given player-object.
427     */
428    
429     void update_los(object *op) {
430     int dx = op->contr->socket.mapx/2, dy = op->contr->socket.mapy/2, x, y;
431    
432     if(QUERY_FLAG(op,FLAG_REMOVED))
433     return;
434    
435     clear_los(op);
436     if(QUERY_FLAG(op,FLAG_WIZ) /* ||XRAYS(op) */)
437     return;
438    
439     /* For larger maps, this is more efficient than the old way which
440     * used the chaining of the block array. Since many space views could
441     * be blocked by different spaces in front, this mean that a lot of spaces
442     * could be examined multile times, as each path would be looked at.
443     */
444     for (x=(MAP_CLIENT_X - op->contr->socket.mapx)/2 - 1; x<(MAP_CLIENT_X + op->contr->socket.mapx)/2 + 1; x++)
445     for (y=(MAP_CLIENT_Y - op->contr->socket.mapy)/2 - 1; y<(MAP_CLIENT_Y + op->contr->socket.mapy)/2 + 1; y++)
446     check_wall(op, x, y);
447    
448    
449     /* do the los of the player. 3 (potential) cases */
450     if(QUERY_FLAG(op,FLAG_BLIND)) /* player is blind */
451     blinded_sight(op);
452     else
453     expand_sight(op);
454    
455     if (QUERY_FLAG(op,FLAG_XRAYS)) {
456     int x, y;
457     for (x = -2; x <= 2; x++)
458     for (y = -2; y <= 2; y++)
459     op->contr->blocked_los[dx + x][dy + y] = 0;
460     }
461     }
462    
463     /* update all_map_los is like update_all_los below,
464     * but updates everyone on the map, no matter where they
465     * are. This generally should not be used, as a per
466     * specific map change doesn't make much sense when tiling
467     * is considered (lowering darkness would certainly be a
468     * strange effect if done on a tile map, as it makes
469     * the distinction between maps much more obvious to the
470     * players, which is should not be.
471     * Currently, this function is called from the
472     * change_map_light function
473     */
474     void update_all_map_los(mapstruct *map) {
475     player *pl;
476    
477     for(pl=first_player;pl!=NULL;pl=pl->next) {
478     if(pl->ob->map==map)
479     pl->do_los=1;
480     }
481     }
482    
483    
484     /*
485     * This function makes sure that update_los() will be called for all
486     * players on the given map within the next frame.
487     * It is triggered by removal or inserting of objects which blocks
488     * the sight in the map.
489     * Modified by MSW 2001-07-12 to take a coordinate of the changed
490     * position, and to also take map tiling into account. This change
491     * means that just being on the same map is not sufficient - the
492     * space that changes must be withing your viewable area.
493     *
494     * map is the map that changed, x and y are the coordinates.
495     */
496    
497     void update_all_los(mapstruct *map, int x, int y) {
498     player *pl;
499    
500     for(pl=first_player;pl!=NULL;pl=pl->next) {
501     /* Player should not have a null map, but do this
502     * check as a safety
503     */
504     if (!pl->ob->map) continue;
505    
506     /* Same map is simple case - see if pl is close enough.
507     * Note in all cases, we did the check for same map first,
508     * and then see if the player is close enough and update
509     * los if that is the case. If the player is on the
510     * corresponding map, but not close enough, then the
511     * player can't be on another map that may be closer,
512     * so by setting it up this way, we trim processing
513     * some.
514     */
515     if(pl->ob->map==map) {
516     if ((abs(pl->ob->x - x) <= pl->socket.mapx/2) &&
517     (abs(pl->ob->y - y) <= pl->socket.mapy/2))
518     pl->do_los=1;
519     }
520     /* Now we check to see if player is on adjacent
521     * maps to the one that changed and also within
522     * view. The tile_maps[] could be null, but in that
523     * case it should never match the pl->ob->map, so
524     * we want ever try to dereference any of the data in it.
525     */
526    
527     /* The logic for 0 and 3 is to see how far the player is
528     * from the edge of the map (height/width) - pl->ob->(x,y)
529     * and to add current position on this map - that gives a
530     * distance.
531     * For 1 and 2, we check to see how far the given
532     * coordinate (x,y) is from the corresponding edge,
533     * and then add the players location, which gives
534     * a distance.
535     */
536     else if (pl->ob->map == map->tile_map[0]) {
537     if ((abs(pl->ob->x - x) <= pl->socket.mapx/2) &&
538     (abs(y + MAP_HEIGHT(map->tile_map[0]) - pl->ob->y) <= pl->socket.mapy/2))
539     pl->do_los=1;
540     }
541     else if (pl->ob->map == map->tile_map[2]) {
542     if ((abs(pl->ob->x - x) <= pl->socket.mapx/2) &&
543     (abs(pl->ob->y + MAP_HEIGHT(map) - y) <= pl->socket.mapy/2))
544     pl->do_los=1;
545     }
546     else if (pl->ob->map == map->tile_map[1]) {
547     if ((abs(pl->ob->x + MAP_WIDTH(map) - x) <= pl->socket.mapx/2) &&
548     (abs(pl->ob->y - y) <= pl->socket.mapy/2))
549     pl->do_los=1;
550     }
551     else if (pl->ob->map == map->tile_map[3]) {
552     if ((abs(x + MAP_WIDTH(map->tile_map[3]) - pl->ob->x) <= pl->socket.mapx/2) &&
553     (abs(pl->ob->y - y) <= pl->socket.mapy/2))
554     pl->do_los=1;
555     }
556     }
557     }
558    
559     /*
560     * Debug-routine which dumps the array which specifies the visible
561     * area of a player. Triggered by the z key in DM mode.
562     */
563    
564     void print_los(object *op) {
565     int x,y;
566     char buf[50], buf2[10];
567    
568     strcpy(buf," ");
569     for(x=0;x<op->contr->socket.mapx;x++) {
570     sprintf(buf2,"%2d",x);
571     strcat(buf,buf2);
572     }
573     new_draw_info(NDI_UNIQUE, 0, op, buf);
574     for(y=0;y<op->contr->socket.mapy;y++) {
575     sprintf(buf,"%2d:",y);
576     for(x=0;x<op->contr->socket.mapx;x++) {
577     sprintf(buf2," %1d",op->contr->blocked_los[x][y]);
578     strcat(buf,buf2);
579     }
580     new_draw_info(NDI_UNIQUE, 0, op, buf);
581     }
582     }
583    
584     /*
585     * make_sure_seen: The object is supposed to be visible through walls, thus
586     * check if any players are nearby, and edit their LOS array.
587     */
588    
589     void make_sure_seen(object *op) {
590     player *pl;
591    
592     for (pl = first_player; pl; pl = pl->next)
593     if (pl->ob->map == op->map &&
594     pl->ob->y - pl->socket.mapy/2 <= op->y &&
595     pl->ob->y + pl->socket.mapy/2 >= op->y &&
596     pl->ob->x - pl->socket.mapx/2 <= op->x &&
597     pl->ob->x + pl->socket.mapx/2 >= op->x)
598     pl->blocked_los[pl->socket.mapx/2 + op->x - pl->ob->x]
599     [pl->socket.mapy/2 + op->y - pl->ob->y] = 0;
600     }
601    
602     /*
603     * make_sure_not_seen: The object which is supposed to be visible through
604     * walls has just been removed from the map, so update the los of any
605     * players within its range
606     */
607    
608     void make_sure_not_seen(object *op) {
609     player *pl;
610     for (pl = first_player; pl; pl = pl->next)
611     if (pl->ob->map == op->map &&
612     pl->ob->y - pl->socket.mapy/2 <= op->y &&
613     pl->ob->y + pl->socket.mapy/2 >= op->y &&
614     pl->ob->x - pl->socket.mapx/2 <= op->x &&
615     pl->ob->x + pl->socket.mapx/2 >= op->x)
616     pl->do_los = 1;
617     }