home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / vbasic / Data / Utils / XZipComp.exe / XceedWinsock.Cab / F112733_Main.bas < prev    next >
Encoding:
BASIC Source File  |  2000-03-27  |  30.8 KB  |  934 lines

  1. Attribute VB_Name = "MainTron"
  2. '
  3. ' Xceed Winsock Library Sample: Tron Sample
  4. ' Copyright (c) 2000 Xceed Software Inc.
  5. '
  6. ' [Main code module]
  7. '
  8. ' This sample application for the Xceed Winsock Library demonstrates
  9. ' service advertising and service lookup using the SAP protocol, as
  10. ' well as connectionless asynchronous byte transfers using the IPX
  11. ' protocol. All transfer events are handled via the "Implements"
  12. ' statement. To successfully create a game, you must have the SAP
  13. ' protocol installed on your system. Otherwise, you can only list
  14. ' and join games.
  15. '
  16. ' This file is part of the Xceed Winsock Library Samples.
  17. ' The source code in this file is only intended as a supplement
  18. ' to Xceed Winsock Library's documentation, and is provided "as is",
  19. ' without warranty of any kind, either expressed or implied.
  20. '
  21.  
  22. Option Explicit
  23.  
  24. ' The game interface form itself
  25.  
  26. Public GameForm         As FrmTron
  27.  
  28. ' Variables that determine the main game modes
  29.  
  30. Public HostMode         As HostModes
  31. Public GameMode         As GameModes
  32.  
  33. ' Game data variables for hosting a game
  34.  
  35. Public Game             As GameData           ' Master game parameters
  36. Public Players(1 To 8)  As Player             ' Server: all player data here, Client: local player only
  37.  
  38. ' Local player information
  39.  
  40. Public LocalPlayer      As Integer            ' Index of local player in the Players array
  41. Public LocalIteration   As Long               ' The latest iteration info our client has received
  42. Public Colors           As New Collection     ' The colors for each player, 1:1 with Players array
  43.  
  44. Public LastLocalPlayerDirection As Directions ' Updated as soon as an arrow key is hit
  45. Public LastLocalPlayerIsBoosting As Integer   ' Updated when nitro boost key state changes
  46. Public LastLocalPlayerIsBraking As Integer    ' Updated when brake key state changes
  47.     
  48. ' General gameplay constants
  49.  
  50. Public Const MaxNitro = 16                    ' Amount of nitro boost at start of each round
  51. Public Const MaxBrakes = 30                   ' Amount of braking power at start of each round
  52. Public Const MaxLifeSavers = 3                ' Amount of Life Savers at start of each round
  53.  
  54. ' Networking constants
  55.  
  56. Public Const GameGuid = "{600D69E1-E89D-11d3-BF75-00600807163F}" ' Guid for advertising the game service
  57.  
  58. ' Variables for listing and joining available games
  59.  
  60. Public GameAddresses() As Address          ' Addresses of the game servers found
  61. Public GameNames() As String               ' Names of players hosting the games
  62. Public GamesFound As Integer               ' Number of game servers found
  63. Public JoinGameSubmenuMaxIndex As Integer  ' Number of "Join game" submenu items already created
  64.  
  65. ' ==================================================
  66. '               Main application loop
  67. ' ==================================================
  68.  
  69. Public Sub Main()
  70.         
  71.     HostMode = hmIdle ' not hosting, not joined.
  72.     GameMode = gmIdle ' not playing, not paused.
  73.     
  74.     Call InitColors   ' Initialise player colors
  75.     
  76.     ' Instantiate and load the game interface form
  77.     
  78.     Set GameForm = New FrmTron
  79.     Load GameForm
  80.         
  81.     Call GameForm.Display
  82.     Call GameForm.SetState(isNoGameHostedOrJoined)
  83.        
  84.     Do
  85.         DoEvents
  86.     Loop Until HostMode = hmQuitting
  87.        
  88. End Sub
  89.  
  90. ' Unload and free the game interface form
  91. '
  92. Public Sub CloseAll()
  93.  
  94.     Unload GameForm
  95.     Set GameForm = Nothing
  96.     
  97. End Sub
  98.  
  99. ' Set up player colors
  100. '
  101. Private Sub InitColors()
  102.     
  103.     Colors.Add vbBlue
  104.     Colors.Add vbRed
  105.     Colors.Add vbGreen
  106.     Colors.Add &HAAAAAA   ' grey
  107.     Colors.Add vbBlack
  108.     Colors.Add vbMagenta
  109.     Colors.Add vbCyan
  110.     Colors.Add &HC74993   ' Purple
  111.  
  112. End Sub
  113.  
  114. ' Wait a specified amount of time, in milliseconds
  115. '
  116. Sub Wait(N As Integer)
  117.  
  118.     Dim T As Double
  119.  
  120.     T = Timer
  121.     
  122.     Do
  123.         DoEvents
  124.     Loop Until ((Timer - T) * 1000) > N
  125.  
  126. End Sub
  127.  
  128. ' This game server procedure handles the activity before and after
  129. ' a round is played.
  130. '
  131. Public Sub StartRound()
  132.  
  133.     Dim Winner As Integer     ' The player that won the round
  134.     Dim RoundData As String   ' The starting information of a round
  135.     Dim Pnum As Integer
  136.     Dim T As Double
  137.     
  138.     Call InitialiseRound      ' Set up initial positions of the players
  139.     
  140.     ' Prepare the information about the round to send to the clients
  141.     
  142.     RoundData = "<round roundid=" & CStr(Game.CurrentRound) & " status=starting>" & vbCrLf
  143.     For Pnum = 1 To 8
  144.         If Players(Pnum).IsAssigned Then
  145.             RoundData = RoundData & "  <player playerid=" & CStr(Pnum) & " name=" & Chr$(34) & Players(Pnum).Name & Chr$(34) & " >" & vbCrLf
  146.             RoundData = RoundData & "    <pos x=" & CStr(Players(Pnum).X) & " y=" & CStr(Players(Pnum).Y) & " />" & vbCrLf
  147.             RoundData = RoundData & "  </player>" & vbCrLf
  148.         End If
  149.     Next Pnum
  150.     RoundData = RoundData & "</round>" & vbCrLf
  151.     
  152.     ' Send the round information to all the clients
  153.     
  154.     Call SendGameSignal(sRoundStarting, RoundData, DP_All)
  155.      
  156.     ' Wait 1 second or until all players have confirmed they are
  157.     ' ready to start the round!
  158.     
  159.     T = Timer
  160.     Do
  161.         DoEvents
  162.     Loop Until AllPlayersReadyToStart() Or ((Timer - T) > 0.99)
  163.     
  164.     ' If any player's haven't confirmed, remove them from the round.
  165.     
  166.     For Pnum = 1 To 8
  167.         If Players(Pnum).IsReadyToStart = False Then
  168.             Players(Pnum).IsAlive = False
  169.             Call SendGameSignal(sDroppedFromRound, "", Pnum)
  170.         End If
  171.         Players(Pnum).IterationsLagging = 0
  172.     Next Pnum
  173.          
  174.     ' Play the actual round!
  175.          
  176.     Winner = PlayRound()
  177.     
  178.     ' Send information to clients about the round's winner, and scores information
  179.     
  180.     If Winner = 0 Then
  181.         Call SendGameSignal(sRoundCompleted, "None", DP_All)
  182.     Else
  183.         Players(Winner).Wins = Players(Winner).Wins + 1
  184.         
  185.         Call SendGameSignal(sRoundCompleted, Players(Winner).Name, DP_All)
  186.                     
  187.         For Pnum = 1 To 8
  188.             If Players(Pnum).IsAssigned Then
  189.                 Call SendGameSignal(sScoresInfo, Players(Pnum).Name & " has " & CStr(Players(Pnum).Wins) & " wins, " & CStr(Players(Pnum).Crashes) & " crashes.", DP_All)
  190.             End If
  191.         Next Pnum
  192.                     
  193.     End If
  194.  
  195.     Game.CurrentRound = Game.CurrentRound + 1
  196.         
  197.     GameMode = gmIdle
  198.             
  199. End Sub
  200.  
  201. ' This procedure pauses a round (if we are a game server) or requests to
  202. ' pause a round (if we are a client)
  203. '
  204. Public Sub PauseRound()
  205.  
  206.     ' Todo
  207.  
  208. End Sub
  209.  
  210. ' This function executes a game round and returns the player number that
  211. ' won the round. Returns 0 if there was no winner.
  212. '
  213. Private Function PlayRound() As Integer
  214.  
  215.     Dim Pnum          As Integer
  216.     Dim Winner        As Integer ' The player that won the round
  217.     Dim PlayersAlive  As Integer
  218.     Dim Iteration     As Long
  219.  
  220.     ' Count the number of players that are alive (that will play in this round)
  221.  
  222.     PlayersAlive = 0
  223.     For Pnum = 1 To 8
  224.         If Players(Pnum).IsAlive Then PlayersAlive = PlayersAlive + 1
  225.     Next Pnum
  226.     
  227.     ' Main loop
  228.     
  229.     Iteration = 0
  230.     
  231.     Do
  232.         
  233.         ' Move the players according to their directions, nitro and brakes
  234.         
  235.         PlayersAlive = PlayersAlive - MovePlayers(Iteration)
  236.             
  237.         ' Wait a specified amount of time so the game doesn't go too fast!
  238.             
  239.         Call Wait(25) ' in milliseconds
  240.  
  241.         ' For each player that's lagging, wait a tiny amount of extra time
  242.  
  243.         For Pnum = 1 To 8
  244.             Call Wait(10 * Players(Pnum).IterationsLagging)
  245.         Next Pnum
  246.  
  247.         ' Update the directions players are going according to the last
  248.         ' communicated player control information signal.
  249.     
  250.         Call GetPlayerInputs
  251.     
  252.         ' Update the iteration number
  253.         
  254.         Iteration = Iteration + 1
  255.         
  256.     Loop Until PlayersAlive < 2 Or HostMode = hmQuitting
  257.  
  258.     ' Check if there's anybody left alive...
  259.  
  260.     Winner = 0
  261.     For Pnum = 1 To 8
  262.         If Players(Pnum).IsAlive Then
  263.             Winner = Pnum
  264.         End If
  265.     Next Pnum
  266.  
  267.     ' Return the results
  268.  
  269.     PlayRound = Winner
  270.  
  271. End Function
  272.  
  273. ' Set up initial players positions
  274. '
  275. Private Sub InitialiseRound()
  276.  
  277.     Dim I As Integer
  278.     
  279.     Do
  280.     
  281.         For I = 1 To 8
  282.    
  283.             If Players(I).IsAssigned Then
  284.        
  285.                 Players(I).X = (Rnd * (Game.SizeX - 10)) + 5
  286.                 Players(I).Y = (Rnd * (Game.SizeY - 10)) + 5
  287.                 Players(I).Direction = Int(Rnd * 4) + 1
  288.                 Players(I).IsAlive = True
  289.                 Players(I).IsReadyToStart = (Players(I).Name = "Computer") Or (I = LocalPlayer) ' Computer players and game server local player are always ready to start!
  290.                 Players(I).Nitro = MaxNitro
  291.                 Players(I).Brakes = MaxBrakes
  292.                 Players(I).LifeSavers = MaxLifeSavers
  293.                 
  294.             Else
  295.             
  296.                 Players(I).IsAlive = False
  297.             
  298.             End If
  299.        
  300.         Next I
  301.     
  302.     Loop Until PlayersFarEnough()
  303.  
  304. End Sub
  305.  
  306. ' Adds a new player and returns the player's color
  307. '
  308. Private Function AddNewPlayer(Name As String, PlayerAddress As Address) As Integer
  309.  
  310.     Dim Slot As Integer
  311.     
  312.     For Slot = 1 To 8
  313.         If Players(Slot).IsAssigned = False Then
  314.             Players(Slot).Name = Name
  315.             Players(Slot).Color = Val(Colors.Item(Slot))
  316.             Players(Slot).Crashes = 0
  317.             Players(Slot).Wins = 0
  318.             If IsNull(PlayerAddress) Then
  319.                 Set Players(Slot).Addr = PlayerAddress
  320.             Else
  321.                 Set Players(Slot).Addr = Nothing
  322.             End If
  323.             Players(Slot).IsAssigned = True
  324.             Exit For
  325.         End If
  326.     Next Slot
  327.        
  328.     AddNewPlayer = Slot
  329.        
  330. End Function
  331.  
  332. ' Call this procedure to attempt to join a game that has been listed.
  333. ' GameNumber indexing starts at 1.
  334. '
  335. Public Sub JoinGame(GameNumber As Integer)
  336.  
  337.     ' Set up PlayerTag, which is sent to server with every communication in order
  338.     ' for the server to quickly and surely identify which player's signal it has received.
  339.     
  340.     PlayerTag = CStr(Timer * 100)
  341.  
  342.     ' Now use Xceed Winsock Library to set up our client socket
  343.     ' and, if successful, we connect to game server.
  344.  
  345.     If SetUpClientSocket() Then
  346.         Call ConnectToGameServer(GameNumber)
  347.     End If
  348.  
  349. End Sub
  350.  
  351. ' This procedure sets up a game, runs the setup for the game server socket and
  352. ' then runs the game advertising function so that clients can find the game on the
  353. ' network.
  354. '
  355. Public Sub CreateGame()
  356.  
  357.         HostMode = hmHosting
  358.         
  359.         ' Set up master game data
  360.         
  361.         Game.CurrentRound = 1
  362.         Game.SizeX = GameForm.picGameArea.ScaleWidth
  363.         Game.SizeY = GameForm.picGameArea.ScaleHeight
  364.                 
  365.         ' Set up the game interface
  366.                 
  367.         Call GameForm.PrintInfo("Creating game...", False, vbRed)
  368.         
  369.         Call GameForm.SetState(isStartBusy)
  370.         
  371.         DoEvents
  372.         
  373.         ' Add local player to players list
  374.  
  375.         LocalPlayer = AddNewPlayer(GameForm.GetLocalName, Nothing)
  376.         
  377.         ' Call AddNewPlayer("Computer", Nothing) to add computer playrs (not good players!)
  378.                 
  379.         Call GameForm.SetPlayerColor(Players(LocalPlayer).Color)
  380.         
  381.         ' Continue setting up game.
  382.         
  383.         If SetUpServerSocket() = True Then    ' Set up server socket. Continue if success.
  384.         
  385.             If AdvertiseGame() = True Then    ' Advertise game with SAP. Continue if success.
  386.             
  387.                 Call GameForm.PrintInfo(GameForm.GetLocalName & "'s game created.", True, vbRed)
  388.                 Call GameForm.SetState(isGameHosted)
  389.                 
  390.             Else
  391.                 HostMode = hmIdle
  392.             End If
  393.             
  394.         Else
  395.             HostMode = hmIdle
  396.         End If
  397.  
  398. End Sub
  399.  
  400. ' This function unjoins a game, cleans up opened ressources
  401. ' If called with the ServerForced parameter set to True, it means
  402. ' that the server forced the unjoin and therefore we should not
  403. ' notify the server we have unjoined the game.
  404. '
  405. Public Sub UnjoinGame(ServerForced As Boolean)
  406.  
  407.     If HostMode = hmJoined Then
  408.         
  409.         If Not ServerForced Then
  410.             Call SendClientSignal(sUnjoining, "", True) ' True: make sure data is sent before client socket is destroyed.
  411.         End If
  412.         
  413.         Call ShutdownClientSocket
  414.     
  415.         HostMode = hmIdle
  416.         GameMode = gmIdle
  417.     
  418.         LocalPlayer = 0
  419.         
  420.     End If
  421.  
  422. End Sub
  423.  
  424. ' This function unjoins a game, cleans up opened ressources
  425. '
  426. Public Sub AbortGame()
  427.  
  428.     Dim Pnum As Integer
  429.  
  430.     Call SendGameSignal(sGameAborted, "", DP_All)
  431.  
  432.     ' Wait a bit to ensure signals have been sent out to clients before we
  433.     ' proceed to close our server socket. Of course, it would be better to
  434.     ' simply  send the signals with the blocking "SendBytesTo" call as opposed
  435.     ' to using "AsyncSendBytesTo" and waiting, but the SendGameSignal
  436.     ' procedure has 3 such calls and we wanted to keep it simple. But don't
  437.     ' worry, we use the proper technique in the NetClient.bas module when
  438.     ' closing the client socket.
  439.     
  440.     Call Wait(250) ' in milliseconds
  441.  
  442.     Call ShutdownServerSocket
  443.  
  444.     HostMode = hmIdle
  445.  
  446.     For Pnum = 1 To 8
  447.         Players(Pnum).IsAssigned = False
  448.     Next Pnum
  449.  
  450. End Sub
  451.  
  452. ' Move each player on the board based on their set directions, brakes and nitro,
  453. ' saving hem before crashing if they have lifesavers left. This function creates
  454. ' an XML-style string containing the new positions of all players and sends it
  455. ' to all the game's client players.
  456. '
  457. Private Function MovePlayers(Iteration As Long) As Integer
  458.  
  459.     Dim Pnum As Integer
  460.     Dim Deaths As Integer
  461.     Dim AddX As Integer
  462.     Dim AddY As Integer
  463.     Dim PlayerDied As Boolean
  464.     Dim NitroUpdate As Boolean
  465.     Dim BrakesUpdate As Boolean
  466.     Dim Speed As Long
  467.     Dim IterationData As String
  468.     
  469.     ' Build the IterationData string which will be sent to the clients
  470.     ' during a round update signal (sIteration)
  471.     
  472.     IterationData = "<iteration no=" & CStr(Iteration) & ">" & vbCrLf
  473.     
  474.     For Pnum = 1 To 8
  475.     
  476.         If Players(Pnum).IsAlive Then
  477.         
  478.             NitroUpdate = False
  479.             BrakesUpdate = False
  480.             PlayerDied = False
  481.             
  482.             ' Check if player is not lagging 3 or more iterations behind.
  483.             ' If not, then calculate player's speed. If yes, then freeze player.
  484.             
  485.             If (Iteration - LastPlayerReceivedIteration(Pnum)) < 3 Then
  486.                
  487.                 Players(Pnum).IterationsLagging = 0
  488.                  
  489.                 ' Check if player is nitro boosting or braking
  490.                 
  491.                 If Players(Pnum).IsBoosting And Players(Pnum).Nitro > 0 Then
  492.                     Speed = 2 + (Players(Pnum).Nitro Mod 8)
  493.                     Players(Pnum).Nitro = Players(Pnum).Nitro - 1
  494.                     NitroUpdate = True
  495.                 ElseIf Players(Pnum).IsBraking And Players(Pnum).Brakes > 0 Then
  496.                     If (Players(Pnum).Brakes Mod 2) Then Speed = 0 Else Speed = 2
  497.                     Players(Pnum).Brakes = Players(Pnum).Brakes - 1
  498.                     BrakesUpdate = True
  499.                 Else
  500.                     Speed = 2
  501.                 End If
  502.             
  503.             Else ' Lagging
  504.             
  505.                 Players(Pnum).IterationsLagging = Players(Pnum).IterationsLagging + 1
  506.                 Speed = 0
  507.             
  508.             End If
  509.         
  510.             ' If the player is moving this iteration, perform necessary checks
  511.         
  512.             If Speed > 0 Then
  513.             
  514.                 Select Case Players(Pnum).Direction
  515.                 Case dNorth
  516.                     AddX = 0
  517.                     AddY = -Speed
  518.                 Case dSouth
  519.                     AddX = 0
  520.                     AddY = Speed
  521.                 Case dEast
  522.                     AddX = Speed
  523.                     AddY = 0
  524.                 Case dWest
  525.                     AddX = -Speed
  526.                     AddY = 0
  527.                 End Select
  528.             
  529.                 If GameForm.picGameArea.Point(Players(Pnum).X + AddX, Players(Pnum).Y + AddY) <> &HFFFFFF Then
  530.                     
  531.                     If Players(Pnum).LifeSavers > 0 Then ' Try to save player's life
  532.                     
  533.                         Players(Pnum).LifeSavers = Players(Pnum).LifeSavers - 1
  534.                         Select Case Players(Pnum).Direction
  535.                         Case dNorth, dSouth ' we'll turn east or west to save life
  536.                             AddY = 0
  537.                             If Rnd > 0.5 Then
  538.                                 LastPlayerDirection(Pnum) = dEast
  539.                                 Players(Pnum).Direction = dEast
  540.                                 AddX = Speed
  541.                             Else
  542.                                 LastPlayerDirection(Pnum) = dWest
  543.                                 Players(Pnum).Direction = dWest
  544.                                 AddX = -Speed
  545.                             End If
  546.                         Case dEast, dWest ' we'll turn north of south to save life
  547.                             AddX = 0
  548.                             If Rnd > 0.5 Then
  549.                                 LastPlayerDirection(Pnum) = dSouth
  550.                                 Players(Pnum).Direction = dSouth
  551.                                 AddY = Speed
  552.                             Else
  553.                                 LastPlayerDirection(Pnum) = dNorth
  554.                                 Players(Pnum).Direction = dNorth
  555.                                 AddY = -Speed
  556.                             End If
  557.                         End Select
  558.                         
  559.                         PlayerDied = GameForm.picGameArea.Point(Players(Pnum).X + AddX, Players(Pnum).Y + AddY) <> &HFFFFFF
  560.                     
  561.                     Else
  562.                         
  563.                         PlayerDied = True
  564.                     
  565.                     End If
  566.                     
  567.                     If PlayerDied Then
  568.                         Players(Pnum).IsAlive = False
  569.                         Players(Pnum).Crashes = Players(Pnum).Crashes + 1
  570.                         Deaths = Deaths + 1
  571.                     End If
  572.                 
  573.                 Else
  574.                     Players(Pnum).X = Players(Pnum).X + AddX
  575.                     Players(Pnum).Y = Players(Pnum).Y + AddY
  576.                 End If
  577.             
  578.             End If
  579.             
  580.             ' Add the player's new position, or position of death to the
  581.             ' iteration data to send for this move. IterationData also
  582.             ' tells clients whether or not to update their brake and nitro gauges.
  583.             
  584.             IterationData = IterationData & "  <player playerid=" & CStr(Pnum) & ">" & vbCrLf
  585.             IterationData = IterationData & "    <pos x=" & CStr(Players(Pnum).X) & " y=" & CStr(Players(Pnum).Y) & " />" & vbCrLf
  586.                 
  587.             If PlayerDied Then
  588.                 IterationData = IterationData & "    <status alive=FALSE "
  589.             Else
  590.                 IterationData = IterationData & "    <status alive=TRUE "
  591.             End If
  592.             
  593.             If BrakesUpdate Then
  594.                 IterationData = IterationData & "updbrakes=" & CStr(Players(Pnum).Brakes) & " "
  595.             End If
  596.             If NitroUpdate Then
  597.                 IterationData = IterationData & "updnitro=" & CStr(Players(Pnum).Nitro) & " "
  598.             End If
  599.                         
  600.             IterationData = IterationData & "/>" & vbCrLf & "  </player>" & vbCrLf
  601.                         
  602.         End If
  603.     
  604.     Next Pnum
  605.  
  606.     IterationData = IterationData & "</iteration>"
  607.  
  608.     Call SendGameSignal(sIteration, IterationData, DP_All)
  609.  
  610.     MovePlayers = Deaths
  611.  
  612. End Function
  613.  
  614. ' This function indicates if two or more players are too close together
  615. ' in order to start a round.
  616. '
  617. Public Function PlayersFarEnough() As Boolean
  618.  
  619.     Dim CurrentPlayer As Integer
  620.     Dim CheckPlayer As Integer
  621.     Dim DistX As Long
  622.     Dim DistY As Long
  623.                
  624.     ' For each player, we check if there is at least 20 pixels distance between
  625.     ' that player and the rest of the players in line to be checked.
  626.             
  627.     For CurrentPlayer = 1 To 7 ' Do not do outer loop on last player.
  628.     
  629.         If Players(CurrentPlayer).IsAlive Then
  630.             
  631.             For CheckPlayer = CurrentPlayer + 1 To 8 ' Check remaining players
  632.                 
  633.                 DistX = Players(CurrentPlayer).X - Players(CheckPlayer).X
  634.                 DistY = Players(CurrentPlayer).Y - Players(CheckPlayer).Y
  635.                 
  636.                 ' Use pythagoras theorem to calculate distance
  637.                         
  638.                 If ((DistX * DistX + DistY * DistY)) < 400 Then
  639.                 
  640.                     PlayersFarEnough = False
  641.                     Exit Function
  642.                 
  643.                 End If
  644.             
  645.             Next CheckPlayer
  646.         
  647.         End If
  648.     
  649.     Next CurrentPlayer
  650.     
  651.     PlayersFarEnough = True
  652.     
  653. End Function
  654.  
  655. ' This procedure handles game signals received from the server or from the
  656. ' client.
  657. '
  658. ' Parameter       Description
  659. ' =============== ================================================================
  660. ' SignalPnum      Indicates which player (in the Players array) the signal is for
  661. ' GS              The game signal code
  662. ' Data            XML-style data that accompanies the signal
  663. '
  664. Public Sub ExecuteGameSignal(SignalPnum As Integer, GS As Signals, Data As String)
  665.  
  666.     Dim Pnum As Integer
  667.  
  668.     Select Case GS
  669.     Case sIteration ' From server: An iteration of a game-time round has been received.
  670.         
  671.         Dim Player As PlayerUpdate
  672.                
  673.         LocalIteration = Val(Mid$(Data, InStr(Data, "no=") + 3))
  674.                 
  675.         For Pnum = 1 To 8
  676.             Player = ParsePlayerData(Data, Pnum)
  677.                     
  678.             If Player.Found = True Then
  679.                 If Player.IsAlive Then
  680.                     GameForm.picGameArea.PSet (Player.X, Player.Y), Colors(Pnum)
  681.                 Else
  682.                     GameForm.picGameArea.Circle (Player.X, Player.Y), 2
  683.                 End If
  684.                     
  685.                 If Pnum = LocalPlayer Then
  686.                     If Player.UpdateBrakes > 0 Then
  687.                         Call GameForm.SetBrakeGauge(Player.UpdateBrakes)
  688.                     End If
  689.                         
  690.                     If Player.UpdateNitro > 0 Then
  691.                         Call GameForm.SetNitroGauge(Player.UpdateNitro)
  692.                     End If
  693.                 End If
  694.             End If
  695.         Next Pnum
  696.         
  697.         ' Inform game server of local player's latest desired move
  698.         
  699.         If HostMode = hmJoined Then
  700.             Call SendClientSignal(sPlayerControlUpdate, GetPlayerControlData(), False)
  701.         ElseIf HostMode = hmHosting Then
  702.             Call ExecuteGameSignal(LocalPlayer, sPlayerControlUpdate, GetPlayerControlData())
  703.         End If
  704.     
  705.     Case sPlayerControlUpdate ' From client: A player's latest desired move
  706.     
  707.         Dim Pos3 As Integer
  708.                 
  709.         LastPlayerReceivedIteration(SignalPnum) = Val(Mid$(Data, InStr(Data, "iteration=") + 10))
  710.                 
  711.         Pos3 = InStr(Data, "<direction d=")
  712.         
  713.         LastPlayerDirection(SignalPnum) = Val(Mid$(Data, Pos3 + 13))
  714.         LastPlayerIsBoosting(SignalPnum) = InStr(Data, "isboosting") > 0
  715.         LastPlayerIsBraking(SignalPnum) = InStr(Data, "isbraking") > 0
  716.     
  717.     Case sRoundStarting ' From server: A round is starting!
  718.         
  719.         Dim PlayerPos(8) As PlayerUpdate
  720.         Dim Blinks As Integer
  721.         Dim I As Integer
  722.         Dim DW As Integer
  723.         
  724.         ' Clear and setup game field and interface
  725.         
  726.         GameMode = gmPlaying
  727.         
  728.         Call GameForm.SetState(isRoundStarted)
  729.         Call GameForm.PrintInfo("Starting round " & CStr(Val(Mid$(Data, InStr(Data, "roundid=") + 8))) & "!", True, vbRed)
  730.         Call GameForm.ClearDisplay
  731.         Call GameForm.SetNitroGauge(MaxNitro)
  732.         Call GameForm.SetBrakeGauge(MaxBrakes)
  733.     
  734.         ' Decode data sent from server
  735.     
  736.         For Pnum = 1 To 8
  737.             PlayerPos(Pnum) = ParsePlayerData(Data, Pnum)
  738.         Next Pnum
  739.     
  740.         ' Display the starting player positions
  741.     
  742.         DW = GameForm.picGameArea.DrawWidth
  743.         GameForm.picGameArea.DrawWidth = 10
  744.                 
  745.         For Blinks = 1 To 5
  746.             For Pnum = 1 To 8
  747.                 If PlayerPos(Pnum).Found = True Then
  748.                     GameForm.picGameArea.PSet (PlayerPos(Pnum).X, PlayerPos(Pnum).Y), Colors(Pnum)
  749.                 End If
  750.             Next Pnum
  751.             
  752.             Call Wait(300) ' in milliseconds
  753.             
  754.             For Pnum = 1 To 8
  755.                 If PlayerPos(Pnum).Found = True Then
  756.                     GameForm.picGameArea.PSet (PlayerPos(Pnum).X, PlayerPos(Pnum).Y), vbWhite
  757.                 End If
  758.             Next Pnum
  759.             
  760.             Call Wait(200) ' in milliseconds
  761.             
  762.         Next Blinks
  763.  
  764.         GameForm.picGameArea.DrawWidth = DW
  765.         
  766.         ' Notify the server that we are now ready to start receiving round iterations
  767.         
  768.         If HostMode = hmJoined Then
  769.             Call SendClientSignal(sReadyToStart, "", True)
  770.         End If
  771.         
  772.     Case sReadyToStart ' From client: Client is ready to start the round now.
  773.     
  774.         Players(SignalPnum).IsReadyToStart = True
  775.         
  776.     Case sDroppedFromRound ' From server: We missed this round due to slow acknowledgement
  777.     
  778.         Call GameForm.PrintInfo("Dropped from this game round...", True, vbRed)
  779.         
  780.     Case sRoundCompleted ' From server: The round is over!
  781.     
  782.         If Data = "None" Then
  783.             Call GameForm.PrintInfo("Round over: no clear winner.", True, vbRed)
  784.         Else
  785.             Call GameForm.PrintInfo(Data & " wins the round!", True, vbRed)
  786.         End If
  787.         
  788.         Call GameForm.SetState(isRoundFinished)
  789.  
  790.         GameMode = gmIdle
  791.  
  792.     Case sRoundPaused ' From server: The round has been paused.
  793.         
  794.         Call GameForm.SetState(isRoundPaused)
  795.         
  796.     Case sRoundUnpaused ' From server: The round has been unpaused.
  797.  
  798.         Call GameForm.SetState(isRoundStarted)
  799.  
  800.     Case sRequestRoundStart ' From client: A player has requested the start of a round!
  801.     
  802.         If GameMode = gmIdle Then
  803.             StartRound
  804.         End If
  805.  
  806.     Case sRequestJoinGame ' From client: A player wishes to join the game
  807.     
  808.         Dim SlotFound As Boolean
  809.         Dim Pos As Integer
  810.         Dim Pos2 As Integer
  811.             
  812.         ' Check if there are any free slots in the Players array
  813.             
  814.         For Pnum = 1 To 8
  815.             If Players(Pnum).IsAssigned = False Then
  816.                 Players(Pnum).IsAssigned = True
  817.                 Set Players(Pnum).Addr = NewPlayerAddress
  818.                 Pos = InStr(Data, "name=" & Chr$(34))
  819.                 Pos2 = InStr(Pos + 6, Data, Chr$(34))
  820.                 Players(Pnum).Name = Mid$(Data, Pos + 6, Pos2 - Pos - 6)
  821.                 Pos = InStr(Data, "tag=")
  822.                 Players(Pnum).Tag = NewPlayerTag
  823.                 SlotFound = True
  824.                 Exit For
  825.             End If
  826.         Next Pnum
  827.       
  828.         ' Inform the client whether they can join in or not
  829.       
  830.         If SlotFound Then
  831.             Call SendGameSignal(sWelcome, "<player playerid=" & CStr(Pnum) & "></player>", Pnum)
  832.             Call SendGameSignal(sServerPrintInfo, Players(Pnum).Name & " has joined the game.", DP_All)
  833.         Else
  834.             Call SendGameSignal(sGameFull, "", DP_Last)
  835.         End If
  836.  
  837.     Case sWelcome ' From server: Player has succesfully joined the game
  838.     
  839.         LocalPlayer = Val(Mid$(Data, InStr(Data, "playerid=") + 9))
  840.     
  841.         Call GameForm.SetState(isGameJoined)
  842.         Call GameForm.ClearDisplay
  843.         Call GameForm.SetPlayerColor(Colors(LocalPlayer))
  844.         HostMode = hmJoined
  845.  
  846.     Case sGameFull ' From server: Player could not join the game
  847.     
  848.         Call GameForm.PrintInfo("That game is full! Not joined.", True, vbRed)
  849.  
  850.     Case sGameAborted ' From server: The game has been aborted, player no longer in game.
  851.     
  852.         Call GameForm.PrintInfo("The game has been aborted.", True, vbRed)
  853.         Call GameForm.SetState(isNoGameHostedOrJoined)
  854.         Call UnjoinGame(True)
  855.                  
  856.     Case sClientChat ' From client: Request to say a chat phrase
  857.     
  858.         Call SendGameSignal(sChatPhrase, Players(SignalPnum).Name & "> " & Data, DP_All)
  859.    
  860.     Case sChatPhrase ' From server: A chat phrase to display on the game interface
  861.         
  862.         Call GameForm.PrintInfo(Data, False, vbBlack)
  863.         
  864.     Case sServerPrintInfo ' From server: An important message to display on the game interface
  865.     
  866.         Call GameForm.PrintInfo(Data, True, vbRed)
  867.         
  868.     Case sScoresInfo ' From server: Scoring information to print out
  869.         
  870.         Call GameForm.PrintInfo(Data, False, vbBlue)
  871.         
  872.     Case sUnjoining ' From client: A notification that the player is leaving the game
  873.     
  874.         Players(SignalPnum).IsAssigned = False
  875.         Call SendGameSignal(sServerPrintInfo, Players(SignalPnum).Name & " left the game.", DP_All)
  876.                 
  877.     End Select
  878.  
  879. End Sub
  880.  
  881. ' Final preparations in order to make a clean exit of the application
  882. '
  883. Public Sub QuitApplication()
  884.  
  885.     If HostMode = hmHosting Then
  886.     
  887.         Call AbortGame
  888.             
  889.     ElseIf HostMode = hmJoined Then
  890.     
  891.         Call UnjoinGame(False)
  892.     
  893.     End If
  894.     
  895.     HostMode = hmQuitting
  896.  
  897. End Sub
  898.  
  899. ' This procedure returns a string containing the last known direction the
  900. ' player has tried to go to. The string is to be sent to the game server.
  901.  
  902. Public Function GetPlayerControlData() As String
  903.  
  904.     Dim Data As String
  905.     
  906.     Data = "<controls iteration=" & CStr(LocalIteration) & ">"
  907.     Data = Data & "  <direction d=" & CStr(LastLocalPlayerDirection) & " />"
  908.     If LastLocalPlayerIsBoosting Then Data = Data & "  <isboosting />"
  909.     If LastLocalPlayerIsBraking Then Data = Data & "  <isbraking />"
  910.     Data = Data & "</controls>"
  911.     
  912.     GetPlayerControlData = Data
  913.  
  914. End Function
  915.  
  916. ' This function checks if all the players that are assigned to the game
  917. ' have confirmed they are ready to start the round the server just told
  918. ' them is starting.
  919. '
  920. Function AllPlayersReadyToStart() As Boolean
  921.  
  922.     Dim AllReady As Boolean
  923.     Dim Pnum As Integer
  924.     
  925.     AllReady = True
  926.  
  927.     For Pnum = 1 To 8
  928.         If Players(Pnum).IsAssigned = True And Players(Pnum).IsReadyToStart = False Then
  929.             AllReady = False
  930.         End If
  931.     Next Pnum
  932.  
  933. End Function
  934.