3-D Tankwars:

 

 

 

 

 

 

 

 

 

 Team Members:

 

Introduction:

            3-D Tankwars (name to be decided) is a multiplayer first person tank fighting game in the spirit of the old Macintosh game Spectre.  We anticipate implementing simple wire-frame 3-d graphics of a game world consisting of tanks and obstacles.  Multiplay will use UDP to allow 32 players to compete at once.  The game will track kills and games will be won when a player reaches a pre-set kill limit and a ranking will be calculated.   Our major goals were to implement fun game-play (most of all), wire-frame based 3-d graphics, and UDP network support.  Secondary goals are to incorporate some sort of sound.

Problem Description:

            The primary difference between this game and the others is that it uses a completely original 3-d renderer which creates the wireframe models of the tanks and displays them on the map.  Furthermore the multiplayer aspect of the game allows up to 32 players to compete at once which is many more than many other groups have attempted.  The game also required the creation of a completely original data structure for holding the data for each of the 32 tanks that will allow the information to be communicated among all 32 players quickly so that all computers will have relatively identical world maps.  Finally, the sound implementation had to be relatively optimized, as the rest of the game uses up a considerable amount of system resources, in order for sound to play smoothly.  Playing background music and sound effects added to the challenge.

 

Asynchronus Keyboard I/O:

            Both the UDP networking and the keyboard data is handled asynchronously.  The goal is to make the tank respond instantly to any changes in keyboard input.  The standard interrupt 9 handler is sufficient to provide this support.  Installing and removing the callback is the same as in previous mp’s but in order for movement changes to be instantaneous we must record key-presses as well as the key releases.  The scan codes for key releases are the same as for key presses except the 7 bit of the scan code is 1 instead of zero.  We then use a byte long bit-string to store the information about the status of the 5 key’s that require this sort of implementation in [_keyFlags] in our KeyboardISR.  This information is then translated to movement information in _keyUpdate and is stored in [_movementFlags].  [_movementFlags] is defined as follows:

 

_movementFlags : flags which are used in the local machine and

will be set by the keyboard callback and _keyUpdate.

bits 7 :  quit game

bits 6,5: unused for now

bits 4 :  shoot

bits 3 : move

bits 2 : dir {0=back, 1=forward}

bits 1 : turn

bits 0 : turn dir { 0=right, 1=left }

 

_keyFlags is defined as follows:

bit 7,6,5 : unused

bit 4 :    Space

bit 3 :    LeftArrow

bit 2 :    RightArrow

bit 1 :    UpArrow

bit 0 :    DownArrow

 

 

Storing Tank Information:

            Every piece of information intrinsic to each of the thirty two tanks is stored in the _TankArray.  It holds information such as the tank’s location, the direction its facing, the amount of damage it can take, whether its shooting or not, it’s color, and which tank the local tank is aiming at.  The x and y position are simply stored as integers in the x-y plane.  The rotation vector (_rot_vector_x, _rot_vector_y ) contains a direction vector which points from the center of the tank out in the direction it is facing with a magnitude of it’s speed.  Damage is simply an integer which indicates how much damage the tank has taken.  IsShooting is a bit-string which was left slightly large to allow for addition of other weapons in the future.  Bit 0 indicates whether to draw the laser as firing, bit 1 indicates whether to record damage from that tank to the tank indicated in target.  If target is 0FFh then that indicates a missed shot.   Color is simply the color the tank should be drawn in which is represented in the standard format alpha-red-green-blue format.  This model of storing tank information is very useful for a multiple player game because each local computer only applies changes to the local tanks entry in the tankArray and then broadcasts it over the network to all the other tanks which copy that updated information into their own tanksArray.  That way, each local tank can see the location and action information necessary to draw and implement game play.  The _tankArray is coded as follows.

 

_tankArray        resb  32*16

            ;word _x_pos

            ;word _y_pos

            ;word _rot_vector_x

            ;word _rot_vector_y

            ;word _damage                

            ;byte _isShooting

            ;dword      _color                 

            ;byte _target          

 

Furthermore there are several global pointers into the tankArray which have numerous uses throughout the game.  [_playerNumber] which indicates which number the local player is in the array and is indicated {1-32}.  [_playerOffset] which is the offset for the start of the entry indicated by [_playerNumber].

 

Moving the Tank on the Plane:

            The local tank must have some initial position.  This can be accomplish by assigning each tank a unique start position on the board that will be the same for every computer in the game, regardless of which _playerNumber is the local tank.  _initializeTankArray is our function for accomplishing this, here the initial start position is set, the start direction, the damage is set to max, it is marked as not shooting, the color is set so each tank is uniquely colored.  Movement of the local tank is accomplished with _moveTank which moves the tank forward and backwards according to the settings in [_movementFlags].  This is simply done by either adding or subtracting the rotation vector from the position vector.  This way the tank will translate along it’s direction.  The rotation is slightly more complicated and is accomplish in function _rotate.  _rotate calculates an angle from the rotation vector in radians using the FPU and adds or subtracts an angle from that angle according to [_movementFlags] and then converts that radian angle back into the direction vector by multiplying it’s sine and cosigne by the tank velocity constant.

 

Network overview:

Joining

The game has 3 different packet structures in use; Join, AckJoin, and Info.  The first client to attempt to join by broadcasting out a join packet.  If it does not receive a response after [_WaitCount] gets to TIMEOUT ticks, it assumes it is the first player and assigns itself player1.  The next player to join will broadcast out a join packet.  Player 1 will receive the packet and respond with an AckJoin packet containing the new total number of players and all their IPs (which is not needed in the present mode).  The new client will make its player number the new total number of players in the packet and copy the list of IPs to its local list.  All other clients will join similarly to the second player.

 

Gameplay

During the game, each player broadcasts its player info to everyone else whenever the data changes.  The other players receive the data and copy it into their local cache of player data, which is used to display the game map and player stats.

 

 

Algorithms:

 

3-D Drawing Algorithms:

;--------------------------------------------------------------

;--                   RotateArray()                          --

;--------------------------------------------------------------

;;; void _RotateArray(long *offset, short length, short angle)

;;; PURPOSE: rotates all points to camera angle

;;; INPUTS: array @ offset (of words), angle

;;; RETURNS: updated array with x and y coords offset

;;; CALLS: None

;;[cos(ang)  sin(ang)] => new x = cos(ang)*x+sin(ang)*y

;;[-sin(ang) cos(ang)] => new y =-sin(ang)*y+cos(ang)*x

;;  author : Allan Rudwick

 

takes an array of x,y,z, and rotates it angle degrees about the origin

 

 

;--------------------------------------------------------------

;--                   Translate()                          --

;--------------------------------------------------------------

;;; void _Translate(word X, word Y, long *offset, short length, short dir)

;;; PURPOSE: changes origin to where camera is located

;;; INPUTS: array @ offset (of words), x, y to translate to/from, direction (0=add/1 =sub <- sub mainly camera)

;;; RETURNS: updated array with x and y coords offset

;;; CALLS: None

;;  author : Allan Rudwick

 

adds a position offset to an array of length length and x,y,z values.

 

 

;--------------------------------------------------------------

;--                   FlagPoints()                          --

;--------------------------------------------------------------

;;; void _FlagPoints(long *offset, short length)

;;; PURPOSE: flag points that are behind the camera or far away from the camera

;;; INPUTS: array @ offset (of words)

;;; RETURNS: updated array

;;; CALLS: None

;;  author : Allan Rudwick

 

changes the x-coordinate of points behind the camera to FFFF to prevent them from being drawn

 

;--------------------------------------------------------------

;--                      ArrayToPixels()                     --

;--------------------------------------------------------------

;;; _ArrayToPixels(dword *offset, word length, dword *pixelOffset)

;;; PURPOSE: convert a point in 3D to 2D for display, uses FPU if X value = FFFF, leave as FFFF

;;; INPUTS: offset of array (of words), length

;;; RETURNS: array of x,y screen locations in pixelOffset

;;; CALLS: None

;;  author : Allan Rudwick

 

converts 3D array at offset of length to a 2D array for output to the screen

 

;--------------------------------------------------------------

;--                      DrawLine()                          --

;--------------------------------------------------------------

;;; void _DrawLine(short X1, short Y1, short X2, short Y2, long pixel)

;;; PURPOSE: Implements Bresenham's Algorithm.  If either input X is FFFFh, dont draw line

;;; INPUTS: X1,Y1,X2,Y2,long Pixel (color values)

;;; RETURNS: updated screen buffer

;;; CALLS: DrawPoint()

;;  author : Allan Rudwick

 

draws a line between 2 x,y points using the algorithm described in class

 

;--------------------------------------------------------------

;--                      SetupCamera()                      --

;--------------------------------------------------------------

;;; void _ParseArray(word playernum)

;;; PURPOSE: Sets CamX, CamY, CamAng to apply to tank

;;; INPUTS: [tankArray]

;;; RETURNS: CamX, CamY, CamAng

;;; CALLS:

;;  author : Allan Rudwick

 

initializes the camera so that it is behind the local tank

 

 

 

Network Algorithms:

;--------------------------------------------------------------

;--                      SetupNetwork()                      --

;--------------------------------------------------------------

;;; void SetupNetwork()

;;; PURPOSE: initialize the network

;;; INPUTS: _SocketHandler

;;; OUTPUTS: [_packoff], [_socket], _address structure, [_localIP]

;;;    [_gotdatagram], [_hostname]

;;; RETURNS: -1 if failed

;;; CALLS: _AllocMem, _InitSocket, _Socket_create,

;;;         _Socket_gethostname, _Socket_gethostbyname,

;;;         _Socket_inet_ntoa, _Socket_htons, _Socket_bind

;;;         _LockArea, _Socket_SetCallback, _Socket_AddCallback

;;;  author:  David Schmitz

Cleanup and return -1 if any call fails

 

Allocate memory for constructing packets

Initialize socket library by calling _Socket_create

Create a socket and store handle in [_socket]

-- not vital code, for future functionality

 Get local hostname and store in [_hostname]

 Use local hostname to get IP and store IP in [_localIP]

Write port to _address structure in network byte order

Bind socket to _address

Lock _gotdatagram and _SocketHandler to make them safe for

   the interrupt to handle

Set callback for network to _SocketHandler function

Add callbacks for SOCKEVENT_READ event

 

To cleanup

Clear socket callback if it was set

close the socket if it was open

call _ExitSocket to cleanup after Socket libraries

return -1

 

 

 

;--------------------------------------------------------------

;--                      SocketHandler()                     --

;--------------------------------------------------------------

;;; void _SocketHandler(int Socket, int Event)

;;; PURPOSE: sets [_gotdatagram] to 1 if interested packet recieved

;;; INPUTS: Socket and Event

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

Checks if our socket caused event and if it is SOCKEVENT_READ

if so, set [_gotdatagram] to 1

otherwise just return

 

 

;--------------------------------------------------------------

;--                                  gotData()                          --

;--------------------------------------------------------------

;;; void gotData()

;;; PURPOSE: Handles when data is received

;;; INPUTS: [_socket]

;;; OUTPUTS: [_gotdatagram], [_buf]

;;; RETURNS: None

;;; CALLS: _Socket_recvfrom, CheckPacketType

;;;  author:  David Schmitz

 

clears [_gotdatagram]

calls _Socket_recvfrom to put received data in [_buf]

call CheckPacketType to interpret received data

 

 

;--------------------------------------------------------------

;--                    CheckPacketType()                     --

;--------------------------------------------------------------

;;; void CheckPacketType()

;;; PURPOSE: Handle responses to received packets

;;; INPUTS: packet in [_buf], [_totalNumPlayers], [_playerNumber]

;;; OUTPUTS: [_playerNumber], [_IPArray], [_playerOffset]

;;; RETURNS: None

;;; CALLS: _SendPack

;;;  author:  David Schmitz

 

check first dword of [_buf] and see if it corresponds to any

      of the defined packet headers

If Join Packet type

   if player 1

      if [_totalNumPlayers] < MAXPLAYERS send valid join packet

      else send invalid join packet

   else ignore packet

If ACK Join Packet type

   if for valid player number

      copy new player number to [_totalNumPlayers]

      copy packet body to _IPArray

      if [_playerNumber] is 0, make it new player number

             also set new [_playerOffset]

If Info Packet type

   ignore if packet from local player

   if packet contains damage for local player

      subtract from local player's health in _tankArray

      if local health becomes less than 0, set exit in [_GameFlags]

      set flag to transmit player info inform others of change in health

   copy body of packet to appropriate player entry in _tankArray

--Quit and Game packets not implemented, for future functionality

return

 

 

;--------------------------------------------------------------

;--                    BuildJoinPacket()                     --

;--------------------------------------------------------------

;;; void BuildJoinPacket()

;;; PURPOSE: Set up buffer to send Join Packet

;;; INPUTS: [_packoff], [_packlen], [_localIP]

;;; OUTPUTS: packet at [_packoff]

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

Make Join packet - 8 bytes

Header is JOINHEAD (4 bytes, all zero's)

Body is the [_localIP] of joining player

 

 

;--------------------------------------------------------------

;--                    BuildAckJPacket()                     --

;--------------------------------------------------------------

;;; void BuildAckJPacket()

;;; PURPOSE: Set up buffer to send Ack Join Packet

;;; INPUTS: [_packoff], [_packlen], [_IPArray], [_totalNumPlayers]

;;; OUTPUTS: packet at [_packoff]

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

copy packet header to start of packet buffer, last byte of

     packet header is [_totalNumPlayers]

uses string instructions to copy [_IPArray] to packet buffer

 

 

 

;--------------------------------------------------------------

;--                    BuildInfoPacket()                     --

;--------------------------------------------------------------

;;; void BuildInfoPacket()

;;; PURPOSE: Set up buffer to send Info Packet

;;; INPUTS: [_packoff], [_packlen], [_playerNumber], _tankArray

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

copies packet header to start of packet buffer, last byte of

       packet header is [_playerNumber]

uses string instructions to copy player entry of _tankArray to buffer

 

 

;--------------------------------------------------------------

;--                    BuildQuitPacket()                     --

;--------------------------------------------------------------

;;; void BuildQuitPacket()

;;; PURPOSE: Set up buffer to send Quit Packet

;;; INPUTS: [_packoff], [_packlen], [_playerNumber]

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

copies QUIT packet header and packet length to [_packlen]

last byte of packet header is [_playerNumber]

 

 

;--------------------------------------------------------------

;--                    BuildGamePacket()                     --

;--------------------------------------------------------------

;;; void BuildGamePacket()

;;; PURPOSE: Set up buffer to send Game Packet

;;; INPUTS: [_packoff], [_packlen]

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

copies Game header to head of packet and length to [_packlen]

packet not used so no further spec

 

 

;--------------------------------------------------------------

;--                       _SendPack()                        --

;--------------------------------------------------------------

;;; int _SendPack(int .PacketType)

;;; PURPOSE: Sends packet of given entry in _packetArray

;;; INPUTS: PacketType, [_socket], [_packoff], _address array

;;; RETURNS: -1 if failed

;;; CALLS: Build*Packet, _Socket_htonl, _Socket_sendto

;;;  author:  David Schmitz

 

takes in an argument which corresponds to a packet type to send

calls entry in array corresponding to call of build function for

      respective packet

set _address structure address to BCASTADDR

call _Socket_sendto to send packet in packet buffer

     return -1 on error

reset address to 0's (INADDR_ANY)

return

 

 

;--------------------------------------------------------------

;--                       CleanupNet()                       --

;--------------------------------------------------------------

;;; void CleanupNet()

;;; PURPOSE: Cleans up after net code and prepares for closing

;;; INPUTS: None

;;; RETURNS: None

;;; CALLS: _Socket_SetCallback, _Socket_close, _ExitSocket

;;;  author:  David Schmitz

 

 

call _Socket_SetCallback to remove callback

call _Socket_close to close socket

call _ExitSocket to cleanup after socket library

 

 

 

Attribution Notes on Network Algorithms:

parts of SocketHandler and SetupNetwork were modified code from UDP

examples by Peter Johnson.  _Socket* calls are all part of winsock

wrappers present in pmodelib.  _ExitSocket and _InitSocket are also

part of pmodelib to initialize libraries and network data structures

_address is a structure defined as part of pmodelib

 

;;    ------------------------------------------------------

;;  void _rotate()

;;    ------------------------------------------------------

;;  inputs :      _movementFlags - stores which movements are to occur this tic

;;    outputs :     _tankArray - updates the rotation of the local tank.     

;;  author :        Peter F. Klemperer     

 

This function calculates rotates the local tank according to _movementFlags.  When a turn is indicated, the rotation vector is converted into a radian angle using the FPU arctangent function, a constant turn amount is added or subtracted from the angle, and the angle is converted back into a vector using the FPU sincos function and then multiplied by the velocity constant.

 

;;    ----------------------------------------------

;;    --                CheckNewLocation()                        --

;;    ---------------------------------------------- 

;;  int _CheckNewLocation(word _newX, word _newY )

;;  inputs :  _newX - the new x postion to be tested.

;;           _newY - the new y postion to be tested. 

;;           _tankArray - holds all the tank information

;;           _playerOffset - holds the local tank offset in tankArray.

;;           _lastPlayerOffset - holds the last legal tank offsetin tankArray

;;  outputs :  return 0 if legal, 1 if not legal.

;;  notes   :  bx contians _playerOffset

;;           cx contains the offset to the index of tankArray being checked.

;;  author :   Peter Klemperer

 

This function checks whether the newPosition is too close to all the other tanks in _tankArray.  NOTE!  If you check every tank entry you will always fail because the new vector will be inside the collision distance of it’s own tank’s original location, so that entry must be skipped.

 

;; -----------------------------------------------------------

;; --               void _moveTank()                    --

;; -----------------------------------------------------------

;; input :  _movementFlags - indicates the movement for this tic.

;;          _tankArray - holds the information for all the tanks.

;;          _playerOffset - holds the offset for the

;;                     local tank in _tankArray

;;

;; output : _tankArray - will hold the updated movement for the local tank

;;          eax holds 1 if tank moved, 0 if not

;; calls :  _CheckNewLocation - checks legality of chosen movement.

;; notes :  ebx holds the _playerOffset.

;; author : Peter Klemperer

 

This function moves the tank forwards and backwards according to _movementFlags.  The movement is accomplished by simply adding or subtracting the rotation vector from the position vector in the local tanks entry in _tankArray.  It then calls CheckNewLocation to vertify that the new position (indicated in _newX and _newY ) is not within the collision distance of any of the other tanks in the _tankArray.  If new position is legal, then the new values replace the old ones in the local tank entry.

 

Subroutines:

 

;--------------------------------------------------------------

;--                          shootFlags()                    --

;--------------------------------------------------------------

;;; void shootFlags()

;;; PURPOSE: Cleans up after net code and prepares for closing

;;; INPUTS: [_movementFlags] - flags whether shoot button was pressed

;;; OUTPUTS: [_TankArray] - set the ISSHOOTING flag for the local tank

;;;        [_movementFLags] - resets the flags for another shot.

;;; CALLS: none

;;; AUTHOR: Peter Klemperer

 

This function check whether each tank is firing and if it is, whether it’s firing at the local tank.  If so, the local tank has been damaged and damage is substracted from the local tanks Damage entry.

 

;;    ---------------------------------------------------

;;  _initializeTankArray  - initializes the tank array

;;    --------------------------------------------------

;;  inputs :  _tankArray

;;  outputs : _tankArray  - updates the values in the array.

;;  note :  the tanks are all initially on the y-axis with position dictated by playerNumber.

;;  initial damage amount is set by STARTDAMAGE and color is all green for now.

;;  author : Peter Klemperer

 

Initiliazes the tankArray so that all tanks have a unique start position.  Care must be used that the start locations are far enough apart that they are not within one anothers collision distance.  This function is covered more heavily earlier in the notes.

 

void _InitializeSound(void)                                Robert Tao

            - Initializes sound to get ready to play making use of DMA and SB16 libraries.

            - Loads the required wav files into memory so they can be played.

Inputs: None

Outputs: Updated DMA Buffer

Calls: _AllocMem, _OpenFile, _ReadFile, _LockArea, _CloseFile, _SB16_Init, _SB16_GetChannel, _SB16_SetFormat, _SB16_SetMixers, _DMA_Allocate_Mem, _DMA_Lock_Mem        

Notes:  Make sure all the necessary variables are set when gathering information from the called functions.

           

void _PlaySound(void)                         Robert Tao

-         Starts constantly transferring to DMA Buffer.

-         Starts constantly playing sound in DMA Buffer.

Inputs: None

Outputs: None

Calls:  _DMA_Start, _SB16_Start

Notes: Make sure the interrupt times are set after the intended portion of buffer has been played.

 

void _RefillDMABuffer(void)                Robert Tao

-         Refills Appropriate half of DMA Buffer

Inputs: None

Outputs: Updated DMA Buffer

Calls: _SB16_Start, _DMA_Stop, _SB16_Stop, _InitializeSound, _PlaySound

Notes: While one half of the buffer is being played, update the other half.  This way, there will not be any awkward pauses or stuttering in the song.  This is where adding up sounds to play two sounds can be implemented.  MMX commands can be used to add up the sounds to play multiple sounds.  Use flags set in different parts of the program to tell whether a sound should be played or what part of the buffer to refill.  If the song is about to end, switch to a single cycle so that it can be ended.  Afterwards, loop the song so that it plays constantly.

 

void _SoundISR(void)                          Robert Tao

            -Increments variables to check progress of DMA buffer

Inputs: None

Outputs: None

Calls: None

Notes: Update [_LoadBuffer] and [_ISRCalls]

 

 

 

;--------------------------------------------------------------

;--                      SetupNetwork()                      --

;--------------------------------------------------------------

;;; void SetupNetwork()

;;; PURPOSE: initialize the network

;;; INPUTS: None

;;; RETURNS: -1 if failed

;;; CALLS: _AllocMem, _InitSocket, _Socket_create,

;;;   _Socket_gethostname, _Socket_gethostbyname,

;;;   _Socket_inet_ntoa, _Socket_htons, _Socket_bind

;;;   _LockArea, _Socket_SetCallback, _Socket_AddCallback

;;;  author:  David Schmitz

 

 

;--------------------------------------------------------------

;--                      SocketHandler()                     --

;--------------------------------------------------------------

;;; void _SocketHandler(int Socket, int Event)

;;; PURPOSE: sets [_gotdatagram] to 1 if interested packet recieved

;;; INPUTS: Socket and Event

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

;--------------------------------------------------------------

;--                 gotData()                          --

;--------------------------------------------------------------

;;; void gotData()

;;; PURPOSE: Handles when data is received

;;; INPUTS: [_gotdatagram]

;;; RETURNS: None

;;; CALLS: _Socket_recvfrom, CheckPacketType

;;;  author:  David Schmitz

 

 

 

;--------------------------------------------------------------

;--                   DrawTank()                                        --

;--------------------------------------------------------------

;;; void _DrawTank(short X, short Y, short width, short length, short height1, short height2, long color, word angle, word damage, word tankid)

;;; PURPOSE: call PointToPixel, Drawline multiple times, draw a pyramid

;;; INPUTS: X,Y, halfwidth, halflength, height1, height2, color, angle (w/ respect to xy plane)

;;; RETURNS: updated screen buffer

;;; CALLS: ArrayToPixels, DrawLine, CenterArray, RotateArray, TranslateArray

;;;  author:  David Schmitz

 

;--------------------------------------------------------------

;--                    CheckPacketType()                     --

;--------------------------------------------------------------

;;; void CheckPacketType()

;;; PURPOSE: Handle responses to received packets

;;; INPUTS: packet in [_buf]

;;; RETURNS: None

;;; CALLS: _SendPack

;;;  author:  David Schmitz

 

;--------------------------------------------------------------

;--                    BuildInfoPacket()                     --

;--------------------------------------------------------------

;;; void BuildInfoPacket()

;;; PURPOSE: Set up buffer to send Info Packet

;;; INPUTS: None

;;; RETURNS: None

;;; CALLS: None

;;;  author:  David Schmitz

 

;--------------------------------------------------------------

;--                       _SendPack()                        --

;--------------------------------------------------------------

;;; int _SendPack(int .PacketType)

;;; PURPOSE: Sends packet of given entry in _packetArray

;;; INPUTS: PacketType

;;; RETURNS: -1 if failed

;;; CALLS: Build*Packet, _Socket_htonl, _Socket_sendto

;;;  author:  David Schmitz

 

;--------------------------------------------------------------

;--                       CleanupNet()                       --

;--------------------------------------------------------------

;;; void CleanupNet()

;;; PURPOSE: Cleans up after net code and prepares for closing

;;; INPUTS: None

;;; RETURNS: None

;;; CALLS: _Socket_SetCallback, _Socket_close, _ExitSocket

;;;  author:  David Schmitz

 

 

Main Loop:

 

;--------------------------------------------------------------

;--                        MP5Main()                         --

;--------------------------------------------------------------

_MP5Main

      call  _Initialize       ;

      mov   byte[_movementFlags], 0

      call  _initializeTankArray

 

 

      ;; Call to join game

      invoke      _SendPack, dword 0

      test  eax, eax

      js    near .EndGameLoop

 

 

     

.MainGameLoop:

      cmp   byte [_gotdatagram], 1                   

      je    .getdata

           

      test  byte [_GameFlags], 00000001b        ;     IF ESC BYTE INDICATED QUIT

      jnz   near .EndGameLoop