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("""
|