Added FlxG.Signals global field

Added FlxG.Signals global field

Strict

Import mojo
Import reflection

Import flxextern
Import flxbasic
Import flxgame
Import flxcamera
Import flxobject
Import flxsignals
Import flxsound
Import flxmusic
Import flxu

Import system.input.accel
Import system.input.joystick
Import system.input.keyboard
Import system.input.mouse
Import system.input.touch
Import system.tweens.flxtween
Import system.tweens.util.ease
Import system.tweens.misc.multivartween
Import system.resolutionpolicy.flxresolutionpolicy
Import system.resolutionpolicy.fill
Import system.flxresourcesmanager
Import system.flxquadtree
Import system.flxreplay
Import system.flximagedata

Import plugin.timermanager
Import plugin.debugpathdisplay

Alias AccelInput = accel.Accel
Alias MouseInput = mouse.Mouse
Alias TouchInput = touch.Touch
Alias JoystickInput = joystick.Joystick
Alias MojoDeviceWidth = mojo.graphics.DeviceWidth
Alias MojoDeviceHeight = mojo.graphics.DeviceHeight

Class FlxG

	Const LIBRARY_NAME:String = "Flixel for Monkey"

	Const LIBRARY_MAJOR_VERSION:Int = 1

	Const LIBRARY_MINOR_VERSION:Int = 0

	Const DATA_SUFFIX:String = "_flx"

	Const RED:Int = $FFFF0012

	Const GREEN:Int = $FF00F225

	Const BLUE:Int = $FF0090E9

	Const PINK:Int = $FFF01EFF

	Const WHITE:Int = $FFFFFFFF

	Const BLACK:Int = $FF000000

	Global Paused:Bool

#If FLX_DEBUG_ENABLED = "1"
	Global Debug:Bool = True
#Else
	Global Debug:Bool = False
#End

	Global Elapsed:Float

	Global TimeScale:Float

	Global DeviceWidth:Int

	Global DeviceHeight:Int

	Global Width:Int

	Global Height:Int

	Global WorldBounds:FlxRect

	Global WorldDivisions:Int

	Global VisualDebug:Bool

	Global Mobile:Bool

	Global GlobalSeed:Int

	Global Scores:Stack<Int>

	Global Score:Int

	Global Levels:Stack<Int>

	Global Level:Int

	Global Accel:AccelInput

	Global Keys:Keyboard

	Global Mouse:MouseInput

	Global Music:FlxMusic

	Global Sounds:FlxGroup

	Global Mute:Bool

	Global Cameras:Stack<FlxCamera>

	Global Camera:FlxCamera

	Global Plugins:Stack<FlxBasic>

	Global VolumeHandler:FlxVolumeChangeListener

	Global Updaterate:Int

	Global Tweener:FlxBasic

	Global Signals:FlxSignals

	Global _DeviceScaleFactorX:Float = 1

	Global _DeviceScaleFactorY:Float = 1

	Global _DeviceOffsetX:Int

	Global _DeviceOffsetY:Int

	Global _BgColor:FlxColor = FlxColor.ARGB(FlxG.BLACK)

	Global _Game:FlxGame

	Global _Volume:Float

	Global _BitmapCache:FlxResourcesManager<Image>

	Global _SoundCache:FlxResourcesManager<Sound>

	Global _LastDrawingColor:Int

	Global _LastDrawingAlpha:Float

	Global _LastDrawingBlend:Int

	Global _CurrentCamera:FlxCamera

Private
#If TARGET = "psm"
	Const _JOY_UNITS_COUNT:Int = 1
#Else
	Const _JOY_UNITS_COUNT:Int = 4
#End
	Const _TOUCH_COUNT:Int = 32

	Global _Joystick:JoystickInput[_JOY_UNITS_COUNT]

	Global _Touch:TouchInput[_TOUCH_COUNT]

	Global _CollideListener:FlxCollideProcessListener = New FlxCollideProcessListener()

	Global _ResolutionPolicy:FlxResolutionPolicy = New FillResolutionPolicy()

	Global _Point:FlxPoint = New FlxPoint()

Public
	Function GetLibraryName:String()
		Return FlxG.LIBRARY_NAME + " v" + FlxG.LIBRARY_MAJOR_VERSION + "." + FlxG.LIBRARY_MINOR_VERSION
	End Function

	Function Log:Void(data:String)
		Print data
		'TODO
	End Function

	Function Random:Float()
		FlxG.GlobalSeed = (FlxG.GlobalSeed * 1664525 + 1013904223)|0
		Return FlxU.Srand(FlxG.GlobalSeed)
	End Function

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

	Function LoadReplay:Void(data:String, state:FlxState = Null, cancelKeys:Int[] = [], timeout:Float = 0, callback:FlxReplayListener = Null)
		_Game._replay.Load(data)
		If (state = Null) Then
			FlxG.ResetGame()
		Else
			FlxG.SwitchState(state)
		End If

		_Game._replayCancelKeys = cancelKeys
		_Game._replayTimer = timeout * 1000
		_Game._replayCallback = callback
		_Game._replayRequested = True
	End Function

	Function ReloadReplay:Void(standardMode:Bool = True)
		If (standardMode) Then
			FlxG.ResetGame()
		Else
			FlxG.ResetState()
		End If

		If (_Game._replay.frameCount > 0) _Game._replayRequested = True
	End Function

	Function StopReplay:Void()
		_Game._replaying = False

	#If FLX_DEBUG_ENABLED = "1"
		If (_Game._debugger <> Null) Then
			'TODO
		End If
	#End

		ResetInput()
	End Function

	Function RecordReplay:Void(standardMode:Bool = True)
		If (standardMode) Then
			FlxG.ResetGame()
		Else
			FlxG.ResetState()
		End If

		_Game._recordingRequested = True
	End Function

	Function StopRecording:String()
		_Game._recording = False

	#If FLX_DEBUG_ENABLED = "1"
		If (_Game._debugger <> Null) Then
			'TODO
		End If
	#End

		Return _Game._replay.Save()
	End Function

	Function ResetState:Void()
		_Game._requestedState = FlxState(_Game._state.GetClassInfo().NewInstance())
	End Function

	Function ResetGame:Void()
		_Game._requestedReset = True
	End Function

	Function ResetInput:Void()
		For Local i:Int = 0 Until _JOY_UNITS_COUNT
			_Joystick[i].Reset()
		Next

		For Local i:Int = 0 Until _TOUCH_COUNT
			_Touch[i].Reset()
		Next

		Accel.Reset()
		Mouse.Reset()

	#If TARGET <> "android" And TARGET <> "psm"
		Keys.Reset()
	#Else
		Keys.Reset(KEY_BACKSPACE, KEY_QUOTES)
	#End
	End Function

	Function PlayMusic:Void(music:String, volume:Float = 1.0)
		If (FlxG.Music = Null) Then
			FlxG.Music = New FlxMusic()

		ElseIf (FlxG.Music.active) Then
			FlxG.Music.Stop()
		End If

		FlxG.Music.Load(music, True)
		FlxG.Music.Volume = volume
		FlxG.Music.survive = True

		FlxG.Music.Play()
	End Function

	Function LoadSound:FlxSound(sound:String, volume:Float = 1.0, looped:Bool = False, autoDestroy:Bool = False, autoPlay:Bool = False, stopPrevious:Bool = True)
		Local s:FlxSound = FlxSound(Sounds.Recycle(ClassInfo(FlxSound.ClassObject)))

		s.Load(sound, looped, autoDestroy, stopPrevious)
		s.Volume = volume
		If (autoPlay) s.Play()

		Return s
	End Function

	Function Play:FlxSound(sound:String, volume:Float = 1.0, looped:Bool = False, autoDestroy:Bool = True)
		Local s:FlxSound = FlxG.LoadSound(sound, volume, looped, autoDestroy, True, False)
		If (Not looped) s.exists = False
		Return s
	End Function

	Function Volume:Float()
		Return _Volume
	End Function

	Function Volume:Void(volume:Float)
		_Volume = volume

		If (_Volume < 0) Then
			_Volume = 0
		ElseIf (_Volume > 1) Then
			_Volume = 1
		End If

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

		If (Music <> Null And Music.active) Then
			Music._UpdateTransform()
		End If

		For Local basic:FlxBasic = EachIn Sounds
			FlxSound(basic)._UpdateTransform()
		Next
	End Function

	Function DestroySounds:Void(forceDestroy:Bool = False)
		If (Music <> Null And (forceDestroy Or Not Music.survive)) Then
			Music.Destroy()
			Music = Null
		End If

		Local sound:FlxSound

		For Local basic:FlxBasic = EachIn Sounds
			sound = FlxSound(basic)

			If (sound <> Null And (forceDestroy Or Not sound.survive)) Then
				sound.Destroy()
			End If
		Next
	End Function

	Function UpdateSounds:Void()
		If (Music <> Null And Music.active) Then
			Music.Update()
		End If

		If (Sounds <> Null And Sounds.active) Then
			Sounds.Update()
		End If
	End Function

	Function PauseSounds:Void()
		If (Music <> Null And Music.exists And Music.active) Then
			Music.Pause()
		End If

		Local sound:FlxSound

		For Local basic:FlxBasic = EachIn Sounds
			sound = FlxSound(basic)

			If (sound <> Null And sound.exists And sound.active) Then
				sound.Pause()
			End If
		Next
	End Function

	Function ResumeSounds:Void()
		If (Music <> Null And Music.exists) Then
			Music.Play()
		End If

		Local sound:FlxSound

		For Local basic:FlxBasic = EachIn Sounds
			sound = FlxSound(basic)

			If (sound <> Null And sound.exists) Then
				sound.Resume()
			End If
		Next
	End Function

	Function CheckBitmapCache:Bool(key:String)
		Return _BitmapCache.CheckResource(key)
	End Function

	Function CreateBitmap:Image(width:Int, height:Int, color:Int, unigue:Bool, key:String = "")
		If (key.Length() = 0) Then
			key = width + "x" + height + ":" + color

			If (unigue And CheckBitmapCache(key)) Then
				Local inc:Int = 0
				Local ukey:String

				Repeat
					ukey = key + inc
					inc += 1
				Until (CheckBitmapCache(ukey))

				key = ukey
			End If
		End If

		If ( Not CheckBitmapCache(key)) Then
			_BitmapCache.Resources.Set(key, (New FlxImageData(width, height, False, color)).Image)
		End If

		Return _BitmapCache.Resources.Get(key)
	End Function

	Function AddBitmap:Image(graphic:String, graphicLoader:FlxResourceLoader<Image>, unique:Bool = False, key:String = "")
		If (key.Length() = 0) Then
			key = graphic

			If (unique And CheckBitmapCache(key)) Then
				Local inc:Int = 0
				Local ukey:String

				Repeat
					ukey = key + inc
					inc += 1
				Until(CheckBitmapCache(ukey))

				key = ukey
			End If
		End If

		Return _BitmapCache.GetResource(key, graphicLoader)
	End Function

	Function RemoveBitmap:Void(graphic:String)
		If (_BitmapCache <> Null) Then
			Local image:Image = _BitmapCache.Resources.Get(graphic)
			If (image <> Null) Then
				image.Discard()
				_BitmapCache.RemoveResource(graphic)
			End If
		End If
	End Function

	Function ClearBitmapCache:Void()
		If (_BitmapCache = Null) _BitmapCache = New FlxResourcesManager<Image>()

		For Local image:Image = EachIn _BitmapCache.Resources.Values()
			If (image <> Null) image.Discard()
		Next

		_BitmapCache.Clear()
	End Function

	Function AddSound:Sound(sound:String, soundLoader:FlxResourceLoader<Sound>)
		Return _SoundCache.GetResource(sound, soundLoader)
	End Function

	Function ClearSoundCache:Void()
		If (_SoundCache = Null) _SoundCache = New FlxResourcesManager<Sound>()

		For Local sound:Sound = EachIn _SoundCache.Resources.Values()
			If (sound <> Null) sound.Discard()
		Next

		_SoundCache.Clear()
	End Function

	Function State:FlxState()
		Return _Game._state
	End Function

	Function SwitchState:Void(state:FlxState)
		FlxG._Game._requestedState = state
	End Function

	Function AddCamera:FlxCamera(newCamera:FlxCamera)
		FlxG.Cameras.Push(newCamera)
		Return newCamera
	End Function

	Function RemoveCamera:Void(camera:FlxCamera, destroy:Bool = True)
		FlxG.Cameras.RemoveEach(camera)
		If (destroy) camera.Destroy()
	End Function

	Function ResetCameras:Void(newCamera:FlxCamera = Null)
		Local cam:FlxCamera
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			cam = FlxG.Cameras.Get(i)
			cam.Destroy()
			i+=1
		Wend

		FlxG.Cameras.Clear()
		FlxG.Camera = Null

		If (newCamera = Null) newCamera = New FlxCamera(0, 0, FlxG.Width, FlxG.Height)

		FlxG.Camera = FlxG.AddCamera(newCamera)
	End Function

	Function Flash:Void(color:Int = FlxG.WHITE, duration:Float = 1, onComplete:FlxCameraFlashListener = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).Flash(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Fade:Void(color:Int = FlxG.BLACK, duration:Float = 1, onComplete:FlxCameraFadeListener = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).Fade(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Shake:Void(intensity:Float = 0.05, duration:Float = 0.5, onComplete:FlxCameraShakeListener = Null, force:Bool = True, direction:Int = FlxCamera.SHAKE_BOTH_AXES)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).Shake(intensity, duration, onComplete, force, direction)
			i+=1
		Wend
	End Function

	Function BgColor:Int()
		If (FlxG.Camera = Null Or Not FlxG.Camera.alive) Return FlxG._BgColor.argb
		Return FlxG.Camera.BgColor
	End Function

	Function SetBgColor:Void(color:Int)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).BgColor = color
			i+=1
		Wend

		FlxG._BgColor.SetARGB(color)
	End Function

	Function Overlap:Bool(objectOrGroup1:FlxBasic = Null, objectOrGroup2:FlxBasic, notifyCallback:FlxOverlapNotifyListener = Null, processCallback:FlxOverlapProcessListener = Null)
		If (objectOrGroup1 = Null) objectOrGroup1 = FlxG.State()
		If (objectOrGroup2 = objectOrGroup1) objectOrGroup2 = Null

		FlxQuadTree.Divisions = FlxG.WorldDivisions

		Local quadTree:FlxQuadTree = FlxQuadTree.Recycle(FlxG.WorldBounds.x, FlxG.WorldBounds.y, FlxG.WorldBounds.width, FlxG.WorldBounds.height)
		quadTree.Load(objectOrGroup1, objectOrGroup2, notifyCallback, processCallback)

		Local result:Bool = quadTree.Execute()
		quadTree.Destroy()

		Return result
	End Function

	Function Collide:Bool(objectOrGroup1:FlxBasic = Null, objectOrGroup2:FlxBasic = Null, notifyCallback:FlxOverlapNotifyListener = Null)
		Return	Overlap(objectOrGroup1, objectOrGroup2, notifyCallback, _CollideListener)
	End Function

	Function AddPlugin:FlxBasic(plugin:FlxBasic)
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			If (pluginList.Get(i).ToString() = plugin.ToString()) Then
				Return plugin
			End If

			i+=1
		Wend

		pluginList.Push(plugin)
		Return plugin
	End Function

	Function GetPlugin:FlxBasic(objectClass:ClassInfo)
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local plugin:FlxBasic
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.GetClassInfo().ExtendsClass(objectClass)) Return plugin

			i+=1
		Wend

		Return Null
	End Function

	Function RemovePlugin:FlxBasic(plugin:FlxBasic)
		Plugins.RemoveEach(plugin)
		Return plugin
	End Function

	Function RemovePluginType:Bool(objectClass:ClassInfo)
		Local results:Bool = False
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = pluginList.Length() - 1

		While(i >= 0)
			If (pluginList.Get(i).GetClassInfo().ExtendsClass(objectClass)) Then
				pluginList.Remove(i)
				results = True
			End If

			i-=1
		Wend

		Return results
	End Function

	Function Init:Void(game:FlxGame, width:Int, height:Int, zoom:Float)
		FlxG._Game = game
		FlxG.Width = width
		FlxG.Height = height

		FlxG.Tweener = New FlxBasic()
		FlxG.Signals = New FlxSignals()

		FlxG.Mute = False
		FlxG._Volume = .5
		FlxG.Sounds = New FlxGroup()
		FlxG.VolumeHandler = Null

		FlxG.ClearBitmapCache()

		FlxCamera.DefaultZoom = zoom
		FlxG.Cameras = New Stack<FlxCamera>()

		Plugins = New Stack<FlxBasic>

	#If FLX_DEBUG_ENABLED = "1"
		AddPlugin(New DebugPathDisplay())
	#End
		AddPlugin(New TimerManager())

		FlxG.Accel = New AccelInput()
		FlxG.Keys = New Keyboard()
		FlxG.Mouse = New MouseInput()

		For Local i:Int = 0 Until _JOY_UNITS_COUNT
			_Joystick[i] = New JoystickInput(i)
		Next

		For Local i:Int = 0 Until _TOUCH_COUNT
			_Touch[i] = New TouchInput(i)
		Next

		FlxG.Mobile = IsMobile()

		FlxG.Scores = New Stack<Int>()
		FlxG.Levels = New Stack<Int>()
		FlxG.VisualDebug = False
	End Function

	Function Reset:Void()
		FlxG.ClearBitmapCache()
		FlxG.DestroySounds(True)
		FlxG.ClearSoundCache()
		FlxG.ResetInput()
		FlxG.DestroySignals()
		FlxG.Levels.Clear()
		FlxG.Scores.Clear()
		FlxG.Level = 0
		FlxG.Score = 0
		FlxG.TimeScale = 1
		FlxG.Elapsed = 0
		FlxG.GlobalSeed = Rnd(1, 10000000)
		FlxG.WorldBounds = New FlxRect(-10, -10, FlxG.Width + 20, FlxG.Height + 20)
		FlxG.WorldDivisions = 6

	#If FLX_DEBUG_ENABLED = "1"
		Local debugPathDisplay:DebugPathDisplay = DebugPathDisplay(FlxG.GetPlugin(ClassInfo(DebugPathDisplay.ClassObject)))
		If (debugPathDisplay <> Null) debugPathDisplay.Clear()
	#End
	End Function

	Function UpdateInput:Void()
	#If TARGET = "html5" Or TARGET = "ios" Or TARGET = "android" Or TARGET = "psm" Or TARGET = "win8"
		Accel.Update(AccelX(), AccelY(), AccelZ())
	#End

	#If TARGET = "glfw" Or TARGET = "psm" Or TARGET = "bmax"
		For Local i:Int = 0 Until _JOY_UNITS_COUNT
			_Joystick[i].Update()
		Next
	#End

	#If TARGET = "xna"
		If (Not FlxG.Mobile) Then
			For Local i:Int = 0 Until _JOY_UNITS_COUNT
				_Joystick[i].Update()
			Next
		Else
			Accel.Update(AccelX(), AccelY(), AccelZ())
		End If
	#End

	#If TARGET = "ios" Or TARGET = "android" Or TARGET = "psm" Or TARGET = "win8"
		For Local i:Int = 0 Until _TOUCH_COUNT
			_Touch[i].Update(TouchX(i), TouchY(i))

			If (i > 0 And Not _Touch[i].Used) Exit
		Next

	#ElseIf TARGET = "html5" Or TARGET = "flash"
		If (Not FlxG.Mobile) Then
			Keys.Update()
		End If

		_Touch[0].Update(TouchX(), TouchY())

	#ElseIf TARGET = "xna"
		If (Not FlxG.Mobile) Then
			Keys.Update()
			_Touch[0].Update(TouchX(), TouchY())
		Else
			For Local i:Int = 0 Until _TOUCH_COUNT
				_Touch[i].Update(TouchX(i), TouchY(i))

				If (i > 0 And Not _Touch[i].Used) Exit
			Next
		End If

	#Else
		Keys.Update()
		_Touch[0].Update(TouchX(), TouchY())
	#End

	#If TARGET = "android" Or TARGET = "psm"
		Keys.Update()
	#End

	#If FLX_DEBUG_ENABLED = "1"
		If (Not _Game._debuggerUp Or Not _Game._debugger.hasMouse) Then
			Mouse.Update(MouseX(), MouseY())
		End If
	#Else
		Mouse.Update(MouseX(), MouseY())
	#End
	End Function

	Function UpdateCameras:Void()
		Local cam:FlxCamera
		Local cams:Stack<FlxCamera> = FlxG.Cameras
		Local i:Int = 0
		Local l:Int = cams.Length()

		While(i < l)
			cam = cams.Get(i)
			If (cam <> Null And cam.exists And cam.active) cam.Update()
			i+=1
		Wend
	End Function

	Function UpdatePlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.active) plugin.Update()
			i+=1
		Wend
	End Function

	Function DrawPlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.visible) plugin.Draw()
			i+=1
		Wend
	End Function

	Function Joystick:JoystickInput(unit:Int = 0)
		Return _Joystick[unit]
	End Function

	Function Touch:TouchInput(index:Int = 0)
		Return _Touch[index]
	End Function

	Function JoystickCount:Int()
		Return _JOY_UNITS_COUNT
	End Function

	Function TouchCount:Int()
		Return _TOUCH_COUNT
	End Function

	Function SetResolutionPolicy:Void(resolutionPolicy:FlxResolutionPolicy)
		_ResolutionPolicy = resolutionPolicy
		_Measure()
	End Function

	Function UpdateDevice:Void()
		If(FlxG.DeviceWidth <> MojoDeviceWidth() Or FlxG.DeviceHeight <> MojoDeviceHeight()) Then
			_Measure()
		End If
	End Function

	Function Tween:MultiVarTween(object:Object, values:StringMap<Float>, duration:Float, type:Int = FlxTween.ONESHOT, complete:FlxTweenListener = Null, ease:FlxEaseFunction = Null, tweener:FlxBasic = Null)
		If (tweener = Null) Then
			If (FlxBasic(object) <> Null) Then
				tweener = FlxBasic(object)
			Else
				tweener = FlxG.Tweener
			End If
		End If

		Local tween:MultiVarTween = New MultiVarTween(complete, type)
		tween.Tween(object, values, duration, ease)
		tweener.AddTween(tween)

		Return tween
	End Function

	Function DestroySignals:Void()
		FlxG.Signals.Destroy()
		FlxG.Signals = Null
	End Function

Private
	Function _Measure:Void()
		FlxG.DeviceWidth = MojoDeviceWidth()
		FlxG.DeviceHeight = MojoDeviceHeight()

		_ResolutionPolicy.OnMeasure(FlxG.DeviceWidth, FlxG.DeviceHeight, _Point)

		FlxG._DeviceScaleFactorX = _Point.x / Float(FlxG.Width)
		FlxG._DeviceScaleFactorY = _Point.y / Float(FlxG.Height)

		Local zoom:Float = FlxCamera.DefaultZoom
		If(FlxG.Camera <> Null) zoom = FlxG.Camera.Zoom

		FlxG._DeviceOffsetX = Ceil( (FlxG.DeviceWidth - _Point.x * zoom) * 0.5)
		FlxG._DeviceOffsetY = Ceil( (FlxG.DeviceHeight - _Point.y * zoom) * 0.5)

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

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

			'recalc values
			cam.X = cam.X
			cam.Y = cam.Y
			cam.Width = cam.Width
			cam.Height = cam.Height

			i += 1
		Wend
	End Function

End Class

Private
Class FlxCollideProcessListener Implements FlxOverlapProcessListener

	Method OnOverlapProcess:Bool(object1:FlxObject, object2:FlxObject)
		Return FlxObject.Separate(object1, object2)
	End Method

End Class

Strict

Import mojo
Import reflection

Import flxextern
Import flxbasic
Import flxgame
Import flxcamera
Import flxobject
Import flxsound
Import flxmusic
Import flxu

Import system.input.accel
Import system.input.joystick
Import system.input.keyboard
Import system.input.mouse
Import system.input.touch
Import system.tweens.flxtween
Import system.tweens.util.ease
Import system.tweens.misc.multivartween
Import system.resolutionpolicy.flxresolutionpolicy
Import system.resolutionpolicy.fill
Import system.flxresourcesmanager
Import system.flxquadtree
Import system.flxreplay
Import system.flximagedata

Import plugin.timermanager
Import plugin.debugpathdisplay

Alias AccelInput = accel.Accel
Alias MouseInput = mouse.Mouse
Alias TouchInput = touch.Touch
Alias JoystickInput = joystick.Joystick
Alias MojoDeviceWidth = mojo.graphics.DeviceWidth
Alias MojoDeviceHeight = mojo.graphics.DeviceHeight

Class FlxG

	Const LIBRARY_NAME:String = "Flixel for Monkey"

	Const LIBRARY_MAJOR_VERSION:Int = 1

	Const LIBRARY_MINOR_VERSION:Int = 0

	Const DATA_SUFFIX:String = "_flx"

	Const RED:Int = $FFFF0012

	Const GREEN:Int = $FF00F225

	Const BLUE:Int = $FF0090E9

	Const PINK:Int = $FFF01EFF

	Const WHITE:Int = $FFFFFFFF

	Const BLACK:Int = $FF000000

	Global Paused:Bool

#If FLX_DEBUG_ENABLED = "1"
	Global Debug:Bool = True
#Else
	Global Debug:Bool = False
#End

	Global Elapsed:Float

	Global TimeScale:Float

	Global DeviceWidth:Int

	Global DeviceHeight:Int

	Global Width:Int

	Global Height:Int

	Global WorldBounds:FlxRect

	Global WorldDivisions:Int

	Global VisualDebug:Bool

	Global Mobile:Bool

	Global GlobalSeed:Int

	Global Scores:Stack<Int>

	Global Score:Int

	Global Levels:Stack<Int>

	Global Level:Int

	Global Accel:AccelInput

	Global Keys:Keyboard

	Global Mouse:MouseInput

	Global Music:FlxMusic

	Global Sounds:FlxGroup

	Global Mute:Bool

	Global Cameras:Stack<FlxCamera>

	Global Camera:FlxCamera

	Global Plugins:Stack<FlxBasic>

	Global VolumeHandler:FlxVolumeChangeListener

	Global Updaterate:Int

	Global Tweener:FlxBasic

	Global _DeviceScaleFactorX:Float = 1

	Global _DeviceScaleFactorY:Float = 1

	Global _DeviceOffsetX:Int

	Global _DeviceOffsetY:Int

	Global _BgColor:FlxColor = FlxColor.ARGB(FlxG.BLACK)

	Global _Game:FlxGame

	Global _Volume:Float

	Global _BitmapCache:FlxResourcesManager<Image>

	Global _SoundCache:FlxResourcesManager<Sound>

	Global _LastDrawingColor:Int

	Global _LastDrawingAlpha:Float

	Global _LastDrawingBlend:Int

	Global _CurrentCamera:FlxCamera

Private
#If TARGET = "psm"
	Const _JOY_UNITS_COUNT:Int = 1
#Else
	Const _JOY_UNITS_COUNT:Int = 4
#End
	Const _TOUCH_COUNT:Int = 32

	Global _Joystick:JoystickInput[_JOY_UNITS_COUNT]

	Global _Touch:TouchInput[_TOUCH_COUNT]

	Global _CollideListener:FlxCollideProcessListener = New FlxCollideProcessListener()

	Global _ResolutionPolicy:FlxResolutionPolicy = New FillResolutionPolicy()

	Global _Point:FlxPoint = New FlxPoint()

Public
	Function GetLibraryName:String()
		Return FlxG.LIBRARY_NAME + " v" + FlxG.LIBRARY_MAJOR_VERSION + "." + FlxG.LIBRARY_MINOR_VERSION
	End Function

	Function Log:Void(data:String)
		Print data
		'TODO
	End Function

	Function Random:Float()
		FlxG.GlobalSeed = (FlxG.GlobalSeed * 1664525 + 1013904223)|0
		Return FlxU.Srand(FlxG.GlobalSeed)
	End Function

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

	Function LoadReplay:Void(data:String, state:FlxState = Null, cancelKeys:Int[] = [], timeout:Float = 0, callback:FlxReplayListener = Null)
		_Game._replay.Load(data)
		If (state = Null) Then
			FlxG.ResetGame()
		Else
			FlxG.SwitchState(state)
		End If

		_Game._replayCancelKeys = cancelKeys
		_Game._replayTimer = timeout * 1000
		_Game._replayCallback = callback
		_Game._replayRequested = True
	End Function

	Function ReloadReplay:Void(standardMode:Bool = True)
		If (standardMode) Then
			FlxG.ResetGame()
		Else
			FlxG.ResetState()
		End If

		If (_Game._replay.frameCount > 0) _Game._replayRequested = True
	End Function

	Function StopReplay:Void()
		_Game._replaying = False

	#If FLX_DEBUG_ENABLED = "1"
		If (_Game._debugger <> Null) Then
			'TODO
		End If
	#End

		ResetInput()
	End Function

	Function RecordReplay:Void(standardMode:Bool = True)
		If (standardMode) Then
			FlxG.ResetGame()
		Else
			FlxG.ResetState()
		End If

		_Game._recordingRequested = True
	End Function

	Function StopRecording:String()
		_Game._recording = False

	#If FLX_DEBUG_ENABLED = "1"
		If (_Game._debugger <> Null) Then
			'TODO
		End If
	#End

		Return _Game._replay.Save()
	End Function

	Function ResetState:Void()
		_Game._requestedState = FlxState(_Game._state.GetClassInfo().NewInstance())
	End Function

	Function ResetGame:Void()
		_Game._requestedReset = True
	End Function

	Function ResetInput:Void()
		For Local i:Int = 0 Until _JOY_UNITS_COUNT
			_Joystick[i].Reset()
		Next

		For Local i:Int = 0 Until _TOUCH_COUNT
			_Touch[i].Reset()
		Next

		Accel.Reset()
		Mouse.Reset()

	#If TARGET <> "android" And TARGET <> "psm"
		Keys.Reset()
	#Else
		Keys.Reset(KEY_BACKSPACE, KEY_QUOTES)
	#End
	End Function

	Function PlayMusic:Void(music:String, volume:Float = 1.0)
		If (FlxG.Music = Null) Then
			FlxG.Music = New FlxMusic()

		ElseIf (FlxG.Music.active) Then
			FlxG.Music.Stop()
		End If

		FlxG.Music.Load(music, True)
		FlxG.Music.Volume = volume
		FlxG.Music.survive = True

		FlxG.Music.Play()
	End Function

	Function LoadSound:FlxSound(sound:String, volume:Float = 1.0, looped:Bool = False, autoDestroy:Bool = False, autoPlay:Bool = False, stopPrevious:Bool = True)
		Local s:FlxSound = FlxSound(Sounds.Recycle(ClassInfo(FlxSound.ClassObject)))

		s.Load(sound, looped, autoDestroy, stopPrevious)
		s.Volume = volume
		If (autoPlay) s.Play()

		Return s
	End Function

	Function Play:FlxSound(sound:String, volume:Float = 1.0, looped:Bool = False, autoDestroy:Bool = True)
		Local s:FlxSound = FlxG.LoadSound(sound, volume, looped, autoDestroy, True, False)
		If (Not looped) s.exists = False
		Return s
	End Function

	Function Volume:Float()
		Return _Volume
	End Function

	Function Volume:Void(volume:Float)
		_Volume = volume

		If (_Volume < 0) Then
			_Volume = 0
		ElseIf (_Volume > 1) Then
			_Volume = 1
		End If

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

		If (Music <> Null And Music.active) Then
			Music._UpdateTransform()
		End If

		For Local basic:FlxBasic = EachIn Sounds
			FlxSound(basic)._UpdateTransform()
		Next
	End Function

	Function DestroySounds:Void(forceDestroy:Bool = False)
		If (Music <> Null And (forceDestroy Or Not Music.survive)) Then
			Music.Destroy()
			Music = Null
		End If

		Local sound:FlxSound

		For Local basic:FlxBasic = EachIn Sounds
			sound = FlxSound(basic)

			If (sound <> Null And (forceDestroy Or Not sound.survive)) Then
				sound.Destroy()
			End If
		Next
	End Function

	Function UpdateSounds:Void()
		If (Music <> Null And Music.active) Then
			Music.Update()
		End If

		If (Sounds <> Null And Sounds.active) Then
			Sounds.Update()
		End If
	End Function

	Function PauseSounds:Void()
		If (Music <> Null And Music.exists And Music.active) Then
			Music.Pause()
		End If

		Local sound:FlxSound

		For Local basic:FlxBasic = EachIn Sounds
			sound = FlxSound(basic)

			If (sound <> Null And sound.exists And sound.active) Then
				sound.Pause()
			End If
		Next
	End Function

	Function ResumeSounds:Void()
		If (Music <> Null And Music.exists) Then
			Music.Play()
		End If

		Local sound:FlxSound

		For Local basic:FlxBasic = EachIn Sounds
			sound = FlxSound(basic)

			If (sound <> Null And sound.exists) Then
				sound.Resume()
			End If
		Next
	End Function

	Function CheckBitmapCache:Bool(key:String)
		Return _BitmapCache.CheckResource(key)
	End Function

	Function CreateBitmap:Image(width:Int, height:Int, color:Int, unigue:Bool, key:String = "")
		If (key.Length() = 0) Then
			key = width + "x" + height + ":" + color

			If (unigue And CheckBitmapCache(key)) Then
				Local inc:Int = 0
				Local ukey:String

				Repeat
					ukey = key + inc
					inc += 1
				Until (CheckBitmapCache(ukey))

				key = ukey
			End If
		End If

		If ( Not CheckBitmapCache(key)) Then
			_BitmapCache.Resources.Set(key, (New FlxImageData(width, height, False, color)).Image)
		End If

		Return _BitmapCache.Resources.Get(key)
	End Function

	Function AddBitmap:Image(graphic:String, graphicLoader:FlxResourceLoader<Image>, unique:Bool = False, key:String = "")
		If (key.Length() = 0) Then
			key = graphic

			If (unique And CheckBitmapCache(key)) Then
				Local inc:Int = 0
				Local ukey:String

				Repeat
					ukey = key + inc
					inc += 1
				Until(CheckBitmapCache(ukey))

				key = ukey
			End If
		End If

		Return _BitmapCache.GetResource(key, graphicLoader)
	End Function

	Function RemoveBitmap:Void(graphic:String)
		If (_BitmapCache <> Null) Then
			Local image:Image = _BitmapCache.Resources.Get(graphic)
			If (image <> Null) Then
				image.Discard()
				_BitmapCache.RemoveResource(graphic)
			End If
		End If
	End Function

	Function ClearBitmapCache:Void()
		If (_BitmapCache = Null) _BitmapCache = New FlxResourcesManager<Image>()

		For Local image:Image = EachIn _BitmapCache.Resources.Values()
			If (image <> Null) image.Discard()
		Next

		_BitmapCache.Clear()
	End Function

	Function AddSound:Sound(sound:String, soundLoader:FlxResourceLoader<Sound>)
		Return _SoundCache.GetResource(sound, soundLoader)
	End Function

	Function ClearSoundCache:Void()
		If (_SoundCache = Null) _SoundCache = New FlxResourcesManager<Sound>()

		For Local sound:Sound = EachIn _SoundCache.Resources.Values()
			If (sound <> Null) sound.Discard()
		Next

		_SoundCache.Clear()
	End Function

	Function State:FlxState()
		Return _Game._state
	End Function

	Function SwitchState:Void(state:FlxState)
		FlxG._Game._requestedState = state
	End Function

	Function AddCamera:FlxCamera(newCamera:FlxCamera)
		FlxG.Cameras.Push(newCamera)
		Return newCamera
	End Function

	Function RemoveCamera:Void(camera:FlxCamera, destroy:Bool = True)
		FlxG.Cameras.RemoveEach(camera)
		If (destroy) camera.Destroy()
	End Function

	Function ResetCameras:Void(newCamera:FlxCamera = Null)
		Local cam:FlxCamera
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			cam = FlxG.Cameras.Get(i)
			cam.Destroy()
			i+=1
		Wend

		FlxG.Cameras.Clear()
		FlxG.Camera = Null

		If (newCamera = Null) newCamera = New FlxCamera(0, 0, FlxG.Width, FlxG.Height)

		FlxG.Camera = FlxG.AddCamera(newCamera)
	End Function

	Function Flash:Void(color:Int = FlxG.WHITE, duration:Float = 1, onComplete:FlxCameraFlashListener = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).Flash(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Fade:Void(color:Int = FlxG.BLACK, duration:Float = 1, onComplete:FlxCameraFadeListener = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).Fade(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Shake:Void(intensity:Float = 0.05, duration:Float = 0.5, onComplete:FlxCameraShakeListener = Null, force:Bool = True, direction:Int = FlxCamera.SHAKE_BOTH_AXES)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).Shake(intensity, duration, onComplete, force, direction)
			i+=1
		Wend
	End Function

	Function BgColor:Int()
		If (FlxG.Camera = Null Or Not FlxG.Camera.alive) Return FlxG._BgColor.argb
		Return FlxG.Camera.BgColor
	End Function

	Function SetBgColor:Void(color:Int)
		Local i:Int = 0
		Local l:Int = FlxG.Cameras.Length()

		While(i < l)
			FlxG.Cameras.Get(i).BgColor = color
			i+=1
		Wend

		FlxG._BgColor.SetARGB(color)
	End Function

	Function Overlap:Bool(objectOrGroup1:FlxBasic = Null, objectOrGroup2:FlxBasic, notifyCallback:FlxOverlapNotifyListener = Null, processCallback:FlxOverlapProcessListener = Null)
		If (objectOrGroup1 = Null) objectOrGroup1 = FlxG.State()
		If (objectOrGroup2 = objectOrGroup1) objectOrGroup2 = Null

		FlxQuadTree.Divisions = FlxG.WorldDivisions

		Local quadTree:FlxQuadTree = FlxQuadTree.Recycle(FlxG.WorldBounds.x, FlxG.WorldBounds.y, FlxG.WorldBounds.width, FlxG.WorldBounds.height)
		quadTree.Load(objectOrGroup1, objectOrGroup2, notifyCallback, processCallback)

		Local result:Bool = quadTree.Execute()
		quadTree.Destroy()

		Return result
	End Function

	Function Collide:Bool(objectOrGroup1:FlxBasic = Null, objectOrGroup2:FlxBasic = Null, notifyCallback:FlxOverlapNotifyListener = Null)
		Return	Overlap(objectOrGroup1, objectOrGroup2, notifyCallback, _CollideListener)
	End Function

	Function AddPlugin:FlxBasic(plugin:FlxBasic)
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			If (pluginList.Get(i).ToString() = plugin.ToString()) Then
				Return plugin
			End If

			i+=1
		Wend

		pluginList.Push(plugin)
		Return plugin
	End Function

	Function GetPlugin:FlxBasic(objectClass:ClassInfo)
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local plugin:FlxBasic
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.GetClassInfo().ExtendsClass(objectClass)) Return plugin

			i+=1
		Wend

		Return Null
	End Function

	Function RemovePlugin:FlxBasic(plugin:FlxBasic)
		Plugins.RemoveEach(plugin)
		Return plugin
	End Function

	Function RemovePluginType:Bool(objectClass:ClassInfo)
		Local results:Bool = False
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = pluginList.Length() - 1

		While(i >= 0)
			If (pluginList.Get(i).GetClassInfo().ExtendsClass(objectClass)) Then
				pluginList.Remove(i)
				results = True
			End If

			i-=1
		Wend

		Return results
	End Function

	Function Init:Void(game:FlxGame, width:Int, height:Int, zoom:Float)
		FlxG._Game = game
		FlxG.Width = width
		FlxG.Height = height

		FlxG.Tweener = New FlxBasic()

		FlxG.Mute = False
		FlxG._Volume = .5
		FlxG.Sounds = New FlxGroup()
		FlxG.VolumeHandler = Null

		FlxG.ClearBitmapCache()

		FlxCamera.DefaultZoom = zoom
		FlxG.Cameras = New Stack<FlxCamera>()

		Plugins = New Stack<FlxBasic>

	#If FLX_DEBUG_ENABLED = "1"
		AddPlugin(New DebugPathDisplay())
	#End
		AddPlugin(New TimerManager())

		FlxG.Accel = New AccelInput()
		FlxG.Keys = New Keyboard()
		FlxG.Mouse = New MouseInput()

		For Local i:Int = 0 Until _JOY_UNITS_COUNT
			_Joystick[i] = New JoystickInput(i)
		Next

		For Local i:Int = 0 Until _TOUCH_COUNT
			_Touch[i] = New TouchInput(i)
		Next

		FlxG.Mobile = IsMobile()

		FlxG.Scores = New Stack<Int>()
		FlxG.Levels = New Stack<Int>()
		FlxG.VisualDebug = False
	End Function

	Function Reset:Void()
		FlxG.ClearBitmapCache()
		FlxG.DestroySounds(True)
		FlxG.ClearSoundCache()
		FlxG.ResetInput()
		FlxG.Levels.Clear()
		FlxG.Scores.Clear()
		FlxG.Level = 0
		FlxG.Score = 0
		FlxG.TimeScale = 1
		FlxG.Elapsed = 0
		FlxG.GlobalSeed = Rnd(1, 10000000)
		FlxG.WorldBounds = New FlxRect(-10, -10, FlxG.Width + 20, FlxG.Height + 20)
		FlxG.WorldDivisions = 6

	#If FLX_DEBUG_ENABLED = "1"
		Local debugPathDisplay:DebugPathDisplay = DebugPathDisplay(FlxG.GetPlugin(ClassInfo(DebugPathDisplay.ClassObject)))
		If (debugPathDisplay <> Null) debugPathDisplay.Clear()
	#End
	End Function

	Function UpdateInput:Void()
	#If TARGET = "html5" Or TARGET = "ios" Or TARGET = "android" Or TARGET = "psm" Or TARGET = "win8"
		Accel.Update(AccelX(), AccelY(), AccelZ())
	#End

	#If TARGET = "glfw" Or TARGET = "psm" Or TARGET = "bmax"
		For Local i:Int = 0 Until _JOY_UNITS_COUNT
			_Joystick[i].Update()
		Next
	#End

	#If TARGET = "xna"
		If (Not FlxG.Mobile) Then
			For Local i:Int = 0 Until _JOY_UNITS_COUNT
				_Joystick[i].Update()
			Next
		Else
			Accel.Update(AccelX(), AccelY(), AccelZ())
		End If
	#End

	#If TARGET = "ios" Or TARGET = "android" Or TARGET = "psm" Or TARGET = "win8"
		For Local i:Int = 0 Until _TOUCH_COUNT
			_Touch[i].Update(TouchX(i), TouchY(i))

			If (i > 0 And Not _Touch[i].Used) Exit
		Next

	#ElseIf TARGET = "html5" Or TARGET = "flash"
		If (Not FlxG.Mobile) Then
			Keys.Update()
		End If

		_Touch[0].Update(TouchX(), TouchY())

	#ElseIf TARGET = "xna"
		If (Not FlxG.Mobile) Then
			Keys.Update()
			_Touch[0].Update(TouchX(), TouchY())
		Else
			For Local i:Int = 0 Until _TOUCH_COUNT
				_Touch[i].Update(TouchX(i), TouchY(i))

				If (i > 0 And Not _Touch[i].Used) Exit
			Next
		End If

	#Else
		Keys.Update()
		_Touch[0].Update(TouchX(), TouchY())
	#End

	#If TARGET = "android" Or TARGET = "psm"
		Keys.Update()
	#End

	#If FLX_DEBUG_ENABLED = "1"
		If (Not _Game._debuggerUp Or Not _Game._debugger.hasMouse) Then
			Mouse.Update(MouseX(), MouseY())
		End If
	#Else
		Mouse.Update(MouseX(), MouseY())
	#End
	End Function

	Function UpdateCameras:Void()
		Local cam:FlxCamera
		Local cams:Stack<FlxCamera> = FlxG.Cameras
		Local i:Int = 0
		Local l:Int = cams.Length()

		While(i < l)
			cam = cams.Get(i)
			If (cam <> Null And cam.exists And cam.active) cam.Update()
			i+=1
		Wend
	End Function

	Function UpdatePlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.active) plugin.Update()
			i+=1
		Wend
	End Function

	Function DrawPlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.Plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.visible) plugin.Draw()
			i+=1
		Wend
	End Function

	Function Joystick:JoystickInput(unit:Int = 0)
		Return _Joystick[unit]
	End Function

	Function Touch:TouchInput(index:Int = 0)
		Return _Touch[index]
	End Function

	Function JoystickCount:Int()
		Return _JOY_UNITS_COUNT
	End Function

	Function TouchCount:Int()
		Return _TOUCH_COUNT
	End Function

	Function SetResolutionPolicy:Void(resolutionPolicy:FlxResolutionPolicy)
		_ResolutionPolicy = resolutionPolicy
		_Measure()
	End Function

	Function UpdateDevice:Void()
		If(FlxG.DeviceWidth <> MojoDeviceWidth() Or FlxG.DeviceHeight <> MojoDeviceHeight()) Then
			_Measure()
		End If
	End Function

	Function Tween:MultiVarTween(object:Object, values:StringMap<Float>, duration:Float, type:Int = FlxTween.ONESHOT, complete:FlxTweenListener = Null, ease:FlxEaseFunction = Null, tweener:FlxBasic = Null)
		If (tweener = Null) Then
			If (FlxBasic(object) <> Null) Then
				tweener = FlxBasic(object)
			Else
				tweener = FlxG.Tweener
			End If
		End If

		Local tween:MultiVarTween = New MultiVarTween(complete, type)
		tween.Tween(object, values, duration, ease)
		tweener.AddTween(tween)

		Return tween
	End Function

Private
	Function _Measure:Void()
		FlxG.DeviceWidth = MojoDeviceWidth()
		FlxG.DeviceHeight = MojoDeviceHeight()

		_ResolutionPolicy.OnMeasure(FlxG.DeviceWidth, FlxG.DeviceHeight, _Point)

		FlxG._DeviceScaleFactorX = _Point.x / Float(FlxG.Width)
		FlxG._DeviceScaleFactorY = _Point.y / Float(FlxG.Height)

		Local zoom:Float = FlxCamera.DefaultZoom
		If(FlxG.Camera <> Null) zoom = FlxG.Camera.Zoom

		FlxG._DeviceOffsetX = Ceil( (FlxG.DeviceWidth - _Point.x * zoom) * 0.5)
		FlxG._DeviceOffsetY = Ceil( (FlxG.DeviceHeight - _Point.y * zoom) * 0.5)

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

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

			'recalc values
			cam.X = cam.X
			cam.Y = cam.Y
			cam.Width = cam.Width
			cam.Height = cam.Height

			i += 1
		Wend
	End Function

End Class

Private
Class FlxCollideProcessListener Implements FlxOverlapProcessListener

	Method OnOverlapProcess:Bool(object1:FlxObject, object2:FlxObject)
		Return FlxObject.Separate(object1, object2)
	End Method

End Class


fix Touch- & KeyEvent state after Scene.ClearChilds()

Strict

Private

Import bono

Public

Class Scene Implements Sceneable, Updateable, Suspendable Abstract
    Private

    Field childs:List<Object> = New List<Object>
    Field keyEventsEnabled:Bool
    Field keyEmitter:KeyEmitter
    Field keyhandlerFan:KeyhandlerFan
    Field touchEventsEnabled:Bool
    Field touchEmitter:TouchEmitter
    Field touchableFan:TouchableFan

    Public

    Method OnSceneEnter:Void()
    End

    Method OnSceneLeave:Void()
    End

    Method OnRender:Void()
        For Local obj:Object = EachIn childs
            If Renderable(obj) Then Renderable(obj).OnRender()
        End
    End

    Method OnUpdate:Void(timer:DeltaTimer)
        For Local obj:Object = EachIn childs
            If Updateable(obj) Then Updateable(obj).OnUpdate(timer)
        End
    End

    Method OnResume:Void()
        For Local obj:Object = EachIn childs
            If Suspendable(obj) Then Suspendable(obj).OnResume()
        End
    End

    Method OnSuspend:Void()
        For Local obj:Object = EachIn childs
            If Suspendable(obj) Then Suspendable(obj).OnSuspend()
        End
    End

    Method ClearChilds:Void()
        For Local child:Object = EachIn childs
            RemoveChild(child)
        End

        EnableTouchEvents(touchEventsEnabled)
        EnableKeyEvents(keyEventsEnabled)
    End

    Method AddChild:Void(child:Object)
        If Not childs.Contains(child) Then childs.AddLast(child)

        If keyhandlerFan And Keyhandler(child)
            GetKeyhandlerFan().Add(Keyhandler(child))
        End
        If touchableFan And Touchable(child)
            GetTouchableFan().Add(Touchable(child))
        End
    End

    Method RemoveChild:Void(child:Object)
        childs.RemoveEach(child)

        If keyhandlerFan And Keyhandler(child)
            GetKeyhandlerFan().Remove(Keyhandler(child))
        End
        If touchableFan And Touchable(child)
            GetTouchableFan().Remove(Touchable(child))
        End
    End

    Method GetDirector:Director()
        Return Director.Shared()
    End

    Method GetApp:App()
        Return GetDirector().GetApp()
    End

    Method EnableTouchEvents:Void(flag:Bool=True)
        If Not touchEmitter And Not flag Then Return

        If flag
            AddChild(GetTouchEmitter())
        Else
            RemoveChild(GetTouchEmitter())
        End
        touchEventsEnabled = flag
    End

    Method GetTouchEmitter:TouchEmitter()
        If Not touchEmitter
            touchEmitter = New TouchEmitter()
            touchEmitter.handler = GetTouchableFan()
        End

        Return touchEmitter
    End

    Method EnableKeyEvents:Void(flag:Bool=True)
        If Not keyEmitter And Not flag Then Return

        If flag
            AddChild(GetKeyEmitter())
        Else
            RemoveChild(GetKeyEmitter())
        End
        keyEventsEnabled = flag
    End

    Method GetKeyEmitter:KeyEmitter()
        If Not keyEmitter
            keyEmitter = New KeyEmitter()
            keyEmitter.handler = GetKeyhandlerFan()
        End

        Return keyEmitter
    End

    Private

    Method GetTouchableFan:TouchableFan()
        If Not touchableFan
            touchableFan = New TouchableFan()

            If Touchable(Self) Then touchableFan.Add(Touchable(Self))

            For Local obj:Object = EachIn childs
                If Not Touchable(obj) Then Continue
                touchableFan.Add(Touchable(obj))
            End
        End

        Return touchableFan
    End

    Method GetKeyhandlerFan:KeyhandlerFan()
        If Not keyhandlerFan
            keyhandlerFan = New KeyhandlerFan()

            If Keyhandler(Self) Then keyhandlerFan.Add(Keyhandler(Self))

            For Local obj:Object = EachIn childs
                If Not Keyhandler(obj) Then Continue
                keyhandlerFan.Add(Keyhandler(obj))
            End
        End

        Return keyhandlerFan
    End
End

Strict

Private

Import bono

Public

Class Scene Implements Sceneable, Updateable, Suspendable Abstract
    Private

    Field childs:List<Object> = New List<Object>
    Field keyEmitter:KeyEmitter
    Field keyhandlerFan:KeyhandlerFan
    Field touchEmitter:TouchEmitter
    Field touchableFan:TouchableFan

    Public

    Method OnSceneEnter:Void()
    End

    Method OnSceneLeave:Void()
    End

    Method OnRender:Void()
        For Local obj:Object = EachIn childs
            If Renderable(obj) Then Renderable(obj).OnRender()
        End
    End

    Method OnUpdate:Void(timer:DeltaTimer)
        For Local obj:Object = EachIn childs
            If Updateable(obj) Then Updateable(obj).OnUpdate(timer)
        End
    End

    Method OnResume:Void()
        For Local obj:Object = EachIn childs
            If Suspendable(obj) Then Suspendable(obj).OnResume()
        End
    End

    Method OnSuspend:Void()
        For Local obj:Object = EachIn childs
            If Suspendable(obj) Then Suspendable(obj).OnSuspend()
        End
    End

    Method ClearChilds:Void()
        For Local child:Object = EachIn childs
            RemoveChild(child)
        End

        If keyEmitter Then AddChild(keyEmitter)
        If touchEmitter Then AddChild(touchEmitter)
    End

    Method AddChild:Void(child:Object)
        If Not childs.Contains(child) Then childs.AddLast(child)

        If keyhandlerFan And Keyhandler(child)
            GetKeyhandlerFan().Add(Keyhandler(child))
        End
        If touchableFan And Touchable(child)
            GetTouchableFan().Add(Touchable(child))
        End
    End

    Method RemoveChild:Void(child:Object)
        childs.RemoveEach(child)

        If keyhandlerFan And Keyhandler(child)
            GetKeyhandlerFan().Remove(Keyhandler(child))
        End
        If touchableFan And Touchable(child)
            GetTouchableFan().Remove(Touchable(child))
        End
    End

    Method GetDirector:Director()
        Return Director.Shared()
    End

    Method GetApp:App()
        Return GetDirector().GetApp()
    End

    Method EnableTouchEvents:Void(flag:Bool=True)
        If Not touchEmitter And Not flag Then Return

        If flag
            AddChild(GetTouchEmitter())
        Else
            RemoveChild(GetTouchEmitter())
        End
    End

    Method GetTouchEmitter:TouchEmitter()
        If Not touchEmitter
            touchEmitter = New TouchEmitter()
            touchEmitter.handler = GetTouchableFan()
        End

        Return touchEmitter
    End

    Method EnableKeyEvents:Void(flag:Bool=True)
        If Not keyEmitter And Not flag Then Return

        If flag
            AddChild(GetKeyEmitter())
        Else
            RemoveChild(GetKeyEmitter())
        End
    End

    Method GetKeyEmitter:KeyEmitter()
        If Not keyEmitter
            keyEmitter = New KeyEmitter()
            keyEmitter.handler = GetKeyhandlerFan()
        End

        Return keyEmitter
    End

    Private

    Method GetTouchableFan:TouchableFan()
        If Not touchableFan
            touchableFan = New TouchableFan()

            If Touchable(Self) Then touchableFan.Add(Touchable(Self))

            For Local obj:Object = EachIn childs
                If Not Touchable(obj) Then Continue
                touchableFan.Add(Touchable(obj))
            End
        End

        Return touchableFan
    End

    Method GetKeyhandlerFan:KeyhandlerFan()
        If Not keyhandlerFan
            keyhandlerFan = New KeyhandlerFan()

            If Keyhandler(Self) Then keyhandlerFan.Add(Keyhandler(Self))

            For Local obj:Object = EachIn childs
                If Not Keyhandler(obj) Then Continue
                keyhandlerFan.Add(Keyhandler(obj))
            End
        End

        Return keyhandlerFan
    End
End


#28 fixed

#28 fixed

Strict

Import mojo

Import flxextern
Import flxpoint
Import flxobject
Import flxcamera
Import flxg

Import system.flxanim
Import system.flxcolor

Import "data/flx_default.png"

Class FlxSprite Extends FlxObject

	Global ClassObject:FlxClass = new FlxSpriteClass()

	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()

	Field _animations:StringMap<FlxAnim>

	Field _flipped:Bool

	Field _flipNeeded:Bool

	Field _curAnim:FlxAnim

	Field _curFrame:Int

	Field _curIndex:Int

	Field _frameTimer:Float

	Field _callback:FlxAnimationListener

	Field _facing:Int

	Field _alpha:Float

	Field _bakedRotation:Float

	Field _pixels:Image

	Field _matrix:Float[6]

	Field _surfaceColor:FlxColor

	Field _halfWidth:Float

	Field _halfHeight:Float

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

		_callback = Null

		_surfaceColor = New FlxColor(FlxG.WHITE)
		_mixedColor = New FlxColor(FlxG.WHITE)

		If (simpleGraphic.Length() = 0)
			simpleGraphic = FlxG.DATA_PREFIX + "default"
		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
		_surfaceColor = Null
		_mixedColor = Null
		_camera = Null
	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)
		_pixels = Null
		_bakedRotation = 0
		_surfaceColor.SetARGB(color)

		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.ID)) 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 (_pixels <> Null) Then
			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
					DrawImage(_pixels, _point.x, _point.y, _curIndex)
				Else
					PushMatrix()
						Transform(-1, 0, 0, 1, _point.x + _halfWidth, _point.y + _halfHeight)
						DrawImage(_pixels, -_halfWidth, -_halfHeight, _curIndex)
					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[3]
						_matrix[2] = _matrix[0] * sin
						_matrix[0] *= cos
						_matrix[3] = cos * _matrix[3]
					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

					DrawImage(_pixels, -origin.x, -origin.y, _curIndex)
				PopMatrix()
			End If
		Else
			If (_camera.Color <> FlxG.WHITE) Then
				_mixedColor.MixRGB(_surfaceColor, _camera._color)

				If (_color.argb <> FlxG.WHITE) Then
					_mixedColor.MixRGB(_color)
				End If

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

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

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

				If (_surfaceColor.a < 1) Then
					_mixedAlpha *= _surfaceColor.a
				End If

				If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
					SetAlpha(_mixedAlpha)
					FlxG._LastDrawingAlpha = _mixedAlpha
				End If
			Else
				If (_surfaceColor.a < 1) Then
					Local _mixedAlpha:Float = _surfaceColor.a * _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
			End If

			If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
				_DrawSurface(_point.x, _point.y)
			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[3]
						_matrix[2] = _matrix[0] * sin
						_matrix[0] *= cos
						_matrix[3] = cos * _matrix[3]
					End If

					Transform(_matrix[0], _matrix[1], _matrix[2], _matrix[3], _matrix[4], _matrix[5])
					_DrawSurface(-origin.x, -origin.y)
				PopMatrix()
			End If
		End If

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

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

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

	Method AddAnimationCallback:Void(animationCallback:FlxAnimationListener)
		_callback = animationCallback
	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

		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

		FlxG.Log("WARNING: No animation called ~q" + animName + "~q")
	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

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

		frameWidth = width
		frameHeight = height
		_ResetHelpers()
	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
		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 _DrawSurface:Void(x:Float, y:Float)
		DrawRect(x, y, frameWidth, frameHeight)
	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

	Method ToString:String()
		Return "FlxSprite"
	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) dirty = True

		ElseIf (_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.name, _curFrame, _curIndex)
			Else
				_callback.OnAnimationFrame("", _curFrame, _curIndex)
			End If
		End If
		dirty = False
	End Method

End Class

Private
Class FlxSpriteClass Implements FlxClass

	Method CreateInstance:Object()
		Return New FlxSprite()
	End Method

	Method InstanceOf:Bool(object:Object)
		Return (FlxSprite(object) <> Null)
	End Method

End Class

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/flx_default.png"

Class FlxSprite Extends FlxObject

	Global ClassObject:FlxClass = new FlxSpriteClass()

	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()

	Field _animations:StringMap<FlxAnim>

	Field _flipped:Bool

	Field _flipNeeded:Bool

	Field _curAnim:FlxAnim

	Field _curFrame:Int

	Field _curIndex:Int

	Field _frameTimer:Float

	Field _callback:FlxAnimationListener

	Field _facing:Int

	Field _alpha:Float

	Field _bakedRotation:Float

	Field _pixels:Image

	Field _matrix:Float[6]

	Field _surfaceColor:FlxColor

	Field _halfWidth:Float

	Field _halfHeight:Float

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

		_callback = Null

		_surfaceColor = New FlxColor(FlxG.WHITE)
		_mixedColor = New FlxColor(FlxG.WHITE)

		If (simpleGraphic.Length() = 0)
			simpleGraphic = FlxG.DATA_PREFIX + "default"
		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
		_surfaceColor = Null
		_mixedColor = Null
		_camera = Null
	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)

		If (reverse) Then
			_flipped = True
		Else
			_flipped = True
		End if

		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)
		_pixels = Null
		_bakedRotation = 0
		_surfaceColor.SetARGB(color)

		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.ID)) 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 (_pixels <> Null) Then
			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
					DrawImage(_pixels, _point.x, _point.y, _curIndex)
				Else
					PushMatrix()
						Transform(-1, 0, 0, 1, _point.x + _halfWidth, _point.y + _halfHeight)
						DrawImage(_pixels, -_halfWidth, -_halfHeight, _curIndex)
					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[3]
						_matrix[2] = _matrix[0] * sin
						_matrix[0] *= cos
						_matrix[3] = cos * _matrix[3]
					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

					DrawImage(_pixels, -origin.x, -origin.y, _curIndex)
				PopMatrix()
			End If
		Else
			If (_camera.Color <> FlxG.WHITE) Then
				_mixedColor.MixRGB(_surfaceColor, _camera._color)

				If (_color.argb <> FlxG.WHITE) Then
					_mixedColor.MixRGB(_color)
				End If

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

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

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

				If (_surfaceColor.a < 1) Then
					_mixedAlpha *= _surfaceColor.a
				End If

				If (FlxG._LastDrawingAlpha <> _mixedAlpha) Then
					SetAlpha(_mixedAlpha)
					FlxG._LastDrawingAlpha = _mixedAlpha
				End If
			Else
				If (_surfaceColor.a < 1) Then
					Local _mixedAlpha:Float = _surfaceColor.a * _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
			End If

			If ((angle = 0 Or _bakedRotation > 0) And scale.x = 1 And scale.y = 1) Then
				_DrawSurface(_point.x, _point.y)
			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[3]
						_matrix[2] = _matrix[0] * sin
						_matrix[0] *= cos
						_matrix[3] = cos * _matrix[3]
					End If

					Transform(_matrix[0], _matrix[1], _matrix[2], _matrix[3], _matrix[4], _matrix[5])
					_DrawSurface(-origin.x, -origin.y)
				PopMatrix()
			End If
		End If

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

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

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

	Method AddAnimationCallback:Void(animationCallback:FlxAnimationListener)
		_callback = animationCallback
	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

		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

		FlxG.Log("WARNING: No animation called ~q" + animName + "~q")
	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

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

		frameWidth = width
		frameHeight = height
		_ResetHelpers()
	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
		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 _DrawSurface:Void(x:Float, y:Float)
		DrawRect(x, y, frameWidth, frameHeight)
	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

	Method ToString:String()
		Return "FlxSprite"
	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) dirty = True

		ElseIf (_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.name, _curFrame, _curIndex)
			Else
				_callback.OnAnimationFrame("", _curFrame, _curIndex)
			End If
		End If
		dirty = False
	End Method

End Class

Private
Class FlxSpriteClass Implements FlxClass

	Method CreateInstance:Object()
		Return New FlxSprite()
	End Method

	Method InstanceOf:Bool(object:Object)
		Return (FlxSprite(object) <> Null)
	End Method

End Class

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


Observer listener to public

Observer listener to public

Strict

Import flxsignal

Class FlxSignalObserver

	Field enabled:Bool

	Field listener:FlxSignalListener

Private
	Field _signal:FlxSignal

	Field _instant:Bool

	Field _priority:Int

Public
	Method New(listener:FlxSignalListener, instant:Bool = False, signal:FlxSignal = Null, priority:Int = 0)
		_signal = signal
		enabled = True
		Self.listener = listener
		_instant = instant
		_priority = priority
	End Method

	Method Destroy:Void()
		_signal = Null
		listener = Null
	End Method

	Method Apply:Void(data:Object)
		If ( Not enabled) Return
		If (_instant) Remove()

		listener.OnSignalEmitted(_signal, data)
	End Method

	Method Remove:Void()
		_signal.Remove(Self)
	End Method

	Method Priority:Int() Property
		Return _priority
	End Method

End Class

Interface FlxSignalListener

	Method OnSignalEmitted:Void(signal:FlxSignal, data:Object)

End Interface

Strict

Import flxsignal

Class FlxSignalObserver

	Field enabled:Bool

Private
	Field _signal:FlxSignal

	Field _listener:FlxSignalListener

	Field _instant:Bool

	Field _priority:Int

Public
	Method New(listener:FlxSignalListener, instant:Bool = False, signal:FlxSignal = Null, priority:Int = 0)
		_signal = signal
		enabled = True
		_listener = listener
		_instant = instant
		_priority = priority
	End Method

	Method Destroy:Void()
		_signal = Null
		_listener = Null
	End Method

	Method Apply:Void(data:Object)
		If ( Not enabled) Return
		If (_instant) Remove()

		_listener.OnSignalEmitted(_signal, data)
	End Method

	Method Remove:Void()
		_signal.Remove(Self)
	End Method

	Method Priority:Int() Property
		Return _priority
	End Method

End Class

Interface FlxSignalListener

	Method OnSignalEmitted:Void(signal:FlxSignal, data:Object)

End Interface