ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/los.C
Revision: 1.28
Committed: Sun Jul 1 05:00:17 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2, rel-2_3
Changes since 1.27: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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