Fixed Get method not found bug in FlxSignal

Strict

Class FlxSignal

Private
	Field _observers:FlxSignalObserverList

	Field _id:Int

Public
	Method New(id:Int)
		_observers = New FlxSignalObserverList()
		_id = id
	End Method

	Method Destroy:Void()
		_observers.Destroy()
		_observers = Null
	End Method

	Method RegisterListener:FlxSignalObserver(listener:FlxSignalListener)
		If (listener = Null) Return Null

		Local observer:FlxSignalObserver = _observers.GetByListener(listener)

		If (observer = Null) Then
			observer = New FlxSignalObserver(listener, False, Self)
			observer._withPriority = False
			_observers.AddLast(observer)
		End If

		Return observer
	End Method

	Method RegisterListener:FlxSignalObserver(listener:FlxSignalListener, instant:Bool)
		If (listener = Null) Return Null

		Local observer:FlxSignalObserver = _observers.GetByListener(listener)

		If (observer = Null) Then
			observer = New FlxSignalObserver(listener, instant, Self)
			observer._withPriority = False
			_observers.AddLast(observer)
		End If

		Return observer
	End Method

	Method RegisterListener:FlxSignalObserver(listener:FlxSignalListener, instant:Bool, priority:Int)
		If (listener = Null) Return Null

		Local observer:FlxSignalObserver = _observers.GetByListener(listener)

		If (observer = Null) Then
			observer = New FlxSignalObserver(listener, instant, Self, priority)
			observer._withPriority = True
			_observers.InsertWithPriority(observer)
		End If

		Return observer
	End Method

	Method RemoveListener:FlxSignalObserver(listener:FlxSignalListener)
		If (listener = Null) Return Null
		Return _observers.RemoveByListener(listener)
	End Method

	Method Clear:Void()
		_observers.Clear()
	End Method

	Method Emit:Void(data:Object)
		Local node:list.Node<FlxSignalObserver> = _observers.FirstNode()

		While (node <> Null)
			node.Value()._Apply(data)
			node = node.NextNode()
		Wend
	End Method

	Method ID:Int() Property
		Return _id
	End Method

End Class

Class FlxSignalObserver

	Field enabled:Bool

Private
	Field _signal:FlxSignal

	Field _instant:Bool

	Field _priority:Int

	Field _withPriority:Bool

	Field _listener:FlxSignalListener

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()
		Disconnect()
		_signal = Null
		_listener = Null
	End Method

	Method Connect:Void()
		If (_signal._observers.GetByListener(_listener) = Null) Then
			If (_withPriority) Then
				_signal._observers.InsertWithPriority(Self)
			Else
				_signal._observers.AddLast(Self)
			End If
		End If
	End Method

	Method Disconnect:Void()
		_signal.RemoveListener(_listener)
	End Method

	Method Priority:Int() Property
		Return _priority
	End Method

	Method Listener:FlxSignalListener() Property
		Return _listener
	End Method

Private
	Method _Apply:Void(data:Object)
		If ( Not enabled) Return
		If (_instant) Disconnect()

		_listener.OnSignalEmitted(_signal, data)
	End Method

End Class

Interface FlxSignalListener

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

End Interface

Private
Class FlxSignalObserverList Extends List<FlxSignalObserver>

	Method Destroy:Void()
		Local node:list.Node<FlxSignalObserver> = FirstNode()

		While (node <> Null)
			node.Value().Destroy()
			node.Remove()

			node = node.NextNode()
		Wend
	End Method

	Method InsertWithPriority:list.Node<FlxSignalObserver>(signalObserver:FlxSignalObserver)
		If (IsEmpty()) Then
			Return AddFirst(signalObserver)
		End If

		Local node:list.Node<FlxSignalObserver> = FirstNode()
		Local priority:Int = signalObserver.Priority

		If (priority > node.Value()._priority) Then
			Return AddFirst(signalObserver)
		End If

		Repeat
			node = node.NextNode()
			If (node = Null) Exit

			If (priority > node.Value()._priority) Then
				Return New list.Node<FlxSignalObserver>(node, node.PrevNode(), signalObserver)
			End If
		Forever

		Return AddLast(signalObserver)
	End Method

	Method RemoveByListener:FlxSignalObserver(listener:FlxSignalListener)
		Local node:list.Node<FlxSignalObserver> = FirstNode()

		While (node <> Null)
			If (node.Value()._listener = listener) Then
				node.Remove()
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return Null
	End Method

	Method GetByListener:FlxSignalObserver(listener:FlxSignalListener)
		Local node:list.Node<FlxSignalObserver> = FirstNode()

		While (node <> Null)
			If (node.Value()._listener = listener) Then
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return Null
	End Method

End Class

Strict

Class FlxSignal

Private
	Field _observers:FlxSignalObserverList

	Field _id:Int

Public
	Method New(id:Int)
		_observers = New FlxSignalObserverList()
		_id = id
	End Method

	Method Destroy:Void()
		_observers.Destroy()
		_observers = Null
	End Method

	Method RegisterListener:FlxSignalObserver(listener:FlxSignalListener)
		If (listener = Null) Return Null

		Local observer:FlxSignalObserver = _observers.GetByListener(listener)

		If (observer = Null) Then
			observer = New FlxSignalObserver(listener, False, Self)
			observer._withPriority = False
			_observers.AddLast(observer)
		End If

		Return observer
	End Method

	Method RegisterListener:FlxSignalObserver(listener:FlxSignalListener, instant:Bool)
		If (listener = Null) Return Null

		Local observer:FlxSignalObserver = _observers.GetByListener(listener)

		If (observer = Null) Then
			observer = New FlxSignalObserver(listener, instant, Self)
			observer._withPriority = False
			_observers.AddLast(observer)
		End If

		Return observer
	End Method

	Method RegisterListener:FlxSignalObserver(listener:FlxSignalListener, instant:Bool, priority:Int)
		If (listener = Null) Return Null

		Local observer:FlxSignalObserver = _observers.GetByListener(listener)

		If (observer = Null) Then
			observer = New FlxSignalObserver(listener, instant, Self, priority)
			observer._withPriority = True
			_observers.InsertWithPriority(observer)
		End If

		Return observer
	End Method

	Method RemoveListener:FlxSignalObserver(listener:FlxSignalListener)
		If (listener = Null) Return Null
		Return _observers.RemoveByListener(listener)
	End Method

	Method Clear:Void()
		_observers.Clear()
	End Method

	Method Emit:Void(data:Object)
		Local node:list.Node<FlxSignalObserver> = _observers.FirstNode()

		While (node <> Null)
			node.Value()._Apply(data)
			node = node.NextNode()
		Wend
	End Method

	Method ID:Int() Property
		Return _id
	End Method

End Class

Class FlxSignalObserver

	Field enabled:Bool

Private
	Field _signal:FlxSignal

	Field _instant:Bool

	Field _priority:Int

	Field _withPriority:Bool

	Field _listener:FlxSignalListener

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()
		Disconnect()
		_signal = Null
		_listener = Null
	End Method

	Method Connect:Void()
		If (_signal._observers.Get(_listener) = Null) Then
			If (_withPriority) Then
				_signal._observers.InsertWithPriority(Self)
			Else
				_signal._observers.AddLast(Self)
			End If
		End If
	End Method

	Method Disconnect:Void()
		_signal.RemoveListener(_listener)
	End Method

	Method Priority:Int() Property
		Return _priority
	End Method

	Method Listener:FlxSignalListener() Property
		Return _listener
	End Method

Private
	Method _Apply:Void(data:Object)
		If ( Not enabled) Return
		If (_instant) Disconnect()

		_listener.OnSignalEmitted(_signal, data)
	End Method

End Class

Interface FlxSignalListener

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

End Interface

Private
Class FlxSignalObserverList Extends List<FlxSignalObserver>

	Method Destroy:Void()
		Local node:list.Node<FlxSignalObserver> = FirstNode()

		While (node <> Null)
			node.Value().Destroy()
			node.Remove()

			node = node.NextNode()
		Wend
	End Method

	Method InsertWithPriority:list.Node<FlxSignalObserver>(signalObserver:FlxSignalObserver)
		If (IsEmpty()) Then
			Return AddFirst(signalObserver)
		End If

		Local node:list.Node<FlxSignalObserver> = FirstNode()
		Local priority:Int = signalObserver.Priority

		If (priority > node.Value()._priority) Then
			Return AddFirst(signalObserver)
		End If

		Repeat
			node = node.NextNode()
			If (node = Null) Exit

			If (priority > node.Value()._priority) Then
				Return New list.Node<FlxSignalObserver>(node, node.PrevNode(), signalObserver)
			End If
		Forever

		Return AddLast(signalObserver)
	End Method

	Method RemoveByListener:FlxSignalObserver(listener:FlxSignalListener)
		Local node:list.Node<FlxSignalObserver> = FirstNode()

		While (node <> Null)
			If (node.Value()._listener = listener) Then
				node.Remove()
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return Null
	End Method

	Method GetByListener:FlxSignalObserver(listener:FlxSignalListener)
		Local node:list.Node<FlxSignalObserver> = FirstNode()

		While (node <> Null)
			If (node.Value()._listener = listener) Then
				Return node.Value()
			End If

			node = node.NextNode()
		Wend

		Return Null
	End Method

End Class


Small bug fix in the Path Finding example

Strict

Import diddy

Global gameScreen:GameScreen

Function Main:Int()
	New MyGame()
	Return 0
End

Class MyGame Extends DiddyApp

	Method OnCreate:Int()
		Super.OnCreate()
		gameScreen = New GameScreen
		game.Start(gameScreen)
		Return 0
	End
End

Class GameScreen Extends Screen
	Const MAP_WIDTH:Int = 20
	Const MAP_HEIGHT:Int = 20
	Const TILE_SIZE:Int = 20

	Field grid:Float[MAP_WIDTH * MAP_HEIGHT]
	Field fx:Int, fy:Int
	Field mx:Int, my:Int
	Field startX:Int = 1, startY:Int = 1
	Field endX:Int = 10, endY:Int = 15
	Field x:Float, y:Float
	Field i:Int
	Field z:Int, g:Float
	Field currentPath:Int = 0

	Method New()
		name = "Game"
	End

	Method Start:Void()
		PathFinder.SetMap(grid, MAP_WIDTH, MAP_HEIGHT, 2, 0)
		x = startX * TILE_SIZE
		y = startY * TILE_SIZE
	End

	Method Render:Void()
		Cls

		'Draw grid tiles
		For fy = 0 Until MAP_HEIGHT
			For fx = 0 Until  MAP_WIDTH
				If grid[fx + fy * MAP_WIDTH] > 0 Then
					SetColor grid[fx + fy * 20] * 255, 0, 0
					DrawRect fx * TILE_SIZE, fy * TILE_SIZE, TILE_SIZE, TILE_SIZE
				End
			Next
		Next

		'Draw grid lines
		SetColor 255, 255, 255
		For fx = 0 To MAP_WIDTH
			DrawLine fx * TILE_SIZE, 0, fx * TILE_SIZE, MAP_HEIGHT * TILE_SIZE
			DrawLine 0, fx * TILE_SIZE, MAP_WIDTH * TILE_SIZE, fx * TILE_SIZE
		Next

		'Draw the "player" position
		SetColor 255, 0, 255
		DrawOval x, y, TILE_SIZE, TILE_SIZE

		'Draw end position
		SetColor 255, 255, 0
		DrawOval endX * TILE_SIZE, endY * TILE_SIZE, TILE_SIZE, TILE_SIZE

		'Draw path
		SetColor 0, 255, 0
		For i = 0 Until PathFinder.paths * 2 Step 2
			DrawRect PathFinder.route[i] * TILE_SIZE + TILE_SIZE/2, PathFinder.route[i + 1] * TILE_SIZE+ TILE_SIZE/2, 5, 5
		Next

		SetColor 255, 255, 255
		DrawHUD()
	End

	Method SetPath:Void()
		startX = x / TILE_SIZE
		startY = y / TILE_SIZE
		PathFinder.FindPath(startX, startY, endX, endY)
		currentPath = (PathFinder.paths - 1) * 2
	End

	Method Update:Void()
		mx = game.mouseX / TILE_SIZE
		my = game.mouseY / TILE_SIZE
		mx = Max(mx, 0)
		mx = Min(mx, 19)
		my = Max(my, 0)
		my = Min(my, 19)

		If MouseDown(0) Then
			grid[mx + my * MAP_WIDTH] = 1
			SetPath()
		End

		If MouseDown(MOUSE_MIDDLE) Then
			grid[mx + my * MAP_WIDTH] = 0
			SetPath()
		End

		If KeyHit(KEY_SPACE)
			endX = mx
			endY = my
			SetPath()
		End

		If currentPath >= 0
			If x < PathFinder.route[currentPath] * TILE_SIZE
				x += 1
			End
			If x > PathFinder.route[currentPath] * TILE_SIZE
				x -= 1
			End
			If y < PathFinder.route[currentPath + 1] * TILE_SIZE
				y += 1
			End
			If y > PathFinder.route[currentPath + 1] * TILE_SIZE
				y -= 1
			End

			If x = PathFinder.route[currentPath] * TILE_SIZE And
				y = PathFinder.route[currentPath + 1] * TILE_SIZE
				currentPath -= 2
			End
		End

		If KeyHit(KEY_ESCAPE)
			FadeToScreen(Null)
		End
	End

	Method DrawHUD:Void()
		DrawText "No. of paths = "+ PathFinder.paths, SCREEN_WIDTH, 10, 1
		DrawText "Mouse Grid = "+ mx+ "," + my, SCREEN_WIDTH, 30, 1
		DrawText "currentPath = " + PathFinder.route[currentPath] + "," + PathFinder.route[currentPath + 1], SCREEN_WIDTH, 30, 1
		FPSCounter.Draw(SCREEN_WIDTH, SCREEN_HEIGHT  - 12, 1)
	End
End

Strict

Import diddy

Global gameScreen:GameScreen

Function Main:Int()
	New MyGame()
	Return 0
End

Class MyGame Extends DiddyApp

	Method OnCreate:Int()
		Super.OnCreate()
		gameScreen = New GameScreen
		game.Start(gameScreen)
		Return 0
	End
End

Class GameScreen Extends Screen
	Const MAP_WIDTH:Int = 20
	Const MAP_HEIGHT:Int = 20
	Const TILE_SIZE:Int = 20

	Field grid:Float[MAP_WIDTH * MAP_HEIGHT]
	Field fx:Int, fy:Int
	Field mx:Int, my:Int
	Field startX:Int = 1, startY:Int = 1
	Field endX:Int = 10, endY:Int = 15
	Field x:Float, y:Float
	Field i:Int
	Field z:Int, g:Float
	Field currentPath:Int = 0

	Method New()
		name = "Game"
	End

	Method Start:Void()
		PathFinder.SetMap(grid, MAP_WIDTH, MAP_HEIGHT, 2, 0)
		x = startX * TILE_SIZE
		y = startY * TILE_SIZE
	End

	Method Render:Void()
		Cls

		'Draw grid tiles
		For fy = 0 Until MAP_HEIGHT
			For fx = 0 Until  MAP_WIDTH
				If grid[fx + fy * MAP_WIDTH] > 0 Then
					SetColor grid[fx + fy * 20] * 255, 0, 0
					DrawRect fx * TILE_SIZE, fy * TILE_SIZE, TILE_SIZE, TILE_SIZE
				End
			Next
		Next

		'Draw grid lines
		SetColor 255, 255, 255
		For fx = 0 To MAP_WIDTH
			DrawLine fx * TILE_SIZE, 0, fx * TILE_SIZE, MAP_HEIGHT * TILE_SIZE
			DrawLine 0, fx * TILE_SIZE, MAP_WIDTH * TILE_SIZE, fx * TILE_SIZE
		Next

		'Draw the "player" position
		SetColor 255, 0, 255
		DrawOval x, y, TILE_SIZE, TILE_SIZE

		'Draw end position
		SetColor 255, 255, 0
		DrawOval endX * TILE_SIZE, endY * TILE_SIZE, TILE_SIZE, TILE_SIZE

		'Draw path
		SetColor 0, 255, 0
		For i = 0 Until PathFinder.paths * 2 Step 2
			DrawRect PathFinder.route[i] * TILE_SIZE + TILE_SIZE/2, PathFinder.route[i + 1] * TILE_SIZE+ TILE_SIZE/2, 5, 5
		Next

		SetColor 255, 255, 255
		DrawHUD()
	End

	Method Update:Void()
		mx = game.mouseX / TILE_SIZE
		my = game.mouseY / TILE_SIZE
		mx = Max(mx, 0)
		mx = Min(mx, 19)
		my = Max(my, 0)
		my = Min(my, 19)

		If MouseDown(0) Then
			grid[mx + my * MAP_WIDTH] = 1
			startX = x / TILE_SIZE
			startY = y / TILE_SIZE
			PathFinder.FindPath(startX, startY, endX, endY)
		End

		If MouseDown(MOUSE_MIDDLE) Then
			grid[mx + my * MAP_WIDTH] = 0
			startX = x / TILE_SIZE
			startY = y / TILE_SIZE
			PathFinder.FindPath(startX, startY, endX, endY)
		End

		If KeyHit(KEY_SPACE)
			startX = x / TILE_SIZE
			startY = y / TILE_SIZE
			endX = mx
			endY = my
			PathFinder.FindPath(startX, startY, endX, endY)
			currentPath = (PathFinder.paths - 1) * 2
		End

		If currentPath >= 0
			If x < PathFinder.route[currentPath] * TILE_SIZE
				x += 1
			End
			If x > PathFinder.route[currentPath] * TILE_SIZE
				x -= 1
			End
			If y < PathFinder.route[currentPath + 1] * TILE_SIZE
				y += 1
			End
			If y > PathFinder.route[currentPath + 1] * TILE_SIZE
				y -= 1
			End

			If x = PathFinder.route[currentPath] * TILE_SIZE And
				y = PathFinder.route[currentPath + 1] * TILE_SIZE
				currentPath -= 2
			End
		End

		If KeyHit(KEY_ESCAPE)
			FadeToScreen(Null)
		End
	End

	Method DrawHUD:Void()
		DrawText "No. of paths = "+ PathFinder.paths, SCREEN_WIDTH, 10, 1
		DrawText "Mouse Grid = "+ mx+ "," + my, SCREEN_WIDTH, 30, 1
		DrawText "currentPath = " + PathFinder.route[currentPath] + "," + PathFinder.route[currentPath + 1], SCREEN_WIDTH, 30, 1
		FPSCounter.Draw(SCREEN_WIDTH, SCREEN_HEIGHT  - 12, 1)
	End
End


Removed a compatibility import to 'publicdatastream'; now using 'ioutil'.

Strict

Public

' Friends:
Friend networking.engine
Friend networking.packetpool

' Imports:
Import engine
Import client

Import ioutil.publicdatastream
Import eternity

Import brl.databuffer
'Import brl.datastream

' Classes:
Class Packet Extends PublicDataStream
	' Constant variable(s):

	' Defaults:

	' Booleans / Flags:
	Const Default_BigEndianStorage:Bool = True

	' Functions:
	Function SizeOfString:Int(S:String)
		Return S.Length ' * 2
	End

	' Constructor(s):
	Method New(Size:Int, FixByteOrder:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		Super.New(Size, FixByteOrder, Resizable, SizeLimit)
	End

	Method New(Message:String, Encoding:String="utf8", FixByteOrder:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		Super.New(SizeOfString(Message), FixByteOrder, Resizable, SizeLimit)

		Data.PokeString(0, Message, Encoding)

		Self._Length = DataLength
	End

	' Destructor(s):
	Method ForceClose:Void()
		' Call ths super-class's 'Close' routine.
		Super.Close()

		' Reset the reference-counter.
		Self.RefCount = 0

		Return
	End

	Method Close:Void()
		RefCount -= 1

		If (RefCount < 1) Then
			ForceClose() ' Super.Close()
		Endif

		Return
	End

	' Methods:
	Method Obtain:Void()
		RefCount += 1

		Return
	End

	' The return-value of this method specifies
	' if this packet is no longer referenced.
	Method Release:Bool()
		RefCount -= 1

		Return Released
	End

	' Properties:
	Method Released:Bool() Property
		Return (RefCount <= 0)
	End

	Method IsReliable:Bool() Property
		Return False
	End

	' Fields (Public):
	' Nothing so far.

	' Fields (Protected):
	Protected

	Field RefCount:Int = 0

	Public
End

Class ReliablePacket Extends Packet Final
	' Constant variable(s):
	Const PACKET_ID_NONE:PacketID = 0

	' Constructor(s):
	Method New(Size:Int, FixByteOrder:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		' Call the super-class's implementation.
		Super.New(Size, FixByteOrder, Resizable, SizeLimit)
	End

	' Destructor(s):
	Method ForceClose:Void()
		' Call the super-class's implementation.
		Super.ForceClose()

		' Set the internal identifier back to default.
		Self._ID = PACKET_ID_NONE

		Return
	End

	' Methods:
	Method Resend:Void(Network:NetworkEngine)
		ResetResendTimer()

		Network.Send(Self)

		Return
	End

	Method Update:Void(Network:NetworkEngine)
		If (Eternity.TimeDifference(ResendTimer) >= Network.PacketResendTime) Then
			Resend(Network)
		Endif

		Return
	End

	' Properties (Public):
	Method Destination:Client() Property
		Return Self._Destination
	End

	' Properties (Protected):
	Protected

	Method Destination:Void(Input:Client) Property
		Self._Destination = Input

		Return
	End

	Public

	' Methods (Private):
	Private

	Method ResetResendTimer:Void()
		ResendTimer = Eternity.GetTime()

		Return
	End

	Public

	' Properties (Public):
	Method ID:PacketID() Property
		Return Self._ID
	End

	Method IsReliable:Bool() Property
		Return True
	End

	' Properties (Private):
	Private

	Method ID:Void(Input:PacketID) Property
		#Rem
			If (Input = PACKET_ID_NONE) Then
				If (ID <> PACKET_ID_NONE) Then ' Input
					Release()
				Endif
			Else
				Self._ID = Input

				Obtain()
			Endif
		#End

		Self._ID = Input

		Return
	End

	Public

	' Fields (Public):
	'Field

	' Fields (Private):
	Private

	Field _Destination:Client

	Field _ID:PacketID = PACKET_ID_NONE

	Field ResendTimer:TimePoint
	'Field LifeTimer:TimePoint

	Public
End

Strict

Public

' Friends:
Friend networking.engine
Friend networking.packetpool

' Imports:
Import engine
Import client

Import publicdatastream
Import eternity

Import brl.databuffer
'Import brl.datastream

' Classes:
Class Packet Extends PublicDataStream
	' Constant variable(s):

	' Defaults:

	' Booleans / Flags:
	Const Default_BigEndianStorage:Bool = True

	' Functions:
	Function SizeOfString:Int(S:String)
		Return S.Length ' * 2
	End

	' Constructor(s):
	Method New(Size:Int, FixByteOrder:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		Super.New(Size, FixByteOrder, Resizable, SizeLimit)
	End

	Method New(Message:String, Encoding:String="utf8", FixByteOrder:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		Super.New(SizeOfString(Message), FixByteOrder, Resizable, SizeLimit)

		Data.PokeString(0, Message, Encoding)

		Self._Length = DataLength
	End

	' Destructor(s):
	Method ForceClose:Void()
		' Call ths super-class's 'Close' routine.
		Super.Close()

		' Reset the reference-counter.
		Self.RefCount = 0

		Return
	End

	Method Close:Void()
		RefCount -= 1

		If (RefCount < 1) Then
			ForceClose() ' Super.Close()
		Endif

		Return
	End

	' Methods:
	Method Obtain:Void()
		RefCount += 1

		Return
	End

	' The return-value of this method specifies
	' if this packet is no longer referenced.
	Method Release:Bool()
		RefCount -= 1

		Return Released
	End

	' Properties:
	Method Released:Bool() Property
		Return (RefCount <= 0)
	End

	Method IsReliable:Bool() Property
		Return False
	End

	' Fields (Public):
	' Nothing so far.

	' Fields (Protected):
	Protected

	Field RefCount:Int = 0

	Public
End

Class ReliablePacket Extends Packet Final
	' Constant variable(s):
	Const PACKET_ID_NONE:PacketID = 0

	' Constructor(s):
	Method New(Size:Int, FixByteOrder:Bool=Default_BigEndianStorage, Resizable:Bool=True, SizeLimit:Int=NOLIMIT)
		' Call the super-class's implementation.
		Super.New(Size, FixByteOrder, Resizable, SizeLimit)
	End

	' Destructor(s):
	Method ForceClose:Void()
		' Call the super-class's implementation.
		Super.ForceClose()

		' Set the internal identifier back to default.
		Self._ID = PACKET_ID_NONE

		Return
	End

	' Methods:
	Method Resend:Void(Network:NetworkEngine)
		ResetResendTimer()

		Network.Send(Self)

		Return
	End

	Method Update:Void(Network:NetworkEngine)
		If (Eternity.TimeDifference(ResendTimer) >= Network.PacketResendTime) Then
			Resend(Network)
		Endif

		Return
	End

	' Properties (Public):
	Method Destination:Client() Property
		Return Self._Destination
	End

	' Properties (Protected):
	Protected

	Method Destination:Void(Input:Client) Property
		Self._Destination = Input

		Return
	End

	Public

	' Methods (Private):
	Private

	Method ResetResendTimer:Void()
		ResendTimer = Eternity.GetTime()

		Return
	End

	Public

	' Properties (Public):
	Method ID:PacketID() Property
		Return Self._ID
	End

	Method IsReliable:Bool() Property
		Return True
	End

	' Properties (Private):
	Private

	Method ID:Void(Input:PacketID) Property
		#Rem
			If (Input = PACKET_ID_NONE) Then
				If (ID <> PACKET_ID_NONE) Then ' Input
					Release()
				Endif
			Else
				Self._ID = Input

				Obtain()
			Endif
		#End

		Self._ID = Input

		Return
	End

	Public

	' Fields (Public):
	'Field

	' Fields (Private):
	Private

	Field _Destination:Client

	Field _ID:PacketID = PACKET_ID_NONE

	Field ResendTimer:TimePoint
	'Field LifeTimer:TimePoint

	Public
End


reject unsupported TexturePacker features in SpriteAtlas

Strict

Private

Import bono
Import bono.vendor.skn3.xml
Import mojo.app

Public

Class SpriteAtlas
    Private

    Field atlasSprite:Sprite
    Field childSprites:StringMap<Sprite> = New StringMap<Sprite>()
    Field xml:XMLDoc
    Field preloaded:Bool

    Public

    Method New(filename:String)
        LoadXml(filename)
        CheckXml()

        LoadAtlasSprite()
        LoadSprites()

        FreeXmlRecursive(xml)
        xml = Null
    End

    Method Preload:Void()
        If preloaded Then Return
        preloaded = True

        Local oldFloat := atlasSprite.GetColor().alphaFloat
        atlasSprite.GetColor().alphaFloat = 0
        atlasSprite.OnRender()
        atlasSprite.GetColor().alphaFloat = oldFloat
    End

    Method Get:Sprite(name:String)
        If Not childSprites.Contains(name)
            Throw New InvalidArgumentException(
                "There is no sprite named: " + name)
        End

        Return childSprites.Get(name).Copy()
    End

    Method GetNames:MapKeys<String, Sprite>()
        Return childSprites.Keys()
    End

    Method Count:Int()
        Return childSprites.Count()
    End

    Method IsEmpty:Bool()
        Return childSprites.IsEmpty()
    End

    Method Contains:Bool(name:String)
        Return childSprites.Contains(name)
    End

    Private

    Method LoadXml:Void(filename:String)
        Local content:String = LoadString(filename)
        If Not content Or content = ""
            Throw New RuntimeException(
                "Unable to load definition from file: " + filename)
        End

        Local error:XMLError = New XMLError
        xml = ParseXML(content, error)

        If Not xml Or error.error
            Throw New RuntimeException(
                "Unable to parse XML: " + error)
        End
    End

    Method CheckXml:Void()
        If Not xml.HasChildren()
            Throw New InvalidSpriteAtlasXmlException(
                "Given xml file seems to be empty")
        End

        If xml.name <> "textureatlas"
            Throw New InvalidSpriteAtlasXmlException(
                "First node must be 'TextureAtlas'")
        End

        If Not xml.HasAttribute("imagepath")
            Throw New InvalidSpriteAtlasXmlException(
                "Missing attribute 'imagepath' in 'TextureAtlas' node")
        End
    End

    Method LoadAtlasSprite:Void()
        atlasSprite = New Sprite(xml.GetAttribute("imagepath"))

        If xml.HasAttribute("width")
            Assert.AssertEquals(
                atlasSprite.GetSize().x,
                Float(xml.GetAttribute("width")))
        End

        If xml.HasAttribute("height")
            Assert.AssertEquals(
                atlasSprite.GetSize().y,
                Float(xml.GetAttribute("height")))
        End
    End

    Method LoadSprites:Void()
        Local name:String
        Local src:Vector2D = New Vector2D()
        Local size:Vector2D = New Vector2D()
        Local rotation:Int

        For Local child:XMLNode = EachIn xml.children
            CheckChildXml(child)

            name = child.GetAttribute("n")
            src.x = Int(child.GetAttribute("x"))
            src.y = Int(child.GetAttribute("y"))
            size.x = Int(child.GetAttribute("w"))
            size.y = Int(child.GetAttribute("h"))

            If child.GetAttribute("r", "n") = "y"
                rotation = 90
            Else
                rotation = 0
            End

            childSprites.Set(
                name,
                atlasSprite.GrabSprite(name, src, size, rotation))
        End
    End

    Method CheckChildXml:Void(child:XMLNode)
        If child.name <> "sprite"
            Throw New InvalidSpriteAtlasXmlException(
                "Unknown node '" + child.name + "' found")
        End

        For Local attr:String = EachIn ["n", "x", "y", "w", "h"]
            If Not child.HasAttribute(attr)
                Throw New InvalidSpriteAtlasXmlException(
                    "Missing attribute '" + attr + "' in sprite node")
            End
        End

        For Local attr:String = EachIn ["oX", "oY", "oW", "oH"]
            If child.HasAttribute(attr)
                Throw New InvalidSpriteAtlasXmlException(
                    "Attribute '" + attr + "' found but not yet implemented")
            End
        End

        If child.HasAttribute("r") And child.GetAttribute("r") <> "y"
            Throw New InvalidSpriteAtlasXmlException(
                "Invalid value for attribute 'r' in sprite node found")
        End
    End

    Method FreeXmlRecursive:Void(xml:XMLNode)
        If Not xml Then Return

        For Local child:XMLNode = EachIn xml.children
            FreeXmlRecursive(child)
            xml.RemoveChild(child)
        End

        xml.ClearAttributes()
        xml.ClearChildren()
    End
End

Strict

Private

Import bono
Import bono.vendor.skn3.xml
Import mojo.app

Public

Class SpriteAtlas
    Private

    Field atlasSprite:Sprite
    Field childSprites:StringMap<Sprite> = New StringMap<Sprite>()
    Field xml:XMLDoc
    Field preloaded:Bool

    Public

    Method New(filename:String)
        LoadXml(filename)
        CheckXml()

        LoadAtlasSprite()
        LoadSprites()

        FreeXmlRecursive(xml)
        xml = Null
    End

    Method Preload:Void()
        If preloaded Then Return
        preloaded = True

        Local oldFloat := atlasSprite.GetColor().alphaFloat
        atlasSprite.GetColor().alphaFloat = 0
        atlasSprite.OnRender()
        atlasSprite.GetColor().alphaFloat = oldFloat
    End

    Method Get:Sprite(name:String)
        If Not childSprites.Contains(name)
            Throw New InvalidArgumentException(
                "There is no sprite named: " + name)
        End

        Return childSprites.Get(name).Copy()
    End

    Method GetNames:MapKeys<String, Sprite>()
        Return childSprites.Keys()
    End

    Method Count:Int()
        Return childSprites.Count()
    End

    Method IsEmpty:Bool()
        Return childSprites.IsEmpty()
    End

    Method Contains:Bool(name:String)
        Return childSprites.Contains(name)
    End

    Private

    Method LoadXml:Void(filename:String)
        Local content:String = LoadString(filename)
        If Not content Or content = ""
            Throw New RuntimeException(
                "Unable to load definition from file: " + filename)
        End

        Local error:XMLError = New XMLError
        xml = ParseXML(content, error)

        If Not xml Or error.error
            Throw New RuntimeException(
                "Unable to parse XML: " + error)
        End
    End

    Method CheckXml:Void()
        If Not xml.HasChildren()
            Throw New InvalidSpriteAtlasXmlException(
                "Given xml file seems to be empty")
        End

        If xml.name <> "textureatlas"
            Throw New InvalidSpriteAtlasXmlException(
                "First node must be 'TextureAtlas'")
        End

        If Not xml.HasAttribute("imagepath")
            Throw New InvalidSpriteAtlasXmlException(
                "Missing attribute 'imagepath' in 'TextureAtlas' node")
        End
    End

    Method LoadAtlasSprite:Void()
        atlasSprite = New Sprite(xml.GetAttribute("imagepath"))

        If xml.HasAttribute("width")
            Assert.AssertEquals(
                atlasSprite.GetSize().x,
                Float(xml.GetAttribute("width")))
        End

        If xml.HasAttribute("height")
            Assert.AssertEquals(
                atlasSprite.GetSize().y,
                Float(xml.GetAttribute("height")))
        End
    End

    Method LoadSprites:Void()
        Local name:String
        Local src:Vector2D = New Vector2D()
        Local size:Vector2D = New Vector2D()
        Local rotation:Int

        For Local child:XMLNode = EachIn xml.children
            CheckChildXml(child)

            name = child.GetAttribute("n")
            src.x = Int(child.GetAttribute("x"))
            src.y = Int(child.GetAttribute("y"))
            size.x = Int(child.GetAttribute("w"))
            size.y = Int(child.GetAttribute("h"))

            If child.GetAttribute("r", "n") = "y"
                rotation = 90
            Else
                rotation = 0
            End

            childSprites.Set(
                name,
                atlasSprite.GrabSprite(name, src, size, rotation))
        End
    End

    Method CheckChildXml:Void(child:XMLNode)
        If child.name <> "sprite"
            Throw New InvalidSpriteAtlasXmlException(
                "Unknown node '" + child.name + "' found")
        End

        For Local attr:String = EachIn ["n", "x", "y", "w", "h"]
            If Not child.HasAttribute(attr)
                Throw New InvalidSpriteAtlasXmlException(
                    "Missing attribute '" + attr + "' in sprite node")
            End
        End

        If child.HasAttribute("r") And child.GetAttribute("r") <> "y"
            Throw New InvalidSpriteAtlasXmlException(
                "Invalid value for attribute 'r' in sprite node found")
        End
    End

    Method FreeXmlRecursive:Void(xml:XMLNode)
        If Not xml Then Return

        For Local child:XMLNode = EachIn xml.children
            FreeXmlRecursive(child)
            xml.RemoveChild(child)
        End

        xml.ClearAttributes()
        xml.ClearChildren()
    End
End


Added the option to wrap Mojo's implementation of 'Millisecs' when available.

Strict

Public

' Preprocessor related:
#TIME_WRAP_MOJO = False

#If BRL_GAMETARGET_IMPLEMENTED
	#TIME_MOJO_IMPLEMENTED = True
#Else
	#TIME_MOJO_IMPLEMENTED = False
#End

' Imports (Public):
Import external

' Imports (Private):
Private

#If TIME_MOJO_IMPLEMENTED
	Import mojo.app
#End

Public

' Functions:

' If we couldn't find a good enough version, use placeholders:
#If Not DELAY_IMPLEMENTED
	Function Delay:Bool(MS:Int)
		Return False
	End
#End

#If Not MILLISECS_IMPLEMENTED And (Not TIME_MOJO_IMPLEMENTED Or TIME_WRAP_MOJO)
	Function Millisecs:Int()
		#If TIME_WRAP_MOJO
			Return app.Millisecs()
		#Else
			Return 0
		#End
	End
#End

Strict

Public

' Preprocessor related:
#If BRL_GAMETARGET_IMPLEMENTED
	#TIME_MOJO_IMPLEMENTED = True
#Else
	#TIME_MOJO_IMPLEMENTED = False
#End

' Imports:
Import external

' Functions:

' If we couldn't find a good enough version, use placeholders:
#If Not DELAY_IMPLEMENTED
	Function Delay:Bool(MS:Int)
		Return False
	End
#End

#If Not MILLISECS_IMPLEMENTED And Not TIME_MOJO_IMPLEMENTED
	Function Millisecs:Int()
		Return 0
	End
#End


FlxCamera fx listeners fixed

FlxCamera fx listeners fixed

Strict

Import flxextern
Import flxpoint
Import flxrect
Import flxbasic
Import flxobject
Import flxg

Import system.flxcolor

Class FlxCamera Extends FlxBasic

	Global ClassObject:FlxClass = New FlxCameraClass()

	Const STYLE_LOCKON:Int = 0

	Const STYLE_PLATFORMER:Int = 1

	Const STYLE_TOPDOWN:Int = 2

	Const STYLE_TOPDOWN_TIGHT:Int = 3

	Const SHAKE_BOTH_AXES:Int = 0

	Const SHAKE_HORIZONTAL_ONLY:Int = 1

	Const SHAKE_VERTICAL_ONLY:Int  = 2

	Global DefaultZoom:Float

	Field target:FlxObject

	Field deadzone:FlxRect

	Field bounds:FlxRect

	Field scroll:FlxPoint

	Field _color:FlxColor

Private
	Const _MIN_FLOAT_VALUE:Float = .0000001

	Field _x:Float

	Field _y:Float

	Field _realX:Float

	Field _realY:Float

	Field _width:Float

	Field _height:Float

	Field _realWidth:Float

	Field _realHeight:Float

	Field _zoom:Float

	Field _point:FlxPoint

	Field _alpha:Float

	Field _scaleX:Float

	Field _scaleY:Float

	Field _angle:Float

	Field _clipped:Bool

	Field _bgColor:FlxColor

	Field _fxFlashColor:Int

	Field _fxFlashDuration:Float

	Field _fxFlashComplete:FlxCameraFlashListener

	Field _fxFlashAlpha:Float

	Field _fxFadeColor:Int

	Field _fxFadeDuration:Float

	Field _fxFadeComplete:FlxCameraFadeListener

	Field _fxFadeAlpha:Float

	Field _fxShakeIntensity:Float

	Field _fxShakeDuration:Float

	Field _fxShakeComplete:FlxCameraShakeListener

	Field _fxShakeOffset:FlxPoint

	Field _fxShakeDirection:Int

	Field _fill:FlxColor

	Field _id:Int

	Global _Inkrement:Int

Public
	Method New(x:Int, y:Int, width:Int, height:Int, zoom:Float = 0)
		Zoom = zoom 'must be first for init
		X = x
		Y = y
		Width = width
		Height = height
		target = Null
		deadzone = Null
		scroll = New FlxPoint()
		_point = New FlxPoint()
		bounds = Null
		_bgColor = New FlxColor(FlxG.BgColor())
		_color = New FlxColor()
		_alpha = 1

		_fxFlashColor = 0
		_fxFlashDuration = 0
		_fxFlashComplete = null
		_fxFlashAlpha = 0

		_fxFadeColor = 0
		_fxFadeDuration = 0
		_fxFadeComplete = Null
		_fxFadeAlpha = 0

		_fxShakeIntensity = 0
		_fxShakeDuration = 0
		_fxShakeComplete = Null
		_fxShakeOffset = New FlxPoint()
		_fxShakeDirection = 0

		active = True

		_fill = New FlxColor(0)

		_id = _Inkrement
		_Inkrement += 1
	End Method

	Method Destroy:Void()
		target = Null
		scroll = Null
		deadzone = Null
		bounds = Null
		_color = Null
		_bgColor = Null
		_fxFlashComplete = Null
		_fxFadeComplete = Null
		_fxShakeComplete = Null
		_fxShakeOffset = Null
		_fill = Null
	End Method

	Method Lock:Void()
		If (_clipped) Then
			SetScissor(_realX + _fxShakeOffset.x * FlxG._DeviceScaleFactorX, _realY + _fxShakeOffset.y * FlxG._DeviceScaleFactorY, _realWidth, _realHeight)
		End If

		PushMatrix()

		Translate(_x + _fxShakeOffset.x, _y + _fxShakeOffset.y)
		Scale(_scaleX, _scaleY)

		If (_clipped Or _bgColor.argb <> FlxG._BgColor.argb)
			SetColor(_bgColor.r, _bgColor.g, _bgColor.b)
			DrawRect(0, 0, _width, _height)
			FlxG._LastDrawingColor = _bgColor.argb
		End If
	End Method

	Method Unlock:Void()
		If (_fill.argb <> 0) Then
			If (_fill.argb <> FlxG._LastDrawingColor) Then
				SetColor(_fill.r, _fill.g, _fill.b)
				FlxG._LastDrawingColor = _fill.argb
			End if

			If (FlxG._LastDrawingAlpha <> _fill.a) Then
				SetAlpha(_fill.a)
				FlxG._LastDrawingAlpha = _fill.a
			End If

			DrawRect(0, 0, _width, _height)
		End If

		PopMatrix()
		_fill.SetARGB(0)

		If (_clipped) Then
			SetScissor(0, 0, FlxG.DeviceWidth, FlxG.DeviceHeight)
		End If
	End Method

	Method Update:Void()
		If (target <> Null) Then
			If (deadzone = Null) Then
				FocusOn(target.GetMidpoint(_point))
			Else
				Local edge:Float
				Local targetX:Float
				Local targetY:Float

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

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

				edge = targetX - deadzone.x
				If (scroll.x > edge) scroll.x = edge
				edge = targetX + target.width - deadzone.x - deadzone.width
				If (scroll.x < edge) scroll.x = edge

				edge  = targetY - deadzone.y
				If (scroll.y > edge) scroll.y = edge
				edge = targetY + target.height - deadzone.y - deadzone.height
				If (scroll.y < edge) scroll.y = edge
			End If
		End If

		If (bounds <> Null) Then
			If (scroll.x < bounds.Left) scroll.x = bounds.Left
			If (scroll.x > bounds.Right - _width) scroll.x = bounds.Right - _width
			If (scroll.y < bounds.Top) scroll.y = bounds.Top
			If (scroll.y > bounds.Bottom - _height) scroll.y = bounds.Bottom - _height
		End If

		If (_fxFlashAlpha > 0) Then
			_fxFlashAlpha -= FlxG.Elapsed / _fxFlashDuration

			If (_fxFlashAlpha <= 0 And _fxFlashComplete <> Null) Then
				_fxFlashComplete.OnFlashComplete()
				_fxFlashComplete = Null
			End If
		End If

		If (_fxFadeAlpha > 0 And _fxFadeAlpha < 1) Then
			_fxFadeAlpha += FlxG.Elapsed / _fxFadeDuration

			If (_fxFadeAlpha >= 1) Then
				_fxFadeAlpha = 1
				If (_fxFadeComplete <> Null) Then
					_fxFadeComplete.OnFadeComplete()
					_fxFadeComplete = Null
				End If
			End If
		End If

		If (_fxShakeDuration > 0) Then
			_fxShakeDuration -= FlxG.Elapsed
			If (_fxShakeDuration <= 0) Then
				_fxShakeOffset.Make()

				If (_fxShakeComplete <> Null) Then
					_fxShakeComplete.OnShakeComplete()
					_fxShakeComplete = Null
				End If
			Else
				If (_fxShakeDirection = SHAKE_BOTH_AXES Or _fxShakeDirection = SHAKE_HORIZONTAL_ONLY) Then
					_fxShakeOffset.x = (FlxG.Random() * _fxShakeIntensity * _width * 2 - _fxShakeIntensity * _width) * _zoom
				End If

				If (_fxShakeDirection = SHAKE_BOTH_AXES Or _fxShakeDirection = SHAKE_VERTICAL_ONLY) Then
					_fxShakeOffset.y = (FlxG.Random() * _fxShakeIntensity * _height * 2 - _fxShakeIntensity * _height) * _zoom
				End If
			End If
		End If
	End Method

	Method Follow:Void(target:FlxObject, style:Int = STYLE_LOCKON)
		Self.target = target
		Local helper:Float

		Select (style)
			Case STYLE_PLATFORMER
				Local w:Float = _width / 8
				Local h:Float = _height / 3
				deadzone = New FlxRect((_width - w) / 2, (_height - h) / 2 - h * .25, w, h)

			Case STYLE_TOPDOWN
				helper = Max(_width, _height) / 4
				deadzone = New FlxRect((_width - helper) / 2, (_height - helper) / 2, helper, helper)

			Case STYLE_TOPDOWN_TIGHT
				helper = Max(_width, _height) / 8
				deadzone = New FlxRect((_width - helper) / 2, (_height - helper) / 2, helper, helper)

			Case STYLE_LOCKON
				deadzone = Null

			Default
				deadzone = Null
		End Select
	End Method

	Method FocusOn:Void(point:FlxPoint)
		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

		scroll.Make(point.x - _width * .5, point.y - _height * .5)
	End Method

	Method SetBounds:Void(x:Float = 0, y:Float = 0, width:Float = 0, height:Float = 0, updateWorld:Bool = False)
		If (bounds = Null) bounds = New FlxRect()
		bounds.Make(x, y, width, height)
		If (updateWorld) FlxG.WorldBounds.CopyFrom(bounds)
		Update()
	End Method

	Method Flash:Void(color:Int = FlxG.WHITE, duration:Float = 1, onComplete:FlxCameraFlashListener = Null, force:Bool = False)
		If (Not force And _fxFlashAlpha > 0) Return

		_fxFlashColor = color
		If (duration <= 0) duration = _MIN_FLOAT_VALUE
		_fxFlashDuration = duration
		_fxFlashComplete = onComplete
		_fxFlashAlpha = 1
	End Method

	Method Fade:Void(color:Int = FlxG.BLACK, duration:Float = 1, onComplete:FlxCameraFadeListener = Null, force:Bool = False)
		If (Not force And _fxFadeAlpha > 0)	Return

		_fxFadeColor = color
		If (duration <= 0) duration = _MIN_FLOAT_VALUE
		_fxFadeDuration = duration
		_fxFadeComplete = onComplete
		_fxFadeAlpha = _MIN_FLOAT_VALUE
	End Method

	Method Shake:Void(intensity:Float = 0.05, duration:Float = 0.5, onComplete:FlxCameraShakeListener = Null, force:Bool = True, direction:Int = SHAKE_BOTH_AXES)
		If (Not force And (_fxShakeOffset.x <> 0 Or _fxShakeOffset.y <> 0)) Return

		_fxShakeIntensity = intensity
		_fxShakeDuration = duration
		_fxShakeComplete = onComplete
		_fxShakeDirection = direction
		_fxShakeOffset.Make()
	End Method

	Method StopFX:Void()
		_fxFlashAlpha = 0
		_fxFadeAlpha = 0
		_fxShakeDuration = 0
		_fxShakeOffset.x = 0
		_fxShakeOffset.y = 0
	End Method

	Method CopyFrom:FlxCamera(camera:FlxCamera)
		If (camera.bounds = Null) Then
			bounds = camera.bounds
		Else
			If (bounds = Null) bounds = New FlxRect()
			bounds.CopyFrom(camera.bounds)
		End If

		target = camera.target
		If (target <> Null) Then
			If (camera.deadzone = Null) Then
				deadzone = Null
			Else
				If (deadzone = Null) deadzone = New FlxRect()
				deadzone.CopyFrom(camera.deadzone)
			End If
		End If

		Return Self
	End Method

	Method X:Float() Property
		Return _x
	End Method

	Method X:Void(x:Float) Property
		_x = x
		_realX = _x * FlxG._DeviceScaleFactorX

		_clipped = _IsClipped()
	End Method

	Method Y:Float() Property
		Return _y
	End Method

	Method Y:Void(y:Float) Property
		_y = y
		_realY = _y * FlxG._DeviceScaleFactorY

		_clipped = _IsClipped()
	End Method

	Method Width:Float() Property
		Return _width
	End Method

	Method Width:Void(width:Float) Property
		_width = width
		_realWidth = Min(Float(FlxG.DeviceWidth), Floor(_width * _scaleX * FlxG._DeviceScaleFactorX))

		_clipped = _IsClipped()
	End Method

	Method Height:Float() Property
		Return _height
	End Method

	Method Height:Void(height:Float) Property
		_height = height
		_realHeight = Min(Float(FlxG.DeviceHeight), Floor(_height * _scaleY * FlxG._DeviceScaleFactorY))

		_clipped = _IsClipped()
	End Method

	Method Zoom:Float() Property
		Return _zoom
	End Method

	Method Zoom:Void(zoom:Float) Property
		If (zoom = 0) Then
			_zoom = FlxCamera.DefaultZoom
		Else
			_zoom = zoom
		End If

		SetScale(_zoom, _zoom)
	End Method

	Method Alpha:Float() Property
		Return _alpha
	End Method

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

	Method Angle:Float() Property
		Return _angle
	End Method

	Method Angle:Void(angle:Float) Property
		_angle = angle
	End Method

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

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

	Method BgColor:Int() Property
		Return _bgColor.argb
	End Method

	Method BgColor:Void(color:Int) Property
		_bgColor.SetARGB(color)
	End Method

	Method GetScale:FlxPoint()
		Return _point.Make(_scaleX, _scaleY)
	End Method

	Method SetScale:Void(x:Float, y:Float)
		_scaleX = x
		_scaleY = y
		_realWidth = Min(Float(FlxG.DeviceWidth), Floor(_width * _scaleX * FlxG._DeviceScaleFactorX))
		_realHeight = Min(Float(FlxG.DeviceHeight), Floor(_height * _scaleY * FlxG._DeviceScaleFactorY))
	End Method

	Method Fill:Void(color:Int, blendAlpha:Bool = True)
		If (blendAlpha) Then
			_fill.SetARGB(color)
		Else
			_fill.SetRGB(color)
		End If
	End Method

	Method DrawFX:Void()
		If (_fxFlashAlpha > 0) Then
			Local alphaComponent:Float

			alphaComponent = _fxFlashColor Shr 24
			If (alphaComponent <= 0) alphaComponent = $FF
			Fill(((alphaComponent * _fxFlashAlpha) Shl 24) + (_fxFlashColor & $00FFFFFF))
		End If

		If (_fxFadeAlpha > 0) Then
			Local alphaComponent:Float

			alphaComponent = _fxFadeColor Shr 24
			If (alphaComponent <= 0) alphaComponent = $FF
			Fill(((alphaComponent * _fxFadeAlpha) Shl 24) + (_fxFadeColor & $00FFFFFF))
		End If
	End Method

	Method ID:Int() Property
		Return _id
	End Method

	Method ToString:String()
		Return "FlxCamera"
	End Method

Private
	Method _IsClipped:Bool()
		Return _realX <> 0 Or _realY <> 0 Or _realWidth <> FlxG.DeviceWidth Or _realHeight <> FlxG.DeviceHeight
	End Method

End Class

Interface FlxCameraFlashListener

	Method OnFlashComplete:Void()

End Interface

Interface FlxCameraFadeListener

	Method OnFadeComplete:Void()

End Interface

Interface FlxCameraShakeListener

	Method OnShakeComplete:Void()

End Interface

Private
Class FlxCameraClass Implements FlxClass

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

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

End Class

Strict

Import flxextern
Import flxpoint
Import flxrect
Import flxbasic
Import flxobject
Import flxg

Import system.flxcolor

Class FlxCamera Extends FlxBasic

	Global ClassObject:FlxClass = New FlxCameraClass()

	Const STYLE_LOCKON:Int = 0

	Const STYLE_PLATFORMER:Int = 1

	Const STYLE_TOPDOWN:Int = 2

	Const STYLE_TOPDOWN_TIGHT:Int = 3

	Const SHAKE_BOTH_AXES:Int = 0

	Const SHAKE_HORIZONTAL_ONLY:Int = 1

	Const SHAKE_VERTICAL_ONLY:Int  = 2

	Global DefaultZoom:Float

	Field target:FlxObject

	Field deadzone:FlxRect

	Field bounds:FlxRect

	Field scroll:FlxPoint

	Field _color:FlxColor

Private
	Const _MIN_FLOAT_VALUE:Float = .0000001

	Field _x:Float

	Field _y:Float

	Field _realX:Float

	Field _realY:Float

	Field _width:Float

	Field _height:Float

	Field _realWidth:Float

	Field _realHeight:Float

	Field _zoom:Float

	Field _point:FlxPoint

	Field _alpha:Float

	Field _scaleX:Float

	Field _scaleY:Float

	Field _angle:Float

	Field _clipped:Bool

	Field _bgColor:FlxColor

	Field _fxFlashColor:Int

	Field _fxFlashDuration:Float

	Field _fxFlashComplete:FlxCameraFlashListener

	Field _fxFlashAlpha:Float

	Field _fxFadeColor:Int

	Field _fxFadeDuration:Float

	Field _fxFadeComplete:FlxCameraFadeListener

	Field _fxFadeAlpha:Float

	Field _fxShakeIntensity:Float

	Field _fxShakeDuration:Float

	Field _fxShakeComplete:FlxCameraShakeListener

	Field _fxShakeOffset:FlxPoint

	Field _fxShakeDirection:Int

	Field _fill:FlxColor

	Field _id:Int

	Global _Inkrement:Int

Public
	Method New(x:Int, y:Int, width:Int, height:Int, zoom:Float = 0)
		Zoom = zoom 'must be first for init
		X = x
		Y = y
		Width = width
		Height = height
		target = Null
		deadzone = Null
		scroll = New FlxPoint()
		_point = New FlxPoint()
		bounds = Null
		_bgColor = New FlxColor(FlxG.BgColor())
		_color = New FlxColor()
		_alpha = 1

		_fxFlashColor = 0
		_fxFlashDuration = 0
		_fxFlashComplete = null
		_fxFlashAlpha = 0

		_fxFadeColor = 0
		_fxFadeDuration = 0
		_fxFadeComplete = Null
		_fxFadeAlpha = 0

		_fxShakeIntensity = 0
		_fxShakeDuration = 0
		_fxShakeComplete = Null
		_fxShakeOffset = New FlxPoint()
		_fxShakeDirection = 0

		active = True

		_fill = New FlxColor(0)

		_id = _Inkrement
		_Inkrement += 1
	End Method

	Method Destroy:Void()
		target = Null
		scroll = Null
		deadzone = Null
		bounds = Null
		_color = Null
		_bgColor = Null
		_fxFlashComplete = Null
		_fxFadeComplete = Null
		_fxShakeComplete = Null
		_fxShakeOffset = Null
		_fill = Null
	End Method

	Method Lock:Void()
		If (_clipped) Then
			SetScissor(_realX + _fxShakeOffset.x * FlxG._DeviceScaleFactorX, _realY + _fxShakeOffset.y * FlxG._DeviceScaleFactorY, _realWidth, _realHeight)
		End If

		PushMatrix()

		Translate(_x + _fxShakeOffset.x, _y + _fxShakeOffset.y)
		Scale(_scaleX, _scaleY)

		If (_clipped Or _bgColor.argb <> FlxG._BgColor.argb)
			SetColor(_bgColor.r, _bgColor.g, _bgColor.b)
			DrawRect(0, 0, _width, _height)
			FlxG._LastDrawingColor = _bgColor.argb
		End If
	End Method

	Method Unlock:Void()
		If (_fill.argb <> 0) Then
			If (_fill.argb <> FlxG._LastDrawingColor) Then
				SetColor(_fill.r, _fill.g, _fill.b)
				FlxG._LastDrawingColor = _fill.argb
			End if

			If (FlxG._LastDrawingAlpha <> _fill.a) Then
				SetAlpha(_fill.a)
				FlxG._LastDrawingAlpha = _fill.a
			End If

			DrawRect(0, 0, _width, _height)
		End If

		PopMatrix()
		_fill.SetARGB(0)

		If (_clipped) Then
			SetScissor(0, 0, FlxG.DeviceWidth, FlxG.DeviceHeight)
		End If
	End Method

	Method Update:Void()
		If (target <> Null) Then
			If (deadzone = Null) Then
				FocusOn(target.GetMidpoint(_point))
			Else
				Local edge:Float
				Local targetX:Float
				Local targetY:Float

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

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

				edge = targetX - deadzone.x
				If (scroll.x > edge) scroll.x = edge
				edge = targetX + target.width - deadzone.x - deadzone.width
				If (scroll.x < edge) scroll.x = edge

				edge  = targetY - deadzone.y
				If (scroll.y > edge) scroll.y = edge
				edge = targetY + target.height - deadzone.y - deadzone.height
				If (scroll.y < edge) scroll.y = edge
			End If
		End If

		If (bounds <> Null) Then
			If (scroll.x < bounds.Left) scroll.x = bounds.Left
			If (scroll.x > bounds.Right - _width) scroll.x = bounds.Right - _width
			If (scroll.y < bounds.Top) scroll.y = bounds.Top
			If (scroll.y > bounds.Bottom - _height) scroll.y = bounds.Bottom - _height
		End If

		If (_fxFlashAlpha > 0) Then
			_fxFlashAlpha -= FlxG.Elapsed / _fxFlashDuration

			If (_fxFlashAlpha <= 0 And _fxFlashComplete <> Null) Then
				_fxFlashComplete.OnFlashComplete()
			End If
		End If

		If (_fxFadeAlpha > 0 And _fxFadeAlpha < 1) Then
			_fxFadeAlpha += FlxG.Elapsed / _fxFadeDuration

			If (_fxFadeAlpha >= 1) Then
				_fxFadeAlpha = 1
				If (_fxFadeComplete <> Null) _fxFadeComplete.OnFadeComplete()
			End If
		End If

		If (_fxShakeDuration > 0) Then
			_fxShakeDuration -= FlxG.Elapsed
			If (_fxShakeDuration <= 0) Then
				_fxShakeOffset.Make()

				If (_fxShakeComplete <> Null) _fxShakeComplete.OnShakeComplete()
			Else
				If (_fxShakeDirection = SHAKE_BOTH_AXES Or _fxShakeDirection = SHAKE_HORIZONTAL_ONLY) Then
					_fxShakeOffset.x = (FlxG.Random() * _fxShakeIntensity * _width * 2 - _fxShakeIntensity * _width) * _zoom
				End If

				If (_fxShakeDirection = SHAKE_BOTH_AXES Or _fxShakeDirection = SHAKE_VERTICAL_ONLY) Then
					_fxShakeOffset.y = (FlxG.Random() * _fxShakeIntensity * _height * 2 - _fxShakeIntensity * _height) * _zoom
				End If
			End If
		End If
	End Method

	Method Follow:Void(target:FlxObject, style:Int = STYLE_LOCKON)
		Self.target = target
		Local helper:Float

		Select (style)
			Case STYLE_PLATFORMER
				Local w:Float = _width / 8
				Local h:Float = _height / 3
				deadzone = New FlxRect((_width - w) / 2, (_height - h) / 2 - h * .25, w, h)

			Case STYLE_TOPDOWN
				helper = Max(_width, _height) / 4
				deadzone = New FlxRect((_width - helper) / 2, (_height - helper) / 2, helper, helper)

			Case STYLE_TOPDOWN_TIGHT
				helper = Max(_width, _height) / 8
				deadzone = New FlxRect((_width - helper) / 2, (_height - helper) / 2, helper, helper)

			Case STYLE_LOCKON
				deadzone = Null

			Default
				deadzone = Null
		End Select
	End Method

	Method FocusOn:Void(point:FlxPoint)
		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

		scroll.Make(point.x - _width * .5, point.y - _height * .5)
	End Method

	Method SetBounds:Void(x:Float = 0, y:Float = 0, width:Float = 0, height:Float = 0, updateWorld:Bool = False)
		If (bounds = Null) bounds = New FlxRect()
		bounds.Make(x, y, width, height)
		If (updateWorld) FlxG.WorldBounds.CopyFrom(bounds)
		Update()
	End Method

	Method Flash:Void(color:Int = FlxG.WHITE, duration:Float = 1, onComplete:FlxCameraFlashListener = Null, force:Bool = False)
		If (Not force And _fxFlashAlpha > 0) Return

		_fxFlashColor = color
		If (duration <= 0) duration = _MIN_FLOAT_VALUE
		_fxFlashDuration = duration
		_fxFlashComplete = onComplete
		_fxFlashAlpha = 1
	End Method

	Method Fade:Void(color:Int = FlxG.BLACK, duration:Float = 1, onComplete:FlxCameraFadeListener = Null, force:Bool = False)
		If (Not force And _fxFadeAlpha > 0)	Return

		_fxFadeColor = color
		If (duration <= 0) duration = _MIN_FLOAT_VALUE
		_fxFadeDuration = duration
		_fxFadeComplete = onComplete
		_fxFadeAlpha = _MIN_FLOAT_VALUE
	End Method

	Method Shake:Void(intensity:Float = 0.05, duration:Float = 0.5, onComplete:FlxCameraShakeListener = Null, force:Bool = True, direction:Int = SHAKE_BOTH_AXES)
		If (Not force And (_fxShakeOffset.x <> 0 Or _fxShakeOffset.y <> 0)) Return

		_fxShakeIntensity = intensity
		_fxShakeDuration = duration
		_fxShakeComplete = onComplete
		_fxShakeDirection = direction
		_fxShakeOffset.Make()
	End Method

	Method StopFX:Void()
		_fxFlashAlpha = 0
		_fxFadeAlpha = 0
		_fxShakeDuration = 0
		_fxShakeOffset.x = 0
		_fxShakeOffset.y = 0
	End Method

	Method CopyFrom:FlxCamera(camera:FlxCamera)
		If (camera.bounds = Null) Then
			bounds = camera.bounds
		Else
			If (bounds = Null) bounds = New FlxRect()
			bounds.CopyFrom(camera.bounds)
		End If

		target = camera.target
		If (target <> Null) Then
			If (camera.deadzone = Null) Then
				deadzone = Null
			Else
				If (deadzone = Null) deadzone = New FlxRect()
				deadzone.CopyFrom(camera.deadzone)
			End If
		End If

		Return Self
	End Method

	Method X:Float() Property
		Return _x
	End Method

	Method X:Void(x:Float) Property
		_x = x
		_realX = _x * FlxG._DeviceScaleFactorX

		_clipped = _IsClipped()
	End Method

	Method Y:Float() Property
		Return _y
	End Method

	Method Y:Void(y:Float) Property
		_y = y
		_realY = _y * FlxG._DeviceScaleFactorY

		_clipped = _IsClipped()
	End Method

	Method Width:Float() Property
		Return _width
	End Method

	Method Width:Void(width:Float) Property
		_width = width
		_realWidth = Min(Float(FlxG.DeviceWidth), Floor(_width * _scaleX * FlxG._DeviceScaleFactorX))

		_clipped = _IsClipped()
	End Method

	Method Height:Float() Property
		Return _height
	End Method

	Method Height:Void(height:Float) Property
		_height = height
		_realHeight = Min(Float(FlxG.DeviceHeight), Floor(_height * _scaleY * FlxG._DeviceScaleFactorY))

		_clipped = _IsClipped()
	End Method

	Method Zoom:Float() Property
		Return _zoom
	End Method

	Method Zoom:Void(zoom:Float) Property
		If (zoom = 0) Then
			_zoom = FlxCamera.DefaultZoom
		Else
			_zoom = zoom
		End If

		SetScale(_zoom, _zoom)
	End Method

	Method Alpha:Float() Property
		Return _alpha
	End Method

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

	Method Angle:Float() Property
		Return _angle
	End Method

	Method Angle:Void(angle:Float) Property
		_angle = angle
	End Method

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

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

	Method BgColor:Int() Property
		Return _bgColor.argb
	End Method

	Method BgColor:Void(color:Int) Property
		_bgColor.SetARGB(color)
	End Method

	Method GetScale:FlxPoint()
		Return _point.Make(_scaleX, _scaleY)
	End Method

	Method SetScale:Void(x:Float, y:Float)
		_scaleX = x
		_scaleY = y
		_realWidth = Min(Float(FlxG.DeviceWidth), Floor(_width * _scaleX * FlxG._DeviceScaleFactorX))
		_realHeight = Min(Float(FlxG.DeviceHeight), Floor(_height * _scaleY * FlxG._DeviceScaleFactorY))
	End Method

	Method Fill:Void(color:Int, blendAlpha:Bool = True)
		If (blendAlpha) Then
			_fill.SetARGB(color)
		Else
			_fill.SetRGB(color)
		End If
	End Method

	Method DrawFX:Void()
		If (_fxFlashAlpha > 0) Then
			Local alphaComponent:Float

			alphaComponent = _fxFlashColor Shr 24
			If (alphaComponent <= 0) alphaComponent = $FF
			Fill(((alphaComponent * _fxFlashAlpha) Shl 24) + (_fxFlashColor & $00FFFFFF))
		End If

		If (_fxFadeAlpha > 0) Then
			Local alphaComponent:Float

			alphaComponent = _fxFadeColor Shr 24
			If (alphaComponent <= 0) alphaComponent = $FF
			Fill(((alphaComponent * _fxFadeAlpha) Shl 24) + (_fxFadeColor & $00FFFFFF))
		End If
	End Method

	Method ID:Int() Property
		Return _id
	End Method

	Method ToString:String()
		Return "FlxCamera"
	End Method

Private
	Method _IsClipped:Bool()
		Return _realX <> 0 Or _realY <> 0 Or _realWidth <> FlxG.DeviceWidth Or _realHeight <> FlxG.DeviceHeight
	End Method

End Class

Interface FlxCameraFlashListener

	Method OnFlashComplete:Void()

End Interface

Interface FlxCameraFadeListener

	Method OnFadeComplete:Void()

End Interface

Interface FlxCameraShakeListener

	Method OnShakeComplete:Void()

End Interface

Private
Class FlxCameraClass Implements FlxClass

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

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

End Class


Added FLX_DEBUG_ENABLED config setting

Added FLX_DEBUG_ENABLED config setting

#REFLECTION_FILTER += "flixel.flx*|flixel.plugin*"

#If CONFIG = "debug"
	#FLX_DEBUG_ENABLED = True
#Else
	#FLX_DEBUG_ENABLED = False
#End

#FLX_WEBGL_ENABLED  = False

#REFLECTION_FILTER += "flixel.flx*|flixel.plugin*"

#FLX_WEBGL_ENABLED  =False


FlxSprite OnScreen fixed

FlxSprite OnScreen 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

		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

		If (Not OnScreen(FlxG._CurrentCamera)) Return

		If (dirty) _CalcFrame()

		_camera = FlxG._CurrentCamera

		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:FlxAnimationCallback)
		_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

		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

		If (Not OnScreen(FlxG._CurrentCamera)) Return

		If (dirty) _CalcFrame()

		_camera = FlxG._CurrentCamera

		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:FlxAnimationCallback)
		_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)
		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


spacing

spacing

let reduce = fn(arr, initial, f) {
    let iter = fn(arr, result) {
        if (len(arr) == 0) {
            result
        } else {
            iter(tail(arr) , f(result , first (arr)))
        }
    };
    iter(arr, initial);
};

let sum = fn(arr) {
    reduce(arr, 0, fn(initial, el) {
        initial + el
    });
};

let array = [1, 2, 3, 4, 5];
let sum = sum(array);
putln("Sum: " + sum);
putln(push(array, 6));

let addNums = fn(x, y) {
    return x + y;
}

let a = 3;
if(true) {
    let a = a + 2;
    putln(a);
}
putln(a);
putln();

let fizz = fn(num) { num % 3 == 0 };
let buzz = fn(num) { num % 5 == 0 };
let num = 1;
while(num <= 100) {
    if(fizz(num)) {
        put("fizz");
    }
    if (buzz(num)) {
        put("buzz");
    }
    if(!fizz(num) && !buzz(num)) {
        put(num);
    }
    putln();
    ++num;
}

let reduce = fn (arr, initial, f) {
    let iter = fn (arr, result) {
        if (len(arr) == 0) {
            result
        } else {
            iter(tail(arr) , f(result , first (arr)))
        }
    };
    iter(arr, initial);
};

let sum = fn(arr) {
    reduce(arr, 0, fn(initial, el) {
        initial + el
    });
};

let array = [1, 2, 3, 4, 5];
let sum = sum(array);
putln("Sum: " + sum);
putln(push(array, 6));

let addNums = fn(x, y) {
    return x + y;
}

let a = 3;
if(true) {
    let a = a + 2;
    putln(a);
}
putln(a);
putln();

let fizz = fn(num) { num % 3 == 0 };
let buzz = fn(num) { num % 5 == 0 };
let num = 1;
while(num <= 100) {
    if(fizz(num)) {
        put("fizz");
    }
    if (buzz(num)) {
        put("buzz");
    }
    if(!fizz(num) && !buzz(num)) {
        put(num);
    }
    putln();
    ++num;
}


Improvement FlxText.DrawDebug

Improvement FlxText.DrawDebug

Strict

Import flxextern
Import flxpoint
Import flxg

Import flixel.system.flxcolor

Import flixel.plugin.debugpathdisplay

Class FlxPath

	Global ClassObject:FlxClass = new FlxObjectClass()

	Field nodes:Stack<FlxPoint>

	Field debugColor:Int

	Field debugScrollFactor:FlxPoint

	Field ignoreDrawDebug:Bool

Private
	Field _point:FlxPoint

	Field _debugNodeColor:FlxColor

Public
	Method New(nodes:Stack<FlxPoint> = Null)
		If (nodes = Null) Then
			Self.nodes = New Stack<FlxPoint>()
		Else
			Self.nodes = nodes
		End if

		_point = New FlxPoint()
		debugScrollFactor = New FlxPoint(1.0, 1.0)
		debugColor = FlxG.WHITE
		ignoreDrawDebug = False

		Local debugPathDisplay:DebugPathDisplay = Manager()
		If (debugPathDisplay <> Null) debugPathDisplay.Add(Self)
	End Method

	Method Destroy:Void()
		Local debugPathDisplay:DebugPathDisplay = Manager()
		If (debugPathDisplay <> Null) debugPathDisplay.Remove(Self)

		debugScrollFactor = Null
		_point = Null
		nodes = Null
		_debugNodeColor = Null
	End Method

	Method Add:Void(x:Float, y:Float)
		nodes.Push(New FlxPoint(x, y))
	End Method

	Method AddAt:Void(x:Float, y:Float, index:Int)
		If (index > nodes.Length()) index = nodes.Length()
		nodes.Insert(index, New FlxPoint(x, y))
	End Method

	Method AddPoint:Void(node:FlxPoint, asReference:Bool = False)
		If (asReference) Then
			nodes.Push(node)
		Else
			nodes.Push(New FlxPoint(node.x, node.y))
		End If
	End Method

	Method AddPointAt:Void(node:FlxPoint, index:Int, asReference:Bool = False)
		If (index > nodes.Length()) index = nodes.Length()

		If (asReference) Then
			nodes.Insert(i, node)
		Else
			nodes.Insert(i, New FlxPoint(node.x, node.y))
		End If
	End Method

	Method Remove:FlxPoint(node:FlxPoint)
		Local i:Int = 0
		Local l:Int = nodes.Length()
		Local point:FlxPoint

		While (i < l)
			point = nodes.Get(i)
			If (point = node) Exit
			i += 1
		Wend

		nodes.Remove(i)
		Return point
	End Method

	Method RemoveAt:FlxPoint(index:Int)
		If (nodes.Length() <= 0) Return Null
		If (index >= nodes.Length()) index = nodes.Length() - 1

		Local point:FlxPoint = nodes.Get(i)
		nodes.Remove(i)
		Return point
	End Method

	Method Head:FlxPoint()
		If (nodes.Length() > 0) Return nodes.Get(0)
		Return Null
	End Method

	Method Tail:FlxPoint()
		If (nodes.Length() > 0) Return nodes.Top()
		Return Null
	End Method

	Method DrawDebug:Void(camera:FlxCamera = Null)
		If (nodes.Length() <= 0) Return
		If (camera = Null) camera = FlxG.Camera

		Local node:FlxPoint
		Local nextNode:FlxPoint
		Local i:Int = 0
		Local l:Int = nodes.Length()

		Local fromX:Float
		Local fromY:Float

		While(i < l)
			node = nodes.Get(i)

			_point.x = node.x - Int(camera.scroll.x * debugScrollFactor.x)
			_point.y = node.y - Int(camera.scroll.y * debugScrollFactor.y)

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

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

			Local nodeSize:Int = 2
			If (i = 0 Or i = l - 1) nodeSize *= 2

			If (_debugNodeColor = Null) _debugNodeColor = New FlxColor()
			_debugNodeColor.SetARGB(FlxG.WHITE)

			If (l > 1) Then
				If (i = 0) Then
					_debugNodeColor.SetARGB(FlxG.GREEN)

				ElseIf (i = l -1) Then
					_debugNodeColor.SetARGB(FlxG.RED)
				End If
			End If

			SetAlpha(.5)

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

			DrawRect(_point.x - nodeSize * 0.5, _point.y - nodeSize * 0.5, nodeSize, nodeSize)

			If (i = l - 1) Exit

			Local linealpha:Float = .3

			nextNode = nodes.Get(i + 1)

			_debugNodeColor.SetARGB(debugColor)

			SetAlpha(linealpha)

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

			fromX = _point.x
			fromY = _point.y

			_point.x = nextNode.x - Int(camera.scroll.x * debugScrollFactor.x)
			_point.y = nextNode.y - Int(camera.scroll.y * debugScrollFactor.y)

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

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

			DrawLine(fromX, fromY, _point.x, _point.y)

			i += 1
		Wend

		SetAlpha(1)
	End Method

	Function Manager:DebugPathDisplay()
		Return DebugPathDisplay(FlxG.GetPlugin(DebugPathDisplay.ClassObject))
	End Function

End Class

Strict

Import flxextern
Import flxpoint
Import flxg

Import flixel.system.flxcolor

Import flixel.plugin.debugpathdisplay

Class FlxPath

	Global ClassObject:FlxClass = new FlxObjectClass()

	Field nodes:Stack<FlxPoint>

	Field debugColor:Int

	Field debugScrollFactor:FlxPoint

	Field ignoreDrawDebug:Bool

Private
	Field _point:FlxPoint

	Field _debugNodeColor:FlxColor

Public
	Method New(nodes:Stack<FlxPoint> = Null)
		If (nodes = Null) Then
			Self.nodes = New Stack<FlxPoint>()
		Else
			Self.nodes = nodes
		End if

		_point = New FlxPoint()
		debugScrollFactor = New FlxPoint(1.0, 1.0)
		debugColor = FlxG.WHITE
		ignoreDrawDebug = False

		Local debugPathDisplay:DebugPathDisplay = Manager()
		If (debugPathDisplay <> Null) debugPathDisplay.Add(Self)
	End Method

	Method Destroy:Void()
		Local debugPathDisplay:DebugPathDisplay = Manager()
		If (debugPathDisplay <> Null) debugPathDisplay.Remove(Self)

		debugScrollFactor = Null
		_point = Null
		nodes = Null
		_debugNodeColor = Null
	End Method

	Method Add:Void(x:Float, y:Float)
		nodes.Push(New FlxPoint(x, y))
	End Method

	Method AddAt:Void(x:Float, y:Float, index:Int)
		If (index > nodes.Length()) index = nodes.Length()
		nodes.Insert(index, New FlxPoint(x, y))
	End Method

	Method AddPoint:Void(node:FlxPoint, asReference:Bool = False)
		If (asReference) Then
			nodes.Push(node)
		Else
			nodes.Push(New FlxPoint(node.x, node.y))
		End If
	End Method

	Method AddPointAt:Void(node:FlxPoint, index:Int, asReference:Bool = False)
		If (index > nodes.Length()) index = nodes.Length()

		If (asReference) Then
			nodes.Insert(i, node)
		Else
			nodes.Insert(i, New FlxPoint(node.x, node.y))
		End If
	End Method

	Method Remove:FlxPoint(node:FlxPoint)
		Local i:Int = 0
		Local l:Int = nodes.Length()
		Local point:FlxPoint

		While (i < l)
			point = nodes.Get(i)
			If (point = node) Exit
			i += 1
		Wend

		nodes.Remove(i)
		Return point
	End Method

	Method RemoveAt:FlxPoint(index:Int)
		If (nodes.Length() <= 0) Return Null
		If (index >= nodes.Length()) index = nodes.Length() - 1

		Local point:FlxPoint = nodes.Get(i)
		nodes.Remove(i)
		Return point
	End Method

	Method Head:FlxPoint()
		If (nodes.Length() > 0) Return nodes.Get(0)
		Return Null
	End Method

	Method Tail:FlxPoint()
		If (nodes.Length() > 0) Return nodes.Top()
		Return Null
	End Method

	Method DrawDebug:Void(camera:FlxCamera = Null)
		If (nodes.Length() <= 0) Return
		If (camera = Null) camera = FlxG.Camera

		Local node:FlxPoint
		Local nextNode:FlxPoint
		Local i:Int = 0
		Local l:Int = nodes.Length()

		Local fromX:Float
		Local fromY:Float

		While(i < l)
			node = nodes.Get(i)

			_point.x = node.x - Int(camera.scroll.x * debugScrollFactor.x)
			_point.y = node.y - Int(camera.scroll.y * debugScrollFactor.y)

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

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

			Local nodeSize:Int = 2
			If (i = 0 Or i = l - 1) nodeSize *= 2

			If (_debugNodeColor = Null) _debugNodeColor = New FlxColor()
			_debugNodeColor.SetARGB(FlxG.WHITE)

			If (l > 1) Then
				If (i = 0) Then
					_debugNodeColor.SetARGB(FlxG.GREEN)

				ElseIf (i = l -1) Then
					_debugNodeColor.SetARGB(FlxG.RED)
				End If
			End If

			SetAlpha(.5)

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

			DrawRect(_point.x - nodeSize * 0.5, _point.y - nodeSize * 0.5, nodeSize, nodeSize)

			If (i = l - 1) Exit

			Local linealpha:Float = .3

			If (i < l - 1) Then
				nextNode = nodes.Get(i + 1)
			Else
				nextNode = nodes.Get(0)
				linealpha = .15
			End If

			_debugNodeColor.SetARGB(debugColor)

			SetAlpha(linealpha)

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

			fromX = _point.x
			fromY = _point.y

			_point.x = nextNode.x - Int(camera.scroll.x * debugScrollFactor.x)
			_point.y = nextNode.y - Int(camera.scroll.y * debugScrollFactor.y)

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

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

			DrawLine(fromX, fromY, _point.x, _point.y)

			i += 1
		Wend

		SetAlpha(1)
	End Method

	Function Manager:DebugPathDisplay()
		Return DebugPathDisplay(FlxG.GetPlugin(DebugPathDisplay.ClassObject))
	End Function

End Class