MysticBBS MPL Question reddit / bbs ---------------------------------------------------------------------- TahrFantastico · 2022-07-21 04:45 I'm trying to create an MPL script for MysticBBS to replace the existing User List command with a custom version that polls different user attributes. I've got it partly working, but what I've been unable to figure out, either by examining the available documentation, the various MPL tutorial docs floating around, or the source code of the last open source version is how to read the custom user attributes. In particular, during the signup sequence, I have the user enter some data in User Optional Field #2, and I have no idea how to pull that data from the script. (Also, while I'm here asking, is there any easy way to have it paginate using the system's routines? I figure the alternative is to read the user's screen length and then manually insert pauses, or write the results to a temp file and then use the built-in "show a file" routine, but it seems like a bit of a weird thing to be missing.) Any help with this would be fantastic. Thanks in advance! ---------------------------------------------------------------------- TahrFantastico · 2022-07-21 05:32 I should note that I've made a small amount of progress myself. In mpl\_common.pas (from the last open-source version's source code, so not the version I'm running admittedly), the part where it pulls user information is defined here: >AddStr ({$IFDEF MPLPARSER} 'useropts', {$ENDIF} iString, 10 \* 61 - 1); CV\[X\]\^.ArrPos := 1; {$IFNDEF MPLPARSER} CV\[X\]\^.VarSize := 61; CV\[X\]\^.ArrDim\[1\] := 10; {$ENDIF} By my admittedly uninformed reading, it seems that it creates a one- dimensional array of strings called useropts, with an array size of 10, and a string size of 61. If I added: >Write(UserOpts\[2\]) To my MPL code, it would compile, but I'd get nothing. So I started just randomly incrementing it, 1 through 10. I actually got results from: >Write(UserOpts\[7\]) However, the first five characters are truncated. (???) So, like, if they'd entered, "Abracadabra", that write command spits out, "adabra". So I'm close but... huh? Should I be using a different method of reading this variable? Any ideas? Also, why 7 to get user option 2? ---------------------------------------------------------------------- TahrFantastico · 2022-07-21 06:28 Okay, I feel silly for posting and then answering my own question before there was a single reply, but for whatever reason, the following spits out the contents of User Option 2: >Write(copy(striplow(UserOpts\[0\]),2,length(striplow(UserOpts\[0\]))- 1)) The reason for all the stripping and copying is that it's prefixed with a bunch of garbage characters (which might be the contents of User Option 1? Who knows?) and striplow gets rid of all of them but one. \*shrug\* ---------------------------------------------------------------------- electronicchicken · 2022-07-21 14:09 If you want to know more about the structure of the data, check out the "records" file included with Mystic, eg. `records.112`. It'll save you from having to dig through outdated source code. The results you're seeing make me think that the structure has changed but MPL doesn't know about it; it's using incorrect offsets to load records from a file. I don't know how MPL programs interface with Mystic and its data, so I can't say for sure. Could be that gooroo needs to fix something, or you're building with an outdated/mismatched `mplc`, etc. I did note that `mpl.doc` is absent from the install I just did. I wonder if it's part of a general push toward Python over MPL. ---------------------------------------------------------------------- myke113 · 2022-07-21 18:25 I've lost count of how many times I've asked questions then figured it out on my own before anyone answered. I of course replied to myself... Which saved me down the road when I had forgotten about the solution, Googled it, then came across my own fix. =) ---------------------------------------------------------------------- dperry324 · 2022-07-21 18:52 You can use MCI2STR() to extract any MCI code into a string. It works for both user data and static BBS data. Player.BBSName:=MCI2Str('BN') MyIp:=Mci2Str('UY') ---------------------------------------------------------------------- dperry324 · 2022-07-21 19:00 According to the wiki, [http://wiki.mysticbbs.com/doku.php?id=displayc odes](http://wiki.mysticbbs.com/doku.php?id=displaycodes) the first three optional data answers are U1, U2, and U3. U1 - User's optional data answer for question #1 U2 - User's optional data answer for question #2 U3 - User's optional data answer for question #3 So if you did something like Uses User Answer1:=MCI2Str('U1') WriteLn('You answered '+Answer1+'!') ---------------------------------------------------------------------- TahrFantastico · 2022-07-21 19:29 Right, I had thought of that, but that pulls the answer of the question for the \*current\* user. I'm looking to cycle through the list of users and pull \*their\* answers. That's why I was trying to parse the UserOpts property. I'm pretty sure using UserOpts is the correct way to do it, but that I just don't understand how to index into the weird packed array it uses. UserOpts\[#\] doesn't seem to work properly, although my kludge is working okay in the meantime. ---------------------------------------------------------------------- dperry324 · 2022-07-21 19:59 Uses Cfg Uses User Type UserXRec = Record Name : String\[40\] Idx : Integer End Var TotUsers : Integer Var TheUsers : Array \[1..500\] of UserXRec Procedure ShowUserInfo Begin GoToXy(9,17) Write('|16|11 Gender : |07'+PadRt(UserSex,25,' ')) Write('|15|11 Calls : |07'+PadRt(Int2Str(UserCalls),25,' ')) GoToXy(9,18) Write('|15|11 FirstOn: |07'+PadRt(DateStr(UserFirstOn,1),25,' ')) Write('|15|11 LastOn : |07'+PadRt(DateStr(UserLastOn,1),25,' ')) End Function GetAge(BD:LongInt):Integer Var Ret : Integer=0 Begin Ret:=DaysAgo(Date2Julian(DateStr(BD,1)))/365 GetAge:=Ret End Procedure ListUsers(I,C:Integer) Var A,J,M,R : Byte Begin For J:=1 To 12 Do Begin M:=J+I-1 GetUser(TheUsers\[M\].Idx) GoToxy(08,J+3) If M = C Then Begin TextColor(30) Write(' '+PadRt(UserAlias+'|17|14#'+Int2Str(UserIndex),30,' ')) Write(PadRt(UserCity,30,' ')) Write(PadRt(DateStr(UserLastOn,1),10,' ')) End Else Begin Write('|14|16 '+PadRt(UserAlias+'|16|06#'+Int2Str(UserIndex),30,' ')) Write('|08|16'+PadRt(UserCity,30,' ')) Write('|11|16'+PadRt(DateStr(UserLastOn,1),10,' ')) End End End Procedure DoUserList Var Ch : Char Var Bar : Byte Var T,U : Integer Var Done : Boolean = False Begin T:=1 Bar:=1 Repeat U:=Bar+T-1 ListUsers(T,U) Ch:=ReadKey If IsArrow Then Begin Case Ch Of \#72: Begin Bar:=Bar-1 If Bar < 1 Then Begin If T > 1 Then T:=T-1 Bar:=1 End End \#80: Begin Bar:=Bar+1 If Bar > 12 Then Begin T:=T+1 Bar:=12 End If U >= TotUsers Then Begin Bar:=12 T:=T-1 End End End End Else Begin Ch:=Upper(Ch) Case Ch Of \#27 : Done:=True End End Until Done End Procedure SortUsers Var X,Y : Integer var UX : UserXRec Begin For X:=1 To TotUsers Do Begin For Y:=1 To TotUsers Do Begin If X <> Y Then Begin If Upper(TheUsers\[X\].Name) < Upper(TheUsers\[Y\].Name) Then Begin UX:=TheUsers\[X\] TheUsers\[X\]:=TheUsers\[Y\] TheUsers\[Y\]:=UX End End End End End Procedure Init Begin TotUsers:=1 While GetUser(TotUsers) And TotUsers < 500 Do Begin TheUsers\[TotUsers\].Name:=UserAlias TheUsers\[TotUsers\].Idx:=TotUsers TotUsers:=TotUsers+1 End TotUsers:=TotUsers-1 SortUsers DispFile('userlist') End Procedure Main Begin DoUserList End Begin ClrScr Init Main TextColor(11) End ---------------------------------------------------------------------- dperry324 · 2022-07-21 20:02 You can use the GetUser() function to iterate through the user list and the MCI values should still work. ---------------------------------------------------------------------- MaxMouse_Hypernode · 2022-09-08 01:45 Yeah like Dperry replied, use GetThisUser and GetUser.. Once you GET the user a few variables are applied to the user variables. ---- Function GETUSER (N: Integer) : Boolean This procedure will read user data into the USER variables. The supplied N is the record number to read. The function returns true if the record was read, or false if a record was not read. The following USER variables will be set when a record is read: Variable Name Type Description ------------------------------------------------------------------- USERDELETED Boolean Is the user marked as deleted? USERNAME String User's real name. USERALIAS String User's BBS alias. USERPASSWORD String User's password. USERADDRESS String User's street address. USERCITY String User's City/State. USERZIP String User's ZipCode. USERHPHONE String User's home phone number. USERDPHONE String User's data phone number. USERBDAY String User's birth date. USERSEX Char User's gender (M = Male, F = FeMale). USERSEC Byte User's security level (0-255). USERMENU String User's Starting Menu (if blank, Mystic uses the default menu as setup in the configuration). USERFIRST LongInt User's date/time of first call to the BBS. This is stored in the packed date format so in order to display the date & time, the functions of DATESTR and TIMESTR need to be used. USERLAST LongInt User's date/time of the last call to the BBS. This is also stored in a packed date format, so the same rules for USERFIRST apply to this. USERCALLS LongInt User's total calls to the BBS system. USERTCALLS Integer User's number of calls to the BBS today. USERDLS LongInt User's total # of downloaded files. USERTDLS Integer User's total # of downloaded files today. ------------------------------------------------------------------- User Related ------------ Variables userid LongInt username String[30] userhandle String[30] userpw String[20] useradd String[30] usercity String[25] userzip String[10] userhphone String[15] userdphone String[15] usergender String[1] userbday LongInt // julian date useremail String[40] userinfo String[40] usersec Byte userstart String[20] userexp String[8] userexpto Byte useraf1 LongInt useraf2 LongInt userdtype Byte userscrnsize Byte userhotkey Boolean userfsedit Boolean userquotewin Boolean userflist Boolean usermread Boolean usermidx Boolean usermeidx Boolean userchat Boolean usersig Boolean usersigptr LongInt userarc String[4] usertheme String[20] usercname String[30] userinvis Boolean useravail Boolean userpip String[20] userpname String[50] usertime Integer usercmbase Word usercmgroup Word usercfbase Word usercfgroup Word usercall LongInt usertcall Word userdls LongInt usertdls Word userdlkb LongInt usertdlkb LongInt userfcall LongInt //dos date userlcall LongInt //dos date userposts LongInt useremails LongInt useruls LongInt userulkb LongInt userbank Word userlastpw String[8] uservyes Byte uservno Byte userdoors LongInt userflag LongInt useropts Array[1..10] of String[60]; UserLastOn UserFirstOn Bit Operations --------------- BitCheck(Pos:Byte; AnyVar) : Boolean Accepts a bit position and checks it against an integer, returning true or false if the bit is on. So for example in the Records, the third bit in UserFlags is UserDeleted: GetThisUser If BitCheck(3, UserFlags) Then WriteLn('User is marked deleted'); BitToggle(Pos:Byte; AnyVar); Accepts a bit position and an integer and toggles the bit. GetThisUser BitToggle(3, UserFlags); // undeletes if they are deleted or deletes if // they are not deleted. BitSet(Pos:Byte; AnyVar; True:Boolean); Accepts a bit position and an integer and sets the bit ON/OFF based on a boolean: GetThisUser BitSet(3, UserFlags, True); // user is marked as deleted MPL now fully supports bitwise math and operators! The following are implemented: AND - Bitwise AND OR - Bitwise OR XOR - Bitwise exclusive OR SHL - Bitwise shift left SHR - Bitwise shift right Example: Const UserDeleted = $04; // established bit for userdeleted from records.pas // note: this value has changed check records.pas! Begin GetThisUser If UserFlags AND UserDeleted <> 0 Then WriteLn('User is deleted'); End;