Attribute VB_Name = "DataBot"
Option Explicit

'The spawn function

Public Sub SpawnBot(ParentBot As Integer, Bot_Type As BOT_FLAVORS, User As String)
On Error GoTo FlyPaper

    Dim I As Integer, O As String

    O = GetTypeString(Bot_Type)

    'On the first run, SocketData = remote server
    If ParentBot > 0 Then
        SocketData = UDPMakeSocket(0)
        SocketData.Remote = BotList(ParentBot).MySession.Remote
    End If

    AddDebug ParentBot, "CREATING SPAWN: " + User + " (" + O + ")", GREEN

    For I = 1 To MAX_BOTS
        If BotList(I).SlotClosed = 0 Then
            With BotList(I)
                AddDebug I, "Respawned as " + O, BLACK
                .MyName = User
                .Bot_Enabled = 0
                .Bot_Type = Bot_Type
                If ParentBot = 0 Then
                    .ArenaName = GetProfileString("Login", "DefaultArena")
                Else
                    .ArenaName = BotList(ParentBot).ArenaName
                End If
                .AttachedTo = -1
                .CenteredOn = -1
                LastPacketID(I) = -1
                .SlotClosed = 1
                .TimerMax = 30
                .MySession = SocketData
                If Bot_Type = SARUNOKAMI_REF Then SetupSettings I
                ConnectBot I
                Exit Sub
            End With
        End If
    Next

Exit Sub
FlyPaper:
    AddDebug ParentBot, "Error detected in SpawnBot(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub ConnectBot(BotID As Integer)
    UDPSend BotID, Chr(0) + Chr(1) + GetString(0) + Chr(1) + Chr(0), False

    AddDebug BotID, "CONNECTING [" + Long2IP(BotList(BotID).MySession.Remote.sin_addr) + " : " + CStr(ntohs(BotList(BotID).MySession.Remote.sin_port)) + "]", GREEN
End Sub

Public Function NextSID(BotID As Integer) As String
    NextSID = GetString(BotList(BotID).LastSID)
    BotList(BotID).LastSID = BotList(BotID).LastSID + 1
End Function

Public Function FindBot(SockID As Long) As Integer
    Dim I As Integer

    For I = 1 To MAX_BOTS
        If BotList(I).MySession.SockID = SockID Then FindBot = I: Exit Function
    Next
End Function

Public Sub UnloadBot(BotID As Integer, FromPlayer As Boolean)
On Error GoTo FlyPaper

    Dim I As Integer, L As Long

    For I = 1 To MAX_BOTS
        If I <> BotID And BotList(I).SlotClosed = 1 Then GoTo FoundOne
    Next
    AddDebug 0, "All bots offline", RED

FoundOne:
    LeaveServer BotID

    If FromPlayer = True Then
        AddDebug BotID, "SPAWN SHUTDOWN BY OPERATOR", RED
    Else
        AddDebug BotID, "SPAWN UNLOADED", RED
    End If

    With BotList(BotID)
        UDPDestroySocket .MySession
        ClearSecures BotID
        ClearBacklog BotID
        ClearACKs BotID
        For I = 0 To MAX_PLAYERS
            .pList(I).OpID = 0
            .pList(I).SSName = ""
        Next
        .SlotClosed = 0
        .Periodic = 0
        .PrizeEnabled = 0
        .PrizeCounter = 0
        .PrizeNumber = 0
        .PrizeWait = 0
        .ArenaName = ""
        .Bot_Enabled = 0
        .Bot_Type = 0
        .LastSID = 0
        .TotalLost = 0
        .TotalPings = 0
        .TotalReliable = 0
        .TotalSent = 0
        .TotalReceived = 0
        .KeepAliveCount = 0
        .AvgPing = 0
        .MaxDeaths = 0
        .MyId = 0
        .MySession.SockID = 0
        .Suicide = 0
        .AutoSpec = 0
        .LockShip = 0
        .KillPrize = 0
        .ErrorChannel = ""
        .LogScores = 0
        .D = 0
        .DownloadingSettings = 0
    End With

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in UnloadBot(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub UnloadAllBots()
    Dim I As Integer

    For I = 1 To MAX_BOTS
        If BotList(I).SlotClosed = 1 Then
            LeaveServer I
            UDPDestroySocket BotList(I).MySession
        End If
    Next
End Sub

'Operator dbase functions

Public Function FindOperator(ByVal Username As String) As Byte
    Dim B As Byte

    Username = LCase(Username)
    For B = 1 To TotalOps
        If OpList(B).Username = Username Then FindOperator = CByte(B): Exit Function
    Next
End Function

Public Sub AddOp(BotID As Integer, Username As String, AccessLevel As ALLOW)
    Dim I As Integer

    If TotalOps = MAX_OPS Then Exit Sub

    TotalOps = TotalOps + 1
    OpList(TotalOps).Username = LCase(Username)
    OpList(TotalOps).OperatorStatus = AccessLevel

    If BotID > 0 Then
        I = FindUser(BotID, Username)
        If I > -1 Then BotList(BotID).pList(I).OpID = TotalOps
    End If

    AddDebug 0, "Operator status changed: " + Username + " @ " + OpKey(AccessLevel), BLACK
End Sub

Public Sub DelOp(BotID As Integer, OpID As Byte)
    Dim I As Integer

    AddDebug 0, "Operator status changed: " + OpList(OpID).Username + " stripped", BLACK
    For I = OpID To TotalOps
        OpList(I) = OpList(I + 1)
    Next
    TotalOps = TotalOps - 1
End Sub

Public Sub SaveOpList(Filename As String)
Dim I As Integer, O As String, F As Integer: F = FreeFile

On Error GoTo ErrHandler

        Open Filename For Output As #F
        Print #F, "Last updated: " + CStr(Date)
        Print #F, "Key: S:Sysops(SuperOp), A:SMods(AccountOp), I:Mods(SimpleOp)"
        For I = 1 To TotalOps
            Select Case OpList(I).OperatorStatus
                Case ALLOW.OP_SIMPLE: O = "I:"
                Case ALLOW.OP_ACCOUNT: O = "A:"
                Case ALLOW.OP_SUPER: O = "S:"
            End Select
            Print #F, O + OpList(I).Username
        Next

ErrHandler: Close #F
End Sub

Public Sub LoadOpList(Filename As String)
Dim O As String, F As Integer: F = FreeFile

On Error GoTo ErrHandler

        Open Filename For Input As #F
        Do
            Line Input #F, O
            Select Case Left(O, 2)
                Case "I:": AddOp 0, Mid(O, 3), OP_SIMPLE
                Case "A:": AddOp 0, Mid(O, 3), OP_ACCOUNT
                Case "S:": AddOp 0, Mid(O, 3), OP_SUPER
            End Select
        Loop

ErrHandler: Close #F
End Sub

Public Function GetOpList(ShowOnlineOnly As Boolean) As String
    Dim O As String, I As Integer

    If ShowOnlineOnly Then
        For I = 1 To TotalOps
            If OpList(I).Online = 1 Then O = O + OpKey(OpList(I).OperatorStatus) + "*" + OpList(I).Username + ", "
        Next
    Else
        For I = 1 To TotalOps
            If OpList(I).Online = 1 Then
                O = O + OpKey(OpList(I).OperatorStatus) + "#" + OpList(I).Username + ", "
            Else
                O = O + OpKey(OpList(I).OperatorStatus) + ":" + OpList(I).Username + ", "
            End If
        Next
    End If

    If O <> "" Then O = Left(O, Len(O) - 2)

    GetOpList = O
End Function

'Player database management

Public Function FindUser(BotID As Integer, ByVal Username As String) As Integer
    Dim I As Integer

    Username = LCase(Username)
    FindUser = -1
    For I = 0 To MAX_PLAYERS
        If Username = LCase(BotList(BotID).pList(I).SSName) Then FindUser = I: Exit Function
    Next
End Function

Public Sub AddUser(BotID As Integer, UserID As Integer, Username As String, Squad As String, Freq As Integer, ShipType As Byte, Wins As Integer, Losses As Integer, Points As Long)
    Dim B As Byte

    If UserID > MAX_PLAYERS Then
        AddDebug BotID, "Error: " + Username + "'s ID (" + CStr(UserID) + ") is OOB", RED
    End If

    With BotList(BotID).pList(UserID)
        .SSName = Username
        .Squad = LCase(Squad)
        .Frequency = Freq
        .ShipType = ShipType
        .Wins = Wins
        .Losses = Losses
        .Points = Points

        B = FindOperator(Username)
        .OpID = B
        If B > 0 Then OpList(B).Online = 1
    End With

    With BotList(BotID)
        If .Bot_Enabled = 1 Then
            If .Bot_Type = ELIM_REF Or .Bot_Type = ZOMBIES_REF Or .Bot_Type = CONQUER_REF Or .Bot_Type = BOUNTYGAME_REF Then
                Dim O As String, I As Integer
                If IsPublicArena(.ArenaName) Then
                    O = "Welcome. " + GetState(BotID) + ". Send !help for info"
                Else
                    O = "Welcome to " + .ArenaName + "! " + GetState(BotID) + ". Send !help for info"
                End If
                For I = 1 To Len(O) Step 89
                    PrivateMessage BotID, UserID, Mid(O, I, 89), 0
                Next
            End If
        ElseIf HasSysop = True And .Bot_Type = ALIAS_REF Then
            PrivateMessage BotID, UserID, "*info", 0
        End If

        .TotalPlayers = .TotalPlayers + 1
    End With

    HandleShipChanges BotID, UserID
    UpdateTitlebar BotID
End Sub

Public Sub DelUser(BotID As Integer, UserID As Integer)
    With BotList(BotID).pList(UserID)
        .SSName = ""
        If .OpID > 0 Then OpList(.OpID).Online = 0
        BotList(BotID).TotalPlayers = BotList(BotID).TotalPlayers - 1
    End With
    UpdateTitlebar BotID
End Sub

Public Sub DeleteAllUsers(BotID As Integer)
    Dim I As Integer

    For I = 0 To MAX_PLAYERS
        With BotList(BotID).pList(I)
            If .SSName <> "" Then
                .SSName = ""
                If .OpID > 0 Then OpList(.OpID).Online = 0
                BotList(BotID).TotalPlayers = BotList(BotID).TotalPlayers - 1
            End If
        End With
    Next
    UpdateTitlebar BotID
End Sub

'List management

Public Function FindItem(BotID As Integer, ByVal ItemName As String) As Byte
    Dim B As Byte

    ItemName = LCase(ItemName)
    If TotalItems(BotID) = 0 Then Exit Function
    For B = 1 To TotalItems(BotID)
        If ItemName = SharedList(BotID, B) Then FindItem = B: Exit Function
    Next
End Function

Public Sub AddItem(BotID As Integer, ItemName As String)
    If TotalItems(BotID) = MAX_SHARES Then Exit Sub

    TotalItems(BotID) = TotalItems(BotID) + 1
    SharedList(BotID, TotalItems(BotID)) = LCase(ItemName)

    Select Case BotList(BotID).Bot_Type
        Case BOT_FLAVORS.SWZ_REF: IncrementCount ItemName
    End Select
End Sub

Public Sub DelItem(BotID As Integer, ItemID As Byte)
    Dim I As Integer

    For I = ItemID To TotalItems(BotID)
        SharedList(BotID, I) = SharedList(BotID, I + 1)
    Next
    TotalItems(BotID) = TotalItems(BotID) - 1
End Sub

Public Function GetItemList(BotID As Integer) As String
    Dim O As String, I As Integer

    For I = 1 To TotalItems(BotID)
        O = O + SharedList(BotID, I) + ", "
    Next
    If O <> "" Then O = Left(O, Len(O) - 2)

    GetItemList = O
End Function

'Queued chat messages

Public Sub AddQueue(BotID As Integer, Message As String)
    Dim I As Integer

    If BotList(BotID).UseQueue = 0 Or HasSysop = True Then
        UDPSend BotID, Message, True
        BotList(BotID).UseQueue = 1
    Else
        For I = 1 To MAX_QUEUED
            If BotList(BotID).QueuedMessages(I) = "" Then BotList(BotID).QueuedMessages(I) = Message: Exit Sub
        Next
    End If
End Sub

Public Sub SendQueue()
    Dim I As Integer, I2 As Integer

    For I = 1 To MAX_BOTS

        With BotList(I)
            If .SlotClosed = 1 Then

                For I2 = 1 To MAX_QUEUED
                    If .QueuedMessages(I2) <> "" Then
                        UDPSend I, .QueuedMessages(I2), True
                        .QueuedMessages(I2) = ""
                        BotList(I).UseQueue = 1
                        GoTo NextBot
                    End If
                Next
                BotList(I).UseQueue = 0

NextBot:

            End If
        End With

    Next
End Sub

'Capital ship counts

Public Sub CheckDate(Username As String)
    If Day(Now) <> Val(GetProfileString("Capital Ship Date", Username)) Then
        SetProfileString "Capital Ship Count", Username, "0"
        SetProfileString "Capital Ship Date", Username, Day(Now)
    End If
End Sub

Public Function GetTotal(Username As String) As Integer
    GetTotal = Val(GetProfileString("Capital Ship Total", Username))
End Function

Public Function GetCount(Username As String) As Integer
    CheckDate Username

    GetCount = Val(GetProfileString("Capital Ship Count", Username))
End Function

Public Sub IncrementCount(Username As String)
    CheckDate Username

    SetProfileString "Capital Ship Count", Username, CStr(Val(GetProfileString("Capital Ship Count", Username)) + 1)
    SetProfileString "Capital Ship Total", Username, CStr(Val(GetProfileString("Capital Ship Total", Username)) + 1)
End Sub

'Game status

Public Sub SetState(BotID As Integer, Bot_State As GAME_STATUS)
    BotList(BotID).Bot_Status = Bot_State
End Sub

Public Function GetRules(BotID As Integer) As String
    With BotList(BotID)
        Select Case .Bot_Type
            Case BOT_FLAVORS.ELIM_REF
                If .Bot_Enabled = 1 Then
                    If .Bot_Status <> VOTE_GAME And .Bot_Status <> CHECK Then
                        Select Case .GameType
                            Case ELIM_TYPE.JavElim:  GetRules = "All on own freqs. Die " + CStr(.MaxDeaths) + " times and you are out. Last player wins"
                            Case ELIM_TYPE.JavRace:  GetRules = "All on own freqs. Kill " + CStr(.MaxDeaths) + " times and you are the winner"
                            Case ELIM_TYPE.Race:     GetRules = "All on own freqs. Kill " + CStr(.MaxDeaths) + " times and you are the winner"
                            Case ELIM_TYPE.TeamElim: GetRules = "All on even teams. Die " + CStr(.MaxDeaths) + " times and you are out. Last player wins"
                            Case ELIM_TYPE.Vanilla:  GetRules = "All on own freqs. Die " + CStr(.MaxDeaths) + " times and you are out. Last player wins"
                            Case ELIM_TYPE.WBElim:   GetRules = "All on own freqs. Die " + CStr(.MaxDeaths) + " times and you are out. Last player wins"
                            Case ELIM_TYPE.WBRace:   GetRules = "All on own freqs. Kill " + CStr(.MaxDeaths) + " times and you are the winner"
                            Case ELIM_TYPE.GolfElim: GetRules = "All on own freqs. Start with 1 point. Kill to gain a point. Die to lose a point. Lose all points are you are out"
                        End Select
                    Else
                        GetRules = "A game has not been selected yet"
                    End If
                Else
                    GetRules = "The Elim'Ref is not enabled"
                End If
            Case BOT_FLAVORS.DSB_REF
                GetRules = "Freq0 uses ships 1 2 3 4, Freq1 uses ships 5 6 7 8"
            Case BOT_FLAVORS.SWZ_REF
                GetRules = "Freq0 uses ships 1 2 3, Freq1 uses ships 4 5 6, Ships 7 and 8 are capital ships - one per team"
            Case BOT_FLAVORS.BOUNTYGAME_REF
                GetRules = "One player is chosen at random to be a BountyRabbit(with 5k bty). Players who kill him become BountyRabbits"
            Case BOT_FLAVORS.CONQUER_REF
                GetRules = "Each player on own freq. Die and you are captured to your killer's freq. Player who 0wns all others wins"
            Case BOT_FLAVORS.ZOMBIES_REF
                GetRules = "All players start on freq 0 as humans. One player changes to freq 1 as zombie. Die once and you become zombie. Last human wins"
        End Select
    End With
End Function

Public Function GetState(BotID As Integer) As String
With BotList(BotID)
    If .Bot_Enabled = 0 Then
        GetState = .MyName + "(" + BotNames(.Bot_Type) + ") is offline"
    Else
        If .Bot_Type = BOUNTYGAME_REF Then
            If .BountyID <> -1 Then
                GetState = "Current BountyRabbit(tm): " + .pList(.BountyID).SSName
            Else
                GetState = "BountyRabbit will start when two players enter"
            End If
        ElseIf .Bot_Type = CONQUER_REF Then
            Select Case .Bot_Status
            Case GAME_STATUS.CHECK:   GetState = "Conquer will start when 4 players enter"
            Case GAME_STATUS.WAIT:    GetState = "Conquer will start in " + CStr(20 - .TimerCounter) + " seconds"
            Case GAME_STATUS.STARTED: GetState = "We are playing conquer"
            End Select
        ElseIf .Bot_Type = ELIM_REF Then
            Select Case .Bot_Status
            Case GAME_STATUS.CHECK
                GetState = "Elim will start when 2 players enter"
            Case GAME_STATUS.STARTED
                Select Case .GameType
                Case ELIM_TYPE.Vanilla:  GetState = "We are playing Elimination to " + CStr(.MaxDeaths) + "; " + CStr(TotalItems(BotID)) + " left"
                Case ELIM_TYPE.Race:     GetState = "We are playing Race to " + CStr(.MaxDeaths) + "."
                Case ELIM_TYPE.WBElim:   GetState = "We are playing Warbird Elimination to " + CStr(.MaxDeaths) + "; " + CStr(TotalItems(BotID)) + " left"
                Case ELIM_TYPE.WBRace:   GetState = "We are playing Warbird Race to " + CStr(.MaxDeaths) + "."
                Case ELIM_TYPE.JavElim:  GetState = "We are playing Javelin Elimination to " + CStr(.MaxDeaths) + "; " + CStr(TotalItems(BotID)) + " left"
                Case ELIM_TYPE.JavRace:  GetState = "We are playing Javelin Race to " + CStr(.MaxDeaths) + "."
                Case ELIM_TYPE.TeamElim: GetState = "We are playing Team Elimination to " + CStr(.MaxDeaths) + "; " + CStr(TotalItems(BotID)) + " left"
                Case ELIM_TYPE.GolfElim: GetState = "We are playing Golf Elimination up to " + CStr(.MaxDeaths) + " points; " + CStr(TotalItems(BotID)) + " left"
                End Select
            Case GAME_STATUS.VOTE_GAME
                GetState = "Voting on what game to play next: 1-Elim,2-Race,3-WBElim,4-WBRace,5-JavElim,6-JavRace,7-TeamElim,8-Golf"
            Case GAME_STATUS.VOTE_DEATHS
                Select Case .GameType
                Case ELIM_TYPE.Vanilla:  GetState = "We are playing Elimination. Vote: number of deaths? (1-10)"
                Case ELIM_TYPE.Race:     GetState = "We are playing Race. Vote: number of deaths? (1-10)"
                Case ELIM_TYPE.WBElim:   GetState = "We are playing Warbird Elimination. Vote: number of deaths? (1-10)"
                Case ELIM_TYPE.WBRace:   GetState = "We are playing Warbird Race. Vote: number of deaths? (1-10)"
                Case ELIM_TYPE.JavElim:  GetState = "We are playing Javelin Elimination. Vote: number of deaths? (1-10)"
                Case ELIM_TYPE.JavRace:  GetState = "We are playing Javelin Race. Vote: number of deaths? (1-10)"
                Case ELIM_TYPE.TeamElim: GetState = "We are playing Team Elimination. Vote: number of deaths? (1-10)"
                Case ELIM_TYPE.GolfElim: GetState = "We are playing Golf Elimination. Vote: max number of points? (1-10)"
                End Select
            Case GAME_STATUS.WAIT_AFTER_RESULTS
                Select Case .GameType
                Case ELIM_TYPE.Vanilla:  GetState = "We are playing Elimination to " + CStr(.MaxDeaths) + "; Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                Case ELIM_TYPE.Race:     GetState = "We are playing Race to " + CStr(.MaxDeaths) + ". Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                Case ELIM_TYPE.WBElim:   GetState = "We are playing Warbird Elimination to " + CStr(.MaxDeaths) + "; Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                Case ELIM_TYPE.WBRace:   GetState = "We are playing Warbird Race to " + CStr(.MaxDeaths) + ". Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                Case ELIM_TYPE.JavElim:  GetState = "We are playing Javelin Elimination to " + CStr(.MaxDeaths) + "; Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                Case ELIM_TYPE.JavRace:  GetState = "We are playing Javelin Race to " + CStr(.MaxDeaths) + ". Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                Case ELIM_TYPE.TeamElim: GetState = "We are playing Team Elimination to " + CStr(.MaxDeaths) + "; Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                Case ELIM_TYPE.GolfElim: GetState = "We are playing Golf Elimination up to " + CStr(.MaxDeaths) + " points; Next game will start in " + CStr(10 - .TimerCounter) + " seconds"
                End Select
            End Select
        ElseIf .Bot_Type = ZOMBIES_REF Then
            Select Case .Bot_Status
            Case GAME_STATUS.CHECK:   GetState = "Zombies will start when 3 players enter"
            Case GAME_STATUS.STARTED: GetState = "We are playing zombies; " + CStr(TotalItems(BotID)) + " humans left"
            Case GAME_STATUS.WAIT:    GetState = "Waiting for someone to become the first zombie on freq 1"
            Case GAME_STATUS.PAUSE:   GetState = "Zombies will start in " + CStr(20 - .TimerCounter) + " seconds"
            End Select
        End If
    End If
End With
End Function

'Ranking statistics

Public Function GetRankString(PlayerName As String) As String
    Dim L As Long, L2 As Long, Better As Long, D As Double, D2 As Double, S As String, Counter As Long, Found As Boolean

    S = LCase(PlayerName)

    For L = 1 To TotalRanked
        If RankedPlayers(L).SSName = S Then Found = True: Exit For
    Next

    If Not Found Then
        GetRankString = "No record for " + PlayerName
        Exit Function
    End If

    D = RankedPlayers(L).GamesWon / RankedPlayers(L).GamesPlayed
    L2 = RankedPlayers(L).Wins - RankedPlayers(L).Losses

    For Counter = 1 To TotalRanked
        With RankedPlayers(Counter)
            If .GamesWon > RankedPlayers(L).GamesWon Then
                Better = Better + 1
            ElseIf .GamesWon = RankedPlayers(L).GamesWon Then
                D2 = .GamesWon / .GamesPlayed
                If D2 > D Then
                    Better = Better + 1
                ElseIf D2 = D And .Wins - .Losses > L2 Then
                    Better = Better + 1
                End If
            End If
        End With
    Next

    GetRankString = PlayerName + " - W/L: " + CStr(RankedPlayers(L).Wins) + "/" + CStr(RankedPlayers(L).Losses) + ", Games won: " + CStr(RankedPlayers(L).GamesWon) + " of " + CStr(RankedPlayers(L).GamesPlayed) + ", Ranked #" + CStr(Better + 1) + " of " + CStr(TotalRanked)
End Function

Public Sub UpdateRank(ByVal PlayerName As String, Won As Boolean, Wins As Integer, Losses As Integer)
    Dim L As Long

    PlayerName = LCase(PlayerName)

    For L = 1 To TotalRanked
        If RankedPlayers(L).SSName = PlayerName Then
            With RankedPlayers(L)
                .GamesPlayed = .GamesPlayed + 1
                If Won = True Then .GamesWon = .GamesWon + 1
                .Wins = .Wins + Wins
                .Losses = .Losses + Losses
            End With
            Exit Sub
        End If
    Next

    TotalRanked = TotalRanked + 1
    With RankedPlayers(TotalRanked)
        .SSName = PlayerName
        .GamesPlayed = 1
        If Won = True Then .GamesWon = 1
        .Wins = Wins
        .Losses = Losses
    End With
End Sub

Public Sub LoadRankList(Filename As String)
    Dim S As String, F As Integer: F = FreeFile

On Error GoTo ErrHandler

    Open Filename For Input As #F
    Do
        Line Input #F, S
        If Left(S, 2) = "R:" Then
            TotalRanked = TotalRanked + 1
            RankedPlayers(TotalRanked) = GetRankEntry(Mid(S, 3))
            If RankedPlayers(TotalRanked).GamesPlayed = 0 Then TotalRanked = TotalRanked - 1
        End If
    Loop

ErrHandler: Close #F

    AddDebug 0, "Elimination rankings loaded. " + CStr(TotalRanked) + " entries", BLUE
End Sub

Public Sub SaveRankList(Filename As String)
    Dim L As Long, F As Integer: F = FreeFile

On Error GoTo ErrHandler

    Open Filename For Output As #F
    Print #F, "Last updated: " + CStr(Date)
    For L = 1 To TotalRanked
        With RankedPlayers(L)
            Print #F, "R:" + .SSName + ":" + CStr(.Wins) + ":" + CStr(.Losses) + ":" + CStr(.GamesWon) + ":" + CStr(.GamesPlayed)
        End With
    Next

ErrHandler: Close #F
End Sub

Public Function GetRankEntry(RawText As String) As RankedPlayer
    '"Catid":<Wins>:<Losses>:<Games Won>:<Games Participated>
    Dim Find(1 To 4) As Integer, I As Integer, Counter As Byte, Result As RankedPlayer

    For I = Len(RawText) To 1 Step -1
        If Mid(RawText, I, 1) = ":" Then
            Counter = Counter + 1
            Find(Counter) = I
            If Counter = 4 Then Exit For
        End If
    Next

    Result.SSName = LCase(Left(RawText, Find(4) - 1))
    Result.Wins = Val(Mid(RawText, Find(4) + 1, Find(3) - Find(4) - 1))
    Result.Losses = Val(Mid(RawText, Find(3) + 1, Find(2) - Find(3) - 1))
    Result.GamesWon = Val(Mid(RawText, Find(2) + 1, Find(1) - Find(2) - 1))
    Result.GamesPlayed = Val(Mid(RawText, Find(1) + 1))

    GetRankEntry = Result
End Function

'Player aliasing

Public Sub LoadAliasList(Filename As String)
    Dim S As String, I As Integer, F As Integer: F = FreeFile

On Error GoTo ErrHandler

    Open Filename For Input As #F
    Do
        Line Input #F, S
        TotalAliases = TotalAliases + 1
        Alias(TotalAliases).User = LCase(Left(S, InStr(1, S, vbTab) - 1))
            S = Mid(S, InStr(1, S, vbTab) + 1)
        Alias(TotalAliases).IP = Left(S, InStr(1, S, vbTab) - 1)
            S = Mid(S, InStr(1, S, vbTab) + 1)
        Alias(TotalAliases).Created = Left(S, InStr(1, S, vbTab) - 1)
            S = Mid(S, InStr(1, S, vbTab) + 1)
        I = InStr(1, S, vbTab)
        If I > 0 Then
            Alias(TotalAliases).Id = Left(S, I - 1)
        Else
            Alias(TotalAliases).Id = S
        End If
    Loop

ErrHandler: Close #F

    AddDebug 0, "Player data loaded. " + CStr(TotalAliases) + " logged aliases", BLUE
End Sub

Public Sub SaveAliasList(Filename As String)
    Dim L As Long, F As Integer: F = FreeFile

On Error GoTo ErrHandler

    Open Filename For Output As #F
    For L = 1 To TotalAliases
        With Alias(L)
            Print #F, .User + vbTab + .IP + vbTab + .Created + vbTab + .Id
        End With
    Next

ErrHandler: Close #F
End Sub

Public Sub Collect(RawText As String)
With Downloading
    Dim I As Integer, I2 As Integer

    '  IP:63.204.133.97  TimeZoneBias:
    '  TimeZoneBias:480  Freq:
    '  TypedName:Team Cheerio!  Demo:
    '  MachineId:880904107  DeathsLeft:
    '  Created: 5-20-2000 05:27:16  Bytes/Sec:

    'Get IP
    I = InStr(1, RawText, "IP:")
    If I > 0 Then
        I2 = InStr(I, RawText, "  TimeZoneBias:")
        If I2 > 0 Then
            .IP = Mid(RawText, I + 3, I2 - I - 3)
        Else
            .IP = Mid(RawText, I + 3)
        End If
    End If

    'Get Username
    I = InStr(1, RawText, "TypedName:")
    If I > 0 Then
        I2 = InStr(I, RawText, "  Demo:")
        If I2 > 0 Then
            .User = Mid(RawText, I + 10, I2 - I - 10)
        Else
            .User = Mid(RawText, I + 10)
        End If
    End If

    'Get MacId
    I = InStr(1, RawText, "MachineId:")
    If I > 0 Then
        I2 = InStr(I, RawText, "  TimeZoneBias:")
        If I2 > 0 Then
            .Id = Mid(RawText, I + 10, I2 - I - 10)
        Else
            .Id = Mid(RawText, I + 10)
        End If
    End If

    'Get Creation Date
    I = InStr(1, RawText, "Created: ")
    If I > 0 Then
        I2 = InStr(I, RawText, "  Bytes/Sec:")
        If I2 > 0 Then
            .Created = Mid(RawText, I + 9, I2 - I - 9)
        Else
            .Created = Mid(RawText, I + 9)
        End If
        I2 = InStr(1, .Created, " ")
        If I2 > 0 Then .Created = Left(.Created, I2 - 1)
    End If

    'Check for completion
    If .Created <> "" And .Id <> "" And .IP <> "" And .User <> "" Then
        Dim Found As Boolean

        .User = LCase(.User)

        For I = 1 To TotalAliases
            If Alias(I).User = .User And Alias(I).Id = .Id Then Found = True: Exit For
        Next

        If Not Found Then
            TotalAliases = TotalAliases + 1
            Alias(TotalAliases) = Downloading
        End If

        .Created = "": .Id = "": .IP = "": .User = ""
    End If
End With
End Sub

'User must be in lower case
Public Function KnownName(User As String) As Integer
    Dim I As Integer

    For I = 1 To TotalAliases
        If Alias(I).User = User Then
            KnownName = I
            Exit Function
        End If
    Next

    KnownName = 0
End Function

Public Function FindAliases(ByVal User As String) As String
    Dim I As Integer, MyId As Integer, FoundIndex As Integer, O As String, Found As Boolean
    Dim MatchesFound(1 To 5000) As Integer, TotalFound As Integer

    User = LCase(User)

    For MyId = 1 To TotalAliases
        If Alias(MyId).User = User Then
            For I = 1 To TotalAliases
                If Alias(I).Id = Alias(MyId).Id Or Alias(I).IP = Alias(MyId).IP Then
                    Found = False
                    For FoundIndex = 1 To TotalFound
                        If MatchesFound(FoundIndex) = I Then Found = True: Exit For
                    Next
                    If Not Found Then
                        O = O + Alias(I).User + ","
                        TotalFound = TotalFound + 1
                        MatchesFound(TotalFound) = I
                    End If
                End If
            Next
        End If
    Next

    If O <> "" Then O = Left(O, Len(O) - 1)
    FindAliases = O
End Function

'Organize frequencies

Public Sub SeparateTeams(BotID As Integer)
    Dim CTeam(0 To 9998) As Integer, I As Integer, R As Integer

    For I = 0 To MAX_PLAYERS
        If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then
            If CTeam(BotList(BotID).pList(I).Frequency) = 1 Then
                Do
                    R = Int(Rnd * 9999)
                Loop While CTeam(R) = 1
                BotList(BotID).pList(I).Frequency = R
                CTeam(R) = 1
                PrivateMessage BotID, I, "*setfreq " + CStr(R), 0
            Else
                CTeam(BotList(BotID).pList(I).Frequency) = 1
            End If
        End If
    Next
End Sub

Public Sub MergeTeams(BotID As Integer)
    Dim CTeam(0 To 1) As Integer, I As Integer, Found As Boolean

    For I = 0 To MAX_PLAYERS
        If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then
            Select Case BotList(BotID).pList(I).Frequency
                Case 0: CTeam(0) = CTeam(0) + 1
                Case 1: CTeam(1) = CTeam(1) + 1
            End Select
        End If
    Next

    For I = 0 To MAX_PLAYERS
        If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then
            Select Case BotList(BotID).pList(I).Frequency
                Case 0
                Case 1
                Case Else
                    If CTeam(0) > CTeam(1) Then
                        CTeam(1) = CTeam(1) + 1
                        PrivateMessage BotID, I, "*setfreq 1", 0
                    Else
                        CTeam(0) = CTeam(0) + 1
                        PrivateMessage BotID, I, "*setfreq 0", 0
                    End If
            End Select
        End If
    Next
End Sub

Public Function CheckTeamElimVictory(BotID As Integer) As Integer
    Dim I As Integer, I2 As Integer, CTeam(0 To 1) As Integer

    For I2 = 1 To TotalItems(BotID)
        I = FindUser(BotID, SharedList(BotID, I2))
        If I > -1 Then
            If BotList(BotID).pList(I).Frequency = 0 Then
                CTeam(0) = 1
            ElseIf BotList(BotID).pList(I).Frequency = 1 Then
                CTeam(1) = 1
            End If
        End If
    Next

    If CTeam(0) = 0 Then
        CheckTeamElimVictory = 1
    ElseIf CTeam(1) = 0 Then
        CheckTeamElimVictory = 0
    Else
        CheckTeamElimVictory = -1
    End If
End Function

'Bot utilities

Public Sub NewRabbit(BotID As Integer, FirstTime As Boolean)
    Dim I As Integer, MagicHat(1 To MAX_PLAYERS) As Integer, TotalCards As Integer, B As Byte

    For I = 0 To MAX_PLAYERS
        If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then
            TotalCards = TotalCards + 1
            MagicHat(TotalCards) = I
        End If
    Next

    If TotalCards < 2 Then
        BotList(BotID).BountyID = -1
        If FirstTime Then PublicMessage BotID, "*arena Bounty rabbit will start when 2 players enter", 0
    Else
        I = MagicHat(Int(Rnd * TotalCards) + 1)
        PublicMessage BotID, "*arena After rummaging through " + BotList(BotID).MyName + "'s magic hat, we have procured a new BountyRabbit: " + BotList(BotID).pList(I).SSName, 0
        PublicMessage BotID, "*arena He is granted 5000 bounty. If he lives for 10 minutes, he wins. Capture him and it's yours! Careful, it might be contageous..", 2
        PublicMessage BotID, "*timereset", 0
        PublicMessage BotID, "*timer 10", 0
        If HasSysop Then
            PrivateMessage BotID, I, "*prize 5000", 0
        Else
            For B = 1 To 50
                PrivateMessage BotID, I, "*prize 100", 0
            Next
        End If
        BotList(BotID).BountyID = I
    End If
End Sub

Public Sub FindHiders(BotID As Integer, Distance As Integer)
    Dim X As Integer, Y As Integer, Hiders(1 To 512) As Integer, TotalHiders As Integer, Found As Boolean, O As String

With BotList(BotID)
    For X = 0 To MAX_PLAYERS
        If .pList(X).SSName <> "" And X <> .MyId And .pList(X).ShipType < 8 Then
            Found = False
            For Y = 0 To MAX_PLAYERS
                If .pList(Y).SSName <> "" And Y <> X And Y <> .MyId Then
                    If Abs(.pList(X).X - .pList(Y).X) <= Distance And Abs(.pList(X).Y - .pList(Y).Y) <= Distance Then
                        Found = True
                        Exit For
                    End If
                End If
            Next
            If Not Found Then
                TotalHiders = TotalHiders + 1
                Hiders(TotalHiders) = X
            End If
        End If
    Next

    For X = 1 To TotalHiders
        O = O + .pList(Hiders(X)).SSName + " @ " + GetPlayerCoords(BotID, Hiders(X)) + ", "
    Next
    If TotalHiders > 0 Then
        O = Left(O, Len(O) - 2)
        For X = 1 To Len(O) Step 82
            PublicMessage BotID, "*arena Hiders: " + Mid(O, X, 82), 0
        Next
    End If
End With
End Sub

Public Sub BountyGameOver(BotID As Integer)
    PublicMessage BotID, "*arena The 10 minutes has elapsed! " + BotList(BotID).pList(BotList(BotID).BountyID).SSName + " survived the duration as a BountyRabbit!", 103
    NewRabbit BotID, True
End Sub

Public Function GetTypeString(Bot_Type As BOT_FLAVORS) As String
    Dim O As String

    Select Case Bot_Type
        Case BOT_FLAVORS.ZOMBIES_REF: O = "ZombieRef"
        Case BOT_FLAVORS.SWZ_REF: O = "SWZ Ship-checker"
        Case BOT_FLAVORS.ALIAS_REF: O = "Alias finder"
        Case BOT_FLAVORS.ELIM_REF: O = "ElimRef"
        Case BOT_FLAVORS.DSB_REF: O = "DSB Ship-checker"
        Case BOT_FLAVORS.CONQUER_REF: O = "ConquerRef"
        Case BOT_FLAVORS.BOUNTYGAME_REF: O = "BountyGameRef"
        Case BOT_FLAVORS.SARUNOKAMI_REF: O = "Saru no kami no robotto"
    End Select

    GetTypeString = O
End Function

Public Function CheckPlayerCount(BotID As Integer, Required As Integer, UseZombiefreq As Boolean) As Boolean
    Dim I As Integer, B As Byte

    If UseZombiefreq = True Then
        For I = 0 To MAX_PLAYERS
            If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 And BotList(BotID).pList(I).Frequency = 1 Then B = B + 1
        Next
    Else
        For I = 0 To MAX_PLAYERS
            If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then B = B + 1
        Next
    End If

    If B >= Required Then
        CheckPlayerCount = True
    Else
        CheckPlayerCount = False
    End If
End Function

Public Function TeamUnevenCount(BotID As Integer) As Integer
    Dim I As Integer, P(0 To 1) As Integer

    For I = 0 To MAX_PLAYERS
        If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then
            Select Case BotList(BotID).pList(I).Frequency
                Case 0: P(0) = P(0) + 1
                Case 1: P(1) = P(1) + 1
            End Select
        End If
    Next

    TeamUnevenCount = Abs(P(0) - P(1))
End Function

Public Sub EvenTeams(BotID As Integer)
    Dim I As Integer, P(0 To 1) As Integer

    For I = 0 To MAX_PLAYERS
        If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then
            Select Case BotList(BotID).pList(I).Frequency
                Case 0: P(0) = P(0) + 1
                Case 1: P(1) = P(1) + 1
            End Select
        End If
    Next

    If P(0) > P(1) Then
        For I = 0 To MAX_PLAYERS
            If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).Frequency = 0 And BotList(BotID).pList(I).ShipType < 8 Then
                PrivateMessage BotID, I, "*setfreq 1", 0
                P(0) = P(0) - 1: P(1) = P(1) + 1
                If P(0) - P(1) <= 1 Then Exit Sub
            End If
        Next
    Else
        For I = 0 To MAX_PLAYERS
            If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).Frequency = 1 And BotList(BotID).pList(I).ShipType < 8 Then
                PrivateMessage BotID, I, "*setfreq 0", 0
                P(0) = P(0) + 1: P(1) = P(1) - 1
                If P(1) - P(0) <= 1 Then Exit Sub
            End If
        Next
    End If
End Sub

Public Sub AddGamePlayers(BotID As Integer, UseZombiefreq As Boolean)
    Dim I As Integer

    TotalItems(BotID) = 0
    If UseZombiefreq = True Then
        For I = 0 To MAX_PLAYERS
            If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 And BotList(BotID).pList(I).Frequency = 0 Then AddItem BotID, BotList(BotID).pList(I).SSName
        Next
    Else
        For I = 0 To MAX_PLAYERS
            If BotList(BotID).pList(I).SSName <> "" And BotList(BotID).pList(I).ShipType < 8 Then AddItem BotID, BotList(BotID).pList(I).SSName
        Next
    End If
End Sub

Public Function GetMedianVote(BotID As Integer) As Byte
    Dim I As Integer, V(0 To 10) As Integer, Best As Integer

    With BotList(BotID)
        For I = 0 To MAX_PLAYERS
            If .pList(I).SSName <> "" And .pList(I).Vote <> 0 Then
                V(.pList(I).Vote) = V(.pList(I).Vote) + 1
                .pList(I).Vote = 0
            End If
        Next
    End With

    For I = 1 To 10
        If V(I) > V(Best) Then Best = I
    Next

    If Best = 0 Then Best = 1
    GetMedianVote = Best
End Function

Public Function IsPublicArena(ArenaName As String) As Boolean
    If ArenaName = "" Or IsNumeric(ArenaName) Then
        IsPublicArena = True
    Else
        IsPublicArena = False
    End If
End Function

'Conquer! database and utilities

Public Sub SetupConquer(BotID As Integer)
On Error GoTo FlyPaper

    Dim I As Integer

    SeparateTeams BotID
    TotalFreqs(BotID) = 0
    With BotList(BotID)
        For I = 0 To MAX_PLAYERS
            If .pList(I).SSName <> "" And .pList(I).ShipType < 8 Then AddConquerPlayer BotID, I, True
        Next
    End With

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in SetupConquer(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub AddConquerPlayer(BotID As Integer, PlayerID As Integer, AllowNewTeam As Boolean)
On Error GoTo FlyPaper

    Dim I As Integer

    For I = 1 To TotalFreqs(BotID)
        If BotList(BotID).pList(PlayerID).Frequency = Conquer(BotID, I).Frequency Then
            Conquer(BotID, I).TotalCurrent = Conquer(BotID, I).TotalCurrent + 1
            Conquer(BotID, I).CurrentPlayers(Conquer(BotID, I).TotalCurrent) = PlayerID
            Exit Sub
        End If
    Next

    TotalFreqs(BotID) = TotalFreqs(BotID) + 1
    Conquer(BotID, TotalFreqs(BotID)).TotalCurrent = 1
    Conquer(BotID, TotalFreqs(BotID)).CurrentPlayers(Conquer(BotID, TotalFreqs(BotID)).TotalCurrent) = PlayerID
    Conquer(BotID, TotalFreqs(BotID)).Frequency = BotList(BotID).pList(PlayerID).Frequency
    If AllowNewTeam = True Then
        Conquer(BotID, TotalFreqs(BotID)).InitialOwner = PlayerID
    Else
        Conquer(BotID, TotalFreqs(BotID)).InitialOwner = -1
    End If

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in AddConquerPlayer(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub ConquerPlayer(BotID As Integer, PlayerID As Integer, KillerID As Integer)
On Error GoTo FlyPaper

    Dim X As Integer, Y As Integer, Freq(0 To 1) As Integer, Current(0 To 1) As Integer
    Dim Occupied As Integer, Winner As Integer, O As String, Dead As Boolean, FreeTheSerfs As Boolean

    For X = 1 To TotalFreqs(BotID)
        For Y = 1 To Conquer(BotID, X).TotalCurrent
            If Conquer(BotID, X).CurrentPlayers(Y) = PlayerID Then Freq(0) = X: Current(0) = Y: Exit For
            If Conquer(BotID, X).CurrentPlayers(Y) = KillerID Then
                If Conquer(BotID, X).InitialOwner = -1 Then
                    Exit Sub
                Else
                    Freq(1) = X
                    Current(1) = Y
                    Exit For
                End If
            End If
        Next
    Next

    If Freq(0) = 0 Or Freq(1) = 0 Then Exit Sub

    MoveConquerPlayer BotID, Freq(0), Current(0), Freq(1)

    If Conquer(BotID, Freq(0)).InitialOwner = PlayerID Then
        If Conquer(BotID, Freq(0)).TotalCurrent > 0 Then FreeTheSerfs = True
        For X = 1 To Conquer(BotID, Freq(0)).TotalCurrent
            MoveConquerPlayer BotID, Freq(0), X, Freq(1)
        Next
    End If

    For X = 1 To TotalFreqs(BotID)
        If Conquer(BotID, X).InitialOwner > -1 Then
            If Conquer(BotID, X).TotalCurrent > 0 Then
                Occupied = Occupied + 1: Winner = X
            ElseIf X = Freq(0) Then
                Dead = True
            End If
        End If
    Next

    If FreeTheSerfs Then
        PublicMessage BotID, "*arena Team OWNED by " + GetFreq(BotID, Freq(0)) + " destroyed. Players OWNED by " + GetFreq(BotID, Freq(0)) + " now enslaved to " + GetFreq(BotID, Freq(1)), 0
        Conquer(BotID, Freq(0)).InitialOwner = -1
    ElseIf Dead Then
        PublicMessage BotID, "*arena Team OWNED by " + GetFreq(BotID, Freq(0)) + " destroyed", 0
    Else
        PublicMessage BotID, "*arena " + BotList(BotID).pList(KillerID).SSName + " ( OWNER " + GetFreq(BotID, Freq(1)) + " ) conquered " + BotList(BotID).pList(PlayerID).SSName, 0
    End If

    DoVictory BotID, Occupied, Winner

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in ConquerPlayer(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub MoveConquerPlayer(BotID As Integer, SourceFreq As Integer, SourcePlayer As Integer, DestFreq As Integer)
On Error GoTo FlyPaper

    Dim I As Integer

    Conquer(BotID, DestFreq).TotalCurrent = Conquer(BotID, DestFreq).TotalCurrent + 1
    Conquer(BotID, DestFreq).CurrentPlayers(Conquer(BotID, DestFreq).TotalCurrent) = Conquer(BotID, SourceFreq).CurrentPlayers(SourcePlayer)

    Conquer(BotID, SourceFreq).TotalCurrent = Conquer(BotID, SourceFreq).TotalCurrent - 1
    For I = SourcePlayer To Conquer(BotID, SourceFreq).TotalCurrent
        Conquer(BotID, SourceFreq).CurrentPlayers(I) = Conquer(BotID, SourceFreq).CurrentPlayers(I + 1)
    Next

    PrivateMessage BotID, Conquer(BotID, DestFreq).CurrentPlayers(Conquer(BotID, DestFreq).TotalCurrent), "*setfreq " + CStr(Conquer(BotID, DestFreq).Frequency), 0

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in MoveConquerPlayer(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub KillConquerPlayer(BotID As Integer, FreqIndex As Integer, PlayerIndex As Integer)
On Error GoTo FlyPaper

    Dim I As Integer, I2 As Integer, Winner As Integer, Occupied As Integer

    Conquer(BotID, FreqIndex).TotalCurrent = Conquer(BotID, FreqIndex).TotalCurrent - 1
    For I = PlayerIndex To Conquer(BotID, FreqIndex).TotalCurrent
        Conquer(BotID, FreqIndex).CurrentPlayers(I) = Conquer(BotID, FreqIndex).CurrentPlayers(I + 1)
    Next

    If Conquer(BotID, FreqIndex).InitialOwner = PlayerIndex Then
        PublicMessage BotID, "*arena Players OWNED by " + GetFreq(BotID, FreqIndex) + " are released from serfdom", 0
        Conquer(BotID, FreqIndex).InitialOwner = -1
    End If

    For I = 1 To TotalFreqs(BotID)
        If Conquer(BotID, I).InitialOwner > -1 And Conquer(BotID, I).TotalCurrent > 0 Then Occupied = Occupied + 1: Winner = I
    Next

    DoVictory BotID, Occupied, Winner

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in KillConquerPlayer(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub DoVictory(BotID As Integer, Occupied As Integer, Winner As Integer)
On Error GoTo FlyPaper

    Dim O As String

    If Occupied = 1 Then
        PublicMessage BotID, "*lock", 0
        PublicMessage BotID, "*arena GAME OVER. Winner: " + GetFreq(BotID, Winner), 103
        If CheckPlayerCount(BotID, 4, False) = False Then PublicMessage BotID, "*arena Not enough players. Conquer will start when 4 players enter", 1
        BotList(BotID).Bot_Status = CHECK
    ElseIf Occupied = 0 Then
        PublicMessage BotID, "*lock", 0
        PublicMessage BotID, "*arena GAME OVER. No winner.", 103
        If CheckPlayerCount(BotID, 4, False) = False Then PublicMessage BotID, "*arena Not enough players. Conquer will start when 4 players enter", 1
        BotList(BotID).Bot_Status = CHECK
    End If

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in DoVictory(): " + Err.Description, RED
    Resume Next
End Sub

Public Sub ConquerCheckFreq(BotID As Integer, PlayerID As Integer)
On Error GoTo FlyPaper

    Dim X As Integer, Y As Integer

    For X = 1 To TotalFreqs(BotID)
        For Y = 1 To Conquer(BotID, X).TotalCurrent
            If Conquer(BotID, X).CurrentPlayers(Y) = PlayerID Then
                If BotList(BotID).pList(PlayerID).ShipType = 8 Then
                    KillConquerPlayer BotID, X, Y
                ElseIf BotList(BotID).pList(PlayerID).Frequency <> Conquer(BotID, X).Frequency Then
                    PrivateMessage BotID, PlayerID, "*setfreq " + CStr(Conquer(BotID, X).Frequency), 0
                End If
                Exit Sub
            End If
        Next
    Next

    If BotList(BotID).pList(PlayerID).ShipType < 8 Then
        AddConquerPlayer BotID, PlayerID, False
    End If

Exit Sub
FlyPaper:
    AddDebug BotID, "Error detected in ConquerCheckFreq(): " + Err.Description, RED
    Resume Next
End Sub

Public Function GetFreq(BotID As Integer, Freq As Integer) As String
    If Conquer(BotID, Freq).InitialOwner >= -1 Then
        GetFreq = BotList(BotID).pList(Conquer(BotID, Freq).InitialOwner).SSName
    Else
        GetFreq = "Nobody"
    End If
End Function

'Scores

Public Sub LoadScores(Filename As String)
    Dim S As String, F As Integer: F = FreeFile

On Error GoTo ErrHandler

    Open Filename For Input As #F
    Do
        Line Input #F, S
        If Left(S, 2) = "C:" Then
            TotalScores = TotalScores + 1
            Scores(TotalScores) = GetScoreEntry(Mid(S, 3))
        End If
    Loop

ErrHandler: Close #F

    AddDebug 0, "Team scores loaded. " + CStr(TotalScores) + " arena entries", BLUE
End Sub

Public Function GetScoreEntry(RawText As String) As LoggedScore
    '<Arena Name(Blank for Public)>:<Freq0 Wins>:<Freq0 Losses>:<Freq0 Flag Victories>:<Freq1 Wins>:<Freq1 Losses>:<Freq1 Flag Victories>
    Dim Find(1 To 6) As Integer, I As Integer, Counter As Byte, Result As LoggedScore

    For I = Len(RawText) To 1 Step -1
        If Mid(RawText, I, 1) = ":" Then
            Counter = Counter + 1
            Find(Counter) = I
            If Counter = 6 Then Exit For
        End If
    Next

    Result.ArenaName = LCase(Left(RawText, Find(6) - 1))
    Result.Freq(0).Wins = Mid(RawText, Find(6) + 1, Find(5) - Find(6) - 1)
    Result.Freq(0).Losses = Mid(RawText, Find(5) + 1, Find(4) - Find(5) - 1)
    Result.Freq(0).FlagVictories = Mid(RawText, Find(4) + 1, Find(3) - Find(4) - 1)
    Result.Freq(1).Wins = Mid(RawText, Find(3) + 1, Find(2) - Find(3) - 1)
    Result.Freq(1).Losses = Mid(RawText, Find(2) + 1, Find(1) - Find(2) - 1)
    Result.Freq(1).FlagVictories = Mid(RawText, Find(1) + 1)

    GetScoreEntry = Result
End Function

Public Sub SaveScores(Filename As String)
    Dim L As Long, F As Integer: F = FreeFile

On Error GoTo ErrHandler

    Open Filename For Output As #F
    Print #F, "Last updated: " + CStr(Date)
    Print #F, "Format - C:<Arena Name>:<Freq0 Wins>:<Freq0 Losses>:<Freq0 Flag Victories>:<Freq1 Wins>:<Freq1 Losses>:<Freq1 Flag Victories>"
    For L = 1 To TotalScores
        With Scores(L)
            Print #F, "C:" + .ArenaName + ":" + CStr(.Freq(0).Wins) + ":" + CStr(.Freq(0).Losses) + ":" + CStr(.Freq(0).FlagVictories) + ":" + CStr(.Freq(1).Wins) + ":" + CStr(.Freq(1).Losses) + ":" + CStr(.Freq(1).FlagVictories)
        End With
    Next

ErrHandler: Close #F
End Sub

Public Sub AddWin(BotID As Integer, Freq As Integer)
    If BotList(BotID).LogScores = 0 Or Freq > 1 Or Freq < 0 Then Exit Sub

    Dim I As Integer

    For I = 1 To TotalScores
        If Scores(I).ArenaName = BotList(BotID).ArenaName Then
            Scores(I).Freq(Freq).Wins = Add(Scores(I).Freq(Freq).Wins, "1")
            Exit Sub
        End If
    Next

    TotalScores = TotalScores + 1

    Scores(TotalScores).ArenaName = BotList(BotID).ArenaName
    Scores(TotalScores).Freq(Freq).Wins = "1"
End Sub

Public Sub AddLoss(BotID As Integer, Freq As Integer)
    If BotList(BotID).LogScores = 0 Or Freq > 1 Or Freq < 0 Then Exit Sub

    Dim I As Integer

    For I = 1 To TotalScores
        If Scores(I).ArenaName = BotList(BotID).ArenaName Then
            Scores(I).Freq(Freq).Losses = Add(Scores(I).Freq(Freq).Losses, "1")
            Exit Sub
        End If
    Next

    TotalScores = TotalScores + 1

    Scores(TotalScores).ArenaName = BotList(BotID).ArenaName
    Scores(TotalScores).Freq(Freq).Losses = "1"
End Sub

Public Sub AddFlagVictory(BotID As Integer, Freq As Integer)
    If BotList(BotID).LogScores = 0 Or Freq > 1 Or Freq < 0 Then Exit Sub

    Dim I As Integer

    For I = 1 To TotalScores
        If Scores(I).ArenaName = BotList(BotID).ArenaName Then
            Scores(I).Freq(Freq).FlagVictories = Add(Scores(I).Freq(Freq).FlagVictories, "1")
            Exit Sub
        End If
    Next

    TotalScores = TotalScores + 1

    Scores(TotalScores).ArenaName = BotList(BotID).ArenaName
    Scores(TotalScores).Freq(Freq).FlagVictories = "1"
End Sub
