Simplify flxsound

Simplify flxsound

Strict

Import mojo.audio

Import flxbasic
Import flxobject
Import flxu
Import flxg
Import system.flxassetsmanager
Import system.flxresourcesmanager

Class FlxSound Extends FlxBasic

	Global ClassObject:FlxSoundClass = New FlxSoundClass()

	Field x:Float

	Field y:Float

	Field survive:Bool

	Field name:String

	Field artist:String

	Field autoDestroy:Bool

	Field _paused:Bool

	Field _looped:Bool

Private
	Const _CHANNELS_COUNT:Int = 32

	Global _UsedChannels:Bool[_CHANNELS_COUNT]

	Global _SoundLoader:FlxSoundLoader = New FlxSoundLoader()

	Field _sound:Sound

	Field _channel:Int

	Field _soundVolume:Float

	Field _soundPan:Float

	Field _volume:Float

	Field _volumeAdjust:Float

	Field _target:FlxObject

	Field _radius:Float

	Field _pan:Bool

	Field _fadeOutTimer:Float

	Field _fadeOutTotal:Float

	Field _pauseOnFadeOut:Bool

	Field _fadeInTimer:Float

	Field _fadeInTotal:Float

	Field _oldMute:Bool

Public
	Method New()
		Super.New()
		_CreateSound()
	End Method

	Method Destroy:Void()
		Kill()
		_sound = Null
		_channel = -1
		_target = Null

		Super.Destroy()
	End Method

	Method Update:Void()
		If (_paused) Return

		Local radial:Float = 1.0
		Local fade:Float = 1.0
		Local updateNeeded:Bool = False

		If (_target <> Null) Then
			'in original flixel: radial = FlxU.GetDistance(_target.x, _target.y, x, y) / _radius. Maybe a bug?
			radial = 1 - FlxU.GetDistance(_target.x, _target.y, x, y) / _radius
			If (radial < 0) radial = 0

			If (_pan) Then
				'in original flixel: Local d:Float = (_target.x - x) / _radius. Maybe a bug?
				Local d:Float = -(_target.x - x) / _radius

				If (d < -1) Then
					d = -1
				ElseIf (d > 1) Then
					d = 1
				End If

				_soundPan = d
			End If

			updateNeeded = True
		End If

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

			If (_fadeOutTimer <= 0) Then
				If (_pauseOnFadeOut) Then
					Pause()
				Else
					Stop()
				End If
			End If

			fade = _fadeOutTimer / _fadeOutTotal
			If (fade < 0) fade = 0

			updateNeeded = True
		ElseIf (_fadeInTimer > 0) Then
			_fadeInTimer -= FlxG.Elapsed

			fade = _fadeInTimer / _fadeInTotal
			If (fade < 0) fade = 0
			fade = 1 - fade

			updateNeeded = True
		End If

		_volumeAdjust = radial * fade

		If (_oldMute <> FlxG.Mute) Then
			_UpdateTransform()
			_oldMute = FlxG.Mute
			updateNeeded = True
		End If

		If (updateNeeded) _UpdateTransform()
	End Method

	Method Kill:Void()
		Super.Kill()
		Stop()
	End Method

	Method Load:FlxSound(sound:String, looped:Bool = False, autoDestroy:Bool = False)
		Stop()
		_CreateSound()
		_sound = FlxG.AddSound(sound, _SoundLoader)
		_looped = looped
		_UpdateTransform()
		If (_sound <> Null) exists = True
		Return Self
	End Method

	Method Proximity:FlxSound(x:Float, y:Float, object:FlxObject, radius:Float, pan:Bool = True)
		Self.x = x
		Self.y = y
		_target = object
		_radius = radius
		_pan = pan

		Return Self
	End Method

	Method Play:Void(forceRestart:Bool = False)
		If (forceRestart) Then
			Local oldAutoDestroy:Bool = autoDestroy
			autoDestroy = False
			Stop()
			autoDestroy = oldAutoDestroy
		End If

		If (_channel < 0)  Then
			_channel = _GetFreeChannel()
			If (_channel < 0) Then
				exists = False
				Return
			End If
		End If

		_UpdateTransform()

		If (Not _paused) Then
			PlaySound(_sound, _channel, _looped)
		Else
			ResumeChannel(_channel)
		End If

		active = True
		_paused = False
	End Method

	Method Resume:Void()
		If (Not _paused) Return

		If (_channel < 0) Then
			exists = False
			Return
		End If

		ResumeChannel(_channel)
		_paused = False
		active = True
	End Method

	Method Pause:Void()
		If (_channel < 0) Then
			exists = False
			Return
		End If

		PauseChannel(_channel)
		_paused = True
		active = False
	End Method

	Method Stop:Void()
		_paused = False

		If (_channel >= 0) Then
			StopChannel(_channel)
			_UsedChannels[_channel] = False
			_channel = -1
			active = False

			If (autoDestroy) Then
				Destroy()
			End If
		Else
			exists = False
		End If
	End Method

	Method FadeOut:Void(seconds:Float, pauseInstead:Bool = False)
		_pauseOnFadeOut = pauseInstead
		_fadeInTimer = 0
		_fadeOutTimer = seconds
		_fadeOutTotal = _fadeOutTimer
	End Method

	Method FadeIn:Void(seconds:Float)
		_fadeOutTimer = 0
		_fadeInTimer = seconds
		_fadeInTotal = _fadeInTimer
	End Method

	Method Volume:Float() Property
		Return _volume
	End Method

	Method Volume:Void(volume:Float) Property
		_volume = volume

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

		_UpdateTransform()
	End Method

	Method GetActualVolume:Float()
		Return _volume * _volumeAdjust
	End Method

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

	Function GetValidExt:String()
		#If TARGET = "glfw" Or TARGET = "xna"
			Return "wav"
		#ElseIf TARGET = "html5"
			If (IsIE()) Then
				Return "mp3"
			Else
				Return "ogg"
			End If
		#Else
			Return "mp3"
		#End
	End Function

	Method _SetTransform:Void(volume:Float, pan:Float)
		If (_channel >= 0) Then
			SetChannelVolume(_channel, volume)
			SetChannelPan(_channel, pan)
		End If
	End Method

	Method _CreateSound:Void()
		Destroy()
		x = 0
		y = 0
		_sound = Null
		_channel = -1
		_paused = False
		_volume = 1.0
		_volumeAdjust = 1.0
		_looped = False
		_target = Null
		_radius = 0
		_pan = False
		_fadeOutTimer = 0
		_fadeOutTotal = 0
		_pauseOnFadeOut = False
		_fadeInTimer = 0
		_fadeInTotal = 0
		exists = False
		active = False
		visible = False
		name = ""
		artist = ""
		autoDestroy = False
	End Method

	Method _UpdateTransform:Void()
		If (Not FlxG.Mute) Then
			_soundVolume = FlxG._Volume * _volume * _volumeAdjust
		Else
			_soundVolume = 0
		End If

		If (_soundVolume < 0) _soundVolume = 0
		_SetTransform(_soundVolume, _soundPan)
	End Method

Private
	Method _GetFreeChannel:Int()
		Local i:Int = 0

		If (ChannelState(0) >= 0) Then
			While (i < _CHANNELS_COUNT)
				If (ChannelState(i) = 0) Return i
				i += 1
			Wend
		Else
			While (i < _CHANNELS_COUNT)
				If (Not _UsedChannels[i])
					_UsedChannels[i] = True
					Return i
				End If
				i += 1
			Wend
		End If

		FlxG.Log("All channels occupied!")
		Return -1
	End Method

End Class

Interface FlxVolumeChangeListener

	Method OnVolumeChange:Void(volume:Float)

 End Interface

Private
Class FlxSoundClass Implements FlxClass

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

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

End Class

Class FlxSoundLoader Extends FlxResourceLoader<Sound>

	Method Load:Sound(name:String)
		Return LoadSound(FlxAssetsManager.GetSoundPath(name))
	End Method

End Class

Strict

Import mojo.audio

Import flxbasic
Import flxobject
Import flxu
Import flxg
Import system.flxassetsmanager
Import system.flxresourcesmanager

Class FlxSound Extends FlxBasic

	Global ClassObject:FlxSoundClass = New FlxSoundClass()

	Field x:Float

	Field y:Float

	Field survive:Bool

	Field name:String

	Field artist:String

	Field autoDestroy:Bool

	Field _paused:Bool

	Field _looped:Bool

Private
	Const _CHANNELS_COUNT:Int = 32

	Global _UsedChannels:Bool[_CHANNELS_COUNT]

	Global _SoundLoader:FlxSoundLoader = New FlxSoundLoader()

	Field _sound:Sound

	Field _channel:Int

	Field _soundVolume:Float

	Field _soundPan:Float

	Field _volume:Float

	Field _volumeAdjust:Float

	Field _target:FlxObject

	Field _radius:Float

	Field _pan:Bool

	Field _fadeOutTimer:Float

	Field _fadeOutTotal:Float

	Field _pauseOnFadeOut:Bool

	Field _fadeInTimer:Float

	Field _fadeInTotal:Float

	Field _oldMute:Bool

Public
	Method New()
		Super.New()
		_CreateSound()
	End Method

	Method Destroy:Void()
		Kill()
		_sound = Null

		If (_channel >= 0) Then
			_UsedChannels[_channel] = False
		End If

		_channel = -1
		_target = Null

		Super.Destroy()
	End Method

	Method Update:Void()
		If (_paused) Return

		Local radial:Float = 1.0
		Local fade:Float = 1.0
		Local updateNeeded:Bool = False

		If (_target <> Null) Then
			'in original flixel: radial = FlxU.GetDistance(_target.x, _target.y, x, y) / _radius. Maybe a bug?
			radial = 1 - FlxU.GetDistance(_target.x, _target.y, x, y) / _radius
			If (radial < 0) radial = 0

			If (_pan) Then
				'in original flixel: Local d:Float = (_target.x - x) / _radius. Maybe a bug?
				Local d:Float = -(_target.x - x) / _radius

				If (d < -1) Then
					d = -1
				ElseIf (d > 1) Then
					d = 1
				End If

				_soundPan = d
			End If

			updateNeeded = True
		End If

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

			If (_fadeOutTimer <= 0) Then
				If (_pauseOnFadeOut) Then
					Pause()
				Else
					Stop()
				End If
			End If

			fade = _fadeOutTimer / _fadeOutTotal
			If (fade < 0) fade = 0

			updateNeeded = True
		ElseIf (_fadeInTimer > 0) Then
			_fadeInTimer -= FlxG.Elapsed

			fade = _fadeInTimer / _fadeInTotal
			If (fade < 0) fade = 0
			fade = 1 - fade

			updateNeeded = True
		End If

		_volumeAdjust = radial * fade

		If (_oldMute <> FlxG.Mute) Then
			_UpdateTransform()
			_oldMute = FlxG.Mute
			updateNeeded = True
		End If

		If (updateNeeded) _UpdateTransform()
	End Method

	Method Kill:Void()
		Super.Kill()
		If (_channel > 0) Stop()
	End Method

	Method Load:FlxSound(sound:String, looped:Bool = False, autoDestroy:Bool = False)
		Stop()
		_CreateSound()
		_sound = FlxG.AddSound(sound, _SoundLoader)
		_looped = looped
		_UpdateTransform()
		If (_sound <> Null) exists = True
		Return Self
	End Method

	Method Proximity:FlxSound(x:Float, y:Float, object:FlxObject, radius:Float, pan:Bool = True)
		Self.x = x
		Self.y = y
		_target = object
		_radius = radius
		_pan = pan

		Return Self
	End Method

	Method Play:Void(forceRestart:Bool = False)
		If (forceRestart) Then
			Local oldAutoDestroy:Bool = autoDestroy
			autoDestroy = False
			Stop()
			autoDestroy = oldAutoDestroy
		End If

		If (_channel < 0)  Then
			_channel = _GetFreeChannel()
			If (_channel < 0) Then
				exists = False
				Return
			End If
		End If

		_UpdateTransform()

		If (Not _paused) Then
			PlaySound(_sound, _channel, _looped)
		Else
			ResumeChannel(_channel)
		End If

		active = True
		_paused = False
	End Method

	Method Resume:Void()
		If (Not _paused) Return

		If (_channel < 0) Then
			exists = False
			Return
		End If

		ResumeChannel(_channel)
		_paused = False
		active = True
	End Method

	Method Pause:Void()
		If (_channel < 0) Then
			exists = False
			Return
		End If

		PauseChannel(_channel)
		_paused = True
		active = False
	End Method

	Method Stop:Void()
		_paused = False

		If (_channel >= 0) Then
			StopChannel(_channel)
			_UsedChannels[_channel] = False
			_channel = -1
			active = False

			If (autoDestroy) Then
				Destroy()
			End If
		Else
			exists = False
		End If
	End Method

	Method FadeOut:Void(seconds:Float, pauseInstead:Bool = False)
		_pauseOnFadeOut = pauseInstead
		_fadeInTimer = 0
		_fadeOutTimer = seconds
		_fadeOutTotal = _fadeOutTimer
	End Method

	Method FadeIn:Void(seconds:Float)
		_fadeOutTimer = 0
		_fadeInTimer = seconds
		_fadeInTotal = _fadeInTimer
	End Method

	Method Volume:Float() Property
		Return _volume
	End Method

	Method Volume:Void(volume:Float) Property
		_volume = volume

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

		_UpdateTransform()
	End Method

	Method GetActualVolume:Float()
		Return _volume * _volumeAdjust
	End Method

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

	Function GetValidExt:String()
		#If TARGET = "glfw" Or TARGET = "xna"
			Return "wav"
		#ElseIf TARGET = "html5"
			If (IsIE()) Then
				Return "mp3"
			Else
				Return "ogg"
			End If
		#Else
			Return "mp3"
		#End
	End Function

	Method _SetTransform:Void(volume:Float, pan:Float)
		If (_channel >= 0) Then
			SetChannelVolume(_channel, volume)
			SetChannelPan(_channel, pan)
		End If
	End Method

	Method _CreateSound:Void()
		Destroy()
		x = 0
		y = 0
		_sound = Null
		_channel = -1
		_paused = False
		_volume = 1.0
		_volumeAdjust = 1.0
		_looped = False
		_target = Null
		_radius = 0
		_pan = False
		_fadeOutTimer = 0
		_fadeOutTotal = 0
		_pauseOnFadeOut = False
		_fadeInTimer = 0
		_fadeInTotal = 0
		exists = False
		active = False
		visible = False
		name = ""
		artist = ""
		autoDestroy = False
	End Method

	Method _UpdateTransform:Void()
		If (Not FlxG.Mute) Then
			_soundVolume = FlxG._Volume * _volume * _volumeAdjust
		Else
			_soundVolume = 0
		End If

		If (_soundVolume < 0) _soundVolume = 0
		_SetTransform(_soundVolume, _soundPan)
	End Method

Private
	Method _GetFreeChannel:Int()
		Local i:Int = 0

		If (ChannelState(0) >= 0) Then
			While (i < _CHANNELS_COUNT)
				If (ChannelState(i) = 0) Return i
				i += 1
			Wend
		Else
			While (i < _CHANNELS_COUNT)
				If (Not _UsedChannels[i])
					_UsedChannels[i] = True
					Return i
				End If
				i += 1
			Wend
		End If

		FlxG.Log("All channels occupied!")
		Return -1
	End Method

End Class

Interface FlxVolumeChangeListener

	Method OnVolumeChange:Void(volume:Float)

 End Interface

Private
Class FlxSoundClass Implements FlxClass

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

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

End Class

Class FlxSoundLoader Extends FlxResourceLoader<Sound>

	Method Load:Sound(name:String)
		Return LoadSound(FlxAssetsManager.GetSoundPath(name))
	End Method

End Class


Vector2D.SwapXY doesn't do what it says it does.

#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

Strict

Public

'Summary: 2D Vector Class
Class Vector2D
	Field x:Float
	Field y:Float

	'summary: Constructor
	Method New(x:Float = 0, y:Float = 0)
		Self.x = x
		Self.y = y
	End

	'summary: Sets the vector by another vector
	Method Set:Vector2D( vector2:Vector2D )
		Self.x = vector2.x
		Self.y = vector2.y
		Return Self
	End

	'summary: Sets the vector by the supplied x and y
	Method Set:Vector2D(x:Float, y:Float )
		Self.x = x
		Self.y = y
		Return Self
	End

	'summary: Creates a copy of the Vector2D
	Method CloneVector:Vector2D()
		Return New Vector2D(x, y)
	End

	'summary: Swaps x and y around
	Method SwapXY:Vector2D()
		Local tmp:Float = Self.x
		Self.x = Self.y
		Self.y = tmp
		Return Self
	End

	'summary: Makes x and y zero
	Method ZeroVector:Vector2D()
		Self.x = 0
		Self.y = 0
		Return Self
	End

	'summary: Is this vector zeroed?
	Method IsZero:Bool()
		If Self.x = 0 And Self.y = 0 Then
			Return True
		End
		Return False
	End

	'summary: Is the vector's length one?
	Method IsNormalized:Bool()
		If Length = 1.0 Then
			Return True
		End
		Return False
	End

	'summary: Does this vector have the same location as another?
	Method Equals:Bool(vector2d:Vector2D)
		If Self.x = vector2d.x And Self.y = vector2d.y Then
			Return True
		End
		Return False
	End

	'summary: Sets the length, which will change x and y but not the angle
	Method Length:Void(value:Float) Property
		Local angle:Float = Angle
		Self.x = Cos(angle) * value
		Self.y = Sin(angle) * value
		If Abs(Self.x) < 0.00000001 Then Self.x = 0
		If Abs(Self.y) < 0.00000001 Then Self.y = 0
	End

	'summary: Gets the length
	Method Length:Float() Property
		Return Sqrt(LengthSquared)
	End

	'summary: Gets the length squared
	Method LengthSquared:Float() Property
		Return Self.x * Self.x + Self.y * Self.y
	End

	'summary: Sets the angle
	Method Angle:Void(value:Float) Property
		Local len:Float = Length
		Self.x = Cos(value) * len
		Self.y = Sin(value) * len
	End

	'summary: Gets the angle
	Method Angle:Float() Property
		Return ATan2(Self.y, Self.x)
	End

	'summary: Set the vector's length to one
	Method Normalize:Vector2D()
		If Length = 0 Then
			Self.x = 1
			Return Self
		End
		Local len:Float = Length
		Self.x /= len
		Self.y /= len
		Return Self
	End

	'summary: Sets the vector's length to len
	Method Normalize:Vector2D(len:Float)
		Length = len
		Return Self
	End

	'summary: Sets the length under the given value
	Method Truncate:Vector2D(max:Float)
		Length = Min(max, Length)
		Return Self
	End

	'summary: Makes the vector face the opposite way
	Method Reverse:Vector2D()
		Self.x = -Self.x
		Self.y = -Self.y
		Return Self
	End

	'summary: Calculate the dot product of this vector and another
	Method DotProduct:Float(vector2D:Vector2D)
		Return Self.x * vector2D.x + Self.y * vector2D.y
	End

	'summary: Calculate the cross product of this and another vector
	Method CrossProd:Float(vector2D:Vector2D)
		Return Self.x * vector2D.y - Self.y * vector2D.x
	End

	'summary: Calculate angle between any two vectors.
	Function AngleBetween:Float(vector1:Vector2D, vector2:Vector2D)
		If (Not vector1.IsNormalized()) Then vector1 = vector1.CloneVector().Normalize()
		If (Not vector2.IsNormalized()) Then vector2 = vector2.CloneVector().Normalize()
		Return ACos(vector1.DotProduct(vector2))
	End

	'summary: Is the vector to the right or left of this one?
	Method Sign:Int(vector2:Vector2D)
		If Perpendicular.DotProduct(vector2) < 0
			Return -1
		End
		Return 1
	End

	'summary: Get the vector that is perpendicular
	Method Perpendicular:Vector2D() Property
		Return New Vector2D(-y, x)
	End

	'summary: Calculate between two vectors
	Method Distance:Float(vector2:Vector2D)
		Return Sqrt(DistSQ(vector2))
	End

	'summary: Calculate squared distance between vectors. Faster than distance.
	Method DistSQ:Float(vector2:Vector2D)
		Local dx:Float = vector2.x - Self.x
		Local dy:Float = vector2.y - Self.y
		Return dx * dx + dy * dy
	End

	'summary: Add a vector to this vector.
	Method Add:Vector2D(vector2:Vector2D)
		Self.x += vector2.x
		Self.y += vector2.y
		Return Self
	End

	'summary: Subtract a vector from this one.
	Method Subtract:Vector2D(vector2:Vector2D)
		Self.x -= vector2.x
		Self.y -= vector2.y
		Return Self
	End

	'summary: Mutiplies this vector by a scalar
	Method Multiply:Vector2D(scalar:Float)
		Self.x *= scalar
		Self.y *= scalar
		Return Self
	End

	'summary: Divide this vector by a scalar
	Method Divide:Vector2D(scalar:Float)
		Self.x /= scalar
		Self.y /= scalar
		Return Self
	End

	'summary: Turn this vector into a string.
	Method ToString:String()
		Return "Vector2D x:" + Self.x + ", y:" + Self.y
	End

	'summary: Calculate distance between two points - overload using x,y
	Method Distance:Float(x:float, y:float)
		Return Sqrt((Self.x-x) * (Self.x-x) + (Self.y-y) * (Self.y-y))
	End
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

Strict

Public

'Summary: 2D Vector Class
Class Vector2D
	Field x:Float
	Field y:Float

	'summary: Constructor
	Method New(x:Float = 0, y:Float = 0)
		Self.x = x
		Self.y = y
	End

	'summary: Sets the vector by another vector
	Method Set:Vector2D( vector2:Vector2D )
		Self.x = vector2.x
		Self.y = vector2.y
		Return Self
	End

	'summary: Sets the vector by the supplied x and y
	Method Set:Vector2D(x:Float, y:Float )
		Self.x = x
		Self.y = y
		Return Self
	End

	'summary: Creates a copy of the Vector2D
	Method CloneVector:Vector2D()
		Return New Vector2D(x, y)
	End

	'summary: Swaps x and y around
	Method SwapXY:Void(x:Float, y:Float)
		Self.x = y
		Self.y = x
	End

	'summary: Makes x and y zero
	Method ZeroVector:Vector2D()
		Self.x = 0
		Self.y = 0
		Return Self
	End

	'summary: Is this vector zeroed?
	Method IsZero:Bool()
		If Self.x = 0 And Self.y = 0 Then
			Return True
		End
		Return False
	End

	'summary: Is the vector's length one?
	Method IsNormalized:Bool()
		If Length = 1.0 Then
			Return True
		End
		Return False
	End

	'summary: Does this vector have the same location as another?
	Method Equals:Bool(vector2d:Vector2D)
		If Self.x = vector2d.x And Self.y = vector2d.y Then
			Return True
		End
		Return False
	End

	'summary: Sets the length, which will change x and y but not the angle
	Method Length:Void(value:Float) Property
		Local angle:Float = Angle
		Self.x = Cos(angle) * value
		Self.y = Sin(angle) * value
		If Abs(Self.x) < 0.00000001 Then Self.x = 0
		If Abs(Self.y) < 0.00000001 Then Self.y = 0
	End

	'summary: Gets the length
	Method Length:Float() Property
		Return Sqrt(LengthSquared)
	End

	'summary: Gets the length squared
	Method LengthSquared:Float() Property
		Return Self.x * Self.x + Self.y * Self.y
	End

	'summary: Sets the angle
	Method Angle:Void(value:Float) Property
		Local len:Float = Length
		Self.x = Cos(value) * len
		Self.y = Sin(value) * len
	End

	'summary: Gets the angle
	Method Angle:Float() Property
		Return ATan2(Self.y, Self.x)
	End

	'summary: Set the vector's length to one
	Method Normalize:Vector2D()
		If Length = 0 Then
			Self.x = 1
			Return Self
		End
		Local len:Float = Length
		Self.x /= len
		Self.y /= len
		Return Self
	End

	'summary: Sets the vector's length to len
	Method Normalize:Vector2D(len:Float)
		Length = len
		Return Self
	End

	'summary: Sets the length under the given value
	Method Truncate:Vector2D(max:Float)
		Length = Min(max, Length)
		Return Self
	End

	'summary: Makes the vector face the opposite way
	Method Reverse:Vector2D()
		Self.x = -Self.x
		Self.y = -Self.y
		Return Self
	End

	'summary: Calculate the dot product of this vector and another
	Method DotProduct:Float(vector2D:Vector2D)
		Return Self.x * vector2D.x + Self.y * vector2D.y
	End

	'summary: Calculate the cross product of this and another vector
	Method CrossProd:Float(vector2D:Vector2D)
		Return Self.x * vector2D.y - Self.y * vector2D.x
	End

	'summary: Calculate angle between any two vectors.
	Function AngleBetween:Float(vector1:Vector2D, vector2:Vector2D)
		If (Not vector1.IsNormalized()) Then vector1 = vector1.CloneVector().Normalize()
		If (Not vector2.IsNormalized()) Then vector2 = vector2.CloneVector().Normalize()
		Return ACos(vector1.DotProduct(vector2))
	End

	'summary: Is the vector to the right or left of this one?
	Method Sign:Int(vector2:Vector2D)
		If Perpendicular.DotProduct(vector2) < 0
			Return -1
		End
		Return 1
	End

	'summary: Get the vector that is perpendicular
	Method Perpendicular:Vector2D() Property
		Return New Vector2D(-y, x)
	End

	'summary: Calculate between two vectors
	Method Distance:Float(vector2:Vector2D)
		Return Sqrt(DistSQ(vector2))
	End

	'summary: Calculate squared distance between vectors. Faster than distance.
	Method DistSQ:Float(vector2:Vector2D)
		Local dx:Float = vector2.x - Self.x
		Local dy:Float = vector2.y - Self.y
		Return dx * dx + dy * dy
	End

	'summary: Add a vector to this vector.
	Method Add:Vector2D(vector2:Vector2D)
		Self.x += vector2.x
		Self.y += vector2.y
		Return Self
	End

	'summary: Subtract a vector from this one.
	Method Subtract:Vector2D(vector2:Vector2D)
		Self.x -= vector2.x
		Self.y -= vector2.y
		Return Self
	End

	'summary: Mutiplies this vector by a scalar
	Method Multiply:Vector2D(scalar:Float)
		Self.x *= scalar
		Self.y *= scalar
		Return Self
	End

	'summary: Divide this vector by a scalar
	Method Divide:Vector2D(scalar:Float)
		Self.x /= scalar
		Self.y /= scalar
		Return Self
	End

	'summary: Turn this vector into a string.
	Method ToString:String()
		Return "Vector2D x:" + Self.x + ", y:" + Self.y
	End

	'summary: Calculate distance between two points - overload using x,y
	Method Distance:Float(x:float, y:float)
		Return Sqrt((Self.x-x) * (Self.x-x) + (Self.y-y) * (Self.y-y))
	End
End


Forgot to comment-out a line.

Forgot to comment-out a line.

Strict

Public

' Preprocessor related:
#If LANG = "cpp"
	#SIZEOF_NATIVE = True
#End

' Imports:
'Import vector

' Constant variable(s):

' Standard type sizes (In bytes):
#If Not SIZEOF_NATIVE
	Const SizeOf_Integer:Int = 4 ' 8

	#If CPP_DOUBLE_PRECISION_FLOATS And LANG = "cpp" And TARGET <> "win8"
		Const SizeOf_FloatingPoint:Int = 8
	#Else
		Const SizeOf_FloatingPoint:Int = 4
	#End

	Const SizeOf_Boolean:Int = 1
#Else
	Const SizeOf_Integer:Int = SizeOf(0)
	Const SizeOf_FloatingPoint:Int = SizeOf(0.0)
	Const SizeOf_Boolean:Int = SizeOf(False)
#End

' External bindings:
#If SIZEOF_NATIVE
	Extern

	' Functions (Native):
	Function SizeOf:Int(I:Int)="(int)sizeof"
	Function SizeOf:Int(F:Float)="(int)sizeof"
	Function SizeOf:Int(B:Bool)="(int)sizeof"

	Public
#End

' Functions (Monkey):
Function IntSize:Int(Size:Int)
	If (Size > 1) Then
		If (Size > 4) Then
			Return 8
		Elseif (Size < 4) Then
			Return 2
		Else
			Return 4
		Endif
	Endif

	Return 1
End

#If Not SIZEOF_NATIVE
	Function SizeOf:Int(I:Int)
		Return SizeOf_Integer
	End

	Function SizeOf:Int(F:Float)
		Return SizeOf_FloatingPoint
	End

	Function SizeOf:Int(B:Bool)
		Return SizeOf_Boolean
	End
#End

Function SizeOf:Int(S:String)
	' Make the input-string upper-case.
	S = S.ToUpper()

	If (S.Find("INT") <> -1) Then
		Return SizeOf(0)
	Elseif (S.Find("FLOAT") <> -1) Then
		Return SizeOf(0.0)
	Elseif (S.Find("BOOL") <> -1) Then
		Return SizeOf(False)
	#Rem
		Elseif (S.Find("VEC") <> -1) Then
			Return Max(Int(S), 1)
	#End
	Endif

	' Return the default response.
	Return 1
End

Strict

Public

' Preprocessor related:
#If LANG = "cpp"
	#SIZEOF_NATIVE = True
#End

' Imports:
Import vector

' Constant variable(s):

' Standard type sizes (In bytes):
#If Not SIZEOF_NATIVE
	Const SizeOf_Integer:Int = 4 ' 8

	#If CPP_DOUBLE_PRECISION_FLOATS And LANG = "cpp" And TARGET <> "win8"
		Const SizeOf_FloatingPoint:Int = 8
	#Else
		Const SizeOf_FloatingPoint:Int = 4
	#End

	Const SizeOf_Boolean:Int = 1
#Else
	Const SizeOf_Integer:Int = SizeOf(0)
	Const SizeOf_FloatingPoint:Int = SizeOf(0.0)
	Const SizeOf_Boolean:Int = SizeOf(False)
#End

' External bindings:
#If SIZEOF_NATIVE
	Extern

	' Functions (Native):
	Function SizeOf:Int(I:Int)="(int)sizeof"
	Function SizeOf:Int(F:Float)="(int)sizeof"
	Function SizeOf:Int(B:Bool)="(int)sizeof"

	Public
#End

' Functions (Monkey):
Function IntSize:Int(Size:Int)
	If (Size > 1) Then
		If (Size > 4) Then
			Return 8
		Elseif (Size < 4) Then
			Return 2
		Else
			Return 4
		Endif
	Endif

	Return 1
End

#If Not SIZEOF_NATIVE
	Function SizeOf:Int(I:Int)
		Return SizeOf_Integer
	End

	Function SizeOf:Int(F:Float)
		Return SizeOf_FloatingPoint
	End

	Function SizeOf:Int(B:Bool)
		Return SizeOf_Boolean
	End
#End

Function SizeOf:Int(S:String)
	' Make the input-string upper-case.
	S = S.ToUpper()

	If (S.Find("INT") <> -1) Then
		Return SizeOf(0)
	Elseif (S.Find("FLOAT") <> -1) Then
		Return SizeOf(0.0)
	Elseif (S.Find("BOOL") <> -1) Then
		Return SizeOf(False)
	#Rem
		Elseif (S.Find("VEC") <> -1) Then
			Return Max(Int(S), 1)
	#End
	Endif

	' Return the default response.
	Return 1
End


alignment bug with scaled sprites fixed

alignment bug with scaled sprites fixed

Strict

Private

Import bono.src.utils
Import sprite
Import sizeable

Public

Class Align Abstract
    Const TOP:Int = 0
    Const BOTTOM:Int = 1
    Const LEFT:Int = 2
    Const RIGHT:Int = 3
    Const CENTER:Int = 4

    Function AdjustHorizontal:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Local scale:Float = 1
        If Sprite(object) Then scale = Sprite(object).scale.x

        Select mode
        Case LEFT
            ' Default alignment - nothing to do here
        Case RIGHT
            pos.x -= object.GetSize().x / scale
        Case CENTER
            pos.x -= object.GetSize().x / scale / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End

    Function AdjustVertical:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Local scale:Float = 1
        If Sprite(object) Then scale = Sprite(object).scale.y

        Select mode
        Case TOP
            ' Default alignment - nothing to do here
        Case BOTTOM
            pos.y -= object.GetSize().y / scale
        Case CENTER
            pos.y -= object.GetSize().y / scale / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End
End

Strict

Private

Import bono.src.utils
Import sizeable

Public

Class Align Abstract
    Const TOP:Int = 0
    Const BOTTOM:Int = 1
    Const LEFT:Int = 2
    Const RIGHT:Int = 3
    Const CENTER:Int = 4

    Function AdjustHorizontal:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Select mode
        Case LEFT
            ' Default alignment - nothing to do here
        Case RIGHT
            pos.x -= object.GetSize().x
        Case CENTER
            pos.x -= object.GetSize().x / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End

    Function AdjustVertical:Void(pos:Vector2D, object:Sizeable, mode:Int)
        Select mode
        Case TOP
            ' Default alignment - nothing to do here
        Case BOTTOM
            pos.y -= object.GetSize().y
        Case CENTER
            pos.y -= object.GetSize().y / 2
        Default
            Error("Invalid alignment mode (" + mode + ") given")
        End
    End
End


prevent RegistryStore from crashing with malformed data

Strict

Private

Import bono

Public

Class RegistryStore<T> Implements Persistable
    Private

    Const SEPARATOR:String = "--CONFIG::SEPARATOR--"
    Const DELIMITER:String = "--CONFIG::DELIMITER--"

    Public

    Method ToString:String()
        Local result:String = ""

        For Local key:String = EachIn Registry<T>.Keys()
            result += key
            result += DELIMITER
            result += Registry<T>.Get(key)
            result += SEPARATOR
        End

        Return result[..-SEPARATOR.Length()]
    End

    Method FromString:Void(data:String)
        If data.Length() = 0 Then Return
        If Not data.Contains(SEPARATOR) Then Return
        Local records:String[] = data.Split(SEPARATOR)

        For Local record:String = EachIn records
            If Not record.Contains(DELIMITER) Then Continue
            Local parts:String[] = record.Split(DELIMITER)
            Registry<T>.Set(parts[0], T(parts[1]))
        End
    End

    Function LoadStateStore:Void()
        Local tmp:RegistryStore<T> = New RegistryStore<T>()
        StateStore.Load(tmp)
    End

    Function SaveStateStore:Void()
        Local tmp:RegistryStore<T> = New RegistryStore<T>()
        StateStore.Save(tmp)
    End
End

Strict

Private

Import bono

Public

Class RegistryStore<T> Implements Persistable
    Private

    Const SEPARATOR:String = "--CONFIG::SEPARATOR--"
    Const DELIMITER:String = "--CONFIG::DELIMITER--"

    Public

    Method ToString:String()
        Local result:String = ""

        For Local key:String = EachIn Registry<T>.Keys()
            result += key
            result += DELIMITER
            result += Registry<T>.Get(key)
            result += SEPARATOR
        End

        Return result[..-SEPARATOR.Length()]
    End

    Method FromString:Void(data:String)
        If data.Length() = 0 Then Return
        Local records:String[] = data.Split(SEPARATOR)

        For Local record:String = EachIn records
            Local parts:String[] = record.Split(DELIMITER)
            Registry<T>.Set(parts[0], T(parts[1]))
        End
    End

    Function LoadStateStore:Void()
        Local tmp:RegistryStore<T> = New RegistryStore<T>()
        StateStore.Load(tmp)
    End

    Function SaveStateStore:Void()
        Local tmp:RegistryStore<T> = New RegistryStore<T>()
        StateStore.Save(tmp)
    End
End