Atrinik Server 2.5
server/los.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 #include <math.h>
00032 
00039 #define SPACE_BLOCK 0.5
00040 
00041 typedef struct blstr
00042 {
00043     int x[4], y[4];
00044     int index;
00045 } blocks;
00046 
00047 static blocks block[MAP_CLIENT_X][MAP_CLIENT_Y];
00048 
00049 /* lightning system */
00050 #define MAX_MASK_SIZE 81
00051 #define NR_LIGHT_MASK 10
00052 #define MAX_LIGHT_SOURCE 13
00053 
00054 static int lmask_x[MAX_MASK_SIZE] =
00055 {
00056     0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,
00057     0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1,
00058     0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0, -1, -2, -3, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -2, -1
00059 };
00060 
00061 static int lmask_y[MAX_MASK_SIZE]=
00062 {
00063     0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -2, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2,
00064     -3, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3,
00065     4, 4, 4, 4, 4, 3, 2, 1, 0, -1, -2, -3, -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -2, -1, 0, 1, 2, 3, 4, 4, 4, 4
00066 };
00067 
00068 static int light_mask[MAX_LIGHT_SOURCE + 1] =
00069 {
00070     0,
00071     1,
00072     2, 3,
00073     4, 5, 6, 6,
00074     7, 7, 8, 8,
00075     8, 9
00076 };
00077 
00078 static int light_mask_width[NR_LIGHT_MASK] =
00079 {
00080     0, 1, 2, 2, 3,
00081     3, 3, 4, 4, 4
00082 };
00083 
00084 static int light_mask_size[NR_LIGHT_MASK] =
00085 {
00086     0, 9, 25, 25, 49,
00087     49, 49, 81, 81, 81
00088 };
00089 
00090 static int light_masks[NR_LIGHT_MASK][MAX_MASK_SIZE] =
00091 {
00092     {0,
00093         0, 0, 0, 0, 0, 0, 0, 0,
00094         0, 0, 0, 0, 0, 0, 0, 0,
00095         0, 0, 0, 0, 0, 0, 0, 0,
00096         0, 0, 0, 0, 0, 0, 0, 0,
00097         0, 0, 0, 0, 0, 0, 0, 0,
00098         0, 0, 0, 0, 0, 0, 0, 0,
00099         0, 0, 0, 0, 0, 0, 0, 0,
00100         0, 0, 0, 0, 0, 0, 0, 0,
00101         0, 0, 0, 0, 0, 0, 0, 0,
00102         0, 0, 0, 0, 0, 0, 0, 0,
00103     },
00104     {40,
00105      20, 20, 20, 20, 20, 20, 20, 20,
00106      0, 0, 0, 0, 0, 0, 0, 0,
00107      0, 0, 0, 0, 0, 0, 0, 0,
00108      0, 0, 0, 0, 0, 0, 0, 0,
00109      0, 0, 0, 0, 0, 0, 0, 0,
00110      0, 0, 0, 0, 0, 0, 0, 0,
00111      0, 0, 0, 0, 0, 0, 0, 0,
00112      0, 0, 0, 0, 0, 0, 0, 0,
00113      0, 0, 0, 0, 0, 0, 0, 0,
00114      0, 0, 0, 0, 0, 0, 0, 0,
00115     },
00116     {80,
00117      40, 40, 40, 40, 40, 40, 40, 40,
00118      20, 20, 20, 20, 20, 20, 20, 20,
00119      20, 20, 20, 20, 20, 20, 20, 20,
00120      0, 0, 0, 0, 0, 0, 0, 0,
00121      0, 0, 0, 0, 0, 0, 0, 0,
00122      0, 0, 0, 0, 0, 0, 0, 0,
00123      0, 0, 0, 0, 0, 0, 0, 0,
00124      0, 0, 0, 0, 0, 0, 0, 0,
00125      0, 0, 0, 0, 0, 0, 0, 0,
00126      0, 0, 0, 0, 0, 0, 0, 0,
00127     },
00128     {160,
00129      80, 80, 80, 80, 80, 80, 80, 80,
00130      40, 40, 40, 40, 40, 40, 40, 40,
00131      40, 40, 40, 40, 40, 40, 40, 40,
00132      0, 0, 0, 0, 0, 0, 0, 0,
00133      0, 0, 0, 0, 0, 0, 0, 0,
00134      0, 0, 0, 0, 0, 0, 0, 0,
00135      0, 0, 0, 0, 0, 0, 0, 0,
00136      0, 0, 0, 0, 0, 0, 0, 0,
00137      0, 0, 0, 0, 0, 0, 0, 0,
00138      0, 0, 0, 0, 0, 0, 0, 0,
00139     },
00140     {160,
00141      80, 80, 80, 80, 80, 80, 80, 80,
00142      40, 40, 40, 40, 40, 40, 40, 40,
00143      40, 40, 40, 40, 40, 40, 40, 40,
00144      20, 20, 20, 20, 20, 20, 20, 20,
00145      20, 20, 20, 20, 20, 20, 20, 20,
00146      20, 20, 20, 20, 20, 20, 20, 20,
00147      0, 0, 0, 0, 0, 0, 0, 0,
00148      0, 0, 0, 0, 0, 0, 0, 0,
00149      0, 0, 0, 0, 0, 0, 0, 0,
00150      0, 0, 0, 0, 0, 0, 0, 0,
00151     },
00152     {320,
00153      160, 160, 160, 160, 160, 160, 160, 160,
00154      80, 80, 80, 80, 80, 80, 80, 80,
00155      80, 80, 80, 80, 80, 80, 80, 80,
00156      40, 40, 40, 40, 40, 40, 40, 40,
00157      40, 40, 40, 40, 40, 40, 40, 40,
00158      40, 40, 40, 40, 40, 40, 40, 40,
00159      0, 0, 0, 0, 0, 0, 0, 0,
00160      0, 0, 0, 0, 0, 0, 0, 0,
00161      0, 0, 0, 0, 0, 0, 0, 0,
00162      0, 0, 0, 0, 0, 0, 0, 0,
00163     },
00164     {320,
00165      160, 160, 160, 160, 160, 160, 160, 160,
00166      80, 80, 80, 80, 80, 80, 80, 80,
00167      80, 80, 80, 80, 80, 80, 80, 80,
00168      40, 40, 40, 40, 40, 40, 40, 40,
00169      40, 40, 40, 40, 40, 40, 40, 40,
00170      40, 40, 40, 40, 40, 40, 40, 40,
00171      0, 0, 0, 0, 0, 0, 0, 0,
00172      0, 0, 0, 0, 0, 0, 0, 0,
00173      0, 0, 0, 0, 0, 0, 0, 0,
00174      0, 0, 0, 0, 0, 0, 0, 0,
00175     },
00176     {320,
00177      160, 160, 160, 160, 160, 160, 160, 160,
00178      80, 80, 80, 80, 80, 80, 80, 80,
00179      80, 80, 80, 80, 80, 80, 80, 80,
00180      40, 40, 40, 40, 40, 40, 40, 40,
00181      40, 40, 40, 40, 40, 40, 40, 40,
00182      40, 40, 40, 40, 40, 40, 40, 40,
00183      20, 20, 20, 20, 20, 20, 20, 20,
00184      20, 20, 20, 20, 20, 20, 20, 20,
00185      20, 20, 20, 20, 20, 20, 20, 20,
00186      20, 20, 20, 20, 20, 20, 20, 20,
00187     },
00188     {640,
00189      320, 320, 320, 320, 320, 320, 320, 320,
00190      160, 160, 160, 160, 160, 160, 160, 160,
00191      160, 160, 160, 160, 160, 160, 160, 160,
00192      80, 80, 80, 80, 80, 80, 80, 80,
00193      80, 80, 80, 80, 80, 80, 80, 80,
00194      80, 80, 80, 80, 80, 80, 80, 80,
00195      40, 40, 40, 40, 40, 40, 40, 40,
00196      40, 40, 40, 40, 40, 40, 40, 40,
00197      40, 40, 40, 40, 40, 40, 40, 40,
00198      40, 40, 40, 40, 40, 40, 40, 40,
00199     },
00200     {1280,
00201      640, 640, 640, 640, 640, 640, 640, 640,
00202      160, 160, 160, 160, 160, 160, 160, 160,
00203      160, 160, 160, 160, 160, 160, 160, 160,
00204      80, 80, 80, 80, 80, 80, 80, 80,
00205      80, 80, 80, 80, 80, 80, 80, 80,
00206      80, 80, 80, 80, 80, 80, 80, 80,
00207      40, 40, 40, 40, 40, 40, 40, 40,
00208      40, 40, 40, 40, 40, 40, 40, 40,
00209      40, 40, 40, 40, 40, 40, 40, 40,
00210      40, 40, 40, 40, 40, 40, 40, 40,
00211     }
00212 
00213 };
00214 
00215 static void expand_sight(object *op);
00216 
00226 void init_block()
00227 {
00228     int x, y, dx, dy, i;
00229     static const int block_x[3] = {-1, -1, 0}, block_y[3] = {-1, 0, -1};
00230 
00231     for (x = 0; x < MAP_CLIENT_X; x++)
00232     {
00233         for (y = 0; y < MAP_CLIENT_Y; y++)
00234         {
00235             block[x][y].index = 0;
00236         }
00237     }
00238 
00239     /* The table should be symmetric, so only do the upper left
00240      * quadrant - makes the processing easier. */
00241     for (x = 1; x <= MAP_CLIENT_X / 2; x++)
00242     {
00243         for (y = 1; y <= MAP_CLIENT_Y / 2; y++)
00244         {
00245             for (i = 0; i < 3; i++)
00246             {
00247                 dx = x + block_x[i];
00248                 dy = y + block_y[i];
00249 
00250                 /* Center space never blocks */
00251                 if (x == MAP_CLIENT_X / 2 && y == MAP_CLIENT_Y / 2)
00252                 {
00253                     continue;
00254                 }
00255 
00256                 /* If its a straight line, it's blocked */
00257                 if ((dx == x && x == MAP_CLIENT_X / 2) || (dy == y && y == MAP_CLIENT_Y / 2))
00258                 {
00259                     /* For simplicity, we mirror the coordinates to block the other
00260                      * quadrants. */
00261                     set_block(x, y, dx, dy);
00262 
00263                     if (x == MAP_CLIENT_X / 2)
00264                     {
00265                         set_block(x, MAP_CLIENT_Y - y -1, dx, MAP_CLIENT_Y - dy - 1);
00266                     }
00267                     else if (y == MAP_CLIENT_Y / 2)
00268                     {
00269                         set_block(MAP_CLIENT_X - x -1, y, MAP_CLIENT_X - dx - 1, dy);
00270                     }
00271                 }
00272                 else
00273                 {
00274                     float d1, s, l;
00275 
00276                     /* We use the algorithm that found out how close the point
00277                      * (x, y) is to the line from dx, dy to the center of the viewable
00278                      * area.  l is the distance from x, y to the line.
00279                      * r is more a curiosity - it lets us know what direction (left/right)
00280                      * the line is off */
00281                     d1 = (float) (pow(MAP_CLIENT_X / 2 - dx, 2) + pow(MAP_CLIENT_Y / 2 - dy, 2));
00282                     s = (float) ((dy - y) * (MAP_CLIENT_X / 2 - dx) - (dx - x) * (MAP_CLIENT_Y / 2 - dy)) / d1;
00283                     l = (float) FABS(sqrt(d1) * s);
00284 
00285                     if (l <= SPACE_BLOCK)
00286                     {
00287                         /* For simplicity, we mirror the coordinates to block the other
00288                          * quadrants. */
00289                         set_block(x, y, dx, dy);
00290                         set_block(MAP_CLIENT_X - x -1, y, MAP_CLIENT_X - dx - 1, dy);
00291                         set_block(x, MAP_CLIENT_Y - y -1, dx, MAP_CLIENT_Y - dy - 1);
00292                         set_block(MAP_CLIENT_X - x - 1, MAP_CLIENT_Y - y - 1, MAP_CLIENT_X - dx - 1, MAP_CLIENT_Y - dy - 1);
00293                     }
00294                 }
00295             }
00296         }
00297     }
00298 }
00299 
00312 void set_block(int x, int y, int bx, int by)
00313 {
00314     int idx = block[x][y].index, i;
00315 
00316     /* Due to flipping, we may get duplicates - better safe than sorry. */
00317     for (i = 0; i < idx; i++)
00318     {
00319         if (block[x][y].x[i] == bx && block[x][y].y[i] == by)
00320         {
00321             return;
00322         }
00323     }
00324 
00325     block[x][y].x[idx] = bx;
00326     block[x][y].y[idx] = by;
00327     block[x][y].index++;
00328 
00329 #ifdef LOS_DEBUG
00330     LOG(llevDebug, "setblock: added %d %d -> %d %d (%d)\n", x, y, bx, by, block[x][y].index);
00331 #endif
00332 }
00333 
00346 static void set_wall(object *op, int x, int y)
00347 {
00348     int i, xt, yt;
00349 
00350     xt = (MAP_CLIENT_X - CONTR(op)->socket.mapx) / 2;
00351     yt = (MAP_CLIENT_Y - CONTR(op)->socket.mapy) / 2;
00352 
00353     for (i = 0; i < block[x][y].index; i++)
00354     {
00355         int dx = block[x][y].x[i], dy = block[x][y].y[i], ax, ay;
00356 
00357         /* ax, ay are the values as adjusted to be in the
00358          * socket look structure. */
00359         ax = dx - xt;
00360         ay = dy - yt;
00361 
00362         if (ax < 0 || ax >= CONTR(op)->socket.mapx || ay < 0 || ay >= CONTR(op)->socket.mapy)
00363         {
00364             continue;
00365         }
00366 
00367         /* We need to adjust to the fact that the socket
00368          * code wants the los to start from the 0, 0
00369          * and not be relative to middle of los array. */
00370 
00371         /* This tile can't be seen */
00372         if (!(CONTR(op)->blocked_los[ax][ay] & BLOCKED_LOS_OUT_OF_MAP))
00373         {
00374             CONTR(op)->blocked_los[ax][ay] |= BLOCKED_LOS_BLOCKED;
00375         }
00376 
00377         set_wall(op, dx, dy);
00378     }
00379 }
00380 
00389 static void check_wall(object *op, int x, int y)
00390 {
00391     int ax, ay, flags;
00392 
00393     /* ax, ay are coordinates as indexed into the look window */
00394     ax = x - (MAP_CLIENT_X - CONTR(op)->socket.mapx) / 2;
00395     ay = y - (MAP_CLIENT_Y - CONTR(op)->socket.mapy) / 2;
00396 
00397     /* this skips the "edges" of view area, the border tiles.
00398      * Naturally, this tiles can't block any view - there is
00399      * nothing behind them. */
00400     if (!block[x][y].index)
00401     {
00402         /* to handle the "blocksview update" right, we give this special
00403          * tiles a "never use it to trigger a los_update()" flag.
00404          * blockview changes to this tiles will have no effect. */
00405 
00406         /* mark the space as OUT_OF_MAP. */
00407         if (blocks_view(op->map,op->x + x - MAP_CLIENT_X / 2, op->y + y - MAP_CLIENT_Y / 2) & P_OUT_OF_MAP)
00408         {
00409             CONTR(op)->blocked_los[ax][ay] = BLOCKED_LOS_OUT_OF_MAP;
00410         }
00411         /* ignore means ignore for LOS */
00412         else
00413         {
00414             CONTR(op)->blocked_los[ax][ay] |= BLOCKED_LOS_IGNORE;
00415         }
00416 
00417         return;
00418     }
00419 
00420 
00421     /* If the converted coordinates are outside the viewable
00422      * area for the client, return now. */
00423     if (ax < 0 || ay < 0 || ax >= CONTR(op)->socket.mapx || ay >= CONTR(op)->socket.mapy)
00424     {
00425         return;
00426     }
00427 
00428     /* If this space is already blocked, prune the processing - presumably
00429      * whatever has set this space to be blocked has done the work and already
00430      * done the dependency chain.
00431      * but check for get_map_from_coord to speedup our client map draw function. */
00432     if (CONTR(op)->blocked_los[ax][ay] & (BLOCKED_LOS_BLOCKED | BLOCKED_LOS_OUT_OF_MAP))
00433     {
00434         if (CONTR(op)->blocked_los[ax][ay] & BLOCKED_LOS_BLOCKED)
00435         {
00436             if ((flags = blocks_view(op->map, op->x + x - MAP_CLIENT_X / 2, op->y + y - MAP_CLIENT_Y / 2)))
00437             {
00438                 /* mark the space as OUT_OF_MAP. */
00439                 if (flags & P_OUT_OF_MAP)
00440                 {
00441                     CONTR(op)->blocked_los[ax][ay] = BLOCKED_LOS_OUT_OF_MAP;
00442                 }
00443                 else
00444                 {
00445                     CONTR(op)->blocked_los[ax][ay] |= BLOCKED_LOS_BLOCKSVIEW;
00446                 }
00447             }
00448         }
00449         return;
00450     }
00451 
00452     if ((flags = blocks_view(op->map, op->x + x - MAP_CLIENT_X / 2, op->y + y - MAP_CLIENT_Y / 2)))
00453     {
00454         set_wall(op, x, y);
00455 
00456         /* out of map clears all other flags! */
00457 
00458         /* Mark the space as OUT_OF_MAP. */
00459         if (flags & P_OUT_OF_MAP)
00460         {
00461             CONTR(op)->blocked_los[ax][ay] = BLOCKED_LOS_OUT_OF_MAP;
00462         }
00463         else
00464         {
00465             CONTR(op)->blocked_los[ax][ay] |= BLOCKED_LOS_BLOCKSVIEW;
00466         }
00467     }
00468 }
00469 
00475 static void blinded_sight(object *op)
00476 {
00477     int x, y;
00478 
00479     for (x = 0; x < CONTR(op)->socket.mapx; x++)
00480     {
00481         for (y = 0; y < CONTR(op)->socket.mapy; y++)
00482         {
00483             CONTR(op)->blocked_los[x][y] |= BLOCKED_LOS_BLOCKED;
00484         }
00485     }
00486 
00487     CONTR(op)->blocked_los[CONTR(op)->socket.mapx / 2][CONTR(op)->socket.mapy / 2] &= ~BLOCKED_LOS_BLOCKED;
00488 }
00489 
00494 void update_los(object *op)
00495 {
00496     int dx = CONTR(op)->socket.mapx_2, dy = CONTR(op)->socket.mapy_2, x, y;
00497 
00498     if (QUERY_FLAG(op, FLAG_REMOVED))
00499     {
00500         return;
00501     }
00502 
00503 #ifdef DEBUG_CORE
00504     LOG(llevDebug, "LOS - %s\n", query_name(op));
00505 #endif
00506 
00507     clear_los(op);
00508 
00509     if (QUERY_FLAG(op, FLAG_WIZ))
00510     {
00511         return;
00512     }
00513 
00514     /* For larger maps, this is more efficient than the old way which
00515      * used the chaining of the block array.  Since many space views could
00516      * be blocked by different spaces in front, this mean that a lot of spaces
00517      * could be examined multile times, as each path would be looked at. */
00518     for (x = (MAP_CLIENT_X - CONTR(op)->socket.mapx) / 2; x < (MAP_CLIENT_X + CONTR(op)->socket.mapx) / 2; x++)
00519     {
00520         for (y = (MAP_CLIENT_Y - CONTR(op)->socket.mapy) / 2; y < (MAP_CLIENT_Y + CONTR(op)->socket.mapy) / 2; y++)
00521         {
00522             check_wall(op, x, y);
00523         }
00524     }
00525 
00526     if (QUERY_FLAG(op, FLAG_BLIND))
00527     {
00528         blinded_sight(op);
00529     }
00530     else
00531     {
00532         expand_sight(op);
00533 
00534         /* Give us an area we can look through when we have xray - this
00535          * stacks to normal LOS. */
00536         if (QUERY_FLAG(op, FLAG_XRAYS))
00537         {
00538             for (x = -3; x <= 3; x++)
00539             {
00540                 for (y = -3; y <= 3; y++)
00541                 {
00542                     if (CONTR(op)->blocked_los[dx + x][dy + y] & BLOCKED_LOS_BLOCKED)
00543                     {
00544                         CONTR(op)->blocked_los[dx + x][dy + y] &= ~BLOCKED_LOS_BLOCKED;
00545                     }
00546                 }
00547             }
00548         }
00549     }
00550 }
00551 
00556 void clear_los(object *op)
00557 {
00558     (void) memset((void *) CONTR(op)->blocked_los, BLOCKED_LOS_VISIBLE, sizeof(CONTR(op)->blocked_los));
00559 }
00560 
00561 #define BLOCKED_LOS_EXPAND 0x20
00562 
00571 static void expand_sight(object *op)
00572 {
00573     int i, x, y, dx, dy;
00574 
00575     /* loop over inner squares */
00576     for (x = 1; x < CONTR(op)->socket.mapx - 1; x++)
00577     {
00578         for (y = 1; y < CONTR(op)->socket.mapy - 1; y++)
00579         {
00580             /* if visible and not blocksview */
00581             if (CONTR(op)->blocked_los[x][y] <= BLOCKED_LOS_BLOCKSVIEW && !(CONTR(op)->blocked_los[x][y] & BLOCKED_LOS_BLOCKSVIEW))
00582             {
00583                 /* mark all directions */
00584                 for (i = 1; i <= 8; i += 1)
00585                 {
00586                     dx = x + freearr_x[i];
00587                     dy = y + freearr_y[i];
00588 
00589                     if (dx < 0 || dy < 0 || dx > CONTR(op)->socket.mapx || dy > CONTR(op)->socket.mapy)
00590                     {
00591                         continue;
00592                     }
00593 
00594                     if (CONTR(op)->blocked_los[dx][dy] & BLOCKED_LOS_BLOCKED)
00595                     {
00596                         CONTR(op)->blocked_los[dx][dy] |= BLOCKED_LOS_EXPAND;
00597                     }
00598                 }
00599             }
00600         }
00601     }
00602 
00603     for (x = 0; x < CONTR(op)->socket.mapx; x++)
00604     {
00605         for (y = 0; y < CONTR(op)->socket.mapy; y++)
00606         {
00607             if (CONTR(op)->blocked_los[x][y] & BLOCKED_LOS_EXPAND)
00608             {
00609                 CONTR(op)->blocked_los[x][y] &= ~(BLOCKED_LOS_BLOCKED | BLOCKED_LOS_EXPAND);
00610             }
00611         }
00612     }
00613 }
00614 
00615 static int get_real_light_source_value(int l)
00616 {
00617     if (l > MAX_LIGHT_SOURCE)
00618         return light_mask[MAX_LIGHT_SOURCE];
00619 
00620     if (l < -MAX_LIGHT_SOURCE)
00621         return -light_mask[MAX_LIGHT_SOURCE];
00622 
00623     if (l < 0)
00624         return -light_mask[-l];
00625 
00626     return light_mask[l];
00627 }
00628 
00629 static void remove_light_mask(mapstruct *map, int x, int y, int mid)
00630 {
00631     MapSpace *msp;
00632     mapstruct *m;
00633     int xt, yt, i, mlen;
00634 
00635     /* Light masks */
00636     if (mid > 0)
00637     {
00638         mlen = light_mask_size[mid];
00639 
00640         for (i = 0; i < mlen; i++)
00641         {
00642             xt = x + lmask_x[i];
00643             yt = y + lmask_y[i];
00644 
00645             if (!(m = get_map_from_coord2(map, &xt, &yt)))
00646             {
00647                 continue;
00648             }
00649 
00650             msp = GET_MAP_SPACE_PTR(m, xt, yt);
00651             msp->light_value -= light_masks[mid][i];
00652         }
00653     }
00654     /* Handle shadow mask */
00655     else
00656     {
00657         mid = -mid;
00658         mlen = light_mask_size[mid];
00659 
00660         for (i = 0; i < mlen; i++)
00661         {
00662             xt = x + lmask_x[i];
00663             yt = y + lmask_y[i];
00664 
00665             if (!(m = get_map_from_coord2(map, &xt, &yt)))
00666             {
00667                 continue;
00668             }
00669 
00670             msp = GET_MAP_SPACE_PTR(m, xt, yt);
00671             msp->light_value += light_masks[mid][i];
00672         }
00673     }
00674 }
00675 
00676 static int add_light_mask(mapstruct *map, int x, int y, int mid)
00677 {
00678     MapSpace *msp;
00679     mapstruct *m;
00680     int xt, yt, i, mlen, map_flag = 0;
00681 
00682     if (mid > 0)
00683     {
00684         mlen = light_mask_size[mid];
00685 
00686         for (i = 0; i < mlen; i++)
00687         {
00688             xt = x + lmask_x[i];
00689             yt = y + lmask_y[i];
00690 
00691             if (!(m = get_map_from_coord2(map, &xt, &yt)))
00692             {
00693                 if (xt)
00694                 {
00695                     map_flag = 1;
00696                 }
00697 
00698                 continue;
00699             }
00700 
00701             /* This light mask crosses some tiled map borders */
00702             if (m != map)
00703             {
00704                 map_flag = 1;
00705             }
00706 
00707             msp = GET_MAP_SPACE_PTR(m, xt, yt);
00708             msp->light_value += light_masks[mid][i];
00709         }
00710     }
00711     /* Shadow masks */
00712     else
00713     {
00714         mid = -mid;
00715         mlen = light_mask_size[mid];
00716 
00717         for (i = 0; i < mlen; i++)
00718         {
00719             xt = x + lmask_x[i];
00720             yt = y + lmask_y[i];
00721 
00722             if (!(m = get_map_from_coord2(map, &xt, &yt)))
00723             {
00724                 if (xt)
00725                 {
00726                     map_flag = 1;
00727                 }
00728 
00729                 continue;
00730             }
00731 
00732             /* This light mask crosses some tiled map borders */
00733             if (m != map)
00734             {
00735                 map_flag = 1;
00736             }
00737 
00738             msp = GET_MAP_SPACE_PTR(m, xt, yt);
00739             msp->light_value -= light_masks[mid][i];
00740         }
00741     }
00742 
00743     return map_flag;
00744 }
00745 
00754 void adjust_light_source(mapstruct *map, int x, int y, int light)
00755 {
00756     int nlm, olm;
00757     MapSpace *msp1 = GET_MAP_SPACE_PTR(map,x,y);
00758 
00759     /* this happens, we don't change the intense of the old light mask */
00760     /* old mask */
00761     olm = get_real_light_source_value(msp1->light_source);
00762     msp1->light_source += light;
00763     /* new mask */
00764     nlm = get_real_light_source_value(msp1->light_source);
00765 
00766     /* Old mask same as new one? not much to do */
00767     if (nlm == olm)
00768     {
00769         return;
00770     }
00771 
00772     if (olm)
00773     {
00774         /* Remove the old light mask */
00775         remove_light_mask(map, x, y, olm);
00776 
00777         /* Perhaps we are in this list - perhaps we are not */
00778         if (msp1->prev_light)
00779         {
00780             msp1->prev_light->next_light = msp1->next_light;
00781         }
00782         else
00783         {
00784             /* We are the list head */
00785             if (map->first_light == msp1)
00786             {
00787                 map->first_light = msp1->next_light;
00788             }
00789         }
00790 
00791         /* Handle next link */
00792         if (msp1->next_light)
00793         {
00794             msp1->next_light->prev_light = msp1->prev_light;
00795         }
00796 
00797         msp1->prev_light = NULL;
00798         msp1->next_light = NULL;
00799     }
00800 
00801     if (nlm)
00802     {
00803         /* Add new light mask */
00804         if (add_light_mask(map, x, y, nlm))
00805         {
00806             /* Don't chain if we are chained previous */
00807             if (msp1->next_light || msp1->prev_light || map->first_light == msp1)
00808             {
00809                 return;
00810             }
00811 
00812             /* We should be always unlinked here - so link it now */
00813             msp1->next_light = map->first_light;
00814 
00815             if (map->first_light)
00816             {
00817                 msp1->next_light->prev_light = msp1;
00818             }
00819 
00820             map->first_light = msp1;
00821         }
00822     }
00823 }
00824 
00834 static void restore_light_mask(mapstruct *restore_map, mapstruct *map, int x, int y, int mid)
00835 {
00836     MapSpace *msp;
00837     mapstruct *m;
00838     int xt, yt, i, mlen;
00839 
00840     if (mid > 0)
00841     {
00842         mlen = light_mask_size[mid];
00843 
00844         for (i = 0; i < mlen; i++)
00845         {
00846             xt = x + lmask_x[i];
00847             yt = y + lmask_y[i];
00848 
00849             m = get_map_from_coord2(map, &xt ,&yt);
00850 
00851             /* Only handle parts inside our calling (restore) map */
00852             if (restore_map != m)
00853             {
00854                 continue;
00855             }
00856 
00857             msp = GET_MAP_SPACE_PTR(m, xt, yt);
00858             msp->light_value += light_masks[mid][i];
00859         }
00860     }
00861     /* Shadow masks */
00862     else
00863     {
00864         mid = -mid;
00865         mlen = light_mask_size[mid];
00866 
00867         for (i = 0; i < mlen; i++)
00868         {
00869             xt = x + lmask_x[i];
00870             yt = y + lmask_y[i];
00871             m = get_map_from_coord2(map, &xt, &yt);
00872 
00873             /* Only handle parts inside our calling (restore) map */
00874             if (restore_map != m)
00875             {
00876                 continue;
00877             }
00878 
00879             msp = GET_MAP_SPACE_PTR(m, xt, yt);
00880             msp->light_value -= light_masks[mid][i];
00881         }
00882     }
00883 }
00884 
00890 void check_light_source_list(mapstruct *map)
00891 {
00892     mapstruct *t_map;
00893     MapSpace *tmp;
00894     int x, y, mid;
00895 
00896     if ((t_map = map->tile_map[0]) && (t_map->in_memory == MAP_IN_MEMORY || t_map->in_memory == MAP_LOADING) && t_map->first_light)
00897     {
00898         /* Check this light source list */
00899         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
00900         {
00901             if (!tmp->first)
00902             {
00903                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO T_MAP PATH?");
00904                 continue;
00905             }
00906 
00907             mid = get_real_light_source_value(tmp->light_source);
00908             /* There MUST be at least one object in this tile - grab it and
00909              * get the x/y offset from it */
00910             x = tmp->first->x;
00911             y = tmp->first->y;
00912 
00913             /* Only light sources reaching in this map */
00914             if (y + light_mask_width[abs(mid)] < MAP_HEIGHT(t_map))
00915             {
00916                 continue;
00917             }
00918 
00919             restore_light_mask(map, t_map, x, y, mid);
00920         }
00921     }
00922 
00923     if ((t_map = map->tile_map[1]) && (t_map->in_memory == MAP_IN_MEMORY || t_map->in_memory == MAP_LOADING) && t_map->first_light)
00924     {
00925         /* Check this light source list */
00926         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
00927         {
00928             if (!tmp->first)
00929             {
00930                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO MAP PATH?");
00931                 continue;
00932             }
00933 
00934             mid = get_real_light_source_value(tmp->light_source);
00935             /* There MUST be at least one object in this tile - grab it and
00936              * get the x/y offset from it! */
00937             x = tmp->first->x;
00938             y = tmp->first->y;
00939 
00940             /* Only light sources reaching in this map */
00941             if (x - light_mask_width[abs(mid)] >= 0)
00942             {
00943                 continue;
00944             }
00945 
00946             restore_light_mask(map, t_map, x, y, mid);
00947         }
00948     }
00949 
00950     if ((t_map = map->tile_map[2]) && (t_map->in_memory == MAP_IN_MEMORY || t_map->in_memory == MAP_LOADING) && t_map->first_light)
00951     {
00952         /* Check this light source list */
00953         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
00954         {
00955             if (!tmp->first)
00956             {
00957                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO T_MAP PATH?");
00958                 continue;
00959             }
00960 
00961             mid = get_real_light_source_value(tmp->light_source);
00962             /* There MUST be at least one object in this tile - grab it and
00963              * get the x/y offset from it! */
00964             x = tmp->first->x;
00965             y = tmp->first->y;
00966 
00967             /* Only light sources reaching in this map */
00968             if (y - light_mask_width[abs(mid)] >= 0)
00969             {
00970                 continue;
00971             }
00972 
00973             restore_light_mask(map, t_map, x, y, mid);
00974         }
00975     }
00976 
00977     if ((t_map = map->tile_map[3]) && (t_map->in_memory == MAP_IN_MEMORY || t_map->in_memory == MAP_LOADING) && t_map->first_light)
00978     {
00979         /* Check this light source list */
00980         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
00981         {
00982             if (!tmp->first)
00983             {
00984                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO T_MAP PATH?");
00985                 continue;
00986             }
00987 
00988             mid = get_real_light_source_value(tmp->light_source);
00989             /* There MUST be at least one object in this tile - grab it and
00990              * get the x/y offset from it! */
00991             x = tmp->first->x;
00992             y = tmp->first->y;
00993 
00994             /* Only light sources reaching in this map */
00995             if (x + light_mask_width[abs(mid)] < MAP_WIDTH(t_map))
00996             {
00997                 continue;
00998             }
00999 
01000             restore_light_mask(map, t_map, x, y, mid);
01001         }
01002     }
01003 
01004     if ((t_map = map->tile_map[4]) && (t_map->in_memory==MAP_IN_MEMORY || t_map->in_memory==MAP_LOADING) &&  t_map->first_light)
01005     {
01006         /* Check this light source list */
01007         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
01008         {
01009             if (!tmp->first)
01010             {
01011                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO T_MAP PATH?");
01012                 continue;
01013             }
01014 
01015             mid=get_real_light_source_value(tmp->light_source);
01016             /* There MUST be at least one object in this tile - grab it and
01017              * get the x/y offset from it! */
01018             x = tmp->first->x;
01019             y = tmp->first->y;
01020 
01021             /* only light sources reaching in this map */
01022             if ((y + light_mask_width[abs(mid)]) < MAP_HEIGHT(t_map) || (x - light_mask_width[abs(mid)]) >= 0)
01023             {
01024                 continue;
01025             }
01026 
01027             restore_light_mask(map, t_map, x, y, mid);
01028         }
01029     }
01030 
01031     if ((t_map = map->tile_map[5]) && (t_map->in_memory == MAP_IN_MEMORY || t_map->in_memory == MAP_LOADING) && t_map->first_light)
01032     {
01033         /* Check this light source list */
01034         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
01035         {
01036             if (!tmp->first)
01037             {
01038                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO MAP PATH?");
01039                 continue;
01040             }
01041 
01042             mid = get_real_light_source_value(tmp->light_source);
01043             /* There MUST be at least one object in this tile - grab it and
01044              * get the x/y offset from it! */
01045             x = tmp->first->x;
01046             y = tmp->first->y;
01047 
01048             /* Only light sources reaching in this map */
01049             if ((x - light_mask_width[abs(mid)]) >= 0 || (y - light_mask_width[abs(mid)]) >= 0)
01050             {
01051                 continue;
01052             }
01053 
01054             restore_light_mask(map, t_map, x, y, mid);
01055         }
01056     }
01057 
01058     if ((t_map = map->tile_map[6]) && (t_map->in_memory == MAP_IN_MEMORY || t_map->in_memory == MAP_LOADING) && t_map->first_light)
01059     {
01060         /* Check this light source list */
01061         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
01062         {
01063             if (!tmp->first)
01064             {
01065                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO T_MAP PATH?");
01066                 continue;
01067             }
01068 
01069             mid = get_real_light_source_value(tmp->light_source);
01070             /* There MUST be at least one object in this tile - grab it and
01071              * get the x/y offset from it! */
01072             x = tmp->first->x;
01073             y = tmp->first->y;
01074 
01075             /* Only light sources reaching in this map */
01076             if ((y - light_mask_width[abs(mid)]) >= 0 || (x + light_mask_width[abs(mid)]) < MAP_WIDTH(t_map))
01077             {
01078                 continue;
01079             }
01080 
01081             restore_light_mask(map, t_map, x, y, mid);
01082         }
01083     }
01084 
01085     if ((t_map = map->tile_map[7]) && (t_map->in_memory == MAP_IN_MEMORY || t_map->in_memory == MAP_LOADING) && t_map->first_light)
01086     {
01087         /* Check this light source list */
01088         for (tmp = t_map->first_light; tmp; tmp = tmp->next_light)
01089         {
01090             if (!tmp->first)
01091             {
01092                 LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", t_map->path ? t_map->path : "NO T_MAP PATH?");
01093                 continue;
01094             }
01095 
01096             mid = get_real_light_source_value(tmp->light_source);
01097             /* There MUST be at least one object in this tile - grab it and
01098              * get the x/y offset from it! */
01099             x = tmp->first->x;
01100             y = tmp->first->y;
01101 
01102             /* Only light sources reaching in this map */
01103             if ((y + light_mask_width[abs(mid)]) < MAP_HEIGHT(t_map) || (x + light_mask_width[abs(mid)]) < MAP_WIDTH(t_map))
01104             {
01105                 continue;
01106             }
01107 
01108             restore_light_mask(map, t_map, x, y, mid);
01109         }
01110     }
01111 }
01112 
01113 /* Remove mask part from OTHER in memory maps! */
01114 static void remove_light_mask_other(mapstruct *map, int x, int y, int mid)
01115 {
01116     MapSpace *msp;
01117     mapstruct *m;
01118     int xt, yt, i, mlen;
01119 
01120     if (mid > 0)
01121     {
01122         mlen = light_mask_size[mid];
01123 
01124         for (i = 0; i < mlen; i++)
01125         {
01126             xt = x + lmask_x[i];
01127             yt = y + lmask_y[i];
01128             m = get_map_from_coord2(map, &xt, &yt);
01129 
01130             /* Only legal OTHER maps */
01131             if (!m || m == map)
01132             {
01133                 continue;
01134             }
01135 
01136             msp = GET_MAP_SPACE_PTR(m, xt, yt);
01137             msp->light_value -= light_masks[mid][i];
01138         }
01139     }
01140     else
01141     {
01142         mid = -mid;
01143         mlen = light_mask_size[mid];
01144 
01145         for (i = 0; i < mlen; i++)
01146         {
01147             xt = x + lmask_x[i];
01148             yt = y + lmask_y[i];
01149             m = get_map_from_coord2(map, &xt, &yt);
01150 
01151             /* Only legal OTHER maps */
01152             if (!m || m == map)
01153             {
01154                 continue;
01155             }
01156 
01157             msp = GET_MAP_SPACE_PTR(m, xt, yt);
01158             msp->light_value += light_masks[mid][i];
01159         }
01160     }
01161 }
01162 
01166 void remove_light_source_list(mapstruct *map)
01167 {
01168     MapSpace *tmp;
01169 
01170     for (tmp = map->first_light; tmp; tmp = tmp->next_light)
01171     {
01172         /* There MUST be at least ONE object in this map space */
01173         if (!tmp->first)
01174         {
01175             LOG(llevBug, "remove_light_source_list() map:>%s< - no object in mapspace of light source!\n", map->path ? map->path : "NO MAP PATH?");
01176             continue;
01177         }
01178 
01179         remove_light_mask_other(map, tmp->first->x, tmp->first->y, get_real_light_source_value(tmp->light_source));
01180     }
01181 
01182     map->first_light = NULL;
01183 }
01184 
01193 int obj_in_line_of_sight(object *obj, rv_vector *rv)
01194 {
01195     /* Bresenham variables */
01196     int fraction, dx2, dy2, stepx, stepy;
01197     /* Stepping variables */
01198     mapstruct *m = rv->part->map;
01199     int x = rv->part->x, y = rv->part->y;
01200 
01201     BRESENHAM_INIT(rv->distance_x, rv->distance_y, fraction, stepx, stepy, dx2, dy2);
01202 
01203     while (1)
01204     {
01205         if (x == obj->x && y == obj->y && m == obj->map)
01206         {
01207             return 1;
01208         }
01209 
01210         if (m == NULL || GET_MAP_FLAGS(m, x, y) & P_BLOCKSVIEW)
01211         {
01212             return 0;
01213         }
01214 
01215         BRESENHAM_STEP(x, y, fraction, stepx, stepy, dx2, dy2);
01216 
01217         m = get_map_from_coord(m, &x, &y);
01218     }
01219 }