class_name SimConfig extends RefCounted ## Tuning constants shared verbatim by the server simulation and the client ## replica. Nothing here may differ between the two builds -- if a value needs ## to differ, it belongs in [GameConfig], not here. # --- Time ------------------------------------------------------------------- const TICK_RATE := 60 const TICK_DELTA := 1.0 / 60.0 ## Server sends a snapshot every N ticks (60 / 3 = 20 Hz). const SNAPSHOT_INTERVAL := 3 ## How far behind the newest snapshot the client renders remote actors. const INTERPOLATION_DELAY_TICKS := 6 # --- Arena ------------------------------------------------------------------ const ARENA_HALF := Vector2(620.0, 340.0) ## Bullets are culled once they leave the arena by this margin. const BULLET_CULL_MARGIN := 64.0 # --- Player ----------------------------------------------------------------- const PLAYER_SPEED := 240.0 ## Authoritative hitbox. Smaller than PLAYER_VISUAL_RADIUS on purpose: a client ## renders its own and everyone else's ship a little late (interpolation delay, ## reconciliation smoothing), so a hitbox that matched the sprite exactly would ## let bullets connect against a ship the player watched dodge clear of them. ## Erring small means the occasional bullet visibly clips the ship without a ## hit -- a client-side illusion, but the one that reads as fair, versus a ## bullet that visibly missed still registering as a hit. const PLAYER_RADIUS := 6.0 ## Render-only. Used by src/view/, never by anything under src/sim/. const PLAYER_VISUAL_RADIUS := 13.0 ## Where a player's bullets are born, measured from the ship's centre. Derived ## from the VISUAL radius rather than the hitbox on purpose: this is the one ## sim number whose whole job is to line up with what the player sees. Keep it ## clear of PLAYER_VISUAL_RADIUS by a few px, or bullets appear to spawn inside ## the ship -- and on a remote client, the ship is also drawn a tick or two ## ahead of the server, so this margin is what absorbs that too. const PLAYER_MUZZLE_OFFSET := PLAYER_VISUAL_RADIUS + 6.0 const PLAYER_MAX_HP := 100 const PLAYER_FIRE_COOLDOWN := 7 # ticks const PLAYER_BULLET_SPEED := 620.0 const PLAYER_BULLET_RADIUS := 4.0 const PLAYER_BULLET_LIFETIME := 90 # ticks const PLAYER_BULLET_DAMAGE := 6 const PLAYER_IFRAMES := 36 # ticks of invulnerability after a hit ## Invulnerable *and* unable to shoot on entering a dungeon, so arriving into a ## live bullet field is survivable. Both halves matter: invulnerability alone ## would make the spawn point a free firing position. const SPAWN_GRACE_TICKS := 120 # 2 seconds # --- Anti-cheat guards ------------------------------------------------------ ## Inputs older than this (relative to the newest accepted) are discarded. const INPUT_MAX_AGE := 30 ## Inputs claiming to be further ahead than this of the server tick are clamped. const INPUT_MAX_LEAD := 12 ## Hard ceiling on inputs consumed from one peer in a single tick. const INPUT_MAX_PER_TICK := 4 # --- Emergency escape ------------------------------------------------------- const ESCAPE_CHANNEL_TICKS := 60 # 1 second ## Taking damage does NOT interrupt the channel. It used to, which sounds like ## the right kind of risk until you notice the interaction with disconnects: if ## a player under fire cannot escape, quitting the process is strictly better ## than using the button, and the escape hatch becomes the cheese. A dropped ## connection now runs the same one-second channel (see SimPlayer.linkdead), ## which only works if being shot cannot cancel it. # --- Bullets ---------------------------------------------------------------- const MAX_BULLETS := 4096 const TEAM_PLAYER := 0 const TEAM_ENEMY := 1 # --- Bullet visual kinds (index into the renderer's atlas) ------------------ const KIND_PLAYER_SHOT := 0 const KIND_ORB := 1 const KIND_NEEDLE := 2 const KIND_HEAVY := 3 # --- Instances -------------------------------------------------------------- const LOBBY_INSTANCE_ID := 1 const DUNGEON_PARTY_MAX := 4 ## How long a forming dungeon waits for more players before it locks. const DUNGEON_FORMING_TICKS := 300 ## Victory lap: how long a cleared dungeon holds the party before returning ## them to the hub and closing. Once closed (or once it empties), the next ## player through the portal opens a fresh instance. const DUNGEON_CLEARED_EXIT_TICKS := 1800 # 30 seconds # --- Portal ----------------------------------------------------------------- const PORTAL_POS := Vector2(0.0, -220.0) const PORTAL_RADIUS := 60.0