diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..b0f629698fd1741a98be988da63ec3db19db41aa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +static/assets/sounds/music.mp3 filter=lfs diff=lfs merge=lfs -text diff --git a/static/.DS_Store b/static/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7ccddc90ebba382fdec81b52e2d0effff29e4866 Binary files /dev/null and b/static/.DS_Store differ diff --git a/static/assets/.DS_Store b/static/assets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e8a9d331f978a801724362b7d9c863fdf3a5ac44 Binary files /dev/null and b/static/assets/.DS_Store differ diff --git a/static/assets/css/game-style.css b/static/assets/css/game-style.css new file mode 100644 index 0000000000000000000000000000000000000000..5fb4ddf23e4b4cc733e5112db7908c38cc515dfb --- /dev/null +++ b/static/assets/css/game-style.css @@ -0,0 +1,564 @@ + /* Layout */ + body { + margin: 0; + font-family: Arial, sans-serif; + display: flex; + background-color: #220a0a; + height: 100vh; + position: relative; + overflow: hidden; +} + +#gameContainer { + display: flex; + width: 100%; + height: 100vh; + overflow: auto; + position: relative; + z-index: 1; + align-items: center; +} + +#mapSection { + flex: 1; + min-width: 600px; + width: fit-content; + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + overflow: auto; + z-index: 2; + padding: 20px; +} + +/* We'll place the P5 canvas in here */ +.map-wrapper { + margin: 20px; + transform-origin: center center; + min-width: min-content; +} + +#chatSection { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + background: #000000; + border-radius: 38px; + overflow: hidden; +} + +#chatHistory { + flex: 1; + overflow-y: auto; + padding: 16px; + background: #f8f8fa; +} + +/* Style moderne pour la barre de scroll */ +#chatHistory::-webkit-scrollbar { + width: 6px; +} + +#chatHistory::-webkit-scrollbar-track { + background: transparent; +} + +#chatHistory::-webkit-scrollbar-thumb { + background: #d1d1d6; + border-radius: 3px; +} + +#chatControls { + padding: 16px; + background: #ffffff; + display: flex; + gap: 12px; + border-top: 1px solid #f1f1f5; +} + +.chat-message { + padding: 12px 16px; + margin: 6px 0; + border-radius: 20px; + max-width: 75%; + font-size: 0.95em; + line-height: 1.4; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.user-message { + background: #007aff; + color: white; + margin-left: auto; + border-radius: 20px 20px 4px 20px; +} + +.assistant-message { + background: #f1f1f5; + color: #000000; + margin-right: auto; + border-radius: 20px 20px 20px 4px; +} + +input { + flex: 1; + padding: 12px 16px; + border: none; + border-radius: 20px; + font-family: inherit; + font-size: 0.95em; + background: #f1f1f5; + transition: background 0.2s; +} + +input:focus { + outline: none; + background: #e5e5ea; +} + +input::placeholder { + color: #8e8e93; +} + +button { + padding: 8px; + width: 40px; + height: 40px; + background: #007aff; + color: white; + border: none; + border-radius: 20px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.2s, background 0.2s; +} + +button:hover { + background: #0056b3; + transform: scale(1.05); +} + +/* Style moderne pour l'indicateur de chargement */ +.loading-dots { + display: inline-flex; + gap: 4px; + padding: 8px 12px; + background: #f1f1f5; + border-radius: 16px; +} + +.dot { + width: 6px; + height: 6px; + background: #8e8e93; + border-radius: 50%; + animation: bounce 1.4s infinite ease-in-out; +} + +.dot:nth-child(1) { + animation-delay: -0.32s; +} + +.dot:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes bounce { + + 0%, + 80%, + 100% { + transform: scale(0); + } + + 40% { + transform: scale(1); + } +} + +/* Modal for API key (if needed) */ +#apiKeyModal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + justify-content: center; + align-items: center; +} + +.modal-content { + background: white; + padding: 20px; + border-radius: 8px; + width: 300px; +} + +#apiKey { + width: 100%; + margin: 10px 0; + padding: 8px; +} + +/* Modifier les styles du chat et du mockup */ +.phone-mockup { + position: relative; + width: 400px; + height: 800px; + background: url("/static/assets/img/phone.png") no-repeat center; + background-size: contain; + display: flex; + justify-content: center; + align-items: center; + margin: auto; + padding: 35px 0; + flex-shrink: 0; + z-index: 2; +} + +.phone-screen { + width: 90%; + height: 96.5%; + position: relative; + overflow: hidden; + margin: 0; + border-radius: 40px; + display: flex; + flex-direction: column; +} + +/* Update media queries for better responsiveness */ +@media (max-height: 900px) { + .phone-mockup { + width: 350px; + height: 700px; + } +} + +@media (max-height: 700px) { + .phone-mockup { + width: 300px; + height: 600px; + } +} + +@media (max-width: 1200px) { + #mapSection { + flex: none; + width: fit-content; + } +} + +@media (max-width: 900px) { + #mapSection { + flex: none; + width: fit-content; + } + .phone-mockup { + min-width: 280px; + } +} + +/* Ajouter les nouveaux styles pour l'en-tête du chat */ +#chatHeader { + padding: 16px; + justify-content: center; + background: #ffffff; + border-bottom: 1px solid #f1f1f5; + display: flex; + align-items: center; + gap: 12px; +} + +.profile-picture { + width: 40px; + height: 40px; + border-radius: 50%; + background: #f1f1f5; + display: flex; + align-items: center; + justify-content: center; +} + +.chat-name { + font-size: 1.1em; + font-weight: 600; + color: #000000; +} + +/* LED Bar */ +.led-bar { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 2px; + background: linear-gradient(90deg, + transparent 0%, + rgba(255, 0, 0, 0.4) 20%, + rgba(255, 0, 0, 0.8) 35%, + rgba(255, 50, 50, 1) 50%, + rgba(255, 0, 0, 0.8) 65%, + rgba(255, 0, 0, 0.4) 80%, + transparent 100%); + z-index: 100; + animation: ledFlicker 4s infinite, ledPulse 10s infinite; + box-shadow: 0 0 20px rgba(255, 0, 0, 0.7), + 0 0 35px rgba(255, 0, 0, 0.5), + 0 0 50px rgba(255, 0, 0, 0.4), + 0 0 70px rgba(155, 0, 0, 0.3); + filter: blur(0.6px); +} + +.light-beam { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 250px; + background: linear-gradient(180deg, + rgba(255, 0, 0, 0.3) 0%, + rgba(255, 0, 0, 0.2) 20%, + rgba(255, 0, 0, 0.15) 30%, + rgba(155, 0, 0, 0.08) 60%, + transparent 100%); + animation: beamFlicker 4s infinite; + pointer-events: none; + filter: blur(2px); +} + +@keyframes ledFlicker { + 0% { + opacity: 1; + } + + 95% { + opacity: 1; + } + + 96% { + opacity: 0.3; + } + + 97% { + opacity: 1; + } + + 98% { + opacity: 0.2; + } + + 99% { + opacity: 0.9; + } + + 100% { + opacity: 1; + } +} + +@keyframes ledPulse { + 0% { + filter: brightness(1) blur(0.6px); + } + + 50% { + filter: brightness(1.3) blur(0.4px); + } + + 100% { + filter: brightness(1) blur(0.6px); + } +} + +@keyframes beamFlicker { + 0% { + opacity: 0.7; + } + + 95% { + opacity: 0.7; + } + + 96% { + opacity: 0.2; + } + + 97% { + opacity: 0.7; + } + + 98% { + opacity: 0.1; + } + + 99% { + opacity: 0.6; + } + + 100% { + opacity: 0.7; + } +} + +/* Background Elements */ +.background-elements { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 1; +} + +.blood { + position: absolute; + top: 94%; + opacity: 0.6; + transform: rotate(20deg); + right: 10%; +} + +.blood-top-left { + top: 0; + left: 0; + width: 300px; +} + +.blood-top-right { + top: 0; + right: 0; + width: 200px; + transform: rotate(20deg); +} + +.splatter { + bottom: 20%; + left: 10%; + width: 200px; +} + +.blood-bottom-right { + bottom: 0; + right: 0; + position: absolute; + top: 90%; + left: 90%; + width: 200px; +} + +/* Sound button styles */ +.sound-button { + position: fixed; + bottom: 20px; + left: 20px; + width: 100px; + height: 100px; + cursor: pointer; + z-index: 1000; + transition: transform 0.2s ease; +} + +.sound-button:hover { + transform: scale(1.1); +} + +.sound-button img { + width: 100%; + height: 100%; + object-fit: contain; +} + +/* Update button styles */ +button { + padding: 8px; + width: 40px; + height: 40px; + background: #007aff; + color: white; + border: none; + border-radius: 10px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: transform 0.2s, background 0.2s; +} + +button img { + width: 15px; + height: 15px; + color: #ffffff; +} + +.numpad-overlay { + position: fixed; + top: 50%; + right: 52%; + transform: translateY(-50%); + background: rgba(0, 0, 0, 0.9); + padding: 20px; + border-radius: 10px; + z-index: 1000; +} + +.hidden { + display: none; +} + +.toggle-numpad { + position: fixed; + top: 20px; + right: 20px; + padding: 10px 15px; + font-size: 20px; + background: #333; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + z-index: 1001; +} + +.numpad-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + max-width: 300px; + margin: 10px auto; +} + +.numpad-key { + padding: 25px; + font-size: 27px; + border: 1px solid #444; + background: #333; + color: white; + cursor: pointer; + border-radius: 5px; +} + +.numpad-key:hover { + background: #444; +} + +.numpad-display { + text-align: center; + font-size: 24px; + margin: 10px; + letter-spacing: 5px; + color: white; +} + +/* Update input styles */ +input { + border-radius: 10px; +} \ No newline at end of file diff --git a/static/assets/css/index-style.css b/static/assets/css/index-style.css new file mode 100644 index 0000000000000000000000000000000000000000..af4955694973568ebd35c34e2edb5f72aeaa36af --- /dev/null +++ b/static/assets/css/index-style.css @@ -0,0 +1,446 @@ +@font-face { + font-family: "HorrorBrush"; + src: url("/static/assets/fonts/horrorbrush.ttf") format("truetype"); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background-color: #000000; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + position: relative; + overflow: hidden; +} + +.background-elements { + position: absolute; + width: 100%; + height: 100%; + pointer-events: none; +} + +.blood { + position: absolute; +} + +.blood-top-left { + top: 0; + left: 0; + width: 350px; + opacity: 50%; +} + +.blood-bottom-right { + bottom: 0; + right: 0; + width: 250px; + position: absolute; + bottom: -120px; + right: -50px; + opacity: 40%; +} + +.blood-top-right { + position: absolute; + top: 0; + right: 0; + width: 250px; + margin: 20px 20px 0px 0px; + transform: rotate(30deg); +} + +.splatter { + position: absolute; + opacity: 60%; + bottom: 240px; + left: 30%; + transform: translateX(-50%); + transform: rotate(20deg); + width: 400px; +} + +main { + display: flex; + flex-direction: column; + align-items: center; + gap: 100px; + z-index: 1; + margin-top: 200px; +} + +.logo { + position: absolute; + top: 40px; + left: 50%; + transform: translateX(-50%); + animation: flicker 4s linear infinite; +} + +.logo img { + width: 230px; + height: auto; +} + +.menu { + display: flex; + flex-direction: column; + gap: 30px; + align-items: center; + position: relative; +} + +.menu::after { + content: ""; + position: absolute; + width: 800px; + height: 800px; + background: radial-gradient( + circle, + rgba(155, 0, 0, 0.35) 0%, + rgba(0, 0, 0, 0) 70% + ); + z-index: -1; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.menu-item { + font-family: "HorrorBrush", cursive; + font-size: 48px; + color: #fff; + text-decoration: none; + transition: color 0.3s ease; + letter-spacing: 4px; + text-transform: uppercase; +} + +.new-game { + color: #9b0000; +} + +.menu-item:hover { + color: #9b0000; +} + +.how-to-play:hover { + color: #9b0000; +} + +.level-maker:hover { + color: #9b0000; +} + +@keyframes flicker { + 0% { + opacity: 1; + } + 5% { + opacity: 0.9; + } + 10% { + opacity: 1; + } + 15% { + opacity: 0.4; + } + 16% { + opacity: 1; + } + 17% { + opacity: 0.4; + } + 18% { + opacity: 1; + } + 35% { + opacity: 1; + } + 36% { + opacity: 0.3; + } + 37% { + opacity: 1; + } + 38% { + opacity: 0.5; + } + 39% { + opacity: 1; + } + 50% { + opacity: 1; + } + 51% { + opacity: 0.7; + } + 52% { + opacity: 1; + } + 53% { + opacity: 0.4; + } + 54% { + opacity: 1; + } + 85% { + opacity: 1; + } + 86% { + opacity: 0.6; + } + 87% { + opacity: 1; + } + 88% { + opacity: 0.4; + } + 89% { + opacity: 1; + } + 100% { + opacity: 1; + } +} + +.led-bar { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 2px; + background: linear-gradient( + 90deg, + transparent 0%, + rgba(255, 0, 0, 0.4) 20%, + rgba(255, 0, 0, 0.8) 35%, + rgba(255, 50, 50, 1) 50%, + rgba(255, 0, 0, 0.8) 65%, + rgba(255, 0, 0, 0.4) 80%, + transparent 100% + ); + z-index: 100; + animation: ledFlicker 4s infinite, ledPulse 10s infinite; + box-shadow: 0 0 20px rgba(255, 0, 0, 0.7), 0 0 35px rgba(255, 0, 0, 0.5), + 0 0 50px rgba(255, 0, 0, 0.4), 0 0 70px rgba(155, 0, 0, 0.3); + filter: blur(0.6px); +} + +.light-beam { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 250px; + background: linear-gradient( + 180deg, + rgba(255, 0, 0, 0.3) 0%, + rgba(255, 0, 0, 0.2) 20%, + rgba(255, 0, 0, 0.15) 30%, + rgba(155, 0, 0, 0.08) 60%, + transparent 100% + ); + animation: beamFlicker 4s infinite; + pointer-events: none; + filter: blur(2px); +} + +@keyframes ledFlicker { + 0% { + opacity: 1; + } + 95% { + opacity: 1; + } + 96% { + opacity: 0.3; + } + 97% { + opacity: 1; + } + 98% { + opacity: 0.2; + } + 99% { + opacity: 0.9; + } + 100% { + opacity: 1; + } +} + +@keyframes ledPulse { + 0% { + filter: brightness(1) blur(0.6px); + } + 50% { + filter: brightness(1.3) blur(0.4px); + } + 100% { + filter: brightness(1) blur(0.6px); + } +} + +@keyframes beamFlicker { + 0% { + opacity: 0.7; + } + 95% { + opacity: 0.7; + } + 96% { + opacity: 0.2; + } + 97% { + opacity: 0.7; + } + 98% { + opacity: 0.1; + } + 99% { + opacity: 0.6; + } + 100% { + opacity: 0.7; + } +} + +/* How to Play Page Styles */ +.content { + color: #fff; + text-align: center; + max-width: 800px; + margin: 40px auto; + padding: 20px; +} + +.content h1 { + font-family: "HorrorBrush", cursive; + font-size: 64px; + color: #9b0000; + position: absolute; + top: 40px; + left: 50%; + transform: translateX(-50%); + letter-spacing: 4px; +} + +.back-button { + font-family: "HorrorBrush", cursive; + font-size: 36px; + color: #fff; + text-decoration: none; + transition: color 0.3s ease; + letter-spacing: 4px; + text-transform: uppercase; + position: absolute; + bottom: 40px; + left: 50%; + transform: translateX(-50%); +} + +.back-button:hover { + color: #9b0000; +} + +.character { + position: absolute; + bottom: -30px; + left: 50%; + transform: translateX(-50%); + z-index: 2; + animation: characterFlicker 6s infinite; +} + +.character img { + width: 550px; + height: auto; +} + +@keyframes characterFlicker { + 0% { + opacity: 1; + filter: brightness(1); + } + 42% { + opacity: 1; + filter: brightness(1); + } + 43% { + opacity: 0.8; + filter: brightness(1.2); + } + 44% { + opacity: 1; + filter: brightness(1); + } + 45% { + opacity: 0.6; + filter: brightness(1.3); + } + 46% { + opacity: 1; + filter: brightness(1); + } + 47% { + opacity: 0.2; + filter: brightness(1.5); + } + 48% { + opacity: 1; + filter: brightness(1); + } + 49% { + opacity: 0.4; + filter: brightness(1.2); + } + 50% { + opacity: 1; + filter: brightness(1); + } + 80% { + opacity: 1; + filter: brightness(1); + } + 81% { + opacity: 0.5; + filter: brightness(1.3); + } + 82% { + opacity: 1; + filter: brightness(1); + } + 100% { + opacity: 1; + filter: brightness(1); + } +} + +/* Modifier les styles pour le bouton son */ +.sound-button { + position: fixed; + bottom: 20px; + left: 20px; + width: 100px; + height: 100px; + cursor: pointer; + z-index: 1000; + transition: transform 0.2s ease; +} + +.sound-button:hover { + transform: scale(1.1); +} + +.sound-button img { + width: 100%; + height: 100%; + object-fit: contain; +} diff --git a/static/assets/fonts/horrorbrush.ttf b/static/assets/fonts/horrorbrush.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cc3a26dc32448f7236ba970fbdc06a965a53889b Binary files /dev/null and b/static/assets/fonts/horrorbrush.ttf differ diff --git a/static/assets/img/.DS_Store b/static/assets/img/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..725a257e0e67d0ddb2a3f703bbd8bfa7a9710151 Binary files /dev/null and b/static/assets/img/.DS_Store differ diff --git a/static/assets/img/appartment/.DS_Store b/static/assets/img/appartment/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ed53d85b57af3f59a874e1f6e6f1c5e4fad4bca8 Binary files /dev/null and b/static/assets/img/appartment/.DS_Store differ diff --git a/static/assets/img/appartment/BaseMap.PNG b/static/assets/img/appartment/BaseMap.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a54fd86eb10555d06d878cf3519aaa70fe2bc243 Binary files /dev/null and b/static/assets/img/appartment/BaseMap.PNG differ diff --git a/static/assets/img/appartment/BedroomDoorLocked.PNG b/static/assets/img/appartment/BedroomDoorLocked.PNG new file mode 100644 index 0000000000000000000000000000000000000000..abc1cb7c6324e704942828c68dc367f50f7261b5 Binary files /dev/null and b/static/assets/img/appartment/BedroomDoorLocked.PNG differ diff --git a/static/assets/img/appartment/BedroomDoorUnlocked.PNG b/static/assets/img/appartment/BedroomDoorUnlocked.PNG new file mode 100644 index 0000000000000000000000000000000000000000..be014abddcca57c7b21b536b5a48dc7c0e905597 Binary files /dev/null and b/static/assets/img/appartment/BedroomDoorUnlocked.PNG differ diff --git a/static/assets/img/appartment/BookcaseSearchable.PNG b/static/assets/img/appartment/BookcaseSearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..fb02650bbe98874222ef85a3c5feb825ec2d6b88 Binary files /dev/null and b/static/assets/img/appartment/BookcaseSearchable.PNG differ diff --git a/static/assets/img/appartment/BookcaseUnusuable.PNG b/static/assets/img/appartment/BookcaseUnusuable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a49fd9d7ff5c12f7e3c5d3ae0f06175e7e5ea36e Binary files /dev/null and b/static/assets/img/appartment/BookcaseUnusuable.PNG differ diff --git a/static/assets/img/appartment/BookcaseUsable.PNG b/static/assets/img/appartment/BookcaseUsable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..486920f1896f20ac751ec92358956cffe6cb9e91 Binary files /dev/null and b/static/assets/img/appartment/BookcaseUsable.PNG differ diff --git a/static/assets/img/appartment/CabinetSearchable.PNG b/static/assets/img/appartment/CabinetSearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..3dbe2161d2437958de2586ff14e5261151bbed56 Binary files /dev/null and b/static/assets/img/appartment/CabinetSearchable.PNG differ diff --git a/static/assets/img/appartment/CabinetUnsearchable.PNG b/static/assets/img/appartment/CabinetUnsearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..4b21ee96ff269f3adc2a429d1e81510a7bfee5b3 Binary files /dev/null and b/static/assets/img/appartment/CabinetUnsearchable.PNG differ diff --git a/static/assets/img/appartment/CoffeeTableUnusable.PNG b/static/assets/img/appartment/CoffeeTableUnusable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..f2f62934cb96d71efef7c9d3ea6d81ab875a2af7 Binary files /dev/null and b/static/assets/img/appartment/CoffeeTableUnusable.PNG differ diff --git a/static/assets/img/appartment/CoffeeTableUsable.PNG b/static/assets/img/appartment/CoffeeTableUsable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..4bfd68bb5c2fabd833adf6002f5d5fadd6631601 Binary files /dev/null and b/static/assets/img/appartment/CoffeeTableUsable.PNG differ diff --git a/static/assets/img/appartment/DeadBodyUnusable.PNG b/static/assets/img/appartment/DeadBodyUnusable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..8c09ae3ba550cdb0b6885fec3a4ce8329eeea701 Binary files /dev/null and b/static/assets/img/appartment/DeadBodyUnusable.PNG differ diff --git a/static/assets/img/appartment/DeadBodyUsable.PNG b/static/assets/img/appartment/DeadBodyUsable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..fb9bdabbbcb8420df1ec3512ac7a86f7947558b7 Binary files /dev/null and b/static/assets/img/appartment/DeadBodyUsable.PNG differ diff --git a/static/assets/img/appartment/DeskSearchable.PNG b/static/assets/img/appartment/DeskSearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..b2048460fa349ecbd0789d258b65584bf51f8936 Binary files /dev/null and b/static/assets/img/appartment/DeskSearchable.PNG differ diff --git a/static/assets/img/appartment/DeskUnsearchable.PNG b/static/assets/img/appartment/DeskUnsearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..8a7a2fc86f9707f426a111a23d2b23afdd350730 Binary files /dev/null and b/static/assets/img/appartment/DeskUnsearchable.PNG differ diff --git a/static/assets/img/appartment/DresserSearchable.PNG b/static/assets/img/appartment/DresserSearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..6d6a32903e473fe1a3911c6b0257dcd7a2b33127 Binary files /dev/null and b/static/assets/img/appartment/DresserSearchable.PNG differ diff --git a/static/assets/img/appartment/DresserUnsearchable.PNG b/static/assets/img/appartment/DresserUnsearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..833a10311ffe32d61edc524154472d6ab54e0fbd Binary files /dev/null and b/static/assets/img/appartment/DresserUnsearchable.PNG differ diff --git a/static/assets/img/appartment/FinalMap.PNG b/static/assets/img/appartment/FinalMap.PNG new file mode 100644 index 0000000000000000000000000000000000000000..0744faa5ba4eb84a12da8b97c46c9eb119b44ed0 Binary files /dev/null and b/static/assets/img/appartment/FinalMap.PNG differ diff --git a/static/assets/img/appartment/FridgeSearchable.PNG b/static/assets/img/appartment/FridgeSearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..28ae5f231a3a603c6b9013ea5938fa63ed30fbda Binary files /dev/null and b/static/assets/img/appartment/FridgeSearchable.PNG differ diff --git a/static/assets/img/appartment/FridgeUnsearchable.PNG b/static/assets/img/appartment/FridgeUnsearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..5fbeedb115d6040a166675333836c490c75f64bb Binary files /dev/null and b/static/assets/img/appartment/FridgeUnsearchable.PNG differ diff --git a/static/assets/img/appartment/GeneratorOff.PNG b/static/assets/img/appartment/GeneratorOff.PNG new file mode 100644 index 0000000000000000000000000000000000000000..00361e54672653d31a4a021286e8f034ac31a8d8 Binary files /dev/null and b/static/assets/img/appartment/GeneratorOff.PNG differ diff --git a/static/assets/img/appartment/GeneratorOn.PNG b/static/assets/img/appartment/GeneratorOn.PNG new file mode 100644 index 0000000000000000000000000000000000000000..5c329b34cb11da5188548e6c622702ad6f46540a Binary files /dev/null and b/static/assets/img/appartment/GeneratorOn.PNG differ diff --git a/static/assets/img/appartment/MainEntranceOpen.PNG b/static/assets/img/appartment/MainEntranceOpen.PNG new file mode 100644 index 0000000000000000000000000000000000000000..236c5b8d469feaa536747279aaa9145126da771b Binary files /dev/null and b/static/assets/img/appartment/MainEntranceOpen.PNG differ diff --git a/static/assets/img/appartment/StorageLocked.png b/static/assets/img/appartment/StorageLocked.png new file mode 100644 index 0000000000000000000000000000000000000000..70e01fc57e8bb61a454290d16bac0ab73fbcc5a2 Binary files /dev/null and b/static/assets/img/appartment/StorageLocked.png differ diff --git a/static/assets/img/appartment/StorageUnlocked.png b/static/assets/img/appartment/StorageUnlocked.png new file mode 100644 index 0000000000000000000000000000000000000000..e5060fe72e45303e02f00677614d5881ce923f79 Binary files /dev/null and b/static/assets/img/appartment/StorageUnlocked.png differ diff --git a/static/assets/img/appartment/StoveSearchable.PNG b/static/assets/img/appartment/StoveSearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..a83683cfbbbca1a4393ce6673df44e30e11f37a5 Binary files /dev/null and b/static/assets/img/appartment/StoveSearchable.PNG differ diff --git a/static/assets/img/appartment/StoveUnsearchable.PNG b/static/assets/img/appartment/StoveUnsearchable.PNG new file mode 100644 index 0000000000000000000000000000000000000000..04b89e03acc5d48fdb30784577ae11ad122d33d4 Binary files /dev/null and b/static/assets/img/appartment/StoveUnsearchable.PNG differ diff --git a/static/assets/img/appartment/TVUnused.PNG b/static/assets/img/appartment/TVUnused.PNG new file mode 100644 index 0000000000000000000000000000000000000000..8d5de282862c9022e38c963b6ee2877cb4ccc604 Binary files /dev/null and b/static/assets/img/appartment/TVUnused.PNG differ diff --git a/static/assets/img/appartment/TVUsed.PNG b/static/assets/img/appartment/TVUsed.PNG new file mode 100644 index 0000000000000000000000000000000000000000..02b66a41dbf27bcbff0ce1a528d892950caf325f Binary files /dev/null and b/static/assets/img/appartment/TVUsed.PNG differ diff --git a/static/assets/img/appartment/TheExit.png b/static/assets/img/appartment/TheExit.png new file mode 100644 index 0000000000000000000000000000000000000000..ff946e5a66f786fb8830e40ab0ff2480feeec815 Binary files /dev/null and b/static/assets/img/appartment/TheExit.png differ diff --git a/static/assets/img/blood-2.png b/static/assets/img/blood-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9e2eb72bd887d887f4cd4ccdbaa32f810d93d8fd Binary files /dev/null and b/static/assets/img/blood-2.png differ diff --git a/static/assets/img/clown.PNG b/static/assets/img/clown.PNG new file mode 100644 index 0000000000000000000000000000000000000000..0fef91c8084f74b728c8ceb381bedda30a6ccaab Binary files /dev/null and b/static/assets/img/clown.PNG differ diff --git a/static/assets/img/gf.png b/static/assets/img/gf.png new file mode 100644 index 0000000000000000000000000000000000000000..3b887c66fc943f2a6530634a0e268264cf631d71 Binary files /dev/null and b/static/assets/img/gf.png differ diff --git a/static/assets/img/hand.png b/static/assets/img/hand.png new file mode 100644 index 0000000000000000000000000000000000000000..9716650fc59e9796778cd76449bc7ee66674e258 Binary files /dev/null and b/static/assets/img/hand.png differ diff --git a/static/assets/img/help.png b/static/assets/img/help.png new file mode 100644 index 0000000000000000000000000000000000000000..31a18a6a7244bab03da08a4c6e5a4ab9cd61cd41 Binary files /dev/null and b/static/assets/img/help.png differ diff --git a/static/assets/img/logo.png b/static/assets/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fa702e7cdc9d0216a780c3bf48f3451a265799b9 Binary files /dev/null and b/static/assets/img/logo.png differ diff --git a/static/assets/img/perso.png b/static/assets/img/perso.png new file mode 100644 index 0000000000000000000000000000000000000000..cb1a1fb621d7c613162c40ae6965c2862bd0ab70 Binary files /dev/null and b/static/assets/img/perso.png differ diff --git a/static/assets/img/phone.png b/static/assets/img/phone.png new file mode 100644 index 0000000000000000000000000000000000000000..7fcadfa3188d597eadb74dc7cd1b84fca61a9967 Binary files /dev/null and b/static/assets/img/phone.png differ diff --git a/static/assets/img/sondon.png b/static/assets/img/sondon.png new file mode 100644 index 0000000000000000000000000000000000000000..6a04f983ad2ee8ae2b8294b4feaea7bb20593636 Binary files /dev/null and b/static/assets/img/sondon.png differ diff --git a/static/assets/img/soundoff.png b/static/assets/img/soundoff.png new file mode 100644 index 0000000000000000000000000000000000000000..7dbb6b031438e741348e59a4579f746ae00ce09a Binary files /dev/null and b/static/assets/img/soundoff.png differ diff --git a/static/assets/img/splatter.png b/static/assets/img/splatter.png new file mode 100644 index 0000000000000000000000000000000000000000..940e296de08a5b6849668a64aaf9d076b9e5d720 Binary files /dev/null and b/static/assets/img/splatter.png differ diff --git a/static/assets/img/vite.svg b/static/assets/img/vite.svg new file mode 100644 index 0000000000000000000000000000000000000000..e7b8dfb1b2a60bd50538bec9f876511b9cac21e3 --- /dev/null +++ b/static/assets/img/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/assets/sounds/message.wav b/static/assets/sounds/message.wav new file mode 100644 index 0000000000000000000000000000000000000000..406605a104a0d50291553c943fc22e541ebd5985 Binary files /dev/null and b/static/assets/sounds/message.wav differ diff --git a/static/assets/sounds/music.mp3 b/static/assets/sounds/music.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..bbcfb0852301d2ee59e37212fe58d90e12b3a6b8 --- /dev/null +++ b/static/assets/sounds/music.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2769acb745016d935744bff69f2eaa00694342c0deb4b1b693e8a8ae33726fa3 +size 4546560 diff --git a/static/assets/sounds/walking.mp3 b/static/assets/sounds/walking.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..25516f159034a4bbca0a0e370f4172350b9dc75c Binary files /dev/null and b/static/assets/sounds/walking.mp3 differ diff --git a/static/game/dev/index.html b/static/game/dev/index.html new file mode 100644 index 0000000000000000000000000000000000000000..c1acf56f4f0ed35ed5fddf0516c79f81210d1f49 --- /dev/null +++ b/static/game/dev/index.html @@ -0,0 +1,131 @@ + + + + + Get Me Out! - Development Grid View + + + + +
+
+ +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/static/game/dev/mistral_backup.js b/static/game/dev/mistral_backup.js new file mode 100644 index 0000000000000000000000000000000000000000..2e95e32a817b249619492b506cda2434b460a9a6 --- /dev/null +++ b/static/game/dev/mistral_backup.js @@ -0,0 +1,50 @@ +class MistralAPI { + constructor() { + this.apiKey = localStorage.getItem('mistralApiKey'); + this.temperature = 0.7; // Default temperature + } + + setApiKey(key) { + this.apiKey = key; + localStorage.setItem('mistralApiKey', key); + } + + getApiKey() { + return this.apiKey; + } + + setTemperature(temp) { + // Ensure temperature is between 0 and 1 + this.temperature = Math.max(0, Math.min(1, temp)); + } + + getTemperature() { + return this.temperature; + } + + async sendMessage(messages) { + if (!this.apiKey) { + throw new Error('API key not set'); + } + + const response = await fetch('https://api.mistral.ai/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.apiKey}` + }, + body: JSON.stringify({ + model: 'mistral-large-latest', + messages: messages, + temperature: this.temperature // Add temperature to the request + }) + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + return data.choices[0].message.content; + } +} \ No newline at end of file diff --git a/static/game/elmnts/apt.js b/static/game/elmnts/apt.js new file mode 100644 index 0000000000000000000000000000000000000000..9b55d2f299e1afe773bf440b834342c4363e325d --- /dev/null +++ b/static/game/elmnts/apt.js @@ -0,0 +1,181 @@ +function getApt() { + return { + "gridCols": 32, + "gridRows": 20, + "girlfriend_start_pos": { + "x": 7, + "y": 16 + }, + "clown_start_pos": { + "x": 1, + "y": 3 + }, + "rooms": [ + { + "name": "Kitchen", + "label_position": { + "x": 28, + "y": 3 + }, + "start_col": 26, + "end_col": 30, + "start_row": 1, + "end_row": 5, + "hiding_places": [] + }, + { + "name": "Storage", + "label_position": { + "x": 3, + "y": 3 + }, + "start_col": 1, + "end_col": 5, + "start_row": 1, + "end_row": 5, + "hiding_places": [ + { + "name": "closet", + "hiding_type": "in", + "position": { + "x": 1, + "y": 2 + } + } + ] + }, + { + "name": "My Bedroom", + "label_position": { + "x": 7, + "y": 14 + }, + "start_col": 1, + "end_col": 8, + "start_row": 13, + "end_row": 18, + "hiding_places": [ + { + "name": "bed", + "hiding_type": "under", + "position": { + "x": 4, + "y": 14 + } + } + ] + }, + { + "name": "Bathroom", + "label_position": { + "x": 16, + "y": 10 + }, + "start_col": 15, + "end_col": 17, + "start_row": 7, + "end_row": 12, + "hiding_places": [ + { + "name": "bathtub", + "hiding_type": "in", + "position": { + "x": 15, + "y": 7 + } + } + ] + }, + { + "name": "Main Hallway", + "label_position": { + "x": 14, + "y": 15 + }, + "start_col": 10, + "end_col": 17, + "start_row": 13, + "end_row": 18, + "hiding_places": [] + }, + { + "name": "Living Room", + "label_position": { + "x": 21, + "y": 15 + }, + "start_col": 19, + "end_col": 24, + "start_row": 13, + "end_row": 18, + "hiding_places": [] + }, + { + "name": "Guest Bedroom", + "label_position": { + "x": 28, + "y": 15 + }, + "start_col": 26, + "end_col": 30, + "start_row": 13, + "end_row": 18, + "hiding_places": [ + { + "name": "bed", + "hiding_type": "under", + "position": { + "x": 28, + "y": 18 + } + } + ] + }, + { + "name": "Dining Room", + "label_position": { + "x": 16, + "y": 3 + }, + "start_col": 14, + "end_col": 24, + "start_row": 1, + "end_row": 5, + "hiding_places": [ + { + "name": "table", + "hiding_type": "under", + "position": { + "x": 20, + "y": 3 + } + } + ] + }, + { + "name": "Office", + "label_position": { + "x": 21, + "y": 9 + }, + "start_col": 19, + "end_col": 24, + "start_row": 7, + "end_row": 11, + "hiding_places": [] + }, + { + "name": "North Hallway", + "label_position": { + "x": 9, + "y": 3 + }, + "start_col": 7, + "end_col": 12, + "start_row": 3, + "end_row": 3, + "hiding_places": [] + } + ] + } +} \ No newline at end of file diff --git a/static/game/elmnts/character.js b/static/game/elmnts/character.js new file mode 100644 index 0000000000000000000000000000000000000000..b3bed138c340ea4083cafecff556b4fe6364e4f9 --- /dev/null +++ b/static/game/elmnts/character.js @@ -0,0 +1,133 @@ +class Character { + constructor(gameState, characterImg) { + this.gameState = gameState; + this.characterImg = characterImg; + this.characterPos = null; + this.previousPos = null; + this.path = []; + this.isMoving = false; + this.moveInterval = null; + this.img = characterImg; + this.speed = 270; + } + + getCharacterPosition() { + return this.characterPos; + } + + setCharacterPosition(pos) { + this.characterPos = pos; + } + + getCurrentRoom() { + if (!this.characterPos) return null; + + // Check each room's boundaries to find which room contains the current position + for (const room of this.gameState.map_data.rooms) { + if (this.characterPos.x >= room.start_col && + this.characterPos.x <= room.end_col && + this.characterPos.y >= room.start_row && + this.characterPos.y <= room.end_row) { + return room.name; + } + } + return null; // Return null if not in any room + } + + drawPath(CELL_SIZE) { + if (this.path.length > 0 && this.isMoving) { + noFill(); + stroke(255, 0, 0); + strokeWeight(2); + line( + this.characterPos.x * CELL_SIZE + CELL_SIZE / 2, + this.characterPos.y * CELL_SIZE + CELL_SIZE / 2, + this.path[0].x * CELL_SIZE + CELL_SIZE / 2, + this.path[0].y * CELL_SIZE + CELL_SIZE / 2 + ); + for (let i = 0; i < this.path.length - 1; i++) { + line( + this.path[i].x * CELL_SIZE + CELL_SIZE / 2, + this.path[i].y * CELL_SIZE + CELL_SIZE / 2, + this.path[i + 1].x * CELL_SIZE + CELL_SIZE / 2, + this.path[i + 1].y * CELL_SIZE + CELL_SIZE / 2 + ); + } + strokeWeight(1); + } + } + + moveCharacterAlongPath(callback=null) { + if (this.moveInterval) { + clearInterval(this.moveInterval); + } + this.isMoving = true; + this.moveInterval = setInterval(() => { + if (this.path.length === 0) { + this.isMoving = false; + clearInterval(this.moveInterval); + if (callback) callback(); + return; + } + this.previousPos = { ...this.characterPos }; + const nextPos = this.path.shift(); + this.characterPos = nextPos; + }, this.speed); + } + + findPath(start, end) { + const queue = [[start]]; + const visited = new Set(); + const key = pos => `${pos.x},${pos.y}`; + visited.add(key(start)); + + while (queue.length > 0) { + const currentPath = queue.shift(); + const current = currentPath[currentPath.length - 1]; + + if (current.x === end.x && current.y === end.y) { + return currentPath; + } + const neighbors = [ + { x: current.x, y: current.y - 1 }, + { x: current.x + 1, y: current.y }, + { x: current.x, y: current.y + 1 }, + { x: current.x - 1, y: current.y } + ]; + for (const next of neighbors) { + if (next.x < 0 || next.x >= GRID_COLS || next.y < 0 || next.y >= GRID_ROWS) continue; + if (visited.has(key(next))) continue; + + const cell = this.gameState.map_data.grid[next.y][next.x]; + if (cell.type === 'wall') continue; + + visited.add(key(next)); + queue.push([...currentPath, next]); + } + } + return []; + } + + moveToPosition(pos,callback=null) { + if (!pos || !this.characterPos) return false; + + this.path = this.findPath(this.characterPos, pos); + if (this.path.length > 0) { + this.isMoving = true; + this.moveCharacterAlongPath(callback); + return true; + } + return false; + } + // Movement methods + moveToRoom(roomName) { + const targetRoom = this.gameState.map_data.rooms + .find(room => room.name.toLowerCase() === roomName.toLowerCase()); + if (!targetRoom || !this.characterPos) return false; + + const destination = targetRoom.label_position; + if (!destination) return false; + this.moveToPosition(destination); + } + +} \ No newline at end of file diff --git a/static/game/elmnts/clown.js b/static/game/elmnts/clown.js new file mode 100644 index 0000000000000000000000000000000000000000..918f6df68e2de6e8597fbf4184f8be1efeb20dfd --- /dev/null +++ b/static/game/elmnts/clown.js @@ -0,0 +1,161 @@ +class Clown extends Character { + constructor(gameState, clownImg) { + super(gameState, clownImg); + this.isChasing = false; + this.targetGirlfriend = null; + this.gameState.clown = this; + this.startAutonomousBehavior(); + this.setCharacterPosition(this.gameState.map_data.clown_start_pos); + + // Add initial speed properties + this.baseSpeed = 600; // Starting movement delay in milliseconds + this.minSpeed = 100; // Fastest possible speed + this.speedIncreaseInterval = 150000; // Speed increases every 30 seconds + this.speedIncreaseAmount = 100; // How much to decrease delay each time + + // Start the speed increase timer + this.startSpeedIncrease(); + } + + startAutonomousBehavior() { + if (this.behaviorInterval) { + clearInterval(this.behaviorInterval); + } + + this.behaviorInterval = setInterval(() => { + this.decideBehavior(); + }, 3000); + } + + decideBehavior() { + if (!this.isMoving) { + const roomEntries = this.gameState.map_data.rooms; + + if (this.targetGirlfriend && !this.gameState.girlfriend.isHiding) { + const girlfriendPos = this.targetGirlfriend.getCharacterPosition(); + if (girlfriendPos) { + this.path = this.findPath(this.characterPos, girlfriendPos); + if (this.path.length > 0) { + this.isChasing = true; + this.moveCharacterAlongPath(); + return; + } + } + } + + this.isChasing = false; + this.targetGirlfriend = null; + + const randomRoom = + roomEntries[Math.floor(Math.random() * roomEntries.length)]; + if (randomRoom) { + this.path = this.findPath(this.characterPos, randomRoom.label_position); + if (this.path.length > 0) { + this.moveCharacterAlongPath(); + } + } + } + } + + checkForGirlfriend(girlfriend) { + // First check if girlfriend exists and has a position + if ( + !this.gameState.girlfriend || + !this.characterPos || + this.gameState.girlfriend.isHiding || // Check if girlfriend is hiding + this.gameState.girlfriend.getIsHiding() // Also check using the getter method + ) { + this.targetGirlfriend = null; + this.isChasing = false; // Stop chasing if was chasing before + return; + } + + const girlfriendPos = this.gameState.girlfriend.getCharacterPosition(); + if (!girlfriendPos) return; + + // First check if in same room + const clownRoom = this.getCurrentRoom(); + const girlfriendRoom = this.gameState.girlfriend.getCurrentRoom(); + + if (clownRoom && girlfriendRoom && clownRoom === girlfriendRoom) { + // Check if within 3 cells in any direction + const xDistance = Math.abs(this.characterPos.x - girlfriendPos.x); + const yDistance = Math.abs(this.characterPos.y - girlfriendPos.y); + + if (xDistance <= 3 && yDistance <= 3) { + this.targetGirlfriend = girlfriend; + // Immediately update path to chase + if (!this.isChasing) { + this.path = this.findPath(this.characterPos, girlfriendPos); + if (this.path.length > 0) { + this.isChasing = true; + this.moveCharacterAlongPath(); + } + } + } + } else { + // Not in same room, stop chasing + this.isChasing = false; + this.targetGirlfriend = null; + } + } + + draw(CELL_SIZE) { + if (this.characterPos) { + const newSize = CELL_SIZE * 3; // Increased from 2x to 3x for 50% bigger + const offset = (newSize - CELL_SIZE) / 2; + push(); + if (this.previousPos && this.characterPos.x > this.previousPos.x) { + scale(-1, 1); + image( + this.img, + -this.characterPos.x * CELL_SIZE - newSize + offset, + this.characterPos.y * CELL_SIZE - offset, + newSize, + newSize + ); + } else { + image( + this.img, + this.characterPos.x * CELL_SIZE - offset, + this.characterPos.y * CELL_SIZE - offset, + newSize, + newSize + ); + } + pop(); + } + } + + moveCharacterAlongPath() { + if (this.path && this.path.length > 0) { + this.isMoving = true; + const nextPos = this.path.shift(); + this.previousPos = { ...this.characterPos }; + this.characterPos = nextPos; + + // Use the current speed for movement delay + setTimeout(() => { + this.isMoving = false; + if (this.path.length > 0) { + this.moveCharacterAlongPath(); + } + }, this.baseSpeed); + } + } + + startSpeedIncrease() { + // Increase speed every 30 seconds + setInterval(() => { + if (this.baseSpeed > this.minSpeed) { + this.baseSpeed = Math.max( + this.baseSpeed - this.speedIncreaseAmount, + this.minSpeed + ); + console.log( + `Clown speed increased! Current delay: ${this.baseSpeed}ms` + ); + } + }, this.speedIncreaseInterval); + } +} diff --git a/static/game/elmnts/furniture.js b/static/game/elmnts/furniture.js new file mode 100644 index 0000000000000000000000000000000000000000..ff1c9c567233cc1431864eaa7ebf09f5b21d52db --- /dev/null +++ b/static/game/elmnts/furniture.js @@ -0,0 +1,305 @@ +function getFurniture() { + return [ + { + "name": "Dresser", + "room": "My Bedroom", + "pos": { + "x": 3, + "y": 17 + }, + "reward": "lockpick", + "state": "unsearchable", + "in_use": false, + "search_msg":"Ok um, I think this is a lockpick 🔐. Why do you even have this?", + "sprite": [ + { + "for": "searchable", + "img": "/assets/img/appartment/DresserSearchable.PNG" + }, + { + "for": "unsearchable", + "img": "/assets/img/appartment/DresserUnsearchable.PNG" + } + ] + }, + { + "name": "Bedroom Door", + "room": "My Bedroom", + "locked": true, + "wall_pos": { + "x": 9, + "y": 15 + }, + "stop_pos":{ + "x": 8, + "y": 15 + } + , + "state": "unlocked", + "in_use": false, + "locked_message":"It's locked, I can't get out!! Why is it locked??", + "unlocked_message":"Ok it's open! 🥳", + "sprite": [ + { + "for": "locked", + "img": "/assets/img/appartment/BedroomDoorLocked.PNG" + }, + { + "for": "unlocked", + "img": "/assets/img/appartment/BedroomDoorUnlocked.PNG" + } + ] + }, + { + "name": "Coffee Table", + "room": "living", + "pos": { + "x": 15, + "y": 21 + }, + "state": "unusable", + "in_use": false, + "key":"oil", + "reward":"remote", + "locked_msg":"Ugh the drawer doesn't open, it's like it's rusty or jammed or smthn. Gotta loosen it somehow", + "unlocked_msg":"This is kinda gross 🤢 k it's open, got the remote 📱", + "sprite": [ + { + "for": "usable", + "img": "/assets/img/appartment/CoffeeTableUsable.PNG" + }, + { + "for": "unusable", + "img": "/assets/img/appartment/CoffeeTableUnusable.PNG" + } + ] + }, + { + "name": "TV", + "room": "living", + "pos": { + "x": 17, + "y": 20 + }, + "state": "used", + "in_use": false, + "key":"remote", + "generator_on":false, + "locked_msg":"I need a remote to turn this on", + "locked_msg_generator_off":"oh shit there's no power i can't turn the tv on", + "unlocked_msg":"ok it's on... um... it's just some static. i think i see a word in there. It says ETHER. Any ideas wtf that means?", + "sprite": [ + { + "for": "used", + "img": "/assets/img/appartment/TVUsed.PNG" + }, + { + "for": "unused", + "img": "/assets/img/appartment/TVUnused.PNG" + } + ] + }, + { + "name": "Bookcase", + "room": "Guest Bedroom", + "pos": { + "x": 28, + "y": 14 + }, + "state": "searchable", + "in_use": true, + "key":"Desk Note", + "reward":"Flashlight", + "locked_msg":"There's like a shit ton of books in here in a bunch of different colors, i have no idea what i'm looking for... 😵‍💫", + "unlocked_msg":"Got the pink book. Looks like it's hollowed out and there's a flashlight inside 🔦. WEIRD?? there's also some writing here that says the mouth holds the key. omg that's so creepy wtf", + "sprite": [ + { + "for": "searchable", + "img": "/assets/img/appartment/BookcaseSearchable.PNG" + }, + { + "for": "usable", + "img": "/assets/img/appartment/BookcaseUsable.PNG" + }, + { + "for": "unusable", + "img": "/assets/img/appartment/BookcaseUnusuable.PNG" + } + ] + }, + + { + "name": "Generator", + "room": "basement", + "pos": { + "x": 3, + "y": 2 + }, + "state": "off", + "in_use": false, + "sprite": [ + { + "for": "off", + "img": "/assets/img/appartment/GeneratorOff.PNG" + }, + { + "for": "on", + "img": "/assets/img/appartment/GeneratorOn.PNG" + } + ] + }, + { + "name": "Dead Body", + "room": "Storage", + "pos": { + "x": 3, + "y": 4 + }, + "state": "usable", + "in_use": true, + "key":"Knife", + "locked_msg":"um... what. the. fuck. IS THIS A DEAD BODY?? WHO ARE YOU??", + "unlocked_msg":"no no no no no ew ew ew ew whyyyyyyy...😭😭😭 theres a note here that says NEO. why the f was there a note in its mouth??", + "sprite": [ + { + "for": "usable", + "img": "/assets/img/appartment/DeadBodyUsable.PNG" + }, + { + "for": "unusable", + "img": "/assets/img/appartment/DeadBodyUnusable.PNG" + } + ] + }, + { + "name": "Desk", + "room": "office", + "pos": { + "x": 20, + "y": 9 + }, + "reward": "Desk Note", + "state": "unsearchable", + "in_use": false, + "search_msg":"There's a note on your desk. It says The flamingo basks in light. what?? 🤔", + "sprite": [ + { + "for": "searchable", + "img": "/assets/img/appartment/DeskSearchable.PNG" + }, + { + "for": "unsearchable", + "img": "/assets/img/appartment/DeskUnsearchable.PNG" + } + ] + }, + { + "name": "Cabinet", + "room": "Kitchen", + "pos": { + "x": 27, + "y": 2 + }, + "state": "searchable", + "in_use": true, + "reward":"knife", + "search_msg":"Omg a knife 🔪... ill take it but there's no way i'm fighting that thing u can't make me ok?? ", + "sprite": [ + { + "for": "searchable", + "img": "/assets/img/appartment/CabinetSearchable.PNG" + }, + { + "for": "unsearchable", + "img": "/assets/img/appartment/CabinetUnsearchable.PNG" + } + ] + }, + { + "name": "Fridge", + "room": "kitchen", + "pos": { + "x": 27, + "y": 4 + }, + "state": "unsearchable", + "in_use": false, + "search_msg":"there's some creepy ouija shit on your fridge with the fridge magnets. They spell out VENES. is that something i should know about??", + "sprite": [ + { + "for": "searchable", + "img": "/assets/img/appartment/FridgeSearchable.PNG" + }, + { + "for": "unsearchable", + "img": "/assets/img/appartment/FridgeUnsearchable.PNG" + } + ] + }, + { + "name": "Stove", + "room": "kitchen", + "pos": { + "x": 29, + "y": 3 + }, + "state": "unsearchable", + "in_use": false, + "search_msg":"U left some olive oil here on the stove for some reason... I feel like it might be useful for something... 🫕", + + "sprite": [ + { + "for": "searchable", + "img": "/assets/img/appartment/StoveSearchable.PNG" + }, + { + "for": "unsearchable", + "img": "/assets/img/appartment/StoveUnsearchable.PNG" + } + ] + },{ + "name":"Storage Shade", + "room":"Storage", + "wall_pos": { + "x": 6, + "y": 3 + }, + "stop_pos":{ + "x": 7, + "y": 3 + }, + "state":"locked", + "in_use": false, + "locked_message":"No no no theres no way im going in there its dark as shit and its already fking scary out here ", + "unlocked_message":"Ok here goes...", + "sprite": [ + { + "for": "locked", + "img": "/assets/img/appartment/StorageLocked.PNG" + }, + { + "for": "unlocked", + "img": "/assets/img/appartment/StorageUnlocked.PNG" + } + ] + },{ + "name":"Entrance", + "room":"Main Hallway", + "pos":{ + "x": 15, + "y": 18 + }, + "state":"locked", + "locked_message":"I seem to need a key to get out of here", + "unlocked_message":"IM OUT, AND THIS RELATIONSHIP IS OVER", + "sprite": [ + { + "for": "locked", + "img": "/assets/img/appartment/TheExit.png" + } + ] + } + + ] + ; +} diff --git a/static/game/elmnts/girlfriend.js b/static/game/elmnts/girlfriend.js new file mode 100644 index 0000000000000000000000000000000000000000..2b09b2a131bc3fe656534d5254906273b72b3438 --- /dev/null +++ b/static/game/elmnts/girlfriend.js @@ -0,0 +1,117 @@ +class Girlfriend extends Character { + constructor(gameState, girlfriendImg) { + super(gameState, girlfriendImg); + this.gameState = gameState; + this.gameState.girlfriend = this; + this.img = girlfriendImg; + this.setCharacterPosition(this.gameState.map_data.girlfriend_start_pos); + this.currentHidingSpot = null; + this.stressLevel = 30; + } + + draw(CELL_SIZE) { + if (this.characterPos) { + push(); + if (this.previousPos && this.characterPos.x > this.previousPos.x) { + scale(-1, 1); + image( + this.img, + -this.characterPos.x * CELL_SIZE - CELL_SIZE * 2, + this.characterPos.y * CELL_SIZE, + CELL_SIZE * 2, + CELL_SIZE * 2 + ); + } else { + if (this.getIsHiding()) { + tint(255, 153); + image( + this.img, + this.characterPos.x * CELL_SIZE, + this.characterPos.y * CELL_SIZE, + CELL_SIZE * 2, + CELL_SIZE * 2 + ); + } else { + image( + this.img, + this.characterPos.x * CELL_SIZE, + this.characterPos.y * CELL_SIZE, + CELL_SIZE * 2, + CELL_SIZE * 2 + ); + } + } + pop(); + } + } + + updateStressLevel(stressChange) { + // Add or subtract the stress change while keeping within 0-100 range + this.stressLevel = Math.max( + 0, + Math.min(100, this.stressLevel + stressChange) + ); + } + + handleAction(response) { + switch (response.action) { + case "go": + this.moveToRoom(response.target); + break; + case "hide": + this.hide(response.target); + break; + } + } + + getAvailableHidingSpots() { + // Find the current room in map data + const currentRoom = this.gameState.map_data.rooms.find( + (room) => room.name === this.getCurrentRoom() + ); + // Return hiding places for current room if found, otherwise empty array + return currentRoom ? currentRoom.hiding_places : []; + } + + getIsHiding() { + const hidingSpots = this.getAvailableHidingSpots(); + if (!this.characterPos || hidingSpots.length === 0) return false; + + return hidingSpots.some( + (spot) => + spot.position.x === this.characterPos.x && + spot.position.y === this.characterPos.y + ); + } + + hide(hidingSpotName) { + const currentRoom = this.getCurrentRoom(); + if (!currentRoom) return; + + // Find the room data from map_data + const roomData = this.gameState.map_data.rooms.find( + (room) => room.name === currentRoom + ); + if (!roomData) return; + + // Find the specific hiding spot in the room by checking if names contain each other + const hidingSpot = roomData.hiding_places.find( + (spot) => + spot.name + .toLowerCase() + .trim() + .includes(hidingSpotName.toLowerCase().trim()) || + hidingSpotName + .toLowerCase() + .trim() + .includes(spot.name.toLowerCase().trim()) + ); + console.log(hidingSpot); + if (!hidingSpot) return; + + // Move to the hiding spot position + this.moveToPosition(hidingSpot.position, () => { + this.currentHidingSpot = hidingSpotName; + }); + } +} diff --git a/static/game/elmnts/grid.js b/static/game/elmnts/grid.js new file mode 100644 index 0000000000000000000000000000000000000000..f30929be5db9904e384a316f5420dc57748e7f92 --- /dev/null +++ b/static/game/elmnts/grid.js @@ -0,0 +1,2604 @@ +function getGrid(){ + return [ + [ + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "wall", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + } + ], + [ + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + } + ], + [ + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + } + ], + [ + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "door", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": "green" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": "red" + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "empty", + "color": null + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": "yellow" + }, + { + "type": "empty", + "color": null + }, + { + "type": "wall", + "color": null + } + ], + [ + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + }, + { + "type": "wall", + "color": null + } + ] + ]; +} \ No newline at end of file diff --git a/static/game/game.js b/static/game/game.js new file mode 100644 index 0000000000000000000000000000000000000000..87c46b1172079edfce7811743081fc9bd7f80abb --- /dev/null +++ b/static/game/game.js @@ -0,0 +1,70 @@ +const CELL_SIZE = 50; +let GRID_COLS = 0; +let GRID_ROWS = 0; +let grid = []; + +let gameState; + +let baseMapImg; +let girlfriendImg; +let clownImg; + +let isSoundOn = localStorage.getItem("isSoundOn") === null ? true : localStorage.getItem("isSoundOn") !== "false"; +const soundIcon = document.getElementById("soundIcon"); +const bgMusic = document.getElementById("bgMusic"); + +const mistralAPI = new MistralAPI(); + +let chatMessages = []; + +let furnitureSprites = {}; + +function setup() { + baseMapImg = loadImage('/assets/img/appartment/baseMap.PNG'); + girlfriendImg = loadImage('/assets/img/gf.png'); + clownImg = loadImage('/assets/img/clown.png'); + + gameState = new GameState({ + ...getApt(), + grid: getGrid(), + furniture:getFurniture() + }); + + furnitureSprites = loadFurnitureSprites(gameState.map_data.furniture); + + GRID_COLS = gameState.map_data.gridCols; + GRID_ROWS = gameState.map_data.gridRows; + + girlfriend = new Girlfriend(gameState, girlfriendImg); + clown = new Clown(gameState, clownImg); + + // Once loaded, initialize the P5 canvas with correct dims + let canvas = createCanvas(GRID_COLS * CELL_SIZE, GRID_ROWS * CELL_SIZE); + canvas.parent('mapWrapper'); + adjustScale(); +} + +function draw() { + clear(); + + if (baseMapImg) { + image(baseMapImg, 0, 0, GRID_COLS * CELL_SIZE, GRID_ROWS * CELL_SIZE); + } + if(furnitureSprites) { + drawFurniture(gameState.map_data.furniture, furnitureSprites); + } + drawGrid(); + // drawWallsAndDoors(); + + drawLabels(gameState.map_data.rooms); + + if (girlfriend) { + girlfriend.drawPath(CELL_SIZE); + girlfriend.draw(CELL_SIZE); + } + if (clown) { + clown.checkForGirlfriend(girlfriend); + clown.drawPath(CELL_SIZE); + clown.draw(CELL_SIZE); + } +} \ No newline at end of file diff --git a/static/game/gameState.js b/static/game/gameState.js new file mode 100644 index 0000000000000000000000000000000000000000..2c624b8b25e0565f6aaa015d21ecaeacd435cae4 --- /dev/null +++ b/static/game/gameState.js @@ -0,0 +1,140 @@ +// Game state management +class GameState { + constructor(map_data) { + this.map_data = map_data; + this.girlfriend = null; + this.clown = null; + + this.searchTargets = [ + "dresser", + "desk", + "bookcase", + "cabinet", + "dead body", + "fridge", + "stove", + "coffee table", + ]; + + this.items = [ + "lock pick", + "book note", + "flashlight", + "knife", + "oil", + "remote", + ]; + + this.useTargets = [ + "bedroom door", + "bookcase", + "storage door", + "dead body", + "coffee table", + "TV", + ]; + + this.inventory = []; + this.isHiding = false; + } + + getStressPrompt() { + const currentStress = this.girlfriend ? this.girlfriend.stressLevel : 50; // Default to 50 if girlfriend not initialized + + return `You are a stress level analyzer. Given a message in the context of a survival horror game, evaluate how stressful or calming the message is. + +Your response must be a JSON object with this format: +{ + "stressChange": number // Between -50 and +50 +} + +The current stress level is ${currentStress}/100. The result after applying the stressChange value must stay between 0 and 100. +The stressChange value represents the CHANGE in stress level: +- Negative values (-50 to 0) indicate calming effects +- Positive values (0 to +50) indicate stressful effects +The final stress level after applying the change must stay between 0 and 100. + +Examples: +"Hide quickly!" -> {"stressChange": 40} +"You're safe now, take a deep breath" -> {"stressChange": -35} +"The killer is right behind you!" -> {"stressChange": 50} +"Let's think about this calmly" -> {"stressChange": -30}`; + } + + getPrompt() { + return ` + +You are a JSON girlfriend that is stuck in her boyfriends appartment with an evil murderous clown. You are currently having a text conversation with your boyfriend who has access to security cameras and can give instructions through text. + +Current state: +- You (the girlfriend) are currently in this Room >> ${this.girlfriend.getCurrentRoom()} +- Your current stress level is ${this.girlfriend.stressLevel}/100 +${ + this.girlfriend.getIsHiding() + ? `- You are currently hiding ${this.girlfriend.currentHidingSpot.hiding_type} the ${this.girlfriend.currentHidingSpot.name}` + : "" +} +${ + this.girlfriend.getCurrentRoom() === this.clown.getCurrentRoom() + ? "- OMG YOU ARE IN THE SAME ROOM AS THE CLOWNNNN!!!" + : "- You have no idea where the clown is, you will hide if you can, if not leave the room" +} + + +RESPONSE FORMAT: +You must ALWAYS respond with a JSON object. +Your response should reflect a girlfriend's reaction to her boyfriend's message given this context and following the following structure: + +1. For movement instructions ("go" action): +{ + "action": "go", + "target": "[room name]", + "textMessage": "[girlfriend's response]" +} + +2. For hiding instructions ("hide" action): +{ + "action": "hide", + "target": "[hiding place name]", + "textMessage": "[girlfriend's response]" +} + +3. For any other input: +{ + "textMessage": "[girlfriend's response]" +} + +VALID ROOMS: +You are only allowed to move to these rooms no other rooms are recognized: +${this.map_data.rooms.map((room) => room.name).join(",\n")} + +VALID HIDING PLACES: +You are only allowed to hide in these hiding spots no other hiding spots are recognized: +${ + this.girlfriend.getAvailableHidingSpots().length > 0 + ? `- You may hide in these available hiding spots (and thats it): ${this.girlfriend + .getAvailableHidingSpots() + .map((spot) => `${spot.hiding_type} ${spot.name}`) + .join(", ")}` + : "- There are no available hiding spots in this room" +} + +YOUR BEHAVIOR: +- You are aware of the danger and are extremely distressed. +${ + this.girlfriend.getCurrentRoom() !== this.clown.getCurrentRoom() + ? "- You have no idea where the clown is" + : "" +} +Your text responses should be: +-- Brief and urgent +-- Reflect genuine fear and panic +-- Write like real text messages (short, quick responses) +-- No time for pleasantries or long explanations +-- May include typos or rushed writing due to stress +--You are very scared but you are also super brave to be honest +-- As long as the stress level increases, you will be more scared and more likely to hide or to not follow the instructions + +`; + } +} diff --git a/static/game/index.html b/static/game/index.html new file mode 100644 index 0000000000000000000000000000000000000000..827f341571e897a9fc35ab0db4730fe7dc95c94a --- /dev/null +++ b/static/game/index.html @@ -0,0 +1,86 @@ + + + + + The Last Message - A text based horror game + + + + +
+
+
+
+ + + + +
+
+
+
+ +
+
+
+
+
+
+
+ +
+
Bae 💖😘
+
+
+
+ + +
+
+
+
+
+ +
+ Sound control +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/game/mistral.js b/static/game/mistral.js new file mode 100644 index 0000000000000000000000000000000000000000..eb817f574b20486c33502abeb3c777f89ca80fc6 --- /dev/null +++ b/static/game/mistral.js @@ -0,0 +1,28 @@ +class MistralAPI { + constructor() { + + } + + async sendMessage(messages) { + const response = await fetch("/mistral-proxy", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + model: "mistral-large-latest", + messages: messages, + temperature: 0.5, + top_p: 0.5, + response_format: { type: "json_object" }, + }), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + return data.choices[0].message.content; + } +} diff --git a/static/game/utilities/chat.js b/static/game/utilities/chat.js new file mode 100644 index 0000000000000000000000000000000000000000..a12788e166ad318577acaa12b82861b0f3e4c870 --- /dev/null +++ b/static/game/utilities/chat.js @@ -0,0 +1,120 @@ +function createLoadingIndicator() { + const loadingDiv = document.createElement("div"); + loadingDiv.className = "chat-message assistant-message"; + loadingDiv.innerHTML = ` +
+
+
+
+
+ `; + return loadingDiv; +} + +async function sendMessage() { + const prompt = document.getElementById("prompt").value.trim(); + if (!prompt) return; + + addMessageToChat("user", prompt); + document.getElementById("prompt").value = ""; + + const chatHistory = document.getElementById("chatHistory"); + const loadingIndicator = createLoadingIndicator(); + chatHistory.appendChild(loadingIndicator); + + // First, get the stress prompt and send it + const stressPrompt = gameState.getStressPrompt(); + const stressMessages = [ + { + role: "system", + content: stressPrompt, + }, + { role: "user", content: prompt }, + ]; + console.log("stressMessages", stressMessages); + + // Get stress level change + const stressResponse = await mistralAPI.sendMessage(stressMessages); + const stressChange = JSON.parse(stressResponse).stressChange || 0; + + // Update girlfriend's stress level + girlfriend.updateStressLevel(stressChange); + console.log("girlfriend.stressLevel", girlfriend.stressLevel); + + console.log("stressChange", stressChange); + + // Now continue with the regular chat flow + let masterPrompt = gameState.getPrompt(); + const recentMessages = chatMessages.slice(-5); + + const messages = [ + { role: "system", content: masterPrompt }, + ...recentMessages, + { role: "user", content: prompt }, + ]; + + const assistantResponse = await mistralAPI.sendMessage(messages); + + chatHistory.removeChild(loadingIndicator); + + const jsonStart = assistantResponse.indexOf("{"); + const jsonEnd = assistantResponse.lastIndexOf("}") + 1; + const jsonContent = assistantResponse.substring(jsonStart, jsonEnd); + const jsonResponse = JSON.parse(jsonContent); + + if (jsonResponse.action) { + girlfriend.handleAction(jsonResponse); + } + + if (jsonResponse.textMessage) { + addMessageToChat("assistant", jsonResponse.textMessage); + } +} + +function addMessageToChat(role, content) { + const chatHistory = document.getElementById("chatHistory"); + const messageDiv = document.createElement("div"); + messageDiv.className = `chat-message ${role}-message`; + messageDiv.textContent = content; + chatHistory.appendChild(messageDiv); + chatHistory.scrollTop = chatHistory.scrollHeight; + + chatMessages.push({ role, content }); + + if (role === "assistant" && localStorage.getItem("isSoundOn") !== "false") { + playMessageSound(); + } +} + +// Update Message function to use girlfriend instance +function Message() { + if (girlfriend) { + // Play message sound when sending a message + if (localStorage.getItem("isSoundOn") !== "false") { + playMessageSound(); + } + sendMessage(); + } +} + +// Allow sending message with Enter +document.addEventListener("DOMContentLoaded", () => { + document.getElementById("prompt").addEventListener("keypress", function (e) { + if (e.key === "Enter") { + e.preventDefault(); + Message(); + } + }); + + try { + const bgMusic = document.getElementById("bgMusic"); + bgMusic.currentTime = 10; + bgMusic.play().catch((error) => { + console.log("Autoplay prevented:", error); + isSoundOn = false; + updateSoundIcon(); + }); + } catch (error) { + console.error("Error playing audio:", error); + } +}); diff --git a/static/game/utilities/draw.js b/static/game/utilities/draw.js new file mode 100644 index 0000000000000000000000000000000000000000..a60f0e5e02429a6a5843b5371485e1141764d3df --- /dev/null +++ b/static/game/utilities/draw.js @@ -0,0 +1,151 @@ +function drawGrid() { + stroke(200); + for (let x = 0; x <= GRID_COLS; x++) { + line(x * CELL_SIZE, 0, x * CELL_SIZE, GRID_ROWS * CELL_SIZE); + } + for (let y = 0; y <= GRID_ROWS; y++) { + line(0, y * CELL_SIZE, GRID_COLS * CELL_SIZE, y * CELL_SIZE); + } +} + +function stringToHue(str) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + return hash % 360; +} + +function drawLabels(rooms) { + for (let room of rooms) { + const hue = stringToHue(room.name); + fill(hue, 30, 95, 0.3); + noStroke(); + + // Draw room highlight rectangle + const width = (room.end_col - room.start_col + 1) * CELL_SIZE; + const height = (room.end_row - room.start_row + 1) * CELL_SIZE; + rect(room.start_col * CELL_SIZE, room.start_row * CELL_SIZE, width, height); + + // Draw room label + fill(0); + textAlign(CENTER, CENTER); + textSize(14); + text( + room.name, + room.label_position.x * CELL_SIZE + CELL_SIZE / 2, + room.label_position.y * CELL_SIZE + CELL_SIZE / 2 + ); + + // Draw hiding places for this room + for (let hidingSpot of room.hiding_places) { + // Draw the hiding place cells + fill(100, 30, 95, 0.3); + noStroke(); + const cell = hidingSpot.position; + rect(cell.x * CELL_SIZE, cell.y * CELL_SIZE, CELL_SIZE, CELL_SIZE); + + const x = cell.x * CELL_SIZE + CELL_SIZE / 2; + const y = cell.y * CELL_SIZE + CELL_SIZE / 2; + + push(); + textAlign(CENTER, CENTER); + textSize(12); + + // Measure exactly the text size (no extra padding) + const labelWidth = textWidth(hidingSpot.name); + const labelHeight = textAscent() + textDescent(); + + // Draw a centered background rectangle + // that's just as wide/tall as the text + rectMode(CENTER); + fill('#f1c94f'); + noStroke(); + rect(x, y, labelWidth, labelHeight / 2, 2); + pop(); + + // Draw the text on top + fill(0); + textAlign(CENTER, CENTER); + textSize(12); + text(hidingSpot.name, x, y); + } + } +} + +function drawWallsAndDoors() { + for (let y = 0; y < GRID_ROWS; y++) { + for (let x = 0; x < GRID_COLS; x++) { + const cell = grid[y][x]; + if (cell.type === 'wall') { + fill(0); + noStroke(); + rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE); + } else if (cell.type === 'door') { + fill(139, 69, 19); // Brown color for doors + noStroke(); + rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE); + } else if (cell.color) { + noStroke(); + switch (cell.color) { + case 'yellow': + fill('#ffeb3b'); + break; + case 'blue': + fill('#2196f3'); + break; + case 'green': + fill('#4caf50'); + break; + case 'red': + fill('#f44336'); + break; + } + rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE); + } + } + } +} + +function loadFurnitureSprites(furniture) { + console.log(furniture); + const sprites = []; + for (let i = 0; i < furniture.length; i++) { + for (let j = 0; j < furniture[i].sprite.length; j++) { + if (!sprites.includes(furniture[i].sprite[j].img)) { + sprites[furniture[i].sprite[j].img] = loadImage(furniture[i].sprite[j].img); + } + } + } + return sprites; +} +function drawFurniture(furniture, sprites) { + // Draw all sprites first + for (let item of furniture) { + const sprite = item.sprite.find(s => s.for === item.state); + if (sprite && sprites[sprite.img]) { + image(sprites[sprite.img], 0, 0, GRID_COLS * CELL_SIZE, GRID_ROWS * CELL_SIZE); + } + } + + // Draw all labels second + for (let item of furniture) { + if (item.pos && item.in_use == true) { + push(); + // Draw light gray background + fill(220); + noStroke(); + const padding = 4; + const textWidth = textSize() * item.name.length * 0.6; + rectMode(CENTER); + rect((item.pos.x + 0.5) * CELL_SIZE, (item.pos.y + 0.5) * CELL_SIZE, textWidth, 20); + + // Draw black text + fill(0); + textAlign(CENTER, CENTER); + textSize(12); + text(item.name, (item.pos.x + 0.5) * CELL_SIZE, (item.pos.y + 0.5) * CELL_SIZE); + pop(); + } + } +} \ No newline at end of file diff --git a/static/game/utilities/helpers.js b/static/game/utilities/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..0081197537134a82582724ffb118371b401f26e4 --- /dev/null +++ b/static/game/utilities/helpers.js @@ -0,0 +1,11 @@ +function adjustScale() { + const availableWidth = window.innerWidth - 400 - 40; // space for chat + margins + const actualCanvasWidth = GRID_COLS * CELL_SIZE; + const scale = availableWidth / actualCanvasWidth; + const mapWrapper = document.querySelector('#mapSection .map-wrapper'); + if (mapWrapper) { + mapWrapper.style.zoom = scale; + } +} + +window.addEventListener('resize', adjustScale); diff --git a/static/game/utilities/numpad.js b/static/game/utilities/numpad.js new file mode 100644 index 0000000000000000000000000000000000000000..b94e74e5a2293c1097b6af81504c8d8adc30ed18 --- /dev/null +++ b/static/game/utilities/numpad.js @@ -0,0 +1,125 @@ + +class Numpad { + constructor(containerId, options = {}) { + this.container = document.getElementById(containerId); + this.options = { + code: options.code || '123', + onSuccess: options.onSuccess || (() => alert('Correct code!')), + onError: options.onError || (() => alert('Wrong code!')) + }; + + this.currentCode = ''; + this.init(); + } + + init() { + // Create display + this.display = document.createElement('div'); + this.display.className = 'numpad-display'; + this.container.appendChild(this.display); + + // Create numpad container + this.numpadGrid = document.createElement('div'); + this.numpadGrid.className = 'numpad-grid'; + this.container.appendChild(this.numpadGrid); + + // Create number buttons + for (let i = 1; i <= 9; i++) { + this.createButton(i); + } + this.createButton(0); + + this.updateDisplay(); + } + + createButton(number) { + const button = document.createElement('button'); + button.className = 'numpad-key'; + button.textContent = number; + button.addEventListener('click', () => this.handleInput(number)); + this.numpadGrid.appendChild(button); + } + + handleInput(number) { + if (this.currentCode.length < 3) { + this.currentCode += number; + this.updateDisplay(); + + if (this.currentCode.length === 3) { + this.checkCode(); + } + } + } + + updateDisplay() { + this.display.textContent = this.currentCode.padEnd(3, 'X'); + } + + checkCode() { + if (this.currentCode === this.options.code) { + this.options.onSuccess(); + } else { + this.options.onError(); + } + this.currentCode = ''; + this.updateDisplay(); + } + + reset() { + this.currentCode = ''; + this.updateDisplay(); + } +} + +// Wait for DOM to be loaded before initializing +document.addEventListener('DOMContentLoaded', () => { + // Create required HTML elements if they don't exist + if (!document.getElementById('numpad-overlay')) { + const overlay = document.createElement('div'); + overlay.id = 'numpad-overlay'; + overlay.className = 'numpad-overlay hidden'; + + const container = document.createElement('div'); + container.id = 'numpad-container'; + overlay.appendChild(container); + + document.body.appendChild(overlay); + } + + if (!document.getElementById('toggle-numpad')) { + const toggleButton = document.createElement('button'); + toggleButton.id = 'toggle-numpad'; + toggleButton.className = 'toggle-numpad'; + toggleButton.textContent = 'Enter Code'; + document.body.appendChild(toggleButton); + } + + // Initialize the numpad with desired options + const numpad = new Numpad('numpad-container', { + code: '123', + onSuccess: () => { + console.log('Success! Correct code entered'); + // Add your game logic here + }, + onError: () => { + console.log('Error! Wrong code'); + } + }); + + // Setup toggle functionality + const toggleButton = document.getElementById('toggle-numpad'); + const numpadOverlay = document.getElementById('numpad-overlay'); + + toggleButton.addEventListener('click', () => { + numpadOverlay.classList.toggle('hidden'); + }); + + // Close numpad when clicking outside + document.addEventListener('click', (event) => { + if (!numpadOverlay.contains(event.target) && + !toggleButton.contains(event.target) && + !numpadOverlay.classList.contains('hidden')) { + numpadOverlay.classList.add('hidden'); + } + }); +}); \ No newline at end of file diff --git a/static/game/utilities/sound.js b/static/game/utilities/sound.js new file mode 100644 index 0000000000000000000000000000000000000000..0d7ff64d400d94d40741400d976fbb5bf5baaff4 --- /dev/null +++ b/static/game/utilities/sound.js @@ -0,0 +1,54 @@ +// Make handleWalkingSound globally available +function handleWalkingSound (isWalking) { + const walkingSound = document.getElementById("walkingSound"); + if (!walkingSound) return; + + if (isWalking && localStorage.getItem("isSoundOn") !== "false") { + walkingSound.currentTime = 0; + walkingSound.volume = 0.3; + walkingSound.play().catch((error) => { + console.log("Could not play walking sound:", error); + }); + } else { + walkingSound.pause(); + } +} + +// Update toggleSound to check girlfriend's movement status +function toggleSound() { + isSoundOn = !isSoundOn; + localStorage.setItem("isSoundOn", isSoundOn.toString()); + + if (isSoundOn) { + if (bgMusic.currentTime < 10) { + bgMusic.currentTime = 10; + } + bgMusic.play(); + if (girlfriend && girlfriend.isMoving) { + handleWalkingSound(true); + } + } else { + bgMusic.pause(); + handleWalkingSound(false); + } + updateSoundIcon(); +} + +function updateSoundIcon() { + soundIcon.src = isSoundOn ? "/static/assets/img/sondon.png" : "/static/assets/img/soundoff.png"; +} + +function playMessageSound() { + try { + const messageSound = document.getElementById("messageSound"); + if (messageSound) { + messageSound.currentTime = 0; + messageSound.volume = 1.0; + messageSound.play().catch((error) => { + console.log("Could not play message sound:", error); + }); + } + } catch (error) { + console.error("Error playing message sound:", error); + } +} \ No newline at end of file diff --git a/static/how-to-play.html b/static/how-to-play.html new file mode 100644 index 0000000000000000000000000000000000000000..30ef1bab904b9ec359efb35150635a6be41f122c --- /dev/null +++ b/static/how-to-play.html @@ -0,0 +1,32 @@ + + + + + + Through Their Eyes - How to Play + + + +
+
+
+ +
+ + + + +
+ +
+
+

How to Play

+ +
+ + Back to Menu +
+ + + + diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000000000000000000000000000000000000..7f654620d7d8612cc7cdec67dc64f46a9c1cfe12 --- /dev/null +++ b/static/index.html @@ -0,0 +1,103 @@ + + + + + + Through Their Eyes + + + +
+
+
+
+ + + + +
+ +
+ + + +
+ Character +
+
+ +
+ Sound control +
+ + + + + +