Paresiast commited on
Commit
39386c5
·
verified ·
1 Parent(s): 0db2a9b

Probabilité de trouver des armes en tuant un ennemi = 20% - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +1408 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Jeux
3
- emoji: 😻
4
- colorFrom: yellow
5
  colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: jeux
3
+ emoji: 🐳
4
+ colorFrom: gray
5
  colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1408 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Dungeon Crawler Rogue-like</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ @import url('https://fonts.googleapis.com/css2?family=MedievalSharp&display=swap');
10
+
11
+ :root {
12
+ --wall-color: #3a2d32;
13
+ --floor-color: #6b5e62;
14
+ --player-color: #f8d347;
15
+ --enemy-color: #d64045;
16
+ --item-color: #5b9a8b;
17
+ --exit-color: #9c6ade;
18
+ --fog-color: rgba(0, 0, 0, 0.7);
19
+ }
20
+
21
+ body {
22
+ font-family: 'MedievalSharp', cursive;
23
+ background-color: #1a1a1a;
24
+ color: #e0e0e0;
25
+ overflow-x: hidden;
26
+ }
27
+
28
+ .game-container {
29
+ perspective: 1000px;
30
+ }
31
+
32
+ .dungeon-cell {
33
+ transition: all 0.3s ease;
34
+ position: relative;
35
+ }
36
+
37
+ .dungeon-cell.wall {
38
+ background-color: var(--wall-color);
39
+ box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
40
+ }
41
+
42
+ .dungeon-cell.floor {
43
+ background-color: var(--floor-color);
44
+ }
45
+
46
+ .dungeon-cell.player {
47
+ background-color: var(--player-color);
48
+ border-radius: 50%;
49
+ z-index: 10;
50
+ transform: scale(0.8);
51
+ box-shadow: 0 0 10px var(--player-color);
52
+ }
53
+
54
+ .dungeon-cell.enemy {
55
+ background-color: var(--enemy-color);
56
+ border-radius: 30%;
57
+ z-index: 5;
58
+ transform: scale(0.8);
59
+ box-shadow: 0 0 10px var(--enemy-color);
60
+ }
61
+
62
+ .dungeon-cell.item {
63
+ background-color: var(--item-color);
64
+ border-radius: 15%;
65
+ z-index: 3;
66
+ transform: scale(0.6);
67
+ box-shadow: 0 0 10px var(--item-color);
68
+ }
69
+
70
+ .dungeon-cell.exit {
71
+ background-color: var(--exit-color);
72
+ z-index: 2;
73
+ animation: pulse 2s infinite;
74
+ }
75
+
76
+ .dungeon-cell.fog {
77
+ background-color: var(--fog-color);
78
+ }
79
+
80
+ .tooltip {
81
+ visibility: hidden;
82
+ position: absolute;
83
+ z-index: 100;
84
+ background-color: rgba(0, 0, 0, 0.8);
85
+ border: 1px solid #444;
86
+ border-radius: 5px;
87
+ padding: 5px;
88
+ font-size: 14px;
89
+ pointer-events: none;
90
+ }
91
+
92
+ @keyframes pulse {
93
+ 0% { opacity: 0.7; }
94
+ 50% { opacity: 1; }
95
+ 100% { opacity: 0.7; }
96
+ }
97
+
98
+ .inventory-item {
99
+ transition: all 0.2s ease;
100
+ }
101
+
102
+ .inventory-item:hover {
103
+ transform: scale(1.1);
104
+ box-shadow: 0 0 10px gold;
105
+ }
106
+
107
+ .health-bar {
108
+ height: 5px;
109
+ background-color: #d64045;
110
+ transition: width 0.3s ease;
111
+ }
112
+
113
+ .mana-bar {
114
+ height: 5px;
115
+ background-color: #6b9ac9;
116
+ transition: width 0.3s ease;
117
+ }
118
+
119
+ .combat-log {
120
+ max-height: 150px;
121
+ overflow-y: auto;
122
+ scrollbar-width: thin;
123
+ }
124
+
125
+ .combat-log::-webkit-scrollbar {
126
+ width: 5px;
127
+ }
128
+
129
+ .combat-log::-webkit-scrollbar-thumb {
130
+ background-color: #555;
131
+ border-radius: 5px;
132
+ }
133
+
134
+ .dungeon-cell.player {
135
+ position: relative;
136
+ }
137
+
138
+ .damage-popup {
139
+ position: absolute;
140
+ color: white;
141
+ font-weight: bold;
142
+ pointer-events: none;
143
+ animation: float-up 1s forwards;
144
+ text-shadow: 1px 1px 2px black;
145
+ }
146
+
147
+ @keyframes float-up {
148
+ 0% { transform: translateY(0); opacity: 1; }
149
+ 100% { transform: translateY(-30px); opacity: 0; }
150
+ }
151
+
152
+ @media (max-width: 768px) {
153
+ .dungeon-grid {
154
+ grid-template-columns: repeat(15, 20px) !important;
155
+ grid-template-rows: repeat(15, 20px) !important;
156
+ }
157
+
158
+ .stats-panel {
159
+ flex-direction: column;
160
+ }
161
+ }
162
+ </style>
163
+ </head>
164
+ <body class="min-h-screen bg-gray-900">
165
+ <div class="container mx-auto px-4 py-8">
166
+ <h1 class="text-4xl font-bold text-center mb-6 text-yellow-400">Dungeon Crawler</h1>
167
+
168
+ <div class="flex flex-col lg:flex-row gap-6">
169
+ <!-- Game Area -->
170
+ <div class="game-container flex-1">
171
+ <div class="flex justify-between items-center mb-4">
172
+ <div class="text-xl">
173
+ Niveau: <span id="dungeon-level" class="font-bold">1</span>
174
+ </div>
175
+ <div class="flex gap-4">
176
+ <button id="new-game-btn" class="px-4 py-2 bg-blue-700 rounded hover:bg-blue-600 transition">Nouvelle partie</button>
177
+ <button id="help-btn" class="px-4 py-2 bg-gray-700 rounded hover:bg-gray-600 transition">Aide</button>
178
+ </div>
179
+ </div>
180
+
181
+ <div id="dungeon" class="mx-auto mb-4">
182
+ <!-- Dungeon grid will be generated here -->
183
+ </div>
184
+
185
+ <div class="flex justify-between items-center">
186
+ <div class="w-1/3">
187
+ <div class="text-sm mb-1">Santé: <span id="health-value">100</span>/100</div>
188
+ <div class="health-bar bg-gray-700 rounded-full">
189
+ <div id="health-bar" class="h-full rounded-full" style="width: 100%"></div>
190
+ </div>
191
+ </div>
192
+
193
+ <div class="w-1/3 text-center">
194
+ <div id="player-status" class="text-yellow-400 font-bold">Exploration</div>
195
+ </div>
196
+
197
+ <div class="w-1/3 text-right">
198
+ <div class="text-sm mb-1">Mana: <span id="mana-value">50</span>/50</div>
199
+ <div class="mana-bar bg-gray-700 rounded-full">
200
+ <div id="mana-bar" class="h-full rounded-full" style="width: 100%"></div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ </div>
205
+
206
+ <!-- Side Panel -->
207
+ <div class="w-full lg:w-80 flex flex-col gap-4">
208
+ <!-- Stats -->
209
+ <div class="bg-gray-800 p-4 rounded-lg">
210
+ <h2 class="text-xl font-bold mb-3 border-b pb-2">Statistiques</h2>
211
+ <div class="grid grid-cols-2 gap-2">
212
+ <div>
213
+ <div class="text-sm text-gray-400">Niveau</div>
214
+ <div id="player-level" class="text-lg">1</div>
215
+ </div>
216
+ <div>
217
+ <div class="text-sm text-gray-400">XP</div>
218
+ <div id="player-xp" class="text-lg">0/100</div>
219
+ </div>
220
+ <div>
221
+ <div class="text-sm text-gray-400">Attaque</div>
222
+ <div class="flex items-center gap-1">
223
+ <div id="player-attack" class="text-lg">5</div>
224
+ <div id="attack-power" class="text-xs text-yellow-400" title="Puissance d'attaque">+0</div>
225
+ </div>
226
+ </div>
227
+ <div>
228
+ <div class="text-sm text-gray-400">Défense</div>
229
+ <div id="player-defense" class="text-lg">3</div>
230
+ </div>
231
+ <div>
232
+ <div class="text-sm text-gray-400">Magie</div>
233
+ <div id="player-magic" class="text-lg">4</div>
234
+ </div>
235
+ <div>
236
+ <div class="text-sm text-gray-400">Or</div>
237
+ <div id="player-gold" class="text-lg">0</div>
238
+ </div>
239
+ </div>
240
+ </div>
241
+
242
+ <!-- Inventory -->
243
+ <div class="bg-gray-800 p-4 rounded-lg">
244
+ <h2 class="text-xl font-bold mb-3 border-b pb-2">Inventaire</h2>
245
+ <div id="inventory" class="grid grid-cols-4 gap-2">
246
+ <!-- Inventory items will be generated here -->
247
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
248
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
249
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
250
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
251
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
252
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
253
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
254
+ <div class="inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1">Vide</div>
255
+ </div>
256
+ </div>
257
+
258
+ <!-- Equipment -->
259
+ <div class="bg-gray-800 p-4 rounded-lg">
260
+ <h2 class="text-xl font-bold mb-3 border-b pb-2">Équipement</h2>
261
+ <div class="grid grid-cols-2 gap-3">
262
+ <div>
263
+ <div class="text-sm text-gray-400 mb-1">Arme</div>
264
+ <div id="equip-weapon" class="inventory-item bg-gray-700 h-16 rounded flex items-center justify-center text-sm">Poings</div>
265
+ </div>
266
+ <div>
267
+ <div class="text-sm text-gray-400 mb-1">Armure</div>
268
+ <div id="equip-armor" class="inventory-item bg-gray-700 h-16 rounded flex items-center justify-center text-sm">Vêtements</div>
269
+ </div>
270
+ <div>
271
+ <div class="text-sm text-gray-400 mb-1">Anneau</div>
272
+ <div id="equip-ring" class="inventory-item bg-gray-700 h-16 rounded flex items-center justify-center text-sm">-</div>
273
+ </div>
274
+ <div>
275
+ <div class="text-sm text-gray-400 mb-1">Amulette</div>
276
+ <div id="equip-amulet" class="inventory-item bg-gray-700 h-16 rounded flex items-center justify-center text-sm">-</div>
277
+ </div>
278
+ </div>
279
+ </div>
280
+
281
+ <!-- Combat Log -->
282
+ <div class="bg-gray-800 p-4 rounded-lg">
283
+ <h2 class="text-xl font-bold mb-3 border-b pb-2">Journal</h2>
284
+ <div id="combat-log" class="combat-log text-sm h-40">
285
+ <div>Bienvenue dans le donjon!</div>
286
+ <div>Utilisez les touches ZQSD ou les flèches pour vous déplacer.</div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ </div>
292
+
293
+ <!-- Help Modal -->
294
+ <div id="help-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center hidden z-50">
295
+ <div class="bg-gray-800 rounded-lg p-6 max-w-2xl max-h-[90vh] overflow-y-auto">
296
+ <div class="flex justify-between items-center mb-4">
297
+ <h2 class="text-2xl font-bold">Aide & Commandes</h2>
298
+ <button id="close-help-btn" class="text-2xl">&times;</button>
299
+ </div>
300
+
301
+ <div class="space-y-4">
302
+ <div>
303
+ <h3 class="text-xl font-semibold mb-2">Contrôles</h3>
304
+ <ul class="list-disc pl-5 space-y-1">
305
+ <li><strong>Z/Flèche haut</strong> : Se déplacer vers le haut</li>
306
+ <li><strong>Q/Flèche gauche</strong> : Se déplacer vers la gauche</li>
307
+ <li><strong>S/Flèche bas</strong> : Se déplacer vers le bas</li>
308
+ <li><strong>D/Flèche droite</strong> : Se déplacer vers la droite</li>
309
+ <li><strong>Espace</strong> : Attaquer un ennemi adjacent</li>
310
+ <li><strong>M</strong> : Lancer un sort (si vous en connaissez)</li>
311
+ <li><strong>I</strong> : Utiliser un objet (potion, parchemin, etc.)</li>
312
+ </ul>
313
+ </div>
314
+
315
+ <div>
316
+ <h3 class="text-xl font-semibold mb-2">Mécaniques de jeu</h3>
317
+ <ul class="list-disc pl-5 space-y-1">
318
+ <li>Explorez le donjon généré procéduralement</li>
319
+ <li>Combattez des monstres pour gagner de l'XP et de l'or</li>
320
+ <li>Trouvez l'escalier pour descendre au niveau suivant</li>
321
+ <li>Ramassez des objets et équipez-vous pour devenir plus fort</li>
322
+ <li>Les potions restaurent votre santé ou votre mana</li>
323
+ <li>Les parchemins contiennent des sorts que vous pouvez apprendre</li>
324
+ </ul>
325
+ </div>
326
+
327
+ <div>
328
+ <h3 class="text-xl font-semibold mb-2">Types d'objets</h3>
329
+ <div class="grid grid-cols-2 gap-4">
330
+ <div>
331
+ <h4 class="font-semibold">Armes</h4>
332
+ <ul class="list-disc pl-5">
333
+ <li>Dagues</li>
334
+ <li>Épées</li>
335
+ <li>Haches</li>
336
+ <li>Masses</li>
337
+ <li>Bâtons</li>
338
+ </ul>
339
+ </div>
340
+ <div>
341
+ <h4 class="font-semibold">Armures</h4>
342
+ <ul class="list-disc pl-5">
343
+ <li>Armures de cuir</li>
344
+ <li>Cottes de mailles</li>
345
+ <li>Armures de plaques</li>
346
+ <li>Boucliers</li>
347
+ </ul>
348
+ </div>
349
+ <div>
350
+ <h4 class="font-semibold">Objets magiques</h4>
351
+ <ul class="list-disc pl-5">
352
+ <li>Anneaux</li>
353
+ <li>Amulettes</li>
354
+ <li>Parchemins</li>
355
+ <li>Baguettes</li>
356
+ </ul>
357
+ </div>
358
+ <div>
359
+ <h4 class="font-semibold">Consommables</h4>
360
+ <ul class="list-disc pl-5">
361
+ <li>Potions de santé</li>
362
+ <li>Potions de mana</li>
363
+ <li>Potions de force</li>
364
+ <li>Parchemins de téléportation</li>
365
+ </ul>
366
+ </div>
367
+ </div>
368
+ </div>
369
+ </div>
370
+ </div>
371
+ </div>
372
+
373
+ <!-- Tooltip -->
374
+ <div id="tooltip" class="tooltip"></div>
375
+
376
+ <script>
377
+ // Game Constants
378
+ const DUNGEON_SIZE = 25;
379
+ const VISIBILITY_RADIUS = 5;
380
+ const CELL_SIZE = 25;
381
+
382
+ // Game State
383
+ let gameState = {
384
+ player: {
385
+ x: 0,
386
+ y: 0,
387
+ health: 100,
388
+ maxHealth: 100,
389
+ mana: 50,
390
+ maxMana: 50,
391
+ level: 1,
392
+ xp: 0,
393
+ xpToNextLevel: 100,
394
+ attack: 5,
395
+ defense: 3,
396
+ magic: 4,
397
+ gold: 0,
398
+ inventory: [],
399
+ equipment: {
400
+ weapon: null,
401
+ armor: null,
402
+ ring: null,
403
+ amulet: null
404
+ },
405
+ knownSpells: []
406
+ },
407
+ dungeon: {
408
+ level: 1,
409
+ map: [],
410
+ items: [],
411
+ enemies: [],
412
+ stairs: { x: 0, y: 0 }
413
+ },
414
+ gameActive: false
415
+ };
416
+
417
+ // Item Database
418
+ const itemsDB = {
419
+ weapons: [
420
+ { id: 'dagger', name: 'Dague', type: 'weapon', attack: 3, speed: 2, value: 10 },
421
+ { id: 'short_sword', name: 'Épée courte', type: 'weapon', attack: 5, speed: 1, value: 25 },
422
+ { id: 'long_sword', name: 'Épée longue', type: 'weapon', attack: 7, speed: 0, value: 50 },
423
+ { id: 'great_sword', name: 'Épée à deux mains', type: 'weapon', attack: 10, speed: -1, value: 120 },
424
+ { id: 'battle_axe', name: 'Hache de guerre', type: 'weapon', attack: 9, speed: -1, value: 80 },
425
+ { id: 'mace', name: 'Masse d\'arme', type: 'weapon', attack: 8, armorPen: 2, speed: -2, value: 70 },
426
+ { id: 'bow', name: 'Arc', type: 'weapon', attack: 4, range: 3, speed: 1, value: 60 },
427
+ { id: 'crossbow', name: 'Arbalète', type: 'weapon', attack: 6, range: 4, speed: -1, value: 90 },
428
+ { id: 'staff', name: 'Bâton', type: 'weapon', attack: 2, magic: 3, speed: 1, value: 15 },
429
+ { id: 'rapier', name: 'Rapière', type: 'weapon', attack: 4, speed: 3, crit: 10, value: 45 }
430
+ ],
431
+ armors: [
432
+ { id: 'leather_armor', name: 'Armure de cuir', type: 'armor', defense: 2, value: 20 },
433
+ { id: 'chain_mail', name: 'Cotte de mailles', type: 'armor', defense: 4, value: 60 },
434
+ { id: 'plate_armor', name: 'Armure de plaques', type: 'armor', defense: 6, value: 120 }
435
+ ],
436
+ rings: [
437
+ { id: 'ring_attack', name: 'Anneau d\'attaque', type: 'ring', attack: 1, value: 50 },
438
+ { id: 'ring_defense', name: 'Anneau de défense', type: 'ring', defense: 1, value: 50 },
439
+ { id: 'ring_magic', name: 'Anneau de magie', type: 'ring', magic: 2, value: 75 }
440
+ ],
441
+ amulets: [
442
+ { id: 'amulet_health', name: 'Amulette de santé', type: 'amulet', maxHealth: 20, value: 100 },
443
+ { id: 'amulet_mana', name: 'Amulette de mana', type: 'amulet', maxMana: 15, value: 100 }
444
+ ],
445
+ potions: [
446
+ { id: 'health_potion', name: 'Potion de santé', type: 'potion', health: 30, value: 20 },
447
+ { id: 'mana_potion', name: 'Potion de mana', type: 'potion', mana: 20, value: 25 },
448
+ { id: 'strength_potion', name: 'Potion de force', type: 'potion', attack: 3, duration: 10, value: 40 }
449
+ ],
450
+ scrolls: [
451
+ { id: 'fireball_scroll', name: 'Parchemin de boule de feu', type: 'scroll', spell: 'fireball', value: 50 },
452
+ { id: 'heal_scroll', name: 'Parchemin de soins', type: 'scroll', spell: 'heal', value: 60 },
453
+ { id: 'teleport_scroll', name: 'Parchemin de téléportation', type: 'scroll', spell: 'teleport', value: 75 }
454
+ ]
455
+ };
456
+
457
+ // Enemy Database
458
+ const enemiesDB = [
459
+ { id: 'goblin', name: 'Gobelin', health: 15, attack: 3, defense: 1, xp: 20, gold: 5, sprite: '🐸' },
460
+ { id: 'skeleton', name: 'Squelette', health: 20, attack: 4, defense: 2, xp: 30, gold: 10, sprite: '💀' },
461
+ { id: 'orc', name: 'Orc', health: 30, attack: 6, defense: 3, xp: 50, gold: 20, sprite: '👹' },
462
+ { id: 'troll', name: 'Troll', health: 50, attack: 8, defense: 5, xp: 80, gold: 40, sprite: '👺' },
463
+ { id: 'ghost', name: 'Fantôme', health: 25, attack: 5, defense: 0, magic: 5, xp: 60, gold: 30, sprite: '👻' },
464
+ { id: 'spider', name: 'Araignée géante', health: 18, attack: 5, defense: 1, speed: 2, xp: 35, gold: 15, sprite: '🕷️' },
465
+ { id: 'bat', name: 'Chauve-souris vampirique', health: 12, attack: 4, lifesteal: 0.5, xp: 25, gold: 10, sprite: '🦇' },
466
+ { id: 'slime', name: 'Gelée', health: 40, attack: 3, defense: 0, split: true, xp: 45, gold: 20, sprite: '🟢' },
467
+ { id: 'knight', name: 'Chevalier maudit', health: 60, attack: 7, defense: 6, xp: 100, gold: 50, sprite: '🤴' },
468
+ { id: 'dragon', name: 'Dragonnet', health: 80, attack: 10, defense: 4, breath: 8, xp: 150, gold: 100, sprite: '🐲' }
469
+ ];
470
+
471
+ // Spells Database
472
+ const spellsDB = {
473
+ fireball: {
474
+ name: 'Boule de feu',
475
+ manaCost: 10,
476
+ range: 3,
477
+ damage: 8,
478
+ description: 'Inflige des dégâts de feu à un ennemi à distance'
479
+ },
480
+ heal: {
481
+ name: 'Soins',
482
+ manaCost: 15,
483
+ health: 20,
484
+ description: 'Restaure une partie de votre santé'
485
+ },
486
+ teleport: {
487
+ name: 'Téléportation',
488
+ manaCost: 20,
489
+ description: 'Vous téléporte à un endroit aléatoire du niveau actuel'
490
+ }
491
+ };
492
+
493
+ // Initialize the game
494
+ function initGame() {
495
+ gameState.gameActive = true;
496
+ gameState.player = {
497
+ x: 0,
498
+ y: 0,
499
+ health: 100,
500
+ maxHealth: 100,
501
+ mana: 50,
502
+ maxMana: 50,
503
+ level: 1,
504
+ xp: 0,
505
+ xpToNextLevel: 100,
506
+ attack: 5,
507
+ defense: 3,
508
+ magic: 4,
509
+ gold: 0,
510
+ inventory: [],
511
+ equipment: {
512
+ weapon: null,
513
+ armor: null,
514
+ ring: null,
515
+ amulet: null
516
+ },
517
+ knownSpells: []
518
+ };
519
+
520
+ generateDungeon(1);
521
+ updateUI();
522
+ addLogMessage("Nouvelle partie commencée! Explorez le donjon.");
523
+ }
524
+
525
+ // Generate a procedural dungeon
526
+ function generateDungeon(level) {
527
+ gameState.dungeon.level = level;
528
+ gameState.dungeon.map = [];
529
+ gameState.dungeon.items = [];
530
+ gameState.dungeon.enemies = [];
531
+
532
+ // Create empty map filled with walls
533
+ for (let y = 0; y < DUNGEON_SIZE; y++) {
534
+ let row = [];
535
+ for (let x = 0; x < DUNGEON_SIZE; x++) {
536
+ row.push(1); // 1 = wall, 0 = floor
537
+ }
538
+ gameState.dungeon.map.push(row);
539
+ }
540
+
541
+ // Generate rooms and corridors
542
+ generateRoomsAndCorridors();
543
+
544
+ // Place player in a random room
545
+ placePlayer();
546
+
547
+ // Place stairs
548
+ placeStairs();
549
+
550
+ // Place enemies
551
+ placeEnemies(level);
552
+
553
+ // Place items
554
+ placeItems(level);
555
+
556
+ // Render dungeon
557
+ renderDungeon();
558
+ }
559
+
560
+ function generateRoomsAndCorridors() {
561
+ const roomCount = 5 + Math.floor(Math.random() * 5);
562
+ const rooms = [];
563
+
564
+ for (let i = 0; i < roomCount; i++) {
565
+ const width = 3 + Math.floor(Math.random() * 5);
566
+ const height = 3 + Math.floor(Math.random() * 5);
567
+ const x = 1 + Math.floor(Math.random() * (DUNGEON_SIZE - width - 2));
568
+ const y = 1 + Math.floor(Math.random() * (DUNGEON_SIZE - height - 2));
569
+
570
+ const newRoom = { x, y, width, height };
571
+ let failed = false;
572
+
573
+ for (const room of rooms) {
574
+ if (roomsIntersect(newRoom, room)) {
575
+ failed = true;
576
+ break;
577
+ }
578
+ }
579
+
580
+ if (!failed) {
581
+ createRoom(newRoom);
582
+ rooms.push(newRoom);
583
+
584
+ // Connect to previous room with corridor
585
+ if (rooms.length > 1) {
586
+ const prevRoom = rooms[rooms.length - 2];
587
+ connectRooms(prevRoom, newRoom);
588
+ }
589
+ }
590
+ }
591
+ }
592
+
593
+ function roomsIntersect(room1, room2) {
594
+ return (
595
+ room1.x <= room2.x + room2.width &&
596
+ room1.x + room1.width >= room2.x &&
597
+ room1.y <= room2.y + room2.height &&
598
+ room1.y + room1.height >= room2.y
599
+ );
600
+ }
601
+
602
+ function createRoom(room) {
603
+ for (let y = room.y; y < room.y + room.height; y++) {
604
+ for (let x = room.x; x < room.x + room.width; x++) {
605
+ gameState.dungeon.map[y][x] = 0; // Floor
606
+ }
607
+ }
608
+ }
609
+
610
+ function connectRooms(room1, room2) {
611
+ const x1 = room1.x + Math.floor(room1.width / 2);
612
+ const y1 = room1.y + Math.floor(room1.height / 2);
613
+ const x2 = room2.x + Math.floor(room2.width / 2);
614
+ const y2 = room2.y + Math.floor(room2.height / 2);
615
+
616
+ // Horizontal then vertical
617
+ if (Math.random() < 0.5) {
618
+ createHTunnel(x1, x2, y1);
619
+ createVTunnel(y1, y2, x2);
620
+ } else { // Vertical then horizontal
621
+ createVTunnel(y1, y2, x1);
622
+ createHTunnel(x1, x2, y2);
623
+ }
624
+ }
625
+
626
+ function createHTunnel(x1, x2, y) {
627
+ for (let x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) {
628
+ gameState.dungeon.map[y][x] = 0;
629
+ }
630
+ }
631
+
632
+ function createVTunnel(y1, y2, x) {
633
+ for (let y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) {
634
+ gameState.dungeon.map[y][x] = 0;
635
+ }
636
+ }
637
+
638
+ function placePlayer() {
639
+ // Find all floor tiles
640
+ const floors = [];
641
+ for (let y = 0; y < DUNGEON_SIZE; y++) {
642
+ for (let x = 0; x < DUNGEON_SIZE; x++) {
643
+ if (gameState.dungeon.map[y][x] === 0) {
644
+ floors.push({ x, y });
645
+ }
646
+ }
647
+ }
648
+
649
+ // Place player on random floor tile
650
+ if (floors.length > 0) {
651
+ const startPos = floors[Math.floor(Math.random() * floors.length)];
652
+ gameState.player.x = startPos.x;
653
+ gameState.player.y = startPos.y;
654
+ }
655
+ }
656
+
657
+ function placeStairs() {
658
+ // Find all floor tiles far from player
659
+ const floors = [];
660
+ for (let y = 0; y < DUNGEON_SIZE; y++) {
661
+ for (let x = 0; x < DUNGEON_SIZE; x++) {
662
+ if (gameState.dungeon.map[y][x] === 0) {
663
+ const dist = Math.sqrt(Math.pow(x - gameState.player.x, 2) + Math.pow(y - gameState.player.y, 2));
664
+ if (dist > DUNGEON_SIZE / 2) {
665
+ floors.push({ x, y });
666
+ }
667
+ }
668
+ }
669
+ }
670
+
671
+ // Place stairs on random floor tile
672
+ if (floors.length > 0) {
673
+ const stairsPos = floors[Math.floor(Math.random() * floors.length)];
674
+ gameState.dungeon.stairs = { x: stairsPos.x, y: stairsPos.y };
675
+ }
676
+ }
677
+
678
+ function placeEnemies(level) {
679
+ const enemyCount = 5 + Math.floor(level * 1.5);
680
+
681
+ for (let i = 0; i < enemyCount; i++) {
682
+ // Find random floor tile not occupied by player or stairs
683
+ let x, y;
684
+ do {
685
+ x = Math.floor(Math.random() * DUNGEON_SIZE);
686
+ y = Math.floor(Math.random() * DUNGEON_SIZE);
687
+ } while (
688
+ gameState.dungeon.map[y][x] !== 0 ||
689
+ (x === gameState.player.x && y === gameState.player.y) ||
690
+ (x === gameState.dungeon.stairs.x && y === gameState.dungeon.stairs.y)
691
+ );
692
+
693
+ // Choose enemy type based on level
694
+ let enemyTypes = enemiesDB;
695
+ if (level < 3) enemyTypes = enemiesDB.slice(0, 2);
696
+ else if (level < 5) enemyTypes = enemiesDB.slice(0, 3);
697
+ else if (level < 7) enemyTypes = enemiesDB.slice(0, 4);
698
+
699
+ const enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
700
+ const enemy = {
701
+ ...enemyType,
702
+ x,
703
+ y,
704
+ currentHealth: enemyType.health,
705
+ id: `enemy_${i}`
706
+ };
707
+
708
+ gameState.dungeon.enemies.push(enemy);
709
+ }
710
+ }
711
+
712
+ function placeItems(level) {
713
+ const itemCount = 3 + Math.floor(level * 0.8);
714
+
715
+ for (let i = 0; i < itemCount; i++) {
716
+ // Find random floor tile not occupied by player, stairs or enemies
717
+ let x, y;
718
+ do {
719
+ x = Math.floor(Math.random() * DUNGEON_SIZE);
720
+ y = Math.floor(Math.random() * DUNGEON_SIZE);
721
+ } while (
722
+ gameState.dungeon.map[y][x] !== 0 ||
723
+ (x === gameState.player.x && y === gameState.player.y) ||
724
+ (x === gameState.dungeon.stairs.x && y === gameState.dungeon.stairs.y) ||
725
+ gameState.dungeon.enemies.some(e => e.x === x && e.y === y)
726
+ );
727
+
728
+ // Choose item type based on level
729
+ let itemPool = [];
730
+
731
+ // Always include potions
732
+ itemPool = itemPool.concat(itemsDB.potions);
733
+
734
+ // Add weapons and armors
735
+ if (level >= 2) itemPool = itemPool.concat(itemsDB.weapons.slice(0, 2));
736
+ if (level >= 3) itemPool = itemPool.concat(itemsDB.armors.slice(0, 1));
737
+ if (level >= 4) itemPool = itemPool.concat(itemsDB.weapons.slice(2, 4));
738
+ if (level >= 5) itemPool = itemPool.concat(itemsDB.armors.slice(1, 2));
739
+ if (level >= 6) itemPool = itemPool.concat(itemsDB.rings);
740
+ if (level >= 7) itemPool = itemPool.concat(itemsDB.amulets);
741
+ if (level >= 8) itemPool = itemPool.concat(itemsDB.scrolls);
742
+
743
+ const itemType = itemPool[Math.floor(Math.random() * itemPool.length)];
744
+ const item = {
745
+ ...itemType,
746
+ x,
747
+ y,
748
+ id: `item_${i}`
749
+ };
750
+
751
+ gameState.dungeon.items.push(item);
752
+ }
753
+ }
754
+
755
+ // Render the dungeon
756
+ function renderDungeon() {
757
+ const dungeonElement = document.getElementById('dungeon');
758
+ dungeonElement.innerHTML = '';
759
+
760
+ dungeonElement.style.display = 'grid';
761
+ dungeonElement.style.gridTemplateColumns = `repeat(${DUNGEON_SIZE}, ${CELL_SIZE}px)`;
762
+ dungeonElement.style.gridTemplateRows = `repeat(${DUNGEON_SIZE}, ${CELL_SIZE}px)`;
763
+ dungeonElement.style.gap = '1px';
764
+
765
+ for (let y = 0; y < DUNGEON_SIZE; y++) {
766
+ for (let x = 0; x < DUNGEON_SIZE; x++) {
767
+ const cell = document.createElement('div');
768
+ cell.className = 'dungeon-cell';
769
+ cell.dataset.x = x;
770
+ cell.dataset.y = y;
771
+
772
+ // Check visibility
773
+ const distance = Math.sqrt(Math.pow(x - gameState.player.x, 2) + Math.pow(y - gameState.player.y, 2));
774
+ const isVisible = distance <= VISIBILITY_RADIUS;
775
+
776
+ if (gameState.dungeon.map[y][x] === 1) {
777
+ cell.classList.add('wall');
778
+ } else {
779
+ cell.classList.add('floor');
780
+
781
+ // Check if cell is in fog of war
782
+ if (!isVisible) {
783
+ cell.classList.add('fog');
784
+ }
785
+ }
786
+
787
+ // Add entities if visible
788
+ if (isVisible) {
789
+ // Check for player
790
+ if (x === gameState.player.x && y === gameState.player.y) {
791
+ cell.classList.add('player');
792
+ cell.title = 'Vous';
793
+ cell.textContent = '🧙';
794
+
795
+ // Add health bar above player
796
+ const healthBar = document.createElement('div');
797
+ healthBar.className = 'absolute -top-1 left-0 right-0 h-1 bg-gray-700 rounded-full';
798
+ healthBar.style.width = '100%';
799
+ cell.appendChild(healthBar);
800
+
801
+ const healthFill = document.createElement('div');
802
+ healthFill.className = 'h-full rounded-full bg-red-500';
803
+ healthFill.style.width = `${(gameState.player.health / gameState.player.maxHealth) * 100}%`;
804
+ healthBar.appendChild(healthFill);
805
+ }
806
+
807
+ // Check for stairs
808
+ else if (x === gameState.dungeon.stairs.x && y === gameState.dungeon.stairs.y) {
809
+ cell.classList.add('exit');
810
+ cell.title = 'Escalier vers le bas';
811
+ cell.textContent = '↓';
812
+ }
813
+
814
+ // Check for enemies
815
+ else {
816
+ const enemy = gameState.dungeon.enemies.find(e => e.x === x && e.y === y);
817
+ if (enemy) {
818
+ cell.classList.add('enemy');
819
+ cell.title = `${enemy.name} (${enemy.currentHealth}/${enemy.health})`;
820
+ cell.textContent = enemy.sprite || '👹';
821
+ }
822
+
823
+ // Check for items
824
+ else {
825
+ const item = gameState.dungeon.items.find(i => i.x === x && i.y === y);
826
+ if (item) {
827
+ cell.classList.add('item');
828
+ cell.title = item.name;
829
+ }
830
+ }
831
+ }
832
+ }
833
+
834
+ dungeonElement.appendChild(cell);
835
+ }
836
+ }
837
+
838
+ // Update dungeon level display
839
+ document.getElementById('dungeon-level').textContent = gameState.dungeon.level;
840
+ }
841
+
842
+ // Update UI elements
843
+ function updateUI() {
844
+ // Player stats
845
+ document.getElementById('health-value').textContent = `${gameState.player.health}/${gameState.player.maxHealth}`;
846
+ document.getElementById('mana-value').textContent = `${gameState.player.mana}/${gameState.player.maxMana}`;
847
+ document.getElementById('health-bar').style.width = `${(gameState.player.health / gameState.player.maxHealth) * 100}%`;
848
+ document.getElementById('mana-bar').style.width = `${(gameState.player.mana / gameState.player.maxMana) * 100}%`;
849
+
850
+ // Player attributes
851
+ document.getElementById('player-level').textContent = gameState.player.level;
852
+ document.getElementById('player-xp').textContent = `${gameState.player.xp}/${gameState.player.xpToNextLevel}`;
853
+
854
+ // Calculate total attack and defense including equipment
855
+ let totalAttack = gameState.player.attack;
856
+ let totalDefense = gameState.player.defense;
857
+ let totalMagic = gameState.player.magic;
858
+
859
+ if (gameState.player.equipment.weapon) {
860
+ totalAttack += gameState.player.equipment.weapon.attack || 0;
861
+ totalMagic += gameState.player.equipment.weapon.magic || 0;
862
+ }
863
+
864
+ if (gameState.player.equipment.armor) {
865
+ totalDefense += gameState.player.equipment.armor.defense || 0;
866
+ }
867
+
868
+ if (gameState.player.equipment.ring) {
869
+ totalAttack += gameState.player.equipment.ring.attack || 0;
870
+ totalDefense += gameState.player.equipment.ring.defense || 0;
871
+ totalMagic += gameState.player.equipment.ring.magic || 0;
872
+ }
873
+
874
+ if (gameState.player.equipment.amulet) {
875
+ totalAttack += gameState.player.equipment.amulet.attack || 0;
876
+ totalDefense += gameState.player.equipment.amulet.defense || 0;
877
+ totalMagic += gameState.player.equipment.amulet.magic || 0;
878
+ }
879
+
880
+ document.getElementById('player-attack').textContent = totalAttack;
881
+
882
+ // Calculate and show attack power from weapon
883
+ let attackPower = 0;
884
+ if (gameState.player.equipment.weapon) {
885
+ attackPower = gameState.player.equipment.weapon.attack || 0;
886
+ }
887
+ const attackPowerElement = document.getElementById('attack-power');
888
+ attackPowerElement.textContent = `+${attackPower}`;
889
+ attackPowerElement.title = `Puissance d'attaque: ${attackPower} (${gameState.player.equipment.weapon?.name || 'Aucune arme'})`;
890
+ document.getElementById('player-defense').textContent = totalDefense;
891
+ document.getElementById('player-magic').textContent = totalMagic;
892
+ document.getElementById('player-gold').textContent = gameState.player.gold;
893
+
894
+ // Equipment
895
+ document.getElementById('equip-weapon').textContent = gameState.player.equipment.weapon ? gameState.player.equipment.weapon.name : 'Poings';
896
+ document.getElementById('equip-armor').textContent = gameState.player.equipment.armor ? gameState.player.equipment.armor.name : 'Vêtements';
897
+ document.getElementById('equip-ring').textContent = gameState.player.equipment.ring ? gameState.player.equipment.ring.name : '-';
898
+ document.getElementById('equip-amulet').textContent = gameState.player.equipment.amulet ? gameState.player.equipment.amulet.name : '-';
899
+
900
+ // Inventory
901
+ const inventoryElement = document.getElementById('inventory');
902
+ inventoryElement.innerHTML = '';
903
+
904
+ for (let i = 0; i < 8; i++) {
905
+ const slot = document.createElement('div');
906
+ slot.className = 'inventory-item bg-gray-700 aspect-square rounded flex items-center justify-center text-xs text-center p-1';
907
+
908
+ if (i < gameState.player.inventory.length) {
909
+ const item = gameState.player.inventory[i];
910
+ slot.textContent = item.name;
911
+ slot.title = getItemDescription(item);
912
+
913
+ // Add click handler for using/equipping items
914
+ slot.addEventListener('click', () => handleItemClick(item));
915
+ } else {
916
+ slot.textContent = 'Vide';
917
+ }
918
+
919
+ inventoryElement.appendChild(slot);
920
+ }
921
+ }
922
+
923
+ function getItemDescription(item) {
924
+ let desc = item.name + '\n';
925
+
926
+ if (item.type === 'weapon') {
927
+ if (item.attack) desc += `Attaque: +${item.attack}\n`;
928
+ if (item.magic) desc += `Magie: +${item.magic}\n`;
929
+ } else if (item.type === 'armor') {
930
+ if (item.defense) desc += `Défense: +${item.defense}\n`;
931
+ } else if (item.type === 'ring' || item.type === 'amulet') {
932
+ if (item.attack) desc += `Attaque: +${item.attack}\n`;
933
+ if (item.defense) desc += `Défense: +${item.defense}\n`;
934
+ if (item.magic) desc += `Magie: +${item.magic}\n`;
935
+ if (item.maxHealth) desc += `Santé max: +${item.maxHealth}\n`;
936
+ if (item.maxMana) desc += `Mana max: +${item.maxMana}\n`;
937
+ } else if (item.type === 'potion') {
938
+ if (item.health) desc += `Restaure ${item.health} points de santé\n`;
939
+ if (item.mana) desc += `Restaure ${item.mana} points de mana\n`;
940
+ if (item.attack) desc += `+${item.attack} attaque pour ${item.duration} tours\n`;
941
+ } else if (item.type === 'scroll') {
942
+ desc += `Enseigne le sort: ${spellsDB[item.spell].name}\n`;
943
+ desc += spellsDB[item.spell].description + '\n';
944
+ }
945
+
946
+ desc += `Valeur: ${item.value} pièces d'or`;
947
+ return desc;
948
+ }
949
+
950
+ function handleItemClick(item) {
951
+ if (item.type === 'weapon' || item.type === 'armor' || item.type === 'ring' || item.type === 'amulet') {
952
+ equipItem(item);
953
+ } else if (item.type === 'potion' || item.type === 'scroll') {
954
+ useItem(item);
955
+ }
956
+ }
957
+
958
+ function equipItem(item) {
959
+ const slot = item.type;
960
+
961
+ // Unequip current item if any
962
+ if (gameState.player.equipment[slot]) {
963
+ gameState.player.inventory.push(gameState.player.equipment[slot]);
964
+ }
965
+
966
+ // Equip new item
967
+ gameState.player.equipment[slot] = item;
968
+
969
+ // Remove from inventory
970
+ const itemIndex = gameState.player.inventory.findIndex(i => i.id === item.id);
971
+ if (itemIndex !== -1) {
972
+ gameState.player.inventory.splice(itemIndex, 1);
973
+ }
974
+
975
+ // Update stats if item affects max health or mana
976
+ if (slot === 'amulet') {
977
+ if (item.maxHealth) {
978
+ gameState.player.maxHealth += item.maxHealth;
979
+ gameState.player.health = Math.min(gameState.player.health, gameState.player.maxHealth);
980
+ }
981
+ if (item.maxMana) {
982
+ gameState.player.maxMana += item.maxMana;
983
+ gameState.player.mana = Math.min(gameState.player.mana, gameState.player.maxMana);
984
+ }
985
+ }
986
+
987
+ updateUI();
988
+ addLogMessage(`Vous avez équipé: ${item.name}`);
989
+ }
990
+
991
+ function useItem(item) {
992
+ if (item.type === 'potion') {
993
+ if (item.health) {
994
+ gameState.player.health = Math.min(gameState.player.health + item.health, gameState.player.maxHealth);
995
+ addLogMessage(`Vous avez utilisé ${item.name} et récupéré ${item.health} points de santé.`);
996
+ }
997
+ if (item.mana) {
998
+ gameState.player.mana = Math.min(gameState.player.mana + item.mana, gameState.player.maxMana);
999
+ addLogMessage(`Vous avez utilisé ${item.name} et récupéré ${item.mana} points de mana.`);
1000
+ }
1001
+ } else if (item.type === 'scroll') {
1002
+ if (!gameState.player.knownSpells.includes(item.spell)) {
1003
+ gameState.player.knownSpells.push(item.spell);
1004
+ addLogMessage(`Vous avez appris le sort: ${spellsDB[item.spell].name}!`);
1005
+ } else {
1006
+ addLogMessage(`Vous connaissez déjà ce sort.`);
1007
+ }
1008
+ }
1009
+
1010
+ // Remove from inventory
1011
+ const itemIndex = gameState.player.inventory.findIndex(i => i.id === item.id);
1012
+ if (itemIndex !== -1) {
1013
+ gameState.player.inventory.splice(itemIndex, 1);
1014
+ }
1015
+
1016
+ updateUI();
1017
+ }
1018
+
1019
+ function addLogMessage(message) {
1020
+ const logElement = document.getElementById('combat-log');
1021
+ const messageElement = document.createElement('div');
1022
+ messageElement.textContent = message;
1023
+ logElement.appendChild(messageElement);
1024
+ logElement.scrollTop = logElement.scrollHeight;
1025
+ }
1026
+
1027
+ function showDamagePopup(x, y, amount, isCritical = false) {
1028
+ const dungeonElement = document.getElementById('dungeon');
1029
+ const cell = dungeonElement.querySelector(`[data-x="${x}"][data-y="${y}"]`);
1030
+
1031
+ if (cell) {
1032
+ const popup = document.createElement('div');
1033
+ popup.className = 'damage-popup';
1034
+ popup.textContent = amount;
1035
+ popup.style.color = isCritical ? '#ff5555' : '#ffffff';
1036
+ popup.style.left = `${cell.offsetLeft + CELL_SIZE / 2}px`;
1037
+ popup.style.top = `${cell.offsetTop}px`;
1038
+
1039
+ dungeonElement.appendChild(popup);
1040
+
1041
+ setTimeout(() => {
1042
+ popup.remove();
1043
+ }, 1000);
1044
+ }
1045
+ }
1046
+
1047
+ // Handle player movement
1048
+ function movePlayer(dx, dy) {
1049
+ if (!gameState.gameActive) return;
1050
+
1051
+ const newX = gameState.player.x + dx;
1052
+ const newY = gameState.player.y + dy;
1053
+
1054
+ // Check bounds
1055
+ if (newX < 0 || newX >= DUNGEON_SIZE || newY < 0 || newY >= DUNGEON_SIZE) {
1056
+ return;
1057
+ }
1058
+
1059
+ // Check if target is a wall
1060
+ if (gameState.dungeon.map[newY][newX] === 1) {
1061
+ return;
1062
+ }
1063
+
1064
+ // Check for enemies
1065
+ const enemy = gameState.dungeon.enemies.find(e => e.x === newX && e.y === newY);
1066
+ if (enemy) {
1067
+ attackEnemy(enemy);
1068
+ return;
1069
+ }
1070
+
1071
+ // Check for items
1072
+ const itemIndex = gameState.dungeon.items.findIndex(i => i.x === newX && i.y === newY);
1073
+ if (itemIndex !== -1) {
1074
+ const item = gameState.dungeon.items[itemIndex];
1075
+ gameState.player.inventory.push(item);
1076
+ gameState.dungeon.items.splice(itemIndex, 1);
1077
+ addLogMessage(`Vous avez ramassé: ${item.name}`);
1078
+ }
1079
+
1080
+ // Check for stairs
1081
+ if (newX === gameState.dungeon.stairs.x && newY === gameState.dungeon.stairs.y) {
1082
+ nextLevel();
1083
+ return;
1084
+ }
1085
+
1086
+ // Move player
1087
+ gameState.player.x = newX;
1088
+ gameState.player.y = newY;
1089
+
1090
+ // Enemy turn
1091
+ moveEnemies();
1092
+
1093
+ renderDungeon();
1094
+ updateUI();
1095
+ }
1096
+
1097
+ function attackEnemy(enemy) {
1098
+ // Calculate player attack
1099
+ let playerAttack = gameState.player.attack;
1100
+ if (gameState.player.equipment.weapon) {
1101
+ playerAttack += gameState.player.equipment.weapon.attack || 0;
1102
+ }
1103
+
1104
+ // Calculate damage
1105
+ const damage = Math.max(1, playerAttack - (enemy.defense || 0));
1106
+ enemy.currentHealth -= damage;
1107
+
1108
+ showDamagePopup(enemy.x, enemy.y, damage);
1109
+ addLogMessage(`Vous avez infligé ${damage} dégâts au ${enemy.name}.`);
1110
+
1111
+ // Check if enemy is dead
1112
+ if (enemy.currentHealth <= 0) {
1113
+ const enemyIndex = gameState.dungeon.enemies.findIndex(e => e.id === enemy.id);
1114
+ if (enemyIndex !== -1) {
1115
+ gameState.dungeon.enemies.splice(enemyIndex, 1);
1116
+ gameState.player.xp += enemy.xp;
1117
+ gameState.player.gold += enemy.gold;
1118
+ addLogMessage(`Vous avez tué le ${enemy.name} et gagné ${enemy.xp} XP et ${enemy.gold} pièces d'or!`);
1119
+
1120
+ // 20% chance to drop a weapon
1121
+ if (Math.random() < 0.2) {
1122
+ // Choose a random weapon based on dungeon level
1123
+ let weaponPool = itemsDB.weapons;
1124
+ if (gameState.dungeon.level < 3) weaponPool = weaponPool.slice(0, 3);
1125
+ else if (gameState.dungeon.level < 5) weaponPool = weaponPool.slice(0, 5);
1126
+
1127
+ const weaponType = weaponPool[Math.floor(Math.random() * weaponPool.length)];
1128
+ const weapon = {
1129
+ ...weaponType,
1130
+ x: enemy.x,
1131
+ y: enemy.y,
1132
+ id: `weapon_${Date.now()}`
1133
+ };
1134
+
1135
+ gameState.dungeon.items.push(weapon);
1136
+ addLogMessage(`Le ${enemy.name} a laissé tomber ${weapon.name}!`);
1137
+ }
1138
+
1139
+ // Check if all enemies are dead
1140
+ if (gameState.dungeon.enemies.length === 0) {
1141
+ addLogMessage("Vous avez nettoyé ce niveau! Un nouveau donjon se forme...");
1142
+ generateDungeon(gameState.dungeon.level);
1143
+ }
1144
+
1145
+ // Check for level up
1146
+ checkLevelUp();
1147
+ }
1148
+ } else {
1149
+ // Enemy counterattack
1150
+ const enemyDamage = Math.max(1, enemy.attack - (gameState.player.defense + (gameState.player.equipment.armor ? gameState.player.equipment.armor.defense : 0)));
1151
+ gameState.player.health -= enemyDamage;
1152
+
1153
+ showDamagePopup(gameState.player.x, gameState.player.y, enemyDamage);
1154
+ addLogMessage(`Le ${enemy.name} vous a infligé ${enemyDamage} dégâts.`);
1155
+
1156
+ // Check if player is dead
1157
+ if (gameState.player.health <= 0) {
1158
+ gameOver();
1159
+ return;
1160
+ }
1161
+ }
1162
+
1163
+ renderDungeon();
1164
+ updateUI();
1165
+ }
1166
+
1167
+ function moveEnemies() {
1168
+ const directions = [
1169
+ { dx: 0, dy: -1 }, // Up
1170
+ { dx: 1, dy: 0 }, // Right
1171
+ { dx: 0, dy: 1 }, // Down
1172
+ { dx: -1, dy: 0 } // Left
1173
+ ];
1174
+
1175
+ for (const enemy of gameState.dungeon.enemies) {
1176
+ // Simple AI: move towards player if in line of sight
1177
+ const dx = gameState.player.x - enemy.x;
1178
+ const dy = gameState.player.y - enemy.y;
1179
+
1180
+ // Try to move in the general direction of the player
1181
+ let moveDir;
1182
+ if (Math.abs(dx) > Math.abs(dy)) {
1183
+ moveDir = dx > 0 ? directions[1] : directions[3];
1184
+ } else {
1185
+ moveDir = dy > 0 ? directions[2] : directions[0];
1186
+ }
1187
+
1188
+ const newX = enemy.x + moveDir.dx;
1189
+ const newY = enemy.y + moveDir.dy;
1190
+
1191
+ // Check if move is valid
1192
+ if (newX >= 0 && newX < DUNGEON_SIZE && newY >= 0 && newY < DUNGEON_SIZE &&
1193
+ gameState.dungeon.map[newY][newX] === 0) {
1194
+
1195
+ // Check if target cell is occupied by another enemy
1196
+ const otherEnemy = gameState.dungeon.enemies.find(e => e.x === newX && e.y === newY);
1197
+ if (!otherEnemy) {
1198
+ enemy.x = newX;
1199
+ enemy.y = newY;
1200
+ }
1201
+ }
1202
+ }
1203
+ }
1204
+
1205
+ function checkLevelUp() {
1206
+ if (gameState.player.xp >= gameState.player.xpToNextLevel) {
1207
+ gameState.player.level++;
1208
+ gameState.player.xp -= gameState.player.xpToNextLevel;
1209
+ gameState.player.xpToNextLevel = Math.floor(gameState.player.xpToNextLevel * 1.5);
1210
+
1211
+ // Increase stats and choose a perk
1212
+ gameState.player.maxHealth += 10 + Math.floor(gameState.player.level/2);
1213
+ gameState.player.health = gameState.player.maxHealth;
1214
+ gameState.player.maxMana += 5 + Math.floor(gameState.player.level/3);
1215
+ gameState.player.mana = gameState.player.maxMana;
1216
+
1217
+ // Choose random perk
1218
+ const perks = [
1219
+ { stat: 'attack', amount: 2, message: '+2 Attaque' },
1220
+ { stat: 'defense', amount: 2, message: '+2 Défense' },
1221
+ { stat: 'magic', amount: 2, message: '+2 Magie' },
1222
+ { stat: 'crit', amount: 5, message: '+5% Chance de Critique' },
1223
+ { stat: 'dodge', amount: 5, message: '+5% Esquive' },
1224
+ { stat: 'lifesteal', amount: 5, message: '+5% Vol de vie' }
1225
+ ];
1226
+
1227
+ const chosenPerk = perks[Math.floor(Math.random() * perks.length)];
1228
+ gameState.player[chosenPerk.stat] = (gameState.player[chosenPerk.stat] || 0) + chosenPerk.amount;
1229
+
1230
+ addLogMessage(`Perk obtenu: ${chosenPerk.message}`);
1231
+
1232
+ addLogMessage(`Félicitations! Vous avez atteint le niveau ${gameState.player.level}!`);
1233
+ updateUI();
1234
+ }
1235
+ }
1236
+
1237
+ function nextLevel() {
1238
+ gameState.dungeon.level++;
1239
+ generateDungeon(gameState.dungeon.level);
1240
+ addLogMessage(`Vous descendez au niveau ${gameState.dungeon.level} du donjon...`);
1241
+ updateUI();
1242
+ }
1243
+
1244
+ function gameOver() {
1245
+ gameState.gameActive = false;
1246
+ addLogMessage(`Vous êtes mort... Game Over!`);
1247
+ document.getElementById('player-status').textContent = 'Mort';
1248
+ document.getElementById('player-status').classList.add('text-red-500');
1249
+ document.getElementById('player-status').classList.remove('text-yellow-400');
1250
+ }
1251
+
1252
+ // Event listeners
1253
+ document.addEventListener('keydown', (e) => {
1254
+ if (!gameState.gameActive) return;
1255
+
1256
+ switch (e.key) {
1257
+ case 'ArrowUp':
1258
+ case 'z':
1259
+ case 'Z':
1260
+ movePlayer(0, -1);
1261
+ break;
1262
+ case 'ArrowRight':
1263
+ case 'd':
1264
+ case 'D':
1265
+ movePlayer(1, 0);
1266
+ break;
1267
+ case 'ArrowDown':
1268
+ case 's':
1269
+ case 'S':
1270
+ movePlayer(0, 1);
1271
+ break;
1272
+ case 'ArrowLeft':
1273
+ case 'q':
1274
+ case 'Q':
1275
+ movePlayer(-1, 0);
1276
+ break;
1277
+ case ' ':
1278
+ // Attack adjacent enemies
1279
+ const directions = [
1280
+ { dx: 0, dy: -1 }, // Up
1281
+ { dx: 1, dy: 0 }, // Right
1282
+ { dx: 0, dy: 1 }, // Down
1283
+ { dx: -1, dy: 0 } // Left
1284
+ ];
1285
+
1286
+ for (const dir of directions) {
1287
+ const enemy = gameState.dungeon.enemies.find(e =>
1288
+ e.x === gameState.player.x + dir.dx &&
1289
+ e.y === gameState.player.y + dir.dy
1290
+ );
1291
+
1292
+ if (enemy) {
1293
+ attackEnemy(enemy);
1294
+ break;
1295
+ }
1296
+ }
1297
+ break;
1298
+ case 'm':
1299
+ case 'M':
1300
+ // Cast spell
1301
+ if (gameState.player.knownSpells.length > 0) {
1302
+ castSpell();
1303
+ } else {
1304
+ addLogMessage("Vous ne connaissez aucun sort!");
1305
+ }
1306
+ break;
1307
+ }
1308
+ });
1309
+
1310
+ function castSpell() {
1311
+ // In a full implementation, this would open a spell selection menu
1312
+ // For now, just cast the first known spell
1313
+ const spellId = gameState.player.knownSpells[0];
1314
+ const spell = spellsDB[spellId];
1315
+
1316
+ if (gameState.player.mana < spell.manaCost) {
1317
+ addLogMessage(`Pas assez de mana pour lancer ${spell.name}!`);
1318
+ return;
1319
+ }
1320
+
1321
+ gameState.player.mana -= spell.manaCost;
1322
+
1323
+ if (spellId === 'fireball') {
1324
+ // Find enemy in range
1325
+ const enemiesInRange = gameState.dungeon.enemies.filter(e => {
1326
+ const dist = Math.sqrt(Math.pow(e.x - gameState.player.x, 2) + Math.pow(e.y - gameState.player.y, 2));
1327
+ return dist <= spell.range;
1328
+ });
1329
+
1330
+ if (enemiesInRange.length > 0) {
1331
+ // Target the closest enemy
1332
+ enemiesInRange.sort((a, b) => {
1333
+ const distA = Math.sqrt(Math.pow(a.x - gameState.player.x, 2) + Math.pow(a.y - gameState.player.y, 2));
1334
+ const distB = Math.sqrt(Math.pow(b.x - gameState.player.x, 2) + Math.pow(b.y - gameState.player.y, 2));
1335
+ return distA - distB;
1336
+ });
1337
+
1338
+ const target = enemiesInRange[0];
1339
+ const damage = spell.damage + Math.floor(gameState.player.magic / 2);
1340
+ target.currentHealth -= damage;
1341
+
1342
+ showDamagePopup(target.x, target.y, damage, true);
1343
+ addLogMessage(`Vous avez lancé ${spell.name} sur ${target.name} et infligé ${damage} dégâts!`);
1344
+
1345
+ // Check if enemy is dead
1346
+ if (target.currentHealth <= 0) {
1347
+ const enemyIndex = gameState.dungeon.enemies.findIndex(e => e.id === target.id);
1348
+ if (enemyIndex !== -1) {
1349
+ gameState.dungeon.enemies.splice(enemyIndex, 1);
1350
+ gameState.player.xp += target.xp;
1351
+ gameState.player.gold += target.gold;
1352
+ addLogMessage(`Vous avez tué le ${target.name} et gagné ${target.xp} XP et ${target.gold} pièces d'or!`);
1353
+
1354
+ // Check for level up
1355
+ checkLevelUp();
1356
+ }
1357
+ }
1358
+ } else {
1359
+ addLogMessage(`Aucun ennemi à portée pour ${spell.name}!`);
1360
+ }
1361
+ } else if (spellId === 'heal') {
1362
+ const healAmount = spell.health + Math.floor(gameState.player.magic / 2);
1363
+ gameState.player.health = Math.min(gameState.player.health + healAmount, gameState.player.maxHealth);
1364
+ addLogMessage(`Vous avez lancé ${spell.name} et récupéré ${healAmount} points de santé.`);
1365
+ } else if (spellId === 'teleport') {
1366
+ // Find all floor tiles
1367
+ const floors = [];
1368
+ for (let y = 0; y < DUNGEON_SIZE; y++) {
1369
+ for (let x = 0; x < DUNGEON_SIZE; x++) {
1370
+ if (gameState.dungeon.map[y][x] === 0 &&
1371
+ !gameState.dungeon.enemies.some(e => e.x === x && e.y === y)) {
1372
+ floors.push({ x, y });
1373
+ }
1374
+ }
1375
+ }
1376
+
1377
+ if (floors.length > 0) {
1378
+ const newPos = floors[Math.floor(Math.random() * floors.length)];
1379
+ gameState.player.x = newPos.x;
1380
+ gameState.player.y = newPos.y;
1381
+ addLogMessage(`Vous vous êtes téléporté ailleurs dans le donjon!`);
1382
+ }
1383
+ }
1384
+
1385
+ // Enemy turn
1386
+ moveEnemies();
1387
+
1388
+ renderDungeon();
1389
+ updateUI();
1390
+ }
1391
+
1392
+ // New game button
1393
+ document.getElementById('new-game-btn').addEventListener('click', initGame);
1394
+
1395
+ // Help button
1396
+ document.getElementById('help-btn').addEventListener('click', () => {
1397
+ document.getElementById('help-modal').classList.remove('hidden');
1398
+ });
1399
+
1400
+ document.getElementById('close-help-btn').addEventListener('click', () => {
1401
+ document.getElementById('help-modal').classList.add('hidden');
1402
+ });
1403
+
1404
+ // Initialize the game
1405
+ initGame();
1406
+ </script>
1407
+ <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=Paresiast/jeux" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1408
+ </html>