Chat.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { Anim, Character, type CharacterContext } from './Character';
  2. import { aimDir } from './Mamie';
  3. /**
  4. * Le Chat.
  5. * - Attack: paw swipe.
  6. * - Special: shoves what is in front of him: falling chunks, loose items, and stunned players
  7. * (others only budge a little). Perfect for pushing someone off the edge.
  8. * - Flaw: now and then he stops to lick his paw for a second, whatever is going on.
  9. */
  10. export class Chat extends Character {
  11. private pawTimer = 0;
  12. private shoveTimer = 0;
  13. private licking = 0;
  14. /** Seconds before the next lick, drawn on the first tick. */
  15. private nextLick = -1;
  16. onAttack(ctx: CharacterContext): void {
  17. const p = this.stats.params;
  18. const [dx, dy] = aimDir(ctx);
  19. const reach = this.size + p.pawReach;
  20. const px = ctx.x + dx * reach;
  21. const py = ctx.y + dy * reach;
  22. ctx.hit(px, py, p.pawRadius, p.pawKnockback, p.pawStun);
  23. ctx.emitOp({ kind: 'carve', x: Math.round(px), y: Math.round(py), r: Math.round(p.pawCarve), power: Math.round(p.pawPower) });
  24. this.pawTimer = p.pawAnim;
  25. }
  26. onSpecial(ctx: CharacterContext): void {
  27. const p = this.stats.params;
  28. const reach = this.size + p.shoveReach / 2;
  29. ctx.shove(ctx.x + ctx.facing * reach, ctx.y, p.shoveRadius, ctx.facing * p.shoveSpeed, -p.shoveLift, p.shoveFraction);
  30. this.shoveTimer = p.shoveAnim;
  31. }
  32. override onTick(ctx: CharacterContext, dt: number): void {
  33. const p = this.stats.params;
  34. this.pawTimer = Math.max(0, this.pawTimer - dt);
  35. this.shoveTimer = Math.max(0, this.shoveTimer - dt);
  36. if (this.nextLick < 0) this.nextLick = p.lickMin + ctx.random() * (p.lickMax - p.lickMin);
  37. if (this.licking > 0) {
  38. this.licking = Math.max(0, this.licking - dt);
  39. return;
  40. }
  41. this.nextLick -= dt;
  42. if (this.nextLick <= 0) {
  43. this.licking = p.lickTime;
  44. this.nextLick = p.lickMin + ctx.random() * (p.lickMax - p.lickMin);
  45. ctx.cue('lick');
  46. }
  47. }
  48. override busy(): boolean {
  49. return this.licking > 0;
  50. }
  51. override anim(): number {
  52. return (this.pawTimer > 0 ? Anim.Attack : 0) | (this.shoveTimer > 0 ? Anim.Special : 0) | (this.licking > 0 ? Anim.Busy : 0);
  53. }
  54. }