Back to Outbreak: Soycoon City
SOURCE / PINNED RELEASE

Made of little things.

Outbreak: Soycoon City

Release
db7750b1d009…
Author-recorded commit
3ee3f5fd27a6…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b87c04571a9

Archive hash verified: dbebdc772b142a1c…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

src/input.ts
import type { Controls } from './game.js';
export class Input {
  pressed = new Set<string>(); touch = new Map<number, string>();
  onAction: (action: string) => void;
  enabled = true;
  constructor(onAction: (action: string) => void) {
    this.onAction = onAction;
    window.addEventListener('keydown', this.down);
    window.addEventListener('keyup', this.up);
    window.addEventListener('blur', this.clear);
    document.addEventListener('visibilitychange', this.clear);
    document.querySelectorAll<HTMLButtonElement>('[data-hold]').forEach(button => {
      button.addEventListener('pointerdown', e => { e.preventDefault(); button.setPointerCapture(e.pointerId); this.touch.set(e.pointerId, button.dataset.hold!); button.classList.add('held'); });
      const end = (e: PointerEvent) => { this.touch.delete(e.pointerId); button.classList.remove('held'); };
      button.addEventListener('pointerup', end); button.addEventListener('pointercancel', end); button.addEventListener('lostpointercapture', end);
    });
  }
  down = (e: KeyboardEvent) => {
    if (!this.enabled || e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement || e.ctrlKey || e.metaKey) return;
    if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.code)) e.preventDefault();
    this.pressed.add(e.code);
    if (!e.repeat) {
      const a: Record<string, string> = { Space: 'shoot', KeyJ: 'shoot', KeyR: 'reload', KeyE: 'interact', Escape: 'pause' };
      if (a[e.code]) this.onAction(a[e.code]);
    }
  };
  up = (e: KeyboardEvent) => { this.pressed.delete(e.code); };
  clear = () => { this.pressed.clear(); this.touch.clear(); document.querySelectorAll('.held').forEach(e => e.classList.remove('held')); };
  get controls(): Controls {
    const all = new Set([...this.pressed, ...this.touch.values()]);
    const aim=all.has('KeyK')||all.has('aim')||all.has('KeyI')||all.has('aimUp'),aimUp=all.has('KeyI')||all.has('aimUp')||(aim&&all.has('ArrowUp'));
    return { forward: Number(all.has('KeyW') || (!aim&&all.has('ArrowUp')) || all.has('forward')) - Number(all.has('KeyS') || all.has('ArrowDown') || all.has('backward')), turn: Number(all.has('KeyA') || all.has('ArrowLeft') || all.has('left')) - Number(all.has('KeyD') || all.has('ArrowRight') || all.has('right')), run: all.has('ShiftLeft') || all.has('ShiftRight') || all.has('run'), aim,aimUp };
  }
  dispose(): void { window.removeEventListener('keydown', this.down); window.removeEventListener('keyup', this.up); window.removeEventListener('blur', this.clear); document.removeEventListener('visibilitychange', this.clear); }
}