Sfoglia il codice sorgente

✨ Make valise 3 minigame

Pedro Tonini Rosenberg Schneider 3 anni fa
parent
commit
4719a1bce7

+ 11 - 0
index.html

@@ -64,6 +64,17 @@
     <script type="text/javascript" src="src/elements/earth/valise2/tutorial/Valise2Tutorial.js"></script>
     <script type="text/javascript" src="src/elements/earth/valise2/level_selector/Valise2LevelButton.js"></script>
     <script type="text/javascript" src="src/elements/earth/valise2/level_selector/Valise2LevelSelector.js"></script>
+    <!-- Valise 3 -->
+    <script type="text/javascript" src="src/elements/earth/valise3/Valise3Levels.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/game/Valise3CardVisualEffect.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/game/Valise3OptionCard.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/game/Valise3QuestionCard.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/game/Valise3GameDialogue.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/game/Valise3Game.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/tutorial/Valise3TutorialDialogue.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/tutorial/Valise3Tutorial.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/level_selector/Valise3LevelButton.js"></script>
+    <script type="text/javascript" src="src/elements/earth/valise3/level_selector/Valise3LevelSelector.js"></script>
     <!-- Rébus -->
     <script type="text/javascript" src="src/elements/earth/rebus/RebusLevels.js"></script>
     <script type="text/javascript" src="src/elements/earth/rebus/level_selector/RebusLevelButton.js"></script>

+ 3 - 1
src/elements/earth/EarthMinigameSelector.js

@@ -183,7 +183,9 @@ class EarthMinigameSelector extends Object2D
 
     _onValise3Selected()
     {
-        console.log("Palavra valise 3 has been selected");
+        var vls = new Valise3LevelSelector("Valise3LevelSelector");
+        GameHandler.addRootObject(vls);
+        this.queueFree();
     }
 
     _onRebusSelected()

+ 374 - 0
src/elements/earth/valise3/Valise3Levels.js

@@ -0,0 +1,374 @@
+/************************************************************************
+ * Valise3Levels.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+const VALISE3_LEVELS = {
+    tutorial:
+    {
+        questionCard:
+        {
+            name: "Caqui",
+        },
+
+        optionCards: [
+        {
+            name: "Aqui",
+            isAnswer: true,
+        },
+        {
+            name: "Casa",
+            isAnswer: false,
+        },
+        {
+            name: "Quiabo",
+            isAnswer: false,
+        },
+        {
+            name: "Pera",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra F.",
+        tip2: "O que está dentro da palavra CAQUI?"
+    },
+
+    level1:
+    {
+        questionCard:
+        {
+            name: "Floresta",
+        },
+
+        optionCards: [
+        {
+            name: "Flor",
+            isAnswer: true,
+        },
+        {
+            name: "Lobo",
+            isAnswer: false,
+        },
+        {
+            name: "Régua",
+            isAnswer: false,
+        },
+        {
+            name: "Árvore",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra A.",
+        tip2: "O que está dentro da palavra FLORESTA?"
+    },
+
+    level2:
+    {
+        questionCard:
+        {
+            name: "Maracujá",
+        },
+
+        optionCards: [
+        {
+            name: "Já",
+            isAnswer: true,
+        },
+        {
+            name: "Mata",
+            isAnswer: false,
+        },
+        {
+            name: "Rato",
+            isAnswer: false,
+        },
+        {
+            name: "Água",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra J.",
+        tip2: "O que está dentro da palavra MARACUJÁ?"
+    },
+
+    level3:
+    {
+        questionCard:
+        {
+            name: "Acordavam",
+        },
+
+        optionCards: [
+        {
+            name: "Corda",
+            isAnswer: true,
+        },
+        {
+            name: "Abacaxi",
+            isAnswer: false,
+        },
+        {
+            name: "Vaca",
+            isAnswer: false,
+        },
+        {
+            name: "Dado",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra C.",
+        tip2: "O que está dentro da palavra ACORDAVAM?"
+    },
+
+    level4:
+    {
+        questionCard:
+        {
+            name: "Melão",
+        },
+
+        optionCards: [
+        {
+            name: "Mel",
+            isAnswer: true,
+        },
+        {
+            name: "Lata",
+            isAnswer: false,
+        },
+        {
+            name: "Não",
+            isAnswer: false,
+        },
+        {
+            name: "Livro",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra M.",
+        tip2: "O que está dentro da palavra MELÃO?"
+    },
+
+    level5:
+    {
+        questionCard:
+        {
+            name: "Abacate",
+        },
+
+        optionCards: [
+        {
+            name: "Aba",
+            isAnswer: true,
+        },
+        {
+            name: "Bala",
+            isAnswer: false,
+        },
+        {
+            name: "Telefone",
+            isAnswer: false,
+        },
+        {
+            name: "Casa",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra A.",
+        tip2: "O que está dentro da palavra ABACATE?"
+    },
+
+    level6:
+    {
+        questionCard:
+        {
+            name: "Goiaba",
+        },
+
+        optionCards: [
+        {
+            name: "Aba",
+            isAnswer: true,
+        },
+        {
+            name: "Gol",
+            isAnswer: false,
+        },
+        {
+            name: "Gaiola",
+            isAnswer: false,
+        },
+        {
+            name: "Baía",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra A.",
+        tip2: "O que está dentro da palavra GOIABA?"
+    },
+
+    level7:
+    {
+        questionCard:
+        {
+            name: "Chamou",
+        },
+
+        optionCards: [
+        {
+            name: "Amou",
+            isAnswer: true,
+        },
+        {
+            name: "Chama",
+            isAnswer: false,
+        },
+        {
+            name: "Ouriço",
+            isAnswer: false,
+        },
+        {
+            name: "Morcego",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra A.",
+        tip2: "O que está dentro da palavra CHAMOU?"
+    },
+
+    level8:
+    {
+        questionCard:
+        {
+            name: "Sementes",
+        },
+
+        optionCards: [
+        {
+            name: "Mente",
+            isAnswer: true,
+        },
+        {
+            name: "Seco",
+            isAnswer: false,
+        },
+        {
+            name: "Teto",
+            isAnswer: false,
+        },
+        {
+            name: "Nabo",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra M.",
+        tip2: "O que está dentro da palavra SEMENTES?"
+    },
+
+    level9:
+    {
+        questionCard:
+        {
+            name: "Limão",
+        },
+
+        optionCards: [
+        {
+            name: "Mão",
+            isAnswer: true,
+        },
+        {
+            name: "Livro",
+            isAnswer: false,
+        },
+        {
+            name: "Caminhão",
+            isAnswer: false,
+        },
+        {
+            name: "Miado",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra M.",
+        tip2: "O que está dentro da palavra LIMÃO?"
+    },
+
+    level10:
+    {
+        questionCard:
+        {
+            name: "Mexerica",
+        },
+
+        optionCards: [
+        {
+            name: "Mexe",
+            isAnswer: true,
+        },
+        {
+            name: "Caixa",
+            isAnswer: false,
+        },
+        {
+            name: "Rica",
+            isAnswer: true,
+        },
+        {
+            name: "Rio",
+            isAnswer: false,
+        },
+        {
+            name: "Espelho",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Uma das palavras começa com a letra M, e a outra começa com a letra R.",
+        tip2: "O que está dentro da palavra MEXERICA?"
+    },
+
+    level11:
+    {
+        questionCard:
+        {
+            name: "Mexerica",
+        },
+
+        optionCards: [
+        {
+            name: "Rica",
+            isAnswer: true,
+        },
+        {
+            name: "Menino",
+            isAnswer: false,
+        },
+        {
+            name: "Casa",
+            isAnswer: false,
+        },
+        {
+            name: "Xadrez",
+            isAnswer: false,
+        }, ],
+
+        tip1: "Começa com a letra R.",
+        tip2: "O que está dentro da palavra MEXERICA?"
+    },
+}

+ 57 - 0
src/elements/earth/valise3/game/Valise3CardVisualEffect.js

@@ -0,0 +1,57 @@
+/************************************************************************
+ * Valise3CardVisualEffect.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3CardVisualEffect extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {number} */
+        this.glowIterations = 7;
+        /** @type {number} */
+        this.glowAmount = 0;
+    }
+
+    _draw( /** @type {number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        db.rectMode(CENTER);
+        if (this.parent.selected)
+        {
+            if (!this.parent.isAnswer)
+            {
+                db.fill(0, 80);
+                db.rect(0, 0, 275, 275, 10, 10);
+            }
+            else
+            {
+                db.noFill();
+                this.glowAmount = min(1.0, this.glowAmount + 0.03);
+                for (let i = 0; i < this.glowIterations; i++)
+                {
+                    db.stroke(255, 255, 100, this.glowAmount * 200 / (this.glowIterations + 1 - i));
+                    db.strokeWeight((this.glowIterations - i) * 6);
+                    db.rect(0, 0, 275, 275, 10);
+                }
+            }
+        }
+    }
+}

+ 122 - 0
src/elements/earth/valise3/game/Valise3Game.js

@@ -0,0 +1,122 @@
+/************************************************************************
+ * Valise3Game.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3Game extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {Object} */
+        this.levelData = null;
+        /** @type {Valise3QuestionCard} */
+        this.questionCard = null;
+        /** @type {Object2D} */
+        this.optionCards = null;
+        /** @type {Button} */
+        this.backButton = null;
+        /** @type {Valise3GameDialogue} */
+        this.dialogue = null;
+
+        /** @type {Number} */
+        this.points = 3;
+        /** @type {Boolean} */
+        this.gameFinished = false;
+        /** @type {Number} */
+        this.numAnswers = 0;
+    }
+
+    _setup()
+    {
+        this.backButton = new Button("BackButton");
+        this.backButton.setLabel("Voltar");
+        this.backButton.setFontSize(30);
+        this.backButton.setPosition(20, 20);
+        this.backButton.setSize(110, 75);
+        this.backButton.connect("mouseClicked", this, "_onBackClicked");
+        this.addChild(this.backButton);
+
+        this.questionCard = new Valise3QuestionCard("QuestionCard");
+        this.questionCard.str = this.levelData.questionCard.name;
+        this.questionCard.setPosition(1920 / 2, 300);
+        this.addChild(this.questionCard);
+
+        this.optionCards = new Object2D("OptionCards");
+        this.addChild(this.optionCards);
+        var idx = [];
+        for (let i = 0; i < this.levelData.optionCards.length; i++)
+            idx.push(i);
+        randomSeed(Date.now());
+        idx = shuffle(idx);
+        for (let i = 0; i < this.levelData.optionCards.length; i++)
+        {
+            var newCard = new Valise3OptionCard(`OptionCard${i}`);
+            newCard.setPosition((i + 1) * 1920 / (this.levelData.optionCards.length + 1), 800);
+            newCard.isAnswer = this.levelData.optionCards[idx[i]].isAnswer;
+            newCard.connect("selected", this, "_onCardSelected");
+            newCard.str = this.levelData.optionCards[idx[i]].name;
+            this.levelData.optionCards[idx[i]].isAnswer ? this.numAnswers++ : 0;
+            this.optionCards.addChild(newCard);
+        }
+        console.log(this.numAnswers)
+
+        this.dialogue = new Valise3GameDialogue("GameDialogue");
+        this.dialogue.connect("endGame", this, "_onDialogueEndGame");
+        this.addChild(this.dialogue);
+    }
+
+    _draw( /** @type {Number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        background(52);
+
+        // db.fill(255);
+        // db.textSize(70);
+        // db.textAlign(CENTER, CENTER);
+        // db.text(`Nível ${this.levelData}`, 1920 / 2, 100);
+    }
+
+    _onCardSelected( /** @type {Boolean} */ isAnswer)
+    {
+        if (!isAnswer) this.points--;
+        else
+        {
+            this.numAnswers--;
+            if (this.numAnswers != 0) return;
+            this.backButton.hide();
+            this.gameFinished = true;
+            for (let i = 0; i < this.optionCards.children.length; i++)
+                this.optionCards.children[i].selectable = false;
+        }
+    }
+
+    _onDialogueEndGame()
+    {
+        this._onBackClicked();
+    }
+
+    _onBackClicked()
+    {
+        var vls = new Valise3LevelSelector("Valise3LevelSelector");
+        GameHandler.addRootObject(vls);
+        AssetHandler.clearTextureCache();
+        this.queueFree();
+    }
+}

+ 86 - 0
src/elements/earth/valise3/game/Valise3GameDialogue.js

@@ -0,0 +1,86 @@
+/************************************************************************
+ * Valise3GameDialogue.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3GameDialogue extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {Button} */
+        this.continueButton = null;
+        /** @type {Timer} */
+        this.timer;
+
+        /** @type {String} */
+        this.suffix = "";
+        /** @type {number} */
+        this.bgOpacity = 0;
+        /** @type {number} */
+        this.textOpacity = 0;
+    }
+
+    _initSignals()
+    {
+        this.addSignal("endGame");
+    }
+
+    _setup()
+    {
+        this.timer = new Timer("Timer", 2, false, true);
+        this.timer.connect("timeout", this, "_onTimerTimeout");
+        this.addChild(this.timer);
+
+        this.continueButton = new Button("ContinueButton", "Continuar");
+        this.continueButton.setFontSize(40);
+        this.continueButton.setPosition(1920 / 2 - this.continueButton.getSize().x / 2, 600);
+        this.continueButton.connect("mouseClicked", this, "_onContinueButtonClicked");
+        this.addChild(this.continueButton);
+        this.continueButton.hide();
+    }
+
+    _draw( /** @type {number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        if (this.parent.gameFinished)
+        {
+            this.timer.start();
+            db.noStroke();
+            db.fill(0, min(this.bgOpacity += 75 * delta, 200));
+            db.rectMode(CENTER);
+            db.rect(db.width / 2, db.height / 2, 1800, 600, 40, 40);
+            db.textAlign(CENTER, CENTER);
+            db.fill(255, min(this.textOpacity += 80 * delta, 255));
+            db.textSize(40);
+            this.parent.points > 1 ? this.suffix = "S" : this.suffix = "";
+            db.text(`PARABÉNS, NÍVEL CONCLUÍDO\n\nVOCÊ GANHOU ${this.parent.points} PONTO${this.suffix}!`, db.width / 2, db.height / 2 - 100);
+        }
+    }
+
+    _onTimerTimeout()
+    {
+        this.continueButton.show();
+    }
+
+    _onContinueButtonClicked()
+    {
+        this.emitSignal("endGame");
+    }
+}

+ 141 - 0
src/elements/earth/valise3/game/Valise3OptionCard.js

@@ -0,0 +1,141 @@
+/************************************************************************
+ * Valise3OptionCard.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3OptionCard extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {String} */
+        this.str = "";
+        /** @type {Boolean} */
+        this.isAnswer = false;
+        /** @type {Boolean} */
+        this.selected = false;
+        /** @type {Boolean} */
+        this.selectable = true;
+        /** @type {Boolean} */
+        this.mouseOver = false;
+        /** @type  {Boolean} */
+        this.mousePress = false;
+
+        /** @type {TextureRes} */
+        this.thumb = null;
+        /** @type {Color} */
+        this.fillColor = new Color(200, 200, 200);
+        /** @type {Boolean} */
+        this.tweenStarted = false;
+        /** @type {Tween} */
+        this.tween = null;
+        /** @type {Timer} */
+        this.timer = null;
+    }
+
+    _initSignals()
+    {
+        this.addSignal("selected");
+    }
+
+    _setup()
+    {
+        var area = new Area2D("area", SHAPES.RECT, new Rect(275, 275), true);
+        area.connect("mouseEntered", this, "_onMouseEntered");
+        area.connect("mouseExited", this, "_onMouseExited");
+        this.addChild(area);
+
+        this.addChild(new Valise3CardVisualEffect("CardVfx"));
+
+        this.tween = new Tween("Tween");
+        this.tween.interpolateProperty(this, "scale", PROPERTY_TYPE.VECTOR2, Vector2.ZERO(), Vector2.ONE(), 2, TRANS_TYPE.ELASTIC, EASE_TYPE.OUT);
+        this.addChild(this.tween);
+        this.setScale(0, 0);
+
+        this.timer = new Timer("Timer", 1, false, true);
+        this.timer.connect("timeout", this, "_onTimerTimeout");
+        this.addChild(this.timer);
+    }
+
+    _update( /** @type {Number} */ delta)
+    {
+        if (this.visible && !this.tweenStarted)
+        {
+            this.timer.start();
+            this.tween.startAll();
+            this.tweenStarted = true;
+        }
+
+        if (this.selectable && this.mouseOver)
+        {
+            if (InputHandler.mouseIsClicked)
+            {
+                this.selected = true;
+                this.selectable = false;
+                this.emitSignal("selected", this.isAnswer);
+
+            }
+
+            if (InputHandler.mouseIsPressed)
+            {
+                this.scale.x = max(this.scale.x - 3.0 * delta, 0.95);
+                this.scale.y = max(this.scale.y - 3.0 * delta, 0.95);
+            }
+            else
+            {
+                this.scale.x = min(this.scale.x + 2.0 * delta, 1.2);
+                this.scale.y = min(this.scale.y + 2.0 * delta, 1.2);
+            }
+        }
+
+        else
+        {
+            this.scale.x = max(this.scale.x - 2.0 * delta, 1);
+            this.scale.y = max(this.scale.y - 2.0 * delta, 1);
+        }
+    }
+
+    _draw( /** @type {Number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        db.rectMode(CENTER);
+        db.fill(this.fillColor.getP5Color());
+        db.rect(0, 0, 275, 275, 10, 10);
+        db.textAlign(CENTER, CENTER);
+        db.fill(0);
+        db.textSize(40);
+        db.text(this.str, 0, 0);
+    }
+
+    _onMouseEntered()
+    {
+        this.mouseOver = true;
+        console.log(this.str);
+    }
+
+    _onMouseExited()
+    {
+        this.mouseOver = false;
+    }
+
+    _onTimerTimeout()
+    {
+        this.tween.stopAll();
+    }
+}

+ 60 - 0
src/elements/earth/valise3/game/Valise3QuestionCard.js

@@ -0,0 +1,60 @@
+/************************************************************************
+ * Valise3QuestionCard.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3QuestionCard extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {String} */
+        this.str = "";
+
+        /** @type {Color} */
+        this.fillColor = new Color(200, 200, 200);
+        /** @type {Tween} */
+        this.tween = null;
+    }
+
+    _setup()
+    {
+        this.tween = new Tween("Tween");
+        this.tween.interpolateProperty(this, "scale", PROPERTY_TYPE.VECTOR2, Vector2.ZERO(), Vector2.ONE(), 2, TRANS_TYPE.ELASTIC, EASE_TYPE.OUT);
+        this.addChild(this.tween);
+    }
+
+    _update( /** @type {Number} */ delta)
+    {
+        if (this.visible) this.tween.startAll();
+    }
+
+    _draw( /** @type {Number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        db.strokeWeight(10);
+        db.rectMode(CENTER);
+        db.fill(this.fillColor.getP5Color());
+        db.rect(0, 0, 275, 275, 10, 10);
+        db.textAlign(CENTER, CENTER);
+        db.fill(0);
+        db.textSize(40);
+        db.text(this.str, 0, 0);
+    }
+}

+ 41 - 0
src/elements/earth/valise3/level_selector/Valise3LevelButton.js

@@ -0,0 +1,41 @@
+/************************************************************************
+ * Valise3LevelButton.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3LevelButton extends Button
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {Object} */
+        this.levelData = null;
+    }
+
+    _initSignals()
+    {
+        this.addSignal("levelSelected");
+    }
+
+    _onMouseClicked()
+    {
+        this.emitSignal("levelSelected", this.levelData);
+    }
+}

+ 108 - 0
src/elements/earth/valise3/level_selector/Valise3LevelSelector.js

@@ -0,0 +1,108 @@
+/************************************************************************
+ * Valise3LevelSelector.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3LevelSelector extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {Object} */
+        this.gridMargins = {
+            left: 0,
+            right: 0,
+            up: 500,
+            down: 0
+        };
+
+        /** @type {number} */
+        this.gridCols = 4;
+    }
+
+    _setup()
+    {
+        var b = new RebusLevelButton("Tutorial");
+        b.levelData = VALISE3_LEVELS.tutorial;
+        b.setLabel("Tutorial");
+        b.setFontSize(40);
+        this.addChild(b);
+        b.setSize(200, 100);
+        b.setPosition((1920 - b.getSize().x) / 2, 300);
+        b.connect("levelSelected", this, "_onTutorialSelected");
+
+        var i = 1;
+        while (VALISE3_LEVELS[`level${i}`])
+        {
+            var b = new Valise3LevelButton(`level${i}`);
+            b.levelData = VALISE3_LEVELS[`level${i}`];
+            b.setLabel(`${i}`);
+            b.setFontSize(40);
+            this.addChild(b);
+            b.setSize(100, 100);
+            b.setPosition((((i - 1) % this.gridCols) + 1) * 1920 / (this.gridCols + 1) - b.getSize().x / 2, this.gridMargins.up + 200 * int((i - 1) / this.gridCols));
+            b.connect("levelSelected", this, "_onLevelSelected");
+            i++;
+        }
+
+        this.backButton = new Button("BackButton");
+        this.backButton.setLabel("Voltar");
+        this.backButton.setFontSize(30);
+        this.backButton.setPosition(20, 20);
+        this.backButton.setSize(110, 75);
+        this.backButton.connect("mouseClicked", this, "_onBackClicked");
+        this.addChild(this.backButton);
+    }
+
+    _draw( /** @type {number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        background(52);
+
+        db.textAlign(CENTER, CENTER);
+        db.fill(255);
+        db.textSize(100);
+        db.text("PALAVRA VALISE 3", 1920 / 2, 125);
+        db.textSize(40);
+        db.text("Escolha o nível", 1920 / 2, 200);
+    }
+
+    _onTutorialSelected( /** @type {Object} */ levelData)
+    {
+        var vt = new Valise3Tutorial("Valise3Tutorial");
+        vt.levelData = levelData;
+        GameHandler.addRootObject(vt);
+        this.queueFree();
+    }
+
+    _onLevelSelected( /** @type {Object} */ levelData)
+    {
+        var vg = new Valise3Game("Valise3Game");
+        vg.levelData = levelData;
+        GameHandler.addRootObject(vg);
+        this.queueFree();
+    }
+
+    _onBackClicked()
+    {
+        var ems = new EarthMinigameSelector("EarthMinigameSelector");
+        GameHandler.addRootObject(ems);
+        this.queueFree();
+    }
+}

+ 201 - 0
src/elements/earth/valise3/tutorial/Valise3Tutorial.js

@@ -0,0 +1,201 @@
+/************************************************************************
+ * Valise3Tutorial.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3Tutorial extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {Object} */
+        this.levelData = null;
+        /** @type {Valise3QuestionCard} */
+        this.questionCard = null;
+        /** @type {Object2D} */
+        this.optionCards = null;
+        /** @type {Button} */
+        this.backButton = null;
+        /** @type {Valise3TutorialDialogue} */
+        this.dialogue = null;
+        /** @type {Timer} */
+        this.timer = null;
+
+        /** @type {Number} */
+        this.points = 3;
+        /** @type {Boolean} */
+        this.gameFinished = false;
+        /** @type {Number} */
+        this.tutorialStep = 0;
+    }
+
+    _setup()
+    {
+        this.backButton = new Button("BackButton");
+        this.backButton.setLabel("Voltar");
+        this.backButton.setFontSize(30);
+        this.backButton.setPosition(20, 20);
+        this.backButton.setSize(110, 75);
+        this.backButton.connect("mouseClicked", this, "_onBackClicked");
+        this.addChild(this.backButton);
+
+        this.questionCard = new Valise3QuestionCard("QuestionCard");
+        this.questionCard.str = this.levelData.questionCard.name;
+        this.questionCard.setPosition(1920 / 2, 300);
+        this.addChild(this.questionCard);
+
+        this.optionCards = new Object2D("OptionCards");
+        this.addChild(this.optionCards);
+        var idx = [];
+        for (let i = 0; i < this.levelData.optionCards.length; i++)
+            idx.push(i);
+        randomSeed(Date.now());
+        idx = shuffle(idx);
+        for (let i = 0; i < this.levelData.optionCards.length; i++)
+        {
+            var newCard = new Valise3OptionCard(`OptionCard${i}`);
+            newCard.setPosition((i + 1) * 1920 / (this.levelData.optionCards.length + 1), 800);
+            newCard.isAnswer = idx[i] == 0;
+            newCard.connect("selected", this, "_onCardSelected");
+            newCard.str = this.levelData.optionCards[idx[i]].name;
+            newCard.selectable = false;
+            this.optionCards.addChild(newCard);
+        }
+
+        this.dialogue = new Valise3TutorialDialogue("TutorialDialogue");
+        this.dialogue.connect("continue", this, "_onTutorialContinue");
+        this.addChild(this.dialogue);
+
+        this.timer = new Timer("Timer", 2, false, true);
+        this.timer.connect("timeout", this, "_onTimerTimeout");
+        this.addChild(this.timer);
+        this.timer.start();
+    }
+
+    _draw( /** @type {Number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        background(52);
+    }
+
+    _onCardSelected( /** @type {Boolean} */ isAnswer)
+    {
+        if (!isAnswer) this.points--;
+        else
+        {
+            this.gameFinished = true;
+            for (let i = 0; i < 4; i++)
+                this.optionCards.children[i].selectable = false;
+        }
+    }
+
+    _onTutorialContinue()
+    {
+        this.tutorialStep++;
+
+        switch (this.tutorialStep)
+        {
+            case 2:
+                this.timer.start(2);
+                break;
+            case 10:
+                this._onBackClicked();
+                break;
+        }
+    }
+
+    _onTimerTimeout()
+    {
+        this.tutorialStep++;
+
+        switch (this.tutorialStep)
+        {
+            case 3:
+                this.optionCards.children[0].selectable = true;
+                this.optionCards.children[0].mouseOver = true;
+                this.optionCards.children[1].selectable = false;
+                this.optionCards.children[1].mouseOver = false;
+                this.optionCards.children[2].selectable = false;
+                this.optionCards.children[2].mouseOver = false;
+                this.optionCards.children[3].selectable = false;
+                this.optionCards.children[3].mouseOver = false;
+                this.timer.start(0.5);
+                break;
+            case 4:
+                this.optionCards.children[0].selectable = false;
+                this.optionCards.children[0].mouseOver = false;
+                this.optionCards.children[1].selectable = true;
+                this.optionCards.children[1].mouseOver = true;
+                this.optionCards.children[2].selectable = false;
+                this.optionCards.children[2].mouseOver = false;
+                this.optionCards.children[3].selectable = false;
+                this.optionCards.children[3].mouseOver = false;
+                this.timer.start(0.5);
+                break;
+            case 5:
+                this.optionCards.children[0].selectable = false;
+                this.optionCards.children[0].mouseOver = false;
+                this.optionCards.children[1].selectable = false;
+                this.optionCards.children[1].mouseOver = false;
+                this.optionCards.children[2].selectable = true;
+                this.optionCards.children[2].mouseOver = true;
+                this.optionCards.children[3].selectable = false;
+                this.optionCards.children[3].mouseOver = false;
+                this.timer.start(0.5);
+                break;
+            case 6:
+                this.optionCards.children[0].selectable = false;
+                this.optionCards.children[0].mouseOver = false;
+                this.optionCards.children[1].selectable = false;
+                this.optionCards.children[1].mouseOver = false;
+                this.optionCards.children[2].selectable = false;
+                this.optionCards.children[2].mouseOver = false;
+                this.optionCards.children[3].selectable = true;
+                this.optionCards.children[3].mouseOver = true;
+                this.timer.start(0.5);
+                break;
+            case 7:
+                this.optionCards.children[0].selectable = false;
+                this.optionCards.children[0].mouseOver = false;
+                this.optionCards.children[1].selectable = false;
+                this.optionCards.children[1].mouseOver = false;
+                this.optionCards.children[2].selectable = false;
+                this.optionCards.children[2].mouseOver = false;
+                this.optionCards.children[3].selectable = false;
+                this.optionCards.children[3].mouseOver = false;
+                this.timer.start(2);
+                break;
+            case 8:
+                this.optionCards.children[0].selected = true;
+                this.optionCards.children[1].selected = true;
+                this.optionCards.children[2].selected = true;
+                this.optionCards.children[3].selected = true;
+                this.timer.start(1);
+                break;
+        }
+    }
+
+    _onBackClicked()
+    {
+        var vls = new Valise3LevelSelector("Valise3LevelSelector");
+        GameHandler.addRootObject(vls);
+        AssetHandler.clearTextureCache();
+        this.queueFree();
+    }
+}

+ 102 - 0
src/elements/earth/valise3/tutorial/Valise3TutorialDialogue.js

@@ -0,0 +1,102 @@
+/************************************************************************
+ * Valise3TutorialDialogue.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Alfabetiza.
+ *
+ * Alfabetiza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfabetiza is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Alfabetiza.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+class Valise3TutorialDialogue extends Object2D
+{
+    constructor(name)
+    {
+        super(name);
+
+        /** @type {Button} */
+        this.continueButton = null;
+        /** @type {Timer} */
+        this.timer;
+
+        /** @type {String} */
+        this.text = "";
+        /** @type {number} */
+        this.bgOpacity = 0;
+        /** @type {number} */
+        this.textOpacity = 0;
+    }
+
+    _initSignals()
+    {
+        this.addSignal("continue");
+    }
+
+    _setup()
+    {
+        this.continueButton = new Button("ContinueButton", "Continuar");
+        this.continueButton.connect("mouseClicked", this, "_onContinueButtonMouseClicked");
+        this.continueButton.hide();
+        this.continueButton.setFontSize(40);
+        this.continueButton.setPosition(1920 / 2 - this.continueButton.getSize().x / 2, 600);
+        this.addChild(this.continueButton);
+    }
+
+    _draw( /** @type {number} */ delta, /** @type {p5.Graphics} */ db)
+    {
+        switch (this.parent.tutorialStep)
+        {
+            case 0:
+                this.bgOpacity = 0;
+                this.textOpacity = 0;
+                break;
+            case 1:
+                this.bgOpacity = min(this.bgOpacity + 150 * delta, 200);
+                this.textOpacity = min(this.textOpacity + 150 * delta, 255);
+                this.text = "Que palavra está dentro da palavra CAQUI?"
+                if (this.textOpacity == 255) this.continueButton.show();
+                break;
+            case 2:
+                this.continueButton.hide();
+                this.bgOpacity = max(this.bgOpacity - 150 * delta, 0);
+                this.textOpacity = max(this.textOpacity - 150 * delta, 0);
+                this.text = "Que palavra está dentro da palavra CAQUI?"
+                break;
+            case 3:
+                this.bgOpacity = 0;
+                this.textOpacity = 0;
+                break;
+            case 9:
+                this.bgOpacity = min(this.bgOpacity + 150 * delta, 200);
+                this.textOpacity = min(this.textOpacity + 150 * delta, 255);
+                this.text = "A palavra dentro de CAQUI é AQUI.\n\nAgora é sua vez!"
+                if (this.textOpacity == 255) this.continueButton.show();
+                break;
+        }
+
+        db.noStroke();
+        db.fill(0, this.bgOpacity);
+        db.rectMode(CENTER);
+        db.rect(db.width / 2, db.height / 2, 1800, 600, 40, 40);
+        db.textAlign(CENTER, CENTER);
+        db.fill(255, this.textOpacity);
+        db.textSize(40);
+        db.text(this.text, db.width / 2, db.height / 2 - 100);
+    }
+
+    _onContinueButtonMouseClicked()
+    {
+        this.emitSignal("continue");
+    }
+}

+ 47 - 0
src/elements/earth/valise3/valise3leveldata.txt

@@ -0,0 +1,47 @@
+Caqui       Aqui, Casa, Quiabo, Pera
+Começa com a letra F.
+O que está dentro da palavra CAQUI?
+
+Floresta    Flor, Lobo, Régua, Árvore
+Começa com a letra A.
+O que está dentro da palavra FLORESTA?
+
+Maracujá    Já, Mata, Rato, Água
+Começa com a letra J.
+O que está dentro da palavra MARACUJÁ?
+
+Acordavam   Corda, Abacaxi, Vaca, Dado
+Começa com a letra C.
+O que está dentro da palavra ACORDAVAM?
+
+Melão       Mel, Lata, Não, Livro
+Começa com a letra M.
+O que está dentro da palavra MELÃO?
+
+Abacate     Aba, Bala, Telefone, Casa
+Começa com a letra A.
+O que está dentro da a palavra ABACATE?
+
+Goiaba      Aba, Gol, Gaiola, Baía
+Começa com a letra A.
+O que está dentro da palavra GOIABA?
+
+Chamou      Amou, Chama, Ouriço, Morcego
+Começa com a letra A.
+O que está dentro da palavra CHAMOU?
+
+Sementes    Mente, Seco, Teto, Nabo
+Começa com a letra M.
+O que está dentro da palavra SEMENTES?
+
+Limão       Mão, Livro, Caminhão, Miado
+Começa com a letra M.
+O que está dentro da palavra LIMÃO?
+
+Mexerica    Mexe, Caixa, Rica, Rio, Espelho
+Uma das palavras começa com a letra M, e a outra começa com a letra R.
+O que está dentro da palavra MEXERICA?
+
+Mexerica    Rica, Menino, Casa, Xadrez
+Começa com a letra R.
+O que está dentro da palavra MEXERICA?