'/*******************************************************************************
'* Here I declare some constants and global variables. That only impotant
'* for this module (gamestate).
'*
'* Everyone has somewhere its own name conventions as specifying its variable.
'* You will surely find your own. But here I describe mine.
'*
'* For constants, I am writing them in upper case. For AGK-Basic totally
'* unimportant, because the compiler works not case sensitive. But it looks
'* better (for my eyes).
'*
'* For global variables, I set a 'g_' at the front followed by another prefix
'* that describes the variable PPType. 'i' for integer, 'f' for float, 'sz' for
'* string and 't' for PPType variable. Finally, then comes the Simple tile name of
'* the variable. The first letter then big again.
'*
'* For global variables that are only important for the module, are similarly
'* written. Only the front is set to an 'm_' followed by the modulame (end with
'* underscore). The rest just like the global variables. >Good to know: You can
'* use all these variables in all modules. It's just a spelling like I prefer it.
'* They behave like all other global variables.
'*
'* AGK works with Id's for its objects/entities. You can receive an free id for
'* your object or you can foce an id. Every time you want to use an entity you
'* have to specify this id.
'* Also here I declare after a certain convention my entities id's.
'* SPRID_ for sprites, SFXID_ for sounds TXTID_ for text and FNTID_ for fonts
'* entities. Again followed by the module name. The last one is the real name.
'*
'*/

Const SFXID_GAME_BOUNCE                 = 1

Const SPRID_GAME_PUCK               = 1
Const SPRID_GAME_PLAYER1            = 2
Const SPRID_GAME_PLAYER2            = 3
Const SPRID_GAME_FIELDTOP           = 4
Const SPRID_GAME_FIELDBOTTOM        = 5
Const SPRID_GAME_FIELDCENTER        = 6

Const TXTID_GAME_SCORE1                 = 1
Const TXTID_GAME_SCORE2                 = 2
Const TXTID_GAME_COUNTDOWN          = 3
Const TXTID_GAME_BOUNCE                 = 4
Const TXTID_GAME_OPENING            = 5

'// Definition of constants for human or cpu player
Const GAME_PLAYERCONTROL_CPU        = 0
Const GAME_PLAYERCONTROL_HUMAN      = 1

'// Definition of some initial constants
Const GAME_BASE_SPEED               = 1000.0       '// Max. racket acceleration (units per sec.)
Const GAME_INIT_PUCK_SPEED          = 250.0         '// Start speed of the puck (units per sec.)
Const GAME_PUCK_ACCEL               = 10.0          '// Acceleration of the puck (units)
Const GAME_OPENING_TIME                 = 3.0               '// Game opening countdown (sec.)
Const GAME_PLAYTIME                     = 180.0         '// Round countdown (sec.)
Const GAME_FRICTION                     = 1.0               '// Friction of the racket

'*******************************************************************************
'*   TPuck (PPType)
'*
'*   This PPType is used to store puck related properties.
'*/

PPType TPuck
    Raw As float fDirX              '// X- movement diretion of the puck.
    Raw As float fDirY              '// Y- movement diretion of the puck.
    Raw As float fPosX              '// X- position of the puck.
    Raw As float fPosY              '// Y- position of the puck.

    Raw As float fSpeed             '// speed of the puck.
    Raw As integer iBounce          '// count every bounce to use as score.
End PPType

'/*******************************************************************************
'*   TPlayer (PPType)
'*
'*   This PPType is used to store player related properties.
'*/

PPType TPlayer
    Raw As float fPosX              '// X- Position of the player
    Raw As float fPosY              '// Y- Position of the player

    Raw As float fSpeed             '// speed of the player
    Raw As integer iScore           '// score of the player
    Raw As integer iControler       '// if player human or cpu.
End PPType

'// We need a variable to check if this module initialized or not. Starting value
'// is 0 (not initialized).
Raw As integer m_game_iInit = 0
Raw As TPuck m_game_tPuck                        '// define puck variable for this module.
Raw As TPlayer m_game_tPlayer1                   '// define player1 for this module.
Raw As TPlayer m_game_tPlayer2                   '// define player2 for this module.
Raw As integer m_game_iGameOver = 0              '// define game over variable for check if the game is over. Init valu is 0 (not over)
Raw As float m_game_fOpening = 0.0                '// define variable for opening countdown. Init value is 0.0 sec.
Raw As integer m_game_iGoal                      '// define variable for check is a goal has fallen.
Raw As float m_game_fTime                        '// define variable for round countdown.


'/*******************************************************************************
'*   InitGame()
'*
'*   To initialize all entities for the game. Loading and / or creating
'*   content for this module.
'*
'*/

Sub InitGame()
    '// Set the direction vector of the puck to 0.0.
    '// Directional vectors are used to determine a direction. The values are
    '// between -1.0 and 1.0 and the length of the vector should always be 1.0.
    m_game_tPuck.fDirX = 0.0
    m_game_tPuck.fDirY = 0.0

    '// Set the position of the puck on the center of the screen.
    m_game_tPuck.fPosX = g_iSWidth * 0.5        '// we stored the screen width in g_iSWidth. See file: main.agc function: InitMain
    m_game_tPuck.fPosY = g_iSHeight * 0.5       '// we stored the screen width in g_iSHeight. See file: main.agc function: InitMain

    '// Set puck speed to 0.0 and bounce count to 0.
    '// Create a sprite for the puck. Normally you use an image (number) for a
    '// nice looking sprite. Here we use 0 for a default sprite (solid color).
    '// Set sprite size to 16x16 units/pixels.
    '// Position the puck-sprite to the center of the screen. There exist two
    '// methods 'SetSpritePositionByOffset' and 'SetSpritePosition'. If you
    '// create a sprite, the offset will automaticly set to the center of the
    '// sprite. So if you use 'SetSpritePositionByOffset' the ancor is in the
    '// center. if you use 'SetSpritePosition' the ancor is on the top/left
    '// corner.
    m_game_tPuck.fSpeed = 0.0
    m_game_tPuck.iBounce = 0
    CreateSprite(SPRID_GAME_PUCK, 0)
    SetSpriteSize(SPRID_GAME_PUCK, 16, 16)
    SetSpritePositionByOffset(SPRID_GAME_PUCK, m_game_tPuck.fPosX, m_game_tPuck.fPosY)

    '// Set the position, speed and score of player1. Player1 are always human
    '// player. Set the controler to human
    '// Create Player! sprite. Set player1 sprite size position the sprite.
    '// Create/Add a virtual joystick to the right edge of the screen. This can
    '// be used to control the racket of player1.
    m_game_tPlayer1.fPosX = g_iSWidth - 64
    m_game_tPlayer1.fPosY = g_iSHeight * 0.5
    m_game_tPlayer1.fSpeed = 0.0
    m_game_tPlayer1.iScore = 0
    m_game_tPlayer1.iControler = GAME_PLAYERCONTROL_HUMAN
    CreateSprite(SPRID_GAME_PLAYER1, 0)
    SetSpriteSize(SPRID_GAME_PLAYER1, 16, 64)
    SetSpritePositionByOffset(SPRID_GAME_PLAYER1, m_game_tPlayer1.fPosX, m_game_tPlayer1.fPosY)

    '// If we start the game an a mobile device. we create a virtual joystick.
    If g_iDesktop = 0 Then
        AddVirtualJoystick(1, g_iSWidth - 32.0, g_iSHeight*0.5, 128)
    EndIf


    '// Same as above ...
    m_game_tPlayer2.fPosX = 64
    m_game_tPlayer2.fPosY = g_iSHeight * 0.5
    m_game_tPlayer2.fSpeed = 0.0
    m_game_tPlayer2.iScore = 0
    CreateSprite(SPRID_GAME_PLAYER2, 0)
    SetSpriteSize(SPRID_GAME_PLAYER2, 16, 64)
    SetSpritePositionByOffset(SPRID_GAME_PLAYER2, m_game_tPlayer2.fPosX, m_game_tPlayer2.fPosY)

    '// ... except create a virtual joystick. We check if it is a one or two
    '// player game.
    If g_iPlayers = 1 Then
        m_game_tPlayer2.iControler = GAME_PLAYERCONTROL_CPU     '// It is a one plaer game so the opponent is the cpu.
    ElseIf g_iPlayers = 2 Then
        m_game_tPlayer2.iControler = GAME_PLAYERCONTROL_HUMAN   '// It is a two player game so the opponent is a human.

        '// Again. If we start the game an a mobile device. we create a virtual joystick for player two.
        If g_iDesktop = 0 Then
            AddVirtualJoystick(2, 32.0, g_iSHeight*0.5, 128)        '// Also we create a virtual joystick on the left edge of the screen.
        EndIf
    EndIf

    '// Create the playfield.
    '// Top boundary over the whole screen width with a thickness of 8 pixels.
    '// Set the position a little down to leave room for score and countdown.
    CreateSprite(SPRID_GAME_FIELDTOP, 0)
    SetSpriteSize(SPRID_GAME_FIELDTOP, g_iSWidth, 8)
    SetSpritePosition(SPRID_GAME_FIELDTOP, 0, 52)

    '// Bottom boundary over the whole screen width with a thickness of 8 pixels.
    '// Set the position a little up to leave room for bounce count and opening
    '// countdown.
    CreateSprite(SPRID_GAME_FIELDBOTTOM, 0)
    SetSpriteSize(SPRID_GAME_FIELDBOTTOM, g_iSWidth, 8)
    SetSpritePosition(SPRID_GAME_FIELDBOTTOM, 0, g_iSHeight-52)

    '// Centerline. Thickness also 8 and from bottom to top boundary.
    CreateSprite(SPRID_GAME_FIELDCENTER, 0)
    SetSpriteSize(SPRID_GAME_FIELDCENTER, 8, g_iSHeight-104)
    SetSpritePosition(SPRID_GAME_FIELDCENTER, (g_iSWidth/2.0)-4, 52)

    '// Initialization of the random number generator. I use the timer for
    '// initialization.
    SetRandomSeed(Timer()*1000)

    '// Load the sound resource in the given id. File will be found in the media
    '// folder.
    LoadSound(SFXID_GAME_BOUNCE, "button.wav")

    '// Create a text, in this case to display the score of player1. Set the text
    '// size for this text, spacing between chars, font to use with this text,
    '// the alignment and the position of the text.
    '// Alignment: 0 = ancor point is the top/left corner of the text.
    '// Alignment: 1 = ancor point is the center/top edge of the text.
    '// Alignment: 2 = ancor point is the top/right corner of the text.
    CreateText(TXTID_GAME_SCORE1, "0000")
    SetTextFont(TXTID_GAME_SCORE1, FNTID_GAMEFONT)
    SetTextSize(TXTID_GAME_SCORE1, 48.0)
    SetTextSpacing(TXTID_GAME_SCORE1, 8)
    SetTextPosition(TXTID_GAME_SCORE1, g_iSWidth*0.75, 0.0)
    SetTextAlignment(TXTID_GAME_SCORE1, 1)

    '// Same as above.
    CreateText(TXTID_GAME_SCORE2, "0000")
    SetTextFont(TXTID_GAME_SCORE2, FNTID_GAMEFONT)
    SetTextSize(TXTID_GAME_SCORE2, 48.0)
    SetTextSpacing(TXTID_GAME_SCORE2, 8)
    SetTextPosition(TXTID_GAME_SCORE2, g_iSWidth*0.25, 0.0)
    SetTextAlignment(TXTID_GAME_SCORE2, 1)

    '// Same as above.
    CreateText(TXTID_GAME_OPENING, "0:00")
    SetTextFont(TXTID_GAME_OPENING, FNTID_GAMEFONT)
    SetTextSize(TXTID_GAME_OPENING, 48.0)
    SetTextSpacing(TXTID_GAME_OPENING, 8)
    SetTextPosition(TXTID_GAME_OPENING, g_iSWidth*0.5, g_iSHeight-48)
    SetTextAlignment(TXTID_GAME_OPENING, 1)

    '// Same as above.
    CreateText(TXTID_GAME_BOUNCE, "000")
    SetTextFont(TXTID_GAME_BOUNCE, FNTID_GAMEFONT)
    SetTextSize(TXTID_GAME_BOUNCE, 48.0)
    SetTextSpacing(TXTID_GAME_BOUNCE, 8)
    SetTextPosition(TXTID_GAME_BOUNCE, g_iSWidth*0.5, g_iSHeight-48)
    SetTextAlignment(TXTID_GAME_BOUNCE, 1)

    '// Same as above.
    CreateText(TXTID_GAME_COUNTDOWN, "0:00")
    SetTextFont(TXTID_GAME_COUNTDOWN, FNTID_GAMEFONT)
    SetTextSize(TXTID_GAME_COUNTDOWN, 48.0)
    SetTextSpacing(TXTID_GAME_COUNTDOWN, 8)
    SetTextPosition(TXTID_GAME_COUNTDOWN, g_iSWidth*0.5, 0)
    SetTextAlignment(TXTID_GAME_COUNTDOWN, 1)

    '// Set opening time variable to the initial opening time. Reset the round
    '// countdown. And set game over variable to game is not over. ;)
    m_game_fOpening = GAME_OPENING_TIME
    m_game_fTime = GAME_PLAYTIME
    m_game_iGameOver = 0

    '// Now this modul is initialized. Set the variable to 1. Mark it as
    '// initialized.
    m_game_iInit = 1
End Sub


'/*******************************************************************************
'*   ReleaseGame()
'*
'*   Release all content of this module.
'**
'*/

Sub ReleaseGame()
    DeleteSound(SFXID_GAME_BOUNCE)

    if GetVirtualJoystickExists(1) Then DeleteVirtualJoystick(1)
    if GetVirtualJoystickExists(2) Then DeleteVirtualJoystick(2)

    DeleteAllSprites()

    DeleteAllText()

    m_game_iInit = 0
End Sub

'/*******************************************************************************
'*   RunGame()
'*   RETURN VALUE    - new game state (handle this in the main loop.)
'*
'*   Main function of intro status. Processing at each loop until the status
'*   is active.
'*
'*/

Function RunGame()
    '// Declare a variable and store the current game state.
    Dim iState As integer
    iState = g_iState

    '// Check if game is initialized! If not than do it.
    '// (Call function: 'InitGame')
    If m_game_iInit = 0 Then InitGame()

    '// Check if the flag for game over is set to 1?
    If m_game_iGameOver = 1 Then
        '// Yes. Draw the game over screen.
        handleGameOverScreen()

        '// Check if the screnn is clickt or taped.
        If GetPointerPressed() Then Function = GAMESTATE_START  '// Yes. Exit function and return the new game state.

        '// No. Exit function and return the current game state.
        Function = GAMESTATE_GAME
    EndIf

    '// Is the opening countdown geater or equal than 0.0?
    If m_game_fOpening! >= 0.0 Then
        handleOpening()                 '// Yes. Call function 'handleOpening'
    ElseIf m_game_fTime! > 0.0 Then     '// No. But if the round time greater 0.0
        Decr m_game_fTime!, g_fFrameTime!    '// Yes. Decrement the round timer.
    EndIf

    '// Handle the player inputs.
    handlePlayerInput()

    '// Move all entities
    handleMoving()

    '// Handle player collision with the playfield boundary.
    handlePlayerCollision()

    '// If any one shot a goal?
    If m_game_iGoal = 0 Then handleBallCollision()  '// No. Also handle puck collision.

    '// draw all entities (playfield, player,puck, score and countdown)
    handleDrawing()
    Function = iState
End Function


'/*******************************************************************************
'*   handleOpening()
'*
'*   Handle the opening countdown. Decrement the counter. Set the speed to
'*   initial value and set new direction of the puck randomly.
'*
'*/

Sub handleOpening()
    '// Decrement the opening counter with the global frame time.
    Decr m_game_fOpening!, g_fFrameTime!

    '// Check if the opening counter below 0.0
    If m_game_fOpening < 0.0 Then
        '// Give the ball a random directional vector. In X direction between 5
        '// and 10 and in Y direction between 1 and 4. Random selection between
        '// left and right (+/-).
        m_game_tPuck.fDirX = RandomSign(Random(5, 10))
        m_game_tPuck.fDirY = Random(1, 4)

        '// The vector must be normalized. Normalized vectors have a length of
        '// 1.0 unit. First calculate the length of the vector (pytagoras). Then
        '// devide the X and Y component by length.
        Local fLength As float
        fLength = Sqrt(m_game_tPuck.fDirX*m_game_tPuck.fDirX + m_game_tPuck.fDirY*m_game_tPuck.fDirY)
        m_game_tPuck.fDirX = m_game_tPuck.fDirX / fLength
        m_game_tPuck.fDirY = m_game_tPuck.fDirY / fLength

        '// Set the puck speed to initial value.
        m_game_tPuck.fSpeed = GAME_INIT_PUCK_SPEED
    EndIf
End Sub


'/*******************************************************************************
'*   handlePlayerInput()
'*
'*   Query the game control. For player 1, player 2 and computer opponent.
'*
'*/

Sub handlePlayerInput()
    '// Declare variable for player movement.
    Local fP1Move As float
    Local fP2Move As float

    '// If we are in desktop mode?
    If g_iDesktop = 1 Then
        If GetRawKeyState(38) = 1 Then fP1Move = -1.0
        If GetRawKeyState(40) = 1 Then fP1Move = 1.0
    Else '// No. Use virtual joystick.
        '// Player one is always human. So get the move value from virtual joystick.
        fP1Move = GetVirtualJoystickY(1)
    EndIf

    '// Check if it is a two player game?
    If g_iPlayers > 1 Then
        '// Again. If we are in desktop mode.
        If g_iDesktop = 1 Then
            If GetRawKeyState(87) = 1 Then fP2Move = -1.0
            If GetRawKeyState(83) = 1 Then fP2Move = 1.0
        Else '// No. Use virtual joystick.
            fP2Move = GetVirtualJoystickY(2)    '// Yes. Also get move value for player 2 from virtual joystick.
        EndIf
    Else    '// No. Calculate the move direction.
        If m_game_tPlayer2.fPosY < m_game_tPuck.fPosY Then fP2Move = 1.0    '// If player 2 above the puck move down
        If m_game_tPlayer2.fPosY > m_game_tPuck.fPosY Then fP2Move = -1.0   '// If player 2 below the puck move up
    EndIf

    '// Calculate the speed of player rackets depency on frame time and new move
    '// direction.
    Incr m_game_tPlayer1.fSpeed, (GAME_BASE_SPEED * g_fFrameTime) * fP1Move
    Incr m_game_tPlayer2.fSpeed, (GAME_BASE_SPEED * g_fFrameTime) * fP2Move
End Sub


'/*******************************************************************************
'*   handleMoving()
'*
'*   Moving logic of players and puck.
'*
'*/

Sub handleMoving()
    '// Add the current speed (multiplied by the frame time) to the position of
    '// the player 1. Player can only move up and down.
    Incr m_game_tPlayer1.fPosY, (m_game_tPlayer1.fSpeed * g_fFrameTime)

    '// Add the current speed (multiplied by the frame time) to the position of
    '// the player 2. Player can only move up and down.
    Incr m_game_tPlayer2.fPosY, (m_game_tPlayer2.fSpeed * g_fFrameTime)

    '// Add the current speed (multiplied by the frame time) to the position of
    '// the puck. Direction vector multiplied with speed.
    Incr m_game_tPuck.fPosX, (m_game_tPuck.fDirX * m_game_tPuck.fSpeed * g_fFrameTime)
    Incr m_game_tPuck.fPosY, (m_game_tPuck.fDirY * m_game_tPuck.fSpeed * g_fFrameTime)

    '// Slow down players with friction multiplied by the frame time.
    m_game_tPlayer1.fSpeed = m_game_tPlayer1.fSpeed / (1.0 + GAME_FRICTION * g_fFrameTime)
    m_game_tPlayer2.fSpeed = m_game_tPlayer2.fSpeed / (1.0 + GAME_FRICTION * g_fFrameTime)

    '// If the speed between 0.5 and -0.5, set the speed to 0.0 for a final stop.
    If Abs(m_game_tPlayer1.fSpeed) < 0.5 Then m_game_tPlayer1.fSpeed = 0.0
    If Abs(m_game_tPlayer2.fSpeed) < 0.5 Then m_game_tPlayer2.fSpeed = 0.0

    '// Is the puck outside the playing field?
    If m_game_iGoal > 0 Then handleGoal()   '// Yes. Call function: 'handleGoal'
End Sub


'/*******************************************************************************
'*   handlePlayerCollision()
'*
'*   Handle players collision with top and bottom boundary.
'*
'*/

Sub handlePlayerCollision()
    '// Player1 top boundary collision.
    '// Does player1 collide with top boundary?
    If(GetSpriteCollision(SPRID_GAME_FIELDTOP, SPRID_GAME_PLAYER1)) Then
        '// Yes. Set player1 to the top boundary without overlap.
        m_game_tPlayer1.fPosY = 64 + GetSpriteHeight(SPRID_GAME_PLAYER1)/2.0

        '// Reverse and quarter the speed. (from move upward to move downward)
        m_game_tPlayer1.fSpeed = -(m_game_tPlayer1.fSpeed*0.25)
    EndIf


    '// Player1 bottom boundary collision.
    '// Does player1 collide with bottom boundary?
    If(GetSpriteCollision(SPRID_GAME_FIELDBOTTOM, SPRID_GAME_PLAYER1)) Then
        '// Yes. Set player1 to the bottom boundary without overlap.
        m_game_tPlayer1.fPosY = g_iSHeight - (56 + GetSpriteHeight(SPRID_GAME_PLAYER1)/2.0)

        '// Reverse and quarter the speed. (from move downward to move upward)
        m_game_tPlayer1.fSpeed = -(m_game_tPlayer1.fSpeed*0.25)
    EndIf

    '// Player2 top boundary collision.
    '// Does player2 collide with top boundary?
    If(GetSpriteCollision(SPRID_GAME_FIELDTOP, SPRID_GAME_PLAYER2)) Then
        '// Yes. Set player2 to the top boundary without overlap.
        m_game_tPlayer2.fPosY = 64 + GetSpriteHeight(SPRID_GAME_PLAYER2)/2.0

        '// Reverse and quarter the speed. (from move upward to move downward)
        m_game_tPlayer2.fSpeed = -(m_game_tPlayer2.fSpeed*0.25)
    EndIf

    '// Player2 bottom boundary collision.
    '// Does player2 collide with bottom boundary?
    If(GetSpriteCollision(SPRID_GAME_FIELDBOTTOM, SPRID_GAME_PLAYER2)) Then
        '// Yes. Set player2 to the bottom boundary without overlap.
        m_game_tPlayer2.fPosY = g_iSHeight - (56 + GetSpriteHeight(SPRID_GAME_PLAYER2)/2.0)

        '// Reverse and quarter the speed. (from move downward to move upward)
        m_game_tPlayer2.fSpeed = -(m_game_tPlayer2.fSpeed*0.25)
    EndIf
End Sub


'/*******************************************************************************
'*   handlePlayerCollision()
'*
'*   Handle puck collision with players and boundarys.
'*
'*/

Sub handleBallCollision()
    '// Declare a variable to register a bounce.
    Dim Raw iIsBounce = 0

    '// Puck top boundary collision.
    '// Does the puck collide with top boundary?
    If GetSpriteCollision(SPRID_GAME_PUCK, SPRID_GAME_FIELDTOP) Then
        '// Yes. Set the puck to top boundary without overlap.
        m_game_tPuck.fPosY = 64.0 + GetSpriteHeight(SPRID_GAME_PUCK)/2.0

        '// Reverse the y-component of the direction vector (from move upward to move downward)
        m_game_tPuck.fDirY = -m_game_tPuck.fDirY

        '// Register a bounce.
        iIsBounce = 1
    EndIf

    '// Puck bottom boundary collision.
    '// Does the puck collide with bottom boundary?
    If GetSpriteCollision(SPRID_GAME_PUCK, SPRID_GAME_FIELDBOTTOM) Then
        '// Yes. Set the puck to bottom boundary without overlap.
        m_game_tPuck.fPosY = g_iSHeight - (56.0 + GetSpriteHeight(SPRID_GAME_PUCK)/2.0)

        '// Reverse the y-component of the direction vector (from move downward to move upward)
        m_game_tPuck.fDirY = -m_game_tPuck.fDirY

        '// Register a bounce.
        iIsBounce = 1
    EndIf

    '// Puck -> player1 collision
    '// Is the puck in or behind the field of movement of the player1?
    '// X position of player1 is screen width - 64. Position of puck and player
    '// are centered. So we must add the half width of puck and player.
    If m_game_tPuck.fPosX > g_iSWidth - 76 Then
        '// Yes. Goal for player2?
        '// Is the puck behind player1?
        If m_game_tPuck.fPosX > g_iSWidth - 56 Then
            '// Yes. Goal for player2!!!
            m_game_iGoal = 2

            '// Exit function without any tests.
            Exit Sub
        EndIf

        '// No. Test player1 - puck collision.
        If GetSpriteCollision(SPRID_GAME_PLAYER1, SPRID_GAME_PUCK) = 1 Then
            '// Yes. Collision.

            '// Declare variable for length calculation. Needed for normalize a
            '// vector.
            Local fLength As float

            '// Set the puck on the left edge of player1. Without overlap.
            m_game_tPuck.fPosX = GetSpriteXByOffset(SPRID_GAME_PLAYER1) - 16

            '// This is the simple solution to let the puck bounce. According to
            '// the angle of incidence = angle of reflection.
            '//~ m_game_tPuck.fDirX = -m_game_tPuck.fDirX

            '// But we use here a more complex bounce characteristics. Depending
            '// on where the puck hits the racket, it bounce off at a more acute
            '// angle.
            '// Get player -> puck direction vector.
            m_game_tPuck.fDirX = m_game_tPuck.fPosX - m_game_tPlayer1.fPosX
            m_game_tPuck.fDirY = m_game_tPuck.fPosY - m_game_tPlayer1.fPosY

            '// Calc length of direction vector
            fLength = Sqrt(m_game_tPuck.fDirX*m_game_tPuck.fDirX + m_game_tPuck.fDirY*m_game_tPuck.fDirY)

            '// Normalize the direction vector.
            m_game_tPuck.fDirX = m_game_tPuck.fDirX / fLength
            m_game_tPuck.fDirY = m_game_tPuck.fDirY / fLength

            '// Register a bounce.
            iIsBounce = 1
        EndIf
    ElseIf m_game_tPuck.fPosX < 76.0 Then   '// No. Is the puck in or behind the field of movement of the player2?
        '// Yes. Goal for player1?
        '// Is the puck behind player2?
        If m_game_tPuck.fPosX < 56 Then
            '// Yes. Goal for player1!!!
            m_game_iGoal = 1

            '// Exit function without any tests.
            Exit Sub
        EndIf

        '// No. Test player2 - puck collision.
        If GetSpriteCollision(SPRID_GAME_PUCK, SPRID_GAME_PLAYER2) = 1 Then
            '// Yes. Collision.

            '// Set the puck on the right edge of player2. Without overlap.
            m_game_tPuck.fPosX = GetSpriteXByOffset(SPRID_GAME_PLAYER2) + 16

            '// This is the simple solution to let the puck bounce. According to
            '// the angle of incidence = angle of reflection.
            '//~ m_game_tPuck.fDirX = -m_game_tPuck.fDirX

            '// But we use here a more complex bounce characteristics. Depending
            '// on where the puck hits the racket, it bounce off at a more acute
            '// angle.
            '// Get player -> puck direction vector.
            m_game_tPuck.fDirX = m_game_tPuck.fPosX - m_game_tPlayer2.fPosX
            m_game_tPuck.fDirY = m_game_tPuck.fPosY - m_game_tPlayer2.fPosY

            '// Calc length of direction vector
            Local fLength As float
            fLength = Sqrt(m_game_tPuck.fDirX*m_game_tPuck.fDirX + m_game_tPuck.fDirY*m_game_tPuck.fDirY)

            '// Normalize the direction vector.
            m_game_tPuck.fDirX = m_game_tPuck.fDirX / fLength
            m_game_tPuck.fDirY = m_game_tPuck.fDirY / fLength

            '// Register a bounce.
            iIsBounce = 1
        EndIf
    EndIf

    '// Is any bounce registerd?
    If iIsBounce = 1 Then
        PlaySound(SFXID_GAME_BOUNCE) '// Yes. Play bounce sound.

        '// Increase the bounce count.
        Incr m_game_tPuck.iBounce

        '// Increase puck speed
        Incr m_game_tPuck.fSpeed, GAME_PUCK_ACCEL

        '// Declare string for new bounce text.
        Local szBounce$

        '// Convert bounce count (integer) to bounce string.
        szBounce$ = Str(m_game_tPuck.iBounce)

        '// We want leading zeros to our counter. So we set a string with three
        '// zeros. Cut the length of the bounce string from it. And stick the
        '// bounce string at the end.
        szBounce$ = Join$(2, Left("000", 3-Len(szBounce)), szBounce)

        '// Set the new string to our bounce text.
        SetTextString(TXTID_GAME_BOUNCE, szBounce$)
    EndIf
End Sub


'/*******************************************************************************
'*   handleDrawing()
'*
'*   There is not much to do. As soon as sprites have been created, and they have
'*   not been made invisible using the SetSpriteVisible(0) command. Are all
'*   sprites drawn automatically.
'*   So we use this function to put the new position of the puck-sprites and
'*   player-sprites. Besides, we change here the round-time counter and the
'*   opening time counter.
'*
'*/

Sub handleDrawing()
    '// Clear the screen with background color. Color was set in
    '// (file: 'main.agc'' -> function: 'MainInit')
    ClearScreen()

    '// Set new position for the puck.
    SetSpritePositionByOffset(SPRID_GAME_PUCK, m_game_tPuck.fPosX, m_game_tPuck.fPosY)

    '// Set new position for player1
    SetSpritePositionByOffset(SPRID_GAME_PLAYER1, m_game_tPlayer1.fPosX, m_game_tPlayer1.fPosY)

    '// Set new position for player1
    SetSpritePositionByOffset(SPRID_GAME_PLAYER2, m_game_tPlayer2.fPosX, m_game_tPlayer2.fPosY)

    '// Declare Strings for minutes und seconds.
    Local szMin$
    Local szSec$

    '// We need the minutes. Because the time is stored in seconds. We need to
    '// convert this in minutes without rest.
    szMin$ = Str(Trunc(m_game_fTime/60))

    '// Now we need the remaining seconds as String.
    'szSec = Str(Mod(m_game_fTime, 60))
	szSec$ = Str(Int(m_game_fTime) % 60)

    '// Now make the round-time counter string.
    szSec$ = Join$(2, Left("00", 2-Len(szSec$)), szSec$)

    '// And set the new string for the countdown text.
    SetTextString(TXTID_GAME_COUNTDOWN, Join$(3, szMin$, ":", szSec$))

    '// Check if the opening counter is active.
    If m_game_fOpening > 0.0 Then
        '// Yes. Build opening counter string/text.
        szMin$ = Str(Trunc(m_game_fOpening/60))
        'szSec = Str(Mod(m_game_fOpening, 60))
		szSec$ = Str(Int(m_game_fOpening) % 60)
        szSec$ = Join$(2, Left("00", 2-Len(szSec$)), szSec$)
        SetTextString(TXTID_GAME_OPENING, Join$(3, szMin$, ":", szSec$))

        '// And hide bounce text and show opening counter.
        SetTextVisible(TXTID_GAME_OPENING, 1)
        SetTextVisible(TXTID_GAME_BOUNCE, 0)
    Else
        '// No. Hide opening counter and show bounce text.
        SetTextVisible(TXTID_GAME_OPENING, 0)
        SetTextVisible(TXTID_GAME_BOUNCE, 1)
    EndIf
End Sub


'/*******************************************************************************
'*   handlePlayerCollision()
'*
'*   Is called by the function: 'handleMoving' when a goal has been registered.
'*
'*/

Sub handleGoal()
    '// Declare string to build the new score text.
    Local szScore$

    '// Goal for player1?
    If m_game_iGoal = 1 Then
        '// Yes. Inrease the score of player1 by bounce count.
        Incr m_game_tPlayer1.iScore, m_game_tPuck.iBounce

        '// Build new score text.
        szScore$ = Str(m_game_tPlayer1.iScore)
        szScore$ = Join$(2, Left("0000", 4-Len(szScore$)), szScore$)
        SetTextString(TXTID_GAME_SCORE1, szScore$)
    ElseIf m_game_iGoal = 2 Then '// No. Goal for player2?
        '// Yes. Inrease the score of player2 by bounce count.
        Incr m_game_tPlayer2.iScore, m_game_tPuck.iBounce

        '// Build new score text.
        szScore$ = Str(m_game_tPlayer2.iScore)
        szScore$ = Join$(2,Left("0000", 4-Len(szScore$)), szScore$)
        SetTextString(TXTID_GAME_SCORE2, szScore$)
    EndIf

    '// Set puck speed to zero.
    m_game_tPuck.fSpeed = 0.0

    '// Set new opening countdown.
    m_game_fOpening = GAME_OPENING_TIME

    '// Set goal flag to zero.
    m_game_iGoal = 0

    '// Set bounce count to zero and build new bounce count text.
    m_game_tPuck.iBounce = 0
    szScore$ = Str(m_game_tPuck.iBounce)
    szScore$ = Join$(2, Left("000", 3-Len(szScore$)), szScore$)
    SetTextString(TXTID_GAME_BOUNCE, szScore$)

    '// reset puck position and direction vector.
    m_game_tPuck.fDirX = 0.0
    m_game_tPuck.fDirY = 0.0
    m_game_tPuck.fPosX = g_iSWidth / 2.0
    m_game_tPuck.fPosY = g_iSHeight / 2.0

    '// Check if the game is over.
    '// If yes then put the game over flag to display the Gameover screen.
    If m_game_fTime <= 0.0 Then m_game_iGameOver = 1
End Sub


'/*******************************************************************************
'*   handleGameOverScreen()
'*
'*   Shows the Game-Over screen. This could have been made as an independent
'*   gamestate.
'*
'*/

Sub handleGameOverScreen()
    '// Calc half screen width.
    Local iHalfScreenWidth As integer
    iHalfScreenWidth = g_iSWidth * 0.5

    '// Clear the screen with background color. Color was set in
    '// (file: 'main.agc'' -> function: 'MainInit')
    ClearScreen()

    '// If we are not in desktop mode then hide virtual joysticks.
    If g_iDesktop = 0 Then
        SetVirtualJoystickVisible(1, 0)
        If g_iPlayers = 2 Then SetVirtualJoystickVisible(2, 0)
    EndIf


    '// Hide the playfield, player and the puck.
    SetSpriteVisible(SPRID_GAME_FIELDBOTTOM, 0)
    SetSpriteVisible(SPRID_GAME_FIELDCENTER, 0)
    SetSpriteVisible(SPRID_GAME_FIELDTOP, 0)
    SetSpriteVisible(SPRID_GAME_PLAYER1, 0)
    SetSpriteVisible(SPRID_GAME_PLAYER2, 0)
    SetSpriteVisible(SPRID_GAME_PUCK, 0)

    '// hide countdown text and shows bounce count text.
    SetTextVisible(TXTID_GAME_COUNTDOWN, 0)
    SetTextVisible(TXTID_GAME_BOUNCE, 1)

    '// The remaining text objects are encroached to display the ending.
    '// Set new text and positions.
    Local szScore$
    szScore$ = Str(m_game_tPlayer1.iScore)
    szScore$ = Join$(2,Left("0000", 4-Len(szScore$)), szScore$)
    SetTextString(TXTID_GAME_SCORE1, Join$(3, "PLAYER 1: ", szScore$, " SCORE"))
    SetTextPosition(TXTID_GAME_SCORE1, iHalfScreenWidth, g_iSHeight * 0.25)

    szScore$ = Str(m_game_tPlayer2.iScore)
    szScore$ = Join$(2,Left("0000", 4-Len(szScore$)) , szScore$)
    SetTextString(TXTID_GAME_SCORE2, Join$(3,"PLAYER 2: ",szScore$," SCORE"))
    SetTextPosition(TXTID_GAME_SCORE2, iHalfScreenWidth, g_iSHeight * 0.25 + 48.0)

    Local iWinner As integer
    If m_game_tPlayer1.iScore > m_game_tPlayer2.iScore Then
        iWinner = 1
    Else
        iWinner = 2
    EndIf

    SetTextString(TXTID_GAME_OPENING, Join$(3, "PLAYER ",Str(iWinner)," WINS"))
    SetTextPosition(TXTID_GAME_OPENING, iHalfScreenWidth, g_iSHeight*0.5)

    SetTextString(TXTID_GAME_BOUNCE, "TAP THE SCREEN TO CONTINUE")
    SetTextPosition(TXTID_GAME_BOUNCE, iHalfScreenWidth, g_iSHeight*0.5 + 48.0)
End Sub

