-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathelevator.t
643 lines (548 loc) · 18.5 KB
/
elevator.t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
//----------------//
// The elevator //
//----------------//
elevatorWalls : DefaultWall
vocabWords = 'elevator north n south s west w stainless steel north/n/south/s/west/w/wall/walls'
name = 'elevator walls'
desc = "The preponderance of stainless steel---thin strips of
stainless steel on the wall, the stainless steel leaning
bar, the stainless steel doors, control panel,
everything---firmly places the elevator as a <q>choice
from the Catalogue of the Painfully Usual</q> as far as
building design goes. "
isPlural = true
;
+Component
vocabWords = '(metal) stainless steel lean leaning bar/rail/pipe/stand/railing/balustrade'
name = 'metal bar'
desc = "Skirting the three main walls is a metal bar for your
leaning pleasure. It sags a little from use, but is
otherwise okay. "
feelDesc = "The railing feels cold and metallic. "
dobjFor(Fix) { verify() { illogical('Cool off your fire of altruism and leave that for the caretaker. '); }}
;
+Component
vocabWords = '(metal) dense vertical thin steel stainless steel strips/stripes/lines'
name = 'strips of metal'
desc = "The walls are covered in dense vertical lines of
stainless steel. "
feelDesc = "The strips are fun to rattle your fingernail along,
but feel rather much like you\'d expect: metal and
stripey. "
;
elevatorFront : DefaultWall
vocabWords = '(elevator) east e front east/e/front/door/doors/wall'
name = 'elevator doors'
desc = "The front of the elevator looks the same as all others
you\'ve stared at while you\'ve waited. To the right of
the doors is the requisite control panel. "
;
+elevatorPanel : Component
vocabWords = '(elevator) control panel/controls/buttons'
name = 'elevator control panel'
desc = "To the right of the elevator doors is a simple control
panel with an assortment of buttons reading: G, 1, 2, 3,
4, 5, 6, and 7, as well as the usual ones to manually open
and close the doors. Below these is a slot for a keycard. "
// This function deactivates all the buttons
deactivateButtons() {
foreach(local x in [elevatorGButton, elevator1Button, elevator2Button, elevator3Button, elevator4Button, elevator5Button, elevator6Button, elevator7Button]) {
x.makeEnabled(nil);
}
}
;
++elevatorOpenButton : Component, Button
vocabWords = 'manual open O button/key/switch/open'
name = 'manual open button'
desc = "This button opens the doors to the elevator, when they can be. "
dobjFor(Push) {
verify() {}
check() {
if(elevator.currentAction is in (elevatorGoingUp, elevatorGoingDown)) {
"You press the <q>open</q> button and it briefly
lights up but darkens as soon as you remove your
finger. ";
exit;
}
}
action() {
// Already open or just about to close, so reset the close action
// and open the door (Without triggering the usual things)
if(elevator.isDoorsOpen || elevator.currentAction == elevatorCloseDoor) {
elevator.currentAction = elevatorOpenDoor;
if(elevator.currentActionID != nil)
elevator.currentActionID.removeEvent;
elevator.currentActionID = new Fuse(elevator,&closeDoors,elevator.doorCloseTime);
"You press the button and the doors reopen. ";
}
else {
"You press the <q>open doors</q> button and the elevator complies. ";
elevator.openDoors();
}
}
}
;
++elevatorCloseButton : Component, Button
vocabWords = 'manual close C button/key/switch/close/closed'
name = 'manual close button'
desc = "This button closes the doors when the automatic timer
just isn't fast enough. The label seems to be more worn
than the surrounding buttons. Impatient residents, you
guess. "
dobjFor(Push) {
verify() {}
check() {
if(!elevator.isDoorsOpen) {
"The doors are already closed, so naturally, the elevator does not respond. ";
exit;
}
}
action() {
elevator.closeDoors();
}
}
;
++elevatorGButton : ElevatorButton, Component
vocabWords = 'level floor storey ground g button bottom floor/level/storey/ground/g/button*buttons'
name = '<q>G</q> button'
myFloor = 0
myFloorName = 'G'
myFloorNameOrdinal = 'ground'
isInteriorButton = true
;
++elevator1Button : ElevatorButton, Component
vocabWords = 'level floor storey first 1 1st one button floor/level/storey/1/1st/one/first/button*buttons'
name = 'button for the first floor'
myFloor = 1
isInteriorButton = true
;
++elevator2Button : ElevatorButton, Component
vocabWords = 'level floor storey 2 two 2nd second button floor/level/storey/two/2/second/2nd/button*buttons'
name = '<q>2</q> button'
myFloor = 2
isInteriorButton = true
;
++elevator3Button : ElevatorButton, Component
vocabWords = 'level floor storey 3 three 3rd third button floor/level/storey/3/three/third/3rd/button*buttons'
name = '<q>3</q> button'
myFloor = 3
isInteriorButton = true
;
++elevator4Button : ElevatorButton, Component
vocabWords = 'level floor storey 4 four fourth 4th button floor/level/storey/4/four/fourth/4th/button*buttons'
name = '<q>4</q> button'
myFloor = 4
isInteriorButton = true
;
++elevator5Button : ElevatorButton, Component
vocabWords = 'level floor storey 5 five 5th fifth button floor/level/storey/5/five/fifth/5th/button*buttons'
name = '<q>5</q> button'
myFloor = 5
isInteriorButton = true
;
++elevator6Button : ElevatorButton, Component
vocabWords = 'level floor storey 6 six sixth 6th button floor/level/storey/6/six/sixth/6th/button*buttons'
name = '<q>6</q> button'
myFloor = 6
isInteriorButton = true
;
++elevator7Button : ElevatorButton, Component
vocabWords = 'level floor storey 7 seven seventh 7th button floor/level/storey/7/seven/seventh/7th/button*buttons'
name = '<q>7</q> button'
myFloor = 7
isInteriorButton = true
;
++elevatorCardReader : Component, Readable
vocabWords = 'keycard card security reader/slot/hole'
name = 'card slot'
desc = "A security card reader is installed in the elevator\'s
control panel at about navel-height. In miniature
writing above the slot is the text <q>INSERT KEY
CARD</q>. "
readDesc = "Miniature writing about the slot reads: <q>INSERT
KEY CARD</q> "
currentEnabled = [ ]
beforeAction() {
inherited;
if( gActionIs(Swipe) && gDobj.ofKind(SwipeCard) )
replaceAction(SwipeThrough, gDobj, self);
}
iobjFor(SwipeThrough) asIobjFor(PutIn)
iobjFor(PutIn) {
verify() {}
check() {
if(!gDobj.ofKind(SwipeCard)) {
if(gDobj.bulk > 2)
"{The dobj/he} {is} too big to fit in the slot. ";
else
"{The dobj/he} {is} inappropriate to put in the slot. ";
exit;
}
if(!gDobj.isValid || gDobj.accessibleFloors.length == 0) {
"You insert the card into the slot. It is taken in
and the reader thinks about it for a second before
buzzily angrily and spitting the card back out.
Maybe there is something wrong with the card? ";
exit;
}
}
action() {
// Set up the variables
local buttonlst = [elevatorGButton, elevator1Button, elevator2Button, elevator3Button, elevator4Button, elevator5Button, elevator6Button, elevator7Button];
local activated = [];
// If our floor is on the card, enable the button
foreach(local x in buttonlst) {
if(gDobj.accessibleFloors.indexOf(x.myFloor) != nil) {
x.makeEnabled(true);
activated = activated.append(x.myFloorNameOrdinal);
}
}
"The card reader sucks in the card, thinks for a second
and chirps happily before ejecting the card. The
buttons for the <<stringLister.showList(activated)>>
floors light up. ";
}
}
;
elevatorCeiling : defaultCeiling
vocabWords = '(elevator) ceiling/up/u/roof'
name = 'ceiling'
desc = "In the usual elevator wait, you\'ve often peered up at
the ceiling. This ceiling is no different---just the
usual lights, frame, and access panel.
<<elevatorCeilingPanel.discover()>> "
location = elevator
;
elevatorCeilingPanel : Door, Hidden ->elevatorAccessPanel
vocabWords = '(elevator) (ceiling) access emergency exit panel/exit/hole/manhole/portal'
name = 'emergency exit panel'
desc = "Although a little more conspicuous than your usual
elevator emergency exit, the panel in the roof is
unremarkable. "
location = elevator
initiallyOpen = nil
okayOpenMsg = 'You shove the access panel open. It lifts up and
clangs on the roof of the elevator. '
okayCloseMsg = 'You reach up and grab the access panel. After a
little bit of stretching and straining you
manage to pull the panel shut. '
isComponentOf(obj) {
return obj==elevatorCeiling;
}
;
elevatorFloor : defaultFloor
vocabWords = '(elevator) floor/down/d/ground'
name = 'floor'
desc = "A worn, grille-shaped carpet once decorated the floor
and is now only here because of tenure, you\'re
guessing. "
;
// Elevator Open event
elevatorOpenEvent : SoundEvent;
// Elevator Close event
elevatorCloseEvent : SoundEvent;
// Elevator slowing down event
elevatorStoppingEvent : SoundEvent;
// Elevator moving event
elevatorMovingEvent : SoundEvent;
// Elevator starting to move
elevatorStartingEvent : SoundEvent;
// THE ELEVATOR
enum elevatorIdle, elevatorGoingUp, elevatorGoingDown, elevatorStopping, elevatorOpenDoor, elevatorCloseDoor;
elevator : Room
name = 'Elevator'
destName = 'the elevator'
desc = "Except for the roughly carpeted floor, the elevator is
pretty much entirely stainless steel. And uninspiringly
so. The walls have thin, vertical metal strips for
decoration, as well as a bar to lean on. Apart from the
control panel adjacent to the doors, this is as exciting
as this elevator gets. "
roomParts = [elevatorWalls,elevatorFront,elevatorCeiling,elevatorFloor]
out = elevatorInnerDoors
east asExit(out)
up {
if(elevatorCeilingPanel.discovered() )
return elevatorCeilingPanel;
else
return nil;
}
// Elevator-specific code
// This holds the reference to the current action
currentActionID = nil
isDoorsOpen = nil
queuedAction = nil
currentAction = elevatorIdle
currentFloor = 0
initialFloor = 0
goalFloor = 0
doorCloseTime = 3
// What is my outside door?
myOutsideDoor() {
local x;
switch(currentFloor) {
case 0:
x = groundElevatorDoors;
break;
case 1:
x = firstElevatorDoors;
break;
case 2:
x = secondElevatorDoors;
break;
case 7:
x = seventhElevatorDoors;
break;
default:
x = nil;
}
return x;
}
// Remove daemons
removeDaemons() {
if(currentActionID != nil) {
currentActionID.removeEvent;
currentActionID = nil;
}
}
// Trigger movement or not
triggerMovement() {
if(currentFloor != goalFloor) {
currentAction = (currentFloor > goalFloor ? elevatorGoingDown : elevatorGoingUp);
currentActionID = new Daemon(self,&doTravel,1);
}
else {
currentAction = elevatorIdle;
currentActionID = nil;
}
}
// Code to open the doors
openDoors() {
isDoorsOpen = true;
currentAction = elevatorOpenDoor;
// Notify my floor that I've opened
elevatorOpenEvent.triggerEvent(myOutsideDoor());
elevatorOpenEvent.triggerEvent(elevatorInnerDoors);
// Queue the door closing
if(currentActionID != nil) {
currentActionID.removeEvent;
}
currentActionID = new Fuse(self,&closeDoors,doorCloseTime);
}
// Code to close the doors
closeDoors() {
if(currentAction not in (elevatorCloseDoor, elevatorGoingUp, elevatorGoingDown)) {
isDoorsOpen = nil;
currentAction = elevatorCloseDoor;
initialFloor = myOutsideDoor().myFloor;
// Notify my floor that I've closed
elevatorCloseEvent.triggerEvent(myOutsideDoor());
elevatorCloseEvent.triggerEvent(elevatorInnerDoors);
// Take care of daemons
removeDaemons();
// If I have a new goal level, start that
triggerMovement();
}
}
// Do travel
doTravel() {
// Check if we've reached our floor
if(currentFloor == goalFloor) {
// Remove the travelling daemon
if(currentActionID != nil) {
currentActionID.removeEvent;
}
// Set up the door opening
currentActionID = new Fuse(self,&openDoors,1);
currentAction = elevatorStopping;
if(myOutsideDoor() != nil)
elevatorStoppingEvent.triggerEvent(myOutsideDoor());
elevatorStoppingEvent.triggerEvent(elevatorInnerDoors);
}
else {
// Still moving, so make some noise, but do nothing else
if(myOutsideDoor() != nil)
elevatorMovingEvent.triggerEvent(myOutsideDoor());
if(currentFloor != initialFloor)
elevatorMovingEvent.triggerEvent(elevatorInnerDoors);
}
if(currentAction is in (elevatorGoingUp,elevatorGoingDown)) {
if(currentAction == elevatorGoingUp)
currentFloor++;
else
currentFloor--;
}
}
;
+elevatorInnerDoors : ElevatorDoors
vocabWords = '(elevator) (lift) (elevater) metal east e door/doors/east/e/out'
destination = (elevator.myOutsideDoor().location)
cannotTravel() { reportFailure(cannotGoThatWayMsg); }
cannotGoThatWayMsg = 'The elevator is currently in motion, wait until it has stopped. '
myFloor = (elevator.currentFloor)
myCallButton = elevatorOpenButton
//dobjFor(Open) remapTo(Push,elevatorOpenButton)
dobjFor(Close) remapTo(Push,elevatorCloseButton)
//dobjFor(TravelVia) { preCond = (inherited() + objOpen) }
;
+ElevatorSounds
openMsg = 'The doors open, heralded by a exclamatory <i>ding!</i> '
closeMsg = 'The doors slide shut with a low rumble and a clunk. '
stopMsg = 'The elevator glides to a whining halt. '
movingMsg = 'The elevator continues rumbling along. '
startMsg {
if(elevator.currentAction == elevatorGoingUp)
return 'The elevator groans and begins moving upwards. ';
else
return 'With a sigh, the elevator drops, leaving your stomach trailing a little behind. ';
}
;
//
// On top of the elevator
elevatorTop : Room
name = 'On top of the elevator'
destName = 'on top of the elevator'
desc = "UNIMPLEMENTED"
roomParts = [elevatorTopGround]
down = elevatorAccessPanel
roomBeforeAction() {
if( gActionIs(Yell) ) {
"You shout out loud. Your voice echoes up and down the
elevator shaft. It soon fades. ";
exit;
}
}
;
+ elevatorAccessPanel : Door // ->elevatorCeilingPanel
vocabWords = 'access emergency panel/hole/porthole'
name = 'emergency panel'
desc = "UNIMPLEMENTED"
initNominalRoomPartLocation = elevatorTopGround
;
elevatorTopGround : Floor
name = 'top of the elevator'
desc = "UNIMPLEMENTED"
;
//
// ASSOCIATED CLASSES
// Elevator buttons class
class ElevatorButton : Button
desc {
"The large <q><<myFloorName>></q> indicates this button
takes the elevator to the <<myFloorNameOrdinal>> floor. ";
if(isEnabled)
"The button is currently lit. ";
else
"The button is currently dim. ";
}
myFloor = 0
myFloorName { return toString(myFloor); }
myFloorNameOrdinal { return spellIntOrdinal(myFloor); }
isInteriorButton = true
isEnabled = nil
makeEnabled(val) {
isEnabled = val;
}
dobjFor(Push) {
verify() {}
check() {
if(!isEnabled) {
"You push the button but the elevator does not
respond. The button is not illuminated, probably
meaning you can\'t use it now. ";
exit;
}
}
action() {
// We're rolling, so deactivate all the buttons
// This happens regardless of whether we are an interior button or not
elevatorPanel.deactivateButtons();
// If we're already there
if(elevator.currentFloor == myFloor) {
if(!elevator.isDoorsOpen)
elevator.openDoors();
else {
if(isInteriorButton)
mainReport('You press the button, but nothing happens, presumably because you are already at the ground floor. ');
else
mainReport('You press the button and stare embarrassed into the open, inviting elevator. ');
}
}
// Otherwise, close the doors if need be and move.
else {
elevator.goalFloor = myFloor;
if(!elevator.isDoorsOpen) {
if(!isInteriorButton)
mainReport('You press the button and wait for the elevator. ');
elevator.triggerMovement();
elevatorStartingEvent.triggerEvent(elevator.myOutsideDoor());
elevatorStartingEvent.triggerEvent(elevatorInnerDoors);
}
else {
if(isInteriorButton)
mainReport('You press the button and the doors begin to close. ');
else
mainReport('You press the button and wait for the elevator. ');
if(currentActionID != nil)
currentActionID.removeEvent;
currentActionID = new Fuse(elevator,&closeDoors,1);
}
}
}
}
;
// Exterior elevator button
// Has some extra customizations
class ElevatorExteriorButton : ElevatorButton
vocabWords = '(elevator) call button/switch/key/up/down/u/d/call'
name = 'elevator call button'
desc = "This button, when pressed, calls the elevator.
<<isIlluminated ? 'The button is illuminated, indicating
the elevator is on its way. ' : 'The button is dim. '>> "
isInteriorButton = nil
isEnabled = true
isIlluminated() { return (elevator.currentAction is in (elevatorGoingUp, elevatorGoingDown)); }
;
// Elevator doors class
class ElevatorDoors : ThroughPassage
vocabWords = '(elevator) (lift) (elevater) metal west w door/doors/west/w/in'
name = 'elevator doors'
desc = "The elevator doors are of the usual shiny metal design. <<openStatus()>>"
openStatus() {
if(isOpen)
return 'They are currently open. ';
else
return 'They are currently closed. ';
}
isOpen = (elevator.isDoorsOpen && elevator.currentFloor == myFloor)
myFloor = (myCallButton.myFloor)
myCallButton = nil
destination = elevator
dobjFor(Open) remapTo(Push,myCallButton)
dobjFor(TravelVia) maybeRemapTo(!elevator.isDoorsOpen,Push,myCallButton)
;
// Elevator sounds class
class ElevatorSounds : SecretFixture, SoundObserver
notifySoundEvent(event, source, info) {
switch(event) {
case elevatorOpenEvent:
callWithSenseContext(source, sight, {: say(openMsg) });
break;
case elevatorCloseEvent:
callWithSenseContext(source, sight, {: say(closeMsg) });
break;
case elevatorStoppingEvent:
callWithSenseContext(source, sight, {: say(stopMsg) });
break;
case elevatorMovingEvent:
callWithSenseContext(source, sight, {: say(movingMsg) });
break;
case elevatorStartingEvent:
callWithSenseContext(source, sight, {: say(startMsg) });
break;
}
}
;