|
Atrinik Server 2.5
|
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 }
1.7.4