1 /* This script file handles the game logic */
5 var maxIndex = maxColumn*maxRow;
6 var board = new Array(maxIndex);
7 var blockSrc = "SamegameCore/BoomBlock.qml";
10 var component = Qt.createComponent(blockSrc);
12 // Index function used instead of a 2D array
13 function index(column, row)
15 return column + row * maxColumn;
18 function timeStr(msecs)
20 var secs = Math.floor(msecs/1000);
21 var m = Math.floor(secs/60);
22 var ret = "" + m + "m " + (secs%60) + "s";
26 function startNewGame()
28 // Delete blocks from previous game
29 for (var i = 0; i < maxIndex; i++) {
34 // Calculate board size
35 maxColumn = Math.floor(gameCanvas.width/gameCanvas.blockSize);
36 maxRow = Math.floor(gameCanvas.height/gameCanvas.blockSize);
37 maxIndex = maxRow * maxColumn;
40 nameInputDialog.forceClose();
44 board = new Array(maxIndex);
46 for (var column = 0; column < maxColumn; column++) {
47 for (var row = 0; row < maxRow; row++) {
48 board[index(column, row)] = null;
49 createBlock(column, row);
52 gameDuration = new Date();
55 var fillFound; // Set after a floodFill call to the number of blocks found
56 var floodBoard; // Set to 1 if the floodFill reaches off that node
58 // NOTE: Be careful with vars named x,y, as the calling object's x,y are still in scope
59 function handleClick(x,y)
61 var column = Math.floor(x/gameCanvas.blockSize);
62 var row = Math.floor(y/gameCanvas.blockSize);
63 if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
65 if (board[index(column, row)] == null)
67 // If it's a valid block, remove it and all connected (does nothing if it's not connected)
68 floodFill(column,row, -1);
71 gameCanvas.score += (fillFound - 1) * (fillFound - 1);
76 function floodFill(column,row,type)
78 if (board[index(column, row)] == null)
83 type = board[index(column,row)].type;
85 // Flood fill initialization
87 floodBoard = new Array(maxIndex);
89 if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
91 if (floodBoard[index(column, row)] == 1 || (!first && type != board[index(column, row)].type))
93 floodBoard[index(column, row)] = 1;
94 floodFill(column + 1, row, type);
95 floodFill(column - 1, row, type);
96 floodFill(column, row + 1, type);
97 floodFill(column, row - 1, type);
98 if (first == true && fillFound == 0)
99 return; // Can't remove single blocks
100 board[index(column, row)].dying = true;
101 board[index(column, row)] = null;
105 function shuffleDown()
108 for (var column = 0; column < maxColumn; column++) {
110 for (var row = maxRow - 1; row >= 0; row--) {
111 if (board[index(column,row)] == null) {
115 var obj = board[index(column, row)];
116 obj.y = (row + fallDist) * gameCanvas.blockSize;
117 board[index(column, row + fallDist)] = obj;
118 board[index(column, row)] = null;
125 for (column = 0; column < maxColumn; column++) {
126 if (board[index(column, maxRow - 1)] == null) {
130 for (row = 0; row < maxRow; row++) {
131 obj = board[index(column, row)];
134 obj.x = (column - fallDist) * gameCanvas.blockSize;
135 board[index(column - fallDist,row)] = obj;
136 board[index(column, row)] = null;
143 function victoryCheck()
145 // Awards bonuses for no blocks left
146 var deservesBonus = true;
147 for (var column = maxColumn - 1; column >= 0; column--)
148 if (board[index(column, maxRow - 1)] != null)
149 deservesBonus = false;
151 gameCanvas.score += 500;
152 // Checks for game over
153 if (deservesBonus || !(floodMoveCheck(0, maxRow - 1, -1))) {
154 gameDuration = new Date() - gameDuration;
155 nameInputDialog.show("You won! Please enter your name: ");
156 nameInputDialog.initialWidth = nameInputDialog.text.width + 20;
157 if (nameInputDialog.name == "")
158 nameInputDialog.width = nameInputDialog.initialWidth;
159 nameInputDialog.text.opacity = 0; // Just a spacer
163 // Only floods up and right, to see if it can find adjacent same-typed blocks
164 function floodMoveCheck(column, row, type)
166 if (column >= maxColumn || column < 0 || row >= maxRow || row < 0)
168 if (board[index(column, row)] == null)
170 var myType = board[index(column, row)].type;
173 return floodMoveCheck(column + 1, row, myType) ||
174 floodMoveCheck(column, row - 1, board[index(column, row)].type);
177 function createBlock(column,row)
179 // Note that we don't wait for the component to become ready. This will
180 // only work if the block QML is a local file. Otherwise the component will
181 // not be ready immediately. There is a statusChanged signal on the
182 // component you could use if you want to wait to load remote files.
183 if(component.status == Component.Ready){
184 var dynamicObject = component.createObject(gameCanvas,
185 {"type": Math.floor(Math.random() * 3),
186 "x": column*gameCanvas.blockSize,
187 "width": gameCanvas.blockSize,
188 "height": gameCanvas.blockSize});
189 if(dynamicObject == null){
190 console.log("error creating block");
191 console.log(component.errorString());
194 dynamicObject.y = row*gameCanvas.blockSize;
195 dynamicObject.spawned = true;
197 board[index(column,row)] = dynamicObject;
199 console.log("error loading block component");
200 console.log(component.errorString());
206 function saveHighScore(name)
211 var db = openDatabaseSync(
214 "Local SameGame High Scores",
217 var dataStr = "INSERT INTO Scores VALUES(?, ?, ?, ?)";
221 maxColumn + "x" + maxRow,
222 Math.floor(gameDuration / 1000)
226 tx.executeSql('CREATE TABLE IF NOT EXISTS Scores(name TEXT, score NUMBER, gridSize TEXT, time NUMBER)');
227 tx.executeSql(dataStr, data);
229 // Only show results for the current grid size
230 var rs = tx.executeSql('SELECT * FROM Scores WHERE gridSize = "'
231 + maxColumn + "x" + maxRow + '" ORDER BY score desc LIMIT 10');
232 var r = "\nHIGH SCORES for this grid size\n\n"
233 for (var i = 0; i < rs.rows.length; i++) {
234 r += (i+1) + ". " + rs.rows.item(i).name + ' got '
235 + rs.rows.item(i).score + ' points in '
236 + rs.rows.item(i).time + ' seconds.\n';
243 function sendHighScore(name)
245 var postman = new XMLHttpRequest()
246 var postData = "name=" + name + "&score=" + gameCanvas.score
247 + "&gridSize=" + maxColumn + "x" + maxRow
248 + "&time=" + Math.floor(gameDuration / 1000);
249 postman.open("POST", scoresURL, true);
250 postman.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
251 postman.onreadystatechange = function() {
252 if (postman.readyState == postman.DONE) {
253 dialog.show("Your score has been uploaded.");
256 postman.send(postData);