[MemoryGame]update MemoryGame(tizen_2.1)
[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 Card = function() {
11     this.cardId = "";
12     this.cardFrontId = "";
13     this.cardGraphics = "";
14     this.cardType = -1;
15     this.found = false;
16 }
17
18 Game = {};
19
20 var normalCardImages = [
21     "images/noglow_balloon.png",
22     "images/noglow_butterflies.png",
23     "images/noglow_crown.png",
24     "images/noglow_cup.png",
25     "images/noglow_elephant.png",
26     "images/noglow_guitar.png",
27     "images/noglow_horn.png",
28     "images/noglow_lion.png",
29     "images/noglow_moon.png",
30     "images/noglow_sun.png",
31     "images/noglow_zebra.png",
32     "images/noglow_blank.png"
33 ];
34 var glowingCardImages = [
35     "images/card_flip_balloon.png",
36     "images/card_flip_butterflies.png",
37     "images/card_flip_crown.png",
38     "images/card_flip_cup.png",
39     "images/card_flip_elephant.png",
40     "images/card_flip_guitar.png",
41     "images/card_flip_horn.png",
42     "images/card_flip_lion.png",
43     "images/card_flip_moon.png",
44     "images/card_flip_sun.png",
45     "images/card_flip_zebra.png",
46     "images/card_flip_blank.png"
47 ];
48
49 var stariconsList = [
50     "images/purple_star.png",
51     "images/green_star.png",
52     "images/red_star.png"
53 ];
54
55 var audioItems = [
56     "flipcard_sound1",
57     "flipcard_sound2",
58     "startGame_sound",
59     "finaleIntro_sound",
60     "winLevel_sound",
61     "victory_sound"
62 ];
63
64 var audioSrc = [
65     "audio/FlipCard.wav",
66     "audio/FlipCard.wav",
67     "audio/StartPage.wav",
68     "audio/TheFinale.wav",
69     "audio/WinLevel.wav",
70     "audio/YouWin.wav"
71 ];
72
73 var SOUND_FLIPCARD1 = 0;
74 var SOUND_FLIPCARD2 = 1;
75 var SOUND_STARTGAME = 2;
76 var SOUND_FINALEINTRO = 3;
77 var SOUND_LEVEL_WON = 4;
78 var SOUND_VICTORY = 5;
79
80
81 var LOCKED_LEVELCARD_STYLE = "setLevel_lockedLevel";
82 var SHOWCARD_STYLE = "flip_to_visible";
83 var GAMES_PER_LEVEL = 3;
84 var LOCAL_STORAGE_KEY = "memorygame_locked_levels";
85
86
87 (function () {
88     var cardsArray = new Array();
89     var levelSelectionUserChoice = -1;
90     var ignoreInputs = false;
91     var firstFlippedCard = undefined;
92     var clickedCardElement = undefined;
93     var levelNumber = -1;
94     var passedGames = 0;
95     var lastPlayedFlipSound = SOUND_FLIPCARD2;
96     var levelLockingStatus = [ false, true, true, true ];
97
98     // Set memberfunctions.
99     Game.flipCallback = flipCallback;
100     Game.flipDelayCallback = flipDelayCallback;
101     Game.gotoNextGame = gotoNextGame;
102     Game.levelSelectionAnimCallback = levelSelectionAnimCallback;
103     Game.introViewSkipCallback = introViewSkipCallback;
104
105     /**
106      * Create sound element base on their ID
107      */
108     function createSoundElement(soundId) {
109         var audioElement = document.createElement('audio');
110         audioElement.setAttribute("id", audioItems[soundId]);
111         audioElement.setAttribute("src", audioSrc[soundId]);
112         if (soundId == SOUND_STARTGAME) {
113             audioElement.setAttribute("preload", "auto");
114             audioElement.setAttribute("autoplay", "autoplay");
115         } else {
116             audioElement.setAttribute("preload", "none");
117         }
118         document.body.appendChild(audioElement);
119     }
120
121     /**
122      * Plays sounds base on their ID
123      */
124     function playSound(soundId) {
125         var audioElement = document.getElementById(audioItems[soundId]);
126         audioElement.pause();
127         audioElement.play();
128     }
129
130     /**
131      * This function prepares the graphical elements of Victory-screen.
132      */
133     function prepareVictoryScreen() {
134         // Draw the curved YOU WIN text.
135         var drawer = new CurvedTextDrawer(document.getElementById("curvedText"));
136         var centerPos = drawer.getCanvasCenterPos();
137         centerPos.mY = -625;
138         drawer.useFont = '70px Romantiques';
139         drawer.drawSectorArc("YOU WIN", centerPos.mX, centerPos.mY, 780, 180, 270, 'ccw', true, 'center');
140
141         $("#homebutton_backtomain").hide();
142     }
143
144     /**
145      * Reads the level lock status from local storage and sets the card element styles
146      * accordingly.
147      */
148     function prepareSelectLevelScreen() {
149         console.log("--> prepareSelectLevelScreen()");
150         var lockedLevels = localStorage.getItem(LOCAL_STORAGE_KEY);
151         for (var i=1; i < levelLockingStatus.length; ++i) {
152             if (lockedLevels != undefined && lockedLevels != null && lockedLevels.length > i) {
153                 console.log("    read data: " + lockedLevels);
154                 if (lockedLevels[i] == '0') {
155                     levelLockingStatus[i] = false;
156                 } else {
157                     levelLockingStatus[i] = true;
158                 }
159             } else {
160                 levelLockingStatus[i] = true;
161             }
162             var cardElement = $("#selLevel_levelCard"+(i+1));
163             cardElement.removeClass(LOCKED_LEVELCARD_STYLE);
164             if (levelLockingStatus[i]) {
165                 cardElement.addClass(LOCKED_LEVELCARD_STYLE);
166             }
167         }
168         console.log("<-- prepareSelectLevelScreen()");
169     }
170
171     /**
172      * Saves the level lock status to local storage.
173      */
174     function saveStatus() {
175         console.log("--> saveStatus()");
176         var lockedLevelsStr = '0';
177         for (var i = 1; i < levelLockingStatus.length; ++i) {
178             if (levelLockingStatus[i]) {
179                 console.log("    level: " + i + ", lock: locked");
180                 lockedLevelsStr += '1';
181             } else {
182                 console.log("    level: " + i + ", lock: unlocked");
183                 lockedLevelsStr += '0';
184             }
185         }
186         console.log("    data: " + lockedLevelsStr);
187         localStorage.setItem(LOCAL_STORAGE_KEY, lockedLevelsStr);
188         console.log("<-- saveStatus()");
189     }
190
191
192     /**
193      * Returns the card object of the card whose DIV element has given ID.
194      * @param   cardDivName     Name of the cards div element.
195      * @return  The matching Card object or undefined if card was not found.
196      */
197     function getCardObject(cardDivName) {
198         for (var i=0; i < cardsArray.length; ++i) {
199             var card = cardsArray[i];
200             if (card.cardId == cardDivName) {
201                 return card;
202             }
203         }
204         return undefined;
205     }
206
207     /**
208      * Marks the cards as found ones and changes the graphics.
209      * @param   card1           First one of the found cards.
210      * @param   card2           Second one of the found cards.
211      */
212     function matchFound(card1, card2) {
213         card1.found = true;
214         card2.found = true;
215
216         // Change the graphics to glowing ones.
217         var gfxIndex = card1.cardType;
218         $(card1.cardId).children(".back").css("visibility", "hidden");
219         $(card2.cardId).children(".back").css("visibility", "hidden");
220         $(card1.cardFrontId).css("background", "url("+glowingCardImages[gfxIndex]+")");
221         $(card2.cardFrontId).css("background", "url("+glowingCardImages[gfxIndex]+")");
222     }
223
224     /**
225      * Checks the states of the cards and tells if all the pairs have been found.
226      * @return  true if all the pairs have been found.
227      */
228     function allPairsFound() {
229         for (var i=0; i < cardsArray.length; ++i) {
230             var card = cardsArray[i];
231             if (card.found == false) {
232                 return false;
233             }
234         }
235         return true;
236     }
237
238
239     /**
240      * A callback function that gets called when card rotation animation ends. This
241      * function checks if two rotated cards are pairs.
242      */
243     function flipCallback() {
244         console.log("--> Game.flipCallback()");
245         if (firstFlippedCard == undefined) {
246             // This is the first card being turned.
247             firstFlippedCard = clickedCardElement;
248             clickedCardElement = undefined;
249             ignoreInputs = false;
250
251         } else {
252             // This is the second card being turned. Check if they are equal.
253             var cardObj1 = getCardObject("#" + firstFlippedCard.attr("id"));
254             var cardObj2 = getCardObject("#" + clickedCardElement.attr("id"));
255             if (cardObj1.cardType == cardObj2.cardType) {
256                 matchFound(cardObj1, cardObj2);
257                 if (allPairsFound()) {
258                     gotoNextGame();
259                 }
260                 ignoreInputs = false;
261                 firstFlippedCard = undefined;
262                 clickedCardElement = undefined;
263
264             } else {
265                 console.log("    no match");
266                 window.setTimeout("Game.flipDelayCallback()", 300);
267             }
268         }
269         console.log("<-- Game.flipCallback()");
270     }
271
272     /**
273      * Callbackfunction that rotates the two latest cards upside down again.
274      */
275     function flipDelayCallback() {
276         ignoreInputs = false;
277         firstFlippedCard.removeClass(SHOWCARD_STYLE);
278         clickedCardElement.removeClass(SHOWCARD_STYLE);
279         firstFlippedCard = undefined;
280         clickedCardElement = undefined;
281     }
282
283     /**
284      * Shuffles the cards in the beginning of the game.
285      * @param   cardsArray      Array that contains the card objects.
286      */
287     function shuffleLevel(cardsArray) {
288         console.log("--> shuffleLevel1()");
289         // Make an array that contains 2 copies of card type ids.
290         var typeIndexArray = new Array();
291         for (var i=0; i < cardsArray.length; ++i) {
292             typeIndexArray.push( (Math.floor(i / 2)) % normalCardImages.length );
293         }
294         for (var i=0; i < typeIndexArray.length; ++i) {
295             var swapWithIndex = Math.floor(Math.random() * 11);
296             var tmpValue = typeIndexArray[swapWithIndex];
297             typeIndexArray[swapWithIndex] = typeIndexArray[i];
298             typeIndexArray[i] = tmpValue;
299         }
300         var elemIndex = 0;
301         for (var i=0; i < cardsArray.length; ++i) {
302             var gfxIndex = typeIndexArray.pop();
303             var card = cardsArray[i];
304             card.cardType = gfxIndex;
305             console.log("elementId: " + card.cardFrontId + ",    graphics: " + normalCardImages[gfxIndex]);
306             $(card.cardFrontId).css("background", "url("+normalCardImages[gfxIndex]+")");
307             $(card.cardId).removeClass(SHOWCARD_STYLE);
308         }
309         console.log("<-- shuffleLevel1()");
310     }
311
312     /**
313      * This should be called when game has been played through. It does the actions that are
314      * needed to handle game and level progress and also showing victory screen.
315      */
316     function gotoNextGame() {
317         console.log("--> gotoNextGame()");
318         if (levelNumber == 4) {
319             levelLockingStatus[0] = false;
320             levelLockingStatus[1] = false;
321             levelLockingStatus[2] = false;
322             levelLockingStatus[3] = false;
323             saveStatus();
324             // Currently finished level was 4. It means that player has finished the game.
325             prepareVictoryScreen();
326             createSoundElement(SOUND_VICTORY);
327             playSound(SOUND_VICTORY);
328             $("#level4").hide();
329             $("#victory").show();
330             return;
331         }
332         passedGames++;
333         var levelOfNextGame = levelNumber;
334         if (passedGames >= GAMES_PER_LEVEL) {
335             // Move to next level.
336             passedGames = 0;
337             levelOfNextGame++;
338
339             // Next level unlocked.
340             levelLockingStatus[levelNumber] = false;
341             if (levelOfNextGame != 4) {
342                 playSound(SOUND_LEVEL_WON);
343             }
344         }
345         if (levelOfNextGame == 4) {
346             // Show intro view before entring the final level.
347             levelLockingStatus[3] = false;
348             createSoundElement(SOUND_FINALEINTRO);
349             playSound(SOUND_FINALEINTRO);
350             $("#homebutton_backtomain").hide();
351             $("#handitem").hide();
352             $("#level3").hide();
353             $("#finaleIntro").show();
354         } else {
355             startGame(levelOfNextGame, false);
356         }
357         saveStatus();
358         console.log("<-- gotoNextGame()");
359     }
360
361     /**
362      * A callback function that gets called when level selection animation has ended.
363      */
364     function levelSelectionAnimCallback() {
365         console.log("--> levelSelectionAnimCallback()");
366         $("#selLevel_page").hide();
367         $("#selLevel_levelCard1").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
368         $("#selLevel_levelCard2").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
369         $("#selLevel_levelCard3").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
370         $("#selLevel_levelCard4").removeClass("selLevel_selectedCard selLevel_anim1 selLevel_anim2 selLevel_anim3 selLevel_anim4");
371         startGame(levelSelectionUserChoice, true);
372         playSound(SOUND_LEVEL_WON);
373         console.log("<-- levelSelectionAnimCallback()");
374     }
375
376     /**
377      * Initializes the structures to start new game.
378      * @param   levelNum        The level that will be started.
379      * @param   resteState      Pass true to reset the game counts to 0.
380      */
381     function startGame(levelNum, resetState) {
382         console.log("--> startGame()");
383         if (resetState) {
384             passGames = 0;
385         }
386
387         // Figure out the amount of cards needed in this level.
388         var cardBgGraphics = "url(images/card_purple.png)"
389         cardsArray = new Array();
390         levelNumber = levelNum;
391         var numOfCards = 12;
392         if (levelNum == 2) {
393             numOfCards = 18;
394             cardBgGraphics = "url(images/card_green.png)"
395         } else if (levelNum == 3) {
396             numOfCards = 24;
397             cardBgGraphics = "url(images/card_red.png)"
398         } else if (levelNum == 4) {
399             numOfCards = 24;
400             cardBgGraphics = "url(images/card_teal.png)"
401         }
402         // Create card objects.
403         for (var i=0; i < numOfCards; ++i) {
404             var card = new Card();
405             card.cardFrontId = "#level"+levelNum+"_card_"+(i+1)+"_front";
406             card.cardId = "#" + $(card.cardFrontId).parent().attr("id");
407             cardsArray.push(card);
408
409             // Manually set toggle the card backgrounds between invisible
410             // background and real card background. We can't use plain css
411             // because the backface-visibility during rotation does not
412             // work in linux Chrome as it should.
413             $(card.cardId).children(".back").css("visibility", "visible");
414         }
415         setTimeout(function() {shuffleLevel(cardsArray);}, 300);
416         $(".card").removeClass(SHOWCARD_STYLE);
417         firstFlippedCard = undefined;
418         clickedCardElement = undefined;
419
420
421         // Update the hand that holds the game count note.
422         var starIconName = stariconsList[levelNum-1];
423         for (var gameIndex = 0; gameIndex < 3; ++gameIndex) {
424             var starImgElement = $("#handleitem_star"+(gameIndex+1));
425             starImgElement.removeClass("unplayedGameStar");
426             if (gameIndex <= passedGames) {
427                 starImgElement.attr("src", starIconName);
428
429             } else {
430                 starImgElement.addClass("unplayedGameStar");
431                 starImgElement.attr("src", "images/star.png");
432             }
433         }
434         if (levelNum != 4) {
435             $("#handitem").css("display", "block");
436         } else {
437             // The hand image is not shown in final level.
438             $("#handitem").hide();
439         }
440
441         // Control the level elements visibility.
442         for (var i=1; i < 5; ++i) {
443             if (i == levelNum) {
444                 $("#level"+i).show();
445             } else {
446                 $("#level"+i).hide();
447             }
448         }
449         if (passedGames == 0) {
450             $("#handitem_gamenum_title").text("GAME 1");
451         } else if (passedGames == 1) {
452             $("#handitem_gamenum_title").text("GAME 2");
453         } else if (passedGames == 2) {
454             $("#handitem_gamenum_title").text("GAME 3");
455         }
456
457         $("#homebutton_backtomain").show();
458         console.log("<-- startGame()");
459     }
460
461     function introViewSkipCallback() {
462         prepareSelectLevelScreen();
463         if ($("#main_page").is(":visible")) {
464             $("#main_page").hide();
465             $("#selLevel_page").show();
466         }
467         license_init("license", "pagebg");
468         help_init("main_help", "help_");
469         createSoundElement(SOUND_FLIPCARD1);
470         createSoundElement(SOUND_FLIPCARD2);
471         createSoundElement(SOUND_LEVEL_WON);
472     }
473
474     // Initialize game once everything has been loaded.
475     $(document).ready(function () {
476         console.log("--> document.ready()");
477
478         createSoundElement(SOUND_STARTGAME);
479
480         // Add the event handler functions.
481         $("#main_page").click(function () {
482             // Hide mainview and show level selection.
483             introViewSkipCallback();
484         });
485
486         $("#selLevel_levelCard1").click(function () {
487             // Start game.
488             levelSelectionUserChoice = 1;
489             playSound(SOUND_FLIPCARD2);
490             $("#selLevel_levelCard1").addClass("selLevel_selectedCard");
491             $("#selLevel_levelCard2").addClass("selLevel_anim1");
492             $("#selLevel_levelCard3").addClass("selLevel_anim1");
493             $("#selLevel_levelCard4").addClass("selLevel_anim1");
494             window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
495         });
496         $("#selLevel_levelCard2").click(function() {
497             if ($(this).hasClass(LOCKED_LEVELCARD_STYLE) == false) {
498                 playSound(SOUND_FLIPCARD2);
499                 levelSelectionUserChoice = 2;
500                 $("#selLevel_levelCard2").addClass("selLevel_selectedCard");
501                 $("#selLevel_levelCard1").addClass("selLevel_anim2");
502                 $("#selLevel_levelCard3").addClass("selLevel_anim2");
503                 $("#selLevel_levelCard4").addClass("selLevel_anim2");
504                 window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
505             }
506         });
507         $("#selLevel_levelCard3").click(function() {
508             if ($(this).hasClass(LOCKED_LEVELCARD_STYLE) == false) {
509                 playSound(SOUND_FLIPCARD2);
510                 levelSelectionUserChoice = 3;
511                 $("#selLevel_levelCard3").addClass("selLevel_selectedCard");
512                 $("#selLevel_levelCard1").addClass("selLevel_anim3");
513                 $("#selLevel_levelCard2").addClass("selLevel_anim3");
514                 $("#selLevel_levelCard4").addClass("selLevel_anim3");
515                 window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
516             }
517         });
518         $("#selLevel_levelCard4").click(function() {
519             if ($(this).hasClass(LOCKED_LEVELCARD_STYLE) == false) {
520                 playSound(SOUND_FLIPCARD2);
521                 levelSelectionUserChoice = 4;
522                 $("#selLevel_levelCard4").addClass("selLevel_selectedCard");
523                 $("#selLevel_levelCard1").addClass("selLevel_anim4");
524                 $("#selLevel_levelCard2").addClass("selLevel_anim4");
525                 $("#selLevel_levelCard3").addClass("selLevel_anim4");
526                 window.setTimeout("Game.levelSelectionAnimCallback()", 1000);
527             }
528         });
529
530         $(".card").click(function() {
531             console.log("--> card.click()");
532             if (!ignoreInputs && !($(this).hasClass(SHOWCARD_STYLE))) {
533                 // We have to use 2 different audio items for flip sound because
534                 // audio API doesn't replay the sound if it is already playing.
535                 if (lastPlayedFlipSound == SOUND_FLIPCARD1) {
536                     lastPlayedFlipSound = SOUND_FLIPCARD2;
537                 } else {
538                     lastPlayedFlipSound = SOUND_FLIPCARD1;
539                 }
540                 createSoundElement(SOUND_FLIPCARD1);
541                 playSound(lastPlayedFlipSound);
542                 clickedCardElement = $(this);
543                 ignoreInputs = true;
544                 console.log("    card id: " + $(this).attr("id"));
545                 $(this).addClass(SHOWCARD_STYLE);
546                 window.setTimeout("Game.flipCallback()", 350);
547             }
548             console.log("<-- card.click()");
549         });
550
551         $("#finaleIntro").click( function() {
552             // Start playing final level.
553             $("#finaleIntro").hide();
554             startGame(4, false);
555         });
556
557         $("#victory_playagain_box").click(function() {
558             console.log("--> victory_playagain_box.click()");
559             prepareSelectLevelScreen();
560             $("#victory").hide();
561             $("#selLevel_page").show();
562             console.log("<-- victory_playagain_box.click()");
563         });
564
565         $("#homebutton_backtomain").click(function() {
566             console.log("--> homebutton.click()");
567             // Hide current levels and show mainpage.
568             $("#level1").hide();
569             $("#level2").hide();
570             $("#level3").hide();
571             $("#level4").hide();
572             $("#handitem").hide();
573             $("#main_page").show();
574             $(this).hide();
575             console.log("<-- homebutton.click()");
576         });
577
578         $("#selLevel_resetLocked").click(function() {
579             localStorage.setItem(LOCAL_STORAGE_KEY, '0000');
580             prepareSelectLevelScreen();
581         });
582     });
583
584     // Skip the welcome screen after a while.
585     window.setTimeout("Game.introViewSkipCallback()", 3500);
586 })();