ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/los.C
Revision: 1.2
Committed: Tue Aug 29 08:01:35 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +230 -230 lines
Log Message:
expand initial tabs to spaces

File Contents

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