IntStack replaced by Stack<Int>

IntStack replaced by Stack<Int>

Strict

Import mojo

Import flxextern
Import flxobject
Import flxrect
Import flxg
Import flxcamera
Import flxgroup
Import flxbasic
Import flxpath

Import system.flxtile
Import system.flxtilemapbuffer

Import "data/flx_autotiles.png"
Import "data/flx_autotiles_alt.png"

Class FlxTilemap Extends FlxObject

	Const AUTOTILES:String = FlxG.DATA_PREFIX + "autotiles"

	Const AUTOTILES_ALT:String = FlxG.DATA_PREFIX + "autotiles_alt"

	Const OFF:Int = 0

	Const AUTO:Int = 1

	Const ALT:Int = 2

	Field auto:Int

	Field widthInTiles:Int

	Field heightInTiles:Int

	Field totalTiles:Int

Private
	Global _tileLoader:FlxTileLoader = New FlxTileLoader()

	Field _tiles:Image

	Field _buffers:Stack<FlxTilemapBuffer>

	Field _data:Int[]

	Field _rects:FlxRect[]

	Field _tileWidth:Int

	Field _tileHeight:Int

	Field _tileObjects:FlxTile[]

	Field _startingIndex:Int = 0

	Field _camera:FlxCamera

	Field _buffer:FlxTilemapBuffer

	Field _screenXInTiles:Int

	Field _screenYInTiles:Int

	Field _screenRows:Int

	Field _screenColumns:Int

Public
	Method New()
		Super.New()
		auto = OFF
		widthInTiles = 0
		heightInTiles = 0
		totalTiles = 0
		_buffers = New Stack<FlxTilemapBuffer>()
		_tileWidth = 0
		_tileHeight = 0
		_tiles = Null
		immovable = True
		_startingIndex = 0
		_camera = Null
		_buffer = Null
	End Method

	Method Destroy:Void()
		_tiles = Null
		_camera = Null
		_buffer = Null

		Local i:Int = 0
		Local l:Int = _tileObjects.Length()

		While (i < l)
			_tileObjects[i].Destroy()
			_tileObjects[i] = Null
		Wend

		_buffers = Null

		Super.Destroy()
	End Method

	Method LoadMap:FlxTilemap(mapData:String, tileGraphic:String, tileWidth:Int = 0, tileHeight:Int = 0, autoTile:Int = OFF, startIndex:Int = 0, drawIndex:Int = 1, collideIndex:Int = 1)
		auto = autoTile
		_startingIndex = startIndex

		Local columns:String[]
		Local rows:String[] = mapData.Split("~n")
		Local row:Int = 0
		Local column:Int
		Local data:Stack<Int> = New Stack<Int>()

		heightInTiles = rows.Length()

		While (row < heightInTiles)
			columns = rows[row].Split(",")

			If (columns.Length() <= 1) Then
				heightInTiles = heightInTiles - 1
				Continue
			End If

			If (widthInTiles = 0) Then
				widthInTiles = columns.Length()
			End If

			column = 0

			While (column < widthInTiles)
				data.Push(Int(columns[column]))
				column += 1
			Wend

			row += 1
		Wend

		_data = data.ToArray()

		Local i:Int

		totalTiles = widthInTiles * heightInTiles

		If (auto > OFF) Then
			_startingIndex = 1
			drawIndex = 1
			collideIndex = 1
			i = 0

			While (i < totalTiles)
				_AutoTile(i)
				i += 1
			Wend
		End If

		_tiles = FlxG.AddBitmap(tileGraphic, _tileLoader)

		_tileWidth = tileWidth
		If (_tileWidth = 0) _tileWidth = _tiles.Height()

		_tileHeight = tileHeight
		If (_tileHeight = 0) _tileHeight = _tileWidth

		i = 0
		Local l:Int = (_tiles.Width() / _tileWidth) * (_tiles.Height() / _tileHeight)

		If (auto > OFF) l += 1
		_tileObjects = _tileObjects.Resize(l)

		While (i < l)
			If (i >= collideIndex) Then
				_tileObjects[i] = New FlxTile(Self, i, _tileWidth, _tileHeight, (i >= drawIndex), allowCollisions)
			Else
				_tileObjects[i] = New FlxTile(Self, i, _tileWidth, _tileHeight, (i >= drawIndex), NONE)
			End If

			i += 1
		Wend

		width = widthInTiles * _tileWidth
		height = heightInTiles * _tileHeight
		_rects = _rects.Resize(totalTiles)
		i = 0

		While (i < totalTiles)
			_UpdateTile(i)
			i += 1
		Wend

		Return Self
	End Method

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

		_camera = FlxG._currentCamera

		If (FlxG._currentCameraID >= _buffers.Length()) _buffers.Push(Null)
		_buffer = _buffers.Get(FlxG._currentCameraID)

		If (_buffer = Null) Then
			_buffer = New FlxTilemapBuffer(_tileWidth, _tileHeight, widthInTiles, heightInTiles, _camera)
			_buffers.Set(FlxG._currentCameraID, _buffer)
		End If

		_screenRows = _buffer.rows
		_screenColumns = _buffer.columns

		If (Not _buffer.dirty) Then
			_point.x = x - Int(_camera.scroll.x * scrollFactor.x) + _buffer.x
			_point.y = y - Int(_camera.scroll.y * scrollFactor.y) + _buffer.y

			_buffer.dirty = _point.x > 0 Or _point.y > 0 Or _point.x + _buffer.width < _camera.Width Or _point.y + _buffer.height < _camera.Height
		End If

		If (_buffer.dirty) Then
			_point.x = Int(_camera.scroll.x * scrollFactor.x) - x
			_point.y = Int(_camera.scroll.y * scrollFactor.y) - y

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

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

			If (_screenXInTiles < 0) _screenXInTiles = 0
			If (_screenXInTiles > widthInTiles - _screenColumns) _screenXInTiles = widthInTiles - _screenColumns
			If (_screenYInTiles < 0) _screenYInTiles = 0
			If (_screenYInTiles > heightInTiles - _screenRows) _screenYInTiles = heightInTiles - _screenRows

			_buffer.x = _screenXInTiles * _tileWidth
			_buffer.y = _screenYInTiles * _tileHeight
		End If

		_point.x = x - Int(_camera.scroll.x * scrollFactor.x) + _buffer.x
		_point.y = y - Int(_camera.scroll.y * scrollFactor.y) + _buffer.y

		If (FlxG._lastDrawingBlend <> AlphaBlend) Then
			SetBlend(AlphaBlend)
			FlxG._lastDrawingBlend = AlphaBlend
		End If

		If (FlxG._lastDrawingColor <> _camera.Color) Then
			SetColor(_camera._color.r, _camera._color.g, _camera._color.b)
			FlxG._lastDrawingColor = _camera.Color
		End If

		Local alpha:Float = _camera._color.a * _camera.Alpha

		If (FlxG._lastDrawingAlpha <> alpha) Then
			SetAlpha(alpha)
			FlxG._lastDrawingAlpha = alpha
		End If

		PushMatrix()
			Translate( _point.x, _point.y)

			Local rowIndex:Int = _screenYInTiles * widthInTiles + _screenXInTiles
			Local row:Int = 0
			Local column:Int
			Local columnIndex:Int
			Local tile:FlxTile

			_point.y = 0

			If (_buffer.scaleFixX = 1 Or _buffer.scaleFixY = 1) Then
				While (row < _screenRows)
					columnIndex = rowIndex
					column = 0
					_point.x = 0

					While (column < _screenColumns)
						_rect = _rects[columnIndex]

						If (_rect <> Null) Then
							DrawImageRect(_tiles, _point.x, _point.y, _rect.x, _rect.y, _rect.width, _rect.height)

							If (FlxG.visualDebug And Not ignoreDrawDebug) Then
								'TODO
							End If
						End If

						_point.x += _tileWidth
						column += 1
						columnIndex += 1
					Wend

					rowIndex += widthInTiles
					_point.y += _tileHeight
					row += 1
				Wend
			Else
				While (row < _screenRows)
					columnIndex = rowIndex
					column = 0
					_point.x = 0

					While (column < _screenColumns)
						_rect = _rects[columnIndex]

						If (_rect <> Null) Then
							DrawImageRect(_tiles, _point.x, _point.y, _rect.x, _rect.y, _rect.width, _rect.height, 0, _buffer.scaleFixX, _buffer.scaleFixY)

							If (FlxG.visualDebug And Not ignoreDrawDebug) Then
								'TODO
							End If
						End If

						_point.x += _tileWidth
						column += 1
						columnIndex += 1
					Wend

					rowIndex += widthInTiles
					_point.y += _tileHeight
					row += 1
				Wend
			End If
		PopMatrix()

		_VISIBLECOUNT += 1
	End Method

	Method GetData:Int[](simple:Bool = False)
		If (Not simple) Return _data

		Local i:Int = 0
		Local l:Int = _data.Length()
		Local data:Int[l]

		While (i < l)
			If (_tileObjects[_data[i]].allowCollisions > 0) Then
				data[i] = 1
			Else
				data[i] = 0
			End If

			i += 1
		Wend

		Return data
	End Method

	Method SetDirty:Void(dirty:Bool = True)
		Local i:Int = 0
		Local l:Int = _buffers.Length()

		While (i < l)
			_buffers.Get(i).dirty = dirty
			i += 1
		Wend
	End Method

	Method FindPath:FlxPath(start:FlxPoint, endPoint:FlxPoint, simplify:Bool = True, raySimplify:Bool = False)
		Local startIndex:Int = Int((start.y - y) / _tileHeight) * widthInTiles + Int((start.x - x) / _tileWidth)
		Local endIndex:Int = Int((endPoint.y - y) / _tileHeight) * widthInTiles + Int((endPoint.x - x) / _tileWidth)

		If (_tileObjects[_data[startIndex]].allowCollisions > 0 Or _tileObjects[_data[endIndex]].allowCollisions > 0) Then
			Return Null
		End If

		Local distances:Int[] = _ComputePathDistance(startIndex, endIndex)
		If (distances.Length() = 0) Return Null

		Local points:Stack<Int> = New Stack<Int>()
		_WalkPath(distances, endIndex, points)

		Local node:FlxPoint

		node = points.Top()
		node.x = start.x
		node.y = start.y

		node = points.Get(0)
		node.x = endPoint.x
		node.y = endPoint.y

		If (simplify) _SimplifyPath(points)
		If (raySimplify) _RaySimplifyPath(points)

		Local path:FlxPath = New FlxPath()
		Local i:Int = points.length() - 1

		While (i >= 0)
			node = points.Get(i)

			If (node <> Null) Then
				path.AddPoint(node, true)
			End If

			i -= 1
		Wend

		Return path
	End Method

	Method Overlaps:Bool(objectOrGroup:FlxBasic, inScreenSpace:Bool = False, camera:FlxCamera = Null)
		If (FlxGroup(objectOrGroup) <> Null) Then
			Local results:Bool = False
			Local basic:FlxBasic
			Local i:Int = 0
			Local members:FlxBasic[] = FlxGroup(objectOrGroup).Members
			Local l:Int = members.Length()

			While (i < l)
				basic = members[i]

				If (FlxObject(basic) <> Null) Then
					If (OverlapsWithCallback(FlxObject(basic))) Then
						results = True
					End If

				Else
					If (Overlaps(x, y, basic, inScreenSpace, camera)) Then
						results = True
					End If
				End If

				i += 1
			Wend

			Return results

		ElseIf (FlxObject(objectOrGroup) <> Null) Then
			Return OverlapsWithCallback(FlxObject(objectOrGroup))
		End If

		Return False
	End Method

	Method OverlapsAt:Bool(x:Float, y:Float, objectOrGroup:FlxBasic, inScreenSpace:Bool = False, camera:FlxCamera = Null)
		If (FlxGroup(objectOrGroup) <> Null) Then
			Local results:Bool = False
			Local basic:FlxBasic
			Local i:Int = 0
			Local members:FlxBasic[] = FlxGroup(objectOrGroup).Members
			Local l:Int = members.Length()

			While (i < l)
				basic = members[i]

				If (FlxObject(basic) <> Null) Then
					_point.x = x
					_point.y = y

					If (OverlapsWithCallback(FlxObject(basic), Null, False, _point)) Then
						results = True
					End If

				Else
					If (OverlapsAt(x, y, basic, inScreenSpace, camera)) Then
						results = True
					End If
				End If

				i += 1
			Wend

			Return results

		ElseIf (FlxObject(objectOrGroup) <> Null) Then
			_point.x = x
			_point.y = y

			Return OverlapsWithCallback(FlxObject(objectOrGroup), Null, False, _point)
		End If

		Return False
	End Method

	Method OverlapsWithCallback:Bool(object:FlxObject, callback:FlxTileOverlapChecker = Null, flipCallbackParams:Bool = False, position:FlxPoint = Null)
		Local results:Bool = False

		Local lx:Float = x
		Local ly:Float = y

		If (position <> Null) Then
			lx = position.x
			ly = position.y
		End If

		Local selectionX:Int = Floor((object.x - lx) / _tileWidth)
		Local selectionY:Int = Floor((object.y - ly) / _tileHeight)
		Local selectionWidth:Int = selectionX + Ceil(object.width / _tileWidth) + 1
		Local selectionHeight:Int = selectionY + Ceil(object.height / _tileHeight) + 1

		If (selectionX < 0) selectionX = 0
		If (selectionY < 0) selectionY = 0
		If (selectionWidth > widthInTiles) selectionWidth = widthInTiles
		If (selectionHeight > heightInTiles) selectionHeight = heightInTiles

		Local rowStart:Int = selectionY * widthInTiles
		Local row:Int = selectionY
		Local column:Int
		Local tile:FlxTile
		Local overlapFound:Bool
		Local deltaX:Float = lx - last.x
		Local deltaY:Float = ly - last.y

		While (row < selectionHeight)
			column = selectionX

			While (column < selectionWidth)
				overlapFound = False
				tile = _tileObjects[_data[rowStart + column]]

				If (tile.allowCollisions) Then
					tile.x = lx + column * _tileWidth
					tile.y = ly + row * _tileHeight
					tile.last.x = tile.x - deltaX
					tile.last.y = tile.y - deltaY

					If (callback <> Null) Then
						If (flipCallbackParams) Then
							overlapFound = callback.IsTileOverlap(object, tile)
						Else
							overlapFound = callback.IsTileOverlap(tile, object)
						End If
					Else
						overlapFound = (object.x + object.width > tile.x And object.x < tile.x + tile.width And object.y + object.height > tile.y And object.y < tile.y + tile.height)
					End If

					If (overlapFound) Then
						If (tile.callback <> Null And (tile.filter = Null Or tile.filter.InstanceOf(object))) Then
							tile.mapIndex = rowStart + column
							tile.callback.OnTileHit(tile, object)
						End If

						results = True
					End If

				ElseIf (tile.callback <> Null And (tile.filter = Null Or tile.filter.InstanceOf(object))) Then
					tile.mapIndex = rowStart + column
					tile.callback.OnTileHit(tile, object)
				End If

				column += 1
			Wend

			rowStart += widthInTiles
			row += 1
		Wend

		Return results
	End Method

	Method OverlapsPoint:Bool(point:FlxPoint, inScreenSpace:Bool = False, camera:FlxCamera = Null)
		If (Not inScreenSpace) Then
			Return _tileObjects[_data[Int(Int((point.y - y) / _tileHeight) * widthInTiles + (point.x - x) / _tileWidth)]].allowCollisions > 0
		End If

		If (camera = Null) camera = FlxG.camera

		point.x -= camera.scroll.x
		point.y -= camera.scroll.y

		GetScreenXY(_point, camera)

		Return _tileObjects[_data[Int(Int((point.y - _point.y) / _tileHeight) * widthInTiles + (point.x - _point.x) / _tileWidth)]].allowCollisions > 0
	End Method

	Method GetTile:Int(x:Int, y:Int)
		Return _data[y * widthInTiles + x]
	End Method

	Method GetTileByIndex:Int(index:Int)
		Return _data[index]
	End Method

	Method GetTileInstances:Stack<Int>(index:Int)
		Local elements:Stack<Int> = Null

		Local i:Int = 0
		Local l:Int = widthInTiles * heightInTiles

		While (i < l)
			If (_data[i] = index) Then
				If (elements = Null) elements = New Stack<Int>()
				elements.Push(i)
			End If

			i += 1
		Wend

		Return elements
	End Method

	Method GetTileCoords:Stack<FlxPoint>(index:Int, midpoint:Bool = True)
		Local elements:Stack<FlxPoint> = Null

		Local point:FlxPoint
		Local i:Int = 0
		Local l:Int = widthInTiles * heightInTiles

		While (i < l)
			If (_data[i] = index) Then
				point = New FlxPoint(x + Int(i Mod widthInTiles) * _tileWidth, y + Int(i / widthInTiles) * _tileHeight)

				If (midpoint) Then
					point.x += _tileWidth * .5
					point.y += _tileHeight * .5
				End If

				If (elements = Null) elements = New Stack<FlxPoint>()
				elements.Push(point)
			End If

			i += 1
		Wend

		Return elements
	End Method

	Method SetTile:Bool(x:Int, y:Int, tile:Int, updateGraphics:Bool = True)
		If (x >= widthInTiles Or y >= heightInTiles) Then
			Return False
		End If

		Return SetTileByIndex(y * widthInTiles + x, tile, updateGraphics)
	End Method

	Method SetTileByIndex:Bool(index:Int, tile:Int, updateGraphics:Bool = True)
		If (index >= _data.Length()) Return False

		_data[index] = tile

		If (Not updateGraphics) Return True

		If (auto = OFF) Then
			_UpdateTile(index)
			Return True
		End If

		Local i:Int = 0
		Local row:Int = Int(index / widthInTiles) - 1
		Local rowLength:Int = row + 3
		Local column:Int = index Mod widthInTiles - 1
		Local columnHeight:Int = column + 3

		While (row < rowLength)
			column = columnHeight - 3

			While (column < columnHeight)
				If (row >= 0 And row < heightInTiles And column >= 0 And column < widthInTiles) Then
					i = row * widthInTiles + column
					_AutoTile(i)
					_UpdateTile(i)
				End If

				column += 1
			Wend

			row += 1
		Wend

		Return True
	End Method

	Method SetTileProperties:Void(tile:Int, allowCollisions:Int = $1111, callback:FlxTileHitListener = Null, callbackFilter:FlxClass, range:Int = 1)
		If (range <= 0) range = 1

		Local tileObject:FlxTile
		Local i:Int = tile
		Local l:Int = tile + range

		While (i < l)
			tileObject = _tileObjects[i]

			tileObject.allowCollisions = allowCollisions
			tileObject.callback = callback
			tileObject.filter = callbackFilter

			i += 1
		Wend
	End Method

	Method Follow:Void(camera:FlxCamera = Null, border:Int = 0, updateWorld:Bool = True)
		If (camera = Null) camera = FlxCamera
		camera.SetBounds(x + border * _tileWidth, y + border * _tileHeight, width - border * _tileWidth * 2, height - border * _tileHeight * 2, updateWorld)
	End Method

	Method GetBounds:FlxRect(bounds:FlxRect = Null)
		If (bounds = Null) bounds = New FlxRect()
		Return bounds.Make(x, y, width, height)
	End Method

	Method Ray:Bool(startPoint:FlxPoint, endPoint:FlxPoint, result:FlxPoint = Null, resolution:Float = 1)
		Local _step:Float = _tileWidth

		If (_tileHeight < _tileWidth) Then
			_step = _tileHeight
		End If

		_step /= resolution

		Local deltaX:Float = endPoint.x - startPoint.x
		Local deltaY:Float = endPoint.y - startPoint.y
		Local distance:Float = Sqrt(deltaX * deltaX + deltaY * deltaY)
		Local steps:Int = Ceil(distance / _step)
		Local stepX:Float = deltaX / steps
		Local stepY:Float = deltaY / steps
		Local curX:Float = startPoint.x - stepX - x
		Local curY:Float = startPoint.y - stepY - y
		Local tileX:Int
		Local tileY:Int
		Local i:Int = 0

		While (i < steps)
			curX += stepX
			curY += stepY

			If (curX < 0 Or curX > width Or curY < 0 Or curY > height) Then
				i += 1
				Continue
			End If

			tileX = curX / _tileWidth
			tileY = curY / _tileHeight

			If (_tileObjects[_data[tileY * widthInTiles + tileX]].allowCollisions) Then
				tileX *= _tileWidth
				tileY *= _tileHeight

				Local rx:Float = 0
				Local ry:Float = 0
				Local q:Float
				Local lx:Float = curX - stepX
				Local ly:Float = curY - stepY

				q = tileX
				If (deltaX < 0) q += _tileWidth

				rx = q
				ry = ly + stepY * ((q - lx) / stepX)

				If (ry < tileY And ry < tileY + _tileHeight) Then
					If (result = Null) Then
						result = New FlxPoint()
					End If

					result.x = rx
					result.y = ry

					Return False
				End If

				q = tileY
				If (deltaY < 0) q += _tileHeight

				rx = lx + stepX * ((q - ly) / stepY)
				ry = q

				If (rx > tileX And rx < tileX + _tileWidth) Then
					If (result = Null) Then
						result = New FlxPoint()
					End If

					result.x = rx
					result.y = ry

					Return False
				End If

				Return True
			End If

			i += 1
		Wend

		Return True
	End Method

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

Private
	Method _SimplifyPath:Void(points:Stack<FlxPoint>)
		Local deltaPrevious:Float
		Local deltaNext:Float
		Local last:FlxPoint = points.Get(0)
		Local node:FlxPoint
		Local nextPoint:FlxPoint
		Local i:Int = 1
		Local l:Int = points.Length() - 1

		While (i < l)
			node = points.Get(i)
			nextPoint = points.Get(i + 1)

			deltaPrevious = (node.x - last.x) / (node.y - last.y)
			deltaNext = (node.x - nextPoint.x) / (node.y - nextPoint.y)

			If (last.x = nextPoint.x Or last.y = nextPoint.y Or deltaPrevious = deltaNext) Then
				points.Set(i, Null)
			Else
				last = node
			End If

			i += 1
		Wend
	End Method

	Method _RaySimplifyPath:Void(points:Stack<FlxPoint>)
		Local source:FlxPoint = points.Get(0)
		Local lastIndex:Int = -1
		Local node:FlxPoint
		Local i:Int = 1
		Local l:Int = points.Length()

		While (i < l)
			node = points.Get(i)
			i += 1

			If (node = Null) Continue

			If (Ray(source, node, _point)) Then
				If (lastIndex >= 0) points.Set(lastIndex, Null)
			Else
				source = points.Get(lastIndex)
			End If

			lastIndex = i - 1
		Wend
	End Method

	Method _ComputePathDistance:Int[](startIndex:Int, endIndex:Int)
		Local mapSize:Int = widthInTiles * heightInTiles
		Local distances:Int[mapSize]
		Local i:Int = 0

		While (i < mapSize)
			If (_tileObjects[_data[i]].allowCollisions) Then
				distances[i] = -2
			Else
				distances[i] = -1
			End If

			i += 1
		Wend

		distances[startIndex] = 0

		Local distance:Int = 1
		Local neighbors:Stack<Int> = New Stack<Int>([startIndex])
		Local current:Stack<Int>
		Local currentIndex:Int
		Local left:Bool
		Local right:Bool
		Local up:Bool
		Local down:Bool
		Local currentLength:Int
		Local foundEnd:Bool = False

		While (neighbors.Length() > 0)
			current = neighbors
			neighbors = New Stack<Int>()

			i = 0
			currentLength = current.Length()

			While (i < currentLength)
				currentIndex = current.Get(i)

				If (currentIndex = endIndex) Then
					foundEnd = True
					neighbors.Clear()
					Exit
				End If

				left = currentIndex Mod widthInTiles > 0
				right = currentIndex Mod widthInTiles < widthInTiles - 1
				up = currentIndex / widthInTiles > 0
				down = currentIndex / widthInTiles < heightInTiles - 1

				Local index:Int

				If (up) Then
					index = currentIndex - widthInTiles

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (right) Then
					index = currentIndex + 1

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (down) Then
					index = currentIndex + widthInTiles

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (left) Then
					index = currentIndex - 1

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (up And right) Then
					index = currentIndex - widthInTiles + 1

					If (distances[index] = -1 And distances[currentIndex - widthInTiles] >= -1 And distances[currentIndex + 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (right And down) Then
					index = currentIndex + widthInTiles + 1

					If (distances[index] = -1 And distances[currentIndex + widthInTiles] >= -1 And distances[currentIndex + 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (left And down) Then
					index = currentIndex + widthInTiles - 1

					If (distances[index] = -1 And distances[currentIndex + widthInTiles] >= -1 And distances[currentIndex - 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (up And left) Then
					index = currentIndex - widthInTiles - 1

					If (distances[index] = -1 And distances[currentIndex - widthInTiles] >= -1 And distances[currentIndex - 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				i += 1
			Wend

			distance += 1
		Wend

		If (Not foundEnd) distances = []

		Return distances
	End Method

	Method _WalkPath:Void(data:Int[], start:Int, points:Stack<FlxPoint>)
		points.Push(New FlxPoint(x + Int(start Mod widthInTiles) * _tileWidth + _tileWidth * .5, y + Int(start Mod widthInTiles) * _tileHeight + _tileHeight * .5))
		If (data[start] = 0) Return

		Local left:Bool = start Mod widthInTiles > 0
		Local right:Bool = start Mod widthInTiles < widthInTiles - 1
		Local up:Bool = start / widthInTiles > 0
		Local down:Bool = start / widthInTiles < heightInTiles - 1

		Local current:Int = data[start]
		Local i:Int

		If (up) Then
			i = start - widthInTiles

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (right) Then
			i = start + 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (down) Then
			i = start + widthInTiles

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (left) Then
			i = start - 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (up And Right) Then
			i = start - widthInTiles + 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (right And down) Then
			i = start + widthInTiles + 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (left And down) Then
			i = start + widthInTiles - 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (up And left) Then
			i = start - widthInTiles - 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If
	End Method

	Method _AutoTile:Void(index:Int)
		If (_data[index] = 0) Return

		_data[index] = 0

		If (index - widthInTiles < 0 Or _data[index - widthInTiles] > 0) Then
			_data[index] += 1
		End If

		If (index Mod widthInTiles >= widthInTiles - 1 Or _data[index + 1] > 0) Then
			_data[index] += 2
		End If

		If (index + widthInTiles >= totalTiles Or _data[index + widthInTiles] > 0) Then
			_data[index] += 4
		End If

		If (index Mod widthInTiles <= 0 Or _data[index - 1] > 0) Then
			_data[index] += 8
		End If

		If (auto = ALT And _data[index] = 15) Then
			If (index Mod widthInTiles > 0 And index + widthInTiles < totalTiles And _data[index + widthInTiles - 1] <= 0) Then
				_data[index] = 1
			End If

			If (index Mod widthInTiles > 0 And index - widthInTiles >= 0 And _data[index - widthInTiles - 1] <= 0) Then
				_data[index] = 2
			End If

			If (index Mod widthInTiles < widthInTiles - 1 And index - widthInTiles >= 0 And _data[index - widthInTiles + 1] <= 0) Then
				_data[index] = 4
			End If

			If (index Mod widthInTiles < widthInTiles - 1 And index + widthInTiles >= totalTiles And _data[index + widthInTiles + 1] <= 0) Then
				_data[index] = 8
			End If
		End If

		_data[index] += 1
	End Method

	Method _UpdateTile:Void(index:Int)
		Local tile:FlxTile = _tileObjects[_data[index]]

		If (tile = Null Or Not tile.visible) Then
			_rects[index] = Null
			Return
		End If

		Local rx:Int = (_data[index] - _startingIndex) * _tileWidth
		Local ry:Int = 0

		If (rx >= _tiles.Width()) Then
			ry = Int(rx / _tiles.Width()) * _tileHeight
			rx Mod= _tiles.Width()
		End If

		_rects[index] = New FlxRect(rx, ry, _tileWidth, _tileHeight)
	End Method

End Class

Private
Class FlxTileLoader Extends FlxResourceLoader<Image>

	Method Load:Image(name:String)
		Return LoadImage(FlxAssetsManager.GetImagePath(name))
	End Method

End Class

Strict

Import mojo

Import flxextern
Import flxobject
Import flxrect
Import flxg
Import flxcamera
Import flxgroup
Import flxbasic
Import flxpath

Import system.flxtile
Import system.flxtilemapbuffer

Import "data/flx_autotiles.png"
Import "data/flx_autotiles_alt.png"

Class FlxTilemap Extends FlxObject

	Const AUTOTILES:String = FlxG.DATA_PREFIX + "autotiles"

	Const AUTOTILES_ALT:String = FlxG.DATA_PREFIX + "autotiles_alt"

	Const OFF:Int = 0

	Const AUTO:Int = 1

	Const ALT:Int = 2

	Field auto:Int

	Field widthInTiles:Int

	Field heightInTiles:Int

	Field totalTiles:Int

Private
	Global _tileLoader:FlxTileLoader = New FlxTileLoader()

	Field _tiles:Image

	Field _buffers:Stack<FlxTilemapBuffer>

	Field _data:Int[]

	Field _rects:FlxRect[]

	Field _tileWidth:Int

	Field _tileHeight:Int

	Field _tileObjects:FlxTile[]

	Field _startingIndex:Int = 0

	Field _camera:FlxCamera

	Field _buffer:FlxTilemapBuffer

	Field _screenXInTiles:Int

	Field _screenYInTiles:Int

	Field _screenRows:Int

	Field _screenColumns:Int

Public
	Method New()
		Super.New()
		auto = OFF
		widthInTiles = 0
		heightInTiles = 0
		totalTiles = 0
		_buffers = New Stack<FlxTilemapBuffer>()
		_tileWidth = 0
		_tileHeight = 0
		_tiles = Null
		immovable = True
		_startingIndex = 0
		_camera = Null
		_buffer = Null
	End Method

	Method Destroy:Void()
		_tiles = Null
		_camera = Null
		_buffer = Null

		Local i:Int = 0
		Local l:Int = _tileObjects.Length()

		While (i < l)
			_tileObjects[i].Destroy()
			_tileObjects[i] = Null
		Wend

		_buffers = Null

		Super.Destroy()
	End Method

	Method LoadMap:FlxTilemap(mapData:String, tileGraphic:String, tileWidth:Int = 0, tileHeight:Int = 0, autoTile:Int = OFF, startIndex:Int = 0, drawIndex:Int = 1, collideIndex:Int = 1)
		auto = autoTile
		_startingIndex = startIndex

		Local columns:String[]
		Local rows:String[] = mapData.Split("~n")
		Local row:Int = 0
		Local column:Int
		Local data:IntStack = New IntStack()

		heightInTiles = rows.Length()

		While (row < heightInTiles)
			columns = rows[row].Split(",")

			If (columns.Length() <= 1) Then
				heightInTiles = heightInTiles - 1
				Continue
			End If

			If (widthInTiles = 0) Then
				widthInTiles = columns.Length()
			End If

			column = 0

			While (column < widthInTiles)
				data.Push(Int(columns[column]))
				column += 1
			Wend

			row += 1
		Wend

		_data = data.ToArray()

		Local i:Int

		totalTiles = widthInTiles * heightInTiles

		If (auto > OFF) Then
			_startingIndex = 1
			drawIndex = 1
			collideIndex = 1
			i = 0

			While (i < totalTiles)
				_AutoTile(i)
				i += 1
			Wend
		End If

		_tiles = FlxG.AddBitmap(tileGraphic, _tileLoader)

		_tileWidth = tileWidth
		If (_tileWidth = 0) _tileWidth = _tiles.Height()

		_tileHeight = tileHeight
		If (_tileHeight = 0) _tileHeight = _tileWidth

		i = 0
		Local l:Int = (_tiles.Width() / _tileWidth) * (_tiles.Height() / _tileHeight)

		If (auto > OFF) l += 1
		_tileObjects = _tileObjects.Resize(l)

		While (i < l)
			If (i >= collideIndex) Then
				_tileObjects[i] = New FlxTile(Self, i, _tileWidth, _tileHeight, (i >= drawIndex), allowCollisions)
			Else
				_tileObjects[i] = New FlxTile(Self, i, _tileWidth, _tileHeight, (i >= drawIndex), NONE)
			End If

			i += 1
		Wend

		width = widthInTiles * _tileWidth
		height = heightInTiles * _tileHeight
		_rects = _rects.Resize(totalTiles)
		i = 0

		While (i < totalTiles)
			_UpdateTile(i)
			i += 1
		Wend

		Return Self
	End Method

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

		_camera = FlxG._currentCamera

		If (FlxG._currentCameraID >= _buffers.Length()) _buffers.Push(Null)
		_buffer = _buffers.Get(FlxG._currentCameraID)

		If (_buffer = Null) Then
			_buffer = New FlxTilemapBuffer(_tileWidth, _tileHeight, widthInTiles, heightInTiles, _camera)
			_buffers.Set(FlxG._currentCameraID, _buffer)
		End If

		_screenRows = _buffer.rows
		_screenColumns = _buffer.columns

		If (Not _buffer.dirty) Then
			_point.x = x - Int(_camera.scroll.x * scrollFactor.x) + _buffer.x
			_point.y = y - Int(_camera.scroll.y * scrollFactor.y) + _buffer.y

			_buffer.dirty = _point.x > 0 Or _point.y > 0 Or _point.x + _buffer.width < _camera.Width Or _point.y + _buffer.height < _camera.Height
		End If

		If (_buffer.dirty) Then
			_point.x = Int(_camera.scroll.x * scrollFactor.x) - x
			_point.y = Int(_camera.scroll.y * scrollFactor.y) - y

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

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

			If (_screenXInTiles < 0) _screenXInTiles = 0
			If (_screenXInTiles > widthInTiles - _screenColumns) _screenXInTiles = widthInTiles - _screenColumns
			If (_screenYInTiles < 0) _screenYInTiles = 0
			If (_screenYInTiles > heightInTiles - _screenRows) _screenYInTiles = heightInTiles - _screenRows

			_buffer.x = _screenXInTiles * _tileWidth
			_buffer.y = _screenYInTiles * _tileHeight
		End If

		_point.x = x - Int(_camera.scroll.x * scrollFactor.x) + _buffer.x
		_point.y = y - Int(_camera.scroll.y * scrollFactor.y) + _buffer.y

		If (FlxG._lastDrawingBlend <> AlphaBlend) Then
			SetBlend(AlphaBlend)
			FlxG._lastDrawingBlend = AlphaBlend
		End If

		If (FlxG._lastDrawingColor <> _camera.Color) Then
			SetColor(_camera._color.r, _camera._color.g, _camera._color.b)
			FlxG._lastDrawingColor = _camera.Color
		End If

		Local alpha:Float = _camera._color.a * _camera.Alpha

		If (FlxG._lastDrawingAlpha <> alpha) Then
			SetAlpha(alpha)
			FlxG._lastDrawingAlpha = alpha
		End If

		PushMatrix()
			Translate( _point.x, _point.y)

			Local rowIndex:Int = _screenYInTiles * widthInTiles + _screenXInTiles
			Local row:Int = 0
			Local column:Int
			Local columnIndex:Int
			Local tile:FlxTile

			_point.y = 0

			If (_buffer.scaleFixX = 1 Or _buffer.scaleFixY = 1) Then
				While (row < _screenRows)
					columnIndex = rowIndex
					column = 0
					_point.x = 0

					While (column < _screenColumns)
						_rect = _rects[columnIndex]

						If (_rect <> Null) Then
							DrawImageRect(_tiles, _point.x, _point.y, _rect.x, _rect.y, _rect.width, _rect.height)

							If (FlxG.visualDebug And Not ignoreDrawDebug) Then
								'TODO
							End If
						End If

						_point.x += _tileWidth
						column += 1
						columnIndex += 1
					Wend

					rowIndex += widthInTiles
					_point.y += _tileHeight
					row += 1
				Wend
			Else
				While (row < _screenRows)
					columnIndex = rowIndex
					column = 0
					_point.x = 0

					While (column < _screenColumns)
						_rect = _rects[columnIndex]

						If (_rect <> Null) Then
							DrawImageRect(_tiles, _point.x, _point.y, _rect.x, _rect.y, _rect.width, _rect.height, 0, _buffer.scaleFixX, _buffer.scaleFixY)

							If (FlxG.visualDebug And Not ignoreDrawDebug) Then
								'TODO
							End If
						End If

						_point.x += _tileWidth
						column += 1
						columnIndex += 1
					Wend

					rowIndex += widthInTiles
					_point.y += _tileHeight
					row += 1
				Wend
			End If
		PopMatrix()

		_VISIBLECOUNT += 1
	End Method

	Method GetData:Int[](simple:Bool = False)
		If (Not simple) Return _data

		Local i:Int = 0
		Local l:Int = _data.Length()
		Local data:Int[l]

		While (i < l)
			If (_tileObjects[_data[i]].allowCollisions > 0) Then
				data[i] = 1
			Else
				data[i] = 0
			End If

			i += 1
		Wend

		Return data
	End Method

	Method SetDirty:Void(dirty:Bool = True)
		Local i:Int = 0
		Local l:Int = _buffers.Length()

		While (i < l)
			_buffers.Get(i).dirty = dirty
			i += 1
		Wend
	End Method

	Method FindPath:FlxPath(start:FlxPoint, endPoint:FlxPoint, simplify:Bool = True, raySimplify:Bool = False)
		Local startIndex:Int = Int((start.y - y) / _tileHeight) * widthInTiles + Int((start.x - x) / _tileWidth)
		Local endIndex:Int = Int((endPoint.y - y) / _tileHeight) * widthInTiles + Int((endPoint.x - x) / _tileWidth)

		If (_tileObjects[_data[startIndex]].allowCollisions > 0 Or _tileObjects[_data[endIndex]].allowCollisions > 0) Then
			Return Null
		End If

		Local distances:Int[] = _ComputePathDistance(startIndex, endIndex)
		If (distances.Length() = 0) Return Null

		Local points:IntStack = New IntStack()
		_WalkPath(distances, endIndex, points)

		Local node:FlxPoint

		node = points.Top()
		node.x = start.x
		node.y = start.y

		node = points.Get(0)
		node.x = endPoint.x
		node.y = endPoint.y

		If (simplify) _SimplifyPath(points)
		If (raySimplify) _RaySimplifyPath(points)

		Local path:FlxPath = New FlxPath()
		Local i:Int = points.length() - 1

		While (i >= 0)
			node = points.Get(i)

			If (node <> Null) Then
				path.AddPoint(node, true)
			End If

			i -= 1
		Wend

		Return path
	End Method

	Method Overlaps:Bool(objectOrGroup:FlxBasic, inScreenSpace:Bool = False, camera:FlxCamera = Null)
		If (FlxGroup(objectOrGroup) <> Null) Then
			Local results:Bool = False
			Local basic:FlxBasic
			Local i:Int = 0
			Local members:FlxBasic[] = FlxGroup(objectOrGroup).Members
			Local l:Int = members.Length()

			While (i < l)
				basic = members[i]

				If (FlxObject(basic) <> Null) Then
					If (OverlapsWithCallback(FlxObject(basic))) Then
						results = True
					End If

				Else
					If (Overlaps(x, y, basic, inScreenSpace, camera)) Then
						results = True
					End If
				End If

				i += 1
			Wend

			Return results

		ElseIf (FlxObject(objectOrGroup) <> Null) Then
			Return OverlapsWithCallback(FlxObject(objectOrGroup))
		End If

		Return False
	End Method

	Method OverlapsAt:Bool(x:Float, y:Float, objectOrGroup:FlxBasic, inScreenSpace:Bool = False, camera:FlxCamera = Null)
		If (FlxGroup(objectOrGroup) <> Null) Then
			Local results:Bool = False
			Local basic:FlxBasic
			Local i:Int = 0
			Local members:FlxBasic[] = FlxGroup(objectOrGroup).Members
			Local l:Int = members.Length()

			While (i < l)
				basic = members[i]

				If (FlxObject(basic) <> Null) Then
					_point.x = x
					_point.y = y

					If (OverlapsWithCallback(FlxObject(basic), Null, False, _point)) Then
						results = True
					End If

				Else
					If (OverlapsAt(x, y, basic, inScreenSpace, camera)) Then
						results = True
					End If
				End If

				i += 1
			Wend

			Return results

		ElseIf (FlxObject(objectOrGroup) <> Null) Then
			_point.x = x
			_point.y = y

			Return OverlapsWithCallback(FlxObject(objectOrGroup), Null, False, _point)
		End If

		Return False
	End Method

	Method OverlapsWithCallback:Bool(object:FlxObject, callback:FlxTileOverlapChecker = Null, flipCallbackParams:Bool = False, position:FlxPoint = Null)
		Local results:Bool = False

		Local lx:Float = x
		Local ly:Float = y

		If (position <> Null) Then
			lx = position.x
			ly = position.y
		End If

		Local selectionX:Int = Floor((object.x - lx) / _tileWidth)
		Local selectionY:Int = Floor((object.y - ly) / _tileHeight)
		Local selectionWidth:Int = selectionX + Ceil(object.width / _tileWidth) + 1
		Local selectionHeight:Int = selectionY + Ceil(object.height / _tileHeight) + 1

		If (selectionX < 0) selectionX = 0
		If (selectionY < 0) selectionY = 0
		If (selectionWidth > widthInTiles) selectionWidth = widthInTiles
		If (selectionHeight > heightInTiles) selectionHeight = heightInTiles

		Local rowStart:Int = selectionY * widthInTiles
		Local row:Int = selectionY
		Local column:Int
		Local tile:FlxTile
		Local overlapFound:Bool
		Local deltaX:Float = lx - last.x
		Local deltaY:Float = ly - last.y

		While (row < selectionHeight)
			column = selectionX

			While (column < selectionWidth)
				overlapFound = False
				tile = _tileObjects[_data[rowStart + column]]

				If (tile.allowCollisions) Then
					tile.x = lx + column * _tileWidth
					tile.y = ly + row * _tileHeight
					tile.last.x = tile.x - deltaX
					tile.last.y = tile.y - deltaY

					If (callback <> Null) Then
						If (flipCallbackParams) Then
							overlapFound = callback.IsTileOverlap(object, tile)
						Else
							overlapFound = callback.IsTileOverlap(tile, object)
						End If
					Else
						overlapFound = (object.x + object.width > tile.x And object.x < tile.x + tile.width And object.y + object.height > tile.y And object.y < tile.y + tile.height)
					End If

					If (overlapFound) Then
						If (tile.callback <> Null And (tile.filter = Null Or tile.filter.InstanceOf(object))) Then
							tile.mapIndex = rowStart + column
							tile.callback.OnTileHit(tile, object)
						End If

						results = True
					End If

				ElseIf (tile.callback <> Null And (tile.filter = Null Or tile.filter.InstanceOf(object))) Then
					tile.mapIndex = rowStart + column
					tile.callback.OnTileHit(tile, object)
				End If

				column += 1
			Wend

			rowStart += widthInTiles
			row += 1
		Wend

		Return results
	End Method

	Method OverlapsPoint:Bool(point:FlxPoint, inScreenSpace:Bool = False, camera:FlxCamera = Null)
		If (Not inScreenSpace) Then
			Return _tileObjects[_data[Int(Int((point.y - y) / _tileHeight) * widthInTiles + (point.x - x) / _tileWidth)]].allowCollisions > 0
		End If

		If (camera = Null) camera = FlxG.camera

		point.x -= camera.scroll.x
		point.y -= camera.scroll.y

		GetScreenXY(_point, camera)

		Return _tileObjects[_data[Int(Int((point.y - _point.y) / _tileHeight) * widthInTiles + (point.x - _point.x) / _tileWidth)]].allowCollisions > 0
	End Method

	Method GetTile:Int(x:Int, y:Int)
		Return _data[y * widthInTiles + x]
	End Method

	Method GetTileByIndex:Int(index:Int)
		Return _data[index]
	End Method

	Method GetTileInstances:IntStack(index:Int)
		Local elements:IntStack = Null

		Local i:Int = 0
		Local l:Int = widthInTiles * heightInTiles

		While (i < l)
			If (_data[i] = index) Then
				If (elements = Null) elements = New IntStack()
				elements.Push(i)
			End If

			i += 1
		Wend

		Return elements
	End Method

	Method GetTileCoords:Stack<FlxPoint>(index:Int, midpoint:Bool = True)
		Local elements:Stack<FlxPoint> = Null

		Local point:FlxPoint
		Local i:Int = 0
		Local l:Int = widthInTiles * heightInTiles

		While (i < l)
			If (_data[i] = index) Then
				point = New FlxPoint(x + Int(i Mod widthInTiles) * _tileWidth, y + Int(i / widthInTiles) * _tileHeight)

				If (midpoint) Then
					point.x += _tileWidth * .5
					point.y += _tileHeight * .5
				End If

				If (elements = Null) elements = New Stack<FlxPoint>()
				elements.Push(point)
			End If

			i += 1
		Wend

		Return elements
	End Method

	Method SetTile:Bool(x:Int, y:Int, tile:Int, updateGraphics:Bool = True)
		If (x >= widthInTiles Or y >= heightInTiles) Then
			Return False
		End If

		Return SetTileByIndex(y * widthInTiles + x, tile, updateGraphics)
	End Method

	Method SetTileByIndex:Bool(index:Int, tile:Int, updateGraphics:Bool = True)
		If (index >= _data.Length()) Return False

		_data[index] = tile

		If (Not updateGraphics) Return True

		If (auto = OFF) Then
			_UpdateTile(index)
			Return True
		End If

		Local i:Int = 0
		Local row:Int = Int(index / widthInTiles) - 1
		Local rowLength:Int = row + 3
		Local column:Int = index Mod widthInTiles - 1
		Local columnHeight:Int = column + 3

		While (row < rowLength)
			column = columnHeight - 3

			While (column < columnHeight)
				If (row >= 0 And row < heightInTiles And column >= 0 And column < widthInTiles) Then
					i = row * widthInTiles + column
					_AutoTile(i)
					_UpdateTile(i)
				End If

				column += 1
			Wend

			row += 1
		Wend

		Return True
	End Method

	Method SetTileProperties:Void(tile:Int, allowCollisions:Int = $1111, callback:FlxTileHitListener = Null, callbackFilter:FlxClass, range:Int = 1)
		If (range <= 0) range = 1

		Local tileObject:FlxTile
		Local i:Int = tile
		Local l:Int = tile + range

		While (i < l)
			tileObject = _tileObjects[i]

			tileObject.allowCollisions = allowCollisions
			tileObject.callback = callback
			tileObject.filter = callbackFilter

			i += 1
		Wend
	End Method

	Method Follow:Void(camera:FlxCamera = Null, border:Int = 0, updateWorld:Bool = True)
		If (camera = Null) camera = FlxCamera
		camera.SetBounds(x + border * _tileWidth, y + border * _tileHeight, width - border * _tileWidth * 2, height - border * _tileHeight * 2, updateWorld)
	End Method

	Method GetBounds:FlxRect(bounds:FlxRect = Null)
		If (bounds = Null) bounds = New FlxRect()
		Return bounds.Make(x, y, width, height)
	End Method

	Method Ray:Bool(startPoint:FlxPoint, endPoint:FlxPoint, result:FlxPoint = Null, resolution:Float = 1)
		Local _step:Float = _tileWidth

		If (_tileHeight < _tileWidth) Then
			_step = _tileHeight
		End If

		_step /= resolution

		Local deltaX:Float = endPoint.x - startPoint.x
		Local deltaY:Float = endPoint.y - startPoint.y
		Local distance:Float = Sqrt(deltaX * deltaX + deltaY * deltaY)
		Local steps:Int = Ceil(distance / _step)
		Local stepX:Float = deltaX / steps
		Local stepY:Float = deltaY / steps
		Local curX:Float = startPoint.x - stepX - x
		Local curY:Float = startPoint.y - stepY - y
		Local tileX:Int
		Local tileY:Int
		Local i:Int = 0

		While (i < steps)
			curX += stepX
			curY += stepY

			If (curX < 0 Or curX > width Or curY < 0 Or curY > height) Then
				i += 1
				Continue
			End If

			tileX = curX / _tileWidth
			tileY = curY / _tileHeight

			If (_tileObjects[_data[tileY * widthInTiles + tileX]].allowCollisions) Then
				tileX *= _tileWidth
				tileY *= _tileHeight

				Local rx:Float = 0
				Local ry:Float = 0
				Local q:Float
				Local lx:Float = curX - stepX
				Local ly:Float = curY - stepY

				q = tileX
				If (deltaX < 0) q += _tileWidth

				rx = q
				ry = ly + stepY * ((q - lx) / stepX)

				If (ry < tileY And ry < tileY + _tileHeight) Then
					If (result = Null) Then
						result = New FlxPoint()
					End If

					result.x = rx
					result.y = ry

					Return False
				End If

				q = tileY
				If (deltaY < 0) q += _tileHeight

				rx = lx + stepX * ((q - ly) / stepY)
				ry = q

				If (rx > tileX And rx < tileX + _tileWidth) Then
					If (result = Null) Then
						result = New FlxPoint()
					End If

					result.x = rx
					result.y = ry

					Return False
				End If

				Return True
			End If

			i += 1
		Wend

		Return True
	End Method

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

Private
	Method _SimplifyPath:Void(points:Stack<FlxPoint>)
		Local deltaPrevious:Float
		Local deltaNext:Float
		Local last:FlxPoint = points.Get(0)
		Local node:FlxPoint
		Local nextPoint:FlxPoint
		Local i:Int = 1
		Local l:Int = points.Length() - 1

		While (i < l)
			node = points.Get(i)
			nextPoint = points.Get(i + 1)

			deltaPrevious = (node.x - last.x) / (node.y - last.y)
			deltaNext = (node.x - nextPoint.x) / (node.y - nextPoint.y)

			If (last.x = nextPoint.x Or last.y = nextPoint.y Or deltaPrevious = deltaNext) Then
				points.Set(i, Null)
			Else
				last = node
			End If

			i += 1
		Wend
	End Method

	Method _RaySimplifyPath:Void(points:Stack<FlxPoint>)
		Local source:FlxPoint = points.Get(0)
		Local lastIndex:Int = -1
		Local node:FlxPoint
		Local i:Int = 1
		Local l:Int = points.Length()

		While (i < l)
			node = points.Get(i)
			i += 1

			If (node = Null) Continue

			If (Ray(source, node, _point)) Then
				If (lastIndex >= 0) points.Set(lastIndex, Null)
			Else
				source = points.Get(lastIndex)
			End If

			lastIndex = i - 1
		Wend
	End Method

	Method _ComputePathDistance:Int[](startIndex:Int, endIndex:Int)
		Local mapSize:Int = widthInTiles * heightInTiles
		Local distances:Int[mapSize]
		Local i:Int = 0

		While (i < mapSize)
			If (_tileObjects[_data[i]].allowCollisions) Then
				distances[i] = -2
			Else
				distances[i] = -1
			End If

			i += 1
		Wend

		distances[startIndex] = 0

		Local distance:Int = 1
		Local neighbors:IntStack = New IntStack([startIndex])
		Local current:IntStack
		Local currentIndex:Int
		Local left:Bool
		Local right:Bool
		Local up:Bool
		Local down:Bool
		Local currentLength:Int
		Local foundEnd:Bool = False

		While (neighbors.Length() > 0)
			current = neighbors
			neighbors = New IntStack()

			i = 0
			currentLength = current.Length()

			While (i < currentLength)
				currentIndex = current.Get(i)

				If (currentIndex = endIndex) Then
					foundEnd = True
					neighbors.Clear()
					Exit
				End If

				left = currentIndex Mod widthInTiles > 0
				right = currentIndex Mod widthInTiles < widthInTiles - 1
				up = currentIndex / widthInTiles > 0
				down = currentIndex / widthInTiles < heightInTiles - 1

				Local index:Int

				If (up) Then
					index = currentIndex - widthInTiles

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (right) Then
					index = currentIndex + 1

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (down) Then
					index = currentIndex + widthInTiles

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (left) Then
					index = currentIndex - 1

					If (distances[index] = -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (up And right) Then
					index = currentIndex - widthInTiles + 1

					If (distances[index] = -1 And distances[currentIndex - widthInTiles] >= -1 And distances[currentIndex + 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (right And down) Then
					index = currentIndex + widthInTiles + 1

					If (distances[index] = -1 And distances[currentIndex + widthInTiles] >= -1 And distances[currentIndex + 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (left And down) Then
					index = currentIndex + widthInTiles - 1

					If (distances[index] = -1 And distances[currentIndex + widthInTiles] >= -1 And distances[currentIndex - 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				If (up And left) Then
					index = currentIndex - widthInTiles - 1

					If (distances[index] = -1 And distances[currentIndex - widthInTiles] >= -1 And distances[currentIndex - 1] >= -1) Then
						distances[index] = distance
						neighbors.Push(index)
					End If
				End If

				i += 1
			Wend

			distance += 1
		Wend

		If (Not foundEnd) distances = []

		Return distances
	End Method

	Method _WalkPath:Void(data:Int[], start:Int, points:Stack<FlxPoint>)
		points.Push(New FlxPoint(x + Int(start Mod widthInTiles) * _tileWidth + _tileWidth * .5, y + Int(start Mod widthInTiles) * _tileHeight + _tileHeight * .5))
		If (data[start] = 0) Return

		Local left:Bool = start Mod widthInTiles > 0
		Local right:Bool = start Mod widthInTiles < widthInTiles - 1
		Local up:Bool = start / widthInTiles > 0
		Local down:Bool = start / widthInTiles < heightInTiles - 1

		Local current:Int = data[start]
		Local i:Int

		If (up) Then
			i = start - widthInTiles

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (right) Then
			i = start + 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (down) Then
			i = start + widthInTiles

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (left) Then
			i = start - 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (up And Right) Then
			i = start - widthInTiles + 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (right And down) Then
			i = start + widthInTiles + 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (left And down) Then
			i = start + widthInTiles - 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If

		If (up And left) Then
			i = start - widthInTiles - 1

			If (data[i] >= 0 And data[i] < current) Then
				_WalkPath(data, i, points)
				Return
			End If
		End If
	End Method

	Method _AutoTile:Void(index:Int)
		If (_data[index] = 0) Return

		_data[index] = 0

		If (index - widthInTiles < 0 Or _data[index - widthInTiles] > 0) Then
			_data[index] += 1
		End If

		If (index Mod widthInTiles >= widthInTiles - 1 Or _data[index + 1] > 0) Then
			_data[index] += 2
		End If

		If (index + widthInTiles >= totalTiles Or _data[index + widthInTiles] > 0) Then
			_data[index] += 4
		End If

		If (index Mod widthInTiles <= 0 Or _data[index - 1] > 0) Then
			_data[index] += 8
		End If

		If (auto = ALT And _data[index] = 15) Then
			If (index Mod widthInTiles > 0 And index + widthInTiles < totalTiles And _data[index + widthInTiles - 1] <= 0) Then
				_data[index] = 1
			End If

			If (index Mod widthInTiles > 0 And index - widthInTiles >= 0 And _data[index - widthInTiles - 1] <= 0) Then
				_data[index] = 2
			End If

			If (index Mod widthInTiles < widthInTiles - 1 And index - widthInTiles >= 0 And _data[index - widthInTiles + 1] <= 0) Then
				_data[index] = 4
			End If

			If (index Mod widthInTiles < widthInTiles - 1 And index + widthInTiles >= totalTiles And _data[index + widthInTiles + 1] <= 0) Then
				_data[index] = 8
			End If
		End If

		_data[index] += 1
	End Method

	Method _UpdateTile:Void(index:Int)
		Local tile:FlxTile = _tileObjects[_data[index]]

		If (tile = Null Or Not tile.visible) Then
			_rects[index] = Null
			Return
		End If

		Local rx:Int = (_data[index] - _startingIndex) * _tileWidth
		Local ry:Int = 0

		If (rx >= _tiles.Width()) Then
			ry = Int(rx / _tiles.Width()) * _tileHeight
			rx Mod= _tiles.Width()
		End If

		_rects[index] = New FlxRect(rx, ry, _tileWidth, _tileHeight)
	End Method

End Class

Private
Class FlxTileLoader Extends FlxResourceLoader<Image>

	Method Load:Image(name:String)
		Return LoadImage(FlxAssetsManager.GetImagePath(name))
	End Method

End Class


Fixed the 'ResizeBuffer' command, and added two extra arguments.

Strict

Public

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

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

#DEBUG_PRINT_QUOTES = False

' Imports (Public):
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

' Official:

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

' Unofficial:

' ImmutableOctet:
Import autostream

Public

' Constant variable(s):

' 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

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

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

' 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

Function ResizeBuffer:DataBuffer(Buffer:DataBuffer, Size:Int, CopyData:Bool=True, DiscardOldBuffer:Bool=False)
	' Allocate a new data-buffer.
	Local B:= New DataBuffer(Size)

	' Copy the buffer's bytes over to 'B'.
	If (CopyData) Then
		Buffer.CopyBytes(0, B, 0, Buffer.Length())
	Endif

	If (DiscardOldBuffer) Then
		Buffer.Discard()
	Endif

	' Return the new buffer ('B').
	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(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
				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

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

	' Functions:
	Function IndexOfList:T(L:List<T>, Index:Int=0)
		' Local variable(s):
		Local Response:T
		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 Response
			Endif
		Next

		Response = Data.Value()

		' Return the value of the assessed node.
		Return Response
	End

	Function CopyArray:T[](Source:T[], Destination:T[])
		Local MinLength:Int = Min(Source.Length(), Destination.Length())

		For Local Index:Int = 0 Until MinLength
			Destination[Index] = Source[Index]
		Next

		Return Destination
	End

	Function CloneArray:T[](Source:T[], Destination:T[]=[])
		If (Destination.Length() = 0) Then
			Destination = New T[Source.Length()]
		Endif

		Return CopyArray(Source, Destination)
	End

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

	Function Read:T[](S:Stream, DataArray:T[], Size:Int=-1)
		If (Size = -1) 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=-1)
		If (Size = -1) Then Size = S.ReadInt()

		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())
		S.WriteString(Data, Encoding)

		Return
	End
End

Strict

Public

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

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

#DEBUG_PRINT_QUOTES = False

' Imports (Public):
Import byteorder
Import imagedimensions
Import retrostrings
Import stringutil

#If CONSOLE_IMPLEMENTED
	Import console
#End

Import sizeof
Import time

#If Not BRL_GAMETARGET_IMPLEMENTED
	Import mojoemulator
#End

' Imports (Private):
Private

' Official:

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

' Unofficial:

' ImmutableOctet:
Import autostream

Public

' Constant variable(s):

' 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

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

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

' 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)
	#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

Function ResizeBuffer:DataBuffer(Buffer:DataBuffer, Size:Int)
	' Allocate a new data-buffer.
	Local B:= New DataBuffer(Size)

	' Copy the buffer's bytes over to 'B'.
	Buffer.CopyBytes(0, B, 0, Min(Size, Buffer.Length()))

	' Return the new buffer ('B').
	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(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
				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

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

	' Functions:
	Function IndexOfList:T(L:List<T>, Index:Int=0)
		' Local variable(s):
		Local Response:T
		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 Response
			Endif
		Next

		Response = Data.Value()

		' Return the value of the assessed node.
		Return Response
	End

	Function CopyArray:T[](Source:T[], Destination:T[])
		Local MinLength:Int = Min(Source.Length(), Destination.Length())

		For Local Index:Int = 0 Until MinLength
			Destination[Index] = Source[Index]
		Next

		Return Destination
	End

	Function CloneArray:T[](Source:T[], Destination:T[]=[])
		If (Destination.Length() = 0) Then
			Destination = New T[Source.Length()]
		Endif

		Return CopyArray(Source, Destination)
	End

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

	Function Read:T[](S:Stream, DataArray:T[], Size:Int=-1)
		If (Size = -1) 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=-1)
		If (Size = -1) Then Size = S.ReadInt()

		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())
		S.WriteString(Data, Encoding)

		Return
	End
End


Added SetMouse for GLFW

Added SetMouse for GLFW

--HG--
extra : convert_revision : svn%3Ae934d3cd-0d57-f34a-94d0-9e8d31ae1c29/trunk%40130

' force strict coding standard
Strict

' import the diddy module
Import diddy

' the starting point for a Monkey app
Function Main:Int()
	' create the "game"
	New MyGame
	Return 0
End

' MyGame
Class MyGame Extends DiddyApp
	' save the starting seed
	Field startingSeed:Int
	Field mouseOn:Bool = true

	Method OnCreate:Int()
		Super.OnCreate()
		' set the seed to use the system time
		startingSeed = RealMillisecs()
		Seed = startingSeed
		ShowMouse()

		Return 0
	End

	Method OnUpdate:Int()
		If KeyHit(KEY_ENTER)
			If mouseOn
				HideMouse()
				mouseOn = False
			Else
				ShowMouse()
				mouseOn = True
			End
		End

		If KeyHit(KEY_ESCAPE)
			ExitApp()
		End

		' this will print "No FlushKeys 3 times
		For Local i:Int = 1 To 3
			If KeyHit(KEY_SPACE)
				Print "No FlushKeys"
			End
		Next
		' this will print "FlushKeys once
		For Local i:Int = 1 To 3
			If KeyHit(KEY_SPACE)
				Print "FlushKeys"
				' force the seed to change
				Rnd(0,1000)
				SetMouse(100, 100)
			End
			' clear the key hits
			FlushKeys()
		Next
		If Not mouseOn
			if (MouseX() < 0 or MouseX() > DEVICE_WIDTH or MouseY()< 0 or MouseY() > DEVICE_HEIGHT)
				ShowMouse()
				SetMouse(MouseX(), MouseY())
			Else
				HideMouse()
			End
		End
		Return 0
	End

	Method OnRender:Int()
		Cls
		DrawText "Starting Seed = "+startingSeed, 10, 10
		DrawText "Seed          = "+Seed, 10, 20
		DrawText "RealMillisecs = "+RealMillisecs(), 10, 30
		DrawText "Millisecs     = "+Millisecs(), 10, 40
		If mouseOn
			DrawText "Mouse On      = true (press enter to toggle)", 10, 50
		Else
			DrawText "Mouse On      = false (press enter to toggle)", 10, 50
		End
		DrawText "UpdateRate    = "+GetUpdateRate(), 10, 60
		DrawText "MouseX        = "+MouseX(), 10, 70
		DrawText "MouseY        = "+MouseY(), 10, 80
		DrawText "DEVICE_WIDTH  = "+DEVICE_WIDTH, 10, 90
		DrawText "DEVICE_HEIGHT = "+DEVICE_HEIGHT, 10, 100

		Return 0
	End

End

' force strict coding standard
Strict

' import the diddy module
Import diddy

' the starting point for a Monkey app
Function Main:Int()
	' create the "game"
	New MyGame
	Return 0
End

' MyGame
Class MyGame Extends DiddyApp
	' save the starting seed
	Field startingSeed:Int
	Field mouseOn:Bool = false

	Method OnCreate:Int()
		' set the seed to use the system time
		startingSeed = RealMillisecs()
		Seed = startingSeed
		HideMouse()

		' 60 FPS please
		SetUpdateRate 60

		Return 0
	End

	Method OnUpdate:Int()
		If KeyHit(KEY_ENTER)
			If mouseOn
				HideMouse()
				mouseOn = False
			Else
				ShowMouse()
				mouseOn = True
			End
		End

		If KeyHit(KEY_ESCAPE)
			ExitApp()
		End

		' this will print "No FlushKeys 3 times
		For Local i:Int = 1 To 3
			If KeyHit(KEY_SPACE)
				Print "No FlushKeys"
			End
		Next
		' this will print "FlushKeys once
		For Local i:Int = 1 To 3
			If KeyHit(KEY_SPACE)
				Print "FlushKeys"
				' force the seed to change
				Rnd(0,1000)
			End
			' clear the key hits
			FlushKeys()
		Next

		Return 0
	End

	Method OnRender:Int()
		Cls
		DrawText "Starting Seed = "+startingSeed, 10, 10
		DrawText "Seed          = "+Seed, 10, 20
		DrawText "RealMillisecs = "+RealMillisecs(), 10, 30
		DrawText "Millisecs     = "+Millisecs(), 10, 40
		If mouseOn
			DrawText "Mouse On      = true (press enter to toggle)", 10, 50
		Else
			DrawText "Mouse On      = false (press enter to toggle)", 10, 50
		End
		DrawText "UpdateRate    = "+GetUpdateRate(), 10, 60
		Return 0
	End

End


Added sender to buttons listener

Added sender to buttons listener

Strict

Import reflection

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

Import "data/button_flx.png"
Import "data/beep_flx.mp3"

Class FlxButton Extends FlxSprite

	Global ClassObject:Object

	Const NORMAL:Int = 0

	Const HIGHLIGHT:Int = 1

	Const PRESSED:Int = 2

	Field label:FlxText

	Field labelOffset:FlxPoint

	Field onUp:FlxButtonClickListener

	Field onDown:FlxButtonDownListener

	Field onOver:FlxButtonOverListener

	Field onOut:FlxButtonOutListener

	Field status:Int

	Field soundOver:FlxSound

	Field soundOut:FlxSound

	Field soundDown:FlxSound

	Field soundUp:FlxSound

Private
	Field _onToggle:Bool

	Field _pressed:Bool

	Field _initialized:Bool

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

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

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

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

		status = NORMAL
		_onToggle = False
		_pressed = False
	End Method

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

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

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

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

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

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

		Super.Destroy()
	End Method

	Method Update:Void()
		_UpdateButton()

		If (label = Null) Return

		Select (Frame)
			Case HIGHLIGHT
				label.Alpha = 1.0

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

			Case NORMAL
				label.Alpha = .8

			Default
				label.Alpha = .8
		End Select
	End Method

	Method Draw:Void()
		Super.Draw()

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

	Method _ResetHelpers:Void()
		Super._ResetHelpers()

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

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

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

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

		If (soundUp.Length() > 0) Then
			Self.soundUp = FlxG.LoadSound(soundUp, soundUpVolume)
		End If
	End Method

	Method On:Bool() Property
		Return _onToggle
	End Method

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

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

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

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

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

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

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

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

					If (status = NORMAL) Then
						status = HIGHLIGHT

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

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

				i += 1
			Wend

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

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

				status = NORMAL
			End If

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

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

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

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

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

End Class

Interface FlxButtonClickListener

	Method OnButtonClick:Void(button:FlxButton)

End Interface

Interface FlxButtonDownListener

	Method OnButtonDown:Void(button:FlxButton)

End Interface

Interface FlxButtonOverListener

	Method OnButtonOver:Void(button:FlxButton)

End Interface

Interface FlxButtonOutListener

	Method OnButtonOut:Void(button:FlxButton)

End Interface

Strict

Import reflection

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

Import "data/button_flx.png"
Import "data/beep_flx.mp3"

Class FlxButton Extends FlxSprite

	Global ClassObject:Object

	Const NORMAL:Int = 0

	Const HIGHLIGHT:Int = 1

	Const PRESSED:Int = 2

	Field label:FlxText

	Field labelOffset:FlxPoint

	Field onUp:FlxButtonClickListener

	Field onDown:FlxButtonDownListener

	Field onOver:FlxButtonOverListener

	Field onOut:FlxButtonOutListener

	Field status:Int

	Field soundOver:FlxSound

	Field soundOut:FlxSound

	Field soundDown:FlxSound

	Field soundUp:FlxSound

Private
	Field _onToggle:Bool

	Field _pressed:Bool

	Field _initialized:Bool

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

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

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

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

		status = NORMAL
		_onToggle = False
		_pressed = False
	End Method

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

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

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

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

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

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

		Super.Destroy()
	End Method

	Method Update:Void()
		_UpdateButton()

		If (label = Null) Return

		Select (Frame)
			Case HIGHLIGHT
				label.Alpha = 1.0

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

			Case NORMAL
				label.Alpha = .8

			Default
				label.Alpha = .8
		End Select
	End Method

	Method Draw:Void()
		Super.Draw()

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

	Method _ResetHelpers:Void()
		Super._ResetHelpers()

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

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

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

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

		If (soundUp.Length() > 0) Then
			Self.soundUp = FlxG.LoadSound(soundUp, soundUpVolume)
		End If
	End Method

	Method On:Bool() Property
		Return _onToggle
	End Method

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

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

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

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

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

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

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

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

					If (status = NORMAL) Then
						status = HIGHLIGHT

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

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

				i += 1
			Wend

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

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

				status = NORMAL
			End If

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

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

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

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

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

End Class

Interface FlxButtonClickListener

	Method OnButtonClick:Void()

End Interface

Interface FlxButtonDownListener

	Method OnButtonDown:Void()

End Interface

Interface FlxButtonOverListener

	Method OnButtonOver:Void()

End Interface

Interface FlxButtonOutListener

	Method OnButtonOut:Void()

End Interface