Replaces the fixed centred arena with per-world tile geometry, which is the foundation the remaining features sit on. - MapGrid: tile grid with three independent flags -- blocks movement, bullets, sight -- so a pit stops feet but not bullets or eyes, and a barricade stops feet and bullets but not eyes. Circle collision with per-axis sliding, and Bresenham line of sight shared by fog and aggro. - MapGen: rooms and corridors generated from (seed, depth), with hand-authored boss arenas from Rooms stamped in first so a corridor can never carve through a designed fight. Reachability from spawn to boss is asserted over 40 seeds -- "usually connected" is the failure mode that ruins one run in twenty. - Dungeons are populated at creation, per room, instead of gating on waves. You explore and choose your fights; the run ends when the boss dies, not when the map is swept. Boss rooms have no lock, so walking out is always available. - Aggro: enemies need range AND line of sight, so a dungeon stays quiet until engaged and cover actually protects. - Hard fog, scrolling camera, and terrain rendering. Maps are streamed per peer in chunks around that peer's player, and the seed is deliberately NOT sent -- a client holding it could regenerate the whole dungeon, which is a map hack for free. Stream radius (900u) is wider than view radius (460u) because the client predicts movement against walls and simulates bullets that die on them; the accepted cost is a cheater seeing a little further than the fog, never the floor plan. Partial map knowledge means wall deaths must be announced rather than derived. A test caught the subtle half of that: out-of-bounds tiles read as WALL by design, so checking geometry before bounds reported every bullet leaving the map as a wall kill. 128 tests (was 103); check.sh, test.sh and smoke.sh pass. 0.26 ms/tick with 4 players and a boss, ~65x headroom.
This commit is contained in:
@@ -124,6 +124,40 @@ would break that test, which is the point of having it.
|
||||
The menu says so out loud when you are in a dungeon -- the mechanic only reads
|
||||
as fair if the player knows the cost before clicking.
|
||||
|
||||
## Maps are streamed, never sent
|
||||
|
||||
A dungeon's geometry reaches a client as **chunks around that client's own
|
||||
player**, and nothing else. In particular the server does *not* send the
|
||||
generation seed, even though maps are a pure function of (kind, seed, depth) and
|
||||
sending two integers would be far cheaper: a client holding the seed can
|
||||
regenerate the entire dungeon locally, which is a complete map hack requiring no
|
||||
skill. Streaming bounds what a modified client can know to roughly where its
|
||||
player has physically been.
|
||||
|
||||
`MAP_STREAM_RADIUS` (900u) is deliberately wider than `FOG_VIEW_RADIUS` (460u).
|
||||
The client needs real geometry it cannot see, because it predicts its own
|
||||
movement against walls and simulates bullets that die on them. The accepted
|
||||
trade is that a cheater sees somewhat further than the fog shows -- what they
|
||||
cannot get is the floor plan.
|
||||
|
||||
Two consequences fall out of partial knowledge:
|
||||
|
||||
- **Wall deaths are announced.** A bullet dying to its lifetime or by leaving
|
||||
the map is derivable from the spawn event and the map's dimensions, so it
|
||||
costs nothing. A bullet dying against a *wall* is not derivable by a client
|
||||
that has not been streamed that wall, so the server sends an explicit
|
||||
`BULLET_DESPAWN`. Getting the order of those two checks wrong is easy and was
|
||||
caught by a test: out-of-bounds tiles read as `WALL` by design, so testing
|
||||
geometry before bounds reports every bullet that merely left the map as a
|
||||
wall kill.
|
||||
- **Unknown tiles are treated as empty**, not solid, so an unstreamed region can
|
||||
never wrongly stop a prediction. The stream radius keeps far enough ahead of
|
||||
the player that this never decides anything visible.
|
||||
|
||||
Hard fog is therefore a *rendering* rule, not a secrecy mechanism. The secrecy
|
||||
lives in what the server declines to send: terrain outside the stream radius,
|
||||
and (next stage) actors outside it.
|
||||
|
||||
## No contact damage
|
||||
|
||||
Nothing hurts you by touching it. Every threat is a bullet you can see and
|
||||
|
||||
Reference in New Issue
Block a user