Below is the full text to src/region.c from NetHack 3.4.3. To link to a particular line, write [[region.c#line123]], for example.
Top of file[]
1. /* SCCS Id: @(#)region.c 3.4 2002/10/15 */ 2. /* Copyright (c) 1996 by Jean-Christophe Collet */ 3. /* NetHack may be freely redistributed. See license for details. */ 4.
The NetHack General Public License applies to screenshots, source code and other content from NetHack. |
5. #include "hack.h" 6. #include "lev.h" 7. 8. /* 9. * This should really go into the level structure, but 10. * I'll start here for ease. It *WILL* move into the level 11. * structure eventually. 12. */ 13. 14. static NhRegion **regions; 15. static int n_regions = 0; 16. static int max_regions = 0; 17. 18. #define NO_CALLBACK (-1) 19. 20. boolean FDECL(inside_gas_cloud, (genericptr,genericptr)); 21. boolean FDECL(expire_gas_cloud, (genericptr,genericptr)); 22. boolean FDECL(inside_rect, (NhRect *,int,int)); 23. boolean FDECL(inside_region, (NhRegion *,int,int)); 24. NhRegion *FDECL(create_region, (NhRect *,int)); 25. void FDECL(add_rect_to_reg, (NhRegion *,NhRect *)); 26. void FDECL(add_mon_to_reg, (NhRegion *,struct monst *)); 27. void FDECL(remove_mon_from_reg, (NhRegion *,struct monst *)); 28. boolean FDECL(mon_in_region, (NhRegion *,struct monst *)); 29. 30. #if 0 31. NhRegion *FDECL(clone_region, (NhRegion *)); 32. #endif 33. void FDECL(free_region, (NhRegion *)); 34. void FDECL(add_region, (NhRegion *)); 35. void FDECL(remove_region, (NhRegion *)); 36. 37. #if 0 38. void FDECL(replace_mon_regions, (struct monst *,struct monst *)); 39. void FDECL(remove_mon_from_regions, (struct monst *)); 40. NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P, 41. const char *,const char *)); 42. boolean FDECL(enter_force_field, (genericptr,genericptr)); 43. NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int)); 44. #endif 45. 46. static void FDECL(reset_region_mids, (NhRegion *)); 47. 48. static callback_proc callbacks[] = { 49. #define INSIDE_GAS_CLOUD 0 50. inside_gas_cloud, 51. #define EXPIRE_GAS_CLOUD 1 52. expire_gas_cloud 53. }; 54.
inside_rect[]
55. /* Should be inlined. */ 56. boolean 57. inside_rect(r, x, y) 58. NhRect *r; 59. int x, y; 60. { 61. return (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy); 62. } 63.
inside_region[]
64. /* 65. * Check if a point is inside a region. 66. */ 67. boolean 68. inside_region(reg, x, y) 69. NhRegion *reg; 70. int x, y; 71. { 72. int i; 73. 74. if (reg == NULL || !inside_rect(&(reg->bounding_box), x, y)) 75. return FALSE; 76. for (i = 0; i < reg->nrects; i++) 77. if (inside_rect(&(reg->rects[i]), x, y)) 78. return TRUE; 79. return FALSE; 80. } 81.
create_region[]
82. /* 83. * Create a region. It does not activate it. 84. */ 85. NhRegion * 86. create_region(rects, nrect) 87. NhRect *rects; 88. int nrect; 89. { 90. int i; 91. NhRegion *reg; 92. 93. reg = (NhRegion *) alloc(sizeof (NhRegion)); 94. /* Determines bounding box */ 95. if (nrect > 0) { 96. reg->bounding_box = rects[0]; 97. } else { 98. reg->bounding_box.lx = 99; 99. reg->bounding_box.ly = 99; 100. reg->bounding_box.hx = 0; 101. reg->bounding_box.hy = 0; 102. } 103. reg->nrects = nrect; 104. reg->rects = nrect > 0 ? (NhRect *)alloc((sizeof (NhRect)) * nrect) : NULL; 105. for (i = 0; i < nrect; i++) { 106. if (rects[i].lx < reg->bounding_box.lx) 107. reg->bounding_box.lx = rects[i].lx; 108. if (rects[i].ly < reg->bounding_box.ly) 109. reg->bounding_box.ly = rects[i].ly; 110. if (rects[i].hx > reg->bounding_box.hx) 111. reg->bounding_box.hx = rects[i].hx; 112. if (rects[i].hy > reg->bounding_box.hy) 113. reg->bounding_box.hy = rects[i].hy; 114. reg->rects[i] = rects[i]; 115. } 116. reg->ttl = -1; /* Defaults */ 117. reg->attach_2_u = FALSE; 118. reg->attach_2_m = 0; 119. /* reg->attach_2_o = NULL; */ 120. reg->enter_msg = NULL; 121. reg->leave_msg = NULL; 122. reg->expire_f = NO_CALLBACK; 123. reg->enter_f = NO_CALLBACK; 124. reg->can_enter_f = NO_CALLBACK; 125. reg->leave_f = NO_CALLBACK; 126. reg->can_leave_f = NO_CALLBACK; 127. reg->inside_f = NO_CALLBACK; 128. clear_hero_inside(reg); 129. clear_heros_fault(reg); 130. reg->n_monst = 0; 131. reg->max_monst = 0; 132. reg->monsters = NULL; 133. reg->arg = NULL; 134. return reg; 135. } 136.
add_rect_to_reg[]
137. /* 138. * Add rectangle to region. 139. */ 140. void 141. add_rect_to_reg(reg, rect) 142. NhRegion *reg; 143. NhRect *rect; 144. { 145. NhRect *tmp_rect; 146. 147. tmp_rect = (NhRect *) alloc(sizeof (NhRect) * (reg->nrects + 1)); 148. if (reg->nrects > 0) { 149. (void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects, 150. (sizeof (NhRect) * reg->nrects)); 151. free((genericptr_t) reg->rects); 152. } 153. tmp_rect[reg->nrects] = *rect; 154. reg->nrects++; 155. reg->rects = tmp_rect; 156. /* Update bounding box if needed */ 157. if (reg->bounding_box.lx > rect->lx) 158. reg->bounding_box.lx = rect->lx; 159. if (reg->bounding_box.ly > rect->ly) 160. reg->bounding_box.ly = rect->ly; 161. if (reg->bounding_box.hx < rect->hx) 162. reg->bounding_box.hx = rect->hx; 163. if (reg->bounding_box.hy < rect->hy) 164. reg->bounding_box.hy = rect->hy; 165. } 166.
add_mon_to_reg[]
167. /* 168. * Add a monster to the region 169. */ 170. void 171. add_mon_to_reg(reg, mon) 172. NhRegion *reg; 173. struct monst *mon; 174. { 175. int i; 176. unsigned *tmp_m; 177. 178. if (reg->max_monst <= reg->n_monst) { 179. tmp_m = (unsigned *) 180. alloc(sizeof (unsigned) * (reg->max_monst + MONST_INC)); 181. if (reg->max_monst > 0) { 182. for (i = 0; i < reg->max_monst; i++) 183. tmp_m[i] = reg->monsters[i]; 184. free((genericptr_t) reg->monsters); 185. } 186. reg->monsters = tmp_m; 187. reg->max_monst += MONST_INC; 188. } 189. reg->monsters[reg->n_monst++] = mon->m_id; 190. } 191.
remove_mon_from_reg[]
192. /* 193. * Remove a monster from the region list (it left or died...) 194. */ 195. void 196. remove_mon_from_reg(reg, mon) 197. NhRegion *reg; 198. struct monst *mon; 199. { 200. register int i; 201. 202. for (i = 0; i < reg->n_monst; i++) 203. if (reg->monsters[i] == mon->m_id) { 204. reg->n_monst--; 205. reg->monsters[i] = reg->monsters[reg->n_monst]; 206. return; 207. } 208. } 209.
mon_in_region[]
210. /* 211. * Check if a monster is inside the region. 212. * It's probably quicker to check with the region internal list 213. * than to check for coordinates. 214. */ 215. boolean 216. mon_in_region(reg, mon) 217. NhRegion *reg; 218. struct monst *mon; 219. { 220. int i; 221. 222. for (i = 0; i < reg->n_monst; i++) 223. if (reg->monsters[i] == mon->m_id) 224. return TRUE; 225. return FALSE; 226. } 227. 228. #if 0 229. /* not yet used */ 230.
clone_region[]
231. /* 232. * Clone (make a standalone copy) the region. 233. */ 234. NhRegion * 235. clone_region(reg) 236. NhRegion *reg; 237. { 238. NhRegion *ret_reg; 239. 240. ret_reg = create_region(reg->rects, reg->nrects); 241. ret_reg->ttl = reg->ttl; 242. ret_reg->attach_2_u = reg->attach_2_u; 243. ret_reg->attach_2_m = reg->attach_2_m; 244. /* ret_reg->attach_2_o = reg->attach_2_o; */ 245. ret_reg->expire_f = reg->expire_f; 246. ret_reg->enter_f = reg->enter_f; 247. ret_reg->can_enter_f = reg->can_enter_f; 248. ret_reg->leave_f = reg->leave_f; 249. ret_reg->can_leave_f = reg->can_leave_f; 250. ret_reg->player_flags = reg->player_flags; /* set/clear_hero_inside,&c*/ 251. ret_reg->n_monst = reg->n_monst; 252. if (reg->n_monst > 0) { 253. ret_reg->monsters = (unsigned *) 254. alloc((sizeof (unsigned)) * reg->n_monst); 255. (void) memcpy((genericptr_t) ret_reg->monsters, (genericptr_t) reg->monsters, 256. sizeof (unsigned) * reg->n_monst); 257. } else 258. ret_reg->monsters = NULL; 259. return ret_reg; 260. } 261. 262. #endif /*0*/ 263.
free_region[]
264. /* 265. * Free mem from region. 266. */ 267. void 268. free_region(reg) 269. NhRegion *reg; 270. { 271. if (reg) { 272. if (reg->rects) 273. free((genericptr_t) reg->rects); 274. if (reg->monsters) 275. free((genericptr_t) reg->monsters); 276. free((genericptr_t) reg); 277. } 278. } 279.
add_region[]
280. /* 281. * Add a region to the list. 282. * This actually activates the region. 283. */ 284. void 285. add_region(reg) 286. NhRegion *reg; 287. { 288. NhRegion **tmp_reg; 289. int i, j; 290. 291. if (max_regions <= n_regions) { 292. tmp_reg = regions; 293. regions = (NhRegion **)alloc(sizeof (NhRegion *) * (max_regions + 10)); 294. if (max_regions > 0) { 295. (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg, 296. max_regions * sizeof (NhRegion *)); 297. free((genericptr_t) tmp_reg); 298. } 299. max_regions += 10; 300. } 301. regions[n_regions] = reg; 302. n_regions++; 303. /* Check for monsters inside the region */ 304. for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++) 305. for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) { 306. /* Some regions can cross the level boundaries */ 307. if (!isok(i,j)) 308. continue; 309. if (MON_AT(i, j) && inside_region(reg, i, j)) 310. add_mon_to_reg(reg, level.monsters[i][j]); 311. if (reg->visible && cansee(i, j)) 312. newsym(i, j); 313. } 314. /* Check for player now... */ 315. if (inside_region(reg, u.ux, u.uy)) 316. set_hero_inside(reg); 317. else 318. clear_hero_inside(reg); 319. } 320.
remove_region[]
321. /* 322. * Remove a region from the list & free it. 323. */ 324. void 325. remove_region(reg) 326. NhRegion *reg; 327. { 328. register int i, x, y; 329. 330. for (i = 0; i < n_regions; i++) 331. if (regions[i] == reg) 332. break; 333. if (i == n_regions) 334. return; 335. 336. /* Update screen if necessary */ 337. if (reg->visible) 338. for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++) 339. for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++) 340. if (isok(x,y) && inside_region(reg, x, y) && cansee(x, y)) 341. newsym(x, y); 342. 343. free_region(reg); 344. regions[i] = regions[n_regions - 1]; 345. regions[n_regions - 1] = (NhRegion *) 0; 346. n_regions--; 347. } 348.
clear_regions[]
349. /* 350. * Remove all regions and clear all related data (This must be down 351. * when changing level, for instance). 352. */ 353. void 354. clear_regions() 355. { 356. register int i; 357. 358. for (i = 0; i < n_regions; i++) 359. free_region(regions[i]); 360. n_regions = 0; 361. if (max_regions > 0) 362. free((genericptr_t) regions); 363. max_regions = 0; 364. regions = NULL; 365. } 366.
run_regions[]
367. /* 368. * This function is called every turn. 369. * It makes the regions age, if necessary and calls the appropriate 370. * callbacks when needed. 371. */ 372. void 373. run_regions() 374. { 375. register int i, j, k; 376. int f_indx; 377. 378. /* End of life ? */ 379. /* Do it backward because the array will be modified */ 380. for (i = n_regions - 1; i >= 0; i--) { 381. if (regions[i]->ttl == 0) { 382. if ((f_indx = regions[i]->expire_f) == NO_CALLBACK || 383. (*callbacks[f_indx])(regions[i], (genericptr_t) 0)) 384. remove_region(regions[i]); 385. } 386. } 387. 388. /* Process remaining regions */ 389. for (i = 0; i < n_regions; i++) { 390. /* Make the region age */ 391. if (regions[i]->ttl > 0) 392. regions[i]->ttl--; 393. /* Check if player is inside region */ 394. f_indx = regions[i]->inside_f; 395. if (f_indx != NO_CALLBACK && hero_inside(regions[i])) 396. (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); 397. /* Check if any monster is inside region */ 398. if (f_indx != NO_CALLBACK) { 399. for (j = 0; j < regions[i]->n_monst; j++) { 400. struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON); 401. 402. if (!mtmp || mtmp->mhp <= 0 || 403. (*callbacks[f_indx])(regions[i], mtmp)) { 404. /* The monster died, remove it from list */ 405. k = (regions[i]->n_monst -= 1); 406. regions[i]->monsters[j] = regions[i]->monsters[k]; 407. regions[i]->monsters[k] = 0; 408. --j; /* current slot has been reused; recheck it next */ 409. } 410. } 411. } 412. } 413. } 414.
in_out_region[]
415. /* 416. * check whether player enters/leaves one or more regions. 417. */ 418. boolean 419. in_out_region(x, y) 420. xchar 421. x, y; 422. { 423. int i, f_indx; 424. 425. /* First check if we can do the move */ 426. for (i = 0; i < n_regions; i++) { 427. if (inside_region(regions[i], x, y) 428. && !hero_inside(regions[i]) && !regions[i]->attach_2_u) { 429. if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) 430. if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) 431. return FALSE; 432. } else 433. if (hero_inside(regions[i]) 434. && !inside_region(regions[i], x, y) 435. && !regions[i]->attach_2_u) { 436. if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) 437. if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) 438. return FALSE; 439. } 440. } 441. 442. /* Callbacks for the regions we do leave */ 443. for (i = 0; i < n_regions; i++) 444. if (hero_inside(regions[i]) && 445. !regions[i]->attach_2_u && !inside_region(regions[i], x, y)) { 446. clear_hero_inside(regions[i]); 447. if (regions[i]->leave_msg != NULL) 448. pline(regions[i]->leave_msg); 449. if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) 450. (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); 451. } 452. 453. /* Callbacks for the regions we do enter */ 454. for (i = 0; i < n_regions; i++) 455. if (!hero_inside(regions[i]) && 456. !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { 457. set_hero_inside(regions[i]); 458. if (regions[i]->enter_msg != NULL) 459. pline(regions[i]->enter_msg); 460. if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) 461. (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); 462. } 463. return TRUE; 464. } 465.
m_in_out_region[]
466. /* 467. * check wether a monster enters/leaves one or more region. 468. */ 469. boolean 470. m_in_out_region(mon, x, y) 471. struct monst *mon; 472. xchar x, y; 473. { 474. int i, f_indx; 475. 476. /* First check if we can do the move */ 477. for (i = 0; i < n_regions; i++) { 478. if (inside_region(regions[i], x, y) && 479. !mon_in_region(regions[i], mon) && 480. regions[i]->attach_2_m != mon->m_id) { 481. if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) 482. if (!(*callbacks[f_indx])(regions[i], mon)) 483. return FALSE; 484. } else if (mon_in_region(regions[i], mon) && 485. !inside_region(regions[i], x, y) && 486. regions[i]->attach_2_m != mon->m_id) { 487. if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) 488. if (!(*callbacks[f_indx])(regions[i], mon)) 489. return FALSE; 490. } 491. } 492. 493. /* Callbacks for the regions we do leave */ 494. for (i = 0; i < n_regions; i++) 495. if (mon_in_region(regions[i], mon) && 496. regions[i]->attach_2_m != mon->m_id && 497. !inside_region(regions[i], x, y)) { 498. remove_mon_from_reg(regions[i], mon); 499. if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) 500. (void) (*callbacks[f_indx])(regions[i], mon); 501. } 502. 503. /* Callbacks for the regions we do enter */ 504. for (i = 0; i < n_regions; i++) 505. if (!hero_inside(regions[i]) && 506. !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { 507. add_mon_to_reg(regions[i], mon); 508. if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) 509. (void) (*callbacks[f_indx])(regions[i], mon); 510. } 511. return TRUE; 512. } 513.
update_player_regions[]
514. /* 515. * Checks player's regions after a teleport for instance. 516. */ 517. void 518. update_player_regions() 519. { 520. register int i; 521. 522. for (i = 0; i < n_regions; i++) 523. if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy)) 524. set_hero_inside(regions[i]); 525. else 526. clear_hero_inside(regions[i]); 527. } 528.
update_monster_region[]
529. /* 530. * Ditto for a specified monster. 531. */ 532. void 533. update_monster_region(mon) 534. struct monst *mon; 535. { 536. register int i; 537. 538. for (i = 0; i < n_regions; i++) { 539. if (inside_region(regions[i], mon->mx, mon->my)) { 540. if (!mon_in_region(regions[i], mon)) 541. add_mon_to_reg(regions[i], mon); 542. } else { 543. if (mon_in_region(regions[i], mon)) 544. remove_mon_from_reg(regions[i], mon); 545. } 546. } 547. } 548. 549. #if 0
replace_mon_regions[]
550. /* not yet used */ 551. 552. /* 553. * Change monster pointer in regions 554. * This happens, for instance, when a monster grows and 555. * need a new structure (internally that is). 556. */ 557. void 558. replace_mon_regions(monold, monnew) 559. struct monst *monold, *monnew; 560. { 561. register int i; 562. 563. for (i = 0; i < n_regions; i++) 564. if (mon_in_region(regions[i], monold)) { 565. remove_mon_from_reg(regions[i], monold); 566. add_mon_to_reg(regions[i], monnew); 567. } 568. } 569.
remove_mon_from_regions[]
570. /* 571. * Remove monster from all regions it was in (ie monster just died) 572. */ 573. void 574. remove_mon_from_regions(mon) 575. struct monst *mon; 576. { 577. register int i; 578. 579. for (i = 0; i < n_regions; i++) 580. if (mon_in_region(regions[i], mon)) 581. remove_mon_from_reg(regions[i], mon); 582. } 583. 584. #endif /*0*/ 585.
visible_region_at[]
586. /* 587. * Check if a spot is under a visible region (eg: gas cloud). 588. * Returns NULL if not, otherwise returns region. 589. */ 590. NhRegion * 591. visible_region_at(x, y) 592. xchar x, y; 593. { 594. register int i; 595. 596. for (i = 0; i < n_regions; i++) 597. if (inside_region(regions[i], x, y) && regions[i]->visible && 598. regions[i]->ttl != 0) 599. return regions[i]; 600. return (NhRegion *) 0; 601. } 602.
show_region[]
603. void 604. show_region(reg, x, y) 605. NhRegion *reg; 606. xchar x, y; 607. { 608. show_glyph(x, y, reg->glyph); 609. } 610.
save_regions[]
611. /** 612. * save_regions : 613. */ 614. void 615. save_regions(fd, mode) 616. int fd; 617. int mode; 618. { 619. int i, j; 620. unsigned n; 621. 622. if (!perform_bwrite(mode)) goto skip_lots; 623. 624. bwrite(fd, (genericptr_t) &moves, sizeof (moves)); /* timestamp */ 625. bwrite(fd, (genericptr_t) &n_regions, sizeof (n_regions)); 626. for (i = 0; i < n_regions; i++) { 627. bwrite(fd, (genericptr_t) ®ions[i]->bounding_box, sizeof (NhRect)); 628. bwrite(fd, (genericptr_t) ®ions[i]->nrects, sizeof (short)); 629. for (j = 0; j < regions[i]->nrects; j++) 630. bwrite(fd, (genericptr_t) ®ions[i]->rects[j], sizeof (NhRect)); 631. bwrite(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof (boolean)); 632. n = 0; 633. bwrite(fd, (genericptr_t) ®ions[i]->attach_2_m, sizeof (unsigned)); 634. n = regions[i]->enter_msg != NULL ? strlen(regions[i]->enter_msg) : 0; 635. bwrite(fd, (genericptr_t) &n, sizeof n); 636. if (n > 0) 637. bwrite(fd, (genericptr_t) regions[i]->enter_msg, n); 638. n = regions[i]->leave_msg != NULL ? strlen(regions[i]->leave_msg) : 0; 639. bwrite(fd, (genericptr_t) &n, sizeof n); 640. if (n > 0) 641. bwrite(fd, (genericptr_t) regions[i]->leave_msg, n); 642. bwrite(fd, (genericptr_t) ®ions[i]->ttl, sizeof (short)); 643. bwrite(fd, (genericptr_t) ®ions[i]->expire_f, sizeof (short)); 644. bwrite(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof (short)); 645. bwrite(fd, (genericptr_t) ®ions[i]->enter_f, sizeof (short)); 646. bwrite(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); 647. bwrite(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); 648. bwrite(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); 649. bwrite(fd, (genericptr_t) ®ions[i]->player_flags, sizeof (boolean)); 650. bwrite(fd, (genericptr_t) ®ions[i]->n_monst, sizeof (short)); 651. for (j = 0; j < regions[i]->n_monst; j++) 652. bwrite(fd, (genericptr_t) ®ions[i]->monsters[j], 653. sizeof (unsigned)); 654. bwrite(fd, (genericptr_t) ®ions[i]->visible, sizeof (boolean)); 655. bwrite(fd, (genericptr_t) ®ions[i]->glyph, sizeof (int)); 656. bwrite(fd, (genericptr_t) ®ions[i]->arg, sizeof (genericptr_t)); 657. } 658. 659. skip_lots: 660. if (release_data(mode)) 661. clear_regions(); 662. } 663.
rest_regions[]
664. void 665. rest_regions(fd, ghostly) 666. int fd; 667. boolean ghostly; /* If a bones file restore */ 668. { 669. int i, j; 670. unsigned n; 671. long tmstamp; 672. char *msg_buf; 673. 674. clear_regions(); /* Just for security */ 675. mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp)); 676. if (ghostly) tmstamp = 0; 677. else tmstamp = (moves - tmstamp); 678. mread(fd, (genericptr_t) &n_regions, sizeof (n_regions)); 679. max_regions = n_regions; 680. if (n_regions > 0) 681. regions = (NhRegion **) alloc(sizeof (NhRegion *) * n_regions); 682. for (i = 0; i < n_regions; i++) { 683. regions[i] = (NhRegion *) alloc(sizeof (NhRegion)); 684. mread(fd, (genericptr_t) ®ions[i]->bounding_box, sizeof (NhRect)); 685. mread(fd, (genericptr_t) ®ions[i]->nrects, sizeof (short)); 686. 687. if (regions[i]->nrects > 0) 688. regions[i]->rects = (NhRect *) 689. alloc(sizeof (NhRect) * regions[i]->nrects); 690. for (j = 0; j < regions[i]->nrects; j++) 691. mread(fd, (genericptr_t) ®ions[i]->rects[j], sizeof (NhRect)); 692. mread(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof (boolean)); 693. mread(fd, (genericptr_t) ®ions[i]->attach_2_m, sizeof (unsigned)); 694. 695. mread(fd, (genericptr_t) &n, sizeof n); 696. if (n > 0) { 697. msg_buf = (char *) alloc(n + 1); 698. mread(fd, (genericptr_t) msg_buf, n); 699. msg_buf[n] = '\0'; 700. regions[i]->enter_msg = (const char *) msg_buf; 701. } else 702. regions[i]->enter_msg = NULL; 703. 704. mread(fd, (genericptr_t) &n, sizeof n); 705. if (n > 0) { 706. msg_buf = (char *) alloc(n + 1); 707. mread(fd, (genericptr_t) msg_buf, n); 708. msg_buf[n] = '\0'; 709. regions[i]->leave_msg = (const char *) msg_buf; 710. } else 711. regions[i]->leave_msg = NULL; 712. 713. mread(fd, (genericptr_t) ®ions[i]->ttl, sizeof (short)); 714. /* check for expired region */ 715. if (regions[i]->ttl >= 0) 716. regions[i]->ttl = 717. (regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0; 718. mread(fd, (genericptr_t) ®ions[i]->expire_f, sizeof (short)); 719. mread(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof (short)); 720. mread(fd, (genericptr_t) ®ions[i]->enter_f, sizeof (short)); 721. mread(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); 722. mread(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); 723. mread(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); 724. mread(fd, (genericptr_t) ®ions[i]->player_flags, sizeof (boolean)); 725. if (ghostly) { /* settings pertained to old player */ 726. clear_hero_inside(regions[i]); 727. clear_heros_fault(regions[i]); 728. } 729. mread(fd, (genericptr_t) ®ions[i]->n_monst, sizeof (short)); 730. if (regions[i]->n_monst > 0) 731. regions[i]->monsters = 732. (unsigned *) alloc(sizeof (unsigned) * regions[i]->n_monst); 733. else 734. regions[i]->monsters = NULL; 735. regions[i]->max_monst = regions[i]->n_monst; 736. for (j = 0; j < regions[i]->n_monst; j++) 737. mread(fd, (genericptr_t) ®ions[i]->monsters[j], 738. sizeof (unsigned)); 739. mread(fd, (genericptr_t) ®ions[i]->visible, sizeof (boolean)); 740. mread(fd, (genericptr_t) ®ions[i]->glyph, sizeof (int)); 741. mread(fd, (genericptr_t) ®ions[i]->arg, sizeof (genericptr_t)); 742. } 743. /* remove expired regions, do not trigger the expire_f callback (yet!); 744. also update monster lists if this data is coming from a bones file */ 745. for (i = n_regions - 1; i >= 0; i--) 746. if (regions[i]->ttl == 0) 747. remove_region(regions[i]); 748. else if (ghostly && regions[i]->n_monst > 0) 749. reset_region_mids(regions[i]); 750. } 751.
reset_region_mids[]
752. /* update monster IDs for region being loaded from bones; `ghostly' implied */ 753. static void 754. reset_region_mids(reg) 755. NhRegion *reg; 756. { 757. int i = 0, n = reg->n_monst; 758. unsigned *mid_list = reg->monsters; 759. 760. while (i < n) 761. if (!lookup_id_mapping(mid_list[i], &mid_list[i])) { 762. /* shrink list to remove missing monster; order doesn't matter */ 763. mid_list[i] = mid_list[--n]; 764. } else { 765. /* move on to next monster */ 766. ++i; 767. } 768. reg->n_monst = n; 769. return; 770. } 771. 772. #if 0
create_msg_region[]
773. /* not yet used */ 774. 775. /*--------------------------------------------------------------* 776. * * 777. * Create Region with just a message * 778. * * 779. *--------------------------------------------------------------*/ 780. 781. NhRegion * 782. create_msg_region(x, y, w, h, msg_enter, msg_leave) 783. xchar x, y; 784. xchar w, h; 785. const char *msg_enter; 786. const char *msg_leave; 787. { 788. NhRect tmprect; 789. NhRegion *reg = create_region((NhRect *) 0, 0); 790. 791. reg->enter_msg = msg_enter; 792. reg->leave_msg = msg_leave; 793. tmprect.lx = x; 794. tmprect.ly = y; 795. tmprect.hx = x + w; 796. tmprect.hy = y + h; 797. add_rect_to_reg(reg, &tmprect); 798. reg->ttl = -1; 799. return reg; 800. } 801. 802.
enter_force_field[]
803. /*--------------------------------------------------------------* 804. * * 805. * Force Field Related Code * 806. * (unused yet) * 807. *--------------------------------------------------------------*/ 808. 809. boolean 810. enter_force_field(p1, p2) 811. genericptr_t p1; 812. genericptr_t p2; 813. { 814. struct monst *mtmp; 815. 816. if (p2 == NULL) { /* That means the player */ 817. if (!Blind) 818. You("bump into %s. Ouch!", 819. Hallucination ? "an invisible tree" : 820. "some kind of invisible wall"); 821. else 822. pline("Ouch!"); 823. } else { 824. mtmp = (struct monst *) p2; 825. if (canseemon(mtmp)) 826. pline("%s bumps into %s!", Monnam(mtmp), something); 827. } 828. return FALSE; 829. } 830.
create_force_field[]
831. NhRegion * 832. create_force_field(x, y, radius, ttl) 833. xchar x, y; 834. int radius, ttl; 835. { 836. int i; 837. NhRegion *ff; 838. int nrect; 839. NhRect tmprect; 840. 841. ff = create_region((NhRect *) 0, 0); 842. nrect = radius; 843. tmprect.lx = x; 844. tmprect.hx = x; 845. tmprect.ly = y - (radius - 1); 846. tmprect.hy = y + (radius - 1); 847. for (i = 0; i < nrect; i++) { 848. add_rect_to_reg(ff, &tmprect); 849. tmprect.lx--; 850. tmprect.hx++; 851. tmprect.ly++; 852. tmprect.hy--; 853. } 854. ff->ttl = ttl; 855. if (!in_mklev && !flags.mon_moving) 856. set_heros_fault(ff); /* assume player has created it */ 857. /* ff->can_enter_f = enter_force_field; */ 858. /* ff->can_leave_f = enter_force_field; */ 859. add_region(ff); 860. return ff; 861. } 862. 863. #endif /*0*/ 864.
expire_gas_cloud[]
865. /*--------------------------------------------------------------* 866. * * 867. * Gas cloud related code * 868. * * 869. *--------------------------------------------------------------*/ 870. 871. /* 872. * Here is an example of an expire function that may prolong 873. * region life after some mods... 874. */ 875. boolean 876. expire_gas_cloud(p1, p2) 877. genericptr_t p1; 878. genericptr_t p2; 879. { 880. NhRegion *reg; 881. int damage; 882. 883. reg = (NhRegion *) p1; 884. damage = (int) reg->arg; 885. 886. /* If it was a thick cloud, it dissipates a little first */ 887. if (damage >= 5) { 888. damage /= 2; /* It dissipates, let's do less damage */ 889. reg->arg = (genericptr_t) damage; 890. reg->ttl = 2; /* Here's the trick : reset ttl */ 891. return FALSE; /* THEN return FALSE, means "still there" */ 892. } 893. return TRUE; /* OK, it's gone, you can free it! */ 894. } 895.
inside_gas_cloud[]
896. boolean 897. inside_gas_cloud(p1, p2) 898. genericptr_t p1; 899. genericptr_t p2; 900. { 901. NhRegion *reg; 902. struct monst *mtmp; 903. int dam; 904. 905. reg = (NhRegion *) p1; 906. dam = (int) reg->arg; 907. if (p2 == NULL) { /* This means *YOU* Bozo! */ 908. if (nonliving(youmonst.data) || Breathless) 909. return FALSE; 910. if (!Blind) 911. make_blinded(1L, FALSE); 912. if (!Poison_resistance) { 913. pline("%s is burning your %s!", Something, makeplural(body_part(LUNG))); 914. You("cough and spit blood!"); 915. losehp(rnd(dam) + 5, "gas cloud", KILLED_BY_AN); 916. return FALSE; 917. } else { 918. You("cough!"); 919. return FALSE; 920. } 921. } else { /* A monster is inside the cloud */ 922. mtmp = (struct monst *) p2; 923. 924. /* Non living and non breathing monsters are not concerned */ 925. if (!nonliving(mtmp->data) && !breathless(mtmp->data)) { 926. if (cansee(mtmp->mx, mtmp->my)) 927. pline("%s coughs!", Monnam(mtmp)); 928. setmangry(mtmp); 929. if (haseyes(mtmp->data) && mtmp->mcansee) { 930. mtmp->mblinded = 1; 931. mtmp->mcansee = 0; 932. } 933. if (resists_poison(mtmp)) 934. return FALSE; 935. mtmp->mhp -= rnd(dam) + 5; 936. if (mtmp->mhp <= 0) { 937. if (heros_fault(reg)) 938. killed(mtmp); 939. else 940. monkilled(mtmp, "gas cloud", AD_DRST); 941. if (mtmp->mhp <= 0) { /* not lifesaved */ 942. return TRUE; 943. } 944. } 945. } 946. } 947. return FALSE; /* Monster is still alive */ 948. } 949.
create_gas_cloud[]
950. NhRegion * 951. create_gas_cloud(x, y, radius, damage) 952. xchar x, y; 953. int radius; 954. int damage; 955. { 956. NhRegion *cloud; 957. int i, nrect; 958. NhRect tmprect; 959. 960. cloud = create_region((NhRect *) 0, 0); 961. nrect = radius; 962. tmprect.lx = x; 963. tmprect.hx = x; 964. tmprect.ly = y - (radius - 1); 965. tmprect.hy = y + (radius - 1); 966. for (i = 0; i < nrect; i++) { 967. add_rect_to_reg(cloud, &tmprect); 968. tmprect.lx--; 969. tmprect.hx++; 970. tmprect.ly++; 971. tmprect.hy--; 972. } 973. cloud->ttl = rn1(3,4); 974. if (!in_mklev && !flags.mon_moving) 975. set_heros_fault(cloud); /* assume player has created it */ 976. cloud->inside_f = INSIDE_GAS_CLOUD; 977. cloud->expire_f = EXPIRE_GAS_CLOUD; 978. cloud->arg = (genericptr_t) damage; 979. cloud->visible = TRUE; 980. cloud->glyph = cmap_to_glyph(S_cloud); 981. add_region(cloud); 982. return cloud; 983. } 984. 985. /*region.c*/