Source:NetHack 3.1.0/mkmaze.c
Jump to navigation
Jump to search
Below is the full text to mkmaze.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/mkmaze.c#line123]], for example.
Warning! This is the source code from an old release. For the latest release, see 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: @(#)mkmaze.c 3.1 93/01/17 */ 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. #include "hack.h" 6. #include "sp_lev.h" 7. 8. #define UP 1 9. #define DOWN 0 10. 11. /* from sp_lev.c, for fixup_special() */ 12. extern char *lev_message; 13. extern lev_region *lregions; 14. extern int num_lregions; 15. 16. static int FDECL(iswall,(int,int)); 17. static boolean FDECL(okay,(int,int,int)); 18. static void FDECL(maze0xy,(coord *)); 19. static boolean FDECL(put_lregion_here,(XCHAR_P,XCHAR_P,XCHAR_P, 20. XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,BOOLEAN_P,d_level *)); 21. static void NDECL(fixup_special); 22. static void NDECL(setup_waterlevel); 23. static void NDECL(unsetup_waterlevel); 24. 25. static int 26. iswall(x,y) 27. int x,y; 28. { 29. if (x<=0 || y<0 || x>COLNO-1 || y>ROWNO-1) 30. return 0; 31. return (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ) 32. || levl[x][y].typ == SDOOR); 33. } 34. 35. void 36. wallification(x1, y1, x2, y2) 37. int x1, y1, x2, y2; 38. { 39. uchar type; 40. short x,y; 41. register struct rm *lev; 42. 43. if (x1 < 0) x1 = 0; 44. if (x2 < x1) x2 = x1; 45. if (x2 > COLNO-1) x2 = COLNO-1; 46. if (x1 > x2) x1 = x2; 47. if (y1 < 0) y1 = 0; 48. if (y2 < y1) y2 = y1; 49. if (y2 > ROWNO-1) y2 = ROWNO-1; 50. if (y1 > y2) y1 = y2; 51. for(x = x1; x <= x2; x++) 52. for(y = y1; y <= y2; y++) { 53. lev = &levl[x][y]; 54. type = lev->typ; 55. if (iswall(x,y)) { 56. if (IS_DOOR(type) || type == SDOOR || type == DBWALL) 57. continue; 58. else 59. if (iswall(x,y-1)) 60. if (iswall(x,y+1)) 61. if (iswall(x-1,y)) 62. if (iswall(x+1,y)) 63. lev->typ = CROSSWALL; 64. else 65. lev->typ = TLWALL; 66. else 67. if (iswall(x+1,y)) 68. lev->typ = TRWALL; 69. else 70. lev->typ = VWALL; 71. else 72. if (iswall(x-1,y)) 73. if (iswall(x+1,y)) 74. lev->typ = TUWALL; 75. else 76. lev->typ = BRCORNER; 77. else 78. if (iswall(x+1,y)) 79. lev->typ = BLCORNER; 80. else 81. lev->typ = VWALL; 82. else 83. if (iswall(x,y+1)) 84. if (iswall(x-1,y)) 85. if (iswall(x+1,y)) 86. lev->typ = TDWALL; 87. else 88. lev->typ = TRCORNER; 89. else 90. if (iswall(x+1,y)) 91. lev->typ = TLCORNER; 92. else 93. lev->typ = VWALL; 94. else 95. lev->typ = HWALL; 96. } 97. } 98. } 99. 100. static boolean 101. okay(x,y,dir) 102. int x,y; 103. register int dir; 104. { 105. move(&x,&y,dir); 106. move(&x,&y,dir); 107. if(x<3 || y<3 || x>x_maze_max || y>y_maze_max || levl[x][y].typ != 0) 108. return(FALSE); 109. return(TRUE); 110. } 111. 112. static void 113. maze0xy(cc) /* find random starting point for maze generation */ 114. coord *cc; 115. { 116. cc->x = 3 + 2*rn2((x_maze_max>>1) - 1); 117. cc->y = 3 + 2*rn2((y_maze_max>>1) - 1); 118. return; 119. } 120. 121. /* 122. * Bad if: 123. * pos is occupied OR 124. * pos is inside restricted region (lx,ly,hx,hy) OR 125. * NOT (pos is corridor and a maze level OR pos is a room OR pos is air) 126. */ 127. boolean 128. bad_location(x, y, lx, ly, hx, hy) 129. xchar x, y; 130. xchar lx, ly, hx, hy; 131. { 132. return(occupied(x, y) || 133. ((x >= lx) && (x <= hx) && (y >= ly) && (y <= hy)) || 134. !((levl[x][y].typ == CORR && level.flags.is_maze_lev) || 135. levl[x][y].typ == ROOM || levl[x][y].typ == AIR)); 136. } 137. 138. /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) */ 139. /* and place something (based on rtype) in that region */ 140. void 141. place_lregion(lx, ly, hx, hy, nlx, nly, nhx, nhy, rtype, lev) 142. xchar lx, ly, hx, hy; 143. xchar nlx, nly, nhx, nhy; 144. xchar rtype; 145. d_level *lev; 146. { 147. int trycnt; 148. boolean oneshot; 149. xchar x, y; 150. 151. if(!lx) { /* default to whole level */ 152. /* 153. * if there are rooms and this a branch, let place_branch choose 154. * the branch location (to avoid putting branches in corridors). 155. */ 156. if(rtype == LR_BRANCH && nroom) { 157. place_branch(Is_branchlev(&u.uz), 0, 0); 158. return; 159. } 160. 161. lx = 1; hx = COLNO-1; 162. ly = 1; hy = ROWNO-1; 163. } 164. 165. /* first a probabilistic approach */ 166. 167. oneshot = (lx == hx && ly == hy); 168. for(trycnt = 0; trycnt < 100; trycnt ++) { 169. 170. x = rn1((hx - lx) + 1, lx); 171. y = rn1((hy - ly) + 1, ly); 172. 173. if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)) 174. return; 175. } 176. 177. /* then a deterministic one */ 178. 179. oneshot = TRUE; 180. for (x = lx; x <= hx; x++) 181. for (y = ly; y <= hy; y++) 182. if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)) 183. return; 184. 185. impossible("Couldn't place lregion type %d!", rtype); 186. } 187. 188. static boolean 189. put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev) 190. xchar x, y; 191. xchar nlx, nly, nhx, nhy; 192. xchar rtype; 193. boolean oneshot; 194. d_level *lev; 195. { 196. if(oneshot) { 197. /* must make due with the only location possible */ 198. /* avoid failure due to a misplaced trap */ 199. /* it might still fail if there's a dungeon feature here */ 200. struct trap *t = t_at(x,y); 201. if (t) deltrap(t); 202. } 203. if(bad_location(x, y, nlx, nly, nhx, nhy)) return(FALSE); 204. switch (rtype) { 205. case LR_TELE: 206. case LR_UPTELE: 207. case LR_DOWNTELE: 208. /* "something" means the player in this case */ 209. if(MON_AT(x, y)) { 210. /* move the monster if no choice, or just try again */ 211. if(oneshot) rloc(m_at(x,y)); 212. else return(FALSE); 213. } 214. u.ux = x; u.uy = y; 215. break; 216. case LR_PORTAL: 217. mkportal(x, y, lev->dnum, lev->dlevel); 218. break; 219. case LR_DOWNSTAIR: 220. case LR_UPSTAIR: 221. mkstairs(x, y, (char)rtype, (struct mkroom *)0); 222. break; 223. case LR_BRANCH: 224. place_branch(Is_branchlev(&u.uz), x, y); 225. break; 226. } 227. return(TRUE); 228. } 229. 230. static boolean was_waterlevel; /* ugh... this shouldn't be needed */ 231. 232. /* this is special stuff that the level compiler cannot (yet) handle */ 233. static void 234. fixup_special() 235. { 236. register lev_region *r = lregions; 237. struct d_level lev; 238. register int x, y; 239. struct mkroom *croom; 240. boolean added_branch = FALSE; 241. 242. if (was_waterlevel) { 243. was_waterlevel = FALSE; 244. u.uinwater = 0; 245. unsetup_waterlevel(); 246. } else if (Is_waterlevel(&u.uz)) { 247. level.flags.hero_memory = 0; 248. was_waterlevel = TRUE; 249. /* water level is an odd beast - it has to be set up 250. before calling place_lregions etc. */ 251. setup_waterlevel(); 252. } 253. for(x = 0; x < num_lregions; x++, r++) { 254. switch(r->rtype) { 255. case LR_BRANCH: 256. added_branch = TRUE; 257. goto place_it; 258. 259. case LR_PORTAL: 260. if(*r->rname >= '0' && *r->rname <= '9') { 261. /* "chutes and ladders" */ 262. lev = u.uz; 263. lev.dlevel = atoi(r->rname); 264. } else 265. lev = find_level(r->rname)->dlevel; 266. /* fall into... */ 267. 268. case LR_UPSTAIR: 269. case LR_DOWNSTAIR: 270. place_it: 271. place_lregion(r->inarea.x1, r->inarea.y1, 272. r->inarea.x2, r->inarea.y2, 273. r->delarea.x1, r->delarea.y1, 274. r->delarea.x2, r->delarea.y2, 275. r->rtype, &lev); 276. break; 277. 278. case LR_TELE: 279. case LR_UPTELE: 280. case LR_DOWNTELE: 281. /* save the region outlines for goto_level() */ 282. if(r->rtype == LR_TELE || r->rtype == LR_UPTELE) { 283. updest.lx = r->inarea.x1; updest.ly = r->inarea.y1; 284. updest.hx = r->inarea.x2; updest.hy = r->inarea.y2; 285. updest.nlx = r->delarea.x1; updest.nly = r->delarea.y1; 286. updest.nhx = r->delarea.x2; updest.nhy = r->delarea.y2; 287. } 288. if(r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) { 289. dndest.lx = r->inarea.x1; dndest.ly = r->inarea.y1; 290. dndest.hx = r->inarea.x2; dndest.hy = r->inarea.y2; 291. dndest.nlx = r->delarea.x1; dndest.nly = r->delarea.y1; 292. dndest.nhx = r->delarea.x2; dndest.nhy = r->delarea.y2; 293. } 294. /* place_lregion gets called from goto_level() */ 295. break; 296. } 297. } 298. 299. /* place dungeon branch if not placed above */ 300. if (!added_branch && Is_branchlev(&u.uz)) { 301. place_lregion(0,0,0,0,0,0,0,0,LR_BRANCH,(d_level *)0); 302. } 303. 304. /* Still need to add some stuff to level file */ 305. if (Is_medusa_level(&u.uz)) { 306. struct obj *otmp; 307. int tryct; 308. 309. croom = &rooms[0]; /* only one room on the medusa level */ 310. for (tryct = rn1(1,3); tryct; tryct--) { 311. x = somex(croom); y = somey(croom); 312. if (goodpos(x, y, (struct monst *)0, (struct permonst *)0)) { 313. otmp = mk_tt_object(STATUE, x, y); 314. while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) || 315. resists_ston(&mons[otmp->corpsenm]))) { 316. otmp->corpsenm = rndmonnum(); 317. otmp->owt = weight(otmp); 318. } 319. } 320. } 321. 322. if (rn2(2)) 323. otmp = mk_tt_object(STATUE, somex(croom), somey(croom)); 324. else /* Medusa statues don't contain books */ 325. otmp = mkcorpstat(STATUE, (struct permonst *)0, 326. somex(croom), somey(croom), FALSE); 327. if (otmp) { 328. while (resists_ston(&mons[otmp->corpsenm]) 329. || poly_when_stoned(&mons[otmp->corpsenm])) { 330. otmp->corpsenm = rndmonnum(); 331. otmp->owt = weight(otmp); 332. } 333. } 334. } else if(Is_wiz1_level(&u.uz)) { 335. croom = search_special(MORGUE); 336. 337. create_secret_door(croom, W_SOUTH|W_EAST|W_WEST); 338. #ifdef MULDGN 339. } else if(Is_knox(&u.uz)) { 340. /* using an unfilled morgue for rm id */ 341. croom = search_special(MORGUE); 342. /* stock the main vault */ 343. for(x = croom->lx; x <= croom->hx; x++) 344. for(y = croom->ly; y <= croom->hy; y++) { 345. mkgold((long) rn1(300, 600), x, y); 346. if(!rn2(3) && !is_pool(x,y)) (void)maketrap(x, y, LANDMINE); 347. } 348. #endif 349. } else if(Is_sanctum(&u.uz)) { 350. croom = search_special(TEMPLE); 351. 352. create_secret_door(croom, W_ANY); 353. } else if(on_level(&u.uz, &orcus_level)) { 354. register struct monst *mtmp, *mtmp2; 355. 356. /* it's a ghost town, get rid of shopkeepers */ 357. for(mtmp = fmon; mtmp; mtmp = mtmp2) { 358. mtmp2 = mtmp->nmon; 359. if(mtmp->isshk) mongone(mtmp); 360. } 361. } 362. 363. if(lev_message) { 364. char *str, *nl; 365. for(str = lev_message; (nl = index(str, '\n')) != 0; str = nl+1) { 366. *nl = '\0'; 367. pline("%s", str); 368. } 369. if(*str) 370. pline("%s", str); 371. free((genericptr_t)lev_message); 372. lev_message = 0; 373. } 374. } 375. 376. void 377. makemaz(s) 378. register const char *s; 379. { 380. int x,y; 381. char protofile[20]; 382. s_level *sp = Is_special(&u.uz); 383. coord mm; 384. 385. if(*s) { 386. if(sp && sp->rndlevs) Sprintf(protofile, "%s-%d", s, 387. rnd((int) sp->rndlevs)); 388. else Strcpy(protofile, s); 389. } else if(*(dungeons[u.uz.dnum].proto)) { 390. if(dunlevs_in_dungeon(&u.uz) > 1) { 391. if(sp && sp->rndlevs) 392. Sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto, 393. dunlev(&u.uz), 394. rnd((int) sp->rndlevs)); 395. else Sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto, 396. dunlev(&u.uz)); 397. } else if(sp && sp->rndlevs) { 398. Sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto, 399. rnd((int) sp->rndlevs)); 400. } else Strcpy(protofile, dungeons[u.uz.dnum].proto); 401. 402. } else Strcpy(protofile, ""); 403. 404. if(*protofile) { 405. Strcat(protofile, LEV_EXT); 406. if(load_special(protofile)) { 407. fixup_special(); 408. return; /* no mazification right now */ 409. } 410. impossible("Couldn't load '%s' - making a maze.", protofile); 411. } 412. 413. level.flags.is_maze_lev = TRUE; 414. 415. #ifndef WALLIFIED_MAZE 416. for(x = 2; x < x_maze_max; x++) 417. for(y = 2; y < y_maze_max; y++) 418. levl[x][y].typ = STONE; 419. #else 420. for(x = 2; x <= x_maze_max; x++) 421. for(y = 2; y <= y_maze_max; y++) 422. levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL; 423. #endif 424. 425. maze0xy(&mm); 426. walkfrom((int) mm.x, (int) mm.y); 427. /* put a boulder at the maze center */ 428. (void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE); 429. 430. #ifdef WALLIFIED_MAZE 431. wallification(2, 2, x_maze_max, y_maze_max); 432. #else 433. for(x = 2; x < x_maze_max; x++) 434. for(y = 2; y < y_maze_max; y++) 435. levl[x][y].seen = 1; /* start out seen */ 436. #endif 437. if(Invocation_lev(&u.uz)) { 438. place_lregion(0,0,0,0, 30, 0, 46, ROWNO, UP, (d_level *)0); 439. do { 440. if(xupstair < 30) 441. x = rn1(COLNO-16-xupstair, xupstair+7); 442. else 443. x = rn1(xupstair-16, 9); 444. y = rn1(7, 8); 445. } while((levl[x][y].typ != CORR && levl[x][y].typ != ROOM) 446. || occupied(x,y)); 447. inv_pos.x = x; 448. inv_pos.y = y; 449. } else { 450. /* no regular up stairs on the first level of a dungeon) */ 451. if(u.uz.dlevel != 1) { 452. mazexy(&mm); 453. mkstairs(mm.x, mm.y, UP, (struct mkroom *)0); 454. } 455. 456. /* no regular down stairs on the last level of a dungeon */ 457. if(dunlev(&u.uz) != dunlevs_in_dungeon(&u.uz)) { 458. mazexy(&mm); 459. mkstairs(mm.x, mm.y, DOWN, (struct mkroom *)0); 460. } 461. } 462. 463. /* place branch stair or portal */ 464. place_branch(Is_branchlev(&u.uz), 0, 0); 465. 466. for(x = rn1(8,11); x; x--) { 467. mazexy(&mm); 468. (void) mkobj_at(rn2(2) ? GEM_CLASS : 0, mm.x, mm.y, TRUE); 469. } 470. for(x = rn1(10,2); x; x--) { 471. mazexy(&mm); 472. (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE); 473. } 474. mazexy(&mm); 475. (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y); 476. for(x = rn1(5,7); x; x--) { 477. mazexy(&mm); 478. (void) makemon((struct permonst *) 0, mm.x, mm.y); 479. } 480. for(x = rn1(6,7); x; x--) { 481. mazexy(&mm); 482. mkgold(0L,mm.x,mm.y); 483. } 484. for(x = rn1(6,7); x; x--) 485. mktrap(0,1,(struct mkroom *) 0, (coord*) 0); 486. } 487. 488. #ifdef MICRO 489. /* Make the mazewalk iterative by faking a stack. This is needed to 490. * ensure the mazewalk is successful in the limited stack space of 491. * the program. This iterative version uses the minimum amount of stack 492. * that is totally safe. 493. */ 494. void 495. walkfrom(x,y) 496. int x,y; 497. { 498. #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */ 499. char mazex[CELLS + 1], mazey[CELLS + 1]; /* char's are OK */ 500. int q, a, dir, pos; 501. int dirs[4]; 502. 503. pos = 1; 504. mazex[pos] = (char) x; 505. mazey[pos] = (char) y; 506. while (pos) { 507. x = (int) mazex[pos]; 508. y = (int) mazey[pos]; 509. if(!IS_DOOR(levl[x][y].typ)) { 510. /* might still be on edge of MAP, so don't overwrite */ 511. #ifndef WALLIFIED_MAZE 512. levl[x][y].typ = CORR; 513. #else 514. levl[x][y].typ = ROOM; 515. #endif 516. levl[x][y].flags = 0; 517. } 518. q = 0; 519. for (a = 0; a < 4; a++) 520. if(okay(x, y, a)) dirs[q++]= a; 521. if (!q) 522. pos--; 523. else { 524. dir = dirs[rn2(q)]; 525. move(&x, &y, dir); 526. #ifndef WALLIFIED_MAZE 527. levl[x][y].typ = CORR; 528. #else 529. levl[x][y].typ = ROOM; 530. #endif 531. move(&x, &y, dir); 532. pos++; 533. if (pos > CELLS) 534. panic("Overflow in walkfrom"); 535. mazex[pos] = (char) x; 536. mazey[pos] = (char) y; 537. } 538. } 539. } 540. #else 541. 542. void 543. walkfrom(x,y) 544. int x,y; 545. { 546. register int q,a,dir; 547. int dirs[4]; 548. 549. if(!IS_DOOR(levl[x][y].typ)) { 550. /* might still be on edge of MAP, so don't overwrite */ 551. #ifndef WALLIFIED_MAZE 552. levl[x][y].typ = CORR; 553. #else 554. levl[x][y].typ = ROOM; 555. #endif 556. levl[x][y].flags = 0; 557. } 558. 559. while(1) { 560. q = 0; 561. for(a = 0; a < 4; a++) 562. if(okay(x,y,a)) dirs[q++]= a; 563. if(!q) return; 564. dir = dirs[rn2(q)]; 565. move(&x,&y,dir); 566. #ifndef WALLIFIED_MAZE 567. levl[x][y].typ = CORR; 568. #else 569. levl[x][y].typ = ROOM; 570. #endif 571. move(&x,&y,dir); 572. walkfrom(x,y); 573. } 574. } 575. #endif /* MICRO */ 576. 577. void 578. move(x,y,dir) 579. register int *x, *y; 580. register int dir; 581. { 582. switch(dir){ 583. case 0: --(*y); break; 584. case 1: (*x)++; break; 585. case 2: (*y)++; break; 586. case 3: --(*x); break; 587. } 588. } 589. 590. void 591. mazexy(cc) /* find random point in generated corridors, 592. so we don't create items in moats, bunkers, or walls */ 593. coord *cc; 594. { 595. int cpt=0; 596. 597. do { 598. cc->x = 3 + 2*rn2((x_maze_max>>1) - 1); 599. cc->y = 3 + 2*rn2((y_maze_max>>1) - 1); 600. cpt++; 601. } while (cpt < 100 && levl[cc->x][cc->y].typ != 602. #ifndef WALLIFIED_MAZE 603. CORR 604. #else 605. ROOM 606. #endif 607. ); 608. if (cpt >= 100) { 609. register int x, y; 610. /* last try */ 611. for (x = 0; x < (x_maze_max>>1) - 1; x++) 612. for (y = 0; y < (y_maze_max>>1) - 1; y++) { 613. cc->x = 3 + 2 * x; 614. cc->y = 3 + 2 * y; 615. if (levl[cc->x][cc->y].typ == 616. #ifndef WALLIFIED_MAZE 617. CORR 618. #else 619. ROOM 620. #endif 621. ) return; 622. } 623. panic("mazexy: can't find a place!"); 624. } 625. return; 626. } 627. 628. void 629. bound_digging() 630. /* put a non-diggable boundary around the initial portion of a level map. 631. * assumes that no level will initially put things beyond the isok() range. 632. * 633. * we can't bound unconditionally on the last line with something in it, 634. * because that something might be a niche which was already reachable, 635. * so the boundary would be breached 636. * 637. * we can't bound unconditionally on one beyond the last line, because 638. * that provides a window of abuse for WALLIFIED_MAZE special levels 639. */ 640. { 641. register int x,y; 642. register unsigned typ; 643. register struct rm *lev; 644. boolean found, nonwall; 645. int xmin,xmax,ymin,ymax; 646. 647. if(Is_earthlevel(&u.uz)) return; /* everything diggable here */ 648. 649. found = nonwall = FALSE; 650. for(xmin=0; !found; xmin++) { 651. lev = &levl[xmin][0]; 652. for(y=0; y<=ROWNO-1; y++, lev++) { 653. typ = lev->typ; 654. if(typ != STONE) { 655. found = TRUE; 656. if(!IS_WALL(typ)) nonwall = TRUE; 657. } 658. } 659. } 660. xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 661. if (xmin < 0) xmin = 0; 662. 663. found = nonwall = FALSE; 664. for(xmax=COLNO-1; !found; xmax--) { 665. lev = &levl[xmax][0]; 666. for(y=0; y<=ROWNO-1; y++, lev++) { 667. typ = lev->typ; 668. if(typ != STONE) { 669. found = TRUE; 670. if(!IS_WALL(typ)) nonwall = TRUE; 671. } 672. } 673. } 674. xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 675. if (xmax >= COLNO) xmax = COLNO-1; 676. 677. found = nonwall = FALSE; 678. for(ymin=0; !found; ymin++) { 679. lev = &levl[xmin][ymin]; 680. for(x=xmin; x<=xmax; x++, lev += ROWNO) { 681. typ = lev->typ; 682. if(typ != STONE) { 683. found = TRUE; 684. if(!IS_WALL(typ)) nonwall = TRUE; 685. } 686. } 687. } 688. ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 689. 690. found = nonwall = FALSE; 691. for(ymax=ROWNO-1; !found; ymax--) { 692. lev = &levl[xmin][ymax]; 693. for(x=xmin; x<=xmax; x++, lev += ROWNO) { 694. typ = lev->typ; 695. if(typ != STONE) { 696. found = TRUE; 697. if(!IS_WALL(typ)) nonwall = TRUE; 698. } 699. } 700. } 701. ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 702. 703. if(ymin >= 0) 704. for(x=xmin; x<=xmax; x++) levl[x][ymin].diggable = W_NONDIGGABLE; 705. if(ymax < ROWNO) 706. for(x=xmin; x<=xmax; x++) levl[x][ymax].diggable = W_NONDIGGABLE; 707. 708. /* Don't bound these until _after_ the previous loops to avoid "ice" */ 709. /* Normal rooms become ice by setting W_NONDIGGABLE -dlc */ 710. if (ymin < 0) ymin = 0; 711. if (ymax >= ROWNO) ymax = ROWNO-1; 712. 713. for(y=ymin; y<=ymax; y++) { 714. levl[xmin][y].diggable = W_NONDIGGABLE; 715. levl[xmax][y].diggable = W_NONDIGGABLE; 716. } 717. } 718. 719. void 720. mkportal(x, y, todnum, todlevel) 721. register xchar x, y, todnum, todlevel; 722. { 723. /* a portal "trap" must be matched by a */ 724. /* portal in the destination dungeon/dlevel */ 725. register struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL); 726. 727. #ifdef DEBUG 728. pline("mkportal: at (%d,%d), to %s, level %d", 729. x, y, dungeons[todnum].dname, todlevel); 730. #endif 731. ttmp->dst.dnum = todnum; 732. ttmp->dst.dlevel = todlevel; 733. return; 734. } 735. 736. /* 737. * Special waterlevel stuff in endgame (TH). 738. * 739. * Some of these functions would probably logically belong to some 740. * other source files, but they are all so nicely encapsulated here. 741. */ 742. 743. /* to ease the work of debuggers at this stage */ 744. #define register 745. 746. struct container { 747. struct container *next; 748. xchar x, y; 749. short what; 750. genericptr_t list; 751. }; 752. #define CONS_OBJ 0 753. #define CONS_MON 1 754. #define CONS_HERO 2 755. #define CONS_TRAP 3 756. 757. static struct bubble { 758. xchar x, y; /* coordinates of the upper left corner */ 759. schar dx, dy; /* the general direction of the bubble's movement */ 760. uchar *bm; /* pointer to the bubble bit mask */ 761. struct bubble *prev, *next; /* need to traverse the list up and down */ 762. struct container *cons; 763. } *bbubbles, *ebubbles; 764. 765. static struct trap *wportal; 766. static int xmin, ymin, xmax, ymax; /* level boundaries */ 767. /* bubble movement boundaries */ 768. #define bxmin (xmin + 1) 769. #define bymin (ymin + 1) 770. #define bxmax (xmax - 1) 771. #define bymax (ymax - 1) 772. 773. static void NDECL(set_wportal); 774. static void FDECL(mk_bubble, (int,int,int)); 775. static void FDECL(mv_bubble, (struct bubble *,int,int,BOOLEAN_P)); 776. 777. void 778. movebubbles() 779. { 780. static boolean up; 781. register struct bubble *b; 782. register int x, y, i, j; 783. struct trap *btrap; 784. static const struct rm water_pos = 785. { cmap_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0 }; 786. 787. /* set up the portal the first time bubbles are moved */ 788. if (!wportal) set_wportal(); 789. 790. vision_recalc(2); 791. 792. /* 793. * Pick up everything inside of a bubble then fill all bubble 794. * locations. 795. */ 796. 797. for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { 798. if (b->cons) panic("movebubbles: cons != null"); 799. for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) 800. for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) 801. if (b->bm[j + 2] & (1 << i)) { 802. if (!isok(x,y)) { 803. impossible("movebubbles: bad pos (%d,%d)", x,y); 804. continue; 805. } 806. 807. /* pick up objects, monsters, hero, and traps */ 808. if (OBJ_AT(x,y)) { 809. struct obj *olist = (struct obj *) 0, *otmp; 810. struct container *cons = (struct container *) 811. alloc(sizeof(struct container)); 812. 813. while ((otmp = level.objects[x][y]) != 0) { 814. remove_object(otmp); 815. otmp->ox = otmp->oy = 0; 816. otmp->nexthere = olist; 817. olist = otmp; 818. } 819. 820. cons->x = x; 821. cons->y = y; 822. cons->what = CONS_OBJ; 823. cons->list = (genericptr_t) olist; 824. cons->next = b->cons; 825. b->cons = cons; 826. } 827. if (MON_AT(x,y)) { 828. struct monst *mon = m_at(x,y); 829. struct container *cons = (struct container *) 830. alloc(sizeof(struct container)); 831. 832. cons->x = x; 833. cons->y = y; 834. cons->what = CONS_MON; 835. cons->list = (genericptr_t) mon; 836. 837. cons->next = b->cons; 838. b->cons = cons; 839. 840. if(mon->wormno) 841. remove_worm(mon); 842. else 843. remove_monster(x, y); 844. 845. newsym(x,y); /* clean up old position */ 846. mon->mx = mon->my = 0; 847. } 848. if (!u.uswallow && x == u.ux && y == u.uy) { 849. struct container *cons = (struct container *) 850. alloc(sizeof(struct container)); 851. 852. cons->x = x; 853. cons->y = y; 854. cons->what = CONS_HERO; 855. cons->list = (genericptr_t) 0; 856. 857. cons->next = b->cons; 858. b->cons = cons; 859. } 860. if ((btrap = t_at(x,y)) != 0) { 861. struct container *cons = (struct container *) 862. alloc(sizeof(struct container)); 863. 864. cons->x = x; 865. cons->y = y; 866. cons->what = CONS_TRAP; 867. cons->list = (genericptr_t) btrap; 868. 869. cons->next = b->cons; 870. b->cons = cons; 871. } 872. 873. levl[x][y] = water_pos; 874. block_point(x,y); 875. } 876. } 877. 878. /* 879. * Every second time traverse down. This is because otherwise 880. * all the junk that changes owners when bubbles overlap 881. * would eventually end up in the last bubble in the chain. 882. */ 883. 884. up = !up; 885. for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { 886. register int rx = rn2(3), ry = rn2(3); 887. 888. mv_bubble(b,b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)), 889. b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)), 890. FALSE); 891. } 892. 893. vision_full_recalc = 1; 894. } 895. 896. void 897. water_friction() 898. { 899. register boolean eff = FALSE; 900. 901. if (u.dx && !rn2(3)) { 902. eff = TRUE; 903. u.dx = 0; 904. } 905. if (u.dy && !rn2(3)) { 906. eff = TRUE; 907. u.dy = 0; 908. } 909. if (eff) pline("Water turbulence affects your movements."); 910. } 911. 912. void 913. save_waterlevel(fd) 914. register int fd; 915. { 916. register struct bubble *b; 917. int n; 918. 919. if (!Is_waterlevel(&u.uz)) return; 920. 921. for (b = bbubbles, n = 0; b; b = b->next, n++) ; 922. bwrite(fd,(genericptr_t)&n,sizeof(int)); 923. bwrite(fd,(genericptr_t)&xmin,sizeof(int)); 924. bwrite(fd,(genericptr_t)&ymin,sizeof(int)); 925. bwrite(fd,(genericptr_t)&xmax,sizeof(int)); 926. bwrite(fd,(genericptr_t)&ymax,sizeof(int)); 927. for (b = bbubbles; b; b = b->next) 928. bwrite(fd,(genericptr_t)b,sizeof(struct bubble)); 929. } 930. 931. void 932. restore_waterlevel(fd) 933. register int fd; 934. { 935. register struct bubble *b = (struct bubble *)0, *btmp; 936. register int i; 937. int n; 938. 939. if (!Is_waterlevel(&u.uz)) return; 940. 941. set_wportal(); 942. mread(fd,(genericptr_t)&n,sizeof(int)); 943. mread(fd,(genericptr_t)&xmin,sizeof(int)); 944. mread(fd,(genericptr_t)&ymin,sizeof(int)); 945. mread(fd,(genericptr_t)&xmax,sizeof(int)); 946. mread(fd,(genericptr_t)&ymax,sizeof(int)); 947. for (i = 0; i < n; i++) { 948. btmp = b; 949. b = (struct bubble *)alloc(sizeof(struct bubble)); 950. mread(fd,(genericptr_t)b,sizeof(struct bubble)); 951. if (bbubbles) { 952. btmp->next = b; 953. b->prev = btmp; 954. } else { 955. bbubbles = b; 956. b->prev = (struct bubble *)0; 957. } 958. mv_bubble(b,0,0,TRUE); 959. } 960. ebubbles = b; 961. b->next = (struct bubble *)0; 962. was_waterlevel = TRUE; 963. } 964. 965. static void 966. set_wportal() 967. { 968. /* there better be only one magic portal on water level... */ 969. for (wportal = ftrap; wportal; wportal = wportal->ntrap) 970. if (wportal->ttyp == MAGIC_PORTAL) return; 971. impossible("set_wportal(): no portal!"); 972. } 973. 974. static void 975. setup_waterlevel() 976. { 977. register int x, y; 978. register int xskip, yskip; 979. register int water_glyph = cmap_to_glyph(S_water); 980. 981. /* ouch, hardcoded... */ 982. 983. xmin = 3; 984. ymin = 1; 985. xmax = 78; 986. ymax = 20; 987. 988. /* set hero's memory to water */ 989. 990. for (x = xmin; x <= xmax; x++) 991. for (y = ymin; y <= ymax; y++) 992. levl[x][y].glyph = water_glyph; 993. 994. /* make bubbles */ 995. 996. xskip = 10 + rn2(10); 997. yskip = 4 + rn2(4); 998. for (x = bxmin; x <= bxmax; x += xskip) 999. for (y = bymin; y <= bymax; y += yskip) 1000. mk_bubble(x,y,rn2(7)); 1001. } 1002. 1003. static void 1004. unsetup_waterlevel() 1005. { 1006. register struct bubble *b, *bb; 1007. 1008. /* free bubbles */ 1009. 1010. for (b = bbubbles; b; b = bb) { 1011. bb = b->next; 1012. free((genericptr_t)b); 1013. } 1014. bbubbles = ebubbles = (struct bubble *)0; 1015. } 1016. 1017. static void 1018. mk_bubble(x,y,n) 1019. register int x, y, n; 1020. { 1021. /* 1022. * These bit masks make visually pleasing bubbles on a normal aspect 1023. * 25x80 terminal, which naturally results in them being mathematically 1024. * anything but symmetric. For this reason they cannot be computed 1025. * in situ, either. The first two elements tell the dimensions of 1026. * the bubble's bounding box. 1027. */ 1028. static uchar 1029. bm2[] = {2,1,0x3}, 1030. bm3[] = {3,2,0x7,0x7}, 1031. bm4[] = {4,3,0x6,0xf,0x6}, 1032. bm5[] = {5,3,0xe,0x1f,0xe}, 1033. bm6[] = {6,4,0x1e,0x3f,0x3f,0x1e}, 1034. bm7[] = {7,4,0x3e,0x7f,0x7f,0x3e}, 1035. bm8[] = {8,4,0x7e,0xff,0xff,0x7e}, 1036. *bmask[] = {bm2,bm3,bm4,bm5,bm6,bm7,bm8}; 1037. 1038. register struct bubble *b; 1039. 1040. if (x >= bxmax || y >= bymax) return; 1041. if (n >= SIZE(bmask)) { 1042. impossible("n too large (mk_bubble)"); 1043. n = SIZE(bmask) - 1; 1044. } 1045. b = (struct bubble *)alloc(sizeof(struct bubble)); 1046. if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1; 1047. if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1; 1048. b->x = x; 1049. b->y = y; 1050. b->dx = 1 - rn2(3); 1051. b->dy = 1 - rn2(3); 1052. b->bm = bmask[n]; 1053. b->cons = 0; 1054. if (!bbubbles) bbubbles = b; 1055. if (ebubbles) { 1056. ebubbles->next = b; 1057. b->prev = ebubbles; 1058. } 1059. else 1060. b->prev = (struct bubble *)0; 1061. b->next = (struct bubble *)0; 1062. ebubbles = b; 1063. mv_bubble(b,0,0,TRUE); 1064. } 1065. 1066. /* 1067. * The player, the portal and all other objects and monsters 1068. * float along with their associated bubbles. Bubbles may overlap 1069. * freely, and the contents may get associated with other bubbles in 1070. * the process. Bubbles are "sticky", meaning that if the player is 1071. * in the immediate neighborhood of one, he/she may get sucked inside. 1072. * This property also makes leaving a bubble slightly difficult. 1073. */ 1074. static void 1075. mv_bubble(b,dx,dy,ini) 1076. register struct bubble *b; 1077. register int dx, dy; 1078. register boolean ini; 1079. { 1080. register int x, y, i, j, colli = 0; 1081. struct bubble ob; 1082. struct container *cons, *ctemp; 1083. 1084. /* some old data for reference */ 1085. 1086. ob.x = b->x; 1087. ob.y = b->y; 1088. ob.bm = b->bm; 1089. 1090. /* move bubble */ 1091. if (dx < -1 || dx > 1 || dy < -1 || dy > 1) { 1092. /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */ 1093. dx = sgn(dx); 1094. dy = sgn(dy); 1095. } 1096. 1097. /* 1098. * collision with level borders? 1099. * 1 = horizontal border, 2 = vertical, 3 = corner 1100. */ 1101. if (b->x <= bxmin) colli |= 2; 1102. if (b->y <= bymin) colli |= 1; 1103. if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2; 1104. if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1; 1105. 1106. if (b->x < bxmin) { 1107. pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin); 1108. b->x = bxmin; 1109. } 1110. if (b->y < bymin) { 1111. pline("bubble ymin: y = %d, ymin = %d", b->y, bymin); 1112. b->y = bymin; 1113. } 1114. if ((int) (b->x + b->bm[0] - 1) > bxmax) { 1115. pline("bubble xmax: x = %d, xmax = %d", 1116. b->x + b->bm[0] - 1, bxmax); 1117. b->x = bxmax - b->bm[0] + 1; 1118. } 1119. if ((int) (b->y + b->bm[1] - 1) > bymax) { 1120. pline("bubble ymax: y = %d, ymax = %d", 1121. b->y + b->bm[1] - 1, bymax); 1122. b->y = bymax - b->bm[1] + 1; 1123. } 1124. 1125. /* bounce if we're trying to move off the border */ 1126. if (b->x == bxmin && dx < 0) dx = -dx; 1127. if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx; 1128. if (b->y == bymin && dy < 0) dy = -dy; 1129. if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy; 1130. 1131. b->x += dx; 1132. b->y += dy; 1133. 1134. /* void positions inside bubble */ 1135. 1136. for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) 1137. for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) 1138. if (b->bm[j + 2] & (1 << i)) { 1139. levl[x][y].typ = AIR; 1140. levl[x][y].lit = 1; 1141. unblock_point(x,y); 1142. } 1143. 1144. /* replace contents of bubble */ 1145. for (cons = b->cons; cons; cons = ctemp) { 1146. ctemp = cons->next; 1147. cons->x += dx; 1148. cons->y += dy; 1149. 1150. switch(cons->what) { 1151. case CONS_OBJ: { 1152. struct obj *olist, *otmp; 1153. 1154. for (olist=(struct obj *)cons->list; olist; olist=otmp) { 1155. otmp = olist->nexthere; 1156. place_object(olist, cons->x, cons->y); 1157. } 1158. break; 1159. } 1160. 1161. case CONS_MON: { 1162. struct monst *mon = (struct monst *) cons->list; 1163. (void) mnearto(mon, cons->x, cons->y, TRUE); 1164. break; 1165. } 1166. 1167. case CONS_HERO: { 1168. int ux0 = u.ux, uy0 = u.uy; 1169. 1170. /* change u.ux0 and u.uy0? */ 1171. u.ux = cons->x; 1172. u.uy = cons->y; 1173. newsym(ux0, uy0); /* clean up old position */ 1174. 1175. if (MON_AT(cons->x, cons->y)) { 1176. mnexto(m_at(cons->x,cons->y)); 1177. } 1178. if (Punished) placebc(); /* do this for now */ 1179. break; 1180. } 1181. 1182. case CONS_TRAP: { 1183. struct trap *btrap = (struct trap *) cons->list; 1184. btrap->tx = cons->x; 1185. btrap->ty = cons->y; 1186. break; 1187. } 1188. 1189. default: 1190. impossible("mv_bubble: unknown bubble contents"); 1191. break; 1192. } 1193. free((genericptr_t)cons); 1194. } 1195. b->cons = 0; 1196. 1197. /* boing? */ 1198. 1199. switch (colli) { 1200. case 1: b->dy = -b->dy; break; 1201. case 3: b->dy = -b->dy; /* fall through */ 1202. case 2: b->dx = -b->dx; break; 1203. default: 1204. /* sometimes alter direction for fun anyway 1205. (higher probability for stationary bubbles) */ 1206. if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) { 1207. b->dx = 1 - rn2(3); 1208. b->dy = 1 - rn2(3); 1209. } 1210. } 1211. } 1212. 1213. 1214. /*mkmaze.c*/