Small fixes

Small fixes

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.Get(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.Get(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.Get(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.Remove(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 Remove: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 Get: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.Get(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.Get(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.Get(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.Remove(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()
		_signal = Null
		_listener = Null
	End Method

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

		_listener.OnSignalEmitted(_signal, data)
	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

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 Remove: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 Get: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


Moved the preprocessor checks in 'filestream' below the imports.

Strict

Public

#Rem
	This acts as a compatibility-layer with the official 'brl' implementation.

	This API intends to be as accurate as possible, allowing
	users to build consistent codebases between platforms.

	ATTENTION: This sub-module does not follow the "standalone" behavioral
	rules applied to the other modules.

	To use this sub-module, you must have the 'regal.ioutil.publicdatastream'
	module installed, and any dependencies it requires.

	In addition, this uses both the standard 'brl.stream' module,
	as well as the internal file-system modules/extensions.
#End

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

Import regal.ioutil.publicdatastream

Import filesystem
Import legend

Public

' Preprocessor related:
#If VIRTUALOS_CREATEFILE_IMPLEMENTED And (VIRTUALOS_EXTENSION_LOADBUFFER Or VIRTUALOS_EXTENSION_SAVEBUFFER)
	#VIRTUALOS_FILESTREAM_IMPLEMENTED = True
#End

#If VIRTUALOS_EXTENSION_LOADBUFFER
	#VIRTUALOS_FILESTREAM_CAN_LOAD = True
#End

#If VIRTUALOS_EXTENSION_SAVEBUFFER
	VIRTUALOS_FILESTREAM_CAN_SAVE = True
#End

#If VIRTUALOS_FILESTREAM_IMPLEMENTED
	' Classes:
	Class FileStream Extends PublicDataStream
		' Constant variable(s):

		' Defaults:
		Const Default_Size:= 4096 ' 4KB

		' Functions:
		Function Open:FileStream(Path:String, Mode:String)
			Try
				Return New FileStream(Path, Mode)
			Catch E:StreamError
				' Nothing so far.
			End

			Return Null
		End

		' Constructor(s) (Public):
		Method New(Path:String, Mode:String, Size:Int=Default_Size, FixByteOrder:Bool=Default_BigEndianStorage, SizeLimit:Int=NOLIMIT)
			Super.New(Size, FixByteOrder, True, SizeLimit)

			EstablishStream(Path, Mode)
		End

		' Constructor(s) (Protected):
		Protected

		Method EstablishStream:Void(Path:String, Mode:String)
			Select Mode
				#If VIRTUALOS_FILESTREAM_CAN_LOAD
					Case "r", "u"
						ReadFileData(RealPath(Path), True)
					Case "a"
						ReadFileData(RealPath(Path), False)
				#End

				#If VIRTUALOS_FILESTREAM_CAN_SAVE
					Case "w"
						CreateFile(Path)
				#End

				Default
					Throw New FileStreamOpenException("Invalid file-mode detected.", Path, Self)
			End Select

			Self.Path = Path
			Self.Mode = Mode

			Return
		End

		Public

		' Methods (Public):
		Method Close:Void()
			#If VIRTUALOS_FILESTREAM_CAN_SAVE
				If (IsOutputStream) Then
					' Push data to the file-system.
					WriteFileData(RealPath(Self.Path))
				Endif
			#End

			' Close the stream properly.
			Super.Close()

			Return
		End

		' Methods (Protected):
		Protected

		#If VIRTUALOS_FILESTREAM_CAN_LOAD
			Method ReadFileData:DataBuffer(RealPath:String, ResetPosition:Bool=True)
				Local Contents:= __OS_LoadBuffer(RealPath)

				If (Contents = Null) Then
					Return Null
				Endif

				Local Position:= Self.Position

				WriteAll(Contents, 0, Contents.Length)

				If (ResetPosition) Then
					Seek(Position)
				Endif

				Return Contents
			End
		#End

		#If VIRTUALOS_FILESTREAM_CAN_SAVE
			Method WriteFileData:Bool(RealPath:String)
				Local Output:= New DataBuffer(Self.Length)

				Self.Data.CopyBytes(Offset, Output, 0, Length)

				If (Not __OS_SaveBuffer(RealPath, Output)) Then
					Return False
				Endif

				'Output.Discard()

				' Return the default response.
				Return True
			End
		#End

		Public

		' Properties:
		Method IsInputStream:Bool() Property
			#If VIRTUALOS_FILESTREAM_CAN_LOAD
				Return (Mode = "r")
			#Else
				Return False
			#End
		End

		Method IsOutputStream:Bool() Property
			#If VIRTUALOS_FILESTREAM_CAN_SAVE
				Return (Mode = "w" Or Mode = "a" Or Mode = "u") ' (Not IsInputStream)
			#Else
				Return False
			#End
		End

		' Fields (Protected):
		Protected

		Field Path:String, Mode:String

		Public
	End
#End

' Exceptions:
Class FileStreamOpenException Extends StreamError
	' Constructor(s):
	Method New(Message:String, Path:String, FS:FileStream)
		Super.New(FS)

		Self.Message = Message
	End

	' Methods:
	Method ToString:String() ' Property
		Return Message
	End

	' Fields (Protected):
	Protected

	Field Message:String

	Public
End

Strict

Public

#Rem
	This acts as a compatibility-layer with the official 'brl' implementation.

	This API intends to be as accurate as possible, allowing
	users to build consistent codebases between platforms.

	ATTENTION: This sub-module does not follow the "standalone" behavioral
	rules applied to the other modules.

	To use this sub-module, you must have the 'regal.ioutil.publicdatastream'
	module installed, and any dependencies it requires.

	In addition, this uses both the standard 'brl.stream' module,
	as well as the internal file-system modules/extensions.
#End

' Preprocessor related:
#If VIRTUALOS_CREATEFILE_IMPLEMENTED And (VIRTUALOS_EXTENSION_LOADBUFFER Or VIRTUALOS_EXTENSION_SAVEBUFFER)
	#VIRTUALOS_FILESTREAM_IMPLEMENTED = True
#End

#If VIRTUALOS_EXTENSION_LOADBUFFER
	#VIRTUALOS_FILESTREAM_CAN_LOAD = True
#End

#If VIRTUALOS_EXTENSION_SAVEBUFFER
	VIRTUALOS_FILESTREAM_CAN_SAVE = True
#End

' Imports (Public):
Import brl.stream

' Imports (Private):
Private

#If VIRTUALOS_FILESTREAM_IMPLEMENTED
	Import regal.ioutil.publicdatastream

	Import filesystem
	Import legend
#End

Public

#If VIRTUALOS_FILESTREAM_IMPLEMENTED
	' Classes:
	Class FileStream Extends PublicDataStream
		' Constant variable(s):

		' Defaults:
		Const Default_Size:= 4096 ' 4KB

		' Functions:
		Function Open:FileStream(Path:String, Mode:String)
			Try
				Return New FileStream(Path, Mode)
			Catch E:StreamError
				' Nothing so far.
			End

			Return Null
		End

		' Constructor(s) (Public):
		Method New(Path:String, Mode:String, Size:Int=Default_Size, FixByteOrder:Bool=Default_BigEndianStorage, SizeLimit:Int=NOLIMIT)
			Super.New(Size, FixByteOrder, True, SizeLimit)

			EstablishStream(Path, Mode)
		End

		' Constructor(s) (Protected):
		Protected

		Method EstablishStream:Void(Path:String, Mode:String)
			Select Mode
				#If VIRTUALOS_FILESTREAM_CAN_LOAD
					Case "r", "u"
						ReadFileData(RealPath(Path), True)
					Case "a"
						ReadFileData(RealPath(Path), False)
				#End

				#If VIRTUALOS_FILESTREAM_CAN_SAVE
					Case "w"
						CreateFile(Path)
				#End

				Default
					Throw New FileStreamOpenException("Invalid file-mode detected.", Path, Self)
			End Select

			Self.Path = Path
			Self.Mode = Mode

			Return
		End

		Public

		' Methods (Public):
		Method Close:Void()
			#If VIRTUALOS_FILESTREAM_CAN_SAVE
				If (IsOutputStream) Then
					' Push data to the file-system.
					WriteFileData(RealPath(Self.Path))
				Endif
			#End

			' Close the stream properly.
			Super.Close()

			Return
		End

		' Methods (Protected):
		Protected

		#If VIRTUALOS_FILESTREAM_CAN_LOAD
			Method ReadFileData:DataBuffer(RealPath:String, ResetPosition:Bool=True)
				Local Contents:= __OS_LoadBuffer(RealPath)

				If (Contents = Null) Then
					Return Null
				Endif

				Local Position:= Self.Position

				WriteAll(Contents, 0, Contents.Length)

				If (ResetPosition) Then
					Seek(Position)
				Endif

				Return Contents
			End
		#End

		#If VIRTUALOS_FILESTREAM_CAN_SAVE
			Method WriteFileData:Bool(RealPath:String)
				Local Output:= New DataBuffer(Self.Length)

				Self.Data.CopyBytes(Offset, Output, 0, Length)

				If (Not __OS_SaveBuffer(RealPath, Output)) Then
					Return False
				Endif

				'Output.Discard()

				' Return the default response.
				Return True
			End
		#End

		Public

		' Properties:
		Method IsInputStream:Bool() Property
			#If VIRTUALOS_FILESTREAM_CAN_LOAD
				Return (Mode = "r")
			#Else
				Return False
			#End
		End

		Method IsOutputStream:Bool() Property
			#If VIRTUALOS_FILESTREAM_CAN_SAVE
				Return (Mode = "w" Or Mode = "a" Or Mode = "u") ' (Not IsInputStream)
			#Else
				Return False
			#End
		End

		' Fields (Protected):
		Protected

		Field Path:String, Mode:String

		Public
	End
#End

' Exceptions:
Class FileStreamOpenException Extends StreamError
	' Constructor(s):
	Method New(Message:String, Path:String, FS:FileStream)
		Super.New(FS)

		Self.Message = Message
	End

	' Methods:
	Method ToString:String() ' Property
		Return Message
	End

	' Fields (Protected):
	Protected

	Field Message:String

	Public
End


Typo fixes

Typo fixes

Strict

Class FlxU

	Function Abs:Float(value:Float)
		Return monkey.math.Abs(value)
	End Function

	Function Floor:Float(value:Float)
		Return monkey.math.Floor(value)
	End Function

	Function Ceil:Float(value:Float)
		Return monkey.math.Ceil(value)
	End Function

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

	Function Min:Float(number1:Float, number2:Float)
		Return monkey.math.Min(number1, number2)
	End Function

	Function Max:Float(number1:Float, number2:Float)
		Return monkey.math.Max(number1, number2)
	End Function

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

	Function Srand:Float(seed:Float)
		Seed = Int(seed * 1000)
		Return Rnd()
	End Function

	Function Shuffle:Object[](objects:Object[], howManyTimes:Int)
		'TODO
	End Function

End Class

Strict

Class FlxU

	Function Abs:Float(value:Float)
		Return monkey.math.Abs(value)
	End Function

	Function Floor:Float(value:Float)
		Return monkey.math.Floor(value)
	End Function

	Function Ceil:Float(value:Float)
		Return monkey.math.Ceil(value)
	End Function

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

	Function Min(number1:Float, number2:Float)
		Return monkey.math.Min(number1, number2)
	End Function

	Function Max(number1:Float, number2:Float)
		Return monkey.math.Max(number1, number2)
	End Function

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

	Function Srand:Float(seed:Float)
		Seed = Int(seed * 1000)
		Return Rnd()
	End Function

	Function Shuffle:Object[](objects:Object[], howManyTimes:Int)
		'TODO
	End Function

End Class


Added a quick 'OutOfBounds' command. It's nothing special, I just need it for something.

Strict

Public

' Preprocessor related:
#Rem
#If TARGET = "glfw" Or TARGET = "sexy"
	#GLFW_TARGET = True
#End
#End

#UTIL_IMPLEMENTED = True

#If IOELEMENT_IMPLEMENTED
	#UTIL_SUPPORT_IOELEMENTS = True
#Else
	#UTIL_SUPPORT_IOELEMENTS = False
#End

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

#If CONFIG = "release"
	#DEBUG_PRINT_ON_ERROR = True
#Else
	#DEBUG_PRINT_ON_ERROR = False
#End

#DEBUG_PRINT_QUOTES = False

#READ_LINE_QUICKLY = True

#If HOST = "winnt"
	#WRITE_LINE_ENDTYPE = "CRLF"
#Else
	#WRITE_LINE_ENDTYPE = "LF"
#End

' Imports (Public):
Import autostream

Import byteorder
Import imagedimensions
Import retrostrings
Import stringutil
Import vector

#If CONSOLE_IMPLEMENTED
	Import console
#End

Import sizeof
Import time

#If Not BRL_GAMETARGET_IMPLEMENTED
	Import mojoemulator
#End

' Imports (Private):
Private

' Unofficial:
#If UTIL_SUPPORT_IOELEMENTS
	Import ioelement
#End

' Official:

' BRL:
Import brl.databuffer
Import brl.stream
Import brl.filepath

Public

' Constant variable(s):

' Type codes (Mainly used for generic classes):
Const TYPE_OBJECT:Int			= 0
Const TYPE_INT:Int				= 1
Const TYPE_BOOL:Int				= 2
Const TYPE_FLOAT:Int			= 3
Const TYPE_STRING:Int			= 4

' Ascii codes:
Const ASCII_CARRIAGE_RETURN:Int = 13
Const ASCII_LINE_FEED:Int = 10

' Used mainly for external code where '-9999...' isn't ever going to be valid.
' You should stick to 'Null' in most cases; try not to use this.
Const NOVAR:Int = -999999

' This acts as a general "automatic-value".
' Basically, you can check against this for things like manually defined array-lengths.
Const UTIL_AUTO:Int = -1

' This is for situations where the length of something can be optional.
Const AUTOMATIC_LENGTH:Int = -1

Const ErrorTemplate:String = "[ERROR] {Debug}: " ' + Space
Const LogTemplate:String = "[Info] {Debug}: " ' + Space

' Global variable(s) (Public):
#If CONSOLE_IMPLEMENTED
	Global DebugConsole:Console = Null
#End

' A global stack logging randomization seeds.
' This is commonly accessed by the 'PushSeed' and 'PopSeed' functions.
Global SeedStack:Stack<Int> = Null

' Global variable(s) (Private):
Private

' Nothing so far.

Public

' Functions:
Function FLAG:Int(ID:Int)
	Return Pow(2, ID)
End

' This command is little-endian only:
Function AsByte:Int(I:Int)
	Return ((I Shl 24) Shr 24)
End

' This command treats data as 8-bit (Turns something like $F7, into $FFFFFFF7)
' This is only applied on little-endian systems,
' please use this command for hex values (Monkey converts hex on compile-time).
Function PaddedHex:Int(I:Int)
	If (Not BigEndian()) Then
		Return AsByte(I)
	Endif

	Return I
End

Function Transfer:Bool(InputStream:Stream, OutputStream:Stream, DataSize:Int)
	' Check for errors:
	If (DataSize = 0) Then Return False
	If (InputStream = Null Or InputStream.Eof()) Then Return False
	If (OutputStream = Null) Then Return False

	' Local variable(s):
	#If FLAG_TEMP_BUFFERS
		Local Data:DataBuffer = New DataBuffer(DataSize)
		Local DataLength:= DataSize ' Data.Length()

		' Read from the input-stream, then write to the output-stream:
		InputStream.Read(Data, 0, DataLength)
		OutputStream.Write(Data, 0, DataLength)

		Data.Discard()
	#Else
		'Local Data:Int[DataSize]

		For Local I:Int = 1 To DataSize ' Data.Length()
			OutputStream.WriteByte(InputStream.ReadByte())
		Next
	#End

	' Return the default response.
	Return True
End

Function Sq:Float(Input:Float)
	Return Pow(Input, 2.0) ' Input * Input
End

Function Sq:Int(Input:Int)
	Return Pow(Input, 2)
End

Function WrapAngle:Float(A:Float)
	While (A < 0.0)
		A += 360.0
	Wend

	While (A > 360.0)
		A -= 360.0
	Wend

	Return A
End

Function WrapColor:Float(C:Float)
	#Rem
	While (C < 0.0)
		C += 255.0
	Wend

	While (C > 255.0)
		C -= 255.0
	Wend
	#End

	Return C Mod 256.0
End

' This command is a helper function for
Function ProcessColorLocation:Int(Point:Int)
	' Check for errors:
	If (Point < 0) Then
		Return 0
	Endif

	Return (SizeOf_Integer_InBits-(SizeOf_Octet_InBits*(Point+1))) ' ((SizeOf_Integer_InBits-SizeOf_Octet_InBits)-(SizeOf_Octet_InBits*Point))
End

' NOTE: This command will produce incorrect color values without all characters present in the encode-string.
Function ColorToString:String(Pixel:Int, Encoding:String="ARGB")
	' Ensure the encoding is always described as uppercase.
	Encoding = Encoding.ToUpper()

	' Return the encoded color-string.
	Return ("R: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("R"))) & $000000FF) +
			", G: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("G"))) & $000000FF) +
			", B: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("B"))) & $000000FF) +
			", A: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("A"))) & $000000FF))
End

Function PrintColor:Void(Pixel:Int, Encoding:String="ARGB")
	Print(ColorToString(Pixel, Encoding))

	Return
End

' This is just a wrapper for the main implementation:
Function PushSeed:Bool()
	Return PushSeed(Seed)
End

' The return value of this function specifies if the seed-stack already existed.
Function PushSeed:Bool(Seed:Int)
	' Local variable(s):
	Local Response:Bool = (SeedStack <> Null)

	If (Not Response) Then
		SeedStack = New IntStack()
	Endif

	SeedStack.Push(Seed)

	' Return the calculated response.
	Return Response
End

' This command retrieves a seed from the seed-stack,
' if no seed exists, the current randomization seed is returned.
Function PopSeed:Int()
	If (SeedStack <> Null) Then
		If (Not SeedStack.IsEmpty()) Then
			Return SeedStack.Pop()
		Endif
	Endif

	' Return the default response.
	Return Seed
End

' This command writes a standard line to a 'Stream'.
' This supports both 'LF', and 'CRLF' line endings currently, and this can be configured with 'WRITE_LINE_ENDTYPE'.
' Though character encoding is supported with this, only ASCII is supported by 'ReadLine'.
Function WriteLine:Bool(S:Stream, Line:String, CharacterEncoding:String="ascii")
	' Check for errors:
	If (S = Null) Then
		Return False
	Endif

	S.WriteString(Line, CharacterEncoding)

	#If WRITE_LINE_ENDTYPE = "CRLF"
		S.WriteByte(ASCII_CARRIAGE_RETURN)
	#End

	S.WriteByte(ASCII_LINE_FEED)

	' Return the default response.
	Return True
End

' This command reads a standard line from a 'Stream'. (This supports both 'LF', and 'CRLF' line endings currently)
' In addition, only 'ASCII' is currently supported.
Function ReadLine:String(S:Stream)
	' Local variable(s):
	Local Position:= S.Position()
	Local Padding:Int = 0 ' * SizeOf_Char
	Local Str:String

	#If Not READ_LINE_QUICKLY
		Local Size:Int = 0
	#End

	While (Not S.Eof())
		Local Char:= S.ReadByte()

		If (Char <> ASCII_LINE_FEED) Then
			If (Char <> ASCII_CARRIAGE_RETURN) Then
				#If READ_LINE_QUICKLY
					Str += String.FromChar(Char)
				#Else
					Size += 1
				#End
			Else
				Padding = 2*SizeOf_Char
			Endif
		Else
			#Rem
				If (Padding = 0) Then
					Padding = 1
				Endif
			#End

			Padding = Max(Padding, 1*SizeOf_Char)

			Exit
		Endif
	Wend

	#If Not READ_LINE_QUICKLY
		S.Seek(Position)

		Str = S.ReadString(Size, "ascii")

		S.Seek(S.Position()+Padding)
	#End

	' Return the string we read from the stream.
	Return Str
End

Function ResizeBuffer:DataBuffer(Buffer:DataBuffer, Size:Int=AUTOMATIC_LENGTH, CopyData:Bool=True, DiscardOldBuffer:Bool=False, OnlyWhenDifferentSizes:Bool=False)
	Local BufferAvailable:Bool = (Buffer <> Null)

	If (BufferAvailable And OnlyWhenDifferentSizes) Then
		If (Size <> AUTOMATIC_LENGTH And Buffer.Length() = Size) Then
			Return Buffer
		Endif
	Endif

	If (Size = AUTOMATIC_LENGTH) Then
		Size = Buffer.Length()
	Endif

	' Allocate a new data-buffer.
	Local B:= New DataBuffer(Size)

	' Copy the buffer's bytes over to 'B'.
	If (BufferAvailable) Then
		If (CopyData) Then
			' Copy the contents of 'Buffer' to the newly generated buffer-object.
			Buffer.CopyBytes(0, B, 0, Buffer.Length())
		Endif

		If (DiscardOldBuffer) Then
			' Discard the old buffer.
			Buffer.Discard()
		Endif
	Endif

	' Return the newly generated buffer.
	Return B
End

#If CONSOLE_IMPLEMENTED
	Function DebugBind:Bool(C:Console)
		If (C = Null) Then Return False

		DebugConsole = C

		' Return the default response.
		Return True
	End
#End

Function DebugError:Void(E:Throwable, StopExecution:Bool=True)
	#If CONFIG = "debug"
		DebugStop()
	#Else
		DebugPrint("Unknown exception has been thrown; continuing anyway.")
	#End

	Return
End

Function DebugError:Void(Msg:String, StopExecution:Bool=True)
	#If DEBUG_PRINT
		' Local variable(s):
		Local TempMsg:String

		If (StopExecution) Then
			TempMsg = ErrorTemplate
		Else
			TempMsg = LogTemplate
		Endif

		#If DEBUG_PRINT_QUOTES
			Msg = Tempmsg + Quote + Msg + Quote
		#Else
			Msg = TempMsg + Msg
		#End

		#If CONSOLE_IMPLEMENTED
			If (DebugConsole <> Null) Then
				DebugConsole.WriteLine(Msg, True)
			Else
		#End

		Print(Msg)

		#If CONSOLE_IMPLEMENTED
			Endif
		#End
	#Else
		' This may change later:
		If (StopExecution) Then
			Msg = ErrorTemplate + Msg
		Endif
	#End

	If (StopExecution) Then
		#If CONFIG = "debug"
			#If DEBUG_PRINT_ON_ERROR
				DebugStop()
			#Else
				Error(Msg)
			#End
		#Else
			#If DEBUG_PRINT
				Local FinalStr:String = (ErrorTemplate + Quote + "Attempt to stop execution failed. (Reason: Release-mode)" + Quote)

				#If CONSOLE_IMPLEMENTED
					If (DebugConsole <> Null) Then
						DebugConsole.WriteLine(FinalStr, True)
					Else
				#End

				Print(FinalStr)

				#If CONSOLE_IMPLEMENTED
					Endif
				#End
			#Else
				Error(Msg)
			#End
		#End
	Endif

	#If CONFIG = "debug"
		' Nothing so far.
	#Else
		' Nothing so far.
	#End

	Return
End

Function DebugPrint:Void(Str:String, StopExecution:Bool=False)
	DebugError(Str, StopExecution)

	Return
End

' This command is useful for dealing with arrays:
Function OutOfBounds:Bool(Position:Int, Length:Int)
	Return (Position >= Length)
End

' The following functions are designed to be used with generic classes:
Function TypeIsObject:Bool(O:Object)
	Return True
End

Function TypeIsObject:Bool(IO:IntObject)
	Return False
End

Function TypeIsObject:Bool(BO:BoolObject)
	Return False
End

Function TypeIsObject:Bool(FO:FloatObject)
	Return False
End

Function TypeIsObject:Bool(SO:StringObject)
	Return False
End

Function TypeIsObject:Bool(I:Int)
	Return False
End

Function TypeIsObject:Bool(B:Bool)
	Return False
End

Function TypeIsObject:Bool(F:Float)
	Return False
End

Function TypeIsObject:Bool(S:String)
	Return False
End

Function TypeOf:Int(O:Object)
	Return TYPE_OBJECT
End

Function TypeOf:Int(IO:IntObject)
	Return TYPE_INT
End

Function TypeOf:Int(BO:BoolObject)
	Return TYPE_BOOL
End

Function TypeOf:Int(FO:FloatObject)
	Return TYPE_FLOAT
End

Function TypeOf:Int(SO:StringObject)
	Return TYPE_STRING
End

Function TypeOf:Int(I:Int)
	Return TYPE_INT
End

Function TypeOf:Int(B:Bool)
	Return TYPE_BOOL
End

Function TypeOf:Int(F:Float)
	Return TYPE_FLOAT
End

Function TypeOf:Int(S:String)
	Return TYPE_STRING
End

' Classes:
Class GenericUtilities<T>
	' Constant variable(s):

	' Comparison response codes (Positive numbers are for error-reporting):
	Const COMPARE_RESPONSE_IDENTICAL:Int			= -1
	Const COMPARE_RESPONSE_WRONG_LENGTH:Int			= -2

	' Other:
	Const AUTO:= UTIL_AUTO

	' Global variable(s):

	' For internal and extern use. That being said, please do not modify this value.
	Global NIL:T

	' Functions:

	' This command gives the user the type-code of 'T'.
	Function Type:Int()
		' Return the type code of 'NIL'.
		Return TypeOf(NIL)
	End

	' This command specifies if 'T' is an object.
	Function IsObject:Bool()
		Return TypeIsObject(NIL)
	End

	' This command wraps the standard 'BoolToString' conversion command.
	Function AsString:String(Input:Bool)
		Return BoolToString(Input)
	End

	' This command reads a string from a standard 'Stream' object.
	Function AsString:String(S:Stream, Length:Int=AUTO, Encoding:String="utf8")
		If (Length = AUTO) Then
			Length = S.Length()
		Endif

		Return S.ReadString(Length, Encoding)
	End

	Function AsString:String(Input:T[], Offset:Int=0, Length:Int=AUTO, AddSpaces:Bool=True)
		' Local variable(s):
		Local Output:String = LeftBracket

		' If no length was specified, use the array's length.
		If (Length = AUTO) Then
			Length = Input.Length()
		Endif

		Local VirtualLength:= Length+Offset

		For Local Index:Int = Offset Until VirtualLength
			Output += Input[Index]

			If (Index+1 < VirtualLength) Then
				Output += Comma

				If (AddSpaces) Then
					Output += Space
				Endif
			Endif
		Next

		Return Output + RightBracket
	End

	Function CopyStringToArray:T[](S:String, Input:T[], Offset:Int=0, Length:Int=AUTO)
		If (Length = AUTO) Then
			Length = Min(S.Length(), Input.Length())
		Endif

		For Local I:Int = Offset Until Length
			Input[I] = S[I]
		Next

		' Just for the sake of convenience, return the 'Input' array.
		Return Input
	End

	Function IndexOfList:T(L:List<T>, Index:Int=0)
		' Local variable(s):
		Local Data:list.Node<T> = L.FirstNode()

		For Local I:= 0 Until Index
			Data = Data.NextNode()

			' Not my favorite method, but it works:
			If (Data = Null) Then
				Return NIL
			Endif
		Next

		' Return the value of the assessed node.
		Return Data.Value()
	End

	Function Zero:T[](Input:T[])
		Return Nil(Input)
	End

	Function Nil:T[](Input:T[])
		For Local Index:= 0 Until Input.Length()
			Input[Index] = NIL
		Next

		Return Input
	End

	Function PrintArray:Void(Input:T[])
		Print(AsString(Input))

		Return
	End

	#Rem
		NOTES:
			* In the event of an error, an empty array will be produced.

			* The 'CopyArray' command's 'FitSource' argument should only be enabled with the
			knowledge that the original destination may have been discarded.

			Your code must reflect this by disregarding the original array,
			and simply assigning the old array to the retrun value.

			EXAMPLE:
				' Local variable(s):
				Local A:T[10], A2:T[3]

				' This will likely produce a new 'T' array, based on the area-delta.
				A2 = CopyArray(A, A2, True)
	#End

	Function CopyArray:T[](Source:T[], Destination:T[], FitSource:Bool)
		Return CopyArray(Source, Destination, 0, 0, AUTO, AUTO, FitSource)
	End

	Function CopyArray:T[](Source:T[], Destination:T[], Source_Offset:Int=0, Destination_Offset:Int=0, Source_Length:Int=AUTO, Destination_Length:Int=AUTO, FitSource:Bool=False)
		If (Source_Length = AUTO) Then
			Source_Length = Source.Length()
		Endif

		If (Destination_Length = AUTO) Then
			Destination_Length = Destination.Length()
		Endif

		' Local variable(s):

		' These two are used as caches for the real lengths of the arrays:
		Local Destination_RealLength:= Destination.Length()
		Local Source_RealLength:= Source.Length()

		' Calculate the source and destination areas:
		Local Source_Area:Int = (Source_Length-Source_Offset)

		' Make sure we have a source to work with:
		If (Source_Area <= 0) Then
			' The source-area is too small for use, return an empty array.
			Return []
		Endif

		Local Destination_Area:Int = (Destination_Length-Destination_Offset)

		' For the sake of safety, we'll also check the destination area:
		If (Destination_Area <= 0) Then
			' The destination-area is too small for use, return an empty array.
			Return []
		Endif

		Local Operation_Area:Int

		If (FitSource And Destination_Area < Source_Area) Then
			Local AreaDelta:Int = (Source_Area-Destination_Area)
			Local NewArea:Int = (Destination_RealLength+AreaDelta)

			If (NewArea > Destination_RealLength) Then
				Destination = Destination.Resize(NewArea)
			Else
				Destination = Destination.Resize(Destination_Length+AreaDelta)
			Endif

			Destination_Area = Source_Area
			Operation_Area = Destination_Area
		Else
			Operation_Area = Min(Source_Area, Destination_Area)
		Endif

		' Copy the contents of the source-array into the destination-array:
		For Local Index:= 0 Until Operation_Area
			Destination[Index+Destination_Offset] = Source[Index+Source_Offset]
		Next

		' Return the destination-array.
		Return Destination
	End

	Function CopyArray:T[](Source:T[])
		Return CloneArray(Source)
	End

	Function CloneArray:T[](Source:T[])
		Return CopyArray(Source, New T[Source.Length()])
	End

	' This command returns a positive number upon an error,
	' otherwise a 'response code' will be given (See the "Contant variable(s)" section for details).
	Function Compare:Int(A1:T[], A2:T[], CheckLength:Bool=True)
		' Local variable(s):
		Local A1_Length:= A1.Length
		Local A2_Length:= A2.Length

		' Check for errors:
		If (CheckLength) Then
			' Make sure they're both the same length.
			If (A1_Length <> A2_Length) Then
				Return COMPARE_RESPONSE_WRONG_LENGTH
			Endif
		Endif

		For Local I:= 0 Until Min(A1_Length, A2_Length)
			If (A1[I] <> A2[I]) Then
				' Not the best of escape methods, but it works.
				Return I
			Endif
		Next

		' Return the default response.
		Return COMPARE_RESPONSE_IDENTICAL
	End

	' This function returns positive if both arrays are identical.
	Function SimpleCompare:Bool(A1:T[], A2:T[], CheckLength:Bool=True)
		Return (Compare(A1, A2, CheckLength) = COMPARE_RESPONSE_IDENTICAL)
	End

	Function Read:T(S:Stream)
		Return Read(S, NIL)
	End

	Function Read:T[](S:Stream, DataArray:T[], Size:Int=AUTO)
		If (Size = AUTO) Then Size = S.ReadInt()

		If (Size > 0) Then
			If (DataArray.Length() = 0) Then
				DataArray = New T[Size]
			Endif
		Endif

		' Local variable(s):
		Local DLength:Int = Min(DataArray.Length, Size)

		For Local Index:= 0 Until DLength
			DataArray[Index] = Read(S, NIL)
		Next

		Return DataArray
	End

	Function Write:Void(S:Stream, DataArray:T[], WriteLength:Bool=True)
		' Local variable(s):
		Local DLength:= DataArray.Length()

		If (WriteLength) Then S.WriteInt(DLength)

		For Local Index:= 0 Until DLength
			Write(S, DataArray[Index])
		Next

		Return
	End

	Function Read:Int(S:Stream, Indentifier:Int, Size:Int=4)
		' Local variable(s):
		Local Data:Int = 0

		If (Size > 1) Then
			If (Size < 4) Then
				Data = S.ReadShort()
			Else
				If (Size > 4) Then
					S.ReadInt()
				Endif

				Data = S.ReadInt()
			Endif
		Else
			Data = S.ReadByte()
		Endif

		Return Data
	End

	Function Write:Void(S:Stream, Data:Int, Size:Int=4)
		Size = IntSize(Size)

		If (Size > 1) Then
			If (Size < 4) Then
				S.WriteShort(Data)
			Else
				If (Size > 4) Then
					S.WriteInt(0)
				Endif

				S.WriteInt(Data)
			Endif
		Else
			S.WriteByte(Data)
		Endif

		Return
	End

	#Rem
	Function Read:Bool(S:Stream, Identifier:Bool)
		Return Read(S, Int(Identifier), 1)
	End

	Function Write:Void(S:Stream, B:Bool)
		Write(S, Int(B), 1)

		Return
	End
	#End

	Function Read:Float(S:Stream, Identifier:Float)
		Return S.ReadFloat()
	End

	Function Write:Void(S:Stream, Data:Float)
		S.WriteFloat(Data)

		Return
	End

	Function Read:String(S:Stream, Data:String, Encoding:String="utf8", Size:Int=AUTO)
		If (Size = AUTO) Then
			Size = S.ReadInt()
		Endif

		Data = S.ReadString(Size, Encoding)

		' Return the newly read string.
		Return Data
	End

	Function Write:Void(S:Stream, Data:String, Encoding:String="utf8", WriteSize:Bool=True)
		If (WriteSize) Then
			S.WriteInt(Data.Length())
		Endif

		S.WriteString(Data, Encoding)

		Return
	End

	#If UTIL_SUPPORT_IOELEMENTS
		Function Read:Void(S:Stream, Data:InputChildElement)
			If (Data = Null) Then
				Return
			Endif

			Data.Load(S)

			Return
		End

		Function Write:Void(S:Stream, Data:OutputChildElement)
			If (Data = Null) Then
				Return
			Endif

			Data.Save(S)
		End
	#End

	' Constructor(s):

	' DO NOT CREATE NEW INSTANCES OF THIS CLASS.
	Method New()
		DebugError("This class should not be used in this was.")
	End
End

Strict

Public

' Preprocessor related:
#Rem
#If TARGET = "glfw" Or TARGET = "sexy"
	#GLFW_TARGET = True
#End
#End

#UTIL_IMPLEMENTED = True

#If IOELEMENT_IMPLEMENTED
	#UTIL_SUPPORT_IOELEMENTS = True
#Else
	#UTIL_SUPPORT_IOELEMENTS = False
#End

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

#If CONFIG = "release"
	#DEBUG_PRINT_ON_ERROR = True
#Else
	#DEBUG_PRINT_ON_ERROR = False
#End

#DEBUG_PRINT_QUOTES = False

#READ_LINE_QUICKLY = True

#If HOST = "winnt"
	#WRITE_LINE_ENDTYPE = "CRLF"
#Else
	#WRITE_LINE_ENDTYPE = "LF"
#End

' Imports (Public):
Import autostream

Import byteorder
Import imagedimensions
Import retrostrings
Import stringutil
Import vector

#If CONSOLE_IMPLEMENTED
	Import console
#End

Import sizeof
Import time

#If Not BRL_GAMETARGET_IMPLEMENTED
	Import mojoemulator
#End

' Imports (Private):
Private

' Unofficial:
#If UTIL_SUPPORT_IOELEMENTS
	Import ioelement
#End

' Official:

' BRL:
Import brl.databuffer
Import brl.stream
Import brl.filepath

Public

' Constant variable(s):

' Type codes (Mainly used for generic classes):
Const TYPE_OBJECT:Int			= 0
Const TYPE_INT:Int				= 1
Const TYPE_BOOL:Int				= 2
Const TYPE_FLOAT:Int			= 3
Const TYPE_STRING:Int			= 4

' Ascii codes:
Const ASCII_CARRIAGE_RETURN:Int = 13
Const ASCII_LINE_FEED:Int = 10

' Used mainly for external code where '-9999...' isn't ever going to be valid.
' You should stick to 'Null' in most cases; try not to use this.
Const NOVAR:Int = -999999

' This acts as a general "automatic-value".
' Basically, you can check against this for things like manually defined array-lengths.
Const UTIL_AUTO:Int = -1

' This is for situations where the length of something can be optional.
Const AUTOMATIC_LENGTH:Int = -1

Const ErrorTemplate:String = "[ERROR] {Debug}: " ' + Space
Const LogTemplate:String = "[Info] {Debug}: " ' + Space

' Global variable(s) (Public):
#If CONSOLE_IMPLEMENTED
	Global DebugConsole:Console = Null
#End

' A global stack logging randomization seeds.
' This is commonly accessed by the 'PushSeed' and 'PopSeed' functions.
Global SeedStack:Stack<Int> = Null

' Global variable(s) (Private):
Private

' Nothing so far.

Public

' Functions:
Function FLAG:Int(ID:Int)
	Return Pow(2, ID)
End

' This command is little-endian only:
Function AsByte:Int(I:Int)
	Return ((I Shl 24) Shr 24)
End

' This command treats data as 8-bit (Turns something like $F7, into $FFFFFFF7)
' This is only applied on little-endian systems,
' please use this command for hex values (Monkey converts hex on compile-time).
Function PaddedHex:Int(I:Int)
	If (Not BigEndian()) Then
		Return AsByte(I)
	Endif

	Return I
End

Function Transfer:Bool(InputStream:Stream, OutputStream:Stream, DataSize:Int)
	' Check for errors:
	If (DataSize = 0) Then Return False
	If (InputStream = Null Or InputStream.Eof()) Then Return False
	If (OutputStream = Null) Then Return False

	' Local variable(s):
	#If FLAG_TEMP_BUFFERS
		Local Data:DataBuffer = New DataBuffer(DataSize)
		Local DataLength:= DataSize ' Data.Length()

		' Read from the input-stream, then write to the output-stream:
		InputStream.Read(Data, 0, DataLength)
		OutputStream.Write(Data, 0, DataLength)

		Data.Discard()
	#Else
		'Local Data:Int[DataSize]

		For Local I:Int = 1 To DataSize ' Data.Length()
			OutputStream.WriteByte(InputStream.ReadByte())
		Next
	#End

	' Return the default response.
	Return True
End

Function Sq:Float(Input:Float)
	Return Pow(Input, 2.0) ' Input * Input
End

Function Sq:Int(Input:Int)
	Return Pow(Input, 2)
End

Function WrapAngle:Float(A:Float)
	While (A < 0.0)
		A += 360.0
	Wend

	While (A > 360.0)
		A -= 360.0
	Wend

	Return A
End

Function WrapColor:Float(C:Float)
	#Rem
	While (C < 0.0)
		C += 255.0
	Wend

	While (C > 255.0)
		C -= 255.0
	Wend
	#End

	Return C Mod 256.0
End

' This command is a helper function for
Function ProcessColorLocation:Int(Point:Int)
	' Check for errors:
	If (Point < 0) Then
		Return 0
	Endif

	Return (SizeOf_Integer_InBits-(SizeOf_Octet_InBits*(Point+1))) ' ((SizeOf_Integer_InBits-SizeOf_Octet_InBits)-(SizeOf_Octet_InBits*Point))
End

' NOTE: This command will produce incorrect color values without all characters present in the encode-string.
Function ColorToString:String(Pixel:Int, Encoding:String="ARGB")
	' Ensure the encoding is always described as uppercase.
	Encoding = Encoding.ToUpper()

	' Return the encoded color-string.
	Return ("R: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("R"))) & $000000FF) +
			", G: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("G"))) & $000000FF) +
			", B: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("B"))) & $000000FF) +
			", A: " + ((Pixel Shr ProcessColorLocation(Encoding.Find("A"))) & $000000FF))
End

Function PrintColor:Void(Pixel:Int, Encoding:String="ARGB")
	Print(ColorToString(Pixel, Encoding))

	Return
End

' This is just a wrapper for the main implementation:
Function PushSeed:Bool()
	Return PushSeed(Seed)
End

' The return value of this function specifies if the seed-stack already existed.
Function PushSeed:Bool(Seed:Int)
	' Local variable(s):
	Local Response:Bool = (SeedStack <> Null)

	If (Not Response) Then
		SeedStack = New IntStack()
	Endif

	SeedStack.Push(Seed)

	' Return the calculated response.
	Return Response
End

' This command retrieves a seed from the seed-stack,
' if no seed exists, the current randomization seed is returned.
Function PopSeed:Int()
	If (SeedStack <> Null) Then
		If (Not SeedStack.IsEmpty()) Then
			Return SeedStack.Pop()
		Endif
	Endif

	' Return the default response.
	Return Seed
End

' This command writes a standard line to a 'Stream'.
' This supports both 'LF', and 'CRLF' line endings currently, and this can be configured with 'WRITE_LINE_ENDTYPE'.
' Though character encoding is supported with this, only ASCII is supported by 'ReadLine'.
Function WriteLine:Bool(S:Stream, Line:String, CharacterEncoding:String="ascii")
	' Check for errors:
	If (S = Null) Then
		Return False
	Endif

	S.WriteString(Line, CharacterEncoding)

	#If WRITE_LINE_ENDTYPE = "CRLF"
		S.WriteByte(ASCII_CARRIAGE_RETURN)
	#End

	S.WriteByte(ASCII_LINE_FEED)

	' Return the default response.
	Return True
End

' This command reads a standard line from a 'Stream'. (This supports both 'LF', and 'CRLF' line endings currently)
' In addition, only 'ASCII' is currently supported.
Function ReadLine:String(S:Stream)
	' Local variable(s):
	Local Position:= S.Position()
	Local Padding:Int = 0 ' * SizeOf_Char
	Local Str:String

	#If Not READ_LINE_QUICKLY
		Local Size:Int = 0
	#End

	While (Not S.Eof())
		Local Char:= S.ReadByte()

		If (Char <> ASCII_LINE_FEED) Then
			If (Char <> ASCII_CARRIAGE_RETURN) Then
				#If READ_LINE_QUICKLY
					Str += String.FromChar(Char)
				#Else
					Size += 1
				#End
			Else
				Padding = 2*SizeOf_Char
			Endif
		Else
			#Rem
				If (Padding = 0) Then
					Padding = 1
				Endif
			#End

			Padding = Max(Padding, 1*SizeOf_Char)

			Exit
		Endif
	Wend

	#If Not READ_LINE_QUICKLY
		S.Seek(Position)

		Str = S.ReadString(Size, "ascii")

		S.Seek(S.Position()+Padding)
	#End

	' Return the string we read from the stream.
	Return Str
End

Function ResizeBuffer:DataBuffer(Buffer:DataBuffer, Size:Int=AUTOMATIC_LENGTH, CopyData:Bool=True, DiscardOldBuffer:Bool=False, OnlyWhenDifferentSizes:Bool=False)
	Local BufferAvailable:Bool = (Buffer <> Null)

	If (BufferAvailable And OnlyWhenDifferentSizes) Then
		If (Size <> AUTOMATIC_LENGTH And Buffer.Length() = Size) Then
			Return Buffer
		Endif
	Endif

	If (Size = AUTOMATIC_LENGTH) Then
		Size = Buffer.Length()
	Endif

	' Allocate a new data-buffer.
	Local B:= New DataBuffer(Size)

	' Copy the buffer's bytes over to 'B'.
	If (BufferAvailable) Then
		If (CopyData) Then
			' Copy the contents of 'Buffer' to the newly generated buffer-object.
			Buffer.CopyBytes(0, B, 0, Buffer.Length())
		Endif

		If (DiscardOldBuffer) Then
			' Discard the old buffer.
			Buffer.Discard()
		Endif
	Endif

	' Return the newly generated buffer.
	Return B
End

#If CONSOLE_IMPLEMENTED
	Function DebugBind:Bool(C:Console)
		If (C = Null) Then Return False

		DebugConsole = C

		' Return the default response.
		Return True
	End
#End

Function DebugError:Void(E:Throwable, StopExecution:Bool=True)
	#If CONFIG = "debug"
		DebugStop()
	#Else
		DebugPrint("Unknown exception has been thrown; continuing anyway.")
	#End

	Return
End

Function DebugError:Void(Msg:String, StopExecution:Bool=True)
	#If DEBUG_PRINT
		' Local variable(s):
		Local TempMsg:String

		If (StopExecution) Then
			TempMsg = ErrorTemplate
		Else
			TempMsg = LogTemplate
		Endif

		#If DEBUG_PRINT_QUOTES
			Msg = Tempmsg + Quote + Msg + Quote
		#Else
			Msg = TempMsg + Msg
		#End

		#If CONSOLE_IMPLEMENTED
			If (DebugConsole <> Null) Then
				DebugConsole.WriteLine(Msg, True)
			Else
		#End

		Print(Msg)

		#If CONSOLE_IMPLEMENTED
			Endif
		#End
	#Else
		' This may change later:
		If (StopExecution) Then
			Msg = ErrorTemplate + Msg
		Endif
	#End

	If (StopExecution) Then
		#If CONFIG = "debug"
			#If DEBUG_PRINT_ON_ERROR
				DebugStop()
			#Else
				Error(Msg)
			#End
		#Else
			#If DEBUG_PRINT
				Local FinalStr:String = (ErrorTemplate + Quote + "Attempt to stop execution failed. (Reason: Release-mode)" + Quote)

				#If CONSOLE_IMPLEMENTED
					If (DebugConsole <> Null) Then
						DebugConsole.WriteLine(FinalStr, True)
					Else
				#End

				Print(FinalStr)

				#If CONSOLE_IMPLEMENTED
					Endif
				#End
			#Else
				Error(Msg)
			#End
		#End
	Endif

	#If CONFIG = "debug"
		' Nothing so far.
	#Else
		' Nothing so far.
	#End

	Return
End

Function DebugPrint:Void(Str:String, StopExecution:Bool=False)
	DebugError(Str, StopExecution)

	Return
End

' The following functions are designed to be used with generic classes:
Function TypeIsObject:Bool(O:Object)
	Return True
End

Function TypeIsObject:Bool(IO:IntObject)
	Return False
End

Function TypeIsObject:Bool(BO:BoolObject)
	Return False
End

Function TypeIsObject:Bool(FO:FloatObject)
	Return False
End

Function TypeIsObject:Bool(SO:StringObject)
	Return False
End

Function TypeIsObject:Bool(I:Int)
	Return False
End

Function TypeIsObject:Bool(B:Bool)
	Return False
End

Function TypeIsObject:Bool(F:Float)
	Return False
End

Function TypeIsObject:Bool(S:String)
	Return False
End

Function TypeOf:Int(O:Object)
	Return TYPE_OBJECT
End

Function TypeOf:Int(IO:IntObject)
	Return TYPE_INT
End

Function TypeOf:Int(BO:BoolObject)
	Return TYPE_BOOL
End

Function TypeOf:Int(FO:FloatObject)
	Return TYPE_FLOAT
End

Function TypeOf:Int(SO:StringObject)
	Return TYPE_STRING
End

Function TypeOf:Int(I:Int)
	Return TYPE_INT
End

Function TypeOf:Int(B:Bool)
	Return TYPE_BOOL
End

Function TypeOf:Int(F:Float)
	Return TYPE_FLOAT
End

Function TypeOf:Int(S:String)
	Return TYPE_STRING
End

' Classes:
Class GenericUtilities<T>
	' Constant variable(s):

	' Comparison response codes (Positive numbers are for error-reporting):
	Const COMPARE_RESPONSE_IDENTICAL:Int			= -1
	Const COMPARE_RESPONSE_WRONG_LENGTH:Int			= -2

	' Other:
	Const AUTO:= UTIL_AUTO

	' Global variable(s):

	' For internal and extern use. That being said, please do not modify this value.
	Global NIL:T

	' Functions:

	' This command gives the user the type-code of 'T'.
	Function Type:Int()
		' Return the type code of 'NIL'.
		Return TypeOf(NIL)
	End

	' This command specifies if 'T' is an object.
	Function IsObject:Bool()
		Return TypeIsObject(NIL)
	End

	' This command wraps the standard 'BoolToString' conversion command.
	Function AsString:String(Input:Bool)
		Return BoolToString(Input)
	End

	' This command reads a string from a standard 'Stream' object.
	Function AsString:String(S:Stream, Length:Int=AUTO, Encoding:String="utf8")
		If (Length = AUTO) Then
			Length = S.Length()
		Endif

		Return S.ReadString(Length, Encoding)
	End

	Function AsString:String(Input:T[], Offset:Int=0, Length:Int=AUTO, AddSpaces:Bool=True)
		' Local variable(s):
		Local Output:String = LeftBracket

		' If no length was specified, use the array's length.
		If (Length = AUTO) Then
			Length = Input.Length()
		Endif

		Local VirtualLength:= Length+Offset

		For Local Index:Int = Offset Until VirtualLength
			Output += Input[Index]

			If (Index+1 < VirtualLength) Then
				Output += Comma

				If (AddSpaces) Then
					Output += Space
				Endif
			Endif
		Next

		Return Output + RightBracket
	End

	Function CopyStringToArray:T[](S:String, Input:T[], Offset:Int=0, Length:Int=AUTO)
		If (Length = AUTO) Then
			Length = Min(S.Length(), Input.Length())
		Endif

		For Local I:Int = Offset Until Length
			Input[I] = S[I]
		Next

		' Just for the sake of convenience, return the 'Input' array.
		Return Input
	End

	Function IndexOfList:T(L:List<T>, Index:Int=0)
		' Local variable(s):
		Local Data:list.Node<T> = L.FirstNode()

		For Local I:= 0 Until Index
			Data = Data.NextNode()

			' Not my favorite method, but it works:
			If (Data = Null) Then
				Return NIL
			Endif
		Next

		' Return the value of the assessed node.
		Return Data.Value()
	End

	Function Zero:T[](Input:T[])
		Return Nil(Input)
	End

	Function Nil:T[](Input:T[])
		For Local Index:= 0 Until Input.Length()
			Input[Index] = NIL
		Next

		Return Input
	End

	Function PrintArray:Void(Input:T[])
		Print(AsString(Input))

		Return
	End

	#Rem
		NOTES:
			* In the event of an error, an empty array will be produced.

			* The 'CopyArray' command's 'FitSource' argument should only be enabled with the
			knowledge that the original destination may have been discarded.

			Your code must reflect this by disregarding the original array,
			and simply assigning the old array to the retrun value.

			EXAMPLE:
				' Local variable(s):
				Local A:T[10], A2:T[3]

				' This will likely produce a new 'T' array, based on the area-delta.
				A2 = CopyArray(A, A2, True)
	#End

	Function CopyArray:T[](Source:T[], Destination:T[], FitSource:Bool)
		Return CopyArray(Source, Destination, 0, 0, AUTO, AUTO, FitSource)
	End

	Function CopyArray:T[](Source:T[], Destination:T[], Source_Offset:Int=0, Destination_Offset:Int=0, Source_Length:Int=AUTO, Destination_Length:Int=AUTO, FitSource:Bool=False)
		If (Source_Length = AUTO) Then
			Source_Length = Source.Length()
		Endif

		If (Destination_Length = AUTO) Then
			Destination_Length = Destination.Length()
		Endif

		' Local variable(s):

		' These two are used as caches for the real lengths of the arrays:
		Local Destination_RealLength:= Destination.Length()
		Local Source_RealLength:= Source.Length()

		' Calculate the source and destination areas:
		Local Source_Area:Int = (Source_Length-Source_Offset)

		' Make sure we have a source to work with:
		If (Source_Area <= 0) Then
			' The source-area is too small for use, return an empty array.
			Return []
		Endif

		Local Destination_Area:Int = (Destination_Length-Destination_Offset)

		' For the sake of safety, we'll also check the destination area:
		If (Destination_Area <= 0) Then
			' The destination-area is too small for use, return an empty array.
			Return []
		Endif

		Local Operation_Area:Int

		If (FitSource And Destination_Area < Source_Area) Then
			Local AreaDelta:Int = (Source_Area-Destination_Area)
			Local NewArea:Int = (Destination_RealLength+AreaDelta)

			If (NewArea > Destination_RealLength) Then
				Destination = Destination.Resize(NewArea)
			Else
				Destination = Destination.Resize(Destination_Length+AreaDelta)
			Endif

			Destination_Area = Source_Area
			Operation_Area = Destination_Area
		Else
			Operation_Area = Min(Source_Area, Destination_Area)
		Endif

		' Copy the contents of the source-array into the destination-array:
		For Local Index:= 0 Until Operation_Area
			Destination[Index+Destination_Offset] = Source[Index+Source_Offset]
		Next

		' Return the destination-array.
		Return Destination
	End

	Function CopyArray:T[](Source:T[])
		Return CloneArray(Source)
	End

	Function CloneArray:T[](Source:T[])
		Return CopyArray(Source, New T[Source.Length()])
	End

	' This command returns a positive number upon an error,
	' otherwise a 'response code' will be given (See the "Contant variable(s)" section for details).
	Function Compare:Int(A1:T[], A2:T[], CheckLength:Bool=True)
		' Local variable(s):
		Local A1_Length:= A1.Length
		Local A2_Length:= A2.Length

		' Check for errors:
		If (CheckLength) Then
			' Make sure they're both the same length.
			If (A1_Length <> A2_Length) Then
				Return COMPARE_RESPONSE_WRONG_LENGTH
			Endif
		Endif

		For Local I:= 0 Until Min(A1_Length, A2_Length)
			If (A1[I] <> A2[I]) Then
				' Not the best of escape methods, but it works.
				Return I
			Endif
		Next

		' Return the default response.
		Return COMPARE_RESPONSE_IDENTICAL
	End

	' This function returns positive if both arrays are identical.
	Function SimpleCompare:Bool(A1:T[], A2:T[], CheckLength:Bool=True)
		Return (Compare(A1, A2, CheckLength) = COMPARE_RESPONSE_IDENTICAL)
	End

	Function Read:T(S:Stream)
		Return Read(S, NIL)
	End

	Function Read:T[](S:Stream, DataArray:T[], Size:Int=AUTO)
		If (Size = AUTO) Then Size = S.ReadInt()

		If (Size > 0) Then
			If (DataArray.Length() = 0) Then
				DataArray = New T[Size]
			Endif
		Endif

		' Local variable(s):
		Local DLength:Int = Min(DataArray.Length, Size)

		For Local Index:= 0 Until DLength
			DataArray[Index] = Read(S, NIL)
		Next

		Return DataArray
	End

	Function Write:Void(S:Stream, DataArray:T[], WriteLength:Bool=True)
		' Local variable(s):
		Local DLength:= DataArray.Length()

		If (WriteLength) Then S.WriteInt(DLength)

		For Local Index:= 0 Until DLength
			Write(S, DataArray[Index])
		Next

		Return
	End

	Function Read:Int(S:Stream, Indentifier:Int, Size:Int=4)
		' Local variable(s):
		Local Data:Int = 0

		If (Size > 1) Then
			If (Size < 4) Then
				Data = S.ReadShort()
			Else
				If (Size > 4) Then
					S.ReadInt()
				Endif

				Data = S.ReadInt()
			Endif
		Else
			Data = S.ReadByte()
		Endif

		Return Data
	End

	Function Write:Void(S:Stream, Data:Int, Size:Int=4)
		Size = IntSize(Size)

		If (Size > 1) Then
			If (Size < 4) Then
				S.WriteShort(Data)
			Else
				If (Size > 4) Then
					S.WriteInt(0)
				Endif

				S.WriteInt(Data)
			Endif
		Else
			S.WriteByte(Data)
		Endif

		Return
	End

	#Rem
	Function Read:Bool(S:Stream, Identifier:Bool)
		Return Read(S, Int(Identifier), 1)
	End

	Function Write:Void(S:Stream, B:Bool)
		Write(S, Int(B), 1)

		Return
	End
	#End

	Function Read:Float(S:Stream, Identifier:Float)
		Return S.ReadFloat()
	End

	Function Write:Void(S:Stream, Data:Float)
		S.WriteFloat(Data)

		Return
	End

	Function Read:String(S:Stream, Data:String, Encoding:String="utf8", Size:Int=AUTO)
		If (Size = AUTO) Then
			Size = S.ReadInt()
		Endif

		Data = S.ReadString(Size, Encoding)

		' Return the newly read string.
		Return Data
	End

	Function Write:Void(S:Stream, Data:String, Encoding:String="utf8", WriteSize:Bool=True)
		If (WriteSize) Then
			S.WriteInt(Data.Length())
		Endif

		S.WriteString(Data, Encoding)

		Return
	End

	#If UTIL_SUPPORT_IOELEMENTS
		Function Read:Void(S:Stream, Data:InputChildElement)
			If (Data = Null) Then
				Return
			Endif

			Data.Load(S)

			Return
		End

		Function Write:Void(S:Stream, Data:OutputChildElement)
			If (Data = Null) Then
				Return
			Endif

			Data.Save(S)
		End
	#End

	' Constructor(s):

	' DO NOT CREATE NEW INSTANCES OF THIS CLASS.
	Method New()
		DebugError("This class should not be used in this was.")
	End
End


Changed EaseInBounceTween, EaseOutBounceTween & EaseInOutBounceTween parameters to match the rest of the tween functions

#Rem
Copyright (c) 2011 Steve Revill and Shane Woolcock
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#End

Function QuadTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If t < 1 Return diff / 2 * t * t + b
	t -= 1
	Return -diff / 2 * (t * (t - 2) - 1) + b
End

Function QuinticTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If (t < 1) Return diff / 2 * t * t * t * t * t + b
	t -= 2
	Return diff / 2 * (t * t * t * t * t + 2) + b
End

Function TweenCalc:Float(p1:Float, p2:Float, t:Float)
	Return p1 + t * (p2 - p1)
End

Function TweenSmooth:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	Return p1 + v * (p2 - p1)
End

Function SmoothStep:Float(x:Float, interpSmooth:Int = 1)
	For Local i:Int = 0 Until interpSmooth
		x *= x * (3 - 2 * x)
	Next

	Return x' x*x * (3-2*x)
End

Function TweenUp:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = Pow(v, 2) 'power of 2.
	Return p1 + v * (p2 - p1)
End

Function TweenDown:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = 1 - Pow(1 - v, 2) 'InvSquared
	Return p1 + v * (p2 - p1)
End

Function Bezier:Float(p1:Float, p2:Float, cp1:Float, cp2:Float, t:Float)
	Local v:Float = p1 * Pow( (1 - t), 3) + 3 * cp1 * Pow( (1 - t), 2) * t + 3 * cp2 * (1 - t) * Pow(t, 2) + p2 * Pow(t, 3)
	Return v
End

Function EaseInBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	Return diff - EaseOutBounceTween(d - t, 0, diff, d) + b
End

Function EaseOutBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d
	If (t < (1 / 2.75))
		Return diff * (7.5625 * t * t) + b
	ElseIf(t < (2 / 2.75))
		t -= (1.5 / 2.75)
		Return diff * (7.5625 * t * t + 0.75) + b
	ElseIf(t < (2.5 / 2.75))
		t -= (2.25 / 2.75)
		Return diff * (7.5625 * t * t + 0.9375) + b
	Else
		t -= (2.625 / 2.75)
		Return diff * (7.5625 * t * t + 0.984375) + b
	End
End

Function EaseInOutBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	If (t < d / 2)
		Return EaseInBounceTween(t * 2, 0, diff, d) * 0.5 + b
	End
	Return EaseOutBounceTween(t * 2 - d, 0, diff, d) * 0.5 + diff * 0.5 + b
End

#Rem
Copyright (c) 2011 Steve Revill and Shane Woolcock
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#End

Function QuadTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If t < 1 Return diff / 2 * t * t + b
	t -= 1
	Return -diff / 2 * (t * (t - 2) - 1) + b
End

Function QuinticTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If (t < 1) Return diff / 2 * t * t * t * t * t + b
	t -= 2
	Return diff / 2 * (t * t * t * t * t + 2) + b
End

Function TweenCalc:Float(p1:Float, p2:Float, t:Float)
	Return p1 + t * (p2 - p1)
End

Function TweenSmooth:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	Return p1 + v * (p2 - p1)
End

Function SmoothStep:Float(x:Float, interpSmooth:Int = 1)
	For Local i:Int = 0 Until interpSmooth
		x *= x * (3 - 2 * x)
	Next

	Return x' x*x * (3-2*x)
End

Function TweenUp:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = Pow(v, 2) 'power of 2.
	Return p1 + v * (p2 - p1)
End

Function TweenDown:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = 1 - Pow(1 - v, 2) 'InvSquared
	Return p1 + v * (p2 - p1)
End

Function Bezier:Float(p1:Float, p2:Float, cp1:Float, cp2:Float, t:Float)
	Local v:Float = p1 * Pow( (1 - t), 3) + 3 * cp1 * Pow( (1 - t), 2) * t + 3 * cp2 * (1 - t) * Pow(t, 2) + p2 * Pow(t, 3)
	Return v
End

Function EaseInBounceTween:Float(t:Float, b:Float, c:Float, d:Float = 1)
	Local diff:Float = c - b
	Return diff - EaseOutBounceTween(d - t, 0, diff, d) + b
End

Function EaseOutBounceTween:Float(t:Float, b:Float, c:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d
	If (t < (1 / 2.75))
		Return diff * (7.5625 * t * t) + b
	ElseIf(t < (2 / 2.75))
		t -= (1.5 / 2.75)
		Return diff * (7.5625 * t * t + 0.75) + b
	ElseIf(t < (2.5 / 2.75))
		t -= (2.25 / 2.75)
		Return diff * (7.5625 * t * t + 0.9375) + b
	Else
		t -= (2.625 / 2.75)
		Return diff * (7.5625 * t * t + 0.984375) + b
	End
End

Function EaseInOutBounceTween:Float(t:Float, b:Float, c:Float, d:Float = 1)
	Local diff:Float = c - b
	If (t < d / 2)
		Return EaseInBounceTween(t * 2, 0, diff, d) * 0.5 + b
	End
	Return EaseOutBounceTween(t * 2 - d, 0, diff, d) * 0.5 + diff * 0.5 + b
End


Comparison config values fixed

Comparison config values fixed

Strict

Import "native/flixel.${TARGET}.${LANG}"

#If TARGET = "html5"
	#If FLX_WEBGL_ENABLED = 1
		Import "native/webgl/mojo.${TARGET}.gl.min.${LANG}"
	#End
#End

Extern

#If LANG="cpp"
	Function IsMobile:Bool() = "flixel::isMobile"
#ElseIf TARGET = "xna" Or TARGET = "psm"
	Function IsMobile:Bool() = "flixel.functions.isMobile"
#Else
	Function IsMobile:Bool() = "flixel.isMobile"
#End

#If TARGET = "xna" Or TARGET = "psm"
	Function FlxOpenURL:Void(url:String) = "flixel.functions.openURL"
#End

#If TARGET = "html5"
	Function IsIE:Bool() = "flixel.isIE"
#End

Strict

Import "native/flixel.${TARGET}.${LANG}"

#If TARGET = "html5"
	#If FLX_WEBGL_ENABLED = "1"
		Import "native/webgl/mojo.${TARGET}.gl.min.${LANG}"
	#End
#End

Extern

#If LANG="cpp"
	Function IsMobile:Bool() = "flixel::isMobile"
#ElseIf TARGET = "xna" Or TARGET = "psm"
	Function IsMobile:Bool() = "flixel.functions.isMobile"
#Else
	Function IsMobile:Bool() = "flixel.isMobile"
#End

#If TARGET = "xna" Or TARGET = "psm"
	Function FlxOpenURL:Void(url:String) = "flixel.functions.openURL"
#End

#If TARGET = "html5"
	Function IsIE:Bool() = "flixel.isIE"
#End


Bitmap cache clearing removed during switch state for best perfomance

Strict

Import mojo

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

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Float

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _total:Int

	Field _accumulator:Float

	Field _step:Float

	Field _maxAccumulation:Float

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updaterate:Int

	Field _framerate:Int

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, updaterate:Int = 60, framerate:Int = 30, useSystemCursor:Bool = False)
		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 45
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate
		FlxG.Updaterate = updaterate
		_total = 0

		_state = Null

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True

		If (Not useSystemCursor) HideMouse()

		forceDebugger = False
		_debuggerUp = False

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

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

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

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

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

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

					_ShowSoundTray()
				End If

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

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

			_UpdateSoundTray(_step)
		#End

		Return 0
	End Method

	Method OnRender:Int()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Local mark:Int = Millisecs()
		Local elapsedMS:Int = mark - _total
		_total = mark

		If (_debugger <> Null) Then
			'TODO!
		Else
			_accumulator += elapsedMS

			if (_accumulator > _maxAccumulation) Then
				_accumulator = _maxAccumulation
			End If

			While (_accumulator >= _step)
				_Step()
				_accumulator -= _step
			Wend
		End If

		FlxBasic._VisibleCount = 0

		_Draw()

		Return 0
	End Method

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

	Method OnResume:Int()
		If (Not _debuggerUp And Not useSystemCursor) Then
			HideMouse()
		End If

		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

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

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()
		FlxG.ResetInput()
		FlxG.DestroySounds()

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

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

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

		_state = _requestedState
		_state.Create()

		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If
	End Method

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

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

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

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

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

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

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

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

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

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

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

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

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

		If (_recording) Then
			_replay.RecordFrame()

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

		_Update()

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

	Method _Update:Void()
		FlxG.Elapsed = FlxG.TimeScale * (_step / 1000.0)

		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()

		If (_debuggerUp) Then
			'TODO!
		End If
	End Method

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

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= ms / 1000.0

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (ms / 1000.0 * FlxG.Height * 2)

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

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Draw:Void()
		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

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

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

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

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

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

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

			i+=1
		Wend

		#If TARGET <> "ios" Or TARGET <> "android"
			If (Not FlxG.Mobile) Then
				_DrawSoundTray()
				FlxG.Mouse.Draw()
			End If
		#End
	End Method

	Method _DrawSoundTray:Void()
		If (_soundTrayVisible) Then
			Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
			If (FlxG.Mute) globalVolume = 0

			PushMatrix()

			Scale(1 / FlxG._DeviceScaleFactorX, 1 / FlxG._DeviceScaleFactorY)
			Translate(_soundTrayX, _soundTrayY)

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

			If (FlxG._LastDrawingColor <> FlxG.BLACK) Then
				SetColor(0, 0, 0)
			End If

			DrawRect(0, 0, _soundTrayWidth, _soundTrayHeight)

			SetColor(255, 255, 255)
			FlxG._LastDrawingColor = FlxG.WHITE

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

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

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

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

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

			'_soundTrayLabel.Draw()

			PopMatrix()
		End If
	End Method

	Method _Reset:Void()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Seed = SystemMillisecs()

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

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

	Method _ResetFramerate:Void()
		SetUpdateRate(FlxG.Framerate)

		_step = 1000.0 / FlxG.Updaterate
		_maxAccumulation = 2000.0 / FlxG.Framerate - 1

		If (_maxAccumulation < _step) Then
			_maxAccumulation = _step
		End If

		_updaterate = FlxG.Updaterate
		_framerate = FlxG.Framerate
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

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

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

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

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

		Self.OnContentInit()
	End Method
End Class

Private
Class FlxFPSCounter

	Field FPS:Int

Private
	Field _FPSCounter:Int

	Field _lastUpdateTime:Int

Public
	Method New()
		Reset()
	End Method

	Method Update:Void()
		If (_lastUpdateTime = 0) Then
			_lastUpdateTime = Millisecs()
		ElseIf (Millisecs() - _lastUpdateTime >= 1000) Then
			FPS = _FPSCounter
			_lastUpdateTime = Millisecs()
			_FPSCounter = 0
		End If

		_FPSCounter += 1
	End Method

	Method Reset:Void()
		FPS = FlxG.Framerate
		_FPSCounter = 0
		_lastUpdateTime = 0
	End Method

End Class

Strict

Import mojo

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

Import "data/flx_beep.mp3"

'#HTML5_SUSPEND_ON_BLUR_ENABLED = "true"

Class FlxGame extends App

	Field useSoundHotKeys:Bool

	Field useSystemCursor:Bool

	Field useVirtualResolution:Bool

	Field forceDebugger:Bool

	Field _state:FlxState

	Field _requestedState:FlxState

	Field _requestedReset:Bool

	Field _debugger:FlxDebugger

	Field _debuggerUp:Bool

	Field _replay:FlxReplay

	Field _replayRequested:Bool

	Field _recordingRequested:Bool

	Field _replaying:Bool

	Field _recording:Bool

	Field _replayCancelKeys:Int[]

	Field _replayTimer:Float

	Field _replayCallback:FlxReplayListener

Private
	Field _iState:FlxClass

	Field _created:Bool

	Field _total:Int

	Field _accumulator:Float

	Field _step:Float

	Field _maxAccumulation:Float

	Field _soundTrayTimer:Float

	Field _soundTrayWidth:Float

	Field _soundTrayHeight:Float

	Field _soundTrayX:Float

	Field _soundTrayY:Float

	Field _soundTrayVisible:Bool

	Field _soundTrayLabel:FlxText

	Field _updaterate:Int

	Field _framerate:Int

Public
	Method New(gameSizeX:Int, gameSizeY:Int, initialState:FlxClass, zoom:Float = 1, updaterate:Int = 60, framerate:Int = 30, useSystemCursor:Bool = False)
		_soundTrayTimer = 0
		_soundTrayWidth = 160
		_soundTrayHeight = 45
		_soundTrayX = 0
		_soundTrayY	= -_soundTrayHeight
		_soundTrayVisible = False

		FlxG.Init(Self, gameSizeX, gameSizeY, zoom)
		FlxG.Framerate = framerate
		FlxG.Updaterate = updaterate
		_total = 0

		_state = Null

		useSoundHotKeys = Not IsMobile()
		Self.useSystemCursor = useSystemCursor
		useVirtualResolution = True

		If (Not useSystemCursor) HideMouse()

		forceDebugger = False
		_debuggerUp = False

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

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

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

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

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

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

					_ShowSoundTray()
				End If

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

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

			_UpdateSoundTray(_step)
		#End

		Return 0
	End Method

	Method OnRender:Int()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Local mark:Int = Millisecs()
		Local elapsedMS:Int = mark - _total
		_total = mark

		If (_debugger <> Null) Then
			'TODO!
		Else
			_accumulator += elapsedMS

			if (_accumulator > _maxAccumulation) Then
				_accumulator = _maxAccumulation
			End If

			While (_accumulator >= _step)
				_Step()
				_accumulator -= _step
			Wend
		End If

		FlxBasic._VisibleCount = 0

		_Draw()

		Return 0
	End Method

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

	Method OnResume:Int()
		If (Not _debuggerUp And Not useSystemCursor) Then
			HideMouse()
		End If

		FlxG.ResetInput()
		FlxG.ResumeSounds()
		Return 0
	End Method

	Method OnContentInit:Void()
	End Method

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

		_soundTrayTimer = 1
		_soundTrayY = 0
		_soundTrayVisible = True
	End Method

	Method _SwitchState:Void()
		FlxG.ResetCameras()
		FlxG.ResetInput()
		FlxG.DestroySounds()
		FlxG.ClearBitmapCache()

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

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

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

		_state = _requestedState
		_state.Create()

		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If
	End Method

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

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

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

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

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

			_replaying = True
		End If

		If (_state <> _requestedState) _SwitchState()

		FlxBasic._ActiveCount = 0

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

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

						Exit
					End If

					i += 1
				Wend
			End If

			_replay.PlayNextFrame()

			If (_replayTimer > 0) Then
				_replayTimer -= _step

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

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

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

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

		If (_recording) Then
			_replay.RecordFrame()

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

		_Update()

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

	Method _Update:Void()
		FlxG.Elapsed = FlxG.TimeScale * (_step / 1000.0)

		FlxG.UpdateSounds()
		FlxG.UpdatePlugins()
		_state.Update()
		FlxG.UpdateCameras()

		If (_debuggerUp) Then
			'TODO!
		End If
	End Method

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

		If (_soundTrayTimer > 0) Then
			_soundTrayTimer -= ms / 1000.0

		ElseIf (_soundTrayY > -_soundTrayHeight)
			_soundTrayY =_soundTrayY - (ms / 1000.0 * FlxG.Height * 2)

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

				'TODO Save sound settings
			End If
		End If
	End Method

	Method _Draw:Void()
		Cls(FlxG._BgColor.r, FlxG._BgColor.g, FlxG._BgColor.b)
		Scale(FlxG._DeviceScaleFactorX, FlxG._DeviceScaleFactorY)

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

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

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

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

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

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

			i+=1
		Wend

		#If TARGET <> "ios" Or TARGET <> "android"
			If (Not FlxG.Mobile) Then
				_DrawSoundTray()
				FlxG.Mouse.Draw()
			End If
		#End
	End Method

	Method _DrawSoundTray:Void()
		If (_soundTrayVisible) Then
			Local globalVolume:Int = FlxU.Round(FlxG.Volume() * 10)
			If (FlxG.Mute) globalVolume = 0

			PushMatrix()

			Scale(1 / FlxG._DeviceScaleFactorX, 1 / FlxG._DeviceScaleFactorY)
			Translate(_soundTrayX, _soundTrayY)

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

			If (FlxG._LastDrawingColor <> FlxG.BLACK) Then
				SetColor(0, 0, 0)
			End If

			DrawRect(0, 0, _soundTrayWidth, _soundTrayHeight)

			SetColor(255, 255, 255)
			FlxG._LastDrawingColor = FlxG.WHITE

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

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

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

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

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

			'_soundTrayLabel.Draw()

			PopMatrix()
		End If
	End Method

	Method _Reset:Void()
		If (FlxG.Framerate <> _framerate Or FlxG.Updaterate <> _updaterate) Then
			_ResetFramerate()
		End If

		Seed = SystemMillisecs()

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

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

	Method _ResetFramerate:Void()
		SetUpdateRate(FlxG.Framerate)

		_step = 1000.0 / FlxG.Updaterate
		_maxAccumulation = 2000.0 / FlxG.Framerate - 1

		If (_maxAccumulation < _step) Then
			_maxAccumulation = _step
		End If

		_updaterate = FlxG.Updaterate
		_framerate = FlxG.Framerate
	End Method

	Method _InitData:Void()
		FlxAssetsManager.Init()

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

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

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

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

		Self.OnContentInit()
	End Method
End Class

Private
Class FlxFPSCounter

	Field FPS:Int

Private
	Field _FPSCounter:Int

	Field _lastUpdateTime:Int

Public
	Method New()
		Reset()
	End Method

	Method Update:Void()
		If (_lastUpdateTime = 0) Then
			_lastUpdateTime = Millisecs()
		ElseIf (Millisecs() - _lastUpdateTime >= 1000) Then
			FPS = _FPSCounter
			_lastUpdateTime = Millisecs()
			_FPSCounter = 0
		End If

		_FPSCounter += 1
	End Method

	Method Reset:Void()
		FPS = FlxG.Framerate
		_FPSCounter = 0
		_lastUpdateTime = 0
	End Method

End Class