Attribute VB_Name = "SSGameServer"
Option Explicit

'Publics

Public MyID                 As Integer
Public ChosenCharacter      As String * 1
Public Const UseUnbanner = False

'Packet filters

Private Enum O1_TYPES
    SessionData = 0
    ClientPositionData = 3
    ServerPositionData = 5
End Enum

Private Enum O2_TYPES
    SessionRequest = 1
    KeyNotify = 2
    ACKRequired = 3
    ACKMessage = 4
    SyncClient = 5
    SyncServer = 6
    Disconnect = 7
    PacketCluster = 14
End Enum

Private Enum ACKREQ_TYPES
    SettingsFile = 0
    YouAreHere = 1
    StartPeriodic = 2
    PlayersEntering = 3
    PlayerQuit = 4
    KillMessage = 6
    Chat_Message = 7
    LagUpdate = 8
    KoTHUpdate = 9
    PasswordAccept = 10
    SoccerGoal = 11
    SetFreqAndShip = 29
    DoorFlip = 33
    FlagStatus = 34
    FlagReward = 35
    MapFile = 41
    ArenaList = 47
End Enum

Private Enum CHAT_TYPES
    Arena_Message = 0
    Public_Message = 2
    Team_Message = 3
    TeamPrivate_Message = 4
    Private_Message = 5
    RemotePrivate_Message = 7
    Channel_Message = 9
End Enum

Public Enum FAILURES
    NONE = 0
    NEW_USER = 1
    BAD_PW = 2
    IP_BLOCK = 3
    ID_BLOCK = 4
    PERMISSION_ZONE = 5
    OBSCENE_NAME = 12
    NAME_MISSING = 16
End Enum

Public ShipTypes(0 To 8)    As String

'Privates

Private SockAddy            As sockaddr

Public LastSID          As Long

'Util

Public Function NextSID() As String
    NextSID = GetString(LastSID)
    LastSID = LastSID + 1
End Function

Public Function Make01Key() As String
    Make01Key = Chr(0) + Chr(1) + GetString(0) + Chr(1) + Chr(0)
End Function

'Handler functions

Private Sub Handler02(Message As String)
    'Server sent a key
    SendLogin MainFrm.LoginHandle.Text, MainFrm.LoginPassword, 234322, 450, 7697, 0
    SendSync 1
    ChatMessage MSG_CLASS.MSG_SERVER, "Sent password packet"
End Sub

Private Sub Handler03(ByVal Message As String)
    'In-game events
    
    Dim L As Long
            
    L = CLng(GetInteger(Mid(Message, 3, 2)))
    If ACKs(L) = 1 Then
        Exit Sub
    Else
        ACKs(L) = 1
    End If
    
    Select Case Asc(Mid(Message, 7, 1))
        Case ACKREQ_TYPES.SettingsFile
            AddDebug "Receiving settings"
            'DrawPacket "Settings", Message
        
        Case ACKREQ_TYPES.YouAreHere
            AddDebug "Bot running as #" + CStr(GetInteger(Mid(Message, 8, 2)))
            MyID = GetInteger(Mid(Message, 8, 2))
        
        Case ACKREQ_TYPES.StartPeriodic
            ChatMessage MSG_CLASS.MSG_SPECIAL, "Logged in successfully"
            MainFrm.Periodic.Enabled = True
        
        Case ACKREQ_TYPES.PlayersEntering
            Message = Mid(Message, 7)
            For L = 1 To Len(Message) Step 64
                If Asc(Mid(Message, L, 1)) = 3 Then AddUser TrimZero(Mid(Message, 3 + L, 24)), GetInteger(Mid(Message, 51 + L, 2)), GetInteger(Mid(Message, 117 + L, 2)), Asc(Mid(Message, 7 + L, 1))
            Next
        
        Case ACKREQ_TYPES.PlayerQuit
            DelUser GetInteger(Mid(Message, 8, 2))
        
        Case ACKREQ_TYPES.KillMessage
            UpdateTitle pList(GetInteger(Mid(Message, 11, 2))).SSName + "(" + CStr(GetInteger(Mid(Message, 13, 2))) + ":" + CStr(GetInteger(Mid(Message, 15, 2))) + ") killed by: " + pList(GetInteger(Mid(Message, 9, 2))).SSName
            
        Case ACKREQ_TYPES.Chat_Message
            Select Case Asc(Mid(Message, 8, 1))
                Case CHAT_TYPES.Arena_Message
                    ChatMessage MSG_CLASS.MSG_ARENA, TrimZero(Mid(Message, 12))
                    
                Case CHAT_TYPES.Channel_Message
                    ChatMessage MSG_CLASS.MSG_CHANNEL, TrimZero(Mid(Message, 12))
                
                Case CHAT_TYPES.Public_Message
                    If GetInteger(Mid(Message, 10, 2)) = -1 Then
                        ChatMessage MSG_CLASS.MSG_PUBLIC, TrimZero(Mid(Message, 12))
                    Else
                        ChatMessage MSG_CLASS.MSG_PUBLIC, TrimZero(Mid(Message, 12)), pList(GetInteger(Mid(Message, 10, 2))).SSName
                    End If
                
                Case CHAT_TYPES.Team_Message
                    If GetInteger(Mid(Message, 10, 2)) = -1 Then
                        ChatMessage MSG_CLASS.MSG_TEAM, TrimZero(Mid(Message, 12))
                    Else
                        ChatMessage MSG_CLASS.MSG_TEAM, TrimZero(Mid(Message, 12)), pList(GetInteger(Mid(Message, 10, 2))).SSName
                    End If
                
                Case CHAT_TYPES.TeamPrivate_Message
                    If GetInteger(Mid(Message, 10, 2)) = -1 Then
                        ChatMessage MSG_CLASS.MSG_TEAM_PRIVATE, TrimZero(Mid(Message, 12))
                    Else
                        ChatMessage MSG_CLASS.MSG_TEAM_PRIVATE, TrimZero(Mid(Message, 12)), pList(GetInteger(Mid(Message, 10, 2))).SSName
                    End If
                
                Case CHAT_TYPES.Private_Message
                    If GetInteger(Mid(Message, 10, 2)) = -1 Then
                        ChatMessage MSG_CLASS.MSG_PRIVATE, TrimZero(Mid(Message, 12))
                    Else
                        ChatMessage MSG_CLASS.MSG_PRIVATE, TrimZero(Mid(Message, 12)), pList(GetInteger(Mid(Message, 10, 2))).SSName
                        If GetInteger(Mid(Message, 10, 2)) <> MyID Then HandleCommand GetInteger(Mid(Message, 10, 2)), TrimZero(Mid(Message, 12))
                    End If
                
                Case CHAT_TYPES.RemotePrivate_Message
                    If GetInteger(Mid(Message, 10, 2)) = 0 Then
                        ChatMessage MSG_CLASS.MSG_REMOTE_PRIVATE, TrimZero(Mid(Message, 12))
                    Else
                        ChatMessage MSG_CLASS.MSG_REMOTE_PRIVATE, TrimZero(Mid(Message, 12)), pList(GetInteger(Mid(Message, 10, 2))).SSName
                    End If
                
                Case Else
                    AddDebug "  Error: unknown chat type #" + CStr(Asc(Mid(Message, 8, 1)))
                    If GetInteger(Mid(Message, 10, 2)) = -1 Then
                        ChatMessage MSG_CLASS.MSG_UNKNOWN, TrimZero(Mid(Message, 12))
                    Else
                        ChatMessage MSG_CLASS.MSG_UNKNOWN, TrimZero(Mid(Message, 12)), pList(GetInteger(Mid(Message, 10, 2))).SSName
                        DrawPacket "Chat", Message
                    End If
            
            End Select
        
        Case ACKREQ_TYPES.LagUpdate
            AddDebug "TotalBytes=" + CStr(GetLong(Mid(Message, 8, 4))) + ", Ping=" + CStr(GetInteger(Mid(Message, 12, 2))) + ", Ping=" + CStr(GetInteger(Mid(Message, 14, 2))) + ", Ploss=" + CStr(GetInteger(Mid(Message, 16))) + ", Ploss=" + CStr(GetInteger(Mid(Message, 18)))
        
        Case ACKREQ_TYPES.KoTHUpdate
            AddDebug pList(GetInteger(Mid(Message, 8, 2))).SSName + " won KoTH!"
            
        Case ACKREQ_TYPES.PasswordAccept
            Select Case Asc(Mid(Message, 8, 1))
                Case FAILURES.NONE
                    ChatMessage MSG_CLASS.MSG_SERVER, "Password packet accepted"
                    EnterArena 8, ""
                Case FAILURES.NEW_USER
                    ChatMessage MSG_CLASS.MSG_SERVER, "Creating a new account for the bot"
                    If UseUnbanner = True Then
                        SendLogin MainFrm.LoginHandle.Text + ChosenCharacter, MainFrm.LoginPassword, Rnd * 1000, Rnd * 1000, Rnd * 1000, 1
                    Else
                        SendLogin MainFrm.LoginHandle.Text, MainFrm.LoginPassword, 234322, 450, 7697, 1
                    End If
                    SendSync 1
                Case FAILURES.BAD_PW
                    LeaveServer
                    MsgBox "Incorrect password", vbInformation, "Oops"
                Case FAILURES.IP_BLOCK
                    LeaveServer
                    MsgBox "IP subnet block, you may not enter", vbInformation, "Oops"
                Case FAILURES.ID_BLOCK
                    LeaveServer
                    MsgBox "Machine ID block, you may not enter", vbInformation, "Oops"
                Case FAILURES.PERMISSION_ZONE
                    LeaveServer
                    MsgBox "This is a permission-only zone", vbInformation, "Oops"
                Case FAILURES.NAME_MISSING
                    LeaveServer
                    MsgBox "Please enter a handle", vbInformation, "Oops"
                Case FAILURES.OBSCENE_NAME
                    LeaveServer
                    MsgBox "Your handle is in obscene.txt: Choose a new name", vbInformation, "Oops"
                Case Else
                    LeaveServer
                    MsgBox "Number " + CStr(Asc(Mid(Message, 8, 1))), vbInformation, "Unknown login error"
            End Select
        
        Case ACKREQ_TYPES.MapFile
            AddDebug "Map checksum packet received"
        
        Case ACKREQ_TYPES.ArenaList
            Message = Mid(Message, 8)
            MainFrm.ArenaList.Clear
            Do While Message <> ""
                MainFrm.ArenaList.AddItem TrimZero(Message) + "(" + CStr(Asc(Mid(Message, Len(TrimZero(Message)) + 2, 1))) + ")"
                Message = Mid(Message, Len(TrimZero(Message)) + 4)
            Loop
            SetState ARENA_LIST_WINDOW
        
        Case ACKREQ_TYPES.SoccerGoal
            AddDebug pList(GetInteger(Mid(Message, 8, 2))).SSName + " scored a goal for " + CStr(GetLong(Mid(Message, 10, 4))) + " points!"
        
        Case ACKREQ_TYPES.SetFreqAndShip
            pList(GetInteger(Mid(Message, 9, 2))).ShipType = Asc(Mid(Message, 8, 1))
            pList(GetInteger(Mid(Message, 9, 2))).Frequency = GetInteger(Mid(Message, 11, 2))
            HandleShipChange GetInteger(Mid(Message, 9, 2))
            AddDebug pList(GetInteger(Mid(Message, 9, 2))).SSName + ": " + ShipTypes(Asc(Mid(Message, 8, 1))) + " on freq " + CStr(GetInteger(Mid(Message, 11, 2)))
        
        Case ACKREQ_TYPES.DoorFlip
            AddDebug "Door-zaps switched states"
            
        Case ACKREQ_TYPES.FlagStatus
            AddDebug "Flag status received"
        
        Case ACKREQ_TYPES.FlagReward
            AddDebug "Flag Reward given"
        
        Case 13
            AddDebug "Unknown status received #13"
        
        Case 22
            AddDebug "Unknown status received #22"
        
        Case 26
            AddDebug "Unknown status received #26"
        
        Case 14
            AddDebug "Unknown status received #14"
'            chatmessage "14: " + CStr(GetInteger(Mid(Message, 8, 2))) + "," + CStr(GetInteger(Mid(Message, 10, 2)))
            
        Case 18
            AddDebug "Unknown status received #18"
'            chatmessage "18: " + pList(GetInteger(Mid(Message, 8, 2))) + ": " + CStr(GetInteger(Mid(Message, 10, 2))) + "," + CStr(GetInteger(Mid(Message, 12, 2))) + "," + CStr(GetInteger(Mid(Message, 14, 2)))
        
        Case 19
            AddDebug "Unknown status received #19"
'            chatmessage "19: " + CStr(GetInteger(Mid(Message, 8, 2))) + "," + CStr(GetInteger(Mid(Message, 10, 2)))
        
        Case 24
            AddDebug "Unknown status received #24"
            'DrawPacket "o7 #24", Message
        
        Case 31
            AddDebug "Unknown status received #31"
        
        Case 44
            AddDebug "Unknown status received #44"
        
        Case 49
            AddDebug "Boolean flag: Unknown #49"
            
        Case Else
            DrawPacket "Unk o7 #" + CStr(Asc(Mid(Message, 7, 1))), Message
    
    End Select
End Sub

Private Sub Handler06(Message As String)
    'Server accepted the 05 packet
    ChatMessage MSG_CLASS.MSG_SERVER, "Sync packet accepted"
End Sub

Private Sub Handler07(Message As String)
    'Server D/Ced the bot
    MainFrm.Periodic.Enabled = False
    ChatMessage MSG_CLASS.MSG_SPECIAL, "Disconnected"
End Sub

Private Sub Handler0E(UnencryptedPacket As String)
    On Error GoTo LeaveCluster
    
    Dim I As Integer, O As String
    
    O = Mid(UnencryptedPacket, 3)
    Do
        I = Asc(Left(O, 1))
        Call HandlePacket(SockAddy, Mid(O, 2, I))
        O = Mid(O, I + 2)
    Loop
    
LeaveCluster:
End Sub

'Handler entry point

Public Sub HandlePacket(Sender As sockaddr, UnencryptedPacket As String)
    SockAddy = Sender
    
    Select Case Asc(Left(UnencryptedPacket, 1))
        Case O1_TYPES.SessionData
            Select Case Asc(Mid(UnencryptedPacket, 2, 1))
                Case O2_TYPES.KeyNotify: Call Handler02(UnencryptedPacket)
                Case O2_TYPES.ACKRequired: Call Handler03(UnencryptedPacket)
                Case O2_TYPES.SyncServer: Call Handler06(UnencryptedPacket)
                Case O2_TYPES.Disconnect: Call Handler07(UnencryptedPacket)
                Case O2_TYPES.PacketCluster: Call Handler0E(UnencryptedPacket)
                Case Else
                    AddDebug "Error: unknown O2 packet #" + CStr(Asc(Mid(UnencryptedPacket, 2, 1)))
            End Select
        Case O1_TYPES.ServerPositionData 'Unhandled
        Case Else
            AddDebug "Error: unknown O1 packet #" + CStr(Asc(Left(UnencryptedPacket, 1)))
    End Select
End Sub
