Sign in to follow this  
Followers 0
smashly

Automissile Commandit (Now with sound)

12 posts in this topic

#1 ·  Posted (edited)

Hi,

Just another trivial WIP game using GDI and GDIPlus.

First a quick Thank You to Frank Dod, Linus, UEZ, Malkey for code I've pinched.

Also thank you to anyone else I've neglected to mention who should be thanked.

Update Changes:

---------------

Added Sound using IrrKlang.

Added Random Appearing Low Orbit Satelite, (drops enemy missiles, be quick and beware!).

Added Timers for keyboard shoot keys.

Corrected Lines blatantly not colliding with booms at random times.

Corrected Game ending when a Bonus City was given while at the bonus screen when there was no Saved Cities.

Still ToDo:

-----------

Better suited sounds.

Gui for Settings

Color Schemes per level

Better game balance, tweaking and code tidy up.

Enemy Smart misiles that avoid your shots (this will be last of all, as I have no idea where to start)

Write the same game using au3irrlicht in 3D :)

Controls:

---------

Mouse Crosshair to tartget.

Left Arrow or Left Mouse Button = Fire Left Missile

Up Arrow or Middle Mouse Button = Fire Middle Missile

Right Arrow Or Right Mouse Button = Fire Right Missile

Enter = Toggle Start/Pause/Resume

Scores:

-------

Bonus City Every 10000

Destroy an Enemy Missile = 100

Destroy Sat Before missile drop = 1000

Destroy Sat After missile drop = 400

End of round bonus:

Surplus Ammo = 50 per shot

Saved City = 250 per city

Bonus Cities = 150 each

Zip attached to post includes Script with Sounds and IrrKlang files.

Unzip and run the AC.au3 script: AutomissileCommandit_v1.zip

Updated Script (works with or without sound), Have fun:

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GDIplus.au3>
#include <WinApi.au3>
#include <Misc.au3>

Opt("MustDeclareVars", 1)
Opt("GUIOnEventMode", 1)
Opt("GUIEventOptions", 1)
Opt("MouseCoordMode", 2)

Global Const $nPI = 4 * ATan(1)
Global Const $nPI_180 = $nPI / 180
Global Const $WM_MBUTTONDBLCLK = 0x0209
Global Const $WM_RBUTTONDBLCLK = 0x0206

; Vars used by IrrKlang sound
Global Enum $ESM_AUTO_DETECT, $ESM_STREAMING, $ESM_NO_STREAMING, $ESM_FORCE_32_BIT = 0x7fffffff ; E_STREAM_MODE
Global $_irrKlangDll

; Flag to set whether sound is enabled or disabled
Global $iSetSound = True ; False to disable sound

; Sound path
Global $sSound = @ScriptDir & "\Sound\"
; Sound files
Global $sBoom = $sSound & "Explosion.ogg"
Global $sShot = $sSound & "Shot.ogg"
Global $sAmmo = $sSound & "Ammo.wav"
Global $sNoAmmo = $sSound & "NoAmmo.ogg"
Global $sSat = $sSound & "Sat.ogg"
Global $sCity = $sSound & "CityExtra.ogg"
Global $sCityAdd = $sSound & "CityAdd.ogg"
Global $sStart = $sSound & "Start.ogg"
Global $sEndGame = $sSound & "EndGame.ogg"
Global $sAttract = $sSound & "Attract.ogg"
Global $sEndLevel = $sSound & "EndLevel.ogg"
Global $sPause = $sSound & "Pause.ogg"
Global $sLineStart = $sSound & "LineStart.ogg"
Global $sLineTravel = $sSound & "LineTravel.ogg"
Global $sHighScore = $sSound & "HighScore.ogg"

; User changable Line volume float value
; we reduce the volume of the lines traveling since we usually have multiple lines going at the same time,
; otherwise the sound of lines traveling would drown out all the other sounds.
Global $fLineVolume = 0.40

; We store the Attract and Line travel sounds because we are looping them and we want to be able to pause and unpause them as needed (user shouldn't change).
Global $hAttract, $hLineTravel

; These vars are flags to play or not play a sound (user shouldn't change).
Global $iEndSound, $iAttractSound, $iEndLevelSound, $iHighScoreSound

;Store settings in this ini.
Global $Ini = @ScriptDir & "\AC.ini"
Global $sTitle = "Automissile Commandit"
Global $hGui
Global $gW = 800 ; Gui Width, set this to whatever, it will scale the height to keep 4:3 ratio
Global $gH = Round(($gW / 4) * 3) ; Gui Height, it's advised not to change this.

; LEFT = Left Fire, UP = Middle Fire, RIGHT = Right Fire, ENTER = Start/Pause/Resume
Global $aKeys[5] = ["{LEFT}", "{UP}", "{RIGHT}", "{ENTER}"]

; Timers for firing shots when using keyboard keys (user shouldn't change).
Global $iLeftTimer = TimerInit(), $iMiddleTimer = TimerInit(), $iRightTimer = TimerInit()

; User Changable display times for messages, line start delays, shots delay
Global $iBlinkDelayTime = 700 ; MS time to flash "Press XXXXX To XXXXXX"
Global $iLevelEndDelay = 5000 ; MS time to display "Level XX Bonus"
Global $iGameOverDelay = 9000 ; MS time to display "GAME OVER"
Global $iHighSoreDelay = 5000 ; MS time to display ""CONGRADULATIONS New High Score = XXXXXXX"
Global $iLineStartDelay = 2250 ; MS time to start lines (Use this delay so the start sound doesn't overlap the lines sound when starting)
Global $iShotDelay = 150 ; MS Delay between shots being fired per turret when using keyboard keys.
;Internal use for flash message (User Shouldn't Change)
Global $iBlink = 1

; User Changable Colors (ARGB colors are used by GDIPlus, BGR Colors are used by GDI)
Global $iCrossColor = 0xFFFFFFFF ; ARGB Crosshair color
Global $iTurretColor = 0xFFAAAAAA ; ARGB Turret color
Global $iCityColor = 0xFF00FF00 ; ARGB City color
Global $iSatColor = 0xFF0000FF ; ARGB Sat color
Global $iShotColor = 0xFFFFFFFF ; ARGB shot color

Global $iLineColor = 0xFF0000 ; BGR Line Color
Global $iSkyColor = 0x000000 ; BGR Background color
Global $iTerrainColor = 0x0000FF ; BGR Terrain Color
Global $iTurretFontColor = $iTerrainColor ; BGR Turret Ammo Text Color
Global $iTextFontColor = 0xFFFFFF ; BGR Text Color for all other text.

; User Changable Line Settings
Global $iDefaultLineSpeedStart = 2 ; Step the line uses on starting a game (start speed the line travels)
Global $iDefaultLineSpeedMax = 3 ; Max step the line can be as the game progresses. (more step, less accurate collisin detection)
Global $iDefaultLinesActiveStart = 5 ; Lines on screen at once when starting game. (this does not take the Sat drop into account)
Global $iDefaultLinesActiveMax = 10 ; Max lines that can be on screen when the game progresses. (this does not take the Sat drop into account)
Global $iDefaultLinesTotal = 30 ; Amount of lines that the level has. (includes Sat drop lines)
Global $iDefaultLineDelayMin = 400 ; Min amount of MS before another line drops (Random Min, Max generated every line drop)
Global $iDefaultLineDelayMax = 1600 ; Max amount of MS before another line drops (Random Min, Max generated every line drop)
Global $iDefaultLineW = 3 ; Visual Line Width
; Internal Line settings (User Shouldn't Change)
Global $iLineSpeedStart = $iDefaultLineSpeedStart
Global $iLineSpeedMax = $iDefaultLineSpeedMax
Global $iLinesActiveStart = $iDefaultLinesActiveStart
Global $iLinesTotal = $iDefaultLinesTotal
Global $iLineDelayMin = $iDefaultLineDelayMin
Global $iLineDelayMax = $iDefaultLineDelayMax
Global $iLineW = $iDefaultLineW
Global $iLineDelay = Random($iLineDelayMin, $iLineDelayMax, 1)
Global $iLineTime = TimerInit()
Global $iLineStartTime
Global $iLinesActive = 0
Global $aLines[$iLinesTotal + 1][11]

; User Changable Shot settings
Global $iShotAmmo = 12 ; Maximum ammo per turret eg: 12 shots x3 turrets = 36 shots in total can be fired in the level.
Global $iShotMax = 3 ; Maximum shots per turret on screen eg: 3 shots x3 turrets = 9 shots could be on screen at the same time.
Global $iShotSpeed = 15 ; Shot Step (How fast the shot travels)
Global $iShotSize = 4 ; Visual size of the shot.
; Internal arrays for shots fired (User Shouldn't Change)
Global $aLeft[$iShotMax + 1][6], $aMiddle[$iShotMax + 1][6], $aRight[$iShotMax + 1][6]

; User Changable Boom Explosion settings
Global $iBoomMaxSize = 60 ; Size the boom expands to.
Global $iBoomStep = 4 ; expand and contract stepping (use $iBoomTD value to change the length of time it takes the boom to complete)
Global $iBoomTD = 40 ; MS timing for boom stepping, more MS slower, less MS faster
Global $aBoomColor[4] = [0xFFF5F5F5, 0xFFFFD700, 0xFFFFA500, 0xFFDC143C] ; ARGB colors for the boom explosion
; Internal use for Boom (User Shouldn't Change)
Global $iBoomMax = $iLinesActiveStart + ($iShotMax * 3)
Global $aBoom[$iBoomMax + 1][7]
Global $iBoomCount = 0

; User changable Sat Settings
Global $iSatDropMin = 2 ; Min amount of lines the Sat drops
Global $iSatDropMax = 5 ; Max amount of lines the Sat drops
Global $iSatLineW = 5 ; visual width of the pen that's used to draw the sat
; internal (User shouldn't change)
Global $iSatDrop ; This will be a random number based on $iSatDropMin and $iSatDropMax

; User Changeable Crosshair settings
Global $iCrossW = 20 ; Cross Width
Global $iCrossH = 20 ; Cross Height
Global $iCrossLineW = 2 ; Cross line Width

; User Changable Score values
Global $iScoreLine = 100 ; Score for user exploded line
Global $iScoreCity = 250 ; Score for saved city at end of level
Global $iScoreCityExtra = 150 ; Score for bonus city  at end of level
Global $iScoreShot = 50 ; Score for Surplus ammo  at end of level
Global $iBonusCityAt = 10000 ; Receive a bonus city every 10000
Global $iScoreSatAfter = 400 ; Score for Sat after line drop
Global $iScoreSatBefore = 1000 ; Score for sat before line drop
; Internal variables for score and other things (User Shouldn't Change)
Global $iScoreTotal = 0
Global $iScoreHigh = IniRead($Ini, "SETTINGS", "HS", 0)
Global $iScoreBonusAmmo = 0
Global $iScoreBonusCity = 0
Global $iScoreBonusCityExtra = 0
Global $iSurplusAmmo = 0
Global $iSurplusCity = 0
Global $iSurplusCityExtra = 0
Global $iSurplusTotal = 0
Global $sTotal = ""
Global $iBonusCityOffset = 1
Global $iBonusCity = 0
Global $iLevel = 1
Global $iLevelEnd = 4
Global $iLevelEndTimer = 0

; To stretch out the loop of difficulty set $iLevelMod to a higer number.
; eg; 2 would mean every 2nd level another line will be added to max lines on screen (If Lines Min is less then Lines Max).
; Also line speed and Line drop delay is scaled by the $iLevelMod
Global $iLevelMod = 2 ; How many levels before another line is added to max line on screen (Amongst other things).
; Internal (User shouldn't change)
; Vars related to next _Int_NextLevel() function, which gets called at the end of each level
; These scale amount of lines on screen per level, step the lines take (speed) and random delay of per line drop.
Global $iLevelMax = ($iDefaultLinesActiveMax - $iDefaultLinesActiveStart) * $iLevelMod ; will be the amount of levels to a complete cycle
Global $iLineDelayGap = $iDefaultLineDelayMax - $iDefaultLineDelayMin ; Gap between random for Line delay drop
Global $iLineDelayMinStep = $iDefaultLineDelayMin / $iDefaultLinesActiveMax ; Min minus step for Line delay drop
Global $iLineDelayMaxStep = $iLineDelayMinStep + ($iLineDelayGap / $iDefaultLinesActiveMax); Max minus step for Line delay drop
Global $iLevelLineStep = ($iDefaultLineSpeedMax - $iDefaultLineSpeedStart) / ($iLevelMax - 1) ; Line step added per level

; Internal measurements for terrain and turrets calculated by the Gui size. (User shouldn't change)
; Alot of other things in the game are based on these measurements!
Global $iBaseW = $gW / 17
Global $iTurretTopW = $iShotSize + 2
Global $iTurretH = Round($gH / 20) * 2
Global $iTerrainH = $iTurretH / 2
Global $tTerrain = _tRect(0, $gH - $iTerrainH, $gW, $iTerrainH)
Global $tSky = _tRect(0, 0, $gW, $gH - $iTerrainH)

; GDI vars (User shouldn't change)
Global $hDC, $hBMP, $hDC_Buffer, $hOldBMP, $hBrush_Sky, $hBrush_Terrain
Global $hPen_Line, $hOld_Pen, $hFont_Ammo, $hOld_Font, $hFont_Score, $hFont_Header, $hFont_Bonus, $hFont_Over

; GDIPlus vars (User shouldn't change)
Global $hBuffer_Graphic, $hBrush_Shot, $hBrush_Boom, $hPen_Cross, $hPen_Sat, $hBrush_City, $hBrush_Turret

; arrays for Mouse pos, Turrets and Cities (User shouldn't change)
Global $aTurret[4][6], $aCity[7][3], $aMouse[2], $aSat[8][2]

; Pause related vars (User shouldn't change)
Global $iPauseLast, $iCursor, $iHotKeyState

; Font vars
Global $atFontAmmo[3]
Global $iFontSizeAmmo = ($iTerrainH / 3) * 2
Global $iFontWeightAmmo = 600
Global $iFontItalicAmmo = 0
Global $iFontUnderlineAmmo = 0

Global $atFontScore[4]
Global $iFontSizeScore = $iTerrainH
Global $iFontWeightScore = 600
Global $iFontItalicScore = 0
Global $iFontUnderlineScore = 0

Global $atFontBonus[2]
Global $iFontSizeHeader = $iTerrainH * 1.5
Global $iFontWeightHeader = 700
Global $iFontItalicHeader = 0
Global $iFontUnderlineHeader = True

Global $atFontOver[3]
Global $iFontSizeOver = ($gW / $gH) * 50
Global $iFontWeightOver = 700
Global $iFontItalicOver = 0
Global $iFontUnderlineOver = 0


$hGui = GUICreate($sTitle, $gW, $gH)
GUISetBkColor(0x000000, $hGui)
GUISetOnEvent($GUI_EVENT_CLOSE, "_GuiEvent", $hGui)
GUISetOnEvent($GUI_EVENT_MINIMIZE, "_GuiEvent", $hGui)
GUISetOnEvent($GUI_EVENT_RESTORE, "_GuiEvent", $hGui)
_StartUp() ; Initiate startup before showing the GUI, this way the Gui is responsive straight away when shown.
GUISetState(@SW_SHOW, $hGui)

While 1
    If Not WinActive($hGui) Then
        If $iLevelEnd <> 4 And $iLevelEnd <> 5 Then _StartPause()
        If $iHotKeyState Then _ToggleHotKeys(1)
    Else
        If Not $iHotKeyState Then _ToggleHotKeys()
    EndIf
    Sleep(10)
WEnd

Func _StartUp()
    ; Start the sound if it exists and $iSetSound is True
    _Init_Sound()

    ; Register mouse clicks with the Gui
    GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN")
    GUIRegisterMsg($WM_LBUTTONDBLCLK, "_WM_LBUTTONDOWN")
    GUIRegisterMsg($WM_MBUTTONDOWN, "_WM_MBUTTONDOWN")
    GUIRegisterMsg($WM_MBUTTONDBLCLK, "_WM_MBUTTONDOWN")
    GUIRegisterMsg($WM_RBUTTONDOWN, "_WM_RBUTTONDOWN")
    GUIRegisterMsg($WM_RBUTTONDBLCLK, "_WM_RBUTTONDOWN")

    ; GDI Resources
    $hDC = _WinAPI_GetDC($hGui)
    $hBMP = _WinAPI_CreateCompatibleBitmap($hDC, $gW, $gH)
    $hDC_Buffer = _WinAPI_CreateCompatibleDC(0)
    $hOldBMP = _WinAPI_SelectObject($hDC_Buffer, $hBMP)
    _WinAPI_SetBkMode($hDC_Buffer, $TRANSPARENT)
    $hPen_Line = _WinAPI_CreatePen($PS_SOLID, $iLineW, $iLineColor)
    $hOld_Pen = _WinAPI_SelectObject($hDC_Buffer, $hPen_Line)
    $hFont_Ammo = _WinAPI_CreateFont($iFontSizeAmmo, 0, 0, 0, $iFontWeightAmmo, $iFontItalicAmmo, $iFontUnderlineAmmo)
    $hOld_Font = _WinAPI_SelectObject($hDC_Buffer, $hFont_Ammo)
    $hFont_Score = _WinAPI_CreateFont($iFontSizeScore, 0, 0, 0, $iFontWeightScore, $iFontItalicScore, $iFontUnderlineScore)
    $hFont_Header = _WinAPI_CreateFont($iFontSizeHeader, 0, 0, 0, $iFontWeightHeader, $iFontItalicHeader, $iFontUnderlineHeader)
    $hFont_Over = _WinAPI_CreateFont($iFontSizeOver, 0, 0, 0, $iFontWeightOver, $iFontItalicOver, $iFontUnderlineOver)
    $hBrush_Sky = _WinAPI_CreateSolidBrush($iSkyColor)
    $hBrush_Terrain = _WinAPI_CreateSolidBrush($iTerrainColor)

    ; GDIPlus Resources
    _GDIPlus_Startup()
    $hBuffer_Graphic = _GDIPlus_GraphicsCreateFromHDC($hDC_Buffer)
    $hBrush_Shot = _GDIPlus_BrushCreateSolid($iShotColor)
    $hBrush_Boom = _GDIPlus_BrushCreateSolid($aBoomColor[0])
    $hBrush_City = _GDIPlus_BrushCreateSolid($iCityColor)
    $hBrush_Turret = _GDIPlus_BrushCreateSolid($iTurretColor)
    $hPen_Cross = _GDIPlus_PenCreate($iCrossColor, $iCrossLineW)
    $hPen_Sat = _GDIPlus_PenCreate($iSatColor, $iSatLineW)

    ; Initiate some basic fuctions
    _ToggleHotKeys()
    _Int_TurretPoly()
    _Init_FontRects()
    _Init_Lines()
    _Init_CityStart()

    ; Start Drawing stuff on the Gui
    AdlibRegister("_Draw", 30)
EndFunc   ;==>_StartUp

Func _Init_Lines()
    Local $iAngle
    $aLines[0][0] = UBound($aLines, 1) - 1
    For $i = 1 To $aLines[0][0]
        $aLines[$i][1] = Random(0, $gW, 1) ; Start X
        $aLines[$i][2] = -$iLineW ; Start Y
        $aLines[$i][3] = $aLines[$i][1] ; Current End X
        $aLines[$i][4] = $aLines[$i][2] + $iLineW ; Current End Y
        $iAngle = _GetAngleDegree($aLines[$i][1], $aLines[$i][2], Random($iLineW, $gW - $iLineW, 1), $gH - $iTerrainH)
        $aLines[$i][5] = Cos($iAngle * $nPI_180) * $iLineSpeedStart; Step/Angle X
        $aLines[$i][6] = Sin($iAngle * $nPI_180) * $iLineSpeedStart; Step/Angle Y
        ;$aLines[$i][7] ; Sound the line will use, initiated by _Init_Sound() function.
        $aLines[$i][8] = 0 ; 0 Sound Paused, 1 Sound Playing
        $aLines[$i][9] = 2 ; 2 Waiting to be active, 1 Active, 0 No line
        $aLines[$i][10] = 0 ; 0 Lines is standard, 1 Line belongs to Sat
    Next
    ; Randomly setup Sat, 50/50 chance
    If Random(0, 1, 1) Then _Init_Sat()
EndFunc   ;==>_Init_Lines

Func _Check_Line()
    If Not $aLines[0][0] Then Return 0
    Local $iBool
    If $iSetSound And (TimerDiff($iLineStartTime) < $iLineStartDelay) Then Return 0
    For $i = 1 To UBound($aLines, 1) - 1
        Switch $aLines[$i][9]
            Case 2
                If $iLinesActive < $iLinesActiveStart And TimerDiff($iLineTime) >= $iLineDelay Then
                    If $aLines[$i][10] Then ;  Line bolongs to Sat
                        If $aSat[0][0] = 2 Then $aSat[0][0] = 1 ; Sat is set to fly if not already
                    Else ; Line is Standard
                        $aLines[$i][3] += $aLines[$i][5]
                        $aLines[$i][4] -= $aLines[$i][6]
                        $aLines[$i][9] = 1
                        $iLinesActive += 1
                        $iLineDelay = Random($iLineDelayMin, $iLineDelayMax)
                        $iLineTime = TimerInit()
                    EndIf
                EndIf
            Case 1
                $iBool = 0
                If _CheckTurretCollision($aLines[$i][3], $aLines[$i][4]) Or _CheckCityCollision($aLines[$i][3], $aLines[$i][4]) Or _WinAPI_PtInRectEx($aLines[$i][3], $aLines[$i][4], $tTerrain) Then
                    $iBool = 1
                EndIf
                Switch _CheckBoomCollision($aLines[$i][3], $aLines[$i][4])
                    Case 2
                        $iScoreTotal += $iScoreLine
                        $iBool = 2
                    Case 1
                        $iBool = 1
                EndSwitch
                If $iBool Then
                    $iLinesActive -= 1
                    $aLines[0][0] -= 1
                    If $iSetSound And $aLines[$i][8] Then _IrrKlangSetIsPaused($aLines[$i][7], $aLines[$i][8])
                    _Init_Boom($aLines[$i][3], $aLines[$i][4], $iBool)
                    For $n = 1 To UBound($aLines, 2) - 1
                        If $n <> 7 Then $aLines[$i][$n] = 0
                    Next
                Else
                    _WinAPI_DrawLine($hDC_Buffer, $aLines[$i][1], $aLines[$i][2], $aLines[$i][3], $aLines[$i][4])
                    $aLines[$i][3] += $aLines[$i][5]
                    $aLines[$i][4] -= $aLines[$i][6]
                    If $iSetSound And Not $aLines[$i][8] Then
                        _IrrKlangPlay2D($sLineStart)
                        _IrrKlangSetIsPaused($aLines[$i][7], $aLines[$i][8])
                        $aLines[$i][8] = 1
                    EndIf
                EndIf
        EndSwitch
    Next
EndFunc   ;==>_Check_Line

Func _Init_Sat()
    Local $iAngle, $iP, $j = 0
    $aSat[0][0] = 2 ; 0 No Sat, 1 Active,  2 Waiting to be active
    $aSat[0][1] = Round($iBaseW / 3) * 2 ; Size of Sat, this makes sure the size can be devided by 2 for an even center for collision check.
    Switch Random(1, 2, 1) ;Direction the Sat is moving, 1 from left, 2 from right
        Case 1
            $aSat[1][0] = -$aSat[0][1] ;X start left
            $aSat[3][0] = $gW ;X End Right
        Case 2
            $aSat[1][0] = $gW ;X start Right
            $aSat[3][0] = -$aSat[0][1] ;X End Left
    EndSwitch
    $aSat[1][1] = Random($iTerrainH, $gH / 2, 1) ; Y Start Position
    $aSat[2][0] = Random(0, $gW - $aSat[0][1], 1); X Drop Position
    $aSat[2][1] = Random($iTerrainH, $gH / 2, 1) ; Y Drop Position
    $aSat[3][1] = Random($iTerrainH, $gH / 2, 1) ; Y End Position
    $iAngle = _GetAngleDegree($aSat[1][0], $aSat[1][1], $aSat[2][0], $aSat[2][1])
    $aSat[4][0] = Cos($iAngle * $nPI_180) * $iLineSpeedStart; Start Step/Angle X
    $aSat[4][1] = Sin($iAngle * $nPI_180) * $iLineSpeedStart; Start Step/Angle Y
    $iAngle = _GetAngleDegree($aSat[2][0], $aSat[2][1], $aSat[3][0], $aSat[3][1])
    $aSat[5][0] = Cos($iAngle * $nPI_180) * $iLineSpeedStart; End Step/Angle X
    $aSat[5][1] = Sin($iAngle * $nPI_180) * $iLineSpeedStart; End Step/Angle Y
;~  $aSat[6][0] ; Sat sound assigned by _Init_Sound() function
    $aSat[6][1] = 0 ; Sound State, 0 Paused, 1 Playing
    $aSat[7][0] = 0 ; 0 Lines waiting to drop, 1 Lines have been dropped
    $iSatDrop = Random($iSatDropMin, $iSatDropMax, 1) ;How may lines the sat will drop
    $iP = Floor($gW / $iSatDrop) ; Part of the gui width, used for each sat line destination
    $aSat[7][1] = Random(1, $aLines[0][0] - ($iSatDrop - 1), 1) ; Index of $aLines Array to start drop of lines
    For $i = $aSat[7][1] To ($aSat[7][1] + ($iSatDrop - 1))
        $aLines[$i][1] = $aSat[2][0] + ($aSat[0][1] / 2) ;Random(0, $gW, 1) ; Start X
        $aLines[$i][2] = $aSat[2][1] + ($aSat[0][1] / 2) ;-$iLineW ; Start Y
        $aLines[$i][3] = $aLines[$i][1] ; Current End X
        $aLines[$i][4] = $aLines[$i][2] ;+ $iLineW ; Current End Y
        $iAngle = _GetAngleDegree($aLines[$i][1], $aLines[$i][2], Random(($iP * $j) + $iLineW, ($iP * ($j + 1)) - $iLineW, 1), $gH - $iTerrainH)
        $aLines[$i][5] = Cos($iAngle * $nPI_180) * $iLineSpeedStart; Step/Angle X
        $aLines[$i][6] = Sin($iAngle * $nPI_180) * $iLineSpeedStart; Step/Angle Y
        $aLines[$i][10] = 1 ; 0 standard line, 1 Sat line
        $j += 1
    Next
EndFunc   ;==>_Init_Sat

Func _Check_Sat()
    If Not $aSat[0][0] Then Return 0
    Local $iBool = 0, $iAngle
    If $aSat[0][0] = 1 Then
        If $iSetSound And Not $aSat[6][1] Then
            _IrrKlangSetIsPaused($aSat[6][0], $aSat[6][1])
            $aSat[6][1] = 1
        EndIf
        ; Draw Sat
        _GDIPlus_GraphicsDrawLine($hBuffer_Graphic, $aSat[1][0], $aSat[1][1], $aSat[1][0] + $aSat[0][1], $aSat[1][1] + $aSat[0][1], $hPen_Sat)
        _GDIPlus_GraphicsDrawLine($hBuffer_Graphic, $aSat[1][0] + $aSat[0][1], $aSat[1][1], $aSat[1][0], $aSat[1][1] + $aSat[0][1], $hPen_Sat)
        _GDIPlus_GraphicsDrawEllipse($hBuffer_Graphic, $aSat[1][0], $aSat[1][1], $aSat[0][1], $aSat[0][1], $hPen_Sat)
        ; Not exactly where the Sat is meant to drop, but close enough ;)
        If _Pixel_Distance($aSat[1][0], $aSat[1][1], $aSat[2][0], $aSat[2][1]) < $iLineSpeedStart And Not $aSat[7][0] Then
            ;; Drop lines
            $aSat[7][0] = 1 ; We check this later if the user kills the sat so we know the score to give.
            For $i = $aSat[7][1] To ($aSat[7][1] + ($iSatDrop - 1))
                $aLines[$i][9] = 1
                $iLinesActive += 1
            Next
            ; Set the step value to end stepping values
            $aSat[4][0] = $aSat[5][0]
            $aSat[4][1] = $aSat[5][1]
        EndIf
        ; Set the Sat step value to be drawn next loop
        $aSat[1][0] += $aSat[4][0]
        $aSat[1][1] -= $aSat[4][1]
        ; Check if the sat is on the screen, if not then get rid of the Sat
        If $aSat[1][0] < -$aSat[0][1] Or $aSat[1][0] > $gW Then $iBool = 1
        ; Check if the Sat has hit a user Boom, if so do the score and get rid of the sat.
        If _CheckSatCollision() Then $iBool = 2
        If $iBool Then
            $aSat[0][0] = 0
            If $iSetSound And $aSat[6][1] Then
                _IrrKlangSetIsPaused($aSat[6][0], $aSat[6][1])
                $aSat[6][1] = 0
            EndIf
            If $iBool = 2 Then ; User boom hit Sat
                If $aSat[7][0] Then
                    ; User killed sat after it dropped it's load
                    $iScoreTotal += $iScoreSatAfter
                Else
                    ; The user killed the sat before it dropped it's load
                    $iScoreTotal += $iScoreSatBefore
                    ; Revert the unused Sat lines back to Standard lines
                    For $i = $aSat[7][1] To ($aSat[7][1] + ($iSatDrop - 1))
                        $aLines[$i][1] = Random(0, $gW, 1) ; Start X
                        $aLines[$i][2] = -$iLineW ; Start Y
                        $aLines[$i][3] = $aLines[$i][1] ; Current End X
                        $aLines[$i][4] = $aLines[$i][2] + $iLineW ; Current End Y
                        $iAngle = _GetAngleDegree($aLines[$i][1], $aLines[$i][2], Random($iLineW, $gW - $iLineW, 1), $gH - $iTerrainH)
                        $aLines[$i][5] = Cos($iAngle * $nPI_180) * $iLineSpeedStart; Step/Angle X
                        $aLines[$i][6] = Sin($iAngle * $nPI_180) * $iLineSpeedStart; Step/Angle Y
                        $aLines[$i][9] = 2 ; 2 Waiting, 1 Active, 0 No Line
                        $aLines[$i][10] = 0 ; 0 Standard line, 1 Sat Line
                    Next
                EndIf
                _Init_Boom($aSat[1][0] + ($aSat[0][1] / 2), $aSat[1][1] + ($aSat[0][1] / 2), 2)
            EndIf
            $aSat[7][1] = 0
        EndIf
    EndIf
EndFunc   ;==>_Check_Sat

Func _CheckSatCollision()
    If Not $aBoom[0][0] Then Return 0
    Local $iSatC, $iBoomC
    For $i = 1 To UBound($aBoom, 1) - 1
        If Not $aBoom[$i][3] Or $aBoom[$i][6] = 1 Then ContinueLoop
        $iSatC = $aSat[0][1] / 2
        $iBoomC = $aBoom[$i][2] / 2
        If _Pixel_Distance($aSat[1][0] + $iSatC, $aSat[1][1] + $iSatC, $aBoom[$i][0] + $iBoomC, $aBoom[$i][1] + $iBoomC) - ($iSatC + $iBoomC) < 1 Then Return 1
    Next
    Return 0
EndFunc   ;==>_CheckSatCollision

Func _Init_Sound()
    If $iSetSound Then
        If _IrrKlangStart() Then
            $hAttract = _IrrKlangPlay2D($sAttract, True, True, True) ; Attract sound
            $aSat[6][0] = _IrrKlangPlay2D($sSat, True, True, True) ; Sat sound
            For $i = 1 To UBound($aLines, 1) - 1
                $aLines[$i][7] = _IrrKlangPlay2D($sLineTravel, True, True, True) ; Line Travel sound
                _IrrKlangSetVolume($aLines[$i][7], $fLineVolume)
            Next
        Else
            $iSetSound = False
        EndIf
    EndIf
EndFunc   ;==>_Init_Sound

Func _Init_FontRects()
    Local $aTmp
    ;Turret Ammo tRect
    For $i = 0 To 2
        $aTmp = $aTurret[$i + 1][1]
        $atFontAmmo[$i] = _tRect($aTmp[1][0], $aTurret[$i + 1][4] + ($iTerrainH - $iFontSizeAmmo), $iBaseW, $iFontSizeAmmo) ; Turret Ammo
    Next
    ; Scores, level and bonus cities tRect
    $atFontScore[0] = _tRect(5, 2, $gW / 2, $iTerrainH) ; Score
    $atFontScore[1] = _tRect(($gW / 2) - 5, 2, $gW / 2, $iTerrainH) ; High score
    $atFontScore[2] = _tRect(5, $gH - $iTerrainH, $gW / 2, $iTerrainH) ; Level
    $atFontScore[3] = _tRect(($gW / 2) - 5, $gH - $iTerrainH, $gW / 2, $iTerrainH) ; Bonus Cities
    ; Bonus Underlined Header and bonus score tRects
    $atFontBonus[0] = _tRect(0, ($gH / 3), $gW, $iFontSizeHeader)
    $atFontBonus[1] = _tRect(0, ($gH / 3) + ($iFontSizeHeader * 1.1), $gW, $gH - (($gH / 3) + $iFontSizeHeader))
    ; Game Over,  Attract, enter to play and New High Score tRects
    $atFontOver[0] = _tRect(0, ($gH - $iFontSizeOver) / 2, $gW, $iFontSizeOver)
    $atFontOver[1] = _tRect(0, ($gH - ($iFontSizeOver * 2)) / 2, $gW, $iFontSizeOver)
    $atFontOver[2] = _tRect(0, ($gH + ($iFontSizeOver * 2)) / 2, $gW, $iFontSizeScore)
EndFunc   ;==>_Init_FontRects


Func _Draw()
    _WinAPI_FillRect($hDC_Buffer, DllStructGetPtr($tSky), $hBrush_Sky)
    _Check_EndLevel()
    If Not $iLevelEnd Then
        _Check_Line()
        _Check_Sat()
        _Check_Shot()
    EndIf
    _Check_City()
    If Not $iLevelEnd Then _Check_Boom()
    _WinAPI_FillRect($hDC_Buffer, DllStructGetPtr($tTerrain), $hBrush_Terrain)
    _Check_Turret()
    _Check_BonusCityGet()
    _Check_String()
    _Check_Mouse()
    _WinAPI_BitBlt($hDC, 0, 0, $gW, $gH, $hDC_Buffer, 0, 0, $SRCCOPY)
EndFunc   ;==>_Draw

Func _Check_String()
    _WinAPI_SetTextColor($hDC_Buffer, $iTurretFontColor)
    _WinAPI_SelectObject($hDC_Buffer, $hFont_Ammo)
    For $i = 0 To 2
        If $aTurret[$i + 1][0] Then _WinAPI_DrawText($hDC_Buffer, StringFormat("%02i", $aTurret[$i + 1][5]), $atFontAmmo[$i], $DT_CENTER)
    Next
    _WinAPI_SetTextColor($hDC_Buffer, $iTextFontColor)
    _WinAPI_SelectObject($hDC_Buffer, $hFont_Score)
    _WinAPI_DrawText($hDC_Buffer, "Score: " & StringFormat("%07i", $iScoreTotal), $atFontScore[0], $DT_LEFT)
    _WinAPI_DrawText($hDC_Buffer, "High Score: " & StringFormat("%07i", $iScoreHigh), $atFontScore[1], $DT_Right)
    _WinAPI_DrawText($hDC_Buffer, "Level: " & StringFormat("%02i", $iLevel), $atFontScore[2], $DT_LEFT)
    _WinAPI_DrawText($hDC_Buffer, "Bonus Cities: " & StringFormat("%02i", $iBonusCity), $atFontScore[3], $DT_Right)
    _ToggleCursor()
    Switch $iLevelEnd
        Case 5 ;;; Pause
            _WinAPI_SelectObject($hDC_Buffer, $hFont_Over)
            _WinAPI_DrawText($hDC_Buffer, "PAUSED", $atFontOver[1], $DT_CENTER)
            If $iBlink Then
                If TimerDiff($iLevelEndTimer) <= $iBlinkDelayTime Then
                    _WinAPI_SelectObject($hDC_Buffer, $hFont_Score)
                    _WinAPI_DrawText($hDC_Buffer, "Press " & StringRegExpReplace($aKeys[3], "[{}]", "") & " To Resume", $atFontOver[2], $DT_CENTER)
                Else
                    $iLevelEndTimer = TimerInit()
                    $iBlink = 0
                EndIf
            Else
                If TimerDiff($iLevelEndTimer) > $iBlinkDelayTime Then
                    $iLevelEndTimer = TimerInit()
                    $iBlink = 1
                EndIf
            EndIf
        Case 4 ;;; Attract
            If $iSetSound And Not $iAttractSound Then
                _IrrKlangSetIsPaused($hAttract, $iAttractSound)
                $iAttractSound = 1
            EndIf
            _WinAPI_SelectObject($hDC_Buffer, $hFont_Over)
            _WinAPI_DrawText($hDC_Buffer, $sTitle, $atFontOver[1], $DT_CENTER)
            If $iBlink Then
                If TimerDiff($iLevelEndTimer) <= $iBlinkDelayTime Then
                    _WinAPI_SelectObject($hDC_Buffer, $hFont_Score)
                    _WinAPI_DrawText($hDC_Buffer, "Press " & StringRegExpReplace($aKeys[3], "[{}]", "") & " To Play", $atFontOver[2], $DT_CENTER)
                Else
                    $iLevelEndTimer = TimerInit()
                    $iBlink = 0
                EndIf
            Else
                If TimerDiff($iLevelEndTimer) > $iBlinkDelayTime Then
                    $iLevelEndTimer = TimerInit()
                    $iBlink = 1
                EndIf
            EndIf
        Case 3 ;;; New High Score
            If TimerDiff($iLevelEndTimer) <= $iHighSoreDelay Then
                If $iSetSound And Not $iHighScoreSound Then
                    $iHighScoreSound = 1
                    _IrrKlangPlay2D($sHighScore)
                EndIf
                _WinAPI_SelectObject($hDC_Buffer, $hFont_Header)
                _WinAPI_DrawText($hDC_Buffer, "CONGRADULATIONS", $atFontBonus[0], $DT_CENTER)
                _WinAPI_SelectObject($hDC_Buffer, $hFont_Score)
                _WinAPI_DrawText($hDC_Buffer, "New High Score: " & $iScoreHigh, $atFontBonus[1], $DT_CENTER)
            Else
                $iLevelEndTimer = TimerInit()
                $iLevelEnd = 4
                $iHighScoreSound = 0
            EndIf
        Case 2 ;;; Game Over
            If TimerDiff($iLevelEndTimer) <= $iGameOverDelay Then
                If $iSetSound And Not $iEndSound Then
                    _IrrKlangPlay2D($sEndGame)
                    $iEndSound = 1
                EndIf
                _WinAPI_SelectObject($hDC_Buffer, $hFont_Over)
                _WinAPI_DrawText($hDC_Buffer, "GAME OVER", $atFontOver[0], $DT_CENTER)
            Else
                If $iScoreTotal > $iScoreHigh Then
                    $iScoreHigh = $iScoreTotal
                    $iLevelEnd = 3
                Else
                    $iLevelEnd = 4
                EndIf
                $iEndSound = 0
                _Init_NewStart()
                $iLevelEndTimer = TimerInit()
            EndIf
        Case 1 ;;; End Level Bonus
            If $sTotal = "" Then
                For $i = 0 To 2
                    If Not $aTurret[$i + 1][5] Then ContinueLoop
                    $iSurplusAmmo += $aTurret[$i + 1][5]
                    $iScoreBonusAmmo += ($iScoreShot * $aTurret[$i + 1][5])
                Next
                If $iScoreBonusAmmo Then $sTotal &= "Surplus Ammo " & $iSurplusAmmo & " x " & $iScoreShot & " Points = " & $iScoreBonusAmmo & @LF

                $iSurplusCity = $aCity[0][0]
                $iScoreBonusCity = ($iScoreCity * $aCity[0][0])
                If $iScoreBonusCity Then $sTotal &= "Saved Cities " & $iSurplusCity & " x " & $iScoreCity & " Points = " & $iScoreBonusCity & @LF

                $iSurplusCityExtra = $iBonusCity
                $iScoreBonusCityExtra = ($iBonusCity * $iScoreCityExtra)
                If $iScoreBonusCityExtra Then $sTotal &= "Bonus Cities " & $iSurplusCityExtra & " x " & $iScoreCityExtra & " Points = " & $iScoreBonusCityExtra & @LF

                $iSurplusTotal = $iScoreBonusAmmo + $iScoreBonusCity + $iScoreBonusCityExtra
                If $iSurplusTotal Then $sTotal &= "Total Bonus: " & $iSurplusTotal
            EndIf
            If TimerDiff($iLevelEndTimer) <= $iLevelEndDelay And $sTotal <> "" Then
                If $iSetSound And Not $iEndLevelSound Then
                    _IrrKlangPlay2D($sEndLevel)
                    $iEndLevelSound = 1
                EndIf
                _WinAPI_SelectObject($hDC_Buffer, $hFont_Header)
                _WinAPI_DrawText($hDC_Buffer, "Level " & $iLevel & " Bonus", $atFontBonus[0], $DT_CENTER)
                _WinAPI_SelectObject($hDC_Buffer, $hFont_Score)
                _WinAPI_DrawText($hDC_Buffer, $sTotal, $atFontBonus[1], $DT_CENTER)
            Else
                $iScoreTotal += $iSurplusTotal
                _Check_BonusCityGet()
                $iScoreBonusAmmo = 0
                $iScoreBonusCity = 0
                $iScoreBonusCityExtra = 0
                $iSurplusAmmo = 0
                $iSurplusCity = 0
                $iSurplusCityExtra = 0
                $iSurplusTotal = 0
                $iLevelEndTimer = 0
                $sTotal = ""
                $iEndLevelSound = 0
                If Not $aCity[0][0] And Not $iBonusCity Then
                    $iLevelEnd = 2
                    $iLevelEndTimer = TimerInit()
                Else
                    $iLevelEnd = 0
                    _Int_NextLevel()
                EndIf
            EndIf
    EndSwitch
EndFunc   ;==>_Check_String

Func _Init_NewStart()
    WinSetTitle($hGui, "", $sTitle)
    $iScoreTotal = 0
    $iLevel = 1
    $iBonusCity = 0
    $iLineSpeedStart = $iDefaultLineSpeedStart
    $iLinesActiveStart = $iDefaultLinesActiveStart
    $iLineDelayMin = $iDefaultLineDelayMin
    $iLineDelayMax = $iDefaultLineDelayMax
    $iBonusCityOffset = 1
    _Init_Lines()
    _Int_TurretPoly(1)
    _Init_CityStart(1)
EndFunc   ;==>_Init_NewStart

Func _Int_NextLevel()
    $iLevel += 1
    If $iLineSpeedStart >= $iDefaultLineSpeedMax Then
        $iLineSpeedStart = $iDefaultLineSpeedStart
    ElseIf $iLineSpeedStart < $iDefaultLineSpeedMax Then
        $iLineSpeedStart += $iLevelLineStep
    EndIf
    If Not Mod($iLevel, $iLevelMod) And $iLinesActiveStart < $iDefaultLinesActiveMax Then
        $iLinesActiveStart += 1
        $iLineDelayMin -= Floor($iLineDelayMinStep)
        $iLineDelayMax -= Floor($iLineDelayMaxStep)
    ElseIf $iLinesActiveStart = $iDefaultLinesActiveMax Then
        $iLinesActiveStart = $iDefaultLinesActiveStart
        $iLineDelayMin = $iDefaultLineDelayMin
        $iLineDelayMax = $iDefaultLineDelayMax
    EndIf
    _Int_TurretPoly(1)
    _Init_Lines()
    _Init_CityStart(2)
    If $iSetSound Then _IrrKlangPlay2D($sStart)
    $iLineStartTime = TimerInit()
EndFunc   ;==>_Int_NextLevel

Func _Check_EndLevel()
    If Not $aLines[0][0] And Not $aBoom[0][0] And Not $iLinesActive And Not $iLevelEnd And Not $aLeft[0][0] And Not $aMiddle[0][0] And Not $aRight[0][0] And Not $aSat[0][0] Then
        $iLevelEnd = 1
        $iLevelEndTimer = TimerInit()
    EndIf
EndFunc   ;==>_Check_EndLevel

Func _Check_Mouse()
    Local $aMGP = MouseGetPos()
    $aMouse[0] = $aMGP[0]
    $aMouse[1] = $aMGP[1]
    If $aMGP[0] > $gW Then $aMouse[0] = $gW
    If $aMGP[0] < 0 Then $aMouse[0] = 0
    If $aMGP[1] > ($gH - ($iTurretH + $iCrossLineW)) Then $aMouse[1] = ($gH - ($iTurretH + $iCrossLineW))
    If $aMGP[1] < 0 Then $aMouse[1] = 0
    If Not $iLevelEnd Then
        _GDIPlus_GraphicsDrawLine($hBuffer_Graphic, $aMouse[0] - $iCrossW / 2, $aMouse[1], $aMouse[0] + $iCrossW / 2, $aMouse[1], $hPen_Cross)
        _GDIPlus_GraphicsDrawLine($hBuffer_Graphic, $aMouse[0], $aMouse[1] - $iCrossH / 2, $aMouse[0], $aMouse[1] + $iCrossH / 2, $hPen_Cross)
    EndIf
EndFunc   ;==>_Check_Mouse

Func _Check_BonusCityGet()
    If $iBonusCityOffset - Floor($iScoreTotal / $iBonusCityAt) = 0 Then
        $iBonusCityOffset += 1
        $iBonusCity += 1
        If $iSetSound Then _IrrKlangPlay2D($sCity)
    EndIf
EndFunc   ;==>_Check_BonusCityGet

; $iFlag 1 will onlt set the state of the turret to active with max ammo, 0 to init turret on script start once only.
Func _Int_TurretPoly($iFlag = 0)
    $aTurret[0][0] = 3 ; Count of turrets that exist
    If $iFlag Then
        For $i = 1 To UBound($aTurret, 1) - 1
            $aTurret[$i][0] = 1 ; Turret exists
            $aTurret[$i][5] = $iShotAmmo ; Ammo the turret has
        Next
        Return $iFlag
    EndIf
    Local $aTmp[6][2] = [[4, 0],[0, $gH - $iTerrainH],[0, $gH - $iTurretH],[0, $gH - $iTurretH],[0, $gH - $iTerrainH],[0, $gH - $iTerrainH]]
    Local $aTmp1[3][5] = [[0, ($iBaseW - $iTurretTopW) / 2, ($iBaseW + $iTurretTopW) / 2, $iBaseW, 0], _
            [($gW - $iBaseW) / 2, ($gW - $iTurretTopW) / 2, ($gW + $iTurretTopW) / 2, ($gW + $iBaseW) / 2, ($gW - $iBaseW) / 2], _
            [$gW - $iBaseW, $gW - (($iBaseW + $iTurretTopW) / 2), $gW - (($iBaseW - $iTurretTopW) / 2), $gW, $gW - $iBaseW]]
    For $i = 1 To UBound($aTurret, 1) - 1
        For $j = 1 To UBound($aTmp, 1) - 1
            $aTmp[$j][0] = $aTmp1[$i - 1][$j - 1]
        Next
        $aTurret[$i][0] = 1 ; Turret exists
        $aTurret[$i][1] = $aTmp ; aPoints array used for collission check
        $aTurret[$i][2] = _PolyStruct($aTmp) ;tPoint struct for drawing the turret polygon
        $aTurret[$i][3] = $aTmp[2][0] ; Shot X start
        $aTurret[$i][4] = $aTmp[2][1] ; Shot Y start
        $aTurret[$i][5] = $iShotAmmo ; Ammo the turret has
    Next
EndFunc   ;==>_Int_TurretPoly

Func _Check_Turret()
    If Not $aTurret[0][0] Then Return 0
    Local $aTmp
    For $i = 1 To UBound($aTurret, 1) - 1
        If Not $aTurret[$i][0] Then ContinueLoop
        $aTmp = $aTurret[$i][2]
        _GDIPlus_StructFillPolygon($hBuffer_Graphic, $aTmp[0], $aTmp[1], $hBrush_Turret)
    Next
EndFunc   ;==>_Check_Turret

Func _CheckTurretCollision($iX, $iY)
    If Not $aTurret[0][0] Then Return 0
    Local $aTmp
    For $i = 1 To UBound($aTurret, 1) - 1
        If Not $aTurret[$i][0] Then ContinueLoop
        $aTmp = $aTurret[$i][1]
        If _PointInPoly($iX, $iY, $aTmp) Then
            $aTurret[0][0] -= 1
            $aTurret[$i][0] = 0
            $aTurret[$i][5] = 0
            Return 1
        EndIf
    Next
    Return 0
EndFunc   ;==>_CheckTurretCollision

; Flag 0 only when script starts
; Flag 1 For a New Start after Game Over
; Flag 2 For replacing destroyed city with bonus city when initiating Next Level
Func _Init_CityStart($iFlag = 0)
    If $iFlag = 2 Then ; Then check for bonus city, called at end of level
        If Not $iBonusCity Then Return 0
        For $i = 1 To UBound($aCity, 1) - 1
            If Not $aCity[$i][2] And $iBonusCity Then
                If $iSetSound Then _IrrKlangPlay2D($sCityAdd)
                $aCity[0][0] += 1
                $aCity[$i][2] = 1
                $iBonusCity -= 1
            EndIf
        Next
    Else ; script start and we initilize all cites
        Local $iStep = 2
        $aCity[0][0] = UBound($aCity, 1) - 1
        For $i = 1 To $aCity[0][0]
            If Not $iFlag Then
                If $i = 4 Then $iStep = 10
                $aCity[$i][0] = _PolyStruct(_Init_City($iBaseW * $iStep, $gH - $iTurretH, $iBaseW, $iTerrainH)) ; Polygon Points array
                $aCity[$i][1] = _tRect($iBaseW * $iStep, ($gH - $iTurretH) + 2, $iBaseW, $iTurretH) ; tRect for collission check
                $iStep += 2
            EndIf
            $aCity[$i][2] = 1 ; 1 Exists, 0 Not Exist
        Next
    EndIf
EndFunc   ;==>_Init_CityStart

Func _Check_City()
    If Not $aCity[0][0] Then Return 0
    Local $aTmp
    For $i = 1 To UBound($aCity, 1) - 1
        If Not $aCity[$i][2] Then ContinueLoop
        $aTmp = $aCity[$i][0]
        _GDIPlus_StructFillPolygon($hBuffer_Graphic, $aTmp[0], $aTmp[1], $hBrush_City)
    Next
EndFunc   ;==>_Check_City

Func _CheckCityCollision($iX, $iY)
    If Not $aCity[0][0] Then Return 0
    For $i = 1 To UBound($aCity, 1) - 1
        If Not $aCity[$i][2] Then ContinueLoop
        If _WinAPI_PtInRectEx($iX, $iY, $aCity[$i][1]) Then
            $aCity[$i][2] = 0
            $aCity[0][0] -= 1
            Return 1
        EndIf
    Next
EndFunc   ;==>_CheckCityCollision

Func _CheckBoomCollision($iX, $iY)
    If Not $aBoom[0][0] Then Return 0
    For $i = 1 To UBound($aBoom, 1) - 1
        If Not $aBoom[$i][3] Then ContinueLoop
        If _PointInEllipse($iX, $iY, $aBoom[$i][0], $aBoom[$i][1], $aBoom[$i][2], $aBoom[$i][2]) Then Return $aBoom[$i][6]
    Next
    Return 0
EndFunc   ;==>_CheckBoomCollision

Func _Init_Shot($iTurret, $iMX, $iMY)
    If $iMY >= $aTurret[$iTurret][4] Or $aTurret[$iTurret][5] <= 0 Then
        If $iSetSound Then _IrrKlangPlay2D($sNoAmmo)
        Return 0
    EndIf
    Local $iDX, $iAngle, $aTmp[4][6]
    If $iSetSound Then _IrrKlangPlay2D($sShot)
    Switch $iTurret
        Case 1
            $aTmp = $aLeft
        Case 2
            $aTmp = $aMiddle
        Case 3
            $aTmp = $aRight
    EndSwitch
    If $aTmp[0][0] < UBound($aTmp, 1) - 1 Then
        $aTurret[$iTurret][5] -= 1
        If $aTurret[$iTurret][5] <= 0 Then _CheckTurretCollision($aTurret[$iTurret][3], $aTurret[$iTurret][4] + 3)
        $aTmp[0][0] += 1
        For $i = 1 To UBound($aTmp, 1) - 1
            If $aTmp[$i][0] = 0 Then $iDX = $i
        Next
        ;get angle from bullet start to destination
        $iAngle = _GetAngleDegree($aTurret[$iTurret][3], $aTurret[$iTurret][4], $iMX, $iMY)
        $aTmp[$iDX][0] = Cos($iAngle * $nPI_180) * $iShotSpeed ;X bullet Step/speed
        $aTmp[$iDX][1] = Sin($iAngle * $nPI_180) * $iShotSpeed ;Y bullet Step/speed
        ;save the start X and Y point of our bullet
        $aTmp[$iDX][2] = $aTurret[$iTurret][3] ;X Bullet start
        $aTmp[$iDX][3] = $aTurret[$iTurret][4] ;Y Bullet start
        $aTmp[$iDX][4] = $iMX ;X Bullet Destination
        $aTmp[$iDX][5] = $iMY ;Y Bullet Destination
        Switch $iTurret
            Case 1
                $aLeft = $aTmp
            Case 2
                $aMiddle = $aTmp
            Case 3
                $aRight = $aTmp
        EndSwitch
    EndIf
EndFunc   ;==>_Init_Shot

Func _Check_Shot()
    Local $aTmp[3] = [$aLeft, $aMiddle, $aRight], $aTmp1
    For $n = 0 To UBound($aTmp) - 1
        $aTmp1 = $aTmp[$n]
        If $aTmp1[0][0] Then
            For $i = 1 To UBound($aTmp1, 1) - 1
                If Not $aTmp1[$i][0] Then ContinueLoop
                _GDIPlus_GraphicsFillEllipse($hBuffer_Graphic, $aTmp1[$i][2], $aTmp1[$i][3], $iShotSize, $iShotSize, $hBrush_Shot)
                ;Step the start X and Y along our angle
                $aTmp1[$i][2] += $aTmp1[$i][0]
                $aTmp1[$i][3] -= $aTmp1[$i][1]

                ;Crude check to see if the bullet has hit the destination, if so then no need to draw it any further, initiate Boom
                If ($aTmp1[$i][3] <= $aTmp1[$i][5]) Then
                    $aTmp1[0][0] -= 1
                    $aTmp1[$i][0] = 0
                    _Init_Boom($aTmp1[$i][4], $aTmp1[$i][5], 2)
                EndIf
            Next
            Switch $n
                Case 0
                    $aLeft = $aTmp1
                Case 1
                    $aMiddle = $aTmp1
                Case 2
                    $aRight = $aTmp1
            EndSwitch
        EndIf
    Next
EndFunc   ;==>_Check_Shot

Func _Init_Boom($iX, $iY, $iOwner)
    For $i = 1 To UBound($aBoom, 1) - 1
        If Not $aBoom[$i][3] Then
            If $iSetSound Then _IrrKlangPlay2D($sBoom)
            $aBoom[0][0] += 1 ; Number of active booms
            $aBoom[$i][0] = $iX - ($iBoomStep / 2) ; X Boom Start
            $aBoom[$i][1] = $iY - ($iBoomStep / 2) ; Y Boom Start
            $aBoom[$i][2] = $iBoomStep ; Width and Height of Boom
            $aBoom[$i][3] = 2 ; State of boom 2 expanding, 1 contracting, 0 no boom
            $aBoom[$i][4] = 0 ; Brush color array index from 0 to 3
            $aBoom[$i][5] = TimerInit() ; used for boom stepping speed.
            $aBoom[$i][6] = $iOwner ; Ownership of the boom for scoring, 1 Line Boom, 2 User Boom
            ; Any line that hits a user boom then that lines boom becomes the users boom.
            ; If a Line hits a turret, city or ground then the boom belongs to the line.
            ; This way a User doesn't get score for a line that wasn't hit by a users boom.
            Return 1
        EndIf
    Next
    Return 0
EndFunc   ;==>_Init_Boom

Func _Check_Boom()
    If Not $aBoom[0][0] Then Return 0
    For $i = 1 To UBound($aBoom, 1) - 1
        If Not $aBoom[$i][3] Then ContinueLoop
        If $aBoom[$i][4] = UBound($aBoomColor) Then $aBoom[$i][4] = 0
        _GDIPlus_BrushSetSolidColor($hBrush_Boom, $aBoomColor[$aBoom[$i][4]])
        _GDIPlus_GraphicsFillEllipse($hBuffer_Graphic, $aBoom[$i][0], $aBoom[$i][1], $aBoom[$i][2], $aBoom[$i][2], $hBrush_Boom)
        If TimerDiff($aBoom[$i][5]) >= $iBoomTD Then
            Switch $aBoom[$i][3]
                Case 2
                    $aBoom[$i][0] -= $iBoomStep / 2
                    $aBoom[$i][1] -= $iBoomStep / 2
                    $aBoom[$i][2] += $iBoomStep
                    If $aBoom[$i][2] >= $iBoomMaxSize Then $aBoom[$i][3] = 1
                    $aBoom[$i][4] += 1
                Case 1
                    $aBoom[$i][0] += $iBoomStep / 2
                    $aBoom[$i][1] += $iBoomStep / 2
                    $aBoom[$i][2] -= $iBoomStep
                    $aBoom[$i][4] += 1
                    If $aBoom[$i][2] <= 0 Then
                        $aBoom[0][0] -= 1
                        For $n = 0 To UBound($aBoom, 2) - 1
                            $aBoom[$i][$n] = 0
                        Next
                    EndIf
            EndSwitch
            $aBoom[$i][5] = TimerInit()
        EndIf
    Next
EndFunc   ;==>_Check_Boom

Func _HotKeyEvent()
    Switch @HotKeyPressed
        Case $aKeys[0] ;Left Fire
            If Not $iLevelEnd Then
                If TimerDiff($iLeftTimer) >= $iShotDelay Then
                    _Init_Shot(1, $aMouse[0], $aMouse[1])
                    $iLeftTimer = TimerInit()
                EndIf
            EndIf
        Case $aKeys[1] ;Middle Fire
            If Not $iLevelEnd Then
                If TimerDiff($iMiddleTimer) >= $iShotDelay Then
                    _Init_Shot(2, $aMouse[0], $aMouse[1])
                    $iMiddleTimer = TimerInit()
                EndIf
            EndIf
        Case $aKeys[2] ;Right Fire
            If Not $iLevelEnd Then
                If TimerDiff($iRightTimer) >= $iShotDelay Then
                    _Init_Shot(3, $aMouse[0], $aMouse[1])
                    $iRightTimer = TimerInit()
                EndIf
            EndIf
        Case $aKeys[3] ;Toggle Start/Pause
            _StartPause()
    EndSwitch
EndFunc   ;==>_HotKeyEvent

Func _StartPause()
    Switch $iLevelEnd
        Case 0, 1, 2, 3 ; Game is playing or in a message screen
            $iPauseLast = $iLevelEnd
            $iLevelEnd = 5
            If $iSetSound Then
                _PauseLoopSounds(True)
                _IrrKlangPlay2D($sPause)
            EndIf
            WinSetTitle($hGui, "", $sTitle)
        Case 4 ; Game is at Attract Screen
            $iLevelEnd = $iPauseLast
            $iPauseLast = 0
            If $iSetSound Then
                _IrrKlangSetIsPaused($hAttract, $iAttractSound)
                $iAttractSound = 0
                _IrrKlangPlay2D($sStart)
                $iLineStartTime = TimerInit()
            EndIf
            WinSetTitle($hGui, "", $sTitle & " - Press " & StringRegExpReplace($aKeys[3], "[{}]", "") & " to Pause")
        Case 5 ; Game is Paused
            $iLevelEnd = $iPauseLast
            $iPauseLast = 0
            If $iSetSound Then
                _IrrKlangPlay2D($sPause)
                _PauseLoopSounds(False)
            EndIf
            WinSetTitle($hGui, "", $sTitle & " - Press " & StringRegExpReplace($aKeys[3], "[{}]", "") & " to Pause")
    EndSwitch
EndFunc   ;==>_StartPause

Func _PauseLoopSounds($iBool)
    For $i = 1 To UBound($aLines, 1) - 1
        If $aLines[$i][9] = 1 Then _IrrKlangSetIsPaused($aLines[$i][7], $iBool)
    Next
    If $aSat[0][0] Then _IrrKlangSetIsPaused($aSat[6][0], $iBool)
EndFunc   ;==>_PauseLoopSounds

Func _ToggleCursor()
    Switch $iLevelEnd
        Case 0, 1, 2, 3 ; Game is playing or in a message screen
            If $iCursor Then
                GUISetCursor(16, 1, $hGui)
                $iCursor = 0
            EndIf
        Case 4, 5 ; Game is Paused or at Attract Screen
            If Not $iCursor Then
                GUISetCursor(2, 1, $hGui)
                $iCursor = 1
            EndIf
    EndSwitch
EndFunc   ;==>_ToggleCursor

Func _GuiEvent()
    Switch @GUI_CtrlId
        Case $GUI_EVENT_CLOSE
            _Exit()
        Case $GUI_EVENT_MINIMIZE
            If $iLevelEnd <> 4 And $iLevelEnd <> 5 Then _StartPause()
            _ToggleHotKeys(1)
            GUISetState(@SW_MINIMIZE, $hGui)
        Case $GUI_EVENT_RESTORE
            _ToggleHotKeys()
            GUISetState(@SW_RESTORE, $hGui)
    EndSwitch
EndFunc   ;==>_GuiEvent

Func _ToggleHotKeys($iState = 0)
    If $iState Then
        For $i = 0 To UBound($aKeys) - 1
            HotKeySet($aKeys[$i])
        Next
        $iHotKeyState = 0
    Else
        For $i = 0 To UBound($aKeys) - 1
            HotKeySet($aKeys[$i], "_HotKeyEvent")
        Next
        $iHotKeyState = 1
    EndIf
EndFunc   ;==>_ToggleHotKeys

Func _WM_LBUTTONDOWN()
    If Not $iLevelEnd Then _Init_Shot(1, $aMouse[0], $aMouse[1])
EndFunc   ;==>_WM_LBUTTONDOWN

Func _WM_MBUTTONDOWN()
    If Not $iLevelEnd Then _Init_Shot(2, $aMouse[0], $aMouse[1])
EndFunc   ;==>_WM_MBUTTONDOWN

Func _WM_RBUTTONDOWN()
    If Not $iLevelEnd Then _Init_Shot(3, $aMouse[0], $aMouse[1])
EndFunc   ;==>_WM_RBUTTONDOWN

Func _Init_City($iX, $iY, $iW, $iH)
    Local $w11 = $iW / 11, $h9 = $iH / 9
    Local $aTmp[27][2]
    $aTmp[0][0] = 25

    $aTmp[1][0] = $iX + 0
    $aTmp[1][1] = $iY + ($h9 * 3)

    $aTmp[2][0] = $iX + $w11
    $aTmp[2][1] = $iY + $h9

    $aTmp[3][0] = $iX + $w11
    $aTmp[3][1] = $iY + ($h9 * 4)

    $aTmp[4][0] = $iX + ($w11 * 2)
    $aTmp[4][1] = $iY + ($h9 * 4)

    $aTmp[5][0] = $iX + ($w11 * 2)
    $aTmp[5][1] = $iY + $h9

    $aTmp[6][0] = $iX + ($w11 * 3)
    $aTmp[6][1] = $iY + $h9

    $aTmp[7][0] = $iX + ($w11 * 3)
    $aTmp[7][1] = $iY + ($h9 * 5)

    $aTmp[8][0] = $iX + ($w11 * 4)
    $aTmp[8][1] = $iY + ($h9 * 5)

    $aTmp[9][0] = $iX + ($w11 * 4)
    $aTmp[9][1] = $iY + ($h9 * 2)

    $aTmp[10][0] = $iX + ($w11 * 4) + ($w11 / 2)
    $aTmp[10][1] = $iY + 0

    $aTmp[11][0] = $iX + ($w11 * 5)
    $aTmp[11][1] = $iY + ($h9 * 2)

    $aTmp[12][0] = $iX + ($w11 * 5)
    $aTmp[12][1] = $iY + ($h9 * 6)

    $aTmp[13][0] = $iX + ($w11 * 6)
    $aTmp[13][1] = $iY + ($h9 * 6)

    $aTmp[14][0] = $iX + ($w11 * 6)
    $aTmp[14][1] = $iY + ($h9 * 2)

    $aTmp[15][0] = $iX + ($w11 * 7)
    $aTmp[15][1] = $iY + ($h9 * 3)

    $aTmp[16][0] = $iX + ($w11 * 7)
    $aTmp[16][1] = $iY + ($h9 * 5)

    $aTmp[17][0] = $iX + ($w11 * 8)
    $aTmp[17][1] = $iY + ($h9 * 5)

    $aTmp[18][0] = $iX + ($w11 * 8)
    $aTmp[18][1] = $iY + ($h9 * 2)

    $aTmp[19][0] = $iX + ($w11 * 9)
    $aTmp[19][1] = $iY + ($h9 * 2)

    $aTmp[20][0] = $iX + ($w11 * 9)
    $aTmp[20][1] = $iY + ($h9 * 4)

    $aTmp[21][0] = $iX + ($w11 * 10)
    $aTmp[21][1] = $iY + ($h9 * 4)

    $aTmp[22][0] = $iX + ($w11 * 10)
    $aTmp[22][1] = $iY + ($h9 * 2)

    $aTmp[23][0] = $iX + $iW
    $aTmp[23][1] = $iY + 0

    $aTmp[24][0] = $iX + $iW
    $aTmp[24][1] = $iY + $iH

    $aTmp[25][0] = $iX + 0
    $aTmp[25][1] = $iY + $iH

    $aTmp[26][0] = $iX + 0
    $aTmp[26][1] = $iY + ($h9 * 2)

    Return $aTmp
EndFunc   ;==>_Init_City

; Since my polygons are drawn every loop I don't want _GDIPlus_FillPolygon looping through the points and creating a struct.
; eg; each city polygon contains 25 points, so 6 cities x 25 point = 150 loops each main loop...
; You can imagine what happens once you add other things to be drawn and checked each main loop, cpu use gets high and everything bogs down.
; So basicaly I do the stuct points before the game starts, this way _GDIPlus_FillPolygon doesn't chew my cpu time when drawing cities and turrets.
Func _PolyStruct($aPoints)
    Local $atPoints[2]
    $atPoints[1] = $aPoints[0][0]
    $atPoints[0] = DllStructCreate("long[" & $atPoints[1] * 2 & "]")
    For $i = 1 To $aPoints[0][0]
        DllStructSetData($atPoints[0], 1, $aPoints[$i][0], (($i - 1) * 2) + 1)
        DllStructSetData($atPoints[0], 1, $aPoints[$i][1], (($i - 1) * 2) + 2)
    Next
    Return $atPoints
EndFunc   ;==>_PolyStruct

Func _GDIPlus_StructFillPolygon($hGraphics, $tPoints, $iCount, $hBrush)
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipFillPolygonI", "handle", $hGraphics, "handle", $hBrush, _
            "ptr", DllStructGetPtr($tPoints), "int", $iCount, "int", "FillModeAlternate")
    Local $tmpError = @error, $tmpExtended = @extended
    If $tmpError Then Return SetError($tmpError, $tmpExtended, False)
    Return $aResult[0] = 0
EndFunc   ;==>_GDIPlus_StructFillPolygon

; Thanks to Malkey
Func _WinAPI_PtInRectEx($iX, $iY, $tRect)
    Local $aResult
    $aResult = DllCall("User32.dll", "int", "PtInRect", "ptr", DllStructGetPtr($tRect), "int", $iX, "int", $iY)
    If @error Then Return SetError(@error, 0, False)
    Return $aResult[0] <> 0
EndFunc   ;==>_WinAPI_PtInRectEx

; Thanks to Malkey
Func _PointInEllipse($xPt, $yPt, $xTL, $yTL, $w, $h)
    Local $bInside = False, $a = $w / 2, $b = $h / 2
    Local $c1X, $c2X, $dist, $xc = $xTL + $a, $yc = $yTL + $b
    $c1X = $xc - ($a ^ 2 - $b ^ 2) ^ (1 / 2); 1st focal point x position
    $c2X = $xc + ($a ^ 2 - $b ^ 2) ^ (1 / 2); 2nd focal point x position
    $dist = (($xPt - $c1X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5 + (($xPt - $c2X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5
    If $dist <= $w Then $bInside = Not $bInside
    Return $bInside
EndFunc   ;==>_PointInEllipse

; Thanks to Malkey
Func _PointInPoly($x, $y, $aPoints)
    Local $bEvenNum = False, $xOnLInE, $yMin, $yMax
    For $i = 1 To $aPoints[0][0]
        $yMin = _Iif($aPoints[$i + 1][1] < $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $yMax = _Iif($aPoints[$i + 1][1] > $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $xOnLInE = -($y * $aPoints[$i + 1][0] - $y * $aPoints[$i][0] - $aPoints[$i][1] * $aPoints[$i + 1][0] + _
                $aPoints[$i][0] * $aPoints[$i + 1][1]) / (-$aPoints[$i + 1][1] + $aPoints[$i][1])
        If ($x < $xOnLInE) And ($y > $yMin) And ($y <= $yMax) Then $bEvenNum = Not $bEvenNum
    Next
    Return $bEvenNum
EndFunc   ;==>_PointInPoly

Func _GetAngleDegree($X1, $Y1, $X2, $Y2)
    Local Const $nPI = 4 * ATan(1)
    Local $XDIFF, $YDIFF, $TempAngle
    $YDIFF = Abs($Y2 - $Y1)
    If $X1 = $X2 And $Y1 = $Y2 Then Return 0
    If $YDIFF = 0 And $X1 < $X2 Then
        Return 0
    ElseIf $YDIFF = 0 And $X1 > $X2 Then
        Return $nPI
    EndIf
    $XDIFF = Abs($X2 - $X1)
    $TempAngle = ATan($XDIFF / $YDIFF)
    If $Y2 > $Y1 Then $TempAngle = $nPI - $TempAngle
    If $X2 < $X1 Then $TempAngle = -$TempAngle
    $TempAngle = ($nPI / 2) - $TempAngle
    If $TempAngle < 0 Then $TempAngle = ($nPI * 2) + $TempAngle
    Return $TempAngle * 180 / $nPI
EndFunc   ;==>_GetAngleDegree

; Thanks to UEZ
Func _Pixel_Distance($X1, $Y1, $X2, $Y2) ;Pythagoras theorem
    Local $a, $b, $c
    If $X2 = $X1 And $Y2 = $Y1 Then
        Return 0
    Else
        $a = $Y2 - $Y1
        $b = $X2 - $X1
        $c = Sqrt($a * $a + $b * $b)
        Return $c
    EndIf
EndFunc   ;==>_Pixel_Distance

Func _tRect($iX, $iY, $iW, $iH)
    Local $tRect = DllStructCreate($tagRECT)
    DllStructSetData($tRect, "Left", $iX)
    DllStructSetData($tRect, "Top", $iY)
    DllStructSetData($tRect, "Right", $iX + $iW)
    DllStructSetData($tRect, "Bottom", $iY + $iH)
    Return $tRect
EndFunc   ;==>_tRect

Func _Exit()
    GUIRegisterMsg($WM_LBUTTONDOWN, "")
    GUIRegisterMsg($WM_LBUTTONDBLCLK, "")
    GUIRegisterMsg($WM_MBUTTONDOWN, "")
    GUIRegisterMsg($WM_MBUTTONDBLCLK, "")
    GUIRegisterMsg($WM_RBUTTONDOWN, "")
    GUIRegisterMsg($WM_RBUTTONDBLCLK, "")

    AdlibUnRegister("_Draw")

    ; Dispose of GDI resources
    _WinAPI_SelectObject($hDC_Buffer, $hOld_Pen)
    _WinAPI_DeleteObject($hPen_Line)
    _WinAPI_SelectObject($hDC_Buffer, $hOld_Font)
    _WinAPI_DeleteObject($hFont_Ammo)
    _WinAPI_DeleteObject($hFont_Score)
    _WinAPI_DeleteObject($hFont_Header)
    _WinAPI_DeleteObject($hFont_Over)
    _WinAPI_DeleteObject($hBrush_Terrain)
    _WinAPI_DeleteObject($hBrush_Sky)
    _WinAPI_SelectObject($hDC_Buffer, $hOldBMP)
    _WinAPI_DeleteObject($hBMP)
    _WinAPI_DeleteDC($hDC_Buffer)
    _WinAPI_DeleteDC($hDC)

    ; Dispose of GDIPlus resources
    _GDIPlus_PenDispose($hPen_Sat)
    _GDIPlus_PenDispose($hPen_Cross)
    _GDIPlus_BrushDispose($hBrush_Turret)
    _GDIPlus_BrushDispose($hBrush_City)
    _GDIPlus_BrushDispose($hBrush_Boom)
    _GDIPlus_BrushDispose($hBrush_Shot)
    _GDIPlus_GraphicsDispose($hBuffer_Graphic)
    _GDIPlus_Shutdown()

    ; Only doing this to make the script appear responsive when closing.
    ; _IrrKlangStop() holds up the closing of the script briefly which gives the gui a sluggish feel when closing.
    GUIDelete($hGui)

    ; Save High Score
    IniWrite($Ini, "SETTINGS", "HS", $iScoreHigh)

    ; Clear any open sounds and Shutdown irrKlang engine if sound is enabled.
    If $iSetSound Then
        _IrrKlangRemoveAllSoundSources()
        _IrrKlangStop()
    EndIf

    Exit
EndFunc   ;==>_Exit

;;;; Some IrrKlang Sound functions, Thanks to Frank Dod for his wrapper and Linus who started translating these for au3irrlicht2.
Func _IrrKlangStart()
    ; only one irrklang device object is supported by this wrapper. this call creates the device object that is exposed to au3
    $_irrKlangDll = DllOpen("IrrKlangWrapper.dll")
    If $_irrKlangDll = -1 Then ; .dll cannot be opened - try to get it by extending %path%:
        EnvSet("PATH", $sSound & ";" & @ScriptDir & "\bin;" & @ScriptDir & "\..\bin;" & EnvGet("PATH"))
        EnvUpdate()
        $_irrKlangDll = DllOpen("IrrKlangWrapper.dll")
        If $_irrKlangDll = -1 Then Return SetError(5, 0, False) ; no chance, so return error:
    EndIf

    Local $aReturn = DllCall($_irrKlangDll, "UINT:cdecl", "IrrKlangStart")
    If @error Then Return SetError(@error, 0, False)
    Return SetError(0, 0, $aReturn[0] = 1)
EndFunc   ;==>_IrrKlangStart

Func _IrrKlangStop()
    ; Stop the sound engine
    DllCall($_irrKlangDll, "none:cdecl", "IrrKlangStop")
    If @error Then Return SetError(@error, 0, False)
;~     DllClose($_irrKlangDll) ;Sometimes errors in XP on exit if started up and then closed quickly a few times.
    Return SetError(@error, 0, True)
EndFunc   ;==>_IrrKlangStop

Func _IrrKlangPlay2D($sFile, $bLooped = False, $bStartPaused = False, $bTrack = False, $iStreamMode = $ESM_AUTO_DETECT, $bSoundEffects = False)
    ; Play a 2D sound
    Local $aReturn = DllCall($_irrKlangDll, "UINT_PTR:cdecl", "IrrKlangPlay2D", "str", $sFile, "UINT", $bLooped, _
            "UINT", $bStartPaused, "UINT", $bTrack, "INT", $iStreamMode, "UINT", $bSoundEffects)
    If @error Then Return SetError(1, 0, False)
    Return SetError(0, 0, $aReturn[0])
EndFunc   ;==>_IrrKlangPlay2D

Func _IrrKlangSetIsPaused($hSound, $iPaused)
    ; Pause a sound
    DllCall($_irrKlangDll, "none:cdecl", "IrrKlangSetIsPaused", "UINT_PTR", $hSound, "UINT", $iPaused)
    Return SetError(@error, 0, @error = 0)
EndFunc   ;==>_IrrKlangSetIsPaused

Func _IrrKlangRemoveAllSoundSources()
    ; Stop all sounds and remove all sound files from memory
    DllCall($_irrKlangDll, "none:cdecl", "IrrKlangRemoveAllSoundSources")
    Return SetError(@error, 0, @error = 0)
EndFunc   ;==>_IrrKlangRemoveAllSoundSources

Func _IrrKlangSetVolume($hSound, $fVolume)
    ; Set the volume of a sound
    DllCall($_irrKlangDll, "none:cdecl", "IrrKlangSetVolume", "UINT_PTR", $hSound, "float", $fVolume)
    Return SetError(@error, 0, @error = 0)
EndFunc   ;==>_IrrKlangSetVolume

Cheers

Edited by smashly

Share this post


Link to post
Share on other sites



AWESOME WORK! Can't wait to see when it is fine tuned. :)


whoa! I can write!

Share this post


Link to post
Share on other sites

I had also the idea to implement Missile Command but ...

Very nice implementation! :)

I'm sure when you add missing items it will be great!

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Hi, thanks for the positive feedback all. :unsure:

Updated first post.

Now has sound and a few other bits n pieces.

Enjoy

Cheers

Share this post


Link to post
Share on other sites

Why you have mixed up WinAPI drawing and GDI+? Performance?

Apropos performance, how about a fps counter?

Now it is much cooler with sound! :unsure:

Br,

UEZ


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Hi UEZ and thanks :unsure:

The mix of GDI and GDI+, yep exactly.

Performance and ease of use.

GDI Draws lines quicker then GDI+ (on older XP pc, eg; P4 3Ghz)

Same with rectangles, GDI is faster.

But GDI+ is easier to work with colors and shapes.

So I traded between both..lol

When I wrote the script I was on an older XP P4 3Ghz pc.

But when testing the script I used multiple newer PC's (i7 @ 4Ghz, Amd 64 X2 @ 3.4Ghz, E8400 @ 3.6Ghz), newer pc's the difference isn't really noticeable.

Cheers

Share this post


Link to post
Share on other sites

This is really nice & I don't even like games. I played with it a little; FileInstall of the sounds folder is a nice add to the script but I can't get the sounds folder to delete on exit. Probably a skill-level issue on my part.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0