|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
|
|
<title>GHOSTLY KNIGHT: Cursed Crypts</title> |
|
|
<link href="https://fonts.googleapis.com/css2?family=MedievalSharp&family=Cinzel+Decorative:wght@700&family=UnifrakturMaguntia&display=swap" rel="stylesheet"> |
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,[email protected],100..700,0..1,-50..200" /> |
|
|
|
|
|
<script src="https://apis.google.com/js/api:client.js"></script> |
|
|
<style> |
|
|
* { |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
box-sizing: border-box; |
|
|
touch-action: manipulation; |
|
|
user-select: none; |
|
|
-webkit-user-select: none; |
|
|
} |
|
|
|
|
|
:root { |
|
|
--blood-red: #8b0000; |
|
|
--dark-purple: #3d0066; |
|
|
--torch-orange: #ff6b35; |
|
|
--bone-white: #f8f4e3; |
|
|
--rusty-metal: #8b5a2b; |
|
|
} |
|
|
|
|
|
body { |
|
|
width: 100vw; |
|
|
height: 100vh; |
|
|
overflow: hidden; |
|
|
background: #000; |
|
|
font-family: 'Cinzel Decorative', cursive; |
|
|
position: fixed; |
|
|
color: var(--bone-white); |
|
|
} |
|
|
|
|
|
#game-container { |
|
|
position: fixed; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
} |
|
|
|
|
|
|
|
|
#loading-screen { |
|
|
position: absolute; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: radial-gradient(ellipse at center, #1a0000 0%, #000 100%); |
|
|
color: var(--torch-orange); |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
z-index: 100; |
|
|
font-size: 2rem; |
|
|
text-shadow: 0 0 10px var(--blood-red); |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.pentagram { |
|
|
position: absolute; |
|
|
width: 200px; |
|
|
height: 200px; |
|
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path fill="none" stroke="%23ff0000" stroke-width="2" d="M50,5 L60,40 L95,40 L65,60 L75,95 L50,75 L25,95 L35,60 L5,40 L40,40 Z"/></svg>') no-repeat center center; |
|
|
background-size: contain; |
|
|
animation: rotate 10s linear infinite; |
|
|
filter: drop-shadow(0 0 8px var(--blood-red)); |
|
|
opacity: 0.7; |
|
|
} |
|
|
|
|
|
@keyframes rotate { |
|
|
from { transform: rotate(0deg); } |
|
|
to { transform: rotate(360deg); } |
|
|
} |
|
|
|
|
|
#loading-bar-container { |
|
|
width: 80%; |
|
|
max-width: 400px; |
|
|
margin-top: 30px; |
|
|
background: rgba(0, 0, 0, 0.7); |
|
|
border: 3px solid var(--blood-red); |
|
|
border-radius: 10px; |
|
|
padding: 5px; |
|
|
box-shadow: 0 0 20px var(--blood-red); |
|
|
position: relative; |
|
|
z-index: 2; |
|
|
} |
|
|
|
|
|
#loading-bar { |
|
|
height: 20px; |
|
|
background: linear-gradient(90deg, #3d0066, #8b0000); |
|
|
border-radius: 5px; |
|
|
width: 0%; |
|
|
transition: width 0.3s; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
#loading-bar::after { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
right: 0; |
|
|
bottom: 0; |
|
|
background: linear-gradient(90deg, |
|
|
rgba(255,255,255,0.1) 0%, |
|
|
rgba(255,255,255,0.3) 50%, |
|
|
rgba(255,255,255,0.1) 100%); |
|
|
animation: shine 2s infinite; |
|
|
} |
|
|
|
|
|
@keyframes shine { |
|
|
0% { transform: translateX(-100%); } |
|
|
100% { transform: translateX(100%); } |
|
|
} |
|
|
|
|
|
#loading-text { |
|
|
margin-top: 20px; |
|
|
font-size: 1.2rem; |
|
|
text-align: center; |
|
|
color: var(--torch-orange); |
|
|
text-shadow: 1px 1px 3px black; |
|
|
max-width: 80%; |
|
|
} |
|
|
|
|
|
|
|
|
#title-screen { |
|
|
position: absolute; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><pattern id="pattern" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse"><image x="0" y="0" width="100" height="100" href="data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'100\' height=\'100\'><rect width=\'100\' height=\'100\' fill=\'%231a0000\'/><path d=\'M20,20 L80,20 L80,80 L20,80 Z\' stroke=\'%238b0000\' stroke-width=\'2\' fill=\'none\'/><circle cx=\'50\' cy=\'50\' r=\'10\' stroke=\'%233d0066\' stroke-width=\'1\' fill=\'none\'/></svg>"/></pattern><rect x="0" y="0" width="100%" height="100%" fill="url(%23pattern)"/><rect x="0" y="0" width="100%" height="100%" fill="rgba(0,0,0,0.7)"/></svg>'); |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
z-index: 50; |
|
|
opacity: 1; |
|
|
transition: opacity 1s; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.menu-bg-overlay { |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: radial-gradient(circle at 50% 40%, rgba(139, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.8) 60%); |
|
|
z-index: 0; |
|
|
} |
|
|
|
|
|
.menu-bg-elements { |
|
|
position: absolute; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
pointer-events: none; |
|
|
z-index: 1; |
|
|
} |
|
|
|
|
|
.chains { |
|
|
position: absolute; |
|
|
width: 100px; |
|
|
height: 200px; |
|
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 40"><path fill="%23663300" d="M10,0 C13,0 15,2 15,5 L15,10 C15,13 17,15 20,15 L20,25 C17,25 15,27 15,30 L15,35 C15,38 13,40 10,40 C7,40 5,38 5,35 L5,30 C5,27 3,25 0,25 L0,15 C3,15 5,13 5,10 L5,5 C5,2 7,0 10,0 Z"/></svg>') repeat-y; |
|
|
background-size: contain; |
|
|
opacity: 0.5; |
|
|
animation: swing 5s infinite alternate; |
|
|
transform-origin: top center; |
|
|
} |
|
|
|
|
|
.bones { |
|
|
position: absolute; |
|
|
width: 100px; |
|
|
height: 50px; |
|
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 50"><path fill="%23f8f4e3" d="M10,25 C10,15 20,5 30,5 C40,5 50,15 50,25 C50,35 60,45 70,45 C80,45 90,35 90,25 C90,15 80,5 70,5 C60,5 50,15 50,25 C50,35 40,45 30,45 C20,45 10,35 10,25 Z"/></svg>'); |
|
|
background-size: contain; |
|
|
background-repeat: no-repeat; |
|
|
opacity: 0.4; |
|
|
} |
|
|
|
|
|
@keyframes swing { |
|
|
0% { transform: rotate(-5deg); } |
|
|
100% { transform: rotate(5deg); } |
|
|
} |
|
|
|
|
|
#title-container { |
|
|
position: relative; |
|
|
z-index: 2; |
|
|
text-align: center; |
|
|
width: 90%; |
|
|
max-width: 600px; |
|
|
perspective: 1000px; |
|
|
} |
|
|
|
|
|
.game-title { |
|
|
font-family: 'UnifrakturMaguntia', cursive; |
|
|
font-size: 4.5rem; |
|
|
color: var(--torch-orange); |
|
|
text-shadow: 0 0 10px var(--blood-red), 0 0 20px var(--blood-red), 0 0 30px var(--blood-red); |
|
|
margin-bottom: 10px; |
|
|
transform-style: preserve-3d; |
|
|
animation: titleGlow 3s infinite alternate; |
|
|
letter-spacing: 3px; |
|
|
} |
|
|
|
|
|
.game-subtitle { |
|
|
font-family: 'MedievalSharp', cursive; |
|
|
font-size: 1.5rem; |
|
|
color: var(--bone-white); |
|
|
text-shadow: 2px 2px 4px #000; |
|
|
margin-bottom: 40px; |
|
|
letter-spacing: 2px; |
|
|
} |
|
|
|
|
|
@keyframes titleGlow { |
|
|
0% { text-shadow: 0 0 10px var(--blood-red), 0 0 20px var(--blood-red), 0 0 30px var(--blood-red); } |
|
|
100% { text-shadow: 0 0 15px var(--blood-red), 0 0 30px var(--blood-red), 0 0 45px var(--torch-orange); } |
|
|
} |
|
|
|
|
|
.menu-container { |
|
|
width: 100%; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
gap: 15px; |
|
|
z-index: 2; |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.menu-btn { |
|
|
background: linear-gradient(to bottom, rgba(139, 0, 0, 0.7), rgba(61, 0, 102, 0.7)); |
|
|
color: var(--bone-white); |
|
|
border: 2px solid var(--torch-orange); |
|
|
border-radius: 10px; |
|
|
padding: 15px 30px; |
|
|
font-size: 1.3rem; |
|
|
font-family: 'Cinzel Decorative', cursive; |
|
|
cursor: pointer; |
|
|
transition: all 0.3s ease; |
|
|
width: 80%; |
|
|
max-width: 300px; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
text-shadow: 1px 1px 2px #000; |
|
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5), inset 0 1px 1px rgba(255, 255, 255, 0.2); |
|
|
} |
|
|
|
|
|
.menu-btn:hover { |
|
|
background: linear-gradient(to bottom, rgba(139, 0, 0, 0.9), rgba(61, 0, 102, 0.9)); |
|
|
transform: translateY(-3px) scale(1.05); |
|
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.6), inset 0 1px 1px rgba(255, 255, 255, 0.2); |
|
|
color: #fff; |
|
|
} |
|
|
|
|
|
.menu-btn:active { |
|
|
transform: translateY(1px); |
|
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.2); |
|
|
} |
|
|
|
|
|
.menu-btn::before { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: -100%; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); |
|
|
transition: 0.5s; |
|
|
} |
|
|
|
|
|
.menu-btn:hover::before { |
|
|
left: 100%; |
|
|
} |
|
|
|
|
|
|
|
|
#canvas { |
|
|
display: block; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: #111; |
|
|
} |
|
|
|
|
|
#game-ui { |
|
|
position: absolute; |
|
|
top: 10px; |
|
|
left: 10px; |
|
|
right: 10px; |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
z-index: 10; |
|
|
color: white; |
|
|
font-size: 1.2rem; |
|
|
text-shadow: 2px 2px 4px black; |
|
|
font-family: 'MedievalSharp', cursive; |
|
|
} |
|
|
|
|
|
#controls { |
|
|
position: absolute; |
|
|
bottom: 20px; |
|
|
right: 20px; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
gap: 15px; |
|
|
z-index: 10; |
|
|
} |
|
|
|
|
|
.control-btn { |
|
|
width: 70px; |
|
|
height: 70px; |
|
|
background: radial-gradient(circle at center, rgba(139, 0, 0, 0.7) 0%, rgba(61, 0, 102, 0.7) 100%); |
|
|
border: 2px solid var(--torch-orange); |
|
|
border-radius: 50%; |
|
|
display: flex; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
color: var(--bone-white); |
|
|
font-size: 1.8rem; |
|
|
cursor: pointer; |
|
|
user-select: none; |
|
|
touch-action: manipulation; |
|
|
position: relative; |
|
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5), inset 0 1px 1px rgba(255, 255, 255, 0.2); |
|
|
transition: all 0.2s; |
|
|
} |
|
|
|
|
|
.control-btn:active { |
|
|
transform: scale(0.95); |
|
|
background: radial-gradient(circle at center, rgba(139, 0, 0, 0.9) 0%, rgba(61, 0, 102, 0.9) 100%); |
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.1); |
|
|
} |
|
|
|
|
|
#joystick-area { |
|
|
position: absolute; |
|
|
bottom: 25px; |
|
|
left: 25px; |
|
|
width: 150px; |
|
|
height: 150px; |
|
|
border-radius: 50%; |
|
|
background: rgba(0, 0, 0, 0.3); |
|
|
border: 2px solid var(--rusty-metal); |
|
|
display: flex; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.5); |
|
|
} |
|
|
|
|
|
#joystick { |
|
|
width: 60px; |
|
|
height: 60px; |
|
|
background: radial-gradient(circle at center, rgba(139, 0, 0, 0.7) 0%, rgba(61, 0, 102, 0.7) 100%); |
|
|
border-radius: 50%; |
|
|
position: relative; |
|
|
transition: transform 0.1s; |
|
|
border: 1px solid var(--torch-orange); |
|
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); |
|
|
} |
|
|
|
|
|
|
|
|
#shop-overlay { |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: rgba(0, 0, 0, 0.85); |
|
|
z-index: 30; |
|
|
display: none; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
color: var(--bone-white); |
|
|
font-family: 'Cinzel Decorative', cursive; |
|
|
} |
|
|
|
|
|
#shop-container { |
|
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><pattern id="shopPattern" x="0" y="0" width="50" height="50" patternUnits="userSpaceOnUse"><path fill="%231a0000" d="M0,0 L50,0 L50,50 L0,50 Z"/><path stroke="%23440033" stroke-width="1" d="M0,0 L50,50 M50,0 L0,50"/></pattern><rect x="0" y="0" width="100%" height="100%" fill="url(%23shopPattern)"/></svg>'); |
|
|
border: 3px solid var(--rusty-metal); |
|
|
border-radius: 15px; |
|
|
padding: 30px; |
|
|
width: 90%; |
|
|
max-width: 500px; |
|
|
max-height: 80vh; |
|
|
overflow-y: auto; |
|
|
box-shadow: 0 0 30px var(--blood-red); |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.shop-header { |
|
|
text-align: center; |
|
|
margin-bottom: 30px; |
|
|
color: var(--torch-orange); |
|
|
text-shadow: 0 0 5px var(--blood-red); |
|
|
} |
|
|
|
|
|
.shop-item { |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
align-items: center; |
|
|
padding: 15px; |
|
|
margin-bottom: 15px; |
|
|
background: linear-gradient(to right, rgba(61, 0, 66, 0.5), rgba(139, 0, 0, 0.5)); |
|
|
border: 1px solid var(--rusty-metal); |
|
|
border-radius: 8px; |
|
|
transition: all 0.3s; |
|
|
} |
|
|
|
|
|
.shop-item:hover { |
|
|
transform: translateY(-3px); |
|
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); |
|
|
} |
|
|
|
|
|
.shop-item-info { |
|
|
flex: 1; |
|
|
} |
|
|
|
|
|
.shop-item-name { |
|
|
font-weight: bold; |
|
|
font-size: 1.2rem; |
|
|
margin-bottom: 5px; |
|
|
color: var(--torch-orange); |
|
|
} |
|
|
|
|
|
.shop-item-desc { |
|
|
font-size: 0.9rem; |
|
|
color: var(--bone-white); |
|
|
opacity: 0.8; |
|
|
font-family: 'MedievalSharp', cursive; |
|
|
} |
|
|
|
|
|
.shop-item-price { |
|
|
font-family: 'MedievalSharp', cursive; |
|
|
color: gold; |
|
|
margin-left: 20px; |
|
|
white-space: nowrap; |
|
|
} |
|
|
|
|
|
.buy-btn { |
|
|
background: linear-gradient(to bottom, #4CAF50, #2E7D32); |
|
|
border: 1px solid #81C784; |
|
|
color: white; |
|
|
padding: 8px 15px; |
|
|
border-radius: 5px; |
|
|
cursor: pointer; |
|
|
font-family: 'Cinzel Decorative', cursive; |
|
|
transition: all 0.2s; |
|
|
} |
|
|
|
|
|
.buy-btn:hover { |
|
|
background: linear-gradient(to bottom, #66BB6A, #388E3C); |
|
|
} |
|
|
|
|
|
.buy-btn:active { |
|
|
transform: scale(0.95); |
|
|
} |
|
|
|
|
|
.material-symbols-outlined { |
|
|
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; |
|
|
margin-right: 10px; |
|
|
color: var(--torch-orange); |
|
|
} |
|
|
|
|
|
#close-shop { |
|
|
position: absolute; |
|
|
top: 10px; |
|
|
right: 10px; |
|
|
background: none; |
|
|
border: none; |
|
|
color: var(--torch-orange); |
|
|
font-size: 1.5rem; |
|
|
cursor: pointer; |
|
|
} |
|
|
|
|
|
|
|
|
#pause-menu { |
|
|
position: absolute; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: rgba(0, 0, 0, 0.85); |
|
|
display: none; |
|
|
flex-direction: column; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
z-index: 20; |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.pause-title { |
|
|
font-size: 3.5rem; |
|
|
color: var(--torch-orange); |
|
|
text-shadow: 0 0 10px var(--blood-red); |
|
|
margin-bottom: 40px; |
|
|
font-family: 'UnifrakturMaguntia', cursive; |
|
|
} |
|
|
|
|
|
|
|
|
#level-select { |
|
|
position: absolute; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: rgba(0, 0, 0, 0.9); |
|
|
display: none; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
z-index: 60; |
|
|
color: var(--bone-white); |
|
|
} |
|
|
|
|
|
.level-select-title { |
|
|
font-size: 2.5rem; |
|
|
margin-bottom: 30px; |
|
|
color: var(--torch-orange); |
|
|
text-shadow: 0 0 10px var(--blood-red); |
|
|
} |
|
|
|
|
|
.levels-container { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); |
|
|
gap: 15px; |
|
|
width: 90%; |
|
|
max-width: 500px; |
|
|
} |
|
|
|
|
|
.level-btn { |
|
|
aspect-ratio: 1; |
|
|
display: flex; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
background: linear-gradient(135deg, rgba(61, 0, 102, 0.7), rgba(139, 0, 0, 0.7)); |
|
|
border: 2px solid var(--rusty-metal); |
|
|
border-radius: 10px; |
|
|
color: var(--bone-white); |
|
|
font-size: 1.5rem; |
|
|
font-weight: bold; |
|
|
cursor: pointer; |
|
|
transition: all 0.3s; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.level-btn:hover { |
|
|
transform: scale(1.05); |
|
|
box-shadow: 0 0 15px var(--torch-orange); |
|
|
} |
|
|
|
|
|
.level-btn.completed { |
|
|
border: 2px solid gold; |
|
|
color: gold; |
|
|
} |
|
|
|
|
|
.level-btn.locked { |
|
|
opacity: 0.5; |
|
|
pointer-events: none; |
|
|
} |
|
|
|
|
|
|
|
|
#controls-info { |
|
|
position: absolute; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background: rgba(0, 0, 0, 0.9); |
|
|
display: none; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
z-index: 60; |
|
|
color: var(--bone-white); |
|
|
text-align: center; |
|
|
padding: 20px; |
|
|
} |
|
|
|
|
|
.controls-info-content { |
|
|
max-width: 500px; |
|
|
background: rgba(139, 0, 0, 0.2); |
|
|
border: 2px solid var(--rusty-metal); |
|
|
border-radius: 15px; |
|
|
padding: 30px; |
|
|
} |
|
|
|
|
|
|
|
|
@media (max-width: 768px) { |
|
|
.game-title { |
|
|
font-size: 3rem; |
|
|
} |
|
|
|
|
|
.game-subtitle { |
|
|
font-size: 1.2rem; |
|
|
} |
|
|
|
|
|
.menu-btn { |
|
|
font-size: 1.1rem; |
|
|
padding: 12px 20px; |
|
|
} |
|
|
|
|
|
.control-btn { |
|
|
width: 60px; |
|
|
height: 60px; |
|
|
font-size: 1.5rem; |
|
|
} |
|
|
|
|
|
#joystick-area { |
|
|
width: 130px; |
|
|
height: 130px; |
|
|
} |
|
|
|
|
|
#joystick { |
|
|
width: 55px; |
|
|
height: 55px; |
|
|
} |
|
|
} |
|
|
|
|
|
@media (min-width: 1200px) { |
|
|
.game-title { |
|
|
font-size: 5rem; |
|
|
} |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div id="game-container"> |
|
|
|
|
|
<div id="loading-screen"> |
|
|
<div class="pentagram"></div> |
|
|
<h1>GHOSTLY KNIGHT</h1> |
|
|
<div id="loading-bar-container"> |
|
|
<div id="loading-bar"></div> |
|
|
</div> |
|
|
<p id="loading-text">Unraveling the cursed scrolls...</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="title-screen"> |
|
|
<div class="menu-bg-overlay"></div> |
|
|
<div class="menu-bg-elements"> |
|
|
<div class="chains" style="left: 10%; top: -50px; width: 80px;"></div> |
|
|
<div class="chains" style="right: 15%; top: -30px; width: 60px; animation-delay: 0.5s;"></div> |
|
|
<div class="bones" style="left: 5%; bottom: 20%; transform: rotate(-30deg);"></div> |
|
|
<div class="bones" style="right: 10%; bottom: 15%; transform: rotate(20deg); width: 80px; height: 40px;"></div> |
|
|
<div class="bones" style="left: 15%; top: 25%; transform: rotate(45deg); width: 70px;"></div> |
|
|
</div> |
|
|
|
|
|
<div id="title-container"> |
|
|
<h1 class="game-title">GHOSTLY KNIGHT</h1> |
|
|
<p class="game-subtitle">Cursed Crypts</p> |
|
|
|
|
|
<div class="menu-container"> |
|
|
<button class="menu-btn" id="start-btn">BEGIN YOUR QUEST</button> |
|
|
<button class="menu-btn" id="level-select-btn">ABYSS SELECTION</button> |
|
|
<button class="menu-btn" id="controls-btn">FORBIDDEN KNOWLEDGE</button> |
|
|
<button class="menu-btn" id="shop-btn">DEMONIC MARKET</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<canvas id="canvas"></canvas> |
|
|
|
|
|
|
|
|
<div id="game-ui"> |
|
|
<div id="health"> |
|
|
<span class="material-symbols-outlined">favorite</span> |
|
|
<span id="health-value">5</span> |
|
|
</div> |
|
|
<div id="score"> |
|
|
<span class="material-symbols-outlined">stars</span> |
|
|
<span id="score-value">0</span> |
|
|
</div> |
|
|
<div id="level"> |
|
|
<span class="material-symbols-outlined">levels</span> |
|
|
<span id="level-value">1-1</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="joystick-area"> |
|
|
<div id="joystick"></div> |
|
|
</div> |
|
|
|
|
|
<div id="controls"> |
|
|
<div class="control-btn" id="jump-btn"> |
|
|
<span class="material-symbols-outlined">arrow_upward</span> |
|
|
</div> |
|
|
<div class="control-btn" id="attack-btn"> |
|
|
<span class="material-symbols-outlined">bolt</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="boss-health" style="display: none;"> |
|
|
<div id="boss-health-fill"></div> |
|
|
</div> |
|
|
<div id="boss-name" style="display: none;"></div> |
|
|
|
|
|
|
|
|
<div id="pause-menu"> |
|
|
<h1 class="pause-title">PAUSED</h1> |
|
|
<button class="menu-btn" id="resume-btn">RESUME</button> |
|
|
<button class="menu-btn" id="restart-btn">RESTART LEVEL</button> |
|
|
<button class="menu-btn" id="quit-btn">RETURN TO SANCTUARY</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="level-complete" style="display: none;"> |
|
|
<h1>LEVEL COMPLETE!</h1> |
|
|
<p id="level-score">REAPED SOULS: 0</p> |
|
|
<p id="level-time">TIME: 0:00</p> |
|
|
<div id="next-level-container" style="margin-top: 30px;"> |
|
|
<button class="menu-btn" id="next-level-btn">DESCEND DEEPER</button> |
|
|
<button class="menu-btn" id="return-btn">RETURN TO SANCTUARY</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="shop-overlay"> |
|
|
<div id="shop-container"> |
|
|
<button id="close-shop"> |
|
|
<span class="material-symbols-outlined">close</span> |
|
|
</button> |
|
|
<h2 class="shop-header">DEMONIC MARKET</h2> |
|
|
|
|
|
<div id="shop-items"> |
|
|
<div class="shop-item" data-id="health_potion"> |
|
|
<div class="shop-item-info"> |
|
|
<div class="shop-item-name">Elixir of Vitality</div> |
|
|
<div class="shop-item-desc">Restores health when consumed</div> |
|
|
</div> |
|
|
<div class="shop-item-price">$1.99</div> |
|
|
<button class="buy-btn">Purchase</button> |
|
|
</div> |
|
|
|
|
|
<div class="shop-item" data-id="damage_boost"> |
|
|
<div class="shop-item-info"> |
|
|
<div class="shop-item-name">Potion of Wrath</div> |
|
|
<div class="shop-item-desc">50% damage boost for 5 minutes</div> |
|
|
</div> |
|
|
<div class="shop-item-price">$2.99</div> |
|
|
<button class="buy-btn">Purchase</button> |
|
|
</div> |
|
|
|
|
|
<div class="shop-item" data-id="gold_pack"> |
|
|
<div class="shop-item-info"> |
|
|
<div class="shop-item-name">Soul Gold Cache</div> |
|
|
<div class="shop-item-desc">5,000 gold pieces to trade</div> |
|
|
</div> |
|
|
<div class="shop-item-price">$4.99</div> |
|
|
<button class="buy-btn">Purchase</button> |
|
|
</div> |
|
|
|
|
|
<div class="shop-item" data-id="cosmetic_armor"> |
|
|
<div class="shop-item-info"> |
|
|
<div class="shop-item-name">Phantom Armor Set</div> |
|
|
<div class="shop-item-desc">Ghostly cosmetic appearance</div> |
|
|
</div> |
|
|
<div class="shop-item-price">$3.99</div> |
|
|
<button class="buy-btn">Purchase</button> |
|
|
</div> |
|
|
|
|
|
<div class="shop-item" data-id="premium_bundle"> |
|
|
<div class="shop-item-info"> |
|
|
<div class="shop-item-name">Dark Lord's Bundle</div> |
|
|
<div class="shop-item-desc">All items + 10,000 gold</div> |
|
|
</div> |
|
|
<div class="shop-item-price">$9.99</div> |
|
|
<button class="buy-btn">Purchase</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="level-select"> |
|
|
<h2 class="level-select-title">CHOOSE YOUR DAMNATION</h2> |
|
|
<div class="levels-container"> |
|
|
<button class="level-btn" data-level="1-1">1-1</button> |
|
|
<button class="level-btn locked" data-level="1-2">1-2</button> |
|
|
<button class="level-btn locked" data-level="1-3">1-3</button> |
|
|
<button class="level-btn locked" data-level="1-4">1-4</button> |
|
|
<button class="level-btn locked" data-level="1-5">1-5</button> |
|
|
</div> |
|
|
<button class="menu-btn" id="back-to-menu" style="margin-top: 30px;">BACK</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="controls-info"> |
|
|
<div class="controls-info-content"> |
|
|
<h2>ARCANE CONTROLS</h2> |
|
|
<p style="margin: 20px 0;"> |
|
|
<span style="display: inline-block; width: 60px;">LEFT:</span> Move the joystick left |
|
|
</p> |
|
|
<p style="margin: 20px 0;"> |
|
|
<span style="display: inline-block; width: 60px;">RIGHT:</span> Move the joystick right |
|
|
</p> |
|
|
<p style="margin: 20px 0;"> |
|
|
<span class="material-symbols-outlined" style="display: inline-block; width: 60px; text-align: center;">arrow_upward</span> Jump |
|
|
</p> |
|
|
<p style="margin: 20px 0;"> |
|
|
<span class="material-symbols-outlined" style="display: inline-block; width: 60px; text-align: center;">bolt</span> Attack |
|
|
</p> |
|
|
<button class="menu-btn" id="back-from-controls" style="margin-top: 30px;">I UNDERSTAND</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
const gameState = { |
|
|
currentLevel: '1-1', |
|
|
score: 0, |
|
|
completedLevels: ['1-1'], |
|
|
purchasedItems: [], |
|
|
coins: 0, |
|
|
highScores: {}, |
|
|
playerInventory: { |
|
|
healthPotions: 0, |
|
|
damageBoosts: 0, |
|
|
cosmeticArmor: false |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
function initGooglePlayGames() { |
|
|
gapi.load('auth2', function() { |
|
|
gapi.auth2.init({ |
|
|
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com' |
|
|
}).then(() => { |
|
|
console.log('Google Play Games initialized'); |
|
|
setupInAppPurchases(); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function setupInAppPurchases() { |
|
|
const purchases = window.cordova.plugins.billing; |
|
|
|
|
|
purchases.initialize("YOUR_PLAY_STORE_KEY") |
|
|
.then(() => { |
|
|
console.log("Billing initialized"); |
|
|
return purchases.getProducts([ |
|
|
'health_potion', |
|
|
'damage_boost', |
|
|
'gold_pack', |
|
|
'cosmetic_armor', |
|
|
'premium_bundle' |
|
|
]); |
|
|
}) |
|
|
.then(products => { |
|
|
console.log("Products loaded:", products); |
|
|
|
|
|
|
|
|
products.forEach(product => { |
|
|
const item = document.querySelector(`.shop-item[data-id="${product.id}"]`); |
|
|
if (item) { |
|
|
const priceElement = item.querySelector('.shop-item-price'); |
|
|
priceElement.textContent = product.price; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelectorAll('.buy-btn').forEach(button => { |
|
|
button.addEventListener('click', () => { |
|
|
const itemId = button.parentElement.dataset.id; |
|
|
purchases.purchase(itemId) |
|
|
.then(purchase => { |
|
|
console.log("Purchase successful:", purchase); |
|
|
processPurchase(itemId); |
|
|
}) |
|
|
.catch(error => { |
|
|
console.log("Purchase failed:", error); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}) |
|
|
.catch(error => { |
|
|
console.log("Error initializing billing:", error); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function processPurchase(itemId) { |
|
|
switch(itemId) { |
|
|
case 'health_potion': |
|
|
gameState.playerInventory.healthPotions += 1; |
|
|
showToast('Elixir of Vitality added to your inventory'); |
|
|
break; |
|
|
case 'damage_boost': |
|
|
gameState.playerInventory.damageBoosts += 1; |
|
|
showToast('Potion of Wrath added to your inventory'); |
|
|
break; |
|
|
case 'gold_pack': |
|
|
gameState.coins += 5000; |
|
|
showToast('5,000 gold pieces added to your treasury'); |
|
|
break; |
|
|
case 'cosmetic_armor': |
|
|
gameState.playerInventory.cosmeticArmor = true; |
|
|
showToast('Phantom Armor Set equipped'); |
|
|
break; |
|
|
case 'premium_bundle': |
|
|
gameState.playerInventory.healthPotions += 1; |
|
|
gameState.playerInventory.damageBoosts += 1; |
|
|
gameState.playerInventory.cosmeticArmor = true; |
|
|
gameState.coins += 10000; |
|
|
showToast('Dark Lord\'s Bundle contents awarded'); |
|
|
break; |
|
|
} |
|
|
|
|
|
|
|
|
if (!gameState.purchasedItems.includes(itemId)) { |
|
|
gameState.purchasedItems.push(itemId); |
|
|
} |
|
|
|
|
|
|
|
|
updateGameUI(); |
|
|
} |
|
|
|
|
|
|
|
|
function showToast(message) { |
|
|
const toast = document.createElement('div'); |
|
|
toast.textContent = message; |
|
|
toast.style.position = 'fixed'; |
|
|
toast.style.bottom = '20%'; |
|
|
toast.style.left = '50%'; |
|
|
toast.style.transform = 'translateX(-50%)'; |
|
|
toast.style.backgroundColor = 'rgba(0,0,0,0.7)'; |
|
|
toast.style.color = 'white'; |
|
|
toast.style.padding = '10px 20px'; |
|
|
toast.style.borderRadius = '5px'; |
|
|
toast.style.zIndex = '1000'; |
|
|
document.body.appendChild(toast); |
|
|
|
|
|
setTimeout(() => { |
|
|
toast.style.transition = 'opacity 1s'; |
|
|
toast.style.opacity = '0'; |
|
|
setTimeout(() => toast.remove(), 1000); |
|
|
}, 3000); |
|
|
} |
|
|
|
|
|
|
|
|
function initControls() { |
|
|
|
|
|
const joystickArea = document.getElementById('joystick-area'); |
|
|
const joystick = document.getElementById('joystick'); |
|
|
|
|
|
let joystickActive = false; |
|
|
let joystickStartX, joystickStartY; |
|
|
let joystickMoveX, joystickMoveY; |
|
|
const maxDistance = 50; |
|
|
|
|
|
joystickArea.addEventListener('touchstart', (e) => { |
|
|
e.preventDefault(); |
|
|
const touch = e.touches[0]; |
|
|
const rect = joystickArea.getBoundingClientRect(); |
|
|
|
|
|
joystickActive = true; |
|
|
joystickStartX = rect.left + rect.width / 2; |
|
|
joystickStartY = rect.top + rect.height / 2; |
|
|
|
|
|
updateJoystickPosition(touch); |
|
|
}); |
|
|
|
|
|
document.addEventListener('touchmove', (e) => { |
|
|
if (joystickActive) { |
|
|
e.preventDefault(); |
|
|
updateJoystickPosition(e.touches[0]); |
|
|
} |
|
|
}, { passive: false }); |
|
|
|
|
|
document.addEventListener('touchend', () => { |
|
|
joystickActive = false; |
|
|
joystick.style.transform = 'translate(0, 0)'; |
|
|
|
|
|
|
|
|
}); |
|
|
|
|
|
function updateJoystickPosition(touch) { |
|
|
const moveX = touch.clientX - joystickStartX; |
|
|
const moveY = touch.clientY - joystickStartY; |
|
|
const distance = Math.sqrt(moveX * moveX + moveY * moveY); |
|
|
|
|
|
let angle = Math.atan2(moveY, moveX); |
|
|
let limitedDistance = Math.min(distance, maxDistance); |
|
|
|
|
|
let finalX = Math.cos(angle) * limitedDistance; |
|
|
let finalY = Math.sin(angle) * limitedDistance; |
|
|
|
|
|
|
|
|
joystick.style.transform = `translate(${finalX}px, ${finalY}px)`; |
|
|
|
|
|
|
|
|
const deadzone = 10; |
|
|
|
|
|
if (finalX < -deadzone) { |
|
|
|
|
|
} else if (finalX > deadzone) { |
|
|
|
|
|
} else { |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
document.getElementById('jump-btn').addEventListener('touchstart', () => { |
|
|
|
|
|
}); |
|
|
|
|
|
document.getElementById('jump-btn').addEventListener('touchend', () => { |
|
|
|
|
|
}); |
|
|
|
|
|
document.getElementById('attack-btn').addEventListener('touchstart', () => { |
|
|
|
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function initMenuNavigation() { |
|
|
document.getElementById('start-btn').addEventListener('click', startGame); |
|
|
document.getElementById('level-select-btn').addEventListener('click', showLevelSelect); |
|
|
document.getElementById('controls-btn').addEventListener('click', showControlsInfo); |
|
|
document.getElementById('shop-btn').addEventListener('click', showShop); |
|
|
|
|
|
document.getElementById('back-to-menu').addEventListener('click', hideLevelSelect); |
|
|
document.getElementById('back-from-controls').addEventListener('click', hideControlsInfo); |
|
|
document.getElementById('close-shop').addEventListener('click', hideShop); |
|
|
|
|
|
|
|
|
document.querySelectorAll('.level-btn').forEach(btn => { |
|
|
if (!btn.classList.contains('locked')) { |
|
|
btn.addEventListener('click', () => { |
|
|
const level = btn.dataset.level; |
|
|
startGame(level); |
|
|
}); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function showLevelSelect() { |
|
|
document.getElementById('level-select').style.display = 'flex'; |
|
|
document.getElementById('title-screen').style.display = 'none'; |
|
|
|
|
|
|
|
|
document.querySelectorAll('.level-btn').forEach(btn => { |
|
|
if (gameState.completedLevels.includes(btn.dataset.level)) { |
|
|
btn.classList.add('completed'); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
function hideLevelSelect() { |
|
|
document.getElementById('level-select').style.display = 'none'; |
|
|
document.getElementById('title-screen').style.display = 'flex'; |
|
|
} |
|
|
|
|
|
function showControlsInfo() { |
|
|
document.getElementById('controls-info').style.display = 'flex'; |
|
|
document.getElementById('title-screen').style.display = 'none'; |
|
|
} |
|
|
|
|
|
function hideControlsInfo() { |
|
|
document.getElementById('controls-info').style.display = 'none'; |
|
|
document.getElementById('title-screen').style.display = 'flex'; |
|
|
} |
|
|
|
|
|
function showShop() { |
|
|
document.getElementById('shop-overlay').style.display = 'flex'; |
|
|
document.getElementById('title-screen').style.display = 'none'; |
|
|
} |
|
|
|
|
|
function hideShop() { |
|
|
document.getElementById('shop-overlay').style.display = 'none'; |
|
|
document.getElementById('title-screen').style.display = 'flex'; |
|
|
} |
|
|
|
|
|
|
|
|
function startGame(level = '1-1') { |
|
|
|
|
|
gameState.currentLevel = level; |
|
|
|
|
|
|
|
|
document.getElementById('title-screen').style.display = 'none'; |
|
|
document.getElementById('level-select').style.display = 'none'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`Starting level ${level}`); |
|
|
} |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
|
|
|
simulateLoading(); |
|
|
|
|
|
|
|
|
initControls(); |
|
|
initMenuNavigation(); |
|
|
|
|
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
function simulateLoading() { |
|
|
const loadingBar = document.getElementById('loading-bar'); |
|
|
const loadingText = document.getElementById('loading-text'); |
|
|
const texts = [ |
|
|
"Unraveling the cursed scrolls...", |
|
|
"Summoning ancient spirits...", |
|
|
"Lighting torches in the dungeon...", |
|
|
"Preparing the undead army...", |
|
|
"Forging demonic armor...", |
|
|
"Charging magical weapons...", |
|
|
"Awakening the dark lords...", |
|
|
"Drawing pentagrams...", |
|
|
"Reciting forbidden chants..." |
|
|
]; |
|
|
|
|
|
let progress = 0; |
|
|
const interval = setInterval(() => { |
|
|
progress += Math.random() * 10; |
|
|
if (progress >= 100) { |
|
|
progress = 100; |
|
|
clearInterval(interval); |
|
|
|
|
|
setTimeout(() => { |
|
|
document.getElementById('loading-screen').style.opacity = '0'; |
|
|
setTimeout(() => { |
|
|
document.getElementById('loading-screen').style.display = 'none'; |
|
|
document.getElementById('title-screen').style.display = 'flex'; |
|
|
}, 500); |
|
|
}, 300); |
|
|
} |
|
|
|
|
|
loadingBar.style.width = `${progress}%`; |
|
|
loadingText.textContent = texts[Math.floor(Math.random() * texts.length)]; |
|
|
}, 300); |
|
|
} |
|
|
</script> |
|
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> |
|
|
</html> |