#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#cs ----------------------------------------------------------------------------

	AutoIt Version: 3.3.6.1
	Author:         oetzn (autoit.de)

	Script Function:
	Snake Mini-Game

	TO-DO:
	* Items einbauen CHECK
	* Level einbauen
	* Verhältnis Normale Items | Special Items in Ini-Speichern (If Abfrage Random Wert)

#ce ----------------------------------------------------------------------------

#include <GDIPlus.au3>
#include <GUIConstants.au3>
#include <Misc.au3>
#include <WinAPI.au3>

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

Opt("GuiCloseOnEsc", 0)
Opt("GuiOnEventMode", 1)
Opt("TrayOnEventMode", 1)
Opt("TrayMenuMode", 1)
Opt("MustDeclareVars", 1)

; STRINGS
Global Const $sTitle = "GDI+ SNAKE"
Global Const $sIniPath = @ScriptDir & "\" & $sTitle & ".ini"
Global Const $sString = "PRESS 'UP', 'DOWN', 'RIGHT' OR 'LEFT' TO BEGIN!"

; ARRAYS
Global $aC[1][3]
Global $aI[1][3]
Global $aP[1][3]
Global $aW[5][80][60] ; 5 Welten mit jeweils einer Größe von 80x60
Global $aITyp[4][2] = [["FASTER", 0xFF0000FF],["SLOWER", 0xFFFFFF00],["DOUBLE", 0xFFFF0000],["HALF", 0xFF00FF00]]

; WORLD 0 (CROSS)
For $i = 5 To 54
	$aW[0][40][$i] = 1
Next

For $i = 4 To 74
	$aW[0][$i][29] = 1
Next

; GUI
Global $GUIWidth = 320 * 3
Global $GUIHeight = 240 * 3

Local $hGUI, $hHelpGui, $hBitmap, $hBitmapWorld, $hGraphics, $hBuffer, $bBufferWorld, $hPenRed, $hPenGrey, $hPenBlue, $hPenGreen, $hPenYellow, $ButtonOK

; INTEGER
Global $iSpeed
Global $iDefSpeed
Global $iDefParts
Global $iParts
Global $iSize
Global $iMovement
Global $iScaleFactor
Global $iLevel
Global $iGrowOnFeed
Global $iTimerFaster
Global $iTimerSlower
Global $iSpeedFactor
Local $iXTemp
Local $iYTemp
Local $i, $j

; BOOLEAN
Global $bRunning = False
Global $bPaused = False
Global $bRestart = False
Global $bFaster = False
Global $bSlower = False

; FLOAT
Global $PlayTimer
Global $SpeedTimer

; INTERNAL USE
Global $bTimerDebug = False
Global $bElseDebug = True
Global $bDebugParts = False
Global $Timer

; READ INI
$iDefSpeed = IniRead($sIniPath, "Values", "Speed", 10)
$iDefParts = IniRead($sIniPath, "Values", "DefaultParts", 10)
$iScaleFactor = IniRead($sTitle, "Values", "ScaleFactor", 1)
$iGrowOnFeed = IniRead($sIniPath, "Values", "GrowOnFeed", 2)
$iTimerFaster = IniRead($sIniPath, "Values", "TimeFaster", 10)
$iTimerSlower = IniRead($sIniPath, "Values", "TimeSlower", 10)
$iSpeedFactor = IniRead($sIniPath, "Values", "Speedfactor", 5)

If $CmdLine[0] > 0 Then
	If Not IsNumber($CmdLine[1]) Then
		MsgBox(16, $sTitle, "ERROR!" & @CRLF & "Falscher Startparameter!")
		Exit
	ElseIf $CmdLine[1] > 5 Then
		MsgBox(16, $sTitle, "ERROR!" & @CRLF & "Maximale Levelanzahl: 5!")
		Exit
	Else
		$iLevel = $CmdLine[1]
	EndIf
EndIf

If Not IsNumber($iLevel) Then $iLevel = 0

$iSpeed = $iDefSpeed
$GUIWidth *= $iScaleFactor
$GUIHeight *= $iScaleFactor
$iSize = $GUIWidth / 80
$iParts = $iDefParts
$iMovement = $iSize

$aP[0][0] = $iSize
$aP[0][1] = $iSize

_GDIPlus_Startup()

$hGUI = GUICreate($sTitle, $GUIWidth, $GUIHeight)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit", $hGUI)

$hHelpGui = GUICreate($sTitle & " Hilfe", 368, 288, 200, 117)
GUICtrlCreateGroup("Kommandozeilenparameter ", 8, 8, 353, 121)
GUICtrlCreateLabel("Gültige Parameter sind natürliche Zahlen zwischen 0 und 5.", 16, 32, 284, 17)
GUICtrlCreateLabel("Zum Beispiel:", 16, 56, 67, 17)
GUICtrlCreateLabel("GDI+ Snake.exe 3", 88, 56, 92, 17)
GUICtrlCreateLabel("GDI+ Snake.exe 0", 200, 56, 92, 17)
GUICtrlCreateLabel("Kein Parameter entspricht dem Parameter 0.", 16, 80, 211, 17)
GUICtrlCreateLabel("Der Parameter gibt die Welt an, die zu Spielbeginn geladen werden soll. ", 16, 104, 344, 17)
GUICtrlCreateGroup("", -99, -99, 1, 1)
GUICtrlCreateGroup("Itemlegende ", 8, 136, 353, 113)
GUICtrlCreateLabel("Ein rotes Item verdoppelt die Länge der Schlagen.", 16, 152, 240, 17)
GUICtrlCreateLabel("Ein grünes Item halbiert die Länge der Schlagen.", 16, 176, 233, 17)
GUICtrlCreateLabel("Ein blaues Item lässt die Schlange kurzzeitig schneller werden.", 16, 200, 298, 17)
GUICtrlCreateLabel("Ein gelbes Item lässt die Schlange kurzzeitig langsamer werden.", 16, 224, 304, 17)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$ButtonOK = GUICtrlCreateButton("OK", 136, 256, 75, 25, $WS_GROUP)
GUICtrlSetOnEvent($ButtonOK, "_Help")

$hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)

$hBitmap = _GDIPlus_BitmapCreateFromGraphics($GUIWidth, $GUIHeight, $hGraphics)
$hBuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

$hBitmapWorld = _GDIPlus_BitmapCreateFromGraphics($GUIWidth, $GUIHeight, $hGraphics)
$bBufferWorld = _GDIPlus_ImageGetGraphicsContext($hBitmapWorld)

$hPenGrey = _GDIPlus_PenCreate(0xFF808080)
$hPenBlue = _GDIPlus_PenCreate($aITyp[0][1])
$hPenYellow = _GDIPlus_PenCreate($aITyp[1][1])
$hPenRed = _GDIPlus_PenCreate($aITyp[2][1])
$hPenGreen = _GDIPlus_PenCreate($aITyp[3][1])

For $i = 0 To 79
	For $j = 0 To 59
		If $aW[$iLevel][$i][$j] == 1 Then
			_GDIPlus_GraphicsDrawRect($bBufferWorld, $i * $iSize, $j * $iSize, $iSize, $iSize, $hPenGrey)
		EndIf
	Next
Next

HotKeySet("p", "_Pause")
HotKeySet("{F1}", "_Help")
HotKeySet("{F2}","_PlaceItem")

TrayTip($sTitle, $sString, 1)

GUISetState(@SW_SHOW, $hGUI)

While Not $bRunning
	Sleep(10)
	If _IsPressed(25) Or _IsPressed(26) Or _IsPressed(27) Or _IsPressed(28) Then $bRunning = True
WEnd

_PlaceItem()

AdlibRegister("_CheckInput", 10)

While 1

	If $bTimerDebug Then $Timer = TimerInit()
	_CheckCollision()
	_CheckTimer()
	If $bTimerDebug Then ConsoleWrite("COLLISION & TIMER CHECKING: " & TimerDiff($Timer) & @CRLF)

	If $bTimerDebug Then $Timer = TimerInit()

	For $i = 0 To UBound($aP, 1) - 1

		If $i == UBound($aP, 1) - 1 And $iParts > 0 Then
			$iXTemp = $aP[$i][0]
			$iYTemp = $aP[$i][1]
		EndIf

		Switch $aP[$i][2]
			Case "LEFT"
				$aP[$i][0] -= $iMovement
			Case "UP"
				$aP[$i][1] -= $iMovement
			Case "RIGHT"
				$aP[$i][0] += $iMovement
			Case "DOWN"
				$aP[$i][1] += $iMovement
		EndSwitch

		If $i == UBound($aP, 1) - 1 And $iParts > 0 Then
			ReDim $aP[UBound($aP, 1) + 1][3]
			$aP[UBound($aP, 1) - 1][0] = $iXTemp
			$aP[UBound($aP, 1) - 1][1] = $iYTemp
			$aP[UBound($aP, 1) - 1][2] = $aP[UBound($aP, 1) - 2][2]
			$iParts -= 1
		EndIf

		For $j = 0 To UBound($aC, 1) - 1
			Select
				Case $aC[$j][2] = ""
					ContinueLoop
				Case $aP[$i][0] == $aC[$j][0] And $aP[$i][1] == $aC[$j][1]
					$aP[$i][2] = $aC[$j][2]
					Select
						Case $i == UBound($aP, 1) - 1
							$aC[$j][2] = ""
					EndSelect
			EndSelect
		Next

	Next

	If $bTimerDebug Then ConsoleWrite("MOVING & CORNER & ADDING: " & TimerDiff($Timer) & @CRLF)

	If $bTimerDebug Then $Timer = TimerInit()

	_GDIPlus_GraphicsClear($hBuffer, 0xFFFFFFFF)

	For $i = 0 To UBound($aP, 1) - 1
		_GDIPlus_GraphicsDrawRect($hBuffer, $aP[$i][0], $aP[$i][1], $iSize, $iSize, 0)
	Next

	_DisplayItem()

	_GDIPlus_GraphicsDrawImageRect($hBuffer, $hBitmapWorld, 0, 0, $GUIWidth, $GUIHeight)
	_GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $GUIWidth, $GUIHeight)

	If $bTimerDebug Then ConsoleWrite("DRAWING EVERYTHING: " & TimerDiff($Timer) & @CRLF)
	If $bDebugParts Then ConsoleWrite("PARTS: " & UBound($aP,1) -1 & @TAB & "ECKEN: " & UBound($aC, 1) -1 & @CRLF & @CRLF)

	Sleep(1000 / $iSpeed)
WEnd

Func _Pause()
	If Not WinActive($sTitle) Then
		HotKeySet("p")
		Send("p")
		HotKeySet("p", "_Pause")
		Return
	EndIf

	$bPaused = Not $bPaused
	While $bPaused
		Sleep(100)
	WEnd
EndFunc   ;==>_Pause

Func _CheckInput()
	If $bPaused Then Return
	Local $bPressed = True

	Select
		Case _IsPressed(25) = 1
			If $aP[0][2] <> "RIGHT" Then $aP[0][2] = "LEFT"
		Case _IsPressed(26) = 1
			If $aP[0][2] <> "DOWN" Then $aP[0][2] = "UP"
		Case _IsPressed(27) = 1
			If $aP[0][2] <> "LEFT" Then $aP[0][2] = "RIGHT"
		Case _IsPressed(28) = 1
			If $aP[0][2] <> "UP" Then $aP[0][2] = "DOWN"
		Case Else
			$bPressed = False
	EndSelect

	If $bPressed = False Then Return

	If $bElseDebug Then ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : UBound($aC, 1) - 1 = ' & UBound($aC, 1) - 1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
	ReDim $aC[UBound($aC, 1) + 1][3]
	If $bElseDebug Then ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : UBound($aC, 1) - 1 = ' & UBound($aC, 1) - 1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
	$aC[UBound($aC, 1) - 1][0] = $aP[0][0]
;~ 	ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $aC[UBound($aC, 1) - 1][0] = ' & $aC[UBound($aC, 1) - 1][0] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
	$aC[UBound($aC, 1) - 1][1] = $aP[0][1]
;~ 	ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $aC[UBound($aC, 1) - 1][1] = ' & $aC[UBound($aC, 1) - 1][1] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
	$aC[UBound($aC, 1) - 1][2] = $aP[0][2]
;~ 	ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $aC[UBound($aC, 1) - 1][2] = ' & $aC[UBound($aC, 1) - 1][2] & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
EndFunc   ;==>_CheckInput

Func _CheckCollision()
	If $aP[0][0] < 0 Or $aP[0][0] > $GUIWidth Or $aP[0][1] < 0 Or $aP[0][1] > $GUIHeight Then _GameOver()
	If Not $iParts > 0 Then
		For $i = 1 To UBound($aP, 1) - 1
			If $aP[0][0] = $aP[$i][0] And $aP[0][1] = $aP[$i][1] Then _GameOver()
		Next
	EndIf

	For $i = 0 To 79
		For $j = 0 To 59
			If $aW[$iLevel][$i][$j] == 1 Then
				If $aW[$iLevel][$i][$j] == 1 And $aP[0][0] == $i * $iSize And $aP[0][1] == $j * $iSize Then _GameOver()
			EndIf
		Next
	Next

	If $aP[0][0] = $aI[0][0] And $aP[0][1] = $aI[0][1] Then
		Switch $aI[0][2]
			Case "NORMAL"
				$iParts += $iGrowOnFeed

			Case $aITyp[0][0]
				$iSpeed *= $iSpeedFactor
				$bFaster = True
				$SpeedTimer = TimerInit()

			Case $aITyp[1][0]
				$iSpeed /= $iSpeedFactor
				$bSlower = True
				$SpeedTimer = TimerInit()

			Case $aITyp[2][0]
				$iParts += (UBound($aP, 1) - 1)

			Case $aITyp[3][0]
				ReDim $aP[(UBound($aP, 1) - 1) / 2][3]

		EndSwitch
		_PlaceItem()
	EndIf
EndFunc   ;==>_CheckCollision

Func _CheckTimer()
	If $bFaster Then
		If TimerDiff($SpeedTimer) > $iTimerFaster * 1000 Then
			$iSpeed /= $iSpeedFactor
			$bFaster = False
		EndIf
	EndIf

	If $bSlower Then
		If TimerDiff($SpeedTimer) > $iTimerSlower * 1000 Then
			$iSpeed *= $iSpeedFactor
			$bSlower = False
		EndIf
	EndIf
EndFunc   ;==>_CheckTimer

Func _PlaceItem()
	Local $iRandom = Random(0, 10, 1)
;~ 	Local $iRandom = 8
	Local $iX
	Local $iY
	Local $bDisplay = False
	Local $bValid = False

	Do

		$iX = Random(5, 75, 1)
		$iY = Random(5, 55, 1)

		For $i = 0 To UBound($aP, 1) - 1
			If $aP[$i][0] <> $iX * $iSize And $aP[$i][1] <> $iY * $iSize And $aW[$iLevel][$iX][$iY] <> 1 Then
				$bDisplay = True
				ExitLoop
			EndIf
		Next

	Until $bDisplay = True

	$aI[0][0] = $iX * $iSize
	$aI[0][1] = $iY * $iSize

	If $iRandom < 7 Then
		$aI[0][2] = "NORMAL"
	Else
		Do
			$iRandom = Random(0, 3, 1)
;~ 			$iRandom = 2
			Switch $bFaster
				Case True
					If $iRandom <> 0 Then $bValid = True
				Case False
					$bValid = True
			EndSwitch

			Switch $bSlower
				Case True
					If $iRandom <> 1 Then $bValid = True
				Case False
					$bValid = True
			EndSwitch

			If $iRandom = 3 And UBound($aP, 1) - 1 = 1 Then $bValid = False

		Until $bValid = True

		$aI[0][2] = $aITyp[$iRandom][0]
	EndIf
EndFunc   ;==>_PlaceItem

Func _DisplayItem()
	Switch $aI[0][2]
		Case "NORMAL"
			_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize)
		Case $aITyp[0][0]
			_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenBlue)
		Case $aITyp[1][0]
			_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenRed)
		Case $aITyp[2][0]
			_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenYellow)
		Case $aITyp[3][0]
			_GDIPlus_GraphicsFillRect($hBuffer, $aI[0][0], $aI[0][1], $iSize, $iSize, $hPenGreen)
	EndSwitch
EndFunc   ;==>_DisplayItem

Func _Help()
	If Not WinActive($sTitle) Then
		HotKeySet("{F1}")
		Send("{F1}")
		HotKeySet("{F1}", "_Help")
		Return
	EndIf

	Switch _WinAPI_IsWindowVisible($hHelpGui)
		Case True
			GUISetState(@SW_HIDE, $hHelpGui)
		Case False
			GUISetState(@SW_SHOW, $hHelpGui)
	EndSwitch
EndFunc   ;==>_Help
Func _GameOver()
	If MsgBox(4, $sTitle, "GAME OVER" & @CR & "TRY AGAIN?") = 6 Then $bRestart = True
	_Exit()
EndFunc   ;==>_GameOver

Func _Exit()
	_GDIPlus_GraphicsDispose($hBuffer)
	_GDIPlus_BitmapDispose($hBitmap)
	_GDIPlus_GraphicsDispose($hGraphics)
	_GDIPlus_Shutdown()
	IniWrite($sIniPath, "Values", "Speed", $iDefSpeed)
	IniWrite($sIniPath, "Values", "DefaultParts", $iDefParts)
	IniWrite($sIniPath, "Values", "ScaleFactor", $iScaleFactor)
	IniWrite($sIniPath, "Values", "GrowOnFeed", $iGrowOnFeed)
	IniWrite($sIniPath, "Values", "TimeFaster", $iTimerFaster)
	IniWrite($sIniPath, "Values", "TimeSlower", $iTimerSlower)
	IniWrite($sIniPath, "Values", "Speedfactor", $iSpeedFactor)
	If $bRestart Then ShellExecute(@ScriptFullPath)
	Exit
EndFunc   ;==>_Exit