! ---------------------------------------------------------------------------------------------------
! Inform Demonstration
! ---------------------------------------------------------------------------------------------------

Constant Story "Adventure Core";

Release 1;

! Some attributes for objects.

Attribute light;
Attribute concealed;
Attribute worn;
Attribute clothing;
Attribute animate;
Attribute proper;
Attribute moved;
Attribute portal;
Attribute container;
Attribute interior;
Attribute open;
Attribute openable;
Attribute workflag;
Attribute enterable;
Attribute scenery;
Attribute static;
Attribute direction;
Attribute visited;
Attribute lockable;
Attribute locked;
Attribute switchable;
Attribute on;
Attribute general;
Attribute edible;
Attribute autosearch;
Attribute scored;
Attribute talkable;
Attribute is_cube;

! Some Default Properties                              

Property longdesc 0;
Property article "a";
Property initpos 0;

Property preroutine $ffff;
Property postroutine $ffff;
Property rodroutine $ffff;
Property weight 1;
Property score_value 0;
Property dirprop;
Property n_to;  Property s_to;
Property e_to;  Property w_to;
Property ne_to; Property se_to;
Property nw_to; Property sw_to;
Property u_to;  Property d_to;

Property portalto;
Property closedpos;
Property long timeleft;
Property with_key;
Property becomes;        

! Compass Direction Objects (Shouldn't need changing)

Object compass "compass" nothing has concealed;
Object n_obj "north wall" compass      
  with name "n" "north" "wall",           article "the", dirprop n_to   has  direction scenery;
Object s_obj "south wall" compass      
  with name "s" "south" "wall",           article "the", dirprop s_to   has  direction scenery;
Object e_obj "east wall" compass      
  with name "e" "east" "wall",            article "the", dirprop e_to   has  direction scenery;
Object w_obj "west wall" compass       
  with name "w" "west" "wall",            article "the", dirprop w_to   has  direction scenery;
Object ne_obj "northeast wall" compass 
  with name "ne" "northe" "wall",         article "the", dirprop ne_to  has  direction scenery;
Object nw_obj "northwest wall" compass
  with name "nw" "northw" "wall",         article "the", dirprop nw_to  has  direction scenery;
Object se_obj "southeast wall" compass
  with name "se" "southe" "wall",         article "the", dirprop se_to  has  direction scenery;
Object sw_obj "southwest wall" compass
  with name "sw" "southw" "wall",         article "the", dirprop sw_to  has  direction scenery;
Object u_obj "ceiling" compass         
  with name "u" "up" "ceiling",           article "the", dirprop u_to   has  direction scenery;
Object d_obj "floor" compass
  with name "d" "down" "floor",           article "the", dirprop d_to   has  direction scenery;

! Help Object

Object help "Help Object" nothing
  with longdesc "This adventure was created using Adventure Core.",

! An object for Dark locations

Object thedark "Darkness" nothing
  with longdesc "It is pitch dark, and you can't see a thing.";

! A starting Room object                              

Object gen_room "Generic Room" nothing
  with longdesc "This is the Generic room, describe as fit."
  has  light;           

! This next object is for Yourself, describe as appropriate

Object selfobj "yourself" office_1
  with name "me" "myself" "self", article "the",
  has  concealed animate proper;                           

! Add your objects after this.
 
! A few dictionary definitions.

Dictionary again_word   "again";
Dictionary g_word       "g";
Dictionary it_word      "it";
Dictionary them_word    "them";
Dictionary and_word     "and";
Dictionary comma_word   "xcomma";
Dictionary but_word     "but";
Dictionary except_word  "except";
Dictionary all_word     "all";
Dictionary both_word    "both";
Dictionary everyt_word  "everyt";
Dictionary the_word     "the";
Dictionary a_word       "a";
Dictionary an_word      "an";
Dictionary o_word       "o";
Dictionary oops_word    "oops";

! Global Definitions, the first three must be location,score and turns 
! for status line                              

Global location = gen_room; ! Change this to wherever you want to start
Global score = 0;
Global turns = 1;
Global maxscore = 50;       ! Change to a suitable value for game 
Global player = selfobj;    ! Change if not selfobj
Global max_carry = 4;       ! Maximum weight you can carry

Global itobj = 0;
Global toomanyf = 0;
Global actor = 0;

Global lightflag = 1;
Global deadflag = 0;

Global buffer string 120;
Global parse string 64;
Global buffer2 string 120;
Global parse2 string 64;
Global inputobjs data 16;
Global action = 0;
Global inp1 = 0;
Global inp2 = 0;
Global multinps data 64;
Global special_word = 0;
Global special_number = 0;

Global scr_mode = 0;

! ---------------------------------------------------------------------------------------------------
! Game control code
! ---------------------------------------------------------------------------------------------------


[ Main;

  print "^^^^Add your own Game intro message here.^"

  Banner();

  LookSub();
  Game();
];

global multiflag;

[ Game unused i j k l meta aflag;

  for i 1 to 100 { j=random(i); }

  while deadflag==0
  {   .Error; inp1=0; inp2=0; action=0;
      Input(inputobjs);

      if actor~=player { CDefArt(actor); print " has better things to do.^"; jump timeslice; }

      if toomanyf==1
      {   toomanyf=0;
          print "(taking the first sixteen objects only)^";
      }
      aflag=0;
      if action~=0 { aflag=1; }
      if action==0 { action=inputobjs->0; }
      meta=0;

      if action==#a$ScoreSub or #a$ScriptonSub or #a$ScriptoffSub { meta=1; }
      if action==#a$SaveSub or #a$RestoreSub { meta=1; }

      if aflag==0
      {   i=inputobjs->1;
          inp1=inputobjs->2;
          inp2=inputobjs->3;
      }
      if aflag~=0
      {   i=2;
      }
      multiflag=0;
      if i==0 { Process(0,0); }
      if i>0
      {   if inp1~=0 { Process(inp1,inp2); }
          if inp1==0
          {   multiflag=1;
              j=multinps->0;
              if j==0 { print "Nothing to do!^"; jump Error; }
              for k 1 to j
              {   l=multinps->k; print_obj l; print ": ";
                  Process(l,inp2);
              }
          }
      }
      .timeslice;
      if deadflag==0 { if meta==0 { Time(); } }
  }
  print "^^    ***";
  if deadflag==1 { print " You have died "; }
  if deadflag==2 { print " You have won "; }
  print "***^^^";
  ScoreSub();

  .RRQPL;
  print "^Would you like to RESTART, RESTORE a saved game or QUIT?^";
  .RRQL;
  print_char '?'; print_char ' ';
  read buffer parse;
  i=parse-->1;
  if i==#w$quit or #w$q { quit; }
  if i==#w$restar { restart; }
  if i==#w$restor { RestoreSub(); jump RRQPL; }
  print "Please answer RESTART, RESTORE or QUIT.^";
  jump RRQL;
];

[ Process i j;
  inp1 = i; inp2 = j;
  if location~=0
  {   i=prop(location,preroutine);
      if i~=$ffff
      {   if indirect(i)~=0 { ret#true; }
      }
  }
  if inp1~=0
  {   i=prop(inp1,preroutine);
      if i~=$ffff
      {   if indirect(i)~=0 { ret#true; }
      }
  }
  j=#actions_table-->action;
  indirect(j);
];

[ PostAct i k;

  k=location; i=prop(k,postroutine);
  if i==$ffff { jump NoLocPost; }
  if indirect(i)~=0 { ret#true; }

  .NoLocPost;
  k=0; i=inputobjs->1;
  if i~=0 { k=inp1; }
  if k==0 { ret#false; }
  i=prop(k,postroutine);
  if i==$ffff { ret#false; }
  indirect(i);
  return sp;
];

[ LPostAct i k;
  k=location;
  if k==0 { ret#false; }
  i=prop(k,postroutine);
  if i==$ffff { ret#false; }
  indirect(i);
  return sp;
];

[ Banner i;
  print_paddr #Story;
  print "^An Interactive Demonstration^\
         Copyright (c) YYYY Authors Name . Rights Notice.^\
         Release ";
  print_num (0-->1) & $03ff;
  print " / Serial number ";
  for i 18 to 23
  {   print_char 0->i;
  }
  print "  (Compiled by Inform v"; inversion; print ")^";
];

[ Time i j k;
  inc turns;

! Insert any timer dependant code here.

  i=lightflag;
  lightflag=OffersLight(parent(player));

  if i==0
  {   if lightflag==1 { new_line; location=parent(player); LookSub(1); }
  }
  if i==1
  {   if lightflag==0 { new_line; print "It is now pitch dark in here!^"; location=thedark; }
  }
];

! Check for Time up on an object.

[ TimeUp i j;
  j=prop(i,timeleft);
  if j>turns { ret#false; }
  if j==0 { ret#false; }
  put_prop i timeleft 0;
  ret#true;
];

[ DecTimeUp i j;
  j=prop(i,timeleft);
  if j==0 { ret#false; }
  dec j; put_prop i timeleft j;
  if j>0 { ret#false; }
  ret#true;
];

[ SetTimer i j;
  j=turns+j;
  put_prop i timeleft j;
];

[ Clock i j;
  j=prop(i,timeleft)-turns;
  return j;
];

[ OffersLight i;
  if i has light { ret#true; }
  if i has container
  {   if i has interior
      {   if i hasnt open { ret#false; }
      }
  }
  i=child(i);
  while i~=0
  {   if 1==OffersLight(i) { ret#true; }
      i=sibling(i);
  }
  ret#false;
];

! ---------------------------------------------------------------------------------------------------
! Verb action routines
! ---------------------------------------------------------------------------------------------------

[ ScoreSub rsc;
  if deadflag==0
  {   print "You have so far scored ";
  }
  if deadflag > 0 { print "In that game you scored "; }
  print_num score; print " out of a possible "
  print_num maxscore; print ", in ";
  print_num turns; print " turns, earning you the rank of ";

! Change rating to suit your game.

  rsc=score;

  if rsc >= 35 { print_ret "navigator."; }
  if rsc >= 20 { print_ret "adventurer."; }
  if rsc >= 5 { print_ret "explorer."; }
  if rsc >= 1 { print_ret "tourist."; }
  print_ret "somnambulist.";
];

[ QuitSub i;
  print "Are you sure you want to quit? ";
  .QSL; read buffer parse;
  i=parse-->1;
  if i==#w$yes or #w$y { quit; }
  if i==#w$no or #w$n { ret#true; }
  print "Please answer yes or no.";
  print_char '>'; print_char ' ';
  jump QSL;
];

[ QQuitSub; quit; ];

[ RestartSub i;
  print "Are you sure you want to restart? ";
  .RSL; read buffer parse;
  i=parse-->1;
  if i==#w$yes { restart; }
  if i==#w$y   { restart; }
  if i==#w$no  { ret#true; }
  if i==#w$n   { ret#true; }
  print "Please answer yes or no.";
  print_char '>'; print_char ' ';
  jump RSL;
];

[ RestoreSub;
  restore Rmaybe;
  print_ret "Failed.";
  .RMaybe; print "Ok.^";
];

[ SaveSub;
  save Smaybe;
  print_ret "Failed.";
  .Smaybe; print "Ok.^";
];

[ ScriptOnSub i;
  if scr_mode==1 { print_ret "Transcripting is already on."; }
  scr_mode=1;
  i=(0-->8)|1;
  put 0 word 8 i;
  print "Start of a transcript of^";
  Banner();
];

[ ScriptOffSub i;
  if scr_mode==0 { print_ret "Transcripting is already off."; }
  print "^End of transcript.^";
  scr_mode=0;
  i=(0-->8)&$fffe;
  put 0 word 8 i;
];

[ InvSub i;
  i=child(player);
  if i==0
  {   print_ret "You are carrying nothing."; }
  print "You are carrying:^";
  Inventory(player);
];

[ Inventory obj n o2 i;
  o2=1;
  if n~=0
  {   for i 1 to n { print "  "; }
      o2=DescribeObj(obj,0); new_line;
  }
  if o2==0 { ret#true; }

  o2=child(obj);
  while o2~=0
  {   Inventory(o2,n+1); o2=sibling(o2);
  }
];

[ TakeSub i;
  i=RTakeSub(location);
  if i~=0  { ret#true; }
  if 1==PostAct() { ret#true; }
  print "Taken.^";
];

[ RTakeSub fromobj i j k;
  if inp1==player
  {   print_ret "As the bishop said to the actress."; }
  if inp1 has animate
  {   print "I don't suppose "; DefArt(inp1); print_ret " would care for that."; }
  i=parent(inp1);
  if i==player
  {   print_ret "You already have that."; }
  while i~=fromobj
  {   if i hasnt container { print_ret "That isn't available."; }
      if i hasnt open { print "Unfortunately the "; print_obj i; print_ret " isn't open."; }
      i=parent(i);
      if i==player { i=fromobj; }
  }
  if inp1 has scenery { print_ret "That's hardly portable."; }
  if inp1 has static { print_ret "Fixed in place."; }
  j=child(player); k=0; while j~=0 { if j hasnt worn { k=k+prop(j,weight); } j=sibling(j); }
  if k>max_carry
  {   print_ret "You're carrying too many things already."; }
  remove_obj inp1;
  insert_obj inp1 player;
  if inp1 hasnt moved
  {   set_attr inp1 moved;
      if inp1 has scored { score=score+prop(inp1,score_value); }
  }
  ret#false;
];

[ DropSub i j k;
  i=parent(inp1);
  if i==location
  {   print_ret "Already on the floor."; }
  if i~=player
  {   print_ret "You haven't got that."; }
  if inp1 has worn
  { print "(First taking it off)^"; clear_attr inp1 worn; }
  remove_obj inp1;
  i=parent(player);
  insert_obj inp1 i;
  if 1==PostAct() { ret#true; }
  print "Dropped.^";
];

[ RemoveSub i;
  i=parent(inp1);
  if i hasnt open { print_ret "Alas, it is closed."; }
  if i~=inp2 { print_ret "But it isn't there now."; }
  if inp2 has worn { print_ret "You'll need to take it off first."; }
  i=RTakeSub(inp2);
  if i~=0  { ret#true; }
  action=#a$TakeSub;
  if 1==PostAct() { ret#true; }
  action=#a$RemoveSub;
  if 1==PostAct() { ret#true; }
  print "Removed.^";
];

[ InsertSub i;
  if inp2==d_obj  { action=#a$DropSub; Process(inp1,0); ret#false; }
  i=parent(inp1);
  if i~=player { print_ret "You need to be holding it before you can put it into something else."; }
  if inp2 hasnt container { print_ret "That can't contain things."; }
  if inp2 hasnt open { print_ret "Alas, it is closed."; }
  if inp2 has worn { print_ret "You'll need to take it off first."; }
  if inp1 has worn { print "(first taking it off)^"; clear_attr inp1 worn; }

  remove_obj inp1; insert_obj inp1 inp2;

  if 1==LPostAct() { ret#true; }
  if multiflag==1 { print_ret "Done."; }
  print "You put the "; print_obj inp1; print " into the "; print_obj inp2; print_ret ".";
];

[ TransferSub i a;
  a=#a$InsertSub; if inp2==d_obj { a=#a$DropSub; }
  i=parent(inp1);
  if i~=player
  {   while i~=0
      {   if i hasnt open { print_ret "That isn't in your possession."; }
          i=parent(i);
          if i==player { jump Segue; }
      }
      print_ret "First pick that up.";
  }
  .Segue; remove_obj inp1; insert_obj inp1 player; action=a; Process(inp1,inp2); ret#false;
];

[ EmptySub;
  inp2=d_obj;
  EmptyTSub();
];

[ EmptyTSub i j;
  if inp1 hasnt container { CDefArt(inp1); print_ret " can't contain things."; }
  if inp1 hasnt open { CDefArt(inp1); print_ret " is closed."; }
  if inp2~=d_obj
  {   if inp2 hasnt container { CDefArt(inp2); print_ret " can't contain things."; }
      if inp2 hasnt open { CDefArt(inp2); print_ret " is closed."; }
  }
  i=inp1; i=child(i);
  if i==0 { DefArt(inp1); print_ret " is empty already."; }
  while i~=0
  {   j=sibling(i);
      print_obj i; print ": ";
      action=#a$TransferSub; Process(i,inp2);
      i=j;
  }
];

[ EnterSub i;
  if inp1 has portal { GoSub(); ret#true; } 
  i=parent(player);
  if i~=location { print "But you're already in the "; print_obj i; print_ret "."; }
  if inp1 hasnt enterable { print_ret "A surreal idea."; }
  i=parent(inp1);
  if i==compass { GoSub(); ret#true; }
  if i~=location { print_ret "You can only get into something on the floor."; }
  remove_obj player;
  insert_obj player inp1;
  print "You get into the "; print_obj inp1; print_ret ".";
];

[ ExitSub i;
  i=parent(player);
  if i==location { print_ret "But you're aren't in anything at the moment."; }
  remove_obj player;
  insert_obj player location;
  print "You are on your own two feet again.^"; LookSub(1); ret#true;
];

[ VagueGoSub;
  print_ret "You'll have to say which compass direction to go in.";
];

[ GoSub i j k df movewith;

  movewith=0;
  i=parent(player);
  if location~=thedark
  {   
      if i~=location { print "You'll have to get out of the "; print_obj i; print_ret " first."; }
  }
  j=prop(i, prop(inp1, dirprop));
  if j==0
  {   print_ret "You can't go that way.";
  }
  if j has portal
  {   if j has concealed { print_ret "You can't go that way."; }
      if j hasnt open
      {   if inp1==u_obj { print "You are unable to climb "; Defart(j); print_ret "."; }
          if inp1==d_obj { print "You are unable to descend "; Defart(j); print_ret "."; }
          print "You can't, since "; Defart(j); print_ret " is in the way.";
      }
      j=prop(j,portalto);
      if j==0 { print "You can't, since "; Defart(j); print_ret " leads nowhere."; }
  }
  if movewith==0  {  remove_obj player; insert_obj player j;  }
  if movewith~=0
  {   if inp1==d_obj or u_obj { print_ret "It won't go that way."; }
      remove_obj movewith; insert_obj movewith j;
  }

  df=OffersLight(j);

  if df~=0 { location=j; lightflag=1; }
  if df==0
  {   
      location=thedark; lightflag=0;
  }

  if 1==LPostAct() { ret#true; }

  LookSub(1);
];

[ LookSub weary i j k o flag descin;
  descin=location;
  new_line; print_obj location; i=parent(player);
  if location~=thedark
  {   if i~=location { print " (in the "; print_obj i; print ")"; descin=i; }
  }
  new_line;

  if location has visited
  {   if weary==1 { jump NoLD; }
  }
  i = prop(location,longdesc);
  print_paddr i; new_line;
  .NoLD;

  if location hasnt visited
  {   set_attr location visited;
      if location has scored
      {   score=score+5;
      }
  }
  o=child(descin); k=0;
  while o~=0
  {   if o hasnt concealed
      {  if o hasnt scenery
         {   set_attr o workflag; inc k;
             if o hasnt moved
             {   j=prop(o,initpos);
                 if o has portal
                 {   if o hasnt open { j=prop(o,closedpos); }
                 }
                 if o has switchable
                 {   if o hasnt on { j=prop(o,closedpos); }
                 }
                 if j~=0
                 {   new_line;
                     print_paddr j; new_line; flag=1;
                     clear_attr o workflag; dec k;
                 }
             }
         }
      }
      o=sibling(o);
  }

  if k==0 { jump AskRoom; }
  new_line;
  if descin~=location { print "In the "; print_obj descin; print " you"; }
  if descin==location { print "You"; }
  print " can ";
  if flag==1 { print "also "; }
  print "see "; i=0;
  o=child(descin);
  while o~=0 { 
   if o has workflag
   {  i=i+1;
      DescribeObj(o,1);
      if i==k-1 { print " and "; }
      if i < k-1 { print ", "; }
   }
   o=sibling(o);
  }
  if descin~=location { print ".^"; }
  if descin==location { print " here.^"; }

  .AskRoom;

  action=#a$LookSub;
  if 1==LPostAct() { ret#true; }
];

[ ExamineSub i;
  if location==thedark { print_ret "Darkness, noun.  An absence of light to see by."; }

  if inp1 has autosearch { SearchSub(); ret#false; }
  i=prop(inp1,longdesc);
  if i==0
  {   if inp1 has container { SearchSub(); ret#false; }
      print "You see nothing special about "; Defart(inp1); print_ret ".";
  }
  print_paddr i; new_line;
  if inp1 has switchable
  {   print "It is currently switched ";
      if inp1 has on { print "on.^"; }
      if inp1 hasnt on { print "off.^"; }
  }
  if 1==PostAct() { ret#true; }
];

[ DescribeObj o listmode p p2 i k rval;

  if listmode ~=2 { Indefart(o); }
  if listmode ==2 { Defart(o); }

  if o has light { print " (providing light)"; }
  if o has worn { print " (being worn)"; }
  if o has container
  {   if listmode ~=2 { print " (which is "; }
      if listmode ==2 { print ", which is "; }
      if o hasnt open
      { print "closed";
        if o has interior { jump Cdone; }
      }
      if o has open { print "open"; }
      p=child(o);
      if p==0
      {   print " but empty";
          jump Cdone;
      }
      if listmode==0 { rval=1; jump Cdone; }
      print " and contains ";
      k=0; p2=p; while p2~=0 { p2=sibling(p2); inc k; }

      i=0; while p~=0 { inc i; DescribeObj(p,1);
        if i==k-1 { print " and "; }
        if i < k-1 { print ", "; }
        p=sibling(p);
      }
      .Cdone;
      if listmode ~=2 { print ")"; }
  }
  return rval;
];

[ GiveSub i j;
  print_obj inp2; print_ret " doesn't seem interested.^";
];

[ UnlockSub i;
  if inp1 hasnt lockable { print_ret "I can't see how to unlock that."; }
  if inp1 hasnt locked { print_ret "It is in fact unlocked now."; }
  i=prop(inp1,with_key);
  if i~=inp2 { print_ret "That doesn't seem to fit the lock."; }
  clear_attr inp1 locked;
  if 1==PostAct() { ret#true; }
  print "You unlock the "; print_obj(inp1); print ".^";
];

[ LockSub i;
  if inp1 hasnt lockable { print_ret "I can't see how to lock that."; }
  if inp1 has locked { print_ret "It is in fact locked now."; }
  if inp1 has open { print_ret "First you'll have to close it."; }
  i=prop(inp1,with_key);
  if i~=inp2 { print_ret "That doesn't seem to fit the lock."; }
  set_attr inp1 locked;
  if 1==PostAct() { ret#true; }
  print "You lock the "; print_obj(inp1); print ".^";
];

[ SwitchonSub;
  if inp1 hasnt switchable { print_ret "That's not something you can switch."; }
  if inp1 has on { print_ret "It's already on."; }
  set_attr inp1 on;
  if 1==PostAct() { ret#true; }
  print "You switch the "; print_obj(inp1); print " on.^";
];

[ SwitchoffSub;
  if inp1 hasnt switchable { print_ret "That's not something you can switch."; }
  if inp1 hasnt on { print_ret "It's already off."; }
  clear_attr inp1 on;
  if 1==PostAct() { ret#true; }
  print "You switch the "; print_obj(inp1); print " off.^";
];

[ OpenSub;
  if inp1 hasnt openable { print_ret "That's not something you can open."; }
  if inp1 has locked { print_ret "It seems to be locked."; }
  if inp1 has open { print_ret "It's already open."; }
  set_attr inp1 open;
  if 1==PostAct() { ret#true; }
  print "You open the "; print_obj(inp1); print ".^";
];

[ CloseSub;
  if inp1 hasnt openable { print_ret "That's not something you can close."; }
  if inp1 hasnt open { print_ret "It's already closed."; }
  clear_attr inp1 open;
  if 1==PostAct() { ret#true; }
  print "You close the "; print_obj(inp1); print ".^";
];

[ DisrobeSub;
  if inp1 hasnt worn { print_ret "You're not wearing that."; }
  clear_attr inp1 worn;
  print "You take off the "; print_obj(inp1); print ".^";
];

[ WearSub i;
  if inp1 hasnt clothing { print_ret "You can't wear that!"; }
  i=parent(inp1);
  if i~=player { print_ret "You're not holding that!"; }
  set_attr inp1 worn;
  if 1==PostAct() { ret#true; }
  print "You put on the "; print_obj(inp1); print ".^";
];

[ RhetSub;
  print_ret "That was a rhetorical question.";
];

[ MagicWordSub;
  print_ret "For a moment you can almost hear a hoarse voice say something to you.  But it passes.";
];

[ BurnSub;
  print_ret "In this game, arson is (usually) forbidden.";
];

[ PraySub;
  print_ret "Spooky!  For a moment there, a deep voice seemed to say ~you're on your own~.";
];

[ WakeSub;
  print_ret "The dreadful truth is, this is not a dream.";
];

[ WakeOSub;
  print_ret "That seems unnecessary.";
];

[ KissSub;
  print_ret "Keep your mind on the game.";
];

[ ThinkSub;
  print_ret "Worth a try, anyway.  Why don't you?";
];

[ SmellSub;
  print_ret "You smell nothing unexpected.";
];

[ ListenSub;
  print_ret "You hear nothing unexpected.";
];

[ TasteSub;
  print_ret "You taste nothing unexpected.";
];

[ TouchSub;
  print_ret "You feel nothing unexpected.";
];

[ TouchTSub;
  if inp1 has animate { print_ret "Keep your hands to yourself!"; }
  print_ret "You feel nothing unexpected.";
];

[ DigSub;
  print_ret "The ground is unsuitable for digging here.";
];

[ CutSub;
  print_ret "In this game, cutting things up is never helpful.";
];

[ JumpsSub;
  print_ret "You jump on the spot, fruitlessly.";
];

[ JumpSub;
  print_ret "In this game, it is never useful to jump over things.";
];

[ TieSub;
  print_ret "In this game, it is never useful to tie things.";
];

[ DrinkSub;
  print_ret "There's nothing suitable to drink here.";
];

[ FillSub;
  print_ret "But there's no water here to carry.";
];

[ SorrySub;
  print_ret "Oh, don't apologise.";
];

[ StrongSub i;
  print_ret "Disgraceful!  Once upon a time adventurers had moral standards.";
];

[ MildSub;
  print_ret "Quite.";
];

[ AttackSub;
  print_ret "Violence isn't the answer, you know.";
];

[ SwimSub;
  print_ret "There's not enough water to swim in.";
];

[ SwingSub;
  print_ret "There's nothing sensible to swing here.";
];

[ BlowSub;
  print_ret "You can't usefully blow that.";
];

[ RubSub;
  print_ret "You achieve nothing by this.";
];

[ SetSub i j;
  print_ret "No, you can't set that.";
];

[ EatSub;
  if inp1 hasnt edible { print_ret "No, it's plainly inedible."; }
  remove inp1;
  print "You eat the "; print_obj inp1; print_ret ".  Not bad.";
];

[ WaveNSub;
  print_ret "You wave, feeling foolish.";
];

[ WaveSub i;
  i=parent(inp1);
  if i~=player { print_ret "But you aren't holding it."; }
  print "You look ridiculous waving the "; print_obj inp1;
  print_ret ".";
];

[ PullSub i j;
  if inp1 has static { print_ret "It is fixed in place."; }
  if inp1 has scenery { print_ret "You are unable to."; }
  print_ret "Nothing obvious happens.";
];

[ PushSub i;
  if inp1 has static { print_ret "It is fixed in place."; }
  if inp1 has scenery { print_ret "You are unable to."; }
  print_ret "Nothing obvious happens.";
];

[ PushDirSub i;
  i=parent(inp2);
  if i~=compass { print_ret "That's not a direction."; }
  if inp2==u_obj or d_obj { print_ret "Not that way you can't."; }
  print_ret "Sorry, nothin here to push.";
];

[ TurnSub;
  if inp1 has static { print_ret "It is fixed in place."; }
  if inp1 has scenery { print_ret "You are unable to."; }
  print_ret "Nothing obvious happens.";
];

[ SqueezeSub i;
  if inp1 has animate { print_ret "Keep your hands to yourself."; }
  print_ret "You achieve nothing by this.";
];

[ LookUnderSub i;
  print_ret "You find nothing of interest.";
];

[ SearchSub i j;
  if inp1 hasnt container
  {   print_ret "You find nothing of interest."; }
  if inp1 has interior
  {   if inp1 hasnt open
      {   print_ret "You can't see inside, since it is closed."; }
  }
  if 1==PostAct() { ret#true; }
  print "You peer at ";
  DescribeObj(inp1,2); print_ret ".";
];

[ Indefart o;
  if o hasnt proper { print_paddr prop(o,article); print " "; }
  print_obj(o);
];

[ Defart o;
  if o hasnt proper { print "the "; }
  print_obj(o);
];

[ CDefart o;
  if o hasnt proper { print "The "; }
  print_obj(o);
];

[ ThrowAtSub i j;
  if inp2 hasnt animate { print_ret "Futile."; }
  print_ret "You lack the nerve when it comes to the crucial moment.";
];

[ AnswerSub i j c;
  print_ret "No reply.";
];  

[ BuySub i;
  print_ret "Nothing is on sale.";
];

[ AskSub;
  print_ret "No reply.";
];  

[ SingSub;
  if random(2)==1 { print "Your yodelling "; }
  else { print "Your singing "; }
  print_ret "is atrocious, if you say so yourself.";
];

[ ClimbSub;
  print_ret "I don't think much is to be achieved by that.";
];  

[ WaitSub;
  print_ret "Time passes.";
];  

[ EchoSub;
  print_ret "There isn't an echo here.";
];  

[ SleepSub i j;
  print_ret "You must have slept yourself out.  You certainly aren't drowsy now.";
];

[ HelpSub i;
  Banner();
  DescribeObj(help);
  ret#true;
];

! ---------------------------------------------------------------------------------------------------
! The Z-code part of the parser
! ---------------------------------------------------------------------------------------------------

global wn;
global nwords;
global mmode;
global mfilter;
global allmode;
global verbn;
global pstack data 16;
global pspare data 16;
global pcount;
global pcounts;
global inferfrom;
global inferword;
global oops_from = 0;
global e_oops = 0;
global oops_heap data 16;

global matchlist data 64;
global match_p;
global match_t;
global match_w;
global indef_mode;
global wnbase;

[ Keyboard b p nw i w x1 x2;
    .KAgain;
    for i 0 to 9 { put oops_heap byte i p->i; }
    new_line; print_char '>'; read b p;
    .KKAgain;
    nw=p->1; w=p-->1;
    if nw == 0
    { print "I beg your pardon?^"; jump KAgain; }
    if w == oops_word { jump dooops; }
    if w ~= o_word { return nw; }
    .dooops;
    if oops_from == 0 { print "Sorry, that can't be corrected.^"; jump KAgain; }
    if nw == 1 { print "Think nothing of it.^"; jump KAgain; }
    if nw > 2 { print "~Oops~ can only correct a single word.^"; jump KAgain; }
    x1=p-->3; x2=p-->4;
    for i 0 to 9 { put p byte i oops_heap->i; }
    w=2*oops_from - 1;
    put p word w x1;
    inc w;
    put p word w x1;
    return nw;
];

[ Input ibuff parset cl clines pline i j k l m o etype amode allwn allk;
    
  .Retry;

    Keyboard(buffer,parse);

  .Retrynotk;
    nwords=parse->1;
    etype=1;
    wnbase=1;
    actor=player;
  .BeginComm;
    wn=wnbase;
    verbn = NextWord();
    if verbn==g_word { verbn=again_word; }
    if verbn==again_word { ret#true; }
    if verbn==0
    {   etype=11; jump GiveError;
    }
    i=(verbn->4) & 1;
    if i==0
    {   wn=wnbase;
        l=NounDomain(compass,0,0);
        if l==1000 { jump Retrynotk; }
        if l~=0 
        {   put ibuff byte 1 1;
            put ibuff byte 0 #a$GoSub;
            put ibuff byte 2 l;
            ret#true;
        }
        if actor==player
        {   for j 2 to nwords
            {   i=NextWord(); if i==comma_word { jump Converse; }
            }
        }
        etype=11; jump GiveError;
        .Converse;
        j=wn-1; k=6;
        if j==1 { print "You can't begin with a comma.^"; jump Retry; }
        wn=1;
        l=NounDomain(player,location,k);
        if l==1000 { jump RetryNotK; }
        if l==0 { print "You seem to want to talk to someone, but I can't see whom.^"; jump Retry; }
        if l has talkable { jump CTAA; }
        if l hasnt animate { print "You can't talk to "; DefArt(l); print ".^"; jump Retry; }
        .CTAA;
        if wn~=j { print "To talk to someone, try ~someone, hello~ or some such.^"; jump Retry; }
        wnbase=j+1; actor=l;
        jump BeginComm;
    }

    i=$ff-(verbn->5);
    parset=(0-->7)-->i;
    clines=(parset->0)-1;

    for cl 0 to clines;
    {   wn=wnbase+1;
        pline=parset+1+cl*8; inferfrom=0;
        j=0; allmode=0;
        for pcount 1 to 6;
        {   put pstack word pcount 0;
            k=pline->pcount;
            if k>7
            {   put pstack word pcount 1000+k;
                if wn > nwords
                {   if inferfrom==0
                    {   if j< pline->0 { inferfrom=pcount; inferword=k; }
                    }
                    if inferfrom==0 { break; }
                }
                if wn <= nwords
                {   if k~=Adjective(parse) { break; } }
                jump Back;
            }
            if j == pline->0
            {  
           
                if wn < nwords+1
                {   for m 0 to 7 { put pspare word m pstack-->m; }
                    pcounts=pcount;
                    etype=2; break; }
                if allmode==1 { wn=allwn; k=allk; jump OList; }
                .AllDone;
                put ibuff byte 1 pline->0;
                put ibuff byte 0 pline->7;
                if j > 0 { itobj=ibuff->2; }
                oops_from = 0;
                ret#true;
            }

            mmode=0; amode=0;

            .OList;
            o=NextWord(); dec wn;
            if o==it_word  { if itobj==0 { etype=8; break; }   }    
            if o==them_word  { if itobj==0 { etype=8; break; }   }    

            indef_mode=0;
            if o==the_word { inc wn; jump OList; }
            if o==a_word { inc wn; indef_mode=1; }
            if o==an_word { inc wn; indef_mode=1; }

            if k==7
            {   special_number=TryNumber(wn);
                special_word=NextWord();
                put ibuff byte j+2 $ff;
                j=j+1;
                put pstack word pcount $ff;
                jump KeepGoing;
            }

            mfilter=0;
            
            if o==everyt_word { o=all_word; }
            if o==both_word { o=all_word; }
            if o==all_word
            {   if k<2 { etype=6; break; }
                if k>=6 { etype=6; break; }
                inc allmode;
                if allmode>2 { etype=7; break; }
                if allmode==2
                {   if k==5 { DoAll(ibuff->3); }
                    if k==4 { DoAll(actor); o=parent(ibuff->3);
                              if o==actor { MultiSub(ibuff->3); }
                            }
                    if k==2 { DoAll(location); }
                    if k==3 { DoAll(actor); }
                    if mfilter~=0 { MultiFilter(mfilter); }
                }
                if allmode==1
                {   allwn=wn; allk=k; DoAll(location);
                }
                inc wn;
                jump Exceptions;
            }

            oops_from=wn;

            if k~=1
            {   l=NounDomain(location, actor, k);
                if l==1000 { jump Retrynotk; }
                if l==0 { etype=3; e_oops=oops_from; break; }
                if k==6
                {   if l hasnt animate
                    {   etype=10; break; }
                }
                if amode==0
                {   put ibuff byte j+2 l;
                    j=j+1;
                    put pstack word pcount l;
                }
                if amode==1
                {   MultiAdd(l); }
                if amode==2
                {   m=MultiSub(l); if allmode~=1 { if m~=0 { etype=m; break; } } }
            }
            if k==1
            {   l=NounDomain(actor,location,k);
                if l==1000 { jump Retrynotk; }
                if l==0 { etype=3; e_oops=oops_from; break; }
                o=parent(l);
                if o~=actor { etype=5; e_oops=oops_from; break; }
                put ibuff byte j+2 l;
                j=j+1;
                put pstack word pcount l;
            }

            .KeepGoing;
            o=NextWord();
            if 0~=Refers(l,o) { jump KeepGoing; }
            if o==comma_word { o=and_word; }
            if o==and_word
            {   if k<2 { etype=6; break; }
                if k>=6 { etype=6; break; }
                if mmode==0 { put multinps byte 0 1;
                put multinps byte 1 l; j=j-1; mmode=1; }
                if amode==0 { amode=1; }
                jump Olist;
            }
            wn=wn-1;
 
            .Resume;
            if allmode==2
            {   jump AllDone;
            }
            if mmode==1
            {   put ibuff byte j+2 0;
                put pstack word pcount 0;
                j=j+1;
            }

            .Back;
        }
    }

    .GiveError;
    if actor~=player
    {   special_number=TryNumber(wnbase);
        wn=wnbase;
        special_word=NextWord();
        action=#a$AnswerSub;
        inp1=1; inp2=actor; actor=player;
        ret#true;
    }

    if etype==1 { print "I didn't understand that sentence.^"; oops_from=1; }
    if etype==2 { print "I only understood you as far as wanting to ";
                  for m 0 to 7 { put pstack word m pspare-->m; }
                  pcount=pcounts;
                  Pcommand(0,1);
                  print ".^";
                }
    if etype==3 { print "You can't see any such thing.^"; oops_from=e_oops; }
    if etype==4 { print "You seem to have said too little!^"; }
    if etype==5 { print "You aren't holding that!^"; oops_from=e_oops; }
    if etype==6 { print "You can't use multiple objects with that verb.^"; }
    if etype==7 { print "You can only use multiple objects once on a line.^"; }
    if etype==8 { print "I'm not sure what 'it' refers to.^"; }
    if etype==9 { print "You excepted something not included anyway!^"; }
    if etype==10 { print "You can only do that to something animate.^"; }
    if etype==11 { print "That's not a verb I recognise.^"; }
    jump Retry; 

    .Exceptions;
    o=NextWord();
    if o==the_word { jump Exceptions; }
    if o==except_word { o=but_word; }
    if o==but_word { amode=2; jump Olist; }
    wn=wn-1;
    jump Resume;

    for i 1 to nwords
    {   j=parse-->(2*i-1);
        if j==0 { print "unknown "; }
        if j~=0 { print_addr j; print_char ' '; }
    }
    new_line;

];

[ MultiAdd o i j;
  i=multinps->0;
  if i==16 { toomanyf=1; ret#true; }
  for j 1 to i
  {   if o==multinps->j { ret#true; }
  }
  i=i+1;
  put multinps byte i o;
  put multinps byte 0 i;
];

[ MultiFilter attr i j o;
  .MFiltl;
  i=multinps->0;
  for j 1 to i
  {   o=multinps->j;
      if o hasnt attr { MultiSub(o); jump Mfiltl; }
  }
];

[ MultiSub o i j k et;
  i=multinps->0;
  for j 1 to i
  {   if o==multinps->j
      {   for k j to i { put multinps byte k multinps->(k+1); }
          i=i-1;
          put multinps byte 0 i;
          et=0; return et;
      }
  }
  et=9; return et;
];

[ DoAll domain i;
  mmode=1; put multinps byte 0 0;
  domain=child(domain);
  while domain~=0
  {   if domain hasnt concealed
      {   if domain hasnt worn
          { MultiAdd(domain); }
      }
      domain=sibling(domain);
  }
];

[ Adjudicate context i j k l m n;
  j=match_p-1; k=0; l=matchlist->0;
  for i 0 to j
  {   n=matchlist->i;
      if n has concealed { jump NeverHaveIt; }
      m=parent(n);
      if context==1 { if m==actor { inc k; l=n; } }
      if context==3 { if m==actor { inc k; l=n; } }
      if context==4 { if m==actor { inc k; l=n; } }
      if context==5 { if m==actor { inc k; l=n; } }
      if context==6 { if n has animate { inc k; l=n; } }
      if context==0 { if m==location { inc k; l=n; } }
      if context==2 { if m==location { inc k; l=n; } }
      .NeverHaveIt;
  }
  if k==1 { return l; }
  if indef_mode==1 { return l; }
  ret#false;
];

[ NounDomain domain1 domain2 context i j k oldw a;
  match_t=0; match_p=0; match_w=wn;

  NounD(domain1); NounD(domain2);
  wn=match_w+match_t;
  if match_p==0 { inc wn; ret#false; }
  if match_w <= nwords
  {   i=matchlist->0;
      if match_p==1 { return i; }
  }
  if match_p>1  { i=Adjudicate(context); }

  if i~=0
  {   if inferfrom==0 { inferfrom=pcount; }
      put pstack word pcount i;
      print "("; Pcommand(inferfrom,0); print ")^";
      return i;
  }

  if match_w > nwords { jump Incomp; }

  print "Which do you mean, ";
  j=match_p-1;
  for i 0 to j
  {   k=matchlist->i; Defart(k);
      if i<j-1 { print ", "; }
      if i==j-1 { print " or "; }
  }
  print "?^";

  .Whichl;
  a=Keyboard(buffer2, parse2);

  j=(parse2-->1);

  if j==both_word { j=all_word; }
  if j==everyt_word { j=all_word; }
  if j==all_word
  { print "Sorry, that's beyond my abilities.  Which one exactly?^"; jump Whichl; }

  j=j->4;
  if 0~=j&1
  {   Copy(buffer, buffer2);
      Copy(parse, parse2);
      k=1000; return k;
  }
  oldw=parse->1;
  put parse byte 1 a+oldw;

  k=oldw+a;
  while k>match_w
  {   i=k-a; MoveWord(k, parse, i);
      dec k;
  }
  for k 1 to a
  {   i=match_w+k-1; MoveWord(i, parse2, k);
  }
  k=1000; return k;


  .Incomp;
  print "What do you want ";
  if actor~=player { DefArt(actor); }
  print "to ";
  Pcommand(0,1);

  print "?^";

  a=Keyboard(buffer2, parse2);

  j=(parse2-->1);

  j=j->4;
  if 0~=j&1
  {   Copy(buffer, buffer2);
      Copy(parse, parse2);
      k=1000; return k;
  }
  oldw=parse->1;

  if inferfrom==0
  {   for k 1 to a
      {   i=match_w+k-1; MoveWord(i, parse2, k);
      }
  }
  if inferfrom~=0
  {   for k 1 to a
      {   i=match_w+k; MoveWord(i, parse2, k);
      }
      put parse2 word 1 Adjadd(inferword);
      MoveWord(match_w, parse2, 1);
      inc a; 
  }
  put parse byte 1 a+oldw;
  k=1000; return k;
];

[ Pcommand from emptyf i j k f m n;
  if from==0
  {   i=parse-->1; from=1; f=1;
      if i==#w$invent { print "take an inventory"; jump vprinted; }
      if i==#w$examine { print "examine"; jump vprinted; }
      if i==#w$discard { print "discard"; jump vprinted; }
      print_addr i;
  }
  .vprinted;
  j=pcount-emptyf;
  for k from to j
  {   if f==1 { print_char ' '; }
      i=pstack-->k;
      if i==0 { print "those things"; jump eopcl; }
      if i==$ff { print "that"; jump eopcl; }
      if i<256 { Defart(i); }
      if i>=1000
      {   i=i-1000;
          print_addr Adjadd(i);
      }
      .eopcl;
      f=1;
  }
];

[ Adjadd i n m;
  m=#adjectives_table;
  while 1==1
  {   n=m-->1;
      if n==i
      {   m=m-->0; return m;
      }
      m=m+4;
  }
];

[ MoveWord at1 b2 at2 x y;
  x=at1*2-1; y=at2*2-1;
  put parse word x b2-->y;
  inc x; inc y;
  put parse word x b2-->y;
];

[ NPutin obj thresh;
  if thresh < match_t { ret#true; }
  if thresh > match_t { match_t=thresh; match_p=0; }
  put matchlist byte match_p obj;
  inc match_p;
];

[ NounD domain i j k o matched thresh;
  if domain==location { i=NounD(compass); }

  domain=child(domain);
  while domain~=0
  { if match_w > nwords { NPutin(domain,1); jump DontAccept; }
    wn=match_w;
    i=Noun();
    if i==1 { if itobj==domain { NPutin(itobj,1); } }
    if 0 == Refers(domain, i) { jump DontAccept; }
        thresh=0;
        .KGL; 
        inc thresh;
        o=NextWord(); if 0~=Refers(domain,o) { jump KGL; }
        NPutin(domain,thresh);
    .DontAccept;
    if domain has container
    {   if domain has open { jump DoDown; }
        if domain has interior { jump DontDown; }
        .DoDown;  k=child(domain);
          if k~=0  { k=NounD(domain); }
        .DontDown;
    }
    domain=sibling(domain);
  }
  ret#false;
];

[ Refers o w j k l m;
    k=prop_addr(o,1); l=(prop_len(k)/2)-1;
    for m 0 to l
    {   j=k-->m; if w==j { ret#true; }
    }
    ret#false;
];

[ Noun ncount i j;
  ncount=0;
  i=NextWord();
  if i==it_word { j=1; return j; }
  if i==them_word { j=1; return j; }
  if i==0 { ret#false; }
  j=i-->4;
  if j&128 == 0 { ret#false; }

  return i;
];

[ Adjective parse i j;
  j=NextWord();
  if j==0 { ret#false; }
  i=j->4;
  if i&8 == 0 { ret#false; }
  return(j->5);
];

[ NextWord i j k;
  if wn > (parse->1) { wn=wn+1; ret#false; }
  i=wn*2-1; wn=wn+1;
  j=parse-->i;
  if j==0
  {   k=wn*4-3; i=buffer->(parse->k);
      if i==',' { j=comma_word; }
  }
  return j;
];

[ HitComma i j k l;
  l=wn-1;
  if l > (parse->1) { ret#false; }
  i=l*4;
  j=parse->i;
  k=parse->(i+1);
  k=k+j;
  print "Word "; print_num l; print " ends with ";
  .HCL;
  i=buffer->k;
  if i==' ' { inc k; jump HCL; }
  if i==',' {   print "a comma^";
k=1; return k; }
  print "no comma^";
  k=0; return k;
];

[ Trynumber w i j c num len mul tot d digit;
  i=w*4+1; j=parse->i; num=j+buffer;
  len=parse->(i-1);
  if len>=4 { mul=1000; }
  if len==3 { mul=100; }
  if len==2 { mul=10; }
  if len==1 { mul=1; }
  tot=0; c=0; len=len-1;
  for c 0 to len
  {   digit=num->c;
      if digit=='0' { d=0; jump digok; }
      if digit=='1' { d=1; jump digok; }
      if digit=='2' { d=2; jump digok; }
      if digit=='3' { d=3; jump digok; }
      if digit=='4' { d=4; jump digok; }
      if digit=='5' { d=5; jump digok; }
      if digit=='6' { d=6; jump digok; }
      if digit=='7' { d=7; jump digok; }
      if digit=='8' { d=8; jump digok; }
      if digit=='9' { d=9; jump digok; }
      ret#false;
      .digok;
      tot=tot+mul*d;
      mul=mul/10;
  }
  return tot;
];

[ Empty buff i size;

  size=buff->0;
  for i 1 to size { put buff byte i 0; }
];

[ Copy bto bfrom i size;

  size=bto->0;
  for i 1 to size { put bto byte i bfrom->i; }
];

[ Dump buff i;

  print "Dump at ";  HexOut(buff);  new_line;
  for i 0 to 31
  {   HexOut(buff->i); print " ";  }
  new_line;
];

[ HexOut i j;
  j=(i/$10)/$10; if j ~= 0; { ; HexDig(j/$10); HexDig(j); } ; HexDig(i/$10); HexDig(i); ];
[ HexDig i;
  i=i % $10; if i<$a { print_char i+'0'; return; } print_char i+'a'-10;
];

! ---------------------------------------------------------------------------------------------------
! The grammar table
! ---------------------------------------------------------------------------------------------------

Verb "take" "get" "pick" "lift"      * "out"                          -> ExitSub
                                     * multi                          -> TakeSub
                                     * multiinside "from" noun        -> RemoveSub
                                     * "in" noun                      -> EnterSub
                                     * "off" held                     -> DisrobeSub;
Verb "stand"                         *                                -> ExitSub
                                     * "up"                           -> ExitSub;
Verb "remove" "shed"                 * held                           -> DisrobeSub
                                     * multiinside "from" noun        -> RemoveSub;
Verb "wear"                          * held                           -> WearSub;
Verb "put"                           * multiexcept "in" noun          -> InsertSub
                                     * multiexcept "into" noun        -> InsertSub
                                     * multiexcept "on" noun          -> InsertSub
                                     * "on" held                      -> WearSub
                                     * "down" multiheld               -> DropSub
                                     * multiheld "down"               -> DropSub;
Verb "insert"                        * multiexcept "in" noun          -> InsertSub
                                     * multiexcept "into" noun        -> InsertSub;
Verb "empty"                         * noun                           -> EmptySub
                                     * noun "to" noun                 -> EmptyTSub
                                     * noun "into" noun               -> EmptyTSub;
Verb "transfer"                      * noun "to" noun                 -> TransferSub;
Verb "drop" "throw" "discard"        * multiheld                      -> DropSub
                                     * multiexcept "in" noun          -> InsertSub
                                     * multiexcept "into" noun        -> InsertSub
                                     * multiexcept "down" noun        -> InsertSub
                                     * held "at" noun                 -> ThrowAtSub;
Verb "give" "pay" "offer" "feed"     * creature multiheld             -> GiveSub
                                     * multiheld "to" creature        -> GiveSub
                                     * "over" multiheld "to" creature -> GiveSub;
Verb "go" "walk" "run" "leave"       *                                -> VagueGoSub
                                     * noun                           -> GoSub
                                     * "through" noun                 -> EnterSub;
Verb "inventory" "i"                 *                                -> InvSub;
Verb "score"                         *                                -> ScoreSub;
Verb "look"                          *                                -> LookSub
                                     * "at" noun                      -> ExamineSub
                                     * "inside" noun                  -> SearchSub
                                     * "in" noun                      -> SearchSub
                                     * "under" noun                   -> LookUnderSub
                                     * "through" noun                 -> SearchSub;
Verb "open" "unwrap" "uncover" "undo"
                                     * noun                           -> OpenSub
                                     * noun "with" held               -> UnlockSub;
Verb "close" "shut" "cover"          * noun                           -> CloseSub;
Verb "enter"                         * noun                           -> EnterSub;
Verb "exit"                          *                                -> ExitSub;
Verb "examine" "x" "read" "watch" "descri" "check"
                                     * noun                           -> ExamineSub;
Verb "q" "quit" "die"                *                                -> QuitSub;
Verb "restore"                       *                                -> RestoreSub;
Verb "restart"                       *                                -> RestartSub;
Verb "save"                          *                                -> SaveSub;
Verb "script"                        *                                -> ScriptOnSub
                                     * "off"                          -> ScriptOffSub
                                     * "on"                           -> ScriptOnSub;
Verb "noscript"                      *                                -> ScriptOffSub;
Verb "yes" "y"                       *                                -> RhetSub;
Verb "no"                            *                                -> RhetSub;
Verb "sorry"                         *                                -> SorrySub;
Verb "shit" "fuck" "damn" "sod"      *                                -> StrongSub
                                     * special                        -> StrongSub;
Verb "bother" "curses" "drat" "darn" *                                -> MildSub
                                     * special                        -> MildSub;
Verb "search"                        * noun                           -> SearchSub;
Verb "wave"                          *                                -> WaveNSub
                                     * noun                           -> WaveSub;
Verb "set"                           * noun                           -> SetSub;
Verb "pull" "drag"                   * noun                           -> PullSub;
Verb "push" "move" "shift" "clear" "press"
                                     * noun                           -> PushSub
                                     * noun noun                      -> PushDirSub
                                     * noun "to" noun                 -> TransferSub;
Verb "turn" "rotate" "twist" "unscrew" "screw"
                                     * noun                           -> TurnSub
                                     * noun "on"                      -> SwitchonSub
                                     * noun "off"                     -> SwitchoffSub;
Verb "switch"                        * noun                           -> SwitchonSub
                                     * noun "on"                      -> SwitchonSub
                                     * noun "off"                     -> SwitchoffSub
                                     * "on" noun                      -> SwitchonSub
                                     * "off" noun                     -> SwitchoffSub;
Verb "lock"                          * noun "with" held               -> LockSub;
Verb "unlock"                        * noun "with" held               -> UnlockSub;
Verb "attack" "break" "smash" "hit" "fight" "wreck" "crack" "destro" "murder" "kill" "tortur"
                                     * noun                           -> AttackSub;
Verb "wait" "z"                      *                                -> WaitSub;
Verb "answer" "say" "shout" "speak"  * special "to" creature          -> AnswerSub;
Verb "ask"                           * creature "about" special       -> AskSub;
Verb "eat"                           * held                           -> EatSub;
Verb "sleep" "nap"                   *                                -> SleepSub;
Verb "peel"                          * noun                           -> TakeSub
                                     * "off" noun                     -> TakeSub;
Verb "sing"                          *                                -> SingSub;
Verb "climb" "scale"                 * noun                           -> ClimbSub;
Verb "buy" "purchase"                * special                        -> BuySub;
Verb "squeeze" "squash"              * noun                           -> SqueezeSub;
Verb "swim" "dive"                   *                                -> SwimSub;
Verb "swing"                         * noun                           -> SwingSub
                                     * "on" noun                      -> SwingSub;
Verb "blow"                          * held                           -> BlowSub;
Verb "pray"                          *                                -> PraySub;
Verb "echo"                          *                                -> EchoSub;
Verb "wake" "awake" "awaken"         *                                -> WakeSub
                                     * "up"                           -> WakeSub
                                     * creature                       -> WakeOSub
                                     * "up" creature                  -> WakeOSub;
Verb "kiss" "embrace" "hug"          * creature                       -> KissSub;
Verb "think"                         *                                -> ThinkSub;
Verb "smell" "sniff"                 *                                -> SmellSub
                                     * noun                           -> SmellSub;
Verb "hear" "listen"                 *                                -> ListenSub
                                     * noun                           -> ListenSub
                                     * "to" noun                      -> ListenSub;
Verb "taste"                         *                                -> TasteSub;
Verb "touch" "fondle" "feel" "grope" *                                -> TouchSub
                                     * noun                           -> TouchTSub;
Verb "rub" "shine" "polish"          * noun                           -> RubSub;
Verb "tie" "attach" "fasten" "fix"   * noun                           -> TieSub
                                     * noun "to" special              -> TieSub;
Verb "burn" "light"                  * noun                           -> BurnSub;
Verb "drink" "swallow" "sip"         * noun                           -> DrinkSub;
Verb "fill"                          * noun                           -> FillSub;
Verb "cut" "slice" "prune" "chop"    * noun                           -> CutSub;
Verb "jump" "skip" "hop"             *                                -> JumpsSub
                                     * "over" noun                    -> JumpSub;
Verb "xyzzy" "plugh" "plover" "blorple" *                             -> MagicWordSub;
Verb "help"                          *                                -> HelpSub;
! ---------------------------------------------------------------------------------------------------

end;
