Source:SLASH'EM 0.0.7E7F2/light.c

Below is the full text to light.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/light.c#line123 ]], for example.

The latest source code for vanilla NetHack is at Source code.

1.   /*	SCCS Id: @(#)light.c	3.4	1997/04/10	*/ 2.   /* Copyright (c) Dean Luick, 1994					*/ 3.   /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    #include "lev.h"	/* for checking save modes */ 7.    8.    /*  9.     * Mobile light sources. 10.   *  11.    * This implementation minimizes memory at the expense of extra 12.   * recalculations. 13.   *  14.    * Light sources are "things" that have a physical position and range. 15.   * They have a type, which gives us information about them. Currently 16.   * they are only attached to objects and monsters. Note well: the 17.   * polymorphed-player handling assumes that both youmonst.m_id and 18.   * youmonst.mx will always remain 0. 19.   *  20.    * Light sources, like timers, either follow game play (RANGE_GLOBAL) or  21. * stay on a level (RANGE_LEVEL). Light sources are unique by their 22.   * (type, id) pair. For light sources attached to objects, this id 23. * is a pointer to the object. 24.   *  25.    * The major working function is do_light_sources. It is called 26.   * when the vision system is recreating its "could see" array. Here 27.   * we add a flag (TEMP_LIT) to the array for all locations that are lit 28.   * via a light source. The bad part of this is that we have to 29. * re-calculate the LOS of each light source every time the vision 30.   * system runs. Even if the light sources and any topology (vision blocking 31.    * positions) have not changed. The good part is that no extra memory 32.   * is used, plus we don't have to figure out how far the sources have moved, 33.   * or if the topology has changed. 34.   *  35.    * The structure of the save/restore mechanism is amazingly similar to  36. * the timer save/restore. This is because they both have the same 37.   * principals of having pointers into objects that must be recalculated 38.   * across saves and restores. 39.   */  40.    41.   #ifdef OVL3 42.   43.   /* flags */ 44.  #define LSF_SHOW	0x1		/* display the light source */ 45.  #define LSF_NEEDS_FIXUP	0x2		/* need oid fixup */ 46.  #define LSF_FLOATING	0x4		/* location not yet determined */ 47.   48.   static light_source *light_base = 0; 49.   50.   STATIC_DCL void FDECL(write_ls, (int, light_source *)); 51.  STATIC_DCL int FDECL(maybe_write_ls, (int, int, BOOLEAN_P)); 52.   53.   /* imported from vision.c, for small circles */ 54.  extern char circle_data[]; 55.  extern char circle_start[]; 56.   57.   /* WAC in artifact.c,  for obj_sheds_light*/ 58.  extern boolean FDECL(obj_special_light, (struct obj *)); 59.   60.   /* Create a new light source. */ 61.   void 62.  new_light_source(x, y, range, type, id) 63.      xchar x, y;  64. int range, type; 65.      genericptr_t id; 66.  {  67.       light_source *ls; 68.   69.       if (range > MAX_RADIUS || range < 1) { 70.  	impossible("new_light_source:  illegal range %d", range); 71.  	return; 72.      }  73.    74.       ls = (light_source *) alloc(sizeof(light_source)); 75.   76.       ls->next = light_base; 77.      ls->x = x;  78. ls->y = y; 79. ls->range = range; 80.      ls->type = type; 81.      ls->id = id; 82.      if (ls->type != LS_TEMP && x == 0) 83.  	ls->flags = LSF_FLOATING; 84.      else 85.      ls->flags = 0; 86.      light_base = ls; 87.   88.       vision_full_recalc = 1;	/* make the source show up */ 89.  }  90.    91.   /*  92.    * Delete a light source. This assumes only one light source is attached 93.   * to an object at a time. 94.   */  95.   void 96.  del_light_source(type, id) 97.      int type; 98.      genericptr_t id; 99.  {  100.      light_source *curr, *prev; 101.     genericptr_t tmp_id; 102.  103.      /* need to be prepared for dealing a with light source which 104.        has only been partially restored during a level change 105.        (in particular: chameleon vs prot. from shape changers) */ 106.     switch (type) { 107.     case LS_OBJECT:	tmp_id = (genericptr_t)(((struct obj *)id)->o_id); 108. 			break; 109.     case LS_MONSTER:	tmp_id = (genericptr_t)(((struct monst *)id)->m_id); 110. 			break; 111.     case LS_TEMP:       tmp_id = id; 112.     			break; 113.     default:		tmp_id = 0; 114. 			break; 115.     }  116.   117.      for (prev = 0, curr = light_base; curr; prev = curr, curr = curr->next) { 118. 	if (curr->type != type) continue; 119.         if (curr->id == ((curr->flags & LSF_NEEDS_FIXUP) ? tmp_id : id)) 120.           {  121.  	    if (prev) 122. 		prev->next = curr->next; 123. 	    else 124. 		light_base = curr->next; 125.  126.  	    free((genericptr_t)curr); 127. 	    vision_full_recalc = 1; 128. 	    return; 129. 	}  130.      }  131.      impossible("del_light_source: not found type=%d, id=0x%lx", type, (long)id); 132. }  133.   134.  /* Mark locations that are temporarily lit via mobile light sources. */ 135.  void 136. do_light_sources(cs_rows) 137.     char **cs_rows; 138. {  139.      int x, y, min_x, max_x, max_y, offset; 140.     char *limits; 141.     short at_hero_range = 0; 142.     light_source *ls; 143.     char *row; 144.  145.      for (ls = light_base; ls; ls = ls->next) { 146. 	ls->flags &= ~LSF_SHOW; 147.  148.  	/*  149.  	 * See if floating light source has been finalized yet. 150. 	 * If not, arrange for vision to be recalculated later. 151. 	 */  152.  	if (ls->flags & LSF_FLOATING) { 153. 	    if (ls->type == LS_OBJECT) { 154. 		if (get_obj_location((struct obj *) ls->id, &ls->x, &ls->y, 155. 		  CONTAINED_TOO | BURIED_TOO)) 156. 		    ls->flags &= ~LSF_FLOATING; 157. 	    } else if (ls->type == LS_MONSTER) { 158. 		if (get_mon_location((struct monst *) ls->id, &ls->x, &ls->y, 159. 		  CONTAINED_TOO | BURIED_TOO)) 160. 		    ls->flags &= ~LSF_FLOATING; 161. 	    }  162.  	    if (ls->flags & LSF_FLOATING) { 163. 		vision_full_recalc = 1; 164. 		continue; 165. 	    }  166.  	}  167.  	/*  168.  	 * Check for moved light sources. It may be possible to 169. * save some effort if an object has not moved, but not in 170. * the current setup -- we need to recalculate for every 171. 	 * vision recalc. 172. 	 */  173.  	if (ls->type == LS_OBJECT) { 174. 	    if (get_obj_location((struct obj *) ls->id, &ls->x, &ls->y, 0)) 175. 		ls->flags |= LSF_SHOW; 176. 	} else if (ls->type == LS_MONSTER) { 177. 	    if (get_mon_location((struct monst *) ls->id, &ls->x, &ls->y, 0)) 178. 		ls->flags |= LSF_SHOW; 179.         } else if (ls->type == LS_TEMP) { 180.             ls->flags |= LSF_SHOW; 181. 	}  182.   183.  	/* minor optimization: don't bother with duplicate light sources */ 184. 	/* at hero */ 185. 	if (ls->x == u.ux && ls->y == u.uy) { 186. 	    if (at_hero_range >= ls->range) 187. 		ls->flags &= ~LSF_SHOW; 188. 	    else 189. 		at_hero_range = ls->range; 190. 	}  191.   192.  	if (ls->flags & LSF_SHOW) { 193. 	    /*  194.  	     * Walk the points in the circle and see if they are 195. 	     * visible from the center. If so, mark'em. 196. 	     *  197.  	     * Kevin's tests indicated that doing this brute-force 198. 	     * method is faster for radius <= 3 (or so). 199. 	     */  200.  	    limits = circle_ptr(ls->range); 201. 	    if ((max_y = (ls->y + ls->range)) >= ROWNO) max_y = ROWNO-1; 202. 	    if ((y = (ls->y - ls->range)) < 0) y = 0; 203. 	    for (y <= max_y; y++) { 204. 		row = cs_rows[y]; 205. 		offset = limits[abs(y - ls->y)]; 206. 		if ((min_x = (ls->x - offset)) < 0) min_x = 0; 207. 		if ((max_x = (ls->x + offset)) >= COLNO) max_x = COLNO-1; 208.  209.  		if (ls->x == u.ux && ls->y == u.uy) { 210. 		    /*  211.  		     * If the light source is located at the hero, then 212. 		     * we can use the COULD_SEE bits already calcualted 213. 		     * by the vision system. More importantly than 214. 		     * this optimization, is that it allows the vision 215. 		     * system to correct problems with clear_path. 216. 		     * The function clear_path is a simple LOS 217. 		     * path checker that doesn't go out of its way 218. 		     * make things look "correct". The vision system 219. 		     * does this. 220. 		     */  221.  		    for (x = min_x; x <= max_x; x++) 222. 			if (row[x] & COULD_SEE) 223. 			    row[x] |= TEMP_LIT; 224. 		} else { 225. 		    for (x = min_x; x <= max_x; x++) 226. 			if ((ls->x == x && ls->y == y)  227.  				|| clear_path((int)ls->x, (int) ls->y, x, y)) 228. 			    row[x] |= TEMP_LIT; 229. 		}  230.  	    }  231.  	}  232.      }  233.  }  234.   235.  /* (mon->mx == 0) implies migrating */ 236. #define mon_is_local(mon)	((mon)->mx > 0) 237.  238.  struct monst * 239. find_mid(nid, fmflags) 240. unsigned nid; 241. unsigned fmflags; 242. {  243.  	struct monst *mtmp; 244.  245.  	if (!nid) 246. 	    return &youmonst; 247. 	if (fmflags & FM_FMON) 248. 		for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 249. 		    if (!DEADMONSTER(mtmp) && mtmp->m_id == nid) return mtmp; 250. 	if (fmflags & FM_MIGRATE) 251. 		for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) 252. 	    	    if (mtmp->m_id == nid) return mtmp; 253. 	if (fmflags & FM_MYDOGS) 254. 		for (mtmp = mydogs; mtmp; mtmp = mtmp->nmon) 255. 	    	    if (mtmp->m_id == nid) return mtmp; 256. 	return (struct monst *) 0; 257. }  258.   259.  /* Save all light sources of the given range. */ 260.  void 261. save_light_sources(fd, mode, range) 262.     int fd, mode, range; 263. {  264.      int count, actual, is_global; 265.     light_source **prev, *curr; 266.  267.      if (perform_bwrite(mode)) { 268. 	count = maybe_write_ls(fd, range, FALSE); 269. 	bwrite(fd, (genericptr_t) &count, sizeof count); 270. 	actual = maybe_write_ls(fd, range, TRUE); 271. 	if (actual != count) 272. 	    panic("counted %d light sources, wrote %d! [range=%d]",  273.  		  count, actual, range); 274.     }  275.   276.      if (release_data(mode)) { 277. 	for (prev = &light_base; (curr = *prev) != 0; ) { 278. 	    if (!curr->id) { 279. 		impossible("save_light_sources: no id! [range=%d]", range); 280. 		is_global = 0; 281. 	    } else 282. 	    switch (curr->type) { 283. 	    case LS_OBJECT: 284. 		is_global = !obj_is_local((struct obj *)curr->id); 285. 		break; 286. 	    case LS_MONSTER: 287. 		is_global = !mon_is_local((struct monst *)curr->id); 288. 		break; 289. 	    case LS_TEMP: 290. 	    	/* Temp light sources should never be saved, but need to  291. * 	set next (or else you get caught in an infinite loop 292.  	    	 */  293.  		prev = &(*prev)->next;  294.  		continue;  295.  	    default:  296.  		is_global = 0;  297.  		impossible("save_light_sources: bad type (%d) [range=%d]", 298. 			   curr->type, range);  299.  		break;  300.  	    }  301.  	    /* if global and not doing local, or vice versa, remove it */  302.  	    if (is_global ^ (range == RANGE_LEVEL)) {  303.  		*prev = curr->next;  304.  		free((genericptr_t)curr);  305.  	    } else {  306.  		prev = &(*prev)->next;  307.  	    }  308.  	}  309.      }  310.  }  311.   312.  /*  313.   * Pull in the structures from disk, but don't recalculate the object  314.   * pointers.  315.   */  316.  void  317.  restore_light_sources(fd)  318.      int fd;  319.  {  320.      int count;  321.      light_source *ls;  322.   323.      /* restore elements */  324.      mread(fd, (genericptr_t) &count, sizeof count);  325.   326.      while (count-- > 0) {  327.  	ls = (light_source *) alloc(sizeof(light_source));  328.  	mread(fd, (genericptr_t) ls, sizeof(light_source));  329.  	ls->next = light_base;  330.  	light_base = ls; 331.     }  332.  }  333.   334.  /* Relink all lights that are so marked. */ 335.  void 336. relink_light_sources(ghostly) 337.     boolean ghostly; 338. {  339.      char which; 340.     unsigned nid; 341.     light_source *ls; 342.  343.      for (ls = light_base; ls; ls = ls->next) { 344. 	if (ls->flags & LSF_NEEDS_FIXUP) { 345. 	    if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { 346. 		if (ghostly) { 347. 		    if (!lookup_id_mapping((unsigned)ls->id, &nid)) 348. 			impossible("relink_light_sources: no id mapping"); 349. 		} else 350. 		    nid = (unsigned) ls->id; 351. 		if (ls->type == LS_OBJECT) { 352. 		    which = 'o'; 353. 		    ls->id = (genericptr_t) find_oid(nid); 354. 		} else { 355. 		    which = 'm'; 356. 		    ls->id = (genericptr_t) find_mid(nid, FM_EVERYWHERE); 357. 		}  358.  		if (!ls->id) 359. 		    impossible("relink_light_sources: cant find %c_id %d",  360.  			       which, nid); 361. 	    } else 362. 		impossible("relink_light_sources: bad type (%d)", ls->type); 363.  364.  	    ls->flags &= ~LSF_NEEDS_FIXUP; 365. 	}  366.      }  367.  }  368.   369.  /*  370.   * Part of the light source save routine. Count up the number of light 371.  * sources that would be written. If write_it is true, actually write 372.  * the light source out. 373.  */  374.  STATIC_OVL int 375. maybe_write_ls(fd, range, write_it) 376.     int fd, range; 377.     boolean write_it; 378. {  379.      int count = 0, is_global; 380.     light_source *ls; 381.  382.      for (ls = light_base; ls; ls = ls->next) { 383. 	if (!ls->id) { 384. 	    impossible("maybe_write_ls: no id! [range=%d]", range); 385. 	    continue; 386. 	}  387.  	switch (ls->type) { 388. 	case LS_OBJECT: 389. 	    is_global = !obj_is_local((struct obj *)ls->id); 390. 	    break; 391. 	case LS_MONSTER: 392. 	    is_global = !mon_is_local((struct monst *)ls->id); 393. 	    break; 394. 		case LS_TEMP: 395. 		    continue; 396. 	default: 397. 	    is_global = 0; 398. 	    impossible("maybe_write_ls: bad type (%d) [range=%d]",  399.  		       ls->type, range); 400. 	    break; 401. 	}  402.  	/* if global and not doing local, or vice versa, count it */ 403. 	if (is_global ^ (range == RANGE_LEVEL)) { 404. 	    count++; 405. 	    if (write_it) write_ls(fd, ls); 406. 	}  407.      }  408.   409.      return count; 410. }  411.   412.  /* Write a light source structure to disk. */ 413.  STATIC_OVL void 414. write_ls(fd, ls) 415.     int fd; 416.     light_source *ls; 417. {  418.      genericptr_t arg_save; 419.     struct obj *otmp; 420.     struct monst *mtmp; 421.  422.      if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { 423. 	if (ls->flags & LSF_NEEDS_FIXUP) 424. 	    bwrite(fd, (genericptr_t)ls, sizeof(light_source)); 425. 	else { 426. 	    /* replace object pointer with id for write, then put back */ 427. 	    arg_save = ls->id; 428. 	    if (ls->type == LS_OBJECT) { 429. 		otmp = (struct obj *)ls->id; 430. 		ls->id = (genericptr_t)otmp->o_id; 431. #ifdef DEBUG 432. 		if (find_oid((unsigned)ls->id) != otmp) 433. 		    panic("write_ls: can't find obj #%u!", (unsigned)ls->id); 434. #endif 435. 	    } else { /* ls->type == LS_MONSTER */ 436. 		mtmp = (struct monst *)ls->id; 437. 		ls->id = (genericptr_t)mtmp->m_id; 438. #ifdef DEBUG 439. 		if (find_mid((unsigned)ls->id, FM_EVERYWHERE) != mtmp) 440. 		    panic("write_ls: can't find mon #%u!", (unsigned)ls->id); 441. #endif 442. 	    }  443.  	    ls->flags |= LSF_NEEDS_FIXUP; 444. 	    bwrite(fd, (genericptr_t)ls, sizeof(light_source)); 445. 	    ls->id = arg_save; 446. 	    ls->flags &= ~LSF_NEEDS_FIXUP; 447. 	}  448.      } else { 449. 	impossible("write_ls: bad type (%d)", ls->type); 450.     }  451.  }  452.   453.  /* Change light source's ID from src to dest. */ 454.  void 455. obj_move_light_source(src, dest) 456.     struct obj *src, *dest; 457. {  458.      light_source *ls; 459.  460.      for (ls = light_base; ls; ls = ls->next) 461. 	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src) 462. 	    ls->id = (genericptr_t) dest; 463.     src->lamplit = 0; 464.     dest->lamplit = 1; 465. }  466.   467.  /* return true if there exist any light sources */ 468. boolean 469. any_light_source 470. {  471.      return light_base != (light_source *) 0; 472. }  473.   474.  /*  475.   * Snuff an object light source if at (x,y). This currently works 476.  * only for burning light sources. 477.  */  478.  void 479. snuff_light_source(x, y)  480. int x, y; 481. { 482.      light_source *ls; 483.     struct obj *obj; 484.  485.      for (ls = light_base; ls; ls = ls->next) 486. 	/*  487.  	Is this position check valid??? Can I assume that the positions 488. 	will always be correct because the objects would have been 489. 	updated with the last vision update? [Is that recent enough???] 490. 	*/  491.  	if (ls->type == LS_OBJECT && ls->x == x && ls->y == y) { 492. 	    obj = (struct obj *) ls->id; 493. 	    if (obj_is_burning(obj)) { 494. 		/* The only way to snuff Sunsword is to unwield it. Darkness 495. 		 * scrolls won't affect it. (If we got here because it was 496.  		 * dropped or thrown inside a monster, this won't matter anyway  497.  		 * because it will go out when dropped.) 498. 		 */  499.  		if (artifact_light(obj)) continue; 500. 		end_burn(obj, obj->otyp != MAGIC_LAMP); 501. 		/*  502.  		 * The current ls element has just been removed (and  503.  		 * ls->next is now invalid). Return assuming that there 504. 		 * is only one light source attached to each object. 505. 		 */  506.  		return; 507. 	    }  508.  	}  509.  }  510.   511.  /* Return TRUE if object sheds any light at all. */ 512.  boolean 513. obj_sheds_light(obj) 514.     struct obj *obj; 515. {  516.      /* so far, only burning objects shed light */ 517.     /* WAC - Some artifacts now shed light */ 518.  519.      return (obj_is_burning(obj) || obj_permanent_light(obj)); 520. }  521.   522.  /* Return TRUE if sheds light AND will be snuffed by end_burn. */ 523.  boolean 524. obj_is_burning(obj) 525.     struct obj *obj; 526. {  527.      return (obj->lamplit &&  528.   		(  obj->otyp == MAGIC_LAMP 529. 		|| obj->otyp == MAGIC_CANDLE 530. 		|| ignitable(obj) 531. #ifdef LIGHTSABERS 532. 		|| is_lightsaber(obj) 533. #endif 534. 		|| artifact_light(obj))); 535. }  536.   537.  /* WAC Return TRUE if object always lights up  538. * Currently only artifacts have this property 539.  */  540.  boolean 541. obj_permanent_light(obj) 542.     struct obj *obj; 543. {  544.      return ((obj->lamplit) &&  545.          (artifact_light(obj))); 546. }  547.   548.  /* copy the light source(s) attachted to src, and attach it/them to dest */ 549. void 550. obj_split_light_source(src, dest) 551.     struct obj *src, *dest; 552. {  553.      light_source *ls, *new_ls; 554.  555.      for (ls = light_base; ls; ls = ls->next) 556. 	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src) { 557. 	    /*  558.  	     * Insert the new source at beginning of list. This will 559. 	     * never interfere us walking down the list - we are already 560. 	     * past the insertion point. 561. 	     */  562.  	    new_ls = (light_source *) alloc(sizeof(light_source)); 563. 	    *new_ls = *ls; 564. 	    if (Is_candle(src)) { 565. 		/* split candles may emit less light than original group */ 566. 		ls->range = candle_light_range(src); 567. 		new_ls->range = candle_light_range(dest); 568. 		vision_full_recalc = 1;	/* in case range changed */ 569. 	    }  570.  	    new_ls->id = (genericptr_t) dest; 571. 	    new_ls->next = light_base; 572. 	    light_base = new_ls; 573. 	    dest->lamplit = 1;		/* now an active light source */ 574. 	}  575.  }  576.   577.  /* light source `src' has been folded into light source `dest'; 578.    used for merging lit candles and adding candle(s) to lit candelabrum */ 579. void 580. obj_merge_light_sources(src, dest) 581. struct obj *src, *dest; 582. {  583.      light_source *ls; 584.  585.      /* src == dest implies adding to candelabrum */ 586.     if (src != dest) end_burn(src, TRUE);		/* extinguish candles */ 587.  588.      for (ls = light_base; ls; ls = ls->next) 589. 	if (ls->type == LS_OBJECT && ls->id == (genericptr_t) dest) { 590. 	    ls->range = candle_light_range(dest); 591. 	    vision_full_recalc = 1;	/* in case range changed */ 592. 	    break; 593. 	}  594.  }  595.   596.  /* Candlelight is proportional to the number of candles; 597.    minimum range is 2 rather than 1 for playability. */ 598.  int 599. candle_light_range(obj) 600. struct obj *obj; 601. {  602.      int radius; 603.  604.      if (obj->otyp == CANDELABRUM_OF_INVOCATION) { 605. 	/*  606.  	 *	The special candelabrum emits more light than the 607. 	 *	corresponding number of candles would. 608. 	 *	 1..3 candles, range 2 (minimum range); 609. 	 *	 4..6 candles, range 3 (normal lamp range); 610. 	 *	    7 candles, range 4 (bright). 611. 	 */  612.  	radius = (obj->spe < 4) ? 2 : (obj->spe < 7) ? 3 : 4; 613.      } else if (Is_candle(obj)) { 614. 	/*  615.  	 *	Range is incremented by powers of 7 so that it will take 616. 	 *	wizard mode quantities of candles to get more light than 617. 	 *	from a lamp, without imposing an arbitrary limit. 618. 	 *	 1..6   candles, range 2; 619. 	 *	 7..48  candles, range 3; 620. 	 *	49..342 candles, range 4; &c. 621. 	 */  622.  	long n = obj->quan; 623.  624.  	radius = 1;	/* always incremented at least once */ 625. 	do { 626. 	    radius++; 627. 	    n /= 7L; 628. 	} while (n > 0L); 629.     } else { 630. 	/* we're only called for lit candelabrum or candles */ 631.      /* impossible("candlelight for %d?", obj->otyp); */ 632. 	radius = 3;		/* lamp's value */ 633.     }  634.      return radius; 635. }  636.   637.  #ifdef WIZARD 638. extern char *FDECL(fmt_ptr, (const genericptr, char *));  /* from alloc.c */ 639.  640.  int 641. wiz_light_sources 642. {  643.      winid win; 644.     char buf[BUFSZ], arg_address[20]; 645.     light_source *ls; 646.  647.      win = create_nhwindow(NHW_MENU);	/* corner text window */ 648.     if (win == WIN_ERR) return 0; 649.  650.      Sprintf(buf, "Mobile light sources: hero @ (%2d,%2d)", u.ux, u.uy); 651.     putstr(win, 0, buf); 652.     putstr(win, 0, ""); 653.  654.      if (light_base) { 655. 	putstr(win, 0, "location range flags  type    id"); 656. 	putstr(win, 0, " - --   ---"); 657. 	for (ls = light_base; ls; ls = ls->next) { 658. 	    Sprintf(buf, "  %2d,%2d   %2d   0x%04x  %s  %s",  659.  		ls->x, ls->y, ls->range, ls->flags,  660.  		(ls->type == LS_OBJECT ? "obj" : 661. 		 ls->type == LS_MONSTER ? 662. 		    (mon_is_local((struct monst *)ls->id) ? "mon" :  663.  		     ((struct monst *)ls->id == &youmonst) ? "you" :  664.  		     "") :		/* migrating monster */ 665. 		 "???"),  666.  		fmt_ptr(ls->id, arg_address)); 667. 	    putstr(win, 0, buf); 668. 	}  669.      } else 670. 	putstr(win, 0, " "); 671.  672.   673.      display_nhwindow(win, FALSE); 674.     destroy_nhwindow(win); 675.  676.      return 0; 677. }  678.   679.  #endif /* WIZARD */ 680.  681.  #endif /* OVL3 */ 682.  683.  /*light.c*/