Add new property Sprite.filepath

Add new property Sprite.filepath

Strict

Private

Import align
Import basedisplayobject
Import bono.kernel
Import bono.utils
Import mojo.graphics

Public

Class Sprite Extends BaseDisplayObject Implements AppObserver
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field imageName:String
    Field _scale:Vector2D = New Vector2D(1, 1)

    Public

    Field halign:Int = Align.LEFT
    Field valign:Int = Align.TOP
    Field frameSpeed:Int
    Field loopAnimation:Bool
    Field rotation:Float

    Method New(imageName:String, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)

        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed
    End

    Method OnLoading:Void()
    End

    Method OnResume:Void()
    End

    Method OnSuspend:Void()
    End

    Method OnCreate:Void()
        If frameSize
            image = LoadImage(imageName, frameSize.x, frameSize.y, frameCount)
            size = frameSize.Copy()
        Else
            image = LoadImage(imageName)
            size = New Vector2D(image.Width(), image.Height())
        End

        If Not image Then Error("Unable to load: " + imageName)
        size.Mul(scale)
    End

    Method OnRender:Void()
        Local renderPos:Vector2D = pos.Copy()
        Align.AdjustHorizontal(renderPos, Self, halign)
        Align.AdjustVertical(renderPos, Self, valign)

        If color Then color.Activate()
        DrawImage(image, renderPos.x, renderPos.y, rotation, scale.x, scale.y, currentFrame)
        If color Then color.Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method Collide:Bool(checkPos:Vector2D)
        If checkPos.x < pos.x Or checkPos.x > pos.x + size.x Then Return False
        If checkPos.y < pos.y Or checkPos.y > pos.y + size.y Then Return False
        Return True
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Method scale:Vector2D() Property
        Return _scale
    End

    Method scale:Void(newScale:Vector2D) Property
        If image Then size = size.Div(_scale).Mul(newScale)
        _scale = newScale
    End

    Method filepath:String() Property
        Return imageName
    End

    Private

    Method SetNameAndPos:Void(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName
        If Not pos Then pos = New Vector2D(0, 0)
        Self.pos = pos
    End
End

Strict

Private

Import align
Import basedisplayobject
Import bono.kernel
Import bono.utils
Import mojo.graphics

Public

Class Sprite Extends BaseDisplayObject Implements AppObserver
    Private

    Field currentFrame:Int
    Field frameCount:Int
    Field frameSize:Vector2D
    Field frameTimer:Int
    Field image:Image
    Field imageName:String
    Field _scale:Vector2D = New Vector2D(1, 1)

    Public

    Field halign:Int = Align.LEFT
    Field valign:Int = Align.TOP
    Field frameSpeed:Int
    Field loopAnimation:Bool
    Field rotation:Float

    Method New(imageName:String, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)
    End

    Method New(imageName:String, frameSize:Vector2D, frameCount:Int, frameSpeed:Int, pos:Vector2D=Null)
        SetNameAndPos(imageName, pos)

        Self.frameSize = frameSize
        Self.frameCount = frameCount
        Self.frameSpeed = frameSpeed
    End

    Method OnLoading:Void()
    End

    Method OnResume:Void()
    End

    Method OnSuspend:Void()
    End

    Method OnCreate:Void()
        If frameSize
            image = LoadImage(imageName, frameSize.x, frameSize.y, frameCount)
            size = frameSize.Copy()
        Else
            image = LoadImage(imageName)
            size = New Vector2D(image.Width(), image.Height())
        End

        If Not image Then Error("Unable to load: " + imageName)
        size.Mul(scale)
    End

    Method OnRender:Void()
        Local renderPos:Vector2D = pos.Copy()
        Align.AdjustHorizontal(renderPos, Self, halign)
        Align.AdjustVertical(renderPos, Self, valign)

        If color Then color.Activate()
        DrawImage(image, renderPos.x, renderPos.y, rotation, scale.x, scale.y, currentFrame)
        If color Then color.Deactivate()
    End

    Method OnUpdate:Void(deltaTimer:DeltaTimer)
        If frameCount <= 0 Then Return
        If animationIsDone Then Return

        If frameTimer < frameSpeed
            frameTimer += deltaTimer.frameTime
            Return
        End

        If (currentFrame + 1) = frameCount
            If loopAnimation
                currentFrame = 1
            End
        Else
            currentFrame += 1
        End
        frameTimer = 0
    End

    Method Restart:Void()
        currentFrame = 0
    End

    Method Collide:Bool(checkPos:Vector2D)
        If checkPos.x < pos.x Or checkPos.x > pos.x + size.x Then Return False
        If checkPos.y < pos.y Or checkPos.y > pos.y + size.y Then Return False
        Return True
    End

    Method animationIsDone:Bool() Property
        If loopAnimation Then Return False
        Return (currentFrame = frameCount)
    End

    Method scale:Vector2D() Property
        Return _scale
    End

    Method scale:Void(newScale:Vector2D) Property
        If image Then size = size.Div(_scale).Mul(newScale)
        _scale = newScale
    End

    Private

    Method SetNameAndPos:Void(imageName:String, pos:Vector2D=Null)
        Self.imageName = imageName
        If Not pos Then pos = New Vector2D(0, 0)
        Self.pos = pos
    End
End


added QuickSort to Sort Module

added QuickSort to Sort Module

#Rem monkeydoc Module maniac.maniacSort
	Sort Module - Version 0.1.0 (alpha)  ~n
	Copyright (C) 2015  Stephan Duckerschein~n

	This is a Sorting Module.
	At the Moment you can choose between: Shell-, Selection-, Bubble-, Quick-  & Insertion Sort algorithms.
	## ATENTION: it operates on the given Array. It doesn't create a new and returns!!!! ##
	## Your Array Int/Float will be changed after using a Sort-Function##

	## ISSUE: sorting StringArrays as well
	Version: 0.1.0
		ShellSort - Int,Float Arrays
		SelectionSort - Int,Float
		BubbleSort - int Float
		InsertionSort - int,Float
		QuickSort -int,float

Example:
<pre>

'This Example shows a little Benchmark-Sort with 10000 Array-Elements

Function Main:Int()
	New Example
	Return 0
End

Class Example Extends App
	Field arr:Float[]
	Field arr2:Float[]
	Field arr3:Float[]
	Field arr4:float[]
	Field arr5:Float[]

	Method OnCreate:Int()
		SetUpdateRate( 60 )
		initManiac(False)
		Local l:Int = 10000
		arr = New Float[l]
		arr2 = New Float[l]
		arr3 = New Float[l]
		arr4 = New Float[l]
		arr5 = New float[l]
		For Local i:Int = 0 Until l
			arr[i] = Rnd(-452232.2,445342.3)
			arr2[i] = arr[i]
			arr3[i] = arr[i]
			arr4[i] = arr[i]
			arr5[i] = arr[i]
		Next

		Print "Sorting"

		Local t:Int = Millisecs()
		ShellSort( arr )
		Print "shell time: " + (Millisecs()- t) + " ms"

		t = Millisecs()
		SelectionSort( arr2 )
		Print "selection time: " + (Millisecs()- t) + " ms"

		t = Millisecs()
		BubbleSort( arr3 )
		Print "Bubble time: " + (Millisecs()- t) + " ms"

		t = Millisecs()
		InsertionSort( arr4 )
		Print "Insertion time: " + (Millisecs()- t) + " ms"

		Local t2:int = Millisecs()
		QuickSort(arr5, 0, arr5.Length()-5, False )
		Print "Quick time: " + (Millisecs()- t2) + " ms"

		For Local i:Int = 0 Until l
			'Print "("+i+") " + arr5[i]
		Next

		Return 0
	End
</pre>

#End

Function ShellSort( arr:Float[]  )
	Local i:Int
	Local j:Int
	Local increment:Float
	Local temp:float

	increment = 3
	While increment > 0
			For i = 0 Until arr.Length()
				j = i
				temp = arr[ i ]
				While j >= increment And arr[j-increment] > temp
						arr[j] = arr[j-increment]
						j = j - increment
				Wend
				arr[j] = temp
			Next
			If increment/2 <> 0 Then
				increment = increment / 2
			ElseIf increment = 1
				increment = 0
			Else
				increment = 1
			EndIf
	Wend
End Function

Function ShellSort( arr:int[]  )
	Local i:Int
	Local j:Int
	Local increment:Float
	Local temp:float

	increment = 3
	While increment > 0
			For i = 0 Until arr.Length()
				j = i
				temp = arr[ i ]
				While j >= increment And arr[j-increment] > temp
						arr[j] = arr[j-increment]
						j = j - increment
				Wend
				arr[j] = temp
			Next
			If increment/2 <> 0 Then
				increment = increment / 2
			ElseIf increment = 1
				increment = 0
			Else
				increment = 1
			EndIf
	Wend
End Function

Function SelectionSort( arr:int[] )
	Local i:Int
	Local j:Int
	Local min:int
	Local temp:float
	For i = 0 until arr.Length()
		min = i
		For j = i+1 until arr.Length()
			If arr[j] < arr[min] Then min = j
		Next
		temp = arr[ i ]
		arr[ i ] = arr[min]
		arr[min] = temp
	Next
End Function

Function SelectionSort( arr:float[] )
	Local i:Int
	Local j:Int
	Local min:int
	Local temp:float
	For i = 0 until arr.Length()
		min = i
		For j = i+1 until arr.Length()
			If arr[j] < arr[min] Then min = j
		Next
		temp = arr[ i ]
		arr[ i ] = arr[min]
		arr[min] = temp
	Next
End Function

Function BubbleSort( arr:int[] )
	Local i:Int
	Local j:Int
	Local temp:float

	For i = arr.Length() To 0 Step -1
		For j = 1 To i
			If arr[ j - 1 ] > arr[ j ] Then
				temp = arr[ j - 1 ]
				arr[ j - 1 ] = arr[ j ]
				arr[ j ] = temp
			EndIf
		Next
	Next
End Function

Function BubbleSort( arr:float[] )
	Local i:Int
	Local j:Int
	Local temp:float

	For i = arr.Length() To 0 Step -1
		For j = 1 until i
			If arr[ j - 1 ] > arr[ j ] Then
				temp = arr[ j - 1 ]
				arr[ j - 1 ] = arr[ j ]
				arr[ j ] = temp
			EndIf
		Next
	Next
End Function

Function InsertionSort( arr:int[] )
	Local i:Int
	Local j:Int
	Local index:int

	For i = 1 until arr.Length() - 1
		index = arr[ i ]
		j = i
		While j > 0 And arr[ j-1 ] > index
			arr[ j ] = arr[ j - 1 ]
			j = j - 1
		Wend
		arr[ j ] = index
	Next
End Function

Function InsertionSort( arr:float[] )
	Local i:Int
	Local j:Int
	Local index:int

	For i = 1 until arr.Length() - 1
		index = arr[ i ]
		j = i
		While j > 0 And arr[ j-1 ] > index
			arr[ j ] = arr[ j - 1 ]
			j = j - 1
		Wend
		arr[ j ] = index
	Next
End Function

Function QuickSort(arr:Float[], L:Int, R:Int, RandomPivot:bool = True )
	Local A, B, SwapA#, SwapB#, Middle#
	A = L
	B = R

	If RandomPivot Then
		Middle = arr[ Rnd(L, R) ]
	Else
		Middle = arr[ (L+R)/2 ]
	EndIf

	While True

		While arr[ A ] < Middle
			A = A + 1
			If A > R Then Exit
		Wend

		While  Middle < arr[ B ]
			B = B - 1
			If B < 0 Then Exit
		Wend

		If A > B Then Exit

		SwapA = arr[ A ]
		SwapB = arr[ A ]
		arr[ A ] = arr[ B ]
		arr[ A ] = arr[ B ]
		arr[ B ] = SwapA
		arr[ B ] = SwapB

		A = A + 1
		B = B - 1

		If B < 0 Then Exit

	Wend

	If L < B Then QuickSort(arr, L, B )
	If A < R Then QuickSort(arr, A, R )
End Function

Function QuickSort(arr:int[], L:Int, R:Int, RandomPivot:bool = True )
	Local A, B, SwapA#, SwapB#, Middle#
	A = L
	B = R

	If RandomPivot Then
		Middle = arr[ Rnd(L, R) ]
	Else
		Middle = arr[ (L+R)/2 ]
	EndIf

	While True

		While arr[ A ] < Middle
			A = A + 1
			If A > R Then Exit
		Wend

		While  Middle < arr[ B ]
			B = B - 1
			If B < 0 Then Exit
		Wend

		If A > B Then Exit

		SwapA = arr[ A ]
		SwapB = arr[ A ]
		arr[ A ] = arr[ B ]
		arr[ A ] = arr[ B ]
		arr[ B ] = SwapA
		arr[ B ] = SwapB

		A = A + 1
		B = B - 1

		If B < 0 Then Exit

	Wend

	If L < B Then QuickSort(arr, L, B )
	If A < R Then QuickSort(arr, A, R )
End Function

#Rem monkeydoc Module maniac.maniacSort
	Sort Module - Version 0.1.0 (alpha)  ~n
	Copyright (C) 2015  Stephan Duckerschein~n

	This is a Sorting Module.
	At the Moment you can choose between: Shell-, Selection-, Bubble- & Insertion Sort algorithms.
	## ATENTION: it operates on the given Array. It doesn't create a new and returns!!!! ##
	## Your Array Int/Float will be changed after using a Sort-Function##

	## ISSUE: sorting StringArrays as well
	Version: 0.1.0
		ShellSort - Int,Float Arrays
		SelectionSort - Int,Float
		BubbleSort - int Float
		InsertionSort - int,Float

#End

Function ShellSort( arr:Float[]  )
	Local i:Int
	Local j:Int
	Local increment:Float
	Local temp:float

	increment = 3
	While increment > 0
			For i = 0 Until arr.Length()
				j = i
				temp = arr[ i ]
				While j >= increment And arr[j-increment] > temp
						arr[j] = arr[j-increment]
						j = j - increment
				Wend
				arr[j] = temp
			Next
			If increment/2 <> 0 Then
				increment = increment / 2
			ElseIf increment = 1
				increment = 0
			Else
				increment = 1
			EndIf
	Wend
End Function

Function ShellSort( arr:int[]  )
	Local i:Int
	Local j:Int
	Local increment:Float
	Local temp:float

	increment = 3
	While increment > 0
			For i = 0 Until arr.Length()
				j = i
				temp = arr[ i ]
				While j >= increment And arr[j-increment] > temp
						arr[j] = arr[j-increment]
						j = j - increment
				Wend
				arr[j] = temp
			Next
			If increment/2 <> 0 Then
				increment = increment / 2
			ElseIf increment = 1
				increment = 0
			Else
				increment = 1
			EndIf
	Wend
End Function

Function SelectionSort( arr:int[] )
	Local i:Int
	Local j:Int
	Local min:int
	Local temp:float
	For i = 0 until arr.Length()
		min = i
		For j = i+1 until arr.Length()
			If arr[j] < arr[min] Then min = j
		Next
		temp = arr[ i ]
		arr[ i ] = arr[min]
		arr[min] = temp
	Next
End Function

Function SelectionSort( arr:float[] )
	Local i:Int
	Local j:Int
	Local min:int
	Local temp:float
	For i = 0 until arr.Length()
		min = i
		For j = i+1 until arr.Length()
			If arr[j] < arr[min] Then min = j
		Next
		temp = arr[ i ]
		arr[ i ] = arr[min]
		arr[min] = temp
	Next
End Function

Function BubbleSort( arr:int[] )
	Local i:Int
	Local j:Int
	Local temp:float

	For i = arr.Length() To 0 Step -1
		For j = 1 To i
			If arr[ j - 1 ] > arr[ j ] Then
				temp = arr[ j - 1 ]
				arr[ j - 1 ] = arr[ j ]
				arr[ j ] = temp
			EndIf
		Next
	Next
End Function

Function BubbleSort( arr:float[] )
	Local i:Int
	Local j:Int
	Local temp:float

	For i = arr.Length() To 0 Step -1
		For j = 1 To i
			If arr[ j - 1 ] > arr[ j ] Then
				temp = arr[ j - 1 ]
				arr[ j - 1 ] = arr[ j ]
				arr[ j ] = temp
			EndIf
		Next
	Next
End Function

Function InsertionSort( arr:int[] )
	Local i:Int
	Local j:Int
	Local index:int

	For i = 1 until arr.Length() - 1
		index = arr[ i ]
		j = i
		While j > 0 And arr[ j-1 ] > index
			arr[ j ] = arr[ j - 1 ]
			j = j - 1
		Wend
		arr[ j ] = index
	Next
End Function

Function InsertionSort( arr:float[] )
	Local i:Int
	Local j:Int
	Local index:int

	For i = 1 until arr.Length() - 1
		index = arr[ i ]
		j = i
		While j > 0 And arr[ j-1 ] > index
			arr[ j ] = arr[ j - 1 ]
			j = j - 1
		Wend
		arr[ j ] = index
	Next
End Function

#rem
Function QuickSort( L, R, RandomPivot = True )
	Local A, B, SwapA#, SwapB#, Middle#
	A = L
	B = R

	If RandomPivot Then
		Middle = SortArray( Rand(L, R) )
	Else
		Middle = SortArray( (L+R)/2 )
	EndIf

	While True

		While SortArray( A ) < Middle
			A = A + 1
			If A > R Then Exit
		Wend

		While  Middle < SortArray( B )
			B = B - 1
			If B < 0 Then Exit
		Wend

		If A > B Then Exit

		SwapA = SortArray( A )
		SwapB = SortArray( A )
		SortArray( A ) = SortArray( B )
		SortArray( A ) = SortArray( B )
		SortArray( B ) = SwapA
		SortArray( B ) = SwapB

		A = A + 1
		B = B - 1

		If B < 0 Then Exit

	Wend

	If L < B Then QuickSort( L, B )
	If A < R Then QuickSort( A, R )
End Function

#end


Added FlxU.Format function

Added FlxU.Format function

Strict

Import mojo
Import reflection

Import flxextern
Import flxpoint
Import flxg
Import system.flximagedata

Alias MonkeyAbs = monkey.math.Abs
Alias MonkeyFloor = monkey.math.Floor
Alias MonkeyCeil = monkey.math.Ceil
Alias MonkeyMin = monkey.math.Min
Alias MonkeyMax = monkey.math.Max
Alias MonkeyGetClass = reflection.GetClass

#If TARGET <> "psm" And TARGET <> "xna"
	Alias FlxOpenURL = mojo.app.OpenUrl
#End

Class FlxU

Private
	Global _objClass:ClassInfo

Public

	Function OpenURL:Void(url:String)
		FlxOpenURL(url)
	End Function

	Function Abs:Float(value:Float)
		Return MonkeyAbs(value)
	End Function

	Function Floor:Float(value:Float)
		Return MonkeyFloor(value)
	End Function

	Function Ceil:Float(value:Float)
		Return MonkeyCeil(value)
	End Function

	Function Round:Float(value:Float)
		If (value > 0) Then
			Return Int(value + .5)
		Else
			Return Int(value - .5)
		End If
	End Function

	Function Min:Float(number1:Float, number2:Float)
		Return MonkeyMin(number1, number2)
	End Function

	Function Max:Float(number1:Float, number2:Float)
		Return MonkeyMax(number1, number2)
	End Function

	Function Bound:Float(value:Float, min:Float, max:Float)
		Return Clamp(value, min, max)
	End Function

	Function Srand:Float(seed:Float)
		Return Float(seed Shr 8 & $ffffff)/$1000000
	End Function

	#Rem
	Function Shuffle:Object[](objects:Object[], howManyTimes:Int)
		Shuffle is not currently supported in Monkey. Use FlxArray.Shuffle method
	End Function
	#End

	#Rem
	Function GetRandom:FlxBasic(objects:FlxBasic[], startIndex:Int = 0, length:Int = 0)
		GetRandom is not currently supported in Monkey. Use FlxArray.GetRandom method
	End Function
	#End

	Function GetTicks:Int()
		Return Millisecs()
	End Function

	Function FormatTicks:String(startTicks:Int, endTicks:Int)
		Return ((endTicks - startTicks) / 1000) + "s"
	End Function

	Function MakeColor:Int(red:Int, green:Int, blue:Int, alpha:Float = 1)
		If (alpha <= 1) alpha *= 255
		Return (alpha & $FF) Shl 24 | (red & $FF) Shl 16 | (green & $FF) Shl 8 | (blue & $FF)
	End Function

	Function MakeColorFromHSB:Int(hue:Float, saturation:Float, brightness:Float, alpha:Float = 1)
		Local red:Float
		Local green:Float
		Local blue:Float

		If (saturation = 0)
			red = brightness
			green = brightness
			blue = brightness
		Else
			If (hue = 360) hue = 0

			Local slice:Int = hue / 60
			Local hf:Float = hue / 60 - slice
			Local aa:Float = brightness * (1 - saturation)
			Local bb:Float = brightness * (1 - saturation * hf)
			Local cc:Float = brightness * (1 - saturation * (1.0 - hf))

			Select (slice)
				Case 0
					red = brightness
					green = cc
					blue = aa

				Case 1
					red = bb
					green = brightness
					blue = aa

				Case 2
					red = aa
					green = brightness
					blue = cc

				Case 3
					red = aa
					green = bb
					blue = brightness

				Case 4
					red = cc
					green = aa
					blue = brightness

				Case 5
					red = brightness
					green = aa
					blue = bb

				Default
					red = 0
					green = 0
					blue = 0
			End Select
		End If

		If (alpha <= 1) alpha *= 255
		Return (alpha & $FF) Shl 24 | int(red * 255) Shl 16 | int(green * 255) Shl 8 | int(blue * 255)
	End Function

	Function GetRGBA:Float[](color:Int, resluts:Float[] = [])
		If (resluts.Length() <> 4) resluts = resluts.Resize(4)

		resluts[0] = (color Shr 16) & $FF
		resluts[1] = (color Shr 8) & $FF
		resluts[2] = color & $FF
		resluts[3] = Float((color Shr 24) & $FF) / 255
		Return resluts
	End Function

	Function GetHSB:Float[](color:Int, resluts:Float[] = [])
		If (resluts.Length() <> 4) resluts = resluts.Resize(4)

		Local red:Float = Float((color Shr 16) & $FF) / 255
		Local green:Float = Float((color Shr 8) & $FF) / 255
		Local blue:Float = Float(color & $FF) / 255

		Local m:Float = MonkeyMax(red, green)
		Local dmax:Float = MonkeyMax(m, blue)
		m = MonkeyMin(red, green)
		Local dmin:Float = MonkeyMin(m, blue)
		Local range:Float = dmax - dmin

		resluts[2] = dmax
		resluts[1] = 0
		resluts[0] = 0

		If (dmax <> 0) resluts[1] = range / dmax

		If (resluts[1] <> 0) Then
			If (red = dmax) Then
				resluts[0] = (green - blue) / range

			ElseIf (green = dmax) Then
				resluts[0] = 2 + (blue - red) / range

			ElseIf (blue = dmax) Then
				resluts[0] = 4 + (red - green) / range
			End If

			resluts[0] *= 60
			If (resluts[0] < 0) resluts[0] += 360
		End If

		resluts[3] = Float((color Shr 24) & $FF) / 255

		Return resluts
	End Function

	Function FormatTime:String(seconds:Float, showMS:Bool = False)
		Local timeString:StringStack = New StringStack()
		timeString.Push(Int(seconds / 60) + ":")

		Local timeStringHepler:Int = Int(seconds) Mod 60

		If (timeStringHepler < 10) Then
			timeString.Push("0")
		End If

		timeString.Push(timeStringHepler)

		If (showMS) Then
			timeString.Push(".")
			timeStringHepler = (seconds - Int(seconds)) * 100

			If (timeStringHepler < 10) Then
				timeString.Push("0")
			End If

			timeString.Push(timeStringHepler)
		End If

		Return timeString.Join("")
	End Function

	Function FormatMoney:String(amount:Float, showDecimal:Bool = True, englishStyle:Bool = True)
		Local helper:Int
		Local sgn:Int = Sgn(amount)
		Local showSgn:Bool = False
		amount = Abs(amount)
		Local intAmount:Int = amount
		Local comma:String = ""
		Local result:String = ""
		Local zeroes:String = ""

		If (intAmount = 0) result = "0"

		While (intAmount > 0)
			If (result.Length() > 0 And comma.Length() <= 0) Then
				If (englishStyle) Then
					comma = ","
				Else
					comma = "."
				End If
			End If

			helper = intAmount - Int(intAmount / 1000) * 1000
			intAmount /= 1000

			zeroes = ""

			If (intAmount > 0) Then
				If (helper < 100) Then
					zeroes = "0"
				End If

				If (helper < 10) Then
					zeroes = "00"
				End If
			End If

			result = zeroes + helper + comma + result
			showSgn = True
		Wend

		If (showDecimal) Then
			intAmount = Round(amount * 100) - (Int(amount) * 100)
			If (intAmount <> 0) showSgn = True

			If (englishStyle) Then
				result += "."
			Else
				result += ","
			End If

			If (intAmount < 10) Then
				result += "0"
			End If

			result += intAmount
		End If

		If (sgn < 0 And showSgn) Then
			Return "-" + result
		End If

		Return result
	End Function

	Function Format:String(text:String, placeHolder:String, value:String)
		Local index:Int = text.Find(placeHolder)
		Local offset:Int = index
		Local char:Int
		Local length:Int = text.Length()

		While (index >= 0)
			char = text[index]
			offset += 1

			While (offset < length And text[offset] = char)
				offset += 1
			Wend

			If (value.Length() < offset - index) Then
				Local l:Int = value.Length()

				While (l < offset - index)
					value = "0" + value
					l += 1
				Wend

			ElseIf(value.Length() > offset - index) Then
				value = value[ (value.Length() - (offset - index)) ..]
			End If

			text = text.Replace(text[index .. offset], value)
			index = text.Find(placeHolder)
			offset = index
		Wend

		Return text
	End Function

	Function GetClassName:String(obj:Object, simple:Bool = False)
		If (simple) Then
			Local name:String = MonkeyGetClass(obj).Name
			Return name[name.FindLast(".")+1..]
		End If

		Return MonkeyGetClass(obj).Name
	End Function

	Function CompareClassNames:Bool(object1:Object, object2:Object)
		Return (MonkeyGetClass(object1).Name = MonkeyGetClass(object2).Name)
	End Function

	Function GetClass:ClassInfo(name:String)
		Return MonkeyGetClass(name)
	End Function

	Function GetObjectClass:ClassInfo()
		If (_objClass <> Null)
			Return _objClass
		End If

		_objClass = MonkeyGetClass("monkey.lang.Object")

		Return _objClass
	End Function

	Function ComputeVelocity:Float(velocity:Float, acceleration:Float = 0, drag:Float = 0, max:Float = 10000)
		If (acceleration <> 0) Then
			velocity += acceleration * FlxG.Elapsed

		ElseIf (drag <> 0) Then
			drag *= FlxG.Elapsed

			If (velocity - drag > 0) Then
				velocity -= drag
			ElseIf (velocity + drag < 0) Then
				velocity += drag
			Else
				velocity = 0
			End If
		End If

		If (velocity <> 0 And max <> 10000) Then
			If (velocity > max) Then
				velocity = max
			ElseIf (velocity < -max) Then
				velocity = -max
			End If
		End If

		Return velocity
	End Function

	Function RotatePoint:FlxPoint(x:Float, y:Float, pivotX:Float, pivotY:Float, angle:Float, point:FlxPoint = Null)
		Local sin:Float = 0
		Local cos:Float = 0
		Local radians:Float = angle * -0.017453293

		While (radians < -PI)
			radians += TWOPI
		Wend

		While (radians > PI)
			radians = radians - TWOPI
		Wend

		If (radians < 0) Then
			sin =  1.27323954 * radians + .405284735 * radians * radians
			If (sin < 0) Then
				sin = .225 * (sin * -sin - sin) + sin
			Else
				sin = .225 * (sin * sin - sin) + sin
			End If
		Else
			sin = 1.27323954 * radians - 0.405284735 * radians * radians
			If (sin < 0) Then
				sin = .225 * (sin * -sin - sin) + sin
			Else
				sin = .225 * (sin * sin - sin) + sin
			End If
		End If

		radians += HALFPI
		If (radians > PI) radians -= TWOPI

		If (radians < 0) Then
			cos = 1.27323954 * radians + 0.405284735 * radians * radians
			If (cos < 0) Then
				cos = .225 * (cos * -cos - cos) + cos
			Else
				cos = .225 * (cos * cos - cos) + cos
			End If
		Else
			cos = 1.27323954 * radians - 0.405284735 * radians * radians
			If (cos < 0) Then
				cos = .225 * (cos * -cos - cos) + cos
			Else
				cos = .225 * (cos * cos - cos) + cos
			End If
		End If

		Local dx:Float = x - pivotX
		Local dy:Float = pivotY + y

		If (point = Null) point = New FlxPoint()
		point.x = pivotX + cos * dx - sin * dy
		point.y = pivotY - sin * dx - cos * dy

		Return point
	End Function

	Function GetAngle:Float(point1:FlxPoint, point2:FlxPoint)
		Local x:Float = point2.x - point1.x
		Local y:Float = point2.y - point1.y

		If (x = 0 And y = 0) Return 0

		Local c1:Float = PI * .25
		Local c2:Float = 3 * c1
		Local ay:Float = MonkeyAbs(y)
		Local angle:Float = 0

		If (x >= 0) Then
			angle = c1 - c1 * ((x - ay) / (x + ay))
		Else
			angle = c2 - c1 * ((x + ay) / (ay - x))
		End If

		If (y < 0) Then
			angle =	-angle * 57.2957796
		Else
			angle =	angle * 57.2957796
		End If

		If (angle > 90) Then
			angle = angle - 270
		Else
			angle += 90
		End If

		Return angle
	End Function

	Function GetDistance:Float(point1:FlxPoint, point2:FlxPoint)
		Local dx:Float = point1.x - point2.x
		Local dy:Float = point1.y - point2.y

		Return Sqrt(dx * dx + dy * dy)
	End Function

	Function GetDistance:Float(x1:Float, y1:Float, x2:Float, y2:Float)
		Local dx:Float = x1 - x2
		Local dy:Float = y1 - y2

		Return Sqrt(dx * dx + dy * dy)
	End Function

	Function SetImageMask:Image(image:Image, maskColor:Int)
		Local bitmapData:FlxImageData = FlxImageData.FromImage(image, True)
		bitmapData.ColorReplace(maskColor, 0)

		Local result:Image = bitmapData.Image
		bitmapData.Destroy()

		Return result
	End Function

	Function SetImagePadding:Image(image:Image, paddings:Int = Image.XYPadding)
		Local paddingX:Int, paddingY:Int

		If (paddings & Image.XPadding) paddingX = 1
		If (paddings & Image.YPadding) paddingY = 1

		Return FlxU.SetImagePadding(image, paddingX, paddingY)
	End Function

	Function SetImagePadding:Image(image:Image, paddingX:Int, paddingY:Int)
		Local bitmapData:FlxImageData = FlxImageData.FromImage(image, False, paddingX, paddingY)
		Local result:Image = bitmapData.Image
		bitmapData.Destroy()

		Return result
	End Function

End Class

Strict

Import mojo
Import reflection

Import flxextern
Import flxpoint
Import flxg
Import system.flximagedata

Alias MonkeyAbs = monkey.math.Abs
Alias MonkeyFloor = monkey.math.Floor
Alias MonkeyCeil = monkey.math.Ceil
Alias MonkeyMin = monkey.math.Min
Alias MonkeyMax = monkey.math.Max
Alias MonkeyGetClass = reflection.GetClass

#If TARGET <> "psm" And TARGET <> "xna"
	Alias FlxOpenURL = mojo.app.OpenUrl
#End

Class FlxU

Private
	Global _objClass:ClassInfo

Public

	Function OpenURL:Void(url:String)
		FlxOpenURL(url)
	End Function

	Function Abs:Float(value:Float)
		Return MonkeyAbs(value)
	End Function

	Function Floor:Float(value:Float)
		Return MonkeyFloor(value)
	End Function

	Function Ceil:Float(value:Float)
		Return MonkeyCeil(value)
	End Function

	Function Round:Float(value:Float)
		If (value > 0) Then
			Return Int(value + .5)
		Else
			Return Int(value - .5)
		End If
	End Function

	Function Min:Float(number1:Float, number2:Float)
		Return MonkeyMin(number1, number2)
	End Function

	Function Max:Float(number1:Float, number2:Float)
		Return MonkeyMax(number1, number2)
	End Function

	Function Bound:Float(value:Float, min:Float, max:Float)
		Return Clamp(value, min, max)
	End Function

	Function Srand:Float(seed:Float)
		Return Float(seed Shr 8 & $ffffff)/$1000000
	End Function

	#Rem
	Function Shuffle:Object[](objects:Object[], howManyTimes:Int)
		Shuffle is not currently supported in Monkey. Use FlxArray.Shuffle method
	End Function
	#End

	#Rem
	Function GetRandom:FlxBasic(objects:FlxBasic[], startIndex:Int = 0, length:Int = 0)
		GetRandom is not currently supported in Monkey. Use FlxArray.GetRandom method
	End Function
	#End

	Function GetTicks:Int()
		Return Millisecs()
	End Function

	Function FormatTicks:String(startTicks:Int, endTicks:Int)
		Return ((endTicks - startTicks) / 1000) + "s"
	End Function

	Function MakeColor:Int(red:Int, green:Int, blue:Int, alpha:Float = 1)
		If (alpha <= 1) alpha *= 255
		Return (alpha & $FF) Shl 24 | (red & $FF) Shl 16 | (green & $FF) Shl 8 | (blue & $FF)
	End Function

	Function MakeColorFromHSB:Int(hue:Float, saturation:Float, brightness:Float, alpha:Float = 1)
		Local red:Float
		Local green:Float
		Local blue:Float

		If (saturation = 0)
			red = brightness
			green = brightness
			blue = brightness
		Else
			If (hue = 360) hue = 0

			Local slice:Int = hue / 60
			Local hf:Float = hue / 60 - slice
			Local aa:Float = brightness * (1 - saturation)
			Local bb:Float = brightness * (1 - saturation * hf)
			Local cc:Float = brightness * (1 - saturation * (1.0 - hf))

			Select (slice)
				Case 0
					red = brightness
					green = cc
					blue = aa

				Case 1
					red = bb
					green = brightness
					blue = aa

				Case 2
					red = aa
					green = brightness
					blue = cc

				Case 3
					red = aa
					green = bb
					blue = brightness

				Case 4
					red = cc
					green = aa
					blue = brightness

				Case 5
					red = brightness
					green = aa
					blue = bb

				Default
					red = 0
					green = 0
					blue = 0
			End Select
		End If

		If (alpha <= 1) alpha *= 255
		Return (alpha & $FF) Shl 24 | int(red * 255) Shl 16 | int(green * 255) Shl 8 | int(blue * 255)
	End Function

	Function GetRGBA:Float[](color:Int, resluts:Float[] = [])
		If (resluts.Length() <> 4) resluts = resluts.Resize(4)

		resluts[0] = (color Shr 16) & $FF
		resluts[1] = (color Shr 8) & $FF
		resluts[2] = color & $FF
		resluts[3] = Float((color Shr 24) & $FF) / 255
		Return resluts
	End Function

	Function GetHSB:Float[](color:Int, resluts:Float[] = [])
		If (resluts.Length() <> 4) resluts = resluts.Resize(4)

		Local red:Float = Float((color Shr 16) & $FF) / 255
		Local green:Float = Float((color Shr 8) & $FF) / 255
		Local blue:Float = Float(color & $FF) / 255

		Local m:Float = MonkeyMax(red, green)
		Local dmax:Float = MonkeyMax(m, blue)
		m = MonkeyMin(red, green)
		Local dmin:Float = MonkeyMin(m, blue)
		Local range:Float = dmax - dmin

		resluts[2] = dmax
		resluts[1] = 0
		resluts[0] = 0

		If (dmax <> 0) resluts[1] = range / dmax

		If (resluts[1] <> 0) Then
			If (red = dmax) Then
				resluts[0] = (green - blue) / range

			ElseIf (green = dmax) Then
				resluts[0] = 2 + (blue - red) / range

			ElseIf (blue = dmax) Then
				resluts[0] = 4 + (red - green) / range
			End If

			resluts[0] *= 60
			If (resluts[0] < 0) resluts[0] += 360
		End If

		resluts[3] = Float((color Shr 24) & $FF) / 255

		Return resluts
	End Function

	Function FormatTime:String(seconds:Float, showMS:Bool = False)
		Local timeString:StringStack = New StringStack()
		timeString.Push(Int(seconds / 60) + ":")

		Local timeStringHepler:Int = Int(seconds) Mod 60

		If (timeStringHepler < 10) Then
			timeString.Push("0")
		End If

		timeString.Push(timeStringHepler)

		If (showMS) Then
			timeString.Push(".")
			timeStringHepler = (seconds - Int(seconds)) * 100

			If (timeStringHepler < 10) Then
				timeString.Push("0")
			End If

			timeString.Push(timeStringHepler)
		End If

		Return timeString.Join("")
	End Function

	Function FormatMoney:String(amount:Float, showDecimal:Bool = True, englishStyle:Bool = True)
		Local helper:Int
		Local sgn:Int = Sgn(amount)
		Local showSgn:Bool = False
		amount = Abs(amount)
		Local intAmount:Int = amount
		Local comma:String = ""
		Local result:String = ""
		Local zeroes:String = ""

		If (intAmount = 0) result = "0"

		While (intAmount > 0)
			If (result.Length() > 0 And comma.Length() <= 0) Then
				If (englishStyle) Then
					comma = ","
				Else
					comma = "."
				End If
			End If

			helper = intAmount - Int(intAmount / 1000) * 1000
			intAmount /= 1000

			zeroes = ""

			If (intAmount > 0) Then
				If (helper < 100) Then
					zeroes = "0"
				End If

				If (helper < 10) Then
					zeroes = "00"
				End If
			End If

			result = zeroes + helper + comma + result
			showSgn = True
		Wend

		If (showDecimal) Then
			intAmount = Round(amount * 100) - (Int(amount) * 100)
			If (intAmount <> 0) showSgn = True

			If (englishStyle) Then
				result += "."
			Else
				result += ","
			End If

			If (intAmount < 10) Then
				result += "0"
			End If

			result += intAmount
		End If

		If (sgn < 0 And showSgn) Then
			Return "-" + result
		End If

		Return result
	End Function

	Function GetClassName:String(obj:Object, simple:Bool = False)
		If (simple) Then
			Local name:String = MonkeyGetClass(obj).Name
			Return name[name.FindLast(".")+1..]
		End If

		Return MonkeyGetClass(obj).Name
	End Function

	Function CompareClassNames:Bool(object1:Object, object2:Object)
		Return (MonkeyGetClass(object1).Name = MonkeyGetClass(object2).Name)
	End Function

	Function GetClass:ClassInfo(name:String)
		Return MonkeyGetClass(name)
	End Function

	Function GetObjectClass:ClassInfo()
		If (_objClass <> Null)
			Return _objClass
		End If

		_objClass = MonkeyGetClass("monkey.lang.Object")

		Return _objClass
	End Function

	Function ComputeVelocity:Float(velocity:Float, acceleration:Float = 0, drag:Float = 0, max:Float = 10000)
		If (acceleration <> 0) Then
			velocity += acceleration * FlxG.Elapsed

		ElseIf (drag <> 0) Then
			drag *= FlxG.Elapsed

			If (velocity - drag > 0) Then
				velocity -= drag
			ElseIf (velocity + drag < 0) Then
				velocity += drag
			Else
				velocity = 0
			End If
		End If

		If (velocity <> 0 And max <> 10000) Then
			If (velocity > max) Then
				velocity = max
			ElseIf (velocity < -max) Then
				velocity = -max
			End If
		End If

		Return velocity
	End Function

	Function RotatePoint:FlxPoint(x:Float, y:Float, pivotX:Float, pivotY:Float, angle:Float, point:FlxPoint = Null)
		Local sin:Float = 0
		Local cos:Float = 0
		Local radians:Float = angle * -0.017453293

		While (radians < -PI)
			radians += TWOPI
		Wend

		While (radians > PI)
			radians = radians - TWOPI
		Wend

		If (radians < 0) Then
			sin =  1.27323954 * radians + .405284735 * radians * radians
			If (sin < 0) Then
				sin = .225 * (sin * -sin - sin) + sin
			Else
				sin = .225 * (sin * sin - sin) + sin
			End If
		Else
			sin = 1.27323954 * radians - 0.405284735 * radians * radians
			If (sin < 0) Then
				sin = .225 * (sin * -sin - sin) + sin
			Else
				sin = .225 * (sin * sin - sin) + sin
			End If
		End If

		radians += HALFPI
		If (radians > PI) radians -= TWOPI

		If (radians < 0) Then
			cos = 1.27323954 * radians + 0.405284735 * radians * radians
			If (cos < 0) Then
				cos = .225 * (cos * -cos - cos) + cos
			Else
				cos = .225 * (cos * cos - cos) + cos
			End If
		Else
			cos = 1.27323954 * radians - 0.405284735 * radians * radians
			If (cos < 0) Then
				cos = .225 * (cos * -cos - cos) + cos
			Else
				cos = .225 * (cos * cos - cos) + cos
			End If
		End If

		Local dx:Float = x - pivotX
		Local dy:Float = pivotY + y

		If (point = Null) point = New FlxPoint()
		point.x = pivotX + cos * dx - sin * dy
		point.y = pivotY - sin * dx - cos * dy

		Return point
	End Function

	Function GetAngle:Float(point1:FlxPoint, point2:FlxPoint)
		Local x:Float = point2.x - point1.x
		Local y:Float = point2.y - point1.y

		If (x = 0 And y = 0) Return 0

		Local c1:Float = PI * .25
		Local c2:Float = 3 * c1
		Local ay:Float = MonkeyAbs(y)
		Local angle:Float = 0

		If (x >= 0) Then
			angle = c1 - c1 * ((x - ay) / (x + ay))
		Else
			angle = c2 - c1 * ((x + ay) / (ay - x))
		End If

		If (y < 0) Then
			angle =	-angle * 57.2957796
		Else
			angle =	angle * 57.2957796
		End If

		If (angle > 90) Then
			angle = angle - 270
		Else
			angle += 90
		End If

		Return angle
	End Function

	Function GetDistance:Float(point1:FlxPoint, point2:FlxPoint)
		Local dx:Float = point1.x - point2.x
		Local dy:Float = point1.y - point2.y

		Return Sqrt(dx * dx + dy * dy)
	End Function

	Function GetDistance:Float(x1:Float, y1:Float, x2:Float, y2:Float)
		Local dx:Float = x1 - x2
		Local dy:Float = y1 - y2

		Return Sqrt(dx * dx + dy * dy)
	End Function

	Function SetImageMask:Image(image:Image, maskColor:Int)
		Local bitmapData:FlxImageData = FlxImageData.FromImage(image, True)
		bitmapData.ColorReplace(maskColor, 0)

		Local result:Image = bitmapData.Image
		bitmapData.Destroy()

		Return result
	End Function

	Function SetImagePadding:Image(image:Image, paddings:Int = Image.XYPadding)
		Local paddingX:Int, paddingY:Int

		If (paddings & Image.XPadding) paddingX = 1
		If (paddings & Image.YPadding) paddingY = 1

		Return FlxU.SetImagePadding(image, paddingX, paddingY)
	End Function

	Function SetImagePadding:Image(image:Image, paddingX:Int, paddingY:Int)
		Local bitmapData:FlxImageData = FlxImageData.FromImage(image, False, paddingX, paddingY)
		Local result:Image = bitmapData.Image
		bitmapData.Destroy()

		Return result
	End Function

End Class


Real elpsed time returned

Real elpsed time returned

Strict

Import mojo

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Int

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _lostFocus:Bool

	Field _step:Int

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _lastUpdateTime:Int

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, framerate:Int = 60, useSystemCursor:Bool = False)
		_lostFocus = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True
		If (Not useSystemCursor) HideMouse()
		_debuggerUp = False

		_state = Null

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
		_created = False

		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 60
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False
	End Method

	Method OnCreate:Int()
		_Reset()
		_InitData()
		_Step()

		_soundTrayX	= (FlxG.Width / 2) * FlxCamera.DefaultZoom - (_soundTrayWidth / 2)
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		Return 0
	End Method

	Method OnUpdate:Int()
		If (_lastUpdateTime <> 0) Then
			FlxG.Elapsed = FlxG.TimeScale * ((Millisecs() - _lastUpdateTime) / 1000.0)
		End If

		_lastUpdateTime = Millisecs()

		#If TARGET <> "ios" Or TARGET <> "android"
			If (useSoundHotKeys) Then
				If (KeyHit(KEY_0)) Then
					FlxG.Mute = Not FlxG.Mute

					If (FlxG.VolumeHandler <> Null) Then
						If (FlxG.Mute) Then
							FlxG.VolumeHandler.OnVolumeChange(0)
						Else
							FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
						End If
					End If

					_ShowSoundTray()
				End If

				If (KeyHit(KEY_MINUS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() - .1)
					_ShowSoundTray()
				End If

				If (KeyHit(KEY_EQUALS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() + .1)
					_ShowSoundTray()
				End If
			End If
		#End

		_UpdateSoundTray()
		_Step()

		Return 0
	End Method

	Method OnRender:Int()
		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (Not FlxG._CurrentCamera.active) Then
				i+=1
				Continue
			End If

			FlxG._CurrentCameraID = i

			If (FlxG._CurrentCamera = Null Or Not FlxG._CurrentCamera.exists Or Not FlxG._CurrentCamera.visible) Continue

			FlxG._CurrentCamera.DrawFX() 'not realy draw. Only calculation
			FlxG._CurrentCamera.Lock()
			_state.Draw()
			FlxG.DrawPlugins()
			FlxG._CurrentCamera.Unlock()

			i+=1
		Wend

		#If TARGET <> "ios" Or TARGET <> "android"
			If (_soundTrayVisible) Then
				Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
				If (FlxG.Mute) globalVolume = 0

				Local bx:Int = 20
				Local by:Int = 28

				If (FlxG._LastDrawingColor <> FlxG.WHITE) Then
					SetColor(255, 255, 255)
					FlxG._LastDrawingColor = FlxG.WHITE
				End If

				PushMatrix()
				Translate(_soundTrayX, _soundTrayY)

				Local i:Int = 0
				While (i < 10)
					If (i < globalVolume) Then
						If (FlxG._LastDrawingAlpha <> 1) Then
							SetAlpha(1)
							FlxG._LastDrawingAlpha = 1
						End If

					Else
						If (FlxG._LastDrawingAlpha <> .5) Then
							SetAlpha(.5)
							FlxG._LastDrawingAlpha = .5
						End If
					End If

					DrawRect(bx, by, 8, i * 2)

					bx += 12
					by -= 2
					i += 1
				Wend

				_soundTrayLabel.Draw()

				PopMatrix()
			End If
		#End

		FlxG.Mouse.Draw()

		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
		If (Not _debuggerUp And useSystemCursor) Then
			HideMouse()
		End If
		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play(FlxG.DATA_PREFIX + "beep")
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()

		_state = _requestedState
		_state.Create()
	End Method

	Method _Step:Void()
		If (_requestedReset) Then
			_requestedReset = False
			_requestedState = FlxState(_iState.CreateInstance())
			_replayTimer = 0
			_replayCancelKeys = []
			_Reset()
			FlxG.Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

			If (_debugger <> Null) Then
				'TODO
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

			If (_debugger <> Null) Then
				'TODO
			End If

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

			If (_debugger <> Null) Then
				'TODO
			End If
		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

			If (_debugger <> Null) Then
				'TODO
			End If
		End If

		_Update()

		If (_debugger <> Null) Then
			'TODO
		End If
	End Method

	Method _UpdateSoundTray:Void()
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= FlxG.Elapsed

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (FlxG.Elapsed * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Update:Void()
		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()
	End Method

	Method _Reset:Void()
		SetUpdateRate(FlxG.Framerate)
		Seed = SystemMillisecs()

		FlxG.DeviceWidth = DeviceWidth()
		FlxG.DeviceHeight = DeviceHeight()

		If (useVirtualResolution) Then
			FlxG._DeviceScaleFactorX = FlxG.DeviceWidth / Float(FlxG.Width)
			FlxG._DeviceScaleFactorY = FlxG.DeviceHeight / Float(FlxG.Height)
		Else
			FlxG._DeviceScaleFactorX = 1
			FlxG._DeviceScaleFactorY = 1
		End If

		_step = 1000.0 / FlxG.Framerate
		_lastUpdateTime = 0
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxG.DATA_PREFIX + FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + Min(size, 17) + ".png")
		Next

		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "default", FlxG.DATA_PREFIX + "default.png")
		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "button", FlxG.DATA_PREFIX + "button.png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor(FlxG.DATA_PREFIX + "cursor", FlxG.DATA_PREFIX + "cursor.png")
		FlxAssetsManager.AddSound(FlxG.DATA_PREFIX + "beep", FlxG.DATA_PREFIX + "beep.mp3")

		Self.OnContentInit()
	End Method
End Class

Strict

Import mojo

Import flxextern
Import flxbasic
Import flxstate
Import flxcamera
Import flxtimer
Import flxtext
Import flxg
Import flxu
Import flxtilemap
Import system.flxassetsmanager
Import system.flxfont
Import system.flxdebugger
Import system.flxreplay
Import plugin.timermanager

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Int

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _lostFocus:Bool

	Field _step:Int

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _fps:Int

	Field _fpsCounter:Int

	Field _lastFpsCounter:Int

	Field _fpsTime:Int

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, framerate:Int = 60, useSystemCursor:Bool = False)
		_lostFocus = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True
		If (Not useSystemCursor) HideMouse()
		_debuggerUp = False

		_state = Null

		_replay = New FlxReplay()
		_replayRequested = False
		_recordingRequested = False
		_replaying = False
		_recording = False

		_iState = initialState
		_requestedState = Null
		_requestedReset = True
		_created = False

		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 60
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False
	End Method

	Method OnCreate:Int()
		_Reset()
		_InitData()
		_Step()

		_soundTrayX	= (FlxG.Width / 2) * FlxCamera.DefaultZoom - (_soundTrayWidth / 2)
		_soundTrayLabel = New FlxText(10, 32, _soundTrayWidth, "VOLUME")
		_soundTrayLabel.SetFormat(FlxText.SYSTEM_FONT, 16, FlxG.WHITE, FlxText.ALIGN_CENTER)
		Return 0
	End Method

	Method OnUpdate:Int()
		#If TARGET <> "ios" Or TARGET <> "android"
			If (useSoundHotKeys) Then
				If (KeyHit(KEY_0)) Then
					FlxG.Mute = Not FlxG.Mute

					If (FlxG.VolumeHandler <> Null) Then
						If (FlxG.Mute) Then
							FlxG.VolumeHandler.OnVolumeChange(0)
						Else
							FlxG.VolumeHandler.OnVolumeChange(FlxG.Volume())
						End If
					End If

					_ShowSoundTray()
				End If

				If (KeyHit(KEY_MINUS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() - .1)
					_ShowSoundTray()
				End If

				If (KeyHit(KEY_EQUALS)) Then
					FlxG.Mute = False
					FlxG.Volume(FlxG.Volume() + .1)
					_ShowSoundTray()
				End If
			End If
		#End

		Return 0
	End Method

	Method OnRender:Int()
		If (_fps < 0) Then
			_fpsTime = Millisecs()
			_fps = FlxG.Framerate
			_lastFpsCounter = _fps
		Else
			If (Millisecs() - _fpsTime > 1000) Then
				If (Abs(_lastFpsCounter - _fpsCounter) < 10) Then
					_fps = _fpsCounter
				End If

				_lastFpsCounter = _fpsCounter
				_fpsCounter = 0
				_fpsTime = Millisecs()
			Else
				_fpsCounter += 1
			End If
		End If

		'Real elapsed very unstable in Monkey. TODO!
		FlxG.Elapsed = FlxG.TimeScale * (1.0 / _fps)

		_UpdateSoundTray()
		_Step()

		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

		FlxG._LastDrawingColor = FlxG.WHITE
		FlxG._LastDrawingBlend = GetBlend()
		FlxG._LastDrawingAlpha = GetAlpha()
		FlxG._CurrentCamera = Null

		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG._CurrentCamera = FlxG.Cameras.Get(i)

			If (Not FlxG._CurrentCamera.active) Then
				i+=1
				Continue
			End If

			FlxG._CurrentCameraID = i

			If (FlxG._CurrentCamera = Null Or Not FlxG._CurrentCamera.exists Or Not FlxG._CurrentCamera.visible) Continue

			FlxG._CurrentCamera.DrawFX() 'not realy draw. Only calculation
			FlxG._CurrentCamera.Lock()
			_state.Draw()
			FlxG.DrawPlugins()
			FlxG._CurrentCamera.Unlock()

			i+=1
		Wend

		#If TARGET <> "ios" Or TARGET <> "android"
			If (_soundTrayVisible) Then
				Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
				If (FlxG.Mute) globalVolume = 0

				Local bx:Int = 20
				Local by:Int = 28

				If (FlxG._LastDrawingColor <> FlxG.WHITE) Then
					SetColor(255, 255, 255)
					FlxG._LastDrawingColor = FlxG.WHITE
				End If

				PushMatrix()
				Translate(_soundTrayX, _soundTrayY)

				Local i:Int = 0
				While (i < 10)
					If (i < globalVolume) Then
						If (FlxG._LastDrawingAlpha <> 1) Then
							SetAlpha(1)
							FlxG._LastDrawingAlpha = 1
						End If

					Else
						If (FlxG._LastDrawingAlpha <> .5) Then
							SetAlpha(.5)
							FlxG._LastDrawingAlpha = .5
						End If
					End If

					DrawRect(bx, by, 8, i * 2)

					bx += 12
					by -= 2
					i += 1
				Wend

				_soundTrayLabel.Draw()

				PopMatrix()
			End If
		#End

		FlxG.Mouse.Draw()

		#If CONFIG = "debug"
			DrawText("FPS: " + _fps, 10, 10)
		#End

		Return 0
	End Method

	Method OnSuspend:Int()
		ShowMouse()
		FlxG.PauseSounds()
		Return 0
	End Method

	Method OnResume:Int()
		If (Not _debuggerUp And useSystemCursor) Then
			HideMouse()
		End If
		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

Private
	Method _ShowSoundTray:Void(silent:Bool = False)
		If (Not silent) Then
			FlxG.Play(FlxG.DATA_PREFIX + "beep")
		End If

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()

		Local timeManager:TimerManager = FlxTimer.Manager()
		If (timeManager <> Null) timeManager.Clear()

		If (_state <> Null) _state.Destroy()

		_state = _requestedState
		_state.Create()
	End Method

	Method _Step:Void()
		If (_requestedReset) Then
			_requestedReset = False
			_requestedState = FlxState(_iState.CreateInstance())
			_replayTimer = 0
			_replayCancelKeys = []
			_Reset()
			FlxG.Reset()
		End If

		If (_recordingRequested) Then
			_recordingRequested = False
			_replay.Create(FlxG.GlobalSeed)
			_recording = True

			If (_debugger <> Null) Then
				'TODO
				FlxG.Log("FLIXEL: starting new flixel gameplay record.")
			End If

		ElseIf (_replayRequested)
			_replayRequested = False
			_replay.Rewind()
			FlxG.GlobalSeed = _replay.seed

			If (_debugger <> Null) Then
				'TODO
			End If

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

		If (_replaying) Then
			If (_replayCancelKeys.Length() > 0 And Not KeyDown(192) And Not KeyDown(220)) Then
				Local i:Int = 0
				Local l:Int = _replayCancelKeys.Length()

				While (i < l)
					If (KeyDown(_replayCancelKeys[i])) Then
						If (_replayCallback <> Null) Then
							_replayCallback.OnReplayComplete()
							_replayCallback = Null
						Else
							FlxG.StopReplay()
						End If

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

				If (_replayTimer <= 0) Then
					If (_replayCallback <> Null) Then
						_replayCallback.OnReplayComplete()
						_replayCallback = Null
					Else
						FlxG.StopReplay()
					End If
				End If
			End If

			If (_replaying And _replay.finished) Then
				FlxG.StopReplay()

				If (_replayCallback <> Null) Then
					_replayCallback.OnReplayComplete()
					_replayCallback = Null
				End If
			End If

			If (_debugger <> Null) Then
				'TODO
			End If
		Else
			FlxG.UpdateInput()
		End If

		If (_recording) Then
			_replay.RecordFrame()

			If (_debugger <> Null) Then
				'TODO
			End If
		End If

		_Update()

		If (_debugger <> Null) Then
			'TODO
		End If
	End Method

	Method _UpdateSoundTray:Void()
		If (Not _soundTrayVisible) Return

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= FlxG.Elapsed

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (FlxG.Elapsed * FlxG.Height * 2)

			If (_soundTrayY <= -_soundTrayHeight) Then
				_soundTrayVisible = False

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Update:Void()
		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()
	End Method

	Method _Reset:Void()
		SetUpdateRate(FlxG.Framerate)
		Seed = SystemMillisecs()

		FlxG.DeviceWidth = DeviceWidth()
		FlxG.DeviceHeight = DeviceHeight()

		If (useVirtualResolution) Then
			FlxG._DeviceScaleFactorX = FlxG.DeviceWidth / Float(FlxG.Width)
			FlxG._DeviceScaleFactorY = FlxG.DeviceHeight / Float(FlxG.Height)
		Else
			FlxG._DeviceScaleFactorX = 1
			FlxG._DeviceScaleFactorY = 1
		End If

		_step = 1000.0 / FlxG.Framerate
		_fps = -1
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

		Local minSystemFontSize:Int = 8
		Local maxSystemFontSize:Int = 24
		Local fontPathPrefix:String = FlxG.DATA_PREFIX + FlxText.SYSTEM_FONT + "_font_"

		Local system:FlxFont = 	FlxAssetsManager.AddFont(FlxText.SYSTEM_FONT)

		For Local size:Int = minSystemFontSize To maxSystemFontSize
			system.SetPath(size, fontPathPrefix + Min(size, 17) + ".png")
		Next

		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "default", FlxG.DATA_PREFIX + "default.png")
		FlxAssetsManager.AddImage(FlxG.DATA_PREFIX + "button", FlxG.DATA_PREFIX + "button.png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES, FlxTilemap.AUTOTILES + ".png")
		FlxAssetsManager.AddImage(FlxTilemap.AUTOTILES_ALT, FlxTilemap.AUTOTILES_ALT + ".png")
		FlxAssetsManager.AddCursor(FlxG.DATA_PREFIX + "cursor", FlxG.DATA_PREFIX + "cursor.png")
		FlxAssetsManager.AddSound(FlxG.DATA_PREFIX + "beep", FlxG.DATA_PREFIX + "beep.mp3")

		Self.OnContentInit()
	End Method
End Class


Refactring names of button listeners

Refactring names of button listeners

Strict

Import flxextern
Import flxsprite
Import flxtext
Import flxpoint
Import flxsound
Import flxg
Import flxcamera
Import system.flxassetsmanager

Import "data/flx_button.png"
Import "data/flx_beep.mp3"

Class FlxButton Extends FlxSprite

	Const NORMAL:Int = 0

	Const HIGHLIGHT:Int = 1

	Const PRESSED:Int = 2

	Field label:FlxText

	Field labelOffset:FlxPoint

	Field onUp:FlxButtonClickListener

	Field onDown:FlxButtonDownListener

	Field onOver:FlxButtonOverListener

	Field onOut:FlxButtonOutListener

	Field status:Int

	Field soundOver:FlxSound

	Field soundOut:FlxSound

	Field soundDown:FlxSound

	Field soundUp:FlxSound

Private
	Field _onToggle:Bool

	Field _pressed:Bool

	Field _initialized:Bool

Public
	Method New(x:Float = 0, y:Float = 0, label:String = "", onClick:FlxButtonClickListener = Null, driver:FlxClass = Null)
		Super.New(x, y)

		If (label.Length() > 0) Then
			Self.label = New FlxText(0, 0, 80, label, driver)
			Self.label.SetFormat(FlxText.SYSTEM_FONT, 8, $FF333333, FlxText.ALIGN_CENTER)
			labelOffset = New FlxPoint(-1, 3)
		End If

		LoadGraphic(FlxG.DATA_PREFIX + "button", True, False, 80, 20)
		onUp = onClick
		onDown = Null
		onOut = Null
		onOver = Null

		soundOver = Null
		soundOut = Null
		soundDown = Null
		soundUp = Null

		status = NORMAL
		_onToggle = False
		_pressed = False
	End Method

	Method Destroy:Void()
		If (label <> Null) Then
			label.Destroy()
			label = Null
		End If

		onUp = Null
		onDown = Null
		onOut = Null
		onOver = Null

		If (soundOver <> Null) Then
			soundOver.Destroy()
			soundOver = Null
		End If

		If (soundOut <> Null) Then
			soundOut.Destroy()
			soundOut = Null
		End If

		If (soundDown <> Null) Then
			soundDown.Destroy()
			soundDown = Null
		End If

		If (soundUp <> Null) Then
			soundUp.Destroy()
			soundUp = Null
		End If

		Super.Destroy()
	End Method

	Method Update:Void()
		_UpdateButton()

		If (label = Null) Return

		Select (Frame)
			Case HIGHLIGHT
				label.Alpha = 1.0

			Case PRESSED
				label.Alpha = .5
				label.y += 1

			Case NORMAL
				label.Alpha = .8

			Default
				label.Alpha = .8
		End Select
	End Method

	Method Draw:Void()
		Super.Draw()

		If (label <> Null) Then
			label.scrollFactor = scrollFactor
			label.Draw()
		End If
	End Method

	Method _ResetHelpers:Void()
		Super._ResetHelpers()

		If (label <> Null) Then
			label.SetWidth(width)
		End If
	End Method

	Method SetSounds:Void(soundOver:String = "", soundOverVolume:Float = 1.0, soundOut:String = "", soundOutVolume:Float = 1.0, soundDown:String = "", soundDownVolume:Float = 1.0, SoundUp:String = "", SoundUpVolume:Float = 1.0)
		If (soundOver.Length() > 0) Then
			Self.soundOver = FlxG.LoadSound(soundOver, soundOverVolume)
		End If

		If (soundOut.Length() > 0) Then
			Self.soundOut = FlxG.LoadSound(soundOut, soundOutVolume)
		End If

		If (soundDown.Length() > 0) Then
			Self.soundDown = FlxG.LoadSound(soundDown, soundDownVolume)
		End If

		If (SoundUp.Length() > 0) Then
			Self.SoundUp = FlxG.LoadSound(SoundUp, SoundUpVolume)
		End If
	End Method

	Method On:Bool() Property
		Return _onToggle
	End Method

	Method On:Void(on:Bool) Property
		_onToggle = on
	End Method

Private
	Method _UpdateButton:Void()
		If (FlxG.mouse.Visible) Then
			Local cameras:Stack<FlxCamera> = FlxG.cameras
			Local camera:FlxCamera
			Local i:Int = 0
			Local l:Int = cameras.Length()
			Local offAll:Bool = True
			Local click:Bool = False

			While (i < l)
				camera = cameras.Get(i)
				FlxG.mouse.GetWorldPosition(camera, _point)

				If (OverlapsPoint(_point, True, camera)) Then
					offAll = False

					If (FlxG.mouse.JustPressed()) Then
						status = PRESSED

						If (onDown <> Null) Then
							onDown.OnButtonDown()
						End If

						If (soundDown <> Null) Then
							soundDown.Play(True)
						End If
					End If

					If (FlxG.mouse.JustReleased() And status = PRESSED) Then
						status = NORMAL
						click = True
					End If

					If (status = NORMAL) Then
						status = HIGHLIGHT

						If (onOver <> Null) Then
							onOver.OnButtonOver()
						End If

						If (soundOver <> Null) Then
							soundOver.Play(True)
						End If
					End If
				End If

				If (offAll) Then
					If (status <> NORMAL) Then
						If (onOut <> Null) Then
							onOut.OnButtonOut()
						End If

						If (soundOut <> Null) Then
							soundOut.Play(True)
						End If
					End If

					status = NORMAL
				End If

				i += 1
			Wend

			If (click) Then
				If (onUp <> Null) Then
					onUp.OnButtonClick()
				End If

				If (soundUp <> Null) Then
					soundUp.Play(True)
				End If
			End If
		End If

		If (label <> Null) Then
			label.x = x
			label.y = y
		End If

		If (labelOffset <> Null) Then
			label.x += labelOffset.x
			label.y += labelOffset.y
		End If

		If (status = HIGHLIGHT And _onToggle) Then
			Frame = NORMAL
		Else
			Frame = status
		End If
	End Method

End Class

Interface FlxButtonClickListener

	Method OnButtonClick:Void()

End Interface

Interface FlxButtonDownListener

	Method OnButtonDown:Void()

End Interface

Interface FlxButtonOverListener

	Method OnButtonOver:Void()

End Interface

Interface FlxButtonOutListener

	Method OnButtonOut:Void()

End Interface

Strict

Import flxextern
Import flxsprite
Import flxtext
Import flxpoint
Import flxsound
Import flxg
Import flxcamera
Import system.flxassetsmanager

Import "data/flx_button.png"
Import "data/flx_beep.mp3"

Class FlxButton Extends FlxSprite

	Const NORMAL:Int = 0

	Const HIGHLIGHT:Int = 1

	Const PRESSED:Int = 2

	Field label:FlxText

	Field labelOffset:FlxPoint

	Field onUp:FlxButtonUpListener

	Field onDown:FlxButtonDownListener

	Field onOver:FlxButtonOverListener

	Field onOut:FlxButtonOutListener

	Field status:Int

	Field soundOver:FlxSound

	Field soundOut:FlxSound

	Field soundDown:FlxSound

	Field soundUp:FlxSound

Private
	Field _onToggle:Bool

	Field _pressed:Bool

	Field _initialized:Bool

Public
	Method New(x:Float = 0, y:Float = 0, label:String = "", onClick:FlxButtonUpListener = Null, driver:FlxClass = Null)
		Super.New(x, y)

		If (label.Length() > 0) Then
			Self.label = New FlxText(0, 0, 80, label, driver)
			Self.label.SetFormat(FlxText.SYSTEM_FONT, 8, $FF333333, FlxText.ALIGN_CENTER)
			labelOffset = New FlxPoint(-1, 3)
		End If

		LoadGraphic(FlxG.DATA_PREFIX + "button", True, False, 80, 20)
		onUp = onClick
		onDown = Null
		onOut = Null
		onOver = Null

		soundOver = Null
		soundOut = Null
		soundDown = Null
		soundUp = Null

		status = NORMAL
		_onToggle = False
		_pressed = False
	End Method

	Method Destroy:Void()
		If (label <> Null) Then
			label.Destroy()
			label = Null
		End If

		onUp = Null
		onDown = Null
		onOut = Null
		onOver = Null

		If (soundOver <> Null) Then
			soundOver.Destroy()
			soundOver = Null
		End If

		If (soundOut <> Null) Then
			soundOut.Destroy()
			soundOut = Null
		End If

		If (soundDown <> Null) Then
			soundDown.Destroy()
			soundDown = Null
		End If

		If (soundUp <> Null) Then
			soundUp.Destroy()
			soundUp = Null
		End If

		Super.Destroy()
	End Method

	Method Update:Void()
		_UpdateButton()

		If (label = Null) Return

		Select (Frame)
			Case HIGHLIGHT
				label.Alpha = 1.0

			Case PRESSED
				label.Alpha = .5
				label.y += 1

			Case NORMAL
				label.Alpha = .8

			Default
				label.Alpha = .8
		End Select
	End Method

	Method Draw:Void()
		Super.Draw()

		If (label <> Null) Then
			label.scrollFactor = scrollFactor
			label.Draw()
		End If
	End Method

	Method _ResetHelpers:Void()
		Super._ResetHelpers()

		If (label <> Null) Then
			label.SetWidth(width)
		End If
	End Method

	Method SetSounds:Void(soundOver:String = "", soundOverVolume:Float = 1.0, soundOut:String = "", soundOutVolume:Float = 1.0, soundDown:String = "", soundDownVolume:Float = 1.0, SoundUp:String = "", SoundUpVolume:Float = 1.0)
		If (soundOver.Length() > 0) Then
			Self.soundOver = FlxG.LoadSound(soundOver, soundOverVolume)
		End If

		If (soundOut.Length() > 0) Then
			Self.soundOut = FlxG.LoadSound(soundOut, soundOutVolume)
		End If

		If (soundDown.Length() > 0) Then
			Self.soundDown = FlxG.LoadSound(soundDown, soundDownVolume)
		End If

		If (SoundUp.Length() > 0) Then
			Self.SoundUp = FlxG.LoadSound(SoundUp, SoundUpVolume)
		End If
	End Method

	Method On:Bool() Property
		Return _onToggle
	End Method

	Method On:Void(on:Bool) Property
		_onToggle = on
	End Method

Private
	Method _UpdateButton:Void()
		If (FlxG.mouse.Visible) Then
			Local cameras:Stack<FlxCamera> = FlxG.cameras
			Local camera:FlxCamera
			Local i:Int = 0
			Local l:Int = cameras.Length()
			Local offAll:Bool = True
			Local click:Bool = False

			While (i < l)
				camera = cameras.Get(i)
				FlxG.mouse.GetWorldPosition(camera, _point)

				If (OverlapsPoint(_point, True, camera)) Then
					offAll = False

					If (FlxG.mouse.JustPressed()) Then
						status = PRESSED

						If (onDown <> Null) Then
							onDown.OnButtonDown()
						End If

						If (soundDown <> Null) Then
							soundDown.Play(True)
						End If
					End If

					If (FlxG.mouse.JustReleased() And status = PRESSED) Then
						status = NORMAL
						click = True
					End If

					If (status = NORMAL) Then
						status = HIGHLIGHT

						If (onOver <> Null) Then
							onOver.OnButtonOver()
						End If

						If (soundOver <> Null) Then
							soundOver.Play(True)
						End If
					End If
				End If

				If (offAll) Then
					If (status <> NORMAL) Then
						If (onOut <> Null) Then
							onOut.OnButtonOut()
						End If

						If (soundOut <> Null) Then
							soundOut.Play(True)
						End If
					End If

					status = NORMAL
				End If

				i += 1
			Wend

			If (click) Then
				If (onUp <> Null) Then
					onUp.OnButtonUp()
				End If

				If (soundUp <> Null) Then
					soundUp.Play(True)
				End If
			End If
		End If

		If (label <> Null) Then
			label.x = x
			label.y = y
		End If

		If (labelOffset <> Null) Then
			label.x += labelOffset.x
			label.y += labelOffset.y
		End If

		If (status = HIGHLIGHT And _onToggle) Then
			Frame = NORMAL
		Else
			Frame = status
		End If
	End Method

End Class

Interface FlxButtonUpListener

	Method OnButtonUp:Void()

End Interface

Interface FlxButtonDownListener

	Method OnButtonDown:Void()

End Interface

Interface FlxButtonOverListener

	Method OnButtonOver:Void()

End Interface

Interface FlxButtonOutListener

	Method OnButtonOut:Void()

End Interface


Added two basic primitive renderers

Added two basic primitive renderers

Strict

Import mojo

Import flxextern
Import flxpoint
Import flxobject
Import flxcamera
Import flxg

Import system.flxanim
Import system.flxcolor

Import "data/default_flx.png"

Class FlxSprite Extends FlxObject

	Global ClassObject:Object

	Field origin:FlxPoint

	Field offset:FlxPoint

	Field scale:FlxPoint

	Field blend:Int

	Field finished:Bool

	Field frameWidth:Int

	Field frameHeight:Int

	Field frames:Int

	Field dirty:Bool

	Field _color:FlxColor

	Field _mixedColor:FlxColor

	Field _camera:FlxCamera

Private
	Global _GraphicLoader:FlxGraphicLoader = New FlxGraphicLoader()

	Global _Matrix:Float[6]

	Field _animations:StringMap<FlxAnim>

	Field _flipped:Bool

	Field _flipNeeded:Bool

	Field _curAnim:FlxAnim

	Field _curFrame:Int

	Field _curIndex:Int

	Field _frameTimer:Float

	Field _paused:Bool

	Field _callback:FlxAnimationListener

	Field _facing:Int

	Field _alpha:Float

	Field _bakedRotation:Float

	Field _pixels:Image

	Field _halfWidth:Float

	Field _halfHeight:Float

	Field _renderer:FlxSpriteRenderer

Public
	Method New(x:Float = 0, y:Float = 0, simpleGraphic:String = "")
		Super.New(x, y)

		offset = New FlxPoint()
		origin = New FlxPoint()

		scale = New FlxPoint(1.0, 1.0)
		_alpha = 1
		_color = New FlxColor(FlxG.WHITE)
		blend = AlphaBlend
		_cameras = Null

		finished = False
		_facing = RIGHT
		_animations = New StringMap<FlxAnim>
		_flipped = False
		_curAnim = Null
		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0
		_paused = False

		_callback = Null

		_mixedColor = New FlxColor(FlxG.WHITE)

		If (simpleGraphic.Length() = 0)
			simpleGraphic = "default" + FlxG.DATA_SUFFIX
		End If

		LoadGraphic(simpleGraphic)
	End Method

	Method Destroy:Void()
		If (_animations <> Null) Then
			_animations.Clear()
			_animations = Null
		End If

		offset = Null
		origin = Null
		scale = Null
		_curAnim = Null
		_callback = Null
		_color = Null
		_mixedColor = Null
		_camera = Null
		_renderer = Null

		Super.Destroy()
	End Method

	Method LoadGraphic:FlxSprite(graphic:String, animated:Bool = False, reverse:Bool = False, width:Int = 0, height:Int = 0, unique:Bool = False)
		_bakedRotation = 0

		_GraphicLoader.name = graphic
		_GraphicLoader.animated = animated
		_GraphicLoader.width = width
		_GraphicLoader.height = height

		_pixels = FlxG.AddBitmap(graphic, _GraphicLoader, unique)

		_flipped = reverse

		Self.width = _pixels.Width()
		frameWidth = Self.width

		Self.height = _pixels.Height()
		frameHeight = Self.height

		ResetHelpers()

		Return Self
	End Method

	Method LoadRotatedGraphic:FlxSprite(graphic:String, rotations:Int = 16, frame:Int = -1)
		Error "LoadRotatedGraphic not currenlty support in " + FlxG.LIBRARY_NAME
		'TODO
		Return Null
	End Method

	Method MakeGraphic:FlxSprite(width:Int, height:Int, color:Int = FlxG.WHITE, unique:Bool = False, key:String = "")
		_pixels = FlxG.CreateBitmap(width, height, color, unique, key)
		_bakedRotation = 0

		Self.width = width
		frameWidth = width
		Self.height = height
		frameHeight = height

		ResetHelpers()

		Return Self
	End Method

	Method PostUpdate:Void()
		Super.PostUpdate()
		_UpdateAnimation()
	End Method

	Method Draw:Void()
		If (_flickerTimer <> 0) Then
			_flicker = Not _flicker
			If (_flicker) Return
		End If

		_camera = FlxG._CurrentCamera

		If (_cameras <> Null And Not _cameras.Contains(_camera)) Return
		If (Not OnScreen(_camera)) Return

		If (dirty) _CalcFrame()

		If (FlxG._LastDrawingBlend <> blend) Then
			SetBlend(blend)
			FlxG._LastDrawingBlend = blend
		End If

		_point.x = x - int(_camera.scroll.x * scrollFactor.x) - offset.x
		_point.y = y - int(_camera.scroll.y * scrollFactor.y) - offset.y

		If (_point.x > 0) Then
			_point.x += 0.0000001
		Else
			_point.x -= 0.0000001
		End If

		If (_point.y > 0) Then
			_point.y += 0.0000001
		Else
			_point.y -= 0.0000001
		End If

		If (_camera.Color <> FlxG.WHITE) Then
			_mixedColor.MixRGB(_color, _camera._color)

			If (FlxG._LastDrawingColor <> _mixedColor.argb) Then
				SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
				FlxG._LastDrawingColor = _mixedColor.argb
			End If
		Else
			If (FlxG._LastDrawingColor <> _color.argb) Then
				SetColor(_color.r, _color.g, _color.b)
				FlxG._LastDrawingColor = _color.argb
			End If
		End If

		If (_camera.Alpha < 1) Then
			Local _mixedAlpha:Float = _camera.Alpha * _alpha

			If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
				SetAlpha(_mixedAlpha)
				FlxG._LastDrawingAlpha = _mixedAlpha
			End If
		Else
			If (FlxG._LastDrawingAlpha <> _alpha) Then
				SetAlpha(_alpha)
				FlxG._LastDrawingAlpha = _alpha
			End If
		End If

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			If ( Not _flipNeeded) Then
				If (_renderer = Null) Then
					DrawImage(_pixels, _point.x, _point.y, _curIndex)
				Else
					_renderer.OnSpriteRender(_point.x, _point.y)
				End If
			Else
				PushMatrix()
					Transform(-1, 0, 0, 1, _point.x + _halfWidth, _point.y + _halfHeight)

					If (_renderer = Null) Then
						DrawImage(_pixels, -_halfWidth, -_halfHeight, _curIndex)
					Else
						_renderer.OnSpriteRender(-_halfWidth, -_halfHeight)
					End If
				PopMatrix()
			End If
		Else
			PushMatrix()
				'Translate
				_Matrix[4] = _point.x + origin.x
				_Matrix[5] = _point.y + origin.y

				'Scale
				_Matrix[0] = scale.x
				_Matrix[3] = scale.y

				'Rotate
				If (angle <> 0 And _bakedRotation = 0) Then
					Local sin:Float = Sin(angle)
					Local cos:Float = Cos(angle)

					_Matrix[1] = sin * _Matrix[0]
					_Matrix[2] = -sin * _Matrix[3]
					_Matrix[0] *= cos
					_Matrix[3] *= cos
				Else
					_Matrix[1] = 0
					_Matrix[2] = 0
				End If

				Transform(_Matrix[0], _Matrix[1], _Matrix[2], _Matrix[3], _Matrix[4], _Matrix[5])

				If (_flipNeeded) Then
					Transform(-1, 0, 0, 1, _halfWidth - origin.x, _halfHeight - origin.y)
				End If

				If (_renderer = Null) Then
					DrawImage(_pixels, -origin.x, -origin.y, _curIndex)
				Else
					_renderer.OnSpriteRender(-origin.x, -origin.y)
				End If
			PopMatrix()
		End If

	#If FLX_DEBUG_ENABLED = "1"
		_VisibleCount += 1;
		If (FlxG.VisualDebug And Not ignoreDrawDebug) DrawDebug(_camera);
	#End
	End Method

	Method DrawFrame:Void(force:Bool = False)
		If (force Or dirty) _CalcFrame()
	End Method

	Method AddAnimation:FlxAnim(name:String, frames:Int[], frameRate:Float = 0, looped:Bool = True)
		Local anim:FlxAnim = New FlxAnim(name, frames, frameRate, looped)
		_animations.Set(name, anim)

		Return anim
	End Method

	Method AddAnimation:FlxAnim(name:String, startFrame:Int, endFrame:Int, frameRate:Float = 0, looped:Bool = True)
		Local i:Int = 0
		Local l:Int = endFrame - startFrame + 1
		Local frames:Int[] = New Int[l]

		While (i < l)
			frames[i] = startFrame + i
			i += 1
		Wend

		Return AddAnimation(name, frames, frameRate, looped)
	End Method

	Method AddAnimation:FlxAnim(name:String, frameRate:Float = 0, looped:Bool = True)
		If (_pixels = Null) Return Null
		Return AddAnimation(name, 0, _pixels.Frames() -1, frameRate, looped)
	End Method

	Method AddAnimationCallback:Void(animationCallback:FlxAnimationListener)
		_callback = animationCallback
	End Method

	Method ClearAnimationCallback:Void()
		_callback = Null
	End Method

	Method GetAnimation:FlxAnim(animName:String)
		Return _animations.Get(animName)
	End Method

	Method GetAnimation:FlxAnim()
		Return _curAnim
	End Method

	Method Play:Void(animName:String, force:Bool = False)
		If (Not force And _curAnim <> Null And animName = _curAnim.name And( _curAnim.looped Or Not finished )) Return

		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0
		_paused = False

		Local anim:FlxAnim = _animations.Get(animName)

		If (anim <> Null) Then
			_curAnim = anim

			If (_curAnim.delay <= 0) Then
				finished = True
			Else
				finished = False
			End If

			_curIndex = _curAnim.frames[_curFrame]
			dirty = True
			Return
		End If

		#If FLX_DEBUG_ENABLED = "1"
			FlxG.Log("WARNING: No animation called ~q" + animName + "~q")
		#End
	End Method

	Method Stop:Void()
		Frame = 0
	End Method

	Method Pause:Void()
		_paused = True
	End Method

	Method Resume:Void()
		_paused = False
	End Method

	Method RandomFrame:Void()
		_curAnim = Null

		If (_pixels <> Null) Then
			_curIndex = Int(FlxG.Random() * (_pixels.Frames() - 1))
		Else
			_curIndex = 0
		End If

		dirty = True
	End Method

	Method SetOriginToCorner:Void()
		origin.x = 0
		origin.y = 0
	End Method

	Method CenterOffsets:Void(adjustPosition:Bool = False)
		offset.x = (frameWidth - width) * .5
		offset.y = (frameHeight - height) * .5

		If (adjustPosition) Then
			x += offset.x
			y += offset.y
		End If
	End Method

	Method Pixels:Image() Property
		Return _pixels
	End Method

	Method Pixels:Void(pixels:Image) Property
		_pixels = pixels

		Local width:Int = 0
		Local height:Int = 0

		If (_pixels <> Null) Then
			width = pixels.Width()
			height = pixels.Height()
		End If

		If (_pixels <> Null Or _renderer = Null) Then
			Self.width = width
			Self.height = height
			frameWidth = width
			frameHeight = height
			ResetHelpers()
		End If
	End Method

	Method Facing:Int() Property
		Return _facing
	End Method

	Method Facing:Void(direction:Int) Property
		If (_facing <> direction) dirty = True
		_facing = direction

		_flipNeeded = (_flipped And _facing = LEFT)
	End Method

	Method Alpha:Float() Property
		Return _alpha
	End Method

	Method Alpha:Void(alpha:Float) Property
		If (alpha < 0) alpha = 0
		_alpha = alpha
	End Method

	Method Color:Int() Property
		Return _color.argb
	End Method

	Method Color:Void(color:Int) Property
		_color.SetRGB(color)
	End Method

	Method Frame:Int() Property
		Return _curIndex
	End Method

	Method Frame:Void(frame:Int) Property
		_curAnim = Null
		_curIndex = frame
		_paused = False
		dirty = True
	End Method

	Method OnScreen:Bool(camera:FlxCamera = Null)
		If (camera = Null) camera = FlxG.Camera
		GetScreenXY(_point, camera)

		_point.x = _point.x - offset.x
		_point.y = _point.y - offset.y

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			Return _point.x + frameWidth > 0 And _point.x < camera.Width And _point.y + frameHeight > 0 And _point.y < camera.Height
		End If

		Local radius:Float = Sqrt(_halfWidth * _halfWidth + _halfHeight * _halfHeight) * Max(Abs(scale.x), Abs(scale.y))
		_point.x += _halfWidth
		_point.y += _halfHeight

		Return _point.x + radius > 0 And _point.x - radius < camera.Width And _point.y + radius > 0 And _point.y - radius < camera.Height
	End Method

	Method SetRenderer:Void(render:FlxSpriteRenderer)
		_renderer = render
		_renderer.OnSpriteBind(Self)

		frameWidth = width
		frameHeight = height

		ResetHelpers()
	End Method

	Method ClearRenderer:Void()
		Local renderer:FlxSpriteRenderer = _renderer
		_renderer = Null
		renderer.OnSpriteUnbind()

		frameWidth = width
		frameHeight = height

		ResetHelpers()
	End Method

	Method ResetHelpers:Void()
		_halfWidth = frameWidth * .5
		_halfHeight = frameHeight * .5
		origin.Make(_halfWidth, _halfHeight)

		If (_pixels <> Null) Then
			frames = _pixels.Frames()
		Else
			frames = 1
		End If

		_curIndex = 0
		_mixedColor.SetARGB(FlxG.WHITE)
	End Method

Private
	Method _UpdateAnimation:Void()
		If (_bakedRotation > 0) Then
			Local oldIndex:Int = _curIndex
			Local angleHelper:Int = angle Mod 360

			If (angleHelper < 0) angleHelper += 360
			_curIndex = angleHelper / _bakedRotation + 0.5

			If (oldIndex <> _curIndex) _CalcFrame()
			Return
		End If

		If (_paused) Return

		If (_curAnim <> Null And _curAnim.delay > 0 And (_curAnim.looped Or Not finished))
			_frameTimer += FlxG.Elapsed
			While (_frameTimer > _curAnim.delay)
				_frameTimer -= _curAnim.delay

				If (_curFrame = _curAnim.frames.Length() - 1) Then
					If (_curAnim.looped) _curFrame = 0
					finished = True
				Else
					_curFrame += 1
				End If

				_curIndex = _curAnim.frames[_curFrame]
				dirty = True
			Wend
		End If

		If (dirty) _CalcFrame()
	End Method

	Method _CalcFrame:Void()
		If (_callback <> Null) Then
			If (_curAnim <> Null) Then
				_callback.OnAnimationFrame(_curAnim, _curFrame, _curIndex)
			Else
				_callback.OnAnimationFrame(Null, _curFrame, _curIndex)
			End If
		End If
		dirty = False
	End Method

End Class

Interface FlxSpriteRenderer

	Method OnSpriteBind:Void(sprite:FlxSprite)

	Method OnSpriteUnbind:Void()

	Method OnSpriteRender:Void(x:Float, y:Float)

End Interface

Class PrimitiveSpriteRenderer Implements FlxSpriteRenderer Abstract

	Method OnSpriteBind:Void(sprite:FlxSprite)
		_sprite = sprite
		_sprite.Pixels = Null
	End Method

	Method OnSpriteUnbind:Void()
		_sprite = Null
		_sprite.Pixels = Null
	End Method

	Method OnSpriteRender:Void(x:Float, y:Float) Abstract

	Private

	Field _sprite:FlxSprite

End Class

Class RectSpriteRenderer Extends PrimitiveSpriteRenderer

	Method OnSpriteRender:Void(x:Float, y:Float)
		DrawRect(x, y, _sprite.frameWidth, _sprite.frameHeight)
	End Method

End Class

Class OvalSpriteRenderer Extends PrimitiveSpriteRenderer

	Method OnSpriteRender:Void(x:Float, y:Float)
		DrawOval(x, y, _sprite.frameWidth, _sprite.frameHeight)
	End Method

End Class

Private
Class FlxGraphicLoader Extends FlxResourceLoader<Image>

	Field name:String
	Field animated:Bool
	Field width:Float
	Field height:Float

	Method Load:Image(name:String)
		Local image:Image = LoadImage(FlxAssetsManager.GetImagePath(Self.name))

		If (Not animated) Then
			Return image
		Else
			Local frames:Int

			If (width = 0 And height = 0) Then
				width = image.Height()
			ElseIf (width = 0) Then
				width = height
			ElseIf (height = 0) Then
				height = width
			End If

			If (height = 0) Then
				frames = Ceil(image.Width() / width)
				height = width
			Else
				frames = Ceil((image.Width() * image.Height()) / (width * height))
			End If

			Return image.GrabImage(0, 0, width, height, frames)
		End If
	End Method

End Class

Strict

Import mojo

Import flxextern
Import flxpoint
Import flxobject
Import flxcamera
Import flxg

Import system.flxanim
Import system.flxcolor

Import "data/default_flx.png"

Class FlxSprite Extends FlxObject

	Global ClassObject:Object

	Field origin:FlxPoint

	Field offset:FlxPoint

	Field scale:FlxPoint

	Field blend:Int

	Field finished:Bool

	Field frameWidth:Int

	Field frameHeight:Int

	Field frames:Int

	Field dirty:Bool

	Field _color:FlxColor

	Field _mixedColor:FlxColor

	Field _camera:FlxCamera

Private
	Global _GraphicLoader:FlxGraphicLoader = New FlxGraphicLoader()

	Global _Matrix:Float[6]

	Field _animations:StringMap<FlxAnim>

	Field _flipped:Bool

	Field _flipNeeded:Bool

	Field _curAnim:FlxAnim

	Field _curFrame:Int

	Field _curIndex:Int

	Field _frameTimer:Float

	Field _paused:Bool

	Field _callback:FlxAnimationListener

	Field _facing:Int

	Field _alpha:Float

	Field _bakedRotation:Float

	Field _pixels:Image

	Field _halfWidth:Float

	Field _halfHeight:Float

	Field _renderer:FlxSpriteRenderer

Public
	Method New(x:Float = 0, y:Float = 0, simpleGraphic:String = "")
		Super.New(x, y)

		offset = New FlxPoint()
		origin = New FlxPoint()

		scale = New FlxPoint(1.0, 1.0)
		_alpha = 1
		_color = New FlxColor(FlxG.WHITE)
		blend = AlphaBlend
		_cameras = Null

		finished = False
		_facing = RIGHT
		_animations = New StringMap<FlxAnim>
		_flipped = False
		_curAnim = Null
		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0
		_paused = False

		_callback = Null

		_mixedColor = New FlxColor(FlxG.WHITE)

		If (simpleGraphic.Length() = 0)
			simpleGraphic = "default" + FlxG.DATA_SUFFIX
		End If

		LoadGraphic(simpleGraphic)
	End Method

	Method Destroy:Void()
		If (_animations <> Null) Then
			_animations.Clear()
			_animations = Null
		End If

		offset = Null
		origin = Null
		scale = Null
		_curAnim = Null
		_callback = Null
		_color = Null
		_mixedColor = Null
		_camera = Null
		_renderer = Null

		Super.Destroy()
	End Method

	Method LoadGraphic:FlxSprite(graphic:String, animated:Bool = False, reverse:Bool = False, width:Int = 0, height:Int = 0, unique:Bool = False)
		_bakedRotation = 0

		_GraphicLoader.name = graphic
		_GraphicLoader.animated = animated
		_GraphicLoader.width = width
		_GraphicLoader.height = height

		_pixels = FlxG.AddBitmap(graphic, _GraphicLoader, unique)

		_flipped = reverse

		Self.width = _pixels.Width()
		frameWidth = Self.width

		Self.height = _pixels.Height()
		frameHeight = Self.height

		ResetHelpers()

		Return Self
	End Method

	Method LoadRotatedGraphic:FlxSprite(graphic:String, rotations:Int = 16, frame:Int = -1)
		Error "LoadRotatedGraphic not currenlty support in " + FlxG.LIBRARY_NAME
		'TODO
		Return Null
	End Method

	Method MakeGraphic:FlxSprite(width:Int, height:Int, color:Int = FlxG.WHITE, unique:Bool = False, key:String = "")
		_pixels = FlxG.CreateBitmap(width, height, color, unique, key)
		_bakedRotation = 0

		Self.width = width
		frameWidth = width
		Self.height = height
		frameHeight = height

		ResetHelpers()

		Return Self
	End Method

	Method PostUpdate:Void()
		Super.PostUpdate()
		_UpdateAnimation()
	End Method

	Method Draw:Void()
		If (_flickerTimer <> 0) Then
			_flicker = Not _flicker
			If (_flicker) Return
		End If

		_camera = FlxG._CurrentCamera

		If (_cameras <> Null And Not _cameras.Contains(_camera)) Return
		If (Not OnScreen(_camera)) Return

		If (dirty) _CalcFrame()

		If (FlxG._LastDrawingBlend <> blend) Then
			SetBlend(blend)
			FlxG._LastDrawingBlend = blend
		End If

		_point.x = x - int(_camera.scroll.x * scrollFactor.x) - offset.x
		_point.y = y - int(_camera.scroll.y * scrollFactor.y) - offset.y

		If (_point.x > 0) Then
			_point.x += 0.0000001
		Else
			_point.x -= 0.0000001
		End If

		If (_point.y > 0) Then
			_point.y += 0.0000001
		Else
			_point.y -= 0.0000001
		End If

		If (_camera.Color <> FlxG.WHITE) Then
			_mixedColor.MixRGB(_color, _camera._color)

			If (FlxG._LastDrawingColor <> _mixedColor.argb) Then
				SetColor(_mixedColor.r, _mixedColor.g, _mixedColor.b)
				FlxG._LastDrawingColor = _mixedColor.argb
			End If
		Else
			If (FlxG._LastDrawingColor <> _color.argb) Then
				SetColor(_color.r, _color.g, _color.b)
				FlxG._LastDrawingColor = _color.argb
			End If
		End If

		If (_camera.Alpha < 1) Then
			Local _mixedAlpha:Float = _camera.Alpha * _alpha

			If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
				SetAlpha(_mixedAlpha)
				FlxG._LastDrawingAlpha = _mixedAlpha
			End If
		Else
			If (FlxG._LastDrawingAlpha <> _alpha) Then
				SetAlpha(_alpha)
				FlxG._LastDrawingAlpha = _alpha
			End If
		End If

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			If ( Not _flipNeeded) Then
				If (_renderer = Null) Then
					DrawImage(_pixels, _point.x, _point.y, _curIndex)
				Else
					_renderer.OnSpriteRender(_point.x, _point.y)
				End If
			Else
				PushMatrix()
					Transform(-1, 0, 0, 1, _point.x + _halfWidth, _point.y + _halfHeight)

					If (_renderer = Null) Then
						DrawImage(_pixels, -_halfWidth, -_halfHeight, _curIndex)
					Else
						_renderer.OnSpriteRender(-_halfWidth, -_halfHeight)
					End If
				PopMatrix()
			End If
		Else
			PushMatrix()
				'Translate
				_Matrix[4] = _point.x + origin.x
				_Matrix[5] = _point.y + origin.y

				'Scale
				_Matrix[0] = scale.x
				_Matrix[3] = scale.y

				'Rotate
				If (angle <> 0 And _bakedRotation = 0) Then
					Local sin:Float = Sin(angle)
					Local cos:Float = Cos(angle)

					_Matrix[1] = sin * _Matrix[0]
					_Matrix[2] = -sin * _Matrix[3]
					_Matrix[0] *= cos
					_Matrix[3] *= cos
				Else
					_Matrix[1] = 0
					_Matrix[2] = 0
				End If

				Transform(_Matrix[0], _Matrix[1], _Matrix[2], _Matrix[3], _Matrix[4], _Matrix[5])

				If (_flipNeeded) Then
					Transform(-1, 0, 0, 1, _halfWidth - origin.x, _halfHeight - origin.y)
				End If

				If (_renderer = Null) Then
					DrawImage(_pixels, -origin.x, -origin.y, _curIndex)
				Else
					_renderer.OnSpriteRender(-origin.x, -origin.y)
				End If
			PopMatrix()
		End If

	#If FLX_DEBUG_ENABLED = "1"
		_VisibleCount += 1;
		If (FlxG.VisualDebug And Not ignoreDrawDebug) DrawDebug(_camera);
	#End
	End Method

	Method DrawFrame:Void(force:Bool = False)
		If (force Or dirty) _CalcFrame()
	End Method

	Method AddAnimation:FlxAnim(name:String, frames:Int[], frameRate:Float = 0, looped:Bool = True)
		Local anim:FlxAnim = New FlxAnim(name, frames, frameRate, looped)
		_animations.Set(name, anim)

		Return anim
	End Method

	Method AddAnimation:FlxAnim(name:String, startFrame:Int, endFrame:Int, frameRate:Float = 0, looped:Bool = True)
		Local i:Int = 0
		Local l:Int = endFrame - startFrame + 1
		Local frames:Int[] = New Int[l]

		While (i < l)
			frames[i] = startFrame + i
			i += 1
		Wend

		Return AddAnimation(name, frames, frameRate, looped)
	End Method

	Method AddAnimation:FlxAnim(name:String, frameRate:Float = 0, looped:Bool = True)
		If (_pixels = Null) Return Null
		Return AddAnimation(name, 0, _pixels.Frames() -1, frameRate, looped)
	End Method

	Method AddAnimationCallback:Void(animationCallback:FlxAnimationListener)
		_callback = animationCallback
	End Method

	Method ClearAnimationCallback:Void()
		_callback = Null
	End Method

	Method GetAnimation:FlxAnim(animName:String)
		Return _animations.Get(animName)
	End Method

	Method GetAnimation:FlxAnim()
		Return _curAnim
	End Method

	Method Play:Void(animName:String, force:Bool = False)
		If (Not force And _curAnim <> Null And animName = _curAnim.name And( _curAnim.looped Or Not finished )) Return

		_curFrame = 0
		_curIndex = 0
		_frameTimer = 0
		_paused = False

		Local anim:FlxAnim = _animations.Get(animName)

		If (anim <> Null) Then
			_curAnim = anim

			If (_curAnim.delay <= 0) Then
				finished = True
			Else
				finished = False
			End If

			_curIndex = _curAnim.frames[_curFrame]
			dirty = True
			Return
		End If

		#If FLX_DEBUG_ENABLED = "1"
			FlxG.Log("WARNING: No animation called ~q" + animName + "~q")
		#End
	End Method

	Method Stop:Void()
		Frame = 0
	End Method

	Method Pause:Void()
		_paused = True
	End Method

	Method Resume:Void()
		_paused = False
	End Method

	Method RandomFrame:Void()
		_curAnim = Null

		If (_pixels <> Null) Then
			_curIndex = Int(FlxG.Random() * (_pixels.Frames() - 1))
		Else
			_curIndex = 0
		End If

		dirty = True
	End Method

	Method SetOriginToCorner:Void()
		origin.x = 0
		origin.y = 0
	End Method

	Method CenterOffsets:Void(adjustPosition:Bool = False)
		offset.x = (frameWidth - width) * .5
		offset.y = (frameHeight - height) * .5

		If (adjustPosition) Then
			x += offset.x
			y += offset.y
		End If
	End Method

	Method Pixels:Image() Property
		Return _pixels
	End Method

	Method Pixels:Void(pixels:Image) Property
		_pixels = pixels

		Local width:Int = 0
		Local height:Int = 0

		If (_pixels <> Null) Then
			width = pixels.Width()
			height = pixels.Height()
		End If

		If (_pixels <> Null Or _renderer = Null) Then
			Self.width = width
			Self.height = height
			frameWidth = width
			frameHeight = height
			ResetHelpers()
		End If
	End Method

	Method Facing:Int() Property
		Return _facing
	End Method

	Method Facing:Void(direction:Int) Property
		If (_facing <> direction) dirty = True
		_facing = direction

		_flipNeeded = (_flipped And _facing = LEFT)
	End Method

	Method Alpha:Float() Property
		Return _alpha
	End Method

	Method Alpha:Void(alpha:Float) Property
		If (alpha < 0) alpha = 0
		_alpha = alpha
	End Method

	Method Color:Int() Property
		Return _color.argb
	End Method

	Method Color:Void(color:Int) Property
		_color.SetRGB(color)
	End Method

	Method Frame:Int() Property
		Return _curIndex
	End Method

	Method Frame:Void(frame:Int) Property
		_curAnim = Null
		_curIndex = frame
		_paused = False
		dirty = True
	End Method

	Method OnScreen:Bool(camera:FlxCamera = Null)
		If (camera = Null) camera = FlxG.Camera
		GetScreenXY(_point, camera)

		_point.x = _point.x - offset.x
		_point.y = _point.y - offset.y

		If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
			Return _point.x + frameWidth > 0 And _point.x < camera.Width And _point.y + frameHeight > 0 And _point.y < camera.Height
		End If

		Local radius:Float = Sqrt(_halfWidth * _halfWidth + _halfHeight * _halfHeight) * Max(Abs(scale.x), Abs(scale.y))
		_point.x += _halfWidth
		_point.y += _halfHeight

		Return _point.x + radius > 0 And _point.x - radius < camera.Width And _point.y + radius > 0 And _point.y - radius < camera.Height
	End Method

	Method SetRenderer:Void(render:FlxSpriteRenderer)
		_renderer = render
		_renderer.OnSpriteBind(Self)

		frameWidth = width
		frameHeight = height

		ResetHelpers()
	End Method

	Method ClearRenderer:Void()
		Local renderer:FlxSpriteRenderer = _renderer
		_renderer = Null
		renderer.OnSpriteUnbind()

		frameWidth = width
		frameHeight = height

		ResetHelpers()
	End Method

	Method ResetHelpers:Void()
		_halfWidth = frameWidth * .5
		_halfHeight = frameHeight * .5
		origin.Make(_halfWidth, _halfHeight)

		If (_pixels <> Null) Then
			frames = _pixels.Frames()
		Else
			frames = 1
		End If

		_curIndex = 0
		_mixedColor.SetARGB(FlxG.WHITE)
	End Method

Private
	Method _UpdateAnimation:Void()
		If (_bakedRotation > 0) Then
			Local oldIndex:Int = _curIndex
			Local angleHelper:Int = angle Mod 360

			If (angleHelper < 0) angleHelper += 360
			_curIndex = angleHelper / _bakedRotation + 0.5

			If (oldIndex <> _curIndex) _CalcFrame()
			Return
		End If

		If (_paused) Return

		If (_curAnim <> Null And _curAnim.delay > 0 And (_curAnim.looped Or Not finished))
			_frameTimer += FlxG.Elapsed
			While (_frameTimer > _curAnim.delay)
				_frameTimer -= _curAnim.delay

				If (_curFrame = _curAnim.frames.Length() - 1) Then
					If (_curAnim.looped) _curFrame = 0
					finished = True
				Else
					_curFrame += 1
				End If

				_curIndex = _curAnim.frames[_curFrame]
				dirty = True
			Wend
		End If

		If (dirty) _CalcFrame()
	End Method

	Method _CalcFrame:Void()
		If (_callback <> Null) Then
			If (_curAnim <> Null) Then
				_callback.OnAnimationFrame(_curAnim, _curFrame, _curIndex)
			Else
				_callback.OnAnimationFrame(Null, _curFrame, _curIndex)
			End If
		End If
		dirty = False
	End Method

End Class

Interface FlxSpriteRenderer

	Method OnSpriteBind:Void(sprite:FlxSprite)

	Method OnSpriteUnbind:Void()

	Method OnSpriteRender:Void(x:Float, y:Float)

End Interface

Private
Class FlxGraphicLoader Extends FlxResourceLoader<Image>

	Field name:String
	Field animated:Bool
	Field width:Float
	Field height:Float

	Method Load:Image(name:String)
		Local image:Image = LoadImage(FlxAssetsManager.GetImagePath(Self.name))

		If (Not animated) Then
			Return image
		Else
			Local frames:Int

			If (width = 0 And height = 0) Then
				width = image.Height()
			ElseIf (width = 0) Then
				width = height
			ElseIf (height = 0) Then
				height = width
			End If

			If (height = 0) Then
				frames = Ceil(image.Width() / width)
				height = width
			Else
				frames = Ceil((image.Width() * image.Height()) / (width * height))
			End If

			Return image.GrabImage(0, 0, width, height, frames)
		End If
	End Method

End Class