шырнулся и умер

This commit is contained in:
Jabak
2024-06-24 01:00:44 +03:00
parent 37fe791fd7
commit 24876d9afa
16 changed files with 516 additions and 1 deletions

View File

@@ -0,0 +1,66 @@
using Content.Server._Amour.Hallucinations;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.StatusEffect;
using Robust.Shared.Prototypes;
namespace Content.Server.Chemistry.ReagentEffects
{
/// <summary>
/// That looks like GenericStatusEffect but with hallucinations pack selection
/// </summary>
public sealed partial class HallucinationsReagentEffect : ReagentEffect
{
[DataField("key")]
public string Key = "Hallucinations";
[DataField(required: true)]
public string Proto = String.Empty;
[DataField]
public float Time = 2.0f;
[DataField]
public bool Refresh = true;
[DataField]
public HallucinationsMetabolismType Type = HallucinationsMetabolismType.Add;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
{
return Loc.GetString("reagent-effect-guidebook-status-effect",
("chance", Probability),
("type", Type),
("time", Time),
("key", $"reagent-effect-status-effect-{Key}"));
}
public override void Effect(ReagentEffectArgs args)
{
var statusSys = args.EntityManager.EntitySysManager.GetEntitySystem<StatusEffectsSystem>();
var hallucinationsSys = args.EntityManager.EntitySysManager.GetEntitySystem<HallucinationsSystem>();
var time = Time;
time *= args.Scale;
if (Type == HallucinationsMetabolismType.Add)
{
if (!hallucinationsSys.StartHallucinations(args.SolutionEntity, Key, TimeSpan.FromSeconds(Time), Refresh, Proto))
return;
}
else if (Type == HallucinationsMetabolismType.Remove)
{
statusSys.TryRemoveTime(args.SolutionEntity, Key, TimeSpan.FromSeconds(time));
}
else if (Type == HallucinationsMetabolismType.Set)
{
statusSys.TrySetTime(args.SolutionEntity, Key, TimeSpan.FromSeconds(time));
}
}
}
public enum HallucinationsMetabolismType
{
Add,
Remove,
Set
}
}

View File

@@ -0,0 +1,149 @@
using Content.Shared._Amour.Hallucinations;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Humanoid;
using Content.Shared.StatusEffect;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._Amour.Hallucinations;
public sealed partial class HallucinationsSystem : EntitySystem
{
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedEyeSystem _eye = default!;
[Dependency] private readonly StatusEffectsSystem _status = default!;
[Dependency] private readonly VisibilitySystem _visibilitySystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HallucinationsComponent, MapInitEvent>(OnHallucinationsInit);
SubscribeLocalEvent<HallucinationsComponent, ComponentShutdown>(OnHallucinationsShutdown);
}
private void OnHallucinationsInit(EntityUid uid, HallucinationsComponent component, MapInitEvent args)
{
component.Layer = _random.Next(100, 150);
if (!_entityManager.TryGetComponent<EyeComponent>(uid, out var eye))
return;
UpdatePreset(component);
_eye.SetVisibilityMask(uid, eye.VisibilityMask | component.Layer, eye);
_adminLogger.Add(LogType.Action, LogImpact.Medium,
$"{ToPrettyString(uid):player} began to hallucinate.");
}
/// <summary>
/// Updates hallucinations component settings to match prototype
/// </summary>
/// <param name="component">Active HallucinationsComponent</param>
public void UpdatePreset(HallucinationsComponent component)
{
if (component.Proto == null)
return;
var preset = component.Proto;
component.Spawns = preset.Entities;
component.Range = preset.Range;
component.SpawnRate = preset.SpawnRate;
component.MinChance = preset.MinChance;
component.MaxChance = preset.MaxChance;
component.MaxSpawns = preset.MaxSpawns;
component.IncreaseChance = preset.IncreaseChance;
}
private void OnHallucinationsShutdown(EntityUid uid, HallucinationsComponent component, ComponentShutdown args)
{
if (!_entityManager.TryGetComponent<EyeComponent>(uid, out var eye))
return;
_eye.SetVisibilityMask(uid, eye.VisibilityMask & ~component.Layer, eye);
_adminLogger.Add(LogType.Action, LogImpact.Medium,
$"{ToPrettyString(uid):player} stopped hallucinating.");
}
/// <summary>
/// Attempts to start hallucinations for target
/// </summary>
/// <param name="target">The target.</param>
/// <param name="key">Status effect key.</param>
/// <param name="time">Duration of hallucinations effect.</param>
/// <param name="refresh">Refresh active effects.</param>
/// <param name="proto">Hallucinations pack prototype.</param>
public bool StartHallucinations(EntityUid target, string key, TimeSpan time, bool refresh, string proto)
{
if (proto == null)
return false;
if (!_proto.TryIndex<HallucinationsPrototype>(proto, out var prototype))
return false;
if (!_status.TryAddStatusEffect<HallucinationsComponent>(target, key, time, refresh))
return false;
var hallucinations = _entityManager.GetComponent<HallucinationsComponent>(target);
hallucinations.Proto = prototype;
UpdatePreset(hallucinations);
hallucinations.CurChance = prototype.MinChance;
return true;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<HallucinationsComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var stat, out var xform))
{
if (_timing.CurTime < stat.NextSecond)
continue;
var rate = stat.SpawnRate;
stat.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(rate);
if (stat.CurChance < stat.MaxChance && stat.CurChance + stat.IncreaseChance <= 1)
stat.CurChance = stat.CurChance + stat.IncreaseChance;
if (!_random.Prob(stat.CurChance))
continue;
stat.SpawnedCount = 0;
var range = stat.Range * 4;
// To be sure that entity will see right entities
UpdatePreset(stat);
// More people - worse hallucinations
foreach (var (ent, comp) in _lookup.GetEntitiesInRange<HumanoidAppearanceComponent>(xform.MapPosition, range))
{
var newCoords = Transform(ent).MapPosition.Offset(_random.NextVector2(stat.Range));
if (stat.SpawnedCount >= stat.MaxSpawns)
continue;
stat.SpawnedCount = stat.SpawnedCount += 1;
var hallucination = Spawn(_random.Pick(stat.Spawns), newCoords);
EnsureComp<VisibilityComponent>(hallucination, out var visibility);
_visibilitySystem.SetLayer(hallucination, visibility, (int) stat.Layer, false);
_visibilitySystem.RefreshVisibility(hallucination, visibilityComponent: visibility);
}
// If there is no one... You are hallucinations source too
var uidnewCoords = Transform(uid).MapPosition.Offset(_random.NextVector2(stat.Range));
if (stat.SpawnedCount >= stat.MaxSpawns)
continue;
stat.SpawnedCount = stat.SpawnedCount += 1;
var uidhallucination = Spawn(_random.Pick(stat.Spawns), uidnewCoords);
EnsureComp<VisibilityComponent>(uidhallucination, out var uidvisibility);
_visibilitySystem.SetLayer(uidhallucination, uidvisibility, (int) stat.Layer, false);
_visibilitySystem.RefreshVisibility(uidhallucination, visibilityComponent: uidvisibility);
}
}
}

View File

@@ -0,0 +1,74 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared._Amour.Hallucinations;
[RegisterComponent]
public sealed partial class HallucinationsComponent : Component
{
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan NextSecond = TimeSpan.Zero;
/// <summary>
/// How far from humanoid can appear hallucination
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Range = 7f;
/// <summary>
/// How often (in seconds) hallucinations spawned
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float SpawnRate = 15f;
/// <summary>
/// Minimum spawn chance per humanoid
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float MinChance = 0.1f;
/// <summary>
/// Max spawn chance per humanoid
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float MaxChance = 0.8f;
/// <summary>
/// How much chance increased per spawn
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float IncreaseChance = 0.1f;
/// <summary>
/// Max spawned hallucinations count for one spawn
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int MaxSpawns = 3;
/// <summary>
/// How much entities already spawned
/// </summary>
public int SpawnedCount = 0;
/// <summary>
/// Current spawn chance
/// </summary>
public float CurChance = 0.1f;
/// <summary>
/// List of prototypes that are spawned as a hallucination.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public List<EntProtoId> Spawns = new();
/// <summary>
/// Hallucinations pack proto
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public HallucinationsPrototype? Proto;
/// <summary>
/// Currently selected for hallucinations layer
/// </summary>
public int Layer = 50;
}

View File

@@ -0,0 +1,56 @@
using Robust.Shared.Prototypes;
namespace Content.Shared._Amour.Hallucinations;
/// <summary>
/// Packs of entities that can become a hallucination
/// </summary>
[Prototype("hallucinationsPack")]
public sealed partial class HallucinationsPrototype : IPrototype
{
[IdDataField]
public string ID { get; private set; } = default!;
/// <summary>
/// List of prototypes that are spawned as a hallucination.
/// </summary>
[DataField("entities")]
public List<EntProtoId> Entities = new();
/// <summary>
/// How far from humanoid can appear hallucination
/// </summary>
[DataField("spawnRange")]
public float Range = 7f;
/// <summary>
/// How often (in seconds) hallucinations spawned
/// </summary>
[DataField("spawnRate")]
public float SpawnRate = 15f;
/// <summary>
/// Minimum spawn chance per humanoid
/// </summary>
[DataField("minChance")]
public float MinChance = 0.8f;
/// <summary>
/// Max spawn chance per humanoid
/// </summary>
[DataField("maxChance")]
public float MaxChance = 0.8f;
/// <summary>
/// How much chance increased per spawn
/// </summary>
[DataField("increasedPerSpawn")]
public float IncreaseChance = 0.1f;
/// <summary>
/// Max spawned hallucinations count for one spawn
/// </summary>
[DataField("maxSpawns")]
public int MaxSpawns = 3;
}

View File

@@ -62,3 +62,8 @@
license: "CC-BY-4.0"
copyright: "Taken and edited from source"
source: "https://freesound.org/people/juskiddink/sounds/215658/"
- files: ["base-hallucination-mob.ogg"]
license: "CC0-1.0"
copyright: "Taken and edited from source"
source: "https://freesound.org/people/Nihil_Existentia/sounds/703361/"

View File

@@ -2,7 +2,7 @@ reagent-effect-status-effect-Stun = оглушительный
reagent-effect-status-effect-KnockedDown = нокаутирующий
reagent-effect-status-effect-Jitter = дрожание
reagent-effect-status-effect-TemporaryBlindness = ослепление
reagent-effect-status-effect-SeeingRainbows = галлюцинации
reagent-effect-status-effect-SeeingRainbows = видеть радугу
reagent-effect-status-effect-Muted = неспособность говорить
reagent-effect-status-effect-Stutter = заикание
reagent-effect-status-effect-ForcedSleep = бессознательность

View File

@@ -346,6 +346,12 @@
type: Add
time: 10
refresh: false
- !type:HallucinationsReagentEffect
key: Hallucinations
proto: MindBreaker
type: Add
time: 20
refresh: true
# TODO: PROPER hallucinations
- type: reagent

View File

@@ -0,0 +1,120 @@
# Base
- type: entity
parent: BaseMob
id: BaseEntityHallucination
name: "???"
description: "???"
suffix: DO NOT MAP
abstract: true
components:
#- type: Hallucination
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeCircle
radius: 0.35
density: 15
mask:
- MobMask
layer:
- None
- type: TimedDespawn
lifetime: 15.0
- type: entity
parent: BaseEntityHallucination
id: HallucinationMobMedical
name: medical
description: That one looks friendly!
noSpawn: true
components:
- type: Sprite
sprite: Mobs/Aliens/Hallucinations/base_hallucinations.rsi
state: medical
- type: MovementSpeedModifier
baseWalkSpeed: 2.0
baseSprintSpeed: 3.7
- type: HTN
rootTask:
task: IdleCompound
- type: AmbientSound
volume: -2
range: 15
sound:
path: /Audio/Ambience/Objects/base-hallucination-mob.ogg
- type: TimedDespawn
lifetime: 45.0
- type: entity
parent: BaseEntityHallucination
id: HallucinationMobNukeop
name: nukie
description: Boom.
noSpawn: true
components:
- type: Sprite
sprite: Mobs/Aliens/Hallucinations/base_hallucinations.rsi
state: nukeop
- type: MovementSpeedModifier
baseWalkSpeed: 3.0
baseSprintSpeed: 4.7
- type: HTN
rootTask:
task: IdleCompound
- type: AmbientSound
volume: -2
range: 15
sound:
path: /Audio/Ambience/Objects/base-hallucination-mob.ogg
- type: TimedDespawn
lifetime: 25.0
- type: entity
parent: BaseEntityHallucination
id: HallucinationMobMusician
name: musician
description: He is definetly playing something...
noSpawn: true
components:
- type: Sprite
sprite: Mobs/Aliens/Hallucinations/base_hallucinations.rsi
state: musician
- type: MovementSpeedModifier
baseWalkSpeed: 1.0
baseSprintSpeed: 1.7
- type: HTN
rootTask:
task: IdleCompound
- type: AmbientSound
volume: -2
range: 15
sound:
path: /Audio/Ambience/Objects/base-hallucination-mob.ogg
- type: TimedDespawn
lifetime: 35.0
- type: entity
parent: BaseEntityHallucination
id: HallucinationMobYeti
name: yeti
description: I want to believe
noSpawn: true
components:
- type: Sprite
sprite: Mobs/Aliens/Hallucinations/base_hallucinations.rsi
state: yeti
- type: MovementSpeedModifier
baseWalkSpeed: 2.0
baseSprintSpeed: 3.0
- type: HTN
rootTask:
task: IdleCompound
- type: AmbientSound
volume: -2
range: 15
sound:
path: /Audio/Ambience/Objects/base-hallucination-mob.ogg
- type: TimedDespawn
lifetime: 30.0

View File

@@ -0,0 +1,9 @@
- type: hallucinationsPack
id: MindBreaker
minChance: 0.4
maxChance: 0.9
entities:
- HallucinationMobMedical
- HallucinationMobNukeop
- HallucinationMobMusician
- HallucinationMobYeti

View File

@@ -71,3 +71,6 @@
#WD EDIT
- type: statusEffect
id: Incorporeal
- type: statusEffect
id: Hallucinations

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,27 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"license": "CC-BY-SA-3.0",
"copyright": "Created by discord:bolbyy for SpaceStation14",
"states": [
{
"name": "medical",
"directions": 4
},
{
"name": "musician",
"directions": 4
},
{
"name": "nukeop",
"directions": 4
},
{
"name": "yeti",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB