diff --git a/README.md b/README.md index c9da637bc..76d40fae0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +CPEN 321 L1A Group Members: + +Team 06 + +1. Bo Hu +2. Xin Wei (Patrick) Tee +3. William (Will) Tang + + +Original Project Infomration: + Hextris ========== @@ -7,19 +18,6 @@ Contributors: - Noah Moroze (@nmoroze) - Michael Yang (@themichaelyang) -#Conribtions -Please submit pull requests to clay-improvements - -# Releases -#### iOS: https://itunes.apple.com/us/app/hextris/id903769553?mt=8 -![](http://i.imgur.com/KBYZcf5.png) - -#### Android: https://play.google.com/store/apps/details?id=com.hextris.hextris -![](http://i.imgur.com/mxj8yKs.png) - -#### Firefox OS: https://marketplace.firefox.com/app/hextris-app -![](http://i.imgur.com/RhECXPg.png) - ## Press kit http://hextris.github.io/presskit/info.html diff --git a/docs/scenarios.txt b/docs/scenarios.txt new file mode 100644 index 000000000..7d4f84575 --- /dev/null +++ b/docs/scenarios.txt @@ -0,0 +1,107 @@ +Github issue: +Please allow for a more gradual increase of speed +#129 opened on Mar 3, 2015 by EricViala + +1. User Story: +As a player +I want to have the ability to speed up or slow down the game +So that I am able to adjust the game for my skill level + +Acceptance Criteria: + +Scenario 1.1: Game is currently at 40% of its original speed or higher +Given that the game has started + And the player is currently playing the game + And the game is at 40% of its original playing speed or higher +When the player presses the "Down" arrow key +Then the speed of the dropping blocks will be slowed down by 10% + And the rate of generation of blocks will be slowed down by 10% + And the game continues. + +Scenario 1.2: Game is currently at 30% of its original speed (game is very slow) +Given that the game has started + And the player is currently playing the game + And the game is at 30% of its original playing speed +When the player presses the "Down" arrow key +Then the speed of the dropping blocks will remain the same + And the rate of generation of blocks blocks will remain the same + And the game continues. + +Scenario 1.3: Game is currently at 170% of its original speed or lower +Given that the game has started + And the player is currently playing the game + And the game is at 170% of its original playing speed or lower +When the player presses the "UP" arrow key +Then the speed of the dropping blocks will be sped up by 10% + And the rate of generation of blocks will be sped up by 10% + And the game continues. + +Scenario 1.4: Game is currently at 180% of its original speed (game is very fast) +Given that the game has started + And the player is currently playing the game + And the game is at 180% of its original playing speed +When the player presses the "UP" arrow key +Then the speed of the dropping blocks will remain the same + And the rate of generation of blocks will remain the same + And the game continues. + + +===================================================== +Github issue: +Alternate color combination to Red/Green, Color blind people may face issue. enhancement +#74 opened on Aug 17, 2014 by tripples + +2. User Story: +As a colourblind player +I want to have the ability change the appearence of the colours of the block +So that I am able to distinguish the blocks from each other + +Scenario 2.1: User Press Colourblind Toggle Button when in the default colour +Given that the game has started + And the player is currently playing the game +When the player presses the "T" key +Then the colour of the blocks will change to another colour that is friendly for the colourblind + And the game continues. + +Scenario 2.2: User Press Colourblind Toggle Button when in a colourblind mode +Given that the game has started + And the player is currently playing the game + And the blocks are currently in a colourblind colour +When the player presses the "T" key +Then the colour of the blocks will change to anothe set of colours that is friendly for the colourblind, + if the player has not cycled through all the colourblind colours yet, otherwise the colour of the blocks + will revert back to the default colour. + And the game continues. + +===================================================== +Additional Feature: +Block falls immediately onto center hex upon keypress + +3. User Story: +As a player +I want to be able to drop the closest falling block immediately onto the side of the center hex I have rotated to immediately +So that I am able to play the game at a faster pace + +Scenario 3.1: User presses Drop Block Toggle Button when a single block is falling +Given that the game has started + And the player is currently playing the game + And a single-block is currently falling +When the player presses the "space" key +Then the currently falling single-block will fall instantly onto the side of the center hex the player has rotated to + And the game continues. + +Scenario 3.2: User presses Drop Block Toggle Button when a doubly-joint block is falling +Given that the game has started + And the player is currently playing the game + And a doubly-joint block is currently falling +When the player presses the "space" key +Then the whole joint block will fall instantly onto the side of the center hex the player has rotated to as a single piece + And the game continues. + +Scenario 3.3: User presses Drop Block Toggle Button when multiple blocks are falling on the screen +Given taht the game has started + And the player is currently playing the game + And there are 2 blocks both falling onto the center hex on the same lane +Whe the player presses the "space" key +Then only the block closest to the center hex falls instantly while the other falling block remains falling at its original speed + And the game continues. diff --git a/index.html b/index.html index a8287cc56..0d1966ad7 100644 --- a/index.html +++ b/index.html @@ -54,7 +54,7 @@ - + diff --git a/js/Block_test.js b/js/Block_test.js new file mode 100644 index 000000000..0efc23e78 --- /dev/null +++ b/js/Block_test.js @@ -0,0 +1,214 @@ +function Block(fallingLane, color, iter, distFromHex, settled) { + settings = { + os: "other", + platform: "nonmobile", + baseScale: 1, + startDist: 340, + creationDt: 9, + scale: 1, + prevScale: 1, + hexWidth: 65, + baseHexWidth: 87, + baseBlockHeight: 20, + blockHeight: 15, + rows: 8, + speedModifier: 0.65, + creationSpeedModifier: 0.65, + comboTime: 310 + }; + // whether or not a block is rested on the center hex or another block + this.settled = (settled === undefined) ? 0 : 1; + this.height = settings.blockHeight; + //the lane which the block was shot from + this.fallingLane = fallingLane; + + this.checked=0; + //the angle at which the block falls + this.angle = 90 - (30 + 60 * fallingLane); + //for calculating the rotation of blocks attached to the center hex + this.angularVelocity = 0; + this.targetAngle = this.angle; + this.color = color; + //blocks that are slated to be deleted after a valid score has happened + this.deleted = 0; + //blocks slated to be removed from falling and added to the hex + this.removed = 0; + //value for the opacity of the white blcok drawn over falling block to give it the glow as it attaches to the hex + this.tint = 0; + //value used for deletion animation + this.opacity = 1; + //boolean for when the block is expanding + this.initializing = 1; + //speed of block + this.iter = iter; + //number of iterations before starting to drop + this.initLen = settings.creationDt; + //side which block is attached too + this.attachedLane = 0; + //distance from center hex + this.distFromHex = distFromHex || settings.startDist * settings.scale ; + + this.incrementOpacity = function() { + if (this.deleted) { + //add shakes + if (this.opacity >= 0.925) { + var tLane = this.attachedLane - MainHex.position; + tLane = MainHex.sides - tLane; + while (tLane < 0) { + tLane += MainHex.sides; + } + + tLane %= MainHex.sides; + MainHex.shakes.push({lane:tLane, magnitude:3 * (window.devicePixelRatio ? window.devicePixelRatio : 1) * (settings.scale)}); + } + //fade out the opacity + this.opacity = this.opacity - 0.075 * MainHex.dt; + if (this.opacity <= 0) { + //slate for final deletion + this.opacity = 0; + this.deleted = 2; + if (gameState == 1 || gameState==0) { + localStorage.setItem("saveState", exportSaveState()); + } + } + } + }; + + this.getIndex = function (){ + //get the index of the block in its stack + var parentArr = MainHex.blocks[this.attachedLane]; + for (var i = 0; i < parentArr.length; i++) { + if (parentArr[i] == this) { + return i; + } + } + }; + + this.draw = function(attached, index) { + this.height = settings.blockHeight; + if (Math.abs(settings.scale - settings.prevScale) > 0.000000001) { + this.distFromHex *= (settings.scale/settings.prevScale); + } + + this.incrementOpacity(); + if(attached === undefined) + attached = false; + + if(this.angle > this.targetAngle) { + this.angularVelocity -= angularVelocityConst * MainHex.dt; + } + else if(this.angle < this.targetAngle) { + this.angularVelocity += angularVelocityConst * MainHex.dt; + } + + if (Math.abs(this.angle - this.targetAngle + this.angularVelocity) <= Math.abs(this.angularVelocity)) { //do better soon + this.angle = this.targetAngle; + this.angularVelocity = 0; + } + else { + this.angle += this.angularVelocity; + } + + this.width = 2 * this.distFromHex / Math.sqrt(3); + this.widthWide = 2 * (this.distFromHex + this.height) / Math.sqrt(3); + //this.widthWide = this.width + this.height + 3; + var p1; + var p2; + var p3; + var p4; + if (this.initializing) { + var rat = ((MainHex.ct - this.ict)/this.initLen); + if (rat > 1) { + rat = 1; + } + p1 = rotatePoint((-this.width / 2) * rat, this.height / 2, this.angle); + p2 = rotatePoint((this.width / 2) * rat, this.height / 2, this.angle); + p3 = rotatePoint((this.widthWide / 2) * rat, -this.height / 2, this.angle); + p4 = rotatePoint((-this.widthWide / 2) * rat, -this.height / 2, this.angle); + if ((MainHex.ct - this.ict) >= this.initLen) { + this.initializing = 0; + } + } else { + p1 = rotatePoint(-this.width / 2, this.height / 2, this.angle); + p2 = rotatePoint(this.width / 2, this.height / 2, this.angle); + p3 = rotatePoint(this.widthWide / 2, -this.height / 2, this.angle); + p4 = rotatePoint(-this.widthWide / 2, -this.height / 2, this.angle); + } + + if (this.deleted) { + ctx.fillStyle = "#FFF"; + } else if (gameState === 0) { + if (this.color.charAt(0) == 'r') { + ctx.fillStyle = rgbColorsToTintedColors[this.color]; + } + else { + ctx.fillStyle = hexColorsToTintedColors[this.color]; + } + } + else { + ctx.fillStyle = this.color; + } + + ctx.globalAlpha = this.opacity; + var baseX = trueCanvas.width / 2 + Math.sin((this.angle) * (Math.PI / 180)) * (this.distFromHex + this.height / 2) + gdx; + var baseY = trueCanvas.height / 2 - Math.cos((this.angle) * (Math.PI / 180)) * (this.distFromHex + this.height / 2) + gdy; + ctx.beginPath(); + ctx.moveTo(baseX + p1.x, baseY + p1.y); + ctx.lineTo(baseX + p2.x, baseY + p2.y); + ctx.lineTo(baseX + p3.x, baseY + p3.y); + ctx.lineTo(baseX + p4.x, baseY + p4.y); + //ctx.lineTo(baseX + p1.x, baseY + p1.y); + ctx.closePath(); + ctx.fill(); + + if (this.tint) { + if (this.opacity < 1) { + if (gameState == 1 || gameState==0) { + localStorage.setItem("saveState", exportSaveState()); + } + + this.iter = 2.25; + this.tint = 0; + } + + ctx.fillStyle = "#FFF"; + ctx.globalAlpha = this.tint; + ctx.beginPath(); + ctx.moveTo(baseX + p1.x, baseY + p1.y); + ctx.lineTo(baseX + p2.x, baseY + p2.y); + ctx.lineTo(baseX + p3.x, baseY + p3.y); + ctx.lineTo(baseX + p4.x, baseY + p4.y); + ctx.lineTo(baseX + p1.x, baseY + p1.y); + ctx.closePath(); + ctx.fill(); + this.tint -= 0.02 * MainHex.dt; + if (this.tint < 0) { + this.tint = 0; + } + } + + ctx.globalAlpha = 1; + }; +} + +function findCenterOfBlocks(arr) { + var avgDFH = 0; + var avgAngle = 0; + for (var i = 0; i < arr.length; i++) { + avgDFH += arr[i].distFromHex; + var ang = arr[i].angle; + while (ang < 0) { + ang += 360; + } + + avgAngle += ang % 360; + } + + avgDFH /= arr.length; + avgAngle /= arr.length; + + return { + x:trueCanvas.width/2 + Math.cos(avgAngle * (Math.PI / 180)) * avgDFH, + y:trueCanvas.height/2 + Math.sin(avgAngle * (Math.PI / 180)) * avgDFH + }; +} diff --git a/js/Hex.js b/js/Hex.js index 64f917b0c..3f6fc7e4b 100644 --- a/js/Hex.js +++ b/js/Hex.js @@ -20,7 +20,7 @@ function Hex(sideLength) { this.lastColorScored = "#000"; this.comboTime = 1; this.texts = []; - this.lastRotate = Date.now(); + this.lastRotate = Date.now(); for (var i = 0; i < this.sides; i++) { this.blocks.push([]); } @@ -57,6 +57,8 @@ function Hex(sideLength) { }; this.doesBlockCollide = function(block, position, tArr) { + + //block has rested on either the center of hex or on another block. Collision happened if (block.settled) { return; } @@ -64,38 +66,57 @@ function Hex(sideLength) { if (position !== undefined) { arr = tArr; if (position <= 0) { + //current block has hit the center hex + if (block.distFromHex - block.iter * this.dt * settings.scale - (this.sideLength / 2) * Math.sqrt(3) <= 0) { block.distFromHex = (this.sideLength / 2) * Math.sqrt(3); block.settled = 1; block.checked = 1; - } else { + } + + //current block is still falling, increment iterations + else { block.settled = 0; block.iter = 1.5 + (waveone.difficulty/15) * 3; } - } else { + } + + else { + + //current block is above an existing settled block and hits the existing block + if (arr[position - 1].settled && block.distFromHex - block.iter * this.dt * settings.scale - arr[position - 1].distFromHex - arr[position - 1].height <= 0) { block.distFromHex = arr[position - 1].distFromHex + arr[position - 1].height; block.settled = 1; block.checked = 1; } + + //either the lower block has not settled yet OR current block has not settled (still falling) else { block.settled = 0; block.iter = 1.5 + (waveone.difficulty/15) * 3; } } - } else { + } + + //block is yet created (position is not defined) + else { var lane = this.sides - block.fallingLane;// -this.position; lane += this.position; lane = (lane+this.sides) % this.sides; var arr = this.blocks[lane]; + // + if (arr.length > 0) { if (block.distFromHex + block.iter * this.dt * settings.scale - arr[arr.length - 1].distFromHex - arr[arr.length - 1].height <= 0) { block.distFromHex = arr[arr.length - 1].distFromHex + arr[arr.length - 1].height; this.addBlock(block); } - } else { + } + + else { if (block.distFromHex + block.iter * this.dt * settings.scale - (this.sideLength / 2) * Math.sqrt(3) <= 0) { block.distFromHex = (this.sideLength / 2) * Math.sqrt(3); this.addBlock(block); @@ -105,7 +126,7 @@ function Hex(sideLength) { }; this.rotate = function(steps) { - if(Date.now()-this.lastRotate<75 && !(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) ) return; + if(Date.now()-this.lastRotate<75 && !(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) ) return; if (!(gameState === 1 || gameState === 0)) return; this.position += steps; if (!history[this.ct]) { @@ -131,7 +152,7 @@ function Hex(sideLength) { }); this.targetAngle = this.targetAngle - steps * 60; - this.lastRotate = Date.now(); + this.lastRotate = Date.now(); }; this.draw = function() { @@ -160,7 +181,7 @@ function Hex(sideLength) { else { this.angle += this.angularVelocity; } - + drawPolygon(this.x + gdx, this.y + gdy + this.dy, this.sides, this.sideLength, this.angle,arrayToColor(this.fillColor) , 0, 'rgba(0,0,0,0)'); }; } @@ -168,3 +189,4 @@ function Hex(sideLength) { function arrayToColor(arr){ return 'rgb(' + arr[0]+ ','+arr[1]+','+arr[2]+')'; } + diff --git a/js/Hex_test.js b/js/Hex_test.js new file mode 100644 index 000000000..fef2aadfd --- /dev/null +++ b/js/Hex_test.js @@ -0,0 +1,157 @@ +function Hex(sideLength) { + window.settings = { + os: "other", + platform: "nonmobile", + baseScale: 1, + startDist: 340, + creationDt: 9, + scale: 1, + prevScale: 1, + hexWidth: 65, + baseHexWidth: 87, + baseBlockHeight: 20, + blockHeight: 15, + rows: 8, + speedModifier: 0.65, + creationSpeedModifier: 0.65, + comboTime: 310 + }; + this.playThrough = 0; + this.fillColor = [44,62,80]; + this.tempColor = [44,62,80]; + this.angularVelocity = 0; + this.position = 0; + this.dy = 0; + this.dt = 1; + this.sides = 6; + this.blocks = []; + this.angle = 180 / this.sides; + this.targetAngle = this.angle; + this.shakes = []; + this.sideLength = sideLength; + this.strokeColor = 'blue'; + this.ct = 0; + this.lastCombo = this.ct - window.settings.comboTime; + this.lastColorScored = "#000"; + this.comboTime = 1; + this.texts = []; + this.lastRotate = Date.now(); + for (var i = 0; i < this.sides; i++) { + this.blocks.push([]); + } + + this.shake = function(obj) { //lane as in particle lane + var angle = 30 + obj.lane * 60; + angle *= Math.PI / 180; + var dx = Math.cos(angle) * obj.magnitude; + var dy = Math.sin(angle) * obj.magnitude; + gdx -= dx; + gdy += dy; + obj.magnitude /= 2 * this.dt; + if (obj.magnitude < 1) { + for (var i = 0; i < this.shakes.length; i++) { + if (this.shakes[i] == obj) { + this.shakes.splice(i, 1); + } + } + } + }; + + this.addBlock = function(block) { + if (!(gameState == 1 || gameState === 0)) return; + block.settled = 1; + block.tint = 0.6; + var lane = this.sides - block.fallingLane;// -this.position; + this.shakes.push({lane:block.fallingLane, magnitude:4.5 * (window.devicePixelRatio ? window.devicePixelRatio : 1) * (window.settings.scale)}); + lane += this.position; + lane = (lane + this.sides) % this.sides; + block.distFromHex = MainHex.sideLength / 2 * Math.sqrt(3) + block.height * this.blocks[lane].length; + this.blocks[lane].push(block); + block.attachedLane = lane; + block.checked = 1; + }; + + this.doesBlockCollide = function(block, position, tArr) { + if (block.settled) { + return; + } + + if (position !== undefined) { + arr = tArr; + if (position <= 0) { + if (block.distFromHex - block.iter * this.dt * window.settings.scale - (this.sideLength / 2) * Math.sqrt(3) <= 0) { + block.distFromHex = (this.sideLength / 2) * Math.sqrt(3); + block.settled = 1; + block.checked = 1; + } else { + block.settled = 0; + block.iter = 1.5 + (waveone.difficulty/15) * 3; + } + } else { + if (arr[position - 1].settled && block.distFromHex - block.iter * this.dt * window.settings.scale - arr[position - 1].distFromHex - arr[position - 1].height <= 0) { + block.distFromHex = arr[position - 1].distFromHex + arr[position - 1].height; + block.settled = 1; + block.checked = 1; + } + else { + block.settled = 0; + block.iter = 1.5 + (waveone.difficulty/15) * 3; + } + } + } else { + var lane = this.sides - block.fallingLane;// -this.position; + lane += this.position; + + lane = (lane+this.sides) % this.sides; + var arr = this.blocks[lane]; + + if (arr.length > 0) { + if (block.distFromHex + block.iter * this.dt * window.settings.scale - arr[arr.length - 1].distFromHex - arr[arr.length - 1].height <= 0) { + block.distFromHex = arr[arr.length - 1].distFromHex + arr[arr.length - 1].height; + this.addBlock(block); + } + } else { + if (block.distFromHex + block.iter * this.dt * window.settings.scale - (this.sideLength / 2) * Math.sqrt(3) <= 0) { + block.distFromHex = (this.sideLength / 2) * Math.sqrt(3); + this.addBlock(block); + } + } + } + }; + + this.rotate = function(steps) { + if(Date.now()-this.lastRotate<75 && !(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) ) return; + if (!(gameState === 1 || gameState === 0)) return; + this.position += steps; + if (!history[this.ct]) { + history[this.ct] = {}; + } + + if (!history[this.ct].rotate) { + history[this.ct].rotate = steps; + } + else { + history[this.ct].rotate += steps; + } + + while (this.position < 0) { + this.position += 6; + } + + this.position = this.position % this.sides; + this.blocks.forEach(function(blocks) { + blocks.forEach(function(block) { + block.targetAngle = block.targetAngle - steps * 60; + }); + }); + + this.targetAngle = this.targetAngle - steps * 60; + this.lastRotate = Date.now(); + }; + +} + +function arrayToColor(arr){ + return 'rgb(' + arr[0]+ ','+arr[1]+','+arr[2]+')'; +} + diff --git a/js/initialization.js b/js/initialization.js index 64d0e6680..e54865bd8 100644 --- a/js/initialization.js +++ b/js/initialization.js @@ -2,10 +2,27 @@ $(document).ready(function() { initialize(); }); function initialize(a) { + // color blind mode variables + // max amount of color blind modes + window.currcb = 0; + window.prevcb = 0; + + window.cbcolors = [ + ["#e74c3c", "#f1c40f", "#3498db", "#2ecc71"], + ["#8e44ad", "#f1c41f", "#3499db", "#d35400"], + ["#000000", "#445555", "#c0c0c0", "#ffffff"] + ] + + // variables to adjust speed of game + window.speedscale = 1; + window.oldspeedscale = 1; + window.rush = 1; window.lastTime = Date.now(); window.iframHasLoaded = false; - window.colors = ["#e74c3c", "#f1c40f", "#3498db", "#2ecc71"]; + + window.colors = window.cbcolors[0]; + window.hexColorsToTintedColors = { "#e74c3c": "rgb(241,163,155)", "#f1c40f": "rgb(246,223,133)", diff --git a/js/initialization_test.js b/js/initialization_test.js new file mode 100644 index 000000000..6eb2e0e91 --- /dev/null +++ b/js/initialization_test.js @@ -0,0 +1,102 @@ +/* This code in this function is identical to that of initialization.js with the exception: + - UI methods are stripped as this is to test the colour change functionality on + the backbone of the game, ensuring that the blocks change colour correctly. + */ +function initialize(a) { + // color blind mode variables + // max amount of color blind modes + window.currcb = 0; + window.prevcb = 0; + + window.cbcolors = [ + ["#e74c3c", "#f1c40f", "#3498db", "#2ecc71"], + ["#8e44ad", "#f1c41f", "#3499db", "#d35400"], + ["#000000", "#445555", "#c0c0c0", "#ffffff"] + ] + + // variables to adjust speed of game + window.speedscale = 1; + window.oldspeedscale = 1; + + window.rush = 1; + window.lastTime = Date.now(); + window.iframHasLoaded = false; + + window.colors = window.cbcolors[0]; + + window.hexColorsToTintedColors = { + "#e74c3c": "rgb(241,163,155)", + "#f1c40f": "rgb(246,223,133)", + "#3498db": "rgb(151,201,235)", + "#2ecc71": "rgb(150,227,183)" + }; + + window.rgbToHex = { + "rgb(231,76,60)": "#e74c3c", + "rgb(241,196,15)": "#f1c40f", + "rgb(52,152,219)": "#3498db", + "rgb(46,204,113)": "#2ecc71" + }; + + window.rgbColorsToTintedColors = { + "rgb(231,76,60)": "rgb(241,163,155)", + "rgb(241,196,15)": "rgb(246,223,133)", + "rgb(52,152,219)": "rgb(151,201,235)", + "rgb(46,204,113)": "rgb(150,227,183)" + }; + + window.hexagonBackgroundColor = 'rgb(236, 240, 241)'; + window.hexagonBackgroundColorClear = 'rgba(236, 240, 241, 0.5)'; + window.centerBlue = 'rgb(44,62,80)'; + window.angularVelocityConst = 4; + window.scoreOpacity = 0; + window.textOpacity = 0; + window.prevGameState = undefined; + window.op = 0; + window.saveState = localStorage.getItem("saveState") || "{}"; + if (saveState !== "{}") { + op = 1; + } + + + window.framerate = 60; + window.history = {}; + window.score = 0; + window.scoreAdditionCoeff = 1; + window.prevScore = 0; + window.numHighScores = 3; + + highscores = []; + + window.blocks = []; + window.MainHex; + window.gdx = 0; + window.gdy = 0; + window.devMode = 0; + window.lastGen = undefined; + window.prevTimeScored = undefined; + window.nextGen = undefined; + window.spawnLane = 0; + window.importing = 0; + window.importedHistory = undefined; + window.startTime = undefined; + window.gameState; + + window.settings = { + os: "other", + platform: "nonmobile", + baseScale: 1, + startDist: 340, + creationDt: 9, + scale: 1, + prevScale: 1, + hexWidth: 65, + baseHexWidth: 87, + baseBlockHeight: 20, + blockHeight: 15, + rows: 8, + speedModifier: 0.65, + creationSpeedModifier: 0.65, + comboTime: 310 + }; +} \ No newline at end of file diff --git a/js/input.js b/js/input.js index c559fb003..f153e0e65 100644 --- a/js/input.js +++ b/js/input.js @@ -41,7 +41,7 @@ function addKeyListeners() { keypress.register_combo({ keys: "space", - on_keydown: function(){pause();} + on_keydown: function(){toggleDrop(window.blocks, MainHex);} }); keypress.register_combo({ @@ -51,6 +51,30 @@ function addKeyListeners() { } }); + // speed up key + keypress.register_combo({ + keys: "up", + on_keydown: function() { + togglespeed(0.1, window.blocks, MainHex); + } + }); + + // slow down key + keypress.register_combo({ + keys: "down", + on_keydown: function() { + togglespeed(-0.1, window.blocks, MainHex); + } + }); + + // colour blind toggle key + keypress.register_combo({ + keys: "t", + on_keydown: function(){ + togglecolor(window.blocks, MainHex); + } + }); + keypress.register_combo({ keys: "enter", on_keydown: function() { @@ -79,32 +103,6 @@ function addKeyListeners() { return false; }); - $("#colorBlindBtn").on('touchstart mousedown', function() { - window.colors = ["#8e44ad", "#f1c40f", "#3498db", "#d35400"]; - - window.hexColorsToTintedColors = { - "#8e44ad": "rgb(229,152,102)", - "#f1c40f": "rgb(246,223,133)", - "#3498db": "rgb(151,201,235)", - "#d35400": "rgb(210,180,222)" - }; - - window.rgbToHex = { - "rgb(142,68,173)": "#8e44ad", - "rgb(241,196,15)": "#f1c40f", - "rgb(52,152,219)": "#3498db", - "rgb(211,84,0)": "#d35400" - }; - - window.rgbColorsToTintedColors = { - "rgb(142,68,173)": "rgb(229,152,102)", - "rgb(241,196,15)": "rgb(246,223,133)", - "rgb(52,152,219)": "rgb(151,201,235)", - "rgb(46,204,113)": "rgb(210,180,222)" - }; - }); - - if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { $("#restart").on('touchstart', function() { init(); @@ -189,3 +187,100 @@ function handleClickTap(x,y) { } } +function togglecolor(blocks, hex){ + // compute the current and next color + window.prevcb = window.currcb; + window.currcb = (window.prevcb + 1) % window.cbcolors.length; + + // set the current window color to the one we need + window.colors = window.cbcolors[currcb]; + + // obtain all the current falling blocks + for (var i = 0; i < blocks.length; i++){ + + // find the colour of the block and change accordingly + for (var j = 0; j < window.cbcolors[window.prevcb].length; j++){ + if (blocks[i].color == window.cbcolors[window.prevcb][j]){ + blocks[i].color = window.cbcolors[window.currcb][j] + } + } + } + + // obtain all colours from the hex and change them + for(var k = 0; k < hex.blocks.length; k++) { + for (var l = 0; l < hex.blocks[k].length; l++) { + for (var m = 0; m < window.cbcolors[window.prevcb].length; m++){ + // find the colour of the block and change accordingly + if (hex.blocks[k][l].color == window.cbcolors[window.prevcb][m]){ + hex.blocks[k][l].color = window.cbcolors[window.currcb][m]; + } + } + } + } +} + +function togglespeed(increment, blocks, hex) { + + // check if we are incrementing or decrementing the game speed + if (increment < 0) { + + // if incrementing, adjust the speed accordingly + if (window.speedscale >= 0.3) { + window.speedscale -= 0.1; + } + } + else { // increment is positive + // if decrementing, adjust the speed accordingly + if (window.speedscale < 1.4) { + window.speedscale += 0.1; + } + } + + // slow down the generation of the wave , if necessary. + if (window.speedscale >= 1){ + waveone.nextGen = waveone.nextGen * (1 / window.speedscale) / (1 / window.oldspeedscale); + } + + if (waveone.nextGen > 3500){ + waveone.nextGen = 3500; + } + + var iterfactor = window.speedscale / window.oldspeedscale; + + // slow down speed of falling blocks + for (var k = 0; k < blocks.length; k++){ + blocks[k].iter = blocks[k].iter * iterfactor; + } + + // obtain all speeds from the hex and change thems + for(var k = 0; k < hex.blocks.length; k++) { + for (var l = 0; l < hex.blocks[k].length; l++) { + hex.blocks[k][l].iter = hex.blocks[k][l].iter*iterfactor; + } + } + + // store the old value of so speed can be adjusted in future + window.oldspeedscale = window.speedscale; +} + +// When called, the currently falling blocks will immediately fall towards the center of hex +function toggleDrop(blocks, hex){ + + // tolerance for comparing doubles + var tolearnce = 0.01; + + // extract only the closest block to the + var minDist = 999999; + for (var i = 0; i < blocks.length; i++){ + if (blocks[i].distFromHex < minDist){ + minDist = blocks[i].distFromHex; + } + } + + //obtain current falling blocks; blocks[0] for a single falling block, [1] for a joint falling block... + for (var i = 0; i < blocks.length; i++){ + if (blocks[i].distFromHex >= (minDist - tolearnce) && blocks[i].distFromHex <= (minDist + tolearnce)){ + hex.addBlock(blocks[i]); + } + } +} diff --git a/js/main.js b/js/main.js index afc8515d6..1a227c908 100644 --- a/js/main.js +++ b/js/main.js @@ -184,6 +184,10 @@ function init(b) { function addNewBlock(blocklane, color, iter, distFromHex, settled) { //last two are optional parameters iter *= settings.speedModifier; + + // PRJ: this line will scale the speed of the block by its respective amount specified in scale + iter *= window.speedscale; + if (!history[MainHex.ct]) { history[MainHex.ct] = {}; } diff --git a/js/wavegen.js b/js/wavegen.js index a4e85ff77..57c3224a9 100644 --- a/js/wavegen.js +++ b/js/wavegen.js @@ -1,17 +1,40 @@ function blockDestroyed() { - if (waveone.nextGen > 1350) { + + // PRJ: all * window.speedscale + + var wavescalespeed; + if (window.speedscale <= 1.3){ + wavescalespeed = window.speedscale; + } + else { + wavescalespeed = 1; + } + + if (waveone.nextGen*wavescalespeed > 1350) { waveone.nextGen -= 30 * settings.creationSpeedModifier; - } else if (waveone.nextGen > 600) { + } else if (waveone.nextGen*wavescalespeed > 600) { waveone.nextGen -= 8 * settings.creationSpeedModifier; } else { waveone.nextGen = 600; } + // PRJ: this function scales down nextGen + if (wavescalespeed > 0.001) { + waveone.nextGen = waveone.nextGen / wavescalespeed; + } + if (waveone.difficulty < 35) { waveone.difficulty += 0.085 * settings.speedModifier; } else { waveone.difficulty = 35; } + + if (waveone.nextGen > 3500){ + waveone.nextGen = 3500; + } + else if (waveone.nextGen < 400){ + waveone.nextGen = 400; + } } function waveGen(hex) { @@ -29,9 +52,14 @@ function waveGen(hex) { this.dt = (settings.platform == 'mobile' ? 14 : 16.6667) * MainHex.ct; this.computeDifficulty(); if ((this.dt - this.lastGen) * settings.creationSpeedModifier > this.nextGen) { - if (this.nextGen > 600) { + + // PRJ: * window.speedscale + if (this.nextGen*window.speedscale > 600) { this.nextGen -= 11 * ((this.nextGen / 1300)) * settings.creationSpeedModifier; } + + // PRJ + this.nextGen = this.nextGen/window.speedscale; } }; diff --git a/qunit.htm b/qunit.htm new file mode 100644 index 000000000..259d12f58 --- /dev/null +++ b/qunit.htm @@ -0,0 +1,299 @@ + + + + + Hetrix Acceptance Tests + + + + + + + + + + + + + +
+
+ + \ No newline at end of file diff --git a/team06_readme.txt b/team06_readme.txt new file mode 100644 index 000000000..8dec5a28d --- /dev/null +++ b/team06_readme.txt @@ -0,0 +1,19 @@ +Team 06 Open-source Project + +Project Objective: +The team wants to resolve the issue of adding red/green colorblind-friendly colors and the issue of allowing more game-speed control. +The team also wants to add the instant block-drop feature as inspired by the original Tetris game. + +List of Implementations: +Implementation 1: toggleColor function + files: js/input.js, js/main.js + +Implementation 2: toggleSpeed function + files: js/input.js, js/wavegen.js + +Implementation 3: toggleDrop function + files: js/input.js + +Unit Tests: using qUnit Libary + files: qunit.htm, js/Hex_test.js, js/Block_test.js, js/initialization_test.js + diff --git a/vendor/blanket.min.js b/vendor/blanket.min.js new file mode 100644 index 000000000..c7d6ec526 --- /dev/null +++ b/vendor/blanket.min.js @@ -0,0 +1,6 @@ +/*! blanket - v1.2.0 */ +"undefined"!=typeof QUnit&&(QUnit.config.autostart=!1),function(a){}(null),function(a){window.isArguments=a.exports}({exports:{}}),function(a){window.forEach=a.exports}({exports:{}}),function(a){window.isArray=a.exports}({exports:{}}),function(a,b){window.objectKeys=b.exports}(function(){return isArguments},{exports:{}}),/*! + * falafel (c) James Halliday / MIT License + * https://github.com/substack/node-falafel + */ +function(a,b){function c(a,b,c){function d(b){c[a.range[0]]=b;for(var d=a.range[0]+1;dparseInt(b,10)}).forEach(function(b){e+=f+"['"+a+"']["+b+"]=0;\n"}),c&&_blanket._branchingArraySetup.sort(function(a,b){return a.line>b.line}).sort(function(a,b){return a.column>b.column}).forEach(function(b){b.file===a&&(e+="if (typeof "+f+"['"+a+"'].branchData["+b.line+"] === 'undefined'){\n",e+=f+"['"+a+"'].branchData["+b.line+"]=[];\n",e+="}",e+=f+"['"+a+"'].branchData["+b.line+"]["+b.column+"] = [];\n",e+=f+"['"+a+"'].branchData["+b.line+"]["+b.column+"].consequent = "+JSON.stringify(b.consequent)+";\n",e+=f+"['"+a+"'].branchData["+b.line+"]["+b.column+"].alternate = "+JSON.stringify(b.alternate)+";\n")}),e+="}"},_blockifyIf:function(a){if(c.indexOf(a.type)>-1){var b=a.consequent||a.body,d=a.alternate;d&&"BlockStatement"!==d.type&&d.update("{\n"+d.source()+"}\n"),b&&"BlockStatement"!==b.type&&b.update("{\n"+b.source()+"}\n")}},_trackBranch:function(a,b){var c=a.loc.start.line,d=a.loc.start.column;_blanket._branchingArraySetup.push({line:c,column:d,file:b,consequent:a.consequent.loc,alternate:a.alternate.loc});var e="_$branchFcn('"+b+"',"+c+","+d+","+a.test.source()+")?"+a.consequent.source()+":"+a.alternate.source();a.update(e)},_addTracking:function(a){var c=_blanket.getCovVar();return function(d){if(_blanket._blockifyIf(d),b.indexOf(d.type)>-1&&"LabeledStatement"!==d.parent.type){if(_blanket._checkDefs(d,a),"VariableDeclaration"===d.type&&("ForStatement"===d.parent.type||"ForInStatement"===d.parent.type))return;if(!d.loc||!d.loc.start)throw new Error("The instrumenter encountered a node with no location: "+Object.keys(d));d.update(c+"['"+a+"']["+d.loc.start.line+"]++;\n"+d.source()),_blanket._trackingArraySetup.push(d.loc.start.line)}else _blanket.options("branchTracking")&&"ConditionalExpression"===d.type?_blanket._trackBranch(d,a):"Literal"===d.type&&"use strict"===d.value&&d.parent&&"ExpressionStatement"===d.parent.type&&d.parent.parent&&"Program"===d.parent.parent.type&&(_blanket._useStrictMode=!0)}},_checkDefs:function(a,b){if(inBrowser){if("VariableDeclaration"===a.type&&a.declarations&&a.declarations.forEach(function(c){if("window"===c.id.name)throw new Error("Instrumentation error, you cannot redefine the 'window' variable in "+b+":"+a.loc.start.line)}),"FunctionDeclaration"===a.type&&a.params&&a.params.forEach(function(c){if("window"===c.name)throw new Error("Instrumentation error, you cannot redefine the 'window' variable in "+b+":"+a.loc.start.line)}),"ExpressionStatement"===a.type&&a.expression&&a.expression.left&&a.expression.left.object&&a.expression.left.property&&a.expression.left.object.name+"."+a.expression.left.property.name===_blanket.getCovVar())throw new Error("Instrumentation error, you cannot redefine the coverage variable in "+b+":"+a.loc.start.line)}else if("ExpressionStatement"===a.type&&a.expression&&a.expression.left&&!a.expression.left.object&&!a.expression.left.property&&a.expression.left.name===_blanket.getCovVar())throw new Error("Instrumentation error, you cannot redefine the coverage variable in "+b+":"+a.loc.start.line)},setupCoverage:function(){e.instrumentation="blanket",e.stats={suites:0,tests:0,passes:0,pending:0,failures:0,start:new Date}},_checkIfSetup:function(){if(!e.stats)throw new Error("You must call blanket.setupCoverage() first.")},onTestStart:function(){_blanket.options("debug")&&console.log("BLANKET-Test event started"),this._checkIfSetup(),e.stats.tests++,e.stats.pending++},onTestDone:function(a,b){this._checkIfSetup(),b===a?e.stats.passes++:e.stats.failures++,e.stats.pending--},onModuleStart:function(){this._checkIfSetup(),e.stats.suites++},onTestsDone:function(){_blanket.options("debug")&&console.log("BLANKET-Test event done"),this._checkIfSetup(),e.stats.end=new Date,inBrowser?this.report(e):(_blanket.options("branchTracking")||delete(inBrowser?window:global)[_blanket.getCovVar()].branchFcn,this.options("reporter").call(this,e))}},_blanket}(),function(a){var b=a.options;a.extend({outstandingRequireFiles:[],options:function(c,d){var e={};if("string"!=typeof c)b(c),e=c;else{if("undefined"==typeof d)return b(c);b(c,d),e[c]=d}e.adapter&&a._loadFile(e.adapter),e.loader&&a._loadFile(e.loader)},requiringFile:function(b,c){"undefined"==typeof b?a.outstandingRequireFiles=[]:"undefined"==typeof c?a.outstandingRequireFiles.push(b):a.outstandingRequireFiles.splice(a.outstandingRequireFiles.indexOf(b),1)},requireFilesLoaded:function(){return 0===a.outstandingRequireFiles.length},showManualLoader:function(){if(!document.getElementById("blanketLoaderDialog")){var a="
";a+=" 
",a+="
",a+="
",a+="Error: Blanket.js encountered a cross origin request error while instrumenting the source files. ",a+="

This is likely caused by the source files being referenced locally (using the file:// protocol). ",a+="

Some solutions include starting Chrome with special flags, running a server locally, or using a browser without these CORS restrictions (Safari).",a+="
","undefined"!=typeof FileReader&&(a+="
Or, try the experimental loader. When prompted, simply click on the directory containing all the source files you want covered.",a+="Start Loader",a+=""),a+="
Close",a+="
",a+="
";var b=".blanketDialogWrapper {";b+="display:block;",b+="position:fixed;",b+="z-index:40001; }",b+=".blanketDialogOverlay {",b+="position:fixed;",b+="width:100%;",b+="height:100%;",b+="background-color:black;",b+="opacity:.5; ",b+="-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; ",b+="filter:alpha(opacity=50); ",b+="z-index:40001; }",b+=".blanketDialogVerticalOffset { ",b+="position:fixed;",b+="top:30%;",b+="width:100%;",b+="z-index:40002; }",b+=".blanketDialogBox { ",b+="width:405px; ",b+="position:relative;",b+="margin:0 auto;",b+="background-color:white;",b+="padding:10px;",b+="border:1px solid black; }";var c=document.createElement("style");c.innerHTML=b,document.head.appendChild(c);var d=document.createElement("div");d.id="blanketLoaderDialog",d.className="blanketDialogWrapper",d.innerHTML=a,document.body.insertBefore(d,document.body.firstChild)}},manualFileLoader:function(a){function b(a){var b=new FileReader;b.onload=g,b.readAsText(a)}var c=Array.prototype.slice;a=c.call(a).filter(function(a){return""!==a.type});var d=a.length-1,e=0,f={};sessionStorage.blanketSessionLoader&&(f=JSON.parse(sessionStorage.blanketSessionLoader));var g=function(c){var g=c.currentTarget.result,h=a[e],i=h.webkitRelativePath&&""!==h.webkitRelativePath?h.webkitRelativePath:h.name;f[i]=g,e++,e===d?(sessionStorage.setItem("blanketSessionLoader",JSON.stringify(f)),document.location.reload()):b(a[e])};b(a[e])},_loadFile:function(b){if("undefined"!=typeof b){var c=new XMLHttpRequest;c.open("GET",b,!1),c.send(),a._addScript(c.responseText)}},_addScript:function(a){var b=document.createElement("script");b.type="text/javascript",b.text=a,(document.body||document.getElementsByTagName("head")[0]).appendChild(b)},hasAdapter:function(b){return null!==a.options("adapter")},report:function(b){document.getElementById("blanketLoaderDialog")||(a.blanketSession=null),b.files=window._$blanket;blanket.options("commonJS")?blanket._commonjs.require:window.require;if(!b.files||!Object.keys(b.files).length)return void(a.options("debug")&&console.log("BLANKET-Reporting No files were instrumented."));if("undefined"!=typeof b.files.branchFcn&&delete b.files.branchFcn,"string"==typeof a.options("reporter"))a._loadFile(a.options("reporter")),a.customReporter(b,a.options("reporter_options"));else if("function"==typeof a.options("reporter"))a.options("reporter")(b,a.options("reporter_options"));else{if("function"!=typeof a.defaultReporter)throw new Error("no reporter defined.");a.defaultReporter(b,a.options("reporter_options"))}},_bindStartTestRunner:function(a,b){a?a(b):"complete"===document.readyState?b():window.addEventListener("load",b,!1)},_loadSourceFiles:function(b){blanket.options("commonJS")?blanket._commonjs.require:window.require;a.options("debug")&&console.log("BLANKET-Collecting page scripts");var c=a.utils.collectPageScripts();if(0===c.length)b();else{sessionStorage.blanketSessionLoader&&(a.blanketSession=JSON.parse(sessionStorage.blanketSessionLoader)),c.forEach(function(b,c){a.utils.cache[b]={loaded:!1}});var d=-1;a.utils.loadAll(function(a){return a?"undefined"!=typeof c[d+1]:(d++,d>=c.length?null:c[d])},b)}},beforeStartTestRunner:function(b){b=b||{},b.checkRequirejs="undefined"==typeof b.checkRequirejs?!0:b.checkRequirejs,b.callback=b.callback||function(){},b.coverage="undefined"==typeof b.coverage?!0:b.coverage,b.coverage?a._bindStartTestRunner(b.bindEvent,function(){a._loadSourceFiles(function(){var c=function(){return b.condition?b.condition():a.requireFilesLoaded()},d=function(){if(c()){a.options("debug")&&console.log("BLANKET-All files loaded, init start test runner callback.");var e=a.options("testReadyCallback");e?"function"==typeof e?e(b.callback):"string"==typeof e&&(a._addScript(e),b.callback()):b.callback()}else setTimeout(d,13)};d()})}):b.callback()},utils:{qualifyURL:function(a){var b=document.createElement("a");return b.href=a,b.href}}})}(blanket),blanket.defaultReporter=function(a){function b(a){var b=document.getElementById(a);"block"===b.style.display?b.style.display="none":b.style.display="block"}function c(a){return a.replace(/\&/g,"&").replace(//g,">").replace(/\"/g,""").replace(/\'/g,"'").replace(/`/g,"`").replace(/[$]/g,"$").replace(/&/g,"&")}function d(a,b){var c=b?0:1;return"undefined"==typeof a||null===typeof a||"undefined"==typeof a[c]?!1:a[c].length>0}function e(a,b,f,g,h){var i="",j="";if(q.length>0)if(i+="",q[0][0].end.line===h){if(i+=c(b.slice(0,q[0][0].end.column))+"",b=b.slice(q[0][0].end.column),q.shift(),q.length>0)if(i+="",q[0][0].end.line===h){if(i+=c(b.slice(0,q[0][0].end.column))+"",b=b.slice(q[0][0].end.column),q.shift(),!f)return{src:i+c(b),cols:f}}else{if(!f)return{src:i+c(b)+"",cols:f};j=""}else if(!f)return{src:i+c(b),cols:f}}else{if(!f)return{src:i+c(b)+"",cols:f};j=""}var k=f[a],l=k.consequent;if(l.start.line>h)q.unshift([k.alternate,k]),q.unshift([l,k]),b=c(b);else{var m="";if(i+=c(b.slice(0,l.start.column-g))+m,f.length>a+1&&f[a+1].consequent.start.line===h&&f[a+1].consequent.start.column-g";var o=k.alternate;if(o.start.line>h)i+=c(b.slice(l.end.column-g)),q.unshift([o,k]);else{if(i+=c(b.slice(l.end.column-g,o.start.column-g)),m="",i+=m,f.length>a+1&&f[a+1].consequent.start.line===h&&f[a+1].consequent.start.column-g",i+=c(b.slice(o.end.column-g)),b=i}}return{src:b+j,cols:f}}var f="#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;} #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-left:50px; width:150px; float:right} .bl-nb {padding-right:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .hit{background-color:#c3e6c7} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:yellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}",g=60,h=document.head,i=0,j=document.body,k=Object.keys(a.files).some(function(b){return"undefined"!=typeof a.files[b].branchData}),l="
results
Coverage (%)
Covered/Total Smts.
"+(k?"
Covered/Total Branches
":"")+"
",m="
{{fileNumber}}.{{file}}
{{percentage}} %
{{numberCovered}}/{{totalSmts}}
"+(k?"
{{passedBranches}}/{{totalBranches}}
":"")+"
";grandTotalTemplate="
{{rowTitle}}
{{percentage}} %
{{numberCovered}}/{{totalSmts}}
"+(k?"
{{passedBranches}}/{{totalBranches}}
":"")+"
";var n=document.createElement("script");n.type="text/javascript",n.text=b.toString().replace("function "+b.name,"function blanket_toggleSource"),j.appendChild(n);var o=function(a,b){return Math.round(a/b*100*100)/100},p=function(a,b,c){var d=document.createElement(a);d.innerHTML=c,b.appendChild(d)},q=[],r=function(a){return"undefined"!=typeof a},s=a.files,t={totalSmts:0,numberOfFilesCovered:0,passedBranches:0,totalBranches:0,moduleTotalStatements:{},moduleTotalCoveredStatements:{},moduleTotalBranches:{},moduleTotalCoveredBranches:{}},u=_blanket.options("modulePattern"),v=u?new RegExp(u):null;for(var w in s)if(s.hasOwnProperty(w)){i++;var x,y=s[w],z=0,A=0,B=[];for(x=0;x0||"undefined"!=typeof y.branchData)if("undefined"!=typeof y.branchData[x+1]){var D=y.branchData[x+1].filter(r),E=0;C=e(E,C,D,0,x+1).src}else C=q.length?e(0,C,null,0,x+1).src:c(C);else C=c(C);var F="";y[x+1]?(A+=1,z+=1,F="hit"):0===y[x+1]&&(z++,F="miss"),B[x+1]="
"+(x+1)+""+C+"
"}t.totalSmts+=z,t.numberOfFilesCovered+=A;var G=0,H=0;if("undefined"!=typeof y.branchData)for(var I=0;I0&&"undefined"!=typeof y.branchData[I][J][1]&&y.branchData[I][J][1].length>0&&H++);if(t.passedBranches+=H,t.totalBranches+=G,v){var K=w.match(v)[1];t.moduleTotalStatements.hasOwnProperty(K)||(t.moduleTotalStatements[K]=0,t.moduleTotalCoveredStatements[K]=0),t.moduleTotalStatements[K]+=z,t.moduleTotalCoveredStatements[K]+=A,t.moduleTotalBranches.hasOwnProperty(K)||(t.moduleTotalBranches[K]=0,t.moduleTotalCoveredBranches[K]=0),t.moduleTotalBranches[K]+=G,t.moduleTotalCoveredBranches[K]+=H}var L=o(A,z),M=m.replace("{{file}}",w).replace("{{percentage}}",L).replace("{{numberCovered}}",A).replace(/\{\{fileNumber\}\}/g,i).replace("{{totalSmts}}",z).replace("{{totalBranches}}",G).replace("{{passedBranches}}",H).replace("{{source}}",B.join(" "));M=g>L?M.replace("{{statusclass}}","bl-error"):M.replace("{{statusclass}}","bl-success"),l+=M}var N=function(a,b,c,d,e){var f=o(b,a),h=g>f?"bl-error":"bl-success",i=e?"Total for module: "+e:"Global total",j=grandTotalTemplate.replace("{{rowTitle}}",i).replace("{{percentage}}",f).replace("{{numberCovered}}",b).replace("{{totalSmts}}",a).replace("{{passedBranches}}",d).replace("{{totalBranches}}",c).replace("{{statusclass}}",h);l+=j};if(v)for(var O in t.moduleTotalStatements)if(t.moduleTotalStatements.hasOwnProperty(O)){var P=t.moduleTotalStatements[O],Q=t.moduleTotalCoveredStatements[O],R=t.moduleTotalBranches[O],S=t.moduleTotalCoveredBranches[O];N(P,Q,R,S,O)}N(t.totalSmts,t.numberOfFilesCovered,t.totalBranches,t.passedBranches,null),l+="
",p("style",h,f),document.getElementById("blanket-main")?document.getElementById("blanket-main").innerHTML=l.slice(23,-6):p("div",j,l)},function(){var a={},b=Array.prototype.slice,c=b.call(document.scripts);b.call(c[c.length-1].attributes).forEach(function(b){if("data-cover-only"===b.nodeName&&(a.filter=b.nodeValue),"data-cover-never"===b.nodeName&&(a.antifilter=b.nodeValue),"data-cover-reporter"===b.nodeName&&(a.reporter=b.nodeValue),"data-cover-adapter"===b.nodeName&&(a.adapter=b.nodeValue),"data-cover-loader"===b.nodeName&&(a.loader=b.nodeValue),"data-cover-timeout"===b.nodeName&&(a.timeout=b.nodeValue),"data-cover-modulepattern"===b.nodeName&&(a.modulePattern=b.nodeValue),"data-cover-reporter-options"===b.nodeName)try{a.reporter_options=JSON.parse(b.nodeValue)}catch(c){if(blanket.options("debug"))throw new Error("Invalid reporter options. Must be a valid stringified JSON object.")}if("data-cover-testReadyCallback"===b.nodeName&&(a.testReadyCallback=b.nodeValue),"data-cover-customVariable"===b.nodeName&&(a.customVariable=b.nodeValue),"data-cover-flags"===b.nodeName){var d=" "+b.nodeValue+" ";d.indexOf(" ignoreError ")>-1&&(a.ignoreScriptError=!0),d.indexOf(" autoStart ")>-1&&(a.autoStart=!0),d.indexOf(" ignoreCors ")>-1&&(a.ignoreCors=!0),d.indexOf(" branchTracking ")>-1&&(a.branchTracking=!0),d.indexOf(" sourceURL ")>-1&&(a.sourceURL=!0),d.indexOf(" debug ")>-1&&(a.debug=!0),d.indexOf(" engineOnly ")>-1&&(a.engineOnly=!0),d.indexOf(" commonJS ")>-1&&(a.commonJS=!0),d.indexOf(" instrumentCache ")>-1&&(a.instrumentCache=!0)}}),blanket.options(a),"undefined"!=typeof requirejs&&blanket.options("existingRequireJS",!0),blanket.options("commonJS")&&(blanket._commonjs={})}(),function(a){a.extend({utils:{normalizeBackslashes:function(a){return a.replace(/\\/g,"/")},matchPatternAttribute:function(b,c){if("string"==typeof c){if(0===c.indexOf("[")){var d=c.slice(1,c.length-1).split(",");return d.some(function(c){return a.utils.matchPatternAttribute(b,a.utils.normalizeBackslashes(c.slice(1,-1)))})}if(0===c.indexOf("//")){var e=c.slice(2,c.lastIndexOf("/")),f=c.slice(c.lastIndexOf("/")+1),g=new RegExp(e,f);return g.test(b)}return 0===c.indexOf("#")?window[c.slice(1)].call(window,b):b.indexOf(a.utils.normalizeBackslashes(c))>-1}return c instanceof Array?c.some(function(c){return a.utils.matchPatternAttribute(b,c)}):c instanceof RegExp?c.test(b):"function"==typeof c?c.call(window,b):void 0},blanketEval:function(b){a._addScript(b)},collectPageScripts:function(){var b=Array.prototype.slice,c=(b.call(document.scripts),[]),d=[],e=a.options("filter");if(null!=e){var f=a.options("antifilter");c=b.call(document.scripts).filter(function(c){return 1===b.call(c.attributes).filter(function(b){return"src"===b.nodeName&&a.utils.matchPatternAttribute(b.nodeValue,e)&&("undefined"==typeof f||!a.utils.matchPatternAttribute(b.nodeValue,f))}).length})}else c=b.call(document.querySelectorAll("script[data-cover]"));return d=c.map(function(c){return a.utils.qualifyURL(b.call(c.attributes).filter(function(a){return"src"===a.nodeName})[0].nodeValue)}),e||a.options("filter","['"+d.join("','")+"']"),d},loadAll:function(b,c,d){var e=b(),f=a.utils.scriptIsLoaded(e,a.utils.ifOrdered,b,c);if(a.utils.cache[e]&&a.utils.cache[e].loaded)f();else{var g=function(){a.options("debug")&&console.log("BLANKET-Mark script:"+e+", as loaded and move to next script."),f()},h=function(b){a.options("debug")&&console.log("BLANKET-File loading finished"),"undefined"!=typeof b&&(a.options("debug")&&console.log("BLANKET-Add file to DOM."),a._addScript(b)),g()};a.utils.attachScript({url:e},function(b){a.utils.processFile(b,e,h,h)})}},attachScript:function(b,c){var d=a.options("timeout")||3e3;setTimeout(function(){if(!a.utils.cache[b.url].loaded)throw new Error("error (timeout="+d+") loading source script: "+b.url)},d),a.utils.getFile(b.url,c,function(){throw new Error("error loading source script: "+b.url)})},ifOrdered:function(b,c){var d=b(!0);d?a.utils.loadAll(b,c):c(new Error("Error in loading chain."))},scriptIsLoaded:function(b,c,d,e){return a.options("debug")&&console.log("BLANKET-Returning function"),function(){a.options("debug")&&console.log("BLANKET-Marking file as loaded: "+b),a.utils.cache[b].loaded=!0,a.utils.allLoaded()?(a.options("debug")&&console.log("BLANKET-All files loaded"),e()):c&&(a.options("debug")&&console.log("BLANKET-Load next file."),c(d,e))}},cache:{},allLoaded:function(){for(var b=Object.keys(a.utils.cache),c=0;cb;b+=1){c=progIds[b];try{new ActiveXObject(c);break}catch(d){}}this.createXhr=function(){return new a(c)}}},craeteXhr:function(){throw new Error("cacheXhrConstructor is supposed to overwrite this function.")},getFile:function(b,c,d,e){var f=!1;if(a.blanketSession)for(var g=Object.keys(a.blanketSession),h=0;h-1)return c(a.blanketSession[i]),void(f=!0)}if(!f){var j=a.utils.createXhr();j.open("GET",b,!0),e&&e(j,b),j.onreadystatechange=function(a){var e,f;4===j.readyState&&(e=j.status,e>399&&600>e?(f=new Error(b+" HTTP status: "+e),f.xhr=j,d(f)):c(j.responseText))};try{j.send(null)}catch(k){if(!k.code||101!==k.code&&1012!==k.code||a.options("ignoreCors")!==!1)throw k;a.showManualLoader()}}}}}),function(){var b=(blanket.options("commonJS")?blanket._commonjs.require:window.require,blanket.options("commonJS")?blanket._commonjs.requirejs:window.requirejs);!a.options("engineOnly")&&a.options("existingRequireJS")&&(a.utils.oldloader=b.load,b.load=function(b,c,d){a.requiringFile(d),a.utils.getFile(d,function(e){a.utils.processFile(e,d,function(){b.completeLoad(c)},function(){a.utils.oldloader(b,c,d)})},function(b){throw a.requiringFile(),b})}),a.utils.cacheXhrConstructor()}()}(blanket),function(){if("undefined"!=typeof QUnit){var a=function(){return window.QUnit.config.queue.length>0&&blanket.noConflict().requireFilesLoaded()};QUnit.config.urlConfig[0].tooltip?(QUnit.config.urlConfig.push({id:"coverage",label:"Enable coverage",tooltip:"Enable code coverage."}),QUnit.urlParams.coverage||blanket.options("autoStart")?(QUnit.begin(function(){blanket.noConflict().setupCoverage()}),QUnit.done(function(a,b){blanket.noConflict().onTestsDone()}),QUnit.moduleStart(function(a){blanket.noConflict().onModuleStart()}),QUnit.testStart(function(a){blanket.noConflict().onTestStart()}),QUnit.testDone(function(a){blanket.noConflict().onTestDone(a.total,a.passed)}),blanket.noConflict().beforeStartTestRunner({condition:a,callback:function(){(!blanket.options("existingRequireJS")||blanket.options("autoStart"))&&QUnit.start()}})):(blanket.options("existingRequireJS")&&(requirejs.load=_blanket.utils.oldloader),blanket.noConflict().beforeStartTestRunner({condition:a,callback:function(){(!blanket.options("existingRequireJS")||blanket.options("autoStart"))&&QUnit.start()},coverage:!1}))):(QUnit.begin=function(){blanket.noConflict().setupCoverage()},QUnit.done=function(a,b){blanket.noConflict().onTestsDone()},QUnit.moduleStart=function(a){blanket.noConflict().onModuleStart()},QUnit.testStart=function(a){blanket.noConflict().onTestStart()},QUnit.testDone=function(a){blanket.noConflict().onTestDone(a.total,a.passed)},blanket.beforeStartTestRunner({condition:a,callback:QUnit.start}))}}(); \ No newline at end of file