Source:Light.c

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