 Rem File: Dndsub7 for Dndbbs Version v5.0a Release r2.0 Tweak t5.0a
 Rem $Include: 'dndbbs.inc'

 ' date/time logged on, time used.
Sub Time.Online(Var)
 On Local Error Goto Err.Trp1
 Graphics.Off=True
 Strng="It is now "+Fclock$
 Call IO.O
 ' calculate serialized date
 Trap=-1
 OnDate#=DateValue(Date.On)
 Strng2=Format$(OnDate#,"ddd dd mmm yyyy")
 ' calculate serialized time
 OnTime#=TimeValue(Time.On)
 Strng3=Format$(OnTime#,"hh:mma/p")
Resume1a:
 Trap=0
 If Trap.Err Then
    Strng="You logged on at "+Date.On+", "+Time.On+"."
 Else
    Strng="You logged on at "+Strng2+", "+Strng3+"."
 Endif
 Call IO.O
 Trap=-2
 d1$=format$(now,"mm-dd-yyyy")
 Var#=DateValue(d1$)-OnDate# ' serialized date
Resume2a:
 Trap=0
 If Var#>=2# Then
    Strng="You have been on for"+Str$(Var#)+" days!"
    Call IO.O
 Else
    ' time online
    Var1!=Timeit!-Timeon ' elapsed
    If Var1!<0! Then Var1!=Var1!+86400! ' midnight
    Strng="You have been on for"
    Strng2="."
    Gosub Time.Display
 Endif
 ' time remaining
 If UserRecord.TimeLimit<SFalse Then
    Strng="You have unlimited time remaining."
    Call IO.O
 Else
    If Var#<2# Then
       Var2!=Timeit!-Timeon ' elapsed
       If Var2!<0! Then Var2!=Var2!+86400! ' midnight
       Var1!=Time.Left-Var2! ' remaining
       If Var1!<0! Then Var1!=0!
       Strng="You have"
       Strng2=" remaining."
       Gosub Time.Display
    Endif
 Endif
 ' usage
 Strng="You have used "+Lcase$(ProgramName$)
 Var#=UserRecord.TimesLogon+1#
 Gosub Time.String
 Strng=Strng+Strng2+"."
 Call IO.O
 Exit Sub
Time.String:
 Select Case Var#
 Case 1
    Strng2=" once"
 Case 2 To 10
    Strng2=" "+Rtrim$(Numeral(Var#))+" times"
 Case Else
    Call Amount(Var#,VarQ$)
    Strng2=VarQ$+" times"
 End Select
 Return
Time.Display:
 Hours=Int(Var1!/3600!)
 Var1!=Var1!-Hours*3600!
 Minutes=Int(Var1!/60!)
 Var1!=Var1!-Minutes*60!
 Seconds=Int(Var1!)
 If Hours>=23 Then
    Strng=Strng+" a very long time"+Strng2
    Call IO.O
    Return
 Endif
 If Hours=False Then
    If Minutes=False Then
       If Seconds=False Then
          Strng=Strng+" 0 seconds"+Strng2
          Call IO.O
          Return
       Endif
    Endif
 Endif
 If Hours>False Then
    Strng=Strng+Str$(Hours)+" hour"
    If Hours>1 Then
       Strng=Strng+"s"
    Endif
    Strng=Strng+","
 Endif
 If Minutes>False Then
    Strng=Strng+Str$(Minutes)+" minute"
    If Minutes>1 Then
       Strng=Strng+"s"
    Endif
    Strng=Strng+","
 Else
    If Seconds=False Then
       Strng=Left$(Strng,Len(Strng)-1)
    Endif
 Endif
 If Seconds>False Then
    Strng=Strng+Str$(Seconds)+" second"
    If Seconds>1 Then
       Strng=Strng+"s"
    Endif
 Else
    Strng=Left$(Strng,Len(Strng)-1)
 Endif
 Strng=Strng+Strng2
 Call IO.O
 Return
Err.Rsm1:
 Exit Sub
 ' test for illegal function call when serialized date is beyond 2078.
Err.Trp1:
 If Trap=-1 Then
    Trap.Err=-1
    Resume Resume1a
 Endif
 If Trap=-2 Then
    Var#=0#
    Resume Resume2a
 Endif
 Resume Err.Rsm1
End Sub

' main command processing subroutine.
Sub Command.Loop
 On Local Error Goto Err.Trp18
 Gosub Get.Config1
 Out2=Ltrim$(Out2)

 ' check ? characters
 If Len(Out2)>0 Then
    If Out2=String$(Len(Out2),"?") Then
       TempX=Len(Out2)+1
       Call Read.Help
       Exit Sub
    Endif
 Endif

 ' check macros
 For Var=1 To MaxShortcutKeys
    Var1$=Rtrim$(Shortcut.Key1(Var))
    If Len(Var1$) Then
       If Var1$=Ucase$(Out2) Then
          Var2$=Rtrim$(Shortcut.Key2(Var))
          If Len(Var2$) Then
             Out2=Var2$
             Exit For
          Endif
       Endif
    Endif
 Next

 ' check command prefixes
 Var1=False
 If Len(Config3(79))>0 Then
    If Left$(Out2,Len(Config3(79)))=Config3(79) Then
       Var1=1 ' Sysop command
    Endif
 Endif
 If Len(Config3(9))>0 Then
    If Left$(Out2,Len(Config3(9)))=Config3(9) Then
       Var1=2 ' DM command
    Endif
 Endif
 If Len(Config3(78))>0 Then
    If Left$(Out2,Len(Config3(78)))=Config3(78) Then
       Var1=3 ' Node command
    Endif
 Endif

 ' check command validity
 TempX=False
 VarX=False
 Select Case Var1
 Case 1
    If Sysop=False Then
       VarX=True
       Strng="That command is reserved for Sysops only!"
    Else
       If Len(Out2)<=Len(Config3(79)) Then
          VarX=True
          Strng="That is not a reserved Sysop command!"
       Else
          If Disable.Sysop Then
             VarX=True
             Strng="All Sysop commands currently disabled."
          Endif
       Endif
    Endif
    If VarX=False Then
       If Mid$(Out2,Len(Config3(79))+1,1)=" " Then
          VarX=True
          Strng="That is not a reserved Sysop command!"
       Endif
       If Out2=Config3(79)+"?" Then
          TempX=-2
       Endif
    Endif
 Case 2
    If Normal.User Then
       VarX=True
       Strng="That command is reserved for DMs only!"
    Else
       If Len(Out2)<=Len(Config3(9)) Then
          VarX=True
          Strng="That is not a reserved DM command!"
       Else
          If Disable.DM Then
             VarX=True
             Strng="All DM commands currently disabled."
          Endif
       Endif
    Endif
    If VarX=False Then
       If Mid$(Out2,Len(Config3(9))+1,1)=" " Then
          VarX=True
          Strng="That is not a reserved DM command!"
       Endif
       If Out2=Config3(9)+"?" Then
          TempX=-3
       Endif
    Endif
 Case 3
    If UserRecord.Level<=False Then
       VarX=True
       Strng="That command is reserved for players only!"
    Else
       If Len(Out2)<=Len(Config3(78)) Then
          VarX=True
          Strng="That is not a reserved node command!"
       Else
          If Disable.Nodes Then
             VarX=True
             Strng="All node commands currently disabled."
          Endif
       Endif
    Endif
    If VarX=False Then
       If Mid$(Out2,Len(Config3(78))+1,1)=" " Then
          VarX=True
          Strng="That is not a reserved node command!"
       Endif
       If Out2=Config3(78)+"?" Then
          TempX=-4
       Endif
    Endif
 End Select
 If TempX Then
    Call Read.Help
    Exit Sub
 Endif
 If VarX Then
    Call IO.O
    Call Send.Illegal
    Exit Sub
 Endif

 ' strip double spaces from user command
 If Var1=False Then
    Out2=Rtrim$(Out2)
    Do
       VarQ=Instr(Out2,"  ")
       If VarQ=False Then
          Exit Do
       Endif
       Out2=Left$(Out2,VarQ-1)+Mid$(Out2,VarQ+1)
    Loop
 Endif

 ' store current command
 Stored.Parsed.Command1=Out2
 Out2=Ucase$(Out2)
 Stored.Parsed.Command2=Out2
 VarZ$=Out2

 ' strip reserved words
 If Var1=0 Then
    If Instr(Out2," ") Then
       If Instr(Instr(Out2," ")+1,Out2," ") Then
          If Option1 Then
             ' read reserved words from file
             Close #TempFile1
             FileName=DND.Path+"noise.dat"
             If Dir$(FileName)<>Nul Then
                Open FileName For Input Shared As #TempFile1
                Do
                   If Eof(TempFile1) Then
                      Exit Do
                   Endif
                   Line Input #TempFile1,Var$
                   Var$=Ucase$(Var$)
                   Call Strip.Line(Var$)
                   If Len(Var$) Then
                      Var$=" "+Ucase$(Var$)+" "
                      VarZ=Instr(Out2,Var$)
                      Do While VarZ
                         Out2=Left$(Out2,VarZ-1)+Mid$(Out2,VarZ+Len(Var$)-1)
                         VarZ=Instr(Out2,Var$)
                      Loop
                   Endif
                Loop
             Endif
          Endif
          If Option3 Then
             ' read reserved words from data
             VarQ=MaxUserCommands+MaxDMcommands+MaxSysopCommands+MaxNodeCommands+MaxLetters
             For VarX=1 To MaxStrips
                TempZ=VarX+VarQ
                Call Read.Message.Record(MessWorkFile8,TempZ)
                If Left$(Ltrim$(UserCommandRecord.CommandSet(1)),1)=";" Then
                   Eat$=Nul
                Else
                   Var$=" "+Ucase$(Ltrim$(Rtrim$(UserCommandRecord.CommandSet(1))))+" "
                   VarZ=Instr(Out2,Var$)
                   Do While VarZ
                      Out2=Left$(Out2,VarZ-1)+Mid$(Out2,VarZ+Len(Var$)-1)
                      VarZ=Instr(Out2,Var$)
                   Loop
                Endif
             Next
          Endif
       Endif
    Endif
 Endif

 ' repeat command
 If Config3(10)<>"" And Config3(10)=Out2 Then
    User.Command=Previous.Command1
    Stored.Parsed.Command1=Previous.Command2
    Stored.Parsed.Command2=Previous.Command3
    If Len(Config3(79))>0 Then
       If Left$(User.Command,Len(Config3(79)))=Config3(79) Then
          Strng="Cannot repeat Sysop command!"
          Call IO.O
          Exit Sub
       Endif
    Endif
    If Len(Config3(9))>0 Then
       If Left$(User.Command,Len(Config3(9)))=Config3(9) Then
          Strng="Cannot repeat DM command!"
          Call IO.O
          Exit Sub
       Endif
    Endif
    If Len(Config3(78))>0 Then
       If Left$(User.Command,Len(Config3(78)))=Config3(78) Then
          Strng="Cannot repeat Node command!"
          Call IO.O
          Exit Sub
       Endif
    Endif
 Else
    User.Command=Out2
 Endif

 ' check nul input
 If User.Command=Nul Then
    Last.Command=Enter$
    Call Update.Mess(4)
    Loops.Counted=Loops.Counted+1
    If Option2=True Then ' disable message
       Loops.Counted=False
    Else
       If Loops.Counted>=Option2 Then
          Strng=Option1$
          If Strng=Nul Then Strng="Nothing happens.."
          Call Convert.String ' convert macros first
          Call Convert.ANSI(False,VarQ,VarR) ' convert prefixes next
          Graphics.On=True
          Call IO.O
          Graphics.On=False
          Loops.Counted=0
       Endif
    Endif
    Exit Sub
 Endif
 Loops.Counted=0

 ' store command
 Previous.Command1=User.Command
 Previous.Command2=Stored.Parsed.Command1
 Previous.Command3=Stored.Parsed.Command2

 ' reset command loop variables
 Entry.Command=False
 Magic.Spell=False

 ' store parsed command
 Temp.Command=User.Command
 If Instr(Temp.Command," ") Then
    Temp.Command=Left$(Temp.Command,Instr(Temp.Command," ")-1)
 Endif
 Parser=Instr(User.Command," ")
 If Parser Then
    Parsed.Command1=Mid$(User.Command,Parser+1)
    Parsed.Command2=Parsed.Command1
    VarX=Instr(Stored.Parsed.Command1," ")+1
    Stored.Parsed.Command1=Mid$(Stored.Parsed.Command1,VarX)
    Stored.Parsed.Command2=Mid$(Stored.Parsed.Command2,VarX)
    Call Numeric
 Endif

 ' store number of parameters
 Params=False
 VarX=Instr(User.Command," ")
 Do While VarX
    Params=Params+1
    VarX=Instr(VarX+1,User.Command," ")
 Loop

 ' process command
 Select Case Var1
 Case 0
    Call Command.Response(VarQ,VarZ$)
    If VarQ Then
       Exit Sub
    Endif
    Call User.Command1
 Case 1
    Call Sysop.Command1
 Case 2
    Call DM.Command1
 Case 3
    Call Node.Command1
 End Select
 Var1=False
 Exit Sub
Get.Config1:
 Option1=-1
 Option2=16
 Option3=-1
 Option1$="Nothing happens.."
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[DNDBBS]" Then
       Do
          VarX=VarX+1
          If VarX>Options.Lines Then
             Return
          Endif
          Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
          If Ucase$(Var$)="[END]" Then
             Return
          Endif
          Var=Instr(Var$,"=")
          If Var Then
             Var2$=Ltrim$(Rtrim$(Left$(Var$,Var-1)))
             Var3$=Ltrim$(Rtrim$(Mid$(Var$,Var+1)))
             Select Case Lcase$(Var2$)
             Case "disable.reserved.words"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option1=0
                End Select
             Case "disable.reserved.words.data"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option3=0
                End Select
             Case "loop.count"
                VarY=Int(Val(Var3$)+.5)
                If VarY=-1 Then
                   Option2=-1
                Endif
                If VarY>=10 And VarY<=32767 Then
                   Option2=VarY
                Endif
             Case "loop.message"
                Option1$=Var3$
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
Err.Rsm18:
 Exit Sub
Err.Trp18:
 Resume Err.Rsm18
End Sub

Sub User.Command1
 On Local Error Goto Err.Trp19
 Remote=-1
 TempQ=False

 ' process command without parameters
 If Params=False Then

    ' process direction command
    Call Numeric2
    Call Get.Direction
    If TempA Then
       Entry.Command=1
       Last.Command.Number=51
       Parsed.Command1=User.Command
       Call Check.Restriction(57,Var2)
       If Var2 Then
          Exit Sub
       Endif
       Last.Command=Direction(TempA)
       Call Update.Mess(4)
       Call Chain.Command(51) ' Call Go.Direction
       Call Send.Unknown2
       Exit Sub
    Endif

    ' process custom direction datafile
    Call Find.Custom(VarX)
    If VarX Then
       Gosub Goto.Custom2
    Endif

    ' process custom direction
    Var$=Rtrim$(RoomRecord.Custom1)
    Var3=13
    Gosub Goto.Custom
    Var$=Rtrim$(RoomRecord.Custom2)
    Var3=14
    Gosub Goto.Custom

    ' single letter command without parameters
    If Config2(110) Then
       If Len(Temp.Command)=1 Then
	  VarX=Asc(Lcase$(Temp.Command))
	  If VarX>=97 And VarX<=122 Then
             TempZ=VarX-96
             TempZ=TempZ+MaxUserCommands+MaxDMcommands+MaxSysopCommands+MaxNodeCommands
             Call Read.Message.Record(MessWorkFile8,TempZ)
             Last.Command.Number=UserCommandRecord.CommandParam
	     If Last.Command.Number>False Then
                Call Read.Message.Record(MessWorkFile8,Last.Command.Number)
                Last.Command=Rtrim$(UserCommandRecord.CommandSet(1))
		TempQ=True
	     Endif
	  Endif
       Endif
    Endif
 Endif

 ' single letter command with parameters
 If TempQ=False Then
    If Config2(110) Then
       If Len(Temp.Command)=1 Then
          VarX=Asc(Lcase$(Temp.Command))
          If VarX>=97 And VarX<=122 Then
             TempZ=VarX-96
             TempZ=TempZ+MaxUserCommands+MaxDMcommands+MaxSysopCommands+MaxNodeCommands
             Call Read.Message.Record(MessWorkFile8,TempZ)
             Last.Command.Number=UserCommandRecord.CommandParam
	     If Last.Command.Number>False Then
                Call Read.Message.Record(MessWorkFile8,Last.Command.Number)
                Last.Command=Rtrim$(UserCommandRecord.CommandSet(1))
                For TempX=1 To 3
                   Call Read.Message.Record(MessWorkFile8,Last.Command.Number+TempX-1)
                   Last.Command=Rtrim$(UserCommandRecord.CommandSet(TempX))
                   OutC$=Rtrim$(Last.Command)
                   If OutC$="" Then
                      OutC$="<>"
                   Endif
                   If OutC$<>"<>" Then
                      If Last.Command=Left$(OutC$,Len(Last.Command)) Then
                         TempY=Last.Command.Number+TempX-1
                         If Params=UserCommandRecord.CommandParam Then
                            Last.Command.Number=TempY
                            TempQ=True
                            Exit For
                         Endif
                      Endif
                   Endif
                Next
	     Endif
	  Endif
       Endif
    Endif
 Endif

 ' two-letter command abbreviation
 If TempQ=False Then
    If Config2(109) Then
       If Len(Temp.Command)=2 Then
	  For Last.Command.Number=1 To MaxUserCommands
             Call Read.Message.Record(MessWorkFile8,Last.Command.Number)
             Last.Command=Rtrim$(UserCommandRecord.CommandSet(1))
             If Temp.Command=UserCommandRecord.CommandAbbr Then
                If Params=UserCommandRecord.CommandParam Then
		   TempQ=True
		   Exit For
		Endif
	     Endif
	  Next
       Endif
    Endif
 Endif

 ' full command with parameters
 If TempQ=False Then
    For Last.Command.Number=1 To MaxUserCommands
       Call Read.Message.Record(MessWorkFile8,Last.Command.Number)
       For TempX=1 To 3
          Last.Command=Rtrim$(UserCommandRecord.CommandSet(TempX))
	  OutC$=Rtrim$(Last.Command)
          If OutC$="" Then
             OutC$="<>"
          Endif
          If OutC$<>"<>" Then
             If Temp.Command=Left$(OutC$,Len(Temp.Command)) Then
                TempQ=True
                Exit For
             Endif
             If Len(Temp.Command)<=2 Then
                If TempX=1 Then
                   Exit For
                Endif
             Endif
          Endif
       Next
       If TempQ Then
          If Params=UserCommandRecord.CommandParam Then
	     Exit For
	  Else
	     TempQ=False
	  Endif
       Endif
    Next
 Endif

 ' unknown command
 If TempQ=False Then
    Call Unknown.Command("")
    Exit Sub
 Endif

 ' command time restriction in seconds
 Var1=UserCommandRecord.CommandTime(1) ' from
 Var1!=Csng(Var1)*3600! ' hours
 Var2=UserCommandRecord.CommandTime(2)
 Var1!=Var1!+Csng(Var2)*60! ' minutes

 Var3=UserCommandRecord.CommandTime(3) ' to
 Var2!=Csng(Var3)*3600! ' hours
 Var4=UserCommandRecord.CommandTime(4)
 Var2!=Var2!+Csng(Var4)*60! ' minutes

 If Var1!>SFalse Or Var2!>SFalse Then
    Call Check.Time2(VarZ,Var1!,Var2!)
    If VarZ=False Then
       Graphics.Off=True
       Strng="Command time restriction!"
       Call IO.O
       ' 23:59-23:59
       Strng="Command is currently restricted from "

       Z1$=Ltrim$(Str$(Var1)) ' from hour
       Z1$=Right$("00"+Z1$,2)
       Z2$=Ltrim$(Str$(Var2)) ' from minute
       Z2$=Right$("00"+Z2$,2)

       Z3$=Ltrim$(Str$(Var3)) ' to hour
       Z3$=Right$("00"+Z3$,2)
       Z4$=Ltrim$(Str$(Var4)) ' to minute
       Z4$=Right$("00"+Z4$,2)

       Strng=Strng+Z1$+":"+Z2$+" to "+Z3$+":"+Z4$

       Call IO.O
       Graphics.Off=False
       Call Send.Restrict
       Exit Sub
    Endif
 Endif

 ' command class restriction
 If Normal.User Then
    If UserRecord.ClassType<AsstDM Then
       If UserCommandRecord.CommandClass(UserRecord.ClassType) Then
	  Graphics.Off=True
	  Strng="Command class restriction!"
	  Call IO.O
          Strng="This command cannot be used by your class."
          Call IO.O
	  Graphics.Off=False
          Call Send.Restrict
	  Exit Sub
       Endif
    Endif
 Endif

 ' check command restriction
 Var1=Last.Command.Number
 Call Check.Restriction(Var1,Var2)
 If Var2 Then
    Exit Sub
 Endif

 ' valid command
 Call Update.Mess(4)

 ' check command is attack
 If UserCommandRecord.AttackCommand Then
    If Params=False Then
       Parsed.Command1=Last.Monster
    Endif
    TempX=False
    Call Chain.Command(0) ' attack.monster
    Last.Command="attack"
    Call Send.Unknown2
    Exit Sub
 Endif

 ' implement command number with parameters
 Command.Time.Limit=UserCommandRecord.CommandLimit
 Select Case Last.Command.Number
 Case 1 ' accept/decline
    TempX=False
    If Ucase$(User.Command)="DECLINE" Then
       TempX=True
    Endif
    Call Chain.Command(1) ' Call Accept.Offer/Decline.Offer
 Case 2 ' alignment
    Call Chain.Command(2) ' Call Align
 Case 3 ' ansi
    Call Get.ANSI
    Exit Sub
 Case 4 ' appeal
    TempX=False
    Call Chain.Command(4) ' Call Appeal
 Case 5 ' auto
    Call Chain.Command(5)
 Case 6 ' avatar
    Call Get.Avatar
    Exit Sub
 Case 8 ' bank
    Call Playwav(12)
    Call Chain.Command(8) ' Call Bank
 Case 15, 36 ' bless/curse
    TempX=False
    If Last.Command.Number=15 Then
       TempX=True
    Endif
    Call Chain.Command(35) ' Call Bless.Self/Curse.Self
 Case 16 ' bless <object>
    Call Chain.Command(16) ' Call Bless.Object
 Case 17, 18 ' break <object>/break <object> <user>
    Call Chain.Command(17) ' Call Smash.Object
 Case 19 ' offer <value/item> to <monster>
    Call Chain.Command(18) ' Call Offer.Monster
 Case 20 ' offer <value/item/container> to <player> for <value/item/container>
    Call Chain.Command(19) ' Call Offer.Player
 Case 21 ' brief
    Call Brief.Mode
    Exit Sub
 Case 22 ' bulletins
    Call Chain.Command(21) ' Call Bulletins
 Case 23 ' buy <value/item>
    Call Chain.Command(22) ' Call Weapons.Shoppe
 Case 24 ' casino
    Call Playwav(12)
    Call Chain.Command(23) ' Call Casino
 Case 25, 26 ' cast/cast <target>
    TempX=True
    Call Chain.Command(24) ' Call Cast.Spell(True)
 Case 27 ' catalog
    TempX=False
    Call Chain.Command(26) ' Call Display.Catalogs(False)
 Case 30 ' chat
    TempX=True
    Call Chain.Command(4) ' Call Page.Sysop
 Case 32 ' close <target>
    Call Chain.Command(31) ' Call Close.Object
 Case 33 ' commands
    TempX=True
    Call Chain.Command(26) ' Call Display.Catalogs(True)
 Case 34 ' configure/settings
    Call Chain.Command(33) ' Call Get.Preferences(True)
 Case 37 ' curse <target>
    Call Chain.Command(36) ' Call Curse.Object
 Case 38 ' dayfile
    TempX=True
    Call Chain.Command(37) ' Call Read.DayFile(True)
 Case 39 ' daylog
    TempX=False
    Call Chain.Command(37) ' Call Read.DayFile(False)
 Case 41 ' dismount <target>
    Call Chain.Command(40) ' Call Exit.Vehicle
 Case 43 ' drink <object>
    Call Chain.Command(42) ' Call Drink.Potion
 Case 44 ' duplex
    If Ucase$(User.Command)="TELETYPE" Then ' synonyn
       Call Flag.Toggles(9)
    Else
       If Ucase$(User.Command)="UPPERCASE" Then ' synonyn
          IO.Upper.Case=True
       Else
          Call Flag.Toggles(3)
       Endif
    Endif
    Exit Sub
 Case 45 ' eat <object>
    Call Chain.Command(44) ' Call Eat.Object
 Case 46 ' echo
    If Ucase$(User.Command)="LOWERCASE" Then ' synonyn
       IO.Upper.Case=False
    Else
       Call Flag.Toggles(2)
    Endif
    Exit Sub
 Case 47 ' experience
    Call Chain.Command(46) ' Call Display.Experience
 Case 48 ' exit
    TempA=12
    Entry.Command=1
    Last.Command.Number=51
    Parsed.Command1="OUT"
    Call Chain.Command(51) ' Call Go.Direction
 Case 50 ' fire <object> <target>
    Call Chain.Command(49) ' Call Fire.Object
 Case 51, 52 ' fix <object>/fix <object> <user>
    Call Chain.Command(50) ' Call Fix.Object
 Case 53 ' fly <direction>
    Entry.Command=Fly
    Call Chain.Command(51) ' Call Enter.Object
 Case 54 ' follow
    Follow.Mode=True
    Call Chain.Command(52)
    Follow.Mode=False
 Case 55 ' fuel <object>
    Call Chain.Command(53) ' Call Fuel.Object
 Case 56 ' give <value/item> to <player/monster>
    Call Chain.Command(54) ' Call Give.Object
 Case 57 ' enter <object>
    Entry.Command=1
    Call Chain.Command(51) ' Call Enter.Object
 Case 58 ' graphics/statusline
    Call Chain.Command(56) ' Call Get.Graphics/StatusLine
 Case 60 ' health
    Call Chain.Command(206) ' Call Display.Health
 Case 61, 62 ' help/help <topic>
    If Params=0 Then
       Stored.Parsed.Command1=Config3(48)
    Endif
    TempX=False
    Call Read.Help ' Call Read.Help(False)
    Exit Sub
 Case 63 ' hide
    TempX=True
    Call Chain.Command(62) ' Call Hide.User
 Case 64 ' hide <object>
    TempX=False
    Call Chain.Command(62) ' Call Hide.Object
 Case 65 ' hide <object> <container>
    TempX=True
    Call Chain.Command(63) ' Call Drop.Into.Container(True)
 Case 66 ' hint
    Call Out.File(Hint.FileName)
    Exit Sub
 Case 67 ' hold <object>
    Call Chain.Command(65) ' Call Hold.Object
 Case 68 ' hunt
    Follow.Mode=True
    Call Chain.Command(52)
    Follow.Mode=False
 ' identify <object>/identify <object> <user>/look <object> <user>
 Case 69, 70, 87
    If Params=1 Then
       If Lcase$(Parsed.Command1)="self" Then
          TempX=4
          Call Chain.Command(150) ' Call Display.Stats
       Else
          Call Chain.Command(83) ' Call Display.Information
       Endif
    Else
       Call Chain.Command(83) ' Call Display.Information
    Endif
 Case 71 ' information
    TempX=4
    Call Chain.Command(150) ' Call Display.Stats
 Case 72 ' inventory
    TempX=1
    If Room.Toggle=False Then
       TempX=3
    Endif
    ' Call Display.Sorted.Inv/Call Display.Inventory
    Call Chain.Command(150)
 Case 75 ' lastuser
    TempX=UnTrue
    Call Chain.Command(37) ' Call Read.DayFile(UnTrue)
 Case 76 ' launch <object> <direction>
    Call Chain.Command(73) ' Call Launch.Object
 Case 77 ' learn <spell>
    Call Chain.Command(74) ' Call Learn.Spell
 Case 78 ' light <object>
    Call Chain.Command(75) ' Call Light.Object
 Case 79 ' linefeeds
    Call Flag.Toggles(1)
    Exit Sub
 Case 80 ' linelength
    Call Get.Linelength
    Exit Sub
 Case 81 ' list
    Call Chain.Command(78) ' Call Weapon.List
 Case 82 ' load <object>
    Call Chain.Command(79) ' Call Load.Object
 Case 83 ' lock <object>
    Call Chain.Command(80) ' Call Lock.Object
 Case 84 ' login
    Call Relogin
    Exit Sub
 Case 85 ' look
    If Room.Toggle Then
       TempX=2
       Call Chain.Command(150) ' Call Display.Sorted.Room
    Else
       Call Chain.Command(103) ' Call Display.Room
    Endif
 Case 86 ' look <object>
    TempX=False
    Select Case Lcase$(Parsed.Command1)
    Case "news"
       Call System.News
       Exit Sub
    Case "inventory"
       TempX=1
       Call Chain.Command(150) ' Call Display.Sorted.Inv
    Case "room"
       TempX=2
       Call Chain.Command(150) ' Call Display.Sorted.Room
    Case "self"
       Call Chain.Command(206) ' Call Display.Health
    Case "bank"
       TempX=1
       Call Chain.Command(998) ' Call Bank.Interest
    Case "mail"
       TempX=2
       Call Chain.Command(998) ' Call Check.New.Mail
    Case "repair"
       TempX=3
       Call Chain.Command(998) ' Call Repair.All
    Case "repairuser"
       TempX=4
       Call Chain.Command(998) ' Call Repair.User
    Case "repairroom"
       TempX=5
       Call Chain.Command(998) ' Call Repair.Room
    Case "repaircontainers"
       TempX=6
       Call Chain.Command(998) ' Call Repair.Containers
    Case "toggle", "sort"
       Room.Toggle=Not Room.Toggle
       If Room.Toggle Then
          Strng="Sort toggle on."
       Else
          Strng="Sort toggle off."
       Endif
       Call IO.O
       Exit Sub
    Case "roomnumber"
       Strng="You are in room #"+Mid$(Str$(Room),2)+"."
       Call Safe.Room
       If TempA Then
          Strng=Strng+" <safe haven>"
       Endif
       Call IO.O
       Exit Sub
    Case "monclass", "monsterclass", "classnumber"
       Call Safe.Room
       Strng="This room monclass:"
       If TempA Then
          Strng=Strng+" <safe haven>."
       Else
          Strng=Strng+Str$(RoomRecord.MonClass)+"."
       Endif
       Call IO.O
       Exit Sub
    Case "version"
       Strng=ProgramName$+" v"+Version$+" r"+Release$+" t"+Tweak$+" "+YearRelease$
       Call IO.O
       Exit Sub
    Case Else
       Call Chain.Command(83) ' Call Display.Information
    End Select
 Case 88 ' lose
    Call Chain.Command(84) ' Call Lose.Player
 Case 90 ' mail
    If Ucase$(User.Command)="VOTE" Then ' synonyn
       Call Chain.Command(210) ' Call Vote
    Else
       Call Chain.Command(86) ' Call Mail
    Endif
 Case 91 ' mix <object>
    Call Chain.Command(87) ' Call Mix.Potion
 Case 92 ' mount <object>
    Call Chain.Command(88) ' Call Enter.Vehicle
 Case 93 ' move <object> <direction>
    Call Chain.Command(89) ' Call Move.Object
 Case 94 ' notice
    Call Out.File(Notice.FileName)
    Exit Sub
 Case 95 ' open <object>
    Call Chain.Command(91) ' Call Open.Object
 Case 96 ' pagelength
    Call Get.Pagelength
    Exit Sub
 Case 97 ' panic
    Call Chain.Command(93) ' Call Panic
 Case 98 ' parley
    Call Chain.Command(94) ' Call Talk.To.Monster
 Case 100 ' password
    Call Chain.Command(96) ' Call Change.PassWord
 Case 101 ' picklock <object>
    Call Chain.Command(97) ' Call Picklock.Object
 Case 102 ' pour <object> <target>
    Call Chain.Command(98) ' Call Pour.Potion
 Case 103 ' prelog
    Call Out.File(Prelog.FileName)
    Exit Sub
 Case 104 ' press <object>
    Call Chain.Command(100) ' Call Press.Object
 Case 105 ' psionic <spell>
    Call Chain.Command(101) ' Call Psi.Mode
 Case 108 ' put <object>
    Call Chain.Command(104) ' Call Drop.Object
 Case 109 ' put <object> <container>
    TempX=False
    Call Chain.Command(63) ' Call Drop.Into.Container(False)
 Case 110 ' quit
    Relogging=False
    Call Quit.Program
    Exit Sub
 Case 111 ' recharge <object>
    Call Chain.Command(107) ' Call Alchemist
 Case 112 ' reload <object>
    Call Chain.Command(108) ' Call Reload.Object
 Case 113 ' repair <object>
    Call Chain.Command(109) ' Call Weapons.Shop
 Case 114 ' reroll
    Call Chain.Command(110) ' Call Reroll.Character
 Case 116 ' return <object>
    Call Chain.Command(112) ' Call Return.Object
 Case 117 ' ride <direction>
    Call Chain.Command(113) ' Call Ride.Vehicle
 Case 118 ' save
    Call Put.User.Record
    Strng="Player file updated."
    Call IO.O
    Exit Sub
 Case 119, 120, 121 ' search/search <container>/search <container> <user>
    TempX=5
    If Params>0 Then
       TempX=6
    Endif
    If Params=1 Then
       Select Case Lcase$(Parsed.Command1)
       Case "news" ' system news
          Call Chain.Command(193) ' Call Old.System.News
       Case "mail" ' check mail
          Graphics.Off=False
          Strng="Check for new mail(y/n)? "
          No.Input.Out="Y"
          Call IO.I
          If Yes Then
             Call New.Mail
          Endif
          Exit Sub
       Case "help"
          TempX=UnTrue
          Call Read.Help ' Call Read.Help(UnTrue)
          Exit Sub
       Case "exits"
          TempX=7
          Call Chain.Command(150) ' Call Search.Room.Exits
       Case Else
          Call Chain.Command(150) ' Call Search.Container
       End Select
    Else
       Call Chain.Command(150) ' Call Search.Room
    Endif
 Case 122 ' sell <object>
    Call Chain.Command(117) ' Call Pawn.Shop
 Case 124 ' sort
    Call Flag.Toggles(5)
    Exit Sub
 Case 125, 126 ' steal <object> <player>/steal <object> <container> <player>
    Call Chain.Command(120) ' Call Steal.Object
 Case 127 ' suicide
    Call Suicide
    Exit Sub
 Case 128 ' swim <direction>
    Entry.Command=Swim
    Call Chain.Command(51) ' Call Enter.Object
 Case 129 ' switch
    Call Chain.Command(123) ' Call Switch.Lights
 Case 130 ' take <object>
    Call Chain.Command(124) ' Call Take.Object
 Case 131 ' take <object> <container>
    Call Chain.Command(125) ' Call Take.From.Container
 Case 132 ' team
    Call Chain.Command(126) ' Call Teams
 Case 133 ' throw <object> <player>
    Call Chain.Command(127) ' Call Throw.Object
 Case 135 ' time
    TempX=True
    Call Chain.Command(205) ' Call Time.Online(True)
 Case 136 ' topten
    Call Shell.Program3
    Exit Sub
 Case 137 ' trace
    Follow.Mode=True
    Call Chain.Command(52)
    Follow.Mode=False
 Case 138 ' track
    Follow.Mode=True
    Call Chain.Command(52)
    Follow.Mode=False
 Case 139 ' train
    Call Chain.Command(207) ' Call Train
 Case 141 ' unlock <object>
    Call Chain.Command(135) ' Call Unlock.Object
 ' discharge <object> <target>/use <object>/use <object> <player>
 Case 40, 142, 143
    TempX=False
    Call Chain.Command(24) ' Call Cast.Spell(False)
 Case 144 ' users
    Call Chain.Command(138) ' Call User.List
 Case 145 ' wait
    Call Chain.Command(139)
 Case 146 ' wear <object>
    Call Chain.Command(65) ' Call Hold.Object
 Case 147 ' welcome
    Call Out.File(Welcome.FileName)
    Exit Sub
 Case 148 ' whatis
    Call Chain.Command(142) ' Call Whatis.Command
 Case 149 ' wish
    TempX=False
    Call Chain.Command(157) ' Call Drop(False)
 Case 150 ' wordwrap
    Call Flag.Toggles(4)
    Exit Sub
 Case 151 ' write
    Call Chain.Command(151) ' Call Write.On.Object
 Case 152 ' imbue
    Call Chain.Command(187) ' Call Imbue.Object
 Case 153 ' zap
    Call Chain.Command(188) ' Call Zap.Object
 Case 154 ' smoke
    Call Chain.Command(191) ' Call Smoke.Object
 Case 155 ' burn
    Call Chain.Command(192) ' Call Burn.Object
 End Select

 ' display message for unknown/missing chain
 Select Case Last.Command.Number
 Case 18, 19
    Strng="There's nothing here to offer to.."
 Case 69, 70, 85, 86, 87
    Strng="There's nothing here to look at.."
 Case 119, 120, 121
    Strng="There's nothing here to search.."
 Case 125, 126
    Strng="There's nothing here to steal.."
 Case Else
    Strng="User command not available."
 End Select
 Call IO.O
 Call Send.Unknown
 Exit Sub

' goto custom direction
Goto.Custom:
 If Var$=String$(12,Chr$(0)) Then
    Return
 Endif
 If Ucase$(Var$)=Ucase$(User.Command) Then
    If RoomRecord.Direct(Var3)>SFalse Then
       Entry.Command=1
       Last.Command.Number=51
       Parsed.Command1=User.Command
       Call Check.Restriction(57,Var2)
       If Var2 Then
          Exit Sub
       Endif
       Last.Command=Var$
       Call Update.Mess(4)
       Call Chain.Command(51) ' Call Go.Direction
       Call Send.Unknown2
       Exit Sub
    Endif
 Endif
 Return

' goto custom direction from datafile
Goto.Custom2:
 Entry.Command=1
 Last.Command.Number=51
 Parsed.Command1=User.Command
 Last.Command=User.Command
 Call Check.Restriction(57,Var2)
 If Var2 Then
    Exit Sub
 Endif
 Call Update.Mess(4)
 Call Chain.Command(51) ' Call Go.Direction
 Call Send.Unknown2
Err.Rsm19:
 Exit Sub
Err.Trp19:
 Resume Err.Rsm19
End Sub

Sub Find.Custom(Var)
 On Local Error Goto Err.Trp19a
 Var=False
 Filename=DND.Path+"custom.dat"
 If Dir$(Filename)<>"" Then
    Close #TempFile1
    Open Filename For Input Shared As #TempFile1
    Do
       If Eof(TempFile1) Then Exit Do
       Input #TempFile1,Var1$,Var1!,Var2!,X,Y
       Var1$=Ucase$(Left$(Var1$,12))
       If Len(Var1$) Then
          If Var1$=Ucase$(User.Command) Then
             If Var1!=Room Then
                Var=True
                Exit Do
             Endif
          Endif
       Endif
    Loop
 Endif
Err.Rsm19a:
 Exit Sub
Err.Trp19a:
 Resume Err.Rsm19a
End Sub

Sub DM.Command1
 On Local Error Goto Err.Trp20
 Remote=-1
 TempQ=False
 Temp.Command=Mid$(Temp.Command,Len(Config3(9))+1)
 If Ucase$(Temp.Command)=Config3(9) Then ' !!
    Strng="Sometimes huge rats crawl around in code."
    Call IO.O
    Exit Sub
 Endif
 If Ucase$(Temp.Command)="RATS" Then
    Strng="Sometimes large rats crawl around in code."
    Call IO.O
    Exit Sub
 Endif
 For Last.Command.Number=1 To MaxDMcommands
    TempZ=Last.Command.Number+MaxUserCommands
    Call Read.Message.Record(MessWorkFile8,TempZ)
    Last.Command=UserCommandRecord.CommandSet(1)
    Last.Command=Rtrim$(Left$(Last.Command,10))
    If Left$(Last.Command,Len(Temp.Command))=Temp.Command Then
       If UserCommandRecord.CommandParam=True Then
          Var$=Lcase$(Last.Command)
          Mid$(Var$,1,1)=Ucase$(Mid$(Var$,1,1))
          Last.Command=Config3(9)+Var$
	  TempQ=True
	  Exit For
       Else
          If Params=UserCommandRecord.CommandParam Then
             Var$=Lcase$(Last.Command)
             Mid$(Var$,1,1)=Ucase$(Mid$(Var$,1,1))
             Last.Command=Config3(9)+Var$
             TempQ=True
             Exit For
	  Endif
       Endif
    Endif
 Next
 If TempQ=False Then
    Call Unknown.Command(Config3(9))
    Exit Sub
 Endif
 TempQ=True
 If Sysop=False Then
    If Dungeon.Master=False Then
       If Dungeon.Master.Assistant=False Then
	  If Guild.Master Then
             If UserCommandRecord.CommandClass(1) Then
		TempQ=False
	     Endif
	  Endif
	  If Governor Then
             If UserCommandRecord.CommandClass(2) Then
		TempQ=False
	     Endif
	  Endif
	  If Town.Mayor Then
             If UserCommandRecord.CommandClass(3) Then
		TempQ=False
	     Endif
	  Endif
       Endif
    Endif
 Endif
 If TempQ=False Then
    Graphics.Off=True
    Strng="Command restriction!"
    Call IO.O
    Graphics.Off=False
    Call Send.Restrict
    Exit Sub
 Endif
 ' check command restriction
 Var1=MaxUserCommands+Last.Command.Number
 Call Check.Restriction(Var1,Var2)
 If Var2 Then
    Exit Sub
 Endif
 Call Update.Mess(4)
 Select Case Last.Command.Number
 Case 1, 2 ' !abort/!abort <node>
    VarX=180+Params
    Call Chain.Command(VarX) ' Call Abort/Call Abort.Node
 Case 3 ' !broadcast
    TempX=17
    Call Chain.Command(153) ' Call <node command>
 Case 4, 5 ' !call/!call <monster>
    VarX=184+Params
    Call Chain.Command(VarX) ' Call Call.Monster/Call Summon.Monster
 Case 6 ' !discard <object>
    Call Chain.Command(186) ' Call Discard.Object
 Case 7 ' !edit
    Call Playwav(8)
    TempC=False
    TempD=False
    Call Chain.Program("EDIT.EXE",Local.Mode,True)
 Case 8 ' !edit <roomnumber>
    TempX!=Int(Val(Parsed.Command1)+.5)
    TempA=False
    Call Chain.Command(159) ' Call Edit.Room(TempX!)
 Case 9 ' !get <object>,..
    Parsed.Command1=Stored.Parsed.Command2
    Call Numeric
    Out2=Parsed.Command1
    Out2=Lcase$(Out2)
    TempX=True
    Call Chain.Command(157) ' Call Drop(True)
 Case 10, 11 ' !help/!help !<topic>
    If Params=0 Then
       Stored.Parsed.Command1=Config3(47)
    Endif
    TempX=True
    Call Read.Help
    Exit Sub
 Case 12 ' !invisible
    Call Invisibility
    Exit Sub
 Case 13 ' !kill <player>
    TempX=True
    Call Chain.Command(0) ' Call Kill.Monster
 Case 14 ' !link
    'Remote=Local.Mode
    Call Chain.Command(160) ' Call Link.Room
 Case 15 ' !noid
    TempX=18
    Call Chain.Command(153) ' Call <node command>
 Case 16 ' !reduce <value>
    Call Chain.Command(204) ' Call Reduce.Monsters
 Case 17 ' !status
    If OS2.Detected=0 Then ' has no freespace
       TempX!=Fre(-1)+Fre(a$) ' free far+temp
    Endif
    Call Chain.Command(202) ' Call Display.Memory
 Case 18 ' !teleport <player>,..
    Call Chain.Command(158) ' Call Teleport.Function
 Case 19, 20 ' !zap/!zap <room#>
    TempX!=Room
    If Params=1 Then
       TempX!=Int(Val(Parsed.Command1)+.5)
    Endif
    Call Chain.Command(156) ' Call Zap.Room()
 End Select
 Strng="DM command not available."
 Call IO.O
 Call Send.Unknown
Err.Rsm20:
 Exit Sub
Err.Trp20:
 Resume Err.Rsm20
End Sub

Sub Sysop.Command1
 On Local Error Goto Err.Trp21
 Remote=-1
 TempQ=False
 If Instr(User.Command," ")=False Then
    Temp.Command=Mid$(Temp.Command,Len(Config3(79))+1)
    For Last.Command.Number=1 To MaxSysopCommands
       TempZ=Last.Command.Number+MaxUserCommands+MaxDMcommands
       Call Read.Message.Record(MessWorkFile8,TempZ)
       Last.Command=UserCommandRecord.CommandSet(1)
       Last.Command=Rtrim$(Left$(Last.Command,10))
       If Left$(Last.Command,Len(Temp.Command))=Temp.Command Then
          Var$=Lcase$(Last.Command)
          Mid$(Var$,1,1)=Ucase$(Mid$(Var$,1,1))
          Last.Command=Config3(79)+Var$
	  TempQ=True
	  Exit For
       Endif
    Next
 Endif
 If TempQ=False Then
    Call Unknown.Command(Config3(79))
    Exit Sub
 Endif
 If UserCommandRecord.CommandClass(1) Then
    Graphics.Off=True
    Strng="Command restriction!"
    Call IO.O
    Graphics.Off=False
    Call Send.Restrict
    Exit Sub
 Endif
 ' check command restriction
 Var1=MaxUserCommands+MaxDMCommands+Last.Command.Number
 Call Check.Restriction(Var1,Var2)
 If Var2 Then
    Exit Sub
 Endif
 Call Update.Mess(4)
 Select Case Last.Command.Number
 Case 1 ' |Clock
    TempX=False
    Call Chain.Command(205) ' Call Time.Online(False)
 Case 2 ' |Config
'    Call Playwav(8)
    Call Chain.Program("DNDCNFG.EXE",Local.Mode,True)
 Case 3 ' |Debug
    Call Flag.Toggles(6)
    Exit Sub
 Case 4 ' |Dos
    TempX=True
    Call System.Type
    TempX$=Strng
    Call Chain.Command(152) ' Call Remote.DOS
 Case 5 ' |Edit
    Temp=True
    If Local.Mode Then
       If Rtrim$(Inline.FileName1)<>Nul Then
          Strng="Use inline editor(y/n)? "
          Call IO.I
          Temp=Yes
       Endif
    Endif
    If Temp Then
       Call Chain.Command(155) ' Call Scrnedit
    Else
       Var$=Inline.FileName1
       Call Shell.Program2(Var$) ' Call Edit.com
       Exit Sub
    Endif
 Case 6 ' |Monitor
    Call Chain.Command(144)
 Case 7 ' |Program
    Temp=True
    If Local.Mode Then
       If Rtrim$(Inline.FileName2)<>Nul Then
          Strng="Use inline interpreter(y/n)? "
          Call IO.I
          Temp=Yes
       Endif
    Endif
    If Temp Then
       TempX$=Nul
       Call Chain.Program("DNDSIC.EXE",Local.Mode,True)
    Else
       Var$=Inline.FileName2
       Call Shell.Program2(Var$) ' Call Qbasic.exe
       Exit Sub
    Endif
 Case 8 ' |Reboot
    Call Chain.Command(208) ' Call Reboot.System
 Case 9 ' |Shell
    TempX=False
    Call System.Type
    TempX$=Strng
    Call Chain.Command(152) ' Call Remote.Shell
 Case 10 ' |Sysed
    Call Chain.Program("DNDEDIT.EXE",Local.Mode,True)
 Case 11 ' |Usage
    TempX=11
    Call Chain.Command(154) ' Call Debug.Menu
 Case 12 ' |Utility
    TempX=12
    Call Chain.Command(154) ' Call Utility.Menu
 Case 13 ' |Toggle
    Call Chain.Command(203)
 Case 14 ' |Control
    Call Chain.Program("EDITEDIT.EXE",Local.Mode,True)
 Case 15 ' |Password
    Call Chain.Command(190)
 End Select
 Strng="Sysop command not available."
 Call IO.O
 Call Send.Unknown
 Exit Sub
Err.Rsm21:
 Exit Sub
Err.Trp21:
 Resume Err.Rsm21
End Sub

Sub Node.Command1
 On Local Error Goto Err.Trp22
 Remote=-1
 TempY=Parse.Temp
 Call Numeric2
 TempX=Parse.Temp
 Temp0=TempX
 Parse.Temp=TempY
 TempQ=False
 Temp.Command=Mid$(Temp.Command,Len(Config3(78))+1)
 For Last.Command.Number=1 To MaxNodeCommands
    TempZ=Last.Command.Number+MaxUserCommands+MaxDMcommands+MaxSysopCommands
    Call Read.Message.Record(MessWorkFile8,TempZ)
    Last.Command=UserCommandRecord.CommandSet(1)
    Last.Command=Rtrim$(Left$(Last.Command,10))
    If Left$(Last.Command,Len(Temp.Command))=Temp.Command Then
       Var$=Lcase$(Last.Command)
       Mid$(Var$,1,1)=Ucase$(Mid$(Var$,1,1))
       Last.Command=Config3(78)+Var$
       TempQ=True
       Exit For
    Endif
 Next
 If TempQ=False Then
    Call Unknown.Command(Config3(78))
    Exit Sub
 Endif
 ' check appended #<n>
 If Last.Command.Number<>10 Then
    If Last.Command.Number<>15 Then
       If TempX Then
          Call Unknown.Command(Config3(78))
          Exit Sub
       Endif
    Endif
 Endif
 If Normal.User Then
    If UserRecord.ClassType<AsstDM Then
       If UserCommandRecord.CommandClass(UserRecord.ClassType) Then
	  Graphics.Off=True
	  Strng="Command restriction!"
	  Call IO.O
	  Graphics.Off=False
          Call Send.Restrict
	  Exit Sub
       Endif
    Endif
 Endif
 ' check command restriction
 Var1=MaxUserCommands+MaxDMCommands+MaxSysopCommands+Last.Command.Number
 Call Check.Restriction(Var1,Var2)
 If Var2 Then
    Exit Sub
 Endif
 ' check player level
 If UserRecord.Level<=False Then
    Call Send.Illegal
    Strng="Your player level is too low!"
    Call IO.O
    Exit Sub
 Endif
 Call Update.Mess(4)
 Command.Time.Limit=UserCommandRecord.CommandLimit
 Select Case Last.Command.Number
 Case 1, 4, 14 ' /auto, /chat, /wait
    Chat.Mode=True
    Call Chain.Command(143)
    Chat.Mode=False
 Case Else
    TempX=Last.Command.Number
    Call Chain.Command(153) ' Call <node command>
 End Select
 Strng="Node command not available."
 Call IO.O
 Call Send.Restrict
Err.Rsm22:
 Exit Sub
Err.Trp22:
 Resume Err.Rsm22
End Sub

' Var1=command number
' Var2=return value
Sub Check.Restriction(Var1,Var2)
 ' fixed 09/05/2019
 On Local Error Goto Err.Trp23
 ' return value
 Var2=False
 ' check command pointer
 Var!=UserRecord.NodeList2
 If Var!=SFalse Then
    Exit Sub
 Endif
 ' open restriction file
 FileName=DND.Path+"restrict.dat"
 Close #TempFile1
 Open FileName For Random Shared As #TempFile1 Len=13
 ' Byte 1/0, FromHour/FromMin/ToHour/ToMin, ClassType, Level.
 Field #TempFile1,1 As B$,2 As FH$,2 As FM$,2 As TH$,2 As TM$,2 As CL$,2 As LV$
 ' get record length of sum of all commands (should be 206)
 Records!=MaxUserCommands+MaxDMCommands+MaxSysopCommands+MaxNodeCommands
 RecLen!=Records!*13!
 ' check command restricted from user record pointer
 If Var!>0! And Var!<=Lof(TempFile1)/RecLen! Then
    VarN!=Csng(Var1)
    If VarN!>0! And VarN!<=Records! Then
       VarR!=(Var!-1!)*Records!+VarN!
       Get #TempFile1,VarR!
       ' command restricted.
       If B$="0" Then
          Strng="Command is currently restricted."
          Goto Restrict
       Endif
       ' command time restriction
       Var1!=Csng(Cvi(FH$))*3600!+Csng(Cvi(FM$))*60! ' from
       Var2!=Csng(Cvi(TH$))*3600!+Csng(Cvi(TM$))*60! ' to
       If Var1!>SFalse Or Var2!>SFalse Then
          Call Check.Time2(Var3,Var1!,Var2!)
          If Var3=False Then
             Graphics.Off=True
             Strng="Command time restriction!"
             Call IO.O
             Strng="Command is currently restricted from "

             Z1$=Ltrim$(Str$(Cvi(FH$))) ' from hour
             Z1$=Right$("00"+Z1$,2)
             Z2$=Ltrim$(Str$(Cvi(FM$))) ' from minute
             Z2$=Right$("00"+Z2$,2)

             Z3$=Ltrim$(Str$(Cvi(TH$))) ' to hour
             Z3$=Right$("00"+Z3$,2)
             Z4$=Ltrim$(Str$(Cvi(TM$))) ' to minute
             Z4$=Right$("00"+Z4$,2)
             Strng=Strng+Z1$+":"+Z2$+" to "+Z3$+":"+Z4$

             Goto Restrict
          Endif
       Endif
       ' classtype restriction.
       C=Cvi(CL$)
       If (C And 2^UserRecord.ClassType)=2^UserRecord.ClassType Then
          Strng="Command is currently restricted from your classtype."
          Goto Restrict
       Endif
       ' level restriction.
       L=Cvi(LV$)
       If UserRecord.Level<L Then
          Strng="Command is currently restricted to level "+Form$(Cdbl(L))+"."
          Goto Restrict
       Endif
    Endif
 Endif
 Exit Sub

Restrict:
 Graphics.Off=True
 Call IO.O
 Graphics.Off=False
 Call Send.Restrict
 Var2=True
 Exit Sub
Err.Rsm23:
 Exit Sub
Err.Trp23:
 Resume Err.Rsm23
End Sub

Sub Copyright(Var)
 ' fixed 06-25-2020
 On Local Error Goto Error.Trap22
 Gosub Get.Config2
 If Var Then
    Time1$=Format$(Now,"hh:mm:ss")
    Close #TempFile1
    FileName=Data.Path1+Config3(51)+Config3(15)
    Open FileName For Random Shared As #TempFile1 Len=26
    If Lof(TempFile1)=0 Then
       Field #TempFile1,26 As S$
       Lset S$="DND Usage File v"+Version$+Chr$(13)+Chr$(10)+Chr$(26)
       Put #TempFile1,1
    Endif
    Field #TempFile1,10 As D$,8 As T$,8 As X$
    If Lof(TempFile1)/26<2 Then
       Lset D$=DateS$
       Lset T$=Time1$
       Lset X$=Mkd$(0#)
       Put #TempFile1,2
    Endif
    If Lof(TempFile1)/26<3 Then
       Lset D$="01-01-1980"
       Lset T$=Time1$
       Lset X$=Mkd$(1#)
       Put #TempFile1,3
    Endif
    Get #TempFile1,2
    Lset D$=DateS$
    Lset T$=Time1$
    Var#=Cvd(X$)
    ' start dndbbs
    If Var=-1 Then
       ' increment usage
       Var#=Var#+1#
       Lset X$=Mkd$(Var#)
       Put #TempFile1,2
       ' reset boot date
       Get #TempFile1,3
       Lset D$=DateS$
       Lset T$=Time1$
       Put #TempFile1,3
    Endif
    Run.Number=Var#
    ' opening screen
    If Var=-2 Then
       Exit Sub
    Endif
    If Bypass.Login Or Bypass.Screen Or Debug.Mode Then
       Exit Sub
    Endif
    If Run.Number>Option1# Then
       Exit Sub
    Endif
    Call Shell.Program("COPYSCRN.EXE","")
 Endif
 Exit Sub
Get.Config2:
 Option1#=10#
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[DNDBBS]" Then
       Do
          VarX=VarX+1
          If VarX>Options.Lines Then
             Return
          Endif
          Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
          If Ucase$(Var$)="[END]" Then
             Return
          Endif
          VarZ=Instr(Var$,"=")
          If VarZ Then
             Var2$=Ltrim$(Rtrim$(Left$(Var$,VarZ-1)))
             Var3$=Ltrim$(Rtrim$(Mid$(Var$,VarZ+1)))
             Select Case Lcase$(Var2$)
             Case "copyscrn.count"
                VarY=Int(Val(Var3$)+.5)
                If VarY>=1 And VarY<=32767 Then
                   Option1#=Cdbl(VarY)
                Endif
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
Error.Resume22:
 Exit Sub
Error.Trap22:
 Resume Error.Resume22
End Sub

Sub Flag.Toggles(Var)
 On Local Error Goto Error.Trap24
 Select Case Var
 Case 1
    User.Linefeeds=Not User.Linefeeds
    If User.Linefeeds=False Then
       Strng="Linefeeds on."
    Else
       Strng="Linefeeds off."
    Endif
    Call IO.O
 Case 2
    Echo=Not Echo
    If Echo=False Then
       Strng="Message echo on."
    Else
       Strng="Message echo off."
    Endif
    Call IO.O
 Case 3
    User.Echo=Not User.Echo
    If User.Echo=False Then
       Strng="Echo duplex on."
    Else
       Strng="Echo duplex off."
    Endif
    Call IO.O
 Case 4
    User.WordWrap=Not User.WordWrap
    If User.WordWrap=False Then
       Strng="Wordwrap on."
    Else
       Strng="Wordwrap off."
    Endif
    Call IO.O
 Case 5
    Sorting=Sorting+1
    Select Case Sorting
    Case 1
       Strng="Inventory charges sorting on."
    Case 2
       Strng="Inventory plus sorting on."
    Case Else
       Sorting=False
       Strng="Inventory sorting off."
    End Select
    Call IO.O
 Case 6
    Debug.Mode=Not Debug.Mode
    If Debug.Mode Then
       Strng="DEBUG mode on."
    Else
       Strng="DEBUG mode off."
    Endif
    Call IO.O
 Case 7
    Disk.Log=Not Disk.Log
    Call Open.Session.Files
 Case 8
    Print.Log=Not Print.Log
    Call Open.Session.Files
 Case 9
    IO.Upper.Case=Not IO.Upper.Case
    If IO.Upper.Case Then
       Strng="Uppercase mode on."
    Else
       Strng="Uppercase mode off."
    Endif
    Call IO.O
 End Select
Error.Resume24:
 Exit Sub
Error.Trap24:
 Resume Error.Resume24
End Sub

Sub Get.Preferences
 On Local Error Goto Error.Trap27
 Allow.Break=True
 Break=False
 Toggle.ANSI=False
 Do While Lost.Carrier=False
    If Break Then
       Exit Do
    Endif
    Call Check.Program(Var)
    If Var Then
       Exit Do
    Endif
    Graphics.Off=False
    Strng="Preference menu:"
    Call IO.O
    Graphics.Off=True
    Strng="[1]Ansi"
    If Local.Mode Then
       If Local.ANSI.Color Then
          Strng=Strng+" (on)"
       Else
          Strng=Strng+" (off)"
       Endif
    Else
       If Remote.ANSI.Color Then
          Strng=Strng+" (on)"
       Else
          Strng=Strng+" (off)"
       Endif
    Endif
    Call IO.O
    Strng="[2]Avatar"
    If Local.Mode Then
       If Local.Avatar.Color Then
          Strng=Strng+" (on)"
       Else
          Strng=Strng+" (off)"
      Endif
    Else
       If Remote.Avatar.Color Then
          Strng=Strng+" (on)"
       Else
          Strng=Strng+" (off)"
       Endif
    Endif
    Call IO.O
    Strng="[3]Echo duplex"
    If User.Echo=False Then
       Strng=Strng+" (on)"
    Else
       Strng=Strng+" (off)"
    Endif
    Call IO.O
    Strng="[4]Linefeeds"
    If User.Linefeeds=False Then
       Strng=Strng+" (on)"
    Else
       Strng=Strng+" (off)"
    Endif
    Call IO.O
    Strng="[5]Linelength
    Strng=Strng+" ("+Mid$(Str$(User.Linelength),2)+")"
    Call IO.O
    Strng="[6]Pagelength"
    Strng=Strng+" ("+Mid$(Str$(User.Pagelength),2)+")"
    Call IO.O
    Strng="[7]Wordwrap"
    If User.WordWrap=False Then
       Strng=Strng+" (on)"
    Else
       Strng=Strng+" (off)"
    Endif
    Call IO.O
    Strng="[8]Uppercase"
    If IO.Upper.Case Then
       Strng=Strng+" (on)"
    Else
       Strng=Strng+" (off)"
    Endif
    Call IO.O
    Strng="[9]Edit line test"
    Call IO.O
    Graphics.Off=False
    Strng="Enter preference selection(1-9, Q to quit)? "
    If Toggle.ANSI=False Then
       Toggle.ANSI=True
       No.Input.Out="1"
    Else
       No.Input.Out="Q"
    Endif
    Call IO.I
    Var$=Nul
    Temp=Int(Val(Out2)+.5)
    If Ucase$(Out2)="Q" Then
       Exit Do
    Endif
    Select Case Temp
    Case 1
       Call Get.ANSI
    Case 2
       Call Get.Avatar
    Case 3
       Call Flag.Toggles(3)
    Case 4
       Call Flag.Toggles(1)
    Case 5
       Call Get.Linelength
    Case 6
       Call Get.Pagelength
    Case 7
       Call Flag.Toggles(4)
    Case 8
       Call Flag.Toggles(9)
    Case 9
       Strng="Edit line test entry(Q to Quit):"
       Call IO.O
       Do While Lost.Carrier=False
          If Break Then
             Exit Do
          Endif
          Call Check.Program(Var)
          If Var Then
             Exit Do
          Endif
          Strng="?"
          Call IO.I
          If Ucase$(Out2)="Q" Then
             Exit Do
          Endif
       Loop
    End Select
 Loop
 Allow.Break=False
 Break=False
Error.Resume27:
 Exit Sub
Error.Trap27:
 Resume Error.Resume27
End Sub

Sub Get.Linelength
 On Local Error Goto Error.Trap31
 Strng="Linelength(40,80)? "
 Call IO.I
 Var=Int(Val(Out2)+.5)
 If Var=40 Or Var=80 Then
    User.Linelength=Var
    Strng="Linelength now"+Str$(Var)+" chars."
    Call IO.O
 Else
    Strng="Linelength out of range."
    Call IO.O
 Endif
Error.Resume31:
 Exit Sub
Error.Trap31:
 Resume Error.Resume31
End Sub

Sub Get.Pagelength
 On Local Error Goto Error.Trap32
 Strng="Pagelength(25,43,50)? "
 Call IO.I
 Var=Int(Val(Out2)+.5)
 If Var=25 Or Var=43 Or Var=50 Then
    User.Pagelength=Var
    Strng="Pagelength now"+Str$(Var)+" lines."
    Call IO.O
 Else
    Strng="Pagelength out of range."
    Call IO.O
 Endif
Error.Resume32:
 Exit Sub
Error.Trap32:
 Resume Error.Resume32
End Sub

Sub Shell.Program2(Var$)
 On Local Error Goto Error.Trap33a
 If Dir$(Var$)=Nul Then
    Strng="Filename "+Chr$(34)+Var$+Chr$(34)+" not found."
    Call IO.O
    Exit Sub
 Endif
 Call Status.Line(-2)
 Call ScreenANSI(4,37,7)
 Color 15,0
 Call Save.Screen(False)
 Call Close.Files
 Shell Var$
 Call Open.Shell.Files
 Call Save.Screen(True)
 Call Reset.Status.Line
 Call Reset.Cursor
Error.Resume33a:
 Exit Sub
Error.Trap33a:
 Resume Error.Resume33a
End Sub

Sub Shell.Program3
 On Local Error Goto Error.Trap33x
 Var$="TOPTEN.EXE"
 Var2$="/Z/N:"+NodeX
 Call Shell.Program(Var$,Var2$)
 Var$=DND.Path+"TOPTEN"+NodeX+".DAT"
 Call Out.File(Var$)
Error.Resume33x:
 Exit Sub
Error.Trap33x:
 Resume Error.Resume33x
End Sub

' subroutine to display unknown message
Sub Unknown.Command(Var$)
 Graphics.Off=True
 Strng="Unknown command!"
 Call IO.O
 If UserRecord.Brief=False Then
    Strng="Type "+Var$+"? for Help.."
    Call IO.O
 Endif
 Graphics.Off=False
 Call Send.Unknown
End Sub

' subroutine to store message
Sub Send.Restrict
 Last.Command="<restrict>"
 Call Update.Mess(4)
End Sub

' subroutine to store message
Sub Send.Unknown
 Last.Command="<unknown>"
 Call Update.Mess(4)
End Sub

' subroutine to store message
Sub Send.Unknown2
 Call Update.Mess(4)
 Strng="Nothing happens!"
 Call IO.O
End Sub

' subroutine to store message
Sub Send.Illegal
 Last.Command="<illegal>"
 Call Update.Mess(4)
End Sub

' subroutine to store message and call help
Sub Read.Help
 Last.Command="<read help>"
 Call Update.Mess(4)
 Last.Command.Number=59
 Call Chain.Command(59)
 Strng="Help not available."
 Call IO.O
End Sub
