Add the conversion match mode

Introduce a second match mode alongside Classic. In Conversion mode
hiders are invisible to each other (and to hunters during Hide), and a
hunter hit converts the hider into a full hunter in place instead of
sending them to the spectator freecam. The mode is replicated to all
clients through the existing phase named-message byte; visibility is
computed locally per client per mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-30 15:20:54 +02:00
1 parent 1f46e6258d
commit f485d1676b
2 files changed
+113 -28

No files matched your search

+42 -10
View File
@@ -86,7 +86,12 @@ public class NetworkPlayerSetup : NetworkBehaviour
if (IsOwner)
{
PlaceAtSpawn();
// A Conversion-mode tag respawns the hider as this Hunter variant mid-Seek; keep the server-set
// position (it converts where it was tagged) by skipping the spawn-area/ring placement. Match-start
// variants spawn while the sub-phase is still None, so they DO place; end-match lobby avatars spawn
// after the sub-phase is cleared, so they place too. Only an in-place conversion lands here mid-Seek.
if (!SpawnedMidSeek())
PlaceAtSpawn();
var manager = FindFirstObjectByType<GameModeManager>(FindObjectsInactive.Include);
if (manager)
@@ -168,9 +173,10 @@ public class NetworkPlayerSetup : NetworkBehaviour
private void Update() => UpdateVisibility();
// Per-client visibility: each machine decides whether to render THIS avatar's body from the LOCAL
// viewer's perspective. A found hider is hidden for everyone; during HIDE, hiders are hidden on hunter
// clients only (the spec - hunters can't see hiders yet). The local owner's own body is left alone unless
// found, so this never fights the FirstPersonController's own-body self-hide.
// viewer's perspective (hunter bodies are always visible; only hider bodies are ever hidden). A found
// hider (Classic) is hidden for everyone. Otherwise it depends on the match MODE - see ComputeVisible.
// The local owner's own body is left alone unless found, so this never fights the FirstPersonController's
// own-body self-hide.
private void UpdateVisibility()
{
bool found = _isFound.Value;
@@ -187,20 +193,46 @@ public class NetworkPlayerSetup : NetworkBehaviour
_visibilityApplied = true;
}
// Decides whether THIS avatar's body is rendered for the local viewer. Hunters and non-match avatars are
// always visible; a Classic-found hider is always hidden; Resolution reveals everyone. The rest is the
// hider-visibility matrix per mode:
// Classic - Hide: hidden from hunters only (hiders still see each other); Seek: visible to all.
// Conversion - Hide: hidden from EVERYONE (hiders don't see each other either); Seek: only hunters see
// hiders (so they can shoot them; hiders stay blind to each other).
private bool ComputeVisible(bool found)
{
if (found) return false;
if (found) return false; // Classic: a found hider is out of play, hidden for all
var match = MatchManager.Instance;
if (match && match.MatchActive
&& match.LocalSubPhase == MatchManager.MatchSubPhase.Hide
&& role == PlayerRole.Hider
&& LocalViewerIsHunter())
return false;
if (!match || !match.MatchActive) return true; // lobby / no match -> everything visible
if (role != PlayerRole.Hider) return true; // hunters are always visible
var phase = match.LocalSubPhase;
if (phase == MatchManager.MatchSubPhase.Resolution) return true; // all revealed at the end
if (match.LocalMatchMode == MatchManager.MatchMode.Conversion)
{
// Hiders are hidden from each other the whole match; only hunters get to see them, and only
// during Seek (so the hide phase truly hides them from everyone but themselves).
if (phase == MatchManager.MatchSubPhase.Hide) return false;
if (phase == MatchManager.MatchSubPhase.Seek) return LocalViewerIsHunter();
return true;
}
// Classic: hiders are hidden from hunters during Hide only; visible to everyone otherwise.
if (phase == MatchManager.MatchSubPhase.Hide && LocalViewerIsHunter()) return false;
return true;
}
// True if this avatar is spawning during the SEEK sub-phase - i.e. a Conversion-mode tag respawning a
// hider as the Hunter variant in place. Match-start and end-match respawns never happen during Seek
// (start spawns before Hide, end spawns after the phase is cleared), so this uniquely flags a conversion.
private static bool SpawnedMidSeek()
{
var match = MatchManager.Instance;
return match && match.LocalSubPhase == MatchManager.MatchSubPhase.Seek;
}
// True if THIS machine's local player is a Hunter role variant (so it must not see hiders during hide).
private static bool LocalViewerIsHunter()
{