2 * Copyright (c) 2012, Intel Corporation.
4 * This program is licensed under the terms and conditions of the
5 * Apache License, version 2.0. The full text of the Apache License is at
6 * http://www.apache.org/licenses/LICENSE-2.0
12 var normalCardImages = [
13 "images/noglow_balloon.png",
14 "images/noglow_butterflies.png",
15 "images/noglow_crown.png",
16 "images/noglow_cup.png",
17 "images/noglow_elephant.png",
18 "images/noglow_guitar.png",
19 "images/noglow_horn.png",
20 "images/noglow_lion.png",
21 "images/noglow_moon.png",
22 "images/noglow_sun.png",
23 "images/noglow_zebra.png",
24 "images/noglow_blank.png"
26 var glowingCardImages = [
27 "images/card_flip_balloon.png",
28 "images/card_flip_butterflies.png",
29 "images/card_flip_crown.png",
30 "images/card_flip_cup.png",
31 "images/card_flip_elephant.png",
32 "images/card_flip_guitar.png",
33 "images/card_flip_horn.png",
34 "images/card_flip_lion.png",
35 "images/card_flip_moon.png",
36 "images/card_flip_sun.png",
37 "images/card_flip_zebra.png",
38 "images/card_flip_blank.png"
42 "images/purple_star.png",
43 "images/green_star.png",
56 var SOUND_FLIPCARD1 = 0;
57 var SOUND_FLIPCARD2 = 1;
58 var SOUND_STARTGAME = 2;
59 var SOUND_FINALEINTRO = 3;
60 var SOUND_LEVEL_WON = 4;
61 var SOUND_VICTORY = 5;
64 var LOCKED_LEVELCARD_STYLE = "setLevel_lockedLevel";
65 var SHOWCARD_STYLE = "flip_to_visible";
66 var GAMES_PER_LEVEL = 3;
67 var LOCAL_STORAGE_KEY = "memorygame_locked_levels";
71 var localizer = new Localizer();
72 var cardsArray = new Array();
73 var levelSelectionUserChoice = -1;
74 var ignoreInputs = false;
75 var firstFlippedCard = undefined;
76 var clickedCardElement = undefined;
79 var lastPlayedFlipSound = SOUND_FLIPCARD2;
80 var levelLockingStatus = [ false, true, true, true ];
82 // Set memberfunctions.
83 Game.flipCallback = flipCallback;
84 Game.flipDelayCallback = flipDelayCallback;
85 Game.gotoNextGame = gotoNextGame;
86 Game.levelSelectionAnimCallback = levelSelectionAnimCallback;
87 Game.introViewSkipCallback = introViewSkipCallback;
90 * Plays sounds base on their ID
92 function playSound(soundId) {
93 var audioElement = document.getElementById(audioItems[soundId]);
99 * This function prepares the graphical elements of Victory-screen.
101 function prepareVictoryScreen() {
102 localizer.localizeVictoryScreen();
104 // Draw the curved YOU WIN text.
105 var drawer = new CurvedTextDrawer(document.getElementById("curvedText"));
106 var centerPos = drawer.getCanvasCenterPos();
108 drawer.useFont = '70px Romantiques';
109 drawer.drawSectorArc(localizer.getTranslation("victory_youwin"), centerPos.mX, centerPos.mY, 780, 180, 270, 'ccw', true, 'center');
111 $("#homebutton_backtomain").hide();
115 * Reads the level lock status from local storage and sets the card element styles
118 function prepareSelectLevelScreen() {
119 console.log("--> prepareSelectLevelScreen()");
120 localizer.localizeSelectLevelScreen();
121 var lockedLevels = localStorage.getItem(LOCAL_STORAGE_KEY);
122 for (var i=1; i < levelLockingStatus.length; ++i) {
123 if (lockedLevels != undefined && lockedLevels != null && lockedLevels.length > i) {
124 console.log(" read data: " + lockedLevels);
125 if (lockedLevels[i] == '0') {
126 levelLockingStatus[i] = false;
128 levelLockingStatus[i] = true;
131 levelLockingStatus[i] = true;
133 var cardElement = $("#selLevel_levelCard"+(i+1));
134 cardElement.removeClass(LOCKED_LEVELCARD_STYLE);
135 if (levelLockingStatus[i]) {
136 cardElement.addClass(LOCKED_LEVELCARD_STYLE);
139 console.log("<-- prepareSelectLevelScreen()");
143 * Saves the level lock status to local storage.
145 function saveStatus() {
146 console.log("--> saveStatus()");
147 var lockedLevelsStr = '0';
148 for (var i = 1; i < levelLockingStatus.length; ++i) {
149 if (levelLockingStatus[i]) {
150 console.log(" level: " + i + ", lock: locked");
151 lockedLevelsStr += '1';
153 console.log(" level: " + i + ", lock: unlocked");
154 lockedLevelsStr += '0';
157 console.log(" data: " + lockedLevelsStr);
158 localStorage.setItem(LOCAL_STORAGE_KEY, lockedLevelsStr);
159 console.log("<-- saveStatus()");
164 * Returns the card object of the card whose DIV element has given ID.
165 * @param cardDivName Name of the cards div element.
166 * @return The matching Card object or undefined if card was not found.
168 function getCardObject(cardDivName) {
169 for (var i=0; i < cardsArray.length; ++i) {
170 var card = cardsArray[i];
171 if (card.cardId == cardDivName) {
179 * Marks the cards as found ones and changes the graphics.
180 * @param card1 First one of the found cards.
181 * @param card2 Second one of the found cards.
183 function matchFound(card1, card2) {
187 // Change the graphics to glowing ones.
188 var gfxIndex = card1.cardType;
189 $(card1.cardId).children(".back").css("visibility", "hidden");
190 $(card2.cardId).children(".back").css("visibility", "hidden");
191 $(card1.cardFrontId).css("background", "url("+glowingCardImages[gfxIndex]+")");
192 $(card2.cardFrontId).css("background", "url("+glowingCardImages[gfxIndex]+")");
196 * Checks the states of the cards and tells if all the pairs have been found.
197 * @return true if all the pairs have been found.
199 function allPairsFound() {
200 for (var i=0; i < cardsArray.length; ++i) {
201 var card = cardsArray[i];
202 if (card.found == false) {
211 * A callback function that gets called when card rotation animation ends. This
212 * function checks if two rotated cards are pairs.
214 function flipCallback() {
215 console.log("--> Game.flipCallback()");
216 if (firstFlippedCard == undefined) {
217 // This is the first card being turned.
218 firstFlippedCard = clickedCardElement;
219 clickedCardElement = undefined;
220 ignoreInputs = false;
223 // This is the second card being turned. Check if they are equal.
224 var cardObj1 = getCardObject("#" + firstFlippedCard.attr("id"));
225 var cardObj2 = getCardObject("#" + clickedCardElement.attr("id"));
226 if (cardObj1.cardType == cardObj2.cardType) {
227 matchFound(cardObj1, cardObj2);
228 if (allPairsFound()) {
231 ignoreInputs = false;
232 firstFlippedCard = undefined;
233 clickedCardElement = undefined;
236 console.log(" no match");
237 window.setTimeout("Game.flipDelayCallback()", 300);
240 console.log("<-- Game.flipCallback()");
244 * Callbackfunction that rotates the two latest cards upside down again.
246 function flipDelayCallback() {
247 ignoreInputs = false;
248 firstFlippedCard.removeClass(SHOWCARD_STYLE);
249 clickedCardElement.removeClass(SHOWCARD_STYLE);
250 firstFlippedCard = undefined;
251 clickedCardElement = undefined;
255 * Shuffles the cards in the beginning of the game.
256 * @param cardsArray Array that contains the card objects.
258 function shuffleLevel(cardsArray) {
259 console.log("--> shuffleLevel1()");
260 // Make an array that contains 2 copies of card type ids.
261 var typeIndexArray = new Array();
262 for (var i=0; i < cardsArray.length; ++i) {
263 typeIndexArray.push( (Math.floor(i / 2)) % normalCardImages.length );
265 for (var i=0; i < typeIndexArray.length; ++i) {
266 var swapWithIndex = Math.floor(Math.random() * 11);
267 var tmpValue = typeIndexArray[swapWithIndex];
268 typeIndexArray[swapWithIndex] = typeIndexArray[i];
269 typeIndexArray[i] = tmpValue;
272 for (var i=0; i < cardsArray.length; ++i) {
273 var gfxIndex = typeIndexArray.pop();
274 var card = cardsArray[i];
275 card.cardType = gfxIndex;
276 console.log("elementId: " + card.cardFrontId + ", graphics: " + normalCardImages[gfxIndex]);
277 $(card.cardFrontId).css("background", "url("+normalCardImages[gfxIndex]+")");
278 $(card.cardId).removeClass(SHOWCARD_STYLE);
280 console.log("<-- shuffleLevel1()");
284 * This should be called when game has been played through. It does the actions that are
285 * needed to handle game and level progress and also showing victory screen.
287 function gotoNextGame() {
288 console.log("--> gotoNextGame()");
289 if (levelNumber == 4) {
290 levelLockingStatus[0] = false;
291 levelLockingStatus[1] = false;
292 levelLockingStatus[2] = false;
293 levelLockingStatus[3] = false;
295 // Currently finished level was 4. It means that player has finished the game.
296 prepareVictoryScreen();
297 playSound(SOUND_VICTORY);
299 $("#victory").show();
303 var levelOfNextGame = levelNumber;
304 if (passedGames >= GAMES_PER_LEVEL) {
305 // Move to next level.
309 // Next level unlocked.
310 levelLockingStatus[levelNumber] = false;
311 if (levelOfNextGame != 4) {
312 playSound(SOUND_LEVEL_WON);
315 if (levelOfNextGame == 4) {
316 // Show intro view before entring the final level.
317 localizer.localizeFinaleIntroScreen();
318 levelLockingStatus[3] = false;
319 playSound(SOUND_FINALEINTRO);
320 $("#homebutton_backtomain").hide();
321 $("#handitem").hide();
323 $("#finaleIntro").show();
325 startGame(levelOfNextGame, false);
328 console.log("<-- gotoNextGame()");
332 * A callback function that gets called when level selection animation has ended.
334 function levelSelectionAnimCallback() {
335 console.log("--> levelSelectionAnimCallback()");
336 $("#selLevel_page").hide();
337 $("#selLevel_levelCard1").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
338 $("#selLevel_levelCard2").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
339 $("#selLevel_levelCard3").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
340 $("#selLevel_levelCard4").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
341 startGame(levelSelectionUserChoice, true);
342 playSound(SOUND_LEVEL_WON);
343 console.log("<-- levelSelectionAnimCallback()");
347 * Initializes the structures to start new game.
348 * @param levelNum The level that will be started.
349 * @param resteState Pass true to reset the game counts to 0.
351 function startGame(levelNum, resetState) {
352 console.log("--> startGame()");
357 // Figure out the amount of cards needed in this level.
358 var cardBgGraphics = "url(images/card_purple.png)"
359 cardsArray = new Array();
360 levelNumber = levelNum;
364 cardBgGraphics = "url(images/card_green.png)"
365 } else if (levelNum == 3) {
367 cardBgGraphics = "url(images/card_red.png)"
368 } else if (levelNum == 4) {
370 cardBgGraphics = "url(images/card_teal.png)"
372 // Create card objects.
373 for (var i=0; i < numOfCards; ++i) {
374 var card = new Card();
375 card.cardFrontId = "#level"+levelNum+"_card_"+(i+1)+"_front";
376 card.cardId = "#" + $(card.cardFrontId).parent().attr("id");
377 cardsArray.push(card);
379 // Manually set toggle the card backgrounds between invisible
380 // background and real card background. We can't use plain css
381 // because the backface-visibility during rotation does not
382 // work in linux Chrome as it should.
383 $(card.cardId).children(".back").css("visibility", "visible");
385 setTimeout(function() {shuffleLevel(cardsArray);}, 300);
386 $(".card").removeClass(SHOWCARD_STYLE);
387 firstFlippedCard = undefined;
388 clickedCardElement = undefined;
391 // Update the hand that holds the game count note.
392 var starIconName = stariconsList[levelNum-1];
393 for (var gameIndex = 0; gameIndex < 3; ++gameIndex) {
394 var starImgElement = $("#handleitem_star"+(gameIndex+1));
395 starImgElement.removeClass("unplayedGameStar");
396 if (gameIndex <= passedGames) {
397 starImgElement.attr("src", starIconName);
400 starImgElement.addClass("unplayedGameStar");
401 starImgElement.attr("src", "images/star.png");
405 $("#handitem").css("display", "block");
407 // The hand image is not shown in final level.
408 $("#handitem").hide();
411 // Control the level elements visibility.
412 for (var i=1; i < 5; ++i) {
414 $("#level"+i).show();
416 $("#level"+i).hide();
419 if (passedGames == 0) {
420 $("#handitem_gamenum_title").text("GAME 1");
421 } else if (passedGames == 1) {
422 $("#handitem_gamenum_title").text("GAME 2");
423 } else if (passedGames == 2) {
424 $("#handitem_gamenum_title").text("GAME 3");
427 localizer.localizeGameScreen(levelNum, passedGames+1);
428 $("#homebutton_backtomain").show();
429 console.log("<-- startGame()");
432 function introViewSkipCallback() {
433 prepareSelectLevelScreen();
434 if ($("#main_page").is(":visible")) {
435 $("#main_page").hide();
436 $("#selLevel_page").show();
440 // Initialize game once everything has been loaded.
441 $(document).ready(function () {
442 console.log("--> document.ready()");
444 license_init("license", "pagebg");
445 help_init("main_help", "help_");
446 localizer.localizeMainScreen();
448 // Add the event handler functions.
449 $("#main_page").click(function () {
450 // Hide mainview and show level selection.
451 prepareSelectLevelScreen();
452 $("#main_page").hide();
453 $("#selLevel_page").show();
456 $("#selLevel_levelCard1").click(function () {
458 levelSelectionUserChoice = 1;
459 playSound(SOUND_FLIPCARD2);
460 $("#selLevel_levelCard1").addClass("selLevel_selectedCard");
461 $("#selLevel_levelCard2").addClass("selLevel_anim1");
462 $("#selLevel_levelCard3").addClass("selLevel_anim1");
463 $("#selLevel_levelCard4").addClass("selLevel_anim1");
464 window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
466 $("#selLevel_levelCard2").click(function() {
467 if ($(this).hasClass(LOCKED_LEVELCARD_STYLE) == false) {
468 playSound(SOUND_FLIPCARD2);
469 levelSelectionUserChoice = 2;
470 $("#selLevel_levelCard2").addClass("selLevel_selectedCard");
471 $("#selLevel_levelCard1").addClass("selLevel_anim2");
472 $("#selLevel_levelCard3").addClass("selLevel_anim2");
473 $("#selLevel_levelCard4").addClass("selLevel_anim2");
474 window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
477 $("#selLevel_levelCard3").click(function() {
478 if ($(this).hasClass(LOCKED_LEVELCARD_STYLE) == false) {
479 playSound(SOUND_FLIPCARD2);
480 levelSelectionUserChoice = 3;
481 $("#selLevel_levelCard3").addClass("selLevel_selectedCard");
482 $("#selLevel_levelCard1").addClass("selLevel_anim3");
483 $("#selLevel_levelCard2").addClass("selLevel_anim3");
484 $("#selLevel_levelCard4").addClass("selLevel_anim3");
485 window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
488 $("#selLevel_levelCard4").click(function() {
489 if ($(this).hasClass(LOCKED_LEVELCARD_STYLE) == false) {
490 playSound(SOUND_FLIPCARD2);
491 levelSelectionUserChoice = 4;
492 $("#selLevel_levelCard4").addClass("selLevel_selectedCard");
493 $("#selLevel_levelCard1").addClass("selLevel_anim4");
494 $("#selLevel_levelCard2").addClass("selLevel_anim4");
495 $("#selLevel_levelCard3").addClass("selLevel_anim4");
496 window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
500 $(".card").click(function() {
501 console.log("--> card.click()");
502 if (!ignoreInputs && !($(this).hasClass(SHOWCARD_STYLE))) {
503 // We have to use 2 different audio items for flip sound because
504 // audio API doesn't replay the sound if it is already playing.
505 if (lastPlayedFlipSound == SOUND_FLIPCARD1) {
506 lastPlayedFlipSound = SOUND_FLIPCARD2;
508 lastPlayedFlipSound = SOUND_FLIPCARD1;
510 playSound(lastPlayedFlipSound);
511 clickedCardElement = $(this);
513 console.log(" card id: " + $(this).attr("id"));
514 $(this).addClass(SHOWCARD_STYLE);
515 window.setTimeout("Game.flipCallback()", 350);
517 console.log("<-- card.click()");
520 $("#finaleIntro").click( function() {
521 // Start playing final level.
522 $("#finaleIntro").hide();
526 $("#victory_playagain_box").click(function() {
527 console.log("--> victory_playagain_box.click()");
528 prepareSelectLevelScreen();
529 $("#victory").hide();
530 $("#selLevel_page").show();
531 console.log("<-- victory_playagain_box.click()");
534 $("#homebutton_backtomain").click(function() {
535 console.log("--> homebutton.click()");
536 // Hide current levels and show mainpage.
541 $("#handitem").hide();
542 $("#main_page").show();
544 console.log("<-- homebutton.click()");
547 $("#selLevel_resetLocked").click(function() {
548 localStorage.setItem(LOCAL_STORAGE_KEY, '0000');
549 prepareSelectLevelScreen();
553 // Skip the welcome screen after a while.
554 window.setTimeout("Game.introViewSkipCallback()", 3500);