Spaces:
Running
Running
Update index.html
Browse files- index.html +183 -254
index.html
CHANGED
@@ -3,41 +3,29 @@
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
-
<title>Thronglets Simulation (
|
7 |
<style>
|
8 |
:root {
|
9 |
-
--grass-dark: #2a6141;
|
10 |
-
--
|
11 |
-
--
|
12 |
-
--rock-dark: #6b727c;
|
13 |
-
--rock-light: #89919c;
|
14 |
-
--tree-trunk: #6f4e37;
|
15 |
-
--tree-leaves: #2b602c;
|
16 |
-
--ui-bg: #e0cda9; /* Parchment/Light wood */
|
17 |
-
--ui-border: #8b4513; /* SaddleBrown */
|
18 |
-
--ui-accent: #6d8c4f; /* Green accent */
|
19 |
-
--ui-text: #3a2e20; /* Dark brown text */
|
20 |
}
|
21 |
|
22 |
body {
|
23 |
margin: 0; overflow: hidden; background: var(--grass-dark);
|
24 |
-
color: #eee; font-family: 'Verdana', sans-serif;
|
25 |
-
|
26 |
-
|
27 |
}
|
28 |
|
29 |
.game-container {
|
30 |
position: relative; width: 95vmin; height: 70vmin;
|
31 |
max-width: 1000px; max-height: 700px;
|
32 |
-
|
33 |
-
background-image: radial-gradient(var(--grass-dark) 15%, transparent 16%),
|
34 |
-
radial-gradient(var(--grass-dark) 15%, transparent 16%);
|
35 |
-
background-size: 30px 30px; background-position: 0 0, 15px 15px;
|
36 |
border: 1px solid var(--tree-trunk); box-sizing: border-box;
|
37 |
overflow: hidden; display: flex; justify-content: center;
|
38 |
-
align-items: center; font-size: 1.5em;
|
39 |
-
|
40 |
-
box-shadow: inset 0 0 20px rgba(0,0,0,0.4);
|
41 |
}
|
42 |
|
43 |
.game-elements {
|
@@ -65,7 +53,6 @@
|
|
65 |
|
66 |
.thronglet {
|
67 |
cursor: default;
|
68 |
-
/* Slower, smoother transition for movement */
|
69 |
transition: top 1s linear, left 1s linear, transform 0.2s ease, opacity 0.5s ease-out, filter 0.3s ease-out;
|
70 |
z-index: 3;
|
71 |
font-family: 'Noto Color Emoji', 'Apple Color Emoji', 'Segoe UI Emoji', Times, Symbola, Aegyptus, Demo;
|
@@ -100,53 +87,43 @@
|
|
100 |
|
101 |
/* Top Left UI Panel */
|
102 |
#topLeftUI { display: flex; flex-direction: column; align-items: center; width: 70px; }
|
103 |
-
.logo {
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
justify-content: center; border-radius: 50%; margin-bottom: 5px;
|
108 |
}
|
109 |
-
.action-grid {
|
110 |
-
|
111 |
-
background: var(--ui-bg); border: 2px solid var(--ui-border);
|
112 |
-
color: var(--ui-text); font-size: 1.2em; width: 30px; height: 30px;
|
113 |
-
display: flex; align-items: center; justify-content: center;
|
114 |
-
border-radius: 4px; cursor: pointer; transition: background-color 0.2s, transform 0.1s;
|
115 |
-
padding: 0; line-height: 1;
|
116 |
}
|
117 |
-
.action-grid button
|
118 |
-
|
119 |
-
|
|
|
|
|
120 |
}
|
|
|
121 |
.action-grid button:hover { background-color: #f5e5c5; }
|
122 |
-
.action-grid button:active { transform: scale(0.95);
|
123 |
-
/*
|
124 |
-
#pointerBtn { grid-column: 1; grid-row: 1; }
|
125 |
-
#
|
126 |
-
#
|
127 |
-
#
|
128 |
-
#brainBtn { grid-column: 1; grid-row: 3; } /* Brain icon */
|
129 |
-
#plantBtn { grid-column: 2; grid-row: 3; } /* Seedling icon */
|
130 |
-
#houseBtn { grid-column: 1; grid-row: 4; } /* House icon */
|
131 |
-
#gearBtn { grid-column: 2; grid-row: 4; } /* Gear icon */
|
132 |
|
133 |
/* Top Right UI Panel */
|
134 |
#topRightUI { display: flex; flex-direction: column; align-items: center; width: 80px; }
|
135 |
.thronglet-icon-display {
|
136 |
-
background: var(--ui-accent); border: 2px solid var(--ui-border);
|
137 |
-
|
138 |
-
|
139 |
-
margin-bottom: 4px; color: var(--ui-bg);
|
|
|
140 |
}
|
141 |
-
/*
|
142 |
-
.thronglet-icon-display span { position: absolute; font-family: 'Noto Color Emoji', 'Apple Color Emoji', 'Segoe UI Emoji', Times, Symbola, Aegyptus, Demo; }
|
143 |
-
.thronglet-icon-display .t-icon1 { top: 30%; left: 30%; transform: scale(0.5); }
|
144 |
-
.thronglet-icon-display .t-icon2 { top: 30%; left: 70%; transform: scale(0.5); }
|
145 |
-
.thronglet-icon-display .t-icon3 { top: 70%; left: 50%; transform: scale(0.5); }
|
146 |
|
147 |
#throngletCountDisplayTopRight { color: var(--ui-text); font-weight: bold; font-size: 1.1em; }
|
148 |
|
149 |
-
/* Hidden elements
|
150 |
.scanline-overlay, .glitch-overlay, .ominous-elements, .info-panel,
|
151 |
.final-screen, .full-black, .netflix-games-logo {
|
152 |
opacity: 0; pointer-events: none; display: none;
|
@@ -154,12 +131,10 @@
|
|
154 |
.visible { opacity: 1 !important; pointer-events: auto !important; display: flex !important; }
|
155 |
.ominous-elements.visible, .info-panel.visible { display: block !important; }
|
156 |
|
157 |
-
|
158 |
@keyframes hatch-pulse { /* Unchanged */
|
159 |
from { transform: translate(-50%, -50%) scale(1); }
|
160 |
to { transform: translate(-50%, -50%) scale(1.05); }
|
161 |
}
|
162 |
-
|
163 |
</style>
|
164 |
</head>
|
165 |
<body>
|
@@ -167,14 +142,13 @@
|
|
167 |
<div class="game-container" id="gameContainer">
|
168 |
<div class="game-elements" id="gameElements">
|
169 |
<!-- Static Elements -->
|
170 |
-
<div class="river"></div>
|
171 |
-
<div class="rock-cluster">πͺ¨<br>πͺ¨πͺ¨</div>
|
172 |
<span class="emoji tree t1">π³</span> <span class="emoji tree t2">π³</span>
|
173 |
<span class="emoji tree t3">π³</span> <span class="emoji tree t4">π³</span>
|
174 |
<span class="emoji tree t5">π³</span>
|
175 |
<!-- Initial dynamic elements -->
|
176 |
<span class="emoji egg" id="egg">π₯</span>
|
177 |
-
<!-- Elements
|
178 |
<div class="ominous-elements" id="ominousElements">π<br>π¦΄<br>ππ¦</div>
|
179 |
<div class="info-panel" id="infoPanel"></div>
|
180 |
<span class="emoji blood" id="bloodSplatter">π©Έ</span>
|
@@ -184,8 +158,8 @@
|
|
184 |
<div class="ui-panel-container">
|
185 |
<div class="ui-panel" id="topLeftUI">
|
186 |
<div class="logo">T</div>
|
187 |
-
<div class="action-grid" id="actionGrid">
|
188 |
-
<button id="pointerBtn" title="Pointer"
|
189 |
<button id="targetBtn" title="Target">π―</button>
|
190 |
<button id="feedButton" title="Feed">π</button>
|
191 |
<button id="cleanButton" title="Clean">π§Ό</button>
|
@@ -195,13 +169,8 @@
|
|
195 |
<button id="gearBtn" title="Settings?">βοΈ</button>
|
196 |
</div>
|
197 |
</div>
|
198 |
-
|
199 |
<div class="ui-panel" id="topRightUI">
|
200 |
-
<div class="thronglet-icon-display">
|
201 |
-
<span class="t-icon1">πΉ</span>
|
202 |
-
<span class="t-icon2">πΉ</span>
|
203 |
-
<span class="t-icon3">πΉ</span>
|
204 |
-
</div>
|
205 |
<span id="throngletCountDisplayTopRight">0</span>
|
206 |
</div>
|
207 |
</div>
|
@@ -214,16 +183,13 @@
|
|
214 |
<div class="full-black" id="fullBlack"></div>
|
215 |
<div class="netflix-games-logo" id="netflixGamesLogo"><span class="emoji">N</span></div>
|
216 |
|
217 |
-
|
218 |
<script>
|
219 |
// --- DOM Elements ---
|
220 |
const egg = document.getElementById('egg');
|
221 |
const gameContainer = document.getElementById('gameContainer');
|
222 |
const gameElements = document.getElementById('gameElements');
|
223 |
-
const actionGrid = document.getElementById('actionGrid');
|
224 |
-
// UI Display
|
225 |
const throngletCountDisplay = document.getElementById('throngletCountDisplayTopRight');
|
226 |
-
// Other elements
|
227 |
const infoPanel = document.getElementById('infoPanel');
|
228 |
const bloodSplatter = document.getElementById('bloodSplatter');
|
229 |
|
@@ -234,41 +200,52 @@
|
|
234 |
const MAX_THRONGLETS = 100;
|
235 |
let gameInterval;
|
236 |
let gameActive = true;
|
237 |
-
let selectedTool = 'pointer';
|
238 |
|
239 |
// --- Web Audio API Setup ---
|
240 |
let audioContext;
|
241 |
let isAudioContextResumed = false;
|
242 |
-
//
|
243 |
-
|
244 |
-
|
245 |
if (!audioContext) {
|
246 |
try {
|
247 |
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
248 |
audioContext = new AudioContext();
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
|
|
263 |
}
|
264 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
265 |
}
|
266 |
-
}
|
267 |
-
function playSound(type) { /* ... Same as before ... */
|
268 |
-
if (!audioContext || !isAudioContextResumed) { if (audioContext && audioContext.state === 'suspended') { audioContext.resume().then(() => { isAudioContextResumed = true; playSound(type); }); } return; }
|
269 |
const osc = audioContext.createOscillator(); const gain = audioContext.createGain(); osc.connect(gain); gain.connect(audioContext.destination);
|
270 |
const now = audioContext.currentTime; let freq = 440, duration = 0.1, vol = 0.2; osc.type = 'sine';
|
271 |
-
switch (type) {
|
272 |
case 'hatch': freq = 660; duration = 0.3; vol = 0.3; osc.type = 'triangle'; gain.gain.setValueAtTime(0, now); gain.gain.linearRampToValueAtTime(vol, now + 0.05); gain.gain.linearRampToValueAtTime(0, now + duration); break;
|
273 |
case 'feed': freq = 880; duration = 0.08; vol = 0.15; gain.gain.setValueAtTime(vol, now); gain.gain.linearRampToValueAtTime(0, now + duration); break;
|
274 |
case 'clean': freq = 1100; duration = 0.1; vol = 0.1; osc.type = 'square'; gain.gain.setValueAtTime(vol, now); gain.gain.linearRampToValueAtTime(0, now + duration); break;
|
@@ -280,7 +257,7 @@
|
|
280 |
default: freq = 900; duration = 0.05; vol = 0.1; gain.gain.setValueAtTime(vol, now); gain.gain.linearRampToValueAtTime(0, now + duration);
|
281 |
}
|
282 |
osc.frequency.setValueAtTime(freq, now); osc.start(now); osc.stop(now + duration);
|
283 |
-
|
284 |
|
285 |
// --- Game Logic ---
|
286 |
function updateUI() {
|
@@ -288,18 +265,19 @@
|
|
288 |
throngletCountDisplay.textContent = livingCount;
|
289 |
}
|
290 |
|
291 |
-
function showInfoPanel(text, duration = 2000) {
|
292 |
if (!gameActive || !infoPanel) return;
|
293 |
infoPanel.textContent = text;
|
294 |
-
infoPanel.style.display = 'block';
|
295 |
-
|
|
|
|
|
296 |
clearTimeout(infoPanel.timeout);
|
297 |
infoPanel.timeout = setTimeout(() => {
|
298 |
infoPanel.style.opacity = 0;
|
299 |
-
// Use transitionend event listener for
|
300 |
-
|
301 |
-
|
302 |
-
}, { once: true });
|
303 |
}, duration);
|
304 |
}
|
305 |
|
@@ -307,156 +285,115 @@
|
|
307 |
const livingCount = thronglets.filter(t => !t.isDead).length;
|
308 |
if (!gameActive || livingCount >= MAX_THRONGLETS) {
|
309 |
if (livingCount >= MAX_THRONGLETS) {
|
310 |
-
|
311 |
-
|
312 |
-
}
|
313 |
-
return;
|
314 |
}
|
315 |
-
|
316 |
const throngletElement = document.createElement('span');
|
317 |
throngletElement.classList.add('emoji', 'thronglet');
|
318 |
-
throngletElement.textContent = 'πΉ'; //
|
319 |
const currentId = nextThrongletId++;
|
320 |
throngletElement.dataset.id = currentId;
|
321 |
-
const spawnX = Math.max(5, Math.min(95, xPercent));
|
322 |
const spawnY = Math.max(5, Math.min(95, yPercent));
|
323 |
-
throngletElement.style.top = `${spawnY}%`;
|
324 |
-
throngletElement.style.left = `${spawnX}%`;
|
325 |
throngletElement.dataset.bornTime = Date.now();
|
326 |
gameElements.appendChild(throngletElement);
|
327 |
|
328 |
-
const newThronglet = {
|
329 |
-
id: currentId, element: throngletElement, hunger: 25, cleanliness: 20, happiness: 70,
|
330 |
-
lastInteraction: Date.now(), lastDuplication: 0, isDead: false, memory: [], feedbackElement: null
|
331 |
-
};
|
332 |
thronglets.push(newThronglet);
|
333 |
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
feedbackElement.style.left = throngletElement.style.left;
|
339 |
-
gameElements.appendChild(feedbackElement);
|
340 |
-
newThronglet.feedbackElement = feedbackElement;
|
341 |
|
342 |
updateUI();
|
343 |
setTimeout(() => { if (!newThronglet.isDead) wander(newThronglet); }, 100);
|
344 |
}
|
345 |
|
346 |
-
function feedThronglet(thronglet) {
|
347 |
if (!gameActive || thronglet.isDead) return;
|
348 |
-
thronglet.hunger = Math.max(0, thronglet.hunger - 50);
|
349 |
-
thronglet.
|
350 |
-
thronglet.lastInteraction = Date.now();
|
351 |
-
showFeedback(thronglet, 'π'); playSound('feed'); thronglet.memory.push('Fed');
|
352 |
}
|
353 |
-
|
354 |
-
function cleanThronglet(thronglet) { /* ... Same as before ... */
|
355 |
if (!gameActive || thronglet.isDead) return;
|
356 |
-
thronglet.cleanliness = Math.max(0, thronglet.cleanliness - 60);
|
357 |
-
thronglet.
|
358 |
-
thronglet.lastInteraction = Date.now();
|
359 |
-
showFeedback(thronglet, 'β¨'); playSound('clean'); thronglet.memory.push('Cleaned');
|
360 |
}
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
thronglet.feedbackElement.classList.add('active');
|
368 |
-
playSound('feedback');
|
369 |
-
clearTimeout(thronglet.feedbackElement.timeout);
|
370 |
-
thronglet.feedbackElement.timeout = setTimeout(() => { if (thronglet.feedbackElement) { thronglet.feedbackElement.classList.remove('active'); } }, 600);
|
371 |
}
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
deathCount++; updateUI(); playSound('death'); thronglet.memory.push(`Died (${reason})`);
|
381 |
-
setTimeout(() => { if (thronglet.element) { thronglet.element.style.opacity = 0; setTimeout(() => { if(thronglet.element) thronglet.element.remove(); }, 500); } }, 3000);
|
382 |
}
|
383 |
-
|
384 |
function wander(thronglet) {
|
385 |
if (!gameActive || thronglet.isDead) return;
|
386 |
-
const moveDist =
|
387 |
-
const currentX = parseFloat(thronglet.element.style.left);
|
388 |
-
const
|
389 |
-
const newX = Math.max(5, Math.min(95, currentX + (Math.random() - 0.5) * moveDist * 2)); // Clamp within 5-95%
|
390 |
const newY = Math.max(5, Math.min(95, currentY + (Math.random() - 0.5) * moveDist * 2));
|
391 |
-
thronglet.element.style.left = `${newX}%`;
|
392 |
-
thronglet.
|
393 |
-
if (thronglet.feedbackElement) { // Ensure feedback follows smoothly
|
394 |
-
thronglet.feedbackElement.style.left = `${newX}%`;
|
395 |
-
thronglet.feedbackElement.style.top = `${newY}%`;
|
396 |
-
}
|
397 |
-
// console.log(`Wander #${thronglet.id} to ${newX.toFixed(1)}%, ${newY.toFixed(1)}%`); // Debug log
|
398 |
}
|
399 |
|
400 |
-
function updateThronglets() {
|
401 |
if (!gameActive) return;
|
402 |
const now = Date.now();
|
403 |
const livingThronglets = thronglets.filter(t => !t.isDead);
|
404 |
|
405 |
livingThronglets.forEach(thronglet => {
|
406 |
const timeSinceLast = now - thronglet.lastInteraction;
|
407 |
-
const baseNeedRate = 0.15;
|
408 |
-
const neglectMultiplier = 1 + Math.min(5, timeSinceLast / 10000);
|
409 |
-
|
410 |
thronglet.hunger = Math.min(100, thronglet.hunger + baseNeedRate * neglectMultiplier * 1.0);
|
411 |
thronglet.cleanliness = Math.min(100, thronglet.cleanliness + baseNeedRate * neglectMultiplier * 0.8);
|
412 |
thronglet.happiness = Math.max(0, thronglet.happiness - baseNeedRate * neglectMultiplier * 1.1);
|
413 |
|
414 |
let deathReason = null;
|
415 |
-
if (thronglet.hunger >= 100) deathReason = "starvation";
|
416 |
-
else if (thronglet.cleanliness >= 100) deathReason = "filth";
|
417 |
-
else if (thronglet.happiness <= 0) deathReason = "misery";
|
418 |
if (deathReason) { killThronglet(thronglet, deathReason); return; }
|
419 |
|
420 |
// Duplication Logic
|
421 |
-
const canDuplicate = thronglet.happiness > 85 && thronglet.hunger < 15 &&
|
422 |
-
thronglet.cleanliness < 15 && timeSinceLast < 15000 &&
|
423 |
-
(now - thronglet.lastDuplication > 20000);
|
424 |
if (canDuplicate && Math.random() < 0.015) {
|
425 |
-
showFeedback(thronglet, 'π'); playSound('duplicate');
|
426 |
-
thronglet.lastDuplication = now; thronglet.lastInteraction = now;
|
427 |
setTimeout(() => {
|
428 |
-
const parentX = parseFloat(thronglet.element.style.left);
|
429 |
-
const parentY = parseFloat(thronglet.element.style.top);
|
430 |
createThronglet(parentX + (Math.random() - 0.5) * 5, parentY + (Math.random() - 0.5) * 5);
|
431 |
}, 500);
|
432 |
}
|
433 |
-
|
434 |
-
|
435 |
-
if (Math.random() < 0.2) { wander(thronglet); }
|
436 |
});
|
437 |
-
// Update UI count periodically
|
438 |
-
if (Math.random() < 0.2) updateUI();
|
439 |
}
|
440 |
|
441 |
// --- Tool Selection Function ---
|
442 |
-
function selectTool(
|
443 |
-
|
|
|
444 |
playSound('ui_click');
|
445 |
-
// Remove 'selected' class from all buttons
|
446 |
actionGrid.querySelectorAll('button').forEach(btn => btn.classList.remove('selected'));
|
447 |
// Add 'selected' class to the clicked button
|
448 |
-
|
449 |
-
|
450 |
-
selectedButton.classList.add('selected');
|
451 |
-
}
|
452 |
-
console.log("Selected tool:", selectedTool); // Log selected tool
|
453 |
}
|
454 |
|
455 |
-
|
456 |
// --- Event Handlers ---
|
457 |
egg.addEventListener('click', () => {
|
458 |
if (!gameActive || egg.classList.contains('hatching') || !document.contains(egg)) return;
|
459 |
-
initAudio(); //
|
460 |
egg.classList.add('hatching'); playSound('hatch');
|
461 |
setTimeout(() => {
|
462 |
if(document.contains(egg)) egg.remove();
|
@@ -464,71 +401,63 @@
|
|
464 |
}, 1000);
|
465 |
});
|
466 |
|
467 |
-
//
|
468 |
actionGrid.addEventListener('click', (event) => {
|
469 |
if (event.target.tagName === 'BUTTON') {
|
470 |
-
const
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
console.log("Gear button clicked (placeholder)");
|
510 |
-
break;
|
511 |
-
default:
|
512 |
-
playSound('error'); // Sound for unhandled buttons
|
513 |
-
break;
|
514 |
}
|
515 |
}
|
516 |
});
|
517 |
|
518 |
-
|
519 |
// --- Initial Setup ---
|
520 |
function initGame() {
|
521 |
-
gameActive = true;
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
|
|
527 |
}
|
528 |
-
|
529 |
-
// Start the game automatically
|
530 |
-
initGame();
|
531 |
-
|
532 |
</script>
|
533 |
</body>
|
534 |
</html>
|
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Thronglets Simulation (v3)</title>
|
7 |
<style>
|
8 |
:root {
|
9 |
+
--grass-dark: #2a6141; --grass-light: #3a815b; --water: #4171a7;
|
10 |
+
--rock-dark: #6b727c; --tree-leaves: #2b602c; --ui-bg: #e0cda9;
|
11 |
+
--ui-border: #8b4513; --ui-accent: #6d8c4f; --ui-text: #3a2e20;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
}
|
13 |
|
14 |
body {
|
15 |
margin: 0; overflow: hidden; background: var(--grass-dark);
|
16 |
+
color: #eee; font-family: 'Verdana', sans-serif; display: flex;
|
17 |
+
flex-direction: column; align-items: center; justify-content: center;
|
18 |
+
min-height: 100vh; position: relative;
|
19 |
}
|
20 |
|
21 |
.game-container {
|
22 |
position: relative; width: 95vmin; height: 70vmin;
|
23 |
max-width: 1000px; max-height: 700px;
|
24 |
+
background-color: var(--grass-light); /* Simple background color */
|
|
|
|
|
|
|
25 |
border: 1px solid var(--tree-trunk); box-sizing: border-box;
|
26 |
overflow: hidden; display: flex; justify-content: center;
|
27 |
+
align-items: center; font-size: 1.5em; position: relative;
|
28 |
+
image-rendering: pixelated; box-shadow: inset 0 0 20px rgba(0,0,0,0.4);
|
|
|
29 |
}
|
30 |
|
31 |
.game-elements {
|
|
|
53 |
|
54 |
.thronglet {
|
55 |
cursor: default;
|
|
|
56 |
transition: top 1s linear, left 1s linear, transform 0.2s ease, opacity 0.5s ease-out, filter 0.3s ease-out;
|
57 |
z-index: 3;
|
58 |
font-family: 'Noto Color Emoji', 'Apple Color Emoji', 'Segoe UI Emoji', Times, Symbola, Aegyptus, Demo;
|
|
|
87 |
|
88 |
/* Top Left UI Panel */
|
89 |
#topLeftUI { display: flex; flex-direction: column; align-items: center; width: 70px; }
|
90 |
+
.logo { /* ... Same style ... */
|
91 |
+
background: var(--ui-accent); border: 2px solid var(--ui-border); color: var(--ui-bg);
|
92 |
+
font-size: 1.8em; font-weight: bold; width: 40px; height: 40px; display: flex;
|
93 |
+
align-items: center; justify-content: center; border-radius: 50%; margin-bottom: 5px;
|
|
|
94 |
}
|
95 |
+
.action-grid { /* ... Same style ... */
|
96 |
+
display: grid; grid-template-columns: 1fr 1fr; gap: 4px; width: 100%;
|
|
|
|
|
|
|
|
|
|
|
97 |
}
|
98 |
+
.action-grid button { /* ... Same style ... */
|
99 |
+
background: var(--ui-bg); border: 2px solid var(--ui-border); color: var(--ui-text);
|
100 |
+
font-size: 1.2em; width: 30px; height: 30px; display: flex; align-items: center;
|
101 |
+
justify-content: center; border-radius: 4px; cursor: pointer;
|
102 |
+
transition: background-color 0.2s, transform 0.1s, border-color 0.1s; padding: 0; line-height: 1;
|
103 |
}
|
104 |
+
.action-grid button.selected { border-color: #fff; box-shadow: inset 0 0 3px rgba(0,0,0,0.4); }
|
105 |
.action-grid button:hover { background-color: #f5e5c5; }
|
106 |
+
.action-grid button:active { transform: scale(0.95); }
|
107 |
+
/* Button IDs */
|
108 |
+
#pointerBtn { grid-column: 1; grid-row: 1; } #targetBtn { grid-column: 2; grid-row: 1; }
|
109 |
+
#feedButton { grid-column: 1; grid-row: 2; } #cleanButton { grid-column: 2; grid-row: 2; }
|
110 |
+
#brainBtn { grid-column: 1; grid-row: 3; } #plantBtn { grid-column: 2; grid-row: 3; }
|
111 |
+
#houseBtn { grid-column: 1; grid-row: 4; } #gearBtn { grid-column: 2; grid-row: 4; }
|
|
|
|
|
|
|
|
|
112 |
|
113 |
/* Top Right UI Panel */
|
114 |
#topRightUI { display: flex; flex-direction: column; align-items: center; width: 80px; }
|
115 |
.thronglet-icon-display {
|
116 |
+
background: var(--ui-accent); border: 2px solid var(--ui-border); width: 50px; height: 50px;
|
117 |
+
border-radius: 50%; display: flex; align-items: center; justify-content: center;
|
118 |
+
font-size: 2em; /* Make single emoji larger */
|
119 |
+
margin-bottom: 4px; color: var(--ui-bg);
|
120 |
+
font-family: 'Noto Color Emoji', 'Apple Color Emoji', 'Segoe UI Emoji', Times, Symbola, Aegyptus, Demo; /* Ensure emoji font */
|
121 |
}
|
122 |
+
/* Removed inner spans for multiple icons */
|
|
|
|
|
|
|
|
|
123 |
|
124 |
#throngletCountDisplayTopRight { color: var(--ui-text); font-weight: bold; font-size: 1.1em; }
|
125 |
|
126 |
+
/* Hidden elements */
|
127 |
.scanline-overlay, .glitch-overlay, .ominous-elements, .info-panel,
|
128 |
.final-screen, .full-black, .netflix-games-logo {
|
129 |
opacity: 0; pointer-events: none; display: none;
|
|
|
131 |
.visible { opacity: 1 !important; pointer-events: auto !important; display: flex !important; }
|
132 |
.ominous-elements.visible, .info-panel.visible { display: block !important; }
|
133 |
|
|
|
134 |
@keyframes hatch-pulse { /* Unchanged */
|
135 |
from { transform: translate(-50%, -50%) scale(1); }
|
136 |
to { transform: translate(-50%, -50%) scale(1.05); }
|
137 |
}
|
|
|
138 |
</style>
|
139 |
</head>
|
140 |
<body>
|
|
|
142 |
<div class="game-container" id="gameContainer">
|
143 |
<div class="game-elements" id="gameElements">
|
144 |
<!-- Static Elements -->
|
145 |
+
<div class="river"></div> <div class="rock-cluster">πͺ¨<br>πͺ¨πͺ¨</div>
|
|
|
146 |
<span class="emoji tree t1">π³</span> <span class="emoji tree t2">π³</span>
|
147 |
<span class="emoji tree t3">π³</span> <span class="emoji tree t4">π³</span>
|
148 |
<span class="emoji tree t5">π³</span>
|
149 |
<!-- Initial dynamic elements -->
|
150 |
<span class="emoji egg" id="egg">π₯</span>
|
151 |
+
<!-- Hidden Elements -->
|
152 |
<div class="ominous-elements" id="ominousElements">π<br>π¦΄<br>ππ¦</div>
|
153 |
<div class="info-panel" id="infoPanel"></div>
|
154 |
<span class="emoji blood" id="bloodSplatter">π©Έ</span>
|
|
|
158 |
<div class="ui-panel-container">
|
159 |
<div class="ui-panel" id="topLeftUI">
|
160 |
<div class="logo">T</div>
|
161 |
+
<div class="action-grid" id="actionGrid">
|
162 |
+
<button id="pointerBtn" title="Pointer">β</button>
|
163 |
<button id="targetBtn" title="Target">π―</button>
|
164 |
<button id="feedButton" title="Feed">π</button>
|
165 |
<button id="cleanButton" title="Clean">π§Ό</button>
|
|
|
169 |
<button id="gearBtn" title="Settings?">βοΈ</button>
|
170 |
</div>
|
171 |
</div>
|
|
|
172 |
<div class="ui-panel" id="topRightUI">
|
173 |
+
<div class="thronglet-icon-display">πΉ</div> <!-- Simplified Icon -->
|
|
|
|
|
|
|
|
|
174 |
<span id="throngletCountDisplayTopRight">0</span>
|
175 |
</div>
|
176 |
</div>
|
|
|
183 |
<div class="full-black" id="fullBlack"></div>
|
184 |
<div class="netflix-games-logo" id="netflixGamesLogo"><span class="emoji">N</span></div>
|
185 |
|
|
|
186 |
<script>
|
187 |
// --- DOM Elements ---
|
188 |
const egg = document.getElementById('egg');
|
189 |
const gameContainer = document.getElementById('gameContainer');
|
190 |
const gameElements = document.getElementById('gameElements');
|
191 |
+
const actionGrid = document.getElementById('actionGrid');
|
|
|
192 |
const throngletCountDisplay = document.getElementById('throngletCountDisplayTopRight');
|
|
|
193 |
const infoPanel = document.getElementById('infoPanel');
|
194 |
const bloodSplatter = document.getElementById('bloodSplatter');
|
195 |
|
|
|
200 |
const MAX_THRONGLETS = 100;
|
201 |
let gameInterval;
|
202 |
let gameActive = true;
|
203 |
+
let selectedTool = 'pointer';
|
204 |
|
205 |
// --- Web Audio API Setup ---
|
206 |
let audioContext;
|
207 |
let isAudioContextResumed = false;
|
208 |
+
// initAudio and playSound functions (same as previous version)
|
209 |
+
function initAudio() {
|
210 |
+
if (isAudioContextResumed) return; // Already resumed
|
211 |
if (!audioContext) {
|
212 |
try {
|
213 |
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
214 |
audioContext = new AudioContext();
|
215 |
+
} catch (e) { console.error("Web Audio API not supported", e); return; }
|
216 |
+
}
|
217 |
+
// Resume on first user interaction if needed
|
218 |
+
if (audioContext.state === 'suspended') {
|
219 |
+
const resumeAudio = () => {
|
220 |
+
if (audioContext.state === 'suspended') {
|
221 |
+
audioContext.resume().then(() => {
|
222 |
+
isAudioContextResumed = true; console.log("AudioContext Resumed");
|
223 |
+
document.body.removeEventListener('click', resumeAudio);
|
224 |
+
document.body.removeEventListener('touchend', resumeAudio);
|
225 |
+
}).catch(e => console.error("Audio resume failed", e));
|
226 |
+
} else { // Already running or closed?
|
227 |
+
isAudioContextResumed = (audioContext.state === 'running');
|
228 |
+
document.body.removeEventListener('click', resumeAudio);
|
229 |
+
document.body.removeEventListener('touchend', resumeAudio);
|
230 |
}
|
231 |
+
};
|
232 |
+
// Use capture phase to potentially catch earlier interactions
|
233 |
+
document.body.addEventListener('click', resumeAudio, { once: true, capture: true });
|
234 |
+
document.body.addEventListener('touchend', resumeAudio, { once: true, capture: true });
|
235 |
+
} else {
|
236 |
+
isAudioContextResumed = true; // Already running
|
237 |
+
}
|
238 |
+
}
|
239 |
+
function playSound(type) {
|
240 |
+
if (!audioContext || !isAudioContextResumed) {
|
241 |
+
console.log("Audio not ready, skipping sound:", type);
|
242 |
+
// Attempt to resume if called before interaction
|
243 |
+
if (audioContext && audioContext.state === 'suspended') initAudio();
|
244 |
+
return;
|
245 |
}
|
|
|
|
|
|
|
246 |
const osc = audioContext.createOscillator(); const gain = audioContext.createGain(); osc.connect(gain); gain.connect(audioContext.destination);
|
247 |
const now = audioContext.currentTime; let freq = 440, duration = 0.1, vol = 0.2; osc.type = 'sine';
|
248 |
+
switch (type) { /* ... cases same as before ... */
|
249 |
case 'hatch': freq = 660; duration = 0.3; vol = 0.3; osc.type = 'triangle'; gain.gain.setValueAtTime(0, now); gain.gain.linearRampToValueAtTime(vol, now + 0.05); gain.gain.linearRampToValueAtTime(0, now + duration); break;
|
250 |
case 'feed': freq = 880; duration = 0.08; vol = 0.15; gain.gain.setValueAtTime(vol, now); gain.gain.linearRampToValueAtTime(0, now + duration); break;
|
251 |
case 'clean': freq = 1100; duration = 0.1; vol = 0.1; osc.type = 'square'; gain.gain.setValueAtTime(vol, now); gain.gain.linearRampToValueAtTime(0, now + duration); break;
|
|
|
257 |
default: freq = 900; duration = 0.05; vol = 0.1; gain.gain.setValueAtTime(vol, now); gain.gain.linearRampToValueAtTime(0, now + duration);
|
258 |
}
|
259 |
osc.frequency.setValueAtTime(freq, now); osc.start(now); osc.stop(now + duration);
|
260 |
+
}
|
261 |
|
262 |
// --- Game Logic ---
|
263 |
function updateUI() {
|
|
|
265 |
throngletCountDisplay.textContent = livingCount;
|
266 |
}
|
267 |
|
268 |
+
function showInfoPanel(text, duration = 2000) {
|
269 |
if (!gameActive || !infoPanel) return;
|
270 |
infoPanel.textContent = text;
|
271 |
+
infoPanel.style.display = 'block';
|
272 |
+
requestAnimationFrame(() => { // Ensure display:block is applied before opacity transition starts
|
273 |
+
infoPanel.style.opacity = 1;
|
274 |
+
});
|
275 |
clearTimeout(infoPanel.timeout);
|
276 |
infoPanel.timeout = setTimeout(() => {
|
277 |
infoPanel.style.opacity = 0;
|
278 |
+
// Use transitionend event listener for reliable hiding
|
279 |
+
const hidePanel = () => { infoPanel.style.display = 'none'; };
|
280 |
+
infoPanel.addEventListener('transitionend', hidePanel, { once: true });
|
|
|
281 |
}, duration);
|
282 |
}
|
283 |
|
|
|
285 |
const livingCount = thronglets.filter(t => !t.isDead).length;
|
286 |
if (!gameActive || livingCount >= MAX_THRONGLETS) {
|
287 |
if (livingCount >= MAX_THRONGLETS) {
|
288 |
+
playSound('error'); showInfoPanel("Population Limit!", 1500);
|
289 |
+
} return;
|
|
|
|
|
290 |
}
|
|
|
291 |
const throngletElement = document.createElement('span');
|
292 |
throngletElement.classList.add('emoji', 'thronglet');
|
293 |
+
throngletElement.textContent = 'πΉ'; // Hamster emoji
|
294 |
const currentId = nextThrongletId++;
|
295 |
throngletElement.dataset.id = currentId;
|
296 |
+
const spawnX = Math.max(5, Math.min(95, xPercent));
|
297 |
const spawnY = Math.max(5, Math.min(95, yPercent));
|
298 |
+
throngletElement.style.top = `${spawnY}%`; throngletElement.style.left = `${spawnX}%`;
|
|
|
299 |
throngletElement.dataset.bornTime = Date.now();
|
300 |
gameElements.appendChild(throngletElement);
|
301 |
|
302 |
+
const newThronglet = { id: currentId, element: throngletElement, hunger: 25, cleanliness: 20, happiness: 70, lastInteraction: Date.now(), lastDuplication: 0, isDead: false, memory: [], feedbackElement: null };
|
|
|
|
|
|
|
303 |
thronglets.push(newThronglet);
|
304 |
|
305 |
+
const feedbackElement = document.createElement('span');
|
306 |
+
feedbackElement.classList.add('emoji', 'feedback');
|
307 |
+
feedbackElement.style.top = throngletElement.style.top; feedbackElement.style.left = throngletElement.style.left;
|
308 |
+
gameElements.appendChild(feedbackElement); newThronglet.feedbackElement = feedbackElement;
|
|
|
|
|
|
|
309 |
|
310 |
updateUI();
|
311 |
setTimeout(() => { if (!newThronglet.isDead) wander(newThronglet); }, 100);
|
312 |
}
|
313 |
|
314 |
+
function feedThronglet(thronglet) {
|
315 |
if (!gameActive || thronglet.isDead) return;
|
316 |
+
thronglet.hunger = Math.max(0, thronglet.hunger - 50); thronglet.happiness = Math.min(100, thronglet.happiness + 8);
|
317 |
+
thronglet.lastInteraction = Date.now(); showFeedback(thronglet, 'π'); playSound('feed'); thronglet.memory.push('Fed');
|
|
|
|
|
318 |
}
|
319 |
+
function cleanThronglet(thronglet) {
|
|
|
320 |
if (!gameActive || thronglet.isDead) return;
|
321 |
+
thronglet.cleanliness = Math.max(0, thronglet.cleanliness - 60); thronglet.happiness = Math.min(100, thronglet.happiness + 4);
|
322 |
+
thronglet.lastInteraction = Date.now(); showFeedback(thronglet, 'β¨'); playSound('clean'); thronglet.memory.push('Cleaned');
|
|
|
|
|
323 |
}
|
324 |
+
function showFeedback(thronglet, emoji) {
|
325 |
+
if (!gameActive || !thronglet.feedbackElement || thronglet.isDead) return;
|
326 |
+
thronglet.feedbackElement.style.top = thronglet.element.style.top; thronglet.feedbackElement.style.left = thronglet.element.style.left;
|
327 |
+
thronglet.feedbackElement.textContent = emoji; thronglet.feedbackElement.classList.add('active'); playSound('feedback');
|
328 |
+
clearTimeout(thronglet.feedbackElement.timeout);
|
329 |
+
thronglet.feedbackElement.timeout = setTimeout(() => { if (thronglet.feedbackElement) { thronglet.feedbackElement.classList.remove('active'); } }, 600);
|
|
|
|
|
|
|
|
|
330 |
}
|
331 |
+
function killThronglet(thronglet, reason = "expiration") {
|
332 |
+
if (!gameActive || thronglet.isDead) return;
|
333 |
+
thronglet.isDead = true; thronglet.element.classList.add('dead'); thronglet.element.textContent = 'π';
|
334 |
+
if (thronglet.feedbackElement) { thronglet.feedbackElement.remove(); thronglet.feedbackElement = null; }
|
335 |
+
bloodSplatter.style.top = thronglet.element.style.top; bloodSplatter.style.left = thronglet.element.style.left;
|
336 |
+
bloodSplatter.classList.add('splatter'); setTimeout(() => { bloodSplatter.classList.remove('splatter'); }, 800);
|
337 |
+
deathCount++; updateUI(); playSound('death'); thronglet.memory.push(`Died (${reason})`);
|
338 |
+
setTimeout(() => { if (thronglet.element) { thronglet.element.style.opacity = 0; setTimeout(() => { if(thronglet.element) thronglet.element.remove(); }, 500); } }, 3000);
|
|
|
|
|
339 |
}
|
|
|
340 |
function wander(thronglet) {
|
341 |
if (!gameActive || thronglet.isDead) return;
|
342 |
+
const moveDist = 0.8; // Further reduced movement distance
|
343 |
+
const currentX = parseFloat(thronglet.element.style.left); const currentY = parseFloat(thronglet.element.style.top);
|
344 |
+
const newX = Math.max(5, Math.min(95, currentX + (Math.random() - 0.5) * moveDist * 2));
|
|
|
345 |
const newY = Math.max(5, Math.min(95, currentY + (Math.random() - 0.5) * moveDist * 2));
|
346 |
+
thronglet.element.style.left = `${newX}%`; thronglet.element.style.top = `${newY}%`;
|
347 |
+
if (thronglet.feedbackElement) { thronglet.feedbackElement.style.left = `${newX}%`; thronglet.feedbackElement.style.top = `${newY}%`; }
|
|
|
|
|
|
|
|
|
|
|
348 |
}
|
349 |
|
350 |
+
function updateThronglets() {
|
351 |
if (!gameActive) return;
|
352 |
const now = Date.now();
|
353 |
const livingThronglets = thronglets.filter(t => !t.isDead);
|
354 |
|
355 |
livingThronglets.forEach(thronglet => {
|
356 |
const timeSinceLast = now - thronglet.lastInteraction;
|
357 |
+
const baseNeedRate = 0.15; const neglectMultiplier = 1 + Math.min(5, timeSinceLast / 10000);
|
|
|
|
|
358 |
thronglet.hunger = Math.min(100, thronglet.hunger + baseNeedRate * neglectMultiplier * 1.0);
|
359 |
thronglet.cleanliness = Math.min(100, thronglet.cleanliness + baseNeedRate * neglectMultiplier * 0.8);
|
360 |
thronglet.happiness = Math.max(0, thronglet.happiness - baseNeedRate * neglectMultiplier * 1.1);
|
361 |
|
362 |
let deathReason = null;
|
363 |
+
if (thronglet.hunger >= 100) deathReason = "starvation"; else if (thronglet.cleanliness >= 100) deathReason = "filth"; else if (thronglet.happiness <= 0) deathReason = "misery";
|
|
|
|
|
364 |
if (deathReason) { killThronglet(thronglet, deathReason); return; }
|
365 |
|
366 |
// Duplication Logic
|
367 |
+
const canDuplicate = thronglet.happiness > 85 && thronglet.hunger < 15 && thronglet.cleanliness < 15 && timeSinceLast < 15000 && (now - thronglet.lastDuplication > 20000);
|
|
|
|
|
368 |
if (canDuplicate && Math.random() < 0.015) {
|
369 |
+
showFeedback(thronglet, 'π'); playSound('duplicate'); thronglet.lastDuplication = now; thronglet.lastInteraction = now;
|
|
|
370 |
setTimeout(() => {
|
371 |
+
const parentX = parseFloat(thronglet.element.style.left); const parentY = parseFloat(thronglet.element.style.top);
|
|
|
372 |
createThronglet(parentX + (Math.random() - 0.5) * 5, parentY + (Math.random() - 0.5) * 5);
|
373 |
}, 500);
|
374 |
}
|
375 |
+
// Wander even less often
|
376 |
+
if (Math.random() < 0.15) { wander(thronglet); }
|
|
|
377 |
});
|
378 |
+
if (Math.random() < 0.2) updateUI(); // Update UI count periodically
|
|
|
379 |
}
|
380 |
|
381 |
// --- Tool Selection Function ---
|
382 |
+
function selectTool(toolButtonElement) {
|
383 |
+
// Get the ID to store the tool name
|
384 |
+
selectedTool = toolButtonElement.id.replace(/Btn|Button/g, ''); // Get base name like 'pointer', 'feed'
|
385 |
playSound('ui_click');
|
386 |
+
// Remove 'selected' class from all buttons in the grid
|
387 |
actionGrid.querySelectorAll('button').forEach(btn => btn.classList.remove('selected'));
|
388 |
// Add 'selected' class to the clicked button
|
389 |
+
toolButtonElement.classList.add('selected');
|
390 |
+
// console.log("Selected tool:", selectedTool);
|
|
|
|
|
|
|
391 |
}
|
392 |
|
|
|
393 |
// --- Event Handlers ---
|
394 |
egg.addEventListener('click', () => {
|
395 |
if (!gameActive || egg.classList.contains('hatching') || !document.contains(egg)) return;
|
396 |
+
initAudio(); // IMPORTANT: Call initAudio on first interaction!
|
397 |
egg.classList.add('hatching'); playSound('hatch');
|
398 |
setTimeout(() => {
|
399 |
if(document.contains(egg)) egg.remove();
|
|
|
401 |
}, 1000);
|
402 |
});
|
403 |
|
404 |
+
// Centralized Action Grid Listener
|
405 |
actionGrid.addEventListener('click', (event) => {
|
406 |
if (event.target.tagName === 'BUTTON') {
|
407 |
+
const buttonElement = event.target;
|
408 |
+
const buttonId = buttonElement.id;
|
409 |
+
initAudio(); // Ensure audio context is active
|
410 |
+
|
411 |
+
// Select the tool visually first
|
412 |
+
selectTool(buttonElement);
|
413 |
+
|
414 |
+
// Perform immediate action for feed/clean
|
415 |
+
if (buttonId === 'feedButton') {
|
416 |
+
const living = thronglets.filter(t => !t.isDead);
|
417 |
+
if (living.length > 0) {
|
418 |
+
// Use reduce with initial value null to handle empty array
|
419 |
+
const target = living.reduce((p, c) => (p === null || c.hunger > p.hunger) ? c : p, null);
|
420 |
+
if (target) { // Check if a target was found
|
421 |
+
feedThronglet(target);
|
422 |
+
} else {
|
423 |
+
// This case shouldn't happen if living.length > 0, but good practice
|
424 |
+
playSound('error');
|
425 |
+
}
|
426 |
+
} else {
|
427 |
+
playSound('error'); // No living thronglets
|
428 |
+
}
|
429 |
+
} else if (buttonId === 'cleanButton') {
|
430 |
+
const living = thronglets.filter(t => !t.isDead);
|
431 |
+
if (living.length > 0) {
|
432 |
+
// Use reduce with initial value null
|
433 |
+
const target = living.reduce((p, c) => (p === null || c.cleanliness > p.cleanliness) ? c : p, null);
|
434 |
+
if (target) { // Check if target found
|
435 |
+
cleanThronglet(target);
|
436 |
+
} else {
|
437 |
+
playSound('error');
|
438 |
+
}
|
439 |
+
} else {
|
440 |
+
playSound('error'); // No living thronglets
|
441 |
+
}
|
442 |
+
} else if (buttonId !== 'pointerBtn') {
|
443 |
+
// Placeholder message/sound for other tools for now
|
444 |
+
console.log(`${selectedTool} tool selected (no action implemented)`);
|
445 |
+
// Optionally play a generic 'select' sound different from 'ui_click'
|
|
|
|
|
|
|
|
|
|
|
446 |
}
|
447 |
}
|
448 |
});
|
449 |
|
|
|
450 |
// --- Initial Setup ---
|
451 |
function initGame() {
|
452 |
+
gameActive = true; updateUI();
|
453 |
+
gameInterval = setInterval(updateThronglets, 400);
|
454 |
+
// Attempt to initialize audio context, but it requires user interaction first
|
455 |
+
// It will be properly initialized/resumed on the first click (e.g., egg click)
|
456 |
+
initAudio();
|
457 |
+
selectTool(document.getElementById('pointerBtn')); // Set pointer as default selected tool visually
|
458 |
+
console.log("Game Initialized. Click the egg.");
|
459 |
}
|
460 |
+
initGame(); // Start the game
|
|
|
|
|
|
|
461 |
</script>
|
462 |
</body>
|
463 |
</html>
|