ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/los.c
Revision: 1.2
Committed: Sun Aug 13 17:16:00 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +1 -1 lines
State: FILE REMOVED
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# Content
1 /*
2 * static char *rcsid_los_c =
3 * "$Id$";
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 }