--- deliantra/server/common/los.C 2008/12/19 22:47:29 1.41 +++ deliantra/server/common/los.C 2008/12/23 01:51:27 1.47 @@ -35,12 +35,12 @@ struct los_info { - sint8 xo, yo; // obscure angle - sint8 xe, ye; // angle deviation - uint8 culled; - uint8 queued; + sint8 xo, yo; // obscure angle + sint8 xe, ye; // angle deviation + uint8 culled; // culled from "tree" + uint8 queued; // already queued uint8 visible; - uint8 flags; + uint8 flags; // LOS_XI/YI }; // temporary storage for the los algorithm, @@ -64,9 +64,9 @@ * controlling the object. */ void -clear_los (player *pl) +player::clear_los (sint8 value) { - memset (pl->los, LOS_BLOCKED, sizeof (pl->los)); + memset (los, value, sizeof (los)); } // enqueue a single mapspace, but only if it hasn't @@ -269,12 +269,14 @@ } /* radius, distance => lightness adjust */ -static sint8 darkness[MAX_LIGHT_RADIUS * 2 + 1][MAX_LIGHT_RADIUS * 3 / 2 + 1]; +static sint8 light_atten[MAX_LIGHT_RADIUS * 2 + 1][MAX_LIGHT_RADIUS * 3 / 2 + 1]; +static sint8 vision_atten[MAX_DARKNESS + 1][MAX_DARKNESS * 3 / 2 + 1]; -static struct darkness_init +static struct los_init { - darkness_init () + los_init () { + /* for lights */ for (int radius = -MAX_LIGHT_RADIUS; radius <= MAX_LIGHT_RADIUS; ++radius) for (int distance = 0; distance <= MAX_LIGHT_RADIUS * 3 / 2; ++distance) { @@ -284,12 +286,19 @@ // actual intensity intensity = max (0, lerp_rd (distance, 0, abs (radius) + 1, intensity, 0)); - darkness [radius + MAX_LIGHT_RADIUS][distance] = radius < 0 + light_atten [radius + MAX_LIGHT_RADIUS][distance] = radius < 0 ? min (3, intensity) : LOS_MAX - intensity; } + + /* for general vision */ + for (int radius = 0; radius <= MAX_DARKNESS; ++radius) + for (int distance = 0; distance <= MAX_DARKNESS * 3 / 2; ++distance) + { + vision_atten [radius][distance] = distance <= radius ? 3 : 4; + } } -} darkness_init; +} los_init; sint8 los_brighten (sint8 b, sint8 l) @@ -305,7 +314,7 @@ template static void -apply_light (object *op, int dx, int dy, int light, const sint8 *darkness_table) +apply_light (object *op, int dx, int dy, int light, const sint8 *atten_table) { // min or max the circular area around basex, basey player *pl = op->contr; @@ -324,7 +333,7 @@ for (int ax = ax0; ax <= ax1; ax++) for (int ay = ay0; ay <= ay1; ay++) pl->los[ax][ay] = - change_it (pl->los[ax][ay], darkness_table [idistance (ax - dx, ay - dy)]); + change_it (pl->los[ax][ay], atten_table [idistance (ax - dx, ay - dy)]); } /* add light, by finding all (non-null) nearby light sources, then @@ -337,11 +346,11 @@ maptile *m = op->map; sint16 nx, ny; - darklevel = m->darkness; + darklevel = m->darklevel (); /* If the player can see in the dark, lower the darklevel for him */ if (QUERY_FLAG (op, FLAG_SEE_IN_DARK)) - darklevel -= LOS_MAX / 2; + darklevel -= 2; /* Do a sanity check. If not valid, some code below may do odd * things. @@ -396,15 +405,14 @@ if (light < 0) pass2 = 1; else - apply_light (op, x - op->x, y - op->y, light, darkness [light + MAX_LIGHT_RADIUS]); + apply_light (op, x - op->x, y - op->y, light, light_atten [light + MAX_LIGHT_RADIUS]); } /* grant some vision to the player, based on the darklevel */ - /* for outdoor maps, ensure some mininum visibility radius */ { - int light = clamp (MAX_DARKNESS - darklevel, op->map->outdoor ? 2 : 0, MAX_LIGHT_RADIUS); + int light = clamp (MAX_DARKNESS - darklevel, 0, MAX_DARKNESS); - apply_light (op, 0, 0, light, darkness [light + MAX_LIGHT_RADIUS]); + apply_light (op, 0, 0, light, vision_atten [light]); } } @@ -427,7 +435,7 @@ sint8 light = ms.light; if (expect_false (light < 0)) - apply_light (op, x - op->x, y - op->y, -light, darkness [light + MAX_LIGHT_RADIUS]); + apply_light (op, x - op->x, y - op->y, -light, light_atten [light + MAX_LIGHT_RADIUS]); } } @@ -439,7 +447,7 @@ static void blinded_sight (object *op) { - op->contr->los[LOS_X0][LOS_Y0] = 3; + op->contr->los[LOS_X0][LOS_Y0] = 1; } /* @@ -452,7 +460,7 @@ if (QUERY_FLAG (op, FLAG_REMOVED)) return; - clear_los (op->contr); + op->contr->clear_los (); if (QUERY_FLAG (op, FLAG_WIZ) /* ||XRAYS(op) */ ) memset (op->contr->los, 0, sizeof (op->contr->los)); @@ -467,7 +475,7 @@ if (QUERY_FLAG (op, FLAG_XRAYS)) for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) - op->contr->los[dx + LOS_X0][dy + LOS_X0] = 0; + min_it (op->contr->los[dx + LOS_X0][dy + LOS_X0], 1); } /* update all_map_los is like update_all_los below, @@ -484,9 +492,8 @@ void update_all_map_los (maptile *map) { - for_all_players (pl) - if (pl->ob && pl->ob->map == map) - pl->do_los = 1; + for_all_players_on_map (pl, map) + pl->do_los = 1; } /* @@ -504,6 +511,8 @@ void update_all_los (const maptile *map, int x, int y) { + map->at (x, y).invalidate (); + for_all_players (pl) { /* Player should not have a null map, but do this @@ -565,6 +574,59 @@ } } +static const int season_timechange[5][HOURS_PER_DAY] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2 3 4 5 6 7 8 9 10 11 12 13 */ + { 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + { 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0}, + { 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0}, + { 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0}, + { 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0} +}; + +void +maptile::set_darkness_map () +{ + timeofday_t tod; + + if (!outdoor) + return; + + get_tod (&tod); + darkness = 0; + + for (int i = HOURS_PER_DAY / 2; i < HOURS_PER_DAY; i++) + change_map_light (season_timechange[tod.season][i]); + + for (int i = 0; i <= tod.hour; i++) + change_map_light (season_timechange[tod.season][i]); +} + +/* + * Compute the darkness level for all maps in the game. Requires the + * time of day as an argument. + */ + +static void +dawn_to_dusk (const timeofday_t * tod) +{ + /* If the light level isn't changing, no reason to do all + * the work below. + */ + if (season_timechange[tod->season][tod->hour] == 0) + return; + + maptile::change_all_map_light (season_timechange[tod->season][tod->hour]); +} + +void +adjust_daylight () +{ + timeofday_t tod; + + get_tod (&tod); + dawn_to_dusk (&tod); +} + /* * make_sure_seen: The object is supposed to be visible through walls, thus * check if any players are nearby, and edit their LOS array.