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