Elevator and stairs (TADS 3 example)

From IFWiki

#charset "us-ascii"

#include <adv3.h>
#include <en_us.h>

versionInfo: GameID
    name = 'TADS 3 Elevator and Stairs Example'
    byline = 'by David Turpin'
    htmlByline = 'by <a href="mailto:dturpin@mainstreettech.com">
                  David Turpin</a>'
    version = '1.0'
    authorEmail = 'David Turpin <dturpin@mainstreettech.com>'
    desc = 'This is the TADS3 version of the Elevator and Stairs example from the IFWiki.'
    htmlDesc = 'This is the TADS3 version of the Elevator and Stairs example from the 
    <a href="http://www.ifwiki.org">IFWiki</a>.'

    showCredit()
    {
        "Elevator and Stairs example from the <a href='http://www.ifwiki.org'>IFWiki</a>.
        <.p>TADS3 version by David Turpin. ";
        "\b";
    }
    showAbout()
    {
        "This is the TADS3 version of the Elevator and Stairs example on the IFWiki. It is a three story
         building with a set of stairs and an elevator.";
    }
;

me: Actor
    location = startRoom
;
gameMain: GameMainDef
    initialPlayerChar = me

    showIntro()
    {
        "An example of Stairs and Elevators\n Version 1.0\n by David Turpin\b";
    }

    showGoodbye()
    {
        "<.p>Thanks for playing!\b";
    }
;

/* Modified Library objects */

modify VerbRule(ClimbUp)
('climb' | 'take') singleDobj 'up' | ('climb' | 'take') 'up' singleDobj
:
;
modify VerbRule(ClimbDown)
('climb' | 'take') singleDobj 'down' | ('climb' | 'take') 'down' singleDobj
:
;
modify Stairway
Stairstaken = nil
dobjFor(TravelVia)
{
 action() 
  {
   gAction.actionTime = 3; 
   "<<!Stairway.Stairstaken ? 'It took longer to take the stairs than you expected. ' : nil>>";
   Stairway.Stairstaken = true; inherited; 
  }
}
;
modify OneWayRoomConnector
dobjFor(TravelVia)
{
 action() 
  {
   gAction.actionTime = 3;
   "<<!Stairway.Stairstaken ? 'It took longer to take the stairs than you expected. ' : nil>>";
   Stairway.Stairstaken = true; inherited; 
  }
}
;

/* Classes for the Example */

class elevatorDoor: Door 'elevator door/elevator' 'elevator door'
"The elevator door is <<isOpen ? "open" : "closed">>, and there's a call button beside it"
openStatus {} // This stops the door from displaying It's open or It's closed at the end of the description
destination = Elevator
dobjFor(Open) 
{
 check() 
 {
  if (isOpen) { "{The dobj/he} is already open"; exit; }
  else { "Try pushing the call button."; exit; }
 } 
}
dobjFor(Close) 
{
 check() 
 {
  if (!isOpen) { "{The dobj/he} is already closed. "; exit; }
  else { "{The dobj/he} will close automatically when it needs to. "; exit; }
 } 
}
;      

class elevatorButton: Button, Fixture '(elevator) button*buttons' 'panel button'
"The panel has three buttons: G, 2, and 3. There is also a LED display that reads '<<Elevator.floor == 1 ? "G" : Elevator.floor>>'."
isLit = nil
dobjFor(Push) 
{
 action() 
 {
  if (elevatorButton.daemonID != nil) 
  {
   elevatorButton.daemonID.removeEvent(); elevatorButton.daemonID = nil;
  }
  if (callButton.daemonID != nil) 
  {
   callButton.daemonID.removeEvent(); callButton.daemonID = nil;
  }
  elevatorButton.daemonID = new Daemon(self, &daemon, 1); 
 }
}
daemonID = nil
floor = 0
startoff = nil
daemon 
{
 switch(floor) 
 {
  case 1: 
  {
   if (EDoor.isOpen) 
   {
    "\n The elevator door closes. ";
    isLit = true;
    EDoor.makeOpen(nil);
    break;
   }
   if (floor > Elevator.floor) 
   {
    "<<!startoff ? '\n You feel the elevator start going up.' : nil>>";
    isLit = true;
    startoff = true;
    Elevator.floor = Elevator.floor + 1; 
   }
   if (floor < Elevator.floor) 
   {
    "<<!startoff ? '\n You feel the elevator start going down.' : nil>>";
    isLit = true;startoff = true;
    Elevator.floor = Elevator.floor - 1;
   }
   if (!EDoor.isOpen && floor == Elevator.floor && !startoff) 
   {
    "\n The elevator door opens. The elevator button goes dark.";
    isLit = nil;
    elevatorButton.daemonID.removeEvent();elevatorButton.daemonID = nil;
    EDoor.makeOpen(true);GEDoor.makeOpen(true);
    callButton.daemonID = new Fuse(GCButton,&doorClose,2);break;
   }
   if (!EDoor.isOpen && floor == Elevator.floor && startoff) 
   { 
    "\n You feel the elevator come to a stop. ";
    startoff = nil;
    break;
   }
   break;
  }
  case 2: 
  {
   if (EDoor.isOpen) 
   {
    "\n The elevator door closes. ";
    isLit = true;
    EDoor.makeOpen(nil);
    break;
   }
   if (floor > Elevator.floor) 
   {
    "<<!startoff ? '\n You feel the elevator start going up.' : nil>>";
    isLit = true;
    startoff = true;
    Elevator.floor = Elevator.floor + 1; 
   }
   if (floor < Elevator.floor) 
   { 
    "<<!startoff ? '\n You feel the elevator start going down.' : nil>>";
    isLit = true;
    startoff = true;
    Elevator.floor = Elevator.floor - 1; 
   }
   if (!EDoor.isOpen && floor == Elevator.floor && !startoff) 
   {
    "\n The elevator door opens. The elevator button goes dark.";
    isLit = nil;
    elevatorButton.daemonID.removeEvent();elevatorButton.daemonID = nil;
    EDoor.makeOpen(true);SEDoor.makeOpen(true);
    callButton.daemonID = new Fuse(SCButton,&doorClose,2);
    break;
   }
   if (!EDoor.isOpen && floor == Elevator.floor && startoff) 
   { 
    "\n You feel the elevator come to a stop. ";
    startoff = nil;
    break;
   }
   break;
  }
  case 3: 
  {
   if (EDoor.isOpen) 
   {
    "\n The elevator door closes. ";
    isLit = true;
    EDoor.makeOpen(nil);
    break;
   }
   if (floor > Elevator.floor) 
   { 
    "<<!startoff ? '\n You feel the elevator start going up.' : nil>>";
    isLit = true;
    startoff = true;
    Elevator.floor = Elevator.floor + 1; 
   }
   if (floor < Elevator.floor) 
   { 
    "<<!startoff ? '\n You feel the elevator start going down.' : nil>>";
    isLit = true;
    startoff = true;
    Elevator.floor = Elevator.floor - 1;
   }
   if (!EDoor.isOpen && floor == Elevator.floor && !startoff)      
   {
    "\n The elevator door opens. The elevator button goes dark.";
    isLit = nil;
    elevatorButton.daemonID.removeEvent();elevatorButton.daemonID = nil;
    EDoor.makeOpen(true);TEDoor.makeOpen(true);
    callButton.daemonID = new Fuse(TCButton,&doorClose,2);
    break;
   }
   if (!EDoor.isOpen && floor == Elevator.floor && startoff) 
   { 
    "\n You feel the elevator come to a stop. ";
    startoff = nil;
    break;
   }
   break;
  }
 } 
}
;

class callButton: Button, Fixture '(elevator) call button*buttons' 'call button'
"Pushing this button summons the elevator to this floor. It's currently <<isLit ? 'lit' : 'dark'>>. "
isLit = nil
wasSaid = nil
startoff = nil
floor = 0
dobjFor(Push)
{
 action() 
 {
  if (callButton.daemonID != nil) 
  {
   callButton.daemonID.removeEvent(); callButton.daemonID = nil;
  }
  callButton.daemonID = new SenseDaemon(self, &daemon, 1,self,sight); 
 }
}
daemonID = nil
daemon 
{
 switch(floor) 
 {
  case 1: 
  {
   if (!GEDoor.isOpen && GCButton.floor == Elevator.floor) 
   {
    isLit = nil;
    GEDoor.makeOpen(true);
    "\n<<startoff ? 'The elevator door opens. The call button blinks off' : 'The elevator door opens.'>> ";
    startoff = nil;
    callButton.daemonID.removeEvent();callButton.daemonID = nil;
    EDoor.makeOpen(true);
    callButton.daemonID = new Fuse(self,&doorClose,2);
    break; 
   }
   if (GEDoor.isOpen && GCButton.floor != Elevator.floor) 
   {
    GEDoor.makeOpen(nil);
    break;
   }
   if (GEDoor.isOpen && GCButton.floor == Elevator.floor) 
   { 
    "Nothing happens. ";
    callButton.daemonID.removeEvent();callButton.daemonID = nil;
    callButton.daemonID = new Fuse(self,&doorClose,2);
    break;
   }
   startoff = true;
   isLit = true;
   "<<wasSaid ? nil : 'The call button lights up.'>>";
   wasSaid = true;
   if (SEDoor.isOpen || TEDoor.isOpen) 
   {
    SEDoor.makeOpen(nil);
    TEDoor.makeOpen(nil);
    break;
   }
   if (GCButton.floor > Elevator.floor) 
   { 
    Elevator.floor = Elevator.floor + 1; 
   }
   if (GCButton.floor < Elevator.floor) 
   {
    Elevator.floor = Elevator.floor - 1;
   } 
   break;
  }
  case 2: 
  {
   if (!SEDoor.isOpen && SCButton.floor == Elevator.floor) 
   {
    isLit = nil; SEDoor.makeOpen(true);
    "\n<<startoff ? 'The elevator door opens. The call button blinks off' : 'The elevator door opens.'>> ";
    startoff = nil;
    callButton.daemonID.removeEvent();callButton.daemonID = nil;
    EDoor.makeOpen(true);
    callButton.daemonID = new Fuse(self,&doorClose,2);
    break; 
   }
   if (SEDoor.isOpen && SCButton.floor != Elevator.floor) 
   {
    SEDoor.makeOpen(nil);
    break;
   }
   if (SEDoor.isOpen && SCButton.floor == Elevator.floor) 
   { 
    "Nothing happens. ";
    callButton.daemonID.removeEvent();callButton.daemonID = nil;
    callButton.daemonID = new Fuse(self,&doorClose,2);
    break;
   }
   startoff = true;
   isLit = true;
   "<<wasSaid ? nil : 'The call button lights up.'>>";
   wasSaid = true;
   if (GEDoor.isOpen || TEDoor.isOpen) 
   {
    GEDoor.makeOpen(nil); 
    TEDoor.makeOpen(nil);
    break;
   }
   if (SCButton.floor > Elevator.floor) 
   {
    Elevator.floor = Elevator.floor + 1; 
   }
   if (SCButton.floor < Elevator.floor) 
   { 
    Elevator.floor = Elevator.floor - 1;
   } 
   break; 
  }
  case 3: 
  {
   if (!TEDoor.isOpen && TCButton.floor == Elevator.floor) 
   {
    isLit = nil; TEDoor.makeOpen(true);
    "\n<<startoff ? 'The elevator door opens. The call button blinks off' : 'The elevator door opens.'>> ";
    startoff = nil;
    callButton.daemonID.removeEvent();callButton.daemonID = nil;
    EDoor.makeOpen(true);
    callButton.daemonID = new Fuse(self,&doorClose,2);
    break; 
   }
   if (TEDoor.isOpen && TCButton.floor != Elevator.floor) 
   {
    TEDoor.makeOpen(nil);
    break;
   }
   if (TEDoor.isOpen && TCButton.floor == Elevator.floor) 
   {
     "Nothing happens. ";
     callButton.daemonID.removeEvent();callButton.daemonID = nil;
     callButton.daemonID = new Fuse(self,&doorClose,2);
     break;
   }
   startoff = true;
   isLit = true;
   "<<wasSaid ? nil : 'The call button lights up.'>>";
   wasSaid = true;
   if (GEDoor.isOpen || SEDoor.isOpen) 
   {
    GEDoor.makeOpen(nil);
    SEDoor.makeOpen(nil);
    break;
   }
   if (TCButton.floor > Elevator.floor) 
   { 
    Elevator.floor = Elevator.floor + 1;
   }
   if (TCButton.floor < Elevator.floor) 
   { 
    Elevator.floor = Elevator.floor - 1;
   } 
   break;
  }
 }
}
doorClose 
{ 
 for(local obj = firstObj(elevatorDoor); obj; obj = nextObj(obj, elevatorDoor))
 {
  obj.makeOpen(nil);
 }
 "<<me.canSee(self) || me.isIn(Elevator) ? '\n The elevator door closes. ' : nil>>"; 
}
;

/* Example objects */		


startRoom: Room 'Ground Floor'
"You are on the ground floor. The <<GEDoor.isOpen ? "open" : "closed">> door to the elevator is north, and the stairs are up. "
north = GEDoor
up = GUpStair
in asExit(north)
;
+GEDoor: elevatorDoor;
+GCButton: callButton {floor = 1};
+GUpStair: StairwayUp ->SStair 'up stairway/stairs' 'stairs'
"They go up. "
dobjFor(Take) asDobjFor(Climb)
;


SecondFloor: Room 'Second Floor'
"You are on the second floor. The <<SEDoor.isOpen ? "open" : "closed">> door to the elevator is north, and stairs go both
 up and down from here. "
north = SEDoor
down : OneWayRoomConnector {destination = startRoom}
up : OneWayRoomConnector {destination = ThirdFloor}
in asExit(north)
;
+FromThird: ExitOnlyPassage, SecretFixture; //SecretFixture makes this object invisible to the player.
+SEDoor: elevatorDoor; 
+SCButton: callButton {floor = 2};
+SStair: Stairway 'stairway/stairs' 'stairs'
"They go up and down. "
dobjFor(Take) 
{
 verify() {}
 check() {}
 action() 
 {
  gAction.actionTime = 0;
  "Do you want to take the stairs up, or take the stairs down? ";
  exit;
 }
}
dobjFor(Climb) asDobjFor(Take)
dobjFor(ClimbUp) remapTo(Up)
dobjFor(ClimbDown) remapTo(Down)
;


ThirdFloor: Room 'Third Floor'
"You are on the third floor.  The <<TEDoor.isOpen ? "open" : "closed">> door to the elevator is north, or you can take the stairs down. "
north = TEDoor
down = TDownStair
in asExit(north)
;
+TEDoor: elevatorDoor;
+TCButton: callButton {floor = 3};
+TDownStair: StairwayDown ->FromThird 'down stairway/stairs' 'stairs'
"They go Down. "
dobjFor(Take) asDobjFor(Climb)
;


Elevator: Room 'Elevator'
"You are inside the elevator. The door to the south is <<EDoor.isOpen ? "open" : "closed">>, and there's the usual panel of buttons beside it. "
south = EDoor
out asExit(south)
floor = 1
;
+EDoor: elevatorDoor
destination
{
 switch(Elevator.floor)
 {
  case 1: {return startRoom;}
  case 2: {return SecondFloor;}
  case 3: {return ThirdFloor;}
  default: {return startRoom;} //to prevent the annoying droping off end warning while compiling.
 }
}
dobjFor(Open) 
{
 check()
 {
  if (isOpen) 
   { 
    "{The dobj/he} is already open";
    exit;
   }
  else 
  { 
   "{The dobj/he} will open automatically when it needs to. ";
   exit;
  }
 }
}
;
+GEButton: elevatorButton '(elevator) G button G' 'button G' {floor = 1};
+SEButton: elevatorButton '(elevator) 2 button 2/two' 'button 2' {floor = 2};
+TEButton: elevatorButton '(elevator) 3 button 3/three' 'button 3' {floor = 3};
+Fixture '(elevator) panel' 'elevator panel'
"The panel has three buttons: G, 2, and 3. There is also a LED display that reads '<<Elevator.floor == 1 ? "G" : Elevator.floor>>'."
;
+Fixture '(Elevator) LED display' 'LED display'
"The LED Display is showing a large red '<<Elevator.floor == 1? 'G' : Elevator.floor>>'."
;