Attribute VB_Name = "Controller"
Option Explicit

'----------------------------------------------------------
'  Myriad
'  Controller Module
'----------------------------------------------------------
'  Version 1.0.0 (2004-05-19)
'  1.0.0: Module started, cleaning up and moving other
'         code. (Cloaked)
'----------------------------------------------------------

'----------------------------------------------------------
'  Release Type
'----------------------------------------------------------
Public Enum releaseType
    mrStable
    mrPrivate
    mrPrivAlpha
    mrPrivBeta
    mrPubAlpha
    mrPubBeta
    mrDevelopment
End Enum
Public mRelease As releaseType

Public Enum ClientBans
    cbStarCraft = 0
    cbBroodWar
    cbWarCraft2
    cbDiablo2
    cbDiablo2x
    cbWarCraft3
    cbWarCraft3x
End Enum

'----------------------------------------------------------
'  Anti-Idle
'----------------------------------------------------------
Public Enum IdleTypes
    idleMessage
    idleUptime
    idleQuotes
    idleMp3
    idleBot
End Enum
Public idleType As IdleTypes, idleDelay As Long, idleMsg As String, _
    idleTimer As Long
Private LastIdleTick As Long
Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, _
    ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, _
    ByVal uIDEvent As Long) As Long

'----------------------------------------------------------
'  Status
'----------------------------------------------------------
Public isConnected As Boolean, isConnecting As Boolean
Public useSafelist As Boolean, useTagbans As Boolean, useAutoBan As Boolean
Public startupTime As Long, useIPBans As Boolean, usePlugBans As Boolean
Public useLockdown As Boolean, useClientBans As Boolean, useIdleBans As Boolean
Public lockdownMessage As String, idleBanDelay As Long, idleBanTimer As Long
Public clientBanData(6) As Boolean, usePhrasebans As Boolean
Public joinOnKick As Boolean, kickTarget As String, _
    rejoinOnKick As Boolean, useGreets As Boolean, _
    whisperGreets As Boolean, greetMessage As String

'----------------------------------------------------------
'  Myriad's BnetBot
'----------------------------------------------------------
Public Bot As BnetBot
Public Declare Function GetTickCount Lib "kernel32.dll" () As Long
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Declare Function RawMyriadDLLVersion Lib "myriad.dll" _
    Alias "MyriadDLLVersion" () As Long
    
'----------------------------------------------------------
'  Event Log
'----------------------------------------------------------
Public Enum EventType
    etNotice
    etWarning
    etError
    etSuccess
    etAlwaysError
End Enum

'----------------------------------------------------------
'  Meeting
'----------------------------------------------------------
Public Meeting As Meeting

'----------------------------------------------------------
'  Quotes
'----------------------------------------------------------
Private Quotes() As String, QuoteI&, QuoteCt&

'----------------------------------------------------------
'  Phrasebans
'----------------------------------------------------------
Private BannedPhrases() As String, PBc&

'----------------------------------------------------------
'  Flood Protection
'----------------------------------------------------------
Private FP As Packet, LastFloodSend&

'----------------------------------------------------------
'  Clan
'----------------------------------------------------------
Public UserClan As Clan

'----------------------------------------------------------
'  Bitshifts
'----------------------------------------------------------
Private m_lPower2(0 To 31) As Long, ShiftInitialized As Boolean

'----------------------------------------------------------
'  Version Information
'----------------------------------------------------------
Public verMajor As Long, verMinor As Long, verRevision As Long, verBuild As Long, verDate As Date
Public verModifier As Long

'----------------------------------------------------------
'  Version Disabling
'----------------------------------------------------------
Public allowConnect As Boolean

'----------------------------------------------------------
'  Automatic Shaman Management
'----------------------------------------------------------
Public AutoClan As AutoClan
Private m_AutoClanEnabled As Boolean

'----------------------------------------------------------
'  Main Sub
'  This sub is run when the bot starts up.
'----------------------------------------------------------
Sub Main()
On Error GoTo Main_Error
    Dim finishTime&, DLLNotFound As Boolean

    ' Version Information
    ' -------------------------------------
    mRelease = mrStable
    verMajor = App.Major
    verMinor = App.Minor
    verRevision = 2
    verBuild = App.Revision
    verDate = #1/20/2006#
    verModifier = 0
    
    'Record startup time.
    startupTime = GetTickCount()
    
    'Seed random number generator.
    Randomize
    
    'Load and show splash screen.
    'Load frmSplash
    'frmSplash.Show
    'DoEvents
    
    'Check myriad.dll version.
On Error GoTo DLL_Error
    If Not bncsutil_checkVersion("1.0.3") Then
        If Not DLLNotFound Then
            MsgBox "The file ""bncsutil.dll"", which Myriad uses " & _
                "for hashing, is not up to the required version " & _
                "(1.0.3).  Myriad cannot start.  " & _
                "Please re-install Myriad.", vbCritical, GetVersion()
            End
        End If
    ElseIf Not DLLNotFound Then
        If (kd_init() = 0) Then
            MsgBox "Failed to initialize CD-key decoder code.  " & _
                "Myriad cannot start.  You should re-install Myriad.", _
                vbCritical, GetVersion()
            End
        End If
    End If
    
    'Initialize queue
On Error GoTo HelperDLL_Error
    If (myriad_queue_prepare() = 0) Then
        MsgBox "Myriad could not prepare its message queue, and will not be able to start.", _
            vbCritical, GetVersion()
        End
    End If
On Error GoTo Main_Error

    allowConnect = True

    'Find Winamp.
    FindWinamp
    
    'Initialize bot object.
    Set Bot = New BnetBot
    
    GetOSVersion
    
    'Initialize whisper controller.
    WC_Initialize
    
    'Initialize clan object.
    Set UserClan = New Clan
    
    'Load main form.
    Dim strTMP$
    Load frmMain
    logEvents = GetBoolean("Enabled", "EventLog", True)
    writeEventLog = GetBoolean("SaveToDisk", "EventLog", False)
    If logEvents Then
        logWindowSize = CLng(Val(GetConfig("WindowHeight", "EventLog")))
        If logWindowSize <= 0 Then _
            logWindowSize = 1575
    Else
        logWindowSize = 0
    End If
    
    useIPBans = GetBoolean("IPBans", "Moderation", False)
    useLockdown = GetBoolean("Lockdown", "Moderation")
    useClientBans = GetBoolean("ClientBans", "Moderation")
    usePlugBans = GetBoolean("PlugBans", "Moderation")
    usePhrasebans = GetBoolean("Phrasebans", "Moderation")
    useIdleBans = GetBoolean("IdleBans", "Moderation")
    lockdownMessage = GetConfig("LockdownMessage", "Moderation")
    useTimestamps = GetBoolean("Timestamps", "Preferences", True)
    use24HourTimestamps = GetBoolean("24HourTimestamps", "Preferences")
    aggressiveFiltering = GetBoolean("Aggressive", "Filters")
    useFloodFilter = GetBoolean("Floods", "Filters", True)
    useMassFilter = GetBoolean("Massloads", "Filters", True)
    useBanFilter = GetBoolean("Bans", "Filters")
    autoClanEnabled = GetBoolean("Enabled", "AutoClan")
    LogEvent "Myriad " & verMajor & "." & verMinor & "." & verRevision & " build " & verBuild & " started."
    
    Select Case LCase$(GetConfig("IdleBanUnit", "Moderation"))
        Case "sec", "seconds", "second"
            idleBanDelay = CLng(Val(GetConfig("IdleBanDelay", "Moderation")) * 1000)
        Case Else
            idleBanDelay = CLng(Val(GetConfig("IdleBanDelay", "Moderation")) * 60000)
    End Select

    joinOnKick = GetBoolean("JoinOnKick", "Behavior", True)
    rejoinOnKick = GetBoolean("RejoinOnKick", "Behavior", True)
    kickTarget = GetBoolean("ChannelOnKick", "Behavior")
    
    useGreets = GetBoolean("Enabled", "Greetings")
    whisperGreets = GetBoolean("Whisper", "Greetings")
    greetMessage = GetConfig("Message", "Greetings")
    
    If useIdleBans Then _
        StartIdleBans
    
    With frmMain
        If LenB(GetConfig("Height", "WindowSize")) Then
            .Height = Val(GetConfig("Height", "WindowSize"))
            .Width = Val(GetConfig("Width", "WindowSize"))
        End If
        .Caption = GetVersion()
        '.sysTray.TrayTip = GetVersion()
        showJoinLeave = GetBoolean("JoinLeave", "Preferences", True)
        
        ApplyFonts
        
        .mnuSettingsJoinLeave.Checked = showJoinLeave
        .mnuSettingsTimestampsEnabled.Checked = useTimestamps
        .mnuSettingsTimestamps24Hour.Checked = use24HourTimestamps
        autoMinimizeTray = GetBoolean("MinimizeToTray", "Preferences")
        .mnuSettingsAutoTray.Checked = autoMinimizeTray
        'HideEventLogs = GetBoolean("HideEventLogs", "Preferences")
        '.mnuSettingsHideEventLogs.Checked = HideEventLogs
        .mnuSettingsWhisperWindows.Checked = GetBoolean("UseWhisperWindows", "Behavior")
        .mnuSettingsTrayOnStartup.Checked = GetBoolean("TrayOnStart", "Behavior")
        BuildQuickChannel
        .mnuSettingsLoggingEvents.Checked = logEvents
        .mnuSettingsLoggingEventsDisk.Enabled = logEvents
        .mnuSettingsLoggingEventsDisk.Checked = writeEventLog
        strTMP = LCase$(GetConfig("LogMode", "Preferences"))
        Select Case strTMP
            Case "all"
                .mnuSettingsLoggingAll.Checked = True
                toLog = logAll
            Case "chat"
                toLog = logChat
                .mnuSettingsLoggingChat.Checked = True
            Case "commands"
                toLog = logCommands
                .mnuSettingsLoggingCommands.Checked = True
            Case Else
                toLog = logNone
                .mnuSettingsLoggingDisabled.Checked = True
        End Select

        LoadDatabase GetConfig("File", "Database", "access.txt")
                
        .onResize
        
        .Refresh
        CreateTrayIcon .TrayListener.hwnd, .Icon, GetVersion, SupportsBubbleTooltips()
        
        AddC "Welcome to " & GetVersion(), vbCyan
        AddC "Created by Cloaked and Scope", vbSilver
        AddC "", vbSilver
        AddC "Updates:", vbSilver
        AddC "StarCraft and BroodWar do NOT work with this version of Myriad due to Warden.", vbSilver
        AddC "WarCraft II BNE connects with BNLS only!", vbSilver
    End With
    
    Dim wsaStart As WSADataType
    Dim i&, W&, WSSD As String, WSS As Boolean
    W = Winsock.WSACleanup
    If (WSAStartup(&H22, wsaStart) <> 0) Then
        MsgBox "Fatal Error: Could not initialize Winsock.", vbCritical, GetVersion()
        End
    Else
        LogEvent "Winsock initialized."
    End If
    LoadPreferences
    LoadQuotes
    LoadPhrasebans
    If GetBoolean("TrayOnStart", "Behavior") Then
        'frmMain.sysTray.InTray = True
        'frmSplash.Hide
        InTray = True
    Else
        finishTime = GetTickCount()
        If (finishTime - startupTime) < 650 Then _
            Sleep (650 - (finishTime - startupTime))
        frmMain.Show
        'frmSplash.Hide
    End If
On Error GoTo FN_Error
    'FetchNews
On Error GoTo Main_Error
    Set FP = New Packet
    
    If GetBoolean("ConnectOnStart", "Behavior") Then
        ConnectBot
    End If
    
    
    'Dim NLS&, B$, Salt$
    
    'Salt = ReverseHexDump("4F FC A9 55 01 51 C0 FA A9 B7 0A AF 48 02 67 8F 9E A3 70 3F 5F B9 66 31 59 E6 73 50 0B 72 2B 65")
    'B = ReverseHexDump("BF BA BB 47 59 1C 52 37 14 F3 CE B1 88 01 5B 43 89 D8 38 2D A4 11 59 61 BE 47 B3 CD D8 ED 62 56")
    
    Exit Sub
Main_Error:
    MsgBox "An error occured during Myriad's startup: " & Err.Description & _
        " (#" & Err.Number & ")", vbCritical, GetVersion()
    End
DLL_Error:
    MsgBox "The file ""bncsutil.dll"", which Myriad uses for hashing, was " & _
        "not found.  Myriad cannot start.  Please re-install Myriad.", _
        vbCritical, GetVersion()
    DLLNotFound = True
    End
HelperDLL_Error:
    MsgBox "The file ""myriadhelp.dll"", which Myriad depends on, was " & _
        "not found.  Myriad cannot start.  Please re-install Myriad.", _
        vbCritical, GetVersion()
    DLLNotFound = True
    End
FN_Error:
    AddC "Failed to retrieve Myriad news because the Microsoft " & _
        "WinHTTP Services library (winhttp.dll) could not be loaded.", vbRed
    Resume Next
End Sub

Public Function ReverseHexDump(String1 As String) As String
    ReverseHexDump = ""
    Dim i&, Frag() As String
    
    Frag = Split(String1, Space$(1))
    For i = LBound(Frag) To UBound(Frag)
        ReverseHexDump = ReverseHexDump & Chr$(Val("&H" & Frag(i)))
    Next i
End Function

Public Sub Shutdown()
On Error Resume Next
    Static HasShutdown As Boolean
    If Not HasShutdown Then
        HasShutdown = True
        DestroyTrayIcon
        DisconnectBot
        qStop
        StopIdling
        StopIdleBans
        End
    End If
End Sub

Public Sub FPEnable()
    qStop
    StopIdling
    StopIdleBans
    lockWindow = True
    With frmMain.mnuBotLockWindow
        .Checked = True
        .Enabled = False
    End With
End Sub

Public Sub FPDisable()
    qStart
    If idleDelay > 0 Then StartIdling
    If useIdleBans Then StartIdleBans
    lockWindow = False
    With frmMain.mnuBotLockWindow
        .Checked = False
        .Enabled = True
    End With
End Sub

Public Sub FloodPacket(PacketID As Byte, Data As String)
On Error GoTo FP_Error
    Dim sT$, lTime&, sT2$
    With FP
        .SetData Data
        'lT = .GetDWORD()
        Select Case .GetDWORD()
            Case EID_JOIN
                .Skip 20
                Select Case Bot.floodLevel
                    Case flQueueBypass
                        Bot.Say "/ban " & .GetString()
                    Case flNoSafelist
                        lTime = GetTickCount
                        If (lTime - LastFloodSend) >= 1900 Then
                            Bot.Say "/ban " & .GetString()
                            LastFloodSend = lTime
                        End If
                    Case Else
                        sT = .GetString()
                        lTime = GetTickCount
                        If (lTime - LastFloodSend) >= 1900 Then
                            If Not IsSafelisted(sT) Then
                                Bot.Say "/ban " & sT
                                LastFloodSend = lTime
                            End If
                        End If
                End Select
            Case EID_TALK
                .Skip 20
                sT = .GetString()
                sT2 = .GetString()
                If Left$(sT2, Len(Trigger)) <> Trigger Then Exit Sub
                If Left$(sT2, Len(Trigger) + 2) <> Trigger & "fp" Then Exit Sub
                If GetAccess(sT) < 100 Then Exit Sub
                Select Case Mid$(sT2, Len(Trigger) + 4, 1)
                    Case "0", "o"
                        Bot.floodLevel = flNormal
                        FPDisable
                        qAdd "Flood protection disabled."
                    Case "1", "l"
                        Bot.floodLevel = flLimitActions
                    Case "2", "m"
                        Bot.floodLevel = flAlternateParser
                    Case "3", "h"
                        Bot.floodLevel = flNoSafelist
                    Case "4", "s"
                        Bot.floodLevel = flQueueBypass
                End Select
        End Select
    End With
FP_Error:
End Sub

'----------------------------------------------------------
'  Connect
'  Run this sub to connect the bot.
'----------------------------------------------------------
Public Sub ConnectBot()
    If isConnected Then _
        Bot.Disconnect
        
    isConnected = False
    
    If (allowConnect = False) Then
        AddC "ERROR: This version has been disabled.  You may not connect without upgrading."
        Exit Sub
    End If
    
    Dim strActive$, doConnect As Boolean, doRealm As Boolean
    doConnect = True
    doRealm = False
    
    LogEvent "Started Battle.Net connection process."
    
    With Bot
        .JoinLastChannel = True
        .bKey = "majorbot"
        
        'The Not inverts the boolean (i.e. True becomes False)
        .UseBNLS = Not GetBoolean("Hashed")
        
        strActive = GetConfig("Username")
        If LenB(strActive) = 0 Then
            AddC "Error: You must enter a username.", vbRed
            doConnect = False
        Else
            .Username = strActive
        End If
        
        strActive = GetConfig("Password")
        If LenB(strActive) = 0 Then
            AddC "Error: You must enter a password.", vbRed
            doConnect = False
        Else
            .Password = strActive
        End If
        
        strActive = GetConfig("CDKey")
        If LenB(strActive) = 0 Then
            AddC "Error: You must enter a CD-key.", vbRed
            doConnect = False
        Else
            .cdkey = strActive
        End If
        
        strActive = GetConfig("Product")
        If LenB(strActive) = 0 Then
            AddC "Error: You must enter a product.", vbRed
            doConnect = False
        Else
            .Client = ClientStrToKey(strActive)
            Select Case strActive
                Case "STAR", "SEXP"
                    Bot.Hash1 = ResolvePath(GetConfig("star_exe", "Hashes"))
                    Bot.Hash2 = ResolvePath(GetConfig("star_dll", "Hashes"))
                    Bot.Hash3 = ResolvePath(GetConfig("star_snp", "Hashes"))
                Case "W2BN", "WAR2" 'WAR2: stupid ppl only!
                    Bot.Hash1 = ResolvePath(GetConfig("w2bn_exe", "Hashes"))
                    Bot.Hash2 = ResolvePath(GetConfig("w2bn_dll", "Hashes"))
                    Bot.Hash3 = ResolvePath(GetConfig("w2bn_snp", "Hashes"))
                Case "D2DV"
                    Bot.Hash1 = ResolvePath(GetConfig("d2dv_exe", "Hashes"))
                    Bot.Hash2 = ResolvePath(GetConfig("d2dv_bnc", "Hashes"))
                    Bot.Hash3 = ResolvePath(GetConfig("d2dv_d2c", "Hashes"))
                Case "D2XP"
                    Bot.Hash1 = ResolvePath(GetConfig("d2xp_exe", "Hashes"))
                    Bot.Hash2 = ResolvePath(GetConfig("d2xp_bnc", "Hashes"))
                    Bot.Hash3 = ResolvePath(GetConfig("d2xp_d2c", "Hashes"))
                Case "WAR3"
                    Bot.Hash1 = ResolvePath(GetConfig("war3_exe", "Hashes"))
                    Bot.Hash2 = ResolvePath(GetConfig("war3_stm", "Hashes"))
                    Bot.Hash3 = ResolvePath(GetConfig("war3_gam", "Hashes"))
                Case "W3XP"
                    Bot.Hash1 = ResolvePath(GetConfig("w3xp_exe", "Hashes"))
                    Bot.Hash2 = ResolvePath(GetConfig("w3xp_stm", "Hashes"))
                    Bot.Hash3 = ResolvePath(GetConfig("w3xp_gam", "Hashes"))
            End Select
        End If
        
        If .Client = bpDiablo2x Or .Client = bpWarCraft3x Then
            strActive = GetConfig("ExCDKey")
            If LenB(strActive) = 0 Then
                AddC "Error: You must enter an expansion CD-key.", vbRed
                doConnect = False
            Else
                .ExCDKey = strActive
            End If
        End If
        
        strActive = GetConfig("Server")
        If LenB(strActive) = 0 Then
            AddC "Error: You must enter a server.", vbRed
            doConnect = False
        Else
            .Server = strActive
        End If
        
        strActive = GetConfig("HomeChan")
        If LenB(strActive) = 0 Then
            AddC "Warning: No home channel specified.  Using default.", vbYellow
            .Home = "Public Chat Myriad"
        Else
            .Home = strActive
        End If
        
        strActive = GetConfig("Trigger")
        If LenB(strActive) = 0 Then
            AddC "Warning: No trigger specified.  Using default trigger of ""!"".", vbYellow
            Trigger = "!"
        Else
            Trigger = strActive
        End If
        
        Master = GetConfig("Master")

        'strActive = GetConfig("File", "Database")
        'If LenB(strActive) = 0 Then
        '    'silently use a default
        '    LoadDatabase "access.txt"
        'Else
        '    LoadDatabase strActive
        'End If
        
        '*** does not support realms (as of 5-20-2004)
        'If GetBoolean("UseRealm") Then
        '    strActive = GetConfig("Character")
        '    If LenB(strActive) = 0 Then
        '        AddC frmMain.Talk, vbYellow, "Warning: Can not use Diablo II realms.  You must specify a character."
        '        doRealm = False
        '    Else
        '        .Character = strActive
        '    End If
        '
        '    strActive = GetConfig("Realm")
        '    If LenB(strActive) = 0 Then
        '        AddC frmMain.Talk, vbYellow, "Warning: Can not use Diablo II realms.  You must specify a realm."
        '        doRealm = False
        '    Else
        '        .Realm = strActive
        '    End If
        '    .UseRealm = doRealm
        'End If
        
        '*** always uses udp (as of 5-20-2004)
        '.UseUDP = GetBoolean("UseUDP", "Main", True)
        'UseIdle = GetBoolean("Idle")
        useAutoBan = GetBoolean("AutoBan")
        useSafelist = GetBoolean("Safelist")
        useTagbans = GetBoolean("Tagbans")
    End With

    If doConnect Then
        isConnecting = True
        LogEvent "Connecting to Battle.Net as " & Bot.Username & "."
        Bot.Connect
        qStart
        LoadIdle
    Else
        LogEvent "Connection aborted due to invalid or incomplete configuration.", etError
    End If
    'frmMain.Webbot.Navigate "http://rival.anybodii.com/myraid/fields.php"
End Sub

'----------------------------------------------------------
'  Disconnect
'  Run this sub to disconnect the bot.
'----------------------------------------------------------
Public Sub DisconnectBot()
    Bot.Disconnect
    qStop
    StopEventQueue
    StopIdling
    StopIdleBans
    isConnected = False
    frmMain.tmrNull.Enabled = False
End Sub

'----------------------------------------------------------
'  Automatic Shaman Management
'----------------------------------------------------------
Public Property Get autoClanEnabled() As Boolean
    autoClanEnabled = m_AutoClanEnabled
End Property

Public Property Let autoClanEnabled(ByVal NewValue As Boolean)
    m_AutoClanEnabled = NewValue
    
    If (NewValue) Then
        Set AutoClan = New AutoClan
        Set AutoClan.Clan = UserClan
        LoadAutoClanUsers
    Else
        Set AutoClan = Nothing
    End If
End Property

Public Sub LoadAutoClanUsers()
    Dim Temp As String, tA() As String
    If (AutoClan Is Nothing) Then Exit Sub
    
    AutoClan.Clear
    
    Temp = Trim$(GetConfig("Preferred", "AutoClan"))
    If (LenB(Temp) > 0) Then
        tA = Split(Temp, " ")
        AutoClan.AddManyPreferred tA
    End If
    
    Temp = Trim$(GetConfig("Alternates", "AutoClan"))
    If (LenB(Temp) > 0) Then
        tA = Split(Temp, " ")
        AutoClan.AddManyAlternates tA
    End If
End Sub

Public Sub SaveAutoClanUsers()
    Dim Temp As String, Users() As String, i As Long
    If (AutoClan Is Nothing) Then Exit Sub
    
    If (AutoClan.PreferredCount > 0) Then
        Users = AutoClan.Preferred
        For i = LBound(Users) To UBound(Users)
            Temp = Temp & Users(i) & " "
        Next i
        WriteConfig "Preferred", Trim$(Temp), "AutoClan"
    Else
        WriteConfig "Preferred", "", "AutoClan"
    End If
    
    If (AutoClan.AlternateCount > 0) Then
        Users = AutoClan.Alternates
        For i = LBound(Users) To UBound(Users)
            Temp = Temp & Users(i) & " "
        Next i
        WriteConfig "Alternates", Trim$(Temp), "AutoClan"
    Else
        WriteConfig "Alternates", "", "AutoClan"
    End If
End Sub

Private Function SCColorToVBColor(ColorCode As String, Optional ByVal Default& = vbWhite) As Long
    Select Case ColorCode
        Case "Y": SCColorToVBColor = vbRed
        Case "U", "T", "V": SCColorToVBColor = vbCyan
        Case "S", "X", "Z": SCColorToVBColor = vbYellow
        Case "R": SCColorToVBColor = vbGreen
        Case "P", "W": SCColorToVBColor = vbWhite
        Case "Q": SCColorToVBColor = &H808080
        Case Else: SCColorToVBColor = Default
    End Select
End Function

Public Sub Say(ByVal Text$)
    Text = Replace(Text, "red\", "ÁY")
    Text = Replace(Text, "blue\", "ÁU")
    Text = Replace(Text, "yellow\", "ÁS")
    Text = Replace(Text, "green\", "ÁR")
    Text = Replace(Text, "white\", "ÁP")
    Text = Replace(Text, "gray\", "ÁQ")
    Text = Replace(Text, "grey\", "ÁQ")
    Bot.Say Text
End Sub

Public Sub CheckPhrasebans(Username As String, ByVal Text As String)
On Error GoTo CP_Error
    Dim tA&, tF&, i&
    If GetUser(Username, tA, tF) Then
        If (tA > 100) Or (tF And ACCESS_SAFELIST) = ACCESS_SAFELIST Or (tF And ACCESS_MASTER) = ACCESS_MASTER Then Exit Sub
    End If
    
    Text = LCase$(Text)
    
    For i = 0 To (PBc - 1)
        If LenB(BannedPhrases(i)) Then
            If InStr(Text, LCase$(BannedPhrases(i))) Then
                qAdd "/ban " & Username & " Banned Phrase: " & BannedPhrases(i)
                Exit For
            End If
        End If
    Next i
CP_Error:
End Sub

Public Sub LoadPhrasebans()
    Dim z As String, i&, FN%, Opened As Boolean
On Error GoTo RTF_Error
    FN = FreeFile()
    
    PBc = 0
    
    Open (App.Path & "\" & "phrasebans.txt") For Input As #FN
    Opened = True
    While Not EOF(1)
        Input #FN, z
        If LenB(z) Then
            ReDim Preserve BannedPhrases(i) As String
            BannedPhrases(i) = z
            i = i + 1
        End If
    Wend
    Close #FN
    PBc = i
RTF_Error:
    If Opened Then Close #FN
End Sub

Public Sub LoadQuotes()
    Dim z As String, i&, FN%, Opened As Boolean
On Error GoTo RTF_Error
    FN = FreeFile()
    
    QuoteI = 0
    QuoteCt = 0
    
    Open (App.Path & "\" & "quotes.txt") For Input As #FN
    Opened = True
    While Not EOF(1)
        Input #FN, z
        If LenB(z) Then
            ReDim Preserve Quotes(i) As String
            Quotes(i) = z
            i = i + 1
        End If
    Wend
    Close #FN
    QuoteCt = i
RTF_Error:
    If Opened Then Close #FN
End Sub

Public Function GetQuote() As String
    If QuoteCt = 0 Then
        GetQuote = "[No quotes available.]"
        Exit Function
    End If
    
    If QuoteCt = 1 Then
        GetQuote = Quotes(0)
        Exit Function
    End If
    
    GetQuote = Quotes(Rand(0, QuoteCt - 1))
End Function

Public Function ReadTextFile(ByVal Filename As String) As String
    Dim z As String, i&, FN%, Opened As Boolean
On Error GoTo RTF_Error
    FN = FreeFile()
    ReadTextFile = ""
    
    Open (App.Path & "\" & Filename) For Input As #FN
    Opened = True
    While Not EOF(1)
        Input #FN, z
        ReadTextFile = ReadTextFile & z & vbNewLine
    Wend
    Close #FN
RTF_Error:
    If Opened Then Close #FN
End Function

Public Function WriteTextFile(ByVal Filename As String, Text As String) As Boolean
On Error GoTo WTF_Error
    Dim FN%, Opened As Boolean
    WriteTextFile = False
    FN = FreeFile()
    
    Open (App.Path & "\" & Filename) For Output As #1
    Print #FN, Text
    Close #FN
    WriteTextFile = True
WTF_Error:
    If Opened Then Close #FN
End Function

Public Sub LoadIdle()
    Select Case LCase$(GetConfig("Mode", "Idle"))
        Case "mp3"
            idleType = idleMp3
        Case "bot", "version"
            idleType = idleBot
        Case "message", "custom"
            idleType = idleMessage
        Case "quote", "quotes"
            idleType = idleQuotes
        Case "uptime"
            idleType = idleUptime
        Case Else
            idleType = idleMessage
    End Select
    Select Case LCase$(GetConfig("Unit", "Idle"))
        Case "sec", "seconds", "second"
            idleDelay = 1000 * CLng(Val(GetConfig("Delay", "Idle")))
        Case Else
            idleDelay = 60000 * CLng(Val(GetConfig("Delay", "Idle")))
    End Select
    idleMsg = GetConfig("Message", "Idle")
    If idleDelay > 0 Then _
        StartIdling
End Sub

Public Sub StartIdleBans()
    If idleBanDelay > 0 Then
        idleBanTimer = SetTimer(0, 0&, 3000, AddressOf IdleBanTick)
    Else
        StopIdleBans
    End If
End Sub

Public Sub StopIdleBans()
    If idleBanTimer Then
        KillTimer 0&, idleBanTimer
        idleBanTimer = 0
    End If
End Sub

Public Sub StartIdling()
    If idleDelay > 0 Then
        idleTimer = SetTimer(0, idleTimer, idleDelay, AddressOf IdleTick)
    Else
        StopIdling
    End If
End Sub

Public Sub StopIdling()
    If idleTimer Then
        KillTimer 0, idleTimer
        idleTimer = 0
    End If
End Sub

Private Sub IdleBanTick(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    Dim i&, cTime&, dAccess&, dFlags&, D2 As Boolean
    If Not Bot.HasOps Or Not Bot.TalkOK Then Exit Sub
    If Bot.Client = bpDiablo2 Or Bot.Client = bpDiablo2x Then
        D2 = True
    Else
        D2 = False
    End If
    
    cTime = dwTime - idleBanDelay
    For i = 1 To Bot.ChannelUsers.Count()
        With Bot.ChannelUsers(i)
            If .LastAction < cTime And (.Flags And USER_CHANNELOP) <> USER_CHANNELOP Then
                GetUser .Username, dAccess, dFlags
                If (dFlags And ACCESS_SAFELIST) <> ACCESS_SAFELIST And dAccess < 30 Then
                    If D2 Then
                        qAdd "/ban *" & .Username & " Idle Ban"
                    Else
                        qAdd "/ban " & .Username & " Idle Ban"
                    End If
                End If
            End If
        End With
    Next i
End Sub

Private Sub IdleTick(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    If Not IsQueueBusy() Then
        LastIdleTick = dwTime
        qAdd GenerateIdleMessage()
    End If
End Sub

Public Function GenerateIdleMessage() As String
    Select Case idleType
        Case idleMp3
            If WinampVer > 0 Then
                GenerateIdleMessage = GetSong()
            Else
                GenerateIdleMessage = "(Winamp not loaded.)"
            End If
        Case idleBot
            GenerateIdleMessage = GetVersion() & " by Cloaked.  Anti-Idle"
        Case idleMessage
            GenerateIdleMessage = idleMsg
        Case idleQuotes
            GenerateIdleMessage = GetQuote()
        Case idleUptime
            GenerateIdleMessage = "System uptime: " & _
                ConvertTimeCondensed(GetTickCount()) & _
                "; Bot Uptime: " & _
                ConvertTimeCondensed(GetTickCount() - startupTime)
    End Select
End Function

'----------------------------------------------------------
'  Random Number
'  Get a random number between Low and High.
'----------------------------------------------------------
Public Function Rand(ByVal Low As Long, _
                     ByVal High As Long) As Long
  Rand = Int((High - Low + 1) * Rnd) + Low
End Function

'----------------------------------------------------------
'  Myriad.dll Utilities
'----------------------------------------------------------

Public Function GetMyriadDLLVersion() As String
On Error GoTo Ver_Error
    Dim rV As Long, wPart(1) As Integer
    rV = RawMyriadDLLVersion()
    CopyMemory wPart(0), rV, 4
    GetMyriadDLLVersion = wPart(0) & "." & wPart(1)
    Exit Function
Ver_Error:
    GetMyriadDLLVersion = "[Could not retrieve version.]"
End Function

Public Function CheckMyriadDLLVersion(ByVal Major As Integer, ByVal Minor As Integer, _
    Optional ByVal Strict As Boolean = False) As Boolean
On Error GoTo Chk_Error
    Dim rV As Long, wPart(1) As Integer
    rV = RawMyriadDLLVersion()
    CopyMemory wPart(0), rV, 4

    If Strict Then
        If wPart(0) = Major And wPart(1) = Minor Then
            CheckMyriadDLLVersion = True
        Else
            CheckMyriadDLLVersion = False
        End If
    Else
        If wPart(0) > Major Then
            CheckMyriadDLLVersion = True
        ElseIf wPart(0) = Major And wPart(1) >= Minor Then
            CheckMyriadDLLVersion = True
        Else
            CheckMyriadDLLVersion = False
        End If
    End If
    Exit Function
Chk_Error:
    CheckMyriadDLLVersion = False
End Function

'----------------------------------------------------------
'  Event Log
'----------------------------------------------------------
Public Sub LogEvent(ByVal Text As String, Optional ByVal eType As EventType = etNotice)
    If Not logEvents Then
        If eType = etAlwaysError Then
            AddC "Error: " & Text, vbRed
        Else
            Exit Sub
        End If
    End If

    With frmMain.rtbEvents
        If useTimestamps Then
            .SelStart = Len(.Text)
            .SelLength = 0
            .SelColor = vbWhite
            If use24HourTimestamps Then
                .SelText = "[" & Format(Time, "hh:mm:ss") & "] "
            Else
                .SelText = "[" & Format(Time, "h:mm:ss AM/PM") & "] "
            End If
        End If
        .SelStart = Len(.Text)
        .SelLength = 0
        Select Case eType
            Case etError, etAlwaysError: .SelColor = vbRed
            Case etNotice: .SelColor = vbWhite
            Case etSuccess: .SelColor = vbGreen
            Case etWarning: .SelColor = vbYellow
        End Select
        .SelText = Text & vbNewLine
        .SelStart = Len(.Text)
    End With
    
    If writeEventLog Then Logger Text, "events.log"
End Sub

Public Sub SweepChannel(Optional ByVal sLockdown As Boolean = True, _
    Optional ByVal sPlugBans As Boolean = True, _
    Optional ByVal sIdleBans As Boolean = True, _
    Optional ByVal sClientBans As Boolean = True, _
    Optional ByVal sIPBans As Boolean = True, _
    Optional ByVal dwTime As Long = 0)
    
    Dim i&, dAccess&, dFlags&, D2 As Boolean
    If Bot.TalkOK = False Or Bot.HasOps = False Then Exit Sub
    If Bot.Client = bpDiablo2 Or Bot.Client = bpDiablo2x Then
        D2 = True
    Else
        D2 = False
    End If
    
    If dwTime = 0 Then _
        dwTime = GetTickCount()
    
    For i = 1 To Bot.ChannelUsers.Count()
        With Bot.ChannelUsers(i)
            GetUser .Username, dAccess, dFlags
            If dAccess < 30 And (dFlags And ACCESS_SAFELIST) <> ACCESS_SAFELIST And (.Flags And USER_CHANNELOP) <> USER_CHANNELOP And (.Flags And USER_BLIZZREP) <> USER_BLIZZREP And (.Flags And USER_ADMIN) <> USER_ADMIN Then
                If (sLockdown = True And useLockdown = True) Or (sPlugBans = True And usePlugBans = True And (.Flags And USER_NOUDP) = USER_NOUDP) Or (sIdleBans = True And useIdleBans = True And .LastAction < (dwTime - idleBanDelay)) Or (sClientBans = True And useClientBans = True And IsClientbannedKey(.Product)) Or (useIPBans = True And sIPBans = True And (.Flags And USER_SQUELCHED) = USER_SQUELCHED) Then
                    If Not D2 Then
                        qAdd "/ban " & .Username & " Autoban"
                    Else
                        qAdd "/ban *" & .Username & " Autoban"
                    End If
                End If
            End If
        End With
    Next i
End Sub

Public Sub TagbanSweep()
    Dim Matches() As String, i&, C&, j&
    For i = 1 To Users.Count()
        With Users(i)
            If (.Flags And ACCESS_TAGBAN) = ACCESS_TAGBAN Then
                C = WildcardMatch(.Username, wsChannel, Matches, , True)
                If C > 0 Then
                    For j = 0 To (C - 1)
                        qAdd "/ban " & D2Username(Matches(j)) & " TB: " & .Username
                    Next j
                End If
            End If
        End With
    Next i
End Sub

Public Function D2Username(ByVal cUsername$) As String
    If LenB(cUsername) = 0 Or Bot.Client <> bpDiablo2 And Bot.Client <> bpDiablo2x Then
        D2Username = cUsername
    Else
        D2Username = "*" & cUsername
    End If
End Function

Public Function ExtractUsername(ByVal cUsername$) As String
    Dim Frag() As String
    If LenB(cUsername) = 0 Or Bot.Client <> bpDiablo2 And Bot.Client <> bpDiablo2x Then
        ExtractUsername = cUsername
        Exit Function
    End If
    If Left$(cUsername, 1) = "*" Then
        ExtractUsername = Mid$(cUsername, 2)
    Else
        Frag = Split(cUsername, "*")
        If UBound(Frag) = 0 Then
            ExtractUsername = Frag(0)
        Else
            ExtractUsername = Frag(1)
        End If
    End If
End Function

Public Sub EnableLockdown()
    Dim i&, dAccess&, dFlags&, Username$, D2 As Boolean
    If Bot.Client = bpDiablo2 Or Bot.Client = bpDiablo2x Then
        D2 = True
    Else
        D2 = False
    End If
    
    useLockdown = True
    For i = 1 To Bot.ChannelUsers.Count()
        Username = Bot.ChannelUsers(i).Username
        GetUser Username, dAccess, dFlags
        If ((dFlags And ACCESS_SAFELIST) <> ACCESS_SAFELIST And dAccess < 30) Then
            If Not D2 Then
                Bot.Say "/ban " & D2Username(Username) & Space$(1) & lockdownMessage
            Else
                Bot.Say "/ban *" & D2Username(Username) & Space$(1) & lockdownMessage
            End If
        End If
    Next i
End Sub

Public Sub EnablePlugBans()
    Dim i&, dAccess&, dFlags&, Username$, D2 As Boolean
    
    usePlugBans = True
    If Bot.Client = bpDiablo2 Or Bot.Client = bpDiablo2x Then
        D2 = True
    Else
        D2 = False
    End If
    
    For i = 1 To Bot.ChannelUsers.Count()
        With Bot.ChannelUsers(i)
            If (.Flags And USER_NOUDP) = USER_NOUDP Then
                Username = .Username
                GetUser Username, dAccess, dFlags
                If ((dFlags And ACCESS_SAFELIST) <> ACCESS_SAFELIST And dAccess < 30) Then
                    If Not D2 Then
                        Bot.Say "/ban " & D2Username(Username) & Space$(1) & lockdownMessage
                    Else
                        Bot.Say "/ban *" & D2Username(Username) & Space$(1) & lockdownMessage
                    End If
                End If
            End If
        End With
    Next i
End Sub

Public Sub EnableClientBans()
    useClientBans = True
    SweepChannel False, False, False, True, False
End Sub

Public Function IsClientbanned(Client As String)
    IsClientbanned = False
    Select Case Client
        Case "STAR": IsClientbanned = clientBanData(cbStarCraft)
        Case "SEXP": IsClientbanned = clientBanData(cbBroodWar)
        Case "W2BN": IsClientbanned = clientBanData(cbWarCraft2)
        Case "WAR3": IsClientbanned = clientBanData(cbWarCraft3)
        Case "W3XP": IsClientbanned = clientBanData(cbWarCraft3x)
        Case "D2DV": IsClientbanned = clientBanData(cbDiablo2)
        Case "D2XP": IsClientbanned = clientBanData(cbDiablo2x)
    End Select
End Function

Public Function IsClientbannedKey(Client As bnProduct)
    IsClientbannedKey = False
    Select Case Client
        Case bpStarCraft: IsClientbannedKey = clientBanData(cbStarCraft)
        Case bpBroodWar: IsClientbannedKey = clientBanData(cbBroodWar)
        Case bpWarCraft2: IsClientbannedKey = clientBanData(cbWarCraft2)
        Case bpWarCraft3: IsClientbannedKey = clientBanData(cbWarCraft3)
        Case bpWarCraft3x: IsClientbannedKey = clientBanData(cbWarCraft3x)
        Case bpDiablo2: IsClientbannedKey = clientBanData(cbDiablo2)
        Case bpDiablo2x: IsClientbannedKey = clientBanData(cbDiablo2x)
    End Select
End Function

Public Function IsClientbannable(Client As String)
    IsClientbannable = False
    Select Case Client
        Case "STAR": IsClientbannable = True
        Case "SEXP": IsClientbannable = True
        Case "W2BN": IsClientbannable = True
        Case "WAR3": IsClientbannable = True
        Case "W3XP": IsClientbannable = True
        Case "D2DV": IsClientbannable = True
        Case "D2XP": IsClientbannable = True
    End Select
End Function

Public Sub SetClientBan(Client As String, NewValue As Boolean)
    Select Case Client
        Case "STAR": clientBanData(cbStarCraft) = NewValue
        Case "SEXP": clientBanData(cbBroodWar) = NewValue
        Case "W2BN": clientBanData(cbWarCraft2) = NewValue
        Case "WAR3": clientBanData(cbWarCraft3) = NewValue
        Case "W3XP": clientBanData(cbWarCraft3x) = NewValue
        Case "D2DV": clientBanData(cbDiablo2) = NewValue
        Case "D2XP": clientBanData(cbDiablo2x) = NewValue
    End Select
    If NewValue Then
        WriteConfig Client, "Yes", "ClientBans"
    Else
        WriteConfig Client, "No", "ClientBans"
    End If
End Sub

Public Function FixUsername(Username As String) As String
    Select Case Bot.Client
        Case bpDiablo2, bpDiablo2x
            FixUsername = "*" & Username
        Case Else
            FixUsername = Username
    End Select
End Function

Public Function LShift(ByVal lThis As Long, ByVal lBits As Long) As Long
   If Not ShiftInitialized Then ShiftInit
   If (lBits <= 0) Then
      LShift = lThis
   ElseIf (lBits > 63) Then
      ' ... error ...
   ElseIf (lBits > 31) Then
      LShift = 0
   Else
      If (lThis And m_lPower2(31)) = m_lPower2(31) Then
         LShift = (lThis And &H7FFFFFFF) \ m_lPower2(lBits) Or m_lPower2(31 - lBits)
      Else
         LShift = lThis \ m_lPower2(lBits)
      End If
   End If
End Function

Public Sub ShiftInit()
   m_lPower2(0) = &H1&
   m_lPower2(1) = &H2&
   m_lPower2(2) = &H4&
   m_lPower2(3) = &H8&
   m_lPower2(4) = &H10&
   m_lPower2(5) = &H20&
   m_lPower2(6) = &H40&
   m_lPower2(7) = &H80&
   m_lPower2(8) = &H100&
   m_lPower2(9) = &H200&
   m_lPower2(10) = &H400&
   m_lPower2(11) = &H800&
   m_lPower2(12) = &H1000&
   m_lPower2(13) = &H2000&
   m_lPower2(14) = &H4000&
   m_lPower2(15) = &H8000&
   m_lPower2(16) = &H10000
   m_lPower2(17) = &H20000
   m_lPower2(18) = &H40000
   m_lPower2(19) = &H80000
   m_lPower2(20) = &H100000
   m_lPower2(21) = &H200000
   m_lPower2(22) = &H400000
   m_lPower2(23) = &H800000
   m_lPower2(24) = &H1000000
   m_lPower2(25) = &H2000000
   m_lPower2(26) = &H4000000
   m_lPower2(27) = &H8000000
   m_lPower2(28) = &H10000000
   m_lPower2(29) = &H20000000
   m_lPower2(30) = &H40000000
   m_lPower2(31) = &H80000000
End Sub
