Nymbo commited on
Commit
71b5cd3
·
verified ·
1 Parent(s): ae95585

adding lots of new mechanics, abilities, and styles

Browse files
Files changed (1) hide show
  1. index.html +478 -64
index.html CHANGED
@@ -3,67 +3,131 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Tiny Healer</title>
7
  <style>
 
8
  body {
9
- font-family: Arial, sans-serif;
10
  display: flex;
11
  justify-content: center;
12
  align-items: center;
13
  height: 100vh;
14
  margin: 0;
15
- background-color: #1a1a1a;
16
- color: white;
17
  }
 
 
18
  #game-container {
19
  width: 800px;
20
  height: 600px;
21
- border: 2px solid #333;
22
  padding: 20px;
23
- background-color: #222;
 
 
 
24
  }
 
 
25
  #combat-window {
26
  display: flex;
27
  justify-content: space-between;
28
  margin-bottom: 20px;
29
  }
 
 
30
  #allies {
31
  width: 45%;
32
  }
 
 
33
  #boss {
34
  width: 45%;
35
  }
 
 
36
  .health-bar {
37
  height: 30px;
38
- background-color: #4CAF50;
39
  margin-bottom: 10px;
40
  position: relative;
41
  cursor: pointer;
 
 
 
42
  }
43
- .health-bar.selected {
44
- background-color: #2196F3;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  .health-bar-text {
47
  position: absolute;
48
  width: 100%;
49
  text-align: center;
50
  line-height: 30px;
 
 
51
  }
 
 
52
  #boss-health-bar {
53
  height: 50px;
54
- background-color: #f44336;
55
  }
 
 
 
 
 
 
56
  #spell-buttons {
57
  display: flex;
58
  justify-content: space-between;
59
  margin-bottom: 10px;
60
  }
 
 
61
  .spell-button {
62
  width: 18%;
63
  height: 50px;
64
- background-color: #008CBA;
65
- border: none;
66
- color: white;
67
  text-align: center;
68
  text-decoration: none;
69
  display: inline-block;
@@ -72,86 +136,283 @@
72
  cursor: pointer;
73
  position: relative;
74
  overflow: hidden;
 
 
75
  }
 
 
 
 
 
 
76
  .spell-button:disabled {
77
- background-color: #555;
 
 
78
  cursor: not-allowed;
79
  }
 
 
80
  .cooldown-progress {
81
  position: absolute;
82
  top: 0;
83
- left: 0;
84
  height: 100%;
85
  width: 0;
86
  background-color: rgba(0, 0, 0, 0.5);
87
- transition: width linear;
88
  }
89
- #spellbook {
 
 
90
  width: 100%;
91
- padding: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  background-color: #333;
 
 
 
 
 
93
  border: none;
94
- color: white;
 
95
  font-size: 16px;
 
96
  margin-top: 10px;
97
  }
98
- #spell-info {
99
- margin-top: 10px;
100
- padding: 10px;
101
  background-color: #444;
102
- border-radius: 5px;
103
- display: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
105
  </style>
106
  </head>
107
  <body>
 
108
  <div id="game-container">
 
109
  <div id="combat-window">
 
110
  <div id="allies"></div>
 
111
  <div id="boss">
 
112
  <div id="boss-health-bar" class="health-bar">
113
  <div class="health-bar-text">Boss HP: 5000/5000</div>
114
  </div>
115
  </div>
116
  </div>
 
117
  <div id="spell-buttons"></div>
118
- <select id="spellbook">
119
- <option value="">Spellbook - Select a spell for info</option>
120
- <option value="0">Quick Heal</option>
121
- <option value="1">Strong Heal</option>
122
- <option value="2">Healing Stream</option>
123
- <option value="3">Chain Heal</option>
124
- <option value="4">Team Heal</option>
125
- </select>
126
- <div id="spell-info"></div>
127
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  <script>
 
130
  const allies = [];
 
131
  let boss = { hp: 5000, maxHp: 5000 };
 
132
  let selectedAlly = null;
 
133
  let globalCooldown = false;
 
 
 
 
 
 
 
 
134
 
 
135
  const spells = [
136
- { name: "Quick Heal", cooldown: 1.5, heal: 10, description: "Heals the target for 10 HP. Global cooldown: 1.5 seconds." },
137
- { name: "Strong Heal", cooldown: 15, heal: 30, description: "Heals the target for 30 HP. Cooldown: 15 seconds." },
138
- { name: "Healing Stream", cooldown: 45, heal: 3, duration: 10, interval: 0.5, description: "Heals the target for 3 HP every 0.5 seconds for 10 seconds. Cooldown: 45 seconds." },
139
- { name: "Chain Heal", cooldown: 15, heal: 10, targets: 3, description: "Heals 3 random allies for 10 HP each. Cooldown: 15 seconds." },
140
- { name: "Team Heal", cooldown: 120, heal: 50, description: "Heals all allies for 50 HP. Cooldown: 2 minutes." }
141
  ];
142
 
 
143
  function createAlly(id) {
144
- return { id, hp: 100, maxHp: 100 };
145
  }
146
 
 
147
  function updateHealthBar(entity, barElement) {
148
  const percentage = (entity.hp / entity.maxHp) * 100;
149
  barElement.style.width = `${percentage}%`;
150
  barElement.querySelector('.health-bar-text').textContent = `HP: ${entity.hp}/${entity.maxHp}`;
 
 
 
 
 
 
 
 
151
  }
152
 
 
 
 
 
 
 
 
 
 
 
153
  function createAllies() {
154
  const alliesContainer = document.getElementById('allies');
 
 
155
  for (let i = 0; i < 5; i++) {
156
  const ally = createAlly(i);
157
  allies.push(ally);
@@ -164,7 +425,9 @@
164
  }
165
  }
166
 
 
167
  function selectAlly(index) {
 
168
  const healthBars = document.querySelectorAll('#allies .health-bar');
169
  healthBars.forEach(bar => bar.classList.remove('selected'));
170
  healthBars[index].classList.add('selected');
@@ -172,28 +435,34 @@
172
  updateSpellButtons();
173
  }
174
 
 
175
  function createSpellButtons() {
176
  const spellButtonsContainer = document.getElementById('spell-buttons');
 
177
  spells.forEach((spell, index) => {
178
  const button = document.createElement('button');
179
  button.className = 'spell-button';
180
- button.innerHTML = `${spell.name}<div class="cooldown-progress"></div>`;
181
  button.onclick = () => castSpell(index);
182
  button.disabled = true;
183
  spellButtonsContainer.appendChild(button);
184
  });
185
  }
186
 
 
187
  function updateSpellButtons() {
188
  const spellButtons = document.querySelectorAll('.spell-button');
189
  spellButtons.forEach((button, index) => {
190
- button.disabled = !selectedAlly || globalCooldown || button.classList.contains('on-cooldown');
191
  });
192
  }
193
 
 
194
  function castSpell(spellIndex) {
195
- if (selectedAlly && !globalCooldown && !document.querySelectorAll('.spell-button')[spellIndex].classList.contains('on-cooldown')) {
196
- const spell = spells[spellIndex];
 
 
197
  switch (spellIndex) {
198
  case 0:
199
  case 1:
@@ -214,15 +483,19 @@
214
  }
215
  }
216
 
 
217
  function healAlly(ally, amount) {
218
- ally.hp = Math.min(ally.hp + amount, ally.maxHp);
219
- updateHealthBar(ally, document.querySelectorAll('.health-bar')[ally.id]);
 
 
220
  }
221
 
 
222
  function startHealingStream(ally, spell) {
223
  let ticks = spell.duration / spell.interval;
224
  function tick() {
225
- if (ticks > 0) {
226
  healAlly(ally, spell.heal);
227
  ticks--;
228
  setTimeout(tick, spell.interval * 1000);
@@ -231,28 +504,39 @@
231
  tick();
232
  }
233
 
 
234
  function chainHeal(spell) {
235
- const targets = allies.sort(() => 0.5 - Math.random()).slice(0, spell.targets);
 
236
  targets.forEach(ally => healAlly(ally, spell.heal));
237
  }
238
 
 
239
  function teamHeal(spell) {
240
  allies.forEach(ally => healAlly(ally, spell.heal));
241
  }
242
 
 
243
  function startSpellCooldown(spellIndex) {
244
  const button = document.querySelectorAll('.spell-button')[spellIndex];
245
  const progressBar = button.querySelector('.cooldown-progress');
246
  button.classList.add('on-cooldown');
247
- progressBar.style.transition = `width ${spells[spellIndex].cooldown}s linear`;
 
248
  progressBar.style.width = '100%';
 
249
  setTimeout(() => {
250
- button.classList.remove('on-cooldown');
251
  progressBar.style.width = '0';
 
 
 
 
252
  updateSpellButtons();
253
  }, spells[spellIndex].cooldown * 1000);
254
  }
255
 
 
256
  function startGlobalCooldown() {
257
  globalCooldown = true;
258
  updateSpellButtons();
@@ -262,18 +546,139 @@
262
  }, 1500);
263
  }
264
 
 
265
  function bossDamage() {
266
- const damageAmount = 8;
267
- const targetAlly = allies[Math.floor(Math.random() * allies.length)];
 
 
 
 
 
 
268
  targetAlly.hp = Math.max(targetAlly.hp - damageAmount, 0);
 
 
 
269
  updateHealthBar(targetAlly, document.querySelectorAll('.health-bar')[targetAlly.id]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  }
271
 
 
272
  function gameLoop() {
273
- bossDamage();
274
- setTimeout(gameLoop, 1000);
 
 
 
 
275
  }
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  document.addEventListener('keydown', (event) => {
278
  const key = event.key;
279
  if (key >= '1' && key <= '5') {
@@ -281,20 +686,29 @@
281
  }
282
  });
283
 
284
- document.getElementById('spellbook').addEventListener('change', (event) => {
285
- const spellIndex = event.target.value;
286
- const spellInfo = document.getElementById('spell-info');
287
- if (spellIndex !== "") {
288
- spellInfo.textContent = spells[spellIndex].description;
289
- spellInfo.style.display = 'block';
290
- } else {
291
- spellInfo.style.display = 'none';
292
- }
293
- });
 
 
 
 
 
 
294
 
 
295
  createAllies();
296
  createSpellButtons();
297
  updateHealthBar(boss, document.getElementById('boss-health-bar'));
 
 
298
  gameLoop();
299
  </script>
300
  </body>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>RPG Healer Combat Game</title>
7
  <style>
8
+ /* Basic body styling */
9
  body {
10
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
11
  display: flex;
12
  justify-content: center;
13
  align-items: center;
14
  height: 100vh;
15
  margin: 0;
16
+ background-color: #0f0f0f;
17
+ color: #ffd100;
18
  }
19
+
20
+ /* Main game container */
21
  #game-container {
22
  width: 800px;
23
  height: 600px;
24
+ border: 2px solid #4a4a4a;
25
  padding: 20px;
26
+ background-color: rgba(0, 0, 0, 0.8);
27
+ position: relative;
28
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
29
+ border-radius: 10px;
30
  }
31
+
32
+ /* Combat window containing allies and boss */
33
  #combat-window {
34
  display: flex;
35
  justify-content: space-between;
36
  margin-bottom: 20px;
37
  }
38
+
39
+ /* Allies section */
40
  #allies {
41
  width: 45%;
42
  }
43
+
44
+ /* Boss section */
45
  #boss {
46
  width: 45%;
47
  }
48
+
49
+ /* Health bar styling */
50
  .health-bar {
51
  height: 30px;
52
+ background-color: #1a1a1a;
53
  margin-bottom: 10px;
54
  position: relative;
55
  cursor: pointer;
56
+ border: 1px solid #4a4a4a;
57
+ border-radius: 5px;
58
+ overflow: hidden;
59
  }
60
+
61
+ .health-bar::before {
62
+ content: '';
63
+ position: absolute;
64
+ top: 0;
65
+ left: 0;
66
+ height: 100%;
67
+ width: 100%;
68
+ background-color: #00ff00;
69
+ transition: width 0.3s ease;
70
+ }
71
+
72
+ /* Selected ally health bar */
73
+ .health-bar.selected::before {
74
+ background-color: #00aaff;
75
+ }
76
+
77
+ /* Dead ally health bar */
78
+ .health-bar.dead::before {
79
+ background-color: #777;
80
  }
81
+
82
+ /* Bleeding ally health bar */
83
+ .health-bar.bleeding::before {
84
+ background-image: linear-gradient(45deg, #00ff00 25%, #ff0000 25%, #ff0000 50%, #00ff00 50%, #00ff00 75%, #ff0000 75%, #ff0000 100%);
85
+ background-size: 40px 40px;
86
+ animation: bleed-animation 1s linear infinite;
87
+ }
88
+
89
+ @keyframes bleed-animation {
90
+ 0% {
91
+ background-position: 0 0;
92
+ }
93
+ 100% {
94
+ background-position: 40px 0;
95
+ }
96
+ }
97
+
98
+ /* Health bar text */
99
  .health-bar-text {
100
  position: absolute;
101
  width: 100%;
102
  text-align: center;
103
  line-height: 30px;
104
+ z-index: 1;
105
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
106
  }
107
+
108
+ /* Boss health bar */
109
  #boss-health-bar {
110
  height: 50px;
 
111
  }
112
+
113
+ #boss-health-bar::before {
114
+ background-color: #ff0000;
115
+ }
116
+
117
+ /* Spell buttons container */
118
  #spell-buttons {
119
  display: flex;
120
  justify-content: space-between;
121
  margin-bottom: 10px;
122
  }
123
+
124
+ /* Individual spell button */
125
  .spell-button {
126
  width: 18%;
127
  height: 50px;
128
+ background-color: #4a4a4a;
129
+ border: 1px solid #ffd100;
130
+ color: #ffd100;
131
  text-align: center;
132
  text-decoration: none;
133
  display: inline-block;
 
136
  cursor: pointer;
137
  position: relative;
138
  overflow: hidden;
139
+ border-radius: 5px;
140
+ transition: all 0.3s ease;
141
  }
142
+
143
+ .spell-button:hover {
144
+ background-color: #666;
145
+ }
146
+
147
+ /* Disabled spell button */
148
  .spell-button:disabled {
149
+ background-color: #333;
150
+ border-color: #666;
151
+ color: #666;
152
  cursor: not-allowed;
153
  }
154
+
155
+ /* Cooldown progress bar on spell buttons */
156
  .cooldown-progress {
157
  position: absolute;
158
  top: 0;
159
+ right: 0;
160
  height: 100%;
161
  width: 0;
162
  background-color: rgba(0, 0, 0, 0.5);
163
+ transition: width 0.1s linear;
164
  }
165
+
166
+ /* Mana bar container */
167
+ #mana-bar {
168
  width: 100%;
169
+ height: 20px;
170
+ background-color: #1a1a1a;
171
+ position: relative;
172
+ border: 1px solid #4a4a4a;
173
+ border-radius: 5px;
174
+ overflow: hidden;
175
+ }
176
+
177
+ /* Mana bar fill */
178
+ #mana-bar-fill {
179
+ height: 100%;
180
+ width: 100%;
181
+ background-color: #0077be;
182
+ transition: width 0.5s;
183
+ }
184
+
185
+ /* Mana text */
186
+ #mana-text {
187
+ position: absolute;
188
+ width: 100%;
189
+ text-align: center;
190
+ line-height: 20px;
191
+ color: #fff;
192
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
193
+ }
194
+
195
+ /* Reset button */
196
+ #reset-button {
197
+ position: absolute;
198
+ top: 50%;
199
+ left: 50%;
200
+ transform: translate(-50%, -50%);
201
+ font-size: 24px;
202
+ padding: 10px 20px;
203
+ background-color: #ffd100;
204
+ color: #000;
205
+ border: none;
206
+ cursor: pointer;
207
+ display: none;
208
+ border-radius: 5px;
209
+ transition: all 0.3s ease;
210
+ }
211
+
212
+ #reset-button:hover {
213
+ background-color: #ffea00;
214
+ }
215
+
216
+ /* Game over and victory messages */
217
+ #game-over, #victory {
218
+ position: absolute;
219
+ top: 40%;
220
+ left: 50%;
221
+ transform: translate(-50%, -50%);
222
+ font-size: 36px;
223
+ display: none;
224
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
225
+ }
226
+
227
+ #game-over {
228
+ color: #ff0000;
229
+ }
230
+
231
+ #victory {
232
+ color: #00ff00;
233
+ }
234
+
235
+ /* Accordion styles */
236
+ .accordion {
237
  background-color: #333;
238
+ color: #ffd100;
239
+ cursor: pointer;
240
+ padding: 18px;
241
+ width: 100%;
242
+ text-align: left;
243
  border: none;
244
+ outline: none;
245
+ transition: 0.4s;
246
  font-size: 16px;
247
+ border-radius: 5px;
248
  margin-top: 10px;
249
  }
250
+
251
+ .accordion:hover {
 
252
  background-color: #444;
253
+ }
254
+
255
+ .panel {
256
+ padding: 0 18px;
257
+ background-color: #1a1a1a;
258
+ max-height: 0;
259
+ overflow: hidden;
260
+ transition: max-height 0.2s ease-out;
261
+ border-radius: 0 0 5px 5px;
262
+ }
263
+
264
+ /* Markdown styles */
265
+ .markdown {
266
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
267
+ line-height: 1.6;
268
+ color: #ccc;
269
+ }
270
+
271
+ .markdown h1, .markdown h2, .markdown h3 {
272
+ color: #ffd100;
273
+ }
274
+
275
+ .markdown code {
276
+ background-color: #333;
277
+ padding: 2px 4px;
278
+ border-radius: 4px;
279
+ }
280
+
281
+ .markdown pre {
282
+ background-color: #333;
283
+ padding: 10px;
284
+ border-radius: 4px;
285
+ overflow-x: auto;
286
  }
287
  </style>
288
  </head>
289
  <body>
290
+ <!-- Main game container -->
291
  <div id="game-container">
292
+ <!-- Combat window containing allies and boss -->
293
  <div id="combat-window">
294
+ <!-- Allies section -->
295
  <div id="allies"></div>
296
+ <!-- Boss section -->
297
  <div id="boss">
298
+ <!-- Boss health bar -->
299
  <div id="boss-health-bar" class="health-bar">
300
  <div class="health-bar-text">Boss HP: 5000/5000</div>
301
  </div>
302
  </div>
303
  </div>
304
+ <!-- Spell buttons container -->
305
  <div id="spell-buttons"></div>
306
+ <!-- Mana bar -->
307
+ <div id="mana-bar">
308
+ <div id="mana-bar-fill"></div>
309
+ <div id="mana-text">Mana: 100/100</div>
310
+ </div>
311
+ <!-- Game over message -->
312
+ <div id="game-over">GAME OVER</div>
313
+ <!-- Victory message -->
314
+ <div id="victory">VICTORY!</div>
315
+ <!-- Reset button -->
316
+ <button id="reset-button">RESET</button>
317
+
318
+ <!-- Spellbook Accordion -->
319
+ <button class="accordion">Spellbook</button>
320
+ <div class="panel">
321
+ <div id="spellbook"></div>
322
+ </div>
323
+
324
+ <!-- Info Accordion -->
325
+ <button class="accordion">Info</button>
326
+ <div class="panel">
327
+ <div id="info" class="markdown">
328
+ <h1>Tiny Healer</h1>
329
+
330
+ <h2>TL;DR</h2>
331
+ <p>Tiny Healer is made with the gameplay loop of a healer in World of Warcraft in mind. Healing in a dungeon minus the game.</p>
332
+
333
+ <h2>Rules</h2>
334
+ <ul>
335
+ <li>You are a healer, you cannot die yourself.</li>
336
+ <li>Target your allies and cast spells to heal them (keybinds are 1-5).</li>
337
+ <li>Allies automatically attack the boss.</li>
338
+ <li>Game Over when all allies are dead.</li>
339
+ <li>Victory when the boss is dead.</li>
340
+ </ul>
341
+
342
+ <h2>Mechanics</h2>
343
+ <ul>
344
+ <li>The boss deals damage to a random ally every second.</li>
345
+ <li>The boss periodically applies a Bleed to a random ally.</li>
346
+ <li>You regenerate Mana passively.</li>
347
+ <li>The Global Cooldown is 1.5 sec.</li>
348
+ </ul>
349
+
350
+ <h2>Usage</h2>
351
+ <p>It's only a few hundred lines of Pygame! The idea is to have a structure to tweak/tune mechanics and create your own boss encounters.</p>
352
+ </div>
353
+ </div>
354
 
355
  <script>
356
+ // Array to store ally objects
357
  const allies = [];
358
+ // Boss object
359
  let boss = { hp: 5000, maxHp: 5000 };
360
+ // Currently selected ally
361
  let selectedAlly = null;
362
+ // Global cooldown flag
363
  let globalCooldown = false;
364
+ // Game active flag
365
+ let gameActive = true;
366
+ // Player's current mana
367
+ let playerMana = 100;
368
+ // Maximum mana
369
+ const maxMana = 100;
370
+ // Boss bleed ability cooldown
371
+ let bossBleedCooldown = 0;
372
 
373
+ // Spell definitions
374
  const spells = [
375
+ { name: "Quick Heal", cooldown: 0, heal: 5, manaCost: 3, description: "A fast, low-cost heal that restores 5 HP." },
376
+ { name: "Strong Heal", cooldown: 15, heal: 30, manaCost: 5, description: "A powerful heal that restores 30 HP, but has a longer cooldown." },
377
+ { name: "Healing Stream", cooldown: 45, heal: 3, duration: 10, interval: 0.5, manaCost: 6, description: "Heals the target for 3 HP every 0.5 seconds for 10 seconds." },
378
+ { name: "Chain Heal", cooldown: 15, heal: 10, targets: 3, manaCost: 10, description: "Heals 3 random allies for 10 HP each." },
379
+ { name: "Team Heal", cooldown: 120, heal: 30, manaCost: 20, description: "Heals all allies for 30 HP, but has a very long cooldown." }
380
  ];
381
 
382
+ // Function to create an ally object
383
  function createAlly(id) {
384
+ return { id, hp: 100, maxHp: 100, alive: true, bleeding: false };
385
  }
386
 
387
+ // Function to update health bars
388
  function updateHealthBar(entity, barElement) {
389
  const percentage = (entity.hp / entity.maxHp) * 100;
390
  barElement.style.width = `${percentage}%`;
391
  barElement.querySelector('.health-bar-text').textContent = `HP: ${entity.hp}/${entity.maxHp}`;
392
+ if (entity.hp <= 0) {
393
+ barElement.classList.add('dead');
394
+ }
395
+ if (entity.bleeding) {
396
+ barElement.classList.add('bleeding');
397
+ } else {
398
+ barElement.classList.remove('bleeding');
399
+ }
400
  }
401
 
402
+ // Function to update the mana bar
403
+ function updateManaBar() {
404
+ const manaBarFill = document.getElementById('mana-bar-fill');
405
+ const manaText = document.getElementById('mana-text');
406
+ const percentage = (playerMana / maxMana) * 100;
407
+ manaBarFill.style.width = `${percentage}%`;
408
+ manaText.textContent = `Mana: ${playerMana}/${maxMana}`;
409
+ }
410
+
411
+ // Function to create ally health bars
412
  function createAllies() {
413
  const alliesContainer = document.getElementById('allies');
414
+ alliesContainer.innerHTML = '';
415
+ allies.length = 0;
416
  for (let i = 0; i < 5; i++) {
417
  const ally = createAlly(i);
418
  allies.push(ally);
 
425
  }
426
  }
427
 
428
+ // Function to select an ally
429
  function selectAlly(index) {
430
+ if (!allies[index].alive) return;
431
  const healthBars = document.querySelectorAll('#allies .health-bar');
432
  healthBars.forEach(bar => bar.classList.remove('selected'));
433
  healthBars[index].classList.add('selected');
 
435
  updateSpellButtons();
436
  }
437
 
438
+ // Function to create spell buttons
439
  function createSpellButtons() {
440
  const spellButtonsContainer = document.getElementById('spell-buttons');
441
+ spellButtonsContainer.innerHTML = '';
442
  spells.forEach((spell, index) => {
443
  const button = document.createElement('button');
444
  button.className = 'spell-button';
445
+ button.innerHTML = `${spell.name}<br>(${spell.manaCost} Mana)<div class="cooldown-progress"></div>`;
446
  button.onclick = () => castSpell(index);
447
  button.disabled = true;
448
  spellButtonsContainer.appendChild(button);
449
  });
450
  }
451
 
452
+ // Function to update spell button states
453
  function updateSpellButtons() {
454
  const spellButtons = document.querySelectorAll('.spell-button');
455
  spellButtons.forEach((button, index) => {
456
+ button.disabled = !selectedAlly || !selectedAlly.alive || globalCooldown || button.classList.contains('on-cooldown') || !gameActive || playerMana < spells[index].manaCost;
457
  });
458
  }
459
 
460
+ // Function to cast a spell
461
  function castSpell(spellIndex) {
462
+ const spell = spells[spellIndex];
463
+ if (selectedAlly && selectedAlly.alive && !globalCooldown && !document.querySelectorAll('.spell-button')[spellIndex].classList.contains('on-cooldown') && gameActive && playerMana >= spell.manaCost) {
464
+ playerMana -= spell.manaCost;
465
+ updateManaBar();
466
  switch (spellIndex) {
467
  case 0:
468
  case 1:
 
483
  }
484
  }
485
 
486
+ // Function to heal an ally
487
  function healAlly(ally, amount) {
488
+ if (ally.alive) {
489
+ ally.hp = Math.min(ally.hp + amount, ally.maxHp);
490
+ updateHealthBar(ally, document.querySelectorAll('.health-bar')[ally.id]);
491
+ }
492
  }
493
 
494
+ // Function to start a healing stream
495
  function startHealingStream(ally, spell) {
496
  let ticks = spell.duration / spell.interval;
497
  function tick() {
498
+ if (ticks > 0 && ally.alive && gameActive) {
499
  healAlly(ally, spell.heal);
500
  ticks--;
501
  setTimeout(tick, spell.interval * 1000);
 
504
  tick();
505
  }
506
 
507
+ // Function to perform chain heal
508
  function chainHeal(spell) {
509
+ const livingAllies = allies.filter(ally => ally.alive);
510
+ const targets = livingAllies.sort(() => 0.5 - Math.random()).slice(0, spell.targets);
511
  targets.forEach(ally => healAlly(ally, spell.heal));
512
  }
513
 
514
+ // Function to heal all allies
515
  function teamHeal(spell) {
516
  allies.forEach(ally => healAlly(ally, spell.heal));
517
  }
518
 
519
+ // Function to start spell cooldown
520
  function startSpellCooldown(spellIndex) {
521
  const button = document.querySelectorAll('.spell-button')[spellIndex];
522
  const progressBar = button.querySelector('.cooldown-progress');
523
  button.classList.add('on-cooldown');
524
+
525
+ progressBar.style.transition = 'width 0.1s linear';
526
  progressBar.style.width = '100%';
527
+
528
  setTimeout(() => {
529
+ progressBar.style.transition = `width ${spells[spellIndex].cooldown}s linear`;
530
  progressBar.style.width = '0';
531
+ }, 100);
532
+
533
+ setTimeout(() => {
534
+ button.classList.remove('on-cooldown');
535
  updateSpellButtons();
536
  }, spells[spellIndex].cooldown * 1000);
537
  }
538
 
539
+ // Function to start global cooldown
540
  function startGlobalCooldown() {
541
  globalCooldown = true;
542
  updateSpellButtons();
 
546
  }, 1500);
547
  }
548
 
549
+ // Function for boss to damage allies
550
  function bossDamage() {
551
+ if (!gameActive) return;
552
+ const damageAmount = 5;
553
+ const livingAllies = allies.filter(ally => ally.alive);
554
+ if (livingAllies.length === 0) {
555
+ endGame();
556
+ return;
557
+ }
558
+ const targetAlly = livingAllies[Math.floor(Math.random() * livingAllies.length)];
559
  targetAlly.hp = Math.max(targetAlly.hp - damageAmount, 0);
560
+ if (targetAlly.hp === 0) {
561
+ targetAlly.alive = false;
562
+ }
563
  updateHealthBar(targetAlly, document.querySelectorAll('.health-bar')[targetAlly.id]);
564
+ if (allies.every(ally => !ally.alive)) {
565
+ endGame();
566
+ }
567
+ }
568
+
569
+ // Function for boss bleed ability
570
+ function bossBleedAbility() {
571
+ if (!gameActive) return;
572
+ bossBleedCooldown--;
573
+ if (bossBleedCooldown <= 0) {
574
+ const livingAllies = allies.filter(ally => ally.alive);
575
+ if (livingAllies.length > 0) {
576
+ const targetAlly = livingAllies[Math.floor(Math.random() * livingAllies.length)];
577
+ targetAlly.bleeding = true;
578
+ updateHealthBar(targetAlly, document.querySelectorAll('.health-bar')[targetAlly.id]);
579
+ let bleedTicks = 4;
580
+ function bleedTick() {
581
+ if (bleedTicks > 0 && targetAlly.alive && gameActive) {
582
+ targetAlly.hp = Math.max(targetAlly.hp - 10, 0);
583
+ updateHealthBar(targetAlly, document.querySelectorAll('.health-bar')[targetAlly.id]);
584
+ bleedTicks--;
585
+ if (bleedTicks === 0) {
586
+ targetAlly.bleeding = false;
587
+ updateHealthBar(targetAlly, document.querySelectorAll('.health-bar')[targetAlly.id]);
588
+ } else {
589
+ setTimeout(bleedTick, 1000);
590
+ }
591
+ }
592
+ }
593
+ bleedTick();
594
+ }
595
+ bossBleedCooldown = 15;
596
+ }
597
+ }
598
+
599
+ // Function for allies to attack boss
600
+ function alliesAttack() {
601
+ if (!gameActive) return;
602
+ const damagePerAlly = 5;
603
+ const livingAllies = allies.filter(ally => ally.alive);
604
+ const totalDamage = livingAllies.length * damagePerAlly;
605
+ boss.hp = Math.max(boss.hp - totalDamage, 0);
606
+ updateHealthBar(boss, document.getElementById('boss-health-bar'));
607
+ if (boss.hp <= 0) {
608
+ victory();
609
+ }
610
+ }
611
+
612
+ // Function to regenerate mana
613
+ function regenerateMana() {
614
+ if (gameActive && playerMana < maxMana) {
615
+ playerMana = Math.min(playerMana + 1, maxMana);
616
+ updateManaBar();
617
+ }
618
+ }
619
+
620
+ // Function to end the game (loss)
621
+ function endGame() {
622
+ gameActive = false;
623
+ document.getElementById('game-over').style.display = 'block';
624
+ document.getElementById('reset-button').style.display = 'block';
625
+ updateSpellButtons();
626
+ }
627
+
628
+ // Function to end the game (victory)
629
+ function victory() {
630
+ gameActive = false;
631
+ document.getElementById('victory').style.display = 'block';
632
+ document.getElementById('reset-button').style.display = 'block';
633
+ updateSpellButtons();
634
+ }
635
+
636
+ // Function to reset the game
637
+ function resetGame() {
638
+ gameActive = true;
639
+ document.getElementById('game-over').style.display = 'none';
640
+ document.getElementById('victory').style.display = 'none';
641
+ document.getElementById('reset-button').style.display = 'none';
642
+ createAllies();
643
+ createSpellButtons();
644
+ boss = { hp: 5000, maxHp: 5000 };
645
+ updateHealthBar(boss, document.getElementById('boss-health-bar'));
646
+ selectedAlly = null;
647
+ globalCooldown = false;
648
+ playerMana = maxMana;
649
+ bossBleedCooldown = 15;
650
+ updateManaBar();
651
+ updateSpellButtons();
652
  }
653
 
654
+ // Main game loop
655
  function gameLoop() {
656
+ if (gameActive) {
657
+ bossDamage();
658
+ bossBleedAbility();
659
+ alliesAttack();
660
+ setTimeout(gameLoop, 1000);
661
+ }
662
  }
663
 
664
+ // Function to populate the spellbook
665
+ function populateSpellbook() {
666
+ const spellbookContainer = document.getElementById('spellbook');
667
+ spellbookContainer.innerHTML = '';
668
+ spells.forEach(spell => {
669
+ const spellInfo = document.createElement('div');
670
+ spellInfo.innerHTML = `<h3>${spell.name}</h3>
671
+ <p>${spell.description}</p>
672
+ <p>Mana Cost: ${spell.manaCost}</p>
673
+ <p>Cooldown: ${spell.cooldown} seconds</p>`;
674
+ spellbookContainer.appendChild(spellInfo);
675
+ });
676
+ }
677
+
678
+ // Set up mana regeneration interval
679
+ setInterval(regenerateMana, 2000);
680
+
681
+ // Event listener for keyboard input
682
  document.addEventListener('keydown', (event) => {
683
  const key = event.key;
684
  if (key >= '1' && key <= '5') {
 
686
  }
687
  });
688
 
689
+ // Event listener for reset button
690
+ document.getElementById('reset-button').addEventListener('click', resetGame);
691
+
692
+ // Event listeners for accordions
693
+ const accordions = document.getElementsByClassName("accordion");
694
+ for (let i = 0; i < accordions.length; i++) {
695
+ accordions[i].addEventListener("click", function() {
696
+ this.classList.toggle("active");
697
+ const panel = this.nextElementSibling;
698
+ if (panel.style.maxHeight) {
699
+ panel.style.maxHeight = null;
700
+ } else {
701
+ panel.style.maxHeight = panel.scrollHeight + "px";
702
+ }
703
+ });
704
+ }
705
 
706
+ // Initial game setup
707
  createAllies();
708
  createSpellButtons();
709
  updateHealthBar(boss, document.getElementById('boss-health-bar'));
710
+ updateManaBar();
711
+ populateSpellbook();
712
  gameLoop();
713
  </script>
714
  </body>