Add 1 files
Browse files- index.html +507 -1081
index.html
CHANGED
@@ -3,421 +3,225 @@
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
-
<title>
|
7 |
<script src="https://cdn.tailwindcss.com"></script>
|
8 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
9 |
<style>
|
10 |
-
@keyframes
|
11 |
-
|
12 |
-
|
|
|
13 |
}
|
14 |
-
|
15 |
-
|
16 |
-
50% { transform: scale(1.05); }
|
17 |
-
100% { transform: scale(1); }
|
18 |
}
|
19 |
-
.
|
20 |
-
|
21 |
-
}
|
22 |
-
.pulse {
|
23 |
-
animation: pulse 1.5s infinite;
|
24 |
-
}
|
25 |
-
.health-bar {
|
26 |
-
transition: width 0.3s ease;
|
27 |
-
}
|
28 |
-
.damage-text {
|
29 |
-
position: absolute;
|
30 |
-
color: red;
|
31 |
-
font-weight: bold;
|
32 |
-
animation: floatUp 1s forwards;
|
33 |
-
}
|
34 |
-
@keyframes floatUp {
|
35 |
-
0% { transform: translateY(0); opacity: 1; }
|
36 |
-
100% { transform: translateY(-50px); opacity: 0; }
|
37 |
-
}
|
38 |
-
.game-container {
|
39 |
-
background-image: url('https://images.unsplash.com/photo-1542273917363-3b1817f69a2d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80');
|
40 |
background-size: cover;
|
41 |
background-position: center;
|
42 |
}
|
43 |
-
.dialog-box {
|
44 |
-
background-color: rgba(0, 0, 0, 0.8);
|
45 |
-
border: 2px solid gold;
|
46 |
-
border-radius: 10px;
|
47 |
-
}
|
48 |
.character-card {
|
49 |
transition: all 0.3s ease;
|
|
|
50 |
}
|
51 |
.character-card:hover {
|
52 |
-
transform:
|
53 |
-
box-shadow: 0 10px
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
}
|
55 |
-
.
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
62 |
}
|
63 |
</style>
|
64 |
</head>
|
65 |
-
<body class="bg-gray-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
<div class="
|
71 |
-
|
72 |
-
|
73 |
-
</
|
74 |
-
<
|
75 |
-
<
|
76 |
-
|
77 |
-
<button onclick="showCredits()" class="bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-lg text-xl w-64 transition-all hover:scale-105">
|
78 |
-
<i class="fas fa-info-circle mr-2"></i> Credits
|
79 |
-
</button>
|
80 |
-
</div>
|
81 |
-
</div>
|
82 |
-
|
83 |
-
<!-- Character Creation -->
|
84 |
-
<div id="character-creation" class="hidden text-center w-full max-w-4xl">
|
85 |
-
<h2 class="text-4xl font-bold mb-8 text-pink-400">Create Your Hero</h2>
|
86 |
-
|
87 |
-
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
88 |
-
<!-- Warrior -->
|
89 |
-
<div class="character-card bg-gray-800 p-6 rounded-lg cursor-pointer" onclick="selectClass('warrior')">
|
90 |
-
<div class="text-5xl mb-4 text-red-500">
|
91 |
-
<i class="fas fa-shield-alt"></i>
|
92 |
-
</div>
|
93 |
-
<h3 class="text-2xl font-bold mb-2">Warrior</h3>
|
94 |
-
<p class="text-gray-300 mb-4">Strong and resilient, excels in melee combat</p>
|
95 |
-
<div class="text-left">
|
96 |
-
<p><i class="fas fa-heart text-red-500 mr-2"></i> High Health</p>
|
97 |
-
<p><i class="fas fa-fist-raised text-orange-500 mr-2"></i> Strong Attacks</p>
|
98 |
-
<p><i class="fas fa-running text-blue-500 mr-2"></i> Low Speed</p>
|
99 |
-
</div>
|
100 |
</div>
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
<div class="
|
110 |
-
<
|
111 |
-
<
|
112 |
-
<p><i class="fas fa-brain text-purple-500 mr-2"></i> Smart</p>
|
113 |
-
</div>
|
114 |
-
</div>
|
115 |
-
|
116 |
-
<!-- Rogue -->
|
117 |
-
<div class="character-card bg-gray-800 p-6 rounded-lg cursor-pointer" onclick="selectClass('rogue')">
|
118 |
-
<div class="text-5xl mb-4 text-green-500">
|
119 |
-
<i class="fas fa-user-ninja"></i>
|
120 |
</div>
|
121 |
-
<
|
122 |
-
|
123 |
-
|
124 |
-
<p><i class="fas fa-tachometer-alt text-green-500 mr-2"></i> High Speed</p>
|
125 |
-
<p><i class="fas fa-heart text-red-500 mr-2"></i> Medium Health</p>
|
126 |
-
<p><i class="fas fa-eye-slash text-gray-500 mr-2"></i> Sneaky</p>
|
127 |
</div>
|
128 |
</div>
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
134 |
-
<div>
|
135 |
-
<label class="block text-left mb-2">Name:</label>
|
136 |
-
<input type="text" id="character-name" class="w-full p-2 rounded bg-gray-700 border border-gray-600" placeholder="Enter your name">
|
137 |
</div>
|
138 |
-
<div>
|
139 |
-
<
|
140 |
-
<
|
141 |
-
<option value="male">Male</option>
|
142 |
-
<option value="female">Female</option>
|
143 |
-
<option value="other">Other</option>
|
144 |
-
</select>
|
145 |
</div>
|
146 |
</div>
|
147 |
</div>
|
148 |
-
|
149 |
-
<button onclick="finalizeCharacter()" class="bg-pink-600 hover:bg-pink-700 text-white font-bold py-3 px-8 rounded-lg text-xl transition-all hover:scale-105">
|
150 |
-
<i class="fas fa-heart mr-2"></i> Begin Adventure
|
151 |
-
</button>
|
152 |
-
</div>
|
153 |
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
<i class="fas fa-user"></i>
|
163 |
-
</div>
|
164 |
-
<h4 class="text-2xl font-bold" id="character-display-name">Unknown</h4>
|
165 |
-
<p class="text-gray-300" id="character-display-class">Class: None</p>
|
166 |
-
</div>
|
167 |
-
|
168 |
-
<div class="mb-4">
|
169 |
-
<div class="flex justify-between mb-1">
|
170 |
-
<span>Health</span>
|
171 |
-
<span id="health-text">100/100</span>
|
172 |
-
</div>
|
173 |
-
<div class="w-full bg-gray-700 rounded-full h-4">
|
174 |
-
<div id="health-bar" class="health-bar bg-red-500 h-4 rounded-full" style="width: 100%"></div>
|
175 |
</div>
|
176 |
</div>
|
177 |
-
|
178 |
-
<div class="mb-4">
|
179 |
-
<div class="flex justify-between mb-1">
|
180 |
-
<span>Mana</span>
|
181 |
-
<span id="mana-text">50/50</span>
|
182 |
-
</div>
|
183 |
-
<div class="w-full bg-gray-700 rounded-full h-4">
|
184 |
-
<div id="mana-bar" class="health-bar bg-blue-500 h-4 rounded-full" style="width: 100%"></div>
|
185 |
-
</div>
|
186 |
-
</div>
|
187 |
-
|
188 |
-
<div class="mb-4">
|
189 |
-
<div class="flex justify-between mb-1">
|
190 |
-
<span>Experience</span>
|
191 |
-
<span id="exp-text">0/100</span>
|
192 |
-
</div>
|
193 |
-
<div class="w-full bg-gray-700 rounded-full h-4">
|
194 |
-
<div id="exp-bar" class="health-bar bg-yellow-500 h-4 rounded-full" style="width: 0%"></div>
|
195 |
-
</div>
|
196 |
-
</div>
|
197 |
-
|
198 |
-
<div class="grid grid-cols-2 gap-2 mb-4">
|
199 |
-
<div class="bg-gray-700 p-2 rounded">
|
200 |
-
<div class="text-sm text-gray-300">Level</div>
|
201 |
-
<div class="font-bold" id="level-text">1</div>
|
202 |
-
</div>
|
203 |
-
<div class="bg-gray-700 p-2 rounded">
|
204 |
-
<div class="text-sm text-gray-300">Gold</div>
|
205 |
-
<div class="font-bold" id="gold-text">10</div>
|
206 |
-
</div>
|
207 |
-
<div class="bg-gray-700 p-2 rounded">
|
208 |
-
<div class="text-sm text-gray-300">Attack</div>
|
209 |
-
<div class="font-bold" id="attack-text">10</div>
|
210 |
-
</div>
|
211 |
-
<div class="bg-gray-700 p-2 rounded">
|
212 |
-
<div class="text-sm text-gray-300">Defense</div>
|
213 |
-
<div class="font-bold" id="defense-text">5</div>
|
214 |
-
</div>
|
215 |
-
</div>
|
216 |
-
|
217 |
-
<button onclick="openInventory()" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 rounded mb-2">
|
218 |
-
<i class="fas fa-backpack mr-2"></i> Inventory
|
219 |
-
</button>
|
220 |
-
<button onclick="openQuests()" class="w-full bg-green-600 hover:bg-green-700 text-white py-2 rounded mb-2">
|
221 |
-
<i class="fas fa-scroll mr-2"></i> Quests
|
222 |
-
</button>
|
223 |
-
<button onclick="saveGame()" class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 rounded">
|
224 |
-
<i class="fas fa-save mr-2"></i> Save Game
|
225 |
-
</button>
|
226 |
-
</div>
|
227 |
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
<!-- Action Buttons -->
|
237 |
-
<div class="grid grid-cols-2 gap-4 mb-6">
|
238 |
-
<button onclick="explore()" class="bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-4 rounded-lg transition-all hover:scale-105">
|
239 |
-
<i class="fas fa-heart mr-2"></i> Meet Girls
|
240 |
-
</button>
|
241 |
-
<button onclick="rest()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition-all hover:scale-105">
|
242 |
-
<i class="fas fa-bed mr-2"></i> Rest
|
243 |
-
</button>
|
244 |
-
<button onclick="visitTown()" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-3 px-4 rounded-lg transition-all hover:scale-105">
|
245 |
-
<i class="fas fa-city mr-2"></i> Visit Town
|
246 |
-
</button>
|
247 |
-
<button onclick="train()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-4 rounded-lg transition-all hover:scale-105">
|
248 |
-
<i class="fas fa-dumbbell mr-2"></i> Train
|
249 |
-
</button>
|
250 |
-
</div>
|
251 |
-
|
252 |
-
<!-- Combat Area -->
|
253 |
-
<div id="combat-area" class="hidden bg-gray-800 bg-opacity-90 rounded-lg p-6">
|
254 |
-
<div class="flex flex-col md:flex-row justify-between items-center mb-8">
|
255 |
-
<!-- Player -->
|
256 |
-
<div class="text-center mb-6 md:mb-0 relative">
|
257 |
-
<div class="text-6xl mb-2" id="player-combat-icon">
|
258 |
-
<i class="fas fa-user"></i>
|
259 |
</div>
|
260 |
-
|
261 |
-
|
262 |
-
|
|
|
|
|
263 |
</div>
|
264 |
-
<div class="text-sm" id="player-health-text">100/100</div>
|
265 |
</div>
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
<
|
274 |
-
<div class="w-full bg-gray-
|
275 |
-
<div
|
276 |
</div>
|
277 |
-
<div class="text-sm" id="enemy-health-text">30/30</div>
|
278 |
</div>
|
279 |
-
</div>
|
280 |
-
|
281 |
-
<!-- Combat Actions -->
|
282 |
-
<div id="combat-actions" class="grid grid-cols-2 gap-4">
|
283 |
-
<button onclick="playerAttack()" class="bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-4 rounded-lg">
|
284 |
-
<i class="fas fa-heart-broken mr-2"></i> Attack
|
285 |
-
</button>
|
286 |
-
<button onclick="playerSpell()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg">
|
287 |
-
<i class="fas fa-magic mr-2"></i> Cast Spell
|
288 |
-
</button>
|
289 |
-
<button onclick="playerDefend()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-3 px-4 rounded-lg">
|
290 |
-
<i class="fas fa-shield-alt mr-2"></i> Defend
|
291 |
-
</button>
|
292 |
-
<button onclick="playerFlee()" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-3 px-4 rounded-lg">
|
293 |
-
<i class="fas fa-running mr-2"></i> Flee
|
294 |
-
</button>
|
295 |
-
</div>
|
296 |
-
</div>
|
297 |
-
|
298 |
-
<!-- Town Area -->
|
299 |
-
<div id="town-area" class="hidden bg-gray-800 bg-opacity-90 rounded-lg p-6">
|
300 |
-
<h3 class="text-2xl font-bold mb-4">Town Square</h3>
|
301 |
-
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
302 |
-
<button onclick="visitShop()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg">
|
303 |
-
<i class="fas fa-shopping-cart mr-2"></i> Shop
|
304 |
-
</button>
|
305 |
-
<button onclick="visitTavern()" class="bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-3 px-4 rounded-lg">
|
306 |
-
<i class="fas fa-beer mr-2"></i> Tavern
|
307 |
-
</button>
|
308 |
-
<button onclick="visitGuild()" class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-4 rounded-lg">
|
309 |
-
<i class="fas fa-scroll mr-2"></i> Adventurer's Guild
|
310 |
-
</button>
|
311 |
-
<button onclick="leaveTown()" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-3 px-4 rounded-lg">
|
312 |
-
<i class="fas fa-door-open mr-2"></i> Leave Town
|
313 |
-
</button>
|
314 |
</div>
|
315 |
</div>
|
316 |
</div>
|
317 |
-
</div>
|
318 |
-
</div>
|
319 |
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
</div>
|
329 |
-
|
330 |
-
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
331 |
-
<div class="bg-gray-700 p-4 rounded-lg text-center">
|
332 |
-
<div class="text-3xl mb-2"><i class="fas fa-sword"></i></div>
|
333 |
-
<div class="font-bold">Iron Sword</div>
|
334 |
-
<div class="text-sm text-gray-300">Attack +5</div>
|
335 |
-
<button class="mt-2 bg-blue-600 hover:bg-blue-700 text-white py-1 px-3 rounded text-sm">
|
336 |
-
Equip
|
337 |
-
</button>
|
338 |
-
</div>
|
339 |
-
<div class="bg-gray-700 p-4 rounded-lg text-center">
|
340 |
-
<div class="text-3xl mb-2"><i class="fas fa-shield-alt"></i></div>
|
341 |
-
<div class="font-bold">Wooden Shield</div>
|
342 |
-
<div class="text-sm text-gray-300">Defense +3</div>
|
343 |
-
<button class="mt-2 bg-blue-600 hover:bg-blue-700 text-white py-1 px-3 rounded text-sm">
|
344 |
-
Equip
|
345 |
-
</button>
|
346 |
-
</div>
|
347 |
-
<div class="bg-gray-700 p-4 rounded-lg text-center">
|
348 |
-
<div class="text-3xl mb-2"><i class="fas fa-flask"></i></div>
|
349 |
-
<div class="font-bold">Health Potion</div>
|
350 |
-
<div class="text-sm text-gray-300">Restores 30 HP</div>
|
351 |
-
<button class="mt-2 bg-green-600 hover:bg-green-700 text-white py-1 px-3 rounded text-sm">
|
352 |
-
Use
|
353 |
-
</button>
|
354 |
</div>
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
<div class="text-sm text-gray-300">Restores 20 MP</div>
|
359 |
-
<button class="mt-2 bg-green-600 hover:bg-green-700 text-white py-1 px-3 rounded text-sm">
|
360 |
-
Use
|
361 |
-
</button>
|
362 |
</div>
|
363 |
</div>
|
364 |
-
|
365 |
-
|
366 |
-
<div class="
|
367 |
-
<div class="bg-
|
368 |
-
<
|
369 |
-
|
370 |
-
<div>
|
371 |
-
|
372 |
-
|
373 |
-
</div>
|
|
|
|
|
|
|
374 |
</div>
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
<div class="
|
379 |
-
<div>
|
380 |
-
|
381 |
-
|
382 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
383 |
</div>
|
384 |
</div>
|
385 |
-
</div>
|
386 |
-
</div>
|
387 |
-
</div>
|
388 |
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
<h4 class="text-xl font-bold text-pink-400">Monstergirl RPG</h4>
|
402 |
-
<p class="text-gray-300">Created with HTML, CSS, and JavaScript</p>
|
403 |
-
</div>
|
404 |
-
|
405 |
-
<div>
|
406 |
-
<h4 class="font-bold">Developer</h4>
|
407 |
-
<p class="text-gray-300">Your Name Here</p>
|
408 |
-
</div>
|
409 |
-
|
410 |
-
<div>
|
411 |
-
<h4 class="font-bold">Special Thanks</h4>
|
412 |
-
<ul class="list-disc list-inside text-gray-300">
|
413 |
-
<li>Tailwind CSS</li>
|
414 |
-
<li>Font Awesome</li>
|
415 |
-
<li>All the wonderful monstergirl artists</li>
|
416 |
-
</ul>
|
417 |
-
</div>
|
418 |
-
|
419 |
-
<div class="pt-4 border-t border-gray-700">
|
420 |
-
<p class="text-sm text-gray-400">© 2023 All Rights Reserved</p>
|
421 |
</div>
|
422 |
</div>
|
423 |
</div>
|
@@ -427,767 +231,389 @@
|
|
427 |
<script>
|
428 |
// Game State
|
429 |
const gameState = {
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
maxMana: 50,
|
441 |
-
attack: 10,
|
442 |
-
defense: 5,
|
443 |
-
gold: 10,
|
444 |
-
inventory: [
|
445 |
-
{ name: 'Iron Sword', type: 'weapon', attack: 5, icon: 'fa-sword' },
|
446 |
-
{ name: 'Wooden Shield', type: 'shield', defense: 3, icon: 'fa-shield-alt' },
|
447 |
-
{ name: 'Health Potion', type: 'consumable', effect: 'heal', amount: 30, icon: 'fa-flask' },
|
448 |
-
{ name: 'Mana Potion', type: 'consumable', effect: 'mana', amount: 20, icon: 'fa-flask' }
|
449 |
-
],
|
450 |
-
equipped: {
|
451 |
-
weapon: { name: 'Iron Sword', type: 'weapon', attack: 5, icon: 'fa-sword' },
|
452 |
-
shield: { name: 'Wooden Shield', type: 'shield', defense: 3, icon: 'fa-shield-alt' }
|
453 |
-
}
|
454 |
},
|
455 |
-
|
456 |
-
|
457 |
-
|
|
|
458 |
};
|
459 |
|
460 |
-
//
|
461 |
-
const
|
462 |
-
{
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
472 |
},
|
473 |
-
{
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
483 |
},
|
484 |
-
|
485 |
-
|
486 |
-
health: 35,
|
487 |
-
maxHealth: 35,
|
488 |
-
attack: 7,
|
489 |
-
defense: 3,
|
490 |
-
exp: 25,
|
491 |
-
gold: 8,
|
492 |
-
image: 'https://i.imgur.com/8X9vY7H.jpg',
|
493 |
-
description: 'A fluffy-eared girl who hops around with boundless energy.'
|
494 |
-
},
|
495 |
-
{
|
496 |
-
name: 'Fox Girl',
|
497 |
-
health: 28,
|
498 |
-
maxHealth: 28,
|
499 |
-
attack: 10,
|
500 |
-
defense: 2,
|
501 |
-
exp: 24,
|
502 |
-
gold: 9,
|
503 |
-
image: 'https://i.imgur.com/3RkLZ2t.jpg',
|
504 |
-
description: 'A cunning kitsune with multiple tails and a playful trickster nature.'
|
505 |
-
},
|
506 |
-
{
|
507 |
-
name: 'Slime Girl',
|
508 |
-
health: 45,
|
509 |
-
maxHealth: 45,
|
510 |
-
attack: 6,
|
511 |
-
defense: 6,
|
512 |
-
exp: 28,
|
513 |
-
gold: 10,
|
514 |
-
image: 'https://i.imgur.com/qM9cB1P.jpg',
|
515 |
-
description: 'A gelatinous girl who can change her shape at will, very squishy!'
|
516 |
-
},
|
517 |
-
{
|
518 |
-
name: 'Dragon Girl',
|
519 |
-
health: 60,
|
520 |
-
maxHealth: 60,
|
521 |
-
attack: 15,
|
522 |
-
defense: 8,
|
523 |
-
exp: 50,
|
524 |
-
gold: 25,
|
525 |
-
image: 'https://i.imgur.com/7wGpL0z.jpg',
|
526 |
-
description: 'A powerful draconic beauty with scales, wings, and a fiery personality.'
|
527 |
-
},
|
528 |
-
{
|
529 |
-
name: 'Wolf Girl',
|
530 |
-
health: 40,
|
531 |
-
maxHealth: 40,
|
532 |
-
attack: 11,
|
533 |
-
defense: 4,
|
534 |
-
exp: 30,
|
535 |
-
gold: 12,
|
536 |
-
image: 'https://i.imgur.com/5tNf8Yq.jpg',
|
537 |
-
description: 'A wild girl with wolf ears and tail, fiercely loyal to her pack.'
|
538 |
-
},
|
539 |
-
{
|
540 |
-
name: 'Mermaid',
|
541 |
-
health: 35,
|
542 |
-
maxHealth: 35,
|
543 |
-
attack: 8,
|
544 |
-
defense: 5,
|
545 |
-
exp: 26,
|
546 |
-
gold: 15,
|
547 |
-
image: 'https://i.imgur.com/9XvLQ2f.jpg',
|
548 |
-
description: 'A beautiful sea maiden with a fish tail, sings enchanting melodies.'
|
549 |
-
},
|
550 |
-
{
|
551 |
-
name: 'Angel',
|
552 |
-
health: 50,
|
553 |
-
maxHealth: 50,
|
554 |
-
attack: 12,
|
555 |
-
defense: 7,
|
556 |
-
exp: 40,
|
557 |
-
gold: 20,
|
558 |
-
image: 'https://i.imgur.com/4kL9s2r.jpg',
|
559 |
-
description: 'A celestial being with pure white wings and a divine presence.'
|
560 |
-
},
|
561 |
-
{
|
562 |
-
name: 'Demon Girl',
|
563 |
-
health: 45,
|
564 |
-
maxHealth: 45,
|
565 |
-
attack: 14,
|
566 |
-
defense: 5,
|
567 |
-
exp: 38,
|
568 |
-
gold: 18,
|
569 |
-
image: 'https://i.imgur.com/2sVp7Qk.jpg',
|
570 |
-
description: 'A seductive temptress with horns and a tail, full of mischief.'
|
571 |
-
},
|
572 |
-
{
|
573 |
-
name: 'Vampire Girl',
|
574 |
-
health: 42,
|
575 |
-
maxHealth: 42,
|
576 |
-
attack: 13,
|
577 |
-
defense: 6,
|
578 |
-
exp: 35,
|
579 |
-
gold: 22,
|
580 |
-
image: 'https://i.imgur.com/1wX9vY7.jpg',
|
581 |
-
description: 'An elegant nocturnal beauty with sharp fangs and a taste for blood.'
|
582 |
-
},
|
583 |
-
{
|
584 |
-
name: 'Ghost Girl',
|
585 |
-
health: 30,
|
586 |
-
maxHealth: 30,
|
587 |
-
attack: 9,
|
588 |
-
defense: 8,
|
589 |
-
exp: 25,
|
590 |
-
gold: 10,
|
591 |
-
image: 'https://i.imgur.com/3RtLZ2t.jpg',
|
592 |
-
description: 'A translucent spirit girl who can phase through walls and objects.'
|
593 |
-
},
|
594 |
-
{
|
595 |
-
name: 'Centaur Girl',
|
596 |
-
health: 55,
|
597 |
-
maxHealth: 55,
|
598 |
-
attack: 12,
|
599 |
-
defense: 9,
|
600 |
-
exp: 45,
|
601 |
-
gold: 25,
|
602 |
-
image: 'https://i.imgur.com/7vGpL0z.jpg',
|
603 |
-
description: 'A majestic half-human half-horse girl with incredible strength.'
|
604 |
-
},
|
605 |
-
{
|
606 |
-
name: 'Lamia',
|
607 |
-
health: 48,
|
608 |
-
maxHealth: 48,
|
609 |
-
attack: 13,
|
610 |
-
defense: 7,
|
611 |
-
exp: 42,
|
612 |
-
gold: 20,
|
613 |
-
image: 'https://i.imgur.com/5sNf8Yq.jpg',
|
614 |
-
description: 'A serpentine beauty with a long snake tail, both alluring and dangerous.'
|
615 |
-
},
|
616 |
-
{
|
617 |
-
name: 'Harpy',
|
618 |
-
health: 38,
|
619 |
-
maxHealth: 38,
|
620 |
-
attack: 11,
|
621 |
-
defense: 4,
|
622 |
-
exp: 32,
|
623 |
-
gold: 15,
|
624 |
-
image: 'https://i.imgur.com/9YvLQ2f.jpg',
|
625 |
-
description: 'A winged girl with talons who can soar through the skies.'
|
626 |
-
}
|
627 |
-
];
|
628 |
-
|
629 |
-
// Game Functions
|
630 |
-
function startNewGame() {
|
631 |
-
document.getElementById('main-menu').classList.add('hidden');
|
632 |
-
document.getElementById('character-creation').classList.remove('hidden');
|
633 |
-
addGameMessage('Begin your adventure by creating your character.');
|
634 |
-
}
|
635 |
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
const selectedCard = document.querySelector(`.character-card:nth-child(${characterClass === 'warrior' ? 1 : characterClass === 'mage' ? 2 : 3})`);
|
641 |
-
selectedCard.classList.add('ring-2', 'ring-pink-400');
|
642 |
-
|
643 |
-
gameState.player.class = characterClass;
|
644 |
-
|
645 |
-
// Update stats based on class
|
646 |
-
if (characterClass === 'warrior') {
|
647 |
-
gameState.player.maxHealth = 120;
|
648 |
-
gameState.player.health = 120;
|
649 |
-
gameState.player.attack = 12;
|
650 |
-
gameState.player.defense = 8;
|
651 |
-
gameState.player.mana = 30;
|
652 |
-
gameState.player.maxMana = 30;
|
653 |
-
} else if (characterClass === 'mage') {
|
654 |
-
gameState.player.maxHealth = 70;
|
655 |
-
gameState.player.health = 70;
|
656 |
-
gameState.player.attack = 8;
|
657 |
-
gameState.player.defense = 3;
|
658 |
-
gameState.player.mana = 80;
|
659 |
-
gameState.player.maxMana = 80;
|
660 |
-
} else if (characterClass === 'rogue') {
|
661 |
-
gameState.player.maxHealth = 90;
|
662 |
-
gameState.player.health = 90;
|
663 |
-
gameState.player.attack = 10;
|
664 |
-
gameState.player.defense = 5;
|
665 |
-
gameState.player.mana = 50;
|
666 |
-
gameState.player.maxMana = 50;
|
667 |
}
|
668 |
-
|
669 |
-
addGameMessage(`You selected the ${characterClass} class.`);
|
670 |
}
|
671 |
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
if (!gameState.player.class) {
|
682 |
-
addGameMessage('Please select a class for your character.', 'error');
|
683 |
-
return;
|
684 |
-
}
|
685 |
-
|
686 |
-
gameState.player.name = nameInput.value.trim();
|
687 |
-
gameState.player.gender = genderSelect.value;
|
688 |
-
|
689 |
-
// Start the game
|
690 |
-
document.getElementById('character-creation').classList.add('hidden');
|
691 |
-
document.getElementById('game-screen').classList.remove('hidden');
|
692 |
-
|
693 |
-
// Update character display
|
694 |
-
updateCharacterDisplay();
|
695 |
-
|
696 |
-
addGameMessage(`Welcome, ${gameState.player.name} the ${gameState.player.class}! Your adventure begins now.`, 'success');
|
697 |
-
}
|
698 |
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
// Update stats
|
705 |
-
document.getElementById('health-text').textContent = `${gameState.player.health}/${gameState.player.maxHealth}`;
|
706 |
-
document.getElementById('mana-text').textContent = `${gameState.player.mana}/${gameState.player.maxMana}`;
|
707 |
-
document.getElementById('exp-text').textContent = `${gameState.player.exp}/${gameState.player.expToNextLevel}`;
|
708 |
-
document.getElementById('level-text').textContent = gameState.player.level;
|
709 |
-
document.getElementById('gold-text').textContent = gameState.player.gold;
|
710 |
-
document.getElementById('attack-text').textContent = gameState.player.attack + (gameState.player.equipped.weapon ? gameState.player.equipped.weapon.attack : 0);
|
711 |
-
document.getElementById('defense-text').textContent = gameState.player.defense + (gameState.player.equipped.shield ? gameState.player.equipped.shield.defense : 0);
|
712 |
-
|
713 |
-
// Update health bar
|
714 |
-
const healthPercent = (gameState.player.health / gameState.player.maxHealth) * 100;
|
715 |
-
document.getElementById('health-bar').style.width = `${healthPercent}%`;
|
716 |
-
|
717 |
-
// Update mana bar
|
718 |
-
const manaPercent = (gameState.player.mana / gameState.player.maxMana) * 100;
|
719 |
-
document.getElementById('mana-bar').style.width = `${manaPercent}%`;
|
720 |
-
|
721 |
-
// Update exp bar
|
722 |
-
const expPercent = (gameState.player.exp / gameState.player.expToNextLevel) * 100;
|
723 |
-
document.getElementById('exp-bar').style.width = `${expPercent}%`;
|
724 |
-
|
725 |
-
// Update character icon based on class
|
726 |
-
const characterIcon = document.getElementById('character-icon');
|
727 |
-
const playerCombatIcon = document.getElementById('player-combat-icon');
|
728 |
-
|
729 |
-
if (gameState.player.class === 'warrior') {
|
730 |
-
characterIcon.innerHTML = '<i class="fas fa-shield-alt text-red-500"></i>';
|
731 |
-
playerCombatIcon.innerHTML = '<i class="fas fa-shield-alt text-red-500"></i>';
|
732 |
-
} else if (gameState.player.class === 'mage') {
|
733 |
-
characterIcon.innerHTML = '<i class="fas fa-hat-wizard text-blue-500"></i>';
|
734 |
-
playerCombatIcon.innerHTML = '<i class="fas fa-hat-wizard text-blue-500"></i>';
|
735 |
-
} else if (gameState.player.class === 'rogue') {
|
736 |
-
characterIcon.innerHTML = '<i class="fas fa-user-ninja text-green-500"></i>';
|
737 |
-
playerCombatIcon.innerHTML = '<i class="fas fa-user-ninja text-green-500"></i>';
|
738 |
-
}
|
739 |
-
|
740 |
-
// Update player combat name
|
741 |
-
document.getElementById('player-combat-name').textContent = gameState.player.name;
|
742 |
-
}
|
743 |
|
744 |
-
|
745 |
-
|
746 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
747 |
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
} else if (type === 'warning') {
|
753 |
-
messageElement.className = 'text-yellow-400';
|
754 |
-
} else {
|
755 |
-
messageElement.className = 'text-gray-300';
|
756 |
-
}
|
757 |
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
|
762 |
-
//
|
763 |
-
|
764 |
}
|
765 |
|
766 |
-
function
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
778 |
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
name: 'Health Potion',
|
789 |
-
type: 'consumable',
|
790 |
-
effect: 'heal',
|
791 |
-
amount: 30,
|
792 |
-
icon: 'fa-flask'
|
793 |
});
|
794 |
-
|
795 |
-
|
796 |
-
}
|
797 |
-
}
|
798 |
-
|
799 |
-
function startCombat() {
|
800 |
-
gameState.inCombat = true;
|
801 |
-
|
802 |
-
// Select a random enemy
|
803 |
-
const randomEnemyIndex = Math.floor(Math.random() * enemies.length);
|
804 |
-
gameState.currentEnemy = {...enemies[randomEnemyIndex]};
|
805 |
-
|
806 |
-
// Update combat UI
|
807 |
-
document.getElementById('combat-area').classList.remove('hidden');
|
808 |
-
document.getElementById('enemy-name').textContent = gameState.currentEnemy.name;
|
809 |
-
document.getElementById('enemy-health-text').textContent = `${gameState.currentEnemy.health}/${gameState.currentEnemy.maxHealth}`;
|
810 |
-
document.getElementById('enemy-health-bar').style.width = '100%';
|
811 |
-
document.getElementById('enemy-image').src = gameState.currentEnemy.image;
|
812 |
-
document.getElementById('enemy-image').alt = gameState.currentEnemy.name;
|
813 |
-
|
814 |
-
// Update player stats in combat
|
815 |
-
document.getElementById('player-health-text').textContent = `${gameState.player.health}/${gameState.player.maxHealth}`;
|
816 |
-
const healthPercent = (gameState.player.health / gameState.player.maxHealth) * 100;
|
817 |
-
document.getElementById('player-health-bar').style.width = `${healthPercent}%`;
|
818 |
-
|
819 |
-
addGameMessage(`You encounter a ${gameState.currentEnemy.name}! ${gameState.currentEnemy.description}`, 'warning');
|
820 |
-
}
|
821 |
-
|
822 |
-
function playerAttack() {
|
823 |
-
if (!gameState.inCombat || !gameState.currentEnemy) {
|
824 |
-
addGameMessage('There is nothing to attack!', 'error');
|
825 |
-
return;
|
826 |
-
}
|
827 |
-
|
828 |
-
// Calculate player damage
|
829 |
-
const playerAttackPower = gameState.player.attack + (gameState.player.equipped.weapon ? gameState.player.equipped.weapon.attack : 0);
|
830 |
-
const damage = Math.max(1, playerAttackPower - Math.floor(gameState.currentEnemy.defense / 2));
|
831 |
-
|
832 |
-
// Apply damage to enemy
|
833 |
-
gameState.currentEnemy.health -= damage;
|
834 |
-
|
835 |
-
// Update enemy health bar
|
836 |
-
const enemyHealthPercent = (gameState.currentEnemy.health / gameState.currentEnemy.maxHealth) * 100;
|
837 |
-
document.getElementById('enemy-health-bar').style.width = `${Math.max(0, enemyHealthPercent)}%`;
|
838 |
-
document.getElementById('enemy-health-text').textContent = `${Math.max(0, gameState.currentEnemy.health)}/${gameState.currentEnemy.maxHealth}`;
|
839 |
-
|
840 |
-
// Show damage text
|
841 |
-
showDamageText(document.querySelector('#combat-area .relative:last-child'), damage);
|
842 |
-
|
843 |
-
addGameMessage(`You attack the ${gameState.currentEnemy.name} for ${damage} damage!`, 'success');
|
844 |
-
|
845 |
-
// Check if enemy is defeated
|
846 |
-
if (gameState.currentEnemy.health <= 0) {
|
847 |
-
enemyDefeated();
|
848 |
-
return;
|
849 |
-
}
|
850 |
-
|
851 |
-
// Enemy attacks back
|
852 |
-
setTimeout(() => {
|
853 |
-
enemyAttack();
|
854 |
-
}, 1000);
|
855 |
-
}
|
856 |
-
|
857 |
-
function playerSpell() {
|
858 |
-
if (!gameState.inCombat || !gameState.currentEnemy) {
|
859 |
-
addGameMessage('There is nothing to attack!', 'error');
|
860 |
-
return;
|
861 |
-
}
|
862 |
-
|
863 |
-
if (gameState.player.mana < 15) {
|
864 |
-
addGameMessage('Not enough mana to cast a spell!', 'error');
|
865 |
return;
|
866 |
}
|
867 |
|
868 |
-
//
|
869 |
-
|
870 |
-
|
|
|
871 |
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
|
|
|
|
|
|
876 |
} else {
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
document.getElementById('enemy-health-bar').style.width = `${Math.max(0, enemyHealthPercent)}%`;
|
886 |
-
document.getElementById('enemy-health-text').textContent = `${Math.max(0, gameState.currentEnemy.health)}/${gameState.currentEnemy.maxHealth}`;
|
887 |
-
|
888 |
-
// Show damage text
|
889 |
-
showDamageText(document.querySelector('#combat-area .relative:last-child'), spellDamage, 'blue');
|
890 |
-
|
891 |
-
addGameMessage(`You cast a spell on the ${gameState.currentEnemy.name} for ${spellDamage} damage!`, 'success');
|
892 |
-
|
893 |
-
// Check if enemy is defeated
|
894 |
-
if (gameState.currentEnemy.health <= 0) {
|
895 |
-
enemyDefeated();
|
896 |
-
return;
|
897 |
}
|
898 |
-
|
899 |
-
// Enemy attacks back
|
900 |
-
setTimeout(() => {
|
901 |
-
enemyAttack();
|
902 |
-
}, 1000);
|
903 |
}
|
904 |
|
905 |
-
function
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
910 |
|
911 |
-
|
|
|
|
|
912 |
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
// Apply damage to player
|
919 |
-
gameState.player.health -= enemyDamage;
|
920 |
|
921 |
-
//
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
|
933 |
-
|
934 |
-
|
935 |
-
playerDefeated();
|
936 |
}
|
937 |
-
}, 1000);
|
938 |
-
}
|
939 |
-
|
940 |
-
function playerFlee() {
|
941 |
-
if (!gameState.inCombat || !gameState.currentEnemy) {
|
942 |
-
addGameMessage('There is nothing to flee from!', 'error');
|
943 |
-
return;
|
944 |
-
}
|
945 |
-
|
946 |
-
// 60% chance to flee successfully
|
947 |
-
if (Math.random() < 0.6) {
|
948 |
-
addGameMessage(`You successfully fled from the ${gameState.currentEnemy.name}!`, 'success');
|
949 |
-
endCombat();
|
950 |
-
} else {
|
951 |
-
addGameMessage(`You failed to flee! The ${gameState.currentEnemy.name} attacks you!`, 'error');
|
952 |
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
965 |
-
|
966 |
-
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
// Show damage text
|
977 |
-
showDamageText(document.querySelector('#combat-area .relative:first-child'), enemyDamage);
|
978 |
-
|
979 |
-
addGameMessage(`The ${gameState.currentEnemy.name} attacks you for ${enemyDamage} damage!`, 'warning');
|
980 |
-
|
981 |
-
// Check if player is defeated
|
982 |
-
if (gameState.player.health <= 0) {
|
983 |
-
playerDefeated();
|
984 |
-
}
|
985 |
-
}
|
986 |
-
|
987 |
-
function enemyDefeated() {
|
988 |
-
addGameMessage(`You defeated the ${gameState.currentEnemy.name}!`, 'success');
|
989 |
-
|
990 |
-
// Gain experience and gold
|
991 |
-
gameState.player.exp += gameState.currentEnemy.exp;
|
992 |
-
gameState.player.gold += gameState.currentEnemy.gold;
|
993 |
|
994 |
-
|
|
|
995 |
|
996 |
-
//
|
997 |
-
|
|
|
998 |
|
999 |
-
//
|
1000 |
-
|
1001 |
}
|
1002 |
|
1003 |
-
function
|
1004 |
-
|
1005 |
-
|
1006 |
-
|
1007 |
-
// Penalty for dying
|
1008 |
-
gameState.player.exp = Math.max(0, gameState.player.exp - 10);
|
1009 |
-
gameState.player.gold = Math.max(0, gameState.player.gold - 5);
|
1010 |
-
|
1011 |
-
// Restore some health
|
1012 |
-
gameState.player.health = Math.floor(gameState.player.maxHealth * 0.3);
|
1013 |
-
|
1014 |
-
// Update display
|
1015 |
-
updateCharacterDisplay();
|
1016 |
|
1017 |
-
|
1018 |
-
|
1019 |
-
|
1020 |
-
|
1021 |
-
|
1022 |
-
gameState.inCombat = false;
|
1023 |
-
gameState.currentEnemy = null;
|
1024 |
-
document.getElementById('combat-area').classList.add('hidden');
|
1025 |
-
}
|
1026 |
-
|
1027 |
-
function checkLevelUp() {
|
1028 |
-
if (gameState.player.exp >= gameState.player.expToNextLevel) {
|
1029 |
-
gameState.player.level++;
|
1030 |
-
gameState.player.exp -= gameState.player.expToNextLevel;
|
1031 |
-
gameState.player.expToNextLevel = Math.floor(gameState.player.expToNextLevel * 1.2);
|
1032 |
-
|
1033 |
-
// Improve stats
|
1034 |
-
gameState.player.maxHealth += 10;
|
1035 |
-
gameState.player.health = gameState.player.maxHealth;
|
1036 |
-
gameState.player.maxMana += 5;
|
1037 |
-
gameState.player.mana = gameState.player.maxMana;
|
1038 |
-
gameState.player.attack += 2;
|
1039 |
-
gameState.player.defense += 1;
|
1040 |
-
|
1041 |
-
addGameMessage(`Level up! You are now level ${gameState.player.level}!`, 'success');
|
1042 |
-
addGameMessage('Your stats have improved!', 'info');
|
1043 |
|
1044 |
-
|
1045 |
-
|
1046 |
-
}
|
1047 |
-
|
1048 |
-
function rest() {
|
1049 |
-
if (gameState.inCombat) {
|
1050 |
-
addGameMessage('You cannot rest while in combat!', 'error');
|
1051 |
-
return;
|
1052 |
-
}
|
1053 |
-
|
1054 |
-
// Restore health and mana
|
1055 |
-
const healthRestored = Math.floor(gameState.player.maxHealth * 0.3);
|
1056 |
-
const manaRestored = Math.floor(gameState.player.maxMana * 0.3);
|
1057 |
-
|
1058 |
-
gameState.player.health = Math.min(gameState.player.maxHealth, gameState.player.health + healthRestored);
|
1059 |
-
gameState.player.mana = Math.min(gameState.player.maxMana, gameState.player.mana + manaRestored);
|
1060 |
-
|
1061 |
-
addGameMessage(`You rest and recover ${healthRestored} health and ${manaRestored} mana.`, 'success');
|
1062 |
-
updateCharacterDisplay();
|
1063 |
-
}
|
1064 |
-
|
1065 |
-
function visitTown() {
|
1066 |
-
if (gameState.inCombat) {
|
1067 |
-
addGameMessage('You cannot visit town while in combat!', 'error');
|
1068 |
-
return;
|
1069 |
}
|
1070 |
|
1071 |
-
|
1072 |
-
|
1073 |
-
}
|
1074 |
-
|
1075 |
-
function leaveTown() {
|
1076 |
-
document.getElementById('town-area').classList.add('hidden');
|
1077 |
-
addGameMessage('You leave the town.', 'info');
|
1078 |
}
|
1079 |
|
1080 |
-
function
|
1081 |
-
|
1082 |
-
|
1083 |
-
|
1084 |
-
|
1085 |
-
addGameMessage('You enjoy a drink at the tavern and hear rumors of a dragon girl in the mountains.', 'info');
|
1086 |
-
}
|
1087 |
-
|
1088 |
-
function visitGuild() {
|
1089 |
-
addGameMessage('The Adventurer\'s Guild has no quests available right now.', 'info');
|
1090 |
-
}
|
1091 |
-
|
1092 |
-
function train() {
|
1093 |
-
if (gameState.inCombat) {
|
1094 |
-
addGameMessage('You cannot train while in combat!', 'error');
|
1095 |
-
return;
|
1096 |
-
}
|
1097 |
-
|
1098 |
-
// Training costs gold but improves stats
|
1099 |
-
if (gameState.player.gold < 5) {
|
1100 |
-
addGameMessage('You need at least 5 gold to train!', 'error');
|
1101 |
-
return;
|
1102 |
-
}
|
1103 |
-
|
1104 |
-
gameState.player.gold -= 5;
|
1105 |
|
1106 |
-
//
|
1107 |
-
const
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
addGameMessage(`After training, your attack increased by ${improvement}! (Cost: 5 gold)`, 'success');
|
1113 |
-
} else {
|
1114 |
-
gameState.player.defense += improvement;
|
1115 |
-
addGameMessage(`After training, your defense increased by ${improvement}! (Cost: 5 gold)`, 'success');
|
1116 |
}
|
1117 |
-
|
1118 |
-
updateCharacterDisplay();
|
1119 |
-
}
|
1120 |
-
|
1121 |
-
function openInventory() {
|
1122 |
-
document.getElementById('inventory-modal').classList.remove('hidden');
|
1123 |
}
|
1124 |
|
1125 |
-
function
|
1126 |
-
|
1127 |
-
}
|
1128 |
-
|
1129 |
-
function openQuests() {
|
1130 |
-
addGameMessage('You have no active quests at the moment.', 'info');
|
1131 |
-
}
|
1132 |
-
|
1133 |
-
function saveGame() {
|
1134 |
-
localStorage.setItem('monstergirlRpgSave', JSON.stringify(gameState));
|
1135 |
-
addGameMessage('Game saved successfully!', 'success');
|
1136 |
-
}
|
1137 |
-
|
1138 |
-
function loadGame() {
|
1139 |
-
const savedGame = localStorage.getItem('monstergirlRpgSave');
|
1140 |
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1156 |
}
|
1157 |
}
|
1158 |
|
1159 |
-
|
1160 |
-
|
1161 |
-
}
|
1162 |
-
|
1163 |
-
function hideCredits() {
|
1164 |
-
document.getElementById('credits-modal').classList.add('hidden');
|
1165 |
-
}
|
1166 |
-
|
1167 |
-
function showDamageText(element, damage, color = 'red') {
|
1168 |
-
const damageText = document.createElement('div');
|
1169 |
-
damageText.className = 'damage-text';
|
1170 |
-
damageText.style.color = color;
|
1171 |
-
damageText.textContent = `-${damage}`;
|
1172 |
-
damageText.style.left = '50%';
|
1173 |
-
damageText.style.transform = 'translateX(-50%)';
|
1174 |
-
|
1175 |
-
element.appendChild(damageText);
|
1176 |
-
|
1177 |
-
// Remove after animation
|
1178 |
-
setTimeout(() => {
|
1179 |
-
damageText.remove();
|
1180 |
-
}, 1000);
|
1181 |
-
}
|
1182 |
-
|
1183 |
-
function capitalizeFirstLetter(string) {
|
1184 |
-
return string.charAt(0).toUpperCase() + string.slice(1);
|
1185 |
-
}
|
1186 |
-
|
1187 |
-
// Initialize game
|
1188 |
-
document.addEventListener('DOMContentLoaded', () => {
|
1189 |
-
addGameMessage('Welcome to Monstergirl RPG!');
|
1190 |
-
});
|
1191 |
</script>
|
1192 |
<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=lunarflu/rpg" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
1193 |
</html>
|
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Monster Girl Academy: Heartstrings</title>
|
7 |
<script src="https://cdn.tailwindcss.com"></script>
|
8 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
9 |
<style>
|
10 |
+
@keyframes float {
|
11 |
+
0% { transform: translateY(0px); }
|
12 |
+
50% { transform: translateY(-10px); }
|
13 |
+
100% { transform: translateY(0px); }
|
14 |
}
|
15 |
+
.floating {
|
16 |
+
animation: float 3s ease-in-out infinite;
|
|
|
|
|
17 |
}
|
18 |
+
.bg-academy {
|
19 |
+
background-image: url('https://images.unsplash.com/photo-1588072432836-e10032774350?q=80&w=2072&auto=format&fit=crop');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
background-size: cover;
|
21 |
background-position: center;
|
22 |
}
|
|
|
|
|
|
|
|
|
|
|
23 |
.character-card {
|
24 |
transition: all 0.3s ease;
|
25 |
+
transform-style: preserve-3d;
|
26 |
}
|
27 |
.character-card:hover {
|
28 |
+
transform: scale(1.05) rotateY(5deg);
|
29 |
+
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
|
30 |
+
}
|
31 |
+
.stat-bar {
|
32 |
+
height: 6px;
|
33 |
+
transition: width 0.5s ease;
|
34 |
+
}
|
35 |
+
.dialogue-box {
|
36 |
+
min-height: 200px;
|
37 |
+
background: rgba(255, 255, 255, 0.9);
|
38 |
+
border-radius: 15px;
|
39 |
+
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
40 |
+
}
|
41 |
+
.choice-btn {
|
42 |
+
transition: all 0.2s ease;
|
43 |
}
|
44 |
+
.choice-btn:hover {
|
45 |
+
transform: translateY(-3px);
|
46 |
+
box-shadow: 0 5px 10px rgba(0,0,0,0.1);
|
47 |
+
}
|
48 |
+
.character-portrait {
|
49 |
+
filter: drop-shadow(0 5px 10px rgba(0,0,0,0.2));
|
|
|
50 |
}
|
51 |
</style>
|
52 |
</head>
|
53 |
+
<body class="bg-gray-100 font-sans">
|
54 |
+
<!-- Main Game Container -->
|
55 |
+
<div class="container mx-auto px-4 py-8 max-w-6xl">
|
56 |
+
<!-- Header -->
|
57 |
+
<header class="bg-purple-900 text-white rounded-xl p-6 mb-8 shadow-lg bg-academy relative overflow-hidden">
|
58 |
+
<div class="absolute inset-0 bg-black opacity-40"></div>
|
59 |
+
<div class="relative z-10 flex flex-col items-center">
|
60 |
+
<h1 class="text-4xl md:text-5xl font-bold mb-2 text-center floating">Monster Girl Academy: Heartstrings</h1>
|
61 |
+
<p class="text-xl text-purple-200 mb-4 text-center">Where bonds transcend species</p>
|
62 |
+
<div class="flex space-x-4">
|
63 |
+
<button id="newGameBtn" class="bg-pink-600 hover:bg-pink-700 text-white px-6 py-2 rounded-full font-semibold transition">New Game</button>
|
64 |
+
<button id="loadGameBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-6 py-2 rounded-full font-semibold transition">Load Game</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
</div>
|
66 |
+
</div>
|
67 |
+
</header>
|
68 |
+
|
69 |
+
<!-- Game Area (initially hidden) -->
|
70 |
+
<div id="gameArea" class="hidden">
|
71 |
+
<!-- Top Bar - Game Info -->
|
72 |
+
<div class="bg-white rounded-xl p-4 mb-6 shadow-md flex flex-wrap justify-between items-center">
|
73 |
+
<div class="flex items-center space-x-4 mb-2 sm:mb-0">
|
74 |
+
<div class="bg-yellow-100 p-2 rounded-lg">
|
75 |
+
<i class="fas fa-calendar-day text-yellow-600"></i>
|
76 |
+
<span id="gameDay" class="font-semibold ml-1">Day 1</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
</div>
|
78 |
+
<div class="bg-blue-100 p-2 rounded-lg">
|
79 |
+
<i class="fas fa-clock text-blue-600"></i>
|
80 |
+
<span id="gameTime" class="font-semibold ml-1">Morning</span>
|
|
|
|
|
|
|
81 |
</div>
|
82 |
</div>
|
83 |
+
<div class="flex items-center space-x-4">
|
84 |
+
<div class="bg-green-100 p-2 rounded-lg">
|
85 |
+
<i class="fas fa-coins text-green-600"></i>
|
86 |
+
<span id="gameMoney" class="font-semibold ml-1">100</span>
|
|
|
|
|
|
|
|
|
87 |
</div>
|
88 |
+
<div class="bg-red-100 p-2 rounded-lg">
|
89 |
+
<i class="fas fa-heart text-red-600"></i>
|
90 |
+
<span id="gameEnergy" class="font-semibold ml-1">10/10</span>
|
|
|
|
|
|
|
|
|
91 |
</div>
|
92 |
</div>
|
93 |
</div>
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
+
<!-- Main Content Area -->
|
96 |
+
<div class="flex flex-col lg:flex-row gap-6">
|
97 |
+
<!-- Left Side - Characters -->
|
98 |
+
<div class="w-full lg:w-1/4">
|
99 |
+
<div class="bg-white rounded-xl p-4 shadow-md mb-6">
|
100 |
+
<h2 class="text-xl font-bold mb-4 text-purple-800 border-b pb-2">Your Connections</h2>
|
101 |
+
<div id="characterList" class="space-y-4">
|
102 |
+
<!-- Characters will be dynamically added here -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
</div>
|
104 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
+
<div class="bg-white rounded-xl p-4 shadow-md">
|
107 |
+
<h2 class="text-xl font-bold mb-4 text-purple-800 border-b pb-2">Your Stats</h2>
|
108 |
+
<div class="space-y-3">
|
109 |
+
<div>
|
110 |
+
<p class="text-sm font-medium text-gray-700 mb-1">Charm <span class="float-right">50%</span></p>
|
111 |
+
<div class="w-full bg-gray-200 rounded-full h-1.5">
|
112 |
+
<div class="bg-pink-500 h-1.5 rounded-full stat-bar" style="width: 50%"></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
</div>
|
114 |
+
</div>
|
115 |
+
<div>
|
116 |
+
<p class="text-sm font-medium text-gray-700 mb-1">Intelligence <span class="float-right">30%</span></p>
|
117 |
+
<div class="w-full bg-gray-200 rounded-full h-1.5">
|
118 |
+
<div class="bg-blue-500 h-1.5 rounded-full stat-bar" style="width: 30%"></div>
|
119 |
</div>
|
|
|
120 |
</div>
|
121 |
+
<div>
|
122 |
+
<p class="text-sm font-medium text-gray-700 mb-1">Courage <span class="float-right">70%</span></p>
|
123 |
+
<div class="w-full bg-gray-200 rounded-full h-1.5">
|
124 |
+
<div class="bg-yellow-500 h-1.5 rounded-full stat-bar" style="width: 70%"></div>
|
125 |
+
</div>
|
126 |
+
</div>
|
127 |
+
<div>
|
128 |
+
<p class="text-sm font-medium text-gray-700 mb-1">Empathy <span class="float-right">40%</span></p>
|
129 |
+
<div class="w-full bg-gray-200 rounded-full h-1.5">
|
130 |
+
<div class="bg-green-500 h-1.5 rounded-full stat-bar" style="width: 40%"></div>
|
131 |
</div>
|
|
|
132 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
</div>
|
134 |
</div>
|
135 |
</div>
|
|
|
|
|
136 |
|
137 |
+
<!-- Center - Main Game View -->
|
138 |
+
<div class="w-full lg:w-2/4">
|
139 |
+
<div class="bg-white rounded-xl p-6 shadow-md mb-6 dialogue-box">
|
140 |
+
<div id="mainEvent" class="text-center py-8">
|
141 |
+
<h2 class="text-2xl font-bold text-purple-900 mb-4">Welcome to Monster Girl Academy</h2>
|
142 |
+
<p class="text-gray-700 mb-6">As the first human student admitted to this prestigious academy for magical beings, you'll navigate complex relationships with fascinating creatures from all walks of life. Each choice shapes your story and determines who you'll become by year's end.</p>
|
143 |
+
<button id="startAdventureBtn" class="bg-purple-600 hover:bg-purple-700 text-white px-8 py-3 rounded-full font-semibold text-lg transition">Begin Your Journey</button>
|
144 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
</div>
|
146 |
+
|
147 |
+
<div id="choicesContainer" class="grid grid-cols-1 md:grid-cols-2 gap-4 hidden">
|
148 |
+
<!-- Choices will be dynamically added here -->
|
|
|
|
|
|
|
|
|
149 |
</div>
|
150 |
</div>
|
151 |
+
|
152 |
+
<!-- Right Side - Calendar and Notifications -->
|
153 |
+
<div class="w-full lg:w-1/4">
|
154 |
+
<div class="bg-white rounded-xl p-4 shadow-md mb-6">
|
155 |
+
<h2 class="text-xl font-bold mb-4 text-purple-800 border-b pb-2">Academy Calendar</h2>
|
156 |
+
<div class="grid grid-cols-7 gap-1 text-center mb-2">
|
157 |
+
<div class="text-xs font-semibold">S</div>
|
158 |
+
<div class="text-xs font-semibold">M</div>
|
159 |
+
<div class="text-xs font-semibold">T</div>
|
160 |
+
<div class="text-xs font-semibold">W</div>
|
161 |
+
<div class="text-xs font-semibold">T</div>
|
162 |
+
<div class="text-xs font-semibold">F</div>
|
163 |
+
<div class="text-xs font-semibold">S</div>
|
164 |
</div>
|
165 |
+
<div class="grid grid-cols-7 gap-1 text-center">
|
166 |
+
<!-- Calendar days will be dynamically added here -->
|
167 |
+
<div class="p-1 text-xs opacity-30">29</div>
|
168 |
+
<div class="p-1 text-xs opacity-30">30</div>
|
169 |
+
<div class="p-1 text-xs opacity-30">31</div>
|
170 |
+
<div class="p-1 text-xs border rounded-full bg-purple-100 font-semibold">1</div>
|
171 |
+
<div class="p-1 text-xs">2</div>
|
172 |
+
<div class="p-1 text-xs">3</div>
|
173 |
+
<div class="p-1 text-xs">4</div>
|
174 |
+
<div class="p-1 text-xs">5</div>
|
175 |
+
<div class="p-1 text-xs">6</div>
|
176 |
+
<div class="p-1 text-xs">7</div>
|
177 |
+
<div class="p-1 text-xs">8</div>
|
178 |
+
<div class="p-1 text-xs">9</div>
|
179 |
+
<div class="p-1 text-xs">10</div>
|
180 |
+
<div class="p-1 text-xs">11</div>
|
181 |
+
<div class="p-1 text-xs">12</div>
|
182 |
+
<div class="p-1 text-xs">13</div>
|
183 |
+
<div class="p-1 text-xs">14</div>
|
184 |
+
<div class="p-1 text-xs">15</div>
|
185 |
+
<div class="p-1 text-xs">16</div>
|
186 |
+
<div class="p-1 text-xs">17</div>
|
187 |
+
<div class="p-1 text-xs">18</div>
|
188 |
+
<div class="p-1 text-xs">19</div>
|
189 |
+
<div class="p-1 text-xs">20</div>
|
190 |
+
<div class="p-1 text-xs">21</div>
|
191 |
+
<div class="p-1 text-xs">22</div>
|
192 |
+
<div class="p-1 text-xs">23</div>
|
193 |
+
<div class="p-1 text-xs">24</div>
|
194 |
+
<div class="p-1 text-xs">25</div>
|
195 |
+
<div class="p-1 text-xs">26</div>
|
196 |
+
<div class="p-1 text-xs">27</div>
|
197 |
+
<div class="p-1 text-xs">28</div>
|
198 |
+
<div class="p-1 text-xs">29</div>
|
199 |
+
<div class="p-1 text-xs">30</div>
|
200 |
+
<div class="p-1 text-xs opacity-30">1</div>
|
201 |
+
<div class="p-1 text-xs opacity-30">2</div>
|
202 |
+
</div>
|
203 |
+
<div class="mt-4 pt-2 border-t">
|
204 |
+
<h3 class="font-semibold text-sm mb-2">Upcoming Events</h3>
|
205 |
+
<ul class="text-xs space-y-1">
|
206 |
+
<li class="flex items-center"><span class="w-2 h-2 bg-pink-500 rounded-full mr-2"></span> Moonlight Festival - Week 2</li>
|
207 |
+
<li class="flex items-center"><span class="w-2 h-2 bg-blue-500 rounded-full mr-2"></span> Midterms - Week 6</li>
|
208 |
+
<li class="flex items-center"><span class="w-2 h-2 bg-green-500 rounded-full mr-2"></span> Sports Day - Week 8</li>
|
209 |
+
</ul>
|
210 |
</div>
|
211 |
</div>
|
|
|
|
|
|
|
212 |
|
213 |
+
<div class="bg-white rounded-xl p-4 shadow-md">
|
214 |
+
<h2 class="text-xl font-bold mb-4 text-purple-800 border-b pb-2">Notifications</h2>
|
215 |
+
<div id="notifications" class="space-y-3">
|
216 |
+
<div class="p-2 bg-blue-50 rounded-lg text-sm">
|
217 |
+
<p class="font-medium">Welcome to Monster Girl Academy!</p>
|
218 |
+
<p class="text-xs text-gray-600">Find your dorm in the West Wing</p>
|
219 |
+
</div>
|
220 |
+
<div class="p-2 bg-yellow-50 rounded-lg text-sm">
|
221 |
+
<p class="font-medium">Orientation at 10AM</p>
|
222 |
+
<p class="text-xs text-gray-600">Main Hall, don't be late!</p>
|
223 |
+
</div>
|
224 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
</div>
|
226 |
</div>
|
227 |
</div>
|
|
|
231 |
<script>
|
232 |
// Game State
|
233 |
const gameState = {
|
234 |
+
day: 1,
|
235 |
+
time: 'Morning',
|
236 |
+
energy: 10,
|
237 |
+
maxEnergy: 10,
|
238 |
+
money: 100,
|
239 |
+
stats: {
|
240 |
+
charm: 50,
|
241 |
+
intelligence: 30,
|
242 |
+
courage: 70,
|
243 |
+
empathy: 40
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
},
|
245 |
+
relationships: {},
|
246 |
+
currentEvent: null,
|
247 |
+
eventHistory: [],
|
248 |
+
flags: {}
|
249 |
};
|
250 |
|
251 |
+
// Monster Girls Database
|
252 |
+
const monstergirls = {
|
253 |
+
seraphina: {
|
254 |
+
id: 'seraphina',
|
255 |
+
name: 'Seraphina',
|
256 |
+
species: 'Lamia',
|
257 |
+
title: 'The Serpent Prodigy',
|
258 |
+
personality: 'Intelligent, ambitious, but socially awkward',
|
259 |
+
initialStats: {
|
260 |
+
trust: 30,
|
261 |
+
affection: 20,
|
262 |
+
curiosity: 60,
|
263 |
+
respect: 50
|
264 |
+
},
|
265 |
+
image: 'lamia.png',
|
266 |
+
color: 'bg-green-100',
|
267 |
+
textColor: 'text-green-800',
|
268 |
+
borderColor: 'border-green-300',
|
269 |
+
likes: ['Ancient history', 'Intellectual debates', 'Quiet libraries'],
|
270 |
+
dislikes: ['Small talk', 'Disorganization', 'Loud noises'],
|
271 |
+
events: [
|
272 |
+
{
|
273 |
+
id: 'library_encounter',
|
274 |
+
title: 'Unexpected Study Partner',
|
275 |
+
description: 'You find Seraphina surrounded by ancient tomes in the library. She seems frustrated with a particularly difficult text.',
|
276 |
+
choices: [
|
277 |
+
{
|
278 |
+
text: 'Offer to help with the research',
|
279 |
+
requirements: { intelligence: 40 },
|
280 |
+
outcomes: [
|
281 |
+
{ type: 'stat', target: 'seraphina', stat: 'trust', change: 10 },
|
282 |
+
{ type: 'stat', target: 'seraphina', stat: 'affection', change: 5 },
|
283 |
+
{ type: 'stat', target: 'player', stat: 'intelligence', change: 5 },
|
284 |
+
{ type: 'flag', id: 'helped_seraphina_research', value: true }
|
285 |
+
]
|
286 |
+
},
|
287 |
+
{
|
288 |
+
text: 'Ask if she wants to take a break and get some air',
|
289 |
+
outcomes: [
|
290 |
+
{ type: 'stat', target: 'seraphina', stat: 'affection', change: -5 },
|
291 |
+
{ type: 'dialogue', text: "Seraphina glares at you. 'I don't have time for breaks. Some of us take our studies seriously.'" }
|
292 |
+
]
|
293 |
+
},
|
294 |
+
{
|
295 |
+
text: 'Quietly sit nearby and study your own materials',
|
296 |
+
outcomes: [
|
297 |
+
{ type: 'stat', target: 'seraphina', stat: 'respect', change: 5 },
|
298 |
+
{ type: 'dialogue', text: "Seraphina glances at you occasionally, seeming to appreciate your quiet diligence." }
|
299 |
+
]
|
300 |
+
}
|
301 |
+
]
|
302 |
+
},
|
303 |
+
// More events for Seraphina...
|
304 |
+
]
|
305 |
},
|
306 |
+
marigold: {
|
307 |
+
id: 'marigold',
|
308 |
+
name: 'Marigold',
|
309 |
+
species: 'Slimegirl',
|
310 |
+
title: 'The Bubbly Alchemist',
|
311 |
+
personality: 'Cheerful, curious, but easily distracted',
|
312 |
+
initialStats: {
|
313 |
+
trust: 50,
|
314 |
+
affection: 40,
|
315 |
+
curiosity: 70,
|
316 |
+
respect: 30
|
317 |
+
},
|
318 |
+
image: 'slime.png',
|
319 |
+
color: 'bg-blue-100',
|
320 |
+
textColor: 'text-blue-800',
|
321 |
+
borderColor: 'border-blue-300',
|
322 |
+
likes: ['New experiences', 'Sweet treats', 'Colorful things'],
|
323 |
+
dislikes: ['Being ignored', 'Boring routines', 'Hot temperatures'],
|
324 |
+
events: [
|
325 |
+
{
|
326 |
+
id: 'lab_accident',
|
327 |
+
title: 'Sticky Situation',
|
328 |
+
description: 'Marigold has accidentally turned herself bright pink during an alchemy experiment and is panicking about how to fix it.',
|
329 |
+
choices: [
|
330 |
+
{
|
331 |
+
text: 'Help her find the antidote in the alchemy books',
|
332 |
+
requirements: { intelligence: 30 },
|
333 |
+
outcomes: [
|
334 |
+
{ type: 'stat', target: 'marigold', stat: 'trust', change: 15 },
|
335 |
+
{ type: 'stat', target: 'player', stat: 'intelligence', change: 5 },
|
336 |
+
{ type: 'dialogue', text: "'You're so smart!' Marigold bubbles happily as you find the solution. 'Let's make the antidote together!'" }
|
337 |
+
]
|
338 |
+
},
|
339 |
+
{
|
340 |
+
text: 'Tell her the pink actually looks cute on her',
|
341 |
+
outcomes: [
|
342 |
+
{ type: 'stat', target: 'marigold', stat: 'affection', change: 10 },
|
343 |
+
{ type: 'dialogue', text: "Marigold giggles and wobbles excitedly. 'You really think so? Maybe I'll stay pink for a while longer!'" }
|
344 |
+
]
|
345 |
+
},
|
346 |
+
{
|
347 |
+
text: 'Report the accident to the professor',
|
348 |
+
outcomes: [
|
349 |
+
{ type: 'stat', target: 'marigold', stat: 'trust', change: -10 },
|
350 |
+
{ type: 'stat', target: 'marigold', stat: 'affection', change: -15 },
|
351 |
+
{ type: 'dialogue', text: "'Snitches get stitches!' Marigold pouts as the professor scolds her. She seems really upset with you." }
|
352 |
+
]
|
353 |
+
}
|
354 |
+
]
|
355 |
+
},
|
356 |
+
// More events for Marigold...
|
357 |
+
]
|
358 |
},
|
359 |
+
// More monster girls...
|
360 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
361 |
|
362 |
+
// Initialize relationships
|
363 |
+
function initRelationships() {
|
364 |
+
for (const girlId in monstergirls) {
|
365 |
+
gameState.relationships[girlId] = { ...monstergirls[girlId].initialStats };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
366 |
}
|
|
|
|
|
367 |
}
|
368 |
|
369 |
+
// DOM Elements
|
370 |
+
const newGameBtn = document.getElementById('newGameBtn');
|
371 |
+
const loadGameBtn = document.getElementById('loadGameBtn');
|
372 |
+
const gameArea = document.getElementById('gameArea');
|
373 |
+
const startAdventureBtn = document.getElementById('startAdventureBtn');
|
374 |
+
const mainEvent = document.getElementById('mainEvent');
|
375 |
+
const choicesContainer = document.getElementById('choicesContainer');
|
376 |
+
const characterList = document.getElementById('characterList');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
377 |
|
378 |
+
// Event Listeners
|
379 |
+
newGameBtn.addEventListener('click', startNewGame);
|
380 |
+
loadGameBtn.addEventListener('click', loadGame);
|
381 |
+
startAdventureBtn.addEventListener('click', beginAdventure);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
382 |
|
383 |
+
// Game Functions
|
384 |
+
function startNewGame() {
|
385 |
+
// Reset game state
|
386 |
+
gameState.day = 1;
|
387 |
+
gameState.time = 'Morning';
|
388 |
+
gameState.energy = 10;
|
389 |
+
gameState.money = 100;
|
390 |
+
gameState.stats = {
|
391 |
+
charm: 50,
|
392 |
+
intelligence: 30,
|
393 |
+
courage: 70,
|
394 |
+
empathy: 40
|
395 |
+
};
|
396 |
+
gameState.eventHistory = [];
|
397 |
+
gameState.flags = {};
|
398 |
|
399 |
+
initRelationships();
|
400 |
+
|
401 |
+
// Show game area
|
402 |
+
gameArea.classList.remove('hidden');
|
|
|
|
|
|
|
|
|
|
|
403 |
|
404 |
+
// Update UI
|
405 |
+
updateGameInfo();
|
406 |
+
renderCharacterList();
|
407 |
|
408 |
+
// Start with first event
|
409 |
+
triggerEvent('welcome_event');
|
410 |
}
|
411 |
|
412 |
+
function loadGame() {
|
413 |
+
// In a real game, this would load from localStorage
|
414 |
+
alert('Load game functionality would go here! For now, starting a new game.');
|
415 |
+
startNewGame();
|
416 |
+
}
|
417 |
+
|
418 |
+
function beginAdventure() {
|
419 |
+
triggerEvent('orientation_event');
|
420 |
+
}
|
421 |
+
|
422 |
+
function triggerEvent(eventId) {
|
423 |
+
// Special events
|
424 |
+
if (eventId === 'welcome_event') {
|
425 |
+
mainEvent.innerHTML = `
|
426 |
+
<div class="flex flex-col items-center">
|
427 |
+
<img src="https://i.imgur.com/JQl1D1X.png" alt="Academy Gates" class="w-full max-w-md rounded-lg mb-4 character-portrait">
|
428 |
+
<h2 class="text-2xl font-bold text-purple-900 mb-4">The Academy Gates</h2>
|
429 |
+
<p class="text-gray-700 mb-4">The towering gates of Monster Girl Academy loom before you, their intricate ironwork depicting scenes of legendary creatures. As the first human student, you're not sure what to expect from this year.</p>
|
430 |
+
<p class="text-gray-700 mb-6">A cheerful harpy flies down to greet you. "Welcome! Orientation starts in an hour at the Main Hall. Until then, feel free to explore the grounds!"</p>
|
431 |
+
<div class="flex space-x-4">
|
432 |
+
<button class="event-choice-btn bg-purple-600 hover:bg-purple-700 text-white px-6 py-2 rounded-full font-semibold transition" data-choice="explore">Explore the Campus</button>
|
433 |
+
<button class="event-choice-btn bg-gray-600 hover:bg-gray-700 text-white px-6 py-2 rounded-full font-semibold transition" data-choice="dorm">Go Straight to Your Dorm</button>
|
434 |
+
</div>
|
435 |
+
</div>
|
436 |
+
`;
|
437 |
|
438 |
+
// Add event listeners to choice buttons
|
439 |
+
document.querySelectorAll('.event-choice-btn').forEach(btn => {
|
440 |
+
btn.addEventListener('click', function() {
|
441 |
+
const choice = this.getAttribute('data-choice');
|
442 |
+
if (choice === 'explore') {
|
443 |
+
triggerEvent('campus_exploration');
|
444 |
+
} else {
|
445 |
+
triggerEvent('dorm_settle');
|
446 |
+
}
|
|
|
|
|
|
|
|
|
|
|
447 |
});
|
448 |
+
});
|
449 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
450 |
return;
|
451 |
}
|
452 |
|
453 |
+
// Find a random event from any girl
|
454 |
+
const availableGirls = Object.values(monstergirls).filter(girl =>
|
455 |
+
!gameState.eventHistory.includes(girl.events[0].id)
|
456 |
+
);
|
457 |
|
458 |
+
if (availableGirls.length > 0) {
|
459 |
+
const randomGirl = availableGirls[Math.floor(Math.random() * availableGirls.length)];
|
460 |
+
const girlEvent = randomGirl.events[0];
|
461 |
+
gameState.currentEvent = girlEvent;
|
462 |
+
gameState.eventHistory.push(girlEvent.id);
|
463 |
+
|
464 |
+
displayEvent(girlEvent, randomGirl);
|
465 |
} else {
|
466 |
+
// No more events (shouldn't happen in demo)
|
467 |
+
mainEvent.innerHTML = `
|
468 |
+
<div class="text-center py-8">
|
469 |
+
<h2 class="text-2xl font-bold text-purple-900 mb-4">End of Demo</h2>
|
470 |
+
<p class="text-gray-700 mb-6">This concludes our preview of Monster Girl Academy: Heartstrings. In the full game, you'd experience dozens more events, deeper relationships, and multiple endings with each character.</p>
|
471 |
+
<button onclick="startNewGame()" class="bg-purple-600 hover:bg-purple-700 text-white px-8 py-3 rounded-full font-semibold text-lg transition">Play Again</button>
|
472 |
+
</div>
|
473 |
+
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
474 |
}
|
|
|
|
|
|
|
|
|
|
|
475 |
}
|
476 |
|
477 |
+
function displayEvent(event, girl) {
|
478 |
+
mainEvent.innerHTML = `
|
479 |
+
<div class="flex flex-col md:flex-row items-center md:items-start">
|
480 |
+
<img src="https://i.imgur.com/${girl.image || 'JQl1D1X.png'}" alt="${girl.name}" class="w-full max-w-xs rounded-lg mb-4 md:mb-0 md:mr-6 character-portrait">
|
481 |
+
<div>
|
482 |
+
<div class="flex items-center mb-2">
|
483 |
+
<h2 class="text-2xl font-bold ${girl.textColor}">${girl.name}</h2>
|
484 |
+
<span class="ml-2 px-2 py-1 text-xs rounded-full ${girl.color} ${girl.textColor}">${girl.species}</span>
|
485 |
+
</div>
|
486 |
+
<p class="text-gray-700 mb-4">${event.description}</p>
|
487 |
+
</div>
|
488 |
+
</div>
|
489 |
+
`;
|
490 |
|
491 |
+
// Display choices
|
492 |
+
choicesContainer.innerHTML = '';
|
493 |
+
choicesContainer.classList.remove('hidden');
|
494 |
|
495 |
+
event.choices.forEach((choice, index) => {
|
496 |
+
const choiceBtn = document.createElement('button');
|
497 |
+
choiceBtn.className = `choice-btn bg-white hover:bg-gray-50 border ${girl.borderColor} text-gray-800 px-4 py-3 rounded-lg font-medium text-left`;
|
498 |
+
choiceBtn.textContent = choice.text;
|
|
|
|
|
|
|
499 |
|
500 |
+
// Check requirements
|
501 |
+
let meetsRequirements = true;
|
502 |
+
if (choice.requirements) {
|
503 |
+
for (const stat in choice.requirements) {
|
504 |
+
if (gameState.stats[stat] < choice.requirements[stat]) {
|
505 |
+
meetsRequirements = false;
|
506 |
+
choiceBtn.className = `choice-btn bg-gray-100 border border-gray-200 text-gray-400 px-4 py-3 rounded-lg font-medium text-left cursor-not-allowed`;
|
507 |
+
choiceBtn.title = `Requires ${stat} ${choice.requirements[stat]}`;
|
508 |
+
}
|
509 |
+
}
|
510 |
+
}
|
511 |
|
512 |
+
if (meetsRequirements) {
|
513 |
+
choiceBtn.addEventListener('click', () => handleChoice(choice, girl));
|
|
|
514 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
515 |
|
516 |
+
choicesContainer.appendChild(choiceBtn);
|
517 |
+
});
|
518 |
+
}
|
519 |
+
|
520 |
+
function handleChoice(choice, girl) {
|
521 |
+
// Apply outcomes
|
522 |
+
choice.outcomes.forEach(outcome => {
|
523 |
+
if (outcome.type === 'stat') {
|
524 |
+
if (outcome.target === 'player') {
|
525 |
+
gameState.stats[outcome.stat] += outcome.change;
|
526 |
+
gameState.stats[outcome.stat] = Math.max(0, Math.min(100, gameState.stats[outcome.stat]));
|
527 |
+
} else {
|
528 |
+
gameState.relationships[girl.id][outcome.stat] += outcome.change;
|
529 |
+
gameState.relationships[girl.id][outcome.stat] = Math.max(0, Math.min(100, gameState.relationships[girl.id][outcome.stat]));
|
530 |
+
}
|
531 |
+
} else if (outcome.type === 'flag') {
|
532 |
+
gameState.flags[outcome.id] = outcome.value;
|
533 |
+
} else if (outcome.type === 'dialogue') {
|
534 |
+
// Show dialogue (simplified for demo)
|
535 |
+
alert(outcome.text);
|
536 |
+
}
|
537 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
538 |
|
539 |
+
// Advance time
|
540 |
+
advanceTime();
|
541 |
|
542 |
+
// Update UI
|
543 |
+
updateGameInfo();
|
544 |
+
renderCharacterList();
|
545 |
|
546 |
+
// Trigger next event
|
547 |
+
triggerEvent('random');
|
548 |
}
|
549 |
|
550 |
+
function advanceTime() {
|
551 |
+
// Simplified time system for demo
|
552 |
+
const times = ['Morning', 'Afternoon', 'Evening', 'Night'];
|
553 |
+
const currentIndex = times.indexOf(gameState.time);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
554 |
|
555 |
+
if (currentIndex < times.length - 1) {
|
556 |
+
gameState.time = times[currentIndex + 1];
|
557 |
+
} else {
|
558 |
+
gameState.time = 'Morning';
|
559 |
+
gameState.day++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
560 |
|
561 |
+
// Restore some energy each new day
|
562 |
+
gameState.energy = Math.min(gameState.maxEnergy, gameState.energy + 5);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
563 |
}
|
564 |
|
565 |
+
// Spend energy
|
566 |
+
gameState.energy = Math.max(0, gameState.energy - 2);
|
|
|
|
|
|
|
|
|
|
|
567 |
}
|
568 |
|
569 |
+
function updateGameInfo() {
|
570 |
+
document.getElementById('gameDay').textContent = `Day ${gameState.day}`;
|
571 |
+
document.getElementById('gameTime').textContent = gameState.time;
|
572 |
+
document.getElementById('gameMoney').textContent = gameState.money;
|
573 |
+
document.getElementById('gameEnergy').textContent = `${gameState.energy}/${gameState.maxEnergy}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
574 |
|
575 |
+
// Update stat bars
|
576 |
+
for (const stat in gameState.stats) {
|
577 |
+
const statElements = document.querySelectorAll(`.stat-bar[data-stat="${stat}"]`);
|
578 |
+
statElements.forEach(el => {
|
579 |
+
el.style.width = `${gameState.stats[stat]}%`;
|
580 |
+
});
|
|
|
|
|
|
|
|
|
581 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
582 |
}
|
583 |
|
584 |
+
function renderCharacterList() {
|
585 |
+
characterList.innerHTML = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
586 |
|
587 |
+
for (const girlId in monstergirls) {
|
588 |
+
const girl = monstergirls[girlId];
|
589 |
+
const relationship = gameState.relationships[girlId];
|
590 |
+
|
591 |
+
const girlCard = document.createElement('div');
|
592 |
+
girlCard.className = `character-card ${girl.color} ${girl.borderColor} border-2 p-3 rounded-lg flex items-center`;
|
593 |
+
|
594 |
+
// Calculate overall relationship percentage (simplified)
|
595 |
+
const totalStats = Object.values(relationship).reduce((a, b) => a + b, 0);
|
596 |
+
const relationshipPercent = Math.floor(totalStats / (Object.keys(relationship).length * 100) * 100);
|
597 |
+
|
598 |
+
girlCard.innerHTML = `
|
599 |
+
<div class="w-12 h-12 rounded-full ${girl.color} border-2 ${girl.borderColor} mr-3 flex-shrink-0 overflow-hidden">
|
600 |
+
<img src="https://i.imgur.com/${girl.image || 'JQl1D1X.png'}" alt="${girl.name}" class="w-full h-full object-cover">
|
601 |
+
</div>
|
602 |
+
<div class="flex-grow">
|
603 |
+
<h3 class="font-semibold ${girl.textColor}">${girl.name}</h3>
|
604 |
+
<p class="text-xs text-gray-600">${girl.species}</p>
|
605 |
+
<div class="w-full bg-gray-200 rounded-full h-1.5 mt-1">
|
606 |
+
<div class="h-1.5 rounded-full ${girl.borderColor.replace('border', 'bg')}" style="width: ${relationshipPercent}%"></div>
|
607 |
+
</div>
|
608 |
+
</div>
|
609 |
+
`;
|
610 |
+
|
611 |
+
characterList.appendChild(girlCard);
|
612 |
}
|
613 |
}
|
614 |
|
615 |
+
// Initialize
|
616 |
+
initRelationships();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
617 |
</script>
|
618 |
<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=lunarflu/rpg" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
619 |
</html>
|