File indexing completed on 2024-05-05 15:53:17
0001 /* GCompris - path.js 0002 * 0003 * SPDX-FileCopyrightText: 2021 Harsh Kumar <hadron43@yahoo.com> 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 * 0006 */ 0007 .pragma library 0008 .import QtQuick 2.12 as Quick 0009 .import "qrc:/gcompris/src/core/core.js" as Core 0010 0011 var numberOfLevel 0012 var items 0013 0014 var currPos = [-1, -1] 0015 var prevPos = [-1, -1] 0016 var map 0017 var decodeIndex 0018 0019 var successSoundPath = 'qrc:/gcompris/src/core/resource/sounds/completetask.wav' 0020 var errorSoundPath = 'qrc:/gcompris/src/core/resource/sounds/crash.wav' 0021 0022 var Directions = { 0023 UP: 'UP', 0024 RIGHT: 'RIGHT', 0025 DOWN: 'DOWN', 0026 LEFT: 'LEFT' 0027 } 0028 0029 var mapModel = { 0030 "path": false, 0031 "flag": false, 0032 "invisible": false, 0033 "rock": false, 0034 "tree": false, 0035 "bush": false, 0036 "grass": false, 0037 "water": false 0038 } 0039 0040 function start(items_) { 0041 items = items_ 0042 numberOfLevel = items.levels.length 0043 items.currentLevel = Core.getInitialLevel(numberOfLevel) 0044 initLevel() 0045 } 0046 0047 function stop() { 0048 } 0049 0050 function initLevel() { 0051 0052 items.rows = items.levels[items.currentLevel].path.length 0053 items.cols = items.levels[items.currentLevel].path[0].length 0054 0055 items.mapListModel.clear() 0056 items.movesListModel.clear() 0057 0058 for(var i=0; i < items.rows * items.cols; ++i) 0059 items.mapListModel.append(mapModel) 0060 0061 map = items.levels[items.currentLevel].path 0062 0063 // reset initial position 0064 prevPos = [-1, -1]; 0065 // intialize position of tux 0066 currPos = findStartAndLoadObstacles() 0067 0068 // find the initial direciton of tux 0069 items.tux.init(findCorrectDirectionAbsolute(currPos[0], currPos[1], -1, -1)) 0070 0071 // reset mapView 0072 items.mapView.init() 0073 0074 // reset the error counter 0075 items.errorsCount = 0 0076 0077 // load the moves if in decode mode 0078 if(items.mode === 'decode') { 0079 loadMoves() 0080 decodeIndex = 0 0081 items.movesListModel.set(0, {"active": true}) 0082 } 0083 0084 items.movesGridView.currentIndex = 0 0085 } 0086 0087 function loadMoves() { 0088 var pos = currPos.slice() 0089 prevPos = [-1, -1] 0090 var direction = items.tux.direction 0091 0092 while(map[pos[1]][pos[0]].toUpperCase() !== 'E') { 0093 var nextDirectionAbsolute = findCorrectDirectionAbsolute(pos[0], pos[1], prevPos[0], prevPos[1]) 0094 var nextDirectionRelative = absoluteDirectionToRelative(nextDirectionAbsolute, direction) 0095 0096 items.movesListModel.append({ 0097 "direction" : (items.movement === 'absolute' ? nextDirectionAbsolute : nextDirectionRelative), 0098 "faded" : false, 0099 "active" : false 0100 }) 0101 0102 prevPos = pos 0103 pos = findNextPositionAbsolute(pos[0], pos[1], nextDirectionAbsolute) 0104 direction = nextDirectionAbsolute 0105 } 0106 0107 prevPos = [-1, -1] 0108 } 0109 0110 function absoluteDirectionToRelative(absoluteDirection, currentDirection) { 0111 var directions = [Directions.DOWN, Directions.LEFT, Directions.UP, Directions.RIGHT] 0112 0113 var diff = directions.indexOf(absoluteDirection) - directions.indexOf(currentDirection) 0114 0115 if(diff === -1 || diff === 3) 0116 return Directions.LEFT 0117 else if(diff === 1 || diff === -3) 0118 return Directions.RIGHT 0119 else if(diff === 0) 0120 return Directions.UP 0121 else 0122 return Directions.DOWN 0123 } 0124 0125 function findCorrectDirectionAbsolute(fromX, fromY, prevX, prevY) { 0126 if(isValidPos([fromX, fromY + 1]) && !(fromX === prevX && fromY + 1 === prevY)) 0127 return Directions.DOWN 0128 else if(isValidPos([fromX + 1, fromY]) && !(fromX + 1 === prevX && fromY === prevY)) 0129 return Directions.RIGHT 0130 else if(isValidPos([fromX - 1, fromY]) && !(fromX - 1 === prevX && fromY === prevY)) 0131 return Directions.LEFT 0132 else if(isValidPos([fromX, fromY - 1]) && !(fromX === prevX && fromY - 1 === prevY)) 0133 return Directions.UP 0134 return null 0135 } 0136 0137 function findStartAndLoadObstacles() { 0138 var start = [-1, -1] 0139 for(var i=0; i < map.length; ++i) { 0140 for(var j=0; j < map[i].length; ++j) { 0141 var c = map[i][j].toUpperCase() 0142 var index = positionToIndex([j, i]) 0143 0144 if(items.mode === 'encode' && ['*', 'E'].indexOf(c) != -1 ) 0145 items.mapListModel.set(index, {"path": true}) 0146 0147 if(c === 'S') { 0148 items.mapListModel.set(index, {"path": true}) 0149 start = [j, i]; 0150 } 0151 else if(c === 'E') 0152 items.mapListModel.set(index, {"flag": true}) 0153 else if(c === 'I') 0154 items.mapListModel.set(index, {"invisible": true}) 0155 else if(c === 'R') 0156 items.mapListModel.set(index, {"rock": true}) 0157 else if(c === 'T') 0158 items.mapListModel.set(index, {"tree": true}) 0159 else if(c === 'B') 0160 items.mapListModel.set(index, {"bush": true}) 0161 else if(c === 'G') 0162 items.mapListModel.set(index, {"grass": true}) 0163 else if(c === 'W') 0164 items.mapListModel.set(index, {"water": true}) 0165 } 0166 } 0167 return start 0168 } 0169 0170 function isValidPos(pos) { 0171 if(prevPos[0] === pos[0] && prevPos[1] === pos[1]) 0172 return false; 0173 0174 if(pos[1] >= map.length || pos[1] < 0 || pos[0] >= map[0].length || pos[0] < 0) 0175 return false; 0176 0177 return map[pos[1]][pos[0]] === '*' || map[pos[1]][pos[0]].toUpperCase() === 'S' || map[pos[1]][pos[0]].toUpperCase() === 'E'; 0178 } 0179 0180 function positionToIndex(posArray) { 0181 return posArray[1] * items.cols + posArray[0]; 0182 } 0183 0184 function indexToPosition(index) { 0185 return [index % items.cols, Math.floor(index / items.rows)] 0186 } 0187 0188 function moveTuxToBlock() { 0189 items.tux.x = items.mapView.x + currPos[0] * items.mapView.cellSize 0190 items.tux.y = items.mapView.y + currPos[1] * items.mapView.cellSize 0191 } 0192 0193 function updateTux() { 0194 moveTuxToBlock() 0195 0196 items.audioEffects.play(successSoundPath) 0197 0198 if(map[currPos[1]][currPos[0]].toUpperCase() === 'E') 0199 items.bonus.good ("tux") 0200 } 0201 0202 function findNextPositionAbsolute(fromX, fromY, direction) { 0203 // find direction change in case of absolute movement 0204 if(direction === Directions.DOWN) 0205 return [fromX, fromY + 1] 0206 else if(direction === Directions.UP) 0207 return [fromX, fromY - 1] 0208 else if(direction === Directions.RIGHT) 0209 return [fromX + 1, fromY] 0210 else if(direction === Directions.LEFT) 0211 return [fromX - 1, fromY] 0212 return [-1, -1] 0213 } 0214 0215 function findNextDirectionRelative(fromX, fromY, direction) { 0216 // find direction change in case of relative movement 0217 var directions = [Directions.DOWN, Directions.LEFT, Directions.UP, Directions.RIGHT] 0218 var keyboardDirections = [Directions.UP, Directions.RIGHT, Directions.DOWN, Directions.LEFT] 0219 var newRelativeCardinalDirection = items.tux.rotation + keyboardDirections.indexOf(direction) * 90 0220 0221 if(newRelativeCardinalDirection < 0) 0222 newRelativeCardinalDirection += 360 0223 0224 newRelativeCardinalDirection = newRelativeCardinalDirection % 360 0225 0226 return directions[newRelativeCardinalDirection / 90] 0227 } 0228 0229 function findNextPositionRelative(fromX, fromY, direction) { 0230 var absoluteDirection = findNextDirectionRelative(fromX, fromY, direction) 0231 return findNextPositionAbsolute(fromX, fromY, absoluteDirection) 0232 } 0233 0234 function moveTowards(direction) { 0235 if(items.tux.isAnimationRunning || items.bonus.isPlaying) 0236 return 0237 0238 var absolutePosition = findNextPositionAbsolute(currPos[0], currPos[1], direction) 0239 0240 var relativeDirection = findNextDirectionRelative(currPos[0], currPos[1], direction) 0241 var relativePosition = findNextPositionRelative(currPos[0], currPos[1], direction) 0242 0243 if((items.movement === 'absolute' && isValidPos(absolutePosition)) || 0244 (items.movement === 'relative' && isValidPos(relativePosition))) { 0245 0246 if(items.mode === 'encode') { 0247 items.movesListModel.append({ 0248 "direction" : direction, 0249 "active" : false, 0250 "faded" : false 0251 }) 0252 0253 items.movesGridView.currentIndex = items.movesListModel.count - 1 0254 } 0255 0256 prevPos = currPos 0257 0258 if(items.movement === 'absolute') { 0259 currPos = absolutePosition 0260 items.tux.direction = direction 0261 } 0262 else { 0263 currPos = relativePosition 0264 items.tux.direction = relativeDirection 0265 } 0266 0267 updateTux() 0268 } 0269 else { 0270 items.audioEffects.play(errorSoundPath) 0271 items.errorsCount ++ 0272 } 0273 } 0274 0275 function processBlockClick(pos) { 0276 if(decodeIndex >= items.movesListModel.count || items.bonus.isPlaying) 0277 return 0278 0279 var correctPos 0280 if(items.movement === 'absolute') 0281 correctPos = findNextPositionAbsolute(currPos[0], currPos[1], items.movesListModel.get(decodeIndex).direction) 0282 else 0283 correctPos = findNextPositionRelative(currPos[0], currPos[1], items.movesListModel.get(decodeIndex).direction) 0284 0285 if(correctPos[0] === pos[0] && correctPos[1] === pos[1]) { 0286 moveTowards(items.movesListModel.get(decodeIndex).direction) 0287 0288 items.movesListModel.set(decodeIndex, {"active" : false, "faded" : true}) 0289 decodeIndex++ 0290 if(decodeIndex < items.movesListModel.count) { 0291 items.movesListModel.set(decodeIndex, {"active" : true}) 0292 items.movesGridView.currentIndex = decodeIndex 0293 } 0294 0295 items.mapListModel.set(positionToIndex(currPos), {"path": true}) 0296 } 0297 else { 0298 items.audioEffects.play(errorSoundPath) 0299 items.errorsCount ++ 0300 } 0301 } 0302 0303 function nextLevel() { 0304 items.currentLevel = Core.getNextLevel(items.currentLevel, numberOfLevel); 0305 initLevel(); 0306 } 0307 0308 function previousLevel() { 0309 items.currentLevel = Core.getPreviousLevel(items.currentLevel, numberOfLevel); 0310 initLevel(); 0311 }