diff --git a/assets/image/Lastwar.png b/assets/image/Lastwar.png new file mode 100644 index 000000000..212f07439 Binary files /dev/null and b/assets/image/Lastwar.png differ diff --git "a/assets/image/M\303\243_QR.png" "b/assets/image/M\303\243_QR.png" new file mode 100644 index 000000000..6a1405a66 Binary files /dev/null and "b/assets/image/M\303\243_QR.png" differ diff --git a/assets/image/amazon_clone_card.jpeg b/assets/image/amazon_clone_card.jpeg new file mode 100644 index 000000000..1ed9e35ab Binary files /dev/null and b/assets/image/amazon_clone_card.jpeg differ diff --git a/assets/image/buildingblock.png b/assets/image/buildingblock.png new file mode 100644 index 000000000..ace88f446 Binary files /dev/null and b/assets/image/buildingblock.png differ diff --git a/assets/image/candy.png b/assets/image/candy.png new file mode 100644 index 000000000..9b2574a4f Binary files /dev/null and b/assets/image/candy.png differ diff --git a/assets/image/chat-7767693_1280.jpg b/assets/image/chat-7767693_1280.jpg new file mode 100644 index 000000000..fa4d62e73 Binary files /dev/null and b/assets/image/chat-7767693_1280.jpg differ diff --git a/assets/image/cutrope.png b/assets/image/cutrope.png new file mode 100644 index 000000000..b83aa2807 Binary files /dev/null and b/assets/image/cutrope.png differ diff --git a/assets/image/mole logo.png b/assets/image/mole logo.png new file mode 100644 index 000000000..4952cf588 Binary files /dev/null and b/assets/image/mole logo.png differ diff --git a/assets/image/mole-bop.png b/assets/image/mole-bop.png new file mode 100644 index 000000000..523a51523 Binary files /dev/null and b/assets/image/mole-bop.png differ diff --git a/assets/image/spaceinvade.png b/assets/image/spaceinvade.png new file mode 100644 index 000000000..342ee4ed3 Binary files /dev/null and b/assets/image/spaceinvade.png differ diff --git a/assets/image/supermario.png b/assets/image/supermario.png new file mode 100644 index 000000000..e7e31219d Binary files /dev/null and b/assets/image/supermario.png differ diff --git a/assets/image/tiltingmaze.png b/assets/image/tiltingmaze.png new file mode 100644 index 000000000..7e4e9b293 Binary files /dev/null and b/assets/image/tiltingmaze.png differ diff --git a/assets/image/traintrack.png b/assets/image/traintrack.png new file mode 100644 index 000000000..be0ec6a1e Binary files /dev/null and b/assets/image/traintrack.png differ diff --git a/assets/image/vp.jpg b/assets/image/vp.jpg new file mode 100644 index 000000000..934a63e8b Binary files /dev/null and b/assets/image/vp.jpg differ diff --git a/assets/image/zeroLine.png b/assets/image/zeroLine.png new file mode 100644 index 000000000..99a1af8d4 Binary files /dev/null and b/assets/image/zeroLine.png differ diff --git a/css/style.css b/css/style.css index e2ab53d7e..35bdcac77 100644 --- a/css/style.css +++ b/css/style.css @@ -82,6 +82,13 @@ body { padding: 1rem; } +/* Hover Effects for Project */ +.projects-container a:hover { + background-color: #f9cbd3; + transform: translateY(-6px); + transition: transform 0.3s ease, background-color 0.3s ease; + } + .card { background: var(--card); border-radius: 8px; diff --git a/index.html b/index.html index 3854b47c1..5c3f703ec 100644 --- a/index.html +++ b/index.html @@ -62,6 +62,17 @@

Counter

+ +
+ +
+
+

Last War

+

+ Save the world by planting trees. +

+
+
@@ -154,6 +165,17 @@

Snake Game

+ +
+ +
+
+

Zero Line Game

+

+ Explore Space +

+
+
@@ -326,6 +348,18 @@

Drum Kit

+ +
+ wordle logo +
+
+ +

Maze Game with AI

+

+ play against AI. +

+
+
wordle logo @@ -408,7 +442,25 @@

Typing Speed Test

Test Your Speed on Typing

+ + + +
+
+ pet +
+
+

Virtual Pet Game

+

+ Adopt, care, and interact with virtual pets +

+
+
+ + + --> +
Rolling Triumph @@ -469,7 +521,10 @@

Dictionary

Dictionary app

-
+ + + +
@@ -501,10 +556,35 @@

TRIVIA

GeoQuest

- Explore the World, One Challenge at a Time!

+ Explore the World, One Challenge at a Time!

+ + + + +
+ + Whac a mole logo + +
+ +
+ +

Whack a Mole

+ +

+ + Smash moles, score big fun!

+ +
+ +
+ + + +
@@ -516,8 +596,20 @@

Pokedex

+ +
+ Super Mario +
+
+

Super Mario

+

+ A Popular Game. +

+
+
+
magic8ball
@@ -550,6 +642,11 @@

Password manager

+ + + + +
Notes Taking @@ -561,6 +658,7 @@

Notes Taking

+
Dice Game @@ -594,6 +692,17 @@

Flappy Bird

+ +
+ Candy Game +
+
+

Candy Game

+

+ A Candy game. +

+
+
Stick Hero @@ -628,6 +737,7 @@

Joke Generator

+
Doodle Jump
@@ -636,8 +746,43 @@

Doodle Jump

Enjoy and Jump.

+ +
+ + + +
+ Train Track Game +
+
+

Train Track Game

+

+ A Train Track Game which is created by Three Js. +

+
+
+ +
+ Building Block +
+
+

Building Block

+

+ A Building Block Game. +

+ +
+ Cut The Rope +
+
+

Cut The Rope

+

+ Cut the rope in game. +

+
+
Email Validator @@ -649,6 +794,28 @@

Email Validator

+ +
+ Mole Bop +
+
+

Mole Bop

+

+ Catch the Bop. +

+
+
+ +
+ Tilting Maze Game +
+
+

Tilting Maze Game

+

+ A Tilting Maze Game. +

+
+
maze game' @@ -660,6 +827,17 @@

Maze Game

+ +
+ Space Invader +
+
+

Space Invader

+

+ A fun Space Invader game. +

+
+
Virtual Keyboard' @@ -695,6 +873,32 @@

Tetris Game

+ + +
+ Qr +
+
+

QR Generator

+

+ QR Generator using HTML, CSS & Js +

+
+
+ + +
+ link tree icon +
+
+

Amazon clone

+

+ get the feeling of real developer +

+
+
+ +
@@ -706,6 +910,19 @@

Connect4(Two player)

+ + +
+ a coin representing how to win the game +
+
+

Space Collision Game

+

+ Space Collision: Catch Coins and avoid Enemies to Score +

+
+
+
pianoImage @@ -717,6 +934,7 @@

Piano

+
@@ -731,8 +949,23 @@

Bubble Hit Game

+ + +
+ chatbot +
+
+

Chatbot

+

+ A simple chatbot.
+ Please use your own google gemini api key for the chatbot to work. +

+
+
+ + - + diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index dda6fdb12..a52231b65 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -266,6 +266,18 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", diff --git a/package-lock.json b/package-lock.json index e973e5209..70c056628 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "body-parser": "^1.20.3", + "dotenv": "^16.4.5", "ejs": "^3.1.10", "express": "^4.21.0", "mongoose": "^8.7.0" @@ -277,6 +278,18 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", diff --git a/package.json b/package.json index 538094b56..d41d3ce50 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "license": "ISC", "dependencies": { "body-parser": "^1.20.3", + "dotenv": "^16.4.5", "ejs": "^3.1.10", "express": "^4.21.0", "mongoose": "^8.7.0" diff --git a/projects/Building Block/index.html b/projects/Building Block/index.html new file mode 100644 index 000000000..18d0b262b --- /dev/null +++ b/projects/Building Block/index.html @@ -0,0 +1,28 @@ + + + + + + Building Block + + + + + +
+
+

Stack the blocks on top of each other

+

Click, tap or press Space when a block is above the stack. Can you reach the blue color blocks?

+

Click, tap or press Space to start game

+
+
+
+
+

You missed the block

+

To reset the game press R

+
+
+
0
+ + + \ No newline at end of file diff --git a/projects/Building Block/script.js b/projects/Building Block/script.js new file mode 100644 index 000000000..1265bd557 --- /dev/null +++ b/projects/Building Block/script.js @@ -0,0 +1,331 @@ +window.focus(); + +let camera, scene, renderer; // ThreeJS globals +let world; // CannonJs world +let lastTime; // Last timestamp of animation +let stack; // Parts that stay solid on top of each other +let overhangs; // Overhanging parts that fall down +const boxHeight = 1; // Height of each layer +const originalBoxSize = 3; // Original width and height of a box +let autopilot; +let gameEnded; +let robotPrecision; // Determines how precise the game is on autopilot + +const scoreElement = document.getElementById("score"); +const instructionsElement = document.getElementById("instructions"); +const resultsElement = document.getElementById("results"); + +init(); + +function setRobotPrecision() { + robotPrecision = Math.random() * 1 - 0.5; +} + +function init() { + autopilot = true; + gameEnded = false; + lastTime = 0; + stack = []; + overhangs = []; + setRobotPrecision(); + + // Initialize CannonJS + world = new CANNON.World(); + world.gravity.set(0, -10, 0); // Gravity pulls things down + world.broadphase = new CANNON.NaiveBroadphase(); + world.solver.iterations = 40; + + // Initialize ThreeJs + const aspect = window.innerWidth / window.innerHeight; + const width = 10; + const height = width / aspect; + + camera = new THREE.OrthographicCamera( + width / -2, // left + width / 2, // right + height / 2, // top + height / -2, // bottom + 0, // near plane + 100 // far plane + ); + + camera.position.set(4, 4, 4); + camera.lookAt(0, 0, 0); + + scene = new THREE.Scene(); + + // Foundation + addLayer(0, 0, originalBoxSize, originalBoxSize); + + // First layer + addLayer(-10, 0, originalBoxSize, originalBoxSize, "x"); + + // Set up lights + const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); + scene.add(ambientLight); + + const dirLight = new THREE.DirectionalLight(0xffffff, 0.6); + dirLight.position.set(10, 20, 0); + scene.add(dirLight); + + // Set up renderer + renderer = new THREE.WebGLRenderer({ antialias: true }); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setAnimationLoop(animation); + document.body.appendChild(renderer.domElement); +} + +function startGame() { + autopilot = false; + gameEnded = false; + lastTime = 0; + stack = []; + overhangs = []; + + if (instructionsElement) instructionsElement.style.display = "none"; + if (resultsElement) resultsElement.style.display = "none"; + if (scoreElement) scoreElement.innerText = 0; + + if (world) { + // Remove every object from world + while (world.bodies.length > 0) { + world.remove(world.bodies[0]); + } + } + + if (scene) { + // Remove every Mesh from the scene + while (scene.children.find((c) => c.type == "Mesh")) { + const mesh = scene.children.find((c) => c.type == "Mesh"); + scene.remove(mesh); + } + + // Foundation + addLayer(0, 0, originalBoxSize, originalBoxSize); + + // First layer + addLayer(-10, 0, originalBoxSize, originalBoxSize, "x"); + } + + if (camera) { + // Reset camera positions + camera.position.set(4, 4, 4); + camera.lookAt(0, 0, 0); + } +} + +function addLayer(x, z, width, depth, direction) { + const y = boxHeight * stack.length; // Add the new box one layer higher + const layer = generateBox(x, y, z, width, depth, false); + layer.direction = direction; + stack.push(layer); +} + +function addOverhang(x, z, width, depth) { + const y = boxHeight * (stack.length - 1); // Add the new box one the same layer + const overhang = generateBox(x, y, z, width, depth, true); + overhangs.push(overhang); +} + +function generateBox(x, y, z, width, depth, falls) { + // ThreeJS + const geometry = new THREE.BoxGeometry(width, boxHeight, depth); + const color = new THREE.Color(`hsl(${30 + stack.length * 4}, 100%, 50%)`); + const material = new THREE.MeshLambertMaterial({ color }); + const mesh = new THREE.Mesh(geometry, material); + mesh.position.set(x, y, z); + scene.add(mesh); + + // CannonJS + const shape = new CANNON.Box( + new CANNON.Vec3(width / 2, boxHeight / 2, depth / 2) + ); + let mass = falls ? 5 : 0; + mass *= width / originalBoxSize; + mass *= depth / originalBoxSize; + const body = new CANNON.Body({ mass, shape }); + body.position.set(x, y, z); + world.addBody(body); + + return { + threejs: mesh, + cannonjs: body, + width, + depth + }; +} + +function cutBox(topLayer, overlap, size, delta) { + const direction = topLayer.direction; + const newWidth = direction == "x" ? overlap : topLayer.width; + const newDepth = direction == "z" ? overlap : topLayer.depth; + + // Update metadata + topLayer.width = newWidth; + topLayer.depth = newDepth; + + // Update ThreeJS model + topLayer.threejs.scale[direction] = overlap / size; + topLayer.threejs.position[direction] -= delta / 2; + + // Update CannonJS model + topLayer.cannonjs.position[direction] -= delta / 2; + + const shape = new CANNON.Box( + new CANNON.Vec3(newWidth / 2, boxHeight / 2, newDepth / 2) + ); + topLayer.cannonjs.shapes = []; + topLayer.cannonjs.addShape(shape); +} + +window.addEventListener("mousedown", eventHandler); +window.addEventListener("touchstart", eventHandler); +window.addEventListener("keydown", function (event) { + if (event.key == " ") { + event.preventDefault(); + eventHandler(); + return; + } + if (event.key == "R" || event.key == "r") { + event.preventDefault(); + startGame(); + return; + } +}); + +function eventHandler() { + if (autopilot) startGame(); + else splitBlockAndAddNextOneIfOverlaps(); +} + +function splitBlockAndAddNextOneIfOverlaps() { + if (gameEnded) return; + + const topLayer = stack[stack.length - 1]; + const previousLayer = stack[stack.length - 2]; + + const direction = topLayer.direction; + + const size = direction == "x" ? topLayer.width : topLayer.depth; + const delta = + topLayer.threejs.position[direction] - + previousLayer.threejs.position[direction]; + const overhangSize = Math.abs(delta); + const overlap = size - overhangSize; + + if (overlap > 0) { + cutBox(topLayer, overlap, size, delta); + + // Overhang + const overhangShift = (overlap / 2 + overhangSize / 2) * Math.sign(delta); + const overhangX = + direction == "x" + ? topLayer.threejs.position.x + overhangShift + : topLayer.threejs.position.x; + const overhangZ = + direction == "z" + ? topLayer.threejs.position.z + overhangShift + : topLayer.threejs.position.z; + const overhangWidth = direction == "x" ? overhangSize : topLayer.width; + const overhangDepth = direction == "z" ? overhangSize : topLayer.depth; + + addOverhang(overhangX, overhangZ, overhangWidth, overhangDepth); + + // Next layer + const nextX = direction == "x" ? topLayer.threejs.position.x : -10; + const nextZ = direction == "z" ? topLayer.threejs.position.z : -10; + const newWidth = topLayer.width; // New layer has the same size as the cut top layer + const newDepth = topLayer.depth; // New layer has the same size as the cut top layer + const nextDirection = direction == "x" ? "z" : "x"; + + if (scoreElement) scoreElement.innerText = stack.length - 1; + addLayer(nextX, nextZ, newWidth, newDepth, nextDirection); + } else { + missedTheSpot(); + } +} + +function missedTheSpot() { + const topLayer = stack[stack.length - 1]; + + // Turn to top layer into an overhang and let it fall down + addOverhang( + topLayer.threejs.position.x, + topLayer.threejs.position.z, + topLayer.width, + topLayer.depth + ); + world.remove(topLayer.cannonjs); + scene.remove(topLayer.threejs); + + gameEnded = true; + if (resultsElement && !autopilot) resultsElement.style.display = "flex"; +} + +function animation(time) { + if (lastTime) { + const timePassed = time - lastTime; + const speed = 0.008; + + const topLayer = stack[stack.length - 1]; + const previousLayer = stack[stack.length - 2]; + + const boxShouldMove = + !gameEnded && + (!autopilot || + (autopilot && + topLayer.threejs.position[topLayer.direction] < + previousLayer.threejs.position[topLayer.direction] + + robotPrecision)); + + if (boxShouldMove) { + // Keep the position visible on UI and the position in the model in sync + topLayer.threejs.position[topLayer.direction] += speed * timePassed; + topLayer.cannonjs.position[topLayer.direction] += speed * timePassed; + + // If the box went beyond the stack then show up the fail screen + if (topLayer.threejs.position[topLayer.direction] > 10) { + missedTheSpot(); + } + } else { + if (autopilot) { + splitBlockAndAddNextOneIfOverlaps(); + setRobotPrecision(); + } + } + + // 4 is the initial camera height + if (camera.position.y < boxHeight * (stack.length - 2) + 4) { + camera.position.y += speed * timePassed; + } + + updatePhysics(timePassed); + renderer.render(scene, camera); + } + lastTime = time; +} + +function updatePhysics(timePassed) { + world.step(timePassed / 1000); // Step the physics world + + // Copy coordinates from Cannon.js to Three.js + overhangs.forEach((element) => { + element.threejs.position.copy(element.cannonjs.position); + element.threejs.quaternion.copy(element.cannonjs.quaternion); + }); +} + +window.addEventListener("resize", () => { + // Adjust camera + console.log("resize", window.innerWidth, window.innerHeight); + const aspect = window.innerWidth / window.innerHeight; + const width = 10; + const height = width / aspect; + + camera.top = height / 2; + camera.bottom = height / -2; + + // Reset renderer + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.render(scene, camera); +}); diff --git a/projects/Building Block/style.css b/projects/Building Block/style.css new file mode 100644 index 000000000..cda966f13 --- /dev/null +++ b/projects/Building Block/style.css @@ -0,0 +1,48 @@ +@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@900&display=swap"); + +body { + margin: 0; + color: white; + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + cursor: pointer; +} + +#instructions { + display: none; +} + +#results, +body:hover #instructions { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + background-color: rgba(20, 20, 20, 0.75); +} + +a:visited { + color: inherit; +} + +#results { + display: none; + cursor: default; +} + +#results .content, +#instructions .content { + max-width: 300px; + padding: 50px; + border-radius: 20px; +} + +#score { + position: absolute; + color: white; + font-size: 3em; + font-weight: bold; + top: 30px; + right: 30px; +} \ No newline at end of file diff --git a/projects/Candy Game/background.jpg b/projects/Candy Game/background.jpg new file mode 100644 index 000000000..4115b1105 Binary files /dev/null and b/projects/Candy Game/background.jpg differ diff --git a/projects/Candy Game/candy.css b/projects/Candy Game/candy.css new file mode 100644 index 000000000..6182b55b6 --- /dev/null +++ b/projects/Candy Game/candy.css @@ -0,0 +1,23 @@ +body { + background: url("./background.jpg") no-repeat center center fixed; + background-size: cover; + font-family: Arial, Helvetica, sans-serif; + color: white; + text-align: center; +} + +#board { + width: 450px; + height: 450px; + background-color: lightblue; + border: 5px solid slategray; + border-radius: 10px; + margin: 0 auto; + display: flex; + flex-wrap: wrap; +} + +#board img { + width: 50px; + height: 50px; +} \ No newline at end of file diff --git a/projects/Candy Game/candy.js b/projects/Candy Game/candy.js new file mode 100644 index 000000000..329b673b1 --- /dev/null +++ b/projects/Candy Game/candy.js @@ -0,0 +1,204 @@ + +var candies = ["Blue", "Orange", "Green", "Yellow", "Red", "Purple"]; +var board = []; +var rows = 9; +var columns = 9; +var score = 0; + +var currTile; +var otherTile; + + +window.onload = function() { + startGame(); + + //1/10th of a second + window.setInterval(function(){ + crushCandy(); + slideCandy(); + generateCandy(); + }, 100); +} + +function randomCandy() { + return candies[Math.floor(Math.random() * candies.length)]; //0 - 5.99 +} + +function startGame() { + for (let r = 0; r < rows; r++) { + let row = []; + for (let c = 0; c < columns; c++) { + // + let tile = document.createElement("img"); + tile.id = r.toString() + "-" + c.toString(); + tile.src = "./images/" + randomCandy() + ".png"; + + //DRAG FUNCTIONALITY + tile.addEventListener("dragstart", dragStart); //click on a candy, initialize drag process + tile.addEventListener("dragover", dragOver); //clicking on candy, moving mouse to drag the candy + tile.addEventListener("dragenter", dragEnter); //dragging candy onto another candy + tile.addEventListener("dragleave", dragLeave); //leave candy over another candy + tile.addEventListener("drop", dragDrop); //dropping a candy over another candy + tile.addEventListener("dragend", dragEnd); //after drag process completed, we swap candies + + document.getElementById("board").append(tile); + row.push(tile); + } + board.push(row); + } + + console.log(board); +} + +function dragStart() { + //this refers to tile that was clicked on for dragging + currTile = this; +} + +function dragOver(e) { + e.preventDefault(); +} + +function dragEnter(e) { + e.preventDefault(); +} + +function dragLeave() { + +} + +function dragDrop() { + //this refers to the target tile that was dropped on + otherTile = this; +} + +function dragEnd() { + + if (currTile.src.includes("blank") || otherTile.src.includes("blank")) { + return; + } + + let currCoords = currTile.id.split("-"); // id="0-0" -> ["0", "0"] + let r = parseInt(currCoords[0]); + let c = parseInt(currCoords[1]); + + let otherCoords = otherTile.id.split("-"); + let r2 = parseInt(otherCoords[0]); + let c2 = parseInt(otherCoords[1]); + + let moveLeft = c2 == c-1 && r == r2; + let moveRight = c2 == c+1 && r == r2; + + let moveUp = r2 == r-1 && c == c2; + let moveDown = r2 == r+1 && c == c2; + + let isAdjacent = moveLeft || moveRight || moveUp || moveDown; + + if (isAdjacent) { + let currImg = currTile.src; + let otherImg = otherTile.src; + currTile.src = otherImg; + otherTile.src = currImg; + + let validMove = checkValid(); + if (!validMove) { + let currImg = currTile.src; + let otherImg = otherTile.src; + currTile.src = otherImg; + otherTile.src = currImg; + } + } +} + +function crushCandy() { + //crushFive(); + //crushFour(); + crushThree(); + document.getElementById("score").innerText = score; + +} + +function crushThree() { + //check rows + for (let r = 0; r < rows; r++) { + for (let c = 0; c < columns-2; c++) { + let candy1 = board[r][c]; + let candy2 = board[r][c+1]; + let candy3 = board[r][c+2]; + if (candy1.src == candy2.src && candy2.src == candy3.src && !candy1.src.includes("blank")) { + candy1.src = "./images/blank.png"; + candy2.src = "./images/blank.png"; + candy3.src = "./images/blank.png"; + score += 30; + } + } + } + + //check columns + for (let c = 0; c < columns; c++) { + for (let r = 0; r < rows-2; r++) { + let candy1 = board[r][c]; + let candy2 = board[r+1][c]; + let candy3 = board[r+2][c]; + if (candy1.src == candy2.src && candy2.src == candy3.src && !candy1.src.includes("blank")) { + candy1.src = "./images/blank.png"; + candy2.src = "./images/blank.png"; + candy3.src = "./images/blank.png"; + score += 30; + } + } + } +} + +function checkValid() { + //check rows + for (let r = 0; r < rows; r++) { + for (let c = 0; c < columns-2; c++) { + let candy1 = board[r][c]; + let candy2 = board[r][c+1]; + let candy3 = board[r][c+2]; + if (candy1.src == candy2.src && candy2.src == candy3.src && !candy1.src.includes("blank")) { + return true; + } + } + } + + //check columns + for (let c = 0; c < columns; c++) { + for (let r = 0; r < rows-2; r++) { + let candy1 = board[r][c]; + let candy2 = board[r+1][c]; + let candy3 = board[r+2][c]; + if (candy1.src == candy2.src && candy2.src == candy3.src && !candy1.src.includes("blank")) { + return true; + } + } + } + + return false; +} + + +function slideCandy() { + for (let c = 0; c < columns; c++) { + let ind = rows - 1; + for (let r = columns-1; r >= 0; r--) { + if (!board[r][c].src.includes("blank")) { + board[ind][c].src = board[r][c].src; + ind -= 1; + } + } + + for (let r = ind; r >= 0; r--) { + board[r][c].src = "./images/blank.png"; + } + } +} + +function generateCandy() { + for (let c = 0; c < columns; c++) { + if (board[0][c].src.includes("blank")) { + board[0][c].src = "./images/" + randomCandy() + ".png"; + } + } +} \ No newline at end of file diff --git a/projects/Candy Game/images/Blue-Striped-Horizontal.png b/projects/Candy Game/images/Blue-Striped-Horizontal.png new file mode 100644 index 000000000..d079458a5 Binary files /dev/null and b/projects/Candy Game/images/Blue-Striped-Horizontal.png differ diff --git a/projects/Candy Game/images/Blue-Striped-Vertical.png b/projects/Candy Game/images/Blue-Striped-Vertical.png new file mode 100644 index 000000000..2fea99144 Binary files /dev/null and b/projects/Candy Game/images/Blue-Striped-Vertical.png differ diff --git a/projects/Candy Game/images/Blue-Wrapped.png b/projects/Candy Game/images/Blue-Wrapped.png new file mode 100644 index 000000000..63514ff0e Binary files /dev/null and b/projects/Candy Game/images/Blue-Wrapped.png differ diff --git a/projects/Candy Game/images/Blue.png b/projects/Candy Game/images/Blue.png new file mode 100644 index 000000000..5b358796d Binary files /dev/null and b/projects/Candy Game/images/Blue.png differ diff --git a/projects/Candy Game/images/Choco.png b/projects/Candy Game/images/Choco.png new file mode 100644 index 000000000..732d6f3d9 Binary files /dev/null and b/projects/Candy Game/images/Choco.png differ diff --git a/projects/Candy Game/images/Green-Striped-Horizontal.png b/projects/Candy Game/images/Green-Striped-Horizontal.png new file mode 100644 index 000000000..0c1cea5f3 Binary files /dev/null and b/projects/Candy Game/images/Green-Striped-Horizontal.png differ diff --git a/projects/Candy Game/images/Green-Striped-Vertical.png b/projects/Candy Game/images/Green-Striped-Vertical.png new file mode 100644 index 000000000..78fa92c3d Binary files /dev/null and b/projects/Candy Game/images/Green-Striped-Vertical.png differ diff --git a/projects/Candy Game/images/Green-Wrapped.png b/projects/Candy Game/images/Green-Wrapped.png new file mode 100644 index 000000000..1710264fc Binary files /dev/null and b/projects/Candy Game/images/Green-Wrapped.png differ diff --git a/projects/Candy Game/images/Green.png b/projects/Candy Game/images/Green.png new file mode 100644 index 000000000..9ffea2a99 Binary files /dev/null and b/projects/Candy Game/images/Green.png differ diff --git a/projects/Candy Game/images/Orange-Striped-Horizontal.png b/projects/Candy Game/images/Orange-Striped-Horizontal.png new file mode 100644 index 000000000..b64bfcfa1 Binary files /dev/null and b/projects/Candy Game/images/Orange-Striped-Horizontal.png differ diff --git a/projects/Candy Game/images/Orange-Striped-Vertical.png b/projects/Candy Game/images/Orange-Striped-Vertical.png new file mode 100644 index 000000000..a6da76fc2 Binary files /dev/null and b/projects/Candy Game/images/Orange-Striped-Vertical.png differ diff --git a/projects/Candy Game/images/Orange-Wrapped.png b/projects/Candy Game/images/Orange-Wrapped.png new file mode 100644 index 000000000..2af5190e2 Binary files /dev/null and b/projects/Candy Game/images/Orange-Wrapped.png differ diff --git a/projects/Candy Game/images/Orange.png b/projects/Candy Game/images/Orange.png new file mode 100644 index 000000000..fdeda79c4 Binary files /dev/null and b/projects/Candy Game/images/Orange.png differ diff --git a/projects/Candy Game/images/Purple-Striped-Horizontal.png b/projects/Candy Game/images/Purple-Striped-Horizontal.png new file mode 100644 index 000000000..3e1b67466 Binary files /dev/null and b/projects/Candy Game/images/Purple-Striped-Horizontal.png differ diff --git a/projects/Candy Game/images/Purple-Striped-Vertical.png b/projects/Candy Game/images/Purple-Striped-Vertical.png new file mode 100644 index 000000000..989f11f09 Binary files /dev/null and b/projects/Candy Game/images/Purple-Striped-Vertical.png differ diff --git a/projects/Candy Game/images/Purple-Wrapped.png b/projects/Candy Game/images/Purple-Wrapped.png new file mode 100644 index 000000000..32a944f62 Binary files /dev/null and b/projects/Candy Game/images/Purple-Wrapped.png differ diff --git a/projects/Candy Game/images/Purple.png b/projects/Candy Game/images/Purple.png new file mode 100644 index 000000000..65e5bf93b Binary files /dev/null and b/projects/Candy Game/images/Purple.png differ diff --git a/projects/Candy Game/images/Red-Striped-Horizontal.png b/projects/Candy Game/images/Red-Striped-Horizontal.png new file mode 100644 index 000000000..b22694c6d Binary files /dev/null and b/projects/Candy Game/images/Red-Striped-Horizontal.png differ diff --git a/projects/Candy Game/images/Red-Striped-Vertical.png b/projects/Candy Game/images/Red-Striped-Vertical.png new file mode 100644 index 000000000..f9217e687 Binary files /dev/null and b/projects/Candy Game/images/Red-Striped-Vertical.png differ diff --git a/projects/Candy Game/images/Red-Wrapped.png b/projects/Candy Game/images/Red-Wrapped.png new file mode 100644 index 000000000..2c30a3ac0 Binary files /dev/null and b/projects/Candy Game/images/Red-Wrapped.png differ diff --git a/projects/Candy Game/images/Red.png b/projects/Candy Game/images/Red.png new file mode 100644 index 000000000..4b3136364 Binary files /dev/null and b/projects/Candy Game/images/Red.png differ diff --git a/projects/Candy Game/images/Yellow-Striped-Horizontal.png b/projects/Candy Game/images/Yellow-Striped-Horizontal.png new file mode 100644 index 000000000..f1a40e7cc Binary files /dev/null and b/projects/Candy Game/images/Yellow-Striped-Horizontal.png differ diff --git a/projects/Candy Game/images/Yellow-Striped-Vertical.png b/projects/Candy Game/images/Yellow-Striped-Vertical.png new file mode 100644 index 000000000..7d9cbf3fa Binary files /dev/null and b/projects/Candy Game/images/Yellow-Striped-Vertical.png differ diff --git a/projects/Candy Game/images/Yellow-Wrapped.png b/projects/Candy Game/images/Yellow-Wrapped.png new file mode 100644 index 000000000..ea48a9bd2 Binary files /dev/null and b/projects/Candy Game/images/Yellow-Wrapped.png differ diff --git a/projects/Candy Game/images/Yellow.png b/projects/Candy Game/images/Yellow.png new file mode 100644 index 000000000..39a8e9e68 Binary files /dev/null and b/projects/Candy Game/images/Yellow.png differ diff --git a/projects/Candy Game/images/blank.png b/projects/Candy Game/images/blank.png new file mode 100644 index 000000000..acbc4fe83 Binary files /dev/null and b/projects/Candy Game/images/blank.png differ diff --git a/projects/Candy Game/index.html b/projects/Candy Game/index.html new file mode 100644 index 000000000..049a1a309 --- /dev/null +++ b/projects/Candy Game/index.html @@ -0,0 +1,16 @@ + + + + + + + Candy Crush + + + + + +

Score: 0

+
+ + \ No newline at end of file diff --git a/projects/Chatbot/index.html b/projects/Chatbot/index.html new file mode 100644 index 000000000..7dd9e2a6d --- /dev/null +++ b/projects/Chatbot/index.html @@ -0,0 +1,33 @@ + + + + + + Chatbot + + + + + +
+
+

Chatbot

+
+ +
+ + Send +
+ +
+ + + + \ No newline at end of file diff --git a/projects/Chatbot/script.js b/projects/Chatbot/script.js new file mode 100644 index 000000000..f9a7eaf8a --- /dev/null +++ b/projects/Chatbot/script.js @@ -0,0 +1,63 @@ +const chatInput = document.querySelector(".chat-input textarea"); +const sendChatBtn = document.querySelector(".chat-input span"); +const chatbox = document.querySelector(".chatbox"); + +let userMessage = ""; +const API_KEY=""; + +const createChatLi = (message, className) => { + const chatLi = document.createElement("li"); + chatLi.classList.add("chat", className); + let chatContent = + className === "outgoing" + ? `

` + : `smart_toy

`; + chatLi.innerHTML = chatContent; + chatLi.querySelector("p").textContent = message; + return chatLi; +}; + +const generateResponse = (incomingChatLi) => { + const API_URL = `https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent?key=${API_KEY}`; + const messageElement = incomingChatLi.querySelector("p"); + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + contents: [ + { + role: "user", + parts: [{ text: userMessage }], + }, + ], + }), + }; + fetch(API_URL, requestOptions) + .then((res) => res.json()) + .then((data) => { + messageElement.textContent = data.candidates[0].content.parts[0].text; + }) + .catch((error) => { + messageElement.textContent = + "Oops! Something went wrong. Please try again later."; + }) + .finally(() => chatbox.scrollTo(0, chatbox.scrollHeight)); +}; + +const handleChat = () => { + userMessage = chatInput.value.trim(); + if (!userMessage) return; + chatInput.value = ""; + + chatbox.appendChild(createChatLi(userMessage, "outgoing")); + chatbox.scrollTo(0, chatbox.scrollHeight); + + setTimeout(() => { + const incomingChatLi = createChatLi("Thinking....", "incoming"); + chatbox.appendChild(incomingChatLi); + chatbox.scrollTo(0, chatbox.scrollHeight); + generateResponse(incomingChatLi); + }, 600); +}; + +sendChatBtn.addEventListener("click", handleChat); diff --git a/projects/Chatbot/style.css b/projects/Chatbot/style.css new file mode 100644 index 000000000..d3dfe7ed7 --- /dev/null +++ b/projects/Chatbot/style.css @@ -0,0 +1,162 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap'); + +* { + box-sizing: border-box; + margin: 0; + padding: 0; + font-family: 'Poppins', sans-serif; +} + +body { + background: #E3F2FD; +} + + +.chatbot { + width: 550px; + height: 600px; + position: fixed; + left: 600px; + top: 100px; + pointer-events: none; + overflow: hidden; + background: #fff; + border-radius: 15px; + box-shadow: 0 0 128px 0 rgba(0, 0, 0, 0.1), + 0 32px 64px -48px rgba(0, 0, 0, 0.5); +} + +.show-chatbot .chatbot { + transform: scale(1); + opacity: 1; + pointer-events: auto; +} + +.chatbot header { + background: #724ae8; + padding: 26px; + text-align: center; + position: relative; +} + + +.chatbot header h2 { + color: #fff; + font-size: 1.8rem; +} + +.chatbot header span { + position: absolute; + right: 20px; + top: 50%; + color: #fff; + cursor: pointer; + display: none; + transform: translateY(-50%); +} + +.chatbot .chatbox { + height: 510px; + overflow-y: auto; + padding: 30px 20px 100px; +} + +.chatbox .chat { + display: flex; + +} + +.chatbox .incoming span { + height: 32px; + width: 32px; + color: #fff; + align-self: flex-end; + background: #724ae8; + text-align: center; + line-height: 32px; + border-radius: 4px; + margin: 0 10px 7px 0; + +} + +.chatbox .outgoing { + margin: 20px 0; + justify-content: flex-end; +} + + +.chatbox .chat p { + color: #fff; + max-width: 75%; + white-space: pre-wrap; + + font-size: 0.95rem; + padding: 12px 16px; + border-radius: 10px 10px 0 10px; + background: #724ae8; +} + +.chatbox .incoming p { + color: #000; + background: #f2f2f2; + border-radius: 10px 10px 10px 0; +} + +.chatbot .chat-input { + position: absolute; + bottom: 0; + width: 100%; + display: flex; + gap: 5px; + background: #fff; + padding: 5px 20px; + border-top: 1px solid #ccc; +} + +.chat-input textarea { + height: 55px; + width: 100%; + border: none; + outline: none; + font-size: 0.95rem; + resize: none; + padding: 16px 15px 16px 0; +} + +.chat-input span { + align-self: flex-end; + height: 55px; + line-height: 55px; + color: #724ae8; + font-size: 1.35rem; + cursor: pointer; + visibility: hidden; +} + +.chat-input textarea:valid~span { + visibility: visible; +} + +@media(max-width:790px) { + .chatbot { + position: fixed; + top: 15px; + left: 22px; + right: 45px; + bottom: 55px; + height: auto; + width: auto; + + + + border-radius: 5px; + } + + .chatbot .chatbox { + height: 90%; + } + + .chatbot header span { + display: block; + } +} \ No newline at end of file diff --git a/projects/Cut The Rope/audio/bouncer.mp3 b/projects/Cut The Rope/audio/bouncer.mp3 new file mode 100644 index 000000000..f371f99f3 Binary files /dev/null and b/projects/Cut The Rope/audio/bouncer.mp3 differ diff --git a/projects/Cut The Rope/audio/bubble.mp3 b/projects/Cut The Rope/audio/bubble.mp3 new file mode 100644 index 000000000..c75017adf Binary files /dev/null and b/projects/Cut The Rope/audio/bubble.mp3 differ diff --git a/projects/Cut The Rope/audio/bubble_break.mp3 b/projects/Cut The Rope/audio/bubble_break.mp3 new file mode 100644 index 000000000..96a25cc27 Binary files /dev/null and b/projects/Cut The Rope/audio/bubble_break.mp3 differ diff --git a/projects/Cut The Rope/audio/button.mp3 b/projects/Cut The Rope/audio/button.mp3 new file mode 100644 index 000000000..4c688adf9 Binary files /dev/null and b/projects/Cut The Rope/audio/button.mp3 differ diff --git a/projects/Cut The Rope/audio/buzz.mp3 b/projects/Cut The Rope/audio/buzz.mp3 new file mode 100644 index 000000000..f42a72f3f Binary files /dev/null and b/projects/Cut The Rope/audio/buzz.mp3 differ diff --git a/projects/Cut The Rope/audio/candy_break.mp3 b/projects/Cut The Rope/audio/candy_break.mp3 new file mode 100644 index 000000000..ac81f0bd6 Binary files /dev/null and b/projects/Cut The Rope/audio/candy_break.mp3 differ diff --git a/projects/Cut The Rope/audio/candy_link.mp3 b/projects/Cut The Rope/audio/candy_link.mp3 new file mode 100644 index 000000000..886c69318 Binary files /dev/null and b/projects/Cut The Rope/audio/candy_link.mp3 differ diff --git a/projects/Cut The Rope/audio/electric.mp3 b/projects/Cut The Rope/audio/electric.mp3 new file mode 100644 index 000000000..6a63d30f5 Binary files /dev/null and b/projects/Cut The Rope/audio/electric.mp3 differ diff --git a/projects/Cut The Rope/audio/game_music.mp3 b/projects/Cut The Rope/audio/game_music.mp3 new file mode 100644 index 000000000..d4a583584 Binary files /dev/null and b/projects/Cut The Rope/audio/game_music.mp3 differ diff --git a/projects/Cut The Rope/audio/game_music2.mp3 b/projects/Cut The Rope/audio/game_music2.mp3 new file mode 100644 index 000000000..60fac987b Binary files /dev/null and b/projects/Cut The Rope/audio/game_music2.mp3 differ diff --git a/projects/Cut The Rope/audio/game_music3.mp3 b/projects/Cut The Rope/audio/game_music3.mp3 new file mode 100644 index 000000000..2abe40076 Binary files /dev/null and b/projects/Cut The Rope/audio/game_music3.mp3 differ diff --git a/projects/Cut The Rope/audio/gravity_off.mp3 b/projects/Cut The Rope/audio/gravity_off.mp3 new file mode 100644 index 000000000..af4ef1996 Binary files /dev/null and b/projects/Cut The Rope/audio/gravity_off.mp3 differ diff --git a/projects/Cut The Rope/audio/gravity_on.mp3 b/projects/Cut The Rope/audio/gravity_on.mp3 new file mode 100644 index 000000000..4df5b77ae Binary files /dev/null and b/projects/Cut The Rope/audio/gravity_on.mp3 differ diff --git a/projects/Cut The Rope/audio/menu_music.mp3 b/projects/Cut The Rope/audio/menu_music.mp3 new file mode 100644 index 000000000..57c1a5a40 Binary files /dev/null and b/projects/Cut The Rope/audio/menu_music.mp3 differ diff --git a/projects/Cut The Rope/audio/monster_chewing.mp3 b/projects/Cut The Rope/audio/monster_chewing.mp3 new file mode 100644 index 000000000..a54d9ecaf Binary files /dev/null and b/projects/Cut The Rope/audio/monster_chewing.mp3 differ diff --git a/projects/Cut The Rope/audio/monster_close.mp3 b/projects/Cut The Rope/audio/monster_close.mp3 new file mode 100644 index 000000000..b8bd0db4a Binary files /dev/null and b/projects/Cut The Rope/audio/monster_close.mp3 differ diff --git a/projects/Cut The Rope/audio/monster_open.mp3 b/projects/Cut The Rope/audio/monster_open.mp3 new file mode 100644 index 000000000..3df9b581a Binary files /dev/null and b/projects/Cut The Rope/audio/monster_open.mp3 differ diff --git a/projects/Cut The Rope/audio/monster_sad.mp3 b/projects/Cut The Rope/audio/monster_sad.mp3 new file mode 100644 index 000000000..830068b94 Binary files /dev/null and b/projects/Cut The Rope/audio/monster_sad.mp3 differ diff --git a/projects/Cut The Rope/audio/pump_1.mp3 b/projects/Cut The Rope/audio/pump_1.mp3 new file mode 100644 index 000000000..0606b0157 Binary files /dev/null and b/projects/Cut The Rope/audio/pump_1.mp3 differ diff --git a/projects/Cut The Rope/audio/pump_2.mp3 b/projects/Cut The Rope/audio/pump_2.mp3 new file mode 100644 index 000000000..a0a9d76a0 Binary files /dev/null and b/projects/Cut The Rope/audio/pump_2.mp3 differ diff --git a/projects/Cut The Rope/audio/pump_3.mp3 b/projects/Cut The Rope/audio/pump_3.mp3 new file mode 100644 index 000000000..4f0090cee Binary files /dev/null and b/projects/Cut The Rope/audio/pump_3.mp3 differ diff --git a/projects/Cut The Rope/audio/pump_4.mp3 b/projects/Cut The Rope/audio/pump_4.mp3 new file mode 100644 index 000000000..667eaa859 Binary files /dev/null and b/projects/Cut The Rope/audio/pump_4.mp3 differ diff --git a/projects/Cut The Rope/audio/ring.mp3 b/projects/Cut The Rope/audio/ring.mp3 new file mode 100644 index 000000000..776f00978 Binary files /dev/null and b/projects/Cut The Rope/audio/ring.mp3 differ diff --git a/projects/Cut The Rope/audio/rope_bleak_1.mp3 b/projects/Cut The Rope/audio/rope_bleak_1.mp3 new file mode 100644 index 000000000..f0d128d2a Binary files /dev/null and b/projects/Cut The Rope/audio/rope_bleak_1.mp3 differ diff --git a/projects/Cut The Rope/audio/rope_bleak_2.mp3 b/projects/Cut The Rope/audio/rope_bleak_2.mp3 new file mode 100644 index 000000000..b275f005f Binary files /dev/null and b/projects/Cut The Rope/audio/rope_bleak_2.mp3 differ diff --git a/projects/Cut The Rope/audio/rope_bleak_3.mp3 b/projects/Cut The Rope/audio/rope_bleak_3.mp3 new file mode 100644 index 000000000..f4593f937 Binary files /dev/null and b/projects/Cut The Rope/audio/rope_bleak_3.mp3 differ diff --git a/projects/Cut The Rope/audio/rope_bleak_4.mp3 b/projects/Cut The Rope/audio/rope_bleak_4.mp3 new file mode 100644 index 000000000..4cbdae885 Binary files /dev/null and b/projects/Cut The Rope/audio/rope_bleak_4.mp3 differ diff --git a/projects/Cut The Rope/audio/rope_get.mp3 b/projects/Cut The Rope/audio/rope_get.mp3 new file mode 100644 index 000000000..ad0a0a866 Binary files /dev/null and b/projects/Cut The Rope/audio/rope_get.mp3 differ diff --git a/projects/Cut The Rope/audio/scratch_in.mp3 b/projects/Cut The Rope/audio/scratch_in.mp3 new file mode 100644 index 000000000..dc7f7fa4f Binary files /dev/null and b/projects/Cut The Rope/audio/scratch_in.mp3 differ diff --git a/projects/Cut The Rope/audio/scratch_out.mp3 b/projects/Cut The Rope/audio/scratch_out.mp3 new file mode 100644 index 000000000..eb3a627db Binary files /dev/null and b/projects/Cut The Rope/audio/scratch_out.mp3 differ diff --git a/projects/Cut The Rope/audio/spider_activate.mp3 b/projects/Cut The Rope/audio/spider_activate.mp3 new file mode 100644 index 000000000..c90e4fdea Binary files /dev/null and b/projects/Cut The Rope/audio/spider_activate.mp3 differ diff --git a/projects/Cut The Rope/audio/spider_fall.mp3 b/projects/Cut The Rope/audio/spider_fall.mp3 new file mode 100644 index 000000000..ea6a78024 Binary files /dev/null and b/projects/Cut The Rope/audio/spider_fall.mp3 differ diff --git a/projects/Cut The Rope/audio/spider_win.mp3 b/projects/Cut The Rope/audio/spider_win.mp3 new file mode 100644 index 000000000..1277e6a01 Binary files /dev/null and b/projects/Cut The Rope/audio/spider_win.mp3 differ diff --git a/projects/Cut The Rope/audio/spike_rotate_in.mp3 b/projects/Cut The Rope/audio/spike_rotate_in.mp3 new file mode 100644 index 000000000..e6b345857 Binary files /dev/null and b/projects/Cut The Rope/audio/spike_rotate_in.mp3 differ diff --git a/projects/Cut The Rope/audio/spike_rotate_out.mp3 b/projects/Cut The Rope/audio/spike_rotate_out.mp3 new file mode 100644 index 000000000..1461ac7d5 Binary files /dev/null and b/projects/Cut The Rope/audio/spike_rotate_out.mp3 differ diff --git a/projects/Cut The Rope/audio/star_1.mp3 b/projects/Cut The Rope/audio/star_1.mp3 new file mode 100644 index 000000000..f31dcf6b5 Binary files /dev/null and b/projects/Cut The Rope/audio/star_1.mp3 differ diff --git a/projects/Cut The Rope/audio/star_2.mp3 b/projects/Cut The Rope/audio/star_2.mp3 new file mode 100644 index 000000000..6d4f1bcf2 Binary files /dev/null and b/projects/Cut The Rope/audio/star_2.mp3 differ diff --git a/projects/Cut The Rope/audio/star_3.mp3 b/projects/Cut The Rope/audio/star_3.mp3 new file mode 100644 index 000000000..26150150f Binary files /dev/null and b/projects/Cut The Rope/audio/star_3.mp3 differ diff --git a/projects/Cut The Rope/audio/tap.mp3 b/projects/Cut The Rope/audio/tap.mp3 new file mode 100644 index 000000000..9818d3a85 Binary files /dev/null and b/projects/Cut The Rope/audio/tap.mp3 differ diff --git a/projects/Cut The Rope/audio/teleport.mp3 b/projects/Cut The Rope/audio/teleport.mp3 new file mode 100644 index 000000000..0a17e9761 Binary files /dev/null and b/projects/Cut The Rope/audio/teleport.mp3 differ diff --git a/projects/Cut The Rope/audio/wheel.mp3 b/projects/Cut The Rope/audio/wheel.mp3 new file mode 100644 index 000000000..5580aa575 Binary files /dev/null and b/projects/Cut The Rope/audio/wheel.mp3 differ diff --git a/projects/Cut The Rope/audio/win.mp3 b/projects/Cut The Rope/audio/win.mp3 new file mode 100644 index 000000000..59c630452 Binary files /dev/null and b/projects/Cut The Rope/audio/win.mp3 differ diff --git a/projects/Cut The Rope/css/ctr.css b/projects/Cut The Rope/css/ctr.css new file mode 100644 index 000000000..3a8dbdce9 --- /dev/null +++ b/projects/Cut The Rope/css/ctr.css @@ -0,0 +1,2333 @@ +html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video { + margin:0; + padding:0; + border:0; + font-size:100%; + font:inherit; + vertical-align:baseline; + -ms-content-zooming:none +} +article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section { + display:block +} +body { + line-height:1 +} +ol,ul { + list-style:none +} +blockquote,q { + quotes:none +} +blockquote:before,blockquote:after,q:before,q:after { + content:''; + content:none +} +table { + border-collapse:collapse; + border-spacing:0 +} +a { + text-decoration:none; + color:inherit +} +a:active,a:focus { + outline:0 +} +#loaderWindow { + margin:0; + width:100%; + height:100%; + position:absolute; + top:0; + left:0; + font-family:gooddognum; + font-size:88px; + color:#fff +} +#loaderLogo { + display:none; + position:relative; + top:200px; + left:190px +} +#loaderBubbles { + width:800px; + height:100%; + margin:0 auto; + position:relative +} +#loaderProgress { + position:absolute; + top:50%; + left:400px +} +#loaderProgressBubble { + position:absolute; + left:-100px; + width:218px; + height:159px; + background-image:url(../images/page/loader-bubble.png); + background-repeat:no-repeat; + text-align:center; + padding-top:70px; + padding-left:10px +} +#loaderCanvasHost { + width:100%; + height:100%; + position:absolute; + top:0; + left:0 +} +#loaderCanvas { + margin:0; + padding:0; + position:absolute; + top:0 +} +@font-face { + font-family:gooddogplain; + src:url(fonts/gooddog-plain/GoodDog-webfont.eot); + src:url(fonts/gooddog-plain/GoodDog-webfont.eot?#iefix) format("embedded-opentype"),url(fonts/gooddog-plain/GoodDog-webfont.woff) format("woff"),url(fonts/gooddog-plain/GoodDog-webfont.ttf) format("truetype"),url(fonts/gooddog-plain/GoodDog-webfont.svg#GoodDogRegular) format("svg"); + font-weight:400; + font-style:normal +} +@font-face { + font-family:gooddognew; + src:url(fonts/gooddog-new/gooddog_new-webfont.eot); + src:url(fonts/gooddog-new/gooddog_new-webfont.eot?#iefix) format("embedded-opentype"),url(fonts/gooddog-new/gooddog_new-webfont.woff) format("woff"),url(fonts/gooddog-new/gooddog_new-webfont.ttf) format("truetype"),url(fonts/gooddog-new/gooddog_new-webfont.svg#GoodDogNewRegular) format("svg"); + font-weight:400; + font-style:normal +} +body { + background-image:url(../images/page/tilebg.jpg); + background-repeat:repeat; + font-family:gooddognew; + font-size:15px; + color:#19130c; + -webkit-user-select:none; + -khtml-user-select:none; + -moz-user-select:none; + -o-user-select:none; + -ms-user-select:none; + user-select:none; + -ms-touch-action:none +} +#bg { + width:100%; + height:100%; + position:absolute; + top:0; + left:0; + display:none +} +.ctrCursor { + cursor:url(../cursors/cursor.cur),url(../cursors/cursor.png),auto +} +.ctrCursor a,.ctrPointer { + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ctrCursorActive { + cursor:url(../cursors/cursorActive.cur),url(../cursors/cursorActive.png),auto +} +footer .dot { + margin:-2px 8px 2px 8px +} +footer .zeptoLogo { + position:relative; + top:20px; + left:-4px +} +#e { + position:absolute; + top:0; + left:0; + display:none; + background:rgba(0,0,0,.6) +} +#d { + background:rgba(0,0,0,.5); + display:none +} +#content { + width:840px; + margin:80px auto 10px; + font-family:sans-serif,Helvetica,Arial; + font-size:.8em; + line-height:1.6em; + color:#3c2110 +} +#content h1 { + font-family:gooddogplain; + font-size:6em; + line-height:1em; + margin-bottom:20px +} +#content h2 { + font-family:gooddogplain; + font-size:3em; + line-height:1em; + margin-bottom:15px; + margin-top:30px +} +#content h3 { + font-family:gooddognew; + font-size:2em; + line-height:1em; + margin-bottom:15px; + margin-top:50px +} +#content h4 { + font-family:gooddognew; + font-size:1.5em; + line-height:1em; + margin-bottom:5px; + margin-top:15px +} +#content p { + margin-bottom:15px +} +#content a { + color:#c92817; + font-weight:700 +} +#content a:hover { + color:#c92817; + text-decoration:underline +} +table { + margin-bottom:30px; + width:100% +} +tbody tr:nth-child(odd) { + background-color:rgba(0,0,0,.1) +} +td,th { + padding:4px +} +th { + text-align:left; + font-weight:700 +} +#pagefooter { + margin:100px auto 10px; + width:840px +} +#pagefooter div { + margin:0 auto 10px +} +.panel { + display:none; + position:absolute; + top:0; + overflow:hidden +} +body { + -ms-touch-action:pan-y; + background:#fff; + overflow:hidden; + background-image:none +} +#loaderWindow { + background-image:url(../images/page/loader-bg.jpg); + background-repeat:no-repeat +} +#gameContainer { + overflow:hidden; + margin:0!important; + position:absolute; + top:0; + left:0 +} +#popupWindow { + z-index:100!important +} +.ui-1024 { +} +.ui-1024 .useSD { + display:none +} +.ui-1024 .useHD { + display:block +} +.ui-1024 #optionSd { + width:32px; + height:32px; + position:absolute; + left:84px; + top:10px +} +.ui-1024 #optionHd { + width:32px; + height:32px; + position:absolute; + left:50px; + top:10px +} +.ui-1024 #c { + position:relative; + width:1024; + height:576; + background-color:#000 +} +.ui-1024 #e { + width:1024; + height:576 +} +.ui-1024 #gameContainer { + position:relative; + margin:40px auto 0; + width:1024px; + height:730px; + padding:0 +} +.ui-1024 #gameBorder { + top:-9px; + left:-12px; + position:absolute; + background-repeat:no-repeat; + width:1047px; + height:598px; + display:none +} +.ui-1024 #gameArea { + margin:0; + position:absolute; + top:0; + left:0; + width:1024px; + height:576px +} +.ui-1024 .panel { + width:1024px; + height:576px +} +.ui-1024 #startBackground { + display:none; + background:url(../images/1024/ui/startbg.jpg) +} +.ui-1024 #menuBackground { + display:none; + background:url(../images/1024/ui/menubg.jpg) +} +.ui-1024 .seethrough { + background:transparent +} +.ui-1024 .panelContent { + position:absolute; + top:0 +} +.ui-1024 #shadowCanvas { + position:absolute; + top:0; + width:1024px; + height:576px +} +.ui-1024 .panelShadow img { + position:relative; + left:-300px; + position:relative; + top:-500px +} +.ui-1024 .fBtnVBox { + width:303px; + margin:0 auto +} +.ui-1024 .fBtn { + width:303px; + height:70px; + background-image:url(../images/1024/ui/fBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:10px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 .fBtn:hover { + background-position:left -71px +} +.ui-1024 .fBtn.disabled { + background-position:0 0; + cursor:inherit +} +.ui-1024 .fBtn.disabled img,.ui-1024 .fBtn.disabled div { + opacity:.6 +} +.ui-1024 .fBtn img { + margin-top:2px +} +.ui-1024 .mBtn { + width:235px; + height:70px; + background-image:url(../images/1024/ui/mBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:10px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 .mBtn img { + margin-top:2px +} +.ui-1024 .mBtn:hover { + background-position:left -71px +} +.ui-1024 .lBtn { + width:423px; + height:70px; + background-image:url(../images/1024/ui/lBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:10px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 .lBtn img { + margin-top:2px +} +.ui-1024 .lBtn:hover { + background-position:left -71px +} +.ui-1024 .sBtn { + width:171px; + height:65px; + background-image:url(../images/1024/ui/sBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:10px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 .sBtn img { + margin-top:2px +} +.ui-1024 .sBtn:hover { + background-position:left -66px +} +.ui-1024 .bBtn { + position:absolute; + top:492px; + left:14px; + width:79px; + height:75px; + background-image:url(../images/1024/ui/bBtn_bgd.png); + background-repeat:no-repeat; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 .bBtn:hover { + background-position:left -75px +} +.ui-1024 .iconBtn { + position:absolute +} +.ui-1024 #loadingPanel { + display:none +} +.ui-1024 #loadingPanel img { + margin-top:100px; + margin-left:420px +} +.ui-1024 #boxScore,.ui-1024 #levelScore { + position:absolute; + top:22px; + right:37px; + height:47px; + padding-right:50px; + background-image:url(../images/1024/ui/star_result_small.png); + background-position:right top; + background-repeat:no-repeat +} +.ui-1024 #boxes { + position:absolute; + top:120px; + left:311px +} +.ui-1024 .boxOption { + width:400px; + height:400px +} +.ui-1024 .boxCanvas { + position:absolute; + width:400px; + height:400px; + left:0; + top:0 +} +.ui-1024 .boxOption .boxTitle { + position:absolute; + top:20px; + left:28px +} +.ui-1024 .boxOmNom { + background-color:#2d2d35; + background-image:url(../images/1024/ui/box_omnom.png); + width:300px; + height:140px; + position:absolute; + top:183px; + left:16px; + background-position:92px 40px; + background-repeat:no-repeat +} +.ui-1024 #boxNavBack,.ui-1024 #boxNavForward { + position:absolute; + top:256px; + left:205px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 #boxNavBack div,.ui-1024 #boxNavForward div { + width:59px; + height:71px; + background-image:url(../images/1024/ui/box_nav_menu.png); + background-repeat:no-repeat +} +.ui-1024 #boxNavBack .boxNavDisabled { + cursor:url(../cursors/cursor.cur),url(../cursors/cursor.png),auto; + background-position:left -71px; + opacity:.25 +} +.ui-1024 #boxNavForward { + left:773px +} +.ui-1024 #boxNavForward div { + background-position:-59px top +} +.ui-1024 #boxNavForward .boxNavDisabled { + cursor:url(../cursors/cursor.cur),url(../cursors/cursor.png),auto; + background-position:-59px -71px; + opacity:.25 +} +.ui-1024 .hideFromMouse { + pointer-events:none +} +.ui-1024 #levelBackground { + display:none +} +.ui-1024 .levelTape { + width:52px; + height:553px; + position:absolute; + left:486px; + top:10px; + background-image:url(../images/1024/ui/leveltape.png); + background-repeat:no-repeat; + display:none +} +.ui-1024 #levelOptions { + position:absolute; + top:63px; + left:300px; + width:10px; + height:10px +} +.ui-1024 #levelPanel .option { + position:absolute; + width:121px; + height:141px +} +.ui-1024 #levelPanel .option .txt { + margin-top:22px; + width:121px; + text-align:center +} +.ui-1024 #levelPanel .stars0,.ui-1024 #levelPanel .stars1,.ui-1024 #levelPanel .stars2,.ui-1024 #levelPanel .stars3 { + position:absolute; + top:81px; + left:34px; + width:88px; + height:48px; + background-image:url(../images/1024/ui/options_stars_bgd.png); + background-repeat:no-repeat +} +.ui-1024 #levelPanel .stars1 { + background-position:left -48px +} +.ui-1024 #levelPanel .stars2 { + background-position:left -96px +} +.ui-1024 #levelPanel .stars3 { + background-position:left -144px +} +.ui-1024 #levelPanel .open { + background-image:url(../images/1024/ui/level_bgd.png); + background-repeat:no-repeat +} +.ui-1024 #levelPanel .locked { + background-image:url(../images/1024/ui/level_bgd.png); + background-position:left -141px; + background-repeat:no-repeat +} +.ui-1024 #levelPanel .purchase { + opacity:.4 +} +.ui-1024 #levelPanel .option-small .stars0,.ui-1024 #levelPanel .option-small .stars1,.ui-1024 #levelPanel .option-small .stars2,.ui-1024 #levelPanel .option-small .stars3 { + position:absolute; + top:53px; + left:22px; + width:58px; + height:30px; + background-image:url(../images/1024/ui/options_stars_bgd_small.png); + background-repeat:no-repeat +} +.ui-1024 #levelPanel .option-small .stars1 { + background-position:left -32px +} +.ui-1024 #levelPanel .option-small .stars2 { + background-position:left -64px +} +.ui-1024 #levelPanel .option-small .stars3 { + background-position:left -96px +} +.ui-1024 #levelPanel .option.option-small { + position:absolute; + width:80px; + height:85px; + margin-top:15px; + text-align:center +} +.ui-1024 #levelPanel .open.option-small { + background-image:url(../images/1024/ui/level_bgd_small.png); + background-repeat:no-repeat +} +.ui-1024 #levelPanel .locked.option-small { + background-image:url(../images/1024/ui/level_bgd_small.png); + background-position:left -93px; + background-repeat:no-repeat +} +.ui-1024 #levelPanel .option.option-small .txt { + margin-top:7px; + width:83px; + text-align:center +} +.ui-1024 #gameBtnTray { + display:none; + position:absolute; + width:180px; + height:42px; + right:0; + top:4px +} +.ui-1024 #gameBtnTray>div { + opacity:.7 +} +.ui-1024 #gameBtnTray>div:hover { + opacity:1 +} +.ui-1024 #gameRestartBtn { + width:42px; + height:42px; + background:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-100px 0; + position:absolute; + top:0; + left:44px +} +.ui-1024 #gameMenuBtn { + position:absolute; + width:88px; + height:42px; + background:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:0 0; + top:0; + left:88px +} +.ui-1024 #gameSound { + width:42px; + height:42px; + background:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + position:absolute; + top:0; + left:0 +} +.ui-1024 #gameSound.allSound { + background-position:-600px 0 +} +.ui-1024 #gameSound.effectsOnly { + background-position:-700px 0 +} +.ui-1024 #gameSound.noSound { + background-position:-800px 0 +} +.ui-1024 #gameMsg { + width:400px; + height:28px; + position:absolute; + right:190px; + top:-12px; + display:none; + text-align:right +} +.ui-1024 #levelMenu { + position:absolute; + top:0; + width:1024px; + height:446px; + background-color:rgba(0,0,0,.6); + display:none; + text-align:center; + padding-top:130px +} +.ui-1024 #levelResults { + display:none; + width:570px; + height:452px; + margin:60px auto 0; + text-align:center; + font-family:gooddogplain; + font-size:32px; + color:#3c2110; + position:relative +} +.ui-1024 #resultStatus { + position:absolute; + width:570px; + top:30px; + left:0; + text-align:center +} +.ui-1024 #levelResults .starCase { + width:281px; + height:93px; + margin:0 auto; + position:relative; + top:95px +} +.ui-1024 #resultTicker { + position:absolute; + top:200px; + left:0; + width:570px; + text-align:center +} +.ui-1024 #resultTickerLabel { + display:none +} +.ui-1024 #resultTickerValue { + padding-left:20px; + display:none +} +.ui-1024 #resultTickerMessage { + display:none +} +.ui-1024 #levelResults .star,.ui-1024 #levelResults .starEmpty { + float:left; + width:93px; + height:93px; + background-image:url(../images/1024/ui/star_result.png); + background-repeat:no-repeat +} +.ui-1024 #levelResults .starEmpty { + background-position:left -93px +} +.ui-1024 #levelResults .line { + position:absolute; + top:250px; + left:100px; + width:369px; + height:7px; + background-image:url(../images/1024/ui/result_line.png); + background-repeat:no-repeat +} +.ui-1024 #resultScore { + font-size:60px; + position:absolute; + top:250px; + width:570px; + display:none +} +.ui-1024 #levelResults .btnCase { + width:550px; + height:75px; + position:absolute; + top:350px; + left:10px +} +.ui-1024 #resultImproved { + width:117px; + height:117px; + background-repeat:no-repeat; + position:absolute; + top:190px; + left:410px; + display:none +} +.ui-1024 #levelResults .btnCase .sBtn { + float:left +} +.ui-1024 #lrMenuBtn { + margin:0 15px +} +.ui-1024 #boxCutter { + background-image:url(../images/1024/ui/boxcutter.png); + background-repeat:no-repeat; + display:none; + position:absolute; + top:281px; + left:178px; + width:339px; + height:321px +} +.ui-1024 #tapeRoll { + background-image:url(../images/1024/ui/taperoll.png); + background-repeat:no-repeat; + display:none; + position:absolute; + top:-14px; + left:436px; + width:130px; + height:175px +} +.ui-1024 #gameCompletePanel { + background-image:url(../images/1024/ui/gamecomplete.jpg); + background-repeat:no-repeat +} +.ui-1024 #finalShareBtn { + position:absolute; + top:430px; + left:160px +} +.ui-1024 #finalShareBtn img { + position:relative; + left:10px; + top:7px +} +.ui-1024 #ffb { + position:absolute; + top:-8px; + left:-25px; + width:83px; + height:83px; + background:url(../images/1024/ui/fb.png); + background-repeat:no-repeat +} +.ui-1024 #gameBorder.gameComplete { + top:-28px; + left:-33px; + position:absolute; + background-repeat:no-repeat; + width:1090px; + height:635px; + display:none; + background-image:url(../images/1024/ui/gamecomplete_border.png); + background-repeat:no-repeat +} +.ui-1024 #finalScore { + position:absolute; + top:340px; + height:47px; + width:1024px +} +.ui-1024 #finalScore img { + margin:0 auto; + display:block +} +.ui-1024 #finalFunBtn { + position:absolute; + top:430px; + left:460px; + display:block +} +.ui-1024 #finalFunBtn img { + position:relative; + left:15px; + top:7px +} +.ui-1024 #funOmNom { + width:102px; + height:101px; + background-image:url(../images/1024/ui/fun-omnom.png); + background-repeat:no-repeat; + position:absolute; + top:-22px; + left:-30px +} +.ui-1024 #congrats { + position:absolute; + top:100px; + left:0; + width:100%; + text-align:center +} +.ui-1024 #optionsPanel { + padding-top:20px +} +.ui-1024 #optionsTitle { + position:relative; + width:503px; + left:-100px; + height:70px +} +.ui-1024 #optionsTitle img { + margin:0 auto; + display:block +} +.ui-1024 #creditsBtn { + display:none +} +.ui-1024 .mini-button { + background-image:url(../images/1024/ui/menu-options.png); + background-repeat:no-repeat; + width:143px; + height:68px; + display:inline-block; + margin-bottom:8px; + margin-right:5px; + text-align:center; + position:relative +} +.ui-1024 .mini-button:hover { + background-position:0 -70px +} +.ui-1024 .options-x { + background-image:url(../images/1024/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-151px -70px; + width:30px; + height:30px +} +.ui-1024 .options-check { + background-image:url(../images/1024/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-78px -151px; + width:35px; + height:35px +} +.ui-1024 .options-check-disabled { + background-image:url(../images/1024/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-150px -102px; + width:35px; + height:35px +} +.ui-1024 #options-speaker { + background-image:url(../images/1024/ui/menu-options.png); + background-repeat:no-repeat; + background-position:0 -140px; + width:65px; + height:57px; + position:absolute; + left:40px; + top:6px +} +.ui-1024 #soundBtn .options-x { + position:absolute; + bottom:5px; + left:70px; + display:none +} +.ui-1024 #soundBtn.disabled #options-speaker { + opacity:.6 +} +.ui-1024 #soundBtn.disabled .options-x { + display:block +} +.ui-1024 #options-note { + background-image:url(../images/1024/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-150px 0; + width:55px; + height:62px; + position:absolute; + left:45px; + top:2px +} +.ui-1024 #musicBtn .options-x { + position:absolute; + bottom:4px; + left:72px; + display:none +} +.ui-1024 #musicBtn.disabled #options-note { + opacity:.6 +} +.ui-1024 #musicBtn.disabled .options-x { + display:block +} +.ui-1024 #dragBtn,.ui-1024 #cutBtn { + background-image:url(../images/1024/ui/menu-options.png); + background-repeat:no-repeat; + width:90px; + height:200px; + display:inline-block; + position:relative; + margin-left:38px +} +.ui-1024 #dragBtn { + background-position:0 -198px; + background-repeat:no-repeat +} +.ui-1024 #dragBtn .options-check-disabled { + position:absolute; + bottom:17px; + left:28px +} +.ui-1024 #cutBtn { + background-position:-105px -198px +} +.ui-1024 #cutBtn .options-check { + position:absolute; + bottom:15px; + left:31px +} +.ui-1024 #cutBtn.disabled .options-check { + display:none +} +.ui-1024 #dragText,.ui-1024 #cutText { + margin-top:115px; + margin-left:-23px +} +.ui-1024 #vid { + display:none; + width:1024px; + height:576px; + position:absolute; + top:0; + left:0; + background:transparent +} +.ui-1024 #fadeToBlack { + display:none; + width:1024px; + height:576px; + position:absolute; + top:0; + left:0; + background:#000 +} +.ui-1024 #menuLogo { + position:absolute; + left:323px; + top:40px; + width:339px; + height:301px; + background-image:url(../images/1024/ui/ph_logo.png); + background-repeat:no-repeat +} +.ui-1024 #menuBtnVbox { + position:absolute; + left:358px; + top:360px +} +.ui-1024 #dmsg { + display:block; + position:relative; + margin:30px auto 0 +} +.ui-1024 #dframe { + position:relative; + width:300px; + height:391px; + background-image:url(../images/1024/ui/drawing-bg.png); + background-repeat:no-repeat; + margin:-10px auto 0 auto +} +.ui-1024 #dpic { + position:absolute; + width:239px; + height:336px; + top:24px; + left:28px +} +.ui-1024 .drawing1 { + background:url(../images/1024/ui/drawing1.jpg) no-repeat +} +.drawing2 { + background:url(../images/1024/ui/drawing2.jpg) no-repeat +} +.drawing3 { + background:url(../images/1024/ui/drawing3.jpg) no-repeat +} +.drawing4 { + background:url(../images/1024/ui/drawing4.jpg) no-repeat +} +.drawing5 { + background:url(../images/1024/ui/drawing5.jpg) no-repeat +} +.drawing6 { + background:url(../images/1024/ui/drawing6.jpg) no-repeat +} +.drawing7 { + background:url(../images/1024/ui/drawing7.jpg) no-repeat +} +.drawing8 { + background:url(../images/1024/ui/drawing8.jpg) no-repeat +} +.drawing9 { + background:url(../images/1024/ui/drawing9.jpg) no-repeat +} +.drawing10 { + background:url(../images/1024/ui/drawing10.jpg) no-repeat +} +.drawing11 { + background:url(../images/1024/ui/drawing11.jpg) no-repeat +} +.drawing12 { + background:url(../images/1024/ui/drawing12.jpg) no-repeat +} +.drawing13 { + background:url(../images/1024/ui/drawing13.jpg) no-repeat +} +.drawing14 { + background:url(../images/1024/ui/drawing14.jpg) no-repeat +} +.drawing15 { + background:url(../images/1024/ui/drawing15.jpg) no-repeat +} +.drawing16 { + background:url(../images/1024/ui/drawing16.jpg) no-repeat +} +.ui-1024 #dshareBtn { + position:relative; + margin:5px auto 0 +} +.ui-1024 #dfb { + position:absolute; + top:-8px; + left:-5px; + width:83px; + height:83px; + /*background-image:url(../images/1024/ui/fb.png);*/ + background-repeat:no-repeat +} +.ui-1024 #gameFooterContainer { + width:1024px +} +.ui-1024 #miniOptionsMenu { + width:400px; + height:50px; + position:absolute; + left:15px; + top:520px +} +.ui-1024 #optionHd.activeResolution { + background:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-300px -50px; + opacity:.8 +} +.ui-1024 #optionHd.inActiveResolution { + background:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-300px 0; + opacity:.6; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 #optionHd.inActiveResolution:hover { + opacity:.8 +} +.ui-1024 #optionSd.activeResolution { + background:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-200px -50px; + opacity:.8 +} +.ui-1024 #optionSd.inActiveResolution { + background:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-200px 0; + opacity:.6; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-1024 #optionSd.inActiveResolution:hover { + opacity:.8 +} +.ui-1024 #optionSound { + width:42px; + height:42px; + background-image:url(../images/1024/ui/buttonsprite.png); + background-repeat:no-repeat; + position:absolute; + left:0; + opacity:.6 +} +.ui-1024 #optionSound.allSound { + background-position:-600px 0 +} +.ui-1024 #optionSound.effectsOnly { + background-position:-700px 0 +} +.ui-1024 #optionSound.noSound { + background-position:-800px 0 +} +.ui-1024 #optionSound:hover { + opacity:.7 +} +.ui-1024 #optionMsg { + width:210px; + height:28px; + position:absolute; + left:135px; + top:-12px; + display:none +} +.ui-1024 #popupWindow { + position:fixed; + top:0; + left:0; + right:0; + bottom:0; + display:none; + background-color:rgba(0,0,0,.4); + z-index:2 +} +.ui-1024 #popupWindow .popupOuterFrame { + margin:98px auto 0; + background-image:url(../images/1024/ui/popupouter.png); + background-repeat:no-repeat; + width:637px; + height:462px; + position:relative +} +.ui-1024 #popupWindow .popupInnerFrame { + position:absolute; + background-image:url(../images/1024/ui/popupinner.jpg); + background-repeat:no-repeat; + width:577px; + height:364px; + left:18px; + top:23px; + display:none +} +.ui-1024 #popupWindow .bottomright { + position:absolute; + bottom:10px; + right:10px +} +.ui-1024 #popupWindow #slowComputer { + background-image:url(../images/1024/ui/popupinner-slow.jpg); + background-repeat:no-repeat +} +.ui-1024 #slowComputerBtn { + position:absolute; + bottom:10px; + left:50px +} +.ui-1024 #slowComputerBtn img { + margin-top:8px +} +.ui-1024 #resetGame { + text-align:center +} +.ui-1024 #resetText { + margin-top:25px +} +.ui-1024 #resetYesBtn { + position:absolute; + bottom:95px; + left:50px +} +.ui-1024 #resetNoBtn { + position:absolute; + bottom:95px; + left:290px +} +.ui-1024 #resetHoldYes { + position:absolute; + bottom:20px; + width:580px; + text-align:center +} +.ui-1024 #missingStars { + text-align:center +} +.ui-1024 #missingLine1 { + margin-top:20px +} +.ui-1024 #missingStar { + background-image:url(../images/1024/ui/star_result_small.png); + background-repeat:no-repeat; + width:51px; + height:47px; + display:inline-block; + vertical-align:top; + margin-top:3px +} +.ui-1024 #missingOkBtn { + display:inline-block +} +.ui-1024 #flag { + background-image:url(../images/1024/ui/flags.png); + background-repeat:no-repeat; + background-position:0 0; + display:inline-block; + width:50px; + height:38px; + position:relative; + top:-12px; + margin-left:10px +} +.ui-1024 #resultImproved { + background-image:url(../images/1024/ui/menu_result_en.png); + background-repeat:no-repeat +} +.ui-1024 .lang-fr #resultImproved { + background-image:url(../images/1024/ui/menu_result_fr.png) +} +.ui-1024 .lang-fr #flag { + background-position:0 -40px +} +.ui-1024 .lang-de #resultImproved { + background-image:url(../images/1024/ui/menu_result_gr.png) +} +.ui-1024 .lang-de #flag { + background-position:0 -80px +} +.ui-1024 .lang-de #gameMenuBtn { + background-position:-855px 0 +} +.ui-1024 .lang-ru #resultImproved { + background-image:url(../images/1024/ui/menu_result_ru.png) +} +.ui-1024 .lang-ru #flag { + background-position:0 -120px +} +.ui-1024 .lang-ru #gameMenuBtn { + background-position:-1000px 0 +} +.ui-1024 #loaderWindow { + height:576px +} +.ui-768 { +} +.ui-768 .useSD { + display:block +} +.ui-768 .useHD { + display:none +} +.ui-768 #optionSd { + width:32px; + height:32px; + position:absolute; + left:70px; + top:6px +} +.ui-768 #optionHd { + width:32px; + height:32px; + position:absolute; + left:38px; + top:6px +} +.ui-768 #c { + position:relative; + width:768; + height:432; + background-color:#000 +} +.ui-768 #e { + width:768; + height:432 +} +.ui-768 #gameContainer { + position:relative; + margin:40px auto 0; + width:768px; + height:548px; + padding:0 +} +.ui-768 #gameBorder { + top:-7px; + left:-9px; + position:absolute; + background-repeat:no-repeat; + width:785px; + height:449px; + display:none +} +.ui-768 #gameArea { + margin:0; + position:absolute; + top:0; + left:0; + width:768px; + height:432px +} +.ui-768 .panel { + width:768px; + height:432px +} +.ui-768 #startBackground { + display:none; + background:url(../images/768/ui/startbg.jpg) +} +.ui-768 #menuBackground { + display:none; + background:url(../images/768/ui/menubg.jpg) +} +.ui-768 .seethrough { + background:transparent +} +.ui-768 .panelContent { + position:absolute; + top:0 +} +.ui-768 #shadowCanvas { + position:absolute; + top:0; + width:768px; + height:432px +} +.ui-768 .panelShadow img { + position:relative; + left:-225px; + position:relative; + top:-375px +} +.ui-768 .fBtnVBox { + width:227px; + margin:0 auto +} +.ui-768 .fBtn { + width:227px; + height:53px; + background-image:url(../images/768/ui/fBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:8px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 .fBtn:hover { + background-position:left -53px +} +.ui-768 .fBtn.disabled { + background-position:0 0; + cursor:inherit +} +.ui-768 .fBtn.disabled img,.ui-768 .fBtn.disabled div { + opacity:.6 +} +.ui-768 .fBtn img { + margin-top:2px +} +.ui-768 .mBtn { + width:176px; + height:53px; + background-image:url(../images/768/ui/mBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:8px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 .mBtn img { + margin-top:2px +} +.ui-768 .mBtn:hover { + background-position:left -53px +} +.ui-768 .lBtn { + width:317px; + height:53px; + background-image:url(../images/768/ui/lBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:8px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 .lBtn img { + margin-top:2px +} +.ui-768 .lBtn:hover { + background-position:left -53px +} +.ui-768 .sBtn { + width:128px; + height:49px; + background-image:url(../images/768/ui/sBtn_bgd.png); + background-repeat:no-repeat; + text-align:center; + margin-bottom:8px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 .sBtn img { + margin-top:2px +} +.ui-768 .sBtn:hover { + background-position:left -50px +} +.ui-768 .bBtn { + position:absolute; + top:369px; + left:11px; + width:59px; + height:56px; + background-image:url(../images/768/ui/bBtn_bgd.png); + background-repeat:no-repeat; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 .bBtn:hover { + background-position:left -56px +} +.ui-768 .iconBtn { + position:absolute +} +.ui-768 #loadingPanel { + display:none +} +.ui-768 #loadingPanel img { + margin-top:75px; + margin-left:315px +} +.ui-768 #boxScore,.ui-768 #levelScore { + position:absolute; + top:17px; + right:28px; + height:35px; + padding-right:38px; + background-image:url(../images/768/ui/star_result_small.png); + background-position:right top; + background-repeat:no-repeat +} +.ui-768 #boxes { + position:absolute; + top:90px; + left:233px +} +.ui-768 .boxOption { + width:300px; + height:300px +} +.ui-768 .boxCanvas { + position:absolute; + width:300px; + height:300px; + left:0; + top:0 +} +.ui-768 .boxOption .boxTitle { + position:absolute; + top:20px; + left:28px +} +.ui-768 .boxOmNom { + background-color:#2d2d35; + background-image:url(../images/768/ui/box_omnom.png); + width:225px; + height:105px; + position:absolute; + top:137px; + left:12px; + background-position:69px 30px; + background-repeat:no-repeat +} +.ui-768 #boxNavBack,.ui-768 #boxNavForward { + position:absolute; + top:192px; + left:154px; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 #boxNavBack div,.ui-768 #boxNavForward div { + width:44px; + height:53px; + background-image:url(../images/768/ui/box_nav_menu.png); + background-repeat:no-repeat +} +.ui-768 #boxNavBack .boxNavDisabled { + cursor:url(../cursors/cursor.cur),url(../cursors/cursor.png),auto; + background-position:left -53px; + opacity:.25 +} +.ui-768 #boxNavForward { + left:580px +} +.ui-768 #boxNavForward div { + background-position:-44px top +} +.ui-768 #boxNavForward .boxNavDisabled { + cursor:url(../cursors/cursor.cur),url(../cursors/cursor.png),auto; + background-position:-44px -53px; + opacity:.25 +} +.ui-768 .hideFromMouse { + pointer-events:none +} +.ui-768 #levelBackground { + display:none +} +.ui-768 .levelTape { + width:39px; + height:415px; + position:absolute; + left:365px; + top:8px; + background-image:url(../images/768/ui/leveltape.png); + background-repeat:no-repeat; + display:none +} +.ui-768 #levelOptions { + position:absolute; + top:47px; + left:225px; + width:10px; + height:10px +} +.ui-768 #levelPanel .option { + position:absolute; + width:91px; + height:106px +} +.ui-768 #levelPanel .option .txt { + margin-top:17px; + width:91px; + text-align:center +} +.ui-768 #levelPanel .stars0,.ui-768 #levelPanel .stars1,.ui-768 #levelPanel .stars2,.ui-768 #levelPanel .stars3 { + position:absolute; + top:61px; + left:26px; + width:66px; + height:36px; + background-image:url(../images/768/ui/options_stars_bgd.png); + background-repeat:no-repeat +} +.ui-768 #levelPanel .stars1 { + background-position:left -36px +} +.ui-768 #levelPanel .stars2 { + background-position:left -72px +} +.ui-768 #levelPanel .stars3 { + background-position:left -108px +} +.ui-768 #levelPanel .open { + background-image:url(../images/768/ui/level_bgd.png); + background-repeat:no-repeat +} +.ui-768 #levelPanel .locked { + background-image:url(../images/768/ui/level_bgd.png); + background-position:left -106px; + background-repeat:no-repeat +} +.ui-768 #levelPanel .purchase { + opacity:.4 +} +.ui-768 #levelPanel .option-small .stars0,.ui-768 #levelPanel .option-small .stars1,.ui-768 #levelPanel .option-small .stars2,.ui-768 #levelPanel .option-small .stars3 { + position:absolute; + top:40px; + left:17px; + width:44px; + height:23px; + background-image:url(../images/768/ui/options_stars_bgd_small.png); + background-repeat:no-repeat +} +.ui-768 #levelPanel .option-small .stars1 { + background-position:left -24px +} +.ui-768 #levelPanel .option-small .stars2 { + background-position:left -48px +} +.ui-768 #levelPanel .option-small .stars3 { + background-position:left -72px +} +.ui-768 #levelPanel .option.option-small { + position:absolute; + width:60px; + height:64px; + margin-top:11px; + text-align:center +} +.ui-768 #levelPanel .open.option-small { + background-image:url(../images/768/ui/level_bgd_small.png); + background-repeat:no-repeat +} +.ui-768 #levelPanel .locked.option-small { + background-image:url(../images/768/ui/level_bgd_small.png); + background-position:left -70px; + background-repeat:no-repeat +} +.ui-768 #levelPanel .option.option-small .txt { + margin-top:5px; + width:62px; + text-align:center +} +.ui-768 #gameBtnTray { + display:none; + position:absolute; + width:135px; + height:32px; + right:0; + top:3px +} +.ui-768 #gameBtnTray>div { + opacity:.7 +} +.ui-768 #gameBtnTray>div:hover { + opacity:1 +} +.ui-768 #gameRestartBtn { + width:32px; + height:32px; + background:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-75px 0; + position:absolute; + top:0; + left:33px +} +.ui-768 #gameMenuBtn { + position:absolute; + width:66px; + height:32px; + background:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:0 0; + top:0; + left:66px +} +.ui-768 #gameSound { + width:32px; + height:32px; + background:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + position:absolute; + top:0; + left:0 +} +.ui-768 #gameSound.allSound { + background-position:-450px 0 +} +.ui-768 #gameSound.effectsOnly { + background-position:-525px 0 +} +.ui-768 #gameSound.noSound { + background-position:-600px 0 +} +.ui-768 #gameMsg { + width:300px; + height:21px; + position:absolute; + right:143px; + top:-9px; + display:none; + text-align:right +} +.ui-768 #levelMenu { + position:absolute; + top:0; + width:768px; + height:335px; + background-color:rgba(0,0,0,.6); + display:none; + text-align:center; + padding-top:98px +} +.ui-768 #levelResults { + display:none; + width:428px; + height:339px; + margin:45px auto 0; + text-align:center; + font-family:gooddogplain; + font-size:24px; + color:#3c2110; + position:relative +} +.ui-768 #resultStatus { + position:absolute; + width:428px; + top:23px; + left:0; + text-align:center +} +.ui-768 #levelResults .starCase { + width:211px; + height:70px; + margin:0 auto; + position:relative; + top:71px +} +.ui-768 #resultTicker { + position:absolute; + top:150px; + left:0; + width:428px; + text-align:center +} +.ui-768 #resultTickerLabel { + display:none +} +.ui-768 #resultTickerValue { + padding-left:20px; + display:none +} +.ui-768 #resultTickerMessage { + display:none +} +.ui-768 #levelResults .star,.ui-768 #levelResults .starEmpty { + float:left; + width:70px; + height:70px; + background-image:url(../images/768/ui/star_result.png); + background-repeat:no-repeat +} +.ui-768 #levelResults .starEmpty { + background-position:left -70px +} +.ui-768 #levelResults .line { + position:absolute; + top:188px; + left:75px; + width:277px; + height:5px; + background-image:url(../images/768/ui/result_line.png); + background-repeat:no-repeat +} +.ui-768 #resultScore { + font-size:45px; + position:absolute; + top:188px; + width:428px; + display:none +} +.ui-768 #levelResults .btnCase { + width:413px; + height:56px; + position:absolute; + top:263px; + left:8px +} +.ui-768 #resultImproved { + width:88px; + height:88px; + background-repeat:no-repeat; + position:absolute; + top:143px; + left:308px; + display:none +} +.ui-768 #levelResults .btnCase .sBtn { + float:left +} +.ui-768 #lrMenuBtn { + margin:0 11px +} +.ui-768 #boxCutter { + background-image:url(../images/768/ui/boxcutter.png); + background-repeat:no-repeat; + display:none; + position:absolute; + top:211px; + left:134px; + width:254px; + height:241px +} +.ui-768 #tapeRoll { + background-image:url(../images/768/ui/taperoll.png); + background-repeat:no-repeat; + display:none; + position:absolute; + top:-11px; + left:327px; + width:98px; + height:131px +} +.ui-768 #gameCompletePanel { + background-image:url(../images/768/ui/gamecomplete.jpg); + background-repeat:no-repeat +} +.ui-768 #finalShareBtn { + position:absolute; + top:323px; + left:120px +} +.ui-768 #finalShareBtn img { + position:relative; + left:8px; + top:5px +} +.ui-768 #ffb { + position:absolute; + top:-6px; + left:-19px; + width:62px; + height:62px; + background:url(../images/768/ui/fb.png); + background-repeat:no-repeat +} +.ui-768 #gameBorder.gameComplete { + top:-21px; + left:-25px; + position:absolute; + background-repeat:no-repeat; + width:818px; + height:476px; + display:none; + background-image:url(../images/768/ui/gamecomplete_border.png); + background-repeat:no-repeat +} +.ui-768 #finalScore { + position:absolute; + top:255px; + height:35px; + width:768px +} +.ui-768 #finalScore img { + margin:0 auto; + display:block +} +.ui-768 #finalFunBtn { + position:absolute; + top:323px; + left:345px; + display:block +} +.ui-768 #finalFunBtn img { + position:relative; + left:11px; + top:5px +} +.ui-768 #funOmNom { + width:77px; + height:76px; + background-image:url(../images/768/ui/fun-omnom.png); + background-repeat:no-repeat; + position:absolute; + top:-17px; + left:-23px +} +.ui-768 #congrats { + position:absolute; + top:75px; + left:0; + width:100%; + text-align:center +} +.ui-768 #optionsPanel { + padding-top:15px +} +.ui-768 #optionsTitle { + position:relative; + width:377px; + left:-75px; + height:53px +} +.ui-768 #optionsTitle img { + margin:0 auto; + display:block +} +.ui-768 #creditsBtn { + display:none +} +.ui-768 .mini-button { + background-image:url(../images/768/ui/menu-options.png); + background-repeat:no-repeat; + width:107px; + height:51px; + display:inline-block; + margin-bottom:6px; + margin-right:4px; + text-align:center; + position:relative +} +.ui-768 .mini-button:hover { + background-position:0 -53px +} +.ui-768 .options-x { + background-image:url(../images/768/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-113px -53px; + width:23px; + height:23px +} +.ui-768 .options-check { + background-image:url(../images/768/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-59px -113px; + width:26px; + height:26px +} +.ui-768 .options-check-disabled { + background-image:url(../images/768/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-113px -77px; + width:26px; + height:26px +} +.ui-768 #options-speaker { + background-image:url(../images/768/ui/menu-options.png); + background-repeat:no-repeat; + background-position:0 -105px; + width:49px; + height:43px; + position:absolute; + left:30px; + top:5px +} +.ui-768 #soundBtn .options-x { + position:absolute; + bottom:4px; + left:53px; + display:none +} +.ui-768 #soundBtn.disabled #options-speaker { + opacity:.6 +} +.ui-768 #soundBtn.disabled .options-x { + display:block +} +.ui-768 #options-note { + background-image:url(../images/768/ui/menu-options.png); + background-repeat:no-repeat; + background-position:-113px 0; + width:41px; + height:47px; + position:absolute; + left:34px; + top:2px +} +.ui-768 #musicBtn .options-x { + position:absolute; + bottom:3px; + left:54px; + display:none +} +.ui-768 #musicBtn.disabled #options-note { + opacity:.6 +} +.ui-768 #musicBtn.disabled .options-x { + display:block +} +.ui-768 #dragBtn,.ui-768 #cutBtn { + background-image:url(../images/768/ui/menu-options.png); + background-repeat:no-repeat; + width:68px; + height:150px; + display:inline-block; + position:relative; + margin-left:29px +} +.ui-768 #dragBtn { + background-position:0 -149px; + background-repeat:no-repeat +} +.ui-768 #dragBtn .options-check-disabled { + position:absolute; + bottom:13px; + left:21px +} +.ui-768 #cutBtn { + background-position:-79px -149px +} +.ui-768 #cutBtn .options-check { + position:absolute; + bottom:11px; + left:23px +} +.ui-768 #cutBtn.disabled .options-check { + display:none +} +.ui-768 #dragText,.ui-768 #cutText { + margin-top:86px; + margin-left:-17px +} +.ui-768 #vid { + display:none; + width:768px; + height:432px; + position:absolute; + top:0; + left:0; + background:transparent +} +.ui-768 #fadeToBlack { + display:none; + width:768px; + height:432px; + position:absolute; + top:0; + left:0; + background:#000 +} +.ui-768 #menuLogo { + position:absolute; + left:242px; + top:30px; + width:254px; + height:226px; + background-image:url(../images/768/ui/ph_logo.png); + background-repeat:no-repeat +} +.ui-768 #menuBtnVbox { + position:absolute; + left:269px; + top:270px +} +.ui-768 #dmsg { + display:block; + position:relative; + margin:23px auto 0 +} +.ui-768 #dframe { + position:relative; + width:225px; + height:293px; + background-image:url(../images/768/ui/drawing-bg.png); + background-repeat:no-repeat; + margin:-8px auto 0 auto +} +.ui-768 #dpic { + position:absolute; + width:179px; + height:252px; + top:18px; + left:21px +} +.ui-768 .drawing1 { + background:url(../images/768/ui/drawing1.jpg) no-repeat +} +.ui-768 .drawing2 { + background:url(../images/768/ui/drawing2.jpg) no-repeat +} +.ui-768 .drawing3 { + background:url(../images/768/ui/drawing3.jpg) no-repeat +} +.drawing4 { + background:url(../images/768/ui/drawing4.jpg) no-repeat +} +.drawing5 { + background:url(../images/768/ui/drawing5.jpg) no-repeat +} +.drawing6 { + background:url(../images/768/ui/drawing6.jpg) no-repeat +} +.drawing7 { + background:url(../images/768/ui/drawing7.jpg) no-repeat +} +.drawing8 { + background:url(../images/768/ui/drawing8.jpg) no-repeat +} +.drawing9 { + background:url(../images/768/ui/drawing9.jpg) no-repeat +} +.drawing10 { + background:url(../images/768/ui/drawing10.jpg) no-repeat +} +.drawing11 { + background:url(../images/768/ui/drawing11.jpg) no-repeat +} +.drawing12 { + background:url(../images/768/ui/drawing12.jpg) no-repeat +} +.drawing13 { + background:url(../images/768/ui/drawing13.jpg) no-repeat +} +.drawing14 { + background:url(../images/768/ui/drawing14.jpg) no-repeat +} +.drawing15 { + background:url(../images/768/ui/drawing15.jpg) no-repeat +} +.drawing16 { + background:url(../images/768/ui/drawing16.jpg) no-repeat +} +.ui-768 #dshareBtn { + position:relative; + margin:5px auto 0 +} +.ui-768 #dfb { + position:absolute; + top:-6px; + left:-4px; + width:62px; + height:62px; + /*background-image:url(../images/768/ui/fb.png);*/ + background-repeat:no-repeat +} +.ui-768 #gameFooterContainer { + width:768px +} +.ui-768 #miniOptionsMenu { + width:300px; + height:38px; + position:absolute; + left:11px; + top:390px +} +.ui-768 #optionHd.activeResolution { + background:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-225px -38px; + opacity:.8 +} +.ui-768 #optionHd.inActiveResolution { + background:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-225px 0; + opacity:.6; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 #optionHd.inActiveResolution:hover { + opacity:.8 +} +.ui-768 #optionSd.activeResolution { + background:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-150px -38px; + opacity:.8 +} +.ui-768 #optionSd.inActiveResolution { + background:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + background-position:-150px 0; + opacity:.6; + cursor:url(../cursors/handcursor.cur),url(../cursors/handcursor.png),auto +} +.ui-768 #optionSd.inActiveResolution:hover { + opacity:.8 +} +.ui-768 #optionSound { + width:32px; + height:32px; + background-image:url(../images/768/ui/buttonsprite.png); + background-repeat:no-repeat; + position:absolute; + left:0; + opacity:.6 +} +.ui-768 #optionSound.allSound { + background-position:-450px 0 +} +.ui-768 #optionSound.effectsOnly { + background-position:-525px 0 +} +.ui-768 #optionSound.noSound { + background-position:-600px 0 +} +.ui-768 #optionSound:hover { + opacity:.7 +} +.ui-768 #optionMsg { + width:158px; + height:21px; + position:absolute; + left:101px; + top:-9px; + display:none +} +.ui-768 #popupWindow { + position:fixed; + top:0; + left:0; + right:0; + bottom:0; + display:none; + background-color:rgba(0,0,0,.4); + z-index:2 +} +.ui-768 #popupWindow .popupOuterFrame { + margin:98px auto 0; + background-image:url(../images/768/ui/popupouter.png); + background-repeat:no-repeat; + width:478px; + height:347px; + position:relative +} +.ui-768 #popupWindow .popupInnerFrame { + position:absolute; + background-image:url(../images/768/ui/popupinner.jpg); + background-repeat:no-repeat; + width:433px; + height:273px; + left:14px; + top:17px; + display:none +} +.ui-768 #popupWindow .bottomright { + position:absolute; + bottom:8px; + right:8px +} +.ui-768 #popupWindow #slowComputer { + background-image:url(../images/768/ui/popupinner-slow.jpg); + background-repeat:no-repeat +} +.ui-768 #slowComputerBtn { + position:absolute; + bottom:8px; + left:38px +} +.ui-768 #slowComputerBtn img { + margin-top:6px +} +.ui-768 #resetGame { + text-align:center +} +.ui-768 #resetText { + margin-top:19px +} +.ui-768 #resetYesBtn { + position:absolute; + bottom:71px; + left:38px +} +.ui-768 #resetNoBtn { + position:absolute; + bottom:71px; + left:218px +} +.ui-768 #resetHoldYes { + position:absolute; + bottom:15px; + width:435px; + text-align:center +} +.ui-768 #missingStars { + text-align:center +} +.ui-768 #missingLine1 { + margin-top:15px +} +.ui-768 #missingStar { + background-image:url(../images/768/ui/star_result_small.png); + background-repeat:no-repeat; + width:38px; + height:35px; + display:inline-block; + vertical-align:top; + margin-top:2px +} +.ui-768 #missingOkBtn { + display:inline-block +} +.ui-768 #flag { + background-image:url(../images/768/ui/flags.png); + background-repeat:no-repeat; + background-position:0 0; + display:inline-block; + width:38px; + height:29px; + position:relative; + top:-9px; + margin-left:8px +} +.ui-768 #resultImproved { + background-image:url(../images/768/ui/menu_result_en.png); + background-repeat:no-repeat +} +.ui-768 .lang-fr #resultImproved { + background-image:url(../images/768/ui/menu_result_fr.png) +} +.ui-768 .lang-fr #flag { + background-position:0 -30px +} +.ui-768 .lang-de #resultImproved { + background-image:url(../images/768/ui/menu_result_gr.png) +} +.ui-768 .lang-de #flag { + background-position:0 -60px +} +.ui-768 .lang-de #gameMenuBtn { + background-position:-641px 0 +} +.ui-768 .lang-ru #resultImproved { + background-image:url(../images/768/ui/menu_result_ru.png) +} +.ui-768 .lang-ru #flag { + background-position:0 -90px +} +.ui-768 .lang-ru #gameMenuBtn { + background-position:-750px 0 +} +.ui-768 #loaderWindow { + height:432px +} \ No newline at end of file diff --git a/projects/Cut The Rope/css/nojavascript.css b/projects/Cut The Rope/css/nojavascript.css new file mode 100644 index 000000000..09543ee9e --- /dev/null +++ b/projects/Cut The Rope/css/nojavascript.css @@ -0,0 +1,40 @@ +body +{ + min-height: 0px; +} + +#bg, #vignette-left, #vignette-right, #vignette-bottom, #umbrella +{ + display: block; +} + +#upgrade +{ + display: block; + width: 623px; + margin: 40px auto; + padding-top: 40px; +} + +#upgrade-header +{ + background: url(../images/page/upgrade-js.png); + width: 439px; + height: 444px; + margin: 0px auto; +} + +.video, +.magasin, +#game_top , +#upgrade-button { + display: none; +} + +.content_old_ie { + display: block; +} + +#lsWarning { + display: none; +} \ No newline at end of file diff --git a/projects/Cut The Rope/css/nosupport.css b/projects/Cut The Rope/css/nosupport.css new file mode 100644 index 000000000..b7b3a355c --- /dev/null +++ b/projects/Cut The Rope/css/nosupport.css @@ -0,0 +1,50 @@ +body +{ + min-height: 0px; + background: url("../images/page/tilebg.jpg") repeat; +} + +#bg, #vignette-left, #vignette-right, #vignette-bottom, #umbrella +{ + display: block; +} + +#upgrade +{ + display: block; + width: 623px; + margin: 40px auto; +} + +#upgrade-header +{ + background: url(../images/page/upgrade-msg.png); + width: 501px; + height: 459px; + margin: 0px auto; +} + +#upgrade-button +{ + background: url(../images/page/upgrade-btn.png); + width: 264px; + height: 75px; + margin: 20px auto; + position: relative; + left: -10px; + display: block; +} + +.video, +.magasin, +#game_top { + display: none; +} + +.content_old_ie { + display: block; +} + +#lsWarning { + display: none; +} \ No newline at end of file diff --git a/projects/Cut The Rope/cursors/cursor.cur b/projects/Cut The Rope/cursors/cursor.cur new file mode 100644 index 000000000..731868297 Binary files /dev/null and b/projects/Cut The Rope/cursors/cursor.cur differ diff --git a/projects/Cut The Rope/cursors/cursor.png b/projects/Cut The Rope/cursors/cursor.png new file mode 100644 index 000000000..9f891d77c Binary files /dev/null and b/projects/Cut The Rope/cursors/cursor.png differ diff --git a/projects/Cut The Rope/cursors/cursorActive.cur b/projects/Cut The Rope/cursors/cursorActive.cur new file mode 100644 index 000000000..d0716773f Binary files /dev/null and b/projects/Cut The Rope/cursors/cursorActive.cur differ diff --git a/projects/Cut The Rope/cursors/cursorActive.png b/projects/Cut The Rope/cursors/cursorActive.png new file mode 100644 index 000000000..169afbaa7 Binary files /dev/null and b/projects/Cut The Rope/cursors/cursorActive.png differ diff --git a/projects/Cut The Rope/cursors/handcursor.cur b/projects/Cut The Rope/cursors/handcursor.cur new file mode 100644 index 000000000..213a5af59 Binary files /dev/null and b/projects/Cut The Rope/cursors/handcursor.cur differ diff --git a/projects/Cut The Rope/cursors/handcursor.png b/projects/Cut The Rope/cursors/handcursor.png new file mode 100644 index 000000000..c676281b9 Binary files /dev/null and b/projects/Cut The Rope/cursors/handcursor.png differ diff --git a/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.eot b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.eot new file mode 100644 index 000000000..1b9a374c8 Binary files /dev/null and b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.eot differ diff --git a/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.svg b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.svg new file mode 100644 index 000000000..7f4c7bdf1 --- /dev/null +++ b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.svg @@ -0,0 +1,648 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.ttf b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.ttf new file mode 100644 index 000000000..14a8daa86 Binary files /dev/null and b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.ttf differ diff --git a/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.woff b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.woff new file mode 100644 index 000000000..c8342ed39 Binary files /dev/null and b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont.woff differ diff --git a/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont2.woff b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont2.woff new file mode 100644 index 000000000..374490121 Binary files /dev/null and b/projects/Cut The Rope/fonts/gooddog-new/gooddog_new-webfont2.woff differ diff --git a/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.eot b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.eot new file mode 100644 index 000000000..05ebed669 Binary files /dev/null and b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.eot differ diff --git a/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.svg b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.svg new file mode 100644 index 000000000..9a983b208 --- /dev/null +++ b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.svg @@ -0,0 +1,147 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Copyright c 1996 by Ethan Dunham Fonthead Design All rights reserved +Designer : Ethan Dunham +Foundry : Ethan Dunham Fonthead Design +Foundry URL : httpwwwfontheadcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.ttf b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.ttf new file mode 100644 index 000000000..da5af27bc Binary files /dev/null and b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.ttf differ diff --git a/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.woff b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.woff new file mode 100644 index 000000000..342d974fb Binary files /dev/null and b/projects/Cut The Rope/fonts/gooddog-plain/GoodDog-webfont.woff differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_01_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_01_p1.jpg new file mode 100644 index 000000000..948f12ae5 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_01_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_01_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_01_p2.jpg new file mode 100644 index 000000000..d314cecf5 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_01_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_02_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_02_p1.jpg new file mode 100644 index 000000000..16c235eac Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_02_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_02_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_02_p2.jpg new file mode 100644 index 000000000..a730b2e3b Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_02_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_03_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_03_p1.jpg new file mode 100644 index 000000000..dd6e7fb14 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_03_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_03_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_03_p2.jpg new file mode 100644 index 000000000..a06930a7c Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_03_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_04_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_04_p1.jpg new file mode 100644 index 000000000..8d1434228 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_04_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_04_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_04_p2.jpg new file mode 100644 index 000000000..5e4ad7c09 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_04_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_05_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_05_p1.jpg new file mode 100644 index 000000000..e8e41e37c Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_05_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_05_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_05_p2.jpg new file mode 100644 index 000000000..fc3f24fd3 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_05_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_06_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_06_p1.jpg new file mode 100644 index 000000000..38ad8afe1 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_06_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_06_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_06_p2.jpg new file mode 100644 index 000000000..aa1e3139c Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_06_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_07_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_07_p1.jpg new file mode 100644 index 000000000..73fc85d20 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_07_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_07_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_07_p2.jpg new file mode 100644 index 000000000..24fa6cf76 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_07_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_08_p1.png b/projects/Cut The Rope/images/1024/game/bgr_08_p1.png new file mode 100644 index 000000000..a04041ba4 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_08_p1.png differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_08_p2.png b/projects/Cut The Rope/images/1024/game/bgr_08_p2.png new file mode 100644 index 000000000..db3c2b334 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_08_p2.png differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_09_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_09_p1.jpg new file mode 100644 index 000000000..1ebc6f510 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_09_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_09_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_09_p2.jpg new file mode 100644 index 000000000..ffd67b944 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_09_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_10_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_10_p1.jpg new file mode 100644 index 000000000..70f4a5208 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_10_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_10_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_10_p2.jpg new file mode 100644 index 000000000..f651cf549 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_10_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_11_p1.jpg b/projects/Cut The Rope/images/1024/game/bgr_11_p1.jpg new file mode 100644 index 000000000..9523f1381 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_11_p1.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/bgr_11_p2.jpg b/projects/Cut The Rope/images/1024/game/bgr_11_p2.jpg new file mode 100644 index 000000000..939fa7531 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/bgr_11_p2.jpg differ diff --git a/projects/Cut The Rope/images/1024/game/big_font.png b/projects/Cut The Rope/images/1024/game/big_font.png new file mode 100644 index 000000000..17466a1a1 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/big_font.png differ diff --git a/projects/Cut The Rope/images/1024/game/char_animations.png b/projects/Cut The Rope/images/1024/game/char_animations.png new file mode 100644 index 000000000..732062c81 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/char_animations.png differ diff --git a/projects/Cut The Rope/images/1024/game/char_animations2.png b/projects/Cut The Rope/images/1024/game/char_animations2.png new file mode 100644 index 000000000..b76aa511d Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/char_animations2.png differ diff --git a/projects/Cut The Rope/images/1024/game/char_animations3.png b/projects/Cut The Rope/images/1024/game/char_animations3.png new file mode 100644 index 000000000..91c3faf19 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/char_animations3.png differ diff --git a/projects/Cut The Rope/images/1024/game/char_supports.png b/projects/Cut The Rope/images/1024/game/char_supports.png new file mode 100644 index 000000000..7c98ecf1b Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/char_supports.png differ diff --git a/projects/Cut The Rope/images/1024/game/font_numbers_big.png b/projects/Cut The Rope/images/1024/game/font_numbers_big.png new file mode 100644 index 000000000..441599d6b Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/font_numbers_big.png differ diff --git a/projects/Cut The Rope/images/1024/game/hud_star.png b/projects/Cut The Rope/images/1024/game/hud_star.png new file mode 100644 index 000000000..1e5c39819 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/hud_star.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_bee_hd.png b/projects/Cut The Rope/images/1024/game/obj_bee_hd.png new file mode 100644 index 000000000..e44dbd361 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_bee_hd.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_bouncer_01.png b/projects/Cut The Rope/images/1024/game/obj_bouncer_01.png new file mode 100644 index 000000000..181ad72e7 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_bouncer_01.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_bouncer_02.png b/projects/Cut The Rope/images/1024/game/obj_bouncer_02.png new file mode 100644 index 000000000..f1cf92300 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_bouncer_02.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_bubble_attached.png b/projects/Cut The Rope/images/1024/game/obj_bubble_attached.png new file mode 100644 index 000000000..011ace74e Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_bubble_attached.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_bubble_flight.png b/projects/Cut The Rope/images/1024/game/obj_bubble_flight.png new file mode 100644 index 000000000..ecee72837 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_bubble_flight.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_bubble_pop.png b/projects/Cut The Rope/images/1024/game/obj_bubble_pop.png new file mode 100644 index 000000000..f345e7b12 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_bubble_pop.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_candy_01.png b/projects/Cut The Rope/images/1024/game/obj_candy_01.png new file mode 100644 index 000000000..c6015afa7 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_candy_01.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_drawing_hidden.png b/projects/Cut The Rope/images/1024/game/obj_drawing_hidden.png new file mode 100644 index 000000000..d1653e83b Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_drawing_hidden.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_electrodes.png b/projects/Cut The Rope/images/1024/game/obj_electrodes.png new file mode 100644 index 000000000..cee49e1e0 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_electrodes.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_hat.png b/projects/Cut The Rope/images/1024/game/obj_hat.png new file mode 100644 index 000000000..5a1ea088d Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_hat.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_hook_01.png b/projects/Cut The Rope/images/1024/game/obj_hook_01.png new file mode 100644 index 000000000..80d35a64b Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_hook_01.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_hook_02.png b/projects/Cut The Rope/images/1024/game/obj_hook_02.png new file mode 100644 index 000000000..93cc54d35 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_hook_02.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_hook_auto.png b/projects/Cut The Rope/images/1024/game/obj_hook_auto.png new file mode 100644 index 000000000..ac1f364b1 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_hook_auto.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_hook_movable.png b/projects/Cut The Rope/images/1024/game/obj_hook_movable.png new file mode 100644 index 000000000..de74b4041 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_hook_movable.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_hook_regulated.png b/projects/Cut The Rope/images/1024/game/obj_hook_regulated.png new file mode 100644 index 000000000..e8aea1584 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_hook_regulated.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_pollen_hd.png b/projects/Cut The Rope/images/1024/game/obj_pollen_hd.png new file mode 100644 index 000000000..2206522a2 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_pollen_hd.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_pump.png b/projects/Cut The Rope/images/1024/game/obj_pump.png new file mode 100644 index 000000000..e3c25d208 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_pump.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_01.png b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_01.png new file mode 100644 index 000000000..23c0b3d4f Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_01.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_02.png b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_02.png new file mode 100644 index 000000000..8fe73104c Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_02.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_03.png b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_03.png new file mode 100644 index 000000000..02f51e5e4 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_03.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_04.png b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_04.png new file mode 100644 index 000000000..a44f3c02b Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_04.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_button.png b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_button.png new file mode 100644 index 000000000..7e1d535b3 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_rotatable_spikes_button.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_spider.png b/projects/Cut The Rope/images/1024/game/obj_spider.png new file mode 100644 index 000000000..7584de8fe Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_spider.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_spikes_01.png b/projects/Cut The Rope/images/1024/game/obj_spikes_01.png new file mode 100644 index 000000000..23bb4adc3 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_spikes_01.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_spikes_02.png b/projects/Cut The Rope/images/1024/game/obj_spikes_02.png new file mode 100644 index 000000000..6f09b9ec1 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_spikes_02.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_spikes_03.png b/projects/Cut The Rope/images/1024/game/obj_spikes_03.png new file mode 100644 index 000000000..9a4038067 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_spikes_03.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_spikes_04.png b/projects/Cut The Rope/images/1024/game/obj_spikes_04.png new file mode 100644 index 000000000..83012b980 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_spikes_04.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_star_disappear.png b/projects/Cut The Rope/images/1024/game/obj_star_disappear.png new file mode 100644 index 000000000..413a3174f Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_star_disappear.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_star_idle.png b/projects/Cut The Rope/images/1024/game/obj_star_idle.png new file mode 100644 index 000000000..e8fdf1f3e Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_star_idle.png differ diff --git a/projects/Cut The Rope/images/1024/game/obj_vinil.png b/projects/Cut The Rope/images/1024/game/obj_vinil.png new file mode 100644 index 000000000..2ccd8aa1e Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/obj_vinil.png differ diff --git a/projects/Cut The Rope/images/1024/game/small_font.png b/projects/Cut The Rope/images/1024/game/small_font.png new file mode 100644 index 000000000..100be45df Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/small_font.png differ diff --git a/projects/Cut The Rope/images/1024/game/tutorial_signs.png b/projects/Cut The Rope/images/1024/game/tutorial_signs.png new file mode 100644 index 000000000..0a0751fd3 Binary files /dev/null and b/projects/Cut The Rope/images/1024/game/tutorial_signs.png differ diff --git a/projects/Cut The Rope/images/1024/save.png b/projects/Cut The Rope/images/1024/save.png new file mode 100644 index 000000000..5caa05b4c Binary files /dev/null and b/projects/Cut The Rope/images/1024/save.png differ diff --git a/projects/Cut The Rope/images/1024/ui/bBtn_bgd.png b/projects/Cut The Rope/images/1024/ui/bBtn_bgd.png new file mode 100644 index 000000000..99856e9cf Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/bBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box10_bgd.png b/projects/Cut The Rope/images/1024/ui/box10_bgd.png new file mode 100644 index 000000000..1c8b2cfbf Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box10_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box11_bgd.png b/projects/Cut The Rope/images/1024/ui/box11_bgd.png new file mode 100644 index 000000000..9f8aaf110 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box11_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box1_bgd.png b/projects/Cut The Rope/images/1024/ui/box1_bgd.png new file mode 100644 index 000000000..59125d998 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box1_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box2_bgd.png b/projects/Cut The Rope/images/1024/ui/box2_bgd.png new file mode 100644 index 000000000..b0bc896ca Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box2_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box3_bgd.png b/projects/Cut The Rope/images/1024/ui/box3_bgd.png new file mode 100644 index 000000000..03d9d7e9a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box3_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box4_bgd.png b/projects/Cut The Rope/images/1024/ui/box4_bgd.png new file mode 100644 index 000000000..a98594623 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box4_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box5_bgd.png b/projects/Cut The Rope/images/1024/ui/box5_bgd.png new file mode 100644 index 000000000..43f4c3af5 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box5_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box6_bgd.png b/projects/Cut The Rope/images/1024/ui/box6_bgd.png new file mode 100644 index 000000000..9d412069a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box6_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box7_bgd.png b/projects/Cut The Rope/images/1024/ui/box7_bgd.png new file mode 100644 index 000000000..80badb51a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box7_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box8_bgd.png b/projects/Cut The Rope/images/1024/ui/box8_bgd.png new file mode 100644 index 000000000..bdf29ceb5 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box8_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box9_bgd.png b/projects/Cut The Rope/images/1024/ui/box9_bgd.png new file mode 100644 index 000000000..94f5258ac Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box9_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box_lock.png b/projects/Cut The Rope/images/1024/ui/box_lock.png new file mode 100644 index 000000000..037d39d4a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box_lock.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box_nav_menu.png b/projects/Cut The Rope/images/1024/ui/box_nav_menu.png new file mode 100644 index 000000000..bd6fe293f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box_nav_menu.png differ diff --git a/projects/Cut The Rope/images/1024/ui/box_omnom.png b/projects/Cut The Rope/images/1024/ui/box_omnom.png new file mode 100644 index 000000000..5d6db514e Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/box_omnom.png differ diff --git a/projects/Cut The Rope/images/1024/ui/boxcutter.png b/projects/Cut The Rope/images/1024/ui/boxcutter.png new file mode 100644 index 000000000..286d65893 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/boxcutter.png differ diff --git a/projects/Cut The Rope/images/1024/ui/boxmore_bgd.png b/projects/Cut The Rope/images/1024/ui/boxmore_bgd.png new file mode 100644 index 000000000..fe24d0d39 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/boxmore_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/buttonsprite.png b/projects/Cut The Rope/images/1024/ui/buttonsprite.png new file mode 100644 index 000000000..5fd92d25a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/buttonsprite.png differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing-bg.png b/projects/Cut The Rope/images/1024/ui/drawing-bg.png new file mode 100644 index 000000000..fec9b3ca6 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing-bg.png differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing1.jpg b/projects/Cut The Rope/images/1024/ui/drawing1.jpg new file mode 100644 index 000000000..5b961d738 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing1.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing10.jpg b/projects/Cut The Rope/images/1024/ui/drawing10.jpg new file mode 100644 index 000000000..c503fe63e Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing10.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing11.jpg b/projects/Cut The Rope/images/1024/ui/drawing11.jpg new file mode 100644 index 000000000..a1906711a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing11.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing12.jpg b/projects/Cut The Rope/images/1024/ui/drawing12.jpg new file mode 100644 index 000000000..d524a447b Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing12.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing13.jpg b/projects/Cut The Rope/images/1024/ui/drawing13.jpg new file mode 100644 index 000000000..5e6c4a24b Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing13.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing14.jpg b/projects/Cut The Rope/images/1024/ui/drawing14.jpg new file mode 100644 index 000000000..1d9797b1d Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing14.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing15.jpg b/projects/Cut The Rope/images/1024/ui/drawing15.jpg new file mode 100644 index 000000000..30884491f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing15.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing16.jpg b/projects/Cut The Rope/images/1024/ui/drawing16.jpg new file mode 100644 index 000000000..afda4050d Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing16.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing2.jpg b/projects/Cut The Rope/images/1024/ui/drawing2.jpg new file mode 100644 index 000000000..83d6709b8 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing2.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing3.jpg b/projects/Cut The Rope/images/1024/ui/drawing3.jpg new file mode 100644 index 000000000..a553db99e Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing3.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing4.jpg b/projects/Cut The Rope/images/1024/ui/drawing4.jpg new file mode 100644 index 000000000..56b774484 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing4.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing5.jpg b/projects/Cut The Rope/images/1024/ui/drawing5.jpg new file mode 100644 index 000000000..e0479d8ad Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing5.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing6.jpg b/projects/Cut The Rope/images/1024/ui/drawing6.jpg new file mode 100644 index 000000000..7c0474ebc Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing6.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing7.jpg b/projects/Cut The Rope/images/1024/ui/drawing7.jpg new file mode 100644 index 000000000..476908627 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing7.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing8.jpg b/projects/Cut The Rope/images/1024/ui/drawing8.jpg new file mode 100644 index 000000000..ed4d8a1fa Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing8.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing9.jpg b/projects/Cut The Rope/images/1024/ui/drawing9.jpg new file mode 100644 index 000000000..fb305cd18 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing9.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_1.jpg b/projects/Cut The Rope/images/1024/ui/drawing_1.jpg new file mode 100644 index 000000000..1f39ceb61 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_1.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_10.jpg b/projects/Cut The Rope/images/1024/ui/drawing_10.jpg new file mode 100644 index 000000000..79e375a17 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_10.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_11.jpg b/projects/Cut The Rope/images/1024/ui/drawing_11.jpg new file mode 100644 index 000000000..34674d92f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_11.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_12.jpg b/projects/Cut The Rope/images/1024/ui/drawing_12.jpg new file mode 100644 index 000000000..ae22fdba7 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_12.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_13.jpg b/projects/Cut The Rope/images/1024/ui/drawing_13.jpg new file mode 100644 index 000000000..e1d26c552 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_13.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_14.jpg b/projects/Cut The Rope/images/1024/ui/drawing_14.jpg new file mode 100644 index 000000000..ad1b22137 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_14.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_15.jpg b/projects/Cut The Rope/images/1024/ui/drawing_15.jpg new file mode 100644 index 000000000..a0f1bcc8d Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_15.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_16.jpg b/projects/Cut The Rope/images/1024/ui/drawing_16.jpg new file mode 100644 index 000000000..9b663c356 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_16.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_2.jpg b/projects/Cut The Rope/images/1024/ui/drawing_2.jpg new file mode 100644 index 000000000..aa0900ae7 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_2.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_3.jpg b/projects/Cut The Rope/images/1024/ui/drawing_3.jpg new file mode 100644 index 000000000..a0aa445b3 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_3.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_4.jpg b/projects/Cut The Rope/images/1024/ui/drawing_4.jpg new file mode 100644 index 000000000..00eb92fa1 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_4.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_5.jpg b/projects/Cut The Rope/images/1024/ui/drawing_5.jpg new file mode 100644 index 000000000..941c7285b Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_5.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_6.jpg b/projects/Cut The Rope/images/1024/ui/drawing_6.jpg new file mode 100644 index 000000000..2a4cbf218 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_6.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_7.jpg b/projects/Cut The Rope/images/1024/ui/drawing_7.jpg new file mode 100644 index 000000000..49d904fdc Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_7.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_8.jpg b/projects/Cut The Rope/images/1024/ui/drawing_8.jpg new file mode 100644 index 000000000..a9ad7974f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_8.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/drawing_9.jpg b/projects/Cut The Rope/images/1024/ui/drawing_9.jpg new file mode 100644 index 000000000..c3e199f69 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/drawing_9.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/fBtn_bgd.png b/projects/Cut The Rope/images/1024/ui/fBtn_bgd.png new file mode 100644 index 000000000..9f4dda77f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/fBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/fb.png b/projects/Cut The Rope/images/1024/ui/fb.png new file mode 100644 index 000000000..32a48255d Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/fb.png differ diff --git a/projects/Cut The Rope/images/1024/ui/flags.png b/projects/Cut The Rope/images/1024/ui/flags.png new file mode 100644 index 000000000..8d92c8d59 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/flags.png differ diff --git a/projects/Cut The Rope/images/1024/ui/fun-omnom.png b/projects/Cut The Rope/images/1024/ui/fun-omnom.png new file mode 100644 index 000000000..c58d54b60 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/fun-omnom.png differ diff --git a/projects/Cut The Rope/images/1024/ui/gamecomplete.jpg b/projects/Cut The Rope/images/1024/ui/gamecomplete.jpg new file mode 100644 index 000000000..bfe9b02c9 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/gamecomplete.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/gamecomplete_border.png b/projects/Cut The Rope/images/1024/ui/gamecomplete_border.png new file mode 100644 index 000000000..2b8275c5a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/gamecomplete_border.png differ diff --git a/projects/Cut The Rope/images/1024/ui/lBtn_bgd.png b/projects/Cut The Rope/images/1024/ui/lBtn_bgd.png new file mode 100644 index 000000000..1f9f0d92b Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/lBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/level_bgd.png b/projects/Cut The Rope/images/1024/ui/level_bgd.png new file mode 100644 index 000000000..0b19634f9 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/level_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/level_bgd_small.png b/projects/Cut The Rope/images/1024/ui/level_bgd_small.png new file mode 100644 index 000000000..382351f06 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/level_bgd_small.png differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg1.jpg b/projects/Cut The Rope/images/1024/ui/levelbg1.jpg new file mode 100644 index 000000000..bef5abe8f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg1.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg10.jpg b/projects/Cut The Rope/images/1024/ui/levelbg10.jpg new file mode 100644 index 000000000..8d6b86e7f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg10.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg11.jpg b/projects/Cut The Rope/images/1024/ui/levelbg11.jpg new file mode 100644 index 000000000..f8e60760e Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg11.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg2.jpg b/projects/Cut The Rope/images/1024/ui/levelbg2.jpg new file mode 100644 index 000000000..3dbba0a0c Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg2.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg3.jpg b/projects/Cut The Rope/images/1024/ui/levelbg3.jpg new file mode 100644 index 000000000..dc807247e Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg3.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg4.jpg b/projects/Cut The Rope/images/1024/ui/levelbg4.jpg new file mode 100644 index 000000000..9968c8a70 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg4.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg5.jpg b/projects/Cut The Rope/images/1024/ui/levelbg5.jpg new file mode 100644 index 000000000..d7f34c384 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg5.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg6.jpg b/projects/Cut The Rope/images/1024/ui/levelbg6.jpg new file mode 100644 index 000000000..049864dea Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg6.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg7.jpg b/projects/Cut The Rope/images/1024/ui/levelbg7.jpg new file mode 100644 index 000000000..c7ee24ee8 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg7.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg8.jpg b/projects/Cut The Rope/images/1024/ui/levelbg8.jpg new file mode 100644 index 000000000..857c47695 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg8.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/levelbg9.jpg b/projects/Cut The Rope/images/1024/ui/levelbg9.jpg new file mode 100644 index 000000000..165fdfd1f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/levelbg9.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/leveltape.png b/projects/Cut The Rope/images/1024/ui/leveltape.png new file mode 100644 index 000000000..3b1c19bf3 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/leveltape.png differ diff --git a/projects/Cut The Rope/images/1024/ui/leveltape_left.png b/projects/Cut The Rope/images/1024/ui/leveltape_left.png new file mode 100644 index 000000000..68716b0d7 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/leveltape_left.png differ diff --git a/projects/Cut The Rope/images/1024/ui/leveltape_right.png b/projects/Cut The Rope/images/1024/ui/leveltape_right.png new file mode 100644 index 000000000..58ca2e05e Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/leveltape_right.png differ diff --git a/projects/Cut The Rope/images/1024/ui/mBtn_bgd.png b/projects/Cut The Rope/images/1024/ui/mBtn_bgd.png new file mode 100644 index 000000000..078fef2eb Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/mBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu-options.png b/projects/Cut The Rope/images/1024/ui/menu-options.png new file mode 100644 index 000000000..a73fbeae7 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu-options.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_br.png b/projects/Cut The Rope/images/1024/ui/menu_result_br.png new file mode 100644 index 000000000..51eacfd8f Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_br.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_en.png b/projects/Cut The Rope/images/1024/ui/menu_result_en.png new file mode 100644 index 000000000..21c60142a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_en.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_es.png b/projects/Cut The Rope/images/1024/ui/menu_result_es.png new file mode 100644 index 000000000..45895da6b Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_es.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_fr.png b/projects/Cut The Rope/images/1024/ui/menu_result_fr.png new file mode 100644 index 000000000..339e01019 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_fr.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_gr.png b/projects/Cut The Rope/images/1024/ui/menu_result_gr.png new file mode 100644 index 000000000..cb2723d77 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_gr.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_it.png b/projects/Cut The Rope/images/1024/ui/menu_result_it.png new file mode 100644 index 000000000..904f372bc Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_it.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_ja.png b/projects/Cut The Rope/images/1024/ui/menu_result_ja.png new file mode 100644 index 000000000..6432d4e23 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_ja.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_ko.png b/projects/Cut The Rope/images/1024/ui/menu_result_ko.png new file mode 100644 index 000000000..075a7b571 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_ko.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_nl.png b/projects/Cut The Rope/images/1024/ui/menu_result_nl.png new file mode 100644 index 000000000..4ff41db88 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_nl.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_ru.png b/projects/Cut The Rope/images/1024/ui/menu_result_ru.png new file mode 100644 index 000000000..70fb927be Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_ru.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menu_result_zh.png b/projects/Cut The Rope/images/1024/ui/menu_result_zh.png new file mode 100644 index 000000000..222c68c8a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menu_result_zh.png differ diff --git a/projects/Cut The Rope/images/1024/ui/menubg.jpg b/projects/Cut The Rope/images/1024/ui/menubg.jpg new file mode 100644 index 000000000..8b705ef5e Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/menubg.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/options_stars_bgd.png b/projects/Cut The Rope/images/1024/ui/options_stars_bgd.png new file mode 100644 index 000000000..ff80e8dc2 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/options_stars_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/options_stars_bgd_small.png b/projects/Cut The Rope/images/1024/ui/options_stars_bgd_small.png new file mode 100644 index 000000000..d1ba55c3a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/options_stars_bgd_small.png differ diff --git a/projects/Cut The Rope/images/1024/ui/perfect_mark.png b/projects/Cut The Rope/images/1024/ui/perfect_mark.png new file mode 100644 index 000000000..9935d902a Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/perfect_mark.png differ diff --git a/projects/Cut The Rope/images/1024/ui/ph_logo.png b/projects/Cut The Rope/images/1024/ui/ph_logo.png new file mode 100644 index 000000000..a7133eaab Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/ph_logo.png differ diff --git a/projects/Cut The Rope/images/1024/ui/pin-omnom.png b/projects/Cut The Rope/images/1024/ui/pin-omnom.png new file mode 100644 index 000000000..f7c933b81 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/pin-omnom.png differ diff --git a/projects/Cut The Rope/images/1024/ui/popupinner-slow.jpg b/projects/Cut The Rope/images/1024/ui/popupinner-slow.jpg new file mode 100644 index 000000000..34bfee326 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/popupinner-slow.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/popupinner.jpg b/projects/Cut The Rope/images/1024/ui/popupinner.jpg new file mode 100644 index 000000000..6a8549aa7 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/popupinner.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/popupouter.png b/projects/Cut The Rope/images/1024/ui/popupouter.png new file mode 100644 index 000000000..5c4c5f2bf Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/popupouter.png differ diff --git a/projects/Cut The Rope/images/1024/ui/result_line.png b/projects/Cut The Rope/images/1024/ui/result_line.png new file mode 100644 index 000000000..5cf69ae5d Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/result_line.png differ diff --git a/projects/Cut The Rope/images/1024/ui/sBtn_bgd.png b/projects/Cut The Rope/images/1024/ui/sBtn_bgd.png new file mode 100644 index 000000000..ef230b8da Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/sBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/1024/ui/shadow.png b/projects/Cut The Rope/images/1024/ui/shadow.png new file mode 100644 index 000000000..11e428d02 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/shadow.png differ diff --git a/projects/Cut The Rope/images/1024/ui/star_result.png b/projects/Cut The Rope/images/1024/ui/star_result.png new file mode 100644 index 000000000..727bd93dc Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/star_result.png differ diff --git a/projects/Cut The Rope/images/1024/ui/star_result_small.png b/projects/Cut The Rope/images/1024/ui/star_result_small.png new file mode 100644 index 000000000..0a7e88c15 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/star_result_small.png differ diff --git a/projects/Cut The Rope/images/1024/ui/startbg.jpg b/projects/Cut The Rope/images/1024/ui/startbg.jpg new file mode 100644 index 000000000..f15a7e3f6 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/startbg.jpg differ diff --git a/projects/Cut The Rope/images/1024/ui/taperoll.png b/projects/Cut The Rope/images/1024/ui/taperoll.png new file mode 100644 index 000000000..944deadd9 Binary files /dev/null and b/projects/Cut The Rope/images/1024/ui/taperoll.png differ diff --git a/projects/Cut The Rope/images/768/ui/bBtn_bgd.png b/projects/Cut The Rope/images/768/ui/bBtn_bgd.png new file mode 100644 index 000000000..663d2dfd0 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/bBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box10_bgd.png b/projects/Cut The Rope/images/768/ui/box10_bgd.png new file mode 100644 index 000000000..07316dd16 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box10_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box11_bgd.png b/projects/Cut The Rope/images/768/ui/box11_bgd.png new file mode 100644 index 000000000..a38ab38cd Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box11_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box1_bgd.png b/projects/Cut The Rope/images/768/ui/box1_bgd.png new file mode 100644 index 000000000..1d40433ab Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box1_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box2_bgd.png b/projects/Cut The Rope/images/768/ui/box2_bgd.png new file mode 100644 index 000000000..ed6e17a69 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box2_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box3_bgd.png b/projects/Cut The Rope/images/768/ui/box3_bgd.png new file mode 100644 index 000000000..b8f862ddf Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box3_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box4_bgd.png b/projects/Cut The Rope/images/768/ui/box4_bgd.png new file mode 100644 index 000000000..82dbc9acb Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box4_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box5_bgd.png b/projects/Cut The Rope/images/768/ui/box5_bgd.png new file mode 100644 index 000000000..5d2248190 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box5_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box6_bgd.png b/projects/Cut The Rope/images/768/ui/box6_bgd.png new file mode 100644 index 000000000..39d7d84bf Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box6_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box7_bgd.png b/projects/Cut The Rope/images/768/ui/box7_bgd.png new file mode 100644 index 000000000..13708f811 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box7_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box8_bgd.png b/projects/Cut The Rope/images/768/ui/box8_bgd.png new file mode 100644 index 000000000..ea3a1d138 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box8_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box9_bgd.png b/projects/Cut The Rope/images/768/ui/box9_bgd.png new file mode 100644 index 000000000..7f2ec8096 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box9_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/box_lock.png b/projects/Cut The Rope/images/768/ui/box_lock.png new file mode 100644 index 000000000..fab27a428 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box_lock.png differ diff --git a/projects/Cut The Rope/images/768/ui/box_nav_menu.png b/projects/Cut The Rope/images/768/ui/box_nav_menu.png new file mode 100644 index 000000000..6302d4c1a Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box_nav_menu.png differ diff --git a/projects/Cut The Rope/images/768/ui/box_omnom.png b/projects/Cut The Rope/images/768/ui/box_omnom.png new file mode 100644 index 000000000..b83aa2807 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/box_omnom.png differ diff --git a/projects/Cut The Rope/images/768/ui/boxcutter.png b/projects/Cut The Rope/images/768/ui/boxcutter.png new file mode 100644 index 000000000..8edb5f37b Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/boxcutter.png differ diff --git a/projects/Cut The Rope/images/768/ui/boxmore_bgd.png b/projects/Cut The Rope/images/768/ui/boxmore_bgd.png new file mode 100644 index 000000000..936efbf02 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/boxmore_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/buttonsprite.png b/projects/Cut The Rope/images/768/ui/buttonsprite.png new file mode 100644 index 000000000..de19cb70a Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/buttonsprite.png differ diff --git a/projects/Cut The Rope/images/768/ui/drawing-bg.png b/projects/Cut The Rope/images/768/ui/drawing-bg.png new file mode 100644 index 000000000..0f33930b7 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing-bg.png differ diff --git a/projects/Cut The Rope/images/768/ui/drawing1.jpg b/projects/Cut The Rope/images/768/ui/drawing1.jpg new file mode 100644 index 000000000..b527645e9 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing1.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing10.jpg b/projects/Cut The Rope/images/768/ui/drawing10.jpg new file mode 100644 index 000000000..52ba76df5 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing10.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing11.jpg b/projects/Cut The Rope/images/768/ui/drawing11.jpg new file mode 100644 index 000000000..d5df53bbc Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing11.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing12.jpg b/projects/Cut The Rope/images/768/ui/drawing12.jpg new file mode 100644 index 000000000..c6546665a Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing12.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing13.jpg b/projects/Cut The Rope/images/768/ui/drawing13.jpg new file mode 100644 index 000000000..94ecd35ab Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing13.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing14.jpg b/projects/Cut The Rope/images/768/ui/drawing14.jpg new file mode 100644 index 000000000..d072e3141 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing14.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing15.jpg b/projects/Cut The Rope/images/768/ui/drawing15.jpg new file mode 100644 index 000000000..edd65ce39 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing15.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing16.jpg b/projects/Cut The Rope/images/768/ui/drawing16.jpg new file mode 100644 index 000000000..b6294f586 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing16.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing2.jpg b/projects/Cut The Rope/images/768/ui/drawing2.jpg new file mode 100644 index 000000000..408fcb0be Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing2.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing3.jpg b/projects/Cut The Rope/images/768/ui/drawing3.jpg new file mode 100644 index 000000000..9da867246 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing3.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing4.jpg b/projects/Cut The Rope/images/768/ui/drawing4.jpg new file mode 100644 index 000000000..32f7452fd Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing4.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing5.jpg b/projects/Cut The Rope/images/768/ui/drawing5.jpg new file mode 100644 index 000000000..8b972f448 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing5.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing6.jpg b/projects/Cut The Rope/images/768/ui/drawing6.jpg new file mode 100644 index 000000000..661fd9867 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing6.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing7.jpg b/projects/Cut The Rope/images/768/ui/drawing7.jpg new file mode 100644 index 000000000..80eff05fa Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing7.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing8.jpg b/projects/Cut The Rope/images/768/ui/drawing8.jpg new file mode 100644 index 000000000..94b3ecc13 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing8.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/drawing9.jpg b/projects/Cut The Rope/images/768/ui/drawing9.jpg new file mode 100644 index 000000000..46f370aab Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/drawing9.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/fBtn_bgd.png b/projects/Cut The Rope/images/768/ui/fBtn_bgd.png new file mode 100644 index 000000000..4a3557958 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/fBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/fb.png b/projects/Cut The Rope/images/768/ui/fb.png new file mode 100644 index 000000000..a863e2b5d Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/fb.png differ diff --git a/projects/Cut The Rope/images/768/ui/flags.png b/projects/Cut The Rope/images/768/ui/flags.png new file mode 100644 index 000000000..774534e25 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/flags.png differ diff --git a/projects/Cut The Rope/images/768/ui/fun-omnom.png b/projects/Cut The Rope/images/768/ui/fun-omnom.png new file mode 100644 index 000000000..08017d7c7 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/fun-omnom.png differ diff --git a/projects/Cut The Rope/images/768/ui/gamecomplete.jpg b/projects/Cut The Rope/images/768/ui/gamecomplete.jpg new file mode 100644 index 000000000..af24cb5c7 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/gamecomplete.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/gamecomplete_border.png b/projects/Cut The Rope/images/768/ui/gamecomplete_border.png new file mode 100644 index 000000000..d1e821533 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/gamecomplete_border.png differ diff --git a/projects/Cut The Rope/images/768/ui/lBtn_bgd.png b/projects/Cut The Rope/images/768/ui/lBtn_bgd.png new file mode 100644 index 000000000..2db762fc8 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/lBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/level_bgd.png b/projects/Cut The Rope/images/768/ui/level_bgd.png new file mode 100644 index 000000000..537bc0b0b Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/level_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/level_bgd_small.png b/projects/Cut The Rope/images/768/ui/level_bgd_small.png new file mode 100644 index 000000000..5ad9ee5bb Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/level_bgd_small.png differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg1.jpg b/projects/Cut The Rope/images/768/ui/levelbg1.jpg new file mode 100644 index 000000000..b43f098c2 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg1.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg10.jpg b/projects/Cut The Rope/images/768/ui/levelbg10.jpg new file mode 100644 index 000000000..ecd25cdf4 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg10.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg11.jpg b/projects/Cut The Rope/images/768/ui/levelbg11.jpg new file mode 100644 index 000000000..2930e00fc Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg11.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg2.jpg b/projects/Cut The Rope/images/768/ui/levelbg2.jpg new file mode 100644 index 000000000..b4b60bff4 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg2.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg3.jpg b/projects/Cut The Rope/images/768/ui/levelbg3.jpg new file mode 100644 index 000000000..e0565d0b9 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg3.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg4.jpg b/projects/Cut The Rope/images/768/ui/levelbg4.jpg new file mode 100644 index 000000000..7f8ff3bbf Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg4.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg5.jpg b/projects/Cut The Rope/images/768/ui/levelbg5.jpg new file mode 100644 index 000000000..0b3158d81 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg5.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg6.jpg b/projects/Cut The Rope/images/768/ui/levelbg6.jpg new file mode 100644 index 000000000..cda178c15 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg6.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg7.jpg b/projects/Cut The Rope/images/768/ui/levelbg7.jpg new file mode 100644 index 000000000..6cf38342e Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg7.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg8.jpg b/projects/Cut The Rope/images/768/ui/levelbg8.jpg new file mode 100644 index 000000000..55d52f67a Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg8.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/levelbg9.jpg b/projects/Cut The Rope/images/768/ui/levelbg9.jpg new file mode 100644 index 000000000..9507206c1 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/levelbg9.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/leveltape.png b/projects/Cut The Rope/images/768/ui/leveltape.png new file mode 100644 index 000000000..a435d3912 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/leveltape.png differ diff --git a/projects/Cut The Rope/images/768/ui/leveltape_left.png b/projects/Cut The Rope/images/768/ui/leveltape_left.png new file mode 100644 index 000000000..5b7ae082e Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/leveltape_left.png differ diff --git a/projects/Cut The Rope/images/768/ui/leveltape_right.png b/projects/Cut The Rope/images/768/ui/leveltape_right.png new file mode 100644 index 000000000..21245e37f Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/leveltape_right.png differ diff --git a/projects/Cut The Rope/images/768/ui/mBtn_bgd.png b/projects/Cut The Rope/images/768/ui/mBtn_bgd.png new file mode 100644 index 000000000..e5b02b884 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/mBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/menu-options.png b/projects/Cut The Rope/images/768/ui/menu-options.png new file mode 100644 index 000000000..a09582451 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/menu-options.png differ diff --git a/projects/Cut The Rope/images/768/ui/menu_result_en.png b/projects/Cut The Rope/images/768/ui/menu_result_en.png new file mode 100644 index 000000000..f7885172a Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/menu_result_en.png differ diff --git a/projects/Cut The Rope/images/768/ui/menu_result_fr.png b/projects/Cut The Rope/images/768/ui/menu_result_fr.png new file mode 100644 index 000000000..0c3e763cf Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/menu_result_fr.png differ diff --git a/projects/Cut The Rope/images/768/ui/menu_result_gr.png b/projects/Cut The Rope/images/768/ui/menu_result_gr.png new file mode 100644 index 000000000..d7a095bed Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/menu_result_gr.png differ diff --git a/projects/Cut The Rope/images/768/ui/menu_result_ru.png b/projects/Cut The Rope/images/768/ui/menu_result_ru.png new file mode 100644 index 000000000..07fa40eca Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/menu_result_ru.png differ diff --git a/projects/Cut The Rope/images/768/ui/menubg.jpg b/projects/Cut The Rope/images/768/ui/menubg.jpg new file mode 100644 index 000000000..1d6d48b09 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/menubg.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/options_stars_bgd.png b/projects/Cut The Rope/images/768/ui/options_stars_bgd.png new file mode 100644 index 000000000..0a08f39a0 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/options_stars_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/options_stars_bgd_small.png b/projects/Cut The Rope/images/768/ui/options_stars_bgd_small.png new file mode 100644 index 000000000..bda2b2904 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/options_stars_bgd_small.png differ diff --git a/projects/Cut The Rope/images/768/ui/perfect_mark.png b/projects/Cut The Rope/images/768/ui/perfect_mark.png new file mode 100644 index 000000000..488f308d0 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/perfect_mark.png differ diff --git a/projects/Cut The Rope/images/768/ui/ph_logo.png b/projects/Cut The Rope/images/768/ui/ph_logo.png new file mode 100644 index 000000000..0a1ac06ff Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/ph_logo.png differ diff --git a/projects/Cut The Rope/images/768/ui/popupinner-slow.jpg b/projects/Cut The Rope/images/768/ui/popupinner-slow.jpg new file mode 100644 index 000000000..99efb502e Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/popupinner-slow.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/popupinner.jpg b/projects/Cut The Rope/images/768/ui/popupinner.jpg new file mode 100644 index 000000000..6c10bd6cf Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/popupinner.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/popupouter.png b/projects/Cut The Rope/images/768/ui/popupouter.png new file mode 100644 index 000000000..6c239cd67 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/popupouter.png differ diff --git a/projects/Cut The Rope/images/768/ui/result_line.png b/projects/Cut The Rope/images/768/ui/result_line.png new file mode 100644 index 000000000..9219f9f9c Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/result_line.png differ diff --git a/projects/Cut The Rope/images/768/ui/sBtn_bgd.png b/projects/Cut The Rope/images/768/ui/sBtn_bgd.png new file mode 100644 index 000000000..423b97ae3 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/sBtn_bgd.png differ diff --git a/projects/Cut The Rope/images/768/ui/shadow.png b/projects/Cut The Rope/images/768/ui/shadow.png new file mode 100644 index 000000000..6b8d6fabf Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/shadow.png differ diff --git a/projects/Cut The Rope/images/768/ui/star_result.png b/projects/Cut The Rope/images/768/ui/star_result.png new file mode 100644 index 000000000..4e310933b Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/star_result.png differ diff --git a/projects/Cut The Rope/images/768/ui/star_result_small.png b/projects/Cut The Rope/images/768/ui/star_result_small.png new file mode 100644 index 000000000..78e6bed6a Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/star_result_small.png differ diff --git a/projects/Cut The Rope/images/768/ui/startbg.jpg b/projects/Cut The Rope/images/768/ui/startbg.jpg new file mode 100644 index 000000000..43ce7ec55 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/startbg.jpg differ diff --git a/projects/Cut The Rope/images/768/ui/taperoll.png b/projects/Cut The Rope/images/768/ui/taperoll.png new file mode 100644 index 000000000..a78578230 Binary files /dev/null and b/projects/Cut The Rope/images/768/ui/taperoll.png differ diff --git a/projects/Cut The Rope/images/ie/1024/ie9msg.png b/projects/Cut The Rope/images/ie/1024/ie9msg.png new file mode 100644 index 000000000..c3f970db9 Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/ie9msg.png differ diff --git a/projects/Cut The Rope/images/ie/1024/ielogo.png b/projects/Cut The Rope/images/ie/1024/ielogo.png new file mode 100644 index 000000000..9410b05c9 Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/ielogo.png differ diff --git a/projects/Cut The Rope/images/ie/1024/pin-chair.png b/projects/Cut The Rope/images/ie/1024/pin-chair.png new file mode 100644 index 000000000..fecc8cdf4 Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/pin-chair.png differ diff --git a/projects/Cut The Rope/images/ie/1024/pin-chairshadow.png b/projects/Cut The Rope/images/ie/1024/pin-chairshadow.png new file mode 100644 index 000000000..e2a6d1d27 Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/pin-chairshadow.png differ diff --git a/projects/Cut The Rope/images/ie/1024/pin-cursor.png b/projects/Cut The Rope/images/ie/1024/pin-cursor.png new file mode 100644 index 000000000..4225b12ef Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/pin-cursor.png differ diff --git a/projects/Cut The Rope/images/ie/1024/pin-ieprompt.png b/projects/Cut The Rope/images/ie/1024/pin-ieprompt.png new file mode 100644 index 000000000..967c962bb Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/pin-ieprompt.png differ diff --git a/projects/Cut The Rope/images/ie/1024/pin-omnom.png b/projects/Cut The Rope/images/ie/1024/pin-omnom.png new file mode 100644 index 000000000..f7c933b81 Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/pin-omnom.png differ diff --git a/projects/Cut The Rope/images/ie/1024/pin-prompt.png b/projects/Cut The Rope/images/ie/1024/pin-prompt.png new file mode 100644 index 000000000..e234b654d Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/pin-prompt.png differ diff --git a/projects/Cut The Rope/images/ie/1024/pin-taskbar.png b/projects/Cut The Rope/images/ie/1024/pin-taskbar.png new file mode 100644 index 000000000..84e91cbb8 Binary files /dev/null and b/projects/Cut The Rope/images/ie/1024/pin-taskbar.png differ diff --git a/projects/Cut The Rope/images/ie/768/ie9msg.png b/projects/Cut The Rope/images/ie/768/ie9msg.png new file mode 100644 index 000000000..f8534fb99 Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/ie9msg.png differ diff --git a/projects/Cut The Rope/images/ie/768/ielogo.png b/projects/Cut The Rope/images/ie/768/ielogo.png new file mode 100644 index 000000000..de37d99e5 Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/ielogo.png differ diff --git a/projects/Cut The Rope/images/ie/768/pin-chair.png b/projects/Cut The Rope/images/ie/768/pin-chair.png new file mode 100644 index 000000000..4e9e6878a Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/pin-chair.png differ diff --git a/projects/Cut The Rope/images/ie/768/pin-chairshadow.png b/projects/Cut The Rope/images/ie/768/pin-chairshadow.png new file mode 100644 index 000000000..101bfe631 Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/pin-chairshadow.png differ diff --git a/projects/Cut The Rope/images/ie/768/pin-cursor.png b/projects/Cut The Rope/images/ie/768/pin-cursor.png new file mode 100644 index 000000000..7b335a1af Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/pin-cursor.png differ diff --git a/projects/Cut The Rope/images/ie/768/pin-ieprompt.png b/projects/Cut The Rope/images/ie/768/pin-ieprompt.png new file mode 100644 index 000000000..ad248c471 Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/pin-ieprompt.png differ diff --git a/projects/Cut The Rope/images/ie/768/pin-omnom.png b/projects/Cut The Rope/images/ie/768/pin-omnom.png new file mode 100644 index 000000000..0524fa617 Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/pin-omnom.png differ diff --git a/projects/Cut The Rope/images/ie/768/pin-prompt.png b/projects/Cut The Rope/images/ie/768/pin-prompt.png new file mode 100644 index 000000000..5a7865a15 Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/pin-prompt.png differ diff --git a/projects/Cut The Rope/images/ie/768/pin-taskbar.png b/projects/Cut The Rope/images/ie/768/pin-taskbar.png new file mode 100644 index 000000000..a82ea8e2f Binary files /dev/null and b/projects/Cut The Rope/images/ie/768/pin-taskbar.png differ diff --git a/projects/Cut The Rope/images/page/404.png b/projects/Cut The Rope/images/page/404.png new file mode 100644 index 000000000..52956a7d0 Binary files /dev/null and b/projects/Cut The Rope/images/page/404.png differ diff --git a/projects/Cut The Rope/images/page/error.png b/projects/Cut The Rope/images/page/error.png new file mode 100644 index 000000000..c6fe52c90 Binary files /dev/null and b/projects/Cut The Rope/images/page/error.png differ diff --git a/projects/Cut The Rope/images/page/loader-bg.jpg b/projects/Cut The Rope/images/page/loader-bg.jpg new file mode 100644 index 000000000..c0549e691 Binary files /dev/null and b/projects/Cut The Rope/images/page/loader-bg.jpg differ diff --git a/projects/Cut The Rope/images/page/loader-bubble.png b/projects/Cut The Rope/images/page/loader-bubble.png new file mode 100644 index 000000000..6bc95f298 Binary files /dev/null and b/projects/Cut The Rope/images/page/loader-bubble.png differ diff --git a/projects/Cut The Rope/images/page/loader-logo.png b/projects/Cut The Rope/images/page/loader-logo.png new file mode 100644 index 000000000..de84f68e8 Binary files /dev/null and b/projects/Cut The Rope/images/page/loader-logo.png differ diff --git a/projects/Cut The Rope/images/page/loader-numbers.png b/projects/Cut The Rope/images/page/loader-numbers.png new file mode 100644 index 000000000..efdf517b1 Binary files /dev/null and b/projects/Cut The Rope/images/page/loader-numbers.png differ diff --git a/projects/Cut The Rope/images/page/loader-smallbubble.png b/projects/Cut The Rope/images/page/loader-smallbubble.png new file mode 100644 index 000000000..10286c694 Binary files /dev/null and b/projects/Cut The Rope/images/page/loader-smallbubble.png differ diff --git a/projects/Cut The Rope/images/page/tilebg.jpg b/projects/Cut The Rope/images/page/tilebg.jpg new file mode 100644 index 000000000..fd204d296 Binary files /dev/null and b/projects/Cut The Rope/images/page/tilebg.jpg differ diff --git a/projects/Cut The Rope/images/page/upgrade-js.png b/projects/Cut The Rope/images/page/upgrade-js.png new file mode 100644 index 000000000..b61e92aa3 Binary files /dev/null and b/projects/Cut The Rope/images/page/upgrade-js.png differ diff --git a/projects/Cut The Rope/images/page/upgrade-mobile.png b/projects/Cut The Rope/images/page/upgrade-mobile.png new file mode 100644 index 000000000..b475ddbcc Binary files /dev/null and b/projects/Cut The Rope/images/page/upgrade-mobile.png differ diff --git a/projects/Cut The Rope/index.html b/projects/Cut The Rope/index.html new file mode 100644 index 000000000..a09fb42fe --- /dev/null +++ b/projects/Cut The Rope/index.html @@ -0,0 +1,225 @@ + + + + + + + + Cut the Rope + + + + + + + + + + + + +
+
+ + + +
+
+ +
+
+ +
+ +
+ +
+ +
+
+
+ +
+ + +
+ + + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + +
+
+ +
+ +
+
+
+ + + +
+
+ +
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/projects/Cut The Rope/scripts/ctr-nonobscure.js b/projects/Cut The Rope/scripts/ctr-nonobscure.js new file mode 100644 index 000000000..9cd27c3e0 --- /dev/null +++ b/projects/Cut The Rope/scripts/ctr-nonobscure.js @@ -0,0 +1,25682 @@ +// a fix for the rotation issue in v1.1 + +document.addEventListener("blur", function () { + document.body.style.transform = "rotate(90deg)"; + setTimeout(function () { + document.body.style.transform = "rotate(0deg)"; + }, 1000) +}, false); + +document.addEventListener("focus", function () { + document.body.style.transform = "rotate(0deg)"; +}, false); + +window.addEventListener("contextmenu", function (e) { + e.preventDefault(); + e.stopPropagation(); + return false; +}, true); + +var GLOBAL_ZOOM = matchMedia("(min-width: 960px)").matches ? 2 : 1; + +(function () { +define('utils/Class',[], function () { + + /* Simple JavaScript Inheritance + * By John Resig http://ejohn.org/ + * MIT Licensed. + */ + // Inspired by base2 and Prototype + + var Class; + + (function () { + var initializing = false; + + var fnTest = /var xyz/.test(function () { + //noinspection JSUnusedLocalSymbols + var xyz; + }) ? /\b_super\b/ : /.*/; + + // The base Class implementation (does nothing) + Class = function () { + }; + + // Create a new Class that inherits from this class + Class.extend = function (prop) { + var _super = this.prototype; + + // Instantiate a base class (but only create the instance, + // don't run the init constructor) + initializing = true; + var prototype = new this(); + initializing = false; + + // Copy the properties over onto the new prototype + for (var name in prop) { + // Check if we're overwriting an existing function + //noinspection JSUnfilteredForInLoop + prototype[name] = typeof prop[name] == "function" && + typeof _super[name] == "function" && fnTest.test(prop[name]) ? + (function (name, fn) { + return function () { + var tmp = this._super; + + // Add a new ._super() method that is the same method + // but on the super-class + //noinspection JSUnfilteredForInLoop + this._super = _super[name]; + + // The method only need to be bound temporarily, so we + // remove it when we're done executing + var ret = fn.apply(this, arguments); + this._super = tmp; + + return ret; + }; + })(name, prop[name]) : + prop[name]; + } + + // The dummy class constructor + /** + * @constructor + */ + function Class() { + // All construction is actually done in the init method + if (!initializing && this.init) + this.init.apply(this, arguments); + } + + // Populate our constructed prototype object + Class.prototype = prototype; + + // Enforce the constructor to be what we expect + Class.prototype.constructor = Class; + + // And make this class extendable + Class.extend = arguments.callee; + + return Class; + }; + })(); + + return Class; +}); +define('core/RGBAColor', + [], + function () { + /** + * RGBAColor constructor + * @constructor + * @param r {number} red + * @param g {number} green + * @param b {number} blue + * @param a {number} alpha + */ + function RGBAColor(r, g, b, a) { + /** type {number} */ + this.r = r; + /** type {number} */ + this.g = g; + /** type {number} */ + this.b = b; + /** type {number} */ + this.a = a; + } + + RGBAColor.prototype.rgbaStyle = function () { + return 'rgba(' + + ((this.r * 255) >> 0) + ',' + + ((this.g * 255) >> 0) + ',' + + ((this.b * 255) >> 0) + ',' + + this.a.toFixed(2) + ')'; + }; + + /** + * @param other {RGBAColor} + * @return {boolean} + */ + RGBAColor.prototype.equals = function (other) { + return this.r === other.r && + this.g === other.g && + this.b === other.b && + this.a === other.a; + }; + + RGBAColor.prototype.copy = function () { + return new RGBAColor(this.r, this.g, this.b, this.a); + }; + + RGBAColor.prototype.copyFrom = function (source) { + this.r = source.r; + this.g = source.g; + this.b = source.b; + this.a = source.a; + }; + + RGBAColor.prototype.add = function (other) { + this.r += other.r; + this.g += other.g; + this.b += other.b; + this.a += other.a; + }; + + RGBAColor.prototype.multiply = function (s) { + this.r *= s; + this.g *= s; + this.b *= s; + this.a *= s; + }; + + /** + * @type {RGBAColor} + * @const + */ + RGBAColor.transparent = new RGBAColor(0, 0, 0, 0); + + /** + * @type {RGBAColor} + * @const + */ + RGBAColor.solidOpaque = new RGBAColor(1, 1, 1, 1); + + /** + * @type {RGBAColor} + * @const + */ + RGBAColor.red = new RGBAColor(1, 0, 0, 1); + + /** + * @type {RGBAColor} + * @const + */ + RGBAColor.blue = new RGBAColor(0, 0, 1, 1); + + /** + * @type {RGBAColor} + * @const + */ + RGBAColor.green = new RGBAColor(0, 1, 0, 1); + + /** + * @type {RGBAColor} + * @const + */ + RGBAColor.black = new RGBAColor(0, 0, 0, 1); + + /** + * @type {RGBAColor} + * @const + */ + RGBAColor.white = RGBAColor.solidOpaque; + + /** + * @enum {string} + */ + RGBAColor.styles = { + SOLID_OPAQUE: "rgba(255,255,255,1)", + TRANSPARENT: "rgba(0,0,0,0)" + }; + + return RGBAColor; + } +); +define('core/Alignment', + [], + function () { + var Alignment = { + /** @const + * @type {number} + */ + UNDEFINED: 0, + /** @const + * @type {number} + */ + LEFT: 1, + /** @const + * @type {number} + */ + HCENTER: 2, + /** @const + * @type {number} + */ + RIGHT: 4, + /** @const + * @type {number} + */ + TOP: 8, + /** @const + * @type {number} + */ + VCENTER: 16, + /** @const + * @type {number} + */ + BOTTOM: 32, + /** @const + * @type {number} + */ + CENTER: 2 | 16, + /** + * @param s {string} input string + * @return {number} + */ + parse: function (s) { + + var a = this.UNDEFINED; + if (s.indexOf("LEFT") > 0) + a = this.LEFT; + else if (s.indexOf("HCENTER") > 0 || s === "CENTER") + a = this.HCENTER; + else if (s.indexOf("RIGHT") > 0) + a = this.RIGHT; + + if (s.indexOf("TOP") > 0) + a |= this.TOP; + else if (s.indexOf("VCENTER") > 0 || s === "CENTER") + a |= this.VCENTER; + else if (s.indexOf("BOTTOM") > 0) + a |= this.BOTTOM; + + return a; + } + }; + + return Alignment; + } +); + +define('core/Vector', + [], + function () { + + /** + * Vector constructor + * @constructor + * @param x {number} + * @param y {number} + */ + function Vector(x, y) { + this.x = x; + this.y = y; + } + + Vector.prototype.add = function (v2) { + this.x += v2.x; + this.y += v2.y; + }; + + Vector.prototype.subtract = function (v2) { + this.x -= v2.x; + this.y -= v2.y; + }; + + Vector.prototype.multiply = function (s) { + this.x *= s; + this.y *= s; + }; + + Vector.prototype.divide = function (s) { + this.x /= s; + this.y /= s; + }; + + Vector.prototype.distance = function (v2) { + var tx = this.x - v2.x, + ty = this.y - v2.y, + dot = tx * tx + ty * ty; + return Math.sqrt(dot); + }; + + Vector.prototype.getLength = function () { + var dot = this.x * this.x + this.y * this.y; + return Math.sqrt(dot); + }; + + /** + * @param v2 {Vector} + * @return {number} + */ + Vector.prototype.getDot = function (v2) { + return this.x * v2.x + this.y * v2.y; + }; + + /** + * @return {boolean} + */ + Vector.prototype.isZero = function () { + return this.x === 0 && this.y === 0; + }; + + /** + * @param v2 {Vector} + * @return {boolean} + */ + Vector.prototype.equals = function (v2) { + return this.x === v2.x && this.y === v2.y; + }; + + Vector.prototype.setToZero = function () { + this.x = 0; + this.y = 0; + }; + + Vector.prototype.normalize = function () { + this.multiply(1 / this.getLength()); + }; + + /** @return {number} */ + Vector.prototype.angle = function () { + return Math.atan(this.y / this.x); + }; + + /** @return {number} */ + Vector.prototype.normalizedAngle = function () { + // Note: y goes first in Math.atan2() + return Math.atan2(this.y, this.x); + }; + + /** @return {Vector} */ + Vector.prototype.copy = function () { + return new Vector(this.x, this.y); + }; + + /** + * Copies the values from another vector + * @param v {Vector} source vector + */ + Vector.prototype.copyFrom = function (v) { + this.x = v.x; + this.y = v.y; + }; + + Vector.prototype.round = function () { + this.x = Math.round(this.x); + //noinspection JSSuspiciousNameCombination + this.y = Math.round(this.y); + }; + + Vector.prototype.rotate = function (rad) { + //noinspection UnnecessaryLocalVariableJS + var cosA = Math.cos(rad), + sinA = Math.sin(rad), + nx = this.x * cosA - this.y * sinA, + ny = this.x * sinA + this.y * cosA; + + this.x = nx; + this.y = ny; + }; + + Vector.prototype.rotateAround = function (rad, cx, cy) { + // shift to the rotation point + this.x -= cx; + this.y -= cy; + + this.rotate(rad); + + // shift back to original location + this.x += cx; + this.y += cy; + }; + + /** @return {string} */ + Vector.prototype.toString = function () { + return '[' + this.x + ', ' + this.y + ']'; + }; + + /** + * Convenience method to create a new zero-based vector + * @return {Vector} + */ + Vector.newZero = function () { + return new Vector(0, 0); + }; + Vector.zero = new Vector(0, 0); + + Vector.newUndefined = function () { + return new Vector(0x7FFFFFFF, 0x7FFFFFFF); + }; + Vector.undefined = Vector.newUndefined(); + + // NOTE: we want to avoid creating new objects when possible so + // we have member methods that modify vector instances. We also + // have static methods below which return a new vector without + // modifying any source vectors. + /** + * @param v1 {Vector} + * @param v2 {Vector} + * @return {Vector} + */ + Vector.add = function (v1, v2) { + return new Vector(v1.x + v2.x, v1.y + v2.y); + }; + /** + * @param v1 {Vector} + * @param v2 {Vector} + * @return {Vector} + */ + Vector.subtract = function (v1, v2) { + return new Vector(v1.x - v2.x, v1.y - v2.y); + }; + /** + * @param v {Vector} + * @param s {number} scalar multiplier + */ + Vector.multiply = function (v, s) { + return new Vector(v.x * s, v.y * s); + }; + /** + * @param v {Vector} source vector + * @param s {number} scalar divisor + * @return {Vector} + */ + Vector.divide = function (v, s) { + return new Vector(v.x / s, v.y / s); + }; + Vector.distance = function (x1, y1, x2, y2) { + var tx = x1 - x2, + ty = y1 - y2, + dot = tx * tx + ty * ty; + return Math.sqrt(dot); + }; + /** + * @param v {Vector} + * @return {Vector} + */ + Vector.perpendicular = function (v) { + //noinspection JSSuspiciousNameCombination + return new Vector(-v.y, v.x); + }; + /** + * @param v {Vector} + * @return {Vector} + */ + Vector.rPerpendicular = function (v) { + //noinspection JSSuspiciousNameCombination + return new Vector(v.y, -v.x); + }; + /** + * @param v {Vector} + * @return {Vector} + */ + Vector.normalize = function (v) { + return this.multiply(v, 1 / v.getLength()); + }; + /** + * @param v {Vector} + * @return {Vector} + */ + Vector.negate = function (v) { + return new Vector(-v.x, -v.y); + }; + + + // initialize temp arrays used in bezier calcs to avoid allocations + Vector._tmpBezierX = new Array(64); + Vector._tmpBezierY = new Array(64); + + Vector.calcPathBezier = function (points, delta) { + var result = new Vector(0, 0); + Vector.setCalcPathBezier(points, delta, result); + return result; + }; + + /** + * Calculates the bezier path vector + * @param points {Array.} + * @param delta {number} + * @param result {Vector} + */ + Vector.setCalcPathBezier = function (points, delta, result) { + var count = points.length; + if (count <= 1) { + result.x = result.y = 0; + return; + } + + var xs = Vector._tmpBezierX, + ys = Vector._tmpBezierY, + d1 = 1 - delta; + + for (var j = 0; j < count; j++) { + var point = points[j]; + xs[j] = point.x; + ys[j] = point.y; + } + + var countMinusOne = count - 1; + for (; countMinusOne > 0; count--, countMinusOne--) { + var i = 0, iPlusOne = 1; + for (; i < countMinusOne; i++, iPlusOne++) { + xs[i] = xs[i] * d1 + xs[iPlusOne] * delta; + ys[i] = ys[i] * d1 + ys[iPlusOne] * delta; + } + } + result.x = xs[0]; + result.y = ys[0]; + }; + + /** + * @param angle {number} + * @return {Vector} + */ + Vector.forAngle = function (angle) { + return new Vector(Math.cos(angle), Math.sin(angle)); + }; + + return Vector; + } +); +define('utils/Constants', + ['core/Vector'], + function (Vector) { + + /** + * convertion rate between screen pixels and si system meters + * @const + * @type {number} + */ + var PIXEL_TO_SI_METERS_K = 80; + + var Constants = { + + /** + * @const + * @type {number} + */ + MAX_TOUCHES: 2, + + /** + * @const + * @type {number} + */ + DIM_TIMEOUT: 0.15, + + /** + * @const + * @type {number} + */ + UNDEFINED: -1, + + /** + * Used in timelines to decide when we should stop caring (occurs + * when very small amounts of time are left in the animation). + * @const + * @type {number} + */ + FLOAT_PRECISION: 0.000001, + + /** + * how many times the world moves slower + * @const + * @type {number} + */ + TIME_SCALE: 1, + + /** + * convertion rate between screen pixels and si system meters + * @const + * @type {number} + */ + PIXEL_TO_SI_METERS_K: PIXEL_TO_SI_METERS_K, + + /** + * @const + * @type {number} + */ + AIR_RESISTANCE: 0.15, + + /** + * @const + * @type {number} + */ + MAX_FORCES: 10, + + /** + * @const + * @type {number} + */ + CANDY2_FLAG: -2, + + + /** + * Max integer. Javascript actually supports larger ints (up to 2^53) + * because all numbers are 64-bit floats. However, we want to use the + * max 32 bit int because sometimes Javascript utilizes integer math + * when possible under the covers, which is much faster. + * @const + * @type {number} + */ + INT_MAX: 0x7FFFFFFF + }; + + return Constants; + } +); + + + +define('utils/Canvas', + [ 'core/RGBAColor' ], + function (RGBAColor) { + + var Canvas = { + domReady: function (elementId) { + this.setTarget(document.getElementById(elementId)); + }, + setTarget: function (element) { + this.id = element; + this.element = element; + this.context = this.element.getContext('2d'); + this.setStyleColor(RGBAColor.white); + }, + /** + * Sets the fill and stroke styles + * @param color {RGBAColor} + */ + setStyleColor: function (color) { + var rgba = color.rgbaStyle(); + this.context.fillStyle = rgba; + this.context.strokeStyle = rgba; + //console.log('Color changed to: ' + rgba); + }, + setStyles: function (style) { + this.context.fillStyle = style; + this.context.strokeStyle = style; + }, + /** + * Fills a shape specified using a triangle strip array, ex: + * 0 -- 2 -- 4 -- 6 + * | | | | + * 1 -- 3 -- 5 -- 7 + * @param points + * @param style + */ + fillTriangleStrip: function (points, style) { + var ctx = this.context, + point = points[0]; + ctx.fillStyle = style; + ctx.beginPath(); + ctx.moveTo(point.x, point.y); + + // draw the bottom portion of the shape + for (var i = 1, len = points.length; i < len; i += 2) { + point = points[i]; + ctx.lineTo(point.x, point.y); + } + + // draw the top portion + for (i = points.length - 2; i >= 0; i -= 2) { + point = points[i]; + ctx.lineTo(point.x, point.y); + } + + ctx.fill(); // auto-closes path + } + + }; + + return Canvas; + } +); +define('visual/ActionType',[], function () { + /** + * @enum {string} + */ + var ActionType = { + SET_VISIBLE: "ACTION_SET_VISIBLE", + SET_TOUCHABLE: "ACTION_SET_TOUCHABLE", + SET_UPDATEABLE: "ACTION_SET_UPDATEABLE", + SET_DRAWQUAD: "ACTION_SET_DRAWQUAD", + + PLAY_TIMELINE: "ACTION_PLAY_TIMELINE", + PAUSE_TIMELINE: "ACTION_PAUSE_TIMELINE", + STOP_TIMELINE: "ACTION_STOP_TIMELINE", + JUMP_TO_TIMELINE_FRAME: "ACTION_JUMP_TO_TIMELINE_FRAME" + }; + + return ActionType; +}); +define('visual/Action',[], function () { + + function ActionData(name, param, subParam) { + this.actionName = name; + this.actionParam = param; + this.actionSubParam = subParam; + } + + function Action(target, data) { + this.actionTarget = target; + this.data = data; + } + + Action.create = function (target, actionName, param, subParam) { + var data = new ActionData(actionName, param, subParam); + return new Action(target, data); + }; + + return Action; + +}); + + +define('visual/TrackType',[], function () { + /** + * @enum {number} + */ + var TrackType = { + POSITION: 0, + SCALE: 1, + ROTATION: 2, + COLOR: 3, + ACTION: 4, + COUNT: 5 + }; + + return TrackType; +}); + +define('visual/KeyFrame', + [ + 'core/Vector', + 'core/RGBAColor', + 'visual/Action', + 'visual/TrackType' + ], + function (Vector, RGBAColor, Action, TrackType) { + + function KeyFrameValue() { + this.pos = Vector.newZero(); + this.scale = Vector.newZero(); + this.rotationAngle = 0; + this.color = RGBAColor.solidOpaque.copy(); + this.actionSet = []; + } + + KeyFrameValue.prototype.copy = function () { + var clone = new KeyFrameValue(); + clone.pos = this.pos.copy(); + clone.scale = this.scale.copy(); + clone.rotationAngle = this.rotationAngle; + clone.color = this.color.copy(); + + // NOTE: this assumes actions are values (not object refs) + clone.actionSet = this.actionSet.slice(0); + return clone; + }; + + /** + * KeyFrame constructor + * @param time {number} + * @param trackType {TrackType} + * @param transitionType {KeyFrame.TransitionType} + * @param value {KeyFrameValue} + */ + function KeyFrame(time, trackType, transitionType, value) { + this.timeOffset = time; + this.trackType = trackType; + this.transitionType = transitionType; + this.value = value; + } + + + KeyFrame.prototype.copy = function () { + return new KeyFrame( + this.timeOffset, + this.trackType, + this.transitionType, + this.value.copy()); + }; + + /** + * @enum {number} + */ + KeyFrame.TransitionType = { + LINEAR: 0, + IMMEDIATE: 1, + EASE_IN: 2, + EASE_OUT: 3 + }; + + /** + * Creates an empty keyframe + * @return {KeyFrame} + */ + KeyFrame.newEmpty = function () { + return new KeyFrame( + 0, // time + TrackType.POSITION, // default track type + KeyFrame.TransitionType.LINEAR, // default transition type + new KeyFrameValue()); + }; + + KeyFrame.makePos = function (x, y, transition, time) { + var v = new KeyFrameValue(); + v.pos.x = x; + v.pos.y = y; + return new KeyFrame(time, TrackType.POSITION, transition, v); + }; + + KeyFrame.makeScale = function (x, y, transition, time) { + var v = new KeyFrameValue(); + v.scale.x = x; + v.scale.y = y; + return new KeyFrame(time, TrackType.SCALE, transition, v); + }; + + KeyFrame.makeRotation = function (r, transition, time) { + var v = new KeyFrameValue(); + v.rotationAngle = r; + return new KeyFrame(time, TrackType.ROTATION, transition, v); + }; + + KeyFrame.makeColor = function (color, transition, time) { + var v = new KeyFrameValue(); + v.color = color; + return new KeyFrame(time, TrackType.COLOR, transition, v); + }; + + KeyFrame.makeAction = function (actions, time) { + var v = new KeyFrameValue(); + v.actionSet = actions; + return new KeyFrame(time, TrackType.ACTION, KeyFrame.TransitionType.LINEAR, v); + }; + + KeyFrame.makeSingleAction = function (target, actionName, actionParam, actionSubParam, time) { + var v = new KeyFrameValue(), + action = Action.create(target, actionName, actionParam, actionSubParam); + v.actionSet = [ action ]; + return new KeyFrame(time, TrackType.ACTION, KeyFrame.TransitionType.LINEAR, v); + }; + + return KeyFrame; + } +); + +define('visual/TimelineTrack', + [ + 'utils/Class', + 'visual/KeyFrame', + 'visual/TrackType', + 'utils/Constants' + ], + function (Class, KeyFrame, TrackType, Constants) { + /** + * @enum {number} + */ + var TrackState = { + NOT_ACTIVE: 0, + ACTIVE: 1 + }; + + var TimelineTrack = Class.extend({ + init: function (timeline, trackType) { + this.type = trackType; + this.state = TrackState.NOT_ACTIVE; + this.relative = false; + + this.startTime = 0; + this.endTime = 0; + + this.keyFrames = []; + + this.t = timeline; + + this.nextKeyFrame = Constants.UNDEFINED; + this.currentStepPerSecond = KeyFrame.newEmpty(); + this.currentStepAcceleration = KeyFrame.newEmpty(); + this.elementPrevState = KeyFrame.newEmpty(); + this.keyFrameTimeLeft = 0; + this.overrun = 0; + + if (trackType === TrackType.ACTION) { + this.actionSets = []; + } + }, + deactivate: function () { + this.state = TrackState.NOT_ACTIVE; + }, + addKeyFrame: function (keyFrame) { + this.setKeyFrame(keyFrame, this.keyFrames.length); + }, + setKeyFrame: function (keyFrame, index) { + this.keyFrames[index] = keyFrame; + + if (this.type === TrackType.ACTION) { + this.actionSets.push(keyFrame.value.actionSet); + } + }, + getFrameTime: function (frameIndex) { + var total = 0; + for (var i = 0; i <= frameIndex; i++) { + total += this.keyFrames[i].timeOffset; + } + return total; + }, + updateRange: function () { + this.startTime = this.getFrameTime(0); + this.endTime = this.getFrameTime(this.keyFrames.length - 1); + }, + updateActionTrack: function (delta) { + if (this.state === TrackState.NOT_ACTIVE) { + if (!this.t.timelineDirReverse) { + if (!(this.t.time - delta > this.endTime || this.t.time < this.startTime)) { + if (this.keyFrames.length > 1) { + this.state = TrackState.ACTIVE; + this.nextKeyFrame = 0; + this.overrun = this.t.time - this.startTime; + + this.nextKeyFrame++; + this.initActionKeyFrame( + this.keyFrames[this.nextKeyFrame - 1], + this.keyFrames[this.nextKeyFrame].timeOffset); + } + else { + this.initActionKeyFrame(this.keyFrames[0], 0); + } + } + } + else { + if (!(this.t.time + delta < this.startTime || this.t.time > this.endTime)) { + if (this.keyFrames.length > 1) { + this.state = TrackState.ACTIVE; + this.nextKeyFrame = this.keyFrames.length - 1; + this.overrun = this.endTime - this.t.time; + this.nextKeyFrame--; + this.initActionKeyFrame( + this.keyFrames[this.nextKeyFrame + 1], + this.keyFrames[this.nextKeyFrame].timeOffset); + } + else { + this.initActionKeyFrame(this.keyFrames[0], 0); + } + } + } + return; + } + + this.keyFrameTimeLeft -= delta; + + // FLOAT_PRECISION is used to fix the situation when timeline + // time >= timeline length but keyFrameTimeLeft is not <= 0 + if (this.keyFrameTimeLeft <= Constants.FLOAT_PRECISION) { + if (this.t.onKeyFrame) { + this.t.onKeyFrame(this.t, this.keyFrames[this.nextKeyFrame], this.nextKeyFrame); + } + + this.overrun = -this.keyFrameTimeLeft; + + if (this.nextKeyFrame === this.keyFrames.length - 1) { + this.setElementFromKeyFrame(this.keyFrames[this.nextKeyFrame]); + this.state = TrackState.NOT_ACTIVE; + } + else if (this.nextKeyFrame === 0) { + this.setElementFromKeyFrame(this.keyFrames[this.nextKeyFrame]); + this.state = TrackState.NOT_ACTIVE + } + else { + if (!this.t.timelineDirReverse) { + this.nextKeyFrame++; + this.initActionKeyFrame( + this.keyFrames[this.nextKeyFrame - 1], + this.keyFrames[this.nextKeyFrame].timeOffset); + } + else { + this.nextKeyFrame--; + var kf = this.keyFrames[this.nextKeyFrame + 1]; + this.initActionKeyFrame(kf, kf.timeOffset); + } + } + } + }, + updateNonActionTrack: function (delta) { + var t = this.t, kf; + if (this.state === TrackState.NOT_ACTIVE) { + if (t.time >= this.startTime && t.time <= this.endTime) { + this.state = TrackState.ACTIVE; + if (!t.timelineDirReverse) { + this.nextKeyFrame = 0; + this.overrun = t.time - this.startTime; + this.nextKeyFrame++; + kf = this.keyFrames[this.nextKeyFrame]; + this.initKeyFrameStepFrom( + this.keyFrames[this.nextKeyFrame - 1], + kf, + kf.timeOffset); + } + else { + this.nextKeyFrame = this.keyFrames.length - 1; + this.overrun = this.endTime - t.time; + this.nextKeyFrame--; + kf = this.keyFrames[this.nextKeyFrame + 1]; + this.initKeyFrameStepFrom( + kf, + this.keyFrames[this.nextKeyFrame], + kf.timeOffset); + } + } + return; + } + + this.keyFrameTimeLeft -= delta; + kf = this.keyFrames[this.nextKeyFrame]; + if (kf.transitionType === KeyFrame.TransitionType.EASE_IN || + kf.transitionType === KeyFrame.TransitionType.EASE_OUT) { + switch (this.type) { + case TrackType.POSITION: + var saPos = this.currentStepAcceleration.value.pos, + xPosDelta = saPos.x * delta, + yPosDelta = saPos.y * delta, + spsPos = this.currentStepPerSecond.value.pos, + oldPosX = spsPos.x, + oldPosY = spsPos.y; + spsPos.x += xPosDelta; + spsPos.y += yPosDelta; + t.element.x += (oldPosX + xPosDelta / 2) * delta; + t.element.y += (oldPosY + yPosDelta / 2) * delta; + break; + case TrackType.SCALE: + var saScale = this.currentStepAcceleration.value.scale, + xScaleDelta = saScale.x * delta, + yScaleDelta = saScale.y * delta, + spsScale = this.currentStepPerSecond.value.scale, + oldScaleX = spsScale.x, + oldScaleY = spsScale.y; + spsScale.x += xScaleDelta; + spsScale.y += yScaleDelta; + t.element.scaleX += (oldScaleX + xScaleDelta / 2) * delta; + t.element.scaleY += (oldScaleY + yScaleDelta / 2) * delta; + break; + case TrackType.ROTATION: + var rDelta = this.currentStepAcceleration.value.rotationAngle * delta, + oldRotationAngle = this.currentStepPerSecond.value.rotationAngle; + this.currentStepPerSecond.value.rotationAngle += rDelta; + t.element.rotation += (oldRotationAngle + rDelta / 2) * delta; + break; + case TrackType.COLOR: + var spsColor = this.currentStepPerSecond.value.color, + oldColorR = spsColor.r, + oldColorG = spsColor.g, + oldColorB = spsColor.b, + oldColorA = spsColor.a, + saColor = this.currentStepAcceleration.value.color, + deltaR = saColor.r * delta, + deltaG = saColor.g * delta, + deltaB = saColor.b * delta, + deltaA = saColor.a * delta; + + // NOTE: it looks like there may be a bug in iOS? For now, we'll follow + // it by adding the delta twice + spsColor.r += (deltaR * 2); + spsColor.g += (deltaG * 2); + spsColor.b += (deltaB * 2); + spsColor.a += (deltaA * 2); + + var elemColor = t.element.color; + elemColor.r += (oldColorR + deltaR / 2) * delta; + elemColor.g += (oldColorG + deltaG / 2) * delta; + elemColor.b += (oldColorB + deltaB / 2) * delta; + elemColor.a += (oldColorA + deltaA / 2) * delta; + break; + case TrackType.ACTION: + break; + } + } + else if (kf.transitionType === KeyFrame.TransitionType.LINEAR) { + var elem = t.element, + spsValue = this.currentStepPerSecond.value; + switch (this.type) { + case TrackType.POSITION: + elem.x += spsValue.pos.x * delta; + elem.y += spsValue.pos.y * delta; + break; + case TrackType.SCALE: + elem.scaleX += spsValue.scale.x * delta; + elem.scaleY += spsValue.scale.y * delta; + break; + case TrackType.ROTATION: + elem.rotationAngle += spsValue.rotationAngle * delta; + break; + case TrackType.COLOR: + elem.color.r += spsValue.color.r * delta; + elem.color.g += spsValue.color.g * delta; + elem.color.b += spsValue.color.b * delta; + elem.color.a += spsValue.color.a * delta; + break; + case TrackType.ACTION: + break; + } + } + + if (this.keyFrameTimeLeft <= Constants.FLOAT_PRECISION) { + if (t.onKeyFrame) { + t.onKeyFrame(t, this.keyFrames[this.nextKeyFrame], this.nextKeyFrame); + } + + this.overrun = -this.keyFrameTimeLeft; + + if (this.nextKeyFrame === this.keyFrames.length - 1) { + this.setElementFromKeyFrame(this.keyFrames[this.nextKeyFrame]); + this.state = TrackState.NOT_ACTIVE; + } + else if (this.nextKeyFrame === 0) { + this.setElementFromKeyFrame(this.keyFrames[this.nextKeyFrame]); + this.state = TrackState.NOT_ACTIVE; + } + else { + if (!t.timelineDirReverse) { + this.nextKeyFrame++; + kf = this.keyFrames[this.nextKeyFrame]; + this.initKeyFrameStepFrom( + this.keyFrames[this.nextKeyFrame - 1], + kf, + kf.timeOffset); + } + else { + this.nextKeyFrame--; + kf = this.keyFrames[this.nextKeyFrame + 1]; + this.initKeyFrameStepFrom( + kf, + this.keyFrames[this.nextKeyFrame], + kf.timeOffset); + } + } + } + }, + initActionKeyFrame: function (kf, time) { + this.keyFrameTimeLeft = time; + this.setElementFromKeyFrame(kf); + + if (this.overrun > 0) { + this.updateActionTrack(this.overrun); + this.overrun = 0; + } + }, + /** + * @param kf {KeyFrame} + */ + setElementFromKeyFrame: function (kf) { + switch (this.type) { + case TrackType.POSITION: + var elem = this.t.element, + kfPos = kf.value.pos; + if (!this.relative) { + elem.x = kfPos.x; + elem.y = kfPos.y; + } + else { + var prevPos = this.elementPrevState.value.pos; + elem.x = prevPos.x + kfPos.x; + elem.y = prevPos.y + kfPos.y; + } + break; + case TrackType.SCALE: + var kfScale = kf.value.scale; + elem = this.t.element; + if (!this.relative) { + elem.scaleX = kfScale.x; + elem.scaleY = kfScale.y; + } + else { + var prevScale = this.elementPrevState.value.scale; + elem.scaleX = prevScale.x + kfScale.x; + elem.scaleY = prevScale.y + kfScale.y; + } + break; + case TrackType.ROTATION: + if (!this.relative) { + this.t.element.rotation = kf.value.rotationAngle; + } + else { + this.t.element.rotation = this.elementPrevState.value.rotationAngle + + kf.value.rotationAngle; + } + break; + case TrackType.COLOR: + var elemColor = this.t.element.color, + kfColor = kf.value.color; + if (!this.relative) { + elemColor.copyFrom(kfColor); + } + else { + var prevColor = this.elementPrevState.value.color; + elemColor.r = prevColor.r + kfColor.r; + elemColor.g = prevColor.g + kfColor.g; + elemColor.b = prevColor.b + kfColor.b; + elemColor.a = prevColor.a + kfColor.a; + } + break; + case TrackType.ACTION: + var actionSet = kf.value.actionSet; + for (var i = 0, len = actionSet.length; i < len; i++) { + var action = actionSet[i]; + action.actionTarget.handleAction(action.data); + } + break; + } + }, + setKeyFrameFromElement: function (kf) { + var kfValue = kf.value, + elem = this.t.element; + switch (this.type) { + case TrackType.POSITION: + kfValue.pos.x = elem.x; + kfValue.pos.y = elem.y; + break; + case TrackType.SCALE: + kfValue.scale.x = elem.scaleX; + kfValue.scale.y = elem.scaleY; + break; + case TrackType.ROTATION: + kfValue.rotationAngle = elem.rotation; + break; + case TrackType.COLOR: + kfValue.color.copyFrom(elem.color); + break; + case TrackType.ACTION: + break; + } + }, + initKeyFrameStepFrom: function (src, dst, time) { + this.keyFrameTimeLeft = time; + + this.setKeyFrameFromElement(this.elementPrevState); + this.setElementFromKeyFrame(src); + + var spsValue = this.currentStepPerSecond.value, + saValue = this.currentStepAcceleration.value; + switch (this.type) { + case TrackType.POSITION: + var spsPos = spsValue.pos, + dstPos = dst.value.pos, + srcPos = src.value.pos; + spsPos.x = (dstPos.x - srcPos.x) / this.keyFrameTimeLeft; + spsPos.y = (dstPos.y - srcPos.y) / this.keyFrameTimeLeft; + break; + case TrackType.SCALE: + var spsScale = spsValue.scale, + dstScale = dst.value.scale, + srcScale = src.value.scale; + spsScale.x = (dstScale.x - srcScale.x) / this.keyFrameTimeLeft; + spsScale.y = (dstScale.y - srcScale.y) / this.keyFrameTimeLeft; + break; + case TrackType.ROTATION: + spsValue.rotationAngle = (dst.value.rotationAngle - src.value.rotationAngle) / this.keyFrameTimeLeft; + break; + case TrackType.COLOR: + var spsColor = spsValue.color, + dstColor = dst.value.color, + srcColor = src.value.color; + spsColor.r = (dstColor.r - srcColor.r) / this.keyFrameTimeLeft; + spsColor.g = (dstColor.g - srcColor.g) / this.keyFrameTimeLeft; + spsColor.b = (dstColor.b - srcColor.b) / this.keyFrameTimeLeft; + spsColor.a = (dstColor.a - srcColor.a) / this.keyFrameTimeLeft; + break; + case TrackType.ACTION: + break; + } + + var isEaseIn = (dst.transitionType === KeyFrame.TransitionType.EASE_IN), + isEaseOut = (dst.transitionType == KeyFrame.TransitionType.EASE_OUT); + if (isEaseIn || isEaseOut) { + switch (this.type) { + case TrackType.POSITION: + spsPos = spsValue.pos; + var saPos = saValue.pos; + spsPos.multiply(2); + saPos.x = spsPos.x / this.keyFrameTimeLeft; + saPos.y = spsPos.y / this.keyFrameTimeLeft; + if (isEaseIn) { + spsPos.x = 0; + spsPos.y = 0; + } + else { + saPos.multiply(-1); + } + break; + case TrackType.SCALE: + spsScale = spsValue.scale; + var saScale = saValue.scale; + spsScale.multiply(2); + saScale.x = spsScale.x / this.keyFrameTimeLeft; + saScale.y = spsScale.y / this.keyFrameTimeLeft; + if (isEaseIn) { + spsScale.x = 0; + spsScale.y = 0; + } + else { + saScale.multiply(-1); + } + break; + case TrackType.ROTATION: + spsValue.rotationAngle *= 2; + saValue.rotationAngle = spsValue.rotationAngle / this.keyFrameTimeLeft; + if (isEaseIn) { + spsValue.rotationAngle = 0; + } + else { + saValue.rotationAngle *= -1; + } + break; + case TrackType.COLOR: + spsColor = spsValue.color; + var saColor = saValue.color; + spsColor.multiply(2); + saColor.r = spsColor.r / this.keyFrameTimeLeft; + saColor.g = spsColor.g / this.keyFrameTimeLeft; + saColor.b = spsColor.b / this.keyFrameTimeLeft; + saColor.a = spsColor.a / this.keyFrameTimeLeft; + if (isEaseIn) { + spsColor.multiply(0); + } + else { + saColor.multiply(-1); + } + + break; + case TrackType.ACTION: + break; + } + } + + if (this.overrun > 0) { + this.updateNonActionTrack(this.overrun); + this.overrun = 0; + } + } + }); + + return TimelineTrack; + } +); + +define('visual/Timeline', + [ + 'utils/Class', + 'visual/TimelineTrack', + 'visual/TrackType', + 'utils/Constants' + ], + function (Class, TimelineTrack, TrackType, Constants) { + + var Timeline = Class.extend({ + init: function () { + this.time = 0; + this.length = 0; + this.loopsLimit = Constants.UNDEFINED; + this.state = Timeline.StateType.STOPPED; + this.loopType = Timeline.LoopType.NO_LOOP; + this.tracks = []; + + // callback fired when the timeline finishes playing + this.onFinished = null; + + // callback fired when the timeline reaches a key frame + this.onKeyFrame = null; + + this.timelineDirReverse = false; + + this.element = null; + }, + addKeyFrame: function (keyFrame) { + var track = this.tracks[keyFrame.trackType], + index = (track == null) ? 0 : track.keyFrames.length; + this.setKeyFrame(keyFrame, index); + }, + setKeyFrame: function (keyFrame, index) { + var track = this.tracks[keyFrame.trackType]; + if (!track) { + this.tracks[keyFrame.trackType] = track = + new TimelineTrack(this, keyFrame.trackType); + } + track.setKeyFrame(keyFrame, index); + }, + getTrack: function (index) { + return this.tracks[index]; + }, + play: function () { + if (this.state !== Timeline.StateType.PAUSED) { + this.time = 0; + this.timelineDirReverse = false; + this.length = 0; + + for (var i = 0, len = this.tracks.length; i < len; i++) { + var track = this.tracks[i]; + if (track) { + track.updateRange(); + if (track.endTime > this.length) { + this.length = track.endTime; + } + } + } + this.update(0); + } + this.state = Timeline.StateType.PLAYING; + + }, + pause: function () { + this.state = Timeline.StateType.PAUSED; + }, + jumpToTrack: function (trackIndex, keyFrame) { + if (this.state === Timeline.StateType.STOPPED) { + this.state = Timeline.StateType.PAUSED; + } + var delta = this.tracks[trackIndex].getFrameTime(keyFrame) - this.time; + this.update(delta); + }, + stop: function () { + this.state = Timeline.StateType.STOPPED; + this.deactivateTracks(); + }, + deactivateTracks: function () { + for (var i = 0, len = this.tracks.length; i < len; i++) { + var track = this.tracks[i]; + if (track) { + track.deactivate(); + } + } + }, + update: function (delta) { + if (this.state !== Timeline.StateType.PLAYING) + return; + + if (!this.timelineDirReverse) + this.time += delta; + else + this.time -= delta; + + for (var i = 0, len = this.tracks.length; i < len; i++) { + var track = this.tracks[i]; + if (track != null) { + if (track.type === TrackType.ACTION) + track.updateActionTrack(delta); + else + track.updateNonActionTrack(delta); + } + } + + if (this.loopType === Timeline.LoopType.PING_PONG) { + var reachedEnd = this.timelineDirReverse === false && + this.time >= this.length - Constants.FLOAT_PRECISION; + if (reachedEnd) { + this.time = Math.max(0, this.length - (this.time - this.length)); + this.timelineDirReverse = true; + } + else { + var reachedStart = this.timelineDirReverse && this.time <= Constants.FLOAT_PRECISION; + if (reachedStart) { + if (this.loopsLimit > 0) { + this.loopsLimit--; + if (this.loopsLimit === 0) { + this.stop(); + if (this.onFinished) { + this.onFinished(this); + } + } + } + + this.time = Math.min(-this.time, this.length); + this.timelineDirReverse = false; + } + } + } + else if (this.loopType === Timeline.LoopType.REPLAY) { + if (this.time >= this.length - Constants.FLOAT_PRECISION) { + if (this.loopsLimit > 0) { + this.loopsLimit--; + if (this.loopsLimit === 0) { + this.stop(); + if (this.onFinished) { + this.onFinished(this); + } + } + } + + this.time = Math.min(this.time - this.length, this.length); + } + } + else if (this.loopType === Timeline.LoopType.NO_LOOP) { + if (this.time >= this.length - Constants.FLOAT_PRECISION) { + this.stop(); + if (this.onFinished) { + this.onFinished(this); + } + } + } + } + }); + + + /** + * @enum {number} + */ + Timeline.LoopType = { + NO_LOOP: 0, + REPLAY: 1, + PING_PONG: 2 + }; + + /** + * @enum {number} + */ + Timeline.StateType = { + STOPPED: 0, + PLAYING: 1, + PAUSED: 2 + }; + + return Timeline; + } +); +define('utils/Radians', + [], + function () { + /** + * Helper class for dealing with radians + */ + var Radians = { + /** + * @const + * @type {number} + */ + degrees360: 6.283185307179586, // Math.PI * 2 + /** + * Converts degrees to radians + * @param degrees {number} + * @return {number} + */ + fromDegrees: function (degrees) { + return degrees * 0.017453292519943295; // degrees * (Math.PI / 180) + }, + /** + * Converts radians to degrees + * @param radians {number} + * @return {number} + */ + toDegrees: function (radians) { + return radians * 57.29577951308232; // radians * 180 / Math.PI + } + }; + + return Radians; + } +); + +define('visual/BaseElement', + [ + 'utils/Class', + 'core/RGBAColor', + 'core/Alignment', + 'utils/Constants', + 'utils/Canvas', + 'visual/ActionType', + 'visual/Timeline', + 'utils/Radians' + ], + function (Class, RGBAColor, Alignment, Constants, Canvas, ActionType, Timeline, Radians) { + + var BaseElement = Class.extend({ + init: function () { + /** @type {BaseElement} */ + this.parent = null; + + /** @type {boolean} */ + this.visible = true; + /** @type {boolean} */ + this.touchable = true; + /** @type {boolean} */ + this.updateable = true; + + /** @type {string} */ + this.name = null; + + /** @type {number} */ + this.x = 0; + /** @type {number} */ + this.y = 0; + + // absolute coords of top left corner + /** @type {number} */ + this.drawX = 0; + /** @type {number} */ + this.drawY = 0; + + /** @type {number} */ + this.width = 0; + /** @type {number} */ + this.height = 0; + + /** @type {number} */ + this.rotation = 0; + + // rotation center offset from the element center + /** @type {number} */ + this.rotationCenterX = 0; + /** @type {number} */ + this.rotationCenterY = 0; + + // use scaleX = -1 for horizontal flip, scaleY = -1 for vertical + /** @type {number} */ + this.scaleX = 1; + /** @type {number} */ + this.scaleY = 1; + + /** type {RGBAColor} */ + this.color = RGBAColor.solidOpaque.copy(); + + /** type {number} */ + this.translateX = 0; + this.translateY = 0; + + /** + * Sets the anchor on the element + * type {number} + */ + this.anchor = Alignment.TOP | Alignment.LEFT; + /** type {number} */ + this.parentAnchor = Alignment.UNDEFINED; + + /** type {bool} children will inherit transformations of the parent */ + this.passTransformationsToChilds = true; + + /** type {boolean} children will inherit color of the parent */ + this.passColorToChilds = true; + + /** type {boolean} touch events can be handled by multiple children */ + this.passTouchEventsToAllChilds = false; + + /** + * @protected + */ + this.children = []; + + /** + * @protected + */ + this.timelines = []; + + /** + * @private + * @type {number} + */ + this.currentTimelineIndex = Constants.UNDEFINED; + + /** + * @private + * @type {Timeline} + */ + this.currentTimeline = null; + }, + /** + * @private + */ + calculateTopLeft: function () { + var parentAnchor = this.parentAnchor, + parent = this.parent, + anchor = this.anchor; + + // align to parent + if (parentAnchor !== 0 /*Alignment.UNDEFINED*/) { + // calculate the x offset first + if (parentAnchor & 1 /*Alignment.LEFT*/) + this.drawX = parent.drawX + this.x; + else if (parentAnchor & 2 /*Alignment.HCENTER*/) + this.drawX = parent.drawX + this.x + (parent.width / 2); + else if (parentAnchor & 4 /*Alignment.RIGHT*/) + this.drawX = parent.drawX + this.x + parent.width; + + // now calculate y offset + if (parentAnchor & 8 /*Alignment.TOP*/) + this.drawY = parent.drawY + this.y; + else if (parentAnchor & 16 /*Alignment.VCENTER*/) + this.drawY = parent.drawY + this.y + (parent.height / 2); + else if (parentAnchor & 32 /*Alignment.BOTTOM*/) + this.drawY = parent.drawY + this.y + parent.height; + } + else { + this.drawX = this.x; + this.drawY = this.y; + } + + // align self anchor + if (!(anchor & 8 /*Alignment.TOP*/)) { + if (anchor & 16 /*Alignment.VCENTER*/) + this.drawY -= (this.height / 2); + else if (anchor & 32 /*Alignment.BOTTOM*/) + this.drawY -= this.height; + } + + if (!(anchor & 1 /*Alignment.LEFT*/)) { + if (anchor & 2 /*Alignment.HCENTER*/) + this.drawX -= (this.width / 2); + else if (anchor & 4 /*Alignment.RIGHT*/) + this.drawX -= this.width; + } + }, + preDraw: function () { + this.calculateTopLeft(); + + var changeScale = (this.scaleX !== 0) && (this.scaleY !== 0) && + ((this.scaleX !== 1) || (this.scaleY !== 1)), + changeRotation = (this.rotation !== 0), + changeTranslate = ((this.translateX !== 0) || (this.translateY !== 0)), + ctx = Canvas.context; + + // save existing canvas state first and then reset + ctx.save(); + + // apply transformations + if (changeScale || changeRotation) { + var rotationOffsetX = ~~(this.drawX + (this.width / 2) + this.rotationCenterX), + rotationOffsetY = ~~(this.drawY + (this.height / 2) + this.rotationCenterY), + translatedRotation = (rotationOffsetX !== 0) || (rotationOffsetY !== 0); + + // move to the right position in the canvas before changes + if (translatedRotation) { + ctx.translate(rotationOffsetX, rotationOffsetY); + } + + if (changeRotation) { + ctx.rotate(Radians.fromDegrees(this.rotation)); + } + if (changeScale) { + ctx.scale(this.scaleX, this.scaleY); + } + + // move back to previous position + if (translatedRotation) { + ctx.translate(-rotationOffsetX, -rotationOffsetY); + } + } + + if (changeTranslate) { + ctx.translate(this.translateX, this.translateY); + } + + // change the alpha + this.previousAlpha = ctx.globalAlpha; + if (this.color.a !== 1 && this.color.a !== this.previousAlpha) { + ctx.globalAlpha = this.color.a; + } + }, + draw: function () { + this.preDraw(); + this.postDraw(); + }, + drawBB: function () { + var ctx = Canvas.context; + ctx.strokeStyle = 'red'; + ctx.strokeRect(this.drawX, this.drawY, this.width, this.height); + }, + postDraw: function () { + var ctx = Canvas.context, + alphaChanged = (this.color.a !== 1 && this.color.a !== this.previousAlpha); + + // for debugging, draw vector from the origin towards 0 degrees + if (this.drawZeroDegreesLine) { + var originX = this.drawX + (this.width >> 1) + this.rotationCenterX, + originY = this.drawY + (this.height >> 1) + this.rotationCenterY; + + ctx.save(); + ctx.lineWidth = 5; + ctx.strokeStyle = "#ff0000"; // red line + ctx.beginPath(); + ctx.moveTo(originX, originY); + ctx.lineTo(originX, originY - 100); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); + } + + if (!this.passTransformationsToChilds) { + + if (this.isDrawBB) { + this.drawBB(); + } + + ctx.restore(); + + if (this.passColorToChilds) { + // canvas state includes alpha so we have to set it again + if (alphaChanged) { + Canvas.context.globalAlpha = this.color.a; + } + } + } + else if (!this.passColorToChilds) { + if (alphaChanged) { + Canvas.context.globalAlpha = this.previousAlpha; + } + } + + // draw children + var children = this.children, + numChildren = children.length; + for (var i = 0; i < numChildren; i++) { + var child = children[i]; + if (child.visible) + child.draw(); + } + + if (this.passTransformationsToChilds) { + + if (this.isDrawBB) { + this.drawBB(); + } + + ctx.restore(); + } + else if (this.passColorToChilds) { + if (alphaChanged) { + Canvas.context.globalAlpha = this.previousAlpha; + } + } + }, + /** + * Updates timelines with the elapsed time + * @param delta {number} + */ + update: function (delta) { + var children = this.children, + numChildren = children.length; + for (var i = 0; i < numChildren; i++) { + var child = children[i]; + if (child.updateable) + child.update(delta); + } + + if (this.currentTimeline) { + this.currentTimeline.update(delta); + } + }, + /** + * @param name {string} + * @return {BaseElement} + */ + getChildWithName: function (name) { + var children = this.children, + numChildren = children.length; + for (var i = 0; i < numChildren; i++) { + var child = children[i]; + if (child.name === name) + return child; + + var descendant = child.getChildWithName(name); + if (descendant !== null) + return descendant; + } + + return null; + }, + setSizeToChildsBounds: function () { + this.calculateTopLeft(); + + var minX = this.drawX, + minY = this.drawY, + maxX = this.drawX + this.width, + maxY = this.drawY + this.height, + children = this.children, + numChildren = children.length; + + for (var i = 0; i < numChildren; i++) { + var child = children[i]; + child.calculateTopLeft(); + + if (child.drawX < minX) + minX = child.drawX; + if (child.drawY < minY) + minY = child.drawY; + + var childMaxX = child.drawX + child.width, + childMaxY = child.drawY + child.height; + if (childMaxX > maxX) + maxX = childMaxX; + if (childMaxY > maxY) + maxY = childMaxY; + } + + this.width = maxX - minX; + this.height = maxY - minY; + }, + /** + * @param a {ActionData} action data + * @return {boolean} true if an action was handled + */ + handleAction: function (a) { + switch (a.actionName) { + case ActionType.SET_VISIBLE: + this.visible = (a.actionSubParam !== 0); + break; + case ActionType.SET_UPDATEABLE: + this.updateable = (a.actionSubParam !== 0); + break; + case ActionType.SET_TOUCHABLE: + this.touchable = (a.actionSubParam !== 0); + break; + case ActionType.PLAY_TIMELINE: + this.playTimeline(a.actionSubParam); + break; + case ActionType.PAUSE_TIMELINE: + this.pauseCurrentTimeline(); + break; + case ActionType.STOP_TIMELINE: + this.stopCurrentTimeline(); + break; + case ActionType.JUMP_TO_TIMELINE_FRAME: + var timeline = this.currentTimeline; + timeline.jumpToTrack(a.actionParam, a.actionSubParam); + break; + default: + return false; + } + + return true; + }, + /** + * @param child {BaseElement} child to add + * @return {number} index of added child + */ + addChild: function (child) { + this.children.push(child); + child.parent = this; + return this.children.length - 1; + }, + addChildWithID: function (child, index) { + this.children[index] = child; + child.parent = this; + }, + /** + * @param i {number} index of the child to remove + */ + removeChildWithID: function (i) { + var child = this.children.splice(i, 1); + child.parent = null; + }, + removeAllChildren: function () { + this.children.length = 0; + }, + /** + * @param c {BaseElement} child to remove + */ + removeChild: function (c) { + var children = this.children, + numChildren = children.length; + for (var i = 0; i < numChildren; i++) { + var child = children[i]; + if (c === child) { + this.removeChildWithID(i); + return; + } + } + }, + /** + * @param i {number} index of child + * @return {BaseElement} + */ + getChild: function (i) { + return this.children[i]; + }, + /** + * @return {number} number of children + */ + childCount: function () { + return this.children.length; + }, + /** + * @return {Array.} children + */ + getChildren: function () { + return this.children; + }, + addTimeline: function (timeline) { + var index = this.timelines.length; + this.addTimelineWithID(timeline, index); + return index; + }, + addTimelineWithID: function (timeline, index) { + timeline.element = this; + this.timelines[index] = timeline; + }, + removeTimeline: function (index) { + if (this.currentTimelineIndex === index) + this.stopCurrentTimeline(); + + if (index < this.timelines.length) { + this.timelines.splice(index, 1); + } + }, + playTimeline: function (index) { + if (this.currentTimeline) { + if (this.currentTimeline.state !== Timeline.StateType.STOPPED) { + this.currentTimeline.stop(); + } + } + this.currentTimelineIndex = index; + this.currentTimeline = this.timelines[index]; + this.currentTimeline.play(); + }, + pauseCurrentTimeline: function () { + this.currentTimeline.pause(); + }, + stopCurrentTimeline: function () { + this.currentTimeline.stop(); + this.currentTimeline = null; + this.currentTimelineIndex = Constants.UNDEFINED; + }, + /** + * @param index {number} + * @return {Timeline} + */ + getTimeline: function (index) { + return this.timelines[index]; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + onTouchDown: function (x, y) { + var ret = false, + count = this.children.length; + for (var i = count - 1; i >= 0; i--) { + var child = this.children[i]; + if (child && child.touchable) { + if (child.onTouchDown(x, y) && ret === false) { + ret = true; + if (!this.passTouchEventsToAllChilds) { + return ret; + } + } + } + } + return ret; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + onTouchUp: function (x, y) { + var ret = false, + count = this.children.length; + for (var i = count - 1; i >= 0; i--) { + var child = this.children[i]; + if (child && child.touchable) { + if (child.onTouchUp(x, y) && ret === false) { + ret = true; + if (!this.passTouchEventsToAllChilds) { + return ret; + } + } + } + } + return ret; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + onTouchMove: function (x, y) { + var ret = false, + count = this.children.length; + for (var i = count - 1; i >= 0; i--) { + var child = this.children[i]; + if (child && child.touchable) { + if (child.onTouchMove(x, y) && ret === false) { + ret = true; + if (!this.passTouchEventsToAllChilds) { + return ret; + } + } + } + } + return ret; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + onDoubleClick: function (x, y) { + var ret = false, + count = this.children.length; + for (var i = count - 1; i >= 0; i--) { + var child = this.children[i]; + if (child && child.touchable) { + if (child.onDoubleClick(x, y) && ret === false) { + ret = true; + if (!this.passTouchEventsToAllChilds) { + return ret; + } + } + } + } + return ret; + }, + /** + * @param enabled {boolean} + */ + setEnabled: function (enabled) { + this.visible = enabled; + this.touchable = enabled; + this.updateable = enabled; + }, + /** + * @return {boolean} + */ + isEnabled: function () { + return (this.visible && this.touchable && this.updateable); + }, + show: function () { + var children = this.children, + numChildren = children.length; + for (var i = 0; i < numChildren; i++) { + var child = children[i]; + if (child.visible) + child.show(); + } + }, + hide: function () { + var children = this.children, + numChildren = children.length; + for (var i = 0; i < numChildren; i++) { + var child = children[i]; + if (child.visible) + child.hide(); + } + } + }); + + return BaseElement; + } +); + +define('core/Rectangle', + [ + 'core/Vector' + ], + function (Vector) { + + /** + * Rectangle constructor + * @constructor + * @param x {number} + * @param y {number} + * @param w {number} width + * @param h {number} height + */ + function Rectangle(x, y, w, h) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + + Rectangle.copy = function (r) { + return new Rectangle(r.x, r.y, r.w, r.h); + }; + + Rectangle.scaleCopy = function (r, scale) { + return new Rectangle(r.x * scale, r.y * scale, r.w * scale, r.h * scale); + }; + + /** + * Returns true if rectangles overlap (used in collision detection) + * @param x1l {number} + * @param y1t {number} + * @param x1r {number} + * @param y1b {number} + * @param x2l {number} + * @param y2t {number} + * @param x2r {number} + * @param y2b {number} + * @return {boolean} + */ + Rectangle.rectInRect = function (x1l, y1t, x1r, y1b, x2l, y2t, x2r, y2b) { + return !(x1l > x2r || x1r < x2l || y1t > y2b || y1b < y2t); + }; + + /** + * get intersection rectangle, it's 0,0 is in the r1 top left corner + * + * // first rectangle + * @param r1x {number} + * @param r1y {number} + * @param r1w {number} + * @param r1h {number} + * + * // second rectangle + * @param r2x {number} + * @param r2y {number} + * @param r2w {number} + * @param r2h {number} + * + * @return {Rectangle} + */ + Rectangle.rectInRectIntersection = function (r1x, r1y, r1w, r1h, r2x, r2y, r2w, r2h) { + var res = new Rectangle(r2x - r1x, r2y - r1y, r2w, r2h); + + if (res.x < 0) { + res.w += res.x; + res.x = 0; + } + if (res.x + res.w > r1w) { + res.w = r1w - res.x; + } + if (res.y < 0) { + res.h += res.y; + res.y = 0; + } + if (res.y + res.h > r1h) { + res.h = r1h - res.y; + } + + return res; + }; + + Rectangle.pointInRect = function (x, y, checkX, checkY, checkWidth, checkHeight) { + return (x >= checkX && + x < checkX + checkWidth && + y >= checkY && + y < checkY + checkHeight); + }; + + + /** + * @const + * @type {number} + */ + var COHEN_LEFT = 1; + + /** + * @const + * @type {number} + */ + var COHEN_RIGHT = 2; + + /** + * @const + * @type {number} + */ + var COHEN_BOT = 4; + /** + * @const + * @type {number} + */ + var COHEN_TOP = 8; + + /** + * @param x_min {number} + * @param y_min {number} + * @param x_max {number} + * @param y_max {number} + * @param p {Vector} + * @return {number} + */ + function vcode(x_min, y_min, x_max, y_max, p) { + return ((p.x < x_min) ? COHEN_LEFT : 0) + + ((p.x > x_max) ? COHEN_RIGHT : 0) + + ((p.y < y_min) ? COHEN_BOT : 0) + + ((p.y > y_max) ? COHEN_TOP : 0); + } + + /** + * Cohen-Sutherland algorithm from russian wikipedia + * @param x1 {number} + * @param y1 {number} + * @param x2 {number} + * @param y2 {number} + * @param rx {number} + * @param ry {number} + * @param w {number} + * @param h {number} + * @return {boolean} + */ + Rectangle.lineInRect = function (x1, y1, x2, y2, rx, ry, w, h) { + var code_a, code_b, code; + var a = new Vector(x1, y1), + b = new Vector(x2, y2), + c; + + //noinspection UnnecessaryLocalVariableJS + var x_min = rx, + y_min = ry, + x_max = rx + w, + y_max = ry + h; + + code_a = vcode(x_min, y_min, x_max, y_max, a); + code_b = vcode(x_min, y_min, x_max, y_max, b); + + while (code_a || code_b) { + if (code_a & code_b) { + return false; + } + + if (code_a) { + code = code_a; + c = a; + } + else { + code = code_b; + c = b; + } + + if (code & COHEN_LEFT) { + c.y += (y1 - y2) * (x_min - c.x) / (x1 - x2); + c.x = x_min; + } else if (code & COHEN_RIGHT) { + c.y += (y1 - y2) * (x_max - c.x) / (x1 - x2); + c.x = x_max; + } + + if (code & COHEN_BOT) { + c.x += (x1 - x2) * (y_min - c.y) / (y1 - y2); + c.y = y_min; + } + else if (code & COHEN_TOP) { + c.x += (x1 - x2) * (y_max - c.y) / (y1 - y2); + c.y = y_max; + } + + if (code == code_a) { + code_a = vcode(x_min, y_min, x_max, y_max, a); + } + else { + code_b = vcode(x_min, y_min, x_max, y_max, b); + } + } + + //release from pool + + + + return true; + }; + + return Rectangle; + } +); + +define('visual/ImageMultiDrawer', + [ + 'visual/BaseElement', + 'utils/Canvas', + 'utils/Constants', + 'core/Rectangle' + ], + function (BaseElement, Canvas, Constants, Rectangle) { + /** + * Holds the information necessary to draw multiple quads from a + * shared source image texture + */ + var ImageMultiDrawer = BaseElement.extend({ + init: function (texture) { + this._super(); + + this.texture = texture; + this.numberOfQuadsToDraw = Constants.UNDEFINED; + + // holds the position in the texture that should be drawn + this.texCoordinates = []; + + // holds the position on the canvas to render the texture quad + this.vertices = []; + + // hold the alpha for each quad (if null then we assume alpha=1) + this.alphas = []; + + // NOTE: in OpenGL its possible to draw multiple quads at once. In + // canvas we'll just draw them sequentially (no need for indices buffer) + }, + setTextureQuad: function (index, textureQuad, vertexQuad, alpha) { + this.texCoordinates[index] = textureQuad; + this.vertices[index] = vertexQuad; + this.alphas[index] = (alpha != null) ? alpha : 1; + }, + removeQuads: function (index) { + this.texCoordinates.splice(index, 1); + this.vertices.splice(index, 1); + this.alphas.splice(index, 1); + }, + mapTextureQuad: function (quadIndex, dx, dy, index) { + this.texCoordinates[index] = Rectangle.copy(this.texture.rects[quadIndex]); + + var offset = this.texture.offsets[quadIndex], + rect = this.texture.rects[quadIndex]; + this.vertices[index] = new Rectangle( + dx + offset.x, dy + offset.y, rect.w, rect.h); + this.alphas[index] = 1; + }, + drawNumberOfQuads: function (n) { + if (n > this.texCoordinates.length) { + n = this.texCoordinates.length; + } + + //console.log("DRAW NO OF QUADS", n) + var ctx = Canvas.context; + for (var i = 0; i < n; i++) { + var source = this.texCoordinates[i], + dest = this.vertices[i], + alpha = this.alphas[i], + previousAlpha = ctx.globalAlpha, + sourceW = Math.ceil(source.w), + sourceH = Math.ceil(source.h); + + // verify we need to draw the source + if (sourceW === 0 || sourceH === 0) { + continue; + } + + // change the alpha if necessary + if (alpha == null) { + // if alpha was not specified, we assume full opacity + alpha = 1; + } + else if (alpha <= 0) { + // no need to draw invisible images + continue; + } + else if (alpha < 1) { + ctx.globalAlpha = alpha; + } + + // rotate the image if requested + var checkRotation = (this.rotationAngles && this.rotationAngles.length > i); + if (checkRotation) { + var rotationAngle = this.rotationAngles[i], + rotationPosition = this.rotationPositions[i], + rotateIsTranslated = (rotationPosition.x !== 0 || rotationPosition.y !== 0); + + if (rotationAngle !== 0) { + if (rotateIsTranslated) { + ctx.translate(rotationPosition.x, rotationPosition.y); + } + ctx.rotate(rotationAngle); + if (rotateIsTranslated) { + ctx.translate(-rotationPosition.x, -rotationPosition.y); + } + } + } + + // see if we need sub-pixel alignment + var qx, qy, qw, qh; + // if (this.drawPosIncrement) { + // qx = Math.round(dest.x / this.drawPosIncrement) * this.drawPosIncrement; + // qy = Math.round(dest.y / this.drawPosIncrement) * this.drawPosIncrement; + // qw = Math.round(dest.w / this.drawPosIncrement) * this.drawPosIncrement; + // qh = Math.round(dest.h / this.drawPosIncrement) * this.drawPosIncrement; + // } + // else { + // otherwise by default we snap to pixel boundaries for perf + qx = ~~(dest.x); + qy = ~~(dest.y); + + // use ceil so that we match the source when scale is equal + qw = 1 + ~~(dest.w); + qh = 1 + ~~(dest.h); + //} + + + ctx.drawImage( + this.texture.image, + source.x, source.y, sourceW, sourceH, // source coordinates + qx, qy, qw, qh); // destination coordinates + + // undo the rotation + if (checkRotation && rotationAngle !== 0) { + if (rotateIsTranslated) { + ctx.translate(rotationPosition.x, rotationPosition.y); + } + ctx.rotate(-rotationAngle); + if (rotateIsTranslated) { + ctx.translate(-rotationPosition.x, -rotationPosition.y); + } + } + + // undo alpha changes + if (alpha !== 1) { + ctx.globalAlpha = previousAlpha; + } + } + }, + draw: function () { + this.preDraw(); + + // only draw if the image is non-transparent + if (this.color.a !== 0) { + var ctx = Canvas.context, + shouldTranslate = ((this.drawX !== 0) || (this.drawY !== 0)); + + if (shouldTranslate) { + ctx.translate(this.drawX, this.drawY); + } + + var count = (this.numberOfQuadsToDraw === Constants.UNDEFINED) + ? this.texCoordinates.length + : this.numberOfQuadsToDraw; + this.drawNumberOfQuads(count); + + if (shouldTranslate) { + ctx.translate(-this.drawX, -this.drawY); + } + } + + this.postDraw(); + } + }); + + return ImageMultiDrawer; + } +); +define('resources/ResourceId', + [], + function () { + + /** + * The resource id corresponds to the index of the entry in the RES_DATA array + * @enum {number} + */ + var ResourceId = { + IMG_DEFAULT: 0, + IMG_LOADERBAR_FULL: 1, + IMG_CHILLINGO: 2, + IMG_MENU_BUTTON_DEFAULT: 3, + FNT_BIG_FONT: 4, + FNT_SMALL_FONT: 5, + IMG_MENU_LOADING: 6, + SND_TAP: 7, + STR_MENU: 8, + SND_BUTTON: 9, + SND_BUBBLE_BREAK: 10, + SND_BUBBLE: 11, + SND_CANDY_BREAK: 12, + SND_MONSTER_CHEWING: 13, + SND_MONSTER_CLOSE: 14, + SND_MONSTER_OPEN: 15, + SND_MONSTER_SAD: 16, + SND_RING: 17, + SND_ROPE_BLEAK_1: 18, + SND_ROPE_BLEAK_2: 19, + SND_ROPE_BLEAK_3: 20, + SND_ROPE_BLEAK_4: 21, + SND_ROPE_GET: 22, + SND_STAR_1: 23, + SND_STAR_2: 24, + SND_STAR_3: 25, + SND_ELECTRIC: 26, + SND_PUMP_1: 27, + SND_PUMP_2: 28, + SND_PUMP_3: 29, + SND_PUMP_4: 30, + SND_SPIDER_ACTIVATE: 31, + SND_SPIDER_FALL: 32, + SND_SPIDER_WIN: 33, + SND_WHEEL: 34, + SND_WIN: 35, + SND_GRAVITY_OFF: 36, + SND_GRAVITY_ON: 37, + SND_CANDY_LINK: 38, + SND_BOUNCER: 39, + IMG_MENU_BGR: 40, + IMG_MENU_BUTTON_CRYSTAL: 41, + IMG_MENU_POPUP: 42, + IMG_MENU_BUTTON_CRYSTAL_ICON: 43, + IMG_MENU_LOGO: 44, + IMG_MENU_LEVEL_SELECTION: 45, + IMG_MENU_PACK_SELECTION: 46, + IMG_MENU_EXTRA_BUTTONS: 47, + IMG_MENU_EXTRA_BUTTONS_EN: 48, + IMG_MENU_BUTTON_SHORT: 49, + IMG_HUD_BUTTONS: 50, + IMG_OBJ_CANDY_01: 51, + IMG_OBJ_SPIDER: 52, + IMG_CONFETTI_PARTICLES: 53, + IMG_MENU_PAUSE: 54, + IMG_MENU_RESULT: 55, + FNT_FONT_NUMBERS_BIG: 56, + IMG_HUD_BUTTONS_EN: 57, + IMG_MENU_RESULT_EN: 58, + IMG_OBJ_STAR_DISAPPEAR: 59, + IMG_OBJ_BUBBLE_FLIGHT: 60, + IMG_OBJ_BUBBLE_POP: 61, + IMG_OBJ_HOOK_AUTO: 62, + IMG_OBJ_SPIKES_04: 63, + IMG_OBJ_BUBBLE_ATTACHED: 64, + IMG_OBJ_HOOK_01: 65, + IMG_OBJ_HOOK_02: 66, + IMG_OBJ_STAR_IDLE: 67, + IMG_HUD_STAR: 68, + IMG_OBJ_SPIKES_03: 69, + IMG_OBJ_SPIKES_02: 70, + IMG_OBJ_SPIKES_01: 71, + IMG_CHAR_ANIMATIONS: 72, + IMG_OBJ_HOOK_REGULATED: 73, + IMG_OBJ_ELECTRODES: 74, + IMG_OBJ_HOOK_MOVABLE: 75, + IMG_OBJ_PUMP: 76, + IMG_TUTORIAL_SIGNS: 77, + IMG_OBJ_SOCKS: 78, + IMG_OBJ_BOUNCER_01: 79, + IMG_OBJ_BOUNCER_02: 80, + IMG_OBJ_VINIL: 81, + SND_SCRATCH_IN: 82, + SND_SCRATCH_OUT: 83, + SND_BUZZ: 84, + SND_TELEPORT: 85, + + SND_MENU_MUSIC: 105, + SND_GAME_MUSIC: 106, + SND_GAME_MUSIC2: 107, + + IMG_DRAWING_HIDDEN: 108, + IMG_OBJ_ROTATABLE_SPIKES_01: 111, + IMG_OBJ_ROTATABLE_SPIKES_02: 112, + IMG_OBJ_ROTATABLE_SPIKES_03: 113, + IMG_OBJ_ROTATABLE_SPIKES_04: 114, + IMG_OBJ_ROTATABLE_SPIKES_BUTTON: 115, + IMG_OBJ_BEE_HD: 116, + IMG_OBJ_POLLEN_HD: 117, + SND_SPIKE_ROTATE_IN: 118, + SND_SPIKE_ROTATE_OUT: 119, + IMG_CHAR_SUPPORTS: 120, + + IMG_BGR_01_P1: 121, + IMG_BGR_01_P2: 122, + IMG_BGR_02_P1: 123, + IMG_BGR_02_P2: 124, + IMG_BGR_03_P1: 125, + IMG_BGR_03_P2: 126, + IMG_BGR_04_P1: 127, + IMG_BGR_04_P2: 128, + IMG_BGR_05_P1: 129, + IMG_BGR_05_P2: 130, + IMG_BGR_06_P1: 131, + IMG_BGR_06_P2: 132, + IMG_BGR_07_P1: 133, + IMG_BGR_07_P2: 134, + IMG_BGR_08_P1: 135, + IMG_BGR_08_P2: 136, + IMG_BGR_09_P1: 137, + IMG_BGR_09_P2: 138, + IMG_BGR_10_P1: 139, + IMG_BGR_10_P2: 140, + IMG_BGR_11_P1: 141, + IMG_BGR_11_P2: 142, + + IMG_BGR_IE: 143, + + IMG_TIME_BGR_1: 144, + IMG_TIME_BGR_2: 145, + IMG_TIME_BGR_3: 146, + IMG_TIME_BGR_4: 147, + IMG_TIME_BGR_5: 148, + IMG_TIME_BGR_6: 149, + + // time edition char animations + IMG_CAESAR_ANIMATIONS_1: 150, + IMG_CAESAR_ANIMATIONS_2: 151, + IMG_CAESAR_ANIMATIONS_3: 152, + IMG_CAESAR_ANIMATIONS_4: 153, + IMG_PAINTER_ANIMATIONS_1: 154, + IMG_PAINTER_ANIMATIONS_2: 155, + IMG_PAINTER_ANIMATIONS_3: 156, + IMG_PAINTER_ANIMATIONS_4: 157, + IMG_PHARAOH_ANIMATIONS_1: 158, + IMG_PHARAOH_ANIMATIONS_2: 159, + IMG_PHARAOH_ANIMATIONS_3: 160, + IMG_PHARAOH_ANIMATIONS_4: 161, + IMG_PIRATE_ANIMATIONS_1: 162, + IMG_PIRATE_ANIMATIONS_2: 163, + IMG_PIRATE_ANIMATIONS_3: 164, + IMG_PIRATE_ANIMATIONS_4: 165, + IMG_PREHISTORIC_ANIMATIONS_1: 166, + IMG_PREHISTORIC_ANIMATIONS_2: 167, + IMG_PREHISTORIC_ANIMATIONS_3: 168, + IMG_PREHISTORIC_ANIMATIONS_4: 169, + IMG_VIKING_ANIMATIONS_1: 170, + IMG_VIKING_ANIMATIONS_2: 171, + IMG_VIKING_ANIMATIONS_3: 172, + IMG_VIKING_ANIMATIONS_4: 173, + + SND_CANDY_HIT: 174, + SND_PREHISTORIC_MONSTER_CHEWING : 175, + SND_PREHISTORIC_MONSTER_OPEN : 176, + SND_PREHISTORIC_MONSTER_CLOSE : 177, + SND_PREHISTORIC_MONSTER_SAD : 178, + SND_TIME_MENU_MUSIC: 179, + IMG_TIME_STANDS: 180, + + RESOURCES_COUNT: 180 + }; + + return ResourceId; + } +); + +define('ResInfo', + [ + 'resources/ResourceId' + ], + function (ResourceId) { + + var RES_INFO_2560 = [ + {id: 0}, + {id: 1}, + {id: 2}, + {id: 4, charOffset: -1, lineOffset: -42, spaceWidth: 20, chars: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u00a9\u00c0\u00e0\u00c2\u00e2\u00c6\u00e6\u00c7\u00e7\u00c8\u00e8\u00c9\u00e9\u00ca\u00ea\u00cb\u00eb\u00ce\u00ee\u00cf\u00ef\u00d4\u00f4\u0152\u0153\u00d9\u00f9\u00db\u00fb\u00dc\u00fc\u00ab\u00bb\u20ac\u00c4\u00e4\u00c9\u00e9\u00d6\u00f6\u00dc\u00fc\u00df\u201e\u201c\u201d\u00b0\u0410\u0411\u0412\u0413\u0414\u0415\u0401\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", + kerning: {}, rects: [4, 4, 33, 156, 41, 4, 38, 156, 83, 4, 61, 156, 148, 4, 41, 156, 193, 4, 73, 156, 270, 4, 38, 156, 312, 4, 19, 156, 335, 4, 44, 156, 383, 4, 41, 156, 428, 4, 54, 156, 486, 4, 43, 156, 533, 4, 22, 156, 559, 4, 46, 156, 609, 4, 23, 156, 636, 4, 51, 156, 691, 4, 54, 156, 749, 4, 23, 156, 776, 4, 53, 156, 833, 4, 44, 156, 881, 4, 48, 156, 933, 4, 51, 156, 4, 164, 49, 156, 57, 164, 52, 156, 113, 164, 55, 156, 172, 164, 41, 156, 217, 164, 24, 156, 245, 164, 24, 156, 273, 164, 59, 156, 336, 164, 36, 156, 376, 164, 51, 156, 431, 164, 44, 156, 479, 164, 62, 156, 545, 164, 51, 156, 600, 164, 51, 156, 655, 164, 58, 156, 717, 164, + 48, 156, 769, 164, 46, 156, 819, 164, 45, 156, 868, 164, 50, 156, 922, 164, 49, 156, 975, 164, 24, 156, 4, 324, 45, 156, 53, 324, 45, 156, 102, 324, 54, 156, 160, 324, 73, 156, 237, 324, 43, 156, 284, 324, 63, 156, 351, 324, 59, 156, 414, 324, 54, 156, 472, 324, 51, 156, 527, 324, 57, 156, 588, 324, 56, 156, 648, 324, 59, 156, 711, 324, 52, 156, 767, 324, 74, 156, 845, 324, 63, 156, 912, 324, 47, 156, 4, 484, 67, 156, 75, 484, 65, 156, 144, 484, 54, 156, 202, 484, 56, 156, 262, 484, 40, 156, 306, 484, 74, 156, 384, 484, 24, 156, 412, 484, 45, 156, 461, 484, 51, 156, 516, 484, 49, 156, 569, 484, 48, 156, 621, 484, 43, 156, 668, 484, + 47, 156, 719, 484, 42, 156, 765, 484, 43, 156, 812, 484, 25, 156, 841, 484, 39, 156, 884, 484, 50, 156, 938, 484, 22, 156, 4, 644, 69, 156, 77, 644, 40, 156, 121, 644, 37, 156, 162, 644, 45, 156, 211, 644, 63, 156, 278, 644, 43, 156, 325, 644, 44, 156, 373, 644, 52, 156, 429, 644, 46, 156, 479, 644, 54, 156, 537, 644, 73, 156, 614, 644, 59, 156, 677, 644, 54, 156, 735, 644, 58, 156, 797, 644, 57, 156, 858, 644, 25, 156, 887, 644, 42, 156, 933, 644, 49, 156, 4, 804, 75, 156, 83, 804, 51, 156, 138, 804, 44, 156, 186, 804, 51, 156, 241, 804, 47, 156, 292, 804, 83, 156, 379, 804, 62, 156, 445, 804, 54, 156, 503, 804, 43, 156, 550, 804, + 45, 156, 599, 804, 45, 156, 648, 804, 45, 156, 697, 804, 45, 156, 746, 804, 45, 156, 795, 804, 45, 156, 844, 804, 45, 156, 893, 804, 45, 156, 942, 804, 41, 156, 4, 964, 41, 156, 49, 964, 33, 156, 86, 964, 34, 156, 124, 964, 63, 156, 191, 964, 48, 156, 243, 964, 82, 156, 329, 964, 61, 156, 394, 964, 53, 156, 451, 964, 44, 156, 499, 964, 53, 156, 556, 964, 43, 156, 603, 964, 53, 156, 660, 964, 43, 156, 707, 964, 53, 156, 764, 964, 59, 156, 827, 964, 65, 156, 896, 964, 51, 156, 951, 964, 44, 156, 4, 1124, 45, 156, 53, 1124, 45, 156, 102, 1124, 63, 156, 169, 1124, 48, 156, 221, 1124, 53, 156, 278, 1124, 43, 156, 325, 1124, 53, 156, + 382, 1124, 43, 156, 429, 1124, 43, 156, 476, 1124, 43, 156, 523, 1124, 40, 156, 567, 1124, 65, 156, 636, 1124, 47, 156, 687, 1124, 50, 156, 741, 1124, 49, 156, 794, 1124, 64, 156, 862, 1124, 46, 156, 912, 1124, 46, 156, 4, 1284, 73, 156, 81, 1284, 46, 156, 131, 1284, 54, 156, 189, 1284, 54, 156, 247, 1284, 62, 156, 313, 1284, 62, 156, 379, 1284, 64, 156, 447, 1284, 52, 156, 503, 1284, 59, 156, 566, 1284, 53, 156, 623, 1284, 48, 156, 675, 1284, 49, 156, 728, 1284, 59, 156, 791, 1284, 55, 156, 850, 1284, 59, 156, 913, 1284, 55, 156, 4, 1444, 58, 156, 66, 1444, 49, 156, 119, 1444, 72, 156, 195, 1444, 83, 156, 282, 1444, 62, + 156, 348, 1444, 58, 156, 410, 1444, 50, 156, 464, 1444, 48, 156, 516, 1444, 67, 156, 587, 1444, 51, 156, 642, 1444, 44, 156, 690, 1444, 41, 156, 735, 1444, 39, 156, 778, 1444, 37, 156, 819, 1444, 41, 156, 864, 1444, 40, 156, 908, 1444, 40, 156, 952, 1444, 61, 156, 4, 1604, 38, 156, 46, 1604, 43, 156, 93, 1604, 43, 156, 140, 1604, 44, 156, 188, 1604, 45, 156, 237, 1604, 62, 156, 303, 1604, 42, 156, 349, 1604, 40, 156, 393, 1604, 49, 156, 446, 1604, 46, 156, 496, 1604, 38, 156, 538, 1604, 69, 156, 611, 1604, 42, 156, 657, 1604, 61, 156, 722, 1604, 43, 156, 769, 1604, 45, 156, 818, 1604, 40, 156, 862, 1604, 63, 156, 929, 1604, + 65, 156, 4, 1764, 51, 156, 59, 1764, 51, 156, 114, 1764, 40, 156, 158, 1764, 39, 156, 201, 1764, 60, 156, 265, 1764, 40, 156, 309, 1764, 112, 156]}, + {id: 5, charOffset: 8, lineOffset: -140, spaceWidth: 45, chars: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u00a9\u00c0\u00e0\u00c2\u00e2\u00c6\u00e6\u00c7\u00e7\u00c8\u00e8\u00c9\u00e9\u00ca\u00ea\u00cb\u00eb\u00ce\u00ee\u00cf\u00ef\u00d4\u00f4\u0152\u0153\u00d9\u00f9\u00db\u00fb\u00dc\u00fc\u00ab\u00bb\u20ac\u00c4\u00e4\u00c9\u00e9\u00d6\u00f6\u00dc\u00fc\u00df\u201e\u201c\u201d\u00b0\u0410\u0411\u0412\u0413\u0414\u0415\u0401\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", + kerning: {}, rects: [4, 4, 16, 156, 24, 4, 19, 156, 47, 4, 35, 156, 86, 4, 21, 156, 111, 4, 43, 156, 158, 4, 19, 156, 181, 4, 7, 156, 192, 4, 24, 156, 220, 4, 23, 156, 247, 4, 30, 156, 281, 4, 24, 156, 309, 4, 9, 156, 322, 4, 25, 156, 351, 4, 10, 156, 365, 4, 28, 156, 397, 4, 31, 156, 432, 4, 10, 156, 446, 4, 29, 156, 479, 4, 24, 156, 507, 4, 26, 156, 537, 4, 29, 156, 570, 4, 28, 156, 602, 4, 29, 156, 635, 4, 31, 156, 670, 4, 21, 156, 695, 4, 10, 156, 709, 4, 10, 156, 723, 4, 33, 156, 760, 4, 19, 156, 783, 4, 28, 156, 815, 4, 24, 156, 843, 4, 36, 156, 883, 4, 28, 156, 915, 4, 28, 156, 947, 4, 32, 156, 983, 4, 27, 156, 4, 164, 25, 156, 33, 164, 24, + 156, 61, 164, 28, 156, 93, 164, 28, 156, 125, 164, 10, 156, 139, 164, 25, 156, 168, 164, 24, 156, 196, 164, 31, 156, 231, 164, 43, 156, 278, 164, 24, 156, 306, 164, 37, 156, 347, 164, 34, 156, 385, 164, 30, 156, 419, 164, 29, 156, 452, 164, 32, 156, 488, 164, 31, 156, 523, 164, 34, 156, 561, 164, 29, 156, 594, 164, 43, 156, 641, 164, 36, 156, 681, 164, 26, 156, 711, 164, 39, 156, 754, 164, 38, 156, 796, 164, 30, 156, 830, 164, 32, 156, 866, 164, 22, 156, 892, 164, 44, 156, 940, 164, 11, 156, 955, 164, 25, 156, 984, 164, 29, 156, 4, 324, 27, 156, 35, 324, 26, 156, 65, 324, 24, 156, 93, 324, 26, 156, 123, 324, 23, 156, 150, 324, 24, + 156, 178, 324, 11, 156, 193, 324, 20, 156, 217, 324, 28, 156, 249, 324, 9, 156, 262, 324, 41, 156, 307, 324, 21, 156, 332, 324, 20, 156, 356, 324, 25, 156, 385, 324, 36, 156, 425, 324, 22, 156, 451, 324, 24, 156, 479, 324, 29, 156, 512, 324, 26, 156, 542, 324, 31, 156, 577, 324, 43, 156, 624, 324, 34, 156, 662, 324, 30, 156, 696, 324, 33, 156, 733, 324, 32, 156, 769, 324, 12, 156, 785, 324, 22, 156, 811, 324, 27, 156, 842, 324, 45, 156, 891, 324, 29, 156, 924, 324, 24, 156, 952, 324, 29, 156, 985, 324, 26, 156, 4, 484, 49, 156, 57, 484, 36, 156, 97, 484, 30, 156, 131, 484, 23, 156, 158, 484, 24, 156, 186, 484, 24, 156, 214, 484, + 24, 156, 242, 484, 24, 156, 270, 484, 24, 156, 298, 484, 24, 156, 326, 484, 24, 156, 354, 484, 24, 156, 382, 484, 22, 156, 408, 484, 22, 156, 434, 484, 17, 156, 455, 484, 17, 156, 476, 484, 36, 156, 516, 484, 27, 156, 547, 484, 50, 156, 601, 484, 35, 156, 640, 484, 29, 156, 673, 484, 24, 156, 701, 484, 29, 156, 734, 484, 23, 156, 761, 484, 29, 156, 794, 484, 23, 156, 821, 484, 30, 156, 855, 484, 34, 156, 893, 484, 37, 156, 934, 484, 29, 156, 967, 484, 24, 156, 995, 484, 24, 156, 4, 644, 24, 156, 32, 644, 36, 156, 72, 644, 27, 156, 103, 644, 29, 156, 136, 644, 23, 156, 163, 644, 30, 156, 197, 644, 23, 156, 224, 644, 23, 156, 251, + 644, 23, 156, 278, 644, 22, 156, 304, 644, 38, 156, 346, 644, 26, 156, 376, 644, 28, 156, 408, 644, 28, 156, 440, 644, 38, 156, 482, 644, 25, 156, 511, 644, 25, 156, 540, 644, 44, 156, 588, 644, 26, 156, 618, 644, 30, 156, 652, 644, 30, 156, 686, 644, 37, 156, 727, 644, 36, 156, 767, 644, 37, 156, 808, 644, 29, 156, 841, 644, 34, 156, 879, 644, 30, 156, 913, 644, 28, 156, 945, 644, 27, 156, 976, 644, 34, 156, 4, 804, 31, 156, 39, 804, 34, 156, 77, 804, 31, 156, 112, 804, 33, 156, 149, 804, 28, 156, 181, 804, 43, 156, 228, 804, 51, 156, 283, 804, 36, 156, 323, 804, 33, 156, 360, 804, 28, 156, 392, 804, 27, 156, 423, 804, 40, 156, + 467, 804, 29, 156, 500, 804, 24, 156, 528, 804, 22, 156, 554, 804, 20, 156, 578, 804, 19, 156, 601, 804, 22, 156, 627, 804, 21, 156, 652, 804, 21, 156, 677, 804, 36, 156, 717, 804, 20, 156, 741, 804, 24, 156, 769, 804, 24, 156, 797, 804, 24, 156, 825, 804, 25, 156, 854, 804, 35, 156, 893, 804, 24, 156, 921, 804, 22, 156, 947, 804, 28, 156, 979, 804, 26, 156, 4, 964, 20, 156, 28, 964, 41, 156, 73, 964, 23, 156, 100, 964, 36, 156, 140, 964, 24, 156, 168, 964, 25, 156, 197, 964, 22, 156, 223, 964, 37, 156, 264, 964, 38, 156, 306, 964, 30, 156, 340, 964, 29, 156, 373, 964, 22, 156, 399, 964, 21, 156, 424, 964, 35, 156, 463, 964, 22, + 156, 489, 964, 112, 156]}, + {id: 51, preCutWidth: 393, preCutHeight: 418, rects: [2, 2, 218, 226, 224, 2, 151, 151, 2, 232, 157, 158, 224, 157, 98, 62, 326, 157, 48, 45, 379, 2, 49, 59, 432, 2, 55, 57, 379, 65, 53, 63, 163, 232, 146, 147, 2, 394, 153, 163, 2, 561, 153, 166, 2, 731, 156, 169, 2, 904, 163, 175, 169, 904, 159, 175, 159, 394, 159, 159, 313, 232, 150, 150, 322, 394, 144, 150, 159, 561, 138, 146, 2, 1083, 302, 303, 301, 561, 107, 158, 412, 561, 96, 157, 2, 1390, 252, 268, 2, 1662, 278, 305, 2, 1971, 371, 397, 2, 2372, 385, 396, 2, 2772, 377, 386], offsets: [103, 130, 122, 133, 119, 131, 145, 176, 168, 182, 171, + 177, 168, 182, 160, 176, 119, 128, 115, 115, 115, 112, 115, 112, 115, 112, 119, 115, 122, 134, 131, 143, 137, 143, 140, 147, 47, 56, 143, 133, 155, 133, 69, 83, 50, 37, 6, -2, 0, -5, 8, 2]}, + {id: 52, preCutWidth: 552, preCutHeight: 552, rects: [0, 0, 88, 85, 0, 85, 46, 152, 46, 85, 106, 149, 0, 237, 78, 162, 78, 237, 93, 155, 0, 399, 88, 158, 152, 85, 46, 152, 88, 399, 144, 145, 0, 557, 138, 141, 0, 698, 145, 145, 0, 843, 146, 141, 0, 984, 161, 140, 0, 1124, 130, 155], offsets: [235, 190, 256, 121, 226, 124, 240, 111, 233, 118, 235, 115, 256, 121, 213, 220, 219, 232, 212, 220, 211, 232, 203, 178, 211, 273]}, + {id: 53, preCutWidth: 290, + preCutHeight: 228, rects: [0, 0, 42, 38, 0, 38, 43, 36, 0, 74, 46, 33, 0, 107, 46, 33, 0, 140, 44, 36, 0, 176, 42, 38, 0, 214, 40, 41, 0, 255, 43, 43, 0, 298, 40, 41, 0, 339, 45, 33, 0, 372, 48, 31, 0, 403, 49, 38, 0, 441, 50, 45, 0, 486, 52, 53, 0, 539, 50, 39, 0, 578, 49, 28, 0, 606, 47, 31, 0, 637, 45, 33, 0, 670, 53, 53, 0, 723, 43, 53, 0, 776, 32, 54, 32, 776, 23, 53, 52, 486, 12, 53, 43, 723, 12, 53, 0, 830, 23, 55, 23, 830, 32, 54, 0, 885, 43, 53], offsets: [123, 98, 122, 99, 121, 100, 121, 100, 122, 99, 123, 98, 124, 96, 122, 95, 124, 96, 121, 100, 120, 101, 119, 97, 119, 94, 118, 90, 119, 97, 119, 103, 120, 101, 121, 100, 118, 89, 123, + 89, 128, 89, 133, 89, 138, 89, 138, 89, 133, 88, 128, 89, 123, 89]}, + {id: 56, charOffset: 2, lineOffset: 2, spaceWidth: 10, chars: "0123456789", kerning: {}, rects: [5, 5, 49, 156, 59, 5, 16, 156, 80, 5, 48, 156, 133, 5, 38, 156, 176, 5, 41, 156, 222, 5, 45, 156, 272, 5, 43, 156, 320, 5, 47, 156, 372, 5, 49, 156, 426, 5, 35, 156]}, + {id: 57, preCutWidth: 2560, preCutHeight: 122, rects: [0, 0, 203, 99, 0, 99, 203, 99], offsets: [2347, 9, 2347, 9]}, + {id: 59, preCutWidth: 552, preCutHeight: 552, rects: [0, 0, 246, 268, 0, 268, 334, 370, 246, 0, 205, 231, 0, 638, 308, 353, 0, 991, 387, 461, 0, 1452, 324, 399, 0, 1851, 335, + 328, 0, 2179, 296, 266, 0, 2445, 240, 230, 296, 2179, 207, 217, 308, 638, 204, 205, 240, 2445, 200, 194, 308, 843, 195, 133], offsets: [145, 116, 76, 38, 166, 132, 113, 56, 75, -2, 113, 34, 87, 82, 102, 114, 128, 124, 148, 130, 149, 134, 151, 138, 153, 141]}, + {id: 60, preCutWidth: 250, preCutHeight: 250, rects: [0, 0, 139, 170, 139, 0, 142, 169, 281, 0, 148, 163, 429, 0, 155, 155, 584, 0, 163, 148, 747, 0, 169, 142, 584, 148, 171, 139, 584, 287, 169, 141, 755, 148, 165, 145, 755, 293, 159, 151, 429, 155, 153, 159, 281, 163, 147, 164, 139, 169, 141, 169, 0, 170, 139, 170], offsets: [55, 40, 54, 41, 51, 44, 47, 48, 43, 51, + 40, 54, 39, 56, 40, 55, 42, 53, 46, 50, 48, 46, 51, 44, 54, 41, 55, 40]}, + {id: 61, preCutWidth: 449, preCutHeight: 446, rects: [0, 0, 308, 285, 0, 285, 302, 282, 0, 567, 297, 281, 0, 848, 296, 277, 0, 1125, 293, 274, 0, 1399, 293, 273, 0, 1672, 295, 271, 0, 1943, 297, 269, 0, 2212, 239, 226, 239, 2212, 241, 223, 0, 2438, 244, 221, 244, 2438, 249, 219], offsets: [83, 82, 87, 84, 90, 86, 91, 90, 93, 94, 92, 99, 90, 104, 88, 111, 101, 119, 97, 128, 92, 138, 86, 148]}, + {id: 62, preCutWidth: 275, preCutHeight: 275, rects: [0, 0, 140, 144, 0, 144, 42, 37], offsets: [69, 62, 117, 119]}, + {id: 63, preCutWidth: 833, preCutHeight: 250, + rects: [0, 0, 566, 93], offsets: [133, 76]}, + {id: 64, preCutWidth: 250, preCutHeight: 250, rects: [0, 0, 155, 154, 0, 154, 181, 210, 0, 364, 185, 180, 0, 544, 183, 178], offsets: [47, 50, 32, 36, 35, 40, 35, 40]}, + {id: 65, preCutWidth: 275, preCutHeight: 275, rects: [0, 0, 125, 126, 0, 126, 37, 35], offsets: [78, 76, 122, 121]}, + {id: 66, preCutWidth: 275, preCutHeight: 275, rects: [0, 0, 125, 126, 0, 126, 37, 35], offsets: [75, 76, 119, 121]}, + {id: 67, preCutWidth: 552, preCutHeight: 552, rects: [2, 2, 234, 221, 240, 2, 77, 76, 240, 82, 70, 76, 321, 2, 64, 76, 321, 82, 58, 76, 389, 2, 51, 76, 389, 82, 46, 76, + 444, 2, 40, 77, 444, 83, 34, 77, 488, 2, 28, 78, 488, 84, 28, 78, 520, 2, 35, 77, 559, 2, 42, 77, 605, 2, 48, 77, 657, 2, 56, 77, 717, 2, 63, 77, 784, 2, 69, 77, 857, 2, 76, 77, 857, 83, 83, 78, 2, 227, 175, 175, 181, 227, 175, 175, 360, 227, 175, 175, 539, 227, 175, 175, 718, 227, 175, 175, 2, 406, 175, 175, 181, 406, 175, 175, 360, 406, 175, 175, 539, 406, 175, 175, 718, 406, 175, 175, 2, 585, 175, 175, 181, 585, 175, 175, 360, 585, 175, 175, 539, 585, 175, 175, 718, 585, 175, 175, 2, 764, 175, 175, 181, 764, 175, 175, 360, 764, 175, 175, 539, 764, 175, 175, 718, 764, 175, 175, 2, 943, 175, 175, 181, 943, 175, 175, 360, 943, 175, + 175, 539, 943, 175, 175, 718, 943, 175, 175, 2, 1122, 175, 175, 2, 1301, 175, 175, 2, 1480, 175, 175, 2, 1659, 175, 175, 2, 1838, 175, 175, 181, 1122, 175, 175, 360, 1122, 175, 175, 539, 1122, 175, 175, 718, 1122, 175, 175, 181, 1301, 175, 175, 181, 1480, 175, 175, 181, 1659, 175, 175, 360, 1301, 229, 231, 593, 1301, 229, 231, 360, 1536, 490, 492], offsets: [156, 156, 233, 231, 236, 231, 239, 231, 242, 231, 246, 231, 248, 231, 251, 231, 254, 231, 257, 231, 257, 231, 253, 231, 250, 231, 247, 231, 243, 231, 240, 231, 237, 231, 234, 231, 230, 230, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 155, 159, 155, 159, 27, 21]}, + {id: ResourceId.IMG_HUD_STAR, preCutWidth: 100, preCutHeight: 100, rects: [0,0,84,85,84,0,58,85,142,0,32,85,174,0,12,85,186,0,28,85,214,0,44,85,258,0,60,85,318,0,70,85,388,0,78,85,466,0,84,85,550,0,84,85], offsets: [6,5,19,5,32,5,42,5,34,5,26,5,18,5,13,5,9,5,6,5,6,5] }, + {id: 69, + preCutWidth: 833, preCutHeight: 250, rects: [0, 0, 453, 93], offsets: [191, 76]}, + {id: 70, preCutWidth: 833, preCutHeight: 250, rects: [0, 0, 333, 93], offsets: [251, 79]}, + {id: 71, preCutWidth: 833, preCutHeight: 250, rects: [0, 0, 212, 93], offsets: [310, 79]}, + {id: 72, preCutWidth: 640, preCutHeight: 640, rects: [0, 0, 291, 302, 291, 0, 363, 409, 654, 0, 383, 309, 1037, 0, 314, 335, 1351, 0, 326, 334, 1677, 0, 374, 330, 291, 409, 405, 492, 2051, 0, 350, 334, 0, 302, 201, 207, 0, 509, 201, 206, 0, 715, 201, 207, 0, 922, 201, 207, 0, 1129, 201, 206, 0, 1335, 201, 210, 0, 1545, 201, 213, 0, 1758, 201, 215, + 0, 1973, 201, 219, 0, 2192, 201, 222, 0, 2414, 201, 223, 0, 2637, 201, 222, 0, 2859, 201, 224, 0, 3083, 201, 224, 0, 3307, 201, 224, 0, 3531, 201, 221, 0, 3752, 201, 218, 2401, 0, 201, 214, 2602, 0, 201, 211, 2803, 0, 222, 196, 2803, 196, 210, 201, 3025, 0, 203, 209, 3228, 0, 197, 214, 3425, 0, 193, 217, 3618, 0, 194, 219, 3812, 0, 197, 210, 291, 901, 200, 202, 3812, 210, 204, 197, 291, 1103, 208, 199, 291, 1302, 212, 202, 291, 1504, 214, 205, 291, 1709, 216, 206, 291, 1915, 204, 226, 291, 2141, 203, 213, 495, 1915, 201, 210, 494, 2141, 201, 208, 291, 2354, 201, 203, 3025, 209, 201, 200, 491, 901, 201, 200, 492, 2354, 201, + 200, 291, 2557, 201, 200, 291, 2757, 201, 207, 291, 2964, 201, 216, 492, 2557, 204, 194, 291, 3180, 221, 171, 291, 3351, 249, 197, 291, 3548, 225, 201, 291, 3749, 205, 205, 492, 2964, 202, 213, 696, 409, 201, 222, 897, 409, 201, 222, 1098, 409, 205, 221, 1303, 409, 229, 213, 1532, 409, 243, 205, 0, 3970, 153, 86, 654, 309, 140, 89, 1775, 409, 212, 196, 1987, 409, 208, 209, 496, 3749, 197, 233, 696, 631, 186, 247, 882, 631, 181, 245, 1063, 631, 186, 243, 1249, 631, 194, 234, 1443, 631, 199, 230, 2195, 409, 199, 221, 1642, 631, 199, 223, 1841, 631, 199, 226, 2040, 631, 199, 228, 2239, 631, 199, 230, 2438, 631, 199, + 230, 2637, 631, 199, 230, 2836, 631, 195, 234, 3031, 631, 190, 238, 3221, 631, 194, 231, 2394, 409, 201, 217, 2595, 409, 207, 209, 2802, 409, 218, 202, 3020, 409, 211, 206, 3231, 409, 206, 210, 3437, 409, 210, 213, 3647, 409, 215, 218, 3415, 631, 220, 223, 3862, 409, 224, 216, 3635, 631, 219, 212, 492, 2757, 195, 205, 3854, 631, 195, 207, 696, 878, 195, 210, 891, 878, 217, 214, 891, 1092, 225, 215, 891, 1307, 219, 215, 696, 1088, 195, 215, 696, 1303, 195, 215, 696, 1518, 195, 215, 891, 1522, 217, 215, 891, 1737, 225, 215, 891, 1952, 223, 218, 891, 2170, 219, 222, 891, 2392, 215, 224, 891, 2616, 216, 216, 1108, 878, + 210, 206, 1318, 878, 218, 202, 1536, 878, 205, 190, 1741, 878, 203, 194, 1944, 878, 202, 206, 2146, 878, 203, 214, 891, 2832, 204, 217, 891, 3049, 204, 216, 2349, 878, 204, 213, 2553, 878, 205, 204, 2758, 878, 205, 192, 2401, 214, 201, 195, 2963, 878, 201, 206, 3164, 878, 204, 212, 3368, 878, 205, 214, 891, 3265, 207, 215, 891, 3480, 208, 216, 3573, 878, 205, 205, 3778, 878, 226, 202, 891, 3696, 212, 204, 696, 1733, 195, 210, 696, 1943, 189, 213, 696, 2156, 190, 218, 696, 2374, 193, 222, 1116, 1092, 198, 213, 1314, 1092, 203, 210, 1517, 1092, 207, 202, 1724, 1092, 211, 204, 1935, 1092, 214, 207, 2149, 1092, 216, + 211, 2365, 1092, 216, 212, 2581, 1092, 216, 212, 2797, 1092, 216, 212, 3013, 1092, 216, 212, 3229, 1092, 216, 212, 3445, 1092, 216, 212, 3661, 1092, 216, 212, 3877, 1092, 216, 212, 1116, 1305, 216, 212, 1116, 1517, 212, 216, 1116, 1733, 206, 222, 1116, 1955, 202, 225, 1116, 2180, 205, 222, 1116, 2402, 210, 213, 1116, 2615, 212, 208, 1116, 2823, 198, 223, 1116, 3046, 196, 232, 696, 2596, 195, 236, 1116, 3278, 198, 236, 1116, 3514, 206, 238, 1116, 3752, 211, 226, 1332, 1305, 217, 207, 891, 3900, 213, 195, 1549, 1305, 212, 179, 1761, 1305, 221, 178, 1982, 1305, 221, 181, 2203, 1305, 215, 180, 2418, 1305, 212, + 179, 2630, 1305, 221, 177, 2851, 1305, 221, 180, 3072, 1305, 215, 180, 3287, 1305, 212, 179, 3499, 1305, 221, 177, 3720, 1305, 221, 180, 1332, 1512, 215, 180, 1332, 1692, 212, 179, 1547, 1512, 216, 176, 1332, 1871, 213, 175, 696, 2832, 194, 205, 696, 3037, 188, 236, 696, 3273, 194, 233, 1332, 2046, 210, 202, 1332, 2248, 204, 194, 1332, 2442, 202, 204], offsets: [173, 274, 137, 156, 133, 207, 152, 237, 154, 244, 134, 240, 107, 104, 148, 242, 220, 227, 220, 227, 220, 227, 220, 227, 220, 227, 220, 224, 220, 221, 220, 218, 220, 215, 220, 212, 220, 211, 220, 211, 220, 210, 220, 210, 220, 210, 220, 213, 220, 216, 220, + 220, 220, 223, 211, 238, 216, 233, 220, 225, 223, 220, 225, 217, 224, 215, 223, 224, 221, 232, 219, 237, 217, 235, 215, 232, 214, 229, 213, 228, 217, 208, 218, 221, 219, 224, 219, 226, 219, 231, 219, 234, 219, 234, 219, 234, 219, 234, 219, 226, 219, 218, 218, 240, 210, 263, 192, 237, 204, 233, 217, 229, 220, 221, 220, 212, 220, 212, 217, 212, 202, 221, 195, 229, 240, 264, 249, 265, 215, 238, 217, 225, 223, 201, 228, 187, 231, 189, 228, 191, 223, 200, 220, 204, 220, 213, 220, 211, 220, 208, 220, 206, 220, 204, 220, 204, 220, 204, 222, 200, 225, 196, 223, 203, 220, 217, 216, 225, 211, 232, 216, 228, 218, 224, 212, 221, 208, + 216, 205, 211, 202, 218, 208, 222, 232, 229, 232, 227, 232, 224, 210, 220, 202, 219, 208, 219, 232, 219, 232, 219, 232, 219, 210, 219, 202, 219, 202, 216, 205, 212, 207, 210, 208, 218, 217, 228, 211, 232, 216, 244, 218, 240, 219, 227, 220, 219, 220, 216, 220, 217, 220, 221, 218, 230, 216, 242, 220, 239, 220, 228, 217, 222, 216, 220, 214, 219, 213, 218, 216, 229, 207, 232, 214, 230, 224, 224, 227, 221, 226, 216, 225, 212, 222, 220, 219, 224, 218, 231, 216, 229, 214, 226, 213, 222, 213, 221, 213, 221, 213, 221, 213, 221, 213, 221, 213, 221, 213, 221, 213, 221, 213, 221, 215, 217, 218, 211, 220, 208, 218, 212, 216, 221, 215, + 226, 222, 210, 223, 201, 223, 197, 222, 197, 219, 195, 216, 206, 211, 225, 213, 238, 213, 254, 207, 255, 207, 252, 210, 253, 213, 254, 207, 256, 207, 253, 210, 253, 213, 254, 207, 256, 207, 253, 210, 253, 213, 254, 211, 257, 214, 258, 227, 227, 230, 195, 226, 199, 215, 232, 218, 239, 220, 230]}, + {id: 73, preCutWidth: 275, preCutHeight: 275, rects: [0, 0, 137, 139, 137, 0, 105, 100, 0, 139, 235, 235, 0, 374, 240, 246], offsets: [65, 70, 84, 86, 18, 19, 13, 14]}, + {id: 74, preCutWidth: 833, preCutHeight: 250, rects: [0, 0, 507, 85, 0, 85, 507, 100, 0, 185, 507, 100, 0, 285, 507, 97, 0, 382, 507, 92], offsets: [163, 82, + 163, 73, 163, 71, 163, 70, 163, 75]}, + {id: 75, preCutWidth: 276, preCutHeight: 276, rects: [0, 0, 84, 128, 84, 0, 68, 109, 152, 0, 50, 109, 0, 128, 140, 121, 0, 249, 148, 147]}, + {id: 76, preCutWidth: 761, preCutHeight: 761, rects: [0, 0, 220, 239, 0, 239, 206, 290, 0, 529, 205, 290, 0, 819, 220, 246, 0, 1065, 237, 219, 0, 1284, 226, 231, 220, 0, 18, 17, 238, 0, 11, 11, 206, 239, 38, 39], offsets: [271, 262, 286, 232, 287, 232, 271, 249, 262, 272, 268, 266, 382, 376, 385, 379, 372, 365]}, + {id: 77, preCutWidth: 998, preCutHeight: 1058, rects: [3, 3, 148, 12, 3, 21, + 39, 187, 48, 21, 182, 150, 236, 21, 144, 130, 3, 214, 244, 233, 253, 214, 159, 143, 157, 3, 49, 9, 386, 21, 89, 84, 3, 453, 102, 148, 3, 607, 260, 315], offsets: [585, 767, 160, 241, 412, 548, 307, 397, 184, 663, 530, 224, 676, 540, 540, 425, 351, 211, 684, 200]}, + {id: 78, preCutWidth: 431, preCutHeight: 431, rects: [0, 0, 294, 335, 294, 0, 297, 336, 0, 335, 291, 252, 591, 0, 307, 293, 0, 587, 276, 224], offsets: [53, 6, 51, 3, 55, 78, 47, 57, 63, 98]}, + {id: 79, preCutWidth: 833, preCutHeight: 250, rects: [0, 0, 194, 127, 0, 127, 201, 103, 0, 230, 204, 96, 0, 326, 193, 142, 0, 468, 194, 111], offsets: [319, 69, 316, 81, + 314, 87, 319, 55, 319, 77]}, + {id: 80, preCutWidth: 833, preCutHeight: 250, rects: [0, 0, 302, 123, 302, 0, 319, 99, 621, 0, 322, 95, 302, 99, 292, 136, 0, 123, 302, 111], offsets: [268, 70, 260, 85, 258, 87, 273, 58, 268, 77]}, + {id: 58, + preCutWidth: 2028, preCutHeight: 1597, rects: [0, 0, 239, 239], offsets: [811, 344]}, + {id: 3, preCutWidth: 936, preCutHeight: 418, rects: [0, 0, 735, 174, 0, 174, 727, 173], offsets: [102, 116, 107, 117]}, + {id: 6, preCutWidth: 2560, preCutHeight: 1440, rects: [2, 2, 58, 1303, 64, 2, 65, 1303, 133, 2, 305, 405, 133, 411, 835, 789], offsets: [1216, 67, 1274, 67, 1096, 31, 455, 578]}, + {id: 40, preCutWidth: 2560, preCutHeight: 1440, rects: [2, 2, 2560, 1440, 2566, 2, 2560, 920, 5130, 2, 1781, 1781], offsets: [0, 0, 0, 520, 388, -172]}, + {id: 41, preCutWidth: 193, preCutHeight: 193, rects: [0, 0, 187, + 149, 0, 149, 187, 149], offsets: [4, 23, 4, 23]}, + {id: 42, preCutWidth: 2560, preCutHeight: 1440, rects: [0, 0, 792, 792, 792, 0, 7, 8, 799, 0, 7, 8, 806, 0, 7, 7, 813, 0, 7, 7, 820, 0, 7, 8], offsets: [880, 283, 1289, 403, 1289, 665, 1289, 770, 1289, 1026, 1289, 531]}, + {id: 43, preCutWidth: 833, preCutHeight: 250, rects: [0, 0, 128, 93], offsets: [133, 76]}, + {id: 44, preCutWidth: 1076, preCutHeight: 983, rects: [0, 0, 868, 795, 0, 795, 267, 300, 267, 795, 305, 135], offsets: [101, 113, 434, 316, 408, 405]}, + {id: 45, preCutWidth: 218, preCutHeight: 218, rects: [0, 0, 190, 196, 0, 196, 202, 208, 0, 404, 143, + 77, 0, 481, 141, 77, 0, 558, 143, 77, 0, 635, 142, 77], offsets: [10, 10, 5, 7, 58, 139, 59, 139, 58, 139, 58, 139]}, + {id: 46, preCutWidth: 1129, preCutHeight: 1092, rects: [2, 2, 229, 183, 235, 2, 166, 174, 405, 2, 146, 69, 405, 75, 146, 85, 555, 2, 144, 140, 703, 2, 173, 166, 2, 189, 162, 168, 2, 361, 169, 170, 2, 535, 166, 171, 2, 710, 166, 175, 172, 710, 166, 172, 342, 710, 166, 174, 512, 710, 166, 174, 682, 710, 166, 174, 2, 889, 477, 221, 880, 2, 58, 58, 2, 1114, 434, 472, 2, 1590, 445, 481, 440, 1114, 434, 472, 451, 1590, 434, 472, 2, 2075, 434, 481, 440, 2075, 434, 473, 2, 2560, 434, 473, 440, 2560, 467, 473, 2, 3037, + 436, 459, 168, 189, 103, 124, 880, 64, 84, 103, 275, 189, 103, 124, 382, 189, 83, 103], offsets: [464, 598, 499, 616, 513, 714, 511, 695, 513, 622, 496, 632, 503, 645, 497, 627, 499, 619, 499, 617, 499, 618, 499, 616, 499, 616, 499, 616, 339, 558, 548, 667, 362, 365, 358, 364, 362, 364, 362, 364, 362, 364, 362, 363, 362, 363, 329, 363, 360, 363, 533, 586, 543, 595, 534, 586, 543, 595]}, + {id: 47, preCutWidth: 679, preCutHeight: 206, rects: [0, 0, 208, 206, 0, 206, 205, 204, 0, 410, 92, 95, 92, 410, 92, 95], offsets: [0, -2, 1, 1, 457, 90, 563, 90]}, + {id: 48, preCutWidth: 679, preCutHeight: 206, rects: [0, 0, 291, + 49], offsets: [143, 106]}, + {id: 49, preCutWidth: 936, preCutHeight: 418, rects: [0, 0, 420, 174, 0, 174, 419, 173], offsets: [262, 115, 263, 115]}, + {id: 50, preCutWidth: 2560, preCutHeight: 122, rects: [0, 0, 96, 97, 96, 0, 96, 97], offsets: [2237, 9, 2237, 9]}, + {id: 54, preCutWidth: 2560, preCutHeight: 380, rects: [0, 0, 2560, 310]}, + {id: 55, preCutWidth: 2560, preCutHeight: 1597, rects: [1, 1, 7, 7, 10, 1, 7, 7, 19, 1, 7, 7, 28, 1, 7, 7, 37, 1, 7, 7, 46, 1, 8, 7, 56, 1, 7, 7, 65, 1, 7, 7, 74, 1, 7, 7, 83, 1, 7, 7, 92, 1, 7, 7, 101, 1, 7, 7, 110, 1, 7, 7, 1, 10, 228, 218, 231, 10, 210, 203, 1, 230, 626, 11, 1, 243, 889, 398], + offsets: [1052, 556, 1261, 556, 1467, 556, 1261, 378, 1264, 771, 1117, 721, 1461, 721, 1264, 721, 1264, 840, 1261, 1186, 1495, 993, 1052, 993, 1617, 768, 816, 350, 825, 358, 603, 465, 153, 89]}, + {id: 108, rects: [0, 0, 198, 194, 0, 194, 198, 194, 0, 388, 198, 194]}, + + // rotateable spikes + {id: 111, rects: [0, 0, 202, 81], offsets: [316, 87], preCutWidth: 833, preCutHeight: 250 }, + {id: 112, rects: [0, 0, 319, 83], offsets: [260, 87], preCutWidth: 833, preCutHeight: 250 }, + {id: 113, rects: [0, 0, 444, 86], offsets: [195, 81], preCutWidth: 833, preCutHeight: 250 }, + {id: 114, rects: [0, 0, 559, 89], offsets: [137, 77], preCutWidth: 833, preCutHeight: 250 }, + {id: 115, rects: [0, 0, 101, 102, 0, 102, 101, 102, 0, 204, 101, 102, 0, 306, 101, 102], offsets: [219, 29, 218, 29, 219, 29, 219, 29], preCutWidth: 534, preCutHeight: 160 }, + + // bee and pollen + {id: 116, preCutWidth: 275, preCutHeight: 275, rects: [0, 0, 4, 4, 2, 2, 89, 116, 95, 2, 177, 37, 276, 2, 187, 77, 95, 43, 87, 61], offsets: [143, 196, 93, 75, 50, 84, 45, 39, 95, 35]}, + {id: 117, preCutWidth: 25, preCutHeight: 25, rects: [0, 0, 25, 25]}, + + // character supports (platform OmNom sits on) + { id: ResourceId.IMG_CHAR_SUPPORTS, rects: [0, 0, 291, 302, 0, 302, 363, 409, 363, 302, 383, 309, 0, 711, 405, 492, 405, 711, 374, 330, 0, 1203, 350, 334, 0, 1537, 314, 335, 350, 1203, 326, 334, 291, 0, 339, 288, 630, 0, 275, 162, 350, 1537, 372, 317], offsets: [173, 274, 137, 156, 133, 207, 107, 104, 134, 240, 148, 242, 152, 237, 154, 244, 145, 259, 181, 392, 123, 236], preCutWidth: 640, preCutHeight: 640 }, + + // vinyl record + { id: ResourceId.IMG_OBJ_VINIL, rects: [1, 1, 1064, 1064, 1067, 1, 532, 495, 1601, 1, 145, 286, 1601, 289, 38, 38, 1748, 1, 204, 174, 1748, 177, 183, 154], offsets: [55, 154, 55, 686, 442, 543, 568, 667, 484, 1083, 493, 1093], preCutWidth: 1174, preCutHeight: 1498 }, + + // background images + { id: ResourceId.IMG_BGR_01_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2305}, + { id: ResourceId.IMG_BGR_01_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 708], offsets: [0, 896], preCutWidth: 2048, preCutHeight: 2305}, + { id: ResourceId.IMG_BGR_02_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_02_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 874], offsets: [0, 835], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_03_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_03_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1052], offsets: [0, 756], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_04_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_04_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1072], offsets: [0, 768], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_05_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_05_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1124], offsets: [0, 624], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_06_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866}, + { id: ResourceId.IMG_BGR_06_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 948], offsets: [0, 760], preCutWidth: 2048, preCutHeight: 1866}, + { id: ResourceId.IMG_BGR_07_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_07_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 886], offsets: [0, 881], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_08_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152, 0, 0, 4, 3], offsets: [0, 0, 1028.5, 581], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_08_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 642, 0, 0, 4, 3], offsets: [0, 889, 1028.5, 581], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_09_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_09_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 858], offsets: [0, 780], preCutWidth: 2048, preCutHeight: 1638}, + { id: ResourceId.IMG_BGR_10_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_10_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 887], offsets: [0, 792], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_11_P1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1153], offsets: [0, -1], preCutWidth: 2048, preCutHeight: 2304}, + { id: ResourceId.IMG_BGR_11_P2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 980], offsets: [0, 802], preCutWidth: 2048, preCutHeight: 2304}, + + { id: ResourceId.IMG_BGR_IE, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866}, + + { id: ResourceId.IMG_TIME_BGR_1, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866}, + { id: ResourceId.IMG_TIME_BGR_2, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866}, + { id: ResourceId.IMG_TIME_BGR_3, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866}, + { id: ResourceId.IMG_TIME_BGR_4, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866}, + { id: ResourceId.IMG_TIME_BGR_5, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866}, + { id: ResourceId.IMG_TIME_BGR_6, resScale: 1.25, skipOffsetAdjustment: true, rects: [0, 0, 2048, 1152], offsets: [0, 0], preCutWidth: 2048, preCutHeight: 1866} + ]; + + return RES_INFO_2560; + } +); + +define('resources/ResEntry', + [], + function () { + + /** + * ResEntry constructor + * @param path {string} location of the file + * @param type {ResourceType} resource type (IMAGE, SOUND, etc) + */ + var ResEntry = function (path, type) { + this.path = path; + this.type = type; + }; + + return ResEntry; + } +); + + +define('resources/ResourceType', + [], + function () { + + /** + * @enum {number} + */ + var ResourceType = { + IMAGE: 0, + SOUND: 1, + FONT: 2, + STRINGS: 3 + }; + + return ResourceType; + } +); + + +define('resources/ResData', + [ + 'resources/ResEntry', + 'resources/ResourceType', + 'resources/ResourceId' + ], + function (ResEntry, ResourceType, ResourceId) { + + var RES_DATA = []; + + + RES_DATA[ResourceId.IMG_DEFAULT] = new ResEntry("zeptolab.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_LOADERBAR_FULL] = new ResEntry("loaderbar_full.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_CHILLINGO] = new ResEntry("Default.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_BUTTON_DEFAULT] = new ResEntry("menu_button_default.png", ResourceType.IMAGE); + RES_DATA[ResourceId.FNT_BIG_FONT] = new ResEntry("big_font.png", ResourceType.FONT); + RES_DATA[ResourceId.FNT_SMALL_FONT] = new ResEntry("small_font.png", ResourceType.FONT); + RES_DATA[ResourceId.IMG_MENU_LOADING] = new ResEntry("menu_loading.png", ResourceType.IMAGE); + RES_DATA[ResourceId.SND_TAP] = new ResEntry("tap", ResourceType.SOUND); + RES_DATA[ResourceId.STR_MENU] = new ResEntry("menu_strings.xml", ResourceType.STRINGS); + RES_DATA[ResourceId.SND_BUTTON] = new ResEntry("button", ResourceType.SOUND); + RES_DATA[ResourceId.SND_BUBBLE_BREAK] = new ResEntry("bubble_break", ResourceType.SOUND); + RES_DATA[ResourceId.SND_BUBBLE] = new ResEntry("bubble", ResourceType.SOUND); + RES_DATA[ResourceId.SND_CANDY_BREAK] = new ResEntry("candy_break", ResourceType.SOUND); + RES_DATA[ResourceId.SND_MONSTER_CHEWING] = new ResEntry("monster_chewing", ResourceType.SOUND); + RES_DATA[ResourceId.SND_MONSTER_CLOSE] = new ResEntry("monster_close", ResourceType.SOUND); + RES_DATA[ResourceId.SND_MONSTER_OPEN] = new ResEntry("monster_open", ResourceType.SOUND); + RES_DATA[ResourceId.SND_MONSTER_SAD] = new ResEntry("monster_sad", ResourceType.SOUND); + RES_DATA[ResourceId.SND_RING] = new ResEntry("ring", ResourceType.SOUND); + RES_DATA[ResourceId.SND_ROPE_BLEAK_1] = new ResEntry("rope_bleak_1", ResourceType.SOUND); + RES_DATA[ResourceId.SND_ROPE_BLEAK_2] = new ResEntry("rope_bleak_2", ResourceType.SOUND); + RES_DATA[ResourceId.SND_ROPE_BLEAK_3] = new ResEntry("rope_bleak_3", ResourceType.SOUND); + RES_DATA[ResourceId.SND_ROPE_BLEAK_4] = new ResEntry("rope_bleak_4", ResourceType.SOUND); + RES_DATA[ResourceId.SND_ROPE_GET] = new ResEntry("rope_get", ResourceType.SOUND); + RES_DATA[ResourceId.SND_STAR_1] = new ResEntry("star_1", ResourceType.SOUND); + RES_DATA[ResourceId.SND_STAR_2] = new ResEntry("star_2", ResourceType.SOUND); + RES_DATA[ResourceId.SND_STAR_3] = new ResEntry("star_3", ResourceType.SOUND); + RES_DATA[ResourceId.SND_ELECTRIC] = new ResEntry("electric", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PUMP_1] = new ResEntry("pump_1", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PUMP_2] = new ResEntry("pump_2", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PUMP_3] = new ResEntry("pump_3", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PUMP_4] = new ResEntry("pump_4", ResourceType.SOUND); + RES_DATA[ResourceId.SND_SPIDER_ACTIVATE] = new ResEntry("spider_activate", ResourceType.SOUND); + RES_DATA[ResourceId.SND_SPIDER_FALL] = new ResEntry("spider_fall", ResourceType.SOUND); + RES_DATA[ResourceId.SND_SPIDER_WIN] = new ResEntry("spider_win", ResourceType.SOUND); + RES_DATA[ResourceId.SND_WHEEL] = new ResEntry("wheel", ResourceType.SOUND); + RES_DATA[ResourceId.SND_WIN] = new ResEntry("win", ResourceType.SOUND); + RES_DATA[ResourceId.SND_GRAVITY_OFF] = new ResEntry("gravity_off", ResourceType.SOUND); + RES_DATA[ResourceId.SND_GRAVITY_ON] = new ResEntry("gravity_on", ResourceType.SOUND); + RES_DATA[ResourceId.SND_CANDY_LINK] = new ResEntry("candy_link", ResourceType.SOUND); + RES_DATA[ResourceId.SND_BOUNCER] = new ResEntry("bouncer", ResourceType.SOUND); + RES_DATA[ResourceId.IMG_MENU_BGR] = new ResEntry("menu_bgr.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_BUTTON_CRYSTAL] = new ResEntry("menu_button_crystal.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_POPUP] = new ResEntry("menu_popup.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_BUTTON_CRYSTAL_ICON] = new ResEntry("menu_button_crystal_icon.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_LOGO] = new ResEntry("menu_logo.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_LEVEL_SELECTION] = new ResEntry("menu_level_selection.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_PACK_SELECTION] = new ResEntry("menu_pack_selection.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_EXTRA_BUTTONS] = new ResEntry("menu_extra_buttons.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_EXTRA_BUTTONS_EN] = new ResEntry("menu_extra_buttons_en.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_BUTTON_SHORT] = new ResEntry("menu_button_short.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_HUD_BUTTONS] = new ResEntry("hud_buttons.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_CANDY_01] = new ResEntry("obj_candy_01.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_SPIDER] = new ResEntry("obj_spider.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_CONFETTI_PARTICLES] = new ResEntry("confetti_particles.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_PAUSE] = new ResEntry("menu_pause.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_RESULT] = new ResEntry("menu_result.png", ResourceType.IMAGE); + RES_DATA[ResourceId.FNT_FONT_NUMBERS_BIG] = new ResEntry("font_numbers_big.png", ResourceType.FONT); + RES_DATA[ResourceId.IMG_HUD_BUTTONS_EN] = new ResEntry("hud_buttons_en.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_MENU_RESULT_EN] = new ResEntry("menu_result_en.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_STAR_DISAPPEAR] = new ResEntry("obj_star_disappear.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_BUBBLE_FLIGHT] = new ResEntry("obj_bubble_flight.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_BUBBLE_POP] = new ResEntry("obj_bubble_pop.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_HOOK_AUTO] = new ResEntry("obj_hook_auto.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_SPIKES_04] = new ResEntry("obj_spikes_04.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_BUBBLE_ATTACHED] = new ResEntry("obj_bubble_attached.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_HOOK_01] = new ResEntry("obj_hook_01.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_HOOK_02] = new ResEntry("obj_hook_02.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_STAR_IDLE] = new ResEntry("obj_star_idle.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_HUD_STAR] = new ResEntry("hud_star.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_SPIKES_03] = new ResEntry("obj_spikes_03.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_SPIKES_02] = new ResEntry("obj_spikes_02.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_SPIKES_01] = new ResEntry("obj_spikes_01.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_CHAR_ANIMATIONS] = new ResEntry("char_animations.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_HOOK_REGULATED] = new ResEntry("obj_hook_regulated.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_ELECTRODES] = new ResEntry("obj_electrodes.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_HOOK_MOVABLE] = new ResEntry("obj_hook_movable.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_PUMP] = new ResEntry("obj_pump.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_TUTORIAL_SIGNS] = new ResEntry("tutorial_signs.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_SOCKS] = new ResEntry("obj_hat.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_BOUNCER_01] = new ResEntry("obj_bouncer_01.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_BOUNCER_02] = new ResEntry("obj_bouncer_02.png", ResourceType.IMAGE); + RES_DATA[ResourceId.SND_MENU_MUSIC] = new ResEntry("menu_music", ResourceType.SOUND); + RES_DATA[ResourceId.SND_GAME_MUSIC] = new ResEntry("game_music", ResourceType.SOUND); + RES_DATA[ResourceId.SND_GAME_MUSIC2] = new ResEntry("game_music2", ResourceType.SOUND); + RES_DATA[ResourceId.IMG_DRAWING_HIDDEN] = new ResEntry("obj_drawing_hidden.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_ROTATABLE_SPIKES_01] = new ResEntry("obj_rotatable_spikes_01.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_ROTATABLE_SPIKES_02] = new ResEntry("obj_rotatable_spikes_02.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_ROTATABLE_SPIKES_03] = new ResEntry("obj_rotatable_spikes_03.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_ROTATABLE_SPIKES_04] = new ResEntry("obj_rotatable_spikes_04.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_ROTATABLE_SPIKES_BUTTON] = new ResEntry("obj_rotatable_spikes_button.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_BEE_HD] = new ResEntry("obj_bee_hd.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_POLLEN_HD] = new ResEntry("obj_pollen_hd.png", ResourceType.IMAGE); + RES_DATA[ResourceId.SND_SPIKE_ROTATE_IN] = new ResEntry("spike_rotate_in", ResourceType.SOUND); + RES_DATA[ResourceId.SND_SPIKE_ROTATE_OUT] = new ResEntry("spike_rotate_out", ResourceType.SOUND); + RES_DATA[ResourceId.IMG_CHAR_SUPPORTS] = new ResEntry("char_supports.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_OBJ_VINIL] = new ResEntry("obj_vinil.png", ResourceType.IMAGE); + RES_DATA[ResourceId.SND_SCRATCH_IN] = new ResEntry("scratch_in", ResourceType.SOUND); + RES_DATA[ResourceId.SND_SCRATCH_OUT] = new ResEntry("scratch_out", ResourceType.SOUND); + RES_DATA[ResourceId.SND_BUZZ] = new ResEntry("buzz", ResourceType.SOUND); + RES_DATA[ResourceId.SND_TELEPORT] = new ResEntry("teleport", ResourceType.SOUND); + + + RES_DATA[ResourceId.IMG_BGR_01_P1] = new ResEntry("bgr_01_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_01_P2] = new ResEntry("bgr_01_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_02_P1] = new ResEntry("bgr_02_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_02_P2] = new ResEntry("bgr_02_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_03_P1] = new ResEntry("bgr_03_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_03_P2] = new ResEntry("bgr_03_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_04_P1] = new ResEntry("bgr_04_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_04_P2] = new ResEntry("bgr_04_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_05_P1] = new ResEntry("bgr_05_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_05_P2] = new ResEntry("bgr_05_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_06_P1] = new ResEntry("bgr_06_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_06_P2] = new ResEntry("bgr_06_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_07_P1] = new ResEntry("bgr_07_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_07_P2] = new ResEntry("bgr_07_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_08_P1] = new ResEntry("bgr_08_p1.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_08_P2] = new ResEntry("bgr_08_p2.png", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_09_P1] = new ResEntry("bgr_09_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_09_P2] = new ResEntry("bgr_09_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_10_P1] = new ResEntry("bgr_10_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_10_P2] = new ResEntry("bgr_10_p2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_11_P1] = new ResEntry("bgr_11_p1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_BGR_11_P2] = new ResEntry("bgr_11_p2.jpg", ResourceType.IMAGE); + + // IE box background + RES_DATA[ResourceId.IMG_BGR_IE] = new ResEntry("bgr_ie.jpg", ResourceType.IMAGE); + + RES_DATA[ResourceId.IMG_TIME_BGR_1] = new ResEntry("bgr_time1.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_TIME_BGR_2] = new ResEntry("bgr_time2.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_TIME_BGR_3] = new ResEntry("bgr_time3.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_TIME_BGR_4] = new ResEntry("bgr_time4.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_TIME_BGR_5] = new ResEntry("bgr_time5.jpg", ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_TIME_BGR_6] = new ResEntry("bgr_time6.jpg", ResourceType.IMAGE); + + RES_DATA[ResourceId.IMG_CAESAR_ANIMATIONS_1] = new ResEntry('Caesar_animations_1_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_CAESAR_ANIMATIONS_2] = new ResEntry('Caesar_animations_2_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_CAESAR_ANIMATIONS_3] = new ResEntry('Caesar_animations_3_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_CAESAR_ANIMATIONS_4] = new ResEntry('Caesar_animations_4_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PAINTER_ANIMATIONS_1] = new ResEntry('Painter_animations_1_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PAINTER_ANIMATIONS_2] = new ResEntry('Painter_animations_2_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PAINTER_ANIMATIONS_3] = new ResEntry('Painter_animations_3_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PAINTER_ANIMATIONS_4] = new ResEntry('Painter_animations_4_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PHARAOH_ANIMATIONS_1] = new ResEntry('Pharaoh_animations_1_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PHARAOH_ANIMATIONS_2] = new ResEntry('Pharaoh_animations_2_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PHARAOH_ANIMATIONS_3] = new ResEntry('Pharaoh_animations_3_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PHARAOH_ANIMATIONS_4] = new ResEntry('Pharaoh_animations_4_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PIRATE_ANIMATIONS_1] = new ResEntry('Pirate_animations_1_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PIRATE_ANIMATIONS_2] = new ResEntry('Pirate_animations_2_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PIRATE_ANIMATIONS_3] = new ResEntry('Pirate_animations_3_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PIRATE_ANIMATIONS_4] = new ResEntry('Pirate_animations_4_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PREHISTORIC_ANIMATIONS_1] = new ResEntry('Prehistoric_animations_1_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PREHISTORIC_ANIMATIONS_2] = new ResEntry('Prehistoric_animations_2_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PREHISTORIC_ANIMATIONS_3] = new ResEntry('Prehistoric_animations_3_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_PREHISTORIC_ANIMATIONS_4] = new ResEntry('Prehistoric_animations_4_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_VIKING_ANIMATIONS_1] = new ResEntry('Viking_animations_1_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_VIKING_ANIMATIONS_2] = new ResEntry('Viking_animations_2_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_VIKING_ANIMATIONS_3] = new ResEntry('Viking_animations_3_hd.png', ResourceType.IMAGE); + RES_DATA[ResourceId.IMG_VIKING_ANIMATIONS_4] = new ResEntry('Viking_animations_4_hd.png', ResourceType.IMAGE); + + RES_DATA[ResourceId.SND_CANDY_HIT] = new ResEntry("candy_hit", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PREHISTORIC_MONSTER_CHEWING] = new ResEntry("prehistoric_monster_chewing", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PREHISTORIC_MONSTER_CLOSE] = new ResEntry("prehistoric_monster_close", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PREHISTORIC_MONSTER_OPEN] = new ResEntry("prehistoric_monster_open", ResourceType.SOUND); + RES_DATA[ResourceId.SND_PREHISTORIC_MONSTER_SAD] = new ResEntry("prehistoric_monster_sad", ResourceType.SOUND); + RES_DATA[ResourceId.SND_TIME_MENU_MUSIC] = new ResEntry("time_menu", ResourceType.SOUND); + + RES_DATA[ResourceId.IMG_TIME_STANDS] = new ResEntry('time-stands.png', ResourceType.IMAGE); + + return RES_DATA; + } +); +define('resources/ResScale', + ['core/Vector', 'core/Rectangle'], + function (Vector, Rectangle) { + + // scales a number and rounds to 4 decimals places of precision + var scaleNumber = function (value, scale) { + return Math.round(value * scale * 10000) / 10000; + }; + + var ResScaler = { + scaleResourceInfos: function (infos, canvasScale) { + + // the canvas scale is ratio of the canvas target size compared + // to the resolution the original assets were designed for. The + // resource scale handles resources that were designed for a + // different resolution. Most of the assets were designed for + // 2560 x 1440 but a few of the later sprites target 2048 x 1080 + + var resScale, i, len, info; + for (i = 0, len = infos.length; i < len; i++) { + info = infos[i]; + resScale = info.resScale || 1; + this.scaleResourceInfo(infos[i], scaleNumber(canvasScale, resScale)); + } + }, + + scaleResourceInfo: function (info, scale) { + if (info.charOffset) { + info.charOffset = scaleNumber(info.charOffset, scale); + } + if (info.lineOffset) { + info.lineOffset = scaleNumber(info.lineOffset, scale); + } + if (info.spaceWidth) { + info.spaceWidth = scaleNumber(info.spaceWidth, scale); + } + if (info.preCutWidth) { + info.preCutWidth = Math.ceil(scaleNumber(info.preCutWidth, scale)); + } + if (info.preCutHeight) { + info.preCutHeight = Math.ceil(scaleNumber(info.preCutHeight, scale)); + } + if (info.rects) { + info.originalRects = this.parseOriginalRects(info.rects); + var extra = false; + + info.rects = this.scaleRects(info.originalRects, scale, info.id); + } + info.adjustmentMaxX = 0; + info.adjustmentMaxX = 0; + if (info.offsets) { + info.originalOffsets = this.parseOriginalOffsets(info.offsets); + this.scaleOffsets(info, scale); + } + }, + + parseOriginalRects: function (rects) { + var i = 0, + len = rects.length, + originalRects = []; + while (i < len) { + var rect = new Rectangle( + rects[i++], + rects[i++], + rects[i++], + rects[i++]); + originalRects.push(rect); + } + return originalRects; + }, + + scaleRects: function (originalRects, scale, id) { + var PADDING = 4, + newRects = [], + maxWidth = 0, + currentY = 0, + numRects = originalRects.length; + + if (id === 5) { + PADDING = 11.25; + scale *= 1.6; + } + + if (id === 68) { + PADDING = 2.78; + scale *= 1.5; + } + + for (var j = 0; j < numRects; j++) { + var oldRect = originalRects[j], + newRect = new Rectangle( + 0, + currentY, + scaleNumber(oldRect.w, scale), + scaleNumber(oldRect.h, scale)); + + newRects.push(newRect); + currentY += Math.ceil(newRect.h) + PADDING; + } + return newRects; + }, + + parseOriginalOffsets: function (offsets) { + var i = 0, + len = offsets.length, + originalOffsets = []; + while (i < len) { + var rect = new Vector( + offsets[i++], + offsets[i++]); + originalOffsets.push(rect); + } + return originalOffsets; + }, + + scaleOffsets: function (info, scale) { + + // Previously we chopped the decimal portion of offsets and then + // offset the image by that amount when scaling the sprite sheet. + // That allows us to always have round offsets to avoid twitchy + // pixels when we snap to pixel boundaries when drawing for perf. + // Unfortunately, the GDI+ sprite resizer can't accurately handle + // the floating point offsets so we'll disable offset adjust for + // now. Instead we'll use high precision drawing coords (instead + // of rounding) for moving and animated elements. + var ALLOW_OFFSET_ADJUSTMENT = false; + + var adjustments = [], // how much to offset the offsets :) + oldOffsets = info.originalOffsets, + newOffsets = [], + scaledOffset, adjustment, i, len; + for (i = 0, len = oldOffsets.length; i < len; i++) { + scaledOffset = oldOffsets[i].copy(); + scaledOffset.x = scaleNumber(scaledOffset.x, scale); + scaledOffset.y = scaleNumber(scaledOffset.y, scale); + + if (!ALLOW_OFFSET_ADJUSTMENT || info.skipOffsetAdjustment) { + // the backgrounds use offsets to place other elements, so + // we don't always want to pixel adjust the offset because + // the c# resizer can only safely adjust the current image. + adjustment = new Vector(0, 0); + } + else { + // find the amount we need to adjust the offset by + adjustment = new Vector( + scaleNumber(scaledOffset.x - scaledOffset.x | 0, 1), + scaleNumber(scaledOffset.y - scaledOffset.y | 0, 1)); + + // remember the biggest adjust we made + info.adjustmentMaxX = Math.max(info.adjustmentMaxX, Math.ceil(adjustment.x)); + info.adjustmentMaxY = Math.max(info.adjustmentMaxY, Math.ceil(adjustment.y)); + + // chop off the decimal portion of the offset + scaledOffset.x = scaledOffset.x | 0; + scaledOffset.y = scaledOffset.y | 0; + } + + adjustments.push(adjustment); + newOffsets.push(scaledOffset); + } + + info.offsets = newOffsets; + info.offsetAdjustments = adjustments; + delete info.originalOffsets; + } + }; + + return ResScaler; + } +); +define('boxes',[], function () { + var boxes = [ + {levels: [ + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 156, y: 139}, + {name: 100, x: 159, y: 51, length: 90, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 2, x: 161, y: 427}, + {name: 3, x: 162, y: 230, timeout: -1}, + {name: 3, x: 161, y: 295, timeout: -1}, + {name: 3, x: 161, y: 361, timeout: -1}, + {name: 4, x: 197, y: 41, locale: "en", text: "Slide across to cut the rope", width: 180}, + {name: 4, x: 202, y: 290, locale: "en", + text: "Deliver candy to Om Nom", width: 200}, + {name: 5, x: 57, y: 119, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 8, x: 231, y: 416, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 109, y: 119, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 119, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 119, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 119, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 14, x: 73, y: 145, locale: "en", moveSpeed: 100, rotateSpeed: 100, special: 2} + ], ru: [ + {name: 14, + x: 73, y: 153, locale: "ru", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 130, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 57, y: 130, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 130, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 130, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 130, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 177, y: 40, locale: "ru", text: "\u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u0438\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0434\u0438\u0442\u0435 \u043a\u0443\u0440\u0441\u043e\u0440\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0440\u0435\u0437\u0430\u0442\u044c \u0432\u0435\u0440\u0435\u0432\u043a\u0443", + width: 300}, + {name: 8, x: 231, y: 415, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 216, y: 280, locale: "ru", text: "\u0414\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043b\u0435\u0434\u0435\u043d\u0435\u0446 \u0410\u043c \u041d\u044f\u043c\u0443", width: 180} + ], fr: [ + {name: 14, x: 73, y: 150, locale: "fr", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 124, locale: "fr", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 57, y: 124, locale: "fr", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 124, locale: "fr", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 213, y: 124, locale: "fr", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 124, locale: "fr", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 177, y: 31, locale: "fr", text: "Clique ou fais glisser pour couper la corde", width: 200}, + {name: 8, x: 231, y: 415, locale: "fr", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 196, y: 290, locale: "fr", text: "Donne un bonbon \u00e0 Om Nom", width: 200} + ], de: [ + {name: 14, x: 73, y: 155, locale: "de", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "de", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "de", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "de", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "de", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "de", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 15, locale: "de", text: "Klicke oder ziehe, um das Seil zu zerschneiden", width: 200}, + {name: 8, x: 231, y: 416, locale: "de", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 210, y: 312, locale: "de", text: "Versorg Om Nom mit Bonbons", width: 200} + ], es: [ + {name: 14, x: 73, y: 155, locale: "es", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "es", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "es", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "es", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "es", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "es", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 45, locale: "es", text: "Haz clic o desliza para cortar la cuerda", width: 200}, + {name: 8, x: 231, y: 416, locale: "es", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 210, y: 312, locale: "es", text: "Haz llegar el caramelo hasta Om Nom.", width: 200} + ], br: [ + {name: 14, x: 73, y: 155, locale: "br", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "br", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "br", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "br", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "br", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "br", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 45, locale: "br", text: "Deslize o dedo para cortar a corda", width: 200}, + {name: 8, x: 231, y: 416, locale: "br", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 200, y: 312, locale: "br", text: "Entregue os doces para Om Nom.", width: 200} + ], ca: [ + {name: 14, x: 73, y: 155, locale: "es", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "es", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "ca", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "ca", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "ca", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "ca", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 45, locale: "ca", text: "Llisca el dit per tallar la corda", width: 200}, + //{name: 8, x: 231, y: 416, locale: "ca", moveSpeed: 100, rotateSpeed: 100}, + ], it: [ + {name: 14, x: 73, y: 155, locale: "it", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "it", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "it", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "it", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "it", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "it", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 20, locale: "it", text: "Scorri per tagliare la corda", width: 200}, + {name: 8, x: 231, y: 436, locale: "it", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 200, y: 305, locale: "it", text: "Porta un bonbon a Om Nom", width: 200} + ], nl: [ + {name: 14, x: 73, y: 155, locale: "nl", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "nl", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "nl", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "nl", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "nl", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "nl", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 25, locale: "nl", text: "Sleep om het touw door te snijden", width: 200}, + {name: 8, x: 231, y: 416, locale: "nl", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 230, y: 312, locale: "nl", text: "Lever het snoepje af bij Om Nom", width: 200} + ], ko: [ + {name: 14, x: 73, y: 155, locale: "ko", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "ko", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "ko", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "ko", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "ko", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "ko", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 65, locale: "ko", text: "손가락으로 줄을 *자르세요.", width: 200}, + {name: 8, x: 231, y: 416, locale: "ko", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 230, y: 312, locale: "ko", text: "Om Nom에게 사탕을 *먹이세요.", width: 200} + ], zh: [ + {name: 14, x: 73, y: 155, locale: "zh", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "zh", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "zh", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "zh", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "zh", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "zh", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 65, locale: "zh", text: "滑动你的手指 即可剪断绳索", width: 200}, + {name: 8, x: 231, y: 416, locale: "zh", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 230, y: 342, locale: "zh", text: "将糖果送给 Om Nom", width: 200} + ], ja: [ + {name: 14, x: 73, y: 155, locale: "ja", moveSpeed: 100, rotateSpeed: 100, special: 2}, + {name: 5, x: 109, y: 129, locale: "ja", moveSpeed: 100, + rotateSpeed: 100}, + {name: 5, x: 57, y: 129, locale: "ja", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 161, y: 129, locale: "ja", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 213, y: 129, locale: "ja", moveSpeed: 100, rotateSpeed: 100}, + {name: 5, x: 265, y: 129, locale: "ja", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 175, y: 60, locale: "ja", text: "指を スライド させて ロープを 切り しましょう", width: 200}, + {name: 8, x: 231, y: 416, locale: "ja", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 240, y: 342, locale: "ja", text: "Om Nomに キャンディを あげ ましょう", width: 200} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 69, y: 203}, + {name: 100, x: 52, y: 70, length: 90, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 162, y: 69, length: 170, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 2, x: 264, y: 419}, + {name: 3, x: 54, y: 250, timeout: -1}, + {name: 3, x: 53, y: 369, timeout: -1}, + {name: 3, x: 280, y: 250, timeout: -1}, + {name: 100, x: 275, + y: 69, length: 320, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 4, x: 113, y: 245, locale: "en", text: "Collect as many stars as you can", width: 200}, + {name: 13, x: 113, y: 321, locale: "en", moveSpeed: 100, rotateSpeed: 100} + ], ru: [ + {name: 13, x: 80, y: 290, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 80, y: 228, locale: "ru", text: "\u0421\u0442\u0430\u0440\u0430\u0439\u0442\u0435\u0441\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0432\u0435\u0437\u0434", + width: 210} + ], fr: [ + {name: 4, x: 137, y: 245, locale: "fr", text: "Collecte autant d'\u00e9toiles que tu le peux", width: 230}, + {name: 13, x: 113, y: 321, locale: "fr", moveSpeed: 100, rotateSpeed: 100} + ], de: [ + {name: 4, x: 66, y: 265, locale: "de", text: "Sammle m\u00f6glichst viele Sternchen", width: 170}, + {name: 13, x: 66, y: 321, locale: "de", moveSpeed: 100, rotateSpeed: 100} + ], es: [ + {name: 4, x: 66, y: 265, locale: "es", text: "Consigue tantas estrellas como puedas.", width: 170}, + {name: 13, x: 66, y: 321, locale: "es", moveSpeed: 100, rotateSpeed: 100} + ], br: [ + {name: 4, x: 66, y: 265, locale: "br", text: "Colete o máximo de estrelas possível", width: 170}, + {name: 13, x: 66, y: 321, locale: "br", moveSpeed: 100, rotateSpeed: 100} + ], ca: [ + {name: 4, x: 56, y: 265, locale: "ca", text: "Aconsegueix totes les estrelles que puguis", width: 170}, + {name: 13, x: 36, y: 321, locale: "ca", moveSpeed: 100, rotateSpeed: 100} + ], it: [ + {name: 4, x: 56, y: 265, locale: "it", text: "Recupera più stelle possibili", width: 170}, + {name: 13, x: 36, y: 321, locale: "it", moveSpeed: 100, rotateSpeed: 100} + ], nl: [ + {name: 4, x: 56, y: 265, locale: "nl", text: "Verzamel zoveel mogelijk sterren", width: 170}, + {name: 13, x: 36, y: 321, locale: "nl", moveSpeed: 100, rotateSpeed: 100} + ], ko: [ + {name: 4, x: 56, y: 265, locale: "ko", text: "별을 최대한 *많이 모으세요.", width: 170}, + {name: 13, x: 36, y: 321, locale: "ko", moveSpeed: 100, rotateSpeed: 100} + ], zh: [ + {name: 4, x: 56, y: 295, locale: "zh", text: "尽可能多地收集星星", width: 200}, + {name: 13, x: 36, y: 321, locale: "zh", moveSpeed: 100, rotateSpeed: 100} + ], ja: [ + {name: 4, x: 46, y: 265, locale: "ja", text: "できるだけ 多くの スターを 獲得 しましょう", width: 220}, + {name: 13, x: 36, y: 321, locale: "ja", moveSpeed: 100, rotateSpeed: 100} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, special: 1, ropePhysicsSpeed: 1} + ], objects: [ + {name: 52, x: 158, y: 187}, + {name: 2, x: 262, y: 362}, + {name: 100, x: 161, y: 315, + length: 93, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 100, x: 289, y: 186, length: 105, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 100, x: 162, y: 57, length: 93, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 100, x: 33, y: 186, length: 105, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 3, x: 159, y: 226, timeout: -1}, + {name: 3, x: 32, y: 312, timeout: -1}, + {name: 3, x: 161, y: 434, timeout: -1} + ]}, + {settings: [ + {name: 0, + gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 101, y: 238}, + {name: 2, x: 219, y: 431}, + {name: 3, x: 102, y: 326, timeout: -1}, + {name: 3, x: 217, y: 209, timeout: -1}, + {name: 3, x: 217, y: 74, timeout: -1}, + {name: 100, x: 96, y: 139, length: 90, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 54, x: 99, y: 391}, + {name: 100, x: 219, y: 252, length: 140, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 4, + x: -25, y: -5, locale: "en", text: "Click to pop the bubble", width: 200, special: 1}, + {name: 4, x: 187, y: 263, locale: "en", text: "The bubble will lift the candy up", width: 200}, + {name: 8, x: 167, y: 391, locale: "en", angle: 15, moveSpeed: 100, rotateSpeed: 100}, + {name: 9, x: 218, y: 78, locale: "en", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 102, x: 269, y: 426, angle: 10, drawing: 1} + ], ru: [ + {name: 8, x: 167, y: 391, locale: "ru", angle: 20, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 158, y: 225, locale: "ru", text: "\u041f\u0443\u0437\u044b\u0440\u044c \u043f\u043e\u0434\u044b\u043c\u0435\u0442 \u043b\u0435\u0434\u0435\u043d\u0435\u0446 \u0432\u0432\u0435\u0440\u0445", + width: 200}, + {name: 4, x: -80, y: 0, locale: "ru", text: "\u041d\u0430\u0436\u043c\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u043b\u043e\u043f\u043d\u0443\u0442\u044c \u043f\u0443\u0437\u044b\u0440\u044c", width: 250, special: 1}, + {name: 9, x: 218, y: 78, locale: "ru", moveSpeed: 100, rotateSpeed: 100, special: 1} + ], fr: [ + {name: 4, x: 135, y: 241, locale: "fr", text: "La bulle fera monter le bonbon", width: 220}, + {name: 8, x: 167, y: 386, locale: "fr", angle: 15, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -10, y: -10, locale: "fr", text: "\u00c9clate la bulle avec ton doigt", + width: 200, special: 1}, + {name: 9, x: 217, y: 78, locale: "fr", moveSpeed: 100, rotateSpeed: 100, special: 1} + ], de: [ + {name: 4, x: -20, y: 15, locale: "de", text: "Klicke, um die Seifenblase platzen zu lassen", width: 200, special: 1}, + {name: 9, x: 217, y: 77, locale: "de", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 168, y: 248, locale: "de", text: "Die Seifenblase l\u00e4sst den Bonbon schweben", width: 250}, + {name: 8, x: 166, y: 390, locale: "de", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], es: [ + {name: 4, x: -60, y: 15, locale: "es", text: "Haz clic sobre la burbuja para que estalle", width: 220, special: 1}, + {name: 9, x: 217, y: 77, locale: "es", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 168, y: 258, locale: "es", text: "Las burbujas hacen que el caramelo se eleve.", width: 250}, + {name: 8, x: 166, y: 390, locale: "es", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], br: [ + {name: 4, x: -60, y: 15, locale: "br", text: "Clique para estourar a bolha", width: 220, special: 1}, + {name: 9, x: 217, y: 77, locale: "br", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 168, y: 278, locale: "br", text: "A bolha vai erguer os doces.", width: 250}, + {name: 8, x: 166, y: 390, locale: "br", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], ca: [ + {name: 4, x: -35, y: 10, locale: "ca", text: "Fes clic per fer explotar la bombolla", width: 200, special: 1}, + {name: 9, x: 217, y: 77, locale: "ca", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 168, y: 248, locale: "ca", text: "La bombolla llançarà les llaminadures cap amunt", width: 250}, + {name: 8, x: 166, y: 390, locale: "ca", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], it: [ + {name: 4, x: -35, y: -15, locale: "it", text: "Clicca per far esplodere la bolla", width: 200, special: 1}, + {name: 9, x: 217, y: 77, locale: "it", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 138, y: 238, locale: "it", text: "La bolla solleverà il bonbon", width: 250}, + {name: 8, x: 166, y: 390, locale: "it", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], nl: [ + {name: 4, x: -35, y: -15, locale: "nl", text: "Klik om de bel door te prikken", width: 200, special: 1}, + {name: 9, x: 217, y: 77, locale: "nl", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 168, y: 238, locale: "nl", text: "Het snoepje drijft in de bel omhoog", width: 250}, + {name: 8, x: 166, y: 390, locale: "nl", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], ko: [ + {name: 4, x: -35, y: 15, locale: "ko", text: "클릭해서 비눗방울을 *터뜨리세요.", width: 200, special: 1}, + {name: 9, x: 217, y: 77, locale: "ko", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 168, y: 318, locale: "ko", text: "비눗방울이 사탕을 *띄워줘요.", width: 250}, + {name: 8, x: 166, y: 390, locale: "ko", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], zh: [ + {name: 4, x: -35, y: 45, locale: "zh", text: "点击戳破气泡", width: 200, special: 1}, + {name: 9, x: 217, y: 77, locale: "zh", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 148, y: 308, locale: "zh", text: "泡泡将提起糖果", width: 250}, + {name: 8, x: 166, y: 390, locale: "zh", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ], ja: [ + {name: 4, x: -35, y: 0, locale: "ja", text: "クリックして バブルを 破裂 させる", width: 200, special: 1}, + {name: 9, x: 217, y: 77, locale: "ja", moveSpeed: 100, rotateSpeed: 10, special: 1}, + {name: 4, x: 168, y: 210, locale: "ja", text: "泡で キャンディを 持ち上げる ことも できます", width: 250}, + {name: 8, x: 166, y: 390, locale: "ja", angle: 15, moveSpeed: 100, rotateSpeed: 100} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, + ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 266, y: 161}, + {name: 100, x: 155, y: 250, length: 95, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 153, y: 110, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 2, x: 155, y: 430}, + {name: 3, x: 37, y: 264, timeout: -1}, + {name: 3, x: 152, y: 70, timeout: -1}, + {name: 3, x: 276, y: 264, timeout: -1}, + {name: 54, x: 252, y: 367}, + {name: 4, x: -100, y: 280, locale: "en", text: "You can restart the level by pressing the", + width: 220}, + {name: 12, x: -30, y: 485, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -15, y: 430, locale: "en", text: "button", width: 100} + ], ru: [ + {name: 4, x: -100, y: 304, locale: "ru", text: "\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0443\u0440\u043e\u0432\u0435\u043d\u044c, \u043d\u0430\u0436\u0430\u0432 \u043a\u043d\u043e\u043f\u043a\u0443", width: 200}, + {name: 12, x: 85, y: 436, locale: "ru", moveSpeed: 100, rotateSpeed: 100} + ], fr: [ + {name: 4, + x: -100, y: 280, locale: "fr", text: "Tu peux recommencer le niveau en touchant le bouton", width: 180}, + {name: 12, x: -70, y: 481, locale: "fr", moveSpeed: 100, rotateSpeed: 100} + ], de: [ + {name: 12, x: -90, y: 440, locale: "de", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -100, y: 282, locale: "de", text: "Lass den Bonbon nicht aus der Schachtel", width: 200} + ], es: [ + {name: 12, x: -52, y: 423, locale: "es", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -100, y: 282, locale: "es", text: "Puedes reinciar el nivel tocando el botón", width: 200} + ], br: [ + {name: 12, x: -52, y: 466, locale: "br", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -100, y: 282, locale: "br", text: "Você pode reiniciar o nível, pressionando o botão", width: 200} + ], ca: [ + {name: 12, x: -60, y: 390, locale: "ca", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -130, y: 282, locale: "ca", text: "Pots reiniciar el nivell prement el botó", width: 240} + ], it: [ + {name: 12, x: -32, y: 445, locale: "it", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -130, y: 282, locale: "it", text: "Puoi ricominciare il livello premendo il tasto", width: 240} + ], nl: [ + {name: 12, x: -62, y: 485, locale: "nl", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -130, y: 282, locale: "nl", text: "Je kunt het level opnieuw opstarten met een druk op de knop", width: 240} + ], ko: [ + {name: 12, x: -90, y: 425, locale: "ko", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -130, y: 282, locale: "ko", text: "버튼을 누르면 *해당 레벨을 처음부터 *다시 시작해요.", width: 240} + ], zh: [ + {name: 12, x: -28, y: 385, locale: "zh", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -130, y: 282, locale: "zh", text: "按下这个按钮 就可以重新开始这一关", width: 350} + ], ja: [ + {name: 12, x: -80, y: 430, locale: "ja", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -130, y: 282, locale: "ja", text: "このボタンで ステージを やり直す ことが できます", width: 240} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, special: 1, ropePhysicsSpeed: 1} + ], objects: [ + {name: 52, x: 161, y: 350}, + {name: 2, x: 163, y: 67}, + {name: 100, x: 243, y: 290, length: 120, wheel: !1, + radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 100, x: 83, y: 401, length: 90, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 54, x: 165, y: 421}, + {name: 100, x: 165, y: 123, length: 200, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 3, x: 97, y: 294, timeout: -1}, + {name: 3, x: 166, y: 422, timeout: -1}, + {name: 3, x: 97, y: 228, timeout: -1} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, + x: 64, y: 139}, + {name: 2, x: 163, y: 427}, + {name: 100, x: 162, y: 68, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 66, y: 68, length: 50, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 163, y: 163, length: 90, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 162, y: 259, length: 130, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, + part: "L"}, + {name: 58, x: 161, y: 329, angle: 0, size: 2}, + {name: 58, x: 159, y: 229, angle: 0, size: 2}, + {name: 3, x: 250, y: 165, timeout: -1}, + {name: 3, x: 64, y: 276, timeout: -1}, + {name: 3, x: 248, y: 275, timeout: -1}, + {name: 10, x: 320, y: 357, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 220, y: 359, locale: "en", text: "Keep the candy away from spikes", width: 200} + ], ru: [ + {name: 10, x: -150, y: 370, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -140, y: 302, locale: "ru", text: "\u041d\u0435 \u0434\u0430\u0439\u0442\u0435 \u043b\u0435\u0434\u0435\u043d\u0446\u0443 \u0440\u0430\u0437\u0431\u0438\u0442\u044c\u0441\u044f \u043e \u0448\u0438\u043f\u044b", + width: 200} + ], fr: [ + {name: 4, x: 210, y: 340, locale: "fr", text: "Garde le bonbon loin des pointes", width: 120}, + {name: 10, x: 266, y: 346, locale: "fr", moveSpeed: 100, rotateSpeed: 100} + ], de: [ + {name: 10, x: -150, y: 380, locale: "de", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -140, y: 327, locale: "de", text: "Pass auf, dass der Bonbon nicht in die N\u00e4he der Spikes kommt", width: 250} + ], es: [ + {name: 10, x: -150, y: 356, locale: "es", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -160, y: 327, locale: "es", text: "¡Mantén el caramelo alejado de los pinchos!", width: 250} + ], br: [ + {name: 10, x: -100, y: 310, locale: "br", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -160, y: 327, locale: "br", text: "Mantenha os doces longe dos espinhos", width: 250} + ], ca: [ + {name: 10, x: -160, y: 376, locale: "ca", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -150, y: 327, locale: "ca", text: "Mantingues les llaminadures allunyades de les puntes", width: 250} + ], it: [ + {name: 10, x: -160, y: 376, locale: "it", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -150, y: 327, locale: "it", text: "Tieni il bonbon lontano dagli aculei", width: 250} + ], nl: [ + {name: 10, x: -130, y: 376, locale: "nl", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -150, y: 327, locale: "nl", text: "Houd het snoepje uit de buurt van pinnen", width: 250} + ], ko: [ + {name: 10, x: -150, y: 366, locale: "ko", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -150, y: 327, locale: "ko", text: "뾰족 장애물을 *조심하세요.", width: 250} + ], zh: [ + {name: 10, x: -160, y: 376, locale: "zh", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -130, y: 355, locale: "zh", text: "让糖果避开尖刺", width: 280} + ], ja: [ + {name: 10, x: -170, y: 376, locale: "ja", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -150, y: 327, locale: "ja", text: "キャンディが トゲに*触れない ように*注意 しましょう", width: 250} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 514, y: 418}, + {name: 100, x: 224, y: 177, + length: 100, wheel: !1, gun: !1, radius: 45, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 448, y: 337, length: 100, wheel: !1, gun: !1, radius: 45, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 335, y: 256, length: 100, wheel: !1, gun: !1, radius: 45, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 52, x: 178, y: 103}, + {name: 3, x: 222, y: 269, timeout: -1}, + {name: 3, x: 448, y: 430, timeout: -1}, + {name: 3, x: 328, y: 345, timeout: -1}, + {name: 100, x: 180, y: 31, length: 50, wheel: !1, + gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 4, x: 310, y: 39, locale: "en", text: "Automatic ropes appear when candy gets into their area", width: 280}, + {name: 8, x: 316, y: 164, locale: "en", moveSpeed: 100, rotateSpeed: 100} + ], ru: [ + {name: 8, x: 325, y: 173, locale: "ru", moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 254, y: 48, locale: "ru", text: "\u0410\u0432\u0442\u043e-\u0432\u0435\u0440\u0435\u0432\u043a\u0438 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043b\u0435\u0434\u0435\u043d\u0435\u0446 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 \u0438\u0445 \u0440\u0430\u0434\u0438\u0443\u0441", + width: 400} + ], fr: [ + {name: 4, x: 283, y: 40, locale: "fr", text: "Les cordes automatiques apparaissent lorsqu'un bonbon arrive dans leur zone", width: 400}, + {name: 8, x: 298, y: 144, locale: "fr", moveSpeed: 100, rotateSpeed: 100} + ], de: [ + {name: 4, x: 300, y: 47, locale: "de", text: "Sobald der Bonbon in ihrer N\u00e4he ist, erscheinen automatisch Seile", width: 390}, + {name: 8, x: 329, y: 152, locale: "de", moveSpeed: 100, rotateSpeed: 100} + ], es: [ + {name: 4, x: 280, y: 50, locale: "es", text: "Las autocuerdas aparecen cuando el caramelo se acerca a ellas.", width: 390}, + {name: 8, x: 329, y: 160, locale: "es", moveSpeed: 100, rotateSpeed: 100} + ], br: [ + {name: 4, x: 280, y: 45, locale: "br", text: "Cordas aparecem automaticamente quando há doces na área delas", width: 390}, + {name: 8, x: 329, y: 152, locale: "br", moveSpeed: 100, rotateSpeed: 100} + ], ca: [ + {name: 4, x: 300, y: 50, locale: "ca", text: "Les cordes apareixen de forma automàtica quan les llaminadures entren a la seva àrea", width: 400}, + {name: 8, x: 298, y: 144, locale: "ca", moveSpeed: 100, rotateSpeed: 100} + ], it: [ + {name: 4, x: 300, y: 40, locale: "it", text: "Le corde automatiche compaiono quando un bonbon si avvicina", width: 400}, + {name: 8, x: 298, y: 144, locale: "it", moveSpeed: 100, rotateSpeed: 100} + ], nl: [ + {name: 4, x: 300, y: 40, locale: "nl", text: "Er verschijnen automatisch touwen wanneer het snoepje er in de buurt komt", width: 400}, + {name: 8, x: 298, y: 144, locale: "nl", moveSpeed: 100, rotateSpeed: 100} + ], ko: [ + {name: 4, x: 280, y: 70, locale: "ko", text: "사탕이 영역에 들어오면 *자동으로 줄이 이어져요.", width: 400}, + {name: 8, x: 298, y: 144, locale: "ko", moveSpeed: 100, rotateSpeed: 100} + ], zh: [ + {name: 4, x: 260, y: 70, locale: "zh", text: "自动绳会在糖果进入 相应区域时出现", width: 400}, + {name: 8, x: 298, y: 144, locale: "zh", moveSpeed: 100, rotateSpeed: 100} + ], ja: [ + {name: 4, x: 300, y: 70, locale: "ja", text: "キャンディが 接近すると 自動式ロープが 現われます", width: 400}, + {name: 8, x: 298, y: 144, locale: "ja", moveSpeed: 100, rotateSpeed: 100} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, + x: 160, y: 316}, + {name: 2, x: 162, y: 439}, + {name: 54, x: 160, y: 317}, + {name: 100, x: 36, y: 413, length: 130, wheel: !1, gun: !1, kickable: !1, kicked: !1, radius: -1, invisible: !1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 291, y: 413, length: 130, wheel: !1, gun: !1, kickable: !1, kicked: !1, radius: -1, invisible: !1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 3, x: 162, y: 381, moveSpeed: 100, rotateSpeed: 0, timeout: -1}, + {name: 100, x: 93, y: 231, length: 100, wheel: !1, gun: !1, kickable: !1, kicked: !1, radius: 70, + invisible: !1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 231, y: 231, length: 100, wheel: !1, gun: !1, kickable: !1, kicked: !1, radius: 70, invisible: !1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 59, x: 232, y: 232, angle: 0, size: 3, path: "0,0", moveSpeed: 40, rotateSpeed: 40, toggled: !1}, + {name: 59, x: 90, y: 232, angle: 0, size: 3, path: "0,0", moveSpeed: -40, rotateSpeed: -40, toggled: !1}, + {name: 3, x: 161, y: 32, timeout: -1}, + {name: 3, x: 161, y: 73, timeout: -1} + ]} + ]}, + {levels: [ + {settings: [ + {name: 0, + gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 161, y: 220}, + {name: 2, x: 254, y: 416}, + {name: 3, x: 299, y: 89, timeout: -1}, + {name: 3, x: 20, y: 89, timeout: -1}, + {name: 3, x: 161, y: 171, timeout: -1}, + {name: 55, x: 42, y: 237, angle: 0}, + {name: 55, x: 277, y: 233, angle: 180}, + {name: 100, x: 162, y: 88, length: 110, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 55, x: 161, y: 334, angle: -90}, + {name: 4, x: 0, y: 357, locale: "en", text: "Tap the Air Cushion to blow objects", + width: 200}, + {name: 8, x: 101, y: 347, locale: "en", angle: 180, moveSpeed: 100, rotateSpeed: 100} + ], ru: [ + {name: 8, x: 104, y: 350, locale: "ru", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 12, y: 337, locale: "ru", text: "\u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 \u043f\u043e\u0434\u0443\u0448\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0443\u0442\u044c \u043d\u0430 \u043b\u0435\u0434\u0435\u043d\u0435\u0446", width: 200} + ], fr: [ + {name: 8, x: 101, y: 347, locale: "fr", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 10, y: 347, locale: "fr", text: "Touche le coussin d'air pour qu'il souffle sur les objets", width: 200} + ], de: [ + {name: 8, x: 102, y: 354, locale: "de", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -15, y: 350, locale: "de", text: "Ber\u00fchre den Luftballon, um Objekte wegzupusten", width: 210} + ], es: [ + {name: 8, x: 102, y: 354, locale: "es", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -25, y: 360, locale: "es", text: "Aprieta el fuelle para soplar aire y mover objetos.", width: 210} + ], br: [ + {name: 8, x: 102, y: 354, locale: "br", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -25, y: 360, locale: "br", text: "Toque a almofada de ar para soprar objetos", width: 210} + ], ca: [ + {name: 8, x: 102, y: 354, locale: "ca", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -25, y: 360, locale: "ca", text: "Prem el coixinet inflable per llançar aire", width: 210} + ], it: [ + {name: 8, x: 102, y: 354, locale: "it", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -25, y: 330, locale: "it", text: "Tocca il cuscino d'aria per soffiare sugli oggetti e spostarli", width: 210} + ], nl: [ + {name: 8, x: 102, y: 354, locale: "nl", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -55, y: 335, locale: "nl", text: "Tik op het luchtkussen om voorwerpen weg te blazen", width: 250} + ], ko: [ + {name: 8, x: 102, y: 354, locale: "ko", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -75, y: 375, locale: "ko", text: "공기 주머니를 터치하면 *물건을 날려 보내요.", width: 250} + ], zh: [ + {name: 8, x: 102, y: 354, locale: "zh", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -65, y: 370, locale: "zh", text: "触按气垫以吹起物品", width: 290} + ], ja: [ + {name: 8, x: 102, y: 354, locale: "ja", angle: 180, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: -90, y: 325, locale: "ja", text: "エアー クッションを タップ して いろいろな ものを 吹き飛ばし ましょう", width: 250} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, special: 1, ropePhysicsSpeed: 1} + ], objects: [ + {name: 52, x: 215, y: 210}, + {name: 2, x: 190, y: 322}, + {name: 55, x: 284, y: 208, angle: -180}, + {name: 100, x: 222, y: 82, length: 90, wheel: !1, + radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 100, x: 101, y: 209, length: 95, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 3, x: 99, y: 253, timeout: -1}, + {name: 3, x: 98, y: 345, timeout: -1}, + {name: 3, x: 98, y: 82, timeout: -1}, + {name: 55, x: 37, y: 343, angle: 0}, + {name: 57, x: 37, y: 257, angle: 0, size: 1}, + {name: 54, x: 97, y: 144}, + {name: 60, x: 220, y: 256, angle: 0, size: 4} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, + x: 321, y: 213}, + {name: 2, x: 431, y: 386}, + {name: 100, x: 323, y: 47, length: 130, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 55, x: 183, y: 224, angle: 0}, + {name: 100, x: 323, y: 167, length: 200, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 323, y: 105, length: 170, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 3, x: 320, y: 399, timeout: -1}, + {name: 57, x: 323, y: 347, angle: 0, size: 1}, + {name: 3, + x: 422, y: 161, timeout: -1}, + {name: 3, x: 322, y: 302, timeout: -1} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 401, y: 423}, + {name: 3, x: 226, y: 158, timeout: -1}, + {name: 3, x: 402, y: 160, timeout: -1}, + {name: 55, x: 151, y: 130, angle: 0}, + {name: 3, x: 529, y: 158, timeout: -1}, + {name: 54, x: 400, y: 351}, + {name: 54, x: 314, y: 351}, + {name: 52, x: 528, y: 225}, + {name: 100, x: 529, y: 87, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 306, y: 87, length: 250, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 529, y: 352, length: 90, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, special: 1, ropePhysicsSpeed: 1} + ], objects: [ + {name: 2, x: 219, y: 433}, + {name: 54, x: 100, y: 176}, + {name: 54, x: 159, y: 178}, + {name: 54, x: 218, y: 178}, + {name: 54, x: 100, y: 242}, + {name: 54, x: 159, y: 244}, + {name: 54, x: 218, y: 244}, + {name: 54, + x: 100, y: 308}, + {name: 54, x: 159, y: 310}, + {name: 54, x: 218, y: 310}, + {name: 54, x: 102, y: 373}, + {name: 54, x: 161, y: 375}, + {name: 54, x: 220, y: 375}, + {name: 54, x: 98, y: 109}, + {name: 54, x: 220, y: 110}, + {name: 3, x: 99, y: 110, timeout: -1}, + {name: 3, x: 218, y: 244, timeout: -1}, + {name: 3, x: 103, y: 372, timeout: -1}, + {name: 52, x: 157, y: 97}, + {name: 55, x: 36, y: 376, angle: -20}, + {name: 55, x: 35, y: 247, angle: -20}, + {name: 55, x: 284, y: 245, angle: 200}, + {name: 55, x: 284, y: 374, angle: 200}, + {name: 54, x: 40, y: 312}, + {name: 54, x: 277, y: 310}, + {name: 54, x: 280, y: 178}, + {name: 54, x: 37, y: 180}, + {name: 100, + x: 163, y: 33, length: 50, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1}, + {name: 54, x: 280, y: 111}, + {name: 54, x: 37, y: 108} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 390, y: 125}, + {name: 2, x: 318, y: 431}, + {name: 100, x: 391, y: 46, length: 40, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 323, y: 225, length: 70, wheel: !1, gun: !1, radius: 80, moveLength: -1, moveVertical: !1, + moveOffset: 0, spider: !0, part: "L"}, + {name: 57, x: 375, y: 406, angle: 90, size: 1}, + {name: 57, x: 256, y: 407, angle: 90, size: 1}, + {name: 4, x: 381, y: 280, locale: "en", text: "Cut the rope before the spider reaches the candy", width: 240}, + {name: 13, x: 385, y: 330, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 3, x: 372, y: 223, timeout: -1}, + {name: 3, x: 230, y: 287, timeout: -1}, + {name: 3, x: 317, y: 377, timeout: -1} + ], ru: [ + {name: 4, x: 48, y: 251, locale: "ru", text: "\u041f\u0435\u0440\u0435\u0440\u0435\u0436\u044c\u0442\u0435 \u0432\u0435\u0440\u0435\u0432\u043a\u0443 \u043f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043f\u0430\u0443\u0447\u043e\u043a \u0434\u043e\u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0434\u043e \u043b\u0435\u0434\u0435\u043d\u0446\u0430", + width: 200}, + {name: 13, x: 35, y: 330, locale: "ru", moveSpeed: 100, rotateSpeed: 100} + ], fr: [ + {name: 4, x: 26, y: 289, locale: "fr", text: "Coupe la corde avant que l'araign\u00e9e n'atteigne le bonbon", width: 260}, + {name: 13, x: 29, y: 344, locale: "fr", moveSpeed: 100, rotateSpeed: 100} + ], de: [ + {name: 4, x: 79, y: 287, locale: "de", text: "Schneide das Seil durch, bevor die Spinne am Bonbon ist", width: 170}, + {name: 13, x: 150, y: 276, locale: "de", moveSpeed: 100, rotateSpeed: 100} + ], es: [ + {name: 4, x: 29, y: 287, locale: "es", text: "Corta la cuerda antes de que la araña llegue al caramelo.", width: 200}, + {name: 13, x: 50, y: 316, locale: "es", moveSpeed: 100, rotateSpeed: 100} + ], br: [ + {name: 4, x: 29, y: 287, locale: "br", text: "Corte a corda antes que a aranha atinja os doces", width: 200}, + {name: 13, x: 20, y: 336, locale: "br", moveSpeed: 100, rotateSpeed: 100} + ], ca: [ + {name: 4, x: 29, y: 287, locale: "ca", text: "Talla la corda abans que l'aranya arribi a les llaminadures", width: 200}, + {name: 13, x: 20, y: 336, locale: "ca", moveSpeed: 100, rotateSpeed: 100} + ], it: [ + {name: 4, x: 29, y: 287, locale: "it", text: "Taglia la corda prima che il ragno raggiunga il bonbon", width: 200}, + {name: 13, x: 50, y: 336, locale: "it", moveSpeed: 100, rotateSpeed: 100} + ], nl: [ + {name: 4, x: 29, y: 267, locale: "nl", text: "Snijd het touw door voordat de spin het snoepje kan bereiken", width: 200}, + {name: 13, x: 40, y: 316, locale: "nl", moveSpeed: 100, rotateSpeed: 100} + ], ko: [ + {name: 4, x: 29, y: 267, locale: "ko", text: "거미가 사탕에 도착하기 전에 줄을 자르세요!", width: 200}, + {name: 13, x: 15, y: 316, locale: "ko", moveSpeed: 100, rotateSpeed: 100} + ], zh: [ + {name: 4, x: 29, y: 297, locale: "zh", text: "在蜘蛛到达糖果之前 剪断绳索", width: 300}, + {name: 13, x: 10, y: 316, locale: "zh", moveSpeed: 100, rotateSpeed: 100} + ], ja: [ + {name: 4, x: 29, y: 267, locale: "ja", text: "クモが キャンディに 到達する 前に ロープを 切り ましょう", width: 200}, + {name: 13, x: 10, y: 316, locale: "ja", moveSpeed: 100, rotateSpeed: 100} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, + special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 442, y: 421}, + {name: 52, x: 181, y: 172}, + {name: 100, x: 345, y: 136, length: 100, wheel: !1, gun: !1, radius: 65, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 185, y: 79, length: 60, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 257, y: 245, length: 100, wheel: !1, gun: !1, radius: 65, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !0, part: "L"}, + {name: 3, x: 256, y: 127, timeout: -1}, + {name: 3, x: 434, y: 336, timeout: -1}, + {name: 3, x: 257, y: 335, timeout: -1}, + {name: 54, x: 345, y: 307}, + {name: 100, x: 436, y: 243, length: 100, wheel: !1, gun: !1, radius: 65, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !0, part: "L"}, + {name: 101, x: 108, y: 273, angle: 20, drawing: 2} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 54, x: 109, y: 257}, + {name: 55, x: 66, y: 72, angle: 50}, + {name: 3, x: 208, y: 191, timeout: -1}, + {name: 3, x: 385, y: 195, timeout: -1}, + {name: 3, x: 546, y: 192, timeout: -1}, + {name: 2, x: 458, y: 416}, + {name: 52, x: 111, y: 174}, + {name: 100, x: 113, y: 83, length: 50, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 55, x: 161, y: 72, angle: 50}, + {name: 55, x: 258, y: 73, angle: 50}, + {name: 55, x: 349, y: 73, angle: 50}, + {name: 100, x: 47, y: 154, length: 460, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !0, part: "L"}, + {name: 55, x: 437, y: 73, angle: 50}, + {name: 60, x: 582, y: 203, angle: 90, size: 4} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, + special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 321, y: 414}, + {name: 52, x: 323, y: 191}, + {name: 100, x: 408, y: 302, length: 140, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !0, part: "L"}, + {name: 100, x: 224, y: 304, length: 140, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !0, part: "L"}, + {name: 100, x: 383, y: 125, length: 80, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !0, part: "L"}, + {name: 100, x: 256, y: 126, length: 80, wheel: !1, gun: !1, radius: -1, moveLength: -1, + moveVertical: !1, moveOffset: 0, spider: !0, part: "L"}, + {name: 3, x: 321, y: 275, moveSpeed: 100, rotateSpeed: 100, timeout: -1}, + {name: 3, x: 660, y: 133, path: "-39,-17,-91,-21,-154,-11,-201,10,-240,49,-284,99,-331,159,", moveSpeed: 45, rotateSpeed: 0, timeout: -1}, + {name: 3, x: -20, y: 142, path: "46,-14,93,-26,142,-18,195,3,239,40,282,97,327,151,", moveSpeed: 45, rotateSpeed: 0, timeout: -1}, + {name: 54, x: 319, y: 340} + ], "layer 2": [ + {name: 60, x: 232, y: 172, angle: 55, size: 4}, + {name: 60, x: 406, y: 172, angle: -55, size: 4} + ]} + ]}, + {levels: [ + {settings: [ + {name: 0, gridSize: 32, + width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 314, y: 372}, + {name: 82, x: 176, y: 397, angle: 25, size: 2}, + {name: 82, x: 454, y: 396, angle: -25, size: 2}, + {name: 100, x: 320, y: 14, length: 160, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 52, x: 159, y: 123}, + {name: 82, x: 86, y: 352, angle: 25, size: 2}, + {name: 82, x: 548, y: 351, angle: -25, size: 2}, + {name: 3, x: 165, y: 350, timeout: -1}, + {name: 3, x: 471, y: 350, timeout: -1}, + {name: 3, x: 320, y: 319, moveSpeed: 35, timeout: -1}, + {name: 82, + x: -6, y: 306, angle: 25, size: 2}, + {name: 82, x: 643, y: 304, angle: -25, size: 2}, + {name: 82, x: 360, y: 440, angle: -25, size: 2}, + {name: 82, x: 267, y: 440, angle: 25, size: 2} + ], en: [ + {name: 4, x: 210, y: 155, locale: "en", text: "Candy will bounce away from this platform", width: 300}, + {name: 13, x: 207, y: 230, locale: "en", moveSpeed: 100, rotateSpeed: 100} + ], ru: [ + {name: 4, x: 200, y: 152, locale: "ru", text: "\u041b\u0435\u0434\u0435\u043d\u0435\u0446 \u043e\u0442\u0441\u043a\u0430\u043a\u0438\u0432\u0430\u0435\u0442 \u043e\u0442 \u0442\u0430\u043a\u0438\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c", + width: 300}, + {name: 13, x: 206, y: 220, locale: "ru", moveSpeed: 100, rotateSpeed: 100} + ], de: [ + {name: 4, x: 210, y: 150, locale: "de", text: "Die S\u00fc\u00dfigkeit wird von der Plattform h\u00fcpfen", width: 270}, + {name: 13, x: 210, y: 219, locale: "de", moveSpeed: 100, rotateSpeed: 100} + ], fr: [ + {name: 4, x: 218, y: 140, locale: "fr", text: "Le bonbon rebondira hors de cette plate-forme", width: 280}, + {name: 13, x: 209, y: 218, locale: "fr", moveSpeed: 100, rotateSpeed: 100} + ], es: [ + {name: 4, x: 218, y: 130, locale: "es", text: "El caramelo rebota al tocar esta plataforma.", width: 290}, + {name: 13, x: 190, y: 185, locale: "es", moveSpeed: 100, rotateSpeed: 100} + ], br: [ + {name: 4, x: 200, y: 130, locale: "br", text: "Doces quicarão para longe desta plataforma.", width: 290}, + {name: 13, x: 190, y: 185, locale: "br", moveSpeed: 100, rotateSpeed: 100} + ], ca: [ + {name: 4, x: 190, y: 130, locale: "ca", text: "Les llaminadures rebotaran des d'aquesta plataforma", width: 290}, + {name: 13, x: 190, y: 185, locale: "ca", moveSpeed: 100, rotateSpeed: 100} + ], it: [ + {name: 4, x: 190, y: 130, locale: "it", text: "Il bonbon rimbalzerà fuori dalla piattaforma", width: 290}, + {name: 13, x: 240, y: 180, locale: "it", moveSpeed: 100, rotateSpeed: 100} + ], nl: [ + {name: 4, x: 190, y: 130, locale: "nl", text: "Het snoepje stuitert tegen dit oppervlak", width: 290}, + {name: 13, x: 190, y: 185, locale: "nl", moveSpeed: 100, rotateSpeed: 100} + ], ko: [ + {name: 4, x: 190, y: 150, locale: "ko", text: "여기에서는 사탕이 *튕겨요.", width: 290}, + {name: 13, x: 190, y: 185, locale: "ko", moveSpeed: 100, rotateSpeed: 100} + ], zh: [ + {name: 4, x: 180, y: 140, locale: "zh", text: "糖果将从 这个平台上弹走", width: 290}, + {name: 13, x: 190, y: 185, locale: "zh", moveSpeed: 100, rotateSpeed: 100} + ], ja: [ + {name: 4, x: 190, y: 100, locale: "ja", text: "この プラットホームに 乗った キャンディは 弾んで 跳ね返ります", width: 290}, + {name: 13, x: 190, y: 185, locale: "ja", moveSpeed: 100, rotateSpeed: 100} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, twoParts: !1} + ], + objects: [ + {name: 82, x: 254, y: 139, angle: -135, size: 2}, + {name: 82, x: 62, y: 136, angle: 135, size: 2}, + {name: 82, x: 253, y: 335, angle: -45, size: 2}, + {name: 82, x: 66, y: 332, angle: 45, size: 2}, + {name: 2, x: 48, y: 222}, + {name: 52, x: 159, y: 235}, + {name: 82, x: 159, y: 373, angle: 0, size: 2}, + {name: 82, x: 157, y: 101, angle: 180, size: 2}, + {name: 3, x: 161, y: 327, timeout: -1}, + {name: 3, x: 160, y: 141, timeout: -1}, + {name: 3, x: 224, y: 234, timeout: -1}, + {name: 100, x: 85, y: 429, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, + x: 241, y: 429, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 91, y: 56, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 231, y: 57, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 55, x: 284, y: 235, angle: 135}, + {name: 103, x: 290, y: 45, angle: 10, drawing: 3} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, + twoParts: !1} + ], objects: [ + {name: 52, x: 231, y: 196}, + {name: 55, x: 129, y: 193, angle: 0}, + {name: 55, x: 651, y: 187, angle: 180}, + {name: 82, x: 336, y: 260, angle: 0, size: 2}, + {name: 82, x: 445, y: 260, angle: 0, size: 2}, + {name: 82, x: 548, y: 260, angle: 0, size: 2}, + {name: 3, x: 575, y: 71, path: "0,150", moveSpeed: 30, timeout: 10}, + {name: 3, x: 385, y: 69, path: "0,150", moveSpeed: 20, timeout: 15}, + {name: 3, x: 481, y: 71, path: "0,150", moveSpeed: 10, timeout: 20}, + {name: 2, x: 55, y: 422}, + {name: 82, x: 225, y: 260, angle: 0, size: 2}, + {name: 100, x: 57, y: 308, length: 100, wheel: !1, gun: !1, radius: 70, + moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 388, y: 133}, + {name: 2, x: 273, y: 41}, + {name: 81, x: 398, y: 189, angle: -30, size: 1}, + {name: 81, x: 191, y: 229, angle: 40, size: 1}, + {name: 81, x: 404, y: 310, angle: -30, size: 1}, + {name: 81, x: 203, y: 372, angle: 30, size: 1}, + {name: 81, x: 397, y: 448, angle: -30, size: 1}, + {name: 3, x: 403, y: 307, path: "RW40", moveSpeed: 75, rotateSpeed: 0, timeout: -1}, + {name: 100, x: 388, y: 27, + length: 70, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L", hidePath: !1}, + {name: 54, x: 308, y: 398}, + {name: 3, x: 204, y: 367, path: "RC40", moveSpeed: 75, rotateSpeed: 0, timeout: -1}, + {name: 3, x: 220, y: 196, timeout: -1} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 140, y: 217}, + {name: 82, x: 131, y: 261, angle: 0, size: 2}, + {name: 55, x: 57, y: 197, angle: 0}, + {name: 2, x: 150, y: 431}, + {name: 3, x: 230, y: 230, timeout: -1}, + {name: 82, x: 281, y: 199, + angle: -90, size: 2}, + {name: 54, x: 222, y: 311}, + {name: 55, x: 57, y: 317, angle: 0}, + {name: 3, x: 165, y: 360, timeout: -1}, + {name: 3, x: 165, y: 70, timeout: -1}, + {name: 82, x: 281, y: 315, angle: -90, size: 2} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, twoParts: !1} + ], objects: [ + {name: 81, x: 211, y: 447, angle: 0, size: 1}, + {name: 81, x: 278, y: 447, angle: 0, size: 1}, + {name: 81, x: 343, y: 448, angle: 0, size: 1}, + {name: 81, x: 407, y: 448, angle: 0, size: 1}, + {name: 81, x: 472, y: 448, angle: 0, size: 1}, + {name: 81, x: 538, y: 448, angle: 0, size: 1}, + {name: 81, + x: 601, y: 448, angle: 0, size: 1}, + {name: 81, x: 280, y: 42, angle: 180, size: 1}, + {name: 81, x: 344, y: 49, angle: 190, size: 1}, + {name: 81, x: 405, y: 66, angle: 200, size: 1}, + {name: 81, x: 462, y: 92, angle: 210, size: 1}, + {name: 81, x: 514, y: 129, angle: 220, size: 1}, + {name: 81, x: 558, y: 174, angle: 230, size: 1}, + {name: 81, x: 595, y: 226, angle: 240, size: 1}, + {name: 81, x: 617, y: 283, angle: 260, size: 1}, + {name: 81, x: 624, y: 345, angle: 270, size: 1}, + {name: 2, x: 52, y: 352}, + {name: 100, x: 219, y: 72, length: 220, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, + part: "L"}, + {name: 52, x: 221, y: 313}, + {name: 81, x: 624, y: 407, angle: -90, size: 1}, + {name: 81, x: 216, y: 42, angle: 180, size: 1}, + {name: 3, x: 558, y: 258, path: "-39,-66,-96,-120,-160,-155,", moveSpeed: 70, timeout: -1}, + {name: 3, x: 587, y: 343, timeout: -1}, + {name: 3, x: 277, y: 409, timeout: -1}, + {name: 55, x: 127, y: 345, angle: 0}, + {name: 81, x: 87, y: 447, angle: 0, size: 1}, + {name: 81, x: 149, y: 447, angle: 0, size: 1}, + {name: 81, x: 25, y: 447, angle: 0, size: 1} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, twoParts: !1} + ], objects: [ + {name: 100, + x: 160, y: 270, length: 140, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 82, x: 160, y: 147, angle: 0, size: 2}, + {name: 52, x: 114, y: 107}, + {name: 2, x: 37, y: 387}, + {name: 100, x: 160, y: 270, length: 100, wheel: !1, gun: !1, radius: 120, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 82, x: 210, y: 386, angle: 90, size: 2}, + {name: 54, x: 273, y: 389}, + {name: 3, x: 277, y: 389, timeout: -1}, + {name: 3, x: 267, y: 145, timeout: -1}, + {name: 3, x: 57, y: 143, timeout: -1} + ]}, + {settings: [ + {name: 0, gridSize: 32, + width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 82, x: 106, y: 407, angle: 0, size: 2}, + {name: 82, x: 278, y: 354, angle: -80, size: 2}, + {name: 82, x: 41, y: 353, angle: 80, size: 2}, + {name: 82, x: 23, y: 250, angle: 80, size: 2}, + {name: 82, x: 298, y: 252, angle: -80, size: 2}, + {name: 55, x: 91, y: 348, angle: 0}, + {name: 52, x: 213, y: 339}, + {name: 2, x: 43, y: 95}, + {name: 3, x: 106, y: 240, timeout: -1}, + {name: 3, x: 70, y: 197, timeout: -1}, + {name: 3, x: 127, y: 191, timeout: -1}, + {name: 82, x: 212, y: 407, angle: 0, size: 2}, + {name: 54, x: 100, y: 207} + ]}, + {settings: [ + {name: 0, + gridSize: 32, width: 800, height: 480}, + {name: 1, ropePhysicsSpeed: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 608, y: 346}, + {name: 52, x: 397, y: 255}, + {name: 82, x: 292, y: 313, angle: 0, size: 2}, + {name: 82, x: 394, y: 313, angle: 0, size: 2}, + {name: 82, x: 499, y: 313, angle: 0, size: 2}, + {name: 82, x: 628, y: 185, angle: -90, size: 2}, + {name: 82, x: 496, y: 53, angle: 180, size: 2}, + {name: 82, x: 290, y: 184, angle: 0, size: 2}, + {name: 82, x: 391, y: 185, angle: 0, size: 2}, + {name: 82, x: 252, y: 247, angle: 90, size: 2}, + {name: 82, x: 392, y: 53, angle: 180, size: 2}, + {name: 82, x: 286, y: 53, angle: 180, size: 2}, + {name: 82, x: 57, y: 188, angle: 90, size: 2}, + {name: 82, x: 58, y: 289, angle: 90, size: 2}, + {name: 82, x: 190, y: 424, angle: 0, size: 2}, + {name: 82, x: 298, y: 425, angle: 0, size: 2}, + {name: 82, x: 406, y: 425, angle: 0, size: 2}, + {name: 55, x: 302, y: 254, angle: 0}, + {name: 82, x: 591, y: 277, angle: -45, size: 2}, + {name: 82, x: 590, y: 92, angle: -135, size: 2}, + {name: 82, x: 97, y: 385, angle: 45, size: 2}, + {name: 82, x: 90, y: 94, angle: 135, size: 2}, + {name: 55, x: 502, y: 372, angle: 180}, + {name: 82, x: 510, y: 425, angle: 0, size: 2}, + {name: 3, x: 571, y: 191, timeout: -1}, + {name: 3, x: 219, y: 237, timeout: -1}, + {name: 3, + x: 372, y: 369, timeout: -1}, + {name: 82, x: 698, y: 380, angle: -45, size: 2}, + {name: 82, x: 685, y: 283, angle: -135, size: 2}, + {name: 82, x: 180, y: 53, angle: 180, size: 2}, + {name: 82, x: 613, y: 425, angle: 0, size: 2} + ]} + ]}, + {levels: [ + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 290, y: 384}, + {name: 56, x: 15, y: 367, group: 0, angle: -90}, + {name: 56, x: 290, y: 114, group: 0, angle: 90}, + {name: 52, x: 15, y: 150}, + {name: 100, x: 15, y: 69, length: 90, wheel: !1, gun: !1, radius: -1, moveLength: 0, moveVertical: !1, + moveOffset: 0, spider: !1, part: "L"}, + {name: 4, x: 46, y: 50, locale: "en", text: "Drop the candy into the magic hat and it will fall out from the other one", width: 200}, + {name: 8, x: 100, y: 360, locale: "en", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 3, x: 15, y: 328, timeout: -1}, + {name: 3, x: 290, y: 177, timeout: -1}, + {name: 3, x: 290, y: 319, timeout: -1} + ], fr: [ + {name: 8, x: 118, y: 347, locale: "fr", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 46, y: 10, locale: "fr", text: "D\u00e9pose le bonbon dans le chapeau magique et il tombera de l'autre chapeau", + width: 200} + ], de: [ + {name: 8, x: 118, y: 348, locale: "de", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 32, y: 37, locale: "de", text: "Wirf den Bonbon in den magischen Hut und er kommt aus einem anderen wieder raus", width: 220} + ], ru: [ + {name: 8, x: 122, y: 354, locale: "ru", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 40, y: 30, locale: "ru", text: "\u041a\u0438\u043d\u044c\u0442\u0435 \u043a\u043e\u043d\u0444\u0435\u0442\u0443 \u0432 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0432\u043e\u043b\u0448\u0435\u0431\u043d\u044b\u0445 \u0448\u043b\u044f\u043f, \u0438 \u043e\u043d\u0430 \u0432\u044b\u043b\u0435\u0442\u0438\u0442 \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0439", + width: 200} + ], es: [ + {name: 8, x: 118, y: 348, locale: "es", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 32, y: 37, locale: "es", text: "Al caer en una chistera mágica, el caramelo saldrá por la otra.", width: 210} + ], br: [ + {name: 8, x: 118, y: 348, locale: "br", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 32, y: 37, locale: "br", text: "Jogue os doces no chapéu mágico e eles cairão do outro chapéu", width: 210} + ], ca: [ + {name: 8, x: 118, y: 358, locale: "ca", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 32, y: 7, locale: "ca", text: "Deixa caure les llaminadures en el barret màgic i tornaran a caure des de l'altre", width: 210} + ], it: [ + {name: 8, x: 118, y: 358, locale: "it", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 32, y: 7, locale: "it", text: "Butta il bonbon nel cappello magico e cadrà dall'altro cappello", width: 210} + ], nl: [ + {name: 8, x: 118, y: 358, locale: "nl", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 32, y: 7, locale: "nl", text: "Laat het snoepje in de toverhoed vallen en het komt er bij de andere weer uit", width: 210} + ], ko: [ + {name: 8, x: 118, y: 358, locale: "ko", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 32, y: 135, locale: "ko", text: "마술 모자에 사탕을 넣으면 *다른 마술 모자에서 *튀어나와요.", width: 210} + ], zh: [ + {name: 8, x: 118, y: 358, locale: "zh", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 0, y: 220, locale: "zh", text: "将糖果丢入魔术帽。 它会从另一个魔术帽中掉出", width: 380} + ], ja: [ + {name: 8, x: 118, y: 358, locale: "ja", angle: 0, moveSpeed: 100, rotateSpeed: 100}, + {name: 4, x: 12, y: 200, locale: "ja", text: "魔法の帽子にキャンディを\n入れると、 他の帽子から\n出てきます", width: 380} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 4, x: 58, y: 0, locale: "en", text: "Candy maintains its speed when teleporting", width: 250}, + {name: 13, x: 39, y: 70, locale: "en", moveSpeed: 100, rotateSpeed: 100}, + {name: 2, x: 253, y: 177}, + {name: 56, x: 241, y: 373, group: 0, angle: -180}, + {name: 56, x: 70, y: 235, group: 0, angle: -60}, + {name: 52, x: 191, y: 379}, + {name: 100, x: 112, y: 378, length: 50, wheel: !1, gun: !1, radius: -1, moveLength: 80, moveVertical: !1, moveOffset: 80, + spider: !1, part: "L"}, + {name: 100, x: 266, y: 321, length: 55, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 100, x: 267, y: 432, length: 55, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 3, x: 113, y: 169, path: "RW30", moveSpeed: 70, timeout: -1}, + {name: 3, x: 148, y: 154, path: "RC30", moveSpeed: 80, timeout: -1}, + {name: 3, x: 130, y: 158, path: "RC20", moveSpeed: 80, timeout: -1} + ], fr: [ + {name: 4, x: -55, y: 13, locale: "fr", text: "La vitesse du bonbon reste identique lorsqu'il est t\u00e9l\u00e9port\u00e9", + width: 300}, + {name: 13, x: -50, y: 73, locale: "fr", moveSpeed: 100, rotateSpeed: 100} + ], de: [ + {name: 4, x: -20, y: 0, locale: "de", text: "Beim Teleportieren beh\u00e4lt der Bonbon seine Geschwindigkeit bei", width: 360}, + {name: 13, x: 0, y: 52, locale: "de", moveSpeed: 100, rotateSpeed: 100} + ], ru: [ + {name: 4, x: 62, y: 1, locale: "ru", text: "\u041a\u043e\u043d\u0444\u0435\u0442\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u0432\u043e\u044e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0430\u0446\u0438\u0438", + width: 300}, + {name: 13, x: 43, y: 69, locale: "ru", moveSpeed: 100, rotateSpeed: 100} + ], es: [ + {name: 4, x: -50, y: 10, locale: "es", text: "El caramelo conserva la velocidad al teletransportarse.", width: 360}, + {name: 13, x: -60, y: 62, locale: "es", moveSpeed: 100, rotateSpeed: 100} + ], br: [ + {name: 4, x: -20, y: 10, locale: "br", text: "Os doces mantêm sua velocidade ao teleportar", width: 360}, + {name: 13, x: -30, y: 62, locale: "br", moveSpeed: 100, rotateSpeed: 100} + ], ca: [ + {name: 4, x: -50, y: 10, locale: "ca", text: "Les llaminadures mantenen la seva velocitat durant el teletransport", width: 360}, + {name: 13, x: -75, y: 62, locale: "ca", moveSpeed: 100, rotateSpeed: 100} + ], it: [ + {name: 4, x: -70, y: 0, locale: "it", text: "I bonbon mantengono la stessa velocità durante il teletrasporto", width: 360}, + {name: 13, x: -75, y: 55, locale: "it", moveSpeed: 100, rotateSpeed: 100} + ], nl: [ + {name: 4, x: -70, y: 0, locale: "nl", text: "Tijdens het teleporteren behoudt het snoepje dezelfde snelheid", width: 360}, + {name: 13, x: 10, y: 52, locale: "nl", moveSpeed: 100, rotateSpeed: 100} + ], ko: [ + {name: 4, x: -50, y: 30, locale: "ko", text: "사탕이 순간 이동할 *때도 속도는 변하지 *않아요.", width: 360}, + {name: 13, x: -55, y: 62, locale: "ko", moveSpeed: 100, rotateSpeed: 100} + ], zh: [ + {name: 4, x: -50, y: 30, locale: "zh", text: "糖果在传送时\n保持速度", width: 360}, + {name: 13, x: 10, y: 62, locale: "zh", moveSpeed: 100, rotateSpeed: 100} + ], ja: [ + {name: 4, x: -50, y: 30, locale: "ja", text: "テレポートするとき、 キャンディの 速度は 維持 されます", width: 360}, + {name: 13, x: -55, y: 62, locale: "ja", moveSpeed: 100, rotateSpeed: 100} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 320, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 55, y: 333}, + {name: 52, x: 220, y: 340}, + {name: 81, x: 130, y: 405, angle: 0, size: 1}, + {name: 81, x: 210, y: 405, angle: 0, size: 1}, + {name: 100, x: 167, y: 310, length: 50, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 56, x: 260, y: 353, group: 0, angle: -180}, + {name: 56, x: 65, y: 165, group: 0, angle: 0}, + {name: 81, x: 280, y: 225, angle: 0, size: 1}, + {name: 81, x: 200, y: 225, angle: 0, size: 1}, + {name: 81, x: 120, y: 225, angle: 0, size: 1}, + {name: 100, x: 198, y: 113, length: 100, wheel: !1, gun: !1, radius: 65, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 3, x: 269, y: 183, path: "1,-110,", moveSpeed: 50, timeout: -1}, + {name: 3, x: 130, y: 84, path: "1,110,", moveSpeed: 50, timeout: -1}, + {name: 3, x: 198, y: 187, timeout: -1} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, + x: 548, y: 117}, + {name: 52, x: 100, y: 315}, + {name: 54, x: 100, y: 316}, + {name: 100, x: 99, y: 442, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 82, x: 47, y: 213, angle: 90, size: 2}, + {name: 55, x: 159, y: 209, angle: 180}, + {name: 56, x: 146, y: 51, group: 0, angle: 90}, + {name: 82, x: 272, y: 209, angle: 90, size: 2}, + {name: 56, x: 322, y: 399, group: 0, angle: 270}, + {name: 55, x: 385, y: 206, angle: 180}, + {name: 56, x: 544, y: 398, group: 1, angle: 270}, + {name: 56, x: 371, y: 54, group: 1, angle: 90}, + {name: 3, x: 546, y: 210, timeout: -1}, + {name: 3, x: 96, y: 210, timeout: -1}, + {name: 3, x: 323, y: 207, timeout: -1} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 433, y: 284}, + {name: 100, x: 338, y: 50, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L", hidePath: !1}, + {name: 100, x: 338, y: 358, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L", hidePath: !1}, + {name: 100, x: 459, y: 202, length: 100, wheel: !1, + gun: !1, radius: -1, moveLength: 100, moveVertical: !1, moveOffset: 0, spider: !1, part: "L", hidePath: !1}, + {name: 100, x: 223, y: 202, length: 100, wheel: !1, gun: !1, radius: -1, moveLength: 100, moveVertical: !1, moveOffset: 100, spider: !1, part: "L", hidePath: !1}, + {name: 52, x: 335, y: 200}, + {name: 3, x: 208, y: 72, timeout: -1}, + {name: 3, x: 432, y: 369, timeout: -1}, + {name: 3, x: 209, y: 369, timeout: -1}, + {name: 56, x: 446, y: 137, group: 0, angle: 180}, + {name: 56, x: 212, y: 427, group: 0, angle: 270}, + {name: 56, x: 433, y: 429, group: 1, angle: 270}, + {name: 56, x: 227, y: 150, group: 1, angle: 0} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 167, y: 358}, + {name: 2, x: 480, y: 76}, + {name: 54, x: 168, y: 358}, + {name: 56, x: 83, y: 281, group: 1, angle: 0}, + {name: 56, x: 84, y: 186, group: 0, angle: 0}, + {name: 56, x: 83, y: 90, group: 1, angle: 0}, + {name: 56, x: 483, y: 374, group: 0, angle: 270}, + {name: 55, x: 243, y: 277, angle: 180}, + {name: 55, x: 242, y: 182, angle: 180}, + {name: 55, x: 243, y: 88, angle: 180}, + {name: 3, x: 112, y: 90, timeout: -1}, + {name: 3, x: 116, y: 280, timeout: -1}, + {name: 3, x: 111, y: 186, + timeout: -1}, + {name: 80, x: 478, y: 144, initialDelay: -2, offTime: 2, onTime: 2, angle: 0, size: 5}, + {name: 55, x: 479, y: 187, angle: 90}, + {name: 100, x: 169, y: 447, length: 60, wheel: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 490, y: 57}, + {name: 56, x: 490, y: 402, group: 0, angle: 270}, + {name: 56, x: 130, y: 105, group: 0, angle: 90}, + {name: 55, x: 130, y: 270, angle: 270}, + {name: 52, x: 490, y: 355}, + {name: 100, + x: 490, y: 267, length: 50, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 3, x: 310, y: 43, timeout: -1}, + {name: 56, x: 130, y: 404, group: 1, angle: 270}, + {name: 56, x: 310, y: 401, group: 1, angle: 270}, + {name: 3, x: 310, y: 162, path: "0,200", moveSpeed: 80, timeout: -1}, + {name: 3, x: 490, y: 187, timeout: -1} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 52, x: 113, y: 189}, + {name: 100, x: 61, y: 187, length: 50, wheel: !1, radius: -1, moveVertical: !0, + spider: !1, part: "L"}, + {name: 100, x: 164, y: 188, length: 50, wheel: !1, radius: -1, moveVertical: !0, spider: !1, part: "L"}, + {name: 3, x: 545, y: 195, timeout: -1}, + {name: 56, x: 111, y: 401, group: 0, angle: 270}, + {name: 2, x: 477, y: 290}, + {name: 54, x: 269, y: 257}, + {name: 56, x: 268, y: 98, group: 0, angle: 90}, + {name: 3, x: 407, y: 191, timeout: -1}, + {name: 3, x: 475, y: 113, timeout: -1}, + {name: 56, x: 273, y: 403, group: 1, angle: 270}, + {name: 56, x: 419, y: 402, group: 1, angle: 270}, + {name: 100, x: 477, y: 195, length: 100, wheel: !1, radius: 50, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, + part: "L"}, + {name: 58, x: 114, y: 74, angle: 0, size: 2} + ]}, + {settings: [ + {name: 0, gridSize: 32, width: 640, height: 480}, + {name: 1, ropePhysicsSpeed: 1, special: 1, twoParts: !1} + ], objects: [ + {name: 2, x: 416, y: 314}, + {name: 52, x: 303, y: 136}, + {name: 100, x: 306, y: 75, length: 20, wheel: !1, gun: !1, radius: -1, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 56, x: 226, y: 400, group: 1, angle: -90}, + {name: 56, x: 304, y: 139, group: 1, angle: -180, path: "RW90", moveSpeed: 150, rotateSpeed: -96}, + {name: 56, x: 420, y: 395, group: 0, angle: -90}, + {name: 56, x: 304, + y: 139, group: 0, angle: -180, path: "RC90", moveSpeed: 100, rotateSpeed: 64}, + {name: 100, x: 224, y: 281, length: 10, wheel: !1, gun: !1, radius: 35, moveLength: -1, moveVertical: !1, moveOffset: 0, spider: !1, part: "L"}, + {name: 3, x: 212, y: 357, timeout: -1}, + {name: 3, x: 237, y: 356, timeout: -1}, + {name: 3, x: 307, y: 198, timeout: -1} + ]} + ]} + ]; + return boxes; +}); +define('resources/ResourcePacks', + [ 'resources/ResourceId' ], + function (ResourceId) { + + var ResourcePacks = {}; + + ResourcePacks.StandardMenuSounds = [ + ResourceId.SND_MENU_MUSIC, + ResourceId.SND_BUTTON, + ResourceId.SND_TAP + ]; + + ResourcePacks.TimeMenuSounds = [ + ResourceId.SND_TIME_MENU_MUSIC, + ResourceId.SND_BUTTON, + ResourceId.SND_TAP + ]; + + // game element images + ResourcePacks.StandardGameImages = [ + ResourceId.IMG_CHAR_ANIMATIONS, + ResourceId.IMG_OBJ_HOOK_01, + ResourceId.IMG_OBJ_HOOK_02, + ResourceId.IMG_OBJ_HOOK_AUTO, + ResourceId.IMG_OBJ_CANDY_01, + ResourceId.IMG_OBJ_BOUNCER_01, + ResourceId.IMG_OBJ_BOUNCER_02, + ResourceId.IMG_OBJ_BUBBLE_ATTACHED, + ResourceId.IMG_OBJ_BUBBLE_FLIGHT, + ResourceId.IMG_OBJ_BUBBLE_POP, + ResourceId.IMG_OBJ_PUMP, + ResourceId.IMG_OBJ_SPIDER, + ResourceId.IMG_OBJ_SPIKES_01, + ResourceId.IMG_OBJ_SPIKES_02, + ResourceId.IMG_OBJ_SPIKES_03, + ResourceId.IMG_OBJ_SPIKES_04, + ResourceId.IMG_OBJ_STAR_IDLE, + ResourceId.IMG_OBJ_STAR_DISAPPEAR, + ResourceId.IMG_HUD_STAR, + ResourceId.IMG_TUTORIAL_SIGNS, + ResourceId.IMG_DRAWING_HIDDEN, + ResourceId.IMG_CHAR_SUPPORTS + ]; + + ResourcePacks.Round5AdditionalGameImages = [ + ResourceId.IMG_OBJ_BEE_HD, + ResourceId.IMG_OBJ_POLLEN_HD + ]; + + ResourcePacks.Round5AdditionalSounds = [ + ResourceId.SND_BUZZ, + ResourceId.SND_GRAVITY_OFF, + ResourceId.SND_GRAVITY_ON + ]; + + ResourcePacks.TimeEditionAdditionalGameImages = [ + ResourceId.IMG_OBJ_SOCKS, + ResourceId.IMG_OBJ_HOOK_MOVABLE, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_01, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_02, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_03, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_04, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_BUTTON + ]; + + ResourcePacks.TimeEditionAdditionalSounds = [ + ResourceId.SND_SPIKE_ROTATE_IN, + ResourceId.SND_SPIKE_ROTATE_OUT, + ResourceId.SND_TELEPORT, + ResourceId.SND_CANDY_HIT, + ResourceId.SND_PREHISTORIC_MONSTER_CHEWING, + ResourceId.SND_PREHISTORIC_MONSTER_OPEN, + ResourceId.SND_PREHISTORIC_MONSTER_CLOSE, + ResourceId.SND_PREHISTORIC_MONSTER_SAD + ]; + + ResourcePacks.FullGameAdditionalGameImages = [ + ResourceId.IMG_OBJ_HOOK_MOVABLE, + ResourceId.IMG_OBJ_HOOK_REGULATED, + ResourceId.IMG_OBJ_ELECTRODES, + ResourceId.IMG_OBJ_SOCKS, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_01, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_02, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_03, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_04, + ResourceId.IMG_OBJ_ROTATABLE_SPIKES_BUTTON, + ResourceId.IMG_OBJ_BEE_HD, + ResourceId.IMG_OBJ_POLLEN_HD, + ResourceId.IMG_OBJ_VINIL + ]; + + ResourcePacks.ChromeLiteAdditionalGameImages = [ + ResourceId.IMG_OBJ_SOCKS, + ResourceId.IMG_OBJ_HOOK_MOVABLE, + ResourceId.IMG_OBJ_ELECTRODES + ]; + + ResourcePacks.ChromeLiteAdditionalGameSounds = [ + ResourceId.SND_TELEPORT, + ResourceId.SND_ELECTRIC + ]; + + // fonts + ResourcePacks.StandardFonts = [ + ResourceId.FNT_SMALL_FONT, + ResourceId.FNT_BIG_FONT, + ResourceId.FNT_FONT_NUMBERS_BIG + ]; + + ResourcePacks.StandardGameSounds = [ + ResourceId.SND_GAME_MUSIC, + ResourceId.SND_BOUNCER, + ResourceId.SND_BUBBLE, + ResourceId.SND_BUBBLE_BREAK, + ResourceId.SND_CANDY_BREAK, + ResourceId.SND_CANDY_LINK, + ResourceId.SND_MONSTER_CHEWING, + ResourceId.SND_MONSTER_CLOSE, + ResourceId.SND_MONSTER_OPEN, + ResourceId.SND_MONSTER_SAD, + ResourceId.SND_PUMP_1, + ResourceId.SND_PUMP_2, + ResourceId.SND_PUMP_3, + ResourceId.SND_PUMP_4, + ResourceId.SND_ROPE_BLEAK_1, + ResourceId.SND_ROPE_BLEAK_2, + ResourceId.SND_ROPE_BLEAK_3, + ResourceId.SND_ROPE_BLEAK_4, + ResourceId.SND_ROPE_GET, + ResourceId.SND_SPIDER_ACTIVATE, + ResourceId.SND_SPIDER_FALL, + ResourceId.SND_SPIDER_WIN, + ResourceId.SND_STAR_1, + ResourceId.SND_STAR_2, + ResourceId.SND_STAR_3, + ResourceId.SND_WIN + ]; + + ResourcePacks.FullGameAdditionalSounds = [ + ResourceId.SND_ELECTRIC, + ResourceId.SND_GRAVITY_OFF, + ResourceId.SND_GRAVITY_ON, + ResourceId.SND_RING, + ResourceId.SND_WHEEL, + ResourceId.SND_SPIKE_ROTATE_IN, + ResourceId.SND_SPIKE_ROTATE_OUT, + ResourceId.SND_SCRATCH_IN, + ResourceId.SND_SCRATCH_OUT, + ResourceId.SND_BUZZ, + ResourceId.SND_TELEPORT + ]; + + ResourcePacks.StandardMenuImageFilenames = [ + 'bBtn_bgd.png', + 'box_lock.png', + 'box_nav_menu.png', + 'box_omnom.png', + 'boxcutter.png', + 'boxmore_bgd.png', + 'buttonsprite.png', + 'fb.png', + 'fBtn_bgd.png', + 'flags.png', + 'fun-omnom.png', + 'gamecomplete.jpg', + 'lBtn_bgd.png', + 'level_bgd.png', + 'level_bgd_small.png', + 'leveltape.png', + 'leveltape_left.png', + 'leveltape_right.png', + 'mBtn_bgd.png', + 'menu_result_en.png', + 'menu_result_fr.png', + 'menu_result_gr.png', + 'menu_result_ru.png', + 'menubg.jpg', + 'options_stars_bgd.png', + 'options_stars_bgd_small.png', + 'perfect_mark.png', + 'ph_logo.png', + 'result_line.png', + 'sBtn_bgd.png', + 'shadow.png', + 'star_result.png', + 'star_result_small.png', + 'startbg.jpg', + 'taperoll.png' + ]; + + ResourcePacks.DrawingMenuImageFilenames = [ + 'drawing-bg.png' + ]; + + ResourcePacks.NetDesignResolutionImageNames = [ + 'android.png', + 'box.png', + 'comic.png', + 'facebook.png', + 'footer_dot.png', + 'footer_finger.png', + 'full_version_bg.png', + 'full_version_text.png', + 'game_bg.png', + 'ipad.png', + 'iphone.png', + 'more_close.png', + 'more_text.png', + 'more_wallpaper.png', + 'more_window_bg.png', + 'more.png', + 'papercraft.png', + 'privacy.png', + 'shop_over.png', + 'shop.png', + 'terms.png', + 'twitter.png', + 'video_bg.png', + 'youtube.png', + 'zepto.png', + 'zeptologo.png' + ]; + + return ResourcePacks; + } +); + + + + +define('ui/BoxType',[], function () { + /** + * @enum {string} + */ + var BoxType = { + NORMAL: "NORMAL", + IEPINNED: "IEPINNED", + MORECOMING: "MORECOMING", + PURCHASE: "PURCHASE", + TIME: "TIME" + }; + + return BoxType; +}); +define('resources/LangId',[], function () { + + + var LangId = { + EN: 0, + FR: 1, + DE: 2, + RU: 3, + KO: 4, //system + ZH: 5, + JA: 6, + ES: 7, + CA: 8, + BR: 9, //system + IT: 10, + NL: 11 + }; + + LangId.fromString = function (val) { + switch (val) { + case 'de': + return LangId.DE; + case 'fr': + return LangId.FR; + case 'ru': + return LangId.RU; + case 'en': + case 'en_GB': + case 'en_US': + return LangId.EN; + case 'ko': + return LangId.KO; + case 'zh': + return LangId.ZH; + case 'ja': + return LangId.JA; + case 'es': + return LangId.ES; + case 'it': + return LangId.IT; + case 'nl': + return LangId.NL; + case 'br': + return LangId.BR; + case 'ca': + return LangId.CA; + } + + // handle BCP-47 style codes, ex: en-US + if (val.length >= 3) { + switch(val.substr(0,3)) { + case 'de-': + return LangId.DE; + case 'fr-': + return LangId.FR; + case 'ru-': + return LangId.RU; + case 'en-': + return LangId.EN; + case 'ko-': + return LangId.KO; + case 'zh-': + return LangId.ZH; + case 'ja-': + return LangId.JA; + case 'es-': + return LangId.ES; + case 'it-': + return LangId.IT; + case 'nl-': + return LangId.NL; + case 'br-': + return LangId.BR; + case 'ca-': + return LangId.CA; + } + } + + return null; + }; + + LangId.toCountryCode = function (langId) { + switch (langId) { + case LangId.DE: + return 'de'; + case LangId.FR: + return 'fr'; + case LangId.RU: + return 'ru'; + case LangId.KO: + return 'ko'; + case LangId.ZH: + return 'zh'; + case LangId.JA: + return 'ja'; + case LangId.ES: + return 'es'; + case LangId.IT: + return 'it'; + case LangId.NL: + return 'nl'; + case LangId.BR: + return 'br'; + case LangId.CA: + return 'ca'; + case LangId.EN: + default: + return 'en'; + } + }; + + return LangId; +}); + +define('config/editions/net-edition', + [ + 'boxes', + 'resources/ResourcePacks', + 'resources/ResourceId', + 'ui/BoxType', + 'resources/LangId' + ], + function (boxes, ResourcePacks, ResourceId, BoxType, LangId) { + + var netEdition = { + + siteUrl: "http://www.cuttherope.net", + + // no hidden drawings yet + disableHiddenDrawings: true, + + // the text to display on the box in the box selector + boxText: [ + { en: "Cardboard Box", ko: "골판지 상자", zh: "纸板盒", ja: "ダンボール箱", nl: "Karton", it: "Cartone", ca: "Cartró", br: "Papelão", es: "Cartón", fr: "Carton", de: "Pappkiste", ru: "\u041a\u0430\u0440\u0442\u043e\u043d\u043d\u0430\u044f"}, + { en: "Fabric Box", ko: "천 상자", zh: "布盒", ja: "布の箱", nl: "Stof", it: "Tessuto", ca: "Tela", br: "Tecido", es: "Tela", fr: "Tissu", de: "Stoffkiste", ru: "\u0422\u043a\u0430\u043d\u0435\u0432\u0430\u044f"}, + { en: "Toy Box", ko: "장난감 상자", zh: "玩具盒", ja: "おもちゃ箱", nl: "Speelgoed", it: "Giochi", ca: "Joguines", br: "Brinquedos", es: "Juguetes", fr: "Jouets", de: "Spielzeugkiste", ru: "\u0418\u0433\u0440\u0443\u0448\u0435\u0447\u043d\u0430\u044f"}, + { en: "Magic Box", ko: "마술 상자", zh: "魔盒", ja: "魔法の箱", nl: "Tover", it: "Magica", ca: "Magica", br: "Mágica", es: "Magia", fr: "Magique", de: "Magiekiste", ru: "\u0412\u043e\u043b\u0448\u0435\u0431\u043d\u0430\u044f"}, + { en: "New levels\ncoming soon!", ko:"새 레벨들이 곧 추가됩니다!", zh:"新关卡 即将到来!", ja: "次の*レベル まで もう すこし!", nl: "Er komen binnenkort nieuwe levels aan!", it: "Nuovi livelli in arrivo!", ca: "Nous nivells pròximament!", br: "Novos níveis em breve!", es: "¡Más niveles próximamente!", fr: "De nouveaux niveaux bient\u00f4t disponibles!", de: "Neue Level\nkommen bald!", ru: "\u041d\u043e\u0432\u044b\u0435 \u0443\u0440\u043e\u0432\u043d\u0438\n\u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u0435!"} + ], + + // !LANG + languages: [ + LangId.EN, + LangId.FR, + LangId.IT, + LangId.DE, + LangId.NL, + LangId.RU, + LangId.ES, + LangId.BR, + LangId.CA, + LangId.KO, + LangId.ZH, + LangId.JA + ], + + // the background image to use for the box in the box selector + boxImages: ["box1_bgd.png", "box2_bgd.png", "box6_bgd.png", "box4_bgd.png", "boxmore_bgd.png"], + + // no box borders in Chrome theme + boxBorders: [], + + // images used for the sliding door transitions + boxDoors: [ + 'levelbg1.jpg', + 'levelbg2.jpg', + 'levelbg6.jpg', + 'levelbg4.jpg' + ], + + // the type of box to create + boxTypes: [BoxType.NORMAL, BoxType.NORMAL, BoxType.NORMAL, BoxType.NORMAL, BoxType.MORECOMING], + + // how many stars are required to unlock each box + unlockStars: [0, 20, 40, 60, null], + + // the index of the quad for the support OmNom sits on + supports: [0, 1, 5, 3, null], + + // determines whether the earth animation is shown + showEarth: [false, false, false, false, false], + + menuSoundIds: ResourcePacks.StandardMenuSounds, + + gameSoundIds: ResourcePacks.StandardGameSounds.concat( + ResourcePacks.ChromeLiteAdditionalGameSounds), + + menuImageFilenames: ResourcePacks.StandardMenuImageFilenames, + + loaderPageImages: [ + 'loader-bg.jpg', + 'loader-logo.png' + ], + + gameImageIds: ResourcePacks.StandardGameImages.concat( + ResourcePacks.ChromeLiteAdditionalGameImages), + + boxes: boxes, + + levelBackgroundIds: [ + ResourceId.IMG_BGR_01_P1, + ResourceId.IMG_BGR_02_P1, + + // import to use the toy box bg (#6 in full game) so offsets are correct + ResourceId.IMG_BGR_06_P1, + + // magic box + ResourceId.IMG_BGR_04_P1 + ], + + // none of the chrome lite levels scroll + levelOverlayIds: [], + + // hidden drawings are disabled + drawingImageNames: [] + }; + + return netEdition; + } +); +define('edition', + [ + 'config/editions/net-edition' + ], + function (netEdition) { + + var mobileEdition = netEdition; + mobileEdition.siteUrl = 'http://mozilla.cuttherope.net'; + + return mobileEdition; + } +); +define('utils/PubSub',[], function () { + var PubSub = {}, + subscriptions = []; + + PubSub.subscribe = function (name, callback) { + subscriptions.push({name: name, callback: callback}); + return [name, callback]; + }; + PubSub.unsubscribe = function (name, callback) { + var i, sub; + for (i = subscriptions.length; i >= 0; i--) { + sub = subscriptions[i]; + if (sub.name === name && sub.callback === callback) { + subscriptions.splice(i, 1); + } + } + }; + PubSub.publish = function (name) { + var callbacks = [], + args = Array.prototype.slice.call(arguments, 1), + i, len; + if (subscriptions.length > 0) { + for (i = 0, len = subscriptions.length; i < len; i++) { + if (subscriptions[i].name === name) { + callbacks.push(subscriptions[i].callback); + } + } + for (i = 0, len = callbacks.length; i < len; i++) { + callbacks[i].apply(this, args); + } + } + }; + + /** + * set of well known channels + * @enum {number} + */ + PubSub.ChannelId = { + LevelWon: 0, + LevelLost: 1, + OmNomClicked: 2, + DrawingClicked: 3, + StarCountChanged: 4, + ControllerActivated: 5, + ControllerDeactivateRequested: 6, + ControllerDeactivated: 7, + ControllerPaused: 8, + ControllerUnpaused: 9, + ControllerViewHidden: 10, + ControllerViewShow: 11, + LanguageChanged: 12, + ShowOptionsPage: 13, + LoadIntroVideo: 14, + Share: 15, + ShowOptions: 16, + EnableGame: 17, + DisableGame: 18, + SetPaidBoxes: 19, + AppInit: 20, + AppDomReady: 21, + AppRun: 22, + PurchaseBoxesPrompt: 23, + PauseGame: 24, + AchievementManager: 25, + UpdateBoxScore: 26, + SignIn: 27, + SignOut: 28, + UpdateCandyScroller: 29, + UpdateVisibleBoxes: 30, + SelectedBoxChanged: 31, + UserIdChanged: 32, + RoamingSettingProvider: 33, + RoamingDataChanged: 34, + BoxesUnlocked: 35 + }; + + return PubSub; +}); +define('core/SettingStorage', + [ + 'edition', + 'utils/PubSub' + ], + function (edition, PubSub) { + + var editionPrefix = edition.settingPrefix || '', + prefix = editionPrefix; + + PubSub.subscribe(PubSub.ChannelId.UserIdChanged, function (userId) { + if (userId) { + prefix = userId + '-' + editionPrefix; + } else { + prefix = editionPrefix; + } + }); + + var settingCache = {}; + + var SettingStorage = { + get: function (key) { + if (!window.localStorage) { + return null; + } + //console.log("GET",key); + if (key in settingCache) { + return settingCache[key]; + } + + return localStorage.getItem(prefix + key); + }, + set: function (key, value) { + if (window.localStorage) { + //console.log("SET",key,value); + if (value == null) { + delete settingCache[key]; + localStorage.removeItem(prefix + key); + } + else { + settingCache[key] = value.toString(); + localStorage.setItem(prefix + key, value.toString()); + } + } + }, + remove: function (key) { + if (window.localStorage) { + //console.log("REMOVE",key) + delete settingCache[key]; + localStorage.removeItem(prefix + key); + } + }, + getBoolOrDefault: function (key, defaultValue) { + var val = this.get(key); + if (val == null) { + return defaultValue; + } + return (val === 'true'); + }, + getIntOrDefault: function (key, defaultValue) { + var val = this.get(key); + if (val == null) { + return defaultValue; + } + return parseInt(val, 10); + } + }; + + return SettingStorage; + + } +); + + +define('ui/QueryStrings', + [], + function () { + + // putting all query strings in a central location so that we can easily add/remove for ship + var QueryStrings = new function () { + + // parse the query strings into a dictionary + function getQueryStrings() { + var assoc = {}, + queryString = location.search.substring(1) || '', + keyValues = queryString.split('&'), + i, len, kv, + decode = function(s) { + return decodeURIComponent(s.replace(/\+/g, " ")); + }; + + for (i = 0, len = keyValues.length; i < len; i++) { + kv = keyValues[i].split('='); + if (kv.length > 1) { + assoc[decode(kv[0])] = decode(kv[1]); + } + } + return assoc; + } + + var qs = getQueryStrings(); + + // case insensitive lookup + var urlContains = function (val) { + var url = window.location.href.toLowerCase(); + return (url.indexOf(val.toLowerCase()) >= 0); + }; + + // debug querystrings + if (false || false) { + this.box = (qs['box'] == null) ? null : parseInt(qs['box'], 10); + this.level = (qs['level'] == null) ? null : parseInt(qs['level'], 10); + this.minFps = (qs['minFps'] == null) ? null : parseInt(qs['minFps'], 10); + this.unlockAllBoxes = (this.box != null && this.level != null) || urlContains('unlockAllBoxes=true'); + this.forcePinnedBox = this.unlockAllBoxes || urlContains('enablePinnedBox=true'); + this.createScoresForBox = (qs['createScoresForBox'] == null) ? null : parseInt(qs['createScoresForBox'], 10); + } + + // there are ok to leave in for ship + this.lang = qs['lang']; + this.showBoxBackgrounds = urlContains('boxBackgrounds=true'); + this.showFrameRate = urlContains('showFrameRate=true'); + this.forceHtml5Audio = urlContains('html5audio=true'); + + // for testing + //this.unlockAllBoxes = true; + //this.showFrameRate = true; + }; + + return QueryStrings; + } +); + +define('platformLoc', + [ + 'resources/LangId' + ], + function (LangId) { + + var DefaultLoc = { + getDefaultLangId: function () { + return LangId.EN; + } + }; + + return DefaultLoc; + } +); + +define('game/CTRSettings', + [ + 'core/SettingStorage', + 'ui/QueryStrings', + 'resources/LangId', + 'platformLoc', + 'utils/PubSub' + ], + function (SettingStorage, QueryStrings, LangId, platformLoc, PubSub) { + + var SettingKeys = { + MUSIC: 'music', + SOUND: 'sound', + CLICK_TO_CUT: 'clickToCut', + IS_HD: 'isHD', + LANGUAGE: "language" + }; + + var CTRSettings = { + + showMenu: true, + + disableTextSelection: true, + + fpsEnabled: QueryStrings.showFrameRate, + + // OmNom will say hello on first level of every session + showGreeting: true, + + // game music + getMusicEnabled: function () { + return SettingStorage.getBoolOrDefault(SettingKeys.MUSIC, true); + }, + setMusicEnabled: function (musicEnabled) { + SettingStorage.set(SettingKeys.MUSIC, musicEnabled); + }, + + // sound effects + getSoundEnabled: function () { + return SettingStorage.getBoolOrDefault(SettingKeys.SOUND, true); + }, + setSoundEnabled: function (soundEnabled) { + SettingStorage.set(SettingKeys.SOUND, soundEnabled); + }, + + // click-to-cut + getClickToCut: function () { + return SettingStorage.getBoolOrDefault(SettingKeys.CLICK_TO_CUT, false); + }, + setClickToCut: function (clickToCutEnabled) { + SettingStorage.set(SettingKeys.CLICK_TO_CUT, clickToCutEnabled); + }, + + // locale + getLangId: function () { + // first see if a querystring override was specified + if (QueryStrings.lang) { + return LangId.fromString(QueryStrings.lang); + } + + // next, check the local storage setting + var langId = SettingStorage.getIntOrDefault(SettingKeys.LANGUAGE, null); + if (langId == null) { + + // see if the platform can provide a default language + langId = platformLoc.getDefaultLangId(); + + // default to english + if (langId == null) { + langId = LangId.EN; + } + } + + return langId; + }, + setLangId: function (langId) { + SettingStorage.set(SettingKeys.LANGUAGE, langId); + }, + + getIsHD: function () { + return SettingStorage.getBoolOrDefault(SettingKeys.IS_HD, null); + }, + // sd or hd resolution + setIsHD: function (isHD) { + SettingStorage.set(SettingKeys.IS_HD, isHD); + }, + + clear: function () { + SettingStorage.remove(SettingKeys.IS_HD); + } + }; + + return CTRSettings; + } +); +define('config/resolutions/2560x1440', + [ 'core/Rectangle' ], + function (Rectangle) { + + var res2560x1440 = { + + /** + * @const + * @type {number} + */ + CANVAS_WIDTH: 2560, + /** + * @const + * @type {number} + */ + CANVAS_HEIGHT: 1440, + + /** + * @const + * @type {number} + */ + CANVAS_SCALE: 1, + + /** + * Platform multiplier (maps the height of the level to the height of the canvas). + * Map height is 480 and canvas height is 576. + * @const + * @type {number} + */ + PM: 3, + + /** + * Adjusts the y offset for the level + * @const + * @type {number} + */ + PMY: 0, + + /** + * @const + * @type {number} + */ + BUNGEE_REST_LEN: 105, + + /** + * @const + * @type {number} + */ + DEFAULT_BUNGEE_LINE_WIDTH: 10, + + /** + * @const + * @type {number} + */ + DEFAULT_BUNGEE_WIDTH: 6, + + /** + * @const + * @type {number} + */ + CLICK_TO_CUT_SEARCH_RADIUS: 60, + + /** + * @const + * @type {number} + */ + MOVER_SCALE: 3, + + /** + * @const + * @type {number} + */ + STAR_RADIUS: 42, + + /** + * @const + * @type {number} + */ + MOUTH_OPEN_RADIUS: 200, + + /** + * @const + * @type {number} + */ + OUT_OF_SCREEN_ADJUSTMENT_BOTTOM: 400, + + /** + * @const + * @type {number} + */ + OUT_OF_SCREEN_ADJUSTMENT_TOP: -400, + + /** + * @const + * @type {Rectangle} + */ + STAR_DEFAULT_BB: new Rectangle(22, 20, 30, 30), + + /** + * @const + * @type {Rectangle} + */ + STAR_BB: new Rectangle(70, 64, 82, 82), + + /** + * @const + * @type {Rectangle} + */ + TARGET_BB: new Rectangle(264.0, 350.0, 108.0, 2.0), + + + // Prehistoric OmNom uses sprites which require a different bounding box + TARGET2_BB: new Rectangle(192, 278, 108, 2), + + /** + * @const + * @type {number} + */ + TUTORIAL_HAND_TARGET_X_1: 385, + /** + * @const + * @type {number} + */ + TUTORIAL_HAND_TARGET_X_2: 700, + + /** + * @const + * @type {number} + */ + BUBBLE_SIZE: 85, + /** + * @const + * @type {number} + */ + BUBBLE_RADIUS: 160, + /** + * @const + * @type {number} + */ + BUBBLE_TOUCH_OFFSET: 60, + /** + * @const + * @type {number} + */ + BUBBLE_TOUCH_SIZE: 200, + /** + * @const + * @type {Rectangle} + */ + BUBBLE_BB: new Rectangle(48, 48, 152, 152), + + /** + * @const + * @type {number} + */ + BUBBLE_IMPULSE_Y: -35, + /** + * @const + * @type {number} + */ + BUBBLE_IMPULSE_RD: 14, + /** + * @const + * @type {number} + */ + STAR_SPIKE_RADIUS: 15, + + /** + * @const + * @type {number} + */ + BOUNCER_RADIUS: 40, + + /** + * @const + * @type {number} + */ + PUMP_POWER_RADIUS: 624, + /** + * @const + * @type {Rectangle} + */ + PUMP_BB: new Rectangle(250, 250, 300, 300), + /** + * @const + * @type {number} + */ + PUMP_DIRT_SPEED: 2500, + /** + * @const + * @type {number} + */ + PUMP_DIRT_PARTICLE_SIZE: 15, + /** + * @const + * @type {number} + */ + PUMP_DIRT_OFFSET: 100, + + /** + * @const + * @type {number} + */ + CANDY_BUBBLE_TUTORIAL_LIMIT_Y: 300, + /** + * @const + * @type {number} + */ + CANDY_BUBBLE_TUTORIAL_LIMIT_X: 1400, + /** + * @const + * @type {Rectangle} + */ + CANDY_BB: new Rectangle(142, 157, 112, 104), + /** + * @const + * @type {Rectangle} + */ + CANDY_LR_BB: new Rectangle(155, 176, 88, 76), + + /** + * @const + * @type {number} + */ + GRAB_RADIUS_ALPHA: 1, + /** + * @const + * @type {number} + */ + GRAB_WHEEL_RADIUS: 110, + /** + * @const + * @type {number} + */ + GRAB_WHEEL_MAX_ROTATION: 5.625, + /** + * @const + * @type {number} + */ + GRAB_WHEEL_SCALE_DIVISOR: 1400, + /** + * @const + * @type {number} + */ + GRAB_ROPE_ROLL_MAX_LENGTH: 1650, + /** + * @const + * @type {number} + */ + GRAB_MOVE_BG_WIDTH: 142, + /** + * @const + * @type {number} + */ + GRAB_MOVE_BG_X_OFFSET: 74, + /** + * @const + * @type {number} + */ + GRAB_MOVE_RADIUS: 65, + /** + * @const + * @type {number} + */ + SPIDER_SPEED: 117, + /** + * @const + * @type {number} + */ + SOCK_LIGHT_Y: 270, + /** + * @const + * @type {number} + */ + SOCK_WIDTH: 140, + /** + * @const + * @type {number} + */ + SOCK_ROTATION_Y_OFFSET: 15, + /** + * @const + * @type {number} + */ + STAR_SOCK_RADIUS: 40, + /** + * @const + * @type {number} + */ + SOCK_TELEPORT_Y: -16, + + /** + * @const + * @type {number} + */ + POLLEN_MIN_DISTANCE: 44, + /** + * @const + * @type {number} + */ + POLLEN_MAX_OFFSET: 4, + + /** + * @const + * @type {number} + */ + RC_CONTROLLER_RADIUS: 90, + + /** + * @const + * @type {number} + */ + IGNORE_TOUCHES_DISTANCE: 100, + /** + * @const + * @type {number} + */ + PREVIEW_CAMERA_SPEED: 800, + /** + * @const + * @type {number} + */ + PREVIEW_CAMERA_SPEED2: 400, + /** + * @const + * @type {number} + */ + MAX_PREVIEW_CAMERA_SPEED: 1000, + /** + * @const + * @type {number} + */ + MIN_PREVIEW_CAMERA_SPEED: 300, + /** + * @const + * @type {number} + */ + CAMERA_SPEED_THRESHOLD: 5500, + /** + * @const + * @type {number} + */ + CAMERA_SPEED: 14, + /** + * @const + * @type {number} + */ + CUT_MAX_SIZE: 12, + /** + * @const + * @type {number} + */ + PHYSICS_SPEED_MULTIPLIER: 1.4 + }; + + return res2560x1440; + } +); +define('config/resolutions/scale', + [ 'core/Rectangle', 'config/resolutions/2560x1440'], + function (Rectangle, res2560x1440) { + + /** + * Initializes the target device profile using a base profile. A set of properties + * will be scaled (based on the difference between the base and target resolutions) + * and then added to the target. + * @param base + * @param target + */ + function initProfile(base, target) { + var scale = target.CANVAS_SCALE; + + target.BUNGEE_REST_LEN = base.BUNGEE_REST_LEN * scale; + target.MOVER_SCALE = base.MOVER_SCALE * scale; + target.STAR_RADIUS = base.STAR_RADIUS * scale; + target.MOUTH_OPEN_RADIUS = base.MOUTH_OPEN_RADIUS * scale; + target.OUT_OF_SCREEN_ADJUSTMENT_TOP = base.OUT_OF_SCREEN_ADJUSTMENT_TOP * scale; + target.OUT_OF_SCREEN_ADJUSTMENT_BOTTOM = base.OUT_OF_SCREEN_ADJUSTMENT_BOTTOM * scale; + target.CLICK_TO_CUT_SEARCH_RADIUS = base.CLICK_TO_CUT_SEARCH_RADIUS * scale; + + target.TARGET_BB = Rectangle.scaleCopy(base.TARGET_BB, scale); + target.TARGET2_BB = Rectangle.scaleCopy(base.TARGET2_BB, scale); + + target.TUTORIAL_HAND_TARGET_X_1 = base.TUTORIAL_HAND_TARGET_X_1 * scale; + target.TUTORIAL_HAND_TARGET_X_2 = base.TUTORIAL_HAND_TARGET_X_2 * scale; + + target.BUBBLE_SIZE = base.BUBBLE_SIZE * scale; + target.BUBBLE_TOUCH_OFFSET = base.BUBBLE_TOUCH_OFFSET * scale; + target.BUBBLE_TOUCH_SIZE = base.BUBBLE_TOUCH_SIZE * scale; + target.BUBBLE_BB = Rectangle.scaleCopy(base.BUBBLE_BB, scale); + target.BUBBLE_RADIUS = base.BUBBLE_RADIUS * scale; + + target.STAR_SPIKE_RADIUS = base.STAR_SPIKE_RADIUS * scale; + target.STAR_BB = Rectangle.scaleCopy(base.STAR_BB, scale); + target.STAR_DEFAULT_BB = Rectangle.scaleCopy(base.STAR_DEFAULT_BB, scale); + + target.BOUNCER_RADIUS = base.BOUNCER_RADIUS * scale; + + target.PUMP_POWER_RADIUS = target.PUMP_POWER_RADIUS || (base.PUMP_POWER_RADIUS * scale); + target.PUMP_BB = Rectangle.scaleCopy(base.PUMP_BB, scale); + target.PUMP_DIRT_SPEED = base.PUMP_DIRT_SPEED * scale; + target.PUMP_DIRT_PARTICLE_SIZE = base.PUMP_DIRT_PARTICLE_SIZE * scale; + target.PUMP_DIRT_OFFSET = base.PUMP_DIRT_OFFSET * scale; + + target.CANDY_BB = Rectangle.scaleCopy(base.CANDY_BB, scale); + target.CANDY_LR_BB = Rectangle.scaleCopy(base.CANDY_LR_BB, scale); + target.CANDY_BUBBLE_TUTORIAL_LIMIT_Y = base.CANDY_BUBBLE_TUTORIAL_LIMIT_Y * scale; + target.CANDY_BUBBLE_TUTORIAL_LIMIT_X = base.CANDY_BUBBLE_TUTORIAL_LIMIT_X * scale; + + target.IGNORE_TOUCHES_DISTANCE = base.IGNORE_TOUCHES_DISTANCE * scale; + target.PREVIEW_CAMERA_SPEED = base.PREVIEW_CAMERA_SPEED * scale; + target.PREVIEW_CAMERA_SPEED2 = base.PREVIEW_CAMERA_SPEED2 * scale; + target.MAX_PREVIEW_CAMERA_SPEED = base.MAX_PREVIEW_CAMERA_SPEED * scale; + target.MIN_PREVIEW_CAMERA_SPEED = base.MIN_PREVIEW_CAMERA_SPEED * scale; + target.CAMERA_SPEED_THRESHOLD = base.CAMERA_SPEED_THRESHOLD * scale; + target.CAMERA_SPEED = base.CAMERA_SPEED * scale; + + target.GRAB_WHEEL_MAX_ROTATION = base.GRAB_WHEEL_MAX_ROTATION * scale; + target.GRAB_WHEEL_SCALE_DIVISOR = base.GRAB_WHEEL_SCALE_DIVISOR * scale; + target.GRAB_WHEEL_RADIUS = base.GRAB_WHEEL_RADIUS * scale; + target.GRAB_ROPE_ROLL_MAX_LENGTH = base.GRAB_ROPE_ROLL_MAX_LENGTH * scale; + target.GRAB_MOVE_BG_WIDTH = base.GRAB_MOVE_BG_WIDTH * scale; + target.GRAB_MOVE_BG_X_OFFSET = base.GRAB_MOVE_BG_X_OFFSET * scale; + target.GRAB_MOVE_RADIUS = base.GRAB_MOVE_RADIUS * scale; + target.SPIDER_SPEED = base.SPIDER_SPEED * scale; + + target.POLLEN_MIN_DISTANCE = base.POLLEN_MIN_DISTANCE * scale; + target.POLLEN_MAX_OFFSET = base.POLLEN_MAX_OFFSET * scale; + + target.RC_CONTROLLER_RADIUS = base.RC_CONTROLLER_RADIUS * scale; + + target.SOCK_LIGHT_Y = base.SOCK_LIGHT_Y * scale; + target.SOCK_WIDTH = base.SOCK_WIDTH * scale; + target.SOCK_ROTATION_Y_OFFSET = base.SOCK_ROTATION_Y_OFFSET * scale; + target.STAR_SOCK_RADIUS = base.STAR_SOCK_RADIUS * scale; + target.SOCK_TELEPORT_Y = base.SOCK_TELEPORT_Y * scale; + + target.CUT_MAX_SIZE = base.CUT_MAX_SIZE * scale; + + target.uiScaledNumber = function (n) { + return Math.round(n * target.UI_IMAGES_SCALE); + }; + } + + /** + * Initializes a target profile scaled from the mac version profile + */ + function initProfileFromMac(target) { + initProfile(res2560x1440, target); + } + + return initProfileFromMac; + } +); + + +define('config/resolutions/480x270', + [], + function () { + var res480x270 = { + + /** + * @const + * @type {number} + */ + VIDEO_WIDTH: 768, + + /** + * @const + * @type {number} + */ + CANVAS_WIDTH: 480, + /** + * @const + * @type {number} + */ + CANVAS_HEIGHT: 320, + /** + * @const + * @type {number} + */ + CANVAS_SCALE: 0.1875, + + /** + * @const + * @type {number} + */ + UI_IMAGES_SCALE: 0.46875, + /** + * @const + * @type {number} + */ + UI_TEXT_SCALE: 1, + /** + * @const + * @type {number} + */ + UI_WIDTH: 480, + /** + * @const + * @type {number} + */ + UI_HEIGHT: 320, + + /** + * @const + * @type {number} + */ + BUNGEE_BEZIER_POINTS: 2, + + /** + * @const + * @type {number} + */ + DEFAULT_BUNGEE_LINE_WIDTH: 2, + + /** + * @const + * @type {number} + */ + DEFAULT_BUNGEE_WIDTH: 2, + + /** + * Platform multiplier (maps the height of the level to the height of the canvas). + * Map height is 480 and canvas height is 576. + * @const + * @type {number} + */ + PM: 0.5625, + + /** + * Adjusts the y offset for the level + * @const + * @type {number} + */ + PMY: 0, + + /** + * @const + * @type {number} + */ + GRAB_RADIUS_ALPHA: 0.8, + + /** + * Controls ascent speed of bubble + * @const + * @type {number} + */ + BUBBLE_IMPULSE_Y: -9, + /** + * Controls descent speed of bubble + * @const + * @type {number} + */ + BUBBLE_IMPULSE_RD: 22, + + /** + * @const + * @type {number} + */ + BOUNCER_MAX_MOVEMENT: 158, + + /** + * @const + * @type {number} + */ + PHYSICS_SPEED_MULTIPLIER: 0.65 + }; + + window.resolution = res480x270; + + return res480x270; + } +); + +define('config/resolutions/768x432', + [], + function () { + + var res768x432 = { + /** + * @const + * @type {number} + */ + VIDEO_WIDTH: 768, + + /** + * @const + * @type {number} + */ + CANVAS_WIDTH: 768, + /** + * @const + * @type {number} + */ + CANVAS_HEIGHT: 432, + /** + * @const + * @type {number} + */ + CANVAS_SCALE: 0.3, + + /** + * @const + * @type {number} + */ + UI_IMAGES_SCALE: .75, + /** + * @const + * @type {number} + */ + UI_TEXT_SCALE: 1, + /** + * @const + * @type {number} + */ + UI_WIDTH: 768, + /** + * @const + * @type {number} + */ + UI_HEIGHT: 432, + + /** + * @const + * @type {number} + */ + BUNGEE_BEZIER_POINTS: 2, + + /** + * @const + * @type {number} + */ + DEFAULT_BUNGEE_LINE_WIDTH: 3, + + /** + * @const + * @type {number} + */ + DEFAULT_BUNGEE_WIDTH: 2, + + /** + * Platform multiplier (maps the height of the level to the height of the canvas). + * Map height is 480 and canvas height is 432. + * @const + * @type {number} + */ + PM: 0.9, + + /** + * Adjusts the y offset for the level + * @const + * @type {number} + */ + PMY: 0, + + /** + * @const + * @type {number} + */ + GRAB_RADIUS_ALPHA: 0.8, + + /** + * Controls ascent speed of bubble + * @const + * @type {number} + */ + BUBBLE_IMPULSE_Y: -14, + /** + * Controls descent speed of bubble + * @const + * @type {number} + */ + BUBBLE_IMPULSE_RD: 24, + + /** + * @const + * @type {number} + */ + BOUNCER_MAX_MOVEMENT: 255, + + /** + * @const + * @type {number} + */ + PHYSICS_SPEED_MULTIPLIER: 0.80 + }; + + return res768x432; + } +); +define('resolution', + [ + "game/CTRSettings", + "config/resolutions/scale", + "config/resolutions/480x270", + "config/resolutions/768x432" + ], + function (settings, scaleResolution, res480, res768) { + + // decide which resolution to target + var $w = $(window), + resolution; + + // Use 480px (for testing in desktop browser) + resolution = res480; + + scaleResolution(resolution); + resolution.isHD = false; + + return resolution; + } +); + +define('utils/Log', + [], + function () { + var Log = { + debug: function (message) { + if (false && window.console) { + console.log(message); + } + }, + alert: function(message) { + if (false) { + alert(message); + Log.debug(message); + } + } + }; + + return Log; + } +); +define('visual/ImageElement', + [ + 'visual/BaseElement', + 'core/Rectangle', + 'resources/ResData', + 'utils/Canvas', + 'utils/Constants', + 'core/Vector', + 'visual/ActionType', + 'utils/Log' + ], + function (BaseElement, Rectangle, RES_DATA, Canvas, Constants, Vector, ActionType, Log) { + + // Note: This class is named Image in the iOS sources but we'll use + // ImageElement to avoid conflicts with the native JS Image class. + + /** + * Texture container with the ability to calculate and draw quads + */ + var ImageElement = BaseElement.extend({ + init: function () { + this._super(); + }, + /** + * Set the texture for this image element + * @param texture {Texture2D} + */ + initTexture: function (texture) { + this.texture = texture; + this.restoreCutTransparency = false; + + if (this.texture.rects.length > 0) + this.setTextureQuad(0); + else + this.setDrawFullImage(); + }, + getTexture: function (resId) { + // using the resMgr would create a circular dependency, + // so we'll assume its been loaded and fetch directly + var texture = RES_DATA[resId].texture; + if (!texture) { + Log.debug('Image not loaded: ' + RES_DATA[resId].path) + } + return texture; + }, + initTextureWithId: function (resId) { + this.resId = resId; + this.initTexture(this.getTexture(resId)); + }, + setTextureQuad: function (n) { + this.quadToDraw = n; + + // don't set width / height to quad size if we cut transparency from each quad + if (!this.restoreCutTransparency) { + var rect = this.texture.rects[n]; + this.width = rect.w; + this.height = rect.h; + } + }, + setDrawFullImage: function () { + this.quadToDraw = Constants.UNDEFINED; + this.width = this.texture.imageWidth; + this.height = this.texture.imageHeight; + }, + doRestoreCutTransparency: function () { + if (this.texture.preCutSize.x !== Vector.undefined.x) { + this.restoreCutTransparency = true; + this.width = this.texture.preCutSize.x; + this.height = this.texture.preCutSize.y; + } + }, + draw: function () { + this.preDraw(); + + // only draw if the image is non-transparent + if (this.color.a !== 0 && this.texture) { + if (this.quadToDraw === Constants.UNDEFINED) { + var qx = this.drawX, + qy = this.drawY; + + Canvas.context.drawImage(this.texture.image, qx, qy); + } + else { + this.drawQuad(this.quadToDraw); + } + } + + this.postDraw(); + }, + drawQuad: function (n) { + var rect = this.texture.rects[n], + quadWidth = rect.w, + quadHeight = rect.h, + qx = this.drawX, + qy = this.drawY; + + + if (this.restoreCutTransparency) { + var offset = this.texture.offsets[n]; + if (offset) { + qx += offset.x; + qy += offset.y; + + // the sprites are generated with rounded offsets, so we + // need to pad the width and height if there is an offset + quadWidth += this.texture.adjustmentMaxX; + quadHeight += this.texture.adjustmentMaxY; + } + } + + // if (this.drawSizeIncrement) { + // // we need sub-pixel size + // quadWidth = ~~(quadWidth / this.drawSizeIncrement) * this.drawSizeIncrement; + // quadHeight = ~~(quadHeight / this.drawSizeIncrement) * this.drawSizeIncrement; + // } + // else { + // otherwise by default we snap to pixel boundaries for perf + quadWidth = 1 + quadWidth | 0; + quadHeight = 1 + quadHeight | 0; + //} + + // if (this.drawPosIncrement) { + // console.log(this.drawPosIncrement, "WAT") + // // we need sub-pixel alignment + // qx = ~~(qx / this.drawPosIncrement) * this.drawPosIncrement; + // qy = ~~(qy / this.drawPosIncrement) * this.drawPosIncrement; + // } + //else { + // otherwise by default we snap to pixel boundaries for perf + qx = qx | 0; + qy = qy | 0; + //} + + Canvas.context.drawImage( + this.texture.image, + rect.x, rect.y, quadWidth, quadHeight, // source coordinates + qx, qy, quadWidth, quadHeight); // destination coordinates + }, + drawTiled: function (q, x, y, width, height) { + + var ctx = Canvas.context, + qx = 0, + qy = 0, + qw, qh, rect, yoff, xoff, wd, hg; + + if (q === Constants.UNDEFINED) { + qw = this.texture.imageWidth; + qh = this.texture.imageHeight; + } + else { + rect = this.texture.rects[q]; + qx = rect.x; + qy = rect.y; + qw = rect.w; + qh = rect.h; + } + + var xInc = qw | 0, + yInc = qh | 0, + ceilW, ceilH; + + yoff = 0; + while (yoff < height) { + xoff = 0; + while (xoff < width) { + wd = width - xoff; + if (wd > qw) { + wd = qw; + } + ceilW = Math.ceil(wd); + + hg = height - yoff; + if (hg > qh) { + hg = qh; + } + ceilH = Math.ceil(hg); + + ctx.drawImage(this.texture.image, + qx | 0, qy | 0, ceilW, ceilH, // source coordinates + x + xoff | 0, y + yoff | 0, ceilW, ceilH); // dest coordinates + + xoff += xInc; + } + + yoff += yInc; + } + }, + /** + * Returns true if the point is inside the boundaries of the current quad + * @param x + * @param y + */ + pointInDrawQuad: function (x, y) { + if (this.quadToDraw === Constants.UNDEFINED) { + return Rectangle.pointInRect( + x, y, + this.drawX, this.drawY, + this.texture.width, this.texture.height); + } + else { + var rect = this.texture.rects[this.quadToDraw], + qx = this.drawX, + qy = this.drawY; + + if (this.restoreCutTransparency) { + var offset = this.texture.offsets[this.quadToDraw]; + qx += offset.x; + qy += offset.y; + } + + return Rectangle.pointInRect(x, y, qx, qy, rect.w, rect.h); + } + }, + /** + * Returns true if the action was handled + * @param actionData {ActionData} + * @return {boolean} + */ + handleAction: function (actionData) { + if (this._super(actionData)) { + return true; + } + + if (actionData.actionName === ActionType.SET_DRAWQUAD) { + this.setTextureQuad(actionData.actionParam); + } + else { + return false; + } + + return true; + }, + setElementPositionWithOffset: function (resId, index) { + var texture = this.getTexture(resId), + offset = texture.offsets[index]; + this.x = offset.x; + this.y = offset.y; + }, + setElementPositionWithCenter: function (resId, index) { + var texture = this.getTexture(resId), + rect = texture.rects[index], + offset = texture.offsets[index]; + this.x = offset.x + (rect.w / 2); + this.y = offset.y + (rect.h / 2); + } + }); + + ImageElement.create = function (resId, drawQuad) { + var image = new ImageElement(); + image.initTextureWithId(resId); + + if (drawQuad != null) + image.setTextureQuad(drawQuad); + + return image; + }; + + return ImageElement; + } +); + +define('visual/Font', + [ + 'visual/ImageElement', + 'utils/Canvas', + 'utils/Constants', + 'utils/Log' + ], + function (ImageElement, Canvas, Constants, Log) { + var Font = ImageElement.extend({ + init: function () { + this._super(); + + this.chars = ''; + this.charOffset = 0; + this.lineOffset = 0; + this.spaceWidth = 0; + this.kerning = null; + }, + initWithVariableSizeChars: function (chars, charTexture, kerningDictionary) { + this.chars = chars; + this.initTexture(charTexture); + this.kerning = kerningDictionary; + }, + setOffsets: function (charOffset, lineOffset, spaceWidth) { + this.charOffset = charOffset; + this.lineOffset = lineOffset; + this.spaceWidth = spaceWidth; + }, + getCharQuad: function (c) { + var charIndex = this.chars.indexOf(c); + if (charIndex >= 0) { + return charIndex; + } + + Log.alert('Char not found in font:' + c); + + // replace missing character with a period + return this.chars.indexOf('.'); + }, + drawQuadWOBind: function (index, x, y) { + var rect = this.texture.rects[index], + quadWidth = Math.ceil(rect.w), + quadHeight = Math.ceil(rect.h); + + Canvas.context.drawImage( + this.texture.image, + rect.x | 0, rect.y | 0, quadWidth, quadHeight, // source coordinates + x | 0, y | 0, quadWidth, quadHeight); // destination coordinates + }, + stringWidth: function (str) { + var strWidth = 0, + len = str.length, + lastOffset = 0; + for (var c = 0; c < len; c++) { + lastOffset = this.getCharOffset(str, c); + + if (str[c] === ' ') { + strWidth += this.spaceWidth + lastOffset; + } + else { + var quadIndex = this.getCharQuad(str[c]), + itemWidth = this.texture.rects[quadIndex].w; + strWidth += itemWidth + lastOffset; + } + } + strWidth -= lastOffset; + return Math.ceil(strWidth); + }, + fontHeight: function () { + return this.texture.rects[0].h; + }, + getCharOffset: function (str, charIndex) { + // no offset if its the last character + if (charIndex === str.length - 1) { + return 0; + } + + // use the default offset if no kerning is defined + if (!this.kerning) { + return this.charOffset; + } + + // see if kerning is specified for char pair or use the default offset + var chars = str[charIndex] + str[charIndex + 1], + v = this.kerning[chars]; + if (v != null) { + return v; + } + else { + return this.charOffset; + } + } + }); + + return Font; + } +); +define('core/Quad2D', + [], + function () { + /** + * Quad2D constructor + * @constructor + * @param x {number} + * @param y {number} + * @param w {number} width + * @param h {number} height + */ + function Quad2D(x, y, w, h) { + var rightX = x + w, + bottomY = y + h; + + // top left + this.tlX = x; + this.tlY = y; + + // top right + this.trX = rightX; + this.trY = y; + + // bottom left + this.blX = x; + this.blY = bottomY; + + // bottom right + this.brX = rightX; + this.brY = bottomY; + } + + return Quad2D; + } +); + +define('core/Texture2D', + ['core/Vector', 'core/Quad2D'], + function (Vector, Quad2D) { + + var Texture2D = function (image) { + this.image = image; + this.rects = []; + this.offsets = []; + this.preCutSize = Vector.newUndefined(); + + // use jquery to work around intermittent dimension issues with images + var $img = $(image); + this.imageWidth = image.width || $img.width(); + this.imageHeight = image.height || $img.height(); + this._invWidth = 1 / this.imageWidth; + this._invHeight = 1 / this.imageHeight; + + // sometimes we need to adjust offsets to pixel align + this.adjustmentMaxX = 0; + this.adjustmentMaxY = 0; + }; + + Texture2D.prototype.addRect = function (rect) { + this.rects.push(rect); + this.offsets.push(new Vector(0, 0)); + }; + + Texture2D.prototype.setOffset = function (index, x, y) { + var offset = this.offsets[index]; + offset.x = x; + offset.y = y; + }; + + Texture2D.prototype.getCoordinates = function (rect) { + return new Quad2D( + this._invWidth * rect.x, + this._invHeight * rect.y, + this._invWidth * rect.w, + this._invHeight * rect.h); + }; + + return Texture2D; + } +); + + +define('resources/ResourceMgr', + [ + 'ResInfo', + 'resources/ResData', + 'resources/ResScale', + 'resources/ResourceType', + 'resolution', + 'visual/Font', + 'core/Texture2D', + 'core/Vector', + 'core/Rectangle', + 'utils/Log' + ], + function (ResInfo, RES_DATA, ResScaler, ResourceType, resolution, Font, Texture2D, Vector, Rectangle, Log) { + + var ResourceMgr = { + init: function () { + // merge info into resource entries + var infos = ResInfo; + ResScaler.scaleResourceInfos(infos, resolution.CANVAS_SCALE); + for (var i = 0, len = infos.length; i < len; i++) { + var info = infos[i]; + delete info.originalRects; + delete info.offsetAdjustments; + + RES_DATA[info.id].info = info; + } + }, + onResourceLoaded: function (resId, img) { + // we store the resource id in the custom id + var resource = RES_DATA[resId]; + switch (resource.type) { + case ResourceType.IMAGE: + resource.texture = new Texture2D(img); + this.setQuads(resource); + break; + case ResourceType.FONT: + resource.texture = new Texture2D(img); + this.setQuads(resource); + var font = new Font(), + info = resource.info; + font.initWithVariableSizeChars( + info.chars, + resource.texture, + info.kerning); + font.setOffsets( + info.charOffset, + info.lineOffset, + info.spaceWidth); + resource.font = font; + break; + } + }, + /** + * Sets texture quads from xml info + * @param resource {ResEntry} + */ + setQuads: function (resource) { + var t = resource.texture, + imageWidth = t.imageWidth, + imageHeight = t.imageHeight, + info = resource.info, + rects = info.rects, + offsets = info.offsets; + + t.preCutSize = Vector.newUndefined(); + + if (!rects) { + return; + } + + // we need to make sure our scaled quad doesn't slightly + // exceed the dimensions of the image. we pad images with + // offsets with 1 extra pixel because offsets are pixel aligned + // so they might need to go slightly beyond the dimensions + // specified in the rect + t.adjustmentMaxX = info.adjustmentMaxX ? info.adjustmentMaxX : 0; + t.adjustmentMaxY = info.adjustmentMaxY ? info.adjustmentMaxY : 0; + + for (var i = 0, len = rects.length; i < len; i++) { + // convert it to a Rectangle object + var rawRect = rects[i], + rect = new Rectangle(rawRect.x, rawRect.y, rawRect.w, rawRect.h); + + if (rect.w + t.adjustmentMaxX > imageWidth) { + rect.w = imageWidth - t.adjustmentMaxX; + } + if (rect.h + t.adjustmentMaxY > imageHeight) { + rect.h = imageHeight - t.adjustmentMaxY; + } + + t.addRect(rect); + } + + if (offsets) { + // set the offsets inside the texture + var oCount = offsets.length; + for (i = 0; i < oCount; i++) { + var offset = offsets[i]; + t.setOffset(i, offset.x, offset.y); + } + } + + // see if there is a pre-cut size specified + if (info.preCutWidth && info.preCutHeight) { + t.preCutSize.x = info.preCutWidth; + t.preCutSize.y = info.preCutHeight; + } + }, + getTexture: function (resId) { + var resEntry = RES_DATA[resId]; + if (resEntry.texture) { + return resEntry.texture; + } + + Log.debug('Image not yet loaded:' + resEntry.path); + return null; + }, + getFont: function (resId) { + var resEntry = RES_DATA[resId]; + if (resEntry.font) { + return resEntry.font; + } + + Log.debug('Font not yet loaded:' + resEntry.path); + return null; + } + }; + + return ResourceMgr; + } +); +define('utils/MathHelper', + [ + 'utils/Constants' + ], + function (Constants) { + var MathHelper = { + /** + * Fits value v to [minV, maxV] + * @param v {number} value + * @param minV {number} + * @param maxV {number} + * @return {number} + */ + fitToBoundaries: function (v, minV, maxV) { + return Math.max(Math.min(v, maxV), minV); + }, + /** + * Returns true if values have the same sign + * @param x {number} + * @param y {number} + * @return {boolean} + */ + sameSign: function (x, y) { + return ((x < 0) === ( y < 0)); + }, + /** + * Returns a random integer from the interval + * @param from {number} + * @param to {number} + */ + randomRange: function (from, to) { + return ~~(Math.random() * (to - from + 1) + from); + }, + randomBool: function () { + return (Math.random() > 0.5); + }, + randomMinus1to1: function () { + return Math.random() * 2 - 1; + }, + /** + * Returns the max of 4 numbers + * @param v1 {number} + * @param v2 {number} + * @param v3 {number} + * @param v4 {number} + * @return {number} + */ + maxOf4: function (v1, v2, v3, v4) { + if (v1 >= v2 && v1 >= v3 && v1 >= v4) return v1; + if (v2 >= v1 && v2 >= v3 && v2 >= v4) return v2; + if (v3 >= v2 && v3 >= v1 && v3 >= v4) return v3; + if (v4 >= v2 && v4 >= v3 && v4 >= v1) return v4; + + return Constants.UNDEFINED; + }, + /** + * Returns the minimum of 4 numbers + * @param v1 {number} + * @param v2 {number} + * @param v3 {number} + * @param v4 {number} + * @return {number} + */ + minOf4: function (v1, v2, v3, v4) { + if (v1 <= v2 && v1 <= v3 && v1 <= v4) return v1; + if (v2 <= v1 && v2 <= v3 && v2 <= v4) return v2; + if (v3 <= v2 && v3 <= v1 && v3 <= v4) return v3; + if (v4 <= v2 && v4 <= v3 && v4 <= v1) return v4; + + return Constants.UNDEFINED; + }, + /** + * @param x1 {number} + * @param y1 {number} + * @param x2 {number} + * @param y2 {number} + * @param x3 {number} + * @param y3 {number} + * @param x4 {number} + * @param y4 {number} + * @return {boolean} + */ + lineInLine: function (x1, y1, x2, y2, x3, y3, x4, y4) { + + var DPx, DPy, + QAx, QAy, + QBx, QBy, + d, la, lb; + + DPx = x3 - x1 + x4 - x2; + DPy = y3 - y1 + y4 - y2; + QAx = x2 - x1; + QAy = y2 - y1; + QBx = x4 - x3; + QBy = y4 - y3; + + d = QAy * QBx - QBy * QAx; + la = QBx * DPy - QBy * DPx; + lb = QAx * DPy - QAy * DPx; + + var absD = Math.abs(d); + return (Math.abs(la) <= absD && Math.abs(lb) <= absD); + }, + + // round to arbitrary precision + roundPrecision: function (value, precision) { + var scalar = Math.pow(10, precision); + return Math.round(value * scalar) / scalar; + }, + + // round to 2 decimals of precision + roundP2: function (value) { + return Math.round(value * 100) / 100; + } + + }; + + return MathHelper; + } +); + + +define('visual/Text', + [ + 'visual/BaseElement', + 'utils/Constants', + 'core/Alignment', + 'visual/ImageMultiDrawer', + 'utils/Canvas', + 'resources/ResourceId', + 'resources/ResourceMgr', + 'resolution', + 'utils/MathHelper', + 'game/CTRSettings' + ], + function (BaseElement, Constants, Alignment, ImageMultiDrawer, Canvas, ResourceId, ResourceMgr, resolution, MathHelper, settings) { + //settings.getLangId() + function FormattedString(str, width) { + this.string = str; + this.width = width; + } + + Text = BaseElement.extend({ + init: function (font) { + this._super(); + this.font = font; + this.formattedStrings = []; + this.width = Constants.UNDEFINED; + this.height = Constants.UNDEFINED; + this.align = Alignment.LEFT; + this.d = new ImageMultiDrawer(font.texture); + this.wrapLongWords = false; + this.maxHeight = Constants.UNDEFINED; + }, + setString: function (newString, width) { + this.string = newString; + if (width == null || width === Constants.UNDEFINED) { + this.wrapWidth = Math.ceil(this.font.stringWidth(newString)); + } + else { + this.wrapWidth = Math.ceil(width); + } + + if (this.string) { + this.formatText(); + this.updateDrawerValues(); + } + }, + updateDrawerValues: function () { + var dx = 0, dy = 0, + itemHeight = this.font.fontHeight(), + n = 0, + dotsString = '..', + dotsOffset = this.font.getCharOffset(dotsString, 0), + linesToDraw = (this.maxHeight === Constants.UNDEFINED) + ? this.formattedStrings.length + : Math.min(this.formattedStrings.length, this.maxHeight / itemHeight + this.font.lineOffset), + drawEllipsis = (linesToDraw !== this.formattedStrings.length); + + for (var i = 0; i < linesToDraw; i++) { + var fs = this.formattedStrings[i], + s = fs.string, + len = s.length; + + if (this.align !== Alignment.LEFT) { + if (this.align === Alignment.HCENTER || this.align === Alignment.CENTER) { + dx = (this.wrapWidth - fs.width) / 2; + } + else { + dx = this.wrapWidth - fs.width; + } + } + else { + dx = 0; + } + + for (var c = 0; c < len; c++) { + if (s[c] === ' ') { + dx += this.font.spaceWidth + this.font.getCharOffset(s, c); + } + else { + var quadIndex = this.font.getCharQuad(s[c]), + itemWidth = this.font.texture.rects[quadIndex].w; + this.d.mapTextureQuad(quadIndex, Math.round(dx), Math.round(dy), n++); + dx += itemWidth + this.font.getCharOffset(s, c); + } + + if (drawEllipsis && i === (linesToDraw - 1)) { + var dotIndex = this.font.getCharQuad('.'); + var dotWidth = this.font.texture.rects[dotIndex].w; + if ((c === len - 1) || + (c === len - 2 && dx + 3 * (dotWidth + dotsOffset) + this.font.spaceWidth > this.wrapWidth)) { + this.d.mapTextureQuad(dotIndex, Math.round(dx), Math.round(dy), n++); + dx += dotWidth + dotsOffset; + this.d.mapTextureQuad(dotIndex, Math.round(dx), Math.round(dy), n++); + dx += dotWidth + dotsOffset; + this.d.mapTextureQuad(dotIndex, Math.round(dx), Math.round(dy), n++); + dx += dotWidth + dotsOffset; + break; + } + } + } + dy += itemHeight + this.font.lineOffset; + } + + if (this.formattedStrings.length <= 1) { + this.height = this.font.fontHeight(); + this.width = dx; + } + else { + this.height = (this.font.fontHeight() + this.font.lineOffset) * + this.formattedStrings.length - this.font.lineOffset; + this.width = this.wrapWidth; + } + + if (this.maxHeight !== Constants.UNDEFINED) { + this.height = Math.min(this.height, this.maxHeight); + } + }, + draw: function () { + this.preDraw(); + + // only draw if the image is non-transparent + if (this.color.a !== 0) { + var len = this.string.length, + ctx = Canvas.context; + if (len > 0) { + ctx.translate(this.drawX, this.drawY); + this.d.drawNumberOfQuads(len); + ctx.translate(-this.drawX, -this.drawY); + } + } + + this.postDraw(); + }, + formatText: function () { + var strIdx = [], + s = this.string, + len = s.length, + idx = 0, + xc = 0, + wc = 0, + xp = 0, + xpe = 0, + wp = 0, + dx = 0; + + while (dx < len) { + var c = s[dx++]; + + if (c == ' ' || c == '\n') { + wp += wc; + xpe = dx - 1; + wc = 0; + xc = dx; + + if (c == ' ') { + xc--; + wc = this.font.spaceWidth + this.font.getCharOffset(s, dx - 1); + } + } + else { + var quadIndex = this.font.getCharQuad(c), + charWidth = this.font.texture.rects[quadIndex].w; + wc += charWidth + this.font.getCharOffset(s, dx - 1); + } + + var tooLong = MathHelper.roundP2(wp + wc) > this.wrapWidth; + + if (this.wrapLongWords && tooLong && xpe == xp) { + wp += wc; + xpe = dx; + wc = 0; + xc = dx; + } + + if (MathHelper.roundP2(wp + wc) > this.wrapWidth && xpe != xp || c == '\n') { + strIdx[idx++] = xp; + strIdx[idx++] = xpe; + while (xc < len && s[xc] == ' ') { + xc++; + wc -= this.font.spaceWidth; + } + + xp = xc; + xpe = xp; + wp = 0; + } + } + + if (wc != 0) { + strIdx[idx++] = xp; + strIdx[idx++] = dx; + } + + var strCount = idx >> 1; + + this.formattedStrings = []; + for (var i = 0; i < strCount; i++) { + var start = strIdx[i << 1], + end = strIdx[(i << 1) + 1], + str = this.string.substring(start, end), + wd = this.font.stringWidth(str), + fs = new FormattedString(str, wd); + this.formattedStrings.push(fs); + } + }, + createFromXml: function (xml) { + var resId = Xml.attrInt(xml, "font"), + font = ResourceMgr.getFont(resId), + element = new Text(font); + + if (xml.hasAttribute("align")) { + element.align = Alignment.parse(Xml.attr(xml, "align")); + } + + if (xml.hasAttribute("string")) { + var strId = Xml.attrInt("string"), + str = ResourceMgr.getString(strId), + strWidth = xml.hasAttribute("width") ? Xml.attrFloat(xml, "width") : Constants.UNDEFINED; + + element.setString(str, strWidth); + } + + if (xml.hasAttribute("height")) { + element.maxHeight = Xml.attrFloat(xml, "height"); + } + + return element; + } + }); + + function stringToArray (ctx, string, width) { + // convert string to array of lines then words + var input = string.split("\n"); + for (var i = 0; i < input.length; ++i) { + input[i] = input[i].split(" "); + } + + var i = 0, j = 0, output = []; + var runningWidth = 0; + var line = 0; + + while (i < input.length) { + while (j < input[i].length) { + if (!output[line]) { output[line] = ""; } + + var text = input[i][j] + " "; + var w = ctx.measureText(text).width; + + // overflow to a newline + if (runningWidth + w > width && runningWidth > 0) { + line++; + runningWidth = 0; + } else { + output[line] += text; + j++; + runningWidth += w; + } + } + + output[line] = output[line].trim(); + i++; + line++; + j = 0; + runningWidth = 0; + } + + return output; + } + + function setupFont (ctx, options) { + var color = options.fontId === 5 ? "#000" : "#fff"; + if (options.alignment !== 1) { + ctx.textAlign = 'center'; + } + + ctx.fillStyle = color; + ctx.font = "normal 100 18px 'gooddognew', sans-serif"; + + if (options.fontId === 4) { + ctx.strokeStyle = 'rgba(0,0,0,0.7)'; + ctx.lineWidth = 3; + } + + if (options.alpha) { + ctx.globalAlpha = options.alpha; + } + } + + Text.drawSystem = function (options) { + var lineHeight = 22; + var cnv = options.canvas ? options.img : document.createElement("canvas"); + cnv.width = options.width || options.maxScaleWidth || options.text.length * 16; + cnv.height = lineHeight; + + var ctx = cnv.getContext("2d"); + var x = cnv.width / 2; + + if (options.alignment === 1) { + x = 0; + } + + setupFont(ctx, options); + + // detect overflow by measuring or newline character + var metric = ctx.measureText(options.text); + if (options.text.indexOf("\n") > 0 || (options.width && metric.width > options.width)) { + var text = stringToArray(ctx, options.text, options.width); + cnv.height = lineHeight * text.length + 5; + + setupFont(ctx, options); + + for (var i = 0; i < text.length; ++i) { + + if (options.fontId === 4) { + ctx.strokeText(text[i], x, (i + 1) * lineHeight) + } + ctx.fillText(text[i], x, (i + 1) * lineHeight); + } + } else { + // use the measured width + if (!options.width || !options.maxScaleWidth) { + cnv.width = metric.width + 5; + setupFont(ctx, options); + if (options.alignment !== 1) x = cnv.width / 2; + } + if (options.fontId === 4) { + ctx.strokeText(options.text, x, 15); + } + ctx.fillText(options.text, x, 15); + } + + if (!options.canvas) { + options.img.src = cnv.toDataURL('image/png'); + options.img.style.paddingTop = "4px"; + + } + + options.img.style.height = "auto"; + options.img.style.width = "auto"; + + return options.img; + } + + Text.drawImg = function (options) { + + // get or create the image element + var img = options.img; + if (!img && options.imgId) { + img = document.getElementById(options.imgId); + } + if (!img && options.imgSel) { + img = $(options.imgSel)[0]; + } + if (!img && options.imgParentId) { + // obbtains img child or prepends new Image if necessary + var $parent = $('#' + options.imgParentId), + $img = $parent.find(options.canvas ? 'canvas' : 'img'); + if ($img.length === 0) { + $img = $( options.canvas ? '' : '').prependTo($parent); + } + img = $img[0]; + } + if (!img) { + img = new Image(); + } + + var lang = settings.getLangId(); + if (lang >= 4 && lang <= 9) { + $("#lang").addClass("lang-system") + options.img = img; + options.text = options.text.toString(); + return Text.drawSystem(options); + } + + var fontId = options.fontId, + width = options.width, + alignment = options.alignment, + scaleToUI = options.scaleToUI, + alpha = options.alpha != null ? options.alpha : 1, + + scale = options.scaleToUI + ? resolution.UI_TEXT_SCALE + : (options.scale || 1), + + // ensure the text is a string (ex: convert number to string) + text = options.text.toString(); + + // save the existing canvas id and switch to the hidden canvas + var existingCanvas = Canvas.element; + + // create a temporary canvas to use + Canvas.setTarget(options.canvas ? img : document.createElement('canvas')); + + var font = ResourceMgr.getFont(fontId); + var t = new Text(font); + var padding = (24 * resolution.CANVAS_SCALE); // add padding to each side + + // set the text parameters + t.x = Math.ceil(padding / 2); + t.y = 0; + t.align = alignment || Alignment.LEFT; + t.setString(text, width); + + // set the canvas width and height + var canvas = Canvas.element, + ctx = Canvas.context, + imgWidth = (width || Math.ceil(t.width)) + Math.ceil(t.x * 2), + imgHeight = Math.ceil(t.height); + canvas.width = imgWidth; + canvas.height = imgHeight; + + var previousAlpha = ctx.globalAlpha; + if (alpha !== previousAlpha) { + ctx.globalAlpha = alpha; + } + + // draw the text and get the image data + t.draw(); + if (!options.canvas) + img.src = canvas.toDataURL('image/png'); + + if (alpha !== previousAlpha) { + ctx.globalAlpha = previousAlpha; + } + + // restore the original canvas for the App + if (existingCanvas) { + Canvas.setTarget(existingCanvas); + } + + var finalWidth = imgWidth * scale, + finalHeight = imgHeight * scale, + maxScaleWidth = options.maxScaleWidth, + topPadding, widthScale; + + // do additional scaling if a max scale width was specified and exceeded + if (maxScaleWidth && finalWidth > maxScaleWidth) { + widthScale = maxScaleWidth / finalWidth; + topPadding = Math.round((1 - widthScale) * finalHeight / 2); + finalWidth *= widthScale; + finalHeight *= widthScale; + } + + // When the src is set using image data, the height and width are + // not immediately available so we'll explicitly set them + var $img = $(img).width(finalWidth).height(finalHeight).css("padding-top", 0); + + // adjust the top padding if we scaled the image for width + if (topPadding) { + $img.css('padding-top', topPadding); + } + + return img; + }; + + Text.drawSmall = function (options) { + options.fontId = ResourceId.FNT_SMALL_FONT; + return Text.drawImg(options); + }; + Text.drawBig = function (options) { + options.fontId = ResourceId.FNT_BIG_FONT; + return Text.drawImg(options); + }; + Text.drawBigNumbers = function (options) { + options.fontId = ResourceId.FNT_FONT_NUMBERS_BIG; + return Text.drawImg(options); + }; + + return Text; + } +); + +define('resources/MenuStringId',[], function () { + /** + * @enum {number} + */ + var MenuId = { + + // extracted from ios sources + PLAY: 0, OPTIONS: 1, EXTRAS: 2, SURVIVAL: 3, FULL_VERSION: 4, RESET: 5, HELP: 6, + ABOUT: 7, CREDITS: 8, MUSIC_ON: 9, MUSIC_OFF: 10, SOUNDS_ON: 11, SOUNDS_OFF: 12, RESET_TEXT: 13, + LEVEL_CLEARED1: 14, LEVEL_CLEARED2: 15, LEVEL_CLEARED3: 16, LEVEL_CLEARED4: 17, LEVEL: 18, + TIME: 19, STAR_BONUS: 20, FINAL_SCORE: 21, BEST_SCORE: 22, SCORE: 23, YES: 24, NO: 25, REPLAY: 26, + NEXT: 27, MENU: 28, LOADING: 29, TOTAL_STARS: 30, OK: 31, UNLOCK_HINT: 32, CANT_UNLOCK_TEXT1: 33, + CANT_UNLOCK_TEXT2: 34, CANT_UNLOCK_TEXT3: 35, GAME_FINISHED_TEXT: 36, GAME_FINISHED_TEXT2: 37, + ACHIEVEMENT_GAINED: 38, CONTINUE: 39, SKIP_LEVEL: 40, LEVEL_SELECT: 41, MAIN_MENU: 42, + + // added for web version + LETS_PLAY: 43, + MORE_CTR_FUN: 44, + SHARE: 45, + SHARE_DRAWING: 46, + SHARE_ELLIPSIS: 47, + FOUND_DRAWING: 48, + DRAG_TO_CUT: 49, + CLICK_TO_CUT: 50, + SHOW_ME: 51, + FREE_DOWNLOAD: 52, + SITE_DESC: 53, + SITE_TITLE: 54, + SITE_ACTION: 55, + LANGUAGE: 56, + RESET_HOLD_YES: 57, + RELOAD_SD: 58, + RELOAD_HD: 59, + EVERYTHING_OFF: 60, + SLOW_TITLE: 61, + SLOW_TEXT: 62, + CONGRATULATIONS: 63, + MUSIC: 64, + SOUNDS: 65, + LEADERBOARDS: 66, + ACHIEVEMENTS: 67, + ACHIEVEMENT_UNLOCKED: 68, + UPGRADE_TO_FULL: 69, + NAME: 70, + AND_TEMPLATE: 71, + BUY_FULL_GAME: 72, + + // added for winjs version + SETTINGS: 200, + PRIVACY: 201 + }; + + return MenuId; +}); +define('resources/MenuStrings', + [ + 'resources/MenuStringId' + ], + function (MenuStringId) { + var locEntries = [ + {id: 0, en: "Play", zh: "玩游戏", ja: "プレイ", ko: "플레이", nl: "Spelen", it: "Gioca", fr: "Jouer", de: "Spielen", ru: "\u0418\u0433\u0440\u0430\u0442\u044c", es: "Jugar", br: "Jogar", ca: "Jugar"}, + {id: 1, en: "Options", zh: "选项", ja: "オプション", ko: "환경설정", nl: "Opties", it: "Opzioni", fr: "Options", de: "Optionen", ru: "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438", es: "Opciones", br: "Opções", ca: "Opcions"}, + {id: 2, en: "Extras", ja: "エクストラ", zh: "额外内容", ko: "부가 기능", nl: "Extra's", it: "Extra", br: "Extras", es: "Extras", fr: "", de: "Extras", ru: "\u0415\u0449\u0435 \u043a\u043e\u0435 \u0447\u0442\u043e", ca: "Extres"}, + {id: 3, en: "Bonus mode", ko: "", fr: "", de: "Bonusmodus", ru: "\u0411\u043e\u043d\u0443\u0441 \u0440\u0435\u0436\u0438\u043c"}, + {id: 4, en: "Full version", es: "Version completa", fr: "Version compl\u00e8te", de: "Vollversion", + ru: "\u041f\u043e\u043b\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f"}, + {id: 5, en: "Reset game", zh: "重置游戏", ja: "リセット", ko: "게임 초기화", nl: "Herstarten", it: "Azzera gioco", ca: "Reiniciar joc", br: "Reiniciar jogo", es: "Restablecer", fr: "R\u00e9initialiser", de: "Neu starten", ru: "\u0421\u0431\u0440\u043e\u0441 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u0430"}, + {id: 6, en: "Help", fr: "", de: "Hilfe", ru: "\u041f\u043e\u043c\u043e\u0449\u044c"}, + {id: 7, en: "About", fr: "À propos", de: "\u00dcber", ru: "\u041e\u0431 \u0438\u0433\u0440\u0435"}, + {id: 8, en: "Credits", es: "Creditos", fr: "Cr\u00e9dits", de: "Mitwirkende", ru: "\u0410\u0432\u0442\u043e\u0440\u044b"}, + {id: 9, en: "Music on", zh: "音乐打开", ja: "音楽:*オン", ko: "배경음 켜기", nl: "Muziek aan", it: "Musica: sì", ca: "Música activada", br: "Música on", es: "Música: si", fr: "Musique oui", de: "Musik an", ru: "\u041c\u0443\u0437\u044b\u043a\u0430 \u0432\u043a\u043b."}, + {id: 10, en: "Music off", zh: "音乐关闭", ja: "音楽:*オフ", ko: "배경음 끄기", nl: "Muziek uit", it: "Musica: no", ca: "Música desactivada", br: "Música off", es: "Música: no", fr: "Musique non", de: "Musik aus ", ru: "\u041c\u0443\u0437\u044b\u043a\u0430 \u0432\u044b\u043a\u043b."}, + {id: 11, en: "Sounds on", zh: "声音打开", ja: "効果音:*オン", ko: "효과음 켜기", nl: "Geluid aan", it: "Suoni: sì", ca: "Sons activats", br: "Sons on", es: "Sonido: si", fr: "Sons oui", de: "Ger\u00e4usche an", ru: "\u0417\u0432\u0443\u043a\u0438 \u0432\u043a\u043b."}, + {id: 12, en: "Sounds off", ja: "効果音:*オフ", zh: "声音关闭", ko: "효과음 끄기", nl: "Geluid uit", it: "Suoni: no", ca: "Sons desactivats", br: "Sons off", es: "Sonido: no", fr: "Sons non", de: "Ger\u00e4usche aus", ru: "\u0417\u0432\u0443\u043a\u0438 \u0432\u044b\u043a\u043b."}, + {id: MenuStringId.RESET_TEXT, + en: "Are you sure you want to reset your progress?", zh: "你确定要*重置游戏*进度吗?", ja: "本当に*リセット*しますか?", ko: "게임을 초기화하시겠습니까?", nl: "Weet je zeker dat je je voortgang wilt wissen?", it: "Vuoi davvero azzerare i tuoi progressi?", ca: "Estàs segur que desitges reiniciar el teu progrés?", br: "Tem certeza de que deseja descartar seu progresso?", es: "¿Seguro que quieres borrar el progreso realizado?", fr: "Voulez-vous vraiment r\u00e9initialiser votre progression?", de: "M\u00f6chtest du deinen Fortschritt wirklich zur\u00fccksetzen?", ru: "\u0423\u0432\u0435\u0440\u0435\u043d\u044b \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0441\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441?"}, + {id: 14, en: "Passable!", zh: "马马虎虎!", ja: "まずまず!", ko: "간신히 통과!", nl: "Voldoende!", it: "Accettabile!", ca: "Acceptable!", br: "Passável!", es: "¡No está mal!", fr: "Passable!", de: "Passabel!", ru: "\u0423\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u0440\u043e\u0439\u0434\u0435\u043d!"}, + {id: 15, en: "Good!", zh: "好!", ja: "グッド!", ko: "좋아요!", nl: "Goed!", it: "Bene!", ca: "Bé!", br: "Bom!", es: "¡Bien!", fr: "Bien!", de: "Gut!", ru: "\u0425\u043e\u0440\u043e\u0448\u043e!"}, + {id: 16, en: "Great!", zh: "真棒!", ja: "グレート!", ko: "잘 했어요!", nl: "Geweldig!", it: "Ottimo!", ca: "Fantàstic!", br: "Ótimo!", es: "¡Genial!", fr: "Super!", de: "Prima!", ru: "\u041e\u0442\u043b\u0438\u0447\u043d\u043e!"}, + {id: 17, en: "Excellent!", zh: "好极了!", ja: "最高!", ko: "아주 잘 했어요!", nl: "Uitstekend!", it: "Eccellente!", ca: "Excellent!", br: "¡Excelente!", es: "Excelente!", fr: "Formidable!", de: "Hervorragend!", ru: "\u0421\u0443\u043f\u0435\u0440!"}, + {id: 18, en: "Level", zh: "关卡", ja: "レベル", ko: "레벨", it: "Livello", ca: "Nivell", br: "Nível", es: "Nivel", fr: "Niveau", de: "Level", ru: "\u0423\u0440\u043e\u0432\u0435\u043d\u044c"}, + {id: 19, en: "Time", zh: "时间", ja: "タイム", ko: "시간", nl: "Tijd", it: "Tempo", ca: "Temps", br: "Tempo", es: "Tiempo", fr: "Temps", de: "Zeit", ru: "\u0412\u0440\u0435\u043c\u044f"}, + {id: 20, en: "Star Bonus", zh: "星星奖励", ja: "スターボーナス", ko: "보너스 별", nl: "Sterrenbonus", it: "Bonus stelle", ca: "Bonus de estrelles", br: "Bônus de estrela", es: "Bonificación estrellas", fr: "Bonus \u00e9toile", + de: "Sternenbonus", ru: "\u0411\u043e\u043d\u0443\u0441 \u0437\u0430 \u0437\u0432\u0435\u0437\u0434\u044b"}, + {id: 21, en: "Your Final Score", zh: "你的*最终得分", ja: "あなたの*最終*スコア", ko: "최종 점수", nl: "Je eindscore", it: "Punteggio finale", ca: "La teva puntuació final", br: "Sua pontuação final", es: "Puntuación final", fr: "Votre score final", de: "Dein Endpunktestand", ru: "\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u043e\u0447\u043a\u0438"}, + {id: 22, en: "Best Score", zh: "最佳得分", ja: "ベスト*スコア", ko: "최고 점수", nl: "Beste score", it: "Miglior punteggio", ca: "Millor puntuació", br: "Melhor pontuação", es: "Mejor puntuación", fr: "Meilleur score", de: "Beste punktzahl", ru: "\u041b\u0443\u0447\u0448\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442"}, + {id: 23, en: "Score", zh: "得分", ja: "スコア", ko: "점수", nl: "Score", it: "Punteggio", ca: "Puntuació", br: "Pontuação", es: "Puntuación", fr: "Score", de: "Punktzahl", ru: "\u041e\u0447\u043a\u0438"}, + {id: 24, en: "Yes", zh: "是", ja: "はい", ko: "예", nl: "Ja", it: "Sì", ca: "Sí", br: "Sim", es: "Sí", fr: "Oui", de: "Ja", ru: "\u0414\u0430"}, + {id: 25, en: "No", zh: "否", ja: "いいえ", ko: "아니요", nl: "Nee", ca: "No", br: "Não", fr: "Non", de: "Nein", ru: "\u041d\u0435\u0442"}, + {id: 26, en: "Replay", zh: "重玩", ja: "やり直す", ko: "다시 하기", nl: "Opnieuw", it: "Rigioca", ca: "Repetir", br: "Repetir", es: "Repetir", fr: "Rejouer", de: "Wieder", ru: "\u0415\u0449\u0435 \u0440\u0430\u0437"}, + {id: 27, en: "Next", zh: "下一步", ja: "次へ", ko: "다음", nl: "Volgende", it: "Prossimo", ca: "Següent", br: "Próximo", es: "Siguiente", fr: "Suivant", de: "Weiter", ru: "\u0412\u043f\u0435\u0440\u0435\u0434"}, + {id: 28, en: "Menu", zh: "菜单", ja: "メニュー", ko: "메뉴", nl: "Menu", ca: "Menú", es: "Menú", fr: "Menu", de: "Men\u00fc", ru: "\u041c\u0435\u043d\u044e"}, + {id: 29, en: "Loading...", zh: "正在加载...", ja: "ロード中...", ko: "불러오는 중...", nl: "Bezig met laden...", it: "Caricamento in corso...", ca: "Carregant ...", br: "Carregando ...", es: "Cargando...", fr: "Chargement...", de: "Laden...", ru: "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430..."}, + {id: 30, en: "Total: %d", zh: "合计: %d", ja: "合計:%d", ko: "총 점수: %d", nl: "Totaal: %d", it: "Totale: %d", fr: "Total: %d", de: "Gesamt: %d", ru: "\u0412\u0441\u0435\u0433\u043e: %d"}, + {id: 31, en: "Ok", zh: "确定", ja: "OK", ko: "확인", nl: "Oké", ca: "Acceptar", es: "Aceptar", fr: "OK", de: "Ok", ru: "Ok"}, + {id: 32, en: "Collect %d stars to unlock this level pack", zh: "收集 %d 颗*星星*才能解锁*这一*关卡集", ja: "アンロック*するには* %d の*スターが*必要です", ko: "이 레벨 상자를 열려면 별 %d개를 모으세요.", nl: "Verzamel %d sterren om dit levelpakket te ontgrendelen", it: "Raccogli %d stelle per sbloccare questo pacchetto di livelli", ca: "Aconsegueix %d estrelles per desbloquejar aquest paquet de nivells", br: "Colete %d estrelas para liberar este nível", es: "Consigue %d estrellas para desbloquear este pack de niveles.", fr: "Recueillez %d \u00e9toiles pour d\u00e9verrouiller ce pack de niveaux", de: "Sammle %d Sterne, um dieses Levelpaket freizuschalten", ru: "\u0421\u043e\u0431\u0435\u0440\u0438\u0442\u0435 %d \u0437\u0432\u0435\u0437\u0434 \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0440\u043e\u0431\u043a\u0443"}, + {id: MenuStringId.CANT_UNLOCK_TEXT1, en: "You are missing", zh: "你还需要", ja: "アンロックには", ko: "이 상자를 열려면", nl: "Je mist", it: "Hai bisogno di", ca: "Encara necessites", br: "Você precisa de", es: "Necesitas", fr: "Il vous en manque", de: "Dir fehlen", ru: "\u0412\u0430\u043c \u043d\u0435\u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0432\u0441\u0435\u0433\u043e"}, + {id: MenuStringId.CANT_UNLOCK_TEXT2, en: "to unlock this box", zh: "才能解锁*这个盒子", ja: "が必要です", ko: "개가 더 필요해요.", nl: "om deze doos te openen", it: "per sblocc. la scatola", ca: "per desbloquejar aquesta caixa", br: "para liberar esta caixa", es: "para abrir esta caja", fr: "pour d\u00e9verrouiller bo\u00eete", de: "um dieses Box freizuschalten", ru: "\u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u0440\u043e\u0431\u043a\u0443"}, + {id: MenuStringId.CANT_UNLOCK_TEXT3, en: "Get more stars from the earlier levels", zh: "从先前的*关卡中*获取更多*星星", ja: "前の*レベルで*スターを*もっと*獲得*しましょう", ko: "이전 레벨에서 별을 더 모으세요.", nl: "Ontvang meer sterren uit de eerdere levels", it: "Ottieni altre stelle nei primi livelli", ca: "Pots aconseguir més estrelles en els nivells anteriors", br: "Obtenha mais estrelas em níveis anteriores", es: "Vuelve a jugar los niveles anteriores para obtener más estrellas", fr: "Recueillez plus d'\u00e9toiles dans les niveaux pr\u00e9c\u00e9dents", + de: "Gewinne mehr Sterne in den niedrigeren Leveln", ru: "\u0421\u043e\u0431\u0435\u0440\u0438\u0442\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0432\u0435\u0437\u0434 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0443\u0440\u043e\u0432\u043d\u044f\u0445"}, + {id: 37, en: "Check back for the new levels coming with the updates", fr: "Revenez pour d\u00e9couvrir de nouveaux niveaux avec les mises \u00e0 jour", de: "Komm bald wieder, neue Level kommen mit den Updates", ru: "\u041d\u043e\u0432\u044b\u0435 \u0443\u0440\u043e\u0432\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441 \u0430\u043f\u0434\u0435\u0439\u0442\u0430\u043c\u0438"}, + {id: MenuStringId.ACHIEVEMENT_GAINED, en: "achievement gained!", es: "Logro obtenido!", fr: "r\u00e9alisation d\u00e9verrouill\u00e9e!", + de: "Erfolg geschafft!", ru: "\u043e\u0442\u043a\u0440\u044b\u0442\u043e!"}, + {id: 39, en: "Continue", zh: "继续", ja: "続ける", ko: "계속", nl: "Doorgaan", it: "Continua", ca: "Continuar", br: "Continuar", es: "Continuar", fr: "Continuer", de: "Weiter", ru: "\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c"}, + {id: 40, en: "Skip level", zh: "跳过关卡", ja: "スキップ", ko: "레벨 건너뛰기", nl: "Overslaan", it: "Salta livello", ca: "Ometre nivell", br: "Pular nível", es: "Saltar nivel", fr: "Passer", de: "\u00dcberspringen", ru: "\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c"}, + {id: 41, en: "Level select", zh: "选择关卡", ja: "レベル*選択", ko: "레벨 선택", nl: "Level kiezen", it: "Sel. livello", ca: "Selecció de nivell", br: "Escolha nível", es: "Elegir nivel", fr: "Choisir niveau", de: "Levelauswahl", ru: "\u0412\u044b\u0431\u043e\u0440 \u0443\u0440\u043e\u0432\u043d\u044f"}, + {id: 42, en: "Main menu", zh: "主菜单", ja: "メイン*メニュー", ko: "주 메뉴", nl: "Hoofdmenu", it: "Menu di gioco", ca: "Menú principal", br: "Menu Princ.", es: "Menú princ", fr: "Menu principal", + de: "Hauptmen\u00fc", ru: "\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e"}, + + { + id: MenuStringId.LANGUAGE, + en: "Language", + ru: "Язык", + fr: "Langue", + de: "Sprache", + es: "Lingua", + br: "Idioma", + ca: "Idioma", + it: "Lingua", + nl: "Taal", + ko: "언어", + ja: "言語", + zh: "语言" + }, + { + id: MenuStringId.DRAG_TO_CUT, + en: "Drag to Cut", + fr: "Glisser", + de: "Ziehe: Schneide", + ru: "Перетаскиванием", + es: "" + }, + { + id: MenuStringId.CLICK_TO_CUT, + en: "Click to Cut", + fr: "Cliquer", + de: "Klicke: Schneide", + ru: "Щелчком", + es: "" + }, + { + id: MenuStringId.LETS_PLAY, + en: "Let's Play", + fr: "C'est parti", + de: "Lass uns spielen", + ru: "Давайте поиграем", + es: "" + }, + { + id: MenuStringId.MORE_CTR_FUN, + en: "More Cut the Rope fun!", + fr: "Toujours plus de Cut the Rope !", + de: "Mehr Cut the Rope Spaß!", + ru: "Еще больше веселья в игре Cut the Rope!" + }, + { + id: MenuStringId.SHARE_ELLIPSIS, + en: "Share...", + fr: "Partager...", + de: "Teilen...", + ru: "Поделиться...", + es: "Compartir..." + }, + { + id: MenuStringId.SHARE, + en: "Share", + fr: "Partager", + de: "Teilen", + ru: "Поделиться", + es: "Compartir" + }, + { + id: MenuStringId.CONGRATULATIONS, + en: "Congratulations!", + fr: "Félicitations!", + de: "Gratulation!", + ru: "Поздравляем!", + es: "Enhorabuena!", + br: "Parabéns!", + ca: "Enhorabona!", + it: "Congratulazioni!", + nl: "Gefeliciteerd!", + ko: "축하합니다!", + zh: "恭喜!", + ja: "おめでとう*ございます!" + }, + { + id: MenuStringId.GAME_FINISHED_TEXT, + en: "You completed the game with %d stars!", + fr: "Tu as terminé le jeu avec %d étoiles !", + de: "Du hast das Spiel mit %d Sternen beendet!", + ru: "Вы завершили игру со следующим количеством звезд: %d!", + ca: "Has finalitzat el joc amb %d estrelles!", + ko: "게임이 끝났습니다!", + zh: "你已完成*该游戏!", + ja: "ゲームを クリアしました!", + es: "¡Has terminado el juego!", + it: "Hai completato il gioco!", + nl: "Je hebt de game uitgespeeld!", + br: "Você terminou o jogo!" + }, + { + id: MenuStringId.SHARE_DRAWING, + en: "I just found one of Om Nom's secret drawings!", + fr: "Je viens juste de trouver un des dessins secrets de Om Nom !", + de: "Ich habe gerade eine geheime Om-Nom-Zeichnung entdeckt!", + ru: "Мною только что был обнаружен один из тайных рисунков Ам Няма!" + }, + { + id: MenuStringId.FOUND_DRAWING, + en: "You found a drawing!", + fr: "Tu as trouvé un dessin !", + de: "Du hast die Zeichnung gefunden!", + ru: "Вы обнаружили рисунок!" + }, + { + id: MenuStringId.SHOW_ME, + en: "Show Me", + fr: "Montre-moi", + de: "Zeig es mir", + ru: "Показать мне" + }, + { + id: MenuStringId.FREE_DOWNLOAD, + en: "Free Download", + fr: "Téléchargement gratuit", + de: "Kostenloser Download", + ru: "Бесплатная загрузка" + }, + { + id: MenuStringId.SITE_DESC, + en: "Cut the Rope is a fun game where you feed candy to the curiously cute green monster Om-nom.", + fr: "Cut the Rope est un jeu amusant dans lequel tu dois nourrir Om Nom, un curieux petit monstre.", + de: "Cut the Rope ist ein lustiges Spiel, wobei du dem kuriosem, niedlichem Monster Om-nom Süßigkeiten fütterst.", + ru: "Cut the Rope это веселая игра, в которой вы кормите сладостями любопытного и милого монстра по имени Ам Ням." + }, + { + id: MenuStringId.SITE_TITLE, + en: "Om Nom is Om Line - Cut the Rope for the Web", + fr: "Om Nom est om ligne - Cut the Rope version web", + de: "Om Nom ist Om Line - Cut the Rope für das Internet", + ru: "Ам Ням в Ам Лайне – веб-версия игры Cut the Rope" + }, + { + id: MenuStringId.SITE_ACTION, + en: 'Play the HTML5 version of "Cut the Rope"!', + fr: 'Joue à Cut the Rope dans sa version HTML5 !', + de: 'Spiele die HTML5 Version von "Cut the Rope"!', + ru: 'Играйте в HTML5-версию игры Cut the Rope!' + }, + { + id: MenuStringId.RESET_HOLD_YES, + en: 'Hold the "yes" button for 3 seconds to reset.', + fr: 'Maintenir le doigt sur "Oui" pendant 3 secondes pour réinitialiser.', + de: 'Halte zum Neustarten 3 Sekunden lang "Ja" gedrückt.', + ru: 'Удерживайте "Да" в течение 3 секунд для сброса прогресса.', + ko: "“예” 버튼을 3초 동안 누르면 초기화됩니다.", + zh: "按住“是”按钮 3 秒即可重置。", + ja: "はい」 のボタンを 3秒間*長押しで リセット", + es: "Mantén pulsado 'Sí' durante 3 segundos para reiniciar.", + it: "Tieni premuto il tasto 'sì' per 3 secondi per azzerare.", + nl: "Houd de Ja-knop 3 seconden ingedrukt om opnieuw te beginnen.", + br: "Segure o botão 'Sim' por 3 segundos para reiniciar.", + ca: "Mantingues premut el botó 'sí' durant 3 segons per reiniciar." + }, + { + id: MenuStringId.EVERYTHING_OFF, + en: 'everything off', + fr: 'tout couper', + de: 'alles aus', + ru: 'все отключено', + es: 'todo apagado', + br: 'todo off', + ca: "tot desactivat", + it: "tutto fuori", + nl: "alles uit" + }, + { + id: MenuStringId.RELOAD_SD, + en: 'reload the game in SD', + fr: 'recharger le jeu en SD', + de: 'Spiel in SD neu laden', + ru: 'перезагрузить игру в SD' + }, + { + id: MenuStringId.RELOAD_HD, + en: 'reload the game in HD', + fr: 'recharger le jeu en HD', + de: 'Spiel in HD neu laden', + ru: 'перезагрузить игру в HD' + }, + { + id: MenuStringId.SLOW_TITLE, + en: 'A Little Too Slow...', + fr: 'Un peu trop lent', + de: 'Etwas zu langsam...', + ru: 'Как-то не очень быстро...' + }, + { + id: MenuStringId.SLOW_TEXT, + en: "Om Nom is sad because your computer is running slow. We'll do our best, but there may be some slow-downs.", + fr: "Om Nom est triste. Votre ordinateur est très lent. Nous ferons notre mieux, mais il est possible que le jeu ralentisse.", + de: "Om Nom ist traurig, weil dein Computer so langsam ist. Wir geben unser Bestes, aber es kann trotzdem zu Verzögerungen kommen.", + ru: 'Ам Ням опечален: у вас слишком медленный компьютер. Мы, конечно, постараемся, но игра у вас может "притормаживать".' + }, + {id: MenuStringId.MUSIC, en: "Music", nl: "Muziek", it: "Musica", ca: "Música", fr: "Musique", de: "Musik", ru: "\u041c\u0443\u0437\u044b\u043a\u0430"}, + {id: MenuStringId.SOUNDS, en: "Sounds", nl: "Geluid", it: "Suoni", ca: "Sons", fr: "Sons oui", de: "Ger\u00e4usche", ru: "\u0417\u0432\u0443\u043a\u0438"}, + { + id: MenuStringId.LEADERBOARDS, + en: 'Leaderboards', + fr: 'Classements', + de: 'Bestenlisten', + ru: 'Таблица рекордов' + }, + { + id: MenuStringId.ACHIEVEMENTS, + en: 'Achievements', + fr: 'Succès', + de: 'Erfolge', + ru: 'Достижения' + }, + { + id: MenuStringId.ACHIEVEMENT_UNLOCKED, + en: 'Achievement unlocked!', + fr: 'Succès débloqué !', + de: 'Erfolg freigeschaltet!', + ru: 'Новое достижение!' + }, + { + id: MenuStringId.UPGRADE_TO_FULL, + en: 'Get MANY MORE\n levels in the full version', + fr: 'De NOMBREUX autres niveaux\n sont disponibles dans la version complète!', + de: 'In der Vollversion gibt\n es noch VIEL MEHR Level!', + ru: 'Получите НАМНОГО БОЛЬШЕ\n уровней в полной версии!' + }, + { + id: MenuStringId.NAME, + en: 'Name', + fr: 'Nom', + de: 'Name', + ru: 'Имя' + }, + { + id: MenuStringId.AND_TEMPLATE, + en: '{0} & {1}', + fr: '{0} et {1}', + de: '{0} und {1}', + ru: '{0} и {1}', + ca: '{0} i {1}', + }, + { + id: MenuStringId.BUY_FULL_GAME, + en: 'Buy Full Game', + fr: 'Acheter le jeu complet', + de: 'Vollversion kaufen', + ru: 'Купить полную версию' + }, + { + id: MenuStringId.SETTINGS, + en: 'Settings', + fr: 'Paramètres', + de: 'Einstellungen', + ru: 'Настройки', + ca: 'Configuració' + }, + { + id: MenuStringId.PRIVACY, + en: 'Privacy', + fr: 'Vie privée', + de: 'Datenschutz', + ru: 'Конфиденциальность' + } + + + + /* + { + id: MenuStringId., + en: '', + fr: '', + de: '', + ru: '' + } + */ + ]; + + return locEntries; + }); +define('resources/Lang', + [ + 'edition', + 'game/CTRSettings', + 'resources/LangId', + 'resources/MenuStrings', + 'utils/Log' + ], + function (edition, settings, LangId, menuStrings, Log) { + + // helper to return the correct string from a loc entry + var getLocalizedText = function (locEntry) { + + // note: we default to english if entry is blank + // !LANG + switch (settings.getLangId()) { + case LangId.FR: + return locEntry.fr || locEntry.en; + case LangId.DE: + return locEntry.de || locEntry.en; + case LangId.RU: + return locEntry.ru || locEntry.en; + case LangId.ES: + return locEntry.es || locEntry.en; + case LangId.BR: + return locEntry.br || locEntry.en; + case LangId.CA: + return locEntry.ca || locEntry.en; + case LangId.IT: + return locEntry.it || locEntry.en; + case LangId.NL: + return locEntry.nl || locEntry.en; + case LangId.KO: + return locEntry.ko || locEntry.en; + case LangId.ZH: + return locEntry.zh || locEntry.en; + case LangId.JA: + return locEntry.ja || locEntry.en; + case LangId.EN: + default: + return locEntry.en; + } + }; + + var Lang = { + boxText: function (boxIndex, includeNumber) { + var locEntry = edition.boxText[boxIndex], + text = getLocalizedText(locEntry); + + // all boxes except last one get prepended numbers + if (text && includeNumber) { + text = (boxIndex + 1) + '. ' + text; + } + + return text; + }, + menuText: function (menuStringId) { + + var locEntry, i, + len = menuStrings.length; + for (i = 0; i < len; i++) { + locEntry = menuStrings[i]; + if (locEntry.id === menuStringId) { + return getLocalizedText(locEntry); + } + } + + Log.debug('Missing menu string for id: ' + menuStringId); + return ""; + }, + getText: getLocalizedText, + getCurrentId: function() { + return settings.getLangId(); + } + }; + + return Lang; + } +); + +define('config/platforms/platform-web', + [ + 'visual/Text', + 'resolution', + 'resources/Lang', + 'resources/MenuStringId', + 'core/Alignment', + 'edition' + ], + function (Text, resolution, Lang, MenuStringId, Alignment, edition) { + + // loc entries that are specific to the web platform + var locEntries = { + GAME_COMPLETE: { + en: "I just finished playing Cut the Rope on the web with %d (out of %d possible) stars!", + fr: "", + de: "", + ru: "" + } + }; + + var WebPlatform = { + + /** + * @const + * @type {boolean} + */ + ENABLE_ANALYTICS: true, + + /** + * @const + * @type {boolean} + */ + ENABLE_ZOOM: false, + + ZOOM_BOX_CANVAS: false, + + imageBaseUrl: 'images/', + resolutionBaseUrl: 'images/' + resolution.UI_WIDTH + '/', + uiImageBaseUrl: 'images/' + resolution.UI_WIDTH + '/ui/', + boxImageBaseUrl: 'images/' + resolution.UI_WIDTH + '/' + (edition.boxDirectory || 'ui/'), + + audioBaseUrl: 'audio/', + getAudioExtension: function () { + return '.mp3'; + }, + + videoBaseUrl: 'video/', + getVideoExtension: function () { + return Modernizr.video.h264 ? '.mp4' : + Modernizr.video.webm ? '.webm' : null; + }, + + getDrawingBaseUrl: function () { + var loc = window.location, + baseUrl = loc.protocol + '//' + loc.host; + return baseUrl + '/images/' + resolution.UI_WIDTH + '/ui/'; + }, + getScoreImageBaseUrl: function () { + var loc = window.location, + baseUrl = loc.protocol + '//' + loc.host; + return baseUrl + "/images/scores/"; + }, + setSoundButtonChange: function($button, callback) { + $button.click(callback); + }, + setMusicButtonChange: function($button, callback) { + $button.click(callback); + }, + updateSoundOption: function ($el, isSoundOn) { + $el.toggleClass('disabled', !isSoundOn); + }, + updateMusicOption: function ($el, isMusicOn) { + $el.toggleClass('disabled', !isMusicOn); + }, + toggleLangUI: function (show) { + $('#langBtn').toggle(show); + }, + setLangOptionClick: function (callback) { + $('#langBtn').click(function(e) { + var langId = null; // just advance to next supported language + callback(langId); + }); + }, + updateLangSetting: function () { + WebPlatform.setOptionText($('#langBtn'), + Lang.menuText(MenuStringId.LANGUAGE) + ':'); + + // Chrome has a layout bug where the css offset on the flag + // icon is not changed immediately. Retrieving the offset + // forces the browser to query location which fixes layout. + $('#flag').offset(); + }, + setCutOptionClick: function (callback) { + $('#cutBtn').click(callback); + }, + updateCutSetting: function (isClickToCut) { + + // fonts use game sized assets based on canvas size + var textWidth = 400 * resolution.CANVAS_SCALE, + + // scale need to take UI size into account + scale = 0.8 * resolution.UI_TEXT_SCALE, + alignment = Alignment.HCENTER; + + // we update the drag text because language changes just + // reset the current click state + Text.drawSmall({ + text: Lang.menuText(MenuStringId.DRAG_TO_CUT), + width: textWidth, + imgId: 'dragText', + scale: scale, + alignment: alignment }); + + // now update the click-to-cut text and check mark + Text.drawSmall({ + text: Lang.menuText(MenuStringId.CLICK_TO_CUT), + width: textWidth, + imgId: 'cutText', + scale: scale, + alignment: alignment }); + $('#cutBtn').toggleClass('disabled', !isClickToCut); + }, + setResetText: function ($el, text) { + WebPlatform.setOptionText($el, text); + }, + setOptionText: function ($button, text) { + Text.drawBig({ text: text, img: $button.find('img')[0], scaleToUI: true }); + }, + getGameCompleteShareText: function (totalStars, possibleStars) { + var text = Lang.getText(locEntries.GAME_COMPLETE) + .replace('%d', totalStars) + .replace('%d', possibleStars); + return text; + }, + meetsRequirements: function () { + // does the browser have the HTML5 features we need? + var meetsReqs = + Modernizr.canvas && + Modernizr.audio && + Modernizr.video && + Modernizr.localstorage && + Modernizr.rgba && + Modernizr.opacity && + Modernizr.fontface && + Modernizr.csstransforms && + Modernizr.hq; + + if (!meetsReqs) { + // load the css for the downlevel experience + Modernizr.load({ + 'load': 'css!css/nosupport.css?RELEASE_TAG' + }); + + // remove youtube video if it exists + $(function() { + $('#yt-video').remove(); + }); + + // track views of the ugprade page + _gaq.push(['_trackEvent', 'Upgrade', 'View']); + } + return meetsReqs; + } + }; + + return WebPlatform; + } +); + +define('platform', + [ + 'config/platforms/platform-web' + ], + function (WebPlatform) { + + var GeckoPlatform = WebPlatform; + + // override audio and video format choices + + GeckoPlatform.getAudioExtension = function () { + return '.mp3'; + }; + + GeckoPlatform.getVideoExtension = function () { + return '.webm'; + }; + + GeckoPlatform.disableSlowWarning = true; + + return GeckoPlatform; + } +); + +define('editionUI',[], function () { + return {}; +}); +// manages sounds (SoundManager2 only for now, but eventually PhoneGap as well) + +document.addEventListener('mozvisibilitychange', function() { + //console.log("VISIBILTY", document.mozHidden); + if (document.mozHidden) { + for (var key in window.sounds__) { + window.sounds__[key]._wasPlaying = !window.sounds__[key].paused; + window.sounds__[key].pause(); + } + } else { + + for (var key in window.sounds__) { + window.sounds__[key]._wasPlaying && window.sounds__[key].play(); + } + } +}); + +define('resources/Sounds', + [ + 'platform', + 'utils/Log' + ], + function (platform, Log) { + + + // export a singleton which manages audio using SoundManager2 + var Sounds = { + onReady: function (callback) { + callback(); + }, + play: function (soundId, onComplete) { + var sound = window.sounds__['s' + soundId]; + var id = 's' + soundId; + + // choose and create a backup sound + if (!sound.paused) { + // lazy clone it + if (!window.backupSounds__[id]) { + window.backupSounds__[id] = window.sounds__[id].cloneNode(); + window.backupSounds__[id].mozAudioChannelType = 'content'; + } + + sound = window.backupSounds__[id]; + } + + sound['addEventListener']("ended", function onendcb () { + sound['removeEventListener']("ended", onendcb); + if (onComplete) { + onComplete(); + } + }, false); + sound['play'](); + }, + isPlaying: function (soundId) { + var sound = window.sounds__['s' + soundId]; + return !sound['paused']; + }, + isPaused: function (soundId) { + var sound = window.sounds__['s' + soundId]; + return sound['paused']; + }, + pause: function (soundId) { + var sound = window.sounds__['s' + soundId]; + sound['pause'](); + }, + stop: function (soundId) { + var sound = window.sounds__['s' + soundId]; + sound['pause'](); + try { + sound['currentTime'] = sound['initialTime']; + } catch (e) {} + }, + setVolume: function (soundId, percent) { + var sound = window.sounds__['s' + soundId]; + sound['volume'] = percent / 100; + } + }; + + return Sounds; + } +); + + +define('PxLoader',[], function () { + + /** + * PixelLab Resource Loader + * Loads resources while providing progress updates. + */ + function PxLoader(settings) { + + // merge settings with defaults + settings = settings || {}; + + // how frequently we poll resources for progress + if (settings.statusInterval == null) { + settings.statusInterval = 5000; // every 5 seconds by default + } + + // delay before logging since last progress change + if (settings.loggingDelay == null) { + settings.loggingDelay = 20 * 1000; // log stragglers after 20 secs + } + + // stop waiting if no progress has been made in the moving time window + if (settings.noProgressTimeout == null) { + settings.noProgressTimeout = Infinity; // do not stop waiting by default + } + + var entries = [], // holds resources to be loaded with their status + progressListeners = [], + timeStarted, + progressChanged = Date.now(); + + /** + * The status of a resource + * @enum {number} + */ + var ResourceState = { + QUEUED: 0, + WAITING: 1, + LOADED: 2, + ERROR: 3, + TIMEOUT: 4 + }; + + // places non-array values into an array. + var ensureArray = function (val) { + if (val == null) { + return []; + } + + if (Array.isArray(val)) { + return val; + } + + return [ val ]; + }; + + // add an entry to the list of resources to be loaded + this.add = function (resource) { + + // ensure tags are in an array + resource.tags = ensureArray(resource.tags); + + // ensure priority is set + if (resource.priority == null) { + resource.priority = Infinity; + } + + entries.push({ + resource: resource, + state: ResourceState.QUEUED + }); + }; + + this.addProgressListener = function (callback, tags) { + progressListeners.push({ + callback: callback, + tags: ensureArray(tags) + }); + }; + + this.addCompletionListener = function (callback, tags) { + progressListeners.push({ + tags: ensureArray(tags), + callback: function (e) { + if (e.completedCount === e.totalCount) { + callback(); + } + } + }); + }; + + // creates a comparison function for resources + var getResourceSort = function (orderedTags) { + + // helper to get the top tag's order for a resource + orderedTags = ensureArray(orderedTags); + var getTagOrder = function (entry) { + var resource = entry.resource, + bestIndex = Infinity; + for (var i = 0, len = resource.tags.length; i < len; i++) { + var index = orderedTags.indexOf(resource.tags[i]); + if (index >= 0 && index < bestIndex) { + bestIndex = index; + } + } + return bestIndex; + }; + + return function (a, b) { + // check tag order first + var aOrder = getTagOrder(a), + bOrder = getTagOrder(b); + if (aOrder < bOrder) return -1; + if (aOrder > bOrder) return 1; + + // now check priority + if (a.priority < b.priority) return -1; + if (a.priority > b.priority) return 1; + return 0; + } + }; + + this.start = function (orderedTags) { + timeStarted = Date.now(); + + // first order the resources + var compareResources = getResourceSort(orderedTags); + entries.sort(compareResources); + + // trigger requests for each resource + for (var i = 0, len = entries.length; i < len; i++) { + var entry = entries[i]; + entry.status = ResourceState.WAITING; + entry.resource.start(this); + } + + // do an initial status check soon since items may be loaded from the cache + setTimeout(statusCheck, 100); + }; + + var statusCheck = function () { + var checkAgain = false, + noProgressTime = (Date.now()) - progressChanged, + timedOut = (noProgressTime >= settings.noProgressTimeout), + shouldLog = (noProgressTime >= settings.loggingDelay); + + for (var i = 0, len = entries.length; i < len; i++) { + var entry = entries[i]; + if (entry.status !== ResourceState.WAITING) { + continue; + } + + // see if the resource has loaded + entry.resource.checkStatus(); + + // if still waiting, mark as timed out or make sure we check again + if (entry.status === ResourceState.WAITING) { + if (timedOut) { + entry.resource.onTimeout(); + } + else { + checkAgain = true; + } + } + } + + // log any resources that are still pending + if (shouldLog && checkAgain) { + log(); + } + + if (checkAgain) { + setTimeout(statusCheck, settings.statusInterval); + } + }; + + this.isBusy = function () { + for (var i = 0, len = entries.length; i < len; i++) { + if (entries[i].status === ResourceState.QUEUED || + entries[i].status === ResourceState.WAITING) { + return true; + } + } + return false; + }; + + // helper which returns true if two arrays share at least one item + var arraysIntersect = function (a, b) { + for (var i = 0, len = a.length; i < len; i++) { + if (b.indexOf(a[i]) >= 0) { + return true; + } + } + return false; + }; + + var onProgress = function (resource, statusType) { + // find the entry for the resource + var entry = null; + for (var i = 0, len = entries.length; i < len; i++) { + if (entries[i].resource === resource) { + entry = entries[i]; + break; + } + } + + // we have already updated the status of the resource + if (entry == null || entry.status !== ResourceState.WAITING) { + return; + } + entry.status = statusType; + progressChanged = Date.now(); + + var numResourceTags = resource.tags.length; + + // fire callbacks for interested listeners + for (var i = 0, numListeners = progressListeners.length; i < numListeners; i++) { + var listener = progressListeners[i], + shouldCall; + + if (listener.tags.length === 0) { + // no tags specified so always tell the listener + shouldCall = true; + } + else { + // listener only wants to hear about certain tags + shouldCall = arraysIntersect(resource.tags, listener.tags); + } + + if (shouldCall) { + sendProgress(entry, listener); + } + } + }; + + this.onLoad = function (resource) { + onProgress(resource, ResourceState.LOADED); + }; + this.onError = function (resource) { + onProgress(resource, ResourceState.ERROR); + }; + this.onTimeout = function (resource) { + onProgress(resource, ResourceState.TIMEOUT); + }; + + // sends a progress report to a listener + var sendProgress = function (updatedEntry, listener) { + // find stats for all the resources the caller is interested in + var completed = 0, + total = 0; + for (var i = 0, len = entries.length; i < len; i++) { + var entry = entries[i], + includeResource; + + if (listener.tags.length === 0) { + // no tags specified so always tell the listener + includeResource = true; + } + else { + includeResource = arraysIntersect(entry.resource.tags, listener.tags); + } + + if (includeResource) { + total++; + if (entry.status === ResourceState.LOADED || + entry.status === ResourceState.ERROR || + entry.status === ResourceState.TIMEOUT) { + completed++; + } + } + } + + listener.callback({ + // info about the resource that changed + resource: updatedEntry.resource, + + // should we expose StatusType instead? + loaded: (updatedEntry.status === ResourceState.LOADED), + error: (updatedEntry.status === ResourceState.ERROR), + timeout: (updatedEntry.status === ResourceState.TIMEOUT), + + // updated stats for all resources + completedCount: completed, + totalCount: total + }); + }; + + // prints the status of each resource to the console + var log = this.log = function (showAll) { + if (!window.console) { + return; + } + + var elapsedSeconds = Math.round((Date.now() - timeStarted) / 1000); + window.console.log('PxLoader elapsed: ' + elapsedSeconds + ' sec'); + + for (var i = 0, len = entries.length; i < len; i++) { + var entry = entries[i]; + if (!showAll && entry.status !== ResourceState.WAITING) { + continue; + } + + var message = 'PxLoader: #' + i + ' ' + entry.resource.getName(); + switch (entry.status) { + case ResourceState.QUEUED: + message += ' (Not Started)'; + break; + case ResourceState.WAITING: + message += ' (Waiting)'; + break; + case ResourceState.LOADED: + message += ' (Loaded)'; + break; + case ResourceState.ERROR: + message += ' (Error)'; + break; + case ResourceState.TIMEOUT: + message += ' (Timeout)'; + break; + } + + if (entry.resource.tags.length > 0) { + message += ' Tags: [' + entry.resource.tags.join(',') + ']'; + } + + window.console.log(message); + } + }; + } + + // shims to ensure we have newer Array utility methods + + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray + if (!Array.isArray) { + Array.isArray = function (arg) { + return Object.prototype.toString.call(arg) == '[object Array]'; + }; + } + + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf + if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement /*, fromIndex */) { + + if (this == null) { + throw new TypeError(); + } + var t = Object(this); + var len = t.length >>> 0; + if (len === 0) { + return -1; + } + var n = 0; + if (arguments.length > 0) { + n = Number(arguments[1]); + if (n != n) { // shortcut for verifying if it's NaN + n = 0; + } else if (n != 0 && n != Infinity && n != -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; + } + + return PxLoader; +}); + + + + +define('PxLoaderSound',['PxLoader'], function (PxLoader) { + + window.sounds__ = {}; + window.backupSounds__ = {}; + + /** + * PxLoader plugin to load sound using SoundManager2 + */ + function PxLoaderSound(id, url, tags, priority) { + var self = this, + loader = null; + + this.tags = tags; + this.priority = priority; + this.sound = new Audio(); + this.sound.mozAudioChannelType = 'content'; + + window.sounds__[id] = this.sound; + this.src = url; + + this.start = function (pxLoader) { + // we need the loader ref so we can notify upon completion + loader = pxLoader; + + + self.sound['src'] = self.src; + self.sound.mozAudioChannelType = 'content'; + loader.onLoad(self); + }; + + this.checkStatus = function () { + switch (self.sound['readyState']) { + case 0: // uninitialised + case 1: // loading + break; + case 2: // failed/error + loader.onError(self); + break; + case 3: // loaded/success + loader.onLoad(self); + break; + } + }; + + this.onTimeout = function () { + loader.onTimeout(self); + }; + + this.getName = function () { + return url; + } + } + + // add a convenience method to PxLoader for adding a sound + PxLoader.prototype.addSound = function (id, url, tags, priority) { + var soundLoader = new PxLoaderSound(id, url, tags, priority); + this.add(soundLoader); + return soundLoader.sound; + }; + + return PxLoaderSound; +}); +define('resources/SoundLoader', + [ + 'platform', + 'edition', + 'resources/ResData', + 'resources/Sounds', + 'PxLoader', + 'PxLoaderSound' + ], + function (platform, edition, resData, Sounds, PxLoader, PxLoaderSound) { + + var completeListeners = [], + startRequested = false, + soundManagerReady = false, + startIfReady = function () { + // ensure start was requested and we are ready + if (!startRequested || !soundManagerReady) { + return; + } + + var pxLoader = new PxLoader({ 'noProgressTimeout': 30 * 1000 }), // stop waiting after 30 secs + baseUrl = platform.audioBaseUrl, + extension = platform.getAudioExtension(), + MENU_TAG = 'MENU', + i, len, soundId, soundUrl; + + // menu sounds first + for (i = 0, len = edition.menuSoundIds.length; i < len; i++) { + soundId = edition.menuSoundIds[i]; + soundUrl = baseUrl + resData[soundId].path + extension; + + // SoundManager2 wants a sound id which a char prefix + pxLoader.addSound('s' + soundId, soundUrl, MENU_TAG); + } + + // now game sounds + for (i = 0, len = edition.gameSoundIds.length; i < len; i++) { + soundId = edition.gameSoundIds[i]; + soundUrl = baseUrl + resData[soundId].path + extension; + + // SoundManager2 wants a sound id which a char prefix + pxLoader.addSound('s' + soundId, soundUrl); + } + + // wait for all sounds before showing main menu + pxLoader.addCompletionListener(function () { + for (var i = 0, len = completeListeners.length; i < len; i++) { + completeListeners[i](); + } + }); + + pxLoader.start(); + }; + + var SoundLoader = { + start: function () { + startRequested = true; + startIfReady(); + }, + onMenuComplete: function (callback) { + completeListeners.push(callback); + } + }; + + Sounds.onReady(function () { + soundManagerReady = true; + startIfReady(); + }); + + return SoundLoader; + } +); + + +define('PxLoaderImage',['PxLoader'], function (PxLoader) { + + /** + * PxLoader plugin to load images + */ + function PxLoaderImage(url, tags, priority) { + var self = this, + loader = null; + + this.img = new Image(); + this.tags = tags; + this.priority = priority; + + var onReadyStateChange = function () { + if (self.img.readyState == 'complete') { + removeEventHandlers(); + loader.onLoad(self); + } + }; + + var onLoad = function () { + removeEventHandlers(); + loader.onLoad(self); + }; + + var onError = function () { + removeEventHandlers(); + loader.onError(self); + }; + + var removeEventHandlers = function () { + self.unbind('load', onLoad); + self.unbind('readystatechange', onReadyStateChange); + self.unbind('error', onError); + }; + + this.start = function (pxLoader) { + // we need the loader ref so we can notify upon completion + loader = pxLoader; + + // NOTE: Must add event listeners before the src is set. We + // also need to use the readystatechange because sometimes + // load doesn't fire when an image is in the cache. + self.bind('load', onLoad); + self.bind('readystatechange', onReadyStateChange); + self.bind('error', onError); + + self.img.src = url; + }; + + // called by PxLoader to check status of image (fallback in case + // the event listeners are not triggered). + this.checkStatus = function () { + if (self.img.complete) { + removeEventHandlers(); + loader.onLoad(self); + } + }; + + // called by PxLoader when it is no longer waiting + this.onTimeout = function () { + removeEventHandlers(); + if (self.img.complete) { + loader.onLoad(self); + } + else { + loader.onTimeout(self); + } + }; + + // returns a name for the resource that can be used in logging + this.getName = function () { + return url; + }; + + // cross-browser event binding + this.bind = function (eventName, eventHandler) { + if (self.img.addEventListener) { + self.img.addEventListener(eventName, eventHandler, false); + } else if (self.img.attachEvent) { + self.img.attachEvent('on' + eventName, eventHandler); + } + }; + + // cross-browser event un-binding + this.unbind = function (eventName, eventHandler) { + if (self.img.removeEventListener) { + self.img.removeEventListener(eventName, eventHandler, false); + } else if (self.img.detachEvent) { + self.img.detachEvent('on' + eventName, eventHandler); + } + }; + + } + + // add a convenience method to PxLoader for adding an image + PxLoader.prototype.addImage = function (url, tags, priority) { + var imageLoader = new PxLoaderImage(url, tags, priority); + this.add(imageLoader); + + // return the img element to the caller + return imageLoader.img; + }; + + return PxLoaderImage; +}); +define('LoadAnimation',[], function () { + + // no load animation in packaged chrome application + return null; +}); +// responsible for preloading resources. It would be nice to use a single +// loader for both images and sound, but the init of SoundManager2 prevents +// queuing sounds before its ready. So for now, we'll keep the sound manager +// loading separate so we don't have to wait to begin loading images. + +define('resources/PreLoader', + [ + 'platform', + 'edition', + 'editionUI', + 'resolution', + 'resources/ResData', + 'resources/SoundLoader', + 'PxLoader', + 'PxLoaderImage', + 'LoadAnimation', + 'resources/ResourceMgr', + 'resources/ResourcePacks' + ], + function (platform, edition, editionUI, resolution, resData, SoundLoader, PxLoader, PxLoaderImage, LoadAnimation, ResourceMgr, ResourcePacks) { + + var menuImagesLoadComplete = false, + menuSoundLoadComplete = false, + completeCallback = null, + checkMenuLoadComplete = function () { + if (!menuImagesLoadComplete || !menuSoundLoadComplete) { + return; + } + + if (LoadAnimation) { + LoadAnimation.notifyLoaded(); + LoadAnimation.hide(); + } + + if (completeCallback) { + // queue the execution of the callback so the loader can + // finish notifying listeners first + setTimeout(completeCallback, 0); + } + + // ensure the completion is only run once + checkMenuLoadComplete = function () { + }; + }; + + var loadImages = function () { + var pxLoader = new PxLoader({ 'noProgressTimeout': 30 * 1000 }), // stop waiting after 30 secs + gameBaseUrl = platform.imageBaseUrl + resolution.CANVAS_WIDTH + '/game/', + MENU_TAG = 'MENU', + FONT_TAG = 'FONT', + GAME_TAG = 'GAME', + i, len, imageUrl; + + // first menu images + var queueMenuImages = function (imageFilenames, menuBaseUrl) { + if (!imageFilenames) { + return; + } + + menuBaseUrl = menuBaseUrl || platform.uiImageBaseUrl; + for (i = 0, len = imageFilenames.length; i < len; i++) { + if (!imageFilenames[i]) { + continue; + } + imageUrl = menuBaseUrl + imageFilenames[i]; + pxLoader.addImage(imageUrl, MENU_TAG); + } + }; + + // queue page images first, the game can wait (we have a load animation) + var passwordPath = platform.imageBaseUrl + (editionUI.passwordDirectory || ''); + queueMenuImages(editionUI.passwordImageNames, passwordPath); + + var passwordResolutionPath = platform.resolutionBaseUrl + (editionUI.passwordResolutionDirectory || ''); + queueMenuImages(editionUI.passwordResolutionImageNames, passwordResolutionPath); + + queueMenuImages(editionUI.pageImageNames, platform.imageBaseUrl + 'page/'); + queueMenuImages(editionUI.pageResolutionImageNames, platform.resolutionBaseUrl + 'page/'); + queueMenuImages(edition.menuImageFilenames); + queueMenuImages(edition.boxImages, platform.boxImageBaseUrl); + queueMenuImages(edition.boxBorders); + queueMenuImages(edition.boxDoors); + + queueMenuImages(edition.drawingImageNames); + + var editionBaseUrl = platform.resolutionBaseUrl + (edition.editionImageDirectory || ''); + queueMenuImages(edition.editionImages, editionBaseUrl); + + // only report progress on the menu images and fonts + pxLoader.addProgressListener(function (e) { + var p = 100 * (e.completedCount / e.totalCount); + if (LoadAnimation) { + LoadAnimation.notifyLoadProgress(p); + } + + if (e.completedCount === e.totalCount) { + menuImagesLoadComplete = true; + checkMenuLoadComplete(); + } + }, [ MENU_TAG, FONT_TAG ]); + + // next fonts and game images + var queueForResMgr = function (ids, tag) { + var i, len, imageId; + for (i = 0, len = ids.length; i < len; i++) { + imageId = ids[i]; + var pxImage = new PxLoaderImage( + gameBaseUrl + resData[imageId].path, + tag); + + // add the resId so we can find it upon completion + pxImage.resId = imageId; + pxLoader.add(pxImage); + } + }; + queueForResMgr(ResourcePacks.StandardFonts, FONT_TAG); + queueForResMgr(edition.gameImageIds, GAME_TAG); + queueForResMgr(edition.levelBackgroundIds, GAME_TAG); + queueForResMgr(edition.levelOverlayIds, GAME_TAG); + + // tell the resource manager about game images and fonts + pxLoader.addProgressListener(function (e) { + ResourceMgr.onResourceLoaded(e.resource.resId, e.resource.img); + }, [ FONT_TAG, GAME_TAG ]); + + pxLoader.start(); + }; + + var PreLoader = { + init: function () { + ResourceMgr.init(); + + // start the loading animation images first + if (LoadAnimation) { + LoadAnimation.init(); + } + + // next start the images + loadImages(); + + // now start the sounds + SoundLoader.onMenuComplete(function () { + menuSoundLoadComplete = true; + checkMenuLoadComplete(); + }); + SoundLoader.start(); + }, + domReady: function () { + if (LoadAnimation) { + LoadAnimation.domReady(); + LoadAnimation.show(); + } + }, + run: function (onComplete) { + completeCallback = onComplete; + checkMenuLoadComplete(); + } + }; + + return PreLoader; + } +); + + +define('game/RoamSettings', + [ + 'edition', + 'utils/PubSub' + ], + function (edition, PubSub) { + + var currentUserId = ''; + PubSub.subscribe(PubSub.ChannelId.UserIdChanged, function (userId) { + currentUserId = userId; + }); + + var roamingProvider = null; + PubSub.subscribe(PubSub.ChannelId.RoamingSettingProvider, function (provider) { + + // copy methods (which will be minified) + if (provider) { + roamingProvider = { + set: provider['set'], + get: provider['get'], + remove: provider['remove'] + }; + } else { + roamingProvider = null; + } + + PubSub.publish(PubSub.ChannelId.RoamingDataChanged); + }); + + var SCORES_PREFIX = 'scores', + STARS_PREFIX = 'stars', + ACHIEVEMENTS_PREFIX = 'achievements'; + + // appends the current user's id to the key prefix + function getFullKey(prefix, boxIndex) { + var key = prefix; + if (currentUserId) { + key += ('-' + currentUserId); + } + + return key; + } + + /* Unfortunately Windows doesn't tell us which value changed. Keeping this + code in case we ever intergrate with another settings store that does + function onSettingChanged(key, value) { + + var parts = (key || '').split('-'); + if (parts.length === 0) { + return; + } + + var userId, boxIndex, levelIndex, achievementIndex; + switch(parts[0]) { + case SCORES_PREFIX: + case STARS_PREFIX: + var userId = (parts.length === 3) ? parts[2] : ''; + if (userId === currentUserId) { + // only need to change data for current user + } + break; + case ACHIEVEMENTS_PREFIX: + var userId = (parts.length === 2) ? parts[1] : ''; + if (userId === currentUserId) { + // only need to change data for current user + } + break; + } + } + */ + + // deserializes hex (and possibly undefined or null values) from a string + function getHexValues(keyPrefix) { + + if (!roamingProvider) { + return null; + } + + var key = getFullKey(keyPrefix), + values = [], + rawValues = (roamingProvider.get(key) || '').split(','), // split csv + len = rawValues.length, + i, val; + + for (i = 0; i < len; i++) { + if (i < rawValues.length) { + + // parse value which is stored in hex + val = parseInt(rawValues[i], 16); + if (isNaN(val)) { + val = null; + } + } else { + val = null; + } + values.push(val); + } + + return values; + } + + // serializes numbers into hex CSVs with compact nulls + function saveHexValues(keyPrefix, values) { + if (!roamingProvider) { + return null; + } + + var key = getFullKey(keyPrefix); + + if (!values) { + roamingProvider.remove(key); + } else { + var rawValues = [], + len = values.length, + i, val; + + for (i = 0; i < len; i++) { + val = values[i]; + if (val == null) { + // we have limited storage space so we'll shorten null values + rawValues.push(''); + } else { + // encode values as hex + rawValues.push(val.toString(16)) + } + } + + // save comma separated values + roamingProvider.set(key, rawValues.join(',')); + } + } + + function getValue(keyPrefix, index) { + if (!roamingProvider) { + return null; + } + + var values = getHexValues(keyPrefix); + return (values.length > index) ? values[index] : null; + } + + function saveValue(keyPrefix, index, value) { + if (!roamingProvider) { + return; + } + + var values = getHexValues(keyPrefix), + prevValue = values[index]; + + // only write if value has changed + if (prevValue !== value) { + values[index] = value; + saveHexValues(keyPrefix, values); + } + } + + var RoamingSettings = { + + // scores + getScore: function(boxIndex, levelIndex) { + return getValue(SCORES_PREFIX + '-' + boxIndex, levelIndex); + }, + setScore: function(boxIndex, levelIndex, score) { + saveValue(SCORES_PREFIX + '-' + boxIndex, levelIndex, score); + }, + + // stars + getStars: function(boxIndex, levelIndex) { + return getValue(STARS_PREFIX + '-' + boxIndex, levelIndex); + }, + setStars: function(boxIndex, levelIndex, stars) { + saveValue(STARS_PREFIX + '-' + boxIndex, levelIndex, stars); + }, + + // achievement counts + getAchievementCount: function(achievementIndex) { + return getValue(ACHIEVEMENTS_PREFIX, achievementIndex); + }, + setAchievementCount: function(achievementIndex, count) { + saveValue(ACHIEVEMENTS_PREFIX, achievementIndex, count); + } + }; + + + return RoamingSettings; + } +); +define('ui/ScoreManager', + [ + 'ui/QueryStrings', + 'utils/PubSub', + 'utils/MathHelper', + 'core/SettingStorage', + 'edition', + 'visual/Text', + 'resources/Lang', + 'resources/LangId', + 'resources/MenuStringId', + 'game/RoamSettings' + ], + function (QueryStrings, PubSub, MathHelper, SettingStorage, edition, Text, + Lang, LangId, MenuStringId, RoamSettings) { + + // we use XOR to obfuscate the level scores to discourage cheats. Doesn't + // prevent hacks - server side code would be necessary for that. + + // make the prefixes hard to find in source code + var SCORE_PREFIX = String.fromCharCode(98, 112), // 'bp' (short for box-points) + STARS_PREFIX = String.fromCharCode(98, 115), // 'bs' (short for box-stars) + + // our XOR value is a random number that is stored in an entry that is + // intended to look similar to the score record for a box + XOR_KEY = SCORE_PREFIX + String.fromCharCode(50, 51, 57, 48), + XOR_VALUE = SettingStorage.getIntOrDefault(XOR_KEY, null); + + // create the random value if it doesn't exist + if (XOR_VALUE == null) { + XOR_VALUE = MathHelper.randomRange(1000, 10000); + SettingStorage.set(XOR_KEY, XOR_VALUE); + } + + // helper functions to get/set score + var getScoreKey = function (box, level) { + var val = ((box * 1000) + level) ^ XOR_VALUE, + key = SCORE_PREFIX + val; + + // make sure we don't overwrite our XOR key + if (key === XOR_KEY) { + return key + '_'; + } + + return key; + }, + setScore = function (box, level, points) { + + SettingStorage.set( + getScoreKey(box, level), + // NOTE: we intentionally swap multiplier to level (key uses box) + (points + (level * 1000) + box) ^ XOR_VALUE + ); + + RoamSettings.setScore(box, level, points); + }, + getScore = function (box, level) { + // fetch both roaming and local scores + var roamScore = RoamSettings.getScore(box, level) || 0, + localKey = getScoreKey(box, level), + localVal = SettingStorage.getIntOrDefault(localKey, null), + localScore = (localVal == null) ? 0 : + (localVal ^ XOR_VALUE) - box - (level * 1000); + + return Math.max(roamScore, localScore); + }; + + // helper functions to get/set stars + var STARS_UNKNOWN = -1, // needs to be a number but can't be null + getStarsKey = function (box, level) { + // NOTE: we intentionally swap multiplier from whats used for points + var key = ((level * 1000) + box) ^ XOR_VALUE; + return STARS_PREFIX + key; + }, + setStars = function (box, level, stars) { + var localStars = (stars == null) ? STARS_UNKNOWN : stars; + SettingStorage.set( + getStarsKey(box, level), + // NOTE: we intentionally swap multiplier to box (key uses level) + (localStars + (box * 1000) + level) ^ XOR_VALUE + ); + + RoamSettings.setStars(box, level, stars); + }, + getStars = function (box, level) { + + var roamStars = RoamSettings.getStars(box, level), + localKey = getStarsKey(box, level), + localVal = SettingStorage.getIntOrDefault(localKey, null), + localStars = (localVal == null) ? null : + (localVal ^ XOR_VALUE) - level - (box * 1000); + + if (localStars === STARS_UNKNOWN || localStars === null) { + return roamStars; + } else if (roamStars == null) { + return localStars; + } + + return Math.max(roamStars, localStars); + }; + + var resetLevel = function (boxIndex, levelIndex) { + // first level gets 0 stars, otherwise null + var stars = (levelIndex === 0) ? 0 : null; + + setStars(boxIndex, levelIndex, stars); + setScore(boxIndex, levelIndex, 0); + }; + + var ScoreBox = function (levelCount, requiredStars, scores, stars) { + this.levelCount = levelCount; + this.requiredStars = requiredStars; + this.scores = scores || []; + this.stars = stars || []; + }; + + var ScoreManager = new function () { + + var boxes = []; + + this.load = function() { + + // clear existing boxes + boxes.length = 0; + + // load box scores + for (var i = 0, len = edition.boxes.length; i < len; i++) { + boxes[i] = loadBox(i); + } + + // update score text + if (appReady) { + ScoreManager.updateTotalScoreText(); + } + }; + + PubSub.subscribe(PubSub.ChannelId.SignIn, this.load); + PubSub.subscribe(PubSub.ChannelId.SignOut, this.load); + PubSub.subscribe(PubSub.ChannelId.RoamingDataChanged, this.load); + + // the score text can only be updated when the app is ready + var appReady = false; + PubSub.subscribe(PubSub.ChannelId.AppRun, function() { appReady = true; }); + + // load previous scores from local storage + var loadBox = function (boxIndex) { + + // see if the box exists by checking for a level 1 star record + var boxExists = (getStars(boxIndex, 0) !== null), + levelCount = edition.boxes[boxIndex].levels.length, + requiredStars = edition.unlockStars[boxIndex], + scores = [], + stars = [], + levelIndex; + + // get (or create) scores and stars from each level + for (levelIndex = 0; levelIndex < levelCount; levelIndex++) { + + // if the box doesn't exist + if (!boxExists) { + resetLevel(boxIndex, levelIndex); + } + + scores.push(getScore(boxIndex, levelIndex)); + stars.push(getStars(boxIndex, levelIndex)); + } + + // generate fake (and good) star counts + if (QueryStrings.createScoresForBox == (boxIndex + 1)) { + for (var i = 0; i < levelCount; i++) { + ScoreManager.setStars(boxIndex, i, 3, true); + } + } + + return new ScoreBox(levelCount, requiredStars, scores, stars); + }; + + this.getXorValue = function() { + return XOR_VALUE; + }; + + this.boxCount = function () { + if (boxes != null) return boxes.length; + return null; + }; + + this.levelCount = function (boxIndex) { + var box = boxes[boxIndex]; + if (box != null) return box.levelCount; + return null; + }; + + this.requiredStars = function (boxIndex) { + var box = boxes[boxIndex]; + if (box != null) return box.requiredStars; + return 0; + }; + + this.achievedStars = function (boxIndex) { + var box = boxes[boxIndex]; + if (box != null) { + var count = 0; + for (var j = 0; j < box.levelCount; j++) { + var stars = box.stars[j]; + count += stars == null ? 0 : stars; + } + return count; + } + return 0; + }; + + this.totalStars = function () { + var total = 0; + for (var i = 0; i < boxes.length; i++) { + total += ScoreManager.achievedStars(i); + } + return total; + }; + + this.possibleStarsForBox = function (boxIndex) { + var box = boxes[boxIndex]; + if (box != null) { + return box.levelCount * 3; + } + return 0; + }; + + this.isBoxLocked = function (boxIndex) { + if (boxIndex == 0) return false; + if (QueryStrings.unlockAllBoxes) return false; + var box = boxes[boxIndex]; + if (box != null && (ScoreManager.totalStars() >= ScoreManager.requiredStars(boxIndex))) { + return false; + } + return true; + }; + + this.isLevelUnlocked = function (boxIndex, levelindex) { + var box = boxes[boxIndex]; + if (QueryStrings.unlockAllBoxes) return true; + if (box != null) { + return (box.stars[levelindex] != null); + } + return false; + }; + + this.setScore = function (boxIndex, levelIndex, levelScore, overridePrevious) { + var box = boxes[boxIndex]; + if (box != null) { + + if (overridePrevious) { + box.scores[levelIndex] = levelScore; + } else { + var prevScore = getScore(boxIndex, levelIndex); + box.scores[levelIndex] = Math.max(levelScore, prevScore); + } + + setScore(boxIndex, levelIndex, box.scores[levelIndex]); + + // sum all scores for the box + var numLevels = box.scores.length, + boxScore = 0, i; + for (i = 0; i < numLevels; i++) { + boxScore += box.scores[i]; + } + + // always report scores since we may have been offline when the + // previous high score was achieved. + PubSub.publish(PubSub.ChannelId.UpdateBoxScore, boxIndex, boxScore); + } + }; + + this.getScore = function (boxIndex, levelIndex) { + var box = boxes[boxIndex]; + if (box != null) return box.scores[levelIndex]; + return null; + }; + + this.setStars = function (boxIndex, levelIndex, score, overridePrevious) { + var previousStars = this.totalStars(), + box = boxes[boxIndex]; + if (box != null) { + + //don't override past high score + var prevStars = getStars(boxIndex, levelIndex); + if (prevStars != null && !overridePrevious) { + box.stars[levelIndex] = Math.max(score, prevStars); + } else { + box.stars[levelIndex] = score; + } + setStars(boxIndex, levelIndex, box.stars[levelIndex]); + } + + var newStarCount = this.totalStars(); + if (newStarCount !== previousStars) { + PubSub.publish(PubSub.ChannelId.StarCountChanged, newStarCount); + } + }; + + this.getStars = function (boxIndex, levelIndex) { + var box = boxes[boxIndex]; + if (box != null) return box.stars[levelIndex]; + return null; + }; + + this.resetGame = function () { + var boxCount = boxes.length, + boxIndex, + box, + levelIndex, + levelCount; + + for (boxIndex = 0; boxIndex < boxCount; boxIndex++) { + box = boxes[boxIndex]; + levelCount = box.levelCount; + for (levelIndex = 0; levelIndex < levelCount; levelIndex++) { + resetLevel(boxIndex, levelIndex); + box.stars[levelIndex] = getStars(boxIndex, levelIndex); + box.scores[levelIndex] = getScore(boxIndex, levelIndex); + } + } + + // update score + this.updateTotalScoreText(); + }; + + this.updateTotalScoreText = function () { + var text = Lang.menuText(MenuStringId.TOTAL_STARS) + .replace('%d', ScoreManager.totalStars()); + Text.drawBig({text: text, imgSel: '#boxScore img', scaleToUI: true }); + }; + + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, this.updateTotalScoreText); + + }; + + return ScoreManager; + } +); +define('ui/Easing', + [], + function () { + + // penner easing (we use for canvas animations) + + var Easing = new function () { + + //@t is the current time (or position) of the tween. This can be seconds or frames, steps, seconds, ms, whatever - as long as the unit is the same as is used for the total time [3]. + //@b is the beginning value of the property. + //@c is the change between the beginning and destination value of the property. + //@d is the total time of the tween. + + this.noEase = function (t, b, c, d) { + return c * t / d + b; + }; + this.easeOutCirc = function (t, b, c, d) { + return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; + }; + this.easeInCirc = function (t, b, c, d) { + return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; + }; + this.easeInOutCirc = function (t, b, c, d) { + if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; + return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; + }; + this.easeInSine = function (t, b, c, d) { + return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; + }; + this.easeOutSine = function (t, b, c, d) { + return c * Math.sin(t / d * (Math.PI / 2)) + b; + }; + this.easeInOutSine = function (t, b, c, d) { + return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; + }; + this.easeInCubic = function (t, b, c, d) { + return c * (t /= d) * t * t + b; + }; + this.easeOutCubic = function (t, b, c, d) { + return c * ((t = t / d - 1) * t * t + 1) + b; + }; + this.easeInOutCubic = function (t, b, c, d) { + if ((t /= d / 2) < 1) return c / 2 * t * t * t + b; + return c / 2 * ((t -= 2) * t * t + 2) + b; + }; + this.easeInExpo = function (t, b, c, d) { + return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; + }; + this.easeOutExpo = function (t, b, c, d) { + return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b; + }; + this.easeInOutExpo = function (t, b, c, d) { + if (t == 0) return b; + if (t == d) return b + c; + if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b; + return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; + }; + this.easeInBounce = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c * (t /= d) * t * ((s + 1) * t - s) + b; + }; + this.easeOutBounce = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; + }; + this.easeInOutBounce = function (t, b, c, d, s) { + if (s == undefined) s = 1.70158; + if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b; + return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b; + }; + this.easeInOutQuad = function (t, b, c, d) { + if ((t /= d / 2) < 1) return c / 2 * t * t + b; + return -c / 2 * ((--t) * (t - 2) - 1) + b; + }; + + }; + + return Easing; + } +); +define('ui/Box', + [ + 'utils/Class', + 'ui/Easing', + 'visual/Text', + 'resolution', + 'platform', + 'ui/BoxType', + 'utils/PubSub', + 'resources/Lang', + 'core/Alignment', + 'ui/ScoreManager', + 'resources/MenuStringId', + 'edition', + 'game/CTRSettings' + ], + function (Class, Easing, Text, resolution, platform, BoxType, PubSub, Lang, Alignment, ScoreManager, MenuStringId, edition, settings) { + + // cache upgrade UI elements + var $upgradeButton; + $(function() { + $upgradeButton = $('#boxUpgradePlate').hide(); + }); + + function hidePurchaseButton() { + if ($upgradeButton) { + $upgradeButton.fadeOut(200); + } + } + + PubSub.subscribe(PubSub.ChannelId.SetPaidBoxes, function(paid) { + if (paid) { + hidePurchaseButton(); + } + }); + + // localize UI element text + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + Text.drawBig({ + text: Lang.menuText(MenuStringId.BUY_FULL_GAME), + imgParentId: 'boxUpgradePlate', + scale: 0.6 * resolution.UI_TEXT_SCALE + }); + }); + + var boxImageBase = (platform.boxImageBaseUrl || platform.uiImageBaseUrl); + + var Box = Class.extend({ + + init: function (boxIndex, bgimg, reqstars, islocked, type) { + + this.index = boxIndex; + this.islocked = islocked; + this.visible = true; + + // initially we assume all boxes are included in the game + this.purchased = true; + + this.bounceStartTime = 0; + this.opacity = 1.0; + this.type = type; + + this.boxImg = new Image(); + + if (bgimg) { + this.boxImg.src = boxImageBase + bgimg; + } + + var textImg = this.textImg = new Image(), + boxWidth = this.boxWidth = resolution.uiScaledNumber(350), + boxTextMargin = this.boxTextMargin = resolution.uiScaledNumber(20), + self = this; + + + // console.log(boxTextMargin) + // this.boxTextMargin = 100; + // } + + this.textRendered = false; + this.renderText = function () { + Text.drawBig({ + text: Lang.boxText(boxIndex, self.includeBoxNumberInTitle), + img: textImg, + width: (boxWidth - (boxTextMargin * 2)) / resolution.UI_TEXT_SCALE, + alignment: Alignment.HCENTER, + scaleToUI: true + }); + + self.textRendered = true; + }; + + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, this.renderText); + + this.reqImg = Text.drawBig({ text: reqstars, scaleToUI: true }); + + this.omNomImg = new Image(); + this.omNomImg.src = platform.uiImageBaseUrl + 'box_omnom.png'; + + this.lockImg = new Image(); + this.lockImg.src = platform.uiImageBaseUrl + 'box_lock.png'; + + this.starImg = new Image(); + this.starImg.src = platform.uiImageBaseUrl + 'star_result_small.png'; + + this.perfectMark = new Image(); + this.perfectMark.src = platform.uiImageBaseUrl + 'perfect_mark.png'; + + this.includeBoxNumberInTitle = true; + }, + + isRequired: function () { + return true; + }, + + isGameBox: function() { + return true; + }, + + isClickable: function() { + return true; + }, + + draw: function(ctx, omnomoffset) { + + var prevAlpha = ctx.globalAlpha; + if (this.opacity !== prevAlpha) { + ctx.globalAlpha = this.opacity; + } + + // render the box + this.render(ctx, omnomoffset); + + // restore alpha + if (this.opacity !== prevAlpha) { + ctx.globalAlpha = prevAlpha; + } + }, + + render: function (ctx, omnomoffset) { + + var isGameBox = this.isGameBox(); + if (isGameBox) { + // draw the black area + ctx.fillStyle = "rgb(45,45,53)"; + ctx.fillRect(resolution.uiScaledNumber(130), resolution.uiScaledNumber(200), + resolution.uiScaledNumber(140), resolution.uiScaledNumber(100)); + + // draw omnom + if (omnomoffset != null) { + ctx.drawImage(this.omNomImg, omnomoffset + resolution.uiScaledNumber(4), resolution.uiScaledNumber(215)); + } + } + + // draw the box image + ctx.drawImage(this.boxImg, resolution.uiScaledNumber(25), resolution.uiScaledNumber(0)); + + if (isGameBox) { + // draw the lock + if (this.islocked) { + + // prefer css dimensions (scaled) for text + var textWidth = $(this.reqImg).width() || this.reqImg.width, + textHeight = $(this.reqImg).height() || this.reqImg.height, + + // ok to use raw image width for star (image already scaled) + starWidth = this.starImg.width || $(this.starImg).width(), + starLeftMargin = resolution.uiScaledNumber(-6), + + // center the text and star label + labelWidth = textWidth + starLeftMargin + starWidth, + labelMaxWidth = resolution.uiScaledNumber(125), + labelOffsetX = (labelMaxWidth - labelWidth) / 2, + labelMinX = resolution.uiScaledNumber(140), + labelX = labelMinX + labelOffsetX; + + // slightly scale the lock image (not quite big enough for our boxes) + // TODO: should resize lock images for every resolution and remove scaling + // TODO: also need to normalize the size of boxes (which vary) + ctx.scale(1.015, 1); + ctx.drawImage(this.lockImg, resolution.uiScaledNumber(23), + resolution.uiScaledNumber(155)); + ctx.scale(1 / 1.015, 1); + + if (this.purchased) { + ctx.drawImage(this.reqImg, labelX, + resolution.uiScaledNumber(220), textWidth, textHeight); + ctx.drawImage(this.starImg, labelX + textWidth + starLeftMargin, + resolution.uiScaledNumber(225)); + } + + /* + // DEBUG: draw red dots to show the label boundaries + ctx.fillStyle= 'red'; + ctx.beginPath(); + ctx.arc(labelMinX, resolution.uiScaledNumber(220), 5, 0, 2*Math.PI, false); + ctx.fill(); + + ctx.beginPath(); + ctx.arc(labelMinX + labelMaxWidth, resolution.uiScaledNumber(220), 5, 0, 2*Math.PI, false); + ctx.fill(); + */ + } + + // draw the perfect mark if user got every star in the box + if (ScoreManager.achievedStars(this.index) === + ScoreManager.possibleStarsForBox(this.index)) { + ctx.drawImage( + this.perfectMark, + resolution.uiScaledNumber(260), + resolution.uiScaledNumber(250)); + } + } + + // draw the text + if (!this.textRendered) { + this.renderText(); + } + + var $textImg = $(this.textImg), + textWidth = $textImg.width() || this.textImg.width, + textHeight = $textImg.height() || this.textImg.height, + x = ~~(resolution.uiScaledNumber(25) + this.boxTextMargin + + (this.boxWidth - (this.boxTextMargin * 2) - textWidth) / 2), + y = resolution.uiScaledNumber(70); + + ctx.drawImage(this.textImg, x, y); + }, + + bounce: function (ctx) { + + if (!ctx) { + return; + } + + this.bounceStartTime = Date.now(); + + // stage boundaries in msec + var s1 = 100, s2 = 300, s3 = 600, + w = resolution.uiScaledNumber(1024), + h = resolution.uiScaledNumber(576); + + var self = this, + renderBounce = function () { + + // get the elapsed time + t = Date.now() - self.bounceStartTime; + + var d, x, y; + + if (t < s1) { + d = Easing.easeOutSine(t, 0, 0.05, s1); // to 0.95 + x = 1.0 - d; + y = 1.0 + d; + } + else if (t < s2) { + d = Easing.easeInOutCubic(t - s1, 0, 0.11, s2 - s1); // to 0.95 + x = 0.95 + d; + y = 1.05 - d; + } + else if (t < s3) { + // intentionally not ending at 1.0 prevents the animation from "snapping" at the end. + // it's not a great hack, but the animation ends up much smoother (esp. in IE) + d = Easing.easeOutCubic(t - s2, 0, 0.05, s3 - s2); // to 0.95 + x = 1.06 - d; + y = 0.94 + d; + } + + var tx = (w - (w * x)) / 2.0, + ty = (h - (h * y)) / 2.0, + sx = (w - (2.0 * tx)) / w, + sy = (h - (2.0 * ty)) / h; + + if (!isNaN(sx) && !isNaN(sy)) { + + ctx.save(); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(resolution.uiScaledNumber(312), resolution.uiScaledNumber(100), + resolution.uiScaledNumber(400), resolution.uiScaledNumber(460)); + ctx.restore(); + + ctx.save(); + ctx.scale(sx, sy); + ctx.translate(tx, ty); + ctx.translate(resolution.uiScaledNumber(312), resolution.uiScaledNumber(130)); + self.draw(ctx, resolution.uiScaledNumber(140)); + ctx.restore(); + } + + if (t > s3) { + self.bounceStartTime = 0; + } else { + window.requestAnimationFrame(renderBounce); + } + }; + + // start the animation + renderBounce(); + + }, + + cancelBounce: function () { + this.bounceStartTime = 0; + }, + + onSelected: function () { + if (!this.purchased) { + $upgradeButton + .toggleClass('purchaseBox', this.isPurchaseBox || false) + .fadeIn(); + } + }, + + onUnselected: function () { + hidePurchaseButton(); + } + + }); + + + return Box; + } +); +define('analytics',[], function () { + + // just what the filename says: no analytics + return {}; +}); +define('ui/PinnedBox', + [ + 'ui/Box', + 'ui/QueryStrings', + 'resources/Lang', + 'resources/MenuStringId', + 'utils/PubSub', + 'edition', + 'visual/Text', + 'platform', + 'analytics', + 'resolution', + 'core/SettingStorage' + ], + function (Box, QueryStrings, Lang, MenuStringId, PubSub, edition, Text, platform, analytics, resolution, SettingStorage) { + + /** + * @enum {number} + */ + var PinnedStates = { + UNDEFINED: -1, // unknown pinned state + HIDDEN: 0, // hidden, probably because the OS d + VISIBLE: 1, // visible and completely playable + PROMPT_IE: 2, // visible but with a prompt to install IE + PROMPT_PIN: 3 // visible but with a prompt to pin the game + }; + + var PinnedBox = Box.extend({ + init: function (boxIndex, bgimg, reqstars, islocked, type) { + this._super(boxIndex, bgimg, reqstars, islocked, type); + this.pinnedState = PinnedStates.UNDEFINED; + this.promptId = null; + + // dom ready init + var self = this; + $(document).ready(function() { + $('#showMeBtn').click(function () { + if (analytics.onShowPinning) { + analytics.onShowPinning(); + } + self.showMePinning(); + }); + + // We'll only get download links for vista and win7. For win8 + // the url is null and we will hide the button (since the user + // already has IE10 installed) + var $getIeButton = $('#installieBtn'), + ieDownload = getIE9DownloadUrl(); + if (ieDownload) { + $getIeButton.on('click', function (e) { + if (analytics.onDownloadIE) { + analytics.onDownloadIE(); + } + window.location.href = ieDownload; + }); + + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + Text.drawBig({ + text: Lang.menuText(MenuStringId.FREE_DOWNLOAD), + img: $getIeButton.find('img')[0], + scaleToUI: true }); + }); + } + else { + $getIeButton.hide(); + } + }); + }, + + isRequired: function () { + // returns true if the box is enabled on the platform. this doesn't always + // mean it is unlocked. For example, in Chrome on Windows, we'll tell + // the user to install IE. On IE, they need to pin the game first. However + // there is no IE on mac so the box is completely disabled. + + return (this.pinnedState !== PinnedStates.HIDDEN); + }, + + initPinnedState: function () { + // returns the version of Internet Explorer or a -1 if another browser + var getIEVersion = function () { + var rv = -1; // Return value assumes failure. + return rv; + if (navigator.appName == 'Microsoft Internet Explorer' || navigator.appName == "MSAppHost/1.0") { + var ua = navigator.userAgent, + re = new RegExp("MSIE ([0-9]?[0-9]{1,}[\.0-9]{0,})"), + matches = re.exec(ua); + if (matches != null && matches.length > 1) { + // first entry is the original string followed by matches + // so index 1 is the first match + rv = parseInt(matches[1], 10); + } + } + return rv; + }; + + // returns a bool indiciating whether IE can run on the current OS + var getIECapableOS = function () { + return false; + try { + var u = navigator.userAgent; + var isWindows = u.indexOf("Windows NT") != -1; + var majVersion = isWindows ? parseInt(u[u.indexOf("Windows NT") + 11]) : -1; + if (isWindows && majVersion >= 6) return true; + } + catch (ex) { + return false; + } + return false; + }; + + // what version of IE are we running (or -1 for non-IE) + var ieVer = getIEVersion(); + + // are we using an OS (Vista or up) that supports IE + var ieCan = getIECapableOS(); + + // are we in IE9 or greater + if (ieVer >= 9 || QueryStrings.forcePinnedBox) { + + var localStorageIsPinned = (platform.ENABLE_PINNED_MODE || (SettingStorage.get("msIsSiteModeActivated") == "true")), + msIsSiteMode = (platform.ENABLE_PINNED_MODE === true); + + // no way to check if this function exists, we have to use try/catch + if (!msIsSiteMode) { + try { + if (window.external.msIsSiteMode()) { + msIsSiteMode = true; + } + } catch (ex) { + } + } + + // is the site pinned + if (localStorageIsPinned || msIsSiteMode || QueryStrings.forcePinnedBox) { + + // show the pinned box with all levels unlocked + this.pinnedState = PinnedStates.VISIBLE; + this.opacity = 1.0; + this.promptId = null; + + // show the first time after being pinned message and save the state + if (!localStorageIsPinned) { + SettingStorage.set("msIsSiteModeActivated", "true"); + if (analytics.onSitePinned) { + analytics.onSitePinned(); + } + } + } + else { + // we're in IE9 but not pinned so show instructions for pinning + this.pinnedState = PinnedStates.PROMPT_PIN; + this.opacity = 0.35; + this.promptId = "pinPrompt"; + + var self = this; + + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + Text.drawBig({ + text: Lang.menuText(MenuStringId.SHOW_ME), + imgSel: '#showMeBtn img', + scaleToUI: true }); + }); + } + } + else if (ieCan) { + this.pinnedState = PinnedStates.PROMPT_IE; + this.opacity = 0.35; + this.promptId = "iePrompt"; + } + else { + // we're not in incompatible OS so do nothing (keep the box hidden) and move the final box forward + this.pinnedState = PinnedStates.HIDDEN; + this.opacity = 0.35; + this.promptId = null; + } + + // return a bool indicating whether the box should be added to the boxes collection + if (this.pinnedState == PinnedStates.HIDDEN || this.pinnedState == PinnedStates.UNDEFINED) { + return false; + } + else { + return true; + } + }, + + onSelected: function () { + if (this.promptId != null) { + $("#pinningContent").stop(true, true).delay(100).fadeIn(800); + $("#" + this.promptId).show(); + } + }, + + onUnselected: function () { + if (this.promptId != null) { + $("#pinningContent").stop(true, true).fadeOut(300); + } + }, + + // runs (and the resets) the "show me" animation for the pinned box + showMePinning: function () { + var cursor = $("#pinCursor"); + var omnom = $("#pinOmNom"); + var shadow = $("#pinChairShadow"); + var button = $("#showMeBtn"); + var taskbar = $("#pinTaskBar"); + button.fadeOut().delay(5500).fadeIn(1000); + shadow.delay(500).fadeOut().delay(6000).fadeIn(300); + cursor.delay(500).fadeIn().delay(2250).animate({ 'left': resolution.uiScaledNumber(200) }, 500, + "easeInOutCirc").fadeOut().animate({ 'top': resolution.uiScaledNumber(65), 'left': resolution.uiScaledNumber(45), scale: '1.0' }, + 0); + omnom.delay(500).fadeIn().delay(1000).animate({ 'top': resolution.uiScaledNumber(305), 'left': resolution.uiScaledNumber(165) }, + 1000, "easeInOutBack").delay(1500).animate({ scale: '0.65' }, + 200).delay(1500).fadeOut(1000).animate({ 'top': resolution.uiScaledNumber(115), 'left': resolution.uiScaledNumber(-49), scale: '1.0' }, + 50).fadeIn(500); + taskbar.delay(500).fadeIn().delay(5000).fadeOut(1000); + } + }); + + return PinnedBox; + } +); + +define('ui/PurchaseBox', + [ + 'ui/Box', + 'utils/PubSub', + 'resources/Lang', + 'visual/Text', + 'resources/MenuStringId', + 'resolution', + 'core/Alignment' + ], + function (Box, PubSub, Lang, Text, MenuStringId, resolution, Alignment) { + + // cache upgrade UI elements + var $upgradePrompt, $upgradeButton; + $(function() { + $upgradePrompt = $('#boxUpgradePrompt').hide(); + $upgradeButton = $('#boxUpgradeButton').hide() + .click(function() { + PubSub.publish(PubSub.ChannelId.PurchaseBoxesPrompt); + }); + }); + + // localize UI element text + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + Text.drawBig({ + text: Lang.menuText(MenuStringId.UPGRADE_TO_FULL), + imgParentId: 'boxUpgradePrompt', + width: resolution.uiScaledNumber(650), + alignment: Alignment.CENTER, + scaleToUI: true + }); + + Text.drawBig({ + text: Lang.menuText(MenuStringId.BUY_FULL_GAME), + imgParentId: 'boxUpgradeButton', + scale: 0.6 * resolution.UI_TEXT_SCALE + }); + }); + + var PurchaseBox = Box.extend({ + init: function (boxIndex, bgimg, reqstars, islocked, type) { + this._super(boxIndex, bgimg, reqstars, islocked, type); + this.purchased = false; + this.includeBoxNumberInTitle = false; + this.isPurchaseBox = true; + }, + + isRequired: function () { + // not a box required for game completion + return false; + }, + + isGameBox: function() { + return false; + }, + + onSelected: function () { + $upgradePrompt.fadeIn(); + $upgradeButton.fadeIn(); + }, + + onUnselected: function () { + $upgradePrompt.fadeOut(); + $upgradeButton.fadeOut(200); + } + + }); + + return PurchaseBox; + } +); + +define('ui/MoreComingBox', + [ + 'ui/Box' + ], + function (Box) { + + var MoreComingBox = Box.extend({ + init: function (boxIndex, bgimg, reqstars, islocked, type) { + this._super(boxIndex, bgimg, reqstars, islocked, type); + this.includeBoxNumberInTitle = false; + }, + + isRequired: function () { + // not a box required for game completion + return false; + }, + + isGameBox: function() { + return false; + }, + + isClickable: function() { + return false; + } + + }); + + return MoreComingBox; + } +); + +define('ui/TimeBox', + [ + 'utils/Class', + 'ui/Box', + 'visual/Text', + 'resolution', + 'platform', + 'ui/BoxType', + 'utils/PubSub', + 'resources/Lang', + 'core/Alignment', + 'ui/ScoreManager', + 'resources/MenuStringId', + 'ui/QueryStrings', + 'edition', + 'utils/MathHelper', + 'core/SettingStorage' + ], + function (Class, Box, Text, resolution, platform, BoxType, PubSub, Lang, Alignment, ScoreManager, + MenuStringId, QueryStrings, edition, MathHelper, SettingStorage) { + + // promotion runs from March 4 - April 14 + // using ticks makes finding hacking more difficult because + // you can't search the code for well known dates + var BoxOpenDates = [ + 1362384000000, // Mar 4 + 1362985200000, // Mar 11 + 1363590000000, // Mar 18 + 1364194800000, // Mar 25 + 1364799600000, // Apr 1 + 1365404400000 // Apr 8 + ]; + + // for testing the date locks + if (true) { + BoxOpenDates = [ + new Date(), // open now + new Date(), // open now + new Date(), // open now + 1364194800000, // Mar 25 + 1364799600000, // Apr 1 + 1365404400000 // Apr 8 + ]; + }; + + // The random seeds that will be XOR'd with the user's unique value + // to create the keys used to store the status of each box unlock + var BoxKeySeeds = [ + 9240, + 7453, + 3646, + 7305, + 5093, + 3829 + ]; + + var LOCK_KEY_PREFIX = String.fromCharCode(98, 107), // prefix is 'bk' + XOR_VALUE = ScoreManager.getXorValue(), + getLockKey = function(boxIndex) { + return LOCK_KEY_PREFIX + (BoxKeySeeds[boxIndex] ^ XOR_VALUE); + }, + isLocked = function(boxIndex) { + var key = getLockKey(boxIndex), + value = SettingStorage.getIntOrDefault(key, 0), + correctValue = (BoxKeySeeds[boxIndex] - 1000) ^ XOR_VALUE; + + return (value !== correctValue && !QueryStrings.unlockAllBoxes); + }, + unlockBox = function(boxIndex) { + var key = getLockKey(boxIndex), + value = (BoxKeySeeds[boxIndex] - 1000) ^ XOR_VALUE; + + SettingStorage.set(key, value); + }; + + var $enterCodeButton = null; + $(document).ready(function() { + $enterCodeButton = $('#boxEnterCodeButton').hide(); + }); + + // cache text images shared between boxes + var availableTextImg = null, + collectTextImg = null, + toUnlockTextImg = null, + bkCodeTextImg = null; + + var MonthNames = [ "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" ]; + + var TimeBox = Box.extend({ + + init: function (boxIndex, bgimg, reqstars, islocked, type) { + this._super(boxIndex, bgimg, reqstars, islocked, type); + this.lockedBoxImg = new Image(); + this.lockedBoxImg.src = this.boxImg.src.replace('.png', '_locked.png'); + this.isBkCodeLocked = isLocked(boxIndex); + this.isTimeLocked = (QueryStrings.unlockAllBoxes !== true) && + (Date.now() < BoxOpenDates[boxIndex]); + this.dateImg = null; + }, + + isClickable: function() { + return (!this.isTimeLocked && !this.isBkCodeLocked); + }, + + onSelected: function () { + if (!this.isTimeLocked && this.isBkCodeLocked) { + $enterCodeButton.fadeIn(); + } + }, + + onUnselected: function () { + $enterCodeButton.hide(); + }, + + render: function (ctx, omnomoffset) { + + var locked = this.islocked || this.isTimeLocked || this.isBkCodeLocked; + + // draw the base box image + ctx.drawImage( + locked ? this.lockedBoxImg : this.boxImg, + resolution.uiScaledNumber(25), + resolution.uiScaledNumber(0)); + + if (this.isTimeLocked) { + + // draw label above date + if (!availableTextImg) { + availableTextImg = new Image(); + Text.drawBig({ + text: 'Available starting from', + img: availableTextImg, + alignment: Alignment.HCENTER, + width: resolution.uiScaledNumber(250) + }); + } + if (availableTextImg.complete) { + ctx.drawImage( + availableTextImg, + resolution.uiScaledNumber(100), + resolution.uiScaledNumber(120), + availableTextImg.width * 0.8 * resolution.UI_TEXT_SCALE, + availableTextImg.height * 0.8 * resolution.UI_TEXT_SCALE); + } + + // draw date the box will open + if (!this.dateImg) { + this.dateImg = new Image(); + var openDate = new Date(BoxOpenDates[this.index]); + Text.drawBig({ + text: MonthNames[openDate.getMonth()] + ' ' + openDate.getDate(), + img: this.dateImg, + width: resolution.uiScaledNumber(200), + alignment: Alignment.HCENTER + }); + } + if (this.dateImg.complete) { + ctx.drawImage( + this.dateImg, + resolution.uiScaledNumber(77), + resolution.uiScaledNumber(195), + this.dateImg.width * 1.2 * resolution.UI_TEXT_SCALE, + this.dateImg.height * 1.2 * resolution.UI_TEXT_SCALE); + } + + } else if (this.isBkCodeLocked) { + + // text label for "Collect" + if (!bkCodeTextImg) { + bkCodeTextImg = new Image(); + Text.drawBig({ + text: 'Visit Burger King to get an\n unlock code!', + img: bkCodeTextImg, + alignment: Alignment.HCENTER, + width: resolution.uiScaledNumber(280) + }); + + Text.drawBig({ + text: 'Enter Code', + imgParentId: 'boxEnterCodeButton', + scaleToUI: true + }); + } + + if (bkCodeTextImg.complete) { + ctx.drawImage( + bkCodeTextImg, + resolution.uiScaledNumber(50), + resolution.uiScaledNumber(90)); + } + + } else if (this.islocked) { + + // text label for "Collect" + if (!collectTextImg) { + collectTextImg = new Image(); + Text.drawBig({ + text: 'Collect', + img: collectTextImg, + scaleToUI: true + }); + } + if (collectTextImg.complete) { + ctx.drawImage( + collectTextImg, + resolution.uiScaledNumber(143), + resolution.uiScaledNumber(108)); + } + + // prefer css dimensions (scaled) for text + var textWidth = ($(this.reqImg).width() || this.reqImg.width) * 1.2, + textHeight = ($(this.reqImg).height() || this.reqImg.height) * 1.2, + + // ok to use raw image width for star (image already scaled) + starWidth = this.starImg.width || $(this.starImg).width(), + starMargin = resolution.uiScaledNumber(-4), + + // center the text and star label + labelWidth = textWidth + starMargin + starWidth, + labelMaxWidth = resolution.uiScaledNumber(125), + labelOffsetX = (labelMaxWidth - labelWidth) / 2, + labelMinX = resolution.uiScaledNumber(140), + labelX = labelMinX + labelOffsetX; + + ctx.drawImage(this.starImg, labelX, + resolution.uiScaledNumber(160)); + ctx.drawImage(this.reqImg, + labelX + starWidth, + resolution.uiScaledNumber(150), + textWidth, textHeight ); + + + // text label for "to unlock" + if (!toUnlockTextImg) { + toUnlockTextImg = new Image(); + Text.drawBig({ + text: 'to unlock', + img: toUnlockTextImg, + scaleToUI: true + }); + } + if (toUnlockTextImg.complete) { + ctx.drawImage( + toUnlockTextImg, + resolution.uiScaledNumber(130), + resolution.uiScaledNumber(204)); + } + } + } + }); + + TimeBox.unlockBox = unlockBox; + TimeBox.isLocked = isLocked; + + return TimeBox; + } +); +define('ui/PanelId',[], function () { + var PanelId = { + MENU: 0, + BOXES: 1, + LEVELS: 2, + GAME: 3, + GAMEMENU: 4, + LEVELCOMPLETE: 5, + GAMECOMPLETE: 6, + OPTIONS: 7, + CREDITS: 8, + LEADERBOARDS: 9, + ACHIEVEMENTS: 10, + PASSWORD: 11 + }; + + return PanelId; +}); + +define('ui/Panel', + [], function () { + + function Panel(id, paneldivid, bgdivid, showshadow) { + this.id = id; + this.panelDivId = paneldivid; + this.bgDivId = bgdivid; + this.showShadow = showshadow; + } + + return Panel; + } +); +define('utils/PointerCapture', + [], + function () { + + var singleTouch = false; + + function PointerCapture(settings) { + + this.el = settings.element; + this.getZoom = settings.getZoom; + + var self = this; + + // save references to the event handlers so they can be removed + this.startHandler = function (event) { + self.preventPanning(event); + + if (singleTouch === false) { + singleTouch = event.changedTouches && event.changedTouches[0].identifier; + } else { + return false; + } + + if (settings.onStart) + return self.translatePosition(event, settings.onStart); + else + return false; // not handled + }; + this.moveHandler = function (event) { + self.preventPanning(event); + + if (event.changedTouches && event.changedTouches[0].identifier !== singleTouch) + return false; + + if (settings.onMove) + return self.translatePosition(event, settings.onMove); + else + return false; // not handled + }; + this.endHandler = function (event) { + self.preventPanning(event); + singleTouch = false; + + if (settings.onEnd) + return self.translatePosition(event, settings.onEnd); + else + return false; // not handled + }; + this.outHandler = function (event) { + if (settings.onOut) + return self.translatePosition(event, settings.onOut); + else + return false; // not handled + }; + } + + // translates from page relative to element relative position + PointerCapture.prototype.translatePosition = function (event, callback) { + // get the mouse coordinate relative to the page + // http://www.quirksmode.org/js/events_properties.html + var posx = 0, + posy = 0; + if (!event) { + event = window.event; + } + + if (event.changedTouches && event.changedTouches.length > 0) { + // iOS removes touches from targetTouches on touchend so we use + // changedTouches when it's available + posx = event.changedTouches[0].pageX; + posy = event.changedTouches[0].pageY; + } + else if (event.targetTouches && event.targetTouches.length > 0) { + posx = event.targetTouches[0].pageX; + posy = event.targetTouches[0].pageY; + } + else if (event.pageX || event.pageY) { + posx = event.pageX; + posy = event.pageY; + } + else if (event.clientX || event.clientY) { + posx = event.clientX + document.body.scrollLeft + + document.documentElement.scrollLeft; + posy = event.clientY + document.body.scrollTop + + document.documentElement.scrollTop; + } + + var offset = $(this.el).offset(), // get mouse coordinates relative to the element + zoom = this.getZoom ? this.getZoom() : 1, // adjust coordinates if the game is zoomed + mouseX = Math.round((posx - offset.left) / zoom), + mouseY = Math.round((posy - offset.top) / zoom); + + return callback(mouseX, mouseY); + }; + + // prevent touches from panning the page + PointerCapture.prototype.preventPanning = function (event) { + if (event['preventManipulation']) { + event['preventManipulation'](); + } + else { + event.preventDefault(); + } + }; + + PointerCapture.prototype.activate = function () { + this.el.addEventListener(PointerCapture.startEventName, this.startHandler, false); + this.el.addEventListener(PointerCapture.moveEventName, this.moveHandler, false); + this.el.addEventListener(PointerCapture.endEventName, this.endHandler, false); + this.el.addEventListener(PointerCapture.outEventName, this.outHandler, false); + }; + + PointerCapture.prototype.deactivate = function () { + this.el.removeEventListener(PointerCapture.startEventName, this.startHandler, false); + this.el.removeEventListener(PointerCapture.moveEventName, this.moveHandler, false); + this.el.removeEventListener(PointerCapture.endEventName, this.endHandler, false); + this.el.removeEventListener(PointerCapture.outEventName, this.outHandler, false); + }; + + // IE10 has pointer events that capture mouse, pen, and touch + PointerCapture.useMSPointerEvents = window.navigator['msPointerEnabled']; + + // We are not using Modernizr in win8, but sometimes we debug in other browsers + PointerCapture.useTouchEvents = (typeof Modernizr !== 'undefined' && Modernizr.touch); + + // cache the correct event names to use + PointerCapture.startEventName = + PointerCapture.useMSPointerEvents ? 'MSPointerDown' : + PointerCapture.useTouchEvents ? 'touchstart' : 'mousedown'; + PointerCapture.moveEventName = + PointerCapture.useMSPointerEvents ? 'MSPointerMove' : + PointerCapture.useTouchEvents ? 'touchmove' : 'mousemove'; + PointerCapture.endEventName = + PointerCapture.useMSPointerEvents ? 'MSPointerUp' : + PointerCapture.useTouchEvents ? 'touchend' : 'mouseup'; + + // Unfortunately there is no touchleave event + PointerCapture.outEventName = + PointerCapture.useMSPointerEvents ? 'MSPointerOut' : 'mouseout'; + + return PointerCapture; + } +); + + + + +define('config/resolutions/ZoomManager', + [], + function () { + + function ZoomManager() { + + // cache the target element + this.$el = null; + + // no zoom by default + this.zoom = GLOBAL_ZOOM; + + this.transformOrigin = 'top left'; + + this.setElementId = function (elementId) { + this.$el = $('#' + elementId); + }; + + this.setElement = function (element) { + this.$el = $(element); + }; + + this.updateCss = function (css) { + + css = css || {}; + + var cssScale = 'scale(' + this.zoom + ')', + prefixes = ['ms', 'o', 'webkit', 'moz'], + transformOrigin = this.transformOrigin, + i, len, key; + + // clear values if no zoom is required + if (this.zoom === 1) { + cssScale = transformOrigin = ''; + } + + // set the transform scale and origin for each browser prefix + for (i = 0, len = prefixes.length; i < len; i++) { + key = '-' + prefixes[i] + '-transform'; + css[key] = cssScale; + css[key + '-origin'] = transformOrigin; + } + + this.$el.css(css); + }; + + this.getCanvasZoom = function() { + return this.zoom || 1; + }; + + this.getUIZoom = function() { + return this.zoom || 1; + }; + + // begin monitoring the window for dimension changes + this.autoResize = function () { + var self = this; + $(window).resize(function () { + self.resize(); + }); + this.resize(); + }; + + this.nativeWidth = 0; + this.nativeHeight = 0; + + var originalHeight = 270; + + this.resize = function (skipZoom) { + // get the viewport and canvas dimensions + var $w = $(window), + vpWidth = $w.width(), + vpHeight = $w.height(), + canvasWidth = this.nativeWidth, + canvasHeight = this.nativeHeight; + + // choose smallest zoom factor that will maximize one side + if (!skipZoom) { + this.zoom = Math.min(vpWidth / canvasWidth, vpHeight / canvasHeight); + } + + this.bgZoom = vpHeight / (originalHeight * this.zoom); + $(".coverBg").css({ + "-webkit-transform": "scale(" + this.bgZoom + ")", + "-moz-transform": "scale(" + this.bgZoom + ")" + }); + + $(".scaleBg").css({ + "-webkit-transform": "scaleY(" + this.bgZoom + ")", + "-moz-transform": "scaleY(" + this.bgZoom + ")" + }); + + // center the game by setting the margin (using auto in css doesn't + // work because of zoom). Note: there are differences in how margin + // is applied. IE doesn't consider margin as part of the zoomed element + // while Chrome does. We can safely ignore this for now as full screen is + // only necessary in win8 (IE10). + var marginLeft = Math.round((vpWidth - (canvasWidth * this.zoom)) / 2), + marginTop = Math.round((vpHeight - (canvasHeight * this.zoom)) / 2); + + this.updateCss({ + 'margin-top': marginTop, + 'margin-left': marginLeft + }); + }; + } + + // we only need a singleton instance + return new ZoomManager(); + } +); +define('ZoomManager', + [ + 'config/resolutions/ZoomManager', + 'resolution' + ], + function (ZoomManager, resolution) { + + ZoomManager.domReady = function () { + + // no scaling, just center the game + this.setElementId('gameContainer'); + + this.nativeWidth = resolution.UI_WIDTH; + this.nativeHeight = resolution.UI_HEIGHT; + this.resize(true /* skipZoom */); + }; + + return ZoomManager; + } +); + +define('game/CTRSoundMgr', + [ + 'game/CTRSettings', + 'utils/Log', + 'resources/ResourceId', + 'resources/Sounds' + ], + function (settings, Log, ResourceId, Sounds) { + var SoundMgr = { + + audioPaused: false, + soundEnabled: settings.getSoundEnabled(), + musicEnabled: settings.getMusicEnabled(), + musicId: null, // background music + playSound: function (soundId) { + if (this.soundEnabled) { + Sounds.play(soundId); + } + }, + pauseSound: function (soundId) { + if (this.soundEnabled && Sounds.isPlaying(soundId)) { + Sounds.pause(soundId); + } + }, + resumeSound: function (soundId) { + if (this.soundEnabled && Sounds.isPaused(soundId)) { + Sounds.play(soundId); + } + }, + playLoopedSound: function (soundId) { + var self = this; + if (this.soundEnabled && !Sounds.isPlaying(soundId)) { + Sounds.play(soundId, function () { + if (!self.audioPaused && self.soundEnabled) { + self.playLoopedSound(soundId); + } + }); + } + }, + stopSound: function (soundId) { + Sounds.stop(soundId); + }, + playMusic: function (soundId) { + + // stop the existing music if different + if (this.musicId && this.musicId !== soundId) { + this.stopMusic(soundId); + } + + var self = this; + if (this.musicEnabled && !Sounds.isPlaying(soundId)) { + this.musicId = soundId; + Sounds.setVolume(soundId, 70); + Sounds.play(soundId, function () { + if (!self.audioPaused && self.musicEnabled) { + self.playMusic(soundId); + } + }); + } + }, + pauseAudio: function () { + + //console.log('Paused audio'); + + this.audioPaused = true; + this.pauseMusic(); + + // electro is the only looped sound effect for now + this.pauseSound(ResourceId.SND_ELECTRIC); + }, + pauseMusic: function () { + if (this.musicId) { + Sounds.pause(this.musicId); + } + }, + resumeAudio: function () { + //console.log('Resumed audio', this.audioPaused); + if (!this.audioPaused) return; + + this.audioPaused = false; + this.resumeMusic(); + this.resumeSound(ResourceId.SND_ELECTRIC); + }, + resumeMusic: function () { + if (this.musicId) { + this.playMusic(this.musicId); + } + }, + stopMusic: function () { + if (this.musicId) { + // stop any currently playing background music + Sounds.stop(this.musicId); + } + }, + setMusicEnabled: function (musicEnabled) { + this.musicEnabled = musicEnabled; + settings.setMusicEnabled(musicEnabled); + if (this.musicEnabled) { + this.resumeMusic(); + } + else { + this.pauseMusic(); + } + }, + setSoundEnabled: function (soundEnabled) { + this.soundEnabled = soundEnabled; + settings.setSoundEnabled(soundEnabled); + } + }; + + return SoundMgr; + } +); + +define('core/ViewController', + [ + 'utils/Class', + 'utils/Constants', + 'utils/PubSub' + ], + function (Class, Constants, PubSub) { + + // COMMENTS from iOS sources: + // controller philosophy + // - there's a root controller which is notified about every controller state change + // - only one controller runs (invokes 'update') at a time + // - controller can control several views (or none) + // - controller can have childs, when controller's child is active, controller itself is paused + // - child controller notifies parent after deactivation + + //noinspection JSUnusedLocalSymbols + /** + * @constructor + */ + var ViewController = Class.extend({ + init: function (parent) { + this.controllerState = ViewController.StateType.INACTIVE; + this.views = []; + this.children = []; + this.activeViewID = Constants.UNDEFINED; + this.activeChildID = Constants.UNDEFINED; + this.pausedViewID = Constants.UNDEFINED; + this.parent = parent; + this.lastTime = Constants.UNDEFINED; + this.delta = 0; + this.frames = 0; + this.accumDt = 0; + this.frameRate = 0; + + // like a bank account for frame updates. we try to keep our + // balance under 1 by doing extra frame updates when above 1 + this.frameBalance = 0; + + // initially assume we are getting 60 fps + this.avgDelta = 1 / 60; + + // keep the last five deltas (init with target fps) + this.pastDeltas = [ + this.avgDelta, + this.avgDelta, + this.avgDelta, + this.avgDelta, + this.avgDelta + ]; + }, + activate: function () { + //Debug.log('View controller activated'); + this.controllerState = ViewController.StateType.ACTIVE; + PubSub.publish(PubSub.ChannelId.ControllerActivated, this); + }, + deactivate: function () { + PubSub.publish(PubSub.ChannelId.ControllerDeactivateRequested, this); + }, + deactivateImmediately: function () { + this.controllerState = ViewController.StateType.INACTIVE; + if (this.activeViewID !== Constants.UNDEFINED) { + this.hideActiveView(); + } + // notify root and parent controllers + PubSub.publish(PubSub.ChannelId.ControllerDeactivate, this); + this.parent.onChildDeactivated(this.parent.activeChildID); + }, + pause: function () { + this.controllerState = ViewController.StateType.PAUSED; + PubSub.publish(PubSub.ChannelId.ControllerPaused, this); + + if (this.activeViewID != Constants.UNDEFINED) { + this.pausedViewID = this.activeViewID; + this.hideActiveView(); + } + }, + unpause: function () { + this.controllerState = ViewController.StateType.ACTIVE; + if (this.activeChildID !== Constants.UNDEFINED) { + this.activeChildID = Constants.UNDEFINED; + } + + PubSub.publish(PubSub.ChannelId.ControllerUnpaused, this); + + if (this.pausedViewID !== Constants.UNDEFINED) { + this.showView(this.pausedViewID); + } + }, + update: function () { + if (this.activeViewID === Constants.UNDEFINED) { + return; + } + + var v = this.activeView(); + + // the physics engine needs to be updated at 60fps. we + // will do up to 3 updates for each frame that is + // actually rendered. This means we could run as low as 20 fps + var maxUpdates = Math.min(3, this.frameBalance | 0); + for (var i = 0; i < maxUpdates; i++) { + v.update(0.016); + this.frameBalance -= 1; + } + }, + resetLastTime: function () { + this.lastTime = Constants.UNDEFINED; + }, + calculateTimeDelta: function (time) { + this.delta = (this.lastTime !== Constants.UNDEFINED) + ? (time - this.lastTime) / 1000 + : 0; + this.lastTime = time; + + // if the physics engine requires 60 fps, how many frames do + // we need to update? + this.frameBalance += this.clampDelta(this.delta) / 0.016; + }, + /** + * Make sure a delta doesn't exceed some reasonable bounds + * Delta changes might be large if we are using requestAnimationFrame + * and the user switches tabs (the browser will stop calling us to + * preserve power). + * @param delta {number} + */ + clampDelta: function (delta) { + if (delta < 0.016) { + // sometimes we'll get a bunch of frames batched together + // but we don't want to go below the 60 fps delta + return 0.016; + } + else if (delta > 0.05) { + // dont go below the delta for 20 fps + return 0.05; + } + return delta; + }, + calculateFPS: function () { + this.frames++; + this.accumDt += this.delta; + + // update the frame rate every second + if (this.accumDt > 1) { + this.frameRate = this.frames / this.accumDt; + this.frames = 0; + this.accumDt = 0; + + // advance the queue of past deltas + this.pastDeltas.shift(); + this.pastDeltas.push(this.clampDelta(1 / this.frameRate)); + + // we use a running average to prevent drastic changes + this.avgDelta = 0; + for (var i = 0, len = this.pastDeltas.length; i < len; i++) { + this.avgDelta += this.pastDeltas[i]; + } + this.avgDelta /= len; + } + }, + addView: function (v, index) { + this.views[index] = v; + }, + deleteView: function (viewIndex) { + this.views[viewIndex] = null; + }, + hideActiveView: function () { + var previousView = this.views[this.activeViewID]; + if (previousView) { + PubSub.publish(PubSub.ChannelId.ControllerViewHidden, previousView); + previousView.hide(); + this.activeViewID = Constants.UNDEFINED; + } + }, + showView: function (index) { + if (this.activeViewID != Constants.UNDEFINED) { + this.hideActiveView(); + } + this.activeViewID = index; + var v = this.views[index]; + PubSub.publish(PubSub.ChannelId.ControllerViewShow, v); + v.show(); + }, + activeView: function () { + return this.views[this.activeViewID]; + }, + getView: function (index) { + return this.views[index]; + }, + addChildWithID: function (controller, index) { + this.children[index] = controller; + }, + deleteChild: function (index) { + this.children[index] = null; + if (this.activeChildID === index) { + this.activeChildID = Constants.UNDEFINED; + } + }, + deactivateActiveChild: function () { + if (this.activeChildID !== Constants.UNDEFINED) { + var prevController = this.children[this.activeChildID]; + if (prevController) { + prevController.deactivate(); + } + this.activeChildID = Constants.UNDEFINED; + } + }, + activateChild: function (index) { + if (this.activeChildID !== Constants.UNDEFINED) { + this.deactivateActiveChild(); + } + + this.pause(); + this.activeChildID = index; + this.children[index].activate(); + }, + onChildDeactivated: function (childType) { + this.unpause(); + }, + activeChild: function () { + return this.children[this.activeChildID]; + }, + getChild: function (index) { + return this.children[index]; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseDown: function (x, y) { + if (this.activeViewID === Constants.UNDEFINED) { + return false; + } + return this.views[this.activeViewID].onTouchDown(x, y); + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseUp: function (x, y) { + if (this.activeViewID === Constants.UNDEFINED) { + return false; + } + return this.views[this.activeViewID].onTouchUp(x, y); + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseDragged: function (x, y) { + if (this.activeViewID === Constants.UNDEFINED) { + return false; + } + return this.views[this.activeViewID].onTouchMove(x, y); + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseMoved: function (x, y) { + // only drag events are used + return false; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + doubleClick: function (x, y) { + if (this.activeViewID === Constants.UNDEFINED) { + return false; + } + return this.views[this.activeViewID].onDoubleClick(x, y); + } + }); + + /** + * @enum {number} + */ + ViewController.StateType = { + INACTIVE: 0, + ACTIVE: 1, + PAUSED: 2 + }; + + return ViewController; + } +); +define('core/RootControllerBase', + [ + 'core/ViewController', + 'utils/PointerCapture', + 'ZoomManager', + 'utils/Constants', + 'game/CTRSettings', + 'resolution', + 'utils/PubSub', + 'utils/Canvas', + 'core/RGBAColor' + ], + function (ViewController, PointerCapture, ZoomManager, Constants, settings, resolution, PubSub, Canvas, RGBAColor) { + /** + * @const + * @type {number} + */ + var TRANSITION_DEFAULT_DELAY = 0.3; + + /** + * @enum {number} + */ + var ViewTransition = { + SLIDE_HORIZONTAL_RIGHT: 0, + SLIDE_HORIZONTAL_LEFT: 1, + SLIDE_VERTICAL_UP: 2, + SLIDE_VERTICAL_DOWN: 3, + FADE_OUT_BLACK: 4, + FADE_OUT_WHITE: 5, + REVEAL: 6, + COUNT: 7 + }; + + var RootController = ViewController.extend({ + init: function (parent) { + this._super(parent); + this.suspended = false; + this.currentController = null; + this.viewTransition = Constants.UNDEFINED; + this.transitionTime = Constants.UNDEFINED; + this.previousView = null; + this.transitionDelay = TRANSITION_DEFAULT_DELAY; + this.deactivateCurrentController = false; + + // when the user holds down the mouse button while moving the mouse + this.dragMode = false; + + PubSub.subscribe(PubSub.ChannelId.ControllerActivated, $.proxy(this.onControllerActivated, this)); + PubSub.subscribe(PubSub.ChannelId.ControllerDeactivateRequested, + $.proxy(this.onControllerDeactivationRequest, this)); + PubSub.subscribe(PubSub.ChannelId.ControllerDeactivated, $.proxy(this.onControllerDeactivated, this)); + PubSub.subscribe(PubSub.ChannelId.ControllerPaused, $.proxy(this.onControllerPaused, this)); + PubSub.subscribe(PubSub.ChannelId.ControllerUnpaused, $.proxy(this.onControllerUnpaused, this)); + PubSub.subscribe(PubSub.ChannelId.ControllerViewHidden, $.proxy(this.onControllerViewHide, this)); + PubSub.subscribe(PubSub.ChannelId.ControllerViewShow, $.proxy(this.onControllerViewShow, this)); + }, + + operateCurrentMVC: function (time) { + if (this.suspended || this.currentController === null) { + return; + } + + // pass control to the active controller + this.currentController.calculateTimeDelta(time); + if (this.transitionTime === Constants.UNDEFINED) { + this.currentController.update(); + } + + if (this.deactivateCurrentController) { + this.deactivateCurrentController = false; + this.currentController.deactivateImmediately(); + } + + // draw the active view + if (this.currentController.activeViewID !== Constants.UNDEFINED) { + + var activeView = this.currentController.activeView(); + if (activeView) { + activeView.draw(); + } + + // always calc fps because we use the avg to adjust delta at runtime + this.currentController.calculateFPS(); + + // draw the fps meter + if (settings.fpsEnabled) { + // make sure we have one cycle of measurements + var frameRate = this.currentController.frameRate.toFixed(0); + if (frameRate > 0) { + // draw the fps frame rate + var ctx = Canvas.context; + ctx.font = "20px Arial"; + ctx.fillStyle = RGBAColor.styles.SOLID_OPAQUE; + ctx.fillText(frameRate + ' fps', 10, resolution.CANVAS_HEIGHT - 10); + } + } + } + }, + activateMouseEvents: function () { + // ensure the pointer capture helper has been created + if (!this.pointerCapture) { + this.pointerCapture = new PointerCapture({ + element: Canvas.element, + onStart: $.proxy(this.mouseDown, this), + onMove: $.proxy(this.mouseMove, this), + onEnd: $.proxy(this.mouseUp, this), + onOut: $.proxy(this.mouseOut, this), + getZoom: function() { + return ZoomManager.getCanvasZoom(); + } + }); + } + + this.pointerCapture.activate(); + }, + deactivateMouseEvents: function () { + if (this.pointerCapture) { + this.pointerCapture.deactivate(); + } + }, + activate: function () { + this._super(); + this.activateMouseEvents(); + + // called to render a frame + var self = this, + requestAnimationFrame = window['requestAnimationFrame'], + animationLoop = function () { + var now = Date.now(); + self.operateCurrentMVC(now); + if (!self.stopAnimation) { + requestAnimationFrame(animationLoop); + } + }; + + // start the animation loop + this.stopAnimation = false; + animationLoop(); + }, + deactivate: function () { + this._super(); + + // set flag to stop animation + this.stopAnimation = true; + + // remove mouse events + this.deactivateMouseEvents(); + }, + + setCurrentController: function (controller) { + this.currentController = controller; + this.currentController.idealDelta = 1 / 60; + }, + getCurrentController: function () { + return this.currentController; + }, + onControllerActivated: function (controller) { + this.setCurrentController(controller); + }, + onControllerDeactivated: function (controller) { + this.currentController = null; + }, + onControllerPaused: function (controller) { + this.currentController = null; + }, + onControllerUnpaused: function (controller) { + this.setCurrentController(controller); + }, + onControllerDeactivationRequest: function (controller) { + this.deactivateCurrentController = true; + }, + onControllerViewShow: function (view) { + if (this.viewTransition !== Constants.UNDEFINED && this.previousView != null) { + this.currentController.calculateTimeDelta(); + this.transitionTime = this.currentController.lastTime + this.transitionDelay; + var activeView = this.currentController.activeView(); + if (activeView) { + activeView.draw(); + } + } + }, + onControllerViewHide: function (view) { + this.previousView = view; + if (this.viewTransition !== Constants.UNDEFINED && this.previousView != null) { + this.previousView.draw(); + } + }, + isSuspended: function () { + return this.suspended; + }, + suspend: function () { + this.suspended = true; + }, + resume: function () { + if (this.currentController) { + this.currentController.resetLastTime(); + } + this.suspended = false; + }, + mouseDown: function (x, y) { + if (this.currentController && this.currentController != this) { + //Log.debug('mouse down at:' + x + ',' + y + ' drag mode was:' + this.dragMode); + this.dragMode = true; + return this.currentController.mouseDown(x, y); + } + return false; + }, + mouseMove: function (x, y) { + if (this.currentController && this.currentController != this) { + if (this.dragMode) { + this.currentController.mouseDragged(x, y); + } + + // fire moved event even if drag event was also fired + return this.currentController.mouseMoved(x, y); + } + return false; + }, + mouseUp: function (x, y) { + if (this.currentController && this.currentController != this) { + //Log.debug('mouse up at:' + x + ',' + y + ' drag mode was:' + this.dragMode); + var handled = this.currentController.mouseUp(x, y); + this.dragMode = false; + return handled; + } + return false; + }, + mouseOut: function (x, y) { + if (this.currentController && this.currentController != this) { + // if the mouse leaves the canvas while down, trigger the mouseup + // event because we won't get it if the user lets go outside + if (this.dragMode) { + //Log.debug('mouse out at:' + x + ',' + y); + var handled = this.currentController.mouseUp(x, y); + this.dragMode = false; + return handled; + } + } + return false; + }, + doubleClick: function (x, y) { + if (this.currentController && this.currentController != this) { + //Log.debug('double click at:' + x + ',' + y + ' drag mode was:' + this.dragMode); + this.currentController.mouseUp(x, y); + this.dragMode = false; + return this.currentController.doubleClick(x, y); + } + return false; + } + }); + + return RootController; + } +); + +define('visual/Animation', + [ + 'visual/ImageElement', + 'core/Quad2D', + 'visual/TrackType', + 'visual/Timeline', + 'visual/Action', + 'visual/ActionType', + 'visual/KeyFrame', + 'utils/Constants' + ], + function (ImageElement, Quad2D, TrackType, Timeline, Action, ActionType, KeyFrame, Constants) { + + /** + * Animation element based on timeline + */ + var Animation = ImageElement.extend({ + init: function () { + this._super(); + }, + /** + * @param delay {number} + * @param loop {number} + * @param start {number} + * @param end {number} + * @return {number} + */ + addAnimationDelay: function (delay, loop, start, end) { + var index = this.timelines.length; + this.addAnimationEndpoints(index, delay, loop, start, end); + return index; + }, + addAnimationWithDelay: function (delay, loopType, count, sequence) { + var index = this.timelines.length; + this.addAnimationSequence(index, delay, loopType, count, sequence); + }, + addAnimationSequence: function (animationId, delay, loopType, count, sequence) { + this.addAnimation(animationId, delay, loopType, count, sequence[0], Constants.UNDEFINED, sequence); + }, + addAnimationEndpoints: function (animationId, delay, loopType, start, end, argumentList) { + var count = end - start + 1; + this.addAnimation(animationId, delay, loopType, count, start, end, argumentList); + }, + /** + * @param animationId {number} + * @param delay {number} + * @param loopType + * @param count {number} + * @param start {number} + * @param end {number} + * @param argumentList + */ + addAnimation: function (animationId, delay, loopType, count, start, end, argumentList) { + var t = new Timeline(), + as = [ Action.create(this, ActionType.SET_DRAWQUAD, start, 0) ]; + + t.addKeyFrame(KeyFrame.makeAction(as, 0)); + + var si = start; + for (var i = 1; i < count; i++) { + if (argumentList) { + si = argumentList[i]; + } + else { + si++; + } + + as = [ Action.create(this, ActionType.SET_DRAWQUAD, si, 0) ]; + t.addKeyFrame(KeyFrame.makeAction(as, delay)); + + if (i == count - 1 && loopType === Timeline.StateType.REPLAY) { + t.addKeyFrame(KeyFrame.makeAction(as, delay)); + } + } + + if (loopType) { + t.loopType = loopType; + } + + this.addTimelineWithID(t, animationId); + }, + setDelay: function (delay, index, animationId) { + var timeline = this.getTimeline(animationId), + track = timeline.getTrack(TrackType.ACTION), + kf = track.keyFrames[index]; + kf.timeOffset = delay; + }, + setPause: function (index, animationId) { + this.setAction(ActionType.PAUSE_TIMELINE, this, 0, 0, index, animationId); + }, + setAction: function (actionName, target, param, subParam, index, animationId) { + var timeline = this.getTimeline(animationId), + track = timeline.getTrack(TrackType.ACTION), + kf = track.keyFrames[index], + action = Action.create(target, actionName, param, subParam); + + kf.value.actionSet.push(action); + }, + switchToAnimation: function (a2, a1, delay) { + var timeline = this.getTimeline(a1), + as = [ Action.create(this, ActionType.PLAY_TIMELINE, 0, a2)], + kf = KeyFrame.makeAction(as, delay); + timeline.addKeyFrame(kf); + }, + /** + * Go to the specified sequence frame of the current animation + * @param index {number} + */ + jumpTo: function (index) { + var timeline = this.currentTimeline; + timeline.jumpToTrack(TrackType.ACTION, index); + } + + + }); + + return Animation; + } +); +define('utils/Mover', + [ + 'utils/Class', + 'utils/MathHelper', + 'core/Vector' + ], + function (Class, MathHelper, Vector) { + + var Mover = Class.extend({ + init: function (pathCapacity, moveSpeed, rotateSpeed) { + this.pathCapacity = pathCapacity; + this.rotateSpeed = rotateSpeed || 0; + this.path = []; + if (pathCapacity > 0) { + this.moveSpeed = new Array(pathCapacity); + for (var i = 0; i < pathCapacity; i++) { + this.moveSpeed[i] = moveSpeed || 0; + } + } + this.pos = new Vector(0, 0); + this.angle = 0; + this.paused = false; + this.reverse = false; + this.overrun = 0; + }, + setMoveSpeed: function (speed) { + for (var i = 0, len = this.pathCapacity; i < len; i++) { + this.moveSpeed[i] = speed; + } + }, + /** + * @param path {string} + * @param start {Vector} + */ + setPathFromString: function (path, start) { + if (path[0] === 'R') { + var clockwise = (path[1] === 'C'), + rad = parseInt(path.substr(2), 10), + pointsCount = rad / 2, + kIncrement = 2 * Math.PI / pointsCount, + theta = 0; + + if (!clockwise) + kIncrement = -kIncrement; + + for (var i = 0; i < pointsCount; ++i) { + var nx = start.x + rad * Math.cos(theta), + ny = start.y + rad * Math.sin(theta); + + this.addPathPoint(new Vector(nx, ny)); + theta += kIncrement; + } + } + else { + this.addPathPoint(start.copy()); + + // remove the trailing comma + if (path[path.length - 1] === ',') { + path = path.substr(0, path.length - 1); + } + + var parts = path.split(','), + len = parts.length; + for (i = 0; i < len; i += 2) { + var xs = parseFloat(parts[i]), + ys = parseFloat(parts[i + 1]), + pathPoint = new Vector(start.x + xs, start.y + ys); + this.addPathPoint(pathPoint); + } + } + }, + /** + * @param pathPoint {Vector} + */ + addPathPoint: function (pathPoint) { + this.path.push(pathPoint); + }, + start: function () { + if (this.path.length > 0) { + this.pos.copyFrom(this.path[0]); + this.targetPoint = 1; + this.calculateOffset(); + } + }, + pause: function () { + this.paused = true; + }, + unpause: function () { + this.paused = false; + }, + setRotateSpeed: function (rotateSpeed) { + this.rotateSpeed = rotateSpeed; + }, + jumpToPoint: function (point) { + this.targetPoint = point; + this.pos.copyFrom(this.path[point]); + this.calculateOffset(); + }, + calculateOffset: function () { + var target = this.path[this.targetPoint]; + this.offset = Vector.subtract(target, this.pos); + this.offset.normalize(); + this.offset.multiply(this.moveSpeed[this.targetPoint]); + }, + setMoveSpeedAt: function (moveSpeed, index) { + this.moveSpeed[index] = moveSpeed; + }, + setMoveReverse: function (reverse) { + this.reverse = reverse; + }, + update: function (delta) { + if (this.paused) + return; + + if (this.path.length > 0) { + var target = this.path[this.targetPoint], + switchPoint = false; + + if (!this.pos.equals(target)) { + var rdelta = delta; + if (this.overrun !== 0) { + rdelta += this.overrun; + this.overrun = 0; + } + + this.pos.add(Vector.multiply(this.offset, rdelta)); + + // see if we passed the target + if (!MathHelper.sameSign(this.offset.x, target.x - this.pos.x) || + !MathHelper.sameSign(this.offset.y, target.y - this.pos.y)) { + this.overrun = Vector.subtract(this.pos, target).getLength(); + + // overrun in seconds + this.overrun /= this.offset.getLength(); + this.pos.copyFrom(target); + switchPoint = true; + } + } + else { + switchPoint = true; + } + + if (switchPoint) { + if (this.reverse) { + this.targetPoint--; + if (this.targetPoint < 0) { + this.targetPoint = this.path.length - 1; + } + } + else { + this.targetPoint++; + if (this.targetPoint >= this.path.length) { + this.targetPoint = 0; + } + } + + this.calculateOffset(); + } + } + + if (this.rotateSpeed !== 0) { + this.angle += this.rotateSpeed * delta; + } + } + }); + + // NOTE: sometimes we need the status indicating whether the + // variable was moved to zero. However, for performance we'll + // offer another version without status. + + Mover.moveToTarget = function (v, t, speed, delta) { + if (t !== v) { + if (t > v) { + v += speed * delta; + if (v > t) { + v = t; + } + } + else { + v -= speed * delta; + if (v < t) { + v = t; + } + } + } + return v; + }; + /** + * + * @param v {number} value + * @param t {number} target + * @param speed {number} + * @param delta {number} + * @return {Object} + */ + Mover.moveToTargetWithStatus = function (v, t, speed, delta) { + var reachedZero = false; + if (t !== v) { + if (t > v) { + v += speed * delta; + if (v > t) { + v = t; + } + } + else { + v -= speed * delta; + if (v < t) { + v = t; + } + } + if (t === v) + reachedZero = true; + } + + return { + value: v, + reachedZero: reachedZero + }; + }; + + /** + * @const + * @type {number} + */ + Mover.MAX_CAPACITY = 100; + + return Mover; + } +); + +define('visual/GameObject', + [ + 'visual/Animation', + 'utils/Mover', + 'core/Rectangle', + 'core/Quad2D', + 'core/Alignment', + 'core/Vector', + 'utils/Radians', + 'utils/Canvas', + 'core/RGBAColor' + ], + function (Animation, Mover, Rectangle, Quad2D, Alignment, Vector, Radians, Canvas, RGBAcolor) { + + var GameObject = Animation.extend({ + init: function () { + this._super(); + this.isDrawBB = false; + }, + initTexture: function (texture) { + this._super(texture); + this.bb = new Rectangle(0, 0, this.width, this.height); + this.rbb = new Quad2D(this.bb.x, this.bb.y, this.bb.width, this.bb.height); + this.anchor = Alignment.CENTER; + + this.rotatedBB = false; + this.topLeftCalculated = false; + }, + setBBFromFirstQuad: function () { + var firstOffset = this.texture.offsets[0], + firstRect = this.texture.rects[0]; + //noinspection JSSuspiciousNameCombination + this.bb = new Rectangle( + Math.round(firstOffset.x), + Math.round(firstOffset.y), + firstRect.width, + firstRect.height); + this.rbb = new Quad2D(this.bb.x, this.bb.y, this.bb.width, this.bb.height); + }, + parseMover: function (item) { + this.rotation = item.angle || 0; + + var path = item.path; + if (path) { + var moverCapacity = Mover.MAX_CAPACITY; + if (path[0] === 'R') { + var rad = parseInt(path.substr(2), 10); + moverCapacity = Math.round(rad / 2 + 1); + } + + var mover = new Mover( + moverCapacity, + item.moveSpeed, + item.rotateSpeed); + mover.angle = this.rotation; + mover.setPathFromString(path, new Vector(this.x, this.y)); + this.setMover(mover); + mover.start(); + } + }, + setMover: function (mover) { + this.mover = mover; + + // turn high precision coordinates on for moving objects + this.drawPosIncrement = 0.0001; + }, + update: function (delta) { + this._super(delta); + + if (!this.topLeftCalculated) { + this.calculateTopLeft(); + this.topLeftCalculated = true; + } + + if (this.mover) { + this.mover.update(delta); + + this.x = this.mover.pos.x; + this.y = this.mover.pos.y; + + if (this.rotatedBB) + this.rotateWithBB(this.mover.angle); + else + this.rotation = this.mover.angle; + } + }, + rotateWithBB: function (angle) { + if (!this.rotatedBB) { + this.rotatedBB = true; + } + this.rotation = angle; + + var bb = this.bb, + tl = new Vector(bb.x, bb.y), + tr = new Vector(bb.x + bb.w, bb.y), + br = new Vector(tr.x, bb.y + bb.h), + bl = new Vector(bb.x, br.y); + + // calculate the angle and offset for rotation + var rad = Radians.fromDegrees(angle), + offsetX = this.width / 2 + this.rotationCenterX, + offsetY = this.height / 2 + this.rotationCenterY; + + tl.rotateAround(rad, offsetX, offsetY); + tr.rotateAround(rad, offsetX, offsetY); + br.rotateAround(rad, offsetX, offsetY); + tl.rotateAround(rad, offsetX, offsetY); + + var rbb = this.rbb; + rbb.tlX = tl.x; + rbb.tlY = tl.y; + rbb.trX = tr.x; + rbb.trY = tr.y; + rbb.brX = br.x; + rbb.brY = br.y; + rbb.blX = bl.x; + rbb.blY = bl.y; + + + + + + }, + drawBB: function () { + var ctx = Canvas.context, + drawX = this.drawX, + drawY = this.drawY, + bb = this.bb, + rbb = this.rbb; + ctx.strokeStyle = 'red'; + ctx.lineWidth = 2; + if (this.rotatedBB) { + ctx.beginPath(); + ctx.moveTo(drawX + rbb.tlX, drawY + rbb.tlY); + ctx.lineTo(drawX + rbb.trX, drawY + rbb.trY); + ctx.lineTo(drawX + rbb.brX, drawY + rbb.brY); + ctx.lineTo(drawX + rbb.blX, drawY + rbb.blY); + ctx.stroke(); + ctx.closePath(); + } + else { + ctx.strokeRect(drawX + bb.x, drawY + bb.y, bb.w, bb.h); + } + }, + /** + * Returns true if the point is inside the object's bounding box + * @param x {number} + * @param y {number} + * @return {boolean} + */ + pointInObject: function (x, y) { + var bb = this.bb, + ox = this.drawX + bb.x, + oy = this.drawY + bb.y; + + return Rectangle.pointInRect(x, y, ox, oy, bb.w, bb.h); + }, + /** + * @param r1x {number} + * @param r1y {number} + * @param r2x {number} + * @param r2y {number} + */ + rectInObject: function (r1x, r1y, r2x, r2y) { + var ox = this.drawX + this.bb.x, + oy = this.drawY + this.bb.y; + + return Rectangle.rectInRect(r1x, r1y, r2x, r2y, ox, oy, ox + this.bb.w, oy + this.bb.h); + } + + + }); + + GameObject.intersect = function (o1, o2) { + var o1x = o1.drawX + o1.bb.x, + o1y = o1.drawY + o1.bb.y, + o2x = o2.drawX + o2.bb.x, + o2y = o2.drawY + o2.bb.y; + + return Rectangle.rectInRect( + o1x, o1y, o1x + o1.bb.w, o1y + o1.bb.h, + o2x, o2y, o2x + o2.bb.w, o2y + o2.bb.h); + }; + + return GameObject; + } +); +define('game/CTRMover', + ['resolution', 'utils/Mover', 'core/Vector'], + function (resolution, Mover, Vector) { + + var CTRMover = Mover.extend({ + init: function (pathCapacity, moveSpeed, rotateSpeed) { + this._super(pathCapacity, moveSpeed, rotateSpeed); + }, + setPathAndStart: function (path, startX, startY) { + var i, nx, ny, xs, ys, + MOVER_SCALE = resolution.MOVER_SCALE; + + if (path[0] === 'R') { + var clockwise = (path[1] === 'C'), + rad = parseInt(path.substr(2), 10), + pointsCount = Math.round((rad * 3) / 2), + k_increment = 2 * Math.PI / pointsCount, + theta = 0; + + // now that the number of points have been calculated we + // can scale the radius to match the current resolution + rad *= MOVER_SCALE; + + if (!clockwise) + k_increment = -k_increment; + + for (i = 0; i < pointsCount; i++) { + nx = startX + rad * Math.cos(theta); + ny = startY + rad * Math.sin(theta); + + this.addPathPoint(new Vector(nx, ny)); + theta += k_increment; + } + } + else { + this.addPathPoint(new Vector(startX, startY)); + if (path[path.length - 1] === ',') { + path = path.substr(0, path.length - 1); + } + var parts = path.split(','), + numParts = parts.length; + for (i = 0; i < numParts; i += 2) { + xs = parts[i]; + ys = parts[i + 1]; + + this.addPathPoint( + new Vector(startX + xs * MOVER_SCALE, startY + ys * MOVER_SCALE)); + } + } + } + }); + + return CTRMover; + } +); + +define('game/CTRGameObject', + [ + 'visual/GameObject', + 'game/CTRMover', + 'resolution', + 'utils/Mover' + ], + function (GameObject, CTRMover, resolution, Mover) { + + var CTRGameObject = GameObject.extend({ + init: function () { + this._super(); + }, + parseMover: function (item) { + this.rotation = item.angle || 0; + + var path = item.path, + MOVER_SCALE = resolution.MOVER_SCALE; + if (path) { + var moverCapacity = Mover.MAX_CAPACITY; + if (path[0] === 'R') { + // Don't scale the radius when used for capacity + // calculation. We want same number of path points + // even if the actual radius is smaller + var rad = parseInt(path.substr(2), 10); + moverCapacity = Math.round(rad * 3 / 2 + 1); + } + var v = item.moveSpeed, + rotateSpeed = item.rotateSpeed, + mover = new CTRMover(moverCapacity, v * MOVER_SCALE, rotateSpeed); + + mover.angle = this.rotation; + mover.setPathAndStart(path, this.x, this.y); + this.setMover(mover); + mover.start(); + } + } + }); + + return CTRGameObject; + } +); + + +define('game/Bouncer', + [ + 'game/CTRGameObject', + 'core/Vector', + 'visual/KeyFrame', + 'visual/ActionType', + 'utils/Radians', + 'utils/Constants', + 'resources/ResourceId', + 'visual/Timeline' + ], + function (CTRGameObject, Vector, KeyFrame, ActionType, Radians, Constants, ResourceId, Timeline) { + + /** + * @const + * @type {number} + */ + var BOUNCER_HEIGHT = 10; + + var IMG_OBJ_BOUNCER_01_start = 0; + var IMG_OBJ_BOUNCER_01_Frame_2 = 1; + var IMG_OBJ_BOUNCER_01_Frame_3 = 2; + var IMG_OBJ_BOUNCER_01_Frame_4 = 3; + var IMG_OBJ_BOUNCER_01_end = 4; + + var IMG_OBJ_BOUNCER_02_start_ = 0; + var IMG_OBJ_BOUNCER_02_Frame_2 = 1; + var IMG_OBJ_BOUNCER_02_Frame_3 = 2; + var IMG_OBJ_BOUNCER_02_Frame_4 = 3; + var IMG_OBJ_BOUNCER_02_end = 4; + + + var Bouncer = CTRGameObject.extend({ + init: function (x, y, width, angle) { + this._super(); + + this.angle = 0; + this.skip = 0; + this.t1 = Vector.newZero(); + this.t2 = Vector.newZero(); + this.b1 = Vector.newZero(); + this.b2 = Vector.newZero(); + + var imageId = Constants.UNDEFINED; + if (width === 1) { + imageId = ResourceId.IMG_OBJ_BOUNCER_01; + } + else if (width === 2) { + imageId = ResourceId.IMG_OBJ_BOUNCER_02; + } + this.initTextureWithId(imageId); + + this.rotation = angle; + this.x = x; + this.y = y; + + this.updateRotation(); + var delay = 0.04, + k = this.addAnimationDelay(delay, Timeline.LoopType.NO_LOOP, IMG_OBJ_BOUNCER_01_start, + IMG_OBJ_BOUNCER_01_end), + t = this.getTimeline(k); + t.addKeyFrame(KeyFrame.makeSingleAction(this, ActionType.SET_DRAWQUAD, 0, 0, delay)); + }, + updateRotation: function () { + var x = this.x; + var y = this.y; + var width = this.width / 2; + + this.t1.x = x - width; + this.t2.x = x + width; + this.t1.y = this.t2.y = y - BOUNCER_HEIGHT / 2.0; + + this.b1.x = this.t1.x; + this.b2.x = this.t2.x; + this.b1.y = this.b2.y = y + BOUNCER_HEIGHT / 2.0; + + var angle = this.angle = this.rotation * 0.017453292519943295; + + this.t1.rotateAround(angle, x, y); + this.t2.rotateAround(angle, x, y); + this.b1.rotateAround(angle, x, y); + this.b2.rotateAround(angle, x, y); + }, + update: function (delta) { + this._super(delta); + if (this.mover) { + this.updateRotation(); + } + } + }); + + return Bouncer; + } +); +define('game/Bubble', + ['visual/GameObject'], + function (GameObject) { + + var Bubble = GameObject.extend({ + init: function () { + this._super(); + this.popped = false; + this.withoutShadow = false; + }, + draw: function () { + if (this.withoutShadow) { + // only do transformations and draw children + this.preDraw(); + this.postDraw(); + } + else { + this._super(); + } + } + }); + + return Bubble; + } +); + +define('visual/Particles', + [ + 'core/Vector', + 'core/RGBAColor', + 'visual/BaseElement', + 'utils/MathHelper', + 'utils/Canvas', + 'resolution', + 'utils/Radians' + ], + function (Vector, RGBAColor, BaseElement, MathHelper, Canvas, resolution, Radians) { + + /** + * @constructor + */ + function PointSprite(x, y, size) { + this.x = x; + this.y = y; + this.size = size; + } + + /** + * @constructor + */ + function Particle() { + this.startPos = new Vector(0, 0); + this.pos = new Vector(0, 0); + this.dir = new Vector(0, 0); + this.radialAccel = 0; + this.tangentialAccel = 0; + this.color = new RGBAColor(0, 0, 0, 0); + this.deltaColor = new RGBAColor(0, 0, 0, 0); + this.size = 0; + this.life = 0; + this.deltaAngle = 0; + this.angle = 0; + + // used in multi-image particles + this.width = 0; + this.height = 0; + } + + var Particles = BaseElement.extend({ + init: function (numParticles) { + this._super(); + this.width = resolution.CANVAS_WIDTH; + this.height = resolution.CANVAS_HEIGHT; + + this.totalParticles = numParticles; + this.particles = []; + + // not active by default + this.active = false; + // duration in seconds of the system. -1 is infinity + this.duration = 0; + // time elapsed since the start of the system (in seconds) + this.elapsed = 0; + + /// Gravity of the particles + this.gravity = new Vector(0, 0); + + // Position variance + this.posVar = new Vector(0, 0); + + // The angle (direction) of the particles measured in degrees + this.angle = 0; + // Angle variance measured in degrees; + this.angleVar = 0; + + // The speed the particles will have. + this.speed = 0; + // The speed variance + this.speedVar = 0; + + // Tangential acceleration + this.tangentialAccel = 0; + // Tangential acceleration variance + this.tangentialAccelVar = 0; + + // Radial acceleration + this.radialAccel = 0; + // Radial acceleration variance + this.radialAccelVar = 0; + + // Size of the particles + this.size = 0; + // Size variance + this.sizeVar = 0; + + // How many seconds will the particle live + this.life = 0; + // Life variance + this.lifeVar = 0; + + // Start color of the particles + this.startColor = new RGBAColor(0, 0, 0, 0); + // Start color variance + this.startColorVar = new RGBAColor(0, 0, 0, 0); + // End color of the particles + this.endColor = new RGBAColor(0, 0, 0, 0); + // End color variance + this.endColorVar = new RGBAColor(0, 0, 0, 0); + + // additive color or blend + this.blendAdditive = false; + // color modulate + this.colorModulate = false; + + // How many particles can be emitted per second + this.emissionRate = 0; + this.emitCounter = 0; + + // Texture of the particles + this.texture = null; + + // Array of (x,y,size) + this.vertices = []; + // Array of colors + this.colors = []; + + // particle idx + this.particleIdx = 0; + + // callback when particle system has finished + this.onFinished = null; + }, + /** + * Creates and adds a particle to the system + * @return {boolean} false if the system is full, otherwise true + */ + addParticle: function () { + if (this.particles.length == this.totalParticles) { + return false; + } + + var particle = new Particle(); + this.initParticle(particle); + this.particles.push(particle); + return true; + }, + initParticle: function (particle) { + particle.pos.x = this.x + this.posVar.x * MathHelper.randomMinus1to1(); + particle.pos.y = this.y + this.posVar.y * MathHelper.randomMinus1to1(); + particle.startPos.copyFrom(particle.pos); + + var a = Radians.fromDegrees(this.angle + (this.angleVar * MathHelper.randomMinus1to1())), + v = new Vector(Math.cos(a), Math.sin(a)), + s = this.speed + this.speedVar * MathHelper.randomMinus1to1(); + + // direction + v.multiply(s); + particle.dir = v; + + // radial acceleration + particle.radialAccel = this.radialAccel + + this.radialAccelVar * MathHelper.randomMinus1to1(); + + // tangential acceleration + particle.tangentialAccel = this.tangentialAccel + + this.tangentialAccelVar * MathHelper.randomMinus1to1(); + + // life + particle.life = this.life + this.lifeVar * MathHelper.randomMinus1to1(); + + // color + var start = new RGBAColor( + this.startColor.r + this.startColorVar.r * MathHelper.randomMinus1to1(), + this.startColor.g + this.startColorVar.g * MathHelper.randomMinus1to1(), + this.startColor.b + this.startColorVar.b * MathHelper.randomMinus1to1(), + this.startColor.a + this.startColorVar.a * MathHelper.randomMinus1to1()); + + var end = new RGBAColor( + this.endColor.r + this.endColorVar.r * MathHelper.randomMinus1to1(), + this.endColor.g + this.endColorVar.g * MathHelper.randomMinus1to1(), + this.endColor.b + this.endColorVar.b * MathHelper.randomMinus1to1(), + this.endColor.a + this.endColorVar.a * MathHelper.randomMinus1to1()); + + particle.color = start; + particle.deltaColor.r = (end.r - start.r) / particle.life; + particle.deltaColor.g = (end.g - start.g) / particle.life; + particle.deltaColor.b = (end.b - start.b) / particle.life; + particle.deltaColor.a = (end.a - start.a) / particle.life; + + // size + particle.size = this.size + this.sizeVar * MathHelper.randomMinus1to1(); + }, + update: function (delta) { + this._super(delta); + if (this.onFinished) { + if (this.particles.length === 0 && !this.active) { + this.onFinished(this); + return; + } + } + + if (this.active && this.emissionRate) { + var rate = 1 / this.emissionRate; + this.emitCounter += delta; + while (this.particles.length < this.totalParticles && this.emitCounter > rate) { + this.addParticle(); + this.emitCounter -= rate; + } + + this.elapsed += delta; + if (this.duration !== -1 && this.duration < this.elapsed) { + this.stopSystem(); + } + } + + this.particleIdx = 0; + while (this.particleIdx < this.particles.length) { + var p = this.particles[this.particleIdx]; + if (p.life > 0) { + + this.updateParticleLocation(p, delta); + + p.color.r += (p.deltaColor.r * delta); + p.color.g += (p.deltaColor.g * delta); + p.color.b += (p.deltaColor.b * delta); + p.color.a += (p.deltaColor.a * delta); + + p.life -= delta; + + this.updateParticle(p, this.particleIdx, delta); + this.particleIdx++; + } + else { + // remove the particle + this.removeParticle(this.particleIdx); + } + } + }, + updateParticleLocation: function (p, delta) { + var tmp, radial, tangential; + + // radial acceleration + if (p.pos.x || p.pos.y) { + radial = p.pos.copy(); + radial.normalize(); + } + else { + radial = new Vector(0, 0); + } + tangential = radial.copy(); + radial.multiply(p.radialAccel); + + // tangential acceleration + var newy = tangential.x; + tangential.x = -tangential.y; + tangential.y = newy; + tangential.multiply(p.tangentialAccel); + + // (gravity + radial + tangential) * delta + tmp = Vector.add(radial, tangential); + tmp.add(this.gravity); + tmp.multiply(delta); + p.dir.add(tmp); + + tmp.copyFrom(p.dir); + tmp.multiply(delta); + p.pos.add(tmp); + + + }, + updateParticle: function (particle, index) { + this.vertices[this.particleIdx] = new PointSprite( + particle.pos.x, + particle.pos.y, + particle.size); + + this.colors[this.particleIdx] = particle.color; + }, + removeParticle: function (index) { + this.particles.splice(index, 1); + }, + startSystem: function (initialParticles) { + this.particles.length = 0; + for (var i = 0; i < initialParticles; i++) { + this.addParticle(); + } + this.active = true; + }, + stopSystem: function () { + this.active = false; + this.elapsed = this.duration; + this.emitCounter = 0; + }, + resetSystem: function () { + this.elapsed = 0; + this.emitCounter = 0; + }, + draw: function () { + this.preDraw(); + + // only draw if the image is non-transparent + if (this.color.a !== 0) { + var ctx = Canvas.context, + image = this.texture.image; + for (var i = 0, len = this.particleIdx; i < len; i++) { + var p = this.particles[i]; + ctx.drawImage(image, Math.round(p.x), Math.round(p.y)); + } + } + + this.postDraw(); + }, + isFull: function () { + return (this.particles.length === this.totalParticles); + } + }); + + return Particles; + } +); +define('visual/MultiParticles', + [ + 'visual/Particles', + 'core/Rectangle', + 'utils/MathHelper', + 'visual/ImageMultiDrawer', + 'resolution' + ], + function (Particles, Rectangle, MathHelper, ImageMultiDrawer, resolution) { + + var MultiParticles = Particles.extend({ + init: function (numParticles, texture) { + this._super(numParticles); + + this.imageGrid = texture; + this.drawer = new ImageMultiDrawer(texture); + this.width = resolution.CANVAS_WIDTH; + this.height = resolution.CANVAS_HEIGHT; + }, + initParticle: function (particle) { + var texture = this.imageGrid, + n = MathHelper.randomRange(0, texture.rects.length - 1), + tquad = texture.rects[n], + vquad = new Rectangle(0, 0, 0, 0); // don't draw initially + + this.drawer.setTextureQuad(this.particles.length, tquad, vquad, 1); + + this._super(particle); + + particle.width = tquad.w * particle.size; + particle.height = tquad.h * particle.size; + }, + updateParticle: function (particle, index) { + // update the current position + this.drawer.vertices[index] = new Rectangle( + particle.pos.x - particle.width / 2, + particle.pos.y - particle.height / 2, + particle.width, + particle.height); + + // update the alpha in the drawer + this.drawer.alphas[index] = particle.color.a; + + // update the color in the particle system + this.colors[index] = particle.color; + }, + removeParticle: function (index) { + this.drawer.removeQuads(index); + this._super(index); + }, + draw: function () { + this.preDraw(); + + /* for debugging rotation: draw a line from origin at 0 degrees + var ctx = Canvas.context; + ctx.save(); + ctx.lineWidth = 5; + ctx.strokeStyle = "blue"; + ctx.beginPath(); + ctx.moveTo(this.drawX, this.drawY); + ctx.lineTo(this.drawX, this.drawY - 100); + ctx.closePath(); + ctx.stroke(); + ctx.restore(); + */ + + this.drawer.draw(); + this.postDraw(); + } + }); + + return MultiParticles; + } +); + +define('visual/RotateableMultiParticles', + [ + 'visual/MultiParticles', + 'utils/Radians', + 'utils/MathHelper', + 'core/Vector' + ], + function (MultiParticles, Radians, MathHelper, Vector) { + var RotateableMultiParticles = MultiParticles.extend({ + init: function (numParticles, texture) { + this._super(numParticles, texture); + this.drawer.rotationAngles = []; + this.drawer.rotationPositions = []; + }, + initParticle: function (particle) { + this._super(particle); + particle.angle = 0; + particle.deltaAngle = Radians.fromDegrees( + this.rotateSpeed + this.rotateSpeedVar * MathHelper.randomMinus1to1()); + + var index = this.particles.length; + this.drawer.rotationAngles[index] = 0; + this.drawer.rotationPositions[index] = new Vector(0, 0); + }, + rotatePreCalc: function (v, cosA, sinA, cx, cy) { + v.x -= cx; + v.y -= cy; + + var nx = v.x * cosA - v.y * sinA, + ny = v.x * sinA + v.y * cosA; + + v.x = nx + cx; + v.y = ny + cy; + }, + updateParticle: function (particle, index, delta) { + this._super(particle, index, delta); + particle.angle += (particle.deltaAngle * delta); + + // we need to save the angle and position for drawing rotation + this.drawer.rotationAngles[index] = particle.angle; + this.drawer.rotationPositions[index].copyFrom(particle.pos); + }, + + removeParticle: function (index) { + this.drawer.rotationAngles.splice(index, 1); + this.drawer.rotationPositions.splice(index, 1); + this._super(index); + } + + }); + + return RotateableMultiParticles; + } +); + +define('game/CandyBreak', + [ + 'visual/RotateableMultiParticles', + 'resolution', + 'utils/MathHelper', + 'core/Rectangle' + ], + function (RotateableMultiParticles, resolution, MathHelper, Rectangle) { + + var IMG_OBJ_CANDY_01_piece_01 = 3; + var IMG_OBJ_CANDY_01_piece_02 = 4; + var IMG_OBJ_CANDY_01_piece_03 = 5; + var IMG_OBJ_CANDY_01_piece_04 = 6; + var IMG_OBJ_CANDY_01_piece_05 = 7; + + var CandyBreak = RotateableMultiParticles.extend({ + init: function (numParticles, texture) { + this._super(numParticles, texture); + + // duration + this.duration = 2; + + // gravity + this.gravity.x = 0; + this.gravity.y = 500.0; + + // angle + this.angle = -90; + this.angleVar = 50; + + // speed of particles + this.speed = 150.0; + this.speedVar = 70.0; + + // radial + this.radialAccel = 0; + this.radialAccelVar = 1; + + // tCTRial + this.tangentialAccel = 0; + this.tangentialAccelVar = 1; + + // emitter position + this.posVar.x = 0.0; + this.posVar.y = 0.0; + + // life of particles + this.life = 2; + this.lifeVar = 0; + + // size, in pixels + this.size = 1; + this.sizeVar = 0.0; + + // emits per second + this.emissionRate = 100; + + // color of particles + this.startColor.r = 1.0; + this.startColor.g = 1.0; + this.startColor.b = 1.0; + this.startColor.a = 1.0; + this.startColorVar.r = 0.0; + this.startColorVar.g = 0.0; + this.startColorVar.b = 0.0; + this.startColorVar.a = 0.0; + this.endColor.r = 1.0; + this.endColor.g = 1.0; + this.endColor.b = 1.0; + this.endColor.a = 1.0; + this.endColorVar.r = 0.0; + this.endColorVar.g = 0.0; + this.endColorVar.b = 0.0; + this.endColorVar.a = 0.0; + + this.rotateSpeed = 0.0; + this.rotateSpeedVar = 600; + + // additive + this.blendAdditive = false; + }, + initParticle: function (particle) { + this._super(particle); + + var texture = this.imageGrid, + n = MathHelper.randomRange(IMG_OBJ_CANDY_01_piece_01, IMG_OBJ_CANDY_01_piece_05), + tquad = texture.rects[n], + vquad = new Rectangle(0, 0, 0, 0); // don't draw initially + + this.drawer.setTextureQuad(this.particles.length, tquad, vquad); + + particle.width = tquad.w * this.size; + particle.height = tquad.h * this.size; + } + }); + + return CandyBreak; + } +); +define('game/Drawing', + [ + 'visual/GameObject', + 'resources/ResourceId', + 'utils/PubSub' + ], + function (GameObject, ResourceId, PubSub) { + + var Drawing = GameObject.extend({ + init: function (hiddenId, drawingIndex) { + this._super(); + this.initTextureWithId(ResourceId.IMG_DRAWING_HIDDEN); + this.setTextureQuad(hiddenId); + this.ingame = true; + this.drawingIndex = drawingIndex; + this.passTransformationsToChilds = false; + }, + showDrawing: function () { + PubSub.publish(PubSub.ChannelId.DrawingClicked, this.drawingIndex); + } + }); + + return Drawing; + } +); +define('game/FingerCut', + [], + function () { + + /** + * @constructor + * @param start {Vector} + * @param end {Vector} + * @param startSize {number} + * @param endSize {number} + * @param color {RGBAColor} + */ + function FingerCut(start, end, startSize, endSize, color) { + this.start = start; + this.end = end; + this.startSize = startSize; + this.endSize = endSize; + this.color = color; + } + + return FingerCut; + } +); +define('physics/ConstraintSystem', + [ + 'utils/Class', + 'core/Vector', + 'utils/Log' + ], + function (Class, Vector, Log) { + + var ConstraintSystem = Class.extend({ + init: function () { + this.relaxationTimes = 1; + + this.parts = []; + }, + addPartAtIndex: function (cp, index) { + // splice with removeLength=0 means we just insert + // the additional element (cp) at the index + this.parts.splice(index, 0, cp); + }, + addPart: function (cp) { + this.parts[this.parts.length] = cp; + }, + log: function () { + Log.debug('Constraint System Log:'); + for (var i = 0, partsLen = this.parts.length; i < partsLen; i++) { + var cp = this.parts[i]; + Log.debug('-- Point: ' + cp.posString()); + for (var j = 0, constraintsLen = cp.constraints.length; j < constraintsLen; j++) { + var c = cp.constraints[j]; + var cInfo = '---- Constraint: ' + c.cp.posString() + ' len: ' + c.restLength; + Log.debug(cInfo); + } + } + }, + removePartAtIndex: function (index) { + this.parts.splice(index, 1); + }, + update: function (delta) { + var parts = this.parts, + numParts = parts.length, + relaxationTimes = this.relaxationTimes; + + // update each part + for (var i = 0; i < numParts; i++) { + parts[i].update(delta); + } + + // satisfy constraints during each relaxation period + + satisfyConstraintArray(parts, relaxationTimes) + } + + // NOTE: base draw() implementation isn't used so we won't port it yet + }); + + return ConstraintSystem; + } +); +define('physics/ConstraintType', + [], + function () { + /** @enum {number} */ + var ConstraintType = { + DISTANCE: 0, + NOT_MORE_THAN: 1, + NOT_LESS_THAN: 2 + }; + + return ConstraintType; + } +); + +define('physics/Gravity', + [ + 'core/Vector', + 'utils/Constants' + ], + function (Vector, Constants) { + + var GCONST = (9.8 * Constants.PIXEL_TO_SI_METERS_K); + + var Gravity = { + /** + * @const + * @type {number} + */ + EARTH_Y: GCONST, + current: new Vector(0, GCONST), + toggle: function () { + Gravity.current.y = -Gravity.current.y; + }, + isZero: function () { + return (Gravity.current.y === 0 && Gravity.current.x === 0); + }, + isNormal: function () { + return (Gravity.current.y === Gravity.EARTH_Y && Gravity.current.x === 0); + }, + reset: function () { + Gravity.current.x = 0; + Gravity.current.y = GCONST; + } + }; + + return Gravity; + } +); +define('physics/MaterialPoint', + [ + 'utils/Class', + 'utils/Constants', + 'core/Vector', + 'physics/Gravity' + ], + function (Class, Constants, Vector, Gravity) { + + var MaterialPoint = Class.extend({ + init: function () { + this.disableGravity = false; + this.setWeight(1); + this.resetAll(); + }, + setWeight: function (w) { + this.weight = w; + this.invWeight = 1 / w; + this.gravity = new Vector(0, Constants.EARTH_Y * w); + }, + resetAll: function () { + var newZero = Vector.newZero; + this.v = newZero(); // velocity vector + this.a = newZero(); // acceleration vector + this.pos = newZero(); + this.posDelta = newZero(); + this.totalForce = newZero(); + }, + updateWithPrecision: function (delta, precision) { + + // Calculate number Of iterations to be made at this update depending + // on maxPossible_dt And dt (chop off fractional part and add 1) + var numIterations = ((delta / precision) >> 0) + 1; + + // update delta based on num of iterations + if (numIterations != 0) { // avoid division by zero + delta = delta / numIterations; + } + + for (var i = 0; i < numIterations; i++) { + this.update(delta); + } + }, + update: function (delta) { + this.totalForce = Vector.newZero(); + + // incorporate gravity + if (!this.disableGravity) { + if (!Gravity.isZero()) { + this.totalForce.add( + Vector.multiply(Gravity.current, this.weight)); + } + else { + this.totalForce.add(this.gravity); + } + } + + var adjustedDelta = delta / Constants.TIME_SCALE; + this.totalForce.multiply(this.invWeight); + this.a = Vector.multiply(this.totalForce, adjustedDelta); + this.v.add(this.a); + + this.posDelta = Vector.multiply(this.v, adjustedDelta); + this.pos.add(this.posDelta); + }, + applyImpulse: function (impulse, delta) { + if (!impulse.isZero()) { + var im = Vector.multiply(impulse, delta / Constants.TIME_SCALE); + this.pos.add(im); + + } + } + }); + + return MaterialPoint; + } +); +function satisfyConstraintArray (arr, n) { + // NOTE: this method is a perf hotspot so be careful with changes + n = n || 1; + + var len = arr.length; + var cons; + + if (!len) return; + + //loop over the rest length + while (n--) { + + for (var cIndex = 0; cIndex < len; ++cIndex) { + + cons = arr[cIndex]; + + var constraints = cons.constraints, + num = constraints.length; + + var pin = cons.pin, + pos = cons.pos, + invWeight = cons.invWeight, + tmp1X, tmp1Y, + tmp2X, tmp2Y; + + if (pin.x !== -1 /* Constants.UNDEFINED */) { + pos.x = pin.x; + pos.y = pin.y; + continue; + } + + for (var i = 0; i < num; i++) { + var c = constraints[i], + cp = c.cp, + cpPos = cp.pos; + + + tmp1X = cpPos.x - pos.x; + tmp1Y = cpPos.y - pos.y; + + if (tmp1X === 0 && tmp1Y === 0) { + tmp1X = 1; + tmp1Y = 1; + } + + var sqrDeltaLength = (tmp1X * tmp1X + tmp1Y * tmp1Y), // get dot product inline + restLength = c.restLength, + sqrRestLength = restLength * restLength, + cType = c.type; + + if (cType === 1 /* ConstraintType.NOT_MORE_THAN */) { + if (sqrDeltaLength <= sqrRestLength) + continue; + } + else if (cType === 2 /*ConstraintType.NOT_LESS_THAN */) { + if (sqrDeltaLength >= sqrRestLength) + continue; + } + + var pinUndefined = (cp.pin.x === -1 /* Constants.UNDEFINED */), + invWeight2 = cp.invWeight, + deltaLength = Math.sqrt(sqrDeltaLength), + minDeltaLength = (deltaLength > 1) ? deltaLength : 1, + diff = (deltaLength - restLength) / + (minDeltaLength * (invWeight + invWeight2)); + + // copy the first position before modification + if (pinUndefined) { + tmp2X = tmp1X; + tmp2Y = tmp1Y; + } + + var tmp1Multiplier = invWeight * diff; + tmp1X *= tmp1Multiplier; + tmp1Y *= tmp1Multiplier; + + pos.x += tmp1X; + pos.y += tmp1Y; + + if (pinUndefined) { + var tmp2Multiplier = invWeight2 * diff; + cpPos.x -= tmp2X * tmp2Multiplier; + cpPos.y -= tmp2Y * tmp2Multiplier; + } + } + } + + }//end while +} + +define('physics/ConstrainedPoint', + [ + 'physics/ConstraintType', + 'physics/MaterialPoint', + 'core/Vector', + 'utils/Constants', + 'physics/Gravity' + ], + function (ConstraintType, MaterialPoint, Vector, Constants, Gravity) { + + function Constraint(cp, restLength, type) { + this.cp = cp; + this.restLength = restLength; + this.type = type; + } + + var ConstrainedPoint = MaterialPoint.extend({ + init: function () { + this.prevPos = new Vector(Constants.INT_MAX, Constants.INT_MAX); + this.pin = new Vector(Constants.UNDEFINED, Constants.UNDEFINED); + this.constraints = []; + this.totalForce = Vector.newZero(); + this._super(); + }, + + /** + * Resets the point by clearing previous position and removing constraints + */ + resetAll: function () { + this._super(); + this.prevPos.x = Constants.INT_MAX; + this.prevPos.y = Constants.INT_MAX; + this.removeConstraints(); + }, + /** + * removes all constraints + */ + removeConstraints: function () { + this.constraints = []; + }, + /** + * Add a new constraint + * @param cp {ConstrainedPoint} + * @param restLength {number} + * @param type {ConstraintType} + */ + addConstraint: function (cp, restLength, type) { + var ct = new Constraint(cp, restLength, type); + this.constraints.push(ct); + }, + /** + * Removes the specified constraint + * @param cp {ConstrainedPoint} + */ + removeConstraint: function (cp) { + var constraints = this.constraints, + len = constraints.length; + for (var i = 0; i < len; i++) { + if (constraints[i].cp === cp) { + constraints.splice(i, 1); + return; + } + } + }, + /** + * Removes the constraint at the specified index + * @param index {number} + */ + removeConstraintAtIndex: function (index) { + this.constraints.splice(index, 1); + }, + /** + * @param fromCp {ConstrainedPoint} + * @param toCp {ConstrainedPoint} + */ + changeConstraint: function (fromCp, toCp) { + var constraints = this.constraints, + len = constraints.length; + for (var i = 0; i < len; i++) { + var constraint = constraints[i]; + if (constraint.cp === fromCp) { + constraint.cp = toCp; + return; + } + } + }, + /** + * Returns true if the constrained point is used by a constraint in the system + * @param cp {ConstrainedPoint} + * @return {boolean} + */ + hasConstraint: function (cp) { + var constraints = this.constraints, + len = constraints.length; + for (var i = 0; i < len; i++) { + if (constraints[i].cp === cp) { + return true; + } + } + + return false; + }, + /** + * @param cp {ConstrainedPoint} + * @param restLength {number} + */ + changeRestLength: function (cp, restLength) { + var constraints = this.constraints, + len = constraints.length; + for (var i = 0; i < len; i++) { + var constraint = constraints[i]; + if (constraint.cp === cp) { + constraint.restLength = restLength; + return; + } + } + }, + /** + * @param fromCp {ConstrainedPoint} + * @param toCp {ConstrainedPoint} + * @param restLength {number} + */ + changeConstraintAndLength: function (fromCp, toCp, restLength) { + var constraints = this.constraints, + len = constraints.length; + for (var i = 0; i < len; i++) { + var constraint = constraints[i]; + if (constraint.cp === fromCp) { + constraint.cp = toCp; + constraint.restLength = restLength; + return; + } + } + }, + /** + * @param cp {ConstrainedPoint} + * @return {number} + */ + restLength: function (cp) { + var constraints = this.constraints, + len = constraints.length; + for (var i = 0; i < len; i++) { + var constraint = constraints[i]; + if (constraint.cp === cp) { + return constraint.restLength; + } + } + + return Constants.UNDEFINED; + }, + /** + * @param delta {number} + */ + update: function (delta) { + + var totalForce = this.totalForce, + currentGravity = Gravity.current; + + if (!this.disableGravity) { + if (currentGravity.y !== 0 || currentGravity.x !== 0) { + totalForce.x = currentGravity.x; + totalForce.y = currentGravity.y; + } + else { + totalForce.x = this.gravity.x * this.invWeight; + totalForce.y = this.gravity.y * this.invWeight; + } + + } else { + totalForce.x = 0; + totalForce.y = 0; + } + + var aMultiplier = delta / Constants.TIME_SCALE * delta / Constants.TIME_SCALE; + this.a.x = this.totalForce.x * aMultiplier; + this.a.y = this.totalForce.y * aMultiplier; + + if (this.prevPos.x === Constants.INT_MAX) { + this.prevPos.x = this.pos.x; + this.prevPos.y = this.pos.y; + } + + this.posDelta.x = this.pos.x - this.prevPos.x + this.a.x; + this.posDelta.y = this.pos.y - this.prevPos.y + this.a.y; + + if (delta > 0) { + var vMultiplier = 1 / delta; + this.v.x = this.posDelta.x * vMultiplier; + this.v.y = this.posDelta.y * vMultiplier; + } + + this.prevPos.x = this.pos.x; + this.prevPos.y = this.pos.y; + + this.pos.x += this.posDelta.x; + this.pos.y += this.posDelta.y; + + }, + satisfyConstraints: function () { + // NOTE: this method is a perf hotspot so be careful with changes + var pin = this.pin, + pos = this.pos, + invWeight = this.invWeight, + tmp1X, tmp1Y, + tmp2X, tmp2Y; + + if (pin.x !== -1 /* Constants.UNDEFINED */) { + pos.x = pin.x; + pos.y = pin.y; + return; + } + + var constraints = this.constraints, + num = constraints.length; + + + for (var i = 0; i < num; i++) { + var c = constraints[i], + cp = c.cp, + cpPos = cp.pos; + + + tmp1X = cpPos.x - pos.x; + tmp1Y = cpPos.y - pos.y; + + if (tmp1X === 0 && tmp1Y === 0) { + tmp1X = 1; + tmp1Y = 1; + } + + var sqrDeltaLength = (tmp1X * tmp1X + tmp1Y * tmp1Y), // get dot product inline + restLength = c.restLength, + sqrRestLength = restLength * restLength, + cType = c.type; + if (cType === 1 /* ConstraintType.NOT_MORE_THAN */) { + if (sqrDeltaLength <= sqrRestLength) + continue; + } + else if (cType === 2 /*ConstraintType.NOT_LESS_THAN */) { + if (sqrDeltaLength >= sqrRestLength) + continue; + } + + var pinUndefined = (cp.pin.x === -1 /* Constants.UNDEFINED */), + invWeight2 = cp.invWeight, + deltaLength = Math.sqrt(sqrDeltaLength), + minDeltaLength = (deltaLength > 1) ? deltaLength : 1, + diff = (deltaLength - restLength) / + (minDeltaLength * (invWeight + invWeight2)); + + // copy the first position before modification + if (pinUndefined) { + tmp2X = tmp1X; + tmp2Y = tmp1Y; + } + + var tmp1Multiplier = invWeight * diff; + tmp1X *= tmp1Multiplier; + tmp1Y *= tmp1Multiplier; + + pos.x += tmp1X; + pos.y += tmp1Y; + + if (pinUndefined) { + var tmp2Multiplier = invWeight2 * diff; + cpPos.x -= tmp2X * tmp2Multiplier; + cpPos.y -= tmp2Y * tmp2Multiplier; + } + } + }, + qcpUpdate: function (delta) { + + // qcpUpdate only differs from update in that it includes material + // force calculations, however those don't appear to be used. So + // for now, qcpUpdate simply calls update + + this.update(delta); + }, + posString: function () { + return this.pos.x.toFixed(2) + ', ' + this.pos.y.toFixed(2); + } + }); + + return ConstrainedPoint; + } +); +define('game/Bungee', + [ + 'physics/ConstraintSystem', + 'physics/ConstrainedPoint', + 'resolution', + 'utils/Constants', + 'physics/ConstraintType', + 'core/Vector', + 'utils/Canvas', + 'core/RGBAColor', + 'utils/Mover', + 'utils/Log' + ], + function (ConstraintSystem, ConstrainedPoint, resolution, Constants, ConstraintType, Vector, Canvas, RGBAColor, Mover, Log) { + + /** + * @const + * @type {number} + */ + var ROLLBACK_K = 0.5; + + /** + * @const + * @type {number} + */ + var BUNGEE_RELAXION_TIMES = 25; + + /** + * @const + * @type {number} + */ + var MAX_BUNGEE_SEGMENTS = 10; + + /** + * @const + * @type {number} + */ + var DEFAULT_PART_WEIGHT = 0.02; + + /** + * @const + * @type {number} + */ + var STRENGTHENED_PART_WEIGHT = 0.5; + + /** + * @const + * @type {number} + */ + var CUT_DISSAPPEAR_TIMEOUT = 2.0; + + /** + * @const + * @type {number} + */ + var WHITE_TIMEOUT = 0.05; + + + /** @enum {number} */ + var BungeeMode = { + NORMAL: 0, + LOCKED: 1 + }; + + // create temp color objects used during draw (to reduce allocations) + var drawBlack = new RGBAColor(0, 0, 0, 1), + drawC1 = new RGBAColor(0, 0, 0, 1), + drawD1 = new RGBAColor(0, 0, 0, 1), + drawC2 = new RGBAColor(0, 0, 0, 1), + drawD2 = new RGBAColor(0, 0, 0, 1); + + var Bungee = ConstraintSystem.extend({ + /** + * Create a new Rope + * @param headCp {ConstrainedPoint} head constrained point + * @param hx {number} head location: x + * @param hy {number} head location: y + * @param tailCp {ConstrainedPoint} tail constrained point + * @param tx {number} tail location: x + * @param ty {number} tail location: y + * @param len {number} length of the rope + */ + init: function (headCp, hx, hy, tailCp, tx, ty, len) { + this._super(); + this.relaxed = 0; + this.relaxationTimes = BUNGEE_RELAXION_TIMES; + this.lineWidth = resolution.DEFAULT_BUNGEE_LINE_WIDTH; + this.width = resolution.DEFAULT_BUNGEE_WIDTH; + this.cut = Constants.UNDEFINED; + this.cutTime = 0; + this.bungeeMode = BungeeMode.NORMAL; + this.highlighted = false; + this.BUNGEE_REST_LEN = resolution.BUNGEE_REST_LEN; + + this.bungeeAnchor = (headCp != null) + ? headCp + : new ConstrainedPoint(); + + if (tailCp != null) + this.tail = tailCp; + else { + this.tail = new ConstrainedPoint(); + this.tail.setWeight(1); + } + + this.bungeeAnchor.setWeight(DEFAULT_PART_WEIGHT); + this.bungeeAnchor.pos.x = hx; + this.bungeeAnchor.pos.y = hy; + + this.tail.pos.x = tx; + this.tail.pos.y = ty; + this.addPart(this.bungeeAnchor); + this.addPart(this.tail); + + this.tail.addConstraint( + this.bungeeAnchor, + this.BUNGEE_REST_LEN, + ConstraintType.DISTANCE); + + var offset = Vector.subtract(this.tail.pos, this.bungeeAnchor.pos); + var pointsNum = Math.round(len / this.BUNGEE_REST_LEN + 2); + offset.divide(pointsNum); + + this.roll(len, offset); + this.forceWhite = false; + this.initialCandleAngle = Constants.UNDEFINED; + this.chosenOne = false; + this.hideTailParts = false; + this.dontDrawRedStretch = false; + + this.drawPts = []; + + this.BUNGEE_BEZIER_POINTS = resolution.BUNGEE_BEZIER_POINTS; + }, + /** + * @return {number} + */ + getLength: function () { + var len = 0, + parts = this.parts, + numParts = parts.length; + if (numParts > 0) { + var v = parts[0].pos; + for (var i = 1; i < numParts; i++) { + var part = parts[i]; + len += v.distance(part.pos); + v = part.pos; + } + } + return len; + }, + roll: function (rollLen, offset) { + if (offset == null) { + offset = Vector.newZero(); + } + + var parts = this.parts, + prev = parts[parts.length - 2], + tail = this.tail, + heroRestLen = tail.restLength(prev), + cp = null; + + while (rollLen > 0) { + if (rollLen >= this.BUNGEE_REST_LEN) { + prev = parts[parts.length - 2]; + cp = new ConstrainedPoint(); + cp.setWeight(DEFAULT_PART_WEIGHT); + cp.pos = Vector.add(prev.pos, offset); + this.addPartAtIndex(cp, this.parts.length - 1); + + tail.changeConstraintAndLength(prev, cp, heroRestLen); + cp.addConstraint(prev, this.BUNGEE_REST_LEN, ConstraintType.DISTANCE); + rollLen -= this.BUNGEE_REST_LEN; + } + else { + var newRestLen = rollLen + heroRestLen; + if (newRestLen > this.BUNGEE_REST_LEN) { + rollLen = this.BUNGEE_REST_LEN; + heroRestLen = newRestLen - this.BUNGEE_REST_LEN; + } + else { + prev = parts[parts.length - 2]; + tail.changeRestLength(prev, newRestLen); + rollLen = 0; + } + } + } + }, + rollBack: function (amount) { + var rollBackLen = amount, + parts = this.parts, + partsCount = parts.length, + prev = parts[partsCount - 2], + tail = this.tail, + heroRestLen = tail.restLength(prev), + oldAnchor; + + while (rollBackLen > 0) { + if (rollBackLen >= this.BUNGEE_REST_LEN) { + + var oldAnchorIndex = partsCount - 2, + newAnchor = parts[partsCount - 3]; + + oldAnchor = parts[oldAnchorIndex]; + tail.changeConstraintAndLength(oldAnchor, newAnchor, heroRestLen); + this.removePartAtIndex(oldAnchorIndex); + partsCount--; + rollBackLen -= this.BUNGEE_REST_LEN; + } + else { + var newRestLen = heroRestLen - rollBackLen; + if (newRestLen < 1) { + rollBackLen = this.BUNGEE_REST_LEN; + heroRestLen = this.BUNGEE_REST_LEN + newRestLen + 1; + } + else { + oldAnchor = parts[partsCount - 2]; + tail.changeRestLength(oldAnchor, newRestLen); + rollBackLen = 0; + } + } + } + + var newTailRestLen = (partsCount - 1) * (this.BUNGEE_REST_LEN + 3); + var constraints = tail.constraints, + numConstraints = constraints.length; + for (var i = 0; i < numConstraints; i++) { + var c = constraints[i]; + if (c.type === ConstraintType.NOT_MORE_THAN) + c.restLength = newTailRestLen; + } + return rollBackLen; + }, + strengthen: function () { + var parts = this.parts, + numParts = parts.length; + for (var i = 0; i < numParts; i++) { + var cp = parts[i]; + if (this.bungeeAnchor.pin.x != Constants.UNDEFINED) { + if (cp != this.tail) { + cp.setWeight(STRENGTHENED_PART_WEIGHT); + } + + if (i > 0) { + var restLen = i * (this.BUNGEE_REST_LEN + 3); + cp.addConstraint(this.bungeeAnchor, restLen, ConstraintType.NOT_MORE_THAN); + } + } + } + }, + /** + * Updates the rope based on the time delta + * @param delta {number} + */ + update: function (delta) { + if (this.cutTime > 0) { + this.cutTime = Mover.moveToTarget(this.cutTime, 0, 1, delta); + if (this.cutTime < CUT_DISSAPPEAR_TIMEOUT - WHITE_TIMEOUT && this.forceWhite) { + this.removePart(this.cut); + } + } + + var parts = this.parts, + numParts = parts.length, + relaxationTimes = this.relaxationTimes, + tail = this.tail, + i, cp, k; + + for (i = 0; i < numParts; i++) { + cp = parts[i]; + if (cp !== tail) { + //Log.debug('Before qcpUpdate, [' + i + '] : ' + cp.pos ); + // NOTE: iOS calls qcpUpdate which is identical to update except + // it incorporates material forces. However, those don't appear to + // be used so we'll simply call update() instead. + cp.update(delta); + } + } + + // satisfy constraints during each relaxation period + satisfyConstraintArray(parts, relaxationTimes); + + // for (i = 0; i < relaxationTimes; i++) { + // for (k = 0; k < numParts; k++) { + // parts[k].satisfyConstraints(); + // } + // } + }, + removePart: function (partIndex) { + this.forceWhite = false; + + var parts = this.parts, + p1 = parts[partIndex], + p2 = parts[partIndex + 1]; + + if (!p2) { + p1.removeConstraints(); + } + else { + var p2Constraints = p2.constraints, + p2NumConstraints = p2Constraints.length; + for (var k = 0; k < p2NumConstraints; k++) { + var c = p2Constraints[k]; + if (c.cp === p1) { + p2.removeConstraintAtIndex(k); + + var np2 = new ConstrainedPoint(); + np2.setWeight(0.00001); + np2.pos.copyFrom(p2.pos); + np2.prevPos.copyFrom(p2.prevPos); + this.addPartAtIndex(np2, partIndex + 1); + np2.addConstraint(p1, this.BUNGEE_REST_LEN, ConstraintType.DISTANCE); + break; + } + } + } + + for (var i = 0, numParts = parts.length; i < numParts; i++) { + var cp = parts[i]; + if (cp != this.tail) + cp.setWeight(0.00001); + } + }, + setCut: function (partIndex) { + this.cut = partIndex; + this.cutTime = CUT_DISSAPPEAR_TIMEOUT; + this.forceWhite = true; + this.highlighted = false; + }, + draw: function () { + var parts = this.parts, + count = parts.length, + ctx = Canvas.context, + i, part, prevPart; + + ctx.lineJoin = "round"; + ctx.lineWidth = this.lineWidth; + + if (this.cut === Constants.UNDEFINED) { + var pts = new Array(count); + for (i = 0; i < count; i++) { + pts[i] = parts[i].pos; + //Log.debug('Point ' + i + ': ' + pts[i].toString()); + } + this.drawBungee(pts); + } + else { + var pts1 = [], + pts2 = [], + part2 = false; + for (i = 0; i < count; i++) { + part = parts[i]; + var linked = true; + + if (i > 0) { + prevPart = parts[i - 1]; + if (!part.hasConstraint(prevPart)) { + linked = false; + } + } + + if (part.pin.x === Constants.UNDEFINED && !linked) { + part2 = true; + } + + if (!part2) { + pts1[i] = part.pos; + } + else { + pts2.push(part.pos); + } + } + + if (pts1.length > 0) { + this.drawBungee(pts1); + } + if (pts2.length > 0 && !this.hideTailParts) { + this.drawBungee(pts2); + } + } + ctx.lineWidth = 1; + }, + drawBungee: function (pts) { + var count = pts.length, + points = this.BUNGEE_BEZIER_POINTS, + drawPts = this.drawPts; + + // we can't calc the distance for a single point + if (count < 2) + return; + + // set the global alpha + var alpha = (this.cut === Constants.UNDEFINED || this.forceWhite) + ? 1 + : this.cutTime / (CUT_DISSAPPEAR_TIMEOUT - WHITE_TIMEOUT); + + if (alpha <= 0) { + return; + } + + var firstPoint = pts[0], + secondPoint = pts[1], + tx = firstPoint.x - secondPoint.x, + ty = firstPoint.y - secondPoint.y, + ptsDistance = Math.sqrt(tx * tx + ty * ty); + + //Log.debug('DrawBungee - point1: ' + firstPoint + ' point2: ' + secondPoint); + + if (ptsDistance <= this.BUNGEE_REST_LEN + 0.3) + this.relaxed = 0; + else if (ptsDistance <= this.BUNGEE_REST_LEN + 1) + this.relaxed = 1; + else if (ptsDistance < this.BUNGEE_REST_LEN + 4) + this.relaxed = 2; + else + this.relaxed = 3; + + if (count < 3) + return; + + var black = drawBlack, + c1 = drawC1, + d1 = drawD1, + c2 = drawC2, + d2 = drawD2; + + // reset the colors (we're reusing temp color objects) + black.r = 0; black.g = 0; black.b = 0; black.a = alpha; + c1.r = 95 / 200; c1.g = 61 / 200; c1.b = 37 / 200; c1.a = alpha; + d1.r = 95 / 500; d1.g = 61 / 500; d1.b = 37 / 500; d1.a = alpha; + c2.r = 152 / 225; c2.g = 99 / 225; c2.b = 62 / 225; c2.a = alpha; + d2.r = 152 / 500; d2.g = 99 / 500; d2.b = 62 / 500; d2.a = alpha; + + if (this.highlighted) { + c1.r *= 3; + c1.g *= 3; + c1.b *= 3; + c2.r *= 3; + c2.g *= 3; + c2.b *= 3; + d1.r *= 3; + d1.g *= 3; + d1.b *= 3; + d2.r *= 3; + d2.g *= 3; + d2.b *= 3; + } + + if (ptsDistance > this.BUNGEE_REST_LEN + 7 && !this.dontDrawRedStretch) { + var f = ptsDistance / this.BUNGEE_REST_LEN * 2; + d1.r *= f; + d2.r *= f; + } + + var useC1 = false, // ropes have alternating color segments + numVertices = (count - 1) * points; + + // // colors + // //noinspection UnnecessaryLocalVariableJS + var b1 = d1, + colorDivisor = (numVertices - 1), + b1rf = (c1.r - d1.r) / colorDivisor, + b1gf = (c1.g - d1.g) / colorDivisor, + b1bf = (c1.b - d1.b) / colorDivisor; + + var numSegments = this.BUNGEE_BEZIER_POINTS - 1, + lastSegmentIndex = numSegments - 1, + ctx = Canvas.context, + previousAlpha = ctx.globalAlpha; + + // set the line style + if (previousAlpha !== alpha) { + ctx.globalAlpha = alpha; + } + + // store the first point in the path + var firstDrawPoint = drawPts[0]; + if (!firstDrawPoint) { + firstDrawPoint = drawPts[0] = firstPoint.copy(); + } else { + firstDrawPoint.x = firstPoint.x; + firstDrawPoint.y = firstPoint.y; + } + + var vertex, a, pathVector, currentColor; + + ctx.beginPath(); + + var currentColor = b1.rgbaStyle(); + if (ctx.strokeStyle !== currentColor) + ctx.strokeStyle = currentColor; + + for (vertex = 1; vertex <= numVertices; vertex++) { + a = vertex / numVertices; + + // use bezier to smooth the draw points + pathVector = drawPts[vertex]; + if (!pathVector) { + pathVector = drawPts[vertex] = new Vector(0, 0); + } + Vector.setCalcPathBezier(pts, a, pathVector); + + // see if we have all the points for this color section + var segmentIndex = (vertex - 1) % numSegments; + if (segmentIndex === lastSegmentIndex || vertex === numVertices) { + + // decide which color to use for this section + // if (this.forceWhite) { + // currentColor = RGBAColor.styles.SOLID_OPAQUE; + // } + // else if (useC1) { + // currentColor = b1.rgbaStyle(); + // } + // else { + // currentColor = b2.rgbaStyle(); + // } + + //ctx.strokeStyle = currentColor; + + // move to the beginning of the color section + var currentIndex = vertex - segmentIndex - 1; + var point = drawPts[currentIndex++]; + ctx.moveTo(point.x, point.y); + + // draw each line segment (2 segments per color section) + for (; currentIndex <= vertex; currentIndex++) { + point = drawPts[currentIndex]; + ctx.lineTo(point.x, point.y); + //Log.debug('Segment to [' + point.x + ', ' + point.y + '] color: ' + currentColor ); + } + + //ctx.stroke(); + //useC1 = !useC1; + + var colorMultiplier = segmentIndex + 1; + + // adjust colors + b1.r += b1rf * colorMultiplier; + b1.g += b1gf * colorMultiplier; + b1.b += b1bf * colorMultiplier; + } + } + + ctx.stroke(); + + // reset the alpha + if (previousAlpha !== alpha) { + ctx.globalAlpha = previousAlpha; + } + } + }); + + + // export const for use in GameScene + Bungee.BUNGEE_RELAXION_TIMES = BUNGEE_RELAXION_TIMES; + + return Bungee; + } +); +define('game/LevelState', + [ + 'edition' + ], + function (edition) { + + // manages state of the current level + var LevelState = { + loadedMap: null, + pack: 0, + level: 0, + survival: false, + + loadLevel: function (pack, level) { + this.pack = pack - 1; + this.level = level - 1; + + var box = edition.boxes[this.pack]; + this.loadedMap = box.levels[this.level]; + } + }; + + return LevelState; + } +); + +define('visual/HorizontallyTiledImage', + [ + 'visual/ImageElement', + 'utils/Canvas', + 'core/Alignment' + ], + function (ImageElement, Canvas, Alignment) { + + var HorizontallyTiledImage = ImageElement.extend({ + init: function () { + this._super(); + }, + /** + * Set the texture for this image element + * @param texture {Texture2D} + */ + initTexture: function (texture) { + this._super(texture); + + this.tiles = []; + this.offsets = []; + this.align = Alignment.CENTER; + }, + setTileHorizontally: function (left, center, right) { + this.tiles[0] = left; + this.tiles[1] = center; + this.tiles[2] = right; + + var h1 = this.texture.rects[left].h, + h2 = this.texture.rects[center].h, + h3 = this.texture.rects[right].h; + + if (h1 >= h2 && h1 >= h3) { + this.height = h1; + } + else if (h2 >= h1 && h2 >= h3) { + this.height = h2; + } + else { + this.height = h3; + } + + this.offsets[0] = ~~((this.height - h1) / 2.0); + this.offsets[1] = ~~((this.height - h2) / 2.0); + this.offsets[2] = ~~((this.height - h3) / 2.0); + }, + draw: function () { + this.preDraw(); + + var left = this.texture.rects[this.tiles[0]], + center = this.texture.rects[this.tiles[1]], + right = this.texture.rects[this.tiles[2]], + tileWidth = this.width - (~~left.w + ~~right.w), + ctx = Canvas.context, + dx = Math.round(this.drawX), + dy = Math.round(this.drawY), + leftCeilW = Math.ceil(left.w), + leftCeilH = Math.ceil(left.h), + rightCeilW = Math.ceil(right.w), + rightCeilH = Math.ceil(right.h); + + if (tileWidth >= 0) { + ctx.drawImage(this.texture.image, + left.x, left.y, leftCeilW, leftCeilH, + dx, dy + this.offsets[0], leftCeilW, leftCeilH); + this.drawTiled(this.tiles[1], + dx + leftCeilW, dy + this.offsets[1], tileWidth, center.h); + ctx.drawImage(this.texture.image, + right.x, right.y, rightCeilW, rightCeilH, + dx + leftCeilW + tileWidth, dy + this.offsets[2], rightCeilW, rightCeilH); + } + else { + var p1 = left.copy(), + p2 = right.copy(); + p1.w = Math.min(p1.w, this.width / 2); + p2.w = Math.min(p2.w, this.width - p1.w); + p2.x += (right.w - p2.w); + + ctx.drawImage(this.texture.image, + p1.x, p1.y, p1.w, p1.h, + dx, dy + this.offsets[0], p1.w, p1.h); + ctx.drawImage(this.texture.image, + p2.x, p2.y, p2.w, p2.h, + dx + p1.w, dy + this.offsets[2], p2.w, p2.h); + } + + this.postDraw(); + }, + + /** + * Draw the tile image to an offscreen canvas and return an Image + */ + getImage: function () { + // save the existing canvas id and switch to the hidden canvas + var existingCanvas = Canvas.element; + + // create a temporary canvas to use + Canvas.setTarget(document.createElement('canvas')); + + // set the canvas width and height + var canvas = Canvas.element, + imgWidth = Math.ceil(this.width), + imgHeight = Math.ceil(this.height); + canvas.width = imgWidth; + canvas.height = imgHeight; + + this.draw(); + var imageData = canvas.toDataURL('image/png'), + img = new Image(); + + img.src = imageData; + + // NOTE: important to use jQuery to avoid intermittent dimension issues + $(img).width(imgWidth).height(imgHeight); + + // restore the original canvas for the App + if (existingCanvas) { + Canvas.setTarget(existingCanvas); + } + + return img; + } + }); + + return HorizontallyTiledImage; + } +); + +define('game/GrabMoveBackground', + [ + 'visual/ImageElement', + 'visual/HorizontallyTiledImage', + 'resolution', + 'resources/ResourceId', + 'core/Texture2D' + ], + function (ImageElement, HorizontallyTiledImage, resolution, ResourceId, Texture2D) { + + var IMG_OBJ_HOOK_MOVABLE_bottom_tile_left = 0; + var IMG_OBJ_HOOK_MOVABLE_bottom_tile_right = 1; + var IMG_OBJ_HOOK_MOVABLE_bottom_tile_middle = 2; + + var GrabMoveBackground = ImageElement.extend({ + init: function (length) { + this._super(); + + // render the tiled image once and cache the image + var tiledImage = new HorizontallyTiledImage(); + tiledImage.initTextureWithId(ResourceId.IMG_OBJ_HOOK_MOVABLE); + tiledImage.setTileHorizontally( + IMG_OBJ_HOOK_MOVABLE_bottom_tile_left, + IMG_OBJ_HOOK_MOVABLE_bottom_tile_middle, + IMG_OBJ_HOOK_MOVABLE_bottom_tile_right); + + tiledImage.width = length + resolution.GRAB_MOVE_BG_WIDTH; + + var completeImage = tiledImage.getImage(); + this.initTexture(new Texture2D(completeImage)); + } + }); + + return GrabMoveBackground; + } +); + +define('game/Grab', + [ + 'game/CTRGameObject', + 'utils/Radians', + 'game/Bungee', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'core/Vector', + 'utils/Mover', + 'utils/Constants', + 'resolution', + 'game/LevelState', + 'visual/Animation', + 'core/Alignment', + 'visual/ImageElement', + 'utils/Canvas', + 'core/RGBAColor', + 'visual/Timeline', + 'utils/MathHelper', + 'visual/HorizontallyTiledImage', + 'game/GrabMoveBackground' + ], + function (CTRGameObject, Radians, Bungee, SoundMgr, ResourceId, Vector, Mover, Constants, resolution, LevelState, Animation, Alignment, ImageElement, Canvas, RGBAColor, Timeline, MathHelper, HorizontallyTiledImage, GrabMoveBackground) { + + /** + * @enum {number} + */ + var SpiderState = { + START: 0, + WALK: 1, + BUSTER: 2, + CATCH: 3 + }; + + /** + * @enum {number} + */ + var GunState = { + SHOW: 0, + HIDE: 1 + }; + + var grabCircleCache = []; + + var Grab = CTRGameObject.extend({ + init: function () { + this._super(); + this.rope = null; + + this.gun = false; + this.gunFired = false; + this.invisible = false; + this.kicked = false; + + this.wheel = false; + this.wheelOperating = Constants.UNDEFINED; + this.lastWheelTouch = Vector.newZero(); + + this.moveLength = 0; + this.moveVertical = false; + this.moveOffset = 0; + this.moveBackground = null; + this.grabMoverHighlight = null; + this.grabMover = null; + this.moverDragging = 0; + this.minMoveValue = 0; + this.maxMoveValue = 0; + + this.hasSpider = false; + this.spiderActive = false; + this.spider = null; + this.spiderPos = 0; + this.shouldActivate = false; + + this.wheelDirty = false; + + this.launcher = false; + this.launcherSpeed = 0; + this.launcherIncreaseSpeed = false; + + this.hideRadius = false; + this.radiusAlpha = 0; + this.radius = 0; + + this.balloon = false; + }, + /** + * + * @param v1 {Vector} start + * @param v2 {Vector} end + * @param c {Vector} center + */ + getRotateAngle: function (v1, v2, c) { + var m1 = Vector.subtract(v1, c); + var m2 = Vector.subtract(v2, c); + + var a = m2.normalizedAngle() - m1.normalizedAngle(); + return Radians.toDegrees(a); + }, + /** + * + * @param v {Vector} + */ + handleWheelTouch: function (x, y) { + this.lastWheelTouch.x = x; + this.lastWheelTouch.y = y; + }, + handleWheelRotate: function (v) { + SoundMgr.playSound(ResourceId.SND_WHEEL); + + var center = new Vector(this.x, this.y), + a = this.getRotateAngle(this.lastWheelTouch, v, center); + if (a > 180) { + a -= 360; + } + else if (a < -180) { + a += 360; + } + + this.wheelImage2.rotation += a; + this.wheelImage3.rotation += a; + this.wheelHighlight.rotation += a; + + a = (a > 0) + ? Math.min(Math.max(1, a), resolution.GRAB_WHEEL_MAX_ROTATION) + : Math.max(Math.min(-1, a), -resolution.GRAB_WHEEL_MAX_ROTATION); + + if (this.rope) { + if (a > 0) { + if (this.rope.getLength() < resolution.GRAB_ROPE_ROLL_MAX_LENGTH) { + this.rope.roll(a); + } + } + else if (a !== 0) { + if (this.rope.parts.length > 3) { + this.rope.rollBack(-a); + } + } + this.wheelDirty = true; + } + this.lastWheelTouch.copyFrom(v); + + }, + update: function (delta) { + this._super(delta); + + if (this.launcher && this.rope) { + var anchor = this.rope.bungeeAnchor, + moveResult; + anchor.pos.x = this.x; + anchor.pos.y = this.y; + anchor.pin.copyFrom(anchor.pos); + + if (this.launcherIncreaseSpeed) { + moveResult = Mover.moveToTargetWithStatus( + this.launcherSpeed, 200, 30, delta); + this.launcherSpeed = moveResult.value; + if (moveResult.reachedZero) + this.launcherIncreaseSpeed = false; + } + else { + moveResult = Mover.moveToTargetWithStatus( + this.launcherSpeed, 130, 30, delta); + this.launcherSpeed = moveResult.value; + if (moveResult.reachedZero) + this.launcherIncreaseSpeed = true; + } + + this.mover.setMoveSpeed(this.launcherSpeed); + } + + if (this.hideRadius) { + this.radiusAlpha -= 1.5 * delta; + if (this.radiusAlpha <= 0) { + this.radius = Constants.UNDEFINED; + this.hideRadius = false; + } + } + + if (this.bee) { + var vt = this.mover.path[this.mover.targetPoint], + vp = this.mover.pos, + v = Vector.subtract(vt, vp), + a = 0, + MAX_ANGLE = 10; + + if (Math.abs(v.x) > 15) { + a = (v.x > 0) ? MAX_ANGLE : -MAX_ANGLE; + } + + this.bee.rotation = Mover.moveToTarget( + this.bee.rotation, a, 60, delta); + } + + if (this.wheel && this.wheelDirty && this.rope) { + var len = this.rope.getLength() * 0.7; + if (len === 0) { + this.wheelImage2.scaleX = this.wheelImage2.scaleY = 0; + } + else { + this.wheelImage2.scaleX = this.wheelImage2.scaleY = + Math.max(0, Math.min(1.2, 1 - len / resolution.GRAB_WHEEL_SCALE_DIVISOR)); + } + } + }, + updateSpider: function (delta) { + if (this.hasSpider && this.shouldActivate) { + this.shouldActivate = false; + this.spiderActive = true; + SoundMgr.playSound(ResourceId.SND_SPIDER_ACTIVATE); + this.spider.playTimeline(SpiderState.START); + } + + if (this.hasSpider && this.spiderActive) { + if (this.spider.currentTimelineIndex !== SpiderState.START) { + this.spiderPos += delta * resolution.SPIDER_SPEED; + } + + var checkingPos = 0, + reachedCandy = false; + + if (this.rope) { + var drawPts = this.rope.drawPts, + BUNGEE_REST_LEN = resolution.BUNGEE_REST_LEN, + a = 2 * BUNGEE_REST_LEN / 3; + for (var i = 0, numPts = drawPts.length; i < numPts; i++) { + + var c1 = drawPts[i], + c2 = drawPts[i + 1], + b = c1.distance(c2), + len = a > b ? a : b; + + if (this.spiderPos >= checkingPos && + (this.spiderPos < checkingPos + len || i > numPts - 3)) { + var overlay = this.spiderPos - checkingPos; + var c3 = Vector.subtract(c2, c1); + c3.multiply(overlay / len); + this.spider.x = c1.x + c3.x; + this.spider.y = c1.y + c3.y; + + if (i > numPts - 3) { + reachedCandy = true; + } + + if (this.spider.currentTimelineIndex !== SpiderState.START) { + this.spider.rotation = c3.normalizedAngle() * 57.29577951308232 + 270; + } + + break; + } + else { + checkingPos += len; + } + } + } + + if (reachedCandy) { + this.spiderPos = Constants.UNDEFINED; + } + } + }, + drawBack: function () { + if (this.invisible) + return; + if (this.gun) + return; + + if (this.kickable && this.kicked && this.rope) { + var pos = this.rope.bungeeAnchor.pos; + this.x = pos.x; + this.y = pos.y; + } + + this.preDraw(); + + if (this.moveLength > 0) { + this.moveBackground.draw(); + } + else { + this.back.draw(); + } + + if (this.radius !== Constants.UNDEFINED || this.hideRadius) { + var color = new RGBAColor(0.2, 0.5, 0.9, this.radiusAlpha), + drawRadius = (this.radius !== Constants.UNDEFINED) ? this.radius : this.previousRadius; + this.drawGrabCircle(this.x, this.y, drawRadius, color); + } + }, + drawGrabCircle: function (x, y, radius, color) { + + if (radius < 0) { + return; + } + + //generate a key for the cache + var key = radius.toString() + "|" + color.rgbaStyle(); + var circleCnv; + + //check the cache first + if (grabCircleCache[key]) { + circleCnv = grabCircleCache[key]; + //console.log("EXISTS IN CACHE") + } else { + + //otherwise create it + circleCnv = document.createElement("canvas"); + circleCnv.width = circleCnv.height = radius * 2 + 4; + + //document.body.appendChild(circleCnv) + + var ctx = circleCnv.getContext("2d"), + totalRadians = 2 * Math.PI, + radiusScaleFactor = (resolution.CANVAS_SCALE * 2), + scaledRadius = radius / radiusScaleFactor, + segments = Math.max(16, Math.round(scaledRadius)); + + // make sure we have an even number of segments + if (segments % 2 !== 0) { + segments++; + } + + ctx.lineWidth = 2; + ctx.strokeStyle = color.rgbaStyle(); + + var segmentRadians = totalRadians / segments; + for (var i = 0; i < segments; i++) { + // only draw every other segment for dashed circle + if (i % 2 === 0) { + var startRadians = (i / segments) * totalRadians; + ctx.beginPath(); + ctx.arc(radius + 2, radius + 2, radius, startRadians, startRadians + segmentRadians, false); + ctx.stroke(); + ctx.closePath(); + } + } + + grabCircleCache[key] = circleCnv; + //console.log("DRAW GRAB CIRCLE", circleCnv) + } + + var mainCtx = Canvas.context; + mainCtx.drawImage(circleCnv, x - radius - 2, y - radius - 2) + + + }, + drawBB: function () { + if (this.wheel) { + this.drawGrabCircle( + this.x, + this.y, + resolution.GRAB_WHEEL_RADIUS, + RGBAColor.red); + } + }, + draw: function () { + if (this.invisible) + return; + + // NOTE: we do pre-draw when drawing the back so the position + // of the back is adjusted. Otherwise the back can be offset + // when there are large moves to position (grab is on DJ disc) + + var b = this.rope; + + if (this.wheel) { + this.wheelHighlight.visible = (this.wheelOperating !== Constants.UNDEFINED); + this.wheelImage3.visible = (this.wheelOperating === Constants.UNDEFINED); + this.wheelImage.draw(); + } + + if (this.gun) { + this.gunBack.draw(); + if (!this.gunFired) { + this.gunArrow.draw(); + } + } + + if (b) { + b.draw(); + } + + if (this.moveLength <= 0) { + this.front.draw(); + } + else { + if (this.moverDragging != Constants.UNDEFINED) { + this.grabMoverHighlight.draw(); + } + else { + this.grabMover.draw(); + } + } + + if (this.wheel) { + this.wheelImage2.draw(); + } + + this.postDraw(); + }, + drawSpider: function () { + this.spider.draw(); + }, + drawGunCup: function () { + this.gunCup.draw(); + }, + setRope: function (rope) { + this.rope = rope; + this.previousRadius = this.radius; + this.radius = Constants.UNDEFINED; + if (this.hasSpider) { + this.shouldActivate = true; + } + }, + setLauncher: function () { + this.launcher = true; + this.launcherIncreaseSpeed = true; + this.launcherSpeed = 130; + var m = new Mover(100, this.launcherSpeed, 0); + m.setPathFromString('RC30', new Vector(this.x, this.y)); + this.setMover(m); + m.start(); + }, + setRadius: function (radius) { + this.previousRadius = this.radius; + this.radius = radius; + + // TODO: handle gun + + if (radius === Constants.UNDEFINED || radius === Constants.CANDY2_FLAG) { + var imageId = MathHelper.randomRange( + ResourceId.IMG_OBJ_HOOK_01, + ResourceId.IMG_OBJ_HOOK_02); + this.back = ImageElement.create(imageId, IMG_OBJ_HOOK_01_bottom); + this.back.doRestoreCutTransparency(); + this.back.anchor = this.back.parentAnchor = Alignment.CENTER; + this.front = ImageElement.create(imageId, IMG_OBJ_HOOK_01_top); + this.front.anchor = this.front.parentAnchor = Alignment.CENTER; + this.addChild(this.back); + this.addChild(this.front); + this.back.visible = false; + this.front.visible = false; + } + else { + this.back = ImageElement.create(ResourceId.IMG_OBJ_HOOK_AUTO, IMG_OBJ_HOOK_AUTO_bottom); + this.back.doRestoreCutTransparency(); + this.back.anchor = this.back.parentAnchor = Alignment.CENTER; + this.front = ImageElement.create(ResourceId.IMG_OBJ_HOOK_AUTO, IMG_OBJ_HOOK_AUTO_top); + this.front.anchor = this.front.parentAnchor = Alignment.CENTER; + this.addChild(this.back); + this.addChild(this.front); + this.back.visible = false; + this.front.visible = false; + + this.radiusAlpha = resolution.GRAB_RADIUS_ALPHA; + this.hideRadius = false; + } + + if (this.wheel) { + this.wheelImage = ImageElement.create(ResourceId.IMG_OBJ_HOOK_REGULATED, + IMG_OBJ_HOOK_REGULATED_bottom); + this.wheelImage.anchor = this.wheelImage.parentAnchor = Alignment.CENTER; + this.addChild(this.wheelImage); + this.wheelImage.visible = false; + + this.wheelImage2 = ImageElement.create(ResourceId.IMG_OBJ_HOOK_REGULATED, + IMG_OBJ_HOOK_REGULATED_rope); + this.wheelImage2.passTransformationsToChilds = false; + + this.wheelHighlight = ImageElement.create(ResourceId.IMG_OBJ_HOOK_REGULATED, + IMG_OBJ_HOOK_REGULATED_active); + this.wheelHighlight.anchor = this.wheelHighlight.parentAnchor = Alignment.CENTER; + this.wheelImage2.addChild(this.wheelHighlight); + + this.wheelImage3 = ImageElement.create(ResourceId.IMG_OBJ_HOOK_REGULATED, + IMG_OBJ_HOOK_REGULATED_top); + this.wheelImage3.anchor = this.wheelImage3.parentAnchor = + this.wheelImage2.anchor = this.wheelImage2.parentAnchor = Alignment.CENTER; + this.wheelImage2.addChild(this.wheelImage3); + this.addChild(this.wheelImage2); + this.wheelImage2.visible = false; + this.wheelDirty = false; + } + }, + setMoveLength: function (length, vertical, offset) { + this.moveLength = length; + this.moveVertical = vertical; + this.moveOffset = offset; + + if (this.moveLength > 0) { + this.moveBackground = new GrabMoveBackground(length); + this.moveBackground.rotationCenterX = -Math.round( + this.moveBackground.width / 2) + resolution.GRAB_MOVE_BG_X_OFFSET; + this.moveBackground.x = -resolution.GRAB_MOVE_BG_X_OFFSET; + + this.grabMoverHighlight = ImageElement.create( + ResourceId.IMG_OBJ_HOOK_MOVABLE, IMG_OBJ_HOOK_MOVABLE_active); + this.grabMoverHighlight.visible = false; + this.grabMoverHighlight.anchor = this.grabMoverHighlight.parentAnchor = Alignment.CENTER; + this.addChild(this.grabMoverHighlight); + + this.grabMover = ImageElement.create( + ResourceId.IMG_OBJ_HOOK_MOVABLE, IMG_OBJ_HOOK_MOVABLE_top); + this.grabMover.visible = false; + this.grabMover.anchor = this.grabMover.parentAnchor = Alignment.CENTER; + this.addChild(this.grabMover); + this.grabMover.addChild(this.moveBackground); + + if (this.moveVertical) { + this.moveBackground.rotation = 90; + this.moveBackground.y = -this.moveOffset; + this.minMoveValue = this.y - this.moveOffset; + this.maxMoveValue = this.y + (this.moveLength - this.moveOffset); + this.grabMover.rotation = 90; + this.grabMoverHighlight.rotation = 90; + } + else { + this.minMoveValue = this.x - this.moveOffset; + this.maxMoveValue = this.x + (this.moveLength - this.moveOffset); + this.moveBackground.x += -this.moveOffset; + } + this.moveBackground.anchor = Alignment.VCENTER | Alignment.LEFT; + this.moveBackground.x += this.x; + this.moveBackground.y += this.y; + this.moveBackground.visible = false; + } + + this.moverDragging = Constants.UNDEFINED; + }, + setBee: function () { + this.bee = ImageElement.create(ResourceId.IMG_OBJ_BEE_HD, IMG_OBJ_BEE_HD_obj_bee); + this.bee.doRestoreCutTransparency(); + this.bee.parentAnchor = Alignment.CENTER; + + var wings = new Animation(); + wings.initTextureWithId(ResourceId.IMG_OBJ_BEE_HD); + wings.parentAnchor = wings.anchor = Alignment.TOP | Alignment.LEFT; + wings.doRestoreCutTransparency(); + wings.addAnimationDelay(0.03, Timeline.LoopType.PING_PONG, IMG_OBJ_BEE_HD_wings_start, IMG_OBJ_BEE_HD_wings_end); + wings.playTimeline(0); + wings.jumpTo(MathHelper.randomRange(0, IMG_OBJ_BEE_HD_wings_end - IMG_OBJ_BEE_HD_wings_start)); + this.bee.addChild(wings); + + var p = this.bee.texture.offsets[IMG_OBJ_BEE_HD__rotation_center]; + this.bee.x = -p.x; + this.bee.y = -p.y; + + this.bee.rotationCenterX = p.x - (this.bee.width / 2); + this.bee.rotationCenterY = p.y - (this.bee.width / 2); + this.bee.scaleX = this.bee.scaleY = 1 / 1.3; + + this.addChild(this.bee); + }, + setSpider: function (hasSpider) { + this.hasSpider = hasSpider; + this.shouldActivate = false; + this.spiderActive = false; + + this.spider = new Animation(); + this.spider.initTextureWithId(ResourceId.IMG_OBJ_SPIDER); + this.spider.doRestoreCutTransparency(); + this.spider.anchor = Alignment.CENTER; + this.spider.x = this.x; + this.spider.y = this.y; + this.spider.visible = false; + + // add spider animations + this.spider.addAnimationEndpoints(SpiderState.START, 0.05, Timeline.LoopType.NO_LOOP, + IMG_OBJ_SPIDER_activation_start, IMG_OBJ_SPIDER_activation_end); + this.spider.setDelay(0.4, 5, SpiderState.START); + this.spider.addAnimationEndpoints(SpiderState.WALK, 0.1, Timeline.LoopType.REPLAY, + IMG_OBJ_SPIDER_crawl_start, IMG_OBJ_SPIDER_crawl_end); + this.spider.switchToAnimation(SpiderState.WALK, SpiderState.START, 0.05); + + this.addChild(this.spider); + }, + destroyRope: function () { + this.rope = null; + } + }); + + // TODO: move into spider + var IMG_OBJ_SPIDER_activation_start = 0; + var IMG_OBJ_SPIDER_activation_end = 6; + var IMG_OBJ_SPIDER_crawl_start = 7; + var IMG_OBJ_SPIDER_crawl_end = 10; + + var IMG_OBJ_HOOK_AUTO_bottom = 0; + var IMG_OBJ_HOOK_AUTO_top = 1; + + var IMG_OBJ_HOOK_01_bottom = 0; + var IMG_OBJ_HOOK_01_top = 1; + + var IMG_OBJ_HOOK_02_bottom = 0; + var IMG_OBJ_HOOK_02_top = 1; + + var IMG_OBJ_HOOK_REGULATED_bottom = 0; + var IMG_OBJ_HOOK_REGULATED_rope = 1; + var IMG_OBJ_HOOK_REGULATED_active = 2; + var IMG_OBJ_HOOK_REGULATED_top = 3; + + var IMG_OBJ_HOOK_MOVABLE_active = 3; + var IMG_OBJ_HOOK_MOVABLE_top = 4; + + // bees + var IMG_OBJ_BEE_HD__rotation_center = 0; + var IMG_OBJ_BEE_HD_obj_bee = 1; + var IMG_OBJ_BEE_HD_wings_start = 2; + var IMG_OBJ_BEE_HD_wings_end = 4; + + return Grab; + } +); +define('game/Pump', + [ + 'visual/GameObject', + 'core/Vector', + 'utils/Radians' + ], + function (GameObject, Vector, Radians) { + + var Pump = GameObject.extend({ + init: function () { + this._super(); + this.angle = 0; + this.t1 = Vector.newZero(); + this.t2 = Vector.newZero(); + this.touchTimer = 0; + this.touch = 0; + }, + updateRotation: function () { + var bbHalfWidth = this.bb.w / 2; + + this.t1.x = this.x - bbHalfWidth; + this.t2.x = this.x + bbHalfWidth; + this.t1.y = this.t2.y = this.y; + + this.angle = Radians.fromDegrees(this.rotation); + + this.t1.rotateAround(this.angle, this.x, this.y); + this.t2.rotateAround(this.angle, this.x, this.y); + } + }); + + return Pump; + } +); +define('game/PumpDirt', + [ + 'visual/MultiParticles', + 'resolution', + 'core/Vector', + 'core/Rectangle', + 'utils/MathHelper' + ], + function (MultiParticles, resolution, Vector, Rectangle, MathHelper) { + + var IMG_OBJ_PUMP_pump_start = 0, + IMG_OBJ_PUMP_pump_end = 5, + IMG_OBJ_PUMP_particle_1 = 6, + IMG_OBJ_PUMP_particle_2 = 7, + IMG_OBJ_PUMP_particle_3 = 8; + + var PumpDirt = MultiParticles.extend({ + init: function (numParticles, texture, angle) { + this._super(numParticles, texture); + + this.angle = angle; + this.angleVar = 10; + + this.speed = resolution.PUMP_DIRT_SPEED; + + // life of particles + this.life = 0.6; + + // size in pixels + this.size = 0.002; + + // emissions per second + this.emissionRate = 50; + + // color of particles + this.startColor.r = 1.0; + this.startColor.g = 1.0; + this.startColor.b = 1.0; + this.startColor.a = 0.6; + + this.endColor.r = 1.0; + this.endColor.g = 1.0; + this.endColor.b = 1.0; + this.endColor.a = 0.0; + + this.additive = true; + }, + initParticle: function (particle) { + this._super(particle); + + var texture = this.imageGrid, + n = MathHelper.randomRange(IMG_OBJ_PUMP_particle_1, IMG_OBJ_PUMP_particle_3), + tquad = texture.rects[n], + vquad = new Rectangle(0, 0, 0, 0); // don't draw initially + + this.drawer.setTextureQuad(this.particles.length, tquad, vquad, 1); + + var particleSize = resolution.PUMP_DIRT_PARTICLE_SIZE; + particle.width = particleSize; + particle.height = particleSize; + }, + updateParticleLocation: function (p, delta) { + p.dir.multiply(0.90); + var tmp = Vector.multiply(p.dir, delta); + tmp.add(this.gravity); + p.pos.add(tmp); + } + }); + + return PumpDirt; + } +); + +define('game/Sock', + [ + 'game/CTRGameObject', + 'visual/Animation', + 'resources/ResourceId', + 'core/Alignment', + 'visual/Timeline', + 'resolution', + 'core/Vector', + 'utils/Mover', + 'utils/Radians', + 'utils/Canvas' + ], + function (CTRGameObject, Animation, ResourceId, Alignment, Timeline, resolution, Vector, Mover, Radians, Canvas) { + + var Sock = CTRGameObject.extend({ + init: function () { + this._super(); + + this.group = 0; + this.angle = 0; + this.t1 = new Vector(0, 0); + this.t2 = new Vector(0, 0); + this.b1 = new Vector(0, 0); + this.b2 = new Vector(0, 0); + + this.idleTimeout = 0; + }, + createAnimations: function () { + this.light = new Animation(); + this.light.initTextureWithId(ResourceId.IMG_OBJ_SOCKS); + this.light.anchor = Alignment.BOTTOM | Alignment.HCENTER; + this.light.parentAnchor = Alignment.TOP | Alignment.HCENTER; + + this.light.y = resolution.SOCK_LIGHT_Y; + this.light.x = 0; + this.light.addAnimationSequence(0, 0.05, Timeline.LoopType.NO_LOOP, 4, + [ Sock.Quads.IMG_OBJ_SOCKS_glow_start, Sock.Quads.IMG_OBJ_SOCKS_glow_start + 1, + Sock.Quads.IMG_OBJ_SOCKS_glow_start + 2, Sock.Quads.IMG_OBJ_SOCKS_glow_start + 2]); + this.light.doRestoreCutTransparency(); + this.light.visible = false; + this.addChild(this.light); + }, + updateRotation: function () { + this.t1.x = this.x - resolution.SOCK_WIDTH / 2; + this.t2.x = this.x + resolution.SOCK_WIDTH / 2; + this.t1.y = this.t2.y = this.y; + + this.b1.x = this.t1.x; + this.b2.x = this.t2.x; + this.b1.y = this.b2.y = this.y + resolution.SOCK_ROTATION_Y_OFFSET; + + this.angle = Radians.fromDegrees(this.rotation); + + this.t1.rotateAround(this.angle, this.x, this.y); + this.t2.rotateAround(this.angle, this.x, this.y); + this.b1.rotateAround(this.angle, this.x, this.y); + this.b2.rotateAround(this.angle, this.x, this.y); + }, + draw: function () { + var tl = this.light.currentTimeline; + if (tl && tl.state === Timeline.StateType.STOPPED) { + this.light.visible = false; + } + this._super(); + }, + drawBB: function () { + // DEBUG: draw bounding lines for transport area + if (false) { + var ctx = Canvas.context; + ctx.lineWidth = 3; + + ctx.beginPath(); + ctx.strokeStyle = 'red'; + ctx.moveTo(this.t1.x, this.t1.y); + ctx.lineTo(this.t2.x, this.t2.y); + ctx.stroke(); + + ctx.beginPath(); + ctx.strokeStyle = 'blue'; + ctx.moveTo(this.b1.x, this.b1.y); + ctx.lineTo(this.b2.x, this.b2.y); + ctx.stroke(); + } + }, + update: function (delta) { + this._super(delta); + if (this.mover) { + this.updateRotation(); + } + } + }); + + /** + * @enum {number} + */ + Sock.Quads = { + IMG_OBJ_SOCKS_hat_01: 0, + IMG_OBJ_SOCKS_hat_02: 1, + IMG_OBJ_SOCKS_glow_start: 2, + IMG_OBJ_SOCKS_level: 3, + IMG_OBJ_SOCKS_glow_end: 4 + }; + + /** + * @enum {number} + */ + Sock.StateType = { + RECEIVING: 0, + THROWING: 1, + IDLE: 2 + }; + + /** + * @const {number} + */ + Sock.IDLE_TIMEOUT = 0.8; + + return Sock; + } +); + +define('visual/GenericButton', + [ + 'visual/BaseElement', + 'visual/ImageElement', + 'core/Rectangle', + 'utils/Constants', + 'core/Alignment' + ], + function (BaseElement, ImageElement, Rectangle, Constants, Alignment) { + + var TOUCH_MOVE_AND_UP_ZONE_INCREASE = 15; + + var GenericButton = BaseElement.extend({ + init: function (id) { + this._super(); + + this.buttonId = id; + this.state = GenericButton.StateType.UP; + + this.touchLeftInc = 0.0; + this.touchRightInc = 0.0; + this.touchTopInc = 0.0; + this.touchBottomInc = 0.0; + + this.onButtonPressed = null; + + this.forcedTouchZone = new Rectangle( + Constants.UNDEFINED, + Constants.UNDEFINED, + Constants.UNDEFINED, + Constants.UNDEFINED); + }, + initWithElements: function (up, down) { + up.parentAnchor = down.parentAnchor = Alignment.TOP | Alignment.LEFT; + this.addChildWithID(up, GenericButton.StateType.UP); + this.addChildWithID(down, GenericButton.StateType.DOWN); + this.setState(GenericButton.StateType.UP); + }, + initWithTextures: function (upTexture, downTexture) { + + var up = new ImageElement(); + up.initTexture(upTexture); + + var down = new ImageElement(); + down.initTexture(downTexture); + + this.initWithElements(up, down); + }, + forceTouchRect: function (rect) { + this.forcedTouchZone = rect; + }, + setTouchIncrease: function (left, right, top, bottom) { + this.touchLeftInc = left; + this.touchRightInc = right; + this.touchTopInc = top; + this.touchBottomInc = bottom; + }, + setState: function (s) { + this.state = s; + var up = this.getChild(GenericButton.StateType.UP), + down = this.getChild(GenericButton.StateType.DOWN); + + up.setEnabled(s === GenericButton.StateType.UP); + down.setEnabled(s === GenericButton.StateType.DOWN); + }, + isInTouchZone: function (tx, ty, td) { + var tzIncrease = td ? 0 : TOUCH_MOVE_AND_UP_ZONE_INCREASE; + + if (this.forcedTouchZone.w !== Constants.UNDEFINED) { + return Rectangle.pointInRect(tx, ty, + this.drawX + this.forcedTouchZone.x - tzIncrease, + this.drawY + this.forcedTouchZone.y - tzIncrease, + this.forcedTouchZone.w + tzIncrease * 2, + this.forcedTouchZone.h + tzIncrease * 2); + } + else { + return Rectangle.pointInRect(tx, ty, + this.drawX - this.touchLeftInc - tzIncrease, + this.drawY - this.touchTopInc - tzIncrease, + this.width + (this.touchLeftInc + this.touchRightInc) + tzIncrease * 2, + this.height + (this.touchTopInc + this.touchBottomInc) + tzIncrease * 2); + } + }, + onTouchDown: function (tx, ty) { + this._super(tx, ty); + + if (this.state === GenericButton.StateType.UP) { + if (this.isInTouchZone(tx, ty, true)) { + this.setState(GenericButton.StateType.DOWN); + return true; + } + } + + return false; + }, + onTouchUp: function (tx, ty) { + this._super(tx, ty); + + if (this.state === GenericButton.StateType.DOWN) { + this.setState(GenericButton.StateType.UP); + if (this.isInTouchZone(tx, ty, false)) { + if (this.onButtonPressed) { + this.onButtonPressed(this.buttonId); + } + return true; + } + } + + return false; + }, + onTouchMove: function (tx, ty) { + this._super(tx, ty); + + if (this.state === GenericButton.StateType.DOWN) { + if (!this.isInTouchZone(tx, ty, false)) { + this.setState(GenericButton.StateType.UP); + } + else { + return true; + } + } + + return false; + }, + addChildWithID: function (child, id) { + this._super(child, id); + + child.parentAnchor = Alignment.TOP | Alignment.LEFT; + + if (id === GenericButton.StateType.DOWN) { + this.width = child.width; + this.height = child.height; + this.setState(GenericButton.StateType.UP); + } + } + }); + + GenericButton.StateType = { + UP: 0, + DOWN: 1 + }; + + return GenericButton; + } +); + +define('game/Spikes', + [ + 'game/CTRGameObject', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'core/Vector', + 'visual/Timeline', + 'utils/Constants', + 'utils/Radians', + 'utils/Mover', + 'visual/ImageElement', + 'visual/GenericButton', + 'core/Alignment', + 'visual/KeyFrame', + 'utils/Canvas', + 'resolution' + ], + function (CTRGameObject, SoundMgr, ResourceId, Vector, Timeline, Constants, Radians, Mover, ImageElement, GenericButton, Alignment, KeyFrame, Canvas, resolution) { + + var Spikes = CTRGameObject.extend({ + init: function (px, py, width, angle, t) { + this._super(); + + // select and load the spikes image + var imageId; + if (t !== Constants.UNDEFINED) { + imageId = ResourceId.IMG_OBJ_ROTATABLE_SPIKES_01 + width - 1; + } + else { + switch (width) { + case 1: + imageId = ResourceId.IMG_OBJ_SPIKES_01; + break; + case 2: + imageId = ResourceId.IMG_OBJ_SPIKES_02; + break; + case 3: + imageId = ResourceId.IMG_OBJ_SPIKES_03; + break; + case 4: + imageId = ResourceId.IMG_OBJ_SPIKES_04; + break; + case 5: + imageId = ResourceId.IMG_OBJ_ELECTRODES; + break; + } + } + this.initTextureWithId(imageId); + + if (t > 0) { + this.doRestoreCutTransparency(); + var normalQuad = IMG_OBJ_ROTATABLE_SPIKES_BUTTON_button_1 + (t - 1) * 2, + pressedQuad = IMG_OBJ_ROTATABLE_SPIKES_BUTTON_button_1_pressed + (t - 1) * 2, + bup = ImageElement.create(ResourceId.IMG_OBJ_ROTATABLE_SPIKES_BUTTON, normalQuad), + bdown = ImageElement.create(ResourceId.IMG_OBJ_ROTATABLE_SPIKES_BUTTON, pressedQuad); + + bup.doRestoreCutTransparency(); + bdown.doRestoreCutTransparency(); + + this.rotateButton = new GenericButton(SPIKES_ROTATION_BUTTON); + this.rotateButton.initWithElements(bup, bdown); + this.rotateButton.onButtonPressed = $.proxy(this.onButtonPressed, this); + this.rotateButton.anchor = this.rotateButton.parentAnchor = Alignment.CENTER; + this.addChild(this.rotateButton); + + // restore bounding box without alpha + var buttonTexture = bup.texture, + vo = buttonTexture.offsets[normalQuad], + vr = buttonTexture.rects[normalQuad], + vs = new Vector(vr.w, vr.h), + vo2 = new Vector(buttonTexture.preCutSize.x, buttonTexture.preCutSize.y); + + vo2.subtract(vs); + vo2.subtract(vo); + + this.rotateButton.setTouchIncrease( + -vo.x + vs.x / 2, + -vo2.x + vs.x / 2, + -vo.y + vs.y / 2, + -vo2.y + vs.y / 2); + + + } + + this.passColorToChilds = false; + this.spikesNormal = false; + this.originalRotation = this.rotation = angle; + + this.t1 = Vector.newZero(); + this.t2 = Vector.newZero(); + this.b1 = Vector.newZero(); + this.b2 = Vector.newZero(); + + this.electro = false; + this.initialDelay = 0; + this.onTime = 0; + this.offTime = 0; + this.electroOn = false; + this.electroTimer = 0; + + this.x = px; + this.y = py; + + this.setToggled(t); + this.updateRotation(); + + if (width === 5) { + this.addAnimationEndpoints( + SpikeAnimation.ELECTRODES_BASE, + 0.05, + Timeline.LoopType.REPLAY, + IMG_OBJ_ELECTRODES_base, + IMG_OBJ_ELECTRODES_base); + this.addAnimationEndpoints( + SpikeAnimation.ELECTRODES_ELECTRIC, + 0.05, + Timeline.LoopType.REPLAY, + IMG_OBJ_ELECTRODES_electric_start, + IMG_OBJ_ELECTRODES_electric_end); + this.doRestoreCutTransparency(); + } + this.touchIndex = Constants.UNDEFINED; + }, + updateRotation: function () { + var pWidth = this.electro + ? this.width - (400 * resolution.CANVAS_SCALE) + : this.texture.rects[this.quadToDraw].w; + + pWidth /= 2; + + this.t1.x = this.x - pWidth; + this.t2.x = this.x + pWidth; + this.t1.y = this.t2.y = this.y - SPIKES_HEIGHT / 2.0; + + this.b1.x = this.t1.x; + this.b2.x = this.t2.x; + this.b1.y = this.b2.y = this.y + SPIKES_HEIGHT / 2.0; + + this.angle = Radians.fromDegrees(this.rotation); + + this.t1.rotateAround(this.angle, this.x, this.y); + this.t2.rotateAround(this.angle, this.x, this.y); + this.b1.rotateAround(this.angle, this.x, this.y); + this.b2.rotateAround(this.angle, this.x, this.y); + }, + turnElectroOn: function () { + this.electroOn = true; + this.playTimeline(SpikeAnimation.ELECTRODES_ELECTRIC); + this.electroTimer = this.onTime; + SoundMgr.playLoopedSound(ResourceId.SND_ELECTRIC); + }, + turnElectroOff: function () { + this.electroOn = false; + this.playTimeline(SpikeAnimation.ELECTRODES_BASE); + this.electroTimer = this.offTime; + SoundMgr.stopSound(ResourceId.SND_ELECTRIC); + }, + update: function (delta) { + this._super(delta); + + if (this.mover || this.shouldUpdateRotation) { + this.updateRotation(); + } + + if (this.electro) { + if (this.electroOn) { + this.electroTimer = Mover.moveToTarget(this.electroTimer, 0, 1, delta); + if (this.electroTimer === 0) { + this.turnElectroOff(); + } + } + else { + this.electroTimer = Mover.moveToTarget(this.electroTimer, 0, 1, delta); + if (this.electroTimer === 0) { + this.turnElectroOn(); + } + } + } + }, + setToggled: function (t) { + this.toggled = t; + }, + getToggled: function () { + return this.toggled; + }, + rotateSpikes: function () { + this.spikesNormal = !this.spikesNormal; + this.removeTimeline(SpikeAnimation.ROTATION_ADJUSTED); + + var rDelta = this.spikesNormal ? 90 : 0, + adjustedRotation = this.originalRotation + rDelta, + tl = new Timeline(); + tl.addKeyFrame(KeyFrame.makeRotation( + this.rotation, + KeyFrame.TransitionType.LINEAR, + 0)); + tl.addKeyFrame(KeyFrame.makeRotation( + adjustedRotation, + KeyFrame.TransitionType.EASE_OUT, + Math.abs(adjustedRotation - this.rotation) / 90 * 0.3)); + tl.onFinished = $.proxy(this.timelineFinished, this); + + this.addTimelineWithID(tl, SpikeAnimation.ROTATION_ADJUSTED); + this.playTimeline(SpikeAnimation.ROTATION_ADJUSTED); + this.shouldUpdateRotation = true; + this.rotateButton.scaleX = -this.rotateButton.scaleX; + }, + timelineFinished: function (t) { + // update rotation one last time now that timeline is complete + this.updateRotation(); + this.shouldUpdateRotation = false; + }, + onButtonPressed: function (n) { + if (n === SPIKES_ROTATION_BUTTON) { + if (this.onRotateButtonPressed) { + this.onRotateButtonPressed(this.toggled); + } + + if (this.spikesNormal) { + SoundMgr.playSound(ResourceId.SND_SPIKE_ROTATE_IN); + } + else { + SoundMgr.playSound(ResourceId.SND_SPIKE_ROTATE_OUT); + } + } + }, + drawBB: function () { + var ctx = Canvas.context; + ctx.beginPath(); + ctx.strokeStyle = 'red'; + ctx.moveTo(this.t1.x, this.t1.y); + ctx.lineTo(this.t2.x, this.t2.y); + ctx.lineTo(this.b2.x, this.b2.y); + ctx.lineTo(this.b1.x, this.b1.y); + ctx.lineTo(this.t1.x, this.t1.y); + ctx.closePath(); + ctx.stroke(); + } + }); + + /** + * @const + * @type {number} + */ + var SPIKES_HEIGHT = 10; + + var IMG_OBJ_ELECTRODES_base = 0; + var IMG_OBJ_ELECTRODES_electric_start = 1; + var IMG_OBJ_ELECTRODES_electric_end = 4; + + var SPIKES_ROTATION_BUTTON = 0; + + var IMG_OBJ_ROTATABLE_SPIKES_01_Shape_3 = 0; + var IMG_OBJ_ROTATABLE_SPIKES_02_size_2 = 0; + var IMG_OBJ_ROTATABLE_SPIKES_03_size_3 = 0; + var IMG_OBJ_ROTATABLE_SPIKES_04_size_4 = 0; + var IMG_OBJ_ROTATABLE_SPIKES_BUTTON_button_1 = 0; + var IMG_OBJ_ROTATABLE_SPIKES_BUTTON_button_1_pressed = 1; + var IMG_OBJ_ROTATABLE_SPIKES_BUTTON_button_2 = 2; + var IMG_OBJ_ROTATABLE_SPIKES_BUTTON_button_2_pressed = 3; + + var SpikeAnimation = { + ELECTRODES_BASE: 0, + ELECTRODES_ELECTRIC: 1, + ROTATION_ADJUSTED: 2 + }; + + return Spikes; + } +); + + +define('game/Star', + [ + 'game/CTRGameObject', + 'visual/Animation', + 'resources/ResourceId', + 'core/Alignment', + 'visual/Timeline', + 'visual/KeyFrame', + 'core/RGBAColor', + 'core/Rectangle', + 'utils/MathHelper', + 'utils/Mover', + 'resolution' + ], + function (CTRGameObject, Animation, ResourceId, Alignment, Timeline, KeyFrame, RGBAColor, Rectangle, MathHelper, Mover, resolution) { + + var IMG_OBJ_STAR_IDLE_glow = 0; + var IMG_OBJ_STAR_IDLE_idle_start = 1; + var IMG_OBJ_STAR_IDLE_idle_end = 18; + var IMG_OBJ_STAR_IDLE_timed_start = 19; + var IMG_OBJ_STAR_IDLE_timed_end = 55; + + + var Star = CTRGameObject.extend({ + init: function () { + this._super(); + + this.time = 0; + this.timeout = 0; + this.timedAnim = null; + + // typically we pixel align image coordinates, but the star animation + // occurs along a small distance so we use a smaller increment so they + // don't appear jerky. It's good to use a value that evenly divides 1 + // so that at least some of the positions are on pixel boundaries. + this.drawPosIncrement = 0.0001; + }, + createAnimations: function () { + var t; + if (this.timeout > 0) { + // create animation + this.timedAnim = new Animation(); + this.timedAnim.initTextureWithId(ResourceId.IMG_OBJ_STAR_IDLE); + this.timedAnim.anchor = this.timedAnim.parentAnchor = Alignment.CENTER; + var delay = this.timeout / (IMG_OBJ_STAR_IDLE_timed_end - IMG_OBJ_STAR_IDLE_timed_start + 1); + this.timedAnim.addAnimationEndpoints(0, delay, Timeline.LoopType.NO_LOOP, + IMG_OBJ_STAR_IDLE_timed_start, IMG_OBJ_STAR_IDLE_timed_end); + + // play and add as child + this.timedAnim.playTimeline(0); + this.time = this.timeout; + this.timedAnim.visible = false; + this.addChild(this.timedAnim); + + // timeline for animation color fade + var tt = new Timeline(); + tt.addKeyFrame(KeyFrame.makeColor( + RGBAColor.solidOpaque.copy(), + KeyFrame.TransitionType.LINEAR, + 0)); + tt.addKeyFrame(KeyFrame.makeColor( + RGBAColor.transparent.copy(), + KeyFrame.TransitionType.LINEAR, + 0.5)); + this.timedAnim.addTimelineWithID(tt, 1); + + // timeline for element scale and color fade + t = new Timeline(); + t.addKeyFrame(KeyFrame.makeScale(1, 1, KeyFrame.TransitionType.LINEAR, 0)); + t.addKeyFrame(KeyFrame.makeScale(0, 0, KeyFrame.TransitionType.LINEAR, 0.25)); + t.addKeyFrame(KeyFrame.makeColor( + RGBAColor.solidOpaque.copy(), + KeyFrame.TransitionType.LINEAR, + 0)); + t.addKeyFrame(KeyFrame.makeColor( + RGBAColor.transparent.copy(), + KeyFrame.TransitionType.LINEAR, + 0.25)); + this.addTimelineWithID(t, 1); + } + + this.bb = Rectangle.copy(resolution.STAR_DEFAULT_BB); + + // timeline to make the star move up and down slightly + t = new Timeline(); + t.addKeyFrame(KeyFrame.makePos(this.x, this.y, KeyFrame.TransitionType.EASE_IN, 0)); + t.addKeyFrame(KeyFrame.makePos(this.x, this.y - 3, KeyFrame.TransitionType.EASE_OUT, 0.5)); + t.addKeyFrame(KeyFrame.makePos(this.x, this.y, KeyFrame.TransitionType.EASE_IN, 0.5)); + t.addKeyFrame(KeyFrame.makePos(this.x, this.y + 3, KeyFrame.TransitionType.EASE_OUT, 0.5)); + t.addKeyFrame(KeyFrame.makePos(this.x, this.y, KeyFrame.TransitionType.EASE_IN, 0.5)); + t.loopType = Timeline.LoopType.REPLAY; + this.addTimelineWithID(t, 0); + this.playTimeline(0); + t.update(MathHelper.randomRange(0, 20) / 10); + + // idle star animation + var sr = new Animation(); + sr.initTextureWithId(ResourceId.IMG_OBJ_STAR_IDLE); + sr.doRestoreCutTransparency(); + sr.addAnimationDelay(0.05, Timeline.LoopType.REPLAY, IMG_OBJ_STAR_IDLE_idle_start, + IMG_OBJ_STAR_IDLE_idle_end); + sr.playTimeline(0); + sr.getTimeline(0).update(MathHelper.randomRange(0, 20) / 10); + sr.anchor = sr.parentAnchor = Alignment.CENTER; + sr.drawPosIncrement = 0.0001; + + this.addChild(sr); + }, + update: function (delta) { + if (this.timeout > 0) { + if (this.time > 0) { + this.time = Mover.moveToTarget(this.time, 0, 1, delta); + } + } + this._super(delta); + }, + draw: function () { + if (this.timedAnim) { + this.timedAnim.draw(); + } + + this._super(); + } + }); + + return Star; + } +); + +define('visual/TextImage', + [ + 'visual/ImageElement', + 'visual/Text', + 'core/Texture2D' + ], + function (ImageElement, Text, Texture2D) { + var TextImage = ImageElement.extend({ + init: function () { + this._super(); + }, + setText: function (fontId, text, width, alignment) { + var img = Text.drawImg({ + fontId: fontId, + text: text, + width: width, + alignment: alignment + }); + this.initTexture(new Texture2D(img)); + } + }); + + return TextImage; + } +); + +define('game/TutorialText', + ['visual/TextImage'], + function (TextImage) { + + var TutorialText = TextImage.extend({ + init: function () { + this._super(); + this.special = 0; + } + }); + + return TutorialText; + } +); +define('visual/Camera2D', + [ + 'utils/Class', + 'core/Vector', + 'utils/Canvas', + 'utils/MathHelper' + ], + function (Class, Vector, Canvas, MathHelper) { + + var Camera2D = Class.extend({ + /** + * Camera2D constructor + * @param speed {number} + * @param cameraSpeed {CameraSpeed} + */ + init: function (speed, cameraSpeed) { + this.speed = speed; + this.type = cameraSpeed; + this.pos = Vector.newZero(); + this.target = Vector.newZero(); + this.offset = Vector.newZero(); + }, + /** + * Changes the camera position (but doesn't actually transform the canvas) + * @param x {number} + * @param y {number} + * @param immediate {boolean} + */ + moveTo: function (x, y, immediate) { + this.target.x = x; + this.target.y = y; + + if (immediate) { + this.pos.copyFrom(this.target); + } + else if (this.type === Camera2D.SpeedType.DELAY) { + this.offset = Vector.subtract(this.target, this.pos); + this.offset.multiply(this.speed); + } + else if (this.type === Camera2D.SpeedType.PIXELS) { + this.offset = Vector.subtract(this.target, this.pos); + this.offset.normalize(); + this.offset.multiply(this.speed); + } + }, + /** + * @param delta {number} time delta + */ + update: function (delta) { + if (!this.pos.equals(this.target)) { + + // add to the current position and round + this.pos.add(Vector.multiply(this.offset, delta)); + this.pos.round(); + + // see if we passed the target + if (!MathHelper.sameSign(this.offset.x, this.target.x - this.pos.x) || + !MathHelper.sameSign(this.offset.y, this.target.y - this.pos.y)) { + this.pos.copyFrom(this.target); + } + + //console.log('camera pos update x:' + this.pos.x + ' y:' + this.pos.y); + } + }, + applyCameraTransformation: function () { + if (this.pos.x !== 0 || this.pos.y !== 0) { + Canvas.context.translate(-this.pos.x, -this.pos.y); + } + }, + cancelCameraTransformation: function () { + if (this.pos.x !== 0 || this.pos.y !== 0) { + Canvas.context.translate(this.pos.x, this.pos.y); + } + } + }); + + /** + * @enum {number} + */ + Camera2D.SpeedType = { + PIXELS: 0, // camera will move with speed pixels per second + DELAY: 1 // camera will reach the target position in 1/speed seconds + }; + + return Camera2D; + } +); +define('utils/DelayedDispatcher', + [], + function () { + + var Dispatch = function (object, callback, param, delay) { + this.object = object; + this.callback = callback; + this.param = param; + this.delay = delay; + }; + + Dispatch.prototype.dispatch = function () { + this.callback.apply( + this.object, // use the object as the context (this) for the callback + this.param); + }; + + var DelayedDispatcher = { + dispatchers: [], + callObject: function (object, callback, param, delay) { + var dp = new Dispatch(object, callback, param, delay); + this.dispatchers.push(dp); + }, + cancelAllDispatches: function () { + this.dispatchers.length = 0; + }, + cancelDispatch: function (object, callback, param) { + for (var i = 0, count = this.dispatchers.length; i < count; i--) { + var dp = this.dispatchers[i]; + if (dp.object === object && + dp.callback === callback && + dp.param === param) { + this.dispatchers.splice(i, 1); + return; + } + } + }, + update: function (delta) { + + // take a snapshot of the current dispatchers since + // the queue may be modified during our update + var currentDps = this.dispatchers.slice(0); + + // update each of the dispatchers + for (var i = 0, len = currentDps.length; i < len; i++) { + var dp = currentDps[i]; + + // a previous dispatch may have cleared the queue, + // so make sure it still exists + var dpIndex = this.dispatchers.indexOf(dp); + if (dpIndex < 0) { + continue; + } + + // update the time and see if its time to fire + dp.delay -= delta; + if (dp.delay <= 0) { + // remove the object from the real pool first + this.dispatchers.splice(dpIndex, 1); + + // now we can run the callback + dp.dispatch(); + } + } + } + + }; + + return DelayedDispatcher; + } +); +define('utils/MapItem',[], function () { + /** + * @enum {number} + */ + var MapItem = { + MAP: 0, + GAME_DESIGN: 1, + TARGET: 2, + STAR: 3, + TUTORIAL_TEXT: 4, + TUTORIAL_01: 5, + TUTORIAL_02: 6, + TUTORIAL_03: 7, + TUTORIAL_04: 8, + TUTORIAL_05: 9, + TUTORIAL_06: 10, + TUTORIAL_07: 11, + TUTORIAL_08: 12, + TUTORIAL_09: 13, + TUTORIAL_10: 14, + TUTORIAL_11: 15, + TUTORIAL_12: 16, + TUTORIAL_13: 17, + TUTORIAL_14: 18, + // leave space for future tutorial elements + // (which the game assumes are sequentially numbered) + + CANDY_L: 50, + CANDY_R: 51, + CANDY: 52, + GRAVITY_SWITCH: 53, + BUBBLE: 54, + PUMP: 55, + SOCK: 56, + SPIKE_1: 57, + SPIKE_2: 58, + SPIKE_3: 59, + SPIKE_4: 60, + SPIKES_SWITCH: 61, + // leave space for future spike elements + + ELECTRO: 80, + BOUNCER1: 81, + BOUNCER2: 82, + // leave space for future bouncers + + GRAB: 100, + HIDDEN_01: 101, + HIDDEN_02: 102, + HIDDEN_03: 103, + // leave space for additional hidden + + ROTATED_CIRCLE: 120, + TARGET_2: 121, + CANDY_2: 122 + + }; + + function getMapItem(name) { + switch (name) { + case 'map': + return MapItem.MAP; + case 'gameDesign': + return MapItem.GAME_DESIGN; + case 'target': + return MapItem.TARGET; + case 'target2': + return MapItem.TARGET_2; + case 'star': + return MapItem.STAR; + case 'tutorialText': + return MapItem.TUTORIAL_TEXT; + case 'tutorial01': + return MapItem.TUTORIAL_01; + case 'tutorial02': + return MapItem.TUTORIAL_02; + case 'tutorial03': + return MapItem.TUTORIAL_03; + case 'tutorial04': + return MapItem.TUTORIAL_04; + case 'tutorial05': + return MapItem.TUTORIAL_05; + case 'tutorial06': + return MapItem.TUTORIAL_06; + case 'tutorial07': + return MapItem.TUTORIAL_07; + case 'tutorial08': + return MapItem.TUTORIAL_08; + case 'tutorial09': + return MapItem.TUTORIAL_09; + case 'tutorial10': + return MapItem.TUTORIAL_10; + case 'tutorial11': + return MapItem.TUTORIAL_11; + case 'tutorial12': + return MapItem.TUTORIAL_12; + case 'tutorial13': + return MapItem.TUTORIAL_13; + case 'tutorial14': + return MapItem.TUTORIAL_14; + case 'candyL': + return MapItem.CANDY_L; + case 'candyR': + return MapItem.CANDY_R; + case 'candy': + return MapItem.CANDY; + case 'candy2': + return MapItem.CANDY_2; + case 'gravitySwitch': + return MapItem.GRAVITY_SWITCH; + case 'bubble': + return MapItem.BUBBLE; + case 'pump': + return MapItem.PUMP; + case 'sock': + return MapItem.SOCK; + case 'spike1': + return MapItem.SPIKE_1; + case 'spike2': + return MapItem.SPIKE_2; + case 'spike3': + return MapItem.SPIKE_3; + case 'spike4': + return MapItem.SPIKE_4; + case 'spikesSwitch': + return MapItem.SPIKES_SWITCH; + case 'electro': + return MapItem.ELECTRO; + case 'bouncer1': + return MapItem.BOUNCER1; + case 'bouncer2': + return MapItem.BOUNCER2; + case 'grab': + return MapItem.GRAB; + case 'hidden01': + return MapItem.HIDDEN_01; + case 'hidden02': + return MapItem.HIDDEN_02; + case 'hidden03': + return MapItem.HIDDEN_03; + case 'rotatedCircle': + return MapItem.ROTATED_CIRCLE; + default: + alert('Unknown map item:' + name); + return null; + } + } + + MapItem.fromName = getMapItem; + + return MapItem; +}); + + +define('visual/AnimationPool', + ['visual/BaseElement'], + function (BaseElement) { + /** + * Container to hold animated objects which can be automatically deleted + * once their animation timelines have completed + */ + var AnimationPool = BaseElement.extend({ + init: function () { + this._super(); + + // keeps track of child elements whose timeline has completed + // and can be removed + this.removeList = []; + }, + update: function (delta) { + // remove the children + for (var i = 0, len = this.removeList.length; i < len; i++) { + this.removeChild(this.removeList[i]); + } + + // clear the remove list + this.removeList.length = 0; + this._super(delta); + }, + /** + * @param timeline {Timeline} + */ + timelineFinished: function (timeline) { + this.removeList.push(timeline.element); + }, + /** + * Returns a delegate that can be invoked when a timeline finishes + */ + timelineFinishedDelegate: function () { + // save a reference to ourselves since we may be called in a + // different context (typically by another class) + var self = this; + return function (timeline) { + self.timelineFinished(timeline); + } + }, + /** + * @param particles {Particles} + */ + particlesFinished: function (particles) { + this.removeList.push(particles); + }, + /** + * Returns a delegate that can be invoked when a particle system finishes + */ + particlesFinishedDelegate: function () { + // save a reference to ourselves since we may be called in a + // different context (typically by another class) + var self = this; + return function (particles) { + self.particlesFinished(particles); + } + } + }); + + return AnimationPool; + } +); + +// @depend BaseElement.js +// @depend ImageMultiDrawer.js +// @depend ../core/Rectangle.js + +define('visual/TileMap', + [ + 'visual/BaseElement', + 'visual/ImageMultiDrawer', + 'core/Rectangle', + 'resolution', + 'utils/Constants', + 'utils/MathHelper', + 'core/Vector' + ], + function (BaseElement, ImageMultiDrawer, Rectangle, resolution, Constants, MathHelper, Vector) { + + /** + * An entry in the tile map + * @constructor + * @param drawerIndex {number} + * @param quadIndex {number} + */ + function TileEntry(drawerIndex, quadIndex) { + this.drawerIndex = drawerIndex; + this.quad = quadIndex; + } + + var TileMap = BaseElement.extend({ + init: function (rows, columns) { + this._super(); + + this.rows = rows; + this.columns = columns; + + this.cameraViewWidth = resolution.CANVAS_WIDTH; + this.cameraViewHeight = resolution.CANVAS_HEIGHT; + + this.parallaxRatio = 1; + + this.drawers = []; + this.tiles = []; + + this.matrix = []; + for (var i = 0; i < columns; i++) { + var column = this.matrix[i] = []; + for (var k = 0; k < rows; k++) { + column[k] = Constants.UNDEFINED; + } + } + + this.repeatedVertically = TileMap.RepeatType.NONE; + this.repeatedHorizontally = TileMap.RepeatType.NONE; + this.horizontalRandom = false; + this.verticalRandom = false; + this.restoreTileTransparency = true; + this.randomSeed = MathHelper.randomRange(1000, 2000); + }, + addTile: function (texture, quadIndex) { + if (quadIndex === Constants.UNDEFINED) { + this.tileWidth = texture.imageWidth; + this.tileHeight = texture.imageHeight; + } + else { + var rect = texture.rects[quadIndex]; + this.tileWidth = rect.w; + this.tileHeight = rect.h; + } + + this.updateVars(); + + var drawerId = Constants.UNDEFINED; + for (var i = 0, len = this.drawers.length; i < len; i++) { + if (this.drawers[i].texture === texture) { + drawerId = i; + break; + } + } + + if (drawerId === Constants.UNDEFINED) { + var d = new ImageMultiDrawer(texture); + drawerId = this.drawers.length; + this.drawers.push(d); + } + + var entry = new TileEntry(drawerId, quadIndex); + this.tiles.push(entry); + }, + updateVars: function () { + this.maxColsOnScreen = 2 + ~~(this.cameraViewWidth / (this.tileWidth + 1)); + this.maxRowsOnScreen = 2 + ~~(this.cameraViewHeight / (this.tileHeight + 1)); + + if (this.repeatedVertically === TileMap.RepeatType.NONE) { + this.maxRowsOnScreen = Math.min(this.maxRowsOnScreen, this.rows); + } + + if (this.repeatedHorizontally === TileMap.RepeatType.NONE) { + this.maxColsOnScreen = Math.min(this.maxColsOnScreen, this.columns); + } + + this.width = this.tileMapWidth = this.columns * this.tileWidth; + this.height = this.tileMapHeight = this.rows * this.tileHeight; + }, + /** + * Fills the tilemap matrix with the specified tile entry index + * @param startRow {number} + * @param startCol {number} + * @param numRows {number} + * @param numCols {number} + * @param tileIndex {number} + */ + fill: function (startRow, startCol, numRows, numCols, tileIndex) { + for (var i = startCol, colEnd = startCol + numCols; i < colEnd; i++) { + for (var k = startRow, rowEnd = startRow + numRows; k < rowEnd; k++) { + this.matrix[i][k] = tileIndex; + } + } + }, + setParallaxRation: function (ratio) { + this.parallaxRatio = ratio; + }, + /** + * @param repeatType {TileMap.RepeatType} + */ + setRepeatHorizontally: function (repeatType) { + this.repeatedHorizontally = repeatType; + this.updateVars(); + }, + setRepeatVertically: function (repeatType) { + this.repeatedVertically = repeatType; + this.updateVars(); + }, + /** + * Updates the tile map based on the current camera position + * @param pos {Vector} + */ + updateWithCameraPos: function (pos) { + var mx = Math.round(pos.x / this.parallaxRatio), + my = Math.round(pos.y / this.parallaxRatio), + tileMapStartX = this.x, + tileMapStartY = this.y, + a, i, len, v; + + if (this.repeatedVertically !== TileMap.RepeatType.NONE) { + var ys = tileMapStartY - my; + a = ~~(ys) % this.tileMapHeight; + if (ys < 0) { + tileMapStartY = a + my; + } + else { + tileMapStartY = a - this.tileMapHeight + my; + } + } + + if (this.repeatedHorizontally !== TileMap.RepeatType.NONE) { + var xs = tileMapStartX - mx; + a = ~~(xs) % this.tileMapWidth; + if (xs < 0) { + tileMapStartX = a + mx; + } + else { + tileMapStartX = a - this.tileMapWidth + mx; + } + } + + // see if tile map is in the camera view + if (!Rectangle.rectInRect( + mx, my, mx + this.cameraViewWidth, my + this.cameraViewHeight, + tileMapStartX, + tileMapStartY, + tileMapStartX + this.tileMapWidth, + tileMapStartY + this.tileMapHeight)) { + return; + } + + var cameraInTilemap = Rectangle.rectInRectIntersection( + tileMapStartX, tileMapStartY, this.tileMapWidth, this.tileMapHeight, // tile map rect + mx, my, this.cameraViewWidth, this.cameraViewHeight); // camera rect + + var checkPoint = new Vector( + Math.max(0, cameraInTilemap.x), + Math.max(0, cameraInTilemap.y)); + + //noinspection JSSuspiciousNameCombination + var startPos = new Vector( + ~~(~~(checkPoint.x) / this.tileWidth), + ~~(~~(checkPoint.y) / this.tileHeight)); + + var highestQuadY = tileMapStartY + startPos.y * this.tileHeight, + currentQuadPos = new Vector(tileMapStartX + startPos.x * this.tileWidth, highestQuadY); + + // reset the number of quads to draw + for (i = 0, len = this.drawers.length; i < len; i++) { + this.drawers[i].numberOfQuadsToDraw = 0; + } + + var maxColumn = startPos.x + this.maxColsOnScreen - 1, + maxRow = startPos.y + this.maxRowsOnScreen - 1; + + if (this.repeatedVertically === TileMap.RepeatType.NONE) { + maxRow = Math.min(this.rows - 1, maxRow); + } + if (this.repeatedHorizontally === TileMap.RepeatType.NONE) { + maxColumn = Math.min(this.columns - 1, maxColumn); + } + + for (i = startPos.x; i <= maxColumn; i++) { + currentQuadPos.y = highestQuadY; + for (var j = startPos.y; j <= maxRow; j++) { + if (currentQuadPos.y >= my + this.cameraViewHeight) { + break; + } + + // find intersection rectangle between camera rectangle and every tiled + // texture rectangle + var resScreen = Rectangle.rectInRectIntersection( + mx, my, this.cameraViewWidth, this.cameraViewHeight, + currentQuadPos.x, currentQuadPos.y, this.tileWidth, this.tileHeight); + + var resTexture = new Rectangle( + (mx - currentQuadPos.x) + resScreen.x, + (my - currentQuadPos.y) + resScreen.y, + resScreen.w, + resScreen.h); + + var ri = Math.round(i), + rj = Math.round(j); + + if (this.repeatedVertically === TileMap.RepeatType.EDGES) { + if (currentQuadPos.y < y) { + rj = 0; + } + else if (currentQuadPos.y >= this.y + this.tileMapHeight) { + rj = this.rows - 1; + } + } + + if (this.repeatedHorizontally === TileMap.RepeatType.EDGES) { + if (currentQuadPos.x < this.x) { + ri = 0; + } + else if (currentQuadPos.x >= this.x + this.tileMapWidth) { + ri = this.columns - 1; + } + } + + if (this.horizontalRandom) { + v = Math.sin(currentQuadPos.x) * this.randomSeed; + ri = Math.abs(~~(v) % this.columns); + } + + if (this.verticalRandom) { + v = Math.sin(currentQuadPos.y) * this.randomSeed; + rj = Math.abs(~~(v) % this.rows); + } + + if (ri >= this.columns) { + ri = ri % this.columns; + } + + if (rj >= this.rows) { + rj = rj % this.rows; + } + + var tile = this.matrix[ri][rj]; + if (tile >= 0) { + var entry = this.tiles[tile], + drawer = this.drawers[entry.drawerIndex], + texture = drawer.texture; + + if (entry.quad !== Constants.UNDEFINED) { + var rect = texture.rects[entry.quad]; + resTexture.x += rect.x; + resTexture.y += rect.y; + } + + var vertRect = new Rectangle( + pos.x + resScreen.x, + pos.y + resScreen.y, + resScreen.w, + resScreen.h); + + drawer.setTextureQuad(drawer.numberOfQuadsToDraw++, resTexture, vertRect); + } + currentQuadPos.y += this.tileHeight; + } + currentQuadPos.x += this.tileWidth; + + if (currentQuadPos.x >= mx + this.cameraViewWidth) { + break; + } + } + + + }, + draw: function () { + this.preDraw(); + for (var i = 0, len = this.drawers.length; i < len; i++) { + this.drawers[i].draw(); + } + this.postDraw(); + } + }); + + /** + * @enum {number} + */ + TileMap.RepeatType = { + NONE: 0, + ALL: 1, + EDGES: 2 + }; + + return TileMap; + } +); +define('visual/BackgroundTileMap', + [ + 'visual/TileMap', + 'core/Vector' + ], + function (TileMap, Vector) { + var BackgroundTileMap = TileMap.extend({ + init: function (rows, columns) { + this._super(rows, columns); + this.lastCameraPos = Vector.newUndefined(); + }, + updateWithCameraPos: function (pos) { + if (!this.lastCameraPos.equals(pos)) { + this._super(pos); + this.lastCameraPos.copyFrom(pos); + } + }, + draw: function () { + /* seems like this should be taken care of in BaseElement.preDraw? + + var rotationOffsetX = this.back.drawX + (this.back.width >> 1) + this.back.rotationCenterX, + rotationOffsetY = this.back.drawY + (this.back.height >> 1) + this.back.rotationCenterY, + ctx = Canvas.context; + + // TODO: skip scaling if unnecessary + ctx.translate(rotationOffsetX, rotationOffsetY); + ctx.scale(this.back.scaleX, this.back.scaleY); + ctx.translate(-rotationOffsetX, -rotationOffsetY); + */ + + this._super(); + } + }); + + return BackgroundTileMap; + } +); + + + + +define('visual/ToggleButton', + [ + 'visual/BaseElement', + 'visual/GenericButton', + 'core/Alignment' + ], + function (BaseElement, GenericButton, Alignment) { + + var ToggleButtonId = { + FACE1: 0, + FACE2: 1 + }; + + var ToggleButton = BaseElement.extend({ + init: function (up1, down1, up2, down2, id) { + this._super(); + + this.buttonId = id; + + this.b1 = new GenericButton(ToggleButtonId.FACE1); + this.b1.initWithElements(up1, down1); + + this.b2 = new GenericButton(ToggleButtonId.FACE2); + this.b2.initWithElements(up2, down2); + + this.b1.parentAnchor = this.b2.parentAnchor = Alignment.TOP | Alignment.LEFT; + this.width = this.b1.width; + this.height = this.b1.height; + + this.addChildWithID(this.b1, ToggleButtonId.FACE1); + this.addChildWithID(this.b2, ToggleButtonId.FACE2); + + this.b2.setEnabled(false); + this.b1.onButtonPressed = $.proxy(this.onButtonPressed, this); + this.b2.onButtonPressed = $.proxy(this.onButtonPressed, this); + }, + onButtonPressed: function (n) { + switch (n) { + case ToggleButtonId.FACE1: + case ToggleButtonId.FACE2: + this.toggle(); + break; + } + if (this.onButtonPressed) { + this.onButtonPressed(this.buttonId); + } + }, + setTouchIncrease: function (left, right, top, bottom) { + this.b1.setTouchIncrease(left, right, top, bottom); + this.b2.setTouchIncrease(left, right, top, bottom); + }, + toggle: function () { + this.b1.setEnabled(!this.b1.isEnabled()); + this.b2.setEnabled(!this.b2.isEnabled()); + }, + isOn: function () { + return this.b2.isEnabled(); + } + }); + + return ToggleButton; + } +); + +define('game/GravityButton', + [ + 'visual/ImageElement', + 'visual/ToggleButton', + 'resources/ResourceId' + ], + function (ImageElement, ToggleButton, ResourceId) { + + var IMG_OBJ_STAR_IDLE_gravity_down = 56; + var IMG_OBJ_STAR_IDLE_gravity_up = 57; + + var GravityButton = ToggleButton.extend({ + init: function () { + var itn = ImageElement.create(ResourceId.IMG_OBJ_STAR_IDLE, IMG_OBJ_STAR_IDLE_gravity_down), + itp = ImageElement.create(ResourceId.IMG_OBJ_STAR_IDLE, IMG_OBJ_STAR_IDLE_gravity_down), + itn2 = ImageElement.create(ResourceId.IMG_OBJ_STAR_IDLE, IMG_OBJ_STAR_IDLE_gravity_up), + itp2 = ImageElement.create(ResourceId.IMG_OBJ_STAR_IDLE, IMG_OBJ_STAR_IDLE_gravity_up); + + this._super(itn, itp, itn2, itp2, GravityButton.DefaultId); + + this.setTouchIncrease(10, 10, 10, 10); + } + }); + + GravityButton.DefaultId = 0; + + return GravityButton; + } +); + +define('game/EarthImage', + [ + 'visual/ImageElement', + 'visual/Timeline', + 'visual/KeyFrame', + 'core/Alignment', + 'resources/ResourceId' + ], + function (ImageElement, Timeline, KeyFrame, Alignment, ResourceId) { + + var IMG_BGR_08_P1__position_window = 1; + var IMG_OBJ_STAR_IDLE_window = 58; + + var EarthImage = ImageElement.extend({ + init: function (offsetX, offsetY) { + this._super(); + this.initTextureWithId(ResourceId.IMG_OBJ_STAR_IDLE); + this.setTextureQuad(IMG_OBJ_STAR_IDLE_window); + this.anchor = Alignment.CENTER; + + var t = new Timeline(); + t.addKeyFrame(KeyFrame.makeRotation(0, KeyFrame.TransitionType.LINEAR, 0)); + t.addKeyFrame(KeyFrame.makeRotation(180, KeyFrame.TransitionType.EASE_OUT, 0.3)); + this.addTimelineWithID(t, EarthImage.TimelineId.UPSIDE_DOWN); + + var t2 = new Timeline(); + t2.addKeyFrame(KeyFrame.makeRotation(180, KeyFrame.TransitionType.LINEAR, 0)); + t2.addKeyFrame(KeyFrame.makeRotation(0, KeyFrame.TransitionType.EASE_OUT, 0.3)); + this.addTimelineWithID(t2, EarthImage.TimelineId.NORMAL); + + this.setElementPositionWithOffset(ResourceId.IMG_BGR_08_P1, IMG_BGR_08_P1__position_window); + this.x += offsetX; + this.y += offsetY; + } + }); + + /** + * @enum {number} + */ + EarthImage.TimelineId = { + NORMAL: 0, + UPSIDE_DOWN: 1 + }; + + return EarthImage; + } +); +define('game/PollenDrawer', + [ + 'visual/BaseElement', + 'core/Vector', + 'resources/ResourceId', + 'visual/ImageElement', + 'visual/ImageMultiDrawer', + 'resources/ResourceMgr', + 'utils/Mover', + 'utils/MathHelper', + 'resolution', + 'core/Rectangle' + ], + function (BaseElement, Vector, ResourceId, ImageElement, ImageMultiDrawer, ResourceMgr, Mover, MathHelper, resolution, Rectangle) { + + function Pollen() { + this.parentIndex = 0; + this.x = 0; + this.y = 0; + + this.scaleX = 1; + this.startScaleX = 1; + this.endScaleX = 1; + + this.scaleY = 1; + this.startScaleY = 1; + this.endScaleY = 1; + + this.alpha = 1; + this.startAlpha = 1; + this.endAlpha = 1; + } + + var PollenDrawer = BaseElement.extend({ + init: function () { + this._super(); + + var pollen = ResourceMgr.getTexture(ResourceId.IMG_OBJ_POLLEN_HD); + + this.qw = pollen.imageWidth; + this.qh = pollen.imageHeight; + + this.drawer = new ImageMultiDrawer(pollen); + this.drawer.drawPosIncrement = 0.1; + + this.pollens = []; + }, + addPollen: function (v, pi) { + var sX = 1, + sY = 1, + size = [ 0.3, 0.3, 0.5, 0.5, 0.6 ], + sizeCounts = size.length, + rx = size[MathHelper.randomRange(0, sizeCounts - 1)], + ry = rx; + + if (MathHelper.randomBool()) { + rx *= 1 + (MathHelper.randomRange(0, 1) / 10); + } + else { + ry *= 1 + (MathHelper.randomRange(0, 1) / 10); + } + + sX *= rx; + sY *= ry; + + var w = this.qw * sX, + h = this.qh * sY, + maxScale = 1, + d = Math.min(maxScale - sX, maxScale - sY), + delta = Math.random(), + pollen = new Pollen(); + + pollen.parentIndex = pi; + pollen.x = v.x; + pollen.y = v.y; + pollen.startScaleX = d + sX; + pollen.startScaleY = d + sY; + pollen.scaleX = pollen.startScaleX * delta; + pollen.scaleY = pollen.startScaleY * delta; + pollen.endScaleX = sX; + pollen.endScaleY = sY; + pollen.endAlpha = 0.3; + pollen.startAlpha = 1; + pollen.alpha = (0.7 * delta) + 0.3; + + var tquad = this.drawer.texture.rects[IMG_OBJ_POLLEN_HD_obj_pollen], + vquad = new Rectangle(v.x - w / 2, v.y - h / 2, w, h); + + this.drawer.setTextureQuad( + this.pollens.length, tquad, vquad, pollen.alpha); + this.pollens.push(pollen); + }, + fillWithPollenFromPath: function (fromIndex, toIndex, grab) { + var MIN_DISTANCE = resolution.POLLEN_MIN_DISTANCE, + v1 = grab.mover.path[fromIndex], + v2 = grab.mover.path[toIndex], + v = Vector.subtract(v2, v1), + vLen = v.getLength(), + times = ~~(vLen / MIN_DISTANCE), + POLLEN_MAX_OFFSET = resolution.POLLEN_MAX_OFFSET, + i, vn; + + v.normalize(); + + for (i = 0; i <= times; i++) { + vn = Vector.add(v1, Vector.multiply(v, i * MIN_DISTANCE)); + vn.x += MathHelper.randomRange(-POLLEN_MAX_OFFSET, POLLEN_MAX_OFFSET); + vn.y += MathHelper.randomRange(-POLLEN_MAX_OFFSET, POLLEN_MAX_OFFSET); + this.addPollen(vn, fromIndex); + } + }, + update: function (delta) { + this._super(delta); + this.drawer.update(delta); + + var len = this.pollens.length, + i, pollen, temp, w, h, moveResult, a; + + for (i = 0; i < len; i++) { + pollen = this.pollens[i]; + + // increment the scale + moveResult = Mover.moveToTargetWithStatus(pollen.scaleX, pollen.endScaleX, 1, delta); + pollen.scaleX = moveResult.value; + if (moveResult.reachedZero) { + // swap the start and end values + temp = pollen.startScaleX; + pollen.startScaleX = pollen.endScaleX; + pollen.endScaleX = temp; + } + + moveResult = Mover.moveToTargetWithStatus(pollen.scaleY, pollen.endScaleY, 1, delta); + pollen.scaleY = moveResult.value; + if (moveResult.reachedZero) { + // swap the start and end values + temp = pollen.startScaleY; + pollen.startScaleY = pollen.endScaleY; + pollen.endScaleY = temp; + } + + w = this.qw * pollen.scaleX; + h = this.qh * pollen.scaleY; + + // update the current position + this.drawer.vertices[i] = new Rectangle( + pollen.x - w / 2, + pollen.y - h / 2, + w, h); + + // increment the alpha + moveResult = Mover.moveToTargetWithStatus(pollen.alpha, pollen.endAlpha, 1, delta); + pollen.alpha = moveResult.value; + if (moveResult.reachedZero) { + // swap the start and end values + temp = pollen.startAlpha; + pollen.startAlpha = pollen.endAlpha; + pollen.endAlpha = temp; + } + + // update the alpha in the drawer + this.drawer.alphas[i] = pollen.alpha; + } + }, + draw: function () { + this.preDraw(); + this.drawer.draw(); + this.postDraw(); + } + }); + + var IMG_OBJ_POLLEN_HD_obj_pollen = 0; + + return PollenDrawer; + } +); +define('game/RotatedCircle', + [ + 'visual/BaseElement', + 'utils/Constants', + 'visual/ImageElement', + 'resources/ResourceId', + 'core/Alignment', + 'resolution', + 'core/Vector', + 'utils/Radians', + 'utils/Canvas' + ], + function (BaseElement, Constants, ImageElement, ResourceId, Alignment, resolution, Vector, Radians, Canvas) { + + var CONTOUR_ALPHA = 0.2, + CONTROLLER_MIN_SCALE = 0.75, + STICKER_MIN_SCALE = 0.4, + CENTER_SCALE_FACTOR = 0.5, + HUNDRED_PERCENT_SCALE_SIZE = 167.0, + CIRCLE_VERTEX_COUNT = 80, + INNER_CIRCLE_WIDTH = 15 * resolution.PM, + OUTER_CIRCLE_WIDTH = 7 * resolution.PM, + ACTIVE_CIRCLE_WIDTH = 3 * resolution.PM, + CONTROLLER_SHIFT_PARAM1 = 22.5 * resolution.PM, + CONTROLLER_SHIFT_PARAM2 = 0.03 * resolution.PM; + + var StickerImage = ImageElement.extend({ + init: function () { + this._super(); + this.initTextureWithId(ResourceId.IMG_OBJ_VINIL); + this.setTextureQuad(IMG_OBJ_VINIL_odj_vinil_sticker); + } + }); + + var RotatedCircle = BaseElement.extend({ + init: function () { + this._super(); + this.containedObjects = []; + this.circles = []; + this.soundPlaying = Constants.UNDEFINED; + this.lastTouch = Vector.newUndefined(); + + this.vinilStickerL = new StickerImage(); + this.vinilStickerL.anchor = Alignment.RIGHT | Alignment.VCENTER; + this.vinilStickerL.scaleX = 1; + this.vinilStickerL.parentAnchor = Alignment.CENTER; + this.vinilStickerL.rotationCenterX = this.vinilStickerL.width / 2 + 0.5; + this.vinilStickerL.drawPosIncrement = 0.001; + + this.vinilStickerR = new StickerImage(); + this.vinilStickerR.scaleX = -1; + this.vinilStickerR.anchor = Alignment.RIGHT | Alignment.VCENTER; + this.vinilStickerR.parentAnchor = Alignment.CENTER; + this.vinilStickerR.rotationCenterX = (this.vinilStickerR.width / 2) - 0.5; + this.vinilStickerR.drawPosIncrement = 0.001; + + this.vinilCenter = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_vinil_center); + this.vinilCenter.anchor = Alignment.CENTER; + + this.vinilHighlightL = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_vinil_highlight); + this.vinilHighlightL.anchor = Alignment.TOP | Alignment.RIGHT; + + this.vinilHighlightR = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_vinil_highlight); + this.vinilHighlightR.scaleX = -1; + this.vinilHighlightR.anchor = Alignment.TOP | Alignment.LEFT; + + this.vinilControllerL = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_controller); + this.vinilControllerL.anchor = Alignment.CENTER; + this.vinilControllerL.rotation = 90.0; + + this.vinilControllerR = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_controller); + this.vinilControllerR.anchor = Alignment.CENTER; + this.vinilControllerR.rotation = -90.0; + + this.vinilActiveControllerL = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_controller_active); + this.vinilActiveControllerL.anchor = this.vinilControllerL.anchor; + this.vinilActiveControllerL.rotation = this.vinilControllerL.rotation; + this.vinilActiveControllerL.visible = false; + + this.vinilActiveControllerR = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_controller_active); + this.vinilActiveControllerR.anchor = this.vinilControllerR.anchor; + this.vinilActiveControllerR.rotation = this.vinilControllerR.rotation; + this.vinilActiveControllerR.visible = false; + + this.vinil = ImageElement.create( + ResourceId.IMG_OBJ_VINIL, IMG_OBJ_VINIL_obj_vinil); + this.vinil.anchor = Alignment.CENTER; + + this.passColorToChilds = false; + + this.addChild(this.vinilStickerL); + this.addChild(this.vinilStickerR); + this.addChild(this.vinilActiveControllerL); + this.addChild(this.vinilActiveControllerR); + this.addChild(this.vinilControllerL); + this.addChild(this.vinilControllerR); + }, + setSize: function (value) { + this.size = value; + + var newScale = this.size / HUNDRED_PERCENT_SCALE_SIZE; + this.vinilHighlightL.scaleX = this.vinilHighlightL.scaleY = + this.vinilHighlightR.scaleY = newScale; + this.vinilHighlightR.scaleX = -newScale; + + this.vinil.scaleX = this.vinil.scaleY = newScale; + + var newStickerScale = (newScale >= STICKER_MIN_SCALE) + ? newScale : STICKER_MIN_SCALE; + this.vinilStickerL.scaleX = this.vinilStickerL.scaleY = this.vinilStickerR.scaleY = newStickerScale; + this.vinilStickerR.scaleX = -newStickerScale; + + var newControllerScale = (newScale >= CONTROLLER_MIN_SCALE) + ? newScale : CONTROLLER_MIN_SCALE; + this.vinilControllerL.scaleX = this.vinilControllerL.scaleY = + this.vinilControllerR.scaleX = this.vinilControllerR.scaleY = newControllerScale; + this.vinilActiveControllerL.scaleX = this.vinilActiveControllerL.scaleY = + this.vinilActiveControllerR.scaleX = this.vinilActiveControllerR.scaleY = newControllerScale; + + this.vinilCenter.scaleX = 1.0 - (1.0 - newStickerScale) * CENTER_SCALE_FACTOR; + this.vinilCenter.scaleY = this.vinilCenter.scaleX; + + this.sizeInPixels = this.vinilHighlightL.width * this.vinilHighlightL.scaleX; + + this.updateChildPositions(); + }, + + hasOneHandle: function () { + return (!this.vinilControllerL.visible); + }, + setHasOneHandle: function (value) { + this.vinilControllerL.visible = !value; + }, + isLeftControllerActive: function () { + return this.vinilActiveControllerL.visible; + }, + setIsLeftControllerActive: function (value) { + this.vinilActiveControllerL.visible = value; + }, + isRightControllerActive: function () { + return this.vinilActiveControllerR.visible; + }, + setIsRightControllerActive: function (value) { + this.vinilActiveControllerR.visible = value; + }, + containsSameObjectWithAnotherCircle: function () { + var len = this.circles.length, + i, anotherCircle; + for (i = 0; i < len; i++) { + anotherCircle = this.circles[i]; + if (anotherCircle != this && + this.containsSameObjectWithCircle(anotherCircle)) { + return true; + } + } + return false; + }, + draw: function () { + var ctx = Canvas.context; + if (this.isRightControllerActive() || this.isLeftControllerActive()) { + var lineWidth = (ACTIVE_CIRCLE_WIDTH + resolution.PM) * this.vinilControllerL.scaleX, + radius = this.sizeInPixels + ~~(lineWidth / 2); + ctx.beginPath(); + ctx.lineWidth = lineWidth; + ctx.arc(this.x, this.y, radius, 0, 2 * Math.PI, false); + ctx.stroke(); + } + + this.vinilHighlightL.color = this.color; + this.vinilHighlightR.color = this.color; + this.vinilControllerL.color = this.color; + this.vinilControllerR.color = this.color; + this.vinil.color = this.color; + this.vinil.draw(); + + var len = this.circles.length, + i, anotherCircle, + selfIndex = this.circles.indexOf(this), + previousAlpha = ctx.globalAlpha; + + if (previousAlpha !== CONTOUR_ALPHA) { + ctx.globalAlpha = CONTOUR_ALPHA; + } + + for (i = 0; i < len; i++) { + anotherCircle = this.circles[i]; + if (anotherCircle != this && + anotherCircle.containsSameObjectWithAnotherCircle() && + (this.circles.indexOf(anotherCircle) < selfIndex )) { + + this.drawCircleIntersection( + this.x, this.y, this.sizeInPixels, + anotherCircle.x, anotherCircle.y, anotherCircle.sizeInPixels, + (OUTER_CIRCLE_WIDTH * anotherCircle.vinilHighlightL.scaleX) * 0.5); + } + } + + if (previousAlpha !== CONTOUR_ALPHA) { + ctx.globalAlpha = previousAlpha; + } + + this.vinilHighlightL.draw(); + this.vinilHighlightR.draw(); + + this._super(); + + this.vinilCenter.draw(); + }, + drawCircleIntersection: function (cx1, cy1, radius1, cx2, cy2, radius2, width) { + var circleDistance = Vector.distance(cx1, cy1, cx2, cy2); + if ((circleDistance >= radius1 + radius2) || + (radius1 >= circleDistance + radius2)) { + return; + } + + //circleDistance = a + b + var a = (radius1 * radius1 - radius2 * radius2 + circleDistance * circleDistance) / (2 * circleDistance), + b = circleDistance - a, + beta = Math.acos(b / radius2), + + diff = new Vector(cx1 - cx2, cy1 - cy2), + centersAngle = diff.angle(), + startAngle = centersAngle - beta, + endAngle = centersAngle + beta; + + if (cx2 > cx1) { + startAngle += Math.PI; + endAngle += Math.PI; + } + + var ctx = Canvas.context; + ctx.beginPath(); + ctx.lineWidth = width; + ctx.arc(cx2, cy2, radius2, startAngle, endAngle, false); + ctx.stroke(); + + + }, + updateChildPositions: function () { + this.vinil.x = this.vinilCenter.x = this.x; + this.vinil.y = this.vinilCenter.y = this.y; + + var highlightDeltaX = this.vinilHighlightL.width / 2 * (1.0 - this.vinilHighlightL.scaleX), + highlightDeltaY = this.vinilHighlightL.height / 2 * (1.0 - this.vinilHighlightL.scaleY), + controllerDeltaX = this.sizeInPixels - + (CONTROLLER_SHIFT_PARAM1 - CONTROLLER_SHIFT_PARAM2 * this.size) + + (1.0 - this.vinilControllerL.scaleX) * (this.vinilControllerL.width / 2); + + this.vinilHighlightL.x = this.x + highlightDeltaX; + this.vinilHighlightR.x = this.x - highlightDeltaX; + this.vinilHighlightL.y = this.vinilHighlightR.y = this.y - highlightDeltaY; + + this.vinilControllerL.x = this.x - controllerDeltaX; + this.vinilControllerR.x = this.x + controllerDeltaX; + this.vinilControllerL.y = this.vinilControllerR.y = this.y; + + this.vinilActiveControllerL.x = this.vinilControllerL.x; + this.vinilActiveControllerL.y = this.vinilControllerL.y; + this.vinilActiveControllerR.x = this.vinilControllerR.x; + this.vinilActiveControllerR.y = this.vinilControllerR.y; + }, + containsSameObjectWithCircle: function (anotherCircle) { + + // check for copy of self + if (this.x === anotherCircle.x && + this.y === anotherCircle.y && + this.size === anotherCircle.size) { + return false; + } + + var len = this.containedObjects.length, + i, object; + for (i = 0; i < len; i++) { + if (anotherCircle.containedObjects.indexOf( + this.containedObjects[i]) >= 0) { + return true; + } + } + return false; + }, + copy: function (zone) { + var copiedCircle = new RotatedCircle(); + copiedCircle.zone = zone; + copiedCircle.x = this.x; + copiedCircle.y = this.y; + copiedCircle.rotation = this.rotation; + copiedCircle.circles = this.circles; + copiedCircle.containedObjects = this.containedObjects; + copiedCircle.operating = Constants.UNDEFINED; + + var copiedSize = this.size * resolution.PM, + copiedRadians = Radians.fromDegrees(copiedCircle.rotation); + copiedCircle.handle1 = new Vector( + copiedCircle.x - copiedSize, copiedCircle.y); + copiedCircle.handle2 = new Vector( + copiedCircle.x + copiedSize, copiedCircle.y); + copiedCircle.handle1.rotateAround( + copiedRadians, copiedCircle.x, copiedCircle.y); + copiedCircle.handle2.rotateAround( + copiedRadians, copiedCircle.x, copiedCircle.y); + + copiedCircle.setSize(this.size); + copiedCircle.setHasOneHandle(this.hasOneHandle()); + + // circle controllers should not be visible + copiedCircle.vinilControllerL.visible = false; + copiedCircle.vinilControllerR.visible = false; + + return copiedCircle; + } + }); + + var IMG_OBJ_VINIL_obj_vinil = 0; + var IMG_OBJ_VINIL_obj_vinil_highlight = 1; + var IMG_OBJ_VINIL_odj_vinil_sticker = 2; + var IMG_OBJ_VINIL_obj_vinil_center = 3; + var IMG_OBJ_VINIL_obj_controller_active = 4; + var IMG_OBJ_VINIL_obj_controller = 5; + + return RotatedCircle; + } +); + +define('achievements/AchievementId',[], function () { + + // This is the internal CTR id for achievements. XBOX and other + // game centers may use different ids. + var AchievementId = { + BRONZE_SCISSORS: 0, + SILVER_SCISSORS: 1, + GOLDEN_SCISSORS: 2, + ROPE_CUTTER: 3, + ROPE_CUTTER_MANIAC: 4, + ULTIMATE_ROPE_CUTTER: 5, + BUBBLE_POPPER: 6, + BUBBLE_MASTER: 7, + SPIDER_BUSTER: 8, + SPIDER_TAMER: 9, + SPIDER_LOVER: 10, + WEIGHT_LOSER: 11, + CALORIE_MINIMIZER: 12, + QUICK_FINGER: 13, + MASTER_FINGER: 14, + TUMMY_TEASER: 15, + CANDY_JUGGLER: 16, + ROMANTIC_SOUL: 17, + MAGICIAN: 18 + }; + + return AchievementId; + +}); + + +define('Achievements', + [], + function () { + + var NoAchievements = { + increment: function(achievementId) { + // no-op + } + }; + + return NoAchievements; + } +); +define('GameScene', + [ + 'game/Bouncer', + 'game/Bubble', + 'game/CandyBreak', + 'game/Drawing', + 'game/FingerCut', + 'game/Grab', + 'game/Pump', + 'game/PumpDirt', + 'game/Sock', + 'game/Spikes', + 'game/Star', + 'game/TutorialText', + 'utils/MathHelper', + 'utils/Mover', + 'visual/Camera2D', + 'utils/DelayedDispatcher', + 'utils/MapItem', + 'visual/AnimationPool', + 'visual/BaseElement', + 'visual/BackgroundTileMap', + 'resources/ResourceMgr', + 'game/CTRSettings', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'utils/Constants', + 'visual/Animation', + 'visual/Timeline', + 'core/Vector', + 'core/RGBAColor', + 'visual/KeyFrame', + 'resolution', + 'utils/PubSub', + 'game/LevelState', + 'edition', + 'core/Alignment', + 'visual/TileMap', + 'physics/ConstrainedPoint', + 'visual/GameObject', + 'game/CTRGameObject', + 'visual/TextImage', + 'game/Bungee', + 'utils/Radians', + 'core/Rectangle', + 'utils/Canvas', + 'visual/ImageElement', + 'physics/ConstraintType', + 'visual/ActionType', + 'game/GravityButton', + 'physics/Gravity', + 'game/EarthImage', + 'resources/LangId', + 'resources/Lang', + 'resources/MenuStringId', + 'game/PollenDrawer', + 'utils/Log', + 'game/RotatedCircle', + 'achievements/AchievementId', + 'Achievements' + ], + function (Bouncer, Bubble, CandyBreak, Drawing, FingerCut, Grab, Pump, PumpDirt, + Sock, Spikes, Star, TutorialText, MathHelper, Mover, Camera2D, + DelayedDispatcher, MapItem, AnimationPool, BaseElement, BackgroundTileMap, + ResourceMgr, settings, SoundMgr, ResourceId, Constants, Animation, Timeline, + Vector, RGBAColor, KeyFrame, resolution, PubSub, LevelState, edition, Alignment, + TileMap, ConstrainedPoint, GameObject, CTRGameObject, TextImage, Bungee, Radians, + Rectangle, Canvas, ImageElement, ConstraintType, ActionType, GravityButton, Gravity, + EarthImage, LangId, Lang, MenuStringId, PollenDrawer, Log, RotatedCircle, + AchievementId, Achievements) { + + + /** + * Tutorial elements can have a special id specified in the level xml + * @const + * @type {number} + */ + var LEVEL1_ARROW_SPECIAL_ID = 2; + + /** + * @enum {number} + */ + var RestartState = { + FADE_IN: 0, + FADE_OUT: 1 + }; + + /** + * @enum {number} + */ + var CameraMove = { + TO_CANDY_PART: 0, + TO_CANDY: 1 + }; + + /** + * @enum {number} + */ + var ButtonMode = { + GRAVITY: 0, + SPIKES: 1 + }; + + /** + * @enum {number} + */ + var PartsType = { + SEPARATE: 0, + DISTANCE: 1, + NONE: 2 + }; + + /** + * @const + * @type {number} + */ + var SCOMBO_TIMEOUT = 0.2; + + /** + * @const + * @type {number} + */ + var SCUT_SCORE = 10; + + /** + * @const + * @type {number} + */ + var MAX_LOST_CANDIES = 3; + + /** + * @const + * @type {number} + */ + var ROPE_CUT_AT_ONCE_TIMEOUT = 0.1; + + // Candy Juggler: keep candy without ropes or bubbles for 30 secs + var CANDY_JUGGLER_TIME = 30; + + /** + * @const + * @type {number} + */ + var BLINK_SKIP = 3; + + /** + * @const + * @type {number} + */ + var MOUTH_OPEN_TIME = 1; + + /** + * @const + * @type {number} + */ + var PUMP_TIMEOUT = 0.05; + + /** + * @const + * @type {number} + */ + var SOCK_SPEED_K = 0.9; + + /** + * @const + * @type {number} + */ + var SOCK_COLLISION_Y_OFFSET = 25; + + /** + * @enum {number} + */ + var CandyBlink = { + INITIAL: 0, + STAR: 1 + }; + + /** + * @enum {number} + */ + var TutorialAnimation = { + SHOW: 0, + HIDE: 1 + }; + + /** + * @enum {number} + */ + var EarthAnimation = { + NORMAL: 0, + UPSIDE_DOWN: 1 + }; + + /** + * Animations for Om-nom character + * @enum {number} + */ + var CharAnimation = { + IDLE: 0, + IDLE2: 1, + IDLE3: 2, + EXCITED: 3, + PUZZLED: 4, + FAIL: 5, + WIN: 6, + MOUTH_OPEN: 7, + MOUTH_CLOSE: 8, + CHEW: 9, + GREETING: 10 + }; + + /** + * @const + * @type {number} + */ + var HUD_STARS_COUNT = 3; + + /** + * @const + * @type {number} + */ + var HUD_CANDIES_COUNT = 3; + + /** + * @const + * @type {number} + */ + var IMG_BGR_01_bgr = 0; + /** + * @const + * @type {number} + */ + var IMG_BGR_01_P2_vert_transition = 0; + var IMG_BGR_02_vert_transition = 1; + + var starDisappearPool = []; + var bubbleDisappear; + + + function applyStarImpulse (star, rd, yImpulse, delta) { + star.applyImpulse( + new Vector( + -star.v.x / rd, + -star.v.y / rd + yImpulse + ), + delta + ); + } + + function isCandyHit (bouncer, star, bouncer_radius) { + var bouncer_radius_double = bouncer_radius * 2; + return ( + Rectangle.lineInRect( + bouncer.t1.x, bouncer.t1.y, + bouncer.t2.x, bouncer.t2.y, + star.pos.x - bouncer_radius, star.pos.y - bouncer_radius, + bouncer_radius_double, bouncer_radius_double) || + Rectangle.lineInRect( + bouncer.b1.x, bouncer.b1.y, + bouncer.b2.x, bouncer.b2.y, + star.pos.x - bouncer_radius, star.pos.y - bouncer_radius, + bouncer_radius_double, bouncer_radius_double)); + } + + var currentPack = -1; + + var GameScene = BaseElement.extend({ + init: function () { + this._super(); + + this.dd = DelayedDispatcher; + + this.initialCameraToStarDistance = Constants.UNDEFINED; + this.restartState = Constants.UNDEFINED; + + // create animation pools + this.aniPool = new AnimationPool(); + this.aniPool.visible = false; + this.addChild(this.aniPool); + + this.staticAniPool = new AnimationPool(); + this.staticAniPool.visible = false; + this.addChild(this.staticAniPool); + + this.camera = new Camera2D(resolution.CAMERA_SPEED, Camera2D.SpeedType.DELAY); + + this.starsCollected = 0; + this.hudStars = []; + starDisappearPool = []; + + for (var i = 0; i < HUD_STARS_COUNT; i++) { + var hs = this.hudStars[i] = new Animation(); + hs.initTextureWithId(ResourceId.IMG_HUD_STAR); + hs.doRestoreCutTransparency(); + hs.addAnimationDelay(0.05, Timeline.LoopType.NO_LOOP, IMG_HUD_STAR_Frame_1, IMG_HUD_STAR_Frame_10); + hs.setPause(IMG_HUD_STAR_Frame_10 - IMG_HUD_STAR_Frame_1, 0); + //TODO: + canvas.xOffsetScaled on next line? + hs.x = 10 + (hs.width + 5) * i; + hs.y = 8; + this.addChild(hs); + } + + this.slastTouch = Vector.newZero(); + this.fingerCuts = []; + for (i = 0; i < Constants.MAX_TOUCHES; i++) { + this.fingerCuts[i] = []; + } + + this.clickToCut = settings.getClickToCut(); + + this.PM = resolution.PM; + this.PMY = resolution.PMY; + this.PMX = 0; + + this.earthAnims = []; + + this.lastCandyRotateDelta = 0; + this.lastCandyRotateDeltaL = 0; + this.lastCandyRotateDeltaR = 0; + + this.attachCount = 0; + this.juggleTimer = 0; + + this.dragging = new Array(Constants.MAX_TOUCHES); + this.startPos = new Array(Constants.MAX_TOUCHES); + this.prevStartPos = new Array(Constants.MAX_TOUCHES); + for (i = 0; i < Constants.MAX_TOUCHES; i++) { + this.dragging[i] = false; + this.startPos[i] = Vector.newZero(); + this.prevStartPos[i] = Vector.newZero(); + } + }, + /** + * @param p {ConstrainedPoint} + * @return {boolean} + */ + pointOutOfScreen: function (p) { + var bottomY = this.mapHeight + resolution.OUT_OF_SCREEN_ADJUSTMENT_BOTTOM, + topY = resolution.OUT_OF_SCREEN_ADJUSTMENT_TOP, + outOfScreen = (p.pos.y > bottomY || p.pos.y < topY); + return outOfScreen; + }, + restart: function () { + this.hide(); + this.show(); + }, + showGreeting: function () { + this.target.playTimeline(CharAnimation.GREETING); + }, + shouldSkipTutorialElement: function (element) { + var langId = settings.getLangId(), + tl = element.locale; + + if (LangId.fromString(tl) !== langId) { + return true; + } + + return false; + }, + show: function () { + starDisappearPool = []; + + //create bubble animation + bubbleDisappear = new Animation(); + bubbleDisappear.initTextureWithId(ResourceId.IMG_OBJ_BUBBLE_POP); + bubbleDisappear.doRestoreCutTransparency(); + bubbleDisappear.anchor = Alignment.CENTER; + + var a = bubbleDisappear.addAnimationDelay(0.05, Timeline.LoopType.NO_LOOP, IMG_OBJ_BUBBLE_POP_Frame_1, + IMG_OBJ_BUBBLE_POP_Frame_12); + bubbleDisappear.getTimeline(a).onFinished = this.aniPool.timelineFinishedDelegate(); + + this.aniPool.removeAllChildren(); + this.staticAniPool.removeAllChildren(); + this.dd.cancelAllDispatches(); + + this.attachCount = 0; + this.juggleTimer = 0; + + // load the background image and overlay + var bgrID = edition.levelBackgroundIds[LevelState.pack], + overlayId = edition.levelOverlayIds[LevelState.pack]; + + if (currentPack != LevelState.pack) { + this.bgTexture = ResourceMgr.getTexture(bgrID); + $("#canvasBackground").css({ + "background": "url('" + this.bgTexture.image.src + "')" + }).show(); + + currentPack = LevelState.pack; + } + + // there may not be an overlay specified if none of the box levels scroll + // this.overlayTexture = overlayId + // ? ResourceMgr.getTexture(overlayId) + // : this.bgTexture; + + // this.back = new BackgroundTileMap(1, 1); + // this.back.setRepeatHorizontally(TileMap.RepeatType.NONE); + // this.back.setRepeatVertically(TileMap.RepeatType.ALL); + // this.back.addTile(this.bgTexture, IMG_BGR_01_bgr); + // this.back.fill(0, 0, 1, 1, 0); + + this.gravityButton = null; + this.gravityTouchDown = Constants.UNDEFINED; + + this.twoParts = PartsType.NONE; + this.partsDist = 0; + + this.targetSock = null; + + SoundMgr.stopSound(ResourceId.SND_ELECTRIC); + + this.bungees = []; + this.razors = []; + this.spikes = []; + this.stars = []; + this.bubbles = []; + this.pumps = []; + this.rockets = []; + this.socks = []; + this.tutorialImages = []; + this.tutorials = []; + this.drawings = []; + this.bouncers = []; + this.rotatedCircles = []; + this.pollenDrawer = null; + + this.star = new ConstrainedPoint(); + this.star.setWeight(1); + this.starL = new ConstrainedPoint(); + this.starL.setWeight(1); + this.starR = new ConstrainedPoint(); + this.starR.setWeight(1); + + // candy + this.candy = new GameObject(); + this.candy.initTextureWithId(ResourceId.IMG_OBJ_CANDY_01); + this.candy.setTextureQuad(IMG_OBJ_CANDY_01_candy_bottom); + this.candy.doRestoreCutTransparency(); + this.candy.anchor = Alignment.CENTER; + this.candy.bb = Rectangle.copy(resolution.CANDY_BB); + this.candy.passTransformationsToChilds = false; + this.candy.scaleX = this.candy.scaleY = 0.71; + this.candy.drawPosIncrement = 0.0001; + + // candy main + this.candyMain = new GameObject(); + this.candyMain.initTextureWithId(ResourceId.IMG_OBJ_CANDY_01); + this.candyMain.setTextureQuad(IMG_OBJ_CANDY_01_candy_main); + this.candyMain.doRestoreCutTransparency(); + this.candyMain.anchor = this.candyMain.parentAnchor = Alignment.CENTER; + this.candy.addChild(this.candyMain); + this.candyMain.scaleX = this.candyMain.scaleY = 0.71; + this.candyMain.drawPosIncrement = 0.0001; + + // candy top + this.candyTop = new GameObject(); + this.candyTop.initTextureWithId(ResourceId.IMG_OBJ_CANDY_01); + this.candyTop.setTextureQuad(IMG_OBJ_CANDY_01_candy_top); + this.candyTop.doRestoreCutTransparency(); + this.candyTop.anchor = this.candyTop.parentAnchor = Alignment.CENTER; + this.candy.addChild(this.candyTop); + this.candyTop.scaleX = this.candyTop.scaleY = 0.71; + this.candyTop.drawPosIncrement = 0.0001; + + // candy blink + this.candyBlink = new Animation(); + this.candyBlink.initTextureWithId(ResourceId.IMG_OBJ_CANDY_01); + this.candyBlink.doRestoreCutTransparency(); + this.candyBlink.addAnimationEndpoints( + CandyBlink.INITIAL, + 0.07, + Timeline.LoopType.NO_LOOP, + IMG_OBJ_CANDY_01_highlight_start, + IMG_OBJ_CANDY_01_highlight_end); + this.candyBlink.addAnimationSequence( + CandyBlink.STAR, + 0.3, // delay + Timeline.LoopType.NO_LOOP, + 2, // count + [ IMG_OBJ_CANDY_01_glow, IMG_OBJ_CANDY_01_glow ]); + var gt = this.candyBlink.getTimeline(CandyBlink.STAR); + gt.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 0)); + gt.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0.2)); + this.candyBlink.visible = false; + this.candyBlink.anchor = this.candyBlink.parentAnchor = Alignment.CENTER; + this.candyBlink.scaleX = this.candyBlink.scaleY = 0.71; + this.candy.addChild(this.candyBlink); + this.candyBlink.drawPosIncrement = 0.0001; + + // candy bubble + this.candyBubbleAnimation = new Animation(); + this.candyBubbleAnimation.initTextureWithId(ResourceId.IMG_OBJ_BUBBLE_FLIGHT); + this.candyBubbleAnimation.x = this.candy.x; + this.candyBubbleAnimation.y = this.candy.y; + this.candyBubbleAnimation.parentAnchor = this.candyBubbleAnimation.anchor = Alignment.CENTER; + this.candyBubbleAnimation.addAnimationDelay(0.05, Timeline.LoopType.REPLAY, + IMG_OBJ_BUBBLE_FLIGHT_Frame_1, IMG_OBJ_BUBBLE_FLIGHT_Frame_13); + this.candyBubbleAnimation.playTimeline(0); + this.candy.addChild(this.candyBubbleAnimation); + this.candyBubbleAnimation.visible = false; + this.candyBubbleAnimation.drawPosIncrement = 0.0001; + + for (var i = 0; i < HUD_STARS_COUNT; i++) { + var hs = this.hudStars[i]; + if (hs.currentTimeline) { + hs.currentTimeline.stop(); + } + hs.setTextureQuad(IMG_HUD_STAR_Frame_1); + } + + var map = LevelState.loadedMap; + this.loadMap(map); + + // add the animations for the bubbles + if (this.twoParts !== PartsType.NONE) { + this.candyBubbleAnimationL = new Animation(); + this.candyBubbleAnimationL.initTextureWithId(ResourceId.IMG_OBJ_BUBBLE_FLIGHT); + this.candyBubbleAnimationL.parentAnchor = this.candyBubbleAnimationL.anchor = Alignment.CENTER; + this.candyBubbleAnimationL.addAnimationDelay(0.05, Timeline.LoopType.REPLAY, + IMG_OBJ_BUBBLE_FLIGHT_Frame_1, IMG_OBJ_BUBBLE_FLIGHT_Frame_13); + this.candyBubbleAnimationL.playTimeline(0); + this.candyL.addChild(this.candyBubbleAnimationL); + this.candyBubbleAnimationL.visible = false; + this.candyBubbleAnimationL.drawPosIncrement = 0.0001; + + this.candyBubbleAnimationR = new Animation(); + this.candyBubbleAnimationR.initTextureWithId(ResourceId.IMG_OBJ_BUBBLE_FLIGHT); + this.candyBubbleAnimationR.parentAnchor = this.candyBubbleAnimationR.anchor = Alignment.CENTER; + this.candyBubbleAnimationR.addAnimationDelay(0.05, Timeline.LoopType.REPLAY, + IMG_OBJ_BUBBLE_FLIGHT_Frame_1, IMG_OBJ_BUBBLE_FLIGHT_Frame_13); + this.candyBubbleAnimationR.playTimeline(0); + this.candyR.addChild(this.candyBubbleAnimationR); + this.candyBubbleAnimationR.visible = false; + this.candyBubbleAnimationR.drawPosIncrement = 0.0001; + } + + var len = this.rotatedCircles.length, r; + for (i = 0; i < len; i++) { + r = this.rotatedCircles[i]; + r.operating = Constants.UNDEFINED; + r.circles = this.rotatedCircles; + } + + this.startCamera(); + + this.tummyTeasers = 0; + + this.starsCollected = 0; + this.candyBubble = null; + this.candyBubbleL = null; + this.candyBubbleR = null; + + this.mouthOpen = false; + this.noCandy = (this.twoParts !== PartsType.NONE); + this.noCandyL = false; + this.noCandyR = false; + this.blink.playTimeline(0); + this.spiderTookCandy = false; + this.time = 0; + this.score = 0; + + this.gravityNormal = true; + Gravity.reset(); + + this.dimTime = 0; + + this.ropesCutAtOnce = 0; + this.ropesAtOnceTimer = 0; + + // delay start candy blink + this.dd.callObject(this, this.doCandyBlink, null, 1); + + var levelLabel = new TextImage(), + levelText = (LevelState.pack + 1) + ' - ' + (LevelState.level + 1); + levelLabel.setText(ResourceId.FNT_BIG_FONT, levelText); + levelLabel.anchor = Alignment.BOTTOM | Alignment.LEFT; + levelLabel.x = 37 * resolution.CANVAS_SCALE; + levelLabel.y = resolution.CANVAS_HEIGHT - (5 * resolution.CANVAS_SCALE); + + var levelLabelTitle = new TextImage(); + levelLabelTitle.setText(ResourceId.FNT_BIG_FONT, Lang.menuText(MenuStringId.LEVEL)); + levelLabelTitle.anchor = Alignment.BOTTOM | Alignment.LEFT; + levelLabelTitle.parentAnchor = Alignment.TOP | Alignment.LEFT; + levelLabelTitle.y = 60 * resolution.CANVAS_SCALE; + levelLabelTitle.rotationCenterX -= levelLabelTitle.width / 2; + levelLabelTitle.scaleX = levelLabelTitle.scaleY = 0.7; + levelLabel.addChild(levelLabelTitle); + + var tl = new Timeline(); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0.5)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 0.5)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 1)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0.5)); + levelLabel.addTimelineWithID(tl, 0); + levelLabel.playTimeline(0); + tl.onFinished = this.staticAniPool.timelineFinishedDelegate(); + this.staticAniPool.addChild(levelLabel); + + if (this.clickToCut) { + this.resetBungeeHighlight(); + } + }, + startCamera: function () { + var SCREEN_WIDTH = resolution.CANVAS_WIDTH, + SCREEN_HEIGHT = resolution.CANVAS_HEIGHT; + + if (this.mapWidth > SCREEN_WIDTH || this.mapHeight > SCREEN_HEIGHT) { + this.ignoreTouches = true; + this.fastenCamera = false; + this.camera.type = Camera2D.SpeedType.PIXELS; + this.camera.speed = 10; + this.cameraMoveMode = CameraMove.TO_CANDY_PART; + + var startX, startY, + cameraTarget = (this.twoParts !== PartsType.NONE) ? this.starL : this.star; + + if (this.mapWidth > SCREEN_WIDTH) { + if (cameraTarget.pos.x > this.mapWidth / 2) { + startX = 0; + startY = 0; + } + else { + startX = this.mapWidth - SCREEN_WIDTH; + startY = 0; + } + } + else { + if (cameraTarget.pos.y > this.mapHeight / 2) { + startX = 0; + startY = 0; + } + else { + startX = 0; + startY = this.mapHeight - SCREEN_HEIGHT; + } + } + + var xScroll = cameraTarget.pos.x - SCREEN_WIDTH / 2, + yScroll = cameraTarget.pos.y - SCREEN_HEIGHT / 2, + targetX = MathHelper.fitToBoundaries(xScroll, 0, this.mapWidth - SCREEN_WIDTH), + targetY = MathHelper.fitToBoundaries(yScroll, 0, this.mapHeight - SCREEN_HEIGHT); + + this.camera.moveTo(startX, startY, true); + + this.initialCameraToStarDistance = this.camera.pos.distance(new Vector(targetX, targetY)); + } + else { + this.ignoreTouches = false; + this.camera.moveTo(0, 0, true); + } + }, + doCandyBlink: function () { + this.candyBlink.playTimeline(CandyBlink.INITIAL); + }, + + /** + * Loads the map object + * @param map {Object} + */ + loadMap: function (map) { + var layers = [], + self = this; + + // get all the layers for this map + for (var layerName in map) { + if (map.hasOwnProperty(layerName)) { + layers.push(map[layerName]); + } + } + + // var enumLayerChildren = function (layers, childCallback) { + // for (var i = 0, numLayers = layers.length; i < numLayers; i++) { + // // parse the children + // var children = layers[i], + // numChildren = children.length; + // for (var j = 0; j < numChildren; j++) { + // //console.log("CALLBAC", i, j) + // childCallback.call(self, children[j]); + // } + // } + // }; + + // first pass handles basic settings and candy + for (var i = 0, numLayers = layers.length; i < numLayers; i++) { + // parse the children + var children = layers[i], + numChildren = children.length; + for (var j = 0; j < numChildren; j++) { + var child = children[j]; + switch (child.name) { + case MapItem.MAP: + this.loadMapSettings(child); + break; + case MapItem.GAME_DESIGN: + this.loadGameDesign(child); + break; + case MapItem.CANDY_L: + this.loadCandyL(child); + break; + case MapItem.CANDY_R: + this.loadCandyR(child); + break; + case MapItem.CANDY: + this.loadCandy(child); + break; + } + } + } + + // second pass handles the rest of the game elements + for (var i = 0, numLayers = layers.length; i < numLayers; i++) { + // parse the children + var children = layers[i], + numChildren = children.length; + for (var j = 0; j < numChildren; j++) { + var child = children[j]; + switch (child.name) { + case MapItem.GRAVITY_SWITCH: + this.loadGravitySwitch(child); + break; + case MapItem.STAR: + this.loadStar(child); + break; + case MapItem.TUTORIAL_TEXT: + this.loadTutorialText(child); + break; + case MapItem.TUTORIAL_01: + case MapItem.TUTORIAL_02: + case MapItem.TUTORIAL_03: + case MapItem.TUTORIAL_04: + case MapItem.TUTORIAL_05: + case MapItem.TUTORIAL_06: + case MapItem.TUTORIAL_07: + case MapItem.TUTORIAL_08: + case MapItem.TUTORIAL_09: + case MapItem.TUTORIAL_10: + case MapItem.TUTORIAL_11: + case MapItem.TUTORIAL_12: + case MapItem.TUTORIAL_13: + case MapItem.TUTORIAL_14: + this.loadTutorialImage(child); + break; + case MapItem.BUBBLE: + this.loadBubble(child); + break; + case MapItem.PUMP: + this.loadPump(child); + break; + case MapItem.SOCK: + this.loadSock(child); + break; + case MapItem.SPIKE_1: + case MapItem.SPIKE_2: + case MapItem.SPIKE_3: + case MapItem.SPIKE_4: + case MapItem.ELECTRO: + this.loadSpike(child); + break; + case MapItem.ROTATED_CIRCLE: + this.loadRotatedCircle(child); + break; + case MapItem.BOUNCER1: + case MapItem.BOUNCER2: + this.loadBouncer(child); + break; + case MapItem.GRAB: + this.loadGrab(child); + break; + case MapItem.TARGET: + this.loadTarget(child); + break; + case MapItem.HIDDEN_01: + case MapItem.HIDDEN_02: + case MapItem.HIDDEN_03: + this.loadHidden(child); + break; + } + } + }; + }, + /** + * Loads the map settings for the map node (inside settings layer) + * @param item + */ + loadMapSettings: function (item) { + this.mapWidth = item.width; + this.mapHeight = item.height; + this.PMX = (resolution.CANVAS_WIDTH - (this.mapWidth * this.PM)) / 2; + this.mapWidth *= this.PM; + this.mapHeight *= this.PM; + + if (edition.showEarth[LevelState.pack]) { + if (this.mapWidth > resolution.CANVAS_WIDTH) { + this.earthAnims.push(new EarthImage(resolution.CANVAS_WIDTH, 0)); + } + if (this.mapHeight > resolution.CANVAS_HEIGHT) { + this.earthAnims.push(new EarthImage(0, resolution.CANVAS_HEIGHT)); + } + this.earthAnims.push(new EarthImage(0, 0)); + } + }, + loadGameDesign: function (item) { + this.special = item.special || 0; + this.ropePhysicsSpeed = item.ropePhysicsSpeed; + this.nightLevel = item.nightLevel; + this.twoParts = item.twoParts ? PartsType.SEPARATE : PartsType.NONE; + this.ropePhysicsSpeed *= resolution.PHYSICS_SPEED_MULTIPLIER; + }, + loadGrab: function (item) { + var gx = item.x * this.PM + this.PMX, + gy = item.y * this.PM + this.PMY, + l = item.length * this.PM, + r = item.radius, + wheel = item.wheel, + kickable = item.kickable, + invisible = item.invisible, + ml = item.moveLength * this.PM || -1, + v = item.moveVertical, + o = item.moveOffset * this.PM || 0, + spider = item.spider, + left = (item.part === "L"), + hidePath = item.hidePath, + gun = item.gun, + g = new Grab(); + + g.x = gx; + g.y = gy; + g.wheel = wheel; + g.gun = gun; + g.kickable = kickable; + g.invisible = invisible; + g.setSpider(spider); + g.parseMover(item); + + if (g.mover) { + g.setBee(); + + if (!hidePath) { + var d = 3, + isCircle = (item.path[0] === 'R'); + + // create pollen drawer if needed + if (!this.pollenDrawer) { + this.pollenDrawer = new PollenDrawer(); + } + + for (var i = 0, len = g.mover.path.length - 1; i < len; i++) { + if (!isCircle || i % d === 0) { + this.pollenDrawer.fillWithPollenFromPath(i, i + 1, g); + } + } + + if (g.mover.path.length > 2) { + this.pollenDrawer.fillWithPollenFromPath(0, g.mover.path.length - 1, g); + } + + } + } + + if (r !== Constants.UNDEFINED) + r *= this.PM; + + if (r === Constants.UNDEFINED && !gun) { + var tail = this.star; + if (this.twoParts !== PartsType.NONE) { + tail = left ? this.starL : this.starR; + } + + var b = new Bungee(null, gx, gy, tail, tail.pos.x, tail.pos.y, l); + b.bungeeAnchor.pin.copyFrom(b.bungeeAnchor.pos); + g.setRope(b); + this.attachCandy(); + } + + g.setRadius(r); + g.setMoveLength(ml, v, o); + + this.bungees.push(g); + }, + loadCandyL: function (item) { + this.starL.pos.x = item.x * this.PM + this.PMX; + this.starL.pos.y = item.y * this.PM + this.PMY; + + this.candyL = new GameObject(); + this.candyL.initTextureWithId(ResourceId.IMG_OBJ_CANDY_01); + this.candyL.setTextureQuad(IMG_OBJ_CANDY_01_part_1); + this.candyL.scaleX = this.candyL.scaleY = 0.71; + this.candyL.passTransformationsToChilds = false; + this.candyL.doRestoreCutTransparency(); + this.candyL.anchor = Alignment.CENTER; + this.candyL.x = this.starL.pos.x; + this.candyL.y = this.starL.pos.y; + this.candyL.bb = Rectangle.copy(resolution.CANDY_LR_BB); + }, + loadCandyR: function (item) { + this.starR.pos.x = item.x * this.PM + this.PMX; + this.starR.pos.y = item.y * this.PM + this.PMY; + + this.candyR = new GameObject(); + this.candyR.initTextureWithId(ResourceId.IMG_OBJ_CANDY_01); + this.candyR.setTextureQuad(IMG_OBJ_CANDY_01_part_2); + this.candyR.scaleX = this.candyR.scaleY = 0.71; + this.candyR.passTransformationsToChilds = false; + this.candyR.doRestoreCutTransparency(); + this.candyR.anchor = Alignment.CENTER; + this.candyR.x = this.starR.pos.x; + this.candyR.y = this.starR.pos.y; + this.candyR.bb = Rectangle.copy(resolution.CANDY_LR_BB); + }, + loadCandy: function (item) { + this.star.pos.x = item.x * this.PM + this.PMX; + this.star.pos.y = item.y * this.PM + this.PMY; + }, + loadGravitySwitch: function (item) { + this.gravityButton = new GravityButton(); + this.gravityButton.onButtonPressed = $.proxy(this.onButtonPressed, this); + this.gravityButton.visible = false; + this.gravityButton.touchable = false; + this.addChild(this.gravityButton); + this.gravityButton.x = item.x * this.PM + this.PMX; + this.gravityButton.y = item.y * this.PM + this.PMY; + this.gravityButton.anchor = Alignment.CENTER; + }, + loadStar: function (item) { + var s = new Star(); + s.initTextureWithId(ResourceId.IMG_OBJ_STAR_IDLE); + s.x = item.x * this.PM + this.PMX; + s.y = item.y * this.PM + this.PMY; + s.timeout = item.timeout; + s.createAnimations(); + + s.bb = Rectangle.copy(resolution.STAR_BB); + s.parseMover(item); + + // let stars move the starting position of mover + s.update(0); + + var l = this.stars.push(s); + + //init the star disappear animations + var sd = starDisappearPool[l - 1] = new Animation(); + sd.initTextureWithId(ResourceId.IMG_OBJ_STAR_DISAPPEAR); + sd.doRestoreCutTransparency(); + sd.anchor = Alignment.CENTER; + + sd.addAnimationDelay(0.05, Timeline.LoopType.NO_LOOP, IMG_OBJ_STAR_DISAPPEAR_Frame_1, + IMG_OBJ_STAR_DISAPPEAR_Frame_13); + }, + loadTutorialText: function (item) { + if (this.shouldSkipTutorialElement(item)) { + return; + } + + if (item.text == null || item.text === '') { + Log.debug('Missing tutorial text'); + return; + } + + var t = new TutorialText(); + t.x = item.x * this.PM + this.PMX; + t.y = item.y * this.PM + this.PMY; + t.special = item.special || 0; + t.align = Alignment.HCENTER; + //t.scaleX = 1.3; + //t.scaleY = 1.3; + + var text = item.text, + textWidth = Math.ceil(item.width * this.PM); + t.setText(ResourceId.FNT_SMALL_FONT, text, textWidth, Alignment.HCENTER); + t.color = RGBAColor.transparent.copy(); + + var tl = new Timeline(), + isFirstLevel = (LevelState.pack === 0 && LevelState.level === 0); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 1)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, + isFirstLevel ? 10 : 5)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, .5)); + t.addTimelineWithID(tl, 0); + + if (t.special === 0) { + t.playTimeline(0); + } + + this.tutorials.push(t); + }, + loadTutorialImage: function (item) { + if (this.shouldSkipTutorialElement(item)) { + return; + } + + var v = item.name - MapItem.TUTORIAL_01, // gets the tutorial number + s = new CTRGameObject(); + + s.initTextureWithId(ResourceId.IMG_TUTORIAL_SIGNS); + s.setTextureQuad(v); + s.color = RGBAColor.transparent.copy(); + s.x = item.x * this.PM + this.PMX; + s.y = item.y * this.PM + this.PMY; + s.rotation = item.angle || 0; + s.special = item.special || 0; + s.parseMover(item); + + var tl = new Timeline(); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 1)); + + if (LevelState.pack === 0 && LevelState.level === 0) { + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, + 10)); + } + else { + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, + 5.2)); + } + + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0.5)); + s.addTimelineWithID(tl, 0); + + if (s.special === 0) { + s.playTimeline(0); + } + else if (s.special === LEVEL1_ARROW_SPECIAL_ID) { + var tl2 = new Timeline(); + tl2.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, + 0)); + tl2.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, + 0.5)); + tl2.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, + 1)); + tl2.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, + 1.1)); + tl2.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, + 0.5)); + + tl2.addKeyFrame(KeyFrame.makePos(s.x, s.y, KeyFrame.TransitionType.LINEAR, 0)); + tl2.addKeyFrame(KeyFrame.makePos(s.x, s.y, KeyFrame.TransitionType.LINEAR, 0.5)); + tl2.addKeyFrame(KeyFrame.makePos(s.x, s.y, KeyFrame.TransitionType.LINEAR, 1)); + tl2.addKeyFrame(KeyFrame.makePos(s.x + resolution.TUTORIAL_HAND_TARGET_X_1, s.y, + KeyFrame.TransitionType.LINEAR, 0.5)); + tl2.addKeyFrame(KeyFrame.makePos(s.x + resolution.TUTORIAL_HAND_TARGET_X_2, s.y, + KeyFrame.TransitionType.LINEAR, 0.5)); + + tl2.loopsLimit = 2; + tl2.loopType = Timeline.LoopType.REPLAY; + + s.addTimelineWithID(tl2, 1); + s.playTimeline(1); + } + + this.tutorialImages.push(s); + }, + loadHidden: function (item) { + // get the hidden image index + var v = item.name - MapItem.HIDDEN_01, + drawingId = item.drawing - 1; + + var alreadyUnlocked = false; + if (!alreadyUnlocked && !edition.disableHiddenDrawings) { + var s = new Drawing(v, drawingId); + s.x = item.x * this.PM + this.PMX; + s.y = item.y * this.PM + this.PMY; + s.rotation = item.angle || 0; + this.drawings.push(s); + } + }, + loadBubble: function (item) { + var at = MathHelper.randomRange( + IMG_OBJ_BUBBLE_ATTACHED_stain_01, IMG_OBJ_BUBBLE_ATTACHED_stain_03), + s = new Bubble(); + s.initTextureWithId(ResourceId.IMG_OBJ_BUBBLE_ATTACHED); + s.setTextureQuad(at); + s.doRestoreCutTransparency(); + + s.bb = Rectangle.copy(resolution.BUBBLE_BB); + s.x = item.x * this.PM + this.PMX; + s.y = item.y * this.PM + this.PMY; + s.anchor = Alignment.CENTER; + s.popped = false; + + var bubble = new ImageElement(); + bubble.initTextureWithId(ResourceId.IMG_OBJ_BUBBLE_ATTACHED); + bubble.setTextureQuad(IMG_OBJ_BUBBLE_ATTACHED_bubble); + bubble.doRestoreCutTransparency(); + bubble.parentAnchor = bubble.anchor = Alignment.CENTER; + s.addChild(bubble); + this.bubbles.push(s); + + + }, + loadPump: function (item) { + var s = new Pump(); + s.initTextureWithId(ResourceId.IMG_OBJ_PUMP); + s.doRestoreCutTransparency(); + s.addAnimationWithDelay(0.05, Timeline.LoopType.NO_LOOP, 4, [1, 2, 3, 0]); + + s.bb = Rectangle.copy(resolution.PUMP_BB); + s.x = item.x * this.PM + this.PMX; + s.y = item.y * this.PM + this.PMY; + s.rotation = item.angle + 90; + s.updateRotation(); + s.anchor = Alignment.CENTER; + this.pumps.push(s); + }, + loadSock: function (item) { + var s = new Sock(); + s.initTextureWithId(ResourceId.IMG_OBJ_SOCKS); + s.scaleX = s.scaleY = 0.7; + s.createAnimations(); + s.doRestoreCutTransparency(); + + s.x = item.x * this.PM + this.PMX; + s.y = item.y * this.PM + this.PMY; + s.group = item.group; + + s.anchor = Alignment.TOP | Alignment.HCENTER; + s.rotationCenterY -= s.height / 2 - SOCK_COLLISION_Y_OFFSET; + + s.setTextureQuad((s.group === 0) + ? Sock.Quads.IMG_OBJ_SOCKS_hat_01 + : Sock.Quads.IMG_OBJ_SOCKS_hat_02); + + s.state = Sock.StateType.IDLE; + s.parseMover(item); + s.rotation += 90; + if (s.mover) { + s.mover.angle += 90; + } + + s.updateRotation(); + this.socks.push(s); + }, + loadSpike: function (item) { + var px = item.x * this.PM + this.PMX, + py = item.y * this.PM + this.PMY, + w = item.size, + a = parseFloat(item.angle) || 0, + tg = (item.toggled === false) + ? Constants.UNDEFINED + : item.toggled || Constants.UNDEFINED, + s = new Spikes(px, py, w, a, tg); + s.parseMover(item); + + if (tg) { + s.onRotateButtonPressed = $.proxy(this.rotateAllSpikesWithId, this); + } + + if (item.name === MapItem.ELECTRO) { + s.electro = true; + s.initialDelay = item.initialDelay; + s.onTime = item.onTime; + s.offTime = item.offTime; + s.electroTimer = 0; + + s.turnElectroOff(); + s.electroTimer += s.initialDelay; + s.updateRotation(); + } + else { + s.electro = false; + } + this.spikes.push(s); + }, + loadRotatedCircle: function (item) { + var px = item.x * this.PM + this.PMX, + py = item.y * this.PM + this.PMY, + size = item.size, + handleAngle = parseFloat(item.handleAngle) || 0, + handleRadians = Radians.fromDegrees(handleAngle), + oneHandle = item.oneHandle, + l = new RotatedCircle(); + + l.anchor = Alignment.CENTER; + l.x = px; + l.y = py; + l.rotation = handleAngle; + l.handle1 = new Vector(l.x - size * this.PM, l.y); + l.handle2 = new Vector(l.x + size * this.PM, l.y); + + l.handle1.rotateAround(handleRadians, l.x, l.y); + l.handle2.rotateAround(handleRadians, l.x, l.y); + + l.setSize(size); + l.setHasOneHandle(oneHandle); + + this.rotatedCircles.push(l); + }, + loadBouncer: function (item) { + var px = item.x * this.PM + this.PMX, + py = item.y * this.PM + this.PMY, + w = item.size, + a = item.angle, + bouncer = new Bouncer(px, py, w, a); + bouncer.parseMover(item); + this.bouncers.push(bouncer); + }, + loadTarget: function (item) { + var target = new GameObject(); + this.target = target; + + target.initTextureWithId(ResourceId.IMG_CHAR_ANIMATIONS); + target.doRestoreCutTransparency(); + + target.bb = Rectangle.copy(resolution.TARGET_BB); + target.drawPosIncrement = 0.0001; + + target.addAnimationEndpoints(CharAnimation.GREETING, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_greeting_start, IMG_CHAR_ANIMATIONS_greeting_end); + target.addAnimationEndpoints(CharAnimation.IDLE, 0.05, Timeline.LoopType.REPLAY, + IMG_CHAR_ANIMATIONS_idle_start, IMG_CHAR_ANIMATIONS_idle_end); + target.addAnimationEndpoints(CharAnimation.IDLE2, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_idle2_start, IMG_CHAR_ANIMATIONS_idle2_end); + target.addAnimationSequence(CharAnimation.IDLE3, 0.05, Timeline.LoopType.NO_LOOP, + (IMG_CHAR_ANIMATIONS_idle3_end - IMG_CHAR_ANIMATIONS_idle3_start + 1) * 2, + [ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124 ]); + target.addAnimationEndpoints(CharAnimation.EXCITED, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_excited_start, IMG_CHAR_ANIMATIONS_excited_end); + target.addAnimationEndpoints(CharAnimation.PUZZLED, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_puzzled_start, IMG_CHAR_ANIMATIONS_puzzled_end); + target.addAnimationEndpoints(CharAnimation.FAIL, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_fail_start, IMG_CHAR_ANIMATIONS_fail_end); + target.addAnimationEndpoints(CharAnimation.WIN, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_mouth_close_start, IMG_CHAR_ANIMATIONS_mouth_close_end); + target.addAnimationEndpoints(CharAnimation.MOUTH_OPEN, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_mouth_open_start, IMG_CHAR_ANIMATIONS_mouth_open_end); + target.addAnimationEndpoints(CharAnimation.MOUTH_CLOSE, 0.05, Timeline.LoopType.NO_LOOP, + IMG_CHAR_ANIMATIONS_mouth_close_start, IMG_CHAR_ANIMATIONS_mouth_close_end); + target.addAnimationEndpoints(CharAnimation.CHEW, 0.05, Timeline.LoopType.REPLAY, + IMG_CHAR_ANIMATIONS_chew_start, IMG_CHAR_ANIMATIONS_chew_end); + target.switchToAnimation(CharAnimation.CHEW, CharAnimation.WIN, 0.05); + target.switchToAnimation(CharAnimation.PUZZLED, CharAnimation.MOUTH_CLOSE, 0.05); + target.switchToAnimation(CharAnimation.IDLE, CharAnimation.GREETING, 0.05); + target.switchToAnimation(CharAnimation.IDLE, CharAnimation.IDLE2, 0.05); + target.switchToAnimation(CharAnimation.IDLE, CharAnimation.IDLE3, 0.05); + target.switchToAnimation(CharAnimation.IDLE, CharAnimation.EXCITED, 0.05); + target.switchToAnimation(CharAnimation.IDLE, CharAnimation.PUZZLED, 0.05); + + // delay greeting by Om-nom + if (settings.showGreeting) { + this.dd.callObject(this, this.showGreeting, null, 2); + settings.showGreeting = false; + } + + target.playTimeline(CharAnimation.IDLE); + + var idle = target.getTimeline(CharAnimation.IDLE); + idle.onKeyFrame = $.proxy(this.onIdleOmNomKeyFrame, this); + + target.setPause( + (IMG_CHAR_ANIMATIONS_mouth_open_end - IMG_CHAR_ANIMATIONS_mouth_open_start), + CharAnimation.MOUTH_OPEN); + this.blink = new Animation(); + this.blink.initTextureWithId(ResourceId.IMG_CHAR_ANIMATIONS); + this.blink.parentAnchor = Alignment.TOP | Alignment.LEFT; + + this.blink.visible = false; + this.blink.addAnimationSequence(0, 0.05, Timeline.LoopType.NO_LOOP, 4, + [ IMG_CHAR_ANIMATIONS_blink_start, IMG_CHAR_ANIMATIONS_blink_end, IMG_CHAR_ANIMATIONS_blink_end, IMG_CHAR_ANIMATIONS_blink_end ]); + this.blink.setAction(ActionType.SET_VISIBLE, this.blink, 0, 0, 2, 0); + this.blinkTimer = BLINK_SKIP; + + this.blink.doRestoreCutTransparency(); + target.addChild(this.blink); + + var supportQuadID = edition.supports[LevelState.pack]; + this.support = ImageElement.create(ResourceId.IMG_CHAR_SUPPORTS, supportQuadID); + this.support.doRestoreCutTransparency(); + this.support.anchor = Alignment.CENTER; + + var sx = item.x, + sy = item.y; + + this.target.x = this.support.x = sx * this.PM + this.PMX | 0; + this.target.y = this.support.y = sy * this.PM + this.PMY | 0; + + this.idlesTimer = MathHelper.randomRange(5, 20); + }, + onIdleOmNomKeyFrame: function (timeline, keyFrame, index) { + + if (index === 1) { + + // om-nom blink + this.blinkTimer--; + if (this.blinkTimer === 0) { + this.blink.visible = true; + this.blink.playTimeline(0); + this.blinkTimer = BLINK_SKIP; + } + + // om-nom idle action + this.idlesTimer--; + if (this.idlesTimer === 0) { + if (MathHelper.randomRange(0, 1) === 1) { + this.target.playTimeline(CharAnimation.IDLE2); + } + else { + this.target.playTimeline(CharAnimation.IDLE3); + } + this.idlesTimer = MathHelper.randomRange(5, 20); + } + } + }, + onRotatedCircleTimelineFinished: function (t) { + var circleToRemove = t.element; + circleToRemove.removeOnNextUpdate = true; + }, + update: function (delta) { + var i, len, moveResult; + for (i = 0, len = this.drawings.length; i < len; i++) { + this.drawings[i].update(delta); + } + + this._super(delta); + this.dd.update(delta); + + if (this.pollenDrawer) { + this.pollenDrawer.update(delta); + } + + for (i = 0; i < Constants.MAX_TOUCHES; i++) { + var cuts = this.fingerCuts[i], + numCuts = cuts.length, + k = 0; + + while (k < numCuts) { + var fc = cuts[k]; + moveResult = Mover.moveToTargetWithStatus(fc.color.a, 0, 10, delta); + fc.color.a = moveResult.value; + if (moveResult.reachedZero) { + cuts.splice(k, 1); + numCuts--; + } + else { + k++; + } + } + } + + for (i = 0, len = this.earthAnims.length; i < len; i++) { + this.earthAnims[i].update(delta); + } + + this.ropesAtOnceTimer = Mover.moveToTarget(this.ropesAtOnceTimer, 0, 1, delta); + + if (this.attachCount === 0) { + this.juggleTimer += delta; + + // has it been 30 secs since the candy was attached? + if (this.juggleTimer > CANDY_JUGGLER_TIME) { + + //Achievements.increment(AchievementId.CANDY_JUGGLER); + + // reset the timer + this.juggleTimer = 0; + } + } + + var SCREEN_WIDTH = resolution.CANVAS_WIDTH, + SCREEN_HEIGHT = resolution.CANVAS_HEIGHT, + cameraTarget = (this.twoParts != PartsType.NONE) ? this.starL : this.star, + xScroll = cameraTarget.pos.x - SCREEN_WIDTH / 2, + yScroll = cameraTarget.pos.y - SCREEN_HEIGHT / 2, + targetX = MathHelper.fitToBoundaries(xScroll, 0, this.mapWidth - SCREEN_WIDTH), + targetY = MathHelper.fitToBoundaries(yScroll, 0, this.mapHeight - SCREEN_HEIGHT); + + this.camera.moveTo(targetX, targetY, false); + + // NOTE: mac sources indicate this is temporary? + if (!(this.freezeCamera && this.camera.type === Camera2D.SpeedType.DELAY)) { + this.camera.update(delta); + } + + if (this.camera.type === Camera2D.SpeedType.PIXELS) { + var IGNORE_TOUCHES_DISTANCE = resolution.IGNORE_TOUCHES_DISTANCE, + PREVIEW_CAMERA_SPEED = resolution.PREVIEW_CAMERA_SPEED, + PREVIEW_CAMERA_SPEED2 = resolution.PREVIEW_CAMERA_SPEED2, + MAX_PREVIEW_CAMERA_SPEED = resolution.MAX_PREVIEW_CAMERA_SPEED, + MIN_PREVIEW_CAMERA_SPEED = resolution.MIN_PREVIEW_CAMERA_SPEED; + + var starDistance = this.camera.pos.distance(new Vector(targetX, targetY)); + if (starDistance < IGNORE_TOUCHES_DISTANCE) { + this.ignoreTouches = false; + } + + if (this.fastenCamera) { + if (this.camera.speed < resolution.CAMERA_SPEED_THRESHOLD) { + this.camera.speed *= 1.5; + } + } + else { + if (starDistance > this.initialCameraToStarDistance / 2.0) { + this.camera.speed += delta * PREVIEW_CAMERA_SPEED; + this.camera.speed = Math.min(MAX_PREVIEW_CAMERA_SPEED, this.camera.speed); + } + else { + this.camera.speed -= delta * PREVIEW_CAMERA_SPEED2; + this.camera.speed = Math.max(MIN_PREVIEW_CAMERA_SPEED, this.camera.speed); + } + } + + if (Math.abs(this.camera.pos.x - targetX) < 1 && + Math.abs(this.camera.pos.y - targetY) < 1) { + this.camera.type = Camera2D.SpeedType.DELAY; + this.camera.speed = resolution.CAMERA_SPEED; + } + } + else { + this.time += delta; + } + + var numGrabs = this.bungees.length; + if (numGrabs > 0) { + var handledRotation = false, + handledRotationL = false, + handledRotationR = false; + + for (i = 0; i < numGrabs; i++) { + // yes, its a little confusing that the bungees array + // actually holds grabs + var g = this.bungees[i]; + g.update(delta); + + var b = g.rope; + + if (g.mover) { + if (b) { + b.bungeeAnchor.pos.x = g.x; + b.bungeeAnchor.pos.y = g.y; + b.bungeeAnchor.pin.copyFrom(b.bungeeAnchor.pos); + } + } + + if (b) { + if (b.cut !== Constants.UNDEFINED && b.cutTime === 0) { + g.destroyRope(); + continue; + } + + b.update(delta * this.ropePhysicsSpeed); + + if (g.hasSpider) { + if (this.camera.type != Camera2D.SpeedType.PIXELS || !this.ignoreTouches) { + g.updateSpider(delta); + } + + if (g.spiderPos === Constants.UNDEFINED) { + this.spiderWon(g); + break; + } + } + } + + if (g.radius !== Constants.UNDEFINED && !g.rope) { + // shared code for creating a rope with a star + var STAR_RADIUS = resolution.STAR_RADIUS, + createRope = $.proxy(function (star) { + var l = new Vector(g.x, g.y).distance(star.pos); + if (l <= g.radius + STAR_RADIUS) { + var b = new Bungee( + null, g.x, g.y, // head + star, star.pos.x, star.pos.y, // tail + g.radius + STAR_RADIUS); + b.bungeeAnchor.pin.copyFrom(b.bungeeAnchor.pos); + g.hideRadius = true; + g.setRope(b); + + this.attachCandy(); + + SoundMgr.playSound(ResourceId.SND_ROPE_GET); + if (g.mover) { + SoundMgr.playSound(ResourceId.SND_BUZZ); + } + } + }, this); + + if (this.twoParts !== PartsType.NONE) { + if (!this.noCandyL) { + createRope(this.starL); + } + if (!this.noCandyR && g.rope == null) { + createRope(this.starR) + } + } + else { + createRope(this.star); + } + } + + if (b) { + var prev = b.bungeeAnchor, + tail = b.parts[b.parts.length - 1], + v = Vector.subtract(prev.pos, tail.pos), + hasCandy = false; + + if (!handledRotation) { + if (this.twoParts !== PartsType.NONE) { + if (tail === this.starL && !this.noCandyL && !handledRotationL) { + hasCandy = true; + } + else if (tail === this.starR && !this.noCandyR && !handledRotationR) { + hasCandy = true; + } + } + else if (!this.noCandy && !handledRotation) { + hasCandy = true; + } + } + + if (b.relaxed !== 0 && b.cut === Constants.UNDEFINED && hasCandy) { + var a = Radians.toDegrees(v.normalizedAngle()); + if (this.twoParts !== PartsType.NONE) { + var candyPart = (tail === this.starL) ? this.candyL : this.candyR; + if (!b.chosenOne) { + b.initialCandleAngle = candyPart.rotation - a; + } + + if (tail === this.starL) { + this.lastCandyRotateDeltaL = a + b.initialCandleAngle - candyPart.rotation; + handledRotationL = true; + } + else { + this.lastCandyRotateDeltaR = a + b.initialCandleAngle - candyPart.rotation; + handledRotationR = true; + } + candyPart.rotation = a + b.initialCandleAngle; + } + else { + if (!b.chosenOne) { + b.initialCandleAngle = this.candyMain.rotation - a; + } + this.lastCandyRotateDelta = a + b.initialCandleAngle - this.candyMain.rotation; + this.candyMain.rotation = a + b.initialCandleAngle; + handledRotation = true; + } + + b.chosenOne = true; + } + else { + b.chosenOne = false; + } + } + } + + if (this.twoParts !== PartsType.NONE) { + if (!handledRotationL && !this.noCandyL) { + this.candyL.rotation += Math.min(5, this.lastCandyRotateDeltaL); + this.lastCandyRotateDeltaL *= 0.98; + } + if (!handledRotationR && !this.noCandyR) { + this.candyR.rotation += Math.min(5, this.lastCandyRotateDeltaR); + this.lastCandyRotateDeltaR *= 0.98; + } + } + else { + if (!handledRotation && !this.noCandy) { + this.candyMain.rotation += Math.min(5, this.lastCandyRotateDelta); + this.lastCandyRotateDelta *= 0.98; + } + } + } + + if (!this.noCandy) { + this.candy.update(delta); + this.star.update(delta * this.ropePhysicsSpeed); + } + + if (this.twoParts !== PartsType.NONE) { + var ropeDelta = delta * this.ropePhysicsSpeed; + this.candyL.update(delta); + this.starL.update(ropeDelta); + this.candyR.update(delta); + this.starR.update(ropeDelta); + if (this.twoParts === PartsType.DISTANCE) { + for (i = 0; i < Bungee.BUNGEE_RELAXION_TIMES; i++) { + this.starL.satisfyConstraints(); + this.starR.satisfyConstraints(); + } + } + if (this.partsDist > 0) { + moveResult = Mover.moveToTargetWithStatus(this.partsDist, 0, 200, delta); + this.partsDist = moveResult.value; + if (moveResult.reachedZero) { + SoundMgr.playSound(ResourceId.SND_CANDY_LINK); + this.twoParts = PartsType.NONE; + this.noCandy = false; + this.noCandyL = true; + this.noCandyR = true; + + //Achievements.increment(AchievementId.ROMANTIC_SOUL); + + if (this.candyBubbleL || this.candyBubbleR) { + this.candyBubble = (this.candyBubbleL ? this.candyBubbleL : this.candyBubbleR); + this.candyBubbleAnimation.visible = true; + } + + this.lastCandyRotateDelta = 0; + this.lastCandyRotateDeltaL = 0; + this.lastCandyRotateDeltaR = 0; + + this.star.pos.x = this.starL.pos.x; + this.star.pos.y = this.starL.pos.y; + this.candy.x = this.star.pos.x; + this.candy.y = this.star.pos.y; + this.candy.calculateTopLeft(); + + var lv = Vector.subtract(this.starL.pos, this.starL.prevPos), + rv = Vector.subtract(this.starR.pos, this.starR.prevPos), + sv = new Vector((lv.x + rv.x) / 2, (lv.y + rv.y) / 2); + this.star.prevPos.copyFrom(this.star.pos); + this.star.prevPos.subtract(sv); + + for (var i = 0, count = this.bungees.length; i < count; i++) { + var g = this.bungees[i], + b = g.rope; + if (b && b.cut !== b.parts.length - 3 && + (b.tail === this.starL || b.tail === this.starR)) { + var prev = b.parts[b.parts.length - 2], + heroRestLen = b.tail.restLength(prev); + this.star.addConstraint(prev, heroRestLen, ConstraintType.DISTANCE); + b.tail = this.star; + b.parts[b.parts.length - 1] = this.star; + b.initialCandleAngle = 0; + b.chosenOne = false; + } + } + + var transform = new Animation(); + transform.initTextureWithId(ResourceId.IMG_OBJ_CANDY_01); + transform.doRestoreCutTransparency(); + transform.x = this.candy.x; + transform.y = this.candy.y; + transform.anchor = Alignment.CENTER; + var a = transform.addAnimationDelay(0.05, Timeline.LoopType.NO_LOOP, + IMG_OBJ_CANDY_01_part_fx_start, IMG_OBJ_CANDY_01_part_fx_end); + transform.getTimeline(a).onFinished = this.aniPool.timelineFinishedDelegate(); + transform.playTimeline(0); + this.aniPool.addChild(transform); + + + + + } + else { + this.starL.changeRestLength(this.starR, this.partsDist); + this.starR.changeRestLength(this.starL, this.partsDist); + } + } + + if (!this.noCandyL && !this.noCandyR && + this.twoParts === PartsType.SEPARATE && + GameObject.intersect(this.candyL, this.candyR)) { + this.twoParts = PartsType.DISTANCE; + this.partsDist = this.starL.pos.distance(this.starR.pos); + this.starL.addConstraint(this.starR, this.partsDist, ConstraintType.NOT_MORE_THAN); + this.starR.addConstraint(this.starL, this.partsDist, ConstraintType.NOT_MORE_THAN); + } + } + + this.target.update(delta); + + if (this.camera.type !== Camera2D.SpeedType.PIXELS || !this.ignoreTouches) { + for (i = 0, len = this.stars.length; i < len; i++) { + var s = this.stars[i]; + if (!s) continue; + s.update(delta); + + if (s.timeout > 0 && s.time === 0) { + s.getTimeline(1).onFinished = this.aniPool.timelineFinishedDelegate(); + this.aniPool.addChild(s); + this.stars.splice(i, 1); + s.timedAnim.playTimeline(1); + s.playTimeline(1); + break; + } + else { + var hits = false; + if (this.twoParts !== PartsType.NONE) { + hits = (GameObject.intersect(this.candyL, s) && !this.noCandyL) || + (GameObject.intersect(this.candyR, s) && !this.noCandyR); + } + else { + hits = GameObject.intersect(this.candy, s) && !this.noCandy; + } + + if (hits) { + + this.candyBlink.playTimeline(CandyBlink.STAR); + this.starsCollected++; + this.hudStars[this.starsCollected - 1].playTimeline(0); + + var starDisappear = starDisappearPool[i]; + starDisappear.x = s.x; + starDisappear.y = s.y; + + starDisappear.playTimeline(0); + this.aniPool.addChild(starDisappear); + + + this.stars[i] = null; + SoundMgr.playSound(ResourceId.SND_STAR_1 + this.starsCollected - 1); + + if (this.target.currentTimelineIndex === CharAnimation.IDLE) { + this.target.playTimeline(CharAnimation.EXCITED); + } + + break; + } + } + } + } + + for (i = 0, len = this.bubbles.length; i < len; i++) { + b = this.bubbles[i]; + b.update(delta); + + if (!b.popped) { + + if (this.twoParts != PartsType.NONE) { + + if (!this.noCandyL && this.isBubbleCapture(b, this.candyL, this.candyBubbleL, this.candyBubbleAnimationL)) { + this.candyBubbleL = b; + break; + } + + if (!this.noCandyR && this.isBubbleCapture(b, this.candyR, this.candyBubbleR, this.candyBubbleAnimationR)) { + this.candyBubbleR = b; + break; + } + } else { + + if (!this.noCandy && this.isBubbleCapture(b, this.candy, this.candyBubble, this.candyBubbleAnimation)) { + this.candyBubble = b; + break; + } + } + } + + if (!b.withoutShadow) { + var numRotatedCircles = this.rotatedCircles.length; + for (j = 0; j < numRotatedCircles; j++) { + var rc = this.rotatedCircles[j], + distanceToCircle = Vector.distance(b.x, b.y, rc.x, rc.y); + if (distanceToCircle < rc.sizeInPixels) { + b.withoutShadow = true; + } + } + } + } + + // tutorial text + for (i = 0, len = this.tutorials.length; i < len; i++) { + var t = this.tutorials[i]; + t.update(delta); + } + + // tutorial images + for (i = 0, len = this.tutorialImages.length; i < len; i++) { + t = this.tutorialImages[i]; + t.update(delta); + } + + var removeCircleIndex = -1; + for (i = 0, len = this.rotatedCircles.length; i < len; i++) { + rc = this.rotatedCircles[i]; + + for (j = 0; j < numGrabs; j++) { + var g = this.bungees[j], + gIndex = rc.containedObjects.indexOf(g), + distance = Vector.distance(g.x, g.y, rc.x, rc.y); + + if (distance <= rc.sizeInPixels + 5 * this.PM) { + if (gIndex < 0) { + rc.containedObjects.push(g); + } + } + else if (gIndex >= 0) { + rc.containedObjects.splice(g, 1); + } + } + + var numBubbles = this.bubbles.length; + for (j = 0; j < numBubbles; j++) { + var b = this.bubbles[j], + distance = Vector.distance(b.x, b.y, rc.x, rc.y), + bIndex = rc.containedObjects.indexOf(b); + + if (distance <= rc.sizeInPixels + 10 * this.PM) { + if (bIndex < 0) { + rc.containedObjects.push(b); + } + } + else if (bIndex >= 0) { + rc.containedObjects.splice(b, 1); + } + } + + if (rc.removeOnNextUpdate) { + removeCircleIndex = i; + } + + rc.update(delta); + } + + if (removeCircleIndex >= 0) { + this.rotatedCircles.splice(removeCircleIndex, 1); + } + + // rockets + for (i = 0, len = this.rockets.length; i < len; i++) { + r = this.rockets[i]; + r.update(delta); + // TODO: finish + } + + // socks + for (i = 0, len = this.socks.length; i < len; i++) { + s = this.socks[i]; + s.update(delta); + var moveStatus = Mover.moveToTargetWithStatus(s.idleTimeout, 0, 1, delta); + s.idleTimeout = moveStatus.value; + if (moveStatus.reachedZero) { + s.state = Sock.StateType.IDLE; + } + + var savedRotation = s.rotation; + s.rotation = 0; + s.updateRotation(); + var rs = this.star.posDelta.copy(); + rs.rotate(Radians.fromDegrees(-savedRotation)); + s.rotation = savedRotation; + s.updateRotation(); + + var bbX = this.star.pos.x - resolution.STAR_SOCK_RADIUS, + bbY = this.star.pos.y - resolution.STAR_SOCK_RADIUS, + bbW = resolution.STAR_SOCK_RADIUS * 2, + bbH = bbW; + + /* + // DEBUG: draw the star bounding box + var ctx = Canvas.context; + ctx.lineWidth = 1; + ctx.strokeStyle = 'red'; + ctx.strokeRect(bbX, bbY, bbW, bbH); + */ + + if (rs.y >= 0 && + (Rectangle.lineInRect( + s.t1.x, s.t1.y, s.t2.x, s.t2.y, + bbX, bbY, bbW, bbH) || + Rectangle.lineInRect( + s.b1.x, s.b1.y, s.b2.x, s.b2.y, + bbX, bbY, bbW, bbH))) { + + if (s.state === Sock.StateType.IDLE) { + + // look for a recieving sock + for (var j = 0; j < len; j++) { + var n = this.socks[j]; + if (n !== s && n.group === s.group) { + s.state = Sock.StateType.RECEIVING; + n.state = Sock.StateType.THROWING; + this.releaseAllRopes(false); + + this.savedSockSpeed = SOCK_SPEED_K * this.star.v.getLength() * + resolution.PHYSICS_SPEED_MULTIPLIER; + this.targetSock = n; + + s.light.playTimeline(0); + s.light.visible = true; + SoundMgr.playSound(ResourceId.SND_TELEPORT); + this.dd.callObject(this, this.teleport, null, 0.1); + break; + } + } + break; + } + + } + else { + if (s.state !== Sock.StateType.IDLE && s.idleTimeout === 0) { + s.idleTimeout = Sock.IDLE_TIMEOUT; + } + } + + } + + // pumps + for (i = 0, len = this.pumps.length; i < len; i++) { + var p = this.pumps[i]; + p.update(delta); + + var moveStatus = Mover.moveToTargetWithStatus(p.touchTimer, 0, 1, delta); + p.touchTimer = moveStatus.value; + if (moveStatus.reachedZero) { + this.operatePump(p, delta); + } + } + + // razors + for (i = 0, len = this.razors.length; i < len; i++) { + var r = this.razors[i]; + r.update(delta); + this.cut(r, null, null, false); + } + + // spikes + var star_spike_radius = resolution.STAR_SPIKE_RADIUS, + star_spike_radius_double = star_spike_radius * 2; + // isCandyHit = function (spike, star) { + // return ( + // Rectangle.lineInRect( + // spike.t1.x, spike.t1.y, + // spike.t2.x, spike.t2.y, + // star.pos.x - star_spike_radius, star.pos.y - star_spike_radius, + // star_spike_radius_double, star_spike_radius_double) || + // Rectangle.lineInRect( + // spike.b1.x, spike.b1.y, + // spike.b2.x, spike.b2.y, + // star.pos.x - star_spike_radius, star.pos.y - star_spike_radius, + // star_spike_radius_double, star_spike_radius_double)); + // }; + + for (i = 0, len = this.spikes.length; i < len; i++) { + s = this.spikes[i]; + + //only update if something happens + if (s.mover || s.shouldUpdateRotation || s.electro) { + s.update(delta); + } + + if (!s.electro || s.electroOn) { + var candyHits = false, + left = false; + if (this.twoParts !== PartsType.NONE) { + candyHits = !this.noCandyL && isCandyHit(s, this.starL, star_spike_radius); + if (candyHits) { + left = true; + } + else { + candyHits = !this.noCandyR && isCandyHit(s, this.starR, star_spike_radius); + } + } + else { + candyHits = !this.noCandy && isCandyHit(s, this.star, star_spike_radius); + } + + if (candyHits) { + if (this.twoParts !== PartsType.NONE) { + if (left) { + if (this.candyBubbleL) { + this.popCandyBubble(true); + } + } + else { + if (this.candyBubbleR) { + this.popCandyBubble(false); + } + } + } + else if (this.candyBubble) { + this.popCandyBubble(false); + } + + var candyTexture = ResourceMgr.getTexture(ResourceId.IMG_OBJ_CANDY_01), + b = new CandyBreak(5, candyTexture); + if (this.gravityButton && !this.gravityNormal) { + b.gravity.y = -500; + b.angle = 90; + } + + b.onFinished = this.aniPool.particlesFinishedDelegate(); + + if (this.twoParts != PartsType.NONE) { + if (left) { + b.x = this.candyL.x; + b.y = this.candyL.y; + this.noCandyL = true; + } + else { + b.x = this.candyR.x; + b.y = this.candyR.y; + this.noCandyR = true; + } + } + else { + b.x = this.candy.x; + b.y = this.candy.y; + this.noCandy = true; + } + + b.startSystem(5); + this.aniPool.addChild(b); + SoundMgr.playSound(ResourceId.SND_CANDY_BREAK); + this.releaseAllRopes(left); + + if (this.restartState !== RestartState.FADE_IN) { + this.dd.callObject(this, this.gameLost, null, 0.3); + } + + return; + } + } + } + + // bouncers + var bouncer_radius = resolution.BOUNCER_RADIUS, + bouncer_radius_double = bouncer_radius * 2; + + for (i = 0, len = this.bouncers.length; i < len; i++) { + var bouncer = this.bouncers[i]; + //if (bouncer.mover) { + bouncer.update(delta); + //} + + candyHits = false; + left = false; + if (this.twoParts !== PartsType.NONE) { + candyHits = !this.noCandyL && isCandyHit(bouncer, this.starL, bouncer_radius); + if (candyHits) { + left = true; + } + else { + candyHits = !this.noCandyR && isCandyHit(bouncer, this.starR, bouncer_radius); + } + } + else { + candyHits = !this.noCandy && isCandyHit(bouncer, this.star, bouncer_radius); + } + + if (candyHits) { + if (this.twoParts !== PartsType.NONE) { + if (left) { + this.handleBounce(bouncer, this.starL, delta); + } + else { + this.handleBounce(bouncer, this.starR, delta); + } + } + else { + this.handleBounce(bouncer, this.star, delta); + } + + break; //stop after hit + } + else { + bouncer.skip = false; + } + } + + // apply force to bubbles + var gravityMultiplier = (this.gravityButton && !this.gravityNormal) ? -1 : 1, + yImpulse = resolution.BUBBLE_IMPULSE_Y * gravityMultiplier, + rd = resolution.BUBBLE_IMPULSE_RD; + + // apply candy impulse + if (this.twoParts === PartsType.SEPARATE) { + if (this.candyBubbleL) { + applyStarImpulse(this.starL, rd, yImpulse, delta); + } + if (this.candyBubbleR) { + applyStarImpulse(this.starR, rd, yImpulse, delta); + } + } + if (this.twoParts === PartsType.DISTANCE) { + if (this.candyBubbleL || this.candyBubbleR) { + applyStarImpulse(this.starL, rd, yImpulse, delta); + applyStarImpulse(this.starR, rd, yImpulse, delta); + } + } + else { + if (this.candyBubble) { + applyStarImpulse(this.star, rd, yImpulse, delta); + } + } + + var targetVector; + if (!this.noCandy) { + var MOUTH_OPEN_RADIUS = resolution.MOUTH_OPEN_RADIUS; + if (!this.mouthOpen) { + targetVector = new Vector(this.target.x, this.target.y); + if (this.star.pos.distance(targetVector) < MOUTH_OPEN_RADIUS) { + this.mouthOpen = true; + this.target.playTimeline(CharAnimation.MOUTH_OPEN); + SoundMgr.playSound(ResourceId.SND_MONSTER_OPEN); + this.mouthCloseTimer = MOUTH_OPEN_TIME; + } + } + else { + if (this.mouthCloseTimer > 0) { + this.mouthCloseTimer = Mover.moveToTarget( + this.mouthCloseTimer, 0, 1, delta); + + if (this.mouthCloseTimer <= 0) { + targetVector = new Vector(this.target.x, this.target.y); + if (this.star.pos.distance(targetVector) > MOUTH_OPEN_RADIUS) { + this.mouthOpen = false; + this.target.playTimeline(CharAnimation.MOUTH_CLOSE); + SoundMgr.playSound(ResourceId.SND_MONSTER_CLOSE); + + // this.tummyTeasers++; + // if (this.tummyTeasers === 10) { + // Achievements.increment(AchievementId.TUMMY_TEASER); + // } + } + else { + this.mouthCloseTimer = MOUTH_OPEN_TIME; + } + } + } + } + + if (this.restartState !== RestartState.FADE_IN) { + if (GameObject.intersect(this.candy, this.target)) { + this.gameWon(); + return; + } + } + } + + var outOfScreen = (this.twoParts === PartsType.NONE && this.pointOutOfScreen(this.star) && !this.noCandy), + outOfScreenL = (this.twoParts !== PartsType.NONE && this.pointOutOfScreen(this.starL) && !this.noCandyL), + outOfScreenR = (this.twoParts !== PartsType.NONE && this.pointOutOfScreen(this.starR) && !this.noCandyR); + + if (outOfScreen || outOfScreenL || outOfScreenR) { + + if (outOfScreen) { + this.noCandy = true; + } + if (outOfScreenL) { + this.noCandyL = true; + } + if (outOfScreenR) { + this.noCandyR = true; + } + + if (this.restartState !== RestartState.FADE_IN) { + + // lost candy achievements + // Achievements.increment(AchievementId.WEIGHT_LOSER); + // Achievements.increment(AchievementId.CALORIE_MINIMIZER); + + if (this.twoParts != PartsType.NONE && this.noCandyL && this.noCandyR) { + return; + } + this.gameLost(); + return; + } + } + + if (this.special !== 0) { + if (this.special === 1) { + if (!this.noCandy && + this.candyBubble != null && + this.candy.y < resolution.CANDY_BUBBLE_TUTORIAL_LIMIT_Y && + this.candy.x > resolution.CANDY_BUBBLE_TUTORIAL_LIMIT_X) { + this.special = 0; + + // tutorial text + for (i = 0, len = this.tutorials.length; i < len; i++) { + t = this.tutorials[i]; + if (t.special === 1) { + t.playTimeline(0); + } + } + + // tutorial images + for (i = 0, len = this.tutorialImages.length; i < len; i++) { + t = this.tutorialImages[i]; + if (t.special === 1) { + t.playTimeline(0); + } + } + } + } + } + + if (this.clickToCut && !this.ignoreTouches) { + this.resetBungeeHighlight(); + + // first see if there is a nearby bungee + var cv = new Vector(0, 0), + pos = Vector.add(this.slastTouch, this.camera.pos), + grab = this.getNearestBungeeGrabByBezierPoints(cv, pos.x, pos.y); + b = grab ? grab.rope : null; + if (b) { + + // now see if there is an active element that would override + // bungee selection + var activeElement = false; + if (this.gravityButton) { + var c = this.gravityButton.getChild( + this.gravityButton.isOn() ? 1 : 0); + if (c.isInTouchZone(pos.x, pos.y, true)) { + activeElement = true; + } + } + + if (this.candyBubble || + (this.twoParts != PartsType.NONE && (this.candyBubbleL || this.candyBubbleR))) { + for (i = 0, len = this.bubbles.length; i < len; i++) { + var s = this.bubbles[i], + BUBBLE_RADIUS = resolution.BUBBLE_RADIUS, + BUBBLE_DIAMETER = BUBBLE_RADIUS * 2; + if (this.candyBubble) { + if (Rectangle.pointInRect(pos.x, pos.y, + this.star.pos.x - BUBBLE_RADIUS, + this.star.pos.y - BUBBLE_RADIUS, + BUBBLE_DIAMETER, BUBBLE_DIAMETER)) { + activeElement = true; + break; + } + } + + if (this.candyBubbleL) { + if (Rectangle.pointInRect(pos.x, pos.y, + this.starL.pos.x - BUBBLE_RADIUS, + this.starL.pos.y - BUBBLE_RADIUS, + BUBBLE_DIAMETER, BUBBLE_DIAMETER)) { + activeElement = true; + break; + } + } + + if (this.candyBubbleR) { + if (Rectangle.pointInRect(pos.x, pos.y, + this.starR.pos.x - BUBBLE_RADIUS, + this.starR.pos.y - BUBBLE_RADIUS, + BUBBLE_DIAMETER, BUBBLE_DIAMETER)) { + activeElement = true; + break; + } + } + } + } + + for (i = 0, len = this.spikes.length; i < len; i++) { + var s = this.spikes[i]; + if (s.rotateButton && + s.rotateButton.isInTouchZone(pos.x, pos.y, true)) { + activeElement = true; + } + } + + for (i = 0, len = this.pumps.length; i < len; i++) { + if (this.pumps[i].pointInObject(pos.x, pos.y)) { + activeElement = true; + break; + } + } + + for (i = 0, len = this.rotatedCircles.length; i < len; i++) { + var rc = this.rotatedCircles[i]; + if (rc.isLeftControllerActive() || rc.isRightControllerActive()) { + activeElement = true; + break; + } + + if (Vector.distance(pos.x, pos.y, rc.handle2.x, rc.handle2.y) <= resolution.RC_CONTROLLER_RADIUS || + Vector.distance(pos.x, pos.y, rc.handle2.x, rc.handle2.y) <= resolution.RC_CONTROLLER_RADIUS) { + activeElement = true; + break; + } + } + + for (i = 0, len = this.bungees.length; i < len; i++) { + var g = this.bungees[i]; + if (g.wheel) { + if (Rectangle.pointInRect(pos.x, pos.y, + g.x - resolution.GRAB_WHEEL_RADIUS, + g.y - resolution.GRAB_WHEEL_RADIUS, + resolution.GRAB_WHEEL_RADIUS * 2, + resolution.GRAB_WHEEL_RADIUS * 2)) { + activeElement = true; + break; + } + } + + if (g.moveLength > 0) { + if (Rectangle.pointInRect(pos.x, pos.y, + g.x - resolution.GRAB_MOVE_RADIUS, + g.y - resolution.GRAB_MOVE_RADIUS, + resolution.GRAB_MOVE_RADIUS * 2, + resolution.GRAB_MOVE_RADIUS * 2) || g.moverDragging !== Constants.UNDEFINED) { + activeElement = true; + break; + } + } + } + + if (!activeElement) { + b.highlighted = true; + } + } + } + + moveResult = Mover.moveToTargetWithStatus(this.dimTime, 0, 1, delta); + this.dimTime = moveResult.value; + if (moveResult.reachedZero) { + if (this.restartState === RestartState.FADE_IN) { + this.restartState = RestartState.FADE_OUT; + this.hide(); + this.show(); + this.dimTime = Constants.DIM_TIMEOUT; + } + else { + this.restartState = Constants.UNDEFINED; + } + } + }, + + isBubbleCapture: function(b, candy, candyBubble, candyBubbleAnimation) { + + var bubbleSize = resolution.BUBBLE_SIZE, + bubbleSizeDouble = bubbleSize * 2; + + if (Rectangle.pointInRect( + candy.x, candy.y, b.x - bubbleSize, b.y - bubbleSize, + bubbleSizeDouble, bubbleSizeDouble)) { + + if (candyBubble) { + this.popBubble(b.x, b.y); + } + candyBubbleAnimation.visible = true; + + SoundMgr.playSound(ResourceId.SND_BUBBLE); + + b.popped = true; + b.removeChildWithID(0); + + this.attachCandy(); + + return true; + } + return false; + }, + teleport: function () { + if (!this.targetSock) { + return; + } + + this.targetSock.light.playTimeline(0); + this.targetSock.light.visible = true; + + var off = new Vector(0, resolution.SOCK_TELEPORT_Y); + off.rotate(Radians.fromDegrees(this.targetSock.rotation)); + + this.star.pos.x = this.targetSock.x; + this.star.pos.y = this.targetSock.y; + this.star.pos.add(off); + + this.star.prevPos.copyFrom(this.star.pos); + + this.star.v.x = 0; + this.star.v.y = -1; + this.star.v.rotate(Radians.fromDegrees(this.targetSock.rotation)); + this.star.v.multiply(this.savedSockSpeed); + + this.star.posDelta.copyFrom(this.star.v); + this.star.posDelta.divide(60); + this.star.prevPos.copyFrom(this.star.pos); + this.star.prevPos.subtract(this.star.posDelta); + this.targetSock = null; + + //Achievements.increment(AchievementId.MAGICIAN); + + + }, + animateLevelRestart: function () { + this.restartState = RestartState.FADE_IN; + this.dimTime = Constants.DIM_TIMEOUT; + }, + isFadingIn: function () { + return (this.restartState === RestartState.FADE_IN); + }, + releaseAllRopes: function (left) { + for (var l = 0, len = this.bungees.length; l < len; l++) { + var g = this.bungees[l], + b = g.rope; + + if (b && + (b.tail === this.star || + (b.tail === this.starL && left) || + (b.tail === this.starR && !left))) { + if (b.cut === Constants.UNDEFINED) { + b.setCut(b.parts.length - 2); + this.detachCandy(); + } + else { + b.hideTailParts = true; + } + + if (g.hasSpider && g.spiderActive) { + this.spiderBusted(g); + } + } + } + }, + attachCandy: function() { + this.attachCount += 1; + //console.log('candy attached. count: ' + this.attachCount); + }, + detachCandy: function() { + this.attachCount -= 1; + this.juggleTimer = 0; + //console.log('candy detached. count: ' + this.attachCount); + }, + calculateScore: function () { + this.timeBonus = Math.max(0, 30 - this.time) * 100; + this.timeBonus /= 10; + this.timeBonus *= 10; + this.starBonus = 1000 * this.starsCollected; + this.score = Math.ceil(this.timeBonus + this.starBonus); + }, + gameWon: function () { + this.dd.cancelAllDispatches(); + + this.target.playTimeline(CharAnimation.WIN); + SoundMgr.playSound(ResourceId.SND_MONSTER_CHEWING); + + if (this.candyBubble) { + this.popCandyBubble(false); + } + + this.noCandy = true; + + this.candy.passTransformationsToChilds = true; + this.candyMain.scaleX = this.candyMain.scaleY = 1; + this.candyTop.scaleX = this.candyTop.scaleY = 1; + + var tl = new Timeline(); + tl.addKeyFrame(KeyFrame.makePos(this.candy.x, this.candy.y, KeyFrame.TransitionType.LINEAR, 0)); + tl.addKeyFrame(KeyFrame.makePos(this.target.x, this.target.y + 10, KeyFrame.TransitionType.LINEAR, + 0.1)); + tl.addKeyFrame(KeyFrame.makeScale(0.71, 0.71, KeyFrame.TransitionType.LINEAR, 0)); + tl.addKeyFrame(KeyFrame.makeScale(0, 0, KeyFrame.TransitionType.LINEAR, 0.1)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 0)); + tl.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0.1)); + this.candy.addTimelineWithID(tl, 0); + this.candy.playTimeline(0); + tl.onFinished = this.aniPool.timelineFinishedDelegate(); + this.aniPool.addChild(this.candy); + + this.calculateScore(); + this.releaseAllRopes(false); + + + var self = this, + onLevelWonAppCallback = function () { + + PubSub.publish(PubSub.ChannelId.LevelWon, { + stars: self.starsCollected, + time: self.time, + score: self.score, + fps: (1 / self.gameController.avgDelta) + }); + }; + + // the closing doors animation takes 850ms so we want it to + // finish before the game level deactivates (and freezes) + if (settings.showMenu) { + this.dd.callObject(this, onLevelWonAppCallback, null, 1); + } + + // stop the electro after 1.5 seconds + this.dd.callObject(this, function () { + // stop the electro spikes sound from looping + SoundMgr.stopSound(ResourceId.SND_ELECTRIC); + }, null, 1.5); + + // fire level won callback after 2 secs + var onLevelWon = function () { + this.gameController.onLevelWon.call(this.gameController); + }; + this.dd.callObject(this, onLevelWon, null, 1.8); + }, + gameLost: function () { + this.dd.cancelAllDispatches(); + this.target.playTimeline(CharAnimation.FAIL); + SoundMgr.playSound(ResourceId.SND_MONSTER_SAD); + + // fire level lost callback after 1 sec + var onLevelLost = function () { + this.gameController.onLevelLost.call(this.gameController); + PubSub.publish(PubSub.ChannelId.LevelLost, { 'time': this.time }); + }; + this.dd.callObject(this, onLevelLost, null, 1); + }, + draw: function () { + + // reset any canvas transformations and clear everything + var ctx = Canvas.context; + ctx.clearRect(0, 0, resolution.CANVAS_WIDTH, resolution.CANVAS_HEIGHT); + + this.preDraw(); + this.camera.applyCameraTransformation(); + //this.back.updateWithCameraPos(this.camera.pos); + //console.log('back x:' + this.back.x + ' y:' + this.back.y); + //this.back.draw(); + + var overlayCut = 2, + q, overlayRect, off; + if (this.mapHeight > resolution.CANVAS_HEIGHT) { + q = IMG_BGR_01_P2_vert_transition; + off = this.overlayTexture.offsets[q].y; + overlayRect = this.overlayTexture.rects[q]; + + ctx.drawImage(this.overlayTexture.image, + overlayRect.x, overlayRect.y + overlayCut, overlayRect.w, overlayRect.h - (overlayCut * 2), + 0, off + overlayCut, overlayRect.w, overlayRect.h - (overlayCut * 2)); + } + + var i, len; + for (i = 0, len = this.drawings.length; i < len; i++) { + this.drawings[i].draw(); + } + + for (i = 0, len = this.earthAnims.length; i < len; i++) { + this.earthAnims[i].draw(); + } + + if (this.pollenDrawer) { + this.pollenDrawer.draw(); + } + if (this.gravityButton) { + this.gravityButton.draw(); + } + + this.support.draw(); + this.target.draw(); + + // tutorial text + for (i = 0, len = this.tutorials.length; i < len; i++) { + this.tutorials[i].draw(); + } + + // tutorial images + for (i = 0, len = this.tutorialImages.length; i < len; i++) { + var ti = this.tutorialImages[i]; + + // don't draw the level1 arrow now - it needs to be on top + if (ti.special !== LEVEL1_ARROW_SPECIAL_ID) { + ti.draw(); + } + } + + for (i = 0, len = this.razors.length; i < len; i++) { + this.razors[i].draw(); + } + + for (i = 0, len = this.rotatedCircles.length; i < len; i++) { + this.rotatedCircles[i].draw(); + } + + for (i = 0, len = this.bubbles.length; i < len; i++) { + this.bubbles[i].draw(); + } + + for (i = 0, len = this.pumps.length; i < len; i++) { + this.pumps[i].draw(); + } + + for (i = 0, len = this.spikes.length; i < len; i++) { + this.spikes[i].draw(); + } + + for (i = 0, len = this.bouncers.length; i < len; i++) { + this.bouncers[i].draw(); + } + + for (i = 0, len = this.socks.length; i < len; i++) { + var sock = this.socks[i]; + sock.y -= SOCK_COLLISION_Y_OFFSET; + sock.draw(); + sock.y += SOCK_COLLISION_Y_OFFSET; + } + + var bungees = this.bungees; + for (i = 0, len = bungees.length; i < len; i++) { + bungees[i].drawBack(); + } + for (i = 0; i < len; i++) { + bungees[i].draw(); + } + + for (i = 0, len = this.stars.length; i < len; i++) { + this.stars[i] && this.stars[i].draw(); + } + + if (!this.noCandy && !this.targetSock) { + this.candy.x = this.star.pos.x; + this.candy.y = this.star.pos.y; + this.candy.draw(); + + if (this.candyBlink.currentTimeline != null) { + this.candyBlink.draw(); + } + } + + if (this.twoParts !== PartsType.NONE) { + if (!this.noCandyL) { + this.candyL.x = this.starL.pos.x; + this.candyL.y = this.starL.pos.y; + this.candyL.draw(); + } + + if (!this.noCandyR) { + this.candyR.x = this.starR.pos.x; + this.candyR.y = this.starR.pos.y; + this.candyR.draw(); + } + } + + for (i = 0, len = bungees.length; i < len; i++) { + var g = bungees[i]; + if (g.hasSpider) { + g.drawSpider(); + } + } + + this.aniPool.draw(); + this.drawCuts(); + this.camera.cancelCameraTransformation(); + this.staticAniPool.draw(); + + // draw the level1 arrow last so its on top + for (i = 0, len = this.tutorialImages.length; i < len; i++) { + ti = this.tutorialImages[i]; + if (ti.special === LEVEL1_ARROW_SPECIAL_ID) { + ti.draw(); + } + } + + this.postDraw(); + }, + drawCuts: function () { + var maxSize = resolution.CUT_MAX_SIZE; + for (var i = 0; i < Constants.MAX_TOUCHES; i++) { + var cuts = this.fingerCuts[i], + count = cuts.length; + if (count > 0) { + var perpSize = 1, + v = 0, + fc = null, + pts = [], + pc = 0; + + for (var k = 0; k < count; k++) { + fc = cuts[k]; + if (k === 0) { + pts[pc++] = fc.start; + } + pts[pc++] = fc.end; + } + + var p = null, + points = 2, + numVertices = count * points, + vertices = [], + bstep = 1 / numVertices, + a = 0; + + while (true) { + if (a > 1) { + a = 1; + } + + p = Vector.calcPathBezier(pts, a); + vertices.push(p); + + if (a === 1) { + break; + } + + a += bstep; + } + + var step = maxSize / numVertices, + verts = []; + for (var k = 0, lenMinusOne = numVertices - 1; k < lenMinusOne; k++) { + var startSize = perpSize, + endSize = (k === numVertices - 1) ? 1 : perpSize + step, + start = vertices[k], + end = vertices[k + 1]; + + // n is the normalized arrow + var n = Vector.subtract(end, start); + n.normalize(); + + var rp = Vector.rPerpendicular(n), + lp = Vector.perpendicular(n); + + if (v === 0) { + var srp = Vector.add(start, Vector.multiply(rp, startSize)), + slp = Vector.add(start, Vector.multiply(lp, startSize)); + + verts.push(slp); + verts.push(srp); + } + + var erp = Vector.add(end, Vector.multiply(rp, endSize)), + elp = Vector.add(end, Vector.multiply(lp, endSize)); + + verts.push(elp); + verts.push(erp); + + perpSize += step; + } + + // draw triangle strip + Canvas.fillTriangleStrip(verts, RGBAColor.styles.SOLID_OPAQUE); + } + } + }, + handlePumpFlow: function (p, s, c, delta) { + var powerRadius = resolution.PUMP_POWER_RADIUS; + if (c.rectInObject(p.x - powerRadius, p.y - powerRadius, p.x + powerRadius, p.y + powerRadius)) { + var tn1 = new Vector(0, 0), + tn2 = new Vector(0, 0), + h = new Vector(c.x, c.y); + + tn1.x = p.x - p.bb.w / 2.0; + tn2.x = p.x + p.bb.w / 2.0; + tn1.y = tn2.y = p.y; + + if (p.angle != 0) { + h.rotateAround(-p.angle, p.x, p.y); + } + + if (h.y < tn1.y && + Rectangle.rectInRect( + h.x - c.bb.w / 2.0, h.y - c.bb.h / 2.0, + h.x + c.bb.w / 2.0, h.y + c.bb.h / 2.0, + tn1.x, tn1.y - powerRadius, tn2.x, tn2.y)) { + + var maxPower = powerRadius * 2.0, + power = maxPower * (powerRadius - (tn1.y - h.y)) / powerRadius, + pumpForce = new Vector(0, -power); + + pumpForce.rotate(p.angle); + s.applyImpulse(pumpForce, delta); + + } + + + } + }, + handleBounce: function (bouncer, star, delta) { + if (bouncer.skip) { + return; + } + + var v = Vector.subtract(star.prevPos, star.pos), + spos = star.prevPos.copy(); + + var angle = bouncer.angle, + x = bouncer.x, + y = bouncer.y; + + spos.rotateAround(-angle, x, y); + + var fromTop = (spos.y < bouncer.y), + dir = fromTop ? -1 : 1, + a = v.getLength() * 40, + b = resolution.BOUNCER_MAX_MOVEMENT, + m = (a > b ? a : b) * dir, + v2 = Vector.forAngle(bouncer.angle), + impulse = Vector.perpendicular(v2); + + impulse.multiply(m); + + star.pos.rotateAround(-angle, x, y); + star.prevPos.rotateAround(-angle, x, y); + star.prevPos.y = star.pos.y; + star.pos.rotateAround(angle, x, y); + star.prevPos.rotateAround(angle, x, y); + + star.applyImpulse(impulse, delta); + bouncer.playTimeline(0); + + SoundMgr.playSound(ResourceId.SND_BOUNCER); + }, + operatePump: function (pump, delta) { + pump.playTimeline(0); + var soundId = MathHelper.randomRange(ResourceId.SND_PUMP_1, ResourceId.SND_PUMP_4); + SoundMgr.playSound(soundId); + + var dirtTexture = ResourceMgr.getTexture(ResourceId.IMG_OBJ_PUMP); + var b = new PumpDirt(5, dirtTexture, Radians.toDegrees(pump.angle) - 90); + b.onFinished = this.aniPool.particlesFinishedDelegate(); + + var v = new Vector(pump.x + resolution.PUMP_DIRT_OFFSET, pump.y); + v.rotateAround(pump.angle - Math.PI / 2, pump.x, pump.y); + b.x = v.x; + b.y = v.y; + + b.startSystem(5); + this.aniPool.addChild(b); + + if (!this.noCandy) { + this.handlePumpFlow(pump, this.star, this.candy, delta); + } + + if (this.twoParts !== PartsType.NONE) { + if (!this.noCandyL) { + this.handlePumpFlow(pump, this.starL, this.candyL, delta); + } + + if (!this.noCandyR) { + this.handlePumpFlow(pump, this.starR, this.candyR, delta); + } + } + + }, + cut: function (razor, v1, v2, immediate) { + var cutCount = 0; + for (var l = 0, len = this.bungees.length; l < len; l++) { + var g = this.bungees[l], + b = g.rope; + + if (!b || b.cut !== Constants.UNDEFINED) { + continue; + } + + var GRAB_WHEEL_RADIUS = resolution.GRAB_WHEEL_RADIUS, + GRAB_WHEEL_DIAMETER = GRAB_WHEEL_RADIUS * 2; + for (var i = 0, iLimit = b.parts.length - 1; i < iLimit; i++) { + var p1 = b.parts[i], + p2 = b.parts[i + 1], + cut = false; + + if (razor) { + if (p1.prevPos.x !== Constants.INT_MAX) { + var minX = MathHelper.minOf4(p1.pos.x, p1.prevPos.x, p2.pos.x, p2.prevPos.x), + minY = MathHelper.minOf4(p1.pos.y, p1.prevPos.y, p2.pos.y, p2.prevPos.y), + maxX = MathHelper.maxOf4(p1.pos.x, p1.prevPos.x, p2.pos.x, p2.prevPos.x), + maxY = MathHelper.maxOf4(p1.pos.y, p1.prevPos.y, p2.pos.y, p2.prevPos.y); + + cut = Rectangle.rectInRect( + minX, minY, maxX, maxY, + razor.drawX, razor.drawY, razor.drawX + razor.width, razor.drawY + razor.height); + } + } + else { + if (g.wheel && Rectangle.lineInRect( + v1.x, v1.y, v2.x, v2.y, + g.x - GRAB_WHEEL_RADIUS, g.y - GRAB_WHEEL_RADIUS, + GRAB_WHEEL_DIAMETER, GRAB_WHEEL_DIAMETER)) { + cut = false; + } + else { + cut = MathHelper.lineInLine( + v1.x, v1.y, v2.x, v2.y, + p1.pos.x, p1.pos.y, p2.pos.x, p2.pos.y); + } + } + + if (cut) { + cutCount++; + + if (g.hasSpider && g.spiderActive) { + this.spiderBusted(g); + } + + SoundMgr.playSound(ResourceId.SND_ROPE_BLEAK_1 + b.relaxed); + + b.setCut(i); + this.detachCandy(); + + if (immediate) { + b.cutTime = 0; + b.removePart(i); + } + + return cutCount; + } + } + } + + return cutCount; + }, + spiderBusted: function (g) { + + SoundMgr.playSound(ResourceId.SND_SPIDER_FALL); + g.hasSpider = false; + var s = ImageElement.create(ResourceId.IMG_OBJ_SPIDER, IMG_OBJ_SPIDER_busted); + s.doRestoreCutTransparency(); + var tl = new Timeline(); + if (this.gravityButton && !this.gravityNormal) { + tl.addKeyFrame(KeyFrame.makePos(g.spider.x, g.spider.y, KeyFrame.TransitionType.EASE_OUT, 0)); + tl.addKeyFrame(KeyFrame.makePos(g.spider.x, g.spider.y + 50, KeyFrame.TransitionType.EASE_OUT, + 0.3)); + tl.addKeyFrame(KeyFrame.makePos(g.spider.x, g.spider.y - resolution.CANVAS_HEIGHT, + KeyFrame.TransitionType.EASE_IN, 1)); + } + else { + tl.addKeyFrame(KeyFrame.makePos(g.spider.x, g.spider.y, KeyFrame.TransitionType.EASE_OUT, 0)); + tl.addKeyFrame(KeyFrame.makePos(g.spider.x, g.spider.y - 50, KeyFrame.TransitionType.EASE_OUT, + 0.3)); + tl.addKeyFrame(KeyFrame.makePos(g.spider.x, g.spider.y + resolution.CANVAS_HEIGHT, + KeyFrame.TransitionType.EASE_IN, 1)); + } + + tl.addKeyFrame(KeyFrame.makeRotation(0, 0, 0)); + tl.addKeyFrame(KeyFrame.makeRotation(MathHelper.randomRange(-120, 120), 0, 1)); + s.addTimelineWithID(tl, 0); + s.playTimeline(0); + s.x = g.spider.x; + s.y = g.spider.y; + s.anchor = Alignment.CENTER; + + tl.onFinished = this.aniPool.timelineFinishedDelegate(); + this.aniPool.addChild(s); + + // spider achievements + // Achievements.increment(AchievementId.SPIDER_BUSTER); + // Achievements.increment(AchievementId.SPIDER_TAMER); + }, + spiderWon: function (sg) { + SoundMgr.playSound(ResourceId.SND_SPIDER_WIN); + + for (var i = 0, count = this.bungees.length; i < count; i++) { + var g = this.bungees[i], + b = g.rope; + if (b && b.tail === this.star) { + if (b.cut !== Constants.UNDEFINED) { + g.destroyRope(); + } + else { + b.setCut(b.parts.length - 2); + this.detachCandy(); + b.forceWhite = false; + } + + if (g.hasSpider && g.spiderActive && sg !== g) { + this.spiderBusted(g); + } + } + } + + sg.hasSpider = false; + this.spiderTookCandy = true; + this.noCandy = true; + + var s = ImageElement.create(ResourceId.IMG_OBJ_SPIDER, IMG_OBJ_SPIDER_stealing); + s.doRestoreCutTransparency(); + this.candy.anchor = this.candy.parentAnchor = Alignment.CENTER; + this.candy.x = 0; + this.candy.y = -5; + + s.addChild(this.candy); + var tl = new Timeline(); + if (this.gravityButton && !this.gravityNormal) { + tl.addKeyFrame(KeyFrame.makePos(sg.spider.x, sg.spider.y - 10, KeyFrame.TransitionType.EASE_OUT, + 0)); + tl.addKeyFrame(KeyFrame.makePos(sg.spider.x, sg.spider.y + 70, KeyFrame.TransitionType.EASE_OUT, + 0.3)); + tl.addKeyFrame(KeyFrame.makePos(sg.spider.x, sg.spider.y - resolution.CANVAS_HEIGHT, + KeyFrame.TransitionType.EASE_IN, 1)); + } + else { + tl.addKeyFrame(KeyFrame.makePos(sg.spider.x, sg.spider.y - 10, KeyFrame.TransitionType.EASE_OUT, + 0)); + tl.addKeyFrame(KeyFrame.makePos(sg.spider.x, sg.spider.y - 70, KeyFrame.TransitionType.EASE_OUT, + 0.3)); + tl.addKeyFrame(KeyFrame.makePos(sg.spider.x, sg.spider.y + resolution.CANVAS_HEIGHT, + KeyFrame.TransitionType.EASE_IN, 1)); + } + + s.addTimelineWithID(tl, 0); + s.playTimeline(0); + s.x = sg.spider.x; + s.y = sg.spider.y - 10; + s.anchor = Alignment.CENTER; + + tl.onFinished = this.aniPool.timelineFinishedDelegate(); + this.aniPool.addChild(s); + + if (this.restartState !== RestartState.FADE_IN) { + this.dd.callObject(this, this.gameLost, null, 2); + } + + // Achievements.increment(AchievementId.SPIDER_LOVER); + }, + popCandyBubble: function (isLeft) { + if (this.twoParts !== PartsType.NONE) { + if (isLeft) { + this.candyBubbleL = null; + this.candyBubbleAnimationL.visible = false; + this.popBubble(this.candyL.x, this.candyL.y); + } + else { + this.candyBubbleR = null; + this.candyBubbleAnimationR.visible = false; + this.popBubble(this.candyR.x, this.candyR.y); + } + } + else { + this.candyBubble = null; + this.candyBubbleAnimation.visible = false; + this.popBubble(this.candy.x, this.candy.y); + } + + + }, + popBubble: function (x, y) { + + this.detachCandy(); + + SoundMgr.playSound(ResourceId.SND_BUBBLE_BREAK); + + bubbleDisappear.x = x; + bubbleDisappear.y = y; + + bubbleDisappear.playTimeline(0); + this.aniPool.addChild(bubbleDisappear); + }, + handleBubbleTouch: function (s, tx, ty) { + if (Rectangle.pointInRect( + tx + this.camera.pos.x, ty + this.camera.pos.y, + s.pos.x - resolution.BUBBLE_TOUCH_OFFSET, s.pos.y - resolution.BUBBLE_TOUCH_OFFSET, + resolution.BUBBLE_TOUCH_SIZE, resolution.BUBBLE_TOUCH_SIZE)) { + this.popCandyBubble(s === this.starL); + + // Achievements.increment(AchievementId.BUBBLE_POPPER); + // Achievements.increment(AchievementId.BUBBLE_MASTER); + + return true; + } + return false; + }, + resetBungeeHighlight: function () { + for (var i = 0, len = this.bungees.length; i < len; i++) { + var grab = this.bungees[i], + bungee = grab.rope; + if (!bungee || bungee.cut !== Constants.UNDEFINED) { + continue; + } + bungee.highlighted = false; + } + }, + getNearestBungeeGrabByBezierPoints: function (s, tx, ty) { + var SEARCH_RADIUS = resolution.CLICK_TO_CUT_SEARCH_RADIUS, + grab = null, + md = SEARCH_RADIUS, + tv = new Vector(tx, ty); + + for (var l = 0, numBungees = this.bungees.length; l < numBungees; l++) { + var g = this.bungees[l], + b = g.rope; + + if (b) { + for (var i = 0, numParts = b.drawPts.length; i < numParts; i++) { + + var c1 = b.drawPts[i], + d = c1.distance(tv); + if (d < SEARCH_RADIUS && d < md) { + md = d; + grab = g; + s.copyFrom(c1); + } + } + } + } + + + return grab; + }, + getNearestBungeeSegmentByConstraints: function (s, g) { + var SEARCH_RADIUS = Number.MAX_VALUE, + nb = null, + md = SEARCH_RADIUS, + sOrig = s.copy(), + b = g.rope; + + if (!b || b.cut !== Constants.UNDEFINED) { + return null; + } + + var GRAB_WHEEL_RADIUS = resolution.GRAB_WHEEL_RADIUS, + GRAB_WHEEL_DIAMETER = GRAB_WHEEL_RADIUS * 2; + for (var i = 0, numParts = b.parts.length - 1; i < numParts; i++) { + var p1 = b.parts[i], + d = p1.pos.distance(sOrig); + if (d < md) { + if (!g.wheel || Rectangle.pointInRect( + p1.pos.x, p1.pos.y, + g.x - GRAB_WHEEL_RADIUS, g.y - GRAB_WHEEL_RADIUS, + GRAB_WHEEL_DIAMETER, GRAB_WHEEL_DIAMETER)) { + + md = d; + nb = b; + s.copyFrom(p1.pos); + } + } + } + + return nb; + }, + touchDown: function (x, y, touchIndex) { + if (this.ignoreTouches) { + if (this.camera.type === Camera2D.SpeedType.PIXELS) { + this.fastenCamera = true; + } + return true; + } + + if (touchIndex >= Constants.MAX_TOUCHES) { + return true; + } + + this.overOmNom = false; + + // if (this.gravityButton) { + // var childIndex = this.gravityButton.isOn() ? 1 : 0, + // child = this.gravityButton.getChild(childIndex); + // if (child.isInTouchZone(x + this.camera.pos.x, y + this.camera.pos.y, true)) { + // this.gravityTouchDown = touchIndex; + // return true; + // } + // } + + if (this.candyBubble) { + if (this.handleBubbleTouch(this.star, x, y)) { + return true; + } + } + + if (this.twoParts !== PartsType.NONE) { + if (this.candyBubbleL) { + if (this.handleBubbleTouch(this.starL, x, y)) { + return true; + } + } + if (this.candyBubbleR) { + if (this.handleBubbleTouch(this.starR, x, y)) { + return true; + } + } + } + + var touch = new Vector(x, y); + if (!this.dragging[touchIndex]) { + this.dragging[touchIndex] = true; + this.startPos[touchIndex].copyFrom(touch); + this.prevStartPos[touchIndex].copyFrom(touch); + } + + + + var i, len, + cameraPos = this.camera.pos, + cameraAdjustedX = x + cameraPos.x, + cameraAdjustedY = y + cameraPos.y; + + // handle rotating spikes + for (i = 0, len = this.spikes.length; i < len; i++) { + var spike = this.spikes[i]; + if (spike.rotateButton && + spike.touchIndex === Constants.UNDEFINED && + spike.rotateButton.onTouchDown(cameraAdjustedX, cameraAdjustedY)) { + spike.touchIndex = touchIndex; + return true; + } + } + + // handle pump touches + for (i = 0, len = this.pumps.length; i < len; i++) { + var pump = this.pumps[i]; + if (pump.pointInObject(cameraAdjustedX, cameraAdjustedY)) { + pump.touchTimer = PUMP_TIMEOUT; + pump.touch = touchIndex; + return true; + } + } + + var activeCircle = null, + hasCircleInside = false, + intersectsAnotherCircle = false; + for (i = 0, len = this.rotatedCircles.length; i < len; i++) { + var r = this.rotatedCircles[i], + d1 = Vector.distance(cameraAdjustedX, cameraAdjustedY, r.handle1.x, r.handle1.y), + d2 = Vector.distance(cameraAdjustedX, cameraAdjustedY, r.handle2.x, r.handle2.y); + if ((d1 < resolution.RC_CONTROLLER_RADIUS && + !r.hasOneHandle()) || + d2 < resolution.RC_CONTROLLER_RADIUS) { + + //check for overlapping + for (var j = i + 1; j < len; j++) { + var r2 = this.rotatedCircles[j], + d3 = Vector.distance(r2.x, r2.y, r.x, r.y); + + if ((d3 + r2.sizeInPixels) <= r.sizeInPixels) { + hasCircleInside = true; + } + + if (d3 <= r.sizeInPixels + r2.sizeInPixels) + intersectsAnotherCircle = true; + } + + r.lastTouch.x = cameraAdjustedX; + r.lastTouch.y = cameraAdjustedY; + r.operating = touchIndex; + + if (d1 < resolution.RC_CONTROLLER_RADIUS) { + r.setIsLeftControllerActive(true); + } + if (d2 < resolution.RC_CONTROLLER_RADIUS) { + r.setIsRightControllerActive(true); + } + + activeCircle = r; + + break; + } + + } + + // circle fading + var activeCircleIndex = this.rotatedCircles.indexOf(activeCircle); + if ((activeCircleIndex != this.rotatedCircles.length - 1) && + intersectsAnotherCircle && !hasCircleInside) { + + var fadeIn = new Timeline(); + fadeIn.addKeyFrame(KeyFrame.makeColor(RGBAColor.transparent.copy(), KeyFrame.TransitionType.LINEAR, 0)); + fadeIn.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 0.2)); + + var fadeOut = new Timeline(); + fadeOut.addKeyFrame(KeyFrame.makeColor(RGBAColor.solidOpaque.copy(), KeyFrame.TransitionType.LINEAR, 0.2)); + fadeOut.onFinished = $.proxy(this.onRotatedCircleTimelineFinished, this); + + var fadingOutCircle = activeCircle.copy(); + fadingOutCircle.addTimeline(fadeOut); + fadingOutCircle.playTimeline(0); + + activeCircle.addTimeline(fadeIn); + activeCircle.playTimeline(0); + + this.rotatedCircles[activeCircleIndex] = fadingOutCircle; + this.rotatedCircles.push(activeCircle); + activeCircle = null; + } + + var GRAB_WHEEL_RADIUS = resolution.GRAB_WHEEL_RADIUS, + GRAB_WHEEL_DIAMETER = GRAB_WHEEL_RADIUS * 2, + GRAB_MOVE_RADIUS = resolution.GRAB_MOVE_RADIUS, + GRAB_MOVE_DIAMETER = GRAB_MOVE_RADIUS * 2; + for (i = 0, len = this.bungees.length; i < len; i++) { + var grab = this.bungees[i]; + if (grab.wheel) { + if (Rectangle.pointInRect(cameraAdjustedX, cameraAdjustedY, + grab.x - GRAB_WHEEL_RADIUS, grab.y - GRAB_WHEEL_RADIUS, GRAB_WHEEL_DIAMETER, GRAB_WHEEL_DIAMETER)) { + grab.handleWheelTouch(cameraAdjustedX, cameraAdjustedY); + grab.wheelOperating = touchIndex; + } + } + + if (grab.moveLength > 0) { + if (Rectangle.pointInRect(cameraAdjustedX, cameraAdjustedY, + grab.x - GRAB_MOVE_RADIUS, grab.y - GRAB_MOVE_RADIUS, GRAB_MOVE_DIAMETER, GRAB_MOVE_DIAMETER)) { + grab.moverDragging = touchIndex; + return true; + } + } + } + + if (this.clickToCut) { + var cutPos = Vector.newZero(), + grab = this.getNearestBungeeGrabByBezierPoints( + cutPos, cameraAdjustedX, cameraAdjustedY), + bungee = grab ? grab.rope : null; + if (bungee && bungee.highlighted) { + if (this.getNearestBungeeSegmentByConstraints(cutPos, grab)) { + this.cut(null, cutPos, cutPos, false); + } + } + } + + // easter egg check must be last to avoid affecting other elements + if (this.target.pointInDrawQuad(x, y)) { + this.overOmNom = true; + } + + return true; + }, + doubleClick: function (x, y, touchIndex) { + if (this.ignoreTouches) { + return true; + } + + return true; + }, + touchUp: function (x, y, touchIndex) { + if (this.ignoreTouches) { + return true; + } + + this.dragging[touchIndex] = false; + + // see if the user clicked on OmNom + if (this.overOmNom && this.target.pointInDrawQuad(x, y)) { + this.overOmNom = false; + PubSub.publish(PubSub.ChannelId.OmNomClicked); + return; + } + else { + this.overOmNom = false; + } + + var i, len, + cameraPos = this.camera.pos, + cameraAdjustedX = x + cameraPos.x, + cameraAdjustedY = y + cameraPos.y; + + // drawings + for (i = 0, len = this.drawings.length; i < len; i++) { + var drawing = this.drawings[i]; + if (drawing.pointInObject(cameraAdjustedX, cameraAdjustedY)) { + drawing.showDrawing(); + + // remove the drawing + this.drawings.splice(i, 1); + break; + } + } + + if (this.gravityButton && this.gravityTouchDown === touchIndex) { + var childIndex = this.gravityButton.isOn() ? 1 : 0, + child = this.gravityButton.getChild(childIndex); + if (child.isInTouchZone(x + this.camera.pos.x, y + this.camera.pos.y, true)) { + this.gravityButton.toggle(); + this.onButtonPressed(GravityButton.DefaultId); + } + this.gravityTouchDown = Constants.UNDEFINED; + } + + // for (i = 0, len = this.spikes.length; i < len; i++) { + // var spike = this.spikes[i]; + // if (spike.rotateButton && spike.touchIndex === touchIndex) { + // spike.touchIndex = Constants.UNDEFINED; + // if (spike.rotateButton.onTouchUp(x + this.camera.pos.x, y + this.camera.pos.y)) { + // return true; + // } + // } + // } + + for (i = 0, len = this.rotatedCircles.length; i < len; i++) { + var r = this.rotatedCircles[i]; + if (r.operating === touchIndex) { + r.operating = Constants.UNDEFINED; + r.soundPlaying = Constants.UNDEFINED; + r.setIsLeftControllerActive(false); + r.setIsRightControllerActive(false); + } + } + + for (i = 0, len = this.bungees.length; i < len; i++) { + var grab = this.bungees[i]; + if (grab.wheel && grab.wheelOperating === touchIndex) { + grab.wheelOperating = Constants.UNDEFINED; + } + + if (grab.moveLength > 0 && grab.moverDragging === touchIndex) { + grab.moverDragging = Constants.UNDEFINED; + } + } + + return true; + }, + touchMove: function (x, y, touchIndex) { + if (this.ignoreTouches) { + return true; + } + + if (touchIndex >= Constants.MAX_TOUCHES) { + return true; + } + + var touch = new Vector(x, y), + i, len; + if (this.startPos[touchIndex].distance(touch) > 10) { + for (i = 0, len = this.pumps.length; i < len; i++) { + var pump = this.pumps[i]; + + // cancel pump touch if we moved + if (pump.touch === touchIndex && pump.touchTimer !== 0) { + pump.touchTimer = 0; + } + } + } + + this.slastTouch.copyFrom(touch); + + + var cameraAdjustedTouch = new Vector( + x + this.camera.pos.x, y + this.camera.pos.y); + + for (i = 0, len = this.rotatedCircles.length; i < len; i++) { + var r = this.rotatedCircles[i]; + if (r.operating === touchIndex) { + var c = new Vector(r.x, r.y); + if (c.distance(cameraAdjustedTouch) < r.sizeInPixels / 10) { + r.lastTouch.copyFrom(cameraAdjustedTouch); + } + + var m1 = Vector.subtract(r.lastTouch, c), + m2 = Vector.subtract(cameraAdjustedTouch, c), + a = m2.normalizedAngle() - m1.normalizedAngle(); + + if (a > Math.PI) { + a = a - 2 * Math.PI; + } + else if (a < -Math.PI) { + a = a + 2 * Math.PI; + } + + r.handle1.rotateAround(a, r.x, r.y); + r.handle2.rotateAround(a, r.x, r.y); + r.rotation += Radians.toDegrees(a); + + var soundToPlay = (a > 0) + ? ResourceId.SND_SCRATCH_IN + : ResourceId.SND_SCRATCH_OUT; + + if (Math.abs(a) < 0.07) + soundToPlay = Constants.UNDEFINED; + + if (r.soundPlaying != soundToPlay && soundToPlay != Constants.UNDEFINED) { + SoundMgr.playSound(soundToPlay); + r.soundPlaying = soundToPlay; + } + + for (i = 0, len = this.bungees.length; i < len; i++) { + var g = this.bungees[i], + gn = new Vector(g.x, g.y); + if (gn.distance(c) <= (r.sizeInPixels + 5 * this.PM)) { + gn.rotateAround(a, r.x, r.y); + g.x = gn.x; + g.y = gn.y; + if (g.rope) { + g.rope.bungeeAnchor.pos.copyFrom(gn); + g.rope.bungeeAnchor.pin.copyFrom(gn); + } + } + } + + for (i = 0, len = this.pumps.length; i < len; i++) { + var g = this.pumps[i], + gn = new Vector(g.x, g.y); + if (gn.distance(c) <= (r.sizeInPixels + 5 * this.PM)) { + gn.rotateAround(a, r.x, r.y); + g.x = gn.x; + g.y = gn.y; + g.rotation += Radians.toDegrees(a); + g.updateRotation(); + } + } + + for (i = 0, len = this.bubbles.length; i < len; i++) { + var g = this.bubbles[i], + gn = new Vector(g.x, g.y); + if (gn.distance(c) <= (r.sizeInPixels + 10 * this.PM) && + g !== this.candyBubble && g !== this.candyBubbleR && g !== this.candyBubbleL) { + gn.rotateAround(a, r.x, r.y); + g.x = gn.x; + g.y = gn.y; + } + } + + if (Rectangle.pointInRect( + this.target.x, this.target.y, + r.x - r.size, r.y - r.size, 2 * r.size, 2 * r.size)) { + gn = new Vector(this.target.x, this.target.y); + gn.rotateAround(a, r.x, r.y); + this.target.x = gn.x; + this.target.y = gn.y; + } + + + + r.lastTouch.copyFrom(cameraAdjustedTouch); + + return true; + } + } + + for (i = 0, len = this.bungees.length; i < len; i++) { + var grab = this.bungees[i]; + if (!grab) { + continue; + } + + if (grab.wheel && grab.wheelOperating === touchIndex) { + grab.handleWheelRotate(cameraAdjustedTouch); + return true; + } + + if (grab.moveLength > 0 && grab.moverDragging === touchIndex) { + if (grab.moveVertical) { + grab.y = MathHelper.fitToBoundaries( + cameraAdjustedTouch.y, grab.minMoveValue, grab.maxMoveValue); + } + else { + grab.x = MathHelper.fitToBoundaries( + cameraAdjustedTouch.x, grab.minMoveValue, grab.maxMoveValue); + } + + if (grab.rope) { + var ba = grab.rope.bungeeAnchor; + ba.pos.x = ba.pin.x = grab.x; + ba.pos.y = ba.pin.y = grab.y; + } + + return true; + } + } + + if (this.dragging[touchIndex]) { + var fc = new FingerCut( + Vector.add(this.startPos[touchIndex], this.camera.pos), + Vector.add(touch, this.camera.pos), + 5, // start size + 5, // end size + RGBAColor.white.copy()), + currentCuts = this.fingerCuts[touchIndex], + ropeCuts = 0; + + currentCuts.push(fc); + for (i = 0, len = currentCuts.length; i < len; i++) { + var fcc = currentCuts[i]; + ropeCuts += this.cut(null, fcc.start, fcc.end, false); + } + + if (ropeCuts > 0) { + this.freezeCamera = false; + + if (this.ropesCutAtOnce > 0 && this.ropesAtOnceTimer > 0) { + this.ropesCutAtOnce += ropeCuts; + } + else { + this.ropesCutAtOnce = ropeCuts; + } + this.ropesAtOnceTimer = ROPE_CUT_AT_ONCE_TIMEOUT; + + // rope cut achievements + // Achievements.increment(AchievementId.ROPE_CUTTER); + // Achievements.increment(AchievementId.ROPE_CUTTER_MANIAC); + // Achievements.increment(AchievementId.ULTIMATE_ROPE_CUTTER); + + // // concurrent cut rope achievements + // if (this.ropesCutAtOnce >= 5) { + // Achievements.increment(AchievementId.MASTER_FINGER); + // } else if (this.ropesCutAtOnce >= 3) { + // Achievements.increment(AchievementId.QUICK_FINGER); + // } + } + + this.prevStartPos[touchIndex].copyFrom(this.startPos[touchIndex]); + this.startPos[touchIndex].copyFrom(touch); + } + + return true; + }, + touchDragged: function (x, y, touchIndex) { + if (touchIndex > Constants.MAX_TOUCHES) { + return false; + } + + this.slastTouch.x = x; + this.slastTouch.y = y; + return true; + }, + onButtonPressed: function (n) { + Gravity.toggle(); + this.gravityNormal = Gravity.isNormal(); + SoundMgr.playSound(this.gravityNormal + ? ResourceId.SND_GRAVITY_OFF + : ResourceId.SND_GRAVITY_ON); + + for (var i = 0, len = this.earthAnims.length; i < len; i++) { + var earthImage = this.earthAnims[i]; + if (Gravity.isNormal()) { + earthImage.playTimeline(EarthImage.TimelineId.NORMAL); + } + else { + earthImage.playTimeline(EarthImage.TimelineId.UPSIDE_DOWN); + } + } + }, + rotateAllSpikesWithId: function (sid) { + for (var i = 0, len = this.spikes.length; i < len; i++) { + if (this.spikes[i].getToggled() === sid) { + this.spikes[i].rotateSpikes(); + } + } + } + }); + + var IMG_OBJ_CANDY_01_candy_bottom = 0; + var IMG_OBJ_CANDY_01_candy_main = 1; + var IMG_OBJ_CANDY_01_candy_top = 2; + + var IMG_OBJ_SPIDER_busted = 11; + var IMG_OBJ_SPIDER_stealing = 12; + + var IMG_OBJ_CANDY_01_highlight_start = 8; + var IMG_OBJ_CANDY_01_highlight_end = 17; + var IMG_OBJ_CANDY_01_glow = 18; + var IMG_OBJ_CANDY_01_part_1 = 19; + var IMG_OBJ_CANDY_01_part_2 = 20; + var IMG_OBJ_CANDY_01_part_fx_start = 21; + var IMG_OBJ_CANDY_01_part_fx_end = 25; + + var IMG_OBJ_STAR_DISAPPEAR_Frame_1 = 0; + var IMG_OBJ_STAR_DISAPPEAR_Frame_2 = 1; + var IMG_OBJ_STAR_DISAPPEAR_Frame_3 = 2; + var IMG_OBJ_STAR_DISAPPEAR_Frame_4 = 3; + var IMG_OBJ_STAR_DISAPPEAR_Frame_5 = 4; + var IMG_OBJ_STAR_DISAPPEAR_Frame_6 = 5; + var IMG_OBJ_STAR_DISAPPEAR_Frame_7 = 6; + var IMG_OBJ_STAR_DISAPPEAR_Frame_8 = 7; + var IMG_OBJ_STAR_DISAPPEAR_Frame_9 = 8; + var IMG_OBJ_STAR_DISAPPEAR_Frame_10 = 9; + var IMG_OBJ_STAR_DISAPPEAR_Frame_11 = 10; + var IMG_OBJ_STAR_DISAPPEAR_Frame_12 = 11; + var IMG_OBJ_STAR_DISAPPEAR_Frame_13 = 12; + + var IMG_OBJ_BUBBLE_FLIGHT_Frame_1 = 0; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_2 = 1; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_3 = 2; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_4 = 3; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_5 = 4; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_6 = 5; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_7 = 6; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_8 = 7; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_9 = 8; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_10 = 9; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_11 = 10; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_12 = 11; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_13 = 12; + var IMG_OBJ_BUBBLE_FLIGHT_Frame_14 = 13; + + var IMG_OBJ_BUBBLE_POP_Frame_1 = 0; + var IMG_OBJ_BUBBLE_POP_Frame_2 = 1; + var IMG_OBJ_BUBBLE_POP_Frame_3 = 2; + var IMG_OBJ_BUBBLE_POP_Frame_4 = 3; + var IMG_OBJ_BUBBLE_POP_Frame_5 = 4; + var IMG_OBJ_BUBBLE_POP_Frame_6 = 5; + var IMG_OBJ_BUBBLE_POP_Frame_7 = 6; + var IMG_OBJ_BUBBLE_POP_Frame_8 = 7; + var IMG_OBJ_BUBBLE_POP_Frame_9 = 8; + var IMG_OBJ_BUBBLE_POP_Frame_10 = 9; + var IMG_OBJ_BUBBLE_POP_Frame_11 = 10; + var IMG_OBJ_BUBBLE_POP_Frame_12 = 11; + + var IMG_OBJ_BUBBLE_ATTACHED_bubble = 0; + var IMG_OBJ_BUBBLE_ATTACHED_stain_01 = 1; + var IMG_OBJ_BUBBLE_ATTACHED_stain_02 = 2; + var IMG_OBJ_BUBBLE_ATTACHED_stain_03 = 3; + + var IMG_HUD_STAR_Frame_1 = 0; + var IMG_HUD_STAR_Frame_2 = 1; + var IMG_HUD_STAR_Frame_3 = 2; + var IMG_HUD_STAR_Frame_4 = 3; + var IMG_HUD_STAR_Frame_5 = 4; + var IMG_HUD_STAR_Frame_6 = 5; + var IMG_HUD_STAR_Frame_7 = 6; + var IMG_HUD_STAR_Frame_8 = 7; + var IMG_HUD_STAR_Frame_9 = 8; + var IMG_HUD_STAR_Frame_10 = 9; + var IMG_HUD_STAR_Frame_11 = 10; + + var IMG_CHAR_ANIMATIONS_idle_start = 8; + var IMG_CHAR_ANIMATIONS_idle_end = 26; + var IMG_CHAR_ANIMATIONS_fail_start = 27; + var IMG_CHAR_ANIMATIONS_fail_end = 39; + var IMG_CHAR_ANIMATIONS_mouth_open_start = 40; + var IMG_CHAR_ANIMATIONS_mouth_open_end = 48; + var IMG_CHAR_ANIMATIONS_mouth_close_start = 49; + var IMG_CHAR_ANIMATIONS_mouth_close_end = 52; + var IMG_CHAR_ANIMATIONS_chew_start = 53; + var IMG_CHAR_ANIMATIONS_chew_end = 61; + var IMG_CHAR_ANIMATIONS_blink_start = 62; + var IMG_CHAR_ANIMATIONS_blink_end = 63; + var IMG_CHAR_ANIMATIONS_excited_start = 64; + var IMG_CHAR_ANIMATIONS_excited_end = 83; + var IMG_CHAR_ANIMATIONS_idle2_start = 84; + var IMG_CHAR_ANIMATIONS_idle2_end = 108; + var IMG_CHAR_ANIMATIONS_idle3_start = 109; + var IMG_CHAR_ANIMATIONS_idle3_end = 124; + var IMG_CHAR_ANIMATIONS_puzzled_start = 125; + var IMG_CHAR_ANIMATIONS_puzzled_end = 151; + var IMG_CHAR_ANIMATIONS_greeting_start = 152; + var IMG_CHAR_ANIMATIONS_greeting_end = 180; + + + return GameScene; + } + +); + +define('core/View', + ['visual/BaseElement', 'resolution'], + function (BaseElement, resolution) { + + var View = BaseElement.extend({ + init: function () { + this._super(); + this.width = resolution.CANVAS_WIDTH; + this.height = resolution.CANVAS_HEIGHT; + } + }); + + return View; + } +); + +// @depend ../core/View.js + +define('game/GameView', + [ + 'core/View', + 'resolution', + 'core/RGBAColor', + 'utils/Canvas', + 'utils/Constants' + ], + function (View, resolution, RGBAColor, Canvas, Constants) { + + var GameView = View.extend({ + init: function () { + this._super(); + }, + draw: function () { + var children = this.children, + childCount = children.length; + for (var i = 0; i < childCount; i++) { + var c = children[i]; + if (!c.visible) { + continue; + } + + c.draw(); + } + + var gs = this.getChild(GameView.ElementType.GAME_SCENE); + if (gs.dimTime > 0) { + var alpha = gs.dimTime / Constants.DIM_TIMEOUT; + if (gs.isFadingIn()) { + alpha = 1 - alpha; + } + + var ctx = Canvas.context, + color = new RGBAColor(1, 1, 1, alpha); + ctx.fillStyle = color.rgbaStyle(); + ctx.fillRect(0, 0, resolution.CANVAS_WIDTH, resolution.CANVAS_HEIGHT); + } + }, + show: function () { + this._super(); + + var gs = this.getChild(GameView.ElementType.GAME_SCENE); + if (gs.animateRestartDim) { + gs.animateLevelRestart(); + } + } + + }); + + /** + * @enum {number} + */ + GameView.ElementType = { + GAME_SCENE: 0, + PAUSE_BUTTON: 1, + RESTART_BUTTON: 2, + NEXT_BUTTON: 3, + PAUSE_MENU: 4, + RESULTS: 5 + }; + + return GameView; + } +); +define('game/GameController', + [ + 'core/ViewController', + 'GameScene', + 'game/GameView', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'utils/Constants' + ], + function (ViewController, GameScene, GameView, SoundMgr, ResourceId, Constants) { + + /** + * @enum {number} + */ + var GameButton = { + PAUSE_RESUME: 0, + PAUSE_RESTART: 1, + PAUSE_SKIP: 2, + PAUSE_LEVEL_SELECT: 3, + PAUSE_EXIT: 4, + WIN_EXIT: 5, + PAUSE: 6, + NEXT_LEVEL: 7, + WIN_RESTART: 8, + WIN_NEXT_LEVEL: 9 + }; + + /** + * @enum {number} + */ + var ExitCodeFrom = { + PAUSE_MENU: 0, + PAUSE_MENU_LEVEL_SELECT: 1, + PAUSE_MENU_LEVEL_SELECT_NEXT_PACK: 2 + }; + + var GameController = ViewController.extend({ + init: function (parent) { + this._super(parent); + this.animateRestart = false; + }, + activate: function () { + this._super(); + SoundMgr.playMusic(ResourceId.SND_GAME_MUSIC); + this.createGameView(); + this.initGameView(); + this.showView(0); + }, + createGameView: function () { + + var view = new GameView(); + var sc = new GameScene(); + sc.gameController = this; + sc.animateRestartDim = this.animateRestart; + this.animateRestart = false; + view.addChildWithID(sc, GameView.ElementType.GAME_SCENE); + + this.addView(view, 0); + }, + + initGameView: function () { + this.setPaused(false); + this.levelFirstStart(); + }, + levelFirstStart: function () { + this.isGamePaused = false; + }, + levelStart: function () { + this.isGamePaused = false; + }, + onLevelWon: function () { + SoundMgr.playSound(ResourceId.SND_WIN); + this.deactivate(); + }, + onLevelLost: function () { + this.restartLevel(); + }, + setPaused: function (paused) { + this.isGamePaused = paused; + + var view = this.getView(0); + if (view) { + var gs = view.getChild(GameView.ElementType.GAME_SCENE); + if (gs) { + gs.touchable = !paused; + gs.updateable = !paused; + + if (paused) { + SoundMgr.pauseAudio(); + } + else { + SoundMgr.resumeAudio(); + } + } + } + }, + pauseLevel: function () { + var view = this.getView(0); + if (view) { + var gs = view.getChild(GameView.ElementType.GAME_SCENE); + if (gs) { + gs.dimTime = 0.0; + this.setPaused(true); + } + } + }, + resumeLevel: function () { + this.setPaused(false); + }, + restartLevel: function () { + this.deleteView(0); + this.animateRestart = true; + this.activate(); + }, + + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseDown: function (x, y) { + // see if the event was handled by the base class + var res = this._super(x, y); + if (res) { + return true; + } + + // see if the game scene is touchable + var view = this.getView(0); + if (view) { + var gs = view.getChild(GameView.ElementType.GAME_SCENE); + if (gs && gs.touchable) { + gs.touchDown(x, y, 0); + return true; + } + } + + return false; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseDragged: function (x, y) { + // see if the event was handled by the base class + var res = this._super(x, y); + if (res) { + return true; + } + + // see if the game scene is touchable + var view = this.getView(0); + if (view) { + var gs = view.getChild(GameView.ElementType.GAME_SCENE); + if (gs && gs.touchable) { + gs.touchDragged(x, y, 0); + return true; + } + } + + return false; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseMoved: function (x, y) { + // see if the event was handled by the base class + var res = this._super(x, y); + if (res) { + return true; + } + + // see if the game scene is touchable + var view = this.getView(0); + if (view) { + var gs = view.getChild(GameView.ElementType.GAME_SCENE); + if (gs && gs.touchable) { + gs.touchMove(x, y, 0); + return true; + } + } + + return false; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + mouseUp: function (x, y) { + // see if the event was handled by the base class + var res = this._super(x, y); + if (res) { + return true; + } + + // see if the game scene is touchable + var view = this.getView(0); + if (view) { + var gs = view.getChild(GameView.ElementType.GAME_SCENE); + if (gs && gs.touchable) { + gs.touchUp(x, y, 0); + return true; + } + } + + return false; + }, + /** + * @param x {number} + * @param y {number} + * @return {boolean} true if event was handled + */ + doubleClick: function (x, y) { + // see if the event was handled by the base class + var res = this._super(x, y); + if (res) { + return true; + } + + var view = this.getView(0); + if (view) { + var gs = view.getChild(GameView.ElementType.GAME_SCENE); + if (gs && gs.touchable) { + gs.doubleClick(x, y, 0); + return true; + } + } + + return false; + } + }); + + return GameController; + } +); +define('game/CTRRootController', + [ + 'core/ViewController', + 'core/RootControllerBase', + 'game/GameController', + 'edition', + 'game/LevelState' + ], + function (ViewController, RootControllerBase, GameController, edition, LevelState) { + + /** + * @enum {number} + */ + var ChildController = { + START: 0, + MENU: 1, + LOADING: 2, + GAME: 3 + }; + + var CTRRootController = RootControllerBase.extend({ + init: function (parent) { + this._super(parent); + }, + startLevel: function (pack, level) { + LevelState.loadLevel(pack, level); + + // activate the root controller if necessary + if (this.controllerState === ViewController.StateType.INACTIVE) { + this.activate(); + } + + // deactivate any existing game that is running + var gameController = this.getChild(ChildController.GAME); + if (gameController) { + gameController.deactivateImmediately(); + } + + // create and add the new game controller + gameController = new GameController(this); + this.addChildWithID(gameController, ChildController.GAME); + this.activateChild(ChildController.GAME); + }, + pauseLevel: function () { + var gameController = this.getChild(ChildController.GAME); + if (gameController) { + gameController.pauseLevel(); + } + }, + resumeLevel: function () { + var gameController = this.getChild(ChildController.GAME); + if (gameController) { + gameController.resumeLevel(); + } + }, + restartLevel: function () { + var gameController = this.getChild(ChildController.GAME); + if (gameController) { + gameController.restartLevel(); + } + }, + stopLevel: function () { + this.deactivateActiveChild(); + }, + isLevelActive: function () { + + // is the root controller active? + if (this.controllerState === ViewController.StateType.INACTIVE) + return false; + + // see if the game controller exists + var gameController = this.getChild(ChildController.GAME); + if (!gameController) + return false; + + // is the game controller active? + if (gameController.controllerState === ViewController.StateType.INACTIVE) + return false; + + // see if the game is paused + if (gameController.isGamePaused) + return false; + + return true; + }, + onChildDeactivated: function (childType) { + this._super(childType); + + if (childType == ChildController.GAME) { + this.deleteChild(ChildController.GAME); + } + } + }); + + // we only need a singleton instance + return new CTRRootController(); + } +); + + + +define('ui/Dialogs', + [ + 'game/CTRRootController', + 'ui/PanelId', + 'ui/Panel', + 'resolution', + 'platform', + 'ui/ScoreManager', + 'ui/BoxManager', + 'utils/PubSub', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'resources/Lang', + 'visual/Text', + 'resources/MenuStringId', + 'edition', + 'core/Alignment' + ], + function (RootController, PanelId, Panel, resolution, platform, ScoreManager, BoxManager, PubSub, SoundMgr, + ResourceId, Lang, Text, MenuStringId, edition, Alignment) { + + // show a popup + var Dialogs = { + showPopup: function (contentDivId) { + RootController.pauseLevel(); + $(".popupOuterFrame").hide(); + $(".popupInnerFrame").hide(); + $("#popupWindow").fadeIn(500, function () { + $("#" + contentDivId).show(); + $(".popupOuterFrame").fadeIn(500); + }); + }, + + closePopup: function () { + SoundMgr.playSound(ResourceId.SND_TAP); + $("#popupWindow").fadeOut(500, function () { + RootController.resumeLevel(); + }); + }, + + showPayDialog: function() { + SoundMgr.playSound(ResourceId.SND_TAP); + Dialogs.showPopup("payDialog"); + }, + + showSlowComputerPopup: function() { + // remove the text images + var $slowComputer = $('#slowComputer'); + $slowComputer.children('img').remove(); + + // add the title and text + var $titleImg = $(Text.drawBig({ + text: Lang.menuText(MenuStringId.SLOW_TITLE), + alignment: Alignment.CENTER, + width: 1200 * resolution.CANVAS_SCALE, + scale: 1.25 * resolution.UI_TEXT_SCALE + })), + $textImg = $(Text.drawBig({ + text: Lang.menuText(MenuStringId.SLOW_TEXT), + width: 1200 * resolution.CANVAS_SCALE, + scale: 0.8 * resolution.UI_TEXT_SCALE + })); + + $textImg.css('margin-left', resolution.uiScaledNumber(30)); + $slowComputer.append($titleImg).append($textImg); + + // shrink button text slightly so it will fit in RU and DE + Text.drawBig({ + text: Lang.menuText(MenuStringId.LETS_PLAY), + imgSel: '#slowComputerBtn img', + scale: 0.8 * resolution.UI_TEXT_SCALE + }); + + Dialogs.showPopup('slowComputer'); + } + }; + + function onPayClick() { + PubSub.publish(PubSub.ChannelId.PurchaseBoxesPrompt); + Dialogs.closePopup(); + } + + // localize dialog text + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + Text.drawBig({ + text: Lang.menuText(MenuStringId.UPGRADE_TO_FULL), + imgParentId: 'payMessage', + width: resolution.uiScaledNumber(650), + alignment: Alignment.CENTER, + scale: 0.8 * resolution.UI_TEXT_SCALE + }); + + Text.drawBig({ + text: Lang.menuText(MenuStringId.BUY_FULL_GAME), + imgParentId: 'payBtn', + scale: 0.6 * resolution.UI_TEXT_SCALE + }); + }); + + $(function() { + + // trigger purchase when pay button is clicked + $('#payImg').click(onPayClick); + $('#payBtn').click(onPayClick); + + // close dialog buttons + $('#payClose').click(Dialogs.closePopup); + $("#slowComputerBtn").click(Dialogs.closePopup); + $('#missingOkBtn').click(Dialogs.closePopup); + $("#resetNoBtn").click(Dialogs.closePopup); + + + }); + + return Dialogs; + } +); +define('ui/BoxPanel', + [ + 'ui/PanelId', + 'ui/Panel', + 'ui/Easing', + 'utils/PointerCapture', + 'resolution', + 'ZoomManager', + 'platform', + 'ui/ScoreManager', + 'utils/PubSub', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'resources/Lang', + 'visual/Text', + 'resources/MenuStringId', + 'ui/Dialogs' + ], + function (PanelId, Panel, Easing, PointerCapture, resolution, ZoomManager, + platform, ScoreManager, PubSub, SoundMgr, ResourceId, Lang, Text, MenuStringId, Dialogs) { + + // BoxPanel displays the set of visible boxes (which may not include all boxes) + + var boxes = [], + currentBoxIndex = 0, + currentOffset = 0, + cancelSlideFlag = false, + isBoxCentered = true, + isAnimationActive = false, + spacing = resolution.uiScaledNumber(600), + centeroffset = resolution.uiScaledNumber(312), + bouncebox = null, + im = null, + canvas, ctx, + $navBack, $navForward; + + + var BoxPanel = new Panel(PanelId.BOXES, "boxPanel", "menuBackground", true); + + // dom ready events + $(function() { + canvas = document.getElementById("boxCanvas"); + ctx = canvas.getContext('2d'); + + // size the canvas (only do this once) + canvas.width = resolution.uiScaledNumber(1024); + canvas.height = resolution.uiScaledNumber(576); + + // handles clicking on the prev box button + $navBack = $('#boxNavBack').click($.proxy(function () { + if (currentBoxIndex > 0) { + slideToBox(currentBoxIndex - 1); + SoundMgr.playSound(ResourceId.SND_TAP); + } + }, this)); + + // handles clicking on the next box button + $navForward = $('#boxNavForward').click($.proxy(function () { + if (currentBoxIndex < boxes.length - 1) { + slideToBox(currentBoxIndex + 1); + SoundMgr.playSound(ResourceId.SND_TAP); + } + }, this)); + + $('#boxUpgradePlate').click(function() { + boxClicked(currentBoxIndex); + }); + }); + + PubSub.subscribe(PubSub.ChannelId.UpdateVisibleBoxes, function(visibleBoxes) { + boxes = visibleBoxes; + BoxPanel.redraw(); + }); + + BoxPanel.init = function(interfaceManager) { + im = interfaceManager; + }; + + BoxPanel.onShow = function() { + this.activate(); + }; + + BoxPanel.onHide = function() { + this.deactivate(); + }; + + BoxPanel.slideToNextBox = function() { + slideToBox(currentBoxIndex + 1); + }; + + BoxPanel.bounceCurrentBox = function() { + bounceCurrentBox(); + }; + + // handles clicking on a box + function boxClicked(visibleBoxIndex) { + if (visibleBoxIndex !== currentBoxIndex) { + // only open the selected box (otherwise navigate to different box) + return; + } + + // we have to translate from visible box index to edition box index + var box = boxes[visibleBoxIndex], + editionBoxIndex = box.index; + + // make sure the box is clickable + if (!box.isClickable()) { + return; + } + + SoundMgr.playSound(ResourceId.SND_TAP); + + if (box.purchased === false) { + PubSub.publish(PubSub.ChannelId.PurchaseBoxesPrompt); + } else if (ScoreManager.isBoxLocked(editionBoxIndex)) { + showLockDialog(editionBoxIndex); + } else { + im.openLevelMenu(editionBoxIndex); + } + } + + function showLockDialog(boxIndex) { + // create localized text images + Text.drawBig({ + text: Lang.menuText(MenuStringId.CANT_UNLOCK_TEXT1), + imgParentId: 'missingLine1', + scaleToUI: true + }); + Text.drawBig({ + text: ScoreManager.requiredStars(boxIndex) - + ScoreManager.totalStars(), + imgParentId: 'missingCount', + scaleToUI: true + }); + Text.drawBig({ + text: Lang.menuText(MenuStringId.CANT_UNLOCK_TEXT2), + imgParentId: 'missingLine2', + scaleToUI: true + }); + Text.drawSmall({ + text: Lang.menuText(MenuStringId.CANT_UNLOCK_TEXT3), + imgParentId: 'missingLine3', + width: 260, + scaleToUI: true + }); + + Text.drawBig({ + text: Lang.menuText(MenuStringId.OK), + imgParentId: 'missingOkBtn', + scaleToUI: true + }); + + SoundMgr.playSound(ResourceId.SND_TAP); + Dialogs.showPopup("missingStars"); + } + + function bounceCurrentBox() { + if (bouncebox != null && ctx != null) { + bouncebox.cancelBounce(); + bouncebox.bounce(ctx); + } + } + + // render the boxes with the given offset + function render(offset) { + + currentOffset = offset; + + // clear the canvas + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, canvas.width, canvas.height); + + var offsetX = centeroffset + offset, + offsetY = resolution.uiScaledNumber(130); + ctx.translate(offsetX, offsetY); + + var boxoffset = 0; + + for (var i = 0; i < boxes.length; i++) { + + var omnomoffset = null, + relboxoffset = offset + boxoffset, + box = boxes[i]; + + if (box.visible) { + + // calculate location of omnom if the box in the middle + if (relboxoffset > resolution.uiScaledNumber(-100) && relboxoffset < resolution.uiScaledNumber(100)) { + omnomoffset = (((centeroffset + offset) * -1) - boxoffset) + resolution.uiScaledNumber(452); + } + + ctx.translate(boxoffset, 0); + box.draw(ctx, omnomoffset); + ctx.translate(-boxoffset, 0); + + boxoffset += spacing; + } + } + + ctx.translate(-offsetX, -offsetY); + } + + var slideInProgress = false, + from, to, startTime; + + function slideToBox(index) { + + // clamp index + if (index < 0) index = 0; + if (index > boxes.length - 1) index = boxes.length - 1; + + // if we don't need to move the boxes, we still render them but only one frame + var duration = (index == currentBoxIndex) ? 0 : 550; + + if (bouncebox && bouncebox != boxes[index] && bouncebox.onUnselected) { + bouncebox.onUnselected(); + } + + // update the current boxindex + currentBoxIndex = index; + + // publish new box index + PubSub.publish( + PubSub.ChannelId.SelectedBoxChanged, + boxes[currentBoxIndex].index); // need to translate to edition box index + + from = currentOffset; + to = -1.0 * spacing * index; + startTime = Date.now(); + + var renderSlide = function() { + + if (!slideInProgress) { + return; + } + + var elapsed = Date.now() - startTime; + currentOffset = Easing.easeOutExpo(elapsed, from, to - from, duration); + render(currentOffset); + + // We need to detect whether the box animation has completed for hit testing. If we + // wait until the animaiton is completely done, though, it feels unresponsive + var d = Math.abs(currentOffset - to); + if (d < 5) isBoxCentered = true; + + if (elapsed >= duration) { + if (bouncebox != boxes[currentBoxIndex]) { + bouncebox = boxes[currentBoxIndex]; + bouncebox.bounce(ctx); + } + if (bouncebox && bouncebox.onSelected) { + bouncebox.onSelected(); + } + slideInProgress = false; + } else { + window.requestAnimationFrame(renderSlide); + } + + }; + + slideInProgress = true; + renderSlide(); + + // update the back/forward buttons + $navBack.find('div').toggleClass('boxNavDisabled', index <= 0); + $navForward.find('div').toggleClass('boxNavDisabled', index >= boxes.length - 1); + } + + // cancels any current animations + function cancelSlideToBox() { + slideInProgress = false; + + if (bouncebox != null) { + bouncebox.cancelBounce(); + } + } + + function isMouseOverBox(x, y) { + if (isBoxCentered && bouncebox != null && bouncebox.isClickable()) { + if (x > resolution.uiScaledNumber(340) && + x < resolution.uiScaledNumber(680) && + y > resolution.uiScaledNumber(140) && + y < resolution.uiScaledNumber(460)) { + return true; + } + } + return false; + } + + var ismousedown = false, + imousedragging = false, + upoffset = 0, + downoffset = 0, + delta = 0, + downx = null, + downy = null; + + function pointerDown(x, y) { + if (ismousedown) { return; } + //console.log('box canvas down: ' + x + ', ' + y); + cancelSlideToBox(); + + downx = x; + downy = y; + downoffset = currentOffset; + ismousedown = true; + } + + function pointerMove(x, y) { + if (ismousedown) { + cancelSlideToBox(); + delta = x - downx; + if (Math.abs(delta) > 5) { + + //$navBack.hide(); + //$navForward.hide(); + + isBoxCentered = false; + render(downoffset + delta); + } + } + else { + $(canvas).toggleClass("ctrPointer", isMouseOverBox(x, y)); + } + } + + function pointerUp(x, y) { + //console.log('box canvas up: ' + x + ', ' + y); + if (ismousedown) { + cancelSlideToBox(); + delta = x - downx; + + if (Math.abs(delta) > spacing / 2) { + // if we've passed the rounding threshold then snap to the nearest box (this is for drags) + upoffset = currentOffset; + var index = Math.round(-1 * upoffset / spacing); + + //console.log('box canvas drag to box: ' + index); + slideToBox(index); + } + + else if (Math.abs(delta) > 5) { + // otherwise, we look for an action more like a flick and go to the next box + var max = resolution.uiScaledNumber(30), min = max * -1, + targetBoxIndex = + (delta > max) ? currentBoxIndex - 1 : + (delta < min) ? currentBoxIndex + 1 : + currentBoxIndex; + + //console.log('box canvas flick to box: ' + targetBoxIndex); + slideToBox(targetBoxIndex); + } + + else { + //console.log('box click: ' + currentBoxIndex); + var currentBox = boxes[currentBoxIndex]; + if (currentBox.isClickable()) { + if (!currentBox.islocked) { + slideToBox(currentBoxIndex); + } + + if (isMouseOverBox(x, y)) { + boxClicked(currentBoxIndex); + } + } + } + } + //$navBack.show(); + //$navForward.show(); + ismousedown = false; + } + + function pointerOut(x, y) { + //console.log('box canvas out: ' + x + ', ' + y); + pointerUp(x, y); + } + + BoxPanel.pointerCapture = null; + BoxPanel.activate = function () { + + // ensure capture helper exists to handle mouse+touch movements + if (!this.pointerCapture) { + + this.pointerCapture = new PointerCapture({ + element: canvas, + onStart: $.proxy(pointerDown, this), + onMove: $.proxy(pointerMove, this), + onEnd: $.proxy(pointerUp, this), + onOut: $.proxy(pointerOut, this), + getZoom: function() { + return ZoomManager.getUIZoom(); + } + }); + } + + this.pointerCapture.activate(); + }; + + BoxPanel.deactivate = function () { + if (this.pointerCapture) { + this.pointerCapture.deactivate(); + } + }; + + BoxPanel.redraw = function() { + slideToBox(currentBoxIndex); + }; + + return BoxPanel; + } +); +define('ui/BoxManager', + [ + 'ui/Box', + 'ui/PinnedBox', + 'ui/BoxType', + 'ui/ScoreManager', + 'utils/PubSub', + 'edition', + 'ui/QueryStrings', + 'ui/PurchaseBox', + 'ui/MoreComingBox', + 'ui/TimeBox', + 'ui/BoxPanel' + ], + function (Box, PinnedBox, BoxType, ScoreManager, PubSub, edition, + QueryStrings, PurchaseBox, MoreComingBox, TimeBox, BoxPanel) { + + var BoxManager = new function () { + + var self = this, + boxes = []; + + PubSub.subscribe(PubSub.ChannelId.SelectedBoxChanged, function(boxIndex) { + BoxManager.currentBoxIndex = boxIndex; + BoxManager.currentLevelIndex = 1; + }); + + var appIsReady = false; + this.appReady = function() { + appIsReady = true; + loadBoxes(); + }; + + self.currentBoxIndex = 0; + + // TODO: the current level index starts at 1, should be zero-based + self.currentLevelIndex = 1; + + // listen to purchase event + var isPaid = false; + PubSub.subscribe(PubSub.ChannelId.SetPaidBoxes, function(paid) { + isPaid = paid; + }); + + this.isNextLevelPlayable = function() { + + // check to make sure we aren't on the last level of the box + if (ScoreManager.levelCount(this.currentBoxIndex) <= this.currentLevelIndex) { + return false; + } + + // see if the game requires purchase of some levels + if (isPaid || !edition.levelRequiresPurchase) { + return true; // already purchased or none required + } + + // check whether next level is free + return !edition.levelRequiresPurchase( + this.currentBoxIndex, + this.currentLevelIndex); // NOTE: checking next level since this index is 1 based (TODO: fix!) + }; + + var loadBoxes = function() { + + // only load boxes if app is ready + if (!appIsReady) { + return; + } + + self.currentBoxIndex = 0; + + // TODO: the current level index starts at 1, should be zero-based + self.currentLevelIndex = 1; + + createBoxes(); + updateVisibleBoxes(); + }; + + // reload boxes when user signs in or out + PubSub.subscribe(PubSub.ChannelId.SignIn, loadBoxes); + PubSub.subscribe(PubSub.ChannelId.SignOut, loadBoxes); + PubSub.subscribe(PubSub.ChannelId.RoamingDataChanged, loadBoxes); + PubSub.subscribe(PubSub.ChannelId.BoxesUnlocked, loadBoxes); + + // returns the number of boxes required to win the game + this.requiredCount = function () { + var count = 0; + for (var i = 0, len = boxes.length; i < len; i++) { + if (boxes[i].isRequired()) { + count++; + } + } + return count; + }; + + this.possibleStars = function () { + var count = 0, + len = boxes.length; + for (var i = 0; i < len; i++) { + // we'll count every box except for the hidden pinned box + if (boxes[i].isRequired()) { + count += ScoreManager.possibleStarsForBox(i); + } + } + return count; + }; + + this.visibleGameBoxes = function() { + var count = 0, + i, len, box; + for (i = 0, len = boxes.length; i < len; i++) { + box = boxes[i]; + + // count boxes that are required to finish the game + // and also purchased + if (box.isRequired() && box.purchased !== false) { + count++; + } + } + return count; + }; + + this.resetLocks = function() { + var i, len, box; + + // don't lock the first box + for (i = 1, len = boxes.length; i < len; i++) { + box = boxes[i]; + + // only lock game boxes + if (box.isGameBox()) { + box.islocked = true; + } + } + + BoxPanel.redraw(); + }; + + this.updateBoxLocks = function () { + var numBoxes = boxes.length, + shouldRedraw = false, + boxIndex, box; + + // unlock new boxes if visual state has not been updated yet + // (first box is always unlocked) + for (boxIndex = 1; boxIndex < numBoxes; boxIndex++) { + box = boxes[boxIndex]; + if (!ScoreManager.isBoxLocked(boxIndex) && box.purchased && box.islocked) { + + box.islocked = false; + shouldRedraw = true; + ScoreManager.setStars(boxIndex, 0, 0); + } + } + + if (shouldRedraw) { + BoxPanel.redraw(); + } + }; + + function createBoxes() { + var images = edition.boxImages, + boxtypes = edition.boxTypes, + i, len, box, type, requiredStars, isLocked; + + // clear any existing boxes + boxes.length = 0; + + // create each box + for (i = 0, len = boxtypes.length; i < len; i++) { + type = boxtypes[i]; + requiredStars = ScoreManager.requiredStars(i); + isLocked = ScoreManager.isBoxLocked(i); + + switch (type) { + case BoxType.IEPINNED: + box = new PinnedBox(i, images[i], requiredStars, isLocked, type); + if (!box.initPinnedState()) { + box = null; // don't add if we can't init pinned state + } + break; + case BoxType.PURCHASE: + box = new PurchaseBox(i, images[i], requiredStars, isLocked, type); + break; + case BoxType.MORECOMING: + box = new MoreComingBox(i, images[i], requiredStars, isLocked, type); + break; + case BoxType.TIME: + box = new TimeBox(i, images[i], requiredStars, isLocked, type); + break; + default: + box = new Box(i, images[i], requiredStars, isLocked, type); + break; + } + + if (box) { + boxes.push(box); + } + } + } + + function updateVisibleBoxes() { + var visibleBoxes = [], + i, box, len; + for (i = 0, len = boxes.length; i < len; i++) { + box = boxes[i]; + box.index = i; + if (box.visible) { + visibleBoxes.push(box); + } + } + + PubSub.publish(PubSub.ChannelId.UpdateVisibleBoxes, visibleBoxes); + } + + function onPaidBoxesChange (paid) { + + paid = paid || (QueryStrings.unlockAllBoxes === true); + + var requiresPurchase = edition.levelRequiresPurchase || function () { return false; }, + i, len, box; + + // first box is always unlocked + for (i = 1, len = boxes.length; i < len; i++) { + box = boxes[i]; + + // hide unpurchased boxes and show upgrade prompt + switch(box.type) { + case BoxType.PURCHASE: + box.visible = !paid; + break; + case BoxType.MORECOMING: + box.visible = paid; + break; + default: + // if not paid, check to see if level 1 of the box requires payment + box.purchased = paid || !requiresPurchase(i, 0); + box.islocked = !box.purchased || ScoreManager.isBoxLocked(i); + break; + } + } + + updateVisibleBoxes(); + } + + PubSub.subscribe(PubSub.ChannelId.SetPaidBoxes, onPaidBoxesChange); + }; + + return BoxManager; + } +); +define('ui/LevelPanel', + [ + 'ui/PanelId', + 'ui/Panel', + 'resolution', + 'platform', + 'ui/ScoreManager', + 'ui/BoxManager', + 'utils/PubSub', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'resources/Lang', + 'visual/Text', + 'resources/MenuStringId', + 'edition', + 'core/Alignment', + 'ui/Dialogs' + ], + function (PanelId, Panel, resolution, platform, ScoreManager, BoxManager, PubSub, SoundMgr, + ResourceId, Lang, Text, MenuStringId, edition, Alignment, Dialogs) { + + var backgroundId = edition.levelBackgroundId || 'levelBackground', + LevelPanel = new Panel(PanelId.LEVELS, "levelPanel", backgroundId, true); + + // cache interface manager reference + var im = null; + + LevelPanel.init = function(interfaceManager) { + + im = interfaceManager; + + // generate level elements + var levelCount = ScoreManager.levelCount(BoxManager.currentBoxIndex); + var $levelOptions = $("#levelOptions"); + + // initialize for a 3x3 grid + var leftOffset = 0, + topOffset = 0, + lineLength = resolution.uiScaledNumber(420), + inc = resolution.uiScaledNumber(153), + modClass = "", + columns = 3, + lastRowCount = levelCount % 3; + + + if (levelCount > 9 && levelCount <= 12) { + + // expand to 4x3 grid + leftOffset = -80; + topOffset = 10; + columns = 4; + lineLength = resolution.uiScaledNumber(500); + inc = resolution.uiScaledNumber(153); + + } else if (levelCount > 12) { + + // expand to a 5x5 grid + leftOffset = -30; + topOffset = -40; + inc = resolution.uiScaledNumber(101); + modClass = "option-small"; + columns = 5, + lastRowCount = levelCount % 5; + } + + var curTop = topOffset, curLeft = leftOffset, el; + + var adLevel = function $addLevel(i, inc, extraPad) { + // create the level button + $('
') + .attr('id', 'option' + (i + 1)) + .data('level', i) + .addClass('option locked ctrPointer ' + modClass) + .css({ 'left': curLeft + (extraPad || 0), 'top': curTop}) + .click(onLevelClick) + .appendTo($levelOptions); + + curLeft += inc; + if (curLeft > lineLength) { + curLeft = leftOffset; + curTop += inc; + } + } + + for (var i = 0, filledRowCount = levelCount - lastRowCount; i < filledRowCount; i++) { + adLevel(i, inc); + } + + if (lastRowCount > 0) { + (function(j) { + var extraPad = (columns - lastRowCount) * inc / 2; + for (; j < levelCount; j++) { + adLevel(j, inc, extraPad); + } + })(i); + } + }; + + LevelPanel.onShow = function() { + updateLevelOptions(); + $('#levelScore').delay(200).fadeIn(700); + $('#levelBack').delay(200).fadeIn(700); + $('#levelOptions').delay(200).fadeIn(700); + $('#levelResults').delay(200).fadeOut(700); + }; + + // listen to purchase event + var isPaid = false; + PubSub.subscribe(PubSub.ChannelId.SetPaidBoxes, function(paid) { + isPaid = paid; + updateLevelOptions(); + }); + + // update level UI when boxes are updated (paid upgrade or roaming data change) + PubSub.subscribe(PubSub.ChannelId.UpdateVisibleBoxes, function(visibleBoxes) { + updateLevelOptions(); + }); + + function requiresPurchase(levelIndex) { + if (isPaid) { + return false; + } + + if (edition.levelRequiresPurchase) { + return edition.levelRequiresPurchase(BoxManager.currentBoxIndex, levelIndex); + } + + return false; + } + + function onLevelClick(event) { + + var levelIndex = parseInt($(this).data('level'), 10); + if (ScoreManager.isLevelUnlocked(BoxManager.currentBoxIndex, levelIndex)) { + im.openLevel(levelIndex + 1); + } else if (requiresPurchase(levelIndex)) { + Dialogs.showPayDialog(); + } else { + // no action + return; + } + + SoundMgr.playSound(ResourceId.SND_TAP); + } + + // draw the level options based on current scores and stars + function updateLevelOptions() { + var boxIndex = BoxManager.currentBoxIndex, + levelCount = ScoreManager.levelCount(boxIndex), + $level, stars, $levelInfo, i, levelRequiresPurchase; + + for (i = 0; i < levelCount; i++) { + + // get a reference to the level button + $level = $("#option" + (i + 1)); + if ($level) { + + // show and prepare the element, otherwise hide it + if (i < levelCount) { + + $level.show(); + + levelRequiresPurchase = requiresPurchase(i); + + // if the level has a score show it, otherwise make it locked + stars = ScoreManager.getStars(boxIndex, i); + if (stars != null) { + + $levelInfo = $("
") + .append($(Text.drawBig({text: i + 1, scaleToUI: true }))) + .append($('
').addClass('stars' + stars)); + + $level + .removeClass('locked purchase') + .addClass('open ctrPointer') + .empty() + .append($levelInfo); + } + else { + $level + .removeClass('open').addClass('locked') + .toggleClass('purchase ctrPointer', levelRequiresPurchase) + .empty(); + } + } + else { + $level.hide(); + } + } + } + + // update the scores + // currently assuming each level has three stars + var text = ScoreManager.achievedStars(BoxManager.currentBoxIndex) + + "/" + (ScoreManager.levelCount(BoxManager.currentBoxIndex) * 3); + Text.drawBig({text: text, imgSel: '#levelScore img', scaleToUI: true }); + BoxManager.updateBoxLocks(); + ScoreManager.updateTotalScoreText(); + } + + return LevelPanel; + } +); +define('Doors', + [ + 'resolution', + 'edition', + 'platform', + 'ui/BoxManager', + 'ui/Easing', + 'utils/PubSub', + 'utils/Canvas' + ], + function (resolution, edition, platform, BoxManager, Easing, PubSub, Canvas) { + + var doorImages = [], + tapeImgL = new Image(), + tapeImgR = new Image(); + + var BoxDoors = {}; + + $(function() { + BoxDoors.canvasLeft = document.getElementById("levelCanvasLeft"); + BoxDoors.canvasRight = document.getElementById("levelCanvasRight"); + + BoxDoors.canvasLeft.width = resolution.uiScaledNumber(1024) / 2 | 0; + BoxDoors.canvasRight.width = resolution.uiScaledNumber(1024) / 2 | 0; + + BoxDoors.canvasLeft.height = 320; + BoxDoors.canvasRight.height = 320; + + BoxDoors.currentIndex = BoxManager.currentBoxIndex; + BoxDoors.showTape = true; + }); + + BoxDoors.appReady = function() { + + // cache the door and tape images (which have already been preloaded) + for (var i = 0, len = edition.boxDoors.length; i < len; i++) { + var doorImg = new Image(); + doorImg.src = platform.uiImageBaseUrl + edition.boxDoors[i]; + doorImages[i] = doorImg; + } + + tapeImgL.src = platform.uiImageBaseUrl + 'leveltape_left.png'; + tapeImgR.src = platform.uiImageBaseUrl + 'leveltape_right.png'; + + BoxDoors.preRenderDoors(); + }; + + BoxDoors.preRenderDoors = function () { + var doorImg = doorImages[BoxManager.currentBoxIndex]; + var leftCtx = BoxDoors.canvasLeft.getContext('2d'); + var rightCtx = BoxDoors.canvasRight.getContext('2d'); + + leftCtx.drawImage(doorImg, 0, 0); + + rightCtx.save(); + rightCtx.translate(doorImg.width, doorImg.height); + rightCtx.rotate(Math.PI); + rightCtx.drawImage(doorImg, 0, 0); + rightCtx.restore(); + + if (BoxDoors.showTape) { + //draw the left side tape + leftCtx.drawImage( + tapeImgL, + BoxDoors.canvasLeft.width - resolution.uiScaledNumber(26), + resolution.uiScaledNumber(10) + ); + + rightCtx.drawImage( + tapeImgR, + 0, + resolution.uiScaledNumber(10) + ); + } + } + + BoxDoors.renderDoors = function (showTape, percentOpen) { + //do another prerender + if (BoxDoors.currentIndex !== BoxManager.currentBoxIndex || + BoxDoors.showTape !== showTape) { + + BoxDoors.currentIndex = BoxManager.currentBoxIndex; + BoxDoors.showTape = showTape; + BoxDoors.preRenderDoors(showTape); + } + + //calculations + var p = percentOpen || 0.0, + dw = BoxDoors.canvasLeft.width, //door width + offset = dw - (dw * (1 - p)); //512 - (512 * (1 - 0.1)) + + //use css3 transformations + $(BoxDoors.canvasLeft).css("transform", "translateX(" + (-1 * offset) + "px)"); + $(BoxDoors.canvasRight).css("transform", "translateX(" + (dw + offset) + "px)"); + + }; + + BoxDoors.openDoors = function (showTape, callback, runInReverse) { + + var r = runInReverse != null ? runInReverse : false; + + var begin = Date.now(); + var dur = 750; + // Draw the door animation on the main game canvas + var ctx = document.getElementById('c').getContext('2d'); + var easing = runInReverse ? Easing.easeOutCubic : Easing.easeInOutCubic; + + function openBoxDoors() { + + var now = Date.now(), + p = now - begin, + v = easing(p, 0, 1, dur); + + if (v < 1) { + BoxDoors.renderDoors(showTape, r ? 1 - v : v, ctx); + window.requestAnimationFrame(openBoxDoors); + } else { + BoxDoors.renderDoors(showTape, r ? 0 : 1, ctx); + + if (r) { + $("#levelPanel").show(); + } + else { + $("#levelPanel").hide(); + } + + if (callback != null) callback(); + } + } + + window.requestAnimationFrame(openBoxDoors); + }; + + BoxDoors.closeDoors = function (showTape, callback) { + BoxDoors.openDoors(showTape, callback, true); + }; + + BoxDoors.closeBoxAnimation = function (callback) { + + // animating to level select + // box already closed, just needs to be taped and then redirected + var tapeRoll = $("#tapeRoll"); + var tapeSlice = $("#levelTape"); + + $('#levelResults').fadeOut(400); + tapeRoll.css("top", resolution.uiScaledNumber(0)); + tapeRoll.delay(400).fadeIn(200, function () { + + var offset = resolution.uiScaledNumber(650); + var offsetH = resolution.uiScaledNumber(553); + var b = Date.now(); + var from = parseInt(tapeRoll.css("top"), 10); + var fromH = resolution.uiScaledNumber(63); + var d = 1000; + + tapeSlice.css("height", fromH); + tapeSlice.show(); + + function rollTape() { + var now = Date.now(), + diff = now - b, + v = Easing.easeInOutCubic(diff, from, offset - from, d), + vH = Easing.easeInOutCubic(diff, fromH, offset - fromH, d); + + tapeRoll.css("top", v); + tapeSlice.css("height", vH); + + if (diff < d) { + window.requestAnimationFrame(rollTape); + } else { + // hide the tape slice and re-render the doors with tape + tapeSlice.hide(); + BoxDoors.renderDoors(true); + + //fade out tape and switch panels + tapeRoll.fadeOut(400, function () { + setTimeout(callback, 200); + }); //end fadeOut + } // end if/else + } // end rollTape + + window.requestAnimationFrame(rollTape); + + }); + }; + + BoxDoors.openBoxAnimation = function(callback) { + + // make sure the doors are rendered closed initially + BoxDoors.renderDoors(true, 0); + + // make sure the gradient (time edition) is removed + BoxDoors.hideGradient(); + + //cut box open with boxCutter + var boxCutter = $("#boxCutter"); + boxCutter.css("top", resolution.uiScaledNumber(371)); + boxCutter.delay(200).fadeIn(200, function () { + + var offset = resolution.uiScaledNumber(-255); + var b = Date.now(); + var from = parseInt(boxCutter.css("top"), 10); + var d = 1000; + + function cutBox() { + var now = Date.now(), + diff = now - b, + v = Easing.easeInOutCubic(diff, from, offset - from, d); + + boxCutter.css("top", v); + + if (diff < d) { + window.requestAnimationFrame(cutBox); + } else { + //fade out cutter and open doors + boxCutter.fadeOut(300, callback); //end fadeOut + } // end if/else + } // end cutBox + + window.requestAnimationFrame(cutBox); + + }); + }; + + BoxDoors.showGradient = function() {}; + BoxDoors.hideGradient = function() {}; + + return BoxDoors; + } +); + +define('ui/TimePasswordPanel', + [ + 'ui/PanelId', + 'ui/Panel', + 'ui/Easing', + 'utils/PubSub', + 'game/CTRSoundMgr', + 'visual/Text', + 'ui/TimeBox', + 'Doors', + 'edition', + 'ui/QueryStrings' + ], + function (PanelId, Panel, Easing, PubSub, SoundMgr, Text, TimeBox, Doors, edition, QueryStrings) { + + var TimePasswordPanel = new Panel(PanelId.PASSWORD, "codePanel", "levelBackground", false), + $message = null, + $codeText = null, + $okButton = null, + $backButton = null; + + TimePasswordPanel.isGameLocked = function() { + + if (!edition.enablePasswordPanel) { + return false; + } + + // see if the first box is locked + return TimeBox.isLocked(0) && !QueryStrings.unlockAllBoxes; + }; + + // dom ready events + $(function() { + + var validating = false; + + $message = $('#codeMessage'); + $codeText = $('#codeText'); + $okButton = $('#codeOkButton'); + $backButton = $('#codeBack').toggle(!TimePasswordPanel.isGameLocked()); + + function setMessageHtml(html) { + + $message.html(html); + + // for some reason, chrome isn't rendering the text when its first set + // we need to do something to trigger layout, so its shown properly + var width = $message.width(); + $message.width(width + 1); + $message.width(width - 1); + } + + var showValidatingMessage = false; + function pulseWhileValidating() { + if (!validating) { + showValidatingMessage = false; + return; + } + + showValidatingMessage = !showValidatingMessage; + setMessageHtml(showValidatingMessage ? 'Validating code . . .' : ''); + setTimeout(pulseWhileValidating, showValidatingMessage ? 600 : 250); + } + + function validationComplete(boxIndex, isValid) { + validating = false; + $codeText.attr('disabled', false); + + if (!isValid) { + setMessageHtml('Sorry, that code is not valid or
has already been redeemed.'); + } else { + setMessageHtml('Code Accepted!'); + + // have any boxes been unlocked? + var isFirstUnlock = true, + i, len; + for (i = 0, len = edition.boxes.length; i < len; i++) { + if (!TimeBox.isLocked(i)) { + isFirstUnlock = false; + break; + } + } + + // unlock all the boxes + for (var i = boxIndex; i >= 0; i--) { + TimeBox.unlockBox(i); + } + + // back button is initially hidden, show it once the game + // has been unlocked (but wait until the panel fades out) + $backButton.delay(3000).show(0); + + // reload the boxes + PubSub.publish(PubSub.ChannelId.BoxesUnlocked, isFirstUnlock); + } + } + + function validateCode() { + // make sure we are not currently validating a code + if (validating) { + return; + } + + // make sure the code is a integer within the valid range + var numBoxes = edition.boxes.length, + codeString = $codeText.val() || '', + firstDigit = codeString.length > 0 ? (parseInt(codeString[0], 10) || 0) : 0, + code = parseInt(codeString, 10); + if (isNaN(code) || code < 0 || firstDigit < 1 || firstDigit > numBoxes) { + setMessageHtml('Oops, that is not a valid code!'); + return; + } + + // find the last unlocked box + for (var lastUnlockedIndex = numBoxes - 1; lastUnlockedIndex >= 0; lastUnlockedIndex--) { + if (!TimeBox.isLocked(lastUnlockedIndex)) { + break; + } + } + + // codes start with the box number + var codeIndex = firstDigit - 1; + if (codeIndex <= lastUnlockedIndex) { + setMessageHtml('Levels for that code have already been unlocked!
' + + 'Visit Burger King each week to get a
new code that will unlock additional levels.'); + return; + } + + // start the validation mode + $codeText.attr('disabled', true); + validating = true; + pulseWhileValidating(); + + $.ajax({ + type: 'POST', + url: 'http://ctrbk.cloudapp.net/api/CTRBKCodes', + contentType: 'application/json', + data: '{"ctrbkcode":"'+ code + '"}', + dataType: 'json', + error: function(jqXHR, textStatus, errorThrown) { + //console.log('error'); + validationComplete(codeIndex, false); + }, + success: function(data, textStatus, jqXHR) { + //console.log('success'); + validationComplete(codeIndex, true); + } + }); + } + + // validate when user hits ENTER in textbox + $codeText.keyup(function(e) { + if(e.which == 13){ + validateCode(); + } else { + // otherwise clear any existing messages + setMessageHtml(''); + } + }); + + // or when the click the ok button + $okButton.click(function () { + validateCode(); + }); + + }); + + var im; + TimePasswordPanel.init = function(interfaceManager) { + im = interfaceManager; + }; + + TimePasswordPanel.onShow = function() { + $message.text(''); + $codeText.val('').focus(); + Doors.renderDoors(false, 0); + Doors.showGradient(); + }; + + TimePasswordPanel.onHide = function() { + Doors.hideGradient(); + }; + + return TimePasswordPanel; + } +); +define('ui/PanelManager', + [ + 'ui/PanelId', + 'ui/Panel', + 'ui/BoxPanel', + 'ui/LevelPanel', + 'ui/TimePasswordPanel', + 'resolution', + 'platform', + 'ui/Easing', + 'utils/PubSub', + 'edition' + ], + function (PanelId, Panel, BoxPanel, LevelPanel, PasswordPanel, resolution, platform, Easing, PubSub, edition) { + + var PanelManager = new function () { + + var _this = this, + panels = []; + + this.onShowPanel = null; + + this.domReady = function () { + fadeToBlack = $("#fadeToBlack"); + + // shadowCanvas = document.getElementById('shadowCanvas'); + // shadowCanvas.width = resolution.uiScaledNumber(1024); + // shadowCanvas.height = resolution.uiScaledNumber(576); + }; + + this.appReady = function (onInitializePanel) { + // we have to wait until the game is ready to run before initializing + // panels because we need the fonts to be loaded + + shadowImage = new Image(); + shadowImage.src = platform.uiImageBaseUrl + 'shadow.png'; + + // initialize each of the panels + if (onInitializePanel) { + for (var i = 0, len = panels.length; i < len; i++) { + onInitializePanel(panels[i].id); + } + } + }; + + // get a panel by id + var getPanelById = this.getPanelById = function (panelId) { + for (var i = 0; i < panels.length; i++) { + if (panels[i].id == panelId) return panels[i]; + } + return null; + }; + + // create our panels + panels.push(new Panel(PanelId.MENU, "menuPanel", "startBackground", true)); + panels.push(BoxPanel); + panels.push(LevelPanel); + + // the game panel re-uses the panel doors in the levelBackground (actually in foreground) + panels.push(new Panel(PanelId.GAME, null, "levelBackground", false)); + panels.push(new Panel(PanelId.GAMEMENU, null, null, false)); + panels.push(new Panel(PanelId.LEVELCOMPLETE, null, null, false)); + panels.push(new Panel(PanelId.GAMECOMPLETE, "gameCompletePanel", "menuBackground", true)); + panels.push(new Panel(PanelId.OPTIONS, "optionsPanel", "menuBackground", true)); + panels.push(new Panel(PanelId.CREDITS, null, null, false)); + panels.push(new Panel(PanelId.LEADERBOARDS, "leaderboardPanel", "menuBackground", true)); + panels.push(new Panel(PanelId.ACHIEVEMENTS, "achievementsPanel", "menuBackground", true)); + panels.push(PasswordPanel); + + this.currentPanelId = PanelId.MENU; + + // show a panel by id + this.showPanel = function (panelId, skipFade) { + + _this.currentPanelId = panelId; + + var panel = getPanelById(panelId); + var skip = skipFade == null ? false : skipFade; + + // enable / disable the shadow animation + // if (panel.showShadow) { + // showShadow(); + // } + // else { + // hideShadow(); + // } + + + // we always use a timeout, even if we skip the animation, to keep the code clean + var timeout = skip ? 0 : fadeInDur + fadePause; + setTimeout(function () { + + // show the panel + if (panel.bgDivId) { $("#" + panel.bgDivId).show(); } + if (panel.panelDivId) { $("#" + panel.panelDivId).show(); } + + // hide other panels + for (var i = 0; i < panels.length; i++) { + var otherPanel = panels[i]; + + if (otherPanel.panelDivId != null && otherPanel.panelDivId != panel.panelDivId) { + $("#" + otherPanel.panelDivId).hide(); + } + + if (otherPanel.bgDivId != null && otherPanel.bgDivId != panel.bgDivId) { + $("#" + otherPanel.bgDivId).hide(); + } + } + + // run the "show" handler + if (_this.onShowPanel != null) { + _this.onShowPanel(panelId); + } + + // fade back in + if (!skip) { + _this.runBlackFadeOut(); + } + + }, timeout); + + // start the animation + if (!skip) { + _this.runBlackFadeIn(); + } + }; + + // fade parameters + var fadeInDur = 100; + var fadePause = 50; + var fadeOutDur = 100; + var fadeTo = 1.0; + var fadeToBlack; + var isFading = false; + + this.runBlackFadeIn = function (callback) { + isFading = true; + var b = Date.now(); + + // reset the overlay + fadeToBlack.css('opacity', 0); + fadeToBlack.css('display', 'block'); + + // our loop + function loop() { + + var now = Date.now(), + diff = now - b, + v = Easing.noEase(diff, 0, fadeTo, fadeInDur); + + fadeToBlack.css('opacity', v); + + if (diff < fadeInDur) { + window.requestAnimationFrame(loop); + } else { + fadeToBlack.css('opacity', fadeTo); + if (callback != null) callback(); + } + } + + window.requestAnimationFrame(loop); + }; + + this.runBlackFadeOut = function () { + if (!isFading) return; + var b = Date.now(); + + // our loop + function loop() { + + var now = Date.now(), + diff = now - b, + v = fadeTo - Easing.noEase(diff, 0, fadeTo, fadeInDur); + + fadeToBlack.css('opacity', v); + + if (diff < fadeInDur) { + window.requestAnimationFrame(loop); + } else { + fadeToBlack.css('opacity', 0); + fadeToBlack.css('display', 'none'); + isFading = false; + } + } + + window.requestAnimationFrame(loop); + }; + + var shadowIsRotating = false; + var shadowAngle = 15.0; + var shadowCanvas = null; + var shadowImage = null; + var shadowOpacity = 1.0; + var shadowIsVisible = false; + var shadowSpeedup = edition.shadowSpeedup || 1; + + + var showShadow = function () { + if (!shadowIsVisible) { + if (shadowCanvas != null) { + var ctx = shadowCanvas.getContext('2d'); + ctx.save(); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, shadowCanvas.width, shadowCanvas.height); + ctx.restore(); + } + + shadowOpacity = 0.0; + shadowIsVisible = true; + + $('#shadowPanel').show(); + if (!shadowIsRotating) { + beginRotateShadow(); + } + } + }; + + var hideShadow = function () { + shadowIsVisible = false; + shadowIsRotating = false; + $('#shadowPanel').hide(); + }; + + // starts the shadow animation + var beginRotateShadow = function () { + var ctx = shadowCanvas.getContext('2d'), + requestAnimationFrame = window['requestAnimationFrame'], + lastRotateTime = Date.now(), + renderShadow = function() { + + if (!shadowIsRotating) { + return; + } + + // move .1 radians every 25 msec + var now = Date.now(), + delta = now - lastRotateTime; + shadowAngle += delta * 0.1 / 25 * shadowSpeedup; + lastRotateTime = now; + + // clear the canvas + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, shadowCanvas.width, shadowCanvas.height); + + // update opacity + if (shadowOpacity < 1.0) { + shadowOpacity += 0.025; + shadowOpacity = Math.min(shadowOpacity, 1.0); + ctx.globalAlpha = shadowOpacity; + } + + // rotate the context + ctx.save(); + ctx.translate(shadowImage.width * 0.5, shadowImage.height * 0.5); + ctx.translate(resolution.uiScaledNumber(-300), resolution.uiScaledNumber(-510)); + ctx.rotate(shadowAngle * Math.PI / 180); + ctx.translate(-shadowImage.width * 0.5, -shadowImage.height * 0.5); + + // draw the image and update the loop + ctx.drawImage(shadowImage, 0, 0); + ctx.restore(); + + requestAnimationFrame(renderShadow); + }; + + shadowIsRotating = true; + renderShadow(); + }; + }; + + PubSub.subscribe(PubSub.ChannelId.BoxesUnlocked, function(isFirstUnlock) { + + var nextPanelId = isFirstUnlock ? PanelId.MENU : PanelId.BOXES; + + // switch back to the boxes panel after a short delay + setTimeout(function() { + PanelManager.showPanel(nextPanelId); + }, 1000); + }); + + return PanelManager; + } +); +define('ui/SocialHelper', + [ + 'platform', + 'edition', + 'resources/Lang', + 'resources/MenuStringId', + 'utils/PubSub', + 'analytics' + ], + function (platform, edition, Lang, MenuStringId, PubSub, analytics) { + + var SocialHelper = new function () { + + this.siteUrl = edition.siteUrl; + + // cuttherope.ie and cuttherope.net + this.appId = '278847552173744'; + + // check for test domain (seperate FB app ids) + var host = window.location.host || ''; + if (host.indexOf('thinkpixellab') >= 0) { + // thinkpixellab.com + this.appId = '239041062884795'; + } else if (host.indexOf('.dev') >= 0) { + // ctr-net.dev + this.appId = '261043477350153'; + } + + // listen to language changes + var self = this; + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + self.siteDescription = Lang.menuText(MenuStringId.SITE_DESC); + self.siteName = Lang.menuText(MenuStringId.SITE_TITLE); + self.siteActions = [ + { + name: Lang.menuText(MenuStringId.SITE_ACTION), + link: edition.siteUrl + } + ]; + }); + + this.initFB = function () { + + // NOTE: must create settings this way to prevent obfuscation + var fbInitSettings = {}; + fbInitSettings['appId'] = self.appId; + fbInitSettings['status'] = true; + fbInitSettings['cookie'] = true; + fbInitSettings['xfbml'] = true; + FB.init(fbInitSettings); + + // report facebook likes + FB.Event.subscribe('edge.create', function (response) { + if (analytics.onFacebookLike) { + analytics.onFacebookLike(); + } + }); + }; + + // remember to return true in the callback + this.postToFeed = function (caption, description, imageurl, callback) { + + // see if the platform has custom sharing + if (platform.customSharing) { + PubSub.publish(PubSub.ChannelId.Share, caption, description, imageurl); + } else { + // otherwise, we'll default to using facebook + + // NOTE: must create settings this way to prevent obfuscation + var publish = {}; + publish['method'] = 'feed'; + publish['name'] = self.siteName; + publish['caption'] = caption; + publish['description'] = description; + publish['link'] = self.siteUrl; + publish['picture'] = imageurl; + publish['actions'] = self.siteActions; + + FB.ui(publish, callback); + } + }; + + this.initTwitter = function (twttr) { + // report tweets from users + twttr['events']['bind']('tweet', function (event) { + if (analytics.onTweet) { + analytics.onTweet(); + } + }); + }; + + }; + + return SocialHelper; + } +); + +define('ui/EasterEggManager', + [ + 'visual/Text', + 'ui/SocialHelper', + 'platform', + 'resolution', + 'analytics', + 'ui/Easing', + 'utils/PubSub', + 'game/CTRRootController', + 'resources/Lang', + 'resources/MenuStringId' + ], + function (Text, SocialHelper, platform, resolution, analytics, Easing, PubSub, RootController, Lang, MenuStringId) { + + var EasterEggManager = function () { + + var devCanvas, canvas, + scaleTo = resolution.uiScaledNumber(2.2); + + this.domReady = function () { + + canvas = document.getElementById("e"); + canvas.width = resolution.uiScaledNumber(1024); + canvas.height = 320; + + devCanvas = document.getElementById("moreCanvas"); + if (devCanvas) { + devCanvas.width = 51; + devCanvas.height = 51; + } + + // event handlers + $('#dshareBtn').click(function () { + + SocialHelper.postToFeed( + Lang.menuText(MenuStringId.SHARE_DRAWING), + SocialHelper.siteDescription, + platform.getDrawingBaseUrl() + "drawing" + drawingNum + ".jpg", + function () { + closeDrawing(); + return true; + }); + + return false; // cancel bubbling + }); + + $('#d').click(function () { + closeDrawing(); + }); + + + $('#moreLink') + .mouseenter(function () { + if (!omNomShowing) { + omNomShowing = true; + showDevLinkOmNom(function () { + omNomShowing = false; + }); + } + }) + .click(function () { + Analytics.atlasAction('SMG_MRTINX_CTR_SITE_BehindtheScenes'); + }); + }; + + this.appReady = function () { + // setup (choosing not to use PanelManager for now because of the fade in animation) + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + Text.drawBig({ text: Lang.menuText(MenuStringId.FOUND_DRAWING), imgId: 'dmsg', scaleToUI: true }); + Text.drawBig({ text: Lang.menuText(MenuStringId.SHARE), imgSel: '#dshareBtn img', scaleToUI: true}); + }); + + PubSub.subscribe(PubSub.ChannelId.OmNomClicked, this.showOmNom); + PubSub.subscribe(PubSub.ChannelId.DrawingClicked, this.showDrawing); + }; + + // ------------------------------------------------------------------------ + // Drawings + // ------------------------------------------------------------------------ + + // show a drawing + var drawingNum = null; + this.showDrawing = function (drawingIndex) { + drawingNum = drawingIndex + 1; + RootController.pauseLevel(); + + $('#gameBtnTray').hide(); + + $('#dpic').addClass('drawing' + drawingNum); + + // setup the scene + $("#dframe").animate({ top: resolution.uiScaledNumber(100), scale: 0.35 }, 0); + $("#dframe").fadeTo(0, 0); + $("#dmsg").animate({ top: resolution.uiScaledNumber(60), scale: 0.5 }, 0); + $("#dmsg").fadeTo(0, 0); + $("#dshareBtn").fadeTo(0, 0); + + // fade in the background (quickly) + $("#d").fadeIn(100, function () { + $("#dframe").fadeTo(0, 1); + $("#dmsg").fadeTo(0, 1); + $("#dframe").animate({ top: 0, scale: 1.0 }, 350, "easeOutBack"); + $("#dmsg").animate({ top: 0, scale: 1.0 }, 350, "easeOutBack"); + $("#dshareBtn").delay(600).fadeTo(200, 1.0); + }); + }; + + var closeDrawing = function () { + $('#dpic').removeClass(); // clear the drawing + $("#dframe").animate({ top: resolution.uiScaledNumber(50), scale: 0.2 }, 350, "easeInExpo"); + $("#dmsg").animate({ top: resolution.uiScaledNumber(50), scale: 0.2 }, 350, "easeInExpo"); + $("#dshareBtn").fadeTo(200, 0); + $("#d").delay(200).fadeOut(200, function () { + RootController.resumeLevel(); + drawingNum = null; + $('#gameBtnTray').show(); + }); + }; + + // ------------------------------------------------------------------------ + // Om Nom + // ------------------------------------------------------------------------ + + // mouse over for dev link + var omNomShowing = false; + + var showDevLinkOmNom = function (onComplete) { + + var ctx = devCanvas.getContext("2d"); + var begin = Date.now(); + var sx = 0.1; + var sy = 0.1; + var tx = 0; + var ty = 0; + var l = 0; + var r = 0; + var dur = 800; + + var sxbegin = sx; + var sybegin = sy; + + var txbegin = tx; + var tybegin = ty; + + var s1 = 600; + var s2 = 400 + s1; + var s3 = 600 + s2; + var s4 = 700 + s3; + var s5 = 500 + s4; + var s6 = 800 + s5; + + var mod = 0; + var modflag = false; + var modt = null; + + function step() { + + var now = Date.now(), + t = now - begin; + + // zoom up OmNom + if (t < s1) { + sy = 0 - Easing.easeOutBounce(t, 0, 100, s1, 1.5); + } + + // move his eyes left + else if (t < s2) { + if (t > s1 + 100) { // delay; + l = -1 * Easing.easeOutExpo(t - (s1 + 100), 0, 10, s2 - (s1 + 100)); + r = l; + } + } + + // move his eyes right + else if (t < s3) { + l = -10 + Easing.easeInOutExpo(t - s2, 0, 20, s3 - s2); + r = l; + } + + // move his eyes back + else if (t < s4) { + if (t > s3 + 100) { // delay; + l = 10 - Easing.easeInOutExpo(t - (s3 + 100), 0, 10, s4 - (s3 + 100)); + r = l; + } + } + else if (t < s5) { + + } + // hide omnom + else if (t < s6) { + ty = Easing.easeOutExpo(t - s5, txbegin, 50, s6 - s5); + } + + if (t > s1 && t < s3) { + mod = Easing.easeInOutBounce(t - s1, 0, 0.02, s3 - s1, 6.0); + } + + if (t > s3 && t < s5) { + mod = 0.02 - Easing.easeInOutBounce(t - s3, 0, 0.02, s5 - s3, 2.0); + } + + // position in the canvas + var mx = 0 + tx; + var my = 75 + ty + sy; + + ctx.save(); + ctx.rotate(30 * Math.PI / 180); + drawOmNom(ctx, 0.32, 0.32 + mod, mx, my, l, r); + ctx.restore(); + + // get the next frame + if (t < s6) { + window.requestAnimationFrame(step); + } + else { + onComplete(); + } + } + + window.requestAnimationFrame(step); + }; + + this.showOmNom = function () { + + var ctx = canvas.getContext("2d"); + + RootController.pauseLevel(); + + $("#e").fadeIn(function () { + + var begin = Date.now(); + var sx = 0.1; + var sy = 0.1; + var tx = 0; + var ty = 0; + var l = 0; + var r = 0; + var dur = 800; + + var sxbegin = sx; + var sybegin = sy; + + var txbegin = tx; + var tybegin = ty; + + var s1 = 600; + var s2 = 400 + s1; + var s3 = 600 + s2; + var s4 = 700 + s3; + var s5 = 500 + s4; + var s6 = 800 + s5; + + var mod = 0; + var modflag = false; + var modt = null; + + function step() { + + var now = Date.now(), + t = now - begin; + + // zoom in OmNom + if (t < s1) { + sx = Easing.easeOutBounce(t, sxbegin, scaleTo, s1, 1.5); + sy = Easing.easeOutBounce(t, sybegin, scaleTo, s1, 1.5); + } + + // move his eyes left + else if (t < s2) { + if (t > s1 + 100) { // delay; + l = -1 * Easing.easeOutExpo(t - (s1 + 100), 0, resolution.uiScaledNumber(10), + s2 - (s1 + 100)); + r = l; + } + + } + + // move his eyes right + else if (t < s3) { + l = resolution.uiScaledNumber(-10) + Easing.easeInOutExpo(t - s2, 0, + resolution.uiScaledNumber(20), s3 - s2); + r = l; + } + + // move his eyes back + else if (t < s4) { + if (t > s3 + 100) { // delay; + l = resolution.uiScaledNumber(10) - Easing.easeInOutExpo(t - (s3 + 100), 0, + resolution.uiScaledNumber(10), s4 - (s3 + 100)); + r = l; + } + } + else if (t < s5) { + + } + // hide omnom + else if (t < s6) { + ty = Easing.easeOutExpo(t - s5, txbegin, resolution.uiScaledNumber(300), s6 - s5); + sx = resolution.uiScaledNumber(scaleTo) - Easing.easeOutExpo(t - s5, 0, + resolution.uiScaledNumber(2.0), s1, s6 - s5); + sy = resolution.uiScaledNumber(scaleTo) - Easing.easeOutExpo(t - s5, 0, + resolution.uiScaledNumber(2.0), s1, s6 - s5); + } + + if (t > s1 && t < s3) { + mod = Easing.easeInOutBounce(t - s1, 0, 0.1, s3 - s1, 6.0); + } + + if (t > s3 && t < s5) { + mod = 0.1 - Easing.easeInOutBounce(t - s3, 0, 0.1, s5 - s3, 2.0); + } + + // get the next frame + if (t < s6) { + window.requestAnimationFrame(step); + } + else { + $("#e").fadeOut(); + RootController.resumeLevel(); + } + + // position in the canvas + var mx = tx + (resolution.uiScaledNumber(500) - (sx / scaleTo * resolution.uiScaledNumber(200))); + var my = ty + (resolution.uiScaledNumber(600) - (sy / scaleTo * resolution.uiScaledNumber(400))); + + drawOmNom(ctx, sx, sy + mod, mx, my, l, r); + + + } + + window.requestAnimationFrame(step); + + }); + }; + + var drawOmNom = function (ctx, scaleX, scaleY, translateX, translateY, leftEyeOffset, rightEyeOffset) { + + // clear the canvas + ctx.save(); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); + ctx.restore(); + + // set the scale and translate to keep OmNom in the right location on the canvas + ctx.save(); + ctx.translate(translateX, translateY); + ctx.scale(scaleX, scaleY); + + + // omnom/dark + ctx.save(); + ctx.beginPath(); + + // omnom/dark/Path + ctx.moveTo(116.1, 38.3); + ctx.bezierCurveTo(117.2, 37.9, 118.2, 37.4, 119.0, 36.8); + ctx.lineTo(119.5, 35.6); + ctx.lineTo(123.3, 21.1); + ctx.bezierCurveTo(124.5, 18.2, 126.8, 14.6, 130.1, 10.3); + ctx.bezierCurveTo(129.9, 15.3, 133.6, 18.2, 141.3, 19.0); + ctx.bezierCurveTo(138.9, 19.1, 136.7, 19.9, 134.8, 21.5); + ctx.bezierCurveTo(132.4, 23.5, 130.7, 25.2, 129.7, 26.8); + ctx.bezierCurveTo(128.9, 28.3, 127.9, 30.7, 126.7, 33.8); + ctx.lineTo(126.4, 36.8); + ctx.lineTo(126.7, 37.7); + ctx.lineTo(128.6, 38.7); + ctx.bezierCurveTo(124.4, 37.5, 120.2, 37.4, 116.1, 38.3); + ctx.closePath(); + + // omnom/dark/Path + ctx.moveTo(241.8, 203.6); + ctx.bezierCurveTo(241.6, 202.9, 241.1, 202.2, 240.5, 201.5); + ctx.lineTo(214.2, 185.6); + ctx.bezierCurveTo(212.8, 190.0, 210.9, 194.2, 208.4, 198.1); + ctx.lineTo(208.3, 198.0); + ctx.lineTo(209.4, 192.8); + ctx.lineTo(211.0, 183.6); + ctx.lineTo(211.2, 182.6); + ctx.lineTo(212.8, 173.3); + ctx.bezierCurveTo(212.3, 176.0, 211.3, 179.0, 210.0, 182.1); + ctx.bezierCurveTo(209.9, 182.4, 209.8, 182.6, 209.7, 182.8); + ctx.bezierCurveTo(208.6, 185.2, 207.3, 187.8, 205.8, 190.5); + ctx.bezierCurveTo(203.4, 194.6, 200.9, 197.9, 198.1, 200.4); + ctx.bezierCurveTo(198.7, 201.8, 199.0, 203.2, 199.2, 204.7); + ctx.bezierCurveTo(199.2, 204.8, 199.2, 204.9, 199.2, 205.0); + ctx.bezierCurveTo(199.5, 207.9, 199.6, 209.6, 199.7, 210.2); + ctx.bezierCurveTo(200.0, 211.2, 200.1, 212.0, 200.2, 212.5); + ctx.lineTo(199.6, 207.8); + ctx.bezierCurveTo(201.8, 213.8, 203.3, 218.7, 204.0, 222.5); + ctx.bezierCurveTo(205.3, 222.4, 206.5, 222.4, 207.7, 222.3); + ctx.bezierCurveTo(213.4, 222.0, 218.9, 221.9, 224.3, 222.1); + ctx.bezierCurveTo(227.5, 222.5, 230.1, 222.1, 232.3, 221.1); + ctx.bezierCurveTo(232.8, 220.7, 233.4, 220.2, 233.9, 219.6); + ctx.bezierCurveTo(235.2, 218.1, 236.5, 216.5, 237.8, 215.0); + ctx.bezierCurveTo(239.1, 213.3, 240.1, 211.5, 240.9, 209.6); + ctx.bezierCurveTo(241.8, 207.4, 242.1, 205.4, 241.8, 203.6); + ctx.closePath(); + + // omnom/dark/Path + ctx.moveTo(148.8, 222.8); + ctx.bezierCurveTo(139.8, 224.7, 129.5, 225.7, 117.8, 225.9); + ctx.bezierCurveTo(109.6, 226.0, 101.7, 225.5, 94.3, 224.3); + ctx.bezierCurveTo(94.3, 224.9, 94.4, 225.6, 94.4, 226.2); + ctx.bezierCurveTo(94.4, 228.1, 94.3, 230.0, 94.0, 232.0); + ctx.lineTo(93.8, 233.0); + ctx.bezierCurveTo(103.6, 234.6, 113.4, 235.1, 123.2, 234.4); + ctx.bezierCurveTo(132.2, 234.4, 141.0, 233.2, 149.5, 231.0); + ctx.bezierCurveTo(149.4, 230.6, 149.4, 230.3, 149.4, 230.0); + ctx.bezierCurveTo(149.0, 227.6, 148.9, 225.2, 148.8, 222.8); + ctx.closePath(); + + // omnom/dark/Path + ctx.moveTo(196.6, 153.6); + ctx.lineTo(194.5, 152.6); + ctx.bezierCurveTo(194.1, 152.8, 193.8, 153.0, 193.4, 153.2); + ctx.bezierCurveTo(192.6, 153.8, 191.7, 154.5, 191.0, 155.2); + ctx.lineTo(190.2, 155.8); + ctx.bezierCurveTo(186.6, 158.8, 183.8, 160.7, 182.0, 161.5); + ctx.bezierCurveTo(182.0, 162.2, 181.4, 164.0, 180.2, 166.7); + ctx.bezierCurveTo(183.2, 164.8, 186.2, 162.7, 189.3, 160.6); + ctx.bezierCurveTo(192.6, 158.2, 195.6, 155.9, 198.4, 153.8); + ctx.bezierCurveTo(197.6, 153.8, 197.0, 153.7, 196.6, 153.6); + ctx.closePath(); + + // omnom/dark/Path + ctx.moveTo(121.1, 189.0); + ctx.bezierCurveTo(128.0, 188.9, 134.8, 188.0, 141.7, 186.0); + ctx.bezierCurveTo(141.3, 185.9, 141.0, 185.7, 140.7, 185.6); + ctx.bezierCurveTo(136.2, 183.2, 133.0, 181.8, 131.3, 181.4); + ctx.bezierCurveTo(128.8, 181.8, 125.7, 181.8, 121.9, 181.4); + ctx.bezierCurveTo(118.1, 181.0, 114.0, 180.5, 109.4, 179.7); + ctx.lineTo(109.3, 179.7); + ctx.bezierCurveTo(108.3, 180.9, 106.5, 182.5, 103.8, 184.6); + ctx.bezierCurveTo(103.6, 184.7, 103.4, 184.9, 103.2, 185.0); + ctx.lineTo(102.1, 185.9); + ctx.lineTo(102.9, 186.1); + ctx.bezierCurveTo(110.1, 188.1, 116.2, 189.0, 121.1, 189.0); + ctx.closePath(); + + // omnom/dark/Path + ctx.moveTo(63.1, 164.7); + ctx.lineTo(50.7, 157.9); + ctx.lineTo(45.8, 159.6); + ctx.lineTo(46.2, 159.9); + ctx.bezierCurveTo(46.3, 160.0, 46.4, 160.1, 46.5, 160.2); + ctx.bezierCurveTo(52.0, 164.0, 57.9, 167.5, 64.4, 170.9); + ctx.lineTo(65.5, 171.5); + ctx.lineTo(65.2, 170.7); + ctx.bezierCurveTo(64.0, 168.0, 63.4, 166.0, 63.1, 164.7); + ctx.closePath(); + + // omnom/dark/Path + ctx.moveTo(36.5, 191.7); + ctx.bezierCurveTo(35.2, 189.5, 34.0, 187.3, 33.0, 185.0); + ctx.lineTo(33.1, 185.9); + ctx.lineTo(34.0, 192.4); + ctx.lineTo(31.3, 189.4); + ctx.bezierCurveTo(30.8, 188.0, 27.8, 189.3, 22.4, 193.3); + ctx.bezierCurveTo(16.9, 197.2, 13.7, 199.6, 12.7, 200.6); + ctx.bezierCurveTo(11.6, 201.6, 10.2, 202.9, 8.4, 204.6); + ctx.bezierCurveTo(6.7, 206.1, 5.4, 207.3, 4.5, 208.2); + ctx.bezierCurveTo(3.6, 209.0, 3.2, 210.1, 3.3, 211.5); + ctx.bezierCurveTo(3.5, 212.9, 4.0, 214.8, 4.8, 217.3); + ctx.bezierCurveTo(5.6, 219.7, 6.5, 221.8, 7.4, 223.5); + ctx.bezierCurveTo(8.3, 225.2, 9.8, 226.4, 11.9, 227.1); + ctx.bezierCurveTo(13.9, 227.7, 15.9, 227.9, 17.8, 227.7); + ctx.bezierCurveTo(19.7, 227.5, 21.3, 227.4, 22.6, 227.4); + ctx.bezierCurveTo(24.5, 227.3, 26.4, 227.2, 28.4, 227.2); + ctx.bezierCurveTo(30.2, 227.2, 32.0, 227.2, 33.8, 227.2); + ctx.bezierCurveTo(35.8, 227.2, 37.7, 227.2, 39.7, 227.2); + ctx.bezierCurveTo(41.2, 227.3, 42.9, 227.4, 44.5, 227.6); + ctx.bezierCurveTo(44.5, 225.9, 44.5, 223.5, 44.6, 220.3); + ctx.lineTo(44.6, 213.4); + ctx.lineTo(44.7, 207.6); + ctx.lineTo(45.1, 204.8); + ctx.lineTo(45.4, 203.0); + ctx.bezierCurveTo(45.4, 202.9, 45.4, 202.8, 45.5, 202.6); + ctx.bezierCurveTo(43.8, 201.2, 42.3, 199.7, 40.9, 198.1); + ctx.bezierCurveTo(39.3, 196.0, 37.9, 193.8, 36.5, 191.7); + ctx.closePath(); + ctx.fillStyle = "rgb(100, 150, 40)"; + ctx.fill(); + + // omnom/light + ctx.beginPath(); + + // omnom/light/Path + ctx.moveTo(212.6, 151.5); + ctx.bezierCurveTo(213.3, 158.8, 213.4, 166.1, 212.8, 173.3); + ctx.bezierCurveTo(212.3, 176.0, 211.3, 179.0, 210.0, 182.2); + ctx.bezierCurveTo(209.9, 182.4, 209.8, 182.6, 209.7, 182.8); + ctx.bezierCurveTo(208.6, 185.3, 207.3, 187.8, 205.8, 190.5); + ctx.bezierCurveTo(203.4, 194.7, 200.9, 198.0, 198.1, 200.5); + ctx.bezierCurveTo(198.7, 201.8, 199.0, 203.3, 199.2, 204.7); + ctx.bezierCurveTo(199.2, 204.8, 199.2, 204.9, 199.2, 205.1); + ctx.bezierCurveTo(199.5, 207.9, 199.6, 209.7, 199.7, 210.2); + ctx.bezierCurveTo(199.9, 214.2, 200.0, 218.2, 199.9, 222.4); + ctx.bezierCurveTo(199.9, 222.5, 199.9, 222.7, 199.9, 222.9); + ctx.bezierCurveTo(199.9, 225.0, 199.7, 227.0, 199.4, 228.8); + ctx.bezierCurveTo(199.1, 230.5, 198.7, 232.0, 198.3, 233.5); + ctx.lineTo(196.7, 235.2); + ctx.bezierCurveTo(196.6, 235.3, 196.5, 235.4, 196.3, 235.5); + ctx.bezierCurveTo(195.2, 236.4, 193.3, 237.6, 190.7, 239.2); + ctx.bezierCurveTo(188.1, 240.8, 184.5, 241.7, 179.9, 242.1); + ctx.bezierCurveTo(175.3, 242.4, 172.0, 242.5, 169.8, 242.3); + ctx.bezierCurveTo(167.8, 242.2, 165.5, 241.7, 162.9, 240.8); + ctx.bezierCurveTo(160.4, 240.0, 158.0, 238.0, 155.6, 234.8); + ctx.bezierCurveTo(155.4, 234.6, 155.3, 234.4, 155.1, 234.2); + ctx.bezierCurveTo(154.3, 233.0, 153.5, 231.6, 152.8, 230.1); + ctx.bezierCurveTo(151.9, 227.9, 151.2, 225.3, 150.7, 222.4); + ctx.bezierCurveTo(150.7, 222.2, 150.6, 222.1, 150.6, 221.9); + ctx.bezierCurveTo(149.7, 216.4, 149.3, 213.1, 149.2, 212.0); + ctx.bezierCurveTo(148.8, 215.6, 148.6, 219.2, 148.8, 222.8); + ctx.bezierCurveTo(139.8, 224.7, 129.5, 225.7, 117.8, 225.9); + ctx.bezierCurveTo(109.6, 226.0, 101.7, 225.5, 94.3, 224.3); + ctx.bezierCurveTo(94.2, 220.8, 94.0, 217.1, 93.8, 213.5); + ctx.bezierCurveTo(93.8, 214.9, 93.7, 216.0, 93.6, 216.6); + ctx.bezierCurveTo(93.5, 217.2, 93.5, 217.7, 93.4, 218.1); + ctx.bezierCurveTo(93.4, 218.5, 93.2, 219.4, 92.8, 220.9); + ctx.bezierCurveTo(92.6, 222.0, 92.3, 223.0, 92.0, 224.0); + ctx.bezierCurveTo(91.9, 224.3, 91.8, 224.6, 91.7, 224.8); + ctx.bezierCurveTo(91.3, 226.0, 90.8, 227.2, 90.2, 228.3); + ctx.bezierCurveTo(89.9, 229.0, 89.5, 229.7, 89.2, 230.4); + ctx.bezierCurveTo(88.8, 230.9, 88.4, 231.4, 88.0, 231.9); + ctx.bezierCurveTo(87.5, 232.6, 86.9, 233.2, 86.2, 233.7); + ctx.bezierCurveTo(85.8, 234.1, 85.4, 234.5, 84.9, 234.9); + ctx.bezierCurveTo(83.9, 235.6, 82.8, 236.2, 81.6, 236.7); + ctx.bezierCurveTo(80.2, 237.3, 78.7, 237.8, 77.1, 238.2); + ctx.bezierCurveTo(74.1, 238.8, 71.0, 239.1, 67.8, 239.1); + ctx.bezierCurveTo(60.2, 239.2, 53.4, 237.3, 47.4, 233.3); + ctx.bezierCurveTo(45.9, 232.5, 45.0, 231.7, 44.9, 230.9); + ctx.lineTo(44.6, 229.2); + ctx.bezierCurveTo(44.6, 228.8, 44.5, 228.3, 44.5, 227.6); + ctx.bezierCurveTo(44.5, 226.0, 44.5, 223.5, 44.6, 220.3); + ctx.lineTo(44.6, 213.4); + ctx.lineTo(44.7, 207.6); + ctx.lineTo(45.1, 204.9); + ctx.lineTo(45.4, 203.0); + ctx.bezierCurveTo(45.4, 202.9, 45.4, 202.8, 45.5, 202.7); + ctx.bezierCurveTo(43.8, 201.2, 42.3, 199.7, 40.9, 198.2); + ctx.bezierCurveTo(39.3, 196.0, 37.9, 193.9, 36.5, 191.7); + ctx.bezierCurveTo(35.2, 189.6, 34.0, 187.4, 33.0, 185.1); + ctx.lineTo(32.7, 183.5); + ctx.bezierCurveTo(31.8, 176.3, 31.0, 168.9, 30.3, 161.3); + ctx.bezierCurveTo(30.3, 161.0, 30.3, 160.7, 30.2, 160.4); + ctx.bezierCurveTo(34.5, 162.0, 39.0, 162.1, 43.8, 160.4); + ctx.bezierCurveTo(44.4, 160.2, 45.1, 159.9, 45.8, 159.6); + ctx.lineTo(46.2, 159.9); + ctx.bezierCurveTo(46.3, 160.0, 46.4, 160.1, 46.5, 160.2); + ctx.bezierCurveTo(52.0, 164.0, 57.9, 167.6, 64.4, 170.9); + ctx.lineTo(65.5, 171.5); + ctx.bezierCurveTo(66.9, 174.7, 68.3, 177.8, 69.8, 180.9); + ctx.bezierCurveTo(71.4, 184.1, 73.4, 187.0, 76.0, 189.7); + ctx.bezierCurveTo(78.5, 192.3, 81.7, 193.4, 85.5, 193.1); + ctx.bezierCurveTo(89.2, 192.6, 92.8, 191.5, 96.3, 189.7); + ctx.bezierCurveTo(98.5, 188.7, 100.4, 187.4, 102.1, 185.9); + ctx.lineTo(102.9, 186.2); + ctx.bezierCurveTo(110.1, 188.1, 116.2, 189.1, 121.1, 189.1); + ctx.bezierCurveTo(128.0, 189.0, 134.8, 188.0, 141.7, 186.1); + ctx.bezierCurveTo(142.1, 186.3, 142.6, 186.5, 143.0, 186.7); + ctx.bezierCurveTo(143.5, 186.9, 144.0, 187.1, 144.5, 187.3); + ctx.bezierCurveTo(147.1, 188.4, 149.8, 189.4, 152.5, 190.3); + ctx.bezierCurveTo(155.3, 191.3, 158.2, 191.8, 161.2, 191.8); + ctx.bezierCurveTo(164.2, 191.8, 166.7, 190.7, 168.6, 188.6); + ctx.bezierCurveTo(170.0, 187.2, 171.1, 185.7, 172.0, 184.1); + ctx.bezierCurveTo(173.4, 181.7, 174.7, 179.2, 175.9, 176.6); + ctx.bezierCurveTo(177.1, 174.0, 178.3, 171.4, 179.4, 168.8); + ctx.bezierCurveTo(179.7, 168.0, 180.0, 167.4, 180.2, 166.8); + ctx.bezierCurveTo(183.2, 164.8, 186.2, 162.8, 189.3, 160.6); + ctx.bezierCurveTo(192.6, 158.2, 195.6, 156.0, 198.4, 153.8); + ctx.bezierCurveTo(199.3, 153.8, 200.6, 153.8, 202.1, 153.6); + ctx.bezierCurveTo(204.6, 153.5, 207.0, 153.1, 209.4, 152.5); + ctx.bezierCurveTo(210.5, 152.2, 211.6, 151.8, 212.6, 151.4); + ctx.bezierCurveTo(212.6, 151.4, 212.6, 151.4, 212.6, 151.5); + ctx.closePath(); + + // omnom/light/Path + ctx.moveTo(124.3, 61.0); + ctx.bezierCurveTo(124.5, 61.3, 124.8, 61.6, 125.0, 61.9); + ctx.bezierCurveTo(133.4, 55.3, 142.8, 50.4, 153.1, 47.4); + ctx.bezierCurveTo(149.8, 46.0, 146.3, 44.6, 142.9, 43.3); + ctx.bezierCurveTo(139.9, 42.5, 137.6, 41.7, 135.8, 41.1); + ctx.bezierCurveTo(134.1, 40.4, 132.7, 40.0, 131.6, 39.8); + ctx.bezierCurveTo(130.5, 39.6, 129.5, 39.2, 128.6, 38.8); + ctx.bezierCurveTo(124.4, 37.6, 120.2, 37.4, 116.1, 38.4); + ctx.bezierCurveTo(115.7, 38.5, 115.2, 38.6, 114.8, 38.7); + ctx.bezierCurveTo(114.6, 38.8, 114.2, 38.9, 113.7, 39.0); + ctx.lineTo(106.0, 40.5); + ctx.bezierCurveTo(102.5, 41.1, 99.2, 41.9, 95.9, 42.8); + ctx.bezierCurveTo(106.9, 45.7, 116.3, 51.7, 124.3, 61.0); + ctx.closePath(); + + // omnom/light/Path + ctx.moveTo(141.3, 19.0); + ctx.lineTo(143.4, 19.0); + ctx.lineTo(144.6, 19.1); + ctx.bezierCurveTo(147.1, 19.4, 148.8, 19.2, 149.7, 18.6); + ctx.bezierCurveTo(151.7, 17.6, 152.9, 16.0, 153.3, 13.7); + ctx.bezierCurveTo(153.7, 12.1, 153.7, 10.4, 153.5, 8.6); + ctx.bezierCurveTo(152.9, 5.3, 150.9, 3.4, 147.6, 3.1); + ctx.bezierCurveTo(141.0, 2.4, 135.2, 4.8, 130.1, 10.3); + ctx.bezierCurveTo(129.9, 15.3, 133.6, 18.2, 141.3, 19.0); + ctx.closePath(); + + // omnom/light/Path + ctx.moveTo(221.0, 104.0); + ctx.bezierCurveTo(220.8, 103.3, 220.5, 102.6, 220.2, 101.9); + ctx.bezierCurveTo(219.3, 99.7, 218.2, 97.5, 216.9, 95.4); + ctx.bezierCurveTo(213.3, 89.7, 209.2, 84.5, 204.4, 79.7); + ctx.bezierCurveTo(205.4, 83.0, 205.9, 86.5, 205.9, 90.2); + ctx.bezierCurveTo(205.8, 91.2, 205.8, 92.2, 205.7, 93.2); + ctx.bezierCurveTo(205.5, 95.7, 205.1, 98.2, 204.6, 100.6); + ctx.bezierCurveTo(204.9, 102.3, 205.3, 104.3, 205.7, 106.6); + ctx.lineTo(205.7, 106.6); + ctx.bezierCurveTo(205.2, 104.4, 204.9, 102.5, 204.6, 101.0); + ctx.bezierCurveTo(204.2, 103.0, 203.6, 104.9, 203.0, 106.9); + ctx.lineTo(202.9, 106.9); + ctx.bezierCurveTo(200.6, 113.5, 197.1, 119.7, 192.3, 125.5); + ctx.bezierCurveTo(188.4, 130.0, 183.6, 133.5, 177.8, 135.9); + ctx.bezierCurveTo(169.7, 139.6, 161.7, 140.9, 153.7, 139.7); + ctx.bezierCurveTo(147.7, 138.6, 142.2, 136.2, 137.2, 132.7); + ctx.bezierCurveTo(131.7, 128.8, 126.4, 125.0, 121.3, 121.5); + ctx.lineTo(120.9, 121.3); + ctx.lineTo(120.6, 121.5); + ctx.bezierCurveTo(113.9, 128.0, 106.4, 133.2, 98.0, 137.3); + ctx.bezierCurveTo(83.7, 144.0, 70.0, 142.9, 56.8, 134.0); + ctx.bezierCurveTo(50.6, 130.0, 45.8, 125.2, 42.5, 119.7); + ctx.bezierCurveTo(38.6, 113.5, 36.7, 106.4, 36.6, 98.3); + ctx.bezierCurveTo(36.6, 93.4, 37.1, 88.7, 38.2, 84.1); + ctx.bezierCurveTo(37.7, 84.8, 37.1, 85.5, 36.6, 86.2); + ctx.bezierCurveTo(29.8, 95.7, 24.4, 105.8, 20.3, 116.5); + ctx.bezierCurveTo(20.4, 116.4, 20.4, 117.0, 20.3, 118.2); + ctx.bezierCurveTo(20.2, 119.7, 20.7, 121.1, 21.6, 122.5); + ctx.bezierCurveTo(22.2, 123.4, 23.3, 125.0, 25.0, 127.3); + ctx.lineTo(26.2, 129.3); + ctx.bezierCurveTo(26.3, 129.4, 26.4, 129.6, 26.5, 129.7); + ctx.bezierCurveTo(27.9, 131.7, 29.4, 133.7, 31.1, 135.6); + ctx.bezierCurveTo(34.0, 138.9, 37.4, 142.0, 41.1, 144.9); + ctx.bezierCurveTo(44.1, 147.2, 47.2, 149.4, 50.5, 151.6); + ctx.bezierCurveTo(52.5, 152.9, 54.7, 154.4, 57.0, 155.8); + ctx.bezierCurveTo(60.8, 158.3, 65.2, 160.8, 70.1, 163.1); + ctx.bezierCurveTo(71.0, 163.6, 72.0, 164.0, 72.9, 164.4); + ctx.bezierCurveTo(79.8, 167.5, 86.9, 170.1, 94.1, 172.2); + ctx.bezierCurveTo(101.5, 174.4, 109.0, 175.9, 116.7, 176.5); + ctx.bezierCurveTo(122.5, 177.2, 128.4, 177.1, 134.5, 176.3); + ctx.bezierCurveTo(141.6, 175.3, 147.4, 174.0, 152.0, 172.4); + ctx.bezierCurveTo(156.6, 170.7, 159.7, 169.4, 161.4, 168.4); + ctx.lineTo(181.4, 156.2); + ctx.bezierCurveTo(187.7, 152.0, 192.6, 148.2, 195.9, 144.6); + ctx.lineTo(202.9, 136.6); + ctx.lineTo(209.8, 126.7); + ctx.lineTo(211.7, 124.0); + ctx.lineTo(214.9, 119.9); + ctx.lineTo(216.7, 117.5); + ctx.bezierCurveTo(217.8, 116.3, 218.7, 115.1, 219.4, 114.0); + ctx.bezierCurveTo(219.8, 113.5, 220.1, 113.0, 220.3, 112.5); + ctx.bezierCurveTo(220.8, 111.5, 221.1, 110.5, 221.3, 109.4); + ctx.bezierCurveTo(221.5, 108.5, 221.6, 107.6, 221.6, 106.7); + ctx.bezierCurveTo(221.6, 105.8, 221.4, 104.9, 221.0, 104.0); + ctx.closePath(); + ctx.fillStyle = "rgb(153, 205, 0)"; + ctx.fill(); + + // omnom/outline + ctx.beginPath(); + + // omnom/outline/Path + ctx.moveTo(245.5, 203.6); + ctx.bezierCurveTo(245.4, 202.9, 245.3, 202.4, 245.2, 202.0); + ctx.bezierCurveTo(244.7, 200.9, 244.1, 200.1, 243.5, 199.7); + ctx.bezierCurveTo(242.9, 199.2, 241.2, 198.1, 238.5, 196.2); + ctx.bezierCurveTo(238.0, 195.9, 237.5, 195.5, 237.0, 195.2); + ctx.bezierCurveTo(234.3, 193.5, 230.8, 191.6, 226.3, 189.3); + ctx.bezierCurveTo(223.0, 187.4, 219.4, 185.7, 215.7, 184.2); + ctx.lineTo(214.7, 183.8); + ctx.bezierCurveTo(216.0, 179.3, 216.8, 174.4, 217.0, 169.3); + ctx.bezierCurveTo(217.3, 162.5, 217.5, 155.7, 217.3, 148.8); + ctx.bezierCurveTo(217.5, 148.7, 217.7, 148.6, 217.9, 148.5); + ctx.bezierCurveTo(220.1, 147.0, 221.6, 145.1, 222.5, 142.8); + ctx.bezierCurveTo(223.5, 140.2, 224.2, 137.4, 224.6, 134.6); + ctx.bezierCurveTo(224.9, 132.2, 225.0, 129.8, 225.1, 127.3); + ctx.bezierCurveTo(225.1, 124.8, 225.1, 122.4, 224.8, 119.9); + ctx.bezierCurveTo(224.8, 119.4, 224.7, 119.0, 224.6, 118.6); + ctx.lineTo(224.5, 115.9); + ctx.bezierCurveTo(225.1, 114.1, 225.4, 111.8, 225.6, 108.9); + ctx.bezierCurveTo(225.7, 107.4, 225.5, 105.8, 224.9, 104.3); + ctx.bezierCurveTo(220.3, 91.4, 212.2, 80.3, 200.6, 71.0); + ctx.bezierCurveTo(195.8, 62.6, 189.0, 55.8, 180.1, 50.6); + ctx.bezierCurveTo(172.6, 46.4, 165.2, 45.0, 157.9, 46.2); + ctx.bezierCurveTo(155.1, 45.0, 152.3, 43.9, 149.4, 42.8); + ctx.bezierCurveTo(148.1, 42.3, 146.8, 41.9, 145.5, 41.4); + ctx.bezierCurveTo(143.2, 40.6, 140.8, 39.9, 138.4, 39.2); + ctx.bezierCurveTo(136.1, 38.4, 133.8, 37.6, 131.6, 36.7); + ctx.bezierCurveTo(131.1, 36.6, 130.8, 36.3, 130.4, 36.0); + ctx.bezierCurveTo(130.1, 35.6, 129.9, 35.3, 129.8, 35.0); + ctx.bezierCurveTo(129.8, 34.3, 129.9, 33.8, 130.1, 33.5); + ctx.bezierCurveTo(130.9, 31.6, 132.7, 30.0, 135.7, 29.0); + ctx.bezierCurveTo(137.8, 27.6, 140.6, 26.5, 144.0, 25.5); + ctx.bezierCurveTo(152.1, 23.0, 156.6, 19.2, 157.4, 13.9); + ctx.bezierCurveTo(158.5, 7.2, 155.6, 2.8, 148.7, 0.7); + ctx.bezierCurveTo(141.1, -1.7, 133.2, 2.0, 125.0, 11.9); + ctx.bezierCurveTo(121.9, 15.6, 120.1, 19.0, 119.4, 22.1); + ctx.lineTo(118.6, 25.4); + ctx.bezierCurveTo(118.2, 30.0, 117.2, 33.0, 115.7, 34.5); + ctx.bezierCurveTo(114.8, 35.3, 113.3, 36.0, 111.2, 36.6); + ctx.bezierCurveTo(104.1, 37.5, 97.2, 39.2, 90.6, 41.6); + ctx.bezierCurveTo(89.4, 41.4, 88.3, 41.3, 87.1, 41.1); + ctx.bezierCurveTo(71.9, 41.6, 59.7, 47.8, 50.4, 59.6); + ctx.bezierCurveTo(46.0, 64.9, 42.7, 70.6, 40.4, 76.7); + ctx.bezierCurveTo(39.8, 77.4, 39.2, 78.1, 38.5, 78.8); + ctx.bezierCurveTo(29.4, 89.5, 22.3, 101.0, 17.2, 113.3); + ctx.bezierCurveTo(16.8, 114.3, 16.4, 115.3, 16.1, 116.3); + ctx.bezierCurveTo(15.8, 117.0, 15.6, 117.6, 15.5, 118.3); + ctx.bezierCurveTo(15.4, 118.7, 15.3, 119.1, 15.3, 119.5); + ctx.bezierCurveTo(15.2, 120.4, 15.1, 121.2, 15.2, 122.1); + ctx.bezierCurveTo(15.5, 124.5, 16.4, 127.1, 18.0, 129.6); + ctx.bezierCurveTo(18.5, 132.0, 18.6, 134.2, 18.3, 136.0); + ctx.bezierCurveTo(17.4, 144.5, 19.9, 151.6, 25.9, 157.5); + ctx.bezierCurveTo(25.9, 159.4, 26.0, 161.4, 26.1, 163.4); + ctx.bezierCurveTo(26.4, 169.1, 27.2, 175.1, 28.4, 181.4); + ctx.bezierCurveTo(28.7, 182.6, 28.9, 183.7, 29.2, 184.9); + ctx.bezierCurveTo(29.1, 184.9, 29.0, 185.0, 28.9, 185.0); + ctx.bezierCurveTo(25.6, 186.9, 22.7, 188.6, 20.2, 190.1); + ctx.bezierCurveTo(17.8, 191.7, 15.6, 193.1, 13.8, 194.4); + ctx.bezierCurveTo(12.5, 195.5, 11.1, 196.7, 9.6, 197.9); + ctx.bezierCurveTo(7.9, 199.0, 6.3, 200.4, 4.9, 201.9); + ctx.bezierCurveTo(3.7, 203.0, 2.7, 204.1, 1.7, 205.0); + ctx.bezierCurveTo(0.7, 206.0, 0.2, 207.4, 0.0, 209.2); + ctx.bezierCurveTo(-0.1, 211.0, 0.0, 212.5, 0.2, 213.8); + ctx.bezierCurveTo(0.4, 215.0, 0.9, 217.0, 1.5, 219.7); + ctx.bezierCurveTo(2.1, 222.4, 3.0, 224.6, 4.0, 226.5); + ctx.bezierCurveTo(5.1, 228.3, 6.7, 229.7, 9.0, 230.6); + ctx.bezierCurveTo(9.6, 230.8, 10.3, 231.0, 11.1, 231.2); + ctx.bezierCurveTo(14.9, 231.1, 18.6, 231.1, 22.4, 231.2); + ctx.bezierCurveTo(24.2, 231.3, 26.0, 231.5, 27.8, 231.7); + ctx.bezierCurveTo(29.4, 231.8, 31.0, 232.0, 32.7, 232.2); + ctx.bezierCurveTo(34.1, 232.3, 35.6, 232.5, 37.1, 232.6); + ctx.bezierCurveTo(38.4, 232.7, 39.8, 232.8, 41.2, 232.9); + ctx.bezierCurveTo(41.5, 232.9, 41.8, 233.0, 42.1, 233.0); + ctx.lineTo(42.2, 233.2); + ctx.bezierCurveTo(42.4, 233.8, 42.8, 234.4, 43.1, 234.8); + ctx.bezierCurveTo(48.8, 238.6, 55.0, 240.9, 61.6, 241.5); + ctx.bezierCurveTo(68.7, 242.6, 75.6, 242.3, 82.4, 240.5); + ctx.bezierCurveTo(82.5, 240.5, 82.5, 240.5, 82.6, 240.5); + ctx.bezierCurveTo(84.0, 240.2, 85.4, 239.9, 86.7, 239.6); + ctx.bezierCurveTo(88.1, 239.3, 89.3, 238.9, 90.4, 238.4); + ctx.bezierCurveTo(90.9, 238.1, 91.4, 237.8, 91.8, 237.3); + ctx.bezierCurveTo(104.5, 241.2, 118.7, 242.0, 134.5, 239.7); + ctx.bezierCurveTo(139.8, 238.9, 145.2, 237.5, 150.9, 235.6); + ctx.bezierCurveTo(151.5, 237.0, 152.2, 238.2, 153.1, 239.5); + ctx.bezierCurveTo(153.8, 240.1, 154.6, 240.7, 155.6, 241.3); + ctx.bezierCurveTo(156.9, 242.2, 158.4, 242.9, 160.2, 243.5); + ctx.bezierCurveTo(161.9, 243.8, 163.7, 244.1, 165.5, 244.5); + ctx.bezierCurveTo(171.9, 244.8, 178.0, 244.7, 183.5, 244.1); + ctx.bezierCurveTo(188.0, 243.7, 192.3, 242.6, 196.2, 240.7); + ctx.bezierCurveTo(197.0, 240.3, 197.6, 239.9, 198.3, 239.5); + ctx.bezierCurveTo(200.0, 238.4, 201.4, 237.4, 202.3, 236.5); + ctx.bezierCurveTo(203.2, 235.6, 203.9, 233.1, 204.5, 229.2); + ctx.bezierCurveTo(204.5, 229.0, 204.6, 228.7, 204.6, 228.3); + ctx.lineTo(223.4, 226.8); + ctx.bezierCurveTo(225.5, 226.6, 227.6, 226.4, 229.8, 226.3); + ctx.bezierCurveTo(232.0, 226.2, 233.8, 225.5, 235.2, 224.1); + ctx.bezierCurveTo(237.0, 222.5, 238.5, 220.8, 239.4, 219.1); + ctx.bezierCurveTo(240.4, 217.5, 241.3, 215.9, 242.2, 214.4); + ctx.bezierCurveTo(243.0, 212.9, 243.6, 211.6, 244.1, 210.5); + ctx.bezierCurveTo(244.6, 209.4, 244.9, 208.1, 245.2, 206.7); + ctx.bezierCurveTo(245.4, 205.2, 245.5, 204.2, 245.5, 203.6); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(219.9, 140.2); + ctx.bezierCurveTo(219.5, 141.6, 218.8, 143.0, 218.0, 144.5); + ctx.bezierCurveTo(217.8, 144.9, 217.6, 145.2, 217.3, 145.6); + ctx.bezierCurveTo(216.7, 146.3, 215.9, 146.9, 214.9, 147.4); + ctx.bezierCurveTo(214.1, 147.8, 213.2, 148.2, 212.3, 148.4); + ctx.bezierCurveTo(210.2, 149.1, 208.0, 149.5, 205.6, 149.5); + ctx.bezierCurveTo(204.5, 149.5, 203.4, 149.4, 202.3, 149.3); + ctx.bezierCurveTo(200.6, 148.9, 199.7, 148.0, 199.8, 146.7); + ctx.lineTo(200.7, 145.2); + ctx.bezierCurveTo(201.3, 144.3, 201.8, 143.4, 202.4, 142.5); + ctx.bezierCurveTo(202.7, 141.9, 203.0, 141.3, 203.4, 140.8); + ctx.bezierCurveTo(203.8, 140.0, 204.2, 139.2, 204.7, 138.5); + ctx.bezierCurveTo(205.3, 137.7, 205.9, 136.8, 206.5, 136.0); + ctx.bezierCurveTo(206.9, 135.5, 207.3, 135.0, 207.6, 134.5); + ctx.bezierCurveTo(208.3, 133.7, 209.0, 132.8, 209.7, 132.0); + ctx.bezierCurveTo(209.9, 131.7, 210.2, 131.4, 210.5, 131.0); + ctx.bezierCurveTo(211.0, 130.4, 211.5, 129.9, 212.1, 129.3); + ctx.bezierCurveTo(212.6, 128.8, 213.1, 128.3, 213.6, 127.8); + ctx.bezierCurveTo(214.1, 127.4, 214.6, 127.0, 215.1, 126.6); + ctx.bezierCurveTo(215.3, 126.4, 215.5, 126.3, 215.6, 126.2); + ctx.bezierCurveTo(216.8, 125.4, 217.9, 124.8, 219.0, 124.5); + ctx.lineTo(219.3, 125.4); + ctx.bezierCurveTo(220.0, 127.9, 220.5, 130.6, 220.8, 133.3); + ctx.bezierCurveTo(221.0, 135.7, 220.8, 138.0, 219.9, 140.2); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(106.0, 40.4); + ctx.lineTo(113.7, 38.9); + ctx.bezierCurveTo(114.2, 38.8, 114.6, 38.7, 114.8, 38.6); + ctx.bezierCurveTo(115.2, 38.6, 115.7, 38.4, 116.1, 38.3); + ctx.bezierCurveTo(117.2, 37.9, 118.2, 37.4, 119.0, 36.8); + ctx.lineTo(119.5, 35.6); + ctx.lineTo(123.3, 21.1); + ctx.bezierCurveTo(124.5, 18.2, 126.8, 14.6, 130.1, 10.3); + ctx.bezierCurveTo(135.2, 4.8, 141.0, 2.4, 147.6, 3.1); + ctx.bezierCurveTo(150.9, 3.4, 152.9, 5.2, 153.5, 8.5); + ctx.bezierCurveTo(153.7, 10.3, 153.7, 12.0, 153.3, 13.7); + ctx.bezierCurveTo(152.9, 15.9, 151.7, 17.6, 149.7, 18.6); + ctx.bezierCurveTo(148.8, 19.2, 147.1, 19.4, 144.6, 19.1); + ctx.lineTo(143.4, 19.0); + ctx.lineTo(141.3, 19.0); + ctx.bezierCurveTo(138.9, 19.1, 136.7, 19.9, 134.8, 21.5); + ctx.bezierCurveTo(132.4, 23.5, 130.7, 25.2, 129.7, 26.8); + ctx.bezierCurveTo(128.9, 28.3, 127.9, 30.7, 126.7, 33.8); + ctx.lineTo(126.4, 36.8); + ctx.lineTo(126.7, 37.7); + ctx.lineTo(128.6, 38.7); + ctx.bezierCurveTo(129.5, 39.2, 130.5, 39.5, 131.6, 39.8); + ctx.bezierCurveTo(132.7, 40.0, 134.1, 40.4, 135.8, 41.0); + ctx.bezierCurveTo(137.6, 41.7, 139.9, 42.4, 142.9, 43.3); + ctx.bezierCurveTo(146.3, 44.6, 149.8, 46.0, 153.1, 47.4); + ctx.bezierCurveTo(142.8, 50.4, 133.4, 55.2, 125.0, 61.8); + ctx.bezierCurveTo(124.8, 61.6, 124.5, 61.3, 124.3, 61.0); + ctx.bezierCurveTo(116.3, 51.7, 106.9, 45.6, 95.9, 42.7); + ctx.bezierCurveTo(99.2, 41.9, 102.5, 41.1, 106.0, 40.4); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(41.7, 90.1); + ctx.bezierCurveTo(42.4, 84.8, 43.6, 79.9, 45.5, 75.3); + ctx.bezierCurveTo(46.5, 72.7, 47.7, 70.1, 49.2, 67.7); + ctx.bezierCurveTo(52.7, 61.9, 57.3, 56.8, 63.0, 52.3); + ctx.bezierCurveTo(70.4, 46.7, 77.8, 43.8, 85.3, 43.7); + ctx.bezierCurveTo(87.3, 43.6, 89.3, 43.8, 91.3, 44.1); + ctx.bezierCurveTo(95.6, 44.9, 100.0, 46.5, 104.4, 49.1); + ctx.bezierCurveTo(111.9, 53.4, 117.3, 59.5, 120.8, 67.4); + ctx.lineTo(124.2, 73.8); + ctx.lineTo(124.6, 73.8); + ctx.bezierCurveTo(124.7, 73.5, 124.9, 73.2, 125.0, 72.9); + ctx.bezierCurveTo(126.3, 71.1, 127.5, 69.4, 128.6, 67.7); + ctx.bezierCurveTo(136.0, 57.6, 146.1, 51.7, 158.7, 50.1); + ctx.bezierCurveTo(158.9, 50.1, 159.1, 50.1, 159.2, 50.1); + ctx.bezierCurveTo(162.5, 50.1, 165.7, 50.5, 168.8, 51.2); + ctx.bezierCurveTo(176.5, 53.0, 183.4, 56.7, 189.4, 62.4); + ctx.bezierCurveTo(190.0, 63.0, 190.6, 63.5, 191.1, 64.1); + ctx.bezierCurveTo(193.9, 67.0, 196.1, 70.1, 197.8, 73.5); + ctx.bezierCurveTo(201.1, 79.7, 202.5, 86.8, 202.2, 94.7); + ctx.bezierCurveTo(202.0, 99.0, 201.3, 103.2, 199.9, 107.1); + ctx.bezierCurveTo(197.5, 114.2, 193.1, 120.7, 186.7, 126.4); + ctx.bezierCurveTo(177.6, 134.4, 168.3, 137.9, 158.5, 137.0); + ctx.bezierCurveTo(153.1, 136.4, 149.4, 135.6, 147.3, 134.6); + ctx.bezierCurveTo(137.6, 129.8, 130.4, 122.6, 125.6, 113.0); + ctx.bezierCurveTo(124.9, 111.7, 124.3, 110.4, 123.8, 109.0); + ctx.bezierCurveTo(123.3, 107.9, 122.9, 106.7, 122.6, 105.5); + ctx.bezierCurveTo(121.9, 106.9, 121.2, 108.3, 120.5, 109.6); + ctx.bezierCurveTo(119.7, 111.0, 118.8, 112.4, 118.0, 113.7); + ctx.bezierCurveTo(110.3, 125.2, 100.6, 132.5, 88.9, 135.6); + ctx.bezierCurveTo(75.9, 139.1, 64.3, 136.3, 54.2, 127.3); + ctx.bezierCurveTo(51.5, 124.9, 49.2, 122.2, 47.4, 119.3); + ctx.bezierCurveTo(42.2, 111.4, 40.4, 101.7, 41.7, 90.1); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(20.3, 118.2); + ctx.bezierCurveTo(20.4, 117.0, 20.4, 116.4, 20.3, 116.5); + ctx.bezierCurveTo(24.4, 105.8, 29.8, 95.7, 36.6, 86.2); + ctx.bezierCurveTo(37.1, 85.5, 37.7, 84.8, 38.2, 84.1); + ctx.bezierCurveTo(37.1, 88.6, 36.6, 93.4, 36.6, 98.3); + ctx.bezierCurveTo(36.7, 106.3, 38.6, 113.5, 42.5, 119.7); + ctx.bezierCurveTo(45.8, 125.2, 50.6, 129.9, 56.8, 134.0); + ctx.bezierCurveTo(70.0, 142.9, 83.7, 143.9, 98.0, 137.2); + ctx.bezierCurveTo(106.4, 133.2, 113.9, 127.9, 120.6, 121.5); + ctx.lineTo(120.9, 121.3); + ctx.lineTo(121.3, 121.5); + ctx.bezierCurveTo(126.4, 125.0, 131.7, 128.7, 137.2, 132.7); + ctx.bezierCurveTo(142.2, 136.2, 147.7, 138.6, 153.7, 139.7); + ctx.bezierCurveTo(161.7, 140.8, 169.7, 139.6, 177.8, 135.9); + ctx.bezierCurveTo(183.6, 133.5, 188.4, 130.0, 192.3, 125.5); + ctx.bezierCurveTo(197.1, 119.7, 200.6, 113.5, 202.9, 106.8); + ctx.bezierCurveTo(203.6, 104.8, 204.2, 102.7, 204.6, 100.6); + ctx.bezierCurveTo(205.1, 98.2, 205.5, 95.7, 205.7, 93.2); + ctx.bezierCurveTo(205.8, 92.2, 205.8, 91.1, 205.9, 90.2); + ctx.bezierCurveTo(205.9, 86.5, 205.4, 83.0, 204.4, 79.6); + ctx.bezierCurveTo(209.2, 84.5, 213.3, 89.7, 216.9, 95.4); + ctx.bezierCurveTo(218.2, 97.5, 219.3, 99.6, 220.2, 101.8); + ctx.bezierCurveTo(220.5, 102.5, 220.8, 103.3, 221.0, 104.0); + ctx.bezierCurveTo(221.4, 104.9, 221.6, 105.7, 221.6, 106.6); + ctx.bezierCurveTo(221.6, 107.6, 221.5, 108.5, 221.3, 109.4); + ctx.bezierCurveTo(221.1, 110.4, 220.8, 111.5, 220.3, 112.5); + ctx.bezierCurveTo(220.1, 113.0, 219.8, 113.5, 219.4, 114.0); + ctx.bezierCurveTo(218.7, 115.1, 217.8, 116.3, 216.7, 117.4); + ctx.lineTo(214.9, 119.9); + ctx.lineTo(211.7, 124.0); + ctx.lineTo(209.8, 126.7); + ctx.lineTo(202.9, 136.6); + ctx.lineTo(195.9, 144.6); + ctx.bezierCurveTo(192.6, 148.2, 187.7, 152.0, 181.4, 156.2); + ctx.lineTo(161.4, 168.4); + ctx.bezierCurveTo(159.7, 169.4, 156.6, 170.7, 152.0, 172.3); + ctx.bezierCurveTo(147.4, 173.9, 141.6, 175.3, 134.5, 176.2); + ctx.bezierCurveTo(128.4, 177.1, 122.5, 177.2, 116.7, 176.5); + ctx.bezierCurveTo(109.0, 175.8, 101.5, 174.4, 94.1, 172.2); + ctx.bezierCurveTo(86.9, 170.0, 79.8, 167.4, 72.9, 164.4); + ctx.bezierCurveTo(72.0, 164.0, 71.0, 163.5, 70.1, 163.1); + ctx.bezierCurveTo(65.2, 160.7, 60.8, 158.3, 57.0, 155.8); + ctx.bezierCurveTo(54.7, 154.3, 52.5, 152.9, 50.5, 151.5); + ctx.bezierCurveTo(47.2, 149.4, 44.1, 147.1, 41.1, 144.8); + ctx.bezierCurveTo(37.4, 142.0, 34.0, 138.9, 31.1, 135.5); + ctx.bezierCurveTo(29.4, 133.7, 27.9, 131.7, 26.5, 129.7); + ctx.bezierCurveTo(26.4, 129.5, 26.3, 129.4, 26.2, 129.3); + ctx.lineTo(25.0, 127.3); + ctx.bezierCurveTo(23.3, 125.0, 22.2, 123.4, 21.6, 122.5); + ctx.bezierCurveTo(20.7, 121.1, 20.2, 119.7, 20.3, 118.2); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(177.9, 163.2); + ctx.lineTo(174.9, 169.8); + ctx.lineTo(174.7, 170.3); + ctx.lineTo(174.4, 170.9); + ctx.bezierCurveTo(174.0, 172.1, 173.5, 173.3, 173.1, 174.5); + ctx.bezierCurveTo(172.2, 177.2, 171.1, 179.7, 169.6, 182.2); + ctx.bezierCurveTo(168.3, 184.5, 166.3, 186.1, 163.6, 187.2); + ctx.bezierCurveTo(160.6, 188.4, 157.5, 188.5, 154.4, 187.3); + ctx.bezierCurveTo(151.9, 186.4, 149.5, 185.5, 147.2, 184.7); + ctx.lineTo(146.7, 184.5); + ctx.lineTo(146.3, 184.3); + ctx.lineTo(140.9, 182.4); + ctx.bezierCurveTo(142.8, 182.1, 145.0, 181.4, 147.5, 180.4); + ctx.bezierCurveTo(148.2, 180.0, 148.9, 179.7, 149.6, 179.4); + ctx.bezierCurveTo(152.5, 178.0, 155.3, 176.5, 158.1, 174.8); + ctx.bezierCurveTo(161.2, 172.9, 164.4, 171.1, 167.5, 169.3); + ctx.bezierCurveTo(170.7, 167.7, 173.7, 165.9, 176.8, 163.9); + ctx.bezierCurveTo(177.2, 163.7, 177.6, 163.5, 177.9, 163.2); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(101.1, 181.4); + ctx.lineTo(97.1, 184.2); + ctx.lineTo(96.8, 184.3); + ctx.lineTo(96.3, 184.7); + ctx.bezierCurveTo(93.2, 186.5, 90.2, 187.9, 87.1, 188.9); + ctx.bezierCurveTo(83.9, 189.9, 81.1, 189.2, 78.6, 186.6); + ctx.bezierCurveTo(76.0, 184.1, 74.0, 181.3, 72.5, 178.3); + ctx.bezierCurveTo(71.3, 175.7, 70.1, 172.9, 69.0, 170.1); + ctx.lineTo(68.0, 167.8); + ctx.bezierCurveTo(67.8, 167.3, 67.7, 166.8, 67.5, 166.3); + ctx.bezierCurveTo(69.1, 167.1, 70.7, 167.9, 72.4, 168.8); + ctx.bezierCurveTo(74.1, 169.6, 75.9, 170.5, 77.9, 171.4); + ctx.bezierCurveTo(79.9, 172.3, 83.2, 173.8, 87.9, 175.9); + ctx.bezierCurveTo(92.5, 177.9, 95.7, 179.3, 97.5, 180.0); + ctx.bezierCurveTo(99.2, 180.7, 100.4, 181.2, 101.1, 181.4); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(25.8, 151.1); + ctx.bezierCurveTo(23.2, 147.7, 22.0, 143.6, 22.3, 139.0); + ctx.bezierCurveTo(22.3, 139.0, 22.3, 139.0, 22.3, 139.0); + ctx.lineTo(22.4, 135.1); + ctx.bezierCurveTo(22.5, 134.4, 22.9, 134.4, 23.6, 134.9); + ctx.bezierCurveTo(24.4, 135.4, 25.2, 136.0, 26.0, 136.6); + ctx.bezierCurveTo(27.6, 137.8, 29.1, 139.0, 30.7, 140.2); + ctx.bezierCurveTo(34.1, 142.9, 37.3, 145.8, 40.4, 148.8); + ctx.bezierCurveTo(42.4, 150.6, 44.1, 152.6, 45.6, 154.7); + ctx.bezierCurveTo(45.8, 155.3, 45.9, 155.7, 45.7, 156.0); + ctx.lineTo(45.5, 156.1); + ctx.bezierCurveTo(40.5, 158.4, 35.6, 158.3, 30.9, 155.9); + ctx.bezierCurveTo(30.6, 155.7, 30.3, 155.6, 30.0, 155.4); + ctx.bezierCurveTo(30.0, 155.3, 29.9, 155.3, 29.9, 155.3); + ctx.bezierCurveTo(28.3, 154.0, 26.9, 152.6, 25.8, 151.1); + ctx.closePath(); + + // omnom/outline/Path + ctx.moveTo(240.9, 209.6); + ctx.bezierCurveTo(240.1, 211.5, 239.1, 213.3, 237.8, 215.0); + ctx.bezierCurveTo(236.5, 216.5, 235.2, 218.1, 233.9, 219.6); + ctx.bezierCurveTo(233.4, 220.2, 232.8, 220.7, 232.3, 221.1); + ctx.bezierCurveTo(230.1, 222.1, 227.5, 222.5, 224.3, 222.1); + ctx.bezierCurveTo(218.9, 221.9, 213.4, 222.0, 207.7, 222.3); + ctx.bezierCurveTo(206.5, 222.4, 205.3, 222.4, 204.0, 222.5); + ctx.bezierCurveTo(203.3, 218.7, 201.8, 213.8, 199.6, 207.8); + ctx.lineTo(200.2, 212.5); + ctx.bezierCurveTo(200.1, 212.0, 200.0, 211.2, 199.7, 210.2); + ctx.bezierCurveTo(199.9, 214.1, 200.0, 218.2, 199.9, 222.3); + ctx.bezierCurveTo(199.9, 222.5, 199.9, 222.7, 199.9, 222.9); + ctx.bezierCurveTo(199.9, 225.0, 199.7, 226.9, 199.4, 228.8); + ctx.bezierCurveTo(199.1, 230.4, 198.7, 232.0, 198.3, 233.5); + ctx.lineTo(196.7, 235.1); + ctx.bezierCurveTo(196.6, 235.2, 196.5, 235.4, 196.3, 235.5); + ctx.bezierCurveTo(195.2, 236.4, 193.3, 237.6, 190.7, 239.1); + ctx.bezierCurveTo(188.1, 240.7, 184.5, 241.7, 179.9, 242.1); + ctx.bezierCurveTo(175.3, 242.4, 172.0, 242.5, 169.8, 242.3); + ctx.bezierCurveTo(167.8, 242.1, 165.5, 241.6, 162.9, 240.8); + ctx.bezierCurveTo(160.4, 239.9, 158.0, 237.9, 155.6, 234.8); + ctx.bezierCurveTo(155.4, 234.6, 155.3, 234.4, 155.1, 234.2); + ctx.bezierCurveTo(154.3, 233.0, 153.5, 231.6, 152.8, 230.0); + ctx.bezierCurveTo(151.9, 227.8, 151.2, 225.3, 150.7, 222.4); + ctx.bezierCurveTo(150.7, 222.2, 150.6, 222.1, 150.6, 221.9); + ctx.bezierCurveTo(149.7, 216.4, 149.3, 213.1, 149.2, 212.0); + ctx.bezierCurveTo(148.8, 215.6, 148.6, 219.2, 148.8, 222.8); + ctx.bezierCurveTo(148.9, 225.2, 149.0, 227.6, 149.4, 230.0); + ctx.bezierCurveTo(149.4, 230.3, 149.4, 230.6, 149.5, 231.0); + ctx.bezierCurveTo(141.0, 233.2, 132.2, 234.4, 123.2, 234.4); + ctx.bezierCurveTo(113.4, 235.1, 103.6, 234.6, 93.8, 233.0); + ctx.lineTo(94.0, 232.0); + ctx.bezierCurveTo(94.3, 230.0, 94.4, 228.1, 94.4, 226.2); + ctx.bezierCurveTo(94.4, 225.6, 94.3, 224.9, 94.3, 224.3); + ctx.bezierCurveTo(94.2, 220.7, 94.0, 217.1, 93.8, 213.5); + ctx.bezierCurveTo(93.8, 214.9, 93.7, 215.9, 93.6, 216.6); + ctx.bezierCurveTo(93.5, 217.2, 93.5, 217.7, 93.4, 218.1); + ctx.bezierCurveTo(93.4, 218.5, 93.2, 219.4, 92.8, 220.9); + ctx.bezierCurveTo(92.6, 222.0, 92.3, 223.0, 92.0, 223.9); + ctx.bezierCurveTo(91.9, 224.2, 91.8, 224.5, 91.7, 224.8); + ctx.bezierCurveTo(91.3, 226.0, 90.8, 227.1, 90.2, 228.3); + ctx.bezierCurveTo(89.9, 229.0, 89.5, 229.7, 89.2, 230.4); + ctx.bezierCurveTo(88.8, 230.9, 88.4, 231.4, 88.0, 231.9); + ctx.bezierCurveTo(87.5, 232.5, 86.9, 233.1, 86.2, 233.7); + ctx.bezierCurveTo(85.8, 234.1, 85.4, 234.5, 84.9, 234.8); + ctx.bezierCurveTo(83.9, 235.6, 82.8, 236.2, 81.6, 236.7); + ctx.bezierCurveTo(80.2, 237.3, 78.7, 237.7, 77.1, 238.1); + ctx.bezierCurveTo(74.1, 238.7, 71.0, 239.0, 67.8, 239.0); + ctx.bezierCurveTo(60.3, 239.1, 53.6, 237.3, 47.7, 233.5); + ctx.bezierCurveTo(47.6, 233.4, 47.5, 233.4, 47.4, 233.3); + ctx.bezierCurveTo(45.9, 232.5, 45.0, 231.7, 44.9, 230.9); + ctx.lineTo(44.6, 229.2); + ctx.bezierCurveTo(44.6, 228.8, 44.5, 228.2, 44.5, 227.6); + ctx.bezierCurveTo(44.5, 225.9, 44.5, 223.5, 44.6, 220.3); + ctx.lineTo(44.6, 213.4); + ctx.lineTo(44.7, 207.6); + ctx.lineTo(43.7, 213.0); + ctx.lineTo(42.4, 220.3); + ctx.bezierCurveTo(41.9, 223.1, 41.7, 225.4, 41.6, 227.4); + ctx.bezierCurveTo(41.0, 227.3, 40.3, 227.3, 39.7, 227.2); + ctx.bezierCurveTo(37.7, 227.2, 35.8, 227.2, 33.8, 227.2); + ctx.bezierCurveTo(32.0, 227.2, 30.2, 227.2, 28.4, 227.2); + ctx.bezierCurveTo(26.4, 227.2, 24.5, 227.3, 22.6, 227.4); + ctx.bezierCurveTo(21.3, 227.4, 19.7, 227.5, 17.8, 227.7); + ctx.bezierCurveTo(15.9, 227.9, 13.9, 227.7, 11.9, 227.1); + ctx.bezierCurveTo(9.8, 226.4, 8.3, 225.2, 7.4, 223.5); + ctx.bezierCurveTo(6.5, 221.8, 5.6, 219.7, 4.8, 217.3); + ctx.bezierCurveTo(4.0, 214.8, 3.5, 212.9, 3.3, 211.5); + ctx.bezierCurveTo(3.2, 210.1, 3.6, 209.0, 4.5, 208.2); + ctx.bezierCurveTo(5.4, 207.3, 6.7, 206.1, 8.4, 204.6); + ctx.bezierCurveTo(10.2, 202.9, 11.6, 201.6, 12.7, 200.6); + ctx.bezierCurveTo(13.7, 199.6, 16.9, 197.2, 22.4, 193.3); + ctx.bezierCurveTo(26.1, 190.5, 28.7, 189.1, 30.1, 188.9); + ctx.bezierCurveTo(31.2, 193.0, 32.3, 197.0, 33.7, 201.0); + ctx.bezierCurveTo(34.2, 202.8, 35.0, 204.4, 36.0, 205.9); + ctx.lineTo(33.3, 187.7); + ctx.lineTo(33.1, 185.9); + ctx.lineTo(32.9, 184.7); + ctx.lineTo(32.7, 183.4); + ctx.bezierCurveTo(31.8, 176.3, 31.0, 168.9, 30.3, 161.3); + ctx.bezierCurveTo(30.3, 161.0, 30.3, 160.7, 30.2, 160.3); + ctx.bezierCurveTo(34.5, 162.0, 39.0, 162.0, 43.8, 160.4); + ctx.bezierCurveTo(44.4, 160.1, 45.1, 159.9, 45.8, 159.6); + ctx.lineTo(50.7, 157.9); + ctx.lineTo(63.1, 164.7); + ctx.bezierCurveTo(63.4, 166.0, 64.0, 168.0, 65.2, 170.7); + ctx.lineTo(65.5, 171.5); + ctx.bezierCurveTo(66.9, 174.7, 68.3, 177.8, 69.8, 180.9); + ctx.bezierCurveTo(71.4, 184.1, 73.4, 187.0, 76.0, 189.6); + ctx.bezierCurveTo(78.5, 192.2, 81.7, 193.4, 85.5, 193.1); + ctx.bezierCurveTo(89.2, 192.6, 92.8, 191.5, 96.3, 189.7); + ctx.bezierCurveTo(98.5, 188.6, 100.4, 187.4, 102.1, 185.9); + ctx.lineTo(103.2, 185.0); + ctx.bezierCurveTo(103.4, 184.9, 103.6, 184.7, 103.8, 184.6); + ctx.bezierCurveTo(106.5, 182.5, 108.3, 180.9, 109.3, 179.7); + ctx.lineTo(109.4, 179.7); + ctx.bezierCurveTo(114.0, 180.5, 118.1, 181.0, 121.9, 181.4); + ctx.bezierCurveTo(125.7, 181.8, 128.8, 181.8, 131.3, 181.4); + ctx.bezierCurveTo(133.0, 181.8, 136.2, 183.2, 140.7, 185.6); + ctx.bezierCurveTo(141.0, 185.7, 141.3, 185.9, 141.7, 186.0); + ctx.bezierCurveTo(142.1, 186.3, 142.6, 186.5, 143.0, 186.7); + ctx.bezierCurveTo(143.5, 186.9, 144.0, 187.1, 144.5, 187.3); + ctx.bezierCurveTo(147.1, 188.4, 149.8, 189.4, 152.5, 190.3); + ctx.bezierCurveTo(155.3, 191.3, 158.2, 191.7, 161.2, 191.7); + ctx.bezierCurveTo(164.2, 191.7, 166.7, 190.7, 168.6, 188.6); + ctx.bezierCurveTo(170.0, 187.2, 171.1, 185.6, 172.0, 184.1); + ctx.bezierCurveTo(173.4, 181.6, 174.7, 179.1, 175.9, 176.6); + ctx.bezierCurveTo(177.1, 174.0, 178.3, 171.4, 179.4, 168.7); + ctx.bezierCurveTo(179.7, 168.0, 180.0, 167.3, 180.2, 166.7); + ctx.bezierCurveTo(181.4, 164.0, 182.0, 162.2, 182.0, 161.5); + ctx.bezierCurveTo(183.8, 160.7, 186.6, 158.8, 190.2, 155.8); + ctx.lineTo(191.0, 155.2); + ctx.bezierCurveTo(191.7, 154.5, 192.6, 153.8, 193.4, 153.2); + ctx.bezierCurveTo(193.8, 153.0, 194.1, 152.8, 194.5, 152.6); + ctx.lineTo(196.6, 153.6); + ctx.bezierCurveTo(197.0, 153.7, 197.6, 153.8, 198.4, 153.8); + ctx.bezierCurveTo(199.3, 153.8, 200.6, 153.7, 202.1, 153.6); + ctx.bezierCurveTo(204.6, 153.5, 207.0, 153.1, 209.4, 152.5); + ctx.bezierCurveTo(210.5, 152.1, 211.6, 151.8, 212.6, 151.3); + ctx.bezierCurveTo(212.6, 151.4, 212.6, 151.4, 212.6, 151.4); + ctx.bezierCurveTo(213.3, 158.8, 213.4, 166.1, 212.8, 173.3); + ctx.lineTo(211.2, 182.6); + ctx.lineTo(211.0, 183.6); + ctx.lineTo(209.4, 192.8); + ctx.lineTo(208.3, 198.0); + ctx.lineTo(208.4, 198.1); + ctx.bezierCurveTo(210.9, 194.2, 212.8, 190.0, 214.2, 185.6); + ctx.lineTo(240.5, 201.5); + ctx.bezierCurveTo(241.1, 202.2, 241.6, 202.9, 241.8, 203.6); + ctx.bezierCurveTo(242.1, 205.4, 241.8, 207.4, 240.9, 209.6); + ctx.closePath(); + ctx.fillStyle = "rgb(35, 44, 30)"; + ctx.fill(); + + // omnom/white + ctx.beginPath(); + + // omnom/white/Path + ctx.moveTo(219.9, 140.2); + ctx.bezierCurveTo(219.5, 141.6, 218.8, 143.0, 218.0, 144.5); + ctx.bezierCurveTo(217.8, 144.9, 217.6, 145.2, 217.3, 145.6); + ctx.bezierCurveTo(216.7, 146.3, 215.9, 146.9, 214.9, 147.4); + ctx.bezierCurveTo(214.1, 147.8, 213.2, 148.2, 212.3, 148.4); + ctx.bezierCurveTo(210.2, 149.1, 208.0, 149.5, 205.6, 149.5); + ctx.bezierCurveTo(204.5, 149.5, 203.4, 149.4, 202.3, 149.3); + ctx.bezierCurveTo(200.6, 148.9, 199.7, 148.0, 199.8, 146.7); + ctx.lineTo(200.7, 145.2); + ctx.bezierCurveTo(201.3, 144.3, 201.8, 143.4, 202.4, 142.5); + ctx.bezierCurveTo(202.7, 141.9, 203.0, 141.3, 203.4, 140.8); + ctx.bezierCurveTo(203.8, 140.0, 204.2, 139.2, 204.7, 138.5); + ctx.bezierCurveTo(205.3, 137.7, 205.9, 136.8, 206.5, 136.0); + ctx.bezierCurveTo(206.9, 135.5, 207.3, 135.0, 207.6, 134.5); + ctx.bezierCurveTo(208.3, 133.7, 209.0, 132.8, 209.7, 132.0); + ctx.bezierCurveTo(209.9, 131.7, 210.2, 131.4, 210.5, 131.0); + ctx.bezierCurveTo(211.0, 130.4, 211.5, 129.9, 212.1, 129.3); + ctx.bezierCurveTo(212.6, 128.8, 213.1, 128.3, 213.6, 127.8); + ctx.bezierCurveTo(214.1, 127.4, 214.6, 127.0, 215.1, 126.6); + ctx.bezierCurveTo(215.3, 126.4, 215.5, 126.3, 215.6, 126.2); + ctx.bezierCurveTo(216.8, 125.4, 217.9, 124.8, 219.0, 124.5); + ctx.lineTo(219.3, 125.4); + ctx.bezierCurveTo(220.0, 127.9, 220.5, 130.6, 220.8, 133.3); + ctx.bezierCurveTo(221.0, 135.7, 220.8, 138.0, 219.9, 140.2); + ctx.closePath(); + + // omnom/white/Path + ctx.moveTo(40.4, 148.8); + ctx.bezierCurveTo(37.3, 145.8, 34.1, 142.9, 30.7, 140.2); + ctx.bezierCurveTo(29.1, 139.0, 27.6, 137.8, 26.0, 136.6); + ctx.bezierCurveTo(25.2, 136.0, 24.4, 135.4, 23.6, 134.9); + ctx.bezierCurveTo(22.9, 134.4, 22.5, 134.4, 22.4, 135.1); + ctx.lineTo(22.3, 139.0); + ctx.bezierCurveTo(22.3, 139.0, 22.3, 139.0, 22.3, 139.0); + ctx.bezierCurveTo(22.0, 143.6, 23.2, 147.7, 25.8, 151.1); + ctx.bezierCurveTo(26.9, 152.6, 28.3, 154.0, 29.9, 155.3); + ctx.bezierCurveTo(29.9, 155.3, 30.0, 155.3, 30.0, 155.4); + ctx.bezierCurveTo(30.3, 155.6, 30.6, 155.7, 30.9, 155.9); + ctx.bezierCurveTo(35.6, 158.3, 40.5, 158.4, 45.5, 156.1); + ctx.lineTo(45.7, 156.0); + ctx.bezierCurveTo(45.9, 155.7, 45.8, 155.3, 45.6, 154.7); + ctx.bezierCurveTo(44.1, 152.6, 42.4, 150.6, 40.4, 148.8); + ctx.closePath(); + + // omnom/white/Path + ctx.moveTo(87.9, 175.9); + ctx.bezierCurveTo(83.2, 173.8, 79.9, 172.3, 77.9, 171.4); + ctx.bezierCurveTo(75.9, 170.5, 74.1, 169.6, 72.4, 168.8); + ctx.bezierCurveTo(70.7, 167.9, 69.1, 167.1, 67.5, 166.3); + ctx.bezierCurveTo(67.7, 166.8, 67.8, 167.3, 68.0, 167.8); + ctx.lineTo(69.0, 170.1); + ctx.bezierCurveTo(70.1, 172.9, 71.3, 175.7, 72.5, 178.3); + ctx.bezierCurveTo(74.0, 181.3, 76.0, 184.1, 78.6, 186.6); + ctx.bezierCurveTo(81.1, 189.2, 83.9, 189.9, 87.1, 188.9); + ctx.bezierCurveTo(90.2, 187.9, 93.2, 186.5, 96.3, 184.7); + ctx.lineTo(96.8, 184.3); + ctx.lineTo(97.1, 184.2); + ctx.lineTo(101.1, 181.4); + ctx.bezierCurveTo(100.4, 181.2, 99.2, 180.7, 97.5, 180.0); + ctx.bezierCurveTo(95.7, 179.3, 92.5, 177.9, 87.9, 175.9); + ctx.closePath(); + + // omnom/white/Path + ctx.moveTo(167.5, 169.3); + ctx.bezierCurveTo(164.4, 171.1, 161.2, 172.9, 158.1, 174.8); + ctx.bezierCurveTo(155.3, 176.5, 152.5, 178.0, 149.6, 179.4); + ctx.bezierCurveTo(148.9, 179.7, 148.2, 180.0, 147.5, 180.4); + ctx.bezierCurveTo(145.0, 181.4, 142.8, 182.1, 140.9, 182.4); + ctx.lineTo(146.3, 184.3); + ctx.lineTo(146.7, 184.5); + ctx.lineTo(147.2, 184.7); + ctx.bezierCurveTo(149.5, 185.5, 151.9, 186.4, 154.4, 187.3); + ctx.bezierCurveTo(157.5, 188.5, 160.6, 188.4, 163.6, 187.2); + ctx.bezierCurveTo(166.3, 186.1, 168.3, 184.5, 169.6, 182.2); + ctx.bezierCurveTo(171.1, 179.7, 172.2, 177.2, 173.1, 174.5); + ctx.bezierCurveTo(173.5, 173.3, 174.0, 172.1, 174.4, 170.9); + ctx.lineTo(174.7, 170.3); + ctx.lineTo(174.9, 169.8); + ctx.lineTo(177.9, 163.2); + ctx.bezierCurveTo(177.6, 163.5, 177.2, 163.7, 176.8, 163.9); + ctx.bezierCurveTo(173.7, 165.9, 170.7, 167.7, 167.5, 169.3); + ctx.closePath(); + + // omnom/white/Path + ctx.moveTo(202.2, 94.7); + ctx.bezierCurveTo(202.5, 86.8, 201.1, 79.7, 197.8, 73.5); + ctx.bezierCurveTo(196.1, 70.1, 193.9, 67.0, 191.1, 64.1); + ctx.bezierCurveTo(190.6, 63.5, 190.0, 63.0, 189.4, 62.4); + ctx.bezierCurveTo(183.4, 56.7, 176.5, 53.0, 168.8, 51.2); + ctx.bezierCurveTo(165.7, 50.5, 162.5, 50.1, 159.2, 50.1); + ctx.bezierCurveTo(159.1, 50.1, 158.9, 50.1, 158.7, 50.1); + ctx.bezierCurveTo(146.1, 51.7, 136.0, 57.6, 128.6, 67.7); + ctx.bezierCurveTo(127.5, 69.4, 126.3, 71.1, 125.0, 72.9); + ctx.bezierCurveTo(124.9, 73.2, 124.7, 73.5, 124.6, 73.8); + ctx.lineTo(124.4, 74.2); + ctx.lineTo(124.2, 73.8); + ctx.lineTo(120.8, 67.4); + ctx.bezierCurveTo(117.3, 59.5, 111.9, 53.4, 104.4, 49.1); + ctx.bezierCurveTo(100.0, 46.5, 95.6, 44.9, 91.3, 44.1); + ctx.bezierCurveTo(89.3, 43.8, 87.3, 43.6, 85.3, 43.7); + ctx.bezierCurveTo(77.8, 43.8, 70.4, 46.7, 63.0, 52.3); + ctx.bezierCurveTo(57.3, 56.8, 52.7, 61.9, 49.2, 67.7); + ctx.bezierCurveTo(47.7, 70.1, 46.5, 72.7, 45.5, 75.3); + ctx.bezierCurveTo(43.6, 79.9, 42.4, 84.8, 41.7, 90.1); + ctx.bezierCurveTo(40.4, 101.7, 42.2, 111.4, 47.4, 119.3); + ctx.bezierCurveTo(49.2, 122.2, 51.5, 124.9, 54.2, 127.3); + ctx.bezierCurveTo(64.3, 136.3, 75.9, 139.1, 88.9, 135.6); + ctx.bezierCurveTo(100.6, 132.5, 110.3, 125.2, 118.0, 113.7); + ctx.bezierCurveTo(118.8, 112.4, 119.7, 111.0, 120.5, 109.6); + ctx.bezierCurveTo(121.2, 108.3, 121.9, 106.9, 122.6, 105.5); + ctx.bezierCurveTo(122.9, 106.7, 123.3, 107.9, 123.8, 109.0); + ctx.bezierCurveTo(124.3, 110.4, 124.9, 111.7, 125.6, 113.0); + ctx.bezierCurveTo(130.4, 122.6, 137.6, 129.8, 147.3, 134.6); + ctx.bezierCurveTo(149.4, 135.6, 153.1, 136.4, 158.5, 137.0); + ctx.bezierCurveTo(168.3, 137.9, 177.6, 134.4, 186.7, 126.4); + ctx.bezierCurveTo(193.1, 120.7, 197.5, 114.2, 199.9, 107.1); + ctx.bezierCurveTo(201.3, 103.2, 202.0, 99.0, 202.2, 94.7); + ctx.closePath(); + ctx.fillStyle = "rgb(255, 255, 255)"; + ctx.fill(); + + // omnom/leftEye + ctx.save(); + ctx.translate(leftEyeOffset, 0); + ctx.beginPath(); + ctx.moveTo(101.3, 71.1); + ctx.bezierCurveTo(101.0, 71.1, 100.7, 71.2, 100.5, 71.3); + ctx.bezierCurveTo(100.5, 71.3, 100.5, 71.3, 100.5, 71.3); + ctx.bezierCurveTo(102.7, 72.9, 103.8, 75.8, 104.0, 79.9); + ctx.bezierCurveTo(104.1, 84.2, 100.5, 86.1, 93.0, 85.6); + ctx.bezierCurveTo(91.0, 85.5, 89.2, 85.4, 87.8, 85.3); + ctx.bezierCurveTo(87.7, 86.6, 87.6, 87.9, 87.6, 89.3); + ctx.bezierCurveTo(87.8, 91.8, 88.6, 94.3, 89.9, 96.7); + ctx.bezierCurveTo(91.9, 101.5, 95.2, 103.9, 99.8, 103.9); + ctx.bezierCurveTo(107.4, 103.7, 112.3, 98.0, 114.7, 86.8); + ctx.bezierCurveTo(114.7, 74.4, 110.2, 69.2, 101.3, 71.1); + ctx.closePath(); + ctx.fillStyle = "rgb(0, 0, 0)"; + ctx.fill(); + ctx.restore(); + + // omnom/rightEye + ctx.save(); + ctx.translate(rightEyeOffset, 0); + ctx.beginPath(); + ctx.moveTo(150.4, 74.1); + ctx.bezierCurveTo(147.9, 71.7, 145.3, 70.5, 142.4, 70.5); + ctx.bezierCurveTo(141.5, 70.5, 140.5, 70.7, 139.6, 71.0); + ctx.bezierCurveTo(140.1, 71.3, 140.6, 71.6, 141.1, 72.0); + ctx.bezierCurveTo(143.3, 73.6, 144.5, 76.5, 144.6, 80.6); + ctx.bezierCurveTo(144.8, 84.9, 141.1, 86.8, 133.7, 86.3); + ctx.bezierCurveTo(132.1, 86.2, 130.8, 86.2, 129.6, 86.1); + ctx.bezierCurveTo(129.6, 86.2, 129.6, 86.2, 129.6, 86.3); + ctx.bezierCurveTo(129.6, 89.1, 130.2, 91.7, 131.5, 94.1); + ctx.bezierCurveTo(134.1, 99.0, 138.3, 101.5, 144.0, 101.5); + ctx.bezierCurveTo(146.8, 101.7, 149.7, 99.7, 152.5, 95.6); + ctx.bezierCurveTo(154.5, 91.6, 155.5, 88.9, 155.5, 87.5); + ctx.bezierCurveTo(155.5, 81.9, 153.8, 77.5, 150.4, 74.1); + ctx.closePath(); + ctx.fillStyle = "rgb(0, 0, 0)"; + ctx.fill(); + ctx.restore(); + + + ctx.restore(); + ctx.restore(); + + }; + + }; + + return new EasterEggManager(); + } +); +// Shim to provide requestAnimationFrame if not supported by the browser + +define('utils/requestAnimationFrame',[], function () { + + // see if the browser natively supports requestAnimationFrame + var vendors = ['ms', 'moz', 'webkit', 'o']; + for (var i = 0; i < vendors.length && !window['requestAnimationFrame']; i++) { + window['requestAnimationFrame'] = window[vendors[i] + 'RequestAnimationFrame']; + } + + // fallback to using setTimeout if requestAnimationFrame isn't available + if (!window['requestAnimationFrame']) { + var renderInterval = 1000 / 60, + lastTime = 0; + window['requestAnimationFrame'] = function (callback, element) { + var currTime = Date.now(); + var timeToCall = Math.max(0, renderInterval - (currTime - lastTime)); + window.setTimeout(function () { + callback(Date.now()); + }, timeToCall); + lastTime = currTime + timeToCall; + } + } + + return window['requestAnimationFrame']; +}); + + +define('ui/VideoManager', + [ + 'edition', + 'resolution', + 'platform', + 'ui/PanelId', + 'ui/PanelManager', + 'game/CTRSettings', + 'game/CTRSoundMgr', + 'utils/PubSub', + 'ui/ScoreManager' + ], + function (edition, resolution, platform, PanelId, PanelManager, settings, SoundMgr, PubSub, ScoreManager) { + + var ensureVideoElement = function () { + var vid = document.getElementById('vid'); + if (!vid) { + try { + vid = document.createElement('video'); + } + catch (ex) { + // creation of the video element occasionally fails in win8 + return null; + } + vid.id = 'vid'; + vid.className = 'ctrPointer'; + $('#video').append(vid); + } + return vid; + }; + + var closeIntroCallback = null; + + var VideoManager = { + + loadIntroVideo: function () { + + // only load the video if the first level hasn't been played + var firstLevelStars = ScoreManager.getStars(0, 0) || 0; + if (firstLevelStars === 0) { + var vid = ensureVideoElement(), + size = resolution.VIDEO_WIDTH, + extension = platform.getVideoExtension(), + baseUrl = platform.videoBaseUrl; + if (vid != null && extension != null) { + try { + vid.src = baseUrl + 'intro_' + size + extension; + vid.load(); + } + catch (ex) { + // loading the video sometimes causes an exception on win8 + } + } + } + }, + + removeIntroVideo: function() { + // we want to remove the video element to free up resources + // as suggested by the IE team + var firstLevelStars = ScoreManager.getStars(0, 0) || 0; + if (firstLevelStars > 0) { + $('#vid').remove(); + } + }, + + playIntroVideo: function (callback) { + + // always show the intro video if the 1st level hasn't been played + var firstLevelStars = ScoreManager.getStars(0, 0) || 0, + + // the video might not exist if the user just reset the game + // (we don't want to replay it during the same app session) + vid = document.getElementById('vid'); + + closeIntroCallback = callback; + + if (firstLevelStars === 0 && vid) { + + // make sure we can play the video + var readyState = vid['readyState']; + if (readyState === 2 || // HAVE_CURRENT_DATA (loadeddata) + readyState === 3 || // HAVE_FUTURE_DATA (canplay) + readyState === 4) { // HAVE_ENOUGH_DATA (canplaythrough) + + SoundMgr.pauseMusic(); + $(vid).fadeIn(300, function () { + vid.play(); + }); + vid.addEventListener('ended', VideoManager.closeIntroVideo); + vid.addEventListener('mousedown', VideoManager.closeIntroVideo); + return; + } + } + + VideoManager.closeIntroVideo(); + }, + + closeIntroVideo: function () { + var vid = document.getElementById('vid'); + $(vid).fadeOut(500, function () { + vid.pause(); + vid.seek = 0; + }); + + if (closeIntroCallback) { + closeIntroCallback(); + } + }, + + loadOutroVideo: function () { + // we can re-use the same video element used for the intro + // because we only show the intro video once per session. + + // get the size and supported format extension + var vid = ensureVideoElement(), + size = resolution.VIDEO_WIDTH, + extension = platform.getVideoExtension(), + baseUrl = platform.videoBaseUrl; + + // start loading the video + if (vid != null && extension != null) { + try { + vid.src = baseUrl + 'outro_' + size + extension; + vid.load(); + } + catch (ex) { + // loading the video sometimes causes an exception on win8 + } + } + }, + + playOutroVideo: function () { + var vid = document.getElementById('vid'); + if (vid) { + // make sure we can play the video + var readyState = vid['readyState']; + if (readyState === 2 || // HAVE_CURRENT_DATA (loadeddata) + readyState === 3 || // HAVE_FUTURE_DATA (canplay) + readyState === 4) { // HAVE_ENOUGH_DATA (canplaythrough) + + SoundMgr.pauseMusic(); + if (!SoundMgr.musicEnabled) { + vid.volume = 0; + } + $(vid).fadeIn(300, function () { + vid.play(); + }); + vid.addEventListener('ended', VideoManager.closeOutroVideo); + vid.addEventListener('mousedown', VideoManager.closeOutroVideo); + } + else { + $(vid).remove(); + PanelManager.showPanel(PanelId.GAMECOMPLETE, false); + } + } + }, + + closeOutroVideo: function () { + PanelManager.showPanel(PanelId.GAMECOMPLETE, true); + var $vid = $('#vid'); + $vid.fadeOut(500, function () { + $vid[0].pause(); + $vid[0].seek = 0; + $vid.remove(); + }); + }, + + domReady: function () { + this.loadIntroVideo(); + } + }; + + // reload the intro video when the game progress is cleared + PubSub.subscribe(PubSub.ChannelId.LoadIntroVideo, function() { + VideoManager.loadIntroVideo(); + }); + + return VideoManager; + } +); + +define('ui/GameBorder', + [ + 'platform', + 'edition' + ], + function (platform, edition) { + + var $border = null, + GAME_COMPLETE_CLASS = 'gameComplete'; + + var GameBorder = { + domReady: function () { + $border = $('#gameBorder'); + }, + setBoxBorder: function (boxIndex) { + var borderFile = edition.boxBorders[boxIndex], + backgroundUrl = borderFile + ? platform.uiImageBaseUrl + borderFile + : ''; + + $border + .removeClass(GAME_COMPLETE_CLASS) + .css("background-image", 'url(' + backgroundUrl + ')'); + }, + setGameCompleteBorder: function () { + $border + .css("background-image", '') + .addClass(GAME_COMPLETE_CLASS); + }, + hide: function () { + $border.hide(); + }, + show: function () { + $border.show(); + }, + fadeIn: function (duration, delay) { + delay = delay || 0; + $border.delay(delay).fadeIn(duration); + }, + fadeOut: function (duration, delay) { + delay = delay || 0; + $border.delay(delay).fadeOut(duration); + } + }; + + return GameBorder; + } +); +define('ui/InterfaceManager', + [ + 'edition', + 'resolution', + 'platform', + 'ui/ScoreManager', + 'ui/BoxManager', + 'ui/PanelId', + 'ui/PanelManager', + 'ui/EasterEggManager', + 'visual/Text', + 'utils/PointerCapture', + 'game/CTRSettings', + 'game/CTRSoundMgr', + 'resources/ResourceId', + 'utils/requestAnimationFrame', + 'ui/Easing', + 'ui/QueryStrings', + 'game/CTRRootController', + 'ui/VideoManager', + 'utils/PubSub', + 'ui/BoxType', + 'resources/Lang', + 'resources/LangId', + 'resources/MenuStringId', + 'core/Alignment', + 'ui/SocialHelper', + 'ui/GameBorder', + 'analytics', + 'Doors', + 'ui/Dialogs' + ], + function (edition, resolution, platform, ScoreManager, BoxManager, PanelId, PanelManager, + EasterEggManager, Text, PointerCapture, settings, SoundMgr, ResourceId, + requestAnimationFrame, Easing, QueryStrings, RootController, VideoManager, PubSub, + BoxType, Lang, LangId, MenuStringId, Alignment, SocialHelper, GameBorder, analytics, + Doors, Dialogs) { + + var menuMusicId = edition.menuMusicId || ResourceId.SND_MENU_MUSIC; + + var InterfaceManager = new function () { + // ------------------------------------------------------------------------ + // Locals Variables + // ------------------------------------------------------------------------ + + var _this = this; + this.useHDVersion = resolution.isHD; + + this.isInLevelSelectMode = false; + this.isInMenuSelectMode = false; + this.isInAdvanceBoxMode = false; + this.isBoxOpen = false; + this.isTransitionActive = false; + + // warn the user if the frame rate is low after the first level + var MIN_FPS = QueryStrings.minFps || 30; + + // sets scaled menu text for the image specified by the selector query + var setImageBigText = function (selector, menuStringId) { + return Text.drawBig({ + text: Lang.menuText(menuStringId), + imgSel: selector, + scaleToUI: true + }); + }; + + // ------------------------------------------------------------------------ + // Initialize Panels (called once for each panel) + // ------------------------------------------------------------------------ + + var updateMiniSoundButton = function (doToggle, buttonId, msgId) { + + var className; + var isSoundOn = SoundMgr.soundEnabled; + var isMusicOn = SoundMgr.musicEnabled; + + if (doToggle) { + if (isSoundOn && isMusicOn) { + isSoundOn = true; + isMusicOn = false; + } + else if (!isSoundOn && !isMusicOn) { + isSoundOn = true; + isMusicOn = true; + } + else { + isSoundOn = false; + isMusicOn = false; + } + + // update settings + SoundMgr.setSoundEnabled(isSoundOn); + SoundMgr.setMusicEnabled(isMusicOn); + } + + if (isSoundOn && !isMusicOn) { + className = "effectsOnly"; + } + else if (!isSoundOn && !isMusicOn) { + className = "noSound"; + } + else { + className = "allSound"; + } + + var allClassNames = 'effectsOnly noSound allSound'; + $("#optionSound").removeClass(allClassNames).addClass(className); + $("#gameSound").removeClass(allClassNames).addClass(className); + + // option panel screen + $("#soundBtn .options-x").css("display", !isSoundOn ? "block" : "none"); + $("#musicBtn .options-x").css("display", !isMusicOn ? "block" : "none"); + + + // get the localized text for the new audio setting + var text; + if (!isMusicOn && !isSoundOn) { + text = Lang.menuText(MenuStringId.EVERYTHING_OFF); + } + else { + var musicId = isMusicOn ? MenuStringId.MUSIC_ON : MenuStringId.MUSIC_OFF, + soundId = isSoundOn ? MenuStringId.SOUNDS_ON : MenuStringId.SOUNDS_OFF, + template = Lang.menuText(MenuStringId.AND_TEMPLATE); + text = template.replace('{0}', Lang.menuText(musicId).toLowerCase()) + .replace('{1}', Lang.menuText(soundId).toLowerCase()); + } + + showMiniOptionMessage(msgId, text); + + }; + + var showMiniOptionMessage = function (msgId, text, delay) { + if (msgId != undefined) { + + var showDelay = delay || 500, + $msg = $("#" + msgId), + $img = $msg.find('img'); + + // make sure the image exists + if ($img.length === 0) { + $img = $('').appendTo($msg); + } + + // render the text + Text.drawSmall({ + text: text, + img: $img[0], + scaleToUI: true, + alpha: 0.6, + alignment: Alignment.LEFT + }); + + // stop any in-progress animations and queue fade in and out + $msg.stop(true, true) + .fadeIn(500).delay(showDelay).fadeOut(750); + } + }; + + // only enable achievements and leaderboard for signed-in users + var signedIn = false, + updateSignInControls = function() { + $('#achievementsBtn').toggleClass('disabled', !signedIn); + $('#leaderboardsBtn').toggleClass('disabled', !signedIn); + }; + PubSub.subscribe(PubSub.ChannelId.SignIn, function() { + signedIn = true; + updateSignInControls(); + }); + PubSub.subscribe(PubSub.ChannelId.SignOut, function() { + signedIn = false; + updateSignInControls(); + }); + + var onInitializePanel = function (panelId) { + + // initialize the MENU panel + if (panelId == PanelId.MENU) { + + $('#playBtn').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + + if (analytics.onPlayClicked) { + analytics.onPlayClicked(); + } + + VideoManager.playIntroVideo(function() { + + var firstLevelStars = ScoreManager.getStars(0, 0) || 0; + if (firstLevelStars === 0) { + // start the first level immediately + _this.noMenuStartLevel(0, 0); + } else { + var panelId = edition.disableBoxMenu ? PanelId.LEVELS : PanelId.BOXES; + PanelManager.showPanel(panelId, true); + } + }); + }); + + $('#optionsBtn').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + // see if there is a custom settings panel we should trigger + if (platform.customOptions) { + PubSub.publish(PubSub.ChannelId.ShowOptions); + } + else { + PanelManager.showPanel(PanelId.OPTIONS); + } + }); + + $('#achievementsBtn').click(function () { + if (signedIn) { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.ACHIEVEMENTS); + } + }).toggleClass('disabled', !signedIn); + + $('#leaderboardsBtn').click(function () { + if (signedIn) { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.LEADERBOARDS); + } + }).toggleClass('disabled', !signedIn); + + // reset popup buttons + var resetTimer = null; + $("#resetYesBtn") + .on(PointerCapture.startEventName, function () { + SoundMgr.playSound(ResourceId.SND_TAP); + resetTimer = setTimeout(function () { + Dialogs.closePopup(); + resetTimer = null; + + settings.clear(); + + //reset scores + ScoreManager.resetGame(); + + // lock all the boxes + BoxManager.resetLocks(); + + PubSub.publish(PubSub.ChannelId.LoadIntroVideo); + + }, 3000); // wait 3 seconds in case user changes their mind + }) + .on(PointerCapture.endEventName, function () { + if (resetTimer != null) { + clearTimeout(resetTimer); + } + }); + + // mini options panel + + updateMiniSoundButton(false, "optionSound"); + $("#optionSound").click(function () { + updateMiniSoundButton(true, "optionSound", "optionMsg"); + }); + + var hdtoggle; + if (_this.useHDVersion) { + $("#optionHd").addClass("activeResolution"); + $("#optionSd").addClass("inActiveResolution"); + $("#optionSd").addClass("ctrPointer"); + $("#optionSd").hover(function () { + showMiniOptionMessage("optionMsg", Lang.menuText(MenuStringId.RELOAD_SD), 4000); + }, function () { + $("#optionMsg").stop(true, true).fadeOut(500); + }); + hdtoggle = "optionSd"; + } + else { + $("#optionSd").addClass("activeResolution"); + $("#optionHd").addClass("inActiveResolution"); + $("#optionHd").addClass("ctrPointer"); + $("#optionHd").hover(function () { + showMiniOptionMessage("optionMsg", Lang.menuText(MenuStringId.RELOAD_HD), 4000); + }, function () { + $("#optionMsg").stop(true, true).fadeOut(500); + }); + hdtoggle = "optionHd"; + } + + $('#' + hdtoggle).click(function (e) { + settings.setIsHD(!_this.useHDVersion); + window.location.reload(); // refresh the page + }); + + // handle language changes + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + setImageBigText('#playBtn img', MenuStringId.PLAY); + setImageBigText('#optionsBtn img', MenuStringId.OPTIONS); + setImageBigText('#resetYesBtn img', MenuStringId.YES); + setImageBigText('#resetNoBtn img', MenuStringId.NO); + + Text.drawBig({ + text: Lang.menuText(MenuStringId.LEADERBOARDS), + imgParentId: 'leaderboardsBtn', + scale: 0.8 * resolution.UI_TEXT_SCALE + }); + + Text.drawBig({ + text: Lang.menuText(MenuStringId.ACHIEVEMENTS), + imgParentId: 'achievementsBtn', + scale: 0.8 * resolution.UI_TEXT_SCALE + }); + + }); + } + + // initialize the BOXES panel + else if (panelId == PanelId.BOXES) { + + // handles clicking on the circular back button + $('#boxBack').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.MENU); + }); + + var panel = PanelManager.getPanelById(panelId); + panel.init(InterfaceManager); + } + + else if (panelId == PanelId.PASSWORD) { + + $('#boxEnterCodeButton').click(function() { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.PASSWORD); + }); + + // handles clicking on the circular back button + $('#codeBack').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.BOXES); + }); + + var panel = PanelManager.getPanelById(panelId); + panel.init(InterfaceManager); + } + + // initialize the LEVELS panel + else if (panelId == PanelId.LEVELS) { + + $('#levelBack').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + var panelId = edition.disableBoxMenu ? PanelId.MENU : PanelId.BOXES; + PanelManager.showPanel(panelId); + }); + + // render the canvas all the way closed + Doors.renderDoors(true, 0.0); + + var panel = PanelManager.getPanelById(panelId); + panel.init(InterfaceManager); + } + else if (panelId == PanelId.GAME) { + $('#gameRestartBtn').click(function () { + if (_this.isTransitionActive) return; + SoundMgr.playSound(ResourceId.SND_TAP); + openLevel(BoxManager.currentLevelIndex, true); // is a restart + }); + + $('#gameMenuBtn').click(function () { + if (_this.isTransitionActive) return; + SoundMgr.playSound(ResourceId.SND_TAP); + openLevelMenu(); + }); + } + else if (panelId == PanelId.GAMEMENU) { + $('#continueBtn').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + closeLevelMenu(); + RootController.resumeLevel(); + }); + + $('#skipBtn').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + closeLevelMenu(); + //unlock next level + if (BoxManager.isNextLevelPlayable()) { + ScoreManager.setStars(BoxManager.currentBoxIndex, BoxManager.currentLevelIndex, 0); + openLevel(BoxManager.currentLevelIndex + 1, false, true); + } else { + $('#gameBtnTray').hide(); + completeBox(); + } + }); + + $('#selectBtn').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + closeLevelMenu(); + closeLevel(); + _this.isInLevelSelectMode = true; + _this.isInMenuSelectMode = false; + _this.closeBox(); + }); + + $('#menuBtn').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + closeLevelMenu(); + closeLevel(); + _this.isInLevelSelectMode = true; + _this.isInMenuSelectMode = true; + _this.closeBox(); + }); + + // mini options panel + updateMiniSoundButton(false, "gameSound"); + $("#gameSound").click(function () { + updateMiniSoundButton(true, "gameSound", "gameMsg"); + }); + + // language changes + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + setImageBigText('#continueBtn img', MenuStringId.CONTINUE); + setImageBigText('#skipBtn img', MenuStringId.SKIP_LEVEL); + setImageBigText('#selectBtn img', MenuStringId.LEVEL_SELECT); + setImageBigText('#menuBtn img', MenuStringId.MAIN_MENU); + }); + } + else if (panelId == PanelId.LEVELCOMPLETE) { + + $('#nextBtn').click(function () { + if (_this.isTransitionActive) return; + notifyBeginTransition(1000, "next level"); + SoundMgr.playSound(ResourceId.SND_TAP); + //is there another level in this box? + if (BoxManager.isNextLevelPlayable()) { + openLevel(BoxManager.currentLevelIndex + 1); + } else { + completeBox(); + } + }); + + $('#replayBtn').click(function () { + if (_this.isTransitionActive) return; + notifyBeginTransition(1000, "replay"); + SoundMgr.playSound(ResourceId.SND_TAP); + openLevel(BoxManager.currentLevelIndex); + }); + + $('#lrMenuBtn').click(function () { + if (_this.isTransitionActive) return; + notifyBeginTransition(1000, "level menu"); + SoundMgr.playSound(ResourceId.SND_TAP); + _this.isInLevelSelectMode = true; + _this.isInMenuSelectMode = false; + _this.tapeBox(); + }); + + // handle language changes + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, function () { + setImageBigText('#nextBtn img', MenuStringId.NEXT); + setImageBigText('#replayBtn img', MenuStringId.REPLAY); + setImageBigText('#lrMenuBtn img', MenuStringId.MENU); + Text.drawSmall({ + text: Lang.menuText(MenuStringId.FINAL_SCORE), + imgId: 'resultTickerMessage', + scaleToUI: true, + canvas: true + }); + }); + } + else if (panelId == PanelId.GAMECOMPLETE) { + $('#gameCompleteBack').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.MENU); + GameBorder.hide(); + }); + + $('#finalShareBtn').click(function () { + + var possibleStars = BoxManager.possibleStars(), + totalStars = ScoreManager.totalStars(); + + SocialHelper.postToFeed( + platform.getGameCompleteShareText(totalStars, possibleStars), + SocialHelper.siteDescription, + platform.getScoreImageBaseUrl() + "score" + totalStars + ".png", + function () { + return true; + }); + + }); + } + else if (panelId == PanelId.OPTIONS) { + + // sound effects + var updateSoundOption = platform.updateSoundOption, + $soundBtn = $('#soundBtn'), + onSoundButtonChange = function () { + var isSoundOn = !(settings.getSoundEnabled()); + SoundMgr.setSoundEnabled(isSoundOn); + SoundMgr.playSound(ResourceId.SND_TAP); + updateSoundOption($soundBtn, isSoundOn); + updateMiniSoundButton(false, "gameSound"); + updateMiniSoundButton(false, "optionSound"); + }; + platform.setSoundButtonChange($soundBtn, onSoundButtonChange); + + // game music + var updateMusicOption = platform.updateMusicOption, + $musicBtn = $('#musicBtn'), + onMusicButtonChange = function () { + SoundMgr.playSound(ResourceId.SND_TAP); + var isMusicOn = !(settings.getMusicEnabled()); + SoundMgr.setMusicEnabled(isMusicOn); + updateMusicOption($musicBtn, isMusicOn); + updateMiniSoundButton(false, "gameSound"); + updateMiniSoundButton(false, "optionSound"); + }; + platform.setMusicButtonChange($musicBtn, onMusicButtonChange); + + // change language + var updateLangOption = platform.updateLangSetting; + platform.setLangOptionClick(function (newLangId) { + SoundMgr.playSound(ResourceId.SND_TAP); + + // if not specified we'll assume that we should advance to + // the next language (so we cycle through as user clicks) + if (newLangId == null) { + var currentIndex = edition.languages.indexOf(settings.getLangId()); + newLangId = edition.languages[(currentIndex + 1) % edition.languages.length]; + } + + settings.setLangId(newLangId); + + // send the notification that language has changed + PubSub.publish(PubSub.ChannelId.LanguageChanged); + }); + + + // click or drag to cut + var updateCutOption = platform.updateCutSetting; + platform.setCutOptionClick(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + var isClickToCut = !(settings.getClickToCut()); + settings.setClickToCut(isClickToCut); + updateCutOption(isClickToCut); + }); + + // reset button + var $resetBtn = $('#resetBtn').click(function () { + + // create localized text images + var resetTextImg = Text.drawBig({ + text: Lang.menuText(MenuStringId.RESET_TEXT), + alignment: Alignment.CENTER, + + // we use canvas scale because text is draw at game scale and + // scaled to UI dimensions by setting the img width & height + width: 1250 * resolution.CANVAS_SCALE, + scaleToUI: true }), + resetHoldYesImg = Text.drawSmall({ + text: Lang.menuText(MenuStringId.RESET_HOLD_YES), + scaleToUI: true, + width: resolution.uiScaledNumber(550) + }); + + // clear existing text image and append to placeholder divs + $('#resetText').empty().append($(resetTextImg)); + $('#resetHoldYes').empty().append($(resetHoldYesImg)); + + SoundMgr.playSound(ResourceId.SND_TAP); + Dialogs.showPopup("resetGame"); + }); + + $('#optionsBack').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.MENU); + }); + + // hide the language if not supported by the edition + platform.toggleLangUI(!edition.disableLanguageOption); + + // update options menu when the language changes + var refreshOptionsButtons = function () { + setImageBigText('#optionsTitle img', MenuStringId.OPTIONS); + updateSoundOption($soundBtn, settings.getSoundEnabled()); + updateMusicOption($musicBtn, settings.getMusicEnabled()); + updateLangOption(); + updateCutOption(settings.getClickToCut()); + platform.setResetText($resetBtn, Lang.menuText(MenuStringId.RESET)); + + // apply a lang-{code} class to a language layer for css styles + var langId = settings.getLangId(); + // !LANG + $('#lang') + .removeClass('lang-system lang-en lang-de lang-ru lang-fr lang-ca lang-br lang-es lang-it lang-nl lang-ko lang-ja lang-zh') + .addClass('lang-' + LangId.toCountryCode(langId)); + + if (langId >= 4 && langId <= 9) { + $("#lang").addClass('lang-system') + } + }; + + PubSub.subscribe(PubSub.ChannelId.LanguageChanged, refreshOptionsButtons); + PubSub.subscribe(PubSub.ChannelId.ShowOptionsPage, refreshOptionsButtons); + + } else if (panelId === PanelId.LEADERBOARDS) { + $('#leaderboardBack').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.MENU); + }); + } else if (panelId === PanelId.ACHIEVEMENTS) { + $('#achievementsBack').click(function () { + SoundMgr.playSound(ResourceId.SND_TAP); + PanelManager.showPanel(PanelId.MENU); + }); + } + //else if (panelId == PanelId.CREDITS) { } + }; + + // ------------------------------------------------------------------------ + // Show Panels (called for each panel when it's shown) + // ------------------------------------------------------------------------ + + var bounceTimeOut = null; + var onShowPanel = function (panelId) { + + var panel = PanelManager.getPanelById(panelId); + + if (panelId == PanelId.MENU || panelId == PanelId.BOXES || panelId == PanelId.OPTIONS) { + GameBorder.fadeOut(300); + } + else if (panelId !== PanelId.LEVELS) { + GameBorder.show(); + } + + // make sure the pause level panel is closed + if (panelId !== PanelId.GAMEMENU) { + closeLevelMenu(); + } + + // make sure the menu music is started on main menu and level selection + // which are the entry points from the game. + if (panelId === PanelId.MENU || panelId === PanelId.LEVELS) { + SoundMgr.playMusic(menuMusicId); + } + + var boxPanel = PanelManager.getPanelById(PanelId.BOXES); + if (panelId == PanelId.BOXES) { + BoxManager.updateBoxLocks(); + ScoreManager.updateTotalScoreText(); + boxPanel.onShow(); + + if (_this.isInAdvanceBoxMode) { + _this.isInAdvanceBoxMode = false; + setTimeout(function () { + $("#levelResults").hide(); + boxPanel.slideToNextBox(); + + // if next level is not playable, show the purchase prompt + if (!BoxManager.isNextLevelPlayable()) { + Dialogs.showPayDialog(); + } + + }, 800); + } + else { + clearTimeout(bounceTimeOut); + bounceTimeOut = setTimeout(function () { + boxPanel.bounceCurrentBox(); + }, 300); + } + } + else { + boxPanel.onHide(); + } + + var codePanel = PanelManager.getPanelById(PanelId.PASSWORD); + if (codePanel) { + if (panelId === PanelId.PASSWORD) { + codePanel.onShow(); + } else { + codePanel.onHide(); + } + } + + if (panelId == PanelId.LEVELS) { + Doors.renderDoors(true, 0); + panel.onShow(); + } + else if (panelId == PanelId.GAME) { + updateMiniSoundButton(false, "optionSound"); + } + //else if (panelId == PanelId.GAMEMENU) { } + //else if (panelId == PanelId.LEVELCOMPLETE) { } + else if (panelId === PanelId.GAMECOMPLETE) { + + $('#levelResults').hide(); + + GameBorder.setGameCompleteBorder(); + + var gameWonText = Lang.menuText(MenuStringId.GAME_FINISHED_TEXT) + .replace('%d', ScoreManager.totalStars()); + Text.drawBig({ + text: gameWonText, + imgSel: '#finalScore img', + scale: 0.8 * resolution.UI_TEXT_SCALE, + alignment: 1 + }); + + $('#congrats').empty().append(Text.drawBig({ + text: Lang.menuText(MenuStringId.CONGRATULATIONS), + scale: 1.2 * resolution.UI_TEXT_SCALE + })); + + Text.drawBig({ + text: Lang.menuText(MenuStringId.SHARE_ELLIPSIS), + imgSel: '#finalShareBtn img', + scale: 0.8 * resolution.UI_TEXT_SCALE, + maxScaleWidth: resolution.uiScaledNumber(130) + }); + Text.drawBig({ + text: Lang.menuText(MenuStringId.MORE_CTR_FUN), + imgSel: '#finalFunBtn img', + scale: 0.8 * resolution.UI_TEXT_SCALE, + maxScaleWidth: resolution.uiScaledNumber(310) + }); + } + else if (panelId == PanelId.OPTIONS) { + PubSub.publish(PubSub.ChannelId.ShowOptionsPage); + } + + else if (panelId == PanelId.ACHIEVEMENTS) { + PubSub.publish(PubSub.ChannelId.UpdateCandyScroller); + } + + else if (panelId == PanelId.LEADERBOARDS) { + PubSub.publish(PubSub.ChannelId.UpdateCandyScroller); + } + //else if (panelId == PanelId.CREDITS) { } + }; + + // ------------------------------------------------------------------------ + // UI methods + // ------------------------------------------------------------------------ + + // Sets the isTransitionActive flag to true and then back to false after the timeout. The + // reason for using a timer here is to ensure that we always clear the flag since some UI + // will be disabled until the flag gets cleared. This is an attempt to prevent new bugs. + + var transitionTimeout = null; + var notifyBeginTransition = function (timeout, name) { + _this.isTransitionActive = true; + if (transitionTimeout != null) clearTimeout(transitionTimeout); + transitionTimeout = setTimeout(function () { + _this.isTransitionActive = false; + transitionTimeout = null; + }, timeout); + }; + + var runScoreTicker = function () { + //$('#resultTicker').text(resultTopLines[currentResultLine]); + $('#resultScore').text(resultBottomLines[currentResultLine]); + currentResultLine++; + if (currentResultLine < resultTopLines.length) { + if (currentResultLine < resultTimeShiftIndex) { + setTimeout(function () { + runScoreTicker(); + }, 10); + } else { + setTimeout(function () { + runScoreTicker(); + }, 167); + } + } + }; + + // play the level + var openLevel = this.openLevel = function (level, isRestart, isSkip) { + + + GameBorder.fadeIn(650, 100); + BoxManager.currentLevelIndex = level; + + // when we start the last level we should begin loading the outro video + if (isLastLevel()) { + VideoManager.loadOutroVideo(); + } + + if (isRestart) { + RootController.restartLevel(); + } + else { + PanelManager.showPanel(PanelId.GAME, true); + setTimeout(function () { + _this.openBox(isSkip); + }, 200); + } + }; + + var closeLevel = function () { + RootController.stopLevel(); + }; + + var isLastLevel = function () { + // see if we are on the last box + var lastPlayableBoxIndex = BoxManager.requiredCount() - 1; + if (BoxManager.currentBoxIndex !== lastPlayableBoxIndex) { + return false; + } + + // on the last level? + var numLevels = ScoreManager.levelCount(BoxManager.currentBoxIndex); + // unfortunately the currentLevelIndex is not zero-based + if (BoxManager.currentLevelIndex !== numLevels) { + return false; + } + + return true; + }; + + var completeBox = function () { + + //attempt to move to the next box + var boxIndex = BoxManager.currentBoxIndex; + + // check for game complete + var requiredIndex = BoxManager.requiredCount() - 1, + isGameComplete = (boxIndex >= requiredIndex); + + if (isGameComplete) { + GameBorder.hide(); + VideoManager.playOutroVideo(); + } + else { + _this.isInAdvanceBoxMode = true; + var panelId = edition.disableBoxMenu ? PanelId.MENU : PanelId.BOXES; + PanelManager.showPanel(panelId, false); + } + + }; + + var openLevelMenu = function () { + RootController.pauseLevel(); + $('#levelMenu').show(); + }; + + var closeLevelMenu = function () { + $('#levelMenu').hide(); + }; + + this.tapeBox = function () { + + if (_this.isInMenuSelectMode) { + GameBorder.fadeOut(800, 400); + SoundMgr.playMusic(menuMusicId); + } + + Doors.closeBoxAnimation(function() { + _this.isBoxOpen = false; + if (_this.isInMenuSelectMode) { + PanelManager.showPanel(PanelId.MENU, false); + } else { + Doors.renderDoors(true, 0); + PanelManager.showPanel(PanelId.LEVELS, true); + } + }); + }; + + this.openBox = function openboxFunc (skip) { + + var timeout = PanelManager.currentPanelId == PanelId.LEVELS ? 400 : 0; + + //fade out options elements + $("#levelScore").fadeOut(); + $("#levelBack").fadeOut(); + + RootController.startLevel(BoxManager.currentBoxIndex + 1, BoxManager.currentLevelIndex); + + $("#levelOptions").fadeOut(timeout, function () { + + if (_this.isBoxOpen) { + $('#levelResults').fadeOut(800); + + setTimeout(function () { + if (skip) { + _this.showGameUI(); + } else { + Doors.openDoors(false, function () { + _this.showGameUI(); + }); + } + }, 400); + } + else { + Doors.openBoxAnimation(function () { + _this.isBoxOpen = true; + + Doors.openDoors(true, function () { + _this.showGameUI(); + }); + }); + } + }); // end fadeOut + }; + + this.closeBox = function () { + _this.closeGameUI(); + + setTimeout(function () { + + // animating from game to results + if (!_this.isInLevelSelectMode) { + $('#levelResults').delay(750).fadeIn(250); + } + + // close the doors + Doors.closeDoors(false, function () { + if (_this.isInLevelSelectMode) { + _this.tapeBox(); + } else { + Doors.showGradient(); + setTimeout(function () { + runScoreTicker(); + }, 250); + } + }); + + }, 250); + }; + + var showLevelBackground = function () { + $("#levelBackground").show(); + }; + + var hideLevelBackground = function () { + $("#levelBackground").hide(); + }; + + this.showGameUI = function () { + hideLevelBackground(); + if (QueryStrings.showBoxBackgrounds && edition.enableBoxBackgroundEasterEgg) { + $("#bg").show(); + } + $('#gameBtnTray').fadeIn(); + }; + + this.closeGameUI = function () { + Doors.renderDoors(false, 1); + notifyBeginTransition(1000, "close game ui"); + showLevelBackground(); + if (QueryStrings.showBoxBackgrounds && edition.enableBoxBackgroundEasterEgg) { + $("#bg").hide(); + } + $('#gameBtnTray').fadeOut(); + }; + + var resultTopLines = [], resultBottomLines = [], currentResultLine = 0, resultTimeShiftIndex = 0; + + this.onLevelWon = function (info) { + var stars = info.stars, + score = info.score, + levelTime = info.time; + + //show level results + var resultStatusText; + var currentPoints = 0; + var index = 0; + var totalStarPoints = stars * 1000; + var currentTime = 1; + var timeSlicePoints = Math.round((score - (stars * 1000)) / levelTime); + + switch (stars) { + case 3: + $('#resultStar1').removeClass('starEmpty').addClass('star'); + $('#resultStar2').removeClass('starEmpty').addClass('star'); + $('#resultStar3').removeClass('starEmpty').addClass('star'); + resultStatusText = Lang.menuText(MenuStringId.LEVEL_CLEARED4); + break; + case 2: + $('#resultStar1').removeClass('starEmpty').addClass('star'); + $('#resultStar2').removeClass('starEmpty').addClass('star'); + $('#resultStar3').removeClass('star').addClass('starEmpty'); + resultStatusText = Lang.menuText(MenuStringId.LEVEL_CLEARED3); + break; + case 1: + $('#resultStar1').removeClass('starEmpty').addClass('star'); + $('#resultStar2').removeClass('star').addClass('starEmpty'); + $('#resultStar3').removeClass('star').addClass('starEmpty'); + resultStatusText = Lang.menuText(MenuStringId.LEVEL_CLEARED2); + break; + default: + $('#resultStar1').removeClass('star').addClass('starEmpty'); + $('#resultStar2').removeClass('star').addClass('starEmpty'); + $('#resultStar3').removeClass('star').addClass('starEmpty'); + resultStatusText = Lang.menuText(MenuStringId.LEVEL_CLEARED1); + break; + } + Text.drawBig({text: resultStatusText, imgSel: '#resultStatus canvas', scaleToUI: true, canvas: true }); + + // set stuff up + var valdiv = $("#resultTickerValue").hide(); + var lbldiv = $("#resultTickerLabel").hide(); + var resdiv = $("#resultScore").empty().hide(); + var stamp = $("#resultImproved").hide(); + var msgdiv = $("#resultTickerMessage").hide(); + + // HELPER FUNCTIONS + + var secondsToMin = function (sec) { + var m = sec / 60 | 0, + s = Math.round(sec % 60); + return m + ":" + (s < 10 ? "0" + s : s); + }; + + var doStarCountdown = function (from, callback) { + + var countDownPoints = from, + duration = 1000, + lastRender = Date.now(), + requestAnimationFrame = window['requestAnimationFrame']; + + var renderCount = function() { + var now = Date.now(), + timeDelta = now - lastRender, + pointDelta = Math.min( + Math.round(from * timeDelta / duration), + countDownPoints); + + lastRender = now; + + countDownPoints -= pointDelta; + currentPoints += pointDelta; + if (countDownPoints <= 0) { + countDownPoints = 0; + currentPoints = from; + lbldiv.fadeOut(400); + valdiv.fadeOut(400, callback); + } else { + requestAnimationFrame(renderCount); + } + + Text.drawSmall({text: countDownPoints, img: valdiv[0], scaleToUI: true, canvas: true }); + Text.drawBigNumbers({text: currentPoints, imgParentId: 'resultScore', scaleToUI: true, canvas: true }); + }; + + renderCount(); + }; + + var doTimeCountdown = function (fromsec, frompoints, callback) { + + var finalPoints = currentPoints + frompoints, + countDownSecs = fromsec, + // between 1 and 2 secs depending on time + duration = Math.max(1000, 2000 - (fromsec * 50)), + lastRender = Date.now(), + requestAnimationFrame = window['requestAnimationFrame']; + + var renderScore = function() { + var now = Date.now(), + percentElapsed = (now - lastRender) / duration; + + lastRender = now; + currentPoints += Math.round(frompoints * percentElapsed); + + countDownSecs -= fromsec * percentElapsed; + if (countDownSecs <= 0) { + countDownSecs = 0; + currentPoints = finalPoints; + lbldiv.fadeOut(400); + valdiv.fadeOut(400, callback); + } else { + requestAnimationFrame(renderScore); + } + + Text.drawSmall({text: secondsToMin(countDownSecs), img: valdiv[0], scaleToUI: true, canvas: true }); + Text.drawBigNumbers({text: currentPoints, imgParentId: 'resultScore', scaleToUI: true, canvas: true }); + }; + + renderScore(); + }; + + // ANIMATION + + // set up the star bonus countdown + Text.drawSmall({text: Lang.menuText(MenuStringId.STAR_BONUS), img: lbldiv[0], scaleToUI: true, canvas: true }); + Text.drawSmall({text: totalStarPoints, img: valdiv[0], scaleToUI: true, canvas: true }); + $('#resultScore img').remove(); + $('#resultScore canvas').remove(); + + // run the animation sequence + setTimeout(function () { + lbldiv.fadeIn(300); + valdiv.fadeIn(300); + resdiv.fadeIn(300, function () { + doStarCountdown(totalStarPoints, function () { + + Text.drawSmall({text: Lang.menuText(MenuStringId.TIME), img: lbldiv[0], scaleToUI: true, canvas: true }); + lbldiv.fadeIn(300); + Text.drawSmall({text: secondsToMin(Math.ceil(levelTime)), img: valdiv[0], scaleToUI: true, canvas: true }); + valdiv.fadeIn(300, function () { + doTimeCountdown(Math.ceil(levelTime), score - currentPoints, function () { + msgdiv.fadeIn(300); + // show the improved result stamp + if (prevScore != null && prevScore > 0 && score > prevScore) { + if ($.browser.msie) { + stamp.show(); + } else { + stamp.animate({ scale: 2.5, opacity: 0.0 }, 0, function () { + stamp.css("display", "block"); + stamp.animate({ scale: 1.0, opacity: 1.0 }, 600, "easeInCubic"); + }); + } + } + }); + }); + + }); + }); + }, 1000); + + + // TODO: right now boxIndex is zero based and levelIndex starts at 1? + var boxIndex = BoxManager.currentBoxIndex, + levelIndex = BoxManager.currentLevelIndex; + + // save the prev score + var prevScore = ScoreManager.getScore(boxIndex, levelIndex - 1); + + // Update score of the current level if there is a best result + ScoreManager.setScore(boxIndex, levelIndex - 1, score); + ScoreManager.setStars(boxIndex, levelIndex - 1, stars); + + // unlock next level + if (ScoreManager.levelCount(boxIndex) > levelIndex && + BoxManager.isNextLevelPlayable()) { + ScoreManager.setStars(boxIndex, levelIndex, 0); + } + + _this.isInLevelSelectMode = false; + _this.closeBox(); + + // events that occur after completing the first level + if (boxIndex === 0 && levelIndex === 1) { + + if (analytics.onFirstLevelComplete) { + analytics.onFirstLevelComplete(info.fps); + } + + // tell the user if the fps was low on the first level + if (info.fps < MIN_FPS && !platform.disableSlowWarning) { + + // delay the popup to allow the score screen to finish + setTimeout(function () { + Dialogs.showSlowComputerPopup(); + }, 3000); + } + + VideoManager.removeIntroVideo(); + } + }; + + // show hide the "behind the scenes" link and the feedback tab when the screen changes size + var isDevLinkVisible = true; + this.updateDevLink = function () { + if ($(window).width() < (resolution.uiScaledNumber(1024) + 120) && isDevLinkVisible) { + $("#moreLink").fadeOut(function () { + isDevLinkVisible = false; + }); + $("#zenbox_tab").fadeOut(); + } + else if ($(window).width() > (resolution.uiScaledNumber(1024) + 120) && !isDevLinkVisible) { + $("#moreLink").fadeIn(function () { + isDevLinkVisible = true; + }); + $("#zenbox_tab").fadeIn(); + } + }; + + // we'll only resume when the game is enabled + this.gameEnabled = true; + + this.pauseGame = function () { + + // make sure the game is active and no transitions are pending + if (PanelManager.currentPanelId === PanelId.GAME && + RootController.isLevelActive() && + !_this.isTransitionActive) { + openLevelMenu(); + } + else { + SoundMgr.pauseMusic(); + } + }; + + this.resumeGame = function () { + if (PanelManager.currentPanelId !== PanelId.GAMEMENU && + _this.gameEnabled) { + SoundMgr.resumeMusic(); + } + }; + + // ------------------------------------------------------------------------ + // Object management stuff + // ------------------------------------------------------------------------ + + this.init = function () { + ScoreManager.load(); + PanelManager.onShowPanel = onShowPanel; + }; + + this.domReady = function () { + + VideoManager.domReady(); + EasterEggManager.domReady(); + PanelManager.domReady(); + GameBorder.domReady(); + + // pause game / music when the user switches tabs + $(window).blur(_this.pauseGame); + + // when returning to the tab, resume music (except when on game menu - no music there) + $(window).focus(_this.resumeGame); + + // hide behind the scenes when we update the page + $(window).resize(function () { + _this.updateDevLink(); + }); + }; + + this.appReady = function () { + + PubSub.subscribe(PubSub.ChannelId.LevelWon, this.onLevelWon); + + Doors.appReady(); + EasterEggManager.appReady(); + PanelManager.appReady(onInitializePanel); + BoxManager.appReady(); + + // initialize all the localized resources + PubSub.publish(PubSub.ChannelId.LanguageChanged); + + // start a specific level? + if (QueryStrings.box != null && QueryStrings.level != null) { + this.noMenuStartLevel(QueryStrings.box - 1, QueryStrings.level - 1); + } + else if (settings.showMenu) { + + // make sure the game is not password locked + var passwordPanel = PanelManager.getPanelById(PanelId.PASSWORD); + if (passwordPanel && passwordPanel.isGameLocked && + passwordPanel.isGameLocked()) { + Doors.renderDoors(true, 0); + PanelManager.showPanel(PanelId.PASSWORD, true); + } else { + PanelManager.showPanel(PanelId.MENU, true); + } + } + + var im = this; + PubSub.subscribe(PubSub.ChannelId.PauseGame, function() { + im.pauseGame(); + }); + PubSub.subscribe(PubSub.ChannelId.EnableGame, function() { + im.gameEnabled = true; + im.resumeGame(); + }); + PubSub.subscribe(PubSub.ChannelId.DisableGame, function() { + im.gameEnabled = false; + im.pauseGame(); + }); + }; + + // used for debug and in level editor to start a level w/o menus + this.noMenuStartLevel = function (boxIndex, levelIndex) { + PanelManager.showPanel(PanelId.GAME, true); + + // unfortunate that box manager is zero index for box and 1 based for level + BoxManager.currentBoxIndex = boxIndex; + BoxManager.currentLevelIndex = levelIndex + 1; + + this.openBox(); + }; + + this.openLevelMenu = function(boxIndex) { + _this.isBoxOpen = false; + Doors.renderDoors(true, 0); + PanelManager.showPanel(PanelId.LEVELS); + GameBorder.setBoxBorder(boxIndex); + }; + + }; + + return InterfaceManager; + } +); +define('app', + [ + 'jquery', + 'resources/PreLoader', + 'resolution', + 'ui/InterfaceManager', + 'utils/Canvas', + 'game/CTRSettings', + 'ZoomManager', + 'utils/PubSub', + 'editionUI' + ], + function ($, preloader, resolution, im, Canvas, settings, ZoomManager, PubSub, editionUI) { + + var App = { + // Gives the app a chance to begin working before the DOM is ready + init: function () { + preloader.init(); + im.init(); + PubSub.publish(PubSub.ChannelId.AppInit); + }, + + // Called by the loader when the DOM is loaded + domReady: function () { + // disable text selection mode in IE9 + if (settings.disableTextSelection) { + if (typeof document.body['onselectstart'] != "undefined") { + document.body['onselectstart'] = function () { + return false; + }; + } + } + + // toggle the active css class when the user clicks + $('.ctrCursor').on('mousedown mouseup', function () { + $(this).toggleClass('ctrCursorActive'); + }); + + $('body').addClass('ui-' + resolution.UI_WIDTH); + + Canvas.domReady('c'); + + // set the canvas drawing dimensions + Canvas.element.width = resolution.CANVAS_WIDTH; + Canvas.element.height = resolution.CANVAS_HEIGHT; + + // set the screen (css) dimensions + $(Canvas.element) + .width(resolution.CANVAS_WIDTH) + .height(resolution.CANVAS_HEIGHT); + + if (ZoomManager.domReady) { + ZoomManager.domReady(); + } + + preloader.domReady(); + im.domReady(); + PubSub.publish(PubSub.ChannelId.AppDomReady); + }, + + run: function () { + + // Called by the loader when the app is ready to run + preloader.run(function() { + im.appReady(); + PubSub.publish(PubSub.ChannelId.AppRun); + + // fade in the game + $(".hideAfterLoad").fadeOut(500); + $(".hideBeforeLoad").fadeIn(500); + + var start = 10; + var inc; + var interval = setInterval(function () { + inc = Math.random() * 15 | 0; + start += inc; + + if (start > 100) { + start = 100; + $("#betterLoader").fadeOut(500); + clearInterval(interval); + } + $("#progress").animate({"width": start + "%"}, 50); + }, 100); + + // show hide behind the scenes when we first load + im.updateDevLink(); + + // put the social links back into the footer (need to be offscreen instead of hidden during load) + $("#gameFooterSocial").css("top", 0); + + }); + } + }; + + return App; + }); + +define('config/exports/CtrExport', + [], + function () { + + function ctrExport(key, value) { + // MUST use string literals for exported properties + var zeptoLab = window['ZeptoLab']; + if (zeptoLab == null) { + zeptoLab = window['ZeptoLab'] = {}; + } + + var ctr = zeptoLab['ctr']; + if (ctr == null) { + ctr = zeptoLab['ctr'] = {}; + } + ctr[key] = value; + } + + return ctrExport; + } +); + +define('ctrExports', + [ + 'config/exports/CtrExport', + 'ui/QueryStrings', + 'ui/SocialHelper', + 'game/CTRSettings', + 'utils/PubSub' + ], + function (ctrExport, QueryStrings, SocialHelper, settings, PubSub) { + + ctrExport('forceHTML5Audio', QueryStrings.forceHtml5Audio); + + window['showFpsCounter'] = function () { + settings.fpsEnabled = true; + }; + + ctrExport('initFB', SocialHelper.initFB); + ctrExport('initTwitter', SocialHelper.initTwitter); + + + ctrExport('onLevelWon', function(callback) { + + PubSub.subscribe(PubSub.ChannelId.LevelWon, function(info) { + + // don't pass along the level info, just tell subscriber + // that the level completed + callback(); + }); + }); + + + ctrExport('pauseGame', function() { + PubSub.publish(PubSub.ChannelId.PauseGame); + }); + + ctrExport('enable', function() { + PubSub.publish(PubSub.ChannelId.EnableGame); + }); + + ctrExport('disable', function() { + PubSub.publish(PubSub.ChannelId.DisableGame); + }); + + return window['ZeptoLab']; + } +); + + +require( + ['app', 'platform', 'ctrExports'], + function (app, platform) { + + // verify that the client meets platform requirements + if (!platform.meetsRequirements()) { + return; + } + + // initialize the application immediately + app.init(); + + // wait until the DOM is loaded before wiring up events + $(document).ready(function () { + app.domReady(); + + // for now, we will immediately run the app + app.run(); + }); + } +); + +define("main", function(){}); +}()); diff --git a/projects/Cut The Rope/scripts/ctr.js b/projects/Cut The Rope/scripts/ctr.js new file mode 100644 index 000000000..63f60a25a --- /dev/null +++ b/projects/Cut The Rope/scripts/ctr.js @@ -0,0 +1,711 @@ +(function() {function ha(){return function(){}}function ka(ba){return function(ca){this[ba]=ca}}function Da(ba){return function(){return this[ba]}}function Ga(ba){return function(){return ba}} +(function(){var ba=function(){var a;(function(){var c=!1,d=/var xyz/.test(ha())?/\b_super\b/:/.*/;a=ha();a.extend=function(b){function f(){!c&&this.init&&this.init.apply(this,arguments)}var a=this.prototype;c=!0;var g=new this;c=!1;for(var k in b)g[k]="function"==typeof b[k]&&"function"==typeof a[k]&&d.test(b[k])?function(b,f){return function(){var c=this.h;this.h=a[b];var d=f.apply(this,arguments);this.h=c;return d}}(k,b[k]):b[k];f.prototype=g;f.extend=arguments.callee;return f}})();return a}(), +ca=function(){function a(a,d,b,f){this.F=a;this.K=d;this.J=b;this.B=f}a.prototype.fi=function(){return"rgba("+(255*this.F>>0)+","+(255*this.K>>0)+","+(255*this.J>>0)+","+this.B.toFixed(2)+")"};a.prototype.rj=function(a){return this.F===a.F&&this.K===a.K&&this.J===a.J&&this.B===a.B};a.prototype.copy=function(){return new a(this.F,this.K,this.J,this.B)};a.prototype.qa=function(a){this.F=a.F;this.K=a.K;this.J=a.J;this.B=a.B};a.prototype.add=function(a){this.F+=a.F;this.K+=a.K;this.J+=a.J;this.B+=a.B}; +a.prototype.multiply=function(a){this.F*=a;this.K*=a;this.J*=a;this.B*=a};a.Fb=new a(0,0,0,0);a.lb=new a(1,1,1,1);a.red=new a(1,0,0,1);a.blue=new a(0,0,1,1);a.green=new a(0,1,0,1);a.ND=new a(0,0,0,1);a.dv=a.lb;a.Ck={Zi:"rgba(255,255,255,1)",CD:"rgba(0,0,0,0)"};return a}(),S=function(){return{e:0,mb:1,Tb:2,Mf:4,Jb:8,Nf:16,Df:32,S:18,parse:function(a){var c=this.e;0=f)b.x=b.y=0;else{for(var e=a.Nw,g=a.Ow,k=1-d,l=0;lthis.ie||(1this.ie||this.ub.time=this.startTime&&e.time<=this.ie&&(this.state=1,e.vd?(this.ba=this.ka.length-1,this.kb=this.ie-e.time,this.ba--,g=this.ka[this.ba+1],this.zj(g,this.ka[this.ba],g.Pc)):(this.ba=0,this.kb=e.time-this.startTime,this.ba++,g=this.ka[this.ba],this.zj(this.ka[this.ba-1],g,g.Pc)));else{this.Da-=a;g=this.ka[this.ba];if(g.Cg===c.A.Ad||g.Cg===c.A.Hb)switch(this.type){case d.Yd:var k=this.jh.value.b;g=k.x*a;var k=k.y*a,l=this.ce.value.b,n=l.x,r=l.y;l.x+= +g;l.y+=k;e.element.x+=(n+g/2)*a;e.element.y+=(r+k/2)*a;break;case d.Oe:k=this.jh.value.scale;g=k.x*a;k=k.y*a;l=this.ce.value.scale;n=l.x;r=l.y;l.x+=g;l.y+=k;e.element.X+=(n+g/2)*a;e.element.da+=(r+k/2)*a;break;case d.Ne:g=this.jh.value.Sa*a;k=this.ce.value.Sa;this.ce.value.Sa+=g;e.element.rotation+=(k+g/2)*a;break;case d.Fe:var m=this.ce.value.color;g=m.F;var k=m.K,l=m.J,n=m.B,p=this.jh.value.color,r=p.F*a,u=p.K*a,q=p.J*a,p=p.B*a;m.F+=2*r;m.K+=2*u;m.J+=2*q;m.B+=2*p;m=e.element.color;m.F+=(g+r/2)* +a;m.K+=(k+u/2)*a;m.J+=(l+q/2)*a;m.B+=(n+p/2)*a}else if(g.Cg===c.A.LINEAR)switch(g=e.element,k=this.ce.value,this.type){case d.Yd:g.x+=k.b.x*a;g.y+=k.b.y*a;break;case d.Oe:g.X+=k.scale.x*a;g.da+=k.scale.y*a;break;case d.Ne:g.Sa+=k.Sa*a;break;case d.Fe:g.color.F+=k.color.F*a,g.color.K+=k.color.K*a,g.color.J+=k.color.J*a,g.color.B+=k.color.B*a}this.Da<=b.Ef&&(e.Qh&&e.Qh(e,this.ka[this.ba],this.ba),this.kb=-this.Da,this.ba===this.ka.length-1?(this.vg(this.ka[this.ba]),this.state=0):0===this.ba?(this.vg(this.ka[this.ba]), +this.state=0):e.vd?(this.ba--,g=this.ka[this.ba+1],this.zj(g,this.ka[this.ba],g.Pc)):(this.ba++,g=this.ka[this.ba],this.zj(this.ka[this.ba-1],g,g.Pc)))}},fg:function(a,b){this.Da=b;this.vg(a);0this.length&&(this.length=c.ie))}}this.state=f.Z.Hq;this.update(0)},pause:function(){this.state=f.Z.Tg},Vs:function(a,b){this.state===f.Z.Xg&&(this.state=f.Z.Tg);this.update(this.Qc[a].xn(b)-this.time)},stop:function(){this.state=f.Z.Xg;this.zx()},zx:function(){for(var a=0,b=this.Qc.length;a=this.length-b.Ef?(this.time=Math.max(0,this.length-(this.time-this.length)),this.vd=!0):this.vd&&this.time<=b.Ef&&(0=this.length-b.Ef&&(0=this.length-b.Ef&&(this.stop(),this.cb&&this.cb(this))}}}});f.ha={Wa:0,vb:1,Gq:2};f.Z={Xg:0,Hq:1,Tg:2};return f}(ba,qb,Ia,N),ea=function(){return{ZD:6.283185307179586,dc:function(a){return 0.017453292519943295*a},Bg:function(a){return 57.29577951308232*a}}}(),ia=function(a,c,d,b,f,e,g,k){return a.extend({init:function(){this.parent=null;this.qi=this.Yb=this.visible=!0;this.name=null;this.ug=this.Rd=this.rotation=this.height=this.width=this.fa= +this.ea=this.y=this.x=0;this.da=this.X=1;this.color=c.lb.copy();this.Ru=this.Qu=0;this.anchor=d.Jb|d.mb;this.oa=d.e;this.Wh=this.te=!0;this.Vj=!1;this.children=[];this.Be=[];this.Vf=b.e;this.yb=null},dh:function(){var a=this.oa,b=this.parent,f=this.anchor;a!==d.e?(a&d.mb?this.ea=b.ea+this.x:a&d.Tb?this.ea=b.ea+this.x+b.width/2:a&d.Mf&&(this.ea=b.ea+this.x+b.width),a&d.Jb?this.fa=b.fa+this.y:a&d.Nf?this.fa=b.fa+this.y+b.height/2:a&d.Df&&(this.fa=b.fa+this.y+b.height)):(this.ea=this.x,this.fa=this.y); +f&d.Jb||(f&d.Nf?this.fa-=this.height/2:f&d.Df&&(this.fa-=this.height));f&d.mb||(f&d.Tb?this.ea-=this.width/2:f&d.Mf&&(this.ea-=this.width))},vc:function(){this.dh();var a=0!==this.X&&0!==this.da&&(1!==this.X||1!==this.da),b=0!==this.rotation,c=0!==this.Qu||0!==this.Ru,d=f.context;d.save();if(a||b){var e=this.ea+this.width/2+this.Rd,g=this.fa+this.height/2+this.ug,q=0!==e||0!==g;q&&d.translate(e,g);b&&d.rotate(k.dc(this.rotation));a&&d.scale(this.X,this.da);q&&d.translate(-e,-g)}c&&d.translate(this.Qu, +this.Ru);this.ak=d.globalAlpha;1!==this.color.B&&this.color.B!==this.ak&&(d.globalAlpha=this.color.B)},v:function(){this.vc();this.uc()},Yf:function(){var a=f.context;a.strokeStyle="red";a.strokeRect(this.ea,this.fa,this.width,this.height)},uc:function(){var a=f.context,b=1!==this.color.B&&this.color.B!==this.ak;if(this.dE){var c=this.ea+(this.width>>1)+this.Rd,d=this.fa+(this.height>>1)+this.ug;a.save();a.lineWidth=5;a.strokeStyle="#ff0000";a.beginPath();a.moveTo(c,d);a.lineTo(c,d-100);a.closePath(); +a.stroke();a.restore()}this.te?!this.Wh&&b&&(f.context.globalAlpha=this.ak):(this.Ss&&this.Yf(),a.restore(),this.Wh&&b&&(f.context.globalAlpha=this.color.B));for(var c=this.children,d=c.length,e=0;ef&&(f=s);k>c&&(c=k)}this.width=f-a;this.height=c-b},Ns:function(a){switch(a.Pr){case e.Si:this.visible=0!==a.$g;break;case e.Ul:this.qi=0!==a.$g;break;case e.Tl:this.Yb=0!==a.$g;break;case e.Il:this.R(a.$g); +break;case e.Fq:this.eA();break;case e.yw:this.Bu();break;case e.Wv:this.yb.Vs(a.Qr,a.$g);break;default:return!1}return!0},T:function(a){this.children.push(a);a.parent=this;return this.children.length-1},ae:function(a,b){this.children[b]=a;a.parent=this},Ot:function(a){this.children.splice(a,1).parent=null},Nt:function(){this.children=[]},removeChild:function(a){for(var b=this.children,f=b.length,c=0;cd?f:0)+(m.y +r?g:0)}c.copy=function(a){return new c(a.x,a.y,a.M,a.U)};c.Sd=function(a,b){return new c(a.x*b,a.y*b,a.M*b,a.U*b)};c.ai=function(a,b,f,c,d,e,g,q){return!(a>g||fq||ca.x&&(a.M+=a.x,a.x=0);a.x+a.M>f&&(a.M=f-a.x);0>a.y&&(a.U+=a.y,a.y=0);a.y+a.U>d&&(a.U=d-a.y);return a};c.Db=function(a,b,f,c,d,e){return a>=f&&a=c&&bthis.vf.length&&(a=this.vf.length);for(var b=c.context,d=0;d=n)continue;else 1>n&&(b.globalAlpha=n);var u=this.tg&&this.tg.length>d;if(u){var q=this.tg[d],A=this.mk[d], +s=0!==A.x||0!==A.y;0!==q&&(s&&b.translate(A.x,A.y),b.rotate(q),s&&b.translate(-A.x,-A.y))}var z,h,C;this.Ha?(z=Math.round(l.x/this.Ha)*this.Ha,h=Math.round(l.y/this.Ha)*this.Ha,C=Math.round(l.M/this.Ha)*this.Ha,l=Math.round(l.U/this.Ha)*this.Ha):(z=Math.round(l.x),h=Math.round(l.y),C=Math.ceil(l.M),l=Math.ceil(l.U));b.drawImage(this.L.qc,k.x,k.y,m,p,z,h,C,l);u&&0!==q&&(s&&b.translate(A.x,A.y),b.rotate(-q),s&&b.translate(-A.x,-A.y));1!==n&&(b.globalAlpha=r)}}},v:function(){this.vc();if(0!==this.color.B){var a= +c.context,b=0!==this.ea||0!==this.fa;b&&a.translate(this.ea,this.fa);this.ws(this.Pj===d.e?this.vf.length:this.Pj);b&&a.translate(-this.ea,-this.fa)}this.uc()}})}(ia,P,N,U),w={IC:0,LC:1,GC:2,PC:3,Ff:4,Kg:5,UC:6,ia:7,AD:8,Yl:9,Xl:10,Wl:11,Zl:12,cm:13,em:14,fm:15,gm:16,fr:17,jm:18,gr:19,hr:20,ir:21,km:22,qm:23,jr:24,kr:25,Cd:26,hm:27,dr:28,er:29,im:30,nm:31,om:32,pm:33,rm:34,sm:35,Ui:36,Vi:37,$l:38,Vl:39,MC:40,NC:41,YC:42,OC:43,VC:44,TC:45,WC:46,RC:47,SC:48,QC:49,JC:50,Bc:51,Rg:52,HC:53,XC:54,ZC:55, +Xk:56,KC:57,$C:58,ul:59,Pg:60,kl:61,Ji:62,tl:63,Hi:64,ll:65,ml:66,Wc:67,Gi:68,sl:69,rl:70,ql:71,Hf:73,Ii:74,Je:75,Li:76,vl:77,If:78,il:79,jl:80,jc:81,lm:82,mm:83,Ti:84,Vg:85,bm:105,am:106,sw:107,hl:108,Mi:111,nl:112,ol:113,pl:114,Qg:115,Og:116,Ki:117,Wi:118,Xi:119,Fi:120,cl:121,Xp:122,dl:123,Yp:124,Zp:125,$p:126,el:127,aq:128,bq:129,cq:130,fl:131,dq:132,fq:133,gq:134,gl:135,iq:136,jq:137,kq:138,lq:139,nq:140,oq:141,pq:142,qq:143,rq:144,sq:145,tq:146,uq:147,vq:148,wq:149,vv:150,wv:151,xv:152,yv:153, +Bv:154,Cv:155,Dv:156,Ev:157,Fv:158,Gv:159,Hv:160,Iv:161,Jv:162,Kv:163,Lv:164,Mv:165,Nv:166,Ov:167,Pv:168,Qv:169,Sv:170,Tv:171,Uv:172,Vv:173,Zq:174,$q:175,br:176,ar:177,cr:178,lr:179,Rv:180,ic:72,Ie:181,Ng:182,dm:183,mD:183},rb=[{id:w.Ff,dd:-1,sc:-42,fc:20,Se:"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u00a9\u00c0\u00e0\u00c2\u00e2\u00c6\u00e6\u00c7\u00e7\u00c8\u00e8\u00c9\u00e9\u00ca\u00ea\u00cb\u00eb\u00ce\u00ee\u00cf\u00ef\u00d4\u00f4\u0152\u0153\u00d9\u00f9\u00db\u00fb\u00dc\u00fc\u00ab\u00bb\u20ac\u00c4\u00e4\u00c9\u00e9\u00d6\u00f6\u00dc\u00fc\u00df\u201e\u201c\u201d\u00b0\u0410\u0411\u0412\u0413\u0414\u0415\u0401\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", +ef:{},f:[4,4,33,156,41,4,38,156,83,4,61,156,148,4,41,156,193,4,73,156,270,4,38,156,312,4,19,156,335,4,44,156,383,4,41,156,428,4,54,156,486,4,43,156,533,4,22,156,559,4,46,156,609,4,23,156,636,4,51,156,691,4,54,156,749,4,23,156,776,4,53,156,833,4,44,156,881,4,48,156,933,4,51,156,4,164,49,156,57,164,52,156,113,164,55,156,172,164,41,156,217,164,24,156,245,164,24,156,273,164,59,156,336,164,36,156,376,164,51,156,431,164,44,156,479,164,62,156,545,164,51,156,600,164,51,156,655,164,58,156,717,164,48,156,769, +164,46,156,819,164,45,156,868,164,50,156,922,164,49,156,975,164,24,156,4,324,45,156,53,324,45,156,102,324,54,156,160,324,73,156,237,324,43,156,284,324,63,156,351,324,59,156,414,324,54,156,472,324,51,156,527,324,57,156,588,324,56,156,648,324,59,156,711,324,52,156,767,324,74,156,845,324,63,156,912,324,47,156,4,484,67,156,75,484,65,156,144,484,54,156,202,484,56,156,262,484,40,156,306,484,74,156,384,484,24,156,412,484,45,156,461,484,51,156,516,484,49,156,569,484,48,156,621,484,43,156,668,484,47,156,719, +484,42,156,765,484,43,156,812,484,25,156,841,484,39,156,884,484,50,156,938,484,22,156,4,644,69,156,77,644,40,156,121,644,37,156,162,644,45,156,211,644,63,156,278,644,43,156,325,644,44,156,373,644,52,156,429,644,46,156,479,644,54,156,537,644,73,156,614,644,59,156,677,644,54,156,735,644,58,156,797,644,57,156,858,644,25,156,887,644,42,156,933,644,49,156,4,804,75,156,83,804,51,156,138,804,44,156,186,804,51,156,241,804,47,156,292,804,83,156,379,804,62,156,445,804,54,156,503,804,43,156,550,804,45,156,599, +804,45,156,648,804,45,156,697,804,45,156,746,804,45,156,795,804,45,156,844,804,45,156,893,804,45,156,942,804,41,156,4,964,41,156,49,964,33,156,86,964,34,156,124,964,63,156,191,964,48,156,243,964,82,156,329,964,61,156,394,964,53,156,451,964,44,156,499,964,53,156,556,964,43,156,603,964,53,156,660,964,43,156,707,964,53,156,764,964,59,156,827,964,65,156,896,964,51,156,951,964,44,156,4,1124,45,156,53,1124,45,156,102,1124,63,156,169,1124,48,156,221,1124,53,156,278,1124,43,156,325,1124,53,156,382,1124,43, +156,429,1124,43,156,476,1124,43,156,523,1124,40,156,567,1124,65,156,636,1124,47,156,687,1124,50,156,741,1124,49,156,794,1124,64,156,862,1124,46,156,912,1124,46,156,4,1284,73,156,81,1284,46,156,131,1284,54,156,189,1284,54,156,247,1284,62,156,313,1284,62,156,379,1284,64,156,447,1284,52,156,503,1284,59,156,566,1284,53,156,623,1284,48,156,675,1284,49,156,728,1284,59,156,791,1284,55,156,850,1284,59,156,913,1284,55,156,4,1444,58,156,66,1444,49,156,119,1444,72,156,195,1444,83,156,282,1444,62,156,348,1444, +58,156,410,1444,50,156,464,1444,48,156,516,1444,67,156,587,1444,51,156,642,1444,44,156,690,1444,41,156,735,1444,39,156,778,1444,37,156,819,1444,41,156,864,1444,40,156,908,1444,40,156,952,1444,61,156,4,1604,38,156,46,1604,43,156,93,1604,43,156,140,1604,44,156,188,1604,45,156,237,1604,62,156,303,1604,42,156,349,1604,40,156,393,1604,49,156,446,1604,46,156,496,1604,38,156,538,1604,69,156,611,1604,42,156,657,1604,61,156,722,1604,43,156,769,1604,45,156,818,1604,40,156,862,1604,63,156,929,1604,65,156,4, +1764,51,156,59,1764,51,156,114,1764,40,156,158,1764,39,156,201,1764,60,156,265,1764,40,156,309,1764,112,156]},{id:w.Kg,dd:2,sc:-90,fc:15,Se:"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u00a9\u00c0\u00e0\u00c2\u00e2\u00c6\u00e6\u00c7\u00e7\u00c8\u00e8\u00c9\u00e9\u00ca\u00ea\u00cb\u00eb\u00ce\u00ee\u00cf\u00ef\u00d4\u00f4\u0152\u0153\u00d9\u00f9\u00db\u00fb\u00dc\u00fc\u00ab\u00bb\u20ac\u00c4\u00e4\u00c9\u00e9\u00d6\u00f6\u00dc\u00fc\u00df\u201e\u201c\u201d\u00b0\u0410\u0411\u0412\u0413\u0414\u0415\u0401\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", +ef:{},f:[4,4,16,156,24,4,19,156,47,4,35,156,86,4,21,156,111,4,43,156,158,4,19,156,181,4,7,156,192,4,24,156,220,4,23,156,247,4,30,156,281,4,24,156,309,4,9,156,322,4,25,156,351,4,10,156,365,4,28,156,397,4,31,156,432,4,10,156,446,4,29,156,479,4,24,156,507,4,26,156,537,4,29,156,570,4,28,156,602,4,29,156,635,4,31,156,670,4,21,156,695,4,10,156,709,4,10,156,723,4,33,156,760,4,19,156,783,4,28,156,815,4,24,156,843,4,36,156,883,4,28,156,915,4,28,156,947,4,32,156,983,4,27,156,4,164,25,156,33,164,24,156,61,164, +28,156,93,164,28,156,125,164,10,156,139,164,25,156,168,164,24,156,196,164,31,156,231,164,43,156,278,164,24,156,306,164,37,156,347,164,34,156,385,164,30,156,419,164,29,156,452,164,32,156,488,164,31,156,523,164,34,156,561,164,29,156,594,164,43,156,641,164,36,156,681,164,26,156,711,164,39,156,754,164,38,156,796,164,30,156,830,164,32,156,866,164,22,156,892,164,44,156,940,164,11,156,955,164,25,156,984,164,29,156,4,324,27,156,35,324,26,156,65,324,24,156,93,324,26,156,123,324,23,156,150,324,24,156,178,324, +11,156,193,324,20,156,217,324,28,156,249,324,9,156,262,324,41,156,307,324,21,156,332,324,20,156,356,324,25,156,385,324,36,156,425,324,22,156,451,324,24,156,479,324,29,156,512,324,26,156,542,324,31,156,577,324,43,156,624,324,34,156,662,324,30,156,696,324,33,156,733,324,32,156,769,324,12,156,785,324,22,156,811,324,27,156,842,324,45,156,891,324,29,156,924,324,24,156,952,324,29,156,985,324,26,156,4,484,49,156,57,484,36,156,97,484,30,156,131,484,23,156,158,484,24,156,186,484,24,156,214,484,24,156,242, +484,24,156,270,484,24,156,298,484,24,156,326,484,24,156,354,484,24,156,382,484,22,156,408,484,22,156,434,484,17,156,455,484,17,156,476,484,36,156,516,484,27,156,547,484,50,156,601,484,35,156,640,484,29,156,673,484,24,156,701,484,29,156,734,484,23,156,761,484,29,156,794,484,23,156,821,484,30,156,855,484,34,156,893,484,37,156,934,484,29,156,967,484,24,156,995,484,24,156,4,644,24,156,32,644,36,156,72,644,27,156,103,644,29,156,136,644,23,156,163,644,30,156,197,644,23,156,224,644,23,156,251,644,23,156, +278,644,22,156,304,644,38,156,346,644,26,156,376,644,28,156,408,644,28,156,440,644,38,156,482,644,25,156,511,644,25,156,540,644,44,156,588,644,26,156,618,644,30,156,652,644,30,156,686,644,37,156,727,644,36,156,767,644,37,156,808,644,29,156,841,644,34,156,879,644,30,156,913,644,28,156,945,644,27,156,976,644,34,156,4,804,31,156,39,804,34,156,77,804,31,156,112,804,33,156,149,804,28,156,181,804,43,156,228,804,51,156,283,804,36,156,323,804,33,156,360,804,28,156,392,804,27,156,423,804,40,156,467,804,29, +156,500,804,24,156,528,804,22,156,554,804,20,156,578,804,19,156,601,804,22,156,627,804,21,156,652,804,21,156,677,804,36,156,717,804,20,156,741,804,24,156,769,804,24,156,797,804,24,156,825,804,25,156,854,804,35,156,893,804,24,156,921,804,22,156,947,804,28,156,979,804,26,156,4,964,20,156,28,964,41,156,73,964,23,156,100,964,36,156,140,964,24,156,168,964,25,156,197,964,22,156,223,964,37,156,264,964,38,156,306,964,30,156,340,964,29,156,373,964,22,156,399,964,21,156,424,964,35,156,463,964,22,156,489,964, +112,156]},{id:w.Bc,D:393,C:418,f:[2,2,218,226,224,2,151,151,2,232,157,158,224,157,98,62,326,157,48,45,379,2,49,59,432,2,55,57,379,65,53,63,163,232,146,147,2,394,153,163,2,561,153,166,2,731,156,169,2,904,163,175,169,904,159,175,159,394,159,159,313,232,150,150,322,394,144,150,159,561,138,146,2,1083,302,303,301,561,107,158,412,561,96,157,2,1390,252,268,2,1662,278,305,2,1971,371,397,2,2372,385,396,2,2772,377,386],p:[103,130,122,133,119,131,145,176,168,182,171,177,168,182,160,176,119,128,115,115,115,112, +115,112,115,112,119,115,122,134,131,143,137,143,140,147,47,56,143,133,155,133,69,83,50,37,6,-2,0,-5,8,2]},{id:52,D:552,C:552,f:[0,0,88,85,0,85,46,152,46,85,106,149,0,237,78,162,78,237,93,155,0,399,88,158,152,85,46,152,88,399,144,145,0,557,138,141,0,698,145,145,0,843,146,141,0,984,161,140,0,1124,130,155],p:[235,190,256,121,226,124,240,111,233,118,235,115,256,121,213,220,219,232,212,220,211,232,203,178,211,273]},{id:56,dd:2,sc:2,fc:10,Se:"0123456789",ef:{},f:[5,5,49,156,59,5,16,156,80,5,48,156,133, +5,38,156,176,5,41,156,222,5,45,156,272,5,43,156,320,5,47,156,372,5,49,156,426,5,35,156]},{id:59,D:552,C:552,f:[0,0,246,268,0,268,334,370,246,0,205,231,0,638,308,353,0,991,387,461,0,1452,324,399,0,1851,335,328,0,2179,296,266,0,2445,240,230,296,2179,207,217,308,638,204,205,240,2445,200,194,308,843,195,133],p:[145,116,76,38,166,132,113,56,75,-2,113,34,87,82,102,114,128,124,148,130,149,134,151,138,153,141]},{id:60,D:250,C:250,f:[0,0,139,170,139,0,142,169,281,0,148,163,429,0,155,155,584,0,163,148,747, +0,169,142,584,148,171,139,584,287,169,141,755,148,165,145,755,293,159,151,429,155,153,159,281,163,147,164,139,169,141,169,0,170,139,170],p:[55,40,54,41,51,44,47,48,43,51,40,54,39,56,40,55,42,53,46,50,48,46,51,44,54,41,55,40]},{id:61,D:449,C:446,f:[0,0,308,285,0,285,302,282,0,567,297,281,0,848,296,277,0,1125,293,274,0,1399,293,273,0,1672,295,271,0,1943,297,269,0,2212,239,226,239,2212,241,223,0,2438,244,221,244,2438,249,219],p:[83,82,87,84,90,86,91,90,93,94,92,99,90,104,88,111,101,119,97,128,92,138, +86,148]},{id:62,D:275,C:275,f:[0,0,140,144,0,144,42,37],p:[69,62,117,119]},{id:63,D:833,C:250,f:[0,0,566,93],p:[133,76]},{id:64,D:250,C:250,f:[0,0,155,154,0,154,181,210,0,364,185,180,0,544,183,178],p:[47,50,32,36,35,40,35,40]},{id:65,D:275,C:275,f:[0,0,125,126,0,126,37,35],p:[78,76,122,121]},{id:66,D:275,C:275,f:[0,0,125,126,0,126,37,35],p:[75,76,119,121]},{id:67,D:552,C:552,f:[2,2,234,221,240,2,77,76,240,82,70,76,321,2,64,76,321,82,58,76,389,2,51,76,389,82,46,76,444,2,40,77,444,83,34,77,488,2,28, +78,488,84,28,78,520,2,35,77,559,2,42,77,605,2,48,77,657,2,56,77,717,2,63,77,784,2,69,77,857,2,76,77,857,83,83,78,2,227,175,175,181,227,175,175,360,227,175,175,539,227,175,175,718,227,175,175,2,406,175,175,181,406,175,175,360,406,175,175,539,406,175,175,718,406,175,175,2,585,175,175,181,585,175,175,360,585,175,175,539,585,175,175,718,585,175,175,2,764,175,175,181,764,175,175,360,764,175,175,539,764,175,175,718,764,175,175,2,943,175,175,181,943,175,175,360,943,175,175,539,943,175,175,718,943,175,175, +2,1122,175,175,2,1301,175,175,2,1480,175,175,2,1659,175,175,2,1838,175,175,181,1122,175,175,360,1122,175,175,539,1122,175,175,718,1122,175,175,181,1301,175,175,181,1480,175,175,181,1659,175,175,360,1301,229,231,593,1301,229,231,360,1536,490,492],p:[156,156,233,231,236,231,239,231,242,231,246,231,248,231,251,231,254,231,257,231,257,231,253,231,250,231,247,231,243,231,240,231,237,231,234,231,230,230,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,155,159,155,159,27,21]},{id:w.Gi,D:100,C:100,f:[0,0,84,85,84,0,58,85,142,0,32,85,174,0,12,85,186,0,28,85,214,0,44,85,258,0,60,85,318,0,70,85,388,0,78,85,466,0,84,85,550,0,84,85],p:[6,5,19,5,32,5,42,5,34,5,26,5,18,5,13,5,9,5,6,5,6,5]},{id:69,D:833,C:250,f:[0,0,453,93],p:[191,76]},{id:70,D:833,C:250,f:[0,0, +333,93],p:[251,79]},{id:71,D:833,C:250,f:[0,0,212,93],p:[310,79]},{id:72,D:640,C:640,f:[0,0,291,302,291,0,363,409,654,0,383,309,1037,0,314,335,1351,0,326,334,1677,0,374,330,291,409,405,492,2051,0,350,334,0,302,201,207,0,509,201,206,0,715,201,207,0,922,201,207,0,1129,201,206,0,1335,201,210,0,1545,201,213,0,1758,201,215,0,1973,201,219,0,2192,201,222,0,2414,201,223,0,2637,201,222,0,2859,201,224,0,3083,201,224,0,3307,201,224,0,3531,201,221,0,3752,201,218,2401,0,201,214,2602,0,201,211,2803,0,222,196,2803, +196,210,201,3025,0,203,209,3228,0,197,214,3425,0,193,217,3618,0,194,219,3812,0,197,210,291,901,200,202,3812,210,204,197,291,1103,208,199,291,1302,212,202,291,1504,214,205,291,1709,216,206,291,1915,204,226,291,2141,203,213,495,1915,201,210,494,2141,201,208,291,2354,201,203,3025,209,201,200,491,901,201,200,492,2354,201,200,291,2557,201,200,291,2757,201,207,291,2964,201,216,492,2557,204,194,291,3180,221,171,291,3351,249,197,291,3548,225,201,291,3749,205,205,492,2964,202,213,696,409,201,222,897,409,201, +222,1098,409,205,221,1303,409,229,213,1532,409,243,205,0,3970,153,86,654,309,140,89,1775,409,212,196,1987,409,208,209,496,3749,197,233,696,631,186,247,882,631,181,245,1063,631,186,243,1249,631,194,234,1443,631,199,230,2195,409,199,221,1642,631,199,223,1841,631,199,226,2040,631,199,228,2239,631,199,230,2438,631,199,230,2637,631,199,230,2836,631,195,234,3031,631,190,238,3221,631,194,231,2394,409,201,217,2595,409,207,209,2802,409,218,202,3020,409,211,206,3231,409,206,210,3437,409,210,213,3647,409,215, +218,3415,631,220,223,3862,409,224,216,3635,631,219,212,492,2757,195,205,3854,631,195,207,696,878,195,210,891,878,217,214,891,1092,225,215,891,1307,219,215,696,1088,195,215,696,1303,195,215,696,1518,195,215,891,1522,217,215,891,1737,225,215,891,1952,223,218,891,2170,219,222,891,2392,215,224,891,2616,216,216,1108,878,210,206,1318,878,218,202,1536,878,205,190,1741,878,203,194,1944,878,202,206,2146,878,203,214,891,2832,204,217,891,3049,204,216,2349,878,204,213,2553,878,205,204,2758,878,205,192,2401,214, +201,195,2963,878,201,206,3164,878,204,212,3368,878,205,214,891,3265,207,215,891,3480,208,216,3573,878,205,205,3778,878,226,202,891,3696,212,204,696,1733,195,210,696,1943,189,213,696,2156,190,218,696,2374,193,222,1116,1092,198,213,1314,1092,203,210,1517,1092,207,202,1724,1092,211,204,1935,1092,214,207,2149,1092,216,211,2365,1092,216,212,2581,1092,216,212,2797,1092,216,212,3013,1092,216,212,3229,1092,216,212,3445,1092,216,212,3661,1092,216,212,3877,1092,216,212,1116,1305,216,212,1116,1517,212,216,1116, +1733,206,222,1116,1955,202,225,1116,2180,205,222,1116,2402,210,213,1116,2615,212,208,1116,2823,198,223,1116,3046,196,232,696,2596,195,236,1116,3278,198,236,1116,3514,206,238,1116,3752,211,226,1332,1305,217,207,891,3900,213,195,1549,1305,212,179,1761,1305,221,178,1982,1305,221,181,2203,1305,215,180,2418,1305,212,179,2630,1305,221,177,2851,1305,221,180,3072,1305,215,180,3287,1305,212,179,3499,1305,221,177,3720,1305,221,180,1332,1512,215,180,1332,1692,212,179,1547,1512,216,176,1332,1871,213,175,696, +2832,194,205,696,3037,188,236,696,3273,194,233,1332,2046,210,202,1332,2248,204,194,1332,2442,202,204],p:[173,274,137,156,133,207,152,237,154,244,134,240,107,104,148,242,220,227,220,227,220,227,220,227,220,227,220,224,220,221,220,218,220,215,220,212,220,211,220,211,220,210,220,210,220,210,220,213,220,216,220,220,220,223,211,238,216,233,220,225,223,220,225,217,224,215,223,224,221,232,219,237,217,235,215,232,214,229,213,228,217,208,218,221,219,224,219,226,219,231,219,234,219,234,219,234,219,234,219, +226,219,218,218,240,210,263,192,237,204,233,217,229,220,221,220,212,220,212,217,212,202,221,195,229,240,264,249,265,215,238,217,225,223,201,228,187,231,189,228,191,223,200,220,204,220,213,220,211,220,208,220,206,220,204,220,204,220,204,222,200,225,196,223,203,220,217,216,225,211,232,216,228,218,224,212,221,208,216,205,211,202,218,208,222,232,229,232,227,232,224,210,220,202,219,208,219,232,219,232,219,232,219,210,219,202,219,202,216,205,212,207,210,208,218,217,228,211,232,216,244,218,240,219,227,220, +219,220,216,220,217,220,221,218,230,216,242,220,239,220,228,217,222,216,220,214,219,213,218,216,229,207,232,214,230,224,224,227,221,226,216,225,212,222,220,219,224,218,231,216,229,214,226,213,222,213,221,213,221,213,221,213,221,213,221,213,221,213,221,213,221,213,221,215,217,218,211,220,208,218,212,216,221,215,226,222,210,223,201,223,197,222,197,219,195,216,206,211,225,213,238,213,254,207,255,207,252,210,253,213,254,207,256,207,253,210,253,213,254,207,256,207,253,210,253,213,254,211,257,214,258,227, +227,230,195,226,199,215,232,218,239,220,230]},{id:73,D:275,C:275,f:[0,0,137,139,137,0,105,100,0,139,235,235,0,374,240,246],p:[65,70,84,86,18,19,13,14]},{id:74,D:833,C:250,f:[0,0,507,85,0,85,507,100,0,185,507,100,0,285,507,97,0,382,507,92],p:[163,82,163,73,163,71,163,70,163,75]},{id:75,D:276,C:276,f:[0,0,84,128,84,0,68,109,152,0,50,109,0,128,140,121,0,249,148,147]},{id:76,D:761,C:761,f:[0,0,220,239,0,239,206,290,0,529,205,290,0,819,220,246,0,1065,237,219,0,1284,226,231,220,0,18,17,238,0,11,11,206, +239,38,39],p:[271,262,286,232,287,232,271,249,262,272,268,266,382,376,385,379,372,365]},{id:77,D:998,C:1058,f:[3,3,148,12,3,21,39,187,48,21,182,150,236,21,144,130,3,214,244,233,253,214,159,143,157,3,49,9,386,21,89,84,3,453,102,148,3,607,260,315],p:[585,767,160,241,412,548,307,397,184,663,530,224,676,540,540,425,351,211,684,200]},{id:78,D:431,C:431,f:[0,0,294,335,294,0,297,336,0,335,291,252,591,0,307,293,0,587,276,224],p:[53,6,51,3,55,78,47,57,63,98]},{id:79,D:833,C:250,f:[0,0,194,127,0,127,201,103, +0,230,204,96,0,326,193,142,0,468,194,111],p:[319,69,316,81,314,87,319,55,319,77]},{id:80,D:833,C:250,f:[0,0,302,123,302,0,319,99,621,0,322,95,302,99,292,136,0,123,302,111],p:[268,70,260,85,258,87,273,58,268,77]},{id:108,f:[0,0,198,194,0,194,198,194,0,388,198,194]},{id:111,f:[0,0,202,81],p:[316,87],D:833,C:250},{id:112,f:[0,0,319,83],p:[260,87],D:833,C:250},{id:113,f:[0,0,444,86],p:[195,81],D:833,C:250},{id:114,f:[0,0,559,89],p:[137,77],D:833,C:250},{id:115,f:[0,0,101,102,0,102,101,102,0,204,101,102, +0,306,101,102],p:[219,29,218,29,219,29,219,29],D:534,C:160},{id:116,D:275,C:275,f:[0,0,4,4,2,2,89,116,95,2,177,37,276,2,187,77,95,43,87,61],p:[143,196,93,75,50,84,45,39,95,35]},{id:117,D:25,C:25,f:[0,0,25,25]},{id:w.Fi,f:[0,0,291,302,0,302,363,409,363,302,383,309,0,711,405,492,405,711,374,330,0,1203,350,334,0,1537,314,335,350,1203,326,334,291,0,339,288,630,0,275,162,350,1537,372,317],p:[173,274,137,156,133,207,107,104,134,240,148,242,152,237,154,244,145,259,181,392,123,236],D:640,C:640},{id:w.jc, +f:[1,1,1064,1064,1067,1,532,495,1601,1,145,286,1601,289,38,38,1748,1,204,174,1748,177,183,154],p:[55,154,55,686,442,543,568,667,484,1083,493,1093],D:1174,C:1498},{id:w.ic,wa:1,f:[1,1,201,207,1,210,201,205,1,417,201,206,1,625,201,207,1,834,201,207,1,1043,201,211,1,1256,201,214,1,1472,201,218,1,1692,201,220,204,1,201,222,204,225,201,224,204,451,201,224,204,677,201,225,204,904,201,226,204,1132,201,226,407,1,201,221,610,1,201,217,813,1,201,213,1016,1,201,210,407,225,204,225,1219,1,203,213,1424,1,201, +210,1627,1,201,207,1830,1,201,203,204,1360,201,200,204,1562,201,200,204,1764,201,200,613,225,201,200,816,225,201,208,1019,225,201,216,1222,225,204,193,1428,225,221,171,1651,225,249,196,407,452,225,197,407,651,205,204,407,857,201,216,407,1075,202,222,407,1299,202,225,407,1526,205,224,407,1752,223,213,634,452,242,203,1,1914,153,86,1902,225,140,89,878,452,218,201,634,657,211,205,634,864,205,210,634,1076,211,214,847,657,214,217,847,876,220,223,1063,657,224,216,1289,657,219,212,634,1292,195,206,634,1500, +195,207,634,1709,195,211,1510,657,217,214,1729,657,225,215,847,1101,219,215,847,1318,195,215,847,1535,195,215,847,1752,195,215,1069,876,217,215,1288,876,225,215,1069,1093,224,219,1069,1314,219,222,1069,1538,215,225,1069,1765,215,217,1515,876,210,205,1098,452,218,201,1318,452,206,193,1526,452,201,195,1727,876,201,206,1295,1093,204,212,1295,1307,206,214,1503,1307,208,215,1503,1524,208,216,1501,1093,206,205,1729,452,206,191,1709,1093,204,194,1295,1523,202,206,1295,1731,202,214,1503,1742,203,217,1713, +1524,204,216,1713,1307,204,212,1713,1742,204,204],p:[220,227,220,228,220,228,220,227,220,227,220,223,220,220,220,216,220,214,220,212,220,210,220,210,220,209,220,208,220,208,220,213,220,217,220,221,220,224,217,209,218,221,219,224,219,227,219,231,219,234,219,234,219,234,219,234,219,226,219,218,218,241,210,263,191,238,203,237,216,230,220,218,219,212,219,209,216,210,204,221,195,231,240,264,249,265,210,232,216,228,218,223,211,220,208,216,204,211,201,218,207,222,231,228,231,227,231,223,209,220,201,219, +207,219,231,219,231,219,231,219,209,219,201,219,201,215,204,212,207,209,208,217,216,228,210,232,215,240,220,238,220,227,217,221,215,219,213,218,213,217,215,228,215,242,217,239,219,226,220,218,220,215,220,216,219,220,218,229],D:640,C:640},{id:w.Ie,wa:1,f:[1,1,213,196,1,199,207,209,1,410,197,232,1,644,186,246,1,892,181,246,1,1140,186,244,1,1386,195,232,1,1620,200,229,210,199,200,219,210,420,200,221,210,643,200,224,210,869,200,227,210,1098,200,229,210,1329,200,229,210,1560,200,229,210,1791,195,234,412, +199,190,238,604,199,194,230,800,199,202,215,1004,199,207,207,1213,199,225,202,1440,199,213,205,1655,199,195,209,1852,199,189,213,412,439,190,217,604,439,193,221,799,439,198,213,999,439,203,208,1204,439,207,202,1413,439,211,204,1626,439,215,207,604,662,216,210,604,874,216,211,604,1087,216,211,604,1300,216,211,604,1513,216,211,604,1726,216,211,822,662,216,211,1040,662,216,211,1258,662,216,211,1476,662,216,211,822,875,212,215,822,1092,205,222,822,1316,202,225,822,1543,205,220,1694,662,210,211,1036,875, +213,207,1843,439,201,207,822,1765,198,222,1036,1084,195,232,1036,1318,195,235,1233,1084,199,236,1233,1322,206,238,1434,1084,211,226,1251,875,217,207,216,1,213,195,431,1,212,179,645,1,221,178,868,1,221,180,1091,1,215,180,1308,1,212,179,1522,1,221,177,1745,1,221,180,1470,875,215,180,1687,875,212,179,1647,1084,221,177,1441,1322,221,180,1664,1322,215,180,1441,1504,212,179,1655,1504,216,176,1655,1682,213,174,1036,1555,193,204,412,658,188,237,1036,1761,194,233,1441,1685,210,202,1,1851,205,194,1233,1562, +202,204],p:[214,238,217,225,222,202,228,188,230,188,227,190,222,202,219,205,219,215,219,213,219,210,219,207,219,205,219,205,219,205,222,200,225,196,223,204,219,219,216,227,207,232,213,229,223,224,226,221,226,216,224,212,221,220,219,225,217,231,215,229,213,226,213,223,213,222,213,222,213,222,213,222,213,222,213,222,213,222,213,222,213,222,215,218,218,211,219,208,218,213,215,222,214,226,219,227,221,211,223,201,222,198,220,197,218,195,215,206,210,225,212,238,212,254,206,255,206,253,209,253,212,254,206, +256,206,253,209,253,212,254,206,256,206,253,209,253,212,254,210,257,213,259,226,228,229,195,225,199,214,232,217,240,219,230],D:640,C:640},{id:w.Ng,wa:1,f:[1,1,222,196,1,199,209,201,1,402,203,209,1,613,197,215,1,830,193,218,1,1050,194,219,200,613,197,210,206,402,201,202,212,199,204,198,196,830,208,200,197,1050,212,204,1,1271,215,207,1,1480,216,208],p:[211,238,216,233,219,225,222,219,224,216,224,215,222,224,220,232,219,236,217,235,215,231,213,228,213,227],D:640,C:640},{id:w.cl,wa:1.25,Ea:!0,f:[0,0, +2048,1152],p:[0,0],D:2048,C:2305},{id:w.Xp,wa:1.25,Ea:!0,f:[0,0,2048,708],p:[0,896],D:2048,C:2305},{id:w.dl,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:2304},{id:w.Yp,wa:1.25,Ea:!0,f:[0,0,2048,874],p:[0,835],D:2048,C:2304},{id:w.Zp,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:2304},{id:w.$p,wa:1.25,Ea:!0,f:[0,0,2048,1052],p:[0,756],D:2048,C:2304},{id:w.el,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:2304},{id:w.aq,wa:1.25,Ea:!0,f:[0,0,2048,1072],p:[0,768],D:2048,C:2304},{id:w.bq,wa:1.25, +Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:2304},{id:w.cq,wa:1.25,Ea:!0,f:[0,0,2048,1124],p:[0,624],D:2048,C:2304},{id:w.fl,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866},{id:w.dq,wa:1.25,Ea:!0,f:[0,0,2048,948],p:[0,760],D:2048,C:1866},{id:w.fq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:2304},{id:w.gq,wa:1.25,Ea:!0,f:[0,0,2048,886],p:[0,881],D:2048,C:2304},{id:w.gl,wa:1.25,Ea:!0,f:[0,0,2048,1152,0,0,4,3],p:[0,0,1028.5,581],D:2048,C:2304},{id:w.iq,wa:1.25,Ea:!0,f:[0,0,2048,642,0,0,4,3], +p:[0,889,1028.5,581],D:2048,C:2304},{id:w.jq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:2304},{id:w.kq,wa:1.25,Ea:!0,f:[0,0,2048,858],p:[0,780],D:2048,C:1638},{id:w.lq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:2304},{id:w.nq,wa:1.25,Ea:!0,f:[0,0,2048,887],p:[0,792],D:2048,C:2304},{id:w.oq,wa:1.25,Ea:!0,f:[0,0,2048,1153],p:[0,-1],D:2048,C:2304},{id:w.pq,wa:1.25,Ea:!0,f:[0,0,2048,980],p:[0,802],D:2048,C:2304},{id:w.qq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866},{id:w.rq,wa:1.25, +Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866},{id:w.sq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866},{id:w.tq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866},{id:w.uq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866},{id:w.vq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866},{id:w.wq,wa:1.25,Ea:!0,f:[0,0,2048,1152],p:[0,0],D:2048,C:1866}],db={l:0,V:1,Bi:2,zD:3},Ka=function(a,c,d){var b=[];b[d.Ff]=new a("big_font.png",c.Bi);b[d.Kg]=new a("small_font.png",c.Bi);b[d.Xk]=new a("font_numbers_big.png", +c.Bi);b[d.ia]=new a("tap",c.V);b[d.Yl]=new a("button",c.V);b[d.Xl]=new a("bubble_break",c.V);b[d.Wl]=new a("bubble",c.V);b[d.Zl]=new a("candy_break",c.V);b[d.cm]=new a("monster_chewing",c.V);b[d.dm]=new a("monster_chewing",c.V);b[d.em]=new a("monster_close",c.V);b[d.fm]=new a("monster_open",c.V);b[d.gm]=new a("monster_sad",c.V);b[d.fr]=new a("ring",c.V);b[d.jm]=new a("rope_bleak_1",c.V);b[d.gr]=new a("rope_bleak_2",c.V);b[d.hr]=new a("rope_bleak_3",c.V);b[d.ir]=new a("rope_bleak_4",c.V);b[d.km]=new a("rope_get", +c.V);b[d.qm]=new a("star_1",c.V);b[d.jr]=new a("star_2",c.V);b[d.kr]=new a("star_3",c.V);b[d.Cd]=new a("electric",c.V);b[d.hm]=new a("pump_1",c.V);b[d.dr]=new a("pump_2",c.V);b[d.er]=new a("pump_3",c.V);b[d.im]=new a("pump_4",c.V);b[d.nm]=new a("spider_activate",c.V);b[d.om]=new a("spider_fall",c.V);b[d.pm]=new a("spider_win",c.V);b[d.rm]=new a("wheel",c.V);b[d.sm]=new a("win",c.V);b[d.Ui]=new a("gravity_off",c.V);b[d.Vi]=new a("gravity_on",c.V);b[d.$l]=new a("candy_link",c.V);b[d.Vl]=new a("bouncer", +c.V);b[d.Bc]=new a("obj_candy_01.png",c.l);b[d.Rg]=new a("obj_spider.png",c.l);b[d.ul]=new a("obj_star_disappear.png",c.l);b[d.Pg]=new a("obj_bubble_flight.png",c.l);b[d.kl]=new a("obj_bubble_pop.png",c.l);b[d.Ji]=new a("obj_hook_auto.png",c.l);b[d.tl]=new a("obj_spikes_04.png",c.l);b[d.Hi]=new a("obj_bubble_attached.png",c.l);b[d.ll]=new a("obj_hook_01.png",c.l);b[d.ml]=new a("obj_hook_02.png",c.l);b[d.Wc]=new a("obj_star_idle.png",c.l);b[d.Gi]=new a("hud_star.png",c.l);b[d.sl]=new a("obj_spikes_03.png", +c.l);b[d.rl]=new a("obj_spikes_02.png",c.l);b[d.ql]=new a("obj_spikes_01.png",c.l);b[d.ic]=new a("char_animations.png",c.l);b[d.Ie]=new a("char_animations2.png",c.l);b[d.Ng]=new a("char_animations3.png",c.l);b[d.Hf]=new a("obj_hook_regulated.png",c.l);b[d.Ii]=new a("obj_electrodes.png",c.l);b[d.Je]=new a("obj_hook_movable.png",c.l);b[d.Li]=new a("obj_pump.png",c.l);b[d.vl]=new a("tutorial_signs.png",c.l);b[d.If]=new a("obj_hat.png",c.l);b[d.il]=new a("obj_bouncer_01.png",c.l);b[d.jl]=new a("obj_bouncer_02.png", +c.l);b[d.bm]=new a("menu_music",c.V);b[d.am]=new a("game_music",c.V);b[d.sw]=new a("game_music2",c.V);b[d.hl]=new a("obj_drawing_hidden.png",c.l);b[d.Mi]=new a("obj_rotatable_spikes_01.png",c.l);b[d.nl]=new a("obj_rotatable_spikes_02.png",c.l);b[d.ol]=new a("obj_rotatable_spikes_03.png",c.l);b[d.pl]=new a("obj_rotatable_spikes_04.png",c.l);b[d.Qg]=new a("obj_rotatable_spikes_button.png",c.l);b[d.Og]=new a("obj_bee_hd.png",c.l);b[d.Ki]=new a("obj_pollen_hd.png",c.l);b[d.Wi]=new a("spike_rotate_in", +c.V);b[d.Xi]=new a("spike_rotate_out",c.V);b[d.Fi]=new a("char_supports.png",c.l);b[d.jc]=new a("obj_vinil.png",c.l);b[d.lm]=new a("scratch_in",c.V);b[d.mm]=new a("scratch_out",c.V);b[d.Ti]=new a("buzz",c.V);b[d.Vg]=new a("teleport",c.V);b[d.cl]=new a("bgr_01_p1.jpg",c.l);b[d.Xp]=new a("bgr_01_p2.jpg",c.l);b[d.dl]=new a("bgr_02_p1.jpg",c.l);b[d.Yp]=new a("bgr_02_p2.jpg",c.l);b[d.Zp]=new a("bgr_03_p1.jpg",c.l);b[d.$p]=new a("bgr_03_p2.jpg",c.l);b[d.el]=new a("bgr_04_p1.jpg",c.l);b[d.aq]=new a("bgr_04_p2.jpg", +c.l);b[d.bq]=new a("bgr_05_p1.jpg",c.l);b[d.cq]=new a("bgr_05_p2.jpg",c.l);b[d.fl]=new a("bgr_06_p1.jpg",c.l);b[d.dq]=new a("bgr_06_p2.jpg",c.l);b[d.fq]=new a("bgr_07_p1.jpg",c.l);b[d.gq]=new a("bgr_07_p2.jpg",c.l);b[d.gl]=new a("bgr_08_p1.png",c.l);b[d.iq]=new a("bgr_08_p2.png",c.l);b[d.jq]=new a("bgr_09_p1.jpg",c.l);b[d.kq]=new a("bgr_09_p2.jpg",c.l);b[d.lq]=new a("bgr_10_p1.jpg",c.l);b[d.nq]=new a("bgr_10_p2.jpg",c.l);b[d.oq]=new a("bgr_11_p1.jpg",c.l);b[d.pq]=new a("bgr_11_p2.jpg",c.l);b[d.qq]= +new a("bgr_ie.jpg",c.l);b[d.rq]=new a("bgr_time1.jpg",c.l);b[d.sq]=new a("bgr_time2.jpg",c.l);b[d.tq]=new a("bgr_time3.jpg",c.l);b[d.uq]=new a("bgr_time4.jpg",c.l);b[d.vq]=new a("bgr_time5.jpg",c.l);b[d.wq]=new a("bgr_time6.jpg",c.l);b[d.vv]=new a("Caesar_animations_1_hd.png",c.l);b[d.wv]=new a("Caesar_animations_2_hd.png",c.l);b[d.xv]=new a("Caesar_animations_3_hd.png",c.l);b[d.yv]=new a("Caesar_animations_4_hd.png",c.l);b[d.Bv]=new a("Painter_animations_1_hd.png",c.l);b[d.Cv]=new a("Painter_animations_2_hd.png", +c.l);b[d.Dv]=new a("Painter_animations_3_hd.png",c.l);b[d.Ev]=new a("Painter_animations_4_hd.png",c.l);b[d.Fv]=new a("Pharaoh_animations_1_hd.png",c.l);b[d.Gv]=new a("Pharaoh_animations_2_hd.png",c.l);b[d.Hv]=new a("Pharaoh_animations_3_hd.png",c.l);b[d.Iv]=new a("Pharaoh_animations_4_hd.png",c.l);b[d.Jv]=new a("Pirate_animations_1_hd.png",c.l);b[d.Kv]=new a("Pirate_animations_2_hd.png",c.l);b[d.Lv]=new a("Pirate_animations_3_hd.png",c.l);b[d.Mv]=new a("Pirate_animations_4_hd.png",c.l);b[d.Nv]=new a("Prehistoric_animations_1_hd.png", +c.l);b[d.Ov]=new a("Prehistoric_animations_2_hd.png",c.l);b[d.Pv]=new a("Prehistoric_animations_3_hd.png",c.l);b[d.Qv]=new a("Prehistoric_animations_4_hd.png",c.l);b[d.Sv]=new a("Viking_animations_1_hd.png",c.l);b[d.Tv]=new a("Viking_animations_2_hd.png",c.l);b[d.Uv]=new a("Viking_animations_3_hd.png",c.l);b[d.Vv]=new a("Viking_animations_4_hd.png",c.l);b[d.Zq]=new a("candy_hit",c.V);b[d.$q]=new a("prehistoric_monster_chewing",c.V);b[d.ar]=new a("prehistoric_monster_close",c.V);b[d.br]=new a("prehistoric_monster_open", +c.V);b[d.cr]=new a("prehistoric_monster_sad",c.V);b[d.lr]=new a("time_menu",c.V);b[d.Rv]=new a("time-stands.png",c.l);return b}(function(){return function(a,c){this.path=a;this.type=c}}(),db,w),sb=function(a,c){function d(a,c){return Math.round(1E4*a*c)/1E4}return{SA:function(a,c){var e,g,k;g=0;for(k=a.length;ga&&(D=a),D=Math.ceil(D),J=g-h,J>z&&(J=z),J=Math.ceil(J),l.drawImage(this.L.qc,k,s,D,J,c+C,d+h,D,J),C+=x;h+=E}},Xj:function(a,b){if(this.rf===f.e)return c.Db(a,b,this.ea,this.fa,this.L.width,this.L.height);var d=this.L.f[this.rf],e=this.ea,g=this.fa;if(this.jk)var l=this.L.p[this.rf],e=e+l.x,g=g+l.y;return c.Db(a, +b,e,g,d.M,d.U)},Ns:function(a){if(this.h(a))return!0;if(a.Pr===g.Ri)this.Ua(a.Qr);else return!1;return!0},$A:function(a,b){var c=this.Jd(a).p[b];this.x=c.x;this.y=c.y},bF:function(a,b){var c=this.Jd(a),d=c.f[b],c=c.p[b];this.x=c.x+d.M/2;this.y=c.y+d.U/2}});l.create=function(a,b){var c=new l;c.sa(a);null!=b&&c.Ua(b);return c};return l}(ia,U,Ka,P,N,K,ua,ja),ub=function(a,c,d,b){return a.extend({init:function(){this.h();this.Se="";this.fc=this.sc=this.dd=0;this.ef=null},Iy:function(a,b,c){this.Se=a; +this.ne(b);this.ef=c},jB:function(a,b,c){this.dd=a;this.sc=b;this.fc=c},vj:function(a){var c=this.Se.indexOf(a);if(0<=c)return c;b.alert("Char not found in font:"+a);return this.Se.indexOf(".")},cE:function(a,b,d){a=this.L.f[a];var k=Math.ceil(a.M),l=Math.ceil(a.U);c.context.drawImage(this.L.qc,a.x,a.y,k,l,b,d,k,l)},Du:function(a){for(var b=0,c=a.length,d=0,l=0;lc&&(h.M=c-b.be);h.U+b.Pf>d&&(h.U=d-b.Pf);b.Ww(h)}if(e)for(c=e.length,g=0;ga===0>d},gb:function(a,d){return Math.floor(Math.random()*(d-a+1)+a)},uA:function(){return 0.5=d&&c>=b&&c>=f?c:d>=c&&d>=b&&d>=f?d:b>=d&&b>=c&&b>=f?b:f>=d&&f>=b&&f>=c?f:a.e},ht:function(c,d,b,f){return c<=d&&c<=b&&c<=f?c:d<=c&&d<=b&&d<=f?d:b<=d&&b<=c&&b<=f?b:f<=d&&f<=b&&f<=c?f:a.e},Sy:function(a,d,b,f,e,g,k,l){var n,r;n=e-a+k-b;r=g-d+l-f;a=b-a;d=f-d;e=k-e;l-=g;g=e*r-l*n;n=a*r-d*n; +r=Math.abs(d*e-l*a);return Math.abs(g)<=r&&Math.abs(n)<=r},ZE:function(a,d){var b=Math.pow(10,d);return Math.round(a*b)/b},au:function(a){return Math.round(100*a)/100}}}(N),da=function(a,c,d,b,f,e,g,k,l){function n(a,b){this.Ag=a;this.width=b}var r=a.extend({init:function(a){this.h();this.font=a;this.je=[];this.height=this.width=c.e;this.align=d.mb;this.kh=new b(a.L);this.iC=!1;this.maxHeight=c.e},lu:function(a,b){this.Ag=a;this.Hg=null==b||b===c.e?Math.ceil(this.font.Du(a)):Math.ceil(b);this.Ag&& +(this.by(),this.ZB())},ZB:function(){for(var a=0,b=0,f=this.font.sn(),g=0,e=this.font.cg("..",0),l=this.maxHeight===c.e?this.je.length:Math.min(this.je.length,this.maxHeight/f+this.font.sc),n=l!==this.je.length,h=0;hthis.Hg)){this.kh.Lj(x,Math.round(a),Math.round(b),g++);a+=E+e;this.kh.Lj(x,Math.round(a),Math.round(b),g++);a+=E+e;this.kh.Lj(x,Math.round(a),Math.round(b),g++);a+=E+e;break}}b+=f+this.font.sc}1>=this.je.length?(this.height=this.font.sn(),this.width=a):(this.height=(this.font.sn()+this.font.sc)*this.je.length-this.font.sc,this.width=this.Hg);this.maxHeight!==c.e&&(this.height= +Math.min(this.height,this.maxHeight))},v:function(){this.vc();if(0!==this.color.B){var a=this.Ag.length,b=f.context;0this.Hg;this.iC&&x&&h==e&&(k+= +g,h=r,g=0,f=r);if(l.au(k+g)>this.Hg&&h!=e||"\n"==J){a[d++]=e;for(a[d++]=h;f>1;this.je=[];for(c=0;c").prependTo(b));b=c[0]}b||(b=new Image);var e=a.tj,l=a.width,n=a.Dc,z=null!=a.alpha?a.alpha:1,c=a.ua?k.bb:a.scale||1,h=a.text.toString(),C=f.element;f.hi(document.createElement("canvas"));e=g.Is(e);e=new r(e);e.x=Math.ceil(24*k.Gb/2);e.y=0;e.align=n||d.mb; +e.lu(h,l);var n=f.element,h=f.context,D=(l||Math.ceil(e.width))+Math.ceil(2*e.x),l=Math.ceil(e.height);n.width=D;n.height=l;var J=h.globalAlpha;z!==J&&(h.globalAlpha=z);e.v();b.src=n.toDataURL("image/png");z!==J&&(h.globalAlpha=J);C&&f.hi(C);z=D*c;c*=l;a=a.ao;var x;a&&z>a&&(a/=z,x=Math.round((1-a)*c/2),z*=a,c*=a);c=$(b).width(z).height(c);x&&c.css("padding-top",x);return b};r.nc=function(a){a.tj=e.Kg;return r.hj(a)};r.ja=function(a){a.tj=e.Ff;return r.hj(a)};r.us=function(a){a.tj=e.Xk;r.hj(a)};return r}(ia, +N,S,Ja,P,w,La,H,Z),F={lw:0,Xd:1,zC:2,BD:3,AC:4,ow:5,FC:6,jC:7,xp:8,gw:9,fw:10,vw:11,uw:12,Oq:13,Yv:14,Zv:15,$v:16,aw:17,Xv:18,Fm:19,xw:20,sv:21,mC:22,uD:23,Mw:24,iw:25,vb:26,NEXT:27,qb:28,LOADING:29,Jw:30,jw:31,ID:32,sp:33,tp:34,up:35,Rp:36,DC:37,ev:38,nv:39,rw:40,bw:41,dw:42,yq:43,Dq:44,Qq:45,Rq:46,Sq:47,Op:48,Gp:49,vp:50,Tq:51,Pp:52,Vq:53,Wq:54,Uq:55,xq:56,Nq:57,Mq:58,Lq:59,Mp:60,Yq:61,Xq:62,wp:63,ew:64,tw:65,Ke:66,Ee:67,fv:68,Jm:69,hw:70,hp:71,wi:72,qw:200,mw:201},ga=function(a,c,d,b,f){function e(a){switch(c.uh()){case d.Lg:return a.j|| +a.s;case d.Ig:return a.i||a.s;case d.Ug:return a.k||a.s;default:return a.s}}return{Vm:function(b,c){var d=e(a.Vm[b]);d&&c&&(d=b+1+". "+d);return d},W:function(a){var c,d,n=b.length;for(d=0;d(a/=b/2)?d/2*a*a*a+c:d/2*((a-=2)*a*a+2)+c};this.Xe=function(a,c,d,b){return a==b?c+d:d*(-Math.pow(2,-10*a/b)+1)+ +c};this.lj=function(a,c,d){return 0==a?0:a==d?0+c:1>(a/=d/2)?c/2*Math.pow(2,10*(a-1))+0:c/2*(-Math.pow(2,-10*--a)+2)+0};this.mn=function(a,c,d,b){var f=1.5;void 0==f&&(f=1.70158);return d*((a=a/b-1)*a*((f+1)*a+f)+1)+c};this.kj=function(a,c,d,b){void 0==b&&(b=1.70158);return 1>(a/=d/2)?c/2*a*a*(((b*=1.525)+1)*a-b)+0:c/2*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)+0};this.xs=function(a,c,d,b){return 1>(a/=b/2)?d/2*a*a+c:-d/2*(--a*(a-2)-1)+c}}}(),wb=function(a,c,d,b,f,e,g,k,l){function n(){function e(b,c,d){if(b)for(c= +c||a.Rc,d=d||"MENU",h=0,C=b.length;hm){var g=100/(100-k)*(n-m);0>g&&(g=0);l+=g}l=q.y.duration&&(q.y.$c=e,q.ve=0.5+0.5*Math.random(), +q.x.offset=Math.random()*(d-q.x.wd*(1/q.ve))),q.y.offset=c+2*q.img.height-a.jo(e-q.y.$c,1,q.y.duration)*(c+2*q.img.height)-q.img.height);e-q.x.$c>=q.x.duration&&(q.x.$c=e,q.x.Wf&&(q.x.$f=!q.x.$f));q.x.val=a.xs(e-q.x.$c,q.x.ke,q.x.wd-q.x.ke,q.x.duration);q.x.abs=q.x.offset+(q.x.$f?q.x.wd-q.x.val:q.x.val);q.x.abs>d-q.img.width*q.ve&&(q.x.abs=d-q.img.width*q.ve);q.ig?(e-q.y.$c>=q.y.duration&&(q.y.$c=e,q.y.Wf&&(q.y.$f=!q.y.$f)),q.y.val=a.xs(e-q.y.$c,q.y.ke,q.y.wd-q.y.ke,q.y.duration)):q.y.val=0;q.y.abs= +q.y.offset+(q.y.$f?q.y.wd-q.y.val:q.y.val);if(q.ig){var C=Math.floor(Math.round(l)/10)%10,A=Math.round(l)%10;h.drawImage(s,100*C,0,100,100,q.x.abs+65,q.y.abs+75,100,100);h.drawImage(s,100*A,0,100,100,q.x.abs+105,q.y.abs+75,100,100);h.drawImage(s,1E3,0,100,100,q.x.abs+145,q.y.abs+75,100,100)}h.save();q.ig?h.drawImage(q.img,q.x.abs,q.y.abs):(h.scale(q.ve,q.ve),h.drawImage(q.img,q.x.abs*(1/q.ve),q.y.abs*(1/q.ve)));h.restore()}r&&window.requestAnimationFrame(b)}r=!0;g();var h=u.getContext("2d"),c=u.height, +d=u.width,f=Date.now(),l=null,k=null,m=-1,p=[new e(!0),new e(!1,0,3E3,5E3,300),new e(!1,300,5E3,6E3,400),new e(!1,2E3,2E3,4E3,200),new e(!1,3200,3E3,5E3,300)];window.requestAnimationFrame(b)}function e(a,b,h,c,d){function f(){this.duration=this.wd=this.ke=this.$c=this.val=this.abs=0;this.$f=this.Wf=!1;this.offset=0}this.y=new f;this.x=new f;this.ig=a;this.delay=b;this.img=this.ig?q:A;this.ve=0.5+0.5*Math.random();this.ig?(this.x.ke=0,this.x.wd=150,this.x.duration=2800,this.x.Wf=!0,this.y.ke=0,this.y.wd= +60,this.y.duration=1300,this.y.Wf=!0):(this.x.ke=0,this.x.wd=d,this.x.duration=h,this.x.Wf=!0,this.y.ke=0,this.y.wd=1,this.y.duration=c,this.y.Wf=!1)}function g(){!l&&p&&u&&(u.width=p.offsetWidth,u.height=p.offsetHeight)}function k(){z&&h&&C&&($(window).on("resize",g),m=setTimeout(function(){l||($("#loaderWindow").fadeIn(),$("#loaderLogo").fadeIn(200),f());m=null},1E3))}var l=!1,n=0,r=!1,m=null,p,u,q,A,s,z=!1,h=!1,C=!1;this.init=function(a){var h=new PxLoader({pt:3E4});d.wz||h.addImage("images/page/tilebg.jpg"); +var f,e,g;if(f=c.mz)for(e=0,g=f.length;ec?d[c]:null}function e(a,c,f){if(k){var e=b(a);if(e[c]!==f&&(e[c]=f,k))if(a=d(a),e){c=[];f=e.length;var g,u;for(g=0;g=D.ei(h)?!1:!0};this.Ny=function(h,c){var d=b[h];return a.Dg?!0:null!=d?null!=d.Eb[c]:!1};this.No=function(a, +h,d,f){var e=b[a];if(null!=e){f?e.sf[h]=d:(f=u(a,h),e.sf[h]=Math.max(d,f));q(a,h,e.sf[h]);h=e.sf.length;for(f=d=0;ft?(h=c.Qx(),l=1-h,h=1+h):300>t?(h=c.nh(t-100,0,0.11,200),l=0.95+h,h=1.05-h):600>t&&(h=c.ys(t-300,0,0.05,300),l=1.06-h,h=0.94+h);l=(d-d*l)/2;h=(f-f*h)/2;var k=(d-2*l)/d,n=(f-2*h)/f;isNaN(k)||isNaN(n)||(a.save(),a.setTransform(1,0,0,1,0,0),a.clearRect(b.d(312),b.d(100),b.d(400),b.d(460)),a.restore(),a.save(),a.scale(k,n),a.translate(l,h),a.translate(b.d(312), +b.d(130)),e.v(a,b.d(140)),a.restore());600=s[a]?!1:q.th(C+(z[a]^D),0)!==(z[a]-1E3^D)&&!m.Dg}var s=p.QD,z=p.PD,h=!1,C=String.fromCharCode(98,107),D=n.ry(),J=null;$(document).ready(function(){J=$("#boxEnterCodeButton").hide()});var x=null,E=null,I=null,wa=null,X="January February March April May June July August September October November December".split(" "); +a=c.extend({init:function(a,b,h,c,d){this.h(a,b,h,c,d);this.dt=new Image;this.dt.src=this.bh.src.replace(".png","_locked.png");this.Cj=A(a)&&p.gE;this.Gj=!0!==m.Dg&&Date.now()=d&&(d=C+(z[c]^D),f=z[c]-1E3^D,q.set(d,f))};a.Ts=A;return a}(ba,Ea,da,H,T,pa,V,ga,S,ta,F,ra,R,Z,za),xa={qb:0,Sc:1,Bd:2,Gf:3,Ci:4,zq:5,Mg:6,Xd:7,xp:8,Ke:9,Ee:10,Me:11},Fa=function(){return function(a,c,d,b){this.id=a;this.pg=c;this.Sf=d;this.zB=b}}(),Ua=function(){function a(a){this.nn=a.element;this.vh=a.vh;var d=this;this.xu=function(b){b=b.originalEvent;d.Bo(b);return a.qo?d.Fk(b,a.qo):!1};this.nt=function(b){b=b.originalEvent;d.Bo(b);return a.no?d.Fk(b, +a.no):!1};this.zs=function(b){b=b.originalEvent;d.Bo(b);return a.ko?d.Fk(b,a.ko):!1};this.yt=function(b){b=b.originalEvent;return a.oo?d.Fk(b,a.oo):!1}}a.prototype.Fk=function(a,d){var b=0,f=0;a||(a=window.event);if(a.changedTouches&&0a?0.016:0.05this.Oc&&(this.Oc=this.path.length-1)):(this.Oc++,this.Oc>=this.path.length&&(this.Oc=0)),this.Xm())}0!==this.o&&(this.a+=this.o*a)}}});a.kf=function(a,c,d,g){c!==a&&(c>a?(a+=d*g,a>c&&(a=c)):(a-=d*g,aa?(a+=d*g,a>c&&(a=c)):(a-=d*g,ab;)this.Tr(),this.Ye-=b;this.oh+=a;-1!==this.duration&&this.duration>0)+1;0!=c&&(a/=c);for(var d=0;d=C)continue;A=-1===s.Mc.x;s=s.Dh;h=(h-C)/((1=this.La?(g=d[d.length-2],l=new c,l.sd(0.02),l.b=e.add(g.b,b),this.Sr(l,this.Ca.length-1),h.js(g,l,k),l.Re(g,this.La,f.Ai),a-=this.La):(l=a+k,l>this.La?(a=this.La,k=l-this.La):(g=d[d.length- +2],h.ej(g,l),a=0))},HA:function(a){for(var b=this.Ca,c=b.length,d=this.hb,h=d.rd(b[c-2]),e;0=this.La){var g=c-2,k=b[c-3];e=b[g];d.js(e,k,h);this.zA(g);c--;a-=this.La}else g=h-a,1>g?(a=this.La,h=this.La+g+1):(e=b[c-2],d.ej(e,g),a=0);b=(c-1)*(this.La+3);d=d.Ub;c=d.length;for(h=0;hthis.de&&this.ag&&this.Qt(this.zb));var b=this.Ca,c=b.length,d=this.Eo,h=this.hb,e,f;for(e=0;ec)){var h=this.zb===b.e|| +this.ag?1:this.de/1.95;if(!(0>=h)){var l=a[0],D=a[1],J=l.x-D.x,D=l.y-D.y,J=Math.sqrt(J*J+D*D);this.Fo=J<=this.La+0.3?0:J<=this.La+1?1:Jc)){n.F=0;n.K=0;n.J=0;n.B=h;r.F=0.475;r.K=0.305;r.J=0.185;r.B=h;m.F=0.19;m.K=0.122;m.J=0.074;m.B=h;p.F=152/225;p.K=0.44;p.J=62/225;p.B=h;u.F=0.304;u.K=0.198;u.J=0.124;u.B=h;this.highlighted&&(r.F*=3,r.K*=3,r.J*=3,p.F*=3,p.K*=3,p.J*=3,m.F*=3,m.K*=3,m.J*=3,u.F*=3,u.K*=3,u.J*=3);J>this.La+7&&!this.Gx&&(J=2*(J/this.La),m.F*=J,u.F*=J);var J=!1,c=(c- +1)*d,x=c-1,d=(r.F-m.F)/x,D=(r.K-m.K)/x,E=(r.J-m.J)/x,I=(p.F-u.F)/x,wa=(p.K-u.K)/x,x=(p.J-u.J)/x,X=this.vi-1,G=X-1,L=g.context,B=L.globalAlpha;B!==h&&(L.globalAlpha=h);var v=f[0];v?(v.x=l.x,v.y=l.y):f[0]=l.copy();for(var w,l=1;l<=c;l++)if(v=l/c,(w=f[l])||(w=f[l]=new e(0,0)),e.cu(a,v,w),v=(l-1)%X,v===G||l===c){L.beginPath();w=this.ag?k.Ck.Zi:J?m.fi():u.fi();L.strokeStyle=w;w=l-v-1;var Y=f[w++];for(L.moveTo(Y.x,Y.y);w<=l;w++)Y=f[w],L.lineTo(Y.x,Y.y);L.stroke();J=!J;v+=1;m.F+=d*v;m.K+=D*v;m.J+=E*v;u.F+= +I*v;u.K+=wa*v;u.J+=x*v}B!==h&&(L.globalAlpha=B)}}}}});a.kv=30;return a}(Ib,hb,H,N,Xa,K,P,ca,na,ja),Oa=function(a){return{bt:null,Od:0,gf:0,pF:!1,bz:function(c,d){this.Od=c-1;this.gf=d-1;this.bt=a.Tf[this.Od].mg[this.gf]}}}(R),jb=function(a,c,d){return a.extend({init:function(){this.h()},ne:function(a){this.h(a);this.ud=[];this.p=[];this.align=d.S},sB:function(a,c,d){this.ud[0]=a;this.ud[1]=c;this.ud[2]=d;a=this.L.f[a].U;c=this.L.f[c].U;d=this.L.f[d].U;this.height=a>=c&&a>=d?a:c>=a&&c>=d?c:d;this.p[0]= +Math.floor((this.height-a)/2);this.p[1]=Math.floor((this.height-c)/2);this.p[2]=Math.floor((this.height-d)/2)},v:function(){this.vc();var a=this.L.f[this.ud[0]],d=this.L.f[this.ud[1]],e=this.L.f[this.ud[2]],g=this.width-(Math.floor(a.M)+Math.floor(e.M)),k=c.context,l=Math.round(this.ea),n=Math.round(this.fa),r=Math.ceil(a.M),m=Math.ceil(a.U),p=Math.ceil(e.M),u=Math.ceil(e.U);0<=g?(k.drawImage(this.L.qc,a.x,a.y,r,m,l,n+this.p[0],r,m),this.Mx(this.ud[1],l+r,n+this.p[1],g,d.U),k.drawImage(this.L.qc, +e.x,e.y,p,u,l+r+g,n+this.p[2],p,u)):(a=a.copy(),d=e.copy(),a.M=Math.min(a.M,this.width/2),d.M=Math.min(d.M,this.width-a.M),d.x+=e.M-d.M,k.drawImage(this.L.qc,a.x,a.y,a.M,a.U,l,n+this.p[0],a.M,a.U),k.drawImage(this.L.qc,d.x,d.y,d.M,d.U,l+a.M,n+this.p[2],d.M,d.U));this.uc()},ly:function(){var a=c.element;c.hi(document.createElement("canvas"));var d=c.element,e=Math.ceil(this.width),g=Math.ceil(this.height);d.width=e;d.height=g;this.v();var d=d.toDataURL("image/png"),k=new Image;k.src=d;$(k).width(e).height(g); +a&&c.hi(a);return k}})}(aa,P,S),Kb=function(a,c,d,b,f){return a.extend({init:function(a){this.h();var g=new c;g.sa(b.Je);g.sB(0,2,1);g.width=a+d.Yk;a=g.ly();this.ne(new f(a))}})}(aa,jb,H,w,Sa),Lb=function(a,c,d,b,f,e,g,k,l,n,r,m,p,u,q,A,s,z,h){return a.extend({init:function(){this.h();this.ta=null;this.m=this.Hh=this.pe=this.uy=this.G=!1;this.Gg=k.e;this.Hj=e.Qa();this.q=0;this.u=!1;this.t=0;this.le=this.bf=this.Bb=null;this.Mj=this.Nj=this.lf=0;this.xg=this.Ic=!1;this.c=null;this.tf=0;this.Xs=this.bp= +this.uk=!1;this.ff=0;this.xh=this.Ij=!1;this.n=this.$h=0},oy:function(a,b,h){a=e.$a(a,h);b=e.$a(b,h).og()-a.og();return c.Bg(b)},wy:function(a,b){this.Hj.x=a;this.Hj.y=b},vy:function(a){b.N(f.rm);var c=new e(this.x,this.y),c=this.oy(this.Hj,a,c);180c&&(c+=360);this.hc.rotation+=c;this.Fg.rotation+=c;this.Eg.rotation+=c;c=0=this.$h&&(this.n=k.e,this.xh=!1));if(this.wb){var b=e.$a(this.Pa.path[this.Pa.Oc],this.Pa.b),c=0;15=h&&(this.tfp-3)){h=this.tf-h;n=e.$a(n,q);n.multiply(h/r);this.c.x=q.x+n.x;this.c.y=q.y+n.y;m>p-3&&(a=!0);0!==this.c.Vf&&(this.c.rotation= +c.Bg(n.og())+270);break}else h+=r}a&&(this.tf=k.e)}},Hx:function(){if(!this.pe&&!this.G){if(this.kg&&this.Hh&&this.ta){var a=this.ta.Ya.b;this.x=a.x;this.y=a.y}this.vc();0c)){var d=u.context,e=2*Math.PI,f=Math.max(16,Math.round(c/(2*l.Gb)));0!==f%2&&f++;d.lineWidth=2;d.strokeStyle=h.fi();h=e/f;for(var g=0;g=this.q?this.gd.v():this.lf!=k.e?this.bf.v():this.le.v();this.m&&this.hc.v();this.uc()}},Lx:function(){this.c.v()},bE:function(){this.sE.v()},ku:function(a){this.ta=a;this.Gt=this.n;this.n=k.e;this.Ic&& +(this.uk=!0)},cF:function(){this.Ij=this.Xs=!0;this.ff=130;var a=new g(100,this.ff,0);a.iu("RC30",new e(this.x,this.y));this.Lo(a);a.start()},lB:function(a){this.Gt=this.n;this.n=a;a===k.e||a===k.lv?(a=s.gb(f.ll,f.ml),this.back=p.create(a,0),this.back.ya(),this.back.anchor=this.back.oa=m.S,this.gd=p.create(a,1),this.gd.anchor=this.gd.oa=m.S,this.T(this.back),this.T(this.gd),this.back.visible=!1,this.gd.visible=!1):(this.back=p.create(f.Ji,0),this.back.ya(),this.back.anchor=this.back.oa=m.S,this.gd= +p.create(f.Ji,1),this.gd.anchor=this.gd.oa=m.S,this.T(this.back),this.T(this.gd),this.back.visible=!1,this.gd.visible=!1,this.$h=l.Tp,this.xh=!1);this.m&&(this.ri=p.create(f.Hf,0),this.ri.anchor=this.ri.oa=m.S,this.T(this.ri),this.ri.visible=!1,this.hc=p.create(f.Hf,1),this.hc.te=!1,this.Eg=p.create(f.Hf,2),this.Eg.anchor=this.Eg.oa=m.S,this.hc.T(this.Eg),this.Fg=p.create(f.Hf,3),this.Fg.anchor=this.Fg.oa=this.hc.anchor=this.hc.oa=m.S,this.hc.T(this.Fg),this.T(this.hc),this.bp=this.hc.visible=!1)}, +fB:function(a,b,c){this.q=a;this.u=b;this.t=c;0g||(e.delay-=a,0>=e.delay&&(this.fe.splice(g,1),e.Ex()))}}}}(),Ub=function(){var a={Bq:0,Qp:1,ur:2,rr:3,Jr:4,Gm:5,wr:6,xr:7,yr:8,zr:9,Ar:10,Br:11,Cr:12,Dr:13,Er:14,Fr:15,Gr:16,Hr:17,Ir:18,qp:50,rp:51,pp:52,Up:53,mp:54,Iq:55,mr:56,nr:57,or:58,pr:59,qr:60,ww:61,Vk:80,jp:81,kp:82,Sp:100,al:101,Vp:102,Wp:103,DR:104,EO:105,LIH:106,GOD:107,TIM:108,OX:109,DIC:110,FIL:111,COM:112,PAW:113,HEO:114,LAS:115,US:116,Pq:120,Hw:121, +mv:122,jE:function(c){switch(c){case "map":return a.Bq;case "gameDesign":return a.Qp;case "target":return a.ur;case "target2":return a.Hw;case "star":return a.rr;case "tutorialText":return a.Jr;case "tutorial01":return a.Gm;case "tutorial02":return a.wr;case "tutorial03":return a.xr;case "tutorial04":return a.yr;case "tutorial05":return a.zr;case "tutorial06":return a.Ar;case "tutorial07":return a.Br;case "tutorial08":return a.Cr;case "tutorial09":return a.Dr;case "tutorial10":return a.Er;case "tutorial11":return a.Fr; +case "tutorial12":return a.Gr;case "tutorial13":return a.Hr;case "tutorial14":return a.Ir;case "candyL":return a.qp;case "candyR":return a.rp;case "candy":return a.pp;case "candy2":return a.mv;case "gravitySwitch":return a.Up;case "bubble":return a.mp;case "pump":return a.Iq;case "sock":return a.mr;case "spike1":return a.nr;case "spike2":return a.or;case "spike3":return a.pr;case "spike4":return a.qr;case "spikesSwitch":return a.ww;case "electro":return a.Vk;case "bouncer1":return a.jp;case "bouncer2":return a.kp; +case "grab":return a.Sp;case "hidden01":return a.al;case "hidden02":return a.Vp;case "hidden03":return a.Wp;case "hidden04":return a.DR;case "hidden05":return a.EO;case "hidden06":return a.LIH;case "hidden07":return a.GOD;case "hidden08":return a.TIM;case "hidden09":return a.OX;case "hidden10":return a.DIC;case "hidden11":return a.FIL;case "hidden12":return a.COM;case "hidden13":return a.PAW;case "hidden14":return a.HEO;case "hidden15":return a.LAS;case "hidden16":return a.US;case "rotatedCircle":return a.Pq;default:return alert("Unknown map item:"+c),null}}};return a}(),Vb=function(a){return a.extend({init:function(){this.h();this.bi=[]},update:function(a){for(var d=0,b=this.bi.length;dk?q+c:q-this.ki+c);this.ci!==l.kc.NONE&&(e-=b,q=Math.floor(e)%this.li,e=0>e?q+b:q-this.li+b);if(d.ai(b,c,b+this.gh,c+this.fh,e,k,e+this.li,k+this.ki)){q=d.Mt(e,k,this.li,this.ki,b,c,this.gh,this.fh);q=new g(Math.max(0,q.x),Math.max(0,q.y));q=new g(Math.floor(Math.floor(q.x)/ +this.xf),Math.floor(Math.floor(q.y)/this.wf));var k=k+q.y*this.wf,z=new g(e+q.x*this.xf,k),e=0;for(A=this.Hd.length;e=c+this.fh);C++){var D=d.Mt(b,c,this.gh,this.fh,z.x,z.y,this.xf,this.wf),J=new d(b-z.x+D.x,c-z.y+D.y,D.M,D.U),x=Math.round(e),E=Math.round(C);this.di===l.kc.Lp&&(z.y= +this.y+this.ki&&(E=this.rows-1));this.ci===l.kc.Lp&&(z.x=this.x+this.li&&(x=this.Te-1));this.yy&&(s=Math.sin(z.x)*this.Lt,x=Math.abs(Math.floor(s)%this.Te));this.eC&&(s=Math.sin(z.y)*this.Lt,E=Math.abs(Math.floor(s)%this.rows));x>=this.Te&&(x%=this.Te);E>=this.rows&&(E%=this.rows);s=this.Yn[x][E];0<=s&&(x=this.ud[s],s=this.Hd[x.Nx],E=s.L,x.It!==f.e&&(x=E.f[x.It],J.x+=x.x,J.y+=x.y),D=new d(a.x+D.x,a.y+D.y,D.M,D.U),s.Ua(s.Pj++,J,D));z.y+=this.wf}z.x+=this.xf;if(z.x>=b+this.gh)break}}}, +v:function(){this.vc();for(var a=0,b=this.Hd.length;a=c+e||c>=k+e||(c=Math.acos((k-(c*c-e*e+k*k)/(2*k))/e),k=(new g(a-h,b-d)).a(),b=k-c,c=k+c,h>a&&(b+=Math.PI,c+=Math.PI),a=l.context,a.beginPath(),a.lineWidth=f,a.arc(h,d,e,b,c,!1),a.stroke())},XB:function(){this.Bf.x= +this.Cf.x=this.x;this.Bf.y=this.Cf.y=this.y;var a=this.Zb.width/2*(1-this.Zb.X),b=this.Zb.height/2*(1-this.Zb.da),c=this.Rb-(m-p*this.size)+(1-this.ob.X)*(this.ob.width/2);this.Zb.x=this.x+a;this.De.x=this.x-a;this.Zb.y=this.De.y=this.y-b;this.ob.x=this.x-c;this.gc.x=this.x+c;this.ob.y=this.gc.y=this.y;this.zc.x=this.ob.x;this.zc.y=this.ob.y;this.Ac.x=this.gc.x;this.Ac.y=this.gc.y},wx:function(a){if(this.x===a.x&&this.y===a.y&&this.size===a.size)return!1;var b=this.Fc.length,c;for(c=0;ca;a++){var b=this.Hn[a]=new w;b.sa(E.Gi);b.ya();b.lc(0.05,X.ha.Wa,0,10);b.sk(10,0);b.x=b.width*a;b.y=0;this.T(b)}this.yk=G.Qa();this.sj=[];for(a=0;athis.kd+v.Fl||a.b.ya;a++){var b=this.Hn[a];b.yb&&b.yb.stop();b.Ua(0)}this.cz(Y.bt);2!==this.I&&(this.ad=new w,this.ad.sa(E.Pg),this.ad.oa=this.ad.anchor=W.S,this.ad.lc(0.05,X.ha.vb,0,12),this.ad.R(0),this.Ia.T(this.ad), +this.ad.visible=!1,this.ad.Ha=1E-4,this.bd=new w,this.bd.sa(E.Pg),this.bd.oa=this.bd.anchor=W.S,this.bd.lc(0.05,X.ha.vb,0,12),this.bd.R(0),this.Ja.T(this.bd),this.bd.visible=!1,this.bd.Ha=1E-4);for(var b=this.Ra.length,c,a=0;aa||this.kd>b){this.me=!0;this.Cs= +!1;this.Y.type=q.Yc.Kf;this.Y.speed=10;var c,h,d=2!==this.I?this.ga:this.Q;this.ld>a?(c=d.b.x>this.ld/2?0:this.ld-a,h=0):d.b.y>this.kd/2?h=c=0:(c=0,h=this.kd-b);var e=d.b.y-b/2,a=p.Zf(d.b.x-a/2,0,this.ld-a),b=p.Zf(e,0,this.kd-b);this.Y.moveTo(c,h,!0);this.Rs=this.Y.b.Ma(new G(a,b))}else this.me=!1,this.Y.moveTo(0,0,!0)},Fx:function(){this.xb.R(0)},cz:function(a){function b(a,c){for(var d=0,e=a.length;dv.pb&&this.Id.push(new P(v.pb, +0)),this.kd>v.ab&&this.Id.push(new P(0,v.ab)),this.Id.push(new P(0,0)))},Yy:function(a){this.O=a.O||0;this.$=a.$;this.vz=a.vz;this.I=a.I?0:2;this.$*=v.Hl},Zy:function(a){var b=a.x*this.P+this.rb,c=a.y*this.P+this.ib,h=a.length*this.P,d=a.n,f=a.m,g=a.kg,k=a.pe,l=a.q*this.P||-1,p=a.u,m=a.t*this.P||0,n=a.c,q="L"===a.H,r=a.wh,D=a.G,x=new e;x.x=b;x.y=c;x.m=f;x.G=D;x.kg=g;x.pe=k;x.qB(n);x.nf(a);if(x.Pa&&(x.TA(),!r)){a="R"===a.path[0];this.ue||(this.ue=new aa);f=0;for(g=x.Pa.path.length-1;fthis.Rs/2?(this.Y.speed+=a*g,this.Y.speed=Math.min(m, +this.Y.speed)):(this.Y.speed-=a*k,this.Y.speed=Math.max(n,this.Y.speed));1>Math.abs(this.Y.b.x-h)&&1>Math.abs(this.Y.b.y-f)&&(this.Y.type=q.Yc.zi,this.Y.speed=v.xi)}else this.time+=a;f=this.Ga.length;if(0g&&k.Fc.push(s):0<=g&&k.Fc.splice(s,1);C=this.bubbles.length;for(m=0;mA&&k.Fc.push(g):0<=A&&k.Fc.splice(g,1)}k.yA&&(n=h);k.update(a)}0<=n&&this.Ra.splice(n,1);h=0;for(e=this.Zt.length;h=this.Oh&&(h=new G(this.target.x,this.target.y),this.Q.b.Ma(h)>f?(this.eo=!1,this.target.mA(),x.N(E.em)):this.Oh=1)):(h=new G(this.target.x,this.target.y),this.Q.b.Ma(h)v.Pk){h=this.O=0;for(e=this.Af.length;hv.ab&&(c=this.to.p[0].y,b=this.to.f[0],a.drawImage(this.to.qc,b.x,b.y+2,b.M,b.U-4,0,c+2,b.M,b.U-4));a=0;for(b=this.ge.length;a=I.Xc)return!0;this.Uj=!1;if(this.Na&&this.Na.fb(this.Na.Vn()?1:0).cf(a+this.Y.b.x,b+this.Y.b.y,!0))return this.An=c,!0;if(this.$b&&this.En(this.Q,a,b)||2!==this.I&&(this.bc&&this.En(this.ga,a,b)||this.mc&&this.En(this.xa,a,b)))return!0;var h=new G(a,b);this.mh[c]||(this.mh[c]= +!0,this.ze[c].qa(h),this.Ao[c].qa(h));var d,e,f=this.Y.b,h=a+f.x,f=b+f.y;d=0;for(e=this.Xb.length;d=I.Xc)return!0;var h=new G(a,b),d,e;if(10Math.PI?h-=2*Math.PI:h<-Math.PI&&(h+=2*Math.PI);b.eg.pa(h,b.x,b.y);b.jd.pa(h,b.x,b.y);b.rotation+=N.Bg(h);d=0Math.abs(h)&&(d=I.e);b.Ro!=d&&d!=I.e&&(x.N(d),b.Ro=d);d=0;for(e=this.Ga.length;dI.Xc)return!1;this.yk.x=a;this.yk.y=b;return!0},Cb:function(){Pa.toggle();this.dg=Pa.Us();x.N(this.dg?E.Ui:E.Vi);for(var a=0,b=this.Id.length;af.d(-100)&&gMath.abs(X-V)&&(G=!0);a>=c?(v!=I[w]&&(v=I[w],v.$r(H)),v&&v.Sh&&v.Sh(),O=!1):window.requestAnimationFrame(b)}}0>a&&(a=0);a>I.length-1&&(a=I.length-1);var c=a==w?0:550;v&&v!=I[a]&&v.Uh&&v.Uh();w=a;l.ra(l.r.sr,I[w].index);R=X;V=-1*L*a;U=Date.now(); +O=!0;b();W.find("div").toggleClass("boxNavDisabled",0>=a);N.find("div").toggleClass("boxNavDisabled",a>=I.length-1)}function h(){O=!1;null!=v&&v.hs()}function C(a,b){return G&&null!=v&&v.Eh()&&a>f.d(340)&&af.d(140)&&bL/2){Q=X;var c=Math.round(-1*Q/L);z(c)}else 5c?w-1:P< +-1*c?w+1:w)):(c=I[w],c.Eh()&&(c.df||z(w),C(a,b)&&A(w)));S=!1}function E(a,b){x(a,b)}var I=[],w=0,X=0,G=!0,L=f.d(600),B=f.d(312),v=null,F=null,Y,H,W,N,K=new c(a.Sc,"boxPanel","menuBackground",!0);$(function(){Y=document.getElementById("boxCanvas");H=Y.getContext("2d");Y.width=f.d(1024);Y.height=f.d(576);W=$("#boxNavBack").click($.proxy(function(){0c?(l.Nc(a,e?1-c:c),window.requestAnimationFrame(d)):(l.Nc(a,e?0:1),e?$("#levelPanel").show():$("#levelPanel").hide(),null!=b&&b())}var e=null!=c?c:!1,g=Date.now(),k=750;l.canvas.getContext("2d");var s=c?f.ys:f.nh;window.requestAnimationFrame(d)};l.tx=function(a){l.so(!1, +a,!0)};l.sx=function(b){var c=$("#tapeRoll"),d=$("#levelTape");$("#levelResults").fadeOut(400);c.css("top",a.d(-14));c.delay(400).fadeIn(200,function(){function e(){var a=Date.now()-k,C=f.nh(a,s,g-s,z);c.css("top",f.nh(a,A,g-A,z));d.css("height",C);a").append($(r.ja({text:d+1,ua:!0}))).append($("
").addClass("stars"+h)),c.removeClass("locked purchase").addClass("open ctrPointer").empty().append(h)):c.removeClass("open").addClass("locked").toggleClass("purchase ctrPointer", +g).empty()):c.hide();a=f.Mm(e.Za)+"/"+3*f.Lc(e.Za);r.ja({text:a,Kc:"#levelScore img",ua:!0});e.Vu();f.pi()}a=new c(a.Bd,"levelPanel",p.DE||"levelBackground",!0);var h=null;a.init=function(a){function b(a,c,h){$("
").attr("id","option"+(a+1)).data("level",a).addClass("option locked ctrPointer "+p).css({left:u+(h||0),top:r}).click(s).appendTo(g);u+=c;u>l&&(u=k,r+=c)}h=a;var c=f.Lc(e.Za),g=$("#levelOptions"),k=0;a=0;var l=d.d(420),m=d.d(153),p="",n=3,q=c%3;9=c?(k=-80,a=10,n=4,l=d.d(500), +m=d.d(153)):12 has already been redeemed.")} +function d(){if(!e){var b=l.Tf.length,f=u.val()||"",g=0k||1>g||g>b?a("Oops, that is not a valid code!"):(u.attr("disabled",!0),e=!0,c(),$.ajax({type:"POST",url:"http://ctrbk.cloudapp.net/api/CTRBKCodes",contentType:"application/json",data:'{"ctrbkcode":"'+k+'"}',dataType:"json",error:function(){h(!1)},success:function(){h(!0)}}))}}p=$("#codeMessage");u=$("#codeText");q=$("#codeOkButton");A=$("#codeBack").toggle(!m.Sn()); +var e=!1,f=r.d(540),k=!1;u.keyup(function(b){13==b.which?d():a("")});q.click(function(){d()})});m.init=ha();m.Th=function(){p.text("");u.val("").focus();k.Nc(!1,0)};m.lo=ha();return m}(xa,Fa,sa,V,ma,da,fb,bb,R,ra,H),pb=function(a,c,d,b,f,e,g,k,l,n){var r=new function(){function l(){function a(){if(w){var d=Date.now();x+=0.1*(d-h)/25*G;h=d;b.setTransform(1,0,0,1,0,0);b.clearRect(0,0,E.width,E.height);1>F&&(F+=0.025,F=Math.min(F,1),b.globalAlpha=F);b.save();b.translate(0.5*I.width,0.5*I.height);b.translate(e.d(-300), +e.d(-510));b.rotate(x*Math.PI/180);b.translate(0.5*-I.width,0.5*-I.height);b.drawImage(I,0,0);b.restore();c(a)}}var b=E.getContext("2d"),c=window.requestAnimationFrame,h=Date.now();w=!0;a()}function p(){if(!H){if(null!=E){var a=E.getContext("2d");a.save();a.setTransform(1,0,0,1,0,0);a.clearRect(0,0,E.width,E.height);a.restore()}F=0;H=!0;$("#shadowPanel").show();w||l()}}var r=this,q=[];this.po=null;this.eb=function(){C=$("#fadeToBlack");E=document.getElementById("shadowCanvas");E.width=e.d(1024);E.height= +e.d(576)};this.Ed=function(a){I=new Image;I.src=g.Rc+"shadow.png";if(a)for(var b=0,c=q.length;bq+100&&(p=m=-1*e.Xe(u-(q+100),0,10,s-(q+100))):uv+100&&(p=m=10-e.lj(u-(v+100),10,z-(v+100))):uq&&uv&&uv+100&&(q=n=-1*e.Xe(O-(v+100),0,b.d(10),w-(v+100))):OF+100&&(q=n=b.d(10)-e.lj(O-(F+100),b.d(10),H-(F+100))):!(Ov&&OF&&O=f.Tt()-1?(H.hide(),z.oA()):(M.Un=!0,g.Va(a.ss?e.qb:e.Sc,!1))}function N(){if(f.Za!== +f.Tt()-1)return!1;var a=b.Lc(f.Za);return f.Nb!==a?!1:!0}function P(){$("#resultScore").text(ia[ea]);ea++;ea").appendTo(a));l.nc({text:b,img:d[0],ua:!0,alpha:0.6});a.stop(!0,!0).fadeIn(500).delay(c).fadeOut(750)}}function T(a,b){var c,d=m.xe,e=m.mf;a&&(d&&e?(d=!0,e=!1):e=d||e?d=!1:d=!0,m.tk(d),m.rk(e));c=d&&!e?"effectsOnly":d||e?"allSound":"noSound";$("#optionSound").removeClass("effectsOnly noSound allSound").addClass(c);$("#gameSound").removeClass("effectsOnly noSound allSound").addClass(c);e||d?(c=e?x.gw:x.fw,d=d?x.vw:x.uw,d=D.W(x.hp).replace("{0}",D.W(c).toLowerCase()).replace("{1}",D.W(d).toLowerCase())): +d=D.W(x.Mp);U(b,d)}function Q(a,b){l.ja({text:D.W(b),Kc:a,ua:!0})}var M=this;this.av=c.Ky;this.qe=this.Dj=this.Un=this.Fh=this.hg=!1;var ba=w.HE||30,Z=!1;h.subscribe(h.r.Bm,function(){Z=!0;S()});h.subscribe(h.r.Cm,function(){Z=!1;S()});var ca=null,aa=null,da=this.Uz=function(a,b,c){H.fadeIn(650,100);f.Nb=a;N()&&z.ez();c?s.ik():(g.Va(e.Gf,!b),setTimeout(function(){M.ut()},200))};this.Fu=function(){M.Fh&&(H.fadeOut(800,400),m.Yh(B));G.sx(function(){M.Dj=!1;M.Fh?g.Va(e.qb,!1):(G.Nc(!0,0),g.Va(e.Bd,!0))})}; +this.ut=function(){var a=g.fj==e.Bd?400:0;$("#levelScore").fadeOut();$("#levelBack").fadeOut();$("#levelOptions").fadeOut(a,function(){M.Dj?($("#levelResults").fadeOut(800),setTimeout(function(){s.yu(f.Za+1,f.Nb);G.so(!1,function(){M.pu()})},400)):G.Tz(function(){M.Dj=!0;s.yu(f.Za+1,f.Nb);G.so(!0,function(){M.pu()})})})};this.dn=function(){M.ux();setTimeout(function(){M.hg||$("#levelResults").delay(750).fadeIn(250);G.tx(function(){M.hg?M.Fu():setTimeout(function(){P()},250)})},250)};this.pu=function(){$("#levelBackground").hide(); +w.ou&&a.Sx&&$("#bg").show();$("#gameBtnTray").fadeIn()};this.ux=function(){G.Nc(!1,1);R();$("#levelBackground").show();w.ou&&a.Sx&&$("#bg").hide();$("#gameBtnTray").fadeOut()};var ga=[],ia=[],ea=0,ja=0;this.mo=function(a){function c(a,b,d){function e(){var c=Date.now(),q=(c-m)/k;m=c;p+=Math.round(b*q);h-=a*q;0>=h?(h=0,p=f,s.fadeOut(400),r.fadeOut(400,d)):n(e);l.nc({text:g(h),img:r[0],ua:!0});l.us({text:p,Ab:"resultScore",ua:!0})}var f=p+b,h=a,k=Math.max(1E3,2E3-50*a),m=Date.now(),n=window.requestAnimationFrame; +e()}function e(a,b){function c(){var e=Date.now(),h=Math.min(Math.round(a*(e-f)/1E3),d);f=e;d-=h;p+=h;0>=d?(d=0,p=a,s.fadeOut(400),r.fadeOut(400,b)):g(c);l.nc({text:d,img:r[0],ua:!0});l.us({text:p,Ab:"resultScore",ua:!0})}var d=a,f=Date.now(),g=window.requestAnimationFrame;c()}function g(a){var b=Math.floor(a/60);a=Math.round(a%60);return b+":"+(10>a?"0"+a:a)}var h=a.Eb,k=a.pk,m=a.time,n,p=0,q=1E3*h;Math.round((k-1E3*h)/m);switch(h){case 3:$("#resultStar1").removeClass("starEmpty").addClass("star"); +$("#resultStar2").removeClass("starEmpty").addClass("star");$("#resultStar3").removeClass("starEmpty").addClass("star");n=D.W(x.aw);break;case 2:$("#resultStar1").removeClass("starEmpty").addClass("star");$("#resultStar2").removeClass("starEmpty").addClass("star");$("#resultStar3").removeClass("star").addClass("starEmpty");n=D.W(x.$v);break;case 1:$("#resultStar1").removeClass("starEmpty").addClass("star");$("#resultStar2").removeClass("star").addClass("starEmpty");$("#resultStar3").removeClass("star").addClass("starEmpty"); +n=D.W(x.Zv);break;default:$("#resultStar1").removeClass("star").addClass("starEmpty"),$("#resultStar2").removeClass("star").addClass("starEmpty"),$("#resultStar3").removeClass("star").addClass("starEmpty"),n=D.W(x.Yv)}l.ja({text:n,Kc:"#resultStatus img",ua:!0});var r=$("#resultTickerValue").hide(),s=$("#resultTickerLabel").hide(),u=$("#resultScore").empty().hide(),v=$("#resultImproved").hide(),w=$("#resultTickerMessage").hide();l.nc({text:D.W(x.xw),img:s[0],ua:!0});l.nc({text:q,img:r[0],ua:!0});$("#resultScore img").remove(); +setTimeout(function(){s.fadeIn(300);r.fadeIn(300);u.fadeIn(300,function(){e(q,function(){l.nc({text:D.W(x.Fm),img:s[0],ua:!0});s.fadeIn(300);l.nc({text:g(Math.ceil(m)),img:r[0],ua:!0});r.fadeIn(300,function(){c(Math.ceil(m),k-p,function(){w.fadeIn(300);null!=B&&0B&&v.animate({scale:2.5,opacity:0},0,function(){v.css("display","block");v.animate({scale:1,opacity:1},600,"easeInCubic")})})})})})},1E3);n=f.Za;var A=f.Nb,B=b.wj(n,A-1);b.No(n,A-1,k);b.we(n,A-1,h);b.Lc(n)>A&&f.Ej()&&b.we(n,A,0);M.hg= +!1;M.dn();0===n&&1===A&&(K.Jz&&K.Jz(a.Es),a.Esc.d(1024)+120&&!fa&&($("#moreLink").fadeIn(function(){fa=!0}),$("#zenbox_tab").fadeIn())};this.un=!0;this.vo=function(){g.fj===e.Gf&&s.My()&&!M.qe?u():m.Xh()};this.Yt=function(){g.fj!==e.Ci&&M.un&&m.Ho()};this.init=function(){b.load();g.po=O};this.eb= +function(){z.eb();k.eb();g.eb();H.eb();$(window).blur(M.vo);$(window).focus(M.Yt);$(window).resize(function(){M.Xu()})};this.Ed=function(){h.subscribe(h.r.zl,this.mo);G.Ed();k.Ed();g.Ed(V);f.Ed();h.ra(h.r.Ib);if(null!=w.ix&&null!=w.gf)this.ot(w.ix-1,w.gf-1);else if(r.qu){var a=g.Ze(e.Me);a&&a.Sn&&a.Sn()?(G.Nc(!0,0),g.Va(e.Me,!0)):g.Va(e.qb,!0)}var b=this;h.subscribe(h.r.Kq,function(){b.vo()});h.subscribe(h.r.Np,function(){b.un=!0;b.Yt()});h.subscribe(h.r.Ip,function(){b.un=!1;b.vo()})};this.ot=function(a, +b){g.Va(e.Gf,!0);f.Za=a;f.Nb=b+1;this.ut()};this.Vz=function(a){M.Dj=!1;G.Nc(!0,0);g.Va(e.Bd);H.UA(a)}};return v}(R,H,T,ta,Qa,xa,pb,kc,da,Ua,qa,ma,w,lc,sa,ra,$a,mc,V,pa,ga,la,F,S,cb,function(a,c){var d=null;return{eb:function(){d=$("#gameBorder")},UA:function(b){b=(b=c.as[b])?a.Rc+b:"";d.removeClass("gameComplete").css("background-image","url("+b+")")},aB:function(){d.css("background-image","").addClass("gameComplete")},hide:function(){d.hide()},show:function(){d.show()},fadeIn:function(a,c){d.delay(c|| +0).fadeIn(a)},fadeOut:function(a,c){d.delay(c||0).fadeOut(a)}}}(T,R),Na,bb,ab),oc=function(a,c,d,b,f,e,g,k,l,n){return{init:function(){a.init();e.Rh(function(){d.init();k.ra(k.r.iv)})},eb:function(){f.Dx&&"undefined"!=typeof document.body.onselectstart&&(document.body.onselectstart=Ga(!1));$(".ctrCursor").on("mousedown mouseup",function(){$(this).toggleClass("ctrCursorActive")});$("body").addClass("ui-"+c.$d);b.eb("c");b.element.width=c.pb;b.element.height=c.ab;c.tC||(c.Rk?$(b.element).width(c.Rk).height(c.sC): +$(b.element).width(c.pb).height(c.ab));g.eb&&g.eb();a.eb();d.eb();k.ra(k.r.hv)},Jo:function(){a.Jo(function(){d.Ed();k.ra(k.r.ip);$(".hideBeforeLoad").fadeIn(500);d.Xu();$("#gameFooterSocial").css("top",0);if(!f.Ym&&n.ft()){$("#lsDomain").text(location.protocol+"//"+location.host);$("#lsChromeInfoLink").show(0<=navigator.userAgent.indexOf("Chrome"));var a=$("#lsWarning").fadeIn(100);$("#lsOkButton").on("click",function(){a.fadeOut()})}})}}}(wb,H,nc,P,qa,za,Va,V,Ta,T),pc=function(a,c,d,b,f){a("forceHTML5Audio", +c.$x);window.showFpsCounter=function(){b.Fs=!0};a("initFB",d.Ey);a("initTwitter",d.Hy);a("onLevelWon",function(a){f.subscribe(f.r.zl,function(){a()})});a("pauseGame",function(){f.ra(f.r.Kq)});a("enable",function(){f.ra(f.r.Np)});a("disable",function(){f.ra(f.r.Ip)});return window.ZeptoLab}(function(){return function(a,c){var d=window.ZeptoLab;null==d&&(d=window.ZeptoLab={});var b=d.ctr;null==b&&(b=d.ctr={});b[a]=c}}(),ra,cb,qa,V);(function(a,c){c.ft()&&(a.init(),$(document).ready(function(){a.eb(); +a.Jo()}))})(oc,T,pc)})();})(); diff --git a/projects/Cut The Rope/scripts/libraries.js b/projects/Cut The Rope/scripts/libraries.js new file mode 100644 index 000000000..50196443d --- /dev/null +++ b/projects/Cut The Rope/scripts/libraries.js @@ -0,0 +1,158 @@ +/* Modernizr 2.6.3 (Custom Build) | MIT & BSD + * Build: http://modernizr.com/download/#-fontface-opacity-rgba-csstransforms-canvas-canvastext-audio-video-localstorage-touch-mq-addtest-teststyles-testprop-prefixes-load + */ +;window.Modernizr=function(a,b,c){function z(a){i.cssText=a}function A(a,b){return z(l.join(a+";")+(b||""))}function B(a,b){return typeof a===b}function C(a,b){return!!~(""+a).indexOf(b)}function D(a,b){for(var d in a){var e=a[d];if(!C(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function E(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:B(f,"function")?f.bind(d||b):f}return!1}function F(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+n.join(d+" ")+d).split(" ");return B(b,"string")||B(b,"undefined")?D(e,b):(e=(a+" "+o.join(d+" ")+d).split(" "),E(e,b,c))}var d="2.6.3",e={},f=b.documentElement,g="modernizr",h=b.createElement(g),i=h.style,j,k={}.toString,l=" -webkit- -moz- -o- -ms- ".split(" "),m="Webkit Moz O ms",n=m.split(" "),o=m.toLowerCase().split(" "),p={},q={},r={},s=[],t=s.slice,u,v=function(a,c,d,e){var h,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:g+(d+1),l.appendChild(j);return h=["­",'"].join(""),l.id=g,(m?l:n).innerHTML+=h,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=f.style.overflow,f.style.overflow="hidden",f.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),f.style.overflow=k),!!i},w=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return v("@media "+b+" { #"+g+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},x={}.hasOwnProperty,y;!B(x,"undefined")&&!B(x.call,"undefined")?y=function(a,b){return x.call(a,b)}:y=function(a,b){return b in a&&B(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=t.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(t.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(t.call(arguments)))};return e}),p.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},p.canvastext=function(){return!!e.canvas&&!!B(b.createElement("canvas").getContext("2d").fillText,"function")},p.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:v(["@media (",l.join("touch-enabled),("),g,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},p.rgba=function(){return z("background-color:rgba(150,255,150,.5)"),C(i.backgroundColor,"rgba")},p.opacity=function(){return A("opacity:.55"),/^0.55$/.test(i.opacity)},p.csstransforms=function(){return!!F("transform")},p.fontface=function(){var a;return v('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},p.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},p.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},p.localstorage=function(){try{return localStorage.setItem(g,g),localStorage.removeItem(g),!0}catch(a){return!1}};for(var G in p)y(p,G)&&(u=G.toLowerCase(),e[u]=p[G](),s.push((e[u]?"":"no-")+u));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)y(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof enableClasses!="undefined"&&enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},z(""),h=j=null,e._version=d,e._prefixes=l,e._domPrefixes=o,e._cssomPrefixes=n,e.mq=w,e.testProp=function(a){return D([a])},e.testAllProps=F,e.testStyles=v,e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t) +};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*\s*$/g,ct={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("