|
<!DOCTYPE html> |
|
<html lang="ru"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title> </title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=Comic+Neue:wght@400;700&display=swap'); |
|
|
|
:root { |
|
--sp-red: #FF0000; |
|
--sp-blue: #0096FF; |
|
--sp-yellow: #FFDE00; |
|
--sp-green: #00A550; |
|
--sp-orange: #FF8C00; |
|
--sp-purple: #800080; |
|
--sp-brown: #8B4513; |
|
--sp-pink: #FF69B4; |
|
} |
|
|
|
body { |
|
font-family: 'Comic Neue', cursive; |
|
background-color: #f0f0f0; |
|
background-image: url('https://i.imgur.com/XWQ5BQa.png'); |
|
background-size: cover; |
|
background-attachment: fixed; |
|
min-height: 100vh; |
|
} |
|
|
|
.character-card { |
|
transition: all 0.3s ease; |
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
|
border: 3px solid #000; |
|
} |
|
|
|
.character-card:hover { |
|
transform: translateY(-5px); |
|
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.2); |
|
} |
|
|
|
.kenny { |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.kenny::after { |
|
content: "О боже! Они убили Кенни!"; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background-color: rgba(255, 0, 0, 0.8); |
|
color: white; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
font-weight: bold; |
|
opacity: 0; |
|
transition: opacity 0.3s; |
|
} |
|
|
|
.kenny.dead::after { |
|
opacity: 1; |
|
} |
|
|
|
.attack-animation { |
|
animation: attack 0.3s ease; |
|
} |
|
|
|
@keyframes attack { |
|
0% { transform: translateX(0); } |
|
50% { transform: translateX(10px); } |
|
100% { transform: translateX(0); } |
|
} |
|
|
|
.progress-bar { |
|
height: 15px; |
|
border-radius: 10px; |
|
overflow: hidden; |
|
background-color: #e5e7eb; |
|
border: 2px solid #000; |
|
} |
|
|
|
.progress-fill { |
|
height: 100%; |
|
transition: width 0.3s ease; |
|
} |
|
|
|
.south-park-modal { |
|
background-color: #fff; |
|
border: 4px solid #000; |
|
border-radius: 0; |
|
box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.2); |
|
} |
|
|
|
.south-park-btn { |
|
background-color: var(--sp-red); |
|
color: white; |
|
border: 2px solid #000; |
|
border-radius: 0; |
|
font-weight: bold; |
|
padding: 8px 16px; |
|
transition: all 0.2s; |
|
font-family: 'Comic Neue', cursive; |
|
text-transform: uppercase; |
|
letter-spacing: 1px; |
|
} |
|
|
|
.south-park-btn:hover { |
|
transform: translate(-2px, -2px); |
|
box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.2); |
|
} |
|
|
|
.south-park-btn:active { |
|
transform: translate(0, 0); |
|
box-shadow: none; |
|
} |
|
|
|
.speech-bubble { |
|
position: relative; |
|
background: #fff; |
|
border: 2px solid #000; |
|
border-radius: 0; |
|
padding: 10px; |
|
margin: 10px 0; |
|
font-size: 14px; |
|
} |
|
|
|
.speech-bubble:after { |
|
content: ''; |
|
position: absolute; |
|
bottom: -10px; |
|
left: 20px; |
|
border-width: 10px 10px 0; |
|
border-style: solid; |
|
border-color: #fff transparent; |
|
display: block; |
|
width: 0; |
|
} |
|
|
|
.speech-bubble:before { |
|
content: ''; |
|
position: absolute; |
|
bottom: -12px; |
|
left: 19px; |
|
border-width: 11px 11px 0; |
|
border-style: solid; |
|
border-color: #000 transparent; |
|
display: block; |
|
width: 0; |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.container { |
|
padding: 10px; |
|
} |
|
|
|
header { |
|
flex-direction: column; |
|
text-align: center; |
|
margin-bottom: 15px; |
|
} |
|
|
|
header img { |
|
margin: 0 auto 10px; |
|
} |
|
|
|
.grid-cols-1 { |
|
grid-template-columns: 1fr; |
|
} |
|
|
|
.lg\:grid-cols-3 { |
|
grid-template-columns: 1fr; |
|
} |
|
|
|
.character-card { |
|
padding: 10px; |
|
} |
|
|
|
.character-card img { |
|
width: 60px; |
|
height: 60px; |
|
} |
|
|
|
#battle-log { |
|
height: 150px; |
|
font-size: 13px; |
|
} |
|
|
|
.south-park-btn { |
|
padding: 6px 12px; |
|
font-size: 14px; |
|
} |
|
|
|
.progress-bar { |
|
height: 12px; |
|
} |
|
} |
|
|
|
|
|
.stan-bg { background-color: var(--sp-blue); } |
|
.cartman-bg { background-color: var(--sp-red); } |
|
.kyle-bg { background-color: var(--sp-green); } |
|
.kenny-bg { background-color: var(--sp-orange); } |
|
.butters-bg { background-color: var(--sp-yellow); } |
|
.wendy-bg { background-color: var(--sp-pink); } |
|
.randy-bg { background-color: var(--sp-brown); } |
|
|
|
|
|
@keyframes pulse { |
|
0% { transform: scale(1); } |
|
50% { transform: scale(1.05); } |
|
100% { transform: scale(1); } |
|
} |
|
|
|
.pulse-animation { |
|
animation: pulse 1.5s infinite; |
|
} |
|
|
|
|
|
.paper-effect { |
|
background-color: white; |
|
border: 2px solid black; |
|
box-shadow: 5px 5px 0 rgba(0,0,0,0.2); |
|
} |
|
</style> |
|
</head> |
|
<body class="min-h-screen"> |
|
<div class="container mx-auto px-2 py-4"> |
|
|
|
<header class="flex flex-col md:flex-row justify-between items-center mb-4 md:mb-8"> |
|
<div class="flex flex-col md:flex-row items-center mb-4 md:mb-0"> |
|
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTN2XYuN2jB0ptwsTR_oVGtzYiEsfY5gIioNQ&s" alt="Логотип South Park" class="h-12 md:h-16 mr-0 md:mr-4 mb-2 md:mb-0"> |
|
<h1 class="text-2xl md:text-4xl font-bold text-red-600 text-center md:text-left">South Park: Кликер Битва</h1> |
|
</div> |
|
<div class="flex items-center space-x-2 md:space-x-4"> |
|
<div class="paper-effect p-2 md:p-3 flex items-center"> |
|
<i class="fas fa-star text-yellow-400 text-xl md:text-2xl mr-1 md:mr-2"></i> |
|
<span id="stars" class="text-xl md:text-2xl font-bold">0</span> |
|
</div> |
|
<div class="paper-effect p-2 md:p-3"> |
|
<span class="text-xs md:text-sm block">Уровень</span> |
|
<span id="level" class="text-xl md:text-2xl font-bold">1</span> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4 md:gap-6"> |
|
|
|
<div class="paper-effect p-4 md:p-6 rounded-xl"> |
|
<h2 class="text-xl md:text-2xl font-bold mb-3 text-center text-blue-600">Ваш персонаж</h2> |
|
<div id="player-character" class="character-card stan-bg p-3 md:p-4 rounded-lg text-center"> |
|
<img id="player-image" src="https://upload.wikimedia.org/wikipedia/ru/9/9e/Stan.png" alt="Стэн" class="w-20 h-20 md:w-32 md:h-32 mx-auto mb-2"> |
|
<h3 id="player-name" class="text-lg md:text-xl font-bold">Стэн Марш</h3> |
|
<div class="progress-bar mb-2"> |
|
<div id="player-health" class="progress-fill bg-green-500" style="width: 100%"></div> |
|
</div> |
|
<div class="flex justify-between text-xs md:text-sm mb-2"> |
|
<span>Здоровье: <span id="player-current-hp">100</span>/<span id="player-max-hp">100</span></span> |
|
<span>Уровень: <span id="player-level">1</span></span> |
|
</div> |
|
<div class="progress-bar mb-2"> |
|
<div id="player-xp" class="progress-fill bg-blue-500" style="width: 0%"></div> |
|
</div> |
|
<div class="text-xs md:text-sm mb-3">Опыт: <span id="player-current-xp">0</span>/<span id="player-next-level-xp">100</span></div> |
|
<div class="grid grid-cols-2 gap-2 mb-3"> |
|
<div class="bg-blue-50 p-1 md:p-2 rounded"> |
|
<span class="block text-xs md:text-sm">Атака</span> |
|
<span id="player-attack" class="font-bold">10</span> |
|
</div> |
|
<div class="bg-blue-50 p-1 md:p-2 rounded"> |
|
<span class="block text-xs md:text-sm">Защита</span> |
|
<span id="player-defense" class="font-bold">5</span> |
|
</div> |
|
</div> |
|
<button id="upgrade-btn" class="w-full south-park-btn bg-green-600 hover:bg-green-700 text-white py-1 md:py-2 rounded-lg font-bold mb-2"> |
|
Улучшить ($<span id="upgrade-cost">50</span>) |
|
</button> |
|
<button id="heal-btn" class="w-full south-park-btn bg-red-600 hover:bg-red-700 text-white py-1 md:py-2 rounded-lg font-bold"> |
|
Лечение ($<span id="heal-cost">30</span>) |
|
</button> |
|
</div> |
|
|
|
<div class="mt-4 md:mt-6"> |
|
<h3 class="text-base md:text-lg font-bold mb-2">Инвентарь</h3> |
|
<div class="grid grid-cols-3 gap-2"> |
|
<div class="bg-yellow-100 p-1 md:p-2 rounded text-center border border-yellow-300"> |
|
<i class="fas fa-utensils text-lg md:text-xl mb-1"></i> |
|
<span class="block text-xs md:text-sm">Сырные шарики</span> |
|
<span id="cheesy-poofs" class="font-bold">0</span> |
|
</div> |
|
<div class="bg-purple-100 p-1 md:p-2 rounded text-center border border-purple-300"> |
|
<i class="fas fa-gem text-lg md:text-xl mb-1"></i> |
|
<span class="block text-xs md:text-sm">Тигрида Виид</span> |
|
<span id="tegridy-weed" class="font-bold">0</span> |
|
</div> |
|
<div class="bg-red-100 p-1 md:p-2 rounded text-center border border-red-300"> |
|
<i class="fas fa-ghost text-lg md:text-xl mb-1"></i> |
|
<span class="block text-xs md:text-sm">Души Кенни</span> |
|
<span id="kenny-souls" class="font-bold">0</span> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="paper-effect p-4 md:p-6 rounded-xl"> |
|
<h2 class="text-xl md:text-2xl font-bold mb-3 text-center text-red-600">Арена битв</h2> |
|
<div id="battle-log" class="bg-gray-100 p-3 rounded-lg h-40 md:h-64 overflow-y-auto mb-3"> |
|
<div class="speech-bubble"> |
|
<p>Добро пожаловать в South Park: Кликер Битва! Выберите персонажа для боя!</p> |
|
</div> |
|
</div> |
|
|
|
<div class="flex flex-col md:flex-row justify-center mb-3 space-y-2 md:space-y-0 md:space-x-3"> |
|
<button id="attack-btn" class="south-park-btn mr-0 md:mr-4"> |
|
<i class="fas fa-fist-raised mr-1 md:mr-2"></i>Атака |
|
</button> |
|
<button id="special-btn" class="south-park-btn bg-yellow-500 hover:bg-yellow-600"> |
|
<i class="fas fa-bolt mr-1 md:mr-2"></i>Ульта (<span id="special-charges">0</span>/3) |
|
</button> |
|
</div> |
|
|
|
<div class="text-center mb-3"> |
|
<button id="collect-stars-btn" class="south-park-btn bg-purple-600 hover:bg-purple-700 pulse-animation"> |
|
<i class="fas fa-star mr-1 md:mr-2"></i>Собирать звёзды (<span id="star-timer">5</span>с) |
|
</button> |
|
</div> |
|
|
|
<div id="enemy-area" class="character-card bg-red-100 p-3 md:p-4 rounded-lg text-center"> |
|
<p class="text-gray-500 italic">Выберите противника для боя</p> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="paper-effect p-4 md:p-6 rounded-xl"> |
|
<h2 class="text-xl md:text-2xl font-bold mb-3 text-center text-green-600">Персонажи</h2> |
|
<div class="grid grid-cols-2 gap-3"> |
|
<div class="character-card cartman-bg p-2 md:p-3 rounded-lg text-center cursor-pointer enemy-select" data-enemy="cartman"> |
|
<img src="https://upload.wikimedia.org/wikipedia/ru/6/68/Eric_Cartman.png" alt="Картман" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1"> |
|
<h3 class="font-bold text-sm md:text-base">Эрик Картман</h3> |
|
<div class="text-xs">Уровень 1</div> |
|
</div> |
|
<div class="character-card kyle-bg p-2 md:p-3 rounded-lg text-center cursor-pointer enemy-select" data-enemy="kyle"> |
|
<img src="https://upload.wikimedia.org/wikipedia/ru/4/4b/Kyle2.jpg" alt="Кайл" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1"> |
|
<h3 class="font-bold text-sm md:text-base">Кайл Брофловски</h3> |
|
<div class="text-xs">Уровень 1</div> |
|
</div> |
|
<div class="character-card kenny kenny-bg p-2 md:p-3 rounded-lg text-center cursor-pointer enemy-select" data-enemy="kenny"> |
|
<img src="https://cdn.ruwiki.ru/ruwiki/files/thumb/4/42/Kenny-sp.jpg/274px-Kenny-sp.jpg" alt="Кенни" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1"> |
|
<h3 class="font-bold text-sm md:text-base">Кенни Маккормик</h3> |
|
<div class="text-xs">Уровень 1</div> |
|
</div> |
|
<div class="character-card butters-bg p-2 md:p-3 rounded-lg text-center cursor-pointer enemy-select" data-enemy="butters"> |
|
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSXEt9XdmVfHWNPsRyCzWzTWv3SpMpKEs_Pcw&s" alt="Баттерс" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1"> |
|
<h3 class="font-bold text-sm md:text-base">Баттерс Стотч</h3> |
|
<div class="text-xs">Уровень 1</div> |
|
</div> |
|
<div class="character-card wendy-bg p-2 md:p-3 rounded-lg text-center cursor-pointer enemy-select" data-enemy="wendy"> |
|
<img src="https://static.wikia.nocookie.net/southpark/images/d/dc/WendyNoHat-0.png/revision/latest?cb=20230429191256" alt="Венди" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1"> |
|
<h3 class="font-bold text-sm md:text-base">Венди Тестабургер</h3> |
|
<div class="text-xs">Уровень 1</div> |
|
</div> |
|
<div class="character-card randy-bg p-2 md:p-3 rounded-lg text-center cursor-pointer enemy-select" data-enemy="randy"> |
|
<img src="https://upload.wikimedia.org/wikipedia/ru/d/d6/Randy_Marsh.png" alt="Рэнди" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1"> |
|
<h3 class="font-bold text-sm md:text-base">Рэнди Марш</h3> |
|
<div class="text-xs">Уровень 1</div> |
|
</div> |
|
</div> |
|
|
|
<div class="mt-4 md:mt-6"> |
|
<h3 class="text-base md:text-lg font-bold mb-2">Магазин</h3> |
|
<div class="space-y-2"> |
|
<button class="w-full bg-yellow-200 hover:bg-yellow-300 p-2 rounded-lg flex justify-between items-center shop-item" data-item="cheesy-poofs" data-cost="20"> |
|
<span class="text-xs md:text-sm">Сырные шарики (+5 HP)</span> |
|
<span class="font-bold">$20</span> |
|
</button> |
|
<button class="w-full bg-purple-200 hover:bg-purple-300 p-2 rounded-lg flex justify-between items-center shop-item" data-item="tegridy-weed" data-cost="50"> |
|
<span class="text-xs md:text-sm">Тигрида Виид (+2 к атаке)</span> |
|
<span class="font-bold">$50</span> |
|
</button> |
|
<button class="w-full bg-red-200 hover:bg-red-300 p-2 rounded-lg flex justify-between items-center shop-item" data-item="kenny-souls" data-cost="100"> |
|
<span class="text-xs md:text-sm">Душа Кенни (Воскрешение)</span> |
|
<span class="font-bold">$100</span> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="character-select-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> |
|
<div class="south-park-modal p-4 md:p-6 w-full max-w-md mx-4"> |
|
<h2 class="text-xl md:text-2xl font-bold mb-3 md:mb-4 text-center">Выберите своего персонажа</h2> |
|
<div class="grid grid-cols-2 gap-3 mb-4 md:mb-6"> |
|
<div class="character-card stan-bg p-2 md:p-4 rounded-lg text-center cursor-pointer character-select" data-character="stan"> |
|
<img src="https://i.imgur.com/JQ6XgGX.png" alt="Стэн" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1 md:mb-2"> |
|
<h3 class="font-bold text-sm md:text-base">Стэн Марш</h3> |
|
<p class="text-xs md:text-sm">Сбалансированные характеристики</p> |
|
</div> |
|
<div class="character-card cartman-bg p-2 md:p-4 rounded-lg text-center cursor-pointer character-select" data-character="cartman"> |
|
<img src="https://i.imgur.com/3tTQxQk.png" alt="Картман" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1 md:mb-2"> |
|
<h3 class="font-bold text-sm md:text-base">Эрик Картман</h3> |
|
<p class="text-xs md:text-sm">Высокая атака, низкая защита</p> |
|
</div> |
|
<div class="character-card kyle-bg p-2 md:p-4 rounded-lg text-center cursor-pointer character-select" data-character="kyle"> |
|
<img src="https://i.imgur.com/9vGjZQ7.png" alt="Кайл" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1 md:mb-2"> |
|
<h3 class="font-bold text-sm md:text-base">Кайл Брофловски</h3> |
|
<p class="text-xs md:text-sm">Высокая защита, низкая атака</p> |
|
</div> |
|
<div class="character-card kenny kenny-bg p-2 md:p-4 rounded-lg text-center cursor-pointer character-select" data-character="kenny"> |
|
<img src="https://i.imgur.com/5QYrWQk.png" alt="Кенни" class="w-16 h-16 md:w-20 md:h-20 mx-auto mb-1 md:mb-2"> |
|
<h3 class="font-bold text-sm md:text-base">Кенни Маккормик</h3> |
|
<p class="text-xs md:text-sm">Случайные бонусы</p> |
|
</div> |
|
</div> |
|
<button id="confirm-character" class="south-park-btn w-full">Начать игру</button> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
const gameState = { |
|
stars: 0, |
|
level: 1, |
|
money: 0, |
|
selectedCharacter: null, |
|
currentEnemy: null, |
|
battleInProgress: false, |
|
starTimer: 5, |
|
starInterval: null, |
|
specialCharges: 0, |
|
inventory: { |
|
'cheesy-poofs': 0, |
|
'tegridy-weed': 0, |
|
'kenny-souls': 0 |
|
}, |
|
characters: { |
|
'stan': { name: 'Стэн Марш', image: 'https://i.imgur.com/JQ6XgGX.png', attack: 10, defense: 5, maxHp: 100, hp: 100, level: 1, xp: 0, nextLevelXp: 100 }, |
|
'cartman': { name: 'Эрик Картман', image: 'https://i.imgur.com/3tTQxQk.png', attack: 15, defense: 3, maxHp: 90, hp: 90, level: 1, xp: 0, nextLevelXp: 100 }, |
|
'kyle': { name: 'Кайл Брофловски', image: 'https://i.imgur.com/9vGjZQ7.png', attack: 8, defense: 8, maxHp: 110, hp: 110, level: 1, xp: 0, nextLevelXp: 100 }, |
|
'kenny': { name: 'Кенни Маккормик', image: 'https://i.imgur.com/5QYrWQk.png', attack: 12, defense: 4, maxHp: 80, hp: 80, level: 1, xp: 0, nextLevelXp: 100 } |
|
}, |
|
enemies: { |
|
'cartman': { name: 'Эрик Картман', image: 'https://i.imgur.com/3tTQxQk.png', attack: 8, defense: 3, maxHp: 50, hp: 50, level: 1, xpReward: 20, moneyReward: 15 }, |
|
'kyle': { name: 'Кайл Брофловски', image: 'https://i.imgur.com/9vGjZQ7.png', attack: 7, defense: 5, maxHp: 60, hp: 60, level: 1, xpReward: 25, moneyReward: 20 }, |
|
'kenny': { name: 'Кенни Маккормик', image: 'https://i.imgur.com/5QYrWQk.png', attack: 9, defense: 2, maxHp: 40, hp: 40, level: 1, xpReward: 30, moneyReward: 25, special: "Легко умирает, но возвращается сильнее" }, |
|
'butters': { name: 'Баттерс Стотч', image: 'https://i.imgur.com/7JvYQxQ.png', attack: 5, defense: 7, maxHp: 70, hp: 70, level: 1, xpReward: 35, moneyReward: 30 }, |
|
'wendy': { name: 'Венди Тестабургер', image: 'https://i.imgur.com/8vYQxQk.png', attack: 6, defense: 6, maxHp: 65, hp: 65, level: 1, xpReward: 40, moneyReward: 35 }, |
|
'randy': { name: 'Рэнди Марш', image: 'https://i.imgur.com/9vYQxQk.png', attack: 10, defense: 4, maxHp: 80, hp: 80, level: 1, xpReward: 50, moneyReward: 50, special: "Сила Тигрида Фармс" } |
|
}, |
|
enemyLevelMultipliers: [1, 1.2, 1.5, 2, 2.5, 3] |
|
}; |
|
|
|
|
|
const elements = { |
|
characterSelectModal: document.getElementById('character-select-modal'), |
|
playerCharacter: document.getElementById('player-character'), |
|
playerImage: document.getElementById('player-image'), |
|
playerName: document.getElementById('player-name'), |
|
playerHealth: document.getElementById('player-health'), |
|
playerCurrentHp: document.getElementById('player-current-hp'), |
|
playerMaxHp: document.getElementById('player-max-hp'), |
|
playerLevel: document.getElementById('player-level'), |
|
playerXp: document.getElementById('player-xp'), |
|
playerCurrentXp: document.getElementById('player-current-xp'), |
|
playerNextLevelXp: document.getElementById('player-next-level-xp'), |
|
playerAttack: document.getElementById('player-attack'), |
|
playerDefense: document.getElementById('player-defense'), |
|
stars: document.getElementById('stars'), |
|
level: document.getElementById('level'), |
|
battleLog: document.getElementById('battle-log'), |
|
enemyArea: document.getElementById('enemy-area'), |
|
attackBtn: document.getElementById('attack-btn'), |
|
specialBtn: document.getElementById('special-btn'), |
|
collectStarsBtn: document.getElementById('collect-stars-btn'), |
|
starTimer: document.getElementById('star-timer'), |
|
specialCharges: document.getElementById('special-charges'), |
|
upgradeBtn: document.getElementById('upgrade-btn'), |
|
upgradeCost: document.getElementById('upgrade-cost'), |
|
healBtn: document.getElementById('heal-btn'), |
|
healCost: document.getElementById('heal-cost'), |
|
cheesyPoofs: document.getElementById('cheesy-poofs'), |
|
tegridyWeed: document.getElementById('tegridy-weed'), |
|
kennySouls: document.getElementById('kenny-souls') |
|
}; |
|
|
|
|
|
function initGame() { |
|
elements.characterSelectModal.classList.remove('hidden'); |
|
|
|
|
|
document.querySelectorAll('.character-select').forEach(btn => { |
|
btn.addEventListener('click', function() { |
|
document.querySelectorAll('.character-select').forEach(b => b.classList.remove('ring-4', 'ring-blue-500')); |
|
this.classList.add('ring-4', 'ring-blue-500'); |
|
gameState.selectedCharacter = this.dataset.character; |
|
}); |
|
}); |
|
|
|
document.getElementById('confirm-character').addEventListener('click', startGame); |
|
|
|
|
|
document.querySelectorAll('.enemy-select').forEach(btn => { |
|
btn.addEventListener('click', function() { |
|
if (gameState.battleInProgress) return; |
|
|
|
const enemyType = this.dataset.enemy; |
|
const enemyLevel = Math.min(Math.floor(gameState.level / 2) + 1, 5); |
|
selectEnemy(enemyType, enemyLevel); |
|
}); |
|
}); |
|
|
|
|
|
elements.attackBtn.addEventListener('click', playerAttack); |
|
|
|
|
|
elements.specialBtn.addEventListener('click', specialAttack); |
|
|
|
|
|
elements.collectStarsBtn.addEventListener('click', startStarCollection); |
|
|
|
|
|
elements.upgradeBtn.addEventListener('click', upgradeCharacter); |
|
|
|
|
|
elements.healBtn.addEventListener('click', healCharacter); |
|
|
|
|
|
document.querySelectorAll('.shop-item').forEach(item => { |
|
item.addEventListener('click', function() { |
|
const itemType = this.dataset.item; |
|
const cost = parseInt(this.dataset.cost); |
|
buyItem(itemType, cost); |
|
}); |
|
}); |
|
} |
|
|
|
|
|
function startGame() { |
|
if (!gameState.selectedCharacter) { |
|
addToBattleLog("Пожалуйста, сначала выберите персонажа!"); |
|
return; |
|
} |
|
|
|
elements.characterSelectModal.classList.add('hidden'); |
|
|
|
|
|
const character = gameState.characters[gameState.selectedCharacter]; |
|
updatePlayerStats(); |
|
|
|
|
|
const bgClasses = ['stan-bg', 'cartman-bg', 'kyle-bg', 'kenny-bg']; |
|
elements.playerCharacter.classList.remove(...bgClasses); |
|
|
|
switch(gameState.selectedCharacter) { |
|
case 'stan': elements.playerCharacter.classList.add('stan-bg'); break; |
|
case 'cartman': elements.playerCharacter.classList.add('cartman-bg'); break; |
|
case 'kyle': elements.playerCharacter.classList.add('kyle-bg'); break; |
|
case 'kenny': elements.playerCharacter.classList.add('kenny-bg'); break; |
|
} |
|
|
|
addToBattleLog(`Добро пожаловать в Саут Парк, ${character.name}!`); |
|
addToBattleLog("Выберите противника для боя и начинайте собирать звёзды!"); |
|
|
|
|
|
updateUI(); |
|
} |
|
|
|
|
|
function selectEnemy(enemyType, level) { |
|
if (gameState.battleInProgress) return; |
|
|
|
const baseEnemy = gameState.enemies[enemyType]; |
|
const multiplier = gameState.enemyLevelMultipliers[level - 1]; |
|
|
|
gameState.currentEnemy = { |
|
...baseEnemy, |
|
attack: Math.floor(baseEnemy.attack * multiplier), |
|
defense: Math.floor(baseEnemy.defense * multiplier), |
|
maxHp: Math.floor(baseEnemy.maxHp * multiplier), |
|
hp: Math.floor(baseEnemy.maxHp * multiplier), |
|
level: level, |
|
xpReward: Math.floor(baseEnemy.xpReward * multiplier), |
|
moneyReward: Math.floor(baseEnemy.moneyReward * multiplier) |
|
}; |
|
|
|
|
|
elements.enemyArea.innerHTML = ` |
|
<img src="${gameState.currentEnemy.image}" alt="${gameState.currentEnemy.name}" class="w-20 h-20 md:w-32 md:h-32 mx-auto mb-2"> |
|
<h3 class="text-lg md:text-xl font-bold">${gameState.currentEnemy.name}</h3> |
|
<div class="progress-bar mb-2"> |
|
<div id="enemy-health" class="progress-fill bg-red-500" style="width: 100%"></div> |
|
</div> |
|
<div class="flex justify-between text-xs md:text-sm mb-2"> |
|
<span>HP: <span id="enemy-current-hp">${gameState.currentEnemy.hp}</span>/<span id="enemy-max-hp">${gameState.currentEnemy.maxHp}</span></span> |
|
<span>Уровень: ${gameState.currentEnemy.level}</span> |
|
</div> |
|
<div class="grid grid-cols-2 gap-2"> |
|
<div class="bg-red-50 p-1 rounded"> |
|
<span class="block text-xs">Атака</span> |
|
<span class="font-bold">${gameState.currentEnemy.attack}</span> |
|
</div> |
|
<div class="bg-red-50 p-1 rounded"> |
|
<span class="block text-xs">Защита</span> |
|
<span class="font-bold">${gameState.currentEnemy.defense}</span> |
|
</div> |
|
</div> |
|
`; |
|
|
|
gameState.battleInProgress = true; |
|
addToBattleLog(`Вы сражаетесь с ${gameState.currentEnemy.name} (Уровень ${gameState.currentEnemy.level})!`); |
|
|
|
|
|
gameState.specialCharges = 0; |
|
updateSpecialButton(); |
|
} |
|
|
|
|
|
function playerAttack() { |
|
if (!gameState.battleInProgress || !gameState.currentEnemy) { |
|
addToBattleLog("Сначала выберите противника для боя!"); |
|
return; |
|
} |
|
|
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
const enemy = gameState.currentEnemy; |
|
|
|
|
|
let damage = Math.max(1, player.attack - Math.floor(enemy.defense / 2)); |
|
|
|
|
|
enemy.hp = Math.max(0, enemy.hp - damage); |
|
|
|
|
|
updateEnemyHealth(); |
|
addToBattleLog(`${player.name} атакует ${enemy.name} и наносит ${damage} урона!`); |
|
|
|
|
|
if (enemy.hp <= 0) { |
|
enemyDefeated(); |
|
return; |
|
} |
|
|
|
|
|
setTimeout(() => { |
|
enemyAttack(); |
|
}, 500); |
|
|
|
|
|
gameState.specialCharges = Math.min(gameState.specialCharges + 1, 3); |
|
updateSpecialButton(); |
|
} |
|
|
|
|
|
function specialAttack() { |
|
if (!gameState.battleInProgress || !gameState.currentEnemy) { |
|
addToBattleLog("Сначала выберите противника для боя!"); |
|
return; |
|
} |
|
|
|
if (gameState.specialCharges < 3) { |
|
addToBattleLog("Нужно 3 заряда для ультимейт атаки!"); |
|
return; |
|
} |
|
|
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
const enemy = gameState.currentEnemy; |
|
|
|
|
|
let damage = 0; |
|
let specialName = ""; |
|
|
|
switch(gameState.selectedCharacter) { |
|
case 'stan': |
|
damage = player.attack * 2; |
|
specialName = "Сила кофе Твика"; |
|
break; |
|
case 'cartman': |
|
damage = player.attack * 3; |
|
specialName = "Уважайте мою авторитетность!"; |
|
break; |
|
case 'kyle': |
|
damage = player.attack + (enemy.maxHp - enemy.hp); |
|
specialName = "Ярость мамы Кайла"; |
|
break; |
|
case 'kenny': |
|
damage = Math.floor(Math.random() * (player.attack * 4)) + 5; |
|
specialName = "Сила Мистериона"; |
|
break; |
|
} |
|
|
|
|
|
enemy.hp = Math.max(0, enemy.hp - damage); |
|
|
|
|
|
updateEnemyHealth(); |
|
addToBattleLog(`${player.name} использует ${specialName} и наносит ${damage} урона ${enemy.name}!`); |
|
|
|
|
|
gameState.specialCharges = 0; |
|
updateSpecialButton(); |
|
|
|
|
|
if (enemy.hp <= 0) { |
|
enemyDefeated(); |
|
return; |
|
} |
|
|
|
|
|
setTimeout(() => { |
|
enemyAttack(); |
|
}, 500); |
|
} |
|
|
|
|
|
function enemyAttack() { |
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
const enemy = gameState.currentEnemy; |
|
|
|
|
|
let damage = Math.max(1, enemy.attack - Math.floor(player.defense / 2)); |
|
|
|
|
|
player.hp = Math.max(0, player.hp - damage); |
|
|
|
|
|
updatePlayerStats(); |
|
addToBattleLog(`${enemy.name} атакует ${player.name} и наносит ${damage} урона!`); |
|
|
|
|
|
if (player.hp <= 0) { |
|
playerDefeated(); |
|
return; |
|
} |
|
|
|
|
|
if (gameState.selectedCharacter === 'kenny' && player.hp <= player.maxHp * 0.3) { |
|
const kennyElement = document.querySelector('.kenny.character-select'); |
|
if (kennyElement) { |
|
kennyElement.classList.add('dead'); |
|
setTimeout(() => { |
|
kennyElement.classList.remove('dead'); |
|
}, 2000); |
|
} |
|
|
|
if (Math.random() < 0.5) { |
|
const healAmount = Math.floor(player.maxHp * 0.5); |
|
player.hp = Math.min(player.maxHp, player.hp + healAmount); |
|
addToBattleLog(`О боже! Они убили Кенни! Но он возвращается с ${healAmount} HP!`); |
|
updatePlayerStats(); |
|
} |
|
} |
|
} |
|
|
|
|
|
function enemyDefeated() { |
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
const enemy = gameState.currentEnemy; |
|
|
|
addToBattleLog(`Вы победили ${enemy.name}!`); |
|
|
|
|
|
player.xp += enemy.xpReward; |
|
gameState.money += enemy.moneyReward; |
|
|
|
addToBattleLog(`+${enemy.xpReward} опыта и $${enemy.moneyReward}!`); |
|
|
|
|
|
checkLevelUp(); |
|
|
|
|
|
if (Math.random() < 0.3) { |
|
const items = ['cheesy-poofs', 'tegridy-weed', 'kenny-souls']; |
|
const randomItem = items[Math.floor(Math.random() * items.length)]; |
|
gameState.inventory[randomItem]++; |
|
updateInventory(); |
|
|
|
let itemName = ''; |
|
switch(randomItem) { |
|
case 'cheesy-poofs': itemName = 'Сырные шарики'; break; |
|
case 'tegridy-weed': itemName = 'Тигрида Виид'; break; |
|
case 'kenny-souls': itemName = "Душа Кенни"; break; |
|
} |
|
|
|
addToBattleLog(`Вы нашли ${itemName}!`); |
|
} |
|
|
|
|
|
gameState.battleInProgress = false; |
|
gameState.currentEnemy = null; |
|
|
|
|
|
updateUI(); |
|
} |
|
|
|
|
|
function playerDefeated() { |
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
|
|
addToBattleLog(`Вы были побеждены ${gameState.currentEnemy.name}!`); |
|
|
|
|
|
if (gameState.inventory['kenny-souls'] > 0) { |
|
gameState.inventory['kenny-souls']--; |
|
player.hp = Math.floor(player.maxHp * 0.5); |
|
addToBattleLog("Вы использовали Душу Кенни и воскресли с 50% HP!"); |
|
updatePlayerStats(); |
|
updateInventory(); |
|
return; |
|
} |
|
|
|
|
|
player.hp = player.maxHp; |
|
gameState.battleInProgress = false; |
|
gameState.currentEnemy = null; |
|
|
|
|
|
updatePlayerStats(); |
|
updateUI(); |
|
|
|
addToBattleLog("Вы были воскрешены с полным HP. Попробуйте снова!"); |
|
} |
|
|
|
|
|
function checkLevelUp() { |
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
|
|
if (player.xp >= player.nextLevelXp) { |
|
player.level++; |
|
player.xp -= player.nextLevelXp; |
|
player.nextLevelXp = Math.floor(player.nextLevelXp * 1.5); |
|
|
|
|
|
player.maxHp = Math.floor(player.maxHp * 1.2); |
|
player.hp = player.maxHp; |
|
player.attack = Math.floor(player.attack * 1.1); |
|
player.defense = Math.floor(player.defense * 1.1); |
|
|
|
|
|
gameState.level = Math.max(gameState.level, player.level); |
|
|
|
addToBattleLog(`Повышение уровня! Теперь вы ${player.level} уровня!`); |
|
addToBattleLog(`Характеристики увеличены: +20% HP, +10% к атаке и защите`); |
|
|
|
updatePlayerStats(); |
|
updateUI(); |
|
} |
|
} |
|
|
|
|
|
function startStarCollection() { |
|
if (gameState.starInterval) return; |
|
|
|
gameState.starTimer = 5; |
|
elements.starTimer.textContent = gameState.starTimer; |
|
elements.collectStarsBtn.disabled = true; |
|
|
|
gameState.starInterval = setInterval(() => { |
|
gameState.starTimer--; |
|
elements.starTimer.textContent = gameState.starTimer; |
|
|
|
if (gameState.starTimer <= 0) { |
|
collectStars(); |
|
clearInterval(gameState.starInterval); |
|
gameState.starInterval = null; |
|
elements.collectStarsBtn.disabled = false; |
|
} |
|
}, 1000); |
|
} |
|
|
|
|
|
function collectStars() { |
|
const starsCollected = Math.floor(Math.random() * 5) + 1; |
|
gameState.stars += starsCollected; |
|
|
|
addToBattleLog(`Вы собрали ${starsCollected} звёзд!`); |
|
updateUI(); |
|
} |
|
|
|
|
|
function upgradeCharacter() { |
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
const cost = parseInt(elements.upgradeCost.textContent); |
|
|
|
if (gameState.money < cost) { |
|
addToBattleLog("Недостаточно денег!"); |
|
return; |
|
} |
|
|
|
gameState.money -= cost; |
|
|
|
|
|
const upgradeType = Math.floor(Math.random() * 3); |
|
let upgradeAmount = 0; |
|
let upgradeStat = ''; |
|
|
|
switch(upgradeType) { |
|
case 0: |
|
upgradeAmount = Math.floor(player.attack * 0.2) + 1; |
|
player.attack += upgradeAmount; |
|
upgradeStat = 'Атака'; |
|
break; |
|
case 1: |
|
upgradeAmount = Math.floor(player.defense * 0.2) + 1; |
|
player.defense += upgradeAmount; |
|
upgradeStat = 'Защита'; |
|
break; |
|
case 2: |
|
upgradeAmount = Math.floor(player.maxHp * 0.15) + 5; |
|
player.maxHp += upgradeAmount; |
|
player.hp += upgradeAmount; |
|
upgradeStat = 'Макс. HP'; |
|
break; |
|
} |
|
|
|
|
|
elements.upgradeCost.textContent = Math.floor(cost * 1.3); |
|
|
|
addToBattleLog(`Улучшена ${upgradeStat} на ${upgradeAmount}!`); |
|
updatePlayerStats(); |
|
updateUI(); |
|
} |
|
|
|
|
|
function healCharacter() { |
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
const cost = parseInt(elements.healCost.textContent); |
|
|
|
if (gameState.money < cost) { |
|
addToBattleLog("Недостаточно денег!"); |
|
return; |
|
} |
|
|
|
if (player.hp >= player.maxHp) { |
|
addToBattleLog("У вас уже полное здоровье!"); |
|
return; |
|
} |
|
|
|
gameState.money -= cost; |
|
|
|
|
|
const healAmount = Math.floor(player.maxHp * 0.5); |
|
player.hp = Math.min(player.maxHp, player.hp + healAmount); |
|
|
|
|
|
elements.healCost.textContent = Math.floor(cost * 1.2); |
|
|
|
addToBattleLog(`Вылечено ${healAmount} HP!`); |
|
updatePlayerStats(); |
|
updateUI(); |
|
} |
|
|
|
|
|
function buyItem(itemType, cost) { |
|
if (gameState.money < cost) { |
|
addToBattleLog("Недостаточно денег!"); |
|
return; |
|
} |
|
|
|
gameState.money -= cost; |
|
gameState.inventory[itemType]++; |
|
|
|
let message = ''; |
|
switch(itemType) { |
|
case 'cheesy-poofs': |
|
message = "Куплены Сырные шарики! Используйте их для лечения 5 HP в любое время."; |
|
break; |
|
case 'tegridy-weed': |
|
message = "Куплена Тигрида Виид! Даёт +2 к атаке постоянно."; |
|
gameState.characters[gameState.selectedCharacter].attack += 2; |
|
break; |
|
case 'kenny-souls': |
|
message = "Куплена Душа Кенни! Может воскресить вас при поражении."; |
|
break; |
|
} |
|
|
|
addToBattleLog(message); |
|
updatePlayerStats(); |
|
updateInventory(); |
|
updateUI(); |
|
} |
|
|
|
|
|
function useItem(itemType) { |
|
if (gameState.inventory[itemType] <= 0) return; |
|
|
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
|
|
switch(itemType) { |
|
case 'cheesy-poofs': |
|
player.hp = Math.min(player.maxHp, player.hp + 5); |
|
addToBattleLog("Использованы Сырные шарики! Вылечено 5 HP."); |
|
break; |
|
case 'kenny-souls': |
|
|
|
break; |
|
} |
|
|
|
gameState.inventory[itemType]--; |
|
updatePlayerStats(); |
|
updateInventory(); |
|
} |
|
|
|
|
|
function updatePlayerStats() { |
|
const player = gameState.characters[gameState.selectedCharacter]; |
|
|
|
elements.playerImage.src = player.image; |
|
elements.playerName.textContent = player.name; |
|
elements.playerHealth.style.width = `${(player.hp / player.maxHp) * 100}%`; |
|
elements.playerCurrentHp.textContent = player.hp; |
|
elements.playerMaxHp.textContent = player.maxHp; |
|
elements.playerLevel.textContent = player.level; |
|
elements.playerXp.style.width = `${(player.xp / player.nextLevelXp) * 100}%`; |
|
elements.playerCurrentXp.textContent = player.xp; |
|
elements.playerNextLevelXp.textContent = player.nextLevelXp; |
|
elements.playerAttack.textContent = player.attack; |
|
elements.playerDefense.textContent = player.defense; |
|
|
|
|
|
elements.playerCharacter.classList.add('attack-animation'); |
|
setTimeout(() => { |
|
elements.playerCharacter.classList.remove('attack-animation'); |
|
}, 300); |
|
} |
|
|
|
|
|
function updateEnemyHealth() { |
|
const enemy = gameState.currentEnemy; |
|
if (!enemy) return; |
|
|
|
const enemyHealthElement = document.getElementById('enemy-health'); |
|
const enemyCurrentHpElement = document.getElementById('enemy-current-hp'); |
|
|
|
if (enemyHealthElement) { |
|
enemyHealthElement.style.width = `${(enemy.hp / enemy.maxHp) * 100}%`; |
|
} |
|
|
|
if (enemyCurrentHpElement) { |
|
enemyCurrentHpElement.textContent = enemy.hp; |
|
} |
|
} |
|
|
|
|
|
function updateUI() { |
|
elements.stars.textContent = gameState.stars; |
|
elements.level.textContent = gameState.level; |
|
} |
|
|
|
|
|
function updateInventory() { |
|
elements.cheesyPoofs.textContent = gameState.inventory['cheesy-poofs']; |
|
elements.tegridyWeed.textContent = gameState.inventory['tegridy-weed']; |
|
elements.kennySouls.textContent = gameState.inventory['kenny-souls']; |
|
} |
|
|
|
|
|
function updateSpecialButton() { |
|
elements.specialCharges.textContent = gameState.specialCharges; |
|
|
|
if (gameState.specialCharges >= 3) { |
|
elements.specialBtn.classList.add('bg-yellow-500', 'hover:bg-yellow-600'); |
|
elements.specialBtn.classList.remove('bg-gray-400', 'hover:bg-gray-500'); |
|
} else { |
|
elements.specialBtn.classList.add('bg-gray-400', 'hover:bg-gray-500'); |
|
elements.specialBtn.classList.remove('bg-yellow-500', 'hover:bg-yellow-600'); |
|
} |
|
} |
|
|
|
|
|
function addToBattleLog(message) { |
|
const logEntry = document.createElement('div'); |
|
logEntry.className = 'speech-bubble'; |
|
logEntry.innerHTML = `<p>${message}</p>`; |
|
elements.battleLog.appendChild(logEntry); |
|
elements.battleLog.scrollTop = elements.battleLog.scrollHeight; |
|
} |
|
|
|
|
|
initGame(); |
|
</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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Formandl/wertq" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |