 Rem File: Dndsub2 for Dndbbs Version v5.0a Release r2.0
 Rem $Include: 'dndbbs.inc'
Sub Login
 On Local Error Goto ErrorTrp1
 Call Prelogin
 Call Init.Spells
 Call Get.Login.Tries(VarZ,VarZ3,VarZ4)
 If Bypass.Login Then
    Logged.In=False
    Call Alt.Login(Var)
    Select Case Var
    Case -1 ' valid
       Call Get.User.Stats(Var)
       If Var=False Then
          Call playwav(5)
	  Call Hang.Up(12)
          Exit Sub
       Endif
    Case 0 ' invalid
       Call playwav(5)
       Call Hang.Up(13)
       Exit Sub
    Case 1 ' online
       Call playwav(5)
       Call Hang.Up(15)
       Exit Sub
    End Select
    Call Display.Prenotice
    Gosub Check.Node
    Call Update.Login
    Call Time.Restriction
    If Security.Guard=False Then
       Goto Null.Login
    Endif
    Logged.In=True
    Call Login.User
    Exit Sub
 Endif
 TempD=False
 Call Display.Prenotice
 Do While Security.Guard
    If Config2(4) Then
       If TempD=False Then
	  Call Out.File(Prelog.FileName)
       Endif
    Endif
    TempD=False
    Login.Try=False
    Tries=False
    Do While Security.Guard
       New.User=False
       Call Get.Codename(Tries)
       If Tries>=VarZ Then
          Call playwav(5)
          Call Hang.Up(7)
          Exit Sub
       Endif
       If Security.Guard=False Then
          Goto Null.Login
       Endif
       If GuestRecord.DualPassword=-2 Then ' no password required
          Eat$=""
       Else
          Call Get.PassWord(Tries2)
          If Tries2>=VarZ Then
             Call playwav(5)
             Call Hang.Up(7)
             Exit Sub
          Endif
       Endif
       If GuestRecord.DualPassword=-2 Then ' no password required
          Eat$=""
       Else
          If GuestRecord.DualPassword=-1 Then
             Call Get.PassWord2(Tries3)
             If Tries3>=VarZ Then
                Call playwav(5)
                Call Hang.Up(7)
                Exit Sub
             Endif
          Endif
       Endif
       If Security.Guard=False Then
          Goto Null.Login
       Endif
       Call Find.PassWord(Logged.User)
       If Logged.User Then
          Call Verify.PassWord(Logged.Pass)
          Select Case Logged.Pass
          Case -1
	     Exit Do
          Case 1
             Strng="That codename is active on another node."
             Call IO.O
             Call Playwav(4)
             Out2="Someone just tried to logon with your codename"
             If Rtrim$(NodeX)=Nul Then
                Out2=Out2+"(Node -)."
             Else
                Out2=Out2+"(Node "+NodeX+")."
             Endif
             Call Send.Mess(28,User.Index,SFalse,Out2)
          Case 0
             If Login.Try>=VarZ Then
                Call playwav(5)
                Call Hang.Up(7)
                Exit Sub
             Endif
             Login.Try=Login.Try+1
             Strng="Illegal password attempt!"
             Call IO.O
             Call Playwav(4)
             Call Sleep.Second2(5!)
             Tries=Tries+1
             Strng2=UserRecord.Question
             If Rtrim$(Strng2)<>Nul Then
                Call Crypto(Strng2)
                If Local.Mode Then
                   Strng="Ask password question(y/n/*)? "
                Else
                   Strng="Ask password question(y/n)? "
                Endif
                Call IO.I
                If Out2="*" Then
                   If Local.Mode Then
                      Strng2=UserRecord.Answer
                      Call Crypto(Strng2)
                      Strng2=Rtrim$(Strng2)
                      Strng="Answer: "+Strng2
                      Call IO.O
                   Endif
                Endif
                If Yes Then
                   Strng2=Lcase$(Rtrim$(Strng2))
                   Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
                   Graphics.Off=True
                   If Right$(Strng2,1)="?" Then
                      Strng=Strng2+" "
                   Else
                      Strng=Strng2+"? "
                   Endif
                   Hidden=True
                   Call IO.I
                   Hidden=False
                   Out2=Rtrim$(Out2)
                   Out2=Lcase$(Out2)
                   Strng2=UserRecord.Answer
                   Call Crypto(Strng2)
                   Strng2=Rtrim$(Strng2)
                   If Out2=Strng2 Then
                      Out2=Rtrim$(UserRecord.PassWord3)
                      Call Crypto(Out2)
                      Out2=Rtrim$(Out2)
                      For Tmp1=1 To Len(Out2)
                         If Asc(Mid$(Out2,Tmp1,1))<32 Then
                            Mid$(Out2,Tmp1,1)="?"
                         Endif
                      Next
                      If Out2=String$(20,"?") Then
                         Out2="????????"
                      Endif
                      Strng="Your password is "+Quote+Lcase$(Out2)+Quote+"."
                   Else
                      Strng="Incorrect answer!"
                   Endif
                   Graphics.Off=False
                   Call IO.O
                Endif
             Endif
          End Select
       Else
          If GuestRecord.OpenSystem=False Then
             Strng="Sorry, system is currently closed.."
             Call IO.O
             Call playwav(5)
             Call Hang.Up(7)
             Exit Sub
          Endif
          If GuestRecord.OpenSystem Then
             Call OpenSystem.Times(VarQ2)
             If VarQ2=False Then
                Var$=Nul
                If Len(Strng3) Then
                   Var$=Left$(Strng3,Len(Strng3)-1)
                Endif
                If Len(Var$) Then
                   Strng="Sorry, system is currently opened only at "+Var$+"."
                   Call IO.O
                Endif
                Call playwav(5)
                Call Hang.Up(7)
                Exit Sub
             Endif
          Endif
          If Security.Guard=False Then
             Goto Null.Login
          Endif
          Graphics.Off=False
          Strng="Username not found in files."
          Call IO.O
          If Security.Guard=False Then
             Goto Null.Login
          Endif
          Call Verify.Newuser(New.User)
          If Security.Guard=False Then
             Goto Null.Login
          Endif
          Select Case New.User
          Case 0
             If Login.Try>=VarZ Then
                Call playwav(5)
                Call Hang.Up(7)
                Exit Sub
             Endif
             Login.Try=Login.Try+1
          Case 1
             Call playwav(5)
	     Call Hang.Up(8)
	     Exit Sub
          Case -1
             If GuestRecord.DualPassword=-1 Then
                Call Verify.Newuser2(New.User)
             Endif
             If Security.Guard=False Then
                Goto Null.Login
             Endif
             If New.User Then
                ' read a blank userrecord
                User.Index=Lof(UserFile)/UserRecLen+1!
                Call Read.Record(UserFile,User.Index)
                Call Init.Newuser
                If Security.Guard=False Then
                   Goto Null.Login
                Endif
                Call Verify.Newlogin(New.User,True)
                If Security.Guard=False Then
                   Goto Null.Login
                Endif
                If New.User Then
                   Exit Do
                Endif
             Endif
          End Select
       Endif
    Loop
    If New.User=False Then
       Call Update.Login
       Call Time.Restriction
       If Security.Guard=False Then
          Goto Null.Login
       Endif
       Logged.In=True
       If GuestRecord.PassWordQuestion Then
          VarR=0
          If Rtrim$(UserRecord.Question)=Nul Then
             VarR=-1
          Endif
          If UserRecord.Question=String$(80,Chr$(0)) Then
             VarR=-1
          Endif
          If VarR Then
             Call Init.Question
          Endif
       Endif
       Gosub Check.Node
       If Config2(6) Then
          Call Out.File(Notice.FileName)
       Endif
       Exit Do
    Endif
    If Config2(6) Then
       Call Out.File(Notice.FileName)
    Endif
    If New.User Then
       Call Roll.Character
       If Security.Guard=False Then
          Goto Null.Login
       Endif
       Call Verify.Newlogin(New.User,False)
       If New.User Then
          ' write a new userrecord
          User.Index=Lof(UserFile)/UserRecLen+1!
          Call Write.Record(UserFile,User.Index)

          ' init newuser settings
	  Call Clear.LogFile
          Call Clear.UserInv
	  Call Clear.TeamFile
          Call Clear.ScrollFile
          Call Clear.Containers
          Call Clear.Bank
          UserRecord.Question=Nul
          UserRecord.Answer=Nul
          If GuestRecord.PassWordQuestion Then
             Call Init.Question
          Endif
	  Exit Do
       Endif
    Endif
 Loop
 If New.User Then
    Call Init.Inventory
    Call Init.Mail(False)
    Strng="Rolled new character"
    If Rtrim$(NodeX)=Nul Then
       Strng=Strng+" (Node -)"
    Else
       Strng=Strng+" (Node "+NodeX+")"
    Endif
    Call Update.DayFile(Strng,True,False)
    Call Update.Login
 Endif
 If Security.Guard=False Then
    Goto Null.Login
 Endif
 Call Get.User.Stats(Var)
 If Var=False Then
    Call playwav(5)
    Call Hang.Up(12)
    Exit Sub
 Endif
 Logged.In=True
 If Config2(5) Then
    Call Out.File(Welcome.FileName)
 Endif
 Call Login.User
 Exit Sub
Null.Login:
 CodeName.Temp=Nul
 PassWord.Temp=Nul
 PassWord.Temp2=Nul
 Lost.Carrier=True
 Exit Sub
Check.Node:
 If Mid$(UserRecord.NodeList,Node+1,1)="0" Then
    If Rtrim$(NodeX)=Nul Then
       Strng2="-"
    Else
       Strng2=NodeX
    Endif
    Strng="Node #"+Strng2+" access not allowed!"
    Call IO.O
    Call playwav(5)
    Call Hang.Up(19)
    Exit Sub
 Endif
 Return
ErrorRsm1:
 Exit Sub
ErrorTrp1:
 Security.Guard=False
 Resume ErrorRsm1
End Sub

Sub Find.PassWord(Var)
 On Local Error Goto ErrorTrp2
 Var=False
 For User.Index=1! To Lof(UserFile)/UserRecLen
    Call Read.Record(UserFile,User.Index)
    Out2=Rtrim$(CodeName.Temp)
    Strng=UserRecord.CodeName
    Strng=Rtrim$(Strng)
    If Strng=Out2 Then
       Var=True
       Exit Sub
    Endif
 Next
 User.Index=SFalse
ErrorRsm2:
 Exit Sub
ErrorTrp2:
 Security.Guard=False
 Resume ErrorRsm2
End Sub

Sub Verify.PassWord(Var)
 On Local Error Goto ErrorTrp3
 Var=False
 Call Search.Mess(User.Index)
 If Temp! Then
    Var=1
    Exit Sub
 Endif
 Strng=Rtrim$(UserRecord.PassWord)
 If GuestRecord.DualPassword=-2 Then ' no password required
    Var=True
    Exit Sub
 Endif
 Out2=PassWord.Temp
 Call Cryptograph(Out2)
 Out2=Rtrim$(Out2)
 If Strng=Out2 Then
    Var=True
 Endif
 If Var Then
    If GuestRecord.DualPassword=-1 Then
       Var=False
       Strng=Rtrim$(UserRecord.PassWord2)
       If Strng=Nul Then
          Var$=PassWord.Temp2
          Call Cryptograph(Var$)
          UserRecord.PassWord2=Var$
          Call Write.Record(UserFile,User.Index)
          Var=True
       Else
          Out2=PassWord.Temp2
          Call Cryptograph(Out2)
          Out2=Rtrim$(Out2)
          If Strng=Out2 Then
             Var=True
          Endif
       Endif
    Endif
 Endif
ErrorRsm3:
 Exit Sub
ErrorTrp3:
 Security.Guard=False
 Resume ErrorRsm3
End Sub

Sub Verify.Newlogin(Var,Var1)
 On Local Error Goto ErrorTrp4
 Var=False
 Do While Security.Guard
    Graphics.Off=False
    If Var1 Then
       Strng=Config3(5)
    Else
       Strng=Config3(77)
    Endif
    No.Echo=True
    Line.Length=1
    Call IO.I
    No.Echo=False
    If Out2=" " Then
       Exit Sub
    Endif
    If No.Input Then
       Var=True
       Exit Sub
    Endif
 Loop
ErrorRsm4:
 Exit Sub
ErrorTrp4:
 Security.Guard=False
 Resume ErrorRsm4
End Sub

Sub Get.Codename(VarQ)
 On Local Error Goto ErrorTrp5
 Gosub Get.Config1
 Call Get.Login.Tries(VarZ2,VarZ3,VarZ4)
 Call Display.Guest
 Do While Security.Guard
    Do While Security.Guard
       GuestLogin=False
       Strng=Nul
       Call IO.O
       Graphics.Off=False
       If Local.Mode And Debug.Mode Then
          If Option1 And Option2 Then
             Strng="Local Sysop: Enter ? to list or * to search."
             Call IO.O
          Else
             If Option1 Then
                Strng="Local Sysop: Enter ? to list."
                Call IO.O
             Else
                If Option2 Then
                   Strng="Local Sysop: Enter * to search."
                   Call IO.O
                Endif
             Endif
          Endif
       Endif
       Graphics.Off=True
       Strng=Space$(9)+"|-->-+----+----+----+----+----+| (try"+Str$(VarQ+1)+" of"+Str$(VarZ2)+")"
       Call IO.O
       Carriage.Return=True
       Strng="Codename?["+Space$(30)+"]"
       Call IO.O
       If Option5 Then
          Call Password.Mask(30)
          Strng=""
          Line.Length=30
          Hidden=True
          Call IO.I
          Hidden=False
          Graphics.Off=False
       Else
          Call Back.Space2(31)
          Line.Length=30
          Upper.Case=True
          Call IO.I
          Upper.Case=False
          Graphics.Off=False
       Endif
       Out2=Ltrim$(Out2)
       Out2=Rtrim$(Out2)
       Out2=Ucase$(Out2)
       VarQ2=0
       If Local.Mode And Debug.Mode Then
          If Out2="?" Then
             VarQ2=-1
             If Option1 Then
                Gosub List.Users
                Call Convert.ANSI(False,VarQ,VarR)
             Endif
          Else
             If Out2="*" Then
                VarQ2=-1
                If Option2 Then
                   Gosub Search.Users
                   Call Convert.ANSI(False,VarQ,VarR)
                Endif
             Endif
          Endif
       Endif
       If VarQ2=0 Then
          CodeName.Temp=Out2
          If Len(CodeName.Temp)>False Then
             Call Validate.Codename(VarZ)
             Select Case VarZ
             Case True ' is valid
                Exit Do
             Case 1 ' not valid
                Strng="Illegal codename."
                Call IO.O
             Case 0 ' not valid w/ message
                Call IO.O
             End Select
          Endif
          VarQ=VarQ+1
          If VarQ>=VarZ2 Then
             Exit Sub
          Endif
       Endif
    Loop
    If GuestLogin Then
       Strng="Guest"
    Else
       Strng=Rtrim$(CodeName.Temp)
       Strng=Lcase$(Strng)
       Mid$(Strng,1,1)=Ucase$(Mid$(Strng,1,1))
    Endif
    Line.Length=1
    No.Input.Out="Y"
    Strng="You are "+Quote+Strng+Quote+"(y/n)? "
    Call IO.I
    If Yes Then
       Exit Do
    Endif
    VarQ=VarQ+1
    If VarQ>=VarZ2 Then
       Exit Sub
    Endif
 Loop
 Exit Sub

List.Users:
 Temp1=False
 For Temp1!=1! To Lof(UserFile)/UserRecLen
    Call Read.Record(UserFile,Temp1!)
    Out3=UserRecord.CodeName
    Out3=Lcase$(Rtrim$(Out3))
    If Out3<>"<deleted>" Then
       Gosub Display.User
       If No Or Quit Then
          Exit For
       Endif
    Endif
 Next
 If Temp1 Then
    Call More.Prompt
 Endif
 Out2=Nul
 Return

Search.Users:
 If Option3 Then
    Strng="Enter codename search(?,* allowed): "
 Else
    Strng="Enter codename search: "
 Endif
 Call IO.I
 Var2$=Lcase$(Out2)
 Temp1=False
 Var2=False
 For Temp1!=1! To Lof(UserFile)/UserRecLen
    Call Read.Record(UserFile,Temp1!)
    Out3=UserRecord.CodeName
    Out3=Lcase$(Rtrim$(Out3))
    If Out3<>"<deleted>" Then
       Out2=Var2$
       If Option3 Then
          Call InstrSUB2(VarX)
       Else
          VarX=Instr(Out3,Out2)
       Endif
       If VarX Then
          Var2=True
          Gosub Display.User
          If No Or Quit Then
             Exit For
          Endif
       Endif
    Endif
 Next
 If Var2=False Then
    Strng="Codename not found."
    Call IO.O
 Endif
 If Temp1 Then
    Call More.Prompt
 Endif
 Out2=Nul
 Return

Display.User:
 Strng=Out3
 If Len(Strng) Then
    Mid$(Strng,1,1)=Ucase$(Mid$(Strng,1,1))
 Endif
 Strng=Rtrim$(UserRecord.Prefix1)+Strng
 Call Convert.ANSI(True,VarQ3,VarR)
 Carriage.Return=True
 Graphics.On=True
 Call IO.O
 Graphics.On=False
 Strng=Strng+" (level "+Form$(Cdbl(UserRecord.Level))+")"
 If UserRecord.ClassType=AsstDM Then
    Strng=Strng+" [AsstDM]"
 Endif
 If UserRecord.ClassType=DM Then
    Strng=Strng+" [DM]"
 Endif
 If UserRecord.Flags And Special.Char4 Then
    Strng=Strng+" [Sysop]"
 Endif
 Call Search.Mess.File(Temp1!,Var1)
 If Var1 Then
    Strng=Strng+" {online}"
 Endif
 If Option4 Then
    Var3$=Rtrim$(UserRecord.PassWord3)
    Call Crypto(Var3$)
    Var3$=Rtrim$(Var3$)
    For Tmp1=1 To Len(Var3$)
       If Asc(Mid$(Var3$,Tmp1,1))<32 Then
          Mid$(Var3$,Tmp1,1)="?"
       Endif
    Next
    If Var3$=String$(20,"?") Then
       Var3$="????????"
    Endif
    If Var3$=Nul Then
       Var3$="<none>"
    Endif
    Strng=Strng+" Password: "+Var3$
 Endif
 Graphics.Off=True
 Call IO.O
 Temp1=Temp1+1
 If Temp1>=User.Pagelength-2 Then
    Temp1=False
    Call More.Prompt
 Endif
 Return

Get.Config1:
 Option1=-1
 Option2=-1
 Option3=-1
 Option4=0
 Option5=0
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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 "allow.sysop.list"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   Option1=0
                End Select
             Case "allow.sysop.search"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   Option2=0
                End Select
             Case "allow.search.specs"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   Option3=0
                End Select
             Case "allow.password.display"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   Option4=-1
                End Select
             Case "make.codename.input"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   Option5=-1
                End Select
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
ErrorRsm5:
 Exit Sub
ErrorTrp5:
 Security.Guard=False
 Resume ErrorRsm5
End Sub

' VarZ returns:
'   -1  =  valid codename
'    0  =  invalid w/ message
'    1  =  invalid w/o message
'    2  =  invalid & displayed messages
Sub Validate.Codename(VarZ)
 On Local Error Goto ErrorTrp5a
 Redim Temp.ArrayS(10) As String
 Const MaxDisable=1024
 Array=10
 Gosub Get.Config6
 VarZ=True ' defaults to is valid
 Strng=CodeName.Temp
 Call Valid.Name(Strng)
 If TempA=False Then
    VarZ=1
    Exit Sub
 Endif
 ' check against badlogin.dat
 Close #TempFile1
 FileName=Data.Path1+Config3(97)+File.Extension1
 If Dir$(FileName)<>Nul Then
    Open FileName For Input Shared As #TempFile1
    Do
       If Eof(TempFile1) Then
          Exit Do
       Endif
       Line Input #TempFile1,Out2
       Call Strip.Line(Out2)
       If Len(Out2) Then
          Out3=Lcase$(Rtrim$(Strng))
          Call InstrSUB2(VarX) ' match ? and *
          If VarX Then
             VarZ=1
             Exit Sub
          Endif
       Endif
    Loop
 Endif
 ' check against permanently deleted usernames
 Close #TempFile1
 FileName=DND.Path+"delete.log"
 If Dir$(FileName)<>Nul Then
    Open FileName For Input Shared As #TempFile1
    Do
       If Eof(TempFile1) Then
          Exit Do
       Endif
       Line Input #TempFile1,Var$ ' username
       If Eof(TempFile1) Then
          Exit Do
       Endif
       Line Input #TempFile1,Var1$ ' date deleted
       If Eof(TempFile1) Then
          Exit Do
       Endif
       Line Input #TempFile1,Var3$ ' reason for deletion
       Out2=Lcase$(Rtrim$(Var$))
       Out3=Lcase$(Rtrim$(Strng))
       VarX=False
       If Len(Out2) Then
          Call InstrSUB2(VarX) ' match ? and *
       Endif
       If VarX Then
          VarZ=2
          If Rtrim$(Var1$)<>Nul Then
             Strng="Deleted Codename: "+Var1$
          Else
             Strng="Deleted Codename."
          Endif
          Call IO.O
          If Rtrim$(Var3$)<>Nul Then
             Strng="Reason: "+Var3$
             Call Convert.String
             Call Convert.ANSI(True,VarQ3,VarR)
             Carriage.Return=True
             Graphics.On=True
             Call IO.O
             Graphics.On=False
          Endif
          Exit Sub
       Endif
    Loop
 Endif
 ' compare against remaining strings
 Parsed.Command1=Codename.Temp
 Call Numeric
 If Parse.Temp Then
    VarZ=1
    Exit Sub
 Endif
 Call Valid(CodeName.Temp,30)
 If Len(CodeName.Temp)=False Then
    VarZ=1
    Exit Sub
 Endif
 If Len(Strng)<3 Then
    VarZ=False
    Strng="Codename must be at least 3 characters."
    Exit Sub
 Endif
 If Instr(Strng," ") Then
    VarZ=2
    Strng="Codename cannot contain spaces."
    Call IO.O
    Strng="Instead of spaces use underscore.."
    Call IO.O
    Strng="Codename should not be your real name!"
    Call IO.O
    Exit Sub
 Endif
 ' reset special symbols
 If Option1$=Nul then
    Option1$=Chr$(0)
 Endif
 ' check all symbols except underscore plus additional config
 TokenList$ = "~`!@#$%^&*()-+=|\{[}]:;'<,>.?/" + CHR$(34)
 VarQ$ = TokenList$ + Option2$
 For VarQ=1 To Len(VarQ$)
    VarZ$=Mid$(VarQ$,VarQ,1)
    If Instr(Strng,VarZ$) Then
       ' check allowed chars
       If Instr(Option1$,VarZ$) Then
          Eat$=Nul
       Else
          VarZ=1
          Exit Sub
       Endif
    Endif
 Next
 If Option1 Then
    If Left$(Lcase$(Strng),4)="self" Then
       VarZ=False
       Strng="Your codename should not start with 'self'.."
       Exit Sub
    Endif
 Endif
 ' "the", "all"
 If Option2 Then
    If Lcase$(Strng)="the" Then
       VarZ=False
       Strng="Your codename should not be 'the'.."
       Exit Sub
    Endif
    If Lcase$(Strng)="all" Then
       VarZ=False
       Strng="Your codename should not be 'all'.."
       Exit Sub
    Endif
 Endif
 ' "god"
 If Option6 Then
    If Lcase$(Strng)="god" Then
       VarZ=False
       Strng="Your codename should not be 'god'.."
       Exit Sub
    Endif
 Endif
 ' "the" or "all" followed by symbol
 If Option2 Then
    If Left$(Lcase$(Strng),3)="the" Then
       Var2$=Mid$(Strng,4,1)
       TokenList$ = TokenList$ + "_"
       If Instr(TokenList$, Var2$) Then
          VarZ=False
          Strng="Your codename should not start with 'the'.."
          Exit Sub
       Endif
    Endif
    If Left$(Lcase$(Strng),3)="all" Then
       Var2$=Mid$(Strng,4,1)
       TokenList$ = TokenList$ + "_"
       If Instr(TokenList$, Var2$) Then
          VarZ=False
          Strng="Your codename should not start with 'all'.."
          Exit Sub
       Endif
    Endif
 Endif
 If Option3 Then
    Var2$=Left$(Strng,1)
    If Var2$>="0" And Var2$<="9" Then
       VarZ=False
       Strng="Codename cannot start with a number."
       Exit Sub
    Endif
 Endif
 ' read reserved words from file
 If Option4 Then
    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,Out2
          Call Strip.Line(Out2)
          If Len(Out2) Then
             Out2=Ucase$(Out2)
             If Strng=Out2 Then
                VarZ=False
                Strng="Codename cannot be a reserved word."
                Exit Sub
             Endif
          Endif
        Loop
     Endif
 Endif
 ' read reserved words from data
 If Option5 Then
    For VarX=1 To MaxStrips
       TempZ=VarX+MaxUserCommands+MaxDMcommands+MaxSysopCommands+MaxNodeCommands+MaxLetters
       Call Read.Message.Record(MessWorkFile8,TempZ)
       Var$=Rtrim$(UserCommandRecord.CommandSet(1))
       If Strng=Var$ Then
          VarZ=False
          Strng="Codename cannot be a reserved word."
          Exit Sub
       Endif
    Next
 Endif
 ' compare against blocked usernames
 For VarX=1 To Array
    Var$=Rtrim$(Temp.ArrayS(VarX))
    If Var$<>Nul Then
       If Lcase$(Var$)=Lcase$(Strng) Then
          VarZ=False
          Strng="Codename is currently blocked."
          Exit Sub
       Endif
    Endif
 Next
 ' compare ansi prefix char
 Strng3=ANSIPrefixChar
 If Len(Strng3) Then
    If Instr(CodeName.Temp,Strng3)>0 Then
       VarZ=1
       Exit Sub
    Endif
 Endif
 If Left$(CodeName.Temp,5)="GUEST" Then
    If Len(Rtrim$(CodeName.Temp))>5 Then
       VarZ=1
       Exit Sub
    Endif
    If Rtrim$(NodeX)=Nul Then
       VarZ=False
       Strng="Illegal node for guest!"
       Exit Sub
    Endif
    If GuestRecord.GuestAllowed=False Then
       VarZ=False
       Strng="Guest account not currently open.."
       Exit Sub
    Endif
    CodeName.Temp="GUEST"+NodeX
    GuestLogin=True
 Endif
 Exit Sub
Get.Config6:
 For VarZ=1 To Array
    Temp.ArrayS(VarZ)=Nul
 Next
 Option1$=Nul
 Option2$=Nul
 Option1=-1
 Option2=-1
 Option3=-1
 Option4=-1
 Option5=-1
 Option6=-1
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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)))

             If Lcase$(Left$(Var2$,16))="disable.codename" Then
                VarY=Int(Val(Mid$(Var2$,17)))
                If VarY>=1 Then
                   If VarY>Array Then
                      If VarY<=MaxDisable Then
                         Array=VarY
                         Redim Preserve Temp.ArrayS(Array) As String
                      Endif
                   Endif
                Endif
                If VarY<=MaxDisable Then
                   Temp.ArrayS(VarY)=Lcase$(Var3$)
                Endif
             Endif

             Select Case Lcase$(Var2$)
             Case "allow.login.chars"
                Option1$=Var3$
             Case "additional.login.chars"
                Option2$=Var3$
             Case "disable.self"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option1=0
                End Select
             Case "disable.the"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option2=0
                End Select
             Case "disable.god"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option6=0
                End Select
             Case "disable.numeric"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option3=0
                End Select
             Case "disable.reserved.words"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option4=0
                End Select
             Case "disable.reserved.words.data"
                Select Case Lcase$(Var3$)
                Case "0","false","off"
                   Option5=0
                End Select
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
ErrorRsm5a:
 Exit Sub
ErrorTrp5a:
 Security.Guard=False
 Resume ErrorRsm5a
End Sub

Sub Get.PassWord(VarQ)
 On Local Error Goto ErrorTrp6
 Call Get.Login.Tries(VarZ2,VarZ3,VarZ4)
 Call Display.Guest
 VarQ=False
 Do While Security.Guard
    Strng=Nul
    Call IO.O

    ' make password entry area
    Graphics.Off=False
    Carriage.Return=True
    Strng="? = help "
    Call IO.O
    Graphics.Off=True
    Strng="|-->-+----+----+----+| (try"+Str$(VarQ+1)+" of"+Str$(VarZ3)+")"
    Call IO.O
    Carriage.Return=True
    Strng="Password?["+Space$(20)+"]"
    Call IO.O
    Call Password.Mask(20)

    ' enter password
    Strng=""
    Line.Length=20
    Hidden=True
    Call IO.I
    Hidden=False
    Graphics.Off=False

    ' process password
    Out2=Ltrim$(Out2)
    Out2=Rtrim$(Out2)
    Out2=Ucase$(Out2)
    If Out2="?" Then
       Do While Security.Guard
          Call Create.Password
          If Out2=Nul Then
             Exit Do
          Endif
          If Len(Out2) Then
             Out3=Out2
             Graphics.Off=False
             Strng="Use this password(y/n)? "
             No.Input.Out="y"
             Call IO.I
             If Yes Then
                Out2=Out3
                Exit Do
             Endif
             If No Then
                Out2=Nul
                VarQ=VarQ+1
                If VarQ>=VarZ2 Then
                   Exit Do
                Endif
             Endif
          Endif
       Loop
    Endif
    If Out2=Nul Then
       VarQ=VarQ+1
       If VarQ>=VarZ3 Then
          Exit Do
       Endif
    Endif
    If Len(Out2) Then
       PassWord.Temp=Out2
       If Left$(CodeName.Temp,5)="GUEST" Then
          If Out2<>"GUEST" Then
             Strng="Illegal guest password!"
             Call IO.O
             VarQ=VarQ+1
             If VarQ>=VarZ2 Then
                Exit Do
             Endif
          Else
             Exit Do
          Endif
       Else
          If Len(PassWord.Temp)<3 Then
             VarQ=VarQ+1
             If VarQ>=VarZ3 Then
                Exit Do
             Endif
             Strng="Password must be at least three characters."
             Call IO.O
             Strng="Use at least 8 characters containing alphanumerics for best security."
             Call IO.O
          Else
             Exit Do
          Endif
       Endif
    Endif
 Loop
ErrorRsm6:
 Exit Sub
ErrorTrp6:
 Security.Guard=False
 Resume ErrorRsm6
End Sub

' make mask area for teletypes
Sub PassWord.Mask(Var)
 On Local Error Goto ErrorTrp6z
 Call Back.Space2(Var+1)
 Carriage.Return=-1
 Strng=String$(Var,"*")
 Call IO.O
 Call Back.Space2(Var)
 Carriage.Return=-1
 Strng=String$(Var,"X")
 Call IO.O
 Call Back.Space2(Var)
 Carriage.Return=-1
 Strng=String$(Var,"|")
 Call IO.O
 Call Back.Space2(Var)
 Carriage.Return=-1
 Strng=String$(Var,"#")
 Call IO.O
 Call Back.Space2(Var)
 Carriage.Return=-1
 Strng=String$(Var,32)
 Call IO.O
 Call Back.Space2(Var)
 Exit Sub
ErrorRsm6z:
 Exit Sub
ErrorTrp6z:
 Security.Guard=False
 Resume ErrorRsm6z
End Sub

Sub Create.PassWord
 On Local Error Goto ErrorTrp6a
 Out2=Nul
 Filename=Data.Path1+"letter4.txt"
 If Dir$(Filename)=Nul Then
    Goto EndCreate
 Endif
 Filename=Data.Path1+"letter5.txt"
 If Dir$(Filename)=Nul Then
    Goto EndCreate
 Endif
 Var1=False
 Var2=False
 Filename=Data.Path1+"letter4.txt"
 Close #TempFile1
 Open Filename For Input As #TempFile1
 Do Until Eof(TempFile1)
    Line Input #TempFile1,Var$
    If Len(Var$)=4 Then
       Var1=Var1+1
    Endif
 Loop
 Filename=Data.Path1+"letter5.txt"
 Close #TempFile1
 Open Filename For Input As #TempFile1
 Do Until Eof(TempFile1)
    Line Input #TempFile1,Var$
    If Len(Var$)=5 Then
       Var2=Var2+1
    Endif
 Loop
 If Var1=False Or Var2=False Then
    Goto EndCreate
 Endif
 Var3=Int(Rnd*Var1+1)
 Var4=Int(Rnd*Var2+1)
 VarX=False
 VarY=False
 Filename=Data.Path1+"letter4.txt"
 Close #TempFile1
 Open Filename For Input As #TempFile1
 Do Until Eof(TempFile1)
    Line Input #TempFile1,Var$
    If Len(Var$)=4 Then
       VarX=VarX+1
    Endif
    If VarX=Var3 Then
       Var1$=Var$
       Exit Do
    Endif
 Loop
 Filename=Data.Path1+"letter5.txt"
 Close #TempFile1
 Open Filename For Input As #TempFile1
 Do Until Eof(TempFile1)
    Line Input #TempFile1,Var$
    If Len(Var$)=5 Then
       VarY=VarY+1
    Endif
    If VarY=Var4 Then
       Var2$=Var$
       Exit Do
    Endif
 Loop
 If Len(Var1$)>0 And Len(Var2$)>0 Then
    Temp1=Int(Rnd*9+1)
    Temp2=Int(Rnd*9+1)
    Var3$=Var1$+Mid$(Str$(Temp1),2)+Mid$(Str$(Temp2),2)+Var2$
    If Len(Var3$)>False Then
       Graphics.Off=False
       Strng="Create password(y/n)? "
       No.Input.Out="y"
       Call IO.I
       Out2=Nul
       If Yes Then
          Graphics.Off=True
          Strng="Your password is: "+Var3$
          Call IO.O
          Out2=Ucase$(Var3$)
       Endif
       Exit Sub
    Endif
 Endif
EndCreate:
 Strng="Passwords must be at least 3 characters, and"
 Call IO.O
 Strng="can contain alphanumeric characters only."
 Call IO.O
 Exit Sub
ErrorRsm6a:
 Exit Sub
ErrorTrp6a:
 Security.Guard=False
 Resume ErrorRsm6a
End Sub

Sub Get.PassWord2(VarQ)
 On Local Error Goto ErrorTrp6b
 Call Get.Login.Tries(VarZ2,VarZ3,VarZ4)
 Call Display.Guest
 VarQ=False
 Do While Security.Guard
    Strng=Nul
    Call IO.O
    Graphics.Off=True
    Strng=Space$(19)+"|-->-+----+----+----+| (try"+Str$(VarQ+1)+" of"+Str$(VarZ4)+")"
    Call IO.O
    Strng="Secondary Password?["+Space$(20)+"]"
    Carriage.Return=True
    Call IO.O
    Call Password.Mask(20)
    Strng=""
    Line.Length=20
    Hidden=True
    Call IO.I
    Hidden=False
    Graphics.Off=False
    Out2=Ltrim$(Out2)
    Out2=Rtrim$(Out2)
    Out2=Ucase$(Out2)
    PassWord.Temp2=Out2
    If Left$(CodeName.Temp,5)="GUEST" Then
       If Out2<>"GUEST" Then
          Strng="Illegal guest password!"
          Call IO.O
          VarQ=VarQ+1
          If VarQ>=VarZ4 Then
             Exit Do
          Endif
       Else
          Exit Do
       Endif
    Else
       If Len(PassWord.Temp2)<3 Then
          VarQ=VarQ+1
          If VarQ>=VarZ4 Then
             Exit Do
          Endif
          Strng="Password must be at least three characters."
          Call IO.O
          Strng="Use at least 8 characters containing alphanumerics for best security."
          Call IO.O
       Else
          Exit Do
       Endif
    Endif
 Loop
ErrorRsm6b:
 Exit Sub
ErrorTrp6b:
 Security.Guard=False
 Resume ErrorRsm6b
End Sub

Sub OpenSystem.Times(VarQ2)
 On Local Error Goto ErrorTrp6c
 VarQ2=True ' assume open system
 Var1$=Rtrim$(GuestRecord.OpenSystemTime1)
 Var2$=Rtrim$(GuestRecord.OpenSystemTime2)
 If Var1$<>Nul Then
    VarX$=Var1$
    Gosub Get.Range
    VarR1=True
 Endif
 If Var2$<>Nul Then
    VarX$=Var2$
    Gosub Get.Range
    VarR2=True
 Endif
 Strng3=Nul
 ' check either time range
 If VarR1 Or VarR2 Then
    If Len(Var1$) Then
       Strng3=Var1$
       If Len(Var2$) Then
          Strng3=Strng3+","+Var2$+","
       Endif
    Else
       Strng3=Var2$+","
    Endif
 Endif
 FileName=Data.Path1+"GUEST"+NodeX+".CFG"
 Close #TempFile1
 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$=Ltrim$(Rtrim$(Var$))
       If Var$<>Nul Then
          If Left$(Var$,1)<>";" Then
             Var=Instr(Var$,"=")
             If Var Then
                Var1$=Left$(Var$,Var-1)
                Var2$=Mid$(Var$,Var+1)
                Var1$=Ltrim$(Rtrim$(Var1$))
                Var2$=Ltrim$(Rtrim$(Var2$))
                Var1$=Ucase$(Var1$)
                Var3$=Var2$
                Var2$=Ucase$(Var2$)
                If Len(Var1$) Then
                   If Len(Var2$) Then
                      ' store open system time
                      If Left$(Var1$,11)="OPENSYSTEM#" Then
                         VarZ=Val(Mid$(Var1$,12))
                         If VarZ>=1 And VarZ<=127 Then
                            VarX$=Var2$
                            Gosub Get.Range
                            Strng3=Strng3+Var2$+","
                            VarR3=True
                         Endif
                      Endif
                   Endif
                Endif
             Endif
          Endif
       Endif
    Loop
 Endif
 If VarR1 Or VarR2 Or VarR3 Then
    VarQ2=False
 Endif
 Exit Sub
Get.Range:
 FromH=Val(Mid$(VarX$,1,2))
 FromM=Val(Mid$(VarX$,4,2))
 ToH=Val(Mid$(VarX$,7,2))
 ToM=Val(Mid$(VarX$,10,2))
 Var1!=Csng(FromH*3600!+FromM*60!)
 Var2!=Csng(ToH*3600!+ToM*60!)
 ' check within range
 Call Check.Time2(Var2,Var1!,Var2!)
 If Var2 Then
    Exit Sub
 Endif
 Return
ErrorRsm6c:
 Exit Sub
ErrorTrp6c:
 Security.Guard=False
 Resume ErrorRsm6c
End Sub

Sub Verify.Newuser(Var)
 On Local Error Goto ErrorTrp8
 Var=False
 If Config2(61)=False Then
    Var=True
    Exit Sub
 Endif
 Do While Security.Guard
    Strng=Config3(14)
    No.Input.Out="C"
    Call IO.I
    Var=False
    Select Case Ucase$(Out2)
    Case "C"
       If GuestRecord.DualPassword=-2 Then ' no password required
          Var=-1
          Exit Sub
       Endif
       Strng=Nul
       Call IO.O
       Graphics.Off=False
       Strng="Verify password: "
       Hidden=True
       Line.Length=20
       Call IO.I
       Hidden=False
       Out2=Ltrim$(Out2)
       Out2=Rtrim$(Out2)
       Out2=Ucase$(Out2)
       Strng=Rtrim$(PassWord.Temp)
       If Strng<>Out2 Then
	  Strng="Passwords don't match!"
	  Call IO.O
	  Exit Do
       Endif
       Strng=Config3(2)
       If Len(Strng)>False Then
	  Call IO.O
	  Call IO.O
       Endif
       Var=True
       Exit Do
    Case "H"
       Var=1
       Exit Do
    Case "R"
       Var=False
       Exit Do
    End Select
 Loop
ErrorRsm8:
 Exit Sub
ErrorTrp8:
 Security.Guard=False
 Resume ErrorRsm8
End Sub

Sub Verify.Newuser2(Var)
 On Local Error Goto ErrorTrp8a
 Var=False
 If Config2(61)=False Then
    Var=True
    Exit Sub
 Endif
 Do While Security.Guard
    Strng=Nul
    Call IO.O
    If GuestRecord.DualPassword=-2 Then ' no password required
       Var=-1
       Exit Sub
    Endif
    Graphics.Off=False
    Strng="Verify secondary password: "
    Hidden=True
    Line.Length=20
    Call IO.I
    Hidden=False
    Out2=Ltrim$(Out2)
    Out2=Rtrim$(Out2)
    Out2=Ucase$(Out2)
    Strng=Rtrim$(PassWord.Temp2)
    If Strng<>Out2 Then
       Strng="Passwords don't match!"
       Call IO.O
       Exit Do
    Endif
    Strng=Config3(2)
    If Len(Strng)>False Then
       Call IO.O
       Call IO.O
    Endif
    Var=True
    Exit Do
 Loop
ErrorRsm8a:
 Exit Sub
ErrorTrp8a:
 Security.Guard=False
 Resume ErrorRsm8a
End Sub

Sub Roll.Character
 On Local Error Goto ErrorTrp9
 UserRecord.Flags=False
 UserRecord.MaxCalls=False
 TempZ=False
 If Config2(51)=False Then
    If Config2(53)=False Then
       If Config2(54)=False Then
	  Strng="List help text during character logon(y/n)? "
	  No.Input.Out="N"
	  Call IO.I
	  If Yes Then
	     TempZ=True
	  Endif
       Endif
    Endif
 Endif
 If Config2(54) Then
    UserRecord.ClassType=Fighter
    UserRecord.Classname=Class.Name(1)
 Else
    If TempZ Then
       Call Logon.Help(5,9)
    Endif
    Call Modify.Class
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 If Config2(51) Then
    Call Roll.Stats
    If Security.Guard=False Then
       Exit Sub
    Endif
 Else
    If TempZ Then
       Call Logon.Help(10,18)
    Endif
    Call Modify.Stats
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 If Config2(54) Then
    UserRecord.Race=Human
 Else
    If TempZ Then
       Call Logon.Help(19,27)
    Endif
    Call Modify.Race
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 If Config2(52)=False Then
    Call Init.Race.Stats
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 If Config2(53) Then
    UserRecord.Proficiency=3
    For Temp3=1 To MaxWeapons
       UserRecord.Weapons(Temp3)=False
    Next
    UserRecord.Weapons(3)=10
 Else
    If TempZ Then
       Call Logon.Help(28,33)
    Endif
    Call Modify.Proficiency
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 If Config2(52)=False Then
    Call Init.Proficiency.Stats
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 Call Init.Stats
 If Security.Guard=False Then
    Exit Sub
 Endif
 If Config2(53) Then
    UserRecord.Align1=False
    UserRecord.Align2=False
 Else
    If TempZ Then
       Call Logon.Help(34,38)
    Endif
    Call Modify.Alignment
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 Call Init.Encumbrance
 If Security.Guard=False Then
    Exit Sub
 Endif
 If GuestLogin Then
    Call Init.Guest
    If Security.Guard=False Then
       Exit Sub
    Endif
 Endif
 Call Display.Init.Stats
ErrorRsm9:
 Exit Sub
ErrorTrp9:
 Security.Guard=False
 Resume ErrorRsm9
End Sub

Sub Logon.Help(Var1,Var2)
 On Local Error Goto ErrorTrp10
 Close #HelpFile3
 Open Logon.Help.FileName For Random Shared As #HelpFile3 Len=HelpRecLen3
 If Lof(HelpFile3)/HelpRecLen3=False Then
    Exit Sub
 Endif
 Graphics.Off=True
 Strng=Nul
 Call IO.O
 If Var1>=False And Var2<=Lof(HelpFile3)/HelpRecLen3 Then
    For Var3=Var1 To Var2
       Call Read.HelpFile(HelpFile3,Var3)
       Strng=Space$(3)+Rtrim$(HelpRecord3.Text)
       Call IO.O
    Next
    Call IO.O
    Call More.Prompt
 Endif
 Graphics.Off=False
ErrorRsm10:
 Exit Sub
ErrorTrp10:
 Security.Guard=False
 Resume ErrorRsm10
End Sub

Sub Modify.Alignment
 On Local Error Goto ErrorTrp11
 If GuestLogin Then
    Temp2=GuestRecord.GuestAlign1
    Temp5=GuestRecord.GuestAlign2
    If Temp2>False And Temp2<=MaxAlignment Then
       If Temp5>False And Temp5<=MaxAlignment Then
          UserRecord.Align1=Temp2-2
          UserRecord.Align2=Temp5-2
          Exit Sub
       Endif
    Endif
 Endif
 Do While Security.Guard
    Graphics.Off=False
    Strng="Player Alignment:"
    Call IO.O
    Strng="Press "+Enter$+" for default."
    Call IO.O
    Graphics.Off=True
    For Temp5=1 To MaxAlignment
       Strng=Mid$(Str$(Temp5),2)+">"+Rtrim$(Alignment.Name1(Temp5))
       Call IO.O
    Next
    Graphics.Off=False
    Strng="Option? "
    No.Input.Out="2"
    Call IO.I
    Temp2=Int(Val(Out2))
    If Temp2>=1 And Temp2<=3 Then
       Exit Do
    Endif
 Loop
 UserRecord.Align1=Temp2-2
 Do While Security.Guard
    Graphics.Off=False
    Strng="Player Alignment:"
    Call IO.O
    Strng="Press "+Enter$+" for default."
    Call IO.O
    Graphics.Off=True
    For Temp5=1 To MaxAlignment
       Strng=Mid$(Str$(Temp5),2)+">"+Rtrim$(Alignment.Name2(Temp5))
       Call IO.O
    Next
    Graphics.Off=False
    Strng="Option? "
    No.Input.Out="2"
    Call IO.I
    Temp2=Int(Val(Out2))
    If Temp2>=1 And Temp2<=3 Then
       Exit Do
    Endif
 Loop
 UserRecord.Align2=Temp2-2
ErrorRsm11:
 Exit Sub
ErrorTrp11:
 Security.Guard=False
 Resume ErrorRsm11
End Sub

Sub Modify.Class
 On Local Error Goto ErrorTrp12
 If GuestLogin Then
    Temp5=GuestRecord.GuestClass
    If Temp5>False And Temp5<=MaxClasses Then
       UserRecord.ClassType=Temp5
       UserRecord.ClassName=Class.Name(Temp5)
    Else
       UserRecord.ClassType=1
       UserRecord.ClassName=Class.Name(1)
    Endif
    Exit Sub
 Endif
 Do While Security.Guard
    Graphics.Off=False
    Strng="Select your character class:"
    Call IO.O
    Strng="Press "+Enter$+" for default."
    Call IO.O
    Temp2=False
    If Config2(7) Or GuestRecord.AllowDMLogon Then
       If Disable.DM=False Then
          If GuestLogin=False Then
             Temp2=True
          Endif
       Endif
    Endif
    Temp3=False
    If Local.Mode Then
       If Disable.DM=False Then
          If GuestLogin=False Then
             If GuestRecord.AllowLocalSysopLogon Then
                Temp3=True
             Endif
          Endif
       Endif
    Endif
    Call IsPasswrd(Var)
    If Var Then
       Temp2=False
       Temp3=False
    Endif
    Graphics.Off=True
    For Temp5=1 To MaxClasses
       Strng=Mid$(Str$(Temp5),2)
       Strng=Strng+">"+Rtrim$(Class.Name(Temp5))
       Call IO.O
    Next
    If Temp2 Then
       Strng="9>"+Rtrim$(Class.Name(9))
       Call IO.O
       Strng="#>"+Rtrim$(Class.Name(10))
       Call IO.O
    Endif
    If Temp3 Then
       Strng="!>Sysop"
       Call IO.O
    Endif
    Graphics.Off=False
    Strng="Option? "
    No.Input.Out="1"
    Call IO.I
    Temp5=Int(Val(Out2))
    If Temp5>=1 And Temp5<=MaxClasses Then
       Exit Do
    Endif
    If Temp2 Then
       If Temp5=9 Then
          Exit Do
       Endif
       If Out2="#" Then
          Temp5=10
          Exit Do
       Endif
    Endif
    If Temp3 Then
       If Out2="!" Then
          Temp5=11
          Exit Do
       Endif
    Endif
 Loop
 If Temp5=11 Then
    Temp5=10
    UserRecord.Flags=UserRecord.Flags Or Special.Char4 ' sysop
 Endif
 If Local.Mode Then
    If GuestRecord.AllowLocalMaxLogon Then
       Do While Lost.Carrier=False
          Strng="Max calls per day(-1=unlimited,0=default,1 to 32767)? "
          Call IO.I
          Temp6=Val(Out2)
          Select Case Temp6
          Case -1,0,1 to MaxInt
             UserRecord.MaxCalls=Temp6
             Exit Do
          End Select
       Loop
    Endif
 Endif
 UserRecord.ClassType=Temp5
 UserRecord.ClassName=Class.Name(Temp5)
ErrorRsm12:
 Exit Sub
ErrorTrp12:
 Security.Guard=False
 Resume ErrorRsm12
End Sub

Sub Modify.Stats
 On Local Error Goto ErrorTrp13
 If GuestLogin Then
    Call Modify.Guest.Stats(Var)
    If Var Then
       Exit Sub
    Endif
 Endif
 Strng="Auto-roll stats(y/n)? "
 Call IO.I
 If Yes Then
    Call Roll.Stats
    Exit Sub
 Endif
 Do While Security.Guard
    Do While Security.Guard
       Graphics.Off=False
       Strng="Enter character statistics, range from"
       Strng=Strng+Str$(Config2(8))+" to"+Str$(Config2(9))+"."
       Call IO.O
       Strng="Average less than or equal to"+Str$(Config1(4))+"."
       Call IO.O
       Strng="Press "+Enter$+" for default."
       Call IO.O
       Temp!=SFalse
       For Temp2=1 To MaxStats
	  Do While Security.Guard
	     Graphics.Off=True
	     Strng=Rtrim$(Stat(Temp2))+">"
	     No.Input.Out=Mid$(Str$(Config1(4)),2)
	     Call IO.I
	     Temp=Int(Val(Out2))
	     If Temp<Config2(8) Or Temp>Config2(9) Then
		Graphics.Off=False
		Strng="The average statistic must range from"+_
		Str$(Config2(8))+" to"+Str$(Config2(9))+"."
		Call IO.O
	     Else
		Temp!=Temp!+Temp
		UserRecord.Stats(Temp2)=Temp
		Exit Do
	     Endif
	  Loop
       Next
       Temp!=Temp!/7!
       TempX$=Str$(Temp!)
       TempX=Instr(TempX$,".")
       If TempX=False Then
	  Out2=TempX$
       Else
	  Out2=Left$(TempX$,TempX-1)+"."+Mid$(TempX$,TempX+1,1)
       Endif
       Graphics.Off=False
       If Temp!<=Config1(4) Then
	  Exit Do
       Endif
       Strng="Average"+Out2+" to high. Try again."
       Call IO.O
    Loop
    Strng="Your average is"+Out2+". Change anything(y/n)? "
    No.Input.Out="N"
    Call IO.I
    If No Then
       Exit Do
    Endif
 Loop
ErrorRsm13:
 Exit Sub
ErrorTrp13:
 Security.Guard=False
 Resume ErrorRsm13
End Sub

Sub Roll.Stats
 On Local Error Goto ErrorTrp14
 Redim Temp.Array1(1 To 7) As Integer
 If GuestLogin Then
    Call Modify.Guest.Stats(Var)
    If Var Then
       Exit Sub
    Endif
 Endif
 Do While Security.Guard
    Strng="Rolling random character stats."
    Call IO.O
    Do While Security.Guard
       Temp!=SFalse
       For Temp1=1 To MaxStats
	  Temp2=Int(Rnd*(Config2(9)-Config2(8)+1)+Config2(8))
	  Temp!=Temp!+Temp2
	  Temp.Array1(Temp1)=Temp2
       Next
       Temp!=Temp!/7!
       If Temp!<=Config1(4) Then
	  Exit Do
       Endif
    Loop
    Graphics.Off=True
    Strng=Nul
    For Temp1=1 To MaxStats
       Strng=Strng+Left$(Stat(Temp1),3)+">"
       Strng=Strng+Str$(Temp.Array1(Temp1))+" "
    Next
    Call IO.O
    Strng="Keep these stats(y/n)? "
    No.Input.Out="Y"
    Call IO.I
    If Yes Then
       Exit Do
    Endif
 Loop
 For Temp1=1 To MaxStats
    UserRecord.Stats(Temp1)=Temp.Array1(Temp1)
 Next
 Erase Temp.Array1
ErrorRsm14:
 Exit Sub
ErrorTrp14:
 Security.Guard=False
 Resume ErrorRsm14
End Sub

Sub Modify.Guest.Stats(Var)
 On Local Error Goto ErrorTrp14a
 Var=False
 Var$=Rtrim$(GuestRecord.GuestStats)
 Var3=False
 Do
    If Var$=Nul Then
       Exit Do
    Endif
    Var1=Instr(Var$,",")
    Var2=False
    If Var1 Then
       Var2=Int(Val(Left$(Var$,Var1-1)))
       Var$=Mid$(Var$,Var1+1)
    Else
       Var2=Int(Val(Var$))
       Var$=Nul
    Endif
    If Var2>False And Var2<=100 Then
       Var3=Var3+1
       If Var3<=MaxStats Then
          UserRecord.Stats(Var3)=Var2
       Else
          If Var3=MaxStats+1 Then
             UserRecord.Beauty=Var2
          Else
             If Var3=MaxStats+2 Then
                UserRecord.Glamour=Var2
             Endif
          Endif
       Endif
    Else
       Exit Do
    Endif
 Loop
 If Var3=MaxStats+2 Then
    Var=True
    Exit Sub
 Endif
ErrorRsm14a:
 Exit Sub
ErrorTrp14a:
 Security.Guard=False
 Resume ErrorRsm14a
End Sub

Sub Modify.Race
 On Local Error Goto ErrorTrp15
 If GuestLogin Then
    Temp2=GuestRecord.GuestRace
    If Temp2>False And Temp2<=MaxRaces Then
       UserRecord.Race=Temp2
       Exit Sub
    Endif
 Endif
 Do While Security.Guard
    Graphics.Off=False
    Strng="Select your character race:"
    Call IO.O
    Strng="Press "+Enter$+" for default."
    Call IO.O
    Graphics.Off=True
    For Temp5=1 To MaxRaces
       Strng=Mid$(Str$(Temp5),2)+">"+Rtrim$(Race(Temp5))
       Call IO.O
    Next
    Graphics.Off=False
    Strng="Option? "
    No.Input.Out="1"
    Call IO.I
    Temp2=Int(Val(Out2))
    If Temp2>=1 And Temp2<=MaxRaces Then
       UserRecord.Race=Temp2
       Exit Do
    Endif
 Loop
ErrorRsm15:
 Exit Sub
ErrorTrp15:
 Security.Guard=False
 Resume ErrorRsm15
End Sub

Sub Modify.Proficiency
 On Local Error Goto ErrorTrp16
 If GuestLogin Then
    Temp2=GuestRecord.GuestProf
    If Temp2>False And Temp2<=MaxWeapons Then
       UserRecord.Proficiency=Temp2
       For Temp3=1 To MaxWeapons
          UserRecord.Weapons(Temp3)=False
       Next
       UserRecord.Weapons(Temp2)=10
       Exit Sub
    Endif
 Endif
 Do While Security.Guard
    Graphics.Off=False
    Strng="Weapon Proficiency:"
    Call IO.O
    Strng="Clerics may only use blunt or pole type weapons."
    Call IO.O
    Strng="Press "+Enter$+" for default."
    Call IO.O
    Graphics.Off=True
    For Temp5=1 To MaxWeapons
       Strng=Mid$(Str$(Temp5),2)+">"+Rtrim$(Weapon.Type.Name(Temp5))
       Call IO.O
    Next
    Graphics.Off=False
    Strng="Option? "
    If UserRecord.ClassType=Cleric Then
       No.Input.Out="1"
    Else
       No.Input.Out="3"
    Endif
    Call IO.I
    Temp2=Int(Val(Out2))
    If UserRecord.ClassType=Cleric Then
       If Temp2=1 Or Temp2=2 Then
	  Exit Do
       Endif
    Else
       If Temp2>=1 And Temp2<=4 Then
	  Exit Do
       Endif
    Endif
 Loop
 UserRecord.Proficiency=Temp2
 For Temp3=1 To MaxWeapons
    UserRecord.Weapons(Temp3)=False
 Next
 UserRecord.Weapons(Temp2)=10
ErrorRsm16:
 Exit Sub
ErrorTrp16:
 Security.Guard=False
 Resume ErrorRsm16
End Sub

Sub Init.Proficiency.Stats
 On Local Error Goto ErrorTrp17
 Graphics.Off=False
 If UserRecord.Race=Gnome Then
    UserRecord.Weapons(UserRecord.Proficiency)=15
    Strng="Gnomes weapon proficiency is raised to 15%"
    Call IO.O
 Endif
 If UserRecord.Race=HalfElf Then
    UserRecord.Weapons(4)=UserRecord.Weapons(4)+5
    Strng="Half-elves thrusting weapon proficiency is raised by 5%"
    Call IO.O
 Endif
 If UserRecord.Race=HalfOrc Then
    UserRecord.Weapons(3)=UserRecord.Weapons(3)+5
    Strng="Half-orcs sharp weapon proficiency is raised by 5%"
    Call IO.O
 Endif
 If UserRecord.ClassType=Lady Then
    UserRecord.Weapons(3)=UserRecord.Weapons(3)-5
    If UserRecord.Weapons(3)<False Then
       UserRecord.Weapons(3)=False
    Endif
    Strng="Lady sharp weapon proficiency is lowered by 5%"
    Call IO.O
 Endif
ErrorRsm17:
 Exit Sub
ErrorTrp17:
 Security.Guard=False
 Resume ErrorRsm17
End Sub

Sub Init.Race.Stats
 On Local Error Goto ErrorTrp18
 Graphics.Off=False
 If UserRecord.Race=Human Then
    UserRecord.Stats(1)=UserRecord.Stats(1)+1
    Strng="Humans strength is raised one point."
    Call IO.O
 Endif
 If UserRecord.Race=Elf Then
    UserRecord.Stats(4)=UserRecord.Stats(4)+1
    Strng="Elves dexterity is raised by one point."
    Call IO.O
 Endif
 If UserRecord.Race=Dwarf Then
    UserRecord.Stats(2)=UserRecord.Stats(2)+1
    Strng="Dwarves intelligence is raised by one point."
    Call IO.O
 Endif
 If UserRecord.Race=Halfling Then
    UserRecord.Stats(3)=UserRecord.Stats(3)+1
    Strng="Halflings wisdom is raised by one point."
    Call IO.O
 Endif
 If UserRecord.Race=Ogre Then
    UserRecord.Stats(1)=UserRecord.Stats(1)+1
    UserRecord.Stats(4)=UserRecord.Stats(4)+1
    Strng="Ogres strength and dexterity are raised by one point."
    Call IO.O
 Endif
 If UserRecord.ClassType=Lady Then
    UserRecord.Stats(1)=UserRecord.Stats(1)-1
    If UserRecord.Stats(1)<1 Then
       UserRecord.Stats(1)=1
    Else
       Strng="Lady strength is lowered by one point."
       Call IO.O
    Endif
 Endif
ErrorRsm18:
 Exit Sub
ErrorTrp18:
 Security.Guard=False
 Resume ErrorRsm18
End Sub

Sub Init.Encumbrance
 On Local Error Goto ErrorTrp18a
 Graphics.Off=False
 Select Case UserRecord.ClassType
 Case Fighter, Thief, Cleric
    UserRecord.Encumbrance=15
 Case Paladin, Ranger, Druid
    UserRecord.Encumbrance=14
 Case MagicUser, Lady
    UserRecord.Encumbrance=13
 Case AsstDM, DM
    UserRecord.Encumbrance=True
 Case Else
    UserRecord.Encumbrance=10
 End Select
ErrorRsm18a:
 Exit Sub
ErrorTrp18a:
 Security.Guard=False
 Resume ErrorRsm18a
End Sub

Sub Init.Stats
 On Local Error Goto ErrorTrp19
 Gosub Get.Config3
 UserRecord.Room=Option4!
 UserRecord.SortInv=False
 UserRecord.Level=Option3
 If Config2(93)=False Then
    UserRecord.Experience=2^(Config2(92)+Option3-1)
 Else
    UserRecord.Experience=False
 Endif
 UserRecord.Gold=Option5#
 UserRecord.Bank=False
 UserRecord.Borrow=False
 UserRecord.Brief=False
 UserRecord.Hidden=Option2
 Hidden.Player=Option2
 UserRecord.FatigueMax=Training.Stats(UserRecord.ClassType,1)*Option3
 UserRecord.VitalityMax=Training.Stats(UserRecord.ClassType,2)*Option3
 UserRecord.MagicMax=Training.Stats(UserRecord.ClassType,3)*Option3
 UserRecord.PsionicMax=Training.Stats(UserRecord.ClassType,4)*Option3
 UserRecord.Fatigue=UserRecord.FatigueMax
 UserRecord.Vitality=UserRecord.VitalityMax
 UserRecord.Magic=UserRecord.MagicMax
 UserRecord.Psionic=UserRecord.PsionicMax
 UserRecord.FromHour=False
 UserRecord.FromMin=False
 UserRecord.ToHour=False
 UserRecord.ToMin=False
 UserRecord.Flags2=False
 UserRecord.WishsLeft=Option1
 UserRecord.Beauty=False
 UserRecord.Glamour=False
 UserRecord.TimeLimit=Config1(40)
 UserRecord.TimeUsed=SFalse
 UserRecord.SysNews="01-01-1980"
 Exit Sub

Get.Config3:
 Option1=3
 Option2=False
 Option3=1
 Option4!=Int(Val(Config3(24)))
 Option5#=Config2(32)
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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 "wishs.left"
                VarY=Int(Val(Var3$))
                Select Case VarY
                Case -1, 0 To MaxInt
                   Option1=VarY
                End Select
             Case "start.hidden"
                Select Case Lcase$(Var3$)
                Case "-1","on","true"
                   Option2=True
                End Select
             Case "newuser.level"
                VarY=Int(Val(Var3$))
                If VarY>0 And VarY<=10 Then
                   Option3=VarY
                Endif
             Case "newuser.room"
                VarY!=Int(Val(Var3$))
                If VarY!>0! And VarY!<=Lof(RoomFile)/RoomRecLen Then
                   Option4!=VarY!
                Endif
             Case "newuser.gold"
                VarY#=Int(Val(Var3$))
                If VarY#>0# Then
                   Option5#=VarY#
                Endif
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
ErrorRsm19:
 Exit Sub
ErrorTrp19:
 Security.Guard=False
 Resume ErrorRsm19
End Sub

Sub Display.Init.Stats
 On Local Error Goto ErrorTrp20
 Graphics.Off=False
 Strng="Your character statistics are:"
 Call IO.O
 Graphics.Off=True
 Strng="Level:"+Str$(UserRecord.Level)
 Strng=Strng+Space$(30-Len(Strng))
 Strng2=Alignment.Name1(UserRecord.Align1+2)
 Strng2=Rtrim$(Strng2)
 Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
 Strng=Strng+"Align1: "+Strng2
 Call IO.O
 If Instr(Str$(UserRecord.Gold),"D") Then
    Strng="Gold: "+Str$(UserRecord.Gold)
 Else
    Strng="Gold:  "+Form$(UserRecord.Gold)
 Endif
 Strng=Left$(Strng,30)
 Strng=Strng+Space$(30-Len(Strng))
 Strng2=Alignment.Name2(UserRecord.Align2+2)
 Strng2=Rtrim$(Strng2)
 Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
 Strng=Strng+"Align2: "+Strng2
 Call IO.O
 Strng="Room: "+Str$(UserRecord.Room)
 Strng=Strng+Space$(30-Len(Strng))
 Temp2=UserRecord.Proficiency
 Strng2=Weapon.Type.Name(Temp2)
 Strng2=Rtrim$(Strng2)
 Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
 Strng=Strng+"Prof:   "+Strng2
 Strng2=Mid$(Str$(UserRecord.Weapons(Temp2)),2)
 Strng=Strng+">"+Strng2+"%"
 Call IO.O
 If Instr(Str$(UserRecord.Experience),"D") Then
    Strng="Exp:  "+Str$(UserRecord.Experience)
 Else
    Strng="Exp:   "+Form$(UserRecord.Experience)
 Endif
 Strng=Left$(Strng,30)
 Strng=Strng+Space$(30-Len(Strng))
 Strng=Strng+Left$(Stat(1),3)+":   "+Str$(UserRecord.Stats(1))
 Call IO.O
 Strng="Fat:  "+Str$(UserRecord.Fatigue)
 Strng=Strng+Space$(30-Len(Strng))
 Strng=Strng+Left$(Stat(2),3)+":   "+Str$(UserRecord.Stats(2))
 Call IO.O
 Strng="Vit:  "+Str$(UserRecord.Vitality)
 Strng=Strng+Space$(30-Len(Strng))
 Strng=Strng+Left$(Stat(3),3)+":   "+Str$(UserRecord.Stats(3))
 Call IO.O
 Strng="Mag:  "+Str$(UserRecord.Magic)
 Strng=Strng+Space$(30-Len(Strng))
 Strng=Strng+Left$(Stat(4),3)+":   "+Str$(UserRecord.Stats(4))
 Call IO.O
 Strng="Psi:  "+Str$(UserRecord.Psionic)
 Strng=Strng+Space$(30-Len(Strng))
 Strng=Strng+Left$(Stat(5),3)+":   "+Str$(UserRecord.Stats(5))
 Call IO.O
 Strng="Race:  "+Race(UserRecord.Race)
 Strng=Strng+Space$(30-Len(Strng))
 Strng=Strng+Left$(Stat(6),3)+":   "+Str$(UserRecord.Stats(6))
 Call IO.O
 Strng2=UserRecord.ClassName
 Mid$(Strng2,1,1)=Ucase$(Mid$(Strng2,1,1))
 Strng="Class: "+Strng2
 Strng=Strng+Space$(30-Len(Strng))
 Strng=Strng+Left$(Stat(7),3)+":   "+Str$(UserRecord.Stats(7))
 Call IO.O
 UserRecord.Beauty=Int(Rnd*(Config2(9)-Config2(8)+1)+Config2(8))
 UserRecord.Glamour=Int(Rnd*(Config2(9)-Config2(8)+1)+Config2(8))
 If UserRecord.ClassType=Lady Then
    Graphics.Off=False
    Strng="Lady class:"
    Call IO.O
    Graphics.Off=True
    Strng="Beauty:"+Str$(UserRecord.Beauty)
    Strng=Strng+Space$(30-Len(Strng))
    Strng=Strng+"Glamour:"+Str$(UserRecord.Glamour)
    Call IO.O
 Endif
 Call More.Prompt
ErrorRsm20:
 Exit Sub
ErrorTrp20:
 Security.Guard=False
 Resume ErrorRsm20
End Sub

Sub Update.Login
 On Local Error Goto ErrorTrp21
 If Security.Guard=False Then
    Exit Sub
 Endif
 If Lost.Carrier Then
    Exit Sub
 Endif
 Auto.Pickup=False
 Strng=UserRecord.DateOn
 If Strng<>DateS$ Then
    UserRecord.NumCalls=False
    UserRecord.TimeUsed=SFalse
 Endif
 ' reset calls made
 TempX=False
 Select Case UserRecord.MaxCalls
 Case 0
    If UserRecord.NumCalls+1>Config2(1) Then
       TempX=True
    Endif
 Case Is>0
    If UserRecord.NumCalls+1>UserRecord.MaxCalls Then
       TempX=True
    Endif
 End Select
 If TempX Then
    Call Write.Record(UserFile,User.Index)
    Call playwav(5)
    Call Hang.Up(5)
    Exit Sub
 Endif
 UserRecord.NumCalls=UserRecord.NumCalls+1
 ' reset invisible status
 Invisible=False
 If UserRecord.ClassType<AsstDM Then
    If Config2(2)=False Then
       UserRecord.Invisible=False
    Else
       If UserRecord.Invisible Then
          Invisible=UserRecord.Level+5
       Endif
    Endif
 Endif
 ' reset time variables
 Two.Minutes.Left=False
 If Time.Override>False Then
    Time.Left=Csng(Time.Override*60!)
 Else
    Select Case UserRecord.TimeLimit
    Case SFalse
       Select Case UserRecord.ClassType
       Case Is>=AsstDM
          Time.Left=Config1(3)*60!
       Case Else
          Select Case UserRecord.Level
          Case Is<=1
             Time.Left=Config1(1)*60!
          Case Else
             Time.Left=Config1(2)*60!
          End Select
       End Select
    Case Is>SFalse
       Var!=Csng(UserRecord.TimeLimit)*60!
       Var!=Var!-UserRecord.TimeUsed
       If Var!<=SFalse Then
          Two.Minutes.Left=True
          Call playwav(5)
          Call Hang.Up(2)
       Endif
       Time.Left=Var!
    End Select
 Endif
 If GuestLogin Then
    If GuestRecord.GuestTimeLeft>False Then
       Time.Left=Csng(GuestRecord.GuestTimeLeft*60!)
    Endif
 Endif
 ' reset remaining stats
 Call Clear.Container.Swap
 Redim History(1 To 10) As String*79
 Call Command.History(-2)
ErrorRsm21:
 Exit Sub
ErrorTrp21:
 Security.Guard=False
 Resume ErrorRsm21
End Sub

' determine login time restrictions
Sub Time.Restriction
 On Local Error Goto Error.Trap7
 Gosub Get.Config2
 Var1=UserRecord.FromHour ' from
 Var1!=Csng(Var1)*3600! ' hours
 Var2=UserRecord.FromMin
 Var1!=Var1!+Csng(Var2)*60! ' minutes

 Var3=UserRecord.ToHour ' to
 Var2!=Csng(Var3)*3600! ' hours
 Var4=UserRecord.ToMin
 Var2!=Var2!+Csng(Var4)*60! ' minutes

 If Var1!>SFalse Or Var2!>SFalse Then
    ' display time restriction
    Strng=Nul
    Call IO.O
    Strng="Time restriction notice."
    Call IO.O
    Strng="Current time restriction is from "+_
    Right$("0"+Mid$(Str$(Var1),2),2)+":"+_
    Right$("0"+Mid$(Str$(Var2),2),2)+" to "+_
    Right$("0"+Mid$(Str$(Var3),2),2)+":"+_
    Right$("0"+Mid$(Str$(Var4),2),2)
    Call IO.O

    ' check within range
    Call Check.Time2(VarZ,Var1!,Var2!)
    If VarZ=False Then ' outside range
       Call Write.Record(UserFile,User.Index)
       Call playwav(5)
       Call Hang.Up(6)
       Exit Sub
    Endif
 Endif

 ' check time restrictions
 Var2=True
 If UserRecord.Flags And Special.Char1 Then
    Var1$=Rtrim$(GuestRecord.TownMayorTime)
    If Len(Var1$) Then
       VarX$="Town Mayor"
       Gosub Check.Time
       Goto End.Check
    Endif
 Endif
 If UserRecord.Flags And Special.Char2 Then
    Var1$=Rtrim$(GuestRecord.GovernorTime)
    If Len(Var1$) Then
       VarX$="Governor"
       Gosub Check.Time
       Goto End.Check
    Endif
 Endif
 If UserRecord.Flags And Special.Char3 Then
    Var1$=Rtrim$(GuestRecord.GuildMasterTime)
    If Len(Var1$) Then
       VarX$="GuildMaster"
       Gosub Check.Time
       Goto End.Check
    Endif
 Endif
 If UserRecord.Flags And Special.Char4 Then
    Var1$=Rtrim$(GuestRecord.SysopTime)
    If Len(Var1$) Then
       VarX$="Sysop"
       Gosub Check.Time
       Goto End.Check
    Endif
 Endif
 If UserRecord.ClassType=DM Then
    Var1$=Rtrim$(GuestRecord.DMTime)
    If Len(Var1$) Then
       VarX$="DM"
       Gosub Check.Time
       Goto End.Check
    Endif
 Endif
 If UserRecord.ClassType=AsstDM Then
    Var1$=Rtrim$(GuestRecord.AsstDMTime)
    If Len(Var1$) Then
       VarX$="Asst. DM"
       Gosub Check.Time
       Goto End.Check
    Endif
 Endif
 ' check special time restrictions
 For VarZ=1 To Special.Names
    Var1$=Rtrim$(SpecialUserTime(VarZ))
    If Len(Var1$) Then
       VarX$=Rtrim$(SpecialUserName(VarZ))
       If Ucase$(Rtrim$(UserRecord.CodeName))=VarX$ Then
          Gosub Check.Time
          Exit For
       Endif
    Endif
 Next
' check user is restricted
End.Check:
 If Var2 Then ' default not restricted
    Goto Display.Notice
 Endif
 Strng=Nul
 Call IO.O
 Strng="Time restriction notice."
 Call IO.O
 VarX$=Lcase$(VarX$)
 If Len(VarX$) Then
    Mid$(VarX$,1,1)=Ucase$(Mid$(VarX$,1,1))
 Endif
 Strng=VarX$+" time restriction is "+Var1$
 Call IO.O
 Call Write.Record(UserFile,User.Index)
 Call playwav(5)
 Call Hang.Up(18)
 Exit Sub

' display time notices
Display.Notice:
 If UserRecord.Flags And Special.Char4 Then ' sysop
    If Option1 Then
       Continuous=False
       Var2=False
       VarQ2=False
       TempC=False
       Strng="Display restricted users(y/n)? "
       No.Input.Out="N"
       Line.Length=1
       Call IO.I
       If Yes Then
          Var1$=Rtrim$(GuestRecord.TownMayorTime)
          VarX$="Town Mayor"
          Gosub Display.Time
          Var1$=Rtrim$(GuestRecord.GovernorTime)
          VarX$="Governor"
          Gosub Display.Time
          Var1$=Rtrim$(GuestRecord.GuildMasterTime)
          VarX$="GuildMaster"
          Gosub Display.Time
          Var1$=Rtrim$(GuestRecord.SysopTime)
          VarX$="Sysop"
          Gosub Display.Time
          Var1$=Rtrim$(GuestRecord.DMTime)
          VarX$="DM"
          Gosub Display.Time
          Var1$=Rtrim$(GuestRecord.AsstDMTime)
          VarX$="Asst. DM"
          Gosub Display.Time
          If VarQ2=False Then
             Strng="No restrictions found."
             Call IO.O
          Endif
          Call More.Prompt
       Endif
    Endif
    If Option2 Then
       If Special.Names>False Then
          Continuous=False
          Var2=False
          TempC=False
          Strng="Display special users(y/n)? "
          No.Input.Out="N"
          Line.Length=1
          Call IO.I
          If Yes Then
             For VarZ=1 To Special.Names
                Var1$=Rtrim$(SpecialUserTime(VarZ))
                VarX$=Lcase$(Rtrim$(SpecialUserName(VarZ)))
                If Len(VarX$) Then
                   Mid$(VarX$,1,1)=Ucase$(Mid$(VarX$,1,1))
                Endif
                Gosub Display.Time
             Next
          Endif
          If TempC Then
             Call More.Prompt
          Endif
       Endif
    Endif
 Endif
 Exit Sub

' check time range
Check.Time:
 FromH=Val(Mid$(Var1$,1,2))
 FromM=Val(Mid$(Var1$,4,2))
 ToH=Val(Mid$(Var1$,7,2))
 ToM=Val(Mid$(Var1$,10,2))
 Var1!=Csng(FromH*3600!+FromM*60!)
 Var2!=Csng(ToH*3600!+ToM*60!)
 Call Check.Time2(Var2,Var1!,Var2!)
 Return

' display restriction notice
Display.Time:
 If Len(Var1$) Then
    VarQ2=True
    If Var2=False Then
       TempC=1
       Var2=True
       Graphics.Off=False
       Strng="Time restriction warning:"
       Call IO.O
    Endif
    Graphics.Off=True
    VarX$=Lcase$(VarX$)
    If Len(VarX$) Then
       Mid$(VarX$,1,1)=Ucase$(Mid$(VarX$,1,1))
    Endif
    Strng=VarX$+" time restriction is "+Var1$
    Call IO.O
    If Continuous=False Then
       TempC=TempC+1
       If TempC>=User.Pagelength-2 Then
          TempC=False
          Call More.Prompt
          If No Or Quit Then
             Exit Sub
          Endif
       Endif
    Endif
 Endif
 Return
Get.Config2:
 Option1=0
 Option2=0
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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 "allow.display.users"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   Option1=-1
                End Select
             Case "allow.display.special.users"
                Select Case Lcase$(Var3$)
                Case "-1", "true", "on"
                   Option2=-1
                End Select
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
Error.Resume7:
 Exit Sub
Error.Trap7:
 Resume Error.Resume7
End Sub

' check current time is within range
Sub Check.Time2(Var2,Var1!,Var2!)
 On Local Error Goto Error.Trap7x
 Var2=False ' default to outside range
 If Var1!>SFalse Or Var2!>SFalse Then
    If Var1!=Var2! Then ' 01:00-01:00
       If Timeit!=Var1! Then
          Var2=True
       Endif
    Else
       If Var1!<Var2! Then ' 02:00-04:00
          If Timeit!>=Var1! And Timeit!<=Var2! Then
             Var2=True
          Endif
       Else ' 22:00-02:00
          If Timeit!>=Var1! Or Timeit!<=Var2! Then
             Var2=True
          Endif
       Endif
    Endif
 Endif
Error.Resume7x:
 Exit Sub
Error.Trap7x:
 Resume Error.Resume7x
End Sub

Sub Init.Newuser
 On Local Error Goto ErrorTrp22
 Strng=PassWord.Temp
 Call Cryptograph(Strng)
 UserRecord.PassWord=Strng
 Strng=PassWord.Temp
 Call Crypto(Strng)
 UserRecord.PassWord3=Strng
 If GuestRecord.DualPassword=-1 Then
    Strng=PassWord.Temp2
    Call Cryptograph(Strng)
    UserRecord.PassWord2=Strng
 Else
    UserRecord.PassWord2=Nul
 Endif
 UserRecord.ClassName=Deleted$
 UserRecord.ClassType=False
 UserRecord.CodeName=CodeName.Temp
 UserRecord.DateOn=DateS$
 UserRecord.MaxCalls=False
 UserRecord.NumCalls=False
 UserRecord.FromHour=False
 UserRecord.FromMin=False
 UserRecord.ToHour=False
 UserRecord.ToMin=False
 For Var=1 To MaxItems
    UserRecord.Weapon(Var).Index=SFalse
    UserRecord.Weapon(Var).Charges=False
    UserRecord.Weapon(Var).Plus=False
 Next
 UserRecord.Prefix1=Nul
 UserRecord.Prefix2=Nul
 UserRecord.Prefix3=Nul
 For Var=1 To MaxShortcutKeys
    UserRecord.ShortcutKey1(Var)=Nul
    UserRecord.ShortcutKey2(Var)=Nul
 Next
 For Var=1 To 10
    UserRecord.FunctionKeys(Var)=Nul
 Next
 UserRecord.StatusVar=0
 UserRecord.TimesLogon=0#
 UserRecord.TimesDied=0#
 UserRecord.NodeList2=0!
 UserRecord.EditList=0!
 ' create/store node list
 UserRecord.NodeList=String$(127,"1")
 Var$=Rtrim$(GuestRecord.NodeBitMask)
 If Len(Var$)=127 Then
    UserRecord.NodeList=Var$
 Endif
 UserRecord.ActionLineString=Nul
 UserRecord.Buffer22=0!
 UserRecord.Buffer23=0!
 UserRecord.Buffer24=0#
 UserRecord.Buffer25=0#
ErrorRsm22:
 Exit Sub
ErrorTrp22:
 Security.Guard=False
 Resume ErrorRsm22
End Sub

Sub Init.Inventory
 On Local Error Goto ErrorTrp22a
 Redim Temp.ArrayX(1 To 9) As Single
 Gosub Get.Config4
 VarQ=False
 If Option1!>0! Then
    For Var1!=1! To Option1!
       Gosub Add.Init.Inv
    Next
 Endif
 For Var1=1 To 9
    Var1!=Temp.ArrayX(Var1)
    Gosub Add.Init.Inv
 Next
 Call Write.Record(UserFile,User.Index)
 If UserRecord.Gold>DFalse Then
    VarQ=True
    If Instr(Str$(UserRecord.Gold),"D") Then
       Strng="You have"+Str$(UserRecord.Gold)+" gold!"
    Else
       Strng="You have "+Form$(UserRecord.Gold)+" gold!"
    Endif
    Call IO.O
 Endif
 VarX=UserRecord.WishsLeft
 Select Case VarX
 Case 0
    Eat$=Nul
 Case -1
    Strng="You are granted unlimited wishes!!"
    Call IO.O
 Case 1
    Strng="You are granted one wish!"
    Call IO.O
 Case 2 To 10
    Strng="You are granted "+Numeral(VarX)+" wishes!"
    Call IO.O
 Case Else
    If VarX>1 Then
       Strng="You are granted "+Form$(Cdbl(VarX))+" wishes!"
       Call IO.O
    Endif
 End Select
 Call More.Prompt
 Erase Temp.ArrayX
 Exit Sub
Add.Init.Inv:
 If Var1!>=1! And Var1!<=Lof(TreasureFile)/TreasureRecLen Then
    Call Read.Record(TreasureFile,Var1!)
    Out2=Lcase$(Rtrim$(TreasureRecord.TreasureName))
    If Len(Out2) Then
       VarQ=True
       Out3=Rtrim$(TreasureRecord.Prefix1)
       Call Capitalize(Out2)
       Strng="You are given "+Out3+Out2
       Call Convert.ANSI(True,VarQ,VarR)
       Carriage.Return=True
       Graphics.On=True
       Call IO.O
       Graphics.On=False
       Strng="!"
       Call IO.O
    Endif
    If TreasureRecord.Container Then
       Call Add.Container.To.User(Var1!)
       Return
    Endif
    Var2=TreasureRecord.Charges
    MessWorkRecord6.User=User.Index
    MessWorkRecord6.Room=SFalse
    MessWorkRecord6.Index=Var1!
    MessWorkRecord6.Charges=Var2
    MessWorkRecord6.Plus=False
    MessWorkRecord6.Prev=SFalse
    MessWorkRecord6.Next=SFalse
    VarX=TreasureRecord.Plus
    If TreasureRecord.Spell Then
       Call Read.Record(SpellFile,TreasureRecord.Spell)
       VarX=SpellRecord.Level
    Endif
    MessWorkRecord6.Plus=VarX
    VarX!=Lof(UserInvFile)/MessWorkRecLen6+1!
    Call Add.List.Node3(VarX!)
 Endif
 Return
Get.Config4:
 Option1!=2!
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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$=Lcase$(Ltrim$(Rtrim$(Left$(Var$,Var-1))))
             Var3$=Ltrim$(Rtrim$(Mid$(Var$,Var+1)))
             If Left$(Var2$,9)="inventory" Then
                VarY=Int(Val(Mid$(Var2$,10)))
                If VarY>=1 And VarY<=9 Then
                   VarY!=Int(Val(Var3$))
                   Temp.ArrayX(VarY)=VarY!
                Endif
             Else
                If Var2$="newuser.inventory" Then
                   VarY!=Int(Val(Var3$))
                   If VarY!>=0! And VarY!<=10! Then
                      Option1!=VarY!
                   Endif
                Endif
             Endif
          Endif
       Loop
    Endif
 Loop
 Return
ErrorRsm22a:
 Exit Sub
ErrorTrp22a:
 Security.Guard=False
 Resume ErrorRsm22a
End Sub

Sub Init.Question
 On Local Error Goto ErrorTrp22b
 If GuestLogin Then
    Out2="what is guest"
    Out2=Out2+Space$(80-Len(Out2))
    Call Crypto(Out2)
    UserRecord.Question=Out2
    Out2="guest is guest"
    Out2=Out2+Space$(20-Len(Out2))
    Call Crypto(Out2)
    UserRecord.Answer=Out2
    Exit Sub
 Endif
 Strng="Record password question & answer(y/n)? "
 No.Input.Out="N"
 Call IO.I
 If Yes Then
    Graphics.Off=False
    Strng="Enter question to ask you if you forget your password:"
    Call IO.O
    Graphics.Off=True
    Strng="?"
    Call IO.I
    Out2=Lcase$(Out2)
    Out2=Out2+Space$(80-Len(Out2))
    Call Crypto(Out2)
    UserRecord.Question=Out2
    Graphics.Off=False
    Strng="Enter answer to question:"
    Call IO.O
    Graphics.Off=True
    Strng="?"
    Call IO.I
    Out2=Lcase$(Out2)
    Out2=Out2+Space$(20-Len(Out2))
    Call Crypto(Out2)
    UserRecord.Answer=Out2
    Graphics.Off=False
    Strng="Your user file has now been updated.."
    Call IO.O
    Call More.Prompt
    Exit Sub
 Endif
ErrorRsm22b:
 Exit Sub
ErrorTrp22b:
 Security.Guard=False
 Resume ErrorRsm22b
End Sub

Sub Pre.Clock(Var$)
 On Local Error Goto ErrorTrp23
 Color 15, 0
 Var$=Fclock$+", Node "
 If Rtrim$(NodeX)=Nul Then
    Var$=Var$+"-"
 Else
    Var$=Var$+NodeX
 Endif
 Var$=Var$+", Port"
 If Local.Mode Then
    Var$=Var$+" -"
 Else
    If Port=-1 Then
       Var$=Var$+" -"
    Else
       Var$=Var$+Str$(Port)
    Endif
 Endif
 If Bypass.Login Then
    Var$=Var$+", (bypass)"
 Endif
 If BBS.Mode = -1 Then
    Var$=Var$+", (door)"
 Endif
 If BBS.Mode = -2 Then
    Var$=Var$+", (telnet)"
 Endif
 Var$=Var$+"."
ErrorRsm23:
 Exit Sub
ErrorTrp23:
 Security.Guard=False
 Resume ErrorRsm23
End Sub

Sub Start.Clock
 On Local Error Goto ErrorTrp23a
 Timeon=Timeit!
 Time.Left=30!
 Two.Minutes.Left=True
ErrorRsm23a:
 Exit Sub
ErrorTrp23a:
 Security.Guard=False
 Resume ErrorRsm23a
End Sub

Sub Prelogin
 On Local Error Goto ErrorTrp24
 Previous.Type1=False
 Previous.Type2=False
 Players.Killed=False
 Monsters.Killed=SFalse
 Permanent.Killed=SFalse
 Clock.On=Fclock2$
 Date.On=DateS$
 Timeon=Timeit!
 Time.On=Format$(Now,"hh:mm:ss")
 Time.Left=600!
 Two.Minutes.Left=False
 Avatar.Code=False
 Color.Code=False
 Chat.Annoy=Config2(68)
 Call Update.Mess(1)
 Security.Guard=True
 Remote.ANSI.Color=False
 Remote.Avatar.Color=False
 Graphics.Status=False
 Strng="[xon]"
 Call Convert.String
 Locate Max.Row-1,1,1 ' 11-15-2019
ErrorRsm24:
 Exit Sub
ErrorTrp24:
 Security.Guard=False
 Resume ErrorRsm24
End Sub

Sub Init.Spells
 On Local Error Goto ErrorTrp24a
 Var!=Lof(SpellFile)/SpellRecLen
 If Config1(38)>SFalse Then
    If Var!>Config1(38) Then
       Var!=Config1(38)
    Endif
 Endif
 LearnedSpells=String$(Var!,"0")
ErrorRsm24a:
 Exit Sub
ErrorTrp24a:
 Security.Guard=False
 Resume ErrorRsm24a
End Sub

Sub Alt.Login(Var)
 On Local Error Goto ErrorTrp25
 Var=False
 CodeName.Temp=Left$(Bypass.CodeName,30)
 Call Valid(CodeName.Temp,30)
 If CodeName.Temp=Nul Then
    Exit Sub
 Endif
 Strng=Rtrim$(CodeName.Temp)
 Call Valid.Name(Strng)
 If TempA=False Then
    Exit Sub
 Endif
 Strng=Rtrim$(CodeName.Temp)
 For User.Index=1! To Lof(UserFile)/UserRecLen
    Call Read.Record(UserFile,User.Index)
    Out2=UserRecord.CodeName
    Out2=Rtrim$(Out2)
    If Strng=Out2 Then
       Call Search.Mess(User.Index)
       If Temp!=SFalse Then
          Var=True
       Else
          Var=1
       Endif
       Exit Sub
    Endif
 Next
 User.Index=SFalse
ErrorRsm25:
 Exit Sub
ErrorTrp25:
 Security.Guard=False
 Resume ErrorRsm25
End Sub

Sub Login.User
 On Local Error Goto ErrorTrp26
 Gosub Get.Config5
 Brief.Messages=False
 Room=UserRecord.Room
 Room.Toggle=False
 Sorting=UserRecord.SortInv
 If Option2 Then
    Hidden.Player=True
    UserRecord.Hidden=True
 Else
    Hidden.Player=UserRecord.Hidden
 Endif
 Graphics.Status=UserRecord.StatusVar
 Statusline.Line=2
 Statusline.String=Nul
 If UserRecord.StatusLineString=String$(80,Chr$(0)) Then
    UserRecord.StatusLineString=Nul
 Endif
 If Rtrim$(UserRecord.StatusLineString)<>Nul Then
    Statusline.String=Rtrim$(UserRecord.StatusLineString)
 Endif   
 If UserRecord.Gold<>Int(UserRecord.Gold) Then
    UserRecord.Gold=Int(UserRecord.Gold)
 Endif
 If UserRecord.Race<=False Then
    UserRecord.Race=Human
 Endif
 If GuestLogin Then
    Call Init.Guest
 Endif
 If Option1 Then
    Allow.Break=True
    Break=False
    Graphics.Off=False
    Strng="Read system news(y/n)? "
    Line.Length=1
    No.Input.Out="Y"
    Call IO.I
    Allow.Break=False
    Break=False
    If Yes Then
       Call System.News
    Endif
 Endif
 Call Init.Mail(True)
 If Config2(38) And Option3 Then
    Allow.Break=True
    Break=False
    Graphics.Off=False
    Strng="Check for new mail(y/n)? "
    Line.Length=1
    No.Input.Out="Y"
    Call IO.I
    Allow.Break=False
    Break=False
    If Yes Then
       Call New.Mail
    Endif
 Endif
 Carriage.Return=True
 Strng=Nul
 Call IO.O
 UserRecord.DateOn=DateS$
 If Config2(14) Then
    Graphics.Off=False
    Strng=Config3(6)
    If Strng<>Nul Then
       No.Echo=True
       Line.Length=1
       Call IO.I
       No.Echo=False
    Endif
 Endif
 Call Display.LogFile
 Call Update.Mess(4)
 Strng="Logged on"
 If Local.Mode=False Then
    Strng=Strng+": "+Modem.Return+"bps"
 Endif
 If Rtrim$(NodeX)=Nul Then
    Strng=Strng+" (Node -)"
 Else
    Strng=Strng+" (Node "+NodeX+")"
 Endif
 If BBS.Mode=-1 Then
    Strng=Strng+" <door>"
 Endif
 If BBS.Mode=-2 Then
    Strng=Strng+" <telnet>"
 Endif
 Call Update.DayFile(Strng,True,False)
 If UserRecord.Level=False Then
    Strng="You are level zero. You can use the 'Train' command once free."
    Call IO.O
 Endif
 Call Clear.Mess
 If Node>False Then
    Out2="Just logged on (Node "+NodeX+")."
    Call Send.Mess(4,SFalse,SFalse,Out2)
 Endif
 Monsters.Killed=UserRecord.MonstersKilled
 Players.Killed=UserRecord.PlayersKilled
 Permanent.Killed=UserRecord.PermanentKilled
 If Lost.Carrier Then
    Security.Guard=False
    Logged.In=False
 Endif
 Graphics.Off=False
 Strng="You are now logged in to Dndbbs..."
 Call IO.O
 New.Mail.Time = SFalse
 New.Mail.Count = 0
 Redim Shortcut.Key1(1 To MaxShortcutKeys) As String*8
 Redim Shortcut.Key2(1 To MaxShortcutKeys) As String*32
 For Var=1 To MaxShortcutKeys
    Shortcut.Key1(Var)=Nul
    Shortcut.Key2(Var)=Nul
 Next

 ' load shortcut keys
 For Var=1 To MaxShortcutKeys
    Var1$=Rtrim$(UserRecord.ShortcutKey1(Var))
    Var2$=Rtrim$(UserRecord.ShortcutKey2(Var))
    If Var1$=String$(8,Chr$(0)) Then
       UserRecord.ShortcutKey1(Var)=Nul
    Else
       If Var2$=String$(32,Chr$(0)) Then
          UserRecord.ShortcutKey2(Var)=Nul
       Else
          If Var1$<>Nul Then
             If Var2$<>Nul Then
                Shortcut.Key1(Var)=Var1$
                Shortcut.Key2(Var)=Var2$
             Endif
          Endif
       Endif
    Endif
 Next

 ' load function key redefinitions
 For Var=1 To 10
    Var$=Rtrim$(UserRecord.FunctionKeys(Var))
    If Var$=String$(20,Chr$(0)) Then
       UserRecord.FunctionKeys(Var)=Nul
    Else
       If Var$<>Nul Then
          Var2$=Chr$(27)+"[0;"+Mid$(Str$(Var+58),2)+";"+Var$+"p"
          If Local.Mode=False Then
             If Remote.ANSI.Color Then
                Call Put.Modem(Var2$)
             Endif
          Else
             If Local.ANSI.Color Then
                Call Put.Screen(Var2$)
             Endif
          Endif
       Endif
    Endif
 Next

 ' load ANSI key file
 '   except A, B, C, D, H, K
 Redim ANSI.Keys(1 To 26) As String*79
 For Var=1 To 26
    ANSI.Keys(Var)=Nul
 Next
 Filename=DND.Path+"ANSI.KEY"
 If Dir$(Filename)<>"" Then
    Close #Tempfile1
    Open FileName For Input Shared As #TempFile1
    Do While Not Eof(TempFile1)
       Line Input #TempFile1, Var$
       Call Strip.Line(Var$)
       If Len(Var$) Then
          Var=Instr(Var$,"=")
          If Var Then
             Var1$=Left$(Var$,Var-1)
             Var2$=Mid$(Var$,Var+1)
             Var1$=Ucase$(Ltrim$(Rtrim$(Var1$)))
             Var2$=Ltrim$(Rtrim$(Var2$))
             If Len(Var1$)=1 Then
                If Var1$>="A" And Var1$<="Z" Then
                   If Len(Var2$) Then
                      ANSI.Keys(Asc(Var1$)-64)=Var2$
                   Endif
                Endif
             Endif
          Endif
       Endif
    Loop
 Endif

 ' init action prompt
 If Len(Option1$) Then
    Action.Prompt=Option1$
 Else
    If UserRecord.Brief Then
       Action.Prompt=Config3(8)
    Else
       Action.Prompt=Config3(7)
    Endif
    If UserRecord.Level<Config2(12) Then
       UserRecord.Brief=False
       Action.Prompt=Config3(7)
    Endif
    Var$=UserRecord.ActionLineString
    If Var$=String$(80,Chr$(0)) Then
       UserRecord.ActionLineString=Action.Prompt
    Else
       Var$=Rtrim$(Var$)
       If Var$<>Nul Then
          Action.Prompt=Var$
          If Right$(Var$,1)=Chr$(1) Then
             Action.Prompt=Left$(Var$,Len(Var$)-1)
          Endif
       Endif
    Endif
 Endif
 ' hardcode default prompt
 If Rtrim$(Action.Prompt)=Nul Then
    If UserRecord.Brief Then
       Action.Prompt="Next:"
    Else
       Action.Prompt="Command>"
    Endif
 Endif

 ' remove user from offline players
 If Config2(55) Then
    For User.Temp=1! To Lof(MessWorkFile4)/MessWorkRecLen4
       Call Read.Record(MessWorkFile4,User.Temp)
       If MessWorkRecord4.Index=User.Index Then
          MessWorkRecord4.Room=SFalse
          Call Write.Record(MessWorkFile4,User.Temp)
       Endif
    Next
 Endif

 ' init all persistent treasure in user inventory
 For Temp5!=1! To Lof(MessWorkFile6)/MessWorkRecLen6
    Call Read.Record(MessWorkFile6,Temp5!)
    If MessWorkRecord6.User=User.Index Then
       VarQ!=MessWorkRecord6.Index
       If VarQ!>SFalse And VarQ!<=Lof(TreasureFile)/TreasureRecLen Then
          Call Read.Record(TreasureFile,VarQ!)
          If TreasureRecord.Persistent Then
             MessWorkRecord6.Time1=Timeit!
             Call Write.Record(MessWorkFile6,Temp5!)
          Endif
       Endif
    Endif
 Next

 ' start room
 Next.Room=Room

 ' play intro
 Call Playwav(6)

 ' remove exit file
 FileName=DND.Path+"DEXIT"+NodeX+".DEF"
 If Dir$(FileName)<>"" Then
    Close #TempFile1
    Kill FileName
 Endif

 ' telnet door name override
 If BBS.Mode=-2 Then
    Door.Name=UserRecord.CodeName
 Endif
 Exit Sub

Get.Config5:
 Option1=True
 Option2=False
 Option3=True
 Option1$=Nul
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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 "read.system.news" ' added 04/12/2021
                Select Case Lcase$(Var3$)
                Case "0","off","false"
                   Option1=False
                End Select
             Case "check.new.mail" ' added 04/12/2021
                Select Case Lcase$(Var3$)
                Case "0","off","false"
                   Option3=False
                End Select
             Case "start.hidden"
                Select Case Lcase$(Var3$)
                Case "-1","on","true"
                   Option2=True
                End Select
             Case "action.prompt"
                If Left$(Var3$,1)=Chr$(34) Then
                   If Right$(Var3$,1)=Chr$(34) Then
                      Option1$=Mid$(Var3$,2)
                      Option1$=Left$(Option1$,Len(Option1$)-1)
                   Endif
                Endif
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
ErrorRsm26:
 Exit Sub
ErrorTrp26:
 Security.Guard=False
 Resume ErrorRsm26
End Sub

Sub Reset.Keys
 On Local Error Goto ErrorTrp26x
 For Var=1 To 10
    Var2$=Chr$(27)+"[0;"+Mid$(Str$(Var+58),2)
    Var2$=Var2$+";0;"+Mid$(Str$(Var+58),2)+"p"
    If Local.Mode=False Then
       If Remote.ANSI.Color Then
          Call Put.Modem(Var2$)
       Endif
    Else
       If Local.ANSI.Color Then
          Call Put.Screen(Var2$)
       Endif
    Endif
 Next
ErrorRsm26x:
 Exit Sub
ErrorTrp26x:
 Resume ErrorRsm26x
End Sub

Sub Init.Guest
 On Local Error Goto ErrorTrp26a
 If GuestRecord.GuestStartsInRoom>SFalse Then
    UserRecord.Room=GuestRecord.GuestStartsInRoom
    Room=UserRecord.Room
 Endif
 If GuestRecord.GuestStartsAtLevel>False Then
    UserRecord.Level=GUestRecord.GuestStartsAtLevel
    If Config2(93)=False Then
       UserRecord.Experience=2^Config2(92)
    Else
       UserRecord.Experience=False
    Endif
    Call New.Stats
 Endif
 Temp5=GuestRecord.GuestClass
 If Temp5>False And Temp5<=MaxClasses Then
    UserRecord.ClassType=Temp5
    UserRecord.ClassName=Class.Name(UserRecord.ClassType)
 Endif
 Temp2=GuestRecord.GuestRace
 If Temp2>False And Temp2<=MaxRaces Then
    UserRecord.Race=Temp2
 Endif
 Temp2=GuestRecord.GuestAlign1
 Temp5=GuestRecord.GuestAlign2
 If Temp2>False And Temp2<=MaxAlignment Then
    If Temp5>False And Temp5<=MaxAlignment Then
       UserRecord.Align1=Temp2-2
       UserRecord.Align2=Temp5-2
    Endif
 Endif
 Temp2=GuestRecord.GuestProf
 If Temp2>False And Temp2<=MaxWeapons Then
    UserRecord.Proficiency=Temp2
 Endif
 Call Modify.Guest.Stats(Var)
ErrorRsm26a:
 Exit Sub
ErrorTrp26a:
 Security.Guard=False
 Resume ErrorRsm26a
End Sub

Sub Display.Prenotice
 On Local Error Goto ErrorTrp27
 ' reset shutdown state
 VarX=Node
 Call Read.Message.Record(MessWorkFile1,VarX+1)
 MessWorkRecord1.ActiveNode=-1
 MessWorkRecord1.SuspendNode=0
 MessWorkRecord1.Monitor=0
 Call Write.Message.Record(MessWorkFile1,VarX+1)
 For Var!=1 To Lof(MessWorkFile2)/MessWorkRecLen2
    Call Read.Record(MessWorkFile2,Var!)
    Mid$(MessWorkRecord2.Flags,Node+1,1)="1"
'    MessWorkRecord2.MessageType=0
    Call Write.Record(MessWorkFile2,Var!)
 Next
 ' assign values
 User.Echo=Config2(86)
 User.Linefeeds=Config2(87)
 User.Wordwrap=Config2(90)
 VarX=Config2(88)
 If VarX=40 Or VarX=80 Then
    Eat$ = Nul
 Else
    VarX=80
 Endif
 User.Linelength=VarX
 VarY=Config2(89)
 If VarY=25 Or VarY=43 Or VarY=50 Then
    Eat$ = Nul
 Else
    VarY=25
 Endif
 User.Pagelength = VarY
 Avatar.Code=12
 Color.Code=32
 Graphics.Off=False
 If Relogging=False Then
    Remote.ANSI.Color=False
    Remote.Avatar.Color=False
    If Local.Mode=False Then
       If Config2(73) Or Config2(85) Then
          Strng="Wait.."
          Call Send.Modem(Strng)
       Endif
       If Config2(73) Then
          Call Check.ANSI
          If Remote.ANSI.Color Then
             Strng="Remote ANSI detected."
             Call IO.O
          Endif
       Endif
       If Config2(85) Then
          Call Check.Avatar
          If Remote.Avatar.Color Then
             Strng="Remote Avatar detected."
             Call IO.O
          Endif
       Endif
    Endif
 Endif
 Call Modem.ANSI(1,37,7)
 Call Modem.ANSI(3,0,0)
 If Config2(3) Then
    Graphics.Off=True
    Strng=Nul
    Call IO.O
    Call Pre.Clock(Var$)
    Strng="Dndbbs online at "+Var$
    Call IO.O
    Graphics.Off=False
    Allow.Break=True
    Break=False
    Graphics.Off=True
    TempD=Break
    Allow.Break=False
    Break=False
 Endif
 If Config2(72) Then
    Allow.Break=True
    Break=False
    Buffer=Nul
    Line.Length=False
    Out2=Nul
    Type.Ahead=Nul
    Graphics.Off=False
    No.Echo=False
    Line.Length=1
    No.Input.Out="Y"
    Strng="Change settings(y/n)? "
    Call IO.I
    Allow.Break=False
    Break=False
    If Yes Then
       Call Get.Preferences
    Endif
 Endif
ErrorRsm27:
 Exit Sub
ErrorTrp27:
 Security.Guard=False
 Resume ErrorRsm27
End Sub

Sub Get.ANSI
 On Local Error Goto ErrorTrp28
 Do
    Strng="Use ANSI color(y/n/h)? "
    No.Input.Out="Y"
    Call IO.I
    Select Case Ucase$(Out2)
    Case "H"
       Call Logon.Help(2,4)
    Case "Y"
       If Local.Mode Then
	  Local.ANSI.Color=True
       Else
	  Remote.ANSI.Color=True
       Endif
       Strng="ANSI codes enabled."
       Exit Do
    Case "N"
       If Local.Mode Then
	  If Local.ANSI.Color Then
             Call ScreenANSI(1,37,0)
	     Local.ANSI.Color=False
	  Endif
       Else
	  If Remote.ANSI.Color Then
	     Call Modem.ANSI(1,37,0)
	     Remote.ANSI.Color=False
	  Endif
       Endif
       Strng="ANSI codes disabled."
       Exit Do
    End Select
 Loop
 Call IO.O
 If Logged.In Then
    Call Status.Line(1)
 Endif
ErrorRsm28:
 Exit Sub
ErrorTrp28:
 Resume ErrorRsm28
End Sub

Sub Get.Avatar
 On Local Error Goto ErrorTrp29
 Do
    Strng="Use Avatar codes(y/n/h)? "
    No.Input.Out="H"
    Call IO.I
    Select Case Ucase$(Out2)
    Case "H"
       Call Logon.Help(39,42)
    Case "Y"
       If Local.Mode Then
	  Local.Avatar.Color=True
       Else
	  Remote.Avatar.Color=True
       Endif
       Strng="Avatar codes enabled."
       Exit Do
    Case "N"
       If Local.Mode Then
	  If Local.Avatar.Color Then
             Call ScreenANSI(1,37,0)
	     Local.Avatar.Color=False
	  Endif
       Else
	  If Remote.Avatar.Color Then
	     Call Modem.ANSI(1,37,0)
	     Remote.Avatar.Color=False
	  Endif
       Endif
       Strng="Avatar codes disabled."
       Exit Do
    End Select
 Loop
 Call IO.O
 If Logged.In Then
    Call Status.Line(1)
 Endif
ErrorRsm29:
 Exit Sub
ErrorTrp29:
 Resume ErrorRsm29
End Sub

Sub Check.ANSI
 On Local Error Goto ErrorTrp30
 Gosub Get.Config9a
 If Option1=0 Then
    Exit Sub
 Endif
 If Remote.ANSI.Color Then
    Exit Sub
 Endif
 Strng=Chr$(27)+"[2J"+Chr$(27)+"[1;1H"+Chr$(27)+"[6n"
 Call Verify.ANSI(Var)
 If Var Then
    Remote.ANSI.Color=Var
 Endif
 Exit Sub
Get.Config9a:
 Option1=-1
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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 "check.remote.ansi"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   Option1=0
                End Select
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
ErrorRsm30:
 Exit Sub
ErrorTrp30:
 Resume ErrorRsm30
End Sub

Sub Check.Avatar
 On Local Error Goto ErrorTrp31
 Gosub Get.Config9b
 If Option1=0 Then
    Exit Sub
 Endif
 Strng=Chr$(12)+Chr$(22)+Chr$(8)+Chr$(1)+Chr$(1)+Chr$(27)+"[6n"
 Call Verify.ANSI(Var)
 Remote.Avatar.Color=Var
 Exit Sub
Get.Config9b:
 Option1=-1
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" 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 "check.remote.avatar"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   Option1=0
                End Select
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
ErrorRsm31:
 Exit Sub
ErrorTrp31:
 Resume ErrorRsm31
End Sub

Sub Verify.ANSI(Var)
 On Local Error Goto ErrorTrp32
 Var=False
 Var1!=Timeit!
 Var2!=Csng(Config2(134))
 Buffer=Nul
 Out3=Chr$(27)+"[1;1R" ' store CPR (Cursor Position Report)
 Call Put.Modem(Strng) ' send cursor position/DSR (Device Status Report)
 Do
    If Time.Elapsed(Var1!,Var2!) Then
       Exit Do
    Endif
    Call Get.Modem(False)
    If Instr(Ucase$(Buffer),Out3) Then
       Var=True
       Exit Do
    Endif
 Loop
 For Var1=1 To Len(Strng)
    Call Back.Space
 Next
ErrorRsm32:
 Exit Sub
ErrorTrp32:
 Resume ErrorRsm32
End Sub

Sub Search.Mess.File(Var1!,Var2)
 On Local Error Goto ErrMain41
 Var2=False
 For TempA=False To MaxNodes
    Call Read.Message.Record(MessWorkFile1,TempA+1)
    Var$=MessWorkRecord1.UserName
    Select Case Rtrim$(Lcase$(Var$))
    Case "login", "logoff", "relogin"
       TempB=False
    Case Deleted$, Offline$
       TempB=False
    Case Else
       TempB=True
    End Select
    If TempB Then
       If MessWorkRecord1.UserIndex=Var1! Then
          Var2=True
          Exit For
       Endif
    Endif
 Next
MainExit41:
 Exit Sub
ErrMain41:
 Resume MainExit41
End Sub

Sub Passwrd3(Var,Var3)
 On Local Error Goto Error.Trap62a
 Var=True
 Call IsPasswrd(Var2)
 If Var2 Then
    If Var3 Then
       VarX=Local.Mode
       Local.Mode=True
    Endif
    Graphics.Off=False
    Strng=Nul
    Call IO.O
    Call Pre.Clock(Var$)
    Strng="Dndbbs online at "+Var$
    Call IO.O
    Carriage.Return=True
    Strng="Password?["+Space$(20)+"]"
    Call IO.O
    Call Password.Mask(20)
    Strng=""
    Line.Length=20
    Allow.Break=True
    Hidden=True
    Call IO.I
    Allow.Break=False
    Hidden=False
    TempA$=Out2
    If TempA$<>TempC$ Then
       Var=False
    Endif
    If Var3 Then
       Local.Mode=VarX
    Endif
 Endif
Error.Resume62a:
 Exit Sub
Error.Trap62a:
 Resume Error.Resume62a
End Sub

Sub IsPasswrd(Var)
 On Local Error Goto Error.Trap62b
 Var=False
 Close #TempFile1
 FileName=DND.Path+"DNDBBS.EXE"
 Open FileName For Binary As #TempFile1
 File.Length!=Lof(TempFile1)
 Get TempFile1,File.Length!,Byte
 Byte.Value=Asc(Byte)
 TempC$=Nul
 ' locate trailing marker indicating password exists
 If Byte.Value=255 Then
    ' read password from .exe file
    For File.Position!=File.Length!-20 To File.Length!-1
       Get TempFile1,File.Position!,Byte
       TempC$=TempC$+Byte
    Next
    Call Crypto(TempC$) ' decrypt password
    TempC$=Rtrim$(TempC$)
    If TempC$<>Nul Then
       Var=True
    Endif
 Endif
Error.Resume62b:
 Exit Sub
Error.Trap62b:
 Resume Error.Resume62b
End Sub

' removes comments from string
Sub Strip.Line(Var$)
 On Local Error Goto Error.Trap63
 Var$=Lcase$(Ltrim$(Rtrim$(Var$)))
 VarQ=Instr(Var$,"'") ' imbedded comment
 If VarQ=1 Then
    Var$=Nul
 Else
    If VarQ Then
       Var$=Left$(Var$,VarQ-1)
       Var$=Ltrim$(Rtrim$(Var$))
    Endif
 Endif         
 If Len(Var$) Then
    If Left$(Var$,1)=";" Then ' line comment
       Var$=Nul
    Endif
 Endif
Error.Resume63:
 Exit Sub
Error.Trap63:
 Resume Error.Resume63
End Sub

Sub Get.Login.Tries(VarZ,VarZ3,VarZ4)
 On Local Error Goto Error.Trap63x
 VarZ=LoginTries
 VarZ3=LoginTries
 VarZ4=LoginTries
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[LOGIN]" Then
       Do
          VarX=VarX+1
          If VarX>Options.Lines Then
             Exit Sub
          Endif
          Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
          If Ucase$(Var$)="[END]" Then
             Exit Sub
          Endif
          Var=Instr(Var$,"=")
          If Var Then
             Var2$=Lcase$(Ltrim$(Rtrim$(Left$(Var$,Var-1))))
             Var3$=Ltrim$(Rtrim$(Mid$(Var$,Var+1)))
             VarY=Int(Val(Var3$))
             If Var2$="login.tries" Then
                If VarY>0 And VarY<=1024 Then
                   VarZ=VarY
                Endif
             Endif
             If Var2$="login.tries2" Then
                If VarY>0 And VarY<=1024 Then
                   VarZ3=VarY
                Endif
             Endif
             If Var2$="login.tries3" Then
                If VarY>0 And VarY<=1024 Then
                   VarZ4=VarY
                Endif
             Endif
          Endif
       Loop
    Endif
 Loop
Error.Resume63x:
 Exit Sub
Error.Trap63x:
 Resume Error.Resume63x
End Sub

Sub Display.Guest
 On Local Error Goto Error.Trap63x2
 If GuestRecord.GuestAllowed Then
    If GuestRecord.OpenSystem=False Then
       If Node>0 Then
          Graphics.Off=False
          Strng="New users type 'guest' to login."
          Call IO.O
       Endif
    Endif
 Endif
Error.Resume63x2:
 Exit Sub
Error.Trap63x2:
 Resume Error.Resume63x2
End Sub
