00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034
00035
00036 #include <global.h>
00037 #include <math.h>
00038
00046 #define SPACE_BLOCK 0.5
00047
00048 typedef struct blstr {
00049 int x[4], y[4];
00050 int index;
00051 } blocks;
00052
00053 static blocks block[MAP_CLIENT_X][MAP_CLIENT_Y];
00054
00055 static void expand_lighted_sight(object *op);
00056
00075 static void set_block(int x, int y, int bx, int by) {
00076 int index = block[x][y].index, i;
00077
00078
00079
00080 for (i = 0; i < index; i++) {
00081 if (block[x][y].x[i] == bx
00082 && block[x][y].y[i] == by)
00083 return;
00084 }
00085
00086 block[x][y].x[index] = bx;
00087 block[x][y].y[index] = by;
00088 block[x][y].index++;
00089 #ifdef LOS_DEBUG
00090 LOG(llevDebug, "setblock: added %d %d -> %d %d (%d)\n", x, y, bx, by, block[x][y].index);
00091 #endif
00092 }
00093
00102 void init_block(void) {
00103 int x, y, dx, dy, i;
00104 static const int block_x[3] = {
00105 -1, -1, 0
00106 }, block_y[3] = {
00107 -1, 0, -1
00108 };
00109
00110 for (x = 0; x < MAP_CLIENT_X; x++)
00111 for (y = 0; y < MAP_CLIENT_Y; y++) {
00112 block[x][y].index = 0;
00113 }
00114
00115
00116
00117
00118 for (x = 1; x <= MAP_CLIENT_X/2; x++) {
00119 for (y = 1; y <= MAP_CLIENT_Y/2; y++) {
00120 for (i = 0; i < 3; i++) {
00121 dx = x+block_x[i];
00122 dy = y+block_y[i];
00123
00124
00125 if (x == MAP_CLIENT_X/2 && y == MAP_CLIENT_Y/2)
00126 continue;
00127
00128
00129 if ((dx == x && x == MAP_CLIENT_X/2)
00130 || (dy == y && y == MAP_CLIENT_Y/2)) {
00131
00132
00133
00134 set_block(x, y, dx, dy);
00135 if (x == MAP_CLIENT_X/2) {
00136 set_block(x, MAP_CLIENT_Y-y-1, dx, MAP_CLIENT_Y-dy-1);
00137 } else if (y == MAP_CLIENT_Y/2) {
00138 set_block(MAP_CLIENT_X-x-1, y, MAP_CLIENT_X-dx-1, dy);
00139 }
00140 } else {
00141 float d1, r, s, l;
00142
00143
00144
00145
00146
00147
00148
00149
00150 d1 = (float)(pow(MAP_CLIENT_X/2-dx, 2)+pow(MAP_CLIENT_Y/2-dy, 2));
00151 r = (float)((dy-y)*(dy-MAP_CLIENT_Y/2)-(dx-x)*(MAP_CLIENT_X/2-dx))/d1;
00152 s = (float)((dy-y)*(MAP_CLIENT_X/2-dx)-(dx-x)*(MAP_CLIENT_Y/2-dy))/d1;
00153 l = FABS(sqrt(d1)*s);
00154
00155 if (l <= SPACE_BLOCK) {
00156
00157
00158
00159 set_block(x, y, dx, dy);
00160 set_block(MAP_CLIENT_X-x-1, y, MAP_CLIENT_X-dx-1, dy);
00161 set_block(x, MAP_CLIENT_Y-y-1, dx, MAP_CLIENT_Y-dy-1);
00162 set_block(MAP_CLIENT_X-x-1, MAP_CLIENT_Y-y-1, MAP_CLIENT_X-dx-1, MAP_CLIENT_Y-dy-1);
00163 }
00164 }
00165 }
00166 }
00167 }
00168 }
00169
00185 static void set_wall(object *op, int x, int y) {
00186 int i;
00187
00188 for (i = 0; i < block[x][y].index; i++) {
00189 int dx = block[x][y].x[i], dy = block[x][y].y[i], ax, ay;
00190
00191
00192
00193
00194 ax = dx-(MAP_CLIENT_X-op->contr->socket.mapx)/2;
00195 ay = dy-(MAP_CLIENT_Y-op->contr->socket.mapy)/2;
00196
00197 if (ax < 0 || ax >= op->contr->socket.mapx
00198 || ay < 0 || ay >= op->contr->socket.mapy)
00199 continue;
00200
00201
00202
00203
00204 op->contr->blocked_los[ax][ay] = 100;
00205 set_wall(op, dx, dy);
00206 }
00207 }
00208
00220 static void check_wall(object *op, int x, int y) {
00221 int ax, ay;
00222
00223 if (!block[x][y].index)
00224 return;
00225
00226
00227 ax = x-(MAP_CLIENT_X-op->contr->socket.mapx)/2;
00228 ay = y-(MAP_CLIENT_Y-op->contr->socket.mapy)/2;
00229
00230
00231
00232
00233 if (ax < 0 || ay < 0 || ax >= op->contr->socket.mapx || ay >= op->contr->socket.mapy)
00234 return;
00235
00236
00237
00238
00239
00240 if (op->contr->blocked_los[ax][ay] == 100)
00241 return;
00242
00243
00244 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))
00245 set_wall(op, x, y);
00246 }
00247
00258 void clear_los(object *op) {
00259
00260
00261
00262
00263
00264 (void)memset((void *)op->contr->blocked_los, 0, MAP_CLIENT_X*MAP_CLIENT_Y);
00265 }
00266
00278 static void expand_sight(object *op) {
00279 int i, x, y, dx, dy;
00280
00281 for (x = 1; x < op->contr->socket.mapx-1; x++)
00282 for (y = 1; y < op->contr->socket.mapy-1; y++) {
00283 if (!op->contr->blocked_los[x][y]
00284 && !(get_map_flags(op->map, NULL,
00285 op->x-op->contr->socket.mapx/2+x,
00286 op->y-op->contr->socket.mapy/2+y,
00287 NULL, NULL)&(P_BLOCKSVIEW|P_OUT_OF_MAP))) {
00288
00289 for (i = 1; i <= 8; i += 1) {
00290 dx = x+freearr_x[i];
00291 dy = y+freearr_y[i];
00292 if (op->contr->blocked_los[dx][dy] > 0)
00293 op->contr->blocked_los[dx][dy] = -1;
00294 }
00295 }
00296 }
00297
00298 if (MAP_DARKNESS(op->map) > 0)
00299 expand_lighted_sight(op);
00300
00301
00302
00303 for (x = 0; x < op->contr->socket.mapx; x++)
00304 for (y = 0; y < op->contr->socket.mapy; y++)
00305 if (op->contr->blocked_los[x][y] < 0)
00306 op->contr->blocked_los[x][y] = 0;
00307 }
00308
00322 int has_carried_lights(const object *op) {
00323
00324 if (op->glow_radius > 0)
00325 return 1;
00326
00327 return 0;
00328 }
00329
00336 static void expand_lighted_sight(object *op) {
00337 int x, y, darklevel, ax, ay, basex, basey, mflags, light, x1, y1;
00338 mapstruct *m = op->map;
00339 sint16 nx, ny;
00340
00341 darklevel = MAP_DARKNESS(m);
00342
00343
00344 if (QUERY_FLAG(op, FLAG_SEE_IN_DARK))
00345 darklevel -= 2;
00346
00347
00348
00349
00350
00351 if (darklevel < 1)
00352 return;
00353
00354
00355
00356
00357 if (darklevel > MAX_DARKNESS) {
00358 LOG(llevError, "Map darkness for %s on %s is too high (%d)\n", op->name, op->map->path, darklevel);
00359 darklevel = MAX_DARKNESS;
00360 }
00361
00362
00363 for (x = 0; x < op->contr->socket.mapx; x++)
00364 for (y = 0; y < op->contr->socket.mapy; y++)
00365 if (op->contr->blocked_los[x][y] != 100)
00366 op->contr->blocked_los[x][y] = MAX_LIGHT_RADII;
00367
00368
00369
00370
00371
00372
00373
00374 for (x = (op->x-op->contr->socket.mapx/2-MAX_LIGHT_RADII), basex = -MAX_LIGHT_RADII;
00375 x <= (op->x+op->contr->socket.mapx/2+MAX_LIGHT_RADII); x++, basex++) {
00376
00377 for (y = (op->y-op->contr->socket.mapy/2-MAX_LIGHT_RADII), basey = -MAX_LIGHT_RADII;
00378 y <= (op->y+op->contr->socket.mapy/2+MAX_LIGHT_RADII); y++, basey++) {
00379 m = op->map;
00380 nx = x;
00381 ny = y;
00382
00383 mflags = get_map_flags(m, &m, nx, ny, &nx, &ny);
00384
00385 if (mflags&P_OUT_OF_MAP)
00386 continue;
00387
00388
00389
00390
00391 light = GET_MAP_LIGHT(m, nx, ny);
00392 if (light != 0) {
00393 for (ax = basex-light; ax <= basex+light; ax++) {
00394 if (ax < 0 || ax >= op->contr->socket.mapx)
00395 continue;
00396 for (ay = basey-light; ay <= basey+light; ay++) {
00397 if (ay < 0 || ay >= op->contr->socket.mapy)
00398 continue;
00399
00400
00401
00402
00403
00404
00405
00406
00407 if (op->contr->blocked_los[ax][ay] != 100) {
00408 x1 = abs(basex-ax)*abs(basex-ax);
00409 y1 = abs(basey-ay)*abs(basey-ay);
00410 if (light > 0)
00411 op->contr->blocked_los[ax][ay] -= MAX((light-isqrt(x1+y1)), 0);
00412 if (light < 0)
00413 op->contr->blocked_los[ax][ay] -= MIN((light+isqrt(x1+y1)), 0);
00414 }
00415 }
00416 }
00417 }
00418 }
00419 }
00420
00421
00422
00423
00424 if (op->map->outdoor && darklevel > (MAX_DARKNESS-3)) {
00425 if (op->contr->blocked_los[op->contr->socket.mapx/2][op->contr->socket.mapy/2] > (MAX_DARKNESS-3))
00426 op->contr->blocked_los[op->contr->socket.mapx/2][op->contr->socket.mapy/2] = MAX_DARKNESS-3;
00427
00428 for (x = -1; x <= 1; x++)
00429 for (y = -1; y <= 1; y++) {
00430 if (op->contr->blocked_los[x+op->contr->socket.mapx/2][y+op->contr->socket.mapy/2] > (MAX_DARKNESS-2))
00431 op->contr->blocked_los[x+op->contr->socket.mapx/2][y+op->contr->socket.mapy/2] = MAX_DARKNESS-2;
00432 }
00433 }
00434
00435 for (x = darklevel-MAX_DARKNESS; x < MAX_DARKNESS+1-darklevel; x++)
00436 for (y = darklevel-MAX_DARKNESS; y < MAX_DARKNESS+1-darklevel; y++)
00437 if (!(op->contr->blocked_los[x+op->contr->socket.mapx/2][y+op->contr->socket.mapy/2] == 100))
00438 op->contr->blocked_los[x+op->contr->socket.mapx/2][y+op->contr->socket.mapy/2] -= MAX(0, 6-darklevel-MAX(abs(x), abs(y)));
00439 }
00440
00450 static void blinded_sight(object *op) {
00451 int x, y;
00452
00453 for (x = 0; x < op->contr->socket.mapx; x++)
00454 for (y = 0; y < op->contr->socket.mapy; y++)
00455 op->contr->blocked_los[x][y] = 100;
00456
00457 op->contr->blocked_los[op->contr->socket.mapx/2][op->contr->socket.mapy/2] = 0;
00458 }
00459
00467 void update_los(object *op) {
00468 int dx = op->contr->socket.mapx/2, dy = op->contr->socket.mapy/2, x, y;
00469
00470 if (QUERY_FLAG(op, FLAG_REMOVED))
00471 return;
00472
00473 clear_los(op);
00474 if (QUERY_FLAG(op, FLAG_WIZ) )
00475 return;
00476
00477
00478
00479
00480
00481
00482 for (x = (MAP_CLIENT_X-op->contr->socket.mapx)/2+1; x < (MAP_CLIENT_X+op->contr->socket.mapx)/2-1; x++)
00483 for (y = (MAP_CLIENT_Y-op->contr->socket.mapy)/2+1; y < (MAP_CLIENT_Y+op->contr->socket.mapy)/2-1; y++)
00484 check_wall(op, x, y);
00485
00486
00487
00488 if (QUERY_FLAG(op, FLAG_BLIND))
00489 blinded_sight(op);
00490 else
00491 expand_sight(op);
00492
00493 if (QUERY_FLAG(op, FLAG_XRAYS)) {
00494 int x, y;
00495 for (x = -2; x <= 2; x++)
00496 for (y = -2; y <= 2; y++)
00497 op->contr->blocked_los[dx+x][dy+y] = 0;
00498 }
00499 }
00500
00516 void update_all_map_los(mapstruct *map) {
00517 player *pl;
00518
00519 for (pl = first_player; pl != NULL; pl = pl->next) {
00520 if (pl->ob->map == map)
00521 pl->do_los = 1;
00522 }
00523 }
00524
00544 void update_all_los(const mapstruct *map, int x, int y) {
00545 player *pl;
00546
00547 for (pl = first_player; pl != NULL; pl = pl->next) {
00548
00549
00550
00551 if (!pl->ob->map)
00552 continue;
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 if (pl->ob->map == map) {
00564 if ((abs(pl->ob->x-x) <= pl->socket.mapx/2)
00565 && (abs(pl->ob->y-y) <= pl->socket.mapy/2))
00566 pl->do_los = 1;
00567 }
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 else if (pl->ob->map == map->tile_map[0]) {
00585 if ((abs(pl->ob->x-x) <= pl->socket.mapx/2)
00586 && (abs(y+MAP_HEIGHT(map->tile_map[0])-pl->ob->y) <= pl->socket.mapy/2))
00587 pl->do_los = 1;
00588 } else if (pl->ob->map == map->tile_map[2]) {
00589 if ((abs(pl->ob->x-x) <= pl->socket.mapx/2)
00590 && (abs(pl->ob->y+MAP_HEIGHT(map)-y) <= pl->socket.mapy/2))
00591 pl->do_los = 1;
00592 } else if (pl->ob->map == map->tile_map[1]) {
00593 if ((abs(pl->ob->x+MAP_WIDTH(map)-x) <= pl->socket.mapx/2)
00594 && (abs(pl->ob->y-y) <= pl->socket.mapy/2))
00595 pl->do_los = 1;
00596 } else if (pl->ob->map == map->tile_map[3]) {
00597 if ((abs(x+MAP_WIDTH(map->tile_map[3])-pl->ob->x) <= pl->socket.mapx/2)
00598 && (abs(pl->ob->y-y) <= pl->socket.mapy/2))
00599 pl->do_los = 1;
00600 }
00601 }
00602 }
00603
00614 void print_los(object *op) {
00615 int x, y;
00616 char buf[MAP_CLIENT_X*2+20], buf2[10];
00617
00618 snprintf(buf, sizeof(buf), "[fixed] ");
00619 for (x = 0; x < op->contr->socket.mapx; x++) {
00620 snprintf(buf2, sizeof(buf2), "%2d", x);
00621 strncat(buf, buf2, sizeof(buf)-strlen(buf)-1);
00622 }
00623 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, buf, NULL);
00624 for (y = 0; y < op->contr->socket.mapy; y++) {
00625 snprintf(buf, sizeof(buf), "[fixed]%2d:", y);
00626 for (x = 0; x < op->contr->socket.mapx; x++) {
00627 snprintf(buf2, sizeof(buf2), " %1d", op->contr->blocked_los[x][y] == 100 ? 1 : 0);
00628 strncat(buf, buf2, sizeof(buf)-strlen(buf)-1);
00629 }
00630 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_DEBUG, buf, NULL);
00631 }
00632 }
00633
00644 void make_sure_seen(const object *op) {
00645 player *pl;
00646
00647 for (pl = first_player; pl; pl = pl->next)
00648 if (pl->ob->map == op->map
00649 && pl->ob->y-pl->socket.mapy/2 <= op->y
00650 && pl->ob->y+pl->socket.mapy/2 >= op->y
00651 && pl->ob->x-pl->socket.mapx/2 <= op->x
00652 && pl->ob->x+pl->socket.mapx/2 >= op->x)
00653 pl->blocked_los[pl->socket.mapx/2+op->x-pl->ob->x][pl->socket.mapy/2+op->y-pl->ob->y] = 0;
00654 }
00655
00667 void make_sure_not_seen(const object *op) {
00668 player *pl;
00669
00670 for (pl = first_player; pl; pl = pl->next)
00671 if (pl->ob->map == op->map
00672 && pl->ob->y-pl->socket.mapy/2 <= op->y
00673 && pl->ob->y+pl->socket.mapy/2 >= op->y
00674 && pl->ob->x-pl->socket.mapx/2 <= op->x
00675 && pl->ob->x+pl->socket.mapx/2 >= op->x)
00676 pl->do_los = 1;
00677 }