home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / MISC / DNDOOR46.ZIP / DNDS2.BAS < prev    next >
BASIC Source File  |  2001-07-11  |  121KB  |  2,672 lines

  1.  Rem * Filename: dnds2.bas Version: v4.6 r1.0
  2.  Rem * This subprogram contains most login routines, and parse routines.
  3.  
  4.  Rem $Include: 'dnddoor.inc'
  5.  
  6.  Rem * routine to login user.
  7.  Rem * output variables:
  8.  Rem *   Time.On - contains time logged in.
  9.  Rem *   Timeon - contains time logged in past midnight.
  10.  Rem *   Time.Left - stores time limit in seconds past midnight.
  11.  Rem *   User.Index - number of record in user file codename will use.
  12.  Rem * processing variables:
  13.  Rem *   Time.Left - during logging in.
  14.  Rem *   Two.Minutes.Left - time remaining flag.
  15.  Rem *   Login.Try - total login attempts.
  16.  Rem *   New.User - flag indicates new user login.
  17.  Rem *   Logged.User - flag indicates user exists in files.
  18.  
  19. Sub Login
  20.  On Local Error Resume Next ' local error resume
  21.  Time.On=Time$ ' store system time logged in (string form hh:mm:ss)
  22.  Timeon=Timer ' store system time logged in (seconds past midnight)
  23.  Timelogged.On=Now ' store time logged in (double format)
  24.  Time.Left=600! ' set time limit during logging in
  25.  Two.Minutes.Left=False ' flag for two minute left display message
  26.  Logged.In=False ' set user logged in flag
  27.  ' format initial login display line
  28.  Outpt="The Adventure Door v"+Version$+", Node: "+Node+", "+FNclock$
  29.  If Local.Mode=False Then
  30.     Outpt=Outpt+", baud"+Str$(Modem.Baud)+"00"
  31.  Endif
  32.  Outpt=Outpt+"."
  33.  Call IO.O ' display initial message
  34.  ' format prompt for login welcome
  35.  Outpt="Press <enter> to display the welcome, or <space> to skip:"
  36.  No.Echo=True ' supress prompt input echo
  37.  Line.Length=1 ' get only one keypress
  38.  Call IO.I ' input routine
  39.  No.Echo=False ' reset echo
  40.  If Inpt=Nul Then ' check empty return
  41.     Call Out.File("welcome.dat") ' display welcome file
  42.  Endif ' end display welcome
  43.  Do ' main login processing loop
  44.     Login.Try=False ' reset login attempts
  45.     Do ' get codename processing loop
  46.        New.User=False ' reset new user flag
  47.        Call Get.Codename ' prompt user for codename
  48.        Call Get.PassWord ' prompt user for password
  49.        Call Find.PassWord(Logged.User) ' find codename in user file
  50.        If Logged.User Then ' compare user has entered an existing codename
  51.           Call Verify.PassWord(Logged.Pass) ' compare entered password
  52.           If Logged.Pass Then ' check if password matches
  53.              Exit Do ' exit codename processing/entry loop
  54.           Endif ' end check password match
  55.           If Login.Try>=3 Then ' compare login attempts
  56.              Call Hang.Up(7) ' routine to terminate program w/ message
  57.              Exit Sub ' exit login routine/return to main
  58.           Endif ' end compare login attempts
  59.           Login.Try=Login.Try+1 ' increment login attempt
  60.           Outpt="Illegal password attempt!" ' display error message
  61.           Call IO.O ' send output/continue codename entry loop
  62.        Else ' user has not entered an existing codename
  63.           Call Get.Newuser.Record ' find an empty user file record
  64.           Call Verify.Newuser(New.User) ' verify password entered
  65.           If New.User>False Then ' user selected disconnect
  66.              Call Hang.Up(8) ' routine to terminate program w/ message
  67.              Exit Sub ' exit routine
  68.           Endif ' end compare disconect
  69.           If New.User<False Then ' user password verified
  70.              Call Init.Newuser ' initialize some new user variables
  71.              Call Verify.Newlogin(New.User,True) ' verify user is new
  72.              If New.User Then ' user selects to continue as a new user
  73.                 Exit Do ' exit codename/password entry loop
  74.              Endif ' end new user continue
  75.           Endif ' end password verify
  76.        Endif ' end compare existing codename
  77.     Loop ' codename/password entry loop
  78.     Call Update.Login ' intialize some login variables
  79.     If New.User=False Then ' compare user is new user
  80.        Exit Do ' exit main login processing loop
  81.     Endif ' end compare new user
  82.     If New.User Then ' compare new user login is verified
  83.        Call Roll.Character ' get user selected character statistics
  84.        Call Verify.Newlogin(New.User,False) ' verify new user to continue
  85.        If New.User Then ' new user is logged in
  86.           Exit Do ' exit main login processing loop
  87.        Endif ' end compare new user login
  88.     Endif ' end compare new user login
  89.  Loop ' end main login processing loop
  90.  Call Login.User ' routine to initialize some login variables
  91.  Outpt=Nul ' send empty output
  92.  Call IO.O ' send output
  93.  Outpt="Press <enter> to begin the adventure:" ' format message
  94.  No.Echo=True ' set flag to supress echo input
  95.  Line.Length=1 ' get one keypress
  96.  Call IO.I ' get input
  97.  No.Echo=False ' reset echo flag
  98.  Next.Room=Room ' store room number
  99.  Call Enter.Room ' display room description
  100.  Logged.In=True ' set user logged in flag
  101.  Func.Buffer=Nul ' reset function key flag
  102. End Sub ' end routine to login user
  103.  
  104.  Rem * routine to find codename entered in user file.
  105.  Rem * output variables:
  106.  Rem *   PassWord.Found - flag if codename is in user file.
  107.  
  108. Sub Find.PassWord(PassWord.Found)
  109.  On Local Error Resume Next ' local error resume
  110.  PassWord.Found=False ' set flag to false
  111.  Inpt=Rtrim$(Player.CodeName) ' store codename
  112.  For User.Index=1 To Lof(UserFile)/Len(UserRecord) ' loop through entire user file
  113.     Call Read.Record(UserFile,User.Index) ' get next user file record
  114.     Outpt=UserRecord.CodeName ' store user file codename
  115.     Call Decrypt(Outpt) ' decrypt user file codename
  116.     Outpt=Rtrim$(Outpt) ' trim user file codename
  117.     If Outpt=Inpt Then ' compare user file codename to codename entered
  118.        PassWord.Found=True ' set return variable flag
  119.        Exit For ' exit user file loop
  120.     Endif ' end check codenames
  121.  Next ' loop through user file
  122. End Sub ' end routine to find user file codename
  123.  
  124.  Rem * routine to verify valid password of codename entered.
  125.  Rem * output variables:
  126.  Rem *   PassWord.Found - flag indicates password exists.
  127.  
  128. Sub Verify.PassWord(PassWord.Found)
  129.  On Local Error Resume Next ' local error resume
  130.  PassWord.Found=False ' set flag to false
  131.  Outpt=UserRecord.PassWord ' store user file password
  132.  Call Decrypt(Outpt) ' decrypt password
  133.  If Len(Outpt)=False Then ' verify decrypt result
  134.     Outpt="Password has a checksum error!" ' format message
  135.     Call IO.O ' send message
  136.     PassWord.Found=False ' set flag to verify password
  137.     Exit Sub ' exit check password routine
  138.  Endif ' end check password
  139.  Outpt=Rtrim$(Outpt) ' store trimmed user file password
  140.  Inpt=Rtrim$(Player.PassWord) ' store password entered
  141.  If Outpt=Inpt Then ' compare user file password to entered password
  142.     PassWord.Found=True ' set flag to verify password
  143.  Endif ' end compare passwords
  144. End Sub ' end routine to check valid password
  145.  
  146.  Rem * routine to verify new user is continuing.
  147.  Rem * input variables:
  148.  Rem *   Message.Type - message to select.
  149.  Rem * output variables:
  150.  Rem *   Response.Type - returns true to continue, false if not.
  151.  
  152. Sub Verify.Newlogin(Response.Type,Message.Type)
  153.  On Local Error Resume Next ' local error resume
  154.  Do ' process input loop
  155.     Graphics.Off=False ' reset color
  156.     If Message.Type Then ' compare prompt
  157.        Outpt="Press <enter> to roll character, or <space> to reenter:"
  158.     Else ' select prompt
  159.        Outpt="Press <enter> to use character, or <space> to reroll:"
  160.     Endif ' end compare prompt
  161.     No.Echo=True ' supress input echo
  162.     Line.Length=1 ' input one keypress
  163.     Call IO.I ' get user input
  164.     No.Echo=False ' reset input echo
  165.     If Inpt=" " Then ' selected space
  166.        Response.Type=False ' set return flag
  167.        Exit Do ' exit routine
  168.     Endif ' end compare select
  169.     If No.Input Then ' compare empty input
  170.        Response.Type=True ' set return flag
  171.        Exit Do ' exit routine
  172.     Endif ' end compare select
  173.  Loop ' process input loop
  174. End Sub ' end routine to prompt to continue
  175.  
  176.  Rem * routine to get codename, check illegal character in codename, verify
  177.  Rem * user has entered correct codename.
  178.  Rem * output variables:
  179.  Rem *   Player.CodeName - contains lowercased, trimmed codename entered.
  180.  
  181. Sub Get.Codename
  182.  On Local Error Resume Next ' local error resume
  183.  Do ' main codename entry processing loop
  184.     Do ' loop until valid codename entered
  185.        Outpt=Nul ' empty output
  186.        Call IO.O ' send output
  187.        Graphics.Off=True ' reset color
  188.        Outpt="         +---------+---------+---------+" ' make length bar
  189.        Call IO.O ' send output
  190.        Outpt="Codename? " ' codename prompt
  191.        Line.Length=30 ' set line length of codename
  192.        Upper.Case=True ' reset uppercase flag
  193.        Call IO.I ' get codename input
  194.        Upper.Case=False ' reset uppercase flag
  195.        Graphics.Off=False ' reset color
  196.        Inpt=Ltrim$(Inpt) ' trim blanks
  197.        Inpt=Rtrim$(Inpt) ' trim blanks
  198.        Inpt=Ucase$(Inpt) ' set input to uppercase
  199.        Player.CodeName=Inpt ' store codename
  200.        If Len(Player.CodeName)>False Then ' check length of codename
  201.           Call Valid(Player.CodeName,30) ' verify valid characters
  202.           If Len(Player.CodeName)>False Then ' check valid codename
  203.              Exit Do ' exit codename entry loop
  204.           Endif ' end check valid characters
  205.           Outpt="Illegal characters in codename!" ' format message
  206.           Call IO.O ' send output
  207.        Endif ' end check codename length
  208.     Loop ' continue entry loop
  209.     Outpt=Rtrim$(Player.CodeName) ' store codename
  210.     Outpt=Lcase$(Outpt) ' set to lowercase
  211.     Mid$(Outpt,1,1)=Ucase$(Mid$(Outpt,1,1)) ' make first character uppercase
  212.     Outpt="You are "+Chr$(34)+Outpt+Chr$(34)+"(y/n)? " ' format prompt
  213.     No.Input.Out="Y" ' set default input to yes
  214.     Line.Length=1 ' reset line length
  215.     Call IO.I ' prompt for correct codename entered
  216.     If Yes Then ' verify user has verified correct codename
  217.        Exit Do ' exit main codename entery loop
  218.     Endif ' end verify user input
  219.  Loop ' end codename entry loop
  220. End Sub ' end routine to get and verify codename entry
  221.  
  222.  Rem * routine to prompt user for password, check valid characters in password.
  223.  Rem * output variables:
  224.  Rem *   Player.PassWord - contains lowercased, trimmed password entered.
  225.  
  226. Sub Get.PassWord
  227.  On Local Error Resume Next ' local error resume
  228.  Do ' password entry loop
  229.     Outpt=Nul ' empty output
  230.     Call IO.O ' send output
  231.     Graphics.Off=True ' reset color
  232.     Outpt="         +---------+---------+" ' make length bar
  233.     Call IO.O ' send output
  234.     Outpt="Password? " ' password prompt
  235.     Line.Length=20 ' set line length of password
  236.     Hidden=True ' set flag to echo mask characters
  237.     Call IO.I ' get input
  238.     Hidden=False ' reset mask flag
  239.     Graphics.Off=False ' reset color
  240.     Inpt=Ltrim$(Inpt) ' trim blanks
  241.     Inpt=Rtrim$(Inpt) ' trim blanks
  242.     Inpt=Ucase$(Inpt) ' set input to uppercase
  243.     Player.PassWord=Inpt ' store password
  244.     If Len(Player.PassWord)>False Then ' check length of password
  245.        Call Valid(Player.PassWord,20) ' verify valid characters
  246.        If Len(Player.PassWord)>False Then ' check valid password
  247.           Exit Do ' exit password entry loop
  248.        Endif ' end check valid characters
  249.        Outpt="Illegal characters in password!" ' format message
  250.        Call IO.O ' send output
  251.     Endif ' end check password length
  252.  Loop ' end password entry loop
  253. End Sub ' end routine to enter password
  254.  
  255.  Rem * routine to find empty user file record.
  256.  Rem * output variables:
  257.  Rem *    User.Index - unused number of record in user file.
  258.  
  259. Sub Get.Newuser.Record
  260.  On Local Error Resume Next ' local error resume
  261.  For User.Index=1 To Lof(UserFile)/Len(UserRecord) ' loop through users
  262.     Call Read.Record(UserFile,User.Index) ' load the user record
  263.     Outpt=UserRecord.CodeName ' store user file codename
  264.     Call Decrypt(Outpt) ' routine to decrypt codename
  265.     If Left$(Outpt,9)=Deleted$ Then ' compare to deleted record
  266.        Exit For ' end loop through user file
  267.     Endif ' end compare deleted record
  268.  Next ' end loop through user file
  269.  ' exit of loop w/o finding a deleted record will set User.Index to one
  270.  ' record past the last in the user file, appending the next record.
  271.  Call Read.Record(UserFile,User.Index) ' get empty user file record
  272.  Outpt="Codename not found in files!" ' make message
  273.  Call IO.O ' send message
  274. End Sub ' end routine to find empty user file record
  275.  
  276.  Rem * routine to verify new user login.
  277.  Rem * output variables:
  278.  Rem *   Response.Type - flag set to 1 to disconnect,
  279.  Rem *   0 if password not verified, -1 if password is verified.
  280.  
  281. Sub Verify.Newuser(Response.Type)
  282.  On Local Error Resume Next ' local error resume
  283.  Do ' password verify loop
  284.     Outpt="Press <C>ontinue, <H>angup, or <R>estart:" ' make message
  285.     No.Input.Out="C" ' default empty input to continue
  286.     Line.Length=1 ' reset line length
  287.     Call IO.I ' get input
  288.     Response.Type=False ' set return flag to unverified
  289.     Select Case Ucase$(Inpt) ' compare input selection
  290.     Case "C" ' continue selected
  291.        Outpt=Nul ' set empty output
  292.        Call IO.O ' send output
  293.        Outpt="Verify password: " ' prompt for password
  294.        Hidden=True ' set echo characters masked
  295.        Line.Length=20 ' line length of password
  296.        Call IO.I ' get user input
  297.        Hidden=False ' reset echo mask flag
  298.        Inpt=Ltrim$(Inpt) ' trim input
  299.        Inpt=Rtrim$(Inpt) ' trim input
  300.        Inpt=Ucase$(Inpt) ' set input uppercase
  301.        Outpt=Rtrim$(Player.PassWord) ' store password entered
  302.        If Outpt<>Inpt Then ' compare password entered to verify entry
  303.           Outpt="Passwords don't match!" ' make error message
  304.           Call IO.O ' send output
  305.           Response.Type=False ' set flag to unverified
  306.           Exit Do ' exit routine
  307.        Endif ' end compare password
  308.        Outpt="Memorize your password!" ' make message
  309.        Call IO.O ' send output
  310.        Call IO.O ' send empty line
  311.        Response.Type=True ' set flag to verified
  312.        Exit Do ' exit routine
  313.     Case "H" ' hangup selected
  314.        Response.Type=1 ' set flag to hangup user
  315.        Exit Do ' exit routine
  316.     Case "R" ' restart selected
  317.        Response.Type=False ' set flag to restart/unverified
  318.        Exit Do ' exit routine
  319.     End Select ' end compare input selection
  320.  Loop ' end password verify loop
  321. End Sub ' end routine to verify new password
  322.  
  323.  Rem * routine to allow user to select new character statistics.
  324.  Rem * processing variables:
  325.  Rem *   Display.Help - flag to display login help messages.
  326.  
  327. Sub Roll.Character
  328.  On Local Error Resume Next ' local error resume
  329.  Display.Help=False ' set flag to display help text
  330.  Outpt="List help text during character logon(y/n)? " ' prompt for help
  331.  No.Input.Out="N" ' default prompt
  332.  Line.Length=1 ' reset line length
  333.  Call IO.I ' get user input
  334.  If Yes Then ' check input
  335.     Display.Help=True ' set help text flag
  336.  Endif ' end check input
  337.  If Display.Help Then ' check help flag
  338.     Call Logon.Help(1) ' display class help text
  339.  Endif ' end check help flag
  340.  Call Modify.Class ' routine to select class type
  341.  If Display.Help Then ' check help flag
  342.     Call Logon.Help(2) ' display statistics entry help text
  343.  Endif ' end check help flag
  344.  Call Modify.Stats ' routine to select character statistics
  345.  If Display.Help Then ' check help flag
  346.     Call Logon.Help(3) ' display race entry help text
  347.  Endif ' end check help flag
  348.  Call Modify.Race ' routine to select character race
  349.  Call Init.Race.Stats ' routine to initialize some race statistics
  350.  If Display.Help Then ' check help flag
  351.     Call Logon.Help(4) ' display weapon proficiency entry help text
  352.  Endif ' end check help flag
  353.  Call Modify.Proficiency ' routine to select weapon proficiency
  354.  Call Init.Proficiency.Stats ' routine to intialize proficiency statistics
  355.  Call Init.Stats ' routine to intialize some character statistics
  356.  If Display.Help Then ' check help flag
  357.     Call Logon.Help(5) ' display alignment entry help text
  358.  Endif ' end check help flag
  359.  Call Modify.Alignment ' routine to select character alignment
  360.  Call Display.Init.Stats ' routine to display character statistics
  361. End Sub ' end routine to get new character statistics
  362.  
  363.  Rem * routine to display help text.
  364.  Rem * input variables:
  365.  Rem *   Help.Number - range of help text file records to display.
  366.  Rem * work variables:
  367.  Rem *   Start.Help, End.Help, Help.Count.
  368.  
  369. Sub Logon.Help(Help.Number)
  370.  On Local Error Resume Next ' local error resume
  371.  Close #HelpFile ' close work file number
  372.  FileName="logon.dat" ' store logon helptext filename
  373.  Open FileName For Random Shared As #HelpFile Len=Len(HelpRecord) ' open file
  374.  Graphics.Off=True ' set color flag
  375.  Outpt=Nul ' send empty line
  376.  Call IO.O ' send output
  377.  Select Case Help.Number ' selection for logon help record ranges
  378.  Case 1 ' help records
  379.     Start.Help=2
  380.     End.Help=6
  381.  Case 2 ' help records
  382.     Start.Help=7
  383.     End.Help=15
  384.  Case 3 ' help records
  385.     Start.Help=16
  386.     End.Help=25
  387.  Case 4 ' help records
  388.     Start.Help=26
  389.     End.Help=32
  390.  Case 5 ' help records
  391.     Start.Help=33
  392.     End.Help=36
  393.  End Select ' end select record ranges
  394.  For Help.Count=Start.Help To End.Help ' loop through help text file range
  395.     Call Read.Record(HelpFile,Help.Count) ' read help record
  396.     Outpt=Rtrim$(HelpRecord.Text) ' format help text
  397.     Call IO.O ' send help output
  398.  Next  'end loop through help file
  399.  Call IO.O ' send ampty output
  400.  Call More.Prompt ' get keypress
  401.  Graphics.Off=False ' reset color flag
  402.  Close #HelpFile
  403. End Sub ' end routine to display help text
  404.  
  405.  Rem * routine to allow user to modify character alignment.
  406.  
  407. Sub Modify.Alignment
  408.  On Local Error Resume Next ' local error resume
  409.  Do ' process modify alignment one loop
  410.     Graphics.Off=False ' reset color
  411.     Outpt="Player Alignment:" ' make message
  412.     Call IO.O ' display message
  413.     Outpt="Press "+Enter$+" for default." ' make message
  414.     Call IO.O ' display message
  415.     Graphics.Off=True ' reset color
  416.     For Align.Count=1 To 3 ' display alignment choices
  417.        Outpt=Mid$(Str$(Align.Count),2)+"> "+ _
  418.        Rtrim$(Alignment.Name1(Align.Count))
  419.        Call IO.O ' send output
  420.     Next ' loop through alignment choices
  421.     Outpt="?" ' prompt for alignment number
  422.     No.Input.Out="2" ' default to neutral
  423.     Line.Length=1 ' reset line length
  424.     Call IO.I ' get input
  425.     Player.Alignment=Int(Val(Inpt)) ' convert to number
  426.     If Player.Alignment>=1 And Player.Alignment<=3 Then ' compare valid choice
  427.        Exit Do ' exit first loop
  428.     Endif ' end compare choice
  429.  Loop ' continue alignment loop
  430.  UserRecord.Align1=Player.Alignment-2 ' store alignment as -1/0/1
  431.  Do ' process modify alignment two loop
  432.     Graphics.Off=False ' reset color
  433.     Outpt="Player Alignment:" ' make message
  434.     Call IO.O ' display message
  435.     Outpt="Press "+Enter$+" for default." ' make message
  436.     Call IO.O ' display message
  437.     Graphics.Off=True ' reset color
  438.     For Align.Count=1 To 3 ' display alignment choices
  439.        Outpt=Mid$(Str$(Align.Count),2)+"> "+ _
  440.        Rtrim$(Alignment.Name2(Align.Count))
  441.        Call IO.O ' send output
  442.     Next ' loop through alignment chocies
  443.     Outpt="?" ' prompt for alignment number
  444.     No.Input.Out="2" ' default to neutral
  445.     Line.Length=1 ' reset line length
  446.     Call IO.I ' get input
  447.     Player.Alignment=Int(Val(Inpt)) ' convert to number
  448.     If Player.Alignment>=1 And Player.Alignment<=3 Then ' compare valid choice
  449.        Exit Do ' exit second loop
  450.     Endif ' end compare choice
  451.  Loop ' continue alignment loop
  452.  UserRecord.Align2=Player.Alignment-2 ' store alignment as -1/0/1
  453. End Sub ' end routine to modify character alignment
  454.  
  455.  Rem * routine to allow user to modify character class type.
  456.  
  457. Sub Modify.Class
  458.  On Local Error Resume Next ' local error resume
  459.  Outpt=Nul ' make empty line
  460.  Call IO.O ' send output
  461.  Do ' class entry process loop
  462.     Graphics.Off=False ' reset color
  463.     Call IO.O ' send blank line
  464.     Outpt="Select your character class:" ' make message
  465.     Call IO.O ' send output
  466.     Outpt="Press "+Enter$+" for default." ' make message
  467.     Call IO.O ' send output
  468.     If Local.Mode=False Then ' console mode allows DM/Asst. DM entries
  469.        Max.Class=8 ' set number of class choices
  470.     Else ' compare console mode
  471.        Max.Class=10 ' set number of class choices
  472.     Endif ' end compare console mode
  473.     Graphics.Off=True ' reset color
  474.     For List.Counter=1 To Max.Class ' loop through class chocies
  475.        Outpt=Mid$(Str$(List.Counter),2) ' store class number
  476.        If List.Counter=10 Then ' store DM class number
  477.           Outpt="#" ' choice ten is pound sign
  478.        Endif ' end compare DM class number
  479.        Outpt=Outpt+"> "+Rtrim$(Class.Name(List.Counter)) ' append class name
  480.        Call IO.O ' send output
  481.     Next ' loop through class choices
  482.     Outpt="?" ' set input prompt
  483.     No.Input.Out="1" ' set default choice
  484.     Line.Length=1 ' reset line length
  485.     Call IO.I ' get user input
  486.     Player.Class=Int(Val(Inpt)) ' convert to number
  487.     If Inpt="#" Then ' compare DM selection
  488.        Player.Class=10 ' set to ten
  489.     Endif ' end compare DM selection
  490.     If Player.Class>=1 And Player.Class<=Max.Class Then ' check class range
  491.        Exit Do ' exit class type entry loop
  492.     Endif ' end check class range
  493.  Loop ' end class type entry loop
  494.  UserRecord.ClassType=Player.Class ' store class number in user record
  495.  Outpt=Class.Name(UserRecord.ClassType) ' get class name
  496.  Call Valid(Outpt,20) ' validate class name
  497.  If Outpt=Nul Then ' verify class name validity
  498.     Outpt="<checksum>" ' set error message
  499.     Call Valid(Outpt,20) ' validate error
  500.  Endif ' end verify class name
  501.  Call Encrypt(Outpt,True) ' encrypt class name
  502.  UserRecord.ClassName=Outpt ' store class name in user record
  503. End Sub ' end routine to modify character class type
  504.  
  505.  Rem * routine to allow user to modify character statistics.
  506.  
  507. Sub Modify.Stats
  508.  On Local Error Resume Next ' local error resume
  509.  Do ' loop until statistics selected are accepted
  510.     Do ' loop until statistics are valid
  511.        Graphics.Off=False ' reset color
  512.        Outpt="Enter character statistics, range from 8 to 18." ' message
  513.        Call IO.O ' send message
  514.        Outpt="Average less than or equal to 12." ' message
  515.        Call IO.O ' send message
  516.        Outpt="Press "+Enter$+" for default." ' message
  517.        Call IO.O ' send message
  518.        Stat.Total!=False ' reset total of selected statistics
  519.        For Class.Number=1 To 7 ' loop through entry of all statistics
  520.           Do ' loop until a valid statistic entered
  521.              Graphics.Off=True ' reset color
  522.              Outpt=Rtrim$(Stat(Class.Number))+">" ' make message w/ stat name
  523.              No.Input.Out="12" ' set default
  524.              Line.Length=2 ' reset line length
  525.              Call IO.I ' get input
  526.              Stat=Int(Val(Inpt)) ' convert to number
  527.              If Stat<8 Or Stat>18 Then ' check range
  528.                 Graphics.Off=False ' reset color
  529.                 Outpt="The average statistic must range from 8 to 18."
  530.                 Call IO.O ' send output message
  531.              Else ' check range
  532.                 Stat.Total!=Stat.Total!+Stat ' increment stat total
  533.                 UserRecord.Stats(Class.Number)=Stat ' store stat in user record
  534.                 Exit Do ' exit validity loop
  535.              Endif ' end check range
  536.           Loop ' continue valid statistic loop
  537.        Next ' loop through all statistics
  538.        Stat.Total!=Stat.Total!/7! ' calculate average of total statistics
  539.        Stats$=Str$(Stat.Total!) ' convert to string
  540.        Stat.Delimit=Instr(Stats$,".") ' search string for decimal
  541.        If Stat.Delimit=False Then ' compare decimal
  542.           Inpt=Stats$ ' set output string to converted string
  543.        Else ' check decimal, truncate to one place
  544.           ' set string
  545.           Inpt=Left$(Stats$,Stat.Delimit-1)+"."+Mid$(Stats$,Stat.Delimit+1,1)
  546.        Endif ' end compare decimal
  547.        Graphics.Off=False ' reset color
  548.        If Stat.Total!<=12 Then ' verify average
  549.           Exit Do ' exit validity loop
  550.        Endif ' end verify average
  551.        Outpt="Average"+Inpt+" to high! Try again.." ' set message
  552.        Call IO.O ' send message
  553.     Loop ' end statistic validity loop
  554.     Outpt="Your average is"+Inpt+". Change anything(y/n)? " ' make message
  555.     No.Input.Out="N" ' set default input
  556.     Line.Length=1 ' reset line length
  557.     Call IO.I ' get user input
  558.     If No Then ' check no entered
  559.        Exit Sub ' exit routine
  560.     Endif ' end check entry
  561.  Loop ' end loop to verify statistics accepted
  562. End Sub ' end routine to modify character statistics
  563.  
  564.  Rem * routine to allow user to modify character race.
  565.  
  566. Sub Modify.Race
  567.  On Local Error Resume Next ' local error resume
  568.  Do ' loop until race entry is accepted
  569.     Graphics.Off=False ' reset color
  570.     Outpt="Select your character race:" ' make message
  571.     Call IO.O ' send message
  572.     Outpt="Press "+Enter$+" for default." ' make message
  573.     Call IO.O ' send message
  574.     Graphics.Off=True ' reset color
  575.     For Race.Count=1 To 8 ' loop through all race choices
  576.        ' choice display
  577.        Outpt=Mid$(Str$(Race.Count),2)+">"+Rtrim$(Race(Race.Count))
  578.        Call IO.O ' send choice
  579.     Next ' end race display loop
  580.     Outpt="?" ' set input prompt
  581.     No.Input.Out="1" ' set default
  582.     Line.Length=1 ' reset line length
  583.     Call IO.I ' get user input
  584.     Player.Race=Int(Val(Inpt)) ' convert to number
  585.     If Player.Race>=1 And Player.Race<=8 Then ' check race range
  586.        UserRecord.Race=Player.Race ' store race in user record
  587.        Exit Sub ' exit routine
  588.     Endif ' end compare race range
  589.  Loop ' end loop to accept race entry
  590. End Sub ' end routine to modify race
  591.  
  592.  Rem * routine to allow user to modify character weapon proficiency.
  593.  
  594. Sub Modify.Proficiency
  595.  On Local Error Resume Next ' local error resume
  596.  Do ' loop until proficiency entry accepted
  597.     Graphics.Off=False ' reset color
  598.     Outpt="Weapon Proficiency:" ' set message
  599.     Call IO.O ' send output
  600.     Outpt="Clerics may only use blunt or pole type weapons." ' message
  601.     Call IO.O ' send output
  602.     Outpt="Press "+Enter$+" for default." ' message
  603.     Call IO.O ' send output
  604.     Graphics.Off=True ' reset color
  605.     For Prof.Count=1 To 4 ' loop through all weapon proficiencies
  606.        Outpt=Mid$(Str$(Prof.Count),2)+"> "+ _
  607.        Rtrim$(Weapon.Type.Name(Prof.Count))
  608.        Call IO.O ' send choice output
  609.     Next ' end weapon choices
  610.     Outpt="?" ' set user prompt
  611.     If UserRecord.ClassType=Cleric Then ' compare class to cleric
  612.        No.Input.Out="1" ' set default
  613.     Else ' compare class
  614.        No.Input.Out="3" ' set default
  615.     Endif ' end compare class
  616.     Line.Length=1 ' reset line length
  617.     Call IO.I ' get user input
  618.     Player.Prof=Int(Val(Inpt)) ' convert to number
  619.     If UserRecord.ClassType=Cleric Then ' compare class to cleric
  620.        ' compare valid choices for cleric
  621.        If Player.Prof=1 Or Player.Prof=2 Then
  622.           Exit Do ' exit weapon input loop
  623.        Endif ' end compare valid chocies
  624.     Else ' compare to non cleric
  625.        If Player.Prof>=1 And Player.Prof<=4 Then ' compare valid choices
  626.           Exit Do ' exit weapon input loop
  627.        Endif ' end compare valid choices
  628.     Endif ' end compare class type
  629.  Loop ' end loop to accept weapon proficiency
  630.  UserRecord.Proficiency=Player.Prof ' store character weapon selection
  631.  For Weapon.Number=1 To 4 ' loop through user record weapon proficiencies
  632.     UserRecord.Weapons(Weapon.Number)=False ' reset to zero
  633.  Next ' end loop through weapon proficiencies
  634.  ' set user record selected weapon profciency
  635.  UserRecord.Weapons(Player.Prof)=10
  636. End Sub ' end routine to modify character weapon proficinecy
  637.  
  638.  Rem * routine to initialize character proficiency statistics.
  639.  
  640. Sub Init.Proficiency.Stats
  641.  On Local Error Resume Next ' local error resume
  642.  Graphics.Off=False ' reset color
  643.  Select Case UserRecord.Race ' compare player character race
  644.  Case 3 ' gnome race
  645.     UserRecord.Weapons(UserRecord.Proficiency)=15 ' increment proficiency
  646.     Outpt="Gnomes weapon proficiency is raised to 15%" ' make message
  647.     Call IO.O ' send message
  648.  Case 6 ' half-elf race
  649.     UserRecord.Weapons(4)=UserRecord.Weapons(4)+5 ' increment proficiency
  650.     Outpt="Half-elves thrusting weapon proficiency is raised by 5%" ' message
  651.     Call IO.O ' send message
  652.  Case 7 ' half-orc race
  653.     UserRecord.Weapons(3)=UserRecord.Weapons(3)+5 ' increment proficiency
  654.     Outpt="Half-orcs sharp weapon proficiency is raised by 5%" ' message
  655.     Call IO.O ' send message
  656.  End Select ' end compare race
  657. End Sub ' end routine to initialize proficiency statistics
  658.  
  659.  Rem * routine to initialize character race statistics.
  660.  
  661. Sub Init.Race.Stats
  662.  On Local Error Resume Next ' local error resume
  663.  Graphics.Off=False ' reset color
  664.  Select Case UserRecord.Race ' compare player character race
  665.  Case 1 ' human race
  666.     UserRecord.Stats(1)=UserRecord.Stats(1)+1 ' increment statistics
  667.     Outpt="Humans strength is raised one point!" ' make message
  668.     Call IO.O ' send message
  669.  Case 2 ' elf race
  670.     UserRecord.Stats(4)=UserRecord.Stats(4)+1 ' increment statistics
  671.     Outpt="Elves dexterity is raised by one point!" ' make message
  672.     Call IO.O ' send message
  673.  Case 4 ' dwarf race
  674.     UserRecord.Stats(2)=UserRecord.Stats(2)+1 ' increment statistics
  675.     Outpt="Dwarves intelligence is raised by one point!" ' make message
  676.     Call IO.O ' send message
  677.  Case 5 ' halfling race
  678.     UserRecord.Stats(3)=UserRecord.Stats(3)+1 ' increment statistics
  679.     Outpt="Halflings wisdom is raised by one point!" ' make message
  680.     Call IO.O ' send message
  681.  Case 8 ' ogre race
  682.     UserRecord.Stats(1)=UserRecord.Stats(1)+1 ' increment statistics
  683.     UserRecord.Stats(4)=UserRecord.Stats(4)+1 ' increment statistics
  684.     Outpt="Ogres strength and dexterity are raised by one point!" ' message
  685.     Call IO.O ' send output
  686.  End Select ' end compare race
  687.  UserRecord.Beauty=Int(Rnd*15+5) ' reset ladies beauty
  688.  UserRecord.Glamour=Int(Rnd*15+5) ' reset ladies glamour
  689. End Sub ' end routine to initialize character race statistics
  690.  
  691.  Rem * routine to initialize some character statistics.
  692.  
  693. Sub Init.Stats
  694.  On Local Error Resume Next ' local error resume
  695.  User.Echo=False ' reset preference
  696.  User.LineFeeds=False ' reset preference
  697.  User.LineLength=80 ' reset preference
  698.  User.PageLength=24 ' reset preference
  699.  User.Wordwrap=False ' reset preference
  700.  UserRecord.Room=1 ' reset user record room number
  701.  UserRecord.Level=1 ' reset user record character level
  702.  UserRecord.Experience=64 ' reset experience
  703.  UserRecord.Gold=2048 ' reset user record gold
  704.  UserRecord.Bank=False ' reset user record amount of gold in bank
  705.  UserRecord.Borrow=False ' reset user record amount of gold borrowed from bank
  706.  UserRecord.Brief=False ' reset user record brief mode
  707.  UserRecord.Echo=False ' reset user echo mode
  708.  UserRecord.Linefeeds=False ' reset user linefeed mode
  709.  UserRecord.Linelength=80 ' reset user linelength
  710.  UserRecord.Pagelength=24 ' reset pagelength
  711.  UserRecord.Wordwrap=False ' reset user word wrap
  712.  UserRecord.FatigueMax=Training.Stats(UserRecord.ClassType,1) ' reset user
  713.  UserRecord.VitalityMax=Training.Stats(UserRecord.ClassType,2) ' record maximum
  714.  UserRecord.MagicMax=Training.Stats(UserRecord.ClassType,3) ' statistic
  715.  UserRecord.PsionicMax=Training.Stats(UserRecord.ClassType,4) ' points
  716.  UserRecord.Fatigue=UserRecord.FatigueMax ' reset user
  717.  UserRecord.Vitality=UserRecord.VitalityMax ' record working
  718.  UserRecord.Magic=UserRecord.MagicMax ' statistic
  719.  UserRecord.Psionic=UserRecord.PsionicMax ' points
  720.  UserRecord.MaxCalls=False ' reset user record maximum calls
  721.  UserRecord.FromHour=False ' reset user record time restrictions
  722.  UserRecord.FromMin=False ' reset user record time restrictions
  723.  UserRecord.ToHour=False ' reset user record time restrictions
  724.  UserRecord.ToMin=False ' reset user record time restrictions
  725.  UserRecord.Flags=False ' reset user record flags variable
  726.  Call Clear.Container(0,True) ' routine to clear the container structure
  727.  For Container.Item=1 To 3 ' loop through user record containers
  728.     UserRecord.Container(Container.Item)=ContainerRec ' reset container record
  729.  Next ' end loop through user record
  730. End Sub ' end routine to initialize character statistics
  731.  
  732.  Rem * routine to display login character statistics.
  733.  
  734. Sub Display.Init.Stats
  735.  On Local Error Resume Next ' local error resume
  736.  Graphics.Off=False ' reset color
  737.  Outpt="Your character statistics are:" ' message
  738.  Call IO.O ' send output
  739.  Graphics.Off=True ' reset color
  740.  Outpt="Level:"+Str$(UserRecord.Level) ' message
  741.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  742.  Alignment.Type$=Alignment.Name1(UserRecord.Align1+2) ' message
  743.  Alignment.Type$=Rtrim$(Alignment.Type$) ' trim blanks
  744.  ' first character uppercase
  745.  Mid$(Alignment.Type$,1,1)=Ucase$(Mid$(Alignment.Type$,1,1))
  746.  Outpt=Outpt+"Align1: "+Alignment.Type$ ' combine message
  747.  Call IO.O ' send output
  748.  Outpt="Gold: "+Str$(UserRecord.Gold) ' message
  749.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  750.  Alignment.Type$=Alignment.Name2(UserRecord.Align2+2) ' message
  751.  Alignment.Type$=Rtrim$(Alignment.Type$) ' trim blanks
  752.  ' first character uppercase
  753.  Mid$(Alignment.Type$,1,1)=Ucase$(Mid$(Alignment.Type$,1,1))
  754.  Outpt=Outpt+"Align2: "+Alignment.Type$ ' combine message
  755.  Call IO.O ' send output
  756.  Outpt="Room: "+Str$(UserRecord.Room) ' message
  757.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  758.  Player.Prof=UserRecord.Proficiency ' get statistic
  759.  Weapon.Type$=Weapon.Type.Name(Player.Prof) ' message
  760.  Weapon.Type$=Rtrim$(Weapon.Type$) ' trim blanks
  761.  ' first character uppercase
  762.  Mid$(Weapon.Type$,1,1)=Ucase$(Mid$(Weapon.Type$,1,1))
  763.  Outpt=Outpt+"Prof:   "+Weapon.Type$ ' combine message
  764.  Weapon.Proficiency$=Str$(UserRecord.Weapons(Player.Prof)) ' message
  765.  Outpt=Outpt+">"+Weapon.Proficiency$+"%" ' combine message
  766.  Call IO.O ' send output
  767.  Outpt="Exp:  "+Str$(UserRecord.Experience) ' message
  768.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  769.  Outpt=Outpt+Left$(Stat(1),3)+":   "+Str$(UserRecord.Stats(1)) ' combine
  770.  Call IO.O ' send output
  771.  Outpt="Fat:  "+Str$(UserRecord.Fatigue) ' message
  772.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  773.  Outpt=Outpt+Left$(Stat(2),3)+":   "+Str$(UserRecord.Stats(2)) ' combine
  774.  Call IO.O ' send output
  775.  Outpt="Vit:  "+Str$(UserRecord.Vitality) ' message
  776.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  777.  Outpt=Outpt+Left$(Stat(3),3)+":   "+Str$(UserRecord.Stats(3)) ' combine
  778.  Call IO.O ' send output
  779.  Outpt="Mag:  "+Str$(UserRecord.Magic) ' message
  780.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  781.  Outpt=Outpt+Left$(Stat(4),3)+":   "+Str$(UserRecord.Stats(4)) ' combine
  782.  Call IO.O ' send output
  783.  Outpt="Psi:  "+Str$(UserRecord.Psionic) ' message
  784.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  785.  Outpt=Outpt+Left$(Stat(5),3)+":   "+Str$(UserRecord.Stats(5)) ' combine
  786.  Call IO.O ' send output
  787.  Outpt="Race:  "+Race(UserRecord.Race) ' message
  788.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  789.  Outpt=Outpt+Left$(Stat(6),3)+":   "+Str$(UserRecord.Stats(6)) ' combine
  790.  Call IO.O ' send output
  791.  Class.Type$=UserRecord.ClassName ' message
  792.  Call Decrypt(Class.Type$) ' decrypt string
  793.  ' first character uppercase
  794.  Mid$(Class.Type$,1,1)=Ucase$(Mid$(Class.Type$,1,1))
  795.  Class.Type$=Left$(Class.Type$,15) ' truncate to right
  796.  Outpt="Class: "+Class.Type$ ' message
  797.  Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  798.  Outpt=Outpt+Left$(Stat(7),3)+":   "+Str$(UserRecord.Stats(7)) ' combine
  799.  Call IO.O ' send output
  800.  If UserRecord.ClassType=Lady Then ' compare class to lady
  801.     Outpt="Lady stats:" ' message
  802.     Call IO.O ' send output
  803.     Outpt="Beauty:"+Str$(UserRecord.Beauty) ' message
  804.     Outpt=Outpt+Space$(25-Len(Outpt)) ' append blanks
  805.     Outpt=Outpt+"Glamour:"+Str$(UserRecord.Glamour) ' combine
  806.     Call IO.O ' send output
  807.  Endif ' end compare class type
  808.  Call More.Prompt ' pause to continue
  809. End Sub ' end routine to display character login statistics
  810.  
  811.  Rem * routine to initialize some variables after login.
  812.  Rem * output variables:
  813.  Rem *   Time.Left - player time left in seconds from login time.
  814.  
  815. Sub Update.Login        
  816.  On Local Error Resume Next ' local error resume
  817.  Outpt=UserRecord.DateOn ' get user's last login date
  818.  Call Decrypt(Outpt) ' decrypt date
  819.  If Outpt<>Date$ Then ' compare last login date to today
  820.     UserRecord.NumCalls=False ' reset user's number of calls logged in per day
  821.  Endif ' end compare last login date
  822.  If UserRecord.ClassType<=Lady Then ' compare user to non DM status
  823.     Calls.Exceeded=False ' set flag to maximum calls exceeded
  824.     UserRecord.NumCalls=UserRecord.NumCalls+1 ' increment user's max calls
  825.     If UserRecord.MaxCalls>False Then ' compare maximum calls
  826.        If UserRecord.NumCalls>UserRecord.MaxCalls Then ' compare calls
  827.           Calls.Exceeded=True ' set maximum call flag
  828.        Endif ' end compare calls to maximum calls
  829.     Else ' end compare maximum calls
  830.        If UserRecord.NumCalls>5 Then ' compare maximum calls to default
  831.           Calls.Exceeded=True ' set maximum call flag
  832.        Endif ' end compare maximum default calls
  833.     Endif ' end compare maximum calls
  834.     If Calls.Exceeded Then ' check user has exceeded maximum calls
  835.        Call Share.Record(UserFile,User.Index) ' put user record
  836.        Call Hang.Up(5) ' routine to terminate program w/ message
  837.        Exit Sub ' exit routine
  838.     Endif ' end check maximum calls
  839.  Endif ' end non DM status
  840.  Call Restricted.Login ' check user is restricted to a time to login
  841.  If UserRecord.ClassType<AsstDM Then ' compare user is non DM status
  842.     UserRecord.Invisible=False ' reset user invisibility
  843.  Endif ' end compare non DM status
  844.  Select Case UserRecord.ClassType ' compare the user class type
  845.  Case Is>=AsstDM ' user is DM/Asst. DM
  846.     Time.Left=3600! ' user gets 60 minutes
  847.  Case Else ' user is non DM
  848.     Select Case UserRecord.Level ' select by user level
  849.     Case Is<2 ' user level is less than two
  850.        Time.Left=900! ' user gets 15 mminutes
  851.     Case Else ' user level is two or more
  852.        Time.Left=1800! ' user gets 30 minutes
  853.     End Select ' end user level
  854.  End Select ' end user DM status
  855.  If Time.Left>Door.Time Then ' compare user's time left to door file time left
  856.     If Door.Time>False Then ' compare door file time
  857.        Time.Left=Door.Time ' reset time left to door time left
  858.     Endif ' end compare door file time
  859.  Endif ' end compare user time left
  860.  Two.Minutes.Left=False ' reset two minutes left message flag
  861.  User.Echo=UserRecord.Echo ' store user preference
  862.  User.LineFeeds=UserRecord.LineFeeds ' store user preference
  863.  User.LineLength=UserRecord.LineLength ' store user preference
  864.  User.PageLength=UserRecord.PageLength ' store user preference
  865.  User.Wordwrap=UserRecord.Wordwrap ' store user preference
  866. End Sub ' end routine to initialize some login variables
  867.  
  868.  Rem * routine to check user is restricted to specific login times.
  869.  Rem * work variables:
  870.  Rem *   Restrict.Start! - time in seconds to restrict logon.
  871.  Rem *   Restrict.End! - time in seconds to restrict logon.
  872.  
  873. Sub Restricted.Login
  874.  On Local Error Resume Next ' local error resume
  875.  ' calculate time restrictions
  876.  Restrict.Start!=Csng(UserRecord.FromHour*3600!+UserRecord.FromMin*60!)
  877.  Restrict.End!=Csng(UserRecord.ToHour*3600!+UserRecord.ToMin*60!)
  878.  ' compare any time restriction
  879.  If Restrict.Start!>False Or Restrict.End!>False Then
  880.     If Timer<Restrict.Start! Or Timer>Restrict.End! Then ' compare time to now
  881.        Call Hang.Up(6) ' routine to terminate program w/ message
  882.     Endif ' end compare time
  883.  Endif ' end compare time restriction
  884. End Sub ' end routine to check restricted time login
  885.  
  886.  Rem * routine to intialize some new user variables in user file record.
  887.  
  888. Sub Init.Newuser
  889.  On Local Error Resume Next ' local error resume
  890.  UserRecord.NumCalls=False ' reset maximum calls made today
  891.  UserRecord.ClassType=False ' reset class type
  892.  Outpt=Player.CodeName ' store codename
  893.  Call Valid(Outpt,30) ' validate codename
  894.  Call Encrypt(Outpt,True) ' encrypt codename
  895.  UserRecord.CodeName=Outpt ' restore codename
  896.  Outpt=Player.PassWord ' store password
  897.  Call Valid(Outpt,20) ' validate password
  898.  Call Encrypt(Outpt,False) ' encrypt password
  899.  UserRecord.PassWord=Outpt ' restore password
  900.  Outpt=Deleted$ ' set deleted
  901.  Call Valid(Outpt,20) ' validate deleted
  902.  Call Encrypt(Outpt,True) ' encrypt deleted
  903.  UserRecord.ClassName=Outpt ' reset classname
  904.  Outpt=Date$ ' store current date
  905.  Call Valid(Outpt,10) ' validate date
  906.  Call Encrypt(Outpt,True) ' encrypt date
  907.  UserRecord.DateOn=Outpt ' reset date
  908.  UserRecord.MaxCalls=False ' reset maximum calls made
  909.  UserRecord.FromHour=False ' reset time restrictions
  910.  UserRecord.FromMin=False
  911.  UserRecord.ToHour=False
  912.  UserRecord.ToMin=False
  913. End Sub ' end routine to intialize new user variables
  914.  
  915.  Rem * routine to initialize some user variables.
  916.  
  917. Sub Login.User
  918.  On Local Error Resume Next ' local error resume
  919.  Number.Monsters=False ' counter of monsters currently in the room
  920.  Monsters.Killed=False ' counter of monster killed by player during session
  921.  ' allocate room monster arrays
  922.  Redim MonsterArray(1 To 20) As MonsterType, _
  923.  MonsterIndex(1 To 20) As Integer
  924.  Max.Spells=Lof(SpellFile)/Len(SpellRecord) ' compute number of spells in file
  925.  If Max.Spells=False Then ' compare empty file
  926.     Max.Spells=1 ' set number to at least one
  927.     Call Share.Record(SpellFile,1) ' put default spell record
  928.  Endif ' end compare file
  929.  ' check bounds of spell file
  930.  If Max.Spells>1024 Then ' check bounds
  931.     Max.Spells=1024 ' reste maximum
  932.  Endif ' end check bounds
  933.  ' make string of zeros length of spell file
  934.  Learned.Spells=String$(Max.Spells,"0")
  935.  If UserRecord.Race<=False Then ' check user race
  936.     UserRecord.Race=1 ' reset to one
  937.  Endif ' end check race
  938.  Call Share.Record(UserFile,User.Index) ' put the user record
  939.  Room=UserRecord.Room ' store the room number
  940.  If UserRecord.Level=False Then ' check user level
  941.     Outpt="You are level zero. You can use the train command once free."
  942.     Call IO.O ' send output message
  943.  Endif ' end compare level
  944.  Call Bank.Interest ' calculate bank interest for balance and loan
  945.  Call Check.Mail ' routine to display number of new messages to player
  946.  Weapon1=False ' reset working game weapon, shield, armor, and ring variables
  947.  Weapon2=False ' reset variable
  948.  Weapon3=False ' reset variable
  949.  Weapon4=False ' reset variable
  950.  Weapon5=False ' reset variable
  951.  Weapon6=False ' reset variable
  952.  Weapon7=False ' reset variable
  953.  Weapon8=False ' reset variable
  954.  Weapon9=False ' reset variable
  955.  Weapon10=False ' reset variable
  956.  Call Get.User.Record ' read the user record
  957.  Call Status.Line(1) ' initialize the console status lines
  958.  Func.Buffer=Nul ' reset function key buffer
  959. End Sub ' end routine to initialize some user variables
  960.  
  961.  Rem * routine to display treasure item.
  962.  Rem * input variables:
  963.  Rem *   Index.Number - treasure record number.
  964.  Rem *   Type.Number - room/inventory flag.
  965.  
  966. Sub Show.Treasure
  967.  On Local Error Resume Next ' local error resume
  968.  If Type.Number Then ' compare treasure in room
  969.     Prefix1="It's " ' format prefix
  970.  Else ' compare treasure in player inventory
  971.     Prefix1="You are carrying " ' format prefix
  972.  Endif ' end compare treasure
  973.  Graphics.Off=True ' reset color
  974.  If TreasureRecord.Scroll Then ' compare treasure to scroll
  975.     If TreasureRecord.Spell Then ' check scroll spell number
  976.        Call Read.Record(SpellFile,TreasureRecord.Spell) ' get spell record
  977.        Inpt=SpellRecord.Chant ' store spell chant
  978.        Inpt=Rtrim$(Inpt) ' trim chant
  979.        Inpt=Lcase$(Inpt) ' trim chant
  980.        Outpt="It reads: '"+Inpt+"'." ' display scroll chant
  981.        Call IO.O ' send message
  982.        Outpt="It disintegrated!" ' scroll vanished message
  983.        Call IO.O ' send output
  984.        If Type.Number=False Then ' compare treasure in room
  985.           ' remove scroll from inventory
  986.           Call Discard.Inventory(Array.Number,True)
  987.        Else ' compare treasure
  988.           Call Discard.Room.Treasure(Array.Number) ' remove scroll from room
  989.        Endif ' end compare treasure
  990.     Endif ' end compare scroll spell number
  991.     Exit Sub ' exit routine
  992.  Endif ' end compare treasure is scroll
  993.  Outpt=Prefix1+Outpts ' format treasure name description
  994.  If TreasureRecord.Keyed Then ' append key number to treasure name
  995.     Outpt=Outpt+"(#"+Right$(Str$(TreasureRecord.Keyed+100000!),5)+")"
  996.  Endif ' end compare treasure key number
  997.  If TreasureRecord.Plus Then ' append plus number to treasure name
  998.     Outpt=Outpt+"(+"+Mid$(Str$(Abs(TreasureRecord.Plus)),2)+")"
  999.  Endif ' end compare treasure plus
  1000.  If TreasureRecord.Spell Then ' append spell plus to treasure name
  1001.     Call Read.Record(SpellFile,TreasureRecord.Spell) ' get spell record
  1002.     Outpt=Outpt+"(+"+Mid$(Str$(SpellRecord.Level),2)+")"
  1003.  Endif ' end compare treasure spell plus
  1004.  If TreasureRecord.LightType Then ' compare treasure to a light
  1005.     If Charges.Number<False Then ' check treasure is also lit
  1006.        Outpt=Outpt+"[lit]" ' append to treasure name
  1007.     Endif ' end check lit treasure
  1008.  Endif ' end compare treasure to light
  1009.  If TreasureRecord.Invisible Then ' compare treasure is invisible
  1010.     Outpt=Outpt+"[inv]" ' append to treasure name
  1011.  Else ' compare treasure
  1012.     If Type.Number=1 Then ' check treasure is in room
  1013.        ' verify treasure in
  1014.        If RoomRecord.Flags(Array.Number)=Hidden.Object Then
  1015.           Outpt=Outpt+"[inv]" ' room is invisible, append to name
  1016.        Endif ' end verify treasure in room was hidden
  1017.     Endif ' end check treasure in room
  1018.  Endif ' end compare treasure is invisible
  1019.  Call IO.O ' display treasure name message
  1020.  If TreasureRecord.Proficiency Then ' compare treasure proficiency
  1021.     Outpt=Weapon.Type.Name(TreasureRecord.Proficiency) ' get proficiency
  1022.     Outpt=Rtrim$(Outpt) ' name and trim
  1023.     Outpt="This is a "+Outpt+" weapon." ' make weapon type message
  1024.     Call IO.O ' display weapon type message
  1025.  Endif ' end compare treasure proficiency
  1026.  If Last.Command.Number=Identify.Command Then ' check identify command used
  1027.     Outpt="It's worth"+Str$(TreasureRecord.Gold)+" gold peices."
  1028.     Call IO.O ' display treasure item gold value
  1029.     Outpt="It weighs"+Str$(TreasureRecord.Weight)+" pounds."
  1030.     Call IO.O ' display weight of item
  1031.     If TreasureRecord.RingType Then ' compare treasure ring type
  1032.        Select Case TreasureRecord.RingType ' determine ring type
  1033.        Case 1 ' ring type
  1034.           Outpt="protection from poison." ' ring type message
  1035.        Case 2 ' ring type
  1036.           Outpt="protection from level drain." ' ring type message
  1037.        Case 3 ' ring type
  1038.           Outpt="protection from spells." ' ring type message
  1039.        End Select ' end dtermine ring type
  1040.        Outpt="Its ring spell is "+Outpt ' make ring type message
  1041.        Call IO.O ' send ring type message
  1042.     Endif ' end compare treasure to ring
  1043.     If TreasureRecord.Spell Then ' compare treasure spell type
  1044.        Call Read.Record(SpellFile,TreasureRecord.Spell) ' get treasure spell
  1045.        Outpt="Its magical spell is "+Rtrim$(SpellRecord.SpellName)+"."
  1046.        Call IO.O ' display name of treasure spell
  1047.     Endif ' end compare treasure spell type
  1048.     ' compare treasure is loaded
  1049.     If TreasureRecord.Loadable Or TreasureRecord.Launchable Then
  1050.        If Charges.Number<=False Then ' compare treasure charges
  1051.           Outpt="It's not loaded." ' display message
  1052.        Else ' compare treasure charges
  1053.           Outpt="It's loaded with"+Str$(Charges.Number)+" charges." ' message
  1054.        Endif ' end compare loaded treasure charges
  1055.        Call IO.O ' send message of charges in loaded treasure
  1056.     Else ' compare treasure item
  1057.        If TreasureRecord.LightType Then ' compare treasure is a light
  1058.           If Charges.Number<False Then ' compare light charges (is negative)
  1059.              Outpt="It's fueled with"+Str$(Abs(Charges.Number))+" charges."
  1060.              Call IO.O ' send message of charges in light
  1061.           Endif ' end compare light charges
  1062.        Else ' compare other treasure plus
  1063.           If TreasureRecord.RingType Or TreasureRecord.Spell Or _
  1064.           TreasureRecord.Plus Then ' treasure has charges
  1065.              If Charges.Number<=False Then ' compare charges
  1066.                 Outpt="It's empty of charges." ' message
  1067.              Else ' compare charges
  1068.                 ' message of charges
  1069.                 Outpt="It has"+Str$(Charges.Number)+" charges."
  1070.              Endif ' end compare charges
  1071.              Call IO.O ' send message of charges
  1072.           Endif ' end compare treasure charges
  1073.        Endif ' end compare treasure plus
  1074.     Endif ' end compare treasure
  1075.     ' compare treasure is ammunition
  1076.     If TreasureRecord.Ammunition Or TreasureRecord.LaunchAmmo Then
  1077.        Outpt="It's ammunition." ' treasure nessage
  1078.        Call IO.O ' send message
  1079.     Endif ' end compare treasure
  1080.     If TreasureRecord.Potion Then ' compare treasure to potion
  1081.        Outpt="It's a potion." ' make message
  1082.        Call IO.O ' send message
  1083.     Endif ' end compare to potion
  1084.     If TreasureRecord.Edible Then ' compare treasure to food
  1085.        Outpt="It's edible." ' make message
  1086.        Call IO.O ' send message
  1087.     Endif ' end compare to food
  1088.  Endif ' end identify command
  1089.  Graphics.Off=False ' reset color
  1090. End Sub ' end routine to display an itemof treasure
  1091.  
  1092.  Rem * routine to display object information.
  1093.  Rem * input variables:
  1094.  Rem *   Index.Number - object record number.
  1095.  Rem *   Type.Number - object is in room/inventory.
  1096.  
  1097. Sub Show.Object
  1098.  On Local Error Resume Next ' local error resume
  1099.  If Type.Number Then ' determine object in room
  1100.     Prefix1="It's " ' make prefix
  1101.  Else ' object in inventory
  1102.     Prefix1="You are carrying " ' make prefix
  1103.  Endif ' end determine in room
  1104.  Graphics.Off=True ' reset color
  1105.  Outpt=Prefix1+Outpts ' make message with object name
  1106.  If ObjectRecord.DoorLock>1 Then ' compare object is locked
  1107.     Outpt=Outpt+"[locked]" ' append to object name
  1108.  Endif ' end compare locked object
  1109.  If ObjectRecord.DoorLock=1 Then ' compare object is unlocked
  1110.     If ObjectRecord.Closed Then ' compare object is closed
  1111.        Outpt=Outpt+"[closed]" ' append to object name
  1112.     Endif ' end compare closed object
  1113.  Endif ' end compare object lock
  1114.  If ObjectRecord.Invisible Then ' compare object is invisible
  1115.     Outpt=Outpt+"[inv]" ' append to object name
  1116.  Endif ' end compare object invisible
  1117.  If ObjectRecord.Keyed Then ' compare object key, append number to name
  1118.     Outpt=Outpt+"(#"+Right$(Str$(ObjectRecord.Keyed+100000!),5)+")"
  1119.  Endif ' end compare object key number
  1120.  Call IO.O ' display message with object name
  1121.  Outpt=ObjectRecord.LongDesc ' store object additional description
  1122.  Outpt=Rtrim$(Outpt) ' trim description
  1123.  If Outpt<>Nul Then ' compare length of description
  1124.     Call IO.O ' display additional object description
  1125.  Endif ' end compare object description length
  1126.  Graphics.Off=False ' reset color
  1127. End Sub ' end routine to display object information
  1128.  
  1129.  Rem * routine to display information on a monster.
  1130.  Rem * input variables:
  1131.  Rem *   Monster.Number - number of monster array.
  1132.  
  1133. Sub Show.Monster
  1134.  On Local Error Resume Next ' local error resume
  1135.  Graphics.Off=True ' reset color
  1136.  Call The.Or.An ' routine for monster name prefix (a, an, the)
  1137.  Level=MonsterArray(Monster.Number).Level ' store monster level
  1138.  Outpt="It's "+Prefix1+Outpts ' make message of monster name
  1139.  ' append monster level (range of player's level capable to kill monster)
  1140.  Outpt=Outpt+"(level"+Str$((Level-1)*2+1)+" to"+Str$(Level*2)+")"
  1141.  Call IO.O ' send message with monster name and level range
  1142.  If Last.Command.Number=Identify.Command Then ' compare identify command
  1143.     Gold.Points#=MonsterArray(Monster.Number).Gold ' store monster gold
  1144.     If Gold.Points#<=False Then ' compare monster gold
  1145.        Gold.Points#=10 ' set to minimum
  1146.     Endif ' end compare monster gold
  1147.     Outpt="It has"+Str$(MonsterArray(Monster.Number).Hits)+" hits,"+ _
  1148.     Str$(MonsterArray(Monster.Number).Experience)+" experience, and"+ _
  1149.     Str$(Gold.Points#)+" gold."
  1150.     Call IO.O ' display message of monster gold
  1151.     Outpt="It carries the following treasure:" ' make message
  1152.     Call IO.O ' send message of treasure carried by monster
  1153.     Inventory.Count=False ' reset number of monster inventory items displayed
  1154.     For Array.Count=1 To 5 ' loop through all monster inventory
  1155.        ' get treasure
  1156.        Treasure.Number=MonsterArray(Monster.Number).Treasure(Array.Count)
  1157.        ' number and check range in treasure file
  1158.        If Treasure.Number>False And _
  1159.           Treasure.Number<=Lof(TreasureFile)/Len(TreasureRecord) Then
  1160.           Carriage.Return=True ' flag to disable return/linefeed
  1161.           Call IO.O ' send output of previous item
  1162.           Call Read.Record(TreasureFile,Treasure.Number) 'get treasure record
  1163.           Outpts=TreasureRecord.TreasureName ' store treasure name
  1164.           Outpt=Rtrim$(Outpts)+", " ' trim name, append comma
  1165.           Inventory.Count=Inventory.Count+1 ' increment items displayed flag
  1166.           If Inventory.Count=1 Then ' compare item to first displayed
  1167.              Mid$(Outpt,1,1)=Ucase$(Mid$(Outpt,1,1)) ' uppercase first item
  1168.           Endif ' end compare first item
  1169.        Endif ' end check treasure file range
  1170.     Next ' end loop through monster inventory
  1171.     If Inventory.Count=False Then ' check if any items displayed
  1172.        Outpt="Nothing at all." ' make message for none
  1173.     Else ' check items displayed
  1174.        Outpt=Left$(Outpt,Len(Outpt)-2)+"." ' trim comma, append period
  1175.        If Inventory.Count>1 Then ' check more than one item displayed
  1176.           Outpt="and "+Outpt ' append to last item
  1177.        Endif ' end check items
  1178.     Endif ' end check item
  1179.     Call IO.O ' send output for last item
  1180.     ' compare monster spell ability
  1181.     Spell.Number=MonsterArray(Monster.Number).Spell
  1182.     ' check spell
  1183.     If Spell.Number>False And _
  1184.     Spell.Number<=Lof(SpellFile)/Len(SpellRecord) Then
  1185.        Call Read.Record(SpellFile,Spell.Number) ' range and get spell record
  1186.        Outpt="It can cast "+Rtrim$(SpellRecord.SpellName)+" spells!"
  1187.        Call IO.O ' send message of spell name monster can cast
  1188.     Endif ' end compare monster spell
  1189.     If MonsterArray(Monster.Number).Poison Then ' compare monster poisonous
  1190.        Outpt="It can poison!" ' make message
  1191.        Call IO.O ' send output message
  1192.     Endif ' end compare monster poisonous
  1193.     If MonsterArray(Monster.Number).LevelDrain Then ' compare monster undead
  1194.        Outpt="It can drain levels!" ' make message
  1195.        Call IO.O ' send output message
  1196.     Endif ' end compare monster undead
  1197.     If MonsterArray(Monster.Number).Psionic Then ' compare monster astral
  1198.        Outpt="It can cast psi spells!" ' make message
  1199.        Call IO.O ' send output message
  1200.     Endif ' end compare monster astral
  1201.  Endif ' end check identify command used
  1202.  Graphics.Off=False ' reset color
  1203. End Sub ' end routine to display monster information
  1204.  
  1205.  Rem * routine to determine validity of room number.
  1206.  Rem * input variables:
  1207.  Rem *   Room - contains room number to check.
  1208.  
  1209. Sub Check.Next.Room
  1210.  On Local Error Resume Next ' local error resume
  1211.  Do ' loop until room is valid, room is created, or nondescriptive hangup
  1212.     If Room>False And _
  1213.     Room<=Lof(RoomFile)/Len(RoomRecord) Then ' check room range
  1214.        Call Read.Room.Record(Room) ' valid range, get room record
  1215.        Exit Sub ' exit routine
  1216.     Endif ' end check valid range
  1217.     If Room>Lof(RoomFile)/Len(RoomRecord) Then ' compare room number range
  1218.        If Not Normal.User Then ' check non DM status
  1219.           Call Add.Room(False,Room.Created) ' routine to create new room
  1220.           If Room.Created Then ' return variable indicates new room created
  1221.              Exit Sub ' exit routine
  1222.           Endif ' end create new room
  1223.        Endif ' end check normal user
  1224.     Endif ' end compare room number range
  1225.     ' otherwise, any room number out of range will be changed to room 1, or
  1226.     ' changed to the resurrection room number.
  1227.     If Lof(RoomFile)/Len(RoomRecord)>=1 Then ' check for room
  1228.        Graphics.Off=False ' reset color
  1229.        Outpt="Nondescriptive room number"+Str$(Room)+"!" ' make error message
  1230.        Call IO.O ' display room number error message
  1231.        Room=1 ' reset room number to resurrection room, continue loop
  1232.     Else ' room file is invalid, room file length is zero
  1233.        Graphics.Off=False ' reset color
  1234.        Room=1 ' reset room number
  1235.        Call Clear.Room(1) ' add first room
  1236.        Exit Sub ' exit routine
  1237.     Endif ' end check room file length
  1238.  Loop ' end loop until valid room number
  1239. End Sub ' end routine to check room number validity
  1240.  
  1241.  Rem * routine to initialize some room variables, check next room number, and
  1242.  Rem * display next room description.
  1243.  Rem * input variables:
  1244.  Rem *   Room - room number to move to.
  1245.  Rem * output variables:
  1246.  Rem *   Room.Rust.Rate - number of prompts to check weapon rusting.
  1247.  Rem *   Room.Steal.Rate - number of prompts to check monster stealing.
  1248.  Rem *   Room.Monster.Rate - number of prompts to check monster encounter.
  1249.  Rem *   Room.Health.Rate - number of prompts to check health increases.
  1250.  
  1251. Sub Display.Room
  1252.  On Local Error Resume Next ' local error resume
  1253.  Call Check.Next.Room ' routine to verify next room number
  1254.  Room.Rust.Rate=False ' store room rust rate
  1255.  Room.Steal.Rate=False ' store room steal rate
  1256.  Room.Monster.Rate=6 ' store default room encounter rate
  1257.  Room.Health.Rate=6 ' store default room health rate
  1258.  Room.Action=RoomRecord.Action
  1259.  If Room.Action>False And Room.Action<=Lof(ActionFile)/Len(ActionRecord) Then
  1260.     Call Read.Record(ActionFile,Room.Action)
  1261.     If ActionRecord.RustRate>False Then ' check room record action rust rate
  1262.        Room.Rust.Rate=ActionRecord.RustRate ' store room rust rate
  1263.     Endif ' end check action
  1264.     If ActionRecord.StealRate>False Then ' check room record action steal rate
  1265.        Room.Steal.Rate=ActionRecord.StealRate ' store room steal rate
  1266.     Endif ' end check action
  1267.     ' check room record action encounter rate
  1268.     If ActionRecord.EncounterRate Then
  1269.        ' store action encounter rate
  1270.        Room.Monster.Rate=ActionRecord.EncounterRate
  1271.     Endif ' end check action
  1272.     If ActionRecord.HealthRate Then ' check room record action health rate
  1273.        Room.Health.Rate=ActionRecord.HealthRate ' store action health rate
  1274.     Endif ' end check action
  1275.  Endif
  1276.  Call Show.Room ' routine to display room
  1277. End Sub ' end routine to process next room
  1278.  
  1279.  Rem * routine to determine if a room is unlit.
  1280.  Rem * return variables:
  1281.  Rem *   Lit.Room - true if room is unlit.
  1282.  
  1283. Sub Check.Lit.Room(Lit.Room)
  1284.  On Local Error Resume Next ' local error resume
  1285.  Lit.Room=False ' room is lit by default
  1286.  Call Read.Room.Record(Room) ' get room record
  1287.  Action.Number=RoomRecord.Action ' store action number
  1288.  ' check action number
  1289.  If Action.Number<1 Or Action.Number>Lof(ActionFile)/Len(ActionRecord) Then
  1290.     Lit.Room=False ' room is lit
  1291.     Exit Sub ' exit lit check routine
  1292.  Endif ' end check action number
  1293.  Call Read.Record(ActionFile,Action.Number) ' get action record number
  1294.  If ActionRecord.Attribute1=LitRoom Then ' compare lit flag
  1295.     Lit.Room=False ' room is lit
  1296.     Exit Sub ' exit check lit routine
  1297.  Endif ' end check lit flag
  1298.  Lit.Room=True ' flag for unlit room
  1299.  For Array.Index=1 To 20 ' loop through all user inventory
  1300.     Treasure.Number=UserRecord.Inv(Array.Index) ' get inventory number
  1301.     If Treasure.Number Then ' compare user treasure number
  1302.        Call Read.Record(TreasureFile,Treasure.Number) ' get treasure record
  1303.        If TreasureRecord.LightType Then ' check treasure item is a light
  1304.           ' check light is charged/lit
  1305.           If UserRecord.Charges(Array.Index)<False Then
  1306.              Lit.Room=False ' set flag for lit room
  1307.              Exit Sub ' exit routine
  1308.           Endif ' end check charged light
  1309.        Endif ' end check treasure is a light
  1310.     Endif ' end compare treasure number
  1311.  Next ' end loop through user inventory
  1312.  For Array.Index=1 To 20 ' loop through all treasure in room
  1313.     ' get room treasure number
  1314.     Treasure.Number=RoomRecord.Treasure(Array.Index)
  1315.     If Treasure.Number Then ' compare treasure number
  1316.        Call Read.Record(TreasureFile,Treasure.Number) ' get treasure record
  1317.        If TreasureRecord.LightType Then ' compare treasure is a light
  1318.           ' compare light is charged
  1319.           If RoomRecord.TreCharges(Array.Index)<False Then
  1320.              Lit.Room=False ' set flag for lit room
  1321.              Exit Sub ' exit routine
  1322.           Endif ' end compare charged light
  1323.        Endif ' end compare treasure is a light
  1324.     Endif ' end compare treasure number
  1325.  Next ' end loop through room treasure
  1326.  For Array.Index=1 To 20 ' loop through all room objects
  1327.     If RoomRecord.Object(Array.Index) Then ' compare room object number
  1328.        Call Read.Record(ObjectFile,RoomRecord.Object(Array.Index)) 'get record
  1329.        If ObjectRecord.LightRoom Then ' check object is a light
  1330.           If ObjectRecord.LightTime=False Then ' object lights at any time
  1331.              Lit.Room=False ' set flag for lit room
  1332.              Exit Sub ' exit routine
  1333.           Else ' light has light time restriction
  1334.              ' calculate seconds light from/to
  1335.              Start.Time!=Csng(ObjectRecord.FromHour*3600!+ _
  1336.              ObjectRecord.FromMin*60!)
  1337.              End.Time!=Csng(ObjectRecord.ToHour*3600!+ObjectRecord.ToMin*60!)
  1338.              ' check valid light time
  1339.              If Start.Time!>False Or End.Time!>False Then
  1340.                 ' compare times
  1341.                 If Timer>=Start.Time! And Timer<=End.Time! Then
  1342.                    Lit.Room=False ' set room lit flag
  1343.                    Exit Sub ' exit routine
  1344.                 Endif ' end compare times
  1345.              Endif ' end check valid light time
  1346.           Endif ' end check object light type
  1347.        Endif ' end check object is a light
  1348.     Endif ' end compare object number
  1349.  Next ' end loop through room objects
  1350.  For Array.Index=1 To 5 ' loop through all user object inventory
  1351.     If UserRecord.Object(Array.Index) Then ' compare user object number
  1352.        Call Read.Record(ObjectFile,UserRecord.Object(Array.Index)) 'get object
  1353.        If ObjectRecord.LightRoom Then ' compare object is a light
  1354.           If ObjectRecord.LightTime=False Then ' check object lights any time
  1355.              Lit.Room=False ' set flag for lit room
  1356.              Exit Sub ' exit routine
  1357.           Else ' compare object light time restriction
  1358.              ' calculate seconds light from/to
  1359.              Start.Time!=Csng(ObjectRecord.FromHour*3600!+ _
  1360.              ObjectRecord.FromMin*60!)
  1361.              End.Time!=Csng(ObjectRecord.ToHour*3600!+ObjectRecord.ToMin*60!)
  1362.              ' check valid light time
  1363.              If Start.Time!>False Or End.Time!>False Then
  1364.                 ' compare times
  1365.                 If Timer>=Start.Time! And Timer<=End.Time! Then
  1366.                    Lit.Room=False ' set lit room flag
  1367.                    Exit Sub ' exit routine
  1368.                 Endif ' end compare times
  1369.              Endif ' end check valid light times
  1370.           Endif ' end compare object light type
  1371.        Endif ' end compare object is a light
  1372.     Endif ' end compare object number
  1373.  Next ' end loop through user objects
  1374. End Sub ' end routine to determine lit room
  1375.  
  1376.  Rem * routine to display all the player character statistics.
  1377.  
  1378. Sub Display.Stats
  1379.  On Local Error Resume Next ' local error resume
  1380.  Graphics.Off=True ' reset color
  1381.  Outpt=UserRecord.CodeName ' get user codename
  1382.  Call Decrypt(Outpt) ' decrypt codename
  1383.  Outpt=Rtrim$(Outpt) ' trim codename
  1384.  Outpt=Lcase$(Outpt) ' set codename to lowercase
  1385.  Mid$(Outpt,1,1)=Ucase$(Mid$(Outpt,1,1)) ' uppercase first letter
  1386.  Outpt="Information: "+Outpt+". "+FNclock$+"." ' make information message
  1387.  Call IO.O ' send message
  1388.  Call Show.Align ' routine to display player alignment
  1389.  Call More.Prompt ' pause display
  1390.  If No Then ' check more prompt response
  1391.     Exit Sub ' exit info display
  1392.  Endif ' end check more prompt
  1393.  Call Show.Health ' routine to display player statistics
  1394.  Call More.Prompt ' pause display
  1395.  If No Then ' check more prompt response
  1396.     Exit Sub ' exit info display
  1397.  Endif ' end check more prompt
  1398.  Call Display.Info ' routine to display additional player information
  1399.  Call More.Prompt ' pause display
  1400.  If No Then ' check more prompt response
  1401.     Exit Sub ' exit info display
  1402.  Endif ' end check more prompt
  1403.  Call Display.Inventory ' routine to display player inventory
  1404.  Call More.Prompt ' pause display
  1405.  If No Then ' check more prompt response
  1406.     Exit Sub ' exit info display
  1407.  Endif ' end check more prompt
  1408.  Call Display.Experience ' routine to display player experience and gold
  1409.  Call More.Prompt ' pause display
  1410.  If No Then ' check more prompt response
  1411.     Exit Sub ' exit info display
  1412.  Endif ' end check more prompt
  1413. End Sub ' end routine to display all player character statistics
  1414.  
  1415.  Rem * routine to display player character experience, and gold.
  1416.  Rem * routine notes:
  1417.  Rem *    although gold and experience required to reach the next level double
  1418.  Rem *    each player level, the experience and gold required for players over
  1419.  Rem *    level 10 only increase by 10,000 points per level over 10.
  1420.  
  1421. Sub Display.Experience
  1422.  On Local Error Resume Next ' local error resume
  1423.  Graphics.Off=True ' reset color
  1424.  Outpt="You have "+FNform$(UserRecord.Gold)+" gold and "+ _
  1425.  FNform$(UserRecord.Experience)+" experience." ' make gold/experience message
  1426.  Call IO.O ' send output message
  1427.  Level=UserRecord.Level ' store player level
  1428.  If Level>False And Level<MaxInt Then ' compare level maximum
  1429.     Level=Level+1 ' increment next level needed
  1430.     ' routine to calculate gold required for next level
  1431.     Call Gold(Gold.Required#)
  1432.     Call Experience(Exp.Required#) ' routine to calculate experience needed
  1433.     Outpt="You need "+FNform$(Gold.Required#)+" gold and "+ _
  1434.     FNform$(Exp.Required#)+" experience to reach level"+Str$(Level)+"."
  1435.     Call IO.O ' send output message
  1436.  Else ' compare level
  1437.     Outpt="There is no experience or gold at your level."
  1438.     Call IO.O
  1439.  Endif ' end compare level
  1440. End Sub
  1441.  
  1442.  Rem * routine to display player characteristics, and weapons, shields, armor,
  1443.  Rem * and rings being held/worn.
  1444.  
  1445. Sub Display.Info
  1446.  On Local Error Resume Next ' local error resume
  1447.  Graphics.Off=True ' reset color
  1448.  If Sysop Then ' verify user is a sysop
  1449.     Outpt="You are a Sysop!" ' make message
  1450.     Call IO.O ' send message
  1451.  Endif ' end verify sysop
  1452.  If Dungeon.Master Then ' verify user is a DM
  1453.     Outpt="You are a Dungeon Master!" ' make message
  1454.     Call IO.O ' send message
  1455.  Endif ' end verify DM
  1456.  If Dungeon.Master.Assistant Then ' verify user is an Asst. DM
  1457.     Outpt="You are an Assistant Dungeon Master!" ' make message
  1458.     Call IO.O ' send message
  1459.  Endif ' end verify Asst. DM
  1460.  If Town.Mayor Then ' verify user is the mayor
  1461.     Outpt="You are the Town Mayor!" ' make message
  1462.     Call IO.O ' send message
  1463.  Endif ' end verify mayor
  1464.  If Governor Then ' verify user is governor
  1465.     Outpt="You are the Governor!" ' make message
  1466.     Call IO.O ' send message
  1467.  Endif ' end verify governor
  1468.  If Guild.Master Then ' verify user is guild master
  1469.     Outpt="You are the Guild Master!" ' make message
  1470.     Call IO.O ' send message
  1471.  Endif ' end verify guild master
  1472.  If UserRecord.Invisible Or Invisible Then ' check invisibility
  1473.     Outpt="You are invisible!" ' make message
  1474.     Call IO.O ' send message
  1475.  Endif ' end check invisibility
  1476.  If UserRecord.Poison Then ' check poisoned
  1477.     Outpt="You are poisoned!" ' make message
  1478.     Call IO.O ' send message
  1479.  Endif ' end check poisoned
  1480.  If Weapon1=False Then ' check wearing armor
  1481.     If Weapon7=False Then ' check wearing ring
  1482.        Outpt="You are wearing nothing." ' make message
  1483.        Call IO.O ' send message
  1484.     Endif ' end check ring
  1485.  Endif ' end check armor
  1486.  If Weapon2=False Then ' check holding weapon
  1487.     If Weapon3=False Then ' check holding shield
  1488.        Outpt="You are holding nothing." ' make message
  1489.        Call IO.O ' send message
  1490.     Endif ' end check shield
  1491.  Endif ' end check weapon
  1492.  Outpt=Nul ' clear display string
  1493.  If Weapon1 Or Weapon7 Then ' check either armor or ring being worn
  1494.     Outpt="You are wearing " ' initialize display string
  1495.     If Weapon1 Then ' check armor being worn
  1496.        Call Read.Record(TreasureFile,Abs(UserRecord.Inv(Weapon4))) ' get armor
  1497.        Outpt=Outpt+Rtrim$(TreasureRecord.TreasureName) ' record, append name
  1498.     Endif ' end check armor worn
  1499.  Endif ' end check either being worn
  1500.  If Weapon7 Then ' check ring being worn
  1501.     Call Read.Record(TreasureFile,Abs(UserRecord.Inv(Weapon7))) 'ring treasure
  1502.     If Weapon1 Then ' check armor worn again
  1503.        Outpt=Outpt+" and "+Rtrim$(TreasureRecord.TreasureName)+"." ' append
  1504.        Call IO.O ' both items being worn
  1505.     Else ' armor not worn
  1506.        Outpt="You are wearing "+Rtrim$(TreasureRecord.TreasureName)+"."
  1507.        Call IO.O ' display only ring being worn
  1508.     Endif ' end check armor worn
  1509.  Else ' end check ring worn
  1510.     If Weapon1 Then ' check armor worn, ring not
  1511.        Outpt=Outpt+"." ' append period
  1512.        Call IO.O ' display only armor worn
  1513.     Endif ' end check armor, ring
  1514.  Endif ' end check ring worn
  1515.  Outpt=Nul ' clear display string
  1516.  If Weapon2 Or Weapon3 Then ' check either weapon or shield being held
  1517.     Outpt="You are holding " ' initialize display string
  1518.     If Weapon2 Then ' check weapon being held
  1519.        Call Read.Record(TreasureFile,Abs(UserRecord.Inv(Weapon6))) 'get weapon
  1520.        Outpt=Outpt+Rtrim$(TreasureRecord.TreasureName) ' record, append name
  1521.     Endif ' end check weapon held
  1522.  Endif ' end check either being held
  1523.  If Weapon3 Then ' check shield being held
  1524.     Call Read.Record(TreasureFile,Abs(UserRecord.Inv(Weapon5))) 'shield record
  1525.     If Weapon2 Then ' check weapon held again
  1526.        Outpt=Outpt+" and "+Rtrim$(TreasureRecord.TreasureName)+"." ' append
  1527.        Call IO.O ' both items being held
  1528.     Else ' weapon not held
  1529.        Outpt="You are holding "+Rtrim$(TreasureRecord.TreasureName)+"."
  1530.        Call IO.O ' display only shield being held
  1531.     Endif ' end check weapon held
  1532.  Else ' end check shield held
  1533.     If Weapon2 Then ' check weapon held, not shield
  1534.        Outpt=Outpt+"." ' append period
  1535.        Call IO.O ' display only weapon held
  1536.     Endif ' end check weapon, shield
  1537.  Endif ' end check shield held
  1538. End Sub ' end routine to display player characteristics
  1539.  
  1540.  Rem * routine to display player character alignment and health statistics.
  1541.  
  1542. Sub Display.Health
  1543.  On Local Error Resume Next ' local error resume
  1544.  Graphics.Off=True ' reset color
  1545.  Call Show.Align ' routine to display alignment
  1546.  Call Show.Health ' routine to display health statistics
  1547. End Sub ' end routine to display alignment/health
  1548.  
  1549.  Rem * routine to display health statistics, and weapon, shield, armor plus.
  1550.  
  1551. Sub Show.Health
  1552.  On Local Error Resume Next ' local error resume
  1553.  Graphics.Off=True ' reset color
  1554.  ' display vital health statistics in percentage form 
  1555.  Outpt="Vitals: " ' make output message
  1556.  Var1#=Cdbl(UserRecord.FatigueMax) ' calculate total hits
  1557.  Var1#=Var1#+Cdbl(+UserRecord.VitalityMax) ' calculate total hits
  1558.  Var2#=Cdbl(UserRecord.Fatigue) ' calculate hits remaining
  1559.  Var2#=Var2#+Cdbl(+UserRecord.Vitality) ' calculate hits remaining
  1560.  Outpt=Outpt+"Body" ' append health message
  1561.  If Var1#=0# Then ' check divide by zero
  1562.     Temp#=0# ' reset health hits
  1563.  Else ' check divide
  1564.     Temp#=((Var2#/Var1#)*.40#)*100# ' compute health percentage
  1565.     Temp#=Int(Temp#) ' compute health integer
  1566.     If Temp#<1.0# Then ' check percentage
  1567.        Temp#=1.0# ' reset percentage
  1568.     Endif ' end check percentage
  1569.  Endif ' end check divide by zero
  1570.  If Temp#<0# Then ' check overflow
  1571.     Temp#=0# ' reset percentage
  1572.  Endif ' end ceck overflow
  1573.  Outpt=Outpt+Str$(Temp#)+"%" ' append health percentage
  1574.  Outpt=Outpt+" Arms" ' append health message
  1575.  If Var1#=0# Then ' check divide by zero
  1576.     Temp#=0# ' reset health hits
  1577.  Else ' check divide
  1578.     Temp#=((Var2#/Var1#)*.25#)*100# ' compute health percentage
  1579.     Temp#=Int(Temp#)
  1580.     If Temp#<1.0# Then ' check percentage
  1581.        Temp#=1.0# ' reset percentage
  1582.     Endif ' end check percentage
  1583.  Endif ' end check divide by zero
  1584.  If Temp#<0# Then ' check overflow
  1585.     Temp#=0# ' reset percentage
  1586.  Endif ' end ceck overflow
  1587.  Outpt=Outpt+Str$(Temp#)+"%" ' append health percentage
  1588.  Outpt=Outpt+" Legs" ' append health message
  1589.  If Var1#=0# Then ' check divide by zero
  1590.     Temp#=0# ' reset health hits
  1591.  Else ' check divide
  1592.     Temp#=((Var2#/Var1#)*.25#)*100# ' compute health percentage
  1593.     Temp#=Int(Temp#)
  1594.     If Temp#<1.0# Then ' check percentage
  1595.        Temp#=1.0# ' reset percentage
  1596.     Endif ' end check percentage
  1597.  Endif ' end check divide by zero
  1598.  If Temp#<0# Then ' check overflow
  1599.     Temp#=0# ' reset percentage
  1600.  Endif ' end ceck overflow
  1601.  Outpt=Outpt+Str$(Temp#)+"%" ' append health percentage
  1602.  Outpt=Outpt+" Head" ' append health message
  1603.  If Var1#=0# Then ' check divide by zero
  1604.     Temp#=0# ' reset health hits
  1605.  Else ' check divide
  1606.     Temp#=((Var2#/Var1#)*.10#)*100# ' cmpute health percentage
  1607.     Temp#=Int(Temp#)
  1608.     If Temp#<1.0# Then ' check percentage
  1609.        Temp#=1.0# ' reset percentage
  1610.     Endif ' end check percentage
  1611.  Endif ' end check divide by zero
  1612.  If Temp#<0# Then ' check overflow
  1613.     Temp#=0# ' reset percentage
  1614.  Endif ' end ceck overflow
  1615.  Outpt=Outpt+Str$(Temp#)+"%" ' append health percentage
  1616.  Call IO.O ' send output
  1617.  ' health statistics line one contains vitals in form:
  1618.  ' Vitals: Fat 10/10(+10) Vit 10/10 Mag 10/10 Psi 10/10
  1619.  If Weapon1 Or Weapon3 Then ' check armor, shield
  1620.     ' add pluses to message
  1621.     Weapon.Plus$="(+"+Mid$(Str$(Weapon1+Weapon3),2)+")"
  1622.  Else ' neither armor, shield
  1623.     Weapon.Plus$=Nul ' clear plusses message
  1624.  Endif ' end check armor, shield
  1625.  Outpt="Vital hits:" ' initialize health one line
  1626.  ' append current fatigue and maximum fatigue
  1627.  Outpt=Outpt+" Fat" ' append stat name
  1628.  Outpt=Outpt+Str$(UserRecord.Fatigue)+"/"+Mid$(Str$(UserRecord.FatigueMax),2)
  1629.  Outpt=Outpt+Weapon.Plus$ ' append plusses message
  1630.  ' append current vitality and maximum vitality
  1631.  Outpt=Outpt+" Vit" ' append stat name
  1632.  Outpt=Outpt+Str$(UserRecord.Vitality)+"/"+Mid$(Str$(UserRecord.VitalityMax),2)
  1633.  ' append current magic points and maximum magic points
  1634.  Outpt=Outpt+" Mag" ' append stat name
  1635.  Outpt=Outpt+Str$(UserRecord.Magic)+"/"+Mid$(Str$(UserRecord.MagicMax),2)
  1636.  ' append current psionic points and maximum psionic points
  1637.  Outpt=Outpt+" Psi" ' append stat name
  1638.  Outpt=Outpt+Str$(UserRecord.Psionic)+"/"+Mid$(Str$(UserRecord.PsionicMax),2)
  1639.  Call IO.O ' display vitals message line
  1640.  ' health statistics line two contains vitals in form:
  1641.  ' Stats: Str 10(+10) Int 10 Wis 10 Dex 10 Con 10 Pie 10 Cha 10
  1642.  Outpt="Stats: " ' initialize vitals message
  1643.  For Array.Index=1 To 7 ' loop through all health statistics
  1644.     ' append first three letters of statistics name and player statistic value
  1645.     Outpt=Outpt+Left$(Stat(Array.Index),3)+Str$(UserRecord.Stats(Array.Index))
  1646.     If Array.Index=1 Then ' check strength selected
  1647.        If Weapon2 Then ' verify weapon being held
  1648.           Outpt=Outpt+"(+"+Mid$(Str$(Weapon2),2)+")" ' append weapon plus
  1649.        Endif ' end check weapon
  1650.     Endif ' end check strength
  1651.     Outpt=Outpt+" " ' append one space
  1652.  Next ' end loop through health statistics
  1653.  Call IO.O ' display vitals message line
  1654.  ' health statistics line three contains vitals in form:
  1655.  ' Weapons: Blunt> 0% Pole> 0% Sharp> 10% Thrusting> 0%
  1656.  Outpt="Weapons: " ' initialize vitals message
  1657.  For Weapon.Number=1 To 4 ' loop through all weapon classes
  1658.     Weapon$=Rtrim$(Weapon.Type.Name(Weapon.Number)) ' make weapon name
  1659.     Mid$(Weapon$,1,1)=Ucase$(Mid$(Weapon$,1,1)) ' make weapon name
  1660.     Outpt=Outpt+Weapon$ ' append weapon class name 
  1661.     ' append player weapon class percentage value
  1662.     Outpt=Outpt+Str$(UserRecord.Weapons(Weapon.Number))+"% "
  1663.  Next ' loop through weapon classes
  1664.  Call IO.O ' display vitals message line
  1665.  ' display lady statistics
  1666.  If UserRecord.ClassType=Lady Then ' compare user class type to lady
  1667.     ' make message for lady statistics
  1668.     Outpt="Lady stats: Beauty "+Str$(UserRecord.Beauty) ' append beauty value
  1669.     Outpt=Outpt+" Glamour "+Str$(UserRecord.Glamour) ' append glamour value
  1670.     Call IO.O ' send lady statistics message
  1671.  Endif ' end compare user class type
  1672. End Sub ' end routine to display health statistics
  1673.  
  1674.  Rem * routine to display player character alignment.
  1675.  
  1676. Sub Show.Align
  1677.  On Local Error Resume Next ' local error resume
  1678.  Graphics.Off=True ' reset color
  1679.  If UserRecord.Level<=False Then ' check user level
  1680.     Outpt="You are dead!" ' make user level message
  1681.     Call IO.O ' send output message
  1682.     Exit Sub ' exit routine
  1683.  Endif ' end check user level
  1684.  Outpt="You are a level"+Str$(UserRecord.Level) ' make user level message
  1685.  If UserRecord.Race<=False Then ' check valid user race
  1686.     UserRecord.Race=1 ' reset user race
  1687.  Endif ' end check valid user race
  1688.  Outpt=Outpt+" "+Rtrim$(Race(UserRecord.Race))+" " ' append user race name
  1689.  Inpt=UserRecord.ClassName ' store user class name
  1690.  Call Decrypt(Inpt) ' decrypt class name
  1691.  Outpt=Outpt+Inpt ' append classname
  1692.  Call IO.O ' send user type message
  1693.  Outpt="You are aligned " ' make aligned message
  1694.  ' append player alignment type name 1 through 3 (-1,0,1 plus 2) number 1
  1695.  Outpt=Outpt+Rtrim$(Alignment.Name1(UserRecord.Align1+2))+" "
  1696.  ' append player alignment type name 1 through 3 (-1,0,1 plus 2) number 2
  1697.  Outpt=Outpt+Rtrim$(Alignment.Name2(UserRecord.Align2+2))+"."
  1698.  Call IO.O ' send player alignment message
  1699. End Sub ' end routine to display player character alignment
  1700.  
  1701.  Rem * DM routine to display status of system.
  1702.  
  1703. Sub Display.Memory
  1704.  On Local Error Resume Next ' local error resume
  1705.  Graphics.Off=False ' reset color
  1706.  Outpt="Dnddoor Author: "+Author$ ' get author name
  1707.  Call IO.O ' display author name string
  1708.  Call System.Type ' get system type
  1709.  Graphics.Off=True ' reset color
  1710.  Outpt="This System: "+Outpt
  1711.  Call IO.O ' display system status message
  1712.  Call Free.Disk.Space ' get free disk space
  1713.  Outpt="Free disk space: "+Outpt+"."
  1714.  Call IO.O ' display system status message
  1715.  ' make message with stack memory
  1716.  Outpt="Free Stack Space: "
  1717.  Outpt=Outpt+Format$(Fre(-2),"#,##0;;")+" B."
  1718.  Call IO.O ' display message
  1719.  ' make message with far memory
  1720.  Outpt="Free String Space: "
  1721.  Outpt=Outpt+Format$(Fre("a"),"#,##0;;")+" B."
  1722.  Call IO.O ' display message
  1723.  If Share.Installed Then
  1724.     Outpt="Share installed."
  1725.     Call IO.O
  1726.  Endif
  1727. End Sub ' end DM routine to display system memory
  1728.  
  1729.  Rem * routine returns operating system type in Outpt.
  1730.  
  1731. '--------D-2130-------------------------------
  1732. 'INT 21 - DOS 2+ - GET DOS VERSION
  1733. '        AH = 30h
  1734. '---DOS 5+ ---
  1735. '        AL = what to return in BH
  1736. '            00h OEM number (as for DOS 2.0-4.0x)
  1737. '            01h version flag
  1738. 'Return: AL = major version number (00h if DOS 1.x)
  1739. '        AH = minor version number
  1740. '        BL:CX = 24-bit user serial number (most versions do not use this)
  1741. 'Notes:  the OS/2 v1.x Compatibility Box returns major version 0Ah (10)
  1742. '        the OS/2 v2.x Compatibility Box returns major version 14h (20)
  1743. '        the Windows/NT DOS box returns version 5.00, subject to SETVER
  1744.  
  1745. '--------W-2F160A-----------------------------
  1746. 'INT 2F - MS Windows 3.1 - IDENTIFY WINDOWS VERSION AND TYPE
  1747. '        AX = 160Ah
  1748. 'Return: AX = 0000h if call supported
  1749. '            BX = version (BH=major, BL=minor)
  1750. '            CX = mode (0002h = standard, 0003h = enhanced)
  1751.  
  1752. Sub System.Type
  1753.  On Local Error Resume Next ' local error resume
  1754.  Inregs.AX=&H2B01 ' setup for dos function call
  1755.  Inregs.CX=&H4445 ' desqview operating
  1756.  Inregs.DX=&H5351 '  parameters
  1757.  Call Interrupt(&H21,Inregs,Outregs) ' call dos function
  1758.  If (Outregs.AX And &HFF)<>&HFF Then ' check system type
  1759.     Outpt="Desqview." ' make display message
  1760.     Exit Sub ' exit from routine
  1761.  Endif ' end check system type
  1762.  Inregs.AX=&HE400 ' setup for dos function call
  1763.  Call Interrupt(&H21,Inregs,Outregs) ' call dos function
  1764.  If (Outregs.AX And &HFF)>&H00 Then ' check system type
  1765.     Outpt="DoubleDos." ' make display message
  1766.     Exit Sub ' exit from routine
  1767.  Endif ' end check system type
  1768.  Inregs.AX=&H3001 ' setup for dos function call
  1769.  Call Interrupt(&H21,Inregs,Outregs) ' call dos function
  1770.  DOS.Major=Outregs.AX And &HFF ' store low order bytes
  1771.  DOS.Minor=(Outregs.AX And &HFF00)/256 ' store high order bytes
  1772.  Inregs.AX=&H160A ' setup for dos function call
  1773.  Call Interrupt(&H2F,Inregs,Outregs) ' call dos function
  1774.  If Outregs.AX=False Then ' check windows installed
  1775.     Win.Minor=Outregs.BX And &HFF ' get windows version low byte 
  1776.     Win.Major=(Outregs.BX And &HFF00)/256 ' get windows version high byte
  1777.     If Win.Major=4 Then ' verify windows
  1778.        If Win.Minor=10 Then ' verify windows type
  1779.           Outpt="Windows 98." ' make display message
  1780.        Else ' check type
  1781.           Outpt="Windows 95." ' make display message
  1782.        Endif ' end check windows type
  1783.     Else ' check windows version
  1784.        ' store windows 3.x version
  1785.        Outpt="Windows"+Str$(Win.Major)+"."+Ltrim$(Str$(Win.Minor))
  1786.     Endif ' end check windows type
  1787.  Else ' check other versions
  1788.     Select Case DOS.Major ' check os/2 version
  1789.     Case 10 ' check os/2
  1790.        Outpt="OS/2 v1.0" ' store os/2 version
  1791.     Case 20 ' check os/2
  1792.        If DOS.Minor=30 Then ' check os/2 minor
  1793.           Outpt="OS/2 v3.0" ' store os/2 version
  1794.        Else ' check os/2 minor
  1795.           Outpt="OS/2 v2.0" ' store os/2 version
  1796.        Endif ' end check os/2 minor
  1797.     Case Else ' remaining version must be dos
  1798.        ' store dos version
  1799.        Outpt="DOS"+Str$(DOS.Major)+"."+Mid$(Str$(DOS.Minor),2)
  1800.     End Select ' end check version
  1801.  Endif ' end check any version
  1802. End Sub ' end routine
  1803.  
  1804.  Rem * routine returns free disk space in Outpt.
  1805.  Rem * processing variables:
  1806.  Rem *   Struc - returns FAT32 free disk space information.
  1807.  Rem *   ASCIZ - stores current drive letter.
  1808.  Rem *   Fat32.Flag - true if fat32 disk space calculated.
  1809.  
  1810. 'INT 2F - MS Windows 3.1 - IDENTIFY WINDOWS VERSION AND TYPE
  1811. '        AX = 160Ah
  1812. 'Return: AX = 0000h if call supported
  1813. '            BX = version (BH=major, BL=minor)
  1814. '            CX = mode (0002h = standard, 0003h = enhanced)
  1815.  
  1816. 'INT 21 - DOS 2+ - GET FREE DISK SPACE
  1817. '        AH = 36h
  1818. '        DL = drive number (00h = default, 01h = A:, etc)
  1819. 'Return: AX = FFFFh if invalid drive
  1820. '        else
  1821. '            AX = sectors per cluster
  1822. '            BX = number of free clusters
  1823. '            CX = bytes per sector
  1824. '            DX = total clusters on drive
  1825. 'Notes:  free space on drive in bytes is AX * BX * CX
  1826. '        total space on drive in bytes is AX * CX * DX
  1827.  
  1828. 'INT 21 - Windows95 - FAT32 - GET EXTENDED FREE SPACE ON DRIVE
  1829. '        AX = 7303h
  1830. '        DS:DX -> ASCIZ string for drive ("C:\" or "\\SERVER\Share")
  1831. '        ES:DI -> buffer for extended free space structure (see #01789)
  1832. '        CX = length of buffer for extended free space
  1833. 'Return: CF clear if successful
  1834. '            ES:DI buffer filled
  1835. '        CF set on error
  1836. '            AX = error code
  1837. '        on DOS versions which do not support the FAT32 calls, this function
  1838. '          returns CF clear/AL=00h (which is the DOS v1+ method for reporting
  1839. '          unimplemented functions)
  1840. 'Format of extended free space structure: (returned in Struc):
  1841. 'Offset  Size    Description     (Table 01789)
  1842. ' 00h    WORD    (ret) size of returned structure
  1843. ' 02h    WORD    (call) structure version (0000h)
  1844. '                (ret) actual structure version (0000h)
  1845. ' 04h    DWORD   number of sectors per cluster (with adjustment for compression)
  1846. ' 08h    DWORD   number of bytes per sector
  1847. ' 0Ch    DWORD   number of available clusters
  1848. ' 10h    DWORD   total number of clusters on the drive
  1849. ' 14h    DWORD   number of physical sectors available on the drive, without
  1850. '                  adjustment for compression
  1851. ' 18h    DWORD   total number of physical sectors on the drive, without
  1852. '                  adjustment for compression
  1853. ' 1Ch    DWORD   number of available allocation units, without adjustment
  1854. '                  for compression
  1855. ' 20h    DWORD   total allocation units, without adjustment for compression
  1856. ' 24h  8 BYTEs   reserved
  1857.  
  1858. Sub Free.Disk.Space
  1859.  On Local Error Resume Next ' local error resume
  1860.  Dim Struc As String*44, ASCIZ As String*4 ' fat32 structure strings
  1861.  Inregs.AX=&H3600 ' setup for dos function call
  1862.  Inregs.DX=&H0000 ' setup for dos function call
  1863.  Call Interrupt(&H21,Inregs,Outregs) ' call dos function
  1864.  If Outregs.AX=&HFFFF Then ' check error status
  1865.     Outpt="<n/a>" ' make unknown message
  1866.     Exit Sub ' exit routine
  1867.  Endif ' end check error status
  1868.  ' check windows
  1869.  Inregs.AX=&H160A ' store function data
  1870.  Call Interrupt(&H2F,Inregs,Outregs) ' call dos function
  1871.  Fat32.Flag=False ' reset disk space flag
  1872.  If Outregs.AX=False Then ' check return error status
  1873.     TempD$=Left$(Curdir$,1) ' get default drive letter
  1874.     ASCIZ=TempD$+":\"+CHR$(0) ' store drive letter
  1875.     Inregs.AX=&H7303 ' dos function for fat32
  1876.     Inregs.DS=VARSEG(ASCIZ) ' pointer to drive variable
  1877.     Inregs.DX=VARPTR(ASCIZ) ' pointer to drive variable
  1878.     Inregs.ES=VARSEG(Struc) ' pointer to fat32 structure string
  1879.     Inregs.DI=VARPTR(Struc) ' pointer to fat32 structure string
  1880.     Inregs.CX=44 ' length of string
  1881.     Call Interrupt(&H21,Inregs,Outregs) ' dos functino call
  1882.     ' check for fat32
  1883.     If (Outregs.Flags And &H1)=&H0 THEN ' test error status
  1884.        If (Outregs.AX And &HFF)>0 THEN ' test error status
  1885.           ' get disk space beyond 2 GB.
  1886.           Bytes#=Clng(Asc(Mid$(Struc,9,1)))
  1887.           Bytes#=Bytes#+Clng(Asc(Mid$(Struc,10,1)))*256#
  1888.           Bytes#=Bytes#+Clng(Asc(Mid$(Struc,11,1)))*65536#
  1889.           Bytes#=Bytes#+Clng(Asc(Mid$(Struc,12,1)))*16777216#
  1890.           Sectors#=ClnG(Asc(Mid$(Struc,21,1)))
  1891.           Sectors#=Sectors#+Clng(Asc(Mid$(Struc,22,1)))*256#
  1892.           Sectors#=Sectors#+Clng(Asc(Mid$(Struc,23,1)))*65536#
  1893.           Sectors#=Sectors#+Clng(Asc(Mid$(Struc,24,1)))*16777216#
  1894.           Disk.Space#=Bytes#*Sectors# ' store fat32 free disk space
  1895.           Fat32.Flag=True ' set disk space flag
  1896.        Endif
  1897.     Endif
  1898.  Endif
  1899.  If Fat32.Flag=False Then ' check fat32 flag
  1900.     Inregs.AX=&H3600 ' setup for dos function call
  1901.     Inregs.DX=&H0000 ' setup for dos function call
  1902.     Call Interrupt(&H21,Inregs,Outregs) ' call dos function
  1903.     If Outregs.AX<False Then ' check high bit integer wrap
  1904.        Sectors#=Cdbl(Outregs.AX+65536) ' increment off twos-complement bit
  1905.     Else ' check high bit
  1906.        Sectors#=Cdbl(Outregs.AX) ' store sectors
  1907.     Endif ' end check high bit
  1908.     If Outregs.BX<False Then ' check high bit integer wrap
  1909.        Clusters#=Cdbl(Outregs.BX+65536) ' increment off twos-complement bit
  1910.     Else ' check high bit
  1911.        Clusters#=Cdbl(Outregs.BX) ' store clusters
  1912.     Endif ' end check high bit
  1913.     If Outregs.CX<False Then ' check high bit integer wrap
  1914.        Bytes#=Cdbl(Outregs.CX+65536) ' increment off twos-complement bit
  1915.     Else ' check high bit
  1916.        Bytes#=Cdbl(Outregs.CX) ' stores bytes 
  1917.     Endif ' end check high bit
  1918.     Disk.Space#=Sectors#*Clusters#*Bytes# ' calculate actual free disk space
  1919.  Endif ' end check fat32 flag
  1920.  Byte.Counter=False ' reset kilo counter
  1921.  ' loop until disk space is an even kilo type
  1922.  Do ' start division loop
  1923.     If Disk.Space#>=1024 Then ' compare disk space to one kilobyte
  1924.        Disk.Space#=Disk.Space#/1024 ' integer divide disk space
  1925.        Byte.Counter=Byte.Counter+1 ' increment kilo type counter
  1926.        If Byte.Counter=4 Then ' check kilos greater than a terabyte
  1927.           Exit Do ' exit if too large
  1928.        Endif ' end check terabyte
  1929.     Else ' check smallest division
  1930.        Exit Do ' exit if division is smallest
  1931.     Endif ' end check kilobyte
  1932.  Loop ' end division loop
  1933.  Outpt=Format$(Disk.Space#,"#,##0.00;;") ' format the disk space 
  1934.  Select Case Byte.Counter ' determine the kilo type
  1935.  Case 0 ' byte case
  1936.     Outpt=Outpt+" B" ' append size
  1937.  Case 1 ' kilobyte case
  1938.     Outpt=Outpt+" KB" ' append size
  1939.  Case 2 ' megabyte case
  1940.     Outpt=Outpt+" MB" ' append size
  1941.  Case 3 ' gigabyte case
  1942.     Outpt=Outpt+" GB" ' append size
  1943.  Case 4 ' terabyte case
  1944.     Outpt=Outpt+" TB" ' append size
  1945.  End Select ' end determine the kilo type
  1946. End Sub ' end routine
  1947.  
  1948.  Rem * routine to display extended information on an object, treasure,
  1949.  Rem * monster, or container using the identify command.
  1950.  
  1951. Sub Identify.Object
  1952.  On Local Error Resume Next ' local error resume
  1953.  If Normal.User Then ' check non DM status
  1954.     If UserRecord.Level<=4 Then ' check player level
  1955.        Outpt="You are not high enough level!" ' make message
  1956.        Call IO.O ' send message
  1957.        Exit Sub ' exit routine
  1958.     Endif ' end check level
  1959.  Endif ' end check DM status
  1960.  Call Display.Information ' routine to display information on an item
  1961. End Sub ' end identify routine
  1962.  
  1963.  Rem * routine to display current time, user's time on, and user's time left.
  1964.  Rem * input variables:
  1965.  Rem *   Time.On - containing the user time on in system time format hh:mm:ss.
  1966.  Rem *   Time.Left - containing the user's time limit in seconds from login.
  1967.  Rem * processing variables:
  1968.  Rem *   OnTime# - contains serial number format of time calculations.
  1969.  Rem *   Hours - contains hours since login.
  1970.  Rem *   Minutes - contains minutes since login.
  1971.  Rem *   Seconds - contains seconds since login.
  1972.  
  1973. Sub Time.Online 
  1974.  On Local Error Resume Next ' local error resume
  1975.  Graphics.Off=True ' reset color
  1976.  Outpt="It is now "+FNclock$+"." ' make display message
  1977.  Call IO.O ' send output message
  1978.  OnTime#=TimeValue(Time$)-TimeValue(Time.On) ' calculate time online
  1979.  If OnTime#<False Then ' check past midnight
  1980.     OnTime#=OnTime#+TimeValue("12:00:00")*2 ' add 24 hours (86,400 seconds)
  1981.  Endif ' end check past midnight
  1982.  Outpt="You have been on for" ' format time display message
  1983.  Time.DIsplay$=Nul ' time display message
  1984.  Gosub Time.Display ' subroutine to display message
  1985.  Hours=Int(Time.Left/3600!) ' calculate hours of time limit
  1986.  Time.Calc=Time.Left-Hours*3600! ' calculate time minus hours
  1987.  Minutes=Int(Time.Calc/60!) ' calculate minutes of time limit
  1988.  Seconds=Time.Calc-Minutes*60! ' calculate seconds of time limit
  1989.  OnTime#=TimeSerial(Hours,Minutes,Seconds)-OnTime# ' calculate time remaining
  1990.  Outpt="You have" ' format time display message
  1991.  Time.Display$=" remaining" ' time display message
  1992.  Gosub Time.Display ' subroutine to display message
  1993.  Exit Sub ' exit routine
  1994.  
  1995.  ' subroutine to display time message
  1996. Time.Display:
  1997.  If Hour(OnTime#)>0 Then ' compare hours of serial time variable
  1998.     Outpt=Outpt+Str$(Hour(OnTime#))+" hours," ' append hours to string
  1999.  Endif ' end compare hours
  2000.  If Minute(OnTime#)>0 Then ' compare minutes of serial time variable
  2001.     Outpt=Outpt+Str$(Minute(OnTime#))+" minutes," ' append minutes to string
  2002.  Endif ' end compare minutes
  2003.  If Second(OnTime#)>0 Then ' compare seconds of serial time variable
  2004.     Outpt=Outpt+Str$(Second(OnTime#))+" seconds," ' append seconds to string
  2005.  Endif ' end compare seconds
  2006.  Outpt=Left$(Outpt,Len(Outpt)-1) ' trim trailing comma
  2007.  Outpt=Outpt+Time.DIsplay$+"." ' combine message
  2008.  Call IO.O ' send output message
  2009.  Return ' exit time display subroutine
  2010. End Sub ' end routine to display time on
  2011.  
  2012.  Rem * routine to display list of weapons for sale, the first 15 items in the
  2013.  Rem * treasure file.
  2014.  
  2015. Sub Weapon.List
  2016.  On Local Error Resume Next ' local error resume
  2017.  Graphics.Off=False ' reset color
  2018.  Outpt="The Blacksmith says: Here's a list of my inventory." ' message
  2019.  Call IO.O ' send output message
  2020.  Graphics.Off=True ' reset color
  2021.  Outpt="To purchase, enter number to buy, for example: Buy 15." ' make message
  2022.  Call IO.O ' send output message
  2023.  Graphics.Off=False ' reset color
  2024.  Outpt="Number Weapon                        Weight Plus   Gold" ' make output
  2025.  Call IO.O ' send output message
  2026.  Allow.Break=True ' allow control-k breaking
  2027.  Break=False ' reset control-k flag
  2028.  Graphics.Off=True ' reset color
  2029.  For List.Count=1 To 20 ' loop through the first 20 treasure items
  2030.     Call Read.Record(TreasureFile,List.Count) ' get the next treasure record
  2031.     Item.Weight=TreasureRecord.Weight ' store the treasure item weight
  2032.     Gold.Value#=TreasureRecord.Gold ' store the treasure item gold value
  2033.     ' store the treasure name
  2034.     WeaponList.Output$=TreasureRecord.TreasureName
  2035.     ' set first character uppercase
  2036.     Mid$(WeaponList.Output$,1,1)=Ucase$(Mid$(WeaponList.Output$,1,1))
  2037.     Weapon.Plus=False ' reset plus
  2038.     If TreasureRecord.Spell Then ' compare item to spell
  2039.        Call Read.Record(SpellFile,TreasureRecord.Spell) ' get spell record
  2040.        Weapon.Plus=SpellRecord.Level ' store spell level of item
  2041.     Else ' end compare spell item
  2042.        If TreasureRecord.Plus Then ' compare treasure item plus
  2043.           Weapon.Plus=Abs(TreasureRecord.Plus) ' store item plus
  2044.        Endif ' end compare treasure item plus
  2045.     Endif ' end compare item spell plus
  2046.     ' combine the treasure weight, gold value, and name with blanks imbedded
  2047.     Outpt=Mid$(Str$(List.Count),2) ' append item value
  2048.     Outpt=Outpt+Space$(8-Len(Str$(List.Count))) ' pad blanks
  2049.     Outpt=Outpt+WeaponList.Output$ ' append item value
  2050.     Outpt=Outpt+Space$(21-Len(WeaponList.Output$)) ' pad blanks
  2051.     Outpt=Outpt+Mid$(Str$(Item.Weight),2) ' append item value
  2052.     Outpt=Outpt+Space$(8-Len(Str$(Item.Weight))) ' pad blanks
  2053.     Outpt=Outpt+Mid$(Str$(Weapon.Plus),2) ' append item value
  2054.     Outpt=Outpt+Space$(8-Len(Str$(Weapon.Plus))) ' pad blanks
  2055.     Outpt=Outpt+Mid$(Str$(Gold.Value#),2) ' append item value
  2056.     Call IO.O ' send message output
  2057.     If Break Then ' check break
  2058.        Exit For ' exit treasure file loop
  2059.     Endif ' end compare break
  2060.  Next ' end treasure file item display loop
  2061.  Allow.Break=False ' reset control-k breaking
  2062.  If Break Then ' check control-k flag
  2063.     Break=False ' reset control-k flag
  2064.     Outpt=Nul ' set output to null
  2065.     Call IO.O ' send empty return
  2066.  Endif ' end check control-k flag
  2067. End Sub ' end routine to list treasure items for sale
  2068.  
  2069.  Rem * routine to allow user to change password.
  2070.  
  2071. Sub Change.PassWord
  2072.  On Local Error Resume Next ' local error resume
  2073.  Graphics.Off=True ' reset color
  2074.  Outpt="Change your password(y/n)? " ' input prompt
  2075.  No.Input.Out="N" ' default input
  2076.  Call IO.I ' get user input
  2077.  If Yes Then ' compare input
  2078.     Outpt="Type in old password for verification:" ' input prompt
  2079.     Line.Length=20 ' line length for password
  2080.     Hidden=True ' echo mask characters
  2081.     Call IO.I ' get user input
  2082.     Hidden=False ' reset echo mask flag
  2083.     Inpt=Ltrim$(Inpt) ' trim entry password
  2084.     Inpt=Rtrim$(Inpt) ' trim entry password
  2085.     Inpt=Ucase$(Inpt) ' set entry password to uppercase
  2086.     Outpt=UserRecord.PassWord ' get user's current password
  2087.     Call Decrypt(Outpt) ' decrypt user password
  2088.     If Outpt=Nul Then ' verify password validity
  2089.        Outpt="This password has a checksum error!" ' make error message
  2090.        Call IO.O ' send output message
  2091.        Exit Sub ' exit routine
  2092.     Endif ' end compare password validity
  2093.     Outpt=Rtrim$(Outpt) ' trim password
  2094.     If Outpt<>Inpt Then ' compare entered password to user password
  2095.        Outpt="Passwords don't match!" ' make error message
  2096.        Call IO.O ' send output message
  2097.        Exit Sub ' exit routine
  2098.     Endif ' end compare passwords
  2099.     Outpt="Type in new password(20 char. max.)" ' format input message
  2100.     Call IO.O ' send output message
  2101.     Line.Length=20 ' set line length of new password
  2102.     Outpt="?" ' set input prompt
  2103.     Hidden=True ' set echo mask character flag
  2104.     Call IO.I ' get user input
  2105.     Hidden=False ' reset echo mask flag
  2106.     If No.Input Then ' check length of input
  2107.        Outpt="Password not changed." ' make error message
  2108.        Call IO.O ' send output message
  2109.        Exit Sub ' exit routine
  2110.     Endif ' end compare length of input
  2111.     Inpt=Ltrim$(Inpt) ' trim new password
  2112.     Inpt=Rtrim$(Inpt) ' trim new password
  2113.     Inpt=Ucase$(Inpt) ' convert to uppercase
  2114.     Call Valid(Inpt,20) ' check validity of new password
  2115.     If Inpt=Nul Then ' compare validity of new password
  2116.        Outpt="Illegal characters in password!" ' make error message
  2117.        Call IO.O ' send output message
  2118.        Exit Sub ' exit routine
  2119.     Endif ' end compare password validity
  2120.     Call Encrypt(Inpt,False) ' encrypt new password
  2121.     UserRecord.PassWord=Inpt ' store new password in user record
  2122.     Outpt="Password changed." ' make message
  2123.     Call IO.O ' send output message
  2124.     Exit Sub ' exit routine
  2125.  Endif ' end compare input
  2126.  Outpt="Password not changed." ' make message
  2127.  Call IO.O ' send output message
  2128. End Sub ' end routine to change password
  2129.  
  2130.  Rem * routine to change alignment once per player character.
  2131.  
  2132. Sub Align
  2133.  On Local Error Resume Next ' local error resume
  2134.  If Normal.User Then ' compare to non DM
  2135.     If UserRecord.Flags And Alignmented Then ' compare user record flag
  2136.        Outpt="You've already changed alignment once!" ' message
  2137.        Call IO.O ' send output
  2138.        Exit Sub ' exit routine
  2139.     Endif ' end compare user record flag
  2140.  Endif ' end compare normal user
  2141.  Outpt="Change alignment(y/n)? " ' input prompt
  2142.  No.Input.Out="Y" ' default input
  2143.  Call IO.I ' get user input
  2144.  If Yes Then ' compare yes entered
  2145.     UserRecord.Flags=UserRecord.Flags Or Alignmented ' set user record flag
  2146.     Call Modify.Alignment ' routine to change alignment
  2147.     Outpt="Alignment is now " ' message with new alignment
  2148.     Outpt=Outpt+Rtrim$(Alignment.Name1(UserRecord.Align1+2))+" " ' message
  2149.     Outpt=Outpt+Rtrim$(Alignment.Name2(UserRecord.Align2+2)) ' message
  2150.     Call IO.O ' send message
  2151.     Exit Sub ' exit routine
  2152.  Endif ' end compare input
  2153.  Outpt="Alignment not changed!" ' make output message
  2154.  Call IO.O ' send output message
  2155. End Sub ' end routine to change alignment
  2156.  
  2157.  Rem * routine to allow user to change all statistics once per character.
  2158.  
  2159. Sub Reroll.Character
  2160.  On Local Error Resume Next ' local error resume
  2161.  If Normal.User Then ' compare to non DM
  2162.     If UserRecord.Flags And Rerolled Then ' check user record flag
  2163.        Outpt="You've already rerolled your character!" ' message
  2164.        Call IO.O ' send output
  2165.        Exit Sub ' exit routine
  2166.     Endif ' end compare user flag
  2167.  Endif ' end compare normal user
  2168.  Outpt="Reroll character(y/n)? " ' prompt user to reroll
  2169.  No.Input.Out="Y" ' set default input
  2170.  Call IO.I ' get user input
  2171.  If Yes Then ' compare yes entered
  2172.     UserRecord.Flags=UserRecord.Flags Or Rerolled ' set user record flag
  2173.     Do ' loop until changes completed
  2174.        Outpt="Character reroll:" ' message
  2175.        Call IO.O ' send output
  2176.        Outpt="Change class type/name(y/n)? " ' input prompt
  2177.        No.Input.Out="Y" ' set default input
  2178.        Call IO.I ' get user input
  2179.        If Yes Then ' compare yes entered
  2180.           Call Modify.Class ' routine to modify class type
  2181.        Endif ' end compare yes entered
  2182.        Outpt="Character reroll:" ' message
  2183.        Call IO.O ' send output
  2184.        Outpt="Change vital statistics(y/n)? " ' input prompt
  2185.        No.Input.Out="Y" ' set default input
  2186.        Call IO.I ' get user input
  2187.        If Yes Then ' compare yes entered
  2188.           Call Modify.Stats ' routine to modify statistics
  2189.        Endif ' end compare yes entered
  2190.        Outpt="Character reroll:" ' message
  2191.        Call IO.O ' send output
  2192.        Outpt="Change character race type/name(y/n)? " ' input prompt
  2193.        No.Input.Out="Y" ' set default input
  2194.        Call IO.I ' get user input
  2195.        If Yes Then ' compare yes entered
  2196.           Call Modify.Race ' routine to modify race
  2197.        Endif ' end compare yes entered
  2198.        Outpt="Character reroll:" ' message
  2199.        Call IO.O ' send output
  2200.        Outpt="Change weapon proficiency(y/n)? " ' input prompt
  2201.        No.Input.Out="Y" ' set default input
  2202.        Call IO.I ' get user input
  2203.        If Yes Then ' compare yes entered
  2204.           Call Modify.Proficiency ' routine to modify weapon proficiency
  2205.        Endif ' end compare yes entered
  2206.        Outpt="Character reroll:" ' message
  2207.        Call IO.O ' send output
  2208.        Outpt="Change character alignment(y/n)? " ' input prompt
  2209.        No.Input.Out="Y" ' set default input
  2210.        Call IO.I ' get user input
  2211.        If Yes Then ' compare yes entered
  2212.           Call Modify.Alignment ' routine to modify alignment
  2213.        Endif ' end compare yes entered
  2214.        Do ' loop until changes finished prompt
  2215.           Outpt="All changes finished(y/n)? " ' input prompt
  2216.           No.Input.Out="Y" ' set default input
  2217.           Call IO.I ' get user input
  2218.           If Yes Then ' compare yes entered
  2219.              Exit Sub ' exit routine
  2220.           Endif ' end compare
  2221.           If No Then ' compare no entered
  2222.              Exit Do ' exit changes loop
  2223.           Endif ' end compare
  2224.        Loop ' loop until yes or no entered
  2225.     Loop ' end loop until changes completed
  2226.     Exit Sub ' exit routine
  2227.  Endif ' end compare yes entered
  2228.  Outpt="Your character has not been rerolled!" ' make output message
  2229.  Call IO.O ' send output message
  2230. End Sub ' end routine to modify all statistics
  2231.  
  2232.  Rem * routine returns a prefix for monster name.
  2233.  Rem * output variables:
  2234.  Rem *   Prefix1 - monster name prefix.
  2235.  
  2236. Sub The.Or.An
  2237.  On Local Error Resume Next ' local error resume
  2238.  If MonsterArray(Monster.Number).Permanent<True Then ' check for nonplayer
  2239.     Prefix1="the " ' make prefix
  2240.  Else ' check monster type
  2241.     Prefix$=MonsterArray(Monster.Number).MonsterName ' get monster name
  2242.     Prefix$=Left$(Prefix$,1) ' get first letter of monster name
  2243.     If Instr("aeiou",Prefix$) Then ' check monster name vowel
  2244.        Prefix1="an " ' set prefix
  2245.     Else ' check vowel
  2246.        Prefix1="a " ' set prefix
  2247.     Endif ' end check monster name vowel
  2248.  Endif ' end check nonplayer
  2249. End Sub ' end routine to get monster name prefix
  2250.  
  2251.  Rem * routine for parsing numeric value from parameter.
  2252.  Rem * input variables:
  2253.  Rem *   Parsed.Command1 - string with imbedded pound sign to check.
  2254.  Rem * output variables:
  2255.  Rem *   Parse.Number - value of number after pound sign.
  2256.  Rem * work variables:
  2257.  Rem *   Delimit - position of # sign.
  2258.  
  2259. Sub Numeric
  2260.  On Local Error Resume Next ' local error resume
  2261.  Parse.Number=False ' reset numeric value
  2262.  Parse.Delimit=Instr(Parsed.Command1,"#") ' search parameter for # sign
  2263.  If Parse.Delimit Then ' check # sign in string
  2264.     ' store numeric value after #
  2265.     Parse.Number=Int(Val(Mid$(Parsed.Command1,Parse.Delimit+1)))
  2266.     ' trim # from string
  2267.     Parsed.Command1=Left$(Parsed.Command1,Parse.Delimit-1)
  2268.  Endif ' end check for # sign in string
  2269. End Sub ' end routine to parse part of parameter
  2270.  
  2271.  Rem * routine decrements parameter # value after calls to search routines.
  2272.  Rem * input variables:
  2273.  Rem *   Parse.Count - counter for search routines.
  2274.  Rem * output variables:
  2275.  Rem *   Parse.Number - decremented # sign value counter.
  2276.  
  2277. Sub Num
  2278.  On Local Error Resume Next ' local error resume
  2279.  If Parse.Number>False Then ' check counter
  2280.     ' decrement search routine value from counter
  2281.     Parse.Number=Parse.Number-Parse.Count
  2282.     If Parse.Number<False Then ' check counter
  2283.        Parse.Number=False ' reset counter
  2284.     Endif ' end check counter
  2285.  Endif ' end check counter
  2286. End Sub ' end routine to decrement # sign value counter
  2287.  
  2288.  Rem * routine to separate two parameters after command input.
  2289.  Rem * input variables:
  2290.  Rem *   Parsed.Command2 - first/second parameters combined.
  2291.  Rem * output variables:
  2292.  Rem *   Parsed.Command1 - first parsed parameter.
  2293.  Rem *   Parsed.Command2 - second parsed parameter.
  2294.  Rem * work variables:
  2295.  Rem *   Delimit - position of # sign.
  2296.  
  2297. Sub Parse
  2298.  On Local Error Resume Next ' local error resume
  2299.  ' find imbedded space in command parameter
  2300.  Parse.Delimit=Instr(Parsed.Command2," ")
  2301.  Parser=False ' reset position of space
  2302.  If Parse.Delimit Then ' check imbedded space
  2303.     ' store first parameter
  2304.     Parsed.Command1=Left$(Parsed.Command2,Parse.Delimit-1)
  2305.     ' store second parameter
  2306.     Parsed.Command2=Mid$(Parsed.Command2,Parse.Delimit+1)
  2307.     Parser=Parse.Delimit ' store parsed space position
  2308.  Endif ' end check for space
  2309. End Sub ' end routine to separate parameters
  2310.  
  2311.  Rem * routine to separate two parameters after command input in reverse order.
  2312.  Rem * input variables:
  2313.  Rem *   Parsed.Command2 - first/second parameters combined.
  2314.  Rem * output variables:
  2315.  Rem *   Parsed.Command1 - second parsed parameter.
  2316.  Rem *   Parsed.Command2 - first parsed parameter.
  2317.  Rem * work variables:
  2318.  Rem *   Delimit - position of # sign.
  2319.  
  2320. Sub ParseX
  2321.  On Local Error Resume Next ' local error resume
  2322.  ' find imbedded space in command parameter
  2323.  Parse.Delimit=Instr(Parsed.Command2," ")
  2324.  Parser=False ' reset position of space
  2325.  If Parse.Delimit Then ' check imbedded space
  2326.     ' store second parameter
  2327.     Parsed.Command1=Mid$(Parsed.Command2,Parse.Delimit+1)
  2328.     ' store first parameter
  2329.     Parsed.Command2=Left$(Parsed.Command2,Parse.Delimit-1)
  2330.     Parser=Parse.Delimit ' storeparsed space position
  2331.  Endif ' end check for space
  2332. End Sub ' end routine to separate parameters in reverse order
  2333.  
  2334.  Rem * routine computes gold player needs for next training level.
  2335.  Rem * output variables:
  2336.  Rem *   Gold.Required# - gold points.
  2337.  
  2338. Sub Gold(Gold.Required#)
  2339.  On Local Error Resume Next ' local error resume
  2340.  If UserRecord.Level<=10 Then ' check player level
  2341.     Gold.Required#=2^(UserRecord.Level+5) ' calculate gold
  2342.  Else ' player level over ten
  2343.     Gold.Required#=2^15+(UserRecord.Level-10)*10000! ' calculate gold
  2344.  Endif ' end check player level
  2345. End Sub ' end routine to calculate gold
  2346.  
  2347.  Rem * routine computes experience player needs for next training level.
  2348.  Rem * output variables:
  2349.  Rem *   Exp.Required# - experience points.
  2350.  
  2351. Sub Experience(Exp.Required#)
  2352.  On Local Error Resume Next ' local error resume
  2353.  If UserRecord.Level<=10 Then ' check player level
  2354.     Exp.Required#=2^(UserRecord.Level+6) ' calculate experience
  2355.  Else ' player level over ten
  2356.     Exp.Required#=2^16+(UserRecord.Level-10)*10000! ' calculate experience
  2357.  Endif ' end check player level
  2358. End Sub ' end routine to calculate experience
  2359.  
  2360.  Rem * routine returns range of numbers.
  2361.  Rem * input variables:
  2362.  Rem *   Upper.Range - contains upper range.
  2363.  Rem * output variables:
  2364.  Rem *   Start.Range - start of range.
  2365.  Rem *   End.Range - end of range.
  2366.  
  2367. Sub Get.Range(Upper.Range,Start.Range,End.Range)
  2368.  On Local Error Resume Next ' local error resume
  2369.  Range.Type$=Mid$(Str$(Upper.Range),2) ' convert upper range to string
  2370.  Outpt="From(1-"+Range.Type$+")? " ' make input prompt
  2371.  No.Input.Out="1" ' default input
  2372.  Call IO.I ' get input
  2373.  Start.Range=Int(Val(Inpt)) ' convert input to integer
  2374.  If Start.Range<1 Then ' check bounds of input
  2375.     Start.Range=1 ' reset input
  2376.  Endif ' end check bounds
  2377.  If Start.Range>Upper.Range Then ' check bounds of input
  2378.     Start.Range=Upper.Range ' reset input
  2379.  Endif ' end check bounds
  2380.  Outpt="To("+Mid$(Str$(Start.Range),2)+"-"+Range.Type$+")? " ' input prompt
  2381.  No.Input.Out=Range.Type$ ' default input
  2382.  Call IO.I ' get input
  2383.  End.Range=Int(Val(Inpt)) ' convert input to integer
  2384.  If End.Range<Start.Range Then ' check bounds
  2385.     End.Range=Start.Range ' reset input
  2386.  Endif ' end check bounds
  2387.  If End.Range>Upper.Range Then ' check bounds
  2388.     End.Range=Upper.Range ' reset input
  2389.  Endif ' end check bounds
  2390. End Sub ' end routine to get range of numbers
  2391.  
  2392.  Rem * routine returns range of numbers.
  2393.  Rem * input variables:
  2394.  Rem *   Start.Range - starting of range.
  2395.  Rem *   End.Range - end of range.
  2396.  Rem * output variables:
  2397.  Rem *   Upper.Range - contains upper range.
  2398.  
  2399. Sub Get.Range2(Start.Range,End.Range,Upper.Range)
  2400.  On Local Error Resume Next ' local error resume
  2401.  Start.Range$=Mid$(Str$(Start.Range),2) ' convert starting range to string
  2402.  End.Range$=Mid$(Str$(End.Range),2) ' convert upper range to string
  2403.  Outpt=Outpt+"("+Start.Range$+"-"+End.Range$+")? " ' make input prompt
  2404.  No.Input.Out=Start.Range$ ' default input
  2405.  Call IO.I ' get input
  2406.  Upper.Range=Int(Val(Inpt)) ' convert input to integer
  2407.  If Upper.Range<Start.Range Then ' check bounds of input
  2408.     Upper.Range=Start.Range ' reset input
  2409.  Endif ' end check bounds
  2410.  If Upper.Range>End.Range Then ' check bounds of input
  2411.     Upper.Range=End.Range ' reset input
  2412.  Endif ' end check bounds
  2413. End Sub ' end routine to get range of numbers
  2414.  
  2415.  Rem * routine returns range of single precision numbers.
  2416.  Rem * input variables:
  2417.  Rem *   Upper.Range! - contains upper range.
  2418.  Rem * output variables:
  2419.  Rem *   Start.Range! - start of range.
  2420.  Rem *   End.Range! - end of range.
  2421.  
  2422. Sub Get.Room.Range(Upper.Range!,Start.Range!,End.Range!)
  2423.  On Local Error Resume Next ' local error resume
  2424.  Range.Type$=Mid$(Str$(Upper.Range!),2) ' convert upper range to string
  2425.  Outpt="From(1-"+Range.Type$+")? " ' make input prompt
  2426.  No.Input.Out="1" ' default input
  2427.  Call IO.I ' get input
  2428.  Start.Range!=Int(Val(Inpt)) ' convert input to integer
  2429.  If Start.Range!<1! Then ' check bounds of input
  2430.     Start.Range!=1! ' reset input
  2431.  Endif ' end check bounds
  2432.  If Start.Range!>Upper.Range! Then ' check bounds of input
  2433.     Start.Range!=Upper.Range! ' reset input
  2434.  Endif ' end check bounds
  2435.  Outpt="To("+Mid$(Str$(Start.Range!),2)+"-"+Range.Type$+")? " ' input prompt
  2436.  No.Input.Out=Range.Type$ ' default input
  2437.  Call IO.I ' get input
  2438.  End.Range!=Int(Val(Inpt)) ' convert input to integer
  2439.  If End.Range!<Start.Range! Then ' check bounds
  2440.     End.Range!=Start.Range! ' reset input
  2441.  Endif ' end check bounds
  2442.  If End.Range!>Upper.Range! Then ' check bounds
  2443.     End.Range!=Upper.Range! ' reset input
  2444.  Endif ' end check bounds
  2445. End Sub ' end routine to get range of numbers
  2446.  
  2447.  Rem * routine returns range of single precision numbers.
  2448.  Rem * input variables:
  2449.  Rem *   Start.Range - starting of range.
  2450.  Rem *   End.Range - end of range.
  2451.  Rem * output variables:
  2452.  Rem *   Upper.Range - contains upper range.
  2453.  
  2454. Sub Get.Room.Range2(Start.Range!,End.Range!,Upper.Range!)
  2455.  On Local Error Resume Next ' local error resume
  2456.  Start.Range$=Mid$(Str$(Start.Range!),2) ' convert starting range to string
  2457.  End.Range$=Mid$(Str$(End.Range!),2) ' convert upper range to string
  2458.  Outpt=Outpt+"("+Start.Range$+"-"+End.Range$+")? " ' make input prompt
  2459.  No.Input.Out=Start.Range$ ' default input
  2460.  Call IO.I ' get input
  2461.  Upper.Range!=Int(Val(Inpt)) ' convert input to integer
  2462.  If Upper.Range!<Start.Range! Then ' check bounds of input
  2463.     Upper.Range!=Start.Range! ' reset input
  2464.  Endif ' end check bounds
  2465.  If Upper.Range!>End.Range! Then ' check bounds of input
  2466.     Upper.Range!=End.Range! ' reset input
  2467.  Endif ' end check bounds
  2468. End Sub ' end routine to get range of numbers
  2469.  
  2470.  Rem * routine returns the charges of an item of treasure.
  2471.  Rem * output variables:
  2472.  Rem *   Charges.Amount - stores treasure type charges.
  2473.  
  2474. Sub TreasureCharges(Charges.Amount)
  2475.  On Local Error Resume Next ' local error resume
  2476.  Charges.Amount=TreasureRecord.Charges ' store treasure charges
  2477.  If TreasureRecord.FuelType Then ' compare treasure to fuel
  2478.     Charges.Amount=TreasureRecord.FuelCharges ' reset treasure charges
  2479.  Endif ' end compare fuel charges
  2480.  If TreasureRecord.LightType Then ' compare vehicle to light
  2481.     Charges.Amount=False ' reset treasure charges
  2482.  Endif ' compare charges
  2483.  If TreasureRecord.Vehicle Then ' compare treasure to vehicle
  2484.     Charges.Amount=TreasureRecord.VehicleHits ' reset treasure charges
  2485.  Endif ' compare charges
  2486. End Sub ' end routine to return charges
  2487.  
  2488.  Rem * routine to wish for an item
  2489.  Rem * input variables:
  2490.  Rem *   Inpt - stores name of item
  2491.  
  2492. Sub Wish.Item
  2493.  On Local Error Resume Next ' local error resume
  2494.  Outpt="The Ghods Thunder.." ' make output message
  2495.  Call IO.O ' send message
  2496.  Outpt="   What Do You Wish For?" ' make input prompt
  2497.  Call IO.I ' get input
  2498.  Stored.Parsed.Command2=Inpt ' store input
  2499.  Parsed.Command1=Stored.Parsed.Command2 ' store input
  2500.  Call Numeric ' parse number
  2501.  Inpt=Parsed.Command1 ' restore input
  2502.  Inpt=Lcase$(Inpt) ' convert to lowercase
  2503.  Call Drop(False) ' call routine to get item
  2504. End Sub
  2505.  
  2506.  Rem * routine to wish for points or an item, or get an object or treasure.
  2507.  Rem * input variables:
  2508.  Rem *   Drop.Type - false to use normal drop routine, true for extended drop.
  2509.  
  2510. Sub Drop(Drop.Type)
  2511.  On Local Error Resume Next ' local error resume
  2512.  Wish.Points=1 ' store points number to wish for
  2513.  If Right$(Inpt,7)=" points" Then ' compare wish for two points
  2514.     Inpt=Left$(Inpt,Len(Inpt)-7) ' truncate wish parameter
  2515.     Wish.Points=2 ' store points number to wish for
  2516.  Endif ' end compare points wish
  2517.  For Stat.Number=1 To 7 ' loop through statistic names
  2518.     Outpts=Stat(Stat.Number) ' get statistic name
  2519.     Outpts=Rtrim$(Outpts) ' trim name
  2520.     Outpts=Lcase$(Outpts) ' lowercase name
  2521.     If Inpt=Outpts Then ' compare wish item to statistic name
  2522.        If Normal.User Then ' check non DM
  2523.           ' check point already wished for
  2524.           If (UserRecord.Flags And 2^Stat.Number) Then
  2525.              Goto Wish.Denied ' jump to wish denied subroutine
  2526.           Endif ' end check point wished for
  2527.        Endif ' end check normal player
  2528.        ' add player wish bitflag
  2529.        UserRecord.Flags=(UserRecord.Flags Or 2^Stat.Number)
  2530.        Wish.Points=Wish.Points*Int(Rnd*3+1) ' calculate points to add
  2531.        ' calculate new statistic
  2532.        New.Stat#=UserRecord.Stats(Stat.Number)+Wish.Points
  2533.        If New.Stat#>MaxInt Then ' compare maximum integer
  2534.           New.Stat#=MaxInt ' reset to maximum integer
  2535.        Endif ' end check maximum integer
  2536.        New.Stat=Cint(New.Stat#) ' store in integer
  2537.        If Normal.User Then ' check non DM
  2538.           If New.Stat>MaxStat Then ' check maximum statistic allowed
  2539.              Goto Wish.Denied ' jump to wish denied subroutine
  2540.           Endif ' end check maximum stat
  2541.        Endif ' end check normal player
  2542.        UserRecord.Stats(Stat.Number)=New.Stat ' increment point wished for
  2543.        Graphics.Off=True ' reset color
  2544.        Outpt="The Ghods Thunder..." ' make ghod message
  2545.        Call IO.O ' send message
  2546.        Outpt="   Your "+Outpts+" Has Been Raised!" ' make stat message
  2547.        Call IO.O ' send update stat message
  2548.        Graphics.Off=False ' reset color
  2549.        Exit Sub ' exit routine
  2550.     Endif ' end compare point wish
  2551.  Next ' end loop through statistic names
  2552.  If Drop.Type=False Then ' check drop type
  2553.     If Normal.User Then ' check normal player
  2554.        If UserRecord.Flags And Wished Then ' check player has already wished
  2555.           Goto Wish.Denied ' jump to wish denied subroutine
  2556.        Endif ' end check already wished
  2557.     Endif ' end check normal user
  2558.  Endif ' end check drop type
  2559.  UserRecord.Flags=UserRecord.Flags Or Wished ' set player wish bitflag
  2560.  Parse.Value=False ' item counter
  2561.  Wish.Charges=False ' item charges
  2562.  Wish.Index=False ' item index
  2563.  ' loop through treasure file
  2564.  For Treasure.Number=1 To Lof(TreasureFile)/Len(TreasureRecord)
  2565.     Call Read.Record(TreasureFile,Treasure.Number) ' get next record
  2566.     Outpts=TreasureRecord.TreasureName ' store treasure name
  2567.     Outpts=Left$(Outpts,Len(Inpt)) ' truncate name
  2568.     If Inpt=Outpts Then ' compare treasure name to wish item name
  2569.        Parse.Value=Parse.Value+1 ' increment item counter
  2570.        ' compare counters
  2571.        If Parse.Number=False Or Parse.Value=Parse.Number Then
  2572.           Wish.Index=Treasure.Number ' store treasure file number
  2573.           Call TreasureCharges(Wish.Charges) ' routine to get treasure charges
  2574.           Exit For ' exit loop through treasure file
  2575.        Endif ' end compare counters
  2576.     Endif ' end compare names
  2577.  Next ' end loop through treasure file
  2578.  If Wish.Index=False Then ' check no treasure match found
  2579.     If Normal.User=False Or Drop.Type Then ' compare DM/Sysop or drop type
  2580.        ' loop through object file
  2581.        For Object.Number=1 To Lof(ObjectFile)/Len(ObjectRecord)
  2582.           Call Read.Record(ObjectFile,Object.Number) ' get object record
  2583.           Outpts=ObjectRecord.ObjectName ' store object name
  2584.           Outpts=Left$(Outpts,Len(Inpt)) ' truncate object name
  2585.           If Inpt=Outpts Then ' compare object name to wish name
  2586.              Parse.Value=Parse.Value+1 ' increment counter
  2587.              ' compare counters
  2588.              If Parse.Number=False Or Parse.Value=Parse.Number Then
  2589.                 ' store negation of object file index
  2590.                 Wish.Index=-Object.Number
  2591.                 Wish.Charges=False ' clear charges
  2592.                 Exit For ' exit loop through object file
  2593.              Endif ' end compare counters
  2594.           Endif ' end compare names
  2595.        Next ' end loop through object file
  2596.     Endif ' end compare drop type/DM, Sysop
  2597.  Endif ' end check treasure found
  2598.  If Drop.Type=False Then ' check drop type
  2599.     If Wish.Index>False Then ' check treasure found
  2600.        If Normal.User Then ' check normal player/not DM
  2601.           If TreasureRecord.Container Then ' check treasure container
  2602.              Wish.Index=False ' clear treasure found
  2603.           Else ' check treasure
  2604.              If TreasureRecord.Vehicle Then ' check treasure vehicle
  2605.                 Wish.Index=False ' clear treasure found
  2606.              Else ' check treasure
  2607.                 Spell.Number=TreasureRecord.Spell ' get treasure spell
  2608.                 ' check spell file bounds
  2609.                 If Spell.Number>False And _
  2610.                 Spell.Number<=Lof(SpellFile)/Len(SpellRecord) Then
  2611.                    Call Read.Record(SpellFile,Spell.Number) ' get spell record
  2612.                    If SpellRecord.SpellType=4 Then ' check spell type wish
  2613.                       Wish.Index=False ' clear treasure found
  2614.                    Endif ' end check wish spell
  2615.                 Endif ' end check spell file bounds
  2616.              Endif ' end check treasure
  2617.           Endif ' end check treasure
  2618.        Endif ' end check normal player
  2619.     Endif ' and check treasure found to drop
  2620.  Endif ' end check drop type
  2621.  Drop.Type=False ' clear drop flag
  2622.  Select Case Wish.Index ' selection of item type to drop
  2623.  Case Is<False ' check object being dropped
  2624.     ' add object to room
  2625.     Call Add.Room.Object(Abs(Wish.Index),Wish.Charges,Drop.Type)
  2626.  Case Is>False ' check treasure being dropped
  2627.     Select Case TreasureRecord.Container ' selection of container dropped
  2628.     Case False ' check treasure container
  2629.        ' add treasure to room
  2630.        Call Add.Room.Treasure(Wish.Index,Wish.Charges,False,Drop.Type)
  2631.     Case True ' check container
  2632.        ' check container name
  2633.        If Rtrim$(RoomRecord.Container.ShortName)=Nul Then
  2634.           Drop.Type=True ' set drop flag
  2635.           ' store container variables
  2636.           ContainerRec.Closed=TreasureRecord.Closed
  2637.           ContainerRec.ContainerName=TreasureRecord.TreasureName
  2638.           ContainerRec.Locked=TreasureRecord.Locked
  2639.           ContainerRec.Keyed=TreasureRecord.Keyed
  2640.           ContainerRec.ShortName=TreasureRecord.ShortName
  2641.           ContainerRec.Permanent=TreasureRecord.Permanent
  2642.           For Container.Count=1 To 5 ' loop through container contents
  2643.              ' clear container contents
  2644.              Call Clear.Container(Container.Count,False)
  2645.           Next ' end loop through container
  2646.           RoomRecord.Container=ContainerRec ' add container record to room
  2647.           Call Share.Room.Record(Room) ' write room record
  2648.        Endif ' end check container
  2649.     End Select ' end select container
  2650.  End Select ' end select treasure
  2651.  If Drop.Type=False Then ' check drop flag
  2652.     Goto Wish.Denied ' jump to wish denied subroutine
  2653.  Endif ' end check drop flag
  2654.  Graphics.Off=True ' reset color
  2655.  Outpt="A Dark Cloud Passes Overhead..." ' make ghod message
  2656.  Call IO.O ' send message
  2657.  Outpt="   Some Treasure Falls From The Sky..." ' make ghod message
  2658.  Call IO.O ' send message
  2659.  Outpt="The Cloud Disappears..." ' make ghod message
  2660.  Call IO.O ' send message
  2661.  Graphics.Off=False ' reset color
  2662.  Exit Sub ' exit routine
  2663.  
  2664. Wish.Denied:
  2665.  Graphics.Off=True ' reset color
  2666.  Outpt="The Ghods Thunder..." ' make ghod message
  2667.  Call IO.O ' send message
  2668.  Outpt="   Your Wish Is Denied!" ' make ghod message
  2669.  Call IO.O ' send message
  2670.  Graphics.Off=False ' reset color
  2671. End Sub ' end routine to drop item to ground
  2672.