ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/los.C
Revision: 1.4
Committed: Sun Sep 10 16:00:23 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +448 -385 lines
Log Message:
indent

File Contents

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