' ################################################################################################################################################################
' #TOP

' Footrace
' Version 3.00 by Softintheheadware

' DESCRIPTION:
' A simple concept for video game locomotion.

' LICENSE:
' Open source and free.

' ================================================================================================================================================================
' CHANGE LOG
' ================================================================================================================================================================
' Date         Who                What
' 02/05/2022   madscijr           Footrace v3.0 = 4 players, tiled graphics, doors/keys, random mazes.
' 01/29/2022   madscijr           Footrace v2.0 = 4 players, color ASCII graphics, player-mapped keyboard+gamepad controls, sound.
' 01/22/2021   madscijr           Footrace v1.0 = 2 players, ASCII graphics, keyboard controlled.
' 10/27/2018   madscijr           Planned out logic and features.
' 08/29/2005   madscijr           Controller design for "See Dick Run (Run Run Run)".
' 02/03/2003   madscijr           Birth of "FootRace" concept, experiments in Visual Basic 6.

' ================================================================================================================================================================
' HOW TO CUSTOMIZE
' ================================================================================================================================================================
' To customize Footrace3 screens, edit
'     Function Footrace3Map1$
'     Function Footrace3Map2$
'     Function Footrace3Map3$
'     NOTE: later we will probably add a level editor
' To customize Footrace3 graphics, edit
'     Function GetTiles$
'     NOTE: later we will re-enable option to load graphics from PNG or BMP file
'           for now if you prefer graphics from a file,
'           comment out the line
'               sError = GetTiles$(imgTiles&, cBlack, cEmpty)
'           and uncomment out the lines
'               sFile$ = m_ProgramPath$ + "Font_8x8_128x128_v3.png"
'               imgTiles& = _LoadImage(sFile$, 32)
'           NOTE: you will need to supply your own 128x128 PNG
'                 file of 8x8 tiles, in mostly ASCII order
'                 (see GetTiles to see which values).
' To customize the Footrace2 screen, edit
'     Function Footrace2Map1$

' ================================================================================================================================================================
' JOURNAL
' ================================================================================================================================================================
' -----------------------------------------------------------------------------
' 02/03/2003 Mon
' -----------------------------------------------------------------------------
' FootRace: a simple racing game like Track & Field but directional.

' -----------------------------------------------------------------------------
' 8/29/2005 Mon
' -----------------------------------------------------------------------------
' Game controller concept for See Dick Run (Run Run Run):
' A = left leg 2x4, moves forward & back
' B = right leg 2x4, moves forward & back
' C = right leg pivot 2x4, moves right/left
' D = left leg pivot 2x4, moves right/left
' E = armature, holds parts in place
' All 2x4s spring loaded

' -----------------------------------------------------------------------------
' 10/27/2018 Sat
' -----------------------------------------------------------------------------
' Footrace = Walking/running game
' Controls
' * Two back & forth (like Atari Tank) or 4-directional or 8-way joysticks
'   with one or more button / trigger
'   ? 2x4s!
'   ? Ski poles
'   ? Toilet plungers!
' * Joystick moves corresponding foot in that direction.
'   When other foot is moved in same direction, person takes a step.
'   ? Turning to face a new direction?
'   ? What would one foot foreward one foot back do?
'   ? What about 2 feet in other combinations of different directions?
'     (define for each combination {of 8 directions + centered} for each foot)
' * Very responsive/quick - the speed of moving joysticks corresponds
'   to speed of walking/running (like Track & Field!)
' * Later - Up/down motion (knee bending)? ie for ducking / jumping.
'   Can be used to allow jumping hurdles, squatting, crawling, climbing, etc.!

' -----------------------------------------------------------------------------
' 1/29/2022 Sat
' -----------------------------------------------------------------------------
' Game is working 4 players with with game controllers and keyboard.
' Player can change control mapping.

' -----------------------------------------------------------------------------
' 2/5/2022 Sat
' -----------------------------------------------------------------------------
' Change game graphics to simple 8x8 tiles which look nicer and a bigger
' playing field fits on screen. Tiles are defined as text in code,
' to be easily edited from IDE.

' PHASE 1:
' change to 8x8 tile graphics
' rainbow walls
' auto-load controller mapping (if none found, prompt user to map controls)
' load tiles from ASCII code instead of image file
' menus use inkey instead of input
' ----------
' store additional screens in external files
' display settings right on main menu
' - indicate whether controls mapped / changed
' - list of screens
' - graphic symbols for players
' - race options: # of laps, etc.
' sync sounds better
' - walking sound should stop when a player stops moving
' - countdown should proceed only when each note finishes playing
' ini file
' - move graphics here to be easily edited by user w/o going into code
' - option to load graphics from PNG file instead of code?
' - option for full screen vs window

' PHASE 2
' don't end round when someone wins, but track 1st, 2nd, 3rd, 4th place
' multiple laps (count laps)
' time players, save best times
' support objects each player must collect before they can finish
' board editor
' - load / save screens
' - 128 cols x 80 rows
' - 2 simultaneous cursors
'   * mouse cursor to select colors, tiles, actions
'   * arrow key controlled cursor to edit screen (0-9 places/erases tiles)
' - keyboad input to draw tiles

' PHASE 3:
' computer-generated levels, mazes, etc.
' let player change graphic symbols for players

' PHASE IV:
' objects
' - portal = stepping on one telports you somewhere else
' - triggers (collect objects to unlock doors, extend bridges, etc.)
' - hurdles / jumping (move both legs in same direction?)
' - locked doors / keys
' - ladder object
' - hidden passages

' PHASE 5 AND BEYOND:
' player handicap (slow down players)
' objects to speed up/slow down players?
' players gain momentum with sustained movement
' Isometric 2.5D version?

' SPIN-OFFS:
' Use Footrace type locomotion to control games like Pong,
' Outlaw/Gunfighter, Atari Adventure, RPGs, etc.

' ################################################################################################################################################################
' BASIC SETTINGS

DefLng A-Z

' ################################################################################################################################################################
' #CONSTANTS = GLOBAL CONSTANTS

' boolean constants:
Const FALSE = 0
Const TRUE = Not FALSE

' BEGIN GAME CONTROLLER MAPPING CONSTANTS
Const cInputNone = 0
Const cInputKey = 1
Const cInputButton = 2
Const cInputAxis = 3

Const cMaxButtons = 12
Const cMaxAxis = 8
Const cMaxControllers = 8
Const cMaxPlayers = 8

' Use as index for array of ControlInputType
Const cInputUp = 1
Const cInputDown = 2
Const cInputLeft = 3
Const cInputRight = 4
Const cInputButton1 = 5
Const cInputButton2 = 6
Const cInputButton3 = 7
Const cInputButton4 = 8

Const c_iKeyDown_F10 = 17408
Const c_iKeyHit_AltLeft = -30764
Const c_iKeyHit_AltRight = -30765
' END GAME CONTROLLER MAPPING CONSTANTS

' BEGIN TEXT GUI CONSTANTS
Const cTextGuiSection = 1
Const cTextGuiButton = 2
Const cTextGuiUnknown = 0

Const cJustifyLeft = 1
Const cJustifyRight = 2
Const cJustifyCenter = 3
Const cJustifyNone = 4
Const cJustifyUnknown = 0
' END TEXT GUI CONSTANTS

' BEGIN GAME OPTION CONSTANTS
Const cObstacleGameOption = 1
Const cMazeGameOption = 2
' END GAME OPTION CONSTANTS

' BEGIN MAZE GENERATOR CONSTANTS
' direction constants
Const cN = 1
Const cE = 2
Const cS = 4
Const cW = 8

' x/y plane constants
Const cX = 0
Const cY = 1
' END MAZE GENERATOR CONSTANTS

' ################################################################################################################################################################
' #UDT #TYPES = USER DEFINED TYPES

' UDT TO HOLD THE INFO FOR A PLAYER
Type PlayerType
    x As Integer ' player x position
    y As Integer ' player y position
    c As Integer ' character to display on screen
    xOld As Integer
    yOld As Integer

    ' control buffer
    moveX As Integer
    moveY As Integer

    moveUp As Integer
    moveDown As Integer
    moveLeft As Integer
    moveRight As Integer
    button1 As Integer
    button2 As Integer
    button3 As Integer
    button4 As Integer

    ' control previous move
    'lastMoveX As Integer
    'lastMoveY As Integer
    lastMoveUp As Integer
    lastMoveDown As Integer
    lastMoveLeft As Integer
    lastMoveRight As Integer
    lastButton1 As Integer
    lastButton2 As Integer
    lastButton3 As Integer
    lastButton4 As Integer

    'repeat As Integer
End Type ' PlayerType

' UDT TO HOLD THE INFO FOR A GAME CONTROLLER
Type ControllerType
    buttonCount As Integer
    axisCount As Integer
End Type ' ControllerType

' UDT TO HOLD THE INFO FOR A GAME CONTROLLER
Type ControlInputType
    device As Integer
    typ As Integer ' cInputKey, cInputButton, cInputAxis
    code As Integer
    value As Integer
    repeat As Integer
End Type ' ControlInputType

' UDT TO HOLD COLOR CODE INFO
Type ColorType
    name As String
    value As _Unsigned Long
End Type ' ColorType

' UDT TO HOLD TEXT GUI
Type ScreenAreaType
    name As String
    typ As Integer ' cTextGuiSection, cTextGuiButton
    item As String
    player As Integer
    x1 As Integer
    y1 As Integer
    x2 As Integer
    y2 As Integer
    'index as integer
End Type ' ScreenAreaType

' DEFINES CLICKABLE BUTTON BOUNDARIES
Type TextButtonType
    item As String
    typ As Integer ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    x1 As Integer
    y1 As Integer
    x2 As Integer
    y2 As Integer
    'index as integer
End Type ' TextButtonType

' DEFINES TEXT LABELS
Type TextLabelType
    item As String ' "Section", "Up", "Down"
    name As String ' "caption", "type", "device", "code", "repeat", "value"
    row As Integer ' row (relative to section y1)
    column As Integer ' column (relative to section x1)
    width As Integer ' needed for cJustifyRight, cJustifyCenter
    justify As Integer ' cJustifyLeft, cJustifyRight, cJustifyCenter, cJustifyUnknown
    caption As String ' holds the label text
    fgcolor As _Unsigned Long
    bgcolor As _Unsigned Long
    'index as integer
End Type ' TextLabelType

' DEFINES TEXT FIELDS
Type TextFieldType
    item As String ' "Section", "Up", "Down"
    name As String ' "caption", "type", "device", "code", "repeat", "value"
    row As Integer ' row (relative to section y1)
    column As Integer ' column (relative to section x1)
    width As Integer ' pad values to this width
    justify As Integer ' cJustifyLeft, cJustifyRight, cJustifyCenter, cJustifyUnknown
    value As String ' holds the formatted value as text
    fgcolor As _Unsigned Long
    bgcolor As _Unsigned Long
    'index as integer
End Type ' TextFieldType

' FOR TEXT SCREEN
Type TextCellType
    value As String
    fgColor As _Unsigned Long
    bgcolor As _Unsigned Long
End Type ' TextCellType

' UDT TO HOLD THE INFO FOR A MAZE
' (DIMENSIONS FOR EACH LEVEL OF DIFFICULTY, ETC.)
Type MazeType
    makeWidth As Integer
    makeRows As Integer
    makeCols As Integer
    finalRows As Integer
    finalCols As Integer
End Type ' MazeType

' ################################################################################################################################################################
' #VARS = GLOBAL VARIABLES

' ENABLE / DISABLE DEBUG CONSOLE
Dim Shared m_bDebug As Integer: m_bDebug = FALSE

' BASIC PROGRAM METADATA
Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
Dim Shared m_VersionInfo$: m_VersionInfo$ = "3.00"

' GAME CONTROLLER MAPPING
Dim Shared m_ControlMapFileName$: m_ControlMapFileName$ = Left$(m_ProgramName$, _InStrRev(m_ProgramName$, ".")) + "map.txt"
ReDim Shared m_arrControlMap(1 To 8, 1 To 8) As ControlInputType ' holds control mapping for each player (player #, direction)
ReDim Shared m_arrController(1 To 8) As ControllerType ' holds info for each game controller
ReDim Shared m_arrButtonCode(1 To 99) As Integer ' Long
ReDim Shared m_arrButtonKey(1 To 99) As String
ReDim Shared m_arrButtonKeyDesc(0 To 512) As String
Dim Shared m_bInitialized As Integer: m_bInitialized = FALSE
Dim Shared m_bHaveMapping As Integer: m_bHaveMapping = FALSE
Dim Shared m_bMappingChanged As Integer: m_bMappingChanged = FALSE

' USE TO GLOBALLY ENABLE/DISABLE REPEATING INPUT PER FUNCTION
' To enable override set m_bRepeatOverride=TRUE,
' otherwise this can be configured for each individual controller
' when you map the functions.
Dim Shared m_bRepeatOverride As Integer: m_bRepeatOverride = TRUE
Dim Shared m_bRepeatUp As Integer: m_bRepeatUp = TRUE
Dim Shared m_bRepeatDown As Integer: m_bRepeatDown = TRUE
Dim Shared m_bRepeatLeft As Integer: m_bRepeatLeft = FALSE
Dim Shared m_bRepeatRight As Integer: m_bRepeatRight = FALSE
Dim Shared m_bRepeatButton1 As Integer: m_bRepeatButton1 = TRUE
Dim Shared m_bRepeatButton2 As Integer: m_bRepeatButton2 = TRUE
Dim Shared m_bRepeatButton3 As Integer: m_bRepeatButton3 = FALSE
Dim Shared m_bRepeatButton4 As Integer: m_bRepeatButton4 = FALSE

' VARIABLES FOR GRAPHIC PRINTING ROUTINES
Dim Shared m_NumColumns As Integer: m_NumColumns = 1
Dim Shared m_PrintRow As Integer: m_PrintRow = 0
Dim Shared m_PrintCol As Integer: m_PrintCol = 0
Dim Shared m_StartRow As Integer: m_StartRow = 0
Dim Shared m_EndRow As Integer: m_EndRow = 0
Dim Shared m_StartCol As Integer: m_StartCol = 0
Dim Shared m_EndCol As Integer: m_EndCol = 0

' VARIABLES FOR TEXT GUI
ReDim Shared m_arrScreenArea(-1) As ScreenAreaType
ReDim Shared m_arrButton(-1) As TextButtonType
ReDim Shared m_arrTextLabel(-1) As TextLabelType
ReDim Shared m_arrTextField(-1) As TextFieldType

' DEMO GAME / TESTING
ReDim Shared m_arrPlayer(1 To 8) As PlayerType ' holds info for each player

' =============================================================================
' LOCAL VARIABLES
Dim in$

' ****************************************************************************************************************************************************************
' ACTIVATE DEBUGGING WINDOW
If m_bDebug = TRUE Then
    $Console
    _Delay 4
    _Console On
    _Echo "Started " + m_ProgramName$
    _Echo "Debugging on..."
End If
' ****************************************************************************************************************************************************************

' =============================================================================
' START THE MAIN ROUTINE
main

' =============================================================================
' FINISH
Screen 0
Print m_ProgramName$ + " finished."
Input "Press <ENTER> to continue", in$

' ****************************************************************************************************************************************************************
' DEACTIVATE DEBUGGING WINDOW
If m_bDebug = TRUE Then
    _Console Off
End If
' ****************************************************************************************************************************************************************

System ' return control to the operating system
End

' /////////////////////////////////////////////////////////////////////////////

Sub main
    Dim RoutineName As String: RoutineName = "main"
    Dim in$
    Dim bFinished As Integer: bFinished = FALSE
    Dim result$: result$ = ""
    Dim iScreen&

    ' SET UP SCREEN
    iScreen& = _NewImage(1024, 768, 32): _ScreenMove 0, 0
    Do
        Screen iScreen&: Cls

        Print m_ProgramName$
        Print
        Print "Footrace " + m_VersionInfo$
        Print "by Softintheheadware"
        Print

        Print "i) Instructions"

        Print "4) Footrace3 - Random Maze"
        Print "3) Footrace3 - Obstacle Course"
        Print "2) Footrace2"
        Print "1) Footrace1"

        Print "L) Load controller mapping"
        Print "M) Map game controls"
        Print "T) Test controller mappings"
        Print "S) Save controller mappings"

        Print "B) Basic controller input test"
        Print "V) View controller mapping"

        ' *****************************************************************************
        ' BEGIN DEBUGGING ONLY ACTIONS
        If m_bDebug = TRUE Then
            Print "D) Dump controller mappings to console window"
            Print "E) Edit  controller mapping for 1 or more players"
            Print "R) Reset controller mapping for 1 or more players"
            Print "C) Map controllers for 1 or more players (text menu, no GUI)"
            Print "Y) Detect color test"
            Print "Z) Custom color font test"
        End If
        ' END DEBUGGING ONLY ACTIONS
        ' *****************************************************************************

        Print
        Print "Q) Exit program"

        Do
            in$ = InKey$

            If UCase$(in$) = "Q" Then
                If m_bMappingChanged Then
                    Print
                    Print "Save new controller mapping?"
                    Print "Y)es N)o C)ancel"
                    Do
                        in$ = UCase$(InKey$)
                        If in$ = "Y" Then
                            result$ = SaveMappings1$
                            If UCase$(Left$(result$, 5)) <> "ERROR" Then
                                bFinished = TRUE
                            End If
                            Exit Do
                        ElseIf in$ = "N" Then
                            bFinished = TRUE
                            Exit Do
                        ElseIf in$ = "C" Then
                            Exit Do
                        End If
                    Loop
                    _KeyClear
                    Exit Do
                Else
                    bFinished = TRUE
                    Exit Do
                End If
            ElseIf UCase$(in$) = "I" Then
                ShowInstructions: Exit Do
            ElseIf UCase$(in$) = "4" Then
                result$ = Footrace3$(cMazeGameOption): Exit Do
            ElseIf UCase$(in$) = "3" Then
                result$ = Footrace3$(cObstacleGameOption): Exit Do
            ElseIf UCase$(in$) = "2" Then
                result$ = Footrace2$: Exit Do
            ElseIf UCase$(in$) = "1" Then
                result$ = Footrace1$: Exit Do

            ElseIf UCase$(in$) = "L" Then
                result$ = LoadMappings1$
                If Len(result$) = 0 Then result$ = "Loaded mappings."
                Exit Do
            ElseIf UCase$(in$) = "M" Then
                result$ = MapInput2$: Exit Do
            ElseIf UCase$(in$) = "T" Then
                result$ = TestMappings1$: Exit Do
            ElseIf UCase$(in$) = "S" Then
                result$ = SaveMappings1$: Exit Do

            ElseIf UCase$(in$) = "B" Then
                result$ = TestJoysticks1$: Exit Do
            ElseIf UCase$(in$) = "V" Then
                PrintControllerMap1: Exit Do

            ElseIf m_bDebug = TRUE Then
                ' *****************************************************************************
                ' BEGIN DEBUGGING ONLY ACTIONS
                If UCase$(in$) = "D" Then
                    DumpControllerMap1: Exit Do
                ElseIf UCase$(in$) = "E" Then
                    result$ = EditMappings1$: Exit Do
                ElseIf UCase$(in$) = "R" Then
                    result$ = ResetMapping1$: Exit Do
                ElseIf UCase$(in$) = "C" Then
                    result$ = MapInput1$: Exit Do
                ElseIf UCase$(in$) = "Y" Then
                    result$ = DetectColor1$: Exit Do
                ElseIf LCase$(in$) = "Z" Then
                    result$ = CustomColorFontTest1$: Exit Do
                End If
                ' END DEBUGGING ONLY ACTIONS
                ' *****************************************************************************
            End If
        Loop

        If Len(result$) > 0 Then
            Screen iScreen&: Cls
            Print result$
            Print
            Print "Press <ENTER> to continue."
            Do: Loop Until InKey$ = Chr$(13)
            _KeyClear
            result$ = ""
        End If

    Loop Until bFinished = TRUE

    ' CLEANUP AND EXIT
    Screen 0 ' RETURN TO TEXT SCREEN
    If imgScreen& < -1 Or imgScreen& > 0 Then _FreeImage imgScreen& ' FREE MEMORY

End Sub ' main

' /////////////////////////////////////////////////////////////////////////////

Sub ShowInstructions
    Dim in$: in$ = GetInstructions$
    Dim iLoop As Integer
    Dim iCount As Integer: iCount = 0
    Dim iRows As Integer: iRows = _Height(0) \ _FontHeight ' GET # OF AVAILABLE TEXT ROWS
    ReDim arrLines(-1) As String
    Cls
    split in$, Chr$(13), arrLines() ' SPLIT OUTPUT INTO LINES
    For iLoop = LBound(arrLines) To UBound(arrLines)
        Print arrLines(iLoop)
        iCount = iCount + 1
        If iCount > (iRows - 5) Then
            Input "PRESS <ENTER> TO CONTINUE"; in$
            iCount = 0
        End If
    Next iLoop
    Input "PRESS <ENTER> TO CONTINUE"; in$
End Sub ' ShowInstructions

' /////////////////////////////////////////////////////////////////////////////

Function GetInstructions$
    Dim in$
    in$ = in$ + "FOOTRACE"
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "Footrace is a simple game where you walk your player around" + Chr$(13)
    in$ = in$ + "by moving each foot. The faster you move your feet, " + Chr$(13)
    in$ = in$ + "the faster you go! Kind of like the old arcade game " + Chr$(13)
    in$ = in$ + "Track & Field but directional, using keyboard or game controller. " + Chr$(13)
    in$ = in$ + "(Tested with Logitech RumblePad 2 (1 joystick per foot), " + Chr$(13)
    in$ = in$ + "iCode USB Adapter for 4 Atari Joysticks, and keyboard.)" + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "GETTING STARTED" + Chr$(13)
    in$ = in$ + "1. Map controls (for Footrace 2 and 3)" + Chr$(13)
    in$ = in$ + "   The first time you run this, select menu option M" + Chr$(13)
    in$ = in$ + "   M) Map game controls" + Chr$(13)
    in$ = in$ + "   to set up your controller input. " + Chr$(13)
    in$ = in$ + "   The game supports 8 input devices " + Chr$(13)
    in$ = in$ + "   (2 for each player, one controls each foot) " + Chr$(13)
    in$ = in$ + "   which are shown graphically on the screen." + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "   Control   Used for" + Chr$(13)
    in$ = in$ + "   -------   --------" + Chr$(13)
    in$ = in$ + "   1         player 1 left foot" + Chr$(13)
    in$ = in$ + "   2         player 1 right foot" + Chr$(13)
    in$ = in$ + "   3         player 2 left foot" + Chr$(13)
    in$ = in$ + "   etc." + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "   For each of the 8 controllers, move the mouse to the " + Chr$(13)
    in$ = in$ + "   function you want to set up " + Chr$(13)
    in$ = in$ + "   (i.e. up/down/left/right/button1/button2/button3/button4) " + Chr$(13)
    in$ = in$ + "   and click it. A gray prompt will appear. " + Chr$(13)
    in$ = in$ + "   Now press the desired input device for that action: " + Chr$(13)
    in$ = in$ + "   * move your joystick in the desired direction, or" + Chr$(13)
    in$ = in$ + "   * press the desired button, or" + Chr$(13)
    in$ = in$ + "   * press the desired key." + Chr$(13)
    in$ = in$ + "   NOTE: For Footrace 2/3 we don't use fire buttons, " + Chr$(13)
    in$ = in$ + "         you can skip mapping those and just map directions." + Chr$(13)
    in$ = in$ + "   When finished, click CLOSE in the upper right corner." + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "2. Save your settings." + Chr$(13)
    in$ = in$ + "   Now that you have gone through all that, choose the option" + Chr$(13)
    in$ = in$ + "   S) Save controller mappings" + Chr$(13)
    in$ = in$ + "   and your mappings will be written to a file in the program " + Chr$(13)
    in$ = in$ + "   folder, which will be autoloaded from now on when you play." + Chr$(13)
    in$ = in$ + "   To change your mappings just select option M, and re-save." + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "3. Load mappings." + Chr$(13)
    in$ = in$ + "   To reload your saved mappings, choose the menu item " + Chr$(13)
    in$ = in$ + "   L) Load controller mapping" + Chr$(13)
    in$ = in$ + "   This is only needed if you have changed (& not saved) mapping" + Chr$(13)
    in$ = in$ + "   and want to revert." + Chr$(13)
    in$ = in$ + "   Note: you can back up your mapping file by simply backing up the " + Chr$(13)
    in$ = in$ + "         footrace.map.txt file (it is named after whatever your " + Chr$(13)
    in$ = in$ + "         exe program is named." + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "4. Test controls." + Chr$(13)
    in$ = in$ + "   If you want to test out your controller settings, " + Chr$(13)
    in$ = in$ + "   choose menu option T " + Chr$(13)
    in$ = in$ + "   T) Test controller mappings" + Chr$(13)
    in$ = in$ + "   which will let you move some cursors around the screen " + Chr$(13)
    in$ = in$ + "   with your controllers." + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "5. Finally, to play the game choose 1-4, where " + Chr$(13)
    in$ = in$ + "   Footrace3 - Random Maze: find your way out of the maze before the others " + Chr$(13)
    in$ = in$ + "               (upto 4 players)." + Chr$(13)
    in$ = in$ + "               Each level gets a little harder - more complicated mazes, " + Chr$(13)
    in$ = in$ + "               a smaller # of exists, and smaller exits." + Chr$(13)
    in$ = in$ + "   Footrace3 - Obstacle Course: get to the finish line before the others " + Chr$(13)
    in$ = in$ + "               (upto 4 players)." + Chr$(13)
    in$ = in$ + "               Some levels contain locked doors (A-Z) which you must unlock " + Chr$(13)
    in$ = in$ + "               by collecting the associated key (a-z)." + Chr$(13)
    in$ = in$ + "               Cycles through 3 different maps. " + Chr$(13)
    in$ = in$ + "               (Later we will probably add a level editor and option to load " + Chr$(13)
    in$ = in$ + "               graphics from a PNG or BMP file)." + Chr$(13)
    in$ = in$ + "   Footrace2 - get to the finish line before the others (upto 4 players)." + Chr$(13)
    in$ = in$ + "               Simpler graphics and layout. No doors/keys/mazes." + Chr$(13)
    in$ = in$ + "               Only has one map." + Chr$(13)
    in$ = in$ + "   Footrace1 - the bare-bones original version, for 2 players. " + Chr$(13)
    in$ = in$ + "               Controls are keyboard only and hardcoded. " + Chr$(13)
    in$ = in$ + "               No sound effects and only one screen." + Chr$(13)
    in$ = in$ + "               Player 1 uses arrow keys + numeric keypad arrow keys." + Chr$(13)
    in$ = in$ + "               Player 2 uses A/S/W/Z and J/K/I/M." + Chr$(13)
    in$ = in$ + "" + Chr$(13)
    in$ = in$ + "HINTS:" + Chr$(13)
    in$ = in$ + "* Keep track of which is your right foot and which is your left!" + Chr$(13)
    in$ = in$ + "  This is a little easier because your left and right feet " + Chr$(13)
    in$ = in$ + "  look a little different (the left has the player #)." + Chr$(13)
    in$ = in$ + "* If you are stuck on a level that no one wants to finish, " + Chr$(13)
    in$ = in$ + "  press ESC and then Y to play again, to continue to the next " + Chr$(13)
    in$ = in$ + "  screen without losing your scores and having to start over. " + Chr$(13)
    GetInstructions$ = in$
End Function ' GetInstructions$

' /////////////////////////////////////////////////////////////////////////////
' Returns TRUE if point (x1%, y1%) is adjacent to point (x2%, y2%)

Function PointsAreAdjacent% (x1%, y1%, x2%, y2%)
    Dim bResult%: bResult% = FALSE

    ' x or y can be the same, but not both
    If (x1% <> x2%) Or (y1% <> y2%) Then
        If (x1% = x2%) Or ((x1% = (x2% + 1)) Or (x2% = (x1% + 1))) Then
            If (y1% = y2%) Or ((y1% = (y2% + 1)) Or (y2% = (y1% + 1))) Then
                bResult% = TRUE
            End If
        End If
    End If
    PointsAreAdjacent% = bResult%
End Function ' PointsAreAdjacent%

' /////////////////////////////////////////////////////////////////////////////
' Pauses for iDS deciseconds (iDS * 100 ms)

Sub PauseDecisecond (iDS As Integer)
    Dim iCount As Integer
    iCount = 0
    Do
        iCount = iCount + 1
        _Limit 10 ' run 10x every second
    Loop Until iCount = iDS
End Sub ' PauseDecisecond

' /////////////////////////////////////////////////////////////////////////////
' Version 3 changes:
' * 8x8 tiles

Function Footrace3$ (iGameOption As Integer)
    ' =============================================================================
    ' CONSTANTS

    ' MIN/MAX VALUES
    Const cMinX = 2
    Const cMaxX = 79
    Const cMinY = 9
    Const cMaxY = 24

    ' FACING DIRECTION CONSTANTS
    Const c_UP = 1
    Const c_DOWN = 2
    Const c_LEFT = 3
    Const c_RIGHT = 4

    ' FOOT MOVEMENT CONSTANTS
    Const c_FORWARD = 1
    Const c_NONE = 2
    Const c_BACK = 3

    ' -----------------------------------------------------------------------------
    ' keyboard code constants for _BUTTON
    ' For now these are hard-coded as constants,
    ' later we would provide an option for the players to map their own input.

    ' PLAYER 1 LEFT JOY KEYS
    Const c_bKey_CrsrUp = 329
    Const c_bKey_CrsrDown = 337
    Const c_bKey_CrsrLeft = 332
    Const c_bKey_CrsrRight = 334
    Const c_bKey_RightCtrl = 286

    ' PLAYER 1 RIGHT JOY KEYS
    Const c_bKey_Kpad8 = 73
    Const c_bKey_Kpad2 = 81
    Const c_bKey_Kpad4 = 76
    Const c_bKey_Kpad6 = 78
    Const c_bKey_Kpad0 = 83

    ' PLAYER 2 LEFT JOY KEYS
    Const c_bKey_A = 31
    Const c_bKey_S = 32
    Const c_bKey_W = 18
    Const c_bKey_Z = 45
    Const c_bKey_LeftCtrl = 30

    ' PLAYER 2 RIGHT JOY KEYS
    Const c_bKey_J = 37
    Const c_bKey_K = 38
    Const c_bKey_I = 24
    Const c_bKey_M = 51
    Const c_bKey_Space = 58

    ' OTHER _KEYDOWN CONSTANTS
    Const c_KeyDown_Y = 121
    Const c_KeyDown_N = 110
    Const c_KeyDown_Esc = 27

    ' PLAYER KEY MAP CONSTANTS
    Const c_Map_Joy1_Left = 1
    Const c_Map_Joy1_Right = 2
    Const c_Map_Joy1_Up = 3
    Const c_Map_Joy1_Down = 4
    Const c_Map_Joy1_Button = 5
    Const c_Map_Joy2_Left = 6
    Const c_Map_Joy2_Right = 7
    Const c_Map_Joy2_Up = 8
    Const c_Map_Joy2_Down = 9
    Const c_Map_Joy2_Button = 10

    ' Array layers
    Const cMapLayer = 1
    Const cPlayerLayer = 2
    Const cObjectLayer = 3

    ' =============================================================================
    ' UDTs
    Type PlayerType3
        number As Integer

        x As Integer
        y As Integer
        new_x As Integer
        new_y As Integer

        ' BEGIN TestMappings1$
        xOld As Integer
        yOld As Integer

        ' control buffer
        moveX As Integer
        moveY As Integer

        ' control move
        moveUp As Integer
        moveDown As Integer
        moveLeft As Integer
        moveRight As Integer
        button1 As Integer
        button2 As Integer
        button3 As Integer
        button4 As Integer

        ' control previous move
        lastMoveUp As Integer
        lastMoveDown As Integer
        lastMoveLeft As Integer
        lastMoveRight As Integer
        lastButton1 As Integer
        lastButton2 As Integer
        lastButton3 As Integer
        lastButton4 As Integer
        ' END TestMappings1$

        direction As Integer ' c_UP, c_DOWN, c_LEFT, c_RIGHT
        movement As Integer ' c_FORWARD, c_NONE, c_BACK

        char As String ' character to draw player with
        fgColor As _Unsigned Long ' foreground color to draw player with
        bgColor As _Unsigned Long ' background color to draw player with

        IsFound As Integer
        IsReady As Integer ' player cannot hold down key
        IsWinner As Integer
        score As Integer ' separate scores for right/left feet!

        instructMoveUp As String
        instructMoveDown As String
        instructMoveLeft As String
        instructMoveRight As String
        instructButton1 As String
        instructButton2 As String
        instructButton3 As String
        instructButton4 As String

        keys As String
    End Type ' PlayerType3

    ' =============================================================================
    ' VARIABLES

    ' GENERAL USE
    Dim sResult As String: sResult = ""
    Dim sError As String: sError = ""
    Dim in$: in$ = ""
    Dim result$

    ' GAME LOGIC
    Dim arrPlayer(8) As PlayerType3 ' really 4 players, code treats each player's left & right feet as separate "players", just easier to code this way!
    'Dim arrMap(1 To 48, 1 To 128) As String
    Dim arrMap(1 To 80, 1 To 128, 1 To 3) As String

    Dim bLeft As Integer
    Dim bRight As Integer
    Dim iLen As Integer
    Dim sMessage As String
    Dim iPlayerLoop As Integer
    Dim iOtherLoop As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
    'DIM bTryMove AS INTEGER
    Dim bTryMoveLeft As Integer
    Dim bTryMoveRight As Integer
    'DIM bDoMove AS INTEGER
    Dim bDoMoveLeft As Integer
    Dim bDoMoveRight As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim iWinnerCount As Integer
    'DIM bHaveWinner AS INTEGER
    Dim bPlaying As Integer
    Dim bFinished As Integer
    Dim fgColor As _Unsigned Long
    Dim bgColor As _Unsigned Long
    Dim wallColor As _Unsigned Long
    Dim iPlayerLeft As Integer
    Dim iPlayerRight As Integer

    ' OLD KEYBOARD INPUT
    Dim arrKeys(512) As Integer ' for tracking keypresses (probably not needed)
    Dim arrKeyMap(2, 10) As Integer ' for mapping keys to each player's action

    ' NEW MAPPED CONTROLLER INPUT
    Dim arrButton(32, 16) As Integer ' number of buttons on the joystick
    Dim arrButtonNew(32, 16) As Integer ' tracks when to initialize values
    Dim arrAxis(32, 16) As Double ' number of axis on the joystick
    Dim arrAxisNew(32, 16) As Integer ' tracks when to initialize values
    Dim iDeviceCount As Integer
    Dim iDevice As Integer
    Dim iNumControllers As Integer
    Dim iController As Integer
    Dim iValue As Integer
    Dim iWhichInput As Integer
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iPlayer As Integer
    Dim iNextY As Integer
    Dim iNextX As Integer
    Dim iNextC As Integer
    Dim iMinX As Integer
    Dim iMaxX As Integer
    Dim iMinY As Integer
    Dim iMaxY As Integer
    Dim bHaveInput As Integer
    'Dim bFinished As Integer
    Dim bFoundWho As Integer
    Dim bRepeat As Integer
    Dim sInstruct As String

    ' OTHER VARS
    Dim iNumber As Integer
    Dim sLast As String
    Dim sNext As String
    Dim iPos As Integer
    Dim iCol1 As Integer
    Dim iCol2 As Integer
    Dim iCol3 As Integer
    Dim iCol4 As Integer
    Dim iLen1 As Integer
    Dim iLen2 As Integer
    Dim iLen3 As Integer
    Dim iLen4 As Integer
    Dim sRightTile As String
    Dim sLeftTile As String
    Dim bIsClear As Integer
    Dim iCount As Integer

    ' GRAPHICS VARS
    Dim sFile$
    Dim imgScreen&: imgScreen& = 0
    Dim imgBackground&: imgBackground& = 0
    Dim imgTiles&: imgTiles& = 0
    Dim iOffsetX As Integer
    Dim iOffSetY As Integer
    Dim iForeColor As Integer
    Dim iBackColor As Integer
    Dim iTileCols As Integer
    Dim iTileRows As Integer
    Dim iTileNum As Integer
    ReDim arrColor(-1) As ColorType

    ' SCREEN
    Dim sMap As String
    Dim iWhichMap As Integer: iWhichMap = 0 ' TODO: make a menu option?
    Dim iDifficulty As Integer: iDifficulty = 1 ' TODO: make a menu option
    Dim iDifficultyCounter As Integer: iDifficultyCounter = 0
    Dim iNumExits As Integer: iNumExits = 4 ' TODO: make a menu option
    Dim iMaxExitSize As Integer: iMaxExitSize = 8 ' TODO: make a menu option
    Dim iNumPlayers As Integer: iNumPlayers = 4 ' TODO: make a menu option

    ' ================================================================================================================================================================
    ' MAKE SURE WE HAVE MAPPING
    If Len(sError) = 0 Then
        If m_bHaveMapping = TRUE Then
            InitKeyboardButtonCodes
        Else
            result$ = LoadMappings1$
            If UCase$(Left$(result$, 5)) <> "ERROR" Then
                InitKeyboardButtonCodes
            Else
                sError = "No controller mapping found. Please map controls." + _
                    chr$(13) + result$
            End If
        End If
    End If

    ' =============================================================================
    ' INITIALIZE GRAPHICS TILES
    If Len(sError) = 0 Then

        ' LOAD TILES (16 cols x 16 rows of 8x8 tiles)

        ' LOAD TILES FROM TEXT DEFINITIONS IN Sub GetTileText
        sError = GetTiles$(imgTiles&, cBlack, cEmpty)

        '' LOAD TILES FROM PNG FILE:
        'sFile$ = m_ProgramPath$ + "Font_8x8_128x128_v3.png" ' 128x128 total, 16x16 of 8x8 tiles
        'imgTiles& = _LoadImage(sFile$, 32)
    End If

    ' =============================================================================
    ' INIT SCREEN + IMAGES
    If Len(sError) = 0 Then
        ' INITIALIZE SCREEN
        bgColor = cBlack
        'Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0
        'UpdateDisplayMapInput2 arrColor(), MapArray(), ScreenArray()
        'Cls , cBlack ' set the background color

        ' LOAD BACKGROUND IMAGE
        imgBackground& = _NewImage(1024, 768, 32)
        Screen imgBackground&
        Cls , bgColor ' set the background color

        ' COPY BACKGROUND TO SCREEN
        imgScreen& = _CopyImage(imgBackground&, 32)
        Screen imgScreen&: _ScreenMove 0, 0
    End If

    ' ================================================================================================================================================================
    ' START FILLSCREEN MODE
    ' Syntax: _FULLSCREEN [_STRETCH | _SQUAREPIXELS| _OFF][, _SMOOTH]
    ' Parameters
    ' _STRETCH default first choice attempts to mimic QBasic's full screens if possible. _FULLSCREEN (function) returns 1.
    ' _SQUAREPIXELS alternate choice enlarges the pixels into squares on some monitors. _FULLSCREEN returns 2
    ' _OFF turns _FULLSCREEN off after full screen has been enabled. _FULLSCREEN (function) returns 0.
    ' Second optional parameter _SMOOTH applies antialiasing to the stretched screen.
    '
    ' Description
    ' Set the SCREEN mode and text WIDTH when necessary first. Otherwise there may be desktop view issues.
    ' _FULLSCREEN with no parameters chooses _STRETCH or _SQUAREPIXELS (prioritizes _STRETCH to mimic QBasic if possible)
    ' Check the fullscreen mode with the _FULLSCREEN function in your programs when a method is required.
    ' It is advisable to get input from the user to confirm that fullscreen was completed or there were possible monitor incompatibilities.
    ' If fullscreen is not confirmed with a _FULLSCREEN (function) return greater than 0, then disable with _FULLSCREEN _OFF.
    ' NOTE: _FULLSCREEN can also be affected by custom _FONT size settings and make program screens too large.

    If TRUE = FALSE Then
        If Len(sError) = 0 Then
            '_FULLSCREEN _STRETCH
            _FullScreen _SquarePixels
            ' check that a full screen mode initialized

            If _FullScreen = 0 Then
                _FullScreen _Off
                Sound 100, .75
            End If
            '_SCREENMOVE _MIDDLE
        End If
    End If

    ' ================================================================================================================================================================
    ' INITIALIZE GAME
    If Len(sError) = 0 Then
        ' init colors
        AddGrayscaleColors arrColor()

        ' INITIALIZE GAME STATE
        bPlaying = TRUE
        For iPlayerLoop = 1 To 8
            arrPlayer(iPlayerLoop).score = 0
        Next iPlayerLoop
    End If

    ' =============================================================================
    ' BEGIN INITIALIZE CONTROL DATA
    If Len(sError) = 0 Then
        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
            arrPlayer(iPlayer).moveX = 0
            arrPlayer(iPlayer).moveY = 0

            arrPlayer(iPlayer).moveUp = FALSE
            arrPlayer(iPlayer).moveDown = FALSE
            arrPlayer(iPlayer).moveLeft = FALSE
            arrPlayer(iPlayer).moveRight = FALSE
            arrPlayer(iPlayer).button1 = FALSE
            arrPlayer(iPlayer).button2 = FALSE
            arrPlayer(iPlayer).button3 = FALSE
            arrPlayer(iPlayer).button4 = FALSE

            arrPlayer(iPlayer).lastMoveUp = FALSE
            arrPlayer(iPlayer).lastMoveDown = FALSE
            arrPlayer(iPlayer).lastMoveLeft = FALSE
            arrPlayer(iPlayer).lastMoveRight = FALSE
            arrPlayer(iPlayer).lastButton1 = FALSE
            arrPlayer(iPlayer).lastButton2 = FALSE
            arrPlayer(iPlayer).lastButton3 = FALSE
            arrPlayer(iPlayer).lastButton4 = FALSE

            arrPlayer(iPlayer).instructMoveUp = "NONE"
            arrPlayer(iPlayer).instructMoveDown = "NONE"
            arrPlayer(iPlayer).instructMoveLeft = "NONE"
            arrPlayer(iPlayer).instructMoveRight = "NONE"
            arrPlayer(iPlayer).instructButton1 = "NONE"
            arrPlayer(iPlayer).instructButton2 = "NONE"
            arrPlayer(iPlayer).instructButton3 = "NONE"
            arrPlayer(iPlayer).instructButton4 = "NONE"

        Next iPlayer

        ' COUNT # OF JOYSTICKS
        ' TODO: find out the right way to count joysticks
        If Len(sError) = 0 Then
            ' D= _DEVICES ' MUST be read in order for other 2 device functions to work!
            iDeviceCount = _Devices ' Find the number of devices on someone's system

            If iDeviceCount > 2 Then
                ' LIMIT # OF DEVICES, IF THERE IS A LIMIT DEFINED
                iNumControllers = iDeviceCount - 2
                If cMaxControllers > 0 Then
                    If iNumControllers > cMaxControllers Then
                        iNumControllers = cMaxControllers
                    End If
                End If
            Else
                ' ONLY 2 FOUND (KEYBOARD, MOUSE)
                'sError = "No game controllers found."
                iNumControllers = 0
            End If
        End If

        ' INITIALIZE CONTROLLER DATA
        If Len(sError) = 0 Then
            For iController = 1 To iNumControllers
                m_arrController(iController).buttonCount = cMaxButtons
                m_arrController(iController).axisCount = cMaxAxis
                For iLoop = 1 To cMaxButtons
                    arrButtonNew(iController, iLoop) = TRUE
                Next iLoop
                For iLoop = 1 To cMaxAxis
                    arrAxisNew(iController, iLoop) = TRUE
                Next iLoop
            Next iController
        End If

        ' INITIALIZE CONTROLLER INPUT
        If Len(sError) = 0 Then
            _KeyClear: _Delay 1
            For iController = 1 To iNumControllers
                iDevice = iController + 2
                While _DeviceInput(iDevice) ' clear and update the device buffer
                    For iLoop = 1 To _LastButton(iDevice)
                        If (iLoop > cMaxButtons) Then Exit For
                        m_arrController(iController).buttonCount = iLoop
                        arrButton(iController, iLoop) = FALSE
                    Next iLoop
                    For iLoop = 1 To _LastAxis(iDevice) ' this loop checks all my axis
                        If (iLoop > cMaxAxis) Then Exit For
                        m_arrController(iController).axisCount = iLoop
                        arrAxis(iController, iLoop) = 0
                    Next iLoop
                Wend ' clear and update the device buffer
            Next iController
        End If

    End If
    ' END INITIALIZE CONTROL DATA
    ' =============================================================================

    ' =============================================================================
    ' BEGIN CREATE INSTRUCTIONS FOR EACH PLAYER
    ' e.g. "D1:A1", "D1:B1", "Keypad2Down", "NONE"
    ' where D=device, A=axis, B=button
    If Len(sError) = 0 Then
        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)

                ' BUILD INSTRUCTION FOR NEXT MAPPED INPUT, SHOWING WHICH DEVICE+AXIS/BUTTON OR KEY
                Select Case m_arrControlMap(iPlayer, iWhichInput).typ
                    Case cInputNone:
                        sInstruct = "NONE"
                    Case cInputKey:
                        sInstruct = GetKeyboardButtonCodeText$(m_arrControlMap(iPlayer, iWhichInput).code)
                    Case cInputButton:
                        sInstruct = "D" + cstr$(m_arrControlMap(iPlayer, iWhichInput).device)
                        sInstruct = sInstruct + ":B" + cstr$(m_arrControlMap(iPlayer, iWhichInput).code)
                    Case cInputAxis:
                        sInstruct = "D" + cstr$(m_arrControlMap(iPlayer, iWhichInput).device)
                        sInstruct = sInstruct + ":A" + cstr$(m_arrControlMap(iPlayer, iWhichInput).code)
                    Case Else:
                        sInstruct = "NONE"
                End Select

                ' SAVE INSTRUCTION TO THE RIGHT PROPERTY
                ' Note: for now we just use up/down/left/right, but later might use buttons so left the code in
                If sInstruct <> "NONE" Then
                    Select Case iWhichInput
                        Case cInputUp:
                            arrPlayer(iPlayer).instructMoveUp = sInstruct
                        Case cInputDown:
                            arrPlayer(iPlayer).instructMoveDown = sInstruct
                        Case cInputLeft:
                            arrPlayer(iPlayer).instructMoveLeft = sInstruct
                        Case cInputRight:
                            arrPlayer(iPlayer).instructMoveRight = sInstruct
                        Case cInputButton1:
                            arrPlayer(iPlayer).instructButton1 = sInstruct
                        Case cInputButton2:
                            arrPlayer(iPlayer).instructButton2 = sInstruct
                        Case cInputButton3:
                            arrPlayer(iPlayer).instructButton3 = sInstruct
                        Case cInputButton4:
                            arrPlayer(iPlayer).instructButton4 = sInstruct
                        Case Else:
                            '(IGNORE)
                    End Select
                End If
            Next iWhichInput
        Next iPlayer
    End If
    ' END CREATE INSTRUCTIONS FOR EACH PLAYER
    ' =============================================================================



    ' ================================================================================================================================================================
    ' BEGIN GAME LOGIC

    If Len(sError) = 0 Then
        _KeyClear: _Delay 1

        ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        ' BEGIN MAIN GAME LOOP

        Do ' LOOP UNTIL bPlaying=FALSE

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' INITIALIZE NEXT ROUND
            iWinnerCount = 0
            'bHaveWinner = FALSE

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' BEGIN INITIALIZE PLAYERS FOR NEXT ROUND
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            '0 to 3
            '0 * 2)+1 = 1
            '1 * 2)+1 = 3
            '2 * 2)+1 = 5
            '3 * 2)+1 = 7
            bgColor = cBlack
            For iPlayerLoop = 0 To 3
                ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                iPlayerLeft = (iPlayerLoop * 2) + 1
                iPlayerRight = iPlayerLeft + 1

                ' PLAYER #
                arrPlayer(iPlayerLeft).number = iPlayerLoop + 1 ' # of player (1-4)

                ' LEFT FOOT
                ' NOT PLACED ON FIELD YET
                arrPlayer(iPlayerLeft).y = -1
                arrPlayer(iPlayerLeft).x = -1
                'arrPlayer(iPlayerLeft).y= 46
                'Select Case iPlayerLoop
                '    Case 0:
                '        arrPlayer(iPlayerLeft).x = 25
                '    Case 1:
                '        arrPlayer(iPlayerLeft).x = 51
                '    Case 2:
                '        arrPlayer(iPlayerLeft).x = 77
                '    Case Else:
                '        arrPlayer(iPlayerLeft).x = 103
                'End Select

                ' RIGHT FOOT
                ' NOT PLACED ON FIELD YET
                arrPlayer(iPlayerRight).y = -1
                arrPlayer(iPlayerRight).x = -1
                'arrPlayer(iPlayerRight).y = 46
                'arrPlayer(iPlayerRight).x = arrPlayer(iPlayerLeft).x + 1

                ' COLORS / GRAPHIC
                'arrPlayer(iPlayerLeft).char = CHR$(64 + iPlayerLoop + 1)
                'arrPlayer(iPlayerRight).char = CHR$(64 + iPlayerLoop + 1)
                arrPlayer(iPlayerLeft).char = Chr$(48 + iPlayerLoop + 1)
                arrPlayer(iPlayerRight).char = " "
                Select Case iPlayerLoop
                    Case 0:
                        'arrPlayer(iPlayerLeft).char = CHR$(248)
                        'arrPlayer(iPlayerRight).char = CHR$(249)
                        'fgColor = cRed ' cWhite
                        fgColor = cWhite
                        bgColor = cRed
                    Case 1:
                        'arrPlayer(iPlayerLeft).char = CHR$(250)
                        'arrPlayer(iPlayerRight).char = CHR$(251)
                        'fgColor = cBlue ' cWhite
                        fgColor = cWhite
                        bgColor = cBlue
                    Case 2:
                        'arrPlayer(iPlayerLeft).char = CHR$(252)
                        'arrPlayer(iPlayerRight).char = CHR$(253)
                        'fgColor = cLime ' cBlack
                        fgColor = cBlack
                        bgColor = cLime
                    Case Else:
                        'arrPlayer(iPlayerLeft).char = CHR$(254)
                        'arrPlayer(iPlayerRight).char = CHR$(255)
                        'fgColor = cYellow ' cBlack
                        fgColor = cBlack
                        bgColor = cYellow
                End Select
                arrPlayer(iPlayerLeft).fgColor = fgColor
                arrPlayer(iPlayerLeft).bgColor = bgColor
                arrPlayer(iPlayerRight).fgColor = fgColor
                arrPlayer(iPlayerRight).bgColor = bgColor

                ' NEW COORDINATES SAME AS OLD
                arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x
                arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y
                arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x
                arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y
                ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                arrPlayer(iPlayerLeft).IsWinner = FALSE
                arrPlayer(iPlayerRight).IsWinner = FALSE

                arrPlayer(iPlayerLeft).xOld = 0
                arrPlayer(iPlayerLeft).yOld = 0
                arrPlayer(iPlayerRight).xOld = 0
                arrPlayer(iPlayerRight).yOld = 0

                ' control buffer
                arrPlayer(iPlayerLeft).moveX = 0
                arrPlayer(iPlayerLeft).moveY = 0
                arrPlayer(iPlayerRight).moveX = 0
                arrPlayer(iPlayerRight).moveY = 0

                ' control move
                arrPlayer(iPlayerLeft).moveUp = FALSE
                arrPlayer(iPlayerLeft).moveDown = FALSE
                arrPlayer(iPlayerLeft).moveLeft = FALSE
                arrPlayer(iPlayerLeft).moveRight = FALSE
                arrPlayer(iPlayerLeft).button1 = FALSE
                arrPlayer(iPlayerLeft).button2 = FALSE
                arrPlayer(iPlayerLeft).button3 = FALSE
                arrPlayer(iPlayerLeft).button4 = FALSE
                arrPlayer(iPlayerRight).moveUp = FALSE
                arrPlayer(iPlayerRight).moveDown = FALSE
                arrPlayer(iPlayerRight).moveLeft = FALSE
                arrPlayer(iPlayerRight).moveRight = FALSE
                arrPlayer(iPlayerRight).button1 = FALSE
                arrPlayer(iPlayerRight).button2 = FALSE
                arrPlayer(iPlayerRight).button3 = FALSE
                arrPlayer(iPlayerRight).button4 = FALSE

                ' control previous move
                arrPlayer(iPlayerLeft).lastMoveUp = FALSE
                arrPlayer(iPlayerLeft).lastMoveDown = FALSE
                arrPlayer(iPlayerLeft).lastMoveLeft = FALSE
                arrPlayer(iPlayerLeft).lastMoveRight = FALSE
                arrPlayer(iPlayerLeft).lastButton1 = FALSE
                arrPlayer(iPlayerLeft).lastButton2 = FALSE
                arrPlayer(iPlayerLeft).lastButton3 = FALSE
                arrPlayer(iPlayerLeft).lastButton4 = FALSE
                arrPlayer(iPlayerRight).lastMoveUp = FALSE
                arrPlayer(iPlayerRight).lastMoveDown = FALSE
                arrPlayer(iPlayerRight).lastMoveLeft = FALSE
                arrPlayer(iPlayerRight).lastMoveRight = FALSE
                arrPlayer(iPlayerRight).lastButton1 = FALSE
                arrPlayer(iPlayerRight).lastButton2 = FALSE
                arrPlayer(iPlayerRight).lastButton3 = FALSE
                arrPlayer(iPlayerRight).lastButton4 = FALSE
                ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                arrPlayer(iPlayerLeft).direction = c_UP
                arrPlayer(iPlayerRight).direction = c_UP

                arrPlayer(iPlayerLeft).movement = c_NONE
                arrPlayer(iPlayerRight).movement = c_NONE

                arrPlayer(iPlayerLeft).IsReady = TRUE
                arrPlayer(iPlayerRight).IsReady = TRUE

                arrPlayer(iPlayerLeft).IsFound = 0
                arrPlayer(iPlayerRight).IsFound = 0

                arrPlayer(iPlayerLeft).keys = ""
                arrPlayer(iPlayerRight).keys = ""

            Next iPlayerLoop
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' END INITIALIZE PLAYERS FOR NEXT ROUND
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' INITIALIZE SCREEN
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            'CLS
            'DrawRect 0, 0, 1024, 768, bgColor
            bgColor = cBlack
            'Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0
            Cls , cBlack ' set the background color

            ' GET # OF AVAILABLE TEXT COLUMNS/ROWS
            iCols = _Width(0) \ _FontWidth
            iRows = _Height(0) \ _FontHeight

            ' GET # OF AVAILABLE TILE COLUMNS/ROWS
            iTileCols = _Width(0) \ 8
            iTileRows = _Height(0) \ 8

            ' SET ANY SCREEN OFFSET
            ' * First 16 rows used by 8 rows of hires text
            '   so map has 128 cols x 80 rows of tiles.
            iOffsetX = -1
            iOffSetY = 15

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' DRAW PLAYING FIELD AND PLAYERS
            ' UPDATE PLAYERS' INITIAL COORDINATES IF FOUND ON MAP
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

            ' LOAD PLAYING FIELD
            ' Stored in 3-D array:
            ' Dimension 1 = terrain (floor = empty = "." / walls = "#")
            ' Dimension 2 = players (1-8) used for collision
            ' Dimension 3 = objects (keys, finish line)

            ' TODO: TWEAK HOW EACH LEVEL AND DIFFICULTY PROGRESSES
            If iGameOption = cObstacleGameOption Then
                ' OBSTACLE COURSE = HUMAN-MADE SCREENS
                ' TODO: CREATE A LEVEL EDITOR
                iWhichMap = iWhichMap + 1 ' : DebugPrint "iWhichMap=" + cstr$(iWhichMap)
                If iWhichMap > 3 Then iWhichMap = 1
                Select Case iWhichMap
                    Case 1:
                        sMap = Footrace3Map1$
                    Case 2:
                        sMap = Footrace3Map2$
                    Case Else:
                        sMap = Footrace3Map3$
                End Select
            Else ' iGameOption = cMazeGameOption
                ' RANDOM MAZE COURSE

                ' GRADUALLY INCREASE IN DIFFICULTY
                iDifficultyCounter = iDifficultyCounter + 1
                If iDifficultyCounter = 1 Then
                    ' SHRINK THE EXIT!
                    If iMaxExitSize > 2 Then
                        iMaxExitSize = iMaxExitSize - 1
                    End If
                ElseIf iDifficultyCounter = 2 Then
                    ' ONE LESS EXIT!
                    iNumExits = iNumExits - 1
                    If iNumExits = 0 Then
                        iNumExits = RandomNumber%(2, 4)
                    End If
                ElseIf iDifficultyCounter = 3 Then
                    ' HARDER MAZE!
                    iDifficulty = iDifficulty + 1
                    ' TODO: allow difficulty 1 when we get players allowed to move 2 feet on one space
                    If iDifficulty > 9 Then
                        iDifficulty = 1
                    End If
                    iDifficultyCounter = 0
                End If

                ' GET THE MAZE
                sMap = GetMaze$(iDifficulty, iNumExits, iNumPlayers)
            End If
            'yyz
            'DebugPrint "sMap:"
            'DebugPrint sMap

            ' CONVERT THE PLAYING FIELD TO AN ARRAY
            StringTo3DArray arrMap(), sMap, cMapLayer

            ' DRAW FIELD + SET COORDINATES
            ' Move players to player layer + set map layer blank
            ' Move keys to object layer + set map layer blank
            bgColor = cBlack
            iForeColor = LBound(arrColor) - 1

            ' Line by line
            For iLoopY = LBound(arrMap, 1) To UBound(arrMap, 1)
                ' Cycle colors
                iForeColor = iForeColor + 1
                If iForeColor > UBound(arrColor) Then
                    iForeColor = LBound(arrColor)
                End If
                iBackColor = iForeColor

                ' Column by column
                For iLoopX = LBound(arrMap, 2) To UBound(arrMap, 2)
                    ' INITIALIZE OTHER LAYERS
                    arrMap(iLoopY, iLoopX, cPlayerLayer) = "."
                    arrMap(iLoopY, iLoopX, cObjectLayer) = "."

                    ' WALL
                    If arrMap(iLoopY, iLoopX, cMapLayer) = "#" Then
                        iTileNum = Asc("#")
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            arrColor(iForeColor).value, arrColor(iBackColor).value, _
                            iLoopX, iLoopY, iOffsetX, iOffsetY

                        ' FINISH LINE (HORIZONTAL)
                    ElseIf arrMap(iLoopY, iLoopX, cMapLayer) = "-" Then
                        iTileNum = Asc("-")
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            cWhite, bgColor, _
                            iLoopX, iLoopY, iOffsetX, iOffsetY

                        ' Place in object layer
                        arrMap(iLoopY, iLoopX, cObjectLayer) = arrMap(iLoopY, iLoopX, cMapLayer)

                        ' Map layer is blank space
                        arrMap(iLoopY, iLoopX, cMapLayer) = "."

                        ' FINISH LINE (VERTICAL)
                    ElseIf arrMap(iLoopY, iLoopX, cMapLayer) = "|" Then
                        iTileNum = 243
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            cWhite, bgColor, _
                            iLoopX, iLoopY, iOffsetX, iOffsetY

                        ' Place in object layer
                        arrMap(iLoopY, iLoopX, cObjectLayer) = arrMap(iLoopY, iLoopX, cMapLayer)

                        ' Map layer is blank space
                        arrMap(iLoopY, iLoopX, cMapLayer) = "."

                        ' PLAYERS
                        'ELSEIF IsNumber(arrMap(iLoopY, iLoopX, cMapLayer)) AND iLoopY > 8 THEN
                    ElseIf IsNumber(arrMap(iLoopY, iLoopX, cMapLayer)) Then
                        iNumber = Val(arrMap(iLoopY, iLoopX, cMapLayer))
                        If iNumber > 0 And iNumber < 9 Then
                            If arrPlayer(iNumber).IsFound = 0 Then
                                arrPlayer(iNumber).IsFound = 1

                                arrPlayer(iNumber).x = iLoopX
                                arrPlayer(iNumber).y = iLoopY
                                arrPlayer(iNumber).new_x = iLoopX
                                arrPlayer(iNumber).new_y = iLoopY

                                iTileNum = Asc(arrPlayer(iNumber).char)
                                DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                    arrPlayer(iNumber).fgColor, arrPlayer(iNumber).bgColor, _
                                    arrPlayer(iNumber).x, arrPlayer(iNumber).y, iOffsetX, iOffsetY

                                ' WRITE TO PLAYER LAYER
                                arrMap(iLoopY, iLoopX, cPlayerLayer) = arrMap(iLoopY, iLoopX, cMapLayer)

                                ' Map layer is blank space
                                arrMap(iLoopY, iLoopX, cMapLayer) = "."

                                ' DUPLICATE
                            Else
                                iTileNum = Asc(" ")
                                DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                    bgColor, bgColor, _
                                    iLoopX, iLoopY, iOffsetX, iOffsetY
                                ' Map layer is blank space
                                arrMap(iLoopY, iLoopX, cMapLayer) = "."
                            End If
                        Else
                            ' NOT 1-8
                            iTileNum = Asc(" ")
                            DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                bgColor, bgColor, _
                                iLoopX, iLoopY, iOffsetX, iOffsetY
                            ' Map layer is blank space
                            arrMap(iLoopY, iLoopX, cMapLayer) = "."
                        End If

                        ' EMPTY SPACE
                    ElseIf arrMap(iLoopY, iLoopX, cMapLayer) = "." Or arrMap(iLoopY, iLoopX, cMapLayer) = " " Then
                        iTileNum = Asc(" ")
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            bgColor, bgColor, _
                            iLoopX, iLoopY, iOffsetX, iOffsetY
                        ' Normalize map layer to "." for blank space
                        arrMap(iLoopY, iLoopX, cMapLayer) = "."

                        ' KEYS
                    ElseIf InStr("abcdefghijklmnopqrstuvwxyz", arrMap(iLoopY, iLoopX, cMapLayer)) > 0 Then
                        iTileNum = Asc(arrMap(iLoopY, iLoopX, cMapLayer))
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            cCyan, bgColor, _
                            iLoopX, iLoopY, iOffsetX, iOffsetY

                        ' Place in object layer
                        arrMap(iLoopY, iLoopX, cObjectLayer) = arrMap(iLoopY, iLoopX, cMapLayer)

                        ' Map layer is blank space
                        arrMap(iLoopY, iLoopX, cMapLayer) = "."

                        ' LOCKED DOORS
                    ElseIf InStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", arrMap(iLoopY, iLoopX, cMapLayer)) > 0 Then
                        iTileNum = Asc(arrMap(iLoopY, iLoopX, cMapLayer))
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            bgColor, arrColor(iBackColor).value, _
                            iLoopX, iLoopY, iOffsetX, iOffsetY

                        ' UNKNOWN
                    Else
                        ' TILE UNKNOWN: IGNORE (TREAT AS EMPTY SPACE)
                        'iTileNum = ASC(arrMap(iLoopY, iLoopX, cMapLayer))
                        iTileNum = Asc(" ")
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            cWhite, bgColor, _
                            iLoopX, iLoopY, iOffsetX, iOffsetY
                        arrMap(iLoopY, iLoopX, cMapLayer) = "."
                    End If

                Next iLoopX
            Next iLoopY

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' FOR EACH PLAYER, VERIFY RIGHT/LEFT FEET FOUND NEXT TO EACH OTHER
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            For iPlayerLoop = 0 To 3
                ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                iPlayerLeft = (iPlayerLoop * 2) + 1
                iPlayerRight = iPlayerLeft + 1

                ' DO WE HAVE BOTH RIGHT AND LEFT FOOT?
                If arrPlayer(iPlayerLeft).IsFound = 1 And arrPlayer(iPlayerRight).IsFound = 1 Then

                    ' ARE FEET NOT NEXT TO EACH OTHER?
                    if PointsAreAdjacent%( _
                        arrPlayer(iPlayerLeft).x, arrPlayer(iPlayerLeft).y, _
                        arrPlayer(iPlayerRight).x, arrPlayer(iPlayerRight).y _
                        ) = FALSE then

                        ' PLAYER IS INVALID!
                        DebugPrint "Player " + cstr$(iPlayerLoop + 1) + " feet not adjacent, disabling."

                        ' ERASE PLAYER FROM SCREEN
                        iTileNum = Asc(" ")
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            bgColor, bgColor, _
                            arrPlayer(iPlayerLeft).x, arrPlayer(iPlayerLeft).y, iOffsetX, iOffsetY
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            bgColor, bgColor, _
                            arrPlayer(iPlayerRight).x, arrPlayer(iPlayerRight).y, iOffsetX, iOffsetY

                        ' DISABLE PLAYER
                        arrPlayer(iPlayerLeft).IsFound = 0
                        arrPlayer(iPlayerRight).IsFound = 0
                    End If
                Else
                    If arrPlayer(iPlayerLeft).IsFound = 1 Then

                        ' PLAYER IS INVALID!
                        DebugPrint "Player " + cstr$(iPlayerLoop + 1) + " right foot not found, disabling."

                        ' ERASE PLAYER FROM SCREEN
                        iTileNum = Asc(" ")
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            bgColor, bgColor, _
                            arrPlayer(iPlayerLeft).x, arrPlayer(iPlayerLeft).y, iOffsetX, iOffsetY

                        ' DISABLE PLAYER
                        arrPlayer(iPlayerLeft).IsFound = 0

                    ElseIf arrPlayer(iPlayerRight).IsFound = 1 Then

                        ' PLAYER IS INVALID!
                        DebugPrint "Player " + cstr$(iPlayerLoop + 1) + " left foot not found, disabling."

                        ' ERASE PLAYER FROM SCREEN
                        iTileNum = Asc(" ")
                        DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                            bgColor, bgColor, _
                            arrPlayer(iPlayerRight).x, arrPlayer(iPlayerRight).y, iOffsetX, iOffsetY

                        ' DISABLE PLAYER
                        arrPlayer(iPlayerRight).IsFound = 0
                    End If
                End If
            Next iPlayerLoop

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' BEGIN SHOW TITLE / SCORE / INSTRUCTIONS
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' TITLE
            Color cRed, cWhite
            PrintString1 1, 1, left$( "" + _
                "   Footrace 3! by Softintheheadware, 2005-2022" + _
                STRING$(iCols, " ") + _
                "", iCols)

            ' HEADER ROW
            iPos = 3: iCol1 = iPos
            sNext = "PLAYER  ": iLen1 = Len(sNext)
            Color bgColor, cLightGray
            PrintString1 3, iPos, sNext

            iPos = iPos + Len(sNext): iCol2 = iPos
            sNext = "SCORE  ": iLen2 = Len(sNext)
            Color bgColor, cDarkGray
            PrintString1 3, iPos, sNext

            iPos = iPos + Len(sNext): iCol3 = iPos
            sNext = Left$("LEFT UP/DOWN/LEFT/RIGHT" + String$(55, " "), 55): iLen3 = Len(sNext)
            Color bgColor, cLightGray
            PrintString1 3, iPos, sNext

            iPos = iPos + Len(sNext): iCol4 = iPos
            sNext = Left$("RIGHT UP/DOWN/LEFT/RIGHT" + String$(55, " "), 55): iLen4 = Len(sNext)
            Color bgColor, cDarkGray
            PrintString1 3, iPos, sNext

            ' SCORE + INSTRUCTIONS FOR EACH PLAYER
            For iPlayerLoop = 0 To 3
                ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                iPlayerLeft = (iPlayerLoop * 2) + 1
                iPlayerRight = iPlayerLeft + 1

                ' SHOW IN PLAYER'S COLOR
                Color arrPlayer(iPlayerLeft).fgColor, arrPlayer(iPlayerLeft).bgColor

                ' PLAYER #
                sMessage = cstr$(iPlayerLoop + 1) + String$(iLen1, " ")
                sMessage = Left$(sMessage, iLen1)
                PrintString1 4 + iPlayerLoop, iCol1, sMessage

                ' SHOW PLAYER SCORE
                sMessage = cstr$(arrPlayer(iPlayerLeft).score + arrPlayer(iPlayerRight).score)
                sMessage = String$(iLen2, " ") + sMessage + String$(2, " ")
                sMessage = Right$(sMessage, iLen2)
                PrintString1 4 + iPlayerLoop, iCol2, sMessage

                ' SHOW CONTROLS FOR LEFT FOOT
                sMessage = ""
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveUp + "/"
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveDown + "/"
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveLeft + "/"
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveRight
                sMessage = sMessage + String$(iLen3, " ")
                sMessage = Left$(sMessage, iLen3)
                PrintString1 4 + iPlayerLoop, iCol3, sMessage

                ' SHOW CONTROLS FOR RIGHT FOOT
                sMessage = ""
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveUp + "/"
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveDown + "/"
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveLeft + "/"
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveRight
                sMessage = sMessage + String$(iLen4, " ")
                sMessage = Left$(sMessage, iLen4)
                PrintString1 4 + iPlayerLoop, iCol4, sMessage
            Next iPlayerLoop
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' END SHOW TITLE / SCORE / INSTRUCTIONS
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

            ' ================================================================================================================================================================
            ' BEGIN CURRENT ROUND
            ' ================================================================================================================================================================

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' BEGIN COUNTDOWN
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' TODO: how do we stop it from printing the next number
            '       before the previous sounds finished playing?
            '       "mf" is not really doing it...
            '       for now we just use a crude timer sub (PauseDecisecond)

            Color cRed, bgColor
            sMessage = Left$("3..." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 8, 3, sMessage
            Play "mfT120v50L4n24L4v0n24mf"

            PauseDecisecond 5

            Color cOrange, bgColor
            sMessage = Left$("2..." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 8, 3, sMessage
            Play "mfT120v50L4n24L4v0n24"

            PauseDecisecond 5

            Color cYellow, bgColor
            sMessage = Left$("1..." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 8, 3, sMessage
            Play "mfT120v50L4n24L4v0n24"

            PauseDecisecond 5

            Color cLime, bgColor
            sMessage = Left$("GO!" + String$(iCols - 4, " "), iCols - 4)
            PrintString1 8, 3, sMessage
            'Play "mbT160L1v50n36T120"
            Play "mfT160L1v50n36T120"

            PauseDecisecond 5

            ' HOW TO EXIT
            Color cCyan, bgColor
            sMessage = Left$("Press <ESC> to quit." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 8, 3, sMessage
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' END COUNTDOWN
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

            Do ' LOOP UNTIL ( _KEYDOWN(c_KeyDown_Esc) OR (iWinnerCount > 0) )

                ' -----------------------------------------------------------------------------
                ' Clear control buffer for players
                For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                    arrPlayer(iPlayer).moveUp = FALSE
                    arrPlayer(iPlayer).moveDown = FALSE
                    arrPlayer(iPlayer).moveLeft = FALSE
                    arrPlayer(iPlayer).moveRight = FALSE
                    arrPlayer(iPlayer).button1 = FALSE
                    arrPlayer(iPlayer).button2 = FALSE
                    arrPlayer(iPlayer).button3 = FALSE
                    arrPlayer(iPlayer).button4 = FALSE
                Next iPlayer

                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR CONTROLLER INPUT
                ' -----------------------------------------------------------------------------
                If iNumControllers > 0 Then
                    For iController = 1 To iNumControllers
                        iDevice = iController + 2

                        ' Check all devices
                        While _DeviceInput(iDevice)
                        Wend ' clear and update the device buffer

                        ' Check each button
                        For iLoop = 1 To _LastButton(iDevice)
                            If (iLoop > cMaxButtons) Then Exit For

                            ' update button array to indicate if a button is up or down currently.
                            'if TRUE=TRUE then
                            If _ButtonChange(iLoop) Then
                                iValue = _Button(iLoop)
                                If iValue <> arrButton(iController, iLoop) Then
                                    ' *****************************************************************************
                                    ' BEGIN PRESSED BUTTON - find who this is mapped for
                                    ' *****************************************************************************
                                    bFoundWho = FALSE
                                    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                                        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                            If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                                If m_arrControlMap(iPlayer, iWhichInput).typ = cInputButton Then
                                                    If m_arrControlMap(iPlayer, iWhichInput).code = iLoop Then
                                                        'if m_arrControlMap(iPlayer, iWhichInput).value = iValue then
                                                        bFoundWho = TRUE
                                                        Select Case iWhichInput
                                                            Case cInputUp:
                                                                arrPlayer(iPlayer).moveUp = TRUE
                                                            Case cInputDown:
                                                                arrPlayer(iPlayer).moveDown = TRUE
                                                            Case cInputLeft:
                                                                arrPlayer(iPlayer).moveLeft = TRUE
                                                            Case cInputRight:
                                                                arrPlayer(iPlayer).moveRight = TRUE
                                                            Case cInputButton1:
                                                                arrPlayer(iPlayer).button1 = TRUE
                                                            Case cInputButton2:
                                                                arrPlayer(iPlayer).button2 = TRUE
                                                            Case cInputButton3:
                                                                arrPlayer(iPlayer).button3 = TRUE
                                                            Case cInputButton4:
                                                                arrPlayer(iPlayer).button4 = TRUE
                                                            Case Else:
                                                                '(IGNORE)
                                                        End Select
                                                        Exit For
                                                        'end if
                                                    End If
                                                End If
                                            End If
                                        Next iWhichInput
                                        If bFoundWho = TRUE Then Exit For
                                    Next iPlayer
                                    ' *****************************************************************************
                                    ' END PRESSED BUTTON - find who this is mapped for
                                    ' *****************************************************************************
                                End If
                            End If
                        Next iLoop

                        ' Check each axis
                        For iLoop = 1 To _LastAxis(iDevice)
                            If (iLoop > cMaxAxis) Then Exit For
                            dblNextAxis = _Axis(iLoop)
                            dblNextAxis = RoundUpDouble#(dblNextAxis, 3)

                            ' I like to give a little "jiggle" resistance to my controls, as I have an old joystick
                            ' which is prone to always give minute values and never really center on true 0.
                            ' A value of 1 means my axis is pushed fully in one direction.
                            ' A value greater than 0.1 means it's been partially pushed in a direction (such as at a 45 degree diagional angle).
                            ' A value of less than 0.1 means we count it as being centered. (As if it was 0.)

                            ' Set sensitivity:
                            'These are way too sensitive for analog:
                            'IF ABS(_AXIS(iLoop)) <= 1 AND ABS(_AXIS(iLoop)) >= .1 THEN
                            'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .01 THEN
                            'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .001 THEN
                            ''For digital input, we'll use a big picture:
                            'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= 0.75 THEN
                            'TODO: add way to calibrate sensitivity...
                            If Abs(dblNextAxis) <= 1 And Abs(dblNextAxis) >= 0.5 Then

                                ' WE WANT CONTINUOUS MOVEMENT (DISABLE FOR NOT)
                                'if TRUE=TRUE then
                                If dblNextAxis <> arrAxis(iController, iLoop) Then
                                    ' MOVED STICK

                                    ' convert to a digital value
                                    If dblNextAxis < 0 Then
                                        iValue = -1
                                    Else
                                        iValue = 1
                                    End If

                                    ' *****************************************************************************
                                    ' BEGIN MOVED STICK - find who this is mapped for
                                    ' *****************************************************************************
                                    bFoundWho = FALSE
                                    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                                        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                            If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                                If m_arrControlMap(iPlayer, iWhichInput).typ = cInputAxis Then
                                                    If m_arrControlMap(iPlayer, iWhichInput).code = iLoop Then
                                                        If m_arrControlMap(iPlayer, iWhichInput).value = iValue Then
                                                            bFoundWho = TRUE
                                                            Select Case iWhichInput
                                                                Case cInputUp:
                                                                    arrPlayer(iPlayer).moveUp = TRUE
                                                                Case cInputDown:
                                                                    arrPlayer(iPlayer).moveDown = TRUE
                                                                Case cInputLeft:
                                                                    arrPlayer(iPlayer).moveLeft = TRUE
                                                                Case cInputRight:
                                                                    arrPlayer(iPlayer).moveRight = TRUE
                                                                Case cInputButton1:
                                                                    arrPlayer(iPlayer).button1 = TRUE
                                                                Case cInputButton2:
                                                                    arrPlayer(iPlayer).button2 = TRUE
                                                                Case cInputButton3:
                                                                    arrPlayer(iPlayer).button3 = TRUE
                                                                Case cInputButton4:
                                                                    arrPlayer(iPlayer).button4 = TRUE
                                                                Case Else:
                                                                    '(IGNORE)
                                                            End Select
                                                            Exit For
                                                        End If
                                                    End If
                                                End If
                                            End If
                                        Next iWhichInput
                                        If bFoundWho = TRUE Then Exit For
                                    Next iPlayer
                                    ' *****************************************************************************
                                    ' END MOVED STICK - find who this is mapped for
                                    ' *****************************************************************************

                                End If
                            End If
                        Next iLoop

                    Next iController
                End If
                ' -----------------------------------------------------------------------------
                ' END CHECK FOR CONTROLLER INPUT
                ' -----------------------------------------------------------------------------

                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR KEYBOARD INPUT #1
                ' -----------------------------------------------------------------------------
                '_KEYCLEAR: _DELAY 1
                While _DeviceInput(1): Wend ' clear and update the keyboard buffer

                ' Detect changed key state
                iDevice = 1 ' keyboard
                For iLoop = LBound(m_arrButtonCode) To UBound(m_arrButtonCode)
                    iCode = m_arrButtonCode(iLoop)
                    If _Button(iCode) <> FALSE Then
                        ' PRESSED KEYBOARD
                        'PRINT "PRESSED " + m_arrButtonKey(iLoop)

                        ' *****************************************************************************
                        ' BEGIN PRESSED KEYBPARD - find who this is mapped for
                        ' *****************************************************************************
                        bFoundWho = FALSE
                        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                    If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                                        'if m_arrControlMap(iPlayer, iWhichInput).code = iLoop then
                                        If m_arrControlMap(iPlayer, iWhichInput).code = iCode Then
                                            'if m_arrControlMap(iPlayer, iWhichInput).value = iValue then
                                            bFoundWho = TRUE
                                            Select Case iWhichInput
                                                Case cInputUp:
                                                    arrPlayer(iPlayer).moveUp = TRUE
                                                Case cInputDown:
                                                    arrPlayer(iPlayer).moveDown = TRUE
                                                Case cInputLeft:
                                                    arrPlayer(iPlayer).moveLeft = TRUE
                                                Case cInputRight:
                                                    arrPlayer(iPlayer).moveRight = TRUE
                                                Case cInputButton1:
                                                    arrPlayer(iPlayer).button1 = TRUE
                                                Case cInputButton2:
                                                    arrPlayer(iPlayer).button2 = TRUE
                                                Case cInputButton3:
                                                    arrPlayer(iPlayer).button3 = TRUE
                                                Case cInputButton4:
                                                    arrPlayer(iPlayer).button4 = TRUE
                                                Case Else:
                                                    '(IGNORE)
                                            End Select
                                            Exit For
                                            'end if
                                        End If
                                    End If
                                End If
                            Next iWhichInput
                            If bFoundWho = TRUE Then Exit For
                        Next iPlayer
                        ' *****************************************************************************
                        ' END PRESSED KEYBPARD - find who this is mapped for
                        ' *****************************************************************************

                    End If
                Next iLoop
                ' -----------------------------------------------------------------------------
                ' END CHECK FOR KEYBOARD INPUT #1
                ' -----------------------------------------------------------------------------

                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                ' BEGIN EVALUATE INPUT AND MOVE PLAYERS
                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

                For iPlayerLoop = 0 To 3
                    ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                    iPlayerLeft = (iPlayerLoop * 2) + 1
                    iPlayerRight = iPlayerLeft + 1

                    ' RESET MOVEMENT
                    bTryMoveLeft = FALSE
                    bTryMoveRight = FALSE
                    bDoMoveLeft = FALSE
                    bDoMoveRight = FALSE

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PREVENT PLAYER FROM MOVING BOTH FEET AT ONCE!
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' TODO: maybe later moving both feet = a way to jump, etc.
                    If arrPlayer(iPlayerLeft).moveUp = TRUE And arrPlayer(iPlayerRight).moveUp = TRUE Then
                        arrPlayer(iPlayerLeft).moveUp = FALSE
                        arrPlayer(iPlayerRight).moveUp = FALSE
                    End If
                    If arrPlayer(iPlayerLeft).moveDown = TRUE And arrPlayer(iPlayerRight).moveDown = TRUE Then
                        arrPlayer(iPlayerLeft).moveDown = FALSE
                        arrPlayer(iPlayerRight).moveDown = FALSE
                    End If
                    If arrPlayer(iPlayerLeft).moveLeft = TRUE And arrPlayer(iPlayerRight).moveLeft = TRUE Then
                        arrPlayer(iPlayerLeft).moveLeft = FALSE
                        arrPlayer(iPlayerRight).moveLeft = FALSE
                    End If
                    If arrPlayer(iPlayerLeft).moveRight = TRUE And arrPlayer(iPlayerRight).moveRight = TRUE Then
                        arrPlayer(iPlayerLeft).moveRight = FALSE
                        arrPlayer(iPlayerRight).moveRight = FALSE
                    End If
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PREVENT PLAYER FROM MOVING BOTH FEET AT ONCE!
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PROCESS LEFT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    If arrPlayer(iPlayerLeft).moveLeft = TRUE Then
                        ' STICK #1 LEFT
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE
                            arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x - 1
                            bTryMoveLeft = TRUE
                        End If
                    ElseIf arrPlayer(iPlayerLeft).moveRight = TRUE Then
                        ' STICK #1 RIGHT
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE
                            arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x + 1
                            bTryMoveLeft = TRUE
                        End If
                    ElseIf arrPlayer(iPlayerLeft).moveUp = TRUE Then
                        ' STICK #1 UP
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE
                            arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y - 1
                            bTryMoveLeft = TRUE
                        End If
                    ElseIf arrPlayer(iPlayerLeft).moveDown = TRUE Then
                        ' STICK #1 DOWN
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE
                            arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y + 1
                            bTryMoveLeft = TRUE
                        End If
                    Else
                        arrPlayer(iPlayerLeft).IsReady = TRUE
                    End If
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PROCESS LEFT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PROCESS RIGHT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    If arrPlayer(iPlayerRight).moveLeft = TRUE Then
                        ' STICK #1 LEFT
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE
                            arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x - 1
                            bTryMoveRight = TRUE
                        End If
                    ElseIf arrPlayer(iPlayerRight).moveRight = TRUE Then
                        ' STICK #1 RIGHT
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE
                            arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x + 1
                            bTryMoveRight = TRUE
                        End If
                    ElseIf arrPlayer(iPlayerRight).moveUp = TRUE Then
                        ' STICK #1 UP
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE
                            arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y - 1
                            bTryMoveRight = TRUE
                        End If
                    ElseIf arrPlayer(iPlayerRight).moveDown = TRUE Then
                        ' STICK #1 DOWN
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE
                            arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y + 1
                            bTryMoveRight = TRUE
                        End If
                    Else
                        arrPlayer(iPlayerRight).IsReady = TRUE
                    End If
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PROCESS RIGHT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PLAYER TRIED TO MOVE LEFT FOOT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    If bTryMoveLeft = TRUE Then
                        ' ASSUME NOT BLOCKED
                        bDoMoveLeft = TRUE

                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' BEGIN - IS THIS FOOT STEPPING TOO FAR AWAY FROM OTHER FOOT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        If bDoMoveLeft = TRUE Then
                            If arrPlayer(iPlayerLeft).new_y < arrPlayer(iPlayerRight).new_y - 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveLeft = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            ElseIf arrPlayer(iPlayerLeft).new_y > arrPlayer(iPlayerRight).new_y + 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveLeft = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            ElseIf arrPlayer(iPlayerLeft).new_x < arrPlayer(iPlayerRight).new_x - 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveLeft = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            ElseIf arrPlayer(iPlayerLeft).new_x > arrPlayer(iPlayerRight).new_x + 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveLeft = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            End If
                        End If
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' END - IS THIS FOOT STEPPING TOO FAR AWAY FROM OTHER FOOT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' BEGIN - IS PLAYER HITTING ANOTHER PLAYER?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        If bDoMoveLeft = TRUE Then
                            sLeftTile = arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x, cPlayerLayer)
                            If (sLeftTile <> ".") Then
                                ' Space is occupied

                                ' TODO: let player have 2 feet together in the same spot
                                '       (for squeezing through tight spaces)
                                'if arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerRight).new_y and arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerRight).new_x then
                                '    bTwoOnOne = TRUE
                                'else
                                ' COLLISION, DON'T MOVE
                                bDoMoveLeft = FALSE
                                BumpSound 2 'iPlayerLoop+1
                                'IF IsNumber(arrMap(iLoopY, iLoopX, cMapLayer)) THEN
                                'end if
                            End If
                        End If
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' END - IS PLAYER HITTING ANOTHER PLAYER?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' BEGIN CHECK TERRAIN LAYER
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        If bDoMoveLeft = TRUE Then
                            ' LOOK AHEAD WHERE LEFT FOOT IS TRYING TO MOVE
                            sLeftTile = arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x, cMapLayer)

                            ' LOCKED DOOR?
                            If InStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", sLeftTile) > 0 Then
                                ' Does player have key?
                                If InStr(arrPlayer(iPlayerLeft).keys, LCase$(sLeftTile)) > 0 Then
                                    ' Unlock door
                                    unlock_door_sound_1

                                    ' TODO: OPTION TO LEAVE DOOR OPEN FOR OTHER PLAYERS
                                    For iLoopY = arrPlayer(iPlayerLeft).new_y - 1 To arrPlayer(iPlayerLeft).new_y + 1
                                        For iLoopX = arrPlayer(iPlayerLeft).new_x - 1 To arrPlayer(iPlayerLeft).new_x + 1
                                            ' OPEN DOOR + ADJACENT (BUT NOT DIAGONALLY) DOOR TILES
                                            If (iLoopY = arrPlayer(iPlayerLeft).new_y Or iLoopX = arrPlayer(iPlayerLeft).new_x) Then
                                                ' IF THIS SPACE CONTAINS THE DOOR
                                                If arrMap(iLoopY, iLoopX, cMapLayer) = sLeftTile Then
                                                    ' Erase door from map (maybe later we can toggle the door from open to closed & vice versa)
                                                    arrMap(iLoopY, iLoopX, cMapLayer) = "."

                                                    ' Erase door on screen
                                                    iTileNum = Asc(" ")
                                                    DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                                        bgColor, bgColor, _
                                                        iLoopX, iLoopY, iOffsetX, iOffsetY
                                                End If
                                            End If
                                        Next iLoopX
                                    Next iLoopY
                                Else
                                    ' NO KEY, BLOCKED!
                                    bDoMoveLeft = FALSE
                                    BumpSound 1
                                End If

                                ' WALL?
                            ElseIf sLeftTile = "#" Then
                                ' BLOCKED BY WALL!
                                bDoMoveLeft = FALSE
                                BumpSound 1 'iPlayerLoop+1
                            End If
                        End If
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' END CHECK TERRAIN LAYER
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' BEGIN DID THE PLAYER TOUCH AN OBJECT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        If bDoMoveLeft = TRUE Then
                            sLeftTile = arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x, cObjectLayer)

                            ' KEY TOUCHED BY LEFT FOOT
                            If InStr("abcdefghijklmnopqrstuvwxyz", sLeftTile) > 0 Then
                                ' Player picks up key
                                get_key_sound_1

                                ' Remove it from the ground
                                arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x, cObjectLayer) = "."

                                ' Store it in left pocket
                                arrPlayer(iPlayerLeft).keys = arrPlayer(iPlayerLeft).keys + sLeftTile

                                ' DID LEFT FOOT CROSS THE FINISH LINE?
                            ElseIf sLeftTile = "-" Or sLeftTile = "|" Then
                                ' WE HAVE A WINNER
                                iWinnerCount = iWinnerCount + 1
                                arrPlayer(iPlayerLeft).IsWinner = TRUE
                            End If
                        End If
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' END DID THE PLAYER TOUCH AN OBJECT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' BEGIN MOVE OR DON'T MOVE
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        If bDoMoveLeft = TRUE Then
                            sLeftTile = arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x, cMapLayer)

                            ' SOUND OF FOOTSTEPS
                            WalkingSound iPlayerLoop + 1

                            ' ERASE PLAYER FROM OLD POSITION
                            iTileNum = Asc(" ")
                            DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                bgColor, bgColor, _
                                arrPlayer(iPlayerLeft).x, arrPlayer(iPlayerLeft).y, iOffsetX, iOffsetY

                            ' MOVE ON MAP
                            arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x, cPlayerLayer) = _
                                arrMap(arrPlayer(iPlayerLeft).y, arrPlayer(iPlayerLeft).x, cPlayerLayer)
                            arrMap(arrPlayer(iPlayerLeft).y, arrPlayer(iPlayerLeft).x, cPlayerLayer) = "."

                            ' UPDATE COORDINATES
                            arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerLeft).new_y
                            arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerLeft).new_x

                            ' DRAW PLAYER IN NEW POSITION
                            iTileNum = Asc(arrPlayer(iPlayerLeft).char)
                            DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                arrPlayer(iPlayerLeft).fgColor, arrPlayer(iPlayerLeft).bgColor, _
                                arrPlayer(iPlayerLeft).x, arrPlayer(iPlayerLeft).y, iOffsetX, iOffsetY
                        Else
                            ' REVERT NEW COORDS TO THE OLD COORDS
                            arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x
                            arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y
                        End If
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' END MOVE OR DON'T MOVE
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                    End If
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PLAYER TRIED TO MOVE LEFT FOOT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PLAYER TRIED TO MOVE RIGHT FOOT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    If bTryMoveRight = TRUE Then
                        ' ASSUME NOT BLOCKED
                        bDoMoveRight = TRUE

                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' BEGIN - IS THIS FOOT STEPPING TOO FAR AWAY FROM OTHER FOOT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        If bDoMoveRight = TRUE Then
                            If arrPlayer(iPlayerLeft).new_y < arrPlayer(iPlayerRight).new_y - 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveRight = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            ElseIf arrPlayer(iPlayerLeft).new_y > arrPlayer(iPlayerRight).new_y + 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveRight = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            ElseIf arrPlayer(iPlayerLeft).new_x < arrPlayer(iPlayerRight).new_x - 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveRight = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            ElseIf arrPlayer(iPlayerLeft).new_x > arrPlayer(iPlayerRight).new_x + 1 Then
                                ' TOO FAR, DON'T MOVE
                                bDoMoveRight = FALSE
                                'BumpSound 2 'iPlayerLoop+1
                            End If
                        End If
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' END - IS THIS FOOT STEPPING TOO FAR AWAY FROM OTHER FOOT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' BEGIN - IS PLAYER HITTING ANOTHER PLAYER?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        If bDoMoveRight = TRUE Then
                            sRightTile = arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x, cPlayerLayer)
                            If (sRightTile <> ".") Then
                                ' Space is occupied

                                ' TODO: let player have 2 feet together in the same spot
                                '       (for squeezing through tight spaces)
                                'if arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerRight).new_y and arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerRight).new_x then
                                '    bTwoOnOne = TRUE
                                'else
                                ' COLLISION, DON'T MOVE
                                bDoMoveRight = FALSE
                                BumpSound 2 'iPlayerLoop+1
                                'IF IsNumber(arrMap(iLoopY, iLoopX, cMapLayer)) THEN
                                'end if
                            End If
                        End If
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' END - IS PLAYER HITTING ANOTHER PLAYER?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' BEGIN CHECK TERRAIN LAYER
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        If bDoMoveRight = TRUE Then
                            ' LOOK AHEAD WHERE RIGHT FOOT IS TRYING TO MOVE
                            sRightTile = arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x, cMapLayer)

                            ' LOCKED DOOR?
                            If InStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", sRightTile) > 0 Then
                                ' Does player have key?
                                If InStr(arrPlayer(iPlayerLeft).keys, LCase$(sRightTile)) > 0 Then
                                    ' Unlock door
                                    unlock_door_sound_1

                                    ' TODO: OPTION TO LEAVE DOOR OPEN FOR OTHER PLAYERS
                                    For iLoopY = arrPlayer(iPlayerRight).new_y - 1 To arrPlayer(iPlayerRight).new_y + 1
                                        For iLoopX = arrPlayer(iPlayerRight).new_x - 1 To arrPlayer(iPlayerRight).new_x + 1
                                            ' OPEN DOOR + ADJACENT (BUT NOT DIAGONALLY) DOOR TILES
                                            If (iLoopY = arrPlayer(iPlayerRight).new_y Or iLoopX = arrPlayer(iPlayerRight).new_x) Then
                                                ' IF THIS SPACE CONTAINS THE DOOR
                                                If arrMap(iLoopY, iLoopX, cMapLayer) = sRightTile Then
                                                    ' Erase door from map (maybe later we can toggle the door from open to closed & vice versa)
                                                    arrMap(iLoopY, iLoopX, cMapLayer) = "."

                                                    ' Erase door on screen
                                                    iTileNum = Asc(" ")
                                                    DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                                        bgColor, bgColor, _
                                                        iLoopX, iLoopY, iOffsetX, iOffsetY
                                                End If
                                            End If
                                        Next iLoopX
                                    Next iLoopY
                                Else
                                    ' NO KEY, BLOCKED!
                                    bDoMoveRight = FALSE
                                    BumpSound 1
                                End If

                                ' WALL?
                            ElseIf sRightTile = "#" Then
                                ' BLOCKED BY WALL!
                                bDoMoveRight = FALSE
                                BumpSound 1 'iPlayerLoop+1
                            End If
                        End If
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' END CHECK TERRAIN LAYER
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' BEGIN DID THE PLAYER TOUCH AN OBJECT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        If bDoMoveRight = TRUE Then
                            sRightTile = arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x, cObjectLayer)

                            ' KEY TOUCHED BY RIGHT FOOT
                            If InStr("abcdefghijklmnopqrstuvwxyz", sRightTile) > 0 Then
                                ' Player picks up key
                                get_key_sound_1

                                ' Remove it from the ground
                                arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x, cObjectLayer) = "."

                                ' Store it in left pocket
                                arrPlayer(iPlayerLeft).keys = arrPlayer(iPlayerLeft).keys + sRightTile

                                ' DID RIGHT FOOT CROSS THE FINISH LINE?
                            ElseIf sRightTile = "-" Or sRightTile = "|" Then
                                ' WE HAVE A WINNER
                                iWinnerCount = iWinnerCount + 1
                                arrPlayer(iPlayerRight).IsWinner = TRUE
                            End If
                        End If
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                        ' END DID THE PLAYER TOUCH AN OBJECT?
                        ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' BEGIN MOVE OR DON'T MOVE
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        If bDoMoveRight = TRUE Then
                            sRightTile = arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x, cMapLayer)

                            ' SOUND OF FOOTSTEPS
                            WalkingSound iPlayerLoop + 1

                            ' ERASE PLAYER FROM OLD POSITION
                            iTileNum = Asc(" ")
                            DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                bgColor, bgColor, _
                                arrPlayer(iPlayerRight).x, arrPlayer(iPlayerRight).y, iOffsetX, iOffsetY

                            ' MOVE ON MAP
                            arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x, cPlayerLayer) = _
                                arrMap(arrPlayer(iPlayerRight).y, arrPlayer(iPlayerRight).x, cPlayerLayer)
                            arrMap(arrPlayer(iPlayerRight).y, arrPlayer(iPlayerRight).x, cPlayerLayer) = "."

                            ' UPDATE COORDINATES
                            arrPlayer(iPlayerRight).y = arrPlayer(iPlayerRight).new_y
                            arrPlayer(iPlayerRight).x = arrPlayer(iPlayerRight).new_x

                            ' DRAW PLAYER IN NEW POSITION
                            iTileNum = Asc(arrPlayer(iPlayerRight).char)
                            DrawColorTile imgScreen&, imgTiles&, iTileNum, _
                                arrPlayer(iPlayerRight).fgColor, arrPlayer(iPlayerRight).bgColor, _
                                arrPlayer(iPlayerRight).x, arrPlayer(iPlayerRight).y, iOffsetX, iOffsetY
                        Else
                            ' REVERT NEW COORDS TO THE OLD COORDS
                            arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x
                            arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y
                        End If
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' END MOVE OR DON'T MOVE
                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                    End If
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PLAYER TRIED TO MOVE RIGHT FOOT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PLAYER PRESSED A BUTTON
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    'IF _BUTTON(arrKeyMap(iPlayerLoop, c_Map_Button)) THEN ' BUTTON KEY IS CURRENTLY DOWN
                    '    'SOUND arrSound(iPlayerLoop), .75
                    'END IF
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PLAYER PRESSED A BUTTON
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                Next iPlayerLoop

                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                ' END EVALUATE INPUT AND MOVE PLAYERS
                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

                _Limit 120 ' keep loop at 120 frames per second
            Loop Until (_KeyDown(c_KeyDown_Esc) Or (iWinnerCount > 0)) ' leave loop when ESC key pressed
            ' ================================================================================================================================================================
            ' END CURRENT ROUND
            ' ================================================================================================================================================================

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' BEGIN DID ANYONE WIN OR DID THEY JUST QUIT?
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            If iWinnerCount > 0 Then
                ' play winner's song
                SuccessTune1

                ' check each player (in case of a tie)
                sMessage = ""
                For iPlayerLoop = 0 To 3
                    ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                    iPlayerLeft = (iPlayerLoop * 2) + 1
                    iPlayerRight = iPlayerLeft + 1

                    ' SCORE SEPARATELY FOR LEFT/RIGHT FEET,
                    ' MAYBE WE CAN USE IT AS A FUN STATISTIC LATER!
                    If arrPlayer(iPlayerLeft).IsWinner = TRUE Then
                        arrPlayer(iPlayerLeft).score = arrPlayer(iPlayerLeft).score + 1
                        sMessage = sMessage + IIFSTR$(Len(sMessage) = 0, "", " AND ") + cstr$(iPlayerLoop + 1)
                    ElseIf arrPlayer(iPlayerRight).IsWinner = TRUE Then
                        arrPlayer(iPlayerRight).score = arrPlayer(iPlayerRight).score + 1
                        sMessage = sMessage + IIFSTR$(Len(sMessage) = 0, "", " AND ") + cstr$(iPlayerLoop + 1)
                    End If
                Next iPlayerLoop

                If iWinnerCount = 1 Then
                    sMessage = "PLAYER " + sMessage + " WINS! "
                Else
                    sMessage = "IT'S A TIE BETWEEN PLAYERS " + sMessage + "! "
                End If

                Color cCyan, bgColor
                PrintString1 8, 3, sMessage + " Play again (Y / N) ?"
                bFinished = FALSE
                Do ' LOOP UNTIL bFinished
                    If _KeyDown(c_KeyDown_Y) Then
                        bFinished = TRUE
                    ElseIf _KeyDown(c_KeyDown_N) Then
                        bPlaying = FALSE
                        bFinished = TRUE
                    End If

                    _Limit 100 ' keep loop at 100 frames per second
                Loop Until bFinished ' leave loop when ESC key pressed
            Else
                ' PLAYER CANCELLED RACE
                quit_race_sound_1

                ' prompt player if they want to quit game or just go to next level, keydown codes: N = 110 Y = 121
                Color cCyan, bgColor
                PrintString1 8, 3, "Race cancelled. Play again (Y / N) ?"
                bFinished = FALSE
                Do ' LOOP UNTIL bFinished
                    If _KeyDown(c_KeyDown_Y) Then
                        bFinished = TRUE
                    ElseIf _KeyDown(c_KeyDown_N) Then
                        ' NOPE, THEY QUIT -> SET FLAG TO EXIT GAME
                        bPlaying = FALSE
                        bFinished = TRUE
                    End If

                    _Limit 100 ' keep loop at 100 frames per second
                Loop Until bFinished ' leave loop when ESC key pressed
            End If
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' END DID ANYONE WIN?
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

        Loop Until (bPlaying = FALSE)
        ' BEGIN MAIN GAME LOOP
        ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

    End If
    ' END GAME LOGIC
    ' ================================================================================================================================================================

    ' HANDLE ERRORS
    If Len(sError) > 0 Then
        'iLen = 40 - LEN(sError): sMessage = sError + STRING$(iLen, " ")
        'Color cCyan, bgColor
        'PrintString1 1, 1, sMessage
        ''LOCATE 3,1: WaitForEnter
        'PrintString1 3, 1, "Press <ENTER> to continue"
        'Sleep

        ' JUST RETURN THE ERROR TEXT TO THE CALLING ROUTINE
        sResult = sError
    End If

    ' -----------------------------------------------------------------------------
    ' RESET SCREEN + FREE MEMORY
    If TRUE = FALSE Then
        _FullScreen _Off
    End If
    Screen 0
    If imgScreen& < -1 Or imgScreen& > 0 Then _FreeImage imgScreen&
    If imgBackground& < -1 Or imgBackground& > 0 Then _FreeImage imgBackground&
    If imgTiles& < -1 Or imgTiles& > 0 Then _FreeImage imgTiles&

    ' -----------------------------------------------------------------------------
    ' RESET AND EXIT
    _KeyClear: _Delay 1
    Footrace3$ = sResult
End Function ' Footrace3$

' /////////////////////////////////////////////////////////////////////////////
' HARDCODED PLAYING BOARD #1, SIZE = 128 cols x 80 rows

Function Footrace3Map1$
    Dim m$
    m$ = ""
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#............................................................FINISH............................................................#" + Chr$(13)
    m$ = m$ + "#------------------------------------------------------------------------------------------------------------------------------#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13)
    m$ = m$ + "#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#..#" + Chr$(13)
    m$ = m$ + "#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#..#" + Chr$(13)
    m$ = m$ + "#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#" + Chr$(13)
    m$ = m$ + "#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "###......##......##.......###......##......##.......###......##......##.......###......##......##.......###......##......##....#" + Chr$(13)
    m$ = m$ + "###......##......##.......###......##......##.......###......##......##.......###......##......##.......###......##......##....#" + Chr$(13)
    m$ = m$ + "#....##......##......######....##......##......######....##......##......######....##......##......######....##......##......###" + Chr$(13)
    m$ = m$ + "#....##......##......######....##......##......######....##......##......######....##......##......######....##......##......###" + Chr$(13)
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13)
    m$ = m$ + "#..#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.#" + Chr$(13)
    m$ = m$ + "#..#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.#" + Chr$(13)
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13)
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13)
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13)
    m$ = m$ + "#.....#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#.#" + Chr$(13)
    m$ = m$ + "#.....#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#.#" + Chr$(13)
    m$ = m$ + "###################..########################..########################..########################..#############################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "###..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..###" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..................###########...............############..............############..............############..................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..................##........##..............##........##..............##........##..............##........##..................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "###..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..###" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#.................####.....####..............####....####..............####....####..............####....####..................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#......................####......................####......................####......................####......................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#.......................12........................34........................56........................78.......................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "################################################################################################################################" + Chr$(13)
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '                                                                                                             11111111111111111111111111111
    Footrace3Map1$ = m$
End Function ' Footrace3Map1$

' /////////////////////////////////////////////////////////////////////////////
' HARDCODED PLAYING BOARD #2, SIZE = 128 cols x 80 rows

' Version 3 changes:
' * uses 8x8 tiles instead of PrintString hires text
' * Resolution    Cols   Rows
'   1024 x  768   128    96
' * First 16 rows used by 8 rows of hires text
'   so map has 128 cols x 80 rows of tiles.

Function Footrace3Map2$
    Dim m$
    m$ = ""
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#............................................................FINISH............................................................#" + Chr$(13)
    m$ = m$ + "#------------------------------------------------------------------------------------------------------------------------------#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..####..####..####..####....####...####..####..####....####..####..####..####....####..####..####..####....####..####..####...#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#####..####..####..####..######..####..####..####..######..####..####..####..######..####..####..####..######..####..####.####.#" + Chr$(13)
    m$ = m$ + "#.........................#.........................#.........................#.........................#......................#" + Chr$(13)
    m$ = m$ + "#.........................#.........................#.........................#.........................#......................#" + Chr$(13)
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13)
    m$ = m$ + "#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#..#" + Chr$(13)
    m$ = m$ + "#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#..#" + Chr$(13)
    m$ = m$ + "#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#" + Chr$(13)
    m$ = m$ + "#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..#" + Chr$(13)
    m$ = m$ + "#.##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..##" + Chr$(13)
    m$ = m$ + "###..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..##....##..##..##..##..##..###" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13)
    m$ = m$ + "#..#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.#" + Chr$(13)
    m$ = m$ + "#..#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.#" + Chr$(13)
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13)
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13)
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13)
    m$ = m$ + "#.....#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#.#" + Chr$(13)
    m$ = m$ + "#.....#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#.#" + Chr$(13)
    m$ = m$ + "###################..########################..########################..########################..#############################" + Chr$(13)
    m$ = m$ + "#...........##.......................##........................##........................##........................##..........#" + Chr$(13)
    m$ = m$ + "#...............##.......................##........................##........................##........................##......#" + Chr$(13)
    m$ = m$ + "#.......##..........##...........##..........##............##..........##............##..........##............##..........##..#" + Chr$(13)
    m$ = m$ + "#.....##....##..........##.....##....##..........##......##....##..........##......##....##..........##......##....##..........#" + Chr$(13)
    m$ = m$ + "#.........##....##.................##....##..................##....##..................##....##..................##....##......#" + Chr$(13)
    m$ = m$ + "#.............##....##.................##....##..................##....##..................##....##..................##....##..#" + Chr$(13)
    m$ = m$ + "#.................##.......................##........................##........................##........................##....#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "###......##......##.......###......##......##.......###......##......##.......###......##......##.......###......##......##....#" + Chr$(13)
    m$ = m$ + "###......##......##.......###......##......##.......###......##......##.......###......##......##.......###......##......##....#" + Chr$(13)
    m$ = m$ + "#....##......##......######....##......##......######....##......##......######....##......##......######....##......##......###" + Chr$(13)
    m$ = m$ + "#....##......##......######....##......##......######....##......##......######....##......##......######....##......##......###" + Chr$(13)
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13)
    m$ = m$ + "#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#" + Chr$(13)
    m$ = m$ + "#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#" + Chr$(13)
    m$ = m$ + "#..#######....#..#..#.....#..#######....#..#..#.....#..#######....#..#..#.....#..#######....#..#..#.....#..#######....#..#..#..#" + Chr$(13)
    m$ = m$ + "#.............#..#..#.....#.............#..#..#.....#.............#..#..#.....#.............#..#..#.....#.............#..#..#..#" + Chr$(13)
    m$ = m$ + "#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#" + Chr$(13)
    m$ = m$ + "#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#" + Chr$(13)
    m$ = m$ + "#..#######....#.....#.....#..#######....#.....#.....#..#######....#.....#.....#..#######....#.....#.....#..#######....#.....#..#" + Chr$(13)
    m$ = m$ + "#.............#.....#.....#.............#.....#.....#.............#.....#.....#.............#.....#.....#.............#.....#..#" + Chr$(13)
    m$ = m$ + "#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#" + Chr$(13)
    m$ = m$ + "#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#" + Chr$(13)
    m$ = m$ + "#..#######....#.....#.....#..#######....#.....#.....#..#######....#.....#.....#..#######....#.....#.....#..#######....#.....#..#" + Chr$(13)
    m$ = m$ + "#.............#.....#.....#.............#.....#.....#.............#.....#.....#.............#.....#.....#.............#.....#..#" + Chr$(13)
    m$ = m$ + "#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#" + Chr$(13)
    m$ = m$ + "#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#..#.....#....#.....#.....#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "#......................#..#......................#..#......................#..#......................#..#......................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..##..##..##..##..##........##..##..##..##..##........##..##..##..##..##........##..##..##..##..##........##..##..##..##..##..#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "###..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..###" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#......................####......................####......................####......................####......................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "#.......................12........................34........................56........................78.......................#" + Chr$(13)
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13)
    m$ = m$ + "################################################################################################################################" + Chr$(13)
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '                                                                                                             11111111111111111111111111111
    Footrace3Map2$ = m$
End Function ' Footrace3Map2$

' /////////////////////////////////////////////////////////////////////////////
' HARDCODED PLAYING BOARD #3, SIZE = 128 cols x 80 rows
' (UNDER CONSTRUCTION)

Function Footrace3Map3$
    Dim m$
    m$ = ""
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#################################------##########################################........................" + Chr$(13)
    m$ = m$ + ".......................#...................#.....#.....#......#.....#.....#..................#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#.....#.....#......#.....#.....#..................#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#...##############..#..#..#..#..#......#..#..#..#..#..##############..#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#................#.....#.....#............#.....#.....#...............#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#................#.....#.....#............#.....#.....#...............#.........#........................" + Chr$(13)
    m$ = m$ + ".......................###########..#######################################################..###########........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#..##################..###################################..##################..#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#...................#...................#...................#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#...................#...................#...................#........................" + Chr$(13)
    m$ = m$ + ".......................##EE##############..#FF###############..#GG###############..#HH###############..#........................" + Chr$(13)
    m$ = m$ + ".......................#......#..#..#......#......#..#..#......#......#..#..#......#......#..#..#......#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#...................#...................#...................#........................" + Chr$(13)
    m$ = m$ + ".......................#.......#..#..#.....#.......#..#..#.....#.......#..#..#.....#.......#..#..#.....#........................" + Chr$(13)
    m$ = m$ + ".......................#AA###############EE#BB###############FF#CC###############GG#DD###############HH#........................" + Chr$(13)
    m$ = m$ + ".......................#.......#.....#.....#.......#.....#.....#.....#.....#.......#.....#.....#.......#........................" + Chr$(13)
    m$ = m$ + ".......................#.......#.....#.....#.......#.....#.....#.....#.....#.......#.....#.....#.......#........................" + Chr$(13)
    m$ = m$ + ".......................#....#.....#.....#..#....#.....#.....#..#..#.....#.....#....#..#.....#.....#....#........................" + Chr$(13)
    m$ = m$ + ".......................#....#e....#.....#..#....#f....#.....#..#..#.....#....g#....#..#.....#....h#....#........................" + Chr$(13)
    m$ = m$ + ".......................#....#############..#....#############..#..#############....#..#############....#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................##...................#...................#...................#..................#........................" + Chr$(13)
    m$ = m$ + ".......................##....####....####...#....####....####...#....####....####...#....####....####..#........................" + Chr$(13)
    m$ = m$ + ".......................##...................#...................#...................#..................#........................" + Chr$(13)
    m$ = m$ + ".......................#.#...................#...................#...................#.................#........................" + Chr$(13)
    m$ = m$ + ".......................#.#.......####........#.......####........#.......####........#.......####......#........................" + Chr$(13)
    m$ = m$ + ".......................#..a...................b..................................c...................d.#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#########....################....################....################....########........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#.........12..................34..................56..................78........#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#########....################....################....################....########........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#..m...................n..................................o...................p.#........................" + Chr$(13)
    m$ = m$ + ".......................#.#.......####........#.......####........#.......####........#.......####......#........................" + Chr$(13)
    m$ = m$ + ".......................#.#...................#...................#...................#.................#........................" + Chr$(13)
    m$ = m$ + ".......................##...................#...................#...................#..................#........................" + Chr$(13)
    m$ = m$ + ".......................##....####....####...#....####....####...#....####....####...#....####....####..#........................" + Chr$(13)
    m$ = m$ + ".......................##...................#...................#...................#..................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#....#############..#....#############..#..#############....#..#############....#........................" + Chr$(13)
    m$ = m$ + ".......................#....#q....#.....#..#....#r....#.....#..#..#.....#....s#....#..#.....#....t#....#........................" + Chr$(13)
    m$ = m$ + ".......................#....#.....#.....#..#....#.....#.....#..#..#.....#.....#....#..#.....#.....#....#........................" + Chr$(13)
    m$ = m$ + ".......................#.......#.....#.....#.......#.....#.....#.....#.....#.......#.....#.....#.......#........................" + Chr$(13)
    m$ = m$ + ".......................#.......#.....#.....#.......#.....#.....#.....#.....#.......#.....#.....#.......#........................" + Chr$(13)
    m$ = m$ + ".......................#MM###############QQ#NN###############RR#OO###############SS#PP###############TT#........................" + Chr$(13)
    m$ = m$ + ".......................#.......#..#..#.....#.......#..#..#.....#.......#..#..#.....#.......#..#..#.....#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#...................#...................#...................#........................" + Chr$(13)
    m$ = m$ + ".......................#......#..#..#......#......#..#..#......#......#..#..#......#......#..#..#......#........................" + Chr$(13)
    m$ = m$ + ".......................##QQ##############..#RR###############..#SS###############..#TT###############..#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#...................#...................#...................#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#...................#...................#...................#........................" + Chr$(13)
    m$ = m$ + ".......................#..##################..###################################..##################..#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................###########..#######################################################..###########........................" + Chr$(13)
    m$ = m$ + ".......................#................#.....#.....#............#.....#.....#...............#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#................#.....#.....#............#.....#.....#...............#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#...##############..#..#..#..#..#......#..#..#..#..#..##############..#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#.....#.....#......#.....#.....#..................#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#...................#.....#.....#......#.....#.....#..................#.........#........................" + Chr$(13)
    m$ = m$ + ".......................#################################------##########################################........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    m$ = m$ + ".......................#...............................................................................#........................" + Chr$(13)
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '                                                                                                             11111111111111111111111111111
    Footrace3Map3$ = m$
End Function ' Footrace3Map3$

' ################################################################################################################################################################
' BEGIN MAZE ROUTINES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Function GetMaze$ (iDifficulty As Integer, iNumExits As Integer, iNumPlayers As Integer)
    Dim sError As String: sError = ""

    Dim arrMazeOptions(10) As MazeType ' holds maze dimensions for each difficulty level

    Dim iWidth As Integer
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iFinalCols As Integer
    Dim iFinalRows As Integer

    Dim sMaze As String
    Dim iMaxRows As Integer: iMaxRows = 80
    Dim iMaxCols As Integer: iMaxCols = 128
    Dim iWall As Integer: iWall = Asc("#")
    Dim iEmpty As Integer: iEmpty = Asc(".")
    Dim iUnknown As Integer: iUnknown = Asc("?")
    Dim iFinishH As Integer: iFinishH = Asc("-")
    Dim iFinishV As Integer: iFinishV = Asc("|")
    Dim sWall As String: sWall = Chr$(iWall)
    Dim sEmpty As String: sEmpty = Chr$(iEmpty)
    ReDim arrMaze(-1, -1) As Integer
    Dim iRowCount As Integer
    Dim iColCount As Integer

    Dim iLoopRows As Integer
    Dim iLoopCols As Integer

    Dim iStartY As Integer
    Dim iStartX As Integer
    Dim iDestY As Integer
    Dim iDestX As Integer

    Dim iPlayerLeft As Integer
    Dim iPlayerRight As Integer

    Dim iPosX As Integer
    Dim iPosY As Integer
    Dim iLoopPlayer As Integer
    Dim bPlaced As Integer
    Dim iDirX As Integer
    Dim iDirY As Integer
    Dim iDistance As Integer
    Dim iExit As Integer
    Dim iExitCount As Integer
    Dim iExitSide As Integer
    Dim iAttempts As Integer
    Dim iMaxAttempts As Integer: iMaxAttempts = 20
    Dim arrFinal(iMaxRows, iMaxCols) As Integer

    Dim sResult As String: sResult = ""

    ' ================================================================================================================================================================
    ' SETUP MAZE OPTIONS
    If Len(sError) = 0 Then
        If iDifficulty < 1 Or iDifficulty > 10 Then
            sError = "ERROR: iDifficulty value of " + cstr$(iDifficulty) + " is not 1-10."
        End If
    End If

    ' ================================================================================================================================================================
    ' GENERATE MAZE
    If Len(sError) = 0 Then

        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
        ' SETUP MAZE OPTIONS

        ' Difficulty   Width    RowsIn   ColsIn   RowsOut   ColsOut
        ' 1            10       7        11       78        122
        ' 2            9        7        12       71        121
        ' 3            8        8        14       73        127
        ' 4            7        9        15       73        121
        ' 5            6        11       18       78        127
        ' 6            5        13       21       79        127
        ' 7            4        15       25       76        126
        ' 8            3        19       31       77        125
        ' 9            2        26       42       79        127
        ' 10           1        39       60       79        121

        arrMazeOptions(1).makeWidth = 10
        arrMazeOptions(1).makeRows = 7
        arrMazeOptions(1).makeCols = 11
        arrMazeOptions(1).finalRows = 78
        arrMazeOptions(1).finalCols = 122

        arrMazeOptions(2).makeWidth = 9
        arrMazeOptions(2).makeRows = 7
        arrMazeOptions(2).makeCols = 12
        arrMazeOptions(2).finalRows = 71
        arrMazeOptions(2).finalCols = 121

        arrMazeOptions(3).makeWidth = 8
        arrMazeOptions(3).makeRows = 8
        arrMazeOptions(3).makeCols = 14
        arrMazeOptions(3).finalRows = 73
        arrMazeOptions(3).finalCols = 127

        arrMazeOptions(4).makeWidth = 7
        arrMazeOptions(4).makeRows = 9
        arrMazeOptions(4).makeCols = 15
        arrMazeOptions(4).finalRows = 73
        arrMazeOptions(4).finalCols = 121

        arrMazeOptions(5).makeWidth = 6
        arrMazeOptions(5).makeRows = 11
        arrMazeOptions(5).makeCols = 18
        arrMazeOptions(5).finalRows = 78
        arrMazeOptions(5).finalCols = 127

        arrMazeOptions(6).makeWidth = 5
        arrMazeOptions(6).makeRows = 13
        arrMazeOptions(6).makeCols = 21
        arrMazeOptions(6).finalRows = 79
        arrMazeOptions(6).finalCols = 127

        arrMazeOptions(7).makeWidth = 4
        arrMazeOptions(7).makeRows = 15
        arrMazeOptions(7).makeCols = 25
        arrMazeOptions(7).finalRows = 76
        arrMazeOptions(7).finalCols = 126

        arrMazeOptions(8).makeWidth = 3
        arrMazeOptions(8).makeRows = 19
        arrMazeOptions(8).makeCols = 31
        arrMazeOptions(8).finalRows = 77
        arrMazeOptions(8).finalCols = 125

        arrMazeOptions(9).makeWidth = 2
        arrMazeOptions(9).makeRows = 26
        arrMazeOptions(9).makeCols = 42
        arrMazeOptions(9).finalRows = 79
        arrMazeOptions(9).finalCols = 127

        arrMazeOptions(10).makeWidth = 1
        arrMazeOptions(10).makeRows = 39
        arrMazeOptions(10).makeCols = 60
        arrMazeOptions(10).finalRows = 79
        arrMazeOptions(10).finalCols = 121

        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
        ' GET SETTINGS FOR THIS DIFFICULTY
        iWidth = arrMazeOptions(iDifficulty).makeWidth
        iRows = arrMazeOptions(iDifficulty).makeRows
        iCols = arrMazeOptions(iDifficulty).makeCols
        iFinalRows = arrMazeOptions(iDifficulty).finalRows
        iFinalCols = arrMazeOptions(iDifficulty).finalCols

        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
        ' GENERATE MAZE
        sMaze = random_maze$(iCols, iRows, iWidth, sWall, sEmpty)
    End If

    ' TRANSFORM MAZE TO ARRAY
    If Len(sError) = 0 Then
        MazeStringToArray sMaze, sWall, sEmpty, iMaxRows, iMaxCols, iWall, iEmpty, iUnknown, arrMaze(), iRowCount, iColCount
        If iRowCount = 0 Or iColCount = 0 Then
            sError = "ERROR: MazeStringToArray failed."
        End If
    End If

    ' ADD PLAYERS TO ARRAY
    If Len(sError) = 0 Then
        ' Enforce 1-4 players
        If iNumPlayers < 1 Then
            iNumPlayers = 1
        ElseIf iNumPlayers > 4 Then
            iNumPlayers = 4
        End If

        ' Find starting position for each
        For iLoopPlayer = 0 To iNumPlayers - 1
            ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
            iPlayerLeft = (iLoopPlayer * 2) + 1
            iPlayerRight = iPlayerLeft + 1

            bPlaced = FALSE
            iPosY = iRowCount \ 2
            iPosX = iColCount \ 2
            iDirY = -1
            iDirX = 0
            iDistance = 2
            Do
                If iPosY > LBound(arrMaze, 1) + 1 And iPosY < UBound(arrMaze, 1) - 1 Then
                    If iPosX > LBound(arrMaze, 2) + 1 And iPosX < UBound(arrMaze, 2) - 1 Then

                        ' FIND 2 EMPTY SPACES FOR PLAYER
                        If arrMaze(iPosY, iPosX) = iEmpty Then
                            ' HERE AND TO THE RIGHT?
                            If arrMaze(iPosY, iPosX + 1) = iEmpty Then
                                ' FOUND A SPACE, PLACE PLAYER RIGHT/LEFT
                                arrMaze(iPosY, iPosX) = Asc(cstr$(iPlayerLeft))
                                arrMaze(iPosY, iPosX + 1) = Asc(cstr$(iPlayerRight))
                                bPlaced = TRUE
                                Exit Do

                                ' HERE AND BELOW?
                            ElseIf arrMaze(iPosY + 1, iPosX) = iEmpty Then
                                ' FOUND A SPACE, PLACE PLAYER RIGHT/LEFT
                                arrMaze(iPosY, iPosX) = Asc(cstr$(iPlayerLeft))
                                arrMaze(iPosY + 1, iPosX) = Asc(cstr$(iPlayerRight))
                                bPlaced = TRUE
                                Exit Do
                            End If
                        End If

                        ' KEEP LOOKING SPIRALING OUTWARD
                        If iDirY = -1 Then
                            iDirY = 0: iDirX = 1
                            iPosX = iPosX + (iDistance * iDirX)
                            iPosY = iPosY + (iDistance * iDirY)
                        ElseIf iDirX = 1 Then
                            iDirY = 1: iDirX = 0
                            iPosX = iPosX + (iDistance * iDirX)
                            iPosY = iPosY + (iDistance * iDirY)
                        ElseIf iDirY = 1 Then
                            iDirY = 0: iDirX = -1
                            iPosX = iPosX + (iDistance * iDirX)
                            iPosY = iPosY + (iDistance * iDirY)
                        Else
                            iDirY = -1: iDirX = 0
                            iPosX = iPosX + (iDistance * iDirX)
                            iPosY = iPosY + (iDistance * iDirY)
                            iDistance = iDistance + 2
                        End If
                    Else
                        ' REACHED THE EDGE AND NONE FOUND
                        Exit Do
                    End If
                Else
                    ' REACHED THE EDGE AND NONE FOUND
                    Exit Do
                End If
            Loop
            If bPlaced = FALSE Then
                sError = "ERROR: Failed to place player " + cstr$((iLoopPlayer + 1) \ 2) + "."
                Exit For
            End If
        Next iLoopPlayer
    End If

    ' ADD EXITS TO ARRAY
    If Len(sError) = 0 Then
        ' Enforce 1-4 exits
        If iNumExits < 1 Then
            iNumExits = 1
        ElseIf iNumExits > 4 Then
            iNumExits = 4
        End If

        ' Initialize
        iExitCount = 0
        For iExit = 1 To iNumExits
            ' keep trying spots until we have an exit
            iAttempts = 0
            Do
                ' pick a side
                iExitSide = RandomNumber%(1, 4)
                Select Case iExitSide
                    Case 1: ' left
                        iPosX = LBound(arrMaze, 2) ' left wall
                        iDestX = iPosX + 1
                        iStartY = RandomNumber%(LBound(arrMaze, 1) + 1, UBound(arrMaze, 1) - 1)
                        If arrMaze(iStartY, iDestX) = iEmpty Then
                            ' look up
                            For iPosY = iStartY To LBound(arrMaze, 1) + 1 Step -1
                                If arrMaze(iPosY, iDestX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishV
                                Else
                                    Exit For
                                End If
                            Next iPosY

                            ' look down
                            For iPosY = iStartY + 1 To UBound(arrMaze, 1) - 1
                                If arrMaze(iPosY, iDestX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishV
                                Else
                                    Exit For
                                End If
                            Next iPosY

                            ' tally the exit and move on
                            iExitCount = iExitCount + 1
                            Exit Do
                        End If
                    Case 2: ' right
                        iPosX = UBound(arrMaze, 2) - 1 ' right wall
                        iDestX = iPosX - 2
                        iStartY = RandomNumber%(LBound(arrMaze, 1) + 1, UBound(arrMaze, 1) - 1)
                        If arrMaze(iStartY, iDestX) = iEmpty Then

                            ' look up
                            For iPosY = iStartY To LBound(arrMaze, 1) + 1 Step -1
                                If arrMaze(iPosY, iDestX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishV
                                Else
                                    Exit For
                                End If
                            Next iPosY

                            ' look down
                            For iPosY = iStartY + 1 To UBound(arrMaze, 1) - 1
                                If arrMaze(iPosY, iDestX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishV
                                Else
                                    Exit For
                                End If
                            Next iPosY

                            ' tally the exit and move on
                            iExitCount = iExitCount + 1
                            Exit Do
                        End If
                    Case 3: ' top
                        iPosY = LBound(arrMaze, 1) ' top wall
                        iDestY = iPosY + 1
                        iStartX = RandomNumber%(LBound(arrMaze, 2) + 1, UBound(arrMaze, 2) - 1)
                        If arrMaze(iDestY, iStartX) = iEmpty Then

                            ' look left
                            For iPosX = iStartX To LBound(arrMaze, 2) + 1 Step -1
                                If arrMaze(iDestY, iPosX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishH
                                Else
                                    Exit For
                                End If
                            Next iPosX

                            ' look right
                            For iPosX = iStartX + 1 To UBound(arrMaze, 2) - 1
                                If arrMaze(iDestY, iPosX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishH
                                Else
                                    Exit For
                                End If
                            Next iPosX

                            ' tally the exit and move on
                            iExitCount = iExitCount + 1
                            Exit Do
                        End If
                    Case Else: ' bottom
                        iPosY = UBound(arrMaze, 1) - 1 ' bottom wall
                        iDestY = iPosY - 2
                        iStartX = RandomNumber%(LBound(arrMaze, 2) + 1, UBound(arrMaze, 2) - 1)
                        If arrMaze(iDestY, iStartX) = iEmpty Then

                            ' look left
                            For iPosX = iStartX To LBound(arrMaze, 2) + 1 Step -1
                                If arrMaze(iDestY, iPosX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishH
                                Else
                                    Exit For
                                End If
                            Next iPosX

                            ' look right
                            For iPosX = iStartX + 1 To UBound(arrMaze, 2) - 1
                                If arrMaze(iDestY, iPosX) = iEmpty Then
                                    arrMaze(iPosY, iPosX) = iFinishH
                                Else
                                    Exit For
                                End If
                            Next iPosX

                            ' tally the exit and move on
                            iExitCount = iExitCount + 1
                            Exit Do
                        End If
                End Select
                iAttempts = iAttempts + 1: If iAttempts > iMaxAttempts Then Exit Do
            Loop
        Next iExit
        If iExitCount < iNumExits Then
            sError = "ERROR: Only found " + cstr$(iExitCount) + " exits out of required " + cstr$(iNumExits) + "."
        End If
    End If

    ' INIT GAME BOARD
    If Len(sError) = 0 Then
        For iLoopRows = LBound(arrFinal, 1) To UBound(arrFinal, 1)
            For iLoopCols = LBound(arrFinal, 2) To UBound(arrFinal, 2)
                arrFinal(iLoopRows, iLoopCols) = iEmpty
            Next iLoopCols
        Next iLoopRows
    End If

    ' COPY ARRAY TO GAME BOARD
    If Len(sError) = 0 Then

        ' Vertically center align maze in destination
        iStartY = ((iMaxRows \ 2) - (iFinalRows \ 2)) - 1

        ' Horizontally center align maze in destination
        iStartX = ((iMaxCols \ 2) - (iFinalCols \ 2)) - 1

        iDestY = iStartY
        For iLoopRows = LBound(arrMaze, 1) To UBound(arrMaze, 1)
            iDestY = iDestY + 1
            If iDestY >= LBound(arrFinal, 1) And iDestY <= UBound(arrFinal, 1) Then
                iDestX = iStartX
                For iLoopCols = LBound(arrMaze, 2) To UBound(arrMaze, 2)
                    iDestX = iDestX + 1
                    If iDestX >= LBound(arrFinal, 2) And iDestX <= UBound(arrFinal, 2) Then
                        '' only copy walls (so not to overwrite perimeter wall)
                        'if arrMaze(iLoopRows, iLoopCols) = iWall then
                        arrFinal(iDestY, iDestX) = arrMaze(iLoopRows, iLoopCols)
                        'end if
                    Else
                        sError = "ERROR: iDestX value " + cstr$(iDestX) + " ouside bounds of arrFinal(" + cstr$(LBound(arrFinal, 2)) + " To " + cstr$(UBound(arrFinal, 2)) + ")"
                        Exit For
                    End If
                Next iLoopCols
                If Len(sError) > 0 Then Exit For
            Else
                sError = "ERROR: iDestY value " + cstr$(iDestY) + " ouside bounds of arrFinal(" + cstr$(LBound(arrFinal, 1)) + " To " + cstr$(UBound(arrFinal, 1)) + ")"
                Exit For
            End If

        Next iLoopRows
    End If

    ' COPY ARRAY TO GAME BOARD
    If Len(sError) = 0 Then
        For iLoopRows = LBound(arrFinal, 1) To UBound(arrFinal, 1)
            For iLoopCols = LBound(arrFinal, 2) To UBound(arrFinal, 2)
                sResult = sResult + Chr$(arrFinal(iLoopRows, iLoopCols))
            Next iLoopCols
            If (iLoopRows < UBound(arrFinal, 1)) Then
                sResult = sResult + Chr$(13)
            End If
        Next iLoopRows
    End If

    '' DRAW WALLS AROUND EDGES
    'if len(sError) = 0 then
    '    for iLoopRows = lbound(arrFinal, 1) to ubound(arrFinal, 1)
    '        iLoopCols = lbound(arrFinal, 2) : arrFinal(iLoopRows, iLoopCols) = 1
    '        iLoopCols = ubound(arrFinal, 2) : arrFinal(iLoopRows, iLoopCols) = 1
    '    next iLoopRows
    '    for iLoopCols = lbound(arrFinal, 2) to ubound(arrFinal, 2)
    '        iLoopRows = lbound(arrFinal, 1) : arrFinal(iLoopRows, iLoopCols) = 1
    '        iLoopRows = ubound(arrFinal, 1) : arrFinal(iLoopRows, iLoopCols) = 1
    '    next iLoopCols
    'end if

    ' RETURN RESULT
    If Len(sError) = 0 Then
        GetMaze$ = sResult
    Else
        GetMaze$ = sError
    End If
End Function ' GetMaze$

' /////////////////////////////////////////////////////////////////////////////

Sub GetMazeTest ()
    Dim in$
    Dim iLoop1 As Integer
    Dim iLoop2 As Integer
    Dim sMaze As String
    Dim iDifficulty As Integer
    Dim iNumExits As Integer
    Dim iNumPlayers As Integer
    Dim iCount As Integer
    Dim iCols As Integer
    Dim iRows As Integer
    ReDim arrLines(-1) As String

    iCols = _Width(0) \ _FontWidth
    iRows = _Height(0) \ _FontHeight

    For iLoop1 = 0 To 11
        iDifficulty = iLoop1
        iNumExits = RandomNumber%(1, 4)
        iNumPlayers = RandomNumber%(0, 5)
        Cls
        Print "GetMaze$(iDifficulty=" + cstr$(iDifficulty) + ", iNumExits=" + cstr$(iNumExits) + ", iNumPlayers=" + cstr$(iNumPlayers) + ") returns:"
        sMaze = GetMaze$(iDifficulty, iNumExits, iNumPlayers)
        If UCase$(Left$(sMaze, 5)) <> "ERROR" Then
            ' SPLIT OUTPUT INTO LINES
            split sMaze, Chr$(13), arrLines()
            iCount = 0
            For iLoop2 = LBound(arrLines) To UBound(arrLines)
                Print arrLines(iLoop2)
                iCount = iCount + 1
                If iCount > (iRows - 10) Then
                    Input "PRESS <ENTER> TO CONTINUE"; in$
                    iCount = 0
                End If
            Next iLoop2
            'print sMaze
        Else
            Print "FAILED, " + sMaze
        End If
        Input "PRESS <ENTER> TO CONTINUE"; in$
    Next iLoop1
End Sub ' GetMazeTest

' /////////////////////////////////////////////////////////////////////////////

'MazeStringToArray  sMaze, sWall, sEmpty, iMaxRows, iMaxCols, iWall, iEmpty, iUnknown, arrMaze(-1,-1), iRowCount, iColCount

SUB MazeStringToArray ( _
    sMaze AS STRING, _
    sWall AS STRING, sEmpty AS STRING, _
    iMaxRows AS INTEGER, iMaxCols AS INTEGER, _
    iWall AS INTEGER, iEmpty AS INTEGER, iUnknown AS INTEGER, _
    arrMaze(-1,-1) AS INTEGER, _
    iRowCount AS INTEGER, iColCount AS INTEGER)

    ReDim arrLines$(0)
    Dim iRow%
    Dim iCol%
    Dim sChar$
    Dim sDelim As String: sDelim = Chr$(13)
    Dim sError As String: sError = ""

    ' SPLIT GRAPHIC INTO LINES
    If Len(sError) = 0 Then
        split sMaze, sDelim, arrLines$()
    End If

    ' COUNT ROWS, COLUMNS
    If Len(sError) = 0 Then
        iRowCount = 0
        iColCount = 0
        For iRow% = 0 To UBound(arrLines$) ' LBOUND(arrLines$) TO UBOUND(arrLines$)
            If iRow% <= iMaxRows Then
                iRowCount = iRowCount + 1
                For iCol% = 1 To Len(arrLines$(iRow%))
                    If iCol% <= iMaxCols Then
                        If iRowCount = 1 Then
                            iColCount = iColCount + 1
                        End If
                    Else
                        ' Exit if out of bounds
                        sError = "ERROR: Column " + cstr$(iCol%) + " exceeds max specified columns " + cstr$(iMaxCols) + "."
                        Exit For
                    End If
                Next iCol%
            Else
                ' Exit if out of bounds
                sError = "ERROR: Row " + cstr$(iRow%) + " exceeds max specified rows " + cstr$(iMaxRows) + "."
                Exit For
            End If
        Next iRow%
    End If

    ' POPULATE ARRAY
    If Len(sError) = 0 Then
        ' SIZE ARRAY TO ACCOMODATE DATA
        ReDim arrMaze(iRowCount, iColCount) As Integer

        For iRow% = 0 To UBound(arrLines$) ' LBOUND(arrLines$) TO UBOUND(arrLines$)
            For iCol% = 1 To Len(arrLines$(iRow%))
                sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
                If (sChar$ = sWall) Then
                    arrMaze(iRow%, iCol% - 1) = iWall
                ElseIf (sChar$ = sEmpty) Then
                    arrMaze(iRow%, iCol% - 1) = iEmpty
                Else
                    arrMaze(iRow%, iCol% - 1) = iUnknown
                End If
            Next iCol%
        Next iRow%
    Else
        ' RETURN ZERO ROW / COLUMN COUNT IF ERROR
        iRowCount = 0
        iColCount = 0
    End If
End Sub ' MazeStringToArray

' /////////////////////////////////////////////////////////////////////////////
' Generates a random maze and returns it as a string.

' MazeGenerator
' based on the javascript Maze Generator by Stephen R. Schmitt
' http://home.att.net/~srschmitt/script_maze_generator.html

' Got it working in VBScript and now QB64!

Function random_maze$ (iCols1 As Integer, iRows1 As Integer, iWidth1 As Integer, sChar1 As String, sEmpty1 As String)
    Dim sResult As String
    Dim arrMaze(79, 127) As Integer ' the maze of cells
    Dim arrStack(2, 65025) As Integer ' cell stack to hold a list of cell locations
    Dim iCols As Integer: iCols = iCols1
    Dim iRows As Integer: iRows = iRows1
    Dim iWidth As Integer: iWidth = iWidth1
    Dim sChar As String: sChar = sChar1
    Dim sEmpty As String: sEmpty = sEmpty1

    ' create and display a maze

    'PRINT "init_cells ..." ' DEBUG
    init_cells iCols, iRows, arrMaze(), arrStack()

    'PRINT "generate_maze ..." ' DEBUG
    generate_maze iCols, iRows, arrMaze(), arrStack()

    'PRINT "writeout_maze$ ..." ' DEBUG
    sResult = writeout_maze$(arrMaze(), iCols, iRows, iWidth, sChar, sEmpty)

    'DIM sFileName AS STRING
    'DIM sError AS STRING
    'DIM sInput AS STRING
    'sFileName = "c:\temp\maze_test_4.txt"
    'sError = PrintFile$(sFileName, sResult, FALSE)
    'IF LEN(sError) = 0 THEN
    '    PRINT "Wrote output to file " + CHR$(34) + sFileName + CHR$(34) + "."
    'ELSE
    '    PRINT "Could not write to file " + CHR$(34) + sFileName + CHR$(34) + "."
    '    PRINT sError
    'END IF
    'INPUT "Press <ENTER> to continue", sInput

    'PRINT "returning value ..." ' DEBUG
    random_maze$ = sResult
End Function ' random_maze$

' /////////////////////////////////////////////////////////////////////////////
' initialize variable sized multidimensional arrays
' ^^^
' This has been giving us trouble in QB64
' (ReDim keeps causing compiler errors, it never seems to be allowed, etc.)
' so for now we are just using a fixed size array
' and manually keeping track of the used rows/coluns.

Sub init_cells ( _
    iCols1 As Integer, iRows1 As Integer, _
    arrMaze(79, 127) As Integer, _
    arrStack(2 , 65025) As Integer _
    )

    Dim iRow As Integer
    Dim iCol As Integer
    Dim iCols As Integer: iCols = iCols1
    Dim iRows As Integer: iRows = iRows1

    'ReDim arrMaze(iCols, iRows) ' create a maze of cells that is the proper size

    ' set all walls of each cell in maze by setting bits :  cN cE cS cW
    For iRow = 0 To iRows - 1
        For iCol = 0 To iCols - 1
            'PRINT "arrMaze R" + STR$(iRow) + "C" + STR$(iCol) ' DEBUG
            arrMaze(iCol, iRow) = cN + cE + cS + cW ' room begins with walls on all 4 sides
            'arrMaze(iCol, iRow) = SetBit256%(arrMaze(iC, iR), cN, True)
            'arrMaze(iCol, iRow) = SetBit256%(arrMaze(iC, iR), cS, True)
            'arrMaze(iCol, iRow) = SetBit256%(arrMaze(iC, iR), cE, True)
            'arrMaze(iCol, iRow) = SetBit256%(arrMaze(iC, iR), cW, True)
        Next iCol
    Next iRow

    ' create stack for storing previously visited locations
    'ReDim arrStack(2, iCols * iRows)

    ' initialize stack
    For iRow = 0 To (iRows * iCols)
        For iCol = 0 To 1
            'PRINT "arrStack R" + STR$(iRow) + "C" + STR$(iCol) ' DEBUG
            arrStack(iCol, iRow) = 0
        Next iCol
    Next iRow

End Sub ' init_cells

' /////////////////////////////////////////////////////////////////////////////
' use depth first search to create a maze

Sub generate_maze ( _
    iCols1 As Integer, iRows1 As Integer, _
    arrMaze(79, 127) As Integer, _
    arrStack(2, 65025) As Integer _
    )

    Dim iCols As Integer: iCols = iCols1 ' UBound(arrMaze, 1)
    Dim iRows As Integer: iRows = iRows1 ' UBound(arrMaze, 2)
    Dim iI As Integer
    Dim iJ As Integer
    Dim iY As Integer
    Dim iX As Integer
    Dim iCurrX As Integer
    Dim iCurrY As Integer
    Dim iVisited As Integer
    Dim iTotal As Integer
    Dim iToS As Integer
    Dim arrMove(2, 4) As Integer
    Dim arrNext(2, 4) As Integer

    ' choose a cell at random and make it the current cell
    iX = RandomNumber(0, iCols - 1)
    iY = RandomNumber(0, iRows - 1)

    ' current search location
    iCurrX = iX
    iCurrY = iY

    iVisited = 1

    iTotal = iRows * iCols

    ' index for top of cell stack
    iToS = 0

    ' arrays of single step movements between cells
    ' stores the next move (dx, dy)

    ' LEFT
    arrMove(cX, 0) = -1
    arrMove(cY, 0) = 0

    ' DOWN
    arrMove(cX, 1) = 0
    arrMove(cY, 1) = 1

    ' RIGHT
    arrMove(cX, 2) = 1
    arrMove(cY, 2) = 0

    ' UP
    arrMove(cX, 3) = 0
    arrMove(cY, 3) = -1

    ' this is used for lookahead for adjacent rooms as we build the maze
    arrNext(cX, 0) = 0
    arrNext(cY, 0) = 0

    arrNext(cX, 1) = 0
    arrNext(cY, 1) = 0

    arrNext(cX, 2) = 0
    arrNext(cY, 2) = 0

    arrNext(cX, 3) = 0
    arrNext(cY, 3) = 0

    While iVisited < iTotal
        ' find all neighbors of current cell with all walls intact
        iJ = 0
        For iI = 0 To 3 ' look at each neighbor

            ' get coordinates of neighbor
            iX = iCurrX + arrMove(cX, iI)
            iY = iCurrY + arrMove(cY, iI)

            ' check for valid next cell
            If (iY >= 0) And (iY < iRows) And (iX >= 0) And (iX < iCols) Then
                ' check if previously visited

                If arrMaze(iX, iY) = (cN + cE + cS + cW) Then
                    ' not visited, so add to possible next cells
                    arrNext(cX, iJ) = iX
                    arrNext(cY, iJ) = iY
                    iJ = iJ + 1
                End If
            End If
        Next iI

        If iJ > 0 Then
            ' current cell has one or more unvisited neighbors, so choose one at random
            ' and knock down the wall between it and the current cell

            iI = RandomNumber(0, iJ - 1)

            If arrNext(cY, iI) = iCurrY Then
                ' next on same row
                iY = iCurrY
                If arrNext(cX, iI) > iCurrX Then
                    ' EAST
                    iX = iCurrX
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cE, FALSE) ' Function SetBit256%(iNum As Variant, iBit As Variant, bVal As Boolean)
                    iX = arrNext(cX, iI)
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cW, FALSE)
                Else
                    ' WEST
                    iX = iCurrX
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cW, FALSE)
                    iX = arrNext(cX, iI)
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cE, FALSE)
                End If
            Else
                ' next on same column
                iX = iCurrX
                If (arrNext(cY, iI) > iCurrY) Then
                    ' SOUTH
                    iY = iCurrY
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cS, FALSE)
                    iY = arrNext(cY, iI)
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cN, FALSE)
                Else
                    ' NORTH
                    iY = iCurrY
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cN, FALSE)
                    iY = arrNext(cY, iI)
                    arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cS, FALSE)
                End If
            End If

            ' push current cell location to stack
            iToS = iToS + 1
            arrStack(cX, iToS) = iCurrX
            arrStack(cY, iToS) = iCurrY

            ' make next cell the current cell
            iCurrX = arrNext(cX, iI)
            iCurrY = arrNext(cY, iI)

            ' increment count of visited cells
            iVisited = iVisited + 1
        Else
            ' reached dead end, backtrack
            ' pop the most recent cell from the cell stack
            ' and make it the current cell
            iCurrX = arrStack(cX, iToS)
            iCurrY = arrStack(cY, iToS)
            iToS = iToS - 1
        End If
    Wend
End Sub ' generate_maze

' /////////////////////////////////////////////////////////////////////////////
' this version writes the maze with variable size rooms

Function writeout_maze$ ( _
    arrMaze(79, 127) As Integer, _
    iCols1 As Integer, iRows1 As Integer, iWidth1 As Integer, _
    sChar1 As String, sEmpty1 As String)

    Dim iR As Integer
    Dim iC As Integer
    Dim iK As Integer
    Dim iCols As Integer
    Dim iRows As Integer
    Dim sTemp As String
    Dim sNext1 As String
    Dim sNext2 As String
    Dim iLoop As Integer
    Dim iWidth As Integer: iWidth = iWidth1
    Dim sChar As String: sChar = sChar1
    Dim sEmpty As String: sEmpty = sEmpty1

    iCols = iCols1 ' UBound(arrMaze, 1)
    iRows = iRows1 ' UBound(arrMaze, 2)

    sTemp = ""
    sNext1 = ""
    sNext2 = ""

    For iR = 0 To iRows - 1
        For iK = 1 To 2
            For iC = 0 To iCols - 1
                If iK = 1 Then
                    If (GetBit256%(arrMaze(iC, iR), cN)) Then
                        'sNext1 = sNext1 + "+" + STRING$(iWidth, "-")
                        sNext1 = sNext1 + sChar + String$(iWidth, sChar)
                    Else
                        'sNext1 = sNext1 + "+" + STRING$(iWidth, " ")
                        sNext1 = sNext1 + sChar + String$(iWidth, sEmpty)
                    End If

                    If (iC + 1) = iCols Then
                        'sNext1 = sNext1 + "+"
                        sNext1 = sNext1 + sChar
                    End If
                ElseIf iK = 2 Then
                    If (GetBit256%(arrMaze(iC, iR), cW)) Then
                        'sNext2 = sNext2 + "|" + STRING$(iWidth, " ")
                        sNext2 = sNext2 + sChar + String$(iWidth, sEmpty)
                    Else
                        'sNext2 = sNext2 + " " + STRING$(iWidth, " ")
                        sNext2 = sNext2 + sEmpty + String$(iWidth, sEmpty)
                    End If

                    If (iC + 1) = iCols Then
                        'sNext2 = sNext2 + "|"
                        sNext2 = sNext2 + sChar
                    End If
                End If
            Next iC
        Next iK

        sTemp = sTemp + sNext1 + Chr$(13)

        For iLoop = 1 To iWidth
            sTemp = sTemp + sNext2 + Chr$(13)
        Next iLoop

        sNext1 = ""
        sNext2 = ""
    Next iR

    For iC = 0 To iCols - 1
        sTemp = sTemp + sChar + String$(iWidth, sChar)
    Next iC

    sTemp = sTemp + sChar + Chr$(13)

    ' RETURN RESULT
    writeout_maze$ = sTemp
End Function ' writeout_maze$

' ################################################################################################################################################################
' END MAZE ROUTINES
' ################################################################################################################################################################


' ################################################################################################################################################################
' BEGIN FOOTRACE 2
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Version 2 changes:
' * 4 players, instead of 2
'   - each player consistes of 2 "feet", which are treated as separate "players"
'     player 1 = player 1's left foot, player 2 = player 1's right foot, etc.
' * Input from control mapping (game controller and/or keyboards)
' * Uses hires screen(1024x768) instead of text.

Function Footrace2$
    ' =============================================================================
    ' CONSTANTS

    ' MIN/MAX VALUES
    Const cMinX = 2
    Const cMaxX = 79
    Const cMinY = 9
    Const cMaxY = 24

    ' FACING DIRECTION CONSTANTS
    Const c_UP = 1
    Const c_DOWN = 2
    Const c_LEFT = 3
    Const c_RIGHT = 4

    ' FOOT MOVEMENT CONSTANTS
    Const c_FORWARD = 1
    Const c_NONE = 2
    Const c_BACK = 3

    ' -----------------------------------------------------------------------------
    ' keyboard code constants for _BUTTON
    ' For now these are hard-coded as constants,
    ' later we would provide an option for the players to map their own input.

    ' PLAYER 1 LEFT JOY KEYS
    Const c_bKey_CrsrUp = 329
    Const c_bKey_CrsrDown = 337
    Const c_bKey_CrsrLeft = 332
    Const c_bKey_CrsrRight = 334
    Const c_bKey_RightCtrl = 286

    ' PLAYER 1 RIGHT JOY KEYS
    Const c_bKey_Kpad8 = 73
    Const c_bKey_Kpad2 = 81
    Const c_bKey_Kpad4 = 76
    Const c_bKey_Kpad6 = 78
    Const c_bKey_Kpad0 = 83

    ' PLAYER 2 LEFT JOY KEYS
    Const c_bKey_A = 31
    Const c_bKey_S = 32
    Const c_bKey_W = 18
    Const c_bKey_Z = 45
    Const c_bKey_LeftCtrl = 30

    ' PLAYER 2 RIGHT JOY KEYS
    Const c_bKey_J = 37
    Const c_bKey_K = 38
    Const c_bKey_I = 24
    Const c_bKey_M = 51
    Const c_bKey_Space = 58

    ' OTHER _KEYDOWN CONSTANTS
    Const c_KeyDown_Y = 121
    Const c_KeyDown_N = 110
    Const c_KeyDown_Esc = 27
    Const c_KeyDown_F1 = 15104

    ' PLAYER KEY MAP CONSTANTS
    Const c_Map_Joy1_Left = 1
    Const c_Map_Joy1_Right = 2
    Const c_Map_Joy1_Up = 3
    Const c_Map_Joy1_Down = 4
    Const c_Map_Joy1_Button = 5
    Const c_Map_Joy2_Left = 6
    Const c_Map_Joy2_Right = 7
    Const c_Map_Joy2_Up = 8
    Const c_Map_Joy2_Down = 9
    Const c_Map_Joy2_Button = 10

    ' =============================================================================
    ' UDTs
    Type PlayerType2
        number As Integer

        x As Integer
        y As Integer
        new_x As Integer
        new_y As Integer

        ' BEGIN TestMappings1$
        xOld As Integer
        yOld As Integer

        ' control buffer
        moveX As Integer
        moveY As Integer

        ' control move
        moveUp As Integer
        moveDown As Integer
        moveLeft As Integer
        moveRight As Integer
        button1 As Integer
        button2 As Integer
        button3 As Integer
        button4 As Integer

        ' control previous move
        lastMoveUp As Integer
        lastMoveDown As Integer
        lastMoveLeft As Integer
        lastMoveRight As Integer
        lastButton1 As Integer
        lastButton2 As Integer
        lastButton3 As Integer
        lastButton4 As Integer
        ' END TestMappings1$

        direction As Integer ' c_UP, c_DOWN, c_LEFT, c_RIGHT
        movement As Integer ' c_FORWARD, c_NONE, c_BACK

        char As String ' character to draw player with
        fgColor As _Unsigned Long ' foreground color to draw player with
        bgColor As _Unsigned Long ' background color to draw player with

        IsFound As Integer
        IsReady As Integer ' player cannot hold down key
        IsWinner As Integer
        score As Integer ' separate scores for right/left feet!

        instructMoveUp As String
        instructMoveDown As String
        instructMoveLeft As String
        instructMoveRight As String
        instructButton1 As String
        instructButton2 As String
        instructButton3 As String
        instructButton4 As String

    End Type ' PlayerType2

    ' =============================================================================
    ' VARIABLES

    ' GENERAL USE
    Dim sResult As String: sResult = ""
    Dim sError As String: sError = ""
    Dim in$: in$ = ""
    Dim result$

    ' GAME LOGIC
    Dim arrPlayer(8) As PlayerType2 ' really 4 players, code treats each player's left & right feet as separate "players", just easier to code this way!
    Dim arrMap(1 To 48, 1 To 128) As String
    Dim bLeft As Integer
    Dim bRight As Integer
    Dim iLen As Integer
    Dim sMessage As String
    Dim iPlayerLoop As Integer
    Dim iOtherLoop As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
    Dim bTryMove As Integer
    Dim bDoMove As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim iWinnerCount As Integer
    'DIM bHaveWinner AS INTEGER
    Dim bPlaying As Integer
    Dim bFinished As Integer
    Dim fgColor As _Unsigned Long
    Dim bgColor As _Unsigned Long
    Dim wallColor As _Unsigned Long
    Dim iPlayerLeft As Integer
    Dim iPlayerRight As Integer

    ' OLD KEYBOARD INPUT
    Dim arrKeys(512) As Integer ' for tracking keypresses (probably not needed)
    Dim arrKeyMap(2, 10) As Integer ' for mapping keys to each player's action

    ' NEW MAPPED CONTROLLER INPUT
    Dim arrButton(32, 16) As Integer ' number of buttons on the joystick
    Dim arrButtonNew(32, 16) As Integer ' tracks when to initialize values
    Dim arrAxis(32, 16) As Double ' number of axis on the joystick
    Dim arrAxisNew(32, 16) As Integer ' tracks when to initialize values
    Dim iDeviceCount As Integer
    Dim iDevice As Integer
    Dim iNumControllers As Integer
    Dim iController As Integer
    Dim iValue As Integer
    Dim iWhichInput As Integer
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iPlayer As Integer
    Dim iNextY As Integer
    Dim iNextX As Integer
    Dim iNextC As Integer
    Dim iMinX As Integer
    Dim iMaxX As Integer
    Dim iMinY As Integer
    Dim iMaxY As Integer
    Dim bHaveInput As Integer
    'Dim bFinished As Integer
    Dim bFoundWho As Integer
    Dim bRepeat As Integer
    Dim sInstruct As String

    ' OTHER VARS
    Dim iNumber As Integer
    Dim sLast As String
    Dim sNext As String
    Dim iPos As Integer
    Dim iCol1 As Integer
    Dim iCol2 As Integer
    Dim iCol3 As Integer
    Dim iCol4 As Integer
    Dim iLen1 As Integer
    Dim iLen2 As Integer
    Dim iLen3 As Integer
    Dim iLen4 As Integer

    ' GRAPHICS VARS
    Dim imgScreen&: imgScreen& = 0

    ' ================================================================================================================================================================
    ' MAKE SURE WE HAVE MAPPING
    If Len(sError) = 0 Then
        If m_bHaveMapping = TRUE Then
            InitKeyboardButtonCodes
        Else
            result$ = LoadMappings1$
            If UCase$(Left$(result$, 5)) <> "ERROR" Then
                InitKeyboardButtonCodes
            Else
                sError = "No controller mapping found. Please map controls." + _
                    chr$(13) + result$
            End If
        End If
    End If

    ' ================================================================================================================================================================
    ' INITIALIZE GAME
    If Len(sError) = 0 Then
        bPlaying = TRUE
        For iPlayerLoop = 1 To 8
            arrPlayer(iPlayerLoop).score = 0
        Next iPlayerLoop
    End If

    ' =============================================================================
    ' INIT SCREEN
    If Len(sError) = 0 Then
        bgColor = cBlack

        imgScreen& = _NewImage(1024, 768, 32)
        Screen imgScreen&: _ScreenMove 0, 0

        'Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0
        ''UpdateDisplayMapInput2 arrColor(), MapArray(), ScreenArray()
        Cls , cBlack ' set the background color
    End If

    ' =============================================================================
    ' BEGIN INITIALIZE CONTROL DATA
    If Len(sError) = 0 Then
        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
            arrPlayer(iPlayer).moveX = 0
            arrPlayer(iPlayer).moveY = 0

            arrPlayer(iPlayer).moveUp = FALSE
            arrPlayer(iPlayer).moveDown = FALSE
            arrPlayer(iPlayer).moveLeft = FALSE
            arrPlayer(iPlayer).moveRight = FALSE
            arrPlayer(iPlayer).button1 = FALSE
            arrPlayer(iPlayer).button2 = FALSE
            arrPlayer(iPlayer).button3 = FALSE
            arrPlayer(iPlayer).button4 = FALSE

            arrPlayer(iPlayer).lastMoveUp = FALSE
            arrPlayer(iPlayer).lastMoveDown = FALSE
            arrPlayer(iPlayer).lastMoveLeft = FALSE
            arrPlayer(iPlayer).lastMoveRight = FALSE
            arrPlayer(iPlayer).lastButton1 = FALSE
            arrPlayer(iPlayer).lastButton2 = FALSE
            arrPlayer(iPlayer).lastButton3 = FALSE
            arrPlayer(iPlayer).lastButton4 = FALSE

            arrPlayer(iPlayer).instructMoveUp = "NONE"
            arrPlayer(iPlayer).instructMoveDown = "NONE"
            arrPlayer(iPlayer).instructMoveLeft = "NONE"
            arrPlayer(iPlayer).instructMoveRight = "NONE"
            arrPlayer(iPlayer).instructButton1 = "NONE"
            arrPlayer(iPlayer).instructButton2 = "NONE"
            arrPlayer(iPlayer).instructButton3 = "NONE"
            arrPlayer(iPlayer).instructButton4 = "NONE"

        Next iPlayer

        ' COUNT # OF JOYSTICKS
        ' TODO: find out the right way to count joysticks
        If Len(sError) = 0 Then
            ' D= _DEVICES ' MUST be read in order for other 2 device functions to work!
            iDeviceCount = _Devices ' Find the number of devices on someone's system

            If iDeviceCount > 2 Then
                ' LIMIT # OF DEVICES, IF THERE IS A LIMIT DEFINED
                iNumControllers = iDeviceCount - 2
                If cMaxControllers > 0 Then
                    If iNumControllers > cMaxControllers Then
                        iNumControllers = cMaxControllers
                    End If
                End If
            Else
                ' ONLY 2 FOUND (KEYBOARD, MOUSE)
                'sError = "No game controllers found."
                iNumControllers = 0
            End If
        End If

        ' INITIALIZE CONTROLLER DATA
        If Len(sError) = 0 Then
            For iController = 1 To iNumControllers
                m_arrController(iController).buttonCount = cMaxButtons
                m_arrController(iController).axisCount = cMaxAxis
                For iLoop = 1 To cMaxButtons
                    arrButtonNew(iController, iLoop) = TRUE
                Next iLoop
                For iLoop = 1 To cMaxAxis
                    arrAxisNew(iController, iLoop) = TRUE
                Next iLoop
            Next iController
        End If

        ' INITIALIZE CONTROLLER INPUT
        If Len(sError) = 0 Then
            _KeyClear: _Delay 1
            For iController = 1 To iNumControllers
                iDevice = iController + 2
                While _DeviceInput(iDevice) ' clear and update the device buffer
                    For iLoop = 1 To _LastButton(iDevice)
                        If (iLoop > cMaxButtons) Then Exit For
                        m_arrController(iController).buttonCount = iLoop
                        arrButton(iController, iLoop) = FALSE
                    Next iLoop
                    For iLoop = 1 To _LastAxis(iDevice) ' this loop checks all my axis
                        If (iLoop > cMaxAxis) Then Exit For
                        m_arrController(iController).axisCount = iLoop
                        arrAxis(iController, iLoop) = 0
                    Next iLoop
                Wend ' clear and update the device buffer
            Next iController
        End If

    End If
    ' END INITIALIZE CONTROL DATA
    ' =============================================================================

    ' =============================================================================
    ' BEGIN CREATE INSTRUCTIONS FOR EACH PLAYER
    ' e.g. "D1:A1", "D1:B1", "Keypad2Down", "NONE"
    ' where D=device, A=axis, B=button

    If Len(sError) = 0 Then
        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)

                ' BUILD INSTRUCTION FOR NEXT MAPPED INPUT, SHOWING WHICH DEVICE+AXIS/BUTTON OR KEY
                Select Case m_arrControlMap(iPlayer, iWhichInput).typ
                    Case cInputNone:
                        sInstruct = "NONE"
                    Case cInputKey:
                        sInstruct = GetKeyboardButtonCodeText$(m_arrControlMap(iPlayer, iWhichInput).code)
                    Case cInputButton:
                        sInstruct = "D" + cstr$(m_arrControlMap(iPlayer, iWhichInput).device)
                        sInstruct = sInstruct + ":B" + cstr$(m_arrControlMap(iPlayer, iWhichInput).code)
                    Case cInputAxis:
                        sInstruct = "D" + cstr$(m_arrControlMap(iPlayer, iWhichInput).device)
                        sInstruct = sInstruct + ":A" + cstr$(m_arrControlMap(iPlayer, iWhichInput).code)
                    Case Else:
                        sInstruct = "NONE"
                End Select

                ' SAVE INSTRUCTION TO THE RIGHT PROPERTY
                ' Note: for now we just use up/down/left/right, but later might use buttons so left the code in
                If sInstruct <> "NONE" Then
                    Select Case iWhichInput
                        Case cInputUp:
                            arrPlayer(iPlayer).instructMoveUp = sInstruct
                        Case cInputDown:
                            arrPlayer(iPlayer).instructMoveDown = sInstruct
                        Case cInputLeft:
                            arrPlayer(iPlayer).instructMoveLeft = sInstruct
                        Case cInputRight:
                            arrPlayer(iPlayer).instructMoveRight = sInstruct
                        Case cInputButton1:
                            arrPlayer(iPlayer).instructButton1 = sInstruct
                        Case cInputButton2:
                            arrPlayer(iPlayer).instructButton2 = sInstruct
                        Case cInputButton3:
                            arrPlayer(iPlayer).instructButton3 = sInstruct
                        Case cInputButton4:
                            arrPlayer(iPlayer).instructButton4 = sInstruct
                        Case Else:
                            '(IGNORE)
                    End Select
                End If
            Next iWhichInput
        Next iPlayer
    End If
    ' END CREATE INSTRUCTIONS FOR EACH PLAYER
    ' =============================================================================



    ' ================================================================================================================================================================
    ' BEGIN GAME LOGIC

    If Len(sError) = 0 Then
        _KeyClear: _Delay 1

        ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        ' BEGIN MAIN GAME LOOP

        Do ' LOOP UNTIL bPlaying=FALSE

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' INITIALIZE NEXT ROUND
            iWinnerCount = 0
            'bHaveWinner = FALSE

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' BEGIN INITIALIZE PLAYERS FOR NEXT ROUND
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            '0 to 3
            '0 * 2)+1 = 1
            '1 * 2)+1 = 3
            '2 * 2)+1 = 5
            '3 * 2)+1 = 7
            For iPlayerLoop = 0 To 3
                ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                iPlayerLeft = (iPlayerLoop * 2) + 1
                iPlayerRight = iPlayerLeft + 1

                ' PLAYER #
                arrPlayer(iPlayerLeft).number = iPlayerLoop + 1 ' # of player (1-4)

                ' LEFT FOOT
                arrPlayer(iPlayerLeft).y = 46
                Select Case iPlayerLoop
                    Case 1:
                        arrPlayer(iPlayerLeft).x = 25
                    Case 2:
                        arrPlayer(iPlayerLeft).x = 51
                    Case 3:
                        arrPlayer(iPlayerLeft).x = 77
                    Case Else:
                        arrPlayer(iPlayerLeft).x = 103
                End Select

                ' RIGHT FOOT
                arrPlayer(iPlayerRight).y = 46
                arrPlayer(iPlayerRight).x = arrPlayer(iPlayerLeft).x + 1

                ' COLORS / GRAPHIC
                'arrPlayer(iPlayerLeft).char = CHR$(64 + iPlayerLoop + 1)
                'arrPlayer(iPlayerRight).char = CHR$(64 + iPlayerLoop + 1)
                arrPlayer(iPlayerLeft).char = Chr$(48 + iPlayerLoop + 1)
                arrPlayer(iPlayerRight).char = " "
                Select Case iPlayerLoop
                    Case 0:
                        fgColor = cWhite
                        bgColor = cRed
                    Case 1:
                        fgColor = cWhite
                        bgColor = cBlue
                    Case 2:
                        fgColor = cBlack
                        bgColor = cLime
                    Case Else:
                        fgColor = cBlack
                        bgColor = cYellow
                End Select
                arrPlayer(iPlayerLeft).fgColor = fgColor
                arrPlayer(iPlayerLeft).bgColor = bgColor
                arrPlayer(iPlayerRight).fgColor = fgColor
                arrPlayer(iPlayerRight).bgColor = bgColor

                ' NEW COORDINATES SAME AS OLD
                arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x
                arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y
                arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x
                arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y
                ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                arrPlayer(iPlayerLeft).IsWinner = FALSE
                arrPlayer(iPlayerRight).IsWinner = FALSE

                arrPlayer(iPlayerLeft).xOld = 0
                arrPlayer(iPlayerLeft).yOld = 0
                arrPlayer(iPlayerRight).xOld = 0
                arrPlayer(iPlayerRight).yOld = 0

                ' control buffer
                arrPlayer(iPlayerLeft).moveX = 0
                arrPlayer(iPlayerLeft).moveY = 0
                arrPlayer(iPlayerRight).moveX = 0
                arrPlayer(iPlayerRight).moveY = 0

                ' control move
                arrPlayer(iPlayerLeft).moveUp = FALSE
                arrPlayer(iPlayerLeft).moveDown = FALSE
                arrPlayer(iPlayerLeft).moveLeft = FALSE
                arrPlayer(iPlayerLeft).moveRight = FALSE
                arrPlayer(iPlayerLeft).button1 = FALSE
                arrPlayer(iPlayerLeft).button2 = FALSE
                arrPlayer(iPlayerLeft).button3 = FALSE
                arrPlayer(iPlayerLeft).button4 = FALSE
                arrPlayer(iPlayerRight).moveUp = FALSE
                arrPlayer(iPlayerRight).moveDown = FALSE
                arrPlayer(iPlayerRight).moveLeft = FALSE
                arrPlayer(iPlayerRight).moveRight = FALSE
                arrPlayer(iPlayerRight).button1 = FALSE
                arrPlayer(iPlayerRight).button2 = FALSE
                arrPlayer(iPlayerRight).button3 = FALSE
                arrPlayer(iPlayerRight).button4 = FALSE

                ' control previous move
                arrPlayer(iPlayerLeft).lastMoveUp = FALSE
                arrPlayer(iPlayerLeft).lastMoveDown = FALSE
                arrPlayer(iPlayerLeft).lastMoveLeft = FALSE
                arrPlayer(iPlayerLeft).lastMoveRight = FALSE
                arrPlayer(iPlayerLeft).lastButton1 = FALSE
                arrPlayer(iPlayerLeft).lastButton2 = FALSE
                arrPlayer(iPlayerLeft).lastButton3 = FALSE
                arrPlayer(iPlayerLeft).lastButton4 = FALSE
                arrPlayer(iPlayerRight).lastMoveUp = FALSE
                arrPlayer(iPlayerRight).lastMoveDown = FALSE
                arrPlayer(iPlayerRight).lastMoveLeft = FALSE
                arrPlayer(iPlayerRight).lastMoveRight = FALSE
                arrPlayer(iPlayerRight).lastButton1 = FALSE
                arrPlayer(iPlayerRight).lastButton2 = FALSE
                arrPlayer(iPlayerRight).lastButton3 = FALSE
                arrPlayer(iPlayerRight).lastButton4 = FALSE
                ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                arrPlayer(iPlayerLeft).direction = c_UP
                arrPlayer(iPlayerRight).direction = c_UP

                arrPlayer(iPlayerLeft).movement = c_NONE
                arrPlayer(iPlayerRight).movement = c_NONE

                arrPlayer(iPlayerLeft).IsReady = TRUE
                arrPlayer(iPlayerRight).IsReady = TRUE

                arrPlayer(iPlayerLeft).IsFound = 0
                arrPlayer(iPlayerRight).IsFound = 0
            Next iPlayerLoop
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' END INITIALIZE PLAYERS FOR NEXT ROUND
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' INITIALIZE SCREEN
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            'CLS
            'DrawRect 0, 0, 1024, 768, bgColor
            bgColor = cBlack
            Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0
            Cls , cBlack ' set the background color

            ' GET # OF AVAILABLE TEXT COLUMNS/ROWS
            iCols = _Width(0) \ _FontWidth
            iRows = _Height(0) \ _FontHeight

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' DRAW PLAYING FIELD AND PLAYERS
            ' UPDATE PLAYERS' INITIAL COORDINATES IF FOUND ON MAP
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

            ' LOAD PLAYING FIELD
            StringToArray arrMap(), Footrace2Map1$

            ' DRAW FIELD + SET COORDINATES
            bgColor = cBlack
            wallColor = cMagenta ' cCyan cGold cWhite cGray cOrange
            For iLoopY = LBound(arrMap, 1) To UBound(arrMap, 1)
                For iLoopX = LBound(arrMap, 2) To UBound(arrMap, 2)
                    If arrMap(iLoopY, iLoopX) = "#" Then
                        'Color cGold, cGold
                        Color wallColor, wallColor
                        PrintString1 iLoopY, iLoopX, "#"
                        Color cWhite, bgColor
                    ElseIf arrMap(iLoopY, iLoopX) = "-" Then
                        Color cWhite, bgColor
                        PrintString1 iLoopY, iLoopX, "-"
                    ElseIf IsNumber(arrMap(iLoopY, iLoopX)) And iLoopY > 8 Then
                        iNumber = Val(arrMap(iLoopY, iLoopX)) - 1
                        If iNumber >= 0 And iNumber <= 3 Then
                            ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                            iPlayerLeft = (iNumber * 2) + 1
                            iPlayerRight = iPlayerLeft + 1

                            arrPlayer(iPlayerLeft).IsFound = arrPlayer(iPlayerLeft).IsFound + 1
                            If arrPlayer(iPlayerLeft).IsFound = 1 Then
                                arrPlayer(iPlayerLeft).x = iLoopX
                                arrPlayer(iPlayerLeft).y = iLoopY
                                arrPlayer(iPlayerLeft).new_x = iLoopX
                                arrPlayer(iPlayerLeft).new_y = iLoopY
                                Color arrPlayer(iPlayerLeft).fgColor, arrPlayer(iPlayerLeft).bgColor
                                PrintString1 arrPlayer(iPlayerLeft).y, arrPlayer(iPlayerLeft).x, arrPlayer(iPlayerLeft).char
                            ElseIf arrPlayer(iPlayerLeft).IsFound = 2 Then
                                arrPlayer(iPlayerRight).x = iLoopX
                                arrPlayer(iPlayerRight).y = iLoopY
                                arrPlayer(iPlayerRight).new_x = iLoopX
                                arrPlayer(iPlayerRight).new_y = iLoopY
                                Color arrPlayer(iPlayerRight).fgColor, arrPlayer(iPlayerRight).bgColor
                                PrintString1 arrPlayer(iPlayerRight).y, arrPlayer(iPlayerRight).x, arrPlayer(iPlayerRight).char
                            Else
                                Color bgColor, bgColor
                                PrintString1 iLoopY, iLoopX, " "
                            End If
                        Else
                            Color bgColor, bgColor
                            PrintString1 iLoopY, iLoopX, " "
                        End If
                    ElseIf arrMap(iLoopY, iLoopX) = "." Or arrMap(iLoopY, iLoopX) = " " Then
                        Color bgColor, bgColor
                        PrintString1 iLoopY, iLoopX, " "
                        'ELSEIF InStr("abcdefghijklmnopqrstuvwxyz1234567890", lcase$(arrMap(iLoopY, iLoopX))) > 0 THEN
                    Else
                        Color cWhite, bgColor
                        PrintString1 iLoopY, iLoopX, arrMap(iLoopY, iLoopX)
                    End If
                Next iLoopX
            Next iLoopY

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' BEGIN SHOW TITLE / SCORE / INSTRUCTIONS
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' TITLE
            Color cRed, cWhite
            PrintString1 1, 1, left$( "" + _
                "   Footrace 2! by Softintheheadware, 2005-2022" + _
                STRING$(iCols, " ") + _
                "", iCols)

            '' HOW TO EXIT
            'Color bgColor, cWhite
            'sMessage = "Press <ESC> to quit."
            'PrintString1 1, (iCols - len(sMessage)) - 2, sMessage

            ' NOTE: We have 128 text columns at 1024x768
            'Print "Player#  Input      Device#  Type     Code             Value"
            'PrintString1 3,3, "PLAYER  SCORE"
            'PrintString1 3,3, "PLAYER  SCORE  INPUT            DEVICE#  TYPE     CODE             VALUE"

            ' HEADER ROW
            iPos = 3: iCol1 = iPos
            sNext = "PLAYER  ": iLen1 = Len(sNext)
            Color bgColor, cLightGray
            PrintString1 3, iPos, sNext

            iPos = iPos + Len(sNext): iCol2 = iPos
            sNext = "SCORE  ": iLen2 = Len(sNext)
            Color bgColor, cDarkGray
            PrintString1 3, iPos, sNext

            iPos = iPos + Len(sNext): iCol3 = iPos
            sNext = Left$("LEFT UP/DOWN/LEFT/RIGHT" + String$(55, " "), 55): iLen3 = Len(sNext)
            Color bgColor, cLightGray
            PrintString1 3, iPos, sNext

            iPos = iPos + Len(sNext): iCol4 = iPos
            sNext = Left$("RIGHT UP/DOWN/LEFT/RIGHT" + String$(55, " "), 55): iLen4 = Len(sNext)
            Color bgColor, cDarkGray
            PrintString1 3, iPos, sNext

            ' SCORE + INSTRUCTIONS FOR EACH PLAYER
            For iPlayerLoop = 0 To 3
                ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                iPlayerLeft = (iPlayerLoop * 2) + 1
                iPlayerRight = iPlayerLeft + 1

                ' SHOW IN PLAYER'S COLOR
                Color arrPlayer(iPlayerLeft).fgColor, arrPlayer(iPlayerLeft).bgColor

                ' PLAYER #
                sMessage = cstr$(iPlayerLoop + 1) + String$(iLen1, " ")
                sMessage = Left$(sMessage, iLen1)
                PrintString1 4 + iPlayerLoop, iCol1, sMessage

                ' SHOW PLAYER SCORE
                sMessage = cstr$(arrPlayer(iPlayerLeft).score + arrPlayer(iPlayerRight).score)
                sMessage = String$(iLen2, " ") + sMessage + String$(2, " ")
                sMessage = Right$(sMessage, iLen2)
                PrintString1 4 + iPlayerLoop, iCol2, sMessage

                ' SHOW CONTROLS FOR LEFT FOOT
                sMessage = ""
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveUp + "/"
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveDown + "/"
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveLeft + "/"
                sMessage = sMessage + arrPlayer(iPlayerLeft).instructMoveRight
                sMessage = sMessage + String$(iLen3, " ")
                sMessage = Left$(sMessage, iLen3)
                PrintString1 4 + iPlayerLoop, iCol3, sMessage

                ' SHOW CONTROLS FOR RIGHT FOOT
                sMessage = ""
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveUp + "/"
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveDown + "/"
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveLeft + "/"
                sMessage = sMessage + arrPlayer(iPlayerRight).instructMoveRight
                sMessage = sMessage + String$(iLen4, " ")
                sMessage = Left$(sMessage, iLen4)
                PrintString1 4 + iPlayerLoop, iCol4, sMessage
            Next iPlayerLoop
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' END SHOW TITLE / SCORE / INSTRUCTIONS
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

            ' ================================================================================================================================================================
            ' BEGIN CURRENT ROUND
            ' ================================================================================================================================================================

            ' DO COUNTDOWN
            ' TODO: how do we stop it from printing the next number before the previous sounds finished playing? "mf" is not really doing it...

            Color cRed, bgColor
            sMessage = Left$("3..." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 9, 3, sMessage
            Play "mfT120v50L4n24L4v0n24mf"

            PauseDecisecond 5

            Color cOrange, bgColor
            sMessage = Left$("2..." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 9, 3, sMessage
            Play "mfT120v50L4n24L4v0n24"

            PauseDecisecond 5

            Color cYellow, bgColor
            sMessage = Left$("1..." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 9, 3, sMessage
            Play "mfT120v50L4n24L4v0n24"

            PauseDecisecond 5

            Color cLime, bgColor
            sMessage = Left$("GO!" + String$(iCols - 4, " "), iCols - 4)
            PrintString1 9, 3, sMessage
            'Play "mbT160L1v50n36T120"
            Play "mfT160L1v50n36T120"

            PauseDecisecond 5

            ' HOW TO EXIT
            Color cCyan, bgColor
            sMessage = Left$("Press <ESC> to quit." + String$(iCols - 4, " "), iCols - 4)
            PrintString1 9, 3, sMessage

            Do ' LOOP UNTIL ( _KEYDOWN(c_KeyDown_Esc) OR (iWinnerCount > 0) )

                ' -----------------------------------------------------------------------------
                ' Clear control buffer for players
                For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                    arrPlayer(iPlayer).moveUp = FALSE
                    arrPlayer(iPlayer).moveDown = FALSE
                    arrPlayer(iPlayer).moveLeft = FALSE
                    arrPlayer(iPlayer).moveRight = FALSE
                    arrPlayer(iPlayer).button1 = FALSE
                    arrPlayer(iPlayer).button2 = FALSE
                    arrPlayer(iPlayer).button3 = FALSE
                    arrPlayer(iPlayer).button4 = FALSE
                Next iPlayer

                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR CONTROLLER INPUT
                If iNumControllers > 0 Then
                    For iController = 1 To iNumControllers
                        iDevice = iController + 2

                        ' Check all devices
                        While _DeviceInput(iDevice)
                        Wend ' clear and update the device buffer

                        ' Check each button
                        For iLoop = 1 To _LastButton(iDevice)
                            If (iLoop > cMaxButtons) Then Exit For

                            ' update button array to indicate if a button is up or down currently.
                            'if TRUE=TRUE then
                            If _ButtonChange(iLoop) Then
                                iValue = _Button(iLoop)
                                If iValue <> arrButton(iController, iLoop) Then
                                    ' *****************************************************************************
                                    ' PRESSED BUTTON

                                    ' BEGIN find who this is mapped for
                                    bFoundWho = FALSE
                                    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                                        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                            If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                                If m_arrControlMap(iPlayer, iWhichInput).typ = cInputButton Then
                                                    If m_arrControlMap(iPlayer, iWhichInput).code = iLoop Then
                                                        'if m_arrControlMap(iPlayer, iWhichInput).value = iValue then
                                                        bFoundWho = TRUE
                                                        Select Case iWhichInput
                                                            Case cInputUp:
                                                                arrPlayer(iPlayer).moveUp = TRUE
                                                            Case cInputDown:
                                                                arrPlayer(iPlayer).moveDown = TRUE
                                                            Case cInputLeft:
                                                                arrPlayer(iPlayer).moveLeft = TRUE
                                                            Case cInputRight:
                                                                arrPlayer(iPlayer).moveRight = TRUE
                                                            Case cInputButton1:
                                                                arrPlayer(iPlayer).button1 = TRUE
                                                            Case cInputButton2:
                                                                arrPlayer(iPlayer).button2 = TRUE
                                                            Case cInputButton3:
                                                                arrPlayer(iPlayer).button3 = TRUE
                                                            Case cInputButton4:
                                                                arrPlayer(iPlayer).button4 = TRUE
                                                            Case Else:
                                                                '(IGNORE)
                                                        End Select
                                                        Exit For
                                                        'end if
                                                    End If
                                                End If
                                            End If
                                        Next iWhichInput
                                        If bFoundWho = TRUE Then Exit For
                                    Next iPlayer
                                    ' END find who this is mapped for

                                End If
                            End If
                        Next iLoop

                        ' Check each axis
                        For iLoop = 1 To _LastAxis(iDevice)
                            If (iLoop > cMaxAxis) Then Exit For
                            dblNextAxis = _Axis(iLoop)
                            dblNextAxis = RoundUpDouble#(dblNextAxis, 3)

                            ' I like to give a little "jiggle" resistance to my controls, as I have an old joystick
                            ' which is prone to always give minute values and never really center on true 0.
                            ' A value of 1 means my axis is pushed fully in one direction.
                            ' A value greater than 0.1 means it's been partially pushed in a direction (such as at a 45 degree diagional angle).
                            ' A value of less than 0.1 means we count it as being centered. (As if it was 0.)

                            ' Set sensitivity:
                            'These are way too sensitive for analog:
                            'IF ABS(_AXIS(iLoop)) <= 1 AND ABS(_AXIS(iLoop)) >= .1 THEN
                            'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .01 THEN
                            'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .001 THEN
                            ''For digital input, we'll use a big picture:
                            'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= 0.75 THEN
                            If Abs(dblNextAxis) <= 1 And Abs(dblNextAxis) >= 0.5 Then

                                ' WE WANT CONTINUOUS MOVEMENT (DISABLE FOR NOT)
                                'if TRUE=TRUE then
                                If dblNextAxis <> arrAxis(iController, iLoop) Then
                                    ' *****************************************************************************
                                    ' MOVED STICK

                                    ' convert to a digital value
                                    If dblNextAxis < 0 Then
                                        iValue = -1
                                    Else
                                        iValue = 1
                                    End If

                                    ' BEGIN find who this is mapped for
                                    bFoundWho = FALSE
                                    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                                        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                            If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                                If m_arrControlMap(iPlayer, iWhichInput).typ = cInputAxis Then
                                                    If m_arrControlMap(iPlayer, iWhichInput).code = iLoop Then
                                                        If m_arrControlMap(iPlayer, iWhichInput).value = iValue Then
                                                            bFoundWho = TRUE
                                                            Select Case iWhichInput
                                                                Case cInputUp:
                                                                    arrPlayer(iPlayer).moveUp = TRUE
                                                                Case cInputDown:
                                                                    arrPlayer(iPlayer).moveDown = TRUE
                                                                Case cInputLeft:
                                                                    arrPlayer(iPlayer).moveLeft = TRUE
                                                                Case cInputRight:
                                                                    arrPlayer(iPlayer).moveRight = TRUE
                                                                Case cInputButton1:
                                                                    arrPlayer(iPlayer).button1 = TRUE
                                                                Case cInputButton2:
                                                                    arrPlayer(iPlayer).button2 = TRUE
                                                                Case cInputButton3:
                                                                    arrPlayer(iPlayer).button3 = TRUE
                                                                Case cInputButton4:
                                                                    arrPlayer(iPlayer).button4 = TRUE
                                                                Case Else:
                                                                    '(IGNORE)
                                                            End Select
                                                            Exit For
                                                        End If
                                                    End If
                                                End If
                                            End If
                                        Next iWhichInput
                                        If bFoundWho = TRUE Then Exit For
                                    Next iPlayer
                                    ' END find who this is mapped for

                                End If
                            End If
                        Next iLoop

                    Next iController
                End If
                ' END CHECK FOR CONTROLLER INPUT
                ' -----------------------------------------------------------------------------

                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR KEYBOARD INPUT #1
                '_KEYCLEAR: _DELAY 1
                While _DeviceInput(1): Wend ' clear and update the keyboard buffer

                ' Detect changed key state
                iDevice = 1 ' keyboard
                For iLoop = LBound(m_arrButtonCode) To UBound(m_arrButtonCode)
                    iCode = m_arrButtonCode(iLoop)
                    If _Button(iCode) <> FALSE Then
                        ' *****************************************************************************
                        ' PRESSED KEYBOARD
                        'PRINT "PRESSED " + m_arrButtonKey(iLoop)

                        ' BEGIN find who this is mapped for
                        bFoundWho = FALSE
                        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                    If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                                        'if m_arrControlMap(iPlayer, iWhichInput).code = iLoop then
                                        If m_arrControlMap(iPlayer, iWhichInput).code = iCode Then
                                            'if m_arrControlMap(iPlayer, iWhichInput).value = iValue then
                                            bFoundWho = TRUE
                                            Select Case iWhichInput
                                                Case cInputUp:
                                                    arrPlayer(iPlayer).moveUp = TRUE
                                                Case cInputDown:
                                                    arrPlayer(iPlayer).moveDown = TRUE
                                                Case cInputLeft:
                                                    arrPlayer(iPlayer).moveLeft = TRUE
                                                Case cInputRight:
                                                    arrPlayer(iPlayer).moveRight = TRUE
                                                Case cInputButton1:
                                                    arrPlayer(iPlayer).button1 = TRUE
                                                Case cInputButton2:
                                                    arrPlayer(iPlayer).button2 = TRUE
                                                Case cInputButton3:
                                                    arrPlayer(iPlayer).button3 = TRUE
                                                Case cInputButton4:
                                                    arrPlayer(iPlayer).button4 = TRUE
                                                Case Else:
                                                    '(IGNORE)
                                            End Select
                                            Exit For
                                            'end if
                                        End If
                                    End If
                                End If
                            Next iWhichInput
                            If bFoundWho = TRUE Then Exit For
                        Next iPlayer
                        ' END find who this is mapped for

                    End If
                Next iLoop
                ' END CHECK FOR KEYBOARD INPUT #1
                ' -----------------------------------------------------------------------------

                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                ' BEGIN EVALUATE INPUT AND MOVE PLAYERS
                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

                For iPlayerLoop = 0 To 3
                    ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                    iPlayerLeft = (iPlayerLoop * 2) + 1
                    iPlayerRight = iPlayerLeft + 1

                    ' RESET MOVEMENT
                    bTryMove = FALSE
                    bDoMove = FALSE

                    ' PREVENT PLAYER FROM MOVING BOTH FEET AT ONCE!
                    If arrPlayer(iPlayerLeft).moveUp = TRUE And arrPlayer(iPlayerRight).moveUp = TRUE Then
                        arrPlayer(iPlayerLeft).moveUp = FALSE
                        arrPlayer(iPlayerRight).moveUp = FALSE
                    End If
                    If arrPlayer(iPlayerLeft).moveDown = TRUE And arrPlayer(iPlayerRight).moveDown = TRUE Then
                        arrPlayer(iPlayerLeft).moveDown = FALSE
                        arrPlayer(iPlayerRight).moveDown = FALSE
                    End If
                    If arrPlayer(iPlayerLeft).moveLeft = TRUE And arrPlayer(iPlayerRight).moveLeft = TRUE Then
                        arrPlayer(iPlayerLeft).moveLeft = FALSE
                        arrPlayer(iPlayerRight).moveLeft = FALSE
                    End If
                    If arrPlayer(iPlayerLeft).moveRight = TRUE And arrPlayer(iPlayerRight).moveRight = TRUE Then
                        arrPlayer(iPlayerLeft).moveRight = FALSE
                        arrPlayer(iPlayerRight).moveRight = FALSE
                    End If

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PROCESS LEFT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ****************************************************************************************************
                    ' I'm sure this logic could be simplified with some kind of logic table!
                    ' ****************************************************************************************************
                    If arrPlayer(iPlayerLeft).moveLeft = TRUE Then

                        ' STICK #1 LEFT
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    'DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    'arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerLeft).x
                                    'arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y - 1
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    'arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerLeft).x
                                    'arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerRight).x
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf arrPlayer(iPlayerLeft).moveRight = TRUE Then
                        ' STICK #1 RIGHT
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    'arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerRight).x
                                    'arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerLeft).x
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf arrPlayer(iPlayerLeft).moveUp = TRUE Then
                        ' STICK #1 UP
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    ElseIf arrPlayer(iPlayerLeft).moveDown = TRUE Then
                        ' STICK #1 DOWN
                        If arrPlayer(iPlayerLeft).IsReady = TRUE Then
                            arrPlayer(iPlayerLeft).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    Else
                        arrPlayer(iPlayerLeft).IsReady = TRUE
                    End If

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PROCESS LEFT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' BEGIN PROCESS RIGHT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ****************************************************************************************************
                    ' I'm sure this logic could be simplified with some kind of logic table!
                    ' ****************************************************************************************************

                    If arrPlayer(iPlayerRight).moveLeft = TRUE Then

                        ' STICK #1 LEFT
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x - 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf arrPlayer(iPlayerRight).moveRight = TRUE Then
                        ' STICK #1 RIGHT
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x + 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf arrPlayer(iPlayerRight).moveUp = TRUE Then
                        ' STICK #1 UP
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    ElseIf arrPlayer(iPlayerRight).moveDown = TRUE Then
                        ' STICK #1 DOWN
                        If arrPlayer(iPlayerRight).IsReady = TRUE Then
                            arrPlayer(iPlayerRight).IsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLeft).x < arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLeft).x > arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerRight).y Then
                                    arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y < arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerRight).x Then
                                If arrPlayer(iPlayerLeft).y > arrPlayer(iPlayerRight).y Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    Else
                        arrPlayer(iPlayerRight).IsReady = TRUE
                    End If
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    ' END PROCESS RIGHT FOOT INPUT
                    ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                    ' DID THE PLAYER TRY TO MOVE? SEE IF ANYTHING IS IN THE WAY

                    If bTryMove = TRUE Then
                        bDoMove = TRUE

                        ' IS PLAYER'S LEFT FOOT HITTING A WALL?
                        If arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x) <> "#" Then
                            ' IS PLAYER'S RIGHT FOOT HITTING A WALL?
                            If arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x) <> "#" Then

                                ' IS PLAYER HITTING ANOTHER PLAYER?
                                For iOtherLoop = 1 To 8

                                    ' IS PLAYER'S LEFT FOOT STEPPING ON ANOTHER PLAYER'S FOOT?
                                    If iOtherLoop <> iPlayerLeft Then
                                        If arrPlayer(iPlayerLeft).new_y = arrPlayer(iOtherLoop).y Then
                                            If arrPlayer(iPlayerLeft).new_x = arrPlayer(iOtherLoop).x Then
                                                ' COLLISION, DON'T MOVE
                                                bDoMove = FALSE
                                                BumpSound 2 'iPlayerLoop+1
                                                Exit For
                                            End If
                                        End If
                                    End If

                                    ' IS PLAYER'S RIGHT FOOT STEPPING ON ANOTHER PLAYER'S FOOT?
                                    If iOtherLoop <> iPlayerRight Then
                                        If arrPlayer(iPlayerRight).new_y = arrPlayer(iOtherLoop).y Then
                                            If arrPlayer(iPlayerRight).new_x = arrPlayer(iOtherLoop).x Then
                                                ' COLLISION, DON'T MOVE
                                                bDoMove = FALSE
                                                BumpSound 2 'iPlayerLoop+1
                                                Exit For
                                            End If
                                        End If
                                    End If
                                Next iOtherLoop
                            Else
                                ' COLLISION, DON'T MOVE
                                bDoMove = FALSE
                                BumpSound 1 'iPlayerLoop+1
                            End If
                        Else
                            ' COLLISION, DON'T MOVE
                            bDoMove = FALSE
                            BumpSound 1 'iPlayerLoop+1
                        End If

                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' MOVE OR DON'T MOVE

                        If bDoMove = TRUE Then
                            ' DID PLAYER CROSS THE FINISH LINE?
                            If arrMap(arrPlayer(iPlayerLeft).new_y, arrPlayer(iPlayerLeft).new_x) = "-" Then
                                'iWinner = iPlayerLeft
                                'bHaveWinner = TRUE
                                iWinnerCount = iWinnerCount + 1
                                arrPlayer(iPlayerLeft).IsWinner = TRUE
                            ElseIf arrMap(arrPlayer(iPlayerRight).new_y, arrPlayer(iPlayerRight).new_x) = "-" Then
                                'iWinner = iPlayerRight
                                'bHaveWinner = TRUE
                                iWinnerCount = iWinnerCount + 1
                                arrPlayer(iPlayerRight).IsWinner = TRUE
                            Else
                                WalkingSound iPlayerLoop + 1
                            End If

                            ' MOVE THE PLAYER IF THEY ARE NOT BLOCKED
                            If (arrPlayer(iPlayerLeft).x <> arrPlayer(iPlayerLeft).new_x) Or (arrPlayer(iPlayerLeft).y <> arrPlayer(iPlayerLeft).new_y) Then
                                Color bgColor, bgColor
                                PrintString1 arrPlayer(iPlayerLeft).y, arrPlayer(iPlayerLeft).x, " "

                                arrPlayer(iPlayerLeft).y = arrPlayer(iPlayerLeft).new_y
                                arrPlayer(iPlayerLeft).x = arrPlayer(iPlayerLeft).new_x

                                Color arrPlayer(iPlayerLeft).fgColor, arrPlayer(iPlayerLeft).bgColor
                                PrintString1 arrPlayer(iPlayerLeft).y, arrPlayer(iPlayerLeft).x, arrPlayer(iPlayerLeft).char
                            End If
                            If (arrPlayer(iPlayerRight).x <> arrPlayer(iPlayerRight).new_x) Or (arrPlayer(iPlayerRight).y <> arrPlayer(iPlayerRight).new_y) Then
                                Color bgColor, bgColor
                                PrintString1 arrPlayer(iPlayerRight).y, arrPlayer(iPlayerRight).x, " "

                                arrPlayer(iPlayerRight).y = arrPlayer(iPlayerRight).new_y
                                arrPlayer(iPlayerRight).x = arrPlayer(iPlayerRight).new_x

                                Color arrPlayer(iPlayerRight).fgColor, arrPlayer(iPlayerRight).bgColor
                                PrintString1 arrPlayer(iPlayerRight).y, arrPlayer(iPlayerRight).x, arrPlayer(iPlayerRight).char
                            End If

                            'LOCATE 5,1: PRINT "Press <ESC> to quit.";
                        Else
                            ' REVERT NEW COORDS TO THE OLD COORDS
                            arrPlayer(iPlayerLeft).new_x = arrPlayer(iPlayerLeft).x
                            arrPlayer(iPlayerLeft).new_y = arrPlayer(iPlayerLeft).y
                            arrPlayer(iPlayerRight).new_x = arrPlayer(iPlayerRight).x
                            arrPlayer(iPlayerRight).new_y = arrPlayer(iPlayerRight).y
                        End If

                    End If
                    ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

                    'IF _BUTTON(arrKeyMap(iPlayerLoop, c_Map_Button)) THEN ' BUTTON KEY IS CURRENTLY DOWN
                    '    'SOUND arrSound(iPlayerLoop), .75
                    'END IF

                Next iPlayerLoop

                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                ' END EVALUATE INPUT AND MOVE PLAYERS
                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

                _Limit 100 ' keep loop at 100 frames per second
            Loop Until (_KeyDown(c_KeyDown_Esc) Or (iWinnerCount > 0)) ' leave loop when ESC key pressed
            ' ================================================================================================================================================================
            ' END CURRENT ROUND
            ' ================================================================================================================================================================

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' BEGIN DID ANYONE WIN OR DID THEY JUST QUIT?
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            If iWinnerCount > 0 Then
                ' play winner's song
                SuccessTune1

                ' check each player (in case of a tie)
                sMessage = ""
                For iPlayerLoop = 0 To 3
                    ' GET INDEX OF NEXT PLAYER LEFT/RIGHT
                    iPlayerLeft = (iPlayerLoop * 2) + 1
                    iPlayerRight = iPlayerLeft + 1

                    ' SCORE SEPARATELY FOR LEFT/RIGHT FEET,
                    ' MAYBE WE CAN USE IT AS A FUN STATISTIC LATER!
                    If arrPlayer(iPlayerLeft).IsWinner = TRUE Then
                        arrPlayer(iPlayerLeft).score = arrPlayer(iPlayerLeft).score + 1
                        sMessage = sMessage + IIFSTR$(Len(sMessage) = 0, "", " AND ") + cstr$(iPlayerLoop + 1)
                    ElseIf arrPlayer(iPlayerRight).IsWinner = TRUE Then
                        arrPlayer(iPlayerRight).score = arrPlayer(iPlayerRight).score + 1
                        sMessage = sMessage + IIFSTR$(Len(sMessage) = 0, "", " AND ") + cstr$(iPlayerLoop + 1)
                    End If
                Next iPlayerLoop

                If iWinnerCount = 1 Then
                    sMessage = "PLAYER " + sMessage + " WINS! "
                Else
                    sMessage = "IT'S A TIE BETWEEN PLAYERS " + sMessage + "! "
                End If

                Color cCyan, bgColor
                PrintString1 9, 3, sMessage + " Play again (Y / N) ?"
                bFinished = FALSE
                Do ' LOOP UNTIL bFinished
                    If _KeyDown(c_KeyDown_Y) Then
                        bFinished = TRUE
                    ElseIf _KeyDown(c_KeyDown_N) Then
                        ' NOPE, THEY QUIT -> SET FLAG TO EXIT GAME
                        bPlaying = FALSE
                        bFinished = TRUE
                    End If

                    _Limit 100 ' keep loop at 100 frames per second
                Loop Until bFinished ' leave loop when ESC key pressed
            Else
                ' NOPE, THEY QUIT -> SET FLAG TO EXIT GAME
                bPlaying = FALSE
            End If
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' END DID ANYONE WIN?
            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------

        Loop Until (bPlaying = FALSE)
        ' BEGIN MAIN GAME LOOP
        ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

    End If
    ' END GAME LOGIC
    ' ================================================================================================================================================================

    ' HANDLE ERRORS
    If Len(sError) > 0 Then
        'iLen = 40 - LEN(sError): sMessage = sError + STRING$(iLen, " ")
        'Color cCyan, bgColor
        'PrintString1 1, 1, sMessage
        ''LOCATE 3,1: WaitForEnter
        'PrintString1 3, 1, "Press <ENTER> to continue"
        'Sleep

        ' JUST RETURN THE ERROR TEXT TO THE CALLING ROUTINE
        sResult = sError
    End If

    ' -----------------------------------------------------------------------------
    ' FREE MEMORY
    Screen 0
    If imgScreen& < -1 Or imgScreen& > 0 Then _FreeImage imgScreen&

    ' -----------------------------------------------------------------------------
    ' RESET AND EXIT
    _KeyClear: _Delay 1
    Footrace2$ = sResult
End Function ' Footrace2$

' ################################################################################################################################################################
' END FOOTRACE 2
' ################################################################################################################################################################


' ################################################################################################################################################################
' BEGIN TEST 8X8 COLOR FONT
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' BASED ON DetectPixelTest3, ReShrinkImage$

Function CustomColorFontTest1$
    ' -----------------------------------------------------------------------------
    ' DECLARATIONS
    Dim sResult As String

    Dim imgScreen&
    Dim imgBackground&
    Dim imgCharset&
    Dim iX As Integer
    Dim iY As Integer
    Dim iOffsetX As Integer
    Dim iOffSetY As Integer
    Dim iTileNum As Integer
    Dim MyString As String
    Dim iLoop1 As Integer
    Dim iForeColor As Integer
    Dim iBackColor As Integer
    Dim fgColor As _Unsigned Long
    Dim bgColor As _Unsigned Long
    Dim bHaveForeColor As Integer
    Dim bHaveBackColor As Integer
    Dim iPos1 As Integer
    ReDim arrColor(-1) As ColorType
    Dim iCols As Integer
    Dim iRows As Integer
    Dim bFinished As Integer

    ' -----------------------------------------------------------------------------
    ' INITIALIZE

    ' LOAD BACKGROUND IMAGE
    imgBackground& = _NewImage(1024, 768, 32)
    Screen imgBackground&
    Cls , cBlack ' set the background color

    ' COPY BACKGROUND TO SCREEN
    imgScreen& = _CopyImage(imgBackground&, 32)

    ' LOAD TEXT FONT (16 cols x 16 rows of 8x8 tiles)
    sFile$ = m_ProgramPath$ + "Font_8x8_#1_128x128.png" ' 128x128 total, 16x16 of 8x8 tiles
    imgCharset& = _LoadImage(sFile$, 32)

    ' DISPLAY SCREEN
    Screen imgScreen&

    ' -----------------------------------------------------------------------------
    ' PLOT TO SCREEN
    'iCols = _Width(0) \ _FontWidth
    'iRows = _Height(0) \ _FontHeight
    iCols = _Width(0) \ 8
    iRows = _Height(0) \ 8

    DebugPrint "iCols = " + cstr$(iCols)
    DebugPrint "iRows = " + cstr$(iRows)

    MyString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()-=_+[]{}\|;:'" + Chr$(34) + ",./<>?`~"
    AddColors arrColor()
    iOffsetX = 0
    iOffSetY = 0
    iForeColor = LBound(arrColor)
    iBackColor = LBound(arrColor)
    'iPos1 = 0
    iY = -1
    iX = -1
    iTileNum = 32
    bHaveBackColor = TRUE
    bFinished = FALSE
    Do
        iX = iX + 1
        If iX >= iCols Then
            iX = 0
            iY = iY + 1
            If iY >= iRows Then bFinished = TRUE
        End If
        If bFinished = FALSE Then
            ' GET TILE
            'iPos1 = iPos1 + 1
            'If iPos1 > Len(MyString) Then iPos1 = 1
            'iTileNum = Asc(Mid$(MyString, iPos1, 1))
            iTileNum = iTileNum + 1
            If iTileNum > 255 Then iTileNum = 33

            ' GET FORE COLOR
            bHaveForeColor = FALSE
            Do
                iForeColor = iForeColor + 1
                If iForeColor > UBound(arrColor) Then
                    iForeColor = LBound(arrColor)
                    bHaveBackColor = FALSE
                End If
                If iForeColor <> iBackColor Then
                    If arrColor(iForeColor).value <> cEmpty Then
                        bHaveForeColor = TRUE
                    End If
                End If
            Loop Until bHaveForeColor = TRUE

            ' GET BACK COLOR
            If bHaveBackColor = FALSE Then
                Do
                    iBackColor = iBackColor + 1
                    If iBackColor > UBound(arrColor) Then
                        'bFinished = TRUE
                        'Exit Do
                        iBackColor = LBound(arrColor)
                    End If
                    If iBackColor <> iForeColor Then
                        'If arrColor(iBackColor).value <> cEmpty Then
                        bHaveBackColor = TRUE
                        'End If
                    End If
                Loop Until bHaveBackColor = TRUE
            End If

            ' DRAW TILE
            If bFinished = FALSE Then
                'DebugPrint _
                '    "Tile " + _Trim$(Str$(iTileNum)) + " " + _
                '    "at (" + _Trim$(Str$(iX)) + "," + _Trim$(Str$(iY)) + ") " + _
                '    "fgcolor = " + arrColor(iForeColor).name + " " + _
                '    "bgcolor = " + arrColor(iBackColor).name

                DrawColorTile imgScreen&, imgCharset&, iTileNum, _
                    arrColor(iForeColor).value, arrColor(iBackColor).value, _
                    iX, iY, iOffsetX, iOffsetY
            End If
        End If
    Loop Until bFinished = TRUE

    If TRUE = FALSE Then
        iTileNum = Asc("#")
        fgColor = cWhite
        For iX = 0 To iCols - 1
            bgColor = cBlue
        iY = 0: DrawColorTile imgScreen&, imgCharset&, iTileNum, _
                    fgColor, bgColor, _
                    iX, iY, iOffsetX, iOffsetY
            bgColor = cRed
        iY = iRows-1: DrawColorTile imgScreen&, imgCharset&, iTileNum, _
                    fgColor, bgColor, _
                    iX, iY, iOffsetX, iOffsetY
        Next iX
        For iY = 0 To iRows - 1
            bgColor = cYellow
        iX = 0: DrawColorTile imgScreen&, imgCharset&, iTileNum, _
                    fgColor, bgColor, _
                    iX, iY, iOffsetX, iOffsetY
            bgColor = cLime
        iX = iCols-1: DrawColorTile imgScreen&, imgCharset&, iTileNum, _
                    fgColor, bgColor, _
                    iX, iY, iOffsetX, iOffsetY
        Next iY
    End If

    ' -----------------------------------------------------------------------------
    ' UPDATE SCREEN
    _Display ' update screen with changes

    ' -----------------------------------------------------------------------------
    ' DONE
    Locate 10, 10
    'Input "Press ENTER to continue"; in$
    Sleep

    ' -----------------------------------------------------------------------------
    ' FREE MEMORY
    Screen 0
    If imgScreen& < -1 Or imgScreen& > 0 Then _FreeImage imgScreen&
    If imgBackground& < -1 Or imgBackground& > 0 Then _FreeImage imgBackground&
    If imgCharset& < -1 Or imgCharset& > 0 Then _FreeImage imgCharset&

    ' -----------------------------------------------------------------------------
    ' RETURN RESULT
    CustomColorFontTest1 = ""
End Function ' CustomColorFontTest1$

' ################################################################################################################################################################
' END TEST 8X8 COLOR FONT
' ################################################################################################################################################################



' ################################################################################################################################################################
' BEGIN GRAPHIC TILE FUNCTIONS
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Draw entire array on screen.

Sub PlotTiles (arrTiles() As Integer, imgTiles&, imgScreen&)
    Dim dx%
    Dim dy%
    Dim TileNum%

    Screen imgScreen&

    For dx% = 1 To UBound(arrTiles, 1)
        For dy% = 1 To UBound(arrTiles, 2)
            TileNum% = arrTiles(dx%, dy%)
            DrawTile imgTiles&, TileNum%, imgScreen&, dx% - 1, dy% - 1
        Next dy%
    Next dx%

    '_Display ' update screen with changes
End Sub ' PlotTiles

' /////////////////////////////////////////////////////////////////////////////
' DIV and MOD:
' c% = a% \ b% ' DIV (INTEGER DIVISION)
' d% = a% MOD b% ' MODULO (DIVISION REMAINDER)

'tw% = tile width/height (in pixels)

Sub DrawTile (imgTiles&, TileNum%, imgScreen&, dx%, dy%)
    '_PUTIMAGE (0, 0), i ' places image at upper left corner of window w/o stretching it
    '_PUTIMAGE (dx1, dy1), sourceHandle&, destHandle&, (sx1, sy1)-(sx2, sy2) ' portion of source to the top-left corner of the destination page
    '_PUTIMAGE (64,  128), imgTiles&,      imgScreen&,   (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page
    '_PutImage (64, 128), imgTiles&, imgScreen&, (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page

    ' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
    cols% = 16
    rows% = 16

    ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    sc% = TileNum% Mod rows%
    sr% = TileNum% \ rows%

    'Print "Tile#" + cstr$(TileNum%) + " at sc%=" + cstr$(sc%) + ",sr%=" + cstr$(sr%)

    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
    'sx1% = sc% * tw%
    sx1% = sc% * 32

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    'sy1% = sr% * tw%
    sy1% = sr% * 32

    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
    'sx2% = sx1% + (tw% - 1)
    sx2% = sx1% + 31

    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
    'sy2% = sy1% + (tw% - 1)
    sy2% = sy1% + 31

    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
    'xDest% = dx% * tw%
    xDest% = dx% * 32

    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
    'yDest% = (dy% * tw%) + 64
    yDest% = (dy% * 32) + 64

    'Print "Tile#" + cstr$(TileNum%) + " at r" + cstr$(sr%) + "c" + cstr$(sc%) + " pixel location r" + cstr$(sy1%) + "c" + cstr$(sx1%) + " through r" + cstr$(sy2%) + "c" + cstr$(sx2%)

    _Dest imgScreen&
    _PutImage (xDest%, yDest%), imgTiles&, imgScreen&, (sx1%, sy1%)-(sx2%, sy2%) ' portion of source to the top-left corner of the destination page

End Sub ' DrawTile

' ################################################################################################################################################################
' END GRAPHIC TILE FUNCTIONS
' ################################################################################################################################################################


' ################################################################################################################################################################
' BEGIN TILE DEFINITIONS
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Function GetTiles$ (imgTiles&, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    Dim RoutineName As String: RoutineName = "GetTiles$"
    Dim sResult As String: sResult = ""
    ReDim arrTileText(0 To 255) As String

    Dim iTileNum As Integer

    ReDim arrLines(-1) As String
    Dim iFromX As Integer
    Dim iFromY As Integer
    Dim sLine As String
    Dim sChar As String

    Dim iTileX As Integer
    Dim iTileY As Integer
    Dim iToX As Integer
    Dim iToY As Integer
    Dim pixelColor As _Unsigned Long
    Dim bFinished As Integer

    ' Do not try to free image handles currently being used as the active SCREEN. Change screen modes first.
    ' _DISPLAY turns off the auto refresh screen default _AUTODISPLAY behavior. Prevents screen flickering.
    If imgTiles& < -1 Or imgTiles& > 0 Then _FreeImage imgTiles&
    imgTiles& = _NewImage(128, 128, 32)
    '    Cls , cEmpty ' set the background color as transparent

    'Screen imgTiles&
    'Cls , bgColor ' set the background color as transparent
    _Dest imgTiles&
    'DrawRect 0, 0, 128, 128, cEmpty
    'DrawBox 0, 0, 128, cWhite
    Cls , cEmpty ' set the background color as transparent

    GetTileText arrTileText()
    iTileX = 0
    iTileY = 0
    bFinished = FALSE
    For iTileNum = 0 To 255
        split arrTileText(iTileNum), Chr$(13), arrLines()
        iToY = iTileY * 8
        If (iToY > _Height(imgTiles&)) Then
            sResult = "iToY value " + cstr$(iToY) + " " + _
                "exceeded image height " + cstr$(_Height(imgTiles&)) + ". " + _
                "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
            bFinished = TRUE
            Exit For
        End If

        For iFromY = LBound(arrLines) To UBound(arrLines)
            sLine = arrLines(iFromY)
            If Len(sLine) > 0 Then
                iToX = iTileX * 8
                For iFromX = 1 To Len(sLine)
                    sChar = Mid$(sLine, iFromX, 1)
                    If sChar = "." Then
                        pixelColor = bgColor ' cEmpty ' POINT(iFromX, iFromY)
                    Else
                        pixelColor = fgColor ' cBlack
                    End If
                    PSet (iToX, iToY), pixelColor
                    iToX = iToX + 1
                    If (iToX > _Width(imgTiles&)) Then
                        sResult = "iToX value " + cstr$(iToX) + " " + _
                            "exceeded image width " + cstr$(_Width(imgTiles&)) + ". " + _
                            "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
                        bFinished = TRUE
                        Exit For
                    End If
                Next iFromX
                iToY = iToY + 1
                If bFinished = TRUE Then Exit For
            End If
        Next iFromY
        If bFinished = TRUE Then Exit For

        iTileX = iTileX + 1
        If iTileX > 15 Then
            iTileX = 0
            iTileY = iTileY + 1
            'if iTileY > 15 then
            '    sResult = "Exceeded max 16 rows of tiles." + _
            '        "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
            '    bFinished = TRUE
            '    exit for
            'end if
        End If
    Next iTileNum

    GetTiles$ = sResult
End Function ' GetTiles$

' /////////////////////////////////////////////////////////////////////////////

Sub GetTileText (arrTileText() As String)
    ReDim arrTileText(0 To 255) As String

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(0) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(1) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(2) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(3) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(4) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(5) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(6) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(7) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(8) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(9) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(10) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(11) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(12) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(13) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(14) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(15) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(16) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(17) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(18) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(19) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(20) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(21) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(22) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(23) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(24) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(25) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(26) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(27) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(28) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(29) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(30) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(31) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(32) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(33) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(34) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(35) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(36) = m$

    m$ = ""
    m$ = m$ + ".22...2." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".2...22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(37) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + ".22..222" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(38) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(39) = m$

    m$ = ""
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(40) = m$

    m$ = ""
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(41) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(42) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(43) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(44) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(45) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(46) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(47) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".222.22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(48) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(49) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(50) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(51) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...2222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(52) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(53) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(54) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(55) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(56) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(57) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(58) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(59) = m$

    m$ = ""
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(60) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(61) = m$

    m$ = ""
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(62) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(63) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22...2." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(64) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(65) = m$

    m$ = ""
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(66) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(67) = m$

    m$ = ""
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(68) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(69) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(70) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(71) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(72) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(73) = m$

    m$ = ""
    m$ = m$ + "...2222." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(74) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(75) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(76) = m$

    m$ = ""
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".222.222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(77) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222.22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(78) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(79) = m$

    m$ = ""
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(80) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(81) = m$

    m$ = ""
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(82) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(83) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(84) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(85) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(86) = m$

    m$ = ""
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".222.222" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(87) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(88) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(89) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(90) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(91) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(92) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(93) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(94) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(95) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(96) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(97) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(98) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(99) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(100) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(101) = m$

    m$ = ""
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(102) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(103) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(104) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(105) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(106) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(107) = m$

    m$ = ""
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(108) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(109) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(110) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(111) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(112) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(113) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(114) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(115) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(116) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(117) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(118) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(119) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(120) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(121) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(122) = m$

    m$ = ""
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..2....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2....." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(123) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(124) = m$

    m$ = ""
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(125) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22....2" + Chr$(13)
    m$ = m$ + "2..2..2." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(126) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(127) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(128) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(129) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(130) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(131) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(132) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(133) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(134) = m$

    m$ = ""
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(135) = m$

    m$ = ""
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    arrTileText(136) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(137) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(138) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(139) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(140) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(141) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(142) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(143) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(144) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(145) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(146) = m$

    m$ = ""
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(147) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    arrTileText(148) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(149) = m$

    m$ = ""
    m$ = m$ + "22....22" + Chr$(13)
    m$ = m$ + "222..222" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "222..222" + Chr$(13)
    m$ = m$ + "22....22" + Chr$(13)
    arrTileText(150) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(151) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(152) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    arrTileText(153) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(154) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(155) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(156) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(157) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".222.22." + Chr$(13)
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(158) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..222222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".......2" + Chr$(13)
    arrTileText(159) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(160) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(161) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(162) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(163) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(164) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(165) = m$

    m$ = ""
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(166) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(167) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(168) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "2222222." + Chr$(13)
    m$ = m$ + "222222.." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "2......." + Chr$(13)
    arrTileText(169) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(170) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(171) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(172) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(173) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(174) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(175) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(176) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(177) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(178) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(179) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(180) = m$

    m$ = ""
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    arrTileText(181) = m$

    m$ = ""
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    arrTileText(182) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(183) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(184) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(185) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(186) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(187) = m$

    m$ = ""
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(188) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(189) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(190) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(191) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    arrTileText(192) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    arrTileText(193) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(194) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(195) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(196) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(197) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(198) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2.2222.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    arrTileText(199) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2222.2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    arrTileText(200) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(201) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(202) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(203) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(204) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(205) = m$

    m$ = ""
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    arrTileText(206) = m$

    m$ = ""
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    arrTileText(207) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(208) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(209) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(210) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(211) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(212) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(213) = m$

    m$ = ""
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(214) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(215) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(216) = m$

    m$ = ""
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    arrTileText(217) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(218) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(219) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(220) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(221) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(222) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(223) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(224) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(225) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(226) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(227) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(228) = m$

    m$ = ""
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    arrTileText(229) = m$

    m$ = ""
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    arrTileText(230) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(231) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(232) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(233) = m$

    m$ = ""
    m$ = m$ + ".......2" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(234) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(235) = m$

    m$ = ""
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(236) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(237) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(238) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(239) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(240) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(241) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(242) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(243) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "...2.2.." + Chr$(13)
    m$ = m$ + "..2...2." + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + "...2.2.." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(244) = m$

    m$ = ""
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + ".2..2..2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + "..2...2." + Chr$(13)
    m$ = m$ + "...2.2.." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(245) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(246) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "...2.2.." + Chr$(13)
    m$ = m$ + "..2...2." + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + "..2...2." + Chr$(13)
    m$ = m$ + "...2.2.." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(247) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "####.###" + Chr$(13)
    m$ = m$ + "###..###" + Chr$(13)
    m$ = m$ + "####.###" + Chr$(13)
    m$ = m$ + "####.###" + Chr$(13)
    m$ = m$ + "####.###" + Chr$(13)
    m$ = m$ + "###...##" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(248) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(249) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "###..###" + Chr$(13)
    m$ = m$ + "##.##.##" + Chr$(13)
    m$ = m$ + "#####.##" + Chr$(13)
    m$ = m$ + "####.###" + Chr$(13)
    m$ = m$ + "###.####" + Chr$(13)
    m$ = m$ + "##....##" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(250) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(251) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "#....###" + Chr$(13)
    m$ = m$ + "#####.##" + Chr$(13)
    m$ = m$ + "##...###" + Chr$(13)
    m$ = m$ + "#####.##" + Chr$(13)
    m$ = m$ + "#####.##" + Chr$(13)
    m$ = m$ + "#....###" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(252) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(253) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "#####.##" + Chr$(13)
    m$ = m$ + "####..##" + Chr$(13)
    m$ = m$ + "###.#.##" + Chr$(13)
    m$ = m$ + "##.##.##" + Chr$(13)
    m$ = m$ + "#......#" + Chr$(13)
    m$ = m$ + "#####.##" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(254) = m$

    m$ = ""
    m$ = m$ + ".######." + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + "########" + Chr$(13)
    m$ = m$ + ".######." + Chr$(13)
    arrTileText(255) = m$

End Sub ' GetTileText

' ################################################################################################################################################################
' END TILE DEFINITIONS
' ################################################################################################################################################################


' ################################################################################################################################################################
' BEGIN COLOR TEXT TILE FUNCTIONS
' ################################################################################################################################################################

'' /////////////////////////////////////////////////////////////////////////////
'' Like DrawColorTile but faster because it uses precalculated coordinates
'' to find the tile on the tile sheet, and the destination on the screen.
'
'' Receives:
'' imgScreen& = handle to screen to draw tile on
'' imgTiles& = handle to 16x16 tile sheet of 16x16 pixel tiles colored black (256 tiles)
'' arrTileSheetMap() = array of TileSheetMapType which holds precalculated positions of tiles on tilesheet
'' arrTileMap() = array of TileMapType which holds precalculated positions where tiles go on screen
'' tileWidthPx% = width of tiles in pixels
'' tileHeightPx% = height of tiles in pixels
'' TileNum% = ordinal number of tile on tile sheet to draw (0-255)
'' TileColor~& = color to use for tile
'' BackColor~& = color to use for background
'' dx% = column # to draw tile at (where each column is 16 pixels wide)
'' dy% = row # to draw tile at (where each row is 16 pixels high)
'
'' *** QUESTION
'' *** IF THE SUB RECEIVES IMAGE HANDLE PARAMETERS imgScreen&, imgTiles&
'' *** ARE THESE BY REFERENCE?
'' *** IF NOT, DO THESE LOCAL COPIES HAVE TO BE RELEASED WITH _FREEIMAGE ?
'
'' TODO: support transparency?
''       Colors returned are always opaque as the transparency value is always 255. Use _ALPHA or _CLEARCOLOR to change it.
'
''DrawColorTileFast imgScreen&, imgTiles&, arrTileSheet16Map(), arrTile16Map(), tileWidthPx%, tileHeightPx%, TileNum%, TileColor~&, BackColor~&, dx%, dy%
'
'Sub DrawColorTileFast (imgScreen&, imgTiles&, arrTileSheetMap() AS TileSheetMapType, arrTileMap() AS TileMapType, tileWidthPx%, tileHeightPx%, TileNum%, TileColor~&, BackColor~&, dx%, dy%)
'    DIM ColorSprite&
'    DIM UniversalSprite&
'
'    ' -----------------------------------------------------------------------------
'    ' PART 1: DRAW BACKGROUND COLOR
'    IF BackColor~& <> cEmpty& THEN
'
'        ' CREATE A TEMPORARY TILE
'        ColorSprite& = _NewImage(tileWidthPx%, tileHeightPx%, 32)
'        _Dest ColorSprite&
'
'        ' AND FILL IT WITH THE BACKGROUND COLOR
'        CLS, BackColor~&
'
'        ' COPY THE TEMPORARY BACKGROUND TILE TO THE SCREEN imgScreen&
'        _SOURCE ColorSprite&
'        _Dest imgScreen&
'
'        '_PUTIMAGE (0  , 0  ), sourceHandle& ' places image at upper left corner of window w/o stretching it
'        '_PUTIMAGE (dx1, dy1), sourceHandle&, destHandle&, (sx1, sy1)-(sx2, sy2) ' portion of source to the top-left corner of the destination page
'        '_PUTIMAGE (64,  128), imgTiles&,     imgScreen&,  (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page
'        '_PutImage (64,  128), imgTiles&,     imgScreen&,  (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page
'        _PutImage (arrTileMap(dx%, dy%).xPos, arrTileMap(dx%, dy%).yPos), ColorSprite&, imgScreen&, (0, 0)-(tileWidthPx% - 1, tileHeightPx% - 1) ' portion of source to the top-left corner of the destination page
'    END IF
'
'    ' -----------------------------------------------------------------------------
'    ' PART 2: DRAW FOREGROUND TILE IN SPECIFIED COLOR
'
'    ' CREATE A TEMPORARY TILE TO COLOR
'    UniversalSprite& = _NewImage(tileWidthPx%, tileHeightPx%, 32)
'
'    ' COPY THE SOURCE (MASK) TILE TO THE TEMPORARY ONE
'    _SOURCE imgTiles&
'    _Dest UniversalSprite&
'
'    '_PutImage(dx, dy)  sourceHandle&, destHandle&     , (sx1                             , sy1                             )-(sx2                           , sy2                           )
'    _PutImage (0 , 0 ), imgTiles&,     UniversalSprite&, (arrTileSheetMap(TileNum%).xStart, arrTileSheetMap(TileNum%).yStart)-(arrTileSheetMap(TileNum%).xEnd, arrTileSheetMap(TileNum%).yEnd)
'
'    ' COLOR IN THE TEMPORARY TILE
'    ' REPLACING BLACK (THE SOURCE COLOR) WITH THE TILE COLOR
''    IF ColorSprite& < -1 THEN _FreeImage ColorSprite&
'    IF ColorSprite& < -1 OR ColorSprite& > 0 THEN _FreeImage ColorSprite&
'    DoColorSwap UniversalSprite&, cBlack, TileColor~&, ColorSprite&
'    'ColorSprite& = swapcolor&(UniversalSprite&, cBlack, TileColor~&)
'    ' ^^^
'    ' PROGRAM CRASHED HERE, BEFORE FIXING swapcolor& AND CHANGING FROM FUNCTION TO SUB DoColorSwap
'
'    ' COPY THE TEMPORARY TILE TO THE SCREEN imgScreen&
'    _SOURCE ColorSprite&
'    _Dest imgScreen&
'    '_PutImage(dx                       , dy                       ), sourceHandle&, destHandle&, (sx1, sy1)-(sx2,              sy2              )
'    _PutImage (arrTileMap(dx%, dy%).xPos, arrTileMap(dx%, dy%).yPos), ColorSprite&,  imgScreen&,  (0,   0  )-(tileWidthPx% - 1, tileHeightPx% - 1) ' portion of source to the top-left corner of the destination page
'
'    ' -----------------------------------------------------------------------------
'    ' PART 3: CLEANUP
'
'    ' ADDED PER FellipeHeitor
'    IF ColorSprite& < -1 OR ColorSprite& > 0 THEN _FREEIMAGE ColorSprite&
'    IF UniversalSprite& < -1 OR UniversalSprite& > 0 THEN _FREEIMAGE UniversalSprite&
'
'End Sub ' DrawColorTileFast
'
' /////////////////////////////////////////////////////////////////////////////
' Original version which calculates coordinates on tile sheet and destination
' screen every time. For a faster version uses precalculated coordinates,
' see DrawColorTileFast.

' Receives:
' imgTiles& = handle to 16x16 tile sheet of 16x16 pixel tiles colored black (256 tiles)
' TileNum% = ordinal number of tile on tile sheet to draw (0-255)
' TileColor~& = color to use for tile
' imgScreen& = handle to screen to draw tile on
' dx% = column # to draw tile at (where each column is 16 pixels wide)
' dy% = row # to draw tile at (where each row is 16 pixels high)
' xOffset% = offset tile this many columns over
' yOffset% = offset tile this many rows down

' TODO: support background color bcolor&

' TODO: support transparency?
'       Colors returned are always opaque as the transparency value is always 255. Use _ALPHA or _CLEARCOLOR to change it.

Sub DrawColorTile (imgScreen&, imgTiles&, TileNum%, TileColor~&, BackColor~&, dx%, dy%, xOffset%, yOffset%)
    Dim cols%
    Dim rows%
    Dim sc%
    Dim sr%
    Dim sx1%
    Dim sy1%
    Dim sx2%
    Dim sy2%
    Dim xDest%
    Dim yDest%
    Dim ColorSprite&
    Dim UniversalSprite&

    '_PUTIMAGE (0, 0), i ' places image at upper left corner of window w/o stretching it
    '_PUTIMAGE (dx1, dy1), sourceHandle&, destHandle&, (sx1, sy1)-(sx2, sy2) ' portion of source to the top-left corner of the destination page
    '_PUTIMAGE (64,  128), imgTiles&,      imgScreen&,   (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page
    '_PutImage (64, 128), imgTiles&, imgScreen&, (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page

    ' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
    cols% = 16
    rows% = 16

    ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    sc% = TileNum% Mod rows%
    sr% = TileNum% \ rows%

    'Print "Tile#" + cstr$(TileNum%) + " at sc%=" + cstr$(sc%) + ",sr%=" + cstr$(sr%)

    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
    'sx1% = sc% * tw%
    sx1% = sc% * 8

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    'sy1% = sr% * tw%
    sy1% = sr% * 8

    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
    'sx2% = sx1% + (tw% - 1)
    sx2% = sx1% + 7

    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
    'sy2% = sy1% + (tw% - 1)
    sy2% = sy1% + 7

    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
    'xDest% = dx% * tw%
    xDest% = dx% * 8 + (8 * xOffset%)

    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
    ''yDest% = (dy% * tw%) + 64
    'yDest% = (dy% * 8) + 64 + (8 * yOffset%)
    yDest% = (dy% * 8) + (8 * yOffset%)

    ' IS THERE A BACKGROUND COLOR?
    If BackColor~& <> cEmpty Then
        ColorSprite& = _NewImage(8, 8, 32)
        _Dest ColorSprite&
        'SCREEN ColorSprite&
        'CLS , _RGB(0, 0, 0) ' makes the background opaque black
        Cls , BackColor~&

        'SCREEN imgScreen& ' SHIFT FOCUS BACK TO THE SCREEN

        ' COPY THE TEMPORARY TILE TO THE SCREEN imgScreen&
        _Source ColorSprite&
        _Dest imgScreen&
        'TODO: SHOULDN'T THIS BE 7,7 NOT 15,15 ?
        '_PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(15, 15) ' portion of source to the top-left corner of the destination page
        _PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page
    End If

    ' CREATE A TEMPORARY TILE TO COLOR
    'UniversalSprite& = _NewImage(tw%, tw%, 32)
    UniversalSprite& = _NewImage(8, 8, 32)

    ' COPY THE TILE TO THE TEMPORARY ONE
    _Source imgTiles&
    _Dest UniversalSprite&
    _PutImage (0, 0), imgTiles&, UniversalSprite&, (sx1%, sy1%)-(sx2%, sy2%)

    ' COLOR IN THE TEMPORARY TILE
    ' REPLACING BLACK (THE SOURCE COLOR) WITH THE TILE COLOR
    'If ColorSprite& < -1 Then _FreeImage ColorSprite&
    If ColorSprite& < -1 Or ColorSprite& > 0 Then _FreeImage ColorSprite&
    'ColorSprite& = swapcolor&(UniversalSprite&, cBlack, TileColor~&)
    DoColorSwap UniversalSprite&, cBlack, TileColor~&, ColorSprite&

    ' COPY THE TEMPORARY TILE TO THE SCREEN imgScreen&
    _Source ColorSprite&
    _Dest imgScreen&
    _PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page

    ' ADDED PER FellipeHeitor
    If ColorSprite& < -1 Or ColorSprite& > 0 Then _FreeImage ColorSprite&
    If UniversalSprite& < -1 Or UniversalSprite& > 0 Then _FreeImage UniversalSprite&

End Sub ' DrawColorTile

'' /////////////////////////////////////////////////////////////////////////////
'' SAME AS DrawColorTile
'' EXCEPT HAS AN ADDITIONAL PARAMETER TransparentColor~&
'' ALLOWING USER TO SPECIFY A TRANSPARENT COLOR OTHER THAN cEmpty
'
'Sub DrawColorTile2 (imgScreen&, imgTiles&, TileNum%, TileColor~&, BackColor~&, dx%, dy%, xOffset%, yOffset%, TransparentColor~&)
'    Dim cols%
'    Dim rows%
'    Dim sc%
'    Dim sr%
'    Dim sx1%
'    Dim sy1%
'    Dim sx2%
'    Dim sy2%
'    Dim xDest%
'    Dim yDest%
'    Dim ColorSprite&
'    Dim UniversalSprite&
'
'    '_PUTIMAGE (0, 0), i ' places image at upper left corner of window w/o stretching it
'    '_PUTIMAGE (dx1, dy1), sourceHandle&, destHandle&, (sx1, sy1)-(sx2, sy2) ' portion of source to the top-left corner of the destination page
'    '_PUTIMAGE (64,  128), imgTiles&,      imgScreen&,   (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page
'    '_PutImage (64, 128), imgTiles&, imgScreen&, (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page
'
'    ' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
'    cols% = 16
'    rows% = 16
'
'    ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
'    sc% = TileNum% Mod rows%
'    sr% = TileNum% \ rows%
'
'    'Print "Tile#" + cstr$(TileNum%) + " at sc%=" + cstr$(sc%) + ",sr%=" + cstr$(sr%)
'
'    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
'    'sx1% = sc% * tw%
'    sx1% = sc% * 8
'
'    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
'    'sy1% = sr% * tw%
'    sy1% = sr% * 8
'
'    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
'    'sx2% = sx1% + (tw% - 1)
'    sx2% = sx1% + 7
'
'    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
'    'sy2% = sy1% + (tw% - 1)
'    sy2% = sy1% + 7
'
'    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
'    'xDest% = dx% * tw%
'    xDest% = dx% * 8 + (8 * xOffset%)
'
'    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
'    ''yDest% = (dy% * tw%) + 64
'    'yDest% = (dy% * 8) + 64 + (8 * yOffset%)
'    yDest% = (dy% * 8) + (8 * yOffset%)
'
'    ' IS THERE A BACKGROUND COLOR?
'    If BackColor~& <> cWhite Then
'        ColorSprite& = _NewImage(8, 8, 32)
'        _Dest ColorSprite&
'        'SCREEN ColorSprite&
'        'CLS , _RGB(0, 0, 0) ' makes the background opaque black
'        Cls , BackColor~&
'
'        'SCREEN imgScreen& ' SHIFT FOCUS BACK TO THE SCREEN
'
'        ' COPY THE TEMPORARY TILE TO THE SCREEN imgScreen&
'        _Source ColorSprite&
'        _Dest imgScreen&
''TODO: SHOULDN'T THIS BE 7,7 NOT 15,15 ?
'        _PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(15, 15) ' portion of source to the top-left corner of the destination page
'        '_PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page
'    End If
'
'    ' CREATE A TEMPORARY TILE TO COLOR
'    'UniversalSprite& = _NewImage(tw%, tw%, 32)
'    UniversalSprite& = _NewImage(8, 8, 32)
'
'    ' COPY THE TILE TO THE TEMPORARY ONE
'    _Source imgTiles&
'    _Dest UniversalSprite&
'    _PutImage (0, 0), imgTiles&, UniversalSprite&, (sx1%, sy1%)-(sx2%, sy2%)
'
'    ' COLOR IN THE TEMPORARY TILE
'    ' REPLACING BLACK (THE SOURCE COLOR) WITH THE TILE COLOR
''    If ColorSprite& < -1 Then _FreeImage ColorSprite&
'     IF ColorSprite& < -1 OR ColorSprite& > 0 THEN _FreeImage ColorSprite&
'    'ColorSprite& = swapcolor&(UniversalSprite&, cBlack, TileColor~&)
'    DoColorSwap UniversalSprite&, cBlack, TileColor~&, ColorSprite&
'
'    ' COPY THE TEMPORARY TILE TO THE SCREEN imgScreen&
'    _Source ColorSprite&
'    _Dest imgScreen&
'    _PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page
'
'    ' ADDED PER FellipeHeitor
'    IF ColorSprite& < -1 OR ColorSprite& > 0 THEN _FreeImage ColorSprite&
'    IF UniversalSprite& < -1 OR UniversalSprite& > 0 THEN _FreeImage UniversalSprite&
'
'End Sub ' DrawColorTile2

' /////////////////////////////////////////////////////////////////////////////
' Latest version with NOVARSEG's changes.

' Based on code from:

' Image color swap?
' https://www.qb64.org/forum/index.php?topic=2312.0

' Like Function swapcolor& except returns new image in a parameter
' in case being a function causes a memory leak?

Sub DoColorSwap (imgOriginal&, oldcolor~&, newcolor~&, imgNew&)
    Dim m As _MEM
    Dim a As _Offset
    Dim c As _Unsigned Long

    a = 0

    imgNew& = _CopyImage(imgOriginal&, 32)
    '^^^
    'THIS IS WHERE THE PROGRAM WAS CRASHING (BUT NO LONGER!)

    '^^^
    'CAN WE DO THIS WITH _PUTIMAGE INSTEAD OF _COPYIMAGE?
    '_SOURCE imgOriginal&
    '_DEST imgNew&
    '_PUTIMAGE 'full source image to fit full destination area after _SOURCE and _DEST are set

    m = _MemImage(imgNew&)

    'ORIGINAL VERSION:
    Do Until a = m.SIZE - 4
        a = a + 4
        c = _MemGet(m, m.OFFSET + a, _Unsigned Long)
        If c = oldcolor~& Then
            _MemPut m, m.OFFSET + a, newcolor~&
        End If
    Loop

    ' ^^^
    ' Re: _CopyImage crashing my program after a while, can somebody please help?
    ' https://www.qb64.org/forum/index.php?topic=3926.15
    ' NOVARSEG
    ' « Reply #17 on: Today at 01:02:53 AM »
    ' Sorry again. Lets say m.size = 8 (bytes)
    ' the first 4 bytes are memgetted . byte 0, 1, 2, 3
    ' then
    '   a = a +4  and right away the condition
    '   DO Until a = m.SIZE - 4
    '     a = (8 - 4) and that exits the DO  LOOP
    ' but bytes 4, 5, 6, 7 don't get memgetted
    ' which is one of the weaknesses of DO UNTIL etc
    ' Always use EXIT DO
    ' Do Until a = m.SIZE would work,
    ' but there is no sense in LOOPing an extra time if you don't have to.
    ' so

    'NEW VERSION SEEMS TO WRITE AN EXTRA TILE TO 0,0:
    'DO
    '    c = _MemGet(m, m.OFFSET + a, _Unsigned Long)
    '    IF c~& = oldcolor~& THEN
    '       _MemPut m, m.OFFSET + a, newcolor~&
    '    END IF
    '    a = a + 4
    '    IF a >= m.size THEN
    '        EXIT DO
    '    END IF
    'LOOP

    _MemFree m
End Sub ' DoColorSwap&

'' /////////////////////////////////////////////////////////////////////////////
'' OLD version v2, works but not as efficient as NOVARSEG's version.
'
'' Image color swap?
'' https://www.qb64.org/forum/index.php?topic=2312.0
'
'' Like Function swapcolor& except returns new image in a parameter
'' in case being a function causes a memory leak?
'
'Sub DoColorSwap1 (imgOriginal&, oldcolor~&, newcolor~&, imgNew&)
'    Dim m As _MEM
'    DIM a As _OFFSET
'    Dim c As _Unsigned Long
'
'    a = 0
'
''THIS IS WHERE THE PROGRAM CRASHES:
'    imgNew& = _CopyImage(imgOriginal&, 32)
''^^^
''CAN WE DO THIS WITH _PUTIMAGE INSTEAD OF _COPYIMAGE?
'
'    m = _MemImage(imgNew&)
'
'    Do Until a = m.SIZE - 4
'        a = a + 4
'        c = _MemGet(m, m.OFFSET + a, _Unsigned Long)
'        If c = oldcolor~& Then
'            _MemPut m, m.OFFSET + a, newcolor~&
'        End If
'    Loop
'    _MemFree m
'End Function ' DoColorSwap1&
'
'' /////////////////////////////////////////////////////////////////////////////
'' Original version 1, from:
'
'' Image color swap?
'' https://www.qb64.org/forum/index.php?topic=2312.0
'
'' Receives:
'' handle& = image handle to swap colors in
'' oldcolor~& = old color to be replaced
'' newcolor~& = new color
'
'' Return value = image handle to copy of image with the new colors
'
'' -----------------------------------------------------------------------------
'' Craz1000:
'' So i am creating another sprite based game.
'' And i have gotten to a point to where i can have
'' an excessive amount of sprites loaded or do a color swap.
'' my question is... if i have for example
'' PlayerSprite& = _LOADIMAGE("Images\Player1.png")
'' If player 1 is blue in color and i want player 2 to be green,
'' am I able just swap blue to green on PlayerSprite&
'' or am i going to have to have 2 different sprites?
'
'' Petr:
'' Hi, 2 different image handle, but you can do this 2 handle
'' from one image. As show this easy example:
'
'' Sample usage:
''
'' $Color:32
''
'' this do image (the same as load it from harddrive)
'' UniversalSprite& = _NewImage(320, 240, 32)
'' _Dest UniversalSprite&
'' Cls , Yellow
'' Line (20, 20)-(300, 220), Blue, BF
'' _Dest 0
''
'' Screen _NewImage(800, 600, 32)
'' Sprite1 = _CopyImage(UniversalSprite&, 32)
'' Sprite2 = swapcolor(UniversalSprite&, Blue, Red)
''
'' _PutImage (50, 100), Sprite1
'' _PutImage (430, 100), Sprite2
'' -----------------------------------------------------------------------------
'
'' ~& = unsigned long type
'
''Function swapcolor& (handle, oldcolor~&, newcolor~&)
'Function swapcolor& (handle&, oldcolor~&, newcolor~&)
'    Dim m As _MEM
'    DIM a&
'    'Dim c As _Unsigned Long
'    DIM c~&
'
''THIS IS WHERE THE PROGRAM CRASHES:
'    swapcolor& = _CopyImage(handle&, 32)
'' ^^^
'' PROGRAM CRASHES HERE WITH THESE VALUE:
'' handle& = -8191
'
'    m = _MemImage(swapcolor&)
'
'    Do Until a& = m.SIZE - 4
'        a& = a& + 4
'
'        c~& = _MemGet(m, m.OFFSET + a&, _Unsigned Long)
'
'        If c~& = oldcolor~& Then
'            _MemPut m, m.OFFSET + a&, newcolor~&
'        End If
'    Loop
'
'    _MemFree m
'
'End Function ' swapcolor&
'
' ################################################################################################################################################################
' END COLOR TEXT TILE FUNCTIONS
' ################################################################################################################################################################








' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN FOOTRACE v2
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Version 2 changes:
' * 4 players, instead of 2
'   - each player consistes of 2 "feet", which are treated as separate "players"
'     player 1 = player 1's left foot, player 2 = player 1's right foot, etc.
' * Input from control mapping (game controller and/or keyboards)
' * Uses hires screen(1024x768) instead of text.

'TODO: move footrace2 here

' /////////////////////////////////////////////////////////////////////////////
' 128x48

' Size of array:
'
' Resolution    Cols   Rows
' 1024 x  768   128    48

' 48 total available # of rows
' -2 rows for title
' -1 row for headings
' -1 for player #1 info
' -1 for player #2 info
' -1 for player #3 info
' -1 for player #4 info
' -- --------------------------
' 41 rows available

Function Footrace2Map1$
    Dim m$
    m$ = ""
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + "#.Footrace! by Softintheheadware, 2021                Press <ESC> to quit......................................................#" + Chr$(13) ' 1
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 2
    m$ = m$ + "#.PLAYER  SCORE................................................................................................................#" + Chr$(13) ' 3
    m$ = m$ + "#.1.......0....................................................................................................................#" + Chr$(13) ' 4
    m$ = m$ + "#.2.......0....................................................................................................................#" + Chr$(13) ' 5
    m$ = m$ + "#.3.......0....................................................................................................................#" + Chr$(13) ' 6
    m$ = m$ + "#.4.......0....................................................................................................................#" + Chr$(13) ' 7
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 8
    m$ = m$ + "#............................................................FINISH............................................................#" + Chr$(13) ' 9
    m$ = m$ + "#------------------------------------------------------------------------------------------------------------------------------#" + Chr$(13) ' 10
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 11
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 12
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13) ' 13
    m$ = m$ + "#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#..#" + Chr$(13) ' 14
    m$ = m$ + "#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#.....#.....##.....##.....#..#" + Chr$(13) ' 15
    m$ = m$ + "#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#" + Chr$(13) ' 16
    m$ = m$ + "#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#..#..#......#......#.....#" + Chr$(13) ' 17
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13) ' 18
    m$ = m$ + "###......##......##.......###......##......##.......###......##......##.......###......##......##.......###......##......##....#" + Chr$(13) ' 19
    m$ = m$ + "###......##......##.......###......##......##.......###......##......##.......###......##......##.......###......##......##....#" + Chr$(13) ' 20
    m$ = m$ + "#....##......##......######....##......##......######....##......##......######....##......##......######....##......##......###" + Chr$(13) ' 21
    m$ = m$ + "#....##......##......######....##......##......######....##......##......######....##......##......######....##......##......###" + Chr$(13) ' 22
    m$ = m$ + "#..########################..########################..########################..########################..#####################" + Chr$(13) ' 23
    m$ = m$ + "#..#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.#" + Chr$(13) ' 24
    m$ = m$ + "#..#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.......#.....#.....#.....#.#" + Chr$(13) ' 25
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13) ' 26
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13) ' 27
    m$ = m$ + "#..#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.......#..#..#..#..#..#..#.#" + Chr$(13) ' 28
    m$ = m$ + "#.....#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#.#" + Chr$(13) ' 29
    m$ = m$ + "#.....#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#..........#.....#.....#..#.#" + Chr$(13) ' 30
    m$ = m$ + "###################..########################..########################..########################..#############################" + Chr$(13) ' 31
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 32
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 33
    m$ = m$ + "###..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..########..##..##..##..##..###" + Chr$(13) ' 34
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 35
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 36
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13) ' 37
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 38
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 39
    m$ = m$ + "#......................####......................####......................####......................####......................#" + Chr$(13) ' 40
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 41
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 42
    m$ = m$ + "########################..########################..########################..########################..########################" + Chr$(13) ' 43
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 44
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 45
    m$ = m$ + "#.......................11........................22........................33........................44.......................#" + Chr$(13) ' 46
    m$ = m$ + "#..............................................................................................................................#" + Chr$(13) ' 47
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 48
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '                                                                                                             11111111111111111111111111111
    Footrace2Map1$ = m$
End Function ' Footrace2Map1$

' /////////////////////////////////////////////////////////////////////////////
' 128x41

Function Footrace2Map2$
    Dim m$
    m$ = ""
    'm$ = m$ + "Footrace! by Softintheheadware, 2021                Press <ESC> to quit.........................................................." + CHR$(13) ' 1
    'm$ = m$ + "................................................................................................................................." + CHR$(13) ' 2
    'm$ = m$ + "PLAYER  LEFT FOOT    RIGHT FOOT             SCORE................................................................................" + CHR$(13) ' 3
    'm$ = m$ + "1       Cursor keys  Numeric keypad arrows  0    ................................................................................" + CHR$(13) ' 4
    'm$ = m$ + "2       A,S,W,Z      D,F,R,C                0    ................................................................................" + CHR$(13) ' 5
    'm$ = m$ + "3       G,H,Y,B      J,K,I,M                0    ................................................................................" + CHR$(13) ' 6
    'm$ = m$ + "4       o,P,0,L      [,],=,'                0    ................................................................................" + CHR$(13) ' 7
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 8
    m$ = m$ + "................................FINISH.........................................................................................." + Chr$(13) ' 9
    m$ = m$ + "################################$$--$$##########################################................................................" + Chr$(13) ' 10
    m$ = m$ + "...................#.....#.....#......#.....#.....#............................................................................." + Chr$(13) ' 11
    m$ = m$ + "...................#.....#.....#......#.....#.....#............................................................................." + Chr$(13) ' 12
    m$ = m$ + "..###############..#..#..#..#..#......#..#..#..#..#..###############............................................................" + Chr$(13) ' 13
    m$ = m$ + ".............x..#.....#.....#............#.....#.....#..z......................................................................." + Chr$(13) ' 14
    m$ = m$ + ".............x..#.....#.....#............#.....#.....#..z......................................................................." + Chr$(13) ' 15
    m$ = m$ + "##############ww######################################yy########################................................................" + Chr$(13) ' 16
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 17
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 18
    m$ = m$ + "......###########.........###########.........###########.........###########..................................................." + Chr$(13) ' 19
    m$ = m$ + "####............#######.............#######.............#######.............####................................................" + Chr$(13) ' 20
    m$ = m$ + "...#............#.....#.............#.....#.............#.....#.............#..................................................." + Chr$(13) ' 21
    m$ = m$ + "...###########..#.....############..#.....############..#.....############..#..................................................." + Chr$(13) ' 22
    m$ = m$ + "#...............#..#................#..#................#..#................#..#................................................" + Chr$(13) ' 23
    m$ = m$ + "#...............#..#................#..#................#..#................#..#................................................" + Chr$(13) ' 24
    m$ = m$ + "#################aa##################bb##################cc##################dd#................................................" + Chr$(13) ' 25
    m$ = m$ + ".......#.....#.....#.......#.....#.....#.......#.....#.....#.......#.....#.....#................................................" + Chr$(13) ' 26
    m$ = m$ + ".......#.....#.....#.......#.....#.....#.......#.....#.....#.......#.....#.....#................................................" + Chr$(13) ' 27
    m$ = m$ + "....#.....#.....#..#....#.....#.....#..#....#.....#.....#..#....#.....#.....#..#................................................" + Chr$(13) ' 28
    m$ = m$ + "....#.....#.....#A.#....#.....#.....#B.#....#.....#.....#C.#....#.....#.....#D.#................................................" + Chr$(13) ' 29
    m$ = m$ + "....################....################....################....################................................................" + Chr$(13) ' 30
    m$ = m$ + "..........WW..................XX..................YY..................ZZ........................................................" + Chr$(13) ' 31
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 32
    m$ = m$ + "#...................#...................#...................#..................................................................." + Chr$(13) ' 33
    m$ = m$ + "#....####....####...#....####....####...#....####....####...#....####....####..................................................." + Chr$(13) ' 34
    m$ = m$ + "#...................#...................#...................#..................................................................." + Chr$(13) ' 35
    m$ = m$ + ".#...................#...................#...................#.................................................................." + Chr$(13) ' 36
    m$ = m$ + ".#.......####........#.......####........#.......####........#.......####......................................................." + Chr$(13) ' 37
    m$ = m$ + "..A...................B...................C...................D................................................................." + Chr$(13) ' 38
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 39
    m$ = m$ + "########....################....################....################....########................................................" + Chr$(13) ' 40
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 41
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 42
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 43
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 44
    m$ = m$ + ".........11..................22..................33..................44........................................................." + Chr$(13) ' 45
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 46
    m$ = m$ + "................................................................................................................................" + Chr$(13) ' 47
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 48
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890
    '                   11111111112222222222333333333344444444445555555555666666666677777777778
    Footrace2Map2$ = m$
End Function ' Footrace2Map2$

' /////////////////////////////////////////////////////////////////////////////
' 80x40

' Size of array:
'
' Cols   Rows
' 80     48

' 48 total available # of rows
' -2 rows for title
' -1 row for headings
' -1 for player #1 info
' -1 for player #2 info
' -1 for player #3 info
' -1 for player #4 info
' -- --------------------------
' 41 rows available

Function Footrace2Map3$
    Dim m$
    m$ = ""
    '                   11111111112222222222333333333344444444445555555555666666666677777777778
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890
    m$ = m$ + "................................................................................" + Chr$(13) ' 1
    m$ = m$ + "................................FINISH.........................................." + Chr$(13) ' 2
    m$ = m$ + "################################$$--$$##########################################" + Chr$(13) ' 3
    m$ = m$ + "...................#.....#.....#......#.....#.....#............................." + Chr$(13) ' 4
    m$ = m$ + "...................#.....#.....#......#.....#.....#............................." + Chr$(13) ' 5
    m$ = m$ + "..###############..#..#..#..#..#......#..#..#..#..#..###############............" + Chr$(13) ' 6
    m$ = m$ + ".............x..#.....#.....#............#.....#.....#..z......................." + Chr$(13) ' 7
    m$ = m$ + ".............x..#.....#.....#............#.....#.....#..z......................." + Chr$(13) ' 8
    m$ = m$ + "##############ww######################################yy########################" + Chr$(13) ' 9
    m$ = m$ + "................................................................................" + Chr$(13) ' 10
    m$ = m$ + "................................................................................" + Chr$(13) ' 11
    m$ = m$ + "......###########.........###########.........###########.........###########..." + Chr$(13) ' 12
    m$ = m$ + "####............#######.............#######.............#######.............####" + Chr$(13) ' 13
    m$ = m$ + "...#............#.....#.............#.....#.............#.....#.............#..." + Chr$(13) ' 14
    m$ = m$ + "...###########..#.....############..#.....############..#.....############..#..." + Chr$(13) ' 15
    m$ = m$ + "#...............#..#................#..#................#..#................#..#" + Chr$(13) ' 16
    m$ = m$ + "#...............#..#................#..#................#..#................#..#" + Chr$(13) ' 17
    m$ = m$ + "#################aa##################bb##################cc##################dd#" + Chr$(13) ' 18
    m$ = m$ + ".......#.....#.....#.......#.....#.....#.......#.....#.....#.......#.....#.....#" + Chr$(13) ' 19
    m$ = m$ + ".......#.....#.....#.......#.....#.....#.......#.....#.....#.......#.....#.....#" + Chr$(13) ' 20
    m$ = m$ + "....#.....#.....#..#....#.....#.....#..#....#.....#.....#..#....#.....#.....#..#" + Chr$(13) ' 21
    m$ = m$ + "....#.....#.....#A.#....#.....#.....#B.#....#.....#.....#C.#....#.....#.....#D.#" + Chr$(13) ' 22
    m$ = m$ + "....################....################....################....################" + Chr$(13) ' 23
    m$ = m$ + "..........WW..................XX..................YY..................ZZ........" + Chr$(13) ' 24
    m$ = m$ + "................................................................................" + Chr$(13) ' 25
    m$ = m$ + "#...................#...................#...................#..................." + Chr$(13) ' 26
    m$ = m$ + "#....####....####...#....####....####...#....####....####...#....####....####..." + Chr$(13) ' 27
    m$ = m$ + "#...................#...................#...................#..................." + Chr$(13) ' 28
    m$ = m$ + ".#...................#...................#...................#.................." + Chr$(13) ' 29
    m$ = m$ + ".#.......####........#.......####........#.......####........#.......####......." + Chr$(13) ' 30
    m$ = m$ + "..A...................B...................C...................D................." + Chr$(13) ' 31
    m$ = m$ + "................................................................................" + Chr$(13) ' 32
    m$ = m$ + "########....################....################....################....########" + Chr$(13) ' 33
    m$ = m$ + "................................................................................" + Chr$(13) ' 34
    m$ = m$ + "................................................................................" + Chr$(13) ' 35
    m$ = m$ + "................................................................................" + Chr$(13) ' 36
    m$ = m$ + "................................................................................" + Chr$(13) ' 37
    m$ = m$ + ".........11..................22..................33..................44........." + Chr$(13) ' 38
    m$ = m$ + "................................................................................" + Chr$(13) ' 39
    m$ = m$ + "################################################################################" + Chr$(13) ' 40
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890
    '                   11111111112222222222333333333344444444445555555555666666666677777777778
    Footrace2Map3$ = m$
End Function ' Footrace2Map3$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END FOOTRACE v2
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ################################################################################################################################################################
' BEGIN SOUND ROUTINES
' ################################################################################################################################################################

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' BEGIN TUNES
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' /////////////////////////////////////////////////////////////////////////////

Sub StartRaceTune1
    Dim in$
    in$ = ""
    'in$ = in$ + "mb"
    in$ = in$ + "mf"
    in$ = in$ + "T120v50L4n24L4v0n24"
    in$ = in$ + "T120v50L4n24L4v0n24"
    in$ = in$ + "T120v50L4n24L4v0n24"
    in$ = in$ + "T160"
    in$ = in$ + "L1v50n36"
    in$ = in$ + "T120"
    Play in$
End Sub ' StartRaceTune1

' /////////////////////////////////////////////////////////////////////////////
' Won the race

Sub SuccessTune1
    Sound 262 * 2, 2
    Sound 50, 1

    Sound 330 * 2, 2
    Sound 50, 1

    Sound 392 * 2, 2
    Sound 50, 1

    Sound 524 * 2, 2
    Sound 40, 3

    Sound 392 * 2, 2
    Sound 40, 1

    Sound 524 * 2, 4
End Sub ' SuccessTune1

' /////////////////////////////////////////////////////////////////////////////
' success tune (finished level or got an object you need)

Sub waster_bas_sound_12
    'ESCAPE THE POLICEMAN
    Sound 262, 2: Sound 330, 2: Sound 392, 2: Sound 523, 3
    Sound 392, 1: Sound 523, 4
End Sub ' waster_bas_sound_12

' /////////////////////////////////////////////////////////////////////////////

Sub quit_race_sound_1
    Dim t%
    For t% = 400 To 200 Step -40
        Sound t%, .3
    Next t%
End Sub ' quit_race_sound_1

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' END TUNES
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' BEGIN WALKING SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' /////////////////////////////////////////////////////////////////////////////
' Walking sounds

Sub WalkingSound (iWhich As Integer)
    Select Case iWhich
        Case 1:
            KISSED_BAS_sound_2_noise
        Case 2:
            leapfrog_bas_sound_1
        Case 3:
            RMORTIS2_sound_1
        Case Else:
            Tiny_Dungeon_sound_1_drumming
    End Select
End Sub ' WalkingSound

' /////////////////////////////////////////////////////////////////////////////
' Walking #1
' short low putt sound (repeat for a kind of engine noise)

Sub KISSED_BAS_sound_2_noise
    Sound 1000, .1
End Sub ' KISSED_BAS_sound_2_noise

' /////////////////////////////////////////////////////////////////////////////
' Walking #2
' leapfrog.bas
' ascending low pitched sounds (footsteps or some basic action)

Sub leapfrog_bas_sound_1
    Play "MBMST220L64O1c"

    ' if sound is too long it keeps playing after player is done moving
    'Play "MBMST220L64O1cP16eP16g"
End Sub ' leapfrog_bas_sound_1

' /////////////////////////////////////////////////////////////////////////////
' Walking #3
' RMORTIS2.BAS
' boop (knocking on door)

Sub RMORTIS2_sound_1
    Sound 400 + Rnd * 100, .1

    ' if sound is too long it keeps playing after player is done moving
    'Sound 40, .1
    'Sound 47, 1: Sound 47, 0
End Sub ' RMORTIS2_sound_1

' /////////////////////////////////////////////////////////////////////////////
' Walking #4
' SierraKen_My 1996 Tiny Dungeon Game v2.bas
' woop! sound (bubble sound)

Sub Tiny_Dungeon_sound_1_drumming
    dr = 10
    Sound 100 + dr * 10, .1

    ' if sound is too long it keeps playing after player is done moving
    ''drumming:
    'For dr = 1 To 20 Step 2
    '    Sound 100 + dr * 10, .1
    '    For tm = 1 To 3000: Next tm
    'Next dr
End Sub ' Tiny_Dungeon_sound_1_drumming

' /////////////////////////////////////////////////////////////////////////////
' Walking #5
' low boop sound (footsteps or some action)

Sub mooncr_sounds_5
    SSHOOT3$ = "MBT255l48n7n10n7"
    Play SSHOOT3$
End Sub ' mooncr_sounds_5

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' END WALKING SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' BEGIN BUMP SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' /////////////////////////////////////////////////////////////////////////////
' Bump sounds

Sub BumpSound (iWhich As Integer)
    Select Case iWhich
        Case 1:
            BEEP_BAS_SOUND_frog
        Case 2:
            cr_bas_sound_8
        Case 3:
            BEEP_BAS_SOUND_frog
        Case Else:
            cr_bas_sound_8
    End Select
End Sub ' BumpSound

' /////////////////////////////////////////////////////////////////////////////
' Bumped into a wall #1
' med-low quick boop sound (bounced into something)

Sub BEEP_BAS_SOUND_frog
    For t% = 100 To 200 Step 5
        Sound 300 - t%, .11
        Sound t%, .11
        Sound t% - 50, .11
    Next
End Sub ' BEEP_BAS_SOUND_frog

' /////////////////////////////////////////////////////////////////////////////
' Bumped into a wall #2
' quick lower pitched murp sound

Sub cr_bas_sound_8
    'Grenade launcher
    Play "mnt255o1l32ccc"
End Sub ' cr_bas_sound_8

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' END BUMP SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' BEGIN GET KEY SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' /////////////////////////////////////////////////////////////////////////////
' quicker little affirmative sequence of notes (got an object)
' based on cr_bas_sound_10

Sub get_key_sound_1
    Play "mst255o3l16cd"
    ''Magic
    ''Play "mst255o3l16cdcdg"
End Sub ' get_key_sound_1

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' END GET KEY SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' BEGIN UNLOCK DOOR SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' /////////////////////////////////////////////////////////////////////////////

Sub unlock_door_sound_1
    Dim z As Integer
    Dim eq As Long
    Dim iCount As Integer

    For z = 1 To 20
        eq = Int(2000 * Rnd) + 200
        Sound eq, .03
    Next z

    'For z = 40 To 2000 Step 162
    'Sound z, .03
    'Next z

    iCount = 0
    Do
        iCount = iCount + 1
        _Limit 4
    Loop Until iCount = 2

    For z = 1 To 20
        eq = Int(2000 * Rnd) + 500 ' 2000
        Sound eq, .03
    Next z

    'For z = 10000 To 100 Step -500
    'Sound z, .001 * 18.2
    'Next z

    iCount = 0
    Do
        iCount = iCount + 1
        _Limit 4
    Loop Until iCount = 2

End Sub ' unlock_door_sound_1

' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' END UNLOCK DOOR SOUNDS
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

' ################################################################################################################################################################
' END SOUND ROUTINES
' ################################################################################################################################################################






























' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN FOOTRACE v1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Function Footrace1$

    ' MIN/MAX VALUES
    Const cMinX = 2
    Const cMaxX = 79
    Const cMinY = 9
    Const cMaxY = 24

    ' FACING DIRECTION CONSTANTS
    Const c_UP = 1
    Const c_DOWN = 2
    Const c_LEFT = 3
    Const c_RIGHT = 4

    ' FOOT MOVEMENT CONSTANTS
    Const c_FORWARD = 1
    Const c_NONE = 2
    Const c_BACK = 3

    ' -----------------------------------------------------------------------------
    ' keyboard code constants for _BUTTON
    ' For now these are hard-coded as constants,
    ' later we would provide an option for the players to map their own input.

    ' PLAYER 1 LEFT JOY KEYS
    Const c_bKey_CrsrUp = 329
    Const c_bKey_CrsrDown = 337
    Const c_bKey_CrsrLeft = 332
    Const c_bKey_CrsrRight = 334
    Const c_bKey_RightCtrl = 286

    ' PLAYER 1 RIGHT JOY KEYS
    Const c_bKey_Kpad8 = 73
    Const c_bKey_Kpad2 = 81
    Const c_bKey_Kpad4 = 76
    Const c_bKey_Kpad6 = 78
    Const c_bKey_Kpad0 = 83

    ' PLAYER 2 LEFT JOY KEYS
    Const c_bKey_A = 31
    Const c_bKey_S = 32
    Const c_bKey_W = 18
    Const c_bKey_Z = 45
    Const c_bKey_LeftCtrl = 30

    ' PLAYER 2 RIGHT JOY KEYS
    Const c_bKey_J = 37
    Const c_bKey_K = 38
    Const c_bKey_I = 24
    Const c_bKey_M = 51
    Const c_bKey_Space = 58

    ' OTHER _KEYDOWN CONSTANTS
    Const c_KeyDown_Y = 121
    Const c_KeyDown_N = 110
    Const c_KeyDown_Esc = 27

    ' PLAYER KEY MAP CONSTANTS
    Const c_Map_Joy1_Left = 1
    Const c_Map_Joy1_Right = 2
    Const c_Map_Joy1_Up = 3
    Const c_Map_Joy1_Down = 4
    Const c_Map_Joy1_Button = 5
    Const c_Map_Joy2_Left = 6
    Const c_Map_Joy2_Right = 7
    Const c_Map_Joy2_Up = 8
    Const c_Map_Joy2_Down = 9
    Const c_Map_Joy2_Button = 10

    ' =============================================================================
    ' UDTs
    Type PlayerType1
        x1 As Integer ' left  foot x
        y1 As Integer ' left  foot y
        x2 As Integer ' right foot x
        y2 As Integer ' right foot y
        new_x1 As Integer ' left  foot x NEW
        new_y1 As Integer ' left  foot y NEW
        new_x2 As Integer ' right foot x NEW
        new_y2 As Integer ' right foot y NEW
        direction As Integer ' c_UP, c_DOWN, c_LEFT, c_RIGHT
        leftFootMovement As Integer ' c_FORWARD, c_NONE, c_BACK
        rightFootMovement As Integer ' c_FORWARD, c_NONE, c_BACK
        leftIsReady As Integer ' player cannot hold down key
        rightIsReady As Integer ' player cannot hold down key
        charLeft As String ' character to draw player with
        charRight As String ' character to draw player with
        score As Integer
    End Type ' PlayerType1

    Dim sError As String: sError = ""
    Dim bLeft As Integer
    Dim bRight As Integer
    Dim iLen As Integer
    Dim sMessage As String
    Dim arrPlayer(2) As PlayerType1
    Dim iPlayerLoop As Integer
    Dim iOtherLoop As Integer
    Dim arrMap(80, 80) As Integer
    Dim iLoopX As Integer
    Dim iLoopY As Integer
    'DIM bRefresh AS INTEGER
    Dim bTryMove As Integer
    Dim bDoMove As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim iWinner As Integer
    Dim bPlaying As Integer
    Dim bFinished As Integer

    ' INPUT VARIABLES
    Dim in$: in$ = ""
    Dim arrKeys(512) As Integer ' for tracking keypresses (probably not needed)
    Dim arrKeyMap(2, 10) As Integer ' for mapping keys to each player's action

    ' ================================================================================================================================================================
    ' INIT KEY MAPPINGS FOR EACH PLAYER
    If Len(sError) = 0 Then
        ' for now we're only supporting 2 players, but later will be 4-8

        ' Key                     _BUTTON       Action         For        Constant
        ' ---------------------   -----------   ------------   ---------  -------
        ' Left                    332           JOY #1 left    player 1   c_bKey_CrsrLeft
        ' Right                   334           JOY #1 right   player 1   c_bKey_CrsrRight
        ' Up                      329           JOY #1 up      player 1   c_bKey_CrsrUp
        ' Down                    337           JOY #1 down    player 1   c_bKey_CrsrDown
        ' Right Ctrl              286           JOY #1 fire    player 1   c_bKey_RightCtrl

        ' KEYPAD 4 Left           76            JOY #2 left    player 1   c_bKey_Kpad4
        ' KEYPAD 6 Right          78            JOY #2 right   player 1   c_bKey_Kpad6
        ' KEYPAD 8 Up             73            JOY #2 up      player 1   c_bKey_Kpad8
        ' KEYPAD 2 Down           81            JOY #2 down    player 1   c_bKey_Kpad2
        ' KEYPAD 0 Ins            83            JOY #2 fire    player 1   c_bKey_Kpad0

        ' A                       31            JOY #1 left    player 2   c_bKey_A
        ' S                       32            JOY #1 right   player 2   c_bKey_S
        ' W                       18            JOY #1 up      player 2   c_bKey_W
        ' Z                       45            JOY #1 down    player 2   c_bKey_Z
        ' Left Ctrl               30            JOY #1 fire    player 2   c_bKey_LeftCtrl

        ' J                       37            JOY #2 left    player 2   c_bKey_J
        ' K                       38            JOY #2 right   player 2   c_bKey_K
        ' I                       24            JOY #2 up      player 2   c_bKey_I
        ' M                       51            JOY #2 down    player 2   c_bKey_M
        ' SPACE                   58            JOY #2 fire    player 2   c_bKey_Space

        arrKeyMap(1, c_Map_Joy1_Left) = c_bKey_CrsrLeft
        arrKeyMap(1, c_Map_Joy1_Right) = c_bKey_CrsrRight
        arrKeyMap(1, c_Map_Joy1_Up) = c_bKey_CrsrUp
        arrKeyMap(1, c_Map_Joy1_Down) = c_bKey_CrsrDown
        arrKeyMap(1, c_Map_Joy1_Button) = c_bKey_RightCtrl

        arrKeyMap(1, c_Map_Joy2_Left) = c_bKey_Kpad4
        arrKeyMap(1, c_Map_Joy2_Right) = c_bKey_Kpad6
        arrKeyMap(1, c_Map_Joy2_Up) = c_bKey_Kpad8
        arrKeyMap(1, c_Map_Joy2_Down) = c_bKey_Kpad2
        arrKeyMap(1, c_Map_Joy2_Button) = c_bKey_Kpad0

        arrKeyMap(2, c_Map_Joy1_Left) = c_bKey_A
        arrKeyMap(2, c_Map_Joy1_Right) = c_bKey_S
        arrKeyMap(2, c_Map_Joy1_Up) = c_bKey_W
        arrKeyMap(2, c_Map_Joy1_Down) = c_bKey_Z
        arrKeyMap(2, c_Map_Joy1_Button) = c_bKey_LeftCtrl

        arrKeyMap(2, c_Map_Joy2_Left) = c_bKey_J
        arrKeyMap(2, c_Map_Joy2_Right) = c_bKey_K
        arrKeyMap(2, c_Map_Joy2_Up) = c_bKey_I
        arrKeyMap(2, c_Map_Joy2_Down) = c_bKey_M
        arrKeyMap(2, c_Map_Joy2_Button) = c_bKey_Space


        ' INITIALIZE GAME
        bPlaying = TRUE
        arrPlayer(1).score = 0
        arrPlayer(2).score = 0

    End If

    ' ================================================================================================================================================================
    ' INITIALIZE NEXT ROUND
    If Len(sError) = 0 Then

        Do ' LOOP UNTIL bPlaying=FALSE
            Cls
            Locate 1, 1: Print "Footrace! by Softintheheadware, 2005-2021           Press <ESC> to quit.";
            Locate 2, 1: Print "";
            Locate 3, 1: Print "PLAYER  LEFT FOOT    RIGHT FOOT             SCORE"
            Locate 4, 1: Print "1       Cursor keys  Numeric keypad arrows  " + cstr$(arrPlayer(1).score);
            Locate 5, 1: Print "2       A,S,W,Z      J,K,I,M                " + cstr$(arrPlayer(2).score);

            ' CLEAR PLAYING FIELD
            For iLoopY = 1 To 25
                For iLoopX = 1 To 80
                    arrMap(iLoopY, iLoopX) = 0
                Next iLoopX
            Next iLoopY

            iWinner = 0

            arrPlayer(1).x1 = 10
            arrPlayer(1).x2 = 11
            arrPlayer(1).y1 = 24
            arrPlayer(1).y2 = 24
            arrPlayer(1).new_x1 = 10
            arrPlayer(1).new_x2 = 11
            arrPlayer(1).new_y1 = 24
            arrPlayer(1).new_y2 = 24
            arrPlayer(1).direction = c_UP
            arrPlayer(1).leftFootMovement = c_NONE
            arrPlayer(1).rightFootMovement = c_NONE
            arrPlayer(1).leftIsReady = TRUE
            arrPlayer(1).rightIsReady = TRUE
            arrPlayer(1).charLeft = "A"
            arrPlayer(1).charRight = "V"

            arrPlayer(2).x1 = 40
            arrPlayer(2).x2 = 41
            arrPlayer(2).y1 = 24
            arrPlayer(2).y2 = 24
            arrPlayer(2).new_x1 = 40
            arrPlayer(2).new_x2 = 41
            arrPlayer(2).new_y1 = 24
            arrPlayer(2).new_y2 = 24
            arrPlayer(2).direction = c_UP
            arrPlayer(2).leftFootMovement = c_NONE
            arrPlayer(2).rightFootMovement = c_NONE
            arrPlayer(2).leftIsReady = TRUE
            arrPlayer(2).rightIsReady = TRUE
            arrPlayer(2).charLeft = "B"
            arrPlayer(2).charRight = "8"

            'bRefresh = TRUE

            ' DRAW BORDER AROUND PLAYING FIELD
            For iLoopY = 6 To 25
                arrMap(iLoopY, 1) = 1
                arrMap(iLoopY, 80) = 1
            Next iLoopY
            For iLoopX = 1 To 80
                arrMap(6, iLoopX) = 1
                arrMap(25, iLoopX) = 1
            Next iLoopX

            'PlotLine arrMap(),  6,  1,  6, 80, 1
            'PlotLine arrMap(),  6,  1, 25,  1, 1
            ''PlotLine arrMap(), 25, 80, 25,  1, 1
            'PlotLine arrMap(), 25,  1, 25, 80, 1
            ''PlotLine arrMap(), 25, 80,  1, 80, 1
            'PlotLine arrMap(),  1, 80, 25, 80, 1

            ' DRAW PYLONS
            For iLoopY = 10 To 20 Step 6
                For iLoopX = 6 To 76 Step 10
                    iY = iLoopY
                    For iX = iLoopX To iLoopX + 4
                        arrMap(iY, iX) = 1
                    Next iX
                    'PRINT "iLoopY=" + cstr$(iLoopY) + ", iLoopX=" + cstr$(iLoopX)
                    'PlotLine arrMap(), iY, iX, iY+4, iX, 1
                Next iLoopX

                If iLoopY < 20 Then
                    For iLoopX = 2 To 72 Step 10
                        iY = iLoopY + 3
                        For iX = iLoopX To iLoopX + 4
                            arrMap(iY, iX) = 1
                        Next iX
                        'PRINT "iLoopY=" + cstr$(iLoopY) + ", iLoopX=" + cstr$(iLoopX)
                        'PlotLine arrMap(), iY, iX+2, iY+4, iX+2, 1
                    Next iLoopX
                End If
            Next iLoopY

            ' DRAW FINISH LINE
            iLoopY = 8
            For iLoopX = 2 To 79
                arrMap(iLoopY, iLoopX) = 2
            Next iLoopX

            ' DRAW PLAYING FIELD
            For iLoopY = 6 To 25
                For iLoopX = 1 To 80
                    Locate iLoopY, iLoopX
                    If arrMap(iLoopY, iLoopX) = 1 Then
                        Print "#";
                    ElseIf arrMap(iLoopY, iLoopX) = 2 Then
                        Print "-";
                    Else
                        Print " ";
                    End If
                Next iLoopX
            Next iLoopY

            ' DRAW PLAYERS
            For iPlayerLoop = 1 To 2
                Locate arrPlayer(iPlayerLoop).y1, arrPlayer(iPlayerLoop).x1: Print arrPlayer(iPlayerLoop).charLeft;
                Locate arrPlayer(iPlayerLoop).y2, arrPlayer(iPlayerLoop).x2: Print arrPlayer(iPlayerLoop).charRight;
            Next iPlayerLoop

            ' ================================================================================================================================================================
            ' MAIN GAME LOOP

            Do ' LOOP UNTIL ( _KEYDOWN(c_KeyDown_Esc) OR (iWinner > 0) )

                ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                ' GET INPUT AND MOVE PLAYERS

                For iPlayerLoop = 1 To 2

                    ' READ KEYBOARD
                    While _DeviceInput(1): Wend ' clear and update the keyboard buffer

                    ' RESET MOVEMENT
                    bTryMove = FALSE
                    bDoMove = FALSE

                    ' READ JOYSTICK #1 INPUT = LEFT FOOT
                    If _Button(arrKeyMap(iPlayerLoop, c_Map_Joy1_Left)) Then

                        ' STICK #1 LEFT
                        If arrPlayer(iPlayerLoop).leftIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).leftIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    'DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    'arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x1
                                    'arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 - 1
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    'arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x1
                                    'arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x2
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf _Button(arrKeyMap(iPlayerLoop, c_Map_Joy1_Right)) Then
                        ' STICK #1 RIGHT
                        If arrPlayer(iPlayerLoop).leftIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).leftIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    'arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x2
                                    'arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x1
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf _Button(arrKeyMap(iPlayerLoop, c_Map_Joy1_Up)) Then
                        ' STICK #1 UP
                        If arrPlayer(iPlayerLoop).leftIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).leftIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    ElseIf _Button(arrKeyMap(iPlayerLoop, c_Map_Joy1_Down)) Then
                        ' STICK #1 DOWN
                        If arrPlayer(iPlayerLoop).leftIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).leftIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    Else
                        arrPlayer(iPlayerLoop).leftIsReady = TRUE
                    End If

                    ' READ JOYSTICK #2 INPUT = RIGHT FOOT
                    If _Button(arrKeyMap(iPlayerLoop, c_Map_Joy2_Left)) Then

                        ' STICK #1 LEFT
                        If arrPlayer(iPlayerLoop).rightIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).rightIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf _Button(arrKeyMap(iPlayerLoop, c_Map_Joy2_Right)) Then
                        ' STICK #1 RIGHT
                        If arrPlayer(iPlayerLoop).rightIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).rightIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                        End If

                    ElseIf _Button(arrKeyMap(iPlayerLoop, c_Map_Joy2_Up)) Then
                        ' STICK #1 UP
                        If arrPlayer(iPlayerLoop).rightIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).rightIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 - 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    ElseIf _Button(arrKeyMap(iPlayerLoop, c_Map_Joy2_Down)) Then
                        ' STICK #1 DOWN
                        If arrPlayer(iPlayerLoop).rightIsReady = TRUE Then
                            arrPlayer(iPlayerLoop).rightIsReady = FALSE

                            ' 1   A
                            '      B
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 2   B
                            '      A
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 3    A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 4    B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 5   AB
                            If arrPlayer(iPlayerLoop).x1 < arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 6   BA
                            If arrPlayer(iPlayerLoop).x1 > arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).y2 Then
                                    arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2 + 1
                                    bTryMove = TRUE
                                End If
                            End If

                            ' 7   A
                            '     B
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 < arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                            ' 8   B
                            '     A
                            If arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).x2 Then
                                If arrPlayer(iPlayerLoop).y1 > arrPlayer(iPlayerLoop).y2 Then
                                    ' DO NOTHING
                                End If
                            End If

                        End If

                    Else
                        arrPlayer(iPlayerLoop).rightIsReady = TRUE
                    End If

                    ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                    ' DID THE PLAYER TRY TO MOVE? SEE IF ANYTHING IS IN THE WAY

                    If bTryMove = TRUE Then
                        bDoMove = TRUE

                        ' TODO: PREVENT PLAYER FROM MOVING BOTH FEET AT ONCE!

                        ' IS PLAYER'S LEFT FOOT HITTING A WALL?
                        If arrMap(arrPlayer(iPlayerLoop).new_y1, arrPlayer(iPlayerLoop).new_x1) <> 1 Then
                            ' IS PLAYER'S RIGHT FOOT HITTING A WALL?
                            If arrMap(arrPlayer(iPlayerLoop).new_y2, arrPlayer(iPlayerLoop).new_x2) <> 1 Then
                                ' IS PLAYER HITTING ANOTHER PLAYER?
                                For iOtherLoop = 1 To 2
                                    If iOtherLoop <> iPlayerLoop Then
                                        ' IS PLAYER'S LEFT FOOT STEPPING ON ANOTHER PLAYER'S LEFT FOOT?
                                        If arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iOtherLoop).y1 Then
                                            If arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iOtherLoop).x1 Then
                                                ' COLLISION, DON'T MOVE
                                                bDoMove = FALSE
                                                Exit For
                                            End If
                                        End If
                                        ' IS PLAYER'S LEFT FOOT STEPPING ON ANOTHER PLAYER'S RIGHT FOOT?
                                        If arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iOtherLoop).y2 Then
                                            If arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iOtherLoop).x2 Then
                                                ' COLLISION, DON'T MOVE
                                                bDoMove = FALSE
                                                Exit For
                                            End If
                                        End If
                                        ' IS PLAYER'S RIGHT FOOT STEPPING ON ANOTHER PLAYER'S LEFT FOOT?
                                        If arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iOtherLoop).y1 Then
                                            If arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iOtherLoop).x1 Then
                                                ' COLLISION, DON'T MOVE
                                                bDoMove = FALSE
                                                Exit For
                                            End If
                                        End If
                                        ' IS PLAYER'S RIGHT FOOT STEPPING ON ANOTHER PLAYER'S RIGHT FOOT?
                                        If arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iOtherLoop).y2 Then
                                            If arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iOtherLoop).x2 Then
                                                ' COLLISION, DON'T MOVE
                                                bDoMove = FALSE
                                                Exit For
                                            End If
                                        End If
                                    End If
                                Next iOtherLoop
                            Else
                                ' COLLISION, DON'T MOVE
                                bDoMove = FALSE
                            End If
                        Else
                            ' COLLISION, DON'T MOVE
                            bDoMove = FALSE
                        End If

                        ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
                        ' MOVE OR DON'T MOVE

                        If bDoMove = TRUE Then
                            ' DID PLAYER CROSS THE FINISH LINE?
                            If arrMap(arrPlayer(iPlayerLoop).new_y1, arrPlayer(iPlayerLoop).new_x1) = 2 Then
                                iWinner = iPlayerLoop
                            ElseIf arrMap(arrPlayer(iPlayerLoop).new_y2, arrPlayer(iPlayerLoop).new_x2) = 2 Then
                                iWinner = iPlayerLoop
                            End If

                            ' MOVE THE PLAYER IF THEY ARE NOT BLOCKED
                            If (arrPlayer(iPlayerLoop).x1 <> arrPlayer(iPlayerLoop).new_x1) Or (arrPlayer(iPlayerLoop).y1 <> arrPlayer(iPlayerLoop).new_y1) Then
                                Locate arrPlayer(iPlayerLoop).y1, arrPlayer(iPlayerLoop).x1
                                Print " ";

                                arrPlayer(iPlayerLoop).y1 = arrPlayer(iPlayerLoop).new_y1
                                arrPlayer(iPlayerLoop).x1 = arrPlayer(iPlayerLoop).new_x1

                                Locate arrPlayer(iPlayerLoop).y1, arrPlayer(iPlayerLoop).x1
                                Print arrPlayer(iPlayerLoop).charLeft;
                            End If
                            If (arrPlayer(iPlayerLoop).x2 <> arrPlayer(iPlayerLoop).new_x2) Or (arrPlayer(iPlayerLoop).y2 <> arrPlayer(iPlayerLoop).new_y2) Then
                                Locate arrPlayer(iPlayerLoop).y2, arrPlayer(iPlayerLoop).x2
                                Print " ";

                                arrPlayer(iPlayerLoop).y2 = arrPlayer(iPlayerLoop).new_y2
                                arrPlayer(iPlayerLoop).x2 = arrPlayer(iPlayerLoop).new_x2

                                Locate arrPlayer(iPlayerLoop).y2, arrPlayer(iPlayerLoop).x2
                                Print arrPlayer(iPlayerLoop).charRight;
                            End If

                            'LOCATE 5,1: PRINT "Press <ESC> to quit.";
                        Else
                            ' REVERT NEW COORDS TO THE OLD COORDS
                            arrPlayer(iPlayerLoop).new_x1 = arrPlayer(iPlayerLoop).x1
                            arrPlayer(iPlayerLoop).new_y1 = arrPlayer(iPlayerLoop).y1
                            arrPlayer(iPlayerLoop).new_x2 = arrPlayer(iPlayerLoop).x2
                            arrPlayer(iPlayerLoop).new_y2 = arrPlayer(iPlayerLoop).y2
                        End If

                    End If
                    ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------


                    'IF _BUTTON(arrKeyMap(iPlayerLoop, c_Map_Button)) THEN ' BUTTON KEY IS CURRENTLY DOWN
                    '    'SOUND arrSound(iPlayerLoop), .75
                    'END IF

                Next iPlayerLoop

                _Limit 100 ' keep loop at 100 frames per second
            Loop Until (_KeyDown(c_KeyDown_Esc) Or (iWinner > 0)) ' leave loop when ESC key pressed

            ' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
            ' DID ANYONE WIN OR DID THEY JUST QUIT?
            If iWinner > 0 Then
                arrPlayer(iWinner).score = arrPlayer(iWinner).score + 1
                Locate 5, 1: Print "PLAYER " + cstr$(iWinner) + " WINS! Play again (Y / N) ?";
                bFinished = FALSE
                Do ' LOOP UNTIL bFinished
                    If _KeyDown(c_KeyDown_Y) Then
                        bFinished = TRUE
                    ElseIf _KeyDown(c_KeyDown_N) Then
                        bPlaying = FALSE
                        bFinished = TRUE
                    End If

                    _Limit 100 ' keep loop at 100 frames per second
                Loop Until bFinished ' leave loop when ESC key pressed
            Else
                ' NOPE, THEY QUIT -> SET FLAG TO EXIT GAME
                bPlaying = FALSE
            End If

        Loop Until (bPlaying = FALSE)

    End If

    If Len(sError) > 0 Then
        iLen = 40 - Len(sError): sMessage = sError + String$(iLen, " ")
        Locate 1, 1: Print sMessage;
        Locate 3, 1: WaitForEnter
    End If

    Footrace1$ = ""
End Function ' Footrace1$

' /////////////////////////////////////////////////////////////////////////////

Sub WaitForEnter
    Dim in$
    Input "Press <ENTER> to continue", in$
End Sub ' WaitForEnter

' /////////////////////////////////////////////////////////////////////////////

Function ColorTest$
    ' declarations
    Dim in$
    Dim iRow As Integer
    Dim iCol As Integer
    Dim iLoop As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim iRed As Integer
    Dim iGreen As Integer
    Dim iBlue As Integer
    ReDim arrColor(-1) As ColorType
    Dim sName As String
    Dim sDigits1 As String
    Dim sDigits2 As String
    Dim iForeColor As Integer
    Dim iBackColor As Integer

    ' INITIALIZE
    AddColors arrColor()

    ' SET UP SCREEN
    'Screen _NewImage(1024, 768, 32)
    Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
    Cls

    sDigits1 = "          111111"
    sDigits2 = "0123456789012345"
    Color cWhite, cBlack
    PrintString 0, 0, "                          111111"
    PrintString 1, 0, "Color #2 =    = 0123456789012345"
    PrintString 2, 0, "--------------------------------"

    iRow = 0
    For iForeColor = 0 To 15 ' 31
        Color cWhite, cBlack
        PrintString (iForeColor * 3) + 4, 0, "Color #1 = " + Right$("  " + cstr$(iForeColor), 2) + " = "
        For iBackColor = 0 To 15
            Color arrColor(iForeColor).value, arrColor(iBackColor).value
            PrintString (iForeColor * 3) + 4, iBackColor + 16, Mid$(sDigits1, iBackColor + 1, 1)
            PrintString (iForeColor * 3) + 5, iBackColor + 16, Mid$(sDigits2, iBackColor + 1, 1)
        Next iBackColor

        Color cWhite, cBlack
        PrintString (iForeColor * 3) + 4, 33, arrColor(iForeColor).name

    Next iForeColor

    Color cWhite, cBlack
    Locate 60, 1
    Input "PRESS <ENTER> TO CONTINUE"; in$

    Screen 0
    ColorTest$ = ""
End Function ' ColorTest$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END FOOTRACE v1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN INPUT MAPPING PART 1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Just a little test to verify _DEFAULTCOLOR and _BACKGROUNDCOLOR work.

Function DetectColor1$
    Dim sResult As String: sResult = ""
    ReDim arrColor(-1) As ColorType
    Dim ScreenArray(1 To 48, 1 To 128) As String
    Dim iRow As Integer
    Dim iCol As Integer
    Dim iForeColor As _Unsigned Long
    Dim iBackColor As _Unsigned Long
    Dim iY As Integer
    Dim iX As Integer
    Dim in$
    Dim iLoop1 As Integer
    Dim iLoop2 As Integer
    Dim sInfo As String
    Dim sNext As String
    Dim sData As String
    Dim sTest As String
    Dim iMaxLen As Integer
    Dim sValue1 As String
    Dim sValue2 As String

    ' INITIALIZE
    'AddColors arrColor()
    'StringToArray ScreenArray(), GetMap$
    ReDim _Preserve arrColor(1 To UBound(arrColor) + 1) As ColorType
    arrColor(UBound(arrColor)).name = "cRed"
    arrColor(UBound(arrColor)).value = cRed
    ReDim _Preserve arrColor(1 To UBound(arrColor) + 1) As ColorType
    arrColor(UBound(arrColor)).name = "cWhite"
    arrColor(UBound(arrColor)).value = cWhite
    ReDim _Preserve arrColor(1 To UBound(arrColor) + 1) As ColorType
    arrColor(UBound(arrColor)).name = "cBlue"
    arrColor(UBound(arrColor)).value = cBlue

    ' GET LEN
    iMaxLen = 0
    For iLoop1 = LBound(arrColor) To UBound(arrColor)
        If Len(arrColor(iLoop1).name) > iMaxLen Then
            iMaxLen = Len(arrColor(iLoop1).name)
        End If
    Next iLoop1

    ' SET UP SCREEN
    Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
    'Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0

    ' DISPLAY GRAPHICALLY
    Cls
    'For iY = LBound(ScreenArray, 1) To UBound(ScreenArray, 1)
    '    For iX = LBound(ScreenArray, 2) To UBound(ScreenArray, 2)
    '        iRow = iY - 1: iCol = iX - 1
    '        Color cRed, cBlack
    '        PrintString iRow, iCol, ScreenArray(iY, iX)
    '    Next iX
    'Next iY
    iRow = 0
    iCol = 0
    For iLoop1 = LBound(arrColor) To UBound(arrColor)
        For iLoop2 = LBound(arrColor) To UBound(arrColor)
            If iLoop1 <> iLoop2 Then
                iCol = 0
                iForeColor = arrColor(iLoop1).value
                iBackColor = arrColor(iLoop2).value
                'sInfo = "Color " + _Trim$(Str$(iForeColor)) + ", " + _Trim$(Str$(iBackColor))
                sInfo = "Color " + _
                    GetColorName$(arrColor(), iForeColor, _Trim$(Str$(iForeColor))) + _
                    ", " + _
                    GetColorName$(arrColor(), iBackColor, _Trim$(Str$(iBackColor)))
                Color cWhite, cBlack: PrintString iRow, iCol, sInfo

                sValue1 = arrColor(iLoop1).name + String$(iMaxLen, " ")
                sValue1 = Left$(sValue1, iMaxLen)
                sValue2 = arrColor(iLoop2).name + String$(iMaxLen, " ")
                sValue2 = Left$(sValue2, iMaxLen)
                sNext = sValue1 + " on " + sValue2
                iCol = Len(sInfo) + 1
                Color iForeColor, iBackColor: PrintString iRow, iCol, sNext

                'sData = "_DEFAULTCOLOR = " + _Trim$(Str$(_DEFAULTCOLOR)) + ", " + "_BACKGROUNDCOLOR = " + _Trim$(Str$(_BACKGROUNDCOLOR))
                'sTest = "_DEFAULTCOLOR " + IIFSTR$(_DEFAULTCOLOR = arrColor(iLoop1).value, "=", "!=") + " fgcolor" + _
                '    ", " + _
                '    "_BACKGROUNDCOLOR " + IIFSTR$(_BACKGROUNDCOLOR = arrColor(iLoop2).value, "=", "!=") + " bgcolor"
                'iCol = iCol + len(sNext) + 1
                'Color cWhite, cBlack : PrintString iRow, iCol, sData
                'iCol = iCol + len(sData) + 1
                'Color cWhite, cBlack : PrintString iRow, iCol, sTest

                sData = "_DEFAULTCOLOR = " + _
                    GetColorName$(arrColor(), _DEFAULTCOLOR, _Trim$(Str$(_DEFAULTCOLOR))) + _
                    ", " + _
                    "_BACKGROUNDCOLOR = " + _
                    GetColorName$(arrColor(), _BACKGROUNDCOLOR, _Trim$(Str$(_BACKGROUNDCOLOR)))
                iCol = iCol + Len(sNext) + 1
                Color cWhite, cBlack: PrintString iRow, iCol, sData

            End If
            iRow = iRow + 1
        Next iLoop2
    Next iLoop1

    '' Get color
    'iForeColor = _DEFAULTCOLOR
    'iBackColor = _BACKGROUNDCOLOR

    ' Show results
    'Cls
    Color cWhite, cBlack
    'print "Color cRed, cBlack"
    'print "Color " + _Trim$(Str$(cRed)) + ", " + _Trim$(Str$(cBlack))
    'print "_DEFAULTCOLOR=" + _Trim$(Str$(iForeColor))
    'print "_BACKGROUNDCOLOR=" + _Trim$(Str$(iBackColor))
    Locate iRow + 1, 1
    Input "PRESS <ENTER> TO CONTINUE"; in$

    ' RETURN RESULT
    DetectColor1$ = sResult
End Function ' DetectColor1$

' /////////////////////////////////////////////////////////////////////////////
' sName = GetColorName$(arrColor(), ColorValue, DefaultName)

Function GetColorName$ (arrColor() As ColorType, ColorValue As _Unsigned Long, DefaultName As String)
    Dim sResult As String
    Dim iLoop As Long
    sResult = DefaultName
    For iLoop = LBound(arrColor) To UBound(arrColor)
        If arrColor(iLoop).value = ColorValue Then
            sResult = arrColor(iLoop).name
            Exit For
        End If
    Next iLoop
    GetColorName$ = sResult
End Function ' GetColorName$

' /////////////////////////////////////////////////////////////////////////////
' TODO: get keyboard input working
' TODO: get continuous movement working for digital joysticks
' TODO: adjust analog joystick sensitivity

Function TestMappings1$
    Dim sResult As String: sResult = ""
    Dim sError As String: sError = ""

    Dim iDeviceCount As Integer
    Dim iDevice As Integer
    Dim iNumControllers As Integer
    Dim iController As Integer
    Dim iValue As Integer
    Dim iWhichInput As Integer

    Dim arrButton(32, 16) As Integer ' number of buttons on the joystick
    Dim arrButtonNew(32, 16) As Integer ' tracks when to initialize values
    Dim arrAxis(32, 16) As Double ' number of axis on the joystick
    Dim arrAxisNew(32, 16) As Integer ' tracks when to initialize values

    Dim iCols As Integer
    Dim iRows As Integer

    Dim iPlayer As Integer
    Dim iNextY As Integer
    Dim iNextX As Integer
    Dim iNextC As Integer

    Dim iMinX As Integer
    Dim iMaxX As Integer
    Dim iMinY As Integer
    Dim iMaxY As Integer

    Dim bHaveInput As Integer
    Dim bFinished As Integer
    Dim bFoundWho As Integer
    Dim bRepeat As Integer

    Dim in$

    ' MAKE SURE WE HAVE MAPPING
    If m_bHaveMapping = TRUE Then
        ' INITIALIZE
        Cls
        InitKeyboardButtonCodes
        iCols = _Width(0) \ _FontWidth
        iRows = _Height(0) \ _FontHeight
        iMinX = 0: iMaxX = iCols
        iMinY = 0: iMaxY = iRows

        ' INITIALIZE PLAYER COORDINATES AND SCREEN CHARACTERS
        iNextY = 1
        iNextX = -3
        iNextC = 64

        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
            iNextX = iNextX + 4
            If iNextX >= iMaxX Then
                iNextX = iMinX
                iNextY = iNextY + 4
                If iNextY > iMaxY Then
                    iNextY = iMinY
                End If
            End If
            iNextC = iNextC + 1
            m_arrPlayer(iPlayer).x = iNextX
            m_arrPlayer(iPlayer).y = iNextY
            m_arrPlayer(iPlayer).c = iNextC
            m_arrPlayer(iPlayer).xOld = iNextX
            m_arrPlayer(iPlayer).yOld = iNextY

            m_arrPlayer(iPlayer).moveX = 0
            m_arrPlayer(iPlayer).moveY = 0

            m_arrPlayer(iPlayer).moveUp = FALSE
            m_arrPlayer(iPlayer).moveDown = FALSE
            m_arrPlayer(iPlayer).moveLeft = FALSE
            m_arrPlayer(iPlayer).moveRight = FALSE
            m_arrPlayer(iPlayer).button1 = FALSE
            m_arrPlayer(iPlayer).button2 = FALSE
            m_arrPlayer(iPlayer).button3 = FALSE
            m_arrPlayer(iPlayer).button4 = FALSE

            m_arrPlayer(iPlayer).lastMoveUp = FALSE
            m_arrPlayer(iPlayer).lastMoveDown = FALSE
            m_arrPlayer(iPlayer).lastMoveLeft = FALSE
            m_arrPlayer(iPlayer).lastMoveRight = FALSE
            m_arrPlayer(iPlayer).lastButton1 = FALSE
            m_arrPlayer(iPlayer).lastButton2 = FALSE
            m_arrPlayer(iPlayer).lastButton3 = FALSE
            m_arrPlayer(iPlayer).lastButton4 = FALSE
        Next iPlayer

        ' COUNT # OF JOYSTICKS
        ' TODO: find out the right way to count joysticks
        If Len(sError) = 0 Then
            ' D= _DEVICES ' MUST be read in order for other 2 device functions to work!
            iDeviceCount = _Devices ' Find the number of devices on someone's system

            If iDeviceCount > 2 Then
                ' LIMIT # OF DEVICES, IF THERE IS A LIMIT DEFINED
                iNumControllers = iDeviceCount - 2
                If cMaxControllers > 0 Then
                    If iNumControllers > cMaxControllers Then
                        iNumControllers = cMaxControllers
                    End If
                End If
            Else
                ' ONLY 2 FOUND (KEYBOARD, MOUSE)
                'sError = "No game controllers found."
                iNumControllers = 0
            End If
        End If

        ' INITIALIZE CONTROLLER DATA
        If Len(sError) = 0 Then
            For iController = 1 To iNumControllers
                m_arrController(iController).buttonCount = cMaxButtons
                m_arrController(iController).axisCount = cMaxAxis
                For iLoop = 1 To cMaxButtons
                    arrButtonNew(iController, iLoop) = TRUE
                Next iLoop
                For iLoop = 1 To cMaxAxis
                    arrAxisNew(iController, iLoop) = TRUE
                Next iLoop
            Next iController
        End If

        ' INITIALIZE CONTROLLER INPUT
        If Len(sError) = 0 Then
            _KeyClear: _Delay 1
            For iController = 1 To iNumControllers
                iDevice = iController + 2
                While _DeviceInput(iDevice) ' clear and update the device buffer
                    For iLoop = 1 To _LastButton(iDevice)
                        If (iLoop > cMaxButtons) Then Exit For
                        m_arrController(iController).buttonCount = iLoop
                        arrButton(iController, iLoop) = FALSE
                    Next iLoop
                    For iLoop = 1 To _LastAxis(iDevice) ' this loop checks all my axis
                        If (iLoop > cMaxAxis) Then Exit For
                        m_arrController(iController).axisCount = iLoop
                        arrAxis(iController, iLoop) = 0
                    Next iLoop
                Wend ' clear and update the device buffer
            Next iController
        End If

        ' GET INPUT AND MOVE PLAYERS AROUND ON SCREEN
        _KeyClear: _Delay 1
        bFinished = FALSE
        Do
            ' Clear control buffer for players
            For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                m_arrPlayer(iPlayer).moveUp = FALSE
                m_arrPlayer(iPlayer).moveDown = FALSE
                m_arrPlayer(iPlayer).moveLeft = FALSE
                m_arrPlayer(iPlayer).moveRight = FALSE
                m_arrPlayer(iPlayer).button1 = FALSE
                m_arrPlayer(iPlayer).button2 = FALSE
                m_arrPlayer(iPlayer).button3 = FALSE
                m_arrPlayer(iPlayer).button4 = FALSE
            Next iPlayer

            ' -----------------------------------------------------------------------------
            ' BEGIN CHECK FOR CONTROLLER INPUT
            If iNumControllers > 0 Then
                For iController = 1 To iNumControllers
                    iDevice = iController + 2

                    ' Check all devices
                    While _DeviceInput(iDevice)
                    Wend ' clear and update the device buffer

                    ' Check each button
                    For iLoop = 1 To _LastButton(iDevice)
                        If (iLoop > cMaxButtons) Then Exit For

                        ' update button array to indicate if a button is up or down currently.
                        'if TRUE=TRUE then
                        If _ButtonChange(iLoop) Then
                            iValue = _Button(iLoop)
                            If iValue <> arrButton(iController, iLoop) Then
                                ' *****************************************************************************
                                ' PRESSED BUTTON

                                ' BEGIN find who this is mapped for
                                bFoundWho = FALSE
                                For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                                    For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                        If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                            If m_arrControlMap(iPlayer, iWhichInput).typ = cInputButton Then
                                                If m_arrControlMap(iPlayer, iWhichInput).code = iLoop Then
                                                    'if m_arrControlMap(iPlayer, iWhichInput).value = iValue then
                                                    bFoundWho = TRUE
                                                    Select Case iWhichInput
                                                        Case cInputUp:
                                                            m_arrPlayer(iPlayer).moveUp = TRUE
                                                        Case cInputDown:
                                                            m_arrPlayer(iPlayer).moveDown = TRUE
                                                        Case cInputLeft:
                                                            m_arrPlayer(iPlayer).moveLeft = TRUE
                                                        Case cInputRight:
                                                            m_arrPlayer(iPlayer).moveRight = TRUE
                                                        Case cInputButton1:
                                                            m_arrPlayer(iPlayer).button1 = TRUE
                                                        Case cInputButton2:
                                                            m_arrPlayer(iPlayer).button2 = TRUE
                                                        Case cInputButton3:
                                                            m_arrPlayer(iPlayer).button3 = TRUE
                                                        Case cInputButton4:
                                                            m_arrPlayer(iPlayer).button4 = TRUE
                                                        Case Else:
                                                            '(IGNORE)
                                                    End Select
                                                    Exit For
                                                    'end if
                                                End If
                                            End If
                                        End If
                                    Next iWhichInput
                                    If bFoundWho = TRUE Then Exit For
                                Next iPlayer
                                ' END find who this is mapped for

                            End If
                        End If
                    Next iLoop

                    ' Check each axis
                    For iLoop = 1 To _LastAxis(iDevice)
                        If (iLoop > cMaxAxis) Then Exit For
                        dblNextAxis = _Axis(iLoop)
                        dblNextAxis = RoundUpDouble#(dblNextAxis, 3)

                        ' I like to give a little "jiggle" resistance to my controls, as I have an old joystick
                        ' which is prone to always give minute values and never really center on true 0.
                        ' A value of 1 means my axis is pushed fully in one direction.
                        ' A value greater than 0.1 means it's been partially pushed in a direction (such as at a 45 degree diagional angle).
                        ' A value of less than 0.1 means we count it as being centered. (As if it was 0.)

                        ' Set sensitivity:
                        'These are way too sensitive for analog:
                        'IF ABS(_AXIS(iLoop)) <= 1 AND ABS(_AXIS(iLoop)) >= .1 THEN
                        'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .01 THEN
                        'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .001 THEN
                        ''For digital input, we'll use a big picture:
                        'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= 0.75 THEN
                        If Abs(dblNextAxis) <= 1 And Abs(dblNextAxis) >= 0.5 Then

                            ' WE WANT CONTINUOUS MOVEMENT (DISABLE FOR NOT)
                            'if TRUE=TRUE then
                            If dblNextAxis <> arrAxis(iController, iLoop) Then
                                ' *****************************************************************************
                                ' MOVED STICK

                                ' convert to a digital value
                                If dblNextAxis < 0 Then
                                    iValue = -1
                                Else
                                    iValue = 1
                                End If

                                ' BEGIN find who this is mapped for
                                bFoundWho = FALSE
                                For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                                    For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                                        If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                            If m_arrControlMap(iPlayer, iWhichInput).typ = cInputAxis Then
                                                If m_arrControlMap(iPlayer, iWhichInput).code = iLoop Then
                                                    If m_arrControlMap(iPlayer, iWhichInput).value = iValue Then
                                                        bFoundWho = TRUE
                                                        Select Case iWhichInput
                                                            Case cInputUp:
                                                                m_arrPlayer(iPlayer).moveUp = TRUE
                                                            Case cInputDown:
                                                                m_arrPlayer(iPlayer).moveDown = TRUE
                                                            Case cInputLeft:
                                                                m_arrPlayer(iPlayer).moveLeft = TRUE
                                                            Case cInputRight:
                                                                m_arrPlayer(iPlayer).moveRight = TRUE
                                                            Case cInputButton1:
                                                                m_arrPlayer(iPlayer).button1 = TRUE
                                                            Case cInputButton2:
                                                                m_arrPlayer(iPlayer).button2 = TRUE
                                                            Case cInputButton3:
                                                                m_arrPlayer(iPlayer).button3 = TRUE
                                                            Case cInputButton4:
                                                                m_arrPlayer(iPlayer).button4 = TRUE
                                                            Case Else:
                                                                '(IGNORE)
                                                        End Select
                                                        Exit For
                                                    End If
                                                End If
                                            End If
                                        End If
                                    Next iWhichInput
                                    If bFoundWho = TRUE Then Exit For
                                Next iPlayer
                                ' END find who this is mapped for

                            End If
                        End If
                    Next iLoop

                Next iController
            End If
            ' END CHECK FOR CONTROLLER INPUT
            ' -----------------------------------------------------------------------------

            ' -----------------------------------------------------------------------------
            ' BEGIN CHECK FOR KEYBOARD INPUT #1
            '_KEYCLEAR: _DELAY 1
            While _DeviceInput(1): Wend ' clear and update the keyboard buffer

            ' Detect changed key state
            iDevice = 1 ' keyboard
            For iLoop = LBound(m_arrButtonCode) To UBound(m_arrButtonCode)
                iCode = m_arrButtonCode(iLoop)
                If _Button(iCode) <> FALSE Then
                    ' *****************************************************************************
                    ' PRESSED KEYBOARD
                    'PRINT "PRESSED " + m_arrButtonKey(iLoop)

                    ' BEGIN find who this is mapped for
                    bFoundWho = FALSE
                    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
                        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                            If m_arrControlMap(iPlayer, iWhichInput).device = iDevice Then
                                If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                                    'if m_arrControlMap(iPlayer, iWhichInput).code = iLoop then
                                    If m_arrControlMap(iPlayer, iWhichInput).code = iCode Then
                                        'if m_arrControlMap(iPlayer, iWhichInput).value = iValue then
                                        bFoundWho = TRUE
                                        Select Case iWhichInput
                                            Case cInputUp:
                                                m_arrPlayer(iPlayer).moveUp = TRUE
                                            Case cInputDown:
                                                m_arrPlayer(iPlayer).moveDown = TRUE
                                            Case cInputLeft:
                                                m_arrPlayer(iPlayer).moveLeft = TRUE
                                            Case cInputRight:
                                                m_arrPlayer(iPlayer).moveRight = TRUE
                                            Case cInputButton1:
                                                m_arrPlayer(iPlayer).button1 = TRUE
                                            Case cInputButton2:
                                                m_arrPlayer(iPlayer).button2 = TRUE
                                            Case cInputButton3:
                                                m_arrPlayer(iPlayer).button3 = TRUE
                                            Case cInputButton4:
                                                m_arrPlayer(iPlayer).button4 = TRUE
                                            Case Else:
                                                '(IGNORE)
                                        End Select
                                        Exit For
                                        'end if
                                    End If
                                End If
                            End If
                        Next iWhichInput
                        If bFoundWho = TRUE Then Exit For
                    Next iPlayer
                    ' END find who this is mapped for

                End If
            Next iLoop
            ' END CHECK FOR KEYBOARD INPUT #1
            ' -----------------------------------------------------------------------------

            ' NOW DRAW PLAYERS ON SCREEN
            For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)

                ' -----------------------------------------------------------------------------
                ' BEGIN UPDATE MOVEMENT CONTROL STATES
                ' If repeating keys are disabled then
                ' disable until the key has been released

                If m_arrControlMap(iPlayer, cInputUp).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).moveUp = TRUE Then
                        If m_arrPlayer(iPlayer).lastMoveUp = TRUE Then
                            m_arrPlayer(iPlayer).moveUp = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastMoveUp = FALSE
                    End If
                End If

                If m_arrControlMap(iPlayer, cInputDown).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).moveDown = TRUE Then
                        If m_arrPlayer(iPlayer).lastMoveDown = TRUE Then
                            m_arrPlayer(iPlayer).moveDown = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastMoveDown = FALSE
                    End If
                End If

                If m_arrControlMap(iPlayer, cInputLeft).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).moveLeft = TRUE Then
                        If m_arrPlayer(iPlayer).lastMoveLeft = TRUE Then
                            m_arrPlayer(iPlayer).moveLeft = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastMoveLeft = FALSE
                    End If
                End If

                If m_arrControlMap(iPlayer, cInputRight).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).moveRight = TRUE Then
                        If m_arrPlayer(iPlayer).lastMoveRight = TRUE Then
                            m_arrPlayer(iPlayer).moveRight = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastMoveRight = FALSE
                    End If
                End If
                ' END UPDATE MOVEMENT CONTROL STATES
                ' -----------------------------------------------------------------------------

                ' -----------------------------------------------------------------------------
                ' BEGIN MOVEMENT ACTIONS

                m_arrPlayer(iPlayer).moveY = 0
                m_arrPlayer(iPlayer).moveX = 0

                If m_arrPlayer(iPlayer).moveUp = TRUE Then
                    m_arrPlayer(iPlayer).moveY = -1
                    m_arrPlayer(iPlayer).lastMoveUp = TRUE
                End If

                If m_arrPlayer(iPlayer).moveDown = TRUE Then
                    m_arrPlayer(iPlayer).moveY = 1
                    m_arrPlayer(iPlayer).lastMoveDown = TRUE
                End If

                If m_arrPlayer(iPlayer).moveLeft = TRUE Then
                    m_arrPlayer(iPlayer).moveX = -1
                    m_arrPlayer(iPlayer).lastMoveLeft = TRUE
                End If

                If m_arrPlayer(iPlayer).moveRight = TRUE Then
                    m_arrPlayer(iPlayer).moveX = 1
                    m_arrPlayer(iPlayer).lastMoveRight = TRUE
                End If
                ' END MOVEMENT ACTIONS
                ' -----------------------------------------------------------------------------


                ' -----------------------------------------------------------------------------
                ' BEGIN MOVEMENT

                ' MOVE RIGHT/LEFT
                m_arrPlayer(iPlayer).x = m_arrPlayer(iPlayer).x + m_arrPlayer(iPlayer).moveX
                If m_arrPlayer(iPlayer).x < iMinX Then
                    m_arrPlayer(iPlayer).x = m_arrPlayer(iPlayer).xOld ' iMinX
                ElseIf m_arrPlayer(iPlayer).x > iMaxX Then
                    m_arrPlayer(iPlayer).x = m_arrPlayer(iPlayer).xOld ' iMaxX
                End If

                ' MOVE UP/DOWN
                m_arrPlayer(iPlayer).y = m_arrPlayer(iPlayer).y + m_arrPlayer(iPlayer).moveY
                If m_arrPlayer(iPlayer).y < iMinY Then
                    m_arrPlayer(iPlayer).y = m_arrPlayer(iPlayer).yOld ' iMinY
                ElseIf m_arrPlayer(iPlayer).y > iMaxY Then
                    m_arrPlayer(iPlayer).y = m_arrPlayer(iPlayer).yOld ' iMaxY
                End If

                ' UPDATE SCREEN
                '_PRINTSTRING (m_arrPlayer(iPlayer).xOld, m_arrPlayer(iPlayer).yOld), " "
                '_PRINTSTRING (m_arrPlayer(iPlayer).x, m_arrPlayer(iPlayer).y), CHR$(m_arrPlayer(iPlayer).c)
                PrintStringCR1 m_arrPlayer(iPlayer).xOld, m_arrPlayer(iPlayer).yOld, " "
                PrintStringCR1 m_arrPlayer(iPlayer).x, m_arrPlayer(iPlayer).y, Chr$(m_arrPlayer(iPlayer).c)
                m_arrPlayer(iPlayer).xOld = m_arrPlayer(iPlayer).x
                m_arrPlayer(iPlayer).yOld = m_arrPlayer(iPlayer).y

                ' END MOVEMENT
                ' -----------------------------------------------------------------------------







                ' -----------------------------------------------------------------------------
                ' BEGIN UPDATE BUTTON STATES
                ' If repeating keys are disabled then
                ' disable until the key has been released

                'if m_bRepeatButton1 = FALSE then
                If m_arrControlMap(iPlayer, cInputButton1).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).button1 = TRUE Then
                        If m_arrPlayer(iPlayer).lastButton1 = TRUE Then
                            m_arrPlayer(iPlayer).button1 = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastButton1 = FALSE
                    End If
                End If
                If m_arrControlMap(iPlayer, cInputButton2).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).button2 = TRUE Then
                        If m_arrPlayer(iPlayer).lastButton2 = TRUE Then
                            m_arrPlayer(iPlayer).button2 = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastButton2 = FALSE
                    End If
                End If
                If m_arrControlMap(iPlayer, cInputButton3).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).button3 = TRUE Then
                        If m_arrPlayer(iPlayer).lastButton3 = TRUE Then
                            m_arrPlayer(iPlayer).button3 = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastButton3 = FALSE
                    End If
                End If
                If m_arrControlMap(iPlayer, cInputButton4).repeat = FALSE Then
                    If m_arrPlayer(iPlayer).button4 = TRUE Then
                        If m_arrPlayer(iPlayer).lastButton4 = TRUE Then
                            m_arrPlayer(iPlayer).button4 = FALSE
                        End If
                    Else
                        m_arrPlayer(iPlayer).lastButton4 = FALSE
                    End If
                End If
                ' END UPDATE BUTTON STATES
                ' -----------------------------------------------------------------------------



                ' -----------------------------------------------------------------------------
                ' BEGIN BUTTON ACTIONS
                If m_arrPlayer(iPlayer).button1 = TRUE Then
                    MakeSound iPlayer, 1
                    m_arrPlayer(iPlayer).lastButton1 = TRUE
                End If

                If m_arrPlayer(iPlayer).button2 = TRUE Then
                    MakeSound iPlayer, 2
                    m_arrPlayer(iPlayer).lastButton2 = TRUE
                End If

                If m_arrPlayer(iPlayer).button3 = TRUE Then
                    MakeSound iPlayer, 3
                    m_arrPlayer(iPlayer).lastButton3 = TRUE
                End If

                If m_arrPlayer(iPlayer).button4 = TRUE Then
                    MakeSound iPlayer, 4
                    m_arrPlayer(iPlayer).lastButton4 = TRUE
                End If
                ' END BUTTON ACTIONS
                ' -----------------------------------------------------------------------------

            Next iPlayer

            _Limit 30
        Loop Until _KeyHit = 27 ' ESCAPE to quit
        _KeyClear: _Delay 1

        sResult = sError
    Else
        sResult = "No mapping loaded. Please load a mapping or map keys."
    End If

    TestMappings1$ = sResult
End Function ' TestMappings1$

' /////////////////////////////////////////////////////////////////////////////

Sub MakeSound (iPlayer As Integer, iButton As Integer)
    Dim note%
    If iPlayer < 1 Then
        iPlayer = 1
    ElseIf iPlayer > 8 Then
        iPlayer = 8
    End If
    If iButton < 1 Then
        iButton = 1
    ElseIf iButton > 4 Then
        iButton = 4
    End If

    note% = iPlayer * 100 + (iButton * 25)
    If note% > 4186 Then
        note% = 4186
    End If
    Sound note%, .75
End Sub ' MakeSound

' /////////////////////////////////////////////////////////////////////////////
' V2 prints in 2 columns.

Sub PrintControllerMap2
    Dim RoutineName As String:: RoutineName = "PrintControllerMap2"
    Dim iPlayer As Integer
    Dim iWhichInput As Integer
    Dim iCount As Integer
    Dim sLine As String
    Dim iHalf As Integer
    Dim sColumn1 As String: sColumn1 = ""
    Dim sColumn2 As String: sColumn2 = ""
    ReDim arrColumn1(-1) As String
    ReDim arrColumn2(-1) As String
    Dim iLoop As Integer
    Dim iColWidth As Integer: iColWidth = 75
    Dim sValue As String
    Dim in$

    ' INITIALIZE
    InitKeyboardButtonCodes

    ' START OUTPUT
    Print "Controller mapping:"
    'Print "Player#  Input      Device#  Type     Code              Value"
    '       1        button #2  x        unknown  x                 x
    '       9        11         9        9        18                9
    '       12345678912345678901123456789123456789123456789012345678123456789
    '       12345678901234567890123456789012345678901234567890123456789012345678901234567890
    '       00000000011111111112222222222333333333344444444445555555555666666666677777777778

    If m_bHaveMapping = TRUE Then
        ' THIS IS A LAZY WAY TO GET 2 COLUMNS!
        iHalf = UBound(m_arrControlMap, 1) / 2

        sLine = "Player#  Input      Device#  Type     Code              Value    Repeat"
        sColumn1 = sColumn1 + StrPadRight$(sLine, iColWidth) + Chr$(13)
        sLine = "-----------------------------------------------------------------------"
        sColumn1 = sColumn1 + StrPadRight$(sLine, iColWidth) + Chr$(13)
        For iPlayer = LBound(m_arrControlMap, 1) To iHalf
            iCount = 0
            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                    iCount = iCount + 1
                End If
            Next iWhichInput
            If iCount > 0 Then
                For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                    If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                        sLine = IntPadRight$(iPlayer, 9)
                        sLine = sLine + StrPadRight$(InputToString$(iWhichInput), 11)
                        sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).device, 9)
                        sLine = sLine + StrPadRight$(InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ), 9)

                        'sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).code, 9)
                        If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                            sValue = GetKeyboardButtonCodeText$(m_arrControlMap(iPlayer, iWhichInput).code)
                            sValue = StrPadRight$(sValue, 18)
                        Else
                            sValue = IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).code, 18)
                        End If
                        sLine = sLine + sValue

                        sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).value, 9)

                        sValue = TrueFalse$(m_arrControlMap(iPlayer, iWhichInput).repeat)
                        sLine = sLine + StrPadRight$(sValue, 6)

                        'Print sLine
                        sLine = StrPadRight$(sLine, iColWidth)
                        sColumn1 = sColumn1 + sLine + Chr$(13)
                    End If
                Next iWhichInput
            Else
                sLine = IntPadRight$(iPlayer, 9) + "(NONE)"
                'Print sLine
                sLine = StrPadRight$(sLine, iColWidth)
                sColumn1 = sColumn1 + sLine + Chr$(13)
            End If
        Next iPlayer

        'sLine = "Player#  Input      Device#  Type     Code              Value"
        sLine = "Player#  Input      Device#  Type     Code              Value    Repeat"
        sColumn2 = sColumn2 + StrPadRight$(sLine, iColWidth) + Chr$(13)
        'sLine = "-------------------------------------------------------------"
        sLine = "-----------------------------------------------------------------------"
        sColumn2 = sColumn2 + StrPadRight$(sLine, iColWidth) + Chr$(13)
        For iPlayer = iHalf + 1 To UBound(m_arrControlMap, 1)
            iCount = 0
            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                    iCount = iCount + 1
                End If
            Next iWhichInput
            If iCount > 0 Then
                For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                    If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                        sLine = IntPadRight$(iPlayer, 9)
                        sLine = sLine + StrPadRight$(InputToString$(iWhichInput), 11)
                        sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).device, 9)
                        sLine = sLine + StrPadRight$(InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ), 9)

                        'sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).code, 9)
                        If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                            sValue = GetKeyboardButtonCodeText$(m_arrControlMap(iPlayer, iWhichInput).code)
                            sValue = StrPadRight$(sValue, 18)
                        Else
                            sValue = IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).code, 18)
                        End If
                        sLine = sLine + sValue

                        sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).value, 9)

                        sValue = TrueFalse$(m_arrControlMap(iPlayer, iWhichInput).repeat)
                        sLine = sLine + StrPadRight$(sValue, 6)

                        'Print sLine
                        sLine = StrPadRight$(sLine, iColWidth)
                        sColumn2 = sColumn2 + sLine + Chr$(13)
                    End If
                Next iWhichInput
            Else
                sLine = IntPadRight$(iPlayer, 9) + "(NONE)"
                'Print sLine
                sLine = StrPadRight$(sLine, iColWidth)
                sColumn2 = sColumn2 + sLine + Chr$(13)
            End If
        Next iPlayer

        split sColumn1, Chr$(13), arrColumn1()
        split sColumn2, Chr$(13), arrColumn2()
        If UBound(arrColumn1) > UBound(arrColumn2) Then
            iCount = UBound(arrColumn1)
        Else
            iCount = UBound(arrColumn2)
        End If
        For iLoop = 0 To iCount
            sLine = ""
            If UBound(arrColumn1) >= iLoop Then
                sLine = sLine + arrColumn1(iLoop)
            Else
                sLine = sLine + String$(iColWidth, " ")
            End If
            sLine = sLine + "     "
            If UBound(arrColumn2) >= iLoop Then
                sLine = sLine + arrColumn2(iLoop)
            Else
                sLine = sLine + String$(iColWidth, " ")
            End If
            Print sLine
        Next iLoop
    Else
        Print "No mapping loaded. Please load a mapping or map keys."
    End If

End Sub ' PrintControllerMap2

' /////////////////////////////////////////////////////////////////////////////
' Original (simple) routine

Sub PrintControllerMap1
    Dim RoutineName As String:: RoutineName = "PrintControllerMap1"
    Dim iPlayer As Integer
    Dim iWhichInput As Integer
    Dim sLine As String
    Dim iNum As Integer
    Dim iCount As Integer
    Dim sValue As String
    Dim iMapCount As Integer
    Dim in$
    Dim sError As String: sError = ""

    ' MAKE SURE WE HAVE MAPPING
    If m_bHaveMapping <> TRUE Then
        sError = "No mapping loaded. Please load a mapping or map keys."
    End If

    ' INITIALIZE
    If Len(sError) = 0 Then
        InitKeyboardButtonCodes
    End If

    ' OUTPUT MAPPING
    If Len(sError) = 0 Then
        iCount = (UBound(m_arrControlMap, 1) - LBound(m_arrControlMap, 1)) + 1
        iNum = 0
        For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
            iNum = iNum + 1

            Cls
            Print "Controller mapping " + cstr$(iNum) + " of " + cstr$(iCount) + ":"
            Print "Player#  Input      Device#  Type     Code             Value      Repeat"
            '      1        button #2  x        unknown  x                x          TRUE
            '      9        11         9        9        9                9          FALSE
            '               11111111112222222222333333333344444444445555555555666666666677777777778
            '      12345678901234567890123456789012345678901234567890123456789012345678901234567890

            ' COUNT KNOWN MAPPED INPUTS FOR NEXT PLAYER'S CONTROLLER
            iCount = 0
            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                    iCount = iCount + 1
                End If
            Next iWhichInput

            ' OUTPUT INPUTS FOR THIS PLAYER'S CONTROLLER
            If iCount > 0 Then
                For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                    If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                        sLine = IntPadRight$(iPlayer, 9)
                        sLine = sLine + StrPadRight$(InputToString$(iWhichInput), 11)
                        sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).device, 9)
                        sLine = sLine + StrPadRight$(InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ), 9)

                        'sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).code, 9)
                        If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                            sValue = GetKeyboardButtonCodeText$(m_arrControlMap(iPlayer, iWhichInput).code)
                            'sValue = StrPadRight$(sValue, 18)
                        Else
                            'sValue = IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).code, 18)
                            sValue = _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).code))
                        End If
                        sValue = StrPadRight$(sValue, 15) + "  "
                        sLine = sLine + sValue

                        sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).value, 9) + "  "

                        sLine = sLine + TrueFalse$(m_arrControlMap(iPlayer, iWhichInput).repeat)
                        Print sLine
                    End If
                Next iWhichInput
            Else
                ' NO MAPPED INPUTS FOR THIS PLAYER'S CONTROLLER
                sLine = IntPadRight$(iPlayer, 9) + "(NONE)"
                Print sLine
            End If

            If m_bMappingChanged = TRUE Then
                Print
                Print "*** UNSAVED CHANGES DETECTED ***"
            End If

            ' DO PAGING
            Print
            Print "PRESS <ENTER> TO CONTINUE OR <ESC> TO EXIT"
            Do
                in$ = InKey$
                If in$ = Chr$(13) Or in$ = Chr$(27) Then Exit Do
            Loop

            If in$ = Chr$(27) Then
                Exit For
            End If

        Next iPlayer

    End If

    ' GET FINAL INPUT
    If in$ = Chr$(13) Or Len(sError) > 0 Then
        If Len(sError) > 0 Then Cls: Print sError
        Print "FINISHED. PRESS <ESC> TO EXIT"
        Do
            in$ = InKey$
            If in$ = Chr$(27) Then Exit Do
        Loop
    End If

    _KeyClear: _Delay 1
End Sub ' PrintControllerMap1

' /////////////////////////////////////////////////////////////////////////////
' Simple routine
' enables debugging, prints to debug window
' when done disables debugging (if it was disabled to begin with)

Sub DumpControllerMap1
    Dim RoutineName As String:: RoutineName = "DumpControllerMap1"
    Dim iPlayer As Integer
    Dim iWhichInput As Integer
    Dim sLine As String
    Dim iCount As Integer
    Dim in$
    Dim bTesting As Integer

    ' ENABLE DEEBUGGING (IF NOT ENABLED)
    bTesting = m_bDebug

    ' ACTIVATE DEBUGGING WINDOW (IF NOT ACTIVATED)
    If m_bDebug = FALSE Then
        m_bDebug = TRUE

        $Console
        _Delay 4
        _Console On
        _Echo "Started " + m_ProgramName$
        _Echo "Debugging on..."
    End If

    ' INITIALIZE
    InitKeyboardButtonCodes

    ' OUTPUT MAPPING
    DebugPrint "INPUT MAPPING"
    DebugPrint ""
    DebugPrint "Have mapping values? m_bHaveMapping    = " + TrueFalse$(m_bHaveMapping)
    DebugPrint "Are changes unsaved? m_bMappingChanged = " + TrueFalse$(m_bMappingChanged)
    DebugPrint ""

    DebugPrint "Player#  Input      Device#  Type     Code             Value      Repeat"
    '           1        button #2  x        unknown  x                x          TRUE
    '           9        11         9        9        9                9          FALSE
    '           12345678912345678901123456789123456789123456789123456789
    '           12345678901234567890123456789012345678901234567890123456789012345678901234567890
    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
        iCount = 0
        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
            If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                iCount = iCount + 1
            End If
        Next iWhichInput
        If iCount > 0 Then
            For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                    sLine = IntPadRight$(iPlayer, 9)
                    sLine = sLine + StrPadRight$(InputToString$(iWhichInput), 11)
                    sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).device, 9)
                    sLine = sLine + StrPadRight$(InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ), 9)
                    sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).code, 15)
                    sLine = sLine + "  "
                    sLine = sLine + IntPadRight$(m_arrControlMap(iPlayer, iWhichInput).value, 9)
                    sLine = sLine + "  "
                    sLine = sLine + TrueFalse$(m_arrControlMap(iPlayer, iWhichInput).repeat)
                    DebugPrint sLine
                End If
            Next iWhichInput
        Else
            sLine = IntPadRight$(iPlayer, 9) + "(NONE)"
            DebugPrint sLine
        End If
    Next iPlayer

    ' WAIT FOR USER
    Cls
    Print "Controller mapping written to console window."
    Input "PRESS <ENTER> TO CONTINUE"; in$

    ' DEACTIVATE DEBUGGING WINDOW (IF IT WAS NOT ACTIVATED BEFORE)
    If bTesting = FALSE Then
        m_bDebug = FALSE

        _Console Off
    End If

End Sub ' DumpControllerMap1

' /////////////////////////////////////////////////////////////////////////////

Function LoadMappings1$
    Dim sResult As String: sResult = ""

    ' INITIALIZE
    InitKeyboardButtonCodes

    ' Try loading map
    sResult = LoadControllerMap1$

    LoadMappings1$ = sResult
End Function ' LoadMappings1$

' /////////////////////////////////////////////////////////////////////////////

Function SaveMappings1$
    Dim sResult As String: sResult = ""
    Dim sError As String: sError = ""

    ' INITIALIZE
    InitKeyboardButtonCodes

    ' Try saving map
    sResult = SaveControllerMap1$

    SaveMappings1$ = sResult
End Function ' SaveMappings1$


' /////////////////////////////////////////////////////////////////////////////

Function ViewMappings2$
    ' INITIALIZE
    InitKeyboardButtonCodes

    PrintControllerMap2
    Print
    Input "PRESS <ENTER> TO CONTINUE", in$
    Print
    ViewMappings2$ = ""
End Function ' ViewMappings2$

' /////////////////////////////////////////////////////////////////////////////
' TODO: test this

Function EditMappings1$
    Dim RoutineName As String: RoutineName = "EditMappings1$"
    Dim in$
    Dim iPlayer As Integer
    Dim iWhichInput As Integer
    Dim iDevice As Integer
    Dim iType As Integer
    Dim iCode As Integer
    Dim iValue As Integer
    Dim iRepeat As Integer
    Dim iItem As Integer
    Dim sResult As String: sResult = ""
    Dim bContinue1 As Integer: bContinue1 = TRUE
    Dim bContinue2 As Integer: bContinue2 = TRUE
    Dim bContinue3 As Integer: bContinue3 = TRUE
    Dim bContinue4 As Integer: bContinue4 = TRUE

    ' INITIALIZE
    InitKeyboardButtonCodes

    ' EDIT
    Do
        PrintControllerMap2
        Print "To edit a mapping, enter a player number: " _
            "1-" + cstr$(cMaxPlayers) + ", " + _
            cstr$(cMaxPlayers+1) + ") or q to exit."
        Input "Edit mapping for player"; in$
        If IsNum%(in$) Then
            iPlayer = Val(in$)
            If iPlayer > 0 And iPlayer <= cMaxPlayers Then
                bContinue2 = TRUE
                Do
                    Print "Editing mappings for player " + cstr$(iPlayer) + "."
                    For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                        'Print right$("  " + cstr$(iWhichInput), 2) + ". " + InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ)
                        Print Right$("  " + cstr$(iWhichInput), 2) + ". " + InputToString$(iWhichInput)
                    Next iWhichInput
                    Input "Type # of control to edit or q to quit editing player"; in$
                    If IsNum%(in$) Then
                        iWhichInput = Val(in$)
                        If iWhichInput >= LBound(m_arrControlMap, 2) And m_arrControlMap <= UBound(m_arrControlMap, 2) Then
                            bContinue3 = TRUE
                            Do
                                Print "Settings for " + InputToString$(iWhichInput) + ":"
                                Print "1. Device #     : " + cstr$(m_arrControlMap(iPlayer, iWhichInput).device)
                                Print "2. Device type  : " + InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ)

                                If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                                    Print "3. Input code   : " + GetKeyboardButtonCodeText$(m_arrControlMap(iPlayer, iWhichInput).code) + _
                                        " (" + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).code)) + ")"
                                Else
                                    Print "3. Input code   : " + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).code))
                                End If

                                Print "4. Input value  : " + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).value))
                                Print "5. Enable repeat: " + TrueFalse$(m_arrControlMap(iPlayer, iWhichInput).repeat)
                                Input "Change item? (1-5 or q to quit editing control)"; in$
                                If IsNum%(in$) Then
                                    iItem = Val(in$)
                                    Select Case iItem
                                        Case 1:
                                            Print "Change the device number."
                                            Input "Type a new device #, 0 for none (disabled), or blank to leave it unchanged"; in$
                                            If IsNum%(in$) Then
                                                iDevice = Val(in$)
                                                If m_arrControlMap(iPlayer, iWhichInput).device <> iDevice Then
                                                    m_arrControlMap(iPlayer, iWhichInput).device = iDevice
                                                    Print "Updated device number. Remember to save mappings when done."
                                                    m_bMappingChanged = TRUE
                                                Else
                                                    Print "(No change.)"
                                                End If
                                            Else
                                                Print "(No change.)"
                                            End If
                                        Case 2:
                                            bContinue4 = TRUE
                                            Do
                                                Print "Change the device type."
                                                Print cstr$(cInputKey) + "=keyboard"
                                                Print cstr$(cInputButton) + "=game controller button"
                                                Print cstr$(cInputAxis) + "=game controller joystick/axis"
                                                Print cstr$(cInputNone) + "=none"
                                                Input "Device type or blank to leave it unchanged"; in$
                                                If IsNum%(in$) Then
                                                    iType = Val(in$)
                                                    if iType=cInputKey or iType=cInputButton or _
                                                        iType=cInputAxis or iType=cInputNone then

                                                        If m_arrControlMap(iPlayer, iWhichInput).typ <> iType Then
                                                            m_arrControlMap(iPlayer, iWhichInput).typ = iType
                                                            Print "Updated device type. Remember to save mappings when done."
                                                            m_bMappingChanged = TRUE
                                                        Else
                                                            Print "(No change.)"
                                                        End If
                                                        bContinue4 = FALSE: Exit Do
                                                    Else
                                                        Print "Please choose one of the listed values."
                                                    End If
                                                Else
                                                    Print "(No change.)"
                                                    bContinue4 = FALSE: Exit Do
                                                End If
                                            Loop Until bContinue4 = FALSE
                                        Case 3:
                                            Print "Change the input code."
                                            Input "Type a new input code, or blank to leave it unchanged"; in$
                                            If IsNum%(in$) Then
                                                iCode = Val(in$)
                                                If m_arrControlMap(iPlayer, iWhichInput).code <> iCode Then
                                                    m_arrControlMap(iPlayer, iWhichInput).code = iCode
                                                    Print "Updated input code. Remember to save mappings when done."
                                                    m_bMappingChanged = TRUE
                                                Else
                                                    Print "(No change.)"
                                                End If
                                            Else
                                                Print "(No change.)"
                                            End If
                                        Case 4:
                                            Print "Change the input value."
                                            Input "Type a new input value, or blank to leave it unchanged"; in$
                                            If IsNum%(in$) Then
                                                iValue = Val(in$)
                                                If m_arrControlMap(iPlayer, iWhichInput).value <> iValue Then
                                                    m_arrControlMap(iPlayer, iWhichInput).value = iValue
                                                    Print "Updated input value. Remember to save mappings when done."
                                                    m_bMappingChanged = TRUE
                                                Else
                                                    Print "(No change.)"
                                                End If
                                            Else
                                                Print "(No change.)"
                                            End If
                                        Case 5:
                                            Print "Change the repeat setting."
                                            Input "Type 1 to enable or 0 to disable, or blank to leave it unchanged"; in$
                                            If IsNum%(in$) Then
                                                iRepeat = Val(in$)
                                                If iRepeat = 0 Then
                                                    If m_arrControlMap(iPlayer, iWhichInput).repeat <> FALSE Then
                                                        m_arrControlMap(iPlayer, iWhichInput).repeat = FALSE
                                                        Print "Repeat disabled. Remember to save mappings when done."
                                                        m_bMappingChanged = TRUE
                                                    Else
                                                        Print "(No change.)"
                                                    End If

                                                ElseIf iRepeat = 1 Then
                                                    If m_arrControlMap(iPlayer, iWhichInput).repeat <> TRUE Then
                                                        m_arrControlMap(iPlayer, iWhichInput).repeat = TRUE
                                                        Print "Repeat enabled. Remember to save mappings when done."
                                                        m_bMappingChanged = TRUE
                                                    Else
                                                        Print "(No change.)"
                                                    End If
                                                Else
                                                    Print "(No change.)"
                                                End If
                                            Else
                                                Print "(No change.)"
                                            End If
                                        Case Else:
                                            Print "Please choose a number between 1 and 4."
                                    End Select
                                Else
                                    bContinue3 = FALSE: Exit Do
                                End If
                            Loop Until bContinue3 = FALSE
                        Else
                            Print "Please choose a number between " + cstr$(LBound(m_arrControlMap, 2)) + " and " + cstr$(UBound(m_arrControlMap, 2)) + "."
                        End If
                    Else
                        bContinue2 = FALSE: Exit Do
                    End If
                Loop Until bContinue2 = FALSE
                If bContinue1 = FALSE Then Exit Do
            Else
                Print "Please choose a number between 1 and " + cstr$(cMaxPlayers) + "."
            End If
        Else
            If Len(sResult) = 0 Then sResult = "(Cancelled.)"
            bContinue1 = FALSE: Exit Do
        End If
    Loop Until bContinue1 = FALSE

    _KeyClear: _Delay 1

    EditMappings1$ = sResult
End Function ' EditMappings1$

' /////////////////////////////////////////////////////////////////////////////

Function ResetMapping1$
    Dim RoutineName As String: RoutineName = "ResetMapping1$"
    Dim in$
    Dim iPlayer As Integer
    Dim sResult As String: sResult = ""

    ' INITIALIZE
    InitKeyboardButtonCodes

    ' RESET
    Do
        PrintControllerMap2

        Print "To delete mapping, enter a player number: " _
            "1-" + cstr$(cMaxPlayers) + ", " + _
            cstr$(cMaxPlayers+1) + " for all, or 0 to exit."
        Input "Delete mapping for player? "; iPlayer

        If iPlayer > 0 And iPlayer <= cMaxPlayers Then
            Print "Delete mappings for player " + cstr$(iPlayer) + "."
            Input "Delete (y/n)"; in$: in$ = LCase$(_Trim$(in$))
            If in$ = "y" Then
                For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                    If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                        m_arrControlMap(iPlayer, iWhichInput).device = 0
                        m_arrControlMap(iPlayer, iWhichInput).typ = 0
                        m_arrControlMap(iPlayer, iWhichInput).code = 0
                        m_arrControlMap(iPlayer, iWhichInput).value = 0
                        m_arrControlMap(iPlayer, iWhichInput).repeat = 0 ' GetGlobalInputRepeatSetting%(iWhichInput)
                    End If
                Next iWhichInput
                sResult = "Mappings deleted for player " + cstr$(iPlayer) + "."
                Print sResult
                m_bHaveMapping = FALSE
                m_bMappingChanged = FALSE
            End If
        ElseIf iPlayer = (cMaxPlayers + 1) Then
            Input "Delete all mappings (y/n)"; in$: in$ = LCase$(_Trim$(in$))
            If in$ = "y" Then
                For iPlayer = 1 To cMaxPlayers
                    For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
                        If InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) <> "unknown" Then
                            m_arrControlMap(iPlayer, iWhichInput).device = 0
                            m_arrControlMap(iPlayer, iWhichInput).typ = 0
                            m_arrControlMap(iPlayer, iWhichInput).code = 0
                            m_arrControlMap(iPlayer, iWhichInput).value = 0
                            m_arrControlMap(iPlayer, iWhichInput).repeat = 0 ' GetGlobalInputRepeatSetting%(iWhichInput)
                        End If
                    Next iWhichInput
                Next iPlayer
                sResult = "All mappings deleted."
                Print sResult
                m_bHaveMapping = FALSE
                m_bMappingChanged = FALSE
            End If
        Else
            If Len(sResult) = 0 Then sResult = "(Cancelled.)"
            Exit Do
        End If
    Loop
    ResetMapping1$ = sResult
End Function ' ResetMapping1$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END INPUT MAPPING PART 1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN STRING TO ARRAY FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' old function?

Sub PicStringToArray (sGraphic As String, sPixel As String, sEmpty As String, sDelim As String, iMaxRows As Integer, iMaxCols As Integer, iPixel As Integer, iEmpty As Integer, iUnknown As Integer, arrSprite( - 1 , - 1) As Integer, iRowCount As Integer, iColCount As Integer)
    ReDim arrLines$(0)
    Dim iRow%
    Dim iCol%
    Dim sChar$
    Dim bError As Integer

    bError = FALSE

    ' SPLIT GRAPHIC INTO LINES
    split sGraphic, sDelim, arrLines$()

    ' COUNT ROWS, COLUMNS
    iRowCount = 0
    iColCount = 0
    For iRow% = 0 To UBound(arrLines$) ' LBOUND(arrLines$) TO UBOUND(arrLines$)
        If iRow% <= iMaxRows Then
            iRowCount = iRowCount + 1
            For iCol% = 1 To Len(arrLines$(iRow%))
                If iCol% <= iMaxCols Then
                    If iRowCount = 1 Then
                        iColCount = iColCount + 1
                    End If
                Else
                    ' Exit if out of bounds
                    bError = TRUE
                    Exit For
                End If
            Next iCol%
        Else
            ' Exit if out of bounds
            bError = TRUE
            Exit For
        End If
    Next iRow%

    ' POPULATE ARRAY
    If bError = FALSE Then
        ' SIZE ARRAY TO ACCOMODATE DATA
        ReDim arrSprite(iRowCount, iColCount) As Integer

        For iRow% = 0 To UBound(arrLines$) ' LBOUND(arrLines$) TO UBOUND(arrLines$)
            For iCol% = 1 To Len(arrLines$(iRow%))
                sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
                If (sChar$ = sPixel) Then
                    arrSprite(iRow%, iCol% - 1) = iPixel
                ElseIf (sChar$ = sEmpty) Then
                    arrSprite(iRow%, iCol% - 1) = iEmpty
                Else
                    arrSprite(iRow%, iCol% - 1) = iUnknown
                End If
            Next iCol%
        Next iRow%
    Else
        ' RETURN ZERO ROW / COLUMN COUNT IF ERROR
        iRowCount = 0
        iColCount = 0
    End If
End Sub ' PicStringToArray

' /////////////////////////////////////////////////////////////////////////////

' Usage:
' Dim StringArray(1 To 48, 1 To 128) As String
' StringToArray StringArray(), GetMap$

' version 2 with indexed array(row, columm)

Sub StringToArray (MyArray() As String, MyString As String)
    Dim sDelim As String
    ReDim arrLines(0) As String
    Dim iRow As Integer
    Dim iCol As Integer
    Dim sChar As String
    Dim iDim1 As Integer
    Dim iDim2 As Integer
    Dim iIndex1 As Integer
    Dim iIndex2 As Integer

    iDim1 = LBound(MyArray, 1)
    iDim2 = LBound(MyArray, 2)
    sDelim = Chr$(13)
    split MyString, sDelim, arrLines()
    For iRow = LBound(arrLines) To UBound(arrLines)
        If iRow <= UBound(MyArray, 1) Then
            For iCol = 1 To Len(arrLines(iRow))
                If iCol <= UBound(MyArray, 2) Then
                    sChar = Mid$(arrLines(iRow), iCol, 1)

                    If Len(sChar) > 1 Then
                        sChar = Left$(sChar, 1)
                    Else
                        If Len(sChar) = 0 Then
                            sChar = "."
                        End If
                    End If

                    iIndex1 = iRow + iDim1
                    iIndex2 = (iCol - 1) + iDim2
                    MyArray(iIndex1, iIndex2) = sChar
                    'DebugPrint "MyArray(" + cstr$(iIndex1) + ", " + cstr$(iIndex2) + " = " + chr$(34) + sChar + chr$(34)
                Else
                    ' Exit if out of bounds
                    Exit For
                End If
            Next iCol
        Else
            ' Exit if out of bounds
            Exit For
        End If
    Next iRow
End Sub ' StringToArray

' /////////////////////////////////////////////////////////////////////////////

' Usage:
' Dim String3DArray(1 To 48, 1 To 128, 1 To 3) As String
' StringTo3DArray StringArray(), GetMap$, 1

' version 3 with indexed array(row, columm, layer)

Sub StringTo3DArray (MyArray() As String, MyString As String, iIndex3 As Integer)
    Dim sDelim As String
    ReDim arrLines(0) As String
    Dim iRow As Integer
    Dim iCol As Integer
    Dim sChar As String
    Dim iDimL1 As Integer
    Dim iDimL2 As Integer
    Dim iIndex1 As Integer
    Dim iIndex2 As Integer

    'DebugPrint "StringTo3DArray started"
    If (iIndex3 >= LBound(MyArray, 3)) And (iIndex3 <= UBound(MyArray, 3)) Then
        iDimL1 = LBound(MyArray, 1)
        iDimL2 = LBound(MyArray, 2)
        sDelim = Chr$(13)
        split MyString, sDelim, arrLines()
        For iRow = LBound(arrLines) To UBound(arrLines)
            If iRow <= UBound(MyArray, 1) Then
                For iCol = 1 To Len(arrLines(iRow))
                    If iCol <= UBound(MyArray, 2) Then
                        sChar = Mid$(arrLines(iRow), iCol, 1)

                        If Len(sChar) > 1 Then
                            sChar = Left$(sChar, 1)
                        Else
                            If Len(sChar) = 0 Then
                                sChar = "."
                            End If
                        End If

                        iIndex1 = iRow + iDimL1
                        iIndex2 = (iCol - 1) + iDimL2

                        'DebugPrint "    MyArray(" + _
                        '    "iIndex1=" + cstr$(iIndex1) + ", " + _
                        '    "iIndex2=" + cstr$(iIndex2) + ", " + _
                        '    "iIndex3=" + cstr$(iIndex3) + ") " + _
                        '    "= " + chr$(34) + sChar + chr$(34)

                        If iIndex1 >= LBound(MyArray, 1) And iIndex1 <= UBound(MyArray, 1) Then
                            If iIndex2 >= LBound(MyArray, 2) And iIndex2 <= UBound(MyArray, 2) Then
                                If iIndex3 >= LBound(MyArray, 3) And iIndex3 <= UBound(MyArray, 3) Then
                                    MyArray(iIndex1, iIndex2, iIndex3) = sChar
                                End If
                            End If
                        End If
                    Else
                        ' Exit if out of bounds
                        Exit For
                    End If
                Next iCol
            Else
                ' Exit if out of bounds
                Exit For
            End If
        Next iRow
    End If
    'DebugPrint "StringTo3DArray finished"
End Sub ' StringTo3DArray

' /////////////////////////////////////////////////////////////////////////////

Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
    Dim MyString As String
    Dim iY As Integer
    Dim iX As Integer
    Dim sLine As String
    MyString = ""
    For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
        sLine = ""
        For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
            sLine = sLine + MyArray(iY, iX)
        Next iX
        MyString = MyString + sLine + Chr$(13)
    Next iY
    ArrayToString$ = MyString
End Function ' ArrayToString$

' /////////////////////////////////////////////////////////////////////////////

Function ArrayToStringTest$ (MyArray() As String)
    Dim MyString As String
    Dim iY As Integer
    Dim iX As Integer
    Dim sLine As String
    MyString = ""

    MyString = MyString + "           11111111112222222222333" + Chr$(13)
    MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
    For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
        sLine = ""
        sLine = sLine + Right$("  " + cstr$(iY), 2)
        For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
            sLine = sLine + MyArray(iY, iX)
        Next iX
        sLine = sLine + Right$("  " + cstr$(iY), 2)
        MyString = MyString + sLine + Chr$(13)
    Next iY
    MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
    MyString = MyString + "           11111111112222222222333" + Chr$(13)
    ArrayToStringTest$ = MyString
End Function ' ArrayToStringTest$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END STRING TO ARRAY FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN INPUT MAPPING v2
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Sub AddScreenArea (NewValue As ScreenAreaType, MyArray() As ScreenAreaType)
    ReDim _Preserve MyArray(1 To UBound(MyArray) + 1) As ScreenAreaType
    MyArray(UBound(MyArray)).item = NewValue.item
    MyArray(UBound(MyArray)).name = NewValue.name
    MyArray(UBound(MyArray)).typ = NewValue.typ
    MyArray(UBound(MyArray)).player = NewValue.player
    MyArray(UBound(MyArray)).x1 = NewValue.x1
    MyArray(UBound(MyArray)).y1 = NewValue.y1
    MyArray(UBound(MyArray)).x2 = NewValue.x2
    MyArray(UBound(MyArray)).y2 = NewValue.y2
    'MyArray(ubound(MyArray)).index = NewValue.index
End Sub ' AddScreenArea

' /////////////////////////////////////////////////////////////////////////////

Sub AddTextButton (NewValue As TextButtonType, MyArray() As TextButtonType)
    ReDim _Preserve MyArray(1 To UBound(MyArray) + 1) As TextButtonType
    MyArray(UBound(MyArray)).item = NewValue.item
    MyArray(UBound(MyArray)).typ = NewValue.typ
    MyArray(UBound(MyArray)).x1 = NewValue.x1
    MyArray(UBound(MyArray)).y1 = NewValue.y1
    MyArray(UBound(MyArray)).x2 = NewValue.x2
    MyArray(UBound(MyArray)).y2 = NewValue.y2
    'MyArray(ubound(MyArray)).index = NewValue.index
End Sub ' AddTextButton

' /////////////////////////////////////////////////////////////////////////////

Sub AddTextLabel (NewValue As TextLabelType, MyArray() As TextLabelType)
    ReDim _Preserve MyArray(1 To UBound(MyArray) + 1) As TextLabelType
    MyArray(UBound(MyArray)).item = NewValue.item
    MyArray(UBound(MyArray)).name = NewValue.name
    MyArray(UBound(MyArray)).row = NewValue.row
    MyArray(UBound(MyArray)).column = NewValue.column
    MyArray(UBound(MyArray)).width = NewValue.width
    MyArray(UBound(MyArray)).justify = NewValue.justify
    MyArray(UBound(MyArray)).caption = NewValue.caption
    MyArray(UBound(MyArray)).fgcolor = NewValue.fgcolor
    MyArray(UBound(MyArray)).bgcolor = NewValue.bgcolor
    'MyArray(ubound(MyArray)).index = NewValue.index
End Sub ' AddTextLabel

' /////////////////////////////////////////////////////////////////////////////

Sub AddTextField (NewValue As TextFieldType, MyArray() As TextFieldType)
    ReDim _Preserve MyArray(1 To UBound(MyArray) + 1) As TextFieldType
    MyArray(UBound(MyArray)).item = NewValue.item
    MyArray(UBound(MyArray)).name = NewValue.name
    MyArray(UBound(MyArray)).row = NewValue.row
    MyArray(UBound(MyArray)).column = NewValue.column
    MyArray(UBound(MyArray)).width = NewValue.width
    MyArray(UBound(MyArray)).justify = NewValue.justify
    MyArray(UBound(MyArray)).value = NewValue.value
    MyArray(UBound(MyArray)).fgcolor = NewValue.fgcolor
    MyArray(UBound(MyArray)).bgcolor = NewValue.bgcolor
    'MyArray(ubound(MyArray)).index = NewValue.index
End Sub ' AddTextField

' /////////////////////////////////////////////////////////////////////////////

Sub SetupScreenAreas
    Dim NewScreenArea As ScreenAreaType
    Dim x1 As Integer
    Dim y1 As Integer
    Dim x2 As Integer
    Dim y2 As Integer

    x1 = 1
    y1 = 1

    NewScreenArea.item = "Control1"
    NewScreenArea.name = "Controller #1"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 1
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()

    x1 = x1 + 32

    NewScreenArea.item = "Control2"
    NewScreenArea.name = "Controller #2"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 2
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()

    x1 = x1 + 32

    NewScreenArea.item = "Control3"
    NewScreenArea.name = "Controller #3"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 3
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()

    x1 = x1 + 32

    NewScreenArea.item = "Control4"
    NewScreenArea.name = "Controller #4"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 4
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()

    x1 = 1
    y1 = y1 + 24

    NewScreenArea.item = "Control5"
    NewScreenArea.name = "Controller #5"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 5
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()

    x1 = x1 + 32

    NewScreenArea.item = "Control6"
    NewScreenArea.name = "Controller #6"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 6
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()

    x1 = x1 + 32

    NewScreenArea.item = "Control7"
    NewScreenArea.name = "Controller #7"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 7
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()

    x1 = x1 + 32

    NewScreenArea.item = "Control8"
    NewScreenArea.name = "Controller #8"
    NewScreenArea.typ = cTextGuiSection
    NewScreenArea.player = 8
    NewScreenArea.x1 = x1
    NewScreenArea.y1 = y1
    NewScreenArea.x2 = x1 + 30
    NewScreenArea.y2 = y1 + 22
    AddScreenArea NewScreenArea, m_arrScreenArea()
End Sub ' SetupScreenAreas

' /////////////////////////////////////////////////////////////////////////////

Sub SetupButtons
    Dim NewTextButton As TextButtonType

    NewTextButton.item = "Up"
    NewTextButton.typ = cInputUp ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 9
    NewTextButton.y1 = 2
    NewTextButton.x2 = 22
    NewTextButton.y2 = 5
    AddTextButton NewTextButton, m_arrButton()

    NewTextButton.item = "Down"
    NewTextButton.typ = cInputDown ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 9
    NewTextButton.y1 = 10
    NewTextButton.x2 = 22
    NewTextButton.y2 = 13
    AddTextButton NewTextButton, m_arrButton()

    NewTextButton.item = "Left"
    NewTextButton.typ = cInputLeft ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 2
    NewTextButton.y1 = 6
    NewTextButton.x2 = 15
    NewTextButton.y2 = 9
    AddTextButton NewTextButton, m_arrButton()

    NewTextButton.item = "Right"
    NewTextButton.typ = cInputRight ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 17
    NewTextButton.y1 = 6
    NewTextButton.x2 = 30
    NewTextButton.y2 = 9
    AddTextButton NewTextButton, m_arrButton()

    NewTextButton.item = "Button1"
    NewTextButton.typ = cInputButton1 ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 2
    NewTextButton.y1 = 15
    NewTextButton.x2 = 15
    NewTextButton.y2 = 18
    AddTextButton NewTextButton, m_arrButton()

    NewTextButton.item = "Button2"
    NewTextButton.typ = cInputButton2 ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 2
    NewTextButton.y1 = 20
    NewTextButton.x2 = 15
    NewTextButton.y2 = 23
    AddTextButton NewTextButton, m_arrButton()

    NewTextButton.item = "Button3"
    NewTextButton.typ = cInputButton3 ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 17
    NewTextButton.y1 = 15
    NewTextButton.x2 = 30
    NewTextButton.y2 = 18
    AddTextButton NewTextButton, m_arrButton()

    NewTextButton.item = "Button4"
    NewTextButton.typ = cInputButton4 ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
    NewTextButton.x1 = 17
    NewTextButton.y1 = 20
    NewTextButton.x2 = 30
    NewTextButton.y2 = 23
    AddTextButton NewTextButton, m_arrButton()
End Sub ' SetupButtons

' /////////////////////////////////////////////////////////////////////////////

Sub SetupTextLabels
    Dim NewLabel As TextLabelType
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Section"
    NewLabel.name = "caption"
    NewLabel.row = 1
    NewLabel.column = 1
    NewLabel.width = 31
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "CONTROLLER #{p}"
    NewLabel.fgcolor = cCyan
    NewLabel.bgcolor = cBlack
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Up"
    NewLabel.name = "caption"
    NewLabel.row = 2
    NewLabel.column = 9
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "UP"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Up"
    NewLabel.name = "type"
    NewLabel.row = 3
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Up"
    NewLabel.name = "device"
    NewLabel.row = 3
    NewLabel.column = 16
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Up"
    NewLabel.name = "code"
    NewLabel.row = 4
    NewLabel.column = 9
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Up"
    NewLabel.name = "repeat"
    NewLabel.row = 4
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyNone
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Up"
    NewLabel.name = "value"
    NewLabel.row = 5
    NewLabel.column = 9
    NewLabel.width = -1
    NewLabel.justify = cJustifyNone
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Down"
    NewLabel.name = "caption"
    NewLabel.row = 10
    NewLabel.column = 9
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "DOWN"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Down"
    NewLabel.name = "type"
    NewLabel.row = 11
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Down"
    NewLabel.name = "device"
    NewLabel.row = 11
    NewLabel.column = 16
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Down"
    NewLabel.name = "code"
    NewLabel.row = 12
    NewLabel.column = 9
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Down"
    NewLabel.name = "repeat"
    NewLabel.row = 12
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Down"
    NewLabel.name = "value"
    NewLabel.row = 13
    NewLabel.column = 9
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Left"
    NewLabel.name = "caption"
    NewLabel.row = 6
    NewLabel.column = 2
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "LEFT"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Left"
    NewLabel.name = "type"
    NewLabel.row = 7
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Left"
    NewLabel.name = "device"
    NewLabel.row = 7
    NewLabel.column = 9
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Left"
    NewLabel.name = "code"
    NewLabel.row = 8
    NewLabel.column = 2
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Left"
    NewLabel.name = "repeat"
    NewLabel.row = 8
    NewLabel.column = 10
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Left"
    NewLabel.name = "value"
    NewLabel.row = 9
    NewLabel.column = 2
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Right"
    NewLabel.name = "caption"
    NewLabel.row = 6
    NewLabel.column = 17
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "RIGHT"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Right"
    NewLabel.name = "type"
    NewLabel.row = 7
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Right"
    NewLabel.name = "device"
    NewLabel.row = 7
    NewLabel.column = 24
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Right"
    NewLabel.name = "code"
    NewLabel.row = 8
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Right"
    NewLabel.name = "repeat"
    NewLabel.row = 8
    NewLabel.column = 25
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Right"
    NewLabel.name = "value"
    NewLabel.row = 9
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Button1"
    NewLabel.name = "caption"
    NewLabel.row = 15
    NewLabel.column = 2
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "BUTTON #1"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button1"
    NewLabel.name = "type"
    NewLabel.row = 16
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button1"
    NewLabel.name = "device"
    NewLabel.row = 16
    NewLabel.column = 9
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button1"
    NewLabel.name = "code"
    NewLabel.row = 17
    NewLabel.column = 2
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button1"
    NewLabel.name = "repeat"
    NewLabel.row = 17
    NewLabel.column = 10
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button1"
    NewLabel.name = "value"
    NewLabel.row = 18
    NewLabel.column = 2
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cRed
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Button2"
    NewLabel.name = "caption"
    NewLabel.row = 20
    NewLabel.column = 2
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "BUTTON #2"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button2"
    NewLabel.name = "type"
    NewLabel.row = 21
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button2"
    NewLabel.name = "device"
    NewLabel.row = 21
    NewLabel.column = 9
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button2"
    NewLabel.name = "code"
    NewLabel.row = 22
    NewLabel.column = 2
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button2"
    NewLabel.name = "repeat"
    NewLabel.row = 22
    NewLabel.column = 10
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button2"
    NewLabel.name = "value"
    NewLabel.row = 23
    NewLabel.column = 2
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cGreen
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Button3"
    NewLabel.name = "caption"
    NewLabel.row = 15
    NewLabel.column = 17
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "BUTTON #3"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button3"
    NewLabel.name = "type"
    NewLabel.row = 16
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button3"
    NewLabel.name = "device"
    NewLabel.row = 16
    NewLabel.column = 24
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button3"
    NewLabel.name = "code"
    NewLabel.row = 17
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button3"
    NewLabel.name = "repeat"
    NewLabel.row = 17
    NewLabel.column = 25
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button3"
    NewLabel.name = "value"
    NewLabel.row = 18
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cBlue
    AddTextLabel NewLabel, m_arrTextLabel()
    ' -----------------------------------------------------------------------------
    NewLabel.item = "Button4"
    NewLabel.name = "caption"
    NewLabel.row = 20
    NewLabel.column = 17
    NewLabel.width = 14
    NewLabel.justify = cJustifyCenter
    NewLabel.caption = "BUTTON #4"
    NewLabel.fgcolor = cYellow
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button4"
    NewLabel.name = "type"
    NewLabel.row = 21
    NewLabel.column = 0
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = ""
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button4"
    NewLabel.name = "device"
    NewLabel.row = 21
    NewLabel.column = 24
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "dev "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button4"
    NewLabel.name = "code"
    NewLabel.row = 22
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "code "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button4"
    NewLabel.name = "repeat"
    NewLabel.row = 22
    NewLabel.column = 25
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = " rep="
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()

    NewLabel.item = "Button4"
    NewLabel.name = "value"
    NewLabel.row = 23
    NewLabel.column = 17
    NewLabel.width = -1
    NewLabel.justify = cJustifyLeft
    NewLabel.caption = "value  "
    NewLabel.fgcolor = cBlack
    NewLabel.bgcolor = cOrange
    AddTextLabel NewLabel, m_arrTextLabel()
End Sub ' SetupTextLabels

' /////////////////////////////////////////////////////////////////////////////

Sub SetupTextFields
    Dim NewField As TextFieldType
    ' -----------------------------------------------------------------------------
    NewField.item = "Up"
    NewField.name = "type"
    NewField.row = 3
    NewField.column = 9
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Up"
    NewField.name = "device"
    NewField.row = 3
    NewField.column = 20
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Up"
    NewField.name = "code"
    NewField.row = 4
    NewField.column = 14
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Up"
    NewField.name = "repeat"
    NewField.row = 4
    NewField.column = 22
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Up"
    NewField.name = "value"
    NewField.row = 5
    NewField.column = 16
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()
    ' -----------------------------------------------------------------------------
    NewField.item = "Down"
    NewField.name = "type"
    NewField.row = 11
    NewField.column = 9
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Down"
    NewField.name = "device"
    NewField.row = 11
    NewField.column = 20
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Down"
    NewField.name = "code"
    NewField.row = 12
    NewField.column = 14
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Down"
    NewField.name = "repeat"
    NewField.row = 12
    NewField.column = 22
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Down"
    NewField.name = "value"
    NewField.row = 13
    NewField.column = 16
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()
    ' -----------------------------------------------------------------------------
    NewField.item = "Left"
    NewField.name = "type"
    NewField.row = 7
    NewField.column = 2
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Left"
    NewField.name = "device"
    NewField.row = 7
    NewField.column = 13
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Left"
    NewField.name = "code"
    NewField.row = 8
    NewField.column = 7
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Left"
    NewField.name = "repeat"
    NewField.row = 8
    NewField.column = 15
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Left"
    NewField.name = "value"
    NewField.row = 9
    NewField.column = 9
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()
    ' -----------------------------------------------------------------------------
    NewField.item = "Right"
    NewField.name = "type"
    NewField.row = 7
    NewField.column = 17
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Right"
    NewField.name = "device"
    NewField.row = 7
    NewField.column = 28
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Right"
    NewField.name = "code"
    NewField.row = 8
    NewField.column = 22
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Right"
    NewField.name = "repeat"
    NewField.row = 8
    NewField.column = 30
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Right"
    NewField.name = "value"
    NewField.row = 9
    NewField.column = 24
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()
    ' -----------------------------------------------------------------------------
    NewField.item = "Button1"
    NewField.name = "type"
    NewField.row = 16
    NewField.column = 2
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button1"
    NewField.name = "device"
    NewField.row = 16
    NewField.column = 13
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button1"
    NewField.name = "code"
    NewField.row = 17
    NewField.column = 7
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button1"
    NewField.name = "repeat"
    NewField.row = 17
    NewField.column = 15
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button1"
    NewField.name = "value"
    NewField.row = 18
    NewField.column = 9
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cRed
    AddTextField NewField, m_arrTextField()
    ' -----------------------------------------------------------------------------
    NewField.item = "Button2"
    NewField.name = "type"
    NewField.row = 21
    NewField.column = 2
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button2"
    NewField.name = "device"
    NewField.row = 21
    NewField.column = 13
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button2"
    NewField.name = "code"
    NewField.row = 22
    NewField.column = 7
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button2"
    NewField.name = "repeat"
    NewField.row = 22
    NewField.column = 15
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button2"
    NewField.name = "value"
    NewField.row = 23
    NewField.column = 9
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cGreen
    AddTextField NewField, m_arrTextField()
    ' -----------------------------------------------------------------------------
    NewField.item = "Button3"
    NewField.name = "type"
    NewField.row = 16
    NewField.column = 17
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button3"
    NewField.name = "device"
    NewField.row = 16
    NewField.column = 28
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button3"
    NewField.name = "code"
    NewField.row = 17
    NewField.column = 22
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button3"
    NewField.name = "repeat"
    NewField.row = 17
    NewField.column = 30
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button3"
    NewField.name = "value"
    NewField.row = 18
    NewField.column = 24
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cBlue
    AddTextField NewField, m_arrTextField()
    ' -----------------------------------------------------------------------------
    NewField.item = "Button4"
    NewField.name = "type"
    NewField.row = 21
    NewField.column = 17
    NewField.width = 7
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button4"
    NewField.name = "device"
    NewField.row = 21
    NewField.column = 28
    NewField.width = 3
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button4"
    NewField.name = "code"
    NewField.row = 22
    NewField.column = 22
    NewField.width = 3
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button4"
    NewField.name = "repeat"
    NewField.row = 22
    NewField.column = 30
    NewField.width = 1
    NewField.justify = cJustifyLeft
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()

    NewField.item = "Button4"
    NewField.name = "value"
    NewField.row = 23
    NewField.column = 24
    NewField.width = 7
    NewField.justify = cJustifyRight
    NewField.value = ""
    NewField.fgcolor = cWhite
    NewField.bgcolor = cOrange
    AddTextField NewField, m_arrTextField()
End Sub ' SetupTextFields

' /////////////////////////////////////////////////////////////////////////////
' Looks in MyArray for the first element
' whose .item matches sItem and .name matches sName
' and returns the index, or MyArray's lbound-1 if not found.

Function GetTextLabel% (MyArray() As TextLabelType, sItem As String, sName As String)
    Dim iResult As Integer: iResult = LBound(MyArray) - 1
    Dim iLoop As Integer
    For iLoop = LBound(MyArray) To UBound(MyArray)
        If MyArray(iLoop).item = sItem Then
            If MyArray(iLoop).name = sName Then
                iResult = iLoop
                Exit For
            End If
        End If
    Next iLoop
    GetTextLabel% = iResult
End Function ' GetTextLabel%

' /////////////////////////////////////////////////////////////////////////////
' Looks in MyArray for the first element
' whose .item matches sItem and .name matches sName
' and returns the index, or MyArray's lbound-1 if not found.

Function GetTextField% (MyArray() As TextFieldType, sItem As String, sName As String)
    Dim iResult As Integer: iResult = LBound(MyArray) - 1
    Dim iLoop As Integer
    For iLoop = LBound(MyArray) To UBound(MyArray)
        If MyArray(iLoop).item = sItem Then
            If MyArray(iLoop).name = sName Then
                iResult = iLoop
                Exit For
            End If
        End If
    Next iLoop
    GetTextField% = iResult
End Function ' GetTextField%

' /////////////////////////////////////////////////////////////////////////////
' Borders + layout for InputMap 2.00.75.

' Size of array:
'
' Resolution    Cols   Rows
' 1024 x  768   128    48

' 48 total available # of rows
' -2 rows for title
' -1 row for headings
' -1 for player #1 info
' -1 for player #2 info
' -1 for player #3 info
' -1 for player #4 info
' -- --------------------------
' 41 rows available

Function GetBorders$
    Dim m$
    m$ = ""
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + "         CONTROLLER #1         #                               #                               #                               X" + Chr$(13) ' 1
    m$ = m$ + "               UP              #                               #                               #                               #" + Chr$(13) ' 2
    m$ = m$ + "        button dev  10         #                               #                               #                               #" + Chr$(13) ' 3
    m$ = m$ + "        code 329 rep=Y         #                               #                               #                               #" + Chr$(13) ' 4
    m$ = m$ + "        value       -1         #                               #                               #                               #" + Chr$(13) ' 5
    m$ = m$ + " LEFT           RIGHT          #                               #                               #                               #" + Chr$(13) ' 6
    m$ = m$ + " button dev  10 button dev  10 #                               #                               #                               #" + Chr$(13) ' 7
    m$ = m$ + " code 332 rep=N code 334 rep=N #                               #                               #                               #" + Chr$(13) ' 8
    m$ = m$ + " value       -1 value       -1 #                               #                               #                               #" + Chr$(13) ' 9
    m$ = m$ + "              DOWN             #                               #                               #                               #" + Chr$(13) ' 10
    m$ = m$ + "        button dev= 10         #                               #                               #                               #" + Chr$(13) ' 11
    m$ = m$ + "        code 337 rep=Y         #                               #                               #                               #" + Chr$(13) ' 12
    m$ = m$ + "        value=      -1         #                               #                               #                               #" + Chr$(13) ' 13
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 14
    m$ = m$ + " BUTTON #1      BUTTON #3      #                               #                               #                               #" + Chr$(13) ' 15
    m$ = m$ + " button dev   1 none   dev   0 #                               #                               #                               #" + Chr$(13) ' 16
    m$ = m$ + " code 286 rep=N code     rep=N #                               #                               #                               #" + Chr$(13) ' 17
    m$ = m$ + " value       -1 value        0 #                               #                               #                               #" + Chr$(13) ' 18
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 19
    m$ = m$ + " BUTTON #2      BUTTON #4      #                               #                               #                               #" + Chr$(13) ' 20
    m$ = m$ + " none   dev   0 none   dev   0 #                               #                               #                               #" + Chr$(13) ' 21
    m$ = m$ + " code     rep=N code     rep=N #                               #                               #                               #" + Chr$(13) ' 22
    m$ = m$ + " value        0 value        0 #                               #                               #                               #" + Chr$(13) ' 23
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 24
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 25
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 26
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 27
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 28
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 29
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 30
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 31
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 32
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 33
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 34
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 35
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 36
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 37
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 38
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 39
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 40
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 41
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 42
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 43
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 44
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 45
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 46
    m$ = m$ + "c                              #                               #                               #                               #" + Chr$(13) ' 47
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 48
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '                                                                                                             11111111111111111111111111111
    GetBorders$ = m$
End Function ' GetBorders$

' /////////////////////////////////////////////////////////////////////////////
' OLD: Borders + layout for InputMap 2.00.75.

Function GetBorders2$
    Dim m$
    m$ = ""
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + "         CONTROLLER #1         #                               #                               #                               #" + Chr$(13) ' 1
    m$ = m$ + "             UP                #                               #                               #                               #" + Chr$(13) ' 2
    m$ = m$ + "      button dev  10           #                               #                               #                               #" + Chr$(13) ' 3
    m$ = m$ + "      code 329 rep=Y           #                               #                               #                               #" + Chr$(13) ' 4
    m$ = m$ + "      value       -1           #                               #                               #                               #" + Chr$(13) ' 5
    m$ = m$ + " LEFT           RIGHT          #                               #                               #                               #" + Chr$(13) ' 6
    m$ = m$ + " button dev  10 button dev  10 #                               #                               #                               #" + Chr$(13) ' 7
    m$ = m$ + " code 332 rep=N code 334 rep=N #                               #                               #                               #" + Chr$(13) ' 8
    m$ = m$ + " value       -1 value       -1 #                               #                               #                               #" + Chr$(13) ' 9
    m$ = m$ + "            DOWN               #                               #                               #                               #" + Chr$(13) ' 10
    m$ = m$ + "      button dev= 10           #                               #                               #                               #" + Chr$(13) ' 11
    m$ = m$ + "      code 337 rep=Y           #                               #                               #                               #" + Chr$(13) ' 12
    m$ = m$ + "      value=      -1           #                               #                               #                               #" + Chr$(13) ' 13
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 14
    m$ = m$ + " BUTTON #1      BUTTON #3      #                               #                               #                               #" + Chr$(13) ' 15
    m$ = m$ + " button dev   1 none   dev   0 #                               #                               #                               #" + Chr$(13) ' 16
    m$ = m$ + " code 286 rep=N code     rep=N #                               #                               #                               #" + Chr$(13) ' 17
    m$ = m$ + " value       -1 value        0 #                               #                               #                               #" + Chr$(13) ' 18
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 19
    m$ = m$ + " BUTTON #2      BUTTON #4      #                               #                               #                               #" + Chr$(13) ' 20
    m$ = m$ + " none   dev   0 none   dev   0 #                               #                               #                               #" + Chr$(13) ' 21
    m$ = m$ + " code     rep=N code     rep=N #                               #                               #                               #" + Chr$(13) ' 22
    m$ = m$ + " value        0 value        0 #                               #                               #                               #" + Chr$(13) ' 23
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 24
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 25
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 26
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 27
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 28
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 29
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 30
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 31
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 32
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 33
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 34
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 35
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 36
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 37
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 38
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 39
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 40
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 41
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 42
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 43
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 44
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 45
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 46
    m$ = m$ + "                               #                               #                               #                               #" + Chr$(13) ' 47
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 48
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '                                                                                                             11111111111111111111111111111
    GetBorders2$ = m$
End Function ' GetBorders2$

' /////////////////////////////////////////////////////////////////////////////
' OLD: Borders + layout for InputMap 2.00.75.

Function GetBorders1$
    Dim m$
    m$ = ""
    '                                                                                                             11111111111111111111111111111
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    m$ = m$ + ".........CONTROLLER.#1.........#...............................#...............................#...............................#" + Chr$(13) ' 1
    m$ = m$ + ".............UP................#...............................#...............................#...............................#" + Chr$(13) ' 2
    m$ = m$ + "......button.dev..10...........#...............................#...............................#...............................#" + Chr$(13) ' 3
    m$ = m$ + "......code.329.rep=Y...........#...............................#...............................#...............................#" + Chr$(13) ' 4
    m$ = m$ + "......value.......-1...........#...............................#...............................#...............................#" + Chr$(13) ' 5
    m$ = m$ + ".LEFT...........RIGHT..........#...............................#...............................#...............................#" + Chr$(13) ' 6
    m$ = m$ + ".button.dev..10.button.dev..10.#...............................#...............................#...............................#" + Chr$(13) ' 7
    m$ = m$ + ".code.332.rep=N.code.334.rep=N.#...............................#...............................#...............................#" + Chr$(13) ' 8
    m$ = m$ + ".value.......-1.value.......-1.#...............................#...............................#...............................#" + Chr$(13) ' 9
    m$ = m$ + "............DOWN...............#...............................#...............................#...............................#" + Chr$(13) ' 10
    m$ = m$ + "......button.dev=.10...........#...............................#...............................#...............................#" + Chr$(13) ' 11
    m$ = m$ + "......code.337.rep=Y...........#...............................#...............................#...............................#" + Chr$(13) ' 12
    m$ = m$ + "......value=......-1...........#...............................#...............................#...............................#" + Chr$(13) ' 13
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 14
    m$ = m$ + ".BUTTON.#1......BUTTON.#3......#...............................#...............................#...............................#" + Chr$(13) ' 15
    m$ = m$ + ".button.dev...1.none...dev...0.#...............................#...............................#...............................#" + Chr$(13) ' 16
    m$ = m$ + ".code.286.rep=N.code.....rep=N.#...............................#...............................#...............................#" + Chr$(13) ' 17
    m$ = m$ + ".value.......-1.value........0.#...............................#...............................#...............................#" + Chr$(13) ' 18
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 19
    m$ = m$ + ".BUTTON.#2......BUTTON.#4......#...............................#...............................#...............................#" + Chr$(13) ' 20
    m$ = m$ + ".none...dev...0.none...dev...0.#...............................#...............................#...............................#" + Chr$(13) ' 21
    m$ = m$ + ".code.....rep=N.code.....rep=N.#...............................#...............................#...............................#" + Chr$(13) ' 22
    m$ = m$ + ".value........0.value........0.#...............................#...............................#...............................#" + Chr$(13) ' 23
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 24
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 25
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 26
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 27
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 28
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 29
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 30
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 31
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 32
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 33
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 34
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 35
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 36
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 37
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 38
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 39
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 40
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 41
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 42
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 43
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 44
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 45
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 46
    m$ = m$ + "...............................#...............................#...............................#...............................#" + Chr$(13) ' 47
    m$ = m$ + "################################################################################################################################" + Chr$(13) ' 48
    '          12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
    '                   11111111112222222222333333333344444444445555555555666666666677777777778888888888999999999900000000001111111111222222222
    '                                                                                                             11111111111111111111111111111
    GetBorders1$ = m$
End Function ' GetBorders1$

' /////////////////////////////////////////////////////////////////////////////
' The following must be initialized and populated before calling:
' ReDim arrColor(-1) As ColorType
' Dim MapArray(1 To 48, 1 To 128) As String ' FOR SCREEN 1024 x  768: 128 x 48
' ReDim ScreenArray(1 To 48, 1 To 128) As TextCellType ' FOR SCREEN 1024 x  768: 128 x 48

' This was an experiment in rolling your own "GUI",
' - what a pain it turned out to be
' - next time maybe we would use InForm and be done with it!

' TODO:
' * clean up and remove all the variable definitions left over
'   from the main routine MapInput2$ this was moved out of.

Sub UpdateDisplayMapInput2( _
    arrColor() As ColorType, _
    MapArray() As String, _
    ScreenArray() As TextCellType _
    )

    Dim RoutineName As String: RoutineName = "UpdateDisplayMapInput2"

    Dim iDeviceCount As Integer ' count # of devices connected to system (keyboard, mouse, game controllers)
    Dim iPlayer As Integer ' same as iController, which of the 8 controllers
    Dim iWhichInput As Integer ' one of: cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4

    Dim iCount As Integer

    Dim sResult As String
    Dim sError As String
    Dim sLine As String

    Dim iForeColor As Integer
    Dim iBackColor As Integer

    Dim sName As String
    Dim sItem As String
    Dim iLoop As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim iCol As Integer
    Dim iRow As Integer

    Dim iStartX As Integer
    Dim iStartY As Integer
    Dim iEndX As Integer
    Dim iEndY As Integer
    Dim iLabel As Integer
    Dim iField As Integer
    Dim iButton As Integer
    Dim iWidth As Integer
    Dim bContinue As Integer
    Dim sValue As String
    Dim iNextWidth As Integer
    Dim iType As Integer
    Dim iIndex As Integer

    Dim in$

    ' MOUSE VARIABLES
    Dim iX1 As Integer: iX1 = 0
    Dim iY1 As Integer: iY1 = 0
    Dim iOldX1 As Integer: iOldX1 = 0
    Dim iOldY1 As Integer: iOldY1 = 0
    Dim bLeftClick As Integer: bLeftClick = FALSE
    Dim bOldLeftClick As Integer: bOldLeftClick = FALSE

    Dim sZone1 As String ' text description of which controller
    Dim sZone2 As String ' text description of which input
    Dim iMapPlayer As Integer ' like iController, which of the 8 controllers

    ' WHICH PORTION OF THE SCREEN USER CLICKED ON
    Dim iTempX As Integer
    Dim iTempY As Integer
    Dim iTextX As Integer
    Dim iTextY As Integer
    Dim iOffsetX As Integer
    Dim iOffsetY As Integer

    ' BOUNDARIES OF BUTTON CLICKED ON
    Dim iMapX1 As Integer
    Dim iMapX2 As Integer
    Dim iMapY1 As Integer
    Dim iMapY2 As Integer

    ' FOR MAPPING CONTROLLER INPUT
    Dim arrButton(32, 16) As Integer ' number of buttons on the joystick
    Dim arrButtonNew(32, 16) As Integer ' tracks when to initialize values
    Dim arrAxis(32, 16) As Double ' number of axis on the joystick
    Dim arrAxisNew(32, 16) As Integer ' tracks when to initialize values
    'Dim iPlayer As Integer
    Dim iController As Integer ' to loop through devices
    Dim iDevice As Integer
    Dim iValue As Integer
    Dim bMoveNext As Integer
    'Dim iLoop As Integer
    Dim iCode As Integer
    Dim bHaveInput As Integer
    'Dim iWhichInput As Integer
    Dim iNextInput As Integer
    Dim sPrompt As String
    Dim dblNextAxis As Double

    Dim ExitX As Integer
    Dim ExitY As Integer

    ' DISPLAY BORDERS
    Cls
    For iRow = LBound(MapArray, 1) To UBound(MapArray, 1)
        For iCol = LBound(MapArray, 2) To UBound(MapArray, 2)
            Color cRed, cBlack
            PrintString2 iRow, iCol, MapArray(iRow, iCol), ScreenArray()
        Next iCol
    Next iRow

    ' DISPLAY CONTROL MAPPINGS
    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
        ' Get top left screen coordinates for this controller
        iStartX = m_arrScreenArea(iPlayer).x1
        iStartY = m_arrScreenArea(iPlayer).y1
        iEndX = m_arrScreenArea(iPlayer).x2
        iEndY = m_arrScreenArea(iPlayer).y2
        iWidth = (iEndX - iStartX) + 1

        sItem = "Section"
        iIndex = GetTextLabel%(m_arrTextLabel(), sItem, "caption")
        If iIndex >= LBound(m_arrTextLabel) Then
            iRow = (iStartY + m_arrTextLabel(iIndex).row) - 1
            iCol = (iStartX + m_arrTextLabel(iIndex).column) - 1
            sValue = m_arrTextLabel(iIndex).caption
            sValue = Replace$(sValue, "{p}", cstr$(iPlayer))
            iNextWidth = m_arrTextLabel(iIndex).width
            If iNextWidth > 0 Then
                Select Case m_arrTextLabel(iIndex).justify
                    Case cJustifyLeft:
                        sValue = StrJustifyLeft$(sValue, iNextWidth)
                    Case cJustifyRight:
                        sValue = StrJustifyRight$(sValue, iNextWidth)
                    Case cJustifyCenter:
                        sValue = StrJustifyCenter$(sValue, iNextWidth)
                    Case Else:
                        ' (DO NOTHING)
                End Select
                Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                PrintString2 iRow, iCol, sValue, ScreenArray()
            ElseIf iNextWidth < 0 Then
                Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                PrintString2 iRow, iCol, sValue, ScreenArray()
            Else
                ' (IGNORE)
            End If
        End If

        ' POPULATE EACH INPUT FOR THIS PLAYER/CONTROLLER:
        ' up,down,left,right,button #1,button #2,button #3,button #4
        ' iWhichInput is one of: cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)

            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            ' BEGIN ITEM

            ' get value to match against m_arrTextField(iField).item
            sItem = InputToItem$(iWhichInput)
            'InputToString$(iWhichInput) returns up,down,left,right,button #1,button #2,button #3,button #4

            ' find the layout for each field for this input
            ' m_arrTextField(iField).name = type,device,code,repeat,value

            ' END ITEM
            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++






            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            ' BEGIN CAPTION

            ' LABEL
            iIndex = GetTextLabel%(m_arrTextLabel(), sItem, "caption")
            If iIndex >= LBound(m_arrTextLabel) Then
                iRow = (iStartY + m_arrTextLabel(iIndex).row) - 1
                iCol = (iStartX + m_arrTextLabel(iIndex).column) - 1
                sValue = m_arrTextLabel(iIndex).caption
                sValue = Replace$(sValue, "{p}", cstr$(iPlayer))
                iNextWidth = m_arrTextLabel(iIndex).width
                If iNextWidth > 0 Then
                    Select Case m_arrTextLabel(iIndex).justify
                        Case cJustifyLeft:
                            sValue = StrJustifyLeft$(sValue, iNextWidth)
                        Case cJustifyRight:
                            sValue = StrJustifyRight$(sValue, iNextWidth)
                        Case cJustifyCenter:
                            sValue = StrJustifyCenter$(sValue, iNextWidth)
                        Case Else:
                            ' (DO NOTHING)
                    End Select
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                ElseIf iNextWidth < 0 Then
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                Else
                    ' (IGNORE)
                End If
            End If
            ' END CAPTION
            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            ' BEGIN TYPE
            '           values are cInputNone,cInputKey,cInputButton,cInputAxis
            '           InputTypeToString$ returns none,key,button,axis,unknown

            ' VALUE
            iIndex = GetTextField%(m_arrTextField(), sItem, "type")
            If iIndex >= LBound(m_arrTextField) Then
                iRow = (iStartY + m_arrTextField(iIndex).row) - 1
                iCol = (iStartX + m_arrTextField(iIndex).column) - 1
                sValue = InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ)
                iNextWidth = m_arrTextField(iIndex).width
                Select Case m_arrTextField(iIndex).justify
                    Case cJustifyLeft:
                        sValue = StrJustifyLeft$(sValue, iNextWidth)
                    Case cJustifyRight:
                        sValue = StrJustifyRight$(sValue, iNextWidth)
                    Case cJustifyCenter:
                        sValue = StrJustifyCenter$(sValue, iNextWidth)
                    Case Else:
                        ' (DO NOTHING)
                End Select
                Color m_arrTextField(iIndex).fgcolor, m_arrTextField(iIndex).bgcolor
                PrintString2 iRow, iCol, sValue, ScreenArray()
            End If

            ' LABEL
            iIndex = GetTextLabel%(m_arrTextLabel(), sItem, "type")
            If iIndex >= LBound(m_arrTextLabel) Then
                iRow = (iStartY + m_arrTextLabel(iIndex).row) - 1
                iCol = (iStartX + m_arrTextLabel(iIndex).column) - 1
                sValue = m_arrTextLabel(iIndex).caption
                sValue = Replace$(sValue, "{p}", cstr$(iPlayer))
                iNextWidth = m_arrTextLabel(iIndex).width
                If iNextWidth > 0 Then
                    Select Case m_arrTextLabel(iIndex).justify
                        Case cJustifyLeft:
                            sValue = StrJustifyLeft$(sValue, iNextWidth)
                        Case cJustifyRight:
                            sValue = StrJustifyRight$(sValue, iNextWidth)
                        Case cJustifyCenter:
                            sValue = StrJustifyCenter$(sValue, iNextWidth)
                        Case Else:
                            ' (DO NOTHING)
                    End Select
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                ElseIf iNextWidth < 0 Then
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                Else
                    ' (IGNORE)
                End If
            End If
            ' END TYPE
            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            ' BEGIN DEVICE

            ' VALUE
            iIndex = GetTextField%(m_arrTextField(), sItem, "device")
            If iIndex >= LBound(m_arrTextField) Then
                iRow = (iStartY + m_arrTextField(iIndex).row) - 1
                iCol = (iStartX + m_arrTextField(iIndex).column) - 1
                sValue = cstr$(m_arrControlMap(iPlayer, iWhichInput).device)
                iNextWidth = m_arrTextField(iIndex).width
                Select Case m_arrTextField(iIndex).justify
                    Case cJustifyLeft:
                        sValue = StrJustifyLeft$(sValue, iNextWidth)
                    Case cJustifyRight:
                        sValue = StrJustifyRight$(sValue, iNextWidth)
                    Case cJustifyCenter:
                        sValue = StrJustifyCenter$(sValue, iNextWidth)
                    Case Else:
                        ' (DO NOTHING)
                End Select
                Color m_arrTextField(iIndex).fgcolor, m_arrTextField(iIndex).bgcolor
                PrintString2 iRow, iCol, sValue, ScreenArray()
            End If

            ' LABEL
            iIndex = GetTextLabel%(m_arrTextLabel(), sItem, "device")
            If iIndex >= LBound(m_arrTextLabel) Then
                iRow = (iStartY + m_arrTextLabel(iIndex).row) - 1
                iCol = (iStartX + m_arrTextLabel(iIndex).column) - 1
                sValue = m_arrTextLabel(iIndex).caption
                sValue = Replace$(sValue, "{p}", cstr$(iPlayer))
                iNextWidth = m_arrTextLabel(iIndex).width
                If iNextWidth > 0 Then
                    Select Case m_arrTextLabel(iIndex).justify
                        Case cJustifyLeft:
                            sValue = StrJustifyLeft$(sValue, iNextWidth)
                        Case cJustifyRight:
                            sValue = StrJustifyRight$(sValue, iNextWidth)
                        Case cJustifyCenter:
                            sValue = StrJustifyCenter$(sValue, iNextWidth)
                        Case Else:
                            ' (DO NOTHING)
                    End Select
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                ElseIf iNextWidth < 0 Then
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                Else
                    ' (IGNORE)
                End If
            End If
            ' END DEVICE
            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            ' BEGIN CODE

            ' VALUE
            iIndex = GetTextField%(m_arrTextField(), sItem, "code")
            If iIndex >= LBound(m_arrTextField) Then
                iRow = (iStartY + m_arrTextField(iIndex).row) - 1
                iCol = (iStartX + m_arrTextField(iIndex).column) - 1

                If m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey Then
                    sValue = GetKeyboardButtonCodeText$(m_arrControlMap(iPlayer, iWhichInput).code)
                Else
                    sValue = cstr$(m_arrControlMap(iPlayer, iWhichInput).code)
                End If

                iNextWidth = m_arrTextField(iIndex).width
                Select Case m_arrTextField(iIndex).justify
                    Case cJustifyLeft:
                        sValue = StrJustifyLeft$(sValue, iNextWidth)
                    Case cJustifyRight:
                        sValue = StrJustifyRight$(sValue, iNextWidth)
                    Case cJustifyCenter:
                        sValue = StrJustifyCenter$(sValue, iNextWidth)
                    Case Else:
                        ' (DO NOTHING)
                End Select
                Color m_arrTextField(iIndex).fgcolor, m_arrTextField(iIndex).bgcolor
                PrintString2 iRow, iCol, sValue, ScreenArray()
            End If

            ' LABEL
            iIndex = GetTextLabel%(m_arrTextLabel(), sItem, "code")
            If iIndex >= LBound(m_arrTextLabel) Then
                iRow = (iStartY + m_arrTextLabel(iIndex).row) - 1
                iCol = (iStartX + m_arrTextLabel(iIndex).column) - 1
                sValue = m_arrTextLabel(iIndex).caption
                sValue = Replace$(sValue, "{p}", cstr$(iPlayer))
                iNextWidth = m_arrTextLabel(iIndex).width
                If iNextWidth > 0 Then
                    Select Case m_arrTextLabel(iIndex).justify
                        Case cJustifyLeft:
                            sValue = StrJustifyLeft$(sValue, iNextWidth)
                        Case cJustifyRight:
                            sValue = StrJustifyRight$(sValue, iNextWidth)
                        Case cJustifyCenter:
                            sValue = StrJustifyCenter$(sValue, iNextWidth)
                        Case Else:
                            ' (DO NOTHING)
                    End Select
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                ElseIf iNextWidth < 0 Then
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                Else
                    ' (IGNORE)
                End If
            End If
            ' END CODE
            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            ' BEGIN VALUE

            ' VALUE
            iIndex = GetTextField%(m_arrTextField(), sItem, "value")
            If iIndex >= LBound(m_arrTextField) Then
                iRow = (iStartY + m_arrTextField(iIndex).row) - 1
                iCol = (iStartX + m_arrTextField(iIndex).column) - 1
                sValue = cstr$(m_arrControlMap(iPlayer, iWhichInput).value)
                iNextWidth = m_arrTextField(iIndex).width
                Select Case m_arrTextField(iIndex).justify
                    Case cJustifyLeft:
                        sValue = StrJustifyLeft$(sValue, iNextWidth)
                    Case cJustifyRight:
                        sValue = StrJustifyRight$(sValue, iNextWidth)
                    Case cJustifyCenter:
                        sValue = StrJustifyCenter$(sValue, iNextWidth)
                    Case Else:
                        ' (DO NOTHING)
                End Select
                Color m_arrTextField(iIndex).fgcolor, m_arrTextField(iIndex).bgcolor
                PrintString2 iRow, iCol, sValue, ScreenArray()
            End If

            ' LABEL
            iIndex = GetTextLabel%(m_arrTextLabel(), sItem, "value")
            If iIndex >= LBound(m_arrTextLabel) Then
                iRow = (iStartY + m_arrTextLabel(iIndex).row) - 1
                iCol = (iStartX + m_arrTextLabel(iIndex).column) - 1
                sValue = m_arrTextLabel(iIndex).caption
                sValue = Replace$(sValue, "{p}", cstr$(iPlayer))
                iNextWidth = m_arrTextLabel(iIndex).width
                If iNextWidth > 0 Then
                    Select Case m_arrTextLabel(iIndex).justify
                        Case cJustifyLeft:
                            sValue = StrJustifyLeft$(sValue, iNextWidth)
                        Case cJustifyRight:
                            sValue = StrJustifyRight$(sValue, iNextWidth)
                        Case cJustifyCenter:
                            sValue = StrJustifyCenter$(sValue, iNextWidth)
                        Case Else:
                            ' (DO NOTHING)
                    End Select
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                ElseIf iNextWidth < 0 Then
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                Else
                    ' (IGNORE)
                End If
            End If
            ' END VALUE
            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            ' BEGIN REPEAT

            ' VALUE
            iIndex = GetTextField%(m_arrTextField(), sItem, "repeat")
            If iIndex >= LBound(m_arrTextField) Then
                iRow = (iStartY + m_arrTextField(iIndex).row) - 1
                iCol = (iStartX + m_arrTextField(iIndex).column) - 1
                sValue = IIFSTR$(m_arrControlMap(iPlayer, iWhichInput).repeat, "Y", "N")
                iNextWidth = m_arrTextField(iIndex).width
                Select Case m_arrTextField(iIndex).justify
                    Case cJustifyLeft:
                        sValue = StrJustifyLeft$(sValue, iNextWidth)
                    Case cJustifyRight:
                        sValue = StrJustifyRight$(sValue, iNextWidth)
                    Case cJustifyCenter:
                        sValue = StrJustifyCenter$(sValue, iNextWidth)
                    Case Else:
                        ' (DO NOTHING)
                End Select
                Color m_arrTextField(iIndex).fgcolor, m_arrTextField(iIndex).bgcolor
                PrintString2 iRow, iCol, sValue, ScreenArray()
            End If

            ' LABEL
            iIndex = GetTextLabel%(m_arrTextLabel(), sItem, "repeat")
            If iIndex >= LBound(m_arrTextLabel) Then
                iRow = (iStartY + m_arrTextLabel(iIndex).row) - 1
                iCol = (iStartX + m_arrTextLabel(iIndex).column) - 1
                sValue = m_arrTextLabel(iIndex).caption
                sValue = Replace$(sValue, "{p}", cstr$(iPlayer))
                iNextWidth = m_arrTextLabel(iIndex).width
                If iNextWidth > 0 Then
                    Select Case m_arrTextLabel(iIndex).justify
                        Case cJustifyLeft:
                            sValue = StrJustifyLeft$(sValue, iNextWidth)
                        Case cJustifyRight:
                            sValue = StrJustifyRight$(sValue, iNextWidth)
                        Case cJustifyCenter:
                            sValue = StrJustifyCenter$(sValue, iNextWidth)
                        Case Else:
                            ' (DO NOTHING)
                    End Select
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                ElseIf iNextWidth < 0 Then
                    Color m_arrTextLabel(iIndex).fgcolor, m_arrTextLabel(iIndex).bgcolor
                    PrintString2 iRow, iCol, sValue, ScreenArray()
                Else
                    ' (IGNORE)
                End If
            End If
            ' END REPEAT
            ' +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        Next iWhichInput
    Next iPlayer

    ' ADD CLOSE BUTTON
    ExitX = (_Width(0) \ _FontWidth) - 4
    ExitY = 1 ' _Height(0) \ _FontHeight
    Color cBlack, cRed
    PrintString2 ExitY, ExitX + 0, "C", ScreenArray()
    PrintString2 ExitY, ExitX + 1, "L", ScreenArray()
    PrintString2 ExitY, ExitX + 2, "O", ScreenArray()
    PrintString2 ExitY, ExitX + 3, "S", ScreenArray()
    PrintString2 ExitY, ExitX + 4, "E", ScreenArray()

End Sub ' UpdateDisplayMapInput2

' /////////////////////////////////////////////////////////////////////////////

Function MapInput2$
    Dim RoutineName As String: RoutineName = "MapInput2$"

    Dim iDeviceCount As Integer ' count # of devices connected to system (keyboard, mouse, game controllers)
    Dim iPlayer As Integer ' same as iController, which of the 8 controllers
    Dim iWhichInput As Integer ' one of: cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4

    Dim bFinished As Integer
    Dim iCount As Integer

    Dim sResult As String
    Dim sError As String: sError = ""
    Dim sLine As String

    ReDim arrColor(-1) As ColorType
    Dim iForeColor As Integer
    Dim iBackColor As Integer

    ' VARIABLES FOR SCREEN
    ' 1024 x  768: 128 x 48
    Dim MapArray(1 To 48, 1 To 128) As String
    ReDim ScreenArray(1 To 48, 1 To 128) As TextCellType

    Dim sName As String
    Dim sItem As String
    Dim iLoop As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim iCol As Integer
    Dim iRow As Integer

    Dim iStartX As Integer
    Dim iStartY As Integer
    Dim iEndX As Integer
    Dim iEndY As Integer
    Dim iLabel As Integer
    Dim iField As Integer
    Dim iButton As Integer
    Dim iWidth As Integer
    Dim bContinue As Integer
    Dim sValue As String
    Dim iNextWidth As Integer
    Dim iType As Integer
    Dim iIndex As Integer

    Dim in$

    ' MOUSE VARIABLES
    Dim iX1 As Integer: iX1 = 0
    Dim iY1 As Integer: iY1 = 0
    Dim iOldX1 As Integer: iOldX1 = 0
    Dim iOldY1 As Integer: iOldY1 = 0
    Dim bLeftClick As Integer: bLeftClick = FALSE
    Dim bOldLeftClick As Integer: bOldLeftClick = FALSE

    Dim sZone1 As String ' text description of which controller
    Dim sZone2 As String ' text description of which input
    Dim iMapPlayer As Integer ' like iController, which of the 8 controllers

    ' WHICH PORTION OF THE SCREEN USER CLICKED ON
    Dim iTempX As Integer
    Dim iTempY As Integer
    Dim iTextX As Integer
    Dim iTextY As Integer
    Dim iOffsetX As Integer
    Dim iOffsetY As Integer

    ' BOUNDARIES OF BUTTON CLICKED ON
    Dim iMapX1 As Integer
    Dim iMapX2 As Integer
    Dim iMapY1 As Integer
    Dim iMapY2 As Integer

    ' FOR MAPPING CONTROLLER INPUT
    Dim arrButton(32, 16) As Integer ' number of buttons on the joystick
    Dim arrButtonNew(32, 16) As Integer ' tracks when to initialize values
    Dim arrAxis(32, 16) As Double ' number of axis on the joystick
    Dim arrAxisNew(32, 16) As Integer ' tracks when to initialize values
    'Dim iPlayer As Integer
    Dim iController As Integer ' to loop through devices
    Dim iDevice As Integer
    Dim iValue As Integer
    Dim bMoveNext As Integer
    'Dim iLoop As Integer
    Dim iCode As Integer
    Dim bHaveInput As Integer
    'Dim iWhichInput As Integer
    Dim iNextInput As Integer
    Dim sCaption As String
    Dim sPrompt As String
    Dim CloseX As Integer
    Dim CloseY As Integer
    Dim dblNextAxis As Double
    Dim bHitEsc As Integer
    Dim bHitEnter As Integer
    Dim bMapMode As Integer ' if TRUE then look for control mapping input
    Dim ExitX As Integer
    Dim ExitY As Integer

    ' =============================================================================
    ' INITIALIZE
    If Len(sError) = 0 Then
        InitKeyboardButtonCodes
        AddColors arrColor()
        StringToArray MapArray(), GetBorders$
        SetupScreenAreas
        SetupButtons
        SetupTextLabels
        SetupTextFields
    End If

    ' =============================================================================
    ' MAKE SURE WE HAVE DEVICES
    If Len(sError) = 0 Then
        ' 1 is the keyboard
        ' 2 is the mouse
        ' 3 is the joystick
        ' unless someone has a strange setup with multiple mice/keyboards/ect...
        ' In that case, you can use _DEVICE$(i) to look for "KEYBOARD", "MOUSE", "JOYSTICK", if necessary.
        ' I've never actually found it necessary, but I figure it's worth mentioning, just in case...

        iDeviceCount = _Devices ' Find the number of devices on someone's system
        'If iDeviceCount < 3 Then
        If iDeviceCount < 1 Then
            sError = "Enough devices not found."
        End If
    End If

    ' =============================================================================
    ' COUNT # OF JOYSTICKS
    ' TODO: find out the right way to count joysticks
    If Len(sError) = 0 Then
        ' D= _DEVICES ' MUST be read in order for other 2 device functions to work!
        iDeviceCount = _Devices ' Find the number of devices on someone's system

        If iDeviceCount > 2 Then
            ' LIMIT # OF DEVICES, IF THERE IS A LIMIT DEFINED
            iNumControllers = iDeviceCount - 2
            If cMaxControllers > 0 Then
                If iNumControllers > cMaxControllers Then
                    iNumControllers = cMaxControllers
                End If
            End If
        Else
            ' ONLY 2 FOUND (KEYBOARD, MOUSE)
            'sError = "No game controllers found."
            iNumControllers = 0
        End If
    End If

    ' =============================================================================
    ' INITIALIZE CONTROLLER DATA
    If Len(sError) = 0 Then
        For iController = 1 To iNumControllers
            m_arrController(iController).buttonCount = cMaxButtons
            m_arrController(iController).axisCount = cMaxAxis
            For iLoop = 1 To cMaxButtons
                arrButtonNew(iController, iLoop) = TRUE
            Next iLoop
            For iLoop = 1 To cMaxAxis
                arrAxisNew(iController, iLoop) = TRUE
            Next iLoop
        Next iController
    End If

    ' =============================================================================
    ' INITIALIZE CONTROLLER INPUT
    If Len(sError) = 0 Then
        _KeyClear: _Delay 1
        For iController = 1 To iNumControllers
            iDevice = iController + 2
            While _DeviceInput(iDevice) ' clear and update the device buffer
                For iLoop = 1 To _LastButton(iDevice)
                    If (iLoop > cMaxButtons) Then Exit For
                    m_arrController(iController).buttonCount = iLoop
                    arrButton(iController, iLoop) = FALSE
                Next iLoop
                For iLoop = 1 To _LastAxis(iDevice) ' this loop checks all my axis
                    If (iLoop > cMaxAxis) Then Exit For
                    m_arrController(iController).axisCount = iLoop
                    arrAxis(iController, iLoop) = 0
                Next iLoop
            Wend ' clear and update the device buffer
        Next iController
    End If

    ' =============================================================================
    ' INIT SCREEN
    If Len(sError) = 0 Then
        Screen _NewImage(1024, 768, 32): _ScreenMove 0, 0
        UpdateDisplayMapInput2 arrColor(), MapArray(), ScreenArray()
    End If

    ' =============================================================================
    ' MAIN LOOP
    If Len(sError) = 0 Then
        ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        ' BEGIN MOUSE #MOUSE
        ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        bFinished = FALSE
        bHitEsc = FALSE
        bHitEnter = FALSE
        bMapMode = FALSE
        CloseX = 0
        CloseY = 0

        ExitX = (_Width(0) \ _FontWidth) - 4
        ExitY = 1 ' _Height(0) \ _FontHeight

        _MouseHide ' hide OS mouse pointer
        Do
            ' READ MOUSE
            Do While _MouseInput: Loop

            ' ERASE CURSOR
            If iOldX1 <> iX1 Or iOldY1 <> iY1 Then
                If iOldX1 > 0 And iOldY1 > 0 Then
                    iTextY = iOldY1 \ _FontHeight
                    iTextX = iOldX1 \ _FontWidth
                    Color ScreenArray(iTextY, iTextX).fgColor, ScreenArray(iTextY, iTextX).bgcolor
                    PrintString1 iTextY, iTextX, ScreenArray(iTextY, iTextX).value
                End If
            End If

            ' SAVE OLD POSITION
            iOldY1 = iY1
            iOldX1 = iX1
            iTempY = iOldY1 \ _FontHeight
            iTempX = iOldX1 \ _FontWidth

            ' GET NEW POSITION
            iY1 = ((_MouseY \ _FontHeight) + 1) * _FontHeight
            iX1 = ((_MouseX \ _FontWidth) + 1) * _FontWidth
            iTextY = iY1 \ _FontHeight
            iTextX = iX1 \ _FontWidth

            ' DRAW CURSOR
            Color cBlack, cMagenta
            PrintString1 iTextY, iTextX, " "

            ' LEFT CLICK
            bLeftClick = _MouseButton(1)
            If bLeftClick Then
                If bOldLeftClick = FALSE Then
                    ' (CLICK ACTION HERE)

                    ' IS SELECTING A CONTROL TO MAP, OR MAPPING A CONTROL?
                    If CloseX = 0 Or CloseY = 0 Then

                        ' DID THEY CLOSE?
                        If (iTextY = ExitY) And (iTextX >= ExitX) Then
                            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                            ' USER CLICKED EXIT SCREEN
                            bFinished = TRUE
                            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                        Else
                            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                            ' BEGIN USER IS SELECTING A CONTROL TO MAP

                            ' WHICH CONTROLLER?
                            For iIndex = LBound(m_arrScreenArea) To UBound(m_arrScreenArea)
                                If iTextY >= m_arrScreenArea(iIndex).y1 Then
                                    If iTextY <= m_arrScreenArea(iIndex).y2 Then
                                        If iTextX >= m_arrScreenArea(iIndex).x1 Then
                                            If iTextX <= m_arrScreenArea(iIndex).x2 Then
                                                iMapPlayer = m_arrScreenArea(iIndex).player
                                                sZone1 = m_arrScreenArea(iIndex).item
                                                iOffsetX = m_arrScreenArea(iIndex).x1 - 1
                                                iOffsetY = m_arrScreenArea(iIndex).y1 - 1
                                                Exit For
                                            End If
                                        End If
                                    End If
                                End If
                            Next iIndex

                            ' WHICH BUTTON?
                            For iIndex = LBound(m_arrButton) To UBound(m_arrButton)
                                If iTextY >= m_arrButton(iIndex).y1 + iOffsetY Then
                                    If iTextY <= m_arrButton(iIndex).y2 + iOffsetY Then
                                        If iTextX >= m_arrButton(iIndex).x1 + iOffsetX Then
                                            If iTextX <= m_arrButton(iIndex).x2 + iOffsetX Then

                                                iWhichInput = m_arrButton(iIndex).typ ' cInputUp, cInputDown, cInputLeft, cInputRight, cInputButton1, cInputButton2, cInputButton3, cInputButton4
                                                sZone2 = m_arrButton(iIndex).item

                                                DebugPrint "clicked " + sZone1 + ", " + sZone2

                                                'iMapX1 = m_arrButton(iIndex).x1+iOffsetX
                                                'iMapX2 = m_arrButton(iIndex).x2+iOffsetX
                                                'iMapY1 = m_arrButton(iIndex).y1+iOffsetY
                                                'iMapY2 = m_arrButton(iIndex).y2+iOffsetY
                                                '
                                                'sPrompt = ""
                                                'sPrompt = sPrompt + "Move control" + chr$(13)
                                                'sPrompt = sPrompt + "or press key " + chr$(13)
                                                'sPrompt = sPrompt + "for " + InputToString$(iWhichInput) + chr$(13)
                                                'sPrompt = sPrompt + "<ESC> + <ENTER>" + chr$(13)
                                                'sPrompt = sPrompt + "to cancel."
                                                'MapInputPrompt sPrompt, iMapX1, iMapX2, iMapY1, iMapY2, cBlack, cWhite

                                                sCaption = "Map " + InputToString$(iWhichInput) + " for " + cstr$(iMapPlayer)
                                                sPrompt = ""
                                                sPrompt = sPrompt + "Move controller or press key" + Chr$(13)
                                                sPrompt = sPrompt + "or click close 'x' to cancel."
                                                MapInputPopup sCaption, cWhite, cGray, sPrompt, cBlack, cWhite, CloseX, CloseY, ScreenArray()

                                            End If
                                        End If
                                    End If
                                End If
                            Next iIndex
                            ' END USER IS SELECTING A CONTROL TO MAP
                            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                        End If
                    Else
                        ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                        ' BEGIN USER CLICKED TO CANCEL MAP MODE
                        If iTextY = ExitY And iTextX = ExitX Then
                            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                            ' USER CLICKED EXIT SCREEN
                            bFinished = TRUE
                            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

                        ElseIf iTextY = CloseY And iTextX = CloseX Then
                            ' USER CLICKED "CANCEL"

                            ' EXIT MAP MODE
                            CloseX = 0
                            CloseY = 0

                            ' REFRESH SCREEN
                            UpdateDisplayMapInput2 arrColor(), MapArray(), ScreenArray()

                        End If
                        ' END USER CLICKED TO CANCEL MAP MODE
                        ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

                    End If
                    bOldLeftClick = TRUE
                End If
            Else
                ' USER RELEASED MOUSE BUTTON
                bOldLeftClick = FALSE
                sZone1 = ""
                sZone2 = ""
                iOffsetX = 0
                iOffsetY = 0
            End If

            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            ' BEGIN LOOK FOR MAPPING INPUT
            If CloseX > 0 And CloseY > 0 Then
                ' =============================================================================
                ' BEGIN LOOK FOR NEXT INPUT
                bMoveNext = FALSE

                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR CONTROLLER INPUT
                For iController = 1 To iNumControllers
                    iDevice = iController + 2

                    ' Check all devices
                    While _DeviceInput(iDevice)

                        ' Check each button
                        If bMoveNext = FALSE Then
                            For iLoop = 1 To _LastButton(iDevice)
                                If (iLoop > cMaxButtons) Then Exit For
                                'm_arrController(iController).buttonCount = iLoop

                                ' update button array to indicate if a button is up or down currently.
                                If _ButtonChange(iLoop) Then
                                    iValue = _Button(iLoop)
                                    If iValue <> arrButton(iController, iLoop) Then
                                        ' *****************************************************************************
                                        ' PRESSED BUTTON

                                        ' make sure this isn't already mapped
                                        bHaveInput = TRUE
                                        If iWhichInput > LBound(m_arrControlMap, 2) Then
                                            ' is input unique?
                                            For iNextInput = LBound(m_arrControlMap, 2) To iWhichInput - 1
                                                If m_arrControlMap(iMapPlayer, iNextInput).device = iDevice Then
                                                    If m_arrControlMap(iMapPlayer, iNextInput).typ = cInputButton Then
                                                        If m_arrControlMap(iMapPlayer, iNextInput).code = iLoop Then
                                                            If m_arrControlMap(iMapPlayer, iNextInput).value = iValue Then
                                                                bHaveInput = FALSE
                                                            End If
                                                        End If
                                                    End If
                                                End If
                                            Next iNextInput
                                        End If

                                        If bHaveInput Then
                                            m_arrControlMap(iMapPlayer, iWhichInput).device = iDevice
                                            m_arrControlMap(iMapPlayer, iWhichInput).typ = cInputButton
                                            m_arrControlMap(iMapPlayer, iWhichInput).code = iLoop
                                            m_arrControlMap(iMapPlayer, iWhichInput).value = iValue
                                            bMoveNext = TRUE
                                            m_bMappingChanged = TRUE
                                            Exit For
                                        End If

                                    End If
                                End If
                            Next iLoop
                        End If

                        ' Check each axis
                        If bMoveNext = FALSE Then
                            For iLoop = 1 To _LastAxis(iDevice)
                                If (iLoop > cMaxAxis) Then Exit For
                                'm_arrController(iController).axisCount = iLoop

                                dblNextAxis = _Axis(iLoop)
                                dblNextAxis = RoundUpDouble#(dblNextAxis, 3)

                                ' I like to give a little "jiggle" resistance to my controls, as I have an old joystick
                                ' which is prone to always give minute values and never really center on true 0.
                                ' A value of 1 means my axis is pushed fully in one direction.
                                ' A value greater than 0.1 means it's been partially pushed in a direction (such as at a 45 degree diagional angle).
                                ' A value of less than 0.1 means we count it as being centered. (As if it was 0.)

                                'These are way too sensitive for analog:
                                'IF ABS(_AXIS(iLoop)) <= 1 AND ABS(_AXIS(iLoop)) >= .1 THEN
                                'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .01 THEN
                                'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .001 THEN

                                'For digital input, we'll use a big picture:
                                If Abs(dblNextAxis) <= 1 And Abs(dblNextAxis) >= 0.75 Then
                                    If dblNextAxis <> arrAxis(iController, iLoop) Then
                                        ' *****************************************************************************
                                        ' MOVED STICK

                                        ' convert to a digital value
                                        If dblNextAxis < 0 Then
                                            iValue = -1
                                        Else
                                            iValue = 1
                                        End If

                                        ' make sure this isn't already mapped
                                        bHaveInput = TRUE
                                        If iWhichInput > LBound(m_arrControlMap, 2) Then
                                            ' is input unique?
                                            For iNextInput = LBound(m_arrControlMap, 2) To iWhichInput - 1
                                                If m_arrControlMap(iMapPlayer, iNextInput).device = iDevice Then
                                                    If m_arrControlMap(iMapPlayer, iNextInput).typ = cInputAxis Then
                                                        If m_arrControlMap(iMapPlayer, iNextInput).code = iLoop Then
                                                            If m_arrControlMap(iMapPlayer, iNextInput).value = iValue Then
                                                                bHaveInput = FALSE
                                                            End If
                                                        End If
                                                    End If
                                                End If
                                            Next iNextInput
                                        End If

                                        If bHaveInput Then
                                            m_arrControlMap(iMapPlayer, iWhichInput).device = iDevice
                                            m_arrControlMap(iMapPlayer, iWhichInput).typ = cInputAxis
                                            m_arrControlMap(iMapPlayer, iWhichInput).code = iLoop
                                            m_arrControlMap(iMapPlayer, iWhichInput).value = iValue
                                            bMoveNext = TRUE
                                            m_bMappingChanged = TRUE
                                            Exit For
                                        End If

                                    End If
                                End If
                            Next iLoop
                        End If

                    Wend ' clear and update the device buffer

                Next iController
                ' END CHECK FOR CONTROLLER INPUT
                ' -----------------------------------------------------------------------------

                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR KEYBOARD INPUT #1
                If bMoveNext = FALSE Then
                    '_KEYCLEAR: _DELAY 1
                    While _DeviceInput(1): Wend ' clear and update the keyboard buffer

                    ' Detect changed key state
                    For iLoop = LBound(m_arrButtonCode) To UBound(m_arrButtonCode)
                        iCode = m_arrButtonCode(iLoop)
                        If _Button(iCode) <> FALSE Then
                            ' *****************************************************************************
                            ' PRESSED KEYBOARD
                            'PRINT "PRESSED " + m_arrButtonKey(iLoop)

                            ' make sure this isn't already mapped
                            bHaveInput = TRUE
                            If iWhichInput > LBound(m_arrControlMap, 2) Then
                                ' is input unique?
                                For iNextInput = LBound(m_arrControlMap, 2) To iWhichInput - 1
                                    If m_arrControlMap(iMapPlayer, iNextInput).device = 1 Then ' .device 1 = keyboard
                                        If m_arrControlMap(iMapPlayer, iNextInput).typ = cInputKey Then
                                            If m_arrControlMap(iMapPlayer, iNextInput).code = iCode Then
                                                'if m_arrControlMap(iMapPlayer, iNextInput).value = TRUE then
                                                bHaveInput = FALSE
                                                'end if
                                            End If
                                        End If
                                    End If
                                Next iNextInput
                            End If

                            If bHaveInput Then
                                m_arrControlMap(iMapPlayer, iWhichInput).device = 1 ' .device 1 = keyboard
                                m_arrControlMap(iMapPlayer, iWhichInput).typ = cInputKey
                                m_arrControlMap(iMapPlayer, iWhichInput).code = iCode
                                m_arrControlMap(iMapPlayer, iWhichInput).value = TRUE
                                bMoveNext = TRUE
                                m_bMappingChanged = TRUE

                                ' CLEAR KEYBOARD BUFFER
                                _KeyClear: _Delay 1

                                Exit For
                            End If

                        End If
                    Next iLoop
                End If
                ' END CHECK FOR KEYBOARD INPUT #1
                ' -----------------------------------------------------------------------------

                If bMoveNext = TRUE Then
                    ' EXIT MAPPING MODE
                    CloseX = 0
                    CloseY = 0
                    iOffsetX = 0
                    iOffsetY = 0

                    ' REFRESH SCREEN
                    UpdateDisplayMapInput2 arrColor(), MapArray(), ScreenArray()
                End If

                ' END LOOK FOR NEXT INPUT
                ' =============================================================================

            End If
            ' END LOOK FOR MAPPING INPUT
            ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

            _Limit 30
        Loop Until bFinished

        _MouseShow "default": _Delay 0.5
        ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        ' END MOUSE @MOUSE
        ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    End If

    ' CLEAR KEYBOARD BUFFER
    _KeyClear

    ' CLEAR SCREEN
    Color cWhite, cBlack
    Cls

    ' DONE
    MapInput2$ = sResult

End Function ' MapInput2$

' /////////////////////////////////////////////////////////////////////////////
' Displays a popup with a close button "X" in the upper right,
' with text in MyString.

' Returns the x,y position of the close button in parameters CloseX, CloseY.

' Resolution    Cols   Rows
' 1024 x  768   128    48

' MapInputPopup sCaption, cBlack, cGray, sText, cBlack, cWhite, CloseX, CloseY

Sub MapInputPopup( _
    sCaption2 As String, fgCaptionColor  As _Unsigned Long, bgCaptionColor As _Unsigned Long, _
    sText As String, fgTextColor As _Unsigned Long, bgTextColor As _Unsigned Long, _
    CloseX As Integer, CloseY As Integer, ScreenArray() As TextCellType _
    )

    ReDim arrLines(-1) As String
    Dim sCaption As String
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iColCount As Integer
    Dim iRowCount As Integer
    Dim iLoopRows As Integer
    Dim iWidth As Integer

    Dim x1 As Integer
    Dim x2 As Integer
    Dim y1 As Integer
    Dim y2 As Integer
    Dim iY As Integer

    ' Figure out window size
    sCaption = sCaption2
    iCols = _Width(0) \ _FontWidth
    iRows = _Height(0) \ _FontHeight
    iColCount = Len(sCaption) + 1
    iRowCount = 0
    split sText, Chr$(13), arrLines()
    For iLoopRows = LBound(arrLines) To UBound(arrLines)
        iRowCount = iRowCount + 1
        If Len(arrLines(iLoopRows)) > iColCount Then
            iColCount = Len(arrLines(iLoopRows))
        End If
    Next iLoopRows

    ' Draw window as long as there is text
    If iColCount > 0 Then
        ' Make sure popup is not wider than screen
        If iColCount > iCols Then iColCount = iCols
        If iRowCount > iRows Then iRowCount = iRows
        If Len(sCaption) > (iCols - 1) Then sCaption = Left$(sCaption, iCols - 1)

        ' Center the popup
        x1 = (iCols - iColCount) \ 2
        y1 = (iRows - iRowCount) \ 2
        x2 = x1 + (iColCount - 1)
        y2 = y1 + (iRowCount - 1)

        ' Draw the caption
        Color fgCaptionColor, bgCaptionColor
        'PrintString1 y1, x1, left$(sCaption + string$(iColCount, " "), iColCount)
        PrintString2 y1, x1, Left$(sCaption + String$(iColCount, " "), iColCount), ScreenArray()

        ' Draw the close button
        Color fgTextColor, bgTextColor
        'PrintString1 y1, x2, "X"
        PrintString2 y1, x2, "X", ScreenArray()
        CloseX = x2: CloseY = y1

        ' Get width
        iWidth = (x2 - x1) + 1

        ' Draw the popup
        iY = y1
        Color fgTextColor, bgTextColor
        For iLoopRows = LBound(arrLines) To UBound(arrLines)
            iY = iY + 1: If iY > y2 Then Exit For
            PrintString2 iY, x1, Left$(arrLines(iLoopRows) + String$(iWidth, " "), iWidth), ScreenArray()
        Next iLoopRows
        For iLoopRows = iY To y2
            'PrintString1 iY, x1, String$(iColCount, " ")
            PrintString2 iLoopRows, x1, String$(iWidth, " "), ScreenArray()
        Next iLoopRows
    Else
        CloseX = 0: CloseY = 0
    End If
End Sub ' MapInputPopup

' /////////////////////////////////////////////////////////////////////////////
' MapInputPrompt MyString, iMapX1, iMapX2, iMapY1, iMapY2, cBlack, cWhite

Sub MapInputPrompt (MyString As String, x1 As Integer, x2 As Integer, y1 As Integer, y2 As Integer, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    ReDim arrLines(-1) As String
    Dim iLoopRows As Integer
    Dim iMaxLen As Integer
    Dim iY As Integer
    If x2 >= x1 Then
        If y2 >= y1 Then
            iMaxLen = (x2 - x1) + 1
            split MyString, Chr$(13), arrLines()
            iLine = 0
            iY = y1
            For iLoopRows = LBound(arrLines) To UBound(arrLines)
                Color fgColor, bgColor
                If Len(arrLines(iLoopRows)) > iMaxLen Then
                    PrintString1 iY, x1, Left$(arrLines(iLoopRows), iMaxLen)
                Else
                    PrintString1 iY, x1, Left$(arrLines(iLoopRows) + String$(iMaxLen, " "), iMaxLen)
                End If
                iY = iY + 1
                If iY > y2 Then
                    Exit For
                End If
            Next iLoopRows
            For iLoopRows = iY To y2
                PrintString1 iY, x1, String$(iMaxLen, " ")
            Next iLoopRows
        End If
    End If
End Sub ' MapInputPrompt

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END INPUT MAPPING v2
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DEBUG #2
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Sub DebugPause (sPrompt As String, iRow As Integer, iColumn As Integer, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    Color fgColor, bgColor

    PrintString iRow, iColumn, String$(128, " ")

    PrintString iRow, iColumn, sPrompt
    Sleep
    '_KEYCLEAR: _DELAY 1
    'DO
    'LOOP UNTIL _KEYDOWN(13) ' leave loop when ENTER key pressed
    '_KEYCLEAR: _DELAY 1
End Sub ' DebugPause

' /////////////////////////////////////////////////////////////////////////////

Sub DebugOut (sPrompt As String, iRow As Integer, iColumn As Integer, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    Color fgColor, bgColor
    PrintString iRow, iColumn, String$(128, " ")
    PrintString iRow, iColumn, sPrompt
End Sub ' DebugOut

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DEBUG #2
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN MOUSE TEST
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Function TestMouseXYButton$
    Dim RoutineName As String: RoutineName = "TestMouseXYButton$"
    Dim iX1 As Integer: iX1 = 0
    Dim iY1 As Integer: iY1 = 0
    Dim iOldX1 As Integer: iOldX1 = 0
    Dim iOldY1 As Integer: iOldY1 = 0
    Dim bLeftClick As Integer: bLeftClick = FALSE
    Dim bRightClick As Integer: bRightClick = FALSE
    Dim bMiddleClick As Integer: bMiddleClick = FALSE
    Dim bOldLeftClick As Integer: bOldLeftClick = FALSE
    Dim bOldRightClick As Integer: bOldRightClick = FALSE
    Dim bOldMiddleClick As Integer: bOldMiddleClick = FALSE
    Dim iX2 As Integer: iX2 = _Width / 2
    Dim iY2 As Integer: iY2 = _Height / 2
    Dim iOldX2 As Integer: iOldX2 = 0
    Dim iOldY2 As Integer: iOldY2 = 0
    Dim iColor1 As _Unsigned Long: iColor1 = cRed
    Dim iColor2 As _Unsigned Long: iColor2 = cLime
    Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
    Cls

    _MouseHide ' hide OS mouse pointer
    Do While _MouseInput: Loop
    Do
        Color cWhite, cBlack
        If iOldX1 <> iX1 Or iOldY1 <> iY1 Then _PrintString (iOldX1, iOldY1), " "
        If iOldX2 <> iX2 Or iOldY2 <> iY2 Then _PrintString (iOldX2, iOldY2), " "

        Color cWhite, cEmpty
        PrintString 0, 0, "_MOUSEX        ="
        PrintString 1, 0, "_MOUSEY        ="
        PrintString 2, 0, "_MOUSEBUTTON(1)="
        PrintString 3, 0, "_MOUSEBUTTON(2)="
        PrintString 4, 0, "_MOUSEBUTTON(3)="
        PrintString 5, 0, "_MOUSEWHEEL X  ="
        PrintString 6, 0, "_MOUSEWHEEL Y  ="
        PrintString 8, 0, "PRESS <ESC> TO EXIT"

        Color cWhite, cBlack
        PrintString 0, 16, Left$(cstr$(iX1) + "     ", 5)
        PrintString 1, 16, Left$(cstr$(iY1) + "     ", 5)
        PrintString 2, 16, Left$(TrueFalse$(bLeftClick) + "     ", 5)
        PrintString 3, 16, Left$(TrueFalse$(bRightClick) + "     ", 5)
        PrintString 4, 16, Left$(TrueFalse$(bMiddleClick) + "     ", 5)
        PrintString 5, 16, Left$(cstr$(iX2) + "     ", 5)
        PrintString 6, 16, Left$(cstr$(iY2) + "     ", 5)

        Color cBlack, iColor1: _PrintString (iX1, iY1), " "
        iOldX1 = iX1: iOldY1 = iY1

        Color cBlack, iColor2: _PrintString (iX2, iY2), " "
        iOldX2 = iX2: iOldY2 = iY2

        iX1 = (_MouseX \ _FontWidth) * _FontWidth
        iY1 = (_MouseY \ _FontHeight) * _FontHeight

        bLeftClick = _MouseButton(1)
        If bLeftClick Then
            If bOldLeftClick = FALSE Then
                If iColor1 = cOrangeRed Then
                    iColor1 = cRed
                ElseIf iColor1 = cRed Then
                    iColor1 = cMagenta
                Else
                    iColor1 = cOrangeRed
                End If
                bOldLeftClick = TRUE
            End If
        Else
            bOldLeftClick = FALSE
        End If

        bRightClick = _MouseButton(2)
        If bRightClick Then
            If bOldRightClick = FALSE Then
                If iColor2 = cBlue Then
                    iColor2 = cLime
                ElseIf iColor2 = cLime Then
                    iColor2 = cYellow
                Else
                    iColor2 = cBlue
                End If
                bOldRightClick = TRUE
            End If
        Else
            bOldRightClick = FALSE
        End If

        bMiddleClick = _MouseButton(3)

        Do While _MouseInput
            If bMiddleClick Then
                iY2 = iY2 + (_MouseWheel * _FontHeight) ' -1 up, 0 no movement, 1 down
            Else
                iX2 = iX2 + (_MouseWheel * _FontWidth) ' -1 up, 0 no movement, 1 down
            End If
        Loop

        If iY2 < 1 Then iY2 = 1
        If iY2 > (_Height - _FontHeight) Then iY2 = (HEIGHT - _FontHeight)

    Loop Until _KeyDown(27)
    _KeyClear

    _MouseShow "default": _Delay 0.5
    Screen 0
    TestMouseXYButton$ = ""
End Function ' TestMouseXYButton$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END MOUSE TEST
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN MAP CONTROLS v1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Function MapInput1$
    Dim RoutineName As String: RoutineName = "MapInput1$"
    Dim in$
    Dim iDeviceCount As Integer
    Dim iPlayer As Integer
    Dim sResult As String
    Dim sError As String

    ' INITIALIZE
    InitKeyboardButtonCodes

    ' SET UP SCREEN
    Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0

    ' MAKE SURE WE HAVE DEVICES
    ' 1 is the keyboard
    ' 2 is the mouse
    ' 3 is the joystick
    ' unless someone has a strange setup with multiple mice/keyboards/ect...
    ' In that case, you can use _DEVICE$(i) to look for "KEYBOARD", "MOUSE", "JOYSTICK", if necessary.
    ' I've never actually found it necessary, but I figure it's worth mentioning, just in case...
    iDeviceCount = _Devices ' Find the number of devices on someone's system
    If iDeviceCount > 2 Then
        '' Try loading map
        'sError = LoadControllerMap1$
        'if len(sError) = 0 then
        '    print "Previous controller mapping loaded."
        'else
        '    print "*******************************************************************************"
        '    print "There were errors loading the controller mapping file:"
        '    print sError
        '    print
        '    print "Try remapping - a new file will be created."
        '    print "*******************************************************************************"
        'end if
        Do
            PrintControllerMap2
            Print "To edit mapping, enter a player number (1-" + cstr$(cMaxPlayers) + ") or 0 to exit."
            Input "Get input for player? "; iPlayer
            If iPlayer > 0 And iPlayer <= cMaxPlayers Then
                sResult = MapInput1b$(iPlayer)
                If Len(sResult) = 0 Then
                    Print "Remember to save mappings when done."
                Else
                    Print sResult
                End If
            Else
                sResult = "(Cancelled.)"
                Exit Do
            End If
        Loop
    Else
        sResult = "No controller devices found."
        Input "PRESS <ENTER> TO CONTINUE", in$
    End If
    MapInput1$ = sResult

End Function ' MapInput1$

' /////////////////////////////////////////////////////////////////////////////
' Detect controls
' THIS VERSION SUPPORTS UPTO 8 JOYSTICKS, WITH UPTO 2 BUTTONS AND 2 AXES EACH
' (THIS IS FOR ATARI 2600 JOYSTICKS)

' The following shared arrays must be declared:
'     ReDim Shared m_arrButtonCode(1 To 99) As Long
'     ReDim Shared m_arrButtonKey(1 To 99) As String

Function MapInput1b$ (iPlayer As Integer)
    Dim RoutineName As String:: RoutineName = "MapInput1b$"
    Dim sResult As String: sResult = ""
    Dim sError As String: sError = ""

    Dim in$

    Dim iDeviceCount As Integer
    Dim iDevice As Integer
    Dim iNumControllers As Integer
    Dim iController As Integer

    Dim iLoop As Integer
    Dim strValue As String
    Dim strAxis As String
    Dim dblNextAxis As Double
    Dim iCount As Long
    Dim iValue As Integer
    Dim iCode As Integer

    Dim arrButton(32, 16) As Integer ' number of buttons on the joystick
    Dim arrButtonNew(32, 16) As Integer ' tracks when to initialize values
    Dim arrAxis(32, 16) As Double ' number of axis on the joystick
    Dim arrAxisNew(32, 16) As Integer ' tracks when to initialize values

    'Dim arrInput(1 To 8) As ControlInputType
    Dim iWhichInput As Integer
    Dim bFinished As Integer
    Dim bHaveInput As Integer
    Dim bMoveNext As Integer
    Dim bCancel As Integer
    Dim iNextInput As Integer

    ' FOR PRINTING OUTPUT
    Dim iDigits As Integer ' # digits to display (values are truncated to this length)
    Dim iColCount As Integer
    Dim iGroupCount As Integer
    Dim sLine As String
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iMaxCols As Integer

    ' INITIALIZE
    If Len(sError) = 0 Then
        iDigits = 4 ' 11
        iColCount = 3
        iGroupCount = 0 ' re-initialized at the top of every loop
        iCols = _Width(0) \ _FontWidth
        iRows = _Height(0) \ _FontHeight
    End If

    ' COUNT # OF JOYSTICKS
    ' TODO: find out the right way to count joysticks
    If Len(sError) = 0 Then
        ' D= _DEVICES ' MUST be read in order for other 2 device functions to work!
        iDeviceCount = _Devices ' Find the number of devices on someone's system

        If iDeviceCount > 2 Then
            ' LIMIT # OF DEVICES, IF THERE IS A LIMIT DEFINED
            iNumControllers = iDeviceCount - 2
            If cMaxControllers > 0 Then
                If iNumControllers > cMaxControllers Then
                    iNumControllers = cMaxControllers
                End If
            End If
        Else
            ' ONLY 2 FOUND (KEYBOARD, MOUSE)
            sError = "No game controllers found."
        End If
    End If

    ' INITIALIZE CONTROLLER DATA
    If Len(sError) = 0 Then
        For iController = 1 To iNumControllers
            m_arrController(iController).buttonCount = cMaxButtons
            m_arrController(iController).axisCount = cMaxAxis
            For iLoop = 1 To cMaxButtons
                arrButtonNew(iController, iLoop) = TRUE
            Next iLoop
            For iLoop = 1 To cMaxAxis
                arrAxisNew(iController, iLoop) = TRUE
            Next iLoop
        Next iController
    End If

    ' INITIALIZE CONTROLLER INPUT
    If Len(sError) = 0 Then
        Cls
        Print "We will now detect controllers."
        Print "Do not touch any keys or game controllers during detection."
        Input "Press <ENTER> to begin"; in$
        _KeyClear: Print
        sLine = "Initializing controllers": Print sLine;
        iMaxCols = (iCols - Len(sLine)) - 1
        iCount = 0
        Do
            iCount = iCount + 1
            If iCount < iMaxCols Then
                Print ".";
            Else
                Print ".": Print sLine: iCount = 0
            End If
            For iController = 1 To iNumControllers
                iDevice = iController + 2
                While _DeviceInput(iDevice) ' clear and update the device buffer
                    For iLoop = 1 To _LastButton(iDevice)
                        If (iLoop > cMaxButtons) Then Exit For
                        m_arrController(iController).buttonCount = iLoop
                        'IF _BUTTONCHANGE(iLoop) THEN
                        '    arrButton(iController, iLoop) = _BUTTON(iLoop)
                        'END IF
                        arrButton(iController, iLoop) = FALSE
                    Next iLoop
                    For iLoop = 1 To _LastAxis(iDevice) ' this loop checks all my axis
                        If (iLoop > cMaxAxis) Then Exit For
                        m_arrController(iController).axisCount = iLoop
                        arrAxis(iController, iLoop) = 0
                    Next iLoop
                Wend ' clear and update the device buffer
            Next iController
            _Limit 30
        Loop Until iCount > 60 ' quit after 2 seconds
        Print: Print
    End If

    ' WAIT FOR INPUT
    If Len(sError) = 0 Then
        Cls
        Print "Press <ESCAPE> to cancel at any time."
        Print

        _KeyClear: _Delay 1
        bCancel = FALSE
        bFinished = FALSE
        iLastPressed = 0
        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
            'print "iWhichInput=" + cstr$(iWhichInput)
            Print "Player #" + cstr$(iPlayer) + " press control for " + InputToString$(iWhichInput) + " or ESC to skip: ";

            ' =============================================================================
            ' BEGIN LOOK FOR NEXT INPUT
            bMoveNext = FALSE
            Do
                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR CONTROLLER INPUT
                For iController = 1 To iNumControllers
                    iDevice = iController + 2

                    ' Check all devices
                    While _DeviceInput(iDevice)

                        ' Check each button
                        If bMoveNext = FALSE Then
                            For iLoop = 1 To _LastButton(iDevice)
                                If (iLoop > cMaxButtons) Then Exit For
                                'm_arrController(iController).buttonCount = iLoop

                                ' update button array to indicate if a button is up or down currently.
                                If _ButtonChange(iLoop) Then
                                    iValue = _Button(iLoop)
                                    If iValue <> arrButton(iController, iLoop) Then
                                        ' *****************************************************************************
                                        ' PRESSED BUTTON

                                        ' make sure this isn't already mapped
                                        bHaveInput = TRUE
                                        If iWhichInput > LBound(m_arrControlMap, 2) Then
                                            ' is input unique?
                                            For iNextInput = LBound(m_arrControlMap, 2) To iWhichInput - 1
                                                If m_arrControlMap(iPlayer, iNextInput).device = iDevice Then
                                                    If m_arrControlMap(iPlayer, iNextInput).typ = cInputButton Then
                                                        If m_arrControlMap(iPlayer, iNextInput).code = iLoop Then
                                                            If m_arrControlMap(iPlayer, iNextInput).value = iValue Then
                                                                bHaveInput = FALSE
                                                            End If
                                                        End If
                                                    End If
                                                End If
                                            Next iNextInput
                                        End If

                                        If bHaveInput Then
                                            m_arrControlMap(iPlayer, iWhichInput).device = iDevice
                                            m_arrControlMap(iPlayer, iWhichInput).typ = cInputButton
                                            m_arrControlMap(iPlayer, iWhichInput).code = iLoop
                                            m_arrControlMap(iPlayer, iWhichInput).value = iValue
                                            bMoveNext = TRUE
                                            m_bMappingChanged = TRUE
                                        End If

                                    End If
                                End If
                            Next iLoop
                        End If

                        ' Check each axis
                        If bMoveNext = FALSE Then
                            For iLoop = 1 To _LastAxis(iDevice)
                                If (iLoop > cMaxAxis) Then Exit For
                                'm_arrController(iController).axisCount = iLoop

                                dblNextAxis = _Axis(iLoop)
                                dblNextAxis = RoundUpDouble#(dblNextAxis, 3)

                                ' I like to give a little "jiggle" resistance to my controls, as I have an old joystick
                                ' which is prone to always give minute values and never really center on true 0.
                                ' A value of 1 means my axis is pushed fully in one direction.
                                ' A value greater than 0.1 means it's been partially pushed in a direction (such as at a 45 degree diagional angle).
                                ' A value of less than 0.1 means we count it as being centered. (As if it was 0.)

                                'These are way too sensitive for analog:
                                'IF ABS(_AXIS(iLoop)) <= 1 AND ABS(_AXIS(iLoop)) >= .1 THEN
                                'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .01 THEN
                                'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .001 THEN

                                'For digital input, we'll use a big picture:
                                If Abs(dblNextAxis) <= 1 And Abs(dblNextAxis) >= 0.75 Then
                                    If dblNextAxis <> arrAxis(iController, iLoop) Then
                                        ' *****************************************************************************
                                        ' MOVED STICK

                                        ' convert to a digital value
                                        If dblNextAxis < 0 Then
                                            iValue = -1
                                        Else
                                            iValue = 1
                                        End If

                                        ' make sure this isn't already mapped
                                        bHaveInput = TRUE
                                        If iWhichInput > LBound(m_arrControlMap, 2) Then
                                            ' is input unique?
                                            For iNextInput = LBound(m_arrControlMap, 2) To iWhichInput - 1
                                                If m_arrControlMap(iPlayer, iNextInput).device = iDevice Then
                                                    If m_arrControlMap(iPlayer, iNextInput).typ = cInputAxis Then
                                                        If m_arrControlMap(iPlayer, iNextInput).code = iLoop Then
                                                            If m_arrControlMap(iPlayer, iNextInput).value = iValue Then
                                                                bHaveInput = FALSE
                                                            End If
                                                        End If
                                                    End If
                                                End If
                                            Next iNextInput
                                        End If

                                        If bHaveInput Then
                                            m_arrControlMap(iPlayer, iWhichInput).device = iDevice
                                            m_arrControlMap(iPlayer, iWhichInput).typ = cInputAxis
                                            m_arrControlMap(iPlayer, iWhichInput).code = iLoop
                                            m_arrControlMap(iPlayer, iWhichInput).value = iValue
                                            bMoveNext = TRUE
                                            m_bMappingChanged = TRUE
                                        End If

                                    End If
                                End If
                            Next iLoop
                        End If

                    Wend ' clear and update the device buffer

                Next iController
                ' END CHECK FOR CONTROLLER INPUT
                ' -----------------------------------------------------------------------------

                ' -----------------------------------------------------------------------------
                ' BEGIN CHECK FOR KEYBOARD INPUT #1
                If bMoveNext = FALSE Then
                    '_KEYCLEAR: _DELAY 1
                    While _DeviceInput(1): Wend ' clear and update the keyboard buffer

                    ' Detect changed key state
                    For iLoop = LBound(m_arrButtonCode) To UBound(m_arrButtonCode)
                        iCode = m_arrButtonCode(iLoop)
                        If _Button(iCode) <> FALSE Then
                            ' *****************************************************************************
                            ' PRESSED KEYBOARD
                            'PRINT "PRESSED " + m_arrButtonKey(iLoop)

                            ' make sure this isn't already mapped
                            bHaveInput = TRUE
                            If iWhichInput > LBound(m_arrControlMap, 2) Then
                                ' is input unique?
                                For iNextInput = LBound(m_arrControlMap, 2) To iWhichInput - 1
                                    If m_arrControlMap(iPlayer, iNextInput).device = 1 Then ' .device 1 = keyboard
                                        If m_arrControlMap(iPlayer, iNextInput).typ = cInputKey Then
                                            If m_arrControlMap(iPlayer, iNextInput).code = iCode Then
                                                'if m_arrControlMap(iPlayer, iNextInput).value = TRUE then
                                                bHaveInput = FALSE
                                                'end if
                                            End If
                                        End If
                                    End If
                                Next iNextInput
                            End If

                            If bHaveInput Then
                                m_arrControlMap(iPlayer, iWhichInput).device = 1 ' .device 1 = keyboard
                                m_arrControlMap(iPlayer, iWhichInput).typ = cInputKey
                                m_arrControlMap(iPlayer, iWhichInput).code = iCode
                                m_arrControlMap(iPlayer, iWhichInput).value = TRUE
                                bMoveNext = TRUE
                                m_bMappingChanged = TRUE
                            End If

                        End If
                    Next iLoop
                End If
                ' END CHECK FOR KEYBOARD INPUT #1
                ' -----------------------------------------------------------------------------

                If bMoveNext = TRUE Then Exit Do
                _Limit 30
            Loop Until _KeyHit = 27 ' ESCAPE to quit
            ' END LOOK FOR NEXT INPUT
            ' =============================================================================

            If bMoveNext = TRUE Then
                Print "Device #" + cstr$(m_arrControlMap(iPlayer, iWhichInput).device) + " " + _
                    InputTypeToString$(m_arrControlMap(iPlayer, iWhichInput).typ) + " " + _
                    cstr$(m_arrControlMap(iPlayer, iWhichInput).code) + " = " + _
                    cstr$(m_arrControlMap(iPlayer, iWhichInput).value)

                ' Only ask user to select repeat if no override.
                If m_bRepeatOverride = FALSE Then
                    Input "Enable repeat (y/n)"; in$: in$ = LCase$(_Trim$(in$))
                    If in$ = "y" Then
                        m_arrControlMap(iPlayer, iWhichInput).repeat = TRUE
                    Else
                        m_arrControlMap(iPlayer, iWhichInput).repeat = FALSE
                    End If
                Else
                    m_arrControlMap(iPlayer, iWhichInput).repeat = GetGlobalInputRepeatSetting%(iWhichInput)
                End If
            Else
                Print "(Skipped)"
                bCancel = TRUE
                bFinished = TRUE
            End If

            If bFinished = TRUE Then Exit For
        Next iWhichInput
    End If

    If Len(sError) = 0 Then
        m_bHaveMapping = TRUE
    Else
        sResult = "ERRORS: " + sError
    End If

    _KeyClear: _Delay 1
    MapInput1b$ = sResult
End Function ' MapInput1b$

' /////////////////////////////////////////////////////////////////////////////
' Receives which input contstant and returns a text description

Function InputToString$ (iWhich As Integer)
    Select Case iWhich
        Case cInputUp:
            InputToString$ = "up"
        Case cInputDown:
            InputToString$ = "down"
        Case cInputLeft:
            InputToString$ = "left"
        Case cInputRight:
            InputToString$ = "right"
        Case cInputButton1:
            InputToString$ = "button #1"
        Case cInputButton2:
            InputToString$ = "button #2"
        Case cInputButton3:
            InputToString$ = "button #3"
        Case cInputButton4:
            InputToString$ = "button #4"
        Case Else:
            InputToString$ = "unknown"
    End Select
End Function ' InputToString$

' /////////////////////////////////////////////////////////////////////////////
' Receives which input contstant and returns a text description
' that matches the TextFieldType and TextLabelType ".item" member.

Function InputToItem$ (iWhich As Integer)
    Select Case iWhich
        Case cInputUp:
            InputToItem$ = "Up"
        Case cInputDown:
            InputToItem$ = "Down"
        Case cInputLeft:
            InputToItem$ = "Left"
        Case cInputRight:
            InputToItem$ = "Right"
        Case cInputButton1:
            InputToItem$ = "Button1"
        Case cInputButton2:
            InputToItem$ = "Button2"
        Case cInputButton3:
            InputToItem$ = "Button3"
        Case cInputButton4:
            InputToItem$ = "Button4"
        Case Else:
            InputToItem$ = ""
    End Select
End Function ' InputToItem$

' /////////////////////////////////////////////////////////////////////////////
' Receives which input contstant and returns its global "repeat" setting

' usage:
'     m_arrControlMap(iPlayer, iWhichInput).repeat = GetGlobalInputRepeatSetting%(cInputUp)

Function GetGlobalInputRepeatSetting% (iWhich As Integer)
    Select Case iWhich
        Case cInputUp:
            GetGlobalInputRepeatSetting% = m_bRepeatUp
        Case cInputDown:
            GetGlobalInputRepeatSetting% = m_bRepeatDown
        Case cInputLeft:
            GetGlobalInputRepeatSetting% = m_bRepeatLeft
        Case cInputRight:
            GetGlobalInputRepeatSetting% = m_bRepeatRight
        Case cInputButton1:
            GetGlobalInputRepeatSetting% = m_bRepeatButton1
        Case cInputButton2:
            GetGlobalInputRepeatSetting% = m_bRepeatButton2
        Case cInputButton3:
            GetGlobalInputRepeatSetting% = m_bRepeatButton3
        Case cInputButton4:
            GetGlobalInputRepeatSetting% = m_bRepeatButton4
        Case Else:
            GetGlobalInputRepeatSetting% = FALSE
    End Select
End Function ' GetGlobalInputRepeatSetting%

' /////////////////////////////////////////////////////////////////////////////

Function InputTypeToString$ (iCode As Integer)
    Select Case iCode
        Case cInputNone:
            InputTypeToString$ = "none"
        Case cInputKey:
            InputTypeToString$ = "key"
        Case cInputButton:
            InputTypeToString$ = "button"
        Case cInputAxis:
            InputTypeToString$ = "axis"
        Case Else:
            InputTypeToString$ = "unknown"
    End Select
End Function ' InputTypeToString$

' /////////////////////////////////////////////////////////////////////////////
' METHOD v2 = faster

Function GetKeyboardButtonCodeText$ (iCode As Integer)
    Dim sResult As String: sResult = ""
    If LBound(m_arrButtonKeyDesc) <= iCode Then
        If UBound(m_arrButtonKeyDesc) >= iCode Then
            sResult = m_arrButtonKeyDesc(iCode)
        End If
    End If
    If Len(sResult) = 0 Then
        sResult = _Trim$(Str$(iCode)) + " (?)"
    End If
    GetKeyboardButtonCodeText$ = sResult
End Function ' GetKeyboardButtonCodeText$

' /////////////////////////////////////////////////////////////////////////////
' METHOD v2
' Faster lookup - a dictionary with a hash lookup would be best
' but this is a quick way to do it since the values never change.

' The following shared arrays must be declared:
'     ReDim Shared m_arrButtonCode(1 To 99) As Long
'     ReDim Shared m_arrButtonKey(1 To 99) As String
'     ReDim Shared m_arrButtonKeyDesc(0 To 512) As String

Sub InitKeyboardButtonCodes ()
    Dim iLoop As Integer

    If m_bInitialized = FALSE Then
        ' CODE(S) DETECTED WITH _BUTTON:
        m_arrButtonCode(1) = 2: m_arrButtonKey(1) = "Esc"
        m_arrButtonCode(2) = 60: m_arrButtonKey(2) = "F1"
        m_arrButtonCode(3) = 61: m_arrButtonKey(3) = "F2"
        m_arrButtonCode(4) = 62: m_arrButtonKey(4) = "F3"
        m_arrButtonCode(5) = 63: m_arrButtonKey(5) = "F4"
        m_arrButtonCode(6) = 64: m_arrButtonKey(6) = "F5"
        m_arrButtonCode(7) = 65: m_arrButtonKey(7) = "F6"
        m_arrButtonCode(8) = 66: m_arrButtonKey(8) = "F7"
        m_arrButtonCode(9) = 67: m_arrButtonKey(9) = "F8"
        m_arrButtonCode(10) = 68: m_arrButtonKey(10) = "F9"
        m_arrButtonCode(11) = 88: m_arrButtonKey(11) = "F11"
        m_arrButtonCode(12) = 89: m_arrButtonKey(12) = "F12"
        m_arrButtonCode(13) = 42: m_arrButtonKey(13) = "Tilde"
        m_arrButtonCode(14) = 3: m_arrButtonKey(14) = "1"
        m_arrButtonCode(15) = 4: m_arrButtonKey(15) = "2"
        m_arrButtonCode(16) = 5: m_arrButtonKey(16) = "3"
        m_arrButtonCode(17) = 6: m_arrButtonKey(17) = "4"
        m_arrButtonCode(18) = 7: m_arrButtonKey(18) = "5"
        m_arrButtonCode(19) = 8: m_arrButtonKey(19) = "6"
        m_arrButtonCode(20) = 9: m_arrButtonKey(20) = "7"
        m_arrButtonCode(21) = 10: m_arrButtonKey(21) = "8"
        m_arrButtonCode(22) = 11: m_arrButtonKey(22) = "9"
        m_arrButtonCode(23) = 12: m_arrButtonKey(23) = "0"
        m_arrButtonCode(24) = 13: m_arrButtonKey(24) = "Minus"
        m_arrButtonCode(25) = 14: m_arrButtonKey(25) = "Equal"
        m_arrButtonCode(26) = 15: m_arrButtonKey(26) = "BkSp"
        m_arrButtonCode(27) = 16: m_arrButtonKey(27) = "Tab"
        m_arrButtonCode(28) = 17: m_arrButtonKey(28) = "Q"
        m_arrButtonCode(29) = 18: m_arrButtonKey(29) = "W"
        m_arrButtonCode(30) = 19: m_arrButtonKey(30) = "E"
        m_arrButtonCode(31) = 20: m_arrButtonKey(31) = "R"
        m_arrButtonCode(32) = 21: m_arrButtonKey(32) = "T"
        m_arrButtonCode(33) = 22: m_arrButtonKey(33) = "Y"
        m_arrButtonCode(34) = 23: m_arrButtonKey(34) = "U"
        m_arrButtonCode(35) = 24: m_arrButtonKey(35) = "I"
        m_arrButtonCode(36) = 25: m_arrButtonKey(36) = "O"
        m_arrButtonCode(37) = 26: m_arrButtonKey(37) = "P"
        m_arrButtonCode(38) = 27: m_arrButtonKey(38) = "BracketLeft"
        m_arrButtonCode(39) = 28: m_arrButtonKey(39) = "BracketRight"
        m_arrButtonCode(40) = 44: m_arrButtonKey(40) = "Backslash"
        m_arrButtonCode(41) = 59: m_arrButtonKey(41) = "CapsLock"
        m_arrButtonCode(42) = 31: m_arrButtonKey(42) = "A"
        m_arrButtonCode(43) = 32: m_arrButtonKey(43) = "S"
        m_arrButtonCode(44) = 33: m_arrButtonKey(44) = "D"
        m_arrButtonCode(45) = 34: m_arrButtonKey(45) = "F"
        m_arrButtonCode(46) = 35: m_arrButtonKey(46) = "G"
        m_arrButtonCode(47) = 36: m_arrButtonKey(47) = "H"
        m_arrButtonCode(48) = 37: m_arrButtonKey(48) = "J"
        m_arrButtonCode(49) = 38: m_arrButtonKey(49) = "K"
        m_arrButtonCode(50) = 39: m_arrButtonKey(50) = "L"
        m_arrButtonCode(51) = 40: m_arrButtonKey(51) = "Semicolon"
        m_arrButtonCode(52) = 41: m_arrButtonKey(52) = "Apostrophe"
        m_arrButtonCode(53) = 29: m_arrButtonKey(53) = "Enter"
        m_arrButtonCode(54) = 43: m_arrButtonKey(54) = "ShiftLeft"
        m_arrButtonCode(55) = 45: m_arrButtonKey(55) = "Z"
        m_arrButtonCode(56) = 46: m_arrButtonKey(56) = "X"
        m_arrButtonCode(57) = 47: m_arrButtonKey(57) = "C"
        m_arrButtonCode(58) = 48: m_arrButtonKey(58) = "V"
        m_arrButtonCode(59) = 49: m_arrButtonKey(59) = "B"
        m_arrButtonCode(60) = 50: m_arrButtonKey(60) = "N"
        m_arrButtonCode(61) = 51: m_arrButtonKey(61) = "M"
        m_arrButtonCode(62) = 52: m_arrButtonKey(62) = "Comma"
        m_arrButtonCode(63) = 53: m_arrButtonKey(63) = "Period"
        m_arrButtonCode(64) = 54: m_arrButtonKey(64) = "Slash"
        m_arrButtonCode(65) = 55: m_arrButtonKey(65) = "ShiftRight"
        m_arrButtonCode(66) = 30: m_arrButtonKey(66) = "CtrlLeft"
        m_arrButtonCode(67) = 348: m_arrButtonKey(67) = "WinLeft"
        m_arrButtonCode(68) = 58: m_arrButtonKey(68) = "Spacebar"
        m_arrButtonCode(69) = 349: m_arrButtonKey(69) = "WinRight"
        m_arrButtonCode(70) = 350: m_arrButtonKey(70) = "Menu"
        m_arrButtonCode(71) = 286: m_arrButtonKey(71) = "CtrlRight"
        m_arrButtonCode(72) = 339: m_arrButtonKey(72) = "Ins"
        m_arrButtonCode(73) = 328: m_arrButtonKey(73) = "Home"
        m_arrButtonCode(74) = 330: m_arrButtonKey(74) = "PgUp"
        m_arrButtonCode(75) = 340: m_arrButtonKey(75) = "Del"
        m_arrButtonCode(76) = 336: m_arrButtonKey(76) = "End"
        m_arrButtonCode(77) = 338: m_arrButtonKey(77) = "PgDn"
        m_arrButtonCode(78) = 329: m_arrButtonKey(78) = "Up"
        m_arrButtonCode(79) = 332: m_arrButtonKey(79) = "Left"
        m_arrButtonCode(80) = 337: m_arrButtonKey(80) = "Down"
        m_arrButtonCode(81) = 334: m_arrButtonKey(81) = "Right"
        m_arrButtonCode(82) = 71: m_arrButtonKey(82) = "ScrollLock"
        m_arrButtonCode(83) = 326: m_arrButtonKey(83) = "NumLock"
        m_arrButtonCode(84) = 310: m_arrButtonKey(84) = "KeypadSlash"
        m_arrButtonCode(85) = 56: m_arrButtonKey(85) = "KeypadMultiply"
        m_arrButtonCode(86) = 75: m_arrButtonKey(86) = "KeypadMinus"
        m_arrButtonCode(87) = 72: m_arrButtonKey(87) = "Keypad7Home"
        m_arrButtonCode(88) = 73: m_arrButtonKey(88) = "Keypad8Up"
        m_arrButtonCode(89) = 74: m_arrButtonKey(89) = "Keypad9PgUp"
        m_arrButtonCode(90) = 79: m_arrButtonKey(90) = "KeypadPlus"
        m_arrButtonCode(91) = 76: m_arrButtonKey(91) = "Keypad4Left"
        m_arrButtonCode(92) = 77: m_arrButtonKey(92) = "Keypad5"
        m_arrButtonCode(93) = 78: m_arrButtonKey(93) = "Keypad6Right"
        m_arrButtonCode(94) = 80: m_arrButtonKey(94) = "Keypad1End"
        m_arrButtonCode(95) = 81: m_arrButtonKey(95) = "Keypad2Down"
        m_arrButtonCode(96) = 82: m_arrButtonKey(96) = "Keypad3PgDn"
        m_arrButtonCode(97) = 285: m_arrButtonKey(97) = "KeypadEnter"
        m_arrButtonCode(98) = 83: m_arrButtonKey(98) = "Keypad0Ins"
        m_arrButtonCode(99) = 84: m_arrButtonKey(99) = "KeypadPeriodDel"

        ' not sure if this works:
        '' CODE(S) DETECTED WITH _KEYDOWN:
        'm_arrButtonCode(100) = -1 : m_arrButtonCode(100) = "F10"

        ' not sure if this works:
        '' CODE(S) DETECTED WITH _KEYHIT:
        'm_arrButtonCode(101) = -2 : m_arrButtonCode(101) = "AltLeft"
        'm_arrButtonCode(102) = -3 : m_arrButtonCode(102) = "AltRight"

        ' SHORT DESCRIPTIONS BY KEYCODE (15 CHARACTERS)
        For iLoop = LBound(m_arrButtonKeyDesc) To UBound(m_arrButtonKeyDesc)
            m_arrButtonKeyDesc(iLoop) = ""
        Next iLoop
        m_arrButtonKeyDesc(2) = "Esc"
        m_arrButtonKeyDesc(60) = "F1"
        m_arrButtonKeyDesc(61) = "F2"
        m_arrButtonKeyDesc(62) = "F3"
        m_arrButtonKeyDesc(63) = "F4"
        m_arrButtonKeyDesc(64) = "F5"
        m_arrButtonKeyDesc(65) = "F6"
        m_arrButtonKeyDesc(66) = "F7"
        m_arrButtonKeyDesc(67) = "F8"
        m_arrButtonKeyDesc(68) = "F9"
        m_arrButtonKeyDesc(88) = "F11"
        m_arrButtonKeyDesc(89) = "F12"
        m_arrButtonKeyDesc(42) = "Tilde"
        m_arrButtonKeyDesc(3) = "1"
        m_arrButtonKeyDesc(4) = "2"
        m_arrButtonKeyDesc(5) = "3"
        m_arrButtonKeyDesc(6) = "4"
        m_arrButtonKeyDesc(7) = "5"
        m_arrButtonKeyDesc(8) = "6"
        m_arrButtonKeyDesc(9) = "7"
        m_arrButtonKeyDesc(10) = "8"
        m_arrButtonKeyDesc(11) = "9"
        m_arrButtonKeyDesc(12) = "0"
        m_arrButtonKeyDesc(13) = "Minus"
        m_arrButtonKeyDesc(14) = "Equal"
        m_arrButtonKeyDesc(15) = "BkSp"
        m_arrButtonKeyDesc(16) = "Tab"
        m_arrButtonKeyDesc(17) = "Q"
        m_arrButtonKeyDesc(18) = "W"
        m_arrButtonKeyDesc(19) = "E"
        m_arrButtonKeyDesc(20) = "R"
        m_arrButtonKeyDesc(21) = "T"
        m_arrButtonKeyDesc(22) = "Y"
        m_arrButtonKeyDesc(23) = "U"
        m_arrButtonKeyDesc(24) = "I"
        m_arrButtonKeyDesc(25) = "O"
        m_arrButtonKeyDesc(26) = "P"
        m_arrButtonKeyDesc(27) = "BracketLeft"
        m_arrButtonKeyDesc(28) = "BracketRight"
        m_arrButtonKeyDesc(44) = "Backslash"
        m_arrButtonKeyDesc(59) = "CapsLock"
        m_arrButtonKeyDesc(31) = "A"
        m_arrButtonKeyDesc(32) = "S"
        m_arrButtonKeyDesc(33) = "D"
        m_arrButtonKeyDesc(34) = "F"
        m_arrButtonKeyDesc(35) = "G"
        m_arrButtonKeyDesc(36) = "H"
        m_arrButtonKeyDesc(37) = "J"
        m_arrButtonKeyDesc(38) = "K"
        m_arrButtonKeyDesc(39) = "L"
        m_arrButtonKeyDesc(40) = "Semicolon"
        m_arrButtonKeyDesc(41) = "Apostrophe"
        m_arrButtonKeyDesc(29) = "Enter"
        m_arrButtonKeyDesc(43) = "ShiftLeft"
        m_arrButtonKeyDesc(45) = "Z"
        m_arrButtonKeyDesc(46) = "X"
        m_arrButtonKeyDesc(47) = "C"
        m_arrButtonKeyDesc(48) = "V"
        m_arrButtonKeyDesc(49) = "B"
        m_arrButtonKeyDesc(50) = "N"
        m_arrButtonKeyDesc(51) = "M"
        m_arrButtonKeyDesc(52) = "Comma"
        m_arrButtonKeyDesc(53) = "Period"
        m_arrButtonKeyDesc(54) = "Slash"
        m_arrButtonKeyDesc(55) = "ShiftRight"
        m_arrButtonKeyDesc(30) = "CtrlLeft"
        m_arrButtonKeyDesc(348) = "WinLeft"
        m_arrButtonKeyDesc(58) = "Spacebar"
        m_arrButtonKeyDesc(349) = "WinRight"
        m_arrButtonKeyDesc(350) = "Menu"
        m_arrButtonKeyDesc(286) = "CtrlRight"
        m_arrButtonKeyDesc(339) = "Ins"
        m_arrButtonKeyDesc(328) = "Home"
        m_arrButtonKeyDesc(330) = "PgUp"
        m_arrButtonKeyDesc(340) = "Del"
        m_arrButtonKeyDesc(336) = "End"
        m_arrButtonKeyDesc(338) = "PgDn"
        m_arrButtonKeyDesc(329) = "Up"
        m_arrButtonKeyDesc(332) = "Left"
        m_arrButtonKeyDesc(337) = "Down"
        m_arrButtonKeyDesc(334) = "Right"
        m_arrButtonKeyDesc(71) = "ScrollLock"
        m_arrButtonKeyDesc(326) = "NumLock"
        m_arrButtonKeyDesc(310) = "KeypadSlash"
        m_arrButtonKeyDesc(56) = "KeypadMultiply"
        m_arrButtonKeyDesc(75) = "KeypadMinus"
        m_arrButtonKeyDesc(72) = "Keypad7Home"
        m_arrButtonKeyDesc(73) = "Keypad8Up"
        m_arrButtonKeyDesc(74) = "Keypad9PgUp"
        m_arrButtonKeyDesc(79) = "KeypadPlus"
        m_arrButtonKeyDesc(76) = "Keypad4Left"
        m_arrButtonKeyDesc(77) = "Keypad5"
        m_arrButtonKeyDesc(78) = "Keypad6Right"
        m_arrButtonKeyDesc(80) = "Keypad1End"
        m_arrButtonKeyDesc(81) = "Keypad2Down"
        m_arrButtonKeyDesc(82) = "Keypad3PgDn"
        m_arrButtonKeyDesc(285) = "KeypadEnter"
        m_arrButtonKeyDesc(83) = "Keypad0Ins"
        m_arrButtonKeyDesc(84) = "KeypadPeriodDel"

        m_bInitialized = TRUE
    End If
End Sub ' InitKeyboardButtonCodes

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END MAP CONTROLS v1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DETECT DIFFICULT KEYS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' not sure if this works

' Returns TRUE if the F10 key is held down.
' We use _KEYDOWN for this because _BUTTON doesn't detect F10.

' Constant must be declared globally:
' Const c_iKeyDown_F10 = 17408

Function KeydownF10%
    Dim iCode As Long
    '_KEYCLEAR: _DELAY 1
    If _KeyDown(c_iKeyDown_F10) = TRUE Then
        KeydownF10% = TRUE
    Else
        KeydownF10% = FALSE
    End If
    '_KEYCLEAR
End Function ' KeydownF10%

' /////////////////////////////////////////////////////////////////////////////
' not sure if this works

' Returns TRUE if the left ALT key is held down.
' We use _KEYHIT for this because _BUTTON doesn't detect ALT.

' Constant must be declared globally:
' Const c_iKeyHit_AltLeft = -30764

Function KeyhitAltLeft%
    '_KEYCLEAR: _DELAY 1
    If _KeyHit = c_iKeyHit_AltLeft Then
        KeyhitAltLeft% = TRUE
    Else
        KeyhitAltLeft% = FALSE
    End If
    '_KEYCLEAR
End Function ' KeyhitAltLeft%

' /////////////////////////////////////////////////////////////////////////////
' not sure if this works

' Returns TRUE if the right ALT key is held down.
' We use _KEYHIT for this because _BUTTON doesn't detect ALT.

' Constant must be declared globally:
' Const c_iKeyHit_AltRight = -30765

Function KeyhitAltRight%
    '_KEYCLEAR: _DELAY 1
    If _KeyHit = c_iKeyHit_AltRight Then
        KeyhitAltRight% = TRUE
    Else
        KeyhitAltRight% = FALSE
    End If
    '_KEYCLEAR
End Function ' KeyhitAltRight%

' /////////////////////////////////////////////////////////////////////////////
' DEVICES Button
' _LASTBUTTON(1) keyboards will normally return 512 buttons. One button is read per loop through all numbers.
' _BUTTONCHANGE(number) returns -1 when pressed, 1 when released and 0 when there is no event since the last read.
' _BUTTON(number) returns -1 when a button is pressed and 0 when released

' Detects most keys (where the codes are documented?)

' However, does not seem to detect:
' Key             Use
' ---             ---
' F10             Function KeydownF10%
' Left Alt        Function KeyhitAltLeft%
' Right Alt       Function KeyhitAltRight%
' Print Screen    (system API call?)
' Pause/Break     (system API call?)

Function KeyPressed% (iCode As Integer)
    '_KEYCLEAR: _DELAY 1
    While _DeviceInput(1): Wend ' clear and update the keyboard buffer
    If _Button(iCode) <> FALSE Then
        KeyPressed% = TRUE
    Else
        KeyPressed% = FALSE
    End If
    '_KEYCLEAR
End Function ' KeyPressed%

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DETECT DIFFICULT KEYS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN JOYSTICK TEST #1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Function TestJoysticks1$
    Dim RoutineName As String: RoutineName = "TestJoysticks1$"
    Dim iDeviceCount As Integer
    Dim sResult As String

    ' 1 is the keyboard
    ' 2 is the mouse
    ' 3 is the joystick
    ' unless someone has a strange setup with multiple mice/keyboards/ect...
    ' In that case, you can use _DEVICE$(i) to look for "KEYBOARD", "MOUSE", "JOYSTICK", if necessary.
    ' I've never actually found it necessary, but I figure it's worth mentioning, just in case...

    iDeviceCount = _Devices ' Find the number of devices on someone's system
    If iDeviceCount > 2 Then
        TestJoysticks1b
        sResult = ""
    Else
        sResult = "No joysticks found."
    End If

    _KeyClear

    TestJoysticks1$ = sResult
End Function ' TestJoysticks1$

' /////////////////////////////////////////////////////////////////////////////
' Reads controllers and displays values on screen.

' Currently this is set up to support up to 8 joysticks,
' with upto 4 buttons and 2 axes each
' Testing with an old USB Logitech RumblePad 2
' and Atari 2600 joysticks plugged into using
' iCode Atari Joystick, Paddle, Driving to USB Adapter 4 ports

' BASED ON CODE BY SMcNeill FROM:
'     Simple Joystick Detection and Interaction  (Read 316 times)
'     https://www.qb64.org/forum/index.php?topic=2160.msg129051#msg129051
'     https://forum.qb64.org/index.php?topic=2160.msg129083#msg129083

Sub TestJoysticks1b ()
    Dim RoutineName As String:: RoutineName = "TestJoysticks1b"

    Dim in$
    Dim iDeviceCount As Integer
    Dim iDevice As Integer

    Dim arrButton(32, 16) As Integer ' number of buttons on the joystick
    Dim arrButtonMin(32, 16) As Integer ' stores the minimum value read
    Dim arrButtonMax(32, 16) As Integer ' stores the maximum value read
    Dim arrAxis(32, 16) As Double ' number of axis on the joystick
    Dim arrAxisMin(32, 16) As Double ' stores the minimum value read
    Dim arrAxisMax(32, 16) As Double ' stores the maximum value read
    Dim arrAxisAvg(32, 16) As Double ' stores the average value read in the last few measurements
    Dim arrButtonNew(32, 16) As Integer ' tracks when to initialize values
    Dim arrAxisNew(32, 16) As Integer ' tracks when to initialize values

    Dim arrController(8) As ControllerType ' holds info for each player
    Dim iNumControllers As Integer
    Dim iController As Integer
    Dim iNextY As Integer
    Dim iNextX As Integer
    Dim iNextC As Integer
    Dim iLoop As Integer
    Dim iDigits As Integer ' # digits to display (values are truncated to this length)
    Dim strValue As String
    Dim strAxis As String
    Dim dblNextAxis As Double
    'DIM iMeasureCount AS INTEGER
    Dim dblAverage As Double
    Dim sngAverage As Single
    Dim sLine As String
    Dim iX As Integer
    Dim iY As Integer

    Dim iCol As Integer
    Dim iRow As Integer
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iColWidth As Integer
    Dim iColCount As Integer
    Dim iGroupCount As Integer

    ' SET UP SCREEN
    Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0

    ' INITIALIZE
    iDigits = 4 ' 11
    iColCount = 3
    iCols = _Width(0) \ _FontWidth
    iRows = _Height(0) \ _FontHeight
    iColWidth = iCols \ iColCount

    ' COUNT # OF JOYSTICKS
    ' D= _DEVICES ' MUST be read in order for other 2 device functions to work!
    iDeviceCount = _Devices ' Find the number of devices on someone's system
    If iDeviceCount < 3 Then
        Cls
        Print "NO JOYSTICKS FOUND, EXITING..."
        Input "PRESS <ENTER>"; in$
        Exit Sub
    End If

    ' BASE # OF PLAYERS ON HOW MANY CONTROLLERS FOUND
    iNumControllers = iDeviceCount - 2 ' TODO: find out the right way to count joysticks
    If iNumControllers > cMaxControllers Then
        iNumControllers = cMaxControllers
    End If

    ' INITIALIZE PLAYER COORDINATES AND SCREEN CHARACTERS
    iNextY = 1
    iNextX = -3
    iNextC = 64
    For iController = 1 To iNumControllers
        iNextX = iNextX + 4
        If iNextX > 80 Then
            iNextX = 1
            iNextY = iNextY + 4
        End If
        iNextC = iNextC + 1
        arrController(iController).buttonCount = cMaxButtons
        arrController(iController).axisCount = cMaxAxis

        For iLoop = 1 To cMaxButtons
            arrButtonNew(iController, iLoop) = TRUE
        Next iLoop
        For iLoop = 1 To cMaxAxis
            arrAxisNew(iController, iLoop) = TRUE
            arrAxisAvg(iController, iLoop) = 0
        Next iLoop
    Next iController

    ' CLEAR THE SCREEN
    'iMeasureCount = 0
    Do
        For iController = 1 To iNumControllers
            iDevice = iController + 2

            While _DeviceInput(iDevice) ' clear and update the device buffer
                ''IF _DEVICEINPUT = 3 THEN ' this says we only care about joystick input values

                ' check all the buttons
                For iLoop = 1 To _LastButton(iDevice)
                    If (iLoop > cMaxButtons) Then
                        Exit For
                    End If
                    arrController(iController).buttonCount = iLoop

                    ' update button array to indicate if a button is up or down currently.
                    If _ButtonChange(iLoop) Then
                        '' _BUTTON(number) returns -1 when a button is pressed and 0 when released.
                        ''arrButton(iLoop) = NOT arrButton(iLoop)
                        arrButton(iController, iLoop) = _Button(iLoop)
                    End If

                    '' SAVE MINIMUM VALUE
                    'if arrButton(iController, iLoop) < arrButtonMin(iController, iLoop) then
                    '    arrButtonMin(iController, iLoop) = arrButton(iController, iLoop)
                    '
                    '    ' INITIALIZE THE MAX TO THE MINIMUM VALUE
                    '    IF arrButtonNew(iController, iLoop) = TRUE THEN
                    '        arrButtonMax(iController, iLoop) = arrButtonMin(iController, iLoop)
                    '        arrButtonNew(iController, iLoop) = FALSE
                    '    END IF
                    'end if
                    '
                    '' SAVE MAXIMUM VALUE
                    'if arrButton(iController, iLoop) > arrButtonMax(iController, iLoop) then
                    '    arrButtonMax(iController, iLoop) = arrButton(iController, iLoop)
                    'end if

                Next iLoop

                For iLoop = 1 To _LastAxis(iDevice) ' this loop checks all my axis
                    If (iLoop > cMaxAxis) Then
                        Exit For
                    End If
                    arrController(iController).axisCount = iLoop

                    ' I like to give a little "jiggle" resistance to my controls, as I have an old joystick
                    ' which is prone to always give minute values and never really center on true 0.
                    ' A value of 1 means my axis is pushed fully in one direction.
                    ' A value greater than 0.1 means it's been partially pushed in a direction (such as at a 45 degree diagional angle).
                    ' A value of less than 0.1 means we count it as being centered. (As if it was 0.)
                    'IF ABS(_AXIS(iLoop)) <= 1 AND ABS(_AXIS(iLoop)) >= .1 THEN

                    dblNextAxis = _Axis(iLoop)
                    dblNextAxis = RoundUpDouble#(dblNextAxis, 3)
                    'IF ABS(dblNextAxis) <= 1 AND ABS(dblNextAxis) >= .01 THEN
                    If Abs(dblNextAxis) <= 1 And Abs(dblNextAxis) >= .001 Then
                        arrAxis(iController, iLoop) = dblNextAxis
                    Else
                        arrAxis(iController, iLoop) = 0
                    End If

                    '' SAVE MINIMUM VALUE
                    'if arrAxis(iController, iLoop) < arrAxisMin(iController, iLoop) then
                    '    arrAxisMin(iController, iLoop) = arrAxis(iController, iLoop)
                    '
                    '    ' INITIALIZE THE MAX TO THE MINIMUM VALUE
                    '    IF arrAxisNew(iController, iLoop) = TRUE THEN
                    '        arrAxisMax(iController, iLoop) = arrAxisMin(iController, iLoop)
                    '        arrAxisNew(iController, iLoop) = FALSE
                    '    END IF
                    'end if
                    '
                    '' SAVE MAXIMUM VALUE
                    'if arrAxis(iController, iLoop) > arrAxisMax(iController, iLoop) then
                    '    arrAxisMax(iController, iLoop) = arrAxis(iController, iLoop)
                    'end if
                    '
                    '' ADD CURRENT VALUE TO AVERAGE SUM
                    'arrAxisAvg(iController, iLoop) = arrAxisAvg(iController, iLoop) + arrAxis(iController, iLoop)

                Next iLoop
            Wend ' clear and update the device buffer

        Next iController

        'PRINT "*** iNumControllers=" + cstr$(iNumControllers) + " ***"
        'iMeasureCount = iMeasureCount + 1
        'if iMeasureCount = 10 then
        'iMeasureCount = 0

        ' And below here is just the simple display routine which displays our values.
        ' If this was for a game, I'd choose something like arrAxis(1) = -1 for a left arrow style input,
        ' arrAxis(1) = 1 for a right arrow style input, rather than just using _KEYHIT or INKEY$.

        InitColumns iColCount
        m_StartRow = 6
        m_EndRow = iRows - 2
        'm_StartCol
        'm_EndCol

        Cls
        PrintStringCR1 1, 1, "Game controller test program."
        PrintStringCR1 1, 2, "This program is free to use and distribute per GNU GPLv3 license."
        PrintStringCR1 1, 3, "Tests up to 4 controllers with 2 axes / 2 buttons each."
        PrintStringCR1 1, 4, "Plug in controllers and move them & press buttons."
        PrintStringCR1 1, 5, "-------------------------------------------------------------------------------"

        iGroupCount = 0

        For iController = 1 To iNumControllers
            For iLoop = 1 To arrController(iController).axisCount ' A loop for each axis
                strAxis = Right$("  " + cstr$(iLoop), 2)

                sLine = ""

                ' display their status to the screen
                sLine = sLine + "Player " + cstr$(iController)

                strValue = FormatNumber$(arrAxis(iController, iLoop), iDigits)
                sLine = sLine + ",   Axis #" + strAxis + " = " + strValue

                'strValue = FormatNumber$(arrAxisMin(iController, iLoop), iDigits)
                'sLine = sLine + ", Min=" + strValue
                '
                'strValue = FormatNumber$(arrAxisMax(iController, iLoop), iDigits)
                'sLine = sLine + ", Max=" + strValue
                '
                '' COMPUTE AVERAGE
                'dblAverage = arrAxisAvg(iController, iLoop) / 10
                'dblAverage = RoundUpDouble# (dblAverage, 3)
                'strValue = FormatNumber$(dblAverage, iDigits)
                'sLine = sLine + ", Avg=" + strValue
                '
                '' CLEAR THE AVERAGE
                'arrAxisAvg(iController, iLoop) = 0

                PrintColumn sLine
            Next iLoop
            For iLoop = 1 To arrController(iController).buttonCount ' A loop for each button
                strAxis = Right$("  " + cstr$(iLoop), 2)

                sLine = ""

                ' display their status to the screen
                sLine = sLine + "Player " + cstr$(iController)

                strValue = FormatNumber$(arrButton(iController, iLoop), iDigits)
                sLine = sLine + ", Button #" + strAxis + " = " + strValue

                'strValue = FormatNumber$(arrButtonMin(iController, iLoop), iDigits)
                'sLine = sLine + ", Min=" + strValue
                '
                'strValue = FormatNumber$(arrButtonMax(iController, iLoop), iDigits)
                'sLine = sLine + ", Max=" + strValue

                PrintColumn sLine
            Next iLoop

            iGroupCount = iGroupCount + 1
            If iGroupCount = 2 Then
                ColumnBreak
                iGroupCount = 0
            End If

        Next iController

        PrintStringCR1 1, iRows - 1, "-------------------------------------------------------------------------------"
        PrintStringCR1 1, iRows - 0, "PRESS <ESC> TO EXIT"

        'end if

        _Limit 30
    Loop Until _KeyHit = 27 ' ESCAPE to quit

    ' RETURN TO TEXT SCREEN
    Screen 0
End Sub ' TestJoysticks1b

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END JOYSTICK TEST #1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN FILE FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' File format is comma-delimited
' containing controller info for one action per line
' where each line contains the following in this order:

' TAB ORDER   INFO             TYPE      DESCRIPTION
' 1           {player #}       Integer   player # this mapping is for
' 2           {which action}   Integer   which action this mapping is for (up/down/right/left/button 1/button 2, etc.)
' 3           {device #}       Integer   number of the device this is mapped to
' 4           {type}           Integer   type of input (one of: cInputKey, cInputButton, cInputAxis)
' 5           {code}           Integer   if button the _BUTTON #, if axis the _AXIS #, if keyboard the _BUTTON #
' 6           {value}          Integer   if axis, the value (-1 or 1), else can be ignored
' 7           {repeat}         Integer   if TRUE, and repeating keys not controlled by global values (when m_bRepeatOverride=TRUE), controls repeating keys for this control

' These need to be declared globally and populated:
'     ReDim Shared m_arrControlMap(1 To 8, 1 To 8) As ControlInputType
'     Dim Shared m_ControlMapFileName$: m_ControlMapFileName$ = Left$(m_ProgramName$, _InStrRev(m_ProgramName$, ".")) + "map.txt"
'     Dim Shared m_bRepeatOverride As Integer

' If there is an error, returns error message,
' else returns blank string.

Function SaveControllerMap1$
    Dim RoutineName As String:: RoutineName = "SaveControllerMap1$"
    Dim sResult As String: sResult = ""
    Dim sError As String: sError = ""
    Dim sFile As String
    Dim in$
    Dim iPlayer As Integer
    Dim iWhichInput As Integer
    Dim sLine As String
    Dim iCount As Long: iCount = 0
    'Dim iError As Long: iError = 0
    Dim sDelim As String: sDelim = "," ' CHR$(9)

    'DebugPrint "--------------------------------------------------------------------------------"
    'DebugPrint "Started " + RoutineName
    'DebugPrint "--------------------------------------------------------------------------------"

    ' Get file name
    If Len(m_ControlMapFileName$) = 0 Then
        m_ControlMapFileName$ = Left$(m_ProgramName$, _InStrRev(m_ProgramName$, ".")) + "map.txt"
    End If
    sFile = Mid$(m_ControlMapFileName$, _InStrRev(m_ControlMapFileName$, "\") + 1)

    '_KeyClear
    'Cls
    'Print "SAVE CONTROLLER MAPPING:"
    'Print "Default file name is " + Chr$(34) + m_ControlMapFileName$ + Chr$(34) + "."
    'Input "Type save file name, or blank for default: ", in$
    'in$ = _Trim$(in$)
    'If Len(in$) > 0 Then
    '    m_ControlMapFileName$ = in$
    'End If
    'sFile = m_ProgramPath$ + m_ControlMapFileName$

    'DebugPrint "m_ControlMapFileName$=" + CHR$(34) + m_ControlMapFileName$ + CHR$(34)

    ' Save mapping to file
    Open m_ControlMapFileName$ For Output As #1

    For iPlayer = LBound(m_arrControlMap, 1) To UBound(m_arrControlMap, 1)
        For iWhichInput = LBound(m_arrControlMap, 2) To UBound(m_arrControlMap, 2)
            sLine = ""

            sLine = sLine + _Trim$(Str$(iPlayer))
            sLine = sLine + sDelim

            sLine = sLine + _Trim$(Str$(iWhichInput))
            sLine = sLine + sDelim

            sLine = sLine + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).device))
            sLine = sLine + sDelim

            sLine = sLine + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).typ))
            sLine = sLine + sDelim

            sLine = sLine + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).code))
            sLine = sLine + sDelim

            sLine = sLine + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).value))
            sLine = sLine + sDelim

            sLine = sLine + _Trim$(Str$(m_arrControlMap(iPlayer, iWhichInput).repeat))

            Print #1, sLine
            iCount = iCount + 1
        Next iWhichInput
    Next iPlayer

    Close #1

    'DebugPrint "Wrote   " + _Trim$(Str$(iCount)) + " lines."
    'Print "Skipped " + _Trim$(Str$(iError)) + " lines."
    'DebugPrint ""
    'Input "PRESS <ENTER> TO CONTINUE", in$

    If Len(sError) = 0 Then
        m_bMappingChanged = FALSE
        sResult = "Saved mapping file " + Chr$(34) + sFile + Chr$(34) + "."
    Else
        sResult = "ERRORS: " + sError
    End If

    SaveControllerMap1$ = sResult
End Function ' SaveControllerMap1$

' /////////////////////////////////////////////////////////////////////////////

Function LoadControllerMap1$
    Dim RoutineName As String:: RoutineName = "LoadControllerMap1$"
    Dim sResult As String: sResult = ""
    Dim sError As String: sError = ""
    Dim sNextErr As String

    Dim sFile As String
    Dim sText As String
    Dim iTotal As Long: iTotal = 0

    Dim iRead As Long: iRead = 0
    Dim iValid As Long: iValid = 0
    Dim iBad As Long: iBad = 0
    Dim iBlank As Long: iBlank = 0

    Dim sLine As String
    ReDim arrNextLine(-1) As String
    Dim iNumValues As Integer
    Dim iAdjust As Integer

    Dim iPlayer As Integer
    Dim iWhichInput As Integer
    Dim iDevice As Integer
    Dim iType As Integer
    Dim iCode As Integer
    Dim iValue As Integer
    Dim bRepeat As Integer
    'Dim sDebugLine As String

    'DebugPrint "--------------------------------------------------------------------------------"
    'DebugPrint "Started " + RoutineName
    'DebugPrint "--------------------------------------------------------------------------------"

    ' Get file name
    If Len(sError) = 0 Then
        If Len(m_ControlMapFileName$) = 0 Then
            m_ControlMapFileName$ = Left$(m_ProgramName$, _InStrRev(m_ProgramName$, ".")) + "map.txt"
        End If
        sFile = Mid$(m_ControlMapFileName$, _InStrRev(m_ControlMapFileName$, "\") + 1)
    End If

    '' Get file name
    'If Len(sError) = 0 Then
    '    Cls
    '    If Len(m_ControlMapFileName$) = 0 Then
    '        m_ControlMapFileName$ = Left$(m_ProgramName$, _InStrRev(m_ProgramName$, ".")) + "map.txt"
    '    End If
    '    Print "LOAD CONTROLLER MAPPING:"
    '    Print "Default file name is " + Chr$(34) + m_ControlMapFileName$ + Chr$(34) + "."
    '    Input "Type name of file to open, or blank for default: ", in$
    '    in$ = _Trim$(in$)
    '    If Len(in$) > 0 Then
    '        m_ControlMapFileName$ = in$
    '    End If
    '    sFile = m_ProgramPath$ + m_ControlMapFileName$
    'End If

    ' Make sure file exists
    If Len(sError) = 0 Then
        If _FileExists(m_ControlMapFileName$) = FALSE Then
            sError = "File not found: " + Chr$(34) + m_ControlMapFileName$ + Chr$(34)
        Else
            'DebugPrint "Found file: " + chr$(34) + m_ControlMapFileName$ + chr$(34)
        End If
    End If

    ' Read data from file
    If Len(sError) = 0 Then
        'DebugPrint "OPEN m_ControlMapFileName$ FOR BINARY AS #1"

        Open m_ControlMapFileName$ For Binary As #1
        sText = Space$(LOF(1))
        Get #1, , sText
        Close #1
        iTotal = Len(sText) - Len(Replace$(sText, Chr$(13), ""))
        sText = ""

        Open m_ControlMapFileName$ For Input As #1
        While Not EOF(1)
            'INPUT #1, sLine
            Line Input #1, sLine ' read entire text file line

            iRead = iRead + 1
            'DebugPrint "Parsing line " + _Trim$(Str$(iRead)) + _
            '    " of " + _Trim$(Str$(iTotal))

            sLine = Replace$(sLine, " ", "") ' Remove spaces
            sLine = Replace$(sLine, Chr$(9), "") ' Remove tabs
            sLine = Replace$(sLine, Chr$(10), "") ' Remove line breaks
            sLine = Replace$(sLine, Chr$(13), "") ' Remove carriage returns
            'DebugPrint "    Trimmed=" + chr$(34) + sLine + chr$(34)

            If Len(sLine) > 0 Then
                split sLine, ",", arrNextLine()
                'DebugPrint "split into arrNextLine()"
                'DebugPrint "    lbound =" + _Trim$(Str$(lbound(arrNextLine))) '+ CHR$(10)
                'DebugPrint "    ubound =" + _Trim$(Str$(ubound(arrNextLine))) '+ CHR$(10)

                iNumValues = (UBound(arrNextLine) - LBound(arrNextLine)) + 1
                If iNumValues > 5 Then
                    iAdjust = -1 '- lbound(arrNextLine)

                    If Len(sNextErr) = 0 Then
                        If IsNum%(arrNextLine(1 + iAdjust)) = TRUE Then
                            iPlayer = Val(arrNextLine(1 + iAdjust))
                        Else
                            sNextErr = "Error on line " + cstr$(iRead) + ", value 1: not a number"
                        End If
                    End If

                    If Len(sNextErr) = 0 Then
                        If IsNum%(arrNextLine(2 + iAdjust)) = TRUE Then
                            iWhichInput = Val(arrNextLine(2 + iAdjust))
                        Else
                            sNextErr = "Error on line " + cstr$(iRead) + ", value 2: not a number"
                        End If
                    End If

                    If Len(sNextErr) = 0 Then
                        If IsNum%(arrNextLine(3 + iAdjust)) = TRUE Then
                            iDevice = Val(arrNextLine(3 + iAdjust))
                        Else
                            sNextErr = "Error on line " + cstr$(iRead) + ", value 3: not a number"
                        End If
                    End If

                    If Len(sNextErr) = 0 Then
                        If IsNum%(arrNextLine(4 + iAdjust)) = TRUE Then
                            iType = Val(arrNextLine(4 + iAdjust))
                        Else
                            sNextErr = "Error on line " + cstr$(iRead) + ", value 4: not a number"
                        End If
                    End If

                    If Len(sNextErr) = 0 Then
                        If IsNum%(arrNextLine(5 + iAdjust)) = TRUE Then
                            iCode = Val(arrNextLine(5 + iAdjust))
                        Else
                            sNextErr = "Error on line " + cstr$(iRead) + ", value 5: not a number"
                        End If
                    End If

                    If Len(sNextErr) = 0 Then
                        If IsNum%(arrNextLine(6 + iAdjust)) = TRUE Then
                            iValue = Val(arrNextLine(6 + iAdjust))
                        Else
                            sNextErr = "Error on line " + cstr$(iRead) + ", value 6: not a number"
                        End If
                    End If

                    ' validate iPlayer
                    If Len(sNextErr) = 0 Then
                        If iPlayer < LBound(m_arrControlMap, 1) Then
                            sNextErr = "Player value " + _Trim$(Str$(iPlayer)) + _
                                " is outside lbound(m_arrControlMap, 1) " + _
                                " which is " + _Trim$(Str$(lbound(m_arrControlMap, 1))) + "."
                        ElseIf iPlayer > UBound(m_arrControlMap, 1) Then
                            sNextErr = "Player value " + _Trim$(Str$(iPlayer)) + _
                                " is outside ubound(m_arrControlMap, 1) " + _
                                " which is " + _Trim$(Str$(ubound(m_arrControlMap, 1))) + "."
                        End If
                    End If

                    ' validate iWhichInput
                    If Len(sNextErr) = 0 Then
                        If iWhichInput < LBound(m_arrControlMap, 2) Then
                            sNextErr = "WhichInput value " + _Trim$(Str$(iWhichInput)) + _
                                " is outside lbound(m_arrControlMap, 2) " + _
                                " which is " + _Trim$(Str$(lbound(m_arrControlMap, 2))) + "."
                        ElseIf iWhichInput > UBound(m_arrControlMap, 2) Then
                            sNextErr = "WhichInput value " + _Trim$(Str$(iWhichInput)) + _
                                " is outside ubound(m_arrControlMap, 2) " + _
                                " which is " + _Trim$(Str$(ubound(m_arrControlMap, 2))) + "."
                        End If
                    End If

                    ' validate repeat setting
                    If iNumValues > 6 Then
                        If Len(sNextErr) = 0 Then
                            If IsNum%(arrNextLine(7 + iAdjust)) = TRUE Then
                                bRepeat = Val(arrNextLine(7 + iAdjust))
                            Else
                                sNextErr = "Error on line " + cstr$(iRead) + ", value 7: not a number"
                            End If
                        End If
                    Else
                        ' get values from global
                        'if m_bRepeatOverride = TRUE then
                        bRepeat = GetGlobalInputRepeatSetting%(iWhichInput)
                        'end if
                    End If
                Else
                    sNextErr = "Error on line " + cstr$(iRead) + ": detected " + cstr$(iNumValues) + " values, expected 6."
                End If

                If Len(sNextErr) = 0 Then
                    iValid = iValid + 1
                    m_arrControlMap(iPlayer, iWhichInput).device = iDevice
                    m_arrControlMap(iPlayer, iWhichInput).typ = iType
                    m_arrControlMap(iPlayer, iWhichInput).code = iCode
                    m_arrControlMap(iPlayer, iWhichInput).value = iValue
                    m_arrControlMap(iPlayer, iWhichInput).repeat = bRepeat
                Else
                    iBad = iBad + 1
                    DebugPrint sNextErr
                End If
            Else
                'DebugPrint "    Line is blank: skipped"
                iBlank = iBlank + 1
            End If ' LEN(sLine) > 0

        Wend
        Close #1
    End If

    'DebugPrint ""
    'DebugPrint "Lines read: " + _Trim$(Str$(iRead))
    'DebugPrint "Valid     : " + _Trim$(Str$(iValid))
    'DebugPrint "Invalid   : " + _Trim$(Str$(iErrors))
    'DebugPrint "Blank     : " + _Trim$(Str$(iBlank))
    'DebugPrint ""
    'Input "PRESS <ENTER> TO CONTINUE", in$

    If Len(sError) = 0 Then
        sResult = "Loaded mapping file " + Chr$(34) + sFile + Chr$(34) + "."
        m_bHaveMapping = TRUE
        m_bMappingChanged = FALSE
    Else
        sResult = "ERRORS: " + sError
    End If

    LoadControllerMap1$ = sResult
End Function ' LoadControllerMap1$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END FILE FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN PLOTTING FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
' From: http://www.thedubber.altervista.org/qbsrc.htm

Sub PlotLine2D (x1a%, y1a%, x2a%, y2a%, MyArray() As _Byte)
    Dim iLoop%
    Dim steep%: steep% = 0
    Dim ev%: ev% = 0
    Dim sx%
    Dim sy%
    Dim dx%
    Dim dy%

    ' GET PARAMETERS
    Dim x1%: x1% = x1a%
    Dim y1%: y1% = y1a%
    Dim x2%: x2% = x2a%
    Dim y2%: y2% = y2a%

    ' FOR RETURN ARRAY
    Dim iMinX%
    Dim iMaxX%
    Dim iMinY%
    Dim iMaxY%
    ReDim MyArray(-1, -1) As _Byte

    ' CLEANUP INPUT
    x1% = Abs(x1%)
    y1% = Abs(y1%)
    x2% = Abs(x2%)
    y2% = Abs(y2%)

    ' SETUP RETURN ARRAY
    If x1% > x2% Then
        iMinX% = x2%
        iMaxX% = x1%
    Else
        iMinX% = x1%
        iMaxX% = x2%
    End If
    If y1% > y2% Then
        iMinY% = y2%
        iMaxY% = y1%
    Else
        iMinY% = y1%
        iMaxY% = y2%
    End If

    If iMinX% > 0 Then iMinX% = 1
    If iMinY% > 0 Then iMinY% = 1

    ReDim MyArray(iMinX% To iMaxX%, iMinY% To iMaxY%) As _Byte
    For sy% = iMinY% To iMaxY%
        For sx% = iMinX% To iMaxX%
            MyArray(sx%, sy%) = 0
        Next sx%
    Next sy%

    ' DRAW THE LINE
    If (x2% - x1%) > 0 Then
        sx% = 1
    Else
        sx% = -1
    End If

    dx% = Abs(x2% - x1%)
    If (y2% - y1%) > 0 Then
        sy% = 1
    Else
        sy% = -1
    End If

    dy% = Abs(y2% - y1%)
    If (dy% > dx%) Then
        steep% = 1
        Swap x1%, y1%
        Swap dx%, dy%
        Swap sx%, sy%
    End If

    ev% = 2 * dy% - dx%
    For iLoop% = 0 To dx% - 1
        If steep% = 1 Then
            '''PSET (y1%, x1%), c%:
            ''LOCATE y1%, x1%
            ''PRINT c$;
            'PlotPoint y1%, x1%, c$, MyArray()
            MyArray(y1%, x1%) = 1
        Else
            '''PSET (x1%, y1%), c%
            ''LOCATE x1%, y1%
            ''PRINT c$;
            'PlotPoint x1%, y1%, c$, MyArray()
            MyArray(x1%, y1%) = 1
        End If

        While ev% >= 0
            y1% = y1% + sy%
            ev% = ev% - 2 * dx%
        Wend
        x1% = x1% + sx%
        ev% = ev% + 2 * dy%
    Next iLoop%
    '''PSET (x2%, y2%), c%
    ''LOCATE x2%, y2%
    ''PRINT c$;
    'PlotPoint x2%, y2%, c$, MyArray()
    MyArray(x2%, y2%) = 1

End Sub ' PlotLine2D

' /////////////////////////////////////////////////////////////////////////////

Function PlotLine2DTest$
    Dim x1%
    Dim y1%
    Dim x2%
    Dim y2%
    Dim sLine As String
    Dim in$
    ReDim MyArray(-1, -1) As _Byte

    Do
        Cls
        Input "ENTER x1,y1,x2,y2 TO PLOT A LINE OR 0 TO EXIT? "; x1%, y1%, x2%, y2%
        If x1% = 0 Then Exit Do

        PlotLine2D x1%, y1%, x2%, y2%, MyArray()

        ' number columns at top
        sLine = "  "
        For x1% = LBound(MyArray, 1) To UBound(MyArray, 1)
            sLine = sLine + Left$(Right$(" " + cstr$(x1%), 2), 1)
        Next x1%
        Print sLine
        sLine = "  "
        For x1% = LBound(MyArray, 1) To UBound(MyArray, 1)
            sLine = sLine + Right$(cstr$(x1%), 1)
        Next x1%
        Print sLine

        ' show array
        For y1% = LBound(MyArray, 2) To UBound(MyArray, 2)
            sLine = Right$(" " + cstr$(y1%), 2) ' number rows on left
            For x1% = LBound(MyArray, 1) To UBound(MyArray, 1)
                If MyArray(x1%, y1%) = 0 Then
                    sLine = sLine + " "
                Else
                    sLine = sLine + "#"
                End If
            Next x1%
            sLine = sLine + cstr$(y1%) ' number rows on right
            Print sLine
        Next y1%

        ' number columns on bottom
        sLine = "  "
        For x1% = LBound(MyArray, 1) To UBound(MyArray, 1)
            sLine = sLine + Right$(cstr$(x1%), 1)
        Next x1%
        Print sLine
        sLine = "  "
        For x1% = LBound(MyArray, 1) To UBound(MyArray, 1)
            sLine = sLine + Left$(Right$(" " + cstr$(x1%), 2), 1)
        Next x1%
        Print sLine

        ' pause
        Print
        Input "PRESS <ENTER> TO CONTINUE"; in$

    Loop

End Function ' PlotLine2DTest$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END PLOTTING FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GRAPHICS FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D RECTANGLE (SOLID)
' Based on DrawBox

'SUB DrawRect (iX%, iY%, iSizeW%, iSizeH%, iColor~&)
Sub DrawRect (iX%, iY%, iSizeW%, iSizeH%, iColor~&)
    Line (iX%, iY%)-(iX% + iSizeW%, iY% + iSizeH%), iColor~&, BF ' Draw a solid box
    'LINE (iX%, iY%)-(iX% + iSize%, iY% + iSize%), iColor%, BF ' Draw a solid box
    'LINE (60, 60)-(130, 100), iColor%, B ' Draw a box outline
End Sub ' DrawRect

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D BOX (SOLID)
' https://www.qb64.org/wiki/LINE

'SUB DrawBox (iX%, iY%, iSize%, iColor~&)
Sub DrawBox (iX%, iY%, iSize%, iColor~&)
    Line (iX%, iY%)-(iX% + iSize%, iY% + iSize%), iColor~&, BF ' Draw a solid box
    'LINE (iX%, iY%)-(iX% + iSize%, iY% + iSize%), iColor%, BF ' Draw a solid box
    'LINE (60, 60)-(130, 100), iColor%, B ' Draw a box outline
End Sub ' DrawBox

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D BOX (OUTLINE)
' https://www.qb64.org/wiki/LINE

' The style parameter 0-255 doesn't seemt to have a solid line?

'SUB DrawStyledOutlineBox (iX%, iY%, iSize%, iColor%, iStyle%)
Sub DrawStyledOutlineBox (iX%, iY%, iSize%, iColor~&, iStyle%)
    ' LINE [STEP] [(column1, row1)]-[STEP] (column2, row2), color[, [{B|BF}], style%]
    ' B creates a box outline with each side parallel to the program screen sides. BF creates a filled box.
    ' The style% signed INTEGER value sets a dotted pattern to draw the line or rectangle outline.

    Line (iX%, iY%)-(iX% + iSize%, iY% + iSize%), iColor~&, B , iStyle%
End Sub ' DrawStyledOutlineBox

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D BOX (OUTLINE) WITH A SOLID LINE

Sub DrawOutlineBox (iX%, iY%, iSize2%, iColor~&, iWeight2%)
    Dim iFromX%
    Dim iFromY%
    Dim iToX%
    Dim iToY%
    iSize% = iSize2% - 1
    iWeight% = iWeight2% - 1
    If iWeight% = 0 Then
        ' TOP LINE
        iFromX% = iX%
        iFromY% = iY%
        iToX% = iX% + iSize%
        iToY% = iY%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF

        ' BOTTOM LINE
        iFromX% = iX%
        iFromY% = iY% + iSize%
        iToX% = iX% + iSize%
        iToY% = iY% + iSize%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF

        ' LEFT LINE
        iFromX% = iX%
        iFromY% = iY%
        iToX% = iX%
        iToY% = iY% + iSize%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF

        ' RIGHT LINE
        iFromX% = iX% + iSize%
        iFromY% = iY%
        iToX% = iX% + iSize%
        iToY% = iY% + iSize%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
    ElseIf iWeight% > 0 Then
        ' TOP LINE
        For iFromY% = iY% To (iY% + iWeight%)
            iFromX% = iX%
            'iFromY% = iY%
            iToX% = iX% + iSize%
            iToY% = iFromY%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromY%

        ' BOTTOM LINE
        For iFromY% = ((iY% + iSize%) - iWeight%) To (iY% + iSize%)
            iFromX% = iX%
            'iFromY% = iY% + iSize%
            iToX% = iX% + iSize%
            iToY% = iFromY%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromY%

        ' LEFT LINE
        For iFromX% = iX% To (iX% + iWeight%)
            'iFromX% = iX%
            iFromY% = iY%
            iToX% = iFromX%
            iToY% = iY% + iSize%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromX%

        ' RIGHT LINE
        For iFromX% = ((iX% + iSize%) - iWeight%) To (iX% + iSize%)
            'iFromX% = iX% + iSize%
            iFromY% = iY%
            iToX% = iFromX%
            iToY% = iY% + iSize%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromX%
    End If
End Sub ' DrawOutlineBox

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GRAPHICS FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GRAPHIC PRINTING ROUTINES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' A way to automatically print to columns.

Sub ColumnBreak ()
    m_PrintRow = m_StartRow
    m_PrintCol = m_PrintCol + 1
    If m_PrintCol > m_NumColumns Then
        'TODO: options for when we go past the last column (stop printing, wrap around)
    End If
End Sub ' ColumnBreak

' /////////////////////////////////////////////////////////////////////////////
' A way to automatically print to columns.

Sub InitColumns (iNumColumns As Integer)
    Dim iCols As Integer
    Dim iRows As Integer
    iCols = _Width(0) \ _FontWidth
    iRows = _Height(0) \ _FontHeight
    If iNumColumns < 1 Or iNumColumns > iCols Then
        m_NumColumns = 1
    Else
        m_NumColumns = iNumColumns
    End If

    If m_StartRow < 1 Or m_StartRow > iRows Then
        m_StartRow = 1
    End If
    If m_EndRow < m_StartRow Or m_EndRow > iRows Then
        m_EndRow = iRows
    End If
    If m_StartCol < 1 Or m_StartCol > m_NumColumns Then
        m_StartCol = 1
    End If
    If m_EndCol < m_StartCol Or m_EndCol > m_NumColumns Then
        m_EndCol = m_NumColumns
    End If

    m_PrintRow = 1
    m_PrintCol = 1
End Sub ' InitColumns

' /////////////////////////////////////////////////////////////////////////////
' A way to automatically print to columns.

' Depends on the following shared variables:
'     Dim Shared m_NumColumns As Integer : m_NumColumns = 1
'     Dim Shared m_PrintRow As Integer : m_PrintRow = 0
'     Dim Shared m_PrintCol As Integer : m_PrintCol = 0
'     Dim Shared m_StartRow As Integer : m_StartRow = 0
'     Dim Shared m_EndRow As Integer : m_EndRow = 0
'     Dim Shared m_StartCol As Integer : m_StartCol = 0
'     Dim Shared m_EndCol As Integer : m_EndCol = 0

' InitColumns 2
' m_PrintRow = 5
' m_PrintCol = 2
' PrintColumn "Col 2, Row 5"
' PrintColumn "m_NumColumns=" + cstr$(m_NumColumns)

Sub PrintColumn (MyString As String)
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iX As Integer
    Dim iY As Integer

    ReDim arrLines(-1) As String
    Dim iRow As Integer
    Dim iCol As Integer
    Dim sChar As String
    Dim sLine As String
    Dim iColWidth As Integer

    iCols = _Width(0) \ _FontWidth
    iRows = _Height(0) \ _FontHeight

    If m_NumColumns < 1 Or m_NumColumns > iCols Then
        m_NumColumns = 1
    End If

    If m_StartRow < 1 Or m_StartRow > iRows Then
        m_StartRow = 1
    End If
    If m_EndRow < m_StartRow Or m_EndRow > iRows Then
        m_EndRow = iRows
    End If
    If m_StartCol < 1 Or m_StartCol > m_NumColumns Then
        m_StartCol = 1
    End If
    If m_EndCol < m_StartCol Or m_EndCol > m_NumColumns Then
        m_EndCol = m_NumColumns
    End If

    If m_PrintRow < m_StartRow Then
        m_PrintRow = m_StartRow
    End If
    If m_PrintCol < m_StartCol Then
        m_PrintCol = m_StartCol
    End If

    iColWidth = iCols \ m_NumColumns

    If m_PrintRow <= m_EndRow Then
        If m_PrintCol <= m_EndCol Then
            split MyString, Chr$(13), arrLines()
            For iRow = 0 To UBound(arrlines)
                sLine = Left$(arrLines(iRow), iColWidth)
                'TODO: wrap remaining text
                iX = _FontWidth * ((m_PrintCol - 1) * iColWidth)
                iY = _FontHeight * (m_PrintRow - 1)
                _PrintString (iX, iY), sLine

                m_PrintRow = m_PrintRow + 1
                If m_PrintRow > m_EndRow Then
                    m_PrintRow = m_StartRow
                    m_PrintCol = m_PrintCol + 1
                    If m_PrintCol > m_NumColumns Then
                        'TODO: options for when we reach the bottom of the last column (stop printing, wrap around)
                        m_PrintCol = 1
                    End If
                End If
            Next iRow
        End If
    End If
End Sub ' PrintColumn

' /////////////////////////////////////////////////////////////////////////////
' Eliminates the math.

' Text resolution:
'  648 x  480:  80 x 30
'  720 x  480:  90 x 30
'  800 x  600: 100 x 37
' 1024 x  768: 128 x 48
' 1280 x 1024: 160 x 64
' 1920 x 1080: 240 x 67
' 2048 x 1152: 256 x 72 (truncated after 70 rows, 255 columns)
' 3840 x 2160: 480 x135 (truncated after 133 rows, 479 columns)

Sub PrintStringCR1 (iCol As Integer, iRow As Integer, MyString As String)
    Dim iCols As Integer
    Dim iRows As Integer
    Dim iX As Integer
    Dim iY As Integer
    iCols = _Width(0) \ _FontWidth
    iRows = _Height(0) \ _FontHeight
    iX = _FontWidth * (iCol - 1)
    iY = _FontHeight * (iRow - 1)
    _PrintString (iX, iY), MyString
End Sub ' PrintStringCR1

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GRAPHIC PRINTING ROUTINES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DEBUGGING ROUTINES #DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Sub DebugPrint (s$)
    If m_bDebug = TRUE Then
        _Echo s$
        'ReDim arrLines$(0)
        'dim delim$ : delim$ = Chr$(13)
        'split MyString, delim$, arrLines$()
    End If
End Sub ' DebugPrint

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DEBUGGING ROUTINES @DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GENERAL PURPOSE ROUTINES #GEN
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////
' Convert a value to string and trim it (because normal Str$ adds spaces)

Function cstr$ (myValue)
    'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
    cstr$ = _Trim$(Str$(myValue))
End Function ' cstr$

' /////////////////////////////////////////////////////////////////////////////
' Convert a Long value to string and trim it (because normal Str$ adds spaces)

Function cstrl$ (myValue As Long)
    cstrl$ = _Trim$(Str$(myValue))
End Function ' cstrl$

' /////////////////////////////////////////////////////////////////////////////
' Convert a Single value to string and trim it (because normal Str$ adds spaces)

Function cstrs$ (myValue As Single)
    ''cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
    cstrs$ = _Trim$(Str$(myValue))
End Function ' cstrs$

' /////////////////////////////////////////////////////////////////////////////
' Convert an unsigned Long value to string and trim it (because normal Str$ adds spaces)

Function cstrul$ (myValue As _Unsigned Long)
    cstrul$ = _Trim$(Str$(myValue))
End Function ' cstrul$

' /////////////////////////////////////////////////////////////////////////////
' Scientific notation - QB64 Wiki
' https://www.qb64.org/wiki/Scientific_notation

' Example: A string function that displays extremely small or large exponential decimal values.

Function DblToStr$ (n#)
    value$ = UCase$(LTrim$(Str$(n#)))
    Xpos% = InStr(value$, "D") + InStr(value$, "E") 'only D or E can be present
    If Xpos% Then
        expo% = Val(Mid$(value$, Xpos% + 1))
        If Val(value$) < 0 Then
            sign$ = "-": valu$ = Mid$(value$, 2, Xpos% - 2)
        Else valu$ = Mid$(value$, 1, Xpos% - 1)
        End If
        dot% = InStr(valu$, "."): L% = Len(valu$)
        If expo% > 0 Then add$ = String$(expo% - (L% - dot%), "0")
        If expo% < 0 Then min$ = String$(Abs(expo%) - (dot% - 1), "0"): DP$ = "."
        For n = 1 To L%
            If Mid$(valu$, n, 1) <> "." Then num$ = num$ + Mid$(valu$, n, 1)
        Next
    Else DblToStr$ = value$: Exit Function
    End If
    DblToStr$ = _Trim$(sign$ + DP$ + min$ + num$ + add$)
End Function ' DblToStr$

' /////////////////////////////////////////////////////////////////////////////

Function FormatNumber$ (myValue, iDigits As Integer)
    Dim strValue As String
    strValue = DblToStr$(myValue) + String$(iDigits, " ")
    If myValue < 1 Then
        If myValue < 0 Then
            strValue = Replace$(strValue, "-.", "-0.")
        ElseIf myValue > 0 Then
            strValue = "0" + strValue
        End If
    End If
    FormatNumber$ = Left$(strValue, iDigits)
End Function ' FormatNumber$

' /////////////////////////////////////////////////////////////////////////////
' From: Bitwise Manipulations By Steven Roman
' http://www.romanpress.com/Articles/Bitwise_R/Bitwise.htm

' Returns the 8-bit binary representation
' of an integer iInput where 0 <= iInput <= 255

Function GetBinary$ (iInput1 As Integer)
    Dim sResult As String
    Dim iLoop As Integer
    Dim iInput As Integer: iInput = iInput1

    sResult = ""

    If iInput >= 0 And iInput <= 255 Then
        For iLoop = 1 To 8
            sResult = LTrim$(RTrim$(Str$(iInput Mod 2))) + sResult
            iInput = iInput \ 2
            'If iLoop = 4 Then sResult = " " + sResult
        Next iLoop
    End If

    GetBinary$ = sResult
End Function ' GetBinary$

' /////////////////////////////////////////////////////////////////////////////
' wonderfully inefficient way to read if a bit is set
' ival = GetBit256%(int we are comparing, int containing the bits we want to read)

' See also: GetBit256%, SetBit256%

Function GetBit256% (iNum1 As Integer, iBit1 As Integer)
    Dim iResult As Integer
    Dim sNum As String
    Dim sBit As String
    Dim iLoop As Integer
    Dim bContinue As Integer
    'DIM iTemp AS INTEGER
    Dim iNum As Integer: iNum = iNum1
    Dim iBit As Integer: iBit = iBit1

    iResult = FALSE
    bContinue = TRUE

    If iNum < 256 And iBit <= 128 Then
        sNum = GetBinary$(iNum)
        sBit = GetBinary$(iBit)
        For iLoop = 1 To 8
            If Mid$(sBit, iLoop, 1) = "1" Then
                'if any of the bits in iBit are false, return false
                If Mid$(sNum, iLoop, 1) = "0" Then
                    iResult = FALSE
                    bContinue = FALSE
                    Exit For
                End If
            End If
        Next iLoop
        If bContinue = TRUE Then
            iResult = TRUE
        End If
    End If

    GetBit256% = iResult
End Function ' GetBit256%

' /////////////////////////////////////////////////////////////////////////////
' From: Bitwise Manipulations By Steven Roman
' http://www.romanpress.com/Articles/Bitwise_R/Bitwise.htm

' Returns the integer that corresponds to a binary string of length 8

Function GetIntegerFromBinary% (sBinary1 As String)
    Dim iResult As Integer
    Dim iLoop As Integer
    Dim strBinary As String
    Dim sBinary As String: sBinary = sBinary1

    iResult = 0
    strBinary = Replace$(sBinary, " ", "") ' Remove any spaces
    For iLoop = 0 To Len(strBinary) - 1
        iResult = iResult + 2 ^ iLoop * Val(Mid$(strBinary, Len(strBinary) - iLoop, 1))
    Next iLoop

    GetIntegerFromBinary% = iResult
End Function ' GetIntegerFromBinary%

' /////////////////////////////////////////////////////////////////////////////

Function IIF (Condition, IfTrue, IfFalse)
    If Condition Then IIF = IfTrue Else IIF = IfFalse
End Function

' /////////////////////////////////////////////////////////////////////////////

Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
    If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
End Function

' /////////////////////////////////////////////////////////////////////////////
' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/

Function IsEven% (n)
    If n Mod 2 = 0 Then
        IsEven% = TRUE
    Else
        IsEven% = FALSE
    End If
End Function ' IsEven%

' /////////////////////////////////////////////////////////////////////////////
' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/

Function IsOdd% (n)
    If n Mod 2 = 1 Then
        IsOdd% = TRUE
    Else
        IsOdd% = FALSE
    End If
End Function ' IsOdd%

' /////////////////////////////////////////////////////////////////////////////
' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0

Function IsNum% (text$)
    Dim a$
    Dim b$
    a$ = _Trim$(text$)
    b$ = _Trim$(Str$(Val(text$)))
    If a$ = b$ Then
        IsNum% = TRUE
    Else
        IsNum% = FALSE
    End If
End Function ' IsNum%

' /////////////////////////////////////////////////////////////////////////////
' Re: Does a Is Number function exist in QB64?
' https://www.qb64.org/forum/index.php?topic=896.15

' MWheatley
' « Reply #18 on: January 01, 2019, 11:24:30 AM »

' returns 1 if string is an integer, 0 if not
Function IsNumber (text$)
    Dim i As Integer

    IsNumber = 1
    For i = 1 To Len(text$)
        If Asc(Mid$(text$, i, 1)) < 45 Or Asc(Mid$(text$, i, 1)) >= 58 Then
            IsNumber = 0
            Exit For
        ElseIf Asc(Mid$(text$, i, 1)) = 47 Then
            IsNumber = 0
            Exit For
        End If
    Next i
End Function ' IsNumber

' /////////////////////////////////////////////////////////////////////////////
' Split and join strings
' https://www.qb64.org/forum/index.php?topic=1073.0

'Combine all elements of in$() into a single string with delimiter$ separating the elements.

Function join$ (in$(), delimiter$)
    Dim result$
    Dim i As Long
    result$ = in$(LBound(in$))
    For i = LBound(in$) + 1 To UBound(in$)
        result$ = result$ + delimiter$ + in$(i)
    Next i
    join$ = result$
End Function ' join$

' /////////////////////////////////////////////////////////////////////////////
' ABS was returning strange values with type LONG
' so I created this which does not.

Function LongABS& (lngValue As Long)
    If Sgn(lngValue) = -1 Then
        LongABS& = 0 - lngValue
    Else
        LongABS& = lngValue
    End If
End Function ' LongABS&

' /////////////////////////////////////////////////////////////////////////////
' Writes sText to a debug file in the EXE folder.
' Debug file is named the same thing as the program EXE name with ".txt" at the end.
' For example the program "C:\QB64\MyProgram.BAS" running as
' "C:\QB64\MyProgram.EXE" would have an output file "C:\QB64\MyProgram.EXE.txt".
' If the file doesn't exist, it is created, otherwise it is appended to.

Sub DebugPrintFile (sText As String)
    Dim sFileName As String
    Dim sError As String
    Dim sOut As String

    sFileName = ProgramPath$ + ProgramName$ + ".txt"
    sError = ""
    If _FileExists(sFileName) = FALSE Then
        sOut = ""
        sOut = sOut + "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + Chr$(13) + Chr$(10)
        sOut = sOut + "PROGRAM : " + ProgramName$ + Chr$(13) + Chr$(10)
        sOut = sOut + "RUN DATE: " + CurrentDateTime$ + Chr$(13) + Chr$(10)
        sOut = sOut + "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + Chr$(13) + Chr$(10)
        sError = PrintFile$(sFileName, sOut, FALSE)
    End If
    If Len(sError) = 0 Then
        sError = PrintFile$(sFileName, sText, TRUE)
    End If
    If Len(sError) <> 0 Then
        Print CurrentDateTime$ + " DebugPrintFile FAILED: " + sError
    End If
End Sub ' DebugPrintFile

' /////////////////////////////////////////////////////////////////////////////

Function IntPadRight$ (iValue As Integer, iWidth As Integer)
    IntPadRight$ = Left$(_Trim$(Str$(iValue)) + String$(iWidth, " "), iWidth)
End Function ' IntPadRight$

' /////////////////////////////////////////////////////////////////////////////
' Returns blank if successful else returns error message.

Function PrintFile$ (sFileName As String, sText As String, bAppend As Integer)
    'x = 1: y = 2: z$ = "Three"

    Dim sError As String: sError = ""

    If Len(sError) = 0 Then
        If (bAppend = TRUE) Then
            If _FileExists(sFileName) Then
                Open sFileName For Append As #1 ' opens an existing file for appending
            Else
                sError = "Error in PrintFile$ : File not found. Cannot append."
            End If
        Else
            Open sFileName For Output As #1 ' opens and clears an existing file or creates new empty file
        End If
    End If
    If Len(sError) = 0 Then
        ' WRITE places text in quotes in the file
        'WRITE #1, x, y, z$
        'WRITE #1, sText

        ' PRINT does not put text inside quotes
        Print #1, sText

        Close #1

        'PRINT "File created with data. Press a key!"
        'K$ = INPUT$(1) 'press a key

        'OPEN sFileName FOR INPUT AS #2 ' opens a file to read it
        'INPUT #2, a, b, c$
        'CLOSE #2

        'PRINT a, b, c$
        'WRITE a, b, c$
    End If

    PrintFile$ = sError
End Function ' PrintFile$

' /////////////////////////////////////////////////////////////////////////////
' Does a _PrintString at the specified row+column.

' iRow and iCol are 0-based.

Sub PrintString (iRow As Integer, iCol As Integer, MyString As String)
    Dim iX As Integer
    Dim iY As Integer
    iX = _FontWidth * iCol
    iY = _FontHeight * iRow ' (iRow + 1)
    _PrintString (iX, iY), MyString
End Sub ' PrintString

' /////////////////////////////////////////////////////////////////////////////
' Does a _PrintString at the specified row+column.

' iRow and iCol are 1-based.

Sub PrintString1 (iRow As Integer, iCol As Integer, MyString As String)
    Dim iX As Integer
    Dim iY As Integer
    iX = _FontWidth * (iCol - 1)
    iY = _FontHeight * (iRow - 1)
    _PrintString (iX, iY), MyString
End Sub ' PrintString1

' /////////////////////////////////////////////////////////////////////////////
' Does a _PrintString at the specified row+column,
' and saves value and color info to ScreenArray.

' PrintString2 iRow, iCol, MyString, ScreenArray()

' iRow and iCol are 1-based.

Sub PrintString2 (iRow As Integer, iCol As Integer, MyString As String, ScreenArray() As TextCellType)
    Dim iX As Integer
    Dim iY As Integer
    Dim iLoop As Integer

    iX = _FontWidth * (iCol - 1)
    iY = _FontHeight * (iRow - 1)
    _PrintString (iX, iY), MyString

    If (iRow >= LBound(ScreenArray, 1)) Then
        If (iRow <= UBound(ScreenArray, 1)) Then
            If (iCol >= LBound(ScreenArray, 2)) Then
                If (iCol <= UBound(ScreenArray, 2)) Then
                    iX = iCol
                    iY = iRow
                    For iLoop = 1 To Len(MyString)
                        If iX > UBound(ScreenArray, 2) Then
                            Exit For
                        Else
                            ScreenArray(iY, iX).value = Mid$(MyString, iLoop, 1)
                            ScreenArray(iY, iX).fgColor = _DefaultColor
                            ScreenArray(iY, iX).bgcolor = _BackgroundColor
                            iX = iX + 1
                        End If
                    Next iLoop
                End If
            End If
        End If
    End If
End Sub ' PrintString2

' /////////////////////////////////////////////////////////////////////////////
' Generate random value between Min and Max.
Function RandomNumber% (Min%, Max%)
    Dim NumSpread%

    ' SET RANDOM SEED
    'Randomize ' Initialize random-number generator.
    Randomize Timer

    ' GET RANDOM # Min%-Max%
    'RandomNumber = Int((Max * Rnd) + Min) ' generate number

    NumSpread% = (Max% - Min%) + 1

    RandomNumber% = Int(Rnd * NumSpread%) + Min% ' GET RANDOM # BETWEEN Max% AND Min%

End Function ' RandomNumber%

' /////////////////////////////////////////////////////////////////////////////

Sub RandomNumberTest
    Dim iCols As Integer: iCols = 10
    Dim iRows As Integer: iRows = 20
    Dim iLoop As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim sError As String
    Dim sFileName As String
    Dim sText As String
    Dim bAppend As Integer
    Dim iMin As Integer
    Dim iMax As Integer
    Dim iNum As Integer
    Dim iErrorCount As Integer
    Dim sInput$

    sFileName = "c:\temp\maze_test_1.txt"
    sText = "Count" + Chr$(9) + "Min" + Chr$(9) + "Max" + Chr$(9) + "Random"
    bAppend = FALSE
    sError = PrintFile$(sFileName, sText, bAppend)
    If Len(sError) = 0 Then
        bAppend = TRUE
        iErrorCount = 0

        iMin = 0
        iMax = iCols - 1
        For iLoop = 1 To 100
            iNum = RandomNumber%(iMin, iMax)
            sText = Str$(iLoop) + Chr$(9) + Str$(iMin) + Chr$(9) + Str$(iMax) + Chr$(9) + Str$(iNum)
            sError = PrintFile$(sFileName, sText, bAppend)
            If Len(sError) > 0 Then
                iErrorCount = iErrorCount + 1
                Print Str$(iLoop) + ". ERROR"
                Print "    " + "iMin=" + Str$(iMin)
                Print "    " + "iMax=" + Str$(iMax)
                Print "    " + "iNum=" + Str$(iNum)
                Print "    " + "Could not write to file " + Chr$(34) + sFileName + Chr$(34) + "."
                Print "    " + sError
            End If
        Next iLoop

        iMin = 0
        iMax = iRows - 1
        For iLoop = 1 To 100
            iNum = RandomNumber%(iMin, iMax)
            sText = Str$(iLoop) + Chr$(9) + Str$(iMin) + Chr$(9) + Str$(iMax) + Chr$(9) + Str$(iNum)
            sError = PrintFile$(sFileName, sText, bAppend)
            If Len(sError) > 0 Then
                iErrorCount = iErrorCount + 1
                Print Str$(iLoop) + ". ERROR"
                Print "    " + "iMin=" + Str$(iMin)
                Print "    " + "iMax=" + Str$(iMax)
                Print "    " + "iNum=" + Str$(iNum)
                Print "    " + "Could not write to file " + Chr$(34) + sFileName + Chr$(34) + "."
                Print "    " + sError
            End If
        Next iLoop

        Print "Finished generating numbers. Errors: " + Str$(iErrorCount)
    Else
        Print "Error creating file " + Chr$(34) + sFileName + Chr$(34) + "."
        Print sError
    End If

    Input "Press <ENTER> to continue", sInput$
End Sub ' RandomNumberTest

' /////////////////////////////////////////////////////////////////////////////
' FROM: String Manipulation
' found at abandoned, outdated and now likely malicious qb64 dot net website
' http://www.qb64.[net]/forum/index_topic_5964-0/
'
'SUMMARY:
'   Purpose:  A library of custom functions that transform strings.
'   Author:   Dustinian Camburides (dustinian@gmail.com)
'   Platform: QB64 (www.qb64.org)
'   Revision: 1.6
'   Updated:  5/28/2012

'SUMMARY:
'[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
'INPUT:
'Text: The input string; the text that's being manipulated.
'Find: The specified sub-string; the string sought within the [Text] string.
'Add: The sub-string that's being added to the [Text] string.

Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
    ' VARIABLES:
    Dim Text2 As String
    Dim Find2 As String
    Dim Add2 As String
    Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
    Dim strBefore As String ' The characters before the string to be replaced.
    Dim strAfter As String ' The characters after the string to be replaced.

    ' INITIALIZE:
    ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
    Text2 = Text1
    Find2 = Find1
    Add2 = Add1

    lngLocation = InStr(1, Text2, Find2)

    ' PROCESSING:
    ' While [Find2] appears in [Text2]...
    While lngLocation
        ' Extract all Text2 before the [Find2] substring:
        strBefore = Left$(Text2, lngLocation - 1)

        ' Extract all text after the [Find2] substring:
        strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))

        ' Return the substring:
        Text2 = strBefore + Add2 + strAfter

        ' Locate the next instance of [Find2]:
        lngLocation = InStr(1, Text2, Find2)

        ' Next instance of [Find2]...
    Wend

    ' OUTPUT:
    Replace$ = Text2
End Function ' Replace$

' /////////////////////////////////////////////////////////////////////////////

Sub ReplaceTest
    Dim in$

    Print "-------------------------------------------------------------------------------"
    Print "ReplaceTest"
    Print

    Print "Original value"
    in$ = "Thiz iz a teZt."
    Print "in$ = " + Chr$(34) + in$ + Chr$(34)
    Print

    Print "Replacing lowercase " + Chr$(34) + "z" + Chr$(34) + " with " + Chr$(34) + "s" + Chr$(34) + "..."
    in$ = Replace$(in$, "z", "s")
    Print "in$ = " + Chr$(34) + in$ + Chr$(34)
    Print

    Print "Replacing uppercase " + Chr$(34) + "Z" + Chr$(34) + " with " + Chr$(34) + "s" + Chr$(34) + "..."
    in$ = Replace$(in$, "Z", "s")
    Print "in$ = " + Chr$(34) + in$ + Chr$(34)
    Print

    Print "ReplaceTest finished."
End Sub ' ReplaceTest

' /////////////////////////////////////////////////////////////////////////////
' https://www.qb64.org/forum/index.php?topic=3605.0
' Quote from: SMcNeill on Today at 03:53:48 PM
'
' Sometimes, you guys make things entirely too  complicated.
' There ya go!  Three functions to either round naturally,
' always round down, or always round up, to whatever number of digits you desire.
' EDIT:  Modified to add another option to round scientific,
' since you had it's description included in your example.

Function Round## (num##, digits%)
    Round## = Int(num## * 10 ^ digits% + .5) / 10 ^ digits%
End Function

Function RoundUp## (num##, digits%)
    RoundUp## = _Ceil(num## * 10 ^ digits%) / 10 ^ digits%
End Function

Function RoundDown## (num##, digits%)
    RoundDown## = Int(num## * 10 ^ digits%) / 10 ^ digits%
End Function

Function Round_Scientific## (num##, digits%)
    Round_Scientific## = _Round(num## * 10 ^ digits%) / 10 ^ digits%
End Function

Function RoundUpDouble# (num#, digits%)
    RoundUpDouble# = _Ceil(num# * 10 ^ digits%) / 10 ^ digits%
End Function

Function RoundUpSingle! (num!, digits%)
    RoundUpSingle! = _Ceil(num! * 10 ^ digits%) / 10 ^ digits%
End Function

' /////////////////////////////////////////////////////////////////////////////
' fantastically inefficient way to set a bit

' example use: arrMaze(iX, iY) = SetBit256%(arrMaze(iX, iY), cS, FALSE)

' See also: GetBit256%, SetBit256%

' newint=SetBit256%(oldint, int containing the bits we want to set, value to set them to)
Function SetBit256% (iNum1 As Integer, iBit1 As Integer, bVal1 As Integer)
    Dim sNum As String
    Dim sBit As String
    Dim sVal As String
    Dim iLoop As Integer
    Dim strResult As String
    Dim iResult As Integer
    Dim iNum As Integer: iNum = iNum1
    Dim iBit As Integer: iBit = iBit1
    Dim bVal As Integer: bVal = bVal1

    If iNum < 256 And iBit <= 128 Then
        sNum = GetBinary$(iNum)
        sBit = GetBinary$(iBit)
        If bVal = TRUE Then
            sVal = "1"
        Else
            sVal = "0"
        End If
        strResult = ""
        For iLoop = 1 To 8
            If Mid$(sBit, iLoop, 1) = "1" Then
                strResult = strResult + sVal
            Else
                strResult = strResult + Mid$(sNum, iLoop, 1)
            End If
        Next iLoop
        iResult = GetIntegerFromBinary%(strResult)
    Else
        iResult = iNum
    End If

    SetBit256% = iResult
End Function ' SetBit256%

' /////////////////////////////////////////////////////////////////////////////
' Scientific notation - QB64 Wiki
' https://www.qb64.org/wiki/Scientific_notation

' Example: A string function that displays extremely small or large exponential decimal values.

Function SngToStr$ (n!)
    value$ = UCase$(LTrim$(Str$(n!)))
    Xpos% = InStr(value$, "D") + InStr(value$, "E") 'only D or E can be present
    If Xpos% Then
        expo% = Val(Mid$(value$, Xpos% + 1))
        If Val(value$) < 0 Then
            sign$ = "-": valu$ = Mid$(value$, 2, Xpos% - 2)
        Else valu$ = Mid$(value$, 1, Xpos% - 1)
        End If
        dot% = InStr(valu$, "."): L% = Len(valu$)
        If expo% > 0 Then add$ = String$(expo% - (L% - dot%), "0")
        If expo% < 0 Then min$ = String$(Abs(expo%) - (dot% - 1), "0"): DP$ = "."
        For n = 1 To L%
            If Mid$(valu$, n, 1) <> "." Then num$ = num$ + Mid$(valu$, n, 1)
        Next
    Else SngToStr$ = value$: Exit Function
    End If
    SngToStr$ = _Trim$(sign$ + DP$ + min$ + num$ + add$)
End Function ' SngToStr$

' /////////////////////////////////////////////////////////////////////////////
' Split and join strings
' https://www.qb64.org/forum/index.php?topic=1073.0
'
' FROM luke, QB64 Developer
' Date: February 15, 2019, 04:11:07 AM »
'
' Given a string of words separated by spaces (or any other character),
' splits it into an array of the words. I've no doubt many people have
' written a version of this over the years and no doubt there's a million
' ways to do it, but I thought I'd put mine here so we have at least one
' version. There's also a join function that does the opposite
' array -> single string.
'
' Code is hopefully reasonably self explanatory with comments and a little demo.
' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.

'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
'
'delimiter$ must be one character long.
'result$() must have been REDIMmed previously.

' Modified to handle multi-character delimiters

Sub split (in$, delimiter$, result$())
    Dim start As Integer
    Dim finish As Integer
    Dim iDelimLen As Integer
    ReDim result$(-1)

    iDelimLen = Len(delimiter$)

    start = 1
    Do
        'While Mid$(in$, start, 1) = delimiter$
        While Mid$(in$, start, iDelimLen) = delimiter$
            'start = start + 1
            start = start + iDelimLen
            If start > Len(in$) Then
                Exit Sub
            End If
        Wend
        finish = InStr(start, in$, delimiter$)
        If finish = 0 Then
            finish = Len(in$) + 1
        End If

        ReDim _Preserve result$(0 To UBound(result$) + 1)

        result$(UBound(result$)) = Mid$(in$, start, finish - start)
        start = finish + 1
    Loop While start <= Len(in$)
End Sub ' split

' /////////////////////////////////////////////////////////////////////////////

Sub SplitTest
    Dim in$
    Dim delim$
    ReDim arrTest$(0)
    Dim iLoop%

    delim$ = Chr$(10)
    in$ = "this" + delim$ + "is" + delim$ + "a" + delim$ + "test"
    Print "in$ = " + Chr$(34) + in$ + Chr$(34)
    Print "delim$ = " + Chr$(34) + delim$ + Chr$(34)
    split in$, delim$, arrTest$()

    For iLoop% = LBound(arrTest$) To UBound(arrTest$)
        Print "arrTest$(" + LTrim$(RTrim$(Str$(iLoop%))) + ") = " + Chr$(34) + arrTest$(iLoop%) + Chr$(34)
    Next iLoop%
    Print
    Print "Split test finished."
End Sub ' SplitTest

' /////////////////////////////////////////////////////////////////////////////

Sub SplitAndReplaceTest
    Dim in$
    Dim out$
    Dim iLoop%
    ReDim arrTest$(0)

    Print "-------------------------------------------------------------------------------"
    Print "SplitAndReplaceTest"
    Print

    Print "Original value"
    in$ = "This line 1 " + Chr$(13) + Chr$(10) + "and line 2" + Chr$(10) + "and line 3 " + Chr$(13) + "finally THE END."
    out$ = in$
    out$ = Replace$(out$, Chr$(13), "\r")
    out$ = Replace$(out$, Chr$(10), "\n")
    out$ = Replace$(out$, Chr$(9), "\t")
    Print "in$ = " + Chr$(34) + out$ + Chr$(34)
    Print

    Print "Fixing linebreaks..."
    in$ = Replace$(in$, Chr$(13) + Chr$(10), Chr$(13))
    in$ = Replace$(in$, Chr$(10), Chr$(13))
    out$ = in$
    out$ = Replace$(out$, Chr$(13), "\r")
    out$ = Replace$(out$, Chr$(10), "\n")
    out$ = Replace$(out$, Chr$(9), "\t")
    Print "in$ = " + Chr$(34) + out$ + Chr$(34)
    Print

    Print "Splitting up..."
    split in$, Chr$(13), arrTest$()

    For iLoop% = LBound(arrTest$) To UBound(arrTest$)
        out$ = arrTest$(iLoop%)
        out$ = Replace$(out$, Chr$(13), "\r")
        out$ = Replace$(out$, Chr$(10), "\n")
        out$ = Replace$(out$, Chr$(9), "\t")
        Print "arrTest$(" + cstr$(iLoop%) + ") = " + Chr$(34) + out$ + Chr$(34)
    Next iLoop%
    Print

    Print "SplitAndReplaceTest finished."
End Sub ' SplitAndReplaceTest

' /////////////////////////////////////////////////////////////////////////////

Function StrPadLeft$ (sValue As String, iWidth As Integer)
    StrPadLeft$ = Right$(String$(iWidth, " ") + sValue, iWidth)
End Function ' StrPadLeft$

' /////////////////////////////////////////////////////////////////////////////

Function StrJustifyRight$ (sValue As String, iWidth As Integer)
    StrJustifyRight$ = Right$(String$(iWidth, " ") + sValue, iWidth)
End Function ' StrJustifyRight$

' /////////////////////////////////////////////////////////////////////////////

Function StrPadRight$ (sValue As String, iWidth As Integer)
    StrPadRight$ = Left$(sValue + String$(iWidth, " "), iWidth)
End Function ' StrPadRight$

' /////////////////////////////////////////////////////////////////////////////

Function StrJustifyLeft$ (sValue As String, iWidth As Integer)
    StrJustifyLeft$ = Left$(sValue + String$(iWidth, " "), iWidth)
End Function ' StrJustifyLeft$

' /////////////////////////////////////////////////////////////////////////////
' div: int1% = num1% \ den1%
' mod: rem1% = num1% MOD den1%

Function StrJustifyCenter$ (sValue As String, iWidth As Integer)
    Dim iLen0 As Integer
    Dim iLen1 As Integer
    Dim iLen2 As Integer
    Dim iExtra As Integer

    iLen0 = Len(sValue)
    If iWidth = iLen0 Then
        ' no extra space: return unchanged
        StrJustifyCenter$ = sValue
    ElseIf iWidth > iLen0 Then
        If IsOdd%(iWidth) Then
            iWidth = iWidth - 1
        End If

        ' center
        iExtra = iWidth - iLen0
        iLen1 = iExtra \ 2
        iLen2 = iLen1 + (iExtra Mod 2)
        StrJustifyCenter$ = String$(iLen1, " ") + sValue + String$(iLen2, " ")
    Else
        ' string is too long: truncate
        StrJustifyCenter$ = Left$(sValue, iWidth)
    End If
End Function ' StrJustifyCenter$

' /////////////////////////////////////////////////////////////////////////////

Function TrueFalse$ (myValue)
    If myValue = TRUE Then
        TrueFalse$ = "TRUE"
    Else
        TrueFalse$ = "FALSE"
    End If
End Function ' TrueFalse$

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GENERAL PURPOSE ROUTINES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN COLOR ARRAY FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' /////////////////////////////////////////////////////////////////////////////

Sub AddColor (ColorValue As _Unsigned Long, ColorName As String, arrColor() As ColorType)
    ReDim _Preserve arrColor(0 To UBound(arrColor) + 1) As ColorType
    arrColor(UBound(arrColor)).name = ColorName
    arrColor(UBound(arrColor)).value = ColorValue
End Sub ' AddColor

' /////////////////////////////////////////////////////////////////////////////

Sub AddColors (arrColor() As ColorType)
    AddColor cBlack, "cBlack", arrColor()
    ''AddColor cDarkGray, "cDarkGray", arrColor()
    ''AddColor cDimGray, "cDimGray", arrColor()
    AddColor cGray, "cGray", arrColor()
    AddColor cSilver, "cSilver", arrColor()
    ''AddColor cLightGray, "cLightGray", arrColor()
    AddColor cWhite, "cWhite", arrColor()

    AddColor cRed, "cRed", arrColor()
    AddColor cOrangeRed, "cOrangeRed", arrColor()
    'AddColor cDarkOrange, "cDarkOrange", arrColor()
    'AddColor cOrange, "cOrange", arrColor()
    'AddColor cGold, "cGold", arrColor()
    AddColor cYellow, "cYellow", arrColor()
    'AddColor cOliveDrab1, "cOliveDrab1", arrColor()
    AddColor cLime, "cLime", arrColor()
    'AddColor cMediumSpringGreen, "cMediumSpringGreen", arrColor()
    AddColor cCyan, "cCyan", arrColor()
    'AddColor cDeepSkyBlue, "cDeepSkyBlue", arrColor()
    AddColor cDodgerBlue, "cDodgerBlue", arrColor()
    'AddColor cSeaBlue, "cSeaBlue", arrColor()
    AddColor cBlue, "cBlue", arrColor()
    'AddColor cBluePurple, "cBluePurple", arrColor()
    AddColor cDeepPurple, "cDeepPurple", arrColor()
    'AddColor cPurple, "cPurple", arrColor()
    'AddColor cPurpleRed, "cPurpleRed", arrColor()

    ''AddColor cGainsboro, "cGainsboro", arrColor()
    ''AddColor cWhiteSmoke, "cWhiteSmoke", arrColor()

    'AddColor cDarkRed, "cDarkRed", arrColor()
    ''AddColor cBrickRed, "cBrickRed", arrColor()

    AddColor cDarkGreen, "cDarkGreen", arrColor()
    'AddColor cGreen, "cGreen", arrColor()
    ''AddColor cOliveDrab, "cOliveDrab", arrColor()
    ''AddColor cLightPink, "cLightPink", arrColor()
    AddColor cMagenta, "cMagenta", arrColor()
    AddColor cHotPink, "cHotPink", arrColor()
    'AddColor cDeepPink, "cDeepPink", arrColor()

    AddColor cDarkBrown, "cDarkBrown", arrColor()
    'AddColor cLightBrown, "cLightBrown", arrColor()
    'AddColor cKhaki, "cKhaki", arrColor()

    AddColor cEmpty, "cEmpty", arrColor()
End Sub ' AddColors

' /////////////////////////////////////////////////////////////////////////////

Sub AddGrayscaleColors (arrColor() As ColorType)
    'AddColor cBlack, "cBlack", arrColor()
    AddColor cDimGray, "cDimGray", arrColor()
    AddColor cGray, "cGray", arrColor()
    AddColor cDarkGray, "cDarkGray", arrColor()
    AddColor cSilver, "cSilver", arrColor()
    AddColor cLightGray, "cLightGray", arrColor()
    AddColor cWhite, "cGainsboro", arrColor()
    AddColor cWhite, "cWhiteSmoke", arrColor()
    AddColor cWhite, "cWhite", arrColor()
End Sub ' AddGrayscaleColors

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END COLOR ARRAY FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN COLOR FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' NOTE: these are mostly negative numbers
'       and have to be forced to positive
'       when stored in the dictionary
'       (only cEmpty should be negative)

Function cRed~& ()
    cRed = _RGB32(255, 0, 0)
End Function

Function cOrangeRed~& ()
    cOrangeRed = _RGB32(255, 69, 0)
End Function ' cOrangeRed~&

Function cDarkOrange~& ()
    cDarkOrange = _RGB32(255, 140, 0)
End Function ' cDarkOrange~&

Function cOrange~& ()
    cOrange = _RGB32(255, 165, 0)
End Function ' cOrange~&

Function cGold~& ()
    cGold = _RGB32(255, 215, 0)
End Function ' cGold~&

Function cYellow~& ()
    cYellow = _RGB32(255, 255, 0)
End Function ' cYellow~&

' LONG-HAIRED FRIENDS OF JESUS OR NOT,
' THIS IS NOT YELLOW ENOUGH (TOO CLOSE TO LIME)
' TO USE FOR OUR COMPLEX RAINBOW SEQUENCE:
Function cChartreuse~& ()
    cChartreuse = _RGB32(127, 255, 0)
End Function ' cChartreuse~&

' WE SUBSTITUTE THIS CSS3 COLOR FOR INBETWEEN LIME AND YELLOW:
Function cOliveDrab1~& ()
    cOliveDrab1 = _RGB32(192, 255, 62)
End Function ' cOliveDrab1~&

Function cLime~& ()
    cLime = _RGB32(0, 255, 0)
End Function ' cLime~&

Function cMediumSpringGreen~& ()
    cMediumSpringGreen = _RGB32(0, 250, 154)
End Function ' cMediumSpringGreen~&

Function cCyan~& ()
    cCyan = _RGB32(0, 255, 255)
End Function ' cCyan~&

Function cDeepSkyBlue~& ()
    cDeepSkyBlue = _RGB32(0, 191, 255)
End Function ' cDeepSkyBlue~&

Function cDodgerBlue~& ()
    cDodgerBlue = _RGB32(30, 144, 255)
End Function ' cDodgerBlue~&

Function cSeaBlue~& ()
    cSeaBlue = _RGB32(0, 64, 255)
End Function ' cSeaBlue~&

Function cBlue~& ()
    cBlue = _RGB32(0, 0, 255)
End Function ' cBlue~&

Function cBluePurple~& ()
    cBluePurple = _RGB32(64, 0, 255)
End Function ' cBluePurple~&

Function cDeepPurple~& ()
    cDeepPurple = _RGB32(96, 0, 255)
End Function ' cDeepPurple~&

Function cPurple~& ()
    cPurple = _RGB32(128, 0, 255)
End Function ' cPurple~&

Function cPurpleRed~& ()
    cPurpleRed = _RGB32(128, 0, 192)
End Function ' cPurpleRed~&

Function cDarkRed~& ()
    cDarkRed = _RGB32(160, 0, 64)
End Function ' cDarkRed~&

Function cBrickRed~& ()
    cBrickRed = _RGB32(192, 0, 32)
End Function ' cBrickRed~&

Function cDarkGreen~& ()
    cDarkGreen = _RGB32(0, 100, 0)
End Function ' cDarkGreen~&

Function cGreen~& ()
    cGreen = _RGB32(0, 128, 0)
End Function ' cGreen~&

Function cOliveDrab~& ()
    cOliveDrab = _RGB32(107, 142, 35)
End Function ' cOliveDrab~&

Function cLightPink~& ()
    cLightPink = _RGB32(255, 182, 193)
End Function ' cLightPink~&

Function cHotPink~& ()
    cHotPink = _RGB32(255, 105, 180)
End Function ' cHotPink~&

Function cDeepPink~& ()
    cDeepPink = _RGB32(255, 20, 147)
End Function ' cDeepPink~&

Function cMagenta~& ()
    cMagenta = _RGB32(255, 0, 255)
End Function ' cMagenta~&

Function cBlack~& ()
    cBlack = _RGB32(0, 0, 0)
End Function ' cBlack~&

Function cDimGray~& ()
    cDimGray = _RGB32(105, 105, 105)
End Function ' cDimGray~&

Function cGray~& ()
    cGray = _RGB32(128, 128, 128)
End Function ' cGray~&

Function cDarkGray~& ()
    cDarkGray = _RGB32(169, 169, 169)
End Function ' cDarkGray~&

Function cSilver~& ()
    cSilver = _RGB32(192, 192, 192)
End Function ' cSilver~&

Function cLightGray~& ()
    cLightGray = _RGB32(211, 211, 211)
End Function ' cLightGray~&

Function cGainsboro~& ()
    cGainsboro = _RGB32(220, 220, 220)
End Function ' cGainsboro~&

Function cWhiteSmoke~& ()
    cWhiteSmoke = _RGB32(245, 245, 245)
End Function ' cWhiteSmoke~&

Function cWhite~& ()
    cWhite = _RGB32(255, 255, 255)
    'cWhite = _RGB32(254, 254, 254)
End Function ' cWhite~&

Function cDarkBrown~& ()
    cDarkBrown = _RGB32(128, 64, 0)
End Function ' cDarkBrown~&

Function cLightBrown~& ()
    cLightBrown = _RGB32(196, 96, 0)
End Function ' cLightBrown~&

Function cKhaki~& ()
    cKhaki = _RGB32(240, 230, 140)
End Function ' cKhaki~&

Function cEmpty~& ()
    'cEmpty~& = -1
    cEmpty = _RGB32(0, 0, 0, 0)
End Function ' cEmpty~&

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END COLOR FUNCTIONS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' A BONUS DIY PROJECT:
' Build your own controller!
' Just some simple switches and wood parts.
' Wire it up to a simple Atari joystick cable.
' Looks like stilts!

' Who says video game controllers can't be fun??

' "see_dick_run_joystick.GIF" 8/9/2005 12:01 PM
' A = left leg 2x4, moves forward & back
' B = right leg 2x4, moves forward & back
' C = right leg pivot 2x4, moves right/left
' D = left leg pivot 2x4, moves right/left
' E = armature, holds parts in place
' All 2x4s spring loaded
'                                                                                  .(&@%/
'                                                                                 ./@&#@%*.
'                                                                                 (@#* /%@*
'                                                                               .*%&*. .(@(,                                              .#%%%%%%%%(/,.
'                                                                               *@&%/***(%@%.                                             ,&@@%######%@%*
'                                                                              *#@@@@@@@@@@&(,                                            ,&@&,      ,&@&,
'                                                                             .%&/.       *#@(.                                           ,&@@#(((((#%@#*
'                                                                            ./%#.         *&#*                                           ,&@@&&&&&&&&&&#,.
'                                                                                                                                         ,&@&,        (@@(
'                                                                                                                                         ,&@@/*******(%@(,
'                                                                                                                                         ,&@@@@@@@@@&#/,
'
'                                       .                                          ,&@@@@@@@@@@@@@@#             .....
'                                     /#*.                                         ,&@&&&&&&&&&&&@@#            #@@@@@&%%%%%%%%(.
'                                .*(##*                                            ,&@&&&&&&&&&&&@@#            #@&&&&&&&&&&&&&@@@@@(
'                              .##.                                  ,&@@@/        ,&@&&&&&&&&&&&@@#            #@&&&&&&&&&&&&&&&&@@(
'                           ./(/.                   ,((((((((((((((((*             ,&@&&&&&&&&&&&@@#            #@&&&&&&&&&&&&&&&&@@(
'                        *&@%.      ......../@@@@@@@/                              ,&@&&&&&&&&&&&@@#            #@&&&&&&&&&&&&&&&&@@(        ..
'                     ,#&% *#######/********,                                      ,&@&&&&&&&&&&&@@#            #@&&&&&&&&&&&&&&&&@@(       .**/##/
'                    (%%%%%/,,.                                                    ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&%/             ,#%#*,,
'                           ../%,                                                  ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                  ..,%&&,
'                               *(//*                                              ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                        *(((//,                  *(/,
'                                   ,&/                                            ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                              /@@@&*              ,&/
'                                     ,,                                           ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                                   ,**(##*          (&,
'                                                                                  ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                                         *%%(,,.     .#(,
'                                                                                  ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                                             ..*&&#.   /@*
'                                                                                  ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                                                  .(((///&#
'                                                                                  ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                                                         #@@*
'                                                                                  ,&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&&@&,                                                     .(#(.
'                                                                                 .*&@&&&&&&&&&&&@@#          /@@&&&&&&&&&&&&&&&@&#.                                           .,,,/%%%%%#.
'                                                                                 (@@&&&&&&&&&&&@&*.          /@@&&&&&&&&&&&&&&@@(                                         ,%&%*....
'                                                                                 (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                                                                                 (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                                                                                 (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                                    ..*%&&&&&&&&&#,..                            (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                                  (#,,.           .,,#/                          (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                               ,/#,                   ,#/,                       (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                             /&,                         *@/                     (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                          *(/,                             ,/(*                  (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                        ,@/                                   /&,                (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&&@@(
'                       /#,.                                   .*#/               (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&@&*.
'                       #%                                      .%#               (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&@%.
'                     *@*                                         /@*             (@@&&&&&&&&&&&@&,         .%@&&&&&&&&&&&&&&&@%.
'                    *(/.                                         ./(*            (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&&&@%.
'                   .%#                                             #%            (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&&&@%.
'                   .%#                                             #%            (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&&&@%.
'                   .%#                                             #%            (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&&&@%.
'                  /&*                                               *&*          (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&&&@%.
'                  /@,                                               ,@/          (@@&&&&&&&&&&&@&,        /@@&&&&&&&&&&&&&&&&@%.
'                  /@,                                               *@/          (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&&&@%.                              .*/%@@&%(*.
'                  /@,                                               *@/          (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&@@(,                             *%@&(/***/(%@(,
'                  /@,                                               *@/          (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&@@/                             *#@(.       .*.
'                   ,#(                                             (#.           (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&@@/                             #@@/
'                   .%#                                             #%            (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&@@/                             #@@/
'                   .%#                                             #%            (@@&&&&&&&&&&&@&,        (@@&&&&&&&&&&&&&&@@/                             ,(@(,      .,/,.
'                   .%#                                             #%            (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&&@@/                              ,(&@%####%&&&/.
'                     *@*                                         *@*             (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&&@@/                                 ,*(%%#(*.
'                      .##                                      .#(.              (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&&@@/
'                       #%                                      .%#               (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&&@@/
'                        ,@/                                   /&,                (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&&@@/
'                        .*((.                               .((*                 (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&@%/.
'                           .#(,                           ,(#.                   (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&@#
'                              ,#(                       (#,                      (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&@#                                  (&&/
'                                ,#/,                 */(,                        (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&@#  ,&@&&&&&&&@%.        ,////(#####,
'                                   ,@@&.         ,&@&,                           (@@&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&@#  ,&&%%%%%%%&%.     #@@/
'                                       *///#@#///*                             *@@&&&&&&&&&&&&&@&,      ,&@&&&&&&&&&&&&&&&@#  ,&&%%%%%%%&%.     /##&%.
'                                           *@@%                    .....       *@@&&&&&&&&&&&@@(       .*&@&&&&&&&&&&&&&&&@#  ,&&%%%%%%%&%.        /&@@%*..                           ..
'                                           *@@%               *%%%%%%%@&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&&&@#  ,&&%%%%%%%&%.         ,&( .,,#%%%#.                     ,(#.
'                                           *@((@/             /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&&&@#  ,&&%%%%%%%&%.           (&,      .(###(**,                .&(
'                                           *@@@@/             /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&&&@#  ,&&%%%%%%%&%.           (&,              *@@@@/             /@,
'                                           *@*,@%/.           /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&&&@#  ,&&%%%%%%%&%.            .%(                  ,////(((,       */(,
'                ................/@*        *@*  (@@(          /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%%&%.                                         (&&&%*.... #%.
'               (&(//////////////#@*        *@*  (&*/#.        /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%%&%.                                              ,,,,/%@@%*
'               (&*,,,,,,,,,,,,,,(@*        *@*  (&.  ((*.     /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%%&%.                              /##########/********,  .(#(.
'               (&*,,,,,,,,,,,,,,,*%#     .%#     ,&(  *@*     /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%@/
'               (&*,,,,,,,,,,,,,,,,%%     .%#     ,&(    */(,  /@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%@/
'             ,@(,,,,,,,,,,,,,,,,,,%%     .%#     ,&(       (&./@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%@/
'             ,@(,,,,,,,,,,,,,,,,,,%%     .%#      ,/#.     .*#&@%%%%%%&&.      *@@&&&&&&&&&&&@@(       (@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%@/
'             ,@(,,,,,,,,,,,,,,,,,,%%     .%#       /@,        /@&%%%%%&&.   .**(@@&&&&&&&&&&&@@(     .*#@@&&&&&&&&&&&&&&@@*   ,&&%%%%%%@/  *##&@&%%%%%%%%%%%%%%%%%%/********************,
'             ,@(,,,,,,,,,,,,,,,,,,%%     .%#       /@,        /@@&%%%%&@@@@@(..*@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&&&@@*   ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,********************#&,
'             ,@(,,,,,,,,,,,,,,,,,,/((,   .%#        .%#       /@%%&&&&@&.      *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&&&@@*   ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&,
'             ,@(,,,,,,,,,,,,,,,,,,,/@/   .%#        .%#       /@%%%%%%&&.      *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&,
'             ,@(,,,,,,,,,,,,,,,,,,,/@/   .%#        .%#       /@%%%%%%&&.      *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&,
'             ,@(,,,,,,,,,,,,,,,,,,,/@/   .%#          *@*     /@%%%%%%&&.      *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&,
'            (%*,,,,,,,,,,,,,,,,,,,,/@/   .%#          *@*     /@%%%%%%&&.      *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&@@(     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&,
'            #%*,,,,,,,,,,,,,,,,,,,,/@/   .%#          *@*     /@%%%%%%&&.      *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*((/.
'            #%*,,,,,,,,,,,,,,,,,,,,,,#&. .%#            #@@@%,(@%%%%%%&&.      *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'            #%*,,,,,,,,,,,,,,,,,,,,,,#&. .%#            #%   ,#@&&&&@@@@%#(.   *@@&&&&&&&&&&&@@(     *@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'            #%*,,,,,,,,,,,,,,,,,,,,,,#&. .%#                  /@%%%%%%&&.  (%%%&@@@@@@@@@&&&&@@(     *@@&&&&&&&&&&&&&&@@(     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'            #%*,,,,,,,,,,,,,,,,,,,,,,#&. .%#                  /@%%%%%@(.       *@@@@@@@@@@@@@@@(     *@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'            #%*,,,,,,,,,,,,,,,,,,,,,,#&. .%#                  /@%%%%%@/        *@@&&&&&&&&&&&@@%((((.*@@&&&&&&&&&&&&&&@@#     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'            #%*,,,,,,,,,,,,,,,,,,,,,,#%. .%#                  /@%%%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&&@@(     ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          ,#(/,,,,,,,,,,,,,,,,,,,,,,,,*&(.%#                  /@%%%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          *@(,,,,,,,,,,,,,,,,,,,,,,,,,*&@@,                   *%##%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          *@(,,,,,,,,,,,,,,,,,,,,,,,,,*&@@,                      ,%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          *@(,,,,,,,,,,,,,,,,,,,,,,,,,*&@@,     ,////////*,.     ,%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          *@(,,,,,,,,,,,,,,,,,,,,,,,,,*&@@,     (@@@@@@@@@@@&/.  ,%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          *@(,,,,,,,,,,,,,,,,,,,,,,,,,*&@@,     (@@(       *#@#, ,%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          *@(,,,,,,,,,,,,,,,,,,,,,,,,,,,#@,     (@@(        ,&&#.,%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@/
'          *@(,,,,,,,,,,,,,,,,,,,,,,,,,*%@@,     (@@(        ,&@&,,%%%@/        *@@&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,##,.
'         ,(%/,,,,,,,,,,,,,,,,,,,,,,,,,*&@@,     (@@(        ,&&(.,%%%@/       #@&&&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'        .%%,,,,,,,,,,,,,,,,,,,,,,,,,,#&*#@,     (@@(      ./%@(. ,%%%@/       #@&&&&&&&&&&&&&@@(    #@&&&&&&&&&&&&&&&@&,      ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'        .%%,,,,,,,,,,,,,,,,,,,,,,,,,,#&*#@,     (@@@@@@@@@%#/,   ,%%%@/       #@&&&&&&&&&&&&@&(,    #@&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'        .%%,,,,,,,,,,,,,,,,,,,,,,,,,,#&*(&*.                     ,%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'         %%,,,,,,,,,,,,,,,,,,,,,,,,/%#/,,*&#                     ,%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'        .%%,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,*&#                  /@%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'        .%%,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,*&#                  /@%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'        .%%,,,,,,,,,,,,,,,,,,,,,,,(##/,,,*&&(.                /@%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'        ,##,,,,,,,,,,,,,,,,,,,,,,,%%*,,,,*&@@*                /@%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'       /@/,,,,,,,,,,,,,,,,,,,,,,,,%%*,,,,,/#@*                /@%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'       /@/,,,,,,,,,,,,,,,,,,,,,,*/##,,,,,,,(@*              ,&&%%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'       /@/,,,,,,,,,,,,,,,,,,,,,,(@(,,,,,,,,(@@#             ,&&%%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&&@@(        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'       /@/,,,,,,,,,,,,,,,,,,,,,,(@(,,,,,,,,(@@%             ,&&%%%%%%@/       #@&&&&&&&&&&&&@%.   *@@&&&&&&&&&&&&&@&(,        ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%.
'       /@/,,,,,,,,,,,,,,,,,,,,,*(@/,,,,,,,,(@@%             ,&&%%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&@%.         ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'       /@/,,,,,,,,,,,,,,,,,,,,*&%,,,,,,,,,,(@(/#*           ,&&%%%%%%@/       #@&&&&&&&&&&&&@%.   /@@&&&&&&&&&&&&&@%.         ,&&%%%%%%@/     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'       /@/,,,,,,,,,,,,,,,,,,,,*&%,,,,,,,,,,/%//@/           ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&&&@%.         ,&&%%%%%%%,     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .%#*,,,,,,,,,,,,,,,,,,,,,*&%,,,,,,,,,,,,%@@/           ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&&&@%.        (&%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .&#,,,,,,,,,,,,,,,,,,,,,#@/,,,,,,,,,,,,,%@@/           ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&&&@%.        (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .&#,,,,,,,,,,,,,,,,,,,,,#@/,,,,,,,,,,,,,%% (&.         ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&&&@%.        (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .&#,,,,,,,,,,,,,,,,,,,,,#@/,,,,,,,,,,,,,%% (&.         ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&&&@%.        (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .&#,,,,,,,,,,,,,,,,,,,*&#,,,,,,,,,,,,,,,%% (&.         ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&&&@%.        (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .&#,,,,,,,,,,,,,,,,,,,*&#,,,,,,,,,,,,,,,%@&(/%/        ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&&&@%.        (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .&#,,,,,,,,,,,,,,,,,,,*&#,,,,,,,,,,,,,,,%@@(*&(        ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&@@%/         (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'     .&#,,,,,,,,,,,,,,,,,,#&*,,,,,,,,,,,,,,,,%@@(*&(        ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'    *#(/,,,,,,,,,,,,,,,,,,#&*,,,,,,,,,,,,,,,,%&(**&(        ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'    (&*,,,,,,,,,,,,,,,,,,,#&*,,,,,,,,,,,,,,,,%%*,,,#@,      ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'    (&*,,,,,,,,,,,,,,,,,/&#*,,,,,,,,,,,,,,,,,%%*,,,#@,      ,&&%%%%%%@/       #@&&&&&&&&&&&&@%. .%@&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'    (&*,,,,,,,,,,,,,,,,,/@(,,,,,,,,,,,,,,,,,,%%*,,,#@,      ,&&%%%%%%@/       #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#
'    (&*,,,,,,,,,,,,,,,,,/@(,,,,,,,,,,,,,,,,,,%%*,,,#&,      ,&&%%%%%%@/       #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#
'    (&*,,,,,,,,,,,,,,,,(#(*,,,,,,,,,,,,,,,,,,%%*,,,,*&#     ,&&%%%%%%@/       #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#
'    (&*,,,,,,,,,,,,,,,,%%*,,,,,,,,,,,,,,,,,,,,/@(,,,*&#     ,&&%%%%%%@/       #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#
'    (&*,,,,,,,,,,,,,,,,%%*,,,,,,,,,,,,,,,,,,,,/@(,,,*&#     ,&&%%%%%%@/       #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&&@@/          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       *%%%%%%%%%%%%%
'  .*(#*,,,,,,,,,,,,,,*(#(,,,,,,,,,,,,,,,,,,,,,/@(,,,,,(@*   ,&&%%%%%%@/       #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&@&#,          (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       /@@&##########
'  ,@(,,,,,,,,,,,,,,,,(@(,,,,,,,,,,,,,,,,,,,,,,/@@@@#,,(@*   ,&&%%%%&%.        #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&@#            (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       /@@#
'  ,@(,,,,,,,,,,,,,,,,(@(,,,,,,,,,,,,,,,,,,,,,,/@@@@@@@@@%/  ,&&%%%%@%         #@&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&@#            (@%%%%%%@#    ,((%@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       /@@&((((((((((
'  ,@(,,,,,,,,,,,,,,,*(&/,,,,,,,,,,,,,,,,,,,,,,/@@@@@@@@@@@@@@@&%%%%@%       *@@&&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&@#            (@%%%%%%@#  ,&@@@@@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       /@@@&&&&&&&&&&
'  ,@(,,,,,,,,,,,,,,*&%,,,,,,,,,,,,,,,,,,,,,,,,/@#//%@@@@@@@@@@@@@&%@%       *@@&&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&@#            (@%%%%%%@# /&@@@@@@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       /@@#
'  ,@(,,,,,,,,,,,,,,*&%,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,/%@@@@@@@@@@@@&*.     *@@&&&&&&&&&&&&&@%./@@&&&&&&&&&&&&&@#            (@%%%%%%@@@@@@@@@@@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       /@@%**********
'  ,@(,,,,,,,,,,,,,,*&%,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,%%.(@@@@@@@@@@@@@/  *@@&&&&&&&&&&&@@/  /@@&&&&&&&&&&&&&@#            (@%%%%%%@@@@@@@&,/@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#       /@@@@@@@@@@@@@
'  ,@(,,,,,,,,,,,,,#@/,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,/((,,&@&&@@@@@@@@@@@@@@&&&&&&&&&&&@@/,&@&&&&&&&&&&&&&&&@#            (@%%%%%%@&//*    /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%#
'  *&(,,,,,,,,,,,,,#@/,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,,/@/,&&%%%%@@&@@@@@@@@@@&&&&&&&&&&@@/,&@&&&&&&&&&&&&&&&@#            (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*%(
' #&*,,,,,,,,,,,,,,#@/,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,,/@/,&&%%%%@% .,,#@@@@@@&&&&&&&&&&@@/,&@&&&&&&&&&&&&&&&@#            (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
' #&*,,,,,,,,,,,,*&#,,,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,,/%(/&&%%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&&&&&&&&&&&@#            (@&%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
' #&*,,,,,,,,,,,,*&#,,,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,,,,#@@&%%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&&&&&&&&&@@*           ,&@@@@@%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
' #%*,,,,,,,,,,,,*&#,,,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,,,,#@@&%%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&&&&&&&&&@@*          *#@@@@@@%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
' #&*,,,,,,,,,,,#&*,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,,,,#@@&%%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&&&&&&&&&@@*        /@@@@@@@@@%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
' #&*,,,,,,,,,,,#&*,,,,,,,,,,,,,,,,,,,,,,,,,,,,/@(,,,,,,,,,,*(@&%%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&@@@@@&&&@@*      .(&@@@@@@&%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
' #&*,,,,,,,,,,,#&*,,,,,,,,,,,,,,,,,,,,,,,,,,,,/%#/,,,,,,,,,,/&&%%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&@@@@@@@@@@@(,   ,#@@@@@@@@@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
' #&*,,,,,,,,,/&#*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&*,,,,,,,,,/&&%%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&@@@@@@@@@@@@&&@@@@@@@@%.#@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'@(,,,,,,,,,,,/@(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&*,,,,,,,,,/&@&%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&@@@@@@@@@@@@@@@@@@@@@*  (@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'@(,,,,,,,,,,,/@(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&*,,,,,,,,,/&@@%%%@%       *@@&&&&&&&&&&&@@/,&@&&&&&&&&&&&&&@@@@@@@@@@@@@@@@@@%%%%%%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'@(,,,,,,,,,,(#(*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&*,,,,,,,,,/&@@%%%@%       *@@&&&&&&&&&&&@@@@@&&&&&&&&&&&&&&@@@@@@@@@@@@@@@@@@@@@@&%@#       /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'@#//////////&%*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#&*,,,,,,,,*(@@@%%%@%       *@@&&&&&&&&&&&@@@@@&&&&&&&&&&&@@@@@@@@@@%*.(%%@@@@@@@@@@@@%,,,    /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'............%@&&&&&&&&&&&&&&&&&&&&/,,,,,,,,,,,,,#&*,,,,,,,,*/@@@@&%@%       *@@&&&&&&&&&&&@@@@@&&&&&&&&&&&@@@@@@@@(.      ...#@@@@@@@@@@@@&&%./@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,(@*
'          ./(/                    *(((((((((((((&@#((((((((((((#&@&@%       *@@&&&&&&&&&&&@@@@@@@@@@@@@@@@@@@@@@&(,          (%.,((%@@@@@@@@@@@@%/,,,,,,,,,,,,,,,,,,,,,,,,,,,*(((.
'          *@*                                   (&.            .%# #@@/  /@@@@@@@@@@&&&&&@@@@@@(       #@@@@@@@*                      *@@@@@@@@@@%,,,,,,,,,,,,,,,,,,,,,,,,,,,*&(
'          .*****/(#########(.                   ,*             .%#                 *********%%.     /%@@@@@@@#                            ****#@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,*&(
'                           .#%%%%%,                              *@*    .,,,,,                    /@@@@@@@@&@#                                /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,*&(
'                                                                 *@&&&&#,.....           (&&&&&&&&&@@@@@@@@&@#                                /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,*&(
'                                                                                              *%@@@@@@@%/                                     /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,*&(
'                                                                                             ,&@@@@@@#                                        /@/,,,,,,,,,,,,,,,,,,,,,,,,,,,,*&(
'                                                                                          .(&@@@@@@@*                                         /@(///////////////#############%@(
'                                                                                         #@@@@@@@&(

' #END
' ################################################################################################################################################################

