/* This script file handles the game logic */ //Note that X/Y referred to here are in game coordinates var maxX = 10;//Nums are for tileSize 40 var maxY = 15; var tileSize = 40; var maxIndex = maxX*maxY; var board = new Array(maxIndex); var tileSrc = "content/BoomBlock.qml"; var scoresURL = "http://qtfx-nokia.trolltech.com.au/samegame/scores.php"; var timer; var component; //Index function used instead of a 2D array function index(xIdx,yIdx) { return xIdx + (yIdx * maxX); } function timeStr(msecs) { var secs = Math.floor(msecs/1000); var m = Math.floor(secs/60); var ret = "" + m + "m " + (secs%60) + "s"; return ret; } function initBoard() { for(i = 0; i= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return; if(board[index(xIdx, yIdx)] == null) return; //If it's a valid tile, remove it and all connected (does nothing if it's not connected) floodFill(xIdx,yIdx, -1); if(fillFound <= 0) return; gameCanvas.score += (fillFound - 1) * (fillFound - 1); shuffleDown(); victoryCheck(); } function floodFill(xIdx,yIdx,type) { if(board[index(xIdx, yIdx)] == null) return; var first = false; if(type == -1){ first = true; type = board[index(xIdx,yIdx)].type; //Flood fill initialization fillFound = 0; floodBoard = new Array(maxIndex); } if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return; if(floodBoard[index(xIdx, yIdx)] == 1 || (!first && type != board[index(xIdx,yIdx)].type)) return; floodBoard[index(xIdx, yIdx)] = 1; floodFill(xIdx+1,yIdx,type); floodFill(xIdx-1,yIdx,type); floodFill(xIdx,yIdx+1,type); floodFill(xIdx,yIdx-1,type); if(first==true && fillFound == 0) return;//Can't remove single tiles board[index(xIdx,yIdx)].dying = true; board[index(xIdx,yIdx)] = null; fillFound += 1; } function shuffleDown() { //Fall down for(xIdx=0; xIdx=0; yIdx--){ if(board[index(xIdx,yIdx)] == null){ fallDist += 1; }else{ if(fallDist > 0){ obj = board[index(xIdx,yIdx)]; obj.targetY += fallDist * tileSize; board[index(xIdx,yIdx+fallDist)] = obj; board[index(xIdx,yIdx)] = null; } } } } //Fall to the left fallDist = 0; for(xIdx=0; xIdx 0){ for(yIdx=0; yIdx=0; xIdx--) if(board[index(xIdx, maxY - 1)] != null) deservesBonus = false; if(deservesBonus) gameCanvas.score += 500; //Checks for game over if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))){ dialog.text = "Game Over. Your score is " + gameCanvas.score; dialog.opacity = 1; timer = new Date() - timer; //if(scoresURL != "") sendHighScore(name); } } //only floods up and right, to see if it can find adjacent same-typed tiles function floodMoveCheck(xIdx, yIdx, type) { if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return false; if(board[index(xIdx, yIdx)] == null) return false; myType = board[index(xIdx, yIdx)].type; if(type == myType) return true; return floodMoveCheck(xIdx + 1, yIdx, myType) || floodMoveCheck(xIdx, yIdx - 1, board[index(xIdx,yIdx)].type); } //If the component isn't ready, then the signal doesn't include the game x,y //So we store any x,y sent that we couldn't create at the time, and use those //if we are triggered by the signal. var waitStack = new Array(maxIndex); var waitTop = -1; function finishCreatingBlock(xIdx,yIdx){ if(component.isReady){ if(xIdx == undefined){ //Called without arguments, create a previously stored (xIdx,yIdx) if(waitTop == -1) return;//Don't have a previously stored (xIdx,yIdx) xIdx = waitStack[waitTop] % maxX; yIdx = Math.floor(waitStack[waitTop] / maxX); waitTop -= 1; } dynamicObject = component.createObject(); if(dynamicObject == null){ print("error creating block"); print(component.errorsString()); return false; } dynamicObject.type = Math.floor(Math.random() * 3); dynamicObject.parent = gameCanvas; dynamicObject.x = xIdx*tileSize; dynamicObject.targetX = xIdx*tileSize; dynamicObject.targetY = yIdx*tileSize; dynamicObject.width = tileSize; dynamicObject.height = tileSize; dynamicObject.spawned = true; board[index(xIdx,yIdx)] = dynamicObject; return true; }else if(component.isError){ print("error creating block"); print(component.errorsString()); }else{ //It isn't ready, but we'll be called again when it is. //So store the requested (xIdx,yIdx) for later use waitTop += 1; waitStack[waitTop] = index(xIdx,yIdx); } return false; } function startCreatingBlock(xIdx,yIdx){ if(component!=null){ finishCreatingBlock(xIdx,yIdx); return; } component = createComponent(tileSrc); if(finishCreatingBlock(xIdx,yIdx)) return; component.statusChanged.connect(finishCreatingBlock()); return; } function tweetHighScore(twitterName, twitterPass) { if(twitterName == '' || twitterPass == '') return false;//Can't login like that var scoreStr = "I just played the QML SameGame, and got " + gameCanvas.score + " points on a " + maxX + "x" + maxY + " grid. It took me " + timeStr(timer) + "."; var postData = "status=" + scoreStr; var postman = new XMLHttpRequest(); postman.open("POST", "http://twitter.com/statuses/update.xml", true, twitterName, twitterPass); postman.onreadystatechange = function() { if (postman.readyState == postman.DONE) { dialog.text = "Your score has been tweeted for you."; dialog.opacity = 1; } } postman.send(postData); } function sendHighScore(name) { var postman = new XMLHttpRequest() var postData = "name="+name+"&score="+gameCanvas.score +"&gridSize="+maxX+"x"+maxY +"&time="+Math.floor(timer/1000); postman.open("POST", scoresURL, true); postman.onreadystatechange = function() { if (postman.readyState == postman.DONE) { dialog.text = "Your score has been uploaded."; dialog.opacity = 1; } } postman.send(postData); }