home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume18 / ccr / part09 < prev    next >
Internet Message Format  |  1993-07-19  |  62KB

  1. Path: uunet!news.tek.com!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v18i024:  ccr - colossal cave (adventure) implemented in TADS, Part09/11
  5. Date: 12 Jul 1993 19:29:11 GMT
  6. Organization: Tektronix, Inc, Redmond, OR, USA
  7. Lines: 2427
  8. Approved: billr@saab.CNA.TEK.COM
  9. Message-ID: <21se27$1d2@ying.cna.tek.com>
  10. NNTP-Posting-Host: saab.cna.tek.com
  11. Xref: uunet comp.sources.games:1824
  12.  
  13. Submitted-by: David Baggett <dmb@xbar.ai.mit.edu>
  14. Posting-number: Volume 18, Issue 24
  15. Archive-name: ccr/part09
  16. Environment: TADS
  17.  
  18.  
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 9 (of 11)."
  27. # Contents:  src/ccr-item.t src/ccr-npc.t src/ccr.t src/makefile
  28. # Wrapped by billr@saab on Mon Jul 12 12:02:45 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'src/ccr-item.t' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'src/ccr-item.t'\"
  32. else
  33. echo shar: Extracting \"'src/ccr-item.t'\" \(26875 characters\)
  34. sed "s/^X//" >'src/ccr-item.t' <<'END_OF_FILE'
  35. X/*
  36. X * Colossal Cave Revisited
  37. X *
  38. X * A remake of Willie Crowther and Don Woods' classic Adventure.
  39. X * Converted from Donald Ekman's PC port of the original FORTRAN source.
  40. X * TADS version by David M. Baggett for ADVENTIONS.
  41. X *
  42. X * Please document all changes in the history so we know who did what.
  43. X *
  44. X * This source code is copylefted under the terms of the GNU Public
  45. X * License.  Essentially, this means that you are free to do whatever
  46. X * you wish with this source code, provided you do not charge any
  47. X * money for it or for any derivative works.
  48. X *
  49. X * ADVENTIONS distributes this game, but you are free to do what you will
  50. X * with it, provided you adhere to the terms in the GNU Public License.
  51. X * Send correspondence regarding this game or original works distributed
  52. X * by ADVENTIONS to 
  53. X *
  54. X *    ADVENTIONS
  55. X *    PO Box 851
  56. X *    Columbia, MD 21044 USA
  57. X *
  58. X * If you would like a catalog of releases, please enclose a SASE.  Thanks!
  59. X *
  60. X * Contributors
  61. X *
  62. X *    dmb    In real life:    David M. Baggett
  63. X *        Internet:    <dmb@ai.mit.edu>
  64. X *        Compu$erve:    76440,2671 (ADVENTIONS account)
  65. X *        GEnie:        ADVENTIONS
  66. X *
  67. X * Modification History
  68. X *
  69. X *  1-Jan-93    dmb    rec.arts.int-fiction BETA release (source only)
  70. X *                      For beta testing only -- not for general
  71. X *            distribution.
  72. X * 20-Apr-93    dmb    Fixed a bug with the treasures: you could
  73. X *            get points for a treasure without being able
  74. X *            to carry it.
  75. X */
  76. X
  77. X/*
  78. X * This file defines all carryable items in the game.
  79. X */
  80. Xclass CCR_item: item;
  81. X
  82. X/*
  83. X * Important notes about treasures:
  84. X *
  85. X * If you want to add treasures, use the CCR_treasure_item class.  Take
  86. X * care to call the original doDrop and pass doTake if you override the
  87. X * doDrop or doTake methods, because it is in these methods that we
  88. X * handle the scoring.
  89. X *
  90. X * Each treasure is worth self.takepoints points when taken for the
  91. X * first time, and an additional self.depositpoints when deposited
  92. X * in the bulding.  Be sure to update global.maxscore and scoreRank
  93. X * if you add treasures (or anything else that gives the player points,
  94. X * for that matter).
  95. X *
  96. X * The proper way to check if an object is a treasure is:
  97. X *
  98. X *     if (isclass(obj, CCR_treasure_item))
  99. X *        ...
  100. X *
  101. X */
  102. Xclass CCR_treasure_item: CCR_item
  103. X    plural = 'treasures' 'goodies' 'loot'
  104. X
  105. X    takepoints = 2        // points for taking this treasure
  106. X    depositpoints = 12    // points for putting in building
  107. X
  108. X    awardedpointsfortaking = nil
  109. X    awardedpointsfordepositing = nil
  110. X    
  111. X    doTake(actor) = {
  112. X        inherited.doTake(actor);
  113. X
  114. X        //
  115. X        // If we didn't get the object (e.g., if the actor's carrying
  116. X        // too much), don't give points.
  117. X        //
  118. X        if (not self.isIn(actor))
  119. X            return;
  120. X
  121. X        //
  122. X        // Give the player some points for taking the treasure
  123. X        // the first time.
  124. X        //
  125. X        // If the player removes a treasure from the bulding
  126. X        // floor, reduce his score by the value of that
  127. X        // treasure.  (This is to prevent him from dropping
  128. X        // a treasure off, getting the points, and then giving
  129. X        // it to the troll or otherwise losing it.) 
  130. X        //
  131. X        if (not self.awardedpointsfortaking) {
  132. X            incscore(self.takepoints);
  133. X            self.awardedpointsfortaking := true;
  134. X        }
  135. X        if (self.awardedpointsfordepositing) {
  136. X            if (self.isIn(Inside_Building)) {
  137. X                incscore(-1 * self.depositpoints);
  138. X                self.awardedpointsfordepositing := nil;
  139. X
  140. X                // That's one more treasure to deposit.
  141. X                global.treasures := global.treasures + 1;
  142. X            }
  143. X        }
  144. X    }
  145. X    doDrop(actor) = {
  146. X        self.checkpoints;
  147. X        pass doDrop;
  148. X    }
  149. X
  150. X    checkpoints = {
  151. X        //
  152. X        // Award points for putting treasure in building (unless
  153. X        // we've already awarded the points for depositing this
  154. X        // treasure).
  155. X        //
  156. X        if (Me.isIn(Inside_Building)) {
  157. X            if (not self.awardedpointsfortaking) {
  158. X                //
  159. X                // This shouldn't happen, but just in case...
  160. X                //
  161. X                incscore(self.takepoints);
  162. X                self.awardedpointsfortaking := true;
  163. X            }
  164. X            else if (not self.awardedpointsfordepositing) {
  165. X                incscore(self.depositpoints);
  166. X                self.awardedpointsfordepositing := true;
  167. X
  168. X                // That's one less treasure to deposit.
  169. X                global.treasures := global.treasures - 1;
  170. X            } 
  171. X        }
  172. X    }
  173. X;
  174. X
  175. Xset_of_keys: CCR_item, keyItem
  176. X    sdesc = "set of keys"
  177. X    ldesc = "It's just a normal-looking set of keys."
  178. X    location = Inside_Building
  179. X    noun = 'keys' 'key' 'keyring' 'set'
  180. X    adjective = 'key'
  181. X;
  182. X
  183. Xbrass_lantern: CCR_item, lightsource
  184. X    turnsleft = 330        // expert mode (default)
  185. X    sdesc = "brass lantern"
  186. X    ldesc = {
  187. X        "It is a shiny brass lamp";
  188. X
  189. X        if (self.islit) {
  190. X            if (self.turnsleft <= 30)
  191. X                ", glowing dimly.";
  192. X            else
  193. X                ", glowing brightly.";
  194. X        }
  195. X        else
  196. X            ".  It is not currently lit.";
  197. X    }
  198. X    location = Inside_Building
  199. X    noun = 'lamp' 'headlamp' 'headlight' 'lantern' 'light'
  200. X
  201. X    ison = nil
  202. X    islit = {
  203. X        if (self.ison and self.turnsleft > 0)
  204. X            return true;
  205. X        else
  206. X            return nil;
  207. X    }    
  208. X    
  209. X    verDoRub(actor) = {}
  210. X    doRub(actor) = {
  211. X        "Rubbing the electric lamp is not particularly 
  212. X        rewarding.  Anyway, nothing exciting happens.";
  213. X    }
  214. X
  215. X    verDoTurnon(actor) = {
  216. X        if (self.ison)
  217. X            "It's already on.";
  218. X    }
  219. X    doTurnon(actor) = {
  220. X        "The lamp is now on.";
  221. X        self.ison := true;
  222. X
  223. X        if (self.turnsleft > 0)
  224. X            notify(self, &wearbatteries, 0);
  225. X        else
  226. X            "  Unfortunately, the batteries seem to
  227. X            be dead.";
  228. X    }
  229. X    verDoTurnoff(actor) = {
  230. X        if (not self.ison)
  231. X            "It's already off.";
  232. X    }
  233. X    doTurnoff(actor) = {
  234. X        "The lamp is now off.";
  235. X        self.turnoff;
  236. X    }
  237. X    verDoLight(actor) = { self.verDoTurnon(actor); }
  238. X    doLight(actor) = { self.doTurnon(actor); }
  239. X
  240. X    verIoPutIn(actor) = {}
  241. X    ioPutIn(actor, dobj) = {
  242. X        if (dobj = old_batteries)
  243. X            "Those batteries are dead; they won't
  244. X            do any good at all.";
  245. X        else if (dobj = fresh_batteries)
  246. X            self.do_replace;
  247. X        else
  248. X            "The only thing you might successfully put in 
  249. X            the lamp is a fresh pair of batteries.";
  250. X    }
  251. X
  252. X    // The following method is called when the player gets resurrected.
  253. X    turnoff = {
  254. X        if (self.ison) {
  255. X            self.ison := nil;
  256. X            unnotify(self, &wearbatteries);
  257. X        }
  258. X    }
  259. X
  260. X    wearbatteries = {
  261. X        self.turnsleft := self.turnsleft - 1;
  262. X
  263. X        if (self.turnsleft < 1) {
  264. X            P(); I();
  265. X            "Your lamp has run out of power. ";
  266. X
  267. X            if (self.replace_batteries) {
  268. X                // do nothing
  269. X            }
  270. X            else if (Me.location.isoutside) {
  271. X                "There's not much point in wandering 
  272. X                around out here, and you can't 
  273. X                explore the cave without a lamp. So 
  274. X                let's just call it a day.";
  275. X
  276. X                call_it_a_day();
  277. X            }
  278. X        }
  279. X        else if (self.turnsleft = 30) {
  280. X            P(); I();
  281. X            "Your lamp is getting dim. ";
  282. X
  283. X            if (self.replace_batteries) {
  284. X                // do nothing.
  285. X            }
  286. X            else if (fresh_batteries.used) {
  287. X                // DMB: changed the wording of this
  288. X                // slightly for convenience.
  289. X                "You're also out of spare batteries.  
  290. X                You'd best start wrapping this up.";
  291. X            }
  292. X            else if (fresh_batteries.location <> nil) {
  293. X                "You'd best go back for those 
  294. X                batteries.";
  295. X            }
  296. X            else {
  297. X                "You'd best start wrapping this up, 
  298. X                unless you can find some fresh 
  299. X                batteries. I seem to recall there's a 
  300. X                vending machine in the maze.  Bring 
  301. X                some coins with you.";
  302. X            }
  303. X        }
  304. X    }
  305. X
  306. X    replace_batteries = {
  307. X        if (fresh_batteries.isIn(Me.location)) {
  308. X            " I'm taking the liberty of replacing the
  309. X            batteries.";
  310. X
  311. X            self.do_replace;
  312. X
  313. X            return true;
  314. X        }
  315. X        else
  316. X            return nil;
  317. X    }
  318. X
  319. X    do_replace = {
  320. X        fresh_batteries.used := true;
  321. X        fresh_batteries.moveInto(nil);
  322. X        old_batteries.moveInto(Me.location);
  323. X        self.turnsleft := 2500;
  324. X    }
  325. X;
  326. X
  327. Xblack_rod: CCR_item
  328. X    sdesc = "black rod"
  329. X    ldesc = "It's a three foot black rod with a rusty star on an end."
  330. X    location = In_Debris_Room
  331. X    noun = 'rod' 'star'
  332. X    adjective = 'black' 'rusty' 'star'
  333. X
  334. X    verDoWave(actor) = {}
  335. X    doWave(actor) = {
  336. X        if (self.isIn(West_Side_Of_Fissure) or
  337. X            self.isIn(On_East_Bank_Of_Fissure)) {
  338. X
  339. X            if (global.closed) {
  340. X                "Peculiar.  Nothing happens.";
  341. X            }
  342. X            else {
  343. X                if (CrystalBridge.exists) {
  344. X                    "The crystal bridge has 
  345. X                    vanished!";
  346. X                    CrystalBridge.exists := nil;
  347. X                }
  348. X                else {
  349. X                    "A crystal bridge now spans 
  350. X                    the fissure.";
  351. X                    CrystalBridge.exists := true;
  352. X                }
  353. X            }
  354. X        }
  355. X        else
  356. X            "Nothing happens.";
  357. X    }
  358. X;
  359. X
  360. Xwicker_cage: CCR_item, container
  361. X    sdesc = "wicker cage"
  362. X    ldesc = {
  363. X        "It's a small wicker cage.";
  364. X    }
  365. X    location = In_Cobble_Crawl
  366. X    noun = 'cage'
  367. X    adjective = 'small' 'wicker' 'bird'
  368. X
  369. X    verDoPutIn(actor) = {}
  370. X    doPutIn(actor, io) = {
  371. X        if (io <> little_bird) {
  372. X            caps(); self.thedesc; " isn't big enough
  373. X            to hold "; io.thedesc; ".";
  374. X        }
  375. X        else
  376. X            pass doPutIn;
  377. X    }
  378. X;
  379. X
  380. X/*
  381. X * The following rod is actually an explosive.  Don't ask ME how anyone
  382. X * is supposed to figure this out from the description.  I've left it
  383. X * the way it was even though I think it's pretty bogus.
  384. X *
  385. X * I've added the words 'explosive' and 'dynamite' as nouns and adjectives,
  386. X * and 'blast' as an adjective.  Perhaps this will give some lucky soul
  387. X * a clue.
  388. X */
  389. Xblack_mark_rod: CCR_item
  390. X    sdesc = "marked rod"
  391. X    ldesc = {
  392. X        "It's a three foot black rod with a rusty mark on an end.";
  393. X    }
  394. X    location = At_Sw_End
  395. X    noun = 'rod' 'mark' 'explosive' 'dynamite'
  396. X    adjective = 'black' 'rusty' 'mark' 'blast' 'explosive' 'dynamite'
  397. X
  398. X    verDoWave(actor) = {}
  399. X    doWave(actor) = { "Nothing happens."; }
  400. X
  401. X    verDoBlastWith(actor) = {}
  402. X    doBlastWith(actor) = { endpuzzle(); }
  403. X;
  404. X
  405. Xlittle_bird: CCR_item
  406. X    sdesc = {
  407. X        if (not self.isIn(wicker_cage))
  408. X            "cheerful ";
  409. X        
  410. X        "little bird";
  411. X    }
  412. X    ldesc = {
  413. X        if (self.isIn(wicker_cage))
  414. X            "The little bird looks unhappy in the cage.";
  415. X        else
  416. X            "The cheerful little bird is sitting here singing.";
  417. X    }
  418. X    location = In_Bird_Chamber
  419. X    noun = 'bird'
  420. X
  421. X    verDoFeed(actor) = {}
  422. X    doFeed(actor) = {
  423. X        "It's not hungry. (It's merely pinin' for the fjords). 
  424. X         Besides, you have no bird seed.";
  425. X    }
  426. X    verIoGiveTo(actor) = {
  427. X        "I suspect it would prefer bird seed.";
  428. X    }
  429. X
  430. X    /*
  431. X     * Catch any attempt to remove the bird.  It won't cooperate
  432. X     * When the player has the rod with the star on the end.
  433. X     */
  434. X    verifyRemove(actor) = {
  435. X        if (self.isIn(Me)) {
  436. X            "You already have the little bird.  If
  437. X            you take it out of the cage it will likely
  438. X            fly away from you.";
  439. X        }
  440. X        else if (black_rod.isIn(Me)) {
  441. X            "The bird was unafraid when you entered, but 
  442. X            as you approach it becomes disturbed and you 
  443. X            cannot catch it.";
  444. X        }
  445. X        else
  446. X            pass verifyRemove;
  447. X    }
  448. X
  449. X    verDoTake(actor) = {
  450. X        if (not wicker_cage.isIn(Me))
  451. X            "You can catch the bird, but you cannot carry it.";
  452. X        else
  453. X            pass verDoTake;
  454. X    }
  455. X    doTake(actor) = {
  456. X        self.doPutIn(Me, wicker_cage);
  457. X    }
  458. X
  459. X    verDoPutIn(actor) = {}
  460. X    doPutIn(actor, io) = {
  461. X        if (io <> wicker_cage) {
  462. X            "Don't put the poor bird in "; io.thedesc; "!";
  463. X        }
  464. X        else
  465. X            pass doPutIn;
  466. X    }
  467. X
  468. X    verDoAttack(actor) = {
  469. X        if (self.isIn(wicker_cage)) 
  470. X            "Oh, leave the poor unhappy bird alone.";
  471. X        else {
  472. X            "The little bird is now dead.  Its body disappears.";
  473. X            self.moveInto(nil);
  474. X        }
  475. X    }
  476. X
  477. X    verDoDrop(actor) = {}
  478. X    doDrop(actor) = {
  479. X        if (self.isIn(Snake.location)) {
  480. X            "The little bird attacks the green snake, and 
  481. X            in an astounding flurry drives the snake 
  482. X            away.";
  483. X
  484. X            Snake.moveInto(nil);
  485. X            self.moveInto(Me.location);
  486. X        }
  487. X        else if (self.isIn(Dragon.location)) {
  488. X            "The little bird attacks the green dragon, 
  489. X            and in an astounding flurry gets burnt to a 
  490. X            cinder.  The ashes blow away.";
  491. X
  492. X            self.moveInto(nil);
  493. X        }
  494. X        else
  495. X            pass doDrop;
  496. X    }
  497. X
  498. X    doTakeOut(actor, io) = {
  499. X        // Drop ourselves automatically.  (The bird flies away
  500. X        // when taken out of a container.)
  501. X        self.doDrop(actor);
  502. X    }
  503. X;
  504. X
  505. Xvelvet_pillow: CCR_item
  506. X    sdesc = "velvet pillow"
  507. X    ldesc = "It's just a small velvet pillow."
  508. X    location = In_Soft_Room
  509. X    noun = 'pillow'
  510. X    adjective = 'velvet' 'small'
  511. X;
  512. X
  513. Xgiant_bivalve: CCR_item
  514. X    opened = nil
  515. X
  516. X    sdesc = {
  517. X        if (self.opened)
  518. X            "giant oyster";
  519. X        else
  520. X            "giant clam";
  521. X
  522. X        if (self.isIn(Me))
  523. X            " >grunt!<";
  524. X    }
  525. X    thedesc = {
  526. X        if (self.opened)
  527. X            "the giant oyster";
  528. X        else
  529. X            "the giant clam";
  530. X    }
  531. X    
  532. X    ldesc = {
  533. X        "It's an enormous clam with its shell tightly closed.";
  534. X
  535. X        // During the endgame, the oyster has something
  536. X        // written on it.
  537. X        if (self.isIn(At_Ne_End) or self.isIn(At_Sw_End)) {
  538. X            "Interesting.  There seems to be something 
  539. X            written on the underside of the oyster.";
  540. X        }
  541. X    }
  542. X    location = In_Shell_Room
  543. X    noun = 'clam' 'oyster' 'bivalve' 'shell'
  544. X    adjective = 'giant' 'enormous' 'massive' 'big' 'huge' 'tightly'
  545. X        'closed' 'five' 'foot' 'five-foot' '5-foot'
  546. X
  547. X    verDoOpen(actor) = { self.verDoOpenWith(actor, nil); }
  548. X    doOpen(actor) = {
  549. X        if (trident.isIn(Me)) {
  550. X            //
  551. X            // In the original, "open clam" would work
  552. X            // ask long as you were carrying the trident,
  553. X            // but this seems very prone to accidental
  554. X            // solving, and since we aren't limited to
  555. X            // two word parsing, I've just taken the
  556. X            // liberty of forcing the player to type
  557. X            // "open clam with trident."
  558. X            //
  559. X            "You'll need to be a bit more specific that 
  560. X            that, I'm afraid.";
  561. X        }
  562. X        else {
  563. X            "You don't have anything strong enough to 
  564. X            open "; self.thedesc; ".";
  565. X        }
  566. X    }
  567. X    verDoOpenWith(actor, io) = {
  568. X        if (self.isIn(Me)) {
  569. X            "I advise you to put down "; self.thedesc;
  570. X            " before opening it.  >Strain!<";
  571. X        }
  572. X    }
  573. X    doOpenWith(actor, io) = {
  574. X        if (io = trident) {
  575. X            if (self.opened) {
  576. X                "The oyster creaks open, revealing nothing 
  577. X                but oyster inside.  It promptly snaps shut 
  578. X                again.";  
  579. X            }
  580. X            else {
  581. X                "A glistening pearl falls out of the clam and 
  582. X                rolls away.  Goodness, this must really be an 
  583. X                oyster.  (I never was very good at 
  584. X                identifying bivalves.)  Whatever it is, it 
  585. X                has now snapped shut again.";
  586. X
  587. X                self.opened := true;
  588. X                pearl.moveInto(In_A_Cul_De_Sac);
  589. X            }
  590. X        }
  591. X        else {
  592. X            caps(); io.thedesc; " isn't strong enough to 
  593. X            open "; self.thedesc; ".";
  594. X        }
  595. X    }
  596. X    verDoBreak(actor) = {
  597. X        "The shell is very strong and is impervious to 
  598. X        attack.";
  599. X    }
  600. X    verDoAttack(actor) = { self.verDoBreak(actor); }
  601. X    verDoAttackWith(actor, io) = { self.verDoBreak(actor); }
  602. X
  603. X    //
  604. X    // The oyster has a hint written on its underside once
  605. X    // the cave's closed.  (Look, don't ask me, I'm just
  606. X    // porting this game!)
  607. X    //
  608. X    verDoRead(actor) = {
  609. X        if (not self.isIn(At_Ne_End) and not self.isIn(At_Sw_End))
  610. X            "You're babbling -- snap out of it!";
  611. X    }
  612. X    doRead(actor) = {
  613. X        //
  614. X        // This is supposed to be a hint (i.e., it's supposed
  615. X        // to cost points), but I've put it in as a freebie
  616. X        // because I think the final puzzle is absurdly
  617. X        // difficult even with the free hint.
  618. X        //
  619. X        "It says, \"There is something strange about this 
  620. X        place, such that one of the words I've always known 
  621. X        now has a new effect.\"";
  622. X    }
  623. X;
  624. X
  625. Xspelunker_today: CCR_item, readable
  626. X    sdesc = "recent issues of \"Spelunker Today\""
  627. X    adesc = { self.sdesc; }
  628. X    ldesc = { self.readdesc; }
  629. X    readdesc = {
  630. X        // This said "magazine is written" in the original,
  631. X        // which is obviously wrong given the sdesc.
  632. X
  633. X        "I'm afraid the magazines are written in Dwarvish.";
  634. X    }
  635. X
  636. X    location = In_Anteroom
  637. X    plural = 'magazines'
  638. X    noun = 'magazine' 'issue' 'issue' 'spelunker'
  639. X        'today' 'dwarvish'
  640. X    adjective = 'spelunker' 'today' 'dwarvish'
  641. X
  642. X    doDrop(actor) = {
  643. X        if (Me.isIn(At_Witts_End))
  644. X            silent_incscore(global.wittpoints);
  645. X
  646. X        pass doDrop;
  647. X    }
  648. X    doTake(actor) = {
  649. X        if (Me.isIn(At_Witts_End))
  650. X            silent_incscore(-1 * global.wittpoints);
  651. X
  652. X        pass doTake;
  653. X    }
  654. X;
  655. X
  656. Xtasty_food: CCR_item, fooditem
  657. X    sdesc = "some tasty food"
  658. X    adesc = { self.sdesc; }
  659. X    thedesc = "the tasty food"
  660. X    ldesc = "Sure looks yummy!"
  661. X    location = Inside_Building
  662. X    noun = 'food' 'ration' 'rations' 'tripe'
  663. X    adjective = 'yummy' 'tasty' 'delicious' 'scrumptious'
  664. X;
  665. X
  666. Xbottle: CCR_item
  667. X    haswater = true
  668. X    hasoil = nil
  669. X
  670. X    sdesc = {
  671. X        if (self.haswater)
  672. X            "small bottle of water";
  673. X        else if (self.hasoil)
  674. X            "small bottle of oil";
  675. X        else
  676. X            "small empty bottle";
  677. X    }
  678. X    location = Inside_Building
  679. X    noun = 'bottle' 'jar' 'flask'
  680. X
  681. X    verIoPutIn(actor) = {}
  682. X    ioPutIn(actor, dobj) = {
  683. X        if (self.haswater)
  684. X            "The bottle is already full of water.";
  685. X        else if (self.hasoil)
  686. X            "The bottle is already full of oil.";
  687. X        else if (dobj = Stream) {
  688. X            "The bottle is now full of water.";
  689. X            self.haswater := true;
  690. X        }
  691. X        else if (dobj = Oil) {
  692. X            "The bottle is now full of oil.";
  693. X            self.hasoil := true;
  694. X        }
  695. X        else {
  696. X            "I'm not sure how to do that.";
  697. X        }
  698. X    }
  699. X
  700. X    verDoFill(actor) = {}
  701. X    doFill(actor) = {
  702. X        if (self.isIn(Stream.location))
  703. X            self.ioPutIn(actor, Stream);
  704. X        else if (self.isIn(Oil.location))
  705. X            self.ioPutIn(actor, Oil);
  706. X        else
  707. X            "There is nothing here with which to fill the 
  708. X            bottle.";
  709. X    }
  710. X
  711. X    verDoEmpty(actor) = {}
  712. X    doEmpty(actor) = {
  713. X        if (self.haswater or self.hasoil)
  714. X            "Your bottle is now empty and the ground is 
  715. X            now wet.";
  716. X        else
  717. X            "The bottle is already empty!";
  718. X
  719. X        self.empty;
  720. X    }
  721. X
  722. X    verDoPourOn(actor, io) = {}
  723. X    doPourOn(actor, io) = {
  724. X        if (io = RustyDoor) {
  725. X            if (self.hasoil) {
  726. X                "The oil has freed up the hinges so that the 
  727. X                door will now move, although it requires some 
  728. X                effort.";
  729. X
  730. X                RustyDoor.isoiled := true;
  731. X            }
  732. X            else if (self.haswater) {
  733. X                "The hinges are quite thoroughly 
  734. X                rusted now and won't budge.";
  735. X            }
  736. X            else {
  737. X                "The bottle is empty.";
  738. X            }
  739. X
  740. X            self.empty;
  741. X        }
  742. X        else if (io = Plant) {
  743. X            if (self.haswater) {
  744. X                Plant.water;
  745. X            }
  746. X            else if (self.hasoil) {
  747. X                "The plant indignantly shakes the oil 
  748. X                off its leaves and asks, \"Water?\"";
  749. X            }
  750. X            else {
  751. X                "The bottle is empty.";
  752. X            }
  753. X
  754. X            self.empty;
  755. X        }
  756. X        else if (io = theFloor)
  757. X            self.doEmpty(actor);
  758. X        else
  759. X            "That doesn't seem productive.";
  760. X    }
  761. X
  762. X    verDoDrink(actor) = {
  763. X        if (not self.hasoil and not self.haswater)
  764. X            "The bottle is empty.";
  765. X
  766. X        if (self.hasoil)
  767. X            "Don't drink the oil, you fool!";
  768. X    }
  769. X    doDrink(actor) = {
  770. X        "The bottle is now empty.";
  771. X        self.empty;
  772. X    }
  773. X
  774. X    empty = {
  775. X        self.haswater := nil;
  776. X        self.hasoil := nil;
  777. X    }
  778. X;
  779. Xwater_in_the_bottle: CCR_decoration
  780. X    sdesc = "water in the bottle"
  781. X    adesc = "water"
  782. X    ldesc = "It looks like ordinary water to me."
  783. X    locationOK = true    // tell compiler OK for location to be method
  784. X    location = {
  785. X        if (bottle.haswater)
  786. X            return bottle.location;
  787. X        else
  788. X            return nil;
  789. X    }
  790. X    noun = 'water' 'h2o'
  791. X
  792. X    verDoPourOn(actor, io) = {}
  793. X    doPourOn(actor, io) = { bottle.doPourOn(actor, io); }
  794. X    verDoDrink(actor) = { bottle.verDoDrink(actor); }
  795. X    doDrink(actor) = { bottle.doDrink(actor); }
  796. X;
  797. Xoil_in_the_bottle: CCR_decoration
  798. X    sdesc = "oil in the bottle"
  799. X    adesc = "oil"
  800. X    ldesc = "It looks like ordinary oil to me."
  801. X    locationOK = true    // tell compiler OK for location to be method
  802. X    location = {
  803. X        if (bottle.hasoil)
  804. X            return bottle.location;
  805. X        else
  806. X            return nil;
  807. X    }
  808. X    noun = 'oil' 'lubricant' 'grease'
  809. X
  810. X    verDoPourOn(actor, io) = {}
  811. X    doPourOn(actor, io) = { bottle.doPourOn(actor, io); }
  812. X    verDoDrink(actor) = { bottle.verDoDrink(actor); }
  813. X    doDrink(actor) = { bottle.doDrink(actor); }
  814. X;
  815. X
  816. Xaxe: CCR_item
  817. X    nograb = nil    // hack for when you attack the bear with it
  818. X
  819. X    sdesc = "dwarf's axe"
  820. X    ldesc = {
  821. X        if (self.nograb)
  822. X            "It's lying beside the bear.";
  823. X        else
  824. X            "It's just a little axe.";
  825. X    }
  826. X    location = nil        // created when first dwarf attacks
  827. X    noun = 'axe'
  828. X    adjective = 'little' 'dwarf' 'dwarvish' 'dwarven' 'dwarf\'s'
  829. X
  830. X    verifyRemove(actor) = {
  831. X        if (self.nograb)
  832. X            "No chance.  It's lying beside the ferocious 
  833. X            bear, quite within harm's way.";
  834. X    }
  835. X;
  836. X
  837. Xfresh_batteries: CCR_item
  838. X    used = nil    // used in lamp yet?
  839. X
  840. X    sdesc = "fresh batteries"
  841. X    ldesc = {
  842. X        "They look like ordinary batteries.  (A sepulchral 
  843. X        voice says, \"Still going!\")";
  844. X    }
  845. X    noun = 'batteries' 'battery' 'duracel' 'duracell' 'duracels'
  846. X        'duracells' 'energizer' 'energizers' 'everready'
  847. X        'everreadies' 'eveready' 'evereadies'
  848. X    adjective = 'fresh'
  849. X
  850. X    location = nil
  851. X;
  852. X
  853. Xold_batteries: CCR_item
  854. X    sdesc = "worn-out batteries"
  855. X    ldesc = {
  856. X        "They look like ordinary batteries.";
  857. X    }
  858. X    noun = 'batteries' 'battery' 'duracel' 'duracell' 'duracels'
  859. X        'duracells' 'energizer' 'energizers' 'everready'
  860. X        'everreadies' 'eveready' 'evereadies'
  861. X    adjective = 'worn' 'out' 'worn-out' 'dead' 'empty' 'dry' 'old'
  862. X
  863. X    location = nil
  864. X;
  865. X
  866. X/*
  867. X * Treasures
  868. X */
  869. Xlarge_gold_nugget: CCR_treasure_item
  870. X    depositpoints = 10
  871. X    sdesc = "large gold nugget"
  872. X    ldesc = "It's a large sparkling nugget of gold!"
  873. X    location = In_Nugget_Of_Gold_Room
  874. X    noun = 'gold' 'nugget'
  875. X    adjective = 'gold' 'large'
  876. X;
  877. Xseveral_diamonds: CCR_treasure_item
  878. X    depositpoints = 10
  879. X    sdesc = "several diamonds"
  880. X    adesc = { self.sdesc; }
  881. X    thedesc = "the diamonds"
  882. X    ldesc = "They look to be of the highest quality!"
  883. X    location = West_Side_Of_Fissure
  884. X    noun = 'diamond' 'diamonds'
  885. X    adjective = 'several' 'high' 'quality' 'high-quality'
  886. X;
  887. Xbars_of_silver: CCR_treasure_item
  888. X    depositpoints = 10
  889. X    sdesc = "bars of silver"
  890. X    adesc = { self.sdesc; }
  891. X    ldesc = "They're probably worth a fortune!"
  892. X    location = Low_N_S_Passage
  893. X    noun = 'silver' 'bars'
  894. X    adjective = 'silver'
  895. X;
  896. Xprecious_jewelry: CCR_treasure_item
  897. X    depositpoints = 10
  898. X    sdesc = "precious jewelry"
  899. X    adesc = { self.sdesc; }
  900. X    ldesc = "It's all quite exquisite!"
  901. X    location = In_South_Side_Chamber
  902. X    noun = 'jewel' 'jewels' 'jewelry'
  903. X    adjective = 'precious' 'exquisite'
  904. X;
  905. Xrare_coins: CCR_treasure_item
  906. X    depositpoints = 10
  907. X    sdesc = "rare coins"
  908. X    adesc = { self.sdesc; }
  909. X    ldesc = "They're a numismatist's dream!"
  910. X    location = In_West_Side_Chamber
  911. X    noun = 'coins'
  912. X    adjective = 'rare'
  913. X;
  914. Xtreasure_chest: CCR_treasure_item
  915. X    spotted = nil    // found yet?  See also Dead_End_13 in ccr-room.t
  916. X
  917. X    depositpoints = 12
  918. X    sdesc = "treasure chest"
  919. X    ldesc = {
  920. X        "It's the pirate's treasure chest, filled with
  921. X        riches of all kinds!";
  922. X    }
  923. X    location = nil
  924. X    noun = 'chest' 'box' 'treasure' 'riches'
  925. X    adjective = 'pirate' 'pirate\'s' 'treasure'     
  926. X;
  927. Xgolden_eggs: CCR_treasure_item
  928. X    depositpoints = 14
  929. X    sdesc = "nest of golden eggs"
  930. X    ldesc = "The nest is filled with beautiful golden eggs!"
  931. X    location = In_Giant_Room
  932. X    noun = 'eggs' 'egg' 'nest'
  933. X    adjective = 'golden' 'beautiful'
  934. X;
  935. Xtrident: CCR_treasure_item
  936. X    depositpoints = 14
  937. X    sdesc = "jeweled trident"
  938. X    ldesc = "The trident is covered with fabulous jewels!"
  939. X    location = In_Cavern_With_Waterfall
  940. X    noun = 'trident'
  941. X    adjective = 'jeweled' 'jewel-encrusted' 'encrusted' 'fabulous'
  942. X
  943. X    verIoOpenWith(actor) = {}
  944. X    ioOpenWith(actor, dobj) = {
  945. X        dobj.doOpenWith(actor, self);
  946. X    }
  947. X;
  948. Xming_vase: CCR_treasure_item
  949. X    depositpoints = 14
  950. X    sdesc = "ming vase"
  951. X    ldesc = {
  952. X        "It's a delicate, previous, ming vase!";
  953. X    }
  954. X    location = In_Oriental_Room
  955. X    noun = 'vase' 'ming' 'shards' 'pottery'
  956. X
  957. X    doDrop(actor) = {
  958. X        if (velvet_pillow.isIn(Me.location)) {
  959. X            "The vase is now resting, delicately, on a 
  960. X            velvet pillow.";
  961. X
  962. X            self.moveInto(Me.location);
  963. X            
  964. X            self.checkpoints;    // make sure we count points
  965. X                        // for putting this in building
  966. X        }
  967. X        else {
  968. X            "The ming vase drops with a delicate crash.";
  969. X            self.shatter;
  970. X        }
  971. X    }
  972. X
  973. X    verIoPutIn(actor) = {}
  974. X    ioPutIn(actor, dobj) = {
  975. X        if (dobj = Stream or dobj = Oil) {
  976. X            "The sudden change in temperature has 
  977. X            delicately shattered the vase.";
  978. X
  979. X            self.shatter;
  980. X        }
  981. X        else {
  982. X            "I'm not sure how to do that.";
  983. X        }
  984. X    }
  985. X
  986. X    verDoFill(actor) = {}
  987. X    doFill(actor) = {
  988. X        if (self.isIn(Stream.location))
  989. X            self.ioPutIn(actor, Stream);
  990. X        else if (self.isIn(Oil.location))
  991. X            self.ioPutIn(actor, Oil);
  992. X        else
  993. X            "There is nothing here with which to fill the 
  994. X            vase.";
  995. X    }
  996. X
  997. X    verDoBreak(actor) = {}
  998. X    doBreak(actor) = {
  999. X        "You have taken the vase and hurled it delicately to 
  1000. X        the ground.";
  1001. X
  1002. X        self.shatter;
  1003. X    }
  1004. X
  1005. X    shatter = {
  1006. X        self.moveInto(nil);
  1007. X        shards.moveInto(Me.location);
  1008. X    }
  1009. X;
  1010. Xshards: CCR_item
  1011. X    sdesc = "some worthless shards of pottery"
  1012. X    adesc = { self.sdesc; }
  1013. X    ldesc = {
  1014. X        "They're just worthless shards of pottery"; 
  1015. X
  1016. X        if (self.location = Me.location)    // not in a container
  1017. X            ", littered everywhere.";
  1018. X        else
  1019. X            ".";
  1020. X
  1021. X        " They look to be the remains of what was once a
  1022. X        beautiful vase.  I guess some oaf must have dropped it.";
  1023. X    }
  1024. X
  1025. X    noun = 'pottery' 'shards'
  1026. X    adjective = 'worthless'
  1027. X;
  1028. X
  1029. Xegg_sized_emerald: CCR_treasure_item
  1030. X    depositpoints = 14
  1031. X    sdesc = "emerald the size of a plover's egg"
  1032. X    adesc = { "an "; self.sdesc; }
  1033. X    ldesc = "Plover's eggs, by the way, are quite large."
  1034. X    location = In_Plover_Room
  1035. X    noun = 'emerald'
  1036. X    adjective = 'egg-sized'
  1037. X;
  1038. Xplatinum_pyramid: CCR_treasure_item
  1039. X    depositpoints = 14
  1040. X    sdesc = "platinum pyramid"
  1041. X    ldesc = "The platinum pyramid is 8 inches on a side!"
  1042. X    location = In_Dark_Room
  1043. X    noun = 'platinum' 'pyramid'
  1044. X    adjective = 'platinum' 'pyramidal'
  1045. X;
  1046. Xpearl: CCR_treasure_item
  1047. X    depositpoints = 14
  1048. X    sdesc = "glistening pearl"
  1049. X    ldesc = "It's incredibly large!"
  1050. X    location = nil
  1051. X    noun = 'pearl'
  1052. X    adjective = 'glistening' 'incredible' 'incredibly' 'large'
  1053. X;
  1054. Xpersian_rug: CCR_treasure_item
  1055. X    depositpoints = 14
  1056. X    sdesc = {
  1057. X        "Persian rug";
  1058. X
  1059. X        if (self.isIn(Dragon.location))
  1060. X            " (upon which the dragon is sprawled out)";
  1061. X    }
  1062. X    adesc = {
  1063. X        "a "; self.sdesc; 
  1064. X    }
  1065. X    ldesc = {
  1066. X        if (self.isIn(Dragon.location))
  1067. X            "The dragon is sprawled out on the Persian rug!!";
  1068. X        else if (not self.isIn(Me))
  1069. X            "The Persian rug is spread out on the floor here.";
  1070. X        else
  1071. X            "The Persian rug is the finest you've ever seen!";
  1072. X    }
  1073. X    location = In_Secret_Canyon
  1074. X    noun = 'rug' 'persian'
  1075. X    adjective = 'persian' 'fine' 'finest' 'dragon\'s'
  1076. X
  1077. X    verifyRemove(actor) = {
  1078. X        if (self.isIn(Dragon.location))
  1079. X            "You'll need to get the dragon to move first!";
  1080. X    }
  1081. X;
  1082. Xrare_spices: CCR_treasure_item
  1083. X    depositpoints = 14
  1084. X    sdesc = "rare spices"
  1085. X    adesc = { self.sdesc; }
  1086. X    ldesc = "They smell wonderfully exotic!"
  1087. X    location = In_Chamber_Of_Boulders
  1088. X    noun = 'spices' 'spice'
  1089. X    adjective = 'rare' 'exotic'
  1090. X
  1091. X    verDoSmell(actor) = {}
  1092. X    doSmell(actor) = { self.ldesc; }
  1093. X;
  1094. Xgolden_chain: CCR_treasure_item, keyedLockable
  1095. X    depositpoints = 14
  1096. X    isfixed = {
  1097. X        if (self.islocked)
  1098. X            return true;
  1099. X        else
  1100. X            return nil;
  1101. X    }
  1102. X    isListed = { return not self.isfixed; }
  1103. X
  1104. X    mykey = set_of_keys    // pretty handy, those!
  1105. X    islocked = true        // locked meaning "locked to the wall."
  1106. X    isopen = nil        // need this since we're keyedLockable
  1107. X
  1108. X    sdesc = "golden chain"
  1109. X    ldesc = {
  1110. X        "The chain has thick links of solid gold!";
  1111. X
  1112. X        if (self.islocked) {
  1113. X            if (Bear.wasreleased)
  1114. X                "It's locked to the wall!";
  1115. X            else
  1116. X                " The bear is chained to the wall with it!";
  1117. X        }
  1118. X    }
  1119. X    heredesc = {
  1120. X        if (self.isfixed) {
  1121. X            P(); I();
  1122. X            if (Bear.wasreleased)
  1123. X                "There is a golden chain here, locked 
  1124. X                to the wall.";
  1125. X            else
  1126. X                "There is a golden chain here, and a 
  1127. X                large cave bear is locked to the wall 
  1128. X                with it!";
  1129. X        }
  1130. X    }
  1131. X    
  1132. X    location = In_Barren_Room
  1133. X    noun = 'chain' 'links' 'shackles'
  1134. X    adjective = 'solid' 'gold' 'golden' 'thick'
  1135. X
  1136. X    verDoLock(actor) = {
  1137. X        if (not self.isIn(In_Barren_Room)) {
  1138. X            "There is nothing here to which the chain can 
  1139. X            be locked.";
  1140. X        }
  1141. X        else
  1142. X            pass verDoLock;
  1143. X    }
  1144. X    verDoLockWith(actor, io) = {
  1145. X        self.verDoLock(actor);    // -> pass verDoLock (OK?)
  1146. X        pass verDoLockWith;
  1147. X    }
  1148. X
  1149. X    verDoUnlock(actor) = {
  1150. X        if (not Bear.wasreleased and not Bear.istame) {
  1151. X            "There is no way to get past the bear to 
  1152. X            unlock the chain, which is probably just as 
  1153. X            well.";
  1154. X        }
  1155. X        else
  1156. X            pass verDoUnlock;
  1157. X    }
  1158. X    verDoUnlockWith(actor, io) = {
  1159. X        self.verDoUnlock(actor);
  1160. X        pass verDoUnlockWith;
  1161. X    }
  1162. X
  1163. X    // inherit proper doUnlock from keyedLockable
  1164. X    doUnlockWith(actor, io) = {
  1165. X        Bear.wasreleased := true;
  1166. X        pass doUnlockWith;
  1167. X    }
  1168. X    
  1169. X    verifyRemove(actor) = {
  1170. X        if (not Bear.wasreleased) {
  1171. X            if (Bear.istame)
  1172. X                "It's locked to the friendly bear.";
  1173. X            else
  1174. X                "It's locked to the ferocious bear!";
  1175. X        }
  1176. X        else if (self.islocked)
  1177. X            "The chain is still locked to the wall.";
  1178. X    }
  1179. X;
  1180. END_OF_FILE
  1181. if test 26875 -ne `wc -c <'src/ccr-item.t'`; then
  1182.     echo shar: \"'src/ccr-item.t'\" unpacked with wrong size!
  1183. fi
  1184. # end of 'src/ccr-item.t'
  1185. fi
  1186. if test -f 'src/ccr-npc.t' -a "${1}" != "-c" ; then 
  1187.   echo shar: Will not clobber existing file \"'src/ccr-npc.t'\"
  1188. else
  1189. echo shar: Extracting \"'src/ccr-npc.t'\" \(25988 characters\)
  1190. sed "s/^X//" >'src/ccr-npc.t' <<'END_OF_FILE'
  1191. X/*
  1192. X * Colossal Cave Revisited
  1193. X *
  1194. X * A remake of Willie Crowther and Don Woods' classic Adventure.
  1195. X * Converted from Donald Ekman's PC port of the original FORTRAN source.
  1196. X * TADS version by David M. Baggett for ADVENTIONS.
  1197. X *
  1198. X * Please document all changes in the history so we know who did what.
  1199. X *
  1200. X * This source code is copylefted under the terms of the GNU Public
  1201. X * License.  Essentially, this means that you are free to do whatever
  1202. X * you wish with this source code, provided you do not charge any
  1203. X * money for it or for any derivative works.
  1204. X *
  1205. X * ADVENTIONS distributes this game, but you are free to do what you will
  1206. X * with it, provided you adhere to the terms in the GNU Public License.
  1207. X * Send correspondence regarding this game or original works distributed
  1208. X * by ADVENTIONS to 
  1209. X *
  1210. X *    ADVENTIONS
  1211. X *    PO Box 851
  1212. X *    Columbia, MD 21044
  1213. X *
  1214. X * If you would like a catalog of releases, please enclose a SASE.  Thanks!
  1215. X *
  1216. X * Contributors
  1217. X *
  1218. X *    dmb    In real life:    David M. Baggett
  1219. X *        Internet:    <dmb@ai.mit.edu>
  1220. X *        Compu$erve:    76440,2671 (ADVENTIONS account)
  1221. X *        GEnie:        ADVENTIONS
  1222. X *
  1223. X * Modification History
  1224. X *
  1225. X *  1-Jan-93    dmb    rec.arts.int-fiction BETA release (source only)
  1226. X *                      For beta testing only -- not for general
  1227. X *            distribution.
  1228. X * 20-Apr-93    dmb    Incorporated Mike Roberts' changes to make
  1229. X *            this a lot faster.  Uses the new intersect
  1230. X *            built-in, so CCR must now be built with TADS
  1231. X *            >= 2.0.13.
  1232. X *
  1233. X */
  1234. X
  1235. X/*
  1236. X * This file handles non-player character (dwarves and pirate) movement.
  1237. X *
  1238. X * Be sure to update exitlist and/or npclist if you add any new travel
  1239. X * verbs to CCR_Room.
  1240. X */
  1241. XinitNPC: function
  1242. X{
  1243. X    local    o;
  1244. X
  1245. X    //
  1246. X    // Construct list of NPC exits for each room
  1247. X    //
  1248. X    o := firstobj(CCR_room);
  1249. X    while (o <> nil) {
  1250. X        if (not o.noNPCs) {
  1251. X            //
  1252. X            // Add this room to the global list of rooms
  1253. X            // the NPC's can be in.
  1254. X            //
  1255. X            global.NPCrooms := global.NPCrooms + o;
  1256. X
  1257. X            do_exitlist(o);
  1258. X            do_npclist(o);
  1259. X        }
  1260. X        else if (global.debug) {
  1261. X            //
  1262. X            // Debugging info:
  1263. X            // 
  1264. X            "\b\"<< o.sdesc >>\" is off limits to NPC's."; 
  1265. X        }
  1266. X
  1267. X        o := nextobj(o, CCR_room);
  1268. X    }
  1269. X}
  1270. X
  1271. X/*
  1272. X * Add standard exits to the list of exits that NPC's should check
  1273. X * when they're wandering about randomly.
  1274. X */
  1275. Xdo_exitlist: function(o)
  1276. X{
  1277. X    local    exitlist, i, j, gotit;
  1278. X        local   tot1, tot2;
  1279. X
  1280. X    //
  1281. X    // List of all exit property names that NPC's will consider.
  1282. X    // Note that magic words are left out because NPC's don't
  1283. X    // know them.
  1284. X    //
  1285. X    exitlist := [
  1286. X        &north &south &east &west
  1287. X        &ne &nw &se &sw
  1288. X        &up &down &in &out
  1289. X
  1290. X        &jump &upstream &downstream &forwards &outdoors 
  1291. X        &left &right &cross &over &across &road &forest 
  1292. X        &valley &stairs &building &gully &stream &rock &bed 
  1293. X        &crawl &cobble &tosurface &dark &passage &low &canyon 
  1294. X        &awkward &giant &view &pit &crack &steps &dome &hall 
  1295. X        &barren &debris &hole &wall &broken &floor &toroom 
  1296. X        &slit &slab &depression &entrance &secret &cave 
  1297. X        &bedquilt &oriental &cavern &shell &reservoir &main 
  1298. X        &office &fork
  1299. X    ];
  1300. X        tot1 := length(exitlist);
  1301. X
  1302. X    for (i := 1; i <= tot1; i++) {
  1303. X        //
  1304. X        // If this exit property is a simple
  1305. X        // object (prop 2), NPC's can use it, so
  1306. X        // add it to the room's NPC exit list.
  1307. X        //
  1308. X        // Make sure we don't add the same
  1309. X        // desination room twice.  Just because
  1310. X        // there are multiple travel verbs from
  1311. X        // one place to another doesn't mean the
  1312. X        // destination should be more likely.
  1313. X        //
  1314. X        if (proptype(o, exitlist[i]) = 2
  1315. X                    and not o.(exitlist[i]).noNPCs) {
  1316. X
  1317. X            //
  1318. X            // Search current exitlist for
  1319. X            // this exit's destination.
  1320. X            //
  1321. X                        gotit := (find(o.NPCexits, o.(exitlist[i])) <> nil);
  1322. X            if (not gotit)
  1323. X                o.NPCexits := o.NPCexits + exitlist[i];
  1324. X        }
  1325. X    }
  1326. X}
  1327. X
  1328. X/*
  1329. X * Add NPC special exits to the list of exits that NPC's should check
  1330. X * when they're wandering about randomly.
  1331. X */
  1332. Xdo_npclist: function(o)
  1333. X{
  1334. X    local    npclist, i, tot;
  1335. X
  1336. X    //
  1337. X    // NPC exits.  These get considered if even if they're methods.
  1338. X    // The only way they won't be added to the list of exits to
  1339. X    // try is if they're = nil and not methods.
  1340. X    //
  1341. X    npclist := [
  1342. X        &NPCexit1 &NPCexit2 &NPCexit3 &NPCexit4
  1343. X        &NPCexit5 &NPCexit6 &NPCexit7 &NPCexit8
  1344. X    ];
  1345. X
  1346. X        tot := length(npclist);
  1347. X    for (i := 1; i <= tot; i++) {
  1348. X        //
  1349. X        // If this NPC exit property is anything but
  1350. X        // nil (i.e., just nil, and not a method
  1351. X        // that returns nil). then NPC's can use it.
  1352. X        // Methods that return nil are fine because
  1353. X        // they might be conditional on some game
  1354. X        // events, like the crystal bridge having
  1355. X        // been created, etc.
  1356. X        //
  1357. X        if (proptype(o, npclist[i]) <> 5) // not = nil
  1358. X            o.NPCexits := o.NPCexits + npclist[i];
  1359. X    }
  1360. X}
  1361. X
  1362. X/*
  1363. X * Make sure NPC room connections are sound.
  1364. X */
  1365. Xcheck_connections: function
  1366. X{
  1367. X    local    o;
  1368. X
  1369. X    o := firstobj(CCR_room);
  1370. X    while (o <> nil) {
  1371. X        if (not o.noNPCs)
  1372. X            do_debug(o);
  1373. X
  1374. X        o := nextobj(o, CCR_room);
  1375. X    }
  1376. X}
  1377. X    
  1378. Xdo_debug: function(o)
  1379. X{
  1380. X    local    i, tot;
  1381. X
  1382. X    if (length(o.NPCexits) = 0) {
  1383. X        P(); I();
  1384. X        "Oh dear, someone seems to have damaged one of my 
  1385. X        room connections.  The room \"";
  1386. X
  1387. X        o.sdesc;
  1388. X
  1389. X        "\" has no exits for NPC's to follow, but it's not 
  1390. X        listed as off limits to NPC's.  Please notify the 
  1391. X        cave management as soon as possible!";
  1392. X    }
  1393. X    else if (global.debug) {
  1394. X        //
  1395. X        // Debugging info:
  1396. X        //             
  1397. X        "\b\""; o.sdesc; "\" has "; say(length(o.NPCexits));
  1398. X        if (length(o.NPCexits) > 1)
  1399. X            " NPC exits:";
  1400. X        else
  1401. X            " NPC exit:";
  1402. X
  1403. X            tot := length(o.NPCexits);
  1404. X        for (i := 1; i <= tot; i++) {
  1405. X            "\b\t-> ";
  1406. X            if (o.(o.NPCexits[i]))
  1407. X                o.(o.NPCexits[i]).sdesc;
  1408. X            else
  1409. X                "(nil)";
  1410. X        }
  1411. X    }
  1412. X}
  1413. X
  1414. X/*
  1415. X * A class defining some common things for NPC's.
  1416. X */
  1417. Xclass NPC: object
  1418. X    //
  1419. X    // List of currect pirate locations.
  1420. X    //
  1421. X    loclist = []        // where they are
  1422. X    newloclist = []        // where they're going
  1423. X
  1424. X    //
  1425. X    // Scatter any NPC's that are currently in
  1426. X    // the room to random rooms in the cave.  (We
  1427. X     // have to make sure the new rooms aren't off
  1428. X    // limits to dwarves, though.) 
  1429. X    //
  1430. X    scatter = {
  1431. X        local    i, dest, len, r, tot;
  1432. X                local   melocs;
  1433. X
  1434. X        for (melocs := [], i := Me.location ; i ; i := i.location)
  1435. X                melocs += i;
  1436. X                if (length(intersect(melocs, self.loclist))) return;
  1437. X
  1438. X        self.newloclist := [];
  1439. X        tot := length(self.loclist);
  1440. X                len := length(global.NPCrooms);
  1441. X        for (i := 1; i <= tot; i++) {
  1442. X            if (find(melocs, self.loclist[i])) {
  1443. X                //
  1444. X                // Make sure we get a real location.
  1445. X                //
  1446. X                dest := nil;
  1447. X                while (dest = nil) {
  1448. X                    r := rand(len);
  1449. X                    dest := global.NPCrooms[r];
  1450. X                }
  1451. X
  1452. X                self.newloclist += dest;
  1453. X            }
  1454. X            else {
  1455. X                self.newloclist += self.loclist[i];
  1456. X            }
  1457. X
  1458. X        }
  1459. X        self.loclist := self.newloclist;
  1460. X    }
  1461. X
  1462. X    //
  1463. X    // Returns true if any NPC's of this type are in locations
  1464. X    // adjacent to the player.  (I.e., if any NPC's could take
  1465. X    // any exit that would bring them to the player's current
  1466. X    // location.)
  1467. X    //
  1468. X    anyadjacent = {
  1469. X        local    adjacent, i, j, len, dir, dest, melocs;
  1470. X            local   tot1;
  1471. X        local   cur;
  1472. X
  1473. X//"\nanyadjacent(enter)\n";
  1474. X        for (melocs := [], i := Me.location ; i ; i := i.location)
  1475. X                melocs += i;
  1476. X
  1477. X        adjacent := nil;
  1478. X            tot1 := length(self.loclist);
  1479. X        for (i := 1; i <= tot1; i++) {
  1480. X            len := length(self.loclist[i].NPCexits);
  1481. X                    cur := self.loclist[i];
  1482. X            for (j := 1; j <= len; j++) {
  1483. X                            dest := cur.(cur.NPCexits[j]);
  1484. X
  1485. X                //
  1486. X                // We need to check the destination
  1487. X                // to be sure it exists.  It may be
  1488. X                // nil if we called an NPCexit method.
  1489. X                //
  1490. X                if (dest) if (find(melocs, dest)) {
  1491. X                    adjacent := true;
  1492. X                    break;
  1493. X                }
  1494. X            }
  1495. X
  1496. X            //
  1497. X            // If we've found an adjacent pirate we
  1498. X            // can stop looking.
  1499. X            //
  1500. X            if (adjacent)
  1501. X                break;
  1502. X        }
  1503. X
  1504. X//"\nanyadjacent(exit)\n";
  1505. X        return adjacent;
  1506. X    }
  1507. X;
  1508. X
  1509. X/*
  1510. X * Move the dwarves.  See the global object in ccr-std.t for paramters.
  1511. X */
  1512. XDwarves: NPC, Actor
  1513. X    rhetoricalturn = -999    // hack -- see yesVerb in ccr-verbs.t
  1514. X    attackers = 0        // number of dwarves that attack this turn
  1515. X    
  1516. X    sdesc = "threatening little dwarf"
  1517. X    ldesc = {
  1518. X        "It's probably not a good idea to get too close.  Suffice
  1519. X        it to say the little guy's pretty aggressive.";
  1520. X    }
  1521. X
  1522. X    noun = 'dwarf' 'dwarves' 'guy'
  1523. X    adjective = 'threatening' 'nasty' 'little' 'mean'
  1524. X
  1525. X    //
  1526. X    // We don't use actorDesc for the dwarves because it gets printed
  1527. X    // too early.  (We want to let the player know that a dwarf is
  1528. X    // in the room as soon as the dwarf moves into the room, not at
  1529. X    // the start of the next turn.)
  1530. X    //
  1531. X    actorDesc = {}
  1532. X
  1533. X    locationOK = true    // tell compiler OK for location to be method
  1534. X    location = {
  1535. X        local    i, melocs;
  1536. X
  1537. X        for (melocs := [], i := Me.location ; i ; i := i.location)
  1538. X                melocs += i;
  1539. X        if (length(intersect(melocs, self.loclist)) = 0)
  1540. X            return(nil);
  1541. X
  1542. X        //
  1543. X        // Check each dwarf's location.  If at least one dwarf
  1544. X        // is in the same location as the player, make our
  1545. X        // location the same as the player's.
  1546. X        //
  1547. X        for (i := 1; i <= length(self.loclist); i++)
  1548. X            if (find(melocs, self.loclist[i]))
  1549. X                return self.loclist[i];
  1550. X
  1551. X        return nil;
  1552. X    }
  1553. X
  1554. X    verDoKick(actor) =  {}
  1555. X    doKick(actor) = {
  1556. X        "You boot the dwarf across the room.  He curses, then 
  1557. X        gets up and brushes himself off.  Now he's madder 
  1558. X        than ever!";
  1559. X    }
  1560. X    verDoAttack(actor) = {
  1561. X        if (not axe.isIn(Me)) {
  1562. X            "With what?  Your bare hands?";
  1563. X            self.rhetoricalturn := global.turnsofar;
  1564. X        }
  1565. X    }
  1566. X    doAttack(actor) = { self.doAttackWith(actor, axe); }
  1567. X
  1568. X    //
  1569. X    // The following method is called when the player responds, "yes"
  1570. X    // to "With what?  Your bare hands?"
  1571. X    //
  1572. X    nicetry = { "You wish."; }
  1573. X    
  1574. X    verDoAttackWith(actor, io) = {}
  1575. X    doAttackWith(actor, io) = {
  1576. X        //
  1577. X        // If the player throws the axe at the dwarf, he
  1578. X        // might reduce the dwarf to a cloud of greasy
  1579. X        // black smoke.
  1580. X        //
  1581. X        if (io = axe) {
  1582. X            if (rand(100) <= global.dwarfhit) {
  1583. X                "You killed a little dwarf.  The body 
  1584. X                vanishes in a cloud of greasy black 
  1585. X                smoke.";
  1586. X
  1587. X                //
  1588. X                // Remove this location from our list
  1589. X                // of locations where dwarves are.
  1590. X                //
  1591. X                self.loclist -= self.location;
  1592. X            }
  1593. X            else {
  1594. X                "You attack a little dwarf, but he 
  1595. X                dodges out of the way.";
  1596. X            }
  1597. X
  1598. X            axe.moveInto(Me.location);
  1599. X        }
  1600. X        else if (io = Hands)
  1601. X            self.nicetry;
  1602. X        else
  1603. X            "Somehow I doubt that'll be very effective.";
  1604. X    }
  1605. X    
  1606. X    verIoGiveTo(actor) = {}
  1607. X    ioGiveTo(actor, dobj) = {
  1608. X        if (dobj = tasty_food) {
  1609. X            self.doFeed(Me);
  1610. X        }
  1611. X        else {
  1612. X            "The dwarf is not at all interested in your 
  1613. X            offer.  (The reason being, perhaps, that if 
  1614. X            he kills you he gets everything you have 
  1615. X            anyway.)";
  1616. X        }
  1617. X    }
  1618. X
  1619. X    verIoThrowAt(actor) = { self.verIoGiveTo(actor); }
  1620. X    ioThrowAt(actor, dobj) = {
  1621. X        if (dobj = axe)
  1622. X            self.doAttackWith(actor, dobj);
  1623. X        else
  1624. X            self.ioGiveTo(actor, dobj);
  1625. X    }
  1626. X    verIoThrowTo(actor) = { self.verIoGiveTo(actor); }
  1627. X    ioThrowTo(actor, dobj) = {
  1628. X        if (dobj = axe)
  1629. X            self.doAttackWith(actor, dobj);
  1630. X        else
  1631. X            self.ioGiveTo(actor, dobj);
  1632. X    }
  1633. X
  1634. X    verDoFeed(actor) = {}
  1635. X    doFeed(actor) = {
  1636. X        if (tasty_food.isIn(Me)) {
  1637. X            "You fool, dwarves eat only coal!  Now you've 
  1638. X            made him *really* mad!!";
  1639. X        }
  1640. X        else {
  1641. X            "You have no food to give the dwarf.";
  1642. X        }
  1643. X    }
  1644. X
  1645. X    //
  1646. X    // Place dwarves in starting locations.
  1647. X    //
  1648. X    place = {
  1649. X        local    i, loc, r;
  1650. X
  1651. X        self.loclist := [];
  1652. X        for (i := 1; i <= global.dwarves; i++) {
  1653. X            //
  1654. X            // If there are any fixed starting locations
  1655. X            // for dwarves left, put this dwarf in the
  1656. X            // next one.  Otherwise place him randomly.
  1657. X            //
  1658. X            loc := nil;
  1659. X            if (length(global.dwarfloc) >= i)
  1660. X                loc := global.dwarfloc[i];
  1661. X
  1662. X            //
  1663. X            // Invalidate initial location if it's off limits
  1664. X            // to NPC's.
  1665. X            //
  1666. X            if (loc)
  1667. X                if (loc.noNPCs)
  1668. X                    loc := nil;
  1669. X
  1670. X            //
  1671. X            // Make sure we get a real location.
  1672. X            //
  1673. X            while (loc = nil) {
  1674. X                r := rand(length(global.NPCrooms));
  1675. X                loc := global.NPCrooms[r];
  1676. X            }
  1677. X            
  1678. X            //
  1679. X            // Add this dwarf's location to the list.
  1680. X            //
  1681. X            self.loclist := self.loclist + loc;
  1682. X        }
  1683. X    }
  1684. X
  1685. X    //
  1686. X    // Move dwarves.
  1687. X    //
  1688. X    move = {
  1689. X        local    i, j, len, r, dest, done, dir, loc;
  1690. X        local   melocs;
  1691. X//"\ndwarves.move(enter)\n";
  1692. X
  1693. X        //
  1694. X        // Move each remaining dwarf.
  1695. X        //
  1696. X        // If the dwarf is currently in the player's location,
  1697. X        // he stays where he is.
  1698. X        //
  1699. X        // If a dwarf is in a location adjacent to the player's
  1700. X        // current location, he moves into the player's location
  1701. X        // if he can.  (We check his possible exits to see if
  1702. X        // any of them go the player's location.)  A consequence
  1703. X        // of this is that dwarves will follow the player
  1704. X        // relentlessly once they've spotted him.  (But the global
  1705. X        // value dwarftenacity can be set to prevent dwarves
  1706. X        // from *always following*, of course.)
  1707. X        //
  1708. X        // If a dwarf isn't adjacent to the player, he just moves
  1709. X        // around randomly.
  1710. X        //
  1711. X        
  1712. X        for (melocs := [], i := Me.location ; i ; i := i.location)
  1713. X                melocs += i;
  1714. X
  1715. X        self.newloclist := [];
  1716. X        self.attackers := 0;    // assume no dwarves attack this turn
  1717. X        for (i := length(self.loclist); i > 0; i--) {
  1718. X            //
  1719. X            // Get a copy of this dwarf's location for speed.
  1720. X            //
  1721. X            loc := self.loclist[i];
  1722. X
  1723. X            //
  1724. X            // Haven't found a new location yet.
  1725. X            //
  1726. X            done := nil;
  1727. X
  1728. X            //
  1729. X            // In player's current location?
  1730. X            //
  1731. X                    if (find(melocs, loc)) {
  1732. X                dest := loc;    // stay put
  1733. X                done := true;
  1734. X            }
  1735. X
  1736. X            //
  1737. X            // Try each exit and see if we can reach the
  1738. X            // player.  If we have an exit that leads to
  1739. X            // the player, we know it's an OK destination
  1740. X            // location, since we pruned off all the noNPCs
  1741. X            // rooms when we constructed the exit lists. 
  1742. X            //
  1743. X            len := length(loc.NPCexits);
  1744. X            if (not done) for (j := len; j > 0; j--) {
  1745. X                dir := loc.NPCexits[j];
  1746. X                dest := loc.(dir);
  1747. X
  1748. X                //
  1749. X                // We need to check the destination
  1750. X                // to be sure it exists.  It may be
  1751. X                // nil if we called an NPCexit method.
  1752. X                //
  1753. X                    if (dest <> nil and find(melocs, dest) <> nil)
  1754. X                    {
  1755. X                    //
  1756. X                    // Is this dwarf tenacious enough
  1757. X                    // to follow the player?
  1758. X                    //
  1759. X                    if (rand(100) <= global.dtenacity)
  1760. X                        done := true;
  1761. X                    break;
  1762. X                }
  1763. X            }
  1764. X
  1765. X            //
  1766. X            // Have we found a destination yet?  If not,
  1767. X            // move dwarf to a randomly selected adjacent
  1768. X            // location.
  1769. X            //
  1770. X            // We need to check the destination because
  1771. X            // the NPCexit methods in the rooms can sometimes
  1772. X            // return nil.  (For example, when the crystal
  1773. X            // bridge doesn't exist yet, the giant's door
  1774. X            // has not been opened, etc.)
  1775. X            //
  1776. X            while (not done) {
  1777. X                dir := loc.NPCexits[rand(len)];
  1778. X                dest := loc.(dir);
  1779. X
  1780. X                if (dest)
  1781. X                    done := true;
  1782. X            }
  1783. X
  1784. X            //
  1785. X            // Set new destination.
  1786. X            //
  1787. X            self.newloclist += dest; 
  1788. X
  1789. X            //
  1790. X            // If the dwarf didn't move, he has an opportunity
  1791. X            // to attack.
  1792. X            //
  1793. X            if (loc = dest) {
  1794. X                    if (find(melocs, loc))
  1795. X                    if (rand(100) <= global.dwarfattack)
  1796. X                        self.attackers++;
  1797. X
  1798. X                //
  1799. X                // Print some debugging info if in debug mode
  1800. X                //
  1801. X                if (global.debug) {
  1802. X                    P();
  1803. X                    "Dwarf stays \""; dest.sdesc; ".\"\n";
  1804. X                }
  1805. X            }
  1806. X            else {
  1807. X                //
  1808. X                // Print some debugging info if in debug mode
  1809. X                //
  1810. X                if (global.debug) {
  1811. X                    P();
  1812. X                    "Dwarf moves from \"";
  1813. X                    self.loclist[i].sdesc; "\" to \"";
  1814. X                    dest.sdesc; ".\"\n";
  1815. X                }
  1816. X            }
  1817. X        }
  1818. X
  1819. X        //
  1820. X        // Replace old locations with destinations.
  1821. X        //
  1822. X        self.loclist := self.newloclist;
  1823. X
  1824. X        self.tell;
  1825. X//"\ndwarves.move(exit)\n";
  1826. X    }
  1827. X
  1828. X    //
  1829. X    // Tell the player what's going on with the dwarves.
  1830. X    //
  1831. X    tell = {    
  1832. X        local    i, j, len, r, dest, done, dir, count, adjacent;
  1833. X        local   melocs;
  1834. X//"\ntell(enter)\n";
  1835. X        //
  1836. X        // Count how many dwarves are in the room with the player.
  1837. X        //
  1838. X        for (melocs := [], i := Me.location ; i ; i := i.location)
  1839. X                melocs += i;
  1840. X        count := length(intersect(melocs, self.loclist));
  1841. X
  1842. X        //
  1843. X        // If any dwarves are in the room with the player and
  1844. X        // the axe hasn't been thrown yet, throw the axe and
  1845. X        // scatter the dwarves.
  1846. X        //
  1847. X        if (count > 0 and axe.location = nil) {
  1848. X            P(); I();
  1849. X
  1850. X            "A little dwarf just walked around a corner, 
  1851. X            saw you, threw a little axe at you which 
  1852. X            missed, cursed, and ran away.";
  1853. X
  1854. X            axe.moveInto(self.location);
  1855. X
  1856. X            //
  1857. X            // Scatter any dwarves in the room.
  1858. X            //
  1859. X            self.scatter;
  1860. X
  1861. X            //
  1862. X            // No dwarves in the room.  Be sure we take back
  1863. X            // those attacks too...
  1864. X            //
  1865. X            count := 0;
  1866. X            self.attackers := 0;
  1867. X        }
  1868. X
  1869. X        //
  1870. X        // Tell the player if any dwarves are in the room with him,
  1871. X        // or if any are nearby.
  1872. X        //
  1873. X        if (count = 0) {
  1874. X            //
  1875. X            // If no dwarves are in the room, but at least
  1876. X            // one dwarf is in an adjacent location, tell
  1877. X            // the player he hears something.
  1878. X            //
  1879. X            // (Only the pirate makes noise in the original,
  1880. X            // which seem a bit strange and not as much fun.)
  1881. X            //
  1882. X            if (self.anyadjacent) {
  1883. X                P(); I(); "You hear the pitter-patter 
  1884. X                of little feet.";
  1885. X            }
  1886. X        }
  1887. X        else if (count = 1) {
  1888. X            P(); I();
  1889. X            "There is a threatening little dwarf in the 
  1890. X            room with you.";
  1891. X        }
  1892. X        else if (count > 1) {
  1893. X            P(); I();
  1894. X            "There are "; say(count); " threatening 
  1895. X            little dwarves in the room with you.";
  1896. X        }
  1897. X
  1898. X        //
  1899. X        // Handle dwarf attacks.
  1900. X        //
  1901. X        if (self.attackers > 0) {
  1902. X            if (self.attackers = 1) {
  1903. X                if (count = 1)
  1904. X                    " He throws a knife at you!";
  1905. X                 else
  1906. X                    " One of them throws a knife 
  1907. X                    at you!";
  1908. X            }
  1909. X            else {
  1910. X                if (self.attackers = count) {
  1911. X                    if (count = 2)
  1912. X                        " Both of them throw 
  1913. X                        knives at you!";
  1914. X                    else 
  1915. X                        " All of them throw 
  1916. X                        knives at you!";
  1917. X                }
  1918. X                else {
  1919. X                    say(self.attackers); " of them throw 
  1920. X                    knives at you!";
  1921. X                }
  1922. X            }
  1923. X
  1924. X            //
  1925. X            // Curtains for our hero?!
  1926. X            //
  1927. X            count := 0;
  1928. X            for (i := 1; i <= self.attackers; i++) {
  1929. X                if (rand(100) <= global.dwarfaccuracy)
  1930. X                    count++;
  1931. X            }
  1932. X
  1933. X            P(); I();
  1934. X            if (count > 0) {
  1935. X                if (count = self.attackers) {
  1936. X                    if (count = 1)
  1937. X                        "It gets you!";
  1938. X                    else if (count = 2)
  1939. X                        "Both of them get you!";
  1940. X                    else
  1941. X                        "All of them get you!";
  1942. X                }
  1943. X                else if (count = 1) {
  1944. X                    "One of them gets you!";
  1945. X                }
  1946. X                else {
  1947. X                    say(count); " of them get 
  1948. X                    you!";
  1949. X                }
  1950. X
  1951. X                die();
  1952. X            }
  1953. X            else {
  1954. X                if (self.attackers = 1) 
  1955. X                    "It misses you!";
  1956. X                else if (self.attackers = 2)
  1957. X                    "Both of them miss you!";
  1958. X                else
  1959. X                    "They all miss you!";
  1960. X            }
  1961. X        }
  1962. X//"\ntell(exit)\n";
  1963. X    }
  1964. X;
  1965. X/*
  1966. X * The player can never get the dwarves' knives (that would be too easy),
  1967. X * but we'll let him examine them anyway.
  1968. X */
  1969. XDwarfKnives: decoration
  1970. X    sdesc = "dwarf's knife"
  1971. X    ldesc = { self.verifyRemove(Me); }
  1972. X    noun = 'knife' 'knives'
  1973. X    adjective = 'sharp' 'nasty' 'dwarf\'s' 'dwarvish' 'dwarven'
  1974. X            'dwarfish'
  1975. X
  1976. X    locationOK = true    // tell compiler OK for location to be method
  1977. X    location = {
  1978. X        return Dwarves.location;
  1979. X    }
  1980. X
  1981. X    verifyRemove(actor) = {
  1982. X        "The dwarves' knives vanish as they strike the walls 
  1983. X        of the cave.";
  1984. X    }
  1985. X
  1986. X    verIoAttackWith(actor) = {
  1987. X        "You don't have the dwarf's knife!";
  1988. X    }
  1989. X;
  1990. X
  1991. X/*
  1992. X * Move the pirate(s).  See the global object in ccr-std.t for paramters.
  1993. X *
  1994. X * This code is quite similar to the Dwarves code, but is simple because
  1995. X * there's never any interaction between the player and the pirates. (The
  1996. X * pirates just come in, do their stuff, and vanish.)
  1997. X *
  1998. X * Note that even if there's more than one pirate, the text printed in
  1999. X * in this object will treat all the pirates as a single one. So the
  2000. X * only difference having multiple pirates makes is that the more you
  2001. X * have, the more likely the player is to run into "him."
  2002. X */
  2003. XPirates: NPC, Actor
  2004. X    location = nil    // not a real actor, so pretend we don't exist
  2005. X
  2006. X    seen = nil    // has the player seen (one of) us?
  2007. X
  2008. X    //
  2009. X    // Place pirates in starting locations.
  2010. X    //
  2011. X    place = {
  2012. X        local    i, loc, r;
  2013. X
  2014. X        self.loclist := [];
  2015. X        for (i := 1; i <= global.pirates; i++) {
  2016. X            //
  2017. X            // If there are any fixed starting locations
  2018. X            // for pirates left, put this pirate in the
  2019. X            // next one.  Otherwise place him randomly.
  2020. X            //
  2021. X            loc := nil;
  2022. X            if (length(global.pirateloc) >= i)
  2023. X                loc := global.pirateloc[i];
  2024. X
  2025. X            //
  2026. X            // Invalidate initial location if it's off limits
  2027. X            // to NPC's.
  2028. X            //
  2029. X            if (loc)
  2030. X                if (loc.noNPCs)
  2031. X                    loc := nil;
  2032. X
  2033. X            //
  2034. X            // Make sure we get a real location.
  2035. X            //
  2036. X            while (loc = nil) {
  2037. X                r := rand(length(global.NPCrooms));
  2038. X                loc := global.NPCrooms[r];
  2039. X            }
  2040. X            
  2041. X            //
  2042. X            // Add this pirate's location to the list.
  2043. X            //
  2044. X            self.loclist := self.loclist + loc;
  2045. X        }
  2046. X    }
  2047. X
  2048. X    //
  2049. X    // Move pirates.
  2050. X    //
  2051. X    move = {
  2052. X        local    i, j, len, r, dest, done, dir, melocs;
  2053. X
  2054. X//"\npirates.move(enter)\n";
  2055. X        //
  2056. X        // Move each remaining pirate.
  2057. X        //
  2058. X        // If the pirate is currently in the player's location,
  2059. X        // he stays where he is.
  2060. X        //
  2061. X        // If a pirate is in a location adjacent to the player's
  2062. X        // current location, he moves into the player's location
  2063. X        // if he can.  We limit this with the ptenacity global.
  2064. X        //
  2065. X        // If a pirate isn't adjacent to the player, he just moves
  2066. X        // around randomly.
  2067. X        //
  2068. X        self.newloclist := [];
  2069. X        for (melocs := [], i := Me.location ; i ; i := i.location)
  2070. X                melocs += i;
  2071. X
  2072. X        for (i := 1; i <= length(self.loclist); i++) {
  2073. X            //
  2074. X            // Haven't found a new location yet.
  2075. X            //
  2076. X            done := nil;
  2077. X
  2078. X            //
  2079. X            // In player's current location?
  2080. X            //
  2081. X            if (find(melocs, self.loclist[i])) {
  2082. X                dest := self.loclist[i];    // stay put
  2083. X                done := true;
  2084. X            }
  2085. X
  2086. X            //
  2087. X            // Try each exit and see if we can reach the
  2088. X            // player.  If we have an exit that leads to
  2089. X            // the player, we know it's an OK destination
  2090. X            // location, since we pruned off all the noNPCs
  2091. X            // rooms when we constructed the exit lists. 
  2092. X            //
  2093. X            len := length(self.loclist[i].NPCexits);
  2094. X            if (not done) for (j := 1; j <= len; j++) {
  2095. X                dir := self.loclist[i].NPCexits[j];
  2096. X                dest := self.loclist[i].(dir);
  2097. X
  2098. X                //
  2099. X                // We need to check the destination
  2100. X                // to be sure it exists.  It may be
  2101. X                // nil if we called an NPCexit method.
  2102. X                //
  2103. X                if (dest) if (find(melocs, dest)) {
  2104. X                    //
  2105. X                    // Is this pirate tenacious enough
  2106. X                    // to follow the player?
  2107. X                    //
  2108. X                    if (rand(100) <= global.ptenacity)
  2109. X                        done := true;
  2110. X                    break;
  2111. X                }
  2112. X            }
  2113. X
  2114. X            //
  2115. X            // Have we found a destination yet?  If not,
  2116. X            // move pirate to a randomly selected adjacent
  2117. X            // location.
  2118. X            //
  2119. X            // We need to check the destination because
  2120. X            // the NPCexit methods in the rooms can sometimes
  2121. X            // return nil.  (For example, when the crystal
  2122. X            // bridge doesn't exist yet, the giant's door
  2123. X            // has not been opened, etc.)
  2124. X            //
  2125. X            while (not done) {
  2126. X                dir := self.loclist[i].NPCexits[rand(len)];
  2127. X                dest := self.loclist[i].(dir);
  2128. X
  2129. X                if (dest)
  2130. X                    done := true;
  2131. X            }
  2132. X
  2133. X            //
  2134. X            // Set new destination.
  2135. X            //
  2136. X            self.newloclist += dest; 
  2137. X
  2138. X            //
  2139. X            // Print some debugging info if in debug mode
  2140. X            //
  2141. X            if (self.loclist[i] = dest) {
  2142. X                if (global.debug) {
  2143. X                    P();
  2144. X                    "Pirate stays \""; dest.sdesc; ".\"\n";
  2145. X                }
  2146. X            }
  2147. X            else {
  2148. X                if (global.debug) {
  2149. X                    P();
  2150. X                    "Pirate moves from \"";
  2151. X                    self.loclist[i].sdesc; "\" to \"";
  2152. X                    dest.sdesc; ".\"\n";
  2153. X                }
  2154. X            }
  2155. X        }
  2156. X
  2157. X        //
  2158. X        // Replace old locations with destinations.
  2159. X        //
  2160. X        self.loclist := self.newloclist;
  2161. X
  2162. X        self.tell;
  2163. X//"\npirates.move(exit)\n";
  2164. X    }
  2165. X
  2166. X    //
  2167. X    // Tell the player what's going on with the pirates.
  2168. X    //
  2169. X    tell = {    
  2170. X        local    i, t, count, snagged, melocs;
  2171. X//"\npirates.tell(enter)\n";
  2172. X
  2173. X        //
  2174. X        // Count how many pirates are in the room with the player.
  2175. X        // (We really only need to know if there are any at all,
  2176. X        // but this is just as easy.)
  2177. X        //
  2178. X        for (melocs := [], i := Me.location ; i ; i := i.location)
  2179. X                melocs += i;
  2180. X        count := length(intersect(melocs, self.loclist));
  2181. X                        
  2182. X        //
  2183. X        // Tell the player if any pirates are nearby.
  2184. X        //
  2185. X        if (count = 0) {
  2186. X            //
  2187. X            // If no pirates are in the room, but at least
  2188. X            // one pirate is in an adjacent location, tell
  2189. X            // the player he hears something.
  2190. X            //
  2191. X            if (self.anyadjacent) {
  2192. X                P(); I();
  2193. X                "There are faint rustling noises from 
  2194. X                the darkness behind you.";
  2195. X            }
  2196. X        }
  2197. X        else if (count > 0) {
  2198. X            //
  2199. X            // A pirate has snagged the player.
  2200. X            // Move any treasures the player is carring
  2201. X            // to the pirate's repository, currently
  2202. X            // hard-coded as Dead_End_13 because there's
  2203. X            // code in that room that can't easily be
  2204. X            // made general.
  2205. X            //
  2206. X            // Since the player may be keeping his treasures
  2207. X            // in containers, it's actually easier just
  2208. X            // to search through the global list of
  2209. X            // treasures and check each one's location to
  2210. X            // see if it's in the player, rather than
  2211. X            // recursively checking all the player's belongings
  2212. X            // and seeing if they're treasures.  (Also, we want
  2213. X            // to get treasures that are just lying around in
  2214. X            // the room too.)
  2215. X            //
  2216. X            snagged := 0;
  2217. X            for (i := 1; i <= length(global.treasurelist); i++) {
  2218. X                t := global.treasurelist[i] ;
  2219. X                if (t.isIn(Me.location)) {
  2220. X                    t.moveInto(Dead_End_13);
  2221. X                    snagged++;
  2222. X                }
  2223. X            }
  2224. X
  2225. X            //
  2226. X            // Print a message telling the player what happened.
  2227. X            //
  2228. X            if (snagged > 0) {
  2229. X                P();
  2230. X                I(); "Out from the shadows behind you 
  2231. X                pounces a bearded pirate!  \"Har, 
  2232. X                har,\" he chortles.  \"I'll just take 
  2233. X                all this booty and hide it away with 
  2234. X                me chest deep in the maze!\"  He 
  2235. X                snatches your treasure and vanishes 
  2236. X                into the gloom.";
  2237. X            }
  2238. X            else {
  2239. X                //
  2240. X                // In the original code, if you weren't
  2241. X                // holding the lamp, you just wouldn't
  2242. X                // see the pirate when you weren't
  2243. X                // carrying any treasures.  This seems
  2244. X                // bogus, so I've added a conditional here.
  2245. X                //
  2246. X                P();
  2247. X                I(); "There are faint rustling noises 
  2248. X                from the darkness behind you.  As you 
  2249. X                turn toward them, ";
  2250. X
  2251. X                if (brass_lantern.isIn(Me))
  2252. X                    "the beam of your lamp falls 
  2253. X                    across";
  2254. X                else
  2255. X                    "you spot";
  2256. X
  2257. X                " a bearded pirate. He is carrying a 
  2258. X                large chest.  \"Shiver me timbers!\" 
  2259. X                He cries, \"I've been spotted!  I'd 
  2260. X                best hie meself off to the maze to 
  2261. X                hide me chest!\" With that, he 
  2262. X                vanishes into the gloom.";
  2263. X            }
  2264. X
  2265. X            //
  2266. X            // Install the treasure chest if it hasn't
  2267. X            // already been installed.  No worries about
  2268. X            // the chest appearing out of nowhere when
  2269. X            // the player's at Dead_End_13, because the
  2270. X            // pirate can't go there.  (It's off limits
  2271. X            // to NPC's.)
  2272. X            //
  2273. X            if (not self.seen) {
  2274. X                treasure_chest.moveInto(Dead_End_13);
  2275. X                self.seen := true;
  2276. X            }
  2277. X
  2278. X            //
  2279. X            // Scatter any pirates in the room.
  2280. X            //
  2281. X            self.scatter;
  2282. X        }
  2283. X//"\npirates.tell(enter)\n";
  2284. X    }
  2285. X;
  2286. END_OF_FILE
  2287. if test 25988 -ne `wc -c <'src/ccr-npc.t'`; then
  2288.     echo shar: \"'src/ccr-npc.t'\" unpacked with wrong size!
  2289. fi
  2290. # end of 'src/ccr-npc.t'
  2291. fi
  2292. if test -f 'src/ccr.t' -a "${1}" != "-c" ; then 
  2293.   echo shar: Will not clobber existing file \"'src/ccr.t'\"
  2294. else
  2295. echo shar: Extracting \"'src/ccr.t'\" \(2419 characters\)
  2296. sed "s/^X//" >'src/ccr.t' <<'END_OF_FILE'
  2297. X/*
  2298. X * Colossal Cave Revisited
  2299. X *
  2300. X * A remake of Willie Crowther and Don Woods' classic Adventure.
  2301. X * Converted from Donald Ekman's PC port of the original FORTRAN source.
  2302. X * TADS version by David M. Baggett for ADVENTIONS.
  2303. X *
  2304. X * Colossal Cave Revisited and its accompanying source code are
  2305. X * Copyright (C) 1993 David M. Baggett.
  2306. X *
  2307. X *---------------------------------------------------------------------------
  2308. X * This program is free software; you can redistribute it and/or modify
  2309. X * it under the terms of version 2 of the GNU General Public License as
  2310. X * published by the Free Software Foundation.
  2311. X *
  2312. X * This program is distributed in the hope that it will be useful,
  2313. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  2314. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2315. X * GNU General Public License for more details.
  2316. X *
  2317. X * You should have received a copy of the GNU General Public License
  2318. X * along with this program; if not, write to the Free Software
  2319. X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  2320. X *
  2321. X *---------------------------------------------------------------------------
  2322. X *
  2323. X * Please document all changes in the history (here as well as in the
  2324. X * appropriate source files) so we know who did what.
  2325. X *
  2326. X *---------------------------------------------------------------------------
  2327. X *
  2328. X * ADVENTIONS distributes this game, but you are free to do what you will
  2329. X * with it, provided you adhere to the terms in the GNU Public License.
  2330. X * Send correspondence regarding this game or original works distributed
  2331. X * by ADVENTIONS to 
  2332. X *
  2333. X *    ADVENTIONS
  2334. X *    PO Box 851
  2335. X *    Columbia, MD 21044
  2336. X *
  2337. X * If you would like a catalog of releases, please enclose a SASE.  Thanks!
  2338. X *
  2339. X * Contributors
  2340. X *
  2341. X *    dmb    In real life:    David M. Baggett
  2342. X *        Internet:    <dmb@ai.mit.edu>
  2343. X *        Compu$erve:    76440,2671 (ADVENTIONS account)
  2344. X *        GEnie:        ADVENTIONS
  2345. X *
  2346. X * Modification History
  2347. X *
  2348. X * 1-Jan-93    dmb    rec.arts.int-fiction BETA release (source only)
  2349. X *                      For beta testing only -- not for general
  2350. X *            distribution.
  2351. X *
  2352. X * 20-Apr-93    dmb     Version 1.0 release.
  2353. X *
  2354. X *  9-Jul-93    dmb    Widespread version 1.0 release for all supported
  2355. X *            machines.
  2356. X *
  2357. X */
  2358. X#include "history.t"
  2359. X
  2360. X#include "ccr-adv.t"
  2361. X#include "format.t"
  2362. X#include "preparse.t"
  2363. X#include "ccr-std.t"
  2364. X#include "ccr-room.t"
  2365. X#include "ccr-item.t"
  2366. X#include "ccr-verb.t"
  2367. X#include "ccr-npc.t"
  2368. X#include "help.t"
  2369. X#include "close.t"
  2370. END_OF_FILE
  2371. if test 2419 -ne `wc -c <'src/ccr.t'`; then
  2372.     echo shar: \"'src/ccr.t'\" unpacked with wrong size!
  2373. fi
  2374. # end of 'src/ccr.t'
  2375. fi
  2376. if test -f 'src/makefile' -a "${1}" != "-c" ; then 
  2377.   echo shar: Will not clobber existing file \"'src/makefile'\"
  2378. else
  2379. echo shar: Extracting \"'src/makefile'\" \(884 characters\)
  2380. sed "s/^X//" >'src/makefile' <<'END_OF_FILE'
  2381. X#
  2382. X# Makefile for Colossal Cave Revisited
  2383. X# Requires TADS compiler 2.1.0 or greater.
  2384. X#
  2385. X# Note that some of the Unix versions of the compilers return error
  2386. X# codes when everything's actually fine.
  2387. X#
  2388. X
  2389. X#
  2390. X# Set TC and TR to point to your TADS compiler and run-time.
  2391. X#
  2392. XTC=        tadsc
  2393. XTR=        tadsr
  2394. X
  2395. XPROGNAME=    ccr
  2396. XDEBUG=        -ds
  2397. XSWAPTIONS=
  2398. XOOPTIONS=    -s -mp32000
  2399. XOPTIONS=    $(OOPTIONS) $(SWAPTIONS) $(DEBUG)
  2400. X
  2401. X# Production version options
  2402. XPOPTIONS=    $(OOPTIONS) $(SWAPTIONS)
  2403. X
  2404. X.PRECIOUS=    $(PROGNAME).gam        # do not delete game file on errors
  2405. X
  2406. XHEADERS= ccr-adv.t ccr-std.t
  2407. XROOMS=   ccr-room.t
  2408. XOBJECTS= ccr-item.t
  2409. XMISC=    close.t ccr-verb.t format.t help.t ccr-npc.t preparse.t thingext.t
  2410. X
  2411. X$(PROGNAME).gam: makefile $(PROGNAME).t $(HEADERS) $(ROOMS) $(OBJECTS) $(MISC)
  2412. X    $(TC) $(OPTIONS) $(PROGNAME).t
  2413. X
  2414. Xproduction: makefile $(PROGNAME).t $(HEADERS) $(ROOMS) $(OBJECTS) $(MISC)
  2415. X    $(TC) $(POPTIONS) $(PROGNAME).t
  2416. END_OF_FILE
  2417. if test 884 -ne `wc -c <'src/makefile'`; then
  2418.     echo shar: \"'src/makefile'\" unpacked with wrong size!
  2419. fi
  2420. # end of 'src/makefile'
  2421. fi
  2422. echo shar: End of archive 9 \(of 11\).
  2423. cp /dev/null ark9isdone
  2424. MISSING=""
  2425. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2426.     if test ! -f ark${I}isdone ; then
  2427.     MISSING="${MISSING} ${I}"
  2428.     fi
  2429. done
  2430. if test "${MISSING}" = "" ; then
  2431.     echo You have unpacked all 11 archives.
  2432.     echo "Now run buildit.sh to make gam file"
  2433.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2434. else
  2435.     echo You still need to unpack the following archives:
  2436.     echo "        " ${MISSING}
  2437. fi
  2438. ##  End of shell archive.
  2439. exit 0
  2440.