#include "fbgfx.bi"

DECLARE SUB MyChainLayer ()

TYPE MyChainType
X AS SINGLE
Y AS SINGLE
OldX AS SINGLE
OldY AS SINGLE
Sprite AS INTEGER
Mode AS INTEGER
Exists AS INTEGER
Length AS INTEGER
PullDistance AS INTEGER
EndDistance AS INTEGER
Fixed AS INTEGER
Speed AS SINGLE
END TYPE

const FALSE = 0
const TRUE = 1
const numofrings = 50
const numofchains = 10
const fpslimit = 80

DIM SHARED MyChain(numofchains, numofrings) AS MyChainType
DIM SHARED set_num_of_chains, set_num_of_rings 
DIM SHARED workpage
DIM SHARED st AS DOUBLE

SCREENRES 640, 480, 8, 2, 0
SCREENSET 1, 0
SETMOUSE 50,50,0

set_num_of_chains = 1
set_num_of_rings = 25

FOR initchain = 1 TO set_num_of_chains
FOR initring = 1 TO set_num_of_rings
MyChain(initchain, initring).Exists = TRUE    
MyChain(initchain, initring).Sprite = 1
IF initring = set_num_of_rings THEN MyChain(initchain, initring).Sprite = 2
MyChain(initchain, initring).PullDistance = 12
MyChain(initchain, initring).EndDistance = 14
MyChain(initchain, initring).Speed = 2
MyChain(initchain, initring).X = 320
MyChain(initchain, initring).Y = 20 + initring * 7
NEXT initring
NEXT initchain
MyChain(1, 1).Fixed = TRUE ' ring 1 is fixed!

DO

screenset workpage, workpage xor 1

CLS

MyChainLayer

IF MULTIKEY(SC_RIGHT) THEN MyChain(1, set_num_of_rings).X = MyChain(1, set_num_of_rings).X + MyChain(1, set_num_of_rings).Speed
IF MULTIKEY(SC_LEFT) THEN MyChain(1, set_num_of_rings).X = MyChain(1, set_num_of_rings).X - MyChain(1, set_num_of_rings).Speed
IF MULTIKEY(SC_DOWN) THEN MyChain(1, set_num_of_rings).Y = MyChain(1, set_num_of_rings).Y + MyChain(1, set_num_of_rings).Speed
IF MULTIKEY(SC_UP) THEN MyChain(1, set_num_of_rings).Y = MyChain(1, set_num_of_rings).Y - MyChain(1, set_num_of_rings).Speed

IF ABS(MyChain(1, set_num_of_rings).X-MyChain(1, set_num_of_rings-1).X)>MyChain(1, set_num_of_rings).EndDistance THEN MyChain(1, set_num_of_rings).X = MyChain(1, set_num_of_rings).OldX
IF ABS(MyChain(1, set_num_of_rings).Y-MyChain(1, set_num_of_rings-1).Y)>MyChain(1, set_num_of_rings).EndDistance THEN MyChain(1, set_num_of_rings).Y = MyChain(1, set_num_of_rings).OldY

workpage xor = 1

do 
loop until timer& - st >= (1/fpslimit) 
st = timer& 

SLEEP 1

LOOP UNTIL MULTIKEY(SC_ESCAPE)

SUB MyChainLayer ()

' Loop through our chains and chain pieces for
' every chain.
FOR countchain = 1 TO set_num_of_chains
FOR countring = 1 TO set_num_of_rings

' Store the chain piece position before moving it.
MyChain(countchain, countring).OldX = MyChain(countchain, countring).X
MyChain(countchain, countring).OldY = MyChain(countchain, countring).Y

' If not moving the last chain piece(IF countring + 1 <= set_num_of_rings)
' and if the current piece is not fixed move it!
IF countring + 1 <= set_num_of_rings AND MyChain(countchain, countring).Fixed = FALSE THEN
' If the next chain piece(countring+1) is more than PullDistance pixels 
' left from the current chain piece(countring), move the current chain 
' piece toward left.
IF MyChain(countchain, countring).X-MyChain(countchain, countring+1).X>MyChain(countchain, countring).PullDistance THEN
MyChain(countchain, countring).X = MyChain(countchain, countring).X-MyChain(countchain, countring).Speed
' Align the current piece with the next piece it follows, if it's higher 
' or lower from this piece. This part is tweaked in the sense of
' "alignment speed" and requires tweaking with speed changes.
IF MyChain(countchain, countring).Y>MyChain(countchain, countring+1).Y THEN MyChain(countchain, countring).Y = MyChain(countchain, countring).Y-ABS(MyChain(countchain, countring).Y-MyChain(countchain, countring+1).Y)*0.08*MyChain(countchain, countring).Speed
IF MyChain(countchain, countring).Y<MyChain(countchain, countring+1).Y THEN MyChain(countchain, countring).Y = MyChain(countchain, countring).Y+ABS(MyChain(countchain, countring).Y-MyChain(countchain, countring+1).Y)*0.08*MyChain(countchain, countring).Speed
END IF
' If the next chain piece is more than PullDistance pixels right from
' the current chain piece, move the current chain piece toward right.
IF MyChain(countchain, countring).X-MyChain(countchain, countring+1).X<-MyChain(countchain, countring).PullDistance THEN
MyChain(countchain, countring).X = MyChain(countchain, countring).X+MyChain(countchain, countring).Speed
IF MyChain(countchain, countring).Y>MyChain(countchain, countring+1).Y THEN MyChain(countchain, countring).Y = MyChain(countchain, countring).Y-ABS(MyChain(countchain, countring).Y-MyChain(countchain, countring+1).Y)*0.08*MyChain(countchain, countring).Speed
IF MyChain(countchain, countring).Y<MyChain(countchain, countring+1).Y THEN MyChain(countchain, countring).Y = MyChain(countchain, countring).Y+ABS(MyChain(countchain, countring).Y-MyChain(countchain, countring+1).Y)*0.08*MyChain(countchain, countring).Speed
END IF
' If the next chain piece is more than PullDistance pixels up from
' the current chain piece, move the current chain piece toward up.
IF MyChain(countchain, countring).Y-MyChain(countchain, countring+1).Y>MyChain(countchain, countring).PullDistance THEN
MyChain(countchain, countring).Y = MyChain(countchain, countring).Y-MyChain(countchain, countring).Speed
' Align the current piece with the next piece it follows, if it's left 
' or right from this piece. This part is tweaked in the sense of
' "alignment speed" and requires tweeking with speed changes.
IF MyChain(countchain, countring).X>MyChain(countchain, countring+1).X THEN MyChain(countchain, countring).X = MyChain(countchain, countring).X-ABS(MyChain(countchain, countring).X-MyChain(countchain, countring+1).X)*0.08*MyChain(countchain, countring).Speed
IF MyChain(countchain, countring).X<MyChain(countchain, countring+1).X THEN MyChain(countchain, countring).X = MyChain(countchain, countring).X+ABS(MyChain(countchain, countring).X-MyChain(countchain, countring+1).X)*0.08*MyChain(countchain, countring).Speed
END IF
' If the next chain piece is more than PullDistance pixels down from
' the current chain piece, move the current chain piece toward down.
IF MyChain(countchain, countring).Y-MyChain(countchain, countring+1).Y<-MyChain(countchain, countring).PullDistance THEN
MyChain(countchain, countring).Y = MyChain(countchain, countring).Y+MyChain(countchain, countring).Speed
IF MyChain(countchain, countring).X>MyChain(countchain, countring+1).X THEN MyChain(countchain, countring).X = MyChain(countchain, countring).X-ABS(MyChain(countchain, countring).X-MyChain(countchain, countring+1).X)*0.08*MyChain(countchain, countring).Speed
IF MyChain(countchain, countring).X<MyChain(countchain, countring+1).X THEN MyChain(countchain, countring).X = MyChain(countchain, countring).X+ABS(MyChain(countchain, countring).X-MyChain(countchain, countring+1).X)*0.08*MyChain(countchain, countring).Speed
END IF
END IF

' The next lines keep the chain rings in a string if one of them is fixed.
IF countring > 1 AND ABS(MyChain(countchain, countring).X-MyChain(countchain, countring-1).X)>MyChain(countchain, countring).EndDistance THEN MyChain(countchain, countring).X = MyChain(countchain, countring).OldX
IF countring > 1 AND ABS(MyChain(countchain, countring).Y-MyChain(countchain, countring-1).Y)>MyChain(countchain, countring).EndDistance THEN MyChain(countchain, countring).Y = MyChain(countchain, countring).OldY

' If a chain piece exists draw it!
' According to the piece sprite draw a specific kind 
' of blob. In a proper game CIRCLE statements should 
' be replaced with PUT and memory buffers holding the
' blob sprites should be connected with
' MyChain(countchain, countring).Sprite.
' Sprite = 1 ' green blob
' Sprite = 2 ' red blob(snake's head)
IF MyChain(countchain, countring).Exists = TRUE THEN
IF MyChain(countchain, countring).Sprite = 1 THEN
CIRCLE (MyChain(countchain, countring).X, MyChain(countchain, countring).Y), 15, 2, , , , F    
CIRCLE (MyChain(countchain, countring).X, MyChain(countchain, countring).Y), 15, 118
LINE (MyChain(countchain, countring).X-5,MyChain(countchain, countring).Y-5)-(MyChain(countchain, countring).X-4,MyChain(countchain, countring).Y-6), 47
END IF
IF MyChain(countchain, countring).Sprite = 2 THEN
CIRCLE (MyChain(countchain, countring).X, MyChain(countchain, countring).Y), 15, 40, , , , F    
CIRCLE (MyChain(countchain, countring).X, MyChain(countchain, countring).Y), 15, 4
LINE (MyChain(countchain, countring).X-5,MyChain(countchain, countring).Y-5)-(MyChain(countchain, countring).X-4,MyChain(countchain, countring).Y-6), 43
END IF
END IF
    
NEXT countring
NEXT countchain
    
END SUB