Spaces:
Sleeping
Sleeping
feat: Complete boss battle integration with 100% fitness victory
Browse files- Add boss defeat callback handler with hidden Gradio button
- Connect JavaScript click events to Python backend
- Add victory effects with multiple quantum bursts
- Update boss state tracking for proper cleanup
- Enable progression from 99% to 100% fitness on boss defeat
- Add legendary achievement unlock for defeating the boss
app.py
CHANGED
@@ -25,7 +25,10 @@ state = {
|
|
25 |
"player_name": f"Player_{random.randint(1000, 9999)}",
|
26 |
"multiplayer_active": False,
|
27 |
"other_players": {},
|
28 |
-
"global_best": 0.9333
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
# Simulated multiplayer data
|
@@ -290,10 +293,57 @@ function createWormhole() {
|
|
290 |
}
|
291 |
}
|
292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
function animate() {
|
294 |
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
|
295 |
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
296 |
|
|
|
|
|
|
|
297 |
// Mouse glow effect
|
298 |
const gradient = ctx.createRadialGradient(mouseX, mouseY, 0, mouseX, mouseY, 100);
|
299 |
gradient.addColorStop(0, 'rgba(123, 63, 242, 0.3)');
|
@@ -348,14 +398,93 @@ function triggerGlitch() {
|
|
348 |
createBurst(10, 'quantum');
|
349 |
}
|
350 |
|
351 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
352 |
const watchQuantum = new MutationObserver((mutations) => {
|
353 |
mutations.forEach((mutation) => {
|
354 |
const text = mutation.target.textContent || '';
|
355 |
if (text.includes('QUANTUM REALM ENTERED')) {
|
356 |
createBurst(5, 'quantum');
|
357 |
-
} else if (text.includes('
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
triggerGlitch();
|
|
|
359 |
}
|
360 |
});
|
361 |
});
|
@@ -384,22 +513,6 @@ canvas.addEventListener('mousemove', (e) => {
|
|
384 |
mouseY = (e.clientY - rect.top) * (canvas.height / rect.height);
|
385 |
});
|
386 |
|
387 |
-
canvas.addEventListener('click', (e) => {
|
388 |
-
const rect = canvas.getBoundingClientRect();
|
389 |
-
const x = (e.clientX - rect.left) * (canvas.width / rect.width);
|
390 |
-
const y = (e.clientY - rect.top) * (canvas.height / rect.height);
|
391 |
-
|
392 |
-
// Create burst at click location
|
393 |
-
for (let i = 0; i < 50; i++) {
|
394 |
-
const angle = (Math.PI * 2 * i) / 50;
|
395 |
-
const speed = Math.random() * 10 + 5;
|
396 |
-
particles.push(new Particle(
|
397 |
-
x + Math.cos(angle) * 10,
|
398 |
-
y + Math.sin(angle) * 10,
|
399 |
-
['#00FF88', '#7B3FF2', '#00AAFF', '#FFD700'][Math.floor(Math.random() * 4)]
|
400 |
-
));
|
401 |
-
}
|
402 |
-
});
|
403 |
|
404 |
// Auto-start evolution after intro
|
405 |
setTimeout(() => {
|
@@ -408,6 +521,8 @@ setTimeout(() => {
|
|
408 |
startBtn.click();
|
409 |
}
|
410 |
}, 4000);
|
|
|
|
|
411 |
</script>
|
412 |
"""
|
413 |
|
@@ -608,6 +723,31 @@ def format_multiplayer_leaderboard():
|
|
608 |
|
609 |
return html
|
610 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
611 |
def simulate_evolution():
|
612 |
"""Simulate one evolution step."""
|
613 |
if not state["running"]:
|
@@ -657,12 +797,22 @@ def simulate_evolution():
|
|
657 |
"message": "βοΈ QUANTUM REALM ENTERED! Reality is bending..."
|
658 |
})
|
659 |
|
660 |
-
if new_fitness >= 0.99:
|
661 |
state["events"].append({
|
662 |
"time": datetime.now().strftime("%H:%M:%S"),
|
663 |
-
"type": "
|
664 |
-
"message": "
|
665 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
666 |
|
667 |
return event
|
668 |
|
@@ -816,7 +966,15 @@ def format_events():
|
|
816 |
html = '<div style="background: #0A0A2A; padding: 15px; border-radius: 10px; height: 300px; overflow-y: auto; font-family: monospace;">'
|
817 |
|
818 |
for event in state["events"][-20:][::-1]:
|
819 |
-
if event["type"] == "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
820 |
color = "#FFD700"
|
821 |
icon = "π"
|
822 |
style = "font-size: 16px; font-weight: bold; background: linear-gradient(45deg, #7B3FF2, #00AAFF); padding: 10px; border-radius: 5px; margin: 5px 0;"
|
@@ -1155,6 +1313,33 @@ with gr.Blocks(
|
|
1155 |
outputs=[fitness_display, generation_display, variants_display, speed_display, fitness_chart, landscape_3d, multiplayer_display, code_display, achievements_display, event_log]
|
1156 |
)
|
1157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1158 |
# Challenge Mode
|
1159 |
with gr.Row():
|
1160 |
gr.Markdown("""
|
|
|
25 |
"player_name": f"Player_{random.randint(1000, 9999)}",
|
26 |
"multiplayer_active": False,
|
27 |
"other_players": {},
|
28 |
+
"global_best": 0.9333,
|
29 |
+
"boss_active": False,
|
30 |
+
"boss_health": 0,
|
31 |
+
"boss_defeated": False
|
32 |
}
|
33 |
|
34 |
# Simulated multiplayer data
|
|
|
293 |
}
|
294 |
}
|
295 |
|
296 |
+
// Click to damage boss
|
297 |
+
canvas.addEventListener('click', (e) => {
|
298 |
+
const rect = canvas.getBoundingClientRect();
|
299 |
+
const x = (e.clientX - rect.left) * (canvas.width / rect.width);
|
300 |
+
const y = (e.clientY - rect.top) * (canvas.height / rect.height);
|
301 |
+
|
302 |
+
// Create burst at click location
|
303 |
+
for (let i = 0; i < 50; i++) {
|
304 |
+
const angle = (Math.PI * 2 * i) / 50;
|
305 |
+
const speed = Math.random() * 10 + 5;
|
306 |
+
particles.push(new Particle(
|
307 |
+
x + Math.cos(angle) * 10,
|
308 |
+
y + Math.sin(angle) * 10,
|
309 |
+
['#00FF88', '#7B3FF2', '#00AAFF', '#FFD700'][Math.floor(Math.random() * 4)]
|
310 |
+
));
|
311 |
+
}
|
312 |
+
|
313 |
+
// Damage boss if active and clicked on it
|
314 |
+
if (bossActive && bossHealth > 0) {
|
315 |
+
const bossX = canvas.width / 2;
|
316 |
+
const bossY = canvas.height / 3;
|
317 |
+
const dist = Math.sqrt((x - bossX) ** 2 + (y - bossY) ** 2);
|
318 |
+
|
319 |
+
if (dist < 80) {
|
320 |
+
bossHealth = Math.max(0, bossHealth - 10);
|
321 |
+
createBurst(3, 'quantum');
|
322 |
+
|
323 |
+
if (bossHealth <= 0 && bossActive) {
|
324 |
+
// Boss defeated!
|
325 |
+
bossActive = false;
|
326 |
+
window.bossDamageCallback && window.bossDamageCallback();
|
327 |
+
|
328 |
+
// Victory effects
|
329 |
+
for (let i = 0; i < 5; i++) {
|
330 |
+
setTimeout(() => {
|
331 |
+
createBurst(10, 'quantum');
|
332 |
+
triggerGlitch();
|
333 |
+
}, i * 200);
|
334 |
+
}
|
335 |
+
}
|
336 |
+
}
|
337 |
+
}
|
338 |
+
});
|
339 |
+
|
340 |
function animate() {
|
341 |
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
|
342 |
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
343 |
|
344 |
+
// Draw boss first (behind particles)
|
345 |
+
drawBoss();
|
346 |
+
|
347 |
// Mouse glow effect
|
348 |
const gradient = ctx.createRadialGradient(mouseX, mouseY, 0, mouseX, mouseY, 100);
|
349 |
gradient.addColorStop(0, 'rgba(123, 63, 242, 0.3)');
|
|
|
398 |
createBurst(10, 'quantum');
|
399 |
}
|
400 |
|
401 |
+
// Boss battle system
|
402 |
+
let bossActive = false;
|
403 |
+
let bossHealth = 100;
|
404 |
+
|
405 |
+
function drawBoss() {
|
406 |
+
if (!bossActive) return;
|
407 |
+
|
408 |
+
const bossX = canvas.width / 2;
|
409 |
+
const bossY = canvas.height / 3;
|
410 |
+
|
411 |
+
// Boss body (menacing eye)
|
412 |
+
ctx.save();
|
413 |
+
ctx.fillStyle = '#FF0000';
|
414 |
+
ctx.strokeStyle = '#000000';
|
415 |
+
ctx.lineWidth = 3;
|
416 |
+
|
417 |
+
// Outer eye
|
418 |
+
ctx.beginPath();
|
419 |
+
ctx.ellipse(bossX, bossY, 80, 40, 0, 0, Math.PI * 2);
|
420 |
+
ctx.fill();
|
421 |
+
ctx.stroke();
|
422 |
+
|
423 |
+
// Inner eye
|
424 |
+
ctx.fillStyle = '#000000';
|
425 |
+
ctx.beginPath();
|
426 |
+
ctx.arc(bossX, bossY, 20, 0, Math.PI * 2);
|
427 |
+
ctx.fill();
|
428 |
+
|
429 |
+
// Pupil that follows mouse
|
430 |
+
const dx = mouseX - bossX;
|
431 |
+
const dy = mouseY - bossY;
|
432 |
+
const angle = Math.atan2(dy, dx);
|
433 |
+
const pupilX = bossX + Math.cos(angle) * 10;
|
434 |
+
const pupilY = bossY + Math.sin(angle) * 10;
|
435 |
+
|
436 |
+
ctx.fillStyle = '#FFFFFF';
|
437 |
+
ctx.beginPath();
|
438 |
+
ctx.arc(pupilX, pupilY, 5, 0, Math.PI * 2);
|
439 |
+
ctx.fill();
|
440 |
+
|
441 |
+
// Health bar
|
442 |
+
ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
|
443 |
+
ctx.fillRect(bossX - 50, bossY - 70, 100, 10);
|
444 |
+
ctx.fillStyle = 'rgba(0, 255, 0, 0.8)';
|
445 |
+
ctx.fillRect(bossX - 50, bossY - 70, bossHealth, 10);
|
446 |
+
ctx.strokeRect(bossX - 50, bossY - 70, 100, 10);
|
447 |
+
|
448 |
+
// Boss title
|
449 |
+
ctx.fillStyle = '#FFFFFF';
|
450 |
+
ctx.font = 'bold 20px Arial';
|
451 |
+
ctx.textAlign = 'center';
|
452 |
+
ctx.fillText('THE LOCAL OPTIMUM', bossX, bossY - 80);
|
453 |
+
|
454 |
+
ctx.restore();
|
455 |
+
|
456 |
+
// Boss attacks
|
457 |
+
if (Math.random() < 0.02 && bossHealth > 0) {
|
458 |
+
// Laser beam attack
|
459 |
+
for (let i = 0; i < 20; i++) {
|
460 |
+
const attackParticle = new Particle(
|
461 |
+
bossX + (Math.random() - 0.5) * 50,
|
462 |
+
bossY,
|
463 |
+
'#FF0000'
|
464 |
+
);
|
465 |
+
attackParticle.vy = 10;
|
466 |
+
attackParticle.vx = (Math.random() - 0.5) * 5;
|
467 |
+
particles.push(attackParticle);
|
468 |
+
}
|
469 |
+
}
|
470 |
+
}
|
471 |
+
|
472 |
+
// Watch for quantum and boss events
|
473 |
const watchQuantum = new MutationObserver((mutations) => {
|
474 |
mutations.forEach((mutation) => {
|
475 |
const text = mutation.target.textContent || '';
|
476 |
if (text.includes('QUANTUM REALM ENTERED')) {
|
477 |
createBurst(5, 'quantum');
|
478 |
+
} else if (text.includes('BOSS APPEARED')) {
|
479 |
+
bossActive = true;
|
480 |
+
bossHealth = 100;
|
481 |
+
speak("Warning! Final boss detected. The Local Optimum blocks your path to perfection!", 1.1, 0.8);
|
482 |
+
} else if (text.includes('BOSS DEFEATED')) {
|
483 |
+
bossActive = false;
|
484 |
+
bossHealth = 0;
|
485 |
+
createBurst(20, 'quantum'); // Massive victory explosion
|
486 |
triggerGlitch();
|
487 |
+
speak("Victory! You have achieved perfection! 100 percent fitness!", 1.2, 1.2);
|
488 |
}
|
489 |
});
|
490 |
});
|
|
|
513 |
mouseY = (e.clientY - rect.top) * (canvas.height / rect.height);
|
514 |
});
|
515 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
516 |
|
517 |
// Auto-start evolution after intro
|
518 |
setTimeout(() => {
|
|
|
521 |
startBtn.click();
|
522 |
}
|
523 |
}, 4000);
|
524 |
+
|
525 |
+
// Boss defeat callback is now defined in the main app
|
526 |
</script>
|
527 |
"""
|
528 |
|
|
|
723 |
|
724 |
return html
|
725 |
|
726 |
+
def handle_boss_defeat():
|
727 |
+
"""Handle boss defeat and reach 100% fitness."""
|
728 |
+
if state["boss_active"] and state["boss_health"] <= 0:
|
729 |
+
state["boss_defeated"] = True
|
730 |
+
state["boss_active"] = False
|
731 |
+
state["fitness_history"].append(1.0) # 100% fitness!
|
732 |
+
|
733 |
+
state["events"].append({
|
734 |
+
"time": datetime.now().strftime("%H:%M:%S"),
|
735 |
+
"type": "victory",
|
736 |
+
"message": "π BOSS DEFEATED! You've achieved 100% FITNESS! PERFECTION ATTAINED!"
|
737 |
+
})
|
738 |
+
|
739 |
+
# Unlock special achievement
|
740 |
+
if "perfection_plus" not in state["achievements"]:
|
741 |
+
state["achievements"].append("perfection_plus")
|
742 |
+
state["events"].append({
|
743 |
+
"time": datetime.now().strftime("%H:%M:%S"),
|
744 |
+
"type": "achievement",
|
745 |
+
"message": "π LEGENDARY ACHIEVEMENT: Perfection Plus Ultra!"
|
746 |
+
})
|
747 |
+
|
748 |
+
return True
|
749 |
+
return False
|
750 |
+
|
751 |
def simulate_evolution():
|
752 |
"""Simulate one evolution step."""
|
753 |
if not state["running"]:
|
|
|
797 |
"message": "βοΈ QUANTUM REALM ENTERED! Reality is bending..."
|
798 |
})
|
799 |
|
800 |
+
if new_fitness >= 0.99 and current_fitness < 0.99:
|
801 |
state["events"].append({
|
802 |
"time": datetime.now().strftime("%H:%M:%S"),
|
803 |
+
"type": "boss",
|
804 |
+
"message": "πΎ FINAL BOSS APPEARED: The Local Optimum! Click on it to attack!"
|
805 |
})
|
806 |
+
# Trigger boss battle
|
807 |
+
state["boss_active"] = True
|
808 |
+
state["boss_health"] = 100
|
809 |
+
|
810 |
+
# Boss battle progress
|
811 |
+
if state["boss_active"] and state["boss_health"] > 0:
|
812 |
+
# Boss slowly damages our fitness
|
813 |
+
damage = random.uniform(0.0001, 0.0005)
|
814 |
+
new_fitness = max(0.98, new_fitness - damage)
|
815 |
+
state["fitness_history"][-1] = new_fitness
|
816 |
|
817 |
return event
|
818 |
|
|
|
966 |
html = '<div style="background: #0A0A2A; padding: 15px; border-radius: 10px; height: 300px; overflow-y: auto; font-family: monospace;">'
|
967 |
|
968 |
for event in state["events"][-20:][::-1]:
|
969 |
+
if event["type"] == "victory":
|
970 |
+
color = "#FFD700"
|
971 |
+
icon = "π"
|
972 |
+
style = "font-size: 20px; font-weight: bold; background: linear-gradient(45deg, #FFD700, #FF6B6B); padding: 15px; border-radius: 10px; margin: 10px 0; animation: pulse 0.5s infinite; text-shadow: 0 0 20px #FFD700; border: 3px solid #FFD700;"
|
973 |
+
elif event["type"] == "boss":
|
974 |
+
color = "#FF0000"
|
975 |
+
icon = "πΎ"
|
976 |
+
style = "font-size: 18px; font-weight: bold; background: rgba(255, 0, 0, 0.3); padding: 12px; border-radius: 8px; margin: 8px 0; border: 2px solid #FF0000; animation: pulse 2s infinite;"
|
977 |
+
elif event["type"] == "achievement":
|
978 |
color = "#FFD700"
|
979 |
icon = "π"
|
980 |
style = "font-size: 16px; font-weight: bold; background: linear-gradient(45deg, #7B3FF2, #00AAFF); padding: 10px; border-radius: 5px; margin: 5px 0;"
|
|
|
1313 |
outputs=[fitness_display, generation_display, variants_display, speed_display, fitness_chart, landscape_3d, multiplayer_display, code_display, achievements_display, event_log]
|
1314 |
)
|
1315 |
|
1316 |
+
# Hidden boss defeat button
|
1317 |
+
boss_defeat_btn = gr.Button("Boss Defeat Trigger", visible=False, elem_id="boss_defeat_btn")
|
1318 |
+
|
1319 |
+
def on_boss_defeat():
|
1320 |
+
"""Handle boss defeat from JavaScript."""
|
1321 |
+
if handle_boss_defeat():
|
1322 |
+
return {}
|
1323 |
+
return {}
|
1324 |
+
|
1325 |
+
boss_defeat_btn.click(
|
1326 |
+
fn=on_boss_defeat,
|
1327 |
+
outputs=[]
|
1328 |
+
)
|
1329 |
+
|
1330 |
+
# JavaScript to handle boss defeat callback
|
1331 |
+
gr.HTML('''
|
1332 |
+
<script>
|
1333 |
+
// Connect boss defeat callback to Gradio
|
1334 |
+
window.bossDamageCallback = () => {
|
1335 |
+
const btn = document.getElementById('boss_defeat_btn');
|
1336 |
+
if (btn) {
|
1337 |
+
btn.click();
|
1338 |
+
}
|
1339 |
+
};
|
1340 |
+
</script>
|
1341 |
+
''')
|
1342 |
+
|
1343 |
# Challenge Mode
|
1344 |
with gr.Row():
|
1345 |
gr.Markdown("""
|