# `QuakeServer.Visibility`
[🔗](https://github.com/jaman/quake_server/blob/v0.1.0/lib/quake_server/visibility.ex#L1)

What a map's visibility lets a viewer potentially see, as FTE's server works it out for
Quake and Half-Life maps (`q1bsp.c`): the leaves an entity's box touches, recorded when
it is linked, and the leaves seen from every leaf within 8 units of a viewer's eye (the
fat PVS), and the leaves that may hear a point (its PHS).

    leaves = QuakeServer.Visibility.touched(bsp, absmin, absmax)
    sight = QuakeServer.Visibility.fat(bsp, eye)
    QuakeServer.Visibility.seen?(sight, leaves)

Touched leaves leave out solid ones; more than 32 are `:all`, seen by every viewer. A
sight is an integer whose bit `i` is set when leaf `i` may be seen, or `:all` on a map
without visibility or from a leaf that keeps none.

# `leaves`

```elixir
@type leaves() :: [non_neg_integer()] | :all
```

The leaves an entity is in.

# `sight`

```elixir
@type sight() :: non_neg_integer() | :all
```

The leaves a viewer may see.

# `fat`

```elixir
@spec fat(Cauldron3D.Bsp.t() | nil, Cauldron3D.Vec.t()) :: sight()
```

The leaves seen from every non-solid leaf within 8 units of `point`.

# `heard`

```elixir
@spec heard(Cauldron3D.Bsp.t() | nil, Cauldron3D.Vec.t()) :: sight()
```

The leaves that may hear `point` (its PHS): those seen from any leaf its leaf sees.
`:all` from leaf 0 or a leaf that keeps no visibility.

# `in_pvs?`

```elixir
@spec in_pvs?(Cauldron3D.Bsp.t() | nil, Cauldron3D.Vec.t(), leaves() | nil) ::
  boolean()
```

Whether an entity in `leaves`, the leaves recorded when it was last linked (`nil` for
one never linked), is in the PVS of `point` (`pvs/2`), as FTE's `checkpvs` decides:
never without a map or for an entity in no leaves, always for one in more than 32,
otherwise when one of its leaves is in that PVS.

# `phs_built?`

```elixir
@spec phs_built?(Cauldron3D.Bsp.t() | nil, number(), boolean()) :: boolean()
```

Whether FTE builds the map's PHS under the cvar `sv_calcphs` `setting`: never at 0,
always at 1, and at 2 unless the game is single player or the table would take a
megabyte or more (a row of whole 32-bit words a world leaf, for each world leaf).

# `point_seen?`

```elixir
@spec point_seen?(Cauldron3D.Bsp.t() | nil, sight(), Cauldron3D.Vec.t()) :: boolean()
```

Whether the leaf `point` is in is in `sight`; always for leaf 0.

# `pvs`

```elixir
@spec pvs(Cauldron3D.Bsp.t() | nil, Cauldron3D.Vec.t()) :: sight()
```

The leaves the leaf `point` is in can see (its PVS); `:all` from leaf 0 or a leaf that
keeps none. A point on a node's plane is taken to its back side.

# `seen?`

```elixir
@spec seen?(sight(), leaves()) :: boolean()
```

Whether any of `leaves` is in `sight`.

# `touched`

```elixir
@spec touched(Cauldron3D.Bsp.t() | nil, Cauldron3D.Vec.t(), Cauldron3D.Vec.t()) ::
  leaves()
```

The non-solid world leaves the box `mins`..`maxs` touches.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
