using UnityEngine;
namespace NecromancerTome
{
///
/// Drains the colour out of the world while the necromancer is channelling something, and
/// lets it back in when he stops (user request 2026-09-14: "эффект, когда мир становится
/// тёмным и чёрнобелым... повесить его на момент ожидания применения порталов и на момент
/// ожидания утаскивания блока", with "желательно плавно... секунды за 3" in both directions).
/// Shared by both channels so the look, the timing and the name of the effect live in one
/// place rather than drifting apart in two files.
///
/// IT IS THE GAME'S OWN POST-PROCESS, not a reimplementation. EntityPlayerLocal carries a
/// ScreenEffects component - ScreenEffectManager - whose SetScreenEffect(name, intensity,
/// fadeTime) is what the engine itself calls for dying ("Dying"), for spawning in
/// ("VibrantDeSat") and for every buff in the game that tints the screen. THE FADE IS THAT
/// THIRD ARGUMENT: three seconds in and three seconds out cost nothing to implement, because
/// the ramp is the effect system's own.
///
/// THE EFFECT IS "Greyscale", AND THE CHOICE IS ABOUT WHO ELSE TOUCHES IT. These effects are
/// a flat namespace of materials loaded from Resources/ScreenEffects - anyone writing to a
/// name overwrites whatever was there, so picking one is mostly picking a fight to avoid:
///
/// - "Greyscale" is written by exactly two things in the whole game, twitch_buffMonochrome
/// and sandbox_blackandwhite - a Twitch-integration reward and a game-mode toggle. Neither
/// happens in an ordinary session, so the channel owns it in practice.
/// - "Dying" and "Dead" are the death visuals the user was describing, and they are exactly
/// the ones NOT to borrow: EntityPlayerLocal.Update writes "Dying" from the player's own
/// health every time it changes, so any damage mid-channel would take the effect over -
/// and being hit mid-channel is a thing that happens.
/// - "Dark" would have supplied the darkening half. It belongs to buffCrouching, which
/// fires on every crouch with a 0.2s fade and would stamp on this one.
///
/// SO THE DARKENING HALF IS DELIBERATELY NOT DONE. Both effects that dim the screen are owned
/// by something that fights for them - crouching, and dying - and losing that fight looks like
/// a bug in this mod rather than in the effect system. Greyscale alone reads as the world
/// going wrong, which is what was actually asked for; if it wants to be darker too, the list
/// below takes a second entry and nothing else changes.
///
/// NOTHING HERE TOUCHES INPUT. The effect is a camera post-process and outlives the timer
/// window on purpose: the three-second fade back keeps running while the player walks away,
/// which is the point of asking for a fade rather than a switch.
///
public static class ChannelVision
{
/// Seconds to fade in, and to fade back out.
public const float FadeSeconds = 3f;
/// What to fade, and how far. A list rather than a single name so a second layer
/// is one entry and not a rewrite - see the class comment on the darkening half.
public static readonly string[] EffectNames = { "Greyscale" };
/// Full strength per effect, in the same order as EffectNames.
public static readonly float[] EffectIntensities = { 1f };
/// Colour drains out over FadeSeconds.
public static void Begin(EntityPlayerLocal _player)
{
Apply(_player, _fullStrength: true);
}
/// Colour comes back over FadeSeconds. Safe to call when nothing is running -
/// fading an effect that is already at zero to zero does nothing - which is what lets
/// every exit path call it without first working out whether it is the one that has to.
///
public static void End(EntityPlayerLocal _player)
{
Apply(_player, _fullStrength: false);
}
public static void Apply(EntityPlayerLocal _player, bool _fullStrength)
{
if (_player == null || _player.ScreenEffectManager == null)
{
return;
}
for (int i = 0; i < EffectNames.Length; i++)
{
float intensity = _fullStrength ? EffectIntensities[i] : 0f;
_player.ScreenEffectManager.SetScreenEffect(EffectNames[i], intensity, FadeSeconds);
}
}
}
}