squareTwo.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. /******************************
  2. * This file holds game states.
  3. ******************************/
  4. /** [GAME STATE]
  5. *
  6. * .squareTwo. = gameName
  7. * .../...\...
  8. * ..a.....b.. = gameMode
  9. * ....\./....
  10. * .....|.....
  11. * ..equals... = gameOperation
  12. * .....|.....
  13. * .1,2,3,4,5. = gameDifficulty
  14. *
  15. * Character : kid
  16. * Theme : (not themed)
  17. * Concept : player select equivalent dividends for fractions with different divisors
  18. * Represent fractions as : subdivided rectangles
  19. *
  20. * Game modes can be :
  21. *
  22. * a : equivalence of fractions
  23. * top has more subdivisions
  24. * b : equivalence of fractions
  25. * bottom has more subdivisions
  26. *
  27. * Operations :
  28. *
  29. * equals : Player selects equivalent fractions of both blocks
  30. *
  31. * @namespace
  32. */
  33. const squareTwo = {
  34. ui: undefined,
  35. control: undefined,
  36. blocks: undefined,
  37. /**
  38. * Main code
  39. */
  40. create: function () {
  41. this.ui = {
  42. message: undefined,
  43. continue: {
  44. // modal: undefined,
  45. button: undefined,
  46. text: undefined,
  47. },
  48. };
  49. this.control = {
  50. blockWidth: 600,
  51. blockHeight: 75,
  52. isCorrect: false,
  53. showEndInfo: false,
  54. animationDelay: 0,
  55. startDelay: false,
  56. startEndAnimation: false,
  57. };
  58. this.blocks = {
  59. top: {
  60. list: [], // List of block objects
  61. auxBlocks: [], // List of shadow under selection blocks
  62. fractions: [], // Fractions
  63. selectedAmount: 0,
  64. hasClicked: false, // Check if player clicked blocks from (a)
  65. animate: false, // Animate blocks from (a)
  66. warningText: undefined,
  67. label: undefined,
  68. },
  69. bottom: {
  70. list: [],
  71. auxBlocks: [],
  72. fractions: [],
  73. selectedAmount: 0,
  74. hasClicked: false,
  75. animate: false,
  76. warningText: undefined,
  77. label: undefined,
  78. },
  79. };
  80. renderBackground();
  81. // Calls function that loads navigation icons
  82. // FOR MOODLE
  83. if (moodle) {
  84. navigation.add.right(['audio']);
  85. } else {
  86. navigation.add.left(['back', 'menu'], 'customMenu');
  87. navigation.add.right(['audio']);
  88. }
  89. // Add kid
  90. this.utils.renderCharacters();
  91. this.utils.renderBlockSetup();
  92. this.utils.renderMainUI();
  93. game.timer.start(); // Set a timer for the current level (used in postScore)
  94. game.event.add('click', this.events.onInputDown);
  95. game.event.add('mousemove', this.events.onInputOver);
  96. },
  97. /**
  98. * Game loop
  99. */
  100. update: function () {
  101. // Animate blocks
  102. if (self.blocks.top.animate || self.blocks.bottom.animate) {
  103. self.utils.moveBlocks();
  104. }
  105. // If (a) and (b) are already clicked
  106. if (
  107. !self.control.startDelay &&
  108. !self.control.startEndAnimation &&
  109. self.blocks.top.hasClicked &&
  110. self.blocks.bottom.hasClicked
  111. ) {
  112. self.control.startDelay = true;
  113. }
  114. if (self.control.startDelay && !self.control.startEndAnimation) {
  115. self.utils.startDelayHandler();
  116. }
  117. // Wait a bit and go to map state
  118. if (self.control.startEndAnimation) {
  119. self.utils.runEndAnimation();
  120. }
  121. game.render.all();
  122. },
  123. utils: {
  124. // RENDERS
  125. renderBlockSetup: function () {
  126. // Coordinates for (a) and (b)
  127. let xA, xB, yA, yB;
  128. if (gameMode != 'b') {
  129. // Has more subdivisions on (b)
  130. xA = context.canvas.width / 2 - self.control.blockWidth / 2;
  131. yA = getFrameInfo().y + 100;
  132. xB = xA;
  133. yB = yA + 3 * self.control.blockHeight + 30;
  134. } else {
  135. // Has more subdivisions on (a)
  136. xB = context.canvas.width / 2 - self.control.blockWidth / 2;
  137. yB = getFrameInfo().y + 100;
  138. xA = xB;
  139. yA = yB + 3 * self.control.blockHeight + 30;
  140. }
  141. // Possible subdivisionList for (a)
  142. const subdivisionList = [2, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20];
  143. // Random index for 'subdivision'
  144. const randomIndex = game.math.randomInRange(
  145. (gameDifficulty - 1) * 2 + 1,
  146. (gameDifficulty - 1) * 2 + 3
  147. );
  148. // Number of subdivisions of (a) and (b) (blocks)
  149. const totalBlocksA = subdivisionList[randomIndex];
  150. const totalBlocksB = game.math.randomDivisor(totalBlocksA);
  151. const blockWidthA = self.control.blockWidth / totalBlocksA;
  152. const blockWidthB = self.control.blockWidth / totalBlocksB;
  153. if (isDebugMode) {
  154. console.log(
  155. '------------------------------' +
  156. '\nGame Map Position: ' +
  157. curMapPosition +
  158. '\n------------------------ setup' +
  159. '\narray: [2, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20]' +
  160. '\nMin index ((gameDifficulty - 1) * 2 + 1): ' +
  161. ((gameDifficulty - 1) * 2 + 1) +
  162. '\nMax index ((gameDifficulty - 1) * 2 + 3): ' +
  163. ((gameDifficulty - 1) * 2 + 3) +
  164. '\n------------------------ this' +
  165. '\nget random min max for A: array[' +
  166. randomIndex +
  167. '] = ' +
  168. totalBlocksA +
  169. '\nget random divisor for B: ' +
  170. totalBlocksB +
  171. '\n------------------------------'
  172. );
  173. }
  174. // (a)
  175. self.utils.renderBlocks(
  176. self.blocks.top,
  177. 'top',
  178. totalBlocksA,
  179. blockWidthA,
  180. colors.blueDark,
  181. colors.blueLight,
  182. xA,
  183. yA
  184. );
  185. // (b)
  186. self.utils.renderBlocks(
  187. self.blocks.bottom,
  188. 'bottom',
  189. totalBlocksB,
  190. blockWidthB,
  191. colors.greenDark,
  192. colors.greenLight,
  193. xB,
  194. yB
  195. );
  196. },
  197. renderBlocks: function (
  198. blocks,
  199. blockType,
  200. totalBlocks,
  201. blockWidth,
  202. lineColor,
  203. fillColor,
  204. x0,
  205. y0
  206. ) {
  207. for (let i = 0; i < totalBlocks; i++) {
  208. // Blocks
  209. const curX = x0 + i * blockWidth;
  210. const curBlock = game.add.geom.rect(
  211. curX,
  212. y0,
  213. blockWidth,
  214. self.control.blockHeight,
  215. fillColor,
  216. 0.5,
  217. lineColor,
  218. 4
  219. );
  220. curBlock.position = blockType;
  221. curBlock.index = i;
  222. curBlock.finalX = x0;
  223. blocks.list.push(curBlock);
  224. // Auxiliar blocks (lower alpha)
  225. const alpha = 0.2;
  226. const curYAux = y0 + self.control.blockHeight + 10;
  227. const curAuxBlock = game.add.geom.rect(
  228. curX,
  229. curYAux,
  230. blockWidth,
  231. self.control.blockHeight,
  232. fillColor,
  233. alpha,
  234. lineColor,
  235. 1
  236. );
  237. blocks.auxBlocks.push(curAuxBlock);
  238. }
  239. // Label - number of blocks (on the right)
  240. let yLabel = y0 + self.control.blockHeight / 2 + 10;
  241. const xLabel = x0 + self.control.blockWidth + 35;
  242. const font = {
  243. ...textStyles.h4_,
  244. font: 'bold ' + textStyles.h4_.font,
  245. fill: lineColor,
  246. };
  247. blocks.label = game.add.text(xLabel, yLabel, blocks.list.length, font);
  248. blocks.label.alpha = showFractions ? 1 : 0;
  249. // 'selected blocks/fraction' label for (a) : at the bottom of (a)
  250. yLabel = y0 + self.control.blockHeight + 40;
  251. blocks.fractions[0] = game.add.text(xLabel, yLabel, '', font);
  252. blocks.fractions[1] = game.add.geom.line(
  253. xLabel,
  254. yLabel + 10,
  255. xLabel + 50,
  256. yLabel + 10,
  257. 2,
  258. lineColor
  259. );
  260. blocks.fractions[1].anchor(0.5, 0);
  261. blocks.fractions[0].alpha = 0;
  262. blocks.fractions[1].alpha = 0;
  263. // Invalid selection text
  264. blocks.warningText = game.add.text(
  265. context.canvas.width / 2,
  266. y0 - 20,
  267. game.lang.s2_error_msg,
  268. { ...font, font: textStyles.h4_.font }
  269. );
  270. blocks.warningText.alpha = 0;
  271. },
  272. renderCharacters: function () {
  273. self.kidAnimation = game.add.sprite(
  274. 100,
  275. context.canvas.height - 128 * 1.5,
  276. 'kid_standing',
  277. 0,
  278. 1.2
  279. );
  280. self.kidAnimation.anchor(0.5, 0.7);
  281. self.kidAnimation.curFrame = 3;
  282. },
  283. renderMainUI: () => {
  284. // Intro text
  285. const treatedMessage = game.lang.squareTwo_intro.split('\\n');
  286. const font = textStyles.h1_;
  287. self.ui.message = [];
  288. self.ui.message.push(
  289. game.add.text(
  290. context.canvas.width / 2,
  291. 170,
  292. treatedMessage[0] + '\n' + treatedMessage[1],
  293. font
  294. )
  295. );
  296. },
  297. renderOperationUI: () => {
  298. const uiList = [
  299. ...self.blocks.top.list,
  300. ...self.blocks.bottom.list,
  301. ...self.blocks.top.fractions,
  302. ...self.blocks.bottom.fractions,
  303. ];
  304. moveList(uiList, -400, 0);
  305. const font = textStyles.fraction;
  306. font.fill = colors.black;
  307. font.align = 'center';
  308. const nominators = [
  309. self.blocks.top.selectedAmount,
  310. self.blocks.bottom.selectedAmount,
  311. ];
  312. const denominators = [
  313. self.blocks.top.list.length,
  314. self.blocks.bottom.list.length,
  315. ];
  316. if (gameMode === 'b') {
  317. const leftNom = nominators[0];
  318. const leftDenom = denominators[0];
  319. nominators[0] = nominators[1];
  320. denominators[0] = denominators[1];
  321. nominators[1] = leftNom;
  322. denominators[1] = leftDenom;
  323. }
  324. const renderList = [];
  325. const padding = 100;
  326. const offsetX = 100;
  327. const cardHeight = 400;
  328. const x0 = padding + 400;
  329. const y0 = context.canvas.height / 2;
  330. let nextX = x0;
  331. const cardX = x0 - padding;
  332. const cardY = y0;
  333. // Card
  334. const card = game.add.geom.rect(
  335. cardX,
  336. cardY,
  337. 0,
  338. cardHeight,
  339. colors.blueLight,
  340. 0.5,
  341. colors.blueDark,
  342. 8
  343. );
  344. card.id = 'card';
  345. card.anchor(0, 0.5);
  346. renderList.push(card);
  347. renderList.push(
  348. game.add.text(
  349. nextX,
  350. y0,
  351. nominators[0] + '\n' + denominators[0],
  352. font,
  353. 70
  354. )
  355. );
  356. const topFractionLine = game.add.geom.rect(
  357. nextX,
  358. y0 + 10,
  359. 100,
  360. 4,
  361. colors.black,
  362. 4
  363. );
  364. topFractionLine.anchor(0.5, 0);
  365. renderList.push(topFractionLine);
  366. font.fill = self.control.isCorrect ? colors.green : colors.red;
  367. nextX += offsetX;
  368. renderList.push(
  369. game.add.text(nextX, y0 + 35, self.control.isCorrect ? '=' : '≠', font)
  370. );
  371. font.fill = colors.black;
  372. nextX += offsetX;
  373. renderList.push(
  374. game.add.text(
  375. nextX,
  376. y0,
  377. nominators[1] + '\n' + denominators[1],
  378. font,
  379. 70
  380. )
  381. );
  382. const bottomFractionLine = game.add.geom.rect(
  383. nextX,
  384. y0 + 10,
  385. 100,
  386. 4,
  387. colors.black,
  388. 4
  389. );
  390. bottomFractionLine.anchor(0.5, 0);
  391. renderList.push(bottomFractionLine);
  392. //let resultWidth = ''.length * widthOfChar;
  393. const cardWidth = nextX - x0 + padding * 2;
  394. card.width = cardWidth;
  395. const endSignX =
  396. (context.canvas.width - cardWidth) / 2 + cardWidth + 400 + 50;
  397. // Center Card
  398. moveList(renderList, (context.canvas.width - cardWidth) / 2, 0);
  399. self.fractionOperationUI = renderList;
  400. return endSignX;
  401. },
  402. renderEndUI: () => {
  403. let btnColor = colors.green;
  404. let btnText = game.lang.continue;
  405. if (!self.control.isCorrect) {
  406. btnColor = colors.red;
  407. btnText = game.lang.retry;
  408. }
  409. // continue button
  410. self.ui.continue.button = game.add.geom.rect(
  411. context.canvas.width / 2 + 400,
  412. context.canvas.height / 2 + 280,
  413. 450,
  414. 100,
  415. btnColor
  416. );
  417. self.ui.continue.button.anchor(0.5, 0.5);
  418. self.ui.continue.text = game.add.text(
  419. context.canvas.width / 2 + 400,
  420. context.canvas.height / 2 + 16 + 280,
  421. btnText,
  422. textStyles.btn
  423. );
  424. },
  425. startDelayHandler: () => {
  426. game.timer.stop();
  427. self.control.animationDelay++;
  428. if (self.control.animationDelay === 50) {
  429. self.ui.message[0].alpha = 0;
  430. self.utils.checkAnswer();
  431. self.control.animationDelay = 0;
  432. self.control.startEndAnimation = true;
  433. }
  434. },
  435. // UPDATE
  436. moveBlocks: function () {
  437. ['top', 'bottom'].forEach((cur) => {
  438. if (self.blocks[cur].animate) {
  439. // Lower selected blocks
  440. for (let i = 0; i < self.blocks[cur].selectedAmount; i++) {
  441. self.blocks[cur].list[i].y += 2;
  442. }
  443. // After fully lowering blocks, set fraction value
  444. if (self.blocks[cur].list[0].y >= self.blocks[cur].auxBlocks[0].y) {
  445. self.blocks[cur].fractions[0].name =
  446. self.blocks[cur].selectedAmount +
  447. '\n' +
  448. self.blocks[cur].list.length;
  449. self.blocks[cur].animate = false;
  450. }
  451. }
  452. });
  453. },
  454. checkAnswer: function () {
  455. for (let block of self.blocks.top.auxBlocks) {
  456. block.alpha = 0;
  457. }
  458. for (let block of self.blocks.bottom.auxBlocks) {
  459. block.alpha = 0;
  460. }
  461. // After delay is over, check result
  462. //if (self.control.animationDelay > 50) {
  463. self.control.isCorrect =
  464. self.blocks.top.selectedAmount / self.blocks.top.list.length ==
  465. self.blocks.bottom.selectedAmount / self.blocks.bottom.list.length;
  466. const x = self.utils.renderOperationUI();
  467. if (self.control.isCorrect) {
  468. if (audioStatus) game.audio.okSound.play();
  469. game.add
  470. .image(x + 50, context.canvas.height / 2, 'answer_correct')
  471. .anchor(0.5, 0.5);
  472. completedLevels++;
  473. if (isDebugMode) console.log('Completed Levels: ' + completedLevels);
  474. } else {
  475. if (audioStatus) game.audio.errorSound.play();
  476. game.add
  477. .image(x, context.canvas.height / 2, 'answer_wrong')
  478. .anchor(0.5, 0.5);
  479. }
  480. self.fetch.postScore();
  481. },
  482. runEndAnimation: function () {
  483. self.control.animationDelay++;
  484. if (self.control.animationDelay === 100) {
  485. self.utils.renderEndUI();
  486. self.control.showEndInfo = true;
  487. if (self.control.isCorrect) canGoToNextMapPosition = true;
  488. else canGoToNextMapPosition = false;
  489. }
  490. },
  491. endLevel: function () {
  492. game.state.start('map');
  493. },
  494. // HANDLERS
  495. /**
  496. * Function called by self.onInputDown() when player clicked a valid rectangle.
  497. *
  498. * @param {object} curBlock clicked rectangle : can be self.blocks.top.list[i] or self.blocks.bottom.list[i]
  499. */
  500. clickSquareHandler: function (curBlock) {
  501. const curSet = curBlock.position;
  502. if (
  503. !self.blocks[curSet].hasClicked &&
  504. curBlock.index != self.blocks[curSet].list.length - 1
  505. ) {
  506. document.body.style.cursor = 'auto';
  507. // Turn auxiliar blocks invisible
  508. for (let i in self.blocks[curSet].list) {
  509. if (i > curBlock.index) self.blocks[curSet].auxBlocks[i].alpha = 0;
  510. }
  511. // Turn value label invisible
  512. self.blocks[curSet].label.alpha = 0;
  513. if (audioStatus) game.audio.popSound.play();
  514. // Save number of selected blocks
  515. self.blocks[curSet].selectedAmount = curBlock.index + 1;
  516. // Set fraction x position
  517. const newX =
  518. curBlock.finalX +
  519. self.blocks[curSet].selectedAmount *
  520. (self.control.blockWidth / self.blocks[curSet].list.length) +
  521. 40;
  522. self.blocks[curSet].fractions[0].x = newX;
  523. self.blocks[curSet].fractions[1].x = newX;
  524. self.blocks[curSet].fractions[0].name = `${curBlock.index + 1}\n${
  525. self.blocks[curSet].list.length
  526. }`;
  527. // End fraction line
  528. self.blocks[curSet].fractions[1].alpha = showFractions ? 1 : 0;
  529. self.blocks[curSet].hasClicked = true; // Inform player have clicked in current block set
  530. self.blocks[curSet].animate = true; // Let it initiate animation
  531. }
  532. game.render.all();
  533. },
  534. /**
  535. * Function called by self.onInputOver() when cursor is over a valid rectangle.
  536. *
  537. * @param {object} curBlock rectangle the cursor is over : can be self.blocks.top.list[i] or self.blocks.bottom.list[i]
  538. */
  539. overSquareHandler: function (curBlock) {
  540. const curSet = curBlock.position;
  541. if (!self.blocks[curSet].hasClicked) {
  542. // self.blocks.top.hasClicked || self.blocks.bottom.hasClicked
  543. // If over fraction 'n/n' shows warning message not allowing it
  544. if (curBlock.index == self.blocks[curSet].list.length - 1) {
  545. const otherSet = curSet == 'top' ? 'bottom' : 'top';
  546. self.blocks[curSet].warningText.alpha = 1;
  547. self.blocks[otherSet].warningText.alpha = 0;
  548. self.utils.outSquareHandler(curSet);
  549. } else {
  550. document.body.style.cursor = 'pointer';
  551. self.blocks.top.warningText.alpha = 0;
  552. self.blocks.bottom.warningText.alpha = 0;
  553. // Selected blocks become fully visible
  554. for (let i in self.blocks[curSet].list) {
  555. self.blocks[curSet].list[i].alpha = i <= curBlock.index ? 1 : 0.5;
  556. }
  557. self.blocks[curSet].fractions[0].name = curBlock.index + 1; // Nominator : selected blocks
  558. const newX =
  559. curBlock.finalX +
  560. (curBlock.index + 1) *
  561. (self.control.blockWidth / self.blocks[curSet].list.length) +
  562. 25;
  563. self.blocks[curSet].fractions[0].x = newX;
  564. self.blocks[curSet].fractions[1].x = newX;
  565. // End fraction nominator and denominator
  566. self.blocks[curSet].fractions[0].alpha = showFractions ? 1 : 0;
  567. }
  568. }
  569. },
  570. /**
  571. * Function called (by self.onInputOver() and self.utils.overSquareHandler()) when cursor is out of a valid rectangle.
  572. *
  573. * @param {object} curSet set of rectangles : can be top (self.blocks.top) or bottom (self.blocks.bottom)
  574. */
  575. outSquareHandler: function (curSet) {
  576. if (!self.blocks[curSet].hasClicked) {
  577. self.blocks[curSet].fractions[0].alpha = 0;
  578. self.blocks[curSet].fractions[1].alpha = 0;
  579. self.blocks[curSet].list.forEach((cur) => {
  580. cur.alpha = 0.5;
  581. });
  582. }
  583. },
  584. },
  585. events: {
  586. /**
  587. * Called by mouse click event
  588. *
  589. * @param {object} mouseEvent contains the mouse click coordinates
  590. */
  591. onInputDown: function (mouseEvent) {
  592. const x = game.math.getMouse(mouseEvent).x;
  593. const y = game.math.getMouse(mouseEvent).y;
  594. // Click block in (a)
  595. self.blocks.top.list.forEach((cur) => {
  596. if (game.math.isOverIcon(x, y, cur)) self.utils.clickSquareHandler(cur);
  597. });
  598. // Click block in (b)
  599. self.blocks.bottom.list.forEach((cur) => {
  600. if (game.math.isOverIcon(x, y, cur)) self.utils.clickSquareHandler(cur);
  601. });
  602. // Continue button
  603. if (self.control.showEndInfo) {
  604. if (game.math.isOverIcon(x, y, self.ui.continue.button)) {
  605. if (audioStatus) game.audio.popSound.play();
  606. self.utils.endLevel();
  607. }
  608. }
  609. // Click navigation icons
  610. navigation.onInputDown(x, y);
  611. game.render.all();
  612. },
  613. /**
  614. * Called by mouse move event
  615. *
  616. * @param {object} mouseEvent contains the mouse move coordinates
  617. */
  618. onInputOver: function (mouseEvent) {
  619. const x = game.math.getMouse(mouseEvent).x;
  620. const y = game.math.getMouse(mouseEvent).y;
  621. let flagA = false;
  622. let flagB = false;
  623. // Mouse over (a) : show fraction
  624. self.blocks.top.list.forEach((cur) => {
  625. if (game.math.isOverIcon(x, y, cur)) {
  626. flagA = true;
  627. self.utils.overSquareHandler(cur);
  628. }
  629. });
  630. if (!flagA) self.utils.outSquareHandler('top');
  631. // Mouse over (b) : show fraction
  632. self.blocks.bottom.list.forEach((cur) => {
  633. if (game.math.isOverIcon(x, y, cur)) {
  634. flagB = true;
  635. self.utils.overSquareHandler(cur);
  636. }
  637. });
  638. if (!flagB) self.utils.outSquareHandler('bottom');
  639. if (!flagA && !flagB) document.body.style.cursor = 'auto';
  640. // Continue button
  641. if (self.control.showEndInfo) {
  642. if (game.math.isOverIcon(x, y, self.ui.continue.button)) {
  643. // If pointer is over icon
  644. document.body.style.cursor = 'pointer';
  645. self.ui.continue.button.scale =
  646. self.ui.continue.button.initialScale * 1.1;
  647. self.ui.continue.text.style = textStyles.btnLg;
  648. } else {
  649. // If pointer is not over icon
  650. document.body.style.cursor = 'auto';
  651. self.ui.continue.button.scale =
  652. self.ui.continue.button.initialScale * 1;
  653. self.ui.continue.text.style = textStyles.btn;
  654. }
  655. }
  656. // Mouse over navigation icons : show name
  657. navigation.onInputOver(x, y);
  658. game.render.all();
  659. },
  660. },
  661. fetch: {
  662. /**
  663. * Saves players data after level ends - to be sent to database. <br>
  664. *
  665. * Attention: the 'line_' prefix data table must be compatible to data table fields (MySQL server)
  666. *
  667. * @see /php/save.php
  668. */
  669. postScore: function () {
  670. // Creates string that is going to be sent to db
  671. const data =
  672. '&line_game=' +
  673. gameShape +
  674. '&line_mode=' +
  675. gameMode +
  676. '&line_oper=equal' +
  677. '&line_leve=' +
  678. gameDifficulty +
  679. '&line_posi=' +
  680. curMapPosition +
  681. '&line_resu=' +
  682. self.control.isCorrect +
  683. '&line_time=' +
  684. game.timer.elapsed +
  685. '&line_deta=' +
  686. 'numBlocksA: ' +
  687. self.blocks.top.list.length +
  688. ', valueA: ' +
  689. self.blocks.top.selectedAmount +
  690. ', numBlocksB: ' +
  691. self.blocks.bottom.list.length +
  692. ', valueB: ' +
  693. self.blocks.bottom.selectedAmount;
  694. // FOR MOODLE
  695. sendToDatabase(data);
  696. },
  697. },
  698. };