1 /* This script file handles the game logic */
3 .import QtQuick.LocalStorage 2.0 as Sql
7 var maxIndex = maxColumn*maxRow;
8 var board = new Array(maxIndex);
9 var blockSrc = "BoomBlock.qml";
12 var component = Qt.createComponent(blockSrc);
13 var highScoreBar = -1;
15 var nameInputDialog = null;
18 // Index function used instead of a 2D array
19 function index(column, row)
21 return column + row * maxColumn;
24 function timeStr(msecs)
26 var secs = Math.floor(msecs/1000);
27 var m = Math.floor(secs/60);
28 var ret = "" + m + "m " + (secs%60) + "s";
32 function startNewGame(gc)
35 // Delete blocks from previous game
36 for (var i = 0; i < maxIndex; i++) {
41 // Calculate board size
42 maxColumn = Math.floor(gameCanvas.width/gameCanvas.blockSize);
43 maxRow = Math.floor(gameCanvas.height/gameCanvas.blockSize);
44 maxIndex = maxRow * maxColumn;
47 if(nameInputDialog != null)
48 nameInputDialog.forceClose();
53 board = new Array(maxIndex);
55 for (var column = 0; column < maxColumn; column++) {
56 for (var row = 0; row < maxRow; row++) {
57 board[index(column, row)] = null;
58 createBlock(column, row);
61 gameDuration = new Date();
64 var fillFound; // Set after a floodFill call to the number of blocks found
65 var floodBoard; // Set to 1 if the floodFill reaches off that node
67 // NOTE: Be careful with vars named x,y, as the calling object's x,y are still in scope
68 function handleClick(x,y)
70 if(gameCanvas == undefined){
71 console.log("But the game hasn't started yet!");
74 var column = Math.floor(x/gameCanvas.blockSize);
75 var row = Math.floor(y/gameCanvas.blockSize);
76 if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
78 if (board[index(column, row)] == null)
80 // If it's a valid block, remove it and all connected (does nothing if it's not connected)
81 floodFill(column,row, -1);
84 gameCanvas.score += (fillFound - 1) * (fillFound - 1);
89 function floodFill(column,row,type)
91 if (board[index(column, row)] == null)
96 type = board[index(column,row)].type;
98 // Flood fill initialization
100 floodBoard = new Array(maxIndex);
102 if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
104 if (floodBoard[index(column, row)] == 1 || (!first && type != board[index(column, row)].type))
106 floodBoard[index(column, row)] = 1;
107 floodFill(column + 1, row, type);
108 floodFill(column - 1, row, type);
109 floodFill(column, row + 1, type);
110 floodFill(column, row - 1, type);
111 if (first == true && fillFound == 0)
112 return; // Can't remove single blocks
113 board[index(column, row)].dying = true;
114 board[index(column, row)] = null;
118 function shuffleDown()
121 for (var column = 0; column < maxColumn; column++) {
123 for (var row = maxRow - 1; row >= 0; row--) {
124 if (board[index(column,row)] == null) {
128 var obj = board[index(column, row)];
129 obj.y = (row + fallDist) * gameCanvas.blockSize;
130 board[index(column, row + fallDist)] = obj;
131 board[index(column, row)] = null;
138 for (column = 0; column < maxColumn; column++) {
139 if (board[index(column, maxRow - 1)] == null) {
143 for (row = 0; row < maxRow; row++) {
144 obj = board[index(column, row)];
147 obj.x = (column - fallDist) * gameCanvas.blockSize;
148 board[index(column - fallDist,row)] = obj;
149 board[index(column, row)] = null;
156 function victoryCheck()
158 // Awards bonuses for no blocks left
159 var deservesBonus = true;
160 for (var column = maxColumn - 1; column >= 0; column--)
161 if (board[index(column, maxRow - 1)] != null)
162 deservesBonus = false;
164 gameCanvas.score += 500;
165 // Checks for game over
166 if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1))) {
167 gameDuration = new Date() - gameDuration;
168 if(nameInputDialog == null){
169 nameInputDialog = Qt.createQmlObject('import "."; import "samegame.js" as Logic; NameInputDialog{onAccepted: Logic.saveHighScore(name)}', gameCanvas, "highscoredialog.qml");
172 dialog = Qt.createComponent("Dialog.qml").createObject(gameCanvas);
175 if(gameCanvas.score > highScoreBar){
176 nameInputDialog.show("You won! Your name: ");
177 nameInputDialog.initialWidth = nameInputDialog.text.width + 20;
178 if (nameInputDialog.name == "")
179 nameInputDialog.width = nameInputDialog.initialWidth;
180 nameInputDialog.text.opacity = 0; // Just a spacer
182 dialog.show("You won!");
187 // Only floods up and right, to see if it can find adjacent same-typed blocks
188 function floodMoveCheck(column, row, type)
190 if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
192 if (board[index(column, row)] == null)
194 var myType = board[index(column, row)].type;
197 return floodMoveCheck(column + 1, row, myType) ||
198 floodMoveCheck(column, row - 1, board[index(column, row)].type);
201 function createBlock(column,row)
203 // Note that we don't wait for the component to become ready. This will
204 // only work if the block QML is a local file. Otherwise the component will
205 // not be ready immediately. There is a statusChanged signal on the
206 // component you could use if you want to wait to load remote files.
207 if(component.status == 1){
208 var dynamicObject = component.createObject(gameCanvas,
209 {"type": Math.floor(Math.random() * 3),
210 "x": column*gameCanvas.blockSize,
211 "width": gameCanvas.blockSize,
212 "height": gameCanvas.blockSize,
213 "particleSystem": gameCanvas.ps});
214 if(dynamicObject == null){
215 console.log("error creating block");
216 console.log(component.errorString());
219 dynamicObject.y = row*gameCanvas.blockSize;
220 dynamicObject.spawned = true;
222 board[index(column,row)] = dynamicObject;
224 console.log("error loading block component");
225 console.log(component.errorString());
231 function initHighScoreBar()
233 var db = Sql.openDatabaseSync(
236 "Local SameGame High Scores",
241 tx.executeSql('CREATE TABLE IF NOT EXISTS Scores(name TEXT, score NUMBER, gridSize TEXT, time NUMBER)');
242 // Only show results for the current grid size
243 var rs = tx.executeSql('SELECT * FROM Scores WHERE gridSize = "'
244 + maxColumn + "x" + maxRow + '" ORDER BY score desc LIMIT 10');
245 if(rs.rows.length < 10)
248 highScoreBar = rs.rows.item(rs.rows.length - 1).score;
253 function saveHighScore(name)
258 var db = Sql.openDatabaseSync(
261 "Local SameGame High Scores",
264 var dataStr = "INSERT INTO Scores VALUES(?, ?, ?, ?)";
268 maxColumn + "x" + maxRow,
269 Math.floor(gameDuration / 1000)
273 tx.executeSql('CREATE TABLE IF NOT EXISTS Scores(name TEXT, score NUMBER, gridSize TEXT, time NUMBER)');
274 tx.executeSql(dataStr, data);
276 // Only show results for the current grid size
277 var rs = tx.executeSql('SELECT * FROM Scores WHERE gridSize = "'
278 + maxColumn + "x" + maxRow + '" ORDER BY score desc LIMIT 10');
279 var r = "\nHIGH SCORES for this grid size\n\n"
280 for (var i = 0; i < rs.rows.length; i++) {
281 r += (i+1) + ". " + rs.rows.item(i).name + ' got '
282 + rs.rows.item(i).score + ' points in '
283 + rs.rows.item(i).time + ' seconds.\n';
285 if(rs.rows.length == 10)
286 highScoreBar = rs.rows.item(9).score;