--- /dev/null
+using Content.Shared.Drowsiness;
+using Content.Shared.StatusEffect;
+using Robust.Client.Graphics;
+using Robust.Client.Player;
+using Robust.Shared.Enums;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
+
+namespace Content.Client.Drowsiness;
+
+public sealed class DrowsinessOverlay : Overlay
+{
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IEntitySystemManager _sysMan = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ public override OverlaySpace Space => OverlaySpace.WorldSpace;
+ public override bool RequestScreenTexture => true;
+ private readonly ShaderInstance _drowsinessShader;
+
+ public float CurrentPower = 0.0f;
+
+ private const float PowerDivisor = 250.0f;
+ private const float Intensity = 0.2f; // for adjusting the visual scale
+ private float _visualScale = 0; // between 0 and 1
+
+ public DrowsinessOverlay()
+ {
+ IoCManager.InjectDependencies(this);
+ _drowsinessShader = _prototypeManager.Index<ShaderPrototype>("Drowsiness").InstanceUnique();
+ }
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ var playerEntity = _playerManager.LocalEntity;
+
+ if (playerEntity == null)
+ return;
+
+ if (!_entityManager.HasComponent<DrowsinessComponent>(playerEntity)
+ || !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
+ return;
+
+ var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
+ if (!statusSys.TryGetTime(playerEntity.Value, SharedDrowsinessSystem.DrowsinessKey, out var time, status))
+ return;
+
+ var curTime = _timing.CurTime;
+ var timeLeft = (float)(time.Value.Item2 - curTime).TotalSeconds;
+
+ CurrentPower += 8f * (0.5f * timeLeft - CurrentPower) * args.DeltaSeconds / (timeLeft + 1);
+ }
+
+ protected override bool BeforeDraw(in OverlayDrawArgs args)
+ {
+ if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp))
+ return false;
+
+ if (args.Viewport.Eye != eyeComp.Eye)
+ return false;
+
+ _visualScale = Math.Clamp(CurrentPower / PowerDivisor, 0.0f, 1.0f);
+ return _visualScale > 0;
+ }
+
+ protected override void Draw(in OverlayDrawArgs args)
+ {
+ if (ScreenTexture == null)
+ return;
+
+ var handle = args.WorldHandle;
+ _drowsinessShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
+ _drowsinessShader.SetParameter("Strength", _visualScale * Intensity);
+ handle.UseShader(_drowsinessShader);
+ handle.DrawRect(args.WorldBounds, Color.White);
+ handle.UseShader(null);
+ }
+}
--- /dev/null
+using Content.Shared.Drowsiness;
+using Robust.Client.Graphics;
+using Robust.Client.Player;
+using Robust.Shared.Player;
+
+namespace Content.Client.Drowsiness;
+
+public sealed class DrowsinessSystem : SharedDrowsinessSystem
+{
+ [Dependency] private readonly IPlayerManager _player = default!;
+ [Dependency] private readonly IOverlayManager _overlayMan = default!;
+
+ private DrowsinessOverlay _overlay = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<DrowsinessComponent, ComponentInit>(OnDrowsinessInit);
+ SubscribeLocalEvent<DrowsinessComponent, ComponentShutdown>(OnDrowsinessShutdown);
+
+ SubscribeLocalEvent<DrowsinessComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
+ SubscribeLocalEvent<DrowsinessComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
+
+ _overlay = new();
+ }
+
+ private void OnPlayerAttached(EntityUid uid, DrowsinessComponent component, LocalPlayerAttachedEvent args)
+ {
+ _overlayMan.AddOverlay(_overlay);
+ }
+
+ private void OnPlayerDetached(EntityUid uid, DrowsinessComponent component, LocalPlayerDetachedEvent args)
+ {
+ _overlay.CurrentPower = 0;
+ _overlayMan.RemoveOverlay(_overlay);
+ }
+
+ private void OnDrowsinessInit(EntityUid uid, DrowsinessComponent component, ComponentInit args)
+ {
+ if (_player.LocalEntity == uid)
+ _overlayMan.AddOverlay(_overlay);
+ }
+
+ private void OnDrowsinessShutdown(EntityUid uid, DrowsinessComponent component, ComponentShutdown args)
+ {
+ if (_player.LocalEntity == uid)
+ {
+ _overlay.CurrentPower = 0;
+ _overlayMan.RemoveOverlay(_overlay);
+ }
+ }
+}
--- /dev/null
+using Content.Shared.Bed.Sleep;
+using Content.Shared.Drowsiness;
+using Content.Shared.StatusEffect;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Drowsiness;
+
+public sealed class DrowsinessSystem : SharedDrowsinessSystem
+{
+ [ValidatePrototypeId<StatusEffectPrototype>]
+ private const string SleepKey = "ForcedSleep"; // Same one used by N2O and other sleep chems.
+
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
+
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<DrowsinessComponent, ComponentStartup>(OnInit);
+ }
+
+ private void OnInit(EntityUid uid, DrowsinessComponent component, ComponentStartup args)
+ {
+ component.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y));
+ }
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator<DrowsinessComponent>();
+ while (query.MoveNext(out var uid, out var component))
+ {
+ if (_timing.CurTime < component.NextIncidentTime)
+ continue;
+
+ // Set the new time.
+ component.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y));
+
+ // sleep duration
+ var duration = TimeSpan.FromSeconds(_random.NextFloat(component.DurationOfIncident.X, component.DurationOfIncident.Y));
+
+ // Make sure the sleep time doesn't cut into the time to next incident.
+ component.NextIncidentTime += duration;
+
+ _statusEffects.TryAddStatusEffect<ForcedSleepingComponent>(uid, SleepKey, duration, false);
+ }
+ }
+}
--- /dev/null
+using Robust.Shared.Prototypes;
+using Content.Shared.Damage.Prototypes;
+
+namespace Content.Server.Radiation.Components;
+
+/// <summary>
+/// Exists for use as a status effect.
+/// Adds the DamageProtectionBuffComponent to the entity and adds the specified DamageModifierSet to its list of modifiers.
+/// </summary>
+[RegisterComponent]
+public sealed partial class RadiationProtectionComponent : Component
+{
+ /// <summary>
+ /// The radiation damage modifier for entities with this component.
+ /// </summary>
+ [DataField("modifier")]
+ public ProtoId<DamageModifierSetPrototype> RadiationProtectionModifierSetId = "PotassiumIodide";
+}
--- /dev/null
+using Content.Server.Radiation.Components;
+using Content.Shared.Damage.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Radiation.EntitySystems;
+
+public sealed class RadiationProtectionSystem : EntitySystem
+{
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<RadiationProtectionComponent, ComponentInit>(OnInit);
+ SubscribeLocalEvent<RadiationProtectionComponent, ComponentShutdown>(OnShutdown);
+ }
+
+ private void OnInit(EntityUid uid, RadiationProtectionComponent component, ComponentInit args)
+ {
+ if (!_prototypeManager.TryIndex(component.RadiationProtectionModifierSetId, out var modifier))
+ return;
+ var buffComp = EnsureComp<DamageProtectionBuffComponent>(uid);
+ // add the damage modifier if it isn't in the dict yet
+ if (!buffComp.Modifiers.ContainsKey(component.RadiationProtectionModifierSetId))
+ buffComp.Modifiers.Add(component.RadiationProtectionModifierSetId, modifier);
+ }
+
+ private void OnShutdown(EntityUid uid, RadiationProtectionComponent component, ComponentShutdown args)
+ {
+ if (!TryComp<DamageProtectionBuffComponent>(uid, out var buffComp))
+ return;
+ // remove the damage modifier from the dict
+ buffComp.Modifiers.Remove(component.RadiationProtectionModifierSetId);
+ // if the dict is empty now, remove the buff component
+ if (buffComp.Modifiers.Count == 0)
+ RemComp<DamageProtectionBuffComponent>(uid);
+ }
+}
--- /dev/null
+using Content.Shared.Damage.Prototypes;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Damage.Components;
+
+/// <summary>
+/// Applies the specified DamageModifierSets when the entity takes damage.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class DamageProtectionBuffComponent : Component
+{
+ /// <summary>
+ /// The damage modifiers for entities with this component.
+ /// </summary>
+ [DataField]
+ public Dictionary<string, DamageModifierSetPrototype> Modifiers = new();
+}
--- /dev/null
+using Content.Shared.Damage.Components;
+
+namespace Content.Shared.Damage.Systems;
+
+public sealed class DamageProtectionBuffSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<DamageProtectionBuffComponent, DamageModifyEvent>(OnDamageModify);
+ }
+
+ private void OnDamageModify(EntityUid uid, DamageProtectionBuffComponent component, DamageModifyEvent args)
+ {
+ foreach (var modifier in component.Modifiers.Values)
+ args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, modifier);
+ }
+}
--- /dev/null
+using System.Numerics;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Drowsiness;
+
+/// <summary>
+/// Exists for use as a status effect. Adds a shader to the client that scales with the effect duration.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
+public sealed partial class DrowsinessComponent : Component
+{
+ /// <summary>
+ /// The random time between sleeping incidents, (min, max).
+ /// </summary>
+ [DataField(required: true)]
+ public Vector2 TimeBetweenIncidents = new Vector2(5f, 60f);
+
+ /// <summary>
+ /// The duration of sleeping incidents, (min, max).
+ /// </summary>
+ [DataField(required: true)]
+ public Vector2 DurationOfIncident = new Vector2(2, 5);
+
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoPausedField]
+ public TimeSpan NextIncidentTime = TimeSpan.Zero;
+}
--- /dev/null
+using Content.Shared.StatusEffect;
+
+namespace Content.Shared.Drowsiness;
+
+public abstract class SharedDrowsinessSystem : EntitySystem
+{
+ [ValidatePrototypeId<StatusEffectPrototype>]
+ public const string DrowsinessKey = "Drowsiness";
+}
reagent-effect-status-effect-Pacified = combat pacification
reagent-effect-status-effect-RatvarianLanguage = ratvarian language patterns
reagent-effect-status-effect-StaminaModifier = modified stamina
+reagent-effect-status-effect-RadiationProtection = radiation protection
+reagent-effect-status-effect-Drowsiness = drowsiness
reagent-name-psicodine = psicodine
reagent-desc-psicodine = Suppresses anxiety and other various forms of mental distress. Overdose causes hallucinations and minor toxin damage.
+
+reagent-name-potassium-iodide = potassium iodide
+reagent-desc-potassium-iodide = Will reduce the damaging effects of radiation by 90%. Prophylactic use only.
+
+reagent-name-haloperidol = haloperidol
+reagent-desc-haloperidol = Removes most stimulating and hallucinogenic drugs. Reduces druggy effects and jitteriness. Causes drowsiness.
contents:
- id: SyringePhalanximine
- id: RadAutoInjector
- - id: EmergencyMedipen
+ - id: PillCanisterPotassiumIodide
- id: PillCanisterHyronalin
- type: entity
Cellular: 0.0
Heat: 2.5
Caustic: 0.0
+
+# protects against radiation
+- type: damageModifierSet
+ id: PotassiumIodide
+ coefficients:
+ Radiation: 0.1
- TemporaryBlindness
- Pacified
- Flashed
+ - RadiationProtection
+ - Drowsiness
- type: Buckle
- type: StandingState
- type: Tag
baseDecayRate: 0.04
- type: StatusEffects
allowed:
- - Stun
- - KnockedDown
- - SlowedDown
- - Stutter
- - Electrocution
- - ForcedSleep
- - TemporaryBlindness
- - Pacified
- - StaminaModifier
- - Flashed
+ - Stun
+ - KnockedDown
+ - SlowedDown
+ - Stutter
+ - Electrocution
+ - ForcedSleep
+ - TemporaryBlindness
+ - Pacified
+ - StaminaModifier
+ - Flashed
+ - RadiationProtection
+ - Drowsiness
- type: Bloodstream
bloodMaxVolume: 150
- type: MobPrice
- Pacified
- StaminaModifier
- Flashed
+ - RadiationProtection
+ - Drowsiness
- type: Body
prototype: Human
requiredLegs: 2
groups:
Brute: -0.07
- type: Fingerprint
-
- type: Blindable
# Other
- type: Temperature
- id: PillHyronalin
amount: 5
+- type: entity
+ name: pill
+ suffix: Potassium iodide 10u
+ parent: Pill
+ id: PillPotassiumIodide
+ components:
+ - type: Pill
+ pillType: 8
+ - type: Sprite
+ state: pill9
+ - type: Label
+ currentLabel: potassium iodide 10u
+ - type: SolutionContainerManager
+ solutions:
+ food:
+ maxVol: 20
+ reagents:
+ - ReagentId: PotassiumIodide
+ Quantity: 10
+
+- type: entity
+ name: pill canister
+ parent: PillCanister
+ id: PillCanisterPotassiumIodide
+ suffix: Potassium iodide 10u, 5
+ components:
+ - type: Label
+ currentLabel: potassium iodide 10u
+ - type: StorageFill
+ contents:
+ - id: PillPotassiumIodide
+ amount: 5
+
- type: entity
name: pill
suffix: Iron 10u
prob: 0.10
maxAmount: 7
orGroup: RandomPill
+ - id: PillPotassiumIodide
+ prob: 0.10
+ maxAmount: 7
+ orGroup: RandomPill
- id: PillIron
prob: 0.10
maxAmount: 7
- !type:AdjustReagent
reagent: Theobromine
amount: 0.05
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 1.0
+ type: Remove
fizziness: 0.25
- type: reagent
- !type:AdjustReagent
reagent: Theobromine
amount: 0.05
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 1.0
+ type: Remove
fizziness: 0.15
- type: reagent
- !type:AdjustReagent
reagent: Theobromine
amount: 0.05
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 1.0
+ type: Remove
fizziness: 0.15
- type: reagent
- !type:AdjustReagent
reagent: Theobromine
amount: 0.05
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 1.0
+ type: Remove
fizziness: 0.25
- type: reagent
- !type:AdjustReagent
reagent: Theobromine
amount: 0.05
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 1.0
+ type: Remove
fizziness: 0.15
- type: reagent
- !type:AdjustReagent
reagent: Theobromine
amount: 0.05
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 1.0
+ type: Remove
fizziness: 0.25
effects:
- !type:SatiateThirst
factor: 2
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 2.0
+ type: Remove
- !type:AdjustReagent
reagent: Theobromine
amount: 0.05
metamorphicMaxFillLevels: 1
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 2.0
+ type: Remove
- type: reagent
id: GreenTea
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 2.0
+ type: Remove
- type: reagent
id: IcedGreenTea
effects:
- !type:SatiateThirst
factor: 6
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 3.0
+ type: Remove
Poison:
effects:
- !type:HealthChange
metamorphicMaxFillLevels: 1
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 2.0
+ type: Remove
- type: reagent
id: Tea
metamorphicMaxFillLevels: 5
metamorphicFillBaseName: fill-
metamorphicChangeColor: false
+ metabolisms:
+ Drink:
+ effects:
+ - !type:SatiateThirst
+ factor: 2
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 1.0
+ type: Remove
- type: reagent
id: RoyRogers
effects:
- !type:SatiateThirst
factor: 2
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 2.0
+ type: Remove
- !type:AdjustReagent
reagent: Theobromine
amount: 0.1
- !type:GenericStatusEffect
key: Stutter
component: StutteringAccent
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 10
+ type: Remove
- !type:ResetNarcolepsy
conditions:
- !type:ReagentThreshold
metabolisms:
Medicine:
effects:
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ time: 10
+ type: Remove
- !type:ResetNarcolepsy
conditions:
- !type:ReagentThreshold
- "psicodine-effect-anxieties-wash-away"
- "psicodine-effect-at-peace"
probability: 0.2
+
+- type: reagent
+ id: PotassiumIodide
+ name: reagent-name-potassium-iodide
+ group: Medicine
+ desc: reagent-desc-potassium-iodide
+ physicalDesc: reagent-physical-desc-grainy
+ flavor: medicine
+ color: "#baa15d"
+ metabolisms:
+ Medicine:
+ effects:
+ - !type:GenericStatusEffect
+ key: RadiationProtection
+ component: RadiationProtection
+ time: 2
+ type: Add
+ refresh: false
+ - !type:HealthChange
+ conditions:
+ - !type:ReagentThreshold
+ min: 20
+ damage:
+ types:
+ Poison: 1
+
+- type: reagent
+ id: Haloperidol
+ name: reagent-name-haloperidol
+ group: Medicine
+ desc: reagent-desc-haloperidol
+ physicalDesc: reagent-physical-desc-crystalline
+ flavor: medicine
+ color: "#27870a"
+ metabolisms:
+ Medicine:
+ effects:
+ - !type:Emote
+ emote: Yawn
+ showInChat: true
+ probability: 0.1
+ - !type:GenericStatusEffect
+ key: Drowsiness
+ component: Drowsiness
+ time: 4
+ type: Add
+ refresh: false
+ - !type:GenericStatusEffect
+ key: Jitter
+ time: 4.0
+ type: Remove
+ - !type:GenericStatusEffect
+ key: SeeingRainbows
+ time: 10.0
+ type: Remove
+ - !type:AdjustReagent
+ reagent: Desoxyephedrine
+ amount: -3.0
+ - !type:AdjustReagent
+ reagent: Ephedrine
+ amount: -3.0
+ - !type:AdjustReagent
+ reagent: Stimulants
+ amount: -3.0
+ - !type:AdjustReagent
+ reagent: THC
+ amount: -3.0
+ - !type:AdjustReagent
+ reagent: SpaceDrugs
+ amount: -3.0
+ - !type:AdjustReagent
+ reagent: Bananadine
+ amount: -3.0
+ - !type:AdjustReagent
+ reagent: SpaceGlue
+ amount: -3.0
+ - !type:AdjustReagent
+ reagent: MindbreakerToxin
+ amount: -3.0
key: KnockedDown
time: 3
type: Remove
+ - !type:GenericStatusEffect
+ conditions:
+ - !type:ReagentThreshold
+ reagent: Haloperidol
+ max: 0.01
+ key: Drowsiness
+ time: 10
+ type: Remove
Medicine:
effects:
- !type:ResetNarcolepsy
key: KnockedDown
time: 1
type: Remove
+ - !type:GenericStatusEffect
+ conditions:
+ - !type:ReagentThreshold
+ reagent: Haloperidol
+ max: 0.01
+ key: Drowsiness
+ time: 10
+ type: Remove
- !type:PopupMessage
visualType: Medium
messages: ["ephedrine-effect-tight-pain", "ephedrine-effect-heart-pounds"]
key: ForcedSleep
time: 3
type: Remove
+ - !type:GenericStatusEffect
+ conditions:
+ - !type:ReagentThreshold
+ reagent: Haloperidol
+ max: 0.01
+ key: Drowsiness
+ time: 10
+ type: Remove
Medicine:
metabolismRate: 1.0
effects:
metabolisms:
Poison:
effects:
+ - !type:Emote
+ emote: Yawn
+ showInChat: true
+ probability: 0.1
- !type:MovespeedModifier
walkSpeedModifier: 0.65
sprintSpeedModifier: 0.65
- !type:GenericStatusEffect
- conditions:
- - !type:ReagentThreshold
- reagent: ChloralHydrate
- min: 10
- key: ForcedSleep
- component: ForcedSleeping
- refresh: false
+ key: Drowsiness
+ component: Drowsiness
+ time: 4
type: Add
+ refresh: false
- !type:HealthChange
conditions:
- !type:ReagentThreshold
catalyst: true
products:
Happiness: 4
+
+- type: reaction
+ id: PotassiumIodide
+ reactants:
+ Potassium:
+ amount: 1
+ Iodine:
+ amount: 1
+ products:
+ PotassiumIodide: 2
+
+- type: reaction
+ id: Haloperidol
+ reactants:
+ Aluminium:
+ amount: 1
+ Chlorine:
+ amount: 1
+ Fluorine:
+ amount: 1
+ Oil:
+ amount: 1
+ PotassiumIodide:
+ amount: 1
+ products:
+ Haloperidol: 5
kind: source
path: "/Textures/Shaders/drunk.swsl"
+- type: shader
+ id: Drowsiness
+ kind: source
+ path: "/Textures/Shaders/radial_blur.swsl"
+
- type: shader
id: Texture
kind: source
- type: statusEffect
id: Flashed
+
+- type: statusEffect
+ id: RadiationProtection
+
+- type: statusEffect
+ id: Drowsiness #blurs your vision and makes you randomly fall asleep
--- /dev/null
+uniform sampler2D SCREEN_TEXTURE;
+uniform highp float Strength;
+const highp int SampleCount = 10; // a higher number makes the shader look better, but has a big performance impact
+
+// a simple radial blur
+void fragment() {
+ highp vec2 uv = FRAGCOORD.xy * SCREEN_PIXEL_SIZE.xy;
+ highp vec2 direction = vec2(0.5, 0.5) - uv;
+ for (int i=1; i <= SampleCount; i++)
+ {
+ COLOR += zTextureSpec(SCREEN_TEXTURE, uv + float(i) * Strength / float(SampleCount) * direction);
+ }
+ COLOR = COLOR / float(SampleCount);
+}