1 2(********************************************************************) 3(* *) 4(* wiz.sd7 Find treasures and fight monsters labyrinth game *) 5(* Copyright (C) 1990 - 1994, 2004, 2007, 2008 Thomas Mertes *) 6(* 2011, 2013, 2021 Thomas Mertes *) 7(* *) 8(* This program is free software; you can redistribute it and/or *) 9(* modify it under the terms of the GNU General Public License as *) 10(* published by the Free Software Foundation; either version 2 of *) 11(* the License, or (at your option) any later version. *) 12(* *) 13(* This program is distributed in the hope that it will be useful, *) 14(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) 15(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) 16(* GNU General Public License for more details. *) 17(* *) 18(* You should have received a copy of the GNU General Public *) 19(* License along with this program; if not, write to the *) 20(* Free Software Foundation, Inc., 51 Franklin Street, *) 21(* Fifth Floor, Boston, MA 02110-1301, USA. *) 22(* *) 23(********************************************************************) 24 25 26$ include "seed7_05.s7i"; 27 include "keybd.s7i"; 28 include "console.s7i"; 29 include "editline.s7i"; 30 include "wrinum.s7i"; 31 32const integer: SIZE_LABY is 8; 33const integer: NUM_LEVELS is 8; 34const integer: RESTRICTED_CONNECTION_COUNT is 5; 35const integer: STAIRS_PER_LEVEL is 3; 36const integer: THINGS_PER_LEVEL is 1; 37const integer: VENDORS_PER_LEVEL is 1; 38const integer: OCCURRENCES_PER_LEVEL is 1; 39const integer: TRANSFERS_PER_LEVEL is 1; 40const integer: ARMOR_STRENGTH_FACTOR is 7; 41 42 43const type: speciesType is new enum 44 HOBBIT, ELF, HUMAN, DWARF 45 end enum; 46 47const func string: str (in speciesType: species) is 48 return [] ("hobbit", "elf", "human", "dwarf")[succ(ord(species))]; 49 50enable_output(speciesType); 51 52 53const type: directType is new enum 54 NORTH, SOUTH, EAST, WEST, UP, DOWN 55 end enum; 56 57const func string: str (in directType: direct) is 58 return [] ("north", "south", "east", "west", "up", "down")[succ(ord(direct))]; 59 60enable_output(directType); 61 62const type: directSet is set of directType; 63 64 65const type: objectType is new enum 66 NOOBJECT, LAMP, RUBY, NORNSTONE, PEARL, OPAL, GREENGEM, BLUEFLAME, 67 PALANTIR, SILMARIL, RUNESTAFF, ORBOFZOT 68 end enum; 69 70const func string: str (in objectType: anObject) is 71 return [] ("nothing", "lamp", "ruby red", "norn Stone", "pale pearl", 72 "opal Eye", "green Gem", "blue Flame", "Palantir", "Silmaril", 73 "Runestaff", "*ORB OF ZOT*")[succ(ord(anObject))]; 74 75enable_output(objectType); 76 77const type: objectSet is set of objectType; 78 79const objectSet: treasureSet is {RUBY, NORNSTONE, PEARL, OPAL, GREENGEM, 80 BLUEFLAME, PALANTIR, SILMARIL}; 81 82 83const type: animateType is new enum 84 NOBODY, KOBOLD, ORC, WOLF, GOBLIN, OGRE, TROLL, BEAR, 85 MINOTAUR, GARGOYLE, CHIMERA, BALROG, DRAGON, VENDOR 86 end enum; 87 88const func string: str (in animateType: anAnimate) is 89 return [] ("nobody", "kobold", "orc", "wolf", "goblin", "ogre", "troll", 90 "bear", "minotaur", "gargoyle", "chimera", "balrog", "dragon", 91 "vendor")[succ(ord(anAnimate))]; 92 93enable_output(animateType); 94 95 96const type: armorType is new enum 97 NOARMOR, LEATHER, CHAINMAIL, PLATE 98 end enum; 99 100const func string: str (in armorType: anArmor) is 101 return [] ("no", "leather", "chainmail", "plate") [succ(ord(anArmor))]; 102 103enable_output(armorType); 104 105 106const type: weaponType is new enum 107 NOWEAPON, DAGGER, MACE, SWORD 108 end enum; 109 110const func string: str (in weaponType: aWeapon) is 111 return [] ("no", "dagger", "mace", "sword") [succ(ord(aWeapon))]; 112 113enable_output(weaponType); 114 115 116const type: commandType is new enum 117 ILLEGAL, GO_NORTH, GO_SOUTH, GO_EAST, GO_WEST, GO_UP, GO_DOWN, WAIT, 118 INVENTORY, HELP, LOOK, MAP, FLARE, USE_LAMP, ATTACK, CAST, BRIBE, 119 STATUS, OPEN, READ, GAZE, TELEPORT, DRINK, SELL, BUY, QUITCOMMAND 120 end enum; 121 122const type: contentType is new enum 123 EMPTYROOM, ENTRANCE, EMPTYCHEST, CHESTWITHSKELETON, CLOSEDCHEST, ORB, 124 POOL, BOOK 125 end enum; 126 127const type: transferType is new enum 128 NOTRANSFER, SINKHOLE, WARP 129 end enum; 130 131const type: occurType is new enum 132 NOOCCURRENCE, LEECH, LETHARGY, FORGET, STEALARMOR, STEALWEAPON, 133 STEALLAMP, STEALFLARES, STEALTREASURE, FINDGOLD, FINDFLARES 134 end enum; 135 136const type: playerType is new struct 137 var speciesType: species is HUMAN; 138 var boolean: isMale is TRUE; 139 var integer: strength is 2; 140 var integer: intelligence is 8; 141 var integer: dexterity is 14; 142 var integer: goldPieces is 10; 143 var armorType: armor is NOARMOR; 144 var integer: armorStrength is 0; 145 var weaponType: weapon is NOWEAPON; 146 var boolean: weaponBlocked is FALSE; 147 var integer: flares is 0; 148 var objectSet: possession is objectSet.value; 149 var integer: turns is 1; 150 var integer: mealHour is 0; 151 var boolean: living is TRUE; 152 var boolean: blind is FALSE; 153 var boolean: haveLeech is FALSE; 154 var boolean: lethargic is FALSE; 155 var boolean: forgetting is FALSE; 156 var boolean: leaveCastle is FALSE; 157 var boolean: quitDialog is FALSE; 158 var boolean: quitProgram is FALSE; 159 end struct; 160 161const type: fightStateType is new struct 162 var integer: monsterCount is NUM_LEVELS * 12; 163 var boolean: angryVendors is FALSE; 164 var integer: webCount is 0; 165 var integer: aggressionOfMonster is 0; 166 var integer: monsterStrength is 0; 167 var boolean: monsterPresent is FALSE; 168 var boolean: monsterWillAttack is FALSE; 169 var boolean: bribed is FALSE; 170 end struct; 171 172const type: roomType is new struct 173 var directSet: connections is {NORTH, SOUTH, EAST, WEST}; 174 var transferType: transfer is NOTRANSFER; 175 var occurType: occurrence is NOOCCURRENCE; 176 var animateType: roomer is NOBODY; 177 var contentType: contents is EMPTYROOM; 178 var objectSet: objects is objectSet.value; 179 var boolean: visited is FALSE; 180 var integer: xPos is 0; 181 var integer: yPos is 0; 182 var integer: zPos is 0; 183 end struct; 184 185const type: roomRef is sub object interface; 186 187type_implements_interface(roomType, roomRef); 188 189const proc: writePos (in roomRef: aRoom) is DYNAMIC; 190const proc: enterRoom (inout roomRef: currentRoom, inout playerType: player, 191 inout fightStateType: fightState) is DYNAMIC; 192const proc: incident (inout roomRef: currentRoom, 193 inout playerType: player) is DYNAMIC; 194const proc: teleportTo (inout roomRef: currentRoom, inout playerType: player, 195 inout fightStateType: fightState) is DYNAMIC; 196const proc: writeFightState (in roomRef: currentRoom, inout playerType: player, 197 inout fightStateType: fightState) is DYNAMIC; 198const proc: executeCommand (inout roomRef: currentRoom, inout playerType: player, 199 inout fightStateType: fightState) is DYNAMIC; 200const proc: removeFromRoom (inout roomRef: currentRoom, 201 in objectType: treasure) is DYNAMIC; 202 203var integer: labyrinthNumber is 0; 204 205var roomRef: currentRoomRef is roomType.value; 206 207const type: objPlaceType is array [objectType] roomRef; 208var objPlaceType: objPlace is objectType times roomType.value; 209 210const type: labyrinthType is array array array roomType; 211var labyrinthType: labyrinth is SIZE_LABY times SIZE_LABY times NUM_LEVELS times roomType.value; 212 213 214const func integer: rangeLaby (in integer: number) is 215 return succ(pred(number) mod SIZE_LABY); 216 217 218const func integer: rangeLevel (in integer: number) is 219 return succ(pred(number) mod NUM_LEVELS); 220 221 222const func integer: range18 (in integer: number) is 223 return number <= 18 ? number: 18; 224 225 226const func speciesType: rand (attr speciesType) is 227 return rand(speciesType.first, speciesType.last); 228 229 230const func animateType: rand (attr animateType) is 231 return rand(KOBOLD, DRAGON); 232 233 234const proc: startText is func 235 begin 236 writeln; 237 writeln; 238 writeln; 239 writeln("*" mult 78); 240 writeln; 241 writeln(" * * * THE WIZARD'S CASTLE * * *"); 242 writeln(" Version 2.0"); 243 writeln; 244 writeln(" Copyright"); 245 writeln(" 1990 - 1994, 2004, 2007, 2008, 2011, 2013, 2021"); 246 writeln(" Thomas Mertes"); 247 writeln; 248 writeln("*" mult 78); 249 writeln; 250 writeln(" A long time ago, in the age of the old universal empire the mighty wizard"); 251 writeln(" ZOT lived in a large subterranean castle, collecting a lot of fabulous"); 252 writeln(" treasures during his long life. Feeling the sources of his vital power"); 253 writeln(" draining away, he created a great orb of power the *ORB OF ZOT*. To hide it"); 254 writeln(" from the cretins of the surface beyond, he hired a group of esurient"); 255 writeln(" monsters to guard the *ORB OF ZOT*. From that time onward, many a bold youth"); 256 writeln(" has ventured into the castle, losing his life in cruel and unimaginable"); 257 writeln(" ways."); 258 writeln; 259 writeln("All right, bold one."); 260 end func; # startText 261 262 263const proc: writeHelp is func 264 begin 265 writeln; 266 writeln("*** WIZARD'S CASTLE COMMAND AND INFORMATION SUMMARY ***"); 267 writeln; 268 writeln("The following commands are available:"); 269 writeln; 270 writeln("H/ELP N/ORTH S/OUTH E/AST W/EST U/P D/OWN"); 271 writeln("L/OOK I/NVENTORY M/AP ST/ATUS A/TTACK C/AST BR/IBE"); 272 writeln("O/PEN R/EAD G/AZE T/ELEPORT DR/INK SE/LL B/UY"); 273 writeln("F/LARE LA/AMP Q/UIT"); 274 writeln; 275 writeln("The contents of rooms are as follows:"); 276 writeln; 277 writeln(". = EMPTY ROOM D = WAY DOWN G = GOLD PIECES P = MAGIC POOL U = WAY UP"); 278 writeln("B = BOOK E = EXIT M = MONSTER S = SINKHOLE V = VENDOR"); 279 writeln("C = CHEST F = FLARES O = CRYSTAL ORB T = TREASURE W = WARP"); 280 writeln; 281 writeln("The benefits of having treasures are:"); 282 writeln; 283 writeln("ruby red - AVOID LETHARGY pale pearl - AVOID LEECH"); 284 writeln("green gem - AVOID FORGETTING opal eye - CURES BLINDNESS"); 285 writeln("blue flame - DISSOLVES BOOKS norn stone - NO BENEFIT"); 286 writeln("palantir - NO BENEFIT silmaril - NO BENEFIT"); 287 end func; # writeHelp 288 289 290const proc: randomRoom (inout integer: xPos, inout integer: yPos, 291 inout integer: zPos) is func 292 begin 293 xPos := rand(1, SIZE_LABY); 294 yPos := rand(1, SIZE_LABY); 295 zPos := rand(1, NUM_LEVELS); 296 end func; # randomRoom 297 298 299const proc: findUninhabitedRoom (inout integer: xPos, inout integer: yPos, 300 in integer: zPos) is func 301 begin 302 repeat 303 xPos := rand(1, SIZE_LABY); 304 yPos := rand(1, SIZE_LABY); 305 until labyrinth[xPos][yPos][zPos].roomer = NOBODY and 306 labyrinth[xPos][yPos][zPos].contents <> ENTRANCE; 307 end func; # findUninhabitedRoom 308 309 310const proc: findEmptyRoom (inout integer: xPos, inout integer: yPos, 311 in integer: zPos) is func 312 begin 313 repeat 314 xPos := rand(1, SIZE_LABY); 315 yPos := rand(1, SIZE_LABY); 316 until labyrinth[xPos][yPos][zPos].transfer = NOTRANSFER and 317 labyrinth[xPos][yPos][zPos].roomer = NOBODY and 318 labyrinth[xPos][yPos][zPos].contents = EMPTYROOM and 319 labyrinth[xPos][yPos][zPos].occurrence = NOOCCURRENCE and 320 labyrinth[xPos][yPos][zPos].objects = objectSet.value; 321 end func; # findEmptyRoom 322 323 324const proc: initRoom (inout roomType: aRoom, in integer: xPos, in integer: yPos, 325 in integer: zPos) is func 326 begin 327 aRoom := roomType.value; 328 aRoom.xPos := xPos; 329 aRoom.yPos := yPos; 330 aRoom.zPos := zPos; 331 end func; # initRoom 332 333 334const proc: initEntrance (inout roomType: aRoom) is func 335 begin 336 aRoom.connections := {NORTH, SOUTH, EAST, WEST}; 337 aRoom.contents := ENTRANCE; 338 aRoom.visited := TRUE; 339 end func; # initEntrance 340 341 342const proc: initRoomConnections is func 343 local 344 const array directSet: restrictedConnections is [] ( 345 { SOUTH, EAST, WEST}, 346 {NORTH, EAST, WEST}, 347 {NORTH, SOUTH, WEST}, 348 {NORTH, SOUTH, EAST }, 349 {NORTH, SOUTH }, 350 {NORTH, EAST }, 351 {NORTH, WEST}, 352 { SOUTH, EAST }, 353 { SOUTH, WEST}, 354 { EAST, WEST}); 355 var directSet: connections is directSet.value; 356 var integer: count is 0; 357 var integer: xPos is 0; 358 var integer: yPos is 0; 359 var integer: zPos is 0; 360 begin 361 for xPos range 1 to SIZE_LABY do 362 for yPos range 1 to SIZE_LABY do 363 for zPos range 1 to NUM_LEVELS do 364 initRoom(labyrinth[xPos][yPos][zPos], xPos, yPos, zPos); 365 end for; 366 write("."); 367 flush(OUT); 368 end for; 369 end for; 370 writeln; 371 for count range 1 to RESTRICTED_CONNECTION_COUNT do 372 for connections range restrictedConnections do 373 randomRoom(xPos, yPos, zPos); 374 labyrinth[xPos][yPos][zPos].connections := connections; 375 end for; 376 end for; 377 for zPos range 1 to NUM_LEVELS do 378 xPos := rand(1, SIZE_LABY); 379 yPos := rand(1, SIZE_LABY); 380 labyrinth[xPos][yPos][zPos].connections := {rand(NORTH, WEST)}; 381 end for; 382 initEntrance(labyrinth[rangeLaby(4)][1][1]); 383 for zPos range 1 to pred(NUM_LEVELS) do 384 for count range 1 to STAIRS_PER_LEVEL do 385 xPos := rand(1, SIZE_LABY); 386 yPos := rand(1, SIZE_LABY); 387 incl(labyrinth[xPos][yPos][zPos].connections, DOWN); 388 incl(labyrinth[xPos][yPos][succ(zPos)].connections, UP); 389 end for; 390 end for; 391 end func; # initRoomConnections 392 393 394const proc: initRoomProperties is func 395 local 396 var integer: count is 0; 397 var integer: xPos is 0; 398 var integer: yPos is 0; 399 var integer: zPos is 0; 400 var contentType: content is EMPTYROOM; 401 var animateType: animate is NOBODY; 402 var objectType: treasure is NOOBJECT; 403 var occurType: occurrence is NOOCCURRENCE; 404 begin 405 for zPos range 1 to NUM_LEVELS do 406 for count range 1 to THINGS_PER_LEVEL do 407 for content range [](CLOSEDCHEST, ORB, POOL, BOOK) do 408 findEmptyRoom(xPos, yPos, zPos); 409 labyrinth[xPos][yPos][zPos].contents := content; 410 end for; 411 end for; 412 end for; 413 for zPos range 1 to NUM_LEVELS do 414 for animate range KOBOLD to DRAGON do 415 findUninhabitedRoom(xPos, yPos, zPos); 416 labyrinth[xPos][yPos][zPos].roomer := animate; 417 end for; 418 for count range 1 to VENDORS_PER_LEVEL do 419 findUninhabitedRoom(xPos, yPos, zPos); 420 labyrinth[xPos][yPos][zPos].roomer := VENDOR; 421 end for; 422 end for; 423 for treasure range treasureSet do 424 randomRoom(xPos, yPos, zPos); 425 incl(labyrinth[xPos][yPos][zPos].objects, treasure); 426 objPlace[treasure] := labyrinth[xPos][yPos][zPos]; 427 end for; 428 for zPos range 1 to NUM_LEVELS do 429 for count range 1 to OCCURRENCES_PER_LEVEL do 430 for occurrence range FINDGOLD to FINDFLARES do 431 xPos := rand(1, SIZE_LABY); 432 yPos := rand(1, SIZE_LABY); 433 labyrinth[xPos][yPos][zPos].occurrence := occurrence; 434 end for; 435 end for; 436 end for; 437 for occurrence range LEECH to STEALTREASURE do 438 randomRoom(xPos, yPos, zPos); 439 labyrinth[xPos][yPos][zPos].occurrence := occurrence; 440 end for; 441 end func; # initRoomProperties 442 443 444const proc: initRoomTransfers is func 445 local 446 var integer: count is 0; 447 var integer: xPos is 0; 448 var integer: yPos is 0; 449 var integer: zPos is 0; 450 begin 451 zPos := rand(1, NUM_LEVELS); 452 findUninhabitedRoom(xPos, yPos, zPos); 453 labyrinth[xPos][yPos][zPos].roomer := rand(animateType); 454 incl(labyrinth[xPos][yPos][zPos].objects, RUNESTAFF); 455 objPlace[RUNESTAFF] := labyrinth[xPos][yPos][zPos]; 456 zPos := rand(1, NUM_LEVELS); 457 findEmptyRoom(xPos, yPos, zPos); 458 labyrinth[xPos][yPos][zPos].transfer := WARP; 459 labyrinth[xPos][yPos][zPos].objects := {ORBOFZOT}; 460 objPlace[ORBOFZOT] := labyrinth[xPos][yPos][zPos]; 461 for zPos range 1 to NUM_LEVELS do 462 for count range 1 to TRANSFERS_PER_LEVEL do 463 findEmptyRoom(xPos, yPos, zPos); 464 labyrinth[xPos][yPos][zPos].transfer := SINKHOLE; 465 findEmptyRoom(xPos, yPos, zPos); 466 labyrinth[xPos][yPos][zPos].transfer := WARP; 467 end for; 468 end for; 469 end func; # initRoomTransfers 470 471 472const func string: aOrAn (in string: word) is func 473 result 474 var string: wordWithIndefiniteArticle is ""; 475 begin 476 if word <> "" then 477 if upper(word[1]) in {'A', 'E', 'I', 'O', 'U'} then 478 wordWithIndefiniteArticle := "an " & word; 479 else 480 wordWithIndefiniteArticle := "a " & word; 481 end if; 482 end if; 483 end func; # aOrAn 484 485 486const proc: DECLARE_A_OR_AN (in type: aType) is func 487 begin 488 const func string: aOrAn (in aType: aValue) is 489 return aOrAn(str(aValue)); 490 end func; 491 492DECLARE_A_OR_AN(speciesType); 493DECLARE_A_OR_AN(weaponType); 494DECLARE_A_OR_AN(animateType); 495 496 497const func string: anyFood is 498 return rand([]("sandwiches", "stew", "soup", "burgers", "roast", 499 "filet", "tace", "pie")); 500 501 502const func string: anyAdjective is 503 return rand([]("a large", "a strange", "an ugly", "an enormous", 504 "a forbidding", "a horrible", "an exotic", 505 "an ordinary")); 506 507 508const func string: numberName (in integer: number) is 509 return number <= 20 ? str(ENGLISH, number) : str(number); 510 511 512const func string: sexName (in boolean: isMale) is 513 return isMale ? "male" : "female"; 514 515 516const func string: titleName (in boolean: isMale) is 517 return isMale ? "sir" : "madam"; 518 519 520const func integer: countOwnedObjects (in playerType: player) is 521 return card(player.possession); 522 523 524const func integer: countOwnedTreasures (in playerType: player) is 525 return card(player.possession & treasureSet); 526 527 528const func objectType: ownedTreasure (in playerType: player) is 529 return rand(player.possession & treasureSet); 530 531 532const func integer: treasureNumber (in objectType: treasure) is 533 return succ(ord(treasure) - ord(RUBY)); 534 535 536const proc: removeFromRoom (inout roomType: currentRoom, 537 in objectType: treasure) is func 538 begin 539 excl(currentRoom.objects, treasure); 540 end func; # removeFromRoom 541 542 543const proc: writePos (in roomType: aRoom) is func 544 begin 545 writeln("(" <& aRoom.xPos <& ", " <& aRoom.yPos <& ") Level: " <& aRoom.zPos); 546 end func; # writePos 547 548 549const proc: findGoldPieces (inout playerType: player, in integer: limit) is func 550 local 551 var integer: goldPieces is 0; 552 begin 553 goldPieces := rand(2, limit); 554 player.goldPieces +:= goldPieces; 555 writeln(numberName(goldPieces) <& " gold pieces!"); 556 writeln("You now have " <& numberName(player.goldPieces) <& " GP'S."); 557 end func; # findGoldPieces 558 559 560const proc: findFlares (inout playerType: player, in integer: limit) is func 561 local 562 var integer: flares is 0; 563 begin 564 flares := rand(2, limit); 565 player.flares +:= flares; 566 writeln(numberName(flares) <& " flares. You now have " <& 567 numberName(player.flares) <& " flares."); 568 end func; # findFlares 569 570 571const func string: roomAdjective (in integer: roomId) is 572 return [0]("", "luxurious ", "expensive ", "wonderful ", "good ", 573 "worn out ", "fine ", "moss-grown ", "old ", "figured ", 574 "patterned ")[roomId rem 11]; 575 576 577const func integer: roomIdInLevel (in roomType: aRoom) is 578 return 64 * pred(labyrinthNumber) + 8 * pred(aRoom.xPos) + pred(aRoom.yPos); 579 580 581const func integer: roomId (in roomType: aRoom) is 582 return 8 * roomIdInLevel(aRoom) + pred(aRoom.zPos); 583 584 585const proc: writeRoomDescription (in roomType: aRoom) is func 586 local 587 var integer: roomId is 0; 588 begin 589 if aRoom.contents = ENTRANCE then 590 writeln("the entrance hall. To the North the castle can be left."); 591 else 592 roomId := roomId(aRoom); 593 case roomId rem 23 of 594 when { 0}: write("a "); 595 when { 1}: write("a gigantic "); 596 when { 2}: write("a large "); 597 when { 3}: write("a long "); 598 when { 4}: write("a small "); 599 when { 5}: write("a narrow "); 600 when { 6}: write("a tiny "); 601 when { 7}: write("a round "); 602 when { 8}: write("an octagonal "); 603 when { 9}: write("a hexagonal "); 604 when {10}: write("a whitewashed "); 605 when {11}: write("a blue painted "); 606 when {12}: write("a black painted "); 607 when {13}: write("a red painted "); 608 when {14}: write("a green painted "); 609 when {15}: write("a brown painted "); 610 when {16}: write("a cold "); 611 when {17}: write("a windy "); 612 when {18}: write("a draughty "); 613 when {19}: write("an antique "); 614 when {20}: write("an old "); 615 when {21}: write("a dusty "); 616 when {22}: write("a dilapidated "); 617 end case; 618 case roomId rem 7 of 619 when {0}: write("dome "); 620 when {1}: write("hall "); 621 when {2}: write("room "); 622 when {3}: write("chamber "); 623 when {4}: write("corridor "); 624 when {5}: write("cavern "); 625 when {6}: write("tunnel "); 626 end case; 627 case roomId rem 17 of 628 when { 0}: write("with wooden planking."); 629 when { 1}: write("blasted out of the rock."); 630 when { 2}: write("that must have been a cellar."); 631 when { 3}: write("with all walls made out of bricks."); 632 when { 4}: write("that has a massive pillar in the centre."); 633 when { 5}: write("with an enormous chandelier hanging down."); 634 when { 6}: write("which has a lot of paintings on the walls."); 635 when { 7}: write("which is totally made from rustless steel."); 636 when { 8}: write("with lots of statues high above your head."); 637 when { 9}: write("with " <& aOrAn(roomAdjective(roomId)) <& "parquet."); 638 when {10}: write("with " <& aOrAn(roomAdjective(roomId)) <& 639 "stone-floor."); 640 when {11}: write("with " <& aOrAn(roomAdjective(roomId)) <& 641 "rug lying on the floor."); 642 when {12}: write("with " <& aOrAn(roomAdjective(roomId)) <& 643 "fresco at the wall."); 644 when {13}: write("with " <& roomAdjective(roomId) <& 645 "walls made from granite."); 646 when {14}: write("with " <& roomAdjective(roomId) <& 647 "panelling at the walls."); 648 when {15}: write("with " <& roomAdjective(roomId) <& 649 "paintings at the ceiling."); 650 when {16}: write("with a floor made out of " <& 651 roomAdjective(roomId) <& "marble."); 652 end case; 653 writeln; 654 end if; 655 end func; # writeRoomDescription 656 657 658const proc: writeConnections (in roomType: aRoom) is func 659 local 660 var integer: roomIdInLevel is 0; 661 var integer: numConnections is 0; 662 var directType: direction is NORTH; 663 begin 664 if UP in aRoom.connections or 665 DOWN in aRoom.connections then 666 roomIdInLevel := roomIdInLevel(aRoom); 667 case roomIdInLevel rem 9 of 668 when {0}: write("At one wall are steps "); 669 when {1}: write("Here is a shaky rope ladder "); 670 when {2}: write("Here is a forbidding staircase "); 671 when {3}: write("Here you find a steel-ladder "); 672 when {4}: write("Here you find a very old staircase "); 673 when {5}: write("There is a narrow spiral staircase "); 674 when {6}: write("There is a rotten ladder "); 675 when {7}: write("There you find a wooden staircase "); 676 when {8}: write("There you find stone steps "); 677 end case; 678 case roomIdInLevel rem 2 of 679 when {0}: write("going "); 680 when {1}: write("leading "); 681 end case; 682 if UP in aRoom.connections then 683 if DOWN in aRoom.connections then 684 write("up and down"); 685 else 686 write("up"); 687 end if; 688 else 689 write("down"); 690 end if; 691 case roomId(aRoom) rem 5 of 692 when {0}: writeln(" into deep darkness."); 693 when {1}: writeln(" into darkness."); 694 when {2}: writeln("ward into darkness."); 695 when {3}: writeln("ward."); 696 when {4}: writeln("."); 697 end case; 698 end if; 699 numConnections := card(aRoom.connections - {UP, DOWN}); 700 if numConnections = 1 or numConnections = 2 then 701 write("The room can " <& 702 card(aRoom.connections) = 1 ? "only " : "" <& 703 "be left to the "); 704 for direction range NORTH to WEST do 705 if direction in aRoom.connections then 706 write(direction); 707 decr(numConnections); 708 if numConnections = 1 then 709 write(" and "); 710 end if; 711 end if; 712 end for; 713 writeln("."); 714 elsif numConnections = 3 then 715 write("There is no way to the "); 716 for direction range NORTH to WEST do 717 if direction not in aRoom.connections then 718 write(direction); 719 end if; 720 end for; 721 writeln("."); 722 end if; 723 end func; # writeConnections 724 725 726const proc: writeThings (in roomType: aRoom) is func 727 begin 728 case aRoom.contents of 729 when {EMPTYCHEST}: writeln("Here is an empty chest."); 730 when {CHESTWITHSKELETON}: writeln("Here is an open chest with a skeleton in it."); 731 when {CLOSEDCHEST}: writeln("Here is a chest."); 732 when {ORB}: writeln("Here is a crystal orb."); 733 when {POOL}: writeln("Here is a pool."); 734 when {BOOK}: writeln("Here is a book."); 735 end case; 736 end func; # writeThings 737 738 739const proc: writeAnimates (in roomType: aRoom) is func 740 begin 741 if aRoom.roomer <> NOBODY then 742 writeln("In this room is " <& aOrAn(aRoom.roomer) <& "."); 743 end if; 744 end func; # writeAnimates 745 746 747const proc: writeObjects (in roomType: aRoom) is func 748 local 749 var integer: count is 0; 750 var integer: number is 0; 751 var objectType: obj is NOOBJECT; 752 begin 753 if aRoom.roomer = NOBODY then 754 count := card(aRoom.objects); 755 if count > 0 then 756 write("This room contains "); 757 for obj range aRoom.objects do 758 incr(number); 759 if number = 1 then 760 write("the "); 761 elsif number = count then 762 write(" and the "); 763 else 764 write(", the "); 765 end if; 766 write(obj); 767 end for; 768 writeln("."); 769 end if; 770 end if; 771 end func; # writeObjects 772 773 774const proc: writeRoomDetails (in roomType: currentRoom) is func 775 begin 776 writeConnections(currentRoom); 777 writeThings(currentRoom); 778 writeAnimates(currentRoom); 779 writeObjects(currentRoom); 780 end func; # writeRoomDetails 781 782 783const proc: look (inout roomType: currentRoom, in playerType: player) is func 784 begin 785 writeln; 786 write("You are in "); 787 if player.blind then 788 writeln("a room."); 789 else 790 writeRoomDescription(currentRoom); 791 end if; 792 writeRoomDetails(currentRoom); 793 end func; # look 794 795 796const func char: readChar is func 797 result 798 var char: ch is '\0;'; 799 local 800 var string: stri is ""; 801 begin 802 stri := upper(getln(IN)); 803 if stri <> "" then 804 ch := stri[1]; 805 end if; 806 end func; # readChar 807 808 809const func char: readChoice is func 810 result 811 var char: ch is ' '; 812 begin 813 writeln; 814 write("Your choice? "); 815 ch := readChar(); 816 end func; # readChoice 817 818 819const proc: readNumber (inout integer: number, inout boolean: okay, 820 inout boolean: quit) is func 821 local 822 var string: stri is ""; 823 begin 824 number := 0; 825 okay := TRUE; 826 stri := upper(getln(IN)); 827 if stri <> "" then 828 if stri = "Q" then 829 okay := FALSE; 830 quit := TRUE; 831 else 832 block 833 number := integer(stri); 834 exception 835 catch RANGE_ERROR: 836 okay := FALSE; 837 end block; 838 end if; 839 end if; 840 end func; # readNumber 841 842 843const proc: readSpecies (inout playerType: player) is func 844 local 845 var boolean: okay is TRUE; 846 begin 847 if not player.quitDialog then 848 repeat 849 okay := TRUE; 850 writeln; 851 writeln("You may be an elf, dwarf, man, or hobbit."); 852 case readChoice() of 853 when {'H'}: player.species := HOBBIT; 854 when {'E'}: player.species := ELF; 855 when {'M'}: player.species := HUMAN; 856 when {'D'}: player.species := DWARF; 857 when {'Q'}: player.quitDialog := TRUE; 858 otherwise: 859 okay := FALSE; 860 writeln; 861 writeln("** That was incorrect. Please type E, D, M, H or Q."); 862 end case; 863 until okay; 864 end if; 865 end func; # readSpecies 866 867 868const proc: readSex (inout playerType: player) is func 869 local 870 var boolean: okay is TRUE; 871 begin 872 if not player.quitDialog then 873 repeat 874 okay := TRUE; 875 writeln; 876 write("Which sex do you prefer? "); 877 case readChar() of 878 when {'M'}: player.isMale := TRUE; 879 when {'F'}: player.isMale := FALSE; 880 when {'Q'}: player.quitDialog := TRUE; 881 otherwise: 882 okay := FALSE; 883 writeln; 884 writeln("** Cute " <& player.species <& ", real cute. Try M, F or Q."); 885 end case; 886 until okay; 887 end if; 888 end func; # readSex 889 890 891const proc: riseAttribute (inout playerType: player, in string: attrName, 892 inout integer: attribute, inout integer: otherPoints) is func 893 local 894 var integer: points is 0; 895 var boolean: okay is TRUE; 896 begin 897 repeat 898 writeln; 899 write("How many points do you wish to add to your " <& attrName <& "? "); 900 readNumber(points, okay, player.quitDialog); 901 if not player.quitDialog then 902 if okay then 903 if points > otherPoints then 904 writeln; 905 writeln("** Dear " <& player.species <& ", you have only " <& 906 numberName(otherPoints) <& " point" <& 907 otherPoints <> 1 ? "s." : "."); 908 okay := FALSE; 909 end if; 910 else 911 writeln; 912 writeln("** Would you please be so kind to type a number or q, " <& 913 player.species <& "."); 914 end if; 915 end if; 916 until okay or player.quitDialog; 917 if okay then 918 attribute +:= points; 919 otherPoints -:= points; 920 end if; 921 end func; # riseAttribute 922 923 924const proc: readAttributes (inout playerType: player) is func 925 local 926 var integer: otherPoints is 0; 927 begin 928 if not player.quitDialog then 929 player.strength := 4 + 2 * ord(player.species); 930 player.intelligence := 8; 931 player.dexterity := 12 - 2 * ord(player.species); 932 if player.species = HOBBIT then 933 otherPoints := 4; 934 else 935 otherPoints := 8; 936 end if; 937 writeln; 938 writeln("Ok, " <& player.species <& ", you have the following attributes:"); 939 writeln("STRENGTH = " <& player.strength <& 940 " INTELLIGENCE = " <& player.intelligence <& 941 " DEXTERITY = " <& player.dexterity); 942 writeln("and " <& otherPoints <& " other points to allocate as you wish."); 943 riseAttribute(player, "strength", player.strength, otherPoints); 944 if not player.quitDialog and otherPoints > 0 then 945 riseAttribute(player, "intelligence", player.intelligence, otherPoints); 946 if not player.quitDialog and otherPoints > 0 then 947 riseAttribute(player, "dexterity", player.dexterity, otherPoints); 948 end if; 949 end if; 950 if not player.quitDialog and otherPoints > 0 then 951 writeln; 952 write("I am sure that you can never use the saved "); 953 if otherPoints = 1 then 954 writeln("point."); 955 else 956 writeln(numberName(otherPoints) <& " points."); 957 end if; 958 end if; 959 end if; 960 end func; # readAttributes 961 962 963const proc: buyAttribute (inout playerType: player, in string: attrName, 964 inout integer: attribute, in integer: price) is func 965 local 966 var char: ch is ' '; 967 var boolean: okay is TRUE; 968 begin 969 if not player.quitDialog and player.goldPieces >= price then 970 repeat 971 repeat 972 okay := TRUE; 973 writeln; 974 writeln("Your " <& attrName <& " is now " <& attribute <& 975 " and you have " <& player.goldPieces <& " GP'S."); 976 write("Do you want to buy a potion of " <& attrName <& 977 " for " <& price <& " GP'S? "); 978 ch := readChar(); 979 case ch of 980 when {'Y'}: 981 player.goldPieces -:= price; 982 attribute := range18(attribute + rand(1, 6)); 983 when {'N'}: noop; 984 when {'Q'}: 985 player.quitDialog := TRUE; 986 otherwise: 987 okay := FALSE; 988 writeln; 989 writeln("** Please answer Y, N or Q."); 990 end case; 991 until okay; 992 until ch <> 'Y' or player.goldPieces < price; 993 if ch <> 'Q' and player.goldPieces < price then 994 writeln; 995 writeln("Your " <& attrName <& " is now " <& attribute <& "."); 996 end if; 997 end if; 998 end func; # buyAttribute 999 1000 1001const proc: buyArmor (inout playerType: player, in integer: priceOfPlate, 1002 in integer: priceOfChainmail, in integer: priceOfLeather) is func 1003 local 1004 var char: ch is ' '; 1005 var boolean: okay is TRUE; 1006 begin 1007 if not player.quitDialog and player.goldPieces >= priceOfLeather then 1008 writeln; 1009 writeln("Ok, " <& player.species <& ", you have " <& player.goldPieces <& 1010 " gold pieces (GP'S) and " <& player.armor <& " armor."); 1011 repeat 1012 okay := TRUE; 1013 writeln("These are the types of armor you can buy:"); 1014 writeln; 1015 if player.goldPieces >= priceOfPlate then 1016 writeln(" P/LATE " <& priceOfPlate lpad 4 <& " GP'S"); 1017 end if; 1018 if player.goldPieces >= priceOfChainmail then 1019 writeln(" C/HAINMAIL " <& priceOfChainmail lpad 4 <& " GP'S"); 1020 end if; 1021 writeln(" L/EATHER " <& priceOfLeather lpad 4 <& " GP'S"); 1022 writeln(" N/OTHING 0 GP'S"); 1023 ch := readChoice(); 1024 if (ch <> 'P' or player.goldPieces < priceOfPlate) and 1025 (ch <> 'C' or player.goldPieces < priceOfChainmail) and 1026 ch not in {'L', 'N', 'Q'} then 1027 okay := FALSE; 1028 writeln; 1029 writeln("** Are you " <& aOrAn(player.species) <& " or " <& 1030 aOrAn(rand(animateType)) <& "?"); 1031 writeln; 1032 end if; 1033 until okay; 1034 case ch of 1035 when {'P'}: 1036 player.armor := PLATE; 1037 player.armorStrength := ord(player.armor) * ARMOR_STRENGTH_FACTOR; 1038 player.goldPieces -:= priceOfPlate; 1039 when {'C'}: 1040 player.armor := CHAINMAIL; 1041 player.armorStrength := ord(player.armor) * ARMOR_STRENGTH_FACTOR; 1042 player.goldPieces -:= priceOfChainmail; 1043 when {'L'}: 1044 player.armor := LEATHER; 1045 player.armorStrength := ord(player.armor) * ARMOR_STRENGTH_FACTOR; 1046 player.goldPieces -:= priceOfLeather; 1047 when {'N'}: noop; 1048 when {'Q'}: 1049 player.quitDialog := TRUE; 1050 end case; 1051 end if; 1052 end func; # buyArmor 1053 1054 1055const proc: buyWeapon (inout playerType: player, in integer: priceOfSword, 1056 in integer: priceOfMace, in integer: priceOfDagger) is func 1057 local 1058 var char: ch is ' '; 1059 var boolean: okay is TRUE; 1060 begin 1061 if not player.quitDialog and player.goldPieces >= priceOfDagger then 1062 writeln; 1063 write("Ok, "); 1064 if player.armor <> NOARMOR then 1065 write("bold "); 1066 end if; 1067 write(player.species <& ", you have " <& player.goldPieces <& 1068 " GP'S left and "); 1069 if player.weapon = NOWEAPON then 1070 writeln("no weapon."); 1071 else 1072 writeln(aOrAn(player.weapon) <& "."); 1073 end if; 1074 repeat 1075 okay := TRUE; 1076 writeln("These are the types of weapons you can buy:"); 1077 writeln; 1078 if player.goldPieces >= priceOfSword then 1079 writeln(" S/WORD " <& priceOfSword lpad 4 <& " GP'S"); 1080 end if; 1081 if player.goldPieces >= priceOfMace then 1082 writeln(" M/ACE " <& priceOfMace lpad 4 <& " GP'S"); 1083 end if; 1084 writeln(" D/AGGER " <& priceOfDagger lpad 4 <& " GP'S"); 1085 writeln(" N/OTHING 0 GP'S"); 1086 ch := readChoice(); 1087 if (ch <> 'S' or player.goldPieces < priceOfSword) and 1088 (ch <> 'M' or player.goldPieces < priceOfMace) and 1089 ch not in {'D', 'N', 'Q'} then 1090 okay := FALSE; 1091 writeln; 1092 writeln("** Is your intelligence really " <& 1093 numberName(player.intelligence) <& "?"); 1094 writeln; 1095 end if; 1096 until okay; 1097 case ch of 1098 when {'S'}: 1099 player.weapon := SWORD; 1100 player.goldPieces -:= priceOfSword; 1101 when {'M'}: 1102 player.weapon := MACE; 1103 player.goldPieces -:= priceOfMace; 1104 when {'D'}: 1105 player.weapon := DAGGER; 1106 player.goldPieces -:= priceOfDagger; 1107 when {'N'}: noop; 1108 when {'Q'}: 1109 player.quitDialog := TRUE; 1110 end case; 1111 end if; 1112 end func; # buyWeapon 1113 1114 1115const proc: buyLamp (inout playerType: player, in integer: price) is func 1116 local 1117 var boolean: okay is TRUE; 1118 begin 1119 if not player.quitDialog and LAMP not in player.possession and 1120 player.goldPieces >= price then 1121 repeat 1122 okay := TRUE; 1123 writeln; 1124 write("Do you want to buy a lamp for " <& price <& " GP'S? "); 1125 case readChar() of 1126 when {'Y'}: 1127 if price > 10 then 1128 writeln; 1129 writeln("It's guaranteed to outlive you."); 1130 end if; 1131 incl(player.possession, LAMP); 1132 player.goldPieces -:= price; 1133 when {'N'}: noop; 1134 when {'Q'}: 1135 player.quitDialog := TRUE; 1136 otherwise: 1137 okay := FALSE; 1138 writeln; 1139 writeln("** Please answer Y, N or Q."); 1140 end case; 1141 until okay; 1142 end if; 1143 end func; # buyLamp 1144 1145 1146const proc: buyFlares (inout playerType: player) is func 1147 local 1148 var integer: flares is 0; 1149 var boolean: okay is TRUE; 1150 begin 1151 if not player.quitDialog and player.goldPieces >= 1 then 1152 writeln; 1153 writeln("Ok, " <& player.species <& ", you have " <& player.goldPieces <& 1154 " GP'S left."); 1155 repeat 1156 writeln; 1157 write("Five flares cost 1 GP. How many do you want? "); 1158 readNumber(flares, okay, player.quitDialog); 1159 if not player.quitDialog then 1160 if okay then 1161 if flares > 5 * player.goldPieces then 1162 writeln; 1163 writeln("** You can afford only " <& 5 * player.goldPieces <& "."); 1164 okay := FALSE; 1165 end if; 1166 else 1167 writeln; 1168 writeln("** If you don't want any, just type 0 (zero)."); 1169 end if; 1170 end if; 1171 until okay or player.quitDialog; 1172 if okay then 1173 player.flares +:= flares; 1174 player.goldPieces -:= (flares + 4) div 5; 1175 end if; 1176 end if; 1177 end func; # buyFlares 1178 1179 1180const proc: buyTreasures (inout playerType: player) is func 1181 local 1182 var objectType: treasure is NOOBJECT; 1183 var integer: treasureNumber is 0; 1184 var integer: price is 0; 1185 var boolean: okay is TRUE; 1186 begin 1187 for treasure range treasureSet do 1188 if not player.quitDialog and treasure not in player.possession then 1189 treasureNumber := treasureNumber(treasure); 1190 price := 125 * treasureNumber + rand(1, 250) + 1191 250 * pred(rand(1, treasureNumber)); 1192 if price <= player.goldPieces then 1193 repeat 1194 okay := TRUE; 1195 writeln; 1196 write("Do you want to buy the " <& treasure <& 1197 " for " <& price <& " GP'S? "); 1198 case readChar() of 1199 when {'Y'}: 1200 removeFromRoom(objPlace[treasure], treasure); 1201 incl(player.possession, treasure); 1202 player.goldPieces -:= price; 1203 when {'N'}: noop; 1204 when {'Q'}: 1205 player.quitDialog := TRUE; 1206 otherwise: 1207 okay := FALSE; 1208 writeln; 1209 writeln("** Please answer Y, N or Q."); 1210 end case; 1211 until okay; 1212 end if; 1213 end if; 1214 end for; 1215 end func; # buyTreasures 1216 1217 1218const proc: buy (in roomType: currentRoom, inout playerType: player) is func 1219 begin 1220 if currentRoom.roomer <> VENDOR then 1221 writeln; 1222 writeln("** You can only buy from a vendor!"); 1223 elsif player.goldPieces < 100 then 1224 writeln; 1225 case rand(1, 14) of 1226 when { 1}: writeln("I do not play with funny money."); 1227 when { 2}: writeln("You need more gold pieces to trade."); 1228 when { 3}: writeln("You haven't got enough cash on hand."); 1229 when { 4}: writeln("Earn money and then come and try again."); 1230 when { 5}: writeln("You need hard currency to trade with me."); 1231 when { 6}: writeln("In capitalism real money is needed for trading."); 1232 when { 7}: writeln("Your dungeon express card - You left home without it."); 1233 when { 8}: writeln("I don't give alms, " <& player.species <& "."); 1234 when { 9}: writeln("You're too poor to trade, " <& player.species <& "."); 1235 when {10}: writeln("I don't trade with a beggar, " <& player.species <& "."); 1236 when {11}: writeln("Even " <& aOrAn(rand(animateType)) <& 1237 " knows that money is needed for trading."); 1238 when {12}: writeln("With " <& numberName(player.goldPieces) <& 1239 " GP'S no trade can be done."); 1240 when {13}: writeln("It's typical for " <& sexName(player.isMale) <& 1241 " " <& player.species <& 1242 "s, that they want to trade without enough money."); 1243 when {14}: writeln("Sorry " <& titleName(player.isMale) <& 1244 ", I'm afraid I don't give credit."); 1245 end case; 1246 else 1247 player.quitDialog := FALSE; 1248 buyArmor(player, 200, 150, 125); 1249 buyWeapon(player, 200, 150, 125); 1250 buyAttribute(player, "strength", player.strength, 100); 1251 buyAttribute(player, "intelligence", player.intelligence, 100); 1252 buyAttribute(player, "dexterity", player.dexterity, 100); 1253 buyLamp(player, 100); 1254 buyTreasures(player); 1255 end if; 1256 end func; # buy 1257 1258 1259const proc: sellTreasures (inout roomType: currentRoom, 1260 inout playerType: player) is func 1261 local 1262 var objectType: treasure is NOOBJECT; 1263 var integer: treasureNumber is 0; 1264 var integer: price is 0; 1265 var boolean: okay is TRUE; 1266 begin 1267 for treasure range treasureSet | {RUNESTAFF, ORBOFZOT} do 1268 if not player.quitDialog and treasure in player.possession then 1269 treasureNumber := treasureNumber(treasure); 1270 price := rand(1, 150) + 150 * pred(rand(1, treasureNumber)); 1271 repeat 1272 okay := TRUE; 1273 writeln; 1274 write("Do you want to sell the " <& treasure <& 1275 " for " <& price <& " GP'S? "); 1276 case readChar() of 1277 when {'Y'}: 1278 excl(player.possession, treasure); 1279 incl(currentRoom.objects, treasure); 1280 objPlace[treasure] := currentRoom; 1281 player.goldPieces +:= price; 1282 when {'N'}: noop; 1283 when {'Q'}: 1284 player.quitDialog := TRUE; 1285 otherwise: 1286 okay := FALSE; 1287 writeln; 1288 writeln("** Please answer Y, N or Q."); 1289 end case; 1290 until okay; 1291 end if; 1292 end for; 1293 end func; # sellTreasures 1294 1295 1296const proc: sell (inout roomType: currentRoom, inout playerType: player) is func 1297 begin 1298 if currentRoom.roomer <> VENDOR then 1299 writeln; 1300 writeln("** You can only sell to a vendor!"); 1301 elsif countOwnedTreasures(player) = 0 then 1302 writeln; 1303 writeln("** You have nothing to offer!"); 1304 else 1305 player.quitDialog := FALSE; 1306 sellTreasures(currentRoom, player); 1307 end if; 1308 end func; # sell 1309 1310 1311const proc: checkArmor (inout playerType: player, in integer: strike) is func 1312 local 1313 var integer: damage is 0; 1314 begin 1315 if player.armor = NOARMOR then 1316 damage := strike; 1317 else 1318 if strike < ord(player.armor) then 1319 damage := 0; 1320 player.armorStrength -:= strike; 1321 else 1322 damage := strike - ord(player.armor); 1323 player.armorStrength -:= ord(player.armor); 1324 end if; 1325 if player.armorStrength < 0 then 1326 player.armorStrength := 0; 1327 player.armor := NOARMOR; 1328 writeln; 1329 writeln("YOUR ARMOR HAS BEEN DESTROYED . . . GOOD LUCK!"); 1330 end if; 1331 end if; 1332 player.strength -:= damage; 1333 end func; # checkArmor 1334 1335 1336const proc: vendorDies (in roomType: currentRoom, 1337 inout playerType: player) is func 1338 local 1339 var objectType: treasure is NOOBJECT; 1340 begin 1341 writeln; 1342 writeln("You get all his wares:"); 1343 writeln(" plate armor"); 1344 player.armor := PLATE; 1345 player.armorStrength := ord(player.armor) * ARMOR_STRENGTH_FACTOR; 1346 writeln(" a sword"); 1347 player.weapon := SWORD; 1348 writeln(" a strength potion"); 1349 player.strength := range18(player.strength + rand(1, 6)); 1350 writeln(" an intelligence potion"); 1351 player.intelligence := range18(player.intelligence + rand(1, 6)); 1352 writeln(" a dexterity potion"); 1353 player.dexterity := range18(player.dexterity + rand(1, 6)); 1354 if LAMP not in player.possession then 1355 writeln(" a lamp"); 1356 incl(player.possession, LAMP); 1357 end if; 1358 for treasure range currentRoom.objects do 1359 writeln(" the " <& treasure); 1360 end for; 1361 end func; # vendorDies 1362 1363 1364const proc: monsterDies (inout roomType: currentRoom, inout playerType: player, 1365 inout fightStateType: fightState) is func 1366 local 1367 var animateType: monster is NOBODY; 1368 var objectType: treasure is NOOBJECT; 1369 begin 1370 monster := currentRoom.roomer; 1371 fightState.monsterPresent := FALSE; 1372 writeln; 1373 writeln("The " <& monster <& " lies dead at your feet!"); 1374 if monster in {WOLF, BEAR, CHIMERA, BALROG, DRAGON} and 1375 player.mealHour + 60 <= player.turns then 1376 writeln; 1377 writeln("You spend an hour eating " <& monster <& " " <& anyFood() <& "."); 1378 player.mealHour := player.turns; 1379 end if; 1380 if monster = VENDOR then 1381 vendorDies(currentRoom, player); 1382 else 1383 for treasure range currentRoom.objects do 1384 writeln("\a"); 1385 writeln("Great Zot! You've found the " <& treasure <& "!"); 1386 end for; 1387 decr(fightState.monsterCount); 1388 end if; 1389 player.possession |:= currentRoom.objects; 1390 currentRoom.objects := objectSet.value; 1391 writeln; 1392 write("You get his hoard of "); 1393 findGoldPieces(player, 99); 1394 currentRoom.roomer := NOBODY; 1395 end func; # monsterDies 1396 1397 1398const proc: monsterAttacks (in animateType: monster, inout playerType: player, 1399 inout fightStateType: fightState) is func 1400 begin 1401 if fightState.webCount > 0 then 1402 decr(fightState.webCount); 1403 if fightState.webCount = 0 then 1404 writeln; 1405 writeln("The web just broke!"); 1406 end if; 1407 end if; 1408 writeln; 1409 write("The " <& monster); 1410 if fightState.webCount > 0 then 1411 writeln(" is stuck and can't attack now!"); 1412 elsif player.dexterity >= rand(3, 21) + 3 * ord(player.blind) then 1413 writeln(" attacks! What luck, he missed you!"); 1414 else 1415 writeln(" attacks! Ouch! He hit you!"); 1416 checkArmor(player, fightState.aggressionOfMonster); 1417 player.living := player.strength >= 1; 1418 end if; 1419 end func; # monsterAttacks 1420 1421 1422const proc: attackMonster (inout roomType: currentRoom, inout playerType: player, 1423 inout fightStateType: fightState) is func 1424 local 1425 var animateType: monster is NOBODY; 1426 begin 1427 monster := currentRoom.roomer; 1428 if player.weapon = NOWEAPON then 1429 writeln; 1430 writeln("** Pounding on " <& aOrAn(monster) <& " won't hurt it!"); 1431 elsif player.weaponBlocked then 1432 writeln; 1433 writeln("** You can't beat it to death with a book!"); 1434 elsif player.dexterity < rand(1, 20) + (3 * ord(player.blind)) then 1435 writeln; 1436 writeln("You missed, too bad!"); 1437 else 1438 writeln; 1439 writeln("You hit the evil " <& monster <& "."); 1440 fightState.monsterStrength -:= ord(player.weapon); 1441 if monster in {GARGOYLE, DRAGON} then 1442 if rand(1, 8) = 1 then 1443 writeln; 1444 writeln("OH NO! Your " <& player.weapon <& " broke!"); 1445 player.weapon := NOWEAPON; 1446 end if; 1447 end if; 1448 if fightState.monsterStrength <= 0 then 1449 monsterDies(currentRoom, player, fightState); 1450 end if; 1451 end if; 1452 end func; # attackMonster 1453 1454 1455const proc: castSpell (inout roomType: currentRoom, inout playerType: player, 1456 inout fightStateType: fightState) is func 1457 local 1458 var integer: damage is 0; 1459 var char: ch is ' '; 1460 begin 1461 writeln; 1462 write("Which spell (web, fireball, deathspell)? "); 1463 ch := readChar(); 1464 writeln; 1465 if ch = 'W' then 1466 decr(player.strength); 1467 fightState.webCount := rand(2, 9); 1468 player.living := player.strength >= 1; 1469 elsif ch = 'F' then 1470 decr(player.strength); 1471 decr(player.intelligence); 1472 if player.intelligence < 1 or player.strength < 1 then 1473 player.living := FALSE; 1474 else 1475 damage := rand(2, 14); 1476 writeln; 1477 writeln("It does " <& damage <& " points worth of damage."); 1478 fightState.monsterStrength -:= damage; 1479 if fightState.monsterStrength <= 0 then 1480 monsterDies(currentRoom, player, fightState); 1481 end if; 1482 end if; 1483 elsif ch = 'D' then 1484 write("DEATH . . . "); 1485 if player.intelligence < rand(16, 19) then 1486 writeln("YOURS!"); 1487 player.intelligence := 0; 1488 player.living := FALSE; 1489 else 1490 writeln("HIS!"); 1491 fightState.monsterStrength := 0; 1492 monsterDies(currentRoom, player, fightState); 1493 end if; 1494 else 1495 writeln("** Try one of the options given."); 1496 end if; 1497 end func; # castSpell 1498 1499 1500const proc: bribeMonster (inout roomType: currentRoom, inout playerType: player, 1501 inout fightStateType: fightState) is func 1502 local 1503 var objectType: treasure is NOOBJECT; 1504 var char: ch is ' '; 1505 var boolean: okay is TRUE; 1506 begin 1507 fightState.bribed := FALSE; 1508 if countOwnedTreasures(player) = 0 then 1509 writeln; 1510 writeln("All I want is your life!"); 1511 else 1512 treasure := ownedTreasure(player); 1513 repeat 1514 okay := TRUE; 1515 writeln; 1516 write("I want the " <& treasure <& ". Will you give it to me? "); 1517 ch := readChar(); 1518 if not ch in {'Y', 'N', 'Q'} then 1519 okay := FALSE; 1520 writeln; 1521 writeln("** Please answer yes or no."); 1522 end if; 1523 until okay; 1524 if ch = 'Y' then 1525 excl(player.possession, treasure); 1526 incl(currentRoom.objects, treasure); 1527 objPlace[treasure] := currentRoom; 1528 writeln; 1529 writeln("Ok, just don't tell anyone else."); 1530 if currentRoom.roomer = VENDOR then 1531 fightState.monsterPresent := FALSE; 1532 fightState.angryVendors := FALSE; 1533 end if; 1534 fightState.bribed := TRUE; 1535 end if; 1536 end if; 1537 end func; # bribeMonster 1538 1539 1540const proc: meetMonster (in roomType: currentRoom, in playerType: player, 1541 inout fightStateType: fightState) is func 1542 local 1543 var animateType: monster is NOBODY; 1544 begin 1545 monster := currentRoom.roomer; 1546 fightState.monsterPresent := TRUE; 1547 fightState.bribed := FALSE; 1548 fightState.webCount := 0; 1549 fightState.aggressionOfMonster := 1 + ord(monster) div 2; 1550 fightState.monsterStrength := ord(monster) + 2; 1551 if monster = VENDOR and not fightState.angryVendors then 1552 writeln; 1553 writeln("You'll be sorry that you did that!"); 1554 fightState.angryVendors := TRUE; 1555 else 1556 writeln("You may attack or retreat."); 1557 if countOwnedTreasures(player) <> 0 then 1558 writeln("You can also attempt a bribe."); 1559 end if; 1560 if player.intelligence >= 15 then 1561 writeln("You can also cast a spell."); 1562 end if; 1563 end if; 1564 if (player.lethargic and RUBY not in player.possession) or 1565 player.blind or player.dexterity < rand(1, 18) then 1566 fightState.monsterWillAttack := TRUE; 1567 else 1568 fightState.monsterWillAttack := FALSE; 1569 end if; 1570 end func; # meetMonster 1571 1572 1573const proc: retreatFromMonster (in roomType: currentRoom, 1574 inout playerType: player, inout fightStateType: fightState) is func 1575 local 1576 var animateType: monster is NOBODY; 1577 begin 1578 if fightState.monsterPresent then 1579 if not fightState.bribed then 1580 monster := currentRoom.roomer; 1581 monsterAttacks(monster, player, fightState); 1582 if player.living then 1583 writeln; 1584 case rand(1, 7) of 1585 when {1}: writeln("You fake a blow and escape."); 1586 when {2}: writeln("You have escaped by turning and running."); 1587 when {3}: writeln("You jump to the left and escape to the right."); 1588 when {4}: writeln("What a furious trick. You escaped by doing nothing."); 1589 when {5}: writeln("The " <& monster <& " stumbled and you escaped."); 1590 when {6}: writeln("You escaped by jumping over the " <& monster <& "!"); 1591 when {7}: writeln("You are lucky, you have escaped because the " <& 1592 monster <& " was diverted by a cry."); 1593 end case; 1594 end if; 1595 end if; 1596 fightState.monsterPresent := FALSE; 1597 end if; 1598 end func; # retreatFromMonster 1599 1600 1601const proc: attack (inout roomType: currentRoom, inout playerType: player, 1602 inout fightStateType: fightState) is func 1603 begin 1604 if currentRoom.roomer = NOBODY then 1605 writeln; 1606 writeln("** There is nothing that can be attacked!"); 1607 else 1608 fightState.bribed := FALSE; 1609 if not fightState.monsterPresent then # attack VENDOR 1610 meetMonster(currentRoom, player, fightState); 1611 end if; 1612 attackMonster(currentRoom, player, fightState); 1613 fightState.monsterWillAttack := TRUE; 1614 end if; 1615 end func; # attack 1616 1617 1618const proc: cast (inout roomType: currentRoom, inout playerType: player, 1619 inout fightStateType: fightState) is func 1620 begin 1621 if currentRoom.roomer = NOBODY then 1622 writeln; 1623 writeln("** There is nothing that can be casted!"); 1624 elsif player.intelligence < 15 then 1625 writeln; 1626 writeln("** Your intelligence must be 15 or more to cast a spell!"); 1627 else 1628 fightState.bribed := FALSE; 1629 if not fightState.monsterPresent then # cast VENDOR 1630 meetMonster(currentRoom, player, fightState); 1631 end if; 1632 castSpell(currentRoom, player, fightState); 1633 fightState.monsterWillAttack := TRUE; 1634 end if; 1635 end func; # cast 1636 1637 1638const proc: bribe (inout roomType: currentRoom, inout playerType: player, 1639 inout fightStateType: fightState) is func 1640 begin 1641 if currentRoom.roomer = NOBODY then 1642 writeln; 1643 writeln("** There is nobody that can be bribed!"); 1644 elsif fightState.monsterPresent then 1645 if fightState.bribed then 1646 writeln; 1647 writeln("I will not give you more than your life."); 1648 else 1649 bribeMonster(currentRoom, player, fightState); 1650 end if; 1651 else 1652 writeln; 1653 writeln("** That does not work."); 1654 end if; 1655 end func; # bribe 1656 1657 1658const proc: meetVendor (inout roomType: currentRoom, in playerType: player, 1659 inout fightStateType: fightState) is func 1660 begin 1661 if fightState.angryVendors then 1662 meetMonster(currentRoom, player, fightState); 1663 else 1664 writeln("You may buy from, sell to, attack, or ignore the vendor."); 1665 end if; 1666 end func; # meetVendor 1667 1668 1669const proc: enterRoom (inout roomType: currentRoom, inout playerType: player, 1670 inout fightStateType: fightState) is func 1671 begin 1672 currentRoom.visited := TRUE; 1673 writeln; 1674 write("You are in "); 1675 if player.blind then 1676 writeln("a new room."); 1677 else 1678 writeRoomDescription(currentRoom); 1679 end if; 1680 case currentRoom.transfer of 1681 when {NOTRANSFER}: 1682 writeRoomDetails(currentRoom); 1683 if currentRoom.roomer = VENDOR then 1684 meetVendor(currentRoom, player, fightState); 1685 elsif currentRoom.roomer <> NOBODY then 1686 meetMonster(currentRoom, player, fightState); 1687 else 1688 if currentRoom.objects <> objectSet.value then 1689 writeln; 1690 if card(currentRoom.objects) = 1 then 1691 writeln("It's now yours!"); 1692 else 1693 writeln("They're yours now!"); 1694 end if; 1695 player.possession |:= currentRoom.objects; 1696 currentRoom.objects := objectSet.value; 1697 end if; 1698 end if; 1699 when {SINKHOLE}: 1700 case roomId(currentRoom) rem 5 of 1701 when {0}: writeln("Here you fall into a sinkhole."); 1702 when {1}: writeln("Here a trap-door opens under your feet and \ 1703 \you fall down."); 1704 when {2}: writeln("You have stepped into a pitfall."); 1705 when {3}: writeln("You step on an open trap-door and fall down."); 1706 when {4}: writeln("You fall into a hole hidden on the ground."); 1707 end case; 1708 currentRoomRef := labyrinth[currentRoom.xPos] 1709 [currentRoom.yPos] 1710 [rangeLevel(succ(currentRoom.zPos))]; 1711 enterRoom(currentRoomRef, player, fightState); 1712 when {WARP}: 1713 write("This room contains a warp. You have been transferred to "); 1714 currentRoomRef := labyrinth[rand(1, SIZE_LABY)] 1715 [rand(1, SIZE_LABY)] 1716 [rand(1, NUM_LEVELS)]; 1717 writePos(currentRoomRef); 1718 enterRoom(currentRoomRef, player, fightState); 1719 end case; 1720 end func; # enterRoom 1721 1722 1723const proc: readCoordinate (inout playerType: player, in char: coordname, 1724 inout integer: coordinate, in integer: coordinateMax) is func 1725 local 1726 var boolean: okay is TRUE; 1727 begin 1728 if not player.quitDialog then 1729 repeat 1730 writeln; 1731 write("Please enter the " <& coordname <& "-coordinate? "); 1732 readNumber(coordinate, okay, player.quitDialog); 1733 if okay then 1734 if coordinate < 1 or coordinate > coordinateMax then 1735 writeln; 1736 writeln("** Try a number from 1 to " <& coordinateMax <& "."); 1737 okay := FALSE; 1738 end if; 1739 elsif not player.quitDialog then 1740 writeln; 1741 writeln("** Would you please be so kind to type a digit, " <& 1742 player.species <& "."); 1743 end if; 1744 until okay or player.quitDialog; 1745 end if; 1746 end func; # readCoordinate 1747 1748 1749const proc: teleportTo (inout roomType: currentRoom, inout playerType: player, 1750 inout fightStateType: fightState) is func 1751 begin 1752 if ORBOFZOT in currentRoom.objects then 1753 excl(player.possession, RUNESTAFF); 1754 player.possession |:= currentRoom.objects; 1755 currentRoom.objects := objectSet.value; 1756 currentRoom.visited := TRUE; 1757 currentRoom.transfer := NOTRANSFER; 1758 enterRoom(currentRoom, player, fightState); 1759 writeln; 1760 writeln("Great unmitigated Zot!"); 1761 writeln; 1762 writeln("You just found the *ORB OF ZOT*!"); 1763 writeln; 1764 writeln("The Runestaff has disappeared!"); 1765 else 1766 enterRoom(currentRoom, player, fightState); 1767 end if; 1768 end func; # teleportTo 1769 1770 1771const proc: teleport (in roomType: currentRoom, inout playerType: player, 1772 inout fightStateType: fightState) is func 1773 local 1774 var integer: xPos is 0; 1775 var integer: yPos is 0; 1776 var integer: zPos is 0; 1777 begin 1778 if RUNESTAFF not in player.possession then 1779 writeln; 1780 writeln("** You can't teleport without the Runestaff!"); 1781 else 1782 player.quitDialog := FALSE; 1783 readCoordinate(player, 'x', xPos, SIZE_LABY); 1784 readCoordinate(player, 'y', yPos, SIZE_LABY); 1785 readCoordinate(player, 'z', zPos, NUM_LEVELS); 1786 if player.quitDialog then 1787 writeln; 1788 writeln("** The Runesaff needs three coordinates, " <& 1789 player.species <& "."); 1790 else 1791 fightState.monsterPresent := FALSE; 1792 currentRoomRef := labyrinth[xPos][yPos][zPos]; 1793 teleportTo(currentRoomRef, player, fightState); 1794 end if; 1795 end if; 1796 end func; # teleport 1797 1798 1799const proc: go (in roomType: currentRoom, inout playerType: player, 1800 inout fightStateType: fightState, in directType: direction) is func 1801 local 1802 const array [directType] integer: delta_x is [directType]( 0, 0, 1, -1, 0, 0); 1803 const array [directType] integer: delta_y is [directType](-1, 1, 0, 0, 0, 0); 1804 const array [directType] integer: delta_z is [directType]( 0, 0, 0, 0, -1, 1); 1805 begin 1806 if direction = NORTH and currentRoom.contents = ENTRANCE then 1807 writeln; 1808 write("Do you really want to leave the castle? "); 1809 if readChar() <> 'Y' then 1810 writeln; 1811 writeln("** Then don't say that you do!"); 1812 else 1813 retreatFromMonster(currentRoom, player, fightState); 1814 player.leaveCastle := TRUE; 1815 end if; 1816 elsif direction in currentRoom.connections then 1817 retreatFromMonster(currentRoom, player, fightState); 1818 if player.living then 1819 currentRoomRef := labyrinth 1820 [ rangeLaby(currentRoom.xPos + delta_x[direction])] 1821 [ rangeLaby(currentRoom.yPos + delta_y[direction])] 1822 [rangeLevel(currentRoom.zPos + delta_z[direction])]; 1823 enterRoom(currentRoomRef, player, fightState); 1824 end if; 1825 else 1826 writeln; 1827 writeln("** There is no way in this direction!"); 1828 end if; 1829 end func; # go 1830 1831 1832const proc: status (in roomType: currentRoom, in playerType: player) is func 1833 begin 1834 writeln; 1835 if not player.blind then 1836 write("You are at "); 1837 writePos(currentRoom); 1838 writeln; 1839 end if; 1840 writeln("STRENGTH = " <& player.strength <& 1841 " INTELLIGENCE = " <& player.intelligence <& 1842 " DEXTERITY = " <& player.dexterity); 1843 writeln("OBJECTS = " <& countOwnedObjects(player) <& 1844 " FLARES = " <& player.flares <& 1845 " GOLD PIECES = " <& player.goldPieces); 1846 writeln("weapon = " <& player.weapon <& " armor = " <& player.armor); 1847 end func; # status 1848 1849 1850const proc: listInventory (in playerType: player) is func 1851 local 1852 var boolean: anythinglisted is FALSE; 1853 var objectType: obj is NOOBJECT; 1854 begin 1855 if player.weapon <> NOWEAPON then 1856 anythinglisted := TRUE; 1857 writeln(" a " <& player.weapon); 1858 end if; 1859 if player.armor <> NOARMOR then 1860 anythinglisted := TRUE; 1861 writeln(" " <& player.armor <& " armor"); 1862 end if; 1863 if player.flares > 0 then 1864 anythinglisted := TRUE; 1865 writeln(" " <& numberName(player.flares) <& " flare" <& 1866 player.flares <> 1 ? "s" : ""); 1867 end if; 1868 if player.goldPieces > 0 then 1869 anythinglisted := TRUE; 1870 writeln(" " <& numberName(player.goldPieces) <& " gold piece" <& 1871 player.goldPieces <> 1 ? "s" : ""); 1872 end if; 1873 for obj range player.possession do 1874 anythinglisted := TRUE; 1875 writeln(" the " <& obj); 1876 end for; 1877 if not anythinglisted then 1878 writeln(" nothing"); 1879 end if; 1880 end func; # listInventory 1881 1882 1883const proc: inventory (in playerType: player) is func 1884 begin 1885 writeln; 1886 writeln("You have:"); 1887 listInventory(player); 1888 end func; # inventory 1889 1890 1891const proc: contentInfo (in roomType: currentRoom, in roomType: aRoom) is func 1892 begin 1893 write(aRoom.xPos = currentRoom.xPos and 1894 aRoom.yPos = currentRoom.yPos ? "<" : " "); 1895 if aRoom.visited then 1896 case aRoom.transfer of 1897 when {NOTRANSFER}: 1898 if aRoom.roomer = NOBODY then 1899 if aRoom.contents <> EMPTYROOM then 1900 case aRoom.contents of 1901 when {ENTRANCE}: write("E"); 1902 when {EMPTYCHEST}: write("."); 1903 when {CHESTWITHSKELETON}: write("."); 1904 when {CLOSEDCHEST}: write("C"); 1905 when {ORB}: write("O"); 1906 when {POOL}: write("P"); 1907 when {BOOK}: write("B"); 1908 end case; 1909 elsif aRoom.objects <> objectSet.value then 1910 write("T"); 1911 elsif UP in aRoom.connections then 1912 write("U"); 1913 elsif DOWN in aRoom.connections then 1914 write("D"); 1915 elsif aRoom.occurrence = FINDFLARES then 1916 write("F"); 1917 elsif aRoom.occurrence = FINDGOLD then 1918 write("G"); 1919 else 1920 write("."); 1921 end if; 1922 elsif aRoom.roomer = VENDOR then 1923 write("V"); 1924 else 1925 write("M"); 1926 end if; 1927 when {SINKHOLE}: write("S"); 1928 when {WARP}: write("W"); 1929 end case; 1930 else 1931 write(" "); 1932 end if; 1933 write(aRoom.xPos = currentRoom.xPos and 1934 aRoom.yPos = currentRoom.yPos ? "> " : " "); 1935 end func; # contentInfo 1936 1937 1938const proc: map (in roomType: currentRoom, in playerType: player) is func 1939 local 1940 var integer: xPos is 0; 1941 var integer: yPos is 0; 1942 var integer: zPos is 0; 1943 begin 1944 writeln; 1945 if player.blind then 1946 writeln("** You are blind, you dumb " <& player.species <& "!"); 1947 else 1948 zPos := currentRoom.zPos; 1949 for yPos range 1 to SIZE_LABY do 1950 for xPos range 1 to SIZE_LABY do 1951 contentInfo(currentRoom, labyrinth[xPos][yPos][zPos]); 1952 end for; 1953 writeln; 1954 writeln; 1955 end for; 1956 write("You are at "); 1957 writePos(currentRoom); 1958 end if; 1959 end func; # map 1960 1961 1962const proc: flare (inout roomType: currentRoom, inout playerType: player) is func 1963 local 1964 var integer: x is 0; 1965 var integer: y is 0; 1966 var integer: xPos is 0; 1967 var integer: yPos is 0; 1968 var integer: zPos is 0; 1969 begin 1970 writeln; 1971 if player.flares = 0 then 1972 writeln("** Hey, bright one, you're out of flares!"); 1973 elsif player.blind then 1974 writeln("** You can't see anything, you dumb " <& player.species <& "!"); 1975 else 1976 decr(player.flares); 1977 zPos := currentRoom.zPos; 1978 for y range pred(currentRoom.yPos) to succ(currentRoom.yPos) do 1979 yPos := rangeLaby(y); 1980 for x range pred(currentRoom.xPos) to succ(currentRoom.xPos) do 1981 xPos := rangeLaby(x); 1982 labyrinth[xPos][yPos][zPos].visited := TRUE; 1983 contentInfo(currentRoom, labyrinth[xPos][yPos][zPos]); 1984 end for; 1985 writeln; 1986 writeln; 1987 end for; 1988 write("You are at "); 1989 writePos(currentRoom); 1990 end if; 1991 end func; # flare 1992 1993 1994const proc: shineIntoRoom (inout roomType: aRoom) is func 1995 begin 1996 aRoom.visited := TRUE; 1997 writeln; 1998 write("The lamp shines into a room at "); 1999 writePos(aRoom); 2000 write("You see "); 2001 writeRoomDescription(aRoom); 2002 writeRoomDetails(aRoom); 2003 end func; # shineIntoRoom 2004 2005 2006const proc: lamp (in roomType: currentRoom, in playerType: player) is func 2007 local 2008 var integer: xPos is 0; 2009 var integer: yPos is 0; 2010 var integer: zPos is 0; 2011 var char: ch is ' '; 2012 begin 2013 writeln; 2014 if LAMP not in player.possession then 2015 writeln("** You don't have a lamp, " <& player.species <& "!"); 2016 elsif player.blind then 2017 writeln("** You are blind, you dumb " <& player.species <& "!"); 2018 else 2019 write("Where do you want to shine the lamp (N, S, E, W)? "); 2020 ch := readChar(); 2021 if not ch in {'N', 'S', 'E', 'W'} then 2022 writeln; 2023 writeln("** That's not a direction, " <& player.species <& "!"); 2024 else 2025 xPos := currentRoom.xPos; 2026 yPos := currentRoom.yPos; 2027 zPos := currentRoom.zPos; 2028 case ch of 2029 when {'N'}: yPos := rangeLaby(pred(yPos)); 2030 when {'S'}: yPos := rangeLaby(succ(yPos)); 2031 when {'W'}: xPos := rangeLaby(pred(xPos)); 2032 when {'E'}: xPos := rangeLaby(succ(xPos)); 2033 end case; 2034 shineIntoRoom(labyrinth[xPos][yPos][zPos]); 2035 end if; 2036 end if; 2037 end func; # lamp 2038 2039 2040const proc: drink (in roomType: currentRoom, inout playerType: player) is func 2041 local 2042 var speciesType: newSpecies is HUMAN; 2043 begin 2044 writeln; 2045 if currentRoom.contents <> POOL then 2046 writeln("** If you want a drink, find a pool!"); 2047 else 2048 write("You take a drink and "); 2049 case rand(1, 8) of 2050 2051 when {1}: 2052 player.strength := range18(player.strength + rand(1, 3)); 2053 writeln("feel stronger."); 2054 2055 when {2}: 2056 player.strength -:= rand(1, 3); 2057 writeln("feel weaker."); 2058 player.living := player.strength >= 1 ; 2059 2060 when {3}: 2061 player.intelligence := range18(player.intelligence + rand(1, 3)); 2062 writeln("feel smarter."); 2063 2064 when {4}: 2065 player.intelligence -:= rand(1, 3); 2066 writeln("feel dumber."); 2067 player.living := player.intelligence >= 1; 2068 2069 when {5}: 2070 player.dexterity := range18(player.dexterity + rand(1, 3)); 2071 writeln("feel nimbler."); 2072 2073 when {6}: 2074 player.dexterity -:= rand(1, 3); 2075 writeln("feel clumsier."); 2076 player.living := player.dexterity >= 1; 2077 2078 when {7}: 2079 newSpecies := rand(speciesType.first, pred(speciesType.last)); 2080 if newSpecies >= player.species then 2081 incr(newSpecies); 2082 end if; 2083 player.species := newSpecies; 2084 writeln("become " <& aOrAn(player.species) <& "."); 2085 2086 when {8}: 2087 player.isMale := not player.isMale; 2088 writeln("turn into a " <& sexName(player.isMale) <& 2089 " " <& player.species <& "."); 2090 end case; 2091 end if; 2092 end func; # drink 2093 2094 2095const proc: read (inout roomType: currentRoom, inout playerType: player) is func 2096 begin 2097 writeln; 2098 if currentRoom.contents <> BOOK then 2099 writeln("** There is nothing that can be read!"); 2100 elsif player.blind then 2101 writeln("** You are blind, you dumb " <& player.species <& "!"); 2102 else 2103 writeln("You open the book and"); 2104 case rand(1, 6) of 2105 2106 when {1}: 2107 writeln("Flash! Oh no! You are now a blind " <& player.species <& "!"); 2108 player.blind := TRUE; 2109 2110 when {2}: 2111 case rand(1, 4) of 2112 when {1}: writeln("It's another volume of Zot's poetry. - YECH!!"); 2113 when {2}: writeln("It's a manual of this game."); 2114 when {3}: writeln("It's a story about a dumb " <& player.species <& 2115 " who finds a book and then dies."); 2116 when {4}: writeln("It's volume number " <& 2117 numberName(rand(1, 20)) <& " of a novel."); 2118 end case; 2119 2120 when {3}: 2121 writeln("It's an old copy of play " <& rand(speciesType) <& "."); 2122 2123 when {4}: 2124 writeln("It's a manual of dexterity!"); 2125 player.dexterity := 18; 2126 2127 when {5}: 2128 writeln("It's a manual of strength!"); 2129 player.strength := 18; 2130 2131 when {6}: 2132 writeln("The book sticks to your hands -"); 2133 writeln("Now you are unable to draw your weapon!"); 2134 player.weaponBlocked := TRUE; 2135 end case; 2136 currentRoom.contents := EMPTYROOM; 2137 end if; 2138 end func; # read 2139 2140 2141const proc: viewRoomWithOrb (inout roomType: aRoom) is func 2142 begin 2143 aRoom.visited := TRUE; 2144 writeRoomDescription(aRoom); 2145 writeConnections(aRoom); 2146 write("You can also see that this room is at "); 2147 writePos(aRoom); 2148 writeAnimates(aRoom); 2149 writeObjects(aRoom); 2150 end func; # viewRoomWithOrb 2151 2152 2153const proc: gazeIntoOrb (inout playerType: player) is func 2154 begin 2155 write("You see "); 2156 case rand(1, 6) of 2157 2158 when {1}: 2159 case rand(1, 10) of 2160 when { 1}: writeln("your own burial!"); 2161 when { 2}: writeln("your mouldering dead body!"); 2162 when { 3}: writeln("yourself in a bloody heap!"); 2163 when { 4}: writeln("yourself with your skull bashed in!"); 2164 when { 5}: writeln("your broken skeleton lying on the ground!"); 2165 when { 6}: writeln("a graveyard and a tombstone with your name!"); 2166 when { 7}: writeln(aOrAn(rand(animateType)) <& " killing you!"); 2167 when { 8}: writeln(aOrAn(rand(speciesType)) <& 2168 " finding your faded bones!"); 2169 when { 9}: writeln(aOrAn(rand(speciesType)) <& " which tells " <& 2170 aOrAn(rand(speciesType)) <& " that you are dead!"); 2171 when {10}: writeln("a " <& sexName(not player.isMale) <& 2172 " " <& player.species <& 2173 " giving flowers on your grave!"); 2174 end case; 2175 decr(player.strength); 2176 write("This message makes you weaker. Your strength is now "); 2177 if player.strength < 1 then 2178 player.living := FALSE; 2179 writeln("zero!"); 2180 else 2181 writeln(numberName(player.strength) <& "."); 2182 end if; 2183 2184 when {2}: 2185 case rand(1, 4) of 2186 when {1}: writeln("yourself drinking from a pool and becoming " <& 2187 aOrAn(rand(animateType)) <& "!"); 2188 when {2}: writeln(aOrAn(rand(animateType)) <& 2189 " drinking from a pool and becoming " <& 2190 aOrAn(rand(speciesType)) <& "."); 2191 when {3}: writeln(aOrAn(rand(speciesType)) <& 2192 " drinking from a pool and becoming " <& 2193 anyAdjective() <& " spider."); 2194 when {4}: writeln("a young " <& rand(FALSE, TRUE) ? "man" : "woman" <& 2195 " drinking from a pool and becoming as old \ 2196 \as the hills."); 2197 end case; 2198 2199 when {3}: 2200 case rand(1, 2) of 2201 when {1}: writeln(aOrAn(rand(animateType)) <& 2202 " gazing back at you."); 2203 when {2}: writeln("that you are watched from " <& 2204 aOrAn(rand(speciesType)) <& "."); 2205 end case; 2206 2207 when {4}: 2208 viewRoomWithOrb(labyrinth[rand(1, SIZE_LABY)] 2209 [rand(1, SIZE_LABY)] 2210 [rand(1, NUM_LEVELS)]); 2211 2212 when {5}: 2213 write("the *ORB OF ZOT* at "); 2214 if rand(FALSE, TRUE) then 2215 writePos(objPlace[ORBOFZOT]); 2216 else 2217 writePos(labyrinth[rand(1, SIZE_LABY)] 2218 [rand(1, SIZE_LABY)] 2219 [rand(1, NUM_LEVELS)]); 2220 end if; 2221 2222 when {6}: 2223 case rand(1, 10) of 2224 when { 1}: writeln("a soap opera rerun."); 2225 when { 2}: writeln("a washing powder commercial."); 2226 when { 3}: writeln("an image to test the reception of the orb."); 2227 when { 4}: writeln("somebody sitting at a computer playing this game."); 2228 when { 5}: writeln("nothing because in the moment there are atmospherics."); 2229 when { 6}: writeln("a scientist demonstrating that an orb could never work."); 2230 when { 7}: writeln("the presentation of the new generation of orb's with sound."); 2231 when { 8}: writeln("that there is a 50% chance that what you see in an orb is correct."); 2232 when { 9}: writeln("yourself looking into an orb where you see yourself looking into ..."); 2233 when {10}: writeln(aOrAn(rand(speciesType)) <& 2234 " announcing todays program of the orb."); 2235 end case; 2236 end case; 2237 end func; # gazeIntoOrb 2238 2239 2240const proc: gaze (in roomType: currentRoom, inout playerType: player, 2241 inout fightStateType: fightState) is func 2242 begin 2243 writeln; 2244 if player.blind then 2245 writeln("** You can't see anything, you dumb " <& player.species <& "!"); 2246 elsif currentRoom.roomer = NOBODY then 2247 case currentRoom.contents of 2248 when {EMPTYROOM}: writeln("You are gazing at an empty wall."); 2249 when {ENTRANCE}: writeln("You are gazing at the exit."); 2250 when {EMPTYCHEST}: writeln("The chest does not fill with gazing at."); 2251 when {CHESTWITHSKELETON}: writeln("The skeleton looks horrible."); 2252 when {CLOSEDCHEST}: writeln("The chest does not open with gazing at."); 2253 when {POOL}: writeln("You see your ugly face mirror in the water."); 2254 when {BOOK}: writeln("You are gazing at the book."); 2255 when {ORB}: gazeIntoOrb(player); 2256 end case; 2257 elsif currentRoom.roomer = VENDOR then 2258 write("You are gazing at the Vendor. "); 2259 if player.isMale then 2260 writeln("But the Vendor does not like male " <& player.species <& "."); 2261 else 2262 writeln("The Vendor smiles and shows his wedding-ring."); 2263 end if; 2264 else 2265 write("The " <& currentRoom.roomer); 2266 if player.isMale then 2267 writeln(" is shocked by the scowl of a strong male " <& 2268 player.species <& "."); 2269 fightState.monsterWillAttack := FALSE; 2270 else 2271 writeln(" cannot be shocked by the scowl of a female " <& 2272 player.species <& "."); 2273 end if; 2274 end if; 2275 end func; # gaze 2276 2277 2278const proc: openChest (inout roomType: currentRoom, inout playerType: player, 2279 inout fightStateType: fightState) is func 2280 local 2281 var directType: direct is NORTH; 2282 begin 2283 if currentRoom.roomer <> NOBODY then 2284 writeln("The " <& currentRoom.roomer <& 2285 " does not allow to open the chest."); 2286 else 2287 write("You open the chest and "); 2288 case rand(1, 2) of 2289 2290 when {1}: 2291 write("find "); 2292 findGoldPieces(player, 99); 2293 currentRoom.contents := EMPTYCHEST; 2294 2295 when {2}: 2296 case rand(1, 7) of 2297 2298 when {1}: 2299 writeln("it is totally empty."); 2300 currentRoom.contents := EMPTYCHEST; 2301 2302 when {2}: 2303 writeln("it disappears in the moment you open it."); 2304 currentRoom.contents := EMPTYROOM; 2305 2306 when {3}: 2307 writeln("... KABOOOM! It explodes!!"); 2308 checkArmor(player, rand(1, 6)); 2309 player.living := player.strength >= 1; 2310 currentRoom.contents := EMPTYROOM; 2311 2312 when {4}: 2313 player.turns +:= 20; 2314 direct := rand(currentRoom.connections - {UP, DOWN}); 2315 writeln("... GAS!! You stagger from the room to the " <& 2316 direct <& "!"); 2317 currentRoom.contents := EMPTYCHEST; 2318 go(currentRoom, player, fightState, direct); 2319 2320 when {5}: 2321 writeln("find " <& anyAdjective() <& " skeleton."); 2322 writeln("It seems that this " <& rand(speciesType) <& 2323 " was also an adventurer."); 2324 currentRoom.contents := CHESTWITHSKELETON; 2325 2326 when {6}: 2327 write("find "); 2328 findFlares(player, 4); 2329 currentRoom.contents := EMPTYCHEST; 2330 2331 when {7}: 2332 if player.armor = NOARMOR then 2333 player.armor := LEATHER; 2334 end if; 2335 writeln("find a brand new " <& player.armor <& " armor."); 2336 player.armorStrength := ord(player.armor) * ARMOR_STRENGTH_FACTOR; 2337 currentRoom.contents := EMPTYCHEST; 2338 end case; 2339 end case; 2340 end if; 2341 end func; # openChest 2342 2343 2344const proc: open (inout roomType: currentRoom, inout playerType: player, 2345 inout fightStateType: fightState) is func 2346 begin 2347 writeln; 2348 if currentRoom.contents <> CLOSEDCHEST then 2349 writeln("** The only thing opened, was your big mouth!"); 2350 else 2351 openChest(currentRoom, player, fightState); 2352 end if; 2353 end func; # open 2354 2355 2356const proc: quit (inout playerType: player) is func 2357 begin 2358 writeln; 2359 write("Do you really want to quit now? "); 2360 if readChar() <> 'Y' then 2361 writeln; 2362 writeln("** Then don't say that you do!"); 2363 else 2364 player.quitProgram := TRUE; 2365 end if; 2366 end func; # quit 2367 2368 2369const proc: wait is func 2370 begin 2371 writeln; 2372 writeln("Waiting ..."); 2373 end func; # wait 2374 2375 2376const proc: illegal (in playerType: player) is func 2377 begin 2378 writeln; 2379 writeln("** Silly " <& player.species <& ", that wasn't a valid command!"); 2380 end func; # illegal 2381 2382 2383const func commandType: readCommand is func 2384 result 2385 var commandType: currentCommand is ILLEGAL; 2386 local 2387 var string: stri is ""; 2388 var char: ch1 is ' '; 2389 var char: ch2 is ' '; 2390 begin 2391 writeln; 2392 write(" -> "); 2393 stri := upper(getln(IN)); 2394 if stri = "" then 2395 currentCommand := WAIT; 2396 else 2397 ch1 := stri[1]; 2398 if length(stri) >= 2 then 2399 ch2 := stri[2]; 2400 end if; 2401 case ch1 of 2402 when {'A'}: currentCommand := ATTACK; 2403 when {'B'}: if ch2 = ' ' or ch2 = 'U' then 2404 currentCommand := BUY; 2405 elsif ch2 = 'R' then 2406 currentCommand := BRIBE; 2407 else 2408 currentCommand := ILLEGAL; 2409 end if; 2410 when {'C'}: currentCommand := CAST; 2411 when {'D'}: if ch2 = ' ' or ch2 = 'O' then 2412 currentCommand := GO_DOWN; 2413 elsif ch2 = 'R' then 2414 currentCommand := DRINK; 2415 else 2416 currentCommand := ILLEGAL; 2417 end if; 2418 when {'E'}: currentCommand := GO_EAST; 2419 when {'F'}: currentCommand := FLARE; 2420 when {'G'}: currentCommand := GAZE; 2421 when {'H'}: currentCommand := HELP; 2422 when {'I'}: currentCommand := INVENTORY; 2423 when {'L'}: if ch2 = ' ' or ch2 = 'O' then 2424 currentCommand := LOOK; 2425 elsif ch2 = 'A' then 2426 currentCommand := USE_LAMP; 2427 else 2428 currentCommand := ILLEGAL; 2429 end if; 2430 when {'M'}: currentCommand := MAP; 2431 when {'N'}: currentCommand := GO_NORTH; 2432 when {'O'}: currentCommand := OPEN; 2433 when {'Q'}: currentCommand := QUITCOMMAND; 2434 when {'R'}: currentCommand := READ; 2435 when {'S'}: if ch2 = ' ' or ch2 = 'O' then 2436 currentCommand := GO_SOUTH; 2437 elsif ch2 = 'T' then 2438 currentCommand := STATUS; 2439 elsif ch2 = 'E' then 2440 currentCommand := SELL; 2441 else 2442 currentCommand := ILLEGAL; 2443 end if; 2444 when {'T'}: currentCommand := TELEPORT; 2445 when {'U'}: currentCommand := GO_UP; 2446 when {'W'}: currentCommand := GO_WEST; 2447 otherwise: currentCommand := ILLEGAL; 2448 end case; 2449 end if; 2450 end func; # readCommand 2451 2452 2453const proc: executeCommand (inout roomType: currentRoom, 2454 inout playerType: player, inout fightStateType: fightState) is func 2455 begin 2456 case readCommand() of 2457 when {GO_NORTH}: go(currentRoom, player, fightState, NORTH); 2458 when {GO_SOUTH}: go(currentRoom, player, fightState, SOUTH); 2459 when {GO_EAST}: go(currentRoom, player, fightState, EAST); 2460 when {GO_WEST}: go(currentRoom, player, fightState, WEST); 2461 when {GO_UP}: go(currentRoom, player, fightState, UP); 2462 when {GO_DOWN}: go(currentRoom, player, fightState, DOWN); 2463 when {WAIT}: wait; 2464 when {INVENTORY}: inventory(player); 2465 when {HELP}: writeHelp; 2466 when {LOOK}: look(currentRoom, player); 2467 when {MAP}: map(currentRoom, player); 2468 when {FLARE}: flare(currentRoom, player); 2469 when {USE_LAMP}: lamp(currentRoom, player); 2470 when {ATTACK}: attack(currentRoom, player, fightState); 2471 when {CAST}: cast(currentRoom, player, fightState); 2472 when {BRIBE}: bribe(currentRoom, player, fightState); 2473 when {STATUS}: status(currentRoom, player); 2474 when {OPEN}: open(currentRoom, player, fightState); 2475 when {READ}: read(currentRoom, player); 2476 when {GAZE}: gaze(currentRoom, player, fightState); 2477 when {TELEPORT}: teleport(currentRoom, player, fightState); 2478 when {DRINK}: drink(currentRoom, player); 2479 when {SELL}: sell(currentRoom, player); 2480 when {BUY}: buy(currentRoom, player); 2481 when {QUITCOMMAND}: quit(player); 2482 otherwise: illegal(player); 2483 end case; 2484 end func; # executeCommand 2485 2486 2487const proc: writeFightState (in roomType: currentRoom, inout playerType: player, 2488 inout fightStateType: fightState) is func 2489 local 2490 var animateType: monster is NOBODY; 2491 begin 2492 if fightState.monsterPresent and not fightState.bribed and 2493 player.living and not player.quitProgram then 2494 monster := currentRoom.roomer; 2495 if fightState.monsterWillAttack then 2496 monsterAttacks(monster, player, fightState); 2497 end if; 2498 fightState.monsterWillAttack := TRUE; 2499 if player.living then 2500 writeln; 2501 writeln("You're facing " <& aOrAn(monster) <& "!"); 2502 writeln("Your strength is " <& player.strength <& 2503 " and your dexterity is " <& player.dexterity <& "."); 2504 end if; 2505 end if; 2506 end func; # writeFightState 2507 2508 2509const proc: incident (inout roomType: currentRoom, 2510 inout playerType: player) is func 2511 local 2512 var objectType: treasure is NOOBJECT; 2513 begin 2514 if PEARL not in player.possession then 2515 if currentRoom.occurrence = LEECH then 2516 writeln("You pocket has a leetch. Now you will lose gold pieces."); 2517 currentRoom.occurrence := NOOCCURRENCE; 2518 player.haveLeech := TRUE; 2519 end if; 2520 if player.haveLeech then 2521 player.goldPieces -:= rand(1, 3); 2522 if player.goldPieces < 0 then 2523 player.goldPieces := 0; 2524 end if; 2525 end if; 2526 end if; 2527 if RUBY not in player.possession then 2528 if currentRoom.occurrence = LETHARGY then 2529 writeln("You feel that you are lethargic now."); 2530 currentRoom.occurrence := NOOCCURRENCE; 2531 player.lethargic := TRUE; 2532 end if; 2533 if player.lethargic then 2534 incr(player.turns); 2535 end if; 2536 end if; 2537 if GREENGEM not in player.possession then 2538 if currentRoom.occurrence = FORGET then 2539 writeln("You see a lot of strange signs on the ground, possibly runes."); 2540 writeln("You try to read them, but you found no sense."); 2541 writeln("You feel that the runes force you to forget the map of the castle."); 2542 currentRoom.occurrence := NOOCCURRENCE; 2543 player.forgetting := TRUE; 2544 end if; 2545 if player.forgetting then 2546 labyrinth[rand(1, SIZE_LABY)] 2547 [rand(1, SIZE_LABY)] 2548 [rand(1, NUM_LEVELS)].visited := FALSE; 2549 end if; 2550 end if; 2551 if player.armor <> NOARMOR and currentRoom.occurrence = STEALARMOR then 2552 writeln("You are knocked down from behind and somebody steals your " <& 2553 player.armor <& " armor."); 2554 currentRoom.occurrence := NOOCCURRENCE; 2555 player.armor := NOARMOR; 2556 end if; 2557 if player.weapon <> NOWEAPON and currentRoom.occurrence = STEALWEAPON then 2558 writeln("You realize that somebody has stolen your " <& player.weapon <& "."); 2559 currentRoom.occurrence := NOOCCURRENCE; 2560 player.weapon := NOWEAPON; 2561 end if; 2562 if LAMP in player.possession and currentRoom.occurrence = STEALLAMP then 2563 writeln("You realize that somebody has stolen your lamp."); 2564 currentRoom.occurrence := NOOCCURRENCE; 2565 excl(player.possession, LAMP); 2566 end if; 2567 if player.flares <> 0 and currentRoom.occurrence = STEALFLARES then 2568 writeln("You realize that somebody has stolen all your flares."); 2569 currentRoom.occurrence := NOOCCURRENCE; 2570 player.flares := 0; 2571 end if; 2572 if currentRoom.occurrence = STEALTREASURE then 2573 if countOwnedTreasures(player) <> 0 then 2574 treasure := ownedTreasure(player); 2575 writeln("You realize that somebody has stolen the " <& treasure <& "."); 2576 currentRoom.occurrence := NOOCCURRENCE; 2577 excl(player.possession, treasure); 2578 end if; 2579 end if; 2580 if currentRoom.occurrence = FINDGOLD then 2581 if currentRoom.roomer = NOBODY then 2582 write("Here you find "); 2583 findGoldPieces(player, 10); 2584 else 2585 writeln("Here are " <& numberName(rand(2, 11)) <& 2586 " GP'S. But the " <& currentRoom.roomer <& 2587 " is faster and takes them."); 2588 end if; 2589 currentRoom.occurrence := NOOCCURRENCE; 2590 end if; 2591 if currentRoom.occurrence = FINDFLARES then 2592 if currentRoom.roomer = NOBODY then 2593 write("Here you find "); 2594 findFlares(player, 4); 2595 else 2596 writeln("Here are " <& numberName(rand(2, 5)) <& 2597 " flares. But the " <& currentRoom.roomer <& 2598 " is faster and takes them."); 2599 end if; 2600 currentRoom.occurrence := NOOCCURRENCE; 2601 end if; 2602 end func; # incident 2603 2604 2605const proc: curesAndDissolves (inout playerType: player) is func 2606 begin 2607 if player.blind and OPAL in player.possession then 2608 writeln; 2609 writeln("The opal Eye cures your blindness!"); 2610 player.blind := FALSE; 2611 end if; 2612 if player.weaponBlocked and BLUEFLAME in player.possession then 2613 writeln; 2614 writeln("The blue Flame dissolves the book!"); 2615 player.weaponBlocked := FALSE; 2616 end if; 2617 if player.haveLeech and PEARL in player.possession then 2618 writeln; 2619 writeln("The pale pearl fixes the leech in your pocket."); 2620 player.haveLeech := FALSE; 2621 end if; 2622 if player.lethargic and RUBY in player.possession then 2623 writeln; 2624 writeln("The ruby red stops your lethargy."); 2625 player.lethargic := FALSE; 2626 end if; 2627 if player.forgetting and GREENGEM in player.possession then 2628 writeln; 2629 writeln("The green Gem stops the forgetting of the map."); 2630 player.forgetting := FALSE; 2631 end if; 2632 end func; # curesAndDissolves 2633 2634 2635const proc: writeRemark (in playerType: player) is func 2636 local 2637 var integer: number is 0; 2638 begin 2639 if rand(1, 5) = 1 then 2640 if player.blind then 2641 number := rand(1, 4); 2642 else 2643 number := rand(1, 5); 2644 end if; 2645 case number of 2646 when {1}: 2647 case rand(1, 8) of 2648 when {1}: writeln("You sneezed."); 2649 when {2}: writeln("You stepped on a frog."); 2650 when {3}: writeln("You have a fit of dizziness."); 2651 when {4}: writeln("You moved your hand through a spiders net."); 2652 when {5}: writeln("There are indications that somebody must have \ 2653 \been here recently."); 2654 when {6}: writeln("A blast of wind blows a cloud of dust across \ 2655 \the room."); 2656 when {7}: writeln("You touch " <& anyAdjective() <& 2657 " insect that immediately flies away."); 2658 when {8}: 2659 writeln("The smell of " <& anyFood() <& " is in the air."); 2660 end case; 2661 when {2}: 2662 write("You smell "); 2663 case rand(1, 9) of 2664 when {1}: writeln("musty air."); 2665 when {2}: writeln("rotten flesh."); 2666 when {3}: writeln("a whiff of good french perfume."); 2667 when {4}: writeln("the bad odour of a mouldering body."); 2668 when {5}: writeln("the pleasant scent of a green meadow."); 2669 when {6}: writeln("the unpleasant stench of an acid."); 2670 when {7}: writeln("mouldering bones which must lie nearby."); 2671 when {8}: writeln(aOrAn(rand(animateType)) <& " frying."); 2672 when {9}: writeln("the presence of a " <& 2673 sexName(not player.isMale) <& " " <& 2674 player.species <& "."); 2675 end case; 2676 when {3}: 2677 write("You feel "); 2678 case rand(1, 10) of 2679 when { 1}: writeln("like you're being watched."); 2680 when { 2}: writeln("terribly frightened."); 2681 when { 3}: writeln("drops falling on your neck."); 2682 when { 4}: writeln("something touching your shoulder."); 2683 when { 5}: writeln("that you will be killed."); 2684 when { 6}: writeln("a cold wind blowing across the room."); 2685 when { 7}: writeln("that you get hungry."); 2686 when { 8}: writeln("vibrations at the ground."); 2687 when { 9}: writeln("danger in the vicinity."); 2688 when {10}: writeln("that a " <& sexName(not player.isMale) <& 2689 " " <& rand(speciesType) <& 2690 " must have been here recently."); 2691 end case; 2692 when {4}: 2693 write("You hear "); 2694 case rand(1, 11) of 2695 when { 1}: writeln("thunder."); 2696 when { 2}: writeln("moaning."); 2697 when { 3}: writeln("a scream."); 2698 when { 4}: writeln("a wumpus."); 2699 when { 5}: writeln("footsteps."); 2700 when { 6}: writeln("a door open."); 2701 when { 7}: writeln("a door slam."); 2702 when { 8}: writeln("rattling sounds."); 2703 when { 9}: writeln("somebody snigger."); 2704 when {10}: writeln("faint rustling noises."); 2705 when {11}: writeln("somebody whisper your name."); 2706 end case; 2707 when {5}: 2708 write("You see "); 2709 case rand(1, 8) of 2710 when {1}: writeln("a bat fly by."); 2711 when {2}: writeln("some flies."); 2712 when {3}: writeln("a shadow passing by."); 2713 when {4}: writeln("a rat crossing the room."); 2714 when {5}: writeln("two eyes glowing in the dark. \ 2715 \A moment later they disappear."); 2716 when {6}: writeln(anyAdjective() <& " footprint."); 2717 when {7}: writeln(anyAdjective() <& " spider running away."); 2718 when {8}: writeln("the mirage of the " <& 2719 rand(LAMP, ORBOFZOT) <& "."); 2720 end case; 2721 end case; 2722 end if; 2723 end func; # writeRemark 2724 2725 2726const proc: die (in playerType: player) is func 2727 begin 2728 writeln("\a"); 2729 writeln("*" mult 78); 2730 writeln("A noble effort, oh formerly living " <& player.species <& "!"); 2731 writeln; 2732 write("You died due to lack of "); 2733 if player.strength < 1 then 2734 writeln("strength."); 2735 elsif player.intelligence < 1 then 2736 writeln("intelligence."); 2737 elsif player.dexterity < 1 then 2738 writeln("dexterity."); 2739 end if; 2740 writeln; 2741 writeln("At the time you died, you had:"); 2742 listInventory(player); 2743 writeln; 2744 writeln("And it took you " <& player.turns <& " turns!"); 2745 end func; # die 2746 2747 2748const proc: exitCastle (inout playerType: player) is func 2749 begin 2750 writeln("\a"); 2751 write("You left the castle with"); 2752 if ORBOFZOT not in player.possession then 2753 write("out"); 2754 end if; 2755 writeln(" the *ORB OF ZOT*."); 2756 writeln; 2757 if ORBOFZOT in player.possession then 2758 writeln("An incredibly glorious victory!!"); 2759 writeln; 2760 writeln("In addition, you got out with the following:"); 2761 writeln(" your life"); 2762 excl(player.possession, ORBOFZOT); 2763 else 2764 writeln("A less than awe-inspiring defeat."); 2765 writeln; 2766 writeln("When you left the castle, you had:"); 2767 writeln(" your miserable life"); 2768 end if; 2769 listInventory(player); 2770 writeln; 2771 writeln("And it took you " <& player.turns <& " turns!"); 2772 end func; # exitCastle 2773 2774 2775const proc: main is func 2776 local 2777 var playerType: player is playerType.value; 2778 var fightStateType: fightState is fightStateType.value; 2779 var char: ch is ' '; 2780 begin 2781 OUT := STD_CONSOLE; 2782 IN := openEditLine(KEYBOARD, OUT); 2783 startText(); 2784 repeat 2785 initRoomConnections(); 2786 initRoomProperties(); 2787 initRoomTransfers(); 2788 labyrinthNumber := rand(1, 50); 2789 player := playerType.value; 2790 fightState := fightStateType.value; 2791 readSpecies(player); 2792 readSex(player); 2793 readAttributes(player); 2794 buyArmor(player, 7, 5, 3); 2795 buyWeapon(player, 7, 5, 3); 2796 buyLamp(player, 2); 2797 buyFlares(player); 2798 if not player.quitDialog then 2799 writeln; 2800 writeln("Ok, " <& player.species <& ", you are now entering the castle."); 2801 writeln("Type H for help."); 2802 currentRoomRef := labyrinth[rangeLaby(4)][1][1]; 2803 enterRoom(currentRoomRef, player, fightState); 2804 repeat 2805 incr(player.turns); 2806 incident(currentRoomRef, player); 2807 curesAndDissolves(player); 2808 writeRemark(player); 2809 executeCommand(currentRoomRef, player, fightState); 2810 writeFightState(currentRoomRef, player, fightState); 2811 until not player.living or player.leaveCastle or player.quitProgram; 2812 if not player.living then 2813 die(player); 2814 elsif player.leaveCastle then 2815 exitCastle(player); 2816 end if; 2817 end if; 2818 repeat 2819 writeln; 2820 write("Are you foolish enough to want to play again? "); 2821 ch := readChar(); 2822 if not ch in {'Y', 'N'} then 2823 writeln; 2824 writeln("** Please answer yes or no."); 2825 end if; 2826 until ch in {'Y', 'N'}; 2827 writeln; 2828 if ch = 'Y' then 2829 writeln("Some " <& player.species <& "s never learn!"); 2830 else 2831 writeln("Maybe dumb " <& player.species <& " is not so dumb after all!"); 2832 end if; 2833 until ch = 'N'; 2834 end func; # main 2835