File indexing completed on 2024-04-28 15:07:48

0001 /* GCompris - crane.js
0002  *
0003  * SPDX-FileCopyrightText: 2016 Stefan Toncu <stefan.toncu29@gmail.com>
0004  *
0005  * Authors:
0006  *   <Marc BRUN> (GTK+ version)
0007  *   Stefan Toncu <stefan.toncu29@gmail.com> (Qt Quick port)
0008  *
0009  *   SPDX-License-Identifier: GPL-3.0-or-later
0010  */
0011 .pragma library
0012 .import QtQuick 2.12 as Quick
0013 .import "qrc:/gcompris/src/core/core.js" as Core
0014 .import GCompris 1.0 as GCompris
0015 
0016 var numberLevelsWords = 2
0017 var numberOfLevel
0018 var words3Letters = []
0019 var words4Letters = []
0020 var words5Letters = []
0021 var items
0022 var url = "qrc:/gcompris/src/activities/crane/resource/"
0023 var currentLocale
0024 var names = []
0025 var names2 = []
0026 var good = []
0027 var levels
0028 
0029 function start(items_) {
0030     items = items_
0031     levels = items.levels
0032     numberOfLevel = levels.length
0033     items.currentLevel = Core.getInitialLevel(numberOfLevel)
0034     currentLocale = GCompris.ApplicationInfo.getVoicesLocale(GCompris.ApplicationSettings.locale)
0035 
0036     /*: Translators: NOTE: Word list for crane activity.
0037         Translate this into a list of 15–25 simple 3-letter
0038         words separated by semi-colons. The words can only contain
0039         lowercase ASCII letters (a–z). Example: cat;dog;win;red;yes
0040     */
0041     words3Letters = qsTr("cat;dog;win;red;yes;big;box;air;arm;car;bus;fun;day;eat;hat;leg;ice;old;egg").split(';')
0042 
0043     /*: Translators: NOTE: Word list for crane activity.
0044         Translate this into a list of 10–20 simple 4-letter
0045         words separated by semi-colons. The words can only contain
0046         lowercase ASCII letters (a–z). Example: blue;best;good;area
0047     */
0048     words4Letters = qsTr("blue;best;good;area;bell;coat;easy;farm;food;else;girl;give;hero;help;hour;sand;song").split(';')
0049 
0050     /*: Translators: NOTE: Word list for crane activity.
0051         Translate this into a list of 10–20 simple 5-letter
0052         words separated by semi-colons. The words can only contain
0053         lowercase ASCII letters (a–z). Example: happy;child;white;apple
0054     */
0055     words5Letters = qsTr("happy;child;white;apple;brown;truth;fresh;green;horse;hotel;house;paper;shape;shirt;study").split(';')
0056 
0057     Core.shuffle(words3Letters)
0058     Core.shuffle(words4Letters)
0059     Core.shuffle(words5Letters)
0060     initLevel()
0061 }
0062 
0063 function stop() {
0064 }
0065 
0066 function initLevel() {
0067     items.score.numberOfSubLevels = levels[items.currentLevel].length
0068     items.score.currentSubLevel = 0
0069     initSubLevel()
0070 }
0071 
0072 function initSubLevel() {
0073     // reset the arrays
0074     names = []
0075     names2 = []
0076 
0077     // set models for repeaters
0078     if (!levels[items.currentLevel][items.score.currentSubLevel].isWord)
0079         setModelImage()
0080     else
0081         setModelWord()
0082 
0083     // set "initialIndex" to the position in the repeater
0084     for(var i = 0; i < names.length; i++) {
0085         if (items.answerRepeater.itemAt(i).source != "") {
0086             items.answerRepeater.itemAt(i).initialIndex = i
0087             good[i] = i
0088         }
0089         else {
0090             // set the initialIndex to -1 if there is no item inside (no source)
0091             items.answerRepeater.itemAt(i).initialIndex = -1
0092             good[i] = -1
0093         }
0094     }
0095 
0096     // select the first item in the grid
0097     for(i = 0; i < items.answerRepeater.count; i++) {
0098         if (items.answerRepeater.itemAt(i).source != "") {
0099             items.selected = i
0100             items.selector.state = "initialized"
0101             break
0102         }
0103     }
0104     items.buttonsBlocked = false;
0105 }
0106 
0107 function getInternalWord() {
0108     // function to get a word from translated lists
0109     var currentWordLength = levels[items.currentLevel][items.score.currentSubLevel].wordLength
0110     var wordsUsed
0111     if (currentWordLength === 3) {
0112         wordsUsed = words3Letters
0113     }
0114     else if (currentWordLength === 4) {
0115         wordsUsed = words4Letters
0116     }
0117     else if (currentWordLength === 5) {
0118         wordsUsed = words5Letters
0119     }
0120     // choosing first word of a list and pushing it to the end of the list like a queue.
0121     var word = wordsUsed[0]
0122     wordsUsed.shift()
0123     wordsUsed.push(word)
0124     return word
0125 }
0126 
0127 // levels with words as items
0128 function setModelWord() {
0129     var numbers = []
0130     var i
0131     var wordsUsed
0132     var word = levels[items.currentLevel][items.score.currentSubLevel].word
0133 
0134     // show or hide the grid
0135     items.showGrid1.opacity = levels[items.currentLevel][items.score.currentSubLevel].showGrid
0136     // set the two boards in line or not
0137     items.background.inLine = levels[items.currentLevel][items.score.currentSubLevel].inLine
0138 
0139     // set the number of columns and rows, be sure we have enough space to display the word
0140     items.columns = levels[items.currentLevel][items.score.currentSubLevel].columns
0141     items.rows = levels[items.currentLevel][items.score.currentSubLevel].rows;
0142 
0143     for (i = 0; i < items.columns * items.rows; i++) {
0144         names[i] = ""
0145         names2[i] = ""
0146         numbers[i] = i;  // generate columns*rows numbers
0147     }
0148 
0149     if(word === undefined) {
0150         word = getInternalWord()
0151     }
0152 
0153     // place the word at a random position in the grid
0154     var randomRow = Math.floor(Math.random() * items.rows)
0155     var randomCol = Math.floor(Math.random() * items.columns)
0156 
0157     // check if the word goes out of the frame and replace to left it if needed
0158     if (items.columns - randomCol - word.length < 0)
0159         randomCol = randomCol - Math.abs(items.columns - randomCol - word.length)
0160 
0161     // set full path (url) to the letter image
0162     var index = 0;
0163     for (i = 0; i < word.length; i++) {
0164         index = randomRow * items.columns + randomCol + i
0165         names[index] =  url + "letters/" + word.charAt(i) + ".svg"
0166         names2[index] = names[index]
0167     }
0168 
0169     Core.shuffle(names)
0170 
0171     // set model for repeaters
0172     items.answerRepeater.model = names.length
0173     items.modelRepeater.model = names2.length
0174     items.gridRepeater.model = names.length
0175 
0176     // set the source of items inside repeaters to names and names2
0177     for (i = 0; i < names.length; i++) {
0178         items.answerRepeater.itemAt(i).source = names[i]
0179         items.modelRepeater.itemAt(i).source = names2[i]
0180     }
0181 }
0182 
0183 // levels with images as items
0184 function setModelImage() {
0185     var numbers = []
0186     var i
0187     var imageList = levels[items.currentLevel][items.score.currentSubLevel].images;
0188 
0189     // set the number of columns and rows from "levels"
0190     items.columns = levels[items.currentLevel][items.score.currentSubLevel].columns
0191     items.rows = levels[items.currentLevel][items.score.currentSubLevel].rows
0192 
0193     for (i = 0; i < items.columns * items.rows; i++) {
0194         names[i] = ""
0195         names2[i] = ""
0196         numbers[i] = i;  // generate columns*rows numbers
0197     }
0198 
0199     // randomize the names
0200     Core.shuffle(imageList)
0201 
0202     //get "levels[items.currentLevel].noOfItems" random numbers
0203     Core.shuffle(numbers)
0204 
0205     for (i = 0; i < imageList.length; i++)
0206         names[numbers[i]] = imageList[i]
0207 
0208     Core.shuffle(numbers)
0209 
0210     for (i = 0; i < imageList.length; i++)
0211         names2[numbers[i]] = imageList[i]
0212 
0213     // set model for repeaters
0214     items.answerRepeater.model = names.length
0215     items.modelRepeater.model = names2.length
0216     items.gridRepeater.model = names.length
0217 
0218     // set the source of items inside repeaters to names and names2
0219     for (i = 0; i < names.length; i++) {
0220         items.answerRepeater.itemAt(i).source = names[i]
0221         items.modelRepeater.itemAt(i).source = names2[i]
0222     }
0223 
0224     // show or hide the grid
0225     items.showGrid1.opacity = levels[items.currentLevel][items.score.currentSubLevel].showGrid
0226 
0227     // set the two boards in line or not
0228     items.background.inLine = levels[items.currentLevel][items.score.currentSubLevel].inLine
0229 }
0230 
0231 // returns the next index needed for switching to another item
0232 function getNextIndex() {
0233     // get the initialIndex
0234     var index = items.answerRepeater.itemAt(items.selected).initialIndex
0235 
0236     var min = 100
0237     var min2 = 100
0238     var biggerIndex = -1
0239     var smallestIndex = -1
0240 
0241     for (var i = 0; i < items.answerRepeater.count; i++) {
0242         var currentItemIndex = items.answerRepeater.itemAt(i).initialIndex
0243         // get the immediat bigger index
0244         if (index < currentItemIndex) {
0245             if (min > currentItemIndex) {
0246                 // update min and index
0247                 min = currentItemIndex
0248                 biggerIndex = i
0249             }
0250         }
0251         // in case current index is the biggest, search the smallest index from start
0252         if (currentItemIndex >= 0 && min2 > currentItemIndex) {
0253             min2 = currentItemIndex
0254             smallestIndex = i
0255         }
0256     }
0257 
0258     // if a bigger index was found, return it
0259     if (biggerIndex != -1)
0260         return biggerIndex
0261 
0262     // this is the biggest index; the next one is the smallest in the array
0263     return smallestIndex
0264 }
0265 
0266 //touchscreen gestures
0267 function gesture(deltax, deltay) {
0268     if (Math.abs(deltax) > 40 || Math.abs(deltay) > 40)
0269         if (deltax > 30 && Math.abs(deltay) < items.sensivity)
0270             move("right")
0271         else if (deltax < -30 && Math.abs(deltay) < items.sensivity)
0272             move("left")
0273         else if (Math.abs(deltax) < items.sensivity && deltay > 30)
0274             move("down")
0275         else if (Math.abs(deltax) < items.sensivity && deltay < 30)
0276             move("up")
0277 }
0278 
0279 //depending on the command, make a move to left/right/up/down or select next item
0280 function move(command) {
0281     if (items.ok && !items.pieceIsMoving) {
0282         var item = items.answerRepeater.itemAt(items.selected)
0283         if (command === "left") {
0284             if (items.selected % items.columns != 0)
0285                 makeMove(item, -item.width, item.x, -1, "x")
0286         } else if (command === "right") {
0287             if ((items.selected+1) % items.columns != 0)
0288                 makeMove(item, item.width, item.x, 1, "x")
0289         } else if (command === "up") {
0290             if (items.selected > items.columns-1)
0291                 makeMove(item, -item.height, item.y, -items.columns, "y")
0292         } else if (command === "down") {
0293             if (items.selected < (items.answerRepeater.count-items.columns))
0294                 makeMove(item, item.height, item.y, items.columns, "y")
0295         } else if (command === "next") {
0296             items.selected = getNextIndex()
0297         }
0298     }
0299 }
0300 
0301 //set the environment for making a move and start the animation
0302 function makeMove(item, distance, startPoint, add, animationProperty) {
0303     if (items.answerRepeater.itemAt(items.selected+add).source == "") {
0304         items.pieceIsMoving = true
0305         //setup the animation
0306         item.distance = distance
0307         item.indexChange = add
0308         item.startPoint = startPoint
0309         item.animationProperty = animationProperty
0310 
0311         //start the animation
0312         item.anim.start()
0313 
0314         //update the selected item
0315         items.selected += add;
0316     }
0317 }
0318 
0319 //check the answer; advance to next level if the answer is good
0320 function checkAnswer() {
0321     var hasWon = true
0322     for (var i = 0; i < items.answerRepeater.count && hasWon; i++) {
0323         if (items.answerRepeater.itemAt(i).source != items.modelRepeater.itemAt(i).source) {
0324             hasWon = false
0325             return;
0326         }
0327     }
0328     items.buttonsBlocked = true;
0329     items.score.currentSubLevel++;
0330     items.score.playWinAnimation();
0331     items.audioEffects.play("qrc:/gcompris/src/core/resource/sounds/completetask.wav");
0332 }
0333 
0334 function nextLevel() {
0335     items.score.stopWinAnimation();
0336     items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel);
0337     initLevel();
0338 }
0339 
0340 function previousLevel() {
0341     items.score.stopWinAnimation();
0342     items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel);
0343     initLevel();
0344 }
0345 
0346 function nextSubLevel() {
0347     if(items.score.currentSubLevel >= items.score.numberOfSubLevels) {
0348         items.bonus.good("flower")
0349     } else {
0350         initSubLevel();
0351     }
0352 }