' Gambas module file

Private $hConfig As Window
Private $hTimer As Timer
' Scores
Private $iS1 As Integer
Private $iS2 As Integer
' Players' paddles
Private $hP1 As Paddle
Private $hP2 As Paddle
' If Paddle2 shall be controlled by an NPC object
Private $bNPC As Boolean
Private $hNPC As NPC
' The ball
Private $hBall As Ball

Public Sub Main()

  ' Make our Window raise events
  Object.Attach(Window, Me, "Window")
  Window.SetFocus()

  Screen.Cursor = Cursor.Hidden
  Screen.Echo = False
  Screen.Input = Input.CBreak

  Window.Border = Border.Ascii
  Window.Caption = Subst$(("Pong v&1 - gb.ncurses Example"), Application.Version)
  Window.Clear()

  $hConfig = New Window(True, 0, 0, 30, 5)
  $hConfig.Border = Border.Ascii
  $hConfig.Center()

  $hTimer = New Timer As "Timer"

  $iS1 = 0
  $iS2 = 0

  $bNPC = True
  GameInit()

End

Private Sub Configure()

  $hConfig.Show()
  $hConfig.Clear()
  $hConfig.PrintCenter(("What to do?\nPlay again: [P]\nChange opponent: [o]\n\nQuit [q]"))
  Select Case Window.Ask(("Poq"))
    Case ("o")
      Configure_Opponent()
    Case ("q")
      Quit
  End Select
  $hConfig.Hide()

End

Private Sub Configure_Opponent()

  $hConfig.Clear()
  $hConfig.PrintCenter(("Play against whom?\n[h]uman, [N]ormal, [m]aster"))
  $bNPC = True
  Select Case Window.Ask(("hNm"))
    Case ("h")
      $bNPC = False
    Case ("n")
      $hNPC.Mode = NPC.Normal
    Case ("m")
      $hNPC.Mode = NPC.Master
  End Select

End

Private Sub GameInit()

  ' If both as 'master' NPCs we could make a screensaver out of it :-)
  $hP1 = New Paddle(Window, 1)
  $hP2 = New Paddle(Window, -1)
  $hBall = New Ball(Window)
  $hNPC = New NPC(Window, $hBall, $hP2)
  GameStart()

End

Private Sub GameStart()

  Window.Buffered = False
  Configure()
  $hP1.Reset()
  $hP2.Reset()
  $hBall.Reset()
  $hNPC.Init()
  Window.Buffered = True
  Redraw()
  ' See SPEED. The width means actually the intra-paddle width:
  $hTimer.Delay = 4000 / Sqr(2 * (Window.Width - 4) ^ 2)
  $hTimer.Start()

End

Public Sub Timer_Timer()

  If $bNPC Then $hNPC.Move()
  Select Case $hBall.Move($hP1, $hP2)
    Case -1
      Inc $iS2
      Goto _NewGame
    Case 1
      Inc $iS1
      Goto _NewGame
  End Select
  ' I suppose that this does not go down to zero
  If $hBall.HitPaddle Then Dec $hTimer.Delay
  Redraw()
  Return

_NewGame:
  ' We want to see it
  Redraw()
  $hTimer.Stop()
  ' FIXME: Makes stack overflow eventually
  GameStart()

End

Public Sub Window_Read()

  Dim iKey As Integer

  iKey = Window.Read()
  Window.Drain()
  ' Go two steps per keystroke
  ' FIXME: Can't reach some coordinate with odd Window.Height
  Select Case iKey
    ' Player 1
    Case Key.Up
      If $hP1.Y > 0 Then $hP1.Y -= 2
    Case Key.Down
      If $hP1.Y + $hP1.Height < Window.Height Then $hP1.Y += 2
    ' Human player 2
    Case Asc("j")
      If Not $bNPC And $hP2.Y > 0 Then $hP2.Y -= 2
    Case Asc("k")
      If Not $bNPC And $hP2.Y + $hP2.Height < Window.Height Then $hP2.Y += 2
    ' Change ball speed :-)
    Case Asc("+")
      If $hTimer.Delay > 10 Then $hTimer.Delay -= 10
    Case Asc("-")
      $hTimer.Delay += 10
    ' Pause
    Case Asc(("p"))
      Pause()
    ' Quit
    Case Asc(("q"))
      Quit
    Case Else
      Return
  End Select
  Redraw()

End

Private Sub Redraw()

  Dim iX As Integer = Window.Width / 4

  ' Scores and net
  Window.Print(" " & Str$($iS1) & " ", iX, 1, Attr.Reverse)
  Window.Print(" " & Str$($iS2) & " ", iX * 3, 1, Attr.Reverse)
  Window.DrawVLine(Window.Width / 2 + 1, 0, Window.Height, ".")
  ' Players and ball may overwrite the unimportant stuff above
  $hP1.Draw()
  $hP2.Draw()
  $hBall.Draw()
  Screen.Refresh()

End

Private Sub Pause()

  $hTimer.Stop()
  Window.PrintCenter(("PAUSE"))
  Screen.Refresh()
  Window.Ask(("p"))
  Window.Clear()
  Redraw()
  $hTimer.Start()

End
