Paresiast commited on
Commit
215768f
·
verified ·
1 Parent(s): 3e33ccb

Cette 3 powerfull spells that cost mana to be cast and create button to use them - Follow Up Deployment

Browse files
Files changed (1) hide show
  1. index.html +271 -24
index.html CHANGED
@@ -89,6 +89,12 @@
89
  box-shadow: 0 0 10px var(--enemy-color);
90
  position: relative;
91
  }
 
 
 
 
 
 
92
  .enemy::before {
93
  content: attr(data-emoji);
94
  position: absolute;
@@ -376,6 +382,21 @@
376
  </div>
377
  </div>
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  <div class="bg-gray-800 p-4 rounded-lg">
380
  <h2 class="text-xl font-bold mb-2 text-yellow-400">Game Log</h2>
381
  <div id="gameLog" class="h-32 overflow-y-auto text-sm bg-gray-900 p-2 rounded">
@@ -512,7 +533,11 @@
512
  { name: "Dragonnet", minLevel: 6, health: 40, damage: 9.5, xp: 50, emoji: "🐉" },
513
  { name: "Wyvern", minLevel: 7, health: 50, damage: 11.5, xp: 60, emoji: "🦅" },
514
  { name: "Dragon", minLevel: 8, health: 70, damage: 14.5, xp: 80, emoji: "🐲" },
515
- { name: "Beholder", minLevel: 9, health: 100, damage: 19.5, xp: 100, emoji: "👁️" }
 
 
 
 
516
  ];
517
 
518
  let player = {
@@ -618,7 +643,46 @@
618
  dungeon[player.y][player.x] = 'player';
619
 
620
  // Add enemies in rooms (avoid first room)
621
- for (let i = 0; i < 5 + player.level; i++) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622
  let room;
623
  do {
624
  room = rooms[Math.floor(Math.random() * rooms.length)];
@@ -627,20 +691,25 @@
627
  const x = room.x + 1 + Math.floor(Math.random() * (room.width - 2));
628
  const y = room.y + 1 + Math.floor(Math.random() * (room.height - 2));
629
 
630
- // Get possible enemies for current level
631
- const possibleEnemies = enemyTypes.filter(e => e.minLevel <= player.level);
632
- const enemyType = possibleEnemies[Math.floor(Math.random() * possibleEnemies.length)];
633
-
634
- enemies.push({
635
- x,
636
- y,
637
- name: enemyType.name,
638
- emoji: enemyType.emoji,
639
- health: enemyType.health * (1 + player.level * 0.2),
640
- damage: enemyType.damage * (1 + player.level * 0.1),
641
- xp: enemyType.xp * (1 + player.level * 0.1)
642
- });
643
- dungeon[y][x] = 'enemy';
 
 
 
 
 
644
  }
645
 
646
  // Add items in rooms
@@ -696,9 +765,18 @@
696
  if (isVisible || (x === player.x && y === player.y)) {
697
  div.classList.add('cell', dungeon[y][x]);
698
  if (dungeon[y][x] === 'enemy') {
699
- const enemy = enemies.find(e => e.x === x && e.y === y);
 
 
 
700
  if (enemy) {
701
- div.setAttribute('data-emoji', enemy.emoji);
 
 
 
 
 
 
702
  }
703
  }
704
  } else {
@@ -710,6 +788,51 @@
710
  }
711
  }
712
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
713
  function updateStats() {
714
  healthEl.textContent = `${player.health}/${player.maxHealth}`;
715
  manaEl.textContent = `${player.mana}/${player.maxMana}`;
@@ -765,7 +888,11 @@
765
  const enemy = enemies[enemyIndex];
766
 
767
  // Player attacks enemy
768
- const playerDamage = Math.max(1, player.attack - Math.floor(enemy.damage / 2));
 
 
 
 
769
  enemy.health -= playerDamage;
770
  addLogMessage(`You hit the ${enemy.name} for ${playerDamage} damage!`, 'yellow');
771
 
@@ -797,6 +924,13 @@
797
  if (player.xp >= player.level * 100) {
798
  levelUp();
799
  }
 
 
 
 
 
 
 
800
  }
801
 
802
  updateStats();
@@ -842,10 +976,21 @@
842
  }
843
  }
844
  else if (targetCell === 'exit') {
845
- // Advance to next level
846
- player.level++;
847
- addLogMessage(`You found the exit! Moving to level ${player.level}`, 'purple');
848
- showLevelComplete();
 
 
 
 
 
 
 
 
 
 
 
849
  }
850
 
851
  // Check if player died from this attack
@@ -878,9 +1023,12 @@
878
  });
879
 
880
  function initGame() {
 
 
881
  generateDungeon();
882
  renderDungeon();
883
  updateStats();
 
884
  addLogMessage(`Entering dungeon level ${player.level}...`, 'yellow');
885
  }
886
 
@@ -894,7 +1042,7 @@
894
  mana: 50,
895
  maxMana: 50,
896
  xp: 0,
897
- level: 1,
898
  attack: 5,
899
  defense: 3,
900
  inventory: [
@@ -957,12 +1105,111 @@
957
  moveLeft.addEventListener('click', () => movePlayer(-1, 0));
958
  moveRight.addEventListener('click', () => movePlayer(1, 0));
959
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
960
  function gameOver() {
961
  deathLevelEl.textContent = player.level;
962
  gameOverModal.style.display = 'flex';
963
  addLogMessage("You have died! Game over.", 'red');
964
  }
965
 
 
 
 
 
 
966
  restartGame.addEventListener('click', () => {
967
  gameOverModal.style.display = 'none';
968
  document.getElementById('newGame').click(); // Trigger new game
 
89
  box-shadow: 0 0 10px var(--enemy-color);
90
  position: relative;
91
  }
92
+
93
+ .boss-cell {
94
+ background-color: #d64045;
95
+ box-shadow: 0 0 15px #ff0000;
96
+ animation: pulse 0.5s infinite;
97
+ }
98
  .enemy::before {
99
  content: attr(data-emoji);
100
  position: absolute;
 
382
  </div>
383
  </div>
384
 
385
+ <div class="bg-gray-800 p-4 rounded-lg mb-4">
386
+ <h2 class="text-xl font-bold mb-2 text-yellow-400">Spells</h2>
387
+ <div class="grid grid-cols-3 gap-2 mb-4">
388
+ <button id="fireballBtn" class="px-2 py-1 bg-red-800 hover:bg-red-700 rounded flex items-center justify-center">
389
+ <i class="fas fa-fire mr-1"></i>Fireball (15 MP)
390
+ </button>
391
+ <button id="healBtn" class="px-2 py-1 bg-green-800 hover:bg-green-700 rounded flex items-center justify-center">
392
+ <i class="fas fa-heart mr-1"></i>Heal (20 MP)
393
+ </button>
394
+ <button id="lightningBtn" class="px-2 py-1 bg-blue-800 hover:bg-blue-700 rounded flex items-center justify-center">
395
+ <i class="fas fa-bolt mr-1"></i>Lightning (25 MP)
396
+ </button>
397
+ </div>
398
+ </div>
399
+
400
  <div class="bg-gray-800 p-4 rounded-lg">
401
  <h2 class="text-xl font-bold mb-2 text-yellow-400">Game Log</h2>
402
  <div id="gameLog" class="h-32 overflow-y-auto text-sm bg-gray-900 p-2 rounded">
 
533
  { name: "Dragonnet", minLevel: 6, health: 40, damage: 9.5, xp: 50, emoji: "🐉" },
534
  { name: "Wyvern", minLevel: 7, health: 50, damage: 11.5, xp: 60, emoji: "🦅" },
535
  { name: "Dragon", minLevel: 8, health: 70, damage: 14.5, xp: 80, emoji: "🐲" },
536
+ { name: "Beholder", minLevel: 9, health: 100, damage: 19.5, xp: 100, emoji: "👁️" },
537
+ // Boss types (stats réduites)
538
+ { name: "Roi Squelette", minLevel: 4, health: 40, damage: 5, xp: 100, emoji: "💀👑", boss: true },
539
+ { name: "Dragon Ancien", minLevel: 8, health: 90, damage: 12, xp: 200, emoji: "🐉🔥", boss: true },
540
+ { name: "Seigneur des Ténèbres", minLevel: 12, health: 150, damage: 20, xp: 300, emoji: "👹🌑", boss: true }
541
  ];
542
 
543
  let player = {
 
643
  dungeon[player.y][player.x] = 'player';
644
 
645
  // Add enemies in rooms (avoid first room)
646
+ const enemyCount = 5 + player.level;
647
+
648
+ // Add a boss every 4 levels
649
+ if (player.level % 4 === 0) {
650
+ const possibleBosses = enemyTypes.filter(e => e.boss && e.minLevel <= player.level);
651
+ if (possibleBosses.length > 0) {
652
+ const bossType = possibleBosses[Math.floor(Math.random() * possibleBosses.length)];
653
+ const bossRoom = rooms[rooms.length - 1]; // Boss in last room
654
+
655
+ // Boss occupies 2x2 space
656
+ const x = bossRoom.x + Math.floor(bossRoom.width / 2) - 1;
657
+ const y = bossRoom.y + Math.floor(bossRoom.height / 2) - 1;
658
+
659
+ enemies.push({
660
+ x, y,
661
+ name: bossType.name,
662
+ emoji: bossType.emoji,
663
+ health: bossType.health * (1 + (player.level / 4)),
664
+ damage: bossType.damage * (1 + (player.level / 8)),
665
+ xp: bossType.xp * (1 + (player.level / 4)),
666
+ isBoss: true,
667
+ width: 2,
668
+ height: 2
669
+ });
670
+
671
+ // Mark boss cells
672
+ for (let dy = 0; dy < 2; dy++) {
673
+ for (let dx = 0; dx < 2; dx++) {
674
+ if (y + dy < SIZE && x + dx < SIZE) {
675
+ dungeon[y + dy][x + dx] = 'enemy';
676
+ }
677
+ }
678
+ }
679
+
680
+ addLogMessage(`A powerful ${bossType.name} awaits in the depths!`, 'red');
681
+ }
682
+ }
683
+
684
+ // Add regular enemies
685
+ for (let i = 0; i < enemyCount; i++) {
686
  let room;
687
  do {
688
  room = rooms[Math.floor(Math.random() * rooms.length)];
 
691
  const x = room.x + 1 + Math.floor(Math.random() * (room.width - 2));
692
  const y = room.y + 1 + Math.floor(Math.random() * (room.height - 2));
693
 
694
+ // Get possible enemies for current level (excluding bosses)
695
+ const possibleEnemies = enemyTypes.filter(e => !e.boss && e.minLevel <= player.level);
696
+ if (possibleEnemies.length > 0) {
697
+ const enemyType = possibleEnemies[Math.floor(Math.random() * possibleEnemies.length)];
698
+
699
+ enemies.push({
700
+ x,
701
+ y,
702
+ name: enemyType.name,
703
+ emoji: enemyType.emoji,
704
+ health: enemyType.health * (1 + player.level * 0.2),
705
+ damage: enemyType.damage * (1 + player.level * 0.1),
706
+ xp: enemyType.xp * (1 + player.level * 0.1),
707
+ isBoss: false,
708
+ width: 1,
709
+ height: 1
710
+ });
711
+ dungeon[y][x] = 'enemy';
712
+ }
713
  }
714
 
715
  // Add items in rooms
 
765
  if (isVisible || (x === player.x && y === player.y)) {
766
  div.classList.add('cell', dungeon[y][x]);
767
  if (dungeon[y][x] === 'enemy') {
768
+ const enemy = enemies.find(e =>
769
+ x >= e.x && x < e.x + (e.width || 1) &&
770
+ y >= e.y && y < e.y + (e.height || 1)
771
+ );
772
  if (enemy) {
773
+ // Only show emoji on first cell of boss
774
+ if ((!enemy.isBoss) || (x === enemy.x && y === enemy.y)) {
775
+ div.setAttribute('data-emoji', enemy.emoji);
776
+ }
777
+ if (enemy.isBoss) {
778
+ div.classList.add('boss-cell');
779
+ }
780
  }
781
  }
782
  } else {
 
788
  }
789
  }
790
 
791
+ function renderInventory() {
792
+ const inventoryEl = document.getElementById('inventory');
793
+ inventoryEl.innerHTML = '';
794
+
795
+ player.inventory.forEach((item, index) => {
796
+ const itemEl = document.createElement('div');
797
+ itemEl.className = `bg-gray-700 p-2 rounded text-center tooltip cursor-pointer hover:bg-gray-600`;
798
+ itemEl.innerHTML = `
799
+ <i class="fas ${item.icon} text-${item.color || 'gray-400'}"></i>
800
+ <span class="tooltip-text">${item.name}${item.damage ? ` (${item.damage} damage)` : ''}${item.defense ? ` (${item.defense} defense)` : ''}${item.heal ? ` (Heals ${item.heal} HP)` : ''}${item.restore ? ` (Restores ${item.restore} MP)` : ''}</span>
801
+ `;
802
+
803
+ itemEl.addEventListener('click', () => useItem(index));
804
+ inventoryEl.appendChild(itemEl);
805
+ });
806
+ }
807
+
808
+ function useItem(index) {
809
+ const item = player.inventory[index];
810
+
811
+ if (item.heal) {
812
+ player.health = Math.min(player.maxHealth, player.health + item.heal);
813
+ addLogMessage(`Used ${item.name}! +${item.heal} HP`, 'green');
814
+ player.inventory.splice(index, 1);
815
+ }
816
+ else if (item.restore) {
817
+ player.mana = Math.min(player.maxMana, player.mana + item.restore);
818
+ addLogMessage(`Used ${item.name}! +${item.restore} MP`, 'blue');
819
+ player.inventory.splice(index, 1);
820
+ }
821
+ else if (item.damage) {
822
+ player.attack += item.damage;
823
+ addLogMessage(`Equipped ${item.name}! +${item.damage} attack`, 'yellow');
824
+ player.inventory.splice(index, 1);
825
+ }
826
+ else if (item.defense) {
827
+ player.defense += item.defense;
828
+ addLogMessage(`Equipped ${item.name}! +${item.defense} defense`, 'purple');
829
+ player.inventory.splice(index, 1);
830
+ }
831
+
832
+ updateStats();
833
+ renderInventory();
834
+ }
835
+
836
  function updateStats() {
837
  healthEl.textContent = `${player.health}/${player.maxHealth}`;
838
  manaEl.textContent = `${player.mana}/${player.maxMana}`;
 
888
  const enemy = enemies[enemyIndex];
889
 
890
  // Player attacks enemy
891
+ let playerDamage = Math.max(1, player.attack - Math.floor(enemy.damage / 2));
892
+ // Bosses take reduced damage
893
+ if (enemy.isBoss) {
894
+ playerDamage = Math.max(1, Math.floor(playerDamage * 0.7));
895
+ }
896
  enemy.health -= playerDamage;
897
  addLogMessage(`You hit the ${enemy.name} for ${playerDamage} damage!`, 'yellow');
898
 
 
924
  if (player.xp >= player.level * 100) {
925
  levelUp();
926
  }
927
+
928
+ // If boss was defeated, advance to next level
929
+ if (enemy.isBoss) {
930
+ player.level++;
931
+ addLogMessage(`You defeated the boss! Moving to level ${player.level}`, 'purple');
932
+ initGame();
933
+ }
934
  }
935
 
936
  updateStats();
 
976
  }
977
  }
978
  else if (targetCell === 'exit') {
979
+ // Check if boss was defeated before allowing exit
980
+ const bossDefeated = !enemies.some(e => e.isBoss);
981
+ if (bossDefeated) {
982
+ // Advance to next level
983
+ const nextLevel = player.level + 1;
984
+ if (nextLevel <= 20) { // Maximum dungeon level
985
+ player.level = nextLevel;
986
+ addLogMessage(`You found the exit! Moving to level ${player.level}`, 'purple');
987
+ showLevelComplete();
988
+ } else {
989
+ addLogMessage("You need to complete previous levels first!", 'red');
990
+ }
991
+ } else {
992
+ addLogMessage("You must defeat the boss before using the exit!", 'red');
993
+ }
994
  }
995
 
996
  // Check if player died from this attack
 
1023
  });
1024
 
1025
  function initGame() {
1026
+ // Ensure level is at least 1
1027
+ player.level = Math.max(1, player.level);
1028
  generateDungeon();
1029
  renderDungeon();
1030
  updateStats();
1031
+ renderInventory();
1032
  addLogMessage(`Entering dungeon level ${player.level}...`, 'yellow');
1033
  }
1034
 
 
1042
  mana: 50,
1043
  maxMana: 50,
1044
  xp: 0,
1045
+ level: 1, // Always start at level 1
1046
  attack: 5,
1047
  defense: 3,
1048
  inventory: [
 
1105
  moveLeft.addEventListener('click', () => movePlayer(-1, 0));
1106
  moveRight.addEventListener('click', () => movePlayer(1, 0));
1107
 
1108
+ function castFireball() {
1109
+ if (player.mana < 15) {
1110
+ addLogMessage("Not enough mana for Fireball!", "red");
1111
+ return;
1112
+ }
1113
+
1114
+ player.mana -= 15;
1115
+ const damage = 15 + player.level * 2;
1116
+
1117
+ // Find all enemies in range (3 cells)
1118
+ const inRange = enemies.filter(e => {
1119
+ const dx = Math.abs(e.x - player.x);
1120
+ const dy = Math.abs(e.y - player.y);
1121
+ return dx <= 3 && dy <= 3;
1122
+ });
1123
+
1124
+ if (inRange.length === 0) {
1125
+ addLogMessage("Fireball fizzles - no enemies in range!", "red");
1126
+ return;
1127
+ }
1128
+
1129
+ inRange.forEach(enemy => {
1130
+ enemy.health -= damage;
1131
+ addLogMessage(`Fireball hits ${enemy.name} for ${damage} damage!`, "orange");
1132
+
1133
+ if (enemy.health <= 0) {
1134
+ addLogMessage(`${enemy.name} was incinerated! +${Math.floor(enemy.xp)} XP`, "green");
1135
+ player.xp += enemy.xp;
1136
+ enemies.splice(enemies.indexOf(enemy), 1);
1137
+ dungeon[enemy.y][enemy.x] = 'floor';
1138
+ }
1139
+ });
1140
+
1141
+ updateStats();
1142
+ renderDungeon();
1143
+ }
1144
+
1145
+ function castHeal() {
1146
+ if (player.mana < 20) {
1147
+ addLogMessage("Not enough mana for Heal!", "red");
1148
+ return;
1149
+ }
1150
+
1151
+ player.mana -= 20;
1152
+ const healAmount = 30 + player.level * 3;
1153
+ player.health = Math.min(player.maxHealth, player.health + healAmount);
1154
+ addLogMessage(`Healing magic restores ${healAmount} HP!`, "green");
1155
+
1156
+ updateStats();
1157
+ }
1158
+
1159
+ function castLightning() {
1160
+ if (player.mana < 25) {
1161
+ addLogMessage("Not enough mana for Lightning!", "red");
1162
+ return;
1163
+ }
1164
+
1165
+ player.mana -= 25;
1166
+
1167
+ // Find closest enemy
1168
+ let closestEnemy = null;
1169
+ let minDist = Infinity;
1170
+
1171
+ enemies.forEach(enemy => {
1172
+ const dx = Math.abs(enemy.x - player.x);
1173
+ const dy = Math.abs(enemy.y - player.y);
1174
+ const dist = dx + dy;
1175
+
1176
+ if (dist < minDist) {
1177
+ minDist = dist;
1178
+ closestEnemy = enemy;
1179
+ }
1180
+ });
1181
+
1182
+ if (!closestEnemy) {
1183
+ addLogMessage("Lightning fizzles - no enemies found!", "red");
1184
+ return;
1185
+ }
1186
+
1187
+ const damage = 30 + player.level * 3;
1188
+ closestEnemy.health -= damage;
1189
+ addLogMessage(`Lightning strikes ${closestEnemy.name} for ${damage} damage!`, "yellow");
1190
+
1191
+ if (closestEnemy.health <= 0) {
1192
+ addLogMessage(`${closestEnemy.name} was electrocuted! +${Math.floor(closestEnemy.xp)} XP`, "green");
1193
+ player.xp += closestEnemy.xp;
1194
+ enemies.splice(enemies.indexOf(closestEnemy), 1);
1195
+ dungeon[closestEnemy.y][closestEnemy.x] = 'floor';
1196
+ }
1197
+
1198
+ updateStats();
1199
+ renderDungeon();
1200
+ }
1201
+
1202
  function gameOver() {
1203
  deathLevelEl.textContent = player.level;
1204
  gameOverModal.style.display = 'flex';
1205
  addLogMessage("You have died! Game over.", 'red');
1206
  }
1207
 
1208
+ // Spell buttons
1209
+ document.getElementById('fireballBtn').addEventListener('click', castFireball);
1210
+ document.getElementById('healBtn').addEventListener('click', castHeal);
1211
+ document.getElementById('lightningBtn').addEventListener('click', castLightning);
1212
+
1213
  restartGame.addEventListener('click', () => {
1214
  gameOverModal.style.display = 'none';
1215
  document.getElementById('newGame').click(); // Trigger new game