569c851c397ee82fd55e400b4b9a693ed8e429ce
[samples/web/MemoryGame.git] / js / main.js
1 /*
2  * Copyright (c) 2012, Intel Corporation.
3  *
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
7  *
8  */
9
10 Game = {};
11
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"
25 ];
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"
39 ];
40
41 var stariconsList = [
42     "images/purple_star.png",
43     "images/green_star.png",
44     "images/red_star.png"
45 ];
46
47 var audioItems = [
48     "flipcard_sound1",
49     "flipcard_sound2",
50     "startGame_sound",
51     "finaleIntro_sound",
52     "winLevel_sound",
53     "victory_sound"
54 ];
55
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;
62
63
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";
68
69
70 (function () {
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;
77     var levelNumber = -1;
78     var passedGames = 0;
79     var lastPlayedFlipSound = SOUND_FLIPCARD2;
80     var levelLockingStatus = [ false, true, true, true ];
81
82     // Set memberfunctions.
83     Game.flipCallback = flipCallback;
84     Game.flipDelayCallback = flipDelayCallback;
85     Game.gotoNextGame = gotoNextGame;
86     Game.levelSelectionAnimCallback = levelSelectionAnimCallback;
87     Game.introViewSkipCallback = introViewSkipCallback;
88
89     /**
90      * Plays sounds base on their ID
91      */
92     function playSound(soundId) {
93         var audioElement = document.getElementById(audioItems[soundId]);
94         audioElement.pause();
95         audioElement.play();
96     }
97
98     /**
99      * This function prepares the graphical elements of Victory-screen.
100      */
101     function prepareVictoryScreen() {
102         localizer.localizeVictoryScreen();
103
104         // Draw the curved YOU WIN text.
105         var drawer = new CurvedTextDrawer(document.getElementById("curvedText"));
106         var centerPos = drawer.getCanvasCenterPos();
107         centerPos.mY = -625;
108         drawer.useFont = '70px Romantiques';
109         drawer.drawSectorArc(localizer.getTranslation("victory_youwin"), centerPos.mX, centerPos.mY, 780, 180, 270, 'ccw', true, 'center');
110
111         $("#homebutton_backtomain").hide();
112     }
113
114     /**
115      * Reads the level lock status from local storage and sets the card element styles
116      * accordingly.
117      */
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;
127                 } else {
128                     levelLockingStatus[i] = true;
129                 }
130             } else {
131                 levelLockingStatus[i] = true;
132             }
133             var cardElement = $("#selLevel_levelCard"+(i+1));
134             cardElement.removeClass(LOCKED_LEVELCARD_STYLE);
135             if (levelLockingStatus[i]) {
136                 cardElement.addClass(LOCKED_LEVELCARD_STYLE);
137             }
138         }
139         console.log("<-- prepareSelectLevelScreen()");
140     }
141
142     /**
143      * Saves the level lock status to local storage.
144      */
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';
152             } else {
153                 console.log("    level: " + i + ", lock: unlocked");
154                 lockedLevelsStr += '0';
155             }
156         }
157         console.log("    data: " + lockedLevelsStr);
158         localStorage.setItem(LOCAL_STORAGE_KEY, lockedLevelsStr);
159         console.log("<-- saveStatus()");
160     }
161
162
163     /**
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.
167      */
168     function getCardObject(cardDivName) {
169         for (var i=0; i < cardsArray.length; ++i) {
170             var card = cardsArray[i];
171             if (card.cardId == cardDivName) {
172                 return card;
173             }
174         }
175         return undefined;
176     }
177
178     /**
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.
182      */
183     function matchFound(card1, card2) {
184         card1.found = true;
185         card2.found = true;
186
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]+")");
193     }
194
195     /**
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.
198      */
199     function allPairsFound() {
200         for (var i=0; i < cardsArray.length; ++i) {
201             var card = cardsArray[i];
202             if (card.found == false) {
203                 return false;
204             }
205         }
206         return true;
207     }
208
209
210     /**
211      * A callback function that gets called when card rotation animation ends. This
212      * function checks if two rotated cards are pairs.
213      */
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;
221
222         } else {
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()) {
229                     gotoNextGame();
230                 }
231                 ignoreInputs = false;
232                 firstFlippedCard = undefined;
233                 clickedCardElement = undefined;
234
235             } else {
236                 console.log("    no match");
237                 window.setTimeout("Game.flipDelayCallback()", 300);
238             }
239         }
240         console.log("<-- Game.flipCallback()");
241     }
242
243     /**
244      * Callbackfunction that rotates the two latest cards upside down again.
245      */
246     function flipDelayCallback() {
247         ignoreInputs = false;
248         firstFlippedCard.removeClass(SHOWCARD_STYLE);
249         clickedCardElement.removeClass(SHOWCARD_STYLE);
250         firstFlippedCard = undefined;
251         clickedCardElement = undefined;
252     }
253
254     /**
255      * Shuffles the cards in the beginning of the game.
256      * @param   cardsArray      Array that contains the card objects.
257      */
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 );
264         }
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;
270         }
271         var elemIndex = 0;
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);
279         }
280         console.log("<-- shuffleLevel1()");
281     }
282
283     /**
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.
286      */
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;
294             saveStatus();
295             // Currently finished level was 4. It means that player has finished the game.
296             prepareVictoryScreen();
297             playSound(SOUND_VICTORY);
298             $("#level4").hide();
299             $("#victory").show();
300             return;
301         }
302         passedGames++;
303         var levelOfNextGame = levelNumber;
304         if (passedGames >= GAMES_PER_LEVEL) {
305             // Move to next level.
306             passedGames = 0;
307             levelOfNextGame++;
308
309             // Next level unlocked.
310             levelLockingStatus[levelNumber] = false;
311             if (levelOfNextGame != 4) {
312                 playSound(SOUND_LEVEL_WON);
313             }
314         }
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();
322             $("#level3").hide();
323             $("#finaleIntro").show();
324         } else {
325             startGame(levelOfNextGame, false);
326         }
327         saveStatus();
328         console.log("<-- gotoNextGame()");
329     }
330
331     /**
332      * A callback function that gets called when level selection animation has ended.
333      */
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()");
344     }
345
346     /**
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.
350      */
351     function startGame(levelNum, resetState) {
352         console.log("--> startGame()");
353         if (resetState) {
354             passGames = 0;
355         }
356
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;
361         var numOfCards = 12;
362         if (levelNum == 2) {
363             numOfCards = 18;
364             cardBgGraphics = "url(images/card_green.png)"
365         } else if (levelNum == 3) {
366             numOfCards = 24;
367             cardBgGraphics = "url(images/card_red.png)"
368         } else if (levelNum == 4) {
369             numOfCards = 24;
370             cardBgGraphics = "url(images/card_teal.png)"
371         }
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);
378
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");
384         }
385         setTimeout(function() {shuffleLevel(cardsArray);}, 300);
386         $(".card").removeClass(SHOWCARD_STYLE);
387         firstFlippedCard = undefined;
388         clickedCardElement = undefined;
389
390
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);
398
399             } else {
400                 starImgElement.addClass("unplayedGameStar");
401                 starImgElement.attr("src", "images/star.png");
402             }
403         }
404         if (levelNum != 4) {
405             $("#handitem").css("display", "block");
406         } else {
407             // The hand image is not shown in final level.
408             $("#handitem").hide();
409         }
410
411         // Control the level elements visibility.
412         for (var i=1; i < 5; ++i) {
413             if (i == levelNum) {
414                 $("#level"+i).show();
415             } else {
416                 $("#level"+i).hide();
417             }
418         }
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");
425         }
426
427         localizer.localizeGameScreen(levelNum, passedGames+1);
428         $("#homebutton_backtomain").show();
429         console.log("<-- startGame()");
430     }
431
432     function introViewSkipCallback() {
433         prepareSelectLevelScreen();
434         if ($("#main_page").is(":visible")) {
435             $("#main_page").hide();
436             $("#selLevel_page").show();
437         }
438     }
439
440     // Initialize game once everything has been loaded.
441     $(document).ready(function () {
442         console.log("--> document.ready()");
443
444         license_init("license", "pagebg");
445         help_init("main_help", "help_");
446         localizer.localizeMainScreen();
447
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();
454         });
455
456         $("#selLevel_levelCard1").click(function () {
457             // Start game.
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);
465         });
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);
475             }
476         });
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);
486             }
487         });
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);
497             }
498         });
499
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;
507                 } else {
508                     lastPlayedFlipSound = SOUND_FLIPCARD1;
509                 }
510                 playSound(lastPlayedFlipSound);
511                 clickedCardElement = $(this);
512                 ignoreInputs = true;
513                 console.log("    card id: " + $(this).attr("id"));
514                 $(this).addClass(SHOWCARD_STYLE);
515                 window.setTimeout("Game.flipCallback()", 350);
516             }
517             console.log("<-- card.click()");
518         });
519
520         $("#finaleIntro").click( function() {
521             // Start playing final level.
522             $("#finaleIntro").hide();
523             startGame(4, false);
524         });
525
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()");
532         });
533
534         $("#homebutton_backtomain").click(function() {
535             console.log("--> homebutton.click()");
536             // Hide current levels and show mainpage.
537             $("#level1").hide();
538             $("#level2").hide();
539             $("#level3").hide();
540             $("#level4").hide();
541             $("#handitem").hide();
542             $("#main_page").show();
543             $(this).hide();
544             console.log("<-- homebutton.click()");
545         });
546
547         $("#selLevel_resetLocked").click(function() {
548             localStorage.setItem(LOCAL_STORAGE_KEY, '0000');
549             prepareSelectLevelScreen();
550         });
551     });
552
553     // Skip the welcome screen after a while.
554     window.setTimeout("Game.introViewSkipCallback()", 3500);
555 })();