浏览代码

adding cheat codes; adding better tutorials; adding win screen

Justin Gilman 3 周之前
父节点
当前提交
311c9595ab
共有 7 个文件被更改,包括 236 次插入17 次删除
  1. 62 1
      css/game.css
  2. 111 15
      game.js
  3. 15 0
      index.html
  4. 1 1
      main.js
  5. 30 0
      ui/gameoverui.js
  6. 3 0
      ui/mainmenuui.js
  7. 14 0
      ui/shopui.js

+ 62 - 1
css/game.css

@@ -202,7 +202,7 @@ button {
     gap: 0;
 }
 
-#currency-meter-container span{
+#currency-meter-container span {
     padding: 12px 0 12px 0;
     color: #7E674F;
 }
@@ -659,4 +659,65 @@ ul#potion-properties-list li {
 #shop-button-container button:hover {
     cursor: pointer;
     border-color: white;
+}
+
+
+
+/****************
+ * Game Over UI *
+ ****************/
+
+#game-over-container {
+    position: fixed;
+    top: 0;
+    left: 0;
+    display: none;
+    width: 100%;
+    height: 100vh;
+}
+
+#game-over-blackout {
+    width: 100%;
+    height: 100%;
+    background-color: black;
+    opacity: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+#game-over-panel {
+    width: 600px;
+    height: 400px;
+    text-align: center;
+    padding: 32px;
+    color: white;
+}
+
+#play-again-button-container {
+    width: 184px;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+#play-again-button-inner-container {
+    padding: 2px;
+    border-radius: 32px;
+    width: 180px;
+    background-color: var(--light-purple);
+}
+
+#play-again-button-container button {
+    font-size: 24px;
+    border: 4px solid var(--dark-purple);
+    color: white;
+    padding: 8px;
+    border-radius: 32px;
+    width: 180px;
+    background-color: var(--light-purple);
+}
+
+#play-again-button-container button:hover {
+    cursor: pointer;
+    border-color: white;
 }

+ 111 - 15
game.js

@@ -28,6 +28,7 @@ import * as potionInfo from './data/potions.json'
 import Shopper from './shopper.js'
 import { buildCanvasText } from './library/canvastext.js'
 import { hideGameStatusUI, updateGameStatusUI } from './ui/gamestatusui.js'
+import { gameOverUI, showGameOverUI } from './ui/gameoverui.js'
 
 export const GAME_SAVE_KEY = "spookonomics-v1"
 const raycast = new THREE.Raycaster()
@@ -167,6 +168,17 @@ async function customerBuilder(randomPotion, delay) {
     return shopper
 }
 
+export function sellTutorialPrompt(stageData) {
+    if(stageData.shopTutorial2.alreadySeen) {
+        return
+    }
+    stageData.shopInactivityHandle = setTimeout(() => {
+        gsap.to(stageData.shopTutorial2.material, {duration: 1.5, opacity: 1, onStart: () => {
+            stageData.shopTutorial2.castShadow = true
+        }})
+    }, 5000)
+}
+
 async function beginSell(game, stageData) {
     if (stageData.potionStocked.length < 1) {
         stageData.soundEffects['audio/witch_cackle1.ogg'].play()
@@ -178,6 +190,8 @@ async function beginSell(game, stageData) {
 
     stageData.isSellingPotions = true
 
+    sellTutorialPrompt(stageData)
+
     let randomPotions = []
     randomPotions.push(...stageData.potionStocked)
     randomPotions.push(...stageData.potionInventory)
@@ -446,6 +460,7 @@ export async function init(inGame) {
     stageData.brewTutorial1.position.z = 2.4
     stageData.brewTutorial1.position.y = 0.2
     stageData.brewTutorial1.rotateOnAxis(new THREE.Vector3(1, 0, 0), -Math.PI / 2)
+    stageData.brewTutorial1.alreadySeen = false
     stageData.brewTutorial1.material.opacity = 0
     stageData.brewTutorial1.castShadow = false
     game.scene.add(stageData.brewTutorial1)
@@ -584,12 +599,24 @@ export async function init(inGame) {
     stageData.shopTutorial1.position.x = -15.5
     stageData.shopTutorial1.position.z = 0.2
     stageData.shopTutorial1.position.y = 1.8
+    stageData.shopTutorial1.alreadySeen = false
 
     stageData.shopTutorial1.scale.set(0.6, 0.6, 0.6)
     stageData.shopTutorial1.material.opacity = 0
     stageData.shopTutorial1.castShadow = false
     game.scene.add(stageData.shopTutorial1)
 
+    stageData.shopTutorial2 = buildCanvasText("Pick the correct potion", { font: "72px Alice" })
+    stageData.shopTutorial2.position.x = -10
+    stageData.shopTutorial2.position.z = -3.4
+    stageData.shopTutorial2.position.y = 1.5
+    stageData.shopTutorial2.alreadySeen = false
+
+    stageData.shopTutorial2.scale.set(1, 1, 1)
+    stageData.shopTutorial2.material.opacity = 0
+    stageData.shopTutorial2.castShadow = false
+    game.scene.add(stageData.shopTutorial2)
+
     stageData.coin = await loadGltf(game, 'models/coin.gltf.glb')
     stageData.coin.position.x = -12
     stageData.coin.position.y = 1.1
@@ -734,6 +761,7 @@ export async function init(inGame) {
     navigationUI(game, stageData)
     brewUI(game, stageData)
     shopUI(game, stageData)
+    gameOverUI(game, stageData)
 
     updateGameStatusUI(game, stageData)
 
@@ -878,10 +906,11 @@ export function onClick() {
                         } else {
                             openShopUI(game, stageData)
 
-                            if (stageData.shopTutorial1.material.opacity == 1) {
+                            if (stageData.shopTutorial1.material.opacity > 0) {
                                 gsap.to(stageData.shopTutorial1.material, {
                                     duration: 1.5, opacity: 0, onComplete: () => {
                                         stageData.shopTutorial1.castShadow = false
+                                        stageData.shopTutorial1.alreadySeen = true
                                     }
                                 })
                             }
@@ -903,10 +932,11 @@ export function onClick() {
                             closeShopUI(game, stageData)
                         } else {
                             openShopUI(game, stageData)
-                            if (stageData.shopTutorial1.material.opacity == 1) {
+                            if (stageData.shopTutorial1.material.opacity > 0) {
                                 gsap.to(stageData.shopTutorial1.material, {
                                     duration: 1.5, opacity: 0, onComplete: () => {
                                         stageData.shopTutorial1.castShadow = false
+                                        stageData.shopTutorial1.alreadySeen = true
                                     }
                                 })
                             }
@@ -938,10 +968,22 @@ export function onClick() {
 
                     stageData.displayedPotions.forEach((potion) => {
                         if (isAChildOf(potion, intersect.object)) {
-
-
                             if (stageData.isSellingPotions) {
+                                if (stageData.sellInactivityHandle) {
+                                    clearTimeout(stageData.sellInactivityHandle)
+                                    stageData.sellInactivityHandle = 0
+                                }
+
                                 if (stageData.customers[0].isMatchingPotion(potion.potionData)) {
+                                    if (stageData.shopTutorial2.material.opacity > 0) {
+                                        gsap.to(stageData.shopTutorial2.material, {
+                                            duration: 1.5, opacity: 0, onComplete: () => {
+                                                stageData.shopTutorial2.castShadow = false
+                                                stageData.shopTutorial2.alreadySeen = true
+                                            }
+                                        })
+                                    }
+
                                     const firstCustomer = stageData.customers[0]
                                     firstCustomer.hideDesire()
                                     const potionMotionPath = [{ x: -11.5, y: 2.75, z: -3.25 }, { x: -12, y: 2, z: -2 }, { x: -13, y: 0.75, z: 2.5 }]
@@ -1040,10 +1082,11 @@ export function onClick() {
                         } else {
                             openBrewUI(game, stageData)
                             //cauldron.isBrewing = true
-                            if (stageData.brewTutorial1.material.opacity == 1) {
+                            if (stageData.brewTutorial1.material.opacity > 0) {
                                 gsap.to(stageData.brewTutorial1.material, {
                                     duration: 1.5, opacity: 0, onComplete: () => {
                                         stageData.brewTutorial1.castShadow = false
+                                        stageData.brewTutorial1.alreadySeen = true
                                     }
                                 })
                             }
@@ -1064,10 +1107,11 @@ export function onClick() {
                             closeBrewUI(game, stageData)
                         } else {
                             openBrewUI(game, stageData)
-                            if (stageData.brewTutorial1.material.opacity == 1) {
+                            if (stageData.brewTutorial1.material.opacity > 0) {
                                 gsap.to(stageData.brewTutorial1.material, {
                                     duration: 1.5, opacity: 0, onComplete: () => {
                                         stageData.brewTutorial1.castShadow = false
+                                        stageData.brewTutorial1.alreadySeen = true
                                     }
                                 })
                             }
@@ -1175,6 +1219,10 @@ function nextCustomer() {
         stageData.isSellingPotions = false
         stageData.currentDay = addAmountToSave("currentday", 1)
         updateGameStatusUI(game, stageData)
+
+        if(stageData.currency >= 1000) {
+            showGameOverUI(game, stageData)
+        }
     } else {
         stageData.customers[0].showDesire()
         if (stageData.potionStocked.length < 1) {
@@ -1331,17 +1379,21 @@ export function moveToRoom(roomId) {
     }
 }
 
-export function onKeyPress() {
+let keyHistory = []
+export function onKeyPress(code) {
     if (game.keyboard['Digit1'] && stageData.currentRoom == ROOM_BREW) {
         moveToRoom(ROOM_SHOP)
+        keyHistory = []
     }
 
     if (game.keyboard['Digit2'] && stageData.currentRoom != ROOM_BREW) {
         moveToRoom(ROOM_BREW)
+        keyHistory = []
     }
 
     if (game.keyboard['Digit3'] && stageData.currentRoom == ROOM_BREW) {
         moveToRoom(ROOM_MARKET)
+        keyHistory = []
     }
 
     if (game.keyboard['Digit9'] || game.keyboard['F9']) {
@@ -1350,18 +1402,62 @@ export function onKeyPress() {
             console.log(`position:`, game.camera.position)
             console.log(`focus:`, game.orbitControls.target)
             moveToRoom(stageData.currentRoom)
+            keyHistory = []
         }
     }
 
     if (game.keyboard['Escape']) {
-        closeBrewUI(game, stageData)
-        closeShopUI(game, stageData)
-        hideNavigationUI(game, stageData)
-        openMainMenuUI(game, stageData)
-        hideGameStatusUI(game, stageData)
-        stageData.currentRoom = ROOM_BREW
-        game.camera.position.copy(stageData.cameraPositions[3].camera)
-        game.lookAtFocus = stageData.cameraPositions[3].focus.clone()
+        returnToMainMenu(game, stageData)
+        keyHistory = []
+    }
+
+    keyHistory.push(code.replace("Key", ""))
+
+    const cheatcode = keyHistory.join("").toLowerCase()
+
+    if(cheatcode.includes("ghostbux")) {
+        keyHistory = []
+        stageData.currency += 1000
+        addAmountToSave("currency", 1000)
+        updateGameStatusUI(game, stageData)
+        stageData.soundEffects['audio/witch_cackle1.ogg'].play()
     }
+
+    if(cheatcode.includes("awesomesauce")) {
+        keyHistory = []
+        stageData.potionInventory.push(...stageData.potionInfo.map(info => info.name))
+        addValueToSave(stageData.potionInventory, "potion-inventory", "spooksauce")
+        stageData.soundEffects['audio/witch_cackle1.ogg'].play()
+    }
+
+    if(cheatcode.includes("yeschef")) {
+        keyHistory = []
+        //TODO: grant all ingredients
+        stageData.soundEffects['audio/witch_cackle1.ogg'].play()
+    }
+}
+
+export function returnToMainMenu(game, stageData) {
+    closeBrewUI(game, stageData)
+    closeShopUI(game, stageData)
+    hideNavigationUI(game, stageData)
+    openMainMenuUI(game, stageData)
+    hideGameStatusUI(game, stageData)
+    stageData.currentRoom = ROOM_BREW
+    game.camera.position.copy(stageData.cameraPositions[3].camera)
+    game.lookAtFocus = stageData.cameraPositions[3].focus.clone()
+    stageData.brewTutorial1.material.opacity = 0
+    stageData.brewTutorial1.castShadow = false
+    stageData.brewTutorial1.alreadySeen = false
+
+    stageData.shopTutorial1.material.opacity = 0
+    stageData.shopTutorial1.castShadow = false
+    stageData.shopTutorial1.alreadySeen = false
+
+    stageData.shopTutorial2.material.opacity = 0
+    stageData.shopTutorial2.castShadow = false
+    stageData.shopTutorial2.alreadySeen = false
+    updatePotionShelfDisplay()
+    updateGameStatusUI(game, stageData)
 }
 

+ 15 - 0
index.html

@@ -234,6 +234,21 @@
             </div>
         </div>
     </div>
+
+    <div id="game-over-container">
+        <div id="game-over-blackout">
+            <div id="game-over-panel">
+                <h1>You Win!</h1>
+                <p>You made 1000 gold in:</p>
+                <h2>8 days</h2>
+                <div id="play-again-button-container">
+                    <div id="play-again-button-inner-container">
+                        <button id="play-again">Play Again?</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
     <!-- Google tag (gtag.js) -->
 	<script async src="https://www.googletagmanager.com/gtag/js?id=G-H4BYTFBKJT"></script>
 	<script>

+ 1 - 1
main.js

@@ -100,7 +100,7 @@ export default async function main(canvasElement) {
         const lastKeyState = game.keyboard[event.code]
         game.keyboard[event.code] = true
         if (!lastKeyState) {
-            onKeyPress()
+            onKeyPress(event.code)
         }
     })
 

+ 30 - 0
ui/gameoverui.js

@@ -0,0 +1,30 @@
+import gsap from "gsap"
+import { clearSaveData, returnToMainMenu } from "../game.js"
+export function gameOverUI(game, stageData) {
+    document.getElementById("play-again").addEventListener('click', event => {
+        hideGameOverUI(game, stageData)
+
+        clearSaveData(stageData)
+        returnToMainMenu(game, stageData)
+    })
+}
+
+export function showGameOverUI(game, stageData) {
+    document.getElementById("game-over-container").style.display = "block"
+    const blackoutContainer = document.getElementById("game-over-blackout")
+    gsap.to(blackoutContainer, { duration: 2, opacity: 1 })
+
+    const gameOverPanel = document.getElementById("game-over-panel")
+    gameOverPanel.getElementsByTagName("p")[0].innerHTML = `You made ${stageData.currency} gold in:`
+    gameOverPanel.getElementsByTagName("h2")[0].innerHTML = `${stageData.currentDay - 1} days`
+}
+
+export function hideGameOverUI(game, stageData) {
+
+    const blackoutContainer = document.getElementById("game-over-blackout")
+    gsap.to(blackoutContainer, {
+        duration: 2, opacity: 0, onComplete: () => {
+            document.getElementById("game-over-container").style.display = "none"
+        }
+    })
+}

+ 3 - 0
ui/mainmenuui.js

@@ -4,6 +4,9 @@ import { clearSaveData, loadSaveData } from "../game.js"
 import { showGameStatusUI } from "./gamestatusui.js"
 
 export function brewTutorialPrompt(stageData) {
+    if(stageData.brewTutorial1.alreadySeen) {
+        return
+    }
     stageData.brewInactivityHandle = setTimeout(() => {
         gsap.to(stageData.brewTutorial1.material, {duration: 1.5, opacity: 1, onStart: () => {
             stageData.brewTutorial1.castShadow = true

+ 14 - 0
ui/shopui.js

@@ -3,6 +3,9 @@ import { addValueToSave, playBottleClink, removeValueFromSave, updatePotionShelf
 
 
 export function shopTutorialPrompt(stageData) {
+    if(stageData.shopTutorial1.alreadySeen) {
+        return
+    }
     stageData.shopInactivityHandle = setTimeout(() => {
         gsap.to(stageData.shopTutorial1.material, {duration: 1.5, opacity: 1, onStart: () => {
             stageData.shopTutorial1.castShadow = true
@@ -10,6 +13,17 @@ export function shopTutorialPrompt(stageData) {
     }, 5000)
 }
 
+export function potionTutorialPrompt(stageData) {
+    if(stageData.shopTutorial2.alreadySeen) {
+        return
+    }
+    stageData.sellInactivityHandle = setTimeout(() => {
+        gsap.to(stageData.shopTutorial2.material, {duration: 1.5, opacity: 1, onStart: () => {
+            stageData.shopTutorial2.castShadow = true
+        }})
+    }, 5000)
+}
+
 export async function shopUI(game, stageData) {
     document.getElementById("shop-container").addEventListener('click', () => {
         closeShopUI(game, stageData)