Welcome, Guest
You have to register before you can post on our site.

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 485
» Latest member: zenevan
» Forum threads: 2,804
» Forum posts: 26,452

Full Statistics

Latest Threads
Merry X-Mas 2024!!
Forum: General Discussion
Last Post: Pete
6 minutes ago
» Replies: 6
» Views: 62
What do you guys like to ...
Forum: General Discussion
Last Post: Pete
18 minutes ago
» Replies: 21
» Views: 433
Space Ship Game
Forum: Works in Progress
Last Post: bplus
4 hours ago
» Replies: 1
» Views: 20
Printing to image handle
Forum: Utilities
Last Post: bplus
5 hours ago
» Replies: 1
» Views: 52
SaucerZap
Forum: QBJS, BAM, and Other BASICs
Last Post: bplus
Today, 04:50 AM
» Replies: 8
» Views: 107
Ascii Christmas Tree
Forum: Christmas Code
Last Post: SierraKen
Yesterday, 09:21 PM
» Replies: 4
» Views: 193
How to Color Mask?
Forum: Help Me!
Last Post: James D Jarvis
Yesterday, 09:19 PM
» Replies: 0
» Views: 29
GNU C++ Compiler error
Forum: Help Me!
Last Post: Kernelpanic
Yesterday, 08:28 PM
» Replies: 54
» Views: 1,370
Raspberry OS
Forum: Help Me!
Last Post: DSMan195276
Yesterday, 06:59 PM
» Replies: 11
» Views: 316
micro(A)v11
Forum: QBJS, BAM, and Other BASICs
Last Post: JRace
Yesterday, 05:21 PM
» Replies: 109
» Views: 5,115

 
  Air Hockey - Dark Theme
Posted by: bplus - 12-25-2023, 09:35 AM - Forum: Games - Replies (6)

For Danilin, vince and Pete Smile

Code: (Select All)
Option _Explicit
'Air Hockey v2-1.bas for QB64
' Started in QB64 Walter fork version (B+=MGA) 2017-09-05
' The first version was a direct translation from SmallBASIC,
' Now v2.0 add some more graphic image handling, try new things.
' 2020-03-11 v2-1 (QB64 v1.4 now) cleanup some code:
' Fix _MOUSEINPUT block too newbie ;)
' Fix flat spots on strikers how long have they been there?
' Increase frames per sec and slow puck speed for less double images.
' Oh that sped up the AI player! Nice.
' Do start shots to the side instead of directly at goal. MUCH BETTER!
' Update opening screen with this info. Now pause the puck at start.
' Ran OPTION _EXPLICIT and found a type-O that has been 0 all this time!

' v2020-03-23 Dark Theme as suggested by Danlin also fix fill circle with color
' also lighten color around the puck, oh fix the rest of the _rgb to rgb32.

Randomize Timer
Const xmax = 1200, ymax = 700 'screen dimensions
Screen _NewImage(xmax, ymax, 32)
_Title "Air Hockey v2020-03-23 Dark Theme"
_Delay .25
_ScreenMove _Middle

Const pr = 16 '              puck radius
Const pr2 = 2 * pr '         puck diameter = bumper width = radius of strikers
Const tl = xmax '            table length
Const tw = tl / 2 '          table width
Const tw13 = .3333 * tw \ 1 'goal end point
Const tw23 = .6667 * tw \ 1 'goal end point
Const speed = 15 '           puck speed also see _limit in main loop
Const midC = 316 '           (tl - 2 * pr2) \ 4 + pr2   'mid line of computer's sin field
Const rangeC = 252 '         316 - 252 = 64 (bumper + pr2)  316 + 252 = 568 (mid screen - pr2)

Common Shared f&, table&, computer, player, s$, tx, px, py, pa, psx, psy, c1, csx, csy, strkr&

f& = _LoadFont("C:\Windows\Fonts\arial.ttf", 25) ' arial normal style  if you have windows
_Font f& '                                         arial is pretty common if you don't have Windows

table& = _NewImage(xmax, tw, 32)
_Dest table&
drawTable

strkr& = _NewImage(2 * pr2 + 1, 2 * pr2 + 1, 32) ' more space to avoid right and bottom flat edges
_Dest strkr&
striker pr2, pr2

_Dest 0 '                                                    Opening screen
cp 7, "Air Hockey, first to score 21 goals wins!"
cp 9, "Player you will be defending the goal on the right (a black slot)."
cp 10, "Your goal is on the left, defended by the computer."
cp 12, "The puck will be started going up and down in the middle of"
cp 13, "the screen at slight angle towards a randomly selected goal."
cp 16, "Press any when ready..."
Sleep
_Delay 1
_MouseHide
Cls
updateScore
_PutImage (0, 0), table&, 0
drawComputerStriker
While _MouseInput: Wend
psx = _MouseX: psy = _MouseY
drawPlayerStriker
initball
While player < 21 And computer < 21 '        play until someone scores 21
    Cls
    updateScore
    _PutImage (0, 0), table&, 0
    drawComputerStriker
    While _MouseInput: Wend
    psx = _MouseX: psy = _MouseY
    drawPlayerStriker
    drawPuck
    _Display
    _Limit 60 '<<<<<<<<<<<<<  slow down, speeed up as needed for good game
Wend
If computer > player Then '                                    last report
    s$ = "Game Won by Computer."
    tx = 450
Else
    s$ = "Game Won by Player!"
    tx = 470
End If
Color _RGB32(200, 240, 140)
_PrintString (tx, tw + 30), s$
_Display
_Delay 3

Sub initball 'toss puck out to side slightly angled to one goal or the other
    Dim pao
    px = tl / 2: py = tw / 2: pao = _Pi(1 / 10) * Rnd
    puck px, py
    _Display
    _Delay .3
    If Rnd < .5 Then pa = _Pi(.5) Else pa = _Pi(1.5)
    If Rnd < .5 Then pa = pa + pao Else pa = pa - pao
End Sub

Sub updateScore
    Color _RGB32(40, 255, 255)
    s$ = "Computer: " + Str$(computer) + Space$(67) + "Player: " + Str$(player)
    _PrintString (200, tw + 30), s$
End Sub

Sub drawTable
    Dim i, shade
    For i = 0 To pr2 Step 4
        shade = 64 + i / pr2 * 100
        Color _RGB32(shade, shade, shade)
        Line (i, i)-(tl - i, tw - i), , BF
    Next
    Line (pr2, pr2)-(tl - pr2, tw - pr2), _RGB32(190, 230, 255), BF 'field
    Line (pr2, pr2)-(tl - pr2, tw - pr2), _RGB32(50, 0, 50), BF 'field
    Line (pr, tw13)-(pr2, tw23), _RGB32(60, 60, 60), BF
    Line (tl - pr2, tw13)-(tl - pr, tw23), _RGB32(60, 60, 60), BF
    Line (tl \ 2 - 1, pr2)-(tl \ 2 + 1, tw - pr2), _RGB32(128, 128, 128), BF
End Sub

Sub drawPlayerStriker
    If psx - pr2 < tl / 2 Then psx = tl / 2 + pr2
    If psx + pr2 > tl - pr2 Then psx = tl - 2 * pr2
    If psy - pr2 < pr2 Then psy = 2 * pr2
    If psy + pr2 > tw - pr2 Then psy = tw - 2 * pr2
    _PutImage (psx - pr2, psy - pr2), strkr&, 0
End Sub

Sub drawComputerStriker
    c1 = c1 + _Pi(1 / 80)
    csx = midC + rangeC * Sin(c1)
    If px > csx Then csy = py + pr2 * 1.5 * Sin(c1)
    If csy - pr2 < pr2 Then csy = 2 * pr2
    If csy + pr2 > tw - pr2 Then csy = tw - 2 * pr2
    _PutImage (csx - pr2, csy - pr2), strkr&, 0
End Sub

Sub drawPuck
    'update ball x, y and see if hit anything
    Dim i, shade
    px = px + speed * Cos(pa)
    py = py + speed * Sin(pa)

    If px - pr < pr2 Then
        If tw13 < py - pr And py + pr < tw23 Then 'through computer slot, player scores
            player = player + 1
            Cls
            updateScore
            drawTable
            striker csx, csy
            striker psx, psy
            puck pr, py
            For i = 0 To pr Step 4
                shade = 64 + i / pr2 * 100
                Color _RGB32(shade, shade, shade)
                Line (i, tw13)-(pr, tw23), , BF ' wow tw13 has been 0
            Next
            snd 1200, 200
            snd 2200, 300
            _Display
            initball
            _Delay .5
            Exit Sub
        Else
            snd 2600, 8
            pa = _Pi(1) - pa
            px = pr2 + pr
        End If
    End If

    If px + pr > tl - pr2 Then
        If tw13 < py - pr And py + pr < tw23 Then
            computer = computer + 1
            Cls
            updateScore
            drawTable
            striker csx, csy
            striker psx, psy
            puck tl - pr, py
            For i = 0 To pr Step 4
                shade = 64 + i / pr2 * 100
                Color _RGB32(shade, shade, shade)
                Line (tl - pr, tw13)-(tl - i, tw23), , BF 't13 again!
            Next
            snd 2200, 300
            snd 1200, 200
            _Display
            initball
            _Delay .5
            Exit Sub
        Else
            snd 2600, 5
            pa = _Pi(1) - pa
            px = tl - pr2 - pr
        End If
    End If

    If py - pr < pr2 Then ' hit top boundry
        snd 2600, 8
        pa = -pa
        py = pr2 + pr
    End If

    If py + pr > tw - pr2 Then ' hit bottom boundry
        snd 2600, 8
        pa = -pa
        py = tw - pr2 - pr
    End If

    If Sqr((px - psx) ^ 2 + (py - psy) ^ 2) < (pr + pr2) Then 'contact player striker
        pa = _Atan2(py - psy, px - psx)
        'boost puck away
        px = px + .5 * speed * Cos(pa)
        py = py + .5 * speed * Sin(pa)
        snd 2200, 4
    End If
    If Sqr((px - csx) ^ 2 + (py - csy) ^ 2) < (pr + pr2) Then 'contact computer striker
        pa = _Atan2(py - csy, px - csx)
        'boost puck away
        px = px + .5 * speed * Cos(pa)
        py = py + .5 * speed * Sin(pa)
        snd 2200, 4
    End If
    puck px, py ' here it is!
End Sub

Sub puck (x, y)
    fillcirc x, y, pr, _RGB32(160, 160, 160)
    fillcirc x, y, pr - 4, _RGB32(190, 100, 0)
End Sub

Sub striker (x, y)
    Dim i, shade
    For i = pr2 To pr Step -1
        shade = 164 - 90 * Sin(i * _Pi(2) / pr)
        fillcirc x, y, i, _RGB32(shade, shade, shade)
    Next
    For i = pr To 0 Step -1
        shade = 185 + 70 * (pr - i) / pr
        fillcirc x, y, i, _RGB32(shade, shade, shade)
    Next
End Sub

'Steve McNeil's  copied from his forum   note: Radius is too common a name
Sub fillcirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long)
    Dim subRadius As Long, RadiusError As Long
    Dim X As Long, Y As Long

    subRadius = Abs(R)
    RadiusError = -subRadius
    X = subRadius
    Y = 0

    If subRadius = 0 Then PSet (CX, CY), C: Exit Sub

    ' Draw the middle span here so we don't draw it twice in the main loop,
    ' which would be a problem with blending turned on.
    Line (CX - X, CY)-(CX + X, CY), C, BF

    While X > Y
        RadiusError = RadiusError + Y * 2 + 1
        If RadiusError >= 0 Then
            If X <> Y + 1 Then
                Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
                Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
        Y = Y + 1
        Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
        Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
    Wend
End Sub

Sub snd (frq, dur)
    Sound frq / 2.2, dur * .01
End Sub

Sub cp (lineNum, s$)
    Dim x, y
    '1200 pixels / 85 characters = 14.11 pixels/char wide
    '700 pixels / 28 lines = 18.42 pixels / char high
    x = (xmax - 11 * Len(s$)) \ 2
    y = lineNum * 25
    _PrintString (x, y), s$
End Sub

Dang did this game get faster???
   

Print this item

  Profile Pong
Posted by: bplus - 12-25-2023, 09:24 AM - Forum: Games - No Replies

Code: (Select All)
Option _Explicit
_Title "Profile Pong 3-0" ' b+ 2023-02-01 started inspired by Rosy game at RCBasic
' 2023-02-05 3-0 Starting with version 2-4 fixed for Proper serving, I redid both paddle shapes to
'circle fills and cleaned up code to that including colsolidting Paddle Collision code.

'                       Rules of Profile Ping Pong (now in effect):
' Ping Pong Legal Service:
' The ball must be struck so the ball first bounces on the server's side and then the
' opponent's side. Version 2-4

' On your return you must clear net and not bounce again on your side of the table.
' Opponent may or may not chooses to wait for bounce.
' Opponent should not attempt to return a ball clearly not going to hit his side of table,
' to win a point. Version 2-2 and above AI will not attempt a return until players serve or
' return hits its side of table.

Const Xmax = 1200, Ymax = 700 '     screen size
Const PaddleR = 44, BallR = 5 '     radii
Const TableL = 100, TableR = 1100 ' table ends
Const TableY = Ymax - 80 '          table height from top screen
Const NetY = TableY - 40 '          net height from top screen
Const NetL = 598 '                  net left side
Const NetR = 602 '                  net right side
Const Gravity = .1 '                just about right drop
Const BallSpeed = 8 '               for ball speed
Const Player = 1 '                  for scoring properly
Const Computer = 2 '                need to know who hit ball last
Const Server = 3 '                  track serve hits right side first

Dim Shared As Long Table '                background image handle
Dim Shared As Long PlayerX, PlayerY '     locating
Dim Shared As Long ComputerX, ComputerY
Dim Shared As Long BallX, BallY
Dim Shared As Double BallDX, BallDY '     ball direction
Dim Shared As Long LastToHit '            scoring helper flags
Dim Shared As Long TouchL, TouchR

Screen _NewImage(Xmax, Ymax, 32) '                                               Game QB Settings
_ScreenMove 60, 20 '                <<< you may want different, for my screen it is almost middle
_MouseHide

Dim As Long mx, my, parkComputerY ' locating
Dim As Long playerPt, computerPt '  scoring and scoring helpers
Dim As Double snd '                 freq for making sounds
Dim As String s '                   temp string for scores
_Font _LoadFont("Arial.ttf", 32) '  everyone has Arial right?

MakeTableImg '                         draw table image
ComputerX = TableL - PaddleR - 3 '     as of now, ComputerX doesnt ever change x position
parkComputerY = TableY - 3 * PaddleR ' keeping ComputerY paddle above board out of trouble

Do '
    ' Serve similar to Rosy Demo Video, just drops ball on human side of table
    TouchL = 0: TouchR = 0: LastToHit = Server: ComputerY = parkComputerY '       resets for serve
    BallY = 550: BallX = TableR - BallR: BallDX = 0: BallDY = 0

    Do '                                            one round of play loop until a point is scored
        Cls
        _PutImage , Table, 0 '                                                 background table...
        _PrintString (100, 100), "Computer:" + Str$(computerPt) '                     score update
        s = "Player:" + Str$(playerPt)
        _PrintString (1100 - _PrintWidth(s), 100), s

        '                                                                            Player Paddle
        While _MouseInput: Wend '                   poll mouse status
        mx = _MouseX: my = _MouseY
        If mx > NetR + PaddleR Then '               keep player on his side of table
            PlayerX = mx: PlayerY = my
        Else
            PlayerY = my '                          OK let me move in Y direction at least
        End If
        FCirc PlayerX, PlayerY, PaddleR, &HFF00BB00
        MakeEyes PlayerX, PlayerY

        ' Computer x is constant behind table edge y adjusted to ballY             Computer Paddle
        If TouchL = 0 Then
            If BallX < NetL Then ComputerY = BallY - 3 * PaddleR Else ComputerY = parkComputerY
        Else
            If BallY > NetY - 3 * PaddleR Then
                ComputerY = BallY + 20 '         this is pure guess!!! Thank you gravity!
            Else
                ComputerY = BallY + 5 '          so upper round part of paddle hits ball upward
            End If
        End If
        FCirc ComputerX, ComputerY, PaddleR, &HFFBB4400
        MakeEyes ComputerX, ComputerY

        '                                                                            ball handling
        BallDY = BallDY + Gravity '                     gravity weighs ball down going up or down
        BallX = BallX + BallDX: BallY = BallY + BallDY

        PaddleCollisions ' check if ball collides with either opponents paddle

        ' collide net   vertical part
        If BallY + BallR > NetY Then
            If BallDX > 0 Then ' going towards player
                If BallX > NetL - BallR And BallX < NetR + BallR Then GoSub player: Exit Do
            ElseIf BallDX < 0 Then ' going towards computer
                If BallX > NetL - BallR And BallX < NetR + BallR Then GoSub computer: Exit Do
            End If
        End If

        ' collide table very important to hit table on opponents side on returns
        If (((BallY + BallR) > TableY) And (BallX > TableL)) And (BallX < TableR) Then
            Sound 600, .25
            If (BallX - BallR) < NetL Then ' table left
                If LastToHit = Server Then GoSub computer: Exit Do
                If TouchL = 0 And BallDX > 0 Then
                    GoSub player: Exit Do
                Else
                    TouchL = TouchL + 1
                    If TouchL > 1 Then GoSub player: Exit Do
                End If
            ElseIf (BallX - BallR) > NetR Then 'table right
                If TouchR = 0 And BallDX < 0 Then ' ball headed left
                    'If server struck ball correctly on his side first then else computer Pt
                    If LastToHit = Server Then LastToHit = Player Else GoSub computer: Exit Do
                Else ' player can only loose round if not serving
                    TouchR = TouchR + 1
                    If TouchR > 1 And LastToHit <> Server Then GoSub computer: Exit Do
                End If
            End If
            BallY = TableY - BallR: BallDY = -BallDY
        End If

        ' collide floor ?   I doubt this ever happens
        If BallY + BallR > Ymax Then
            If LastToHit = Server Then
                GoSub computer: Exit Do
            End If
            If BallX + BallR < TableL Then
                If (TouchL > 0 And LastToHit = Player) Or (LastToHit = Computer) Then
                    GoSub player
                Else
                    GoSub computer
                End If
            ElseIf BallX - BallR > TableR Then
                If (TouchR > 0 And LastToHit = Computer) Or (LastToHit = Player) Then
                    GoSub computer
                Else
                    GoSub player
                End If
            End If
            Exit Do
        End If

        ' collide left boundry
        If BallX - BallR < 0 Then
            If LastToHit = Server Then GoSub computer: Exit Do
            If (TouchL > 0) And (LastToHit = Player) Then
                GoSub player
            ElseIf LastToHit = Computer Then
                GoSub player
            ElseIf ((TouchL = 0) And (LastToHit = Player)) Then ' player hit to far
                GoSub computer
            End If
            Exit Do
        ElseIf BallX + BallR > Xmax Then 'collide right boundary
            If LastToHit = Server Then GoSub computer: Exit Do
            If (TouchR > 0 And LastToHit = Computer) Or (LastToHit = Player) Then
                GoSub computer
            Else ' computer hit too far
                GoSub player
            End If
            Exit Do
        End If
        FCirc BallX, BallY, BallR, &HFFFFFFFF
        _Display
        _Limit 60
    Loop
    _PrintString (100, 100), "Computer:" + Str$(computerPt) '                     score update
    s = "Player:" + Str$(playerPt)
    _PrintString (1100 - _PrintWidth(s), 100), s
    _Display
    If computerPt >= 21 Then
        _MessageBox "Sorry,", "The Computer out did you this game."
        computerPt = 0: playerPt = 0
    ElseIf playerPt >= 21 Then
        _MessageBox "Congrats!", "You beat the Computer."
        computerPt = 0: playerPt = 0
    Else
        _Delay 1.3
    End If
Loop
End

player:
For snd = 400 To 800 Step 20: Sound snd, .5: Next '                  player pt
playerPt = playerPt + 1
FArc PlayerX, PlayerY, 23, 1, _D2R(55), _D2R(125), &HFFFF0000 '           smile
FArc ComputerX, ComputerY + 46, 23, 1, _D2R(240), _D2R(300), &HFFFF0000 ' frown
FCirc BallX, BallY, BallR, &HFFFFFFFF
_Display
_Delay 1
Return
computer:
For snd = 800 To 400 Step -20: Sound snd, .5: Next '               computer pt
computerPt = computerPt + 1
FArc ComputerX, ComputerY, 23, 1, _D2R(55), _D2R(125), &HFFFF0000 '       smile
FArc PlayerX, PlayerY + 46, 23, 1, _D2R(240), _D2R(300), &HFFFF0000 '     frown
FCirc BallX, BallY, BallR, &HFFFFFFFF
_Display
_Delay 1
Return

' ============================================================================= Code for this app
Sub PaddleCollisions '                         handles collisions with both paddles
    Dim a##, x&, y&, collided&
    x& = PlayerX: y& = PlayerY '               check Players Paddle
    GoSub checkCollision
    If collided& Then
        If LastToHit <> Server Then LastToHit = Player
        TouchR = 0
    End If
    x& = ComputerX: y& = ComputerY '           check Computers Paddle
    GoSub checkCollision
    If collided& Then LastToHit = Computer: TouchL = 0
    Exit Sub
    checkCollision: ' distance between circle origins of ball and paddle
    If Sqr((x& - BallX) ^ 2 + (y& - BallY) ^ 2) < BallR + PaddleR Then
        Sound 230, 1 '                         paddle strike
        a## = _Atan2(BallY - y&, BallX - x&) ' redirect ball
        BallDX = BallSpeed * Cos(a##)
        BallDY = BallSpeed * Sin(a##)
        BallX = BallX + 2 * BallDX '           boost ball innew direction
        BallY = BallY + 2 * BallDY
        collided& = -1 '                       flag collided
    Else
        collided& = 0 '                        flag not collided
    End If
    Return
End Sub

Sub MakeEyes (x, y)
    Dim a
    FCirc x - 10, y, 8, &HFFFFFFFF '                              eyeballs
    FCirc x + 10, y, 8, &HFFFFFFFF
    a = _Atan2(BallY - y, BallX - (x - 10)) '                     for left iris pointing at ball
    FCirc x - 10 + 2.5 * Cos(a), y + 2.5 * Sin(a), 3, &HFF000000
    a = _Atan2(BallY - y, BallX - (x + 10)) '                     for right iris pointing at ball
    FCirc x + 10 + 2.5 * Cos(a), y + 2.5 * Sin(a), 3, &HFF000000
    Line (x - 3, y + 23)-Step(6, 2), &HFFFF0000, BF '             for mouth
End Sub

Sub MakeTableImg
    Table = _NewImage(_Width, _Height, 32)
    Color , &HFF000088: Cls
    _Dest Table
    Line (TableL, TableY)-(TableR, TableY + 20), &HFF008855, BF
    Line (TableL + 40, TableY + 20)-(TableL + 50, _Height), &HFF444444, BF
    Line (TableR - 50, TableY + 20)-(TableR - 40, _Height), &HFF444444, BF
    Line (NetL, NetY)-(NetR, TableY), &HFF444444, BF
    Line (NetL + 1, NetY)-(NetR - 1, NetY + 20), &HFFFFFFFF, BF
    _Dest 0
End Sub

'2023-02-04 Fill Arc draw an arc with thickness, tested in Profile Pong 3-0
' this sub needs sub FCirc(CX As Long, CY As Long, R As Long, C As _Unsigned Long) for dots
Sub FArc (x, y, r, thickness, RadianStart, RadianStop, c As _Unsigned Long)
    Dim al, a
    'x, y origin of arc, r = radius, thickness is radius of dots, c = color
    'RadianStart is first angle clockwise from due East = 0 in Radians
    ' arc will start drawing there and clockwise until RadianStop angle reached
    If RadianStop < RadianStart Then
        FArc x, y, r, thickness, RadianStart, _Pi(2), c
        FArc x, y, r, 0, thickness, RadianStop, c
    Else
        al = _Pi * r * r * (RadianStop - RadianStart) / _Pi(2)
        For a = RadianStart To RadianStop Step 1 / al
            FCirc x + r * Cos(a), y + r * Sin(a), thickness, c
        Next
    End If
End Sub
' =========================================================================== from my Code Library
Sub FCirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long) ' Gold standard for Circle Fill
    Dim Radius As Long, RadiusError As Long
    Dim X As Long, Y As Long
    Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
    If Radius = 0 Then PSet (CX, CY), C: Exit Sub
    Line (CX - X, CY)-(CX + X, CY), C, BF
    While X > Y
        RadiusError = RadiusError + Y * 2 + 1
        If RadiusError >= 0 Then
            If X <> Y + 1 Then
                Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
                Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
            End If
            X = X - 1
            RadiusError = RadiusError - X * 2
        End If
        Y = Y + 1
        Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
        Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
    Wend
End Sub

   

Print this item

Thumbs Up Idea for Tutorial
Posted by: bplus - 12-25-2023, 08:44 AM - Forum: Learning Resources and Archives - Replies (3)

Hi @TerryRitchie

Have you considered Debug Topic for your Tutorial?

+1 BTW I just searched it for that topic and love all the new graphics you have in Contents!

Print this item

  Codebreaker
Posted by: SMcNeill - 12-24-2023, 11:02 AM - Forum: SMcNeill - No Replies

Code: (Select All)
$Color:32
Dim Shared f, f1, lastsolved, guess(10), guesses
Screen _NewImage(640, 480, 32)
Randomize Timer
f = _LoadFont("courbd.ttf", 64, "monospace")
f1 = _LoadFont("courbd.ttf", 32, "monospace")
Color Black, none

n$ = GetNum(5)

Do
    Cls
    guess$ = "": wheel = 0: Xon = 0
    For i = 1 To Len(n$)
        guess$ = guess$ + _Trim$(Str$(guess(i)))
    Next
    DrawLock guess$, n$

    While _MouseInput: wheel = wheel + _MouseWheel: Wend
    X = _MouseX: y = _MouseY: mb = _MouseButton(1): mb2 = _MouseButton(2)

    If y > 105 And y < 195 Then 'we're on the proper spot to be in the combination area
        Xon = Int((X - 105) / (300 / Len(n$)) + 1) 'this is the tumbler we're on
        If Xon > 0 And Xon <= Len(n$) Then
            If wheel Then
                guess(Xon) = guess(Xon) + wheel
            End If
            If mb And Not oldmouse Then guess(Xon) = guess(Xon) + 1
            If mb2 And Not oldmouse2 Then guess(Xon) = guess(Xon) - 1
            If guess(Xon) > 9 Then guess(Xon) = 0
            If guess(Xon) < 0 Then guess(Xon) = 9
        End If
    End If
    If mb And Not oldmouse Then
        If y > 205 And y < 295 Then 'in the solved row
            If X > 105 And X < 395 Then 'in the Last row
                lastsolved = 0: guesses = guesses + 1
                For i = 1 To Len(n$)
                    If Asc(guess$, i) = Asc(n$, i) Then lastsolved = lastsolved + 1
                Next
            End If
        End If
    End If
    oldmouse = mb: oldmouse2 = mb2
    _Display
    _Limit 15
Loop Until lastsolved = Len(n$)
_AutoDisplay
Cls
Color White
_Font f1
Print "YAY!  You got it in"; guesses; "tries!"
Sleep
System

Function GetNum$ (size)
    For i = 1 To size
        n = Int(Rnd * 11)
        tempGetNum$ = tempGetNum$ + _Trim$(Str$(n))
    Next
    GetNum$ = tempGetNum$
End Function

Sub DrawLock (guess$, num$)
    _Font f
    Color Black, none
    size = Len(num$)
    s = 300 / size
    Line (100, 100)-(400, 200), SlateGray, BF
    Line (100, 100)-(400, 300), SlateGray, BF
    Line (105, 105)-(395, 195), LightGray, BF
    Line (105, 205)-(395, 295), Green, BF
    For i = i To (size - 1)
        Line (100 + i * s, 100)-Step(5, 100), SlateGray, BF
        t$ = Mid$(guess$, i, 1)
        left = 105 + (s - _FontWidth) / 2
        _PrintString (left + (i - 1) * s, 150 - _FontHeight / 2), t$
    Next
    t$ = Mid$(guess$, i, 1)
    _PrintString (left + (i - 1) * s, 150 - _FontHeight / 2), t$
    _Font f1
    _PrintString (110, 210), "Last:" + _Trim$(Str$(lastsolved))
    _PrintString (110, 250), "Guesses:" + _Trim$(Str$(guesses))
End Sub


Another old work, found and shared here once again.  Some of you old timers who used to lurk at the old forums before they disappeared might remember seeing this already.

Quote:A little game I was playing around with making to just give my little grand-niece something to waste time on when she comes to visit.

This should be easy enough to figure out:
Use the mouse wheel or the buttons to increase or decrease the values of a tumbler.
Click in the green area to make a guess and see how many numbers you got correct out of your attempt.

Match the actual combination and win!


At this point, this only runs through the creation and puzzle process a single time, for a single 5-digit combination lock. I suppose all it really needs at this point to become a "replayable game" is to offer an option to select difficulty (it can generate anywhere up to 9-digit locks for increased difficulty), and then an option to replay/quit again afterwards -- but that's a simple enough mod for another day, when I have a little more free time again.

Now the question is: How fast can someone solve these type of puzzles? What's the best strategy to get to the win in the least possible number of moves normally?

Randomly type in a number and you *could* get it in one guess, but where's the logic in that?

Type in each number one at a time, click to check, and you're guaranteed to get the solution in 10 * wordlength guesses.

Type in all 5 digits the same, and you can eliminate a whole number from your guess each time. (For example guess five zeros 00000, find out that there's no matches, you've now dropped the possible data pool down to only using numbers 1 to 9. Do it for each of the numbers from 0 to 10, and you've eliminated half the puzzle in 10 guesses, as your 5 digit number can't hold 10 different values!)

Now that I've came up with the little problem to create the puzzles, I'm now left pondering on what might be the best solution for an AI to use to guess the puzzle in the fewest amount of tries possible. Anyone have any thoughts on a surefire Code Breaker solution routine with the fewest possible attempts usually?

I may end up trying to incorporate some sort of competition where a player tries to compete against the computer to shoot for the answer first, so various ideas for AI attempts could be written into the game as different opponents to try your luck against. Suzy might just try random numbers. Jane might do the meticulous one by one approach. Fred might do an elimination approach to solving. Anybody have any other methods to attempt for an AI?

Like most things on my "To Do List", adding AI to this was something which I never got around to doing. LOL!

Print this item

  Steve's Lesson on Tic-Tac-Toe
Posted by: SMcNeill - 12-24-2023, 10:49 AM - Forum: SMcNeill - No Replies

Browsing and moving things into the new subforum for games, I stumbled across this little tutorial I did ages ago, and I thought I'd share it here once again.   This will teach you how to become an unbeatable player at Tic-Tac-Toe -- guaranteed!

Code: (Select All)
$Color:32

Dim Shared ViewScreen As Long, Font As Long

ViewScreen = _NewImage(640, 480, 32)
Screen ViewScreen
$Resize:On
fontsize = 20
Font = _LoadFont("courbd.ttf", fontsize, "monospace")
_Font Font

Do
Resizer
Lessons num
k = _KeyHit
Select Case k
Case 27 'escape
System
Case 19200 'previous
If num > 0 Then num = num - 1
Case 18432 'up font
If fontsize < 128 Then
fontsize = fontsize + 2
temp = _LoadFont("courbd.ttf", fontsize, "monospace")
_Font temp
_FreeFont Font
Font = temp
End If
Case 20480 'down font
If fontsize > 6 Then
fontsize = fontsize - 2
temp = _LoadFont("courbd.ttf", fontsize, "monospace")
_Font temp
_FreeFont Font
Font = temp
End If
Case 19712 'next
If num < 123 Then num = num + 1
End Select
_Limit 30
_Display
Loop



Sub Lessons (num)
Static DoOnce
Select Case num
Case 0 'just print
Cls
WordWrap "Hello World."
WordWrap "This is Steve's Tuturial on Tic-Tac-Toe!"
Print
WordWrap "Press <RIGHT ARROW> to move forward in the lessons."
Case 1
Cls
WordWrap "How many places can one start at in Tic-Tac-Toe? Let's look at the board below to find out!"
DrawBoard ""
Case 2
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 1"
DrawBoard "X"
Case 3
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 2"
DrawBoard ".X"
Case 4
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 3"
DrawBoard "..X"
Case 5
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 4"
DrawBoard "...X"
Case 6
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 5"
DrawBoard "....X"
Case 7
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 6"
DrawBoard ".....X"
Case 8
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 7"
DrawBoard "......X"
Case 9
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 8"
DrawBoard ".......X"
Case 10
Cls
WordWrap "First, there's the top-right corner, which makes one spot, and we'll count as we go from there."
WordWrap "Current count = 9"
DrawBoard "........X"
Case 11
Cls
WordWrap "There's only 9 spots on a Tic-Tac-Toe board, so our first move has to be in one of those nine spaces!"
Print
WordWrap "BUT..."
Print
WordWrap "Tic-Tac-Toe is a game of SYMMETRY. There's really only THREE positions to consider in the game."
Case 12
Cls
WordWrap "The outer corners."
DrawBoard "X.X...X.X"
Case 13
Cls
WordWrap "The middle edges."
DrawBoard ".X.X.X.X."
Case 14
Cls
WordWrap "And the center of it all -- the center!"
DrawBoard "....X...."
Case 15
Cls
WordWrap "So, to start this tuturial out, let's start with X in one of the OUTER CORNERS."
DrawBoard "X"
Case 16
Cls
WordWrap "Now, O has 8 different places they can move. Let's look at all those possible moves, and I'll show you what X's next move should be."
WordWrap "First, O goes right beside X... X then goes to their opposite free corner."
DrawBoard "XO....X.."
Case 17
Cls
WordWrap "This is a losing position for O, as here would be the next 2 moves played out:"
WordWrap "O blocks the win, X takes the middle..."
DrawBoard "XO.OX.X.."
Case 18
Cls
WordWrap "So what if O would have went to the far corner instead?"
WordWrap "X then goes to their diagional free corner."
DrawBoard "X.O.....X"
Case 19
Cls
WordWrap "O is now forced to block in the center, and X then blocks O."
WordWrap "Guess who just lost?"
DrawBoard "X.O.O.X.X"
Case 20
Cls
WordWrap "So, let's just continue on around the edges from there. What happens when O is placed in the right middle edge? Remember what I said about SYMMETRY before?"
WordWrap "Doesn't this set up look just like what we saw previously with O in the top middle?"
DrawBoard "X....OX.."
Case 21
Cls
WordWrap "Yep. Same predictible results. O loses."
DrawBoard "X..OXOX.."
Case 22
Cls
WordWrap "And if O were to move down to the next open position, it's another outer corner."
WordWrap "X, once again, just takes the opposite corner for the win."
DrawBoard "X.....X.O"
Case 23
Cls
WordWrap "Next space on the rotation would be the bottom middle... Which is just like the other two middles we've seen so far..."
WordWrap "Can you see why O loses here?"
DrawBoard "X.X....O."
Case 24
Cls
WordWrap "And around we go, with another corner, which plays like the other corners for O.."
DrawBoard "X.X...O.."
Case 25
Cls
WordWrap "And the last move around the edge is right below X, in the left middle... Which results in... The same as before!"
DrawBoard "X.XO....."
Case 26
Cls
WordWrap "So, as we've seen, if X starts on an outer edge, if the next move by O is on an outside tile, then X wins!"
WordWrap "The whole game is decided by the first move!"
WordWrap "O's *ONLY* possible move is into the middle, which will force a draw unless someone is honestly just REALLY stupid!"
DrawBoard "X...O...."
Case 27
Cls
WordWrap "So in conclusion here: IF X starts with any OUTSIDE CORNER, the *ONLY* place O can go -- without losing -- is to the center."
WordWrap "*ALL* other moves lets X manulate the board for a guaranteed win."
DrawBoard "X...O...."
Case 28
Cls
WordWrap "And, since the game is SYMMETRICAL, as we've seen so far, the *EXACT* same pattern plays out if X starts in *ANY* of the OUTER CORNERS."
WordWrap "IF X takes an OUTER CORNER, the *ONLY* move O can make is to take the center, or lose."
Case 29
Cls
WordWrap "Which then leads to the question: What if X takes the center on their first move?"
DrawBoard "....X...."
Case 30
Cls
WordWrap "O basically only has two choices here: OUTER EDGE or MIDDLE EDGE. Let's look at them both, starting with O taking a MIDDLE EDGE..."
WordWrap "O takes a middle, X takes an outer beside it."
DrawBoard ".OX.X...."
Case 31
Cls
WordWrap "O has to block, and now X can take the other corner. Guess who just won?"
DrawBoard ".OX.X.O.X"
Case 32
Cls
WordWrap "So if X takes the center, and O takes a middle, then X wins! First move determines the game once again."
WordWrap "IF O doesn't want to lose, all they can do is take an OUTER CORNER when X takes the center."
DrawBoard "O...X...."
Case 33
Cls
WordWrap "So that means the only possible place left to talk about is if X starts in a MIDDLE EDGE position."
DrawBoard ".X......."
Case 34
Cls
WordWrap "And honestly, there's not to much to say about this position, except *DON'T*."
WordWrap "There's *NO* move that O can make which guarantees X a win if they start off with an OUTER MIDDLE tile."
WordWrap "Unless someone just plays terribly on purpose, these games will end in a draw."
WordWrap "ONLY start there if you're playing with an elementry grade child."
Case 35
Cls
WordWrap "So, to basically sum up:"
WordWrap "Tic-Tac-Toe is basically a game that is won in the first move."
WordWrap "X's two possible moves are OUTER EDGE and CENTER."
WordWrap "O's counters are CENTER and OUTER EDGE."
WordWrap "Remember those two things, and you have become almost unbeatable at Tic-Tac-Toe. (Unless just pure exhaustion or disinterest causes you to make a mismove after that...)"
Case 36
Cls
WordWrap "AND THAT'S ALL THERE IS TO TIC-TAC-TOE!"
Case 37
Cls
Color &HFFFF0000, 0
WordWrap "X's two possible starting moves are OUTER EDGE and CENTER."
WordWrap "O's counters are CENTER and OUTER EDGE."
Case 38
System
End Select
End Sub


Sub DrawBoard (text$)
Static board, boardfont
yStart = CsrLin * _FontHeight(Font)
d = _Dest: s = _Source
If board = 0 Then
board = _NewImage(600, 600, 32)
boardfont = _LoadFont("courbd.ttf", 196, "monospace")
End If
_Dest board: _Source board
Cls
Line (190, 0)-Step(20, 600), Yellow, BF
Line (390, 0)-Step(20, 600), Yellow, BF
Line (0, 190)-Step(600, 20), Yellow, BF
Line (0, 390)-Step(600, 20), Yellow, BF
_Font boardfont
For i = 0 To 8
temp$ = Mid$(text$, i + 1, 1)
Select Case temp$
Case "X", "x"
Color Red, 0
_PrintString ((i Mod 3) * 200 + 40, (i \ 3) * 200 + 10), "X"
Case "O", "o", "0"
Color Green, 0
_PrintString ((i Mod 3) * 200 + 40, (i \ 3) * 200 + 10), "O"
End Select
Next
_Dest d: _Source s
_PutImage (0, yStart)-(_Width, _Height), board
End Sub


Sub WordWrap (text As String)
Dim BreakPoint As String
BreakPoint = ",./- ;:!" 'I consider all these to be valid breakpoints. If you want something else, change them.
w = _Width
pw = _PrintWidth(text)
x = Pos(0): y = CsrLin
If _PixelSize <> 0 Then x = x * _FontWidth
firstlinewidth = w - x + 1
If pw <= firstlinewidth Then
Print text
Else
'first find the natural length of the line
For i = 1 To Len(text)
p = _PrintWidth(Left$(text, i))
If p > firstlinewidth Then Exit For
Next
lineend = i - 1
t$ = RTrim$(Left$(text, lineend)) 'at most, our line can't be any longer than what fits the screen.
For i = lineend To 1 Step -1
If InStr(BreakPoint, Mid$(text, i, 1)) Then lineend = i: Exit For
Next
Print Left$(text, lineend)
WordWrap LTrim$(Mid$(text, lineend + 1))
End If
End Sub

Sub Speak (text$)
text$ = Chr$(34) + "(pause), " + text$ + Chr$(34)
Open "temp.ps1" For Output As #1
Print #1, "Add-Type -AssemblyName System.Speech; "
Print #1, "$voice = New-Object System.Speech.Synthesis.SpeechSynthesizer; "
Print #1, "$voice.SelectVoice(" + Chr$(34) + "Microsoft Zira Desktop" + Chr$(34) + "); "
Print #1, "$voice.Speak(" + text$ + "); "
Close #1
Shell _Hide "powershell ./temp.ps1"
End Sub

Sub Resizer
If _Resize Then
_Delay .5
x = _ResizeWidth
y = _ResizeHeight
temp = _NewImage(x, y, 32)
Screen temp
_FreeImage ViewScreen
ViewScreen = temp
_Font Font
End If
End Sub


The start of a simple little Tic-Tac-Toe Tutorial. Folks have been writing little games for this in QB64, so I thought I'd take a moment to help showcase the logic of the game.

Text is resizable and auto-formats, with the up and down arrow keys.
Right arrows move forward a page/lesson.
Left arrows move back, so you can compare, if needed, to see what happened.
Escape, of course, lets you quit at any time.

Try it out and let me know how it looks. Wink


Side note: Screen is also fully resizable, and auto-formats itself to adjust to the size you make it.

Print this item

  Round Table Flip by johannhowitzer
Posted by: SMcNeill - 12-24-2023, 10:37 AM - Forum: Games - No Replies

Game made for the 2021 QB64 Game Jam Contest: https://itch.io/jam/qb64-game-jam/rate/918922

Quote:Now, notes about the code!

The core mechanics of gravity and magnetism created some really confusing interplay that took me several days to untangle to this point, and there are still a few minor things that don't work quite correctly, but you can solve the puzzles just fine. Due to all the wrangling of the core mechanics, I was only able to create four levels, and the levels aren't super inspired. They just show off the mechanics and leave it at that.

It's just shy of 3000 lines of code, although I imported some key systems from my main game project for this, namely the input handling and keybinding system (woo, gamepad support, if that's your bag!), the sprite sheet slicer, and my own custom font system. My code is extremely well-organized, so if you want to repurpose those systems, feel free, it shouldn't be hard. If you wave a cookie in my face, I might yank one out for you myself.

You can also create your own levels if you want, go to sub load_stage and you'll see walls of text strings where I did my level building. You can replace these levels with your own, or expand the level count if you like by changing total_stages in the header. Due to my hurry to complete the jam, some stuff like level names, character names, etc are in random places in the code - some in the header, some in the last couple subs. Down to the wire, I had to stop being so organized and start doing stuff quickly.

The logic of the core gravity and magnetism mechanics can be seen in sub move_entity. I decided to create a reflexive tree of nodes, where each node records its entity index and parent node. First I swept each node's neighbors to add more nodes, until I ran out of nodes to look at; then I iterated through removing disqualified nodes until no more got removed. For moving a character, this just starts with the character and immediately moves whatever was found to be connected; for gravity, since it has to check every entity in the stage, the move_entity routine simply marks the entities as moving, then when I've checked everything, every marked entity moves.

The game will only accept inputs when nothing is moving, and I put in a 3-frame slide so you can see things move and fall; this means it's easy to move too fast and have the game not take your inputs. But since it's turn-based, you can't be screwed over by this, and since the game has a rewind mechanic (up to 100 moves can be undone), I didn't have to exhaustively look for potential softlocks. Which are everywhere in this, the good old push-block-into-corner will get you stuck in lots of places.

I made a couple of the assets, but nearly everything is from opengameart and freesound. You are completely free to reuse whatever you like.

Let me know what you think!

   


.zip   Round Table Flip.zip (Size: 2.3 MB / Downloads: 34)

Code: (Select All)
Const true = -1
Const false = 0
Const magnet = 1

' ===== Screen =====

Const screenw = 800
Const screenh = 600
Const boardw = 255
Const boardh = 255
Const block_size = 31
Dim Shared stagew As Integer
Dim Shared stageh As Integer

Const turn_max = 100

Dim Shared fullscreen As _Unsigned Long
fullscreen = _NewImage(screenw, screenh, 32)
Screen fullscreen

Do: Loop Until _ScreenExists = true
_Title "Round Table Flip"

_Source fullscreen ' Prevent handles from ever being null
_Dest fullscreen

Type coordinate_dec
x As Double
y As Double
End Type
Type coordinate_int
x As Long
y As Long
End Type

Dim Shared hue(6) As _Unsigned Long
Const hue_transparent = 0
hue(hue_transparent) = _RGBA32(0, 0, 0, 0)
Const hue_black = 1
hue(hue_black) = _RGBA32(0, 0, 0, 255)
Const hue_white = 2
hue(hue_white) = _RGBA32(255, 255, 255, 255)
Const hue_red = 3
hue(hue_red) = _RGBA32(255, 0, 0, 255) ' Only used for enemy health bars
Const hue_green = 4
hue(hue_green) = _RGBA32(0, 255, 0, 255) ' Only used in debug menu
Const hue_dkblue = 5
hue(hue_dkblue) = _RGBA32(0, 74, 149, 223) ' Windows
Const hue_ltblue = 6
hue(hue_ltblue) = _RGBA32(0, 124, 249, 255)

Dim Shared camera As coordinate_int
Dim Shared move_offset As coordinate_dec

' --- Entity types ---

Const e_warrior = 1
Const e_archer = 2
Const e_wizard = 3

Const e_crate = 4
Const e_crate_metal = 5

Const entity_specs = 5

' --- Entity flags ---

Const shield_down = 1 ' Warrior shield
Const shield_up = 2

Const summoned = 3 ' Wizard summoned crate

' --- Block types ---

Const b_empty = 0

Const b_grass = 1
Const b_ground = 2
Const b_ground_metal = 3
Const b_spikes = 4
Const b_plate = 5
Const b_lever_l = 6
Const b_lever_r = 7
Const b_door_shut = 8
Const b_door_open = 9
Const b_telepad = 10
Const b_goal = 11

Const block_specs = 11

' --- Sprites ---

Const spr_warrior_d_l = 1
Const spr_warrior_d_r = 2
Const spr_warrior_u_l = 3
Const spr_warrior_u_r = 4
Const spr_archer_d_l = 5
Const spr_archer_d_r = 6
Const spr_archer_u_l = 7
Const spr_archer_u_r = 8
Const spr_wizard_d_l = 9
Const spr_wizard_d_r = 10
Const spr_wizard_u_l = 11
Const spr_wizard_u_r = 12

Const spr_grass = 13
Const spr_ground = 14
Const spr_ground_metal = 15
Const spr_crate = 16
Const spr_crate_metal = 17
Const spr_spikes = 18
Const spr_plate = 19
Const spr_lever_l = 20
Const spr_lever_r = 21
Const spr_door_shut = 22
Const spr_door_open = 23
Const spr_telepad = 24
Const spr_goal = 25
Const spr_magnetic = 26
Const spr_summoned = 27

Const spr_control = 28
Const spr_shield = 29
Const spr_psychic = 30

Const sprite_total = 30

Dim Shared sprite_ref(sprite_total) As Integer
' Use constants above as index to get sprite number for image files

' --- Sound effects ---

Const sfx_menu_move = 1 ' Move menu cursor
Const sfx_menu_confirm = 2 ' Confirm menu selection

Const sfx_crush = 3
Const sfx_lever = 4

Const sfx_wind = 29
Const sfx_music = 30

Const sfx_total = 30

Dim Shared sfx(sfx_total, 100) As _Unsigned Long

Call load_sfx

' ===== Images =====

Dim Shared block_image As _Unsigned Long
Dim Shared background As _Unsigned Long

Dim Shared fade_image As _Unsigned Long

Dim Shared store_screen As _Unsigned Long ' Anytime screen state should be stored
Dim Shared assembly As _Unsigned Long ' For assembling anything that can be done all at once
store_screen = _NewImage(screenw, screenh, 32)
assembly = _NewImage(screenw, screenh, 32)
Call load_images

' ===== Block data =====

Type block_spec_structure
solid As _Byte ' true if blocks movement and gravity
metal As _Byte ' false = nonmetallic, true = metallic, magnet = magnetic
sprite As Integer
End Type
Dim Shared block_spec(block_specs) As block_spec_structure
Call set_block_spec_data

Type block_structure
spec As _Byte ' index of block type, named constants
switch As coordinate_int ' Which switch is responsible for toggling this block
flag As Integer ' special status, such as wizard conjured block, named constants
metal As _Byte ' false = nonmetallic, true = metallic, magnet = magnetic
End Type
Dim Shared block(turn_max, boardw, boardh) As block_structure

' ===== Entity data =====

Type entity_spec_structure
name As String
metal As _Byte ' on spawn, false = nonmetallic, true = metallic, magnet = magnetic, includes warrior boots
flip As coordinate_int ' true if sprite has flipped versions on that axis
sprite As Integer
End Type
Dim Shared entity_spec(entity_specs) As entity_spec_structure
Call set_entity_spec_data

Type entity_structure
spec As _Byte ' index of entity_spec
pos As coordinate_int
moving As _Byte ' used by move_entity to mark entity as moving in the current step
flip As coordinate_int ' visual, flip.x is <-1 1>, flip.y is ^-1 1v
flag As Integer ' special status, such as wizard conjured block, named constants
metal As _Byte ' false = nonmetallic, true = metallic, magnet = magnetic
End Type
Dim Shared entity(turn_max, 1000) As entity_structure
Dim Shared entity_count(turn_max) As Integer

' ===== Movement chunking nodes =====

Const node_push = 1
Const node_magnet = 2
Const node_support = 3

Type node_structure
i As Integer ' index of node entity
parent As Integer ' parent node
connect As _Byte ' type of node connection via constants above
End Type
Dim Shared node(1000) As node_structure
Dim Shared node_count As Integer
Dim Shared c_node As Integer ' node currently being examined

' ===== Sprites =====

Type sprite_structure
pos As coordinate_int ' position in sprite sheet
size As coordinate_int ' size of sprite in sheet
size_draw As coordinate_int ' size of sprite when displayed - equal to size.xy if no stretch
frames As Integer ' sprite's frames of animation
fpf As _Byte ' Frame counter ticks per animation frame (0 defaults to 1)
' A value of 2 will allow 2 ticks to go by before the next animation frame
offset As coordinate_int ' display position relative to hitbox position
hb_size As coordinate_int ' size of hitbox, to be copied to entity_spec().size.xy after parse
image As _Unsigned Long ' Handle of sprite sheet
End Type

Dim Shared sprite_count As Integer
Dim Shared sprite(1000) As sprite_structure

' ===== Fonts =====

Type font_structure
image As _Unsigned Long
pos As coordinate_int
h As Integer
w As Integer
End Type

' Alignment in font calls
Const left_align = 0
Const right_align = 1
Const center_align = 2

Const fonts = 2
Dim Shared font(fonts, 255) As font_structure

' Font references
Const f_font = 1 ' Fixed-width, half size of blocks
Const f_font_gold = 2
Call initialize_font(f_font, "data\font.png")
Call initialize_font(f_font_gold, "data\fontgold.png")

Const cursor_offset = 40 ' Distance f_setback_blue's cursor moves left from text, when pointing at it

' ===== Menu options =====

Dim Shared option_restart_confirm As _Byte ' true means instant restart will ask for confirmation
Dim Shared option_sound As _Byte ' true is on
Dim Shared option_sensitivity As _Byte ' Amount a stick needs to be tilted before input is registered

option_restart_confirm = false
option_sound = false
option_sensitivity = 7

' ===== Input handling =====

Dim Shared dev_keyboard As _Byte ' Store device index, to be re-checked whenever inputs are involved
Dim Shared dev_gamepad As _Byte
Const keyboard = 1
Const gamepad = 2

' References for press function and hold array
Const armor_key = 1
Const shield_key = 2
Const jump_key = 3
Const arrow_key = 4
Const alchemy_key = 5
Const block_key = 6
Const action_key = 7
Const gravity_key = 8
Const up_key = 9
Const down_key = 10
Const left_key = 11
Const right_key = 12
Const switch_key = 13
Const rewind_key = 14
Const restart_key = 15
Const ok_key = 16
Const cancel_key = 17
Const enter_key = 18
Const esc_key = 19

' Input reference and binding data
Const keybind_count = 19 ' Number of gameplay functions, including enter and esc
kc = keybind_count
Dim Shared keybind_overlap(kc, kc) As _Byte ' True if slots can have the same key
Dim Shared keybind_name$(kc) ' Name of keybind slots - "WEAPON, UP" etc

Dim Shared key_name$(512, 2) ' Names of keyboard keys and gamepad buttons
Dim Shared keybind(kc, 2) As Integer ' Contains key code assigned by player
Dim Shared keybind_edit(kc, 2) As Integer ' Used during keybind menu, overwrites keybind() on exit
Dim Shared keybind_default(kc, 2) As Integer ' Defaults in case player wants to reset

Call set_key_data

Dim Shared keybind_error(kc, 2) As Single ' for flashing red when attempting to bind a duplicate

' Input tracking flags
Dim Shared press(kc) As _Byte ' What was pressed this frame
Dim Shared hold(kc) As _Byte ' What was pressed last frame

' ===== Directions =====

Const up = 1
Const right = 2
Const down = 3
Const left = 4
Dim Shared delta(4) As coordinate_int
delta(up).x = 0: delta(up).y = -1
delta(right).x = 1: delta(right).y = 0
delta(down).x = 0: delta(down).y = 1
delta(left).x = -1: delta(left).y = 0

' ===== Sorting =====

Type sort_structure
s_index As Integer ' Reference to array being sorted
s_value As Single ' Value being used for sorting
End Type

Dim Shared sorting(1000) As sort_structure ' Before sort
Dim Shared sorting_count As Integer
Dim Shared sorted(1000) As sort_structure ' After sort
Dim Shared sorted_count As Integer

' ===== Misc data =====

Dim Shared current_stage As _Byte
Const total_stages = 4
Dim Shared stage_name$(total_stages)
stage_name$(1) = "QUEST"
stage_name$(2) = "LOCKS"
stage_name$(3) = "REUNION"
stage_name$(4) = "DESCENT"

Dim Shared turn As Integer ' gameplay is turn-based, this value increments each time player makes a move
' full stage data is copied into the new turn, then altered
' rewinding simply decrements this value, which auto-reverts to old state
Dim Shared last_turn As Integer ' turn cannot rewind into this
Dim Shared turn_wrap As _Byte ' rewind won't wrap around to turn_max until this is set to true

Dim Shared gravity(turn_max) As _Byte ' uses directional constants above - up, down

Dim Shared control As _Byte ' Which character is being controlled

Call parse_sprites(block_image)
Call set_sprite_ref





' ===== Main =====

Call load_settings

Call set_hold(true)
Call title
System





' ===== Routine index =====

'--- Core ---
'title
'play_stage
'option_menu
'keybind_menu

'--- Important ---
'f new_press
'update_inputs
'set_press
'set_hold
'update_gravity
'update_camera
'spawn
'despawn
'move_entity
' move_marked_entities
' add_node
' remove_node
' entity_has_node
' f magnetized
'use_lever
'detect_devices
'press_any_key
'set_default_keybinds
'f confirm
'load_stage

'--- Conversion ---
'f plus_limit
'f toggle
'f half
'f inthalf
'f sq
'f wrap
'f rounding
'f round_up
'f mod_dec
'f text_width
'f text_contains
'f trim$
'sort

'--- Shorthand ---
'f get_dir
'f on_board

'--- Loading ---
'load_settings
'save_settings
'load_images
'load_sfx
'load_stage
'initialize_font
'parse_sprites
'f scan_text
'f scan_right
'f scan_down
'scan_error

'--- Display ---
'draw_background
'draw_stage
' draw_sprite
'glass_fonts
'round_rect
'f text_tag_replace
'f text_replace
'capture_screen
'restore_screen
'clear_image
'overlay
'play_sound
' play_menu_move
' play_menu_confirm

'--- Initial data ---
'set_key_data
'set_sprite_ref
'set_block_spec_data





' --------------------------
' ========== Core ==========
' --------------------------

Sub title

' 0-Start
' 1-Options
' 2-Quit

Do
c = 0
Call set_hold(true)

' Title screen
Do
_Limit 60
Call clear_image(fullscreen, hue(hue_dkblue))
Call draw_background

d& = fullscreen

Call glass_fonts("ROUND TABLE FLIP", f_font_gold, fullscreen, inthalf(screenw), 120, center_align)

' Menu options
f = f_font
x1 = 350: y1 = 270: h = Int(font(f, 0).h * 1.2)
Call glass_fonts("Start", f, fullscreen, inthalf(screenw), y1, left_align)
Call glass_fonts("Options", f, fullscreen, inthalf(screenw), y1 + h, left_align)
Call glass_fonts("Quit", f, fullscreen, inthalf(screenw), y1 + (h * 2), left_align)

' Cursor
Call glass_fonts("@", f_font, fullscreen, x1 - cursor_offset, y1 + (c * h), left_align)

Call glass_fonts("By johannhowitzer, for the 2021 QB64 Game Jam", f, fullscreen, inthalf(screenw), 500, center_align)

_Display

If new_press(up_key) = true And new_press(down_key) = false Then
c = wrap(c - 1, 0, 2)
ElseIf new_press(down_key) = true And new_press(up_key) = false Then
c = wrap(c + 1, 0, 2)
End If

If new_press(esc_key) = true Or new_press(cancel_key) = true Then
c = 2
End If

If new_press(enter_key) = true Or new_press(ok_key) = true Then

If c = 0 Then ' Start
Call play_menu_confirm
Exit Do

ElseIf c = 1 Then ' Options
Call play_menu_confirm
Call option_menu
c = 0

ElseIf c = 2 Then ' Quit
Exit Sub
End If

End If

Call update_inputs
Loop

Do
Call load_stage(current_stage)
q = play_stage
Loop Until q = true
Loop

End Sub


Function play_stage

play_stage = false

turn = 1
last_turn = 1
turn_wrap = false
moved = true
d_move = false
action = false

Call set_hold(true)

Do
_Limit 60
If _SndPlaying(sfx(sfx_music, 1)) = false Then play_sound (sfx_music)

If moved = true Then
' Copy state

dt = wrap(turn + 1, 1, turn_max)
If dt < turn Then turn_wrap = true

For y = 1 To boardh
For x = 1 To boardw
block(dt, x, y).spec = block(turn, x, y).spec
block(dt, x, y).switch.x = block(turn, x, y).switch.x
block(dt, x, y).switch.y = block(turn, x, y).switch.y
block(dt, x, y).flag = block(turn, x, y).flag
block(dt, x, y).metal = block(turn, x, y).metal
Next x
Next y
For n = 1 To entity_count(turn)
entity(dt, n).spec = entity(turn, n).spec
entity(dt, n).pos.x = entity(turn, n).pos.x
entity(dt, n).pos.y = entity(turn, n).pos.y
entity(dt, n).moving = entity(turn, n).moving
entity(dt, n).flip.x = entity(turn, n).flip.x
entity(dt, n).flip.y = entity(turn, n).flip.y
entity(dt, n).flag = entity(turn, n).flag
entity(dt, n).metal = entity(turn, n).metal
Next n
entity_count(dt) = entity_count(turn)
gravity(dt) = gravity(turn)

' Increment turn

turn = dt
last_turn = dt

' Process what happened this turn

If d_move = left Or d_move = right Then
For n = 1 To entity_count(turn)
entity(turn, n).moving = false
Next n
Call move_entity(control, d_move, false)
Call move_marked_entities(d_move)

entity(turn, control).flip.x = delta(d_move).x
End If

Select Case action
Case armor_key
entity(turn, e_warrior).metal = toggle(entity(turn, e_warrior).metal, true, magnet)

Case shield_key
entity(turn, e_warrior).flag = toggle(entity(turn, e_warrior).flag, shield_down, shield_up)

Case jump_key
dx = get_dir(entity(turn, e_archer).flip.x, 0)
dy = get_dir(0, -delta(gravity(turn)).y)

For n = 1 To entity_count(turn)
entity(turn, n).moving = false
Next n
Call move_entity(control, dy, false)
Call move_marked_entities(dy)

For n = 1 To entity_count(turn)
entity(turn, n).moving = false
Next n
Call move_entity(control, dy, true)
Call move_marked_entities(dy)

For n = 1 To entity_count(turn)
entity(turn, n).moving = false
Next n
Call move_entity(control, dx, true)
Call move_marked_entities(dx)

Case arrow_key
d = entity(turn, e_archer).flip.x
px = entity(turn, e_archer).pos.x
lx = px + d
ly = entity(turn, e_archer).pos.y

Do While on_board(lx, ly) = true
s = block(turn, lx, ly).spec

' Found a lever, use it
If s = b_lever_l Or s = b_lever_r Then
Call use_lever(lx, ly)
Exit Do
End If

' Hit a solid block
If block_spec(s).solid = true Then Exit Do

' Hit an entity
For n = 1 To entity_count(turn)
If entity(turn, n).pos.x = lx And entity(turn, n).pos.y = ly Then Exit Do
Next n

lx = lx + d
Loop

For p = 1 To 5
_Limit 60
Call draw_stage
For x_p = px To lx Step Sgn(lx - px)
x1 = ((block_size + 1) * x_p) - camera.x
y1 = ((block_size + 1) * ly) - camera.y
If x_p <> px Then Call draw_sprite(sprite_ref(spr_psychic), x1, y1)
Next x_p
_Display
Next p

Case alchemy_key
For n = 1 To entity_count(turn)
If entity(turn, n).flag = summoned Then
entity(turn, n).spec = toggle(entity(turn, n).spec, e_crate, e_crate_metal)
entity(turn, n).metal = toggle(entity(turn, n).metal, true, false)
End If
Next n

Case block_key
dx = entity(turn, e_wizard).pos.x + entity(turn, e_wizard).flip.x
dy = entity(turn, e_wizard).pos.y

If on_board(dx, dy) = true Then
blocked = false
If block_spec(block(turn, dx, dy).spec).solid = true Then blocked = true
For n = 1 To entity_count(turn)
If entity(turn, n).pos.x = dx And entity(turn, n).pos.y = dy Then blocked = true
Next n

If blocked = false Then
' Remove any existing summoned block
For n = entity_count(turn) To 1 Step -1
If entity(turn, n).flag = summoned Then Call despawn(n)
Next n

Call spawn(e_crate, dx, dy, 1, summoned)
End If
End If

Case action_key
ex = entity(turn, control).pos.x
ey = entity(turn, control).pos.y
s = block(turn, ex, ey).spec

' Lever
If s = b_lever_l Or s = b_lever_r Then Call use_lever(ex, ey)

' *** Telepad

End Select

If reverse_gravity = true Then gravity(turn) = toggle(gravity(turn), up, down)
Call update_gravity
End If

Call update_camera

Call draw_stage
_Display

' Death check
d = false
For n = 1 To 3
dx = entity(turn, n).pos.x
dy = entity(turn, n).pos.y
For n1 = 4 To entity_count(turn)
If entity(turn, n1).pos.x = dx And entity(turn, n1).pos.y = dy Then
d = true
Exit For
End If
Next n1
Next n
If d = true Then
_SndPause (sfx(sfx_music, 1))
Call play_sound(sfx_crush)
Call play_sound(sfx_wind)
Do
_Limit 60
If _SndPlaying(sfx(sfx_wind, 1)) = false Then play_sound (sfx_wind)

Call draw_stage
Line (0, 0)-Step(screenw, screenh), _RGBA(255, 0, 0, 31), BF
_Display

If new_press(rewind_key) = true Then
dt = wrap(turn - 1, 1, turn_max)
If dt <> last_turn Then turn = dt
Call set_hold(true)
_SndStop (sfx(sfx_wind, 1))
Exit Do
End If

If new_press(restart_key) = true Then
c = true
If option_restart_confirm = true Then
c = confirm("Restart?", true)
End If
If c = true Then
_SndStop (sfx(sfx_wind, 1))
Exit Function
End If
End If

If new_press(esc_key) = true Then
Call play_menu_confirm
c = confirm("Quit?", false)
If c = true Then
play_stage = true
_SndStop (sfx(sfx_music, 1))
_SndStop (sfx(sfx_wind, 1))
Exit Function
End If
End If

Call update_inputs
Loop
End If

' Victory check
v = false
For n = 1 To 3
If block(turn, entity(turn, n).pos.x, entity(turn, n).pos.y).spec = b_goal Then v = true
Next n
If v = true Then
current_stage = current_stage + 1
If current_stage > total_stages Then
Call draw_background
Call glass_fonts("You completed the game!", f_font_gold, fullscreen, inthalf(screenw), 150, center_align)
Call glass_fonts("This week has been a lot of fun,", f_font, fullscreen, inthalf(screenw), 250, center_align)
Call glass_fonts("and I'm very happy to finish the jam.", f_font, fullscreen, inthalf(screenw), 300, center_align)
Call glass_fonts("Thanks for playing!", f_font, fullscreen, inthalf(screenw), 400, center_align)
Call press_any_key
current_stage = total_stages
End If
Call save_settings
Exit Function
End If

moved = false
For b = 1 To switch_key - 1
If new_press(b) = true Then moved = true
Next b

If new_press(rewind_key) = true Then
dt = wrap(turn - 1, 1, turn_max)
If dt > turn And turn_wrap = false Then z = false Else z = true
If dt <> last_turn And z = true Then turn = dt
End If

If new_press(switch_key) = true Then control = wrap(control + 1, 1, 3)

If new_press(gravity_key) = true Then reverse_gravity = true Else reverse_gravity = false

d_move = false
If new_press(left_key) = true And new_press(right_key) = false Then d_move = left
If new_press(right_key) = true And new_press(left_key) = false Then d_move = right

action = false
If new_press(action_key) = true Then action = action_key
If control = e_warrior And new_press(armor_key) = true Then action = armor_key
If control = e_warrior And new_press(shield_key) = true Then action = shield_key
If control = e_archer And new_press(jump_key) = true Then action = jump_key
If control = e_archer And new_press(arrow_key) = true Then action = arrow_key
If control = e_wizard And new_press(alchemy_key) = true Then action = alchemy_key
If control = e_wizard And new_press(block_key) = true Then action = block_key

If new_press(restart_key) = true Then
c = true
If option_restart_confirm = true Then
c = confirm("Restart?", true)
End If
If c = true Then Exit Function
End If

If new_press(esc_key) = true Then
Call play_menu_confirm
c = confirm("Quit?", false)
If c = true Then
play_stage = true
_SndStop (sfx(sfx_music, 1))
Exit Function
End If
End If

Call update_inputs
Loop

End Function


Sub option_menu

menu_restart_confirm = 0 ' ON-[OFF]
menu_sound = 1 ' [ON]-OFF
menu_reset = 2
menu_controls = 3
menu_exit = 4

Call set_hold(true)

d& = fullscreen

c = 0

Do
_Limit 60
Call clear_image(d&, hue(hue_black))
Call draw_background

' Menu options
f = f_font: a = left_align
x1 = 300: y1 = 270: h = Int(font(f, 0).h * 1.2)
Call glass_fonts("Restart confirmation", f, d&, x1, y1 + (h * menu_restart_confirm), a)
Call glass_fonts("Sound", f, d&, x1, y1 + (h * menu_sound), a)
Call glass_fonts("Reset progress", f, d&, x1, y1 + (h * menu_reset), a)
Call glass_fonts("Controls", f, d&, x1, y1 + (h * menu_controls), a)
Call glass_fonts("Done", f, d&, x1, y1 + (h * menu_exit), a)

' Option states
f = f_font
x2 = 520
rc$ = "OFF": sd$ = "OFF"
If option_restart_confirm = true Then rc$ = "ON"
If option_sound = true Then sd$ = "ON"

a = right_align
Call glass_fonts(rc$, f, d&, x2, y1 + (h * menu_restart_confirm), a)
Call glass_fonts(sd$, f, d&, x2, y1 + (h * menu_sound), a)

' Cursor
Call glass_fonts("@", f_font, d&, x1 - cursor_offset, y1 + (c * h), left_align)

_Display

' Input
x = 0: y = 0
If new_press(left_key) = true Then x = -1
If new_press(right_key) = true Or new_press(enter_key) = true Or new_press(ok_key) = true Then x = 1
If new_press(up_key) = true Then y = -1
If new_press(down_key) = true Then y = 1

s = false
If y <> 0 Then s = true
If x <> 0 And c <= menu_sound Then s = true
If s = true Then Call play_menu_move

c = wrap(c + y, 0, menu_exit)

If c = menu_restart_confirm Then option_restart_confirm = wrap(option_restart_confirm + x, true, false)
If c = menu_sound Then option_sound = wrap(option_sound + x, true, false)

If new_press(esc_key) = true Then
Call play_menu_confirm
Exit Do
End If
If new_press(enter_key) = true Or new_press(ok_key) = true Then
If c = menu_reset Then
Call play_menu_confirm
r = confirm("Really reset progress?", false)
If r = true Then current_stage = 1

ElseIf c = menu_controls Then
Call play_menu_confirm
Call keybind_menu

ElseIf c = menu_exit Then
Call play_menu_confirm
Exit Do
End If
End If

Call update_inputs
Loop

Call save_settings

End Sub


Sub keybind_menu

Call set_hold(true)

d& = fullscreen

x1 = 100: x2 = 343: x3 = 543 ' Three columns
y1 = 100 ' Top of column headers
f1 = f_font: f2 = f_font
h = font(f1, 0).h
w = 120 ' Width of a keybind setting display column

kc = keybind_count
menu_stick = kc + 1
menu_default = kc + 2
menu_exit = kc + 3
cx = 1: cy = 1

' Copy keybinds to editing array
For b = 1 To kc
keybind_edit(b, keyboard) = keybind(b, keyboard)
keybind_edit(b, gamepad) = keybind(b, gamepad)
keybind_error(b, keyboard) = 0
keybind_error(b, gamepad) = 0
Next b

Do
_Limit 60

' Red error flash decay
For b = 1 To kc
keybind_error(b, keyboard) = plus_limit(keybind_error(b, keyboard), -0.05, 0)
keybind_error(b, gamepad) = plus_limit(keybind_error(b, gamepad), -0.05, 0)
Next b

Call clear_image(d&, hue(hue_black))
Call draw_background

' Headers
Call glass_fonts("KEYBOARD", f1, d&, x2, y1, left_align)
Call glass_fonts("GAMEPAD", f1, d&, x3, y1, left_align)

' Enter/Esc grey frame
Call round_rect(x1 - 3, y1 + (h * enter_key) - 1, (x2 - x1) + w, (h - 1) * 2, d&, _RGBA32(255, 255, 255, 127), 1)

' Keybind slots
For n = 1 To kc
y2 = y1 + (n * h)

' Red error flash for attempted duplicate keybind
If keybind_error(n, keyboard) > 0 Then Call round_rect(x2 - 3, y2 - 1, w, h - 1, d&, _RGBA32(255, 0, 0, keybind_error(n, keyboard) * 255), 1)
If keybind_error(n, gamepad) > 0 Then Call round_rect(x3 - 3, y2 - 1, w, h - 1, d&, _RGBA32(255, 0, 0, keybind_error(n, gamepad) * 255), 1)

Call glass_fonts(keybind_name$(n), f1, d&, x1, y2, left_align)
Call glass_fonts(key_name$(keybind_edit(n, keyboard), keyboard), f2, d&, x2, y2, left_align)
If n < enter_key Then Call glass_fonts(key_name$(keybind_edit(n, gamepad), gamepad), f2, d&, x3, y2, left_align)
Next n

Call glass_fonts("ANALOG SENSITIVITY", f1, d&, x2, y1 + (h * menu_stick), left_align)
Call glass_fonts("RESET TO DEFAULT", f1, d&, x2, y1 + (h * menu_default), left_align)
Call glass_fonts("EXIT", f1, d&, x2, y1 + (h * menu_exit), left_align)

t$ = ""
Select Case cy
Case armor_key: t$ = "Lancelot: Turn your magnetic coat on or off."
Case shield_key: t$ = "Lancelot: Raise or lower your shield."
Case jump_key: t$ = "Percival: Jump forward."
Case arrow_key: t$ = "Percival: Interact with stuff from a distance."
Case alchemy_key: t$ = "Galahad: Switch your crate between wooden and metal."
Case block_key: t$ = "Galahad: Generate an artificial crate."
Case action_key: t$ = "Interact with stuff."
Case gravity_key: t$ = "Reverse the stage's gravity."
Case up_key: t$ = "For menus only."
Case down_key: t$ = "For menus only."
Case left_key: t$ = "Move left."
Case right_key: t$ = "Move right."
Case switch_key: t$ = "Select another character."
Case rewind_key: t$ = "Undo last move."
Case restart_key: t$ = "Restart the stage."
Case ok_key: t$ = "For menus only."
Case cancel_key: t$ = "For menus only."
End Select
Call glass_fonts(t$, f1, d&, inthalf(screenw), y1 + (h * (menu_exit + 2)), center_align)

' Bar for analog sensitivity
Line (x3, y1 + (h * menu_stick) - 2)-Step(w * 0.9, h - 1), hue(hue_dkblue), B
Line (x3 + 2, y1 + (h * menu_stick))-Step((w - 4) * (option_sensitivity * 0.1), h - 5), hue(hue_ltblue), BF

' Cursor
If cx = 1 Then Call glass_fonts("@", f1, d&, x2 - cursor_offset, y1 + (h * cy), left_align)
If cx = 2 Then Call glass_fonts("@", f1, d&, x3 - cursor_offset, y1 + (h * cy), left_align)
_Display

' Directional inputs
dx = 0: dy = 0
If new_press(left_key) = true And new_press(right_key) = false Then dx = -1
If new_press(right_key) = true And new_press(left_key) = false Then dx = 1
If new_press(up_key) = true And new_press(down_key) = false Then dy = -1
If new_press(down_key) = true And new_press(up_key) = false Then dy = 1

' Cursor movement sound
s = false
If dy <> 0 Then s = true
If dx <> 0 And cy < menu_default Then s = true
If s = true Then Call play_menu_move

' Cursor movement
cx = wrap(cx + dx, 1, 2)
Do
cy = wrap(cy + dy, 1, menu_exit)
Loop While cy = enter_key Or cy = esc_key ' Cursor skips over Enter and Esc
If cy > kc Then cx = 1

' Directional option changing
If cy = menu_stick Then option_sensitivity = wrap(option_sensitivity + dx, 1, 9)

' Exit
If new_press(esc_key) = true Or new_press(cancel_key) = true Then
Call play_menu_confirm
Exit Do
End If

' Handling enter/ok input
If dx = 0 And dy = 0 Then
If new_press(enter_key) = true Or new_press(ok_key) = true Then
If cy = menu_exit Then
Call play_menu_confirm
Exit Do

ElseIf cy = menu_default Then
Call play_menu_confirm
r = confirm("Reset to default?", false)
If r = true Then
Call set_default_keybinds
For b = 1 To kc
keybind_edit(b, keyboard) = keybind(b, keyboard)
keybind_edit(b, gamepad) = keybind(b, gamepad)
Next b
End If

ElseIf cy = menu_stick Then
Call play_menu_move
option_sensitivity = wrap(option_sensitivity + 1, 1, 9)

' Rebinding a key
ElseIf cy <= kc - 2 Then
Call detect_devices
For n = 1 To keybind_count
keybind_error(n, keyboard) = 0
keybind_error(n, gamepad) = 0
Next n
v = false

' Keyboard - fixed amount of buttons, with expected codes
If cx = 1 Then
Call play_menu_confirm
d = keyboard

' Draw blue behind selected keybind
Call round_rect(x2 - 3, y1 + (h * cy) - 1, 120, h - 1, d&, _RGBA32(0, 0, 255, 191), 1)
Call glass_fonts(key_name$(keybind_edit(cy, d), d), f2, d&, x2, y1 + (h * cy), left_align)

' Wait for empty keyboard inputs
Do
_Limit 60
_Display
e = true

z = _DeviceInput(dev_keyboard)
For b = 1 To _LastButton(dev_keyboard)
If _Button(b) = true Then e = false
Next b
Loop Until e = true

' Wait for valid keyboard input
Do
_Limit 60
_Display
If new_press(esc_key) = true Then Exit Do ' Cancel binding

z = _DeviceInput(dev_keyboard)
For b = 1 To _LastButton(dev_keyboard)
If _Button(b) = true And b <> 2 And b <> 29 Then
v = b
Exit Do
End If
Next b

Call update_inputs
Loop Until v <> false
End If

' Gamepad - variable amount of buttons and axes
If cx = 2 And dev_gamepad <> false Then
Call play_menu_confirm
d = gamepad
z = _DeviceInput(dev_gamepad)

' Draw blue behind selected keybind
Call round_rect(x3 - 3, y1 + (h * cy) - 3, 120, h - 1, d&, _RGBA32(0, 0, 255, 191), 1)
Call glass_fonts(key_name$(keybind_edit(cy, d), d), f2, d&, x3, y1 + (h * cy), left_align)

Call glass_fonts("Press ENTER to remove", f1, d&, x3, y1 + (h * (menu_exit + 1)), left_align)

' Wait for empty gamepad inputs
Do
_Limit 60
_Display
e = true

z = _DeviceInput(dev_gamepad)
For b = 1 To _LastButton(dev_gamepad)
If _Button(b) = true Then e = false
Next b
For a = 1 To _LastAxis(dev_gamepad)
If Abs(_Axis(a)) > (option_sensitivity * 0.1) Then e = false
Next a
Loop Until e = true

' Wait for valid gamepad input
Do
_Limit 60
_Display
If new_press(esc_key) = true Then Exit Do ' Cancel binding
If new_press(enter_key) = true Then ' Remove existing button
Call play_menu_confirm
keybind_edit(cy, d) = false
v = false
Exit Do
End If

z = _DeviceInput(dev_gamepad)
For b = 1 To _LastButton(dev_gamepad)
If _Button(b) = true Then
v = b
Exit Do
End If
Next b

For a = 1 To _LastAxis(dev_gamepad)
ax = _Axis(a)
If Abs(ax) > (option_sensitivity * 0.1) Then
v = a
If ax < 0 Then v = v + 100 Else v = v + 200
Exit Do
End If
Next a

Call update_inputs
Loop Until v <> false
End If

If v <> false Then
' Check for duplicates
dupe = false
For b = 1 To keybind_count
If b <> cy And keybind_edit(b, d) = v And keybind_overlap(cy, b) = false Then
dupe = true
keybind_error(b, d) = 1
End If
Next b

' No duplicate, set new keybind
If dupe = false Then
Call play_menu_confirm
keybind_edit(cy, d) = v
Else
Call play_sound(sfx_explosion)
End If
End If

Call set_press(true)
End If
End If
End If

Call update_inputs
Loop

' Copy new keybinds to keybind array
For b = 1 To kc
keybind(b, keyboard) = keybind_edit(b, keyboard)
keybind(b, gamepad) = keybind_edit(b, gamepad)
Next b

Call save_settings

End Sub





' -------------------------------
' ========== Important ==========
' -------------------------------

Function new_press (b)
new_press = false
If press(b) = true And hold(b) = false Then new_press = true
End Function


Sub update_inputs

Call detect_devices

For b = 1 To keybind_count
hold(b) = press(b)
press(b) = false

d = keyboard
If dev_keyboard <> false Then
z = _DeviceInput(dev_keyboard)
If _Button(keybind(b, d)) = true Then press(b) = true
End If

d = gamepad
If dev_gamepad <> false And keybind(b, d) <> false Then
z = _DeviceInput(dev_gamepad)

If keybind(b, d) < 100 Then ' Button
If _Button(keybind(b, d)) = true Then press(b) = true

' Stick handling:
' keybind() set to 101, 102 etc. is an assignment of stick 1, 2 etc. in the negative direction
' keybind() set to 201, 202 etc. is an assignment of stick 1, 2 etc. in the positive direction
ElseIf keybind(b, d) > 200 Then ' Stick positive
If _Axis(keybind(b, d) - 200) > option_sensitivity * 0.1 Then press(b) = true
Else ' Stick negative
If _Axis(keybind(b, d) - 100) < -option_sensitivity * 0.1 Then press(b) = true
End If
End If
Next b

End Sub


Sub set_press (p)
For b = 1 To keybind_count
press(b) = p
Next b
End Sub


Sub set_hold (p)
For b = 1 To keybind_count
hold(b) = p
Next b
End Sub


Sub update_gravity

Do
For n = 1 To entity_count(turn)
entity(turn, n).moving = false
Next n

' Mark all entities that can be moved by gravity
For n = 1 To entity_count(turn)
If entity(turn, n).moving = false Then Call move_entity(n, gravity(turn), false)
Next n

Call move_marked_entities(gravity(turn))

moved_any = false
For n = 1 To entity_count(turn)
If entity(turn, n).moving = true Then moved_any = true
Next n
Loop Until moved_any = false

End Sub


Sub update_camera

' Get camera destination
cx = ((block_size + 1) * entity(turn, control).pos.x) - inthalf(screenw)
cy = ((block_size + 1) * entity(turn, control).pos.y) - inthalf(screenh)

' Camera moves in the direction of that destination
camera.x = plus_limit(camera.x, round_up((cx - camera.x) * 0.3), cx)
camera.y = plus_limit(camera.y, round_up((cy - camera.y) * 0.3), cy)

End Sub


Sub spawn (i, x, y, f, flag)

entity_count(turn) = entity_count(turn) + 1
n = entity_count(turn)

entity(turn, n).spec = i
entity(turn, n).pos.x = x
entity(turn, n).pos.y = y
entity(turn, n).flip.x = f
entity(turn, n).flip.y = delta(gravity(turn)).y
entity(turn, n).flag = flag
entity(turn, n).metal = entity_spec(i).metal

End Sub


Sub despawn (d)

entity_count(turn) = entity_count(turn) - 1
For n = d To entity_count(turn)
entity(turn, n).spec = entity(turn, n + 1).spec
entity(turn, n).pos.x = entity(turn, n + 1).pos.x
entity(turn, n).pos.y = entity(turn, n + 1).pos.y
entity(turn, n).flip.x = entity(turn, n + 1).flip.x
entity(turn, n).flip.y = entity(turn, n + 1).flip.y
entity(turn, n).flag = entity(turn, n + 1).flag
entity(turn, n).metal = entity(turn, n + 1).metal
Next n

End Sub


Sub move_entity (i, m, jump)

node_count = 1
node(1).i = i
node(1).parent = true ' can never be removed via false parent index
c_node = 1

g = gravity(turn)

' Assemble chunk
Do
e = node(c_node).i
ex = entity(turn, e).pos.x
ey = entity(turn, e).pos.y

For n = 1 To entity_count(turn)
dx = entity(turn, n).pos.x - ex
dy = entity(turn, n).pos.y - ey

If Abs(dx) + Abs(dy) = 1 Then
' Entity is next to node

d = get_dir(dx, dy)

' Logic for adding nodes to chunk
add = false

If d = m And n > 3 Then add = node_push ' Push

' Moving character can shear off magnetic block beneath
If c_node = 1 And e <= 3 And d = g Then z = false Else z = true
If magnetized(entity(turn, e).metal, entity(turn, n).metal) = true And z = true Then add = node_magnet ' Magnetism

' Characters can't support anything unless warrior with shield up
If e <= 3 And entity(turn, e).flag <> shield_up Then z = false Else z = true
If Abs(d - g) = 2 And z = true Then add = node_support ' Support

If add <> false Then Call add_node(n, c_node, add)
End If
Next n

c_node = c_node + 1
Loop Until c_node > node_count

' Remove invalid nodes until none are removed
Do
removed_node = false

c_node = 1
Do
e = node(c_node).i

mx = entity(turn, e).pos.x + delta(m).x
my = entity(turn, e).pos.y + delta(m).y

' Logic for removing nodes from chunk
remove = false

If node(c_node).parent = false Then remove = true ' Parent missing

' Moving into a solid block
If on_board(mx, my) = true Then
If block_spec(block(turn, mx, my).spec).solid = true Then remove = true
End If

' Moving into a non-chunk entity
For n = 1 To entity_count(turn)
If entity(turn, n).pos.x = mx And entity(turn, n).pos.y = my Then
z = false
If e <= 3 And n <= 3 Then z = true ' Character can move into character
If m = g And e > 3 And n <= 3 Then z = true ' Non-character can fall into character
If entity_has_node(n) = false And z = false Then remove = true
End If
Next n

If remove = false And m = g Then
' Falling onto warrior shield
If entity(turn, e_warrior).pos.x = mx And entity(turn, e_warrior).pos.y = my And entity(turn, e_warrior).flag = shield_up Then remove = true

' Magnetism while falling
For d = 1 To 4
dx = entity(turn, e).pos.x + delta(d).x
dy = entity(turn, e).pos.y + delta(d).y

' Magnetized to a block
If on_board(dx, dy) = true Then
If magnetized(entity(turn, e).metal, block(turn, dx, dy).metal) = true Then remove = true
End If

' Magnetized to a non-chunk entity
For n = 1 To entity_count(turn)
If entity(turn, n).pos.x = dx And entity(turn, n).pos.y = dy Then
If entity_has_node(n) = false And magnetized(entity(turn, e).metal, entity(turn, n).metal) = true Then remove = true
End If
Next n
Next d

ElseIf remove = false And m <> g Then
' First node is character trying to move with nothing underneath
If c_node = 1 And e <= 3 And jump = false Then
gx = entity(turn, e).pos.x + delta(g).x
gy = entity(turn, e).pos.y + delta(g).y

s = true
If on_board(gx, gy) = true Then
s = false

' Block underneath
If block_spec(block(turn, gx, gy).spec).solid = true Then s = true

' Non-character entity underneath
For n = 4 To entity_count(turn)
If entity(turn, n).pos.x = gx And entity(turn, n).pos.y = gy Then
s = true
Exit For
End If
Next n

' Warrior with shield underneath
If entity(turn, e_warrior).pos.x = gx And entity(turn, e_warrior).pos.y = gy And entity(turn, e_warrior).flag = shield_up Then s = true
End If

If s = false Then remove = true
End If

' *** Magnetism while moving

End If

If remove = true Then
If c_node = 1 Then Exit Sub ' Movement failed completely

removed_node = true
Call remove_node(c_node)
End If

c_node = c_node + 1
Loop Until c_node > node_count

Loop Until removed_node = false

' Mark all entities involved in this move
For n = 1 To node_count
entity(turn, node(n).i).moving = true
Next n
Cls

End Sub


Sub move_marked_entities (d)

' Move entities

For n = 1 To entity_count(turn)
If entity(turn, n).moving = true Then
entity(turn, n).pos.x = entity(turn, n).pos.x + delta(d).x
entity(turn, n).pos.y = entity(turn, n).pos.y + delta(d).y
If d = gravity(turn) Then entity(turn, n).flip.y = delta(gravity(turn)).y
End If
Next n

' Animate the move

mpf = 0.34
dx = delta(d).x
dy = delta(d).y
move_offset.x = -dx
move_offset.y = -dy

Do
_Limit 60
Call update_camera
Call draw_stage
_Display

move_offset.x = plus_limit(move_offset.x, dx * mpf, 0)
move_offset.y = plus_limit(move_offset.y, dy * mpf, 0)
Loop Until move_offset.x = 0 And move_offset.y = 0

move_offset.x = 0
move_offset.y = 0

End Sub


Sub add_node (i, p, c)

' Abort if node already exists
For n = 2 To node_count ' Skip first node since its parent is true
If node(n).i = i And node(node(n).parent).i = node(p).i And node(n).connect = c Then Exit Sub
Next n

node_count = node_count + 1
node(node_count).i = i
node(node_count).parent = p
node(node_count).connect = c

End Sub


Sub remove_node (n)

node_count = node_count - 1
node(n).i = node(n + 1).i
node(n).parent = node(n + 1).parent
node(n).connect = node(n + 1).connect

' Adjust references
For p = 1 To node_count
If node(p).parent > n Then node(p).parent = node(p).parent - 1
If node(p).parent = n Then node(p).parent = false

If c_node >= n Then c_node = c_node - 1
Next p

End Sub


Function entity_has_node (e)

entity_has_node = false
For n = 1 To node_count
If node(n).i = e Then
entity_has_node = true
Exit Function
End If
Next n

End Function


Function magnetized (m1, m2)

magnetized = false
If m1 = magnet Or m2 = magnet Then z = true Else z = false
If m1 <> false And m2 <> false And z = true Then magnetized = true

End Function


Sub use_lever (lx, ly)

Call play_sound(sfx_lever)

block(turn, lx, ly).spec = toggle(block(turn, lx, ly).spec, b_lever_l, b_lever_r)

For y = 1 To stageh
For x = 1 To stagew
If block(turn, x, y).switch.x = lx And block(turn, x, y).switch.y = ly Then
s = block(turn, x, y).spec

' Switch ground magnetism
If s = b_ground_metal Then block(turn, x, y).metal = toggle(block(turn, x, y).metal, true, magnet)

' Switch door
If s = b_door_shut Or s = b_door_open Then block(turn, x, y).spec = toggle(block(turn, x, y).spec, b_door_shut, b_door_open)
End If
Next x
Next y

End Sub


Sub detect_devices

dev_keyboard = false
dev_gamepad = false

devices = _Devices
For n = devices To 1 Step -1
If Left$(_Device$(n), 10) = "[KEYBOARD]" Then dev_keyboard = n
If Left$(_Device$(n), 12) = "[CONTROLLER]" Then dev_gamepad = n
Next n

End Sub


Sub press_any_key
Do
_Limit 60
_Display
For b = 1 To keybind_count
If new_press(b) = true Then Exit Sub
Next b
Call update_inputs
Loop
End Sub


Sub set_default_keybinds

Call detect_devices

For b = 1 To keybind_count
keybind(b, keyboard) = keybind_default(b, keyboard)
keybind(b, gamepad) = keybind_default(b, gamepad)
Next b

' Eliminate any defaults that go beyond a gamepad's features
If dev_gamepad <> false Then
d = gamepad
l = _LastButton(dev_gamepad)
For b = 1 To keybind_count
If keybind(b, d) < 100 And keybind(b, d) > l Then keybind(b, d) = false
Next b

If _LastAxis(dev_gamepad) < 2 Then
keybind(up_key, d) = false
keybind(down_key, d) = false
keybind(left_key, d) = false
keybind(right_key, d) = false
End If
End If

End Sub


Function confirm (t$, c)

Call capture_screen

' pass c in with starting cursor position, true starts on YES
f = f_font
t2$ = "YES NO": t2b$ = "NO"
t3$ = "@"

h = font(f, 0).h
w = text_width(t$, f)
w2 = text_width(t2$, f): w2b = text_width(t2b$, f)
If w < w2 + (cursor_offset * 2) Then w = w2 + (cursor_offset * 2)

x = inthalf(screenw)
y = inthalf(screenh) - h

w3 = inthalf(w) + h

Call set_hold(true)
Do
_Limit 60
Call restore_screen
Call round_rect(x - w3, y - h, w3 * 2, (h * 4) - 4, fullscreen, hue(hue_dkblue), 2)
cx = x - inthalf(w2) - cursor_offset + ((c + 1) * (w2 - w2b))
Call glass_fonts(t$, f, fullscreen, x, y, center_align)
Call glass_fonts(t2$, f, fullscreen, x, y + h, center_align)
Call glass_fonts(t3$, f, fullscreen, cx, y + h, left_align)
_Display

If new_press(left_key) = true Or new_press(right_key) = true Then
Call play_menu_move
c = wrap(c + 1, true, false)
Else
If new_press(enter_key) = true Or new_press(ok_key) = true Then
Call play_menu_confirm
Exit Do
End If
End If

Call update_inputs
Loop

confirm = c

End Function


Sub load_stage (stage)

Dim b$(boardh)
For l = 1 To boardh
b$(l) = ""
Next l

turn = 1
last_turn = turn_max
gravity(turn) = down ' Start with normal gravity by default
f_x = 1 ' Start with characters facing right by default

stagew = 0
stageh = 0

control = 1

entity_count(turn) = 0

For y = 1 To boardh
For x = 1 To boardw
block(turn, x, y).spec = b_empty
Next x
Next y

If stage = 2 Then
l = 1
' 1 2 3 4 5 6 7 8 9 10
' 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
b$(l) = "##############################################################################################################": l = l + 1
b$(l) = "############################################ : # | : #####################################################": l = l + 1
b$(l) = "############################################ ~ # ~~~ #####################################################": l = l + 1
b$(l) = "############################################ ~~# # # #####################################################": l = l + 1
b$(l) = "############################################ # | # \ # #####################################################": l = l + 1
b$(l) = "############################################ # ~~#~~~# #####################################################": l = l + 1
b$(l) = "############################################ # ### # #####################################################": l = l + 1
b$(l) = "############################################ # ### # #####################################################": l = l + 1
b$(l) = "############################################ # : | ! #\ #####################################################": l = l + 1
b$(l) = "############################################ #~~~~~~~#~~ #####################################################": l = l + 1
b$(l) = "############################################ # # #####################################################": l = l + 1
b$(l) = "############################################ # 321 # #####################################################": l = l + 1
b$(l) = "############################################ # ~~~~~ # #####################################################": l = l + 1
b$(l) = "############################################ ##### #####################################################": l = l + 1
b$(l) = "############################################ ##### #####################################################": l = l + 1
b$(l) = "############################################~~~~#####~~~~#####################################################": l = l + 1
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
block(turn, 54, 17).switch.x = 55
block(turn, 54, 17).switch.y = 24
block(turn, 52, 17).switch.x = 55
block(turn, 52, 17).switch.y = 24
block(turn, 48, 17).switch.x = 55
block(turn, 48, 17).switch.y = 24
block(turn, 48, 20).switch.x = 55
block(turn, 48, 20).switch.y = 24

block(turn, 48, 24).switch.x = 52
block(turn, 48, 24).switch.y = 20
block(turn, 50, 24).switch.x = 52
block(turn, 50, 24).switch.y = 20

ElseIf stage = 4 Then
l = 1
' 1 2 3 4 5 6 7 8 9 10
' 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
b$(l) = "#################################################%%###%%######################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ ~~~ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ ! #####################################################": l = l + 1
b$(l) = "################################################ ~~~ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ ###################################################": l = l + 1
b$(l) = "################################################ \###################################################": l = l + 1
b$(l) = "################################################ ~~###################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ #####################################################": l = l + 1
b$(l) = "################################################ 321 | +##################################################": l = l + 1
b$(l) = "################################################~~~~~~~~~~~~##################################################": l = l + 1
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
block(turn, 58, 34).switch.x = 59
block(turn, 58, 34).switch.y = 30

ElseIf stage = 1 Then
l = 1
' 1 2 3 4 5 6 7 8 9 10
' 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
b$(l) = "##############################################################################################################": l = l + 1
b$(l) = "############################################# ##############################################################": l = l + 1
b$(l) = "############################################# ##############################################################": l = l + 1
b$(l) = "############################################ #############################################################": l = l + 1
b$(l) = "################################### ### ! #############################################################": l = l + 1
b$(l) = "################################### ~~~ ############################################################": l = l + 1
b$(l) = "################################ ############################################################": l = l + 1
b$(l) = "################################ +~~~~~~~~~## ####################################################": l = l + 1
b$(l) = "################################ ~~%%&&########### ####################################################": l = l + 1
b$(l) = "################################ ################# ####################################################": l = l + 1
b$(l) = "################################ ################# ####################################################": l = l + 1
b$(l) = "################################ ### ############# ##################################################": l = l + 1
b$(l) = "################################ ### ### | \##################################################": l = l + 1
b$(l) = "################################~~ # ~ ~~~~~ ~~##################################################": l = l + 1
b$(l) = "################################## = # ### ####################################################": l = l + 1
b$(l) = "##################################~~~~~~~ + ### ####################################################": l = l + 1
b$(l) = "#########################################~~~~~~~~###~~~~ ####################################################": l = l + 1
b$(l) = "######################################################## ####################################################": l = l + 1
b$(l) = "######################################################## ####################################################": l = l + 1
b$(l) = "################################################# ### ####################################################": l = l + 1
b$(l) = "################################################# ### ####################################################": l = l + 1
b$(l) = "############################################### ### ####################################################": l = l + 1
b$(l) = "############################## ###\ ### ####################################################": l = l + 1
b$(l) = "############################## ###~~ ### ####################################################": l = l + 1
b$(l) = "############################## = | ####################################################": l = l + 1
b$(l) = "############################## 321 ~~~~~~~ ~~~~~~~~~~~~~~####################################################": l = l + 1
b$(l) = "##############################~~~~~~#######~##################################################################": l = l + 1
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
block(turn, 55, 40).switch.x = 48
block(turn, 55, 40).switch.y = 38
block(turn, 51, 28).switch.x = 60
block(turn, 51, 28).switch.y = 28

ElseIf stage = 3 Then
l = 1
' 1 2 3 4 5 6 7 8 9 10
' 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
b$(l) = "#######################################################################&&#####################################": l = l + 1
b$(l) = "###################################################################### ####################################": l = l + 1
b$(l) = "###################################################################### ####################################": l = l + 1
b$(l) = "###################################################################### ####################################": l = l + 1
b$(l) = "#######################################################%############## ####################################": l = l + 1
b$(l) = "############################################ #### ############ #################################": l = l + 1
b$(l) = "############################################ #################################": l = l + 1
b$(l) = "############################################ ! #################################": l = l + 1
b$(l) = "############################################ ~~~ ~~~~~~~ ~~~#################################": l = l + 1
b$(l) = "############################################ 1 + ~~~~ \+ ### ####### ####################################": l = l + 1
b$(l) = "############################################~~~~%####~~~~~### ####### ####################################": l = l + 1
b$(l) = "############################################################# ####### ####################################": l = l + 1
b$(l) = "############################################################# #######~~~~####################################": l = l + 1
b$(l) = "############################################################# ###############################################": l = l + 1
b$(l) = "############################################################# ###############################################": l = l + 1
b$(l) = "############################################################# ##### ###################################": l = l + 1
b$(l) = "############################################################# ##### ###################################": l = l + 1
b$(l) = "############################################### ##### ####### #### ~ ~ ~ ###################################": l = l + 1
b$(l) = "############################################ ###### #### # # # ###################################": l = l + 1
b$(l) = "############################################ # # # # #################################": l = l + 1
b$(l) = "############################################ 3 = ~~ | \#################################": l = l + 1
b$(l) = "############################################~~~%~##~~ ~~~~~~~~~~~~~~ # # # ~~#################################": l = l + 1
b$(l) = "##################################################### ############## # # # ###################################": l = l + 1
b$(l) = "#####################################################~############## ###################################": l = l + 1
b$(l) = "#################################################################### 2 ###################################": l = l + 1
b$(l) = "####################################################################~~~~~~~###################################": l = l + 1
For n = 1 To 15
b$(l) = "##############################################################################################################": l = l + 1
Next n
block(turn, 66, 36).switch.x = 77
block(turn, 66, 36).switch.y = 36
block(turn, 56, 20).switch.x = 56
block(turn, 56, 20).switch.y = 25

End If

' Set blocks
For y = 1 To boardh
If b$(y) <> "" Then stageh = y
l = Len(b$(y))

For x = 1 To l
If l > stagew Then stagew = l

t$ = Mid$(b$(y), x, 1)

If t$ = " " Then block(turn, x, y).spec = b_empty
If t$ = "~" Then block(turn, x, y).spec = b_grass
If t$ = "#" Then block(turn, x, y).spec = b_ground
If t$ = "&" Or t$ = "%" Then block(turn, x, y).spec = b_ground_metal
If t$ = "^" Then block(turn, x, y).spec = b_spikes
If t$ = "_" Then block(turn, x, y).spec = b_plate
If t$ = "\" Then block(turn, x, y).spec = b_lever_l
If t$ = "/" Then block(turn, x, y).spec = b_lever_r
If t$ = "|" Then block(turn, x, y).spec = b_door_shut
If t$ = ":" Then block(turn, x, y).spec = b_door_open
If t$ = "@" Then block(turn, x, y).spec = b_telepad
If t$ = "!" Then block(turn, x, y).spec = b_goal

block(turn, x, y).metal = block_spec(block(turn, x, y).spec).metal

If t$ = "%" Then block(turn, x, y).metal = magnet
Next x
Next y

' Spawn characters
For c = 1 To 3
For y = 1 To boardh
For x = 1 To Len(b$(y))
t$ = Mid$(b$(y), x, 1)
If t$ = "1" Or t$ = "2" Or t$ = "3" Then
If Val(t$) = c Then Call spawn(c, x, y, f_x, false)
End If
Next x
Next y
Next c
entity(turn, e_warrior).flag = shield_down

' Spawn other entities
For y = 1 To boardh
For x = 1 To Len(b$(y))
Select Case Mid$(b$(y), x, 1)
Case "=": Call spawn(e_crate, x, y, 1, false)
Case "+": Call spawn(e_crate_metal, x, y, 1, false)
End Select
Next x
Next y

' Initial camera
camera.x = ((block_size + 1) * entity(turn, control).pos.x) - inthalf(screenw)
camera.y = ((block_size + 1) * entity(turn, control).pos.y) - inthalf(screenh)

End Sub





' --------------------------------
' ========== Conversion ==========
' --------------------------------

Function plus_limit (n, p, l)
q = n + p
If Sgn(q - l) = Sgn(p) Then q = l
plus_limit = q
End Function


Function toggle (v, p, q)
If v = p Then toggle = q
If v = q Then toggle = p
End Function


Function half (n)
half = n * 0.5
End Function
Function inthalf (n)
inthalf = Int(n * 0.5)
End Function


Function sq (n)
' For code clarity
sq = n * n
End Function


Function wrap (n, l1, h1)
' n is adjusted back within lower(l) and upper(h) bounds similar to mod operator
l = l1: h = h1 ' make sure h is never less than l, this also prevents division by zero
If h1 < l1 Then
l = h1: h = l1
End If
x = (l - n) / ((h - l) + 1)
If x <> Int(x) Then x = x + 1
wrap = n + (Int(x) * ((h - l) + 1))
End Function


Function rounding (n)
p = Int(n)
If mod_dec(n, 1) > 0.5 Then p = p + 1
rounding = p
End Function


Function round_up (n)
p = Int(n)
If mod_dec(n, 1) <> 0 Then p = p + 1
round_up = p
End Function


Function mod_dec (n, d)
mod_dec = n
If d = 0 Then Exit Function ' Division by zero protection
mod_dec = ((n / d) - Int(n / d)) * d
End Function


Function text_width (t$, f)
w = 0
For n = 1 To Len(t$)
w = w + font(f, Asc(Mid$(t$, n, 1))).w + 1
Next n
text_width = w - 1
End Function


Function text_contains (t$, c$)
text_contains = false
For n = 1 To Len(t$) - Len(c$) + 1
If Mid$(t$, n, Len(c$)) = c$ Then
text_contains = n
Exit Function
End If
Next n
End Function


Function trim$ (t$)
trim$ = ""
For n = 1 To Len(t$)
If Mid$(t$, n, 1) <> " " Then
trim$ = Right$(t$, n - 1)
Exit Function
End If
Next n
End Function


Sub sort (d)

' Before calling, put key values in sorting().s_index, .s_value, and sorting_count
' Takes s_index and s_value in sorting(), sorts them into sorted() by s_value, in direction of sgn(d)

c = 1
sorted(1).s_index = sorting(1).s_index
sorted(1).s_value = sorting(1).s_value

For n1 = 2 To sorting_count ' sorting() index being inserted
For n2 = 1 To c + 1 ' position in sorted() being checked
If n2 > c Or Sgn(sorted(n2).s_value - sorting(n1).s_value) = Sgn(d) Then
For n3 = c To n2 Step -1 ' make space for insertion
sorted(n3 + 1).s_index = sorted(n3).s_index
sorted(n3 + 1).s_value = sorted(n3).s_value
Next n3

sorted(n2).s_index = sorting(n1).s_index
sorted(n2).s_value = sorting(n1).s_value
c = c + 1
Exit For
End If
Next n2
Next n1
sorted_count = c

End Sub





' -------------------------------
' ========== Shorthand ==========
' -------------------------------

Function get_dir (x, y)
get_dir = false
For d = 1 To 4
If delta(d).x = x And delta(d).y = y Then get_dir = d
Next d
End Function


Function on_board (x, y)
on_board = true
If x < 1 Or x > boardw Or y < 1 Or y > boardh Then on_board = false
End Function





' -----------------------------
' ========== Loading ==========
' -----------------------------

Sub load_settings

If _FileExists("settings.ini") = false Then
Call save_settings
Exit Sub
End If

Open "settings.ini" For Binary As #1
Get #1, 1, keybind()
Get #1, , current_stage
Get #1, , option_restart_confirm
Get #1, , option_sound
Get #1, , option_sensitivity
Close #1

Call detect_devices
For b = 1 To keybind_count
' Reset invalid keyboard binds to default
If keybind(b, keyboard) < 1 Or keybind(b, keyboard) > 512 Then keybind(b, keyboard) = keybind_default(b, keyboard)

' Reset invalid gamepad binds to unset
If dev_gamepad <> false Then
lb = _LastButton(dev_gamepad)
la = _LastAxis(dev_gamepad)
If keybind(b, gamepad) < 100 Then
If keybind(b, gamepad) < 1 Or keybind(b, gamepad) > lb Then keybind(b, gamepad) = false
Else
If keybind(b, gamepad) > 200 Then k = keybind(b, gamepad) - 200 Else k = keybind(b, gamepad) - 100
If k < 1 Or k > la Then keybind(b, gamepad) = false
End If
End If
Next b

' Reset invalid option states to default
If current_stage < 1 Or current_stage > total_stages Then current_stage = 1
If option_restart_confirm <> true Then option_restart_confirm = false
If option_sound <> false Then option_sound = true
If option_sensitivity < 1 Or option_sensitivity > 9 Then option_sensitivity = 7

End Sub


Sub save_settings

Open "settings.ini" For Binary As #1
Put #1, 1, keybind()
Put #1, , current_stage
Put #1, , option_restart_confirm
Put #1, , option_sound
Put #1, , option_sensitivity
Close #1

End Sub


Sub load_images

preserve& = _Source

fade_image = _LoadImage("data\fade.png")

block_image = _LoadImage("data\block.png")
background = _LoadImage("data\background.png")

_Source preserve&

End Sub


Sub load_sfx

sfx(sfx_crush, 1) = _SndOpen("data\crush.ogg")
sfx(sfx_lever, 1) = _SndOpen("data\lever.ogg")
sfx(sfx_wind, 1) = _SndOpen("data\wind.ogg")
sfx(sfx_music, 1) = _SndOpen("data\music.ogg")

End Sub


Sub initialize_font (f, font$)

preserve& = _Source

font(f, 0).image = _LoadImage(font$)
_Source font(f, 0).image
_ClearColor Point(0, 0), font(f, 0).image
i& = font(f, 0).image
d~& = Point(1, 0) ' Detection color

' Height
font(f, 0).h = scan_down(1, 2, i&, d~&) - 3

y = 0
For cy = 0 To 15
y = scan_down(1, y, i&, d~&) + 1
x = 1
For cx = 0 To 15
n = (cy * 16) + cx
font(f, n).pos.x = x ' Source position
font(f, n).pos.y = y
x = scan_right(x, y, i&, d~&) + 1
font(f, n).w = x - font(f, n).pos.x - 2 ' Variable width
Next cx
Next cy

_Source preserve&

End Sub


Sub parse_sprites (i&)

preserve& = _Source

_Source i&
d~& = Point(0, 0) ' Detection color
s = sprite_count + 1
x1 = 1 ' Top left of first sprite
y1 = 2

Do
sprite(s).image = i&

' Source position
sprite(s).pos.x = x1
sprite(s).pos.y = y1

' Sprite size
x2 = scan_right(x1, y1, i&, d~&)
y2 = scan_down(x1, y1, i&, d~&)
sprite(s).size.x = x2 - x1 - 1
sprite(s).size.y = y2 - y1 - 1

' Animation frame count
x2 = scan_right(x2, y1, i&, d~&)
sprite(s).frames = Int(((x2 + 1) - x1) / (sprite(s).size.x + 2))
If sprite(s).frames < 1 Then sprite(s).frames = 1

' Frame counter ticks per animation frame
sprite(s).fpf = scan_right(x2, y1 - 1, i&, d~&) - x2
If sprite(s).fpf < 1 Then sprite(s).fpf = 1
x2 = x2 + 1

' Sprite display position - relative to entity hitbox position
x_hb = scan_right(x2 - 1, y1, i&, d~&)
y_hb = scan_down(x2, y1 - 1, i&, d~&)
sprite(s).offset.x = x2 - x_hb
sprite(s).offset.y = y1 - y_hb
' #OPT If either offset is zero, this forces the other one to be zero as well
' Easy fix is to move the detection pixels outside the sprite area

' Hitbox size
sprite(s).hb_size.x = scan_right(x_hb, y1, i&, d~&) - x_hb
sprite(s).hb_size.y = scan_down(x2, y_hb, i&, d~&) - y_hb

y1 = y2 + 1
If Point(x1 - 1, y1) = d~& Then ' End of column
If Point(x1, 0) = d~& Then Exit Do ' No more columns
y1 = 2
x1 = scan_right(x1, 0, i&, d~&) + 1 ' Find new column
End If

s = s + 1
Loop

sprite_count = s

_Source preserve&

End Sub


Function scan_text (p1, t$, d$)
p = p1
Do
p = p + 1
If p > Len(t$) - (Len(d$) - 1) Then
scan_text = 0
Exit Function
End If
Loop Until Mid$(t$, p, Len(d$)) = d$
scan_text = p
End Function


Function scan_right (x1, y, i&, d~&) ' Starting position (noninclusive), image, detection color
x = x1
preserve& = _Source
_Source i&
w = _Width(i&)
Do
x = x + 1
If x > w Then Call scan_error(x, y, "right")
Loop Until Point(x, y) = d~& Or x > w
scan_right = x
_Source preserve&
End Function


Function scan_down (x, y1, i&, d~&)
y = y1
preserve& = _Source
_Source i&
h = _Height(i&)
Do
y = y + 1
If y > h Then Call scan_error(x, y, "down")
Loop Until Point(x, y) = d~& Or y > h
scan_down = y
_Source preserve&
End Function


Sub scan_error (x, y, t$)
t1$ = "Moved " + t$ + " beyond image at" + Str$(x) + "," + Str$(y)
Call glass_fonts(t1$, f_font, fullscreen, 0, 0, left_align)
Call press_any_key
End Sub





' -----------------------------
' ========== Display ==========
' -----------------------------

Sub draw_background
_PutImage (0, 0)-(screenw, screenh), background, fullscreen, (0, 0)-(screenw, screenh)
End Sub

Sub draw_stage

Call clear_image(fullscreen, hue(hue_black))
Call draw_background

w = block_size

' Draw blocks
For y = 1 To boardh
For x = 1 To boardw
b = block(turn, x, y).spec
If b <> b_empty Then
x1 = ((w + 1) * x) - camera.x
y1 = ((w + 1) * y) - camera.y

s = block_spec(b).sprite

Call draw_sprite(s, x1, y1)
If block(turn, x, y).metal = magnet Then Call draw_sprite(sprite_ref(spr_magnetic), x1, y1) ' Magnetic overlay
End If
Next x
Next y

' Draw entities, ending with characters
For n = entity_count(turn) To 1 Step -1
e = entity(turn, n).spec
x1 = ((w + 1) * entity(turn, n).pos.x) - camera.x
y1 = ((w + 1) * entity(turn, n).pos.y) - camera.y

s = entity_spec(e).sprite
If entity_spec(e).flip.x = true And entity(turn, n).flip.x = 1 Then m = 1 Else m = 0
If entity_spec(e).flip.y = true And entity(turn, n).flip.y = -1 Then
If entity_spec(e).flip.x = true Then m = m + 2 Else m = m + 1
End If
s = s + m

If entity(turn, n).moving = true Then
x1 = x1 + ((w + 1) * move_offset.x)
y1 = y1 + ((w + 1) * move_offset.y)
End If

Call draw_sprite(s, x1, y1)
If entity(turn, n).metal = magnet Then Call draw_sprite(sprite_ref(spr_magnetic), x1, y1) ' Magnetic overlay
If entity(turn, n).flag = summoned Then Call draw_sprite(sprite_ref(spr_summoned), x1, y1) ' Summoned crate overlay
If entity(turn, n).flag = shield_up Then Call draw_sprite(sprite_ref(spr_shield), x1, y1) ' Shield overlay
If n = control Then Call draw_sprite(sprite_ref(spr_control), x1, y1) ' Yellow player control arrow
Next n

_PutImage (0, 0)-(800, 65), fade_image, fullscreen, (0, 0)-(800, 65)

s& = fullscreen
a = left_align
f = f_font
fg = f_font_gold
h = font(f, 0).h

y1 = 0: x1 = 0
y2 = h: x2 = 100
y3 = h * 2

d = keyboard
Locate 1, 1
If control = e_warrior Then
tk1$ = key_name$(keybind(armor_key, d), d): ta1$ = "Magnetic Coat"
tk2$ = key_name$(keybind(shield_key, d), d): ta2$ = "Shield"
ElseIf control = e_archer Then
tk1$ = key_name$(keybind(jump_key, d), d): ta1$ = "Jump"
tk2$ = key_name$(keybind(arrow_key, d), d): ta2$ = "Telekinesis"
ElseIf control = e_wizard Then
tk1$ = key_name$(keybind(alchemy_key, d), d): ta1$ = "Transform Block"
tk2$ = key_name$(keybind(block_key, d), d): ta2$ = "Summon Block"
End If

Call glass_fonts("--- " + entity_spec(control).name + " ---", fg, s&, x1, y1, a)
Call glass_fonts("[" + tk1$ + "]", fg, s&, x1, y2, a): Call glass_fonts(ta1$, f, s&, x2, y2, a)
Call glass_fonts("[" + tk2$ + "]", fg, s&, x1, y3, a): Call glass_fonts(ta2$, f, s&, x2, y3, a)

x1 = 250: x2 = 350
Call glass_fonts("[" + key_name$(keybind(action_key, d), d) + "]", fg, s&, x1, y1, a): Call glass_fonts("Action", f, s&, x2, y1, a)
Call glass_fonts("[" + key_name$(keybind(gravity_key, d), d) + "]", fg, s&, x1, y2, a): Call glass_fonts("Reverse Gravity", f, s&, x2, y2, a)
Call glass_fonts("[" + key_name$(keybind(switch_key, d), d) + "]", fg, s&, x1, y3, a): Call glass_fonts("Switch Character", f, s&, x2, y3, a)
x1 = 500: x2 = 600
Call glass_fonts("--- STAGE" + Str$(current_stage) + ": " + stage_name$(current_stage) + " ---", fg, s&, x1, y1, a)
Call glass_fonts("[" + key_name$(keybind(rewind_key, d), d) + "]", fg, s&, x1, y2, a): Call glass_fonts("Rewind", f, s&, x2, y2, a)
Call glass_fonts("[" + key_name$(keybind(restart_key, d), d) + "]", fg, s&, x1, y3, a): Call glass_fonts("Restart", f, s&, x2, y3, a)

Locate 5
'print entity(turn, control).pos.x; entity(turn, control).pos.y

End Sub


Sub draw_sprite (s, x, y)
w = block_size
_PutImage (x, y)-Step(w, w), block_image, fullscreen, (sprite(s).pos.x, sprite(s).pos.y)-Step(w, w)
End Sub


Sub glass_fonts (t$, f, p&, x1, y1, d)
' Text, font, destination image surface, position, alignment

x = x1: y = y1

If d <> left_align Then
' Adjust starting point based on line width, for center or right align
w = text_width(t$, f)
If d = center_align Then w = inthalf(w)
x = plus_limit(x, -w, 0)
End If

h = font(f, 0).h
For n = 1 To Len(t$)
c = Asc(Mid$(t$, n, 1))
w = font(f, c).w
_PutImage (x, y)-Step(w, h), font(f, 0).image, p&, (font(f, c).pos.x, font(f, c).pos.y)-Step(w, h)
x = x + w + 1
Next n

End Sub


Sub round_rect (px, py, sx, sy, d&, h&, bevel)
preserve& = _Dest
_Dest d&
For n1 = 0 To bevel
n2 = bevel - n1
If n1 <> bevel Then
Line (px + n2, py + n1)-(px + sx - n2, py + n1), h&
Line (px + n2, py + sy - n1)-(px + sx - n2, py + sy - n1), h&
Else
Line (px + n2, py + n1)-(px + sx - n2, py + sy - n1), h&, BF
End If
Next n1
_Dest preserve&
End Sub


Function text_tag_replace$ (t1$, f)
' Flag parameter invokes specific tag set, false to use all

t$ = t1$

If f = false Or f = text_tag_keybind Then
' Look for every "#kb01" etc in string and replace with key_name$
n = scan_text(0, LCase$(t$), "#kb")
Do While n <> 0
i = Val(Mid$(t$, n + 3, 2))
t$ = text_replace$(t$, key_name$(keybind(i, keyboard), keyboard), n, 5)
n = scan_text(n, LCase$(t$), "#kb")
Loop

End If
text_tag_replace$ = t$

End Function


Function text_replace$ (t$, r$, p, l)
' p = position of section to replace, l = its length
text_replace$ = Left$(t$, p - 1) + r$ + Right$(t$, Len(t$) - p - (l - 1))
End Function


Sub capture_screen
Call clear_image(store_screen, hue(hue_black))
_PutImage (0, 0)-(screenw, screenh), fullscreen, store_screen, (0, 0)-(screenw, screenh)
End Sub


Sub restore_screen
Call clear_image(fullscreen, hue(hue_black))
_PutImage (0, 0)-(screenw, screenh), store_screen, fullscreen, (0, 0)-(screenw, screenh)
End Sub


Sub clear_image (d&, h~&)
preserve& = _Dest
_Dest d&
Cls , h~&
_Dest preserve&
End Sub


Sub overlay (d&, h~&)
preserve& = _Dest: preserve2& = _Source
_Dest d&: _Source d&
Line (0, 0)-(_Width, _Height), h~&, BF
_ClearColor Point(_Width - 1, _Height - 1), d&
_Dest preserve&: _Source preserve2&
End Sub


Sub play_sound (s)

If option_sound = false Then Exit Sub

' Count valid sounds at this index and select one randomly
c = 1
Do Until sfx(s, c + 1) = false
c = c + 1
Loop
r = Int(Rnd * c) + 1

If sfx(s, r) <> false Then _SndPlay sfx(s, r)

End Sub


Sub play_menu_move
Call play_sound(sfx_menu_move)
End Sub
Sub play_menu_confirm
Call play_sound(sfx_menu_confirm)
End Sub





' ----------------------------------
' ========== Initial data ==========
' ----------------------------------

Sub set_key_data

key_name$(false, keyboard) = "NOT SET"
key_name$(false, gamepad) = "NOT SET"

d = keyboard
For n = 1 To 512
key_name$(n, d) = "UNKNOWN"
Next n
key_name$(2, d) = "ESC"
key_name$(60, d) = "F1"
key_name$(61, d) = "F2"
key_name$(62, d) = "F3"
key_name$(63, d) = "F4"
key_name$(64, d) = "F5"
key_name$(65, d) = "F6"
key_name$(66, d) = "F7"
key_name$(67, d) = "F8"
key_name$(68, d) = "F9"
key_name$(88, d) = "F11"
key_name$(89, d) = "F12"
key_name$(42, d) = "~"
key_name$(3, d) = "1"
key_name$(4, d) = "2"
key_name$(5, d) = "3"
key_name$(6, d) = "4"
key_name$(7, d) = "5"
key_name$(8, d) = "6"
key_name$(9, d) = "7"
key_name$(10, d) = "8"
key_name$(11, d) = "9"
key_name$(12, d) = "0"
key_name$(13, d) = "-"
key_name$(14, d) = "="
key_name$(15, d) = "BKSP"
key_name$(16, d) = "TAB"
key_name$(17, d) = "Q"
key_name$(18, d) = "W"
key_name$(19, d) = "E"
key_name$(20, d) = "R"
key_name$(21, d) = "T"
key_name$(22, d) = "Y"
key_name$(23, d) = "U"
key_name$(24, d) = "I"
key_name$(25, d) = "O"
key_name$(26, d) = "P"
key_name$(27, d) = "["
key_name$(28, d) = "]"
key_name$(44, d) = "\"
key_name$(31, d) = "A"
key_name$(32, d) = "S"
key_name$(33, d) = "D"
key_name$(34, d) = "F"
key_name$(35, d) = "G"
key_name$(36, d) = "H"
key_name$(37, d) = "J"
key_name$(38, d) = "K"
key_name$(39, d) = "L"
key_name$(40, d) = ";"
key_name$(41, d) = "'"
key_name$(29, d) = "ENTER"
key_name$(43, d) = "L SHIFT"
key_name$(45, d) = "Z"
key_name$(46, d) = "X"
key_name$(47, d) = "C"
key_name$(48, d) = "V"
key_name$(49, d) = "B"
key_name$(50, d) = "N"
key_name$(51, d) = "M"
key_name$(52, d) = ","
key_name$(53, d) = "."
key_name$(54, d) = "/"
key_name$(55, d) = "R SHIFT"
key_name$(30, d) = "L CTRL"
key_name$(58, d) = "SPACE"
key_name$(286, d) = "R CTRL"
key_name$(339, d) = "INS"
key_name$(340, d) = "DEL"
key_name$(328, d) = "HOME"
key_name$(336, d) = "END"
key_name$(330, d) = "PG UP"
key_name$(338, d) = "PG DN"
key_name$(329, d) = "UP"
key_name$(337, d) = "DOWN"
key_name$(332, d) = "LEFT"
key_name$(334, d) = "RIGHT"
key_name$(310, d) = "NUM /"
key_name$(56, d) = "NUM *"
key_name$(75, d) = "NUM -"
key_name$(79, d) = "NUM +"
key_name$(285, d) = "NUM ENTER"
key_name$(72, d) = "NUM 7"
key_name$(73, d) = "NUM 8"
key_name$(74, d) = "NUM 9"
key_name$(76, d) = "NUM 4"
key_name$(77, d) = "NUM 5"
key_name$(78, d) = "NUM 6"
key_name$(80, d) = "NUM 1"
key_name$(81, d) = "NUM 2"
key_name$(82, d) = "NUM 3"
key_name$(83, d) = "NUM 0"
key_name$(84, d) = "NUM ."

' Troublesome keyboard codes:
' 71 - Scroll Lock
' 70 - Pause
' 59 - Caps Lock
' 348 - Windows Left
' 349 - Windows Right?
' 350 - Menu
' 326 - Num Lock

d = gamepad
For n = 1 To 20
key_name$(n, d) = "BUTTON" + Str$(n)
Next n
For n = 1 To 8
key_name$(n + 100, d) = "AXIS" + Str$(n) + "-"
key_name$(n + 200, d) = "AXIS" + Str$(n) + "+"
Next n

'const armor_key = 1
'const shield_key = 2
'const jump_key = 3
'const arrow_key = 4
'const alchemy_key = 5
'const block_key = 6
'const action_key = 7
'const gravity_key = 8

'const up_key = 9
'const down_key = 10
'const left_key = 11
'const right_key = 12
'const switch_key = 13
'const rewind_key = 14
'const restart_key = 15
'const ok_key = 16
'const cancel_key = 17
'const enter_key = 18
'const esc_key = 19

keybind_name$(armor_key) = "MAGNETIC COAT"
keybind_name$(shield_key) = "SHIELD"
keybind_name$(jump_key) = "JUMP"
keybind_name$(arrow_key) = "TELEKINESIS"
keybind_name$(alchemy_key) = "ALCHEMY"
keybind_name$(block_key) = "SUMMON BLOCK"
keybind_name$(action_key) = "ACTION"
keybind_name$(gravity_key) = "REVERSE GRAVITY"

keybind_name$(up_key) = "UP"
keybind_name$(down_key) = "DOWN"
keybind_name$(left_key) = "LEFT"
keybind_name$(right_key) = "RIGHT"
keybind_name$(switch_key) = "SWITCH CHARACTER"
keybind_name$(rewind_key) = "REWIND"
keybind_name$(restart_key) = "RESTART STAGE"
keybind_name$(ok_key) = "MENU OK"
keybind_name$(cancel_key) = "MENU CANCEL"
keybind_name$(enter_key) = "PAUSE/OK"
keybind_name$(esc_key) = "PAUSE/CANCEL"

d = keyboard
keybind_default(armor_key, d) = 47 ' c
keybind_default(shield_key, d) = 45 ' z
keybind_default(jump_key, d) = 47 ' c
keybind_default(arrow_key, d) = 45 ' z
keybind_default(alchemy_key, d) = 47 ' c
keybind_default(block_key, d) = 45 ' z
keybind_default(action_key, d) = 46 ' x
keybind_default(gravity_key, d) = 58 ' SPACE

keybind_default(up_key, d) = 329
keybind_default(down_key, d) = 337
keybind_default(left_key, d) = 332
keybind_default(right_key, d) = 334
keybind_default(switch_key, d) = 30 ' LCTRL
keybind_default(rewind_key, d) = 15 ' BKSP
keybind_default(restart_key, d) = 20 ' r
keybind_default(ok_key, d) = 46 ' x
keybind_default(cancel_key, d) = 47 ' c
keybind_default(enter_key, d) = 29
keybind_default(esc_key, d) = 2

d = gamepad
keybind_default(armor_key, d) = 2 ' B
keybind_default(shield_key, d) = 4 ' Y
keybind_default(jump_key, d) = 2 ' B
keybind_default(arrow_key, d) = 4 ' Y
keybind_default(alchemy_key, d) = 2 ' B
keybind_default(block_key, d) = 4 ' Y
keybind_default(action_key, d) = 1 ' A
keybind_default(gravity_key, d) = 3 ' X

keybind_default(up_key, d) = 102 ' stick up
keybind_default(down_key, d) = 202 ' stick down
keybind_default(left_key, d) = 101 ' stick left
keybind_default(right_key, d) = 201 ' stick right
keybind_default(switch_key, d) = 6 ' R
keybind_default(rewind_key, d) = 5 ' L
keybind_default(restart_key, d) = 7 ' Select
keybind_default(ok_key, d) = 1 ' A
keybind_default(cancel_key, d) = 2 ' B
keybind_default(enter_key, d) = false ' Enter and Esc are not found on gamepad
keybind_default(esc_key, d) = false

' OK and Cancel can overlap with any gameplay functions

b = ok_key
keybind_overlap(b, armor_key) = true: keybind_overlap(armor_key, b) = true
keybind_overlap(b, shield_key) = true: keybind_overlap(shield_key, b) = true
keybind_overlap(b, jump_key) = true: keybind_overlap(jump_key, b) = true
keybind_overlap(b, arrow_key) = true: keybind_overlap(arrow_key, b) = true
keybind_overlap(b, alchemy_key) = true: keybind_overlap(alchemy_key, b) = true
keybind_overlap(b, block_key) = true: keybind_overlap(block_key, b) = true
keybind_overlap(b, action_key) = true: keybind_overlap(action_key, b) = true
keybind_overlap(b, gravity_key) = true: keybind_overlap(gravity_key, b) = true
keybind_overlap(b, switch_key) = true: keybind_overlap(switch_key, b) = true
keybind_overlap(b, rewind_key) = true: keybind_overlap(rewind_key, b) = true
keybind_overlap(b, restart_key) = true: keybind_overlap(restart_key, b) = true

b = cancel_key
keybind_overlap(b, armor_key) = true: keybind_overlap(armor_key, b) = true
keybind_overlap(b, shield_key) = true: keybind_overlap(shield_key, b) = true
keybind_overlap(b, jump_key) = true: keybind_overlap(jump_key, b) = true
keybind_overlap(b, arrow_key) = true: keybind_overlap(arrow_key, b) = true
keybind_overlap(b, alchemy_key) = true: keybind_overlap(alchemy_key, b) = true
keybind_overlap(b, block_key) = true: keybind_overlap(block_key, b) = true
keybind_overlap(b, action_key) = true: keybind_overlap(action_key, b) = true
keybind_overlap(b, gravity_key) = true: keybind_overlap(gravity_key, b) = true
keybind_overlap(b, switch_key) = true: keybind_overlap(switch_key, b) = true
keybind_overlap(b, rewind_key) = true: keybind_overlap(rewind_key, b) = true
keybind_overlap(b, restart_key) = true: keybind_overlap(restart_key, b) = true

' Characters can overlap with each other in any way

keybind_overlap(armor_key, jump_key) = true: keybind_overlap(jump_key, armor_key) = true
keybind_overlap(armor_key, arrow_key) = true: keybind_overlap(arrow_key, armor_key) = true
keybind_overlap(shield_key, jump_key) = true: keybind_overlap(jump_key, shield_key) = true
keybind_overlap(shield_key, arrow_key) = true: keybind_overlap(arrow_key, shield_key) = true

keybind_overlap(jump_key, alchemy_key) = true: keybind_overlap(alchemy_key, jump_key) = true
keybind_overlap(jump_key, block_key) = true: keybind_overlap(block_key, jump_key) = true
keybind_overlap(arrow_key, alchemy_key) = true: keybind_overlap(alchemy_key, arrow_key) = true
keybind_overlap(arrow_key, block_key) = true: keybind_overlap(block_key, arrow_key) = true

keybind_overlap(alchemy_key, armor_key) = true: keybind_overlap(armor_key, alchemy_key) = true
keybind_overlap(alchemy_key, shield_key) = true: keybind_overlap(shield_key, alchemy_key) = true
keybind_overlap(block_key, armor_key) = true: keybind_overlap(armor_key, block_key) = true
keybind_overlap(block_key, shield_key) = true: keybind_overlap(shield_key, block_key) = true

Call set_default_keybinds

End Sub


Sub set_sprite_ref

' ----- Set sprite references - must be in order found in image files -----

s = 1
sprite_ref(spr_warrior_d_l) = s: s = s + 1
sprite_ref(spr_warrior_d_r) = s: s = s + 1
sprite_ref(spr_warrior_u_l) = s: s = s + 1
sprite_ref(spr_warrior_u_r) = s: s = s + 1
sprite_ref(spr_archer_d_l) = s: s = s + 1
sprite_ref(spr_archer_d_r) = s: s = s + 1
sprite_ref(spr_archer_u_l) = s: s = s + 1
sprite_ref(spr_archer_u_r) = s: s = s + 1
sprite_ref(spr_wizard_d_l) = s: s = s + 1
sprite_ref(spr_wizard_d_r) = s: s = s + 1
sprite_ref(spr_wizard_u_l) = s: s = s + 1
sprite_ref(spr_wizard_u_r) = s: s = s + 1

sprite_ref(spr_grass) = s: s = s + 1
sprite_ref(spr_ground) = s: s = s + 1
sprite_ref(spr_ground_metal) = s: s = s + 1
sprite_ref(spr_crate) = s: s = s + 1
sprite_ref(spr_crate_metal) = s: s = s + 1
sprite_ref(spr_spikes) = s: s = s + 1
sprite_ref(spr_plate) = s: s = s + 1
sprite_ref(spr_lever_l) = s: s = s + 1
sprite_ref(spr_lever_r) = s: s = s + 1
sprite_ref(spr_door_shut) = s: s = s + 1
sprite_ref(spr_door_open) = s: s = s + 1
sprite_ref(spr_telepad) = s: s = s + 1
sprite_ref(spr_goal) = s: s = s + 1
sprite_ref(spr_magnetic) = s: s = s + 1

sprite_ref(spr_control) = s: s = s + 1
sprite_ref(spr_summoned) = s: s = s + 1
sprite_ref(spr_shield) = s: s = s + 1
sprite_ref(spr_psychic) = s: s = s + 1

' ----- Set sprites -----

entity_spec(e_warrior).sprite = sprite_ref(spr_warrior_d_l)
entity_spec(e_archer).sprite = sprite_ref(spr_archer_d_l)
entity_spec(e_wizard).sprite = sprite_ref(spr_wizard_d_l)

entity_spec(e_crate).sprite = sprite_ref(spr_crate)
entity_spec(e_crate_metal).sprite = sprite_ref(spr_crate_metal)

block_spec(b_grass).sprite = sprite_ref(spr_grass)
block_spec(b_ground).sprite = sprite_ref(spr_ground)
block_spec(b_ground_metal).sprite = sprite_ref(spr_ground_metal)
block_spec(b_spikes).sprite = sprite_ref(spr_spikes)
block_spec(b_plate).sprite = sprite_ref(spr_plate)
block_spec(b_lever_l).sprite = sprite_ref(spr_lever_l)
block_spec(b_lever_r).sprite = sprite_ref(spr_lever_r)
block_spec(b_door_shut).sprite = sprite_ref(spr_door_shut)
block_spec(b_door_open).sprite = sprite_ref(spr_door_open)
block_spec(b_telepad).sprite = sprite_ref(spr_telepad)
block_spec(b_goal).sprite = sprite_ref(spr_goal)

End Sub


Sub set_entity_spec_data

entity_spec(e_warrior).name = "Lancelot"
entity_spec(e_warrior).metal = true
entity_spec(e_warrior).flip.x = true
entity_spec(e_warrior).flip.y = true

entity_spec(e_archer).name = "Percival"
entity_spec(e_archer).metal = false
entity_spec(e_archer).flip.x = true
entity_spec(e_archer).flip.y = true

entity_spec(e_wizard).name = "Galahad"
entity_spec(e_wizard).metal = false
entity_spec(e_wizard).flip.x = true
entity_spec(e_wizard).flip.y = true

entity_spec(e_crate).metal = false

entity_spec(e_crate_metal).metal = true

End Sub


Sub set_block_spec_data

block_spec(b_empty).solid = false
block_spec(b_empty).metal = false

block_spec(b_grass).solid = true
block_spec(b_grass).metal = false

block_spec(b_ground).solid = true
block_spec(b_ground).metal = false

block_spec(b_ground_metal).solid = true
block_spec(b_ground_metal).metal = true

block_spec(b_spikes).solid = true
block_spec(b_spikes).metal = false

block_spec(b_plate).solid = false
block_spec(b_plate).metal = false

block_spec(b_lever_l).solid = false
block_spec(b_lever_l).metal = false

block_spec(b_lever_r).solid = false
block_spec(b_lever_r).metal = false

block_spec(b_door_shut).solid = true
block_spec(b_door_shut).metal = false

block_spec(b_door_open).solid = false
block_spec(b_door_open).metal = false

block_spec(b_telepad).solid = false
block_spec(b_telepad).metal = false

block_spec(b_goal).solid = false
block_spec(b_goal).metal = false

End Sub

Print this item

  Doubles Wild Board Game
Posted by: SMcNeill - 12-24-2023, 10:30 AM - Forum: Donald Foster - No Replies

Quote:Hello All,

Doubles Wild is a 2 to 4 player strategy board game with some luck.

Object of the game: The player scoring the most 3 in a rows at the end of the is the winner.
The ends when the current player taking their turn has no balls left to play.
If the game ends in a tie, the board is cleared and those players who tied, starts another game and the first player to get 1 or more 3 in a row wins.

The wooden board consist of 81 dimples where balls can be placed, 9 X 9 board. Around the outside of the dimples are row and column numbers from 3 to 11. Just outside the rows and column numbers are piece storage cutouts to hold each player's pieces. Outside the storage areas are peg holes to indicate how many 3 in a row each player has with peg in the first hole indicating none.
In a 2 player game, each player has 24 balls. Player 1 uses the blue balls and player 2 uses the red ones. With 3 players, each player has 18 pieces each. Player 3 plays the purple balls. With 4 players, each player has 12 balls and player 4 uses the green balls.

A turn consist of the player rolling 4 dice, 2 red and 2 blue. The red dice are added together and the total represents the red rows on the sides of the board. The blue dice are also added together with the total representing then blue columns at the top and bottom of the board. Example: Player rolls a red 5 & 4, blue 2 & 4. That would be Row 9, column 6.

A square cursor surrounds the numbers that's representing the rows and columns. There is also a round cursor at that board location if that position is playable. If that location already has the current player's piece on it or if an opponents piece is part of a 3 in a row at that position, that location is blocked and can not be played there. If the location is empty, the player may place their ball there. If an opponent has a piece there and it is not part of a 3 in a row, the player can declare a battle for that position.

If the player rolls doubles of the red or blue dice, they can place their piece at any playable location on the other row or column that not doubles. Example: If a player rolls double red 4's and a blue 3 and 5, the play may place their piece at any playable row on column 8 and vice versa. If the player rolls doubles on the red and blue dice, the player can place their piece at any playable location on the board. A ball is placed on the board by clicking at that location.
Each player, if chooses, may re-roll 1 or both pairs of dice once per turn. The player may re-roll 1 pair or all dice. If after the second roll, that position is blocked, that player ends their turn. If the location is empty, they must place their piece there. If the location is occupied by an opponent and not part of a 3 in a row, that player must engage a battle for that position.

Once battle is engaged, the battle board appears on right side of the screen. Both players use 3 dice each in the battle. The player that engaged the battle is the Attacker and uses the red dice. The other player is the Defender and uses the blue dice. The best of 3 rolls wins the battle. If the players tie after 3 rolls, the Defender wins the battle. At the start of the battle, all dice are blank. Both player uses the "R O L L D I C E" button to roll their dice. The begins with the Attacker rolling first, then the Defender. The second and third rolls done the same. The Attacker choose which dice they wish to keep by clicking on the dice and a cursor will surround that dice. If clicked again, it will be de-selected. The players may choose 1, 2 ,3 or none of the dice to keep. The Attacker always rolls first. If the Defender wins the battle, their ball remains at that location and if the Attacker wins, their ball will replace the Defenders ball.

At the end of each turn, all 3 in a rows will be calculated and the player's peg position will be updated.

Hope you enjoy playing.

Donald

   

   

   

Code: (Select All)
_Title "Doubles Wild - Designed by Andy Daniel 2001 - Programmed by Donald L. Foster Jr. 2019"

Screen _NewImage(1440, 900, 32)

Randomize Timer

'_PALETTECOLOR 1, _RGB32(109, 39, 0) ' background
'_PALETTECOLOR 2, _RGB32(205, 134, 66) ' LT Square
'_PALETTECOLOR 3, _RGB32(184, 104, 36) ' MED Piece
'_PALETTECOLOR 4, _RGB32(154, 74, 6) ' DK Piece

Background&& = _RGB(109, 39, 0)
Board&& = _RGB(204, 124, 56)
DkBoard&& = _RGB(154, 74, 6)
LtBoard&& = _RGB(235, 164, 96)
White&& = _RGB(255, 255, 255)
Black&& = _RGB(0, 0, 0)
BlueDice&& = _RGB(0, 70, 215)
RedDice&& = _RGB(210, 0, 0)
BlueBall&& = _RGB(0, 0, 200)
RedBall&& = _RGB(200, 0, 0)
YellowBall&& = _RGB(128, 0, 128)
GreenBall&& = _RGB(0, 110, 0)

Dim BoardX(11, 11), BoardY(11, 11) As Integer
Dim BoardPlayer(11, 11), Playable(11, 11) As Integer
Dim PlayerPegX(4, 35), PlayerPegY(4, 35) As Integer
Dim StorageX(4, 24), StorageY(4, 24) As Integer
Dim RowX(11, 2), RowY(11, 2), ColumnX(11, 2), ColumnY(11, 2) As Integer
Dim Blocked(11, 11) As Integer

PlayerColor&&(1) = BlueBall&&
PlayerColor&&(2) = RedBall&&
PlayerColor&&(3) = YellowBall&&
PlayerColor&&(4) = GreenBall&&

Player = 1:

BattleMessage1$(1, 1) = "Attacker, Roll Your First Roll."
BattleMessage1$(2, 1) = "Defender, Roll Your First Roll."
BattleMessage1$(1, 2) = "Attacker, Choose Dice To Keep. "
BattleMessage1$(2, 2) = "Defender, Choose Dice To Keep. "
BattleMessage1$(1, 3) = "Attacker, Choose Dice To Keep. "
BattleMessage1$(2, 3) = "Defender, Choose Dice To Keep. "
BattleMessage2$(1, 1) = " "
BattleMessage2$(2, 1) = " "
BattleMessage2$(1, 2) = " Then Roll Your Second Roll. "
BattleMessage2$(2, 2) = " Then Roll Your Second Roll. "
BattleMessage2$(1, 3) = " Then Roll Your Third Roll. "
BattleMessage2$(2, 3) = " Then Roll Your Third Roll. "
BattleWinner$(1) = " Attacker Won The Battle!!! "
BattleWinner$(2) = " Defender Won The Battle!!! "
PressEnter$ = " Press <ENTER> To Continue. "

' Set Background Color
Cls , Background&&

Line (901, 10)-(1430, 890), Board&&, BF

' Draw DOUBLES WILD
Locate 1, 1: Print " D O U B L E S W I L D ";
W1 = 7: W2 = 0
For Z1 = 1 To 12
V2 = 0
For Y1 = 0 To 13
U2 = 0
For X1 = W1 To W1 + 9
If Point(X1, Y1) = White&& Then
If Z1 > 8 Then
If Y1 >= 0 And Y1 < 4 Then Color PlayerColor&&(1) Else If Y1 > 3 And Y1 < 7 Then Color PlayerColor&&(2) Else If Y1 > 6 And Y1 < 10 Then Color PlayerColor&&(3) Else Color PlayerColor&&(4)
Else
Color White&&
End If
Line (950 + U2 + W2, 20 + V2)-(952 + U2 + W2, 22 + V2), , BF
End If
U2 = U2 + 3
Next
V2 = V2 + 3
Next
W1 = W1 + 16: If Z1 > 8 Then W2 = W2 + 30 Else W2 = W2 + 40
Next
Line (0, 0)-(200, 20), Background&&, BF
Color Black&&: X = 0: For Z = 1 To 6: Circle (983 + X, 41), 4: Paint (983 + X, 41): X = X + 40: Next

' Draw Board
PSet (10, 870), Board&&: Draw "U860R860D860L860F20R860NH20U860H20"
Paint (100, 860), Board&&: Paint (100, 880), DkBoard&&, Board&&: Paint (880, 100), DkBoard&&, Board&&
X = 200
For Z = 11 To 3 Step -1
V = 200
For Y = 3 To 11
X1 = V: X2 = X: GoSub DrawDimple
BoardX(Z, Y) = V: BoardY(Z, Y) = X
V = V + 60
Next
X = X + 60
Next

' Draw Numbers on the Board
Color White&&, Board&&: Locate 5, 150: Print " 3 4 5 6 7 8 9 10 11 ";
W1 = 1191: W2 = 0: T2 = 0
For Z1 = 1 To 9
V2 = 0
For Y1 = 65 To 78
U2 = 0
For X1 = W1 To W1 + 17
If Point(X1, Y1) = White&& Then
If Z1 > 7 Then S2 = 7 Else S2 = 0
Line (177 + W2 + U2, 134 + V2)-(178 + W2 + U2, 135 + V2), BlueDice&&, BF: ColumnX(Z1 + 2, 1) = 200 + T2: ColumnY(Z1 + 2, 1) = 145
Line (177 + W2 + U2, 724 + V2)-(178 + W2 + U2, 725 + V2), BlueDice&&, BF: ColumnX(Z1 + 2, 2) = 200 + T2: ColumnY(Z1 + 2, 2) = 735
Line (122 + U2 + S2, 667 + V2 - T2)-(123 + U2 + S2, 668 + V2 - T2), RedDice&&, BF: RowX(Z1 + 2, 1) = 146: RowY(Z1 + 2, 1) = 665 - T2 + 13
Line (709 + U2 + S2, 667 + V2 - T2)-(710 + U2 + S2, 668 + V2 - T2), RedDice&&, BF: RowX(Z1 + 2, 2) = 733: RowY(Z1 + 2, 2) = 665 - T2 + 13
End If
U2 = U2 + 2
Next
V2 = V2 + 2
Next
W1 = W1 + 24: T2 = T2 + 60: If Z1 = 7 Then W2 = W2 + 66 Else W2 = W2 + 60
Next
Line (1180, 60)-(1410, 80), Board&&, BF

' Setup Storage Spaces
Color LtBoard&&
Circle (150, 83), 40, , 1.50, 4.80: Circle (730, 83), 40, , 4.60, 1.60
Circle (83, 150), 40, , 0, 3.10: Circle (797, 150), 40, , 0, 3.10
Circle (83, 730), 40, , 3.10, 0: Circle (797, 730), 40, , 3.10, 0
Circle (150, 797), 40, , 1.50, 4.80: Circle (730, 797), 40, , 4.60, 1.60
Line (150, 43)-(730, 43): Line (150, 123)-(730, 123)
Line (150, 757)-(730, 757): Line (150, 837)-(730, 837)
Line (43, 150)-(43, 730): Line (123, 150)-(123, 730)
Line (757, 150)-(757, 730): Line (837, 150)-(837, 730)
Paint (400, 60): Paint (400, 800): Paint (80, 400): Paint (800, 400)


Line (911, 70)-(1420, 880), White&&, B

Color Black&&, Board&&: Locate 7, 133: Print "How Many Players? ( 2 to 4 )";

For Z = 1 To 15: A$ = InKey$: Next
GetPlayers: A$ = InKey$: If A$ = "" GoTo GetPlayers Else If Val(A$) > 1 And Val(A$) < 5 Then Players = Val(A$) Else GoTo GetPlayers

Color Black&&, Board&&: Locate 7, 133: Print " ";

GoSub PlaceBalls: GoSub UpdatePegs




StartTurn:
BattleEngaged = 0: Roll = 1

' Draw Player Indicator
X1 = 1165: X2 = 180: X3 = Player: GoSub DrawBall
Color Black&&, Board&&: Locate 14, 143: Print "Player"; Player

RollDice:
Color Black&&, Board&&: Locate 42, 141: Print "R O L L: "; Roll;

' Check for End of Game
If Pieces(Player) = 0 Then
Color Black&&, Board&&: Locate 52, 120: Print " Player"; Player; "You Have No Pieces Left to Play. ";
Color Black&&, Board&&: Locate 54, 120: Print " Press <ENTER> to Continue. ";
For Z = 1 To 15: A$ = InKey$: Next
ENTER: A$ = InKey$: If A$ = "" GoTo ENTER Else If Asc(A$) <> 13 GoTo ENTER
For Z = 50 To 52 Step 2: Locate Z, 120: Print String$(55, 32);: Next
WinningScore = 0
For Z = 1 To Players
If Score(Z) > WinningScore Then WinningScore = Score(Z)
Next
Winners = 0
For Z = 1 To Players
If Score(Z) = WinningScore Then Winners = Winners + 1: Winner(Winners) = Z: Winner = Z
Next
If Winners > 1 Then
Color Black&&, Board&&: Locate 52, 120: Print " The Game Ended in a Tie. First 3 In A Row Wins!!! ";
Color Black&&, Board&&: Locate 54, 120: Print " Press <ENTER> to Start the Next Round. ";
For Z = 1 To 15: A$ = InKey$: Next
ENTER1: A$ = InKey$: If A$ = "" GoTo ENTER1 Else If Asc(A$) <> 13 GoTo ENTER1
Line (30, 16)-(860, 36), Board&&, BF: Line (30, 844)-(860, 864), Board&&, BF
GoSub ClearBoard: GoSub PlaceBalls: NextTurn = 1: Roll = 1
Score(1) = 0: Score(2) = 0: Score(3) = 0: Score(4) = 0: GoSub UpdatePegs
Counter = 1: Player = Winner(1): GoTo StartTurn
Else

X1 = 1165: X2 = 180: X3 = Winner: GoSub DrawBall
Color Black&&, Board&&: Locate 14, 143: Print "Player"; Winner;
Color Black&&, Board&&: Locate 52, 120: Print " Player"; Winner; "is the Winner!!! ";
Color Black&&, Board&&: Locate 54, 120: Print " Play Another Game? ( Y or N ) ";
For Z = 1 To 15: A$ = InKey$: Next
GetYorN: A$ = UCase$(InKey$): If A$ = "" GoTo GetYorN
If A$ = "Y" Then Run
If A$ = "N" Then System
GoTo GetYorN
End If
End If


' Draw All 4 Dice Cubes
X2 = 359: For Z = 1 To 2: X1 = 1010: For Y = 1 To 2: X4 = Z: DiceX(Z, Y) = X1: DiceY(Z, Y) = X2: GoSub DrawDice: X1 = X1 + 128: Next: X2 = X2 + 128: Next

GoSub DrawButtons: GoSub ResetButtons

' Roll Dice
For Z = 1 To 12
For Y = 1 To 2
For X = 1 To 2
If Roll > 1 And RollDice(Y) = 0 GoTo RollLoop
X3 = Int(Rnd * 6) + 1: Dice(Y, X) = X3
X4 = Y: X1 = DiceX(Y, X): X2 = DiceY(Y, X): GoSub DrawDots
_Delay .05
RollLoop:
Next
Next
Next

SetupRowColumn:
If Dice(1, 1) = Dice(1, 2) Then Row = 0 Else Row = Dice(1, 1) + Dice(1, 2)
If Dice(2, 1) = Dice(2, 2) Then Column = 0 Else Column = Dice(2, 1) + Dice(2, 2)

' Place Cursors at Row and Column if not Wild
Color White&&
If Row > 0 Then
Line (RowX(Row, 1) - 19, RowY(Row, 1) - 19)-(RowX(Row, 1) + 19, RowY(Row, 1) + 19), , B
Line (RowX(Row, 2) - 19, RowY(Row, 2) - 19)-(RowX(Row, 2) + 19, RowY(Row, 2) + 19), , B
End If

If Column > 0 Then
Line (ColumnX(Column, 1) - 19, ColumnY(Column, 1) - 19)-(ColumnX(Column, 1) + 19, ColumnY(Column, 1) + 19), , B
Line (ColumnX(Column, 2) - 19, ColumnY(Column, 2) - 19)-(ColumnX(Column, 2) + 19, ColumnY(Column, 2) + 19), , B
End If

Playable = 0
If Row = 0 And Column = 0 Then
For Z = 3 To 11
For Y = 3 To 11
If BoardPlayer(Z, Y) <> Player And Blocked(Z, Y) = 0 Then Circle (BoardX(Z, Y), BoardY(Z, Y)), 27, White&&: Playable(Z, Y) = 1: Playable = 1
Next
Next
If Playable = 1 Then Color Black&&, Board&&: Locate 52, 120: Print " Place Your Ball On Any Playable Position on the Board. ";
ElseIf Row = 0 Then
For Z = 3 To 11
If BoardPlayer(Z, Column) <> Player And Blocked(Z, Column) = 0 Then Circle (BoardX(Z, Column), BoardY(Z, Y)), 27, White&&: Playable(Z, Column) = 1: Playable = 1
Next
If Playable = 1 Then Color Black&&, Board&&: Locate 52, 120: Print " Place Your Ball on Any Playable Row on Column "; LTrim$(Str$(Column)); ". ";
If Playable = 0 Then Color Black&&, Board&&: Locate 52, 120: Print " There are No Playable Rows on Column "; LTrim$(Str$(Column)); ". ";
ElseIf Column = 0 Then
For Z = 3 To 11
If BoardPlayer(Row, Z) <> Player And Blocked(Row, Z) = 0 Then Circle (BoardX(Row, Z), BoardY(Row, Z)), 27, White&&: Playable(Row, Z) = 1: Playable = 1
Next
If Playable = 1 Then Color Black&&, Board&&: Locate 52, 120: Print " Place Your Ball on Any Playable Column on Row "; LTrim$(Str$(Row)); ". ";
If Playable = 0 Then Color Black&&, Board&&: Locate 52, 120: Print " There are No Playable Columns on Row"; LTrim$(Str$(Row)); ". ";
Else
If BoardPlayer(Row, Column) <> Player And Blocked(Row, Column) = 0 Then Circle (BoardX(Row, Column), BoardY(Row, Column)), 27, White&&: Playable(Row, Column) = 1: Playable = 1
If Playable = 1 Then
If BoardPlayer(Row, Column) <> 0 And BoardPlayer(Row, Column) <> Player Then
Color Black&&, Board&&: Locate 52, 120: Print "You May Battle the Player at Position Row "; LTrim$(Str$(Row)); ", Column "; LTrim$(Str$(Column)); ". ";
Else
Color Black&&, Board&&: Locate 52, 120: Print " You May Place Your Ball at Position Row "; LTrim$(Str$(Row)); ", Column "; LTrim$(Str$(Column)); ". ";
End If
End If
If Playable = 0 Then Color Black&&, Board&&: Locate 52, 120: Print " The Position at Row "; LTrim$(Str$(Row)); ", Column"; Column; "is Blocked. ";
End If

If Roll = 1 Then Color Black&&, Board&&: Locate 54, 120: Print " Or Roll One or Both Pairs of Dice. ";
If Roll = 2 Then
If Playable = 0 Then
Color Black&&, Board&&: Locate 54, 120: Print " Press <ENTER> to Continue. ";
For Z = 1 To 15: A$ = InKey$: Next
Continue: A$ = InKey$: If A$ = "" GoTo Continue Else If Asc(A$) <> 13 GoTo Continue
GoSub RemoveCursors: GoTo EndTurn
Else
Color Black&&, Board&&: Locate 54, 120: Print " ";
End If
End If

GetMoveInput:
Do While _MouseInput
' Check Red Dice KEEP / ROLL Button
If _MouseX > 1261 And _MouseX < 1336 And _MouseY > 336 And _MouseY < 380 And _MouseButton(1) = -1 And Roll = 1 Then
GoSub MouseButtonRelease: Color Black&&, LtBoard&&: Locate 23, 160
If RedDiceButton = 0 Then RedDiceButton = 1: Print "R O L L"; Else RedDiceButton = 0: Print "K E E P";
GoSub UpdateRollButton: GoTo GetMoveInput
End If

' Check Blue Dice KEEP / ROLL Button
If _MouseX > 1261 And _MouseX < 1336 And _MouseY > 446 And _MouseY < 508 And _MouseButton(1) = -1 And Roll = 1 Then
GoSub MouseButtonRelease: Color Black&&, LtBoard&&: Locate 31, 160
If BlueDiceButton = 0 Then BlueDiceButton = 1: Print "R O L L"; Else BlueDiceButton = 0: Print "K E E P";
GoSub UpdateRollButton: GoTo GetMoveInput
End If

' Check Roll Dice Button
If _MouseX > 1094 And _MouseX < 1236 And _MouseY > 577 And _MouseY < 619 And _MouseButton(1) = -1 And DiceRollButton = 1 And Roll = 1 Then
GoSub MouseButtonRelease: Roll = Roll + 1: Color Black&&, Board&&: Locate 42, 141: Print "R O L L: "; Roll;
For Z = 1 To 20
For Y = 1 To 2
If RedDiceButton = 1 Then X3 = Int(Rnd * 6) + 1: Dice(1, Y) = X3: X4 = 1: X1 = DiceX(1, Y): X2 = DiceY(1, Y): GoSub DrawDots
If BlueDiceButton = 1 Then X3 = Int(Rnd * 6) + 1: Dice(2, Y) = X3: X4 = 2: X1 = DiceX(2, Y): X2 = DiceY(2, Y): GoSub DrawDots
_Delay .05
Next
Next
GoSub ResetButtons: GoSub RemoveCursors: GoTo SetupRowColumn
End If

' Check Board Locations and Place Ball
For Z = 3 To 11
For Y = 3 To 11
If _MouseX > BoardX(Z, Y) - 20 And _MouseX < BoardX(Z, Y) + 20 And _MouseY > BoardY(Z, Y) - 20 And _MouseY < BoardY(Z, Y) + 20 And _MouseButton(1) = -1 And Playable(Z, Y) = 1 Then
Row = Z: Column = Y: GoSub MouseButtonRelease: GoSub ResetButtons: GoSub RemoveCursors
If BoardPlayer(Z, Y) <> 0 And BoardPlayer(Z, Y) <> Player Then Circle (BoardX(Z, Y), BoardY(Z, Y)), 27, White&&: GoSub BattleEngaged: GoTo EndMoveInput
Paint (StorageX(Player, Pieces(Player)), StorageY(Player, Pieces(Player))), LtBoard&&: Pieces(Player) = Pieces(Player) - 1
BoardPlayer(Z, Y) = Player: X1 = BoardX(Z, Y): X2 = BoardY(Z, Y): X3 = Player: GoSub DrawBall: GoTo EndMoveInput
End If
Next
Next
Loop
GoTo GetMoveInput

EndMoveInput:
' Check for Player's Three in a Rows
Score(Player) = 0
For Z = 3 To 11
For Y = 3 To 9
If BoardPlayer(Z, Y) = Player And BoardPlayer(Z, Y + 1) = Player And BoardPlayer(Z, Y + 2) = Player Then Score(Player) = Score(Player) + 1: Blocked(Z, Y) = 1: Blocked(Z, Y + 1) = 1: Blocked(Z, Y + 2) = 1
If BoardPlayer(Y, Z) = Player And BoardPlayer(Y + 1, Z) = Player And BoardPlayer(Y + 2, Z) = Player Then Score(Player) = Score(Player) + 1: Blocked(Y, Z) = 1: Blocked(Y + 1, Z) = 1: Blocked(Y + 2, Z) = 1
Next
Next
For Z = 3 To 9
For Y = 3 To 9
If BoardPlayer(Z, Y) = Player And BoardPlayer(Z + 1, Y + 1) = Player And BoardPlayer(Z + 2, Y + 2) = Player Then Score(Player) = Score(Player) + 1: Blocked(Z, Y) = 1: Blocked(Z + 1, Y + 1) = 1: Blocked(Z + 2, Y + 2) = 1
If BoardPlayer(Z, Y + 2) = Player And BoardPlayer(Z + 1, Y + 1) = Player And BoardPlayer(Z + 2, Y) = Player Then Score(Player) = Score(Player) + 1: Blocked(Z, Y + 2) = 1: Blocked(Z + 1, Y + 1) = 1: Blocked(Z + 2, Y) = 1
Next
Next

GoSub UpdatePegs

EndTurn:
Roll = 1: GoSub ResetButtons

If NextTurn = 1 Then
If Score(Player) > 0 Then
X1 = 1165: X2 = 180: X3 = Player: GoSub DrawBall
Color Black&&, Board&&: Locate 14, 143: Print "Player"; Winner(1)
Color Black&&, Board&&: Locate 52, 120: Print " Player"; Player; "is the Winner!!! ";
Color Black&&, Board&&: Locate 54, 120: Print " Play Another Game? ( Y or N ) ";
For Z = 1 To 15: A$ = InKey$: Next
YorN: A$ = UCase$(InKey$): If A$ = "" GoTo YorN
If A$ = "Y" Then Run
If A$ = "N" Then System
GoTo YorN
End If
If Counter = Winners Then Counter = 1 Else Counter = Counter + 1
Player = Winner(Counter)
Else
If Player = Players Then Player = 1 Else Player = Player + 1
End If

GoTo StartTurn


MouseButtonRelease:
Do While _MouseInput
If _MouseButton(1) = 0 Then Return
Loop
GoTo MouseButtonRelease


DrawBall:
Color PlayerColor&&(X3)
Circle (X1, X2), 20: Paint (X1, X2)
Circle (X1 - 6, X2 - 6), 3, White&&: Paint (X1 - 6, X2 - 6), White&&

Return


PlaceBalls:
If Players = 2 Then
Pieces(1) = 24: Pieces(2) = 24
X = 0: V = 24
For Z = 1 To 23 Step 2
X3 = 2: X1 = 153 + X: X2 = 66: GoSub DrawBall: StorageX(2, V) = X1: StorageY(2, V) = X2
X1 = 178 + X: X2 = 100: GoSub DrawBall: StorageX(2, V - 1) = X1: StorageY(2, V - 1) = X2
X3 = 1: X1 = 178 + X: X2 = 814: GoSub DrawBall: StorageX(1, Z + 1) = X1: StorageY(1, Z + 1) = X2
X1 = 153 + X: X2 = 780: GoSub DrawBall: StorageX(1, Z) = X1: StorageY(1, Z) = X2
X = X + 50: V = V - 2
_Delay .025
Next
ElseIf Players = 3 Then
Pieces(1) = 16: Pieces(2) = 16: Pieces(3) = 16
X = 0: V = 16
For Z = 1 To 15 Step 2
X3 = 2: X1 = 161 + X: X2 = 66: GoSub DrawBall: StorageX(2, V) = X1: StorageY(2, V) = X2
X1 = 198 + X: X2 = 100: GoSub DrawBall: StorageX(2, V - 1) = X1: StorageY(2, V - 1) = X2
X3 = 1: X1 = 198 + X: X2 = 814: GoSub DrawBall: StorageX(1, Z + 1) = X1: StorageY(1, Z + 1) = X2
X1 = 161 + X: X2 = 780: GoSub DrawBall: StorageX(1, Z) = X1: StorageY(1, Z) = X2
X3 = 3: X1 = 66: X2 = 198 + X: GoSub DrawBall: StorageX(3, Z + 1) = X1: StorageY(3, Z + 1) = X2
X1 = 100: X2 = 161 + X: GoSub DrawBall: StorageX(3, Z) = X1: StorageY(3, Z) = X2
X = X + 75: V = V - 2
_Delay .025
Next
Else
X = 0: V = 12
Pieces(1) = 12: Pieces(2) = 12: Pieces(3) = 12: Pieces(4) = 12
For Z = 1 To 12
X3 = 2: X1 = 154 + X: X2 = 83: GoSub DrawBall: StorageX(2, V) = X1: StorageY(2, V) = X2
X3 = 1: X1 = 154 + X: X2 = 797: GoSub DrawBall: StorageX(1, Z) = X1: StorageY(1, Z) = X2
X3 = 3: X1 = 83: X2 = 154 + X: GoSub DrawBall: StorageX(3, Z) = X1: StorageY(3, Z) = X2
X3 = 4: X1 = 797: X2 = 154 + X: GoSub DrawBall: StorageX(4, V) = X1: StorageY(4, V) = X2
X = X + 52: V = V - 1
_Delay .025
Next
End If
Return


ClearBoard:
For Z = 3 To 11
For Y = 3 To 11
BoardPlayer(Z, Y) = 0: Blocked(Z, Y) = 0: Playable(Z, Y) = 0: X1 = BoardX(Z, Y): X2 = BoardY(Z, Y): Color Board&&: Paint (X1, X2): GoSub DrawDimple
Next
Next
Return


DrawDimple:
Circle (X1, X2), 15, LtBoard&&: Paint (X1, X2), LtBoard&&

Return


UpdatePegs:
' Setup Peg Hole Locations
X = 0: V = 0
If Players = 2 And NextTurn = 0 Then X5 = 40: X6 = 840: r = 7 Else X5 = 160: X6 = 720: r = 5
For Z = 1 To r
W = 0
For Y = 1 To 5
PlayerPegX(1, V) = X5 + W + X: PlayerPegY(1, V) = 854
PlayerPegX(2, V) = X6 - W - X: PlayerPegY(2, V) = 26
PlayerPegX(3, V) = 26: PlayerPegY(3, V) = 160 + W + X
PlayerPegX(4, V) = 854: PlayerPegY(4, V) = 720 - W - X
W = W + 20: V = V + 1
Next
X = X + 120
Next


For Z = 1 To 4
If r = 7 And Z < 3 Then s = 34 Else s = 24
For Y = 0 To s
If Score(Z) = Y And Z <= Players Then T = 1: Color White&& Else T = 0: Color DkBoard&&
If NextTurn = 1 Then
If T = 1 Then
X = 0
For W = 1 To Winners
If Z = Winner(W) Then X = 1
Next
If X = 0 Then Color DkBoard&&
End If
End If
Circle (PlayerPegX(Z, Y), PlayerPegY(Z, Y)), 5: Paint (PlayerPegX(Z, Y), PlayerPegY(Z, Y))
_Delay .01
Next
Next
Return


UpdateRollButton:
If Roll = 1 Then
If RedDiceButton = 1 Or BlueDiceButton = 1 Then DiceRollButton = 1: Color Black&&, LtBoard&& Else RollDiceButton = 0: Color White&&, LtBoard&&
Else
Color White&&, LtBoard&&
End If
Locate 38, 138: Print "R O L L D I C E";
Return


ResetButtons:
RedDiceButton = 0: BlueDiceButton = 0: RollDiceButton = 0
Color Black&&, LtBoard&&: Locate 23, 160: Print "K E E P";
Color Black&&, LtBoard&&: Locate 31, 160: Print "K E E P";
Color White&&, LtBoard&&: Locate 38, 138: Print "R O L L D I C E";
Return


DrawButtons:
' Draw ROLL DICE Button
Color LtBoard&&: Circle (1095, 598), 20, , 1.5, 4.8: Circle (1235, 598), 20, , 4.6, 1.6
Line (1095, 578)-(1235, 578): Line (1095, 618)-(1235, 618): Paint (1165, 583)

' Draw Red Dice KEEP / Roll Button
Color LtBoard&&: Circle (1262, 359), 20, , 1.5, 4.8: Circle (1335, 359), 20, , 4.6, 1.6
Line (1262, 339)-(1335, 339): Line (1262, 379)-(1335, 379): Paint (1290, 344)

' Draw Blue Dice KEEP / ROLL Button
Color LtBoard&&: Circle (1262, 487), 20, , 1.5, 4.8: Circle (1335, 487), 20, , 4.6, 1.6
Line (1262, 467)-(1335, 467): Line (1262, 507)-(1335, 507): Paint (1290, 472)
Return


DrawDice:
If X4 = 1 Then Color RedDice&& Else Color BlueDice&&
Circle (X1 - 25, X2 - 25), 10, , 1.50, 3.10: Circle (X1 + 25, X2 - 25), 10, , 0, 1.6
Circle (X1 - 25, X2 + 25), 10, , 3.1, 4.75: Circle (X1 + 25, X2 + 25), 10, , 4.5, 0
Line (X1 - 25, X2 - 35)-(X1 + 25, X2 - 35): Line (X1 - 25, X2 + 35)-(X1 + 25, X2 + 35)
Line (X1 - 35, X2 - 25)-(X1 - 35, X2 + 25): Line (X1 + 35, X2 - 25)-(X1 + 35, X2 + 25)
Paint (X1, X2)
Return


DrawDots:
If X4 = 1 Then Color RedDice&& Else Color BlueDice&&
Line (X1 - 25, X2 - 25)-(X1 + 25, X2 + 25), , BF: Color White&&
If X3 = 1 Or X3 = 3 Or X3 = 5 Then Circle (X1, X2), 5: Paint (X1, X2)
If X3 > 1 Then Circle (X1 - 18, X2 - 18), 5: Paint (X1 - 18, X2 - 18): Circle (X1 + 18, X2 + 18), 5: Paint (X1 + 18, X2 + 18)
If X3 > 3 Then Circle (X1 + 18, X2 - 18), 5: Paint (X1 + 18, X2 - 18): Circle (X1 - 18, X2 + 18), 5: Paint (X1 - 18, X2 + 18)
If X3 = 6 Then Circle (X1 - 18, X2), 5: Paint (X1 - 18, X2): Circle (X1 + 18, X2), 5: Paint (X1 + 18, X2)
Return

RemoveCursors:
Color Board&&: Playable = 0
For r = 11 To 3 Step -1: For s = 3 To 11: Playable(r, s) = 0: Circle (BoardX(r, s), BoardY(r, s)), 27, Board&&: Next: Next
For r = 3 To 11
For s = 1 To 2
Line (RowX(r, s) - 19, RowY(r, s) - 19)-(RowX(r, s) + 19, RowY(r, s) + 19), , B
Line (ColumnX(r, s) - 19, ColumnY(r, s) - 19)-(ColumnX(r, s) + 19, ColumnY(r, s) + 19), , B
Next
Next
Return


BattleEngaged:
Line (912, 71)-(1419, 879), Board&&, BF

AttackerPlayer = Player: DefenderPlayer = BoardPlayer(Row, Column)
Color White&&, Board&&: Locate 7, 127: Print "B A T T L E E N G A G E D";

Color White&&, Board&&: Locate 13, 138: Print "A T T A C K E R :";
Color PlayerColor&&(AttackerPlayer): X1 = 1165: X2 = 240: X3 = AttackerPlayer: GoSub DrawBall
Color Black&&, Board&&: Locate 18, 143: Print "Player"; AttackerPlayer;

Color White&&, Board&&: Locate 38, 138: Print "D E F E N D E R :";
Color PlayerColor&&(DefenderPlayer): X1 = 1165: X2 = 639: X3 = DefenderPlayer: GoSub DrawBall
Color Black&&, Board&&: Locate 43, 143: Print "Player"; DefenderPlayer;

X2 = 350: For Z = 1 To 2: X1 = 1045: For Y = 1 To 3: X4 = Z: BattleDiceX(Z, Y) = X1: BattleDiceY(Z, Y) = X2: GoSub DrawDice: X1 = X1 + 120: Next: X2 = X2 + 178: Next

Color LtBoard&&: Circle (1095, 439), 20, , 1.5, 4.8: Circle (1235, 439), 20, , 4.6, 1.6
Line (1095, 419)-(1235, 419): Line (1095, 459)-(1235, 459): Paint (1165, 439)
Color Black&&, LtBoard&&: Locate 28, 138: Print "R O L L D I C E";

For BattleRoll = 1 To 3
Color Black&&, Board&&: Locate 49, 134: Print "B A T T L E R O L L # ";: Print BattleRoll;
For BattlePlayer = 1 To 2
Color White&&, Board&&: Locate 52, 132: Print BattleMessage1$(BattlePlayer, BattleRoll);
Color White&&, Board&&: Locate 54, 132: Print BattleMessage2$(BattlePlayer, BattleRoll);

If BattlePlayer = 1 Then AttackerColor&& = Background&&: DefenderColor&& = Board&& Else AttackerColor&& = Board&&: DefenderColor&& = Background&&
Line (995, 300)-(1335, 400), AttackerColor&&, B: Line (995, 478)-(1335, 578), DefenderColor&&, B

GetRollDice:
Do While _MouseInput
' Check Roll Dice Button
If _MouseX > 1094 And _MouseX < 1236 And _MouseY > 418 And _MouseY < 460 And _MouseButton(1) = -1 Then GoSub MouseButtonRelease: GoTo BattleRoll
' Check Select Dice
If BattleRoll > 1 Then
For Dice = 1 To 3
If _MouseX > BattleDiceX(BattlePlayer, Dice) - 36 And _MouseX < BattleDiceX(BattlePlayer, Dice) + 36 And _MouseY > BattleDiceY(BattlePlayer, Dice) - 36 And _MouseY < BattleDiceY(BattlePlayer, Dice) + 36 And _MouseButton(1) = -1 Then SelectedDice = Dice: GoSub MouseButtonRelease: GoTo SelectDice
Next
End If
Loop
GoTo GetRollDice

SelectDice:
If SelectedDice(BattlePlayer, SelectedDice) = 1 Then SelectedDice(BattlePlayer, SelectedDice) = 0: Color Board&& Else SelectedDice(BattlePlayer, SelectedDice) = 1: Color White&&
Line (BattleDiceX(BattlePlayer, SelectedDice) - 42, BattleDiceY(BattlePlayer, SelectedDice) - 42)-(BattleDiceX(BattlePlayer, SelectedDice) + 42, BattleDiceY(BattlePlayer, SelectedDice) + 42), , B
GoTo GetRollDice

BattleRoll:
For Z = 1 To 20
For Y = 1 To 3
If BattleRoll > 1 And SelectedDice(BattlePlayer, Y) = 1 GoTo EndRollLoop
X3 = Int(Rnd * 6) + 1: BattleDice(BattlePlayer, Y) = X3
X4 = BattlePlayer: X1 = BattleDiceX(BattlePlayer, Y): X2 = BattleDiceY(BattlePlayer, Y): GoSub DrawDots
_Delay .05
EndRollLoop:
Next
Next

For Z = 1 To 3
SelectedDice(BattlePlayer, Z) = 0
Line (BattleDiceX(BattlePlayer, Z) - 42, BattleDiceY(BattlePlayer, Z) - 42)-(BattleDiceX(BattlePlayer, Z) + 42, BattleDiceY(BattlePlayer, Z) + 42), Board&&, B
Next

EndBattleLoop:
Next
Next

BattleTotal(1) = 0: BattleTotal(2) = 0: For Z = 1 To 2: For Y = 1 To 3: BattleTotal(Z) = BattleTotal(Z) + BattleDice(Z, Y): Next: Next

If BattleTotal(1) > BattleTotal(2) Then BattleWinner = 1 Else BattleWinner = 2

Color White&&, Board&&: Locate 52, 132: Print BattleWinner$(BattleWinner);
Color White&&, Board&&: Locate 54, 132: Print PressEnter$;

For Z = 1 To 15: A$ = InKey$: Next
WinnerEnter: A$ = InKey$: If A$ = "" GoTo WinnerEnter Else If Asc(A$) <> 13 GoTo WinnerEnter

If BattleWinner = 1 Then
BoardPlayer(Row, Column) = Player: X1 = BoardX(Row, Column): X2 = BoardY(Row, Column): X3 = AttackerPlayer: GoSub DrawBall
Paint (StorageX(Player, Pieces(Player)), StorageY(Player, Pieces(Player))), LtBoard&&: Pieces(Player) = Pieces(Player) - 1
End If

Line (912, 71)-(1419, 879), Board&&, BF: Circle (BoardX(Row, Column), BoardY(Row, Column)), 27, Board&&
Return

Print this item

  Laser Chess Board Game
Posted by: SMcNeill - 12-24-2023, 10:26 AM - Forum: Donald Foster - Replies (3)

Quote:Laser Chess

Laser Chess is a computer board game releasedin 1987. Many different versions hasbeen released over the years in pc and real board game form with different pieces and different rules. This is my take on the original version.

The objectof the game is to either capture or destroy your enemy’s King. Most of the game is spent arranging mirrors to set up to fire your Laser. All the pieces the same 1 space up, down, right or left. Each turn consist of 2 moves. a move consist of moving a pieces or rotating a piece or firing your laser. You can rotate a pieces and moves it to a new location in 1 turn counts as 2 moves. On a turn you also move 2 separate pieces or moves 1 piece twice. All pieces can be rotated except the King and the Hyper-cube.

Only the King and the Block can capture an enemy’s piece.All pieces can be captured except the Hypercube. The Hypercube also can not be destroyed. The Hypercube when placed onto another piece, it causes that piece to disappear and re-appear at a random vacant location on the board. The Hypercube can only be used once per turn. The Triangle Mirror deflects the beam 90 degrees. The Triangle Mirror can be destroyed if hit at 1 of the non-mirror sides. The Diagonal Mirror also deflect the beam 90 degrees, bu can not be destroyed. The Block has a mirror on 1 side and can be hit on the other 3 sides. Again, the Block can captures enemy pieces. Then Straight Mirror can not be destroyed. If the Straight Mirror or the Block is hit straight on, the beam is returned by to the source and the Laser that fired the beam is destroyed.

The center of the board is called the Hyper Square and isa fixed Hypercube. When a piece lands in the Hyper Square, that piece is transported to a random vacant location.

I used a code snippet by bplus to enlarge the size of the characters.

Donald

   


.docx   Laser Chess Rules.docx (Size: 49.68 KB / Downloads: 43)

Code: (Select All)
_Title "Laser Chess - Designed by Mike Duppong 1987 - Programmed by Donald L. Foster Jr. 2018 - Code Sniplet by bplus"

' Laser Chess was released in COMPUTE! magazine 1987. Code listed in BASIC and Machine Language for Amiga, Commodore 64, Apple II, and Atari 8-bit family.
' I got a copy of it around 1989 that ran on the IBC PC version. I started making this game in 1989, but did not complete it.
' It has been re-made with different names, different pieces and with different rules.
' Back then I thought about making the real board game, but never got around to it. I was even going to attemp to make a 3D real board game 9 x 9 x 9.
' The mirrors would not only reflect the beam horizontal and vertical, but up and down then levels also.
' I used a code siplet by bplus to enlarge the characters on the screen.

Screen _NewImage(1014, 735, 256)

_PaletteColor 1, _RGB32(255, 128, 0) ' Backgraound
_PaletteColor 2, _RGB32(0, 152, 254) ' Blue Square
_PaletteColor 3, _RGB32(128, 0, 128) ' Purple Piece
_PaletteColor 4, _RGB32(0, 0, 200) ' Green Piece
_PaletteColor 5, _RGB32(255, 0, 0) ' Laser Beam
_PaletteColor 6, _RGB32(40, 40, 40) ' Light Grey
_PaletteColor 7, _RGB32(20, 20, 20) ' Dark Grey
_PaletteColor 8, _RGB32(255, 255, 0) ' Yellow

_Limit 10

Randomize Timer

DefInt A-Z

Dim Hit$(10)

Player = 1: Opponent = 2

PlayerColor(1) = 3: PlayerColor(2) = 4

PieceRotations(1) = 4: PieceRotations(2) = 2: PieceRotations(3) = 2: PieceRotations(4) = 4: PieceRotations(5) = 4: PieceRotations(6) = 1: PieceRotations(7) = 4: PieceRotations(8) = 1

' Setup Board Players
For Z = 1 To 9: BoardPlayer(1, Z) = 2: BoardPlayer(2, Z) = 2: BoardPlayer(8, Z) = 1: BoardPlayer(9, Z) = 1: Next

' Setup Board Pieces
Data 1,1,1,1,1,4,4,1,3,4,4,3,7,5,2,6,8,2,2,8,6,2,5,7,3,4,4,3,1,4,4,1,1,1,1,1
For Z = 1 To 9: Read BoardPiece(1, Z), BoardPiece(2, Z), BoardPiece(8, Z), BoardPiece(9, Z): Next

' Setup Board Rotate
Data 4,3,2,1,4,4,2,1,2,4,2,1,2,2,2,1,1,1,1,1,1,2,4,4,1,4,2,2,3,4,2,2,3,4,1,2
For Z = 1 To 9: Read BoardRotate(1, Z), BoardRotate(2, Z), BoardRotate(8, Z), BoardRotate(9, Z): Next

Rotate$(1) = "TA0": Rotate$(2) = "TA90": Rotate$(3) = "TA180": Rotate$(4) = "TA270"

HyperSquare$ = "BU33BL33C15D66R66U66L66BF3D60R60U60L60BH1P15,15"

Piece$(1, 1) = "BL29BU22C3D50R50H50BD5BR2P3,3L2U5E1C15F50": Piece$(2, 1) = "BL29BU23C4D50R50H50BD5BR2P4,4L2U5E1C15F50"
Piece$(1, 2) = "BL33C3D2R66U4L66D2BR2P3,3L2D3C15R66BU6L66": Piece$(2, 2) = "BL33C4D2R66U4L66D2BR2P4,4L2D3C15R66BU6L66"
Piece$(1, 3) = "BG30C3F1E60H2G60BR2P3,3L2F3C15E60BH4G60": Piece$(2, 3) = "BG30C4F1E60H2G60BR2P4,4L2F3C15E60BH4G60"
Piece$(1, 4) = "BR28BD29C3U58L57D58R57BH5P3,3F5C15U58": Piece$(2, 4) = "BR28BD29C4U58L57D58R57BH5P4,4F5C15U58"
Piece$(1, 5) = "BL29BD25C3E25H25D50BU5BR2P3,3L2D5F1C15E26H26": Piece$(2, 5) = "BL29BD25C4E25H25D50BU5BR2P4,4L2D5F1C15E26H26"
Piece$(1, 6) = "TA0BU33BL33C3D66R66U66L66BF3D60R60U60L60BH1P3,3": Piece$(2, 6) = "TA0BU33BL33C4D66R66U66L66BF3D60R60U60L60BH1P4,4"
Piece$(1, 7) = "BR29C3D25H22L23U6R23E22D25BL5P3,3": Piece$(2, 7) = "BR29C4D25H22L23U6R23E22D25BL 5P4,4"
Piece$(1, 8) = "TA0BU33C3G33F33E33H33BD7BL2G24R24U24BR4F24L24U24BD28D24E24L24BL4L24F24U24BR2P3,3": Piece$(2, 8) = "TA0BU33C4G33F33E33H33BD7BL2G24R24U24BR4F24L24U24BD28D24E24L24BL4L24F24U24BR2P4,4"

LaserBeam$(1) = "BL17BD1C5L21U2R21D2BH1P5,5" ' Fire Laser
LaserBeam$(2) = "BL38BD1C5R77U2L77D2BE1P5,5BR70P5,5" ' Straight Through
LaserBeam$(3) = "BR38BD1C5L8U2R8D2BH1P5,5" ' Side of Block and Triangle Hit
LaserBeam$(4) = "BR38BD1C5L5U2R5D2BH1P5,5" 'King Hit
LaserBeam$(5) = "BR38BD1C5L39U39R2D37R37D2BH1P5,5" ' Triangle Piece Deflection
LaserBeam$(6) = "BR38BD1C5L31H9U31R2D32U3BL1P5,5R1D3F6R32D2BH1P5,5" ' Diagnol Piece Deflection
LaserBeam$(7) = "BR38BD1C5U2L37U37L2D77R2U38R37BH1P5,5" ' Full Beam Splitter
LaserBeam$(8) = "BR38BD1C5L34U2R34D2BH1P5,5" ' Laser Side Hit
LaserBeam$(9) = "BR38BD1C5L34U2R34D2BH1P5,5" ' Hit Side on Straight Mirror

Cursor$ = "BU38BL38D76R76U76L75D75R74U74L74"

Hit$(0) = " N O N E "
Hit$(1) = " Opponent's King "
Hit$(2) = " Your King "
Hit$(3) = " Opponent's Laser "
Hit$(4) = " Your Laser "
Hit$(5) = "Opponent's Beam Splitter"
Hit$(6) = " Your Beam Splitter "
Hit$(7) = " Opponent's Block "
Hit$(8) = " Your Block "
Hit$(9) = " Opponent's Mirror "
Hit$(10) = " Your Mirror "

Message$ = " LASER CHESS ": X1 = 95: X2 = 200: X3 = 15: X4 = 8: X5 = 4: GoSub DrawMessage
Message$ = " START ": X1 = 400: X2 = 400: X3 = 8: X4 = 4: X5 = 5: GoSub DrawMessage

Line (0, 0)-(100, 30), 0, BF: Circle (920, 252), 20, 5: Paint (920, 251), 5: Line (0, 249)-(900, 254), 5, BF

PressStartMouseInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)

If (MouseX > 414) * (MouseX < 606) * (MouseY > 390) * (MouseY < 465) Then
CanSelect = 1: Line (414, 390)-(606, 465), 15, B
Else
CanSelect = 0: Line (414, 390)-(606, 465), 0, B
End If
If (MouseLeftButton = -1) * (CanSelect = 1) Then GoSub ReleaseMouseButton: GoTo Start

Loop
GoTo PressStartMouseInput

Start:

Cls , 1 ' Set Background Color
Line (770, 662)-(970, 712), 7, BF

Message$ = " LASER": X1 = 705: X2 = 0: X3 = 0: X4 = 6: X5 = 1: GoSub DrawMessage
Message$ = " CHESS": X1 = 705: X2 = 70: X3 = 15: X4 = 6: X5 = 2: GoSub DrawMessage
Message$ = " Fire Laser": X1 = 775: X2 = 673: X3 = 5: X4 = 2: X5 = 3: GoSub DrawMessage

Line (0, 0)-(100, 30), 1, BF: Circle (1000, 38), 8, 5: Paint (1000, 38), 5: Line (726, 37)-(1000, 39), 5, BF

' Draw Fire Laser Button
PSet (970, 662), 7: Draw "L200D50NG10R200U50E10L220D70R220U70BL10BD8P6,7BR8P0,7"

' Draw Board
Line (10, 10)-(725, 725), 15, BF: Line (15, 15)-(720, 720), 0, BF
X = 60
For Z = 1 To 9
V = 60
For Y = 1 To 9
If (Z + Y) / 2 = Int((Z + Y) / 2) Then T = 2: X6 = 2 Else T = 0: X6 = 0
Line (V - 38, X - 38)-(V + 38, X + 38), T, BF
If BoardPlayer(Z, Y) > 0 Then X1 = V: X2 = X: X3 = BoardPlayer(Z, Y): X4 = BoardPiece(Z, Y): X5 = BoardRotate(Z, Y): GoSub DrawPiece
If Z = 5 And Y = 5 Then PSet (V, X), 2: Draw HyperSquare$
BoardX(Z, Y) = V: BoardY(Z, Y) = X
V = V + 77
Next
X = X + 77
Next

StartGame:
MovesLeft = 2: LaserFired = 0: HyperSquare = 0

' Display Player Indicators
X1 = 766: X2 = 613: X3 = Player: X4 = 7: X5 = 4: X6 = 1: GoSub DrawPiece
X1 = 765: X2 = 182: X3 = Player: X4 = 1: X5 = 4: X6 = 1: GoSub DrawPiece
X1 = 975: X2 = 182: X3 = Player: X4 = 1: X5 = 3: X6 = 1: GoSub DrawPiece
X1 = 974: X2 = 613: X3 = Opponent: X4 = 8: X5 = 2: X6 = 1: GoSub DrawPiece
PSet (765, 596), 5: Draw "U416R210D401L2U399L206D414L2BE1P5,5"

Color 0, 1: Locate 14, 106: Print "Player"; Player;

MovesLeft: Color 0, 1: Locate 40, 103: Print "Moves Left:"; MovesLeft;

' Set All Playable Moves to 0
For Z = 1 To 9: For Y = 1 To 9: Playable(Z, Y) = 0: Next: Next

Color 0, 1: Locate 16, 101: Print " Choose a Piece ";
Color 0, 1: Locate 18, 101: Print " or Fire Laser ";

ChooseAPieceInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)

If MouseLeftButton = -1 And LaserFired = 0 And MouseX > 759 And MouseX < 981 And MouseY > 651 And MouseY < 723 Then GoSub ReleaseMouseButton: GoTo FireLaser

For Z = 1 To 9
For Y = 1 To 9
If (MouseLeftButton = -1) * (MouseX > BoardX(Z, Y) - 38) * (MouseX < BoardX(Z, Y) + 38) * (MouseY > BoardY(Z, Y) - 38) * (MouseY < BoardY(Z, Y) + 38) Then
If BoardPlayer(Z, Y) = Player Then Row1 = Z: Column1 = Y: GoSub ReleaseMouseButton: GoTo EndChoice1
End If
Next
Next
Loop
GoTo ChooseAPieceInput

EndChoice1:

Piece = BoardPiece(Row1, Column1)
Rotate = BoardRotate(Row1, Column1)
Rotations = PieceRotations(BoardPiece(Row1, Column1))
BoardX1 = BoardX(Row1, Column1): BoardY1 = BoardY(Row1, Column1)

' Get Board Square Color
If (Row1 + Column1) / 2 = Fix((Row1 + Column1) / 2) Then SquareColor1 = 2 Else SquareColor1 = 0

' Check Playable Moves
Playable(Row1, Column1) = 1

If Column1 - 1 >= 1 Then
If Row1 = 5 And Column1 - 1 = 5 Then Playable(5, 5) = 1
If BoardPiece(Row1, Column1) = 6 Then Playable(Row1, Column1 - 1) = 1
If BoardPlayer(Row1, Column1 - 1) = 0 Then Playable(Row1, Column1 - 1) = 1
If (BoardPiece(Row1, Column1) = 4 Or BoardPiece(Row1, Column1) = 8) And BoardPlayer(Row1, Column1 - 1) <> Player Then Playable(Row1, Column1 - 1) = 1
End If

If Row1 + 1 <= 9 Then
If Row1 + 1 = 5 And Column1 = 5 Then Playable(5, 5) = 1
If BoardPiece(Row1, Column1) = 6 Then Playable(Row1 + 1, Column1) = 1
If BoardPlayer(Row1 + 1, Column1) = 0 Then Playable(Row1 + 1, Column1) = 1
If (BoardPiece(Row1, Column1) = 4 Or BoardPiece(Row1, Column1) = 8) And BoardPlayer(Row1 + 1, Column1) <> Player Then Playable(Row1 + 1, Column1) = 1
End If

If Column1 + 1 <= 9 Then
If Row1 = 5 And Column1 + 1 = 5 Then Playable(5, 5) = 1
If BoardPiece(Row1, Column1) = 6 Then Playable(Row1, Column1 + 1) = 1
If BoardPlayer(Row1, Column1 + 1) = 0 Then Playable(Row1, Column1 + 1) = 1
If (BoardPiece(Row1, Column1) = 4 Or BoardPiece(Row1, Column1) = 8) And BoardPlayer(Row1, Column1 + 1) <> Player Then Playable(Row1, Column1 + 1) = 1
End If

If Row1 - 1 >= 1 Then
If Row1 - 1 = 5 And Column1 = 5 Then Playable(5, 5) = 1
If BoardPiece(Row1, Column1) = 6 Then Playable(Row1 - 1, Column1) = 1
If BoardPlayer(Row1 - 1, Column1) = 0 Then Playable(Row1 - 1, Column1) = 1
If (BoardPiece(Row1, Column1) = 4 Or BoardPiece(Row1, Column1) = 8) And BoardPlayer(Row1 - 1, Column1) <> Player Then Playable(Row1 - 1, Column1) = 1
End If

PSet (BoardX1, BoardY1), Point(BoardX1, BoardY1): Draw "C15" + Cursor$

' Check If Piece Can Be Rotated
If Rotations > 1 Then
Color 0, 1: Locate 16, 101: Print "Choose a Rotation";
Color 0, 1: Locate 18, 101: Print " ";

X = 307
For Z = 1 To Rotations
X1 = 869: X2 = X: X3 = Player: X4 = Piece: X5 = Z: X6 = 1: GoSub DrawPiece
B(Z) = X: X = X + 90
Next

GetRotationMouseInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)

For Z = 1 To Rotations
If (MouseX > 831) * (MouseX < 908) * (MouseY > B(Z) - 39) * (MouseY < B(Z) + 39) Then
CanSelect = 1: Line (831, B(Z) - 38)-(907, B(Z) + 38), 15, B
Else
CanSelect = 0: Line (831, B(Z) - 38)-(907, B(Z) + 38), 1, B
End If
If (MouseLeftButton = -1) * (CanSelect = 1) Then Rotation = Z: GoSub ReleaseMouseButton: GoTo EndChoice2
Next
Loop
GoTo GetRotationMouseInput

EndChoice2:
If Rotation <> Rotate Then MovesLeft = MovesLeft - 1: Color 0, 1: Locate 40, 103: Print "Moves Left:"; MovesLeft;

If MovesLeft = 0 Then
' Remove Piece Rotations
Line (831, 269)-(907, 630), 1, BF

' Set Current Piece To New Rotation Position
BoardRotate(Row1, Column1) = Rotation

' Remove Cursor and Piece From Current Location
Line (BoardX1 - 38, BoardY1 - 38)-(BoardX1 + 38, BoardY1 + 38), SquareColor1, BF

' Redraw Piece in Current Position With New Rotation
X1 = BoardX1: X2 = BoardY1: X3 = Player: X4 = Piece: X5 = Rotation: X6 = SquareColor1: GoSub DrawPiece: GoTo EndTurn
End If

Else Rotation = Rotate

End If

Color 0, 1: Locate 16, 101: Print "Choose a Location";
'COLOR 0, 1: LOCATE 18, 101: PRINT " ";

ChooseALocationInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)
If MouseLeftButton = -1 And MouseX > 759 And MouseX < 981 And MouseY > 651 And MouseY < 723 Then GoSub ReleaseMouseButton: GoTo FireLaser
For Z = 1 To 9
For Y = 1 To 9
If (MouseLeftButton = -1) * (MouseX > BoardX(Z, Y) - 38) * (MouseX < BoardX(Z, Y) + 38) * (MouseY > BoardY(Z, Y) - 38) * (MouseY < BoardY(Z, Y) + 38) Then
If Playable(Z, Y) = 1 Then Row2 = Z: Column2 = Y: GoSub ReleaseMouseButton: GoTo EndChoice3
End If
Next
Next
Loop
GoTo ChooseALocationInput

EndChoice3:
BoardX2 = BoardX(Row2, Column2): BoardY2 = BoardY(Row2, Column2)
If (Row2 + Column2) / 2 = Fix((Row2 + Column2) / 2) Then SquareColor2 = 2 Else SquareColor2 = 0

' Get New Location Information
Player2 = BoardPlayer(Row2, Column2): Piece2 = BoardPiece(Row2, Column2): Rotate2 = BoardRotate(Row2, Column2)

' Piece stayed at Same Location
If Row2 = Row1 And Column2 = Column1 Then
Line (BoardX1 - 38, BoardY1 - 38)-(BoardX1 + 38, BoardY1 + 38), SquareColor1, BF
BoardRotate(Row2, Column2) = Rotation: X1 = BoardX2: X2 = BoardY2: X3 = Player: X4 = Piece: X5 = Rotation: X6 = SquareColor1: GoSub DrawPiece
Line (831, 269)-(907, 630), 1, BF: GoTo MovesLeft
End If

' Check if Move is HyperCuber or Hyper Square
If BoardPiece(Row1, Column1) = 6 Or (Row2 = 5 And Column2 = 5) Then
X = 0
While (X = 0)
Row3 = Int(Rnd * 9) + 1: Column3 = Int(Rnd * 9) + 1: If BoardPlayer(Row3, Column3) = 0 Then X = 1
If Row3 = 5 And Column3 = 5 Then X = 0
Wend

BoardX3 = BoardX(Row3, Column3): BoardY3 = BoardY(Row3, Column3)
If (Row3 + Column3) / 2 = Fix((Row3 + Column3) / 2) Then SquareColor3 = 2: C$ = "C2" Else SquareColor3 = 0: C$ = "C0"

If BoardPiece(Row1, Column1) = 6 Then
BoardPlayer(Row3, Column3) = Player2: BoardPiece(Row3, Column3) = Piece2: BoardRotate(Row3, Column3) = Rotate2
BoardPlayer(Row2, Column2) = Player: BoardPlayer(Row2, Column2) = 6: BoardRotate(Row2, Column2) = 1
BoardPlayer(Row1, Column1) = 0: BoardPiece(Row1, Column1) = 0: BoardRotate(Row1, Column1) = 0
Line (BoardX1 - 38, BoardY1 - 38)-(BoardX1 + 38, BoardY1 + 38), SquareColor1, BF
Line (BoardX2 - 38, BoardY2 - 38)-(BoardX2 + 38, BoardY2 + 38), SquareColor2, BF
X1 = BoardX2: X2 = BoardY2: X3 = Player: X4 = 6: X5 = 1: GoSub DrawPiece
X1 = BoardX3: X2 = BoardY3: X3 = BoardPlayer(Row3, Column3): X4 = BoardPiece(Row3, Column3): X5 = BoardRotate(Row3, Column3): GoSub DrawPiece
End If

If Row2 = 5 And Column2 = 5 Then
BoardPlayer(Row3, Column3) = Player: BoardPiece(Row3, Column3) = Piece: BoardRotate(Row3, Column3) = Rotation
BoardPlayer(Row1, Column1) = 0: BoardPiece(Row1, Column1) = 0: BoardRotate(Row1, Column1) = 0
Line (BoardX1 - 38, BoardY1 - 38)-(BoardX1 + 38, BoardY1 + 38), SquareColor1, BF
Line (BoardX2 - 38, BoardY2 - 38)-(BoardX2 + 38, BoardY2 + 38), SquareColor2, BF
X1 = BoardX3: X2 = BoardY3: X3 = Player: X4 = Piece: X5 = Rotation: GoSub DrawPiece
End If

' Remove Piece Rotations
Line (831, 269)-(907, 630), 1, BF

Color 0, 1: Locate 16, 101: Print "Piece Transported"
Color 0, 1: Locate 18, 98: Print "Press ENTER to Continue";

MovesLeft = MovesLeft - 1: Color 0, 1: Locate 40, 103: Print "Moves Left:"; MovesLeft;

GetENTER2: A$ = InKey$
If A$ = "" Then
PSet (BoardX3, BoardY3), Point(BoardX3, BoardY3): Draw "C8" + Cursor$: _Delay .2
PSet (BoardX3, BoardY3), Point(BoardX3, BoardY3): Draw C$ + Cursor$: _Delay .2
GoTo GetENTER2
End If
If Asc(A$) <> 13 Then GoTo GetENTER2

Color 0, 1: Locate 18, 98: Print " ";

If MovesLeft > 0 Then GoTo MovesLeft
End If

' Asign New Location to Player
BoardPlayer(Row2, Column2) = Player: BoardPiece(Row2, Column2) = Piece: BoardRotate(Row2, Column2) = Rotation

' Set Old Location to 0
BoardPlayer(Row1, Column1) = 0: BoardPiece(Row1, Column1) = 0: BoardRotate(Row1, Column1) = 0

' Clear Piece and Cursors From Old Location
Line (BoardX1 - 38, BoardY1 - 38)-(BoardX1 + 38, BoardY1 + 38), SquareColor1, BF

' Clear New Location
Line (BoardX2 - 38, BoardY2 - 38)-(BoardX2 + 38, BoardY2 + 38), SquareColor2, BF

' Redraw Piece at New Location
X1 = BoardX2: X2 = BoardY2: X3 = Player: X4 = Piece: X5 = Rotation: GoSub DrawPiece

' Remove Piece Rotations
Line (831, 269)-(907, 650), 1, BF

' Check If Piece Captured is Opponents King
If Player2 = Opponent And Piece2 = 8 And (Piece = 4 Or Piece = 8) Then

Color 0, 1: Locate 16, 101: Print " W I N N E R ! ";
Color 0, 1: Locate 18, 101: Print " King Captured ";

Color 0, 1: Locate 39, 100: Print "Play Another Game?";
Color 0, 1: Locate 40, 100: Print " Yes or No ";

GoTo AnotherGame
End If

MovesLeft = MovesLeft - 1: Color 0, 1: Locate 40, 103: Print "Moves Left:"; MovesLeft;

EndTurn:

If MovesLeft > 0 GoTo MovesLeft

Swap Player, Opponent: GoTo StartGame


ReleaseMouseButton:
Do While _MouseInput
If _MouseButton(1) = 0 Then Return
Loop
GoTo ReleaseMouseButton


DrawMessage:
If X5 > 3 Then V = 0 Else V = 1
Color 15, V: Locate 1, 1: Print Message$;
w = 8 * Len(Message$): h = 16

If X5 = 1 Then Dim p(w, h)
If X5 = 2 Then Dim q(w, h)
If X5 = 3 Then Dim r(w, h)
If X5 = 4 Then Dim s(w, h)
If X5 = 5 Then Dim t(w, h)

For Y = 0 To h
For X = 0 To w
If X5 = 1 Then If Point(X, Y) <> 1 Then p(X, Y) = 2
If X5 = 2 Then If Point(X, Y) <> 1 Then q(X, Y) = 2
If X5 = 3 Then If Point(X, Y) <> 1 Then r(X, Y) = 2
If X5 = 4 Then If Point(X, Y) <> 0 Then s(X, Y) = 2
If X5 = 5 Then If Point(X, Y) <> 0 Then t(X, Y) = 2
Next
Next

For Y = 0 To h - 1
For X = 0 To w - 1
If X5 = 1 Then If p(X, Y) > 1 Then V = X3 Else V = 1
If X5 = 2 Then If q(X, Y) > 1 Then V = X3 Else V = 1
If X5 = 3 Then If r(X, Y) > 1 Then V = X3 Else V = 7
If X5 = 4 Then If s(X, Y) > 0 Then V = X3 Else V = 0
If X5 = 5 Then If t(X, Y) > 0 Then V = X3 Else V = 0
Line (X1 + X * X4, X2 + Y * X4)-(X1 + X * X4 + X4, X2 + Y * X4 + X4), V, BF
Next
Next
Return


DrawPiece: PSet (X1, X2), X6: Draw Rotate$(X5) + Piece$(X3, X4): Return


UpdateBoard:
For Z = 1 To 9
For Y = 1 To 9
BoardX = BoardX(Z, Y): BoardY = BoardY(Z, Y): If (Z + Y) / 2 = Fix((Z + Y) / 2) Then SquareColor = 2 Else SquareColor = 0
Line (BoardX - 39, BoardY - 39)-(BoardX + 39, BoardY + 39), SquareColor, BF
If Z = 5 And Y = 5 Then PSet (BoardX, BoardY), 2: Draw HyperSquare$
If BoardPlayer(Z, Y) > 0 Then X1 = BoardX: X2 = BoardY: X3 = BoardPlayer(Z, Y): X4 = BoardPiece(Z, Y): X5 = BoardRotate(Z, Y): X6 = SquareColor: GoSub DrawPiece
Next
Next
Return


FireLaser:
For Z = 1 To 3: BeamDirection(Z) = 0: Hit(Z) = 0: Next: LaserFired = 1: NextBeam = 1

MovesLeft = MovesLeft - 1: Color 0, 1: Locate 40, 103: Print "Moves Left:"; MovesLeft;

' Get Laser Location and Beam Direction
For Z = 1 To 9
For Y = 1 To 9
If BoardPlayer(Z, Y) = Player And BoardPiece(Z, Y) = 7 Then LaserRow = Z: LaserColumn = Y: BeamDirection(1) = BoardRotate(Z, Y): Direction = BeamDirection(1)
Next
Next

' Fire Laser Beam Exiting Laser
X1 = BoardX(LaserRow, LaserColumn): X2 = BoardY(LaserRow, LaserColumn): V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(BeamDirection(1)) + LaserBeam$(1)

' Set Beam 1 Row and Column to Laser's Location
Row(1) = LaserRow: Column(1) = LaserColumn

CheckBeams:
For Z = 1 To 3
BeamRow = Row(Z): BeamColumn = Column(Z): If BeamDirection(Z) > 0 Then Beam = Z: On BeamDirection(Z) GOSUB BeamLeft, BeamDown, BeamRight, BeamUp
Next

' Check If All Beams Has Ended
If BeamDirection(1) + BeamDirection(2) + BeamDirection(3) > 0 Then GoTo CheckBeams

' Redraw Beam from Laser if Laser is Destroyed
If Hit(1) = 4 Or Hit(2) = 4 Or Hit(3) = 4 Then X1 = BoardX(LaserRow, LaserColumn): X2 = BoardY(LaserRow, LaserColumn): V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(Direction) + LaserBeam$(1)

' Display List of Destroyed Pieces
Color 0, 1: Locate 16, 101: Print " Pieces Destroyed ";: X = 16: HitTotal = 0

' Display Destroyed Pieces
For Z = 1 To 3
HitTotal = HitTotal + Hit(Z): If Hit(Z) > 0 Then X = X + 2: Locate X, 98: Print Hit$(Hit(Z));
Next

' Display "N O N E" If No Pieces Were Destroyed
If HitTotal = 0 Then X = X + 2: Locate X, 97: Print Hit$(0);

X = X + 2: Locate X, 98: Print "Press ENTER to Continue";

GetENTER1: A$ = UCase$(InKey$): If A$ = "" Then GoTo GetENTER1
If Asc(A$) <> 13 Then GoTo GetENTER1

For Z = 16 To 24 Step 2: Locate Z, 98: Print " ";: Next

' Delete Destroyed From Memory
BoardPlayer(DrestroyRow, DestroyColumn) = 0: BoardPiece(DestroyRow, DestroyColumn) = 0: BoardRotate(DestroyRow, DrestroyColumn) = 0

' Remove Laser Beams and Destroyed Pieces From Board
GoSub UpdateBoard

'Check If King(s) Been Destroyed
For Z = 1 To 3
If Hit(Z) = 1 Or Hit(Z) = 2 Then Winner = Winner + Hit(Z)
Next

If Winner > 0 Then GoTo Winner

GoTo EndTurn


BeamLeft:
If BeamColumn - 1 >= 1 Then
BeamColumn = BeamColumn - 1: BeamX = BoardX(BeamRow, BeamColumn): BeamY = BoardY(BeamRow, BeamColumn): StartColor = Point(BeamX, BeamY)
BoardPlayer = BoardPlayer(BeamRow, BeamColumn): BoardPiece = BoardPiece(BeamRow, BeamColumn): BoardRotate = BoardRotate(BeamRow, BeamColumn)

If BoardPlayer = 0 Or BoardPiece = 6 Or (BoardPiece = 2 And BoardRotate = 1) Then BeamDraw = 2: BeamRotate = 1 ' Beam Pass Straight Through
If (BoardPiece = 1 And BoardRotate = 1) Or (BoardPiece = 5 And BoardRotate = 2) Then BeamDirection(Beam) = 4: BeamDraw = 5: BeamRotate = 1 ' Deflect Up off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 2 Then BeamDirection(Beam) = 4: BeamDraw = 6: BeamRotate = 1 ' Deflect Up off Diagnol Mirror
If (BoardPiece = 1 And BoardRotate = 4) Or (BoardPiece = 5 And BoardRotate = 4) Then BeamDirection(Beam) = 2: BeamDraw = 5: BeamRotate = 4 ' Deflect Down off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 1 Then BeamDirection(Beam) = 2: BeamDraw = 6: BeamRotate = 4 ' Deflect Down off Diagnol Mirror
If BoardPiece = 5 And BoardRotate = 1 Then BeamDirection(Beam) = 2: NextBeam = NextBeam + 1: BeamDirection(NextBeam) = 4: Row(NextBeam) = BeamRow: Column(NextBeam) = BeamColumn: BeamDraw = 7: BeamRotate = 1 ' Deflect From Beam Splitter
If BoardPiece = 1 And (BoardRotate = 2 Or BoardRotate = 3) Then Hit(Beam) = 9: BeamDraw = 3: BeamRotate = 1 ' Hit Side of Triagle Mirror
If BoardPiece = 4 And BoardRotate > 1 Then Hit(Beam) = 7: BeamDraw = 3: BeamRotate = 1 ' Hit Side or Back of Block
If BoardPiece = 5 And BoardRotate = 3 Then Hit(Beam) = 5: BeamDraw = 3: BeamRotate = 1 ' Hit Back of Beam Spliter
If BoardPiece = 7 And BoardRotate = 1 Then Hit(Beam) = 3: BeamDraw = 3: BeamRotate = 1 ' Hit Back of Laser
If BoardPiece = 7 And (BoardRotate = 2 Or BoardRotate = 4) Then Hit(Beam) = 3: BeamDraw = 8: BeamRotate = 1 ' Hit Side of Laser
If BoardPiece = 7 And BoardRotate = 3 Then Hit(Beam) = 3: BeamDraw = 1: BeamRotate = 3 ' Hit Front of Laser
If BoardPiece = 2 And BoardRotate = 2 Then Hit(Beam) = 4: BeamDraw = 9: BeamRotate = 1 ' Hit Your Own Laser from Straight Mirror
If BoardPiece = 4 And BoardRotate = 1 Then Hit(Beam) = 4: BeamDraw = 3: BeamRotate = 1 ' Hit Your Own Laser from Block Mirror
If BoardPiece = 8 Then Hit(Beam) = 1: BeamDraw = 4: BeamRotate = 1 ' Hit King

If Hit(Beam) > 0 Then
BeamDirection(Beam) = 0
If Hit(Beam) = 4 Then
' Destroy Own Laser, Hit From Straight Mirror
BoardPlayer(LaserRow, LaserColumn) = 0: BoardPiece(LaserRow, LaserColumn) = 0: BoardRotate(LaserRow, LaserColumn) = 0
DestroyRow = LaserRow: DestroyColumn = LaserColumn
Else
' Destroy Anyother Piece
DestroyRow = BeamRow: DestroyColumn = BeamColumn
If BoardPlayer(BeamRow, BeamColumn) = Player Then Hit(Beam) = Hit(Beam) + 1
End If

' Draw Cursor Around Destroyed Pieces
X1 = BoardX(DestroyRow, DestroyColumn): X2 = BoardY(DestroyRow, DestroyColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw "C8" + Cursor$

' End Beam Path
BeamDirection(Beam) = 0
End If

' Draw Beam
X1 = BoardX(BeamRow, BeamColumn): X2 = BoardY(BeamRow, BeamColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(BeamRotate) + LaserBeam$(BeamDraw)

' Set Last Location of Beam
Row(Beam) = BeamRow: Column(Beam) = BeamColumn
Else
BeamDirection(Beam) = 0
End If
Return


BeamDown:
If BeamRow + 1 <= 9 Then
BeamRow = BeamRow + 1: BeamX = BoardX(BeamRow, BeamColumn): BeamY = BoardY(BeamRow, BeamColumn): StartColor = Point(BeamX, BeamY)
BoardPlayer = BoardPlayer(BeamRow, BeamColumn): BoardPiece = BoardPiece(BeamRow, BeamColumn): BoardRotate = BoardRotate(BeamRow, BeamColumn)

If BoardPlayer = 0 Or BoardPiece = 6 Or (BoardPiece = 2 And BoardRotate = 2) Then BeamDraw = 2: BeamRotate = 2 ' Beam Pass Straight Through
If (BoardPiece = 1 And BoardRotate = 1) Or (BoardPiece = 5 And BoardRotate = 1) Then BeamDirection(Beam) = 3: BeamDraw = 5: BeamRotate = 1 ' Deflect Right off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 2 Then BeamDirection(Beam) = 3: BeamDraw = 6: BeamRotate = 1 ' Deflect Right off Diagnol Mirror
If (BoardPiece = 1 And BoardRotate = 2) Or (BoardPiece = 5 And BoardRotate = 3) Then BeamDirection(Beam) = 1: BeamDraw = 5: BeamRotate = 2 ' Deflect Left off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 1 Then BeamDirection(Beam) = 1: BeamDraw = 6: BeamRotate = 2 ' Deflect Left off Diagnol Mirror
If BoardPiece = 5 And BoardRotate = 2 Then BeamDirection(Beam) = 3: NextBeam = NextBeam + 1: BeamDirection(NextBeam) = 1: Row(NextBeam) = BeamRow: Column(NextBeam) = BeamColumn: BeamDraw = 7: BeamRotate = 2 ' Deflect From Beam Splitter
If BoardPiece = 1 And (BoardRotate = 3 Or BoardRotate = 4) Then Hit(Beam) = 9: BeamDraw = 3: BeamRotate = 2 ' Hit Side of Triagle Mirror
If BoardPiece = 4 And (BoardRotate = 1 Or BoardRotate > 2) Then Hit(Beam) = 7: BeamDraw = 3: BeamRotate = 2 ' Hit Side or Back of Block
If BoardPiece = 5 And BoardRotate = 4 Then Hit(Beam) = 5: BeamDraw = 3: BeamRotate = 2 ' Hit Back of Beam Spliter
If BoardPiece = 7 And BoardRotate = 2 Then Hit(Beam) = 3: BeamDraw = 3: BeamRotate = 2 ' Hit Back of Laser
If BoardPiece = 7 And (BoardRotate = 1 Or BoardRotate = 3) Then Hit(Beam) = 3: BeamDraw = 8: BeamRotate = 2 ' Hit Side of Laser
If BoardPiece = 7 And BoardRotate = 4 Then Hit(Beam) = 3: BeamDraw = 1: BeamRotate = 4 ' Hit Front of Laser
If BoardPiece = 2 And BoardRotate = 1 Then Hit(Beam) = 4: BeamDraw = 9: BeamRotate = 2 ' Hit Your Own Laser from Straight Mirror
If BoardPiece = 4 And BoardRotate = 2 Then Hit(Beam) = 4: BeamDraw = 3: BeamRotate = 2 ' Hit Your Own Laser from Block Mirror
If BoardPiece = 8 Then Hit(Beam) = 1: BeamDraw = 4: BeamRotate = 2 ' Hit King

If Hit(Beam) > 0 Then
BeamDirection(Beam) = 0
If Hit(Beam) = 4 Then
' Destroy Own Laser, Hit From Straight Mirror
BoardPlayer(LaserRow, LaserColumn) = 0: BoardPiece(LaserRow, LaserColumn) = 0: BoardRotate(LaserRow, LaserColumn) = 0
DestroyRow = LaserRow: DestroyColumn = LaserColumn
Else
' Destroy Anyother Piece
DestroyRow = BeamRow: DestroyColumn = BeamColumn
If BoardPlayer = Player Then Hit(Beam) = Hit(Beam) + 1
End If

' Draw Cursor Around Destroyed Pieces
X1 = BoardX(DestroyRow, DestroyColumn): X2 = BoardY(DestroyRow, DestroyColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw "C8" + Cursor$

' End Beam Path
BeamDirection(Beam) = 0
End If

' Draw Beam
X1 = BoardX(BeamRow, BeamColumn): X2 = BoardY(BeamRow, BeamColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(BeamRotate) + LaserBeam$(BeamDraw)

' Set Last Location of Beam
Row(Beam) = BeamRow: Column(Beam) = BeamColumn
Else
BeamDirection(Beam) = 0
End If
Return


BeamRight:
If BeamColumn + 1 <= 9 Then
BeamColumn = BeamColumn + 1: BeamX = BoardX(BeamRow, BeamColumn): BeamY = BoardY(BeamRow, BeamColumn): StartColor = Point(BeamX, BeamY)
BoardPlayer = BoardPlayer(BeamRow, BeamColumn): BoardPiece = BoardPiece(BeamRow, BeamColumn): BoardRotate = BoardRotate(BeamRow, BeamColumn)

If BoardPlayer = 0 Or BoardPiece = 6 Or (BoardPiece = 2 And BoardRotate = 1) Then BeamDraw = 2: BeamRotate = 1 ' Beam Pass Straight Through
If (BoardPiece = 1 And BoardRotate = 2) Or (BoardPiece = 5 And BoardRotate = 2) Then BeamDirection(Beam) = 4: BeamDraw = 5: BeamRotate = 2 ' Deflect Up off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 1 Then BeamDirection(Beam) = 4: BeamDraw = 6: BeamRotate = 2 ' Deflect Up off Diagnol Mirror
If (BoardPiece = 1 And BoardRotate = 3) Or (BoardPiece = 5 And BoardRotate = 4) Then BeamDirection(Beam) = 2: BeamDraw = 5: BeamRotate = 3 ' Deflect Down off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 2 Then BeamDirection(Beam) = 2: BeamDraw = 6: BeamRotate = 3 ' Deflect Down off Diagnol Mirror
If BoardPiece = 5 And BoardRotate = 3 Then BeamDirection(Beam) = 4: NextBeam = NextBeam + 1: BeamDirection(NextBeam) = 2: Row(NextBeam) = BeamRow: Column(NextBeam) = BeamColumn: BeamDraw = 7: BeamRotate = 3 ' Deflect From Beam Splitter
If BoardPiece = 1 And (BoardRotate = 1 Or BoardRotate = 4) Then Hit(Beam) = 9: BeamDraw = 3: BeamRotate = 3 ' Hit Side of Triagle Mirror
If BoardPiece = 4 And (BoardRotate < 3 Or BoardRotate = 4) Then Hit(Beam) = 7: BeamDraw = 3: BeamRotate = 3 ' Hit Side or Back of Block
If BoardPiece = 5 And BoardRotate = 1 Then Hit(Beam) = 5: BeamDraw = 3: BeamRotate = 3 ' Hit Back of Beam Spliter
If BoardPiece = 7 And BoardRotate = 3 Then Hit(Beam) = 3: BeamDraw = 3: BeamRotate = 3 ' Hit Back of Laser
If BoardPiece = 7 And (BoardRotate = 2 Or BoardRotate = 4) Then Hit(Beam) = 3: BeamDraw = 8: BeamRotate = 3 ' Hit Side of Laser
If BoardPiece = 7 And BoardRotate = 1 Then Hit(Beam) = 3: BeamDraw = 1: BeamRotate = 1 ' Hit Front of Laser
If BoardPiece = 2 And BoardRotate = 2 Then Hit(Beam) = 4: BeamDraw = 9: BeamRotate = 3 ' Hit Your Own Laser from Straight Mirror
If BoardPiece = 4 And BoardRotate = 3 Then Hit(Beam) = 4: BeamDraw = 3: BeamRotate = 3 ' Hit Your Own Laser from Block Mirror
If BoardPiece = 8 Then Hit(Beam) = 1: BeamDraw = 4: BeamRotate = 4 ' Hit King

If Hit(Beam) > 0 Then
BeamDirection(Beam) = 0
If Hit(Beam) = 4 Then
' Destroy Own Laser, Hit From Straight Mirror
BoardPlayer(LaserRow, LaserColumn) = 0: BoardPiece(LaserRow, LaserColumn) = 0: BoardRotate(LaserRow, LaserColumn) = 0
DestroyRow = LaserRow: DestroyColumn = LaserColumn
Else
' Destroy Anyother Piece
DestroyRow = BeamRow: DestroyColumn = BeamColumn
If BoardPlayer = Player Then Hit(Beam) = Hit(Beam) + 1
End If

' Draw Cursor Around Destroyed Pieces
X1 = BoardX(DestroyRow, DestroyColumn): X2 = BoardY(DestroyRow, DestroyColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw "C8" + Cursor$

' End Beam Path
BeamDirection(Beam) = 0
End If

' Draw Beam
X1 = BoardX(BeamRow, BeamColumn): X2 = BoardY(BeamRow, BeamColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(BeamRotate) + LaserBeam$(BeamDraw)

' Set Last Location of Beam
Row(Beam) = BeamRow: Column(Beam) = BeamColumn
Else
BeamDirection(Beam) = 0
End If
Return


BeamUp:
If BeamRow - 1 >= 1 Then
BeamRow = BeamRow - 1: BeamX = BoardX(BeamRow, BeamColumn): BeamY = BoardY(BeamRow, BeamColumn): StartColor = Point(BeamX, BeamY)
BoardPlayer = BoardPlayer(BeamRow, BeamColumn): BoardPiece = BoardPiece(BeamRow, BeamColumn): BoardRotate = BoardRotate(BeamRow, BeamColumn)

If BoardPlayer = 0 Or BoardPiece = 6 Or (BoardPiece = 2 And BoardRotate = 2) Then BeamDraw = 2: BeamRotate = 2 ' Beam Pass Straight Through
If (BoardPiece = 1 And BoardRotate = 3) Or (BoardPiece = 5 And BoardRotate = 3) Then BeamDirection(Beam) = 1: BeamDraw = 5: BeamRotate = 3 ' Deflect Left off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 2 Then BeamDirection(Beam) = 1: BeamDraw = 6: BeamRotate = 3 ' Deflect Left off Diagnol Mirror
If (BoardPiece = 1 And BoardRotate = 4) Or (BoardPiece = 5 And BoardRotate = 1) Then BeamDirection(Beam) = 3: BeamDraw = 5: BeamRotate = 4 ' Deflect Right off Triangle Mirror
If BoardPiece = 3 And BoardRotate = 1 Then BeamDirection(Beam) = 3: BeamDraw = 6: BeamRotate = 4 ' Deflect Right off Diagnol Mirror
If BoardPiece = 5 And BoardRotate = 4 Then BeamDirection(Beam) = 1: NextBeam = NextBeam + 1: BeamDirection(NextBeam) = 3: Row(NextBeam) = BeamRow: Column(NextBeam) = BeamColumn: BeamDraw = 7: BeamRotate = 4 ' Deflect From Beam Splitter
If BoardPiece = 1 And (BoardRotate = 1 Or BoardRotate = 2) Then Hit(Beam) = 9: BeamDraw = 3: BeamRotate = 4 ' Hit Side of Triagle Mirror
If BoardPiece = 4 And BoardRotate < 4 Then Hit(Beam) = 7: BeamDraw = 3: BeamRotate = 4 ' Hit Side or Back of Block
If BoardPiece = 5 And BoardRotate = 2 Then Hit(Beam) = 5: BeamDraw = 3: BeamRotate = 4 ' Hit Back of Beam Spliter
If BoardPiece = 7 And BoardRotate = 4 Then Hit(Beam) = 3: BeamDraw = 3: BeamRotate = 4 ' Hit Back of Laser
If BoardPiece = 7 And (BoardRotate = 1 Or BoardRotate(BeamRow, BeamColumn) = 3) Then Hit(Beam) = 3: BeamDraw = 8: BeamRotate = 4 ' Hit Side of Laser
If BoardPiece = 7 And BoardRotate = 2 Then Hit(Beam) = 3: BeamDraw = 1: BeamRotate = 2 ' Hit Front of Laser
If BoardPiece = 2 And BoardRotate = 1 Then Hit(Beam) = 4: BeamDraw = 9: BeamRotate = 4 ' Hit Your Own Laser from Straight Mirror
If BoardPiece = 4 And BoardRotate = 4 Then Hit(Beam) = 4: BeamDraw = 3: BeamRotate = 4 ' Hit Your Own Laser from Block Mirror
If BoardPiece = 8 Then Hit(Beam) = 1: BeamDraw = 4: BeamRotate = 4 ' Hit King

If Hit(Beam) > 0 Then
BeamDirection(Beam) = 0
If Hit(Beam) = 4 Then
' Destroy Own Laser, Hit From Straight Mirror
BoardPlayer(LaserRow, LaserColumn) = 0: BoardPiece(LaserRow, LaserColumn) = 0: BoardRotate(LaserRow, LaserColumn) = 0
DestroyRow = LaserRow: DestroyColumn = LaserColumn
Else
' Destroy Anyother Piece
DestroyRow = BeamRow: DestroyColumn = BeamColumn
If BoardPlayer(BeamRow, BeamColumn) = Player Then Hit(Beam) = Hit(Beam) + 1
End If

' Draw Cursor Around Destroyed Pieces
X1 = BoardX(DestroyRow, DestroyColumn): X2 = BoardY(DestroyRow, DestroyColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw "C8" + Cursor$

' End Beam Path
BeamDirection(Beam) = 0
End If

' Draw Beam
X1 = BoardX(BeamRow, BeamColumn): X2 = BoardY(BeamRow, BeamColumn)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(BeamRotate) + LaserBeam$(BeamDraw)

' Set Last Location of Beam
Row(Beam) = BeamRow: Column(Beam) = BeamColumn
Else
BeamDirection(Beam) = 0
End If

Return


Winner:
If Winner = 1 Then Winner = Player Else If Winner = 2 Then Winner = Opponent

If Winner = 1 Then T1 = 1: T2 = 1: T3 = 1: T4 = 2 Else If Winner = 2 Then T1 = 2: T2 = 2: T3 = 2: T4 = 1 Else T1 = 1: T2 = 1: T3 = 2: T4 = 2

If Winner < 3 Then
X1 = 766: X2 = 613: X3 = T1: X4 = 7: X5 = 4: X6 = 1: GoSub DrawPiece
X1 = 765: X2 = 182: X3 = T2: X4 = 1: X5 = 4: X6 = 1: GoSub DrawPiece
X1 = 975: X2 = 182: X3 = T3: X4 = 1: X5 = 3: X6 = 1: GoSub DrawPiece
X1 = 974: X2 = 613: X3 = T4: X4 = 8: X5 = 2: X6 = 1: GoSub DrawPiece
PSet (765, 596), 5: Draw "TA0U416R210D401L2U399L206D414L2BE1P5,5"

Color 0, 1: Locate 14, 106: Print "Player"; Winner;
Color 0, 1: Locate 16, 101: Print " W I N N E R ! ";
Color 0, 1: Locate 18, 101: Print " King Destroyed ";
Else
Line (730, 150)-(1010, 650), 1, BF
Color 0, 1: Locate 12, 101: Print " T I E G A M E "
Color 0, 1: Locate 14, 96: Print "Both Kings where Destroyed!";

Color 0, 1: Locate 16, 101: Print "Play Another Game?";
Color 0, 1: Locate 17, 101: Print " Yes or No ";

X1 = 766: X2 = 605: X3 = 1: X4 = 8: X5 = 4: X6 = 1: GoSub DrawPiece
X1 = 765: X2 = 315: X3 = 1: X4 = 1: X5 = 4: X6 = 1: GoSub DrawPiece
X1 = 975: X2 = 315: X3 = 2: X4 = 1: X5 = 3: X6 = 1: GoSub DrawPiece
X1 = 974: X2 = 605: X3 = 2: X4 = 8: X5 = 2: X6 = 1: GoSub DrawPiece
X1 = 869: X2 = 315: X3 = Player: X4 = 5: X5 = 4: X6 = 1: GoSub DrawPiece
X1 = 869: X2 = 455: X3 = Player: X4 = 7: X5 = 4: X6 = 1: GoSub DrawPiece
PSet (870, 438), 5: Draw "TA0U122R103D256R2U258L210D258R2U256R101D122R2BH1P5,5"
End If


AnotherGame:
YesNo: A$ = UCase$(InKey$): If A$ = "" Then GoTo YesNo
If A$ = "Y" Then Run
If A$ = "N" Then System
GoTo YesNo



'LOCATE 18, 98: PRINT Hit$(5);

X1 = BoardX(9, 3): X2 = BoardY(9, 3)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(2) + LaserBeam$(6)

X1 = BoardX(8, 2): X2 = BoardY(8, 2)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(4) + LaserBeam$(3)

X1 = BoardX(8, 3): X2 = BoardY(8, 3)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(4) + LaserBeam$(3)

X1 = BoardX(9, 2): X2 = BoardY(9, 2)
V = Point(X1, X2): PSet (X1, X2), V: Draw Rotate$(1) + LaserBeam$(5)

Print this item

  Rushi Board Game
Posted by: SMcNeill - 12-24-2023, 10:16 AM - Forum: Donald Foster - No Replies

Quote:Hello all,

Rushi is a 2 player board game. The goal is to be the first player to get their pieces across the board to their opponent's home row. The Board is a 6X5 game board with each players having 7 pieces, 6 on the board and 1 in their hand. There are 3 different pieces: cross, x and single arrow piece. All pieces has arrows. The arrows point to other squares on the board.

A move consist of taking the piece in your hand and placing on the board at 1 of the squares that at least 1 arrow is poiting to. Then pick up 1 of the pieces that has an arrow pointing to the square you placed your piece. The piece you pick up goes in your hand. So a move consist of placing a piece and picking up a piece. If you have no playable moves or you can choose to swap the piece in your hand with another of your pieces on the board. However, you can not swap pieces 2 moves in a row.

To prevent players from keeping a piece on their back row, preventing their opponent from moving a piece there, all pieces must be moved off their back row within 100 moves. after 89 moves, if either player still has any pieces on their back row they will get a warning to get their pieces off the back row. So each player will have 5 moves each to clear their back row. If after 100 moves, 1 of the players still has a piece on the back row, the game is over and their opponent is delcaired the winner. If both players still have a piece left on their back row, the game ends in a draw.

The first player has the blue arrow piece and their oppnent has the green arrows. The back side of the pieces are blue and green accordingly. A back side of the current players piece is centered on the right side of the screen to indicate which player's turn it is. Beside the player's indicator piece on the right side of the screen, will appear a SWAP button that you can click if you wish to swap pieces. The button will then be selected and you will be prompt to choose piece on the board to swap with.

The game starts off with a single arrow piece in your hand. That piece can be placed on the board facing 4 different directions. So, when the game starts, 4 single arrow pieces are on the right side of the screen, beside the board next to your back row. use your mouse to select which piece rotation you want. Then that rotation will be selected with a cursor around it and placed centered. The cross and the X will automatically be selected and you just choose the square on the board to place it.

If more than 1 piece is pointing to the piece just placed, a cursor will surround those pieces. Click on the piece that you want to put in your hand. If only 1 piece pointed to that square, the piece will automatically placed in your hand and play continued to the next player.

As the pieces reach your opponents back row, they are flipped to the back side of the piece and locked there. if you can't play a piece then your turn is skipped and you will be prompted to press ENTER to continue to next player.

I have included a copy of the rules. Hope you enjoy playing.

Donald

   


.docx   RUSHI COMPLETE RULES.docx (Size: 190.1 KB / Downloads: 32)

Code: (Select All)
_Title "Rushi Desigbned by Danny Zondervanby 2016 - Programmed by Donal L. Foster Jr. 2017"

Screen _NewImage(1125, 735, 256)

_PaletteColor 1, _RGB32(244, 164, 96) ' Light Square
_PaletteColor 2, _RGB32(94, 38, 18) ' Dark Square
_PaletteColor 3, _RGB32(10, 124, 235) ' Blue Piece
_PaletteColor 4, _RGB32(0, 170, 0) ' Green Piece

DefInt A-Z

Player = 1: Opponant = 2: Move = 0

PieceInHand(1) = 1: PieceInHand(2) = 1
HandY(1) = 638: HandY(2) = 98: Piece1Y(1) = 503: Piece1Y(2) = 98
FinishCount(1) = 0: FinishCount(2) = 0


Arrow1$ = "BU15C3R8U17R8H15G15R8D17R8BU5P3,3"
Arrow2$ = "BU15C4R8U17R8H15G15R8D17R8BU5P4,4"

Line (0, 0)-(1125, 735), 2, BF

' Draw Board
Line (15, 15)-(856, 720), 0, BF
X = 0
For Z = 1 To 5
W = 0
For Y = 1 To 6
If Fix((Z + Y) / 2) = (Z + Y) / 2 Then U = 2 Else U = 1
Line (98 + W - 67, 98 + X - 67)-(98 + W + 67, 98 + X + 67), U, BF
If Z = 1 Then BoardPlayer(Z, Y) = 2: BoardRotate(Z, Y) = 1
If Z = 5 Then BoardPlayer(Z, Y) = 1: BoardRotate(Z, Y) = 1
If Y = 1 Or Y = 6 Then BoardPiece(Z, Y) = 1: If Z = 1 Then BoardRotate(Z, Y) = 3
If Y = 2 Or Y = 5 Then BoardPiece(Z, Y) = 2
If Y = 3 Or Y = 4 Then BoardPiece(Z, Y) = 3
If BoardPlayer(Z, Y) > 0 Then X1 = 98 + W: X2 = 98 + X: X3 = BoardPlayer(Z, Y): X4 = BoardPiece(Z, Y): X5 = BoardRotate(Z, Y): GoSub DrawPiece
BoardX(Z, Y) = 98 + W: BoardY(Z, Y) = 98 + X
W = W + 135
Next
X = X + 135
Next

Color 15, 2: Locate 2, 114: Print "R U S H I";

' Draw Player's Piece in Hand
X1 = 990: X2 = 98: X3 = 2: X4 = 1: X5 = 3: GoSub DrawPiece
X1 = 990: X2 = 638: X3 = 1: X4 = 1: X5 = 1: GoSub DrawPiece

StartGame:
' Draw Player Indicator
X1 = 923: X2 = 368: X3 = Player: X4 = 4: GoSub DrawPiece

Piece = PieceInHand(Player): Rotation = 1

Line (996, 306)-(1120, 430), 2, BF

' End Game if Pieces are on Back Row After 100 Moves
Winner = 0: If Moves = 101 Then If C(1) = 1 And C(2) = 1 Then Winner = 3 Else If C(1) = 1 Then Winner = 2 Else If C(2) = 1 Then Winner = 1
If Winner > 0 Then GoTo Winner

' Check for Players Pieces Still on Back Row at 90 Moves
If Moves > 89 Then
C(1) = 0: C(2) = 0
For Z = 1 To 6
If BoardPlayer(1, Z) = 2 Then C(2) = 1
If BoardPlayer(5, Z) = 1 Then C(1) = 1
Next
End If

' If Player is Still on Back Row, Display Warning.
If C(Player) = 1 Then
Color 15, 2: Locate 22, 126: Print "W A R N I N G";
Color 15, 2: Locate 24, 126: Print "Remove Pieces";
Color 15, 2: Locate 25, 126: Print "From Back Row";
Color 15, 2: Locate 45, 111: Print "Press <ENTER> to Continue.";

GetENTER1: A$ = UCase$(InKey$): If A$ = "" GoTo GetENTER1
If Asc(A$) <> 13 Then GoTo GetENTER1
Line (996, 306)-(1120, 430), 2, BF
End If

'Check For Legal Moves
CanPlay = 0
For Z = 1 To 5
For Y = 1 To 6
W1 = Z: W2 = Y: GoSub CheckLegalMoves
Next
Next

' No Playable Moves
If CanPlay = 0 And LastMove(Player) = 0 Then
SwapPiece = 1: X1 = 1058: X2 = 368: X4 = 5: GoSub DrawPiece
X1 = 990: X2 = HandY(Player): Piece = PieceInHand(Player)
Line (X1 - 62, X2 - 62)-(X1 + 62, X2 + 62), 15, B
GoTo SwapPieces
ElseIf CanPlay = 0 Then
GoTo CantPlay
End If

' Remove Playable Cursors
For Z = 1 To 5
For Y = 1 To 6
If (Z + Y) / 2 = Fix((Z + Y) / 2) Then V = 2 Else V = 1
If Playable(Z, Y) = 1 Then Playable(Z, Y) = 0: Line (BoardX(Z, Y) - 62, BoardY(Z, Y) - 62)-(BoardX(Z, Y) + 62, BoardY(Z, Y) + 62), V, B
Next
Next

' Piece in Hand is a Sigle Arrow
If Piece = 1 Then
Line (923, HandY(Player) - 62)-(1057, HandY(Player) + 62), 2, BF
X = 0: T = 1
For Z = 1 To 2
W = 0
For Y = 1 To 2
X1 = 923 + W: X2 = Piece1Y(Player) + X: X3 = Player: X4 = 1: X5 = T: GoSub DrawPiece
A(T) = X1: B(T) = X2
W = W + 135: T = T + 1
Next
X = X + 135
Next
Color 15, 2: Locate 45, 111: Print " Choose a Piece Rotation. ";

GetRotationMouseInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)

For Z = 1 To 4
If (MouseX > A(Z) - 63) * (MouseX < A(Z) + 63) * (MouseY > B(Z) - 63) * (MouseY < B(Z) + 63) Then
CanSelect = 1: Line (A(Z) - 62, B(Z) - 62)-(A(Z) + 62, B(Z) + 62), 15, B
Else
CanSelect = 0: Line (A(Z) - 62, B(Z) - 62)-(A(Z) + 62, B(Z) + 62), 2, B
End If
If (MouseLeftButton = -1) * (CanSelect = 1) Then
Rotation = Z: GoSub ReleaseMouseButton
Line (A(1) - 62, B(1) - 62)-(A(4) + 62, B(4) + 62), 2, BF
X1 = 990: X2 = HandY(Player): X3 = Player: X4 = 1: X5 = Rotation: GoSub DrawPiece
GoTo GetBoardInput
End If
Next
Loop
GoTo GetRotationMouseInput
Else X1 = 990: X2 = HandY(Player): Piece = PieceInHand(Player): Rotation = 1
End If

GetBoardInput:
' Draw Cursor Around Piece in Hand
Line (X1 - 62, X2 - 62)-(X1 + 62, X2 + 62), 15, B

' Draw Swap Button
X1 = 1058: X2 = 368: X4 = 5: GoSub DrawPiece

Color 15, 2: Locate 45, 111: Print " Choose a Board Location. ";

ChooseALocationMouseInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)
If LastMove(Player) = 0 And MouseLeftButton = -1 And MouseX > 996 And MouseX < 1120 And MouseY > 306 And MouseY < 430 Then SwapPiece = 1: LastMove(Player) = 1: GoTo SwapPieces
For Z = 1 To 5
For Y = 1 To 6
If (MouseLeftButton = -1) * (MouseX > BoardX(Z, Y) - 67) * (MouseX < BoardX(Z, Y) + 67) * (MouseY > BoardY(Z, Y) - 67) * (MouseY < BoardY(Z, Y) + 67) Then
If BoardPlayer(Z, Y) = 0 Then Row = Z: Column = Y: LastMove(Player) = 0: GoTo EndChoice1
End If
Next
Next
Loop
GoTo ChooseALocationMouseInput

EndChoice1:

' Check for Legal Move
W1 = Row: W2 = Column: GoSub CheckLegalMoves
If X = 0 GoTo ChooseALocationMouseInput

' Move Piece from Hand to Board
Line (923, HandY(Player) - 62)-(1057, HandY(Player) + 62), 2, BF

If (Row = 1 And Player = 1) Or (Row = 5 And Player = 2) Then FinishCount(Player) = FinishCount(Player) + 1: Piece = 4

BoardPlayer(Row, Column) = Player: BoardPiece(Row, Column) = Piece: BoardRotate(Row, Column) = Rotation
X1 = BoardX(Row, Column): X2 = BoardY(Row, Column): X3 = Player: X4 = Piece: X5 = Rotation: GoSub DrawPiece

If X4 = 0 Then BoardPlayer(Row, Column) = 0: BoardPiece(Row, Column) = 0: BoardRotate(Row, Column) = 0

' Check for Multiple Pieces to Put in Hand
If X > 1 Then
X = 0: Color 15, 2: Locate 45, 111: Print "Choose Piece to Put in Hand.";
For Z = 1 To 5
For Y = 1 To 6
If (Z + Y) / 2 = Fix((Z + Y) / 2) Then V = 15 Else V = 0
If Playable(Z, Y) Then Line (BoardX(Z, Y) - 62, BoardY(Z, Y) - 62)-(BoardX(Z, Y) + 62, BoardY(Z, Y) + 62), V, B
Next
Next

ChooseAPieceInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)
For Z = 1 To 5
For Y = 1 To 6
If (MouseLeftButton = -1) * (MouseX > BoardX(Z, Y) - 62) * (MouseX < BoardX(Z, Y) + 62) * (MouseY > BoardY(Z, Y) - 62) * (MouseY < BoardY(Z, Y) + 62) Then
If Playable(Z, Y) = 1 Then Row2 = Z: Column2 = Y: GoTo EndChoice2
End If
Next
Next
Loop
GoTo ChooseAPieceInput
Else
For Z = 1 To 5
For Y = 1 To 6
If Playable(Z, Y) = 1 Then Row2 = Z: Column2 = Y: X4 = BoardPiece(Z, Y): X5 = BoardRotate(Z, Y)
Next
Next
End If

EndChoice2:

' Remove Playable Cursors
For Z = 1 To 5
For Y = 1 To 6
If (Z + Y) / 2 = Fix((Z + Y) / 2) Then V = 2 Else V = 1
If Playable(Z, Y) = 1 Then Playable(Z, Y) = 0: Line (BoardX(Z, Y) - 62, BoardY(Z, Y) - 62)-(BoardX(Z, Y) + 62, BoardY(Z, Y) + 62), V, B
Next
Next

' Move Piece from Board To Hand
If (Row2 + Column2) / 2 = Fix((Row2 + Column2) / 2) Then V = 2 Else V = 1
Line (BoardX(Row2, Column2) - 62, BoardY(Row2, Column2) - 62)-(BoardX(Row2, Column2) + 62, BoardY(Row2, Column2) + 62), V, BF

X1 = 990: X2 = HandY(Player): X3 = Player: X4 = BoardPiece(Row2, Column2): PieceInHand(Player) = X4
If X4 = 1 And Player = 2 Then X5 = 3 Else X5 = 1

BoardPlayer(Row2, Column2) = 0: BoardPiece(Row2, Column2) = 0: BoardRotate(Row2, Column2) = 0: GoSub DrawPiece

' Draw Color Circles at Ends of Board
If Row2 = 1 Or Row2 = 5 Then
X1 = BoardX(Row2, Column2): X2 = BoardY(Row2, Column2)
If (Row2 + Column2) / 2 = Fix((Row2 + Column2) / 2) Then V = 1 Else V = 2
If Row2 = 1 Then U = 4 Else U = 3
Circle (X1, X2), 15, U: Paint (X1, X2), U: Circle (X1, X2), 12, V: Paint (X1, X2), V
End If

SwapPieces:
If SwapPiece = 1 Then
SwapPiece = 0: Line (996, 306)-(1120, 430), 15, B

Color 15, 2: Locate 45, 111: Print " Choose Piece to Swap With. ";

ChooseSwapPieceInput:
Do While _MouseInput
MouseX = _MouseX: MouseY = _MouseY: MouseLeftButton = _MouseButton(1)
For Z = 1 To 5
For Y = 1 To 6
If (MouseLeftButton = -1) * (MouseX > BoardX(Z, Y) - 62) * (MouseX < BoardX(Z, Y) + 62) * (MouseY > BoardY(Z, Y) - 62) * (MouseY < BoardY(Z, Y) + 62) Then
If BoardPlayer(Z, Y) = Player Then Row1 = Z: Column1 = Y: GoTo EndChoice3
End If
Next
Next
Loop
GoTo ChooseSwapPieceInput

EndChoice3:
TempPiece = Piece: TempRotate = Rotation
PieceInHand(Player) = BoardPiece(Row1, Column1): HandRotate(Player) = BoardRotate(Row1, Column1)
BoardPiece(Row1, Column1) = TempPiece: BoardRotate(Row1, Column1) = TempRotate

If (Row1 + Column1) / 2 = Fix((Row1 + Column1) / 2) Then V = 2 Else V = 1
Line (BoardX(Row1, Column1) - 62, BoardY(Row1, Column1) - 62)-(BoardX(Row1, Column1) + 62, BoardY(Row1, Column1) + 62), V, BF
X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): X3 = Player: X4 = BoardPiece(Row1, Column1): X5 = BoardRotate(Row1, Column1): GoSub DrawPiece

Line (923, HandY(Player) - 62)-(1057, HandY(Player) + 62), 2, BF
If Player = 1 Then X5 = 1 Else X5 = 3
X1 = 990: X2 = HandY(Player): X3 = Player: X4 = PieceInHand(Player): GoSub DrawPiece

Line (996, 306)-(1120, 430), 2, BF
End If

' Check for Winner
If FinishCount(Player) = 6 Then Winner = Player: GoTo Winner

CantPlay:
If CanPlay = 0 Then
Color 15, 2: Locate 45, 111: Print " No Playable Moves. <ENTER> ";
GetENTER: A$ = UCase$(InKey$): If A$ = "" GoTo GetENTER
If Asc(A$) <> 13 Then GoTo GetENTER
End If

Move = Move + 1: Swap Player, Opponant: GoTo StartGame


DrawPiece:
If X4 = 4 And X3 = 1 Then V = 3 Else If X4 = 4 And X3 = 2 Then V = 4 Else V = 15

Line (X1 - 47, X2 - 57)-(X1 + 47, X2 - 57), 0
Line (X1 - 57, X2 - 47)-(X1 - 57, X2 + 47), 0
Line (X1 - 47, X2 + 57)-(X1 + 47, X2 + 57), 0
Line (X1 + 57, X2 - 47)-(X1 + 57, X2 + 47), 0
Circle (X1 - 47, X2 - 47), 10, 0, 1.5, 3.1
Circle (X1 - 47, X2 + 47), 10, 0, 3.1, 4.8
Circle (X1 + 47, X2 + 47), 10, 0, 4.6, 0
Circle (X1 + 47, X2 - 47), 10, 0, 0, 1.7
Paint (X1, X2), V, 0

If X4 = 5 Then Color 0, 15: Locate 24, 130: Print "S W A P";

If V < 15 Then Return

If X3 = 1 Then
If (X4 = 1 And X5 = 1) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA0" + Arrow1$
If (X4 = 1 And X5 = 2) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA270" + Arrow1$
If (X4 = 1 And X5 = 3) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA180" + Arrow1$
If (X4 = 1 And X5 = 4) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA90" + Arrow1$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA315BU10" + Arrow1$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA225BU10" + Arrow1$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA135BU10" + Arrow1$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA45BU10" + Arrow1$
Else
If (X4 = 1 And X5 = 1) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA0" + Arrow2$
If (X4 = 1 And X5 = 2) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA270" + Arrow2$
If (X4 = 1 And X5 = 3) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA180" + Arrow2$
If (X4 = 1 And X5 = 4) Or X4 = 3 Then PSet (X1, X2), 15: Draw "TA90" + Arrow2$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA315BU10" + Arrow2$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA225BU10" + Arrow2$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA135BU10" + Arrow2$
If X4 = 2 Then PSet (X1, X2), 15: Draw "TA45BU10" + Arrow2$
End If
Return


ReleaseMouseButton:
Do While _MouseInput
If _MouseButton(1) = 0 Then Return
Loop
GoTo ReleaseMouseButton


CheckLegalMoves:
X = 0
If W1 - 1 >= 1 Then If BoardPlayer(W1 - 1, W2) = Player Then If (BoardPiece(W1 - 1, W2) = 1 And BoardRotate(W1 - 1, W2) = 3) Or BoardPiece(W1 - 1, W2) = 3 Then X = X + 1: Playable(W1 - 1, W2) = 1
If W1 - 1 >= 1 And W2 + 1 <= 6 Then If BoardPlayer(W1 - 1, W2 + 1) = Player Then If BoardPiece(W1 - 1, W2 + 1) = 2 Then X = X + 1: Playable(W1 - 1, W2 + 1) = 1
If W2 + 1 <= 6 Then If BoardPlayer(W1, W2 + 1) = Player Then If (BoardPiece(W1, W2 + 1) = 1 And BoardRotate(W1, W2 + 1) = 4) Or BoardPiece(W1, W2 + 1) = 3 Then X = X + 1: Playable(W1, W2 + 1) = 1
If W1 + 1 <= 5 And W2 + 1 <= 6 Then If BoardPlayer(W1 + 1, W2 + 1) = Player Then If BoardPiece(W1 + 1, W2 + 1) = 2 Then X = X + 1: Playable(W1 + 1, W2 + 1) = 1
If W1 + 1 <= 5 Then If BoardPlayer(W1 + 1, W2) = Player Then If (BoardPiece(W1 + 1, W2) = 1 And BoardRotate(W1 + 1, W2) = 1) Or BoardPiece(W1 + 1, W2) = 3 Then X = X + 1: Playable(W1 + 1, W2) = 1
If W1 + 1 <= 5 And W2 - 1 >= 1 Then If BoardPlayer(W1 + 1, W2 - 1) = Player Then If BoardPiece(W1 + 1, W2 - 1) = 2 Then X = X + 1: Playable(W1 + 1, W2 - 1) = 1
If W2 - 1 >= 1 Then If BoardPlayer(W1, W2 - 1) = Player Then If (BoardPiece(W1, W2 - 1) = 1 And BoardRotate(W1, W2 - 1) = 2) Or BoardPiece(W1, W2 - 1) = 3 Then X = X + 1: Playable(W1, W2 - 1) = 1
If W1 - 1 >= 1 And W2 - 1 >= 1 Then If BoardPlayer(W1 - 1, W2 - 1) = Player Then If BoardPiece(W1 - 1, W2 - 1) = 2 Then X = X + 1: Playable(W1 - 1, W2 - 1) = 1
If X > 0 Then CanPlay = 1
Return


Winner:
Line (861, 306)-(1120, 430), 2, BF

If Winner = 3 Then
Color 15, 2: Locate 22, 111: Print " After 100 Moves ";
Color 15, 2: Locate 23, 111: Print "Both Have Pieces in Back Row";
Color 15, 2: Locate 25, 111: Print "The Game Ended in a D R A W!";
Else
X1 = 923: X2 = 368: X3 = Winner: X4 = 4: GoSub DrawPiece
Color 15, 2: Locate 24, 126: Print "W I N N E R !";
End If

Color 15, 2: Locate 45, 111: Print "Play Another Game? (Y or N)";
GetYesNo: A$ = UCase$(InKey$): If A$ = "" GoTo GetYesNo
If A$ = "Y" Then Run
If A$ = "N" Then System
GoTo GetYesNo

Print this item

  Tixel Board Game
Posted by: SMcNeill - 12-24-2023, 10:13 AM - Forum: Donald Foster - No Replies

Quote:Hello All,

This is 3 versions of almost the same game. They are all 2 player abstract strategy board game play on a 6x6 game board.

Tix was created first with square shaped pieces.
Tixel was created shortly after with a partial circle cut out of 1 side.
Tixel with Extension Set includes the Tix tile set that each player can choose to exchange some of their Tixel pieces for Tix pieces.

When the pieces are on the board with the sides parallel to the board spaces, those pieces are said to be Inactive.
When the pieces are on the board with the side diagonal to the board spaces, those pieces are said to be Active.
Active pieces can be moved or slid across the board. All Active pieces that are each side of the sliding piece is rotated Inactive.
Pieces can only be put on the board in an Active state. No 2 Active pieces can be directly next to each other.
A player loses when they have no Active Pieces on the board.

An option to play on an 8x8 board included.

A complete copy of both sets of rules are included.

Hope you enjoy playing.

Donald


   


.pdf   Tix Rules.pdf (Size: 998.72 KB / Downloads: 35)

.pdf   Tixel Board Game Rules.pdf (Size: 645.03 KB / Downloads: 42)

Code: (Select All)

_Title "Tixel - Game Designed by Martijn Althuizen - Programmed by Donald L. Foster Jr."

Screen _NewImage(1237, 735, 256)

_PaletteColor 1, _RGB32(255, 0, 0) ' Red
_PaletteColor 2, _RGB32(0, 70, 255) ' Blue
_PaletteColor 3, _RGB32(170, 170, 170) ' Lt Grey
_PaletteColor 4, _RGB32(255, 215, 0) ' Gold
_PaletteColor 5, _RGB32(120, 120, 120) ' DK Grey
_PaletteColor 6, _RGB32(145, 145, 145) ' Med Grey
_Limit 100


Dim V As Integer
Dim W As Integer
Dim X As Integer
Dim Y As Integer
Dim Z As Integer

Dim X1 As Integer
Dim X2 As Integer
Dim X3 As Integer

Dim MouseX As Integer
Dim MouseY As Integer
Dim MouseLeftButton As Integer

Dim Player As Integer ' Current Player
Dim Opponant As Integer ' Current Opponant
Dim GameChoice As Integer ' 1 - Tix, 2 - Tixel, 3 - Tixel with Extensions
Dim Active As Integer ' 0 - Current Piece Not Active, 1 - Current Piece is Active
Dim Piece As Integer ' 1 - Expansion Piece, 2 - Tixel Piece
Dim Rotation As Integer ' 1 - Curve Up or UpRight, 2 - Curve if Right or DownRight, 3 - Curve is Down or DownLeft, 4 - Curve is Left or UpLeft
Dim Direction As Integer ' 1 - Up, 2 - Right, 3 - Down, 4 - Left

Dim GameBoard As Integer ' 1 - 6 X 6 Game Board, 2 - 8 X 8 Game Board
Dim Pieces As Integer ' Number of Pieces Each Player Has: 1 - 8, 2 - 10
Dim BoardSize As Integer
Dim PieceSize As Integer
Dim BonusMove As Integer
Dim StartingX As Integer
Dim StartingY As Integer
Dim Increase As Integer
Dim PoolX As Integer
Dim PoolY As Integer
Dim Rotate As Integer
Dim RotationX As Integer
Dim RotationY As Integer
Dim Playable As Integer
Dim LastRow As Integer
Dim LastCol As Integer
Dim Row As Integer
Dim Col As Integer
Dim Row1 As Integer
Dim Col2 As Integer
Dim Column1 As Integer
Dim Row2 As Integer
Dim Column2 As Integer
Dim Escape As Integer
Dim Update As Integer

Dim ButtonY(3) As Integer
Dim FirstMove(2) As Integer ' Is This Players First Move? 1 - Yes, 0 - No
Dim RotationY(4) As Integer
Dim GameCursorY(5) As Integer ' Y Location on Screen for Game Choice Cursor

Dim ExpansionPieces(2) As Integer
Dim RegularPieces(2) As Integer
Dim PoolPieces(2) As Integer
Dim PoolExpPieces(2) As Integer
Dim PoolRegPieces(2) As Integer
Dim BoardPlayer(8, 8) As Integer ' Player at Selected Board Location: 0 - Empty, 1 - Player 1, 2 - Player 2
Dim BoardPiece(8, 8) As Integer ' Piece at Selected Board Location: 1 - Pix / Extension Piece, 2 - Pixel
Dim BoardActive(8, 8) As Integer
Dim BoardRotation(8, 8) As Integer ' Rotation of Piece at Selected Board Location: 1 - 4
Dim BoardX(8, 8) As Integer ' X Location Board Square is on the Screen
Dim BoardY(8, 8) As Integer ' Y Location Board Square is on the Screen
Dim Playable(8, 8) As Integer
Dim CircleSize(2) As Integer
Dim Start(2, 2, 4) As _Float
Dim EndCir(2, 2, 4) As _Float
Dim SetBack(2, 2) As Integer
Dim Xsetback(2, 2, 4) As Integer
Dim Ysetback(2, 2, 4) As Integer

Dim Piece$(2, 2, 3)
Dim Rotate$(2, 4)
Dim Remove$(2)
Dim Playable$(2)
Dim RemoveIndicator$(2)
Dim Box$(2)
Dim Button$(3)

Player = 1: Opponant = 2: BonusMove = 0
FirstMove(1) = 1: FirstMove(2) = 1
CircleSize(1) = 82: CircleSize(2) = 63
SetBack(1, 0) = 88: SetBack(1, 1) = 82: SetBack(2, 0) = 115

Xsetback(1, 0, 1) = 0: Ysetback(1, 0, 1) = -115: Xsetback(1, 0, 2) = 115: Ysetback(1, 0, 2) = 0: Xsetback(1, 0, 3) = 0: Ysetback(1, 0, 3) = 115: Xsetback(1, 0, 4) = -115: Ysetback(1, 0, 4) = 0
Xsetback(1, 1, 1) = 82: Ysetback(1, 1, 1) = -82: Xsetback(1, 1, 2) = 82: Ysetback(1, 1, 2) = 82: Xsetback(1, 1, 3) = -82: Ysetback(1, 1, 3) = 82: Xsetback(1, 1, 4) = -82: Ysetback(1, 1, 4) = -82
Xsetback(2, 0, 1) = 0: Ysetback(2, 0, 1) = -88: Xsetback(2, 0, 2) = 88: Ysetback(2, 0, 2) = 0: Xsetback(2, 0, 3) = 0: Ysetback(2, 0, 3) = 88: Xsetback(2, 0, 4) = -88: Ysetback(2, 0, 4) = 0
Xsetback(2, 1, 1) = 62: Ysetback(2, 1, 1) = -62: Xsetback(2, 1, 2) = 62: Ysetback(2, 1, 2) = 62: Xsetback(2, 1, 3) = -62: Ysetback(2, 1, 3) = 62: Xsetback(2, 1, 4) = -62: Ysetback(2, 1, 4) = -62

Start(1, 0, 1) = 4.00: EndCir(1, 0, 1) = 5.42: Start(1, 0, 2) = 2.42: EndCir(1, 0, 2) = 3.88: Start(1, 0, 3) = 0.88: EndCir(1, 0, 3) = 2.27: Start(1, 0, 4) = 5.57: EndCir(1, 0, 4) = 0.73
Start(1, 1, 1) = 3.23: EndCir(1, 1, 1) = 4.65: Start(1, 1, 2) = 1.62: EndCir(1, 1, 2) = 3.06: Start(1, 1, 3) = 0.08: EndCir(1, 1, 3) = 1.50: Start(1, 1, 4) = 4.78: EndCir(1, 1, 4) = 6.19
Start(2, 0, 1) = 4.07: EndCir(2, 0, 1) = 5.37: Start(2, 0, 2) = 2.48: EndCir(2, 0, 2) = 3.82: Start(2, 0, 3) = 0.94: EndCir(2, 0, 3) = 2.21: Start(2, 0, 4) = 5.63: EndCir(2, 0, 4) = 0.67
Start(2, 1, 1) = 3.29: EndCir(2, 1, 1) = 4.59: Start(2, 1, 2) = 1.68: EndCir(2, 1, 2) = 3.00: Start(2, 1, 3) = 0.14: EndCir(2, 1, 3) = 1.46: Start(2, 1, 4) = 4.80: EndCir(2, 1, 4) = 6.15

Piece$(1, 1, 1) = "BR53C1U53L107D107R107U54BL10P1,1": Piece$(1, 1, 2) = "BR53C2U53L107D107R107U54BL10P2,2"
Piece$(2, 1, 1) = "BR38C1U38L76D76R76U38BL10P1,1": Piece$(2, 1, 2) = "BR38C2U38L76D76R76U38BL10P2,2"
Piece$(1, 2, 1) = "BL53C1U53D107R107U107D20BL5P1,1": Piece$(1, 2, 2) = "BL53C2U53D107R107U107D20BL5P2,2": Piece$(1, 2, 3) = "BL53C3U53D107R107U107D20BL5P3,3"
Piece$(2, 2, 1) = "BL38C1U38D76R76U76D10BL5P1,1": Piece$(2, 2, 2) = "BL38C2U38D76R76U76D10BL5P2,2": Piece$(2, 2, 3) = "BL38C3U38D76R76U76D10BL5P3,3"
Rotate$(0, 1) = "TA0": Rotate$(0, 2) = "TA270": Rotate$(0, 3) = "TA180": Rotate$(0, 4) = "TA90"
Rotate$(1, 1) = "TA315": Rotate$(1, 2) = "TA225": Rotate$(1, 3) = "TA135": Rotate$(1, 4) = "TA45"
Remove$(1) = "BU63NR15NL15BU2P3,3": Remove$(2) = "BU48NR10NL10BU2P3,3"
Playable$(1) = "TA0C5BR30U30L60D60R60U36BL10P5,5": Playable$(2) = "TA0C5BR25U25L50D50R50U31BL10P5,5"
Box$(1) = "BU70R10P15,15": Box$(2) = "BU50P15,15"
Button$(1) = " Slide Piece ": Button$(2) = " Return Piece": Button$(3) = " Rotate Piece"
TixelT$ = "TA0C4D44R44U44L44BF5P4,4H5C0D44R44U44L44R1D43R42U42L42D11R16D30R10U30R15BH5P0,0"
TixI$ = "TA0C4D44R44U44L44BF5P4,4H5C0D44R44U44L44R1D43R42U42L42R16D41R10U41BG5P0,0"
TixelI$ = "TA0C0NR44D44R44H1l42U42R42L15BD5P4,0U5C0D42L10U42BF5P0,0"
TixelX$ = "C4D44R44U44L44BF5P4,4H5C0D44R44U44L44R1D43R42U42L42R16D16L15D10R15D15R10U15R15U10L15U15BG5P0,0"
TixX$ = "C4G31F31E31H31BD5P4,4BU5C0G31F31E31H31BD3G28F28E28H28BU1P0,0F11G11H11G8F11G11F8E11F11E8H11E11BL10P0,0"
TixelE$ = "TA0C0R44D44L44E1R42U42L42R10BD5P4,0BU6C0R34G9L30BE5P0,0G5BD26R30F9L10BU5P0,0BU12NL27U10L27BF5P0,0"
TixelL$ = "C4D44R44U44L44BF5P4,4H5C0D44R44U44L44R1D43R42U42L42R15ND42R10D32R16BG5P0,0"

Cls , 15: Color 0, 15

' Get Game Choice Cursor Locations
X = 296: For Z = 1 To 5: GameCursorY(Z) = X: X = X + 48: Next

Locate 15, 68: Print "Choose A Game To Play";
Locate 20, 77: Print "Tix";
Locate 23, 76: Print "Tixel";
Locate 26, 66: Print "Tixel With Extension Set";

GetGameChoiceInput:
Do While _MouseInput
For Z = 1 To 3
If _MouseX > 509 And _MouseX < 721 And _MouseY > GameCursorY(Z) - 1 And _MouseY < GameCursorY(Z) + 30 Then
Line (510, GameCursorY(Z))-(720, GameCursorY(Z) + 30), 0, B
If _MouseButton(1) = -1 Then GoSub ReleaseMouseButton: GameChoice = Z: GoTo EndGameChoiceLoop
Else Line (510, GameCursorY(Z))-(720, GameCursorY(Z) + 30), 15, B
End If
Next
Loop
GoTo GetGameChoiceInput

EndGameChoiceLoop:
' Setup Number of Pieces
If GameChoice = 1 Then Piece = 1: Pieces = 8 Else Piece = 2: Pieces = 10

If GameChoice = 1 Then
For Z = 1 To 2
RegularPieces(Z) = 0: PoolRegPieces(Z) = 0
ExpansionPieces(Z) = Pieces: PoolExpPieces(Z) = Pieces
Next
ElseIf GameChoice = 2 Then
For Z = 1 To 2
RegularPieces(Z) = Pieces: PoolRegPieces(Z) = Pieces
ExpansionPieces(Z) = 0: PoolExpPieces(Z) = 0
Next
ElseIf GameChoice = 3 Then
Cls , 15: Color 0, 15
For Y = 1 To 2
Locate 15, 58: Print "Player"; Y; "How Many Expansion Pieces? 0 - 4";: V = 0
For Z = 0 To 4
Locate 20 + V, 70: Print "Exchange"; Z; "Piece(s)";: V = V + 3
Next
GetExpansionInput:
Do While _MouseInput
For Z = 1 To 5
If _MouseX > 518 And _MouseX < 730 And _MouseY > GameCursorY(Z) - 1 And _MouseY < GameCursorY(Z) + 30 Then
Line (519, GameCursorY(Z))-(729, GameCursorY(Z) + 30), 0, B
If _MouseButton(1) = -1 Then
GoSub ReleaseMouseButton: Z = Z - 1
ExpansionPieces(Y) = Z: PoolExpPieces(Y) = Z
RegularPieces(Y) = Pieces - Z: PoolRegPieces(Y) = Pieces - Z
GoTo EndExpansionLoop
End If
Else Line (519, GameCursorY(Z))-(729, GameCursorY(Z) + 30), 15, B
End If
Next
Loop
GoTo GetExpansionInput
EndExpansionLoop:
Next
End If

' Get Game Board Size
Cls , 15: Color 0, 15

Locate 15, 69: Print "Choose A Game Board";
Locate 20, 70: Print "6 X 6 Game Board";
Locate 23, 70: Print "8 X 8 Game Board";

GetGameBoardInput:
Do While _MouseInput
For Z = 1 To 2
If _MouseX > 514 And _MouseX < 726 And _MouseY > GameCursorY(Z) - 1 And _MouseY < GameCursorY(Z) + 30 Then
Line (515, GameCursorY(Z))-(725, GameCursorY(Z) + 30), 0, B
If _MouseButton(1) = -1 Then GoSub ReleaseMouseButton: GameBoard = Z: GoTo EndGameBoardLoop
Else Line (515, GameCursorY(Z))-(725, GameCursorY(Z) + 30), 15, B
End If
Next
Loop
GoTo GetGameBoardInput

EndGameBoardLoop:

' Setup Game Board Borders
If GameBoard = 1 Then
BoardSize = 6: PieceSize = 53: StartingX = 330: StartingY = 79: Increase = 115: PoolX = 80: PoolY = 194: RotationX = 1097
Else BoardSize = 8: PieceSize = 38: StartingX = 320: StartingY = 67: Increase = 86: PoolX = 95: PoolY = 240: RotationX = 1100
End If

' Draw Board
Cls , 15

W = StartingY
For Z = 1 To BoardSize
X = StartingX
For Y = 1 To BoardSize
Line (X - PieceSize, W - PieceSize)-(X + PieceSize, W + PieceSize), 3, BF
BoardX(Z, Y) = X: BoardY(Z, Y) = W
X = X + Increase
Next
W = W + Increase
Next

' Draw Tixel Logo
If GameChoice = 1 Then
PSet (59, 20), 0: Draw TixelT$ + "BR11BU7" + TixI$ + "BR56BU15" + TixX$
Else
Circle (136, 42), 32, 0, 2.3, 3.98: Circle (135, 42), 32, 0, 2.3, 3.98: Circle (140, 42), 32, 0, 5.5, .8: Circle (141, 42), 32, 0, 5.5, .8
PSet (19, 20), 0: Draw TixelT$ + "BR10BU7" + TixelI$ + "BR49BU15" + TixX$ + "BR17BU12" + TixelE$ + "BU22BR34" + TixelL$
If GameChoice = 3 Then Color 0, 15: Locate 6, 9: Print "With Extension Set";
End If

StartGame:

If BoardSize = 6 Then V = 1 Else V = 0
Color 0, 15: Locate 8, 10: Print String$(V, 32); "P L A Y E R: "; Player;

GoSub UpdatePool

CheckForLegalMoves:
Playable = 0
For Z = 1 To BoardSize
For Y = 1 To BoardSize
Playable(Z, Y) = 0
' Check For Piece Placement
If BoardPlayer(Z, Y) = Player And BoardActive(Z, Y) = 1 Then
' Check For Piece Slide
If BonusMove = 1 And Z = LastRow And Y = LastCol GoTo Skip
If Z = 2 And BoardPlayer(1, Y) = 0 Then Playable = 1: Playable(Z, Y) = 1
If Z - 2 >= 1 Then If BoardPlayer(Z - 1, Y) = 0 And ((BoardPlayer(Z - 2, Y) = 0) Or (BoardPiece(Z - 2, Y) = 2 And BoardActive(Z - 2, Y) = 0 And BoardRotation(Z - 2, Y) = 3)) Then Playable = 1: Playable(Z, Y) = 1
If Y = BoardSize - 1 And BoardPlayer(Z, BoardSize) = 0 Then Playable = 1: Playable(Z, Y) = 1
If Y + 2 <= BoardSize Then If BoardPlayer(Z, Y + 1) = 0 And ((BoardPlayer(Z, Y + 2) = 0) Or (BoardPiece(Z, Y + 2) = 2 And BoardActive(Z, Y + 2) = 0 And BoardRotation(Z, Y + 2) = 4)) Then Playable = 1: Playable(Z, Y) = 1
If Z = BoardSize - 1 And BoardPlayer(BoardSize, Y) = 0 Then Playable = 1: Playable(Z, Y) = 1
If Z + 2 <= BoardSize Then If BoardPlayer(Z + 1, Y) = 0 And ((BoardPlayer(Z + 2, Y) = 0) Or (BoardPiece(Z + 2, Y) = 2 And BoardActive(Z + 2, Y) = 0 And BoardRotation(Z + 2, Y) = 1)) Then Playable = 1: Playable(Z, Y) = 1
If Y = 2 And BoardPlayer(Z, 1) = 0 Then Playable = 1: Playable(Z, Y) = 1
If Y - 2 >= 1 Then If BoardPlayer(Z, Y - 1) = 0 And ((BoardPlayer(Z, Y - 2) = 0) Or (BoardPiece(Z, Y - 2) = 2 And BoardActive(Z, Y - 2) = 0 And BoardRotation(Z, Y - 2) = 2)) Then Playable = 1: Playable(Z, Y) = 1
Skip:
End If
Next
Next

If FirstMove(Player) = 1 Then FirstMove(Player) = 0: Playable = 1

' Check if No Moves
If Playable = 0 Then
Locate 2, 125: Print " You Have No Playable Moves. "
Locate 4, 125: Print " Press <ENTER> To Continue. ";
GetENTER: A$ = InKey$: If A$ = "" GoTo GetENTER
If Asc(A$) <> 13 GoTo GetENTER
GoTo Winner
End If

Locate 2, 125: Print " Choose A Board Location. ";
Locate 3, 125: Print " ";

If BonusMove = 1 Then
Locate 4, 125: Print " Activate Non Active Piece. ";
Locate 5, 125: Print " Rotate An Active Piece. ";
Locate 6, 125: Print "Return Active Piece To Pool.";
End If

ChooseALocationInput:
Do While _MouseInput
For Z = 1 To BoardSize
For Y = 1 To BoardSize
If _MouseButton(1) = -1 And _MouseX > BoardX(Z, Y) - PieceSize And _MouseX < BoardX(Z, Y) + PieceSize And _MouseY > BoardY(Z, Y) - PieceSize And _MouseY < BoardY(Z, Y) + PieceSize Then
If BoardPlayer(Z, Y) = Opponant GoTo ChooseALocationInput Else Row1 = Z: Column1 = Y: GoSub ReleaseMouseButton: GoTo EndChoice1
End If
Next
Next
Loop
GoTo ChooseALocationInput

EndChoice1:
Piece = BoardPiece(Row1, Column1): Active = BoardActive(Row1, Column1): Rotation = BoardRotation(Row1, Column1)

' Check for Empty Pool and Selected Empty Board Space
If PoolPieces(Player) = 0 And Piece = 0 GoTo ChooseALocationInput

' Check if Last Piece Played Bonus Move
If BonusMove = 1 And Row1 = LastRow And Column1 = LastCol GoTo ChooseALocationInput

' Place A Piece On The Board
If BoardPlayer(Row1, Column1) = 0 And PoolPieces(Player) > 0 Then
Z = Row1: Y = Column1: GoSub CheckForPlacePiece
If V = 4 Then
Locate 3, 125: Print " ";
Locate 4, 125: Print " ";
Locate 5, 125: Print " ";
Locate 6, 125: Print " ";

Playable = 1: Active = 1: Rotate = 0
X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1)

Circle (X1, X2), 10, 4: Paint (X1, X2), 4

If GameChoice = 1 Then Piece = 1 Else Piece = 2
If PoolRegPieces(Player) > 0 And PoolExpPieces(Player) > 0 Then GoSub ChoosePieceType

If Piece = 2 Then Escape = 0: GoSub ChooseARotation Else Rotation = 2

X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): X3 = Player

Line (X1 - PieceSize, X2 - PieceSize)-(X1 + PieceSize, X2 + PieceSize), 3, BF

BoardPlayer(Row1, Column1) = Player: BoardPiece(Row1, Column1) = Piece: BoardActive(Row1, Column1) = Active: BoardRotation(Row1, Column1) = Rotation
If Piece = 2 Then PoolRegPieces(Player) = PoolRegPieces(Player) - 1 Else PoolExpPieces(Player) = PoolExpPieces(Player) - 1

GoSub DrawPiece: GoTo EndMove
Else If BoardPlayer(Row1, Column1) = 0 GoTo ChooseALocationInput
End If
End If



' Check For Bonus Move
If BonusMove = 1 And BoardPlayer(Row1, Column1) = Player Then Playable(Row1, Column1) = 1: Playable = 1
If Playable = 0 GoTo ChooseALocationInput

If BonusMove = 1 Then
' Activate a Non Active Piece
If Active = 0 Then
Z = Row1: Y = Column1: GoSub CheckForPlacePiece
If V = 4 Then
Active = 1
If Piece = 1 Then
X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): X3 = Player
Line (X1 - PieceSize, X2 - PieceSize)-(X1 + PieceSize, X2 + PieceSize), 3, BF
BoardActive(Row1, Column1) = Active
GoSub DrawPiece: GoTo EndMove
Else
Rotate = 0: Active = 1: Escape = 0: GoSub ChooseARotation
X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): X3 = Player
Line (X1 - PieceSize, X2 - PieceSize)-(X1 + PieceSize, X2 + PieceSize), 3, BF
BoardActive(Row1, Column1) = Active: BoardRotation(Row1, Column1) = Rotate
GoSub DrawPiece: GoTo EndMove
End If
End If
End If
End If

' Check if can Slide
If BonusMove = 0 And BoardPlayer(Row1, Column1) = Player And Active = 1 Then
X = 0: X1 = Row1: X2 = Column1: GoSub CheckSlidePlayable: If X = 0 GoTo ChooseALocationInput
Else If BoardPlayer(Row1, Column1) = Player GoTo ChooseALocationInput
End If

X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): Row = Row1: Col = Column1

Circle (X1, X2), 10, 4: Paint (X1, X2), 4

Piece = BoardPiece(Row1, Column1)
Active = BoardActive(Row1, Column1)
Rotation = BoardRotation(Row1, Column1)

Locate 2, 125: Print "Choose Location To Slide To.";

If BonusMove = 1 Then
Locate 3, 125: Print " ";
Locate 4, 125: Print " Choose An Active Rotation. ";
Locate 5, 125: Print "Return Active Piece To Pool.";
Locate 6, 125: Print " ";
End If

If BonusMove = 1 Then

' Setup Buttons
If Piece = 2 Then V = 3 Else V = 2
X = 0: W = 0
For Z = 1 To V
PSet (1200, 157 + X), 6: Draw "L200D50NG10R200U50E10L220D70R220U70BL10BD8P3,6BR8P5,6BL20BD10P6,6"
Color 15, 6: Locate 12 + W, 131: Print Button$(Z);
ButtonY(Z) = 157 + X: X = X + 96: W = W + 6
Next

GetButtonInput:
Do While _MouseInput
For Z = 1 To V

' Check For Side Move
If _MouseButton(1) = -1 And _MouseX > 999 And _MouseX < 1201 And _MouseY > ButtonY(1) - 1 And _MouseY < ButtonY(1) + 51 Then
GoSub ReleaseMouseButton: Line (985, 10)-(1215, 450), 15, BF
If BoardPlayer(Row1, Column1) = Player And Active = 1 GoTo GetPlayableSlideMoves
End If

' Remove Piece nd Put in Pool
If _MouseButton(1) = -1 And _MouseX > 999 And _MouseX < 1201 And _MouseY > ButtonY(1) - 1 And _MouseY < ButtonY(2) + 51 Then
GoSub ReleaseMouseButton: Line (985, 10)-(1215, 450), 15, BF: Row = Row1: Col = Column1
BoardPlayer(Row1, Column1) = 0: BoardActive(Row1, Column1) = 0: BoardPiece(Row1, Column1) = 0: BoardRotation(Row1, Column1) = 0
If Piece = 1 Then PoolExpPieces(Player) = PoolExpPieces(Player) + 1 Else PoolRegPieces(Player) = PoolRegPieces(Player) + 1
X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): GoSub RemovePlayableIndicators: GoSub RemovePiece: GoTo EndMove
End If

' Check For Piece Rotation
If _MouseButton(1) = -1 And _MouseX > 999 And _MouseX < 1201 And _MouseY > ButtonY(1) - 1 And _MouseY < ButtonY(3) + 51 Then
GoSub ReleaseMouseButton: Line (955, 10)-(1245, 450), 15, BF
Rotate = Rotation: Active = 1: Escape = 1: Update = 0: GoSub ChooseARotation
X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): X3 = Player
Line (X1 - PieceSize, X2 - PieceSize)-(X1 + PieceSize, X2 + PieceSize), 3, BF
BoardActive(Row1, Column1) = Active: BoardRotation(Row1, Column1) = Rotation
GoSub RemovePlayableIndicators: GoSub RemovePiece: GoSub DrawPiece: GoTo EndMove
End If

Next
Loop
GoTo GetButtonInput
End If

GetPlayableSlideMoves:
For Z = 1 To BoardSize: For Y = 1 To BoardSize: Playable(Z, Y) = 0: Next: Next
X = 0: X1 = Row1: X2 = Column1: GoSub CheckSlidePlayable: If X = 0 GoTo ChooseALocationInput

ChooseAMoveInput:
' Get Board Location To Slide Piece
Do While _MouseInput
For Z = 1 To BoardSize
For Y = 1 To BoardSize
If (_MouseButton(1) = -1) * (_MouseX > BoardX(Z, Y) - PieceSize) * (_MouseX < BoardX(Z, Y) + PieceSize) * (_MouseY > BoardY(Z, Y) - PieceSize) * (_MouseY < BoardY(Z, Y) + PieceSize) Then
If Playable(Z, Y) > 0 Then Row2 = Z: Column2 = Y: Direction = Playable(Z, Y): GoSub ReleaseMouseButton: GoTo EndChoice2
End If
Next
Next
Loop
GoTo ChooseAMoveInput

EndChoice2:
X = 0: X1 = Row2: X2 = Column2:

GoSub RemovePlayableIndicators

' Remove Piece Front Starting Position
X1 = BoardX(Row1, Column1): X2 = BoardY(Row1, Column1): Row = Row1: Col = Column1: GoSub RemovePiece
BoardPlayer(Row, Col) = 0: BoardPiece(Row, Col) = 0: BoardActive(Row, Col) = 0: BoardRotation(Row, Col) = 0

' Draw Indicator at Selected Location
X1 = BoardX(Row2, Column2): X2 = BoardY(Row2, Column2)
Circle (X1, X2), 10, 4: Paint (X1, X2), 4

GoSub RotateAffectedPieces

' Get Activation and Rotation of Piece Moved
X1 = Row2: X2 = Column2: GoSub GetActivationRotation

' Setup Piece At New Location
BoardPlayer(Row2, Column2) = Player: BoardPiece(Row2, Column2) = Piece: BoardActive(Row2, Column2) = Active: BoardRotation(Row2, Column2) = Rotation
X1 = BoardX(Row2, Column2): X2 = BoardY(Row2, Column2): X3 = Player: GoSub DrawPiece

'Check if Piece Played Was Sacrified
If Active = 0 Then
Locate 2, 125: Print " Piece Played Was Scrificed. "
Locate 4, 125: Print " Play Bonus Move? ( Y or N ) ";
GetYN: A$ = UCase$(InKey$): If A$ = "" GoTo GetYN
If A$ = "Y" Then BonusMove = 1: LastRow = Row2: LastCol = Column2: GoTo StartGame
If A$ <> "N" GoTo GetYN
End If

EndMove: BonusMove = 0: FirstMove(Player) = 0: Swap Player, Opponant: GoTo StartGame


ReleaseMouseButton:
Do While _MouseInput
If _MouseButton(1) = 0 Then Return
Loop
GoTo ReleaseMouseButton


UpdatePool:
Line (25, 137)-(251, 712), 15, BF
PoolPieces(Player) = PoolRegPieces(Player) + PoolExpPieces(Player)
V1 = 1: W1 = PoolY
For Z1 = 1 To Pieces / 2
X = PoolX
For Y1 = 1 To 2
X1 = X: X2 = W1: X3 = Player: Active = 0: Rotation = 1
If V1 <= RegularPieces(Player) Then
If V1 <= PoolRegPieces(Player) Then Piece = 2: GoSub DrawPiece
Else
If V1 <= RegularPieces(Player) + PoolExpPieces(Player) Then Piece = 1: GoSub DrawPiece
End If
X = X + Increase: V1 = V1 + 1
Next
W1 = W1 + Increase
Next
Return


DrawPiece:
If Piece = 2 Then Circle (X1 + Xsetback(GameBoard, Active, Rotation), X2 + Ysetback(GameBoard, Active, Rotation)), CircleSize(GameBoard), X3, Start(GameBoard, Active, Rotation), EndCir(GameBoard, Active, Rotation)
PSet (X1, X2), Point(X1 + Xsetback(GameBoard, Active, Rotation), X2 + Ysetback(GameBoard, Active, Rotation)): Draw Rotate$(Active, Rotation) + Piece$(GameBoard, Piece, X3)
Return


RemovePiece:
X1 = BoardX(Row, Col): X2 = BoardY(Row, Col)
If GameBoard = 1 Then X = 62 Else X = 47
Line (X1 - X, X2 - X)-(X1 + X, X2 + X), 15, BF
Line (X1 - PieceSize, X2 - PieceSize)-(X1 + PieceSize, X2 + PieceSize), 3, BF
PSet (X1, X2), 3: If Row = 1 Then Draw "TA0" + Box$(GameBoard) Else Draw "TA0" + Remove$(GameBoard)
PSet (X1, X2), 3: If Col = 1 Then Draw "TA90" + Box$(GameBoard) Else Draw "TA90" + Remove$(GameBoard)
PSet (X1, X2), 3: If Row = BoardSize Then Draw "TA180" + Box$(GameBoard) Else Draw "TA180" + Remove$(GameBoard)
PSet (X1, X2), 3: If Col = BoardSize Then Draw "TA270" + Box$(GameBoard) Else Draw "TA270" + Remove$(GameBoard)
Return


RemovePlayableIndicators:
For Z2 = 1 To BoardSize
For Y2 = 1 To BoardSize
If Playable(Z2, Y2) > 0 Then Playable(Z2, Y2) = 0: Paint (BoardX(Z2, Y2) - 1, BoardY(Z2, Y2)), 3
Next
Next
Return


CheckForPlacePiece:
V = 0
If Z = 1 Then V = V + 1
If Z - 1 >= 1 Then If (BoardPlayer(Z - 1, Y) = 0) Or (BoardPiece(Z - 1, Y) = 2 And BoardActive(Z - 1, Y) = 0 And BoardRotation(Z - 1, Y) = 3) Then V = V + 1
If Y = BoardSize Then V = V + 1
If Y + 1 <= BoardSize Then If (BoardPlayer(Z, Y + 1) = 0) Or (BoardPiece(Z, Y + 1) = 2 And BoardActive(Z, Y + 1) = 0 And BoardRotation(Z, Y + 1) = 4) Then V = V + 1
If Z = BoardSize Then V = V + 1
If Z + 1 <= BoardSize Then If (BoardPlayer(Z + 1, Y) = 0) Or (BoardPiece(Z + 1, Y) = 2 And BoardActive(Z + 1, Y) = 0 And BoardRotation(Z + 1, Y) = 1) Then V = V + 1
If Y = 1 Then V = V + 1
If Y - 1 >= 1 Then If (BoardPlayer(Z, Y - 1) = 0) Or (BoardPiece(Z, Y - 1) = 2 And BoardActive(Z, Y - 1) = 0 And BoardRotation(Z, Y - 1) = 2) Then V = V + 1
If V = 4 Then X = 1: Playable(Z, Y) = 1
Return


ChoosePieceType:
Locate 2, 125: Print " Choose A Piece Type. ";

If GameBoard = 1 Then V = 79 Else V = 60

X = 173
For Z = 1 To 2
X1 = RotationX: X2 = X: RotationY(Z) = X: Piece = Z: Rotation = 1: GoSub DrawPiece
X = X + 160
Next

GetPieceInput:
Do While _MouseInput
For Z = 1 To 2
If _MouseX > RotationX - V And _MouseX < RotationX + V And _MouseY > RotationY(Z) - V And _MouseY < RotationY(Z) + V Then
Line (RotationX - V, RotationY(Z) - V)-(RotationX + V, RotationY(Z) + V), 0, B
If _MouseButton(1) = -1 Then GoSub ReleaseMouseButton: Piece = Z: GoTo EndPieceLoop
Else Line (RotationX - V, RotationY(Z) - V)-(RotationX + V, RotationY(Z) + V), 15, B
End If
Next
Loop
GoTo GetPieceInput

EndPieceLoop:
Line (1010, 50)-(1185, 735), 15, BF
Return


ChooseARotation:
For Z = 2 To 6: Locate Z, 125: Print String$(32, 30);: Next

Locate 2, 125: Print " Choose A Rotation. ";

If GameBoard = 1 Then V = 79 Else V = 60
Sel(1) = 0: Sel(2) = 0: Sel(3) = 0: Sel(4) = 0
If Rotate = 0 Then Sel(1) = 1: Sel(2) = 1: Sel(3) = 1: Sel(4) = 1
If Rotate = 1 Then Sel(2) = 1: Sel(4) = 1
If Rotate = 2 Then Sel(1) = 1: Sel(3) = 1
If Rotate = 3 Then Sel(2) = 1: Sel(4) = 1
If Rotate = 4 Then Sel(1) = 1: Sel(3) = 1

X = 173
For A = 1 To 4
X1 = RotationX: X2 = X: RotationY(A) = X: Rotation = A
If Sel(A) = 1 Then X3 = Player Else X3 = 3
GoSub DrawPiece
X = X + 160
Next

GetRotationInput:
Do While _MouseInput
For A = 1 To 4
If _MouseX > RotationX - V And _MouseX < RotationX + V And _MouseY > RotationY(A) - V And _MouseY < RotationY(A) + V Then
If Sel(A) = 1 Then
Line (RotationX - V, RotationY(A) - V)-(RotationX + V, RotationY(A) + V), 0, B
Else Line (RotationX - V, RotationY(A) - V)-(RotationX + V, RotationY(A) + V), 15, B
End If
If _MouseButton(1) = -1 And Sel(A) = 1 Then GoSub ReleaseMouseButton: Rotation = A: GoTo EndRotationLoop
Else Line (RotationX - V, RotationY(A) - V)-(RotationX + V, RotationY(A) + V), 15, B
End If
Next
Loop
GoTo GetRotationInput

EndRotationLoop:
Line (1010, 50)-(1185, 735), 15, BF
Return


CheckSlidePlayable:
V = 0:
CheckUp:
W = 0
If X1 - V - 1 >= 1 Then
V = V + 1
If BoardPlayer(X1 - V, X2) = 0 Then
If Piece = 2 Then W = 1
If X1 - V = 1 Then W = 1
If X1 - V - 1 >= 1 Then
If BoardPlayer(X1 - V - 1, X2) = 0 Then W = 1
If BoardActive(X1 - V - 1, X2) = 0 Then W = 1
End If
End If
If W = 1 Then X = 1: Playable(X1 - V, X2) = 1: PSet (BoardX(X1 - V, X2), BoardY(X1 - V, X2)), 3: Draw Playable$(GameBoard): GoTo CheckUp
End If

V = 0:
CheckRight:
W = 0
If X2 + V + 1 <= BoardSize Then
V = V + 1
If BoardPlayer(X1, X2 + V) = 0 Then
If X2 + V = BoardSize Then W = 1
If Piece = 2 Then W = 1
If X2 + V + 1 <= BoardSize Then
If BoardPlayer(X1, X2 + V + 1) = 0 Then W = 1
If BoardActive(X1, X2 + V + 1) = 0 Then W = 1
End If
If W = 1 Then X = 1: Playable(X1, X2 + V) = 2: PSet (BoardX(X1, X2 + V), BoardY(X1, X2 + V)), 3: Draw Playable$(GameBoard): GoTo CheckRight
End If
End If

V = 0:
CheckDown:
W = 0
If X1 + V + 1 <= BoardSize Then
V = V + 1
If BoardPlayer(X1 + V, X2) = 0 Then
If X1 + V = BoardSize Then W = 1
If Piece = 2 Then W = 1
If X1 + V + 1 <= BoardSize Then
If BoardPlayer(X1 + V + 1, X2) = 0 Then W = 1
If BoardActive(X1 + V + 1, X2) = 0 Then W = 1
End If
If W = 1 Then X = 1: Playable(X1 + V, X2) = 3: PSet (BoardX(X1 + V, X2), BoardY(X1 + V, X2)), 3: Draw Playable$(GameBoard): GoTo CheckDown
End If
End If

V = 0:
CheckLeft:
W = 0
If X2 - V - 1 >= 1 Then
V = V + 1
If BoardPlayer(X1, X2 - V) = 0 Then
If X2 - V = 1 Then W = 1
If Piece = 2 Then W = 1
If X2 - V - 1 >= 1 Then
If BoardPlayer(X1, X2 - V - 1) = 0 Then W = 1
If BoardActive(X1, X2 - V - 1) = 0 Then W = 1
End If
If W = 1 Then X = 1: Playable(X1, X2 - V) = 4: PSet (BoardX(X1, X2 - V), BoardY(X1, X2 - V)), 3: Draw Playable$(GameBoard): GoTo CheckLeft
End If
End If
Return


RotateAffectedPieces:
Select Case Direction
Case 1:
For A = Row1 - 1 To Row2 Step -1
If Column1 - 1 >= 1 Then
If BoardActive(A, Column1 - 1) = 1 Then
Rotation = BoardRotation(A, Column1 - 1): Piece = BoardPiece(A, Column1 - 1)
BoardActive(A, Column1 - 1) = 0: BoardRotation(A, Column1 - 1) = Rotation
X1 = BoardX(A, Column1 - 1): X2 = BoardY(A, Column1 - 1): Row = A: Col = Column1 - 1
Active = 0: X3 = BoardPlayer(A, Column1 - 1): GoSub RemovePiece: GoSub DrawPiece
End If
End If
If Column1 + 1 <= BoardSize Then
If BoardActive(A, Column1 + 1) = 1 Then
Rotation = BoardRotation(A, Column1 + 1): Piece = BoardPiece(A, Column1 + 1)
If Piece = 2 Then If Rotation = 4 Then Rotation = 1 Else Rotation = Rotation + 1
BoardActive(A, Column1 + 1) = 0: BoardRotation(A, Column1 + 1) = Rotation
X1 = BoardX(A, Column1 + 1): X2 = BoardY(A, Column1 + 1): Row = A: Col = Column1 + 1
Active = 0: X3 = BoardPlayer(A, Column1 + 1): GoSub RemovePiece: GoSub DrawPiece
End If
End If
Next

Case 2:
For A = Column1 + 1 To Column2
If Row1 - 1 >= 1 Then
If BoardActive(Row1 - 1, A) = 1 Then
Rotation = BoardRotation(Row1 - 1, A): Piece = BoardPiece(Row1 - 1, A)
BoardActive(Row1 - 1, A) = 0: BoardRotation(Row1 - 1, A) = Rotation
X1 = BoardX(Row1 - 1, A): X2 = BoardY(Row1 - 1, A): Row = Row1 - 1: Col = A
Active = 0: X3 = BoardPlayer(Row1 - 1, A): GoSub RemovePiece: GoSub DrawPiece
End If
End If
If Row1 + 1 <= BoardSize Then
If BoardActive(Row1 + 1, A) = 1 Then
Rotation = BoardRotation(Row1 + 1, A): Piece = BoardPiece(Row1 + 1, A)
If Piece = 2 Then If Rotation = 4 Then Rotation = 1 Else Rotation = Rotation + 1
BoardActive(Row1 + 1, A) = 0: BoardRotation(Row1 + 1, A) = Rotation
X1 = BoardX(Row1 + 1, A): X2 = BoardY(Row1 + 1, A): Row = Row1 + 1: Col = A
Active = 0: X3 = BoardPlayer(Row1 + 1, A): GoSub RemovePiece: GoSub DrawPiece
End If
End If
Next

Case 3:
For A = Row1 + 1 To Row2
If Column1 - 1 >= 1 Then
If BoardActive(A, Column1 - 1) = 1 Then
Rotation = BoardRotation(A, Column1 - 1): Piece = BoardPiece(A, Column1 - 1)
If Piece = 2 Then If Rotation = 4 Then Rotation = 1 Else Rotation = Rotation + 1
BoardActive(A, Column1 - 1) = 0: BoardRotation(A, Column1 - 1) = Rotation
X1 = BoardX(A, Column1 - 1): X2 = BoardY(A, Column1 - 1): Row = A: Col = Column1 - 1
Active = 0: X3 = BoardPlayer(A, Column1 - 1): GoSub RemovePiece: GoSub DrawPiece
End If
End If
If Column1 + 1 <= BoardSize Then
If BoardActive(A, Column1 + 1) = 1 Then
Rotation = BoardRotation(A, Column1 + 1): Piece = BoardPiece(A, Column1 + 1)
BoardActive(A, Column1 + 1) = 0: BoardRotation(A, Column1 + 1) = Rotation
X1 = BoardX(A, Column1 + 1): X2 = BoardY(A, Column1 + 1): Row = A: Col = Column1 + 1
Active = 0: X3 = BoardPlayer(A, Column1 + 1): GoSub RemovePiece: GoSub DrawPiece
End If
End If

Next
Case 4:
For A = Column1 - 1 To Column2 Step -1
If Row1 - 1 >= 1 Then
If BoardActive(Row1 - 1, A) = 1 Then
Rotation = BoardRotation(Row1 - 1, A): Piece = BoardPiece(Row1 - 1, A)
If Piece = 2 Then If Rotation = 4 Then Rotation = 1 Else Rotation = Rotation + 1
BoardActive(Row1 - 1, A) = 0: BoardRotation(Row1, A) = Rotation
X1 = BoardX(Row1 - 1, A): X2 = BoardY(Row1 - 1, A): Row = Row1 - 1: Col = A
Active = 0: X3 = BoardPlayer(Row1 - 1, A): GoSub RemovePiece: GoSub DrawPiece
End If
End If
If Row1 + 1 <= BoardSize Then
If BoardActive(Row1 + 1, A) = 1 Then
Rotation = BoardRotation(Row1 + 1, A): Piece = BoardPiece(Row1 + 1, A)
BoardActive(Row1 + 1, A) = 0: BoardRotation(Row1 + 1, A) = Rotation: Row = Row1 + 1: Col = A
X1 = BoardX(Row1 + 1, A): X2 = BoardY(Row1 + 1, A): Row = Row1 + 1: Col = A
Active = 0: X3 = BoardPlayer(Row1 + 1, A): GoSub RemovePiece: GoSub DrawPiece
End If
End If

Next

End Select
Return


GetActivationRotation:
V = 0
If X1 = 1 Then V = V + 1
If X1 - 1 >= 1 Then If BoardPlayer(X1 - 1, X2) = 0 Or (BoardPiece(X1 - 1, X2) = 2 And BoardActive(X1 - 1, X2) = 0 And BoardRotation(X1 - 1, X2) = 3) Then V = V + 1
If X2 = BoardSize Then V = V + 1
If X2 + 1 <= BoardSize Then If BoardPlayer(X1, X2 + 1) = 0 Or (BoardPiece(X1, X2 + 1) = 2 And BoardActive(X1, X2 + 1) = 0 And BoardRotation(X1, X2 + 1) = 4) Then V = V + 1
If X1 = BoardSize Then V = V + 1
If X1 + 1 <= BoardSize Then If BoardPlayer(X1 + 1, X2) = 0 Or (BoardPiece(X1 + 1, X2) = 2 And BoardActive(X1 + 1, X2) = 0 And BoardRotation(X1 + 1, X2) = 1) Then V = V + 1
If X2 = 1 Then V = V + 1
If X2 - 1 >= 1 Then If BoardPlayer(X1, X2 - 1) = 0 Or (BoardPiece(X1, X2 - 1) = 2 And BoardActive(X1, X2 - 1) = 0 And BoardRotation(X1, X2 - 1) = 2) Then V = V + 1
If V = 4 Then
Active = 1: Rotation = 0: If Piece = 2 Then GoSub ChooseARotation Else Rotation = 1
Else
Active = 0: Rotation = 0
Select Case Direction
Case 1: If X1 - 1 >= 1 Then If BoardActive(X1 - 1, X2) = 1 Then Rotation = 1
Case 2: If X2 + 1 <= BoardSize Then If BoardActive(X1, X2 + 1) = 1 Then Rotation = 2
Case 3: If X1 + 1 <= BoardSize Then If BoardActive(X1 + 1, X2) = 1 Then Rotation = 3
Case 4: If X2 - 1 >= 1 Then If BoardActive(X1, X2 - 1) = 1 Then Rotation = 4
End Select
If Rotation = 0 Then If Piece = 2 Then GoSub ChooseARotation Else Rotation = 1
End If
Return


Winner:
Swap Player, Opponant

Color 0, 15: Locate 8, 10: Print String$(V, 32); "P L A Y E R: "; Player;:

GoSub UpdatePool

Locate 2, 125: Print " Player"; Player; "is the Winner!!! ";
Locate 3, 125: Print " ";
Locate 4, 124: Print "Play Another Game? ( Y or N )";

AnotherGame:
A$ = UCase$(InKey$): If A$ = "" GoTo AnotherGame
If A$ = "Y" Then Run
If A$ = "N" Then System
GoTo AnotherGame

Print this item