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