… | |
… | |
267 | |
267 | |
268 | return 0; |
268 | return 0; |
269 | } |
269 | } |
270 | |
270 | |
271 | /* radius, distance => lightness adjust */ |
271 | /* radius, distance => lightness adjust */ |
272 | static sint8 darkness[MAX_LIGHT_RADIUS * 2 + 1][MAX_LIGHT_RADIUS * 3 / 2 + 1]; |
272 | static sint8 light_atten[MAX_LIGHT_RADIUS * 2 + 1][MAX_LIGHT_RADIUS * 3 / 2 + 1]; |
|
|
273 | static sint8 vision_atten[MAX_DARKNESS + 1][MAX_DARKNESS * 3 / 2 + 1]; |
273 | |
274 | |
274 | static struct darkness_init |
275 | static struct los_init |
275 | { |
276 | { |
276 | darkness_init () |
277 | los_init () |
277 | { |
278 | { |
|
|
279 | /* for lights */ |
278 | for (int radius = -MAX_LIGHT_RADIUS; radius <= MAX_LIGHT_RADIUS; ++radius) |
280 | for (int radius = -MAX_LIGHT_RADIUS; radius <= MAX_LIGHT_RADIUS; ++radius) |
279 | for (int distance = 0; distance <= MAX_LIGHT_RADIUS * 3 / 2; ++distance) |
281 | for (int distance = 0; distance <= MAX_LIGHT_RADIUS * 3 / 2; ++distance) |
280 | { |
282 | { |
281 | // max intensity |
283 | // max intensity |
282 | int intensity = min (LOS_MAX, abs (radius) + 1); |
284 | int intensity = min (LOS_MAX, abs (radius) + 1); |
283 | |
285 | |
284 | // actual intensity |
286 | // actual intensity |
285 | intensity = max (0, lerp_rd (distance, 0, abs (radius) + 1, intensity, 0)); |
287 | intensity = max (0, lerp_rd (distance, 0, abs (radius) + 1, intensity, 0)); |
286 | |
288 | |
287 | darkness [radius + MAX_LIGHT_RADIUS][distance] = radius < 0 |
289 | light_atten [radius + MAX_LIGHT_RADIUS][distance] = radius < 0 |
288 | ? min (3, intensity) |
290 | ? min (3, intensity) |
289 | : LOS_MAX - intensity; |
291 | : LOS_MAX - intensity; |
290 | } |
292 | } |
|
|
293 | |
|
|
294 | /* for general vision */ |
|
|
295 | for (int radius = 0; radius <= MAX_DARKNESS; ++radius) |
|
|
296 | for (int distance = 0; distance <= MAX_DARKNESS * 3 / 2; ++distance) |
|
|
297 | { |
|
|
298 | vision_atten [radius][distance] = distance <= radius ? 3 : 4; |
|
|
299 | } |
291 | } |
300 | } |
292 | } darkness_init; |
301 | } los_init; |
293 | |
302 | |
294 | sint8 |
303 | sint8 |
295 | los_brighten (sint8 b, sint8 l) |
304 | los_brighten (sint8 b, sint8 l) |
296 | { |
305 | { |
297 | return b == LOS_BLOCKED ? b : min (b, l); |
306 | return b == LOS_BLOCKED ? b : min (b, l); |
… | |
… | |
303 | return max (b, l); |
312 | return max (b, l); |
304 | } |
313 | } |
305 | |
314 | |
306 | template<sint8 change_it (sint8, sint8)> |
315 | template<sint8 change_it (sint8, sint8)> |
307 | static void |
316 | static void |
308 | apply_light (object *op, int dx, int dy, int light, const sint8 *darkness_table) |
317 | apply_light (object *op, int dx, int dy, int light, const sint8 *atten_table) |
309 | { |
318 | { |
310 | // min or max the circular area around basex, basey |
319 | // min or max the circular area around basex, basey |
311 | player *pl = op->contr; |
320 | player *pl = op->contr; |
312 | |
321 | |
313 | dx += LOS_X0; |
322 | dx += LOS_X0; |
… | |
… | |
322 | int ay1 = min (dy + light, LOS_Y0 + hy); |
331 | int ay1 = min (dy + light, LOS_Y0 + hy); |
323 | |
332 | |
324 | for (int ax = ax0; ax <= ax1; ax++) |
333 | for (int ax = ax0; ax <= ax1; ax++) |
325 | for (int ay = ay0; ay <= ay1; ay++) |
334 | for (int ay = ay0; ay <= ay1; ay++) |
326 | pl->los[ax][ay] = |
335 | pl->los[ax][ay] = |
327 | change_it (pl->los[ax][ay], darkness_table [idistance (ax - dx, ay - dy)]); |
336 | change_it (pl->los[ax][ay], atten_table [idistance (ax - dx, ay - dy)]); |
328 | } |
337 | } |
329 | |
338 | |
330 | /* add light, by finding all (non-null) nearby light sources, then |
339 | /* add light, by finding all (non-null) nearby light sources, then |
331 | * mark those squares specially. |
340 | * mark those squares specially. |
332 | */ |
341 | */ |
… | |
… | |
394 | |
403 | |
395 | if (expect_false (light)) |
404 | if (expect_false (light)) |
396 | if (light < 0) |
405 | if (light < 0) |
397 | pass2 = 1; |
406 | pass2 = 1; |
398 | else |
407 | else |
399 | apply_light<los_brighten> (op, x - op->x, y - op->y, light, darkness [light + MAX_LIGHT_RADIUS]); |
408 | apply_light<los_brighten> (op, x - op->x, y - op->y, light, light_atten [light + MAX_LIGHT_RADIUS]); |
400 | } |
409 | } |
401 | |
410 | |
402 | /* grant some vision to the player, based on the darklevel */ |
411 | /* grant some vision to the player, based on the darklevel */ |
403 | /* for outdoor maps, ensure some mininum visibility radius */ |
|
|
404 | { |
412 | { |
405 | int light = clamp (MAX_DARKNESS - darklevel, op->map->outdoor ? 2 : 0, MAX_LIGHT_RADIUS); |
413 | int light = clamp (MAX_DARKNESS - darklevel, 0, MAX_DARKNESS); |
406 | |
414 | |
407 | apply_light<los_brighten> (op, 0, 0, light, darkness [light + MAX_LIGHT_RADIUS]); |
415 | apply_light<los_brighten> (op, 0, 0, light, vision_atten [light]); |
408 | } |
416 | } |
409 | } |
417 | } |
410 | |
418 | |
411 | // possibly do 2nd pass for rare negative glow radii |
419 | // possibly do 2nd pass for rare negative glow radii |
412 | // for effect, those are always considered to be stronger than anything else |
420 | // for effect, those are always considered to be stronger than anything else |
… | |
… | |
425 | mapspace &ms = m->at (nx, ny); |
433 | mapspace &ms = m->at (nx, ny); |
426 | ms.update (); |
434 | ms.update (); |
427 | sint8 light = ms.light; |
435 | sint8 light = ms.light; |
428 | |
436 | |
429 | if (expect_false (light < 0)) |
437 | if (expect_false (light < 0)) |
430 | apply_light<los_darken> (op, x - op->x, y - op->y, -light, darkness [light + MAX_LIGHT_RADIUS]); |
438 | apply_light<los_darken> (op, x - op->x, y - op->y, -light, light_atten [light + MAX_LIGHT_RADIUS]); |
431 | } |
439 | } |
432 | } |
440 | } |
433 | |
441 | |
434 | /* blinded_sight() - sets all viewable squares to blocked except |
442 | /* blinded_sight() - sets all viewable squares to blocked except |
435 | * for the one the central one that the player occupies. A little |
443 | * for the one the central one that the player occupies. A little |
… | |
… | |
437 | * really need for any reasonable game play. |
445 | * really need for any reasonable game play. |
438 | */ |
446 | */ |
439 | static void |
447 | static void |
440 | blinded_sight (object *op) |
448 | blinded_sight (object *op) |
441 | { |
449 | { |
442 | op->contr->los[LOS_X0][LOS_Y0] = 3; |
450 | op->contr->los[LOS_X0][LOS_Y0] = 1; |
443 | } |
451 | } |
444 | |
452 | |
445 | /* |
453 | /* |
446 | * update_los() recalculates the array which specifies what is |
454 | * update_los() recalculates the array which specifies what is |
447 | * visible for the given player-object. |
455 | * visible for the given player-object. |
… | |
… | |
482 | * change_map_light function |
490 | * change_map_light function |
483 | */ |
491 | */ |
484 | void |
492 | void |
485 | update_all_map_los (maptile *map) |
493 | update_all_map_los (maptile *map) |
486 | { |
494 | { |
487 | for_all_players (pl) |
495 | for_all_players_on_map (pl, map) |
488 | if (pl->ob && pl->ob->map == map) |
|
|
489 | pl->do_los = 1; |
496 | pl->do_los = 1; |
490 | } |
497 | } |
491 | |
498 | |
492 | /* |
499 | /* |
493 | * This function makes sure that update_los() will be called for all |
500 | * This function makes sure that update_los() will be called for all |
494 | * players on the given map within the next frame. |
501 | * players on the given map within the next frame. |
… | |
… | |
502 | * map is the map that changed, x and y are the coordinates. |
509 | * map is the map that changed, x and y are the coordinates. |
503 | */ |
510 | */ |
504 | void |
511 | void |
505 | update_all_los (const maptile *map, int x, int y) |
512 | update_all_los (const maptile *map, int x, int y) |
506 | { |
513 | { |
|
|
514 | map->at (x, y).invalidate (); |
|
|
515 | |
507 | for_all_players (pl) |
516 | for_all_players (pl) |
508 | { |
517 | { |
509 | /* Player should not have a null map, but do this |
518 | /* Player should not have a null map, but do this |
510 | * check as a safety |
519 | * check as a safety |
511 | */ |
520 | */ |