Source:NetHack 3.2.0/light.c

Below is the full text to light.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.0/light.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

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