Source:SLASH'EM 0.0.7E7F2/light.c
Revision as of 19:11, 7 March 2008 by Kernigh bot (talk | contribs) (SLASH'EM 0.0.7E7F2/light.c moved to Source:SLASH'EM 0.0.7E7F2/light.c: Robot: moved page)
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.
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
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. "<m>") : /* migrating monster */ 665. "???"), 666. fmt_ptr(ls->id, arg_address)); 667. putstr(win, 0, buf); 668. } 669. } else 670. putstr(win, 0, "<none>"); 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*/