Author Topic: Tic Tac Toe Rings by Fellippe Heitor  (Read 469 times)

Offline Qwerkey

  • Moderator
  • Forum Resident
  • Posts: 736
Tic Tac Toe Rings by Fellippe Heitor
« on: May 24, 2020, 05:40:12 AM »
Tic Tac Toe Rings

Author: @FellippeHeitor
Source: qb64.org Forum
URL: https://www.qb64.org/forum/index.php?topic=2368.0
Version: 1
Tags: [Graphics], [Skill], [Addictive]

Description:
I recently found the game Rings by a studio called Gamezaur. This is my attempt at recreating it.

I won't elaborate on the gameplay here. Keep the concept of "Tic Tac Toe" in mind - except it's single-player mode - and you should master it in no time.


Code: QB64: [Select]
  1.  
  2. $EXEICON:'./assets/images/tttr.ico'
  3.  
  4. $VERSIONINFO:FILEVERSION#=1,0,0,0
  5. $VERSIONINFO:PRODUCTVERSION#=1,0,0,0
  6. $VERSIONINFO:CompanyName=Fellippe Heitor
  7. $VERSIONINFO:ProductName=Tic Tac Toe Ring
  8. $VERSIONINFO:ProductVersion=1.0
  9. $VERSIONINFO:Comments=Based ON 'Rings.' by Gamezaur; Created with QB64.
  10. $VERSIONINFO:Web=https://github.COM/FellippeHeitor/TicTacToeRing
  11. $VERSIONINFO:InternalName=tictactoering.bas
  12.  
  13. CONST true = -1, false = 0
  14.  
  15. 'Required shared variables for printLarge
  16. DIM SHARED charSet(255, 1 TO 16, 1 TO 8) AS _BYTE
  17.  
  18. initializeCharSetPrintLarge
  19.  
  20. TYPE object
  21.     x AS SINGLE
  22.     y AS SINGLE
  23.     xv AS SINGLE
  24.     yv AS SINGLE
  25.     xa AS SINGLE
  26.     ya AS SINGLE
  27.     set AS STRING * 6
  28.     size AS SINGLE
  29.     start AS SINGLE
  30.     duration AS SINGLE
  31.     state AS _BYTE
  32.     text AS INTEGER
  33.     w AS INTEGER
  34.     h AS INTEGER
  35.     r AS INTEGER
  36.     g AS INTEGER
  37.     b AS INTEGER
  38.  
  39. DIM canvas AS LONG
  40. canvas = _NEWIMAGE(600, 600, 32)
  41.  
  42. SCREEN canvas
  43. _TITLE "Tic Tac Toe Ring"
  44.  
  45. DIM peg(0 TO 12) AS object
  46. DIM del(1 TO 9) AS object
  47.  
  48. DIM emptySet$
  49. emptySet$ = MKI$(-1) + MKI$(-1) + MKI$(-1)
  50. peg(0).set = emptySet$
  51.  
  52. 'set pegs positions
  53. DIM spacing AS INTEGER
  54. setPegs
  55.  
  56. 'set combo messages
  57. DIM megaComboMsg$(1 TO 6)
  58. setComboMessages
  59.  
  60. setRingColors
  61.  
  62. DIM circleImage(1 TO i, 1 TO 3) AS LONG
  63. generateRingImages
  64.  
  65. DIM crownIcon AS LONG
  66. generateCrownIcon
  67.  
  68. DIM bg AS LONG, bgWithoutShelf AS LONG
  69. generateBG
  70.  
  71. 'flash warning
  72. _PUTIMAGE (0, 0), bg
  73. centerLarge (_HEIGHT / 2) - fontHeightLarge(2) / 2, "This game contains bright,", 2
  74. centerLarge (_HEIGHT / 2) + fontHeightLarge(2) / 2, "rapidly flashing colors.", 2
  75.  
  76. DIM music AS _BYTE, sfx AS _BYTE
  77. music = true
  78. sfx = true
  79.  
  80. loadGame
  81.  
  82. 'load sounds
  83. j = TIMER
  84. DIM selectSound AS LONG
  85. selectSound = _SNDOPEN("assets/sounds/select.ogg")
  86. IF selectSound > 0 THEN _SNDVOL selectSound, .3
  87.  
  88. DIM wooshSound AS LONG
  89. wooshSound = _SNDOPEN("assets/sounds/woosh.ogg")
  90. IF wooshSound > 0 THEN _SNDVOL wooshSound, .5
  91.  
  92. DIM woodblock AS LONG
  93. woodblock = _SNDOPEN("assets/sounds/woodblock.wav")
  94.  
  95. DIM track(1 TO 1) AS LONG, mainTrackVolume AS SINGLE
  96. track(1) = _SNDOPEN("assets/music/track1.ogg")
  97. mainTrackVolume = 1
  98. IF track(1) > 0 THEN _SNDVOL track(1), mainTrackVolume
  99.  
  100. DIM comboSound(1 TO 8) AS LONG, a$
  101. RESTORE comboSoundFiles
  102. FOR i = 1 TO 8
  103.     READ a$
  104.     comboSound(i) = _SNDOPEN("assets/sounds/" + a$)
  105.  
  106. comboSoundFiles:
  107. DATA DO.ogg,re.ogg,mi.ogg,fa.ogg,sol.ogg,la.ogg,si.ogg,do2.ogg
  108.  
  109. 'if loading sounds took more than 2 seconds, no need to pause
  110. j = TIMER - j
  111. IF j < 2 THEN pause 2 - j
  112.  
  113. DIM thisColor AS INTEGER
  114. doIntro
  115.  
  116.  
  117. 'add divs to bg
  118. bgWithoutShelf = _COPYIMAGE(bg)
  119. LINE (_WIDTH / 2 - (_WIDTH / spacing) * 2, _HEIGHT / 2 - (_HEIGHT / spacing) * 2)-STEP(_WIDTH / spacing * 4, _HEIGHT / spacing * 4), _RGB32(0, 50), BF
  120. LINE (3 + peg(10).x - (_WIDTH / spacing / 2), 3 + peg(10).y - (_WIDTH / spacing / 2))-(3 + peg(12).x + (_WIDTH / spacing / 2), 3 + peg(12).y + (_WIDTH / spacing / 2)), _RGB32(255, 15), BF
  121. LINE (peg(10).x - (_WIDTH / spacing / 2), peg(10).y - (_WIDTH / spacing / 2))-(peg(12).x + (_WIDTH / spacing / 2), peg(12).y + (_WIDTH / spacing / 2)), _RGB32(255, 15), BF
  122.  
  123. 'game
  124. DIM score AS _UNSIGNED LONG, visibleScore AS _UNSIGNED LONG
  125. DIM highscore AS _UNSIGNED LONG, visibleHighScore AS _UNSIGNED LONG
  126. DIM level AS _UNSIGNED LONG, maxColors AS INTEGER
  127. DIM animation(0 TO 8) AS object, gameOver AS _BYTE
  128. DIM particle(5000) AS object, pauseGame AS _BYTE
  129.  
  130. animation(0).duration = .25 'board flash
  131. FOR i = 1 TO 5
  132.     animation(i).duration = .5 'matches
  133. animation(6).duration = 1 'new set spawn
  134. animation(7).duration = 1 'combo info
  135.  
  136. DIM multiplier AS INTEGER
  137. multiplier = 1
  138.  
  139. visibleScore = score
  140. visibleHighScore = highscore
  141.  
  142. DIM button(100) AS object
  143. DIM caption(100) AS STRING
  144. DIM totalButtons AS INTEGER
  145. DIM currentButton AS INTEGER
  146.  
  147.     DO 'main game loop
  148.         'read mouse data
  149.         WHILE _MOUSEINPUT: WEND
  150.  
  151.         'read keyboard
  152.         DIM keyb AS LONG
  153.         keyb = _KEYHIT
  154.  
  155.         IF mainTrackVolume > .5 AND music THEN
  156.             mainTrackVolume = mainTrackVolume - .05
  157.             IF track(1) > 0 THEN _SNDVOL track(1), mainTrackVolume
  158.         END IF
  159.         'redraw board
  160.         _DONTBLEND
  161.         _PUTIMAGE (0, 0), bg
  162.         _BLEND
  163.  
  164.         'print osd
  165.         DIM enterSettings AS _BYTE
  166.         createMainScreenButtons
  167.         IF ABS(keyb) <> 27 AND pauseGame = false AND enterSettings = false THEN doButtons
  168.  
  169.         _PUTIMAGE (25, 28), crownIcon
  170.         COLOR _RGB32(200)
  171.         _PRINTSTRING (52, 28), STR$(visibleHighScore)
  172.  
  173.         COLOR _RGB32(255)
  174.         printLarge 0, 45, STR$(visibleScore), 6
  175.  
  176.         IF multiplier > 1 THEN
  177.             _PRINTSTRING (52, 132), "x" + LTRIM$(STR$(multiplier))
  178.         END IF
  179.  
  180.         drawPegs
  181.         generateNewSets
  182.  
  183.         IF ABS(keyb) <> 27 AND pauseGame = false AND enterSettings = false THEN checkButtons
  184.  
  185.         DIM prevbt AS INTEGER
  186.         IF currentButton <> prevbt THEN
  187.             IF currentButton > 0 AND sfx AND selectSound > 0 THEN _SNDPLAYCOPY selectSound
  188.             prevbt = currentButton
  189.         END IF
  190.  
  191.         IF _MOUSEBUTTON(1) THEN
  192.             'drag?
  193.             DIM dragging AS INTEGER
  194.             DIM mouseDown AS _BYTE
  195.             IF NOT mouseDown THEN
  196.                 'are we beginning to drag a ring or set of rings?
  197.                 dragging = 0
  198.                 FOR i = 10 TO 12
  199.                     IF dist(peg(i).x, peg(i).y, _MOUSEX, _MOUSEY) <= 40 AND peg(i).set <> emptySet$ THEN
  200.                         dragging = i
  201.                         EXIT FOR
  202.                     END IF
  203.                 NEXT
  204.  
  205.                 mouseDown = true
  206.             END IF
  207.         ELSE
  208.             IF mouseDown THEN
  209.                 IF dragging = 0 THEN
  210.                     IF enterSettings = false AND currentButton = 1 THEN
  211.                         enterSettings = true
  212.                         _CONTINUE
  213.                     END IF
  214.  
  215.                     IF pauseGame = false AND currentButton = 2 THEN 'pause
  216.                         pauseGame = true
  217.                         _CONTINUE
  218.                     END IF
  219.                 END IF
  220.  
  221.                 'place rings
  222.                 DIM placed AS _BYTE
  223.                 placed = false
  224.  
  225.                 IF dragging THEN
  226.                     FOR i = 1 TO 9
  227.                         IF dist(peg(i).x, peg(i).y, _MOUSEX, _MOUSEY) <= 40 THEN
  228.                             'check that the chosen peg can hold the current set of rings
  229.                             placed = true
  230.                             FOR j = 1 TO 3
  231.                                 IF CVI(MID$(peg(dragging).set, j * 2 - 1, 2)) > 0 AND CVI(MID$(peg(i).set, j * 2 - 1, 2)) > 0 THEN
  232.                                     placed = false
  233.                                     EXIT FOR
  234.                                 END IF
  235.                             NEXT
  236.                             IF placed THEN
  237.                                 IF woodblock > 0 AND sfx THEN _SNDPLAYCOPY woodblock
  238.                                 FOR j = 1 TO 3
  239.                                     IF CVI(MID$(peg(dragging).set, j * 2 - 1, 2)) > 0 THEN
  240.                                         MID$(peg(i).set, j * 2 - 1, 2) = MID$(peg(dragging).set, j * 2 - 1, 2)
  241.                                     END IF
  242.                                 NEXT
  243.                                 peg(dragging).set = emptySet$
  244.                                 EXIT FOR
  245.                             ELSE
  246.                                 EXIT FOR
  247.                             END IF
  248.                         END IF
  249.                     NEXT
  250.                 END IF
  251.  
  252.                 FOR j = 1 TO 9
  253.                     'prepare backup copies for deletion tagging
  254.                     del(j) = peg(j)
  255.                 NEXT
  256.  
  257.                 'check matches
  258.                 DIM r(1 TO 3) AS INTEGER, previousScore AS _UNSIGNED LONG
  259.                 DIM s$, found1 AS INTEGER, found2 AS INTEGER, scored AS _BYTE
  260.                 DIM totalMatches AS INTEGER
  261.                 totalMatches = 0
  262.                 previousScore = score
  263.                 IF placed THEN
  264.                     'look for 3 same-color rings on peg(i) --> ((o))
  265.                     FOR j = 1 TO 3
  266.                         r(j) = CVI(MID$(peg(i).set, j * 2 - 1, 2))
  267.                     NEXT
  268.                     IF r(1) = r(2) AND r(2) = r(3) THEN
  269.                         score = score + 3 * multiplier
  270.                         animation(0).start = TIMER
  271.                         animation(5).start = TIMER
  272.                         animation(5).x = peg(i).x
  273.                         animation(5).y = peg(i).y
  274.                         animation(5).r = _RED32(c(r(1)))
  275.                         animation(5).g = _GREEN32(c(r(1)))
  276.                         animation(5).b = _BLUE32(c(r(1)))
  277.                         animation(8).r = _RED32(c(r(1)))
  278.                         animation(8).g = _GREEN32(c(r(1)))
  279.                         animation(8).b = _BLUE32(c(r(1)))
  280.                         del(i).set = emptySet$
  281.                         addParticles peg(i).x, peg(i).y, 70, c(r(1))
  282.                         addParticles peg(i).x, peg(i).y, 30, _RGB32(_RED32(c(r(1))) + 30, _GREEN32(c(r(1))) + 30, _BLUE32(c(r(1))) + 30)
  283.                         totalMatches = totalMatches + 1
  284.                     END IF
  285.  
  286.                     'look for line matches |, -, /, \
  287.                     DIM m AS INTEGER, checks AS INTEGER
  288.                     DIM nextPeg(0 TO 2) AS INTEGER
  289.                     FOR m = 1 TO 4
  290.                         SELECT CASE m
  291.                             CASE 1 'across
  292.                                 checks = 3
  293.                                 r(1) = 1
  294.                                 r(2) = 4
  295.                                 r(3) = 7
  296.                                 nextPeg(1) = 1
  297.                                 nextPeg(2) = 2
  298.                             CASE 2 'down
  299.                                 checks = 3
  300.                                 r(1) = 1
  301.                                 r(2) = 2
  302.                                 r(3) = 3
  303.                                 nextPeg(1) = 3
  304.                                 nextPeg(2) = 6
  305.                             CASE 3 'diagonal \
  306.                                 checks = 1
  307.                                 r(1) = 1
  308.                                 nextPeg(1) = 4
  309.                                 nextPeg(2) = 8
  310.                             CASE 4 'diagonal /
  311.                                 checks = 1
  312.                                 r(1) = 3
  313.                                 nextPeg(1) = 2
  314.                                 nextPeg(2) = 4
  315.                         END SELECT
  316.  
  317.                         FOR i = 1 TO checks
  318.                             'look at each ring on the first peg of each row
  319.                             FOR j = 1 TO 3
  320.                                 scored = false
  321.                                 s$ = MID$(peg(r(i)).set, j * 2 - 1, 2)
  322.                                 IF s$ = MKI$(-1) THEN _CONTINUE
  323.                                 found1 = INSTR(peg(r(i) + nextPeg(1)).set, s$)
  324.                                 found2 = INSTR(peg(r(i) + nextPeg(2)).set, s$)
  325.                                 IF found1 > 0 AND found2 > 0 THEN
  326.                                     'match! clear all rings of the same color in this group of pegs
  327.                                     FOR k = 0 TO 2
  328.                                         found1 = INSTR(del(r(i) + nextPeg(k)).set, s$)
  329.                                         DO WHILE found1
  330.                                             MID$(del(r(i) + nextPeg(k)).set, found1, 2) = MKI$(-1)
  331.                                             addParticles del(r(i) + nextPeg(k)).x, del(r(i) + nextPeg(k)).y, 23, c(CVI(s$))
  332.                                             addParticles del(r(i) + nextPeg(k)).x, del(r(i) + nextPeg(k)).y, 10, _RGB32(_RED32(c(CVI(s$))) + 30, _GREEN32(c(CVI(s$))) + 30, _BLUE32(c(CVI(s$))) + 30)
  333.                                             score = score + multiplier
  334.                                             found1 = INSTR(del(r(i) + nextPeg(k)).set, s$)
  335.                                         LOOP
  336.                                     NEXT
  337.                                     scored = true
  338.                                     totalMatches = totalMatches + 1
  339.                                     animation(0).start = TIMER
  340.                                     animation(m).start = TIMER
  341.                                     animation(m).x = peg(r(i)).x
  342.                                     animation(m).y = peg(r(i)).y
  343.                                     animation(m).r = _RED32(c(CVI(s$)))
  344.                                     animation(m).g = _GREEN32(c(CVI(s$)))
  345.                                     animation(m).b = _BLUE32(c(CVI(s$)))
  346.                                     animation(8).r = _RED32(c(CVI(s$)))
  347.                                     animation(8).g = _GREEN32(c(CVI(s$)))
  348.                                     animation(8).b = _BLUE32(c(CVI(s$)))
  349.                                 END IF
  350.  
  351.                                 IF scored THEN MID$(del(r(i)).set, j * 2 - 1, 2) = MKI$(-1)
  352.                             NEXT
  353.                         NEXT
  354.                     NEXT
  355.  
  356.                     FOR j = 1 TO 9
  357.                         'perform deletion, if any items were marked = MKI$(-1)
  358.                         peg(j) = del(j)
  359.                     NEXT
  360.  
  361.                     IF previousScore < score THEN
  362.                         IF wooshSound > 0 AND sfx THEN _SNDPLAYCOPY wooshSound
  363.  
  364.                         multiplier = multiplier + 1
  365.  
  366.                         IF sfx THEN
  367.                             IF multiplier - 1 <= UBOUND(combosound) THEN
  368.                                 IF comboSound(multiplier - 1) > 0 THEN
  369.                                     _SNDPLAYCOPY comboSound(multiplier - 1)
  370.                                 END IF
  371.                             ELSE
  372.                                 IF comboSound(UBOUND(combosound)) > 0 THEN
  373.                                     _SNDPLAYCOPY comboSound(UBOUND(combosound))
  374.                                 END IF
  375.                             END IF
  376.                         END IF
  377.  
  378.                         DIM m$(1 TO 2)
  379.                         m$(1) = megaComboMsg$(_CEIL(RND * UBOUND(megaComboMsg$)))
  380.                         m$(2) = LTRIM$(STR$(multiplier)) + "x combo!"
  381.                         animation(7).start = TIMER
  382.                         animation(8).start = TIMER
  383.                         animation(8).x = _MOUSEX
  384.                         animation(8).y = _MOUSEY
  385.                         animation(8).xa = score - previousScore
  386.                         animation(8).ya = dist(_MOUSEX, _MOUSEY, printWidthLarge(STR$(visibleScore), 6) / 2, 45)
  387.                         animation(8).duration = 5
  388.                     ELSE
  389.                         multiplier = 1
  390.                     END IF
  391.                     IF score > highscore THEN highscore = score
  392.                 END IF
  393.             END IF
  394.             mouseDown = false
  395.             dragging = 0
  396.         END IF
  397.  
  398.         hoverHighlight
  399.         checkAvailableMoves
  400.         drawRings
  401.         doAnimations
  402.         updateScore
  403.         updateParticles
  404.  
  405.         'update display
  406.         _DISPLAY
  407.  
  408.         IF enterSettings THEN
  409.             addParticles _MOUSEX, _MOUSEY, 30, _RGB32(255)
  410.             addParticles _MOUSEX, _MOUSEY, 30, _RGB32(67, 172, 183)
  411.             settingsScreen
  412.             enterSettings = false
  413.         END IF
  414.  
  415.         IF pauseGame THEN
  416.             addParticles _MOUSEX, _MOUSEY, 30, _RGB32(255)
  417.             addParticles _MOUSEX, _MOUSEY, 30, _RGB32(67, 172, 183)
  418.             keyb = -27
  419.             pauseGame = false
  420.         END IF
  421.  
  422.         'limit fps
  423.         _LIMIT 60
  424.  
  425.         DIM userQuit AS _BYTE
  426.         userQuit = _EXIT
  427.         IF keyb = -27 THEN EXIT DO
  428.     LOOP UNTIL gameOver OR userQuit
  429.  
  430.     saveGame
  431.  
  432.     IF userQuit THEN SYSTEM
  433.  
  434.     endScreen
  435.  
  436.  
  437. SUB setPegs
  438.     SHARED spacing AS INTEGER
  439.     SHARED peg() AS object
  440.     SHARED emptySet$
  441.  
  442.     DIM l AS SINGLE, i AS INTEGER, j AS SINGLE, k AS SINGLE
  443.     spacing = 6
  444.     l = -(_HEIGHT / spacing)
  445.     FOR i = 1 TO 12
  446.         j = j + 1
  447.         IF j > 3 THEN j = 1: l = l + (_HEIGHT / spacing)
  448.         SELECT CASE j
  449.             CASE 1: k = -_WIDTH / spacing
  450.             CASE 2: k = 0
  451.             CASE 3: k = _WIDTH / spacing
  452.         END SELECT
  453.         peg(i).x = _WIDTH / 2 + k
  454.         peg(i).y = _HEIGHT / 2 + l
  455.         peg(i).set = emptySet$
  456.     NEXT
  457.  
  458. SUB setComboMessages
  459.     SHARED megaComboMsg$()
  460.     DIM i AS INTEGER
  461.  
  462.     RESTORE megaComboMsgs
  463.     FOR i = 1 TO UBOUND(megaComboMsg$)
  464.         READ megaComboMsg$(i)
  465.     NEXT
  466.     megaComboMsgs:
  467.     DATA Fantastic,Outstanding,Amazing,Awesome,MEGA,SUPER
  468.  
  469. SUB setRingColors
  470.     SHARED i AS INTEGER
  471.  
  472.     i = i + 1: c(i) = _RGB32(0, 78, 249) 'blue
  473.     i = i + 1: c(i) = _RGB32(0, 100, 0) 'green
  474.     i = i + 1: c(i) = _RGB32(222, 61, 44) 'red
  475.     i = i + 1: c(i) = _RGB32(216, 216, 44) 'yellow
  476.     i = i + 1: c(i) = _RGB32(233, 139, 17) 'orange
  477.     i = i + 1: c(i) = _RGB32(222, 105, 161) 'pink
  478.     i = i + 1: c(i) = _RGB32(139, 11, 205) 'purple
  479.     i = i + 1: c(i) = _RGB32(55, 211, 211) 'cyan
  480.     i = i + 1: c(i) = _RGB32(255, 255, 255) 'white
  481.     i = i + 1: c(i) = _RGB32(100, 100, 100) 'dark gray
  482.  
  483. SUB generateRingImages
  484.     DIM j AS INTEGER, k AS INTEGER
  485.     SHARED circleImage() AS LONG
  486.  
  487.     FOR j = 1 TO UBOUND(c)
  488.         FOR k = 1 TO 3
  489.             circleImage(j, k) = _NEWIMAGE(k * 29, k * 29, 32)
  490.             _DEST circleImage(j, k)
  491.             PAINT (0, 0), _RGB32(255, 0, 255)
  492.             CircleFill _WIDTH / 2, _HEIGHT / 2, k * 14, c(j)
  493.             CircleFill _WIDTH / 2, _HEIGHT / 2, k * (8 + k), _RGB32(255, 0, 255)
  494.             _CLEARCOLOR _RGB32(255, 0, 255)
  495.         NEXT
  496.     NEXT
  497.  
  498. SUB generateCrownIcon
  499.     SHARED crownIcon AS LONG
  500.     DIM i AS INTEGER, j AS INTEGER
  501.     DIM px AS INTEGER
  502.  
  503.     RESTORE crownIconData
  504.     crownIcon = _NEWIMAGE(24, 14, 32)
  505.     _DEST crownIcon
  506.     FOR i = 0 TO 13
  507.         FOR j = 0 TO 23
  508.             READ px
  509.             SELECT CASE px
  510.                 CASE 1
  511.                     PSET (j, i), _RGB32(0)
  512.                 CASE 2
  513.                     PSET (j, i), _RGB32(205, 161, 0)
  514.             END SELECT
  515.         NEXT
  516.     NEXT
  517.  
  518.     crownIconData:
  519.     DATA 0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0
  520.     DATA 0,0,0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0
  521.     DATA 0,0,0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0
  522.     DATA 0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0
  523.     DATA 1,2,2,1,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,1,2,2,1
  524.     DATA 1,2,2,1,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,1,2,2,1
  525.     DATA 0,1,1,2,1,1,0,0,0,1,2,2,2,2,1,0,0,0,1,1,2,1,1,0
  526.     DATA 0,0,1,2,2,2,1,1,0,1,2,2,2,2,1,0,1,1,2,2,2,1,0,0
  527.     DATA 0,0,1,2,2,2,2,2,1,2,2,2,2,2,2,1,2,2,2,2,2,1,0,0
  528.     DATA 0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0
  529.     DATA 0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0
  530.     DATA 0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0
  531.     DATA 0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0
  532.     DATA 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
  533.  
  534. SUB generateBG
  535.     SHARED bg AS LONG
  536.     DIM i AS SINGLE
  537.  
  538.     bg = _NEWIMAGE(_WIDTH, _HEIGHT, 32)
  539.     _DEST bg
  540.     FOR i = 0 TO _HEIGHT - 1 STEP _HEIGHT / 60
  541.         LINE (0, 0)-(_WIDTH - 1, i), _RGB32(139, 116, 177, 5), BF
  542.     NEXT
  543.  
  544. SUB doIntro
  545.     SHARED thisColor AS INTEGER
  546.     SHARED circleImage() AS LONG
  547.     SHARED track() AS LONG
  548.     SHARED bg AS LONG
  549.     SHARED music AS _BYTE
  550.  
  551.     DIM x AS SINGLE, y AS SINGLE, j AS INTEGER
  552.     DIM introRings(1 TO 30) AS object
  553.     DIM i AS INTEGER
  554.  
  555.     FOR i = 1 TO UBOUND(introRings)
  556.         introRings(i).xa = RND * _PI(2)
  557.         introRings(i).xv = RND * 5
  558.         introRings(i).r = RND * 30 + 50
  559.         introRings(i).set = MKI$(-1) + MKI$(-1) + MKI$(_CEIL(RND * UBOUND(c)))
  560.     NEXT
  561.  
  562.     addParticles _WIDTH / 2, _HEIGHT / 2, 5000, _RGB32(255)
  563.  
  564.     DIM introTimer AS SINGLE
  565.     introTimer = TIMER
  566.     IF track(1) > 0 AND music THEN _SNDLOOP track(1)
  567.     DO
  568.         _DONTBLEND
  569.         _PUTIMAGE (0, 0), bg
  570.         _BLEND
  571.  
  572.         FOR i = 1 TO UBOUND(introRings)
  573.             introRings(i).xa = introRings(i).xa + .01
  574.             introRings(i).r = introRings(i).r + introRings(i).xv
  575.             x = _WIDTH / 2 + COS(introRings(i).xa) * introRings(i).r
  576.             y = _HEIGHT / 2 + SIN(introRings(i).xa) * introRings(i).r
  577.  
  578.             FOR j = 1 TO 3
  579.                 thisColor = CVI(MID$(introRings(i).set, j * 2 - 1, 2))
  580.                 IF thisColor > 0 THEN
  581.                     _PUTIMAGE (x - (_WIDTH(circleImage(thisColor, j)) / 2), y - (_HEIGHT(circleImage(thisColor, j)) / 2)), circleImage(thisColor, j)
  582.                 END IF
  583.             NEXT
  584.         NEXT
  585.  
  586.         updateParticles
  587.  
  588.         LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGB32(255, map(TIMER - introTimer, 4, 6, 0, 255)), BF
  589.  
  590.         COLOR _RGB32(0)
  591.         centerLarge (_HEIGHT / 2) - fontHeightLarge(2) + 3, "Tic Tac Toe", 2
  592.         centerLarge (_HEIGHT / 2) + 3, "Rings", 7
  593.         centerLarge _HEIGHT - fontHeightLarge(2) + 3, "Fellippe Heitor, 2020", 1
  594.  
  595.         COLOR _RGB32(255)
  596.         centerLarge (_HEIGHT / 2) - fontHeightLarge(2), "Tic Tac Toe", 2
  597.         centerLarge (_HEIGHT / 2), "Rings", 7
  598.         centerLarge _HEIGHT - fontHeightLarge(2), "Fellippe Heitor, 2020", 1
  599.  
  600.         LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGB32(255, map(TIMER - introTimer, 0, 1.5, 255, 0)), BF
  601.         LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGB32(255, map(TIMER - introTimer, 4, 5, 0, 255)), BF
  602.         LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGB32(0, map(TIMER - introTimer, 5, 6, 0, 255)), BF
  603.  
  604.         WHILE _MOUSEINPUT: WEND
  605.         _DISPLAY
  606.         _LIMIT 60
  607.     LOOP UNTIL TIMER - introTimer > 6 OR _KEYHIT OR _MOUSEBUTTON(1)
  608.  
  609.  
  610. SUB drawPegs
  611.     SHARED peg() AS object
  612.  
  613.     DIM i AS INTEGER
  614.     FOR i = 1 TO 9
  615.         CircleFill peg(i).x, peg(i).y, 3, _RGB32(255)
  616.     NEXT
  617.  
  618. SUB generateNewSets
  619.     SHARED peg() AS object
  620.     SHARED animation() AS object
  621.     SHARED emptySet$
  622.     SHARED level AS _UNSIGNED LONG, maxColors AS INTEGER
  623.  
  624.     DIM i AS INTEGER
  625.     DIM j AS INTEGER
  626.  
  627.     'new sets must be generated according to
  628.     'current board's available positions
  629.     IF peg(10).set + peg(11).set + peg(12).set = emptySet$ + emptySet$ + emptySet$ THEN
  630.         level = level + 1
  631.         maxColors = map(level, 1, 60, 3, UBOUND(c)) 'as level goes up, add more colors
  632.         IF maxColors < 3 THEN maxColors = 3
  633.         IF maxColors > UBOUND(c) THEN maxColors = UBOUND(c)
  634.  
  635.         DIM pegsUsed AS STRING, thisPeg AS INTEGER, newPeg AS INTEGER
  636.         pegsUsed = ""
  637.         FOR i = 10 TO 12
  638.             'reset this peg
  639.             peg(i).set = emptySet$
  640.  
  641.             'choose an existing peg randomly
  642.             newPeg = _CEIL(RND * 9)
  643.             thisPeg = newPeg
  644.             DO
  645.                 IF INSTR(peg(thisPeg).set, MKI$(-1)) > 0 AND INSTR(pegsUsed, MKI$(thisPeg)) = 0 THEN
  646.                     'found a peg with an empty slot or more
  647.                     EXIT DO
  648.                 END IF
  649.                 thisPeg = thisPeg + 1
  650.                 IF thisPeg > 9 THEN thisPeg = 1
  651.                 IF thisPeg = newPeg THEN
  652.                     'full circle
  653.                     thisPeg = 0
  654.                     EXIT DO
  655.                 END IF
  656.             LOOP
  657.  
  658.             'store the chosen peg's id
  659.             IF thisPeg > 0 THEN pegsUsed = pegsUsed + MKI$(thisPeg)
  660.  
  661.             'generate a set, with random colors
  662.             DO
  663.                 FOR j = 1 TO 3
  664.                     IF MID$(peg(thisPeg).set, j * 2 - 1, 2) = MKI$(-1) THEN
  665.                         IF RND * 100 < 30 THEN
  666.                             MID$(peg(i).set, j * 2 - 1, 2) = MKI$(_CEIL(RND * maxColors))
  667.                         END IF
  668.                     END IF
  669.                 NEXT
  670.             LOOP WHILE peg(i).set = emptySet$ 'can't be empty
  671.             IF INSTR(peg(i).set, MKI$(-1)) = 0 THEN 'can't be full
  672.                 j = _CEIL(RND * 3)
  673.                 MID$(peg(i).set, j * 2 - 1, 2) = MKI$(-1)
  674.             END IF
  675.         NEXT
  676.         animation(6).start = TIMER
  677.     END IF
  678.  
  679. SUB doAnimations
  680.     DIM i AS INTEGER, j AS SINGLE, k AS SINGLE, l AS SINGLE
  681.     SHARED animation() AS object
  682.     SHARED peg() AS object
  683.     SHARED totalMatches AS INTEGER
  684.     SHARED m$(), spacing AS INTEGER
  685.     SHARED visibleScore AS _UNSIGNED LONG
  686.  
  687.     FOR i = 0 TO UBOUND(animation)
  688.         IF TIMER - animation(i).start <= animation(i).duration THEN
  689.             DIM animSize AS SINGLE
  690.             animSize = map(TIMER - animation(i).start, 0, animation(i).duration, 50, 0)
  691.             SELECT CASE i
  692.                 CASE 0 'board flash
  693.                     LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGB32(255, map(TIMER - animation(i).start, 0, animation(i).duration, 100, 0)), BF
  694.                 CASE 1 'across
  695.                     FOR j = 0 TO _WIDTH STEP _WIDTH / 30
  696.                         FOR k = 1 TO animSize STEP 5
  697.                             CircleFill j, animation(i).y, k, _RGB32(animation(i).r, animation(i).g, animation(i).b, 20)
  698.                         NEXT
  699.                     NEXT
  700.                 CASE 2 'down
  701.                     FOR j = 0 TO _WIDTH STEP _WIDTH / 30
  702.                         FOR k = 1 TO animSize STEP 5
  703.                             CircleFill animation(i).x, j, k, _RGB32(animation(i).r, animation(i).g, animation(i).b, 20)
  704.                         NEXT
  705.                     NEXT
  706.                 CASE 3 'diagonal \
  707.                     FOR j = 0 TO _WIDTH STEP _WIDTH / 30
  708.                         FOR k = 1 TO animSize STEP 5
  709.                             CircleFill j, j, k, _RGB32(animation(i).r, animation(i).g, animation(i).b, 20)
  710.                         NEXT
  711.                     NEXT
  712.                 CASE 4 'diagonal /
  713.                     FOR j = 0 TO _WIDTH STEP _WIDTH / 30
  714.                         FOR k = 1 TO animSize STEP 5
  715.                             CircleFill j, _HEIGHT - j, k, _RGB32(animation(i).r, animation(i).g, animation(i).b, 20)
  716.                         NEXT
  717.                     NEXT
  718.                 CASE 5 'single peg ((o))
  719.                     FOR k = 1 TO animSize * 2
  720.                         CircleFill animation(i).x, animation(i).y, k, _RGB32(animation(i).r, animation(i).g, animation(i).b, 20)
  721.                     NEXT
  722.                 CASE 6 'new peg set
  723.                     FOR k = 10 TO 12
  724.                         CIRCLE (peg(k).x, peg(k).y), animSize * 1.5, _RGB32(255, animSize / 2)
  725.                         CIRCLE (peg(k).x, peg(k).y), animSize, _RGB32(255, animSize)
  726.                     NEXT
  727.                 CASE 7 'combo info
  728.                     k = INT(map(animSize, 50, 40, 1, 4))
  729.                     IF k < 1 THEN k = 1
  730.                     IF k > 4 THEN k = 4
  731.                     COLOR _RGB32(0, 80)
  732.                     FOR l = -4 TO 4 STEP 8
  733.                         IF totalMatches > 1 THEN
  734.                             printLarge (l + _WIDTH - printWidthLarge(m$(1), k)) / 2, (l + _HEIGHT - fontHeightLarge(k)) / 2 - fontHeightLarge(k), m$(1), k
  735.                         END IF
  736.                         printLarge (l + _WIDTH - printWidthLarge(m$(2), k)) / 2, (l + _HEIGHT - fontHeightLarge(k)) / 2, m$(2), k
  737.                     NEXT
  738.                     COLOR _RGB32(255)
  739.                     IF totalMatches > 1 THEN
  740.                         printLarge (_WIDTH - printWidthLarge(m$(1), k)) / 2, (_HEIGHT - fontHeightLarge(k)) / 2 - fontHeightLarge(k), m$(1), k
  741.                     END IF
  742.                     printLarge (_WIDTH - printWidthLarge(m$(2), k)) / 2, (_HEIGHT - fontHeightLarge(k)) / 2, m$(2), k
  743.                 CASE 8 'score increase
  744.                     DIM a AS SINGLE
  745.                     animation(8).x = lerp(animation(8).x, printWidthLarge(STR$(visibleScore), 6) / 2, .06)
  746.                     animation(8).y = lerp(animation(8).y, 45, .06)
  747.                     a = dist(animation(8).x, animation(8).y, printWidthLarge(STR$(visibleScore), 6) / 2, 45)
  748.                     IF a <= 30 THEN
  749.                         animation(8).start = 0
  750.                     END IF
  751.                     a = map(a, 0, animation(8).ya, 0, 1024)
  752.                     COLOR _RGB32(animation(8).r, animation(8).g, animation(8).b, a)
  753.                     printLarge 2 + animation(8).x, 2 + animation(8).y, LTRIM$(STR$(animation(8).xa)), 4
  754.                     COLOR _RGB32(255, a)
  755.                     printLarge animation(8).x, animation(8).y, LTRIM$(STR$(animation(8).xa)), 4
  756.             END SELECT
  757.         END IF
  758.     NEXT
  759.  
  760. SUB saveGame
  761.     SHARED score AS _UNSIGNED LONG, highscore AS _UNSIGNED LONG
  762.     SHARED level AS _UNSIGNED LONG
  763.     SHARED gameOver AS _BYTE
  764.     SHARED peg() AS object
  765.     SHARED music AS _BYTE, sfx AS _BYTE
  766.  
  767.     DIM i AS INTEGER
  768.  
  769.     OPEN "tictactoering.dat" FOR BINARY AS #1
  770.     DIM signature AS STRING
  771.     signature = "tttring"
  772.     PUT #1, 1, signature
  773.     PUT #1, , music
  774.     PUT #1, , sfx
  775.     PUT #1, , score
  776.     PUT #1, , highscore
  777.     PUT #1, , level
  778.     PUT #1, , gameOver
  779.     FOR i = 1 TO 12
  780.         PUT #1, , peg(i)
  781.     NEXT
  782.     CLOSE #1
  783.  
  784. SUB loadGame
  785.     SHARED score AS _UNSIGNED LONG, highscore AS _UNSIGNED LONG
  786.     SHARED level AS _UNSIGNED LONG
  787.     SHARED gameOver AS _BYTE
  788.     SHARED peg() AS object
  789.     SHARED music AS _BYTE, sfx AS _BYTE
  790.  
  791.     DIM i AS INTEGER
  792.  
  793.     OPEN "tictactoering.dat" FOR BINARY AS #1
  794.     IF LOF(1) THEN
  795.         DIM signature AS STRING
  796.         signature = SPACE$(7)
  797.         GET #1, 1, signature
  798.         IF signature <> "tttring" THEN
  799.             CLOSE #1
  800.             EXIT SUB
  801.         END IF
  802.         GET #1, , music
  803.         GET #1, , sfx
  804.         GET #1, , score
  805.         GET #1, , highscore
  806.         GET #1, , level
  807.         GET #1, , gameOver
  808.  
  809.         IF gameOver = false THEN
  810.             FOR i = 1 TO 12
  811.                 GET #1, , peg(i)
  812.             NEXT
  813.         ELSE
  814.             gameOver = false
  815.             score = 0
  816.             level = 0
  817.         END IF
  818.     ELSE
  819.         'user just upgraded from first versions?
  820.         'retrieve their highscore and kill old file
  821.         CLOSE #1
  822.         IF _FILEEXISTS("tictactoering.score") THEN
  823.             OPEN "tictactoering.score" FOR BINARY AS #1
  824.             IF LOF(1) THEN
  825.                 GET #1, 1, score
  826.                 GET #1, , highscore
  827.                 GET #1, , level
  828.                 GET #1, , gameOver
  829.  
  830.                 IF gameOver = false THEN
  831.                     FOR i = 1 TO 12
  832.                         GET #1, , peg(i)
  833.                     NEXT
  834.                 ELSE
  835.                     gameOver = false
  836.                     score = 0
  837.                     level = 0
  838.                 END IF
  839.             END IF
  840.             CLOSE #1
  841.             KILL "tictactoering.score"
  842.         END IF
  843.     END IF
  844.     CLOSE #1
  845.  
  846. SUB addParticles (x AS SINGLE, y AS SINGLE, total AS INTEGER, c AS _UNSIGNED LONG)
  847.     DIM addedP AS INTEGER, p AS INTEGER
  848.     DIM a AS SINGLE
  849.     SHARED particle() AS object
  850.  
  851.     addedP = 0: p = 0
  852.     DO
  853.         p = p + 1
  854.         IF p > UBOUND(particle) THEN EXIT DO
  855.         IF particle(p).state = true THEN _CONTINUE
  856.         addedP = addedP + 1
  857.         particle(p).state = true
  858.         particle(p).x = x
  859.         particle(p).y = y
  860.         a = RND * _PI(2)
  861.         particle(p).xv = COS(a) * (RND * 10)
  862.         particle(p).yv = SIN(a) * (RND * 10)
  863.         particle(p).r = _RED32(c)
  864.         particle(p).g = _GREEN32(c)
  865.         particle(p).b = _BLUE32(c)
  866.         particle(p).size = _CEIL(RND * 3)
  867.         particle(p).start = TIMER
  868.         particle(p).duration = RND
  869.     LOOP UNTIL addedP >= total
  870.  
  871. SUB updateScore
  872.     STATIC lastScoreUpdate AS SINGLE, lastHighScoreUpdate AS SINGLE
  873.     SHARED visibleScore AS _UNSIGNED LONG, score AS _UNSIGNED LONG
  874.     SHARED visibleHighScore AS _UNSIGNED LONG, highscore AS _UNSIGNED LONG
  875.     SHARED animation() AS object, woodblock AS LONG
  876.     SHARED sfx AS _BYTE
  877.  
  878.     IF visibleScore < score AND TIMER - lastScoreUpdate > .05 AND animation(8).start = 0 THEN
  879.         visibleScore = visibleScore + 1
  880.         IF woodblock > 0 AND sfx THEN _SNDPLAYCOPY woodblock
  881.         lastScoreUpdate = TIMER
  882.     END IF
  883.  
  884.     IF visibleHighScore < highscore AND TIMER - lastHighScoreUpdate > .05 AND animation(8).start = 0 THEN
  885.         visibleHighScore = visibleHighScore + 1
  886.         lastHighScoreUpdate = TIMER
  887.     END IF
  888.  
  889. SUB updateParticles
  890.     DIM i AS INTEGER
  891.     SHARED particle() AS object
  892.  
  893.     FOR i = 1 TO UBOUND(particle)
  894.         CONST gravity = .1
  895.         IF particle(i).state THEN
  896.             particle(i).xv = particle(i).xv + particle(i).xa
  897.             particle(i).x = particle(i).x + particle(i).xv
  898.             particle(i).yv = particle(i).yv + particle(i).ya + gravity
  899.             particle(i).y = particle(i).y + particle(i).yv
  900.  
  901.             IF particle(i).x > _WIDTH OR particle(i).x < 0 OR particle(i).y > _HEIGHT OR particle(i).y < 0 THEN
  902.                 particle(i).state = false
  903.             ELSE
  904.                 CircleFill particle(i).x, particle(i).y, particle(i).size, _RGB32(particle(i).r, particle(i).g, particle(i).b, map(TIMER - particle(i).start, 0, particle(i).duration, 255, 0))
  905.             END IF
  906.         END IF
  907.     NEXT
  908.  
  909. SUB hoverHighlight
  910.     SHARED peg() AS object
  911.     SHARED emptySet$
  912.     SHARED dragging AS INTEGER
  913.  
  914.     STATIC highLit AS INTEGER, glow AS SINGLE, glowStep AS SINGLE
  915.     DIM halo AS INTEGER
  916.     DIM i AS INTEGER, k AS SINGLE, j AS SINGLE
  917.  
  918.     IF dragging THEN EXIT SUB
  919.  
  920.     FOR i = 10 TO 12
  921.         IF peg(i).set = emptySet$ THEN _CONTINUE
  922.         IF dist(peg(i).x, peg(i).y, _MOUSEX, _MOUSEY) <= 40 THEN
  923.             k = 0
  924.             IF MID$(peg(i).set, 5, 2) <> MKI$(-1) THEN
  925.                 halo = 40
  926.             ELSEIF MID$(peg(i).set, 3, 2) <> MKI$(-1) THEN
  927.                 halo = 25
  928.             ELSE
  929.                 halo = 12
  930.             END IF
  931.  
  932.             IF highLit <> i THEN
  933.                 highLit = i
  934.                 glow = 10
  935.                 glowStep = .2
  936.             END IF
  937.  
  938.             IF glowStep = 0 THEN glowStep = .2
  939.             glow = glow + glowStep
  940.             IF glow < 8 THEN glow = 8: glowStep = glowStep * -1
  941.             IF glow > 16 THEN glow = 16: glowStep = glowStep * -1
  942.  
  943.             FOR j = glow TO 8 STEP -.5
  944.                 k = k + .8
  945.                 CircleFill peg(i).x, peg(i).y, halo + k, _RGB32(255, j)
  946.                 CircleFill peg(i).x, peg(i).y, (halo / 2) + k, _RGB32(0, j)
  947.             NEXT
  948.  
  949.             EXIT FOR
  950.         END IF
  951.     NEXT
  952.  
  953. SUB checkAvailableMoves
  954.     SHARED dragging AS INTEGER
  955.     SHARED peg() AS object
  956.     SHARED emptySet$
  957.     SHARED gameOver AS _BYTE
  958.     SHARED placed AS _BYTE
  959.  
  960.     DIM i AS INTEGER, j AS INTEGER, k AS INTEGER
  961.  
  962.     IF dragging = 0 THEN
  963.         IF peg(10).set <> emptySet$ OR peg(11).set <> emptySet$ OR peg(12).set <> emptySet$ THEN
  964.             gameOver = true 'glass is half empty; consider no more moves
  965.             FOR i = 10 TO 12
  966.                 IF peg(i).set <> emptySet$ THEN
  967.                     'can this set fit the board?
  968.                     FOR j = 1 TO 9
  969.                         placed = true
  970.                         FOR k = 1 TO 3
  971.                             IF CVI(MID$(peg(i).set, k * 2 - 1, 2)) > 0 AND CVI(MID$(peg(j).set, k * 2 - 1, 2)) > 0 THEN
  972.                                 placed = false
  973.                                 EXIT FOR
  974.                             END IF
  975.                         NEXT
  976.                         IF placed THEN gameOver = false: EXIT FOR
  977.                     NEXT
  978.                 END IF
  979.                 IF gameOver = false THEN EXIT FOR 'no need to test further, there's still hope
  980.             NEXT
  981.         END IF
  982.  
  983.         IF gameOver = false THEN
  984.             'is board full?
  985.             'that means we used all sets and no matches were found = game over
  986.             DIM board$
  987.             board$ = ""
  988.             FOR i = 1 TO 9
  989.                 board$ = board$ + peg(i).set
  990.             NEXT
  991.             IF INSTR(board$, MKI$(-1)) = 0 THEN gameOver = true
  992.         END IF
  993.     END IF
  994.  
  995. SUB drawRings
  996.     DIM i AS INTEGER
  997.     SHARED peg() AS object
  998.     SHARED circleImage() AS LONG
  999.     SHARED dragging AS INTEGER
  1000.     SHARED thisColor AS INTEGER
  1001.  
  1002.     DIM x AS SINGLE, y AS SINGLE
  1003.     DIM j AS INTEGER
  1004.  
  1005.     FOR i = 1 TO 12
  1006.         IF i = dragging THEN
  1007.             x = _MOUSEX
  1008.             y = _MOUSEY
  1009.         ELSE
  1010.             x = peg(i).x
  1011.             y = peg(i).y
  1012.         END IF
  1013.  
  1014.         FOR j = 1 TO 3
  1015.             thisColor = CVI(MID$(peg(i).set, j * 2 - 1, 2))
  1016.             IF thisColor > 0 THEN
  1017.                 _PUTIMAGE (x - (_WIDTH(circleImage(thisColor, j)) / 2), y - (_HEIGHT(circleImage(thisColor, j)) / 2)), circleImage(thisColor, j)
  1018.             END IF
  1019.         NEXT
  1020.     NEXT
  1021.  
  1022. SUB CircleFill (x AS LONG, y AS LONG, R AS LONG, C AS _UNSIGNED LONG)
  1023.     DIM x0 AS SINGLE, y0 AS SINGLE
  1024.     DIM e AS SINGLE
  1025.  
  1026.     x0 = R
  1027.     y0 = 0
  1028.     e = -R
  1029.     DO WHILE y0 < x0
  1030.         IF e <= 0 THEN
  1031.             y0 = y0 + 1
  1032.             LINE (x - x0, y + y0)-(x + x0, y + y0), C, BF
  1033.             LINE (x - x0, y - y0)-(x + x0, y - y0), C, BF
  1034.             e = e + 2 * y0
  1035.         ELSE
  1036.             LINE (x - y0, y - x0)-(x + y0, y - x0), C, BF
  1037.             LINE (x - y0, y + x0)-(x + y0, y + x0), C, BF
  1038.             x0 = x0 - 1
  1039.             e = e - 2 * x0
  1040.         END IF
  1041.     LOOP
  1042.     LINE (x - R, y)-(x + R, y), C, BF
  1043.  
  1044. FUNCTION map! (value!, minRange!, maxRange!, newMinRange!, newMaxRange!)
  1045.     map! = ((value! - minRange!) / (maxRange! - minRange!)) * (newMaxRange! - newMinRange!) + newMinRange!
  1046.  
  1047. FUNCTION lerp! (start!, stp!, amt!)
  1048.     DIM mult AS INTEGER
  1049.     IF start! < stp! THEN mult = -1 ELSE mult = 1
  1050.     lerp! = (mult * amt!) * (stp! - start!) + start!
  1051.  
  1052. FUNCTION dist! (x1!, y1!, x2!, y2!)
  1053.     dist! = _HYPOT((x2! - x1!), (y2! - y1!))
  1054.  
  1055. SUB printLarge (x AS SINGLE, y AS SINGLE, text$, fontSize AS INTEGER)
  1056.     DIM i AS LONG, j AS LONG, c AS LONG, char AS _UNSIGNED _BYTE
  1057.  
  1058.     IF fontSize = 0 THEN fontSize = 1
  1059.  
  1060.     FOR c = 1 TO LEN(text$)
  1061.         char = ASC(text$, c)
  1062.         FOR i = 1 TO 16
  1063.             FOR j = 1 TO 8
  1064.                 IF charSet(char, i, j) THEN
  1065.                     IF _PRINTMODE <> 2 THEN
  1066.                         LINE ((x - fontSize) + j * fontSize + ((c - 1) * (fontSize * 8)), (y - fontSize) + i * fontSize)-STEP(fontSize - 1, fontSize - 1), _DEFAULTCOLOR, BF
  1067.                     END IF
  1068.                 ELSE
  1069.                     IF _PRINTMODE = 3 OR _PRINTMODE = 2 THEN
  1070.                         LINE ((x - fontSize) + j * fontSize + ((c - 1) * (fontSize * 8)), (y - fontSize) + i * fontSize)-STEP(fontSize - 1, fontSize - 1), _BACKGROUNDCOLOR, BF
  1071.                     END IF
  1072.                 END IF
  1073.             NEXT
  1074.         NEXT
  1075.     NEXT
  1076.  
  1077. SUB centerLarge (y AS SINGLE, text$, fontSize AS INTEGER)
  1078.     printLarge (_WIDTH - printWidthLarge(text$, fontSize)) / 2, y, text$, fontSize
  1079.  
  1080. FUNCTION fontHeightLarge (fontSize AS INTEGER)
  1081.     fontHeightLarge = fontSize * 16
  1082.  
  1083. FUNCTION fontWidthLarge (fontSize AS INTEGER)
  1084.     fontWidthLarge = fontSize * 8
  1085.  
  1086. FUNCTION printWidthLarge (text$, fontSize AS INTEGER)
  1087.     printWidthLarge = fontWidthLarge(fontSize) * LEN(text$)
  1088.  
  1089. SUB initializeCharSetPrintLarge
  1090.     DIM char, row, column
  1091.     RESTORE charSet8x16
  1092.     FOR char = 0 TO 255
  1093.         FOR row = 1 TO 16
  1094.             FOR column = 1 TO 8
  1095.                 READ charSet(char, row, column)
  1096.             NEXT
  1097.         NEXT
  1098.     NEXT
  1099.  
  1100.     charSet8x16:
  1101.     DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,0,-1,0,0,0,0,0,0,-1,-1,0,-1,0,0,-1,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,-1,-1,-1,-1,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,0,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1102.     DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,-1,-1,0,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,0,0,-1,-1,-1,0,0,-1,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,-1,0,0,-1,-1,-1,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1103.     DATA 0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
  1104.     DATA -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,0,0,0,-1,-1,0,0,-1,-1,0,0,-1,0,0,0,0,-1,0,0,-1,0,0,0,0,-1,0,0,-1,-1,0,0,-1,-1,0,0,0,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,0,0,-1,-1,0,0,-1,-1,0,-1,-1,-1,-1,0,-1,-1,0,-1,-1,-1,-1,0,-1,-1,0,0,-1,-1,0,0,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,0,0,0,0,0,-1,-1,-1,0,0,0,0,-1,-1,0,-1,0,0,0,-1,-1,0,0,-1,0,0,-1,-1,-1,-1,0,0,0,-1,-1,0,0,-1,-1,0,0
  1105.     DATA -1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,0,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,0,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,0,-1,-1,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,-1,-1,-1,-1,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,0,0,0,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,0,0,-1,-1
  1106.     DATA 0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,0,-1,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,-1,0,0,-1,-1,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,-1,-1,0,0,-1,-1,-1,-1,0,0,-1,-1,-1,0,0,-1,-1,-1,0,0,-1,-1,-1,-1,0,0,-1,-1,0,-1,-1,0,-1,-1,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,0,0,-1,-1,-1
  1107.     DATA -1,-1,0,0,0,0,-1,-1,-1,-1,0,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,0,-1,-1,-1,-1,0,-1,-1,0,-1,-1,-1,-1,0,-1,-1,0,-1,-1,0,-1,-1,-1,-1,0,-1,-1,0,0,0,-1,-1,0,-1,-1
  1108.     DATA 0,0,0,-1,-1,0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,0,0,-1,-1,0,0,0,-1,-1,0,0,-1,-1,0,0,0,0,0,0,0,-1,-1,-1,0,0,0,0,-1,-1,0,-1,-1,0,0,-1,-1,0,0,0,-1,-1,0,-1,-1,0,0,0,-1,-1,0,0,-1,-1,0,-1,-1,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,0,-1,-1,0,0,-1,-1,0,0,0,-1,-1,0,0,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,-1,-1,-1,-1
  1109.     DATA -1,-1,0,0,0,-1,-1,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,-1,-1,0,0,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1110.     DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,0,0,-1,-1,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,-1,0,0,0,0,-1,-1,0,-1,-1,0,0,-1,-1,-1,-1,-1,-1,-1,0,0,-1,-1,0,-1,-1,0,0,0,0,-1,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,0,0,0,0
  1111.     DATA -1,-1,-1,0,0,0,0,0,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,-1,-1,-1,-1,0,0,-1,-1,-1,-1,-1,0,0,0,-1,-1,-1,-1,-1,0,0,0,0,-1,-1,-1,0,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0<