File size: 2,436 Bytes
414dc55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Det. Hale — your partner on the wire. Contextual, spoiler-safe hints from the server.
import { useEffect, useState } from 'preact/hooks'

import { getHint } from '../api'
import { useTypewriter } from '../engine/pixel'
import { useGame } from '../store'
import { Portrait } from './components'

const HIDDEN = new Set(['title', 'verdict', 'share', 'boot'])
const FALLBACK = 'Work the evidence, detective. Find where a statement and a fact disagree, and press there.'

export function Assistant() {
  const g = useGame()
  const [open, setOpen] = useState(false)
  const [hint, setHint] = useState('')
  const screen = g.state.screen

  useEffect(() => {
    const t = () => setOpen((o) => !o)
    const c = () => setOpen(false)
    window.addEventListener('toggle-hint', t)
    window.addEventListener('close-hint', c)
    return () => {
      window.removeEventListener('toggle-hint', t)
      window.removeEventListener('close-hint', c)
    }
  }, [])

  useEffect(() => {
    setOpen(false)
  }, [screen])

  useEffect(() => {
    if (!open) return
    let alive = true
    setHint('')
    getHint(g.runId, screen)
      .then((r) => {
        if (alive) setHint(r.hint || FALLBACK)
      })
      .catch(() => {
        if (alive) setHint(FALLBACK)
      })
    return () => {
      alive = false
    }
  }, [open, screen, g.runId])

  const [typed, done] = useTypewriter(open ? hint : '', g.state.tweaks.typeSpeed || 18, open)

  if (HIDDEN.has(screen) || !open) return null
  return (
    <div class="assistant">
      <div class="assistant__panel">
        <div class="between" style={{ marginBottom: 8 }}>
          <div class="row" style={{ gap: 8, alignItems: 'center' }}>
            <div style={{ background: 'var(--ink-1)', boxShadow: 'inset 0 0 0 2px var(--ink-0)', padding: 2 }}>
              <Portrait id="detective" px={3} />
            </div>
            <div class="col" style={{ gap: 1 }}>
              <span class="t-display amber" style={{ fontSize: 9 }}>DET. HALE</span>
              <span class="t-label" style={{ fontSize: 7 }}>YOUR PARTNER · ON THE WIRE</span>
            </div>
          </div>
          <button class="assistant__x" onClick={() => setOpen(false)}>✕</button>
        </div>
        <p class="t-body" style={{ fontSize: 14, lineHeight: 1.5, color: 'var(--bone-2)' }}>
          “{typed}
          {!done && <span class="cursor" />}”
        </p>
      </div>
    </div>
  )
}