'/*
' * StealthBot Shared Scripting Class
' *
' * ScriptSupportClass.cls
' *
' * This class basically mirrors the signatures of several important StealthBot functions
' * for the purpose of allowing your scripts to interact with the rest of the program.
' *
' * I'm very accomodating to the SB scripting community. If you have something you want
' * to see mirrored or some change you want made, don't hesitate to e-mail me about it
' * at stealth@stealthbot.net or bring it up on our scripting forums at stealthbot.net.
' *
' * SCRIPTING SYSTEM CHANGELOG
' *     (version 2.6, scripting system build 20)
' *     - Exposed the entire internal bot variable class to the scripting system
' *         clsBotVars.txt shows you what you can access, BotVars.varName
' *         Suggested by Imhotep[Nu]
' *     - Fixed the MonitoredUserIsOnline() function (thanks Cnegurozka)
' *     - Added BotPath function (thanks werehamster)
' *     - Added IsOnline function (thanks Xelloss)
' *     - Added Sleep function (thanks Imhotep[Nu])
' *     - Added GetPositionByName function (thanks werehamster)
' *     - Added GetNameByPosition function (thanks werehamster)
' *     - Added GetBotVersion function (thanks Imhotep[Nu])
' *     - Changed the ReloadSettings function (thanks Imhotep[Nu])
' *     - New scripting event: Event_LoggedOff() (thanks Imhotep[Nu])
' *     - Added Connect() and Disconnect() functions (thanks Imhotep[Nu])
' *     - Added BotClose() function (thanks Imhotep[Nu])
' *     - Changed GetInternalData() function and added GetInternalDataByUsername() function
' *     - Added GetInternalUserCount() function
' *     - Added Event_ChannelLeave() function (request of Imhotep[Nu])
' *     - Added GetConfigEntry() and WriteConfigEntry() functions
' *     - Added PrintURLToFile() function (thanks SoCxFiftyToo)
' *     - Added VetoThisMessage() function -- use in Event_PressedEnter to prevent the
' *         message in the event's arguments from being sent to Battle.net
' *
' *     (version 2.5, scripting system build 19)
' *     - Command() now returns the command response string (requested)
' *     - New SSC function GetInternalData(sUser, lDataType) - see the function in this file for details
' *     - New SSC function IsShitlisted()
' *     - New SSC function PadQueue() added
' *
' *     (version 2.4R2, scripting system build 18)
' *     - AddChat now loops from 0 to ubound, which is correct. (Thanks Imhotep[Nu])
' *     - Added the ReloadSettings function
' *     - The Event_Close() sub is called when a user reloads the config
' *     - Fixed the signature for Event_KeyPress in script.txt (should be Event_PressedEnter)
' *     - Added Event_UserInChannel()
' *     - Clarified how #include works in script.txt
' *
' *     (version 2.4, scripting system build 17)
' *     - The Event_ChannelJoin scripted subroutine is now usable (thanks -)(nsane-)
' *     - Exposed a MSINET control to the Scripting system, for use in script-to-website
' *         communication
' *     - Added the #include keyword for script files -- more information is in script.txt
' *     - Added the MonitoredUserIsOnline() function
' *     - The Level variable is now properly passed to the script control
' *     - Added scripting events:
' *         > ServerError messages
' *         > PressedEnter
' *     - The script control class now has access to GetTickCount and Beep API calls
' *         and has been improved based on user requests
' *     - Added the Match, DoReplace, DoBeep and GetGTC functions
' *     - Added the myChannel, BotFlags and myUsername publicly accessible variables
' *     - Added the _KeyReturn() event, for processing profile keys returned from the server
' *     - Added the RequestUserProfile() method, for requesting any user's profile
' *     - Added the SetBotProfile() method, for setting the bot's current profile
' *     - Added the Event_Close() event, which executes on Form_Unload()
' *     - Event_Load() is now called when you reload the script.txt file
' *     - Added the OriginalStatstring variable to Event_Join(). It contains the unparsed statstring of the joining user
' */

Option Explicit

Public myChannel As String '// will contain the bot's current channel at runtime.
Public BotFlags As Long '// will contain the bot's current battle.net flags at runtime.
Public myUsername As String '// will contain the bot's current username at runtime.
                            '// NOTE: This may be different than the bot's config.ini username

'// myTrigger has been replaced by BotVars.BotVars.Trigger
'Public myTrigger As String '// contains the bot's current trigger at runtime
         
Public Enum BanTypes
    btBan = 0     '// used in calling the BanKickUnban() subroutine
    btKick = 1
    btUnban = 2
End Enum

'/* ******************************************************************************************
' *
' *
' *
' *
' * INTERNAL BOT "MIRROR" FUNCTIONS
' *         Usage: ssc.function(arguments)
' *         Example:    ssc.AddChat vbBlue, "Hello world!"
' *
' *
' * ******************************************************************************************
' */

'// ADDCHAT
'// Grok's famous AddChat subroutine. Processes Starcraft/Diablo II color codes automatically.
'// Format: AddChat(Color, Text)
'// Extensible as far as you need:
'// AddChat(Color, Text, Color, Text, Color, Text) -- will all display on one line.
Public Sub AddChat(ParamArray saElements() As Variant)

    '// somehow necessary to actually loop through the array instead of passing it directly. Geh.

    Dim i As Integer
    
    For i = 0 To UBound(saElements) Step 2
        frmChat.AddChat saElements(i), saElements(i + 1)
    Next i

End Sub


'// ADDQ (ADD QUEUE)
'// Adds a string to the message send queue.
'// Nonzero priority messages will be sent with precedence over 0-priority messages.
Public Sub AddQ(ByVal sText As String, Optional ByVal Priority As Byte = 0)

    frmChat.AddQ sText, Priority
    
End Sub


'// COMMAND
'// Calls StealthBot's command processor
'// Messages passed to the processor will be evaluated as commands
'// Public Function Commands(ByRef dbAccess As udtGetAccessResponse, Username As String, _
'//     Message As String, InBot As Boolean, Optional CC As Byte = 0) As String

'// RETURNS: The response string, or an empty string if there is no response

'// Detailed description of each variable:
'// dbAccess    is assembled below. It consists of the speaker username's access within the bot.
'//             For scripting purposes, this module will assemble dbAccess by calling GetAccess() on
'//             the username you specify.
'// Username    is the speaker's username (the username of the person using the command.)
'// Message     is the raw command message from Battle.net. If the user says ".say test", the raw
'//             command message is ".say test". This is the method by which you should call the commands.
'// InBot       defines whether or not the command has been issued from inside the bot. If it has,
'//             the trigger is temporarily changed to "/". Basically, for scripting purposes you can
'//             use it to control whether or not your command responses display publicly.
'// CC          CC controls whether or not the command string is passed to the Custom Command processor.
'//             For scripting purposes I will not allow the user to set CC, it is always 0.
Public Function Command(ByVal Username As String, ByVal Message As String, ByVal InBot As Boolean) As String

    Dim dbAccess As udtGetAccessResponse
    '// GetAccess() will return the access type the commands sub needs
    dbAccess = GetAccess(Username)
    
    Command = Commands(dbAccess, Username, Message, InBot, 0)
    
End Function


'// PING
'// Returns the cached ping of the specified user.
'// If the user is not present in the channel, it returns -3.
Public Function Ping(ByVal Username As String) As Long
    
    Ping = GetPing(Username)
    
End Function


'// BANKICKUNBAN
'// Returns a string corresponding to the success or failure of a ban attempt.
'// Responses should be directly queued using AddQ().
'// Example response strings:
'//     That user is safelisted.
'//     The bot does not have ops.
'//     /ban thePerson Your mother!

'// Variable descriptions:
'// INPT    - Contains the username of the person followed by any extension to it, such as ban message
'//         - Examples: "thePerson Your Mother has a very extremely unequivocally long ban message!"
'//         -           "thePerson"
'//         -           "thePerson Short ban message

'// SPEAKERACCESS   contains the access of the person attempting to ban/kick. This is not applied in
'//                 unban situations.
'//                 In Kick and Ban situations, the target's access must be less than or equal to
'//                 this value -- use it to control inherent safelisting (ie all users with > 20 access
'//                 are not affected by it)

'// MODE        contains the purpose of the subroutine call. The same routine is used to ban, kick and
'//             unban users, so make that choice when calling it.
'//             Ban = 0; Kick = 1; Unban = 2. Any other value will cause the function to die a horrible
'//             death. (not really, it just won't do anything.)
         
Public Function BanKickUnban(ByVal Inpt As String, ByVal SpeakerAccess As Integer, _
    Optional ByVal Mode As BanTypes = 0) As String

    BanKickUnban = Ban(Inpt, SpeakerAccess, CByte(Mode))

End Function


'// ISSAFELISTED
'// Returns True if the user is safelisted, False if they're not. Pretty simple.
Public Function isSafelisted(ByVal Username As String) As Boolean

    isSafelisted = GetSafelist(Username)

End Function

'// ISSHITLISTED
'// Returns a null string if the user is not shitlisted, otherwise returns the shitlist message.
Public Function isShitlisted(ByVal Username As String) As String

    isShitlisted = GetShitlist(Username)

End Function



'// GETDBENTRY
'// Bit of a modification to my existing GetAccess() call to return the data to you effectively.
'// The scripting control isn't the greatest.
'// Pass it the username and it will pass you the person's access and flags.
'// If the name is not in the database, it will return -1 / null flags.
Public Sub GetDBEntry(ByVal Username As String, ByRef Access, ByRef Flags) '// yum, Variants >:\

    Dim Temp As udtGetAccessResponse
    
    Temp = GetAccess(Username)
    
    Access = Temp.Access
    Flags = Temp.Flags

End Sub


'// PREPARELIKECHECK
'// Prepares a string for comparison using the Visual Basic LIKE operator
'// Originally written by Zorm, since expanded
Public Function PrepareLikeCheck(ByVal sText As String) As String

    PrepareLikeCheck = PrepareCheck(sText)

End Function


'// GETGTC
'// Returns the current system uptime in milliseconds as reported by the GetTickCount() API call
Public Function GetGTC() As Long
    
    GetGTC = GetTickCount()
    
End Function


'// DOBEEP
'// Executes a call to the Beep() API function
Public Function DoBeep(ByVal lFreq As Long, ByVal lDuration As Long) As Long

    DoBeep = Beep(lFreq, lDuration)
    
End Function


'// DOREPLACE
'// Equivalent to the VB Replace() function which does not exist in VBScript
Public Function DoReplace(ByVal Expression As Variant, ByVal Find As Variant, ByVal Replace As Variant, _
    Optional ByVal start As Long = 1, Optional ByVal Count As Long = -1, Optional ByVal CompareMethod As Long = 0) As String

    DoReplace = Replace(Expression, Find, Replace, start, Count, CompareMethod)

End Function


'// MATCH
'// Allows VBScripters to use the Like comparison operator in VB
'// Specify TRUE to the third argument (DoPreparation) to automatically prepare both inbound strings
'//     for compatibility with Like
Public Function Match(ByVal sString As String, ByVal sPattern As String, ByVal DoPreparation As Boolean) As Boolean

    If DoPreparation Then
        sString = PrepareCheck(sString)
        sPattern = PrepareCheck(sPattern)
    End If
    
    Match = (sString Like sPattern)
    
End Function


'// MONITOREDUSERISONLINE
'// Allows vbscripters to check the User Monitor status of a given user
'// Returns -1 if the user is not in the monitor, 0 for offline and 1 for online
Public Function MonitoredUserIsOnline(ByVal Username As String) As Integer
    
    If MonitorExists Then
        MonitoredUserIsOnline = MonitorForm.GetUserStatus(Username)
    Else
        MonitoredUserIsOnline = -1
    End If
    
End Function


'// SETBOTPROFILE
'// Sets the bot's current profile to the specified value(s).
'// If passed as null, the values will not be reset, so profile data you are not changing will not be overwritten.
Public Sub SetBotProfile(ByVal sNewSex As String, ByVal sNewLocation As String, ByVal sNewDescription As String)
    
    Call SetProfile(sNewLocation, sNewSex, sNewDescription)
    
End Sub


'// GETUSERPROFILE
'// Gets the profile of a specified user. The profile is returned in three pieces via the _KeyReturn() event.
'// If Username is null, the bot's current username will be used instead.
Public Sub GetUserProfile(ByVal Username As String)
    
    If LenB(Username) > 0 Then
        Call RequestProfile(Username)
    Else
        Call RequestProfile(CurrentUsername)
    End If
    
End Sub


'// RELOADSETTINGS
'// Reloads the bot's configuration settings, userlist, safelist, tagban list, and script.txt files - equivalent to
'//     clicking "Reload Config" under the Settings menu inside the bot.
'// @param DoNotLoadFontSettings - when passed a value of 1 the bot will not
'//     attempt to alter the main richtextbox font settings, which causes its contents to be erased
Public Sub ReloadSettings(ByVal DoNotLoadFontSettings As Byte)

    Call frmChat.ReloadConfig(DoNotLoadFontSettings)
    
End Sub


'// BOTPATH
'// Returns the bot's current path. Future compatibility with multiple user profiles is already in place.
'//     Return value includes the trailing "\".
Public Function BotPath() As String
    
    BotPath = GetProfilePath()
    
End Function


'// GETINTERNALUSERCOUNT
'// Returns the highest index for use when calling GetInternalDataByIndex
'//     this allows you to call that function with (1 to GetInternalUserCount())
Public Function GetInternalUserCount() As Integer
    
    GetInternalUserCount = colUsersInChannel.Count
    
End Function


'// GETINTERNALDATABYINDEX
'// Retrieves the specified stored internal data for a given user in the channel
'//  If the specified user isn't present, the return value is -5
'//  See lDataType constants in GetInternalData() below
Public Function GetInternalDataByUsername(ByVal sUser As String, ByVal lDataType As Long) As Variant

    Dim i As Integer
    
    i = UsernameToIndex(sUser)
    
    GetInternalDataByUsername = GetInternalData(i, lDataType)

End Function


'// GETINTERNALDATA
'// Retrieves the specified stored internal data for a given user in the channel
'//  If the specified user is not present, return value is '-5'
Public Function GetInternalData(ByVal iIndex As Integer, ByVal lDataType As Long) As Variant
    ' -- '
    '       these constants will be useful in making calls to this function
    '                           |   <purpose>
    Const GID_CLAN = 0          '-> retrieves 4-character clan name
    Const GID_FLAGS = 1         '-> retrieves Battle.net flags
    Const GID_PING = 2          '-> retrieves ping on login
    Const GID_PRODUCT = 3       '-> retrieves 4-digit product code
    Const GID_ISSAFELISTED = 4  '-> retrieves Boolean value denoting safelistedness
    Const GID_STATSTRING = 5    '-> retrieves unparsed statstring
    Const GID_TIMEINCHANNEL = 6 '-> retrieves time in channel in seconds
    Const GID_TIMESINCETALK = 7 '-> retrieves time since last message in seconds
    ' -- '
    
    If iIndex > 0 Then
        Select Case lDataType
            Case GID_CLAN
                GetInternalData = colUsersInChannel.Item(iIndex).Clan
                
            Case GID_FLAGS
                GetInternalData = colUsersInChannel.Item(iIndex).Flags
            
            Case GID_PING
                GetInternalData = colUsersInChannel.Item(iIndex).Ping
            
            Case GID_PRODUCT
                GetInternalData = colUsersInChannel.Item(iIndex).Product
            
            Case GID_ISSAFELISTED
                GetInternalData = colUsersInChannel.Item(iIndex).Safelisted
            
            Case GID_STATSTRING
                GetInternalData = colUsersInChannel.Item(iIndex).Statstring
            
            Case GID_TIMEINCHANNEL
                GetInternalData = colUsersInChannel.Item(iIndex).TICs
            
            Case GID_TIMESINCETALK
                GetInternalData = colUsersInChannel.Item(iIndex).TimeSinceTalk
            
            Case Else
                GetInternalData = 0
                
        End Select
    Else
        GetInternalData = -5
    End If
    
End Function


'// ISONLINE
'// Returns a boolean denoting teh bot's status ONLINE=TRUE, OFFLINE=FALSE.
Public Function IsOnline() As Boolean
    
    IsOnline = g_Online
    
End Function


'// SLEEP
'// Mirror function for the Kernel32.dll function Sleep()
Public Sub Sleep(ByVal dwMilliseconds As Long)
    
    Call Sleep(dwMilliseconds)
    
End Sub


'// GETPOSITIONBYNAME
'// Returns the channel list position of a user by their username
'// Returns -1 if the user is not present
Public Function GetPositionByName(ByVal sUser As String) As Integer
    
    GetPositionByName = frmChat.CheckChannel(sUser)
    
End Function


'// GETNAMEBYPOSITION
'// Returns the name of the person at position X in the channel list.
'// Positions are 1-based. Returns an empty string if the user isn't present
Public Function GetNameByPosition(ByVal X As Integer) As String
    
    With frmChat.lvChannel.ListItems
        If X > 0 And X < .Count Then
            GetNameByPosition = .Item(X).text
        Else
            GetNameByPosition = ""
        End If
    End With
    
End Function


'// GETBOTVERSION
'// Returns the current StealthBot app version as a string.
Public Function GetBotVersion() As String
    
    GetBotVersion = "StealthBot v" & App.Major & "." & App.Minor
    
    '// Compiler flag - BETA = 0 in public releases
    #If BETA = 1 Then
        GetBotVersion = GetBotVersion & App.Revision & " Development Edition"
    #End If
    
End Function


'// CONNECT
'// Connects the bot. Will disconnect an already-existent connection.
Public Sub Connect()
    
    Call frmChat.DoConnect
    
End Sub



'// DISCONNECT
'// Closes any current connections within the bot.
Public Sub Disconnect()
    
    Call frmChat.DoDisconnect
    
End Sub


'// BOTCLOSE
'// Shuts down StealthBot
Public Sub BotClose()
    
    Call frmChat.Form_Unload(0)
    
End Sub


'// GETCONFIGENTRY
'// Reads a value from config.ini and returns it as a string
'// If no value is present an empty string will be returned
'// PARAMETERS
'//     sSection - Section heading from the INI file - examples: "Main", "Other"
'//     sEntryName - Entry you want to read - examples: "Server", "Username"
'//     sFileName - File you're reading from - examples: "config.ini", "definitions.ini"
Public Function GetConfigEntry(ByVal sSection As String, ByVal sEntryName As String, ByVal sFileName As String) As String
    
    If LenB(sFileName) = 0 Then sFileName = "config.ini"
    
    GetConfigEntry = ReadINI(sSection, sEntryName, sFileName)
    
End Function



'// WRITECONFIGENTRY
'// Writes a value to config.ini
'// PARAMETERS
'//     sSection - Section heading from the INI file - examples: "Main", "Other"
'//     sEntryName - Entry you want to read - examples: "Server", "Username"
'//     sValue - Value to be written to the file
'//     sFileName - File you're reading from - examples: "config.ini", "definitions.ini"
Public Sub WriteConfigEntry(ByVal sSection As String, ByVal sEntryName As String, ByVal sValue As String, ByVal sFileName As String)
    
    If LenB(sFileName) = 0 Then sFileName = "config.ini"
    
    WriteINI sSection, sEntryName, sValue, sFileName
    
End Sub



'// VETOTHISMESSAGE
'// Used with PressedEnter event to prevent a message from being sent to Battle.net
'// For use processing scripts entirely internally
Public Sub VetoThisMessage()

    SetVeto True
    
End Sub



'// PRINTURLTOFILE
'// Mirror function for the Windows API URLDownloadToFile() function
'// Currently you are restricted to placing files in the StealthBot install directory only
Public Sub PrintURLToFile(ByVal sFileName As String, ByVal sURL As String)
    
    sFileName = App.Path & "\" & sFileName
    
    URLDownloadToFile 0, sURL, sFileName, 0, 0
    
End Sub


'// PADQUEUE
'// Pads the queue so further messages will be sent more slowly
Public Sub PadQueue()
    
    QueueLoad = QueueLoad + 1

End Sub