Below is the full text to hack.do.c from the source code of Hack 1.0. To link to a particular line, write [[Hack 1.0/hack.do.c#line123]], for example.
Warning! This is the source code from an old release. For the latest release, see Source code
Screenshots and source code from Hack are used under the CWI license. |
1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2. 3. #include <stdio.h> 4. #include <signal.h> 5. #include "hack.h" 6. #include "def.func_tab.h" 7. 8. extern char *getenv(),*parse(),*getlogin(),*lowc(),*unctrl(); 9. extern int float_down(); 10. extern char *nomovemsg, *catmore; 11. extern struct obj *splitobj(), *addinv(); 12. extern boolean hmon(); 13. 14. /* Routines to do various user commands */ 15. 16. int done1(); 17. 18. dodrink() { 19. register struct obj *otmp,*objs; 20. register struct monst *mtmp; 21. register int unkn = 0, nothing = 0; 22. 23. otmp = getobj("!", "drink"); 24. if(!otmp) return(0); 25. switch(otmp->otyp){ 26. case POT_RESTORE_STRENGTH: 27. unkn++; 28. pline("Wow! This makes you feel great!"); 29. if(u.ustr < u.ustrmax) { 30. u.ustr = u.ustrmax; 31. flags.botl = 1; 32. } 33. break; 34. case POT_BOOZE: 35. unkn++; 36. pline("Ooph! This tastes like liquid fire!"); 37. Confusion += d(3,8); 38. /* the whiskey makes us feel better */ 39. if(u.uhp < u.uhpmax) losehp(-1, "bottle of whiskey"); 40. if(!rn2(4)) { 41. pline("You pass out."); 42. multi = -rnd(15); 43. nomovemsg = "You awake with a headache."; 44. } 45. break; 46. case POT_INVISIBILITY: 47. if(Invis) 48. nothing++; 49. else { 50. if(!Blind) 51. pline("Gee! All of a sudden, you can't see yourself."); 52. else 53. pline("You feel rather airy."), unkn++; 54. newsym(u.ux,u.uy); 55. } 56. Invis += rn1(15,31); 57. break; 58. case POT_FRUIT_JUICE: 59. pline("This tastes like fruit juice."); 60. lesshungry(20); 61. break; 62. case POT_HEALING: 63. pline("You begin to feel better."); 64. flags.botl = 1; 65. u.uhp += rnd(10); 66. if(u.uhp > u.uhpmax) 67. u.uhp = ++u.uhpmax; 68. if(Blind) Blind = 1; /* see on next move */ 69. if(Sick) Sick = 0; 70. break; 71. case POT_PARALYSIS: 72. pline("Your feet are frozen to the floor!"); 73. nomul(-(rn1(10,25))); 74. break; 75. case POT_MONSTER_DETECTION: 76. if(!fmon) { 77. strange_feeling(otmp); 78. return(1); 79. } else { 80. cls(); 81. for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) 82. if(mtmp->mx > 0) 83. at(mtmp->mx,mtmp->my,mtmp->data->mlet); 84. prme(); 85. pline("You sense the presence of monsters."); 86. more(); 87. docrt(); 88. } 89. break; 90. case POT_OBJECT_DETECTION: 91. if(!fobj) { 92. strange_feeling(otmp); 93. return(1); 94. } else { 95. for(objs = fobj; objs; objs = objs->nobj) 96. if(objs->ox != u.ux || objs->oy != u.uy) 97. goto outobjmap; 98. pline("You sense the presence of objects close nearby."); 99. break; 100. outobjmap: 101. cls(); 102. for(objs = fobj; objs; objs = objs->nobj) 103. at(objs->ox,objs->oy,objs->olet); 104. prme(); 105. pline("You sense the presence of objects."); 106. more(); 107. docrt(); 108. } 109. break; 110. case POT_SICKNESS: 111. pline("Yech! This stuff tastes like poison."); 112. if(Poison_resistance) 113. pline("(But in fact it was biologically contaminated orange juice.)"); 114. losestr(rn1(4,3)); 115. losehp(rnd(10), "poison potion"); 116. break; 117. case POT_CONFUSION: 118. if(!Confusion) 119. pline("Huh, What? Where am I?"); 120. else 121. nothing++; 122. Confusion += rn1(7,16); 123. break; 124. case POT_GAIN_STRENGTH: 125. pline("Wow do you feel strong!"); 126. if(u.ustr == 118) break; 127. if(u.ustr > 17) u.ustr += rnd(118-u.ustr); 128. else u.ustr++; 129. if(u.ustr > u.ustrmax) u.ustrmax = u.ustr; 130. flags.botl = 1; 131. break; 132. case POT_SPEED: 133. if(Wounded_legs) { 134. if((Wounded_legs & BOTH_SIDES) == BOTH_SIDES) 135. pline("Your legs feel somewhat better."); 136. else 137. pline("Your leg feels somewhat better."); 138. Wounded_legs = 0; 139. unkn++; 140. break; 141. } 142. if(!(Fast & ~INTRINSIC)) 143. pline("You are suddenly moving much faster."); 144. else 145. pline("Your legs get new energy."), unkn++; 146. Fast += rn1(10,100); 147. break; 148. case POT_BLINDNESS: 149. if(!Blind) 150. pline("A cloud of darkness falls upon you."); 151. else 152. nothing++; 153. Blind += rn1(100,250); 154. seeoff(0); 155. break; 156. case POT_GAIN_LEVEL: 157. pluslvl(); 158. break; 159. case POT_EXTRA_HEALING: 160. pline("You feel much better."); 161. flags.botl = 1; 162. u.uhp += d(2,20)+1; 163. if(u.uhp > u.uhpmax) 164. u.uhp = (u.uhpmax += 2); 165. if(Blind) Blind = 1; 166. if(Sick) Sick = 0; 167. break; 168. case POT_LEVITATION: 169. if(!Levitation) 170. float_up(); 171. else 172. nothing++; 173. Levitation += rnd(100); 174. u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down; 175. break; 176. default: 177. pline("What a funny potion! (%d)", otmp->otyp); 178. impossible(); 179. return(0); 180. } 181. if(nothing) { 182. unkn++; 183. pline("You have a peculiar feeling for a moment, then it passes."); 184. } 185. if(otmp->dknown && !objects[otmp->otyp].oc_name_known) { 186. if(!unkn) { 187. objects[otmp->otyp].oc_name_known = 1; 188. u.urexp += 10; 189. } else if(!objects[otmp->otyp].oc_uname) 190. docall(otmp); 191. } 192. useup(otmp); 193. return(1); 194. } 195. 196. pluslvl() 197. { 198. register num; 199. 200. pline("You feel more experienced."); 201. num = rnd(10); 202. u.uhpmax += num; 203. u.uhp += num; 204. u.uexp = (10*pow(u.ulevel-1))+1; 205. pline("Welcome to level %d.", ++u.ulevel); 206. flags.botl = 1; 207. } 208. 209. strange_feeling(obj) 210. register struct obj *obj; 211. { 212. pline("You have a strange feeling for a moment, then it passes."); 213. if(!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) 214. docall(obj); 215. useup(obj); 216. } 217. 218. dodrop() { 219. register struct obj *obj; 220. 221. obj = getobj("0$#", "drop"); 222. if(!obj) return(0); 223. if(obj->olet == '$') { 224. if(obj->quan == 0) 225. pline("You didn't drop any gold pieces."); 226. else { 227. mkgold((int) obj->quan, u.ux, u.uy); 228. pline("You dropped %u gold piece%s.", 229. obj->quan, plur(obj->quan)); 230. if(Invis) newsym(u.ux, u.uy); 231. } 232. free((char *) obj); 233. return(1); 234. } 235. return(drop(obj)); 236. } 237. 238. drop(obj) register struct obj *obj; { 239. if(obj->owornmask & (W_ARMOR | W_RING)){ 240. pline("You cannot drop something you are wearing."); 241. return(0); 242. } 243. if(obj == uwep) { 244. if(uwep->cursed) { 245. pline("Your weapon is welded to your hand!"); 246. return(0); 247. } 248. setuwep((struct obj *) 0); 249. } 250. pline("You dropped %s.", doname(obj)); 251. dropx(obj); 252. return(1); 253. } 254. 255. dropx(obj) register struct obj *obj; { 256. if(obj->otyp == CRYSKNIFE) 257. obj->otyp = WORM_TOOTH; 258. freeinv(obj); 259. obj->ox = u.ux; 260. obj->oy = u.uy; 261. obj->nobj = fobj; 262. fobj = obj; 263. if(Invis) newsym(u.ux,u.uy); 264. subfrombill(obj); 265. stackobj(obj); 266. } 267. 268. /* drop several things */ 269. doddrop() { 270. return(ggetobj("drop", drop, 0)); 271. } 272. 273. rhack(cmd) 274. register char *cmd; 275. { 276. register struct func_tab *tlist = list; 277. boolean firsttime = FALSE; 278. register res; 279. 280. if(!cmd) { 281. firsttime = TRUE; 282. flags.nopick = 0; 283. cmd = parse(); 284. } 285. if(!*cmd || *cmd == 0377) 286. return; /* probably we just had an interrupt */ 287. if(movecm(cmd)) { 288. walk: 289. if(multi) flags.mv = 1; 290. domove(); 291. return; 292. } 293. if(movecm(lowc(cmd))) { 294. flags.run = 1; 295. rush: 296. if(firsttime){ 297. if(!multi) multi = COLNO; 298. u.last_str_turn = 0; 299. } 300. flags.mv = 1; 301. #ifdef QUEST 302. if(flags.run >= 4) finddir(); 303. if(firsttime){ 304. u.ux0 = u.ux + u.dx; 305. u.uy0 = u.uy + u.dy; 306. } 307. #endif QUEST 308. domove(); 309. return; 310. } 311. if((*cmd == 'f' && movecm(cmd+1)) || 312. movecm(unctrl(cmd))) { 313. flags.run = 2; 314. goto rush; 315. } 316. if(*cmd == 'F' && movecm(lowc(cmd+1))) { 317. flags.run = 3; 318. goto rush; 319. } 320. if(*cmd == 'm' && movecm(cmd+1)) { 321. flags.run = 0; 322. flags.nopick = 1; 323. goto walk; 324. } 325. if(*cmd == 'M' && movecm(lowc(cmd+1))) { 326. flags.run = 1; 327. flags.nopick = 1; 328. goto rush; 329. } 330. #ifdef QUEST 331. if(*cmd == cmd[1] && (*cmd == 'f' || *cmd == 'F')) { 332. flags.run = 4; 333. if(*cmd == 'F') flags.run += 2; 334. if(cmd[2] == '-') flags.run += 1; 335. goto rush; 336. } 337. #endif QUEST 338. while(tlist->f_char) { 339. if(*cmd == tlist->f_char){ 340. res = (*(tlist->f_funct))(0); 341. if(!res) { 342. flags.move = 0; 343. multi = 0; 344. } 345. return; 346. } 347. tlist++; 348. } 349. pline("Unknown command '%s'",cmd); 350. multi = flags.move = 0; 351. } 352. 353. doredraw() 354. { 355. docrt(); 356. return(0); 357. } 358. 359. dohelp() 360. { 361. if(child(1)){ 362. execl(catmore,"more","help",(char *)0); 363. exit(1); 364. } 365. return(0); 366. } 367. 368. #ifdef SHELL 369. dosh(){ 370. register char *str; 371. if(child(0)) { 372. (void) chdir(getenv("HOME")); 373. if(str = getenv("SHELL")) execl(str,str,(char *) 0); 374. if(strcmp("player", getlogin())) 375. execl("/bin/sh","sh",(char *) 0); 376. pline("sh: cannot execute."); 377. exit(1); 378. } 379. return(0); 380. } 381. #endif SHELL 382. 383. #ifdef BSD 384. #include <sys/wait.h> 385. #else 386. #include <wait.h> 387. #endif BSD 388. 389. child(wt) { 390. register int f = fork(); 391. if(f == 0){ /* child */ 392. settty((char *) 0); 393. (void) setuid(getuid()); 394. return(1); 395. } 396. if(f == -1) { /* cannot fork */ 397. pline("Fork failed. Try again."); 398. return(0); 399. } 400. /* fork succeeded; wait for child to exit */ 401. (void) signal(SIGINT,SIG_IGN); 402. (void) signal(SIGQUIT,SIG_IGN); 403. (void) wait((union wait *) 0); 404. setctty(); 405. (void) signal(SIGINT,done1); 406. #ifdef WIZARD 407. if(wizard) (void) signal(SIGQUIT,SIG_DFL); 408. #endif WIZARD 409. if(wt) getret(); 410. docrt(); 411. return(0); 412. } 413. 414. dodown() 415. { 416. if(u.ux != xdnstair || u.uy != ydnstair) { 417. pline("You can't go down here."); 418. return(0); 419. } 420. if(u.ustuck) { 421. pline("You are being held, and cannot go down."); 422. return(1); 423. } 424. if(Levitation) { 425. pline("You're floating high above the stairs."); 426. return(0); 427. } 428. 429. goto_level(dlevel+1, TRUE); 430. return(1); 431. } 432. 433. doup() 434. { 435. if(u.ux != xupstair || u.uy != yupstair) { 436. pline("You can't go up here."); 437. return(0); 438. } 439. if(u.ustuck) { 440. pline("You are being held, and cannot go up."); 441. return(1); 442. } 443. if(inv_weight() + 5 > 0) { 444. pline("Your load is too heavy to climb the stairs."); 445. return(1); 446. } 447. 448. goto_level(dlevel-1, TRUE); 449. return(1); 450. } 451. 452. goto_level(newlevel, at_stairs) 453. register int newlevel; 454. register boolean at_stairs; 455. { 456. register fd; 457. register boolean up = (newlevel < dlevel); 458. 459. if(newlevel <= 0) done("escaped"); /* in fact < 0 is impossible */ 460. if(newlevel == dlevel) return; /* this cannot happen either */ 461. 462. glo(dlevel); 463. fd = creat(lock,FMASK); 464. if(fd < 0) { 465. /* 466. * This is not quite impossible: e.g., we may have 467. * exceeded our quota. If that is the case then we 468. * cannot leave this level, and cannot save either. 469. */ 470. pline("A mysterious force prevents you from going %d.", 471. up ? "up" : "down"); 472. return; 473. } 474. 475. if(Punished) unplacebc(); 476. keepdogs(); 477. seeoff(1); 478. flags.nscrinh = 1; 479. u.ux = FAR; /* hack */ 480. (void) inshop(); /* probably was a trapdoor */ 481. 482. savelev(fd); 483. (void) close(fd); 484. 485. dlevel = newlevel; 486. if(maxdlevel < dlevel) 487. maxdlevel = dlevel; 488. glo(dlevel); 489. if((fd = open(lock,0)) < 0) 490. mklev(); 491. else { 492. (void) getlev(fd); 493. (void) close(fd); 494. } 495. 496. if(at_stairs) { 497. if(up) { 498. u.ux = xdnstair; 499. u.uy = ydnstair; 500. if(!u.ux) { /* entering a maze from below? */ 501. u.ux = xupstair; /* this will confuse the player! */ 502. u.uy = yupstair; 503. } 504. if(Punished){ 505. pline("With great effort you climb the stairs"); 506. placebc(1); 507. } 508. } else { 509. u.ux = xupstair; 510. u.uy = yupstair; 511. if(inv_weight() + 5 > 0 || Punished){ 512. pline("You fall down the stairs."); 513. losehp(rnd(3), "fall"); 514. if(Punished) { 515. if(uwep != uball && rn2(3)){ 516. pline("... and are hit by the iron ball"); 517. losehp(rnd(20), "iron ball"); 518. } 519. placebc(1); 520. } 521. selftouch("Falling, you"); 522. } 523. } 524. } else { /* trapdoor or level_tele */ 525. do { 526. u.ux = rnd(COLNO-1); 527. u.uy = rn2(ROWNO); 528. } while(levl[u.ux][u.uy].typ != ROOM || 529. m_at(u.ux,u.uy)); 530. if(Punished){ 531. if(uwep != uball && !up /* %% */ && rn2(5)){ 532. pline("The iron ball falls on your head."); 533. losehp(rnd(25), "iron ball"); 534. } 535. placebc(1); 536. } 537. selftouch("Falling, you"); 538. } 539. (void) inshop(); 540. #ifdef TRACK 541. initrack(); 542. #endif TRACK 543. 544. losedogs(); 545. flags.nscrinh = 0; 546. setsee(); 547. docrt(); 548. pickup(); 549. read_engr_at(u.ux,u.uy); 550. } 551. 552. donull() { 553. return(1); /* Do nothing, but let other things happen */ 554. } 555. 556. struct monst *bhit(), *boomhit(); 557. dothrow() 558. { 559. register struct obj *obj; 560. register struct monst *mon; 561. register tmp; 562. 563. obj = getobj("#)", "throw"); /* it is also possible to throw food */ 564. /* (or jewels, or iron balls ... ) */ 565. if(!obj || !getdir()) 566. return(0); 567. if(obj->owornmask & (W_ARMOR | W_RING)){ 568. pline("You can't throw something you are wearing"); 569. return(0); 570. } 571. if(obj == uwep){ 572. if(obj->cursed){ 573. pline("Your weapon is welded to your hand"); 574. return(1); 575. } 576. if(obj->quan > 1) 577. setuwep(splitobj(obj, 1)); 578. else 579. setuwep((struct obj *) 0); 580. } 581. else if(obj->quan > 1) 582. (void) splitobj(obj, 1); 583. freeinv(obj); 584. if(u.uswallow) { 585. mon = u.ustuck; 586. bhitpos.x = mon->mx; 587. bhitpos.y = mon->my; 588. } else if(obj->otyp == BOOMERANG) { 589. mon = boomhit(u.dx,u.dy); 590. /* boomhit delivers -1 if the thing was caught */ 591. if((int) mon == -1) { 592. (void) addinv(obj); 593. return(1); 594. } 595. } else 596. mon = bhit(u.dx,u.dy, 597. (!Punished || obj != uball) ? 8 : 598. !u.ustuck ? 5 : 1, 599. obj->olet); 600. if(mon) { 601. /* awake monster if sleeping */ 602. wakeup(mon); 603. 604. if(obj->olet == WEAPON_SYM) { 605. tmp = -1+u.ulevel+mon->data->ac+abon(); 606. if(obj->otyp < ROCK) { 607. if(!uwep || 608. uwep->otyp != obj->otyp+(BOW-ARROW)) 609. tmp -= 4; 610. else { 611. tmp += uwep->spe; 612. } 613. } else 614. if(obj->otyp == BOOMERANG) tmp += 4; 615. tmp += obj->spe; 616. if(u.uswallow || tmp >= rnd(20)) { 617. if(hmon(mon,obj,1) == TRUE){ 618. /* mon still alive */ 619. #ifndef NOWORM 620. cutworm(mon,bhitpos.x,bhitpos.y,obj->otyp); 621. #endif NOWORM 622. } else mon = 0; 623. /* weapons thrown disappear sometimes */ 624. if(obj->otyp < BOOMERANG && rn2(3)) { 625. /* check bill; free */ 626. obfree(obj, (struct obj *) 0); 627. return(1); 628. } 629. } else miss(objects[obj->otyp].oc_name, mon); 630. } else if(obj->otyp == HEAVY_IRON_BALL) { 631. tmp = -1+u.ulevel+mon->data->ac+abon(); 632. if(!Punished || obj != uball) tmp += 2; 633. if(u.utrap) tmp -= 2; 634. if(u.uswallow || tmp >= rnd(20)) { 635. if(hmon(mon,obj,1) == FALSE) 636. mon = 0; /* he died */ 637. } else miss("iron ball", mon); 638. } else { 639. if(cansee(bhitpos.x,bhitpos.y)) 640. pline("You miss %s.",monnam(mon)); 641. else pline("You miss it."); 642. if(obj->olet == FOOD_SYM && mon->data->mlet == 'd') 643. if(tamedog(mon,obj)) return(1); 644. if(obj->olet == GEM_SYM && mon->data->mlet == 'u'){ 645. if(obj->dknown && objects[obj->otyp].oc_name_known){ 646. if(objects[obj->otyp].g_val > 0){ 647. u.uluck += 5; 648. goto valuable; 649. } else { 650. pline("%s is not interested in your junk.", 651. Monnam(mon)); 652. } 653. } else { /* value unknown to @ */ 654. u.uluck++; 655. valuable: 656. pline("%s graciously accepts your gift.", 657. Monnam(mon)); 658. mpickobj(mon, obj); 659. rloc(mon); 660. return(1); 661. } 662. } 663. } 664. } 665. obj->ox = bhitpos.x; 666. obj->oy = bhitpos.y; 667. obj->nobj = fobj; 668. fobj = obj; 669. /* prevent him from throwing articles to the exit and escaping */ 670. /* subfrombill(obj); */ 671. stackobj(obj); 672. if(Punished && obj == uball && 673. (bhitpos.x != u.ux || bhitpos.y != u.uy)){ 674. freeobj(uchain); 675. unpobj(uchain); 676. if(u.utrap){ 677. if(u.utraptype == TT_PIT) 678. pline("The ball pulls you out of the pit!"); 679. else { 680. register int side = 681. rn2(3) ? LEFT_SIDE : RIGHT_SIDE; 682. pline("The ball pulls you out of the bear trap."); 683. pline("Your %s leg is severely damaged.", 684. (side == LEFT_SIDE) ? "left" : "right"); 685. Wounded_legs |= side + rnd(1000); 686. losehp(2, "thrown ball"); 687. } 688. u.utrap = 0; 689. } 690. unsee(); 691. uchain->nobj = fobj; 692. fobj = uchain; 693. u.ux = uchain->ox = bhitpos.x - u.dx; 694. u.uy = uchain->oy = bhitpos.y - u.dy; 695. setsee(); 696. (void) inshop(); 697. } 698. if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y); 699. return(1); 700. } 701. 702. getdir() 703. { 704. char buf[2]; 705. pline("What direction?"); 706. buf[0] = readchar(); 707. buf[1] = 0; 708. return(movecm(buf)); 709. } 710. 711. /* split obj so that it gets size num */ 712. /* remainder is put in the object structure delivered by this call */ 713. struct obj * 714. splitobj(obj, num) register struct obj *obj; register int num; { 715. register struct obj *otmp; 716. otmp = newobj(0); 717. *otmp = *obj; /* copies whole structure */ 718. otmp->o_id = flags.ident++; 719. otmp->onamelth = 0; 720. obj->quan = num; 721. obj->owt = weight(obj); 722. otmp->quan -= num; 723. otmp->owt = weight(otmp); /* -= obj->owt ? */ 724. obj->nobj = otmp; 725. if(obj->unpaid) splitbill(obj,otmp); 726. return(otmp); 727. } 728. 729. char * 730. lowc(str) 731. register char *str; 732. { 733. static char buf[2]; 734. 735. if(*str >= 'A' && *str <= 'Z') *buf = *str+'a'-'A'; 736. else *buf = *str; 737. buf[1] = 0; 738. return(buf); 739. } 740. 741. char * 742. unctrl(str) 743. register char *str; 744. { 745. static char buf[2]; 746. if(*str >= ('A' & 037) && *str <= ('Z' & 037)) 747. *buf = *str + 0140; 748. else *buf = *str; 749. buf[1] = 0; 750. return(buf); 751. }