1// TADS3 Example File 2// Source: https://www.tads.org/t3doc/doc/t3QuickStart.htm 3 4#charset "us-ascii" 5#include <adv3.h> 6#include <en_us.h> 7 8versionInfo: GameID 9 IFID = '558c20af-6559-477a-9f98-b7b4274cd304' 10 name = 'The Best Burglar' 11 byline = 'by Eric Eve' 12 htmlByline = 'by <a href="mailto:eric.eve@hmc.ox.ac.uk"> 13 Eric Eve</a>' 14 version = '3' 15 authorEmail = 'Eric Eve <eric.eve@hmc.ox.ac.uk>' 16 desc = 'You are the world\'s best burglar faced with the greatest challenge 17 of your felonious career.' 18 htmlDesc = 'You are the world\'s best burglar faced with the greatest 19 challenge of your felonious career.' 20; 21 22gameMain: GameMainDef 23 /* the initial player character is 'me' */ 24 initialPlayerChar = me 25 26 showIntro() 27 { 28 "<b>The Best Burglar</b>\nWell, you've got this far. Now it's just a 29 quick nip inside the house and out again carrying the Orb of Ultimate 30 Satisfaction, an object that no burglar has ever managed to steal 31 before. If you can pull it off you're sure to win the Burglar of the 32 Year Award, putting you at the pinnacle of your profession.\b"; 33 } 34 35 showGoodbye() 36 { 37 "Thanks for playing! "; 38 } 39; 40 41startRoom: OutdoorRoom 'Driveway' 42 "The large red-brick Tudor house stands immediately to the north of this end 43 of the driveway, while the drive back to the road where you left your 44 getaway vehicle runs off though a belt of trees to the southwest." 45 46 roomFirstDesc = "Here you are in the drive of Number 305 Erehwon Avenue, 47 with the great house you've come to burgle standing just before you to 48 the north. The drive back to the road where you left your getaway 49 vehicle runs off though a belt of trees to the southwest." 50 51 north = frontDoor 52 in asExit(north) 53 southwest = drive 54; 55 56+ me: Actor 57 pcDesc = "You're Alexis Lightfinger, burglar extraordinaire, the most 58 professional thief in the known universe; but you're on a job now, so 59 you don't have time for the narcissistic indulgence of admiring your own 60 appearance. You're far too professional not to have come fully prepared, 61 so there's no practical need to look yourself over again. " 62; 63 64++ Container 'large white swag bag*bags' 'swag bag' 65 "It's a large white bag with <q>SWAG</q> printed on it in very large 66 letters. Everyone knows that no real burglar would ever carry such a thing, 67 so by carrying it you know no one will take you for a real burglar. Cunning, 68 eh? " 69; 70 71+ frontDoor: LockableWithKey, Door 'solid oak front door*doors' 'front door' 72 "The lintel above the front door is carved with the date 1589, presumably 73 the date the house was built. The door itself is made of solid oak. " 74 keyList = [brassKey] 75 76 makeOpen(stat) 77 { 78 inherited(stat); 79 if(stat) 80 achievement.awardPointsOnce(); 81 } 82 83 achievement: Achievement { +10 "opening the front door" } 84 85; 86 87+ flowerPot: ComplexContainer 'terracotta small flower flowerpot/pot*pots' 88 'flower pot' 89 "It's a perfectly ordinary small terracota pot, though it looks like no 90 one's got round to putting a plant in it yet. " 91 subContainer: ComplexComponent, Container { bulkCapacity = 3} 92 subUnderside: ComplexComponent, Underside { } 93 94 initSpecialDesc = "A small flower pot rests on the ground not far from the 95 front door. " 96 97 bulk = 3 98 bulkCapacity = 3 99; 100 101++ brassKey: Hidden, Key 'small brass key*keys' 'small brass key' 102 "It's an ordinary enough small brass key. " 103 subLocation = &subUnderside 104; 105 106+ Enterable -> frontDoor 'large red red-brick tudor house/mansion/front 107 *houses*buildings' 'house' 108 "It's a large red-brick Tudor house with mullioned windows, climbing 109 creepers and the date 1589 carved over the door. " 110; 111 112++ Component '(door) carved lintel' 'lintel' 113 "Its most noteworthy feature is the date 1589 carved into it. " 114; 115 116+ Decoration 'mullioned windows' 'windows' 117 "They're architecturally attractive, no doubt, but not especially helpful to 118 burglars. " 119 120 notImportantMsg = 'It\'s a matter of professional pride with you never to 121 mess with windows. ' 122 isPlural = true 123; 124 125+ Decoration 'green climbing ivy/creepers/creeper' 'creepers' 126 "The front of the house is festooned with green creepers -- ivy, perhaps, 127 but botany was never your strong point since in the main plants aren't 128 worth burgling. " 129 130 notImportantMsg = 'The creepers can\'t help you burgle the house -- they\'re 131 certainly not strong enough to climb and they\'re certainly not worth 132 stealing -- so you may as well leave them alone. ' 133 isPlural = true 134; 135 136+ drive: PathPassage 'drive/path/avenue' 'drive' 137 "The drive leading back to the road runs off through a belt of trees to the 138 southwest. " 139 140 dobjFor(TravelVia) 141 { 142 action() 143 { 144 "You retrace your steps back to the road, where your trusty unmarked 145 burglarmobile is still parked, ready for your quick getaway. "; 146 147 if(orb.isIn(me)) 148 { 149 "Congratulations! You have got away with the Orb of Ultimate 150 Satisfaction, a feat never before performed. As you slip the orb 151 onto the back seat of your car and climb into the driver's seat 152 you tell yourself that you're now absolutely certain to win 153 the Burglar of the Year Award!\b"; 154 155 achievement.awardPointsOnce(); 156 157 finishGameMsg(ftVictory, [finishOptionUndo, 158 finishOptionFullScore]); 159 } 160 else 161 { 162 "It's a shame you didn't manage to steal the orb, though. 163 Without it you'll never win the Burglar of the Year Award 164 now.\b"; 165 166 finishGameMsg(ftFailure, [finishOptionUndo]); 167 } 168 } 169 } 170 171 okayRubMsg = 'What -- all of it? That may take a while! ' 172 achievement: Achievement { +10 "getting away with the orb" } 173; 174 175+ Decoration 'belt/trees' 'trees' 176 "The trees are in full leaf, which is good, because they hide what you're 177 doing from the road. " 178 179 notImportantMsg = 'The trees are doing a good job of hiding you from the 180 road, so you may as well leave them alone. It\'s not as if they\'re 181 something you could steal, after all. ' 182; 183 184hallway: Room 'Hallway' 185 "This hall is or grand proportions but pretty bare. The front door lies to 186 the south and other exits lead east, north and west. " 187 188 south = hallDoor 189 out asExit(south) 190 west = study 191 north: FakeConnector { "You're pretty sure that only leads to the kitchen, 192 and you haven't come here to cook a meal. " } 193 194 east: DeadEndConnector { 'the living room' "You <<one of>>walk through the 195 doorway and find yourself in<<or>>return to<<stopping>> the living room 196 where you take <<one of>> a <<or>>another<<stopping>> quick look around, 197 but <<one of>><<or>> once again<<stopping>> failing to find anything of 198 interest you quickly return to the hall. "} 199; 200 201+ hallDoor: Lockable, Door -> frontDoor 'front door*doors' 'front door' 202; 203 204+ table:Surface 'small wooden mahogany side table/legs*tables' 'small table' 205 "It's a small mahogany table standing on four thin legs. " 206 initSpecialDesc = "A small table rests by the east wall. " 207 bulk = 5 208 209 dobjFor(Take) 210 { 211 check() 212 { 213 if(contents.length > 0) 214 failCheck('It\'s probably not a very good idea to try picking 215 up the table while <<contents[1].nameIs>> still on it. '); 216 } 217 } 218; 219 220++ vase: Container 'cheap china floral vase/pattern' 'vase' 221 "It's only a cheap thing, made of china but painted in a tasteless floral 222 pattern using far too many primary colours. " 223 224 bulk = 3 225 bulkCapacity = 3 226; 227 228+++ silverKey: Hidden, Key 'small silver key*keys' 'small silver key' 229; 230 231study: Room 'Study' 232 "This study is much as you would expect: somewhat spartan. A desk stands in 233 the middle of the room with a chair placed just behind it. A <<if 234 picture.moved>>safe is built into <<else>> rather bland painting hangs on 235 <<end>> the west wall. The way out is to the east. " 236 east = hallway 237 out asExit(east) 238; 239 240+ desk: Heavy, Platform 'plain wooden desk' 'desk' 241 "It's a plain wooden desk with a single drawer. " 242 dobjFor(Open) remapTo(Open, drawer) 243 dobjFor(Close) remapTo(Close, drawer) 244 dobjFor(LookIn) remapTo(LookIn, drawer) 245 dobjFor(UnlockWith) remapTo(UnlockWith, drawer, IndirectObject) 246 dobjFor(LockWith) remapTo(LockWith, drawer, IndirectObject) 247 dobjFor(Lock) remapTo(Lock, drawer) 248 dobjFor(Unlock) remapTo(Unlock, drawer) 249; 250 251++ drawer: KeyedContainer, Component '(desk) drawer*drawers' 'drawer' 252 "It's an ordinary desk drawer with a small silver lock. " 253 keyList = [silverKey] 254; 255 256+++ notebook: Readable 'small bright red notebook/book/cover/pages' 257 'small red notebook' 258 "It's a small notebook with a bright red cover. " 259 260 readDesc = "You open the notebook and flick through its pages. The only 261 thing you find of any interest is a page with <q>SAFE DATE</q> scrawled 262 across it. After satisfying yourself that the notebook contains nothing 263 else of any potential relevance you snap it shut again. <.reveal 264 safe-date>" 265 266 dobjFor(Open) asDobjFor(Read) 267 dobjFor(LookIn) asDobjFor(Read) 268 269 dobjFor(Read) 270 { 271 action() 272 { 273 inherited; 274 achievement.awardPointsOnce(); 275 } 276 } 277 278 cannotCloseMsg = 'It\'s already closed. ' 279 achievement: Achievement { +5 "reading the notebook" } 280; 281 282+ CustomImmovable, Chair 'red office swivel chair' 'chair' 283 "It's a typical office swivel chair, covered in red fabric. " 284 285 cannotTakeMsg = 'You see no reason to burden yourself with such a useless 286 object; that would be quite unprofessional. ' 287 288; 289 290+ picture: RoomPartItem, Thing 'rather bland picture/painting/landscape' 291 'picture' 292 "It's a landscape, pleasantly executed enough, but of no great distinction 293 and definitely not worth the bother of stealing. " 294 295 initNominalRoomPartLocation = defaultWestWall 296 initSpecialDesc = "A rather bland painting hangs on the west wall. " 297 isListed = (moved) 298 299 bulk = 8 300 301 dobjFor(LookBehind) 302 { 303 action() 304 { 305 if(moved) 306 inherited; 307 else 308 { 309 safe.discover(); 310 "Behind the picture is a safe built into the wall. "; 311 } 312 } 313 } 314 315 moveInto(newDest) 316 { 317 if(!safe.discovered) 318 { 319 "Removing the painting from the wall reveals a safe behind. "; 320 safe.discover(); 321 } 322 inherited(newDest); 323 } 324; 325 326+ safe: RoomPartItem, Hidden, CustomFixture, ComplexContainer 327 'sturdy steel safe' 'safe' 328 "It's a sturdy steel safe with a single dial on its door. " 329 330 subContainer: ComplexComponent, IndirectLockable, OpenableContainer 331 { 332 bulkCapacity = 5 333 makeOpen(stat) 334 { 335 inherited(stat); 336 if(stat) 337 achievement.awardPointsOnce(); 338 } 339 340 achievement: Achievement { +10 "opening the safe" } 341 } 342 343 specialDesc = "A safe is built into the west wall. " 344 specialNominalRoomPartLocation = defaultWestWall 345 cannotTakeMsg = 'It's firmly built into the wall; you can't budge it. ' 346 347 discover() 348 { 349 if(!discovered) 350 { 351 foreach(local cur in allContents) 352 cur.discover(); 353 354 achievement.awardPointsOnce(); 355 } 356 inherited(); 357 } 358 359 achievement: Achievement { +5 "finding the safe" } 360; 361 362++ safeDoor: Hidden, ContainerDoor '(safe) door' 'safe door' 363 "It has a circular dial attached to its centre. " 364; 365 366+++ safeDial: Hidden, Component, NumberedDial 'circular dial*dials' 'dial' 367 "The dial can be turned to any number between <<minSetting>> and 368 <<maxSetting>>. It's currently at <<curSetting>>. " 369 370 minSetting = 0 371 maxSetting = 99 372 curSetting = '35' 373 374 num1 = 0 375 num2 = 0 376 correctCombination = 1589 377 378 makeSetting(val) 379 { 380 inherited(val); 381 num2 = num1; 382 num1 = toInteger(val); 383 if(100 * num2 + num1 == correctCombination) 384 { 385 "You hear a slight <i>click</i> come from the safe door. "; 386 safe.makeLocked(nil); 387 } 388 else if(!safe.isOpen) 389 safe.makeLocked(true); 390 } 391; 392 393++ orb: Thing 'ultimate battered dull metal orb/sphere/ball/satisfaction' 394 'Orb of Ultimate Satisfaction' 395 "It doesn't look much be honest, just a battered sphere made of some dull 396 metal, but you've been told it's the most valuable and desirable object 397 in the known universe! " 398 399 aName = (theName) 400 401 subLocation = &subContainer 402 403 okayRubMsg = 'As {you/he} rub{s} {the dobj/him} a shimmering djiin suddenly 404 appears in the air before you!\b 405 <q>Hello, you have reached the automated holographic answering service 406 of Jeannie the Genie,</q> she announces. <q>I\'m sorry I\'m not 407 available to respond to your rub in person right now, but my hours of 408 activity have been heavily curtailed by the European Working Time 409 Directive. Before making a wish, please make sure that you have 410 conducted a full risk assessment in line with the latest Health and 411 Safety Guidelines. Also, please note that before any wish can be granted 412 you must sign a Form P45/PDQ/LOL indemnifying this wish-granting agency 413 against any consequential loss or damage arising from the fulfilment of 414 your desires. Thank you for rubbing. Have a nice day!</q>\b 415 Her message complete, the holographic djiin fades away into 416 non-existence. ' 417 418 moveInto(dest) 419 { 420 inherited(dest); 421 if(dest.isOrIsIn(me)) 422 achievement.awardPointsOnce(); 423 } 424 425 achievement: Achievement { +10 "taking the orb" } 426; 427 428//------------------------------------------------------------------------------ 429 430/* DEFINE A NEW VERB */ 431 432DefineTAction(Rub) 433; 434 435VerbRule(Rub) 436 'rub' dobjList 437 : RubAction 438 verbPhrase = 'rub/rubbing (what)' 439; 440 441/* When creating a new verb, you'll want to modify the Thing class so as to provide 442 default handling for the command. The defaults specified here will be used except 443 on objects for which you define explicit handling of the command. */ 444 445modify Thing 446 dobjFor(Rub) 447 { 448 preCond = [touchObj] 449 action() { mainReport(okayRubMsg); } 450 } 451 452 okayRubMsg = '{You/he} rub{s} {the dobj/him} but not much happens as a 453 result. ' 454 455 shouldNotBreakMsg = 'Only amateurs go round breaking things unnecessarily. ' 456; 457 458//------------------------------------------------------------------------------ 459 460/* HINTS */ 461 462TopHintMenu; 463 464+ Goal -> (frontDoor.achievement) 465 'How do I get into the house?' 466 [ 467 'Well, the windows don\'t seem a good way in. ', 468 'So perhaps you\'d better try the front door. ', 469 'Could someone have left a key around somewhere? ', 470 'Is there anything lying around where someone could have hidden a key? ', 471 'What about that flowerpot? ', 472 'Try looking under the flowerpot. ' 473 ] 474 475 goalState = OpenGoal 476; 477 478/* The closeWhenSeen property of the following Goal object is an example of how to 479 make your hint menu respond dynamically to the player's current situation. */ 480 481+ Goal 'Where can I find the orb? ' 482 [ 483 'Something like that is bound to be kept safe. ', 484 'So it\'s probably inside the house. ' 485 ] 486 487 goalState = OpenGoal 488 closeWhenSeen = hallway 489; 490 491+ Goal 'Where can I find the orb?' 492 [ 493 'It\'s sure to be kept somewhere safe. ', 494 'You\'d better hunt around. ', 495 'Somewhere in the study seems the most likely place. ', 496 deskHint, 497 'But it should be safely locked in a safe ', 498 'Where might someone hide a safe in this study? ', 499 'What could be behind that picture on the wall? ', 500 'Try looking behind the picture (or simply taking the picture). ' 501 ] 502 503 openWhenSeen = hallway 504 closeWhenSeen = orb 505; 506 507++ deskHint: Hint 'Have you tried looking in the desk drawer? ' 508 [deskGoal] 509; 510 511+ deskGoal: Goal 'How do I get the desk drawer open?' 512 [ 513 'Have you examined the drawer? ', 514 'What might you need to unlock it? ', 515 'Where might you find such a thing? ', 516 'What have you seen that a small key might be hidden in? ', 517 'How carefully have you searched the hall? ', 518 'What is (or was) on the hall table? ', 519 'What might that vase be for? ', 520 'Try looking in the vase. ' 521 ] 522 closeWhenSeen = notebook 523; 524 525+ Goal 'How do I get the safe open?' 526 [ 527 'How carefully have you examined the safe? ', 528 'Where might someone leave a clue to the combination? ', 529 deskHint, 530 'Make sure you read the notebook. ', 531 'Once you\'ve found the combination you need to use the dial. ', 532 'If the combination is a number larger than 99 you\'ll need to enter it 533 in stages. ', 534 'For example, if the combination were 1234 you\'d first need to turn the 535 dial to 12 and then turn it to 34. ' 536 ] 537 538 openWhenSeen = safe 539 closeWhenAchieved = (safe.subContainer.achievement) 540; 541 542+ Goal 'What does the clue in the notebook mean?' 543 [ 544 'Well, <q>SAFE</q> might refer to something you want to open. ', 545 'Have you seen a date round here? ', 546 'When was this house built? ', 547 'Where might you find the year in which this house was built? ', 548 'How carefully have you looked at the front of the house? ', 549 'Did you examine the door? ' 550 ] 551 552 openWhenRevealed = 'safe-date' 553 closeWhenAchieved = (safe.subContainer.achievement) 554; 555 556 557+ Goal 'What do I do with the orb now I\'ve got it?' 558 [ 559 'Well, you could try rubbing it. ', 560 'But the main thing to do now is to escape with it. ' 561 ] 562 openWhenSeen = orb 563; 564