--- deliantra/server/common/los.C 2008/12/23 06:58:23 1.48 +++ deliantra/server/common/los.C 2008/12/23 22:03:06 1.49 @@ -21,26 +21,27 @@ * The authors can be reached via e-mail to */ -/* Nov 95 - inserted USE_LIGHTING code stuff in here - b.t. */ - +#include //D #include #include -static void expand_lighted_sight (object *op); - +// los flags enum { - LOS_XI = 0x01, - LOS_YI = 0x02, + FLG_XI = 0x01, // we have an x-parent + FLG_YI = 0x02, // we have an y-parent + FLG_BLOCKED = 0x04, // this space blocks the view + FLG_QUEUED = 0x80 // already queued in queue, or border }; struct los_info { - sint8 xo, yo; // obscure angle - sint8 xe, ye; // angle deviation + uint8 flags; // FLG_xxx uint8 culled; // culled from "tree" - uint8 queued; // already queued uint8 visible; - uint8 flags; // LOS_XI/YI + uint8 pad0; + + sint8 xo, yo; // obscure angle + sint8 xe, ye; // angle deviation }; // temporary storage for the los algorithm, @@ -77,17 +78,14 @@ sint8 x = LOS_X0 + dx; sint8 y = LOS_Y0 + dy; - if (x < 0 || x >= MAP_CLIENT_X) return; - if (y < 0 || y >= MAP_CLIENT_Y) return; - los_info &l = los[x][y]; l.flags |= flags; - if (l.queued) + if (l.flags & FLG_QUEUED) return; - l.queued = 1; + l.flags |= FLG_QUEUED; queue[q1].x = dx; queue[q1].y = dy; @@ -103,9 +101,33 @@ static void calculate_los (player *pl) { - int max_radius = max (pl->ns->mapx, pl->ns->mapy) / 2; - - memset (los, 0, sizeof (los)); + { + // we keep one line for ourselves, for the border flag + // so the client area is actually MAP_CLIENT_(X|Y) - 2 + int half_x = min (LOS_X0 - 1, pl->ns->mapx / 2); + int half_y = min (LOS_Y0 - 1, pl->ns->mapy / 2); + + // create borders, the corners are not touched + for (int dx = -half_x; dx <= half_x; ++dx) + los [dx + LOS_X0][LOS_Y0 - (half_y + 1)].flags = + los [dx + LOS_X0][LOS_Y0 + (half_y + 1)].flags = FLG_QUEUED; + + for (int dy = -half_y; dy <= half_y; ++dy) + los [LOS_X0 - (half_x + 1)][dy + LOS_Y0].flags = + los [LOS_X0 + (half_x + 1)][dy + LOS_Y0].flags = FLG_QUEUED; + + // now reset the los area and also add blocked flags + // which supposedly is faster than doing it inside the + // spiral path algorithm below, except when very little + // area is visible, in which case it is slower, evening + // out los calculation times between large and small los maps. + // apply_lights also iterates over this area, maybe these + // two passes could be combined somehow. + rectangular_mapspace_iterate_begin (pl->observe, -half_x, half_x, -half_y, half_y) + los_info &l = los [LOS_X0 + dx][LOS_Y0 + dy]; + l.flags = m && m->at (nx, ny).flags () & P_BLOCKSVIEW ? FLG_BLOCKED : 0; + rectangular_mapspace_iterate_end + } q1 = 0; q2 = 0; // initialise queue, not strictly required enqueue (0, 0); // enqueue center @@ -128,17 +150,15 @@ sint8 x = LOS_X0 + dx; sint8 y = LOS_Y0 + dy; - //int distance = idistance (dx, dy); if (distance > max_radius) continue;//D - int distance = 0;//D - los_info &l = los[x][y]; - if (expect_true (l.flags & (LOS_XI | LOS_YI))) + if (expect_true (l.flags & (FLG_XI | FLG_YI))) { l.culled = 1; + l.xo = l.yo = l.xe = l.ye = 0; // check contributing spaces, first horizontal - if (expect_true (l.flags & LOS_XI)) + if (expect_true (l.flags & FLG_XI)) { los_info *xi = &los[x - sign (dx)][y]; @@ -173,7 +193,7 @@ } // check contributing spaces, last vertical, identical structure - if (expect_true (l.flags & LOS_YI)) + if (expect_true (l.flags & FLG_YI)) { los_info *yi = &los[x][y - sign (dy)]; @@ -207,13 +227,7 @@ } } - // check whether this space blocks the view - maptile *m = pl->observe->map; - sint16 nx = pl->observe->x + dx; - sint16 ny = pl->observe->y + dy; - - if (expect_true (!xy_normalise (m, nx, ny)) - || expect_false (m->at (nx, ny).flags () & P_BLOCKSVIEW)) + if (l.flags & FLG_BLOCKED) { l.xo = l.xe = abs (dx); l.yo = l.ye = abs (dy); @@ -222,6 +236,7 @@ // copy the los from the square towards the player, // so outward diagonal corners are lit. pl->los[x][y] = los[x - sign0 (dx)][y - sign0 (dy)].visible ? 0 : LOS_BLOCKED; + l.visible = false; } else @@ -232,7 +247,7 @@ && (l.ye <= 0 || l.ye > l.yo); pl->los[x][y] = l.culled ? LOS_BLOCKED - : l.visible ? max (0, 2 - max_radius + distance) + : l.visible ? 0 : 3; } @@ -243,10 +258,10 @@ // positive and negative directions. if (!l.culled) { - if (dx >= 0) enqueue (dx + 1, dy, LOS_XI); - if (dx <= 0) enqueue (dx - 1, dy, LOS_XI); - if (dy >= 0) enqueue (dx, dy + 1, LOS_YI); - if (dy <= 0) enqueue (dx, dy - 1, LOS_YI); + if (dx >= 0) enqueue (dx + 1, dy, FLG_XI); + if (dx <= 0) enqueue (dx - 1, dy, FLG_XI); + if (dy >= 0) enqueue (dx, dy + 1, FLG_YI); + if (dy <= 0) enqueue (dx, dy - 1, FLG_YI); } } } @@ -274,6 +289,9 @@ { los_init () { + assert (("QUEUE_LENGTH, MAP_CLIENT_X and MAP_CLIENT_Y *must* be powers of two", + !(QUEUE_LENGTH & (QUEUE_LENGTH - 1)))); + /* for lights */ for (int radius = -MAX_LIGHT_RADIUS; radius <= MAX_LIGHT_RADIUS; ++radius) for (int distance = 0; distance <= MAX_LIGHT_RADIUS * 3 / 2; ++distance) @@ -348,11 +366,6 @@ int half_x = pl->ns->mapx / 2; int half_y = pl->ns->mapy / 2; - int min_x = op->x - half_x - MAX_LIGHT_RADIUS; - int min_y = op->y - half_y - MAX_LIGHT_RADIUS; - int max_x = op->x + half_x + MAX_LIGHT_RADIUS; - int max_y = op->y + half_y + MAX_LIGHT_RADIUS; - int pass2 = 0; // negative lights have an extra pass if (!darklevel) @@ -362,8 +375,7 @@ /* first, make everything totally dark */ for (int dx = -half_x; dx <= half_x; dx++) for (int dy = -half_x; dy <= half_y; dy++) - if (pl->los[dx + LOS_X0][dy + LOS_Y0] != LOS_BLOCKED) - pl->los[dx + LOS_X0][dy + LOS_Y0] = LOS_MAX; + max_it (pl->los[dx + LOS_X0][dy + LOS_Y0], LOS_MAX); /* * Only process the area of interest. @@ -371,16 +383,9 @@ * array. Its easier to just increment them here (and start with the right * value) than to recalculate them down below. */ - for (int x = min_x; x <= max_x; x++) - for (int y = min_y; y <= max_y; y++) + rectangular_mapspace_iterate_begin (pl->observe, -half_x - MAX_LIGHT_RADIUS, half_x + MAX_LIGHT_RADIUS, -half_y - MAX_LIGHT_RADIUS, half_y + MAX_LIGHT_RADIUS) + if (m) { - maptile *m = pl->observe->map; - sint16 nx = x; - sint16 ny = y; - - if (!xy_normalise (m, nx, ny)) - continue; - mapspace &ms = m->at (nx, ny); ms.update (); sint8 light = ms.light; @@ -389,8 +394,9 @@ if (light < 0) pass2 = 1; else - apply_light (pl, x - op->x, y - op->y, light, light_atten [light + MAX_LIGHT_RADIUS]); + apply_light (pl, dx, dy, light, light_atten [light + MAX_LIGHT_RADIUS]); } + rectangular_mapspace_iterate_end /* grant some vision to the player, based on the darklevel */ { @@ -404,23 +410,17 @@ // for effect, those are always considered to be stronger than anything else // but they can't darken a place completely if (pass2) - for (int x = min_x; x <= max_x; x++) - for (int y = min_y; y <= max_y; y++) - { - maptile *m = pl->observe->map; - sint16 nx = x; - sint16 ny = y; - - if (!xy_normalise (m, nx, ny)) - continue; - - mapspace &ms = m->at (nx, ny); - ms.update (); - sint8 light = ms.light; - - if (expect_false (light < 0)) - apply_light (pl, x - op->x, y - op->y, -light, light_atten [light + MAX_LIGHT_RADIUS]); - } + rectangular_mapspace_iterate_begin (pl->observe, -half_x - MAX_LIGHT_RADIUS, half_x + MAX_LIGHT_RADIUS, -half_y - MAX_LIGHT_RADIUS, half_y + MAX_LIGHT_RADIUS) + if (m) + { + mapspace &ms = m->at (nx, ny); + ms.update (); + sint8 light = ms.light; + + if (expect_false (light < 0)) + apply_light (pl, dx, dy, -light, light_atten [light + MAX_LIGHT_RADIUS]); + } + rectangular_mapspace_iterate_end } /* blinded_sight() - sets all viewable squares to blocked except @@ -444,14 +444,16 @@ if (ob->flag [FLAG_REMOVED])//D really needed? return; - clear_los (); - if (ob->flag [FLAG_WIZLOOK]) - memset (los, 0, sizeof (los)); + clear_los (0); else if (observe->flag [FLAG_BLIND]) /* player is blind */ - blinded_sight (this); + { + clear_los (); + blinded_sight (this); + } else { + clear_los (); calculate_los (this); apply_lights (this); } @@ -459,7 +461,7 @@ if (observe->flag [FLAG_XRAYS]) for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) - min_it (los[dx + LOS_X0][dy + LOS_X0], 1); + min_it (los[dx + LOS_X0][dy + LOS_Y0], 1); } /* update all_map_los is like update_all_los below, @@ -620,7 +622,7 @@ if (pl->ob->map == op->map && pl->ob->y - pl->ns->mapy / 2 <= op->y && 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) - pl->los[op->x - pl->ob->x + LOS_X0][op->y - pl->ob->y + LOS_X0] = 0; + pl->los[op->x - pl->ob->x + LOS_X0][op->y - pl->ob->y + LOS_Y0] = 0; } /*