Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

dumduel: slower bullets with fade, stick legs, MatrixChunky8 handles, passive dummy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+37 -35
+37 -35
system/public/aesthetic.computer/disks/dumduel.mjs
··· 4 4 5 5 const ARENA_W = 180; 6 6 const ARENA_H = 180; 7 - const BULLET_SPEED = 1.2; 7 + const BULLET_SPEED = 0.7; 8 8 const BULLET_R = 2; 9 9 const MOVE_SPEED = 1.0; 10 10 const FIRE_INTERVAL = 100; // frames between auto-shots (~1.7s) ··· 271 271 272 272 if (phase !== "fight" || !me || (!isDueling() && !dummy)) return; 273 273 274 - // Dummy AI — wander randomly in 2D 274 + // Dummy AI — just wander (no shooting) 275 275 if (dummy && opponent?.alive) { 276 - opponent.fireTimer--; 277 276 if (frameCount % 90 === 0) { 278 277 opponent.targetX = 20 + Math.random() * (ARENA_W - 40); 279 278 opponent.targetY = 20 + Math.random() * (ARENA_H - 40); ··· 284 283 if (dist > 1) { 285 284 opponent.x += (odx / dist) * MOVE_SPEED * 0.7; 286 285 opponent.y += (ody / dist) * MOVE_SPEED * 0.7; 287 - } 288 - const dummyMoving = Math.abs(opponent.targetX - opponent.x) > 2 || Math.abs(opponent.targetY - opponent.y) > 2; 289 - const theirBulletOut = bullets.some((b) => b.owner === "them"); 290 - if (opponent.fireTimer <= 0 && !dummyMoving && !theirBulletOut) { 291 - opponent.fireTimer = FIRE_INTERVAL; 292 - const { nx, ny } = norm(me.x - opponent.x, me.y - opponent.y); 293 - bullets.push({ 294 - x: opponent.x + nx * 6, y: opponent.y + ny * 6, 295 - vx: nx * BULLET_SPEED, vy: ny * BULLET_SPEED, 296 - owner: "them", 297 - }); 298 286 } 299 287 } 300 288 ··· 343 331 const b = bullets[i]; 344 332 b.x += b.vx; 345 333 b.y += b.vy; 334 + b.age = (b.age || 0) + 1; 335 + 336 + // Fade out after traveling a while 337 + if (b.age > 200) { 338 + bullets.splice(i, 1); 339 + continue; 340 + } 346 341 347 342 // Off arena 348 343 if (b.x < -10 || b.x > ARENA_W + 10 || b.y < -10 || b.y > ARENA_H + 10) { ··· 404 399 } 405 400 } 406 401 407 - function paint({ wipe, ink, box, write, circle, screen }) { 402 + function paint({ wipe, ink, box, write, circle, line, screen }) { 408 403 sw = screen.width; 409 404 sh = screen.height; 410 405 wipe(240, 238, 232); ··· 428 423 }); 429 424 430 425 if (me && opponent) { 431 - drawFigure(ink, circle, box, ox, oy, me, [50, 120, 200]); 432 - drawFigure(ink, circle, box, ox, oy, opponent, [200, 70, 60]); 426 + drawFigure(ink, circle, box, line, ox, oy, me, [50, 120, 200]); 427 + drawFigure(ink, circle, box, line, ox, oy, opponent, [200, 70, 60]); 433 428 } 434 429 435 430 const d0 = roster[0]?.handle || "?"; ··· 442 437 } 443 438 444 439 if (phase === "fight" || phase === "roundover") { 445 - // Bullets 440 + // Bullets (fade with age) 446 441 for (const b of bullets) { 447 - if (b.owner === "me") ink(50, 120, 200); 448 - else ink(200, 70, 60); 442 + const alpha = Math.max(40, 255 - (b.age || 0) * 1.2); 443 + if (b.owner === "me") ink(50, 120, 200, alpha); 444 + else ink(200, 70, 60, alpha); 449 445 circle(ox + Math.floor(b.x), oy + Math.floor(b.y), BULLET_R, true); 450 446 } 451 447 ··· 459 455 } 460 456 461 457 if (me && opponent) { 462 - drawFigure(ink, circle, box, ox, oy, me, [50, 120, 200]); 463 - drawFigure(ink, circle, box, ox, oy, opponent, [200, 70, 60]); 458 + drawFigure(ink, circle, box, line, ox, oy, me, [50, 120, 200]); 459 + drawFigure(ink, circle, box, line, ox, oy, opponent, [200, 70, 60]); 464 460 } 465 461 466 - // Handle labels 462 + // Handle labels (MatrixChunky8) 467 463 if (me) { 468 464 ink(50, 120, 200, 150).write(myHandle, { 469 465 x: ox + Math.floor(me.x) - myHandle.length * 3, 470 - y: oy + Math.floor(me.y) + BODY_R + 3, 471 - }); 466 + y: oy + Math.floor(me.y) + BODY_R + 5, 467 + }, undefined, undefined, false, "MatrixChunky8"); 472 468 } 473 469 if (opponent) { 474 470 ink(200, 70, 60, 150).write(opponent.handle, { 475 471 x: ox + Math.floor(opponent.x) - opponent.handle.length * 3, 476 - y: oy + Math.floor(opponent.y) + BODY_R + 3, 477 - }); 472 + y: oy + Math.floor(opponent.y) + BODY_R + 5, 473 + }, undefined, undefined, false, "MatrixChunky8"); 478 474 } 479 475 480 476 if (phase === "roundover" && roundWinner) { ··· 523 519 } 524 520 } 525 521 526 - function drawFigure(ink, circle, box, ox, oy, fig, col) { 522 + function drawFigure(ink, circle, box, line, ox, oy, fig, col) { 527 523 const fx = ox + Math.floor(fig.x); 528 524 const fy = oy + Math.floor(fig.y); 529 525 530 526 if (!fig.alive) { 527 + // Dead — X mark 531 528 ink(col[0], col[1], col[2], 60); 532 - circle(fx, fy, BODY_R, false); 533 - ink(col[0], col[1], col[2], 40); 534 - box(fx - 1, fy - 1, 2, 2); 529 + line(fx - 3, fy - 3, fx + 3, fy + 3); 530 + line(fx + 3, fy - 3, fx - 3, fy + 3); 535 531 return; 536 532 } 537 533 538 - // Body (filled circle) 539 534 ink(...col); 540 - circle(fx, fy, BODY_R, true); 541 - // Inner highlight 542 - ink(col[0] + 40, col[1] + 40, col[2] + 40).circle(fx, fy, BODY_R - 2, false); 535 + // Legs (splayed below body) 536 + line(fx, fy + 1, fx - 4, fy + 6); 537 + line(fx, fy + 1, fx + 4, fy + 6); 538 + // Arms 539 + line(fx - 1, fy - 1, fx - 5, fy + 2); 540 + line(fx + 1, fy - 1, fx + 5, fy + 2); 541 + // Head (filled circle on top) 542 + circle(fx, fy - 2, 3, true); 543 + // Eye dot 544 + ink(255, 255, 255).box(fx, fy - 3, 1, 1); 543 545 } 544 546 545 547 function meta() {