#include <GdiPlus.au3>
#include <Misc.au3>

Opt("GUIOnEventMode", 1)
$hGUI = GUICreate("Tetris", 288, 448, 192, 124)
GUISetOnEvent(-3, "_Exit")

GUISetState(@SW_SHOW)

Local $hUser32 = DllOpen("user32.dll")
_GDIPlus_Startup()

$hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
_GDIPlus_GraphicsClear($hGraphics)

Global $aField[9][14], $aBlock[4][2]

Local $aPalette[7] = [_GDIPlus_BrushCreateSolid(0xFF00FF00), _GDIPlus_BrushCreateSolid(0xFFFF0000), _GDIPlus_BrushCreateSolid(0xFFFF4500), _
					  _GDIPlus_BrushCreateSolid(0xFF0000FF), _GDIPlus_BrushCreateSolid(0xFFFFFF00), _GDIPlus_BrushCreateSolid(0xFF8888FF), _GDIPlus_BrushCreateSolid(0xFFFF00FF)]

$aBlock = _GenerateRandomBlock()
$iCurrColor = @extended
$iTurn = 0

$iScore = 0

Local $bLeft, $bRight, $bTurn, $bDown, $bDrop

AdlibRegister("_PushTheBlock", 850)

While Sleep(30)
	_GDIPlus_GraphicsClear($hGraphics)

	For $x = 0 To 8
		For $y = 0 To 13
			If $aField[$x][$y] Then _GDIPlus_GraphicsFillRect($hGraphics, $x * 32, $y * 32, 32, 32, $aPalette[$aField[$x][$y] - 1])
		Next
	Next

	For $i = 0 To 3
		_GDIPlus_GraphicsFillRect($hGraphics, $aBlock[$i][0] * 32, $aBlock[$i][1] * 32, 32, 32, $aPalette[$iCurrColor - 1])
	Next

	If _IsPressed("25", $hUser32) and Not $bLeft and Not _Collides($aBlock, -1, 0) Then
		For $i = 0 To 3
			$aBlock[$i][0] -= 1
		Next

		$bLeft = True
	ElseIf _IsPressed("27", $hUser32) and Not $bRight and Not _Collides($aBlock, 1, 0) Then
		For $i = 0 To 3
			$aBlock[$i][0] += 1
		Next

		$bRight = True
	ElseIf _IsPressed("26", $hUser32) and Not $bTurn and $iCurrColor <> 5 Then
		Switch $iCurrColor - 1
			Case 0 ;S-Block
				Switch $iTurn
					Case 0
						Local $tmpBlock[4][2] = [[$aBlock[0][0], $aBlock[0][1] - 2], [$aBlock[1][0] - 1, $aBlock[1][1] - 1], [$aBlock[2][0], $aBlock[2][1]], [$aBlock[3][0] - 1, $aBlock[3][1] + 1]]

					Case 1
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 2, $aBlock[0][1] + 1], [$aBlock[1][0] + 1, $aBlock[1][1]], [$aBlock[2][0], $aBlock[2][1] + 1], [$aBlock[3][0] - 1, $aBlock[3][1]]]

					Case 2
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 1, $aBlock[0][1] + 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] - 1, $aBlock[2][1] - 1], [$aBlock[3][0], $aBlock[3][1] - 2]]

					Case 3
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 1, $aBlock[0][1]], [$aBlock[1][0], $aBlock[1][1] + 1], [$aBlock[2][0] + 1, $aBlock[2][1]], [$aBlock[3][0] + 2, $aBlock[3][1] + 1]]
				EndSwitch

			Case 1 ;RS-Block
				Switch $iTurn
					Case 0
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 1, $aBlock[0][1] - 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] - 1, $aBlock[2][1] - 1], [$aBlock[3][0] - 2, $aBlock[3][1]]]

					Case 1
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 1, $aBlock[0][1] + 2], [$aBlock[1][0], $aBlock[1][1] + 1], [$aBlock[2][0] + 1, $aBlock[2][1]], [$aBlock[3][0], $aBlock[3][1] - 1]]

					Case 2
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 2, $aBlock[0][1]], [$aBlock[1][0] - 1, $aBlock[1][1] - 1], [$aBlock[2][0], $aBlock[2][1]], [$aBlock[3][0] + 1, $aBlock[3][1] - 1]]

					Case 3
						Local $tmpBlock[4][2] = [[$aBlock[0][0], $aBlock[0][1] - 1], [$aBlock[1][0] + 1, $aBlock[1][1]], [$aBlock[2][0], $aBlock[2][1] + 1], [$aBlock[3][0] + 1, $aBlock[3][1] + 2]]
				EndSwitch

			Case 2 ;L-Block
				Switch $iTurn
					Case 0
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 2, $aBlock[0][1] + 1], [$aBlock[1][0] + 1, $aBlock[1][1]], [$aBlock[2][0], $aBlock[2][1] - 1], [$aBlock[3][0] - 1, $aBlock[3][1]]]

					Case 1
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 1, $aBlock[0][1] + 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] + 1, $aBlock[2][1] - 1], [$aBlock[3][0], $aBlock[3][1] - 2]]

					Case 2
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 1, $aBlock[0][1]], [$aBlock[1][0], $aBlock[1][1] + 1], [$aBlock[2][0] + 1, $aBlock[2][1] + 2], [$aBlock[3][0] + 2, $aBlock[3][1] + 1]]

					Case 3
						Local $tmpBlock[4][2] = [[$aBlock[0][0], $aBlock[0][1] - 2], [$aBlock[1][0] - 1, $aBlock[1][1] - 1], [$aBlock[2][0] - 2, $aBlock[2][1]], [$aBlock[3][0] - 1, $aBlock[3][1] + 1]]
				EndSwitch

			Case 3 ;RL-Block
				Switch $iTurn
					Case 0
						Local $tmpBlock[4][2] = [[$aBlock[0][0], $aBlock[0][1] - 1], [$aBlock[1][0] - 1, $aBlock[1][1]], [$aBlock[2][0], $aBlock[2][1] + 1], [$aBlock[3][0] + 1, $aBlock[3][1] + 2]]

					Case 1
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 1, $aBlock[0][1] - 1], [$aBlock[1][0], $aBlock[1][1] - 2], [$aBlock[2][0] - 1, $aBlock[2][1] - 1], [$aBlock[3][0] - 2, $aBlock[3][1]]]

					Case 2
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 1, $aBlock[0][1] + 2], [$aBlock[1][0] + 2, $aBlock[1][1] + 1], [$aBlock[2][0] + 1, $aBlock[2][1]], [$aBlock[3][0], $aBlock[3][1] - 1]]

					Case 3
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 2, $aBlock[0][1]], [$aBlock[1][0] - 1, $aBlock[1][1] + 1], [$aBlock[2][0], $aBlock[2][1]], [$aBlock[3][0] + 1, $aBlock[3][1] - 1]]
				EndSwitch

			Case 5 ;I-Block
				Switch $iTurn
					Case 0
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 1, $aBlock[0][1] - 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] - 1, $aBlock[2][1] + 1], [$aBlock[3][0] - 2, $aBlock[3][1] + 2]]

					Case 1
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 2, $aBlock[0][1] + 1], [$aBlock[1][0] + 1, $aBlock[1][1]], [$aBlock[2][0], $aBlock[2][1] - 1], [$aBlock[3][0] - 1, $aBlock[3][1] - 2]]

					Case 2
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 2, $aBlock[0][1] + 2], [$aBlock[1][0] - 1, $aBlock[1][1] + 1], [$aBlock[2][0], $aBlock[2][1]], [$aBlock[3][0] + 1, $aBlock[3][1] - 1]]

					Case 3
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 1, $aBlock[0][1] - 2], [$aBlock[1][0], $aBlock[1][1] - 1], [$aBlock[2][0] + 1, $aBlock[2][1]], [$aBlock[3][0] + 2, $aBlock[3][1] + 1]]
				EndSwitch

			Case 6 ;T-Block
				Switch $iTurn
					Case 0
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 1, $aBlock[0][1] - 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] - 1, $aBlock[2][1] - 1], [$aBlock[3][0] - 1, $aBlock[3][1] + 1]]

					Case 1
						Local $tmpBlock[4][2] = [[$aBlock[0][0] + 1, $aBlock[0][1] + 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] + 1, $aBlock[2][1] - 1], [$aBlock[3][0] - 1, $aBlock[3][1] - 1]]

					Case 2
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 1, $aBlock[0][1] + 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] + 1, $aBlock[2][1] + 1], [$aBlock[3][0] + 1, $aBlock[3][1] -1]]

					Case 3
						Local $tmpBlock[4][2] = [[$aBlock[0][0] - 1, $aBlock[0][1] - 1], [$aBlock[1][0], $aBlock[1][1]], [$aBlock[2][0] - 1, $aBlock[2][1] + 1], [$aBlock[3][0] + 1, $aBlock[3][1] + 1]]
				EndSwitch
		EndSwitch

		If Not _Collides($tmpBlock, 0, 0) Then
			$aBlock = $tmpBlock
			$iTurn = Mod($iTurn + 1, 4)
		EndIf

		$bTurn = True
	ElseIf _IsPressed("28", $hUser32) and Not $bDown and Not _Collides($aBlock, 0, 1) Then
		_PushTheBlock()

		$bDown = True
	ElseIf _IsPressed("20", $hUser32) and Not $bDrop Then
		For $i = 0 To 14
			If _Collides($aBlock, 0, $i) Then ExitLoop
		Next

		For $x = 0 To $i
			_PushTheBlock()
		Next

		$bDrop = True
	EndIf


	If Not _IsPressed("25", $hUser32) Then $bLeft = False
	If Not _IsPressed("26", $hUser32) Then $bTurn = False
	If Not _IsPressed("27", $hUser32) Then $bRight = False
	If Not _IsPressed("28", $hUser32) Then $bDown = False
	If Not _IsPressed("20", $hUser32) Then $bDrop = False
WEnd

Func _Collides($aBlock, $iIncX, $iIncY)
	For $i = 0 To 3
		If $aBlock[$i][0] + $iIncX < 0 or $aBlock[$i][0] + $iIncX > 8 or $aBlock[$i][1] + $iIncY > 13 Then Return 1
	Next

	For $i = 0 To 3
		If $aField[$aBlock[$i][0] + $iIncX][$aBlock[$i][1] + $iIncY] Then Return 1
	Next
EndFunc

Func _PushTheBlock()
	If Not _Collides($aBlock, 0, 1) Then
		For $i = 0 To 3
			$aBlock[$i][1] += 1
		Next
	Else
		For $i = 0 To 3
			$aField[$aBlock[$i][0]][$aBlock[$i][1]] = $iCurrColor
		Next

		$aBlock = _GenerateRandomBlock()
		$iCurrColor = @extended
		$iTurn = 0

		If _Collides($aBlock, 0, 0) Then
			MsgBox(48, "Game Over", "Looks like you messed up!" & @CRLF & "Score: " & $iScore)
			Exit
		EndIf
	EndIf

	$m = 1

	Do
		Dim $aNewField[9][0] ;Dim nutzen damit alle vorherigen Einträge gelöscht werden.

		For $iRow = 0 To 13
			$m = 1

			For $iColumn = 0 To 8
				$m *= $aField[$iColumn][$iRow]
			Next

			If $m Then
				For $iRow_ = 0 To 13
					If $iRow_ = $iRow Then ContinueLoop

					ReDim $aNewField[9][UBound($aNewField, 2) + 1]

					For $i = 0 To 8
						$aNewField[$i][UBound($aNewField, 2) - 1] = $aField[$i][$iRow_]
					Next
				Next

				ExitLoop
			EndIf
		Next

		If UBound($aNewField, 2) Then
			Dim $aField[9][14]

			For $i = 14 - UBound($aNewField, 2) To 13
				For $i_ = 0 To 8
					$aField[$i_][$i] = $aNewField[$i_][$i - 14 + UBound($aNewField, 2)]
				Next
			Next

			$iScore += 1
			WinSetTitle($hGUI, "", "Tetris Score: " & $iScore)
		EndIf
	Until Not UBound($aNewField, 2)
EndFunc

Func _Exit()

	_GDIPlus_Shutdown()
	Exit
EndFunc

Func _GenerateRandomBlock()
	Local $iRandom = Random(1, 7, 1)

	Switch $iRandom
		Case 1 ;S-Block
			Local $aReturn[4][2] = [[3, 3], [4, 3], [4, 2], [5, 2]]

		Case 2 ;RS-Block
			Local $aReturn[4][2] = [[3, 2], [4, 2], [4, 3], [5, 3]]

		Case 3 ;L-Block
			Local $aReturn[4][2] = [[3, 1], [3, 2], [3, 3], [4, 3]]

		Case 4 ;RL-Block
			Local $aReturn[4][2] = [[3, 3], [4, 3], [4, 2], [4, 1]]

		Case 5 ;O-Block
			Local $aReturn[4][2] = [[3, 2], [3, 3], [4, 2], [4, 3]]

		Case 6 ;I-Block
			Local $aReturn[4][2] = [[3, 2], [4, 2], [5, 2], [6, 2]]

		Case 7 ;T-Block
			Local $aReturn[4][2] = [[3, 2], [4, 2], [4, 3], [5, 2]]

	EndSwitch

	SetExtended($iRandom)
	Return $aReturn
EndFunc