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