2048 2.1.02.bas
2048 2.1.02.bas
2048 2.1.02.bas
'
'Fellippe Heitor <fellippepip@gmail.com> 2 de maio de 2014 01:51
'Para: me@gabrielecirulli.com
'
'Hey there! I loved the simplicity and genius of your 2048 game and
'it inspired me to write my own version of it in QuickBASIC 4.5.
'If you care to take a look, it's here (source included - you'll
'probably need DosBOX to run it): https://www....
'
'Re: 2048 in Qbasic
'1 mensagem
'Gabriele Cirulli <me@gabrielecirulli.com> 18 de maio de 2014 14:50
'Para: Fellippe Heitor <fellippepip@icloud.com>
'
'That sounds very nice! I'm on a mac so I probably won't be able to play,
'but congrats and thank you for putting effort into it!
'
'Gabriele
'-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
'That's how this game was born. The idea's not mine, but all the code is.
'I wrote this originally in QB4.5 (as you can read above) and it worked
'in screen 0. I'm really proud of it, actually! But then I met QB64 and
'the new challenge was to port it to graphics mode, while retaining most
'of the code. That's why you'll see lots of text coordinates being converted
'to graphics coordinates by using _FONTWIDTH and _FONTHEIGHT.
'
'If you enjoy it, please send feedback!
'email: fellippepip@gmail.com
'twitter: fellippeheitor
'-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
'New in version 2.1.01:
' - Help screen, triggered by clicking the help icon on the screen or F1.
' - Sounds can be switched on/off using F2.
'
'New in version 2.1.02:
' - Sounds. If the sound files are present, they are played instead of
' PLAY sounds. Sound files are licensed under the Creative Commons 0
' License or Sampling Plus 1.0, and come from the following sources:
' - https://www.freesound.org/people/blue2107/sounds/59978/
' "Bubble Pop" byuser blue2107
'
' - http://soundbible.com/1441-Elevator-Ding.html
' "Elevator Ding" by user Corsica
'
' - http://soundbible.com/2068-Woosh.html
' "Woosh" by user Mark DiAngelo
'
_TITLE "2048"
$RESIZE:STRETCH
'Constants
CONST MinAchievement = 32
CONST NoAnimation = 0
CONST FastAnimation = 1
CONST NormalAnimation = 2
CONST SameColor = -1
CONST DirUp = 8
CONST DirDown = 2
CONST DirLeft = 4
CONST DirRight = 6
CONST CellWidth = 16
CONST CellHeight = 7
CONST Line1 = 6
CONST Line2 = Line1 + CellHeight
CONST Line3 = Line2 + CellHeight
CONST Line4 = Line3 + CellHeight
CONST Column1 = 18
CONST Column2 = Column1 + CellWidth
CONST Column3 = Column2 + CellWidth
CONST Column4 = Column3 + CellWidth
'Our "sound files". Instructions for the PLAY commands throughout the game
CONST SoundForMovement = "MB O0 L64 C"
CONST SoundForSum = "MB O2 L64 E,G"
CONST SoundForAchievement = "MB O2 L32 E,G,> C E,G,> C"
CONST True = -1
CONST False = NOT True
CONST UserWantsToQuit = 16
'Type declarations
TYPE BoardControl
CellValue AS INTEGER
PreviousValue AS INTEGER
WasSummed AS INTEGER
END TYPE
TYPE Coordinates
x AS INTEGER
y AS INTEGER
END TYPE
TYPE HighestScoresType
PlayerName AS STRING * 8
Points AS LONG
END TYPE
'Highscore variables
DIM SHARED HighestScore AS LONG, CatchError AS INTEGER
DIM SHARED HighScores(1 TO 11) AS HighestScoresType
DIM SHARED Restored AS _BYTE
DIM SHARED Score AS LONG
'Misc variables
DIM SHARED GameScreen AS LONG
DIM SHARED InputCol AS INTEGER
DIM SHARED CheatSuspend AS _BYTE
DIM SHARED Cheat AS STRING
DIM SHARED SoundSwitch AS _BYTE
DIM SHARED GlobalSum AS _BYTE
DIM SHARED QuitAttempt AS INTEGER
DIM i AS INTEGER
'Set a game screen that's just slightly different to default 800x600 resolution
'so that we have no unreachable text lines, considering _FONT16 default
GameScreen = _NEWIMAGE(800, 592, 32)
SCREEN GameScreen
RESTORE Colors32
FOR i = 0 TO 15
READ r&, g&, b&
ColorPalette(i) = _RGB32(r&, g&, b&)
NEXT
MainScreenBackground = ColorPalette(15)
BoardBack = CellBGColor(0)
FOR i = 1 TO 11
HighScores(i).PlayerName = "-"
HighScores(i).Points = 0
NEXT i
SoundSwitch = True
LastMovement = False
LastSum = 0
Achievement = MinAchievement
Settings ReadSettings
HighestScore = 0
FOR i = 1 TO 11
IF HighScores(i).Points > HighestScore THEN
HighestScore = HighScores(i).Points
END IF
NEXT i
FOR x = 1 TO 4
FOR y = 1 TO 4
SELECT CASE x
CASE 1: PrintRows(x, y) = Line1
CASE 2: PrintRows(x, y) = Line2
CASE 3: PrintRows(x, y) = Line3
CASE 4: PrintRows(x, y) = Line4
END SELECT
SELECT CASE y
CASE 1: PrintCols(x, y) = Column1
CASE 2: PrintCols(x, y) = Column2
CASE 3: PrintCols(x, y) = Column3
CASE 4: PrintCols(x, y) = Column4
END SELECT
NEXT y
NEXT x
HideAchievement = False
ShowAchievement = False
AchievementRow = 1
EditMode = NotEditing
Intro
CLS , MainScreenBackground
DisplayEmptyBoard 'Just because I want it to have a shadow
RANDOMIZE TIMER
CheatSuspend = False
Won = False
DisplayBoard
IF Score = 0 AND Restored = False THEN GenerateNewNumber 2, True
DisplayScore
Backup
DO
_LIMIT 30
k$ = ""
DO WHILE k$ = ""
_LIMIT 30
QuitAttempt = _EXIT
IF QuitAttempt > 0 AND Score > 0 THEN
EndGame UserWantsToQuit
ELSEIF QuitAttempt > 0 AND Score = 0 THEN
SYSTEM
END IF
IF ClickedOnHelpButton THEN ShowHelp
k$ = INKEY$
LOOP
SELECT CASE k$
CASE CHR$(27)
EndGame False
CASE CHR$(0) + CHR$(72) 'Up
MoveCells DirUp
CASE CHR$(0) + CHR$(80) 'Down
MoveCells DirDown
CASE CHR$(0) + CHR$(75) 'Left
MoveCells DirLeft
CASE CHR$(0) + CHR$(77) 'Right
MoveCells DirRight
CASE CHR$(0) + CHR$(59) 'F1
ShowHelp
CASE CHR$(0) + CHR$(63) 'F5
COLOR ColorPalette(0), MainScreenBackground
CLS
ShowHelpIcon
ClearBoard
DisplayEmptyBoard
GenerateNewNumber 2, True
Score = 0
DisplayScore
CASE CHR$(26) 'CTRL + Z
IF LastMovement THEN
RestoreBackup
Score = Score - LastSum
LastSum = 0
LastMovement = False
DisplayBoard
DisplayScore
LOCATE BottomLine, 1: COLOR ColorPalette(7), MainScreenBackground
PRINT "UNDONE ";
StartStatusBarTimer
ELSE
LOCATE BottomLine, 1: COLOR ColorPalette(7), MainScreenBackground
PRINT "NO UNDO ";
StartStatusBarTimer
END IF
CASE CHR$(0) + CHR$(60) 'F2
SoundSwitch = NOT SoundSwitch
LOCATE BottomLine, 1: COLOR ColorPalette(7), MainScreenBackground
PRINT "Sound";
IF SoundSwitch THEN PRINT " ON"; ELSE PRINT "OFF";
StartStatusBarTimer
CASE ELSE
IF NOT CheatSuspend THEN
Cheat = Cheat + k$
LOCATE BottomLine, 1: COLOR ColorPalette(7), MainScreenBackground
PRINT STRING$(LEN(Cheat), "*"); STRING$(8 - LEN(Cheat), " ");
StartStatusBarTimer
END IF
END SELECT
IF LEN(Cheat) = 8 THEN
ClearStatusBar
SYSTEM
SettingsError:
CatchError = ERR
RESUME NEXT
SUB Backup ()
'Creates a copy of the BoardArray so that the player can CTRL+Z the last movement
made
DIM x AS INTEGER, y AS INTEGER
FOR x = 1 TO 4
FOR y = 1 TO 4
BoardArray(x, y).PreviousValue = BoardArray(x, y).CellValue
NEXT y
NEXT x
END SUB
'Set background color for eventual subsequent PRINT statements, as boxes are
usually displayed
'to show messages to the user.
COLOR , BgColor
'If Shadow was requested, draw it first. Shadow is dark grey with ALPHA (_RGBA32)
IF Shadow THEN
ShadowColor = _RGBA32(100, 100, 100, 100)
LINE ((((_WIDTH \ _FONTWIDTH) \ 2) - BoxWidth \ 2) * _FONTWIDTH, BoxTop *
_FONTHEIGHT - (_FONTHEIGHT \ 2))-STEP(BoxWidth * _FONTWIDTH, BoxHeight *
_FONTHEIGHT), ShadowColor, BF
END IF
'The border.
IF HasBorder THEN
BorderColor = _RGB32(r&, g&, b&)
'Set background color for eventual subsequent PRINT statements, as boxes are
usually displayed
'to show messages to the user.
COLOR , BgColor
END SUB
END SUB
END FUNCTION
SUB ClearHighScores ()
'Asks user to confirm before clearing high scores (<DELETE> key)
DIM i AS INTEGER
ThisDelay = .03
FOR i = 1 TO 3
Center i, STRING$(31, " ")
_DELAY ThisDelay
NEXT i
k$ = ""
DO WHILE k$ = ""
_LIMIT 30
k$ = INKEY$
LOOP
CheatSuspend = True
BoxHeight = 18
BoxTop = ((_HEIGHT \ _FONTHEIGHT) \ 2) - (BoxHeight \ 2)
IF Won = True THEN WinAnimation
HideHelpIcon
DO
k$ = ""
DO WHILE k$ = ""
_LIMIT 30
k$ = INKEY$
QuitAttempt = _EXIT
IF QuitAttempt > 0 THEN k$ = "N"
LOOP
SELECT CASE UCASE$(k$)
CASE CHR$(27), "N"
COLOR ColorPalette(7), ColorPalette(8)
IF GameOver = True OR Won OR GameOver = UserWantsToQuit THEN
ClearBoard
Score = 0
END IF
Settings WriteSettings
SYSTEM
CASE "Y"
IF GameOver = True OR Won THEN
Score = 0: Won = False
GameOver = False
COLOR ColorPalette(0), MainScreenBackground
CLS
ShowHelpIcon
ClearBoard
DisplayEmptyBoard
GenerateNewNumber 2, True
DisplayScore
CheatSuspend = False
EXIT SUB
ELSEIF GameOver = UserWantsToQuit THEN
Settings WriteSettings
SYSTEM
ELSE
DisplayBoard
DisplayScore
CheatSuspend = False
HideAchievement = True: ShowAchievement = False
AchievementTimer% = _FREETIMER
AchievementShown# = TIMER - 1
ON TIMER(AchievementTimer%, .05) TopMessageTimerAction
TIMER(AchievementTimer%) ON
EXIT SUB
END IF
CASE CHR$(0) + CHR$(83) 'Delete Key
IF GameOver = True OR Won THEN
ClearHighScores
COLOR ColorPalette(7), ColorPalette(0)
ShowHighScores
END IF
END SELECT
LOOP
END SUB
'Randomly picks one of the free cells and fills it with either a 2 or a 4
NewCell = INT(RND * TotalFreeCells) + 1
InitialValue = INT(RND * 4) + 1
IF InitialValue < 2 THEN InitialValue = 2
IF InitialValue > 2 THEN InitialValue = 4
SUB Intro ()
'Displays the initial screen with credits.
DIM StartRow AS INTEGER
CLS , ColorPalette(0)
StartRow = ((_HEIGHT \ _FONTHEIGHT) \ 2) - 2
ThisDelay = .03
ZoomBox 0, 0, _WIDTH, _HEIGHT, ColorPalette(0), ColorPalette(15), 10
ZoomBox ((_WIDTH \ 2) - ((45 \ 2) * 8)) - 8, StartRow * _FONTHEIGHT - _FONTHEIGHT,
45 * 8, 6 * _FONTHEIGHT, ColorPalette(15), ColorPalette(7), 10
COLOR ColorPalette(8), ColorPalette(7)
Center StartRow + 1, "2048"
'Center 13, "programmed in QuickBASIC 4.5"
Center StartRow + 3, "Fellippe Heitor (@FellippeHeitor)"
Center StartRow + 4, "(based on the work of Gabriele Cirulli)"
_DELAY 1
END SUB
SUB ClearBoard ()
'Erases all values on the board, to restart the game
DIM x AS INTEGER, y AS INTEGER
FOR x = 1 TO 4
FOR y = 1 TO 4
BoardArray(x, y).CellValue = 0
NEXT y
NEXT x
END SUB
SUB ManageBoard ()
'Edit mode, only reachable through the use of a cheat code
'(made for testing purposes)
DIM k$
DIM PreviousX AS INTEGER, PreviousY AS INTEGER
DIM i AS INTEGER, BlinkTimer AS INTEGER
CLS , ColorPalette(7)
DisplayEmptyBoard
LOCATE BottomLine, 1
COLOR ColorPalette(0), ColorPalette(7)
PRINT "EDIT MODE: Arrows move; ENTER grabs/releases cell; <V> to change value.";
EditX = 1
EditY = 1
Grabbed = False
BlinkState = False
BlinkTimer = _FREETIMER
ON TIMER(BlinkTimer, .5) MakeCellBlink
TIMER(BlinkTimer) ON
DO
DisplayBoard
k$ = ""
PreviousX = EditX
PreviousY = EditY
DO WHILE k$ = "": _LIMIT 30: k$ = INKEY$: LOOP
SELECT CASE k$
CASE CHR$(27)
CLS , MainScreenBackground
ShowHelpIcon
DisplayBoard
DisplayScore
TIMER(BlinkTimer) FREE
EXIT SUB
CASE CHR$(13) 'Enter
Grabbed = NOT Grabbed
PutCell EditX, EditY, BoardBack, BoardArray(EditX, EditY).CellValue,
NormalAnimation
CASE "v", "V" 'Changes cell value. <Shift> cycles backwards through
possible values.
IF LCASE$(k$) = k$ THEN
IF BoardArray(EditX, EditY).CellValue = 0 THEN
BoardArray(EditX, EditY).CellValue = 2
ELSEIF BoardArray(EditX, EditY).CellValue >= 1024 THEN
BoardArray(EditX, EditY).CellValue = 0
ELSE
BoardArray(EditX, EditY).CellValue = BoardArray(EditX,
EditY).CellValue * 2
END IF
ELSE
IF BoardArray(EditX, EditY).CellValue = 0 THEN
BoardArray(EditX, EditY).CellValue = 1024
ELSEIF BoardArray(EditX, EditY).CellValue = 2 THEN
BoardArray(EditX, EditY).CellValue = 0
ELSE
BoardArray(EditX, EditY).CellValue = BoardArray(EditX,
EditY).CellValue \ 2
END IF
END IF
CASE CHR$(0) + CHR$(72) 'Up
EditX = EditX - 1
IF EditX = 0 THEN EditX = 1
IF Grabbed THEN
IF NOT (PreviousX = EditX) THEN
SWAP BoardArray(EditX, EditY).CellValue, BoardArray(EditX + 1,
EditY).CellValue
END IF
END IF
CASE CHR$(0) + CHR$(80) 'Down
EditX = EditX + 1
IF EditX = 5 THEN EditX = 4
IF Grabbed THEN
IF NOT (PreviousX = EditX) THEN
SWAP BoardArray(EditX, EditY).CellValue, BoardArray(EditX - 1,
EditY).CellValue
END IF
END IF
CASE CHR$(0) + CHR$(75) 'Left
EditY = EditY - 1
IF EditY = 0 THEN EditY = 1
IF Grabbed THEN
IF NOT (PreviousY = EditY) THEN
SWAP BoardArray(EditX, EditY).CellValue, BoardArray(EditX,
EditY + 1).CellValue
END IF
END IF
CASE CHR$(0) + CHR$(77) 'Right
EditY = EditY + 1
IF EditY = 5 THEN EditY = 4
IF Grabbed THEN
IF NOT (PreviousY = EditY) THEN
SWAP BoardArray(EditX, EditY).CellValue, BoardArray(EditX,
EditY - 1).CellValue
END IF
END IF
END SELECT
LOOP
TIMER(BlinkTimer) FREE
END SUB
SUB WinAnimation ()
DIM Ascii2048(1 TO 7) AS STRING, Image2048 AS LONG
DIM i AS INTEGER, ColorToShow AS INTEGER
DIM x AS INTEGER, y AS INTEGER
DIM ImageX AS INTEGER, ImageY AS INTEGER
DIM AnimationSteps AS INTEGER
'Image is 28 x 7 characters
Ascii2048(1) = " ���� ���� � � ���� "
Ascii2048(2) = "� � � � � � � �"
Ascii2048(3) = " � � � � � � �"
Ascii2048(4) = " �� � � ����� ���� "
Ascii2048(5) = " � � � � � �"
Ascii2048(6) = "� � � � � �"
Ascii2048(7) = "������ ���� � ���� "
FOR x = 1 TO 4
FOR y = 1 TO 4
PutCell x, y, SameColor, 2048, NormalAnimation
IF SoundSwitch THEN
IF Blop THEN
_SNDPLAYCOPY Blop
ELSE
PLAY SoundForSum
END IF
END IF
NEXT y
NEXT x
ColorToShow = 512 'Will show a huge cell (the actual board size) with values/colors
equivalent to 512, 1024 and then 2048
DO
ThisDelay = .5
AnimationSteps = 30
ThisDelay = ThisDelay / AnimationSteps
IF SoundSwitch THEN
IF Blop THEN
_SNDPLAYCOPY Blop
ELSE
PLAY SoundForSum
END IF
END IF
ThisDelay = .2
_DELAY ThisDelay
ColorToShow = ColorToShow * 2
IF ColorToShow > 2048 THEN
IF SoundSwitch THEN
IF Ding THEN
_SNDPLAYCOPY Ding
ELSE
PLAY SoundForAchievement
END IF
END IF
EXIT DO
END IF
LOOP
_FREEIMAGE Image2048
END SUB
IntermediateWidth = CellWidth
SELECT CASE Direction
CASE DirUp
VectorX = -1
VectorY = 0
CASE DirDown
VectorX = 1
VectorY = 0
CASE DirLeft
VectorX = 0
VectorY = -1
IntermediateWidth = CellWidth \ 2
CASE DirRight
VectorX = 0
VectorY = 1
END SELECT
_DELAY ThisDelay
END SUB
DIM i AS INTEGER
DIM AnimationSteps AS INTEGER
DIM x AS INTEGER, y AS INTEGER
DIM w AS INTEGER, h AS INTEGER
AnimationSteps = 10
SkipAnimation:
BoxAt PrintCols(Row, Col), PrintRows(Row, Col), CellWidth, CellHeight,
CellBGColor(InitialValue), True
LOCATE PrintRows(Row, Col) + (CellHeight \ 2), PrintCols(Row, Col) + (CellWidth \
2) - 2
PRINT InitialValue;
END SUB
COLOR , BgColor
IF BgColorFrom <> SameColor THEN
RedFrom = _RED(BgColorFrom)
GreenFrom = _GREEN(BgColorFrom)
BlueFrom = _BLUE(BgColorFrom)
RedTo = _RED(BgColor)
GreenTo = _GREEN(BgColor)
BlueTo = _BLUE(BgColor)
ThisStepX = w \ AnimationSteps
ThisStepY = h \ AnimationSteps
IF BgColorFrom = SameColor THEN ThisStepColor = BgColor
FOR i = 1 TO AnimationSteps
IF BgColorFrom <> SameColor THEN
RedStep = RedStep + ((RedTo - RedFrom) / AnimationSteps)
GreenStep = GreenStep + ((GreenTo - GreenFrom) / AnimationSteps)
BlueStep = BlueStep + ((BlueTo - BlueFrom) / AnimationSteps)
ThisStepColor = _RGB32(RedStep, GreenStep, BlueStep)
END IF
xx = x + (w \ 2) - ((ThisStepX * i) \ 2)
yy = y + (h \ 2) - ((ThisStepY * i) \ 2)
ww = ThisStepX * i
hh = ThisStepY * i
_DELAY ThisDelay
NEXT i
END SUB
SUB DisplayScore ()
DIM x AS INTEGER
DIM y AS INTEGER
DIM i AS INTEGER
DIM Msg$
IF Restored THEN
COLOR ColorPalette(8), MainScreenBackground
Msg$ = "(loaded state; <F5> to start a new game)"
Center BottomLine, Msg$
Restored = False
ELSE
ClearStatusBar
END IF
END SUB
SUB DisplaySummedCells ()
'Updates the board view to show the cells that have collided and been summed.
'Animates each newly summed cell. This is not actually intended. I originally
'planned to animated ALL summed cells at once, but I didn't manage to and ended
'up leaving it as is. Shame on me for being lazy.
DIM i AS INTEGER
ThisDelay = .02
FOR Row = 1 TO 4
FOR Col = 1 TO 4
IF BoardArray(Row, Col).WasSummed = True THEN
COLOR CellFGColor(BoardArray(Row, Col).CellValue),
CellBGColor(BoardArray(Row, Col).CellValue)
PutCell Row, Col, CellBGColor(BoardArray(Row, Col).CellValue / 2),
BoardArray(Row, Col).CellValue, NormalAnimation
IF SoundSwitch THEN
IF Blop THEN
_SNDPLAYCOPY Blop
ELSE
PLAY SoundForSum
END IF
END IF
END IF
NEXT Col
NEXT Row
END SUB
SUB DisplayBoard ()
'Reads the BoardArray and displays the current state on the screen. No animation.
DIM x AS INTEGER
DIM y AS INTEGER
DIM TempValue AS INTEGER
DIM HasBorder AS _BYTE
FOR x = 1 TO 4
FOR y = 1 TO 4
IF BoardArray(x, y).WasSummed THEN
TempValue = BoardArray(x, y).CellValue / 2
ELSE
TempValue = BoardArray(x, y).CellValue
END IF
END SUB
SUB DisplayEmptyBoard ()
'Shows only the blank board placeholder. Animates board with ZoomBox
ThisDelay = .02
ZoomBox PrintCols(1, 1) * 8 - 8, PrintRows(1, 1) * 16 - 16, CellWidth * 4 * 8,
CellHeight * 4 * 16, ColorPalette(15), BoardBack, 20
BoxCenter PrintRows(1, 1), CellWidth * 4, CellHeight * 4, BoardBack, False, True
END SUB
GlobalMove = False
GlobalSum = False
Backup
LastSum = 0
IF SoundSwitch THEN
IF Woosh THEN
_SNDPLAYCOPY Woosh
ELSE
PLAY SoundForMovement
END IF
END IF
SELECT CASE Direction
CASE DirDown
StartBoundary = 3
FinalBoundary = 1
Vector = 1
CASE DirUp
StartBoundary = 2
FinalBoundary = 4
Vector = -1
CASE DirRight
StartBoundary = 3
FinalBoundary = 1
Vector = 1
CASE DirLeft
StartBoundary = 2
FinalBoundary = 4
Vector = -1
END SELECT
DO
DidSum = False
DidMove = False
'Finally, check if after all sums we found a 2048 cell, which means the game was
won
'I gotta be honest here: Not playing the original game, nor playing my own have I
ever
'been able to achieve the 2048 cell without cheating. Shame on me for being so
clumsy.
FOR x = 1 TO 4
FOR y = 1 TO 4
BoardArray(x, y).WasSummed = False
IF BoardArray(x, y).CellValue = 2048 THEN
Won = True
EndGame False
END IF
NEXT y
NEXT x
CheckPossibleMoves
END SUB
SUB RestoreBackup ()
'User hit CTRL+Z. If we have a backup copy (only 1 step back is allowed at this
point)
'we restore the backup board. Any points won with the last move will also be lost.
DIM x AS INTEGER, y AS INTEGER
FOR x = 1 TO 4
FOR y = 1 TO 4
BoardArray(x, y).CellValue = BoardArray(x, y).PreviousValue
NEXT y
NEXT x
END SUB
ShowHighScores
SkipAnimation = False
CurrentHighScore = 11
'Clear the keyboard buffer so that we can have the animation at least start.
WHILE INKEY$ <> "": WEND
HighScores(CurrentHighScore).PlayerName = "-"
HighScores(CurrentHighScore).Points = 0
StepsToTake = 1
CheckHighScores = 11
HighScores(CurrentHighScore).Points = Score
ShowHighScores
'If a new highscore was achieved, input user name for the record
IF CurrentHighScore < 11 THEN
LOCATE BoxTop + 3 + CurrentHighScore, InputCol
COLOR ColorPalette(14), ColorPalette(7)
INPUT "", HighScores(CurrentHighScore).PlayerName
HighScores(CurrentHighScore).PlayerName = UCASE$
(HighScores(CurrentHighScore).PlayerName)
IF LTRIM$(RTRIM$(HighScores(CurrentHighScore).PlayerName)) = "" THEN
HighScores(CurrentHighScore).PlayerName = "-"
END IF
COLOR ColorPalette(7), ColorPalette(0)
ShowHighScores
END IF
END IF
DisplayScore
END SUB
CatchError = 0
SELECT CASE WhatToDo
CASE WriteSettings
'Write sound setting and highest scores to 2048.DAT;
'If file can't be created, exits sub. Not essential anyway.
'Current game state is also saved upon exit.
DataFile = FREEFILE
ON ERROR GOTO SettingsError
OPEN "2048.DAT" FOR RANDOM AS DataFile
IF CatchError = 57 THEN EXIT SUB
Restored = False
FOR x = 1 TO 4
FOR y = 1 TO 4
PUT DataFile, , BoardArray(x, y).CellValue
IF BoardArray(x, y).CellValue > 0 THEN Restored = True
NEXT y
NEXT x
CLOSE DataFile
CASE ReadSettings
'Read sound setting and highest scores from 2048.DAT;
'Last game saved is also restored, if any.
'If file is not found, uses the zeroed highest scores list.
DataFile = FREEFILE
ON ERROR GOTO SettingsError
OPEN "2048.DAT" FOR INPUT AS DataFile
IF CatchError = 53 THEN
Restored = False
EXIT SUB
END IF
CLOSE DataFile
OPEN "2048.DAT" FOR RANDOM AS DataFile
FOR x = 1 TO 4
FOR y = 1 TO 4
GET DataFile, , BoardArray(x, y).CellValue
IF Achievement < BoardArray(x, y).CellValue THEN
Achievement = BoardArray(x, y).CellValue
END IF
NEXT y
NEXT x
CLOSE DataFile
END SELECT
END SUB
SUB ShowANewHighScoreMessage ()
'Displays a banner if a new highscore was achieved.
DIM i AS INTEGER
SUB ShowHighScores ()
'Populate the final dialog with saved highscores
DIM i AS INTEGER, ValueToText AS STRING
FOR i = 1 TO 10
ValueToText = LTRIM$(RTRIM$(STR$(HighScores(i).Points)))
ValueToText = HighScores(i).PlayerName + STRING$(18 - LEN(ValueToText), ".") +
ValueToText
COLOR ColorPalette(8), ColorPalette(7)
Center BoxTop + 3 + i, ValueToText
NEXT i
IF NOT InputCol THEN InputCol = CenterCol(ValueToText)
END SUB
SUB TopMessageTimerAction ()
'Displays achievements banner with a brief animation. Leaves it up there for 1
second.
'If achievement banner is already there, waits until the desired time has passed
'(set using AchievementShown# = TIMER - DesiredTime) and clears it.
IF HideAchievement THEN
IF TIMER - AchievementShown# < 2 THEN EXIT SUB 'Wait before clearing
achievements panel
COLOR ColorPalette(0), MainScreenBackground
Center AchievementRow, STRING$(30, " ")
IF AchievementRow = 1 THEN
HideAchievement = False
TIMER(AchievementTimer%) FREE
ELSE
AchievementRow = AchievementRow - 1
END IF
END IF
IF ShowAchievement THEN
COLOR CellFGColor(Achievement), CellBGColor(Achievement)
Center AchievementRow, STRING$(30, " ")
IF AchievementRow = 3 THEN
Center 2, "New Achievement: " + STR$(Achievement) + " tile."
HideAchievement = True
ShowAchievement = False
AchievementShown# = TIMER
ELSE
AchievementRow = AchievementRow + 1
END IF
END IF
END SUB
SUB CheckPossibleMoves ()
'Can the game go on? Are there still empty cells to move to?
'Are there still cells with the same value aligned and ready
'to be summed? Well, let's see that in this procedure.
DIM x AS INTEGER, y AS INTEGER
FOR x = 1 TO 4
FOR y = 1 TO 4
IF BoardArray(x, y).CellValue = 0 THEN EXIT SUB
SELECT CASE x
CASE 1
SELECT CASE y
CASE 1
IF BoardArray(x, y).CellValue = BoardArray(x + 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y +
1).CellValue THEN EXIT SUB
CASE 2, 3
IF BoardArray(x, y).CellValue = BoardArray(x + 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y +
1).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y -
1).CellValue THEN EXIT SUB
CASE 4
IF BoardArray(x, y).CellValue = BoardArray(x, y -
1).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x + 1,
y).CellValue THEN EXIT SUB
END SELECT
CASE 2, 3
SELECT CASE y
CASE 1
IF BoardArray(x, y).CellValue = BoardArray(x + 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y +
1).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x - 1,
y).CellValue THEN EXIT SUB
CASE 2, 3
IF BoardArray(x, y).CellValue = BoardArray(x + 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x - 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y +
1).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y -
1).CellValue THEN EXIT SUB
CASE 4
IF BoardArray(x, y).CellValue = BoardArray(x + 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y -
1).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x - 1,
y).CellValue THEN EXIT SUB
END SELECT
CASE 4
SELECT CASE y
CASE 1
IF BoardArray(x, y).CellValue = BoardArray(x - 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y +
1).CellValue THEN EXIT SUB
CASE 2, 3
IF BoardArray(x, y).CellValue = BoardArray(x - 1,
y).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y +
1).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x, y -
1).CellValue THEN EXIT SUB
CASE 4
IF BoardArray(x, y).CellValue = BoardArray(x, y -
1).CellValue THEN EXIT SUB
IF BoardArray(x, y).CellValue = BoardArray(x - 1,
y).CellValue THEN EXIT SUB
END SELECT
END SELECT
NEXT y
NEXT x
FUNCTION BottomLine
'Calculates what the bottom line is in current screen mode, considering
'current font height.
BottomLine = (_HEIGHT \ _FONTHEIGHT)
END FUNCTION
SUB ClearStatusBar
'Clears status bar messages and cheat codes. Frees the timer that invoked the
subprocedure.
LOCATE BottomLine, 1
COLOR , MainScreenBackground
PRINT STRING$(_WIDTH \ _FONTWIDTH, " ");
TIMER(StatusBarTimer) FREE
'If this procedure was invoked while the player tried to use a cheat code,
'this clears what has been typed so far. Gotta type faster next time.
IF LEN(Cheat) < 8 THEN Cheat = ""
END SUB
SUB StartStatusBarTimer
'This subprocedure is invoked everytime a new message is printed
'to the status bar. That way each message only gets to be shown for
'one second.
TIMER(StatusBarTimer) FREE
StatusBarTimer = _FREETIMER
ON TIMER(StatusBarTimer, 1) ClearStatusBar
TIMER(StatusBarTimer) ON
END SUB
SUB MakeCellBlink
'Make cells blink (like a cursor) to indicate edit mode
IF Grabbed THEN
COLOR , ColorPalette(12)
ELSE
COLOR , CellBGColor(BoardArray(EditX, EditY).CellValue)
END IF
PRINT BoardArray(EditX, EditY).CellValue;
END SUB
FUNCTION ClickedOnHelpButton
DIM mx AS INTEGER, my AS INTEGER, mb AS INTEGER
ClickedOnHelpButton = False
IF mb THEN
IF mx > HelpIconX THEN
IF my > HelpIconY THEN
IF mx < HelpIconX + HelpIconW AND my < HelpIconY + HelpIconH THEN
ClickedOnHelpButton = True
_DELAY .2
END IF
END IF
END IF
END IF
END FUNCTION
SUB ShowHelpIcon
'Place help icon on the screen
HelpIcon = _LOADIMAGE("helpicon.png")
SUB HideHelpIcon
'Place a box on screen to cover the help icon
LINE (HelpIconX, HelpIconY)-STEP(HelpIconW, HelpIconY), MainScreenBackground, BF
END SUB
SUB ShowHelp
DIM BackupScreen AS LONG, k$, mb AS INTEGER
DIM HelpText(1 TO 19) AS STRING, i AS INTEGER
DIM BoxTop AS INTEGER
HelpText(1) = "Here's the deal: You've got this grid with cells, which"
HelpText(2) = "you move around using arrow keys. Every time you move"
HelpText(3) = "the board, all cells go that way and eventually collide."
HelpText(4) = "If a cell collides with another cell holding the same"
HelpText(5) = "value, they will be merged into a new cell that contains"
HelpText(6) = "the resulting sum. You are supposed to combine cells"
HelpText(7) = "and generate every time higher valued cells."
HelpText(9) = "Your goal is to achieve the mythical 2048 cell."
HelpText(11) = "It's going to be a hypnotical shiny shade of green"
HelpText(12) = "when it appears on your screen."
HelpText(14) = "You can:"
HelpText(15) = "Restart the game with F5"
HelpText(16) = "Toggle sound with F2"
HelpText(17) = "Undo your last move with CTRL+Z"
HelpText(19) = "Hit any key or click here to go back to game"
BackupScreen = _COPYIMAGE(0)
HelpScreen = _LOADIMAGE("helptext.png")
'place a semitransparent box over current screen to give focus to help instructions
LINE (0, 0)-(_WIDTH, _HEIGHT), _RGBA32(255, 255, 255, 150), BF
IF HelpScreen < -1 THEN
_PUTIMAGE (0, 0), HelpScreen
ELSE
BoxTop = ((_HEIGHT \ _FONTHEIGHT) \ 2) - (UBOUND(helptext) \ 2)
BoxCenter BoxTop, 60, UBOUND(helptext) + 2, ColorPalette(8), True, True
COLOR ColorPalette(15), ColorPalette(8)
FOR i = 1 TO UBOUND(helptext)
Center BoxTop + i, HelpText(i)
NEXT i
END IF
k$ = ""
DO
k$ = INKEY$
WHILE _MOUSEINPUT: WEND
mb = _MOUSEBUTTON(1)
IF mb THEN
_DELAY .02
EXIT DO
END IF
LOOP WHILE k$ = ""
WHILE _MOUSEINPUT: WEND
_DELAY .2
_PUTIMAGE (0, 0), BackupScreen
_FREEIMAGE BackupScreen
_FREEIMAGE HelpScreen
END SUB